@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,13 +1,15 @@
1
1
  import { lexShell, PARSE_FAILURE_SENTENCE, substitutionsInHeredocBody, literalTextOf, literalTildeSpelling, } from "../../shell/lex.js";
2
2
  import { programTextOf, readOfText, readsOf, rewritten, segmentReadingsOf, settledFieldsOf, spelledWithHome, isArithmeticBody, unreadableSentenceOf } from "./shell-read-word.js";
3
3
  import { assignmentArithmetic, bare, listedVerbCandidates, pathSubcommandOf, programTextSentence, pushAssignment, roleReads, subscriptOnly, unlistedWords } from "./shell-read-argv.js";
4
- import { ARITHMETIC_TEST_OPERATORS, BindingThread, arithmeticSubstitutions, isArithmeticCommand, bindingEffectOf, loopListHeadAt, parameterBodySubstitutions, projectSegment, valueOf, } from "./shell-read-bindings.js";
5
- import { isShellSyntaxWord, programBasename, programPositionRunsShell, readProgramPosition, shellScanDeclineOf, } from "./bash-program-position.js";
4
+ import { ARITHMETIC_TEST_OPERATORS, BindingThread, arithmeticSubstitutions, isArithmeticCommand, bindingEffectOf, joinRebound, loopListHeadAt, namesBoundIn, parameterBodySubstitutions, projectSegment, valueOf, } from "./shell-read-bindings.js";
5
+ import { commandEnvironmentNames, isShellSyntaxWord, programBasename, programPositionRunsShell, readProgramPosition, shellScanDeclineOf, } from "./bash-program-position.js";
6
+ import { WorkdirThread, baseShiftOf, textCalls, textMayMove, textMovesOf, textSetsPhysical, withCommandEnvironment } from "./shell-read-workdir.js";
6
7
  import { POLL_LOOP_MAX_BEATS, attachedOptionPayloads, resolveOperandLexically, isPathShapedToken, programTextSlotFiles, } from "./bash-readonly-classifier.js";
