@isaacriehm/cairn-core 0.19.0 → 0.21.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.
Files changed (164) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/attention/index.d.ts +0 -2
  3. package/dist/attention/index.js +0 -2
  4. package/dist/attention/index.js.map +1 -1
  5. package/dist/attention/restore.d.ts +1 -1
  6. package/dist/attention/restore.js +1 -1
  7. package/dist/attention/source-strip.d.ts +2 -2
  8. package/dist/attention/source-strip.js +2 -2
  9. package/dist/components/audit.d.ts +20 -3
  10. package/dist/components/audit.js +220 -51
  11. package/dist/components/audit.js.map +1 -1
  12. package/dist/doctor/index.js +96 -3
  13. package/dist/doctor/index.js.map +1 -1
  14. package/dist/gc/citation-integrity.d.ts +2 -2
  15. package/dist/gc/citation-integrity.js +9 -7
  16. package/dist/gc/citation-integrity.js.map +1 -1
  17. package/dist/gc/classify.js +3 -16
  18. package/dist/gc/classify.js.map +1 -1
  19. package/dist/gc/entity-orphan.js +7 -5
  20. package/dist/gc/entity-orphan.js.map +1 -1
  21. package/dist/gc/sweep.d.ts +1 -1
  22. package/dist/gc/sweep.js +1 -1
  23. package/dist/hooks/post-tool-use/ask-user-blocked.d.ts +1 -2
  24. package/dist/hooks/post-tool-use/ask-user-blocked.js +1 -2
  25. package/dist/hooks/post-tool-use/ask-user-blocked.js.map +1 -1
  26. package/dist/hooks/post-tool-use/citation-scanner.d.ts +2 -2
  27. package/dist/hooks/post-tool-use/citation-scanner.js +1 -1
  28. package/dist/hooks/post-tool-use/read-enricher.d.ts +1 -1
  29. package/dist/hooks/post-tool-use/read-enricher.js +1 -1
  30. package/dist/hooks/post-tool-use/write-guardian.d.ts +1 -5
  31. package/dist/hooks/post-tool-use/write-guardian.js +21 -14
  32. package/dist/hooks/post-tool-use/write-guardian.js.map +1 -1
  33. package/dist/hooks/runners/session-start.js +61 -1
  34. package/dist/hooks/runners/session-start.js.map +1 -1
  35. package/dist/hooks/runners/stop.js +20 -30
  36. package/dist/hooks/runners/stop.js.map +1 -1
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/init/detect-components.d.ts +3 -2
  41. package/dist/init/detect-components.js +31 -13
  42. package/dist/init/detect-components.js.map +1 -1
  43. package/dist/init/detect.d.ts +1 -5
  44. package/dist/init/detect.js +157 -143
  45. package/dist/init/detect.js.map +1 -1
  46. package/dist/init/glob-inference.js +24 -0
  47. package/dist/init/glob-inference.js.map +1 -1
  48. package/dist/init/index.d.ts +3 -3
  49. package/dist/init/index.js +1 -1
  50. package/dist/init/index.js.map +1 -1
  51. package/dist/init/init.js +0 -14
  52. package/dist/init/init.js.map +1 -1
  53. package/dist/init/mapper-merge.d.ts +1 -4
  54. package/dist/init/mapper-merge.js +4 -17
  55. package/dist/init/mapper-merge.js.map +1 -1
  56. package/dist/init/mapper-parallel.js +1 -1
  57. package/dist/init/mapper-parallel.js.map +1 -1
  58. package/dist/init/mapper-prompts.d.ts +1 -23
  59. package/dist/init/mapper-prompts.js +1 -25
  60. package/dist/init/mapper-prompts.js.map +1 -1
  61. package/dist/init/mapper.d.ts +0 -6
  62. package/dist/init/mapper.js +0 -3
  63. package/dist/init/mapper.js.map +1 -1
  64. package/dist/init/module-slicer.js +3 -24
  65. package/dist/init/module-slicer.js.map +1 -1
  66. package/dist/init/overlay.js +5 -16
  67. package/dist/init/overlay.js.map +1 -1
  68. package/dist/init/phases/9d-comp-walk.js +1 -1
  69. package/dist/init/phases/9d-comp-walk.js.map +1 -1
  70. package/dist/init/source-comments/strip-replace.d.ts +1 -1
  71. package/dist/init/source-comments/strip-replace.js +2 -2
  72. package/dist/init/source-comments/walker.js +8 -79
  73. package/dist/init/source-comments/walker.js.map +1 -1
  74. package/dist/init/types.d.ts +8 -16
  75. package/dist/init/walker.d.ts +1 -1
  76. package/dist/init/walker.js +1 -1
  77. package/dist/mcp/schemas.d.ts +4 -4
  78. package/dist/mcp/schemas.js +1 -1
  79. package/dist/mcp/serve.js +9 -0
  80. package/dist/mcp/serve.js.map +1 -1
  81. package/dist/mcp/tools/decision-get.js +2 -2
  82. package/dist/mcp/tools/decision-get.js.map +1 -1
  83. package/dist/mcp/tools/index.js +0 -6
  84. package/dist/mcp/tools/index.js.map +1 -1
  85. package/dist/mcp/tools/mission-advance.d.ts +3 -4
  86. package/dist/mcp/tools/mission-advance.js +10 -14
  87. package/dist/mcp/tools/mission-advance.js.map +1 -1
  88. package/dist/mcp/tools/record-decision.js +7 -6
  89. package/dist/mcp/tools/record-decision.js.map +1 -1
  90. package/dist/mcp/tools/resolve-attention.js +50 -30
  91. package/dist/mcp/tools/resolve-attention.js.map +1 -1
  92. package/dist/migrate/config-io.d.ts +16 -0
  93. package/dist/migrate/config-io.js +71 -0
  94. package/dist/migrate/config-io.js.map +1 -0
  95. package/dist/migrate/index.d.ts +5 -0
  96. package/dist/migrate/index.js +5 -0
  97. package/dist/migrate/index.js.map +1 -0
  98. package/dist/migrate/migrations/0001-drop-dead-config-fields.d.ts +12 -0
  99. package/dist/migrate/migrations/0001-drop-dead-config-fields.js +39 -0
  100. package/dist/migrate/migrations/0001-drop-dead-config-fields.js.map +1 -0
  101. package/dist/migrate/registry.d.ts +9 -0
  102. package/dist/migrate/registry.js +10 -0
  103. package/dist/migrate/registry.js.map +1 -0
  104. package/dist/migrate/runner.d.ts +45 -0
  105. package/dist/migrate/runner.js +170 -0
  106. package/dist/migrate/runner.js.map +1 -0
  107. package/dist/migrate/semver.d.ts +11 -0
  108. package/dist/migrate/semver.js +35 -0
  109. package/dist/migrate/semver.js.map +1 -0
  110. package/dist/migrate/types.d.ts +39 -0
  111. package/dist/migrate/types.js +13 -0
  112. package/dist/migrate/types.js.map +1 -0
  113. package/dist/missions/task-link.js +3 -3
  114. package/dist/missions/task-link.js.map +1 -1
  115. package/dist/sensors/catalog.js +4 -9
  116. package/dist/sensors/catalog.js.map +1 -1
  117. package/dist/sensors/decisions.js +55 -19
  118. package/dist/sensors/decisions.js.map +1 -1
  119. package/dist/sensors/diff.d.ts +12 -0
  120. package/dist/sensors/diff.js +103 -0
  121. package/dist/sensors/diff.js.map +1 -1
  122. package/dist/sensors/index.d.ts +4 -5
  123. package/dist/sensors/index.js +2 -3
  124. package/dist/sensors/index.js.map +1 -1
  125. package/dist/sensors/runner.d.ts +34 -37
  126. package/dist/sensors/runner.js +63 -53
  127. package/dist/sensors/runner.js.map +1 -1
  128. package/dist/sensors/stub-catalog.d.ts +6 -3
  129. package/dist/sensors/stub-catalog.js +7 -19
  130. package/dist/sensors/stub-catalog.js.map +1 -1
  131. package/dist/sensors/types.d.ts +11 -55
  132. package/dist/sensors/types.js +4 -8
  133. package/dist/sensors/types.js.map +1 -1
  134. package/dist/session-start/build.js +5 -5
  135. package/dist/session-start/build.js.map +1 -1
  136. package/dist/session-start/templates.d.ts +1 -1
  137. package/dist/session-start/templates.js +1 -1
  138. package/dist/tasks/lifecycle.d.ts +3 -4
  139. package/dist/tasks/lifecycle.js +9 -12
  140. package/dist/tasks/lifecycle.js.map +1 -1
  141. package/package.json +2 -2
  142. package/templates/.cairn/git-hooks/pre-commit +7 -4
  143. package/templates/.github/workflows/cairn-check.yml +8 -0
  144. package/dist/attention/bulk-accept.d.ts +0 -78
  145. package/dist/attention/bulk-accept.js +0 -348
  146. package/dist/attention/bulk-accept.js.map +0 -1
  147. package/dist/attention/serve/api.d.ts +0 -24
  148. package/dist/attention/serve/api.js +0 -383
  149. package/dist/attention/serve/api.js.map +0 -1
  150. package/dist/attention/serve/index.d.ts +0 -63
  151. package/dist/attention/serve/index.js +0 -219
  152. package/dist/attention/serve/index.js.map +0 -1
  153. package/dist/mcp/tools/attention-serve.d.ts +0 -23
  154. package/dist/mcp/tools/attention-serve.js +0 -84
  155. package/dist/mcp/tools/attention-serve.js.map +0 -1
  156. package/dist/mcp/tools/attention-wait.d.ts +0 -18
  157. package/dist/mcp/tools/attention-wait.js +0 -84
  158. package/dist/mcp/tools/attention-wait.js.map +0 -1
  159. package/dist/mcp/tools/bulk-accept-attention.d.ts +0 -22
  160. package/dist/mcp/tools/bulk-accept-attention.js +0 -84
  161. package/dist/mcp/tools/bulk-accept-attention.js.map +0 -1
  162. package/dist/sensors/attestation.d.ts +0 -44
  163. package/dist/sensors/attestation.js +0 -262
  164. package/dist/sensors/attestation.js.map +0 -1
