@isaacriehm/cairn-core 0.4.3 → 0.5.0
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/dist/.tsbuildinfo +1 -1
- package/dist/align-undo/index.d.ts +6 -0
- package/dist/align-undo/index.js +6 -0
- package/dist/align-undo/index.js.map +1 -0
- package/dist/align-undo/log.d.ts +53 -0
- package/dist/align-undo/log.js +99 -0
- package/dist/align-undo/log.js.map +1 -0
- package/dist/align-undo/undo.d.ts +66 -0
- package/dist/align-undo/undo.js +187 -0
- package/dist/align-undo/undo.js.map +1 -0
- package/dist/attention/dedup.js +1 -47
- package/dist/attention/dedup.js.map +1 -1
- package/dist/drain/drain.d.ts +77 -0
- package/dist/drain/drain.js +464 -0
- package/dist/drain/drain.js.map +1 -0
- package/dist/drain/index.d.ts +5 -0
- package/dist/drain/index.js +5 -0
- package/dist/drain/index.js.map +1 -0
- package/dist/fix-align/index.d.ts +5 -0
- package/dist/fix-align/index.js +5 -0
- package/dist/fix-align/index.js.map +1 -0
- package/dist/fix-align/run.d.ts +99 -0
- package/dist/fix-align/run.js +258 -0
- package/dist/fix-align/run.js.map +1 -0
- package/dist/ground/alignment-pending.d.ts +28 -0
- package/dist/ground/alignment-pending.js +83 -0
- package/dist/ground/alignment-pending.js.map +1 -0
- package/dist/ground/anchor-map.d.ts +14 -0
- package/dist/ground/anchor-map.js +57 -0
- package/dist/ground/anchor-map.js.map +1 -0
- package/dist/ground/index.d.ts +9 -2
- package/dist/ground/index.js +8 -2
- package/dist/ground/index.js.map +1 -1
- package/dist/ground/paths.d.ts +21 -0
- package/dist/ground/paths.js +43 -0
- package/dist/ground/paths.js.map +1 -1
- package/dist/ground/schemas.d.ts +201 -0
- package/dist/ground/schemas.js +126 -1
- package/dist/ground/schemas.js.map +1 -1
- package/dist/ground/slug.d.ts +60 -0
- package/dist/ground/slug.js +103 -0
- package/dist/ground/slug.js.map +1 -0
- package/dist/ground/sot-bindings.d.ts +14 -0
- package/dist/ground/sot-bindings.js +80 -0
- package/dist/ground/sot-bindings.js.map +1 -0
- package/dist/ground/sot-cache.d.ts +18 -0
- package/dist/ground/sot-cache.js +63 -0
- package/dist/ground/sot-cache.js.map +1 -0
- package/dist/ground/topic-index.d.ts +20 -0
- package/dist/ground/topic-index.js +60 -0
- package/dist/ground/topic-index.js.map +1 -0
- package/dist/hooks/post-tool-use/index.d.ts +2 -0
- package/dist/hooks/post-tool-use/index.js +1 -0
- package/dist/hooks/post-tool-use/index.js.map +1 -1
- package/dist/hooks/post-tool-use/sot-align.d.ts +166 -0
- package/dist/hooks/post-tool-use/sot-align.js +1311 -0
- package/dist/hooks/post-tool-use/sot-align.js.map +1 -0
- package/dist/hooks/pre-commit/index.d.ts +8 -0
- package/dist/hooks/pre-commit/index.js +8 -0
- package/dist/hooks/pre-commit/index.js.map +1 -0
- package/dist/hooks/pre-commit/sot-align-precommit.d.ts +60 -0
- package/dist/hooks/pre-commit/sot-align-precommit.js +221 -0
- package/dist/hooks/pre-commit/sot-align-precommit.js.map +1 -0
- package/dist/hooks/runners/session-start.js +41 -0
- package/dist/hooks/runners/session-start.js.map +1 -1
- package/dist/hooks/sot-align-common.d.ts +39 -0
- package/dist/hooks/sot-align-common.js +152 -0
- package/dist/hooks/sot-align-common.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/init/index.d.ts +4 -2
- package/dist/init/index.js +2 -1
- package/dist/init/index.js.map +1 -1
- package/dist/init/ingest-docs.d.ts +30 -47
- package/dist/init/ingest-docs.js +113 -410
- package/dist/init/ingest-docs.js.map +1 -1
- package/dist/init/init.d.ts +8 -0
- package/dist/init/init.js +58 -29
- package/dist/init/init.js.map +1 -1
- package/dist/init/phases/5-brand.js +1 -1
- package/dist/init/phases/5-brand.js.map +1 -1
- package/dist/init/phases/5b-topic-index.d.ts +30 -0
- package/dist/init/phases/5b-topic-index.js +62 -0
- package/dist/init/phases/5b-topic-index.js.map +1 -0
- package/dist/init/phases/6-docs-ingest.d.ts +4 -5
- package/dist/init/phases/6-docs-ingest.js +5 -6
- package/dist/init/phases/6-docs-ingest.js.map +1 -1
- package/dist/init/phases/index.d.ts +2 -0
- package/dist/init/phases/index.js +1 -0
- package/dist/init/phases/index.js.map +1 -1
- package/dist/init/phases/parallel-678.d.ts +14 -17
- package/dist/init/phases/parallel-678.js +77 -98
- package/dist/init/phases/parallel-678.js.map +1 -1
- package/dist/init/phases/source-comments-output-io.d.ts +16 -10
- package/dist/init/phases/source-comments-output-io.js +7 -10
- package/dist/init/phases/source-comments-output-io.js.map +1 -1
- package/dist/init/phases/types.d.ts +1 -1
- package/dist/init/phases/types.js +1 -0
- package/dist/init/phases/types.js.map +1 -1
- package/dist/init/rules-merge/discover.d.ts +8 -3
- package/dist/init/rules-merge/discover.js +7 -3
- package/dist/init/rules-merge/discover.js.map +1 -1
- package/dist/init/rules-merge/ingest.d.ts +81 -28
- package/dist/init/rules-merge/ingest.js +456 -162
- package/dist/init/rules-merge/ingest.js.map +1 -1
- package/dist/init/sot-emit.d.ts +84 -0
- package/dist/init/sot-emit.js +218 -0
- package/dist/init/sot-emit.js.map +1 -0
- package/dist/init/source-comments/classify.d.ts +12 -10
- package/dist/init/source-comments/classify.js +13 -25
- package/dist/init/source-comments/classify.js.map +1 -1
- package/dist/init/source-comments/index.d.ts +1 -1
- package/dist/init/source-comments/index.js +1 -1
- package/dist/init/source-comments/index.js.map +1 -1
- package/dist/init/source-comments/ingest.d.ts +91 -67
- package/dist/init/source-comments/ingest.js +392 -361
- package/dist/init/source-comments/ingest.js.map +1 -1
- package/dist/init/topic-index/index.d.ts +36 -0
- package/dist/init/topic-index/index.js +46 -0
- package/dist/init/topic-index/index.js.map +1 -0
- package/dist/init/topic-index/judge.d.ts +20 -0
- package/dist/init/topic-index/judge.js +65 -0
- package/dist/init/topic-index/judge.js.map +1 -0
- package/dist/init/topic-index/resolve.d.ts +50 -0
- package/dist/init/topic-index/resolve.js +196 -0
- package/dist/init/topic-index/resolve.js.map +1 -0
- package/dist/init/topic-index/walk.d.ts +43 -0
- package/dist/init/topic-index/walk.js +293 -0
- package/dist/init/topic-index/walk.js.map +1 -0
- package/dist/mcp/schemas.d.ts +45 -8
- package/dist/mcp/schemas.js +43 -7
- package/dist/mcp/schemas.js.map +1 -1
- package/dist/mcp/tools/align-drain.d.ts +7 -0
- package/dist/mcp/tools/align-drain.js +26 -0
- package/dist/mcp/tools/align-drain.js.map +1 -0
- package/dist/mcp/tools/index.js +3 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/init-phases.js +4 -1
- package/dist/mcp/tools/init-phases.js.map +1 -1
- package/dist/mcp/tools/resolve-attention.d.ts +2 -2
- package/dist/mcp/tools/resolve-attention.js +828 -5
- package/dist/mcp/tools/resolve-attention.js.map +1 -1
- package/dist/status-line/event-queue.d.ts +40 -0
- package/dist/status-line/event-queue.js +195 -0
- package/dist/status-line/event-queue.js.map +1 -0
- package/dist/status-line/format.d.ts +1 -1
- package/dist/status-line/format.js +49 -6
- package/dist/status-line/format.js.map +1 -1
- package/dist/status-line/index.d.ts +41 -0
- package/dist/status-line/index.js +14 -0
- package/dist/status-line/index.js.map +1 -1
- package/dist/status-line/reader.js +23 -18
- package/dist/status-line/reader.js.map +1 -1
- package/dist/status-line/writer.d.ts +1 -1
- package/dist/status-line/writer.js +5 -0
- package/dist/status-line/writer.js.map +1 -1
- package/dist/text/jaccard.d.ts +19 -0
- package/dist/text/jaccard.js +68 -0
- package/dist/text/jaccard.js.map +1 -0
- package/package.json +1 -1
- package/templates/.cairn/git-hooks/pre-commit +16 -3
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer A undo log + `cairn attention undo` runner. Plan §11.7.
|
|
3
|
+
*/
|
|
4
|
+
export { AlignUndoEntry, alignUndoLogPath, appendAlignUndoEntry, pruneAlignUndoLog, readAlignUndoLog, } from "./log.js";
|
|
5
|
+
export { runAttentionUndo } from "./undo.js";
|
|
6
|
+
export type { UndoArgs, UndoEntryOutcome, UndoResult } from "./undo.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer A undo log + `cairn attention undo` runner. Plan §11.7.
|
|
3
|
+
*/
|
|
4
|
+
export { AlignUndoEntry, alignUndoLogPath, appendAlignUndoEntry, pruneAlignUndoLog, readAlignUndoLog, } from "./log.js";
|
|
5
|
+
export { runAttentionUndo } from "./undo.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/align-undo/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer A audit log for `cairn attention undo` (plan §11.7).
|
|
3
|
+
*
|
|
4
|
+
* Every Layer A auto-resolution (Tier 1 cite, Tier 2 same cite, Tier 3
|
|
5
|
+
* fresh DEC creation, augments-DEC/INV emission) appends one line to
|
|
6
|
+
* `.cairn/state/align-undo-log.jsonl`. The CLI command
|
|
7
|
+
* `cairn attention undo [--since <duration>]` reads recent entries and
|
|
8
|
+
* reverses them.
|
|
9
|
+
*
|
|
10
|
+
* The deviation from plan §11.7's literal "reads invalidation events
|
|
11
|
+
* from `.cairn/events/`" — invalidation events are designed for
|
|
12
|
+
* cross-session broadcast (kind, refs, source), not for carrying the
|
|
13
|
+
* (file, offset, original_raw) metadata that undo needs. Keeping the
|
|
14
|
+
* undo log separate avoids polluting the broadcast surface and lets
|
|
15
|
+
* the GC retention policy stay independent.
|
|
16
|
+
*
|
|
17
|
+
* Truncation policy: `cairn attention undo` rewrites the log keeping
|
|
18
|
+
* only entries OUTSIDE the undo window so re-running `undo` against
|
|
19
|
+
* the same window is idempotent.
|
|
20
|
+
*/
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
export declare const AlignUndoEntry: z.ZodObject<{
|
|
23
|
+
ts: z.ZodString;
|
|
24
|
+
session_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
|
+
kind: z.ZodEnum<{
|
|
26
|
+
"tier1-cite": "tier1-cite";
|
|
27
|
+
"tier2-cite": "tier2-cite";
|
|
28
|
+
"tier3-creation": "tier3-creation";
|
|
29
|
+
augments: "augments";
|
|
30
|
+
}>;
|
|
31
|
+
file: z.ZodString;
|
|
32
|
+
start_offset: z.ZodNumber;
|
|
33
|
+
end_offset: z.ZodNumber;
|
|
34
|
+
original_raw: z.ZodString;
|
|
35
|
+
replacement: z.ZodString;
|
|
36
|
+
primary_id: z.ZodString;
|
|
37
|
+
primary_kind: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
DEC: "DEC";
|
|
39
|
+
INV: "INV";
|
|
40
|
+
}>>;
|
|
41
|
+
augments_existing_id: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type AlignUndoEntry = z.infer<typeof AlignUndoEntry>;
|
|
44
|
+
export declare function alignUndoLogPath(repoRoot: string): string;
|
|
45
|
+
export declare function appendAlignUndoEntry(repoRoot: string, entry: AlignUndoEntry): void;
|
|
46
|
+
export declare function readAlignUndoLog(repoRoot: string): AlignUndoEntry[];
|
|
47
|
+
/**
|
|
48
|
+
* Rewrite the undo log keeping only the entries NOT in `undone`.
|
|
49
|
+
* Idempotency: running `cairn attention undo --since <window>` twice
|
|
50
|
+
* on the same window does nothing the second time because the entries
|
|
51
|
+
* inside the window have already been removed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function pruneAlignUndoLog(repoRoot: string, remaining: AlignUndoEntry[]): void;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer A audit log for `cairn attention undo` (plan §11.7).
|
|
3
|
+
*
|
|
4
|
+
* Every Layer A auto-resolution (Tier 1 cite, Tier 2 same cite, Tier 3
|
|
5
|
+
* fresh DEC creation, augments-DEC/INV emission) appends one line to
|
|
6
|
+
* `.cairn/state/align-undo-log.jsonl`. The CLI command
|
|
7
|
+
* `cairn attention undo [--since <duration>]` reads recent entries and
|
|
8
|
+
* reverses them.
|
|
9
|
+
*
|
|
10
|
+
* The deviation from plan §11.7's literal "reads invalidation events
|
|
11
|
+
* from `.cairn/events/`" — invalidation events are designed for
|
|
12
|
+
* cross-session broadcast (kind, refs, source), not for carrying the
|
|
13
|
+
* (file, offset, original_raw) metadata that undo needs. Keeping the
|
|
14
|
+
* undo log separate avoids polluting the broadcast surface and lets
|
|
15
|
+
* the GC retention policy stay independent.
|
|
16
|
+
*
|
|
17
|
+
* Truncation policy: `cairn attention undo` rewrites the log keeping
|
|
18
|
+
* only entries OUTSIDE the undo window so re-running `undo` against
|
|
19
|
+
* the same window is idempotent.
|
|
20
|
+
*/
|
|
21
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
import { logger } from "../logger.js";
|
|
25
|
+
const log = logger("align-undo.log");
|
|
26
|
+
export const AlignUndoEntry = z.object({
|
|
27
|
+
ts: z.string(),
|
|
28
|
+
session_id: z.string().nullable().optional(),
|
|
29
|
+
kind: z.enum(["tier1-cite", "tier2-cite", "tier3-creation", "augments"]),
|
|
30
|
+
file: z.string(),
|
|
31
|
+
start_offset: z.number(),
|
|
32
|
+
end_offset: z.number(),
|
|
33
|
+
/** Original prose block raw (incl. comment delimiters) before strip-replace. */
|
|
34
|
+
original_raw: z.string(),
|
|
35
|
+
/** Replacement that was inserted (e.g. `// §DEC-1234567`). */
|
|
36
|
+
replacement: z.string(),
|
|
37
|
+
/** DEC/INV id cited (tier1/tier2 cite) or freshly emitted (tier3 / augments). */
|
|
38
|
+
primary_id: z.string(),
|
|
39
|
+
/** For tier3-creation: was the freshly-emitted entity a DEC or INV? */
|
|
40
|
+
primary_kind: z.enum(["DEC", "INV"]).optional(),
|
|
41
|
+
/** For augments: the existing entity id that was augmented (its cite stays). */
|
|
42
|
+
augments_existing_id: z.string().optional(),
|
|
43
|
+
});
|
|
44
|
+
export function alignUndoLogPath(repoRoot) {
|
|
45
|
+
return join(repoRoot, ".cairn", "state", "align-undo-log.jsonl");
|
|
46
|
+
}
|
|
47
|
+
export function appendAlignUndoEntry(repoRoot, entry) {
|
|
48
|
+
const validated = AlignUndoEntry.parse(entry);
|
|
49
|
+
const path = alignUndoLogPath(repoRoot);
|
|
50
|
+
try {
|
|
51
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
52
|
+
appendFileSync(path, `${JSON.stringify(validated)}\n`, "utf8");
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
log.warn({ err: err instanceof Error ? err.message : String(err) }, "align-undo log append failed");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function readAlignUndoLog(repoRoot) {
|
|
59
|
+
const path = alignUndoLogPath(repoRoot);
|
|
60
|
+
if (!existsSync(path))
|
|
61
|
+
return [];
|
|
62
|
+
const text = readFileSync(path, "utf8");
|
|
63
|
+
if (text.trim().length === 0)
|
|
64
|
+
return [];
|
|
65
|
+
const out = [];
|
|
66
|
+
for (const line of text.split("\n")) {
|
|
67
|
+
const trimmed = line.trim();
|
|
68
|
+
if (trimmed.length === 0)
|
|
69
|
+
continue;
|
|
70
|
+
try {
|
|
71
|
+
out.push(AlignUndoEntry.parse(JSON.parse(trimmed)));
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
log.warn({ err: err instanceof Error ? err.message : String(err) }, "skipping malformed align-undo entry");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Rewrite the undo log keeping only the entries NOT in `undone`.
|
|
81
|
+
* Idempotency: running `cairn attention undo --since <window>` twice
|
|
82
|
+
* on the same window does nothing the second time because the entries
|
|
83
|
+
* inside the window have already been removed.
|
|
84
|
+
*/
|
|
85
|
+
export function pruneAlignUndoLog(repoRoot, remaining) {
|
|
86
|
+
const path = alignUndoLogPath(repoRoot);
|
|
87
|
+
try {
|
|
88
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
89
|
+
if (remaining.length === 0) {
|
|
90
|
+
writeFileSync(path, "", "utf8");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
writeFileSync(path, `${remaining.map((e) => JSON.stringify(e)).join("\n")}\n`, "utf8");
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
log.warn({ err: err instanceof Error ? err.message : String(err) }, "align-undo log prune failed");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/align-undo/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cairn attention undo` runner (plan §11.7).
|
|
3
|
+
*
|
|
4
|
+
* Reverses Layer A auto-resolutions logged at
|
|
5
|
+
* `.cairn/state/align-undo-log.jsonl`. The CLI passes `--since
|
|
6
|
+
* <duration>` (default 1h); only entries within the window are
|
|
7
|
+
* undone, the rest stay in the log.
|
|
8
|
+
*
|
|
9
|
+
* Currently reverses:
|
|
10
|
+
*
|
|
11
|
+
* - `tier1-cite` / `tier2-cite` — find the cite line in the current
|
|
12
|
+
* source, swap it back for the original prose block. Idempotent
|
|
13
|
+
* when the source has been hand-edited away from the cite already.
|
|
14
|
+
*
|
|
15
|
+
* Out of scope for v0.5.0 (deferred to v0.6 — these need targeted
|
|
16
|
+
* ledger surgery + sotBindings/sotCache rollback):
|
|
17
|
+
*
|
|
18
|
+
* - `tier3-creation` — would need to delete the DEC/INV file, drop
|
|
19
|
+
* its sotBindings / sotCache / topic-index entries, refresh the
|
|
20
|
+
* ledger, and restore the source. Reported in the undo summary
|
|
21
|
+
* so the operator can hand-resolve.
|
|
22
|
+
*
|
|
23
|
+
* - `augments` — would need to delete the sibling DEC/INV and
|
|
24
|
+
* remove its cite from the double-cite while keeping the
|
|
25
|
+
* existing-id cite in place.
|
|
26
|
+
*
|
|
27
|
+
* Idempotent: the runner truncates undone entries from the log so a
|
|
28
|
+
* second invocation against the same window is a no-op.
|
|
29
|
+
*/
|
|
30
|
+
import { type AlignUndoEntry } from "./log.js";
|
|
31
|
+
export interface UndoArgs {
|
|
32
|
+
repoRoot: string;
|
|
33
|
+
/**
|
|
34
|
+
* Wall-clock window. Entries with `ts` newer than `now - sinceMs`
|
|
35
|
+
* are undone. Default 1h.
|
|
36
|
+
*/
|
|
37
|
+
sinceMs?: number;
|
|
38
|
+
/** Dry-run: classify entries but do not modify source / log. */
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface UndoEntryOutcome {
|
|
42
|
+
entry: AlignUndoEntry;
|
|
43
|
+
/**
|
|
44
|
+
* - `reverted` — source was rewritten back to the original prose.
|
|
45
|
+
* - `already-reverted`— the cite token is no longer in source (operator beat us).
|
|
46
|
+
* - `not-supported` — kind requires manual surgery (tier3-creation, augments).
|
|
47
|
+
* - `source-missing` — source file no longer exists.
|
|
48
|
+
* - `error` — write failed (logged + reported).
|
|
49
|
+
*/
|
|
50
|
+
status: "reverted" | "already-reverted" | "not-supported" | "source-missing" | "error";
|
|
51
|
+
detail?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface UndoResult {
|
|
54
|
+
/** Total entries inside the undo window. */
|
|
55
|
+
windowEntries: number;
|
|
56
|
+
/** Entries left in the log because they were outside the window. */
|
|
57
|
+
outsideWindow: number;
|
|
58
|
+
/** Per-entry outcomes for everything inside the window. */
|
|
59
|
+
outcomes: UndoEntryOutcome[];
|
|
60
|
+
reverted: number;
|
|
61
|
+
alreadyReverted: number;
|
|
62
|
+
notSupported: number;
|
|
63
|
+
sourceMissing: number;
|
|
64
|
+
errors: number;
|
|
65
|
+
}
|
|
66
|
+
export declare function runAttentionUndo(args: UndoArgs): Promise<UndoResult>;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cairn attention undo` runner (plan §11.7).
|
|
3
|
+
*
|
|
4
|
+
* Reverses Layer A auto-resolutions logged at
|
|
5
|
+
* `.cairn/state/align-undo-log.jsonl`. The CLI passes `--since
|
|
6
|
+
* <duration>` (default 1h); only entries within the window are
|
|
7
|
+
* undone, the rest stay in the log.
|
|
8
|
+
*
|
|
9
|
+
* Currently reverses:
|
|
10
|
+
*
|
|
11
|
+
* - `tier1-cite` / `tier2-cite` — find the cite line in the current
|
|
12
|
+
* source, swap it back for the original prose block. Idempotent
|
|
13
|
+
* when the source has been hand-edited away from the cite already.
|
|
14
|
+
*
|
|
15
|
+
* Out of scope for v0.5.0 (deferred to v0.6 — these need targeted
|
|
16
|
+
* ledger surgery + sotBindings/sotCache rollback):
|
|
17
|
+
*
|
|
18
|
+
* - `tier3-creation` — would need to delete the DEC/INV file, drop
|
|
19
|
+
* its sotBindings / sotCache / topic-index entries, refresh the
|
|
20
|
+
* ledger, and restore the source. Reported in the undo summary
|
|
21
|
+
* so the operator can hand-resolve.
|
|
22
|
+
*
|
|
23
|
+
* - `augments` — would need to delete the sibling DEC/INV and
|
|
24
|
+
* remove its cite from the double-cite while keeping the
|
|
25
|
+
* existing-id cite in place.
|
|
26
|
+
*
|
|
27
|
+
* Idempotent: the runner truncates undone entries from the log so a
|
|
28
|
+
* second invocation against the same window is a no-op.
|
|
29
|
+
*/
|
|
30
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
31
|
+
import { join } from "node:path";
|
|
32
|
+
import { logger } from "../logger.js";
|
|
33
|
+
import { pruneAlignUndoLog, readAlignUndoLog, } from "./log.js";
|
|
34
|
+
const log = logger("align-undo.runner");
|
|
35
|
+
const DEFAULT_SINCE_MS = 60 * 60 * 1_000;
|
|
36
|
+
/* -------------------------------------------------------------------------- */
|
|
37
|
+
/* Run */
|
|
38
|
+
/* -------------------------------------------------------------------------- */
|
|
39
|
+
export async function runAttentionUndo(args) {
|
|
40
|
+
const { repoRoot } = args;
|
|
41
|
+
const sinceMs = args.sinceMs ?? DEFAULT_SINCE_MS;
|
|
42
|
+
const dryRun = args.dryRun === true;
|
|
43
|
+
const cutoff = Date.now() - sinceMs;
|
|
44
|
+
const all = readAlignUndoLog(repoRoot);
|
|
45
|
+
const inside = [];
|
|
46
|
+
const outside = [];
|
|
47
|
+
for (const e of all) {
|
|
48
|
+
const tsMs = Date.parse(e.ts);
|
|
49
|
+
if (Number.isFinite(tsMs) && tsMs >= cutoff) {
|
|
50
|
+
inside.push(e);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
outside.push(e);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const outcomes = [];
|
|
57
|
+
// Process newest first — undoing in reverse order matches typical
|
|
58
|
+
// operator intent ("undo my last 5 minutes of cites").
|
|
59
|
+
inside.sort((a, b) => Date.parse(b.ts) - Date.parse(a.ts));
|
|
60
|
+
for (const entry of inside) {
|
|
61
|
+
outcomes.push(reverseEntry(repoRoot, entry, dryRun));
|
|
62
|
+
}
|
|
63
|
+
const result = {
|
|
64
|
+
windowEntries: inside.length,
|
|
65
|
+
outsideWindow: outside.length,
|
|
66
|
+
outcomes,
|
|
67
|
+
reverted: outcomes.filter((o) => o.status === "reverted").length,
|
|
68
|
+
alreadyReverted: outcomes.filter((o) => o.status === "already-reverted").length,
|
|
69
|
+
notSupported: outcomes.filter((o) => o.status === "not-supported").length,
|
|
70
|
+
sourceMissing: outcomes.filter((o) => o.status === "source-missing").length,
|
|
71
|
+
errors: outcomes.filter((o) => o.status === "error").length,
|
|
72
|
+
};
|
|
73
|
+
if (!dryRun) {
|
|
74
|
+
// Keep entries that we couldn't undo (not-supported / errors) so
|
|
75
|
+
// the operator can re-attempt or hand-resolve. Entries we
|
|
76
|
+
// reverted (or that were already reverted) are removed.
|
|
77
|
+
const keep = [
|
|
78
|
+
...outside,
|
|
79
|
+
...outcomes
|
|
80
|
+
.filter((o) => o.status === "not-supported" || o.status === "error")
|
|
81
|
+
.map((o) => o.entry),
|
|
82
|
+
];
|
|
83
|
+
pruneAlignUndoLog(repoRoot, keep);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
/* -------------------------------------------------------------------------- */
|
|
88
|
+
/* Per-entry reversal */
|
|
89
|
+
/* -------------------------------------------------------------------------- */
|
|
90
|
+
function reverseEntry(repoRoot, entry, dryRun) {
|
|
91
|
+
if (entry.kind === "tier3-creation" || entry.kind === "augments") {
|
|
92
|
+
return {
|
|
93
|
+
entry,
|
|
94
|
+
status: "not-supported",
|
|
95
|
+
detail: entry.kind === "tier3-creation"
|
|
96
|
+
? "fresh DEC/INV creation undo deferred to v0.6 — manually delete the entity file and restore the source block"
|
|
97
|
+
: "augments-sibling undo deferred to v0.6 — manually delete the sibling and trim the double-cite",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const abs = join(repoRoot, entry.file);
|
|
101
|
+
if (!existsSync(abs)) {
|
|
102
|
+
return { entry, status: "source-missing", detail: `${entry.file} no longer exists` };
|
|
103
|
+
}
|
|
104
|
+
let source;
|
|
105
|
+
try {
|
|
106
|
+
source = readFileSync(abs, "utf8");
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return {
|
|
110
|
+
entry,
|
|
111
|
+
status: "error",
|
|
112
|
+
detail: `cannot read ${entry.file}: ${err instanceof Error ? err.message : String(err)}`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Locate the cite line in the current source. The exact byte offsets
|
|
116
|
+
// recorded at log-time are stale (the strip-replace re-flowed the
|
|
117
|
+
// file), so we search for the literal replacement string instead.
|
|
118
|
+
const replacement = entry.replacement.trimEnd();
|
|
119
|
+
const idx = source.indexOf(replacement);
|
|
120
|
+
if (idx === -1) {
|
|
121
|
+
// Already hand-edited away — operator removed the cite themselves.
|
|
122
|
+
return {
|
|
123
|
+
entry,
|
|
124
|
+
status: "already-reverted",
|
|
125
|
+
detail: `cite "${replacement.trim()}" not found in ${entry.file}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Swap the replacement (matched + any trailing whitespace until newline) for the original raw.
|
|
129
|
+
// Replacement is typically a one-liner like "// §DEC-aaaaaaa"; we
|
|
130
|
+
// want to preserve indentation if the original raw had any.
|
|
131
|
+
const lineStart = source.lastIndexOf("\n", idx) + 1;
|
|
132
|
+
const lineEnd = source.indexOf("\n", idx + replacement.length);
|
|
133
|
+
const cutEnd = lineEnd === -1 ? source.length : lineEnd;
|
|
134
|
+
const before = source.slice(0, lineStart);
|
|
135
|
+
const after = source.slice(cutEnd);
|
|
136
|
+
// Match the indentation that strip-replace prepended on the cite —
|
|
137
|
+
// leading whitespace from `lineStart` up to the `idx`.
|
|
138
|
+
const indent = source.slice(lineStart, idx);
|
|
139
|
+
const reflowedOriginal = reapplyIndent(entry.original_raw, indent);
|
|
140
|
+
const next = `${before}${reflowedOriginal}${after}`;
|
|
141
|
+
if (!dryRun) {
|
|
142
|
+
try {
|
|
143
|
+
writeFileSync(abs, next, "utf8");
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
log.warn({ file: entry.file, err: err instanceof Error ? err.message : String(err) }, "align-undo write failed");
|
|
147
|
+
return {
|
|
148
|
+
entry,
|
|
149
|
+
status: "error",
|
|
150
|
+
detail: `cannot write ${entry.file}: ${err instanceof Error ? err.message : String(err)}`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { entry, status: "reverted", detail: `${entry.file}` };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Re-apply the leading indent that the cite line carried so the
|
|
158
|
+
* restored original block lines up at the right column. Most blocks'
|
|
159
|
+
* raw already includes the full indentation — we only prepend `indent`
|
|
160
|
+
* to lines that start without it, which handles JSDoc / line-comment
|
|
161
|
+
* blocks captured at column 0.
|
|
162
|
+
*/
|
|
163
|
+
function reapplyIndent(raw, indent) {
|
|
164
|
+
if (indent.length === 0)
|
|
165
|
+
return raw;
|
|
166
|
+
const lines = raw.split("\n");
|
|
167
|
+
const out = [];
|
|
168
|
+
let isFirst = true;
|
|
169
|
+
for (const line of lines) {
|
|
170
|
+
if (isFirst) {
|
|
171
|
+
out.push(line);
|
|
172
|
+
isFirst = false;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (line.length === 0) {
|
|
176
|
+
out.push(line);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (line.startsWith(indent) || /^\s/.test(line)) {
|
|
180
|
+
out.push(line);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
out.push(`${indent}${line}`);
|
|
184
|
+
}
|
|
185
|
+
return out.join("\n");
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=undo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/align-undo/undo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,GAEjB,MAAM,UAAU,CAAC;AAElB,MAAM,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAiDxC,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AAEzC,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAc;IACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IAEpC,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,kEAAkE;IAClE,uDAAuD;IACvD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,aAAa,EAAE,MAAM,CAAC,MAAM;QAC5B,aAAa,EAAE,OAAO,CAAC,MAAM;QAC7B,QAAQ;QACR,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM;QAChE,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC,MAAM;QAC/E,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC,MAAM;QACzE,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC,MAAM;QAC3E,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM;KAC5D,CAAC;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,iEAAiE;QACjE,0DAA0D;QAC1D,wDAAwD;QACxD,MAAM,IAAI,GAAqB;YAC7B,GAAG,OAAO;YACV,GAAG,QAAQ;iBACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,eAAe,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC;iBACnE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SACvB,CAAC;QACF,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEhF,SAAS,YAAY,CACnB,QAAgB,EAChB,KAAqB,EACrB,MAAe;IAEf,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACjE,OAAO;YACL,KAAK;YACL,MAAM,EAAE,eAAe;YACvB,MAAM,EACJ,KAAK,CAAC,IAAI,KAAK,gBAAgB;gBAC7B,CAAC,CAAC,6GAA6G;gBAC/G,CAAC,CAAC,+FAA+F;SACtG,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,mBAAmB,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,KAAK;YACL,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,eAAe,KAAK,CAAC,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SACzF,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,kEAAkE;IAClE,kEAAkE;IAClE,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,mEAAmE;QACnE,OAAO;YACL,KAAK;YACL,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,SAAS,WAAW,CAAC,IAAI,EAAE,kBAAkB,KAAK,CAAC,IAAI,EAAE;SAClE,CAAC;IACJ,CAAC;IAED,+FAA+F;IAC/F,kEAAkE;IAClE,4DAA4D;IAC5D,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,mEAAmE;IACnE,uDAAuD;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC5C,MAAM,gBAAgB,GAAG,aAAa,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,GAAG,MAAM,GAAG,gBAAgB,GAAG,KAAK,EAAE,CAAC;IAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CACN,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3E,yBAAyB,CAC1B,CAAC;YACF,OAAO;gBACL,KAAK;gBACL,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,gBAAgB,KAAK,CAAC,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;aAC1F,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,GAAW,EAAE,MAAc;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACpC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}
|
package/dist/attention/dedup.js
CHANGED
|
@@ -20,55 +20,9 @@
|
|
|
20
20
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { decisionsDir } from "../ground/paths.js";
|
|
23
|
-
|
|
24
|
-
/* Tokenization */
|
|
25
|
-
/* -------------------------------------------------------------------------- */
|
|
26
|
-
/**
|
|
27
|
-
* Stopwords. Hard-coded English set plus a handful of cairn-domain
|
|
28
|
-
* terms that appear in nearly every draft and would otherwise dominate
|
|
29
|
-
* Jaccard scores ("rationale", "decision").
|
|
30
|
-
*/
|
|
31
|
-
const STOPWORDS = new Set([
|
|
32
|
-
"the", "a", "an", "and", "or", "of", "in", "on", "to", "for", "with",
|
|
33
|
-
"by", "from", "is", "are", "was", "were", "be", "been", "being", "has",
|
|
34
|
-
"have", "had", "do", "does", "did", "this", "that", "these", "those",
|
|
35
|
-
"it", "its", "as", "at", "but", "if", "than", "so", "use", "used",
|
|
36
|
-
"using", "via", "out", "off", "up", "our", "their", "one", "two",
|
|
37
|
-
"when", "where", "what", "how", "why", "who", "which", "can", "should",
|
|
38
|
-
"must", "will", "shall", "may", "not", "no", "any", "all", "some",
|
|
39
|
-
"few", "more", "most", "only", "also",
|
|
40
|
-
]);
|
|
23
|
+
import { jaccard, tokenize } from "../text/jaccard.js";
|
|
41
24
|
/** Default char window of body to fold into the token bag. */
|
|
42
25
|
const BODY_CHAR_WINDOW = 500;
|
|
43
|
-
function stem(w) {
|
|
44
|
-
if (w.length <= 4)
|
|
45
|
-
return w;
|
|
46
|
-
if (w.endsWith("ing"))
|
|
47
|
-
return w.slice(0, -3);
|
|
48
|
-
if (w.endsWith("ed"))
|
|
49
|
-
return w.slice(0, -2);
|
|
50
|
-
if (w.endsWith("s") && !w.endsWith("ss"))
|
|
51
|
-
return w.slice(0, -1);
|
|
52
|
-
return w;
|
|
53
|
-
}
|
|
54
|
-
function tokenize(text) {
|
|
55
|
-
return new Set(text
|
|
56
|
-
.toLowerCase()
|
|
57
|
-
.replace(/[^a-z0-9\s]/g, " ")
|
|
58
|
-
.split(/\s+/)
|
|
59
|
-
.map(stem)
|
|
60
|
-
.filter((w) => w.length >= 3 && !STOPWORDS.has(w)));
|
|
61
|
-
}
|
|
62
|
-
function jaccard(a, b) {
|
|
63
|
-
if (a.size === 0 && b.size === 0)
|
|
64
|
-
return 0;
|
|
65
|
-
let inter = 0;
|
|
66
|
-
for (const x of a)
|
|
67
|
-
if (b.has(x))
|
|
68
|
-
inter += 1;
|
|
69
|
-
const union = a.size + b.size - inter;
|
|
70
|
-
return union === 0 ? 0 : inter / union;
|
|
71
|
-
}
|
|
72
26
|
function parseMinimalFrontmatter(raw) {
|
|
73
27
|
const m = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
74
28
|
if (m === null || m[1] === undefined || m[2] === undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/attention/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/attention/dedup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer C — SessionStart drain (plan §4.3).
|
|
3
|
+
*
|
|
4
|
+
* Reads the rich deferred logs written by Layer A
|
|
5
|
+
* (`.cairn/staleness/layer-a-deferred.jsonl`) and Layer B
|
|
6
|
+
* (`.cairn/staleness/pre-commit-deferred.jsonl`), re-checks each entry
|
|
7
|
+
* against the current source location, and applies one of three
|
|
8
|
+
* verdicts to each surviving entry:
|
|
9
|
+
*
|
|
10
|
+
* - `same` → strip-replace the prose block with `// §DEC-<id>`
|
|
11
|
+
* cite. Pure deterministic for Layer B `tier1`
|
|
12
|
+
* entries (the pre-commit hook already passed the
|
|
13
|
+
* Tier 1 floors); Haiku-judged for everything else.
|
|
14
|
+
* - `different` → drop the entry, no source change.
|
|
15
|
+
* - `ambiguous` → write to `.cairn/ground/alignment-pending/` so
|
|
16
|
+
* the cairn-attention skill surfaces a side-by-side
|
|
17
|
+
* review next session.
|
|
18
|
+
*
|
|
19
|
+
* Drain truncates both deferred logs after running. The lightweight
|
|
20
|
+
* drift events in `.cairn/staleness/log.jsonl` are an audit trail and
|
|
21
|
+
* stay.
|
|
22
|
+
*
|
|
23
|
+
* Cost: capped at `max_haiku_calls` (default 30 per plan §4.3 budget).
|
|
24
|
+
* Excess entries stay in the deferred logs for the next drain. Each
|
|
25
|
+
* Haiku call is verdict-cached at
|
|
26
|
+
* `.cairn/cache/haiku/drain-judge/<blockHash>-<decId>.json` keyed on
|
|
27
|
+
* `(block_content_hash, dec_body_hash)`, so re-running the same block
|
|
28
|
+
* against the same DEC body short-circuits without burning a call.
|
|
29
|
+
*
|
|
30
|
+
* Haiku unavailable fallback: drain attempts the deterministic re-check
|
|
31
|
+
* pass only (Layer B tier1 entries get applied; everything else stays
|
|
32
|
+
* deferred). `setHaikuAvailable(false)` raises the statusline banner.
|
|
33
|
+
*/
|
|
34
|
+
export type DrainJudgeVerdict = "same" | "different" | "ambiguous";
|
|
35
|
+
export interface DrainArgs {
|
|
36
|
+
repoRoot: string;
|
|
37
|
+
/** When provided, drain pushes drain-progress / drain-done blips to this session's queue. */
|
|
38
|
+
sessionId?: string | null;
|
|
39
|
+
/** Hard cap on Haiku judge calls. Default 30 (plan §4.3). */
|
|
40
|
+
maxHaikuCalls?: number;
|
|
41
|
+
/** Dry run — classify but do not strip-replace, write alignment-pending, or truncate logs. */
|
|
42
|
+
dryRun?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Inject the dedup judge — bypasses the live Haiku call. Used by
|
|
45
|
+
* smoke fixtures and the `cairn align drain --mock` debug path.
|
|
46
|
+
*/
|
|
47
|
+
mockJudge?: (args: {
|
|
48
|
+
blockBody: string;
|
|
49
|
+
candidate: {
|
|
50
|
+
id: string;
|
|
51
|
+
body: string;
|
|
52
|
+
};
|
|
53
|
+
}) => Promise<DrainJudgeVerdict>;
|
|
54
|
+
/** Override Haiku availability detection (smoke fixtures). */
|
|
55
|
+
haikuAvailable?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface DrainResult {
|
|
58
|
+
/** Total entries read from both deferred logs. */
|
|
59
|
+
totalEntries: number;
|
|
60
|
+
/** Entries whose source block could not be relocated (gone / edited / cited). */
|
|
61
|
+
droppedMissing: number;
|
|
62
|
+
/** Entries auto-cited via deterministic re-check (Layer B tier1). */
|
|
63
|
+
citedDeterministic: number;
|
|
64
|
+
/** Entries auto-cited via Haiku `same` verdict. */
|
|
65
|
+
citedHaiku: number;
|
|
66
|
+
/** Entries dropped via Haiku `different` verdict. */
|
|
67
|
+
droppedDifferent: number;
|
|
68
|
+
/** Entries written to alignment-pending via Haiku `ambiguous` verdict. */
|
|
69
|
+
pending: number;
|
|
70
|
+
/** Entries left in the deferred logs because the Haiku cap was hit or Haiku is offline. */
|
|
71
|
+
deferred: number;
|
|
72
|
+
/** Total Haiku calls actually issued (cache hits do not count). */
|
|
73
|
+
haikuCalls: number;
|
|
74
|
+
/** True when the drain ran without Haiku (fallback path). */
|
|
75
|
+
haikuFallback: boolean;
|
|
76
|
+
}
|
|
77
|
+
export declare function runDrain(args: DrainArgs): Promise<DrainResult>;
|