@sema-agent/core 7.54.0 → 7.55.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 (403) hide show
  1. package/CHANGELOG.md +451 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cc-peer-directory.d.ts +36 -0
  5. package/dist/agents/cc-peer-directory.js +138 -0
  6. package/dist/agents/cc-peer-wire.d.ts +105 -0
  7. package/dist/agents/cc-peer-wire.js +98 -0
  8. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  9. package/dist/agents/cc-uds-peer-channel.js +457 -0
  10. package/dist/agents/cross-session-envelope.d.ts +4 -1
  11. package/dist/agents/cross-session-envelope.js +8 -1
  12. package/dist/agents/cross-session-judge.d.ts +2 -2
  13. package/dist/agents/list-agents-tool.js +2 -1
  14. package/dist/agents/observer.d.ts +4 -5
  15. package/dist/agents/observer.js +2 -1
  16. package/dist/agents/peer-admission.d.ts +6 -0
  17. package/dist/agents/peer-admission.js +4 -1
  18. package/dist/agents/peer-directory.d.ts +43 -9
  19. package/dist/agents/peer-directory.js +66 -23
  20. package/dist/agents/peer-notices.d.ts +1 -1
  21. package/dist/agents/peer-session-drain.d.ts +3 -1
  22. package/dist/agents/peer-session-drain.js +1 -0
  23. package/dist/agents/read-inbox-tool.js +2 -1
  24. package/dist/agents/retain-ledger.d.ts +1 -1
  25. package/dist/agents/roster-store.d.ts +1 -1
  26. package/dist/agents/send-message-tool.d.ts +10 -0
  27. package/dist/agents/send-message-tool.js +34 -5
  28. package/dist/agents/subagent.d.ts +34 -79
  29. package/dist/agents/subagent.js +45 -46
  30. package/dist/agents/tool-filter.d.ts +29 -46
  31. package/dist/agents/tool-filter.js +8 -31
  32. package/dist/agents/verify.d.ts +3 -3
  33. package/dist/brain/anthropic.js +14 -9
  34. package/dist/brain/errors.d.ts +15 -0
  35. package/dist/brain/errors.js +10 -0
  36. package/dist/brain/model-presets.d.ts +4 -4
  37. package/dist/brain/open-responses.js +15 -10
  38. package/dist/brain/openai.js +17 -12
  39. package/dist/brain/provider-dialect.d.ts +39 -3
  40. package/dist/brain/provider-dialect.js +28 -0
  41. package/dist/brain/reasoning.d.ts +1 -1
  42. package/dist/brain/request-params.d.ts +55 -5
  43. package/dist/brain/request-params.js +35 -3
  44. package/dist/brain/retry.d.ts +1 -1
  45. package/dist/brain/route-adjudicator.d.ts +15 -0
  46. package/dist/brain/route-adjudicator.js +15 -0
  47. package/dist/brain/stream-engine.js +6 -5
  48. package/dist/brain/stream-shared.d.ts +1 -1
  49. package/dist/core/advisor-verdict.d.ts +120 -0
  50. package/dist/core/advisor-verdict.js +92 -0
  51. package/dist/core/agent-definition.d.ts +7 -8
  52. package/dist/core/allow-entry.d.ts +49 -23
  53. package/dist/core/allow-entry.js +57 -32
  54. package/dist/core/allow-rule-shadow.d.ts +7 -0
  55. package/dist/core/approval-object.d.ts +2 -1
  56. package/dist/core/approval-object.js +6 -6
  57. package/dist/core/ask-origin.d.ts +63 -11
  58. package/dist/core/ask-origin.js +27 -5
  59. package/dist/core/ask-question.js +10 -4
  60. package/dist/core/auto-compaction.d.ts +11 -8
  61. package/dist/core/auto-compaction.js +4 -2
  62. package/dist/core/auto-mode-arming.d.ts +2 -2
  63. package/dist/core/auto-mode-defaults.d.ts +8 -8
  64. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  65. package/dist/core/auto-mode-prompt.d.ts +1 -1
  66. package/dist/core/auto-mode.d.ts +17 -9
  67. package/dist/core/auto-mode.js +9 -6
  68. package/dist/core/background-agent-store.d.ts +3 -3
  69. package/dist/core/canonical-json.d.ts +1 -1
  70. package/dist/core/canonical-json.js +2 -2
  71. package/dist/core/checkpoint-requirements.d.ts +6 -3
  72. package/dist/core/checkpoint-requirements.js +4 -14
  73. package/dist/core/checkpoint-store.d.ts +80 -51
  74. package/dist/core/checkpoint-store.js +56 -74
  75. package/dist/core/child-clamp-seats.d.ts +6 -0
  76. package/dist/core/child-clamp-seats.js +3 -16
  77. package/dist/core/compliance.d.ts +2 -2
  78. package/dist/core/context-edit.d.ts +6 -7
  79. package/dist/core/cross-boundary-taint.d.ts +9 -3
  80. package/dist/core/cross-boundary-taint.js +5 -3
  81. package/dist/core/decision-receipt.js +2 -2
  82. package/dist/core/effective-path-target.d.ts +1 -1
  83. package/dist/core/engine-notice.d.ts +19 -5
  84. package/dist/core/exec-output-tail.d.ts +1 -1
  85. package/dist/core/file-history-retention.d.ts +1 -1
  86. package/dist/core/file-history-store.d.ts +59 -9
  87. package/dist/core/file-history-store.js +35 -17
  88. package/dist/core/gate-fold.js +3 -2
  89. package/dist/core/gate-lanes.js +12 -8
  90. package/dist/core/gate-outcome.d.ts +17 -4
  91. package/dist/core/gate-outcome.js +30 -0
  92. package/dist/core/governance-codes.d.ts +13 -3
  93. package/dist/core/governance-codes.js +10 -0
  94. package/dist/core/hands-band.d.ts +1 -1
  95. package/dist/core/hooks.d.ts +4 -4
  96. package/dist/core/host-target.d.ts +49 -0
  97. package/dist/core/host-target.js +59 -0
  98. package/dist/core/image-downsample.d.ts +1 -1
  99. package/dist/core/lsp-diagnostics.d.ts +4 -4
  100. package/dist/core/lsp.d.ts +3 -3
  101. package/dist/core/mailbox-store.d.ts +4 -0
  102. package/dist/core/mcp-connection-pool.d.ts +18 -2
  103. package/dist/core/mcp-connection-pool.js +53 -6
  104. package/dist/core/mcp-failure.d.ts +23 -4
  105. package/dist/core/mcp-failure.js +26 -11
  106. package/dist/core/mcp-listing-drift.d.ts +10 -0
  107. package/dist/core/mcp-listing-drift.js +6 -0
  108. package/dist/core/mcp-server-link.d.ts +173 -0
  109. package/dist/core/mcp-server-link.js +127 -0
  110. package/dist/core/mcp-server-spec.d.ts +4 -2
  111. package/dist/core/mcp-session-end.d.ts +26 -0
  112. package/dist/core/mcp-session-end.js +29 -0
  113. package/dist/core/mcp-startup-request.d.ts +17 -0
  114. package/dist/core/mcp-startup-request.js +17 -0
  115. package/dist/core/mcp.d.ts +13 -13
  116. package/dist/core/mcp.js +187 -162
  117. package/dist/core/media-byte-cap.d.ts +1 -1
  118. package/dist/core/memory-engine/engine.d.ts +9 -9
  119. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  120. package/dist/core/memory-engine/tools.js +4 -1
  121. package/dist/core/mode-policy.d.ts +1 -1
  122. package/dist/core/namespaced-rule-name.d.ts +33 -7
  123. package/dist/core/namespaced-rule-name.js +39 -25
  124. package/dist/core/output-style.d.ts +1 -1
  125. package/dist/core/param-rule-reach.d.ts +15 -0
  126. package/dist/core/param-rule-reach.js +30 -0
  127. package/dist/core/parent-spec-seat.d.ts +8 -1
  128. package/dist/core/parent-spec-seat.js +4 -0
  129. package/dist/core/pause-registry.d.ts +16 -5
  130. package/dist/core/pause-registry.js +6 -2
  131. package/dist/core/peer-channel.d.ts +70 -0
  132. package/dist/core/peer-channel.js +1 -0
  133. package/dist/core/permission-rule-consent.d.ts +11 -5
  134. package/dist/core/permission-rule-consent.js +37 -30
  135. package/dist/core/permission-rule-model.d.ts +233 -64
  136. package/dist/core/permission-rule-model.js +384 -85
  137. package/dist/core/permission-rule-provider.d.ts +2 -1
  138. package/dist/core/permission-rule-store.d.ts +20 -25
  139. package/dist/core/permission-rule-store.js +1 -4
  140. package/dist/core/permission-rule-sync.d.ts +11 -2
  141. package/dist/core/permission-rule-sync.js +8 -1
  142. package/dist/core/permission-rules.d.ts +49 -11
  143. package/dist/core/permission-rules.js +123 -89
  144. package/dist/core/persisted-rule-arms.d.ts +4 -2
  145. package/dist/core/present-plan-tool.js +3 -1
  146. package/dist/core/protocol-naming.d.ts +2 -2
  147. package/dist/core/read-only-shell-table.d.ts +1 -1
  148. package/dist/core/read-only-shell.d.ts +1 -1
  149. package/dist/core/roles.d.ts +6 -2
  150. package/dist/core/roles.js +45 -44
  151. package/dist/core/rule-offer-read.d.ts +53 -0
  152. package/dist/core/rule-offer-read.js +146 -0
  153. package/dist/core/rule-owner.d.ts +46 -0
  154. package/dist/core/rule-owner.js +28 -0
  155. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  156. package/dist/core/runner/advisor-instructions.js +61 -0
  157. package/dist/core/runner/advisor-tool.d.ts +33 -0
  158. package/dist/core/runner/advisor-tool.js +112 -0
  159. package/dist/core/runner/announce-once-ledger.d.ts +4 -26
  160. package/dist/core/runner/announce-once-ledger.js +14 -46
  161. package/dist/core/runner/approval-feedback.js +6 -3
  162. package/dist/core/runner/assemble-result.d.ts +1 -1
  163. package/dist/core/runner/caller-roster.d.ts +7 -0
  164. package/dist/core/runner/caller-roster.js +11 -0
  165. package/dist/core/runner/classifier-ladder.d.ts +27 -5
  166. package/dist/core/runner/classifier-ladder.js +12 -11
  167. package/dist/core/runner/compaction-restate.d.ts +10 -6
  168. package/dist/core/runner/compaction-restate.js +9 -3
  169. package/dist/core/runner/contracts.d.ts +13 -9
  170. package/dist/core/runner/conversation-segment.d.ts +28 -0
  171. package/dist/core/runner/conversation-segment.js +42 -0
  172. package/dist/core/runner/cross-boundary-lane.d.ts +6 -5
  173. package/dist/core/runner/cross-boundary-lane.js +26 -15
  174. package/dist/core/runner/decide-continuation.d.ts +7 -4
  175. package/dist/core/runner/decide-continuation.js +2 -2
  176. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  177. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  178. package/dist/core/runner/derived-route-fallback.js +9 -7
  179. package/dist/core/runner/gate-exit.d.ts +6 -0
  180. package/dist/core/runner/gate-exit.js +7 -2
  181. package/dist/core/runner/initial-run-state.js +1 -1
  182. package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
  183. package/dist/core/runner/permission-rule-lanes.js +14 -7
  184. package/dist/core/runner/person-path-rows.js +1 -1
  185. package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -5
  186. package/dist/core/runner/prepare-acquire-reconcile.js +5 -3
  187. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  188. package/dist/core/runner/prepare-advisor.js +77 -0
  189. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  190. package/dist/core/runner/prepare-config-doors.d.ts +6 -4
  191. package/dist/core/runner/prepare-config-doors.js +18 -12
  192. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  193. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  194. package/dist/core/runner/prepare-file-history.js +39 -39
  195. package/dist/core/runner/prepare-gate-stations.d.ts +1 -4
  196. package/dist/core/runner/prepare-gate-stations.js +2 -7
  197. package/dist/core/runner/prepare-inherited-gate.d.ts +5 -4
  198. package/dist/core/runner/prepare-inherited-gate.js +3 -3
  199. package/dist/core/runner/prepare-park-ask.js +7 -7
  200. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  201. package/dist/core/runner/prepare-policy-chain.js +4 -10
  202. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  203. package/dist/core/runner/prepare-project-context.js +6 -3
  204. package/dist/core/runner/prepare-prompt-inputs.js +1 -1
  205. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -2
  206. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  207. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  208. package/dist/core/runner/prepare-safety-scan.js +8 -6
  209. package/dist/core/runner/prepare-task.js +15 -18
  210. package/dist/core/runner/prepare-tool-disclosure-mount.js +6 -4
  211. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -3
  212. package/dist/core/runner/prepare-wiring-manifest.js +2 -2
  213. package/dist/core/runner/resume-policy-outcome.js +1 -1
  214. package/dist/core/runner/retired-runner-deps.js +1 -1
  215. package/dist/core/runner/run-attachment-seats.js +0 -1
  216. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  217. package/dist/core/runner/run-compaction-machinery.js +2 -12
  218. package/dist/core/runner/run-git-lane.d.ts +1 -0
  219. package/dist/core/runner/run-harness-handlers.js +2 -3
  220. package/dist/core/runner/run-leg.js +13 -0
  221. package/dist/core/runner/run-settle-and-teardown.js +1 -1
  222. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  223. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  224. package/dist/core/runner/run-turn-boundary.js +14 -12
  225. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  226. package/dist/core/runner/session-rule-policy.js +13 -28
  227. package/dist/core/runner/side-call-account.d.ts +32 -8
  228. package/dist/core/runner/side-call-account.js +23 -1
  229. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  230. package/dist/core/runner/sub-agent-deny-lists.js +4 -3
  231. package/dist/core/runner/synthetic-tools.d.ts +10 -13
  232. package/dist/core/runner/synthetic-tools.js +4 -2
  233. package/dist/core/runner/tool-disclosure.js +2 -1
  234. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  235. package/dist/core/runner/tool-face-overlay.js +17 -1
  236. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  237. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  238. package/dist/core/runner/turn-attachments.d.ts +60 -67
  239. package/dist/core/runner-deps.d.ts +37 -37
  240. package/dist/core/runtime-caps.d.ts +4 -4
  241. package/dist/core/safety-merge-corpus.js +17 -1
  242. package/dist/core/same-plain-value.d.ts +40 -0
  243. package/dist/core/same-plain-value.js +49 -0
  244. package/dist/core/scheduler.d.ts +1 -1
  245. package/dist/core/sensitive-path-policy.d.ts +1 -1
  246. package/dist/core/sensitive-path-policy.js +1 -1
  247. package/dist/core/session-policy-store.d.ts +77 -22
  248. package/dist/core/session-policy-store.js +56 -14
  249. package/dist/core/session-reconcile.d.ts +2 -2
  250. package/dist/core/session-store.d.ts +80 -30
  251. package/dist/core/session-store.js +118 -76
  252. package/dist/core/session.d.ts +24 -46
  253. package/dist/core/shared-memory/tools.js +3 -1
  254. package/dist/core/shared-memory/types.d.ts +1 -1
  255. package/dist/core/side-query.d.ts +10 -0
  256. package/dist/core/side-query.js +5 -0
  257. package/dist/core/store-contracts/checkpoint-store-contract.js +29 -2
  258. package/dist/core/store-contracts/file-history-store-contract.js +43 -3
  259. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  260. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  261. package/dist/core/store-contracts/session-repo-contract.js +125 -0
  262. package/dist/core/store-contracts/session-store-contract.d.ts +4 -7
  263. package/dist/core/store-contracts/session-store-contract.js +259 -41
  264. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  265. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  266. package/dist/core/task-event.d.ts +10 -4
  267. package/dist/core/task-notification.d.ts +3 -3
  268. package/dist/core/task-registry-agent.d.ts +4 -4
  269. package/dist/core/task-registry-shared.d.ts +4 -4
  270. package/dist/core/task-registry-shared.js +1 -0
  271. package/dist/core/task-registry.d.ts +4 -4
  272. package/dist/core/task-registry.js +3 -1
  273. package/dist/core/task-result.d.ts +3 -3
  274. package/dist/core/task-spec.d.ts +52 -52
  275. package/dist/core/task-stream.d.ts +6 -6
  276. package/dist/core/task-tool-shape.d.ts +4 -4
  277. package/dist/core/tighten-task-spec.d.ts +1 -1
  278. package/dist/core/tool-catalog-entries.d.ts +19 -2
  279. package/dist/core/tool-catalog-entries.js +57 -42
  280. package/dist/core/tool-conformance.js +1 -0
  281. package/dist/core/tool-errors.d.ts +2 -2
  282. package/dist/core/tool-face-reader.js +5 -3
  283. package/dist/core/tool-face.d.ts +21 -2
  284. package/dist/core/tool-face.js +1 -1
  285. package/dist/core/tool-model-gate.d.ts +3 -3
  286. package/dist/core/tool-name-aliases.d.ts +29 -8
  287. package/dist/core/tool-name-aliases.js +27 -3
  288. package/dist/core/tool-name-readings.d.ts +5 -8
  289. package/dist/core/tool-name-readings.js +1 -2
  290. package/dist/core/tool-policy.d.ts +24 -5
  291. package/dist/core/tool-policy.js +34 -10
  292. package/dist/core/tool-registry.d.ts +14 -7
  293. package/dist/core/tool-registry.js +17 -7
  294. package/dist/core/tool-result-store.js +2 -1
  295. package/dist/core/tool-roster.d.ts +47 -18
  296. package/dist/core/tool-roster.js +53 -32
  297. package/dist/core/tool-spec-members.js +1 -1
  298. package/dist/core/tool-spec.d.ts +35 -21
  299. package/dist/core/tools.js +3 -2
  300. package/dist/core/trace.d.ts +4 -0
  301. package/dist/core/untrusted-egress.d.ts +1 -1
  302. package/dist/core/untrusted-text.d.ts +1 -1
  303. package/dist/core/warm-resume.d.ts +1 -1
  304. package/dist/core/wiring-manifest.d.ts +49 -0
  305. package/dist/core/wiring-manifest.js +13 -5
  306. package/dist/core/workflow-journal-store.d.ts +62 -0
  307. package/dist/core/workflow-journal-store.js +77 -1
  308. package/dist/core/workflow-run-store.d.ts +6 -0
  309. package/dist/core/workflow-run-store.js +2 -0
  310. package/dist/engine/compaction/compaction.d.ts +9 -9
  311. package/dist/engine/execution-env/node-execution-env.d.ts +19 -5
  312. package/dist/engine/execution-env/node-execution-env.js +43 -22
  313. package/dist/engine/harness/agent-harness.d.ts +14 -8
  314. package/dist/engine/harness/agent-harness.js +33 -26
  315. package/dist/engine/harness/types.d.ts +29 -7
  316. package/dist/engine/harness/types.js +12 -1
  317. package/dist/engine/llm/types.d.ts +9 -9
  318. package/dist/engine/llm/validation.d.ts +4 -1
  319. package/dist/engine/llm/validation.js +13 -1
  320. package/dist/engine/loop/agent-loop.d.ts +1 -1
  321. package/dist/engine/loop/agent-loop.js +10 -8
  322. package/dist/engine/loop/types.d.ts +15 -13
  323. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  324. package/dist/engine/session/memory-repo.d.ts +10 -11
  325. package/dist/engine/session/memory-repo.js +13 -8
  326. package/dist/engine/session/parent-chain-guard.d.ts +11 -0
  327. package/dist/engine/session/parent-chain-guard.js +10 -0
  328. package/dist/engine/session/repo-utils.d.ts +31 -3
  329. package/dist/engine/session/repo-utils.js +42 -5
  330. package/dist/engine/session/storage-base.js +3 -0
  331. package/dist/index.d.ts +27 -15
  332. package/dist/index.js +21 -11
  333. package/dist/internal/harness-types.d.ts +1 -1
  334. package/dist/internal/harness.d.ts +4 -3
  335. package/dist/internal/harness.js +3 -2
  336. package/dist/internal/llm.d.ts +1 -1
  337. package/dist/internal/llm.js +1 -1
  338. package/dist/orchestration/goal.js +2 -2
  339. package/dist/orchestration/run-workflow-tool.d.ts +2 -2
  340. package/dist/orchestration/run-workflow-tool.js +5 -3
  341. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  342. package/dist/orchestration/workflow-types.d.ts +18 -0
  343. package/dist/orchestration/workflow-types.js +6 -0
  344. package/dist/orchestration/workflow.d.ts +2 -13
  345. package/dist/orchestration/workflow.js +21 -31
  346. package/dist/prompt-assembly/event-registry.js +1 -0
  347. package/dist/prompt-assembly/tool-catalog.d.ts +3 -0
  348. package/dist/prompt-assembly/tool-catalog.js +3 -0
  349. package/dist/prompts/default.d.ts +14 -14
  350. package/dist/scenarios/full-body.d.ts +4 -4
  351. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  352. package/dist/stores/file/adoption/adopt.js +24 -31
  353. package/dist/stores/file/adoption/marker.d.ts +6 -13
  354. package/dist/stores/file/adoption/marker.js +6 -15
  355. package/dist/stores/file/checkpoint-store.d.ts +3 -0
  356. package/dist/stores/file/checkpoint-store.js +9 -3
  357. package/dist/stores/file/file-history-store.d.ts +20 -19
  358. package/dist/stores/file/file-history-store.js +152 -135
  359. package/dist/stores/file/fs-atomic.d.ts +15 -0
  360. package/dist/stores/file/fs-atomic.js +89 -14
  361. package/dist/stores/file/index.d.ts +1 -1
  362. package/dist/stores/file/mailbox-store.d.ts +3 -0
  363. package/dist/stores/file/mailbox-store.js +3 -1
  364. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  365. package/dist/stores/file/permission-rule-adopt.js +15 -16
  366. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  367. package/dist/stores/file/permission-rule-store.js +21 -14
  368. package/dist/stores/file/session-policy-store.d.ts +3 -3
  369. package/dist/stores/file/session-store.d.ts +26 -11
  370. package/dist/stores/file/session-store.js +77 -40
  371. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  372. package/dist/stores/file/workflow-journal-store.js +28 -13
  373. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  374. package/dist/tools/artifact/artifact-tool.js +2 -1
  375. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  376. package/dist/tools/fs/fs-bash.d.ts +2 -2
  377. package/dist/tools/fs/fs-bash.js +3 -1
  378. package/dist/tools/fs/fs-shared.d.ts +8 -8
  379. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  380. package/dist/tools/fs/notebook.d.ts +2 -2
  381. package/dist/tools/fs/read-deny.d.ts +29 -7
  382. package/dist/tools/fs/read-deny.js +63 -22
  383. package/dist/tools/fs/removal-targets.d.ts +1 -1
  384. package/dist/tools/fs/safety.d.ts +9 -9
  385. package/dist/tools/fs/search.d.ts +6 -6
  386. package/dist/tools/fs/shell-read-check.js +6 -1
  387. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  388. package/dist/tools/fs/shell-read-judge.js +5 -2
  389. package/dist/tools/loop-tick.d.ts +2 -2
  390. package/dist/tools/scheduler-tools.js +5 -1
  391. package/dist/tools/task-list.d.ts +7 -7
  392. package/dist/tools/task-list.js +5 -1
  393. package/dist/tools/todo.js +2 -1
  394. package/dist/tools/web.d.ts +1 -1
  395. package/dist/tools/web.js +40 -37
  396. package/dist/tools/worktree.d.ts +3 -3
  397. package/dist/tools/worktree.js +3 -1
  398. package/package.json +1 -1
  399. package/test/export-surface.snapshot.json +5756 -5638
  400. package/wire-changes/core@7.54.1.json +37 -0
  401. package/wire-changes/core@7.55.0.json +3318 -0
  402. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  403. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -118,11 +118,12 @@ async function settleTrailingBatchTurn(state, signal, emit, settle) {
118
118
  terminalEmitted = ended;
119
119
  }
