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
@@ -0,0 +1,296 @@
import { useCallback, useEffect, useMemo } from "react";
import type { Dispatch, MutableRefObject, SetStateAction } from "react";
import { runAutoReviewScan as runAutoReviewScanAction, runVisibleGridScan as runVisibleGridScanAction } from "./scanViewScanActions";
import {
initializeLearningState,
loadReviewQueue as loadReviewQueueFromRepo,
persistParsedArtifact as persistParsedArtifactHelper,
saveReviewSample as saveReviewSampleHelper,
} from "./scanViewReviewHelpers";
import { createReviewContext, createScanActionContext } from "./scanViewControllerService";
import { useScanCommandListener } from "./useScanCommandListener";
import type { ParsedArtifactCandidate } from "../../../lib/artifactOcrParser";
import type { ScannerLearningRules } from "../../../lib/scannerLearning";
import type { BooleanResult, CaptureOptions, CaptureResult, ClickResult, ReviewSampleRecord } from "../../../types/global";
import type {
ArtifactRepositoryPort,
ReviewSampleRepositoryPort,
LearningRepositoryPort,
RuntimeRepositoryPort,
AutomationRepositoryPort,
} from "../../../infrastructure/repositories/rendererBridgeRepositoryTypes";
import type { AutoScanStats, ScanSummary } from "../../../lib/scannerSession";
import type { RuntimeInfo } from "../../../types/global";
type BooleanSetter = Dispatch<SetStateAction<boolean>>;
type NumberSetter = Dispatch<SetStateAction<number>>;
type StringSetter = Dispatch<SetStateAction<string>>;
type NumberOrNullSetter = Dispatch<SetStateAction<number | null>>;
type ScannerRulesSetter = Dispatch<SetStateAction<ScannerLearningRules>>;
type ReviewSamplesSetter = Dispatch<SetStateAction<ReviewSampleRecord[]>>;
type ScanSummarySetter = Dispatch<SetStateAction<ScanSummary | null>>;
type AutoScanStatsSetter = Dispatch<SetStateAction<AutoScanStats>>;
interface ScanViewActionInput {
autoScanRunning: boolean;
setAutoScanRunning: BooleanSetter;
isScanning: boolean;
stopVisibleScanRef: MutableRefObject<boolean>;
selectedSourceId: string;
bridgeReady: boolean;
automationRepo?: AutomationRepositoryPort;
runtimeInfo?: RuntimeInfo | null;
runtimeRepo?: RuntimeRepositoryPort;
scanLimit: number;
skipRows: number;
detectedInventoryCount: number;
setScanSummary: ScanSummarySetter;
setAutoScanStats: AutoScanStatsSetter;
setReviewStatus: StringSetter;
appendAutomationLog: (line: string) => void;
appendClickDiagnostics: (result: ClickResult, prefix?: string) => void;
parseArtifact: (capture: CaptureResult | null) => ParsedArtifactCandidate | null;
artifactRepo?: ArtifactRepositoryPort;
reviewSamplesRepo?: ReviewSampleRepositoryPort;
learningRepo?: LearningRepositoryPort;
onStoredArtifactsChanged?: (() => Promise<void>) | (() => void);
setReviewSampleTotal: NumberSetter;
setReviewSamples: ReviewSamplesSetter;
setLearningRulesLoaded: BooleanSetter;
setScannerLearningRules: ScannerRulesSetter;
setStoredTotal: NumberOrNullSetter;
scannerLearningRules: ScannerLearningRules;
captureSelectedSource: (delayMs?: number, focusGenshin?: boolean, options?: CaptureOptions) => Promise<CaptureResult | null>;
latestCapture: CaptureResult | null;
parsedArtifact: ParsedArtifactCandidate | null;
canCaptureSource: boolean;
setReviewQueueOpen: BooleanSetter;
}
export interface ScanViewActionResult {
requestScanStop: (reason?: string) => void;
saveReviewSample: (
capture?: CaptureResult | null,
parsed?: ParsedArtifactCandidate | null,
reason?: string,
) => Promise<BooleanResult | null>;
loadReviewQueue: () => Promise<void>;
openReviewQueue: () => Promise<void>;
runAutoReviewScan: () => Promise<void>;
runVisibleGridScan: () => Promise<void>;
}
export function useScanViewActions(input: ScanViewActionInput): ScanViewActionResult {
const {
autoScanRunning,
setAutoScanRunning,
isScanning,
stopVisibleScanRef,
selectedSourceId,
bridgeReady,
automationRepo,
runtimeInfo,
runtimeRepo,
scanLimit,
skipRows,
detectedInventoryCount,
setScanSummary,
setAutoScanStats,
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
parseArtifact,
artifactRepo,
reviewSamplesRepo,
learningRepo,
onStoredArtifactsChanged,
setReviewSampleTotal,
setReviewSamples,
setLearningRulesLoaded,
setScannerLearningRules,
setStoredTotal,
scannerLearningRules,
captureSelectedSource,
latestCapture,
parsedArtifact,
canCaptureSource,
setReviewQueueOpen,
} = input;
const requestScanStop = useCallback((reason = "Stop angefordert.") => {
stopVisibleScanRef.current = true;
appendAutomationLog(`stop requested: ${reason}`);
setReviewStatus(`${reason} Der aktuelle Klick/Capture-Schritt wird noch sauber beendet.`);
}, [appendAutomationLog, setReviewStatus, stopVisibleScanRef]);
const reviewContext = useMemo(
() =>
createReviewContext({
artifactRepo,
reviewSamplesRepo,
learningRepo,
onStoredArtifactsChanged,
setReviewSampleTotal,
setReviewSamples,
setLearningRulesLoaded,
setScannerLearningRules,
setReviewStatus,
setStoredTotal,
appendAutomationLog,
}),
[
artifactRepo,
reviewSamplesRepo,
learningRepo,
onStoredArtifactsChanged,
setReviewSampleTotal,
setReviewSamples,
setLearningRulesLoaded,
setScannerLearningRules,
setReviewStatus,
setStoredTotal,
appendAutomationLog,
],
);
useEffect(() => {
void initializeLearningState(reviewContext);
}, [reviewContext]);
const focusDashboard = useCallback(async () => {
try {
await automationRepo?.focusMainWindow?.();
} catch {
// Best-effort fallback; state remains in renderer.
}
}, [automationRepo?.focusMainWindow]);
const parseArtifactAndPersist = useCallback(
async function parseArtifactAndPersist(
capture: CaptureResult | null,
parsed: ParsedArtifactCandidate,
source: string,
needsReview: boolean,
) {
return persistParsedArtifactHelper(capture, parsed, source, needsReview, reviewContext);
},
[reviewContext],
);
const handleSaveReviewSample = useCallback(
async function handleSaveReviewSample(
capture: CaptureResult | null = latestCapture,
parsed: ParsedArtifactCandidate | null = parsedArtifact,
reason = "manual",
): Promise<BooleanResult | null> {
const result = await saveReviewSampleHelper(
capture,
parsed,
reason,
scannerLearningRules,
reviewContext,
);
return result.result ? { ok: result.result.ok } : null;
},
[latestCapture, parsedArtifact, reviewContext, scannerLearningRules],
);
const scanActionContext = useMemo(
() =>
createScanActionContext({
autoScanRunning,
setAutoScanRunning,
isScanning,
stopVisibleScanRef,
selectedSourceId,
bridgeReady,
automationRepo,
runtimeInfo,
runtimeRepo,
scanLimit,
skipRows,
detectedInventoryCount,
setScanSummary,
setAutoScanStats,
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
parseArtifact,
persistParsedArtifact: parseArtifactAndPersist,
saveReviewSample: handleSaveReviewSample,
focusDashboard,
captureSelectedSource,
captureFastSelectedSource: (delayMs = 0, focusGenshin = false) => captureSelectedSource(delayMs, focusGenshin, { skipOcr: true }),
}),
[
autoScanRunning,
setAutoScanRunning,
isScanning,
stopVisibleScanRef,
selectedSourceId,
bridgeReady,
automationRepo,
runtimeInfo,
runtimeRepo,
scanLimit,
skipRows,
detectedInventoryCount,
setScanSummary,
setAutoScanStats,
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
parseArtifact,
parseArtifactAndPersist,
handleSaveReviewSample,
focusDashboard,
captureSelectedSource,
],
);
const loadReviewQueueAction = useCallback(async () => {
await loadReviewQueueFromRepo(reviewContext);
}, [reviewContext]);
const openReviewQueueModal = useCallback(async () => {
await loadReviewQueueAction();
setReviewQueueOpen(true);
}, [loadReviewQueueAction, setReviewQueueOpen]);
const runAutoReviewScan = useCallback(async () => {
if (autoScanRunning || !selectedSourceId || !canCaptureSource) return;
await runAutoReviewScanAction(scanActionContext);
}, [autoScanRunning, canCaptureSource, selectedSourceId, scanActionContext]);
const runVisibleGridScan = useCallback(async () => {
if (autoScanRunning || !bridgeReady || !selectedSourceId || !automationRepo?.clickScreen || !automationRepo?.scrollScreen) {
return;
}
await runVisibleGridScanAction(scanActionContext);
}, [
autoScanRunning,
bridgeReady,
selectedSourceId,
automationRepo?.clickScreen,
automationRepo?.scrollScreen,
scanActionContext,
]);
useScanCommandListener({
automationRepo,
autoScanRunning,
isScanning,
selectedSourceId,
requestScanStop,
runVisibleGridScan,
});
return {
requestScanStop,
saveReviewSample: handleSaveReviewSample,
loadReviewQueue: loadReviewQueueAction,
openReviewQueue: openReviewQueueModal,
runAutoReviewScan,
runVisibleGridScan,
};
}