@sema-agent/core 7.54.1 → 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 (399) hide show
  1. package/CHANGELOG.md +437 -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-advisor.d.ts +63 -0
  186. package/dist/core/runner/prepare-advisor.js +77 -0
  187. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  188. package/dist/core/runner/prepare-config-doors.d.ts +6 -4
  189. package/dist/core/runner/prepare-config-doors.js +18 -12
  190. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  191. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  192. package/dist/core/runner/prepare-file-history.js +39 -39
  193. package/dist/core/runner/prepare-gate-stations.d.ts +1 -4
  194. package/dist/core/runner/prepare-gate-stations.js +2 -7
  195. package/dist/core/runner/prepare-inherited-gate.d.ts +5 -4
  196. package/dist/core/runner/prepare-inherited-gate.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.js +7 -7
  198. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  199. package/dist/core/runner/prepare-policy-chain.js +4 -10
  200. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  201. package/dist/core/runner/prepare-project-context.js +6 -3
  202. package/dist/core/runner/prepare-prompt-inputs.js +1 -1
  203. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -2
  204. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  205. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  206. package/dist/core/runner/prepare-safety-scan.js +8 -6
  207. package/dist/core/runner/prepare-task.js +15 -18
  208. package/dist/core/runner/prepare-tool-disclosure-mount.js +6 -4
  209. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -3
  210. package/dist/core/runner/prepare-wiring-manifest.js +2 -2
  211. package/dist/core/runner/resume-policy-outcome.js +1 -1
  212. package/dist/core/runner/retired-runner-deps.js +1 -1
  213. package/dist/core/runner/run-attachment-seats.js +0 -1
  214. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  215. package/dist/core/runner/run-compaction-machinery.js +2 -12
  216. package/dist/core/runner/run-git-lane.d.ts +1 -0
  217. package/dist/core/runner/run-harness-handlers.js +2 -3
  218. package/dist/core/runner/run-leg.js +13 -0
  219. package/dist/core/runner/run-settle-and-teardown.js +1 -1
  220. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  221. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  222. package/dist/core/runner/run-turn-boundary.js +14 -12
  223. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  224. package/dist/core/runner/session-rule-policy.js +13 -28
  225. package/dist/core/runner/side-call-account.d.ts +32 -8
  226. package/dist/core/runner/side-call-account.js +23 -1
  227. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  228. package/dist/core/runner/sub-agent-deny-lists.js +4 -3
  229. package/dist/core/runner/synthetic-tools.d.ts +10 -13
  230. package/dist/core/runner/synthetic-tools.js +4 -2
  231. package/dist/core/runner/tool-disclosure.js +2 -1
  232. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  233. package/dist/core/runner/tool-face-overlay.js +17 -1
  234. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  235. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  236. package/dist/core/runner/turn-attachments.d.ts +60 -67
  237. package/dist/core/runner-deps.d.ts +37 -37
  238. package/dist/core/runtime-caps.d.ts +4 -4
  239. package/dist/core/safety-merge-corpus.js +17 -1
  240. package/dist/core/same-plain-value.d.ts +40 -0
  241. package/dist/core/same-plain-value.js +49 -0
  242. package/dist/core/scheduler.d.ts +1 -1
  243. package/dist/core/sensitive-path-policy.d.ts +1 -1
  244. package/dist/core/sensitive-path-policy.js +1 -1
  245. package/dist/core/session-policy-store.d.ts +77 -22
  246. package/dist/core/session-policy-store.js +56 -14
  247. package/dist/core/session-reconcile.d.ts +2 -2
  248. package/dist/core/session-store.d.ts +80 -30
  249. package/dist/core/session-store.js +118 -76
  250. package/dist/core/session.d.ts +24 -46
  251. package/dist/core/shared-memory/tools.js +3 -1
  252. package/dist/core/shared-memory/types.d.ts +1 -1
  253. package/dist/core/side-query.d.ts +10 -0
  254. package/dist/core/side-query.js +5 -0
  255. package/dist/core/store-contracts/checkpoint-store-contract.js +29 -2
  256. package/dist/core/store-contracts/file-history-store-contract.js +43 -3
  257. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  258. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  259. package/dist/core/store-contracts/session-repo-contract.js +125 -0
  260. package/dist/core/store-contracts/session-store-contract.d.ts +4 -7
  261. package/dist/core/store-contracts/session-store-contract.js +215 -41
  262. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  263. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  264. package/dist/core/task-event.d.ts +10 -4
  265. package/dist/core/task-notification.d.ts +3 -3
  266. package/dist/core/task-registry-agent.d.ts +4 -4
  267. package/dist/core/task-registry-shared.d.ts +4 -4
  268. package/dist/core/task-registry-shared.js +1 -0
  269. package/dist/core/task-registry.d.ts +4 -4
  270. package/dist/core/task-registry.js +3 -1
  271. package/dist/core/task-result.d.ts +3 -3
  272. package/dist/core/task-spec.d.ts +52 -52
  273. package/dist/core/task-stream.d.ts +6 -6
  274. package/dist/core/task-tool-shape.d.ts +4 -4
  275. package/dist/core/tighten-task-spec.d.ts +1 -1
  276. package/dist/core/tool-catalog-entries.d.ts +19 -2
  277. package/dist/core/tool-catalog-entries.js +57 -42
  278. package/dist/core/tool-conformance.js +1 -0
  279. package/dist/core/tool-errors.d.ts +2 -2
  280. package/dist/core/tool-face-reader.js +5 -3
  281. package/dist/core/tool-face.d.ts +21 -2
  282. package/dist/core/tool-face.js +1 -1
  283. package/dist/core/tool-model-gate.d.ts +3 -3
  284. package/dist/core/tool-name-aliases.d.ts +29 -8
  285. package/dist/core/tool-name-aliases.js +27 -3
  286. package/dist/core/tool-name-readings.d.ts +5 -8
  287. package/dist/core/tool-name-readings.js +1 -2
  288. package/dist/core/tool-policy.d.ts +24 -5
  289. package/dist/core/tool-policy.js +34 -10
  290. package/dist/core/tool-registry.d.ts +14 -7
  291. package/dist/core/tool-registry.js +17 -7
  292. package/dist/core/tool-result-store.js +2 -1
  293. package/dist/core/tool-roster.d.ts +47 -18
  294. package/dist/core/tool-roster.js +53 -32
  295. package/dist/core/tool-spec-members.js +1 -1
  296. package/dist/core/tool-spec.d.ts +35 -21
  297. package/dist/core/tools.js +3 -2
  298. package/dist/core/trace.d.ts +4 -0
  299. package/dist/core/untrusted-egress.d.ts +1 -1
  300. package/dist/core/untrusted-text.d.ts +1 -1
  301. package/dist/core/warm-resume.d.ts +1 -1
  302. package/dist/core/wiring-manifest.d.ts +49 -0
  303. package/dist/core/wiring-manifest.js +13 -5
  304. package/dist/core/workflow-journal-store.d.ts +62 -0
  305. package/dist/core/workflow-journal-store.js +77 -1
  306. package/dist/core/workflow-run-store.d.ts +6 -0
  307. package/dist/core/workflow-run-store.js +2 -0
  308. package/dist/engine/compaction/compaction.d.ts +9 -9
  309. package/dist/engine/execution-env/node-execution-env.d.ts +19 -5
  310. package/dist/engine/execution-env/node-execution-env.js +43 -22
  311. package/dist/engine/harness/agent-harness.d.ts +14 -8
  312. package/dist/engine/harness/agent-harness.js +33 -26
  313. package/dist/engine/harness/types.d.ts +29 -7
  314. package/dist/engine/harness/types.js +12 -1
  315. package/dist/engine/llm/types.d.ts +9 -9
  316. package/dist/engine/llm/validation.d.ts +4 -1
  317. package/dist/engine/llm/validation.js +13 -1
  318. package/dist/engine/loop/agent-loop.d.ts +1 -1
  319. package/dist/engine/loop/agent-loop.js +10 -8
  320. package/dist/engine/loop/types.d.ts +15 -13
  321. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  322. package/dist/engine/session/memory-repo.d.ts +10 -11
  323. package/dist/engine/session/memory-repo.js +13 -8
  324. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  325. package/dist/engine/session/parent-chain-guard.js +1 -1
  326. package/dist/engine/session/repo-utils.d.ts +31 -3
  327. package/dist/engine/session/repo-utils.js +42 -5
  328. package/dist/index.d.ts +27 -15
  329. package/dist/index.js +21 -11
  330. package/dist/internal/harness-types.d.ts +1 -1
  331. package/dist/internal/harness.d.ts +3 -3
  332. package/dist/internal/harness.js +2 -2
  333. package/dist/internal/llm.d.ts +1 -1
  334. package/dist/internal/llm.js +1 -1
  335. package/dist/orchestration/goal.js +2 -2
  336. package/dist/orchestration/run-workflow-tool.d.ts +2 -2
  337. package/dist/orchestration/run-workflow-tool.js +5 -3
  338. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  339. package/dist/orchestration/workflow-types.d.ts +18 -0
  340. package/dist/orchestration/workflow-types.js +6 -0
  341. package/dist/orchestration/workflow.d.ts +2 -13
  342. package/dist/orchestration/workflow.js +21 -31
  343. package/dist/prompt-assembly/event-registry.js +1 -0
  344. package/dist/prompt-assembly/tool-catalog.d.ts +3 -0
  345. package/dist/prompt-assembly/tool-catalog.js +3 -0
  346. package/dist/prompts/default.d.ts +14 -14
  347. package/dist/scenarios/full-body.d.ts +4 -4
  348. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  349. package/dist/stores/file/adoption/adopt.js +24 -31
  350. package/dist/stores/file/adoption/marker.d.ts +6 -13
  351. package/dist/stores/file/adoption/marker.js +6 -15
  352. package/dist/stores/file/checkpoint-store.d.ts +3 -0
  353. package/dist/stores/file/checkpoint-store.js +9 -3
  354. package/dist/stores/file/file-history-store.d.ts +20 -19
  355. package/dist/stores/file/file-history-store.js +152 -135
  356. package/dist/stores/file/fs-atomic.d.ts +15 -0
  357. package/dist/stores/file/fs-atomic.js +89 -14
  358. package/dist/stores/file/index.d.ts +1 -1
  359. package/dist/stores/file/mailbox-store.d.ts +3 -0
  360. package/dist/stores/file/mailbox-store.js +3 -1
  361. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  362. package/dist/stores/file/permission-rule-adopt.js +15 -16
  363. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  364. package/dist/stores/file/permission-rule-store.js +21 -14
  365. package/dist/stores/file/session-policy-store.d.ts +3 -3
  366. package/dist/stores/file/session-store.d.ts +26 -11
  367. package/dist/stores/file/session-store.js +77 -40
  368. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  369. package/dist/stores/file/workflow-journal-store.js +28 -13
  370. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  371. package/dist/tools/artifact/artifact-tool.js +2 -1
  372. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  373. package/dist/tools/fs/fs-bash.d.ts +2 -2
  374. package/dist/tools/fs/fs-bash.js +3 -1
  375. package/dist/tools/fs/fs-shared.d.ts +8 -8
  376. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  377. package/dist/tools/fs/notebook.d.ts +2 -2
  378. package/dist/tools/fs/read-deny.d.ts +29 -7
  379. package/dist/tools/fs/read-deny.js +63 -22
  380. package/dist/tools/fs/removal-targets.d.ts +1 -1
  381. package/dist/tools/fs/safety.d.ts +9 -9
  382. package/dist/tools/fs/search.d.ts +6 -6
  383. package/dist/tools/fs/shell-read-check.js +6 -1
  384. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  385. package/dist/tools/fs/shell-read-judge.js +5 -2
  386. package/dist/tools/loop-tick.d.ts +2 -2
  387. package/dist/tools/scheduler-tools.js +5 -1
  388. package/dist/tools/task-list.d.ts +7 -7
  389. package/dist/tools/task-list.js +5 -1
  390. package/dist/tools/todo.js +2 -1
  391. package/dist/tools/web.d.ts +1 -1
  392. package/dist/tools/web.js +40 -37
  393. package/dist/tools/worktree.d.ts +3 -3
  394. package/dist/tools/worktree.js +3 -1
  395. package/package.json +1 -1
  396. package/test/export-surface.snapshot.json +5756 -5638
  397. package/wire-changes/core@7.55.0.json +3318 -0
  398. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  399. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { type AskClass, type AskOrigin, type AssertAllKeysHandled, type ModeReleaseReason, type PermissionMode, type PersistedRuleMandate } from "./ask-origin.js";
