blun-king-cli 9.1.567 → 9.1.570

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 (263) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/agent-spine-plugin/.claude-plugin/marketplace.json +1 -1
  3. package/agent-spine-plugin/.claude-plugin/plugin.json +1 -1
  4. package/agent-spine-plugin/.codex-plugin/plugin.json +2 -1
  5. package/agent-spine-plugin/CHANGELOG.md +1581 -0
  6. package/agent-spine-plugin/README.md +30 -4
  7. package/agent-spine-plugin/blun.plugin.json +3 -3
  8. package/agent-spine-plugin/docs/acceptance.md +61 -0
  9. package/agent-spine-plugin/docs/assignment-continuation.md +48 -0
  10. package/agent-spine-plugin/docs/host-integration.md +178 -0
  11. package/agent-spine-plugin/docs/preflight-recall.md +69 -0
  12. package/agent-spine-plugin/docs/preservation-contract.md +53 -0
  13. package/agent-spine-plugin/docs/quality-gates.md +50 -0
  14. package/agent-spine-plugin/docs/releasing.md +85 -0
  15. package/agent-spine-plugin/docs/session-timeline.md +251 -0
  16. package/agent-spine-plugin/docs/source-roots.md +113 -0
  17. package/agent-spine-plugin/docs/structured-completion.md +67 -0
  18. package/agent-spine-plugin/docs/world-model.md +94 -0
  19. package/agent-spine-plugin/hooks/codex.json +2 -2
  20. package/agent-spine-plugin/hooks/hooks.json +1 -1
  21. package/agent-spine-plugin/hooks/version.json +1 -1
  22. package/agent-spine-plugin/package.json +13 -3
  23. package/agent-spine-plugin/scripts/check-codex-install.js +226 -0
  24. package/agent-spine-plugin/scripts/check-hosts.js +14 -5
  25. package/agent-spine-plugin/scripts/check-install-hook.js +226 -0
  26. package/agent-spine-plugin/scripts/check-install-selfstarter.js +154 -0
  27. package/agent-spine-plugin/scripts/check-install.js +478 -0
  28. package/agent-spine-plugin/scripts/check-line-budget.js +58 -0
  29. package/agent-spine-plugin/scripts/check-syntax.js +29 -0
  30. package/agent-spine-plugin/scripts/github-actions.js +11 -0
  31. package/agent-spine-plugin/scripts/hermetic-process.js +183 -0
  32. package/agent-spine-plugin/scripts/release-check.js +145 -0
  33. package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
  34. package/agent-spine-plugin/scripts/run-checks.js +47 -0
  35. package/agent-spine-plugin/scripts/run-tests-hermetic.js +89 -0
  36. package/agent-spine-plugin/skills/agent-spine/SKILL.md +16 -2
  37. package/agent-spine-plugin/spine-example/1-identity.md +12 -0
  38. package/agent-spine-plugin/spine-example/2-voice.md +6 -0
  39. package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
  40. package/agent-spine-plugin/spine-example/4-history.md +4 -0
  41. package/agent-spine-plugin/src/cli-agent.js +296 -0
  42. package/agent-spine-plugin/src/cli-attention.js +95 -0
  43. package/agent-spine-plugin/src/cli-autonomy.js +36 -0
  44. package/agent-spine-plugin/src/cli-common.js +71 -0
  45. package/agent-spine-plugin/src/cli-continuity.js +116 -0
  46. package/agent-spine-plugin/src/cli-core.js +128 -0
  47. package/agent-spine-plugin/src/cli-diagnostics.js +291 -0
  48. package/agent-spine-plugin/src/cli-host.js +21 -0
  49. package/agent-spine-plugin/src/cli-learning.js +305 -0
  50. package/agent-spine-plugin/src/cli-premortem.js +16 -0
  51. package/agent-spine-plugin/src/cli-sharing.js +230 -0
  52. package/agent-spine-plugin/src/cli.js +40 -1350
  53. package/agent-spine-plugin/src/codex-reader-launcher.js +182 -0
  54. package/agent-spine-plugin/src/hook.js +185 -567
  55. package/agent-spine-plugin/src/index.js +16 -2
  56. package/agent-spine-plugin/src/lib/acceptance.js +113 -11
  57. package/agent-spine-plugin/src/lib/action-lesson-recall.js +53 -0
  58. package/agent-spine-plugin/src/lib/attention-context.js +167 -0
  59. package/agent-spine-plugin/src/lib/attention-events.js +113 -0
  60. package/agent-spine-plugin/src/lib/attention-privacy.js +72 -0
  61. package/agent-spine-plugin/src/lib/attention-schema.js +164 -0
  62. package/agent-spine-plugin/src/lib/attention-storage.js +93 -0
  63. package/agent-spine-plugin/src/lib/attention.js +9 -600
  64. package/agent-spine-plugin/src/lib/audit-premortem.js +223 -0
  65. package/agent-spine-plugin/src/lib/audit.js +56 -6
  66. package/agent-spine-plugin/src/lib/autonomy-policy.js +110 -0
  67. package/agent-spine-plugin/src/lib/autonomy-store.js +202 -0
  68. package/agent-spine-plugin/src/lib/autonomy.js +8 -0
  69. package/agent-spine-plugin/src/lib/briefing.js +67 -4
  70. package/agent-spine-plugin/src/lib/catalog-document-read.js +51 -0
  71. package/agent-spine-plugin/src/lib/catalog.js +1 -1
  72. package/agent-spine-plugin/src/lib/codex-installation.js +231 -0
  73. package/agent-spine-plugin/src/lib/codex-skill-installation.js +211 -0
  74. package/agent-spine-plugin/src/lib/context.js +3 -1
  75. package/agent-spine-plugin/src/lib/delivery-agent-usage.js +224 -0
  76. package/agent-spine-plugin/src/lib/delivery-assignment.js +220 -0
  77. package/agent-spine-plugin/src/lib/delivery-command-actions.js +453 -0
  78. package/agent-spine-plugin/src/lib/delivery-knowledge.js +78 -0
  79. package/agent-spine-plugin/src/lib/delivery-premortem-binding.js +107 -0
  80. package/agent-spine-plugin/src/lib/delivery-premortem-closure.js +171 -0
  81. package/agent-spine-plugin/src/lib/delivery-premortem-codec.js +45 -0
  82. package/agent-spine-plugin/src/lib/delivery-premortem-correction.js +101 -0
  83. package/agent-spine-plugin/src/lib/delivery-premortem-file.js +21 -0
  84. package/agent-spine-plugin/src/lib/delivery-premortem-index.js +493 -0
  85. package/agent-spine-plugin/src/lib/delivery-premortem-inspection.js +37 -0
  86. package/agent-spine-plugin/src/lib/delivery-premortem-recovery.js +120 -0
  87. package/agent-spine-plugin/src/lib/delivery-premortem-rejection.js +65 -0
  88. package/agent-spine-plugin/src/lib/delivery-premortem-results.js +28 -0
  89. package/agent-spine-plugin/src/lib/delivery-premortem-session-guard.js +46 -0
  90. package/agent-spine-plugin/src/lib/delivery-premortem-write-ledger.js +285 -0
  91. package/agent-spine-plugin/src/lib/delivery-premortem.js +499 -0
  92. package/agent-spine-plugin/src/lib/delivery-shell-heredoc.js +115 -0
  93. package/agent-spine-plugin/src/lib/delivery-shell-substitutions.js +111 -0
  94. package/agent-spine-plugin/src/lib/delivery-shell-wrapper.js +64 -0
  95. package/agent-spine-plugin/src/lib/delivery-target.js +73 -0
  96. package/agent-spine-plugin/src/lib/delivery-verification.js +445 -0
  97. package/agent-spine-plugin/src/lib/documents.js +27 -5
  98. package/agent-spine-plugin/src/lib/filesystem-retry.js +2 -0
  99. package/agent-spine-plugin/src/lib/gateway-common.js +68 -0
  100. package/agent-spine-plugin/src/lib/gateway-control.js +302 -0
  101. package/agent-spine-plugin/src/lib/gateway-delivery.js +103 -0
  102. package/agent-spine-plugin/src/lib/gateway-execution.js +350 -0
  103. package/agent-spine-plugin/src/lib/gateway-host-lifecycle.js +185 -0
  104. package/agent-spine-plugin/src/lib/gateway-inspection.js +85 -0
  105. package/agent-spine-plugin/src/lib/gateway-knowledge.js +129 -0
  106. package/agent-spine-plugin/src/lib/gateway-policy-provenance.js +197 -0
  107. package/agent-spine-plugin/src/lib/gateway-premortem-disposition.js +82 -0
  108. package/agent-spine-plugin/src/lib/gateway-premortem.js +363 -0
  109. package/agent-spine-plugin/src/lib/gateway-runs.js +300 -0
  110. package/agent-spine-plugin/src/lib/gateway-runtime-identity.js +31 -0
  111. package/agent-spine-plugin/src/lib/gateway-runtime-records.js +21 -0
  112. package/agent-spine-plugin/src/lib/gateway-runtime.js +18 -1623
  113. package/agent-spine-plugin/src/lib/gateway-state-transaction.js +356 -0
  114. package/agent-spine-plugin/src/lib/gateway-state.js +342 -0
  115. package/agent-spine-plugin/src/lib/hook-artifact-guards.js +356 -0
  116. package/agent-spine-plugin/src/lib/hook-audit.js +16 -2
  117. package/agent-spine-plugin/src/lib/hook-briefing-use.js +68 -0
  118. package/agent-spine-plugin/src/lib/hook-context.js +424 -0
  119. package/agent-spine-plugin/src/lib/hook-final-message.js +26 -0
  120. package/agent-spine-plugin/src/lib/hook-input.js +27 -0
  121. package/agent-spine-plugin/src/lib/hook-output.js +140 -0
  122. package/agent-spine-plugin/src/lib/hook-premortem.js +257 -0
  123. package/agent-spine-plugin/src/lib/hook-process-advisory.js +37 -0
  124. package/agent-spine-plugin/src/lib/hook-protection.js +95 -0
  125. package/agent-spine-plugin/src/lib/hook-stop-verification.js +84 -0
  126. package/agent-spine-plugin/src/lib/hook-timeline.js +91 -0
  127. package/agent-spine-plugin/src/lib/identifier-analysis.js +446 -0
  128. package/agent-spine-plugin/src/lib/indexed-memory.js +23 -6
  129. package/agent-spine-plugin/src/lib/knowledge-evidence.js +431 -0
  130. package/agent-spine-plugin/src/lib/learning-applications.js +441 -0
  131. package/agent-spine-plugin/src/lib/learning-candidates.js +274 -0
  132. package/agent-spine-plugin/src/lib/learning-context.js +130 -0
  133. package/agent-spine-plugin/src/lib/learning-delivery-contracts.js +310 -0
  134. package/agent-spine-plugin/src/lib/learning-evaluation-contracts.js +350 -0
  135. package/agent-spine-plugin/src/lib/learning-evaluation-registration.js +372 -0
  136. package/agent-spine-plugin/src/lib/learning-evaluation-revocation.js +292 -0
  137. package/agent-spine-plugin/src/lib/learning-evidence-contracts.js +321 -0
  138. package/agent-spine-plugin/src/lib/learning-findings.js +458 -0
  139. package/agent-spine-plugin/src/lib/learning-measurement-contracts.js +285 -0
  140. package/agent-spine-plugin/src/lib/learning-measurements.js +265 -0
  141. package/agent-spine-plugin/src/lib/learning-outcome-contracts.js +165 -0
  142. package/agent-spine-plugin/src/lib/learning-outcomes.js +343 -0
  143. package/agent-spine-plugin/src/lib/learning-reconciliation.js +290 -0
  144. package/agent-spine-plugin/src/lib/learning-retry-contracts.js +188 -0
  145. package/agent-spine-plugin/src/lib/learning-schema.js +229 -0
  146. package/agent-spine-plugin/src/lib/learning-scope-targets.js +424 -0
  147. package/agent-spine-plugin/src/lib/learning-state-upgrade.js +477 -0
  148. package/agent-spine-plugin/src/lib/learning-status-configuration.js +476 -0
  149. package/agent-spine-plugin/src/lib/learning-storage.js +203 -0
  150. package/agent-spine-plugin/src/lib/learning-trial-recovery.js +218 -0
  151. package/agent-spine-plugin/src/lib/learning-validation-contracts.js +375 -0
  152. package/agent-spine-plugin/src/lib/learning-validation-renewal.js +298 -0
  153. package/agent-spine-plugin/src/lib/learning-validation-runtime.js +234 -0
  154. package/agent-spine-plugin/src/lib/learning.js +36 -6923
  155. package/agent-spine-plugin/src/lib/lesson-recall-session.js +172 -0
  156. package/agent-spine-plugin/src/lib/mcp-autonomy-tools.js +37 -0
  157. package/agent-spine-plugin/src/lib/mcp-delivery-completion.js +124 -0
  158. package/agent-spine-plugin/src/lib/mcp-delivery-tools.js +45 -0
  159. package/agent-spine-plugin/src/lib/mcp-premortem.js +68 -0
  160. package/agent-spine-plugin/src/lib/mcp-runtime.js +269 -0
  161. package/agent-spine-plugin/src/lib/mcp-source-context.js +51 -0
  162. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +164 -0
  163. package/agent-spine-plugin/src/lib/mcp-world-tools.js +52 -0
  164. package/agent-spine-plugin/src/lib/owned-file-lock.js +30 -10
  165. package/agent-spine-plugin/src/lib/project-portfolio.js +176 -0
  166. package/agent-spine-plugin/src/lib/selfstarter-core.js +382 -0
  167. package/agent-spine-plugin/src/lib/selfstarter-jobs.js +149 -0
  168. package/agent-spine-plugin/src/lib/selfstarter-lease.js +204 -0
  169. package/agent-spine-plugin/src/lib/selfstarter-policy.js +90 -0
  170. package/agent-spine-plugin/src/lib/selfstarter-workspace.js +111 -0
  171. package/agent-spine-plugin/src/lib/selfstarter.js +11 -911
  172. package/agent-spine-plugin/src/lib/session-timeline-auth.js +316 -0
  173. package/agent-spine-plugin/src/lib/session-timeline-codex.js +58 -0
  174. package/agent-spine-plugin/src/lib/session-timeline-contract.js +48 -0
  175. package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +41 -0
  176. package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +132 -0
  177. package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +17 -0
  178. package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +500 -0
  179. package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +157 -0
  180. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +74 -0
  181. package/agent-spine-plugin/src/lib/session-timeline-host-receipt.js +117 -0
  182. package/agent-spine-plugin/src/lib/session-timeline-invocation.js +201 -0
  183. package/agent-spine-plugin/src/lib/session-timeline-king.js +79 -0
  184. package/agent-spine-plugin/src/lib/session-timeline-prior.js +59 -0
  185. package/agent-spine-plugin/src/lib/session-timeline-provider.js +34 -0
  186. package/agent-spine-plugin/src/lib/session-timeline-query.js +55 -0
  187. package/agent-spine-plugin/src/lib/session-timeline-results.js +31 -0
  188. package/agent-spine-plugin/src/lib/session-timeline-root.js +11 -0
  189. package/agent-spine-plugin/src/lib/session-timeline-search.js +82 -0
  190. package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +217 -0
  191. package/agent-spine-plugin/src/lib/session-timeline-source.js +83 -0
  192. package/agent-spine-plugin/src/lib/session-timeline-state.js +45 -0
  193. package/agent-spine-plugin/src/lib/session-timeline-transport.js +50 -0
  194. package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +148 -0
  195. package/agent-spine-plugin/src/lib/session-timeline.js +453 -0
  196. package/agent-spine-plugin/src/lib/source-roots.js +69 -136
  197. package/agent-spine-plugin/src/lib/source-tree-scan.js +178 -0
  198. package/agent-spine-plugin/src/lib/task-knowledge-context.js +78 -0
  199. package/agent-spine-plugin/src/lib/timeline-tool-guard.js +202 -0
  200. package/agent-spine-plugin/src/lib/world-knowledge.js +249 -0
  201. package/agent-spine-plugin/src/lib/world-model.js +278 -0
  202. package/agent-spine-plugin/src/mcp.js +20 -161
  203. package/agent-spine-plugin/src/version.js +1 -1
  204. package/agent-spine-plugin/src/worker.js +22 -5
  205. package/bin/agent-resume-snapshot.cjs +2 -2
  206. package/bin/agentspine-king-goal-inbox.mjs +111 -0
  207. package/bin/agentspine-king-goal-intake.mjs +106 -0
  208. package/bin/baseline-skill-performance-policy.cjs +1 -16
  209. package/bin/core-bootstrap.js +3 -0
  210. package/bin/curiosity-scout-policy.cjs +5 -1
  211. package/bin/input-draft-persistence.cjs +2 -2
  212. package/bin/king-tui-function-contract.json +33 -0
  213. package/bin/launcher-restart-policy.cjs +150 -0
  214. package/bin/launcher-runtime.js +56 -44
  215. package/bin/managed-context-startup-policy.cjs +27 -0
  216. package/bin/managed-plugin-selection.cjs +116 -0
  217. package/bin/mistake-relevance-policy.cjs +1 -1
  218. package/bin/observer-hooks.cjs +14 -0
  219. package/bin/oversized-context-offload-policy.cjs +86 -0
  220. package/bin/plugin-bootstrap.js +7 -40
  221. package/bin/proactive-compaction-policy.cjs +1 -1
  222. package/bin/provider-model-refresh-deadline.cjs +53 -0
  223. package/bin/provider-model-refresh-policy.cjs +107 -0
  224. package/bin/release-artifact-freeze-policy.cjs +30 -0
  225. package/bin/repeated-user-message-projection.cjs +3 -126
  226. package/bin/research-page-result.cjs +74 -0
  227. package/bin/runtime-exit-ledger.cjs +1 -0
  228. package/bin/session-compaction-policy.cjs +84 -0
  229. package/bin/skill-listing-performance-policy.cjs +2 -2
  230. package/bin/standard-tools-bootstrap.js +0 -37
  231. package/bin/subagent-skill-policy.cjs +3 -1
  232. package/bin/telegram-approval-relay.cjs +12 -7
  233. package/bin/telegram-private-conversation-policy.cjs +3 -2
  234. package/bin/telegram-queue-handoff-policy.cjs +24 -0
  235. package/bin/thinking-activity-status-policy.cjs +1 -1
  236. package/bin/thinking-only-guard.cjs +16 -12
  237. package/bin/tool-call-loop-policy.cjs +0 -2
  238. package/bin/tool-result-offload-policy.cjs +11 -2
  239. package/bin/tui-functional-contract.cjs +55 -0
  240. package/bin/update-notice.js +18 -14
  241. package/bin/user-message-offload-policy.cjs +1 -1
  242. package/bin/user-prompt-hook-origin-policy.cjs +34 -0
  243. package/bin/windows-node-crash-dump.cjs +110 -0
  244. package/blun.mjs +2861 -1173
  245. package/codebase-index/codebase_index.py +4 -3
  246. package/package.json +5 -18
  247. package/standard-skills/research-evidence/SKILL.md +39 -0
  248. package/standard-skills/research-evidence/references/evidence-format.md +82 -0
  249. package/standard-skills/research-evidence/scripts/evidence-collection.cjs +254 -0
  250. package/standard-skills/research-evidence/scripts/score-report.cjs +112 -0
  251. package/standard-skills/web-lesen/SKILL.md +37 -22
  252. package/standard-skills/web-lesen/scripts/crawl_public.py +376 -0
  253. package/telegram-plugin/DELIVERY.md +36 -0
  254. package/telegram-plugin/bin/telegram-approval-relay.cjs +13 -7
  255. package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +122 -0
  256. package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +3 -2
  257. package/telegram-plugin/bin/telegram-reply-parts.cjs +149 -0
  258. package/telegram-plugin/dist/bridge.mjs +7 -56
  259. package/telegram-plugin/dist/mcp-server.mjs +33 -4
  260. package/agent-spine-plugin/skill/SKILL.md +0 -76
  261. package/bin/mnemo-connect-heartbeat.cjs +0 -204
  262. package/bin/mnemo-tool-agent-policy.cjs +0 -22
  263. package/telegram-plugin/bin/telegram-mnemo-capture.cjs +0 -297
