plasalid 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/ai/agent.d.ts +6 -7
- package/dist/ai/agent.js +27 -11
- package/dist/ai/personas.js +48 -46
- package/dist/ai/system-prompt.js +1 -1
- package/dist/ai/tools/account-mutex.d.ts +1 -0
- package/dist/ai/tools/account-mutex.js +16 -0
- package/dist/ai/tools/index.js +4 -12
- package/dist/ai/tools/ingest.d.ts +1 -1
- package/dist/ai/tools/ingest.js +282 -242
- package/dist/ai/tools/merchants.js +1 -28
- package/dist/ai/tools/read.js +8 -8
- package/dist/ai/tools/record.js +3 -36
- package/dist/ai/tools/resolve.js +25 -22
- package/dist/ai/tools/scan.js +0 -1
- package/dist/ai/tools/types.d.ts +14 -21
- package/dist/cli/commands/record.js +1 -82
- package/dist/cli/commands/resolve.d.ts +5 -2
- package/dist/cli/commands/resolve.js +36 -5
- package/dist/cli/commands/revert.js +4 -2
- package/dist/cli/commands/rules.js +2 -2
- package/dist/cli/commands/scan.js +199 -128
- package/dist/cli/commands/status.js +5 -5
- package/dist/cli/index.js +8 -29
- package/dist/cli/ink/ScanDashboard.d.ts +49 -0
- package/dist/cli/ink/ScanDashboard.js +214 -0
- package/dist/cli/ink/scan_dashboard.d.ts +40 -25
- package/dist/cli/ink/scan_dashboard.js +139 -44
- package/dist/db/queries/account-balance.d.ts +1 -1
- package/dist/db/queries/questions.d.ts +62 -0
- package/dist/db/queries/questions.js +110 -0
- package/dist/db/queries/transactions.d.ts +1 -1
- package/dist/db/queries/unknowns.d.ts +17 -15
- package/dist/db/queries/unknowns.js +35 -39
- package/dist/db/schema.js +6 -28
- package/dist/scanner/audit/auditor.d.ts +31 -0
- package/dist/scanner/audit/auditor.js +72 -0
- package/dist/scanner/audit/engine.d.ts +10 -0
- package/dist/scanner/audit/engine.js +98 -0
- package/dist/scanner/audit/eventBus.d.ts +60 -0
- package/dist/scanner/audit/eventBus.js +35 -0
- package/dist/scanner/audit/passes/index.d.ts +11 -0
- package/dist/scanner/audit/passes/index.js +9 -0
- package/dist/scanner/audit/passes/types.d.ts +23 -0
- package/dist/scanner/audit/passes/types.js +1 -0
- package/dist/scanner/audit/types.d.ts +27 -0
- package/dist/scanner/audit/types.js +1 -0
- package/dist/scanner/auditor.d.ts +51 -0
- package/dist/scanner/auditor.js +80 -0
- package/dist/scanner/buffer/engine.d.ts +9 -0
- package/dist/scanner/buffer/engine.js +110 -0
- package/dist/scanner/buffer/sharedBuffer.d.ts +78 -0
- package/dist/scanner/buffer/sharedBuffer.js +130 -0
- package/dist/scanner/buffer/types.d.ts +67 -0
- package/dist/scanner/buffer/types.js +1 -0
- package/dist/scanner/buffer.d.ts +45 -38
- package/dist/scanner/buffer.js +93 -61
- package/dist/scanner/bus/engine.d.ts +11 -0
- package/dist/scanner/bus/engine.js +42 -0
- package/dist/scanner/bus/types.d.ts +53 -0
- package/dist/scanner/bus/types.js +1 -0
- package/dist/scanner/bus.d.ts +38 -0
- package/dist/scanner/bus.js +37 -0
- package/dist/scanner/chunk-worker.d.ts +19 -0
- package/dist/scanner/chunk-worker.js +67 -0
- package/dist/scanner/chunkWorker.d.ts +20 -0
- package/dist/scanner/chunkWorker.js +59 -0
- package/dist/scanner/chunker/chunker.d.ts +7 -0
- package/dist/scanner/chunker/chunker.js +60 -0
- package/dist/scanner/chunker.d.ts +7 -0
- package/dist/scanner/chunker.js +60 -0
- package/dist/scanner/converge.d.ts +29 -0
- package/dist/scanner/converge.js +15 -0
- package/dist/scanner/decrypt.d.ts +10 -0
- package/dist/scanner/decrypt.js +80 -0
- package/dist/scanner/engine/scanEngine.d.ts +24 -0
- package/dist/scanner/engine/scanEngine.js +87 -0
- package/dist/scanner/engine/types.d.ts +90 -0
- package/dist/scanner/engine/types.js +1 -0
- package/dist/scanner/engine.d.ts +90 -0
- package/dist/scanner/engine.js +84 -0
- package/dist/scanner/file-worker.d.ts +33 -0
- package/dist/scanner/file-worker.js +28 -0
- package/dist/scanner/fileWorker.d.ts +33 -0
- package/dist/scanner/fileWorker.js +22 -0
- package/dist/scanner/hooks/types.d.ts +25 -0
- package/dist/scanner/hooks/types.js +1 -0
- package/dist/scanner/hooks.d.ts +23 -0
- package/dist/scanner/hooks.js +1 -0
- package/dist/scanner/parse.d.ts +10 -0
- package/dist/scanner/parse.js +47 -0
- package/dist/scanner/passes/index.d.ts +8 -0
- package/dist/scanner/passes/index.js +6 -0
- package/dist/scanner/passes/types.d.ts +22 -0
- package/dist/scanner/passes/types.js +1 -0
- package/dist/scanner/pdf/chunker.d.ts +7 -0
- package/dist/scanner/pdf/chunker.js +60 -0
- package/dist/scanner/pdf/password-store.d.ts +34 -0
- package/dist/scanner/pdf/password-store.js +83 -0
- package/dist/scanner/pdf/pdf-unlock.d.ts +17 -0
- package/dist/scanner/pdf/pdf-unlock.js +50 -0
- package/dist/scanner/pdf/pdf.d.ts +17 -0
- package/dist/scanner/pdf/pdf.js +36 -0
- package/dist/scanner/pdf/state-machine.d.ts +60 -0
- package/dist/scanner/pdf/state-machine.js +64 -0
- package/dist/scanner/pdf/unlock.d.ts +22 -0
- package/dist/scanner/pdf/unlock.js +121 -0
- package/dist/scanner/phase-decrypt.d.ts +10 -0
- package/dist/scanner/phase-decrypt.js +80 -0
- package/dist/scanner/phase-parse.d.ts +10 -0
- package/dist/scanner/phase-parse.js +46 -0
- package/dist/scanner/phases/chunk.d.ts +8 -0
- package/dist/scanner/phases/chunk.js +13 -0
- package/dist/scanner/phases/commit.d.ts +12 -0
- package/dist/scanner/phases/commit.js +140 -0
- package/dist/scanner/phases/decrypt.d.ts +10 -0
- package/dist/scanner/phases/decrypt.js +80 -0
- package/dist/scanner/phases/parse.d.ts +10 -0
- package/dist/scanner/phases/parse.js +46 -0
- package/dist/scanner/phases/resolve.d.ts +10 -0
- package/dist/scanner/phases/resolve.js +17 -0
- package/dist/scanner/phases/review.d.ts +10 -0
- package/dist/scanner/phases/review.js +12 -0
- package/dist/scanner/progress.d.ts +14 -0
- package/dist/scanner/progress.js +21 -0
- package/dist/scanner/resolver-memory.d.ts +8 -0
- package/dist/scanner/resolver-memory.js +24 -0
- package/dist/scanner/resolver.d.ts +39 -0
- package/dist/scanner/resolver.js +196 -0
- package/dist/scanner/result.d.ts +17 -0
- package/dist/scanner/result.js +19 -0
- package/dist/scanner/run-passes.d.ts +30 -0
- package/dist/scanner/run-passes.js +15 -0
- package/dist/scanner/unlock.js +1 -1
- package/dist/scanner/worker.d.ts +19 -0
- package/dist/scanner/worker.js +67 -0
- package/dist/scanner/workers/chunkWorker.d.ts +20 -0
- package/dist/scanner/workers/chunkWorker.js +65 -0
- package/dist/scanner/workers/fileWorker.d.ts +32 -0
- package/dist/scanner/workers/fileWorker.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { runScanAgent } from "../../ai/agent.js";
|
|
3
|
+
import { buildDocumentBlock } from "../pdf.js";
|
|
4
|
+
/**
|
|
5
|
+
* Process one chunk: run the LLM scan agent over a single-page PDF blob with
|
|
6
|
+
* the shared Buffer + chunkId injected. The agent's `record_transactions`
|
|
7
|
+
* calls land in the shared buffer; events fan out to the auditor and the
|
|
8
|
+
* dashboard.
|
|
9
|
+
*/
|
|
10
|
+
export async function runChunkWorker(deps, hooks) {
|
|
11
|
+
const workerId = `cw:${randomUUID()}`;
|
|
12
|
+
hooks.onWorkerStart?.(workerId, deps.chunk);
|
|
13
|
+
const outcome = await tryParseChunk(deps);
|
|
14
|
+
hooks.onWorkerEnd?.(workerId, deps.chunk, outcome.ok);
|
|
15
|
+
if (!outcome.ok)
|
|
16
|
+
await recordChunkFailure(deps.buffer, deps.chunk, outcome.error);
|
|
17
|
+
return { workerId, ...outcome };
|
|
18
|
+
}
|
|
19
|
+
async function tryParseChunk(deps) {
|
|
20
|
+
try {
|
|
21
|
+
await runScanAgent({
|
|
22
|
+
db: deps.db,
|
|
23
|
+
initialMessages: [
|
|
24
|
+
{
|
|
25
|
+
role: "user",
|
|
26
|
+
content: [
|
|
27
|
+
buildDocumentBlock(deps.chunk.bytes, deps.chunk.fileName, deps.chunk.mime),
|
|
28
|
+
{ type: "text", text: buildChunkPrompt(deps.chunk) },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
prompt: { fileName: deps.chunk.fileName },
|
|
33
|
+
agentCtx: {
|
|
34
|
+
interactive: false,
|
|
35
|
+
buffer: deps.buffer,
|
|
36
|
+
chunkId: deps.chunk.chunkId,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
return { ok: true };
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function recordChunkFailure(buffer, chunk, error) {
|
|
46
|
+
await buffer.appendUnknown({
|
|
47
|
+
chunkId: chunk.chunkId,
|
|
48
|
+
transaction_id: null,
|
|
49
|
+
account_id: null,
|
|
50
|
+
kind: "chunk_failed",
|
|
51
|
+
prompt: `Chunk ${chunk.fileName} p${chunk.pageNumber} failed to parse: ${error}.`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function buildChunkPrompt(chunk) {
|
|
55
|
+
return [
|
|
56
|
+
`You are parsing page ${chunk.pageNumber} of ${chunk.totalPages} of ${chunk.fileName}.`,
|
|
57
|
+
``,
|
|
58
|
+
`Steps:`,
|
|
59
|
+
`1. Call list_accounts to see what already exists.`,
|
|
60
|
+
`2. If this page reveals an account that isn't in the chart yet, call create_account once.`,
|
|
61
|
+
`3. For every transaction on this page, call record_transactions (plural) with all rows in one batch.`,
|
|
62
|
+
`4. If the first or last row looks incomplete (no date, or no amount column visible — the row likely continues onto an adjacent page), call note_unknown with kind="boundary_continuation" and the raw row text. Do NOT invent missing fields.`,
|
|
63
|
+
`5. When done with this page, call mark_file_scanned with a short summary.`,
|
|
64
|
+
].join("\n");
|
|
65
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type Database from "libsql";
|
|
2
|
+
import { type ChunkWorkerDeps, type ChunkWorkerResult } from "./chunkWorker.js";
|
|
3
|
+
import type { ScanBuffer } from "../buffer/types.js";
|
|
4
|
+
import type { Chunk, ScanHooks } from "../engine/types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Strategy hook — pluggable parser for one chunk. Default is the LLM-driven
|
|
7
|
+
* runChunkWorker; tests and alternate flows (OCR-only, mock, dry-run) inject
|
|
8
|
+
* their own without modifying the file worker. Open for extension; closed
|
|
9
|
+
* for modification.
|
|
10
|
+
*/
|
|
11
|
+
export type ChunkWorkerFn = (deps: ChunkWorkerDeps, hooks: ScanHooks) => Promise<ChunkWorkerResult>;
|
|
12
|
+
export interface FileWorkerDeps {
|
|
13
|
+
readonly db: Database.Database;
|
|
14
|
+
readonly buffer: ScanBuffer;
|
|
15
|
+
readonly fileId: string;
|
|
16
|
+
readonly chunks: readonly Chunk[];
|
|
17
|
+
readonly maxChunkWorkers: number;
|
|
18
|
+
/** Optional override; defaults to the LLM-backed runChunkWorker. */
|
|
19
|
+
readonly chunkWorkerFn?: ChunkWorkerFn;
|
|
20
|
+
}
|
|
21
|
+
export interface FileWorkerResult {
|
|
22
|
+
readonly workerId: string;
|
|
23
|
+
readonly fileId: string;
|
|
24
|
+
readonly ok: number;
|
|
25
|
+
readonly failed: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Process every chunk of one file in parallel up to `maxChunkWorkers`. The
|
|
29
|
+
* shared buffer + bus are dependency-injected; this function has no global
|
|
30
|
+
* state and never reaches outside its args.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runFileWorker(deps: FileWorkerDeps, hooks: ScanHooks): Promise<FileWorkerResult>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { runWithConcurrency } from "../concurrency.js";
|
|
3
|
+
import { runChunkWorker } from "./chunkWorker.js";
|
|
4
|
+
/**
|
|
5
|
+
* Process every chunk of one file in parallel up to `maxChunkWorkers`. The
|
|
6
|
+
* shared buffer + bus are dependency-injected; this function has no global
|
|
7
|
+
* state and never reaches outside its args.
|
|
8
|
+
*/
|
|
9
|
+
export async function runFileWorker(deps, hooks) {
|
|
10
|
+
const workerId = `fw:${randomUUID()}`;
|
|
11
|
+
const chunkFn = deps.chunkWorkerFn ?? runChunkWorker;
|
|
12
|
+
const tasks = deps.chunks.map(chunk => () => chunkFn({ db: deps.db, buffer: deps.buffer, chunk }, hooks));
|
|
13
|
+
const settled = await runWithConcurrency(tasks, deps.maxChunkWorkers);
|
|
14
|
+
let ok = 0, failed = 0;
|
|
15
|
+
for (const r of settled) {
|
|
16
|
+
if (!r.ok || !r.value.ok)
|
|
17
|
+
failed++;
|
|
18
|
+
else
|
|
19
|
+
ok++;
|
|
20
|
+
}
|
|
21
|
+
return { workerId, fileId: deps.fileId, ok, failed };
|
|
22
|
+
}
|