@@ -1,383 +0,0 @@
1
- /**
2
- * JSON API for the triage GUI. Routes mirror the existing attention
3
- * MCP handlers (resolve / bulk-accept / dedup / restore) so all writes
4
- * funnel through `withWriteLock`.
5
- */
6
- import { existsSync, readdirSync, statSync } from "node:fs";
7
- import { readFile, writeFile, rename, rm, mkdir } from "node:fs/promises";
8
- import { join, dirname } from "node:path";
9
- import { parse as parseYaml } from "yaml";
10
- import { z } from "zod";
11
- import { bulkAcceptObvious } from "../bulk-accept.js";
12
- import { findDuplicateClusters } from "../dedup.js";
13
- import { runDecSourceStrip, parseDraftMeta } from "../source-strip.js";
14
- import { decisionsDir, writeDecisionsLedger, parseFrontmatterRecord, } from "@isaacriehm/cairn-state";
15
- import { withWriteLock } from "../../lock.js";
16
- import { writeInvalidationEvent } from "../../events/index.js";
17
- import { logger } from "../../logger.js";
18
- const log = logger("attention.serve.api");
19
- const MAX_BODY_BYTES = 5 * 1024 * 1024; // 5MB
20
- const BODY_TIMEOUT_MS = 10_000;
21
- const BulkAcceptInput = z.object({
22
- threshold: z.enum(["high", "medium", "low"]).optional(),
23
- dryRun: z.boolean().optional(),
24
- });
25
- const ClusterMergeInput = z.object({
26
- survivor_id: z.string(),
27
- member_ids: z.array(z.string()).optional(),
28
- });
29
- const EditDraftInput = z.object({
30
- title: z.string().optional(),
31
- body_markdown: z.string().optional(),
32
- });
33
- const ConfigSchema = z.object({
34
- project_globs: z.object({
35
- route_handler_globs: z.array(z.string()).optional(),
36
- dto_globs: z.array(z.string()).optional(),
37
- generator_source_globs: z.array(z.string()).optional(),
38
- high_stakes_globs: z.array(z.string()).optional(),
39
- }).optional(),
40
- off_limits: z.array(z.string()).optional(),
41
- }).passthrough();
42
- /**
43
- * Top-level dispatch. Always responds with JSON.
44
- */
45
- export async function handleApi(req, res, ctx) {
46
- ctx.touch();
47
- const url = req.url ?? "/";
48
- const parsedUrl = new URL(url, `http://${req.headers.host || "localhost"}`);
49
- // Security: Validate Token
50
- const queryToken = parsedUrl.searchParams.get("token");
51
- const authHeader = req.headers["authorization"];
52
- const bearerToken = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
53
- if (queryToken !== ctx.token && bearerToken !== ctx.token) {
54
- return sendJson(res, 403, { ok: false, error: "forbidden: invalid token" });
55
- }
56
- try {
57
- if (parsedUrl.pathname === "/api/state" && req.method === "GET") {
58
- return sendJson(res, 200, await buildState(ctx));
59
- }
60
- if (parsedUrl.pathname === "/api/heartbeat" && req.method === "POST") {
61
- return sendJson(res, 200, { ok: true });
62
- }
63
- if (parsedUrl.pathname === "/api/done" && req.method === "POST") {
64
- ctx.onDone();
65
- return sendJson(res, 200, { ok: true, ...ctx.counters });
66
- }
67
- if (parsedUrl.pathname === "/api/bulk-accept" && req.method === "POST") {
68
- const bodyRaw = await readJsonBody(req);
69
- const parsed = BulkAcceptInput.safeParse(bodyRaw);
70
- if (!parsed.success) {
71
- return sendJson(res, 400, { ok: false, error: "invalid input" });
72
- }
73
- const threshold = parsed.data.threshold ?? "high";
74
- const dryRun = parsed.data.dryRun === true;
75
- const result = await bulkAcceptObvious({
76
- repoRoot: ctx.repoRoot,
77
- globs: await loadGlobs(ctx.repoRoot),
78
- threshold,
79
- dryRun,
80
- });
81
- if (!dryRun)
82
- ctx.counters.accepted += result.decsAccepted;
83
- return sendJson(res, 200, { ok: true, ...result });
84
- }
85
- if (parsedUrl.pathname === "/api/cluster/merge" && req.method === "POST") {
86
- const bodyRaw = await readJsonBody(req);
87
- const parsed = ClusterMergeInput.safeParse(bodyRaw);
88
- if (!parsed.success) {
89
- return sendJson(res, 400, { ok: false, error: "invalid input" });
90
- }
91
- const survivor = parsed.data.survivor_id;
92
- const members = parsed.data.member_ids ?? [];
93
- if (!survivor.startsWith("DEC-")) {
94
- return sendJson(res, 400, { ok: false, error: "missing survivor_id" });
95
- }
96
- let rejectedCount = 0;
97
- for (const m of members) {
98
- if (m === survivor)
99
- continue;
100
- const ok = await rejectDraft(ctx.repoRoot, m);
101
- if (ok)
102
- rejectedCount += 1;
103
- }
104
- ctx.counters.merged += rejectedCount;
105
- return sendJson(res, 200, { ok: true, survivor_id: survivor, rejected: rejectedCount });
106
- }
107
- // /api/draft/:id/<accept|reject|edit>
108
- const draftMatch = parsedUrl.pathname.match(/^\/api\/draft\/(DEC-[0-9a-f]{7,})\/(accept|reject|edit)$/);
109
- if (draftMatch !== null && req.method === "POST") {
110
- const id = draftMatch[1];
111
- const action = draftMatch[2];
112
- if (id === undefined || action === undefined) {
113
- return sendJson(res, 400, { ok: false, error: "invalid path" });
114
- }
115
- if (action === "accept") {
116
- const out = await acceptDraft(ctx.repoRoot, id);
117
- if (out.ok)
118
- ctx.counters.accepted += 1;
119
- return sendJson(res, out.ok ? 200 : 400, out);
120
- }
121
- if (action === "reject") {
122
- const ok = await rejectDraft(ctx.repoRoot, id);
123
- if (ok)
124
- ctx.counters.rejected += 1;
125
- return sendJson(res, ok ? 200 : 400, { ok });
126
- }
127
- if (action === "edit") {
128
- const bodyRaw = await readJsonBody(req);
129
- const parsed = EditDraftInput.safeParse(bodyRaw);
130
- if (!parsed.success) {
131
- return sendJson(res, 400, { ok: false, error: "invalid input" });
132
- }
133
- const result = await editDraft(ctx.repoRoot, id, parsed.data);
134
- if (result.ok)
135
- ctx.counters.edited += 1;
136
- return sendJson(res, result.ok ? 200 : 400, result);
137
- }
138
- }
139
- res.statusCode = 404;
140
- res.setHeader("content-type", "application/json");
141
- res.end(JSON.stringify({ ok: false, error: "no route" }));
142
- }
143
- catch (err) {
144
- log.error({ url, err: err instanceof Error ? err.message : String(err) }, "api handler threw");
145
- sendJson(res, 500, {
146
- ok: false,
147
- error: err instanceof Error ? err.message : "internal error",
148
- });
149
- }
150
- }
151
- function sendJson(res, status, body) {
152
- res.statusCode = status;
153
- res.setHeader("content-type", "application/json");
154
- res.setHeader("cache-control", "no-store");
155
- res.end(JSON.stringify(body));
156
- }
157
- async function readJsonBody(req) {
158
- return new Promise((resolve, reject) => {
159
- const chunks = [];
160
- let bytesReceived = 0;
161
- const timeout = setTimeout(() => {
162
- req.destroy();
163
- reject(new Error("body timeout"));
164
- }, BODY_TIMEOUT_MS);
165
- req.on("data", (c) => {
166
- if (!(c instanceof Buffer)) {
167
- return;
168
- }
169
- bytesReceived += c.length;
170
- if (bytesReceived > MAX_BODY_BYTES) {
171
- clearTimeout(timeout);
172
- req.destroy();
173
- reject(new Error("body too large"));
174
- return;
175
- }
176
- chunks.push(c);
177
- });
178
- req.on("error", (err) => {
179
- clearTimeout(timeout);
180
- reject(err);
181
- });
182
- req.on("end", () => {
183
- clearTimeout(timeout);
184
- const raw = Buffer.concat(chunks).toString("utf8");
185
- if (raw.length === 0)
186
- return resolve({});
187
- try {
188
- const parsed = JSON.parse(raw);
189
- resolve(typeof parsed === "object" && parsed !== null ? parsed : {});
190
- }
191
- catch {
192
- resolve({});
193
- }
194
- });
195
- });
196
- }
197
- async function loadGlobs(repoRoot) {
198
- const cfgPath = join(repoRoot, ".cairn", "config.yaml");
199
- if (!existsSync(cfgPath))
200
- return {};
201
- try {
202
- const raw = await readFile(cfgPath, "utf8");
203
- const parsed = parseYaml(raw);
204
- const result = ConfigSchema.safeParse(parsed);
205
- if (!result.success)
206
- return {};
207
- const cfg = result.data;
208
- const globs = {};
209
- const projectGlobs = cfg.project_globs;
210
- if (projectGlobs !== undefined) {
211
- if (projectGlobs.route_handler_globs)
212
- globs.route_handler_globs = projectGlobs.route_handler_globs;
213
- if (projectGlobs.dto_globs)
214
- globs.dto_globs = projectGlobs.dto_globs;
215
- if (projectGlobs.generator_source_globs)
216
- globs.generator_source_globs = projectGlobs.generator_source_globs;
217
- if (projectGlobs.high_stakes_globs)
218
- globs.high_stakes_globs = projectGlobs.high_stakes_globs;
219
- }
220
- if (cfg.off_limits)
221
- globs.off_limits = cfg.off_limits;
222
- return globs;
223
- }
224
- catch {
225
- return {};
226
- }
227
- }
228
- async function buildState(ctx) {
229
- const decDir = decisionsDir(ctx.repoRoot);
230
- const inboxDir = join(decDir, "_inbox");
231
- const drafts = [];
232
- if (existsSync(inboxDir)) {
233
- const entries = readdirSync(inboxDir, { withFileTypes: true });
234
- for (const e of entries) {
235
- if (!e.isFile() || !e.name.endsWith(".draft.md"))
236
- continue;
237
- const abs = join(inboxDir, e.name);
238
- let raw;
239
- try {
240
- raw = await readFile(abs, "utf8");
241
- }
242
- catch {
243
- continue;
244
- }
245
- const fm = parseFrontmatterRecord(raw).fm;
246
- const body = stripFrontmatter(raw);
247
- const id = stringField(fm, "id") ?? e.name.replace(/\.draft\.md$/, "");
248
- const title = stringField(fm, "proposedTitle") ??
249
- stringField(fm, "title") ??
250
- id;
251
- let mtimeMs = 0;
252
- try {
253
- mtimeMs = statSync(abs).mtimeMs;
254
- }
255
- catch {
256
- /* leave 0 */
257
- }
258
- drafts.push({
259
- id,
260
- path: `.cairn/ground/decisions/_inbox/${e.name}`,
261
- title,
262
- sourceFile: stringField(fm, "sourceFile") ?? "",
263
- source: stringField(fm, "capture_source") ?? "",
264
- confidence: stringField(fm, "capture_confidence"),
265
- body,
266
- proposedRationale: stringField(fm, "proposedRationale"),
267
- mtimeMs,
268
- });
269
- }
270
- drafts.sort((a, b) => a.mtimeMs - b.mtimeMs);
271
- }
272
- const dedup = findDuplicateClusters({ repoRoot: ctx.repoRoot });
273
- return {
274
- drafts,
275
- clusters: dedup.clusters,
276
- counts: {
277
- drafts: drafts.length,
278
- clusters: dedup.clusters.length,
279
- reducible: dedup.reducible,
280
- ...ctx.counters,
281
- },
282
- };
283
- }
284
- async function acceptDraft(repoRoot, id) {
285
- const decDir = decisionsDir(repoRoot);
286
- const inboxPath = join(decDir, "_inbox", `${id}.draft.md`);
287
- const acceptedPath = join(decDir, `${id}.md`);
288
- if (!existsSync(inboxPath)) {
289
- return { ok: false, error: `no draft at ${inboxPath}` };
290
- }
291
- return await withWriteLock(repoRoot, async () => {
292
- await mkdir(dirname(acceptedPath), { recursive: true });
293
- const draft = await readFile(inboxPath, "utf8");
294
- const meta = parseDraftMeta(draft);
295
- const promoted = draft.replace(/^status:\s*draft(?:-from-[a-z-]+)?\b/m, "status: accepted");
296
- await writeFile(acceptedPath, promoted, "utf8");
297
- try {
298
- await rm(inboxPath, { force: true });
299
- }
300
- catch {
301
- /* best-effort */
302
- }
303
- try {
304
- writeInvalidationEvent(repoRoot, {
305
- kind: "decision_accepted",
306
- refs: [{ kind: "decision", id }],
307
- path: `.cairn/ground/decisions/${id}.md`,
308
- source: { session_id: null, tool: "cairn_attention_serve" },
309
- });
310
- }
311
- catch {
312
- /* best-effort */
313
- }
314
- try {
315
- writeDecisionsLedger({ repoRoot });
316
- }
317
- catch (err) {
318
- log.warn({ err: err instanceof Error ? err.message : String(err) }, "ledger rebuild failed after accept");
319
- }
320
- if (meta?.captureSource === "init-source-comments" &&
321
- meta.blockId !== null) {
322
- runDecSourceStrip({ repoRoot, decId: id, meta });
323
- }
324
- return { ok: true };
325
- });
326
- }
327
- async function rejectDraft(repoRoot, id) {
328
- const decDir = decisionsDir(repoRoot);
329
- const inboxPath = join(decDir, "_inbox", `${id}.draft.md`);
330
- const rejectedPath = join(decDir, "_inbox", `${id}.rejected.md`);
331
- if (!existsSync(inboxPath))
332
- return false;
333
- return await withWriteLock(repoRoot, async () => {
334
- await rename(inboxPath, rejectedPath);
335
- try {
336
- writeInvalidationEvent(repoRoot, {
337
- kind: "decision_rejected",
338
- refs: [{ kind: "decision", id }],
339
- path: `.cairn/ground/decisions/_inbox/${id}.rejected.md`,
340
- source: { session_id: null, tool: "cairn_attention_serve" },
341
- });
342
- }
343
- catch {
344
- /* best-effort */
345
- }
346
- return true;
347
- });
348
- }
349
- async function editDraft(repoRoot, id, input) {
350
- const decDir = decisionsDir(repoRoot);
351
- const inboxPath = join(decDir, "_inbox", `${id}.draft.md`);
352
- if (!existsSync(inboxPath))
353
- return { ok: false, error: "draft missing" };
354
- const newTitle = input.title ?? null;
355
- const newRationale = input.body_markdown ?? null;
356
- if (newTitle === null && newRationale === null) {
357
- return { ok: false, error: "no fields to update" };
358
- }
359
- return await withWriteLock(repoRoot, async () => {
360
- let raw = await readFile(inboxPath, "utf8");
361
- if (newTitle !== null) {
362
- raw = raw.replace(/^title:.*$/m, `title: ${JSON.stringify(newTitle)}`);
363
- raw = raw.replace(/^# DEC-[0-9a-f]{7,} —.*$/m, `# ${id} — ${newTitle}`);
364
- }
365
- if (newRationale !== null) {
366
- // Replace the whole body after the frontmatter with the new rationale
367
- // wrapped in the canonical heading. Preserves frontmatter.
368
- const fmMatch = raw.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
369
- const fm = fmMatch?.[0] ?? "";
370
- raw = `${fm}\n# ${id}\n\n## Proposed rationale\n\n${newRationale}\n`;
371
- }
372
- await writeFile(inboxPath, raw, "utf8");
373
- return { ok: true };
374
- });
375
- }
376
- function stripFrontmatter(doc) {
377
- return doc.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
378
- }
379
- function stringField(fm, key) {
380
- const v = fm[key];
381
- return typeof v === "string" ? v : null;
382
- }
383
- //# sourceMappingURL=api.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/attention/serve/api.ts"],"names":[],"mappings":"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"}
@@ -1,63 +0,0 @@
1
- /**
2
- * Browser-based DEC-draft triage GUI.
3
- *
4
- * Spawned by `cairn attention serve` (CLI) or
5
- * `cairn_attention_serve` (MCP). Operator drains the inbox in the
6
- * browser instead of through `AskUserQuestion` round-trips, then
7
- * clicks "I'm done" — the server writes a sentinel at
8
- * `.cairn/cache/attention-done.json` that the caller polls (via
9
- * `cairn_attention_wait` or by tailing the file).
10
- *
11
- * Why a GUI: at >15 drafts the inline `AskUserQuestion` flow burns
12
- * `cairn_decision_get` calls per draft and 4-cap-per-question batches
13
- * the operator through dozens of MCP turns. The browser does all the
14
- * I/O directly against `.cairn/`, dropping per-triage round-trips to
15
- * zero.
16
- *
17
- * Mechanics:
18
- * - HTTP server on a free port (or operator-supplied), bound to
19
- * 127.0.0.1 so the surface is local-only.
20
- * - JSON API mirrors the existing attention handlers (bulk-accept,
21
- * dedup, resolve, restore) so all writes funnel through the same
22
- * `withWriteLock` path the MCP tools use.
23
- * - Static SPA bundle (vanilla HTML+JS+CSS) under
24
- * `cairn-core/templates/attention-ui/` — no build step.
25
- * - Idle timeout: 10 min default, reset by `/api/heartbeat`. Server
26
- * shuts down when idle exceeds the timeout or on `/api/done`.
27
- */
28
- /** Read-only accessor for `cairn_attention_wait` and tests. */
29
- export declare function getActiveAttentionServer(repoRoot: string): AttentionServeHandle | undefined;
30
- export interface AttentionServeOptions {
31
- repoRoot: string;
32
- /** Listen port. Pass 0 to let the OS pick. */
33
- port: number;
34
- /** Idle (no heartbeat / no API activity) before auto-shutdown. */
35
- idleTimeoutMs?: number;
36
- /** Optional caller-supplied abort signal. */
37
- signal?: AbortSignal;
38
- }
39
- export interface AttentionServeHandle {
40
- port: number;
41
- url: string;
42
- token: string;
43
- sentinelPath: string;
44
- /** Resolves once the server has shut down (operator clicked Done or idled out). */
45
- done: Promise<DoneState>;
46
- /** Force shutdown — typically wired to SIGINT / SIGTERM in CLI. */
47
- close: () => Promise<void>;
48
- }
49
- export interface DoneState {
50
- reason: "done" | "idle" | "abort";
51
- accepted: number;
52
- rejected: number;
53
- merged: number;
54
- edited: number;
55
- startedAt: string;
56
- endedAt: string;
57
- }
58
- /**
59
- * Boot the triage server. Returns once the listener is ready;
60
- * `handle.done` resolves when the operator finishes or the server
61
- * idles out.
62
- */
63
- export declare function startAttentionServer(opts: AttentionServeOptions): Promise<AttentionServeHandle>;