@@ -0,0 +1,172 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { replaceFileWithRetry } from "./filesystem-retry.js";
5
+ import { withOwnedFileLock } from "./owned-file-lock.js";
6
+ import { projectStateDir } from "./paths.js";
7
+
8
+ const SCHEMA = "agentspine.lesson-recall-sessions/v1";
9
+ const AUTHORITY = "context-only";
10
+ const ID_RE = /^[A-Za-z0-9][A-Za-z0-9:_.@/-]{0,127}$/;
11
+ const MAX_BYTES = 1024 * 1024;
12
+ const MAX_SESSIONS = 128;
13
+ const MAX_PATHS = 8;
14
+ const TTL_MS = 24 * 60 * 60 * 1000;
15
+
16
+ function boundedId(value) {
17
+ return typeof value === "string" && ID_RE.test(value) ? value : null;
18
+ }
19
+
20
+ function time(value = new Date()) {
21
+ const date = value instanceof Date ? value : new Date(value);
22
+ if (!Number.isFinite(date.getTime())) throw new Error("lesson recall timestamp is invalid");
23
+ return date;
24
+ }
25
+
26
+ function suppliedScope(input) {
27
+ const value = input.agent_spine_scope && typeof input.agent_spine_scope === "object"
28
+ ? input.agent_spine_scope : input;
29
+ return {
30
+ entityId: boundedId(value.entity_id ?? value.entityId),
31
+ projectId: boundedId(value.project_id ?? value.projectId),
32
+ groupId: boundedId(value.group_id ?? value.groupId),
33
+ taskId: boundedId(value.task_id ?? value.taskId ?? value.currentTaskId)
34
+ };
35
+ }
36
+
37
+ function sessionId(input) {
38
+ return boundedId(input.session_id ?? input.sessionId);
39
+ }
40
+
41
+ function emptyState(root) {
42
+ return { schema: SCHEMA, root, sessions: [], authority: AUTHORITY };
43
+ }
44
+
45
+ function validPath(item) {
46
+ return item && typeof item.path === "string" && item.path.length > 0 && item.path.length <= 512
47
+ && !item.path.startsWith("/") && !item.path.startsWith("../") && !item.path.includes("/../")
48
+ && /^[a-f0-9]{64}$/.test(item.sha256 || "");
49
+ }
50
+
51
+ function validSession(item) {
52
+ return item && boundedId(item.sessionId) && item.host === "claude"
53
+ && [item.entityId, item.projectId, item.groupId, item.taskId].every((value) => value === null || boundedId(value))
54
+ && Array.isArray(item.paths) && item.paths.length <= MAX_PATHS && item.paths.every(validPath)
55
+ && Number.isFinite(new Date(item.updatedAt).getTime())
56
+ && Number.isFinite(new Date(item.expiresAt).getTime())
57
+ && item.authority === AUTHORITY;
58
+ }
59
+
60
+ function normalizeState(value, root) {
61
+ if (!value || value.schema !== SCHEMA || value.root !== root || value.authority !== AUTHORITY
62
+ || !Array.isArray(value.sessions) || value.sessions.length > MAX_SESSIONS
63
+ || value.sessions.some((item) => !validSession(item))) {
64
+ throw new Error("lesson recall session state is invalid");
65
+ }
66
+ return value;
67
+ }
68
+
69
+ async function pathsFor(root) {
70
+ const directory = await projectStateDir(root);
71
+ return { path: join(directory, "lesson-recall-sessions.json"),
72
+ lockPath: join(directory, "lesson-recall-sessions.lock") };
73
+ }
74
+
75
+ async function readState(path, root) {
76
+ try {
77
+ const metadata = await stat(path);
78
+ if (metadata.size > MAX_BYTES) throw new Error("lesson recall session state exceeds 1 MiB");
79
+ return normalizeState(JSON.parse(await readFile(path, "utf8")), root);
80
+ } catch (error) {
81
+ if (error.code !== "ENOENT") throw error;
82
+ return emptyState(root);
83
+ }
84
+ }
85
+
86
+ async function saveState(state, path, assertOwned) {
87
+ const content = `${JSON.stringify(state, null, 2)}\n`;
88
+ if (Buffer.byteLength(content) > MAX_BYTES) throw new Error("lesson recall session state exceeds 1 MiB");
89
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
90
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
91
+ await writeFile(temporary, content, { mode: 0o600 });
92
+ try {
93
+ await replaceFileWithRetry(temporary, path, { beforeAttempt: assertOwned });
94
+ } catch (error) {
95
+ await unlink(temporary).catch((cleanupError) => {
96
+ if (cleanupError.code !== "ENOENT") error.cleanupError = cleanupError;
97
+ });
98
+ throw error;
99
+ }
100
+ }
101
+
102
+ function sameScope(record, input) {
103
+ const scope = suppliedScope(input);
104
+ return record.sessionId === sessionId(input) && record.host === "claude"
105
+ && record.entityId === scope.entityId && record.projectId === scope.projectId
106
+ && record.groupId === scope.groupId && record.taskId === scope.taskId;
107
+ }
108
+
109
+ export function hookMemoryQuery(input) {
110
+ for (const key of ["prompt", "user_prompt", "message", "input"]) {
111
+ if (typeof input[key] === "string" && input[key].trim()) return input[key].slice(0, 16384);
112
+ }
113
+ const tool = typeof input.tool_name === "string" ? input.tool_name : "";
114
+ const values = [];
115
+ const visit = (value, key = "", depth = 0) => {
116
+ if (depth > 4 || values.length >= 32) return;
117
+ if (typeof value === "string" && /(?:path|file|target|cmd|command|pattern|query)/i.test(key)) {
118
+ values.push(value.slice(0, 2048));
119
+ return;
120
+ }
121
+ if (!value || typeof value !== "object") return;
122
+ if (Array.isArray(value)) {
123
+ for (const item of value.slice(0, 16)) visit(item, key, depth + 1);
124
+ return;
125
+ }
126
+ for (const [name, item] of Object.entries(value).slice(0, 32)) visit(item, name, depth + 1);
127
+ };
128
+ visit(input.tool_input ?? input.tool_args ?? {});
129
+ return [tool, ...values].filter(Boolean).join(" ");
130
+ }
131
+
132
+ export async function loadLessonRecallSelection({ root, input, now = new Date() }) {
133
+ const session = sessionId(input);
134
+ const scope = suppliedScope(input);
135
+ if (!session) return { status: "no-session", paths: [], authority: AUTHORITY };
136
+ if (scope.groupId) return { status: "group-suppressed", paths: [], authority: AUTHORITY };
137
+ const { path } = await pathsFor(root);
138
+ const state = await readState(path, root);
139
+ const timestamp = time(now);
140
+ const record = state.sessions.find((item) => sameScope(item, input)
141
+ && new Date(item.expiresAt).getTime() >= timestamp.getTime());
142
+ return record
143
+ ? { status: "restored", paths: record.paths.map((item) => item.path), updatedAt: record.updatedAt,
144
+ expiresAt: record.expiresAt, authority: AUTHORITY }
145
+ : { status: "empty", paths: [], authority: AUTHORITY };
146
+ }
147
+
148
+ export async function rememberLessonRecallSelection({ root, input, sources, now = new Date() }) {
149
+ const session = sessionId(input);
150
+ const scope = suppliedScope(input);
151
+ if (!session) return { status: "no-session", paths: [], authority: AUTHORITY };
152
+ if (scope.groupId) return { status: "group-suppressed", paths: [], authority: AUTHORITY };
153
+ const selected = sources.filter((item) => item.relativePath !== "MEMORY.md").slice(0, MAX_PATHS)
154
+ .map((item) => ({ path: item.relativePath, sha256: item.snapshot.metadata.sha256 }));
155
+ if (!selected.length) return { status: "empty", paths: [], authority: AUTHORITY };
156
+ const timestamp = time(now);
157
+ const updatedAt = timestamp.toISOString();
158
+ const expiresAt = new Date(timestamp.getTime() + TTL_MS).toISOString();
159
+ const names = await pathsFor(root);
160
+ return withOwnedFileLock(names.lockPath, async ({ assertOwned }) => {
161
+ const state = await readState(names.path, root);
162
+ state.sessions = state.sessions.filter((item) => new Date(item.expiresAt).getTime() >= timestamp.getTime()
163
+ && !sameScope(item, input));
164
+ state.sessions.push({ sessionId: session, host: "claude", ...scope, paths: selected,
165
+ updatedAt, expiresAt, authority: AUTHORITY });
166
+ state.sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
167
+ state.sessions = state.sessions.slice(0, MAX_SESSIONS);
168
+ await saveState(state, names.path, assertOwned);
169
+ return { status: "recorded", paths: selected.map((item) => item.path), updatedAt, expiresAt,
170
+ authority: AUTHORITY };
171
+ });
172
+ }
@@ -0,0 +1,37 @@
1
+ const scope = {
2
+ registrationId: { type: "string" }, tenantId: { type: "string" },
3
+ groupId: { anyOf: [{ type: "string" }, { type: "null" }] }
4
+ };
5
+
6
+ export const autonomyTools = [
7
+ {
8
+ name: "project_portfolio",
9
+ description: "Return a bounded, exact-scope overview of explicitly registered projects and at most one deduplicated proactive notice. Context only; grants no authority.",
10
+ inputSchema: { type: "object", additionalProperties: false, required: ["tenantId"],
11
+ properties: { root: { type: "string" }, tenantId: scope.tenantId, groupId: scope.groupId,
12
+ markPresented: { type: "boolean" }, now: { type: "string" } } }
13
+ },
14
+ {
15
+ name: "record_project_observation",
16
+ description: "Record one evidence-classified project observation for an existing exact-scope registration. It may create a context-only notice, never authority.",
17
+ inputSchema: { type: "object", additionalProperties: false,
18
+ required: ["registrationId", "tenantId", "kind", "evidenceClass", "summary", "sourceDigest"],
19
+ properties: { root: { type: "string" }, ...scope,
20
+ kind: { type: "string", enum: ["ci", "error", "idea", "goal", "state"] },
21
+ status: { type: "string", enum: ["open", "passed", "failed", "resolved", "unknown"] },
22
+ evidenceClass: { type: "string", enum: ["objective", "user-feedback", "model-suggestion"] },
23
+ summary: { type: "string", maxLength: 500 }, sourceDigest: { type: "string", pattern: "^[a-f0-9]{64}$" },
24
+ observedAt: { type: "string" }, expiresAt: { anyOf: [{ type: "string" }, { type: "null" }] } } }
25
+ },
26
+ {
27
+ name: "evaluate_autonomy_action",
28
+ description: "Evaluate an action against the configured autonomy level and any separately required exact execution grant. This gate never grants a capability.",
29
+ inputSchema: { type: "object", additionalProperties: false,
30
+ required: ["registrationId", "tenantId", "action"],
31
+ properties: { root: { type: "string" }, ...scope,
32
+ action: { type: "string", enum: ["observe", "advise", "execute", "publish"] },
33
+ capability: { anyOf: [{ type: "string" }, { type: "null" }] }, actorId: { type: "string" },
34
+ jobId: { type: "string" }, taskId: { type: "string" }, targetId: { type: "string" },
35
+ projectId: { type: "string" }, host: { type: "string", enum: ["claude", "codex"] }, now: { type: "string" } } }
36
+ }
37
+ ];
@@ -0,0 +1,124 @@
1
+ import { inspectPremortemState, verifyPremortemBeforeWrite,
2
+ verifyPremortemStop } from "./delivery-premortem.js";
3
+ import { verifyDeliveryAgentUse } from "./delivery-agent-usage.js";
4
+ import { verifyDeliveryStop } from "./delivery-verification.js";
5
+ import { normalizePremortemBinding } from "./delivery-premortem-binding.js";
6
+ import { hasSecretShapedText } from "./delivery-premortem-closure.js";
7
+ import { canonicalPremortem } from "./delivery-premortem-codec.js";
8
+ import { withActiveDeliveryAssignment } from "./delivery-assignment.js";
9
+
10
+ const DIGEST = { type: "string", pattern: "^[a-f0-9]{64}$" };
11
+ const ID = { type: "string", minLength: 1, maxLength: 512 };
12
+ const OPTIONAL_ID = { anyOf: [ID, { type: "null" }] };
13
+ const CATEGORIES = ["baseline-environment", "contract-tests", "delivery-path"];
14
+ const BINDING_FIELDS = ["host", "sessionId", "projectId", "entityId", "groupId",
15
+ "taskId", "assignmentId", "goalId", "goalStepId", "queueId", "gatewayAttempt",
16
+ "planDefinitionsDigest"];
17
+
18
+ export const deliveryCompletionTool = {
19
+ name: "complete_delivery",
20
+ description: "Store structured completion checks for an ordinary assignment after observed post-write tests. Stop still rechecks all gates. No permissions, tests, goal outcomes, or host identity are created.",
21
+ inputSchema: {
22
+ type: "object", additionalProperties: false,
23
+ required: ["root", "requirementId", "binding", "artifactDigest", "lastWriteDigest", "checks"],
24
+ properties: {
25
+ root: ID,
26
+ requirementId: { type: "string", pattern: "^premortem-requirement:[a-f0-9]{64}:[a-f0-9]{64}$" },
27
+ binding: {
28
+ type: "object", additionalProperties: false,
29
+ required: ["host", "sessionId", "projectId", "assignmentId"],
30
+ properties: Object.fromEntries(BINDING_FIELDS.map(key => [key,
31
+ key === "gatewayAttempt" ? { anyOf: [{ type: "integer", minimum: 1 }, { type: "null" }] }
32
+ : ["host", "sessionId", "projectId", "assignmentId"].includes(key) ? ID : OPTIONAL_ID]))
33
+ },
34
+ artifactDigest: DIGEST, lastWriteDigest: DIGEST,
35
+ checks: {
36
+ type: "array", minItems: 3, maxItems: 3,
37
+ items: { type: "object", additionalProperties: false,
38
+ required: ["category", "checkId", "status", "result"],
39
+ properties: {
40
+ category: { type: "string", enum: CATEGORIES }, checkId: ID,
41
+ status: { const: "PASS" }, result: { type: "string", minLength: 1, maxLength: 1024 }
42
+ } }
43
+ }
44
+ }
45
+ }
46
+ };
47
+
48
+ function reject(status, reason) {
49
+ return { status, blocked: true, reason, authority: "context-only" };
50
+ }
51
+
52
+ function strictKeys(value, keys) {
53
+ return value && typeof value === "object" && !Array.isArray(value)
54
+ && Object.keys(value).every(key => keys.includes(key));
55
+ }
56
+
57
+ function closureMessage(args) {
58
+ if (![args.artifactDigest, args.lastWriteDigest].every(value =>
59
+ typeof value === "string" && /^[a-f0-9]{64}$/.test(value))) throw new Error("completion digests are invalid");
60
+ if (!Array.isArray(args.checks) || args.checks.length !== 3) throw new Error("completion requires three checks");
61
+ const lines = args.checks.map(check => {
62
+ if (!strictKeys(check, ["category", "checkId", "status", "result"])
63
+ || !CATEGORIES.includes(check.category) || check.status !== "PASS"
64
+ || !/^check-[a-f0-9]{20}$/.test(check.checkId || "")
65
+ || typeof check.result !== "string" || !check.result.trim() || check.result.length > 1024
66
+ || /[\0\r\n]/.test(check.result) || hasSecretShapedText(check.result)) {
67
+ throw new Error("completion check is invalid or contains secret-shaped content");
68
+ }
69
+ return `- ${check.category} ${check.checkId}: PASS — ${check.result.trim()}`;
70
+ });
71
+ return [`Premortem closure sha256 ${args.artifactDigest}`,
72
+ `Premortem latest write sha256 ${args.lastWriteDigest}`, ...lines].join("\n");
73
+ }
74
+
75
+ export async function completeDelivery(args) {
76
+ try {
77
+ if (!strictKeys(args, ["root", "requirementId", "binding", "artifactDigest", "lastWriteDigest", "checks"])
78
+ || typeof args.root !== "string" || !args.root
79
+ || !strictKeys(args.binding, BINDING_FIELDS)) throw new Error("completion requires exact bound arguments");
80
+ const message = closureMessage(args);
81
+ const binding = normalizePremortemBinding(args.binding);
82
+ return await withActiveDeliveryAssignment({ root: args.root, binding },
83
+ assertOwned => completeBoundDelivery(args, binding, message, assertOwned));
84
+ } catch (error) {
85
+ return reject("invalid-completion", String(error.message).slice(0, 400));
86
+ }
87
+ }
88
+
89
+ async function completeBoundDelivery(args, binding, message, assertOwned) {
90
+ const current = await inspectPremortemState({ root: args.root, requirementId: args.requirementId });
91
+ if (current.blocked || current.status === "degraded") return current;
92
+ if (!current.hasWrite || !binding.assignmentId
93
+ || canonicalPremortem(binding) !== canonicalPremortem(current.binding)) {
94
+ return reject("foreign-completion", "Completion requires the exact written assignment binding.");
95
+ }
96
+ // Goal verification has a distinct task/queue lane. Preserve its existing
97
+ // checkpoint and outcome route until a host supplies that verified lane.
98
+ if (binding.goalId || binding.queueId) {
99
+ return reject("goal-completion-required", "Use the existing goal checkpoint and outcome completion route.");
100
+ }
101
+ const usage = await verifyDeliveryAgentUse({ root: args.root, requirementId: args.requirementId });
102
+ if (usage.blocked || usage.status !== "verified") return usage;
103
+ const prepared = await verifyPremortemBeforeWrite({ root: args.root, binding });
104
+ if (prepared.blocked || prepared.status !== "verified") return prepared;
105
+ if (prepared.digest !== args.artifactDigest) return reject("stale", "Completion artifact digest is stale.");
106
+ const verificationArgs = { root: args.root, host: binding.host, sessionId: binding.sessionId,
107
+ scope: { ...binding, currentTaskId: binding.taskId } };
108
+ const before = await verifyDeliveryStop(verificationArgs);
109
+ if (before.blocked) return before;
110
+ if (before.status !== "verified") return reject("untested", "No observed successful post-write test is available.");
111
+ await assertOwned();
112
+ const closed = await verifyPremortemStop({ root: args.root, binding, message,
113
+ testStateDigest: before.stateDigest });
114
+ if (closed.blocked || closed.status !== "closed") return closed;
115
+ const after = await verifyDeliveryStop(verificationArgs);
116
+ if (after.blocked) return after;
117
+ if (after.status !== "verified" || after.stateDigest !== before.stateDigest) {
118
+ return reject("changed", "Test evidence changed during completion; recheck the latest write before Stop.");
119
+ }
120
+ return { status: "recorded", blocked: false, requirementId: args.requirementId,
121
+ closure: closed.closure, testStateDigest: before.stateDigest,
122
+ instruction: "Finish with a normal user-facing summary. Stop rechecks all delivery gates.",
123
+ authority: "context-only" };
124
+ }
@@ -0,0 +1,45 @@
1
+ const requirementId = {
2
+ type: "string",
3
+ pattern: "^premortem-requirement:[a-f0-9]{64}:[a-f0-9]{64}$"
4
+ };
5
+
6
+ export const sessionBriefingTool = {
7
+ name: "session_briefing",
8
+ description: "Assemble one byte-budgeted, privacy-filtered session packet across native sources, relationships, accepted learning, reviewed shared memory, tasks, and optional attention cues. With requirementId, the actual MCP call becomes delivery preflight stage 1. Read-only and context-only.",
9
+ inputSchema: {
10
+ type: "object", additionalProperties: false,
11
+ properties: {
12
+ root: { type: "string" }, cwd: { type: "string" },
13
+ host: { type: "string", enum: ["codex", "claude", "generic"] },
14
+ entityId: { anyOf: [{ type: "string" }, { type: "null" }] },
15
+ userId: { anyOf: [{ type: "string" }, { type: "null" }] },
16
+ tenantId: { anyOf: [{ type: "string" }, { type: "null" }] },
17
+ groupId: { anyOf: [{ type: "string" }, { type: "null" }] },
18
+ projectId: { anyOf: [{ type: "string" }, { type: "null" }] },
19
+ currentTaskId: { anyOf: [{ type: "string" }, { type: "null" }] },
20
+ includePrivate: { type: "boolean" }, focusActive: { type: "boolean" },
21
+ includeSourceContent: { type: "boolean" },
22
+ maxBytes: { type: "integer", minimum: 4096, maximum: 262144 },
23
+ now: { type: "string" }, requirementId
24
+ }
25
+ }
26
+ };
27
+
28
+ export const deliveryKnowledgeTool = {
29
+ name: "delivery_knowledge_query",
30
+ description: "Query exact target fingerprints, indexed contracts, recent-error terms, and the scoped AgentSpine context for one delivery. With its hook-issued requirement this actual MCP call becomes preflight stage 2 and grants no authority.",
31
+ inputSchema: {
32
+ type: "object", additionalProperties: false,
33
+ required: ["root", "requirementId", "targetPaths", "contractPaths", "recentErrorTerms"],
34
+ properties: {
35
+ root: { type: "string", minLength: 1 }, requirementId,
36
+ targetPaths: { type: "array", minItems: 1, maxItems: 32,
37
+ items: { type: "string", minLength: 1, maxLength: 512 } },
38
+ contractPaths: { type: "array", minItems: 1, maxItems: 8,
39
+ items: { type: "string", minLength: 1, maxLength: 512 } },
40
+ recentErrorTerms: { type: "array", minItems: 1, maxItems: 16,
41
+ items: { type: "string", minLength: 1, maxLength: 512 } },
42
+ maxBytes: { type: "integer", minimum: 4096, maximum: 262144 }
43
+ }
44
+ }
45
+ };
@@ -0,0 +1,68 @@
1
+ const failure = {
2
+ type: "string",
3
+ minLength: 29,
4
+ maxLength: 500,
5
+ pattern: "^this delivery fails because\\s+\\S"
6
+ };
7
+
8
+ const check = { type: "string", minLength: 1, maxLength: 500 };
9
+
10
+ function premortemItem(category) {
11
+ return {
12
+ type: "object",
13
+ additionalProperties: false,
14
+ required: ["category", "failure", "check"],
15
+ properties: {
16
+ category: { const: category },
17
+ failure,
18
+ check
19
+ }
20
+ };
21
+ }
22
+
23
+ export const deliveryPremortemTool = {
24
+ name: "record_delivery_premortem",
25
+ description: "Record the three required, context-only delivery failure checks before the first write. This audited receipt grants no permissions or tool access.",
26
+ inputSchema: {
27
+ type: "object",
28
+ additionalProperties: false,
29
+ required: ["root", "requirementId", "items"],
30
+ properties: {
31
+ root: { type: "string", minLength: 1 },
32
+ requirementId: {
33
+ type: "string",
34
+ pattern: "^premortem-requirement:[a-f0-9]{64}:[a-f0-9]{64}$"
35
+ },
36
+ items: {
37
+ type: "array",
38
+ minItems: 3,
39
+ maxItems: 3,
40
+ items: {
41
+ oneOf: [
42
+ premortemItem("baseline-environment"),
43
+ premortemItem("contract-tests"),
44
+ premortemItem("delivery-path")
45
+ ]
46
+ }
47
+ }
48
+ }
49
+ }
50
+ };
51
+
52
+ export const deliveryPremortemRecoveryTool = {
53
+ name: "recover_delivery_premortem",
54
+ description: "Create a fresh assignment-bound requirement from a preserved legacy conflict. The predecessor, rejection history, and all checks remain immutable; this grants no authority.",
55
+ inputSchema: {
56
+ type: "object",
57
+ additionalProperties: false,
58
+ required: ["root", "predecessorRequirementId"],
59
+ properties: {
60
+ root: { type: "string", minLength: 1 },
61
+ predecessorRequirementId: {
62
+ type: "string",
63
+ pattern: "^premortem-requirement:[a-f0-9]{64}:[a-f0-9]{64}$"
64
+ },
65
+ taskId: { anyOf: [{ type: "string", minLength: 1, maxLength: 512 }, { type: "null" }] }
66
+ }
67
+ }
68
+ };