@sema-agent/core 7.47.0 → 7.49.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 (431) hide show
  1. package/CHANGELOG.md +472 -0
  2. package/README.md +2 -2
  3. package/dist/agents/cascade.d.ts +2 -5
  4. package/dist/agents/child-failure.d.ts +20 -0
  5. package/dist/agents/child-failure.js +28 -0
  6. package/dist/agents/cross-session-ref.d.ts +11 -3
  7. package/dist/agents/cross-session-ref.js +6 -0
  8. package/dist/agents/cumulative-stats.d.ts +12 -15
  9. package/dist/agents/cumulative-stats.js +1 -1
  10. package/dist/agents/extra-tool-names.js +1 -1
  11. package/dist/agents/inherited-tool-pool.d.ts +17 -13
  12. package/dist/agents/inherited-tool-pool.js +4 -3
  13. package/dist/agents/peer-session-drain.d.ts +3 -2
  14. package/dist/agents/peer-session-drain.js +5 -4
  15. package/dist/agents/send-message-tool.js +2 -9
  16. package/dist/agents/subagent.d.ts +10 -29
  17. package/dist/agents/subagent.js +65 -53
  18. package/dist/agents/suspend-guard.d.ts +1 -1
  19. package/dist/agents/tool-filter.d.ts +76 -65
  20. package/dist/agents/tool-filter.js +122 -92
  21. package/dist/agents/verify.d.ts +4 -7
  22. package/dist/agents/verify.js +6 -7
  23. package/dist/bench/metrics.d.ts +1 -2
  24. package/dist/brain/anthropic.js +133 -79
  25. package/dist/brain/errors.d.ts +53 -6
  26. package/dist/brain/errors.js +22 -2
  27. package/dist/brain/input-too-long.d.ts +40 -19
  28. package/dist/brain/input-too-long.js +3 -16
  29. package/dist/brain/open-responses.js +19 -10
  30. package/dist/brain/openai.js +123 -32
  31. package/dist/brain/provider-dialect.d.ts +214 -0
  32. package/dist/brain/provider-dialect.js +186 -0
  33. package/dist/brain/request-params.d.ts +27 -8
  34. package/dist/brain/request-params.js +7 -12
  35. package/dist/brain/request-route.d.ts +84 -0
  36. package/dist/brain/request-route.js +41 -0
  37. package/dist/brain/retry.d.ts +8 -0
  38. package/dist/brain/retry.js +10 -4
  39. package/dist/brain/route-adjudicator.d.ts +7 -0
  40. package/dist/brain/route-adjudicator.js +5 -1
  41. package/dist/brain/status-sink.d.ts +20 -0
  42. package/dist/brain/status-sink.js +11 -0
  43. package/dist/brain/stream-engine.d.ts +52 -1
  44. package/dist/brain/stream-engine.js +81 -24
  45. package/dist/brain/stream-shared.d.ts +57 -11
  46. package/dist/brain/stream-shared.js +28 -2
  47. package/dist/core/a2a.d.ts +1 -0
  48. package/dist/core/agent-config-dir.js +3 -2
  49. package/dist/core/allow-entry.d.ts +21 -12
  50. package/dist/core/allow-entry.js +39 -32
  51. package/dist/core/arg-summary.d.ts +17 -24
  52. package/dist/core/arg-summary.js +169 -68
  53. package/dist/core/ask-origin.d.ts +42 -24
  54. package/dist/core/ask-origin.js +18 -13
  55. package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
  56. package/dist/core/auto-mode-prompt-assets.js +1 -1
  57. package/dist/core/auto-mode-prompt.d.ts +11 -1
  58. package/dist/core/auto-mode-prompt.js +13 -10
  59. package/dist/core/auto-mode-rebuild.d.ts +7 -0
  60. package/dist/core/auto-mode-rebuild.js +4 -1
  61. package/dist/core/canonical-json.d.ts +3 -0
  62. package/dist/core/canonical-json.js +2 -1
  63. package/dist/core/checkpoint-requirements.d.ts +892 -0
  64. package/dist/core/checkpoint-requirements.js +333 -0
  65. package/dist/core/checkpoint-store.d.ts +95 -66
  66. package/dist/core/checkpoint-store.js +14 -26
  67. package/dist/core/child-clamp-seats.d.ts +228 -69
  68. package/dist/core/child-clamp-seats.js +211 -17
  69. package/dist/core/classifier-unavailable-arm.d.ts +5 -1
  70. package/dist/core/classifier-unavailable-arm.js +3 -3
  71. package/dist/core/compliance.d.ts +3 -0
  72. package/dist/core/compliance.js +9 -4
  73. package/dist/core/credential-vocabulary.d.ts +140 -0
  74. package/dist/core/credential-vocabulary.js +131 -0
  75. package/dist/core/decision-receipt.js +1 -1
  76. package/dist/core/effective-path-target.d.ts +73 -16
  77. package/dist/core/effective-path-target.js +63 -33
  78. package/dist/core/engine-notice.d.ts +32 -7
  79. package/dist/core/file-history-store.js +2 -2
  80. package/dist/core/fs-write-gate-policy.d.ts +4 -0
  81. package/dist/core/fs-write-gate-policy.js +22 -5
  82. package/dist/core/gate-bounded-await.d.ts +28 -13
  83. package/dist/core/gate-bounded-await.js +41 -4
  84. package/dist/core/gate-fold.d.ts +1 -1
  85. package/dist/core/gate-fold.js +24 -25
  86. package/dist/core/gate-lanes.js +16 -15
  87. package/dist/core/gate-outcome.d.ts +20 -5
  88. package/dist/core/gate-outcome.js +5 -0
  89. package/dist/core/governance-codes.d.ts +11 -4
  90. package/dist/core/governance-codes.js +14 -3
  91. package/dist/core/hooks.d.ts +4 -0
  92. package/dist/core/locked-config.d.ts +8 -0
  93. package/dist/core/locked-config.js +14 -2
  94. package/dist/core/lsp.js +3 -5
  95. package/dist/core/mailbox-store.d.ts +3 -4
  96. package/dist/core/mcp-connection-pool.d.ts +75 -0
  97. package/dist/core/mcp-connection-pool.js +128 -0
  98. package/dist/core/mcp-failure.d.ts +2 -1
  99. package/dist/core/mcp-failure.js +13 -2
  100. package/dist/core/mcp-server-spec.d.ts +1 -1
  101. package/dist/core/mcp.d.ts +4 -0
  102. package/dist/core/mcp.js +70 -43
  103. package/dist/core/memory-engine/content-origin.js +2 -14
  104. package/dist/core/memory-engine/engine.d.ts +32 -22
  105. package/dist/core/memory-engine/engine.js +103 -55
  106. package/dist/core/memory-engine/file-backend.d.ts +13 -30
  107. package/dist/core/memory-engine/file-backend.js +37 -252
  108. package/dist/core/memory-engine/index.d.ts +1 -1
  109. package/dist/core/memory-engine/index.js +1 -1
  110. package/dist/core/memory-engine/layout.d.ts +139 -9
  111. package/dist/core/memory-engine/layout.js +350 -7
  112. package/dist/core/memory-engine/scope-contract.d.ts +10 -0
  113. package/dist/core/memory-engine/scope-contract.js +8 -0
  114. package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
  115. package/dist/core/memory-engine/session-incarnation.js +5 -2
  116. package/dist/core/memory-engine/types.d.ts +10 -1
  117. package/dist/core/memory.js +5 -17
  118. package/dist/core/model-seat.d.ts +4 -4
  119. package/dist/core/model-seat.js +1 -1
  120. package/dist/core/mounted-mcp.d.ts +57 -0
  121. package/dist/core/mounted-mcp.js +19 -0
  122. package/dist/core/namespaced-rule-name.d.ts +29 -0
  123. package/dist/core/namespaced-rule-name.js +52 -0
  124. package/dist/core/park-selfcheck.d.ts +1 -1
  125. package/dist/core/park-selfcheck.js +16 -6
  126. package/dist/core/path-guard-rows.d.ts +99 -0
  127. package/dist/core/path-guard-rows.js +45 -0
  128. package/dist/core/path-identity.d.ts +22 -16
  129. package/dist/core/path-identity.js +10 -10
  130. package/dist/core/path-rule-binding.d.ts +2 -1
  131. package/dist/core/path-rule-binding.js +3 -1
  132. package/dist/core/pause-registry.d.ts +16 -2
  133. package/dist/core/pause-registry.js +6 -0
  134. package/dist/core/permission-rule-consent.js +0 -7
  135. package/dist/core/permission-rule-model.d.ts +68 -24
  136. package/dist/core/permission-rule-model.js +105 -24
  137. package/dist/core/permission-rule-store.js +2 -2
  138. package/dist/core/permission-rules.d.ts +3 -30
  139. package/dist/core/permission-rules.js +4 -54
  140. package/dist/core/read-root-candidate.d.ts +1 -3
  141. package/dist/core/read-root-candidate.js +4 -15
  142. package/dist/core/real-approval.d.ts +4 -3
  143. package/dist/core/retired-keys.d.ts +13 -0
  144. package/dist/core/retired-keys.js +14 -0
  145. package/dist/core/roles.d.ts +2 -3
  146. package/dist/core/roles.js +15 -6
  147. package/dist/core/runner/assemble-result.d.ts +0 -7
  148. package/dist/core/runner/assemble-result.js +19 -31
  149. package/dist/core/runner/caller-roster.d.ts +78 -0
  150. package/dist/core/runner/caller-roster.js +219 -0
  151. package/dist/core/runner/checkpoint-scope.d.ts +16 -16
  152. package/dist/core/runner/checkpoint-scope.js +2 -2
  153. package/dist/core/runner/child-tree.js +2 -2
  154. package/dist/core/runner/contracts.d.ts +68 -35
  155. package/dist/core/runner/decide-continuation.d.ts +51 -3
  156. package/dist/core/runner/decide-continuation.js +76 -21
  157. package/dist/core/runner/denial-limit-arms.d.ts +17 -5
  158. package/dist/core/runner/denial-limit-arms.js +11 -9
  159. package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
  160. package/dist/core/runner/extra-body-dropped-seat.js +22 -0
  161. package/dist/core/runner/finish-reason-seat.d.ts +9 -0
  162. package/dist/core/runner/finish-reason-seat.js +40 -0
  163. package/dist/core/runner/gate-exit.d.ts +44 -32
  164. package/dist/core/runner/gate-exit.js +112 -25
  165. package/dist/core/runner/inherited-ask-grants.js +6 -4
  166. package/dist/core/runner/mcp-redial.d.ts +3 -3
  167. package/dist/core/runner/mcp-redial.js +3 -4
  168. package/dist/core/runner/park-commit.d.ts +1 -1
  169. package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
  170. package/dist/core/runner/permission-rule-lanes.js +5 -4
  171. package/dist/core/runner/prepare-artifact.d.ts +4 -0
  172. package/dist/core/runner/prepare-artifact.js +2 -1
  173. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  174. package/dist/core/runner/prepare-ask-lane.js +12 -6
  175. package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
  176. package/dist/core/runner/prepare-boundary-parks.js +4 -7
  177. package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
  178. package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
  179. package/dist/core/runner/prepare-config-doors.d.ts +9 -9
  180. package/dist/core/runner/prepare-config-doors.js +10 -5
  181. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  182. package/dist/core/runner/prepare-defer-classify.js +5 -3
  183. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  184. package/dist/core/runner/prepare-delegation-surface.js +3 -3
  185. package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
  186. package/dist/core/runner/prepare-gate-stations.js +9 -7
  187. package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
  188. package/dist/core/runner/prepare-hands-readface.js +7 -7
  189. package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
  190. package/dist/core/runner/prepare-inherited-gate.js +14 -15
  191. package/dist/core/runner/prepare-listings.d.ts +7 -24
  192. package/dist/core/runner/prepare-listings.js +4 -5
  193. package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
  194. package/dist/core/runner/prepare-memory-engine-session.js +4 -3
  195. package/dist/core/runner/prepare-memory.d.ts +6 -0
  196. package/dist/core/runner/prepare-memory.js +13 -13
  197. package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
  198. package/dist/core/runner/prepare-offload-wrappers.js +3 -3
  199. package/dist/core/runner/prepare-park-ask.d.ts +7 -8
  200. package/dist/core/runner/prepare-park-ask.js +17 -10
  201. package/dist/core/runner/prepare-policy-chain.js +24 -44
  202. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  203. package/dist/core/runner/prepare-project-context.js +3 -4
  204. package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
  205. package/dist/core/runner/prepare-protocol-tools.js +3 -4
  206. package/dist/core/runner/prepare-run-refs.d.ts +3 -0
  207. package/dist/core/runner/prepare-run-refs.js +2 -1
  208. package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
  209. package/dist/core/runner/prepare-safety-scan.js +1 -2
  210. package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
  211. package/dist/core/runner/prepare-suspend-saga.js +28 -12
  212. package/dist/core/runner/prepare-task.d.ts +1 -1
  213. package/dist/core/runner/prepare-task.js +67 -56
  214. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
  215. package/dist/core/runner/prepare-wiring-manifest.js +5 -8
  216. package/dist/core/runner/resume-apply.js +7 -14
  217. package/dist/core/runner/resume-checkpoint-screen.js +11 -4
  218. package/dist/core/runner/resume-internals-and-config.js +2 -2
  219. package/dist/core/runner/resume-policy-outcome.js +5 -32
  220. package/dist/core/runner/resume-review-outcome.js +4 -1
  221. package/dist/core/runner/retired-runner-deps.d.ts +6 -0
  222. package/dist/core/runner/retired-runner-deps.js +10 -1
  223. package/dist/core/runner/run-brain-sinks.d.ts +4 -0
  224. package/dist/core/runner/run-brain-sinks.js +5 -2
  225. package/dist/core/runner/run-harness-handlers.js +27 -34
  226. package/dist/core/runner/run-leg.d.ts +0 -2
  227. package/dist/core/runner/run-leg.js +32 -33
  228. package/dist/core/runner/run-terminal-adoption.js +4 -3
  229. package/dist/core/runner/runtask.js +8 -8
  230. package/dist/core/runner/session-rule-policy.js +5 -5
  231. package/dist/core/runner/stream-settle-backstop.js +7 -4
  232. package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
  233. package/dist/core/runner/sub-agent-deny-lists.js +111 -80
  234. package/dist/core/runner/terminal-account.d.ts +48 -0
  235. package/dist/core/runner/terminal-account.js +186 -0
  236. package/dist/core/runner/tool-end-body.d.ts +54 -17
  237. package/dist/core/runner/tool-end-body.js +27 -2
  238. package/dist/core/runner/tool-face-overlay.d.ts +3 -1
  239. package/dist/core/runner/tool-face-overlay.js +6 -4
  240. package/dist/core/runner/tool-occurrence.d.ts +106 -0
  241. package/dist/core/runner/tool-occurrence.js +123 -0
  242. package/dist/core/runner/tool-progress-lane.d.ts +16 -8
  243. package/dist/core/runner/tool-progress-lane.js +25 -34
  244. package/dist/core/runner/turn-attachments.d.ts +1 -1
  245. package/dist/core/runner/write-protection-station.d.ts +21 -9
  246. package/dist/core/runner/write-protection-station.js +20 -17
  247. package/dist/core/runner-deps.d.ts +12 -22
  248. package/dist/core/safety-axis-vocab.d.ts +1 -1
  249. package/dist/core/safety-merge-corpus.d.ts +1 -1
  250. package/dist/core/secret-env.d.ts +16 -5
  251. package/dist/core/secret-env.js +23 -63
  252. package/dist/core/sensitive-path-policy.d.ts +19 -18
  253. package/dist/core/sensitive-path-policy.js +73 -49
  254. package/dist/core/session-policy-store.d.ts +6 -3
  255. package/dist/core/session-policy-store.js +28 -10
  256. package/dist/core/session-reconcile.d.ts +3 -0
  257. package/dist/core/session-reconcile.js +5 -4
  258. package/dist/core/session-store.d.ts +5 -0
  259. package/dist/core/session-store.js +12 -0
  260. package/dist/core/session.d.ts +13 -0
  261. package/dist/core/shared-memory/normalize.d.ts +17 -4
  262. package/dist/core/shared-memory/normalize.js +7 -7
  263. package/dist/core/shell-lexer.js +5 -4
  264. package/dist/core/shell-wrapper-table.d.ts +2 -2
  265. package/dist/core/shell-wrapper-table.js +1 -1
  266. package/dist/core/skill-grant.js +1 -1
  267. package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
  268. package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
  269. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
  270. package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
  271. package/dist/core/stub-env.d.ts +2 -0
  272. package/dist/core/stub-env.js +1 -0
  273. package/dist/core/synthetic-read-verdict.js +2 -2
  274. package/dist/core/task-event.d.ts +59 -5
  275. package/dist/core/task-result.d.ts +1 -1
  276. package/dist/core/task-spec.d.ts +42 -9
  277. package/dist/core/terminal-cause.d.ts +94 -11
  278. package/dist/core/tighten-task-spec.d.ts +5 -4
  279. package/dist/core/tighten-task-spec.js +20 -25
  280. package/dist/core/tool-catalog-entries.d.ts +5 -7
  281. package/dist/core/tool-catalog-entries.js +14 -15
  282. package/dist/core/tool-face.d.ts +47 -0
  283. package/dist/core/tool-face.js +5 -0
  284. package/dist/core/tool-model-gate.d.ts +5 -5
  285. package/dist/core/tool-name-aliases.d.ts +35 -10
  286. package/dist/core/tool-name-aliases.js +15 -0
  287. package/dist/core/tool-name-list.d.ts +30 -0
  288. package/dist/core/tool-name-list.js +55 -0
  289. package/dist/core/tool-name-readings.d.ts +1 -9
  290. package/dist/core/tool-name-readings.js +1 -3
  291. package/dist/core/tool-policy.d.ts +195 -85
  292. package/dist/core/tool-policy.js +165 -381
  293. package/dist/core/tool-registry.d.ts +44 -1
  294. package/dist/core/tool-registry.js +26 -0
  295. package/dist/core/tool-roster.d.ts +19 -1
  296. package/dist/core/tool-roster.js +21 -2
  297. package/dist/core/tool-spec-members.d.ts +45 -0
  298. package/dist/core/tool-spec-members.js +169 -0
  299. package/dist/core/tool-spec.d.ts +46 -8
  300. package/dist/core/tools.d.ts +6 -2
  301. package/dist/core/tools.js +8 -4
  302. package/dist/core/untrusted-egress.js +29 -26
  303. package/dist/core/untrusted-text.d.ts +13 -10
  304. package/dist/core/untrusted-text.js +6 -44
  305. package/dist/core/workflow-journal-store.d.ts +4 -1
  306. package/dist/core/write-protect.d.ts +65 -29
  307. package/dist/core/write-protect.js +235 -177
  308. package/dist/engine/compaction/compaction.d.ts +2 -2
  309. package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
  310. package/dist/engine/execution-env/node-execution-env.js +16 -38
  311. package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
  312. package/dist/engine/execution-env/symlink-chain.js +32 -0
  313. package/dist/engine/harness/types.d.ts +7 -0
  314. package/dist/engine/llm/tool-turns.d.ts +3 -0
  315. package/dist/engine/llm/tool-turns.js +1 -0
  316. package/dist/engine/llm/types.d.ts +59 -23
  317. package/dist/engine/loop/agent-loop.js +16 -2
  318. package/dist/engine/session/memory-repo.js +11 -3
  319. package/dist/engine/session/repo-utils.d.ts +8 -0
  320. package/dist/engine/session/repo-utils.js +13 -0
  321. package/dist/index.d.ts +20 -23
  322. package/dist/index.js +17 -20
  323. package/dist/internal/harness.d.ts +1 -1
  324. package/dist/internal/harness.js +1 -1
  325. package/dist/internal/llm.d.ts +2 -2
  326. package/dist/internal/llm.js +1 -1
  327. package/dist/orchestration/governance-baseline-validity.js +1 -1
  328. package/dist/orchestration/run-spec.js +3 -3
  329. package/dist/orchestration/run-workflow-tool.d.ts +16 -35
  330. package/dist/orchestration/run-workflow-tool.js +38 -78
  331. package/dist/orchestration/workflow-governance.d.ts +21 -25
  332. package/dist/orchestration/workflow-governance.js +38 -78
  333. package/dist/orchestration/workflow-primitives.d.ts +7 -22
  334. package/dist/orchestration/workflow-primitives.js +5 -12
  335. package/dist/orchestration/workflow-types.d.ts +1 -1
  336. package/dist/orchestration/workflow.d.ts +61 -11
  337. package/dist/orchestration/workflow.js +191 -119
  338. package/dist/prompt-assembly/types.d.ts +1 -1
  339. package/dist/scenarios/full-body.d.ts +1 -1
  340. package/dist/shell/lex.d.ts +0 -21
  341. package/dist/shell/lex.js +278 -70
  342. package/dist/shell/shell-words.d.ts +35 -0
  343. package/dist/shell/shell-words.js +65 -0
  344. package/dist/stores/file/checkpoint-store.d.ts +5 -5
  345. package/dist/stores/file/checkpoint-store.js +5 -2
  346. package/dist/stores/file/index.d.ts +0 -8
  347. package/dist/stores/file/index.js +0 -12
  348. package/dist/stores/file/session-store.d.ts +3 -0
  349. package/dist/stores/file/session-store.js +44 -19
  350. package/dist/tools/artifact/artifact-tool.js +2 -0
  351. package/dist/tools/fs/bash-program-position.d.ts +17 -3
  352. package/dist/tools/fs/bash-program-position.js +25 -10
  353. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  354. package/dist/tools/fs/bash-readonly-classifier.js +8 -7
  355. package/dist/tools/fs/containment-face.d.ts +4 -0
  356. package/dist/tools/fs/containment-face.js +3 -0
  357. package/dist/tools/fs/fs-shared.d.ts +10 -0
  358. package/dist/tools/fs/fs-shared.js +18 -0
  359. package/dist/tools/fs/fs-write.js +4 -2
  360. package/dist/tools/fs/index.d.ts +3 -2
  361. package/dist/tools/fs/index.js +2 -2
  362. package/dist/tools/fs/program-read-model.d.ts +99 -23
  363. package/dist/tools/fs/program-read-model.js +129 -55
  364. package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
  365. package/dist/tools/fs/program-read-model.rows.js +18 -10
  366. package/dist/tools/fs/read-deny-home.d.ts +35 -30
  367. package/dist/tools/fs/read-deny-home.js +45 -38
  368. package/dist/tools/fs/read-deny.d.ts +35 -27
  369. package/dist/tools/fs/read-deny.js +126 -92
  370. package/dist/tools/fs/removal-targets.d.ts +56 -23
  371. package/dist/tools/fs/removal-targets.js +74 -87
  372. package/dist/tools/fs/safety.d.ts +29 -22
  373. package/dist/tools/fs/safety.js +17 -11
  374. package/dist/tools/fs/search.js +10 -8
  375. package/dist/tools/fs/shell-read-argv.d.ts +4 -7
  376. package/dist/tools/fs/shell-read-argv.js +6 -8
  377. package/dist/tools/fs/shell-read-bindings.d.ts +203 -46
  378. package/dist/tools/fs/shell-read-bindings.js +488 -144
  379. package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
  380. package/dist/tools/fs/shell-read-builtins.js +43 -0
  381. package/dist/tools/fs/shell-read-check.d.ts +15 -1
  382. package/dist/tools/fs/shell-read-check.js +51 -42
  383. package/dist/tools/fs/shell-read-establish.js +9 -10
  384. package/dist/tools/fs/shell-read-functions.d.ts +22 -0
  385. package/dist/tools/fs/shell-read-functions.js +29 -0
  386. package/dist/tools/fs/shell-read-judge.d.ts +48 -18
  387. package/dist/tools/fs/shell-read-judge.js +33 -4
  388. package/dist/tools/fs/shell-read-plan.d.ts +13 -20
  389. package/dist/tools/fs/shell-read-plan.js +200 -194
  390. package/dist/tools/fs/shell-read-start.d.ts +80 -0
  391. package/dist/tools/fs/shell-read-start.js +99 -0
  392. package/dist/tools/fs/shell-read-word.d.ts +35 -6
  393. package/dist/tools/fs/shell-read-word.js +89 -9
  394. package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
  395. package/dist/tools/fs/shell-read-workdir.js +281 -0
  396. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
  397. package/dist/tools/fs/shell-read-write-targets.js +14 -5
  398. package/dist/tools/fs/shell-reentry-text.d.ts +26 -26
  399. package/dist/tools/fs/shell-reentry-text.js +31 -34
  400. package/dist/tools/task-list.d.ts +1 -2
  401. package/dist/tools/web.js +1 -1
  402. package/package.json +4 -1
  403. package/test/export-surface.snapshot.json +107 -143
  404. package/wire-changes/core@7.48.0.json +252 -0
  405. package/wire-changes/core@7.49.0.json +4765 -0
  406. package/dist/agents/teacher.d.ts +0 -159
  407. package/dist/agents/teacher.js +0 -577
  408. package/dist/agents/team.d.ts +0 -226
  409. package/dist/agents/team.js +0 -257
  410. package/dist/core/strategy-store.d.ts +0 -238
  411. package/dist/core/strategy-store.js +0 -253
  412. package/dist/orchestration/builtin-workflows.d.ts +0 -133
  413. package/dist/orchestration/builtin-workflows.js +0 -159
  414. package/dist/scenarios/env.d.ts +0 -40
  415. package/dist/scenarios/env.js +0 -39
  416. package/dist/scenarios/scenario-registry.d.ts +0 -110
  417. package/dist/scenarios/scenario-registry.js +0 -140
  418. package/dist/scenarios/teacher-quickstart.d.ts +0 -40
  419. package/dist/scenarios/teacher-quickstart.js +0 -12
  420. package/dist/stores/cc/lockfile.d.ts +0 -10
  421. package/dist/stores/cc/lockfile.js +0 -98
  422. package/dist/stores/cc/mailbox-store.d.ts +0 -20
  423. package/dist/stores/cc/mailbox-store.js +0 -255
  424. package/dist/stores/cc/roster-adapter.d.ts +0 -12
  425. package/dist/stores/cc/roster-adapter.js +0 -117
  426. package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
  427. package/dist/stores/cc/sidecar-transcript.js +0 -264
  428. package/dist/stores/cc/task-list-store.d.ts +0 -2
  429. package/dist/stores/cc/task-list-store.js +0 -125
  430. package/dist/stores/file/strategy-store.d.ts +0 -97
  431. package/dist/stores/file/strategy-store.js +0 -341