7
- import { BLOCK_WORD_NAMES, commandLineOf, commandLineOptionSpellings, declaredAttributes, isDeclarationBuiltin, isInertBuiltin, launcherOptionPathRole, launcherOptionStep, readOptionRole, programLanguageOf, programTextOpensOf, selectedOptions, movesBaseUnfollowed, opensNoOperand, programDelivery, programRow, readArgRoles, runsShellText, } from "./program-read-model.js";
8
- import { isAbsolutePathForm } from "./safety.js";
9
- import { codeBodies, launchedInput, pipedTextOf, reentryText, scriptFileAt, stdinTextsOf } from "./shell-reentry-text.js";
10
- import { plannedOnce, rebasePlan, startedAt, stdinFeeds } from "./shell-read-start.js";
8
+ import { BLOCK_WORD_NAMES, commandLineOf, commandLineOptionSpellings, declaredAttributes, isDeclarationBuiltin, isInertBuiltin, launcherOptionPathRole, launcherOptionStep, readOptionRole, programLanguageOf, programTextOpensOf, selectedOptions, movesBaseByStack, opensNoOperand, programDelivery, programRow, readArgRoles, runsShellText, } from "./program-read-model.js";
9
+ import { shellWordsOf } from "../../shell/shell-words.js";
10
+ import { isAbsoluteForFamily } from "./safety.js";
11
+ import { codeBodies, launchedInput, reentryText, scriptFileAt, stdinTextsOf } from "./shell-reentry-text.js";
12
+ import { heldAt, plannedOnce, rebasePlan, startedAt, stdinFeeds } from "./shell-read-start.js";
11
13
  export const READ_CANDIDATE_PROVENANCES = Object.freeze([
12
14
  "operand",
13
15
  "option_value",
@@ -23,22 +25,26 @@ export const READ_CANDIDATE_PROVENANCES = Object.freeze([
23
25
  "object_path",
24
26
  ]);
25
27
  const NESTING_MAX = 4;
26
- const LOOP_END = new Set(["done"]), COPROC = new Set(["coproc"]);
27
- const BASE_CANDIDATE_MAX = 256;
28
+ const LOOP_END = shellWordsOf("loop_end"), LOOP_CONDITION = shellWordsOf("loop_condition"), COPROC = shellWordsOf("background"), RESERVED = shellWordsOf("rule_reserved");
28
29
  export function planShellReads(command, decl, depth = 0, start) {
30
+ return planText(command, decl, depth, start).plan;
31
+ }
32
+ function planText(command, decl, depth, start, from) {
29
33
  const shape = { grouped: false, backgrounded: false, strayRedirection: false };
30
34
  if (depth > NESTING_MAX)
31
- return { segments: [], unreadable: `command text nested more than ${NESTING_MAX} levels deep`, shape };
35
+ return { plan: { segments: [], unreadable: `command text nested more than ${NESTING_MAX} levels deep`, shape }, end: "unmodelled", physical: false };
32
36
  const lexed = lexShell(command);
33
37
  if ("parseFailure" in lexed)
34
- return { segments: [], unreadable: PARSE_FAILURE_SENTENCE[lexed.parseFailure.reason], shape };
38
+ return { plan: { segments: [], unreadable: PARSE_FAILURE_SENTENCE[lexed.parseFailure.reason], shape }, end: "unmodelled", physical: false };
35
39
  const unreadable = unreadableSentenceOf(lexed, command);
36
40
  const projected = lexed.segments.map((segment) => projectSegment(segment));
37
41
  const named = projected.map((p, si) => bindingEffectOf(lexed.segments[si], p.argv, p, () => "unknown"));
38
42
  const boundHere = (name) => named.some((e) => e.all === "unknown" || e.bindings.some((b) => b.name === name));
39
43
  const boundAnywhere = (name) => boundHere(name) || start?.boundAnywhere(name) === true;
40
44
  const declaredHome = decl.homeDir !== undefined ? [{ spelled: decl.homeDir }] : "unknown";
41
- const initial = start?.initial ?? ((name) => (name === "HOME" ? declaredHome : "unknown"));
45
+ const declaredCdPath = decl.cdPath === "unknown" ? "unknown" : [{ spelled: (decl.cdPath ?? []).join(":") }];
46
+ const declared = (name, rebound) => (rebound ? "unknown" : name === "HOME" ? declaredHome : name === "CDPATH" ? declaredCdPath : "unknown");
47
+ const initial = start?.initial ?? ((name) => declared(name, false));
42
48
  const loopShapes = projected.map((p) => loopShapeOf(p));
43
49
  const loopEndOf = new Map();
44
50
  {
@@ -53,26 +59,35 @@ export function planShellReads(command, decl, depth = 0, start) {
53
59
  }
54
60
  });
55
61
  }
56
- const names = new BindingThread(lexed.segments, named, initial, boundAnywhere, loopEndOf, start?.homeTouched === true, start?.inherited);
57
- const laterStart = { initial: (name) => (name === "HOME" && !boundAnywhere("HOME") ? declaredHome : "unknown"), boundAnywhere, homeTouched: boundAnywhere("HOME"), inherited: names.inheritedAt() };
58
- const nestedPlanner = (table) => (text, kind, at) => planShellReads(text, decl, depth + 1, kind === "substitution" ? { initial: (name) => table.stateOf(name), boundAnywhere, homeTouched: table.homeTouched, inherited: table.inherited } : startedAt(laterStart, at));
62
+ const names = new BindingThread(lexed.segments, named, initial, boundAnywhere, loopEndOf, start?.homeTouched === true, start?.inherited, start?.names);
63
+ const laterStart = { initial: (name) => declared(name, boundAnywhere(name)), boundAnywhere, homeTouched: boundAnywhere("HOME"), inherited: names.inheritedAt() };
64
+ const nestedPlanner = (table, si) => (text, kind, at) => planShellReads(text, decl, depth + 1, kind === "substitution" ? { initial: (name) => table.stateOf(name), boundAnywhere, homeTouched: table.homeTouched, inherited: table.inherited, thread: heldThread(moves.functions), names: heldAt(table) } : startedAt(kind === "now" ? { ...laterStart, inherited: { ...laterStart.inherited, rebound: joinRebound(table.inherited.rebound, commandEnvironmentNames(projected[si].argv)) }, ...(readProgramPosition(projected[si].argv).program?.basename === "eval" ? { thread: heldThread(moves.unread), names: heldAt(table, names.functionBound()) } : {}) } : { ...laterStart, thread: heldThread(moves.functions, workdir.mayBePhysical || moves.physicalAt.some(Boolean)), names: names.heldAnywhere() }, at));
59
65
  const empty = lexed.segments.map((segment, si) => segmentIsEmpty(segment, projected[si]));
60
66
  const facts = projected.map(() => undefined);
61
67
  const tables = projected.map(() => undefined);
62
- const fedAt = stdinFeeds(lexed.segments, start?.stdin ?? [], (si) => (facts[si - 1] === undefined ? [projected[si - 1].argv] : (facts[si - 1].readings ?? [facts[si - 1]]).map((f) => f.argv)).map((argv) => pipedTextOf(lexed.segments[si - 1], argv)));
68
+ const fedAt = stdinFeeds(lexed.segments, start?.stdin ?? [], (si) => [{ from: `${lexed.segments[si - 1].text.trim()} |` }]);
63
69
  const factsAt = (si, table) => {
64
70
  tables[si] ??= table;
65
- return (facts[si] ??= segmentFacts(lexed.segments[si], projected[si], decl, table, nestedPlanner(table), fedAt(si)));
71
+ return (facts[si] ??= segmentFacts(lexed.segments[si], projected[si], decl, table, nestedPlanner(table, si), fedAt(si)));
66
72
  };
67
73
  const basesOf = projected.map(() => new Set());
68
74
  const unmodelled = projected.map(() => false);
69
- let candidates = (start?.bases !== undefined && start.bases !== "unmodelled" ? start.bases : [decl.cwd]).map((base) => ({ base, skippedCd: -1 }));
70
- let baseLost = start?.bases === "unmodelled";
71
- let floorBases;
72
- const loseBase = (reachable, floorTarget) => {
73
- baseLost = true;
74
- floorBases ??= [...new Set([...reachable.map((c) => c.base), ...(floorTarget !== undefined ? [floorTarget] : [])])];
75
+ const moves = textMovesOf(new Set(projected.flatMap((p) => p.defines)), projected.map((p) => p.argv), (si) => names.inFunctionBody(si), start?.thread);
76
+ names.runsBodies(moves.runsBodyAt, moves.bodiesAt.some((b) => b.length > 0), moves.mayCallAt.map((c, si) => (c ? commandEnvironmentNames(projected[si].argv) : undefined)));
77
+ const workdir = new WorkdirThread(from ?? start?.bases ?? [decl.cwd], depth === 0 || start?.bases !== undefined || from !== undefined, start?.thread?.physical === true);
78
+ const workdirContext = {
79
+ ...(decl.homeDir !== undefined ? { homeDir: decl.homeDir } : {}),
80
+ textBinds: boundAnywhere,
81
+ evalEnd: (text, c, table) => {
82
+ if (moves.bodyMoves && textCalls(text, moves.functions))
83
+ return { end: "unmodelled", physical: false };
84
+ if (!textMayMove(text, moves.functions) && !textSetsPhysical(text))
85
+ return { end: [c], physical: false };
86
+ const ran = planText(text, decl, depth + 1, { initial: (name) => table.stateOf(name), boundAnywhere, homeTouched: table.homeTouched, inherited: table.inherited, thread: heldThread(moves.unread), names: heldAt(table, names.functionBound()) }, [c]);
87
+ return { end: ran.end, physical: ran.physical };
88
+ },
75
89
  };
90
+ const heldThread = (unread, physical = workdir.mayBePhysical) => ({ physical, functions: moves.functions, unread });
76
91
  let andRunStart = 0;
77
92
  let crossedAllAnd = true;
78
93
  let crossedAnyOr = false;
@@ -89,55 +104,28 @@ export function planShellReads(command, decl, depth = 0, start) {
89
104
  }
90
105
  if (empty[si]) {
91
106
  if (!replay)
92
- factsAt(si, names.tableAt(si, andRunStart));
107
+ factsAt(si, names.tableAt(si, andRunStart, workdir.where(andRunStart)));
93
108
  return;
94
109
  }
95
110
  if (previousEmitted >= 0 && !crossedAllAnd)
96
111
  andRunStart = crossedAnyOr ? si + 1 : si;
97
- const f = replay ? facts[si] : factsAt(si, names.tableAt(si, andRunStart));
98
- const pipeFed = f.connector === "|" || lexed.segments[si + 1]?.connector === "|";
99
- reaches[si] ??= { andJoined: previousEmitted >= 0 && crossedAllAnd, orBroken: !crossedAllAnd && crossedAnyOr, moveProvable: f.moveProvable && !replay && !pipeFed };
112
+ const f = replay ? facts[si] : factsAt(si, names.tableAt(si, andRunStart, workdir.where(andRunStart)));
113
+ const pipeFed = f.connector === "|" || lexed.segments[si + 1]?.connector === "|", call = moves.callAt(si, tables[si]);
114
+ reaches[si] ??= { andJoined: previousEmitted >= 0 && crossedAllAnd, orBroken: !crossedAllAnd && crossedAnyOr, moveProvable: f.moveProvable && !replay && !pipeFed && !names.runsApart(si) };
100
115
  crossedAllAnd = true;
101
116
  crossedAnyOr = false;
102
117
  previousEmitted = si;
103
- const reachable = candidates.filter((c) => c.skippedCd < andRunStart);
104
- if (baseLost)
118
+ if (workdir.lost)
105
119
  unmodelled[si] = true;
106
120
  else
107
- for (const c of reachable)
121
+ for (const c of workdir.reachable(andRunStart))
108
122
  basesOf[si].add(c.base);
109
- const move = f.baseMove;
110
- if (move === undefined || baseLost)
111
- return;
112
- if (typeof move.target === "string" || move.target.expands !== false) {
113
- loseBase(reachable, typeof move.target !== "string" ? move.target.floorSpelled : move.target === "home" ? decl.homeDir : undefined);
114
- return;
115
- }
116
- const target = move.target.spelled;
117
- const provable = reaches[si].moveProvable;
118
- const branched = [];
119
- for (const c of candidates) {
120
- if (c.skippedCd < andRunStart) {
121
- const moved = joinBase(c.base, target, decl.homeDir);
122
- if (moved === undefined) {
123
- loseBase(reachable);
124
- return;
125
- }
126
- branched.push({ base: moved, skippedCd: c.skippedCd });
127
- }
128
- branched.push({ base: c.base, skippedCd: provable ? si : c.skippedCd });
129
- }
130
- const byBase = new Map();
131
- for (const c of branched) {
132
- const prior = byBase.get(c.base);
133
- if (prior === undefined || c.skippedCd < prior.skippedCd)
134
- byBase.set(c.base, c);
135
- }
136
- const next = [...byBase.values()];
137
- if (next.length > BASE_CANDIDATE_MAX)
138
- loseBase(reachable);
139
- else
140
- candidates = next;
123
+ if (moves.physicalAt[si])
124
+ workdir.setPhysical();
125
+ if (f.shift !== undefined && call !== "named")
126
+ workdir.shift(si, { shift: f.shift, provable: reaches[si].moveProvable && call === undefined, andRunStart, table: withCommandEnvironment(tables[si], projected[si].argv), cdable: moves.cdableFrom >= 0 && si > moves.cdableFrom }, workdirContext);
127
+ if (moves.losesBaseAt(si, tables[si]))
128
+ workdir.lose(si, workdir.reachable(andRunStart));
141
129
  };
142
130
  const bind = (si) => {
143
131
  const table = tables[si];
@@ -146,12 +134,16 @@ export function planShellReads(command, decl, depth = 0, start) {
146
134
  const end = loopEndOf.get(si);
147
135
  if (end !== undefined) {
148
136
  const body = named.slice(si + 1, end);
149
- names.kill(si, body.some((e) => e.all === "unknown") ? "all" : body.flatMap((e) => e.bindings.map((b) => b.name)));
137
+ names.kill(si, body.some((e) => e.all === "unknown") ? "all" : [...body.flatMap((e) => e.bindings.map((b) => b.name)), ...(moves.mayMove.slice(si + 1, end).some(Boolean) ? ["PWD", "OLDPWD"] : [])]);
150
138
  }
151
139
  const segment = lexed.segments[si];
152
- const effect = bindingEffectOf(segment, projected[si].argv, projected[si], (w, quoted, overlay) => valueOf(w, table, quoted, overlay));
140
+ const effect = bindingEffectOf(segment, projected[si].argv, projected[si], (w, quoted, overlay) => valueOf(w, table, quoted, overlay), moves.callAt(si, table), (builtin) => table.builtinState(builtin));
153
141
  const { all, ...rest } = effect;
154
142
  names.apply(si, all === "reset" ? rest : effect, segment.connector === "&&" || segment.connector === "||", end);
143
+ if (moves.callAt(si, table) !== undefined)
144
+ names.kill(si, moves.callsUnread(si, table) ? "all" : names.functionBound());
145
+ if (moves.bodiesAt[si].length > 0)
146
+ names.runsLater(si, moves.bodiesAt[si].reduce((held, b) => joinRebound(held, namesBoundIn(b)), names.functionBound()));
155
147
  };
156
148
  for (let si = 0; si < projected.length; si++) {
157
149
  const shapeOfLoop = loopShapes[si];
@@ -168,17 +160,15 @@ export function planShellReads(command, decl, depth = 0, start) {
168
160
  const frame = loops.pop();
169
161
  if (frame === undefined)
170
162
  continue;
171
- const body = facts.slice(frame.bodyStart, si);
172
- const moves = body.some((b) => b?.baseMove !== undefined);
173
- if (!moves)
163
+ if (!facts.slice(frame.bodyStart, si).some((b, k) => b?.shift !== undefined || (tables[frame.bodyStart + k] !== undefined && moves.losesBaseAt(frame.bodyStart + k, tables[frame.bodyStart + k]))))
174
164
  continue;
175
165
  if (frame.beats === undefined) {
176
166
  for (let k = frame.bodyStart; k < si; k++)
177
167
  unmodelled[k] = true;
178
- loseBase(candidates.filter((c) => c.skippedCd < andRunStart));
168
+ workdir.lose(si, workdir.reachable(andRunStart));
179
169
  continue;
180
170
  }
181
- for (let beat = 1; beat < frame.beats && !baseLost; beat++) {
171
+ for (let beat = 1; beat < frame.beats && !workdir.lost; beat++) {
182
172
  for (let k = frame.bodyStart; k < si; k++)
183
173
  thread(k, true);
184
174
  }
@@ -195,14 +185,19 @@ export function planShellReads(command, decl, depth = 0, start) {
195
185
  if (threaded.empty)
196
186
  continue;
197
187
  const bases = unmodelled[si] ? "unmodelled" : [...basesOf[si]];
188
+ const floorBases = workdir.floorBases;
198
189
  const floor = unmodelled[si] && floorBases !== undefined && floorBases.length > 0 ? floorBases : undefined;
199
- const withBases = (c) => {
190
+ const placedAt = (at, atFloor) => (c) => {
200
191
  const relative = relativeSpelling(c.spelled);
201
- const here = c.provenance === "object_path" && bases !== "unmodelled" ? [...new Set(bases.flatMap(ancestorsOf))] : bases;
202
- return { ...c, bases: relative ? here : [], ...(relative && floor !== undefined ? { floorBases: floor } : {}) };
192
+ const here = c.provenance === "object_path" && at !== "unmodelled" ? [...new Set(at.flatMap(ancestorsOf))] : at;
193
+ return { ...c, bases: relative ? here : [], ...(relative && atFloor !== undefined ? { floorBases: atFloor } : {}) };
203
194
  };
195
+ const withBases = placedAt(bases, floor);
204
196
  const move = threaded.baseMove;
205
197
  for (const f of threaded.readings ?? [threaded]) {
198
+ const moved = readProgramPosition(f.argv).launcherMovesBase;
199
+ const programPlaced = moved ? placedAt("unmodelled", bases !== "unmodelled" ? bases : floor) : withBases;
200
+ const programRead = (c) => (c.provenance === "stdin_redirect" ? withBases(c) : programPlaced(c));
206
201
  segments.push({
207
202
  text: f.text,
208
203
  connector: f.connector,
@@ -213,16 +208,17 @@ export function planShellReads(command, decl, depth = 0, start) {
213
208
  ...(f.unreadProgramText !== undefined ? { unreadProgramText: f.unreadProgramText } : {}),
214
209
  ...(f.stdin !== undefined ? { stdin: f.stdin } : {}),
215
210
  declines: f.declines,
216
- reads: dedupe(f.reads).map(withBases),
211
+ reads: dedupe(f.reads).map(programRead),
217
212
  redirects: f.redirects.map((r) => (r.target === undefined ? { op: r.op, direction: r.direction } : { op: r.op, direction: r.direction, target: withBases(r.target) })),
218
213
  ...(move !== undefined ? { baseMove: { target: typeof move.target === "string" ? move.target : withBases(move.target) } } : {}),
219
214
  bases,
220
- nested: f.nested.map((n) => (f.elsewhere?.has(n) === true ? n : rebasePlan(n, decl.cwd, bases))),
215
+ nested: f.nested.map((n) => (f.elsewhere?.has(n) === true ? n : rebasePlan(n, decl.cwd, moved && f.shellSide?.has(n) !== true ? "unmodelled" : bases, bases === "unmodelled" ? floor : bases))),
221
216
  reach: reaches[si] ?? { andJoined: false, orBroken: false, moveProvable: false },
217
+ rebound: tables[si]?.rebound ?? "all",
222
218
  });
223
219
  }
224
220
  }
225
- return { segments, shape, ...(unreadable !== undefined ? { unreadable } : {}) };
221
+ return { plan: { segments, shape, ...(unreadable !== undefined ? { unreadable } : {}) }, end: workdir.end(), physical: workdir.mayBePhysical };
226
222
  }
227
223
  function ancestorsOf(dir) {
228
224
  const out = [dir];
@@ -234,15 +230,14 @@ function parentOf(dir) {
234
230
  return resolveOperandLexically(dir, "..", undefined) ?? dir;
235
231
  }
236
232
  function loopShapeOf(p) {
237
- const head = p.argv[0];
238
- if (head === undefined)
233
+ if (p.argv[0] === undefined)
239
234
  return undefined;
240
235
  if (loopListHeadAt(p.argv) !== undefined)
241
236
  return "head";
242
- if (isShellSyntaxWord(head, LOOP_END))
237
+ if (isShellSyntaxWord(p.argv[0], LOOP_END))
243
238
  return "end";
244
239
  const pos = readProgramPosition(p.argv);
245
- return pos.controlWords.some((i) => p.argv[i].folded === "while" || p.argv[i].folded === "until") ? "head" : undefined;
240
+ return pos.controlWords.some((i) => LOOP_CONDITION.has(p.argv[i].folded)) ? "head" : undefined;
246
241
  }
247
242
  function segmentIsEmpty(segment, p) {
248
243
  if (p.argv.length > 0 || p.redirects.length > 0 || segment.substitutions.length > 0)
@@ -263,19 +258,22 @@ function segmentFacts(segment, p, decl, table, nestedPlan, fed) {
263
258
  if (readings.length === 1)
264
259
  return readingFacts(segment, { ...p, argv: readings[0].argv }, decl, readings[0], nestedPlan, fed);
265
260
  const once = plannedOnce(nestedPlan);
266
- const each = readings.map((reading) => readingFacts(segment, { ...p, argv: reading.argv }, decl, reading, once, fed));
261
+ return readInSeveral(readings.map((reading) => readingFacts(segment, { ...p, argv: reading.argv }, decl, reading, once, fed)));
262
+ }
263
+ function readInSeveral(each) {
267
264
  const first = each[0];
268
265
  const move = each.find((f) => f.baseMove !== undefined)?.baseMove;
269
266
  return {
270
267
  ...first,
271
268
  moveProvable: false,
272
269
  ...(move !== undefined ? { baseMove: { target: typeof move.target === "string" ? move.target : { ...move.target, expands: "unresolvable" } } } : {}),
273
- readings: each,
270
+ ...(each.some((f) => f.shift !== undefined) ? { shift: { kind: "lost" } } : {}),
271
+ readings: each.flatMap((f) => f.readings ?? [f]),
274
272
  };
275
273
  }
276
274
  function readingFacts(segment, p, decl, reading, nestedPlan, fed) {
277
275
  const table = reading.table;
278
- const planner = (text, kind, at) => nestedPlan(text, kind, kind === "later" ? { ...at, floors: reading.floors } : at);
276
+ const planner = (text, kind, at) => nestedPlan(text, kind, kind !== "substitution" ? { ...at, floors: reading.floors } : at);
279
277
  const facts = segmentFactsRead(segment, p, decl, table, planner, fed, reading.reads);
280
278
  const unresolvedRaw = new Set();
281
279
  for (const t of segment.tokens) {
@@ -297,11 +295,13 @@ function readingFacts(segment, p, decl, reading, nestedPlan, fed) {
297
295
  return [unsettle(one), ...shadows];
298
296
  };
299
297
  const move = facts.baseMove;
298
+ const shift = facts.shift;
300
299
  return {
301
300
  ...facts,
302
301
  reads: facts.reads.flatMap(each),
303
302
  redirects: facts.redirects.map((r) => (r.target === undefined ? r : { ...r, target: unsettle(r.target) })),
304
303
  ...(move !== undefined && typeof move.target !== "string" ? { baseMove: { target: unsettle(move.target) } } : {}),
304
+ ...(shift?.kind === "cd" && typeof shift.target !== "string" ? { shift: { ...shift, target: unsettle(shift.target) } } : {}),
305
305
  };
306
306
  }
307
307
  function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
@@ -343,6 +343,7 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
343
343
  }
344
344
  if (unreadableHeredoc)
345
345
  nested.push({ segments: [], unreadable: "a here-document body carries a substitution this lexer cannot delimit", shape: { grouped: false, backgrounded: false, strayRedirection: false } });
346
+ const shellSide = new Set(nested);
346
347
  if (isArithmeticCommand(segment))
347
348
  ctx.reentered.push(...arithmeticSubstitutions(p.argv.map((w) => w.folded).join(" "), table));
348
349
  for (const t of segment.tokens) {
@@ -365,26 +366,31 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
365
366
  };
366
367
  const done = (f) => {
367
368
  const reentered = [...new Set(ctx.reentered)];
368
- for (const body of reentered)
369
- nested.push(nestedPlan(body, "later"));
369
+ for (const body of reentered) {
370
+ const plan = nestedPlan(body, "later");
371
+ nested.push(plan);
372
+ shellSide.add(plan);
373
+ }
370
374
  return {
371
375
  ...base,
372
376
  ...f,
373
377
  ...(reentered.length > 0 ? { reentry: "shell" } : {}),
374
378
  ...(f.unreadProgramText === undefined && ctx.programText !== undefined ? { unreadProgramText: ctx.programText } : {}),
375
379
  ...(elsewhere.size > 0 ? { elsewhere } : {}),
380
+ ...(shellSide.size > 0 ? { shellSide } : {}),
376
381
  };
377
382
  };
378
383
  const head = toks[0]?.folded;
379
- if (isShellSyntaxWord(p.argv[0], COPROC) && toks.length > 1) {
380
- const tail = (from) => ({ ...p, argv: p.argv.slice(from) });
381
- const first = segmentFacts(segment, tail(1), decl, table, nestedPlan, fed);
382
- if (toks.length < 3)
383
- return { ...first, backgrounds: true };
384
- const second = segmentFacts(segment, tail(2), decl, table, nestedPlan, fed);
385
- const seen = new Set(first.nested.map((n) => JSON.stringify(n.segments.map((sg) => sg.text))));
386
- const extraNested = second.nested.filter((n) => !seen.has(JSON.stringify(n.segments.map((sg) => sg.text))));
387
- return { ...first, ...(second.reentry === "shell" ? { reentry: second.reentry } : {}), reads: [...first.reads, ...second.reads], nested: [...first.nested, ...extraNested], backgrounds: true };
384
+ const pos = readProgramPosition(p.argv);
385
+ const coproc = pos.written !== undefined && isShellSyntaxWord(p.argv[pos.written], COPROC) ? pos.written : undefined;
386
+ if (coproc !== undefined && toks.length > coproc + 1) {
387
+ const once = plannedOnce(nestedPlan);
388
+ const tail = (from) => ({ ...p, argv: p.argv.slice(coproc + from) });
389
+ const background = (f) => ({ ...f, backgrounds: true, ...(f.readings !== undefined ? { readings: f.readings.map((g) => ({ ...g, backgrounds: true })) } : {}) });
390
+ const first = segmentFacts(segment, tail(1), decl, table, once, fed);
391
+ if (toks.length < coproc + 3 || isShellSyntaxWord(p.argv[coproc + 1], RESERVED) || readProgramPosition(tail(2).argv.slice(0, 1)).refusal !== undefined)
392
+ return background(first);
393
+ return background(readInSeveral([first, segmentFacts(segment, tail(2), decl, table, once, fed)]));
388
394
  }
389
395
  const loop = loopShapeOf(p);
390
396
  if (loopListHeadAt(p.argv) !== undefined)
@@ -398,7 +404,6 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
398
404
  }
399
405
  return done({ empty: false, launcherChain: [], declines: [], reads, moveProvable: false });
400
406
  }
401
- const pos = readProgramPosition(p.argv);
402
407
  const written = pos.written;
403
408
  if (written === undefined)
404
409
  return done({ empty: segmentIsEmpty(segment, p), launcherChain: [], declines: [], reads, moveProvable: false });
@@ -482,6 +487,7 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
482
487
  }
483
488
  }
484
489
  let reentry;
490
+ let shift;
485
491
  if (pos.argvFromStdin)
486
492
  reentry = "argv";
487
493
  const reenterShell = (verb, argvs) => {
@@ -500,7 +506,7 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
500
506
  script(reentryText(shell, t, s.literal), user);
501
507
  }
502
508
  for (const { text, ...at } of scripts.values()) {
503
- const plan = nestedPlan(text, "later", at);
509
+ const plan = nestedPlan(text, "now", at);
504
510
  nested.push(plan);
505
511
  if (at.as?.login === true)
506
512
  elsewhere.add(plan);
@@ -511,14 +517,14 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
511
517
  if (file !== undefined)
512
518
  reads.push(bare(file, "operand"));
513
519
  }
514
- return done({ empty: false, launcherChain, verb, reentry: "shell", declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), ...(stdin.length > 0 ? { stdin } : {}) });
520
+ return done({ empty: false, launcherChain, verb, reentry: "shell", declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), ...(stdin.length > 0 ? { stdin } : {}), ...(shift !== undefined ? { shift } : {}) });
515
521
  };
516
522
  if (pos.refusal !== undefined) {
517
523
  const owner = programRow(programBasename(pos.refusal.owner));
518
524
  if (pos.refusal.kind === "option_at_program_position" && owner !== undefined && commandLineOptionSpellings(owner).length > 0) {
519
525
  const text = commandStringValue(owner, toks, pos.refusal.option);
520
526
  if (text !== undefined) {
521
- nested.push(nestedPlan(text.value, "later"));
527
+ nested.push(nestedPlan(text.value, "now"));
522
528
  reentry = "shell";
523
529
  unlistedWords(reads, toks, text.next, launcherIndices, "unlisted_word", ctx);
524
530
  return done({ empty: false, launcherChain, ...(verb !== undefined ? { verb } : {}), reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}) });
@@ -551,6 +557,12 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
551
557
  const programRead = toks[program.index];
552
558
  if (rewritten(programRead) || isPathShapedToken(programRead.folded))
553
559
  reads.push(bare(programRead, "program_path"));
560
+ if (rewritten(programRead) && !programRead.word.pieces.some((p) => p.literal?.includes("/") === true))
561
+ shift = { kind: "lost" };
562
+ if (basename === "eval")
563
+ shift = argReads.every((r) => literalTextOf(r.word.pieces) !== undefined) && reentryText("eval", texts) !== undefined ? { kind: "eval", text: reentryText("eval", texts) } : { kind: "lost" };
564
+ if (basename === "source" || basename === ".")
565
+ shift = { kind: "lost" };
554
566
  if (runsShellText(basename))
555
567
  return reenterShell(verb, [{ shell: basename, texts, args, words: argReads }]);
556
568
  const row = programRow(basename);
@@ -559,11 +571,16 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
559
571
  reentry = "interpreter";
560
572
  const moveProvable = pos.controlWords.length === 0 && pos.launchers.length === 0 && pos.assignments.length === 0 && program.name === basename;
561
573
  let baseMove;
574
+ const moving = baseShiftOf(basename, argReads, (r) => bare(r, "cd_target"));
575
+ if (moving !== undefined)
576
+ shift = moving.shift;
577
+ if (moving?.reported !== undefined)
578
+ baseMove = { target: moving.reported };
562
579
  if (basename === "cd") {
563
- baseMove = cdMove(argReads, reads);
580
+ if (typeof baseMove?.target === "object")
581
+ reads.push(baseMove.target);
564
582
  }
565
- else if (movesBaseUnfollowed(basename)) {
566
- baseMove = { target: "unmodelled" };
583
+ else if (movesBaseByStack(basename)) {
567
584
  unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", ctx, program);
568
585
  }
569
586
  else if (listed) {
@@ -631,6 +648,7 @@ function segmentFactsRead(segment, p, decl, table, nestedPlan, fed, toks) {
631
648
  declines,
632
649
  reads,
633
650
  ...(baseMove !== undefined ? { baseMove } : {}),
651
+ ...(shift !== undefined ? { shift } : {}),
634
652
  moveProvable,
635
653
  ...(loopHead !== undefined ? { loopHead } : {}),
636
654
  });
@@ -648,10 +666,7 @@ function dedupe(reads) {
648
666
  return out;
649
667
  }
650
668
  function relativeSpelling(spelled) {
651
- return !(isAbsolutePathForm(spelled) || spelled.startsWith("~"));
652
- }
653
- function joinBase(base, target, homeDir) {
654
- return resolveOperandLexically(base, target, homeDir);
669
+ return !(isAbsoluteForFamily("own", spelled) || spelled.startsWith("~"));
655
670
  }
656
671
  function redirectFact(r, table, homeDir) {
657
672
  if (r.target === undefined)
@@ -692,13 +707,3 @@ function literalBeats(toks) {
692
707
  return undefined;
693
708
  return words.length <= POLL_LOOP_MAX_BEATS ? words.length : undefined;
694
709
  }
695
- function cdMove(args, reads) {
696
- const target = args.find((t) => !t.folded.startsWith("-") || t.folded === "-");
697
- if (target === undefined)
698
- return { target: "home" };
699
- if (target.folded === "-")
700
- return { target: "previous" };
701
- const c = bare(target, "cd_target");
702
- reads.push(c);
703
- return { target: c };
704
- }
@@ -5,14 +5,14 @@
5
5
  * the segment it sits in ({@link rebasePlan}), unless it starts in a working directory of its own.
6
6
  */
7
7
  import type { LexedSegment } from "../../shell/lex.js";
8
- import type { BindingTable, FloorValue, NameReader } from "./shell-read-bindings.js";
8
+ import type { BindingTable, FloorValue, InheritedFunctions, NameReader } from "./shell-read-bindings.js";
9
9
  import type { TargetUser } from "./program-read-model.js";
10
10
  import type { StdinText } from "./shell-reentry-text.js";
11
11
  import type { ReadCandidate, ShellReadPlan } from "./shell-read-plan.js";
12
12
  /** Where a nested text starts its names: a substitution body inherits the table of the segment it sits in (a subshell
13
- * holds every variable); a text the shell runs later or elsewhere (a code body, `eval`'s text, a child shell's `-c`)
14
- * starts from the text's own start — every name unknown, `HOME` the declared home unless the enclosing text binds it
15
- * anywhere. `boundAnywhere` answers for the enclosing texts. */
13
+ * holds every variable of the shell that forks it); a text the shell runs later or elsewhere (a code body, `eval`'s
14
+ * text, a child shell's `-c`) starts from the text's own start — every name unknown, `HOME` the declared home unless
15
+ * the enclosing text binds it anywhere. `boundAnywhere` answers for the enclosing texts. */
16
16
  export interface PlanStart {
17
17
  readonly initial: NameReader;
18
18
  readonly boundAnywhere: (name: string) => boolean;
@@ -23,9 +23,30 @@ export interface PlanStart {
23
23
  /** The working directories it starts in, where they are not the enclosing segment's (a login shell starts in its user's
24
24
  * home; `"unmodelled"` — a home the text does not settle). */
25
25
  readonly bases?: readonly string[] | "unmodelled";
26
+ /** The thread of the shell that runs the text, where the text runs in that shell or a fork of it ({@link HeldThread}). */
27
+ readonly thread?: HeldThread;
28
+ /** What the shell around the text holds where the text runs in that shell or a fork of it — a literal `eval` text, a
29
+ * substitution body, a text run later (a `trap` action): each function and builtin key as it stands there
30
+ * ({@link InheritedFunctions}). A text a new process runs (a child shell's `-c`) holds none: every builtin enabled, no function. */
31
+ readonly names?: InheritedFunctions;
26
32
  /** What arrives on its own standard input (the input of the shell running it). */
27
33
  readonly stdin?: readonly StdinText[];
28
34
  }
35
+ /** The thread of the shell that runs a text, at the segment that hands it on: a literal `eval` text is not a new plan but the next
36
+ * segment of the same thread, so it starts in all of it and hands the working directory and the physical mode back; a substitution
37
+ * body (a fork) and a text run later start in what the shell holds and hand nothing back. `functions`: the names a call may mean
38
+ * (the shell's definition heads and the ones an `eval` text defines), `unread` those whose bodies the nested plan has not read — an
39
+ * `eval` text reads the shell's bodies through the names they bind, every other text has none of them in front of it. */
40
+ export interface HeldThread {
41
+ readonly physical: boolean;
42
+ readonly functions: ReadonlySet<string>;
43
+ readonly unread: ReadonlySet<string>;
44
+ }
45
+ /** What a shell holds at a segment, for a text that runs in it or in a fork of it ({@link PlanStart.names}): each function and builtin key
46
+ * as it stands there, and the names a call to one of its functions may change — the ones the text reads a call of: an `eval` text names
47
+ * the shell's functions (`bound`: what a call to one of them changes); a substitution body and a text run later read none of their bodies
48
+ * (the shell's functions are {@link HeldThread.unread} there: a call to one makes every name unknown), so they name none. */
49
+ export declare function heldAt(table: BindingTable, bound?: InheritedFunctions["bound"]): InheritedFunctions;
29
50
  /** What a segment says of the start of a text it hands a shell to run later: the deny floors of the words it holds as
30
51
  * written, the user the shell runs as ({@link TargetUser}), and the shell's standard input. */
31
52
  export interface NestedStart {
@@ -52,6 +73,8 @@ export declare function stdinFeeds(segments: readonly LexedSegment[], start: rea
52
73
  * $(cat secret)`), so its relative candidates are re-based onto the ENCLOSING segment's bases — every base the
53
74
  * nested text derived from the start is carried over by prefix, an unsettled enclosing base leaves every
54
75
  * relative candidate unplaced, and absolute candidates are untouched. Recursive: a nested plan's own nested plans
55
- * derive from the same start.
76
+ * derive from the same start. A candidate left unplaced is judged where the text stood when it lost track (its floor,
77
+ * {@link ReadCandidate.floorBases}): the places the nested text was in move with it like its bases, and an enclosing segment that
78
+ * lost its base itself hands on its own floor (`floor`).
56
79
  */
57
- export declare function rebasePlan(plan: ShellReadPlan, from: string, to: ReadCandidate["bases"]): ShellReadPlan;
80
+ export declare function rebasePlan(plan: ShellReadPlan, from: string, to: ReadCandidate["bases"], floor?: readonly string[]): ShellReadPlan;
@@ -1,3 +1,7 @@
1
+ const NO_NAMES = new Set();
2
+ export function heldAt(table, bound = NO_NAMES) {
3
+ return { start: (key) => table.stateOf(key), bound };
4
+ }
1
5
  const ROOT_HOMES = ["/root", "/var/root"];
2
6
  export function startedAt(later, at) {
3
7
  if (at === undefined)
@@ -58,24 +62,27 @@ export function stdinFeeds(segments, start, piped) {
58
62
  };
59
63
  return fedAt;
60
64
  }
61
- export function rebasePlan(plan, from, to) {
65
+ export function rebasePlan(plan, from, to, floor) {
62
66
  if (to !== "unmodelled" && to.length === 1 && to[0] === from)
63
67
  return plan;
64
68
  const fromSep = from.endsWith("/") || from.endsWith("\\") ? from : `${from}/`;
65
- const moveBase = (b) => {
66
- if (to === "unmodelled")
67
- return [];
69
+ const moveInto = (into, b) => {
68
70
  if (b === from)
69
- return [...to];
71
+ return [...into];
70
72
  if (b.startsWith(fromSep))
71
- return to.map((t) => `${t.endsWith("/") || t.endsWith("\\") ? t : `${t}/`}${b.slice(fromSep.length)}`);
73
+ return into.map((t) => `${t.endsWith("/") || t.endsWith("\\") ? t : `${t}/`}${b.slice(fromSep.length)}`);
72
74
  return [b];
73
75
  };
76
+ const moveBase = (b) => (to === "unmodelled" ? [] : moveInto(to, b));
77
+ const floorAt = to === "unmodelled" ? floor : to;
78
+ const moveFloor = (bases, into) => [...new Set(bases.flatMap((b) => moveInto(into, b)))];
74
79
  const moveCandidate = (c) => {
75
- if (c.bases === "unmodelled" || c.bases.length === 0)
80
+ if (c.bases === "unmodelled")
81
+ return c.floorBases === undefined || floorAt === undefined ? c : { ...c, floorBases: moveFloor(c.floorBases, floorAt) };
82
+ if (c.bases.length === 0)
76
83
  return c;
77
84
  if (to === "unmodelled")
78
- return { ...c, bases: "unmodelled" };
85
+ return floor === undefined ? { ...c, bases: "unmodelled" } : { ...c, bases: "unmodelled", floorBases: moveFloor(c.bases, floor) };
79
86
  return { ...c, bases: [...new Set(c.bases.flatMap(moveBase))] };
80
87
  };
81
88
  return {
@@ -86,7 +93,7 @@ export function rebasePlan(plan, from, to) {
86
93
  redirects: s.redirects.map((r) => (r.target === undefined ? r : { ...r, target: moveCandidate(r.target) })),
87
94
  ...(s.baseMove !== undefined ? { baseMove: { target: typeof s.baseMove.target === "string" ? s.baseMove.target : moveCandidate(s.baseMove.target) } } : {}),
88
95
  bases: s.bases === "unmodelled" || to === "unmodelled" ? "unmodelled" : [...new Set(s.bases.flatMap(moveBase))],
89
- nested: s.nested.map((n) => rebasePlan(n, from, to)),
96
+ nested: s.nested.map((n) => rebasePlan(n, from, to, floor)),
90
97
  })),
91
98
  };
92
99
  }
@@ -85,6 +85,10 @@ function overlaidTable(table, overlay) {
85
85
  isInteger: (name) => table.isInteger(name),
86
86
  ifsTouched: table.ifsTouched,
87
87
  homeTouched: table.homeTouched,
88
+ rebound: table.rebound,
89
+ providedByShell: (name) => table.providedByShell(name),
90
+ functionState: (name) => table.functionState(name),
91
+ builtinState: (name) => table.builtinState(name),
88
92
  floorOf: (name) => {
89
93
  const held = table.stateOf(name);
90
94
  return overlay.get(name) !== "unknown" || held === "unknown" ? table.floorOf(name) : [...table.floorOf(name), ...held.map(floorOf)];