@isaacriehm/cairn-core 0.3.6 → 0.3.8

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Bulk-accept obvious DEC drafts + stamp confidence on invariants.
3
+ *
4
+ * Mirrors the per-draft accept flow in `mcp/tools/resolve-attention.ts`
5
+ * (`choice: "a"`) but applies it in one pass over `_inbox/` filtered
6
+ * by the `scoring.ts` heuristic. Operator runs this once per
7
+ * adoption to drain the obvious classifications, then triages the
8
+ * medium / low-confidence remainder interactively via the existing
9
+ * cairn-attention skill.
10
+ *
11
+ * Design:
12
+ * - Score each draft from frontmatter + body (prose, raw block) so
13
+ * it can run against drafts written before the scoring pipeline
14
+ * existed (back-compat for v0.3.6 adoptions).
15
+ * - High-confidence DEC drafts: move `_inbox/<id>.draft.md`
16
+ * → `<id>.md`, flip `status:` frontmatter to `accepted`, and
17
+ * stamp `capture_confidence: high`. Rebuild
18
+ * `decisions.ledger.yaml` once at the end.
19
+ * - Medium / low-confidence DEC drafts: stay in `_inbox/` but
20
+ * get `capture_confidence` stamped so the cairn-attention skill
21
+ * can prioritize what to surface first.
22
+ * - Invariants are already at `status: active` (phase 7b promotes
23
+ * them on write). Just stamp `capture_confidence` so future
24
+ * UX can hide low-confidence ones from the active set.
25
+ *
26
+ * Side-effect-only: emits decision_accepted events, runs the source
27
+ * strip-replace pass on accepted source-comment drafts so the §INV /
28
+ * §DEC citations land in the original source.
29
+ */
30
+ import type { ProjectGlobs } from "../sensors/types.js";
31
+ import { type DraftConfidence } from "./scoring.js";
32
+ export interface BulkAcceptArgs {
33
+ repoRoot: string;
34
+ /** Project globs sourced from `.cairn/config.yaml`. */
35
+ globs: ProjectGlobs;
36
+ /** Pilot module path (workflow.md `pilot_module`) for scoring bias. */
37
+ pilotModule?: string;
38
+ /**
39
+ * Minimum confidence to auto-accept DEC drafts. Defaults to "high"
40
+ * — only obvious accepts move out of the inbox. "medium" widens
41
+ * acceptance; "low" effectively accepts everything (do not use
42
+ * unless the operator explicitly opts in).
43
+ */
44
+ threshold?: DraftConfidence;
45
+ /** Don't write — just compute counts. Returns the same shape. */
46
+ dryRun?: boolean;
47
+ }
48
+ export interface BulkAcceptResult {
49
+ decsScanned: number;
50
+ decsAccepted: number;
51
+ decsByConfidence: Record<DraftConfidence, number>;
52
+ acceptedIds: string[];
53
+ invariantsScanned: number;
54
+ invariantsByConfidence: Record<DraftConfidence, number>;
55
+ dryRun: boolean;
56
+ }
57
+ /**
58
+ * Score, stamp, and (for high-confidence DECs) accept inbox drafts in
59
+ * bulk. Returns the count summary the CLI / skill renders to the
60
+ * operator.
61
+ */
62
+ export declare function bulkAcceptObvious(args: BulkAcceptArgs): Promise<BulkAcceptResult>;
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Bulk-accept obvious DEC drafts + stamp confidence on invariants.
3
+ *
4
+ * Mirrors the per-draft accept flow in `mcp/tools/resolve-attention.ts`
5
+ * (`choice: "a"`) but applies it in one pass over `_inbox/` filtered
6
+ * by the `scoring.ts` heuristic. Operator runs this once per
7
+ * adoption to drain the obvious classifications, then triages the
8
+ * medium / low-confidence remainder interactively via the existing
9
+ * cairn-attention skill.
10
+ *
11
+ * Design:
12
+ * - Score each draft from frontmatter + body (prose, raw block) so
13
+ * it can run against drafts written before the scoring pipeline
14
+ * existed (back-compat for v0.3.6 adoptions).
15
+ * - High-confidence DEC drafts: move `_inbox/<id>.draft.md`
16
+ * → `<id>.md`, flip `status:` frontmatter to `accepted`, and
17
+ * stamp `capture_confidence: high`. Rebuild
18
+ * `decisions.ledger.yaml` once at the end.
19
+ * - Medium / low-confidence DEC drafts: stay in `_inbox/` but
20
+ * get `capture_confidence` stamped so the cairn-attention skill
21
+ * can prioritize what to surface first.
22
+ * - Invariants are already at `status: active` (phase 7b promotes
23
+ * them on write). Just stamp `capture_confidence` so future
24
+ * UX can hide low-confidence ones from the active set.
25
+ *
26
+ * Side-effect-only: emits decision_accepted events, runs the source
27
+ * strip-replace pass on accepted source-comment drafts so the §INV /
28
+ * §DEC citations land in the original source.
29
+ */
30
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync, } from "node:fs";
31
+ import { dirname, join } from "node:path";
32
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
33
+ import { decisionsDir, invariantsDir } from "../ground/paths.js";
34
+ import { writeDecisionsLedger } from "../ground/ledgers.js";
35
+ import { withWriteLock } from "../lock.js";
36
+ import { scoreDecDraft, scoreInvariant, } from "./scoring.js";
37
+ /**
38
+ * Score, stamp, and (for high-confidence DECs) accept inbox drafts in
39
+ * bulk. Returns the count summary the CLI / skill renders to the
40
+ * operator.
41
+ */
42
+ export async function bulkAcceptObvious(args) {
43
+ const threshold = args.threshold ?? "high";
44
+ const dry = args.dryRun ?? false;
45
+ // ── DEC drafts ────────────────────────────────────────────────────
46
+ const inboxDir = join(decisionsDir(args.repoRoot), "_inbox");
47
+ const decResult = {
48
+ decsScanned: 0,
49
+ decsAccepted: 0,
50
+ decsByConfidence: { high: 0, medium: 0, low: 0 },
51
+ acceptedIds: [],
52
+ };
53
+ if (existsSync(inboxDir)) {
54
+ const entries = readdirSync(inboxDir, { withFileTypes: true });
55
+ const drafts = entries.filter((e) => e.isFile() && e.name.endsWith(".draft.md"));
56
+ decResult.decsScanned = drafts.length;
57
+ if (drafts.length > 0) {
58
+ await withWriteLock(args.repoRoot, () => {
59
+ for (const e of drafts) {
60
+ const abs = join(inboxDir, e.name);
61
+ let raw;
62
+ try {
63
+ raw = readFileSync(abs, "utf8");
64
+ }
65
+ catch {
66
+ continue;
67
+ }
68
+ const fm = parseFrontmatter(raw);
69
+ const body = stripFrontmatter(raw);
70
+ const id = stringField(fm, "id") ?? e.name.replace(/\.draft\.md$/, "");
71
+ const sourceFile = stringField(fm, "sourceFile") ?? "";
72
+ const titleFm = stringField(fm, "proposedTitle") ?? stringField(fm, "title") ?? "";
73
+ const rationaleFm = stringField(fm, "proposedRationale") ?? extractSection(body, "Proposed rationale");
74
+ const proseFromBody = extractSection(body, "Source comment");
75
+ const prose = rationaleFm.length > 0 ? rationaleFm : proseFromBody;
76
+ const score = scoreDecDraft({
77
+ sourceFile,
78
+ prose,
79
+ title: titleFm,
80
+ rawComment: proseFromBody,
81
+ globs: args.globs,
82
+ ...(args.pilotModule !== undefined ? { pilotModule: args.pilotModule } : {}),
83
+ });
84
+ decResult.decsByConfidence[score] += 1;
85
+ // Always stamp the confidence so future passes (and the
86
+ // skill) can read it without re-scoring.
87
+ const stampedFm = { ...fm, capture_confidence: score };
88
+ if (atOrAbove(score, threshold)) {
89
+ // Promote to accepted.
90
+ const acceptedFm = { ...stampedFm, status: "accepted" };
91
+ const acceptedBody = renderDoc(acceptedFm, body);
92
+ const acceptedPath = join(decisionsDir(args.repoRoot), `${id}.md`);
93
+ if (!dry) {
94
+ mkdirSync(dirname(acceptedPath), { recursive: true });
95
+ writeFileSync(acceptedPath, acceptedBody, "utf8");
96
+ try {
97
+ rmSync(abs, { force: true });
98
+ }
99
+ catch {
100
+ /* best-effort */
101
+ }
102
+ }
103
+ decResult.decsAccepted += 1;
104
+ decResult.acceptedIds.push(id);
105
+ }
106
+ else {
107
+ // Stay in inbox; persist confidence stamp so the skill
108
+ // can sort/show it.
109
+ const stampedDoc = renderDoc(stampedFm, body);
110
+ if (!dry) {
111
+ writeFileSync(abs, stampedDoc, "utf8");
112
+ }
113
+ }
114
+ }
115
+ // Rebuild the ledger once at the end so accepted DECs surface
116
+ // in `cairn_decisions_in_scope` immediately.
117
+ if (!dry && decResult.decsAccepted > 0) {
118
+ try {
119
+ writeDecisionsLedger({ repoRoot: args.repoRoot });
120
+ }
121
+ catch {
122
+ /* best-effort */
123
+ }
124
+ }
125
+ });
126
+ }
127
+ }
128
+ // ── Invariants ────────────────────────────────────────────────────
129
+ // Already at status: active on disk. Just stamp confidence so the
130
+ // attention skill can hide / down-weight low-confidence ones.
131
+ const invDir = invariantsDir(args.repoRoot);
132
+ const invResult = {
133
+ invariantsScanned: 0,
134
+ invariantsByConfidence: { high: 0, medium: 0, low: 0 },
135
+ };
136
+ if (existsSync(invDir)) {
137
+ const invEntries = readdirSync(invDir, { withFileTypes: true });
138
+ const invFiles = invEntries.filter((e) => e.isFile() && /^INV-\d{4,}\.md$/.test(e.name));
139
+ invResult.invariantsScanned = invFiles.length;
140
+ if (invFiles.length > 0 && !dry) {
141
+ await withWriteLock(args.repoRoot, () => {
142
+ for (const e of invFiles) {
143
+ const abs = join(invDir, e.name);
144
+ let raw;
145
+ try {
146
+ raw = readFileSync(abs, "utf8");
147
+ }
148
+ catch {
149
+ continue;
150
+ }
151
+ const fm = parseFrontmatter(raw);
152
+ const body = stripFrontmatter(raw);
153
+ const sourceFile = stringField(fm, "sourceFile") ?? "";
154
+ const titleFm = stringField(fm, "title") ?? "";
155
+ const rawCommentBody = extractSection(body, "Source comment");
156
+ const constraintBody = extractSection(body, "Constraint");
157
+ const prose = constraintBody.length > 0 ? constraintBody : titleFm;
158
+ const score = scoreInvariant({
159
+ sourceFile,
160
+ prose,
161
+ title: titleFm,
162
+ rawComment: rawCommentBody,
163
+ globs: args.globs,
164
+ ...(args.pilotModule !== undefined ? { pilotModule: args.pilotModule } : {}),
165
+ });
166
+ invResult.invariantsByConfidence[score] += 1;
167
+ const stamped = { ...fm, capture_confidence: score };
168
+ const stampedDoc = renderDoc(stamped, body);
169
+ writeFileSync(abs, stampedDoc, "utf8");
170
+ }
171
+ });
172
+ }
173
+ else if (invFiles.length > 0 && dry) {
174
+ // Dry run still scores so the operator can see the distribution.
175
+ for (const e of invFiles) {
176
+ const abs = join(invDir, e.name);
177
+ let raw;
178
+ try {
179
+ raw = readFileSync(abs, "utf8");
180
+ }
181
+ catch {
182
+ continue;
183
+ }
184
+ const fm = parseFrontmatter(raw);
185
+ const body = stripFrontmatter(raw);
186
+ const sourceFile = stringField(fm, "sourceFile") ?? "";
187
+ const titleFm = stringField(fm, "title") ?? "";
188
+ const rawCommentBody = extractSection(body, "Source comment");
189
+ const constraintBody = extractSection(body, "Constraint");
190
+ const prose = constraintBody.length > 0 ? constraintBody : titleFm;
191
+ const score = scoreInvariant({
192
+ sourceFile,
193
+ prose,
194
+ title: titleFm,
195
+ rawComment: rawCommentBody,
196
+ globs: args.globs,
197
+ ...(args.pilotModule !== undefined ? { pilotModule: args.pilotModule } : {}),
198
+ });
199
+ invResult.invariantsByConfidence[score] += 1;
200
+ }
201
+ }
202
+ }
203
+ return {
204
+ ...decResult,
205
+ ...invResult,
206
+ dryRun: dry,
207
+ };
208
+ }
209
+ // ── Helpers ────────────────────────────────────────────────────────
210
+ function parseFrontmatter(doc) {
211
+ const m = doc.match(/^---\n([\s\S]*?)\n---/);
212
+ if (m === null || m[1] === undefined)
213
+ return {};
214
+ try {
215
+ const parsed = parseYaml(m[1]);
216
+ return typeof parsed === "object" && parsed !== null
217
+ ? parsed
218
+ : {};
219
+ }
220
+ catch {
221
+ return {};
222
+ }
223
+ }
224
+ function stripFrontmatter(doc) {
225
+ return doc.replace(/^---\n[\s\S]*?\n---\n?/, "");
226
+ }
227
+ function renderDoc(fm, body) {
228
+ return `---\n${stringifyYaml(fm).trimEnd()}\n---\n${body.startsWith("\n") ? body : `\n${body}`}`;
229
+ }
230
+ function stringField(fm, key) {
231
+ const v = fm[key];
232
+ return typeof v === "string" ? v : null;
233
+ }
234
+ function extractSection(body, header) {
235
+ // Find `## <header>` and return content until the next `## ` block.
236
+ const re = new RegExp(`##\\s+${escapeRegex(header)}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`, "i");
237
+ const m = body.match(re);
238
+ if (m === null || m[1] === undefined)
239
+ return "";
240
+ // Strip surrounding code-fence markers if the section is fenced.
241
+ return m[1].replace(/^\s*```[a-z0-9]*\n?/i, "").replace(/```\s*$/, "").trim();
242
+ }
243
+ function escapeRegex(s) {
244
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
245
+ }
246
+ function atOrAbove(score, threshold) {
247
+ const order = { low: 0, medium: 1, high: 2 };
248
+ return order[score] >= order[threshold];
249
+ }
250
+ //# sourceMappingURL=bulk-accept.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-accept.js","sourceRoot":"","sources":["../../src/attention/bulk-accept.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { scoreDecDraft, scoreInvariant, type DraftConfidence, type DraftScoreInput, } from "./scoring.js";
2
+ export { bulkAcceptObvious, type BulkAcceptArgs, type BulkAcceptResult, } from "./bulk-accept.js";
@@ -0,0 +1,3 @@
1
+ export { scoreDecDraft, scoreInvariant, } from "./scoring.js";
2
+ export { bulkAcceptObvious, } from "./bulk-accept.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/attention/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,GAGf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,iBAAiB,GAGlB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Confidence scoring for source-comment-derived DEC drafts and
3
+ * invariant proposals.
4
+ *
5
+ * Phase 7b emits one DEC draft per "rationale"-class essay comment and
6
+ * one invariant per "constraint"-class essay comment. On a busy
7
+ * monorepo the classifier easily produces 400+ drafts — no human will
8
+ * sort through that interactively, so we score each draft by a small
9
+ * set of heuristics and bulk-accept the obvious ones during attention
10
+ * drain. Operator triages only the medium / low-confidence remainder.
11
+ *
12
+ * Heuristic stance:
13
+ * - **DEC drafts** are attribution-of-existing-prose. Cost of keeping
14
+ * a borderline draft is near zero (queryable rationale metadata).
15
+ * Bias accepts upward — score ≥7 → high.
16
+ * - **Invariants** become enforcement signals; false positives turn
17
+ * into noise during sensor sweeps. Bias accepts downward —
18
+ * stricter signal required (modal verb + reason + high-stakes
19
+ * location) before high-confidence accept.
20
+ *
21
+ * Scoring is pure. Inputs are the parsed draft fields; no filesystem.
22
+ */
23
+ import type { ProjectGlobs } from "../sensors/types.js";
24
+ export type DraftConfidence = "high" | "medium" | "low";
25
+ export interface DraftScoreInput {
26
+ /** Repo-relative path to the source file the draft was extracted from. */
27
+ sourceFile: string;
28
+ /** Comment prose (markers stripped). */
29
+ prose: string;
30
+ /** Suggested DEC title or invariant text. */
31
+ title: string;
32
+ /** Raw block including markers + JSDoc tags. */
33
+ rawComment: string;
34
+ /** Project globs from `.cairn/config.yaml`. */
35
+ globs: ProjectGlobs;
36
+ /** Pilot module path (e.g. `core/src`); empty / "." treated as no bias. */
37
+ pilotModule?: string;
38
+ }
39
+ /**
40
+ * Score a DEC draft. Max 9 / threshold 7→high / 4→medium.
41
+ */
42
+ export declare function scoreDecDraft(input: DraftScoreInput): DraftConfidence;
43
+ /**
44
+ * Score an invariant proposal. Max 9 / threshold 7→high / 4→medium.
45
+ * Stricter than DEC scoring: requires modal verb + reason + high-stakes
46
+ * location for high confidence, since false-positive invariants become
47
+ * sensor-sweep noise downstream.
48
+ */
49
+ export declare function scoreInvariant(input: DraftScoreInput): DraftConfidence;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Confidence scoring for source-comment-derived DEC drafts and
3
+ * invariant proposals.
4
+ *
5
+ * Phase 7b emits one DEC draft per "rationale"-class essay comment and
6
+ * one invariant per "constraint"-class essay comment. On a busy
7
+ * monorepo the classifier easily produces 400+ drafts — no human will
8
+ * sort through that interactively, so we score each draft by a small
9
+ * set of heuristics and bulk-accept the obvious ones during attention
10
+ * drain. Operator triages only the medium / low-confidence remainder.
11
+ *
12
+ * Heuristic stance:
13
+ * - **DEC drafts** are attribution-of-existing-prose. Cost of keeping
14
+ * a borderline draft is near zero (queryable rationale metadata).
15
+ * Bias accepts upward — score ≥7 → high.
16
+ * - **Invariants** become enforcement signals; false positives turn
17
+ * into noise during sensor sweeps. Bias accepts downward —
18
+ * stricter signal required (modal verb + reason + high-stakes
19
+ * location) before high-confidence accept.
20
+ *
21
+ * Scoring is pure. Inputs are the parsed draft fields; no filesystem.
22
+ */
23
+ import { matchAnyGlob } from "../ground/glob.js";
24
+ const DECISION_VERBS = /\b(chose|chosen|choose|decided|prefer|preferred|because|locked|enforce|enforced|require|required|adopt|adopted|standardize|standardized|switch|migrated|deprecate|reject|rejected)\b/i;
25
+ const JSDOC_TAGS = /@(domain|scope|orgScope|see|param|returns|throws|deprecated|since|module|namespace|file|fileoverview|public|private|protected|internal|readonly|override|sealed|immutable|invariant)\b/;
26
+ const INVARIANT_MODALS = /\b(MUST|MUSTN'T|MUST NOT|NEVER|ALWAYS|SHALL|SHALL NOT|CANNOT|FORBID|FORBIDDEN|REQUIRED|REQUIRES)\b/i;
27
+ const REASON_MARKERS = /\b(because|to (prevent|ensure|avoid|guarantee|preserve|enforce|stop)|otherwise)\b/i;
28
+ function inHighStakes(file, globs) {
29
+ return matchAnyGlob(file, globs.high_stakes_globs ?? []);
30
+ }
31
+ function inPilot(file, pilot) {
32
+ if (pilot === undefined)
33
+ return false;
34
+ const p = pilot.trim();
35
+ if (p.length === 0 || p === "." || p === "ALL")
36
+ return false;
37
+ // Pilot module is a directory; treat any file under it as in-pilot.
38
+ return file === p || file.startsWith(`${p}/`);
39
+ }
40
+ function inRoutesOrDtos(file, globs) {
41
+ const combined = [
42
+ ...(globs.route_handler_globs ?? []),
43
+ ...(globs.dto_globs ?? []),
44
+ ];
45
+ return matchAnyGlob(file, combined);
46
+ }
47
+ /**
48
+ * Score a DEC draft. Max 9 / threshold 7→high / 4→medium.
49
+ */
50
+ export function scoreDecDraft(input) {
51
+ let score = 0;
52
+ if (inHighStakes(input.sourceFile, input.globs))
53
+ score += 3;
54
+ if (inPilot(input.sourceFile, input.pilotModule))
55
+ score += 1;
56
+ if (inRoutesOrDtos(input.sourceFile, input.globs))
57
+ score += 1;
58
+ const proseLen = input.prose.trim().length;
59
+ if (proseLen >= 80 && proseLen <= 800)
60
+ score += 2;
61
+ const titleLen = input.title.trim().length;
62
+ if (titleLen >= 10 && titleLen <= 80)
63
+ score += 1;
64
+ if (DECISION_VERBS.test(input.prose))
65
+ score += 2;
66
+ if (JSDOC_TAGS.test(input.rawComment))
67
+ score += 1;
68
+ if (score >= 7)
69
+ return "high";
70
+ if (score >= 4)
71
+ return "medium";
72
+ return "low";
73
+ }
74
+ /**
75
+ * Score an invariant proposal. Max 9 / threshold 7→high / 4→medium.
76
+ * Stricter than DEC scoring: requires modal verb + reason + high-stakes
77
+ * location for high confidence, since false-positive invariants become
78
+ * sensor-sweep noise downstream.
79
+ */
80
+ export function scoreInvariant(input) {
81
+ let score = 0;
82
+ if (inHighStakes(input.sourceFile, input.globs))
83
+ score += 3;
84
+ const modalText = `${input.title}\n${input.prose}`;
85
+ if (INVARIANT_MODALS.test(modalText))
86
+ score += 3;
87
+ if (REASON_MARKERS.test(input.prose))
88
+ score += 2;
89
+ const proseLen = input.prose.trim().length;
90
+ if (proseLen >= 50 && proseLen <= 600)
91
+ score += 1;
92
+ if (score >= 7)
93
+ return "high";
94
+ if (score >= 4)
95
+ return "medium";
96
+ return "low";
97
+ }
98
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/attention/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAoBjD,MAAM,cAAc,GAClB,uLAAuL,CAAC;AAE1L,MAAM,UAAU,GAAG,wLAAwL,CAAC;AAE5M,MAAM,gBAAgB,GACpB,qGAAqG,CAAC;AAExG,MAAM,cAAc,GAAG,oFAAoF,CAAC;AAE5G,SAAS,YAAY,CAAC,IAAY,EAAE,KAAmB;IACrD,OAAO,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,KAAyB;IACtD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC7D,oEAAoE;IACpE,OAAO,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,KAAmB;IACvD,MAAM,QAAQ,GAAG;QACf,GAAG,CAAC,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC;QACpC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;KAC3B,CAAC;IACF,OAAO,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAsB;IAClD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC5D,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,WAAW,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC7D,IAAI,cAAc,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC3C,IAAI,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,GAAG;QAAE,KAAK,IAAI,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC3C,IAAI,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,EAAE;QAAE,KAAK,IAAI,CAAC,CAAC;IACjD,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IACjD,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAElD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAsB;IACnD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;IACnD,IAAI,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IACjD,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC3C,IAAI,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,GAAG;QAAE,KAAK,IAAI,CAAC,CAAC;IAElD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export declare const VERSION: string;
7
7
  export { logger, setLogFile, setLogNull, setLogStderr } from "./logger.js";
8
8
  export { withWriteLock, acquireOperationLock, OperationLockHeldError, } from "./lock.js";
9
9
  export type { WithLockOptions } from "./lock.js";
10
+ export * from "./attention/index.js";
10
11
  export * from "./claude/index.js";
11
12
  export * from "./context/index.js";
12
13
  export * from "./decision-capture/index.js";
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ function readVersion() {
22
22
  export const VERSION = readVersion();
23
23
  export { logger, setLogFile, setLogNull, setLogStderr } from "./logger.js";
24
24
  export { withWriteLock, acquireOperationLock, OperationLockHeldError, } from "./lock.js";
25
+ export * from "./attention/index.js";
25
26
  export * from "./claude/index.js";
26
27
  export * from "./context/index.js";
27
28
  export * from "./decision-capture/index.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,oDAAoD;AACpD,SAAS,WAAW;IAClB,IAAI,OAAO,iBAAiB,KAAK,QAAQ;QAAE,OAAO,iBAAiB,CAAC;IACpE,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CACjC,CAAC;IACzB,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC;AACD,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,EAAE,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAGnB,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,OAAO,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,GAGd,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,oDAAoD;AACpD,SAAS,WAAW;IAClB,IAAI,OAAO,iBAAiB,KAAK,QAAQ;QAAE,OAAO,iBAAiB,CAAC;IACpE,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CACjC,CAAC;IACzB,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC;AACD,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,EAAE,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAGnB,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,OAAO,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,GAGd,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `cairn_bulk_accept_attention` MCP tool.
3
+ *
4
+ * Wraps `bulkAcceptObvious` so the cairn-attention skill can drain
5
+ * obvious DEC drafts in one tool call instead of N rounds of
6
+ * `cairn_resolve_attention(choice="a")` per draft. Loads the project
7
+ * globs + pilot module from `.cairn/config.yaml` so the scoring
8
+ * heuristic has the same context the cli subcommand does.
9
+ *
10
+ * Returns a slim count-distribution shape — no draft bodies, no file
11
+ * paths beyond the accepted ID list. Skill renders the summary inline,
12
+ * then proceeds to interactive triage of the remaining (medium + low)
13
+ * drafts via the existing per-item flow.
14
+ */
15
+ import { type DraftConfidence } from "../../attention/index.js";
16
+ import type { ToolDef } from "./types.js";
17
+ interface BulkAcceptInput {
18
+ threshold?: DraftConfidence;
19
+ dryRun?: boolean;
20
+ }
21
+ export declare const bulkAcceptAttentionTool: ToolDef<BulkAcceptInput>;
22
+ export {};
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `cairn_bulk_accept_attention` MCP tool.
3
+ *
4
+ * Wraps `bulkAcceptObvious` so the cairn-attention skill can drain
5
+ * obvious DEC drafts in one tool call instead of N rounds of
6
+ * `cairn_resolve_attention(choice="a")` per draft. Loads the project
7
+ * globs + pilot module from `.cairn/config.yaml` so the scoring
8
+ * heuristic has the same context the cli subcommand does.
9
+ *
10
+ * Returns a slim count-distribution shape — no draft bodies, no file
11
+ * paths beyond the accepted ID list. Skill renders the summary inline,
12
+ * then proceeds to interactive triage of the remaining (medium + low)
13
+ * drafts via the existing per-item flow.
14
+ */
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { parse as parseYaml } from "yaml";
18
+ import { z } from "zod";
19
+ import { bulkAcceptObvious, } from "../../attention/index.js";
20
+ const confidenceSchema = z.enum(["high", "medium", "low"]);
21
+ const inputShape = {
22
+ threshold: confidenceSchema.optional(),
23
+ dryRun: z.boolean().optional(),
24
+ };
25
+ function loadProjectGlobs(repoRoot) {
26
+ const configPath = join(repoRoot, ".cairn", "config.yaml");
27
+ if (!existsSync(configPath)) {
28
+ return { globs: {} };
29
+ }
30
+ let parsed;
31
+ try {
32
+ parsed = parseYaml(readFileSync(configPath, "utf8"));
33
+ }
34
+ catch {
35
+ return { globs: {} };
36
+ }
37
+ if (typeof parsed !== "object" || parsed === null)
38
+ return { globs: {} };
39
+ const cfg = parsed;
40
+ const globs = {};
41
+ const pickList = (v) => {
42
+ if (!Array.isArray(v))
43
+ return undefined;
44
+ return v.filter((x) => typeof x === "string");
45
+ };
46
+ const high = pickList(cfg["high_stakes_globs"]);
47
+ if (high !== undefined)
48
+ globs.high_stakes_globs = high;
49
+ const off = pickList(cfg["off_limits"]);
50
+ if (off !== undefined)
51
+ globs.off_limits = off;
52
+ const projectGlobs = cfg["project_globs"];
53
+ if (typeof projectGlobs === "object" && projectGlobs !== null) {
54
+ const pg = projectGlobs;
55
+ const route = pickList(pg["route_handler_globs"]);
56
+ if (route !== undefined)
57
+ globs.route_handler_globs = route;
58
+ const dto = pickList(pg["dto_globs"]);
59
+ if (dto !== undefined)
60
+ globs.dto_globs = dto;
61
+ const gen = pickList(pg["generator_source_globs"]);
62
+ if (gen !== undefined)
63
+ globs.generator_source_globs = gen;
64
+ const hi = pickList(pg["high_stakes_globs"]);
65
+ if (hi !== undefined && globs.high_stakes_globs === undefined) {
66
+ globs.high_stakes_globs = hi;
67
+ }
68
+ }
69
+ const pilot = typeof cfg["pilot_module"] === "string" ? cfg["pilot_module"] : undefined;
70
+ return pilot !== undefined ? { globs, pilotModule: pilot } : { globs };
71
+ }
72
+ export const bulkAcceptAttentionTool = {
73
+ name: "cairn_bulk_accept_attention",
74
+ description: "Score every DEC draft + invariant in `.cairn/ground/decisions/_inbox/` and `.cairn/ground/invariants/` against a confidence heuristic (file in high_stakes_globs / pilot module / route or dto globs, prose substantiveness, decision verbs, JSDoc tags). Auto-promote DEC drafts at or above `threshold` (default 'high') out of the inbox to accepted state and rebuild the decisions ledger. Stamp `capture_confidence` on every draft + invariant so subsequent attention surfaces can sort. Use this once per adoption to drain the obvious classifications before per-item triage. Returns count distributions and the accepted ID list. `dryRun: true` reports the same distribution without writing.",
75
+ inputSchema: inputShape,
76
+ handler: async (ctx, input) => {
77
+ const { globs, pilotModule } = loadProjectGlobs(ctx.repoRoot);
78
+ return bulkAcceptObvious({
79
+ repoRoot: ctx.repoRoot,
80
+ globs,
81
+ ...(pilotModule !== undefined ? { pilotModule } : {}),
82
+ threshold: input.threshold ?? "high",
83
+ ...(input.dryRun !== undefined ? { dryRun: input.dryRun } : {}),
84
+ });
85
+ },
86
+ };
87
+ //# sourceMappingURL=bulk-accept-attention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-accept-attention.js","sourceRoot":"","sources":["../../../src/mcp/tools/bulk-accept-attention.ts"],"names":[],"mappings":"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"}