@sema-agent/core 7.47.0 → 7.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/CHANGELOG.md +472 -0
  2. package/README.md +2 -2
  3. package/dist/agents/cascade.d.ts +2 -5
  4. package/dist/agents/child-failure.d.ts +20 -0
  5. package/dist/agents/child-failure.js +28 -0
  6. package/dist/agents/cross-session-ref.d.ts +11 -3
  7. package/dist/agents/cross-session-ref.js +6 -0
  8. package/dist/agents/cumulative-stats.d.ts +12 -15
  9. package/dist/agents/cumulative-stats.js +1 -1
  10. package/dist/agents/extra-tool-names.js +1 -1
  11. package/dist/agents/inherited-tool-pool.d.ts +17 -13
  12. package/dist/agents/inherited-tool-pool.js +4 -3
  13. package/dist/agents/peer-session-drain.d.ts +3 -2
  14. package/dist/agents/peer-session-drain.js +5 -4
  15. package/dist/agents/send-message-tool.js +2 -9
  16. package/dist/agents/subagent.d.ts +10 -29
  17. package/dist/agents/subagent.js +65 -53
  18. package/dist/agents/suspend-guard.d.ts +1 -1
  19. package/dist/agents/tool-filter.d.ts +76 -65
  20. package/dist/agents/tool-filter.js +122 -92
  21. package/dist/agents/verify.d.ts +4 -7
  22. package/dist/agents/verify.js +6 -7
  23. package/dist/bench/metrics.d.ts +1 -2
  24. package/dist/brain/anthropic.js +133 -79
  25. package/dist/brain/errors.d.ts +53 -6
  26. package/dist/brain/errors.js +22 -2
  27. package/dist/brain/input-too-long.d.ts +40 -19
  28. package/dist/brain/input-too-long.js +3 -16
  29. package/dist/brain/open-responses.js +19 -10
  30. package/dist/brain/openai.js +123 -32
  31. package/dist/brain/provider-dialect.d.ts +214 -0
  32. package/dist/brain/provider-dialect.js +186 -0
  33. package/dist/brain/request-params.d.ts +27 -8
  34. package/dist/brain/request-params.js +7 -12
  35. package/dist/brain/request-route.d.ts +84 -0
  36. package/dist/brain/request-route.js +41 -0
  37. package/dist/brain/retry.d.ts +8 -0
  38. package/dist/brain/retry.js +10 -4
  39. package/dist/brain/route-adjudicator.d.ts +7 -0
  40. package/dist/brain/route-adjudicator.js +5 -1
  41. package/dist/brain/status-sink.d.ts +20 -0
  42. package/dist/brain/status-sink.js +11 -0
  43. package/dist/brain/stream-engine.d.ts +52 -1
  44. package/dist/brain/stream-engine.js +81 -24
  45. package/dist/brain/stream-shared.d.ts +57 -11
  46. package/dist/brain/stream-shared.js +28 -2
  47. package/dist/core/a2a.d.ts +1 -0
  48. package/dist/core/agent-config-dir.js +3 -2
  49. package/dist/core/allow-entry.d.ts +21 -12
  50. package/dist/core/allow-entry.js +39 -32
  51. package/dist/core/arg-summary.d.ts +17 -24
  52. package/dist/core/arg-summary.js +169 -68
  53. package/dist/core/ask-origin.d.ts +42 -24
  54. package/dist/core/ask-origin.js +18 -13
  55. package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
  56. package/dist/core/auto-mode-prompt-assets.js +1 -1
  57. package/dist/core/auto-mode-prompt.d.ts +11 -1
  58. package/dist/core/auto-mode-prompt.js +13 -10
  59. package/dist/core/auto-mode-rebuild.d.ts +7 -0
  60. package/dist/core/auto-mode-rebuild.js +4 -1
  61. package/dist/core/canonical-json.d.ts +3 -0
  62. package/dist/core/canonical-json.js +2 -1
  63. package/dist/core/checkpoint-requirements.d.ts +892 -0
  64. package/dist/core/checkpoint-requirements.js +333 -0
  65. package/dist/core/checkpoint-store.d.ts +95 -66
  66. package/dist/core/checkpoint-store.js +14 -26
  67. package/dist/core/child-clamp-seats.d.ts +228 -69
  68. package/dist/core/child-clamp-seats.js +211 -17
  69. package/dist/core/classifier-unavailable-arm.d.ts +5 -1
  70. package/dist/core/classifier-unavailable-arm.js +3 -3
  71. package/dist/core/compliance.d.ts +3 -0
  72. package/dist/core/compliance.js +9 -4
  73. package/dist/core/credential-vocabulary.d.ts +140 -0
  74. package/dist/core/credential-vocabulary.js +131 -0
  75. package/dist/core/decision-receipt.js +1 -1
  76. package/dist/core/effective-path-target.d.ts +73 -16
  77. package/dist/core/effective-path-target.js +63 -33
  78. package/dist/core/engine-notice.d.ts +32 -7
  79. package/dist/core/file-history-store.js +2 -2
  80. package/dist/core/fs-write-gate-policy.d.ts +4 -0
  81. package/dist/core/fs-write-gate-policy.js +22 -5
  82. package/dist/core/gate-bounded-await.d.ts +28 -13
  83. package/dist/core/gate-bounded-await.js +41 -4
  84. package/dist/core/gate-fold.d.ts +1 -1
  85. package/dist/core/gate-fold.js +24 -25
  86. package/dist/core/gate-lanes.js +16 -15
  87. package/dist/core/gate-outcome.d.ts +20 -5
  88. package/dist/core/gate-outcome.js +5 -0
  89. package/dist/core/governance-codes.d.ts +11 -4
  90. package/dist/core/governance-codes.js +14 -3
  91. package/dist/core/hooks.d.ts +4 -0
  92. package/dist/core/locked-config.d.ts +8 -0
  93. package/dist/core/locked-config.js +14 -2
  94. package/dist/core/lsp.js +3 -5
  95. package/dist/core/mailbox-store.d.ts +3 -4
  96. package/dist/core/mcp-connection-pool.d.ts +75 -0
  97. package/dist/core/mcp-connection-pool.js +128 -0
  98. package/dist/core/mcp-failure.d.ts +2 -1
  99. package/dist/core/mcp-failure.js +13 -2
  100. package/dist/core/mcp-server-spec.d.ts +1 -1
  101. package/dist/core/mcp.d.ts +4 -0
  102. package/dist/core/mcp.js +70 -43
  103. package/dist/core/memory-engine/content-origin.js +2 -14
  104. package/dist/core/memory-engine/engine.d.ts +32 -22
  105. package/dist/core/memory-engine/engine.js +103 -55
  106. package/dist/core/memory-engine/file-backend.d.ts +13 -30
  107. package/dist/core/memory-engine/file-backend.js +37 -252
  108. package/dist/core/memory-engine/index.d.ts +1 -1
  109. package/dist/core/memory-engine/index.js +1 -1
  110. package/dist/core/memory-engine/layout.d.ts +139 -9
  111. package/dist/core/memory-engine/layout.js +350 -7
  112. package/dist/core/memory-engine/scope-contract.d.ts +10 -0
  113. package/dist/core/memory-engine/scope-contract.js +8 -0
  114. package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
  115. package/dist/core/memory-engine/session-incarnation.js +5 -2
  116. package/dist/core/memory-engine/types.d.ts +10 -1
  117. package/dist/core/memory.js +5 -17
  118. package/dist/core/model-seat.d.ts +4 -4
  119. package/dist/core/model-seat.js +1 -1
  120. package/dist/core/mounted-mcp.d.ts +57 -0
  121. package/dist/core/mounted-mcp.js +19 -0
  122. package/dist/core/namespaced-rule-name.d.ts +29 -0
  123. package/dist/core/namespaced-rule-name.js +52 -0
  124. package/dist/core/park-selfcheck.d.ts +1 -1
  125. package/dist/core/park-selfcheck.js +16 -6
  126. package/dist/core/path-guard-rows.d.ts +99 -0
  127. package/dist/core/path-guard-rows.js +45 -0
  128. package/dist/core/path-identity.d.ts +22 -16
  129. package/dist/core/path-identity.js +10 -10
  130. package/dist/core/path-rule-binding.d.ts +2 -1
  131. package/dist/core/path-rule-binding.js +3 -1
  132. package/dist/core/pause-registry.d.ts +16 -2
  133. package/dist/core/pause-registry.js +6 -0
  134. package/dist/core/permission-rule-consent.js +0 -7
  135. package/dist/core/permission-rule-model.d.ts +68 -24
  136. package/dist/core/permission-rule-model.js +105 -24
  137. package/dist/core/permission-rule-store.js +2 -2
  138. package/dist/core/permission-rules.d.ts +3 -30
  139. package/dist/core/permission-rules.js +4 -54
  140. package/dist/core/read-root-candidate.d.ts +1 -3
  141. package/dist/core/read-root-candidate.js +4 -15
  142. package/dist/core/real-approval.d.ts +4 -3
  143. package/dist/core/retired-keys.d.ts +13 -0
  144. package/dist/core/retired-keys.js +14 -0
  145. package/dist/core/roles.d.ts +2 -3
  146. package/dist/core/roles.js +15 -6
  147. package/dist/core/runner/assemble-result.d.ts +0 -7
  148. package/dist/core/runner/assemble-result.js +19 -31
  149. package/dist/core/runner/caller-roster.d.ts +78 -0
  150. package/dist/core/runner/caller-roster.js +219 -0
  151. package/dist/core/runner/checkpoint-scope.d.ts +16 -16
  152. package/dist/core/runner/checkpoint-scope.js +2 -2
  153. package/dist/core/runner/child-tree.js +2 -2
  154. package/dist/core/runner/contracts.d.ts +68 -35
  155. package/dist/core/runner/decide-continuation.d.ts +51 -3
  156. package/dist/core/runner/decide-continuation.js +76 -21
  157. package/dist/core/runner/denial-limit-arms.d.ts +17 -5
  158. package/dist/core/runner/denial-limit-arms.js +11 -9
  159. package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
  160. package/dist/core/runner/extra-body-dropped-seat.js +22 -0
  161. package/dist/core/runner/finish-reason-seat.d.ts +9 -0
  162. package/dist/core/runner/finish-reason-seat.js +40 -0
  163. package/dist/core/runner/gate-exit.d.ts +44 -32
  164. package/dist/core/runner/gate-exit.js +112 -25
  165. package/dist/core/runner/inherited-ask-grants.js +6 -4
  166. package/dist/core/runner/mcp-redial.d.ts +3 -3
  167. package/dist/core/runner/mcp-redial.js +3 -4
  168. package/dist/core/runner/park-commit.d.ts +1 -1
  169. package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
  170. package/dist/core/runner/permission-rule-lanes.js +5 -4
  171. package/dist/core/runner/prepare-artifact.d.ts +4 -0
  172. package/dist/core/runner/prepare-artifact.js +2 -1
  173. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  174. package/dist/core/runner/prepare-ask-lane.js +12 -6
  175. package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
  176. package/dist/core/runner/prepare-boundary-parks.js +4 -7
  177. package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
  178. package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
  179. package/dist/core/runner/prepare-config-doors.d.ts +9 -9
  180. package/dist/core/runner/prepare-config-doors.js +10 -5
  181. package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
  182. package/dist/core/runner/prepare-defer-classify.js +5 -3
  183. package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
  184. package/dist/core/runner/prepare-delegation-surface.js +3 -3
  185. package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
  186. package/dist/core/runner/prepare-gate-stations.js +9 -7
  187. package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
  188. package/dist/core/runner/prepare-hands-readface.js +7 -7
  189. package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
  190. package/dist/core/runner/prepare-inherited-gate.js +14 -15
  191. package/dist/core/runner/prepare-listings.d.ts +7 -24
  192. package/dist/core/runner/prepare-listings.js +4 -5
  193. package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
  194. package/dist/core/runner/prepare-memory-engine-session.js +4 -3
  195. package/dist/core/runner/prepare-memory.d.ts +6 -0
  196. package/dist/core/runner/prepare-memory.js +13 -13
  197. package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
  198. package/dist/core/runner/prepare-offload-wrappers.js +3 -3
  199. package/dist/core/runner/prepare-park-ask.d.ts +7 -8
  200. package/dist/core/runner/prepare-park-ask.js +17 -10
  201. package/dist/core/runner/prepare-policy-chain.js +24 -44
  202. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  203. package/dist/core/runner/prepare-project-context.js +3 -4
  204. package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
  205. package/dist/core/runner/prepare-protocol-tools.js +3 -4
  206. package/dist/core/runner/prepare-run-refs.d.ts +3 -0
  207. package/dist/core/runner/prepare-run-refs.js +2 -1
  208. package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
  209. package/dist/core/runner/prepare-safety-scan.js +1 -2
  210. package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
  211. package/dist/core/runner/prepare-suspend-saga.js +28 -12
  212. package/dist/core/runner/prepare-task.d.ts +1 -1
  213. package/dist/core/runner/prepare-task.js +67 -56
  214. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
  215. package/dist/core/runner/prepare-wiring-manifest.js +5 -8
  216. package/dist/core/runner/resume-apply.js +7 -14
  217. package/dist/core/runner/resume-checkpoint-screen.js +11 -4
  218. package/dist/core/runner/resume-internals-and-config.js +2 -2
  219. package/dist/core/runner/resume-policy-outcome.js +5 -32
  220. package/dist/core/runner/resume-review-outcome.js +4 -1
  221. package/dist/core/runner/retired-runner-deps.d.ts +6 -0
  222. package/dist/core/runner/retired-runner-deps.js +10 -1
  223. package/dist/core/runner/run-brain-sinks.d.ts +4 -0
  224. package/dist/core/runner/run-brain-sinks.js +5 -2
  225. package/dist/core/runner/run-harness-handlers.js +27 -34
  226. package/dist/core/runner/run-leg.d.ts +0 -2
  227. package/dist/core/runner/run-leg.js +32 -33
  228. package/dist/core/runner/run-terminal-adoption.js +4 -3
  229. package/dist/core/runner/runtask.js +8 -8
  230. package/dist/core/runner/session-rule-policy.js +5 -5
  231. package/dist/core/runner/stream-settle-backstop.js +7 -4
  232. package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
  233. package/dist/core/runner/sub-agent-deny-lists.js +111 -80
  234. package/dist/core/runner/terminal-account.d.ts +48 -0
  235. package/dist/core/runner/terminal-account.js +186 -0
  236. package/dist/core/runner/tool-end-body.d.ts +54 -17
  237. package/dist/core/runner/tool-end-body.js +27 -2
  238. package/dist/core/runner/tool-face-overlay.d.ts +3 -1
  239. package/dist/core/runner/tool-face-overlay.js +6 -4
  240. package/dist/core/runner/tool-occurrence.d.ts +106 -0
  241. package/dist/core/runner/tool-occurrence.js +123 -0
  242. package/dist/core/runner/tool-progress-lane.d.ts +16 -8
  243. package/dist/core/runner/tool-progress-lane.js +25 -34
  244. package/dist/core/runner/turn-attachments.d.ts +1 -1
  245. package/dist/core/runner/write-protection-station.d.ts +21 -9
  246. package/dist/core/runner/write-protection-station.js +20 -17
  247. package/dist/core/runner-deps.d.ts +12 -22
  248. package/dist/core/safety-axis-vocab.d.ts +1 -1
  249. package/dist/core/safety-merge-corpus.d.ts +1 -1
  250. package/dist/core/secret-env.d.ts +16 -5
  251. package/dist/core/secret-env.js +23 -63
  252. package/dist/core/sensitive-path-policy.d.ts +19 -18
  253. package/dist/core/sensitive-path-policy.js +73 -49
  254. package/dist/core/session-policy-store.d.ts +6 -3
  255. package/dist/core/session-policy-store.js +28 -10
  256. package/dist/core/session-reconcile.d.ts +3 -0
  257. package/dist/core/session-reconcile.js +5 -4
  258. package/dist/core/session-store.d.ts +5 -0
  259. package/dist/core/session-store.js +12 -0
  260. package/dist/core/session.d.ts +13 -0
  261. package/dist/core/shared-memory/normalize.d.ts +17 -4
  262. package/dist/core/shared-memory/normalize.js +7 -7
  263. package/dist/core/shell-lexer.js +5 -4
  264. package/dist/core/shell-wrapper-table.d.ts +2 -2
  265. package/dist/core/shell-wrapper-table.js +1 -1
  266. package/dist/core/skill-grant.js +1 -1
  267. package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
  268. package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
  269. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
  270. package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
  271. package/dist/core/stub-env.d.ts +2 -0
  272. package/dist/core/stub-env.js +1 -0
  273. package/dist/core/synthetic-read-verdict.js +2 -2
  274. package/dist/core/task-event.d.ts +59 -5
  275. package/dist/core/task-result.d.ts +1 -1
  276. package/dist/core/task-spec.d.ts +42 -9
  277. package/dist/core/terminal-cause.d.ts +94 -11
  278. package/dist/core/tighten-task-spec.d.ts +5 -4
  279. package/dist/core/tighten-task-spec.js +20 -25
  280. package/dist/core/tool-catalog-entries.d.ts +5 -7
  281. package/dist/core/tool-catalog-entries.js +14 -15
  282. package/dist/core/tool-face.d.ts +47 -0
  283. package/dist/core/tool-face.js +5 -0
  284. package/dist/core/tool-model-gate.d.ts +5 -5
  285. package/dist/core/tool-name-aliases.d.ts +35 -10
  286. package/dist/core/tool-name-aliases.js +15 -0
  287. package/dist/core/tool-name-list.d.ts +30 -0
  288. package/dist/core/tool-name-list.js +55 -0
  289. package/dist/core/tool-name-readings.d.ts +1 -9
  290. package/dist/core/tool-name-readings.js +1 -3
  291. package/dist/core/tool-policy.d.ts +195 -85
  292. package/dist/core/tool-policy.js +165 -381
  293. package/dist/core/tool-registry.d.ts +44 -1
  294. package/dist/core/tool-registry.js +26 -0
  295. package/dist/core/tool-roster.d.ts +19 -1
  296. package/dist/core/tool-roster.js +21 -2
  297. package/dist/core/tool-spec-members.d.ts +45 -0
  298. package/dist/core/tool-spec-members.js +169 -0
  299. package/dist/core/tool-spec.d.ts +46 -8
  300. package/dist/core/tools.d.ts +6 -2
  301. package/dist/core/tools.js +8 -4
  302. package/dist/core/untrusted-egress.js +29 -26
  303. package/dist/core/untrusted-text.d.ts +13 -10
  304. package/dist/core/untrusted-text.js +6 -44
  305. package/dist/core/workflow-journal-store.d.ts +4 -1
  306. package/dist/core/write-protect.d.ts +65 -29
  307. package/dist/core/write-protect.js +235 -177
  308. package/dist/engine/compaction/compaction.d.ts +2 -2
  309. package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
  310. package/dist/engine/execution-env/node-execution-env.js +16 -38
  311. package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
  312. package/dist/engine/execution-env/symlink-chain.js +32 -0
  313. package/dist/engine/harness/types.d.ts +7 -0
  314. package/dist/engine/llm/tool-turns.d.ts +3 -0
  315. package/dist/engine/llm/tool-turns.js +1 -0
  316. package/dist/engine/llm/types.d.ts +59 -23
  317. package/dist/engine/loop/agent-loop.js +16 -2
  318. package/dist/engine/session/memory-repo.js +11 -3
  319. package/dist/engine/session/repo-utils.d.ts +8 -0
  320. package/dist/engine/session/repo-utils.js +13 -0
  321. package/dist/index.d.ts +20 -23
  322. package/dist/index.js +17 -20
  323. package/dist/internal/harness.d.ts +1 -1
  324. package/dist/internal/harness.js +1 -1
  325. package/dist/internal/llm.d.ts +2 -2
  326. package/dist/internal/llm.js +1 -1
  327. package/dist/orchestration/governance-baseline-validity.js +1 -1
  328. package/dist/orchestration/run-spec.js +3 -3
  329. package/dist/orchestration/run-workflow-tool.d.ts +16 -35
  330. package/dist/orchestration/run-workflow-tool.js +38 -78
  331. package/dist/orchestration/workflow-governance.d.ts +21 -25
  332. package/dist/orchestration/workflow-governance.js +38 -78
  333. package/dist/orchestration/workflow-primitives.d.ts +7 -22
  334. package/dist/orchestration/workflow-primitives.js +5 -12
  335. package/dist/orchestration/workflow-types.d.ts +1 -1
  336. package/dist/orchestration/workflow.d.ts +61 -11
  337. package/dist/orchestration/workflow.js +191 -119
  338. package/dist/prompt-assembly/types.d.ts +1 -1
  339. package/dist/scenarios/full-body.d.ts +1 -1
  340. package/dist/shell/lex.d.ts +0 -21
  341. package/dist/shell/lex.js +278 -70
  342. package/dist/shell/shell-words.d.ts +35 -0
  343. package/dist/shell/shell-words.js +65 -0
  344. package/dist/stores/file/checkpoint-store.d.ts +5 -5
  345. package/dist/stores/file/checkpoint-store.js +5 -2
  346. package/dist/stores/file/index.d.ts +0 -8
  347. package/dist/stores/file/index.js +0 -12
  348. package/dist/stores/file/session-store.d.ts +3 -0
  349. package/dist/stores/file/session-store.js +44 -19
  350. package/dist/tools/artifact/artifact-tool.js +2 -0
  351. package/dist/tools/fs/bash-program-position.d.ts +17 -3
  352. package/dist/tools/fs/bash-program-position.js +25 -10
  353. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  354. package/dist/tools/fs/bash-readonly-classifier.js +8 -7
  355. package/dist/tools/fs/containment-face.d.ts +4 -0
  356. package/dist/tools/fs/containment-face.js +3 -0
  357. package/dist/tools/fs/fs-shared.d.ts +10 -0
  358. package/dist/tools/fs/fs-shared.js +18 -0
  359. package/dist/tools/fs/fs-write.js +4 -2
  360. package/dist/tools/fs/index.d.ts +3 -2
  361. package/dist/tools/fs/index.js +2 -2
  362. package/dist/tools/fs/program-read-model.d.ts +99 -23
  363. package/dist/tools/fs/program-read-model.js +129 -55
  364. package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
  365. package/dist/tools/fs/program-read-model.rows.js +18 -10
  366. package/dist/tools/fs/read-deny-home.d.ts +35 -30
  367. package/dist/tools/fs/read-deny-home.js +45 -38
  368. package/dist/tools/fs/read-deny.d.ts +35 -27
  369. package/dist/tools/fs/read-deny.js +126 -92
  370. package/dist/tools/fs/removal-targets.d.ts +56 -23
  371. package/dist/tools/fs/removal-targets.js +74 -87
  372. package/dist/tools/fs/safety.d.ts +29 -22
  373. package/dist/tools/fs/safety.js +17 -11
  374. package/dist/tools/fs/search.js +10 -8
  375. package/dist/tools/fs/shell-read-argv.d.ts +4 -7
  376. package/dist/tools/fs/shell-read-argv.js +6 -8
  377. package/dist/tools/fs/shell-read-bindings.d.ts +203 -46
  378. package/dist/tools/fs/shell-read-bindings.js +488 -144
  379. package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
  380. package/dist/tools/fs/shell-read-builtins.js +43 -0
  381. package/dist/tools/fs/shell-read-check.d.ts +15 -1
  382. package/dist/tools/fs/shell-read-check.js +51 -42
  383. package/dist/tools/fs/shell-read-establish.js +9 -10
  384. package/dist/tools/fs/shell-read-functions.d.ts +22 -0
  385. package/dist/tools/fs/shell-read-functions.js +29 -0
  386. package/dist/tools/fs/shell-read-judge.d.ts +48 -18
  387. package/dist/tools/fs/shell-read-judge.js +33 -4
  388. package/dist/tools/fs/shell-read-plan.d.ts +13 -20
  389. package/dist/tools/fs/shell-read-plan.js +200 -194
  390. package/dist/tools/fs/shell-read-start.d.ts +80 -0
  391. package/dist/tools/fs/shell-read-start.js +99 -0
  392. package/dist/tools/fs/shell-read-word.d.ts +35 -6
  393. package/dist/tools/fs/shell-read-word.js +89 -9
  394. package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
  395. package/dist/tools/fs/shell-read-workdir.js +281 -0
  396. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
  397. package/dist/tools/fs/shell-read-write-targets.js +14 -5
  398. package/dist/tools/fs/shell-reentry-text.d.ts +26 -26
  399. package/dist/tools/fs/shell-reentry-text.js +31 -34
  400. package/dist/tools/task-list.d.ts +1 -2
  401. package/dist/tools/web.js +1 -1
  402. package/package.json +4 -1
  403. package/test/export-surface.snapshot.json +107 -143
  404. package/wire-changes/core@7.48.0.json +252 -0
  405. package/wire-changes/core@7.49.0.json +4765 -0
  406. package/dist/agents/teacher.d.ts +0 -159
  407. package/dist/agents/teacher.js +0 -577
  408. package/dist/agents/team.d.ts +0 -226
  409. package/dist/agents/team.js +0 -257
  410. package/dist/core/strategy-store.d.ts +0 -238
  411. package/dist/core/strategy-store.js +0 -253
  412. package/dist/orchestration/builtin-workflows.d.ts +0 -133
  413. package/dist/orchestration/builtin-workflows.js +0 -159
  414. package/dist/scenarios/env.d.ts +0 -40
  415. package/dist/scenarios/env.js +0 -39
  416. package/dist/scenarios/scenario-registry.d.ts +0 -110
  417. package/dist/scenarios/scenario-registry.js +0 -140
  418. package/dist/scenarios/teacher-quickstart.d.ts +0 -40
  419. package/dist/scenarios/teacher-quickstart.js +0 -12
  420. package/dist/stores/cc/lockfile.d.ts +0 -10
  421. package/dist/stores/cc/lockfile.js +0 -98
  422. package/dist/stores/cc/mailbox-store.d.ts +0 -20
  423. package/dist/stores/cc/mailbox-store.js +0 -255
  424. package/dist/stores/cc/roster-adapter.d.ts +0 -12
  425. package/dist/stores/cc/roster-adapter.js +0 -117
  426. package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
  427. package/dist/stores/cc/sidecar-transcript.js +0 -264
  428. package/dist/stores/cc/task-list-store.d.ts +0 -2
  429. package/dist/stores/cc/task-list-store.js +0 -125
  430. package/dist/stores/file/strategy-store.d.ts +0 -97
  431. package/dist/stores/file/strategy-store.js +0 -341
