@sema-agent/core 7.48.0 → 7.49.1

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 (421) hide show
  1. package/CHANGELOG.md +457 -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 +38 -31
  51. package/dist/core/arg-summary.d.ts +21 -28
  52. package/dist/core/arg-summary.js +235 -88
  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 +94 -65
  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 +43 -11
  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 +21 -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.d.ts +4 -0
  101. package/dist/core/mcp.js +70 -43
  102. package/dist/core/memory-engine/content-origin.js +2 -14
  103. package/dist/core/memory-engine/engine.d.ts +32 -22
  104. package/dist/core/memory-engine/engine.js +103 -55
  105. package/dist/core/memory-engine/file-backend.d.ts +13 -30
  106. package/dist/core/memory-engine/file-backend.js +37 -252
  107. package/dist/core/memory-engine/index.d.ts +1 -1
  108. package/dist/core/memory-engine/index.js +1 -1
  109. package/dist/core/memory-engine/layout.d.ts +139 -9
  110. package/dist/core/memory-engine/layout.js +350 -7
  111. package/dist/core/memory-engine/scope-contract.d.ts +10 -0
  112. package/dist/core/memory-engine/scope-contract.js +8 -0
  113. package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
  114. package/dist/core/memory-engine/session-incarnation.js +5 -2
  115. package/dist/core/memory-engine/types.d.ts +10 -1
  116. package/dist/core/memory.js +5 -17
  117. package/dist/core/model-seat.d.ts +4 -4
  118. package/dist/core/model-seat.js +1 -1
  119. package/dist/core/mounted-mcp.d.ts +57 -0
  120. package/dist/core/mounted-mcp.js +19 -0
  121. package/dist/core/namespaced-rule-name.d.ts +29 -0
  122. package/dist/core/namespaced-rule-name.js +52 -0
  123. package/dist/core/park-selfcheck.d.ts +1 -1
  124. package/dist/core/park-selfcheck.js +16 -6
  125. package/dist/core/path-guard-rows.d.ts +99 -0
  126. package/dist/core/path-guard-rows.js +45 -0
  127. package/dist/core/path-identity.d.ts +22 -16
  128. package/dist/core/path-identity.js +10 -10
  129. package/dist/core/path-rule-binding.d.ts +2 -1
  130. package/dist/core/path-rule-binding.js +3 -1
  131. package/dist/core/pause-registry.d.ts +16 -2
  132. package/dist/core/pause-registry.js +6 -0
  133. package/dist/core/permission-rule-consent.js +0 -7
  134. package/dist/core/permission-rule-model.d.ts +68 -24
  135. package/dist/core/permission-rule-model.js +105 -24
  136. package/dist/core/permission-rule-store.js +2 -2
  137. package/dist/core/permission-rules.d.ts +3 -30
  138. package/dist/core/permission-rules.js +4 -54
  139. package/dist/core/read-root-candidate.d.ts +1 -3
  140. package/dist/core/read-root-candidate.js +4 -15
  141. package/dist/core/real-approval.d.ts +4 -3
  142. package/dist/core/retired-keys.d.ts +13 -0
  143. package/dist/core/retired-keys.js +14 -0
  144. package/dist/core/roles.d.ts +2 -3
  145. package/dist/core/roles.js +15 -6
  146. package/dist/core/runner/assemble-result.d.ts +0 -7
  147. package/dist/core/runner/assemble-result.js +19 -31
  148. package/dist/core/runner/caller-roster.d.ts +78 -0
  149. package/dist/core/runner/caller-roster.js +219 -0
  150. package/dist/core/runner/checkpoint-scope.d.ts +16 -16
  151. package/dist/core/runner/checkpoint-scope.js +2 -2
  152. package/dist/core/runner/child-tree.js +2 -2
  153. package/dist/core/runner/contracts.d.ts +68 -35
  154. package/dist/core/runner/decide-continuation.d.ts +51 -3
  155. package/dist/core/runner/decide-continuation.js +76 -21
  156. package/dist/core/runner/denial-limit-arms.d.ts +17 -5
  157. package/dist/core/runner/denial-limit-arms.js +11 -9
  158. package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
  159. package/dist/core/runner/extra-body-dropped-seat.js +22 -0
  160. package/dist/core/runner/finish-reason-seat.d.ts +9 -0
  161. package/dist/core/runner/finish-reason-seat.js +40 -0
  162. package/dist/core/runner/gate-exit.d.ts +44 -32
  163. package/dist/core/runner/gate-exit.js +112 -25
  164. package/dist/core/runner/inherited-ask-grants.js +6 -4
  165. package/dist/core/runner/mcp-redial.d.ts +3 -3
  166. package/dist/core/runner/mcp-redial.js +3 -4
  167. package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
  168. package/dist/core/runner/permission-rule-lanes.js +5 -4
  169. package/dist/core/runner/prepare-artifact.d.ts +4 -0
  170. package/dist/core/runner/prepare-artifact.js +2 -1
  171. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  172. package/dist/core/runner/prepare-ask-lane.js +12 -6
  173. package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
  174. package/dist/core/runner/prepare-boundary-parks.js +4 -7
  175. package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
  176. package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
  177. package/dist/core/runner/prepare-config-doors.d.ts +9 -9
  178. package/dist/core/runner/prepare-config-doors.js +10 -5
  179. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  180. package/dist/core/runner/prepare-defer-classify.js +5 -3
  181. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  182. package/dist/core/runner/prepare-delegation-surface.js +3 -3
  183. package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
  184. package/dist/core/runner/prepare-gate-stations.js +9 -7
  185. package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
  186. package/dist/core/runner/prepare-hands-readface.js +7 -7
  187. package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
  188. package/dist/core/runner/prepare-inherited-gate.js +14 -15
  189. package/dist/core/runner/prepare-listings.d.ts +7 -24
  190. package/dist/core/runner/prepare-listings.js +4 -5
  191. package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
  192. package/dist/core/runner/prepare-memory-engine-session.js +4 -3
  193. package/dist/core/runner/prepare-memory.d.ts +6 -0
  194. package/dist/core/runner/prepare-memory.js +13 -13
  195. package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
  196. package/dist/core/runner/prepare-offload-wrappers.js +3 -3
  197. package/dist/core/runner/prepare-park-ask.d.ts +7 -8
  198. package/dist/core/runner/prepare-park-ask.js +17 -10
  199. package/dist/core/runner/prepare-policy-chain.js +24 -44
  200. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  201. package/dist/core/runner/prepare-project-context.js +3 -4
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -4
  204. package/dist/core/runner/prepare-run-refs.d.ts +3 -0
  205. package/dist/core/runner/prepare-run-refs.js +2 -1
  206. package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
  207. package/dist/core/runner/prepare-safety-scan.js +1 -2
  208. package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
  209. package/dist/core/runner/prepare-suspend-saga.js +28 -12
  210. package/dist/core/runner/prepare-task.d.ts +1 -1
  211. package/dist/core/runner/prepare-task.js +67 -56
  212. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
  213. package/dist/core/runner/prepare-wiring-manifest.js +5 -8
  214. package/dist/core/runner/resume-apply.js +7 -14
  215. package/dist/core/runner/resume-checkpoint-screen.js +11 -4
  216. package/dist/core/runner/resume-internals-and-config.js +2 -2
  217. package/dist/core/runner/resume-policy-outcome.js +5 -32
  218. package/dist/core/runner/resume-review-outcome.js +4 -1
  219. package/dist/core/runner/retired-runner-deps.d.ts +6 -0
  220. package/dist/core/runner/retired-runner-deps.js +10 -1
  221. package/dist/core/runner/run-brain-sinks.d.ts +4 -0
  222. package/dist/core/runner/run-brain-sinks.js +5 -2
  223. package/dist/core/runner/run-harness-handlers.js +29 -36
  224. package/dist/core/runner/run-leg.d.ts +0 -2
  225. package/dist/core/runner/run-leg.js +32 -33
  226. package/dist/core/runner/run-terminal-adoption.js +4 -3
  227. package/dist/core/runner/runtask.js +8 -8
  228. package/dist/core/runner/session-rule-policy.js +5 -5
  229. package/dist/core/runner/stream-settle-backstop.js +7 -4
  230. package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
  231. package/dist/core/runner/sub-agent-deny-lists.js +111 -80
  232. package/dist/core/runner/terminal-account.d.ts +48 -0
  233. package/dist/core/runner/terminal-account.js +186 -0
  234. package/dist/core/runner/tool-end-body.d.ts +54 -17
  235. package/dist/core/runner/tool-end-body.js +27 -2
  236. package/dist/core/runner/tool-face-overlay.d.ts +3 -1
  237. package/dist/core/runner/tool-face-overlay.js +6 -4
  238. package/dist/core/runner/tool-occurrence.d.ts +106 -0
  239. package/dist/core/runner/tool-occurrence.js +123 -0
  240. package/dist/core/runner/tool-progress-lane.d.ts +16 -8
  241. package/dist/core/runner/tool-progress-lane.js +25 -34
  242. package/dist/core/runner/tool-turn-repair-seat.d.ts +28 -4
  243. package/dist/core/runner/tool-turn-repair-seat.js +36 -13
  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/secret-env.d.ts +16 -5
  249. package/dist/core/secret-env.js +23 -63
  250. package/dist/core/sensitive-path-policy.d.ts +19 -18
  251. package/dist/core/sensitive-path-policy.js +73 -49
  252. package/dist/core/session-reconcile.d.ts +3 -0
  253. package/dist/core/session-reconcile.js +5 -4
  254. package/dist/core/session-store.d.ts +5 -0
  255. package/dist/core/session-store.js +12 -0
  256. package/dist/core/session.d.ts +13 -0
  257. package/dist/core/shared-memory/normalize.d.ts +17 -4
  258. package/dist/core/shared-memory/normalize.js +7 -7
  259. package/dist/core/shell-lexer.js +5 -4
  260. package/dist/core/shell-wrapper-projection.js +1 -1
  261. package/dist/core/skill-grant.js +1 -1
  262. package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
  263. package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
  264. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
  265. package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
  266. package/dist/core/stub-env.d.ts +2 -0
  267. package/dist/core/stub-env.js +1 -0
  268. package/dist/core/synthetic-read-verdict.js +2 -2
  269. package/dist/core/task-event.d.ts +59 -5
  270. package/dist/core/task-result.d.ts +1 -1
  271. package/dist/core/task-spec.d.ts +42 -9
  272. package/dist/core/terminal-cause.d.ts +94 -11
  273. package/dist/core/tighten-task-spec.d.ts +5 -4
  274. package/dist/core/tighten-task-spec.js +20 -25
  275. package/dist/core/tool-catalog-entries.d.ts +5 -7
  276. package/dist/core/tool-catalog-entries.js +14 -15
  277. package/dist/core/tool-face.d.ts +47 -0
  278. package/dist/core/tool-face.js +5 -0
  279. package/dist/core/tool-model-gate.d.ts +5 -5
  280. package/dist/core/tool-name-aliases.d.ts +26 -2
  281. package/dist/core/tool-name-aliases.js +13 -0
  282. package/dist/core/tool-name-list.d.ts +30 -0
  283. package/dist/core/tool-name-list.js +55 -0
  284. package/dist/core/tool-name-readings.d.ts +1 -9
  285. package/dist/core/tool-name-readings.js +1 -3
  286. package/dist/core/tool-policy.d.ts +195 -85
  287. package/dist/core/tool-policy.js +165 -380
  288. package/dist/core/tool-registry.d.ts +44 -1
  289. package/dist/core/tool-registry.js +26 -0
  290. package/dist/core/tool-roster.d.ts +19 -1
  291. package/dist/core/tool-roster.js +21 -2
  292. package/dist/core/tool-spec-members.d.ts +45 -0
  293. package/dist/core/tool-spec-members.js +169 -0
  294. package/dist/core/tool-spec.d.ts +46 -8
  295. package/dist/core/tools.d.ts +6 -2
  296. package/dist/core/tools.js +8 -4
  297. package/dist/core/untrusted-egress.js +29 -26
  298. package/dist/core/untrusted-text.d.ts +13 -10
  299. package/dist/core/untrusted-text.js +6 -44
  300. package/dist/core/workflow-journal-store.d.ts +4 -1
  301. package/dist/core/write-protect.d.ts +65 -29
  302. package/dist/core/write-protect.js +235 -177
  303. package/dist/engine/compaction/compaction.d.ts +2 -2
  304. package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
  305. package/dist/engine/execution-env/node-execution-env.js +16 -38
  306. package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
  307. package/dist/engine/execution-env/symlink-chain.js +32 -0
  308. package/dist/engine/harness/types.d.ts +7 -0
  309. package/dist/engine/llm/tool-turns.d.ts +3 -0
  310. package/dist/engine/llm/tool-turns.js +1 -0
  311. package/dist/engine/llm/types.d.ts +59 -23
  312. package/dist/engine/loop/agent-loop.js +16 -2
  313. package/dist/engine/session/memory-repo.js +11 -3
  314. package/dist/engine/session/repo-utils.d.ts +8 -0
  315. package/dist/engine/session/repo-utils.js +13 -0
  316. package/dist/index.d.ts +20 -23
  317. package/dist/index.js +17 -20
  318. package/dist/internal/harness.d.ts +1 -1
  319. package/dist/internal/harness.js +1 -1
  320. package/dist/internal/llm.d.ts +2 -2
  321. package/dist/internal/llm.js +1 -1
  322. package/dist/orchestration/governance-baseline-validity.js +1 -1
  323. package/dist/orchestration/run-spec.js +3 -3
  324. package/dist/orchestration/run-workflow-tool.d.ts +16 -35
  325. package/dist/orchestration/run-workflow-tool.js +38 -78
  326. package/dist/orchestration/workflow-governance.d.ts +21 -25
  327. package/dist/orchestration/workflow-governance.js +38 -78
  328. package/dist/orchestration/workflow-primitives.d.ts +7 -22
  329. package/dist/orchestration/workflow-primitives.js +5 -12
  330. package/dist/orchestration/workflow-types.d.ts +1 -1
  331. package/dist/orchestration/workflow.d.ts +61 -11
  332. package/dist/orchestration/workflow.js +189 -117
  333. package/dist/scenarios/full-body.d.ts +1 -1
  334. package/dist/shell/lex.d.ts +0 -21
  335. package/dist/shell/lex.js +250 -68
  336. package/dist/shell/shell-words.d.ts +35 -0
  337. package/dist/shell/shell-words.js +65 -0
  338. package/dist/stores/file/checkpoint-store.d.ts +5 -5
  339. package/dist/stores/file/checkpoint-store.js +5 -2
  340. package/dist/stores/file/index.d.ts +0 -8
  341. package/dist/stores/file/index.js +0 -12
  342. package/dist/stores/file/session-store.d.ts +3 -0
  343. package/dist/stores/file/session-store.js +44 -19
  344. package/dist/tools/artifact/artifact-tool.js +2 -0
  345. package/dist/tools/fs/bash-program-position.d.ts +12 -4
  346. package/dist/tools/fs/bash-program-position.js +32 -9
  347. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  348. package/dist/tools/fs/bash-readonly-classifier.js +8 -7
  349. package/dist/tools/fs/containment-face.d.ts +4 -0
  350. package/dist/tools/fs/containment-face.js +3 -0
  351. package/dist/tools/fs/fs-shared.d.ts +10 -0
  352. package/dist/tools/fs/fs-shared.js +18 -0
  353. package/dist/tools/fs/fs-write.js +4 -2
  354. package/dist/tools/fs/index.d.ts +1 -1
  355. package/dist/tools/fs/program-read-model.d.ts +46 -20
  356. package/dist/tools/fs/program-read-model.js +50 -20
  357. package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
  358. package/dist/tools/fs/program-read-model.rows.js +16 -15
  359. package/dist/tools/fs/read-deny-home.d.ts +33 -47
  360. package/dist/tools/fs/read-deny-home.js +35 -49
  361. package/dist/tools/fs/read-deny.d.ts +23 -22
  362. package/dist/tools/fs/read-deny.js +114 -89
  363. package/dist/tools/fs/removal-targets.d.ts +56 -23
  364. package/dist/tools/fs/removal-targets.js +65 -87
  365. package/dist/tools/fs/safety.d.ts +29 -22
  366. package/dist/tools/fs/safety.js +17 -11
  367. package/dist/tools/fs/search.js +10 -8
  368. package/dist/tools/fs/shell-read-argv.js +1 -1
  369. package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
  370. package/dist/tools/fs/shell-read-bindings.js +324 -86
  371. package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
  372. package/dist/tools/fs/shell-read-builtins.js +43 -0
  373. package/dist/tools/fs/shell-read-check.d.ts +15 -1
  374. package/dist/tools/fs/shell-read-check.js +67 -43
  375. package/dist/tools/fs/shell-read-establish.js +6 -6
  376. package/dist/tools/fs/shell-read-functions.d.ts +22 -0
  377. package/dist/tools/fs/shell-read-functions.js +29 -0
  378. package/dist/tools/fs/shell-read-judge.d.ts +51 -18
  379. package/dist/tools/fs/shell-read-judge.js +40 -4
  380. package/dist/tools/fs/shell-read-plan.d.ts +12 -6
  381. package/dist/tools/fs/shell-read-plan.js +118 -113
  382. package/dist/tools/fs/shell-read-start.d.ts +29 -6
  383. package/dist/tools/fs/shell-read-start.js +16 -9
  384. package/dist/tools/fs/shell-read-word.js +4 -0
  385. package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
  386. package/dist/tools/fs/shell-read-workdir.js +281 -0
  387. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
  388. package/dist/tools/fs/shell-read-write-targets.js +14 -5
  389. package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
  390. package/dist/tools/fs/shell-reentry-text.js +3 -11
  391. package/dist/tools/task-list.d.ts +1 -2
  392. package/dist/tools/web.js +1 -1
  393. package/package.json +4 -1
  394. package/test/export-surface.snapshot.json +107 -143
  395. package/wire-changes/core@7.49.0.json +4765 -0
  396. package/dist/agents/teacher.d.ts +0 -159
  397. package/dist/agents/teacher.js +0 -577
  398. package/dist/agents/team.d.ts +0 -226
  399. package/dist/agents/team.js +0 -257
  400. package/dist/core/strategy-store.d.ts +0 -238
  401. package/dist/core/strategy-store.js +0 -253
  402. package/dist/orchestration/builtin-workflows.d.ts +0 -133
  403. package/dist/orchestration/builtin-workflows.js +0 -159
  404. package/dist/scenarios/env.d.ts +0 -40
  405. package/dist/scenarios/env.js +0 -39
  406. package/dist/scenarios/scenario-registry.d.ts +0 -110
  407. package/dist/scenarios/scenario-registry.js +0 -140
  408. package/dist/scenarios/teacher-quickstart.d.ts +0 -40
  409. package/dist/scenarios/teacher-quickstart.js +0 -12
  410. package/dist/stores/cc/lockfile.d.ts +0 -10
  411. package/dist/stores/cc/lockfile.js +0 -98
  412. package/dist/stores/cc/mailbox-store.d.ts +0 -20
  413. package/dist/stores/cc/mailbox-store.js +0 -255
  414. package/dist/stores/cc/roster-adapter.d.ts +0 -12
  415. package/dist/stores/cc/roster-adapter.js +0 -117
  416. package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
  417. package/dist/stores/cc/sidecar-transcript.js +0 -264
  418. package/dist/stores/cc/task-list-store.d.ts +0 -2
  419. package/dist/stores/cc/task-list-store.js +0 -125
  420. package/dist/stores/file/strategy-store.d.ts +0 -97
  421. package/dist/stores/file/strategy-store.js +0 -341
