@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
@@ -1,12 +1,13 @@
1
- import { releasableAskClassesFor } from "./ask-origin.js";
2
- import { canonicalizeTarget, isWinFormPath, writeTargetPath, isUncPath, isAbsoluteForFamily, joinForFamily, pathFamilyOf } from "../tools/fs/safety.js";
1
+ import { anchorSpelling, canonicalizeTarget, isAbsoluteForFamily, isWinFormPath, writeTargetPath, isUncPath, pathFamilyOf } from "../tools/fs/safety.js";
2
+ import { judgePathRows } from "./path-guard-rows.js";
3
3
  import { protectivePathTargetOf } from "./tool-registry.js";
4
4
  import { pathTargetBaseOf } from "./effective-path-target.js";
5
5
  import { canonicalDataRootKeys, dataRootSpellings, relativeUnderRoot } from "./sensitive-path-policy.js";
6
- import { symlinkChainHops } from "./path-identity.js";
6
+ import { chainHopsOrNone, symlinkChainHops } from "./path-identity.js";
7
7
  import { readDenyPatternRun } from "../tools/fs/read-deny.js";
8
8
  import { agentConfigDirSegments, agentConfigDirTail } from "./agent-config-dir.js";
9
9
  import { thrownText } from "./thrown-value.js";
10
+ import { fromSource, gateWaitFailureOf } from "./gate-bounded-await.js";
10
11
  const freezeTable = (rows) => Object.freeze(rows.map((r) => Object.freeze(r)));
11
12
  export const WRITE_PROTECTED_DEFAULT_TABLE = freezeTable([
12
13
  { name: ".gitconfig", kind: "basename" },
@@ -85,39 +86,52 @@ function describeEntryValue(v) {
85
86
  return String(v);
86
87
  }
87
88
  }
88
- function normalizeWriteProtectedEntry(entry) {
89
+ function normalizeWriteProtectedEntry(entry, owner = "writeProtectedPaths") {
89
90
  const shape = typeof entry === "string" ? { name: entry, kind: entry.includes("/") ? "segment-run" : "segment" } : entry;
90
91
  if (typeof shape !== "object" || shape === null || typeof shape.name !== "string") {
91
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} is not a name string or { name, kind } row.`);
92
+ throw new Error(`${owner}: entry ${describeEntryValue(entry)} is not a name string or { name, kind } row.`);
92
93
  }
93
94
  const name = shape.name;
94
95
  if (!KINDS.includes(shape.kind)) {
95
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} has kind ${describeEntryValue(shape.kind)} — known kinds: ${KINDS.join(", ")}.`);
96
+ throw new Error(`${owner}: entry ${describeEntryValue(entry)} has kind ${describeEntryValue(shape.kind)} — known kinds: ${KINDS.join(", ")}.`);
96
97
  }
97
98
  const kind = shape.kind;
98
99
  const { homeAnchored, run } = readDenyPatternRun(name);
99
100
  if (homeAnchored) {
100
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} opens with the home word "~", which this table does not place — its names are matched wherever their segments appear. ` +
101
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} opens with the home word "~", which this table does not place — its names are matched wherever their segments appear. ` +
101
102
  (run.length > 0 ? `Spell the name without it (${describeEntryValue(run)}), which covers the home's file and every same-named one.` : "The home directory itself is not a row; spell the name of what it holds."));
102
103
  }
103
104
  if (name.includes("*") || name.includes("?")) {
104
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a wildcard metacharacter — this table speaks LITERAL names only (a silently-literal "*" would guard less than it reads); pattern semantics live in createSensitivePathPolicy.`);
105
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} contains a wildcard metacharacter — this table speaks LITERAL names only (a silently-literal "*" would guard less than it reads); pattern semantics live in createSensitivePathPolicy.`);
105
106
  }
106
107
  if (name.includes("\\")) {
107
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a backslash — names are "/"-separated (both path families are matched); spell the segments with "/".`);
108
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} contains a backslash — names are "/"-separated (both path families are matched); spell the segments with "/".`);
108
109
  }
109
110
  const segments = name.split("/").filter((s) => s.length > 0);
110
111
  if (segments.length === 0) {
111
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains no path segments and would protect nothing — remove the entry or spell the name.`);
112
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} contains no path segments and would protect nothing — remove the entry or spell the name.`);
112
113
  }
113
114
  if (segments.some((s) => s === "." || s === "..")) {
114
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a "." or ".." segment — the judge folds dot segments lexically before matching, so such a row could never match anything; spell the real name.`);
115
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} contains a "." or ".." segment — the judge folds dot segments lexically before matching, so such a row could never match anything; spell the real name.`);
115
116
  }
