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:
@@ -0,0 +1,86 @@
|
||||
import type { ParsedArtifactCandidate } from "./artifactOcrParser.js";
|
||||
import type { StoredArtifactRecord } from "../types/storage.js";
|
||||
|
||||
/**
|
||||
* Signature used inside one scan session to detect that the detail panel
|
||||
* actually changed after a click. Includes the equipped character so two
|
||||
* otherwise identical pieces on different characters still count as new.
|
||||
*/
|
||||
export function sessionSignature(parsed: ParsedArtifactCandidate) {
|
||||
return [
|
||||
parsed.name,
|
||||
parsed.slot,
|
||||
parsed.level,
|
||||
parsed.mainStat,
|
||||
parsed.mainValue,
|
||||
parsed.setName,
|
||||
parsed.equipped,
|
||||
parsed.substats.join("|"),
|
||||
].join("::");
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature used for the persistent store. Excludes the equipped character,
|
||||
* so re-equipping an artifact updates the existing record instead of
|
||||
* duplicating it. Level is part of the identity because the local DB now
|
||||
* persists partially leveled pieces as distinct scan states.
|
||||
*/
|
||||
export function storeSignature(parsed: ParsedArtifactCandidate) {
|
||||
return [
|
||||
parsed.name,
|
||||
parsed.slot,
|
||||
parsed.level,
|
||||
parsed.mainStat,
|
||||
parsed.mainValue,
|
||||
parsed.setName,
|
||||
parsed.substats.join("|"),
|
||||
].join("::");
|
||||
}
|
||||
|
||||
export function hashId(value: string) {
|
||||
let hash = 5381;
|
||||
for (let index = 0; index < value.length; index++) {
|
||||
hash = ((hash << 5) + hash + value.charCodeAt(index)) >>> 0;
|
||||
}
|
||||
return `${hash.toString(16).padStart(8, "0")}-${value.length.toString(16)}`;
|
||||
}
|
||||
|
||||
export function toStoredArtifact(parsed: ParsedArtifactCandidate, source: string, needsReview: boolean): StoredArtifactRecord {
|
||||
return {
|
||||
id: hashId(storeSignature(parsed)),
|
||||
name: parsed.name,
|
||||
slot: parsed.slot,
|
||||
level: parsed.level,
|
||||
setName: parsed.setName,
|
||||
mainStat: parsed.mainStat,
|
||||
mainValue: parsed.mainValue,
|
||||
substats: [...parsed.substats],
|
||||
equipped: parsed.equipped,
|
||||
confidence: parsed.confidence,
|
||||
needsReview,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
export function isReviewOnlyArtifactSource(source: string | null | undefined) {
|
||||
return /^review-/i.test(source ?? "");
|
||||
}
|
||||
|
||||
export function storedArtifactStrength(record: StoredArtifactRecord | null | undefined) {
|
||||
if (!record) return 0;
|
||||
return (
|
||||
(record.confidence ?? 0)
|
||||
+ Math.min(16, (record.substats?.length ?? 0) * 4)
|
||||
+ (record.needsReview ? -10 : 8)
|
||||
+ (record.equipped && !/not detected/i.test(record.equipped) ? 3 : 0)
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveStoredArtifactSource(existingSource: string | null | undefined, incomingSource: string | null | undefined) {
|
||||
const existing = existingSource ?? "";
|
||||
const incoming = incomingSource ?? "";
|
||||
if (!incoming) return existing;
|
||||
if (!existing) return incoming;
|
||||
if (isReviewOnlyArtifactSource(incoming) && !isReviewOnlyArtifactSource(existing)) return existing;
|
||||
return incoming;
|
||||
}
|
||||
Reference in New Issue
Block a user