@@ -1,3 +1,24 @@
1
+ /**
2
+ * The PROGRAM READ MODEL — one table that answers "what does this program do with its k-th word", and the readers
3
+ * every shell face reads it through.
4
+ *
5
+ * A row is one program (the basename bash runs; a versioned spelling of an interpreter is its row), carrying every
6
+ * argument fact the shell faces need: its option grammar (one per implementation where implementations disagree),
7
+ * the ROLE each option value and each operand plays, whether a form walks a tree, how an interpreter receives the
8
+ * program it runs, what a launcher steps over before the program it runs, which words a builtin keeps as shell text
9
+ * to run later. The rows live in `program-read-model.rows.ts`; this module is the schema and the readers.
10
+ *
11
+ * Every reader below is a PROJECTION of the same row: the option-slot reading the candidate extraction walks
12
+ * (`readArgs`), the traversal reading, the program-delivery reading, the launcher step, the program-text reading of a
13
+ * language the station parses, the message slots, the code bodies. A reader never carries a table of its own; a fact
14
+ * one reader needs and the row does not state is added to the row, where every other reader sees it too.
15
+ *
16
+ * Rows are checked against the real binaries by `test/program-read-model.binary-gate.test.ts`: each declared option
17
+ * of each row is run, per implementation, on fixtures whose every word is a FIFO, and the words the binary OPENED are
18
+ * compared with the words the row predicts it opens. A row whose opener cannot be witnessed locally (a daemon, an
19
+ * object store, a shell builtin) says so in its `witness`, with the reason.
20
+ */
21
+ import { type WordPiece } from "../../shell/lex.js";
1
22
  /** What a datum names: never a file. */