@@ -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,6 +29,10 @@ 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. */
@@ -91,7 +94,8 @@ export interface ProgramPosition {
91
94
  /** The program the stream-fed chain member runs when the chain names none (`xargs` runs `echo`). */
92
95
  readonly defaultProgram?: string;
93
96
  /** The program bash RUNS: the first word past the chain. `name` is the folded word as written, `basename` what
94
- * bash resolves (`/usr/bin/cat` is `cat`). `undefined` when the chain names none or the read was refused. */
97
+ * bash resolves (`/usr/bin/cat` is `cat`). `undefined` when the chain names none (a lookup, `command -v git`, runs
98
+ * nothing) or the read was refused. */
95
99
  readonly program: {
96
100
  readonly index: number;
97
101
  readonly name: string;
@@ -99,6 +103,10 @@ export interface ProgramPosition {
99
103
  } | undefined;
100
104
  /** Why no program could be read; `undefined` beside `program: undefined` means the chain simply names none. */
101
105
  readonly refusal: ProgramPositionRefusal | undefined;
106
+ /** A launcher of the chain moves the directory or the root the program runs in, or where its word is looked up
107
+ * (`env -C <dir>`, `sudo -R <dir>`, `env -P <dirs>`): the program is still the word it names, but where its path
108
+ * operands resolve is not the command line's working directory — each consumer reads that as it must. */
109
+ readonly launcherMovesBase: boolean;
102
110
  }
103
111
  /**
104
112
  * 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, launcherOptionQueries, 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,6 +15,13 @@ 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
27
  return isShellSyntaxWord(words[i], set);
@@ -21,7 +29,7 @@ export function isBareControlWord(words, i, set) {
21
29
  export function isShellSyntaxWord(w, set) {
22
30
  return w !== undefined && w.atCommandPosition && w.raw === w.folded && set.has(w.folded);
23
31
  }
24
- export const LOOP_LIST_HEADS = new Set(["for", "select"]);
32
+ export const LOOP_LIST_HEADS = shellWordsOf("loop_list_head");
25
33
  export function isLeadingAssignmentWord(words, i) {
26
34
  const w = words[i];
27
35
  return w !== undefined && w.assignment !== undefined && w.assignment.bare && w.atCommandPosition;
@@ -30,7 +38,7 @@ function launcherRowOf(name) {
30
38
  const row = programRow(name);
31
39
  return row?.launcher !== undefined ? row : undefined;
32
40
  }
33
- function pastLauncherOptions(launcher, folded, i) {
41
+ function pastLauncherOptions(launcher, folded, i, moved, queried) {
34
42
  const row = launcherRowOf(launcher);
35
43
  if (row === undefined)
36
44
  return i;
@@ -47,7 +55,13 @@ function pastLauncherOptions(launcher, folded, i) {
47
55
  return i;
48
56
  if (step === 2 && folded[i + 1] === undefined)
49
57
  return i;
58
+ if (launcherOptionMovesBase(row, tok))
59
+ moved?.();
60
+ if (launcherOptionQueries(row, tok))
61
+ queried?.();
50
62
  i += step;
63
+ if (tok === "--")
64
+ return i;
51
65
  }
52
66
  }
53
67
  export const PROGRAM_POSITION_REFUSAL_KINDS = Object.freeze(["option_at_program_position", "control_syntax_at_program_position"]);
@@ -60,7 +74,7 @@ export function readProgramPosition(words) {
60
74
  controlWords.push(i);
61
75
  i = pastLauncherOptions(controlWord, folded, i + 1);
62
76
  }
63
- const none = (written, assignments, refusal) => ({ controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: undefined, refusal });
77
+ const none = (written, assignments, refusal) => ({ controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: undefined, refusal, launcherMovesBase: false });
64
78
  if (i >= folded.length)
65
79
  return none(undefined, []);
66
80
  const written = i;
@@ -78,25 +92,32 @@ export function readProgramPosition(words) {
78
92
  return none(written, assignments, { kind: "option_at_program_position", owner, option: head });
79
93
  }
80
94
  if (!LAUNCHER_NAMES.has(basename)) {
81
- return { controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: { index: i, name: head, basename }, refusal: undefined };
95
+ return { controlWords, written, assignments, launchers: [], argvFromStdin: false, runsDefaultProgram: false, program: { index: i, name: head, basename }, refusal: undefined, launcherMovesBase: false };
82
96
  }
83
97
  const launchers = [{ index: i, name: basename }];
84
98
  const owner = head;
85
99
  const shellRefusal = (launcher, from) => ({ kind: "control_syntax_at_program_position", owner, word: "sh", runsShell: { launcher, from } });
86
100
  let lastRow = launcherRowOf(basename)?.launcher;
87
101
  let owedOperands = lastRow?.requiredOperands ?? 0;
88
- const chain0 = (program, refusal) => ({ controlWords, written, assignments, launchers, argvFromStdin: false, runsDefaultProgram: false, program, refusal });
102
+ const chain0 = (program, refusal) => ({ controlWords, written, assignments, launchers, argvFromStdin: false, runsDefaultProgram: false, program, refusal, launcherMovesBase: false });
89
103
  if (launcherRunsShell(launcherRowOf(basename), folded.slice(i + 1)))
90
104
  return chain0(undefined, shellRefusal(i, i + 1));
91
105
  let argvFromStdin = feedsArgvFromStdin(basename);
92
106
  let lastReentry = argvFromStdin ? i : -1;
93
107
  let reentryDefault = argvFromStdin ? streamDefaultProgram(basename) : undefined;
108
+ let launcherMovesBase = false;
109
+ const moved = () => { launcherMovesBase = true; };
110
+ let looksUp = false;
111
+ const queried = () => { looksUp = true; };
94
112
  const chain = (program, refusal) => {
95
113
  const runsDefaultProgram = lastReentry === folded.length - 1;
96
- return { controlWords, written, assignments, launchers, argvFromStdin, runsDefaultProgram, ...(runsDefaultProgram && reentryDefault !== undefined ? { defaultProgram: reentryDefault } : {}), program, refusal };
114
+ return { controlWords, written, assignments, launchers, argvFromStdin, runsDefaultProgram, ...(runsDefaultProgram && reentryDefault !== undefined ? { defaultProgram: reentryDefault } : {}), program, refusal, launcherMovesBase };
97
115
  };
98
116
  const selectsShell = (l, end) => selectedOptions(launcherRowOf(l.name), folded.slice(l.index + 1, end)).some((o) => o.mode === "interactive");
99
- for (let j = pastLauncherOptions(basename, folded, i + 1); j < folded.length; j++) {
117
+ const first = pastLauncherOptions(basename, folded, i + 1, moved, queried);
118
+ if (looksUp)
119
+ return chain(undefined);
120
+ for (let j = first; j < folded.length; j++) {
100
121
  const t = folded[j];
101
122
  if (owedOperands > 0 && !t.startsWith("-")) {
102
123
  owedOperands -= 1;
@@ -121,7 +142,9 @@ export function readProgramPosition(words) {
121
142
  if (launcherRunsShell(launcherRowOf(wordBasename), folded.slice(j + 1)))
122
143
  return chain(undefined, shellRefusal(j, j + 1));
123
144
  owedOperands = lastRow?.requiredOperands ?? 0;
124
- j = pastLauncherOptions(wordBasename, folded, j + 1) - 1;
145
+ j = pastLauncherOptions(wordBasename, folded, j + 1, moved, queried) - 1;
146
+ if (looksUp)
147
+ return chain(undefined);
125
148
  continue;
126
149
  }
127
150
  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.`;
@@ -188,7 +188,7 @@ export interface HandsToolkitOptions {
188
188
  * same list as {@link import("./shell-read-check.js").ShellReadJudgeInput.readDenyHomes}. */
189
189
  readDenyHomes?: readonly string[];
190
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").readDenyHomeLinksOf} / {@link import("./read-deny-home.js").readDenyRootLinksOf},
191
+ * spelling ({@link import("./read-deny-home.js").readDenyLinksOf},
192
192
  * keyed by the row's pattern) — the Runner passes the
193
193
  * locations its own judge was compiled with, so the band and the gate judge one placement.
194
194
  * Unless a mount carries both, the band resolves the placement itself the way the Runner does (the homes it carries