@@ -1,11 +1,13 @@
1
- import { canonicalizeTarget, isAbsoluteForFamily, joinForFamily, pathFamilyOf, pathIdentityOf, spellingOfIdentity, win32NamespaceScreen } from "../tools/fs/safety.js";
1
+ import { anchorSpelling, canonicalizeTarget, familyFor, hasWin32AliasedComponent, isAbsoluteForFamily, normalizeAbsPathLexically, pathFamilyOf, pathIdentityOf, spellingOfIdentity, win32NamespaceScreen } from "../tools/fs/safety.js";
2
2
  import { declaredPathTargetOf, pathTargetValue, protectivePathTargetOf } from "./tool-registry.js";
3
3
  import { symlinkChainHops } from "./path-identity.js";
4
4
  import { DEFAULT_GATE_AWAIT_TIMEOUT_MS, withGateTimeout } from "./gate-bounded-await.js";
5
+ import { thrownText } from "./thrown-value.js";
5
6
  export function pathTargetBaseOf(pt, bases) {
6
7
  return (pt?.base ?? "cwd") === "root" ? bases.root : (bases.cwd ?? bases.root);
7
8
  }
8
- export function splitAbsoluteGlobPattern(pattern, family) {
9
+ export function splitAbsoluteGlobPattern(pattern, tree) {
10
+ const family = tree ?? familyFor("own", pattern);
9
11
  const screened = win32NamespaceScreen(pattern, family);
10
12
  if (!screened.ok)
11
13
  return { refused: screened.refuse };
@@ -31,10 +33,8 @@ export function effectivePathTargetOf(call, pt, bases) {
31
33
  if ("refused" in spelling)
32
34
  return { kind: "refused", reason: spelling.refused };
33
35
  if (spelling.spelled !== undefined)
34
- return resolveSpelling(spelling.spelled, spelling.base, bases);
35
- const declaredBase = spelling.base;
36
- const family = pathFamilyOf(bases);
37
- return declaredBase !== undefined && isAbsoluteForFamily(family, declaredBase) ? readingOf(pathIdentityOf(declaredBase, family, bases.root ?? bases.cwd)) : unreadableBase(declaredBase);
36
+ return placeSpelling(spelling.spelled, spelling.base, bases);
37
+ return spelling.base !== undefined && isAbsoluteForFamily(readingFamilyOf(bases, spelling.base), spelling.base) ? placeSpelling(spelling.base, undefined, bases) : unreadableBase(spelling.base);
38
38
  }
39
39
  export function effectivePathSpellingOf(call, pt, bases) {
40
40
  if (pt === undefined)
@@ -55,36 +55,58 @@ export function effectivePathSpellingOf(call, pt, bases) {
55
55
  }
56
56
  return { base: declaredBase };
57
57
  }
58
- function resolveSpelling(spelled, declaredBase, bases) {
59
- const family = pathFamilyOf(bases);
58
+ export function placeSpelling(spelled, declaredBase, bases) {
59
+ const family = readingFamilyOf(bases, spelled);
60
60
  const screened = win32NamespaceScreen(spelled, family);
61
61
  if (!screened.ok)
62
62
  return { kind: "refused", reason: screened.refuse };
63
63
  const tree = bases.root ?? bases.cwd;
64
64
  if (isAbsoluteForFamily(family, screened.spelled))
65
- return readingOf(pathIdentityOf(screened.spelled, family, tree));
66
- if (declaredBase === undefined || family === undefined || !isAbsoluteForFamily(family, declaredBase))
65
+ return readingOf(pathIdentityOf(screened.spelled, family, tree), family);
66
+ if (declaredBase === undefined || !isAbsoluteForFamily(family, declaredBase))
67
67
  return unreadableBase(declaredBase);
68
- return readingOf(pathIdentityOf(joinForFamily(family, declaredBase, screened.spelled), family, tree));
68
+ return readingOf(pathIdentityOf(anchorSpelling(family, declaredBase, screened.spelled), family, tree), family);
69
+ }
70
+ export function readingFamilyOf(bases, spelled) {
71
+ return pathFamilyOf(bases) ?? familyFor("own", spelled);
69
72
  }
70
- function readingOf(r) {
73
+ function readingOf(r, family) {
71
74
  if (r.ok)
72
- return { kind: "path", identity: r.identity };
75
+ return { kind: "path", identity: r.identity, family };
73
76
  return r.reason === "relative" || r.reason === "unanchored" ? undefined : { kind: "refused", reason: r.reason };
74
77
  }
75
78
  function unreadableBase(base) {
76
79
  return { kind: "unreadable", reason: base === undefined ? "the call's path is relative to a base that was not supplied" : `the base this call resolves against (${JSON.stringify(base)}) is not a fully-qualified path of this tree's family` };
77
80
  }
78
- export async function readPathViews(env, spelled, base, bases, signal, opts) {
79
- const lexical = resolveSpelling(spelled, base, bases);
81
+ export const READ_ROOT_CANDIDATE_DIR_MAX = 1024;
82
+ export function validatePath(value, contract) {
83
+ if (typeof value !== "string" || !isAbsoluteForFamily("own", value))
84
+ return undefined;
85
+ if (contract.intent === "validate-coordinate")
86
+ return value;
87
+ if (value.length > READ_ROOT_CANDIDATE_DIR_MAX)
88
+ return undefined;
89
+ if (/[\u0000-\u001f\u007f\u2028\u2029]/.test(value))
90
+ return undefined;
91
+ const folded = normalizeAbsPathLexically(value);
92
+ if (folded !== value || normalizeAbsPathLexically(`${value}/..`) === value)
93
+ return undefined;
94
+ if (hasWin32AliasedComponent(value))
95
+ return undefined;
96
+ return win32NamespaceScreen(value, familyFor("own", value)).ok ? value : undefined;
97
+ }
98
+ export async function readPath(env, spelled, base, bases, contract, signal) {
99
+ const lexical = placeSpelling(spelled, base, bases);
80
100
  const family = pathFamilyOf(bases);
81
- if (env === undefined || family === undefined || lexical?.kind === "unreadable")
101
+ if (contract.views === "lexical" || env === undefined || family === undefined || lexical?.kind === "unreadable")
82
102
  return { lexical, hops: [] };
83
103
  const canonical = await canonicalizeTarget(env, spelled, signal, family, base);
84
104
  const climbs = (s) => s !== undefined && (family === "win" ? /(^|[\\/])\.\.([\\/]|$)/ : /(^|\/)\.\.(\/|$)/).test(s);
85
105
  const followsALink = canonical.ok && (climbs(spelled) || climbs(base) || lexical?.kind !== "path" || absoluteTargetIdentityOf(canonical.key, bases) !== lexical.identity);
86
- const hops = opts?.hops === true && followsALink ? await withGateTimeout(symlinkChainHops(env, spelled, signal, family, base), DEFAULT_GATE_AWAIT_TIMEOUT_MS, signal, "canonicalChain").catch(() => []) : [];
87
- return { lexical, canonical, hops };
106
+ const chain = contract.views === "chain" && followsALink
107
+ ? await withGateTimeout(symlinkChainHops(env, spelled, signal, family, base), DEFAULT_GATE_AWAIT_TIMEOUT_MS, signal, "canonicalChain").catch((err) => ({ ok: false, cause: thrownText(err), asked: true }))
108
+ : { ok: true, hops: [] };
109
+ return chain.ok ? { lexical, canonical, hops: chain.hops } : { lexical, canonical, hops: [], hopsUnread: true };
88
110
  }
89
111
  export function absoluteTargetIdentityOf(spelled, bases) {
90
112
  const r = pathIdentityOf(spelled, pathFamilyOf(bases), bases.root ?? bases.cwd);
@@ -94,7 +116,6 @@ const READ_FOR = new WeakMap();
94
116
  const REREAD = new WeakMap();
95
117
  export async function readCallTarget(env, call, signal, leads) {
96
118
  const bases = { ...(call.root !== undefined ? { root: call.root } : {}), ...(call.cwd !== undefined ? { cwd: call.cwd } : {}) };
97
- const family = pathFamilyOf(bases);
98
119
  const views = new Map();
99
120
  const viewOf = (pt) => {
100
121
  const sel = effectivePathSpellingOf(call, pt, bases);
@@ -102,7 +123,7 @@ export async function readCallTarget(env, call, signal, leads) {
102
123
  return Promise.resolve(undefined);
103
124
  if ("refused" in sel)
104
125
  return Promise.resolve({ kind: "refused", reason: sel.refused });
105
- const target = sel.spelled !== undefined ? { spelled: sel.spelled, base: sel.base } : sel.base !== undefined && isAbsoluteForFamily(family, sel.base) ? { spelled: sel.base, base: undefined } : undefined;
126
+ const target = sel.spelled !== undefined ? { spelled: sel.spelled, base: sel.base } : sel.base !== undefined && isAbsoluteForFamily(readingFamilyOf(bases, sel.base), sel.base) ? { spelled: sel.base, base: undefined } : undefined;
106
127
  if (target === undefined)
107
128
  return Promise.resolve(unreadableBase(sel.base));
108
129
  const { spelled, base } = target;
@@ -110,9 +131,9 @@ export async function readCallTarget(env, call, signal, leads) {
110
131
  const prior = views.get(key);
111
132
  if (prior !== undefined)
112
133
  return prior;
113
- const read = readPathViews(env, spelled, base, bases, signal, { hops: true })
114
- .catch(() => ({ lexical: resolveSpelling(spelled, base, bases), hops: [] }))
115
- .then((v) => viewFrom(v, family));
134
+ const read = readPath(env, spelled, base, bases, { intent: "resolve", views: "chain" }, signal)
135
+ .catch((err) => ({ lexical: placeSpelling(spelled, base, bases), canonical: { ok: false, message: `the environment threw resolving the target: ${thrownText(err)}` }, hops: [] }))
136
+ .then(viewFrom);
116
137
  views.set(key, read);
117
138
  return read;
118
139
  };
@@ -130,13 +151,14 @@ export function withArgsReading(req, args, signal) {
130
151
  const reread = reading === undefined ? undefined : REREAD.get(reading);
131
152
  return reread === undefined ? undefined : reread(args, signal).then((targetReading) => ({ ...req, args, targetReading }));
132
153
  }
133
- function viewFrom(v, family) {
154
+ function viewFrom(v) {
134
155
  if (v.lexical === undefined)
135
156
  return undefined;
136
157
  if (v.lexical.kind !== "path")
137
158
  return Object.freeze({ ...v.lexical });
138
159
  const canonical = v.canonical?.ok === true ? v.canonical.key : undefined;
139
- return Object.freeze({ kind: "path", lexical: spellingOfIdentity(v.lexical.identity, family), ...(canonical !== undefined ? { canonical } : {}), ...(v.hops.length > 0 ? { hops: Object.freeze([...v.hops]) } : {}) });
160
+ const unread = (v.canonical !== undefined && !v.canonical.ok) || v.hopsUnread === true;
161
+ return Object.freeze({ kind: "path", lexical: spellingOfIdentity(v.lexical.identity, v.lexical.family), ...(canonical !== undefined ? { canonical } : {}), ...(v.hops.length > 0 ? { hops: Object.freeze([...v.hops]) } : {}), ...(unread ? { unread: true } : {}) });
140
162
  }
141
163
  export function callTargetReadingOf(req) {
142
164
  const r = req.targetReading;
@@ -149,21 +171,29 @@ export function callTargetViewsOf(req, direction, bare = {}) {
149
171
  if (v === undefined || v.kind === "refused")
150
172
  return undefined;
151
173
  if (v.kind === "unreadable")
152
- return { spellings: [], unreadable: v.reason };
153
- const spellings = [v.lexical];
154
- for (const s of [v.canonical, ...(v.hops ?? [])])
155
- if (s !== undefined && !spellings.includes(s))
156
- spellings.push(s);
157
- return { spellings };
174
+ return { views: [], unreadable: v.reason };
175
+ if (direction === "allow" && (v.canonical === undefined || v.unread === true))
176
+ return { views: [], unreadable: ALLOW_UNRESOLVED };
177
+ const views = [{ path: v.lexical, kind: "lexical" }];
178
+ const seen = (p) => views.some((w) => w.path === p);
179
+ if (v.canonical !== undefined && !seen(v.canonical))
180
+ views.push({ path: v.canonical, kind: "canonical" });
181
+ for (const hop of v.hops ?? [])
182
+ if (!seen(hop))
183
+ views.push({ path: hop, kind: "hop" });
184
+ return { views };
158
185
  }
159
186
  const own = req.root !== undefined || req.cwd !== undefined ? { ...(req.root !== undefined ? { root: req.root } : {}), ...(req.cwd !== undefined ? { cwd: req.cwd } : {}) } : bare;
160
187
  const target = effectivePathTargetOf(req, direction === "tighten" ? protectivePathTargetOf(req) : declaredPathTargetOf(req), own);
161
188
  if (target === undefined || target.kind === "refused")
162
189
  return undefined;
163
190
  if (target.kind === "unreadable")
164
- return { spellings: [], unreadable: target.reason };
165
- return { spellings: [spellingOfIdentity(target.identity, pathFamilyOf(own))] };
191
+ return { views: [], unreadable: target.reason };
192
+ if (direction === "allow")
193
+ return { views: [], unreadable: ALLOW_UNRESOLVED };
194
+ return { views: [{ path: spellingOfIdentity(target.identity, target.family), kind: "lexical" }] };
166
195
  }
196
+ const ALLOW_UNRESOLVED = "where the target resolves was not read, so no allow by path can speak for it";
167
197
  export function legCallTargetStamp(leg) {
168
198
  const taken = new WeakMap();
169
199
  return (req, signal) => {
@@ -34,11 +34,14 @@ export interface EngineNotice {
34
34
  * prepared leg, never per judgment and never re-fired for a mid-run roster delta; absent ⇒ the judge
35
35
  * has its target view, or no covered write tool was mounted AT PREPARE, or there is no judge —
36
36
  * `wiringManifest.writeProtection` reports the judge's reading either way.
37
- * - `"config.write_protection_unresolved"` (#869) — this leg's write-protection judge HAS a target view
38
- * and the environment behind it could not answer: it refused a spelling, could not follow a link, or
39
- * threw. That view then does not vote and the write is judged by its SPELLING alone (the judge's
40
- * absence law), so the disclosure is the only place a deployment learns that its write floor is
41
- * running on half a judgment. Announce, never narrow — no verdict moves because of this notice; the
37
+ * - `"config.path_view_unresolved"` (#869; 7.48.0 `config.write_protection_unresolved`) — this leg's write-protection judge HAS a target view
38
+ * and one SOURCE of a judgment did not answer: the environment refused a spelling, could not follow a link,
39
+ * threw, or did not answer within the gate's deadline — on the target, its link chain or a root's key — or
40
+ * a deployment policy's guarded write rows did not come back. A target whose real destination (or chain)
41
+ * could not be determined is refused where the table has rows; an auxiliary source is absent on its own (a
42
+ * root exempts and places nothing; rows that did not come back are held, so the writes they could guard are
43
+ * not placed); every row an answering source met stays met — the judge's absence law. The disclosure is
44
+ * where a deployment learns its environment is the reason. Announce, never narrow — no verdict moves because of this notice; the
42
45
  * verdict already moved when the environment failed to answer. Audience `operator`.
43
46
  * `detail: { reason, cause, sessionId, runId }` — `reason` is `"unresolved-symlink"` (a link whose
44
47
  * real target is unknowable) or `"unresolvable-target"` (everything else: a refused spelling, an
@@ -60,11 +63,12 @@ export interface EngineNotice {
60
63
  * - `"permission.allowed_tool_not_granted"` — an allow list holds entries that grant (or refuse) nothing: a loaded skill's
61
64
  * `allowed-tools` / `disallowed-tools`, the request's `TaskSpec.allowedTools`, the deployment's `RunnerDeps.allowedTools`.
62
65
  * `*` (it voids an allow list; on a deny list it reads as nothing and the rest still refuses), `mcp__*` (no server
63
- * named), a write-path or domain entry, a shape the rule grammar does not read. The run goes on and asks for those tools
66
+ * named), a rule on a tool with no such rule form (an allow by path on a tool other than `Read` / `Edit`, a deny by host),
67
+ * a shape the rule grammar refuses, a tool name stale against the run's roster. The run goes on and asks for those tools
64
68
  * as usual. Audience `user`; once per prepared task for the skill and request lists (`detail.sessionId` present), once
65
69
  * per Runner for the deployment's (at construction, no session). `detail: { sessionId?, entries: [{ source, entry,
66
70
  * reason, skill?, list? }] }` (`source` ∈ `skill` / `request` / `deployment`; `skill` and `list` only on a skill's;
67
- * `reason` ∈ `wildcard_all` / `namespace_wildcard` / `path_pattern` / `domain` / `content_unsupported` / `grammar`).
71
+ * `reason` ∈ {@link import("./allow-entry.js").ALLOW_ENTRY_INERT_REASONS}).
68
72
  * - `"skills.listing_truncated"` — the `<skills>` disclosure block did not fit its byte budget, so
69
73
  * at least one skill is listed without its description (`nameOnly`) or, in the pathological case,
70
74
  * not listed at all (`dropped`); the `Skill` tool still serves every one of them. Audience
@@ -269,6 +273,27 @@ export interface EngineNotice {
269
273
  * `"charset"` (a control byte, a space, a non-ASCII unit or `~`), `"length"` (admitted characters, over 128)
270
274
  * or `"duplicate"` (a renamed later call); `rawLength` present for the two shape reasons only; never the raw
271
275
  * bytes. Absent ⇒ no call of the run was folded.
276
+ * - `"route.finish_reason_unknown"` (#1457) — the provider ended a response with a stream-end word (an
277
+ * OpenAI-family `finish_reason`) the brain does not read. The turn is kept — its text and the stop its content
278
+ * implies — and the word rides `AssistantMessage.finishReasonUnknown` (and, when the run completes on that turn,
279
+ * `terminal.detail`); the notice is what keeps the keep from being a silent clean stop. ONCE PER LEG PER WORD.
280
+ * Audience `user` (the person reading the answer judges whether it is whole); `detail: { finishReason,
281
+ * sessionId, runId }` — the word in the provider echo shape, `?` when it had bytes outside it.
282
+ * - `"route.stream_end_ignored"` (#1457) — the provider's stream sent more after its first terminal statement, on
283
+ * either wire: a later ending (OpenAI-family `finish_reason`, Anthropic `stop_reason`), error frame or content (a
284
+ * delta, a block, a new message). The first ending decided the turn and nothing after it was added
285
+ * (`AssistantMessage.streamEndIgnored`). ONCE PER LEG PER (statement, word). Audience `user`; `detail: {
286
+ * statement: "ending" | "error" | "content", word, frames, sessionId, runId }` — `word` the first such frame's
287
+ * (for content, its kind), `frames` how many came.
288
+ * - `"route.extra_body_reserved_dropped"` (#1520) — a request's `Model.extraBody` carried keys the wire adapter
289
+ * sets itself (`temperature`, `max_tokens`, `stop`, the thinking-enable keys, `messages`, `tools`, …), so the
290
+ * adapter stripped them and the request went out with the engine's value (or without the key); core wins, and
291
+ * that is said. One reading at the one strip site — the model spec of the task, a model spec a host brain
292
+ * rewrote for a single request, and the leg's internal calls (the compaction summary, mid-task or at the end of
293
+ * the task, and a side query fired from a tool) are announced alike. Advisory: the turn
294
+ * runs. ONCE PER LEG PER (api, key set) — a deployment fact, not a request fact. Audience `operator`;
295
+ * `detail: { keys, api, modelId, sessionId, runId }` — `keys` the key NAMES in `extraBody`'s order (never a
296
+ * value), `api` the wire the adapter speaks, `modelId` the catalog id the request was sent as.
272
297
  * - `"context.tool_turn_repaired"` (#1224) — a provider request was built from a transcript that breaks the
273
298
  * tool-turn law, and the request view restored it (`engine/llm/tool-turns.ts`; the transcript is never
274
299
  * rewritten): a block after an assistant's tool calls moved ahead of them (`trailing_text`), a result recorded
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { thrownText } from "./thrown-value.js";
3
- import { isAbsoluteForFamily, isAbsolutePathForm, isWinFormPath, pathFamilyOf } from "../tools/fs/safety.js";
3
+ import { isAbsoluteForFamily, isWinFormPath, pathFamilyOf, relativeInEveryFamily } from "../tools/fs/safety.js";
4
4
  import { fileHistoryBoundariesToKeep, resolveFileHistoryRetention } from "./file-history-retention.js";
5
5
  const normSlash = (p) => p.replace(/\\/g, "/");
6
6
  const stripTrailSep = (p) => (isWinFormPath(p) ? p.replace(/[\\/]+$/, "") : p.replace(/\/+$/, ""));
@@ -20,7 +20,7 @@ function joinUnder(root, rel) {
20
20
  return stripTrailSep(root) + (win ? "\\" : "/") + (win ? rel.replace(/\//g, "\\") : rel);
21
21
  }
22
22
  function isUnsafeRelPathLike(relN) {
23
- return isAbsolutePathForm(relN) || /^[A-Za-z]:/.test(relN) || relN.split("/").includes("..");
23
+ return !relativeInEveryFamily(relN) || relN.split("/").includes("..");
24
24
  }
25
25
  function parentDirOf(absPath) {
26
26
  const win = isWinFormPath(absPath);
@@ -1,5 +1,9 @@
1
1
  import type { ExecutionEnv } from "../internal/harness-types.js";
2
2
  import type { PermissionResult, ToolPolicy } from "./tool-policy.js";
3
+ import { type PathGuardRow } from "./path-guard-rows.js";
4
+ /** One write domain SOURCE as an allow row of the one table: it reaches every location at or below one of its admitted keys.
5
+ * The write gate's three sources, and a session rule's `allowDirs` (the confinement that admits a write only inside them). */
6
+ export declare function domainRow(source: "advertised" | "configured" | "accepted" | "session", dirs: readonly string[]): PathGuardRow;
3
7
  /** design/388 B22 — the identity triple the exemption probe hands the store beside the name. */
4
8
  export interface ToolCallIdentity {
5
9
  capabilityId: string;
@@ -3,6 +3,20 @@ import { isWithin } from "./runner/session-rule-policy.js";
3
3
  import { swallowedFenceRoot } from "./runner/advertised-writable-dirs.js";
4
4
  import { declaredPathTargetOf, isProtectedWrite } from "./tool-registry.js";
5
5
  import { pathTargetBaseOf } from "./effective-path-target.js";
6
+ import { judgePathRows } from "./path-guard-rows.js";
7
+ export function domainRow(source, dirs) {
8
+ return {
9
+ name: `write domain (${source})`,
10
+ grammar: { kind: "domain", dirs, source },
11
+ polarity: "allow",
12
+ faces: ["write"],
13
+ placement: "anywhere",
14
+ fold: "exact",
15
+ exemptible: false,
16
+ origin: source === "advertised" ? "builtin" : "addition",
17
+ reach: (view) => (dirs.some((dir) => isWithin(dir, view.path)) ? { reach: "reached" } : { reach: "not_reached" }),
18
+ };
19
+ }
6
20
  const ask = (message) => ({ action: "ask", message, decisionReason: "rule" });
7
21
  function absoluteRootOf(rootPath, envCwd) {
8
22
  return rootPath === undefined ? undefined : lexicalViewOf(rootPath, envCwd);
@@ -56,10 +70,12 @@ export function createFsWriteGatePolicy(opts) {
56
70
  if (!canon.ok) {
57
71
  return ask(`write to "${path}" requires approval: its real target could not be resolved (${canon.message})${advisory}`);
58
72
  }
59
- for (const root of req.advertisedWritableRoots ?? []) {
60
- if (isWithin(root, canon.key))
61
- return { action: "allow" };
62
- }
73
+ const advertised = req.advertisedWritableRoots ?? [];
74
+ const targetViews = { views: [{ path: canon.key, kind: "canonical" }] };
75
+ const admitted = { configured: [], accepted: [] };
76
+ const admits = () => judgePathRows([domainRow("advertised", advertised), domainRow("configured", admitted.configured), domainRow("accepted", admitted.accepted)], targetViews, "allow") !== undefined;
77
+ if (admits())
78
+ return { action: "allow" };
63
79
  let fenceRootsCanonical;
64
80
  let refusedDomain;
65
81
  for (const [dirs, structural] of [
@@ -87,7 +103,8 @@ export function createFsWriteGatePolicy(opts) {
87
103
  continue;
88
104
  }
89
105
  }
90
- if (isWithin(dir.key, canon.key))
106
+ (structural ? admitted.configured : admitted.accepted).push(dir.key);
107
+ if (admits())
91
108
  return { action: "allow" };
92
109
  }
93
110
  }
@@ -35,19 +35,34 @@ export declare const DEFAULT_GATE_AWAIT_TIMEOUT_MS = 30000;
35
35
  export declare function createGateDeadline(input: {
36
36
  approvalTimeoutMs?: number;
37
37
  }, notifier: Parameters<typeof traceHookCrash>[2]): () => number;
38
+ /** What ONE source of a judgment answered: its value, or its absence and why (it threw — synchronously or not — or did not
39
+ * answer before the judgment's signal ended the wait; `gateWaitFailureOf(cause)` says which wait ended it). */
40
+ export type SourceAnswer<T> = {
41
+ readonly ok: true;
42
+ readonly value: T;
43
+ } | {
44
+ readonly ok: false;
45
+ readonly cause: unknown;
46
+ };
38
47
  /**
39
- * The write-protection judge's wait, at both of its call sites — and the ONE minter of the `unresolvable`
40
- * verdict. An elapsed or aborted judgment is not "a target the environment could not resolve" (the judge
41
- * answers that one itself, by dropping the view that could not contribute and letting the lexical half
42
- * stand); it is NO judgment at all — not even the lexical half's answer came back — and there is nothing
43
- * for the fold or the approved-edit arm to act on but their own fail-closed arm. A wait that produced
44
- * nothing knows nothing about what it was waiting for, which is why `unresolvedSymlink` is `false` here
45
- * and not a guess.
48
+ * THE one way a source enters a path judgment — an environment lookup (the real target, the link chain, a root's key) or a
49
+ * provider of rows (a deployment's guarded write rows): asked, bounded by the signal the judgment was handed (the gate's
50
+ * deadline), and SETTLED — never thrown. A source that fails or does not answer in time is absent on its own (its view does not
51
+ * vote, its root exempts nothing, its rows are held unplaced), and every other source's answer stands: no source's failure
52
+ * reaches the judgment as a whole. No signal (a host calling a judge directly) ⇒ bounded by {@link DEFAULT_GATE_AWAIT_TIMEOUT_MS}.
53
+ */
54
+ export declare function fromSource<T>(ask: () => Promise<T>, signal: AbortSignal | undefined, label: string): Promise<SourceAnswer<T>>;
55
+ /**
56
+ * The write-protection judgment at both of its gate call sites. The gate's ONE deadline is handed DOWN as the judgment's
57
+ * signal, so it bounds each of the judgment's sources on its own ({@link fromSource}): a view that did not answer in time takes no
58
+ * part, an exemption root whose key did not come back exempts nothing, and a row a view already met stays met — the one
59
+ * absence law of every path table, per lookup. `judge` returns `null` synchronously for a call it does not cover (no deadline
60
+ * is armed, no seat read); `undefined` is returned then.
46
61
  *
47
- * KNOWN, AND NARROWER THAN IT LOOKS: the lexical half is computed synchronously at the top of `judge`, so
48
- * a spelling HIT is already on a settled promise before this wait begins and cannot elapse; what this arm
49
- * refuses is a spelling MISS whose environment half never came back. Closing even that would mean handing
50
- * the deadline INTO the judge so the missing half could be dropped there too — a seat change on a public
51
- * type, deliberately not taken here.
62
+ * The wait here is the LIVENESS net for a judgment that does not observe the signal it was handed, and it ends one turn of the
63
+ * event loop AFTER the deadline: a judgment whose every lookup races the signal (the engine's) has settled by then with what it
64
+ * found, so the net never stands in for its answer. A judgment that never came back, or threw, determined nothing about where
65
+ * the write lands, and the table it judges for has rows: `unresolvable` (the one absence law's target arm — refused), reported
66
+ * as a deployment callback failing.
52
67
  */
53
- export declare function awaitWriteProtectionJudgment(judged: Promise<WriteProtectionVerdict>, ms: number, signal?: AbortSignal, onFailure?: (err: unknown) => void): Promise<WriteProtectionVerdict>;
68
+ export declare function awaitWriteProtectionJudgment(judge: (signal: AbortSignal) => Promise<WriteProtectionVerdict> | null, deadlineMs: () => number, signal?: AbortSignal, onFailure?: (err: unknown) => void): Promise<WriteProtectionVerdict | undefined>;
@@ -23,7 +23,15 @@ export function withGateTimeout(p, ms, signal, label = "reversibilityProbe") {
23
23
  signal?.removeEventListener("abort", onAbort);
24
24
  fn(v);
25
25
  };
26
- const onAbort = () => done(reject, gateWaitError(`${label} aborted (task ended)`, "aborted"));
26
+ const onAbort = () => {
27
+ const reason = signal?.reason;
28
+ const ended = gateWaitFailureOf(reason) !== undefined
29
+ ? reason
30
+ : reason?.name === "TimeoutError"
31
+ ? gateWaitError(`${label} timed out (its deadline elapsed)`, "timeout")
32
+ : gateWaitError(`${label} aborted (task ended)`, "aborted");
33
+ done(reject, ended);
34
+ };
27
35
  const timer = ms !== undefined
28
36
  ? setTimeout(() => done(reject, gateWaitError(`${label} timed out after ${ms}ms`, "timeout")), ms)
29
37
  : undefined;
@@ -53,12 +61,41 @@ export function createGateDeadline(input, notifier) {
53
61
  return resolved;
54
62
  };
55
63
  }
56
- export async function awaitWriteProtectionJudgment(judged, ms, signal, onFailure) {
64
+ export async function fromSource(ask, signal, label) {
57
65
  try {
58
- return await withGateTimeout(judged, ms, signal, "writeProtectionJudge");
66
+ return { ok: true, value: await withGateTimeout(Promise.resolve().then(ask), signal === undefined ? DEFAULT_GATE_AWAIT_TIMEOUT_MS : undefined, signal, label) };
67
+ }
68
+ catch (cause) {
69
+ return { ok: false, cause };
70
+ }
71
+ }
72
+ export async function awaitWriteProtectionJudgment(judge, deadlineMs, signal, onFailure) {
73
+ const deadline = new AbortController();
74
+ const judged = judge(deadline.signal);
75
+ if (judged === null)
76
+ return undefined;
77
+ const ms = deadlineMs();
78
+ const net = new AbortController();
79
+ const endBoth = (reason) => {
80
+ if (!deadline.signal.aborted)
81
+ deadline.abort(reason);
82
+ setImmediate(() => net.abort(reason));
83
+ };
84
+ const timer = setTimeout(() => endBoth(gateWaitError(`writeProtectionJudge timed out after ${ms}ms`, "timeout")), ms);
85
+ const onTaskAbort = () => endBoth(gateWaitError("writeProtectionJudge aborted (task ended)", "aborted"));
86
+ if (signal?.aborted === true)
87
+ onTaskAbort();
88
+ else
89
+ signal?.addEventListener("abort", onTaskAbort);
90
+ try {
91
+ return await withGateTimeout(judged, undefined, net.signal, "writeProtectionJudge");
59
92
  }
60
93
  catch (err) {
61
94
  onFailure?.(err);
62
- return { kind: "unresolvable", cause: thrownText(err), unresolvedSymlink: false };
95
+ return { kind: "unresolvable", cause: `the write-protection judgment did not answer: ${thrownText(err)}`, unresolvedSymlink: false };
96
+ }
97
+ finally {
98
+ clearTimeout(timer);
99
+ signal?.removeEventListener("abort", onTaskAbort);
63
100
  }
64
101
  }
@@ -1,4 +1,4 @@
1
- import { type GatePass } from "./runner/gate-exit.js";
1
+ import type { GatePass } from "./runner/gate-exit.js";
2
2
  import type { ToolGateResult } from "./hooks.js";
3
3
  /**
4
4
  * Run the fold over the pass: adjudicate, fold the hook-ask, tighten. Writes `req` (re-minted over the FINAL
@@ -2,9 +2,8 @@ import { inlineUntrusted } from "./untrusted-text.js";
2
2
  import { markTightenMessage } from "./safety-axis-vocab.js";
3
3
  import { PROBE_REASON_MAX, normalizeProbeCause } from "./checkpoint-store.js";
4
4
  import { normalizeReadRootCandidate } from "./read-root-candidate.js";
5
- import { passAskFace } from "./runner/gate-exit.js";
6
5
  import { traceHookCrash } from "./gate-crash-trace.js";
7
- import { writeProtectionMandated, writeProtectionTightenDecision, writeProtectionUnresolved } from "./write-protect.js";
6
+ import { writeProtectionMandated, writeProtectionTightenDecision } from "./write-protect.js";
8
7
  import { createGateDeadline, awaitWriteProtectionJudgment, gateWaitFailureOf, withGateTimeout } from "./gate-bounded-await.js";
9
8
  import { thrownText } from "./thrown-value.js";
10
9
  import { refuseOutOfContractDecision } from "./tool-policy.js";
@@ -18,10 +17,11 @@ export async function runGateFold(pass) {
18
17
  pass.req = await stamped;
19
18
  pass.decision = adjudicate ? refuseOutOfContractDecision(await (callSignal !== undefined ? adjudicate(pass.req, callSignal) : adjudicate(pass.req))) : { action: "allow" };
20
19
  {
21
- const refusedBy = ledger.fromDecision(pass.decision);
22
- if (refusedBy !== undefined)
23
- pass.deniedBy = refusedBy;
24
- if (refusedBy !== undefined)
20
+ const read = ledger.fromDecision(pass.decision);
21
+ pass.decision = read.decision;
22
+ if (read.deniedBy !== undefined)
23
+ pass.deniedBy = read.deniedBy;
24
+ if (read.deniedBy !== undefined)
25
25
  pass.denyCause = ledger.causeOf(pass.decision);
26
26
  const attributed = ledger.classifierRoundOf(pass.decision);
27
27
  if (attributed !== undefined)
@@ -154,21 +154,18 @@ export async function runGateFold(pass) {
154
154
  }
155
155
  const writeProtectionStanding = pass.decision.action;
156
156
  if ((writeProtectionStanding === "allow" || writeProtectionStanding === "ask") && input.writeProtectionCheck !== undefined) {
157
- const judged = input.writeProtectionCheck(toolName, pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput, pass.req.face, input.trackedCwd?.(), pass.callSignal ?? input.abortSignal);
158
- const verdict = judged === null
159
- ? undefined
160
- : await awaitWriteProtectionJudgment(judged, boundedAwaitDeadlineMs(), pass.callSignal ?? input.abortSignal, (err) => {
161
- const kind = gateWaitFailureOf(err);
162
- if (kind === "aborted" || input.abortSignal?.aborted === true)
163
- return;
164
- traceHookCrash(input, new Error(`write-protection judge ${kind === "timeout" ? "timed out" : "threw"} for tool "${toolName}" (toolCallId ${toolCallId}) — this call's write target could not be judged: ${thrownText(err)}`), notifier);
165
- });
157
+ const check = input.writeProtectionCheck;
158
+ const judgedArgs = pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput;
159
+ const verdict = await awaitWriteProtectionJudgment((deadline) => check(toolName, judgedArgs, pass.req.face, input.trackedCwd?.(), deadline), boundedAwaitDeadlineMs, pass.callSignal ?? input.abortSignal, (err) => {
160
+ const kind = gateWaitFailureOf(err);
161
+ if (kind === "aborted" || input.abortSignal?.aborted === true)
162
+ return;
163
+ traceHookCrash(input, new Error(`write-protection judge ${kind === "timeout" ? "timed out" : "threw"} for tool "${toolName}" (toolCallId ${toolCallId}) — this call's write target could not be judged: ${thrownText(err)}`), notifier);
164
+ });
166
165
  if (verdict !== undefined && writeProtectionMandated(verdict))
167
166
  pass.writeProtected = true;
168
- if (verdict !== undefined && writeProtectionUnresolved(verdict))
169
- pass.writeProtectionUnresolved = true;
170
- const decision = verdict === undefined ? undefined : writeProtectionTightenDecision(toolName, verdict, passAskFace(pass));
171
- if (decision !== undefined && writeProtectionStanding === "allow") {
167
+ const decision = verdict === undefined ? undefined : writeProtectionTightenDecision(toolName, verdict);
168
+ if (decision !== undefined && (writeProtectionStanding === "allow" || decision.action === "deny")) {
172
169
  pass.decision = decision;
173
170
  if (decision.action === "ask")
174
171
  pass.tightenedBy = "safety";
@@ -182,10 +179,10 @@ export async function runGateFold(pass) {
182
179
  }
183
180
  return await pass.afterFold(pass);
184
181
  }
185
- function shellReadAskMessage(toolName, finding) {
186
- return finding === "outside_roots"
187
- ? `tool "${toolName}" reads outside the directories allowed for this session — explicit approval required`
188
- : `tool "${toolName}" reads where the session's read boundary could not establish what is read — explicit approval required`;
182
+ function shellReadAskMessage(toolName, verdict) {
183
+ if (verdict.finding !== "outside_roots")
184
+ return `tool "${toolName}" reads where the session's read boundary could not establish what is read — explicit approval required`;
185
+ return `tool "${toolName}" ${verdict.face === "write" ? "writes" : "reads"} outside the directories allowed for this session — explicit approval required`;
189
186
  }
190
187
  function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
191
188
  const account = verdict.sentence !== undefined && verdict.sentence.trim().length > 0 ? inlineUntrusted(verdict.sentence, PROBE_REASON_MAX) : undefined;
@@ -193,6 +190,8 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
193
190
  pass.shellWritesPlaced = true;
194
191
  if (verdict.writeProtected === true)
195
192
  pass.writeProtected = true;
193
+ if (verdict.targetUnresolved === true)
194
+ pass.targetUnresolved = true;
196
195
  if (verdict.unplacedOptions !== undefined)
197
196
  pass.shellUnplacedOptions = verdict.unplacedOptions;
198
197
  if (verdict.finding === "unestablishable" || verdict.finding === "declined" || verdict.unestablished === true)
@@ -217,7 +216,7 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
217
216
  const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
218
217
  pass.decision = {
219
218
  action: "ask",
220
- message: shellReadAskMessage(toolName, verdict.finding),
219
+ message: shellReadAskMessage(toolName, verdict),
221
220
  decisionReason: "safety",
222
221
  probeMandated: true,
223
222
  ...(account !== undefined ? { probeReason: account } : {}),
@@ -236,7 +235,7 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
236
235
  const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
237
236
  pass.decision = {
238
237
  action: "ask",
239
- message: shellReadAskMessage(toolName, verdict.finding),
238
+ message: shellReadAskMessage(toolName, verdict),
240
239
  decisionReason: "safety",
241
240
  ...(account !== undefined ? { probeReason: account } : {}),
242
241
  ...(candidate !== undefined ? { probeReadRootCandidate: candidate } : {}),