2
23
  export declare const DATUM_FORMS: readonly ["count", "pattern", "name-pattern", "label", "message", "delimiter"];
3
24
  export type DatumForm = (typeof DATUM_FORMS)[number];
@@ -272,6 +293,23 @@ export interface LauncherSpec {
272
293
  readonly requiredOperandSpelling?: RegExp;
273
294
  /** A lone `-` in its option section is its own switch (`env -`, the obsolete spelling of `env -i`). */
274
295
  readonly bareDash?: true;
296
+ /** It runs its shell as ANOTHER user ({@link TargetUser}): the user an option of `userWith` names (`sudo -u USER`), or —
297
+ * a {@link shellText} `user` launcher — its user operand; root where none is named. The shell's `HOME` is that user's
298
+ * home (`target`), or the caller's or that user's as the launcher's policy decides (`policy`: `sudo -s`); a switch of
299
+ * `loginWith` (`sudo -i`, `su -l`, su's lone `-` operand) starts it as a LOGIN shell — its `HOME` that user's, and it
300
+ * stands in that home. A `names-program` switch (`su -m`) keeps the caller's environment, `HOME` with it. */
301
+ readonly asUser?: {
302
+ readonly userWith?: readonly string[];
303
+ readonly home: "target" | "policy";
304
+ readonly loginWith: readonly string[];
305
+ };
306
+ }
307
+ /** The user a launcher runs its shell as ({@link LauncherSpec.asUser}): the name, where a word spells it literally; the
308
+ * shell's `HOME` (`caller` — kept; `target` — that user's; `either` — one of the two); whether it is a login shell. */
309
+ export interface TargetUser {
310
+ readonly name?: string;
311
+ readonly home: "caller" | "target" | "either";
312
+ readonly login: boolean;
275
313
  }