11
11
  import { type AutoModeClassifierRound, type AutoModeFallbackCause } from "./auto-mode.js";
12
+ import { type AllowRuleClearance } from "./allow-rule-shadow.js";
12
13
  /**
13
14
  * How the wait an ask was in ENDED — the closed set. One word per way a wait can end; the `who` on the
14
15
  * record says which party ended it and is fixed BY the word (see {@link Settlement}).
@@ -302,9 +303,9 @@ export type VetoTableCoversEveryDeniedBy = AssertAllKeysHandled<Exclude<DeniedBy
302
303
  * deny came through the classifier station. The classifier ends a round three ways, and until this
303
304
  * member the wire carried the three as one layer word plus prose:
304
305
  * - `unavailable` — the classifier could not run (the model leg threw / rejected / ran past the cap):
305
- * a fail-closed refusal that SAYS SO — the call may simply be retried later (CC 2.1.250 `x1t`);
306
+ * a fail-closed refusal that SAYS SO — the call may simply be retried later;
306
307
  * - `parse_error` — the classifier answered outside its verdict contract: blocked for safety, counted by
307
- * the denial limit like a ruling (CC 2.1.250 `Ure`);
308
+ * the denial limit like a ruling;
308
309
  * - ABSENT beside `deniedBy: "classifier"` — the classifier's own RULING (a `<block>yes` verdict).
309
310
  * The WHY behind an `unavailable` (error vs timeout) is not a branching fact: the deny sentence spells it
310
311
  * and the `auto_mode.classified` trace frame carries it (`cause: "error" | "timeout"`).
@@ -350,11 +351,19 @@ export type CauseTableCoversEveryDeniedBy = AssertAllKeysHandled<Exclude<DeniedB
350
351
  * candidate ladder and can name no model (a hand-built decider; a parked ancestor's cross-process rebuild,
351
352
  * whose single fresh leg has none); or one did not rule (it could not run, or replied with no verdict) and
352
353
  * handed the question to the approval seat, whose settlement then names the resolution that ask reached.
353
- * Additive. Invariant I6 ({@link screenGateOutcome}) screens its shape. */
354
+ * Additive. Invariant I6 ({@link screenGateOutcome}) screens its shape.
355
+ *
356
+ * `clearedBy` — the allow layer's account of a call it let run without asking: which member's allow rule cleared the ask
357
+ * (`hook` / `deployment` / `persisted` / `skill` / `request`) and the entries it stood on, sanitized and capped as a shadow
358
+ * record is, with `positions` for a list member (the indices of those entries in the list the run received — a host maps them
359
+ * onto the declaration it sent for this run). Present exactly when an allow member cleared a standing ask and nobody answered
360
+ * it: absent on a call nothing asked about, a mode's release or acceptance, the read-only arm's, the classifier's or the
361
+ * sandbox's allow, and a person's yes. Additive. Invariant I9 ({@link screenGateOutcome}) screens its shape. */
354
362
  export type GateDisposition = {
355
363
  kind: "allowed";
356
364
  classifier?: AutoModeClassifierRound;
357
365
  released?: ModeRelease;
366
+ clearedBy?: AllowRuleClearance;
358
367
  } | {
359
368
  kind: "denied";
360
369
  deniedBy: DeniedBy;
@@ -415,7 +424,11 @@ export interface ModeRefusal {
415
424
  * record outlives the policy of its day), every member of `classes` is an ask class, `origin` / `mandate` / `reason`,
416
425
  * when present, are members of their closed sets, and `reason` names a member of `classes` (the mint takes it from
417
426
  * that set) — a mode releases nothing a person answered;
418
- * I8 `deniedBy === "mode"` ⇔ `mode` present (`bypassPermissions` | `dontAsk`) with `askClass` and `classes`.
427
+ * I8 `deniedBy === "mode"` ⇔ `mode` present (`bypassPermissions` | `dontAsk`) with `askClass` and `classes`;
428
+ * I9 `disposition.clearedBy` present ⇒ `kind === "allowed"`, no settlement and no release (an allow member cleared the ask
429
+ * before anyone answered it), `member` one of the allow layer's members, `entries` a list of strings, `omitted` a positive
430
+ * whole number when present, and `positions` — only on a list member (`request`, `deployment`) — a list of non-negative
431
+ * whole numbers.
419
432
  * Nothing here is read out of an ABSENCE: an ordinary allow with no ask is `{ disposition: { kind: "allowed" } }`,
420
433
  * a direct policy deny is `{ disposition: { kind: "denied", deniedBy: "policy" } }`, and neither carries a
421
434
  * settlement because neither settled one.
@@ -1,5 +1,6 @@
1
1
  import { isAskClass, isAskOrigin, isModeReleaseReason, isPermissionMode, isPersistedRuleMandate, ASK_FACES, releasableAskClassesFor } from "./ask-origin.js";
2
2
  import { isAutoModeFallbackCause } from "./auto-mode.js";
3
+ import { ALLOW_RULE_MEMBERS } from "./allow-rule-shadow.js";
3
4
  export const SETTLEMENT_KINDS = Object.freeze([
4
5
  "human_allowed",
5
6
  "human_refused",
@@ -153,6 +154,31 @@ export function releasePolicyDefects(g) {
153
154
  const held = [askClass, ...classes];
154
155
  return ASK_FACES.some((face) => held.every((c) => releasableAskClassesFor(face).includes(c))) ? [] : [`I7: released.classes ${JSON.stringify(classes)} is not a set one face of this engine's table releases`];
155
156
  }
157
+ const LIST_MEMBERS = new Set(["request", "deployment"]);
158
+ const ALLOW_MEMBER_SET = new Set(ALLOW_RULE_MEMBERS);
159
+ function clearanceDefects(v, settled, released) {
160
+ const c = objectOf(v);
161
+ if (c === undefined)
162
+ return [`I9: disposition.clearedBy is not an object (${shapeOf(v)})`];
163
+ const out = [];
164
+ if (settled)
165
+ out.push("I9: a clearance carries no settlement — an allow rule cleared the ask before anyone answered it");
166
+ if (released)
167
+ out.push("I9: a clearance stands beside no mode release — the ask it cleared never reached the mode");
168
+ if (!ALLOW_MEMBER_SET.has(c.member))
169
+ out.push(`I9: clearedBy.member ${spelled(c.member)} is not one of the allow layer's members (${ALLOW_RULE_MEMBERS.join(", ")})`);
170
+ if (!Array.isArray(c.entries) || !c.entries.every((e) => typeof e === "string"))
171
+ out.push("I9: clearedBy.entries must be a list of strings");
172
+ if (c.omitted !== undefined && !(typeof c.omitted === "number" && Number.isInteger(c.omitted) && c.omitted > 0))
173
+ out.push(`I9: clearedBy.omitted ${spelled(c.omitted)} is not a positive whole number`);
174
+ if (c.positions !== undefined) {
175
+ if (!LIST_MEMBERS.has(c.member))
176
+ out.push(`I9: clearedBy.positions stands only on a list member (request, deployment), not ${spelled(c.member)}`);
177
+ if (!Array.isArray(c.positions) || !c.positions.every((p) => typeof p === "number" && Number.isInteger(p) && p >= 0))
178
+ out.push("I9: clearedBy.positions must be a list of non-negative whole numbers");
179
+ }
180
+ return out;
181
+ }
156
182
  const DENY_ONLY_MEMBERS = Object.freeze(["deniedBy", "cause", "mode", "askClass", "classes"]);
157
183
  function objectOf(v) {
158
184
  return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
@@ -252,6 +278,10 @@ export function screenGateOutcome(g, opts) {
252
278
  defects.push(`I7: released.reason "${String(r.reason)}" is not a member of released.classes`);
253
279
  }
254
280
  }
281
+ if (denied !== undefined && denied.clearedBy !== undefined)
282
+ defects.push("I9: disposition.clearedBy stands only on an allowed disposition");
283
+ if (d !== undefined && d.clearedBy !== undefined)
284
+ defects.push(...clearanceDefects(d.clearedBy, settled, d.released !== undefined));
255
285
  if (denied !== undefined) {
256
286
  const modeRefusal = denied.deniedBy === "mode";
257
287
  if (modeRefusal !== (denied.mode !== undefined))
@@ -1,7 +1,13 @@
1
1
  import type { AssertAllKeysHandled } from "./ask-origin.js";
2
- /** Retry class of a governance code: `transient` = a later retry can self-heal (control-plane
3
- * absence/outage); `terminal` = policy adjudicated, re-issuing changes nothing. */
2
+ /** The engine's one retry vocabulary, defined here and nowhere else — can repeating the same request succeed?
3
+ * `transient` = a later retry can succeed with nothing changed first (the cause clears by itself, with no stated
4
+ * horizon: a control plane briefly absent, contention, an interrupted call); `terminal` = repeating it changes
5
+ * nothing until something named changes first — a verdict (a policy, or a usage window until the `retryAfterMs` it
6
+ * states), the deployment, the store or the input. Governance codes and file-history faults answer in it. */
4
7
  export type GovernanceRetryClass = "transient" | "terminal";
8
+ /** Is `value` one of the two words — the one membership reading (keyed by the type: a word added there is a missing
9
+ * row here, at compile time). */
10
+ export declare function isGovernanceRetryClass(value: unknown): value is GovernanceRetryClass;
5
11
  /**
6
12
  * The closed governance-code registry. tsc forces every entry to a valid class; the gate test
7
13
  * forces the naming convention and pack-family completeness. Adding a code = one deliberate row.
@@ -139,7 +145,7 @@ export type NoticeAudience = "user" | "operator";
139
145
  * the union's catalog ({@link EngineNotice.code}). The groups below say only which family a row joins,
140
146
  * so the catalog is not written a second time here and the two cannot drift.
141
147
  */
142
- export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.read_deny_swapped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.path_view_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.credential_not_withheld", "config.cross_boundary_posture_undeclared", "config.cross_boundary_record_unwritten", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "config.session_rules_earlier_grammar", "permission.allowed_tool_not_granted", "mods.registration_refused", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.credential_origin_mismatch", "route.response_model_mismatch", "route.tool_call_id_folded", "route.finish_reason_unknown", "route.stream_end_ignored", "route.extra_body_reserved_dropped", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "tool_result.media_refused", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable", "permission.entry_mode_clamped"];
148
+ export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.read_deny_swapped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.path_view_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.credential_not_withheld", "config.cross_boundary_posture_undeclared", "config.cross_boundary_record_unwritten", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "config.session_rules_earlier_grammar", "permission.allowed_tool_not_granted", "mods.registration_refused", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.seat_detached", "advisor.not_attached", "route.credential_origin_mismatch", "route.response_model_mismatch", "route.tool_call_id_folded", "route.finish_reason_unknown", "route.stream_end_ignored", "route.extra_body_reserved_dropped", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "tool_result.media_refused", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable", "permission.entry_mode_clamped"];
143
149
  /** A catalogued code (see {@link ENGINE_NOTICE_CODES}); {@link NOTICE_MINTER} says who mints it. NOT the type of
144
150
  * `EngineNotice.code`, which stays `string` — a host forwarding its own notices through the same
145
151
  * sink is a supported shape, and narrowing that field would break it. */
@@ -242,6 +248,8 @@ declare const NOTICE_AUDIENCE_TABLE: {
242
248
  readonly "memory.project_scope_absent": "operator";
243
249
  readonly "route.fallback_to_primary": "operator";
244
250
  readonly "route.classifier_unroutable": "operator";
251
+ readonly "route.seat_detached": "operator";
252
+ readonly "advisor.not_attached": "user";
245
253
  readonly "route.response_model_mismatch": "operator";
246
254
  readonly "route.tool_call_id_folded": "operator";
247
255
  readonly "route.extra_body_reserved_dropped": "operator";
@@ -351,6 +359,8 @@ declare const NOTICE_MINTER_TABLE: {
351
359
  readonly "memory.project_scope_absent": "engine";
352
360
  readonly "route.fallback_to_primary": "engine";
353
361
  readonly "route.classifier_unroutable": "engine";
362
+ readonly "route.seat_detached": "engine";
363
+ readonly "advisor.not_attached": "engine";
354
364
  readonly "route.credential_origin_mismatch": "engine";
355
365
  readonly "route.response_model_mismatch": "engine";
356
366
  readonly "route.tool_call_id_folded": "engine";
@@ -1,3 +1,7 @@
1
+ const RETRY_CLASS_WORDS = Object.freeze({ transient: true, terminal: true });
2
+ export function isGovernanceRetryClass(value) {
3
+ return typeof value === "string" && Object.hasOwn(RETRY_CLASS_WORDS, value);
4
+ }
1
5
  export const GOVERNANCE_CODES = {
2
6
  "usage.window_exhausted": "terminal",
3
7
  "memory.admission_required": "transient",
@@ -189,6 +193,8 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
189
193
  "memory.project_scope_absent",
190
194
  "route.fallback_to_primary",
191
195
  "route.classifier_unroutable",
196
+ "route.seat_detached",
197
+ "advisor.not_attached",
192
198
  "route.credential_origin_mismatch",
193
199
  "route.response_model_mismatch",
194
200
  "route.tool_call_id_folded",
@@ -303,6 +309,8 @@ const NOTICE_AUDIENCE_TABLE = {
303
309
  "memory.project_scope_absent": "operator",
304
310
  "route.fallback_to_primary": "operator",
305
311
  "route.classifier_unroutable": "operator",
312
+ "route.seat_detached": "operator",
313
+ "advisor.not_attached": "user",
306
314
  "route.response_model_mismatch": "operator",
307
315
  "route.tool_call_id_folded": "operator",
308
316
  "route.extra_body_reserved_dropped": "operator",
@@ -393,6 +401,8 @@ const NOTICE_MINTER_TABLE = {
393
401
  "memory.project_scope_absent": "engine",
394
402
  "route.fallback_to_primary": "engine",
395
403
  "route.classifier_unroutable": "engine",
404
+ "route.seat_detached": "engine",
405
+ "advisor.not_attached": "engine",
396
406
  "route.credential_origin_mismatch": "engine",
397
407
  "route.response_model_mismatch": "engine",
398
408
  "route.tool_call_id_folded": "engine",
@@ -110,7 +110,7 @@ export interface HandsBandOptions {
110
110
  /** Deployment write gate — COMPOSED with (never replacing) the engine's MemoryEngine write-scan gate:
111
111
  * this hook judges first (a rejection short-circuits), the engine gate then still runs in full. */
112
112
  beforeWrite?: BeforeWriteHook;
113
- /** RB-198 F1 (CC 220 `Zry`/`WZi.#m` parity): on a foreground Bash command's OWN timeout, an eligible
113
+ /** RB-198 F1: on a foreground Bash command's OWN timeout, an eligible
114
114
  * command (see `canAutoBackground` — no `git` anywhere in the command, not a `sleep`-first-word wait) is
115
115
  * adopted as a background task instead of being killed — CC's own posture ("received no response for
116
116
  * Nms" would otherwise force a wasteful blind re-run of a non-idempotent long command). Default `false`
@@ -295,7 +295,7 @@ export interface StopHookResult {
295
295
  * more turn.
296
296
  *
297
297
  * **It DOES count toward the consecutive-block cap, and it never resets it.** This sentence used to
298
- * say the opposite ("the cap is driven by `block` alone", cited to CC 2.1.201), and it was wrong on
298
+ * say the opposite ("the cap is driven by `block` alone"), and it was wrong on
299
299
  * both halves. Re-read against CC: the `additionalContext` branch pushes into the SAME array as the
300
300
  * blocking-error branch, the loop counts that array's length against the cap, and CC never resets
301
301
  * mid-run. The engine was fixed to match; the sentence here was not, so the module that DEFINES this
@@ -971,7 +971,7 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
971
971
  */
972
972
  shellGated?: boolean;
973
973
  /**
974
- * design/276 (CC 2.1.233 P11 arm 4): true when the called tool is the peer-message verb — a message
974
+ * design/276 (P11 arm 4): true when the called tool is the peer-message verb — a message
975
975
  * to another agent (`SendMessage`). ENGINE-FILLED from the wire name at the caller, never a
976
976
  * configuration knob; a caller's same-named shadow tool is keyed too (for a tighten, over-asking is
977
977
  * the fail-safe direction). Under an armed {@link autoMode} the gate tightens a surviving `allow` to
@@ -1009,7 +1009,7 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
1009
1009
  */
1010
1010
  shellReadCheck?: import("../tools/fs/shell-read-check.js").ShellReadCheck;
1011
1011
  /**
1012
- * design/143 批2 (A, CC 2.1.207 auto mode): when present, a surviving `ask` is routed to the
1012
+ * design/143 批2 (A, auto mode): when present, a surviving `ask` is routed to the
1013
1013
  * small-model policy CLASSIFIER before any human/durable resolution:
1014
1014
  * - verdict `allow` → the ask resolves to allow (`decisionReason:"classifier"`) — no suspend, no onAsk;
1015
1015
  * - verdict `block` → deny (`decisionReason:"classifier"`, `source:"classifier"`; CC `automode-blocked`); `parse_error` too;
@@ -1033,7 +1033,7 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
1033
1033
  autoMode?: {
1034
1034
  decider: import("./auto-mode.js").AutoModeDecider;
1035
1035
  /**
1036
- * The per-run DENIAL-LIMIT tracker beside the decider (CC 2.1.250 `FO`/`Wie`; same owner,
1036
+ * The per-run DENIAL-LIMIT tracker beside the decider (same owner,
1037
1037
  * same lifetime). Absent ⇒ the pre-#548 chain byte for byte: every block is a deny, without bound.
1038
1038
  * Present ⇒ a block first counts, then judges; the block that reaches a bound becomes the fallback
1039
1039
  * ask (`requiresRealApproval: true` + `denialLimitFallback`), and a classifier allow or a person's
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The HOST vocabulary, one home for how a host is spelled and read:
3
+ * · {@link hostOfSpelling} — the RULE side: the host a `<Tool>(domain:<host>)` rule names;
4
+ * · {@link hostOfUrl} — the CALL side: the host a URL names, which every host-rule judge reads as the call's subject and the
5
+ * engine's fetch tool reads as the host it connects to (one reading, two readers);
6
+ * · {@link callHostTargetOf} — which argument of a call carries that URL: the host face's protective and declared readings.
7
+ * Both sides go through the URL parser (lower case, IDN in its ASCII form, a full-width dot folded, an IPv4 shorthand expanded)
8
+ * and read trailing dots off; a call's host that does not read back as itself through the rule side's reader names no host a rule
9
+ * can be judged on, so a rule and a call that name one host always name it in one spelling.
10
+ *
11
+ * Leaf module: it reads the catalog's host slots (the protective floor) and the name-reading seat, nothing else.
12
+ */
13
+ import { type ToolCallLike } from "./tool-registry.js";
14
+ /** The host a spelling names as the URL parser reads it (trailing dots read off), or undefined when the spelling is more or
15
+ * less than a host: empty, carrying whitespace or a separator a URL reads as something else, a port (a `:` outside an
16
+ * address's brackets), credentials, a path. */
17
+ export declare function hostOfSpelling(spelled: string): string | undefined;
18
+ /** Is this host (as {@link hostOfUrl} reads it) an address — the URL parser's IPv4 form or a bracketed IPv6? */
19
+ export declare function isAddressHost(host: string): boolean;
20
+ /** Why a URL names no host a rule can be judged on — the closed set the fetch tool maps to its own refusal sentences:
21
+ * not a string; not a URL; not http(s); credentials in it; a host that does not read back as itself once its trailing dots
22
+ * are read off (`https://2130706433../` — the parser keeps the name, the rule side reads `127.0.0.1`). */
23
+ export declare const HOST_UNREADABLE_REASONS: readonly ["not_text", "not_url", "not_http", "credentials", "unstable"];
24
+ export type HostUnreadableReason = (typeof HOST_UNREADABLE_REASONS)[number];
25
+ /** The host a URL names, or why it names none. */
26
+ export type HostReading = {
27
+ readonly host: string;
28
+ } | {
29
+ readonly unreadable: HostUnreadableReason;
30
+ };
31
+ /** The words a refusal states for each unreadable reason. */
32
+ export declare const HOST_UNREADABLE_SENTENCE: Readonly<Record<HostUnreadableReason, string>>;
33
+ /** THE call-side reading of a URL: the host it names (lower case, IDN in its ASCII form, trailing dots read off), or why it
34
+ * names none ({@link HostUnreadableReason}). */
35
+ export declare function hostOfUrl(value: unknown): HostReading;
36
+ /** Which reading a judge takes: `tighten` for a deny, an ask and the unreadable law; `grant` for an allow. */
37
+ export type HostReadingDirection = "tighten" | "grant";
38
+ /**
39
+ * The host a call reaches as every host-rule judge reads it — the rule policy's host lane, a person's stored rows, the entry
40
+ * lists, the approval card's offer — or undefined when the call has no URL slot in that direction:
41
+ * · `tighten` — the PROTECTIVE reading: the call face's own slot, else the catalog's slot under the first name the call
42
+ * answers to that declares one (a bare request, or a face that declares none). Borrowing a slot can only add a host to
43
+ * judge, so a deny or an ask keeps reaching a same-name tool;
44
+ * · `grant` — the DECLARED reading: the call face's own slot only. A tool that declares none (a caller's tool that merely took
45
+ * the fetch tool's name, a bare request) is not the tool the catalog describes, and no allow by host reaches it.
46
+ * The slot's value is read by {@link hostOfUrl}; a value that names no host answers `{ unreadable }`, and each judge's law
47
+ * says what that means for its direction.
48
+ */
49
+ export declare function callHostTargetOf(call: ToolCallLike, direction: HostReadingDirection): HostReading | undefined;
@@ -0,0 +1,59 @@
1
+ import { hostTargetOf } from "./tool-registry.js";
2
+ import { seatOf } from "./tool-name-readings.js";
3
+ export function hostOfSpelling(spelled) {
4
+ if (spelled === "" || /[\s/\\@?#%]/.test(spelled) || (spelled.includes(":") && !/^\[[^\]]+\]$/.test(spelled)))
5
+ return undefined;
6
+ let url;
7
+ try {
8
+ url = new URL(`https://${spelled}/`);
9
+ }
10
+ catch {
11
+ return undefined;
12
+ }
13
+ if (url.port !== "" || url.username !== "" || url.password !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "")
14
+ return undefined;
15
+ const host = url.hostname.replace(/\.+$/, "");
16
+ return host === "" ? undefined : host;
17
+ }
18
+ export function isAddressHost(host) {
19
+ return host.startsWith("[") || /^\d+\.\d+\.\d+\.\d+$/.test(host);
20
+ }
21
+ export const HOST_UNREADABLE_REASONS = Object.freeze(["not_text", "not_url", "not_http", "credentials", "unstable"]);
22
+ export const HOST_UNREADABLE_SENTENCE = Object.freeze({
23
+ not_text: "the URL argument is not a string",
24
+ not_url: "the URL does not parse",
25
+ not_http: "the URL is not http(s)",
26
+ credentials: "the URL carries credentials",
27
+ unstable: "the URL's host does not read back as one host",
28
+ });
29
+ export function hostOfUrl(value) {
30
+ if (typeof value !== "string")
31
+ return { unreadable: "not_text" };
32
+ let url;
33
+ try {
34
+ url = new URL(value);
35
+ }
36
+ catch {
37
+ return { unreadable: "not_url" };
38
+ }
39
+ if (url.protocol !== "http:" && url.protocol !== "https:")
40
+ return { unreadable: "not_http" };
41
+ if (url.username !== "" || url.password !== "")
42
+ return { unreadable: "credentials" };
43
+ const host = url.hostname.replace(/\.+$/, "");
44
+ return host !== "" && hostOfSpelling(host) === host ? { host } : { unreadable: "unstable" };
45
+ }
46
+ export function callHostTargetOf(call, direction) {
47
+ const slot = hostSlotOf(call, direction);
48
+ if (slot === undefined)
49
+ return undefined;
50
+ const args = call.args;
51
+ const own = typeof args === "object" && args !== null && !Array.isArray(args) && Object.hasOwn(args, slot.param);
52
+ return hostOfUrl(own ? args[slot.param] : undefined);
53
+ }
54
+ function hostSlotOf(call, direction) {
55
+ const declared = call.face?.hostTarget;
56
+ if (declared !== undefined || direction === "grant")
57
+ return declared;
58
+ return seatOf("floor.protectiveHostTarget", { get: hostTargetOf }, call)?.value;
59
+ }
@@ -7,7 +7,7 @@
7
7
  * `core/types.ts`) needed no changes on this car.
8
8
  */
9
9
  /**
10
- * design/116 W5-1 — the max base64 size of ONE inline image (5MB). Value = CC 2.1.187
10
+ * design/116 W5-1 — the max base64 size of ONE inline image (5MB). Value =
11
11
  * `API_IMAGE_MAX_BASE64_SIZE` (constants/apiLimits.ts:22, "5 * 1024 * 1024 // 5 MB" — the hard Anthropic API
12
12
  * limit on a base64 image block; CC resizes/compresses down to fit UNDER it, imageResizer.ts). An MCP server
13
13
  * returning a bigger image previously passed straight through = a context/API bomb.
@@ -83,7 +83,7 @@ export declare class LspDiagnosticsRegistry {
83
83
  * the map; a judgment that fails withholds them all). The run's drain already marked them delivered, so they do not come back. */
84
84
  export declare function withholdListedDiagnostics(files: LspFileDiagnostics[], withheldOf: (uris: readonly string[]) => Promise<ReadonlyMap<string, unknown>>): Promise<LspFileDiagnostics[]>;
85
85
  /**
86
- * CC 198 `formatDiagnosticsSummary` (198:320480-320499), verbatim shape:
86
+ * `formatDiagnosticsSummary` shape:
87
87
  * ```
88
88
  * {basename}:
89
89
  * {symbol} [Line {line+1}:{col+1}] {message}[ [{code}]][ ({source})]
@@ -96,16 +96,16 @@ export declare function withholdListedDiagnostics(files: LspFileDiagnostics[], w
96
96
  * repository. They land inside the `<new-diagnostics>` envelope, and (since this block is now
97
97
  * delivered inside a marked reminder shell) inside an authority-marked reminder too, so a diagnostic
98
98
  * message carrying `</new-diagnostics>` closed the envelope and placed server text at the top level
99
- * of engine-authored authority. CC 223 does not neutralize here either — a deliberate, disclosed
99
+ * of engine-authored authority. The reference does not neutralize here either — a deliberate, disclosed
100
100
  * hardening divergence: CC ships the same block inside the same reminder shell, so the hole exists on
101
101
  * both sides and only the fix is ours. Neutralization runs BEFORE the join, so the 4000-char cap
102
102
  * still bounds the FINAL text and can never cut inside a neutralized marker's own bytes.
103
103
  */
104
104
  export declare function formatDiagnosticsSummary(files: LspFileDiagnostics[]): string;
105
- /** CC 198 model-facing injection block (198:320500-320503), verbatim framing.
105
+ /** Model-facing injection block.
106
106
  *
107
107
  * DELIVERY (design/319 sibling work): the runner shells this block in a MARKED `<system-reminder>`
108
- * before steering it — CC 223 `case "diagnostics"` does the same (`ih([Vr({content: …})])` → the
108
+ * before steering it — the reference's `case "diagnostics"` does the same (`ih([Vr({content: …})])` → the
109
109
  * reminder wrap), and until that was matched this was the engine's only authority text reaching the
110
110
  * model as a bare block with no provenance mark at all. The block's own bytes are unchanged; the
111
111
  * shell is applied at the delivery site (runtask), not baked in here, so this exported renderer keeps
@@ -58,8 +58,8 @@ export interface LspSymbolInfo {
58
58
  * answered null/[] — today's behavior byte-for-byte, and what an external manager returning bare
59
59
  * `{kind:"none"}` keeps getting). The failure reasons exist because one literal "No results." used to cover
60
60
  * both real emptiness and every transport-level fault — a findReferences that TIMED OUT read as "no
61
- * references, safe to delete" (CC 2.1.220 keeps these apart: `Error performing ${operation}: ...` vs the
62
- * plain empty-result strings, (pretty220.js:474840, historical; not relocated in 250 — see cc-250 anchors)).
61
+ * references, safe to delete" (the reference keeps these apart: `Error performing ${operation}: ...` vs the
62
+ * plain empty-result strings).
63
63
  */
64
64
  export type LspNoneReason = "unsupported_operation" | "server_error" | "timeout" | "cancelled" | "server_terminated" | "no_call_hierarchy_item"
65
65
  /** HRD-LSP-7: the QUERIED file could not be read for the didOpen/didChange re-sync (deleted between the
@@ -246,7 +246,7 @@ export interface LspTransport {
246
246
  * gate (no read face) only; a gated read is the admitted held object's ({@link LspReadAdmission}). TOC = local fs; TOB =
247
247
  * the sandbox ExecutionEnv. */
248
248
  export type LspReadText = (filePath: string, signal?: AbortSignal) => Promise<string>;
249
- /** CC 2.1.220's LSP file cap (10MB — `File too large for LSP analysis`, (pretty220.js:474745, historical; not relocated in 250 — see cc-250 anchors)). Single-sourced
249
+ /** The LSP file cap (10MB — `File too large for LSP analysis`). Single-sourced
250
250
  * in core: the TOOL-layer check in {@link createLspTool} (the model-visible enforcement, CC-parity) and the
251
251
  * defense-in-depth throw in the engine's `defaultLspReadText` must agree on one number. */
252
252
  export declare const MAX_LSP_FILE_BYTES: number;
@@ -221,6 +221,10 @@ export interface MailboxStore {
221
221
  * (the in-memory reference); absent = undeclared (the CC inbox adapter). Read by
222
222
  * {@link mailboxCrossProcessMountVerdict}; any other value is a malformed declaration and refuses. */
223
223
  readonly crossProcessSafe?: boolean;
224
+ /** WHICH boxes this store serves, as an opaque word: two store objects with the same identity read and write
225
+ * the same boxes (one backing directory, one database), in whichever process they live. Absent = the store
226
+ * cannot say — and then no peer may assume that a box it appends to here is one another session drains. */
227
+ readonly identity?: string;
224
228
  /** Durably park one message. Refuses `"mailbox.recipient_tombstoned"` when the backend can see
225
229
  * that its recipient is in the deployment's pre-delete state (see the interface notes above). */
226
230
  append(scope: string, handle: string, msg: MailboxAppendMessage): Promise<number>;
@@ -18,6 +18,7 @@
18
18
  * answer to its questions belongs to the leg that is waiting on it.
19
19
  */
20
20
  import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
21
+ import { ConnectionListing, type LenientListedTool } from "./mcp-server-link.js";
21
22
  import type { McpServerSpec } from "./mcp-server-spec.js";
22
23
  /** The slice of a listed tool the SDK client caches per connection (its output validator, its task-support flags). */
23
24
  export interface McpToolMeta {
@@ -31,6 +32,8 @@ export type McpListingWriter = (tools: ReadonlyArray<McpToolMeta>, apply: (all:
31
32
  /** One leg's hold on a pooled connection. */
32
33
  export interface McpLease {
33
34
  readonly client: Client;
35
+ /** The connection's listing, one record shared by every holder (mcp-server-link.ts `ConnectionListing`). */
36
+ readonly listing: ConnectionListing<LenientListedTool>;
34
37
  /**
35
38
  * Open a `tools/list` round trip on the connection — call it BEFORE the request. The returned writer records the result twice over:
36
39
  * as the connection's metadata for each listed tool, at this listing's version (its place in the order listings were opened on the
@@ -65,13 +68,26 @@ export declare class McpConnectionPool {
65
68
  * Lease the connection for `key`, dialling it with `dial` when none is live. `fresh` replaces the pool's current connection with a new
66
69
  * dial (a re-dial): the connection it replaces lives on until its other holders release it. Resolves `undefined` once the pool is
67
70
  * closed — the caller dials for itself. A dial that rejects rejects every waiter of that dial, and the pool keeps nothing of it.
71
+ *
72
+ * `signal` is the CALLER's abort, and it is that caller's alone: it ends this caller's wait (rejecting with its reason) and leaves the dial
73
+ * to the legs still waiting on it. The dial belongs to the pool: it is given a stop of its own, fired when the last leg waiting on it has
74
+ * walked away, so a leg's abort neither holds nor cancels a dial another leg still needs.
68
75
  */
69
- acquire(key: string, dial: () => Promise<Client>, opts?: {
76
+ acquire(key: string, dial: (stop: AbortSignal) => Promise<Client>, opts?: {
70
77
  fresh?: boolean;
78
+ signal?: AbortSignal;
71
79
  }): Promise<McpLease | undefined>;
80
+ /**
81
+ * Wait for a dial as one of its legs; this leg's abort ends only this leg's wait. The last leg to walk away abandons the dial in the
82
+ * same step as its abort (see {@link abandon}) — the table holds only dials some leg still waits on, so a leg that asks next dials afresh
83
+ * instead of joining a stopped dial and failing with another leg's abort.
84
+ */
85
+ private waitOn;
86
+ /** A dial nobody waits on any more: out of the table and stopped, and — had it landed already — the connection nobody leased is let go, so such a dial leaves no connection behind. */
87
+ private abandon;
72
88
  /** Make the next lease of `key` dial a new connection. */
73
89
  detach(key: string): void;
74
- /** No lease is granted after this; the connections still held stay open until their holders release them. */
90
+ /** No lease is granted after this; the connections still held stay open until their holders release them — one nobody holds is closed now. */
75
91
  close(): void;
76
92
  /** How many connections the pool holds open right now (for the lifecycle pins). */
77
93
  get live(): number;
@@ -1,4 +1,5 @@
1
1
  import { canonicalize } from "./canonical-json.js";
2
+ import { ConnectionListing } from "./mcp-server-link.js";
2
3
  export class McpConnectionPool {
3
4
  entries = new Map();
4
5
  dialing = new Map();
@@ -17,25 +18,67 @@ export class McpConnectionPool {
17
18
  async acquire(key, dial, opts) {
18
19
  if (this.shut)
19
20
  return undefined;
21
+ opts?.signal?.throwIfAborted();
20
22
  if (opts?.fresh === true)
21
23
  this.detach(key);
22
24
  let entry = this.entries.get(key);
23
25
  if (entry === undefined || entry.closed) {
24
26
  let pending = this.dialing.get(key);
25
27
  if (pending === undefined) {
26
- const started = this.dialNew(key, this.generation.get(key) ?? 0, dial);
27
- pending = started;
28
- this.dialing.set(key, started);
28
+ const stop = new AbortController();
29
+ const started = this.dialNew(key, this.generation.get(key) ?? 0, () => dial(stop.signal));
30
+ const own = { promise: started, waiters: 0, stop };
31
+ pending = own;
32
+ this.dialing.set(key, own);
29
33
  const settled = () => {
30
- if (this.dialing.get(key) === started)
34
+ if (this.dialing.get(key) === own)
31
35
  this.dialing.delete(key);
32
36
  };
33
37
  void started.then(settled, settled);
34
38
  }
35
- entry = await pending;
39
+ entry = await this.waitOn(key, pending, opts?.signal);
36
40
  }
37
41
  return this.lease(entry);
38
42
  }
43
+ async waitOn(key, dial, signal) {
44
+ dial.waiters++;
45
+ let waiting = true;
46
+ const stopWaiting = () => {
47
+ if (waiting)
48
+ dial.waiters--;
49
+ waiting = false;
50
+ };
51
+ try {
52
+ if (signal === undefined)
53
+ return await dial.promise;
54
+ return await new Promise((resolve, reject) => {
55
+ const walkAway = () => {
56
+ stopWaiting();
57
+ if (dial.waiters === 0)
58
+ this.abandon(key, dial, signal.reason);
59
+ reject(signal.reason);
60
+ };
61
+ signal.addEventListener("abort", walkAway, { once: true });
62
+ dial.promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", walkAway));
63
+ });
64
+ }
65
+ finally {
66
+ stopWaiting();
67
+ }
68
+ }
69
+ abandon(key, dial, reason) {
70
+ if (this.dialing.get(key) === dial)
71
+ this.dialing.delete(key);
72
+ dial.stop.abort(reason);
73
+ dial.promise.then((entry) => {
74
+ if (entry.refs > 0 || entry.closed)
75
+ return;
76
+ entry.current = false;
77
+ if (this.entries.get(key) === entry)
78
+ this.entries.delete(key);
79
+ void entry.client.close().catch(() => undefined);
80
+ }, () => undefined);
81
+ }
39
82
  detach(key) {
40
83
  this.generation.set(key, (this.generation.get(key) ?? 0) + 1);
41
84
  const e = this.entries.get(key);
@@ -47,6 +90,9 @@ export class McpConnectionPool {
47
90
  }
48
91
  close() {
49
92
  this.shut = true;
93
+ for (const e of [...this.entries.values()])
94
+ if (e.refs === 0 && !e.closed)
95
+ void e.client.close().catch(() => undefined);
50
96
  }
51
97
  get live() {
52
98
  let n = 0;
@@ -57,7 +103,7 @@ export class McpConnectionPool {
57
103
  }
58
104
  async dialNew(key, generation, dial) {
59
105
  const client = await dial();
60
- const entry = { client, refs: 0, listeners: new Set(), holders: new Map(), meta: new Map(), nextVersion: 0, current: true, closed: false };
106
+ const entry = { client, listing: new ConnectionListing(), refs: 0, listeners: new Set(), holders: new Map(), meta: new Map(), nextVersion: 0, current: true, closed: false };
61
107
  client.onclose = () => {
62
108
  entry.closed = true;
63
109
  if (this.entries.get(key) === entry)
@@ -86,6 +132,7 @@ export class McpConnectionPool {
86
132
  };
87
133
  const lease = {
88
134
  client: entry.client,
135
+ listing: entry.listing,
89
136
  onClose: (fn) => {
90
137
  mine.add(fn);
91
138
  entry.listeners.add(fn);
@@ -120,14 +120,17 @@ export type McpExchangeOutcome = McpFailureKind | "completed";
120
120
  * mint of the record — no two sites can disagree about the word, about which words may carry
121
121
  * `errorCode`, or about what a completed exchange proves. */
122
122
  export declare function livenessOf(outcome: McpExchangeOutcome, observedAt: number): McpServerLiveness | undefined;
123
+ /** A request over an established connection; `session` when the request carried the session id the server issued at the handshake. */
124
+ export type McpRequestSite = {
125
+ phase: "request";
126
+ session?: true;
127
+ };
123
128
  /** Where the failure was judged: at the dial (connect + initial listing), where an errno on a stdio
124
129
  * transport is the child process failing to spawn, or on a request over an established connection. */
125
130
  export type McpFailureSite = {
126
131
  phase: "connect";
127
132
  transport: "stdio" | "http" | undefined;
128
- } | {
129
- phase: "request";
130
- };
133
+ } | McpRequestSite;
131
134
  /**
132
135
  * The one MCP failure record. Both fields are always present; `httpStatus` rides only with
133
136
  * `kind === "http_status"`.
@@ -213,4 +216,20 @@ export interface HttpTransportFailure {
213
216
  delivered: McpDelivered;
214
217
  httpStatus?: number;
215
218
  }
216
- export declare function describeHttpTransportFailure(err: unknown): HttpTransportFailure | undefined;
219
+ export declare function describeHttpTransportFailure(err: unknown, at?: McpRequestSite): HttpTransportFailure | undefined;
220
+ /**
221
+ * The one reading of a lost session: a request that carried the session id the server issued at the handshake (`at.session`) was
222
+ * answered 404 by the HTTP endpoint — the protocol's word for a session it no longer knows (a restart, a reaped session). It is the
223
+ * server's REPORT, not a proof that nothing ran: the call lane sends the request again once on a fresh session, and every face that
224
+ * renders the failure names it ({@link LOST_SESSION}), while its record stays the table's (`http_status`, `delivered: "unknown"`) — a
225
+ * server that executed the request and then answered 404 ran it. Read from the thrown value's structure and the site, never from the
226
+ * body's text. Nothing else qualifies: a 5xx, a timeout or a lost pipe leave the outcome unknown, a protocol error or a tool's own error
227
+ * means the server processed the call, a 400 is the protocol's word for a request that lacked its session header (a server that answers
228
+ * an unknown session 400 with words saying so is not read by its words), and a 404 on a connection that holds no session id is an
229
+ * endpoint answering, not a session ending.
230
+ */
231
+ export declare function sessionGone(err: unknown, at: McpFailureSite): boolean;
232
+ /** What every face says of a lost session ({@link sessionGone}). */
233
+ export declare const LOST_SESSION = "the server reported the session the request was sent on gone (its HTTP endpoint answered 404 to the session id it issued)";
234
+ /** A failure's text, with a lost session ({@link sessionGone}) named ahead of it — for a face that renders the failure as one line. */
235
+ export declare function namingLostSession(err: unknown, at: McpRequestSite, text: string): string;