chore: initialize repository baseline

Import the existing Electron + React + TypeScript app as the version-control
baseline before the scanner rework (C# input/capture sidecar, resolution-anchored
layout profiles, OCR preprocessing, eval harness, rescan-merge, GOOD interop).

Housekeeping in this commit:
- Remove orphaned temp_inputhelper_block.ts (duplicate of the input-helper script).
- Ignore .claude/scheduled_tasks.lock local session state.
- Add .gitattributes to normalize line endings (LF in repo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
AzuTear
2026-07-05 20:31:01 +02:00
commit e76d88e0c7
147 changed files with 26220 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import { ipcMain } from "electron";
import type {
BooleanResult,
FocusGenshinResult,
RuntimeInfo,
SaveSnapshotResult,
ScannerStatusPayload,
} from "../../src/types/global.js";
import type { AppSnapshot } from "../../src/types/domain.js";
interface AppCommandDependencies {
focusMainWindow: () => BooleanResult;
moveMainWindowOffGenshin: () => Promise<void>;
focusGenshinForScanStart: () => Promise<FocusGenshinResult>;
publishScannerStatus: (status: ScannerStatusPayload) => Promise<BooleanResult>;
getRuntimeInfo: () => Promise<RuntimeInfo>;
loadSnapshot: () => Promise<AppSnapshot | null>;
saveSnapshot: (snapshot: AppSnapshot) => Promise<SaveSnapshotResult>;
runMockScan: () => Promise<AppSnapshot | null>;
showOverlay: () => Promise<BooleanResult>;
hideOverlay: () => Promise<BooleanResult>;
}
export function registerAppHandlers({
focusMainWindow,
moveMainWindowOffGenshin,
focusGenshinForScanStart,
publishScannerStatus,
getRuntimeInfo,
loadSnapshot,
saveSnapshot,
runMockScan,
showOverlay,
hideOverlay,
}: AppCommandDependencies) {
ipcMain.handle("app:focusMainWindow", async () => focusMainWindow());
ipcMain.handle("automation:focusGenshin", async () => {
await moveMainWindowOffGenshin();
return focusGenshinForScanStart();
});
ipcMain.handle("scanner:publishStatus", async (_event, status: ScannerStatusPayload) => {
await publishScannerStatus(status);
return { ok: true };
});
ipcMain.handle("app:getRuntimeInfo", async () => getRuntimeInfo());
ipcMain.handle("snapshot:load", async () => loadSnapshot());
ipcMain.handle("snapshot:save", async (_event, snapshot: AppSnapshot) => saveSnapshot(snapshot));
ipcMain.handle("scan:runMock", async () => runMockScan());
ipcMain.handle("overlay:show", () => showOverlay());
ipcMain.handle("overlay:hide", () => hideOverlay());
}
+26
View File
@@ -0,0 +1,26 @@
import { ipcMain } from "electron";
import type { CaptureOptions, CaptureResult, CaptureSourceInfo, ClickResult, ScrollResult, AutomationGuard } from "../../src/types/global.js";
interface CaptureCommandDependencies {
listSources: () => Promise<CaptureSourceInfo[]>;
captureSource: (sourceId: string, delayMs?: number, focusGenshin?: boolean, options?: CaptureOptions) => Promise<CaptureResult>;
clickScreen: (x: number, y: number) => Promise<ClickResult>;
scrollScreen: (notches: number, anchorX?: number, anchorY?: number) => Promise<ScrollResult>;
getAutomationGuard: () => Promise<AutomationGuard>;
}
export function registerCaptureHandlers({
listSources,
captureSource,
clickScreen,
scrollScreen,
getAutomationGuard,
}: CaptureCommandDependencies) {
ipcMain.handle("capture:listSources", async () => listSources());
ipcMain.handle("capture:captureSource", async (_event, sourceId: string, delayMs = 0, focusGenshin = false, options?: CaptureOptions) => {
return captureSource(sourceId, delayMs, focusGenshin, options);
});
ipcMain.handle("automation:clickScreen", async (_event, x: number, y: number) => clickScreen(x, y));
ipcMain.handle("automation:scrollScreen", async (_event, notches: number, anchorX?: number, anchorY?: number) => scrollScreen(notches, anchorX, anchorY));
ipcMain.handle("automation:getGuard", async () => getAutomationGuard());
}
+84
View File
@@ -0,0 +1,84 @@
import { ipcMain } from "electron";
import type {
ArtifactStoreLoadResult,
ArtifactStoreRepositoryPort,
ArtifactStoreSaveResult,
ReviewSampleListResult,
ReviewSamplePayload,
ReviewSamplesRepositoryPort,
} from "../repositories/contracts.js";
import type {
GoodDatabase,
LoadScannerLearningRulesResult,
SaveScannerLearningRulesResult,
ScannerLearningRulePayload,
SaveResultWithPath,
} from "../../src/types/global.js";
import type { StoredArtifactRecord } from "../../src/types/storage.js";
type ArtifactStoreAccessor = () => ArtifactStoreRepositoryPort;
type ReviewSamplesAccessor = () => ReviewSamplesRepositoryPort;
interface PersistenceDependencies {
getArtifactStoreRepository: ArtifactStoreAccessor;
getReviewSamplesRepository: ReviewSamplesAccessor;
artifactStorePath: () => string;
reviewSamplesPath: () => string;
loadReviewSamples: (limit?: number) => Promise<ReviewSampleListResult>;
loadScannerLearningRules: () => Promise<LoadScannerLearningRulesResult>;
writeScannerLearningRules: (rules: ScannerLearningRulePayload) => Promise<SaveScannerLearningRulesResult>;
exportGood: (payload: GoodDatabase) => Promise<SaveResultWithPath>;
}
export function registerPersistenceHandlers({
getArtifactStoreRepository,
getReviewSamplesRepository,
artifactStorePath,
reviewSamplesPath,
loadReviewSamples,
loadScannerLearningRules,
writeScannerLearningRules,
exportGood,
}: PersistenceDependencies) {
ipcMain.handle("review:saveSample", async (_event, sample: ReviewSamplePayload) => {
try {
return await getReviewSamplesRepository().append(sample);
} catch {
const filePath = reviewSamplesPath();
return { ok: false, path: filePath };
}
});
ipcMain.handle("review:loadSamples", async (_event, limit = 50) => {
return loadReviewSamples(Number(limit) || 50);
});
ipcMain.handle("scanner:loadLearningRules", async () => {
return loadScannerLearningRules();
});
ipcMain.handle("scanner:saveLearningRules", async (_event, rules: ScannerLearningRulePayload) => {
return writeScannerLearningRules(rules);
});
ipcMain.handle("artifacts:load", async () => {
try {
return (await getArtifactStoreRepository().loadAll()) as ArtifactStoreLoadResult;
} catch {
return { ok: false, artifacts: [], total: 0, path: artifactStorePath() };
}
});
ipcMain.handle("artifacts:saveMany", async (_event, records: StoredArtifactRecord[]) => {
try {
const safeRecords = Array.isArray(records) ? records : [];
return (await getArtifactStoreRepository().saveMany(safeRecords)) as ArtifactStoreSaveResult;
} catch {
return { ok: false, added: 0, updated: 0, total: 0, path: artifactStorePath() };
}
});
ipcMain.handle("good:export", async (_event, payload: GoodDatabase) => {
return exportGood(payload);
});
}