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
+101
View File
@@ -0,0 +1,101 @@
import { describe, expect, it } from "vitest";
import {
automationBlockReason,
buildInventoryPagePlan,
buildGridModel,
requiresAdminForAutomation,
} from "./automationPlanner";
describe("automationPlanner", () => {
it("requires admin whenever this app's own process is not elevated", () => {
expect(requiresAdminForAutomation({ ok: true, isElevated: false, platform: "win32" })).toBe(true);
expect(requiresAdminForAutomation({ ok: true, isElevated: true, platform: "win32" })).toBe(false);
expect(requiresAdminForAutomation({ ok: false, isElevated: false, platform: "win32" })).toBe(false);
expect(requiresAdminForAutomation(null)).toBe(false);
});
it("returns a user-facing admin block reason when not elevated", () => {
expect(automationBlockReason({ ok: true, isElevated: false, platform: "win32" })).toContain("Administrator");
expect(automationBlockReason({ ok: true, isElevated: true, platform: "win32" })).toBe("");
});
it("builds a dense click grid from partial detected centers", () => {
const grid = buildGridModel({
rows: 3,
cols: 4,
confidence: 96,
source: "detected",
centers: [
{ row: 0, col: 0, x: 100, y: 200 },
{ row: 0, col: 1, x: 220, y: 200 },
{ row: 0, col: 3, x: 460, y: 200 },
{ row: 2, col: 0, x: 100, y: 500 },
{ row: 2, col: 3, x: 460, y: 500 },
],
});
expect(grid).not.toBeNull();
expect(grid?.targets).toHaveLength(12);
expect(grid?.stepX).toBe(120);
expect(grid?.stepY).toBe(150);
expect(grid?.targets.find((target) => target.row === 1 && target.col === 2)).toMatchObject({ x: 340, y: 350 });
});
it("plans overlapping inventory pages like Inventory Kamera for a partial final page", () => {
const targets = Array.from({ length: 40 }, (_, index) => ({
row: Math.floor(index / 8),
col: index % 8,
x: index * 10,
y: index * 10,
}));
const firstPage = buildInventoryPagePlan({
targets,
cols: 8,
rows: 5,
totalTargetCount: 50,
processedTargets: 0,
rowsQueued: 0,
});
expect(firstPage.pageTargets).toHaveLength(40);
expect(firstPage.startIndex).toBe(0);
expect(firstPage.scrollRowsAfterPage).toBe(2);
const finalPage = buildInventoryPagePlan({
targets,
cols: 8,
rows: 5,
totalTargetCount: 50,
processedTargets: 40,
rowsQueued: 5,
});
expect(finalPage.pageTargets).toHaveLength(10);
expect(finalPage.startIndex).toBe(24);
expect(finalPage.pageTargets[0]).toMatchObject({ row: 3, col: 0 });
expect(finalPage.scrollRowsAfterPage).toBe(0);
});
it("keeps the first page top-aligned when the whole inventory fits inside one visible page", () => {
const targets = Array.from({ length: 40 }, (_, index) => ({
row: Math.floor(index / 8),
col: index % 8,
x: index * 10,
y: index * 10,
}));
const singlePage = buildInventoryPagePlan({
targets,
cols: 8,
rows: 5,
totalTargetCount: 16,
processedTargets: 0,
rowsQueued: 0,
});
expect(singlePage.pageTargets).toHaveLength(16);
expect(singlePage.startIndex).toBe(0);
expect(singlePage.pageTargets[0]).toMatchObject({ row: 0, col: 0 });
expect(singlePage.pageTargets[15]).toMatchObject({ row: 1, col: 7 });
expect(singlePage.scrollRowsAfterPage).toBe(0);
});
});