@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,7 +1,7 @@
1
1
  import { join } from "node:path";
2
2
  import { assertAdoptionBootGate } from "./adoption/marker.js";
3
3
  import { checkpointExecutionRecorded, executionRecordDisposition, ExecutionOutcomeConflictError, } from "../../core/checkpoint-execution-record.js";
4
- import { appendPendingSteer, CheckpointError, checkpointOccMatches, checkpointRowMatches, summarizeCheckpoint, validatePendingSteer, winnerFromOutcome, } from "../../core/checkpoint-store.js";
4
+ import { appendPendingSteer, CheckpointError, checkpointOccMatches, checkpointRowMatches, encodeAtFidelity, summarizeCheckpoint, validatePendingSteer, winnerFromOutcome, } from "../../core/checkpoint-store.js";
5
5
  import { SharedLedgerTable } from "./shared-ledger.js";
6
6
  import { guardCorruptSink } from "./corrupt-read-sink.js";
7
7
  const CHECKPOINT_LEDGER_EVENT_REGISTRY = {
@@ -109,7 +109,10 @@ export class FileCheckpointStore {
109
109
  return this.ledger.withLock(token, fn);
110
110
  }
111
111
  commit(ev, fsync) {
112
- this.ledger.commit(ev, fsync, this.compactEvery);
112
+ const held = encodeAtFidelity(this.fidelity, ev);
113
+ if (!held.ok)
114
+ throw held.cause;
115
+ this.ledger.commit(held.value, fsync, this.compactEvery);
113
116
  }
114
117
  async put(token, cp) {
115
118
  return this.withLock(token, () => {
@@ -8,7 +8,6 @@ import { type FileSessionPolicyStoreOptions } from "./session-policy-store.js";
8
8
  import { type FileFileHistoryStoreOptions } from "./file-history-store.js";
9
9
  import type { CorruptReadInfo } from "./corrupt-read-sink.js";
10
10
  import type { FileHistoryStore } from "../../core/file-history-store.js";
11
- import type { StrategyStore } from "../../core/strategy-store.js";
12
11
  import type { BackgroundAgentStore } from "../../core/background-agent-store.js";
13
12
  import type { MailboxStore } from "../../core/mailbox-store.js";
14
13
  import type { RosterStore } from "../../agents/roster-store.js";
@@ -23,7 +22,6 @@ export { FileSessionPolicyStore, type FileSessionPolicyStoreOptions, type Sessio
23
22
  export { FileFileHistoryStore, type FileFileHistoryStoreOptions } from "./file-history-store.js";
24
23
  export { FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult } from "./workflow-journal-store.js";
25
24
  export { FileUsageWindowStore, type FileUsageWindowStoreOptions } from "./usage-window-store.js";
26
- export { FileStrategyStore, type FileStrategyStoreOptions } from "./strategy-store.js";
27
25
  export { resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock } from "./fs-atomic.js";
28
26
  export { FileStoreLockError, type FileStoreLockErrorCode } from "./fs-atomic.js";
29
27
  export { atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog } from "./fs-atomic.js";
@@ -152,12 +150,6 @@ export declare class FileStorageBackend {
152
150
  /** design/151 §7 S3c — the durable SendMessage mailbox (tier-3 parking lane), same data root.
153
151
  * Wire into `RunnerDeps.mailboxStore` (single-instance pairing, same as above). */
154
152
  readonly mailboxStore: MailboxStore;
155
- /** File-backed teacher-mode strategy repository (`root/strategies`) — pass as
156
- * `TeacherConfig.strategyStore` (with a `scope`) so escalation strategies survive a restart;
157
- * the in-memory default forgets everything each process, which zeroes the cross-session reuse
158
- * the repository exists for. Aggregated here so the TOC full-persistence assembly stays one
159
- * constructor (the same half-wiring hazard as the delegation trio). */
160
- readonly strategyStore: StrategyStore;
161
153
  /** design/147 S1c — the durable name→agent roster (layer 0.5 resolution), `root/roster.json`.
162
154
  * Wire into `RunnerDeps.rosterStore` so name-addressing survives a restart alongside the rows. */
163
155
  readonly rosterStore: RosterStore;
@@ -13,7 +13,6 @@ import { FileUsageWindowStore } from "./usage-window-store.js";
13
13
  import { FileBackgroundAgentStore } from "./background-agent-store.js";
14
14
  import { FileMailboxStore } from "./mailbox-store.js";
15
15
  import { FileRosterStore } from "../../agents/roster-store.js";
16
- import { FileStrategyStore } from "./strategy-store.js";
17
16
  import { FileFileHistoryStore } from "./file-history-store.js";
18
17
  export { FileCheckpointStore } from "./checkpoint-store.js";
19
18
  export { FileMemoryStore } from "./memory-store.js";
@@ -23,7 +22,6 @@ export { FileSessionPolicyStore } from "./session-policy-store.js";
23
22
  export { FileFileHistoryStore } from "./file-history-store.js";
24
23
  export { FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult } from "./workflow-journal-store.js";
25
24
  export { FileUsageWindowStore } from "./usage-window-store.js";
26
- export { FileStrategyStore } from "./strategy-store.js";
27
25
  export { resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock } from "./fs-atomic.js";
28
26
  export { FileStoreLockError } from "./fs-atomic.js";
29
27
  export { atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog } from "./fs-atomic.js";
@@ -41,7 +39,6 @@ export class FileStorageBackend {
41
39
  usageWindowStore;
42
40
  backgroundAgentStore;
43
41
  mailboxStore;
44
- strategyStore;
45
42
  rosterStore;
46
43
  fileHistoryStore;
47
44
  consolidationLock;
@@ -84,15 +81,6 @@ export class FileStorageBackend {
84
81
  built.push(() => this.fileMailbox.close());
85
82
  this.mailboxStore = this.fileMailbox;
86
83
  this.rosterStore = new FileRosterStore(join(this.root, "roster.json"), corruptRead ?? {});
87
- const strategiesRoot = join(this.root, "strategies");
88
- this.strategyStore = new FileStrategyStore({
89
- root: strategiesRoot,
90
- ...(opts.onCorruptRead !== undefined
91
- ? {
92
- onIncident: (i) => opts.onCorruptRead?.({ kind: "file", path: i.path ?? strategiesRoot, reason: `strategy ${i.op}: ${i.error}` }),
93
- }
94
- : {}),
95
- });
96
84
  this.fileHistoryStore = new FileFileHistoryStore(this.root, { ...(opts.fileHistory ?? {}), ...(corruptRead ?? {}) });
97
85
  this.consolidationLock = createFileConsolidationLock(join(this.root, "consolidation-locks"));
98
86
  }
@@ -72,6 +72,9 @@ export declare class FileSessionRepo implements SessionRepo {
72
72
  olderThanMs?: number;
73
73
  scope?: string;
74
74
  }): Promise<PlacedSessionRow[]>;
75
+ /** The row as it stands before a file-replacing write: `undefined` ⇔ there is no row (no file); a row
76
+ * whose header cannot be read answers an empty header (it exists, its cells are unknown). */
77
+ private priorHeader;
75
78
  /** Cheap placement probe for one id (the TtlSessionStore's cold-cache release consults it so the
76
79
  * placed real-deletion obligation holds after a restart). `undefined` = missing file OR unplaced. */
77
80
  placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { BaseSessionStorage, StoredSession, SessionError, getEntriesToFork, uuidv7, validateEntriesForImport, } from "../../internal/harness.js";
3
+ import { BaseSessionStorage, StoredSession, SessionError, assertForkTarget, forkRowCells, getEntriesToFork, incarnationCell, uuidv7, validateEntriesForImport, } from "../../internal/harness.js";
4
4
  import { canonicalStoreKey, AppendLog, atomicWriteFile, ensureDir, readJsonlRecords, sanitizePathComponent } from "./fs-atomic.js";
5
5
  import { guardCorruptSink } from "./corrupt-read-sink.js";
6
6
  import { assertAdoptionBootGate } from "./adoption/marker.js";
@@ -102,10 +102,25 @@ export class FileSessionRepo {
102
102
  if (meta === undefined) {
103
103
  throw new SessionError("corrupt_session", `Session ${id} is unreadable: its log has no meta header (${tally?.dropped ?? 0} of ${tally?.total ?? lines.length} records skipped as corrupt)`);
104
104
  }
105
- const { createdAt, forkedFrom, placement } = meta;
106
- return { createdAt, ...(forkedFrom !== undefined ? { forkedFrom } : {}), ...(placement !== undefined ? { placement } : {}), entries };
105
+ const { createdAt, forkedFrom, placement, incarnation, forkedFromIncarnation } = meta;
106
+ for (const [key, token] of [["incarnation", incarnation], ["forkedFromIncarnation", forkedFromIncarnation]]) {
107
+ if (token !== undefined && typeof token !== "string")
108
+ this.disclose(path, `session header carries a non-string ${key} (${typeof token}) — read as an UNKNOWN occupant`, id);
109
+ }
110
+ return {
111
+ meta: {
112
+ id,
113
+ createdAt,
114
+ ...(forkedFrom !== undefined ? { forkedFrom } : {}),
115
+ ...(placement !== undefined ? { placement } : {}),
116
+ ...(typeof incarnation === "string" ? { incarnation } : {}),
117
+ ...(typeof forkedFromIncarnation === "string" ? { forkedFromIncarnation } : {}),
118
+ },
119
+ entries,
120
+ };
107
121
  }
108
- storage(id, createdAt, entries, forkedFrom, placement) {
122
+ storage(meta, entries) {
123
+ const { id } = meta;
109
124
  const canonical = canonicalStoreKey(this.pathFor(id));
110
125
  const live = sharedSessionStorages.get(canonical)?.deref();
111
126
  if (live !== undefined) {
@@ -114,7 +129,7 @@ export class FileSessionRepo {
114
129
  return live;
115
130
  }
116
131
  const log = new AppendLog(this.pathFor(id));
117
- const created = new FileSessionStorage(log, { id, createdAt, ...(forkedFrom !== undefined ? { forkedFrom } : {}), ...(placement !== undefined ? { placement } : {}) }, entries, canonical);
132
+ const created = new FileSessionStorage(log, meta, entries, canonical);
118
133
  sharedSessionStorages.set(canonical, new WeakRef(created));
119
134
  created.addHolder(this);
120
135
  this.joined.set(canonical, new WeakRef(created));
@@ -140,15 +155,16 @@ export class FileSessionRepo {
140
155
  if (!existsSync(path)) {
141
156
  evictSharedSessionStorage(canonicalStoreKey(path));
142
157
  const placement = options.placement !== undefined ? { ...options.placement, placedAt: options.placement.placedAt ?? Date.now() } : undefined;
143
- atomicWriteFile(this.tmpDir, path, `${JSON.stringify({ kind: "meta", id, createdAt, ...(placement !== undefined ? { placement } : {}) })}\n`);
144
- return new StoredSession(this.storage(id, createdAt, [], undefined, placement));
158
+ const meta = { id, createdAt, ...(placement !== undefined ? { placement } : {}), ...incarnationCell(undefined) };
159
+ atomicWriteFile(this.tmpDir, path, `${JSON.stringify({ kind: "meta", ...meta })}\n`);
160
+ return new StoredSession(this.storage(meta, []));
145
161
  }
146
- const { createdAt: existingCreatedAt, forkedFrom, placement, entries } = this.read(id);
147
- return new StoredSession(this.storage(id, existingCreatedAt || createdAt, entries, forkedFrom, placement));
162
+ const { meta, entries } = this.read(id);
163
+ return new StoredSession(this.storage({ ...meta, createdAt: meta.createdAt || createdAt }, entries));
148
164
  }
149
165
  async open(metadata) {
150
- const { createdAt, forkedFrom, placement, entries } = this.read(metadata.id);
151
- return new StoredSession(this.storage(metadata.id, createdAt, entries, forkedFrom, placement));
166
+ const { meta, entries } = this.read(metadata.id);
167
+ return new StoredSession(this.storage(meta, entries));
152
168
  }
153
169
  async list() {
154
170
  let names;
@@ -167,7 +183,7 @@ export class FileSessionRepo {
167
183
  continue;
168
184
  const id = name.slice(0, -SUFFIX.length);
169
185
  try {
170
- const { createdAt, forkedFrom, placement } = this.read(id);
186
+ const { createdAt, forkedFrom, placement } = this.read(id).meta;
171
187
  if (placement !== undefined)
172
188
  continue;
173
189
  out.push({ id, createdAt, ...(forkedFrom !== undefined ? { forkedFrom } : {}) });
@@ -199,7 +215,7 @@ export class FileSessionRepo {
199
215
  const id = name.slice(0, -SUFFIX.length);
200
216
  let placement;
201
217
  try {
202
- placement = this.read(id).placement;
218
+ placement = this.read(id).meta.placement;
203
219
  }
204
220
  catch (err) {
205
221
  if (!(err instanceof SessionError && err.code === "not_found")) {
@@ -227,9 +243,17 @@ export class FileSessionRepo {
227
243
  }
228
244
  return out;
229
245
  }
246
+ priorHeader(id) {
247
+ try {
248
+ return this.read(id).meta;
249
+ }
250
+ catch (err) {
251
+ return err instanceof SessionError && err.code === "not_found" ? undefined : {};
252
+ }
253
+ }
230
254
  async placementOf(sessionId) {
231
255
  try {
232
- return this.read(sessionId).placement;
256
+ return this.read(sessionId).meta.placement;
233
257
  }
234
258
  catch {
235
259
  return undefined;
@@ -245,20 +269,20 @@ export class FileSessionRepo {
245
269
  }
246
270
  }
247
271
  async fork(sourceMetadata, options = {}) {
272
+ assertForkTarget(sourceMetadata.id, options.id);
248
273
  const source = await this.open(sourceMetadata);
249
274
  const forked = await getEntriesToFork(source.getStorage(), options);
250
275
  const id = options.id ?? uuidv7();
251
276
  const createdAt = new Date().toISOString();
252
277
  const path = this.pathFor(id);
253
- const lines = [
254
- JSON.stringify({ kind: "meta", id, createdAt, forkedFrom: sourceMetadata.id }),
255
- ];
278
+ const meta = { id, createdAt, ...forkRowCells(await source.getMetadata()) };
279
+ const lines = [JSON.stringify({ kind: "meta", ...meta })];
256
280
  for (const entry of forked) {
257
281
  lines.push(JSON.stringify({ kind: "entry", entry }));
258
282
  }
259
283
  evictSharedSessionStorage(canonicalStoreKey(path));
260
284
  atomicWriteFile(this.tmpDir, path, `${lines.join("\n")}\n`);
261
- return new StoredSession(this.storage(id, createdAt, [...forked], sourceMetadata.id));
285
+ return new StoredSession(this.storage(meta, [...forked]));
262
286
  }
263
287
  async exportEntries(sessionId) {
264
288
  return this.read(sessionId).entries;
@@ -266,9 +290,10 @@ export class FileSessionRepo {
266
290
  async importEntries(sessionId, owner, entries, options) {
267
291
  void owner;
268
292
  const validated = validateEntriesForImport(entries, options);
293
+ const prior = this.priorHeader(sessionId);
269
294
  evictSharedSessionStorage(canonicalStoreKey(this.pathFor(sessionId)));
270
295
  const createdAt = new Date().toISOString();
271
- const lines = [JSON.stringify({ kind: "meta", id: sessionId, createdAt })];
296
+ const lines = [JSON.stringify({ kind: "meta", id: sessionId, createdAt, ...incarnationCell(prior) })];
272
297
  for (const entry of validated) {
273
298
  lines.push(JSON.stringify({ kind: "entry", entry }));
274
299
  }
@@ -5,6 +5,7 @@ import { Type } from "typebox";
5
5
  import { ARTIFACT_ACTION_CONCURRENCY_SAFE, ARTIFACT_COMMIT_THROW_OUTCOME, ARTIFACT_FAILURE_RESULT_CODE, ARTIFACT_HOST_ERROR_CODE, ARTIFACT_LIST_SCOPES, ARTIFACT_PLANE_CONTENT_ORIGIN, ARTIFACT_PUBLISH_CONTEXTS, } from "../../core/artifact-host.js";
6
6
  import { ARTIFACT_TOOL_NAME, toolFace } from "../../core/tool-catalog-entries.js";
7
7
  import { resolveAsk } from "../../core/tool-policy.js";
8
+ import { approvalCardOf } from "../../core/tool-roster.js";
8
9
  import { errorResult } from "../../core/tools.js";
9
10
  import { inlineUntrusted } from "../../core/untrusted-text.js";
10
11
  import { actionDescription, artifactDescription, PARAM_TEXT, urlDescription } from "./artifact-text.js";
@@ -343,6 +344,7 @@ export function createArtifactTool(opts) {
343
344
  args: { action: "read", url },
344
345
  message: `Read a shared artifact: ${inlineUntrusted(url, 300)}${title}${version} — an artifact another person shared with this user; approving covers re-reads of it for the rest of this run.`,
345
346
  requiresRealApproval: true,
347
+ approvalCard: approvalCardOf({ toolName: ARTIFACT_TOOL_NAME }, toolFace("artifact").renderHints?.approvalCard),
346
348
  }, onAsk, ctx.signal);
347
349
  if (resolved.action !== "allow")
348
350
  return { ok: false, reason: resolved.message ?? "not approved" };
@@ -16,9 +16,8 @@ export declare const NOT_AUTO_ALLOWED = "\u2014 not auto-allowed";
16
16
  export declare function programBasename(word: string): string;
17
17
  /**
18
18
  * The `NAME=` / `NAME+=` prefix as WRITTEN in a whitespace-split token. This is NOT the position reader's grammar
19
- * — the reader reads the lexer's {@link LexedWord.assignment} fact — but the two readers that still walk the
20
- * command TEXT rather than its words (the unverifiable-delete policy and the activity summary) read it, and
21
- * they read it here so that they read one spelling. It retires with them.
19
+ * — the reader reads the lexer's {@link LexedWord.assignment} fact — but the one reader that still walks the
20
+ * command TEXT rather than its words (the activity summary) reads it here. It retires with it.
22
21
  */
23
22
  export declare const ASSIGNMENT_PREFIX: RegExp;
24
23
  /** The prefix a whitespace-split token BEGINS with, or `undefined` — the text readers' view of
@@ -30,10 +29,21 @@ export declare function writtenAssignmentPrefix(token: string): {
30
29
  readonly appends: boolean;
31
30
  readonly settlesWholeName: boolean;
32
31
  } | undefined;
32
+ /** The names a segment's COMMAND ENVIRONMENT sets for the program it starts: the assignment words in front of the
33
+ * program (the lexer's {@link LexedWord.assignment} fact, a launcher's `NAME=value` operand included) — or `all` where
34
+ * a launcher in front of it may set, clear or replace the environment (`env -u` / `-i`, `sudo`, `su`, …). */
35
+ export declare function commandEnvironmentNames(argv: readonly LexedWord[]): ReadonlySet<string> | "all";
33
36
  export { SHELL_CONTROL_PREFIXES };
34
37
  /** A control word is a keyword only when bash sees it BARE: `'if'` / `"do"` / `\\!` are command names (a program
35
38
  * looked up on PATH, whose failure changes nothing), so a quoted or escaped spelling never counts as one. */
36
39
  export declare function isBareControlWord(words: readonly LexedWord[], i: number, set: ReadonlySet<string>): boolean;
40
+ /** Does the shell read this word as syntax — a reserved word, a control word, `{`, `coproc` — of `set`? Only a word
41
+ * written BARE where bash reads a command's first word (the lexer's {@link LexedWord.atCommandPosition}): a quoted or
42
+ * escaped spelling is a command name, and a word an expansion produced (a value, a split field) is never syntax —
43
+ * bash parses the line before it expands it. The one reading every syntax reader of a command's words asks. */
44
+ export declare function isShellSyntaxWord(w: LexedWord | undefined, set: ReadonlySet<string>): boolean;
45
+ /** The words that head a loop over a list (`for NAME in …`, `select NAME in …`). */
46
+ export declare const LOOP_LIST_HEADS: ReadonlySet<string>;
37
47
  /**
38
48
  * A word bash strips as an ASSIGNMENT before it chooses the program: the lexer's assignment fact, written BARE
39
49
  * (the name, the brackets and the operator unquoted — a quoted VALUE still assigns, a quoted operator is a
@@ -92,6 +102,10 @@ export interface ProgramPosition {
92
102
  } | undefined;
93
103
  /** Why no program could be read; `undefined` beside `program: undefined` means the chain simply names none. */
94
104
  readonly refusal: ProgramPositionRefusal | undefined;
105
+ /** A launcher of the chain moves the directory or the root the program runs in, or where its word is looked up
106
+ * (`env -C <dir>`, `sudo -R <dir>`, `env -P <dirs>`): the program is still the word it names, but where its path
107
+ * operands resolve is not the command line's working directory — each consumer reads that as it must. */
108
+ readonly launcherMovesBase: boolean;
95
109
  }
96
110
  /**
97
111
  * Read the program position of one segment's argv words.
@@ -1,5 +1,6 @@
1
1
  import { SHELL_CONTROL_PREFIXES } from "../../shell/lex.js";
2
- import { BLOCK_WORD_NAMES, LAUNCHER_NAMES, feedsArgvFromStdin, launcherOptionStep, launcherRunsShell, programRow, selectedOptions, streamDefaultProgram } from "./program-read-model.js";
2
+ import { shellWordsOf } from "../../shell/shell-words.js";
3
+ import { BLOCK_WORD_NAMES, LAUNCHER_NAMES, feedsArgvFromStdin, launcherOptionMovesBase, launcherOptionStep, launcherRunsShell, programRow, selectedOptions, streamDefaultProgram } from "./program-read-model.js";
3
4
  export const NOT_AUTO_ALLOWED = "— not auto-allowed";
4
5
  export function programBasename(word) {
5
6
  return word.includes("/") ? (word.split("/").pop() ?? word) : word;
@@ -14,11 +15,21 @@ export function writtenAssignmentPrefix(token) {
14
15
  const bracket = written.indexOf("[");
15
16
  return { prefix, name: bracket < 0 ? written : written.slice(0, bracket), appends, settlesWholeName: !appends && bracket < 0 };
16
17
  }
18
+ const ENVIRONMENT_KEEPING_LAUNCHERS = new Set(["nice", "nohup", "time", "timeout", "stdbuf", "ionice", "chrt", "taskset", "command", "builtin", "caffeinate"]);
19
+ export function commandEnvironmentNames(argv) {
20
+ const pos = readProgramPosition(argv);
21
+ if (pos.launchers.some((l) => !ENVIRONMENT_KEEPING_LAUNCHERS.has(l.name)))
22
+ return "all";
23
+ return new Set(argv.slice(0, pos.program?.index ?? argv.length).flatMap((w) => (w.assignment?.bare === true ? [w.assignment.name] : [])));
24
+ }
17
25
  export { SHELL_CONTROL_PREFIXES };
18
26
  export function isBareControlWord(words, i, set) {
19
- const w = words[i];
20
- return w !== undefined && w.raw === w.folded && set.has(w.folded);
27
+ return isShellSyntaxWord(words[i], set);
28
+ }
29
+ export function isShellSyntaxWord(w, set) {
30
+ return w !== undefined && w.atCommandPosition && w.raw === w.folded && set.has(w.folded);
21
31
  }
32
+ export const LOOP_LIST_HEADS = shellWordsOf("loop_list_head");
22
33
  export function isLeadingAssignmentWord(words, i) {
23
34
  const w = words[i];
24
35
  return w !== undefined && w.assignment !== undefined && w.assignment.bare && w.atCommandPosition;
@@ -27,7 +38,7 @@ function launcherRowOf(name) {
27
38
  const row = programRow(name);
28
39
  return row?.launcher !== undefined ? row : undefined;
29
40
  }
30
- function pastLauncherOptions(launcher, folded, i) {
41
+ function pastLauncherOptions(launcher, folded, i, moved) {
31
42
  const row = launcherRowOf(launcher);
32
43
  if (row === undefined)
33
44
  return i;
@@ -44,6 +55,8 @@ function pastLauncherOptions(launcher, folded, i) {
44
55
  return i;
45
56
  if (step === 2 && folded[i + 1] === undefined)
46
57
  return i;
58
+ if (launcherOptionMovesBase(row, tok))
59
+ moved?.();
47
60
  i += step;
48
61
  }
49
62
  }
@@ -57,7 +70,7 @@ export function readProgramPosition(words) {
57
70
  controlWords.push(i);
58
71
  i = pastLauncherOptions(controlWord, folded, i + 1);
59
72
  }
60
- const none = (written, assignments, refusal) => ({ controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: undefined, refusal });
73
+ const none = (written, assignments, refusal) => ({ controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: undefined, refusal, launcherMovesBase: false });
61
74
  if (i >= folded.length)
62
75
  return none(undefined, []);
63
76
  const written = i;
@@ -75,25 +88,27 @@ export function readProgramPosition(words) {
75
88
  return none(written, assignments, { kind: "option_at_program_position", owner, option: head });
76
89
  }
77
90
  if (!LAUNCHER_NAMES.has(basename)) {
78
- return { controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: { index: i, name: head, basename }, refusal: undefined };
91
+ return { controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: { index: i, name: head, basename }, refusal: undefined, launcherMovesBase: false };
79
92
  }
80
93
  const launchers = [{ index: i, name: basename }];
81
94
  const owner = head;
82
95
  const shellRefusal = (launcher, from) => ({ kind: "control_syntax_at_program_position", owner, word: "sh", runsShell: { launcher, from } });
83
96
  let lastRow = launcherRowOf(basename)?.launcher;
84
97
  let owedOperands = lastRow?.requiredOperands ?? 0;
85
- const chain0 = (program, refusal) => ({ controlWords, written, assignments, launchers, argvFromStdin: false, runsDefaultProgram: false, program, refusal });
98
+ const chain0 = (program, refusal) => ({ controlWords, written, assignments, launchers, argvFromStdin: false, runsDefaultProgram: false, program, refusal, launcherMovesBase: false });
86
99
  if (launcherRunsShell(launcherRowOf(basename), folded.slice(i + 1)))
87
100
  return chain0(undefined, shellRefusal(i, i + 1));
88
101
  let argvFromStdin = feedsArgvFromStdin(basename);
89
102
  let lastReentry = argvFromStdin ? i : -1;
90
103
  let reentryDefault = argvFromStdin ? streamDefaultProgram(basename) : undefined;
104
+ let launcherMovesBase = false;
105
+ const moved = () => { launcherMovesBase = true; };
91
106
  const chain = (program, refusal) => {
92
107
  const runsDefaultProgram = lastReentry === folded.length - 1;
93
- return { controlWords, written, assignments, launchers, argvFromStdin, runsDefaultProgram, ...(runsDefaultProgram && reentryDefault !== undefined ? { defaultProgram: reentryDefault } : {}), program, refusal };
108
+ return { controlWords, written, assignments, launchers, argvFromStdin, runsDefaultProgram, ...(runsDefaultProgram && reentryDefault !== undefined ? { defaultProgram: reentryDefault } : {}), program, refusal, launcherMovesBase };
94
109
  };
95
110
  const selectsShell = (l, end) => selectedOptions(launcherRowOf(l.name), folded.slice(l.index + 1, end)).some((o) => o.mode === "interactive");
96
- for (let j = pastLauncherOptions(basename, folded, i + 1); j < folded.length; j++) {
111
+ for (let j = pastLauncherOptions(basename, folded, i + 1, moved); j < folded.length; j++) {
97
112
  const t = folded[j];
98
113
  if (owedOperands > 0 && !t.startsWith("-")) {
99
114
  owedOperands -= 1;
@@ -118,7 +133,7 @@ export function readProgramPosition(words) {
118
133
  if (launcherRunsShell(launcherRowOf(wordBasename), folded.slice(j + 1)))
119
134
  return chain(undefined, shellRefusal(j, j + 1));
120
135
  owedOperands = lastRow?.requiredOperands ?? 0;
121
- j = pastLauncherOptions(wordBasename, folded, j + 1) - 1;
136
+ j = pastLauncherOptions(wordBasename, folded, j + 1, moved) - 1;
122
137
  continue;
123
138
  }
124
139
  if (t.startsWith("-"))
@@ -361,7 +361,7 @@ export declare function formatOutOfRootReadApprovalOption(directory: string): st
361
361
  * resolved to nothing, was dropped, and the verdict was empty, i.e. a read outside every root
362
362
  * AUTO-ALLOWED on the one face whose doctrine is hard refusal in exactly that direction.
363
363
  * The second fact is why the lane split in
364
- * {@link collectSegmentBoundaryFindings} tests {@link isAbsolutePathForm} BESIDE this predicate,
364
+ * {@link collectSegmentBoundaryFindings} tests {@link isAbsoluteForFamily} (an address's own family) BESIDE this predicate,
365
365
  * which is what the option-payload arm always did; the two now read one rule rather than two. */
366
366
  export declare function isPathShapedToken(tok: string): boolean;
367
367
  /** Resolve one operand against the boundary's base, WITHOUT touching the filesystem. Returns undefined
@@ -1,5 +1,6 @@
1
- import { isAbsoluteForFamily, isAbsolutePathForm, isBlockedDevicePath, isShellRootedSpellingUnmapped, joinForFamily, nativeUncSpellingOf, normalizeAbsPathLexically, win32NamespaceScreen, pathFamilyOf } from "./safety.js";
1
+ import { anchorSpelling, isAbsoluteForFamily, isBlockedDevicePath, isShellRootedSpellingUnmapped, nativeUncSpellingOf, normalizeAbsPathLexically, win32NamespaceScreen, pathFamilyOf } from "./safety.js";
2
2
  import { PARSE_FAILURE_SENTENCE, UNRESOLVED_SENTENCE, argvOf, lexShell, literalTildeSpelling, } from "../../shell/lex.js";
3
+ import { shellWordsOf } from "../../shell/shell-words.js";
3
4
  import { textBindsHome } from "./shell-read-bindings.js";
4
5
  import { NOT_AUTO_ALLOWED, argvReentryUnjudged, isBareControlWord, programPositionRefusalSentence, readProgramPosition, } from "./bash-program-position.js";
5
6
  import { BLOCK_WORD_NAMES, attachedStdinFile, declaresOption, firstOperandSlot, opensNoOperand, programDelivery, programRow, programTextReadings, readArgRoles, readArgs, readProgramTextLanguage, runsShellText, selectedOptions, slotValueCandidates, suppliesFirstOperandSlot, takesSeparatedDatum, valuesAreLiteral, writeReadings, writesPath, } from "./program-read-model.js";
@@ -171,7 +172,7 @@ const PARENT_SEGMENT_RE = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
171
172
  export function resolveOperandSpellings(base, operand, homeDir) {
172
173
  let raw = operand;
173
174
  if (raw === "~" || raw.startsWith("~/")) {
174
- if (homeDir === undefined || !isAbsolutePathForm(homeDir))
175
+ if (homeDir === undefined || !isAbsoluteForFamily("own", homeDir))
175
176
  return undefined;
176
177
  raw = raw === "~" ? homeDir : `${homeDir.replace(/[/\\]+$/, "")}/${raw.slice(2)}`;
177
178
  }
@@ -181,13 +182,13 @@ export function resolveOperandSpellings(base, operand, homeDir) {
181
182
  const family = base === undefined ? undefined : pathFamilyOf({ root: base });
182
183
  if (!win32NamespaceScreen(raw, family).ok)
183
184
  return undefined;
184
- if (isAbsoluteForFamily(family, raw))
185
+ if (isAbsoluteForFamily(family ?? "own", raw))
185
186
  return spellingsOf(nativeUncSpellingOf(family, raw));
186
187
  if (base === undefined || family === undefined || !isAbsoluteForFamily(family, base))
187
188
  return undefined;
188
189
  if (isShellRootedSpellingUnmapped(family, raw))
189
190
  return undefined;
190
- return spellingsOf(joinForFamily(family, base, raw));
191
+ return spellingsOf(anchorSpelling(family, base, raw));
191
192
  }
192
193
  function spellingsOf(absolute) {
193
194
  const folded = normalizeAbsPathLexically(absolute);
@@ -660,7 +661,7 @@ export function attachedOptionPayloads(tok) {
660
661
  return out;
661
662
  }
662
663
  const whole = literal(tok.slice(1));
663
- if (whole.length > 0 && (isPathShapedToken(whole) || isAbsolutePathForm(whole)))
664
+ if (whole.length > 0 && (isPathShapedToken(whole) || isAbsoluteForFamily("own", whole)))
664
665
  out.push(whole);
665
666
  for (let k = 2; k <= tok.length; k++) {
666
667
  if (![...tok.slice(1, k)].every((ch) => CLUSTER_OPTION_CHAR.test(ch)))
@@ -744,7 +745,7 @@ export function classifyCompoundReadonlyDetailed(command, allow, boundary) {
744
745
  const written = folded[from];
745
746
  if (written === undefined)
746
747
  return { reason: "empty command" };
747
- if (written === "coproc")
748
+ if (shellWordsOf("background").has(written))
748
749
  return { reason: "`coproc` backgrounds a command — a backgrounded process outlives the command" };
749
750
  if (isBareControlWord(words, from, BLOCK_WORD_NAMES)) {
750
751
  unlistedSegments.add(si);
@@ -777,7 +778,7 @@ export function classifyCompoundReadonlyDetailed(command, allow, boundary) {
777
778
  if (runsShellText(name))
778
779
  return { reason: unjudgedProgramTextRefusal(parsed.name, "runs its argument as shell text") };
779
780
  if (pos.launchers.length > 0) {
780
- const listed = program !== undefined && (allow.has(program.basename) || program.basename === "cd");
781
+ const listed = program !== undefined && allow.has(program.basename);
781
782
  if (program !== undefined && !listed && runsShellText(program.basename)) {
782
783
  return { reason: `"${written}" runs "${program.basename}", which runs its argument as shell text this classifier does not read ${NOT_AUTO_ALLOWED}` };
783
784
  }
@@ -3,6 +3,10 @@
3
3
  * type gates all still run). One type for both seats: the two faces differ in WHICH band consults
4
4
  * them, never in what the word means. */
5
5
  export type ContainmentFace = "open" | "roots";
6
+ /** Does a face state skip the roots-containment step? The ONE reading of a face seat a containment judgment takes — the
7
+ * structured tools' path check and the shell station's write face alike: `"open"` skips it; `"roots"` and an ABSENT
8
+ * state run it (absent ⇒ roots, the historical fence). */
9
+ export declare function skipsRootsContainment(face: ContainmentFace | undefined): boolean;
6
10
  /** Which band a face governs. Selects the seat spellings and the error codes below — never the
7
11
  * resolution ORDER, which is one body shared by both. */
8
12
  export type ContainmentFaceKind = "read" | "write";
@@ -1,4 +1,7 @@
1
1
  import { describeRejectedValue } from "../../core/tool-search-setting.js";
2
+ export function skipsRootsContainment(face) {
3
+ return face === "open";
4
+ }
2
5
  const FACE_DIALECT = {
3
6
  read: {
4
7
  key: "readFace",
@@ -253,6 +253,16 @@ export declare function bashMaxOutputChars(): number;
253
253
  export declare const FILE_PATH_PARAMS: {
254
254
  file_path: Type.TString;
255
255
  };
256
+ /**
257
+ * Write's pre-validation argument repair — CC 2.1.296 `orr` (the Write tool's `coerceInput`, cli296.js:247143),
258
+ * the two rules that matter under a non-strict schema: `path` is read as `file_path` when `file_path` is absent
259
+ * and `path` is a string; exactly one of `file_text` / `file_content` is read as `content` when `content` is
260
+ * absent and the value is a string. Anything else — both content aliases, a present `file_path`, a non-string
261
+ * value — is left to the schema, which refuses it by naming the parameter. The repaired key REPLACES the alias
262
+ * (it is deleted), so no second spelling rides on into the gates. Idempotent, and the very same object for a
263
+ * call that needs no repair (the loop's "prepared arguments changed" test is a reference test).
264
+ */
265
+ export declare function coerceWriteArguments(args: unknown): unknown;
256
266
  /** Honest head+tail truncation to {@link bashMaxOutputChars}: the middle is dropped with a real-total
257
267
  * marker, because the head AND tail both matter for a shell. Kept as the inline shape even beside the
258
268
  * file-backed recovery below — unlike a background task's poll-for-the-latest-tail interaction, a
@@ -185,6 +185,24 @@ export function bashMaxOutputChars() {
185
185
  export const FILE_PATH_PARAMS = {
186
186
  file_path: Type.String({ description: "File path (within the configured root)." }),
187
187
  };
188
+ const WRITE_CONTENT_ALIASES = ["file_text", "file_content"];
189
+ export function coerceWriteArguments(args) {
190
+ if (args === null || typeof args !== "object" || Array.isArray(args))
191
+ return args;
192
+ const a = args;
193
+ let repaired;
194
+ if (!Object.hasOwn(a, "file_path") && typeof a["path"] === "string") {
195
+ repaired = { ...a, file_path: a["path"] };
196
+ delete repaired["path"];
197
+ }
198
+ const spelled = WRITE_CONTENT_ALIASES.filter((k) => Object.hasOwn(a, k));
199
+ const alias = spelled[0];
200
+ if (alias !== undefined && spelled.length === 1 && !Object.hasOwn(a, "content") && typeof a[alias] === "string") {
201
+ repaired = { ...(repaired ?? a), content: a[alias] };
202
+ delete repaired[alias];
203
+ }
204
+ return repaired ?? args;
205
+ }
188
206
  export function clipShellOutput(s) {
189
207
  return clipWithFilePointer(s, bashMaxOutputChars());
190
208
  }
@@ -3,7 +3,7 @@ import { Type } from "typebox";
3
3
  import { defineTool, errorResult } from "../../core/tools.js";
4
4
  import { sha256, resolveKey, violationText, violationDetails, requireRead, checkStale, checkEditMatch, checkNoChange, fileArgPath, resolveQuoteMatch, adaptNewStringQuotes, resolveEscapeMatch, adaptNewStringEscapes, escapeMatchWasAttempted, ESCAPE_MATCH_MISS_NOTE, deletionOldString, countOccurrences, READ_REFUSED_ESCAPE_HINT, } from "./safety.js";
5
5
  import { decodeTextBytes, encodeTextForFile, normalizeEditText, normalizeFileText } from "./encoding.js";
6
- import { MAX_EDIT_BYTES, decodeEditBytes, tooLargeToEditMessage, truncatedUtf16BodyMessage, persistedTextOf, notReadRefusalText, enoentMessage, FILE_STATE_TRAILER, FILE_PATH_PARAMS, ipynbRedirect, countLines, applyRecordedEdit, } from "./fs-shared.js";
6
+ import { MAX_EDIT_BYTES, decodeEditBytes, tooLargeToEditMessage, truncatedUtf16BodyMessage, persistedTextOf, notReadRefusalText, enoentMessage, FILE_STATE_TRAILER, FILE_PATH_PARAMS, coerceWriteArguments, ipynbRedirect, countLines, applyRecordedEdit, } from "./fs-shared.js";
7
7
  import { toolFace } from "../../core/tool-catalog-entries.js";
8
8
  import { thrownText } from "../../core/thrown-value.js";
9
9
  async function envFinalWrite(env, key, content, signal, opts) {
@@ -326,7 +326,7 @@ export function createEditFileTool(env, state, rootCanonical, cwdRef, additional
326
326
  });
327
327
  }
328
328
  export function createWriteFileTool(env, state, rootCanonical, cwdRef, additionalRoots, beforeWrite, trackEdit, onEdited, writeFace, writeDeny) {
329
- return defineTool({
329
+ const write = defineTool({
330
330
  name: "Write",
331
331
  ...toolFace("write"),
332
332
  description: "Writes a file to the local filesystem, overwriting if one exists.\n" +
@@ -420,6 +420,8 @@ export function createWriteFileTool(env, state, rootCanonical, cwdRef, additiona
420
420
  };
421
421
  },
422
422
  });
423
+ write.prepareArguments = coerceWriteArguments;
424
+ return write;
423
425
  }
424
426
  const notebookNotIpynbMessage = (notebookPath) => `Error (NotebookEdit): "${notebookPath}" is not a .ipynb file; use Edit for other file types.`;
425
427
  const NOTEBOOK_CELL_TYPE_REQUIRED_MESSAGE = `Error (NotebookEdit): Cell type is required when using edit_mode=insert.`;
@@ -187,8 +187,9 @@ export interface HandsToolkitOptions {
187
187
  * under a short bound of its own, and a probe of it that fails costs that entry alone. The public shell judgment takes the
188
188
  * same list as {@link import("./shell-read-check.js").ShellReadJudgeInput.readDenyHomes}. */
189
189
  readDenyHomes?: readonly string[];
190
- /** Where each home-anchored row's literal head leads beyond the home's spellings
191
- * ({@link import("./read-deny-home.js").readDenyHomeLinksOf}, keyed by the row's pattern) — the Runner passes the
190
+ /** Where each home-anchored row's literal head leads beyond the home's spellings, and each rooted row's (`/…`) beyond its own
191
+ * spelling ({@link import("./read-deny-home.js").readDenyLinksOf},
192
+ * keyed by the row's pattern) — the Runner passes the
192
193
  * locations its own judge was compiled with, so the band and the gate judge one placement.
193
194
  * Unless a mount carries both, the band resolves the placement itself the way the Runner does (the homes it carries
194
195
  * are its home set — the account is not asked and no home is added;
@@ -14,7 +14,7 @@ export * from "./read-deny.js";
14
14
  export { readDenyHomesOf } from "./read-deny-home.js";
15
15
  import { BASH_READONLY_DEFAULT_ALLOW } from "./bash-readonly-classifier.js";
16
16
  export { BASH_CLASSIFY_EXTRA_ALLOW, bashClassifyDefaultAllow } from "./bash-readonly-classifier.js";
17
- import { checkedReadDenyHomes, compileReadDeny, compileWriteDeny, readDenyBuiltinConfigOf, readDenyPatternRun } from "./read-deny.js";
17
+ import { checkedReadDenyHomes, compileReadDeny, compileWriteDeny, isRootedReadDenyPattern, readDenyBuiltinConfigOf, readDenyPatternRun } from "./read-deny.js";
18
18
  import { withGateTimeout } from "../../core/gate-bounded-await.js";
19
19
  import { carryHomeViews, homeViewsAt, placeReadDenyAtHome, placementViewsOf, readDenyPlacedLater, sayPlacementLost } from "./read-deny-home.js";
20
20
  import { deploymentFaceClampNotice, resolveContainmentFace } from "./containment-face.js";
@@ -51,7 +51,7 @@ export function createHandsToolkit(env, readFileState, rootCanonical, opts = {})
51
51
  const carriedViews = carried ? placementViewsOf(opts.readDenyHomes) : undefined;
52
52
  if (carried && carriedViews === undefined)
53
53
  sayPlacementLost();
54
- const placesNothing = !unplaced.entries.some((e) => readDenyPatternRun(e.pattern).homeAnchored);
54
+ const placesNothing = !unplaced.entries.some((e) => readDenyPatternRun(e.pattern).homeAnchored || isRootedReadDenyPattern(e.pattern));
55
55
  const late = carried || placesNothing ? undefined : readDenyPlacedLater(carryHomeViews(unplaced, homeViewsAt(env, [])), () => placeReadDenyAtHome(env, compileAt, readDenyHomes));
56
56
  const readDeny = late?.matcher ??
57
57
  (carried