276
314
  /** How a program receives the PROGRAM it runs (an interpreter): an option value, an operand (`operands.positional`),
277
315
  * or standard input when it names none. */
@@ -322,11 +360,9 @@ export interface ProgramRow {
322
360
  /** What a declaration builtin does to every name it binds with no switch selected ({@link OptionSpec.assigns}):
323
361
  * `readonly` makes them read-only, as `declare -r` does. */
324
362
  readonly assigns?: DeclaredAttribute;
325
- /** It moves the working directory in a way the station does not follow (`pushd`). */
326
- readonly movesBase?: "unfollowed";
327
- /** What it writes to its standard output, read off its operands ({@link printedText}): `words` = its operands joined
328
- * by a space (`echo`), `format` = its one operand as a format (`printf`). */
329
- readonly prints?: "words" | "format";
363
+ /** It moves the working directory through the directory stack (`pushd` / `popd`): the working-directory thread reads
364
+ * how (`shell-read-workdir.ts`). */
365
+ readonly movesBase?: "stack";
330
366
  /** A shell block word at the program position: it names no command of its own. */
331
367
  readonly syntax?: "block";
332
368
  /** Git-style subcommands: the word after the program's own options names one, and the words after it are read by
@@ -366,7 +402,7 @@ export declare function isDeclarationBuiltin(name: string): boolean;
366
402
  export declare function declaredAttributes(row: ProgramRow | undefined, args: readonly string[]): ReadonlySet<DeclaredAttribute>;
367
403
  /** Opens no file, starts no program and evaluates nothing (a declaration builtin: only bare — its caller checks). */
368
404
  export declare function isInertBuiltin(name: string): boolean;
369
- export declare function movesBaseUnfollowed(name: string): boolean;
405
+ export declare function movesBaseByStack(name: string): boolean;
370
406
  /** The LONG-OPTION name carried by a token (`--file=p` → `file`, `--reg` → `reg`); `undefined` for anything that is
371
407
  * not a long option with a non-empty name (`--`, `--=x`, a short option). */
372
408
  export declare function longOptionNameOf(tok: string): string | undefined;
@@ -563,6 +599,20 @@ export declare function attachedStdinFile(row: ProgramRow | undefined, tok: stri
563
599
  /** The row read under each implementation's grammar alone (one view per grammar), or the row itself when it declares
564
600
  * at most one. A reader that needs to know what ONE implementation does with an argv reads these views. */
565
601
  export declare function implementationsOf(row: ProgramRow): readonly ProgramRow[];
602
+ /** What a scan over an argv's option words found: the specs selected, the values they took (argv index; the value
603
+ * inside the option word when it is attached), and the operands (argv indices). */
604
+ interface OptionScan {
605
+ readonly specs: readonly OptionSpec[];
606
+ /** Each selected option's spelling as its row declares it (`-x`, `--exec`), in step with `specs`. */
607
+ readonly names: readonly string[];
608
+ readonly values: readonly {
609
+ readonly at: number;
610
+ readonly value?: string;
611
+ readonly spec: OptionSpec;
612
+ readonly name: string;
613
+ }[];
614
+ readonly operands: readonly number[];
615
+ }
566
616
  /**
567
617
  * Every option spec an argv selects. A short cluster is read as getopt reads it, scanning left to right: a declared
568
618
  * letter is selected; a value-taking letter owns the rest of the token (and the next word, when it ends the token); a
@@ -574,6 +624,14 @@ export declare function implementationsOf(row: ProgramRow): readonly ProgramRow[
574
624
  * option, and a word past `--`, included. The reading a check that only ever refuses takes: it errs to more options.
575
625
  */
576
626
  export declare function selectedOptions(row: ProgramRow | undefined, args: readonly string[], under?: "one-implementation"): OptionSpec[];
627
+ /** The options ONE implementation's reading of an argv selects ({@link selectedOptions}), named by the spelling its row
628
+ * declares them under (`-x`, `--exec`), and the values they take. An option is told apart by its spelling, never by its
629
+ * spec: spellings share specs (every switch of a row is one). */
630
+ export declare function selectedSpellings(row: ProgramRow, args: readonly string[]): Pick<OptionScan, "names" | "values">;
631
+ /** Does ONE implementation of a row (`view`, {@link implementationsOf}) reject these option words — a spelling the row
632
+ * declares (another implementation's) that this one does not? getopt calls it an invalid option: the program runs
633
+ * nothing. */
634
+ export declare function implementationRejects(row: ProgramRow, view: ProgramRow, words: readonly string[]): boolean;
577
635
  /** A path role whose effect writes. */
578
636
  export type WritingRole = Extract<ArgRole, {
579
637
  kind: "path";
@@ -629,14 +687,6 @@ export declare function programDelivery(row: ProgramRow | undefined, args: reado
629
687
  /** The language of the program an interpreter row runs: the language of its program operand, or of the first option that
630
688
  * delivers program text or a program file. `undefined` for a row that runs no program text. */
631
689
  export declare function programLanguageOf(row: ProgramRow | undefined): string | undefined;
632
- /**
633
- * The text a printer row ({@link ProgramRow.prints}) writes to its standard output, read off its argv (the program word
634
- * excluded; `undefined` = a word whose value the command does not spell). `undefined` wherever the words do not spell the
635
- * text: such a word, an option the row does not explain, an escape the program may interpret (a backslash: `echo -e`, an
636
- * `echo` that reads escapes by default, every `printf` format), a format with a directive (`%`) or values to fill it, or a
637
- * row that prints nothing it is handed.
638
- */
639
- export declare function printedText(row: ProgramRow | undefined, args: readonly (string | undefined)[]): string | undefined;
640
690
  /**
641
691
  * The argv indices some implementation of the row reads as a path it OPENS (an ordinary operand, a value or operand of a
642
692
  * reading path role, a program file) while another reads them as something else (program text, a backup suffix, a
@@ -656,22 +706,43 @@ export declare function moduleTailOf(row: ProgramRow | undefined, args: readonly
656
706
  * value exists only attached (spelled bare, it takes nothing), 1 for one that takes the next word; `undefined` for any
657
707
  * other spelling and for an option the walk does not step over. */
658
708
  export declare function launcherOptionArity(row: ProgramRow, tok: string): 0 | 1 | undefined;
659
- /** The PATH role of the value a launcher option spelled EXACTLY takes (`xargs -a FILE`, `strace -o FILE`), or `undefined`
660
- * when its value names no path. Such a value is a word the launcher opens or writes, not an operand of its own. */
709
+ /** The PATH role of the value a launcher option word takes (`xargs -a FILE`, `strace -fo FILE`, `strace -oFILE`), or
710
+ * `undefined` when its value names no path ({@link readLauncherOption}). Such a value is a word the launcher opens or
711
+ * writes, not an operand of its own. */
661
712
  export declare function launcherOptionPathRole(row: ProgramRow, tok: string): Extract<ArgRole, {
662
713
  kind: "path";
663
714
  }> | undefined;
664
- /** How many tokens one launcher option occupies, or `undefined` where the row does not explain it: an arity-1 option
665
- * separated (2), a value fused to its long name or short letter (1); a switch, an attached-only option, or a cluster of
666
- * switches (1); a lone `-` where the launcher reads it as its own switch (1). */
715
+ /** Does this launcher option word move the base its program runs in — the directory, the root, or where its word is looked
716
+ * up (an option whose value's role is a path with a `base`) — read off the option itself, whether or not its value is
717
+ * written (`nsenter -w` bare takes the target process's directory)? In a cluster, a letter up to the first that takes a
718
+ * value. `false` for any word the walk does not step. */
719
+ export declare function launcherOptionMovesBase(row: ProgramRow, tok: string): boolean;
720
+ /** How many words one launcher option occupies ({@link readLauncherOption}), or `undefined` where the row does not
721
+ * explain it. */
667
722
  export declare function launcherOptionStep(row: ProgramRow, tok: string): 1 | 2 | undefined;
668
723
  /** Does a launcher that runs a shell ({@link LauncherSpec.shellText}) run one over these words — the words after it —
669
724
  * rather than the program they name? Not where an implementation selects one of its {@link LauncherSpec.programWith}
670
725
  * options (as that implementation reads them: past `--` a word is an operand). */
671
726
  export declare function launcherRunsShell(row: ProgramRow, args: readonly string[]): boolean;
727
+ /** The user a launcher runs its shell as ({@link LauncherSpec.asUser}), read off its own words (`words`, as the program
728
+ * receives them) by its row's walk: the value of its last `userWith` option, else its user operand (`operand`; a lone `-`
729
+ * in front of it starts a login shell, `dash`), else root — a name only where it is spelled as one (`root`, `#0`, a login
730
+ * name); `undefined` for a launcher that runs no other user. */
731
+ export declare function targetUserOf(row: ProgramRow, words: readonly string[], operand?: {
732
+ readonly name?: string;
733
+ readonly dash: boolean;
734
+ }): TargetUser | undefined;
672
735
  /** The spellings of a launcher's command-line options (`env -S` / `--split-string`): the value is a command line the
673
736
  * launcher splits and runs. */
674
737
  export declare function commandLineOptionSpellings(row: ProgramRow | undefined): readonly string[];
738
+ /** The command line ONE launcher option word carries, read as getopt reads the word ({@link readLauncherOption}): a
739
+ * command-line spelling ({@link commandLineOptionSpellings}) exactly — `"next"`, the next word is the line — or with its
740
+ * value after `=` (long) or after the letter (short, `attached`); in a short cluster every letter before the
741
+ * command-line letter is a switch the walk steps (`env -vS 'S'`, `env -iS'S'`). `undefined` where the word carries
742
+ * none. */
743
+ export declare function commandLineOf(row: ProgramRow, tok: string): {
744
+ readonly attached: string;
745
+ } | "next" | undefined;
675
746
  /** One implementation's reading of where the program text is: the text (every text option's value joined by newlines,
676
747
  * or the first operand), `from-file` (an option names a FILE holding it), `unparsed` (an option the grammar does not
677
748
  * declare, or a text option with nothing left to take), or `none` (no program text at all). */
@@ -699,13 +770,18 @@ export declare function subcommandOf(row: ProgramRow | undefined, words: readonl
699
770
  readonly relocated: boolean;
700
771
  } | undefined;
701
772
  /**
702
- * The indices of the SETTLED words a row's subcommand reads as message text: the value of its message option attached
703
- * or as the next word, by its own grammar. The global options are read exactly ({@link subcommandOf}); in the subcommand
704
- * an unknown long option takes no value, an unknown short letter or an unsettled word takes the next word (which is
705
- * then never a message).
773
+ * The indices of the words a row's subcommand reads as message text: the value of its message option attached or as the
774
+ * next word, by its own grammar. The global options are read exactly ({@link subcommandOf}); in the subcommand an unknown
775
+ * long option takes no value, an unknown short letter or an unsettled word takes the next word (which is then never a
776
+ * message). The option word itself is settled; its separate value is a message whether the text settles it or the shell
777
+ * computes it as ONE argument — every expansion in it a command substitution in double quotes, whose output is one field
778
+ * (a parameter is not taken so: `"$@"` and `"${a[@]}"` are several).
706
779
  */
707
780
  export declare function messageWords(program: string, words: readonly {
708
781
  readonly folded: string;
709
782
  readonly expands: unknown;
783
+ readonly word?: {
784
+ readonly expansions: readonly WordPiece[];
785
+ };
710
786
  }[], programIndex: number): Set<number>;
711
787
  export {};
@@ -66,8 +66,8 @@ export function isInertBuiltin(name) {
66
66
  const b = programRow(name)?.builtin;
67
67
  return b === "inert" || b === "declaration";
68
68
  }
69
- export function movesBaseUnfollowed(name) {
70
- return programRow(name)?.movesBase === "unfollowed";
69
+ export function movesBaseByStack(name) {
70
+ return programRow(name)?.movesBase === "stack";
71
71
  }
72
72
  export function longOptionNameOf(tok) {
73
73
  if (!tok.startsWith("--") || tok.length === 2)
@@ -682,6 +682,16 @@ export function implementationsOf(row) {
682
682
  export function selectedOptions(row, args, under) {
683
683
  return row === undefined ? [] : [...scanOptions(row, args, under === "one-implementation").specs];
684
684
  }
685
+ export function selectedSpellings(row, args) {
686
+ const scan = scanOptions(row, args, true);
687
+ return { names: scan.names, values: scan.values };
688
+ }
689
+ export function implementationRejects(row, view, words) {
690
+ if (view === row)
691
+ return false;
692
+ const declares = (n) => (n.startsWith("--") ? mergedTable(view, "long").has(n.slice(2)) : mergedTable(view, n.length === 2 ? "short" : "dashWords").has(n.slice(1)));
693
+ return selectedSpellings(row, words).names.some((n) => !declares(n));
694
+ }
685
695
  function scanOptions(row, args, one) {
686
696
  const stopsAtOperand = one && row.grammars[0]?.afterFirstOperand === "operands";
687
697
  const shorts = mergedTable(row, "short");
@@ -689,8 +699,10 @@ function scanOptions(row, args, one) {
689
699
  const dashWords = mergedTable(row, "dashWords");
690
700
  const obsolete = row.grammars.flatMap((g) => (g.obsoleteFirst === undefined ? [] : [g.obsoleteFirst]));
691
701
  const specs = [];
702
+ const names = [];
692
703
  const values = [];
693
704
  const operands = [];
705
+ const select = (spec, name) => { specs.push(spec); names.push(name); };
694
706
  let endOfOptions = false;
695
707
  for (let k = 0; k < args.length; k++) {
696
708
  const t = args[k];
@@ -704,7 +716,7 @@ function scanOptions(row, args, one) {
704
716
  for (const ch of t.replace(/^.\d+/, "")) {
705
717
  const spec = o.letters[ch];
706
718
  if (spec !== undefined)
707
- specs.push(spec);
719
+ select(spec, `-${ch}`);
708
720
  }
709
721
  continue;
710
722
  }
@@ -719,13 +731,13 @@ function scanOptions(row, args, one) {
719
731
  endOfOptions = true;
720
732
  continue;
721
733
  }
722
- const take = (spec, attached) => {
734
+ const take = (spec, name, attached) => {
723
735
  if (attached !== undefined) {
724
- values.push({ at: k, value: attached, spec });
736
+ values.push({ at: k, value: attached, spec, name });
725
737
  return;
726
738
  }
727
739
  if (one && k + 1 < args.length) {
728
- values.push({ at: k + 1, spec });
740
+ values.push({ at: k + 1, spec, name });
729
741
  k++;
730
742
  }
731
743
  };
@@ -735,22 +747,23 @@ function scanOptions(row, args, one) {
735
747
  continue;
736
748
  const eq = t.indexOf("=");
737
749
  const exact = longs.get(name);
738
- const hits = exact !== undefined ? [exact] : [...longs].filter(([full]) => isLongOptionAbbrevOf(name, full)).map(([, m]) => m);
739
- for (const m of hits)
740
- specs.push(m.spec);
741
- if (hits.length === 1 && (hits[0].arity === 1 || (eq >= 0 && hits[0].arity === "attached")))
742
- take(hits[0].spec, eq >= 0 ? t.slice(eq + 1) : undefined);
743
- else if (one && eq < 0 && hits.length > 1 && hits.every((m) => m.arity === 1))
750
+ const hits = exact !== undefined ? [[name, exact]] : [...longs].filter(([full]) => isLongOptionAbbrevOf(name, full));
751
+ for (const [full, m] of hits)
752
+ select(m.spec, `--${full}`);
753
+ const [full, only] = hits[0] ?? [];
754
+ if (hits.length === 1 && (only.arity === 1 || (eq >= 0 && only.arity === "attached")))
755
+ take(only.spec, `--${full}`, eq >= 0 ? t.slice(eq + 1) : undefined);
756
+ else if (one && eq < 0 && hits.length > 1 && hits.every(([, m]) => m.arity === 1))
744
757
  k++;
745
758
  continue;
746
759
  }
747
760
  const word = /^-([A-Za-z_][\w-]+)$/.exec(t)?.[1];
748
761
  const dash = word === undefined ? undefined : dashWords.get(word);
749
762
  if (dash !== undefined) {
750
- specs.push(dash.spec);
763
+ select(dash.spec, t);
751
764
  if (one) {
752
765
  if (dash.arity === 1)
753
- take(dash.spec, undefined);
766
+ take(dash.spec, t, undefined);
754
767
  continue;
755
768
  }
756
769
  }
@@ -761,18 +774,18 @@ function scanOptions(row, args, one) {
761
774
  continue;
762
775
  break;
763
776
  }
764
- specs.push(m.spec);
777
+ select(m.spec, `-${t[i]}`);
765
778
  if (m.arity === 0)
766
779
  continue;
767
780
  const rest = t.slice(i + 1);
768
781
  if (rest !== "")
769
- values.push({ at: k, value: rest, spec: m.spec });
782
+ values.push({ at: k, value: rest, spec: m.spec, name: `-${t[i]}` });
770
783
  else if (m.arity === 1 || m.arity === "suffix")
771
- take(m.spec, undefined);
784
+ take(m.spec, `-${t[i]}`, undefined);
772
785
  break;
773
786
  }
774
787
  }
775
- return { specs, values, operands };
788
+ return { specs, names, values, operands };
776
789
  }
777
790
  export function writesPath(role) {
778
791
  return role?.kind === "path" && WRITING_EFFECTS.has(role.effect);
@@ -966,21 +979,6 @@ export function programLanguageOf(row) {
966
979
  return r.language;
967
980
  return undefined;
968
981
  }
969
- export function printedText(row, args) {
970
- const words = args.filter((a) => a !== undefined);
971
- if (row?.prints === undefined || words.length !== args.length)
972
- return undefined;
973
- const events = readArgRoles(row, words);
974
- const from = events.find((e) => e.kind === "operand" || e.kind === "dash-word-operand")?.at ?? words.length;
975
- if (events.some((e) => e.at < from && e.kind === "option" && e.reading === "speculative"))
976
- return undefined;
977
- const printed = words.slice(from);
978
- if (printed.some((w) => w.includes("\\")))
979
- return undefined;
980
- if (row.prints === "words")
981
- return printed.join(" ");
982
- return printed.length === 1 && !printed[0].includes("%") ? printed[0] : undefined;
983
- }
984
982
  export function wordsReadBySomeImplementations(row, args) {
985
983
  if (row === undefined || row.grammars.length < 2)
986
984
  return new Set();
@@ -1021,9 +1019,16 @@ export function moduleTailOf(row, args) {
1021
1019
  }
1022
1020
  function steppableLauncherOption(row, tok) {
1023
1021
  const m = tok.startsWith("--") ? (tok.includes("=") ? undefined : mergedTable(row, "long").get(tok.slice(2))) : tok.length === 2 && tok.startsWith("-") ? mergedTable(row, "short").get(tok[1]) : undefined;
1024
- if (m === undefined || m.spec.value?.kind === "shell-text" || (m.spec.value?.kind === "path" && m.spec.value.base !== undefined))
1022
+ if (m === undefined || m.spec.value?.kind === "shell-text")
1025
1023
  return undefined;
1026
- return m.arity === "disputed" ? undefined : m;
1024
+ return m.arity !== "disputed" || takesNoWordBare(row, tok) ? m : undefined;
1025
+ }
1026
+ function takesNoWordBare(row, spelling) {
1027
+ const key = spelling.startsWith("--") ? spelling.slice(2) : spelling.slice(1);
1028
+ return row.grammars.every((g) => {
1029
+ const s = (spelling.startsWith("--") ? g.long : g.short)[key];
1030
+ return s === undefined || s.arity === 0 || s.arity === "attached";
1031
+ });
1027
1032
  }
1028
1033
  export function launcherOptionArity(row, tok) {
1029
1034
  if (row.grammars.length === 0)
@@ -1033,34 +1038,80 @@ export function launcherOptionArity(row, tok) {
1033
1038
  const m = steppableLauncherOption(row, tok);
1034
1039
  return m === undefined ? undefined : m.arity === 1 ? 1 : 0;
1035
1040
  }
1041
+ function readLauncherOption(row, tok) {
1042
+ if (tok === "-")
1043
+ return row.launcher?.bareDash === true ? { step: 1 } : undefined;
1044
+ if (tok === "--")
1045
+ return launcherOptionArity(row, tok) === 0 ? { step: 1 } : undefined;
1046
+ if (tok.startsWith("--")) {
1047
+ const eq = tok.indexOf("=");
1048
+ const m = steppableLauncherOption(row, eq > 2 ? tok.slice(0, eq) : tok);
1049
+ if (m === undefined)
1050
+ return undefined;
1051
+ if (eq > 2)
1052
+ return m.arity === 0 || m.arity === "disputed" ? undefined : { step: 1, valued: m };
1053
+ return m.arity === 1 ? { step: 2, valued: m } : { step: 1 };
1054
+ }
1055
+ if (!/^-[^-]/.test(tok))
1056
+ return undefined;
1057
+ for (let i = 1; i < tok.length; i++) {
1058
+ const m = steppableLauncherOption(row, `-${tok[i]}`);
1059
+ if (m === undefined)
1060
+ return undefined;
1061
+ if (m.arity === 0)
1062
+ continue;
1063
+ if (i + 1 < tok.length)
1064
+ return m.arity === "disputed" ? undefined : { step: 1, valued: m };
1065
+ return m.arity === 1 ? { step: 2, valued: m } : { step: 1 };
1066
+ }
1067
+ return { step: 1 };
1068
+ }
1036
1069
  export function launcherOptionPathRole(row, tok) {
1037
- const role = steppableLauncherOption(row, tok)?.spec.value;
1070
+ const role = readLauncherOption(row, tok)?.valued?.spec.value;
1038
1071
  return role?.kind === "path" ? role : undefined;
1039
1072
  }
1040
- export function launcherOptionStep(row, tok) {
1041
- if (tok === "-" && row.launcher?.bareDash === true)
1042
- return 1;
1043
- const exact = launcherOptionArity(row, tok);
1044
- if (exact !== undefined)
1045
- return exact === 1 ? 2 : 1;
1046
- const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
1047
- if (eq > 2 && steppableLauncherOption(row, tok.slice(0, eq))?.arity !== undefined && steppableLauncherOption(row, tok.slice(0, eq)).arity !== 0)
1048
- return 1;
1049
- if (/^-[A-Za-z]./.test(tok) && !tok.startsWith("--")) {
1050
- const first = steppableLauncherOption(row, tok.slice(0, 2));
1051
- if (first !== undefined && first.arity !== 0)
1052
- return 1;
1073
+ export function launcherOptionMovesBase(row, tok) {
1074
+ const moves = (m) => m?.spec.value?.kind === "path" && m.spec.value.base !== undefined;
1075
+ if (tok === "-" || tok === "--")
1076
+ return false;
1077
+ if (tok.startsWith("--")) {
1078
+ const eq = tok.indexOf("=");
1079
+ return moves(steppableLauncherOption(row, eq > 2 ? tok.slice(0, eq) : tok));
1053
1080
  }
1054
- if (/^-[A-Za-z]+$/.test(tok) && [...tok.slice(1)].every((ch) => launcherOptionArity(row, `-${ch}`) === 0 && steppableLauncherOption(row, `-${ch}`)?.arity === 0))
1055
- return 1;
1056
- return undefined;
1081
+ if (!/^-[^-]/.test(tok))
1082
+ return false;
1083
+ for (let i = 1; i < tok.length; i++) {
1084
+ const m = steppableLauncherOption(row, `-${tok[i]}`);
1085
+ if (m === undefined)
1086
+ return false;
1087
+ if (moves(m))
1088
+ return true;
1089
+ if (m.arity !== 0)
1090
+ return false;
1091
+ }
1092
+ return false;
1093
+ }
1094
+ export function launcherOptionStep(row, tok) {
1095
+ return readLauncherOption(row, tok)?.step;
1057
1096
  }
1058
1097
  export function launcherRunsShell(row, args) {
1059
1098
  const l = row.launcher;
1060
1099
  if (l?.shellText === undefined)
1061
1100
  return false;
1062
- const specs = new Set((l.programWith ?? []).map((s) => (s.startsWith("--") ? mergedTable(row, "long").get(s.slice(2)) : mergedTable(row, "short").get(s.slice(1)))?.spec));
1063
- return !implementationsOf(row).some((view) => selectedOptions(view, args, "one-implementation").some((o) => specs.has(o)));
1101
+ const programWith = l.programWith ?? [];
1102
+ return !implementationsOf(row).some((view) => selectedSpellings(view, args).names.some((n) => programWith.includes(n)));
1103
+ }
1104
+ export function targetUserOf(row, words, operand) {
1105
+ const as = row.launcher?.asUser;
1106
+ if (as === undefined)
1107
+ return undefined;
1108
+ const own = selectedSpellings(row, words);
1109
+ const user = own.values.filter((v) => as.userWith?.includes(v.name) === true).at(-1);
1110
+ const named = user !== undefined ? user.value ?? words[user.at] : operand === undefined ? "root" : operand.name;
1111
+ const login = operand?.dash === true || own.names.some((n) => as.loginWith.includes(n));
1112
+ const keepsCaller = selectedOptions(row, words).some((o) => o.mode === "names-program");
1113
+ const name = named === "#0" ? "root" : named !== undefined && /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(named) ? named : undefined;
1114
+ return { ...(name !== undefined ? { name } : {}), home: login ? "target" : as.home === "policy" ? "either" : keepsCaller ? "caller" : "target", login };
1064
1115
  }
1065
1116
  export function commandLineOptionSpellings(row) {
1066
1117
  if (row === undefined)
@@ -1070,6 +1121,25 @@ export function commandLineOptionSpellings(row) {
1070
1121
  ...[...mergedTable(row, "long")].filter(([, m]) => m.spec.value?.kind === "shell-text").map(([n]) => `--${n}`),
1071
1122
  ];
1072
1123
  }
1124
+ export function commandLineOf(row, tok) {
1125
+ const lines = new Set(commandLineOptionSpellings(row));
1126
+ if (tok.startsWith("--")) {
1127
+ const eq = tok.indexOf("=");
1128
+ if (!lines.has(eq > 2 ? tok.slice(0, eq) : tok))
1129
+ return undefined;
1130
+ return eq > 2 ? { attached: tok.slice(eq + 1) } : "next";
1131
+ }
1132
+ if (!/^-[^-]/.test(tok))
1133
+ return undefined;
1134
+ for (let i = 1; i < tok.length; i++) {
1135
+ const letter = `-${tok[i]}`;
1136
+ if (lines.has(letter))
1137
+ return i + 1 < tok.length ? { attached: tok.slice(i + 1) } : "next";
1138
+ if (steppableLauncherOption(row, letter)?.arity !== 0)
1139
+ return undefined;
1140
+ }
1141
+ return undefined;
1142
+ }
1073
1143
  export function readProgramTextLanguage(row) {
1074
1144
  const first = row?.operands?.positional?.[0];
1075
1145
  return first?.kind === "program-text" && READ_LANGUAGES.has(first.language) ? first.language : undefined;
@@ -1203,12 +1273,16 @@ export function messageWords(program, words, programIndex) {
1203
1273
  const j = programIndex + 1 + found.at;
1204
1274
  const sub = found.row.grammars[0];
1205
1275
  const settled = (k) => words[k] !== undefined && words[k].expands === false;
1276
+ const oneArgument = (k) => {
1277
+ const pieces = words[k]?.word?.expansions ?? [];
1278
+ return pieces.length > 0 && pieces.every((p) => p.expansion?.kind === "command" && p.expansion.yields === "one");
1279
+ };
1206
1280
  const longValues = Object.entries(sub.long).filter(([, s]) => s.arity === 1);
1207
1281
  let pending;
1208
1282
  for (let k = j + 1; k < words.length; k++) {
1209
1283
  const w = words[k].folded;
1210
1284
  if (pending !== undefined) {
1211
- if (pending === "message" && settled(k))
1285
+ if (pending === "message" && (settled(k) || oneArgument(k)))
1212
1286
  out.add(k);
1213
1287
  pending = undefined;
1214
1288
  continue;
@@ -1,17 +1,3 @@
1
- /**
2
- * The rows of the program read model (`program-read-model.ts` is the schema and the readers). One row per program
3
- * bash can run at a segment's program position, grouped by family. Every row is DATA: adding a program, an option or
4
- * an implementation is a row edit, never a reader branch.
5
- *
6
- * How a row is written:
7
- * · an option is declared with its arity and, where it is known, the ROLE of its value; a value whose role is not
8
- * known is declared by arity alone, and every reader then reads that option the speculative way;
9
- * · where two implementations of one program disagree, the row carries one grammar per implementation, and the
10
- * readers combine them (a short letter whose arity they dispute is read as nothing; a disputed long name as
11
- * optional-valued; a spelling one implementation does not declare is one it rejects, opening nothing);
12
- * · a row is checked against the real binaries by the gate (`test/program-read-model.binary-gate.test.ts`);
13
- * a row the gate cannot run says why in `witness`.
14
- */
15
1
  import type { ProgramRow } from "./program-read-model.js";
16
2
  /** The time a launcher waits (`timeout 5s …`): a number with an optional unit. */
17
3
  export declare const DURATION_SPELLING: RegExp;
@@ -1,3 +1,4 @@
1
+ import { shellWordsOf } from "../../shell/shell-words.js";
1
2
  const READ = { kind: "path", effect: "read" };
2
3
  const WRITE = { kind: "path", effect: "write" };
3
4
  const CREATED = { kind: "path", effect: "create" };
@@ -391,7 +392,7 @@ const launchers = [
391
392
  optional: { "-i": LABEL, "-l": COUNT, "--replace": LABEL, "--eof": LABEL, "--max-lines": COUNT },
392
393
  }, {}), { reads: { "-a": val(READ, { delivers: "operands" }), "--arg-file": val(READ, { delivers: "operands" }) } }, { lacks: ["-d", "-i", "-l", "-a", "--arg-file", "--null", "--no-run-if-empty", "--verbose", "--exit", "--interactive", "--open-tty", "--show-limits", "--help", "--version", "--max-args", "--max-procs", "--delimiter", "--max-chars", "--process-slot-var", "--replace", "--eof", "--max-lines"] }), launcher: {}, reentry: { kind: "argv", defaultProgram: "echo" }, witness: BINARY },
393
394
  launcher("busybox"),
394
- launcher("sudo", { assignmentOperands: true, shellCommand: "escaped" }, launcherGrammar({
395
+ launcher("sudo", { assignmentOperands: true, shellCommand: "escaped", asUser: { userWith: ["-u", "--user"], home: "policy", loginWith: ["-i", "--login"] } }, launcherGrammar({
395
396
  switches: ["-A", "-b", "-E", "-H", "-K", "-k", "-l", "-n", "-P", "-S", "-V", "-v", "--askpass", "--background", "--preserve-env", "--set-home", "--remove-timestamp", "--reset-timestamp", "--list", "--non-interactive", "--preserve-groups", "--stdin", "--version", "--validate", "--bell", "--help"],
396
397
  shells: ["-i", "-s", "--login", "--shell"],
397
398
  values: {
@@ -399,10 +400,10 @@ const launchers = [
399
400
  "--user": LABEL, "--group": LABEL, "--other-user": LABEL, "--close-from": COUNT, "--chdir": WORKDIR, "--host": LABEL, "--prompt": LABEL, "--role": LABEL, "--chroot": ROOTDIR, "--type": LABEL, "--command-timeout": COUNT, "--auth-type": LABEL,
400
401
  },
401
402
  }, { stepsDashDash: true }), { witness: PRIVILEGED }),
402
- launcher("doas", {}, launcherGrammar({ switches: ["-L", "-n"], shells: ["-s"], values: { "-a": LABEL, "-u": LABEL, "-C": READ } }, { stepsDashDash: true }), { witness: PRIVILEGED }),
403
+ launcher("doas", { asUser: { userWith: ["-u"], home: "target", loginWith: [] } }, launcherGrammar({ switches: ["-L", "-n"], shells: ["-s"], values: { "-a": LABEL, "-u": LABEL, "-C": READ } }, { stepsDashDash: true }), { witness: PRIVILEGED }),
403
404
  launcher("pkexec", { whenNoProgram: "shell" }, launcherGrammar({ switches: ["--disable-internal-agent", "--keep-cwd", "--version", "--help"], values: { "--user": LABEL } }), { witness: PRIVILEGED }),
404
- { key: "su", grammars: implementations(SU, { afterFirstOperand: "options" }, { lacks: SU_LINUX_ONLY, afterFirstOperand: "operands" }), launcher: { shellText: "user" }, witness: PRIVILEGED },
405
- { key: "runuser", grammars: [launcherGrammar({ ...SU_OPTIONS, values: { ...SU_OPTIONS.values, "-u": LABEL, "--user": LABEL } }, { afterFirstOperand: "options", stepsDashDash: true })], launcher: { shellText: "user", programWith: ["-u", "--user"] }, witness: PRIVILEGED },
405
+ { key: "su", grammars: implementations(SU, { afterFirstOperand: "options" }, { lacks: SU_LINUX_ONLY, afterFirstOperand: "operands" }), launcher: { shellText: "user", asUser: { home: "target", loginWith: ["-l", "--login"] } }, witness: PRIVILEGED },
406
+ { key: "runuser", grammars: [launcherGrammar({ ...SU_OPTIONS, values: { ...SU_OPTIONS.values, "-u": LABEL, "--user": LABEL } }, { afterFirstOperand: "options", stepsDashDash: true })], launcher: { shellText: "user", programWith: ["-u", "--user"], asUser: { home: "target", loginWith: ["-l", "--login"] } }, witness: PRIVILEGED },
406
407
  launcher("chroot", { requiredOperands: 1, whenNoProgram: "shell" }, undefined, { witness: PRIVILEGED }),
407
408
  launcher("setpriv", {}, undefined, { witness: PRIVILEGED }),
408
409
  launcher("nohup", {}, grammar({}, BANNERS)),
@@ -420,7 +421,15 @@ const launchers = [
420
421
  { key: "stdbuf", grammars: implementations(grammar({ i: val(LABEL), o: val(LABEL), e: val(LABEL) }, { input: val(LABEL), output: val(LABEL), error: val(LABEL), ...BANNERS }), {}, { lacks: ["--input", "--output", "--error", "--help", "--version"] }), launcher: {}, witness: BINARY },
421
422
  launcher("timeout", { requiredOperands: 1, requiredOperandSpelling: DURATION_SPELLING }, grammar({ v: SWITCH, k: val(COUNT), s: val(LABEL) }, { foreground: SWITCH, "preserve-status": SWITCH, verbose: SWITCH, "kill-after": val(COUNT), signal: val(LABEL), ...BANNERS })),
422
423
  { key: "time", grammars: implementations(grammar({ p: SWITCH, a: SWITCH, v: SWITCH, q: SWITCH, f: val(LABEL), o: val(WRITE) }, { portability: SWITCH, append: SWITCH, verbose: SWITCH, quiet: SWITCH, help: SWITCH, version: SWITCH, format: val(LABEL), output: val(WRITE) }, { stepsDashDash: true }), {}, { lacks: ["-v", "-q", "-f", "--portability", "--append", "--verbose", "--quiet", "--help", "--version", "--format", "--output"] }), launcher: {}, witness: BINARY },
423
- launcher("watch", { shellText: "joined" }, undefined, { witness: SHELL_TEXT_LAUNCHER }),
424
+ { key: "watch", grammars: [
425
+ launcherGrammar({
426
+ switches: ["-b", "-C", "-c", "-e", "-f", "-g", "-h", "-p", "-r", "-t", "-w", "-v", "-x", "--beep", "--color", "--no-color", "--errexit", "--follow", "--chgexit", "--exec", "--precise", "--no-rerun", "--no-title", "--no-wrap", "--help", "--version"],
427
+ banners: ["-h", "-v"],
428
+ values: { "-n": COUNT, "--interval": COUNT, "-q": COUNT, "--equexit": COUNT, "-s": WRITE, "--shotsdir": WRITE },
429
+ optional: { "-d": LABEL, "--differences": LABEL },
430
+ }, { afterFirstOperand: "operands", stepsDashDash: true }),
431
+ launcherGrammar({ switches: ["-d", "-t"], values: { "-n": COUNT } }, { afterFirstOperand: "operands", stepsDashDash: true }),
432
+ ], launcher: { shellText: "joined", programWith: ["-x", "--exec"] }, witness: SHELL_TEXT_LAUNCHER },
424
433
  launcher("setsid", {}, launcherGrammar({ switches: ["-c", "-f", "-w", "--ctty", "--fork", "--wait", "--help", "--version"] })),
425
434
  launcher("flock", { requiredOperands: 1 }, launcherGrammar({
426
435
  switches: ["-s", "-x", "-u", "-n", "-o", "-F", "--shared", "--exclusive", "--unlock", "--nonblock", "--nb", "--close", "--no-fork", "--verbose", "--help", "--version"],
@@ -496,7 +505,7 @@ const git = {
496
505
  const noPath = (key, rest, extra = {}) => ({ key, grammars: [], operands: { rest }, witness: BINARY, ...extra });
497
506
  const BUILTIN_ONLY = { declared: "a shell builtin with no binary of its own on every host: its words are read by the shell" };
498
507
  const noPathRows = [
499
- noPath("pwd", LABEL, { builtin: "inert" }), noPath("echo", LABEL, { builtin: "inert", grammars: [grammar(switches("neE"), {}, { afterFirstOperand: "operands" })], prints: "words" }), noPath("printf", LABEL, { grammars: [grammar({ v: val(BINDS_NAME) })], prints: "format" }), noPath("whoami", LABEL), noPath("uname", LABEL),
508
+ noPath("pwd", LABEL, { builtin: "inert" }), noPath("echo", LABEL, { builtin: "inert", grammars: [grammar(switches("neE"), {}, { afterFirstOperand: "operands" })] }), noPath("printf", LABEL, { grammars: [grammar({ v: val(BINDS_NAME) })] }), noPath("whoami", LABEL), noPath("uname", LABEL),
500
509
  noPath("which", LABEL), noPath("basename", LABEL), noPath("dirname", LABEL),
501
510
  { key: "tr", grammars: [], operands: { rest: LABEL, stdinBelow: "always" }, witness: BINARY },
502
511
  noPath("cal", COUNT), noPath("uptime", LABEL), noPath("id", LABEL), noPath("groups", LABEL), noPath("nproc", LABEL), noPath("locale", LABEL),
@@ -575,6 +584,7 @@ const stdinReaders = [
575
584
  ];
576
585
  const SYNTAX = { declared: "shell syntax, not a program: read by the lexer" };
577
586
  const block = (key, g = []) => ({ key, grammars: g, syntax: "block", witness: SYNTAX });
587
+ const BLOCK_GRAMMARS = { "[[": [grammar({ v: val(BINDS_NAME) })] };
578
588
  export const PROGRAM_ROWS = [
579
589
  head, tail, cut, grepRow("grep"), grepRow("egrep"), grepRow("fgrep"), diff, cmp, sed, date, tar, find, curl,
580
590
  ls, walker("du", "names", true), walker("rg", "contents", false), walker("tree", "names", true), walker("ag", "contents", false), walker("ack", "contents", false),
@@ -614,11 +624,9 @@ export const PROGRAM_ROWS = [
614
624
  ...nameBinders,
615
625
  ...["make", "gmake", "bmake", "cmake", "ninja", "meson"].map(assignmentNotPaths),
616
626
  containerRuntime("docker"), containerRuntime("podman"),
617
- { key: "pushd", grammars: [], movesBase: "unfollowed", witness: BUILTIN_ONLY },
618
- { key: "popd", grammars: [], movesBase: "unfollowed", witness: BUILTIN_ONLY },
627
+ ...[...shellWordsOf("stack_mover")].map((key) => ({ key, grammars: [], movesBase: "stack", witness: BUILTIN_ONLY })),
619
628
  ...SHELLS.map((s) => shellRow(s, "c-option", BINARY, [SHELL_GRAMMARS[s]], "script")),
620
629
  shellRow("eval", "words", BUILTIN_ONLY), shellRow("source", "file-operand", BUILTIN_ONLY), shellRow(".", "file-operand", BUILTIN_ONLY), shellRow("parallel", "non-option-words", BINARY, [], "script"),
621
630
  ...codeBodyRows,
622
- ...["for", "select", "case", "esac", "fi", "done", "function", "coproc", "]]", "in"].map((k) => block(k)),
623
- block("[[", [grammar({ v: val(BINDS_NAME) })]),
631
+ ...[...shellWordsOf("block")].map((k) => block(k, BLOCK_GRAMMARS[k])),
624
632
  ];