116
117
  if (segments.length > 1 && kind !== "segment-run") {
117
- throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} spans ${segments.length} segments but declares kind "${kind}" — multi-segment names match as kind "segment-run".`);
118
+ throw new Error(`${owner}: entry ${describeEntryValue(name)} spans ${segments.length} segments but declares kind "${kind}" — multi-segment names match as kind "segment-run".`);
118
119
  }
119
120
  return { name: segments.join("/"), kind };
120
121
  }
122
+ export function writeProtectedEntryProblem(entry, owner) {
123
+ try {
124
+ normalizeWriteProtectedEntry(entry, owner);
125
+ return undefined;
126
+ }
127
+ catch (e) {
128
+ return e.message;
129
+ }
130
+ }
131
+ export function writeProtectedEntryIdentity(entry) {
132
+ const row = normalizeWriteProtectedEntry(entry);
133
+ return `${row.kind}:${foldWriteProtectName(row.name)}`;
134
+ }
121
135
  export function resolveWriteProtectedTable(entries) {
122
136
  if (entries === undefined)
123
137
  return WRITE_PROTECTED_DEFAULT_TABLE;
@@ -128,7 +142,7 @@ export function resolveWriteProtectedTable(entries) {
128
142
  const seen = new Set();
129
143
  for (const entry of entries) {
130
144
  const row = normalizeWriteProtectedEntry(entry);
131
- const key = `${row.kind}:${foldWriteProtectName(row.name)}`;
145
+ const key = writeProtectedEntryIdentity(row);
132
146
  if (seen.has(key))
133
147
  continue;
134
148
  seen.add(key);
@@ -185,206 +199,250 @@ function relativeUnderDataRoot(path, roots) {
185
199
  }
186
200
  return null;
187
201
  }
202
+ export function spelledExemptionOf(dataRootPaths) {
203
+ const roots = dataRootPaths.map((r) => {
204
+ const win = isWinFormPath(r);
205
+ return { win, segments: pathViewSegments(r, "literal", win ? BOTH_SEPARATOR_FAMILIES : POSIX_SEPARATOR_FAMILY, uncAnchorSegments(r)) };
206
+ });
207
+ return (spelling) => relativeUnderDataRoot(spelling, roots);
208
+ }
188
209
  export const WRITE_PROTECTION_TARGET_VIEWS = Object.freeze(["spelling-only", "target"]);
189
210
  export function compileWriteProtection(entries, opts) {
190
211
  const rows = resolveWriteProtectedTable(entries);
191
212
  if (rows.length === 0)
192
213
  return undefined;
193
- const dataRootPaths = dataRootSpellings(opts?.dataRoot);
194
- const rootViews = dataRootPaths.map((r) => {
195
- const win = isWinFormPath(r);
196
- return { win, segments: pathViewSegments(r, "literal", win ? BOTH_SEPARATOR_FAMILIES : POSIX_SEPARATOR_FAMILY, uncAnchorSegments(r)) };
197
- });
198
- const basenames = new Map();
199
- const segments = new Map();
200
- const runs = [];
214
+ const { dataRoot, ...seats } = opts ?? {};
215
+ return compileWriteJudgment(rows, entries === undefined ? "builtin" : "replacement", { ...seats, exemptRoots: dataRootSpellings(dataRoot) }).matcher;
216
+ }
217
+ export function compileLegWriteJudgment(entries, opts) {
218
+ const rows = resolveWriteProtectedTable(entries);
219
+ const compiled = compileWriteJudgment(rows, "replacement", opts);
220
+ const guardRows = opts.guardRows;
221
+ return {
222
+ matcher: rows.length === 0 ? undefined : compiled.matcher,
223
+ judgeWriteTarget: rows.length === 0 && guardRows === undefined
224
+ ? undefined
225
+ : async (target, judgeOpts) => {
226
+ const hit = await compiled.judgment(target, { ...(judgeOpts?.signal !== undefined ? { signal: judgeOpts.signal } : {}), ...(judgeOpts?.canonical === true ? { canonical: true } : {}) }, guardRows);
227
+ return hit === undefined ? undefined : hit.unreadable === undefined && TABLE_ROWS.has(hit.row) ? "protected" : "guarded";
228
+ },
229
+ };
230
+ }
231
+ const TABLE_ROWS = new WeakSet();
232
+ function heldRows(cause) {
233
+ return { name: "the deployment's guarded write rows", grammar: { kind: "segment-glob", run: "" }, polarity: "deny", faces: ["write"], placement: "anywhere", fold: "exact", exemptible: false, origin: "replacement", reach: () => ({ reach: "unreadable", reason: `the rows did not come back: ${cause}` }) };
234
+ }
235
+ function compileWriteJudgment(rows, origin, opts) {
236
+ const dataRootPaths = opts.exemptRoots;
237
+ const spelledRemainder = spelledExemptionOf(dataRootPaths);
238
+ const readingMemo = new Map();
239
+ const readingsOf = (spelling) => {
240
+ const known = readingMemo.get(spelling);
241
+ if (known !== undefined)
242
+ return known;
243
+ const raw = [pathViewSegments(spelling, "literal", POSIX_SEPARATOR_FAMILY, uncAnchorSegments(spelling)), pathViewSegments(spelling, "literal"), ...WIN32_NORMALIZATIONS.map((n) => pathViewSegments(spelling, n))];
244
+ const folded = raw.map((segs) => segs.map(foldWriteProtectSegment));
245
+ if (readingMemo.size >= 64)
246
+ readingMemo.clear();
247
+ readingMemo.set(spelling, folded);
248
+ return folded;
249
+ };
250
+ const literalRow = (row, reach, placement) => {
251
+ const minted = { name: row.name, kind: row.kind, grammar: { kind: "literal-name", match: row.kind, name: row.name }, polarity: "ask", faces: ["write"], placement, fold: "protective", exemptible: true, origin, reach };
252
+ TABLE_ROWS.add(minted);
253
+ return minted;
254
+ };
255
+ const tableRows = [];
256
+ for (const kind of KINDS) {
257
+ for (const row of rows) {
258
+ if (row.kind !== kind)
259
+ continue;
260
+ const parts = foldWriteProtectName(row.name).split("/").filter((s) => s.length > 0);
261
+ tableRows.push(literalRow(row, (view) => (readingsOf(view.path).some((segs) => literalNameMeets(kind, parts, segs)) ? REACHED : NOT_REACHED), "anywhere"));
262
+ }
263
+ }
201
264
  const configTails = [];
202
265
  for (const row of rows) {
203
- const folded = foldWriteProtectName(row.name);
204
- if (row.kind === "basename") {
205
- if (!basenames.has(folded))
206
- basenames.set(folded, row.name);
207
- }
208
- else if (row.kind === "segment") {
209
- if (!segments.has(folded))
210
- segments.set(folded, row.name);
211
- }
212
- else {
213
- runs.push({ name: row.name, parts: folded.split("/").filter((s) => s.length > 0) });
214
- }
215
266
  const tail = row.kind === "basename" ? undefined : agentConfigDirTail(row.name);
216
267
  if (tail !== undefined && opts?.agentConfigDir !== undefined)
217
- configTails.push({ hit: { name: row.name, kind: row.kind }, tail: foldWriteProtectName(tail).split("/").filter((s) => s.length > 0) });
268
+ configTails.push({ row, tail: foldWriteProtectName(tail).split("/").filter((s) => s.length > 0) });
218
269
  }
219
270
  const configRootSpelled = opts?.agentConfigDir === undefined ? [] : [agentConfigDirSegments(opts.agentConfigDir)];
220
- const judgeAtConfigRoots = (segs, roots) => {
221
- for (const root of roots) {
222
- const at = root.map(foldWriteProtectSegment);
223
- if (segs.length < at.length || !at.every((a, i) => segs[i] === a))
224
- continue;
225
- for (const { hit, tail } of configTails)
226
- if (segs.length >= at.length + tail.length && tail.every((t, i) => segs[at.length + i] === t))
227
- return hit;
228
- }
229
- return null;
271
+ const configRowsAt = (canonicalRoots) => configTails.map(({ row, tail }) => literalRow(row, (view) => {
272
+ if (!isAbsoluteForFamily("own", view.path))
273
+ return NOT_REACHED;
274
+ const roots = view.kind === "canonical" ? [...configRootSpelled, ...canonicalRoots] : configRootSpelled;
275
+ return readingsOf(view.path).some((segs) => roots.some((root) => atConfigRoot(segs, root.map(foldWriteProtectSegment), tail))) ? REACHED : NOT_REACHED;
276
+ }, { below: opts?.agentConfigDir ?? "" }));
277
+ const tableAt = (canonicalRoots) => (configTails.length === 0 ? tableRows : [...tableRows, ...configRowsAt(canonicalRoots)]);
278
+ const spelledView = (spelled, kind) => {
279
+ const remainder = spelledRemainder(spelled);
280
+ return { path: spelled, kind, ...(remainder !== null ? { exemptRemainder: remainder } : {}) };
230
281
  };
231
- const judgeSegments = (raw, configRoots) => {
232
- if (raw.length === 0)
233
- return null;
234
- const segs = raw.map(foldWriteProtectSegment);
235
- const base = basenames.get(segs[segs.length - 1] ?? "");
236
- if (base !== undefined)
237
- return { name: base, kind: "basename" };
238
- for (const s of segs) {
239
- const hit = segments.get(s);
240
- if (hit !== undefined)
241
- return { name: hit, kind: "segment" };
282
+ const anchoredSpelling = (path, cwd) => {
283
+ const base = typeof cwd === "string" && cwd.length > 0 ? cwd : undefined;
284
+ return base !== undefined ? anchorSpelling(pathFamilyOf({ cwd: base }), base, path) : path;
285
+ };
286
+ const env = opts?.env;
287
+ const rootPath = opts?.rootPath;
288
+ const judgment = async (path, ctx, extraSource) => {
289
+ let noted = false;
290
+ const noteAbsence = (cause, unresolvedSymlink) => {
291
+ if (noted)
292
+ return;
293
+ noted = true;
294
+ opts?.onViewAbsent?.({ cause, unresolvedSymlink });
295
+ };
296
+ const sourceFailed = (err, what) => {
297
+ if (gateWaitFailureOf(err) !== "aborted")
298
+ noteAbsence(what === undefined ? thrownText(err) : `${what}: ${thrownText(err)}`, false);
299
+ };
300
+ const extra = await (async () => {
301
+ if (extraSource === undefined)
302
+ return [];
303
+ const answer = await fromSource(() => extraSource({ ...(env !== undefined ? { env } : {}), ...(ctx.signal !== undefined ? { signal: ctx.signal } : {}) }), ctx.signal, "deploymentRows");
304
+ if (answer.ok)
305
+ return answer.value;
306
+ sourceFailed(answer.cause, "the deployment's guarded write rows did not come back, so the writes they could guard are not placed");
307
+ return [heldRows(thrownText(answer.cause))];
308
+ })();
309
+ const givenKey = ctx.canonical === true && env !== undefined;
310
+ const base = ctx.base ?? ctx.cwd ?? rootPath;
311
+ const lexical = givenKey ? undefined : spelledView(anchoredSpelling(path, ctx.base ?? ctx.cwd), "lexical");
312
+ const bySpelling = lexical === undefined ? undefined : judgePathRows([...tableAt([]), ...extra], { views: [lexical] }, "tighten");
313
+ if (bySpelling !== undefined && bySpelling.unreadable === undefined && TABLE_ROWS.has(bySpelling.row))
314
+ return bySpelling;
315
+ if (env === undefined)
316
+ return bySpelling;
317
+ const family = pathFamilyOf({ root: rootPath, cwd: ctx.cwd ?? env.cwd });
318
+ const rootLookupFailed = (err) => sourceFailed(err, "a root's key did not come back, so that root takes no part");
319
+ let canonKey = givenKey ? path : undefined;
320
+ let canonAliased = false;
321
+ let targetUnread;
322
+ let targetUnreadSymlink = false;
323
+ if (!givenKey) {
324
+ const answer = await fromSource(() => canonicalizeTarget(env, path, ctx.signal, family, base), ctx.signal, "canonicalTarget");
325
+ if (!answer.ok) {
326
+ sourceFailed(answer.cause);
327
+ targetUnread = thrownText(answer.cause);
328
+ }
329
+ else if (answer.value.ok) {
330
+ canonKey = answer.value.key;
331
+ canonAliased = answer.value.aliasResolved === true;
332
+ }
333
+ else {
334
+ noteAbsence(answer.value.message, answer.value.unresolvedSymlink === true);
335
+ targetUnread = answer.value.message;
336
+ targetUnreadSymlink = answer.value.unresolvedSymlink === true;
337
+ }
242
338
  }
243
- for (const run of runs) {
244
- const n = run.parts.length;
245
- for (let i = 0; i + n <= segs.length; i++) {
246
- if (run.parts.every((p, j) => segs[i + j] === p))
247
- return { name: run.name, kind: "segment-run" };
339
+ const canonicalRoots = canonKey === undefined || configTails.length === 0 || opts?.agentConfigDir === undefined ? [] : (await canonicalDataRootKeys(env, [opts.agentConfigDir], ctx.signal, rootLookupFailed)).map(agentConfigDirSegments);
340
+ const table = [...tableAt(canonicalRoots), ...extra];
341
+ const aliased = canonAliased ? { aliasResolved: true } : {};
342
+ const views = [...(lexical !== undefined ? [{ ...lexical, ...aliased }] : []), ...(canonKey !== undefined ? [{ path: canonKey, kind: "canonical", ...aliased }] : [])];
343
+ const identity = {};
344
+ const identityRemainder = () => (identity.asked ??= (async () => {
345
+ if (canonKey === undefined)
346
+ return undefined;
347
+ for (const rootKey of await canonicalDataRootKeys(env, dataRootPaths, ctx.signal, rootLookupFailed)) {
348
+ const relative = relativeUnderRoot(canonKey, rootKey);
349
+ if (relative !== null)
350
+ return relative;
248
351
  }
352
+ return undefined;
353
+ })());
354
+ const judged = async () => {
355
+ const unread = targetUnread !== undefined ? { unreadable: targetUnread } : {};
356
+ const hit = judgePathRows(table, { views, ...unread }, "tighten");
357
+ if (hit === undefined)
358
+ return undefined;
359
+ const relative = await identityRemainder();
360
+ const final = relative === undefined ? hit : judgePathRows(table, { views: views.map((v) => (v.kind === "canonical" ? { ...v, exemptRemainder: relative } : v)), identityExempt: true, ...unread }, "tighten");
361
+ return final !== undefined && final.unreadable !== undefined && targetUnread !== undefined && targetUnreadSymlink ? { ...final, unresolvedSymlink: true } : final;
362
+ };
363
+ const byTarget = canonKey === undefined ? undefined : await judged();
364
+ if (byTarget !== undefined && byTarget.unreadable === undefined && TABLE_ROWS.has(byTarget.row))
365
+ return byTarget;
366
+ if (givenKey)
367
+ return byTarget;
368
+ if (identity.asked !== undefined && (await identity.asked) !== undefined && table.every((row) => row.exemptible))
369
+ return byTarget;
370
+ const chain = await fromSource(() => symlinkChainHops(env, path, ctx.signal, family, base), ctx.signal, "canonicalChain");
371
+ if (!chain.ok) {
372
+ sourceFailed(chain.cause);
373
+ targetUnread ??= thrownText(chain.cause);
249
374
  }
250
- return configTails.length === 0 ? null : judgeAtConfigRoots(segs, configRoots);
251
- };
252
- const judgeViews = (spelling, configRoots = configRootSpelled) => {
253
- const posix = judgeSegments(pathViewSegments(spelling, "literal", POSIX_SEPARATOR_FAMILY, uncAnchorSegments(spelling)), configRoots);
254
- if (posix !== null)
255
- return posix;
256
- const bothSeparators = judgeSegments(pathViewSegments(spelling, "literal"), configRoots);
257
- if (bothSeparators !== null)
258
- return bothSeparators;
259
- for (const normalization of WIN32_NORMALIZATIONS) {
260
- const hit = judgeSegments(pathViewSegments(spelling, normalization), configRoots);
261
- if (hit !== null)
262
- return hit;
375
+ else {
376
+ if (!chain.value.ok && chain.value.asked) {
377
+ noteAbsence(chain.value.cause, false);
378
+ targetUnread ??= chain.value.cause;
379
+ }
380
+ for (const hop of chainHopsOrNone(chain.value))
381
+ views.push(spelledView(hop, "hop"));
263
382
  }
264
- return null;
265
- };
266
- const judgeSpelled = (spelled) => {
267
- const remainder = relativeUnderDataRoot(spelled, rootViews);
268
- return remainder === null ? judgeViews(spelled) : judgeViews(remainder, []);
383
+ return judged();
269
384
  };
270
- const judgeSpelling = (path, cwd) => {
271
- const base = typeof cwd === "string" && cwd.length > 0 ? cwd : undefined;
272
- const family = pathFamilyOf({ cwd: base });
273
- const spelled = base !== undefined && family !== undefined && !isAbsoluteForFamily(family, path) ? joinForFamily(family, base, path) : path;
274
- return judgeSpelled(spelled);
275
- };
276
- const env = opts?.env;
277
- const rootPath = opts?.rootPath;
278
- return {
385
+ const matcher = {
279
386
  rows,
280
387
  targetView: env === undefined ? "spelling-only" : "target",
281
388
  matchPath(path, cwd) {
282
- return judgeSpelling(path, cwd);
389
+ const hit = judgePathRows(tableAt([]), { views: [spelledView(anchoredSpelling(path, cwd), "lexical")] }, "tighten");
390
+ return hit === undefined ? null : { name: hit.row.name, kind: hit.row.kind };
283
391
  },
284
392
  async judge(path, ctx = {}) {
285
- const givenKey = ctx.canonical === true && env !== undefined;
286
- const bySpelling = givenKey ? null : judgeSpelling(path, ctx.cwd);
287
- if (bySpelling !== null)
288
- return { kind: "hit", hit: bySpelling, via: "spelling" };
289
- if (env === undefined)
393
+ const hit = await judgment(path, ctx);
394
+ if (hit === undefined)
290
395
  return { kind: "clear" };
291
- const family = pathFamilyOf({ root: rootPath, cwd: ctx.cwd ?? env.cwd });
292
- const base = ctx.base ?? ctx.cwd ?? rootPath;
293
- let noted = false;
294
- const noteAbsence = (cause, unresolvedSymlink) => {
295
- if (noted)
296
- return;
297
- noted = true;
298
- opts?.onViewAbsent?.({ cause, unresolvedSymlink });
299
- };
300
- let canonKey = givenKey ? path : undefined;
301
- if (!givenKey) {
302
- try {
303
- const canon = await canonicalizeTarget(env, path, ctx.signal, family, base);
304
- if (canon.ok)
305
- canonKey = canon.key;
306
- else
307
- noteAbsence(canon.message, canon.unresolvedSymlink === true);
308
- }
309
- catch (err) {
310
- noteAbsence(thrownText(err), false);
311
- }
312
- }
313
- try {
314
- if (canonKey !== undefined) {
315
- const canonicalRoots = configTails.length === 0 || opts?.agentConfigDir === undefined ? [] : (await canonicalDataRootKeys(env, [opts.agentConfigDir], ctx.signal)).map(agentConfigDirSegments);
316
- const byTarget = judgeViews(canonKey, [...configRootSpelled, ...canonicalRoots]);
317
- if (byTarget !== null) {
318
- for (const rootKey of await canonicalDataRootKeys(env, dataRootPaths, ctx.signal)) {
319
- const relative = relativeUnderRoot(canonKey, rootKey);
320
- if (relative === null)
321
- continue;
322
- if (relative === "")
323
- return { kind: "clear" };
324
- const remainder = judgeViews(relative, []);
325
- return remainder === null ? { kind: "clear" } : { kind: "hit", hit: remainder, via: "target" };
326
- }
327
- return { kind: "hit", hit: byTarget, via: "target" };
328
- }
329
- }
330
- for (const hop of givenKey ? [] : await symlinkChainHops(env, path, ctx.signal, family, base, (cause) => noteAbsence(cause, false))) {
331
- const byHop = judgeSpelled(hop);
332
- if (byHop === null)
333
- continue;
334
- if (canonKey !== undefined) {
335
- for (const rootKey of await canonicalDataRootKeys(env, dataRootPaths, ctx.signal)) {
336
- if (relativeUnderRoot(canonKey, rootKey) !== null)
337
- return { kind: "clear" };
338
- }
339
- }
340
- return { kind: "hit", hit: byHop, via: "chain" };
341
- }
342
- }
343
- catch (err) {
344
- noteAbsence(thrownText(err), false);
345
- }
346
- return { kind: "clear" };
396
+ if (hit.unreadable !== undefined)
397
+ return { kind: "unresolvable", cause: hit.unreadable, unresolvedSymlink: hit.unresolvedSymlink === true };
398
+ return verdictOf(hit);
347
399
  },
348
400
  };
401
+ return { matcher, judgment };
349
402
  }
350
- export function writeProtectionTightenDecision(toolName, verdict, face) {
351
- if (verdict.kind === "hit") {
352
- return {
353
- action: "ask",
354
- message: verdict.via === "target"
355
- ? `tool "${toolName}" writes to a write-protected path — its real target resolves onto table entry "${verdict.hit.name}" — explicit approval required`
356
- : verdict.via === "chain"
357
- ? `tool "${toolName}" writes to a write-protected path — its symlink chain passes through table entry "${verdict.hit.name}" — explicit approval required`
358
- : `tool "${toolName}" writes to a write-protected path (table entry "${verdict.hit.name}") — explicit approval required`,
359
- decisionReason: "safety",
360
- };
361
- }
403
+ const REACHED = { reach: "reached" };
404
+ const NOT_REACHED = { reach: "not_reached" };
405
+ function literalNameMeets(kind, parts, segs) {
406
+ if (segs.length === 0)
407
+ return false;
408
+ if (kind === "basename")
409
+ return segs[segs.length - 1] === parts[0];
410
+ if (kind === "segment")
411
+ return segs.includes(parts[0]);
412
+ for (let i = 0; i + parts.length <= segs.length; i++)
413
+ if (parts.every((p, j) => segs[i + j] === p))
414
+ return true;
415
+ return false;
416
+ }
417
+ function atConfigRoot(segs, root, tail) {
418
+ return segs.length >= root.length + tail.length && root.every((a, i) => segs[i] === a) && tail.every((t, i) => segs[root.length + i] === t);
419
+ }
420
+ function verdictOf(hit) {
421
+ return { kind: "hit", hit: { name: hit.row.name, kind: hit.row.kind }, via: hit.viewKind === "canonical" ? "target" : hit.viewKind === "hop" ? "chain" : "spelling" };
422
+ }
423
+ export function writeProtectionTightenDecision(toolName, verdict) {
424
+ if (verdict.kind === "clear")
425
+ return undefined;
362
426
  if (verdict.kind === "unresolvable") {
363
- if (releasableAskClassesFor(face).includes("write_protection_unresolved")) {
364
- return {
365
- action: "ask",
366
- message: verdict.unresolvedSymlink
367
- ? `tool "${toolName}" writes to a symlink whose real target could not be resolved, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause}) — explicit approval required`
368
- : `tool "${toolName}" writes to a target that could not be resolved on this tree, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause}) — explicit approval required`,
369
- decisionReason: "safety",
370
- };
371
- }
372
427
  return {
373
428
  action: "deny",
374
- message: verdict.unresolvedSymlink
375
- ? `tool "${toolName}" is blocked: its target is a symlink whose real target could not be resolved, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause})`
376
- : `tool "${toolName}" is blocked: its target could not be resolved on this tree, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause})`,
429
+ message: `tool "${toolName}" is refused (target_unresolved): where its write target leads on disk could not be determined${verdict.unresolvedSymlink ? " (a link on the way could not be followed)" : ""}, so the write-protected table cannot tell whether it lands on a protected path — ${verdict.cause}`,
377
430
  decisionReason: "safety",
378
431
  };
379
432
  }
380
- return undefined;
433
+ return {
434
+ action: "ask",
435
+ message: verdict.via === "target"
436
+ ? `tool "${toolName}" writes to a write-protected path — its real target resolves onto table entry "${verdict.hit.name}" — explicit approval required`
437
+ : verdict.via === "chain"
438
+ ? `tool "${toolName}" writes to a write-protected path — its symlink chain passes through table entry "${verdict.hit.name}" — explicit approval required`
439
+ : `tool "${toolName}" writes to a write-protected path (table entry "${verdict.hit.name}") — explicit approval required`,
440
+ decisionReason: "safety",
441
+ };
381
442
  }
382
443
  export function writeProtectionMandated(verdict) {
383
444
  return verdict.kind === "hit";
384
445
  }
385
- export function writeProtectionUnresolved(verdict) {
386
- return verdict.kind === "unresolvable";
387
- }
388
446
  export function createWriteProtectionCheck(entries, opts) {
389
447
  const matcher = compileWriteProtection(entries, opts);
390
448
  return matcher === undefined ? undefined : writeProtectionMountOver(matcher, opts?.rootPath);
@@ -450,8 +450,8 @@ export interface CompactionPreparation {
450
450
  * (raised in review as a contradiction; it is not one, but it was unstated). Byte-identity is
451
451
  * over the SUMMARIZATION REQUEST ASSEMBLY, and there it is exact. Registering
452
452
  * `<instruction-files>` in the authority census additionally puts it in the derived
453
- * fenced/shelled-lane sets, so external bytes that literally spell the tag are now defused with a
454
- * ZWSP on those lanes — for every deployment, seat or no seat. That is not a compatibility break
453
+ * fenced/shelled-lane sets, so external bytes that literally spell the tag are now defused (an
454
+ * entity in the bracket's place) on those lanes — for every deployment, seat or no seat. That is not a compatibility break
455
455
  * smuggled in: those lanes rewrite bytes BY CONTRACT (that is what makes them fences), it is what
456
456
  * registering any new authority envelope means in this tree, and the alternative — a
457
457
  * model-facing authority tag that the fences built to defuse forgeries do not defuse — is
@@ -8,21 +8,6 @@ import type { SchedulerCapability, ScheduledIntent, SchedulerContext, ScheduledT
8
8
  import { SchedulerError } from "../../core/scheduler.js";
9
9
  /** Convert user-facing timeout seconds into a positive, timer-safe millisecond delay. */
10
10
  export declare function resolveExecTimeoutMs(timeoutSeconds: unknown): number | undefined;
11
- /**
12
- * Anchor a RELATIVE symlink target at its link's own directory, UNFOLDED and with exactly one separator
13
- * between the two. A directory that IS a root already ends in its own separator (`/`, `C:\`, `C:/`,
14
- * `\\host\share\`, all of which `dirname` answers that way), and concatenating a second one mints a
15
- * DOUBLE-separator spelling for a path that has one spelling — `/tmp -> private/tmp` came back as
16
- * `//private/tmp`, which the judges that walk this chain then match against nothing, because a guarded row
17
- * and a containment root are both written with single separators. Joining through `path.resolve`/`path.join`
18
- * would fix the separator and fold `..` with it, which is the one thing this walk may not do.
19
- *
20
- * `separator` is the one the caller's `dirname` writes, passed rather than read from the module so the rule
21
- * is a pure function of its inputs. A backslash counts as a terminator only where it IS a separator: on a
22
- * POSIX tree a directory whose name ends in one (`/a/b\`) is an ordinary name, and reading it as terminated
23
- * would rename `/a/b\/t` to `/a/b\t` — the same class of rewrite as folding `..` lexically.
24
- */
25
- export declare function anchorAtLinkDir(linkDir: string, target: string, separator: string): string;
26
11
  /** review finding (win32): `where bash.exe` can resolve to `System32\bash.exe` — the
27
12
  * WSL LAUNCHER, not a native shell. Running it drops into a Linux subsystem where Windows cwd/paths
28
13
  * do not exist; silently adopting it is exactly the "wrong shell, false green" failure D1 forbids.
@@ -99,6 +84,9 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
99
84
  /** `ExecutionEnv.homeDir` = the `HOME` the shell child receives (its `~`/`$HOME`/`${HOME}` all expand to it), read LIVE off the same `shellEnv`-over-`inheritEnv` merge each exec gets; ABSENT when the
100
85
  * child gets none (an allowlist that withholds it: `~` then falls back to passwd while `$HOME` is empty — two values, no single home, home-relative operands stay fail-closed). Residual: a per-exec `env.HOME` override. */
101
86
  get homeDir(): string | undefined;
87
+ /** `ExecutionEnv.cdPath` = the `CDPATH` the shell child receives, read LIVE off the same merge each exec gets (never the
88
+ * engine process's own environment): its entries, `[]` when the child gets none. Residual: a per-exec `env.CDPATH`. */
89
+ get cdPath(): readonly string[];
102
90
  private shellPath?;
103
91
  private shellEnv?;
104
92
  private inheritEnv;
@@ -194,14 +182,8 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
194
182
  fileIdentity(path: string): Promise<Result<string, FileError>>;
195
183
  readLink(path: string): Promise<Result<string, FileError>>;
196
184
  /**
197
- * The LEAF symlink chain ({@link FileSystem.canonicalChain}): `readlink` on the whole spelling, then on each
198
- * target, until a hop is not a link (`EINVAL`), is absent (`ENOENT` / `ENOTDIR`), repeats, or the bound is
199
- * reached. A relative target is ANCHORED at its link's directory and never folded — `..` is the filesystem's
200
- * to resolve during the next `readlink`'s own lookup (a lexical fold reads `bridge/../next` as `next` and misses
201
- * every link behind `bridge`). Anchoring puts EXACTLY ONE separator between the directory and the target
202
- * ({@link anchorAtLinkDir}); a root directory already ends in its own. One syscall per hop, no `lstat`. On a
203
- * win32 host a share-shaped hop is kept and ends the walk unprobed. Any other errno is an answer nobody can
204
- * use (`err`), never a shortened chain.
185
+ * The LEAF symlink chain ({@link FileSystem.canonicalChain}): {@link walkSymlinkChain} over {@link readLinkTarget}
186
+ * (not the `readLink` method: a wrapper counting or overriding it sees only a caller's own calls).
205
187
  */
206
188
  canonicalChain(path: string): Promise<Result<SymlinkChain, FileError>>;
207
189
  exists(path: string): Promise<Result<boolean, FileError>>;