@isaacriehm/cairn-core 0.7.3 → 0.8.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 (117) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/doctor/index.js +57 -0
  3. package/dist/doctor/index.js.map +1 -1
  4. package/dist/gc/citation-integrity.js +3 -1
  5. package/dist/gc/citation-integrity.js.map +1 -1
  6. package/dist/gc/doc-claims.d.ts +31 -0
  7. package/dist/gc/doc-claims.js +213 -0
  8. package/dist/gc/doc-claims.js.map +1 -0
  9. package/dist/gc/doc-source-drift.d.ts +31 -0
  10. package/dist/gc/doc-source-drift.js +190 -0
  11. package/dist/gc/doc-source-drift.js.map +1 -0
  12. package/dist/gc/index.d.ts +4 -0
  13. package/dist/gc/index.js +2 -0
  14. package/dist/gc/index.js.map +1 -1
  15. package/dist/gc/sweep.js +18 -0
  16. package/dist/gc/sweep.js.map +1 -1
  17. package/dist/gc/types.d.ts +2 -2
  18. package/dist/hooks/runners/context-threshold.d.ts +63 -0
  19. package/dist/hooks/runners/context-threshold.js +179 -0
  20. package/dist/hooks/runners/context-threshold.js.map +1 -0
  21. package/dist/hooks/runners/gc-autotrigger.d.ts +49 -0
  22. package/dist/hooks/runners/gc-autotrigger.js +87 -0
  23. package/dist/hooks/runners/gc-autotrigger.js.map +1 -0
  24. package/dist/hooks/runners/index.d.ts +2 -0
  25. package/dist/hooks/runners/index.js +1 -0
  26. package/dist/hooks/runners/index.js.map +1 -1
  27. package/dist/hooks/runners/session-start.js +110 -6
  28. package/dist/hooks/runners/session-start.js.map +1 -1
  29. package/dist/hooks/runners/stop.js +119 -0
  30. package/dist/hooks/runners/stop.js.map +1 -1
  31. package/dist/init/index.d.ts +5 -1
  32. package/dist/init/index.js +2 -0
  33. package/dist/init/index.js.map +1 -1
  34. package/dist/init/ingest-docs.d.ts +6 -1
  35. package/dist/init/ingest-docs.js.map +1 -1
  36. package/dist/init/init.js +11 -6
  37. package/dist/init/init.js.map +1 -1
  38. package/dist/init/mapper-parallel.js +13 -6
  39. package/dist/init/mapper-parallel.js.map +1 -1
  40. package/dist/init/phases/1-detect.d.ts +17 -4
  41. package/dist/init/phases/1-detect.js +48 -4
  42. package/dist/init/phases/1-detect.js.map +1 -1
  43. package/dist/init/phases/10-rules-merge.js +13 -1
  44. package/dist/init/phases/10-rules-merge.js.map +1 -1
  45. package/dist/init/phases/11-baseline.js.map +1 -1
  46. package/dist/init/phases/12-strip.js +14 -1
  47. package/dist/init/phases/12-strip.js.map +1 -1
  48. package/dist/init/phases/3-mapper.js.map +1 -1
  49. package/dist/init/phases/4-seed.js +1 -1
  50. package/dist/init/phases/4-seed.js.map +1 -1
  51. package/dist/init/phases/5-pilot.js.map +1 -1
  52. package/dist/init/phases/6-brand.js +2 -4
  53. package/dist/init/phases/6-brand.js.map +1 -1
  54. package/dist/init/phases/8-docs-ingest.js +13 -1
  55. package/dist/init/phases/8-docs-ingest.js.map +1 -1
  56. package/dist/init/phases/9-source-comments.js +13 -1
  57. package/dist/init/phases/9-source-comments.js.map +1 -1
  58. package/dist/init/phases/orchestrator.d.ts +10 -0
  59. package/dist/init/phases/orchestrator.js +12 -0
  60. package/dist/init/phases/orchestrator.js.map +1 -1
  61. package/dist/init/phases/parallel-8910.js +29 -4
  62. package/dist/init/phases/parallel-8910.js.map +1 -1
  63. package/dist/init/phases/source-comments-output-io.d.ts +7 -2
  64. package/dist/init/phases/source-comments-output-io.js.map +1 -1
  65. package/dist/init/phases/types.d.ts +49 -9
  66. package/dist/init/phases/types.js.map +1 -1
  67. package/dist/init/post-git-init.d.ts +53 -0
  68. package/dist/init/post-git-init.js +74 -0
  69. package/dist/init/post-git-init.js.map +1 -0
  70. package/dist/init/preflight-guards.d.ts +11 -2
  71. package/dist/init/preflight-guards.js +27 -5
  72. package/dist/init/preflight-guards.js.map +1 -1
  73. package/dist/init/rules-merge/index.d.ts +1 -1
  74. package/dist/init/rules-merge/ingest.d.ts +6 -1
  75. package/dist/init/rules-merge/ingest.js.map +1 -1
  76. package/dist/init/skill-budget.d.ts +39 -0
  77. package/dist/init/skill-budget.js +99 -0
  78. package/dist/init/skill-budget.js.map +1 -0
  79. package/dist/init/types.d.ts +9 -0
  80. package/dist/mcp/bootstrap-guard.js +2 -2
  81. package/dist/mcp/bootstrap-guard.js.map +1 -1
  82. package/dist/mcp/schemas.d.ts +34 -0
  83. package/dist/mcp/schemas.js +50 -0
  84. package/dist/mcp/schemas.js.map +1 -1
  85. package/dist/mcp/telemetry.d.ts +1 -1
  86. package/dist/mcp/tools/bootstrap-retry.d.ts +23 -0
  87. package/dist/mcp/tools/bootstrap-retry.js +53 -0
  88. package/dist/mcp/tools/bootstrap-retry.js.map +1 -0
  89. package/dist/mcp/tools/index.js +10 -0
  90. package/dist/mcp/tools/index.js.map +1 -1
  91. package/dist/mcp/tools/init-phases.js +4 -8
  92. package/dist/mcp/tools/init-phases.js.map +1 -1
  93. package/dist/mcp/tools/resume.d.ts +21 -0
  94. package/dist/mcp/tools/resume.js +88 -0
  95. package/dist/mcp/tools/resume.js.map +1 -0
  96. package/dist/mcp/tools/task-complete.d.ts +23 -0
  97. package/dist/mcp/tools/task-complete.js +51 -0
  98. package/dist/mcp/tools/task-complete.js.map +1 -0
  99. package/dist/mcp/tools/task-create.js +17 -11
  100. package/dist/mcp/tools/task-create.js.map +1 -1
  101. package/dist/mcp/tools/task-journal-append.d.ts +22 -0
  102. package/dist/mcp/tools/task-journal-append.js +44 -0
  103. package/dist/mcp/tools/task-journal-append.js.map +1 -0
  104. package/dist/paths/index.js +1 -1
  105. package/dist/paths/index.js.map +1 -1
  106. package/dist/status-line/format.js +20 -0
  107. package/dist/status-line/format.js.map +1 -1
  108. package/dist/tasks/index.d.ts +2 -0
  109. package/dist/tasks/index.js +2 -0
  110. package/dist/tasks/index.js.map +1 -0
  111. package/dist/tasks/lifecycle.d.ts +107 -0
  112. package/dist/tasks/lifecycle.js +302 -0
  113. package/dist/tasks/lifecycle.js.map +1 -0
  114. package/dist/trace/index.d.ts +1 -1
  115. package/dist/trace/index.js +2 -2
  116. package/dist/trace/index.js.map +1 -1
  117. package/package.json +2 -2
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `cairn_resume` — read the active task's journal + spec and emit a
3
+ * resume payload that primes a fresh-context session cold.
4
+ *
5
+ * Called by the `/cairn-resume <task_id>` slash command after the
6
+ * operator `/clear`s mid-task. SessionStart hook also calls this
7
+ * automatically when it detects an active task whose journal has
8
+ * entries from a prior session_id.
9
+ *
10
+ * The payload is structured so the slash-command body can render a
11
+ * tight resume context block: title, goal, what's been done, what's
12
+ * next, in-scope decisions/invariants. No Haiku call — pure read.
13
+ */
14
+ import type { ToolDef } from "./types.js";
15
+ interface Input {
16
+ task_id?: string;
17
+ /** Cap on most-recent journal entries returned. Default 7. */
18
+ max_entries?: number;
19
+ }
20
+ export declare const resumeTool: ToolDef<Input>;
21
+ export {};
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `cairn_resume` — read the active task's journal + spec and emit a
3
+ * resume payload that primes a fresh-context session cold.
4
+ *
5
+ * Called by the `/cairn-resume <task_id>` slash command after the
6
+ * operator `/clear`s mid-task. SessionStart hook also calls this
7
+ * automatically when it detects an active task whose journal has
8
+ * entries from a prior session_id.
9
+ *
10
+ * The payload is structured so the slash-command body can render a
11
+ * tight resume context block: title, goal, what's been done, what's
12
+ * next, in-scope decisions/invariants. No Haiku call — pure read.
13
+ */
14
+ import { existsSync, readFileSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { parse as parseYaml } from "yaml";
17
+ import { mcpError } from "../errors.js";
18
+ import { resumeInput } from "../schemas.js";
19
+ import { findCurrentActiveTask, readTaskJournal, } from "../../tasks/index.js";
20
+ async function handler(ctx, input) {
21
+ const taskId = input.task_id ?? findCurrentActiveTask(ctx.repoRoot);
22
+ if (taskId === null) {
23
+ return mcpError("TASK_NOT_FOUND", "no active task to resume");
24
+ }
25
+ const taskDir = join(ctx.repoRoot, ".cairn", "tasks", "active", taskId);
26
+ if (!existsSync(taskDir)) {
27
+ return mcpError("TASK_NOT_FOUND", `active task directory missing: .cairn/tasks/active/${taskId}/`);
28
+ }
29
+ const specPath = join(taskDir, "spec.tightened.md");
30
+ let title = taskId;
31
+ let goal = "(spec not found)";
32
+ let inScopeDecisions = [];
33
+ let inScopeInvariants = [];
34
+ let targetPathGlobs = [];
35
+ if (existsSync(specPath)) {
36
+ const raw = readFileSync(specPath, "utf8");
37
+ const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\n---\r?\n([\s\S]*)$/);
38
+ if (fmMatch) {
39
+ try {
40
+ const fm = parseYaml(fmMatch[1] ?? "");
41
+ if (typeof fm.title === "string")
42
+ title = fm.title;
43
+ if (Array.isArray(fm.in_scope_decisions)) {
44
+ inScopeDecisions = fm.in_scope_decisions.filter((x) => typeof x === "string");
45
+ }
46
+ if (Array.isArray(fm.in_scope_invariants)) {
47
+ inScopeInvariants = fm.in_scope_invariants.filter((x) => typeof x === "string");
48
+ }
49
+ if (Array.isArray(fm.target_path_globs)) {
50
+ targetPathGlobs = fm.target_path_globs.filter((x) => typeof x === "string");
51
+ }
52
+ }
53
+ catch {
54
+ // malformed frontmatter — fall through with defaults
55
+ }
56
+ const body = fmMatch[2] ?? "";
57
+ const goalMatch = body.match(/##\s+Goal\s*\r?\n+([\s\S]*?)(?:\r?\n##\s+|$)/);
58
+ if (goalMatch && goalMatch[1] !== undefined) {
59
+ goal = goalMatch[1].trim();
60
+ }
61
+ }
62
+ }
63
+ const journal = readTaskJournal(ctx.repoRoot, taskId, "active");
64
+ const cap = Math.max(1, Math.min(50, input.max_entries ?? 7));
65
+ const recent = journal.slice(-cap);
66
+ const lastEntry = journal.length > 0 ? journal[journal.length - 1] : null;
67
+ const nextStep = lastEntry?.next_step ?? null;
68
+ const payload = {
69
+ ok: true,
70
+ task_id: taskId,
71
+ title,
72
+ goal,
73
+ in_scope_decisions: inScopeDecisions,
74
+ in_scope_invariants: inScopeInvariants,
75
+ target_path_globs: targetPathGlobs,
76
+ recent_entries: recent,
77
+ next_step: nextStep,
78
+ total_entries: journal.length,
79
+ };
80
+ return payload;
81
+ }
82
+ export const resumeTool = {
83
+ name: "cairn_resume",
84
+ description: "Read the active task's journal + tightened spec and emit a resume payload (title, goal, in-scope DECs/INVs, last N journal entries, last-known next_step). Used after `/clear` to rebuild operator context cold. `task_id` defaults to the most-recently-touched active task.",
85
+ inputSchema: resumeInput,
86
+ handler,
87
+ };
88
+ //# sourceMappingURL=resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/mcp/tools/resume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,qBAAqB,EACrB,eAAe,GAEhB,MAAM,sBAAsB,CAAC;AA4B9B,KAAK,UAAU,OAAO,CAAC,GAAe,EAAE,KAAY;IAClD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,QAAQ,CACb,gBAAgB,EAChB,0BAA0B,CAC3B,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,QAAQ,CACb,gBAAgB,EAChB,sDAAsD,MAAM,GAAG,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACpD,IAAI,KAAK,GAAG,MAAM,CAAC;IACnB,IAAI,IAAI,GAAG,kBAAkB,CAAC;IAC9B,IAAI,gBAAgB,GAAa,EAAE,CAAC;IACpC,IAAI,iBAAiB,GAAa,EAAE,CAAC;IACrC,IAAI,eAAe,GAAa,EAAE,CAAC;IAEnC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACrE,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAoB,CAAC;gBAC1D,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ;oBAAE,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;gBACnD,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC;oBACzC,gBAAgB,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAC7C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;gBACJ,CAAC;gBACD,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC1C,iBAAiB,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;gBACJ,CAAC;gBACD,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;oBACxC,eAAe,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC1C,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC7E,IAAI,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC5C,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,QAAQ,GAAG,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC;IAE9C,MAAM,OAAO,GAAkB;QAC7B,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,MAAM;QACf,KAAK;QACL,IAAI;QACJ,kBAAkB,EAAE,gBAAgB;QACpC,mBAAmB,EAAE,iBAAiB;QACtC,iBAAiB,EAAE,eAAe;QAClC,cAAc,EAAE,MAAM;QACtB,SAAS,EAAE,QAAQ;QACnB,aAAa,EAAE,OAAO,CAAC,MAAM;KAC9B,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAmB;IACxC,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,+QAA+Q;IACjR,WAAW,EAAE,WAAW;IACxB,OAAO;CACR,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `cairn_task_complete` — graduate an active task to a terminal phase
3
+ * and move its directory to `.cairn/tasks/done/`.
4
+ *
5
+ * Tasks created by `cairn_task_create` start at `phase: running`.
6
+ * This tool is the explicit terminal write — called by the reviewer
7
+ * subagent after attestation, by the cairn-direction skill on a
8
+ * confirmed pivot, or by the Stop-hook auto-graduator when the
9
+ * reviewer attestation lands.
10
+ *
11
+ * Outcomes:
12
+ * - `succeeded` — work complete, attestation present
13
+ * - `failed` — work attempted but did not pass acceptance
14
+ * - `aborted` — task abandoned (operator pivoted, scope removed)
15
+ */
16
+ import type { ToolDef } from "./types.js";
17
+ interface Input {
18
+ task_id: string;
19
+ outcome: "succeeded" | "failed" | "aborted";
20
+ summary?: string;
21
+ }
22
+ export declare const taskCompleteTool: ToolDef<Input>;
23
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `cairn_task_complete` — graduate an active task to a terminal phase
3
+ * and move its directory to `.cairn/tasks/done/`.
4
+ *
5
+ * Tasks created by `cairn_task_create` start at `phase: running`.
6
+ * This tool is the explicit terminal write — called by the reviewer
7
+ * subagent after attestation, by the cairn-direction skill on a
8
+ * confirmed pivot, or by the Stop-hook auto-graduator when the
9
+ * reviewer attestation lands.
10
+ *
11
+ * Outcomes:
12
+ * - `succeeded` — work complete, attestation present
13
+ * - `failed` — work attempted but did not pass acceptance
14
+ * - `aborted` — task abandoned (operator pivoted, scope removed)
15
+ */
16
+ import { requireBootstrap } from "../bootstrap-guard.js";
17
+ import { mcpError } from "../errors.js";
18
+ import { taskCompleteInput } from "../schemas.js";
19
+ import { completeTask } from "../../tasks/index.js";
20
+ async function handler(ctx, input) {
21
+ const block = requireBootstrap(ctx.repoRoot);
22
+ if (block !== null)
23
+ return block;
24
+ const result = completeTask({
25
+ repoRoot: ctx.repoRoot,
26
+ taskId: input.task_id,
27
+ outcome: input.outcome,
28
+ ...(input.summary !== undefined ? { summary: input.summary } : {}),
29
+ source: "cairn_task_complete",
30
+ });
31
+ if (!result.ok) {
32
+ if (result.code === "TASK_NOT_FOUND" || result.code === "ALREADY_COMPLETED") {
33
+ return mcpError("TASK_NOT_FOUND", result.message);
34
+ }
35
+ return mcpError("INTERNAL_ERROR", result.message);
36
+ }
37
+ return {
38
+ ok: true,
39
+ task_id: result.taskId,
40
+ outcome: result.outcome,
41
+ completed_at: result.completedAt,
42
+ moved_to: result.movedTo,
43
+ };
44
+ }
45
+ export const taskCompleteTool = {
46
+ name: "cairn_task_complete",
47
+ description: "Graduate an active task (`.cairn/tasks/active/<task_id>/`) to a terminal phase (succeeded / failed / aborted) and move its directory to `.cairn/tasks/done/`. Called by the reviewer subagent after writing attestation.yaml, by the cairn-direction skill on a confirmed pivot, or by the Stop-hook auto-graduator. Returns TASK_NOT_FOUND if the task was already completed.",
48
+ inputSchema: taskCompleteInput,
49
+ handler,
50
+ };
51
+ //# sourceMappingURL=task-complete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-complete.js","sourceRoot":"","sources":["../../../src/mcp/tools/task-complete.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAQpD,KAAK,UAAU,OAAO,CAAC,GAAe,EAAE,KAAY;IAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAEjC,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,KAAK,CAAC,OAAO;QACrB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,EAAE,qBAAqB;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC5E,OAAO,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,YAAY,EAAE,MAAM,CAAC,WAAW;QAChC,QAAQ,EAAE,MAAM,CAAC,OAAO;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC9C,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACT,gXAAgX;IAClX,WAAW,EAAE,iBAAiB;IAC9B,OAAO;CACR,CAAC"}
@@ -1,23 +1,29 @@
1
1
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import { createHash, randomUUID } from "node:crypto";
3
4
  import { stringify as stringifyYaml } from "yaml";
4
5
  import { requireBootstrap } from "../bootstrap-guard.js";
5
6
  import { mcpError } from "../errors.js";
6
7
  import { taskCreateInput } from "../schemas.js";
7
8
  /**
8
- * Generate a `task_id` matching the regex
9
- * `^TSK-\d{4}-\d{2}-\d{2}-[a-z0-9-]+-\d{5}$`. The 5-digit millisecond
10
- * suffix collides only on same-millisecond invocations within the
11
- * same slug which never happens in practice and would be caught by
12
- * the directory-already-exists check anyway.
9
+ * Generate a `task_id` matching the regex `^TSK-[a-z0-9-]+-[0-9a-f]{7}$`.
10
+ *
11
+ * Format: `TSK-<slug>-<7-hex>` where the 7-hex suffix is the first
12
+ * 7 chars of `sha256(slug + crypto.randomUUID())`. Stable, content-
13
+ * addressed, no counter file, no rollover. ~268M unique values per
14
+ * slug bucket; cross-slug collisions impossible because the slug is
15
+ * in the id.
16
+ *
17
+ * Rationale: operators don't manually check task numbers; if order
18
+ * matters, `ls .cairn/tasks/` sorts by mtime. Hash is the safer
19
+ * long-haul format.
13
20
  */
14
21
  function generateTaskId(slug) {
15
- const now = new Date();
16
- const yyyy = String(now.getUTCFullYear());
17
- const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
18
- const dd = String(now.getUTCDate()).padStart(2, "0");
19
- const ms = String(now.getTime()).slice(-5).padStart(5, "0");
20
- return `TSK-${yyyy}-${mm}-${dd}-${slug}-${ms}`;
22
+ const hash = createHash("sha256")
23
+ .update(`${slug}${randomUUID()}`, "utf8")
24
+ .digest("hex")
25
+ .slice(0, 7);
26
+ return `TSK-${slug}-${hash}`;
21
27
  }
22
28
  function renderInvariantId(id) {
23
29
  return id.startsWith("§") ? id : `§${id}`;
@@ -1 +1 @@
1
- {"version":3,"file":"task-create.js","sourceRoot":"","sources":["../../../src/mcp/tools/task-create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"task-create.js","sourceRoot":"","sources":["../../../src/mcp/tools/task-create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `cairn_task_journal_append` — append a per-turn journal entry to
3
+ * the active task. The journal is the authoritative record that
4
+ * survives `/clear` so a fresh session can resume cold.
5
+ *
6
+ * Cairn-as-resume-layer: main Claude calls this at the end of every
7
+ * assistant turn while a task is active. Stop hook surfaces a context-
8
+ * threshold prompt when usage crosses the configured limit; the
9
+ * `/cairn-resume <task_id>` slash command in the next session reads
10
+ * the journal back via `cairn_resume`.
11
+ */
12
+ import type { ToolDef } from "./types.js";
13
+ interface Input {
14
+ task_id?: string;
15
+ summary: string;
16
+ next_step?: string;
17
+ files_touched?: string[];
18
+ decisions_loaded?: string[];
19
+ session_id?: string;
20
+ }
21
+ export declare const taskJournalAppendTool: ToolDef<Input>;
22
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `cairn_task_journal_append` — append a per-turn journal entry to
3
+ * the active task. The journal is the authoritative record that
4
+ * survives `/clear` so a fresh session can resume cold.
5
+ *
6
+ * Cairn-as-resume-layer: main Claude calls this at the end of every
7
+ * assistant turn while a task is active. Stop hook surfaces a context-
8
+ * threshold prompt when usage crosses the configured limit; the
9
+ * `/cairn-resume <task_id>` slash command in the next session reads
10
+ * the journal back via `cairn_resume`.
11
+ */
12
+ import { requireBootstrap } from "../bootstrap-guard.js";
13
+ import { mcpError } from "../errors.js";
14
+ import { taskJournalAppendInput } from "../schemas.js";
15
+ import { appendTaskJournal, findCurrentActiveTask } from "../../tasks/index.js";
16
+ async function handler(ctx, input) {
17
+ const block = requireBootstrap(ctx.repoRoot);
18
+ if (block !== null)
19
+ return block;
20
+ const taskId = input.task_id ?? findCurrentActiveTask(ctx.repoRoot);
21
+ if (taskId === null) {
22
+ return mcpError("TASK_NOT_FOUND", "no active task — call cairn_task_create first or pass task_id explicitly");
23
+ }
24
+ const ok = appendTaskJournal({
25
+ repoRoot: ctx.repoRoot,
26
+ taskId,
27
+ sessionId: input.session_id ?? null,
28
+ summary: input.summary,
29
+ ...(input.next_step !== undefined ? { nextStep: input.next_step } : {}),
30
+ ...(input.files_touched !== undefined ? { filesTouched: input.files_touched } : {}),
31
+ ...(input.decisions_loaded !== undefined ? { decisionsLoaded: input.decisions_loaded } : {}),
32
+ });
33
+ if (!ok) {
34
+ return mcpError("TASK_NOT_FOUND", `active task directory missing: .cairn/tasks/active/${taskId}/`);
35
+ }
36
+ return { ok: true, task_id: taskId };
37
+ }
38
+ export const taskJournalAppendTool = {
39
+ name: "cairn_task_journal_append",
40
+ description: "Append one journal entry to the active task's journal.jsonl. Call at the end of every assistant turn while a task is active so that `/cairn-resume <task_id>` after a `/clear` rebuilds the operator's mental state cold. `summary` is a ≤160-char one-liner of what just happened; `next_step` is what comes next. `task_id` is optional — Cairn picks the most-recently-touched active task when omitted.",
41
+ inputSchema: taskJournalAppendInput,
42
+ handler,
43
+ };
44
+ //# sourceMappingURL=task-journal-append.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-journal-append.js","sourceRoot":"","sources":["../../../src/mcp/tools/task-journal-append.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAWhF,KAAK,UAAU,OAAO,CAAC,GAAe,EAAE,KAAY;IAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAEjC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,QAAQ,CACb,gBAAgB,EAChB,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,iBAAiB,CAAC;QAC3B,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM;QACN,SAAS,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;QACnC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnF,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7F,CAAC,CAAC;IAEH,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,QAAQ,CACb,gBAAgB,EAChB,sDAAsD,MAAM,GAAG,CAChE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAmB;IACnD,IAAI,EAAE,2BAA2B;IACjC,WAAW,EACT,6YAA6Y;IAC/Y,WAAW,EAAE,sBAAsB;IACnC,OAAO;CACR,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join, resolve } from "node:path";
3
- const CAIRN_HOME_ROOT = ".local/cairn";
3
+ const CAIRN_HOME_ROOT = ".cairn";
4
4
  export function cairnHome() {
5
5
  return resolve(homedir(), CAIRN_HOME_ROOT);
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,eAAe,GAAG,cAAc,CAAC;AAIvC,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC9C,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,SAAiB;IACjE,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACnF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,qBAAqB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC3E,MAAM,IAAI,GAAG,UAAU;SACpB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,qBAAqB,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,eAAe,GAAG,QAAQ,CAAC;AAIjC,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC9C,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,SAAiB;IACjE,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACnF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,qBAAqB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC3E,MAAM,IAAI,GAAG,UAAU;SACpB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,qBAAqB,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -105,8 +105,28 @@ function renderSignal(s, progress, nowMs = Date.now()) {
105
105
  const summary = summaryCounterText(s.event_counters);
106
106
  if (summary !== null)
107
107
  return summary;
108
+ // Idle heartbeat — flips the idle state from "silent = healthy" to
109
+ // "visible = healthy" so the operator never has to wonder whether
110
+ // Cairn is alive. Renders only when there is actual ground state in
111
+ // scope; on a fresh adoption with zero decisions the line stays
112
+ // minimal.
113
+ const heartbeat = renderIdleHeartbeat(s);
114
+ if (heartbeat !== null)
115
+ return heartbeat;
108
116
  return null;
109
117
  }
118
+ /**
119
+ * Idle heartbeat — `✓ <N>·<M>` where N = decisions in scope, M = §INV
120
+ * invariants in scope. Returns null when both counts are zero (a brand-
121
+ * new adoption where the load-bearing surfaces haven't filled yet).
122
+ */
123
+ function renderIdleHeartbeat(s) {
124
+ const dec = Math.max(0, s.decisions_in_scope ?? 0);
125
+ const inv = Math.max(0, s.invariants_in_scope ?? 0);
126
+ if (dec === 0 && inv === 0)
127
+ return null;
128
+ return `✓ ${dec}·${inv}`;
129
+ }
110
130
  export function formatStatus(s, ctx, progress, nowMs = Date.now()) {
111
131
  const parts = ["⬡ cairn"];
112
132
  const signal = renderSignal(s, progress ?? null, nowMs);
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/status-line/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/status-line/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { appendTaskJournal, completeTask, findCurrentActiveTask, readTaskAttestationState, readTaskJournal, transitionTaskPhase, } from "./lifecycle.js";
2
+ export type { AppendJournalArgs, CompleteTaskArgs, CompleteTaskError, CompleteTaskResult, JournalEntry, TaskAttestationState, TaskOutcome, TaskTransitionPhase, TransitionTaskPhaseArgs, } from "./lifecycle.js";
@@ -0,0 +1,2 @@
1
+ export { appendTaskJournal, completeTask, findCurrentActiveTask, readTaskAttestationState, readTaskJournal, transitionTaskPhase, } from "./lifecycle.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,wBAAwB,EACxB,eAAe,EACf,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Task lifecycle helpers — the only sanctioned writers of `status.yaml`
3
+ * phase transitions and the only path that moves a task directory from
4
+ * `tasks/active/` to `tasks/done/`.
5
+ *
6
+ * Two surfaces:
7
+ * - `completeTask` — terminal phase + dir move; emits invalidation.
8
+ * - `transitionTaskPhase` — in-place phase write (e.g. running →
9
+ * ready_for_review); no dir move.
10
+ *
11
+ * Plus a read helper `readTaskAttestationState` used by the Stop hook
12
+ * auto-graduator to decide which transition (if any) to apply.
13
+ *
14
+ * Tasks created by `cairn_task_create` start at `phase: running`.
15
+ * The reviewer subagent calls `completeTask` after writing
16
+ * `attestation.yaml`; the Stop hook auto-graduator handles the cases
17
+ * where the reviewer is skipped (trivial tasks with
18
+ * `needs_review: false`).
19
+ */
20
+ export type TaskOutcome = "succeeded" | "failed" | "aborted";
21
+ export type TaskTransitionPhase = "queued" | "tightening" | "running" | "sensor_check" | "ready_for_review" | "awaiting_attestation" | "reviewing" | "backprop";
22
+ export interface CompleteTaskArgs {
23
+ repoRoot: string;
24
+ taskId: string;
25
+ outcome: TaskOutcome;
26
+ summary?: string;
27
+ /**
28
+ * What invoked this completion — written into the invalidation event
29
+ * `source.tool` field. Defaults to `cairn_task_complete`; the Stop
30
+ * hook auto-graduator passes `cairn_stop_auto_graduate` so the audit
31
+ * log distinguishes the two paths.
32
+ */
33
+ source?: string;
34
+ }
35
+ export interface CompleteTaskResult {
36
+ ok: true;
37
+ taskId: string;
38
+ outcome: TaskOutcome;
39
+ completedAt: string;
40
+ movedTo: string;
41
+ }
42
+ export interface CompleteTaskError {
43
+ ok: false;
44
+ code: "TASK_NOT_FOUND" | "ALREADY_COMPLETED" | "DONE_DIR_COLLISION";
45
+ message: string;
46
+ }
47
+ /**
48
+ * Write the terminal phase + move the active dir → done. Returns an
49
+ * error envelope on failure rather than throwing — callers (MCP tool,
50
+ * Stop hook) decide how to surface.
51
+ */
52
+ export declare function completeTask(args: CompleteTaskArgs): CompleteTaskResult | CompleteTaskError;
53
+ export interface TransitionTaskPhaseArgs {
54
+ repoRoot: string;
55
+ taskId: string;
56
+ newPhase: TaskTransitionPhase;
57
+ }
58
+ export declare function transitionTaskPhase(args: TransitionTaskPhaseArgs): boolean;
59
+ export interface TaskAttestationState {
60
+ rootAttestation: boolean;
61
+ subagentAttestations: number;
62
+ needsReview: boolean;
63
+ phase: string | null;
64
+ }
65
+ /**
66
+ * Read the attestation + needs_review state for an active task. Used
67
+ * by the Stop hook auto-graduator to decide which phase transition (if
68
+ * any) to apply.
69
+ */
70
+ export declare function readTaskAttestationState(repoRoot: string, taskId: string): TaskAttestationState | null;
71
+ export interface JournalEntry {
72
+ ts: string;
73
+ session_id: string | null;
74
+ summary: string;
75
+ next_step?: string;
76
+ files_touched?: string[];
77
+ decisions_loaded?: string[];
78
+ }
79
+ export interface AppendJournalArgs {
80
+ repoRoot: string;
81
+ taskId: string;
82
+ sessionId: string | null;
83
+ summary: string;
84
+ nextStep?: string;
85
+ filesTouched?: string[];
86
+ decisionsLoaded?: string[];
87
+ }
88
+ /**
89
+ * Append a single journal entry to
90
+ * `.cairn/tasks/active/<task_id>/journal.jsonl`. The journal is the
91
+ * authoritative record of what happened during a task across multiple
92
+ * Claude Code sessions. The resume command reads it after `/clear`
93
+ * to rebuild the operator's mental state.
94
+ *
95
+ * Returns false when the task directory is missing — caller decides
96
+ * how to surface (typically a no-op since journal append is best-effort
97
+ * inside the Stop hook).
98
+ */
99
+ export declare function appendTaskJournal(args: AppendJournalArgs): boolean;
100
+ export declare function readTaskJournal(repoRoot: string, taskId: string, scope?: "active" | "done"): JournalEntry[];
101
+ /**
102
+ * Look up the single active task that should be the implicit target
103
+ * for `cairn_task_journal_append` / `cairn_resume`. Picks the task
104
+ * with the most-recently-modified `status.yaml` whose phase is in the
105
+ * active set. Returns null when no active task exists.
106
+ */
107
+ export declare function findCurrentActiveTask(repoRoot: string): string | null;