120
120
  else if (!ended) {
121
+ state.hasMoreToolCalls = !batch.terminate;
121
122
  const boundary = { message: tail, toolResults: batch.messages, context: state.context, newMessages: state.newMessages };
122
- adoptNextTurnSnapshot(state, await state.config.prepareNextTurn?.(boundary));
123
+ adoptNextTurnSnapshot(state, await state.config.prepareNextTurn?.({ ...boundary, continues: state.hasMoreToolCalls }));
123
124
  ended = (await state.config.shouldStopAfterTurn?.(boundary)) === true || signal?.aborted === true;
124
125
  if (!ended)
125
- state.pendingMessages.push(...((await state.config.getSteeringMessages?.()) || []));
126
+ state.pendingMessages.push(...((await state.config.getSteeringMessages?.(state.hasMoreToolCalls)) || []));
126
127
  }
127
128
  settle.report({ assistantMessage: tail, settled: batch.messages.length, aborted: ended });
128
129
  if (ended && !terminalEmitted)
@@ -242,7 +243,7 @@ async function createLoopState(context, config, newMessages) {
242
243
  config,
243
244
  newMessages,
244
245
  firstTurn: true,
245
- pendingMessages: (await config.getSteeringMessages?.()) || [],
246
+ pendingMessages: (await config.getSteeringMessages?.(true)) || [],
246
247
  hasMoreToolCalls: true,
247
248
  truncatedOutputContinues: 0,
248
249
  staticReasoningCutRecoveries: context.messages.filter((m) => m.role === "assistant" && m.staticReasoningCut === true).length,
@@ -258,7 +259,7 @@ async function runLoop(state, signal, emit, streamFn, runtime, trace) {
258
259
  const followUpMessages = (await state.config.getFollowUpMessages?.()) || [];
259
260
  if (followUpMessages.length === 0) {
260
261
  if ((state.config.pendingInjectionCount?.() ?? 0) > 0) {
261
- state.pendingMessages = (await state.config.getSteeringMessages?.()) || [];
262
+ state.pendingMessages = (await state.config.getSteeringMessages?.(false)) || [];
262
263
  if (state.pendingMessages.length > 0) {
263
264
  trace?.({ kind: "continue", reason: "steer_injected" });
264
265
  }
@@ -448,7 +449,7 @@ async function runTurnPhases(state, signal, turnController, publishSeat, retract
448
449
  retractSeat();
449
450
  state.degenerateContinues++;
450
451
  await emit({ type: "turn_end", message, toolResults: [] });
451
- const drained = (await state.config.getSteeringMessages?.()) || [];
452
+ const drained = (await state.config.getSteeringMessages?.(false)) || [];
452
453
  state.pendingMessages = drained.length > 0 ? drained : [createDegenerateRecoveryNudge()];
453
454
  return { kind: "ran", recovered: "degenerate_output_recovery" };
454
455
  }
@@ -493,7 +494,7 @@ async function runTurnPhases(state, signal, turnController, publishSeat, retract
493
494
  context: state.context,
494
495
  newMessages: state.newMessages,
495
496
  };
496
- const nextTurnSnapshot = await state.config.prepareNextTurn?.(nextTurnContext);
497
+ const nextTurnSnapshot = await state.config.prepareNextTurn?.({ ...nextTurnContext, continues: state.hasMoreToolCalls });
497
498
  adoptNextTurnSnapshot(state, nextTurnSnapshot);
498
499
  if (await state.config.shouldStopAfterTurn?.({
499
500
  message,
@@ -504,7 +505,7 @@ async function runTurnPhases(state, signal, turnController, publishSeat, retract
504
505
  await emit({ type: "agent_end", messages: state.newMessages });
505
506
  return { kind: "terminal", reason: "stop_requested" };
506
507
  }
507
- state.pendingMessages = (await state.config.getSteeringMessages?.()) || [];
508
+ state.pendingMessages = (await state.config.getSteeringMessages?.(state.hasMoreToolCalls)) || [];
508
509
  const truncated = state.config.recovery?.truncatedOutput;
509
510
  if (message.stopReason === "length") {
510
511
  if (truncated && toolCalls.length === 0 && state.pendingMessages.length === 0) {
@@ -653,6 +654,7 @@ async function settleInterruptedTurn(state, message, executor, committedResults,
653
654
  toolResults,
654
655
  context: state.context,
655
656
  newMessages: state.newMessages,
657
+ continues: state.hasMoreToolCalls,
656
658
  });
657
659
  adoptNextTurnSnapshot(state, nextTurnSnapshot);
658
660
  if (await state.config.shouldStopAfterTurn?.({
@@ -664,7 +666,7 @@ async function settleInterruptedTurn(state, message, executor, committedResults,
664
666
  await emit({ type: "agent_end", messages: state.newMessages });
665
667
  return { kind: "terminal", reason: "stop_requested" };
666
668
  }
667
- state.pendingMessages = (await state.config.getSteeringMessages?.()) || [];
669
+ state.pendingMessages = (await state.config.getSteeringMessages?.(state.hasMoreToolCalls)) || [];
668
670
  return { kind: "ran" };
669
671
  }
670
672
  async function streamAssistantResponse(context, config, signal, emit, streamFn, runtime, executor, staticReasoningCutDowngrade) {
@@ -176,6 +176,8 @@ export interface AgentLoopTurnUpdate {
176
176
  thinkingLevel?: ThinkingLevel;
177
177
  }
178
178
  export interface PrepareNextTurnContext extends ShouldStopAfterTurnContext {
179
+ /** `hasMoreToolCalls`: the turn's tool results go back to the model as the next request (its batch neither ended the run nor was cut by an interjection; a recovery nudge is not one). */
180
+ continues: boolean;
179
181
  }
180
182
  /**
181
183
  * Prompt-too-long recovery seam (design/118 ④b, the CC reactive-compact chain adapted to sema's
@@ -214,8 +216,8 @@ export interface LoopPromptTooLongRecovery {
214
216
  maxRetries?: number;
215
217
  /**
216
218
  * M1 (docs/PARITY-CONTEXT-TRANSACTIONS-2026-07-10 §4): withhold the failed assistant's
217
- * message_start/message_end stream events while a recovery attempt is pending — CC 198 holds
218
- * these errors inside its stream decoder (`claude-cli-2.1.198.pretty.js:473371-473374`) and only
219
+ * message_start/message_end stream events while a recovery attempt is pending — the reference holds
220
+ * these errors inside its stream decoder and only
219
221
  * leaks them once recovery's outcome is known. Recovery succeeded ⇒ the failure stays invisible
220
222
  * to event consumers; failed/declined ⇒ the events leak at that point (terminal truth unchanged).
221
223
  * Default true (CC-aligned). `false` restores the pre-M1 live leak of the interim error.
@@ -239,7 +241,7 @@ export interface LoopTruncatedOutputRecovery {
239
241
  maxContinues?: number;
240
242
  }
241
243
  /**
242
- * Malformed-tool-use retry (design/119 S2, CC 2.1.198 :473745-473785). A turn that stops with
244
+ * Malformed-tool-use retry (design/119 S2). A turn that stops with
243
245
  * `toolUse` but carries ZERO parseable tool calls (the brain dropped truncated/invalid ones) used to
244
246
  * end the run silently mid-task. When enabled, inject a synthetic retry nudge and run another turn,
245
247
  * up to `maxRetries` per run (CC: once). Absent ⇒ OFF (pre-S2 behavior).
@@ -249,7 +251,7 @@ export interface LoopMalformedToolUseRecovery {
249
251
  maxRetries?: number;
250
252
  }
251
253
  /**
252
- * Thinking-only retry (design/119 S2, CC 2.1.198 :473786-473825 — the adaptive-thinking era
254
+ * Thinking-only retry (design/119 S2 — the adaptive-thinking era
253
255
  * companion). A turn that stops normally with thinking block(s) but NO visible text and NO tool
254
256
  * calls used to end the run as a silent empty success. When enabled, inject a "respond with visible
255
257
  * output" nudge and run another turn, up to `maxRetries` per run (CC: once). Absent ⇒ OFF.
@@ -345,7 +347,7 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
345
347
  */
346
348
  stallTimeoutsPerCall?: () => import("../llm/types.js").StallTimeouts | undefined;
347
349
  /**
348
- * design/120 P1: concurrency cap inside a parallel tool batch. Default 10 (CC 198's production
350
+ * design/120 P1: concurrency cap inside a parallel tool batch. Default 10 (the reference's production
349
351
  * default — its knob is the CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY env; sema takes config).
350
352
  */
351
353
  maxToolConcurrency?: number;
@@ -473,11 +475,11 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
473
475
  * If messages are returned, they are added to the context before the next LLM call.
474
476
  * Tool calls from the current assistant message are not skipped.
475
477
  *
476
- * Use this for "steering" the agent while it's working.
478
+ * Use this for "steering" the agent while it's working. `continuing`: {@link PrepareNextTurnContext.continues} here.
477
479
  *
478
480
  * Contract: must not throw or reject. Return [] when no steering messages are available.
479
481
  */
480
- getSteeringMessages?: () => Promise<AgentMessage[]>;
482
+ getSteeringMessages?: (continuing: boolean) => Promise<AgentMessage[]>;
481
483
  /**
482
484
  * Returns follow-up messages to process after the agent would otherwise stop.
483
485
  *
@@ -520,7 +522,7 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
520
522
  /**
521
523
  * design/373 S1 — the FINAL COMMIT POINT's synchronous double-check: how many queued injection
522
524
  * frames a boundary drain could deliver right now (steer + follow-up, excluding frames a live
523
- * hold or an unwinding run would refuse to drain). Consulted SYNCHRONOUSLY after the follow-up
525
+ * hold, an unwinding run or the advisory rule would refuse to drain). Consulted SYNCHRONOUSLY after the follow-up
524
526
  * drain (and stop gate) answered empty, with zero awaits between the check and the terminal
525
527
  * commit — a frame that arrived during the stop gate's await window is therefore served by this
526
528
  * run instead of being stranded behind an already-decided terminal. Absent ⇒ the pre-373 commit
@@ -759,17 +761,17 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = unk
759
761
  * - "parallel": this tool can execute concurrently with other tool calls.
760
762
  *
761
763
  * If omitted, the tool is treated as NOT concurrency-safe unless its input-level
762
- * `isConcurrencySafe` hook opts a call in (fail-closed; CC 2.1.206 TOOL_DEFAULTS parity).
764
+ * `isConcurrencySafe` hook opts a call in (fail-closed).
763
765
  */
764
766
  executionMode?: ToolExecutionMode;
765
767
  /**
766
- * MCP server self-declared result-size threshold (CC 198 `_meta["anthropic/maxResultSizeChars"]`,
767
- * pretty.js:320015/:320061 — consumer caps at 500K). Set by the MCP materializer when the server
768
+ * MCP server self-declared result-size threshold (`_meta["anthropic/maxResultSizeChars"]`,
769
+ * consumer caps at 500K). Set by the MCP materializer when the server
768
770
  * declares it; consulted by the offload mount in prepare-task. Absent on non-MCP tools.
769
771
  */
770
772
  mcpMaxResultSizeChars?: number;
771
773
  /**
772
- * RB-400-a — MCP server-declared inline pin (CC 220 `_meta["anthropic/alwaysLoad"]`): set by the
774
+ * RB-400-a — MCP server-declared inline pin (`_meta["anthropic/alwaysLoad"]`): set by the
773
775
  * MCP materializer when the server's tools/list entry declares it; prepare-task folds these names
774
776
  * into the defer classification's exemption set, ahead of the MCP constant-defer arm — the
775
777
  * server's own channel for keeping one tool's full schema inlined. Absent on non-MCP tools.
@@ -803,7 +805,7 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = unk
803
805
  * partitioner for every tool WITHOUT an explicit `executionMode:"parallel"` (a statically-parallel
804
806
  * tool needs no refinement); `true` = treat THIS CALL as concurrency-safe. A throw = false
805
807
  * (fail-closed, CC same). The partitioner validates the call's args against the tool schema FIRST
806
- * (schema-invalid ⇒ unsafe, CC 206 safeParse parity) and hands the hook the validated+coerced
808
+ * (schema-invalid ⇒ unsafe) and hands the hook the validated+coerced
807
809
  * args — still treat defensively (a direct caller may pass raw args). Omitted ⇒ the static mode stands.
808
810
  */
809
811
  isConcurrencySafe?: (args: unknown) => boolean;
@@ -127,12 +127,12 @@ export declare class NodeLspManager implements LspServerManager {
127
127
  }
128
128
  /** Resolve a file path to a languageId via its extension (undefined = no mapping → degrade). */
129
129
  export declare function languageFor(filePath: string): string | undefined;
130
- /** CC 2.1.220's LSP file cap — single-sourced in core (`src/core/lsp.ts`), where the tool-layer check
130
+ /** The LSP file cap — single-sourced in core (`src/core/lsp.ts`), where the tool-layer check
131
131
  * enforces it model-visibly; re-exported here so engine-path importers keep working. */
132
132
  export { MAX_LSP_FILE_BYTES } from "../../core/lsp.js";
133
133
  /**
134
134
  * RB-232: the local default {@link LspReadText}, hardened with a stat-first precondition (CC
135
- * 2.1.220 validateInput does the same before ever reading — "Path is not a file", (pretty220.js:474700, historical; not relocated in 250 — see cc-250 anchors)).
135
+ * the reference's validateInput does the same before ever reading — "Path is not a file").
136
136
  * The stat check is the LOAD-BEARING part, do not "simplify" it away: a plain `readFile` on a FIFO/socket
137
137
  * blocks forever on the FIRST read and PINS a libuv threadpool thread (default pool = 4) for the process
138
138
  * lifetime — measured: `readFile(fifo, { signal })` with an abort fired at 2s was still unsettled at 10s,
@@ -1,22 +1,21 @@
1
- import { type Session, type SessionForkOptions, type SessionMetadata, type SessionRepo, type SessionTreeEntry } from "../harness/types.js";
2
- export declare class InMemorySessionRepo implements SessionRepo<SessionMetadata, {
3
- id?: string;
4
- }> {
1
+ import { type Session, type SessionCreateOptions, type SessionForkOptions, type SessionHead, type SessionMetadata, type SessionRepo, type SessionTreeEntry } from "../harness/types.js";
2
+ export declare class InMemorySessionRepo implements SessionRepo<SessionMetadata, SessionCreateOptions> {
5
3
  private sessions;
6
- create(options?: {
7
- id?: string;
8
- }): Promise<Session>;
4
+ create(options?: SessionCreateOptions): Promise<Session>;
9
5
  open(metadata: SessionMetadata): Promise<Session>;
6
+ /** The row's head off the one session object that IS the row: every cell comes from that object, so a delete and re-create of the
7
+ * id while this reads cannot mix two generations. */
8
+ headOf(sessionId: string): Promise<SessionHead | undefined>;
10
9
  list(): Promise<SessionMetadata[]>;
11
10
  delete(metadata: SessionMetadata): Promise<void>;
12
- fork(sourceMetadata: SessionMetadata, options: SessionForkOptions): Promise<Session>;
11
+ fork(sourceMetadata: SessionMetadata, options: SessionForkOptions & SessionCreateOptions): Promise<Session>;
13
12
  /** 2c session-sync: the FULL log for export. InMemory holds everything (no F3 floor), so
14
13
  * `getEntries()` IS the full oldest-first log with `id`/`parentId` verbatim. */
15
14
  exportEntries(sessionId: string): Promise<SessionTreeEntry[]>;
16
15
  /** 2c session-sync: import a verbatim log into `sessionId`. The single invariant gate runs first
17
- * ({@link validateEntriesForImport}, fail-closed); `owner` is a durable multi-tenant concept that the local
18
- * in-memory backend has no field for, so it is accepted but unused here. design/171: the operator's
19
- * trusted-import flag is forwarded to the gate that persists — see SessionRepo.importEntries. */
16
+ * ({@link validateEntriesForImport}, fail-closed); a new row records `owner`, an existing row keeps its metadata whole.
17
+ * design/171: the operator's trusted-import flag is forwarded to the gate that persists — see
18
+ * SessionRepo.importEntries. */
20
19
  importEntries(sessionId: string, owner: string | undefined, entries: SessionTreeEntry[], options?: {
21
20
  preserveActorAssertions?: boolean;
22
21
  }): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { SessionError } from "../harness/types.js";
2
2
  import { validateEntriesForImport } from "./import-validate.js";
3
3
  import { InMemorySessionStorage } from "./memory-storage.js";
4
- import { assertForkTarget, createSessionId, createTimestamp, forkRowCells, getEntriesToFork, incarnationCell, toSession } from "./repo-utils.js";
4
+ import { assertForkTarget, createSessionId, createTimestamp, forkRowCells, frozenRow, getEntriesToFork, headOfSession, importRowCells, incarnationCell, ownerCell, toSession } from "./repo-utils.js";
5
5
  export class InMemorySessionRepo {
6
6
  sessions = new Map();
7
7
  async create(options = {}) {
@@ -10,11 +10,12 @@ export class InMemorySessionRepo {
10
10
  if (existing)
11
11
  return existing;
12
12
  }
13
- const metadata = {
13
+ const metadata = frozenRow({
14
14
  id: options.id ?? createSessionId(),
15
15
  createdAt: createTimestamp(),
16
16
  ...incarnationCell(undefined),
17
- };
17
+ ...ownerCell(options.owner),
18
+ });
18
19
  const storage = new InMemorySessionStorage({ metadata });
19
20
  const session = toSession(storage);
20
21
  this.sessions.set(metadata.id, session);
@@ -27,6 +28,10 @@ export class InMemorySessionRepo {
27
28
  }
28
29
  return session;
29
30
  }
31
+ async headOf(sessionId) {
32
+ const row = this.sessions.get(sessionId);
33
+ return row === undefined ? undefined : headOfSession(row);
34
+ }
30
35
  async list() {
31
36
  return Promise.all([...this.sessions.values()].map((session) => session.getMetadata()));
32
37
  }
@@ -37,11 +42,11 @@ export class InMemorySessionRepo {
37
42
  assertForkTarget(sourceMetadata.id, options.id);
38
43
  const source = await this.open(sourceMetadata);
39
44
  const forkedEntries = await getEntriesToFork(source.getStorage(), options);
40
- const metadata = {
45
+ const metadata = frozenRow({
41
46
  id: options.id ?? createSessionId(),
42
47
  createdAt: createTimestamp(),
43
- ...forkRowCells(await source.getMetadata()),
44
- };
48
+ ...forkRowCells(await source.getMetadata(), options.owner),
49
+ });
45
50
  const storage = new InMemorySessionStorage({ metadata, entries: forkedEntries });
46
51
  const session = toSession(storage);
47
52
  this.sessions.set(metadata.id, session);
@@ -52,7 +57,7 @@ export class InMemorySessionRepo {
52
57
  return session.getStorage().getEntries();
53
58
  }
54
59
  async importEntries(sessionId, owner, entries, options) {
55
- void owner;
60
+ ownerCell(owner);
56
61
  const validated = validateEntriesForImport(entries, options);
57
62
  let prior = this.sessions.get(sessionId);
58
63
  let header = prior !== undefined ? await prior.getMetadata() : undefined;
@@ -60,7 +65,7 @@ export class InMemorySessionRepo {
60
65
  prior = this.sessions.get(sessionId);
61
66
  header = prior !== undefined ? await prior.getMetadata() : undefined;
62
67
  }
63
- const metadata = { id: sessionId, createdAt: createTimestamp(), ...incarnationCell(header) };
68
+ const metadata = frozenRow(importRowCells(sessionId, owner, header, createTimestamp()));
64
69
  this.sessions.set(sessionId, toSession(new InMemorySessionStorage({ metadata, entries: validated })));
65
70
  }
66
71
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The memory of one walk up a session log's parent chain, shared by `getPathToRoot`, the resume-at ancestry scan and the fork-point judge `settledForkOptions` (the import validator still keeps its own loop — #2253). An entry the
3
+ * walk stands on twice means the parent links loop, which no ancestry can contain: the walk is refused
4
+ * `invalid_session` naming that entry instead of being followed again, and saying what a person can do (start a new session, or fork from an entry the
5
+ * loop does not touch). One guard per walk.
6
+ */
7
+ export declare class ParentChainGuard {
8
+ private readonly stepped;
9
+ /** Records that the walk now stands on `id`; throws `invalid_session` when it already stood there. */
10
+ stepOnto(id: string): void;
11
+ }
@@ -0,0 +1,10 @@
1
+ import { SessionError } from "../harness/types.js";
2
+ export class ParentChainGuard {
3
+ stepped = new Set();
4
+ stepOnto(id) {
5
+ if (this.stepped.has(id)) {
6
+ throw new SessionError("invalid_session", `Entry ${id} is its own ancestor (parent chain cycles at ${id}) — start a new session, or fork from an entry above the loop`);
7
+ }
8
+ this.stepped.add(id);
9
+ }
10
+ }
@@ -1,4 +1,4 @@
1
- import { type SessionMetadata, type SessionStorage, type SessionTreeEntry } from "../harness/types.js";
1
+ import { type SessionHead, type SessionMetadata, type SessionStorage, type SessionTreeEntry } from "../harness/types.js";
2
2
  import type { Session } from "../harness/types.js";
3
3
  export declare function createSessionId(): string;
4
4
  /** The {@link SessionMetadata.incarnation} cell for a write laying a row's metadata down — the bundled repos' ONE mint point.
@@ -10,10 +10,38 @@ export declare function incarnationCell(existing: Pick<SessionMetadata, "incarna
10
10
  * occupant, silently; a cell that is there but is not a token (`""`, a non-string) is an unknown occupant too and `disclose`
11
11
  * is told once with the cell's shape (never its value). The cell never makes this throw; a throw from `disclose` propagates. */
12
12
  export declare function readIncarnationCell(raw: unknown, disclose: (detail: string) => void): string | undefined;
13
+ /**
14
+ * Whether two heads of one session id name the same occupant (each side a {@link SessionHead}, or a row's {@link SessionMetadata}).
15
+ * `"unknown"` whenever either side has no row or no occupant token — unknown is never `"same"`, so a caller that may only proceed on the
16
+ * same occupant refuses on it.
17
+ */
18
+ export declare function compareOccupants(before: {
19
+ readonly incarnation?: SessionHead["incarnation"];
20
+ } | undefined, after: {
21
+ readonly incarnation?: SessionHead["incarnation"];
22
+ } | undefined): "same" | "different" | "unknown";
23
+ /** The {@link SessionHead} a session object shows: its metadata's owner and occupant and its storage's leaf, off that one object. */
24
+ export declare function headOfSession(session: Session): Promise<SessionHead>;
25
+ /** The {@link SessionMetadata.owner} cell the write creating a row records: `owner` (a string, or `null`; `undefined` = none named =
26
+ * `null`). An `owner` that is neither is refused before the write, so no row ever holds an owner cell that reads as neither. */
27
+ export declare function ownerCell(owner: unknown): Pick<SessionMetadata, "owner">;
28
+ /** The metadata an import lays down. An import replaces the log, never the row: an existing row keeps its metadata whole (its creation
29
+ * time, lineage, placement, occupant and owner were recorded by the write that created it); an absent id is a new row recording `owner`
30
+ * and a fresh occupant. `owner` is judged either way. */
31
+ export declare function importRowCells(sessionId: string, owner: unknown, existing: SessionMetadata | undefined, createdAt: string): SessionMetadata;
32
+ /** The one decoding of a stored owner cell: a string is the owner; absence (`undefined`, `null`) is anonymous. A cell that is there
33
+ * but is neither cannot be read as anyone's, and reading it as anonymous would admit every principal — the row is refused as
34
+ * `corrupt_session` instead (a read fault, never an answer). */
35
+ export declare function readOwnerCell(raw: unknown, sessionId: string): string | null;
13
36
  /** A fork lands on a row OTHER than its source: onto its own id it would mint a new occupant over the source's transcript and erase the lineage that carries the source's records. */
14
37
  export declare function assertForkTarget(sourceId: string, targetId: string | undefined): void;
15
- /** A fork row's cells, minted from the SOURCE row as it stands at fork time: the lineage (`forkedFrom` + the occupant copied) and a fresh occupant of its own. */
16
- export declare function forkRowCells(source: SessionMetadata): Pick<SessionMetadata, "forkedFrom" | "forkedFromIncarnation" | "incarnation">;
38
+ /** A fork row's cells, minted from the SOURCE row as it stands at fork time — the same row the fork copies its history from: the lineage
39
+ * (`forkedFrom` + the occupant copied), a fresh occupant of its own, and its owner — `owner` when one is named, otherwise (absent or `null`)
40
+ * the source row's, so a copy of an owned history is never anonymous and never another generation's. */
41
+ export declare function forkRowCells(source: SessionMetadata, owner?: string | null): Pick<SessionMetadata, "forkedFrom" | "forkedFromIncarnation" | "incarnation" | "owner">;
42
+ /** A row's metadata as the bundled repos hold it: frozen (its placement tuple too), so a caller holding the object `getMetadata()` or
43
+ * `list()` returns cannot rewrite the row's identity cells — the owner, the occupant, the placement, the lineage — without a write. */
44
+ export declare function frozenRow<T extends SessionMetadata>(meta: T): T;
17
45
  export declare function createTimestamp(): string;
18
46
  export declare function toSession<TMetadata extends SessionMetadata>(storage: SessionStorage<TMetadata>): Session<TMetadata>;
19
47
  export declare function getEntriesToFork(storage: SessionStorage, options: {
@@ -11,20 +11,57 @@ export function incarnationCell(existing) {
11
11
  return existing.incarnation !== undefined ? { incarnation: existing.incarnation } : {};
12
12
  }
13
13
  export function readIncarnationCell(raw, disclose) {
14
- if (typeof raw === "string" && raw !== "")
14
+ if (isOccupantToken(raw))
15
15
  return raw;
16
16
  if (raw === undefined || raw === null)
17
17
  return undefined;
18
- const shape = raw === "" ? "an empty string" : Array.isArray(raw) ? "a non-string value (array)" : `a non-string value (${typeof raw})`;
19
- disclose(`the incarnation cell holds ${shape} — read as an unknown occupant`);
18
+ disclose(`the incarnation cell holds ${raw === "" ? "an empty string" : nonStringShape(raw)} — read as an unknown occupant`);
20
19
  return undefined;
21
20
  }
21
+ function isOccupantToken(raw) {
22
+ return typeof raw === "string" && raw !== "";
23
+ }
24
+ function nonStringShape(raw) {
25
+ return Array.isArray(raw) ? "a non-string value (array)" : `a non-string value (${typeof raw})`;
26
+ }
27
+ export function compareOccupants(before, after) {
28
+ const a = before?.incarnation;
29
+ const b = after?.incarnation;
30
+ if (!isOccupantToken(a) || !isOccupantToken(b))
31
+ return "unknown";
32
+ return a === b ? "same" : "different";
33
+ }
34
+ export async function headOfSession(session) {
35
+ const meta = await session.getMetadata();
36
+ return { owner: meta.owner ?? null, incarnation: meta.incarnation, leafId: await session.getStorage().getLeafId() };
37
+ }
38
+ export function ownerCell(owner) {
39
+ if (owner !== undefined && owner !== null && typeof owner !== "string")
40
+ throw new TypeError(`session owner must be a string (owned) or null (anonymous), got ${nonStringShape(owner)}`);
41
+ return { owner: owner ?? null };
42
+ }
43
+ export function importRowCells(sessionId, owner, existing, createdAt) {
44
+ const named = ownerCell(owner);
45
+ return existing ?? { id: sessionId, createdAt, ...incarnationCell(undefined), ...named };
46
+ }
47
+ export function readOwnerCell(raw, sessionId) {
48
+ if (typeof raw === "string")
49
+ return raw;
50
+ if (raw === undefined || raw === null)
51
+ return null;
52
+ throw new SessionError("corrupt_session", `session ${sessionId}'s owner cell holds ${nonStringShape(raw)} — neither an owner nor anonymous; refusing to read the row`);
53
+ }
22
54
  export function assertForkTarget(sourceId, targetId) {
23
55
  if (targetId === sourceId)
24
56
  throw new SessionError("invalid_fork_target", `cannot fork session ${sourceId} onto its own id — fork into a new id`);
25
57
  }
26
- export function forkRowCells(source) {
27
- return { forkedFrom: source.id, ...(source.incarnation !== undefined ? { forkedFromIncarnation: source.incarnation } : {}), ...incarnationCell(undefined) };
58
+ export function forkRowCells(source, owner) {
59
+ return { forkedFrom: source.id, ...(source.incarnation !== undefined ? { forkedFromIncarnation: source.incarnation } : {}), ...incarnationCell(undefined), ...ownerCell(owner ?? source.owner) };
60
+ }
61
+ export function frozenRow(meta) {
62
+ if (meta.placement !== undefined)
63
+ Object.freeze(meta.placement);
64
+ return Object.freeze(meta);
28
65
  }
29
66
  export function createTimestamp() {
30
67
  return new Date().toISOString();
@@ -1,4 +1,5 @@
1
1
  import { SessionError, } from "../harness/types.js";
2
+ import { ParentChainGuard } from "./parent-chain-guard.js";
2
3
  import { uuidv7 } from "./uuid.js";
3
4
  function updateLabelCache(labelsById, entry) {
4
5
  if (entry.type !== "label") {
@@ -111,11 +112,13 @@ export class BaseSessionStorage {
111
112
  return [];
112
113
  }
113
114
  const path = [];
115
+ const chain = new ParentChainGuard();
114
116
  let current = this.byId.get(leafId);
115
117
  if (!current) {
116
118
  throw new SessionError("not_found", `Entry ${leafId} not found`);
117
119
  }
118
120
  while (current) {
121
+ chain.stepOnto(current.id);
119
122
  path.push(current);
120
123
  if (current.id === this.floorId) {
121
124
  break;