@sema-agent/core 7.54.1 → 7.56.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 (621) hide show
  1. package/CHANGELOG.md +950 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cascade.js +1 -1
  5. package/dist/agents/cc-peer-directory.d.ts +36 -0
  6. package/dist/agents/cc-peer-directory.js +139 -0
  7. package/dist/agents/cc-peer-wire.d.ts +105 -0
  8. package/dist/agents/cc-peer-wire.js +98 -0
  9. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  10. package/dist/agents/cc-uds-peer-channel.js +457 -0
  11. package/dist/agents/child-model-seat.d.ts +0 -11
  12. package/dist/agents/child-model-seat.js +0 -3
  13. package/dist/agents/cross-session-envelope.d.ts +4 -1
  14. package/dist/agents/cross-session-envelope.js +8 -1
  15. package/dist/agents/cross-session-judge.d.ts +2 -2
  16. package/dist/agents/list-agents-tool.d.ts +3 -1
  17. package/dist/agents/list-agents-tool.js +9 -8
  18. package/dist/agents/observer.d.ts +4 -5
  19. package/dist/agents/observer.js +2 -1
  20. package/dist/agents/peer-admission.d.ts +6 -0
  21. package/dist/agents/peer-admission.js +4 -1
  22. package/dist/agents/peer-directory.d.ts +65 -13
  23. package/dist/agents/peer-directory.js +90 -25
  24. package/dist/agents/peer-notices.d.ts +1 -1
  25. package/dist/agents/peer-session-drain.d.ts +3 -1
  26. package/dist/agents/peer-session-drain.js +3 -2
  27. package/dist/agents/read-inbox-tool.js +2 -1
  28. package/dist/agents/repair-loop.js +2 -2
  29. package/dist/agents/retain-ledger.d.ts +1 -1
  30. package/dist/agents/roster-store.d.ts +1 -1
  31. package/dist/agents/send-message-tool.d.ts +10 -0
  32. package/dist/agents/send-message-tool.js +37 -8
  33. package/dist/agents/subagent.d.ts +39 -82
  34. package/dist/agents/subagent.js +109 -106
  35. package/dist/agents/tool-filter.d.ts +31 -46
  36. package/dist/agents/tool-filter.js +13 -33
  37. package/dist/agents/verify.d.ts +6 -5
  38. package/dist/agents/verify.js +3 -3
  39. package/dist/brain/anthropic.js +43 -81
  40. package/dist/brain/errors.d.ts +15 -0
  41. package/dist/brain/errors.js +10 -0
  42. package/dist/brain/media-degrade.d.ts +18 -7
  43. package/dist/brain/media-degrade.js +13 -2
  44. package/dist/brain/model-capability.d.ts +37 -0
  45. package/dist/brain/model-capability.js +34 -0
  46. package/dist/brain/model-presets.d.ts +6 -12
  47. package/dist/brain/model-presets.js +1 -6
  48. package/dist/brain/open-responses.js +27 -35
  49. package/dist/brain/openai.js +30 -98
  50. package/dist/brain/provider-dialect.d.ts +39 -3
  51. package/dist/brain/provider-dialect.js +28 -0
  52. package/dist/brain/reasoning-request.d.ts +96 -0
  53. package/dist/brain/reasoning-request.js +174 -0
  54. package/dist/brain/reasoning.d.ts +12 -12
  55. package/dist/brain/reasoning.js +4 -3
  56. package/dist/brain/request-params.d.ts +62 -9
  57. package/dist/brain/request-params.js +42 -7
  58. package/dist/brain/retry.d.ts +1 -1
  59. package/dist/brain/route-adjudicator.d.ts +15 -0
  60. package/dist/brain/route-adjudicator.js +15 -0
  61. package/dist/brain/status-sink.d.ts +20 -0
  62. package/dist/brain/status-sink.js +7 -0
  63. package/dist/brain/stream-engine.js +6 -5
  64. package/dist/brain/stream-shared.d.ts +1 -1
  65. package/dist/core/a2a.d.ts +2 -1
  66. package/dist/core/a2a.js +19 -13
  67. package/dist/core/advisor-verdict.d.ts +120 -0
  68. package/dist/core/advisor-verdict.js +92 -0
  69. package/dist/core/agent-definition.d.ts +17 -8
  70. package/dist/core/allow-entry.d.ts +69 -36
  71. package/dist/core/allow-entry.js +81 -52
  72. package/dist/core/allow-rule-shadow.d.ts +10 -3
  73. package/dist/core/approval-object.d.ts +2 -1
  74. package/dist/core/approval-object.js +6 -6
  75. package/dist/core/ask-origin.d.ts +127 -29
  76. package/dist/core/ask-origin.js +87 -25
  77. package/dist/core/ask-question.d.ts +51 -8
  78. package/dist/core/ask-question.js +12 -7
  79. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  80. package/dist/core/ask-unresolvable-notice.js +16 -2
  81. package/dist/core/auto-compaction.d.ts +11 -8
  82. package/dist/core/auto-compaction.js +4 -2
  83. package/dist/core/auto-mode-arming.d.ts +2 -2
  84. package/dist/core/auto-mode-defaults.d.ts +8 -8
  85. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  86. package/dist/core/auto-mode-prompt.d.ts +1 -1
  87. package/dist/core/auto-mode.d.ts +17 -9
  88. package/dist/core/auto-mode.js +9 -6
  89. package/dist/core/background-agent-store.d.ts +3 -3
  90. package/dist/core/canonical-json.d.ts +1 -1
  91. package/dist/core/canonical-json.js +2 -2
  92. package/dist/core/checkpoint-generation.d.ts +53 -0
  93. package/dist/core/checkpoint-generation.js +35 -0
  94. package/dist/core/checkpoint-queries.d.ts +180 -0
  95. package/dist/core/checkpoint-queries.js +272 -0
  96. package/dist/core/checkpoint-requirements.d.ts +19 -4
  97. package/dist/core/checkpoint-requirements.js +8 -14
  98. package/dist/core/checkpoint-store.d.ts +165 -72
  99. package/dist/core/checkpoint-store.js +79 -82
  100. package/dist/core/child-clamp-seats.d.ts +6 -0
  101. package/dist/core/child-clamp-seats.js +3 -16
  102. package/dist/core/compliance.d.ts +2 -2
  103. package/dist/core/context-edit.d.ts +6 -7
  104. package/dist/core/cross-boundary-taint.d.ts +11 -4
  105. package/dist/core/cross-boundary-taint.js +3 -3
  106. package/dist/core/decision-receipt.d.ts +37 -3
  107. package/dist/core/decision-receipt.js +19 -19
  108. package/dist/core/delegation-not-started.d.ts +6 -0
  109. package/dist/core/delegation-not-started.js +17 -0
  110. package/dist/core/effective-path-target.d.ts +1 -1
  111. package/dist/core/engine-attestation.d.ts +93 -0
  112. package/dist/core/engine-attestation.js +70 -0
  113. package/dist/core/engine-capabilities.d.ts +4 -1
  114. package/dist/core/engine-capabilities.js +1 -1
  115. package/dist/core/engine-notice.d.ts +45 -12
  116. package/dist/core/exec-output-tail.d.ts +1 -1
  117. package/dist/core/file-history-retention.d.ts +1 -1
  118. package/dist/core/file-history-store.d.ts +147 -21
  119. package/dist/core/file-history-store.js +58 -32
  120. package/dist/core/gate-fold.d.ts +1 -1
  121. package/dist/core/gate-fold.js +24 -11
  122. package/dist/core/gate-lanes.js +81 -68
  123. package/dist/core/gate-outcome.d.ts +40 -6
  124. package/dist/core/gate-outcome.js +56 -0
  125. package/dist/core/governance-codes.d.ts +17 -3
  126. package/dist/core/governance-codes.js +16 -0
  127. package/dist/core/hands-band.d.ts +1 -1
  128. package/dist/core/hooks.d.ts +21 -20
  129. package/dist/core/hooks.js +3 -1
  130. package/dist/core/host-floor.d.ts +128 -0
  131. package/dist/core/host-floor.js +206 -0
  132. package/dist/core/host-target.d.ts +84 -0
  133. package/dist/core/host-target.js +92 -0
  134. package/dist/core/image-downsample.d.ts +1 -1
  135. package/dist/core/lsp-diagnostics.d.ts +4 -4
  136. package/dist/core/lsp.d.ts +3 -3
  137. package/dist/core/mailbox-store.d.ts +4 -0
  138. package/dist/core/mcp-connection-pool.d.ts +18 -2
  139. package/dist/core/mcp-connection-pool.js +53 -6
  140. package/dist/core/mcp-failure.d.ts +23 -4
  141. package/dist/core/mcp-failure.js +26 -11
  142. package/dist/core/mcp-listing-drift.d.ts +10 -0
  143. package/dist/core/mcp-listing-drift.js +6 -0
  144. package/dist/core/mcp-server-link.d.ts +173 -0
  145. package/dist/core/mcp-server-link.js +127 -0
  146. package/dist/core/mcp-server-spec.d.ts +4 -2
  147. package/dist/core/mcp-session-end.d.ts +26 -0
  148. package/dist/core/mcp-session-end.js +29 -0
  149. package/dist/core/mcp-startup-request.d.ts +17 -0
  150. package/dist/core/mcp-startup-request.js +17 -0
  151. package/dist/core/mcp.d.ts +17 -13
  152. package/dist/core/mcp.js +240 -189
  153. package/dist/core/media-byte-cap.d.ts +1 -1
  154. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  155. package/dist/core/memory-engine/engine.d.ts +9 -9
  156. package/dist/core/memory-engine/engine.js +4 -4
  157. package/dist/core/memory-engine/layout.d.ts +60 -8
  158. package/dist/core/memory-engine/layout.js +65 -6
  159. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  160. package/dist/core/memory-engine/tools.js +4 -1
  161. package/dist/core/mode-policy.d.ts +1 -1
  162. package/dist/core/model-seat.d.ts +10 -3
  163. package/dist/core/mods/classic-events.d.ts +67 -0
  164. package/dist/core/mods/classic-events.js +1 -0
  165. package/dist/core/mods/dollar.d.ts +13 -0
  166. package/dist/core/mods/extension-call.d.ts +31 -0
  167. package/dist/core/mods/extension-call.js +43 -0
  168. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  169. package/dist/core/mods/kernel/dispatch.js +140 -69
  170. package/dist/core/mods/kernel/events.d.ts +47 -11
  171. package/dist/core/mods/kernel/events.js +66 -42
  172. package/dist/core/mods/kernel/index.d.ts +4 -4
  173. package/dist/core/mods/kernel/index.js +2 -2
  174. package/dist/core/mods/kernel/receive.d.ts +39 -5
  175. package/dist/core/mods/kernel/receive.js +290 -17
  176. package/dist/core/mods/kernel/registration.d.ts +33 -2
  177. package/dist/core/mods/kernel/registration.js +6 -7
  178. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  179. package/dist/core/mods/kernel/site-rules.js +24 -42
  180. package/dist/core/mods/spec-seats.d.ts +69 -0
  181. package/dist/core/mods/spec-seats.js +114 -0
  182. package/dist/core/mods/stations.d.ts +28 -8
  183. package/dist/core/mods/stations.js +29 -13
  184. package/dist/core/mods/tool-call.d.ts +79 -0
  185. package/dist/core/mods/tool-call.js +152 -0
  186. package/dist/core/namespaced-rule-name.d.ts +44 -24
  187. package/dist/core/namespaced-rule-name.js +50 -43
  188. package/dist/core/output-style.d.ts +1 -1
  189. package/dist/core/param-rule-reach.d.ts +15 -0
  190. package/dist/core/param-rule-reach.js +30 -0
  191. package/dist/core/parent-spec-seat.d.ts +13 -1
  192. package/dist/core/parent-spec-seat.js +6 -0
  193. package/dist/core/park-selfcheck.js +1 -0
  194. package/dist/core/pause-registry.d.ts +16 -5
  195. package/dist/core/pause-registry.js +6 -2
  196. package/dist/core/peer-channel.d.ts +70 -0
  197. package/dist/core/peer-channel.js +1 -0
  198. package/dist/core/permission-rule-consent.d.ts +30 -5
  199. package/dist/core/permission-rule-consent.js +147 -50
  200. package/dist/core/permission-rule-model.d.ts +245 -65
  201. package/dist/core/permission-rule-model.js +421 -107
  202. package/dist/core/permission-rule-org.d.ts +6 -2
  203. package/dist/core/permission-rule-org.js +7 -3
  204. package/dist/core/permission-rule-provider.d.ts +6 -2
  205. package/dist/core/permission-rule-provider.js +41 -11
  206. package/dist/core/permission-rule-store.d.ts +22 -26
  207. package/dist/core/permission-rule-store.js +12 -6
  208. package/dist/core/permission-rule-sync.d.ts +11 -2
  209. package/dist/core/permission-rule-sync.js +11 -3
  210. package/dist/core/permission-rule-syntax.d.ts +5 -4
  211. package/dist/core/permission-rule-syntax.js +2 -2
  212. package/dist/core/permission-rules.d.ts +53 -15
  213. package/dist/core/permission-rules.js +125 -100
  214. package/dist/core/persisted-rule-arms.d.ts +6 -4
  215. package/dist/core/persisted-rule-arms.js +10 -12
  216. package/dist/core/present-plan-tool.js +3 -1
  217. package/dist/core/principal-name.d.ts +20 -0
  218. package/dist/core/principal-name.js +22 -0
  219. package/dist/core/prompt-section-seat.js +4 -6
  220. package/dist/core/protocol-http-auth.d.ts +26 -5
  221. package/dist/core/protocol-http-auth.js +137 -4
  222. package/dist/core/protocol-naming.d.ts +2 -2
  223. package/dist/core/read-only-shell-table.d.ts +1 -1
  224. package/dist/core/read-only-shell.d.ts +1 -1
  225. package/dist/core/retired-keys.d.ts +16 -0
  226. package/dist/core/retired-keys.js +16 -4
  227. package/dist/core/rewrite-rejudge.d.ts +60 -0
  228. package/dist/core/rewrite-rejudge.js +36 -0
  229. package/dist/core/roles.d.ts +34 -3
  230. package/dist/core/roles.js +66 -53
  231. package/dist/core/rule-lane-reads.d.ts +20 -15
  232. package/dist/core/rule-lane-reads.js +45 -17
  233. package/dist/core/rule-offer-read.d.ts +53 -0
  234. package/dist/core/rule-offer-read.js +146 -0
  235. package/dist/core/rule-owner.d.ts +46 -0
  236. package/dist/core/rule-owner.js +29 -0
  237. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  238. package/dist/core/runner/advisor-instructions.js +61 -0
  239. package/dist/core/runner/advisor-tool.d.ts +33 -0
  240. package/dist/core/runner/advisor-tool.js +112 -0
  241. package/dist/core/runner/announce-once-ledger.d.ts +18 -26
  242. package/dist/core/runner/announce-once-ledger.js +19 -46
  243. package/dist/core/runner/approval-feedback.js +6 -3
  244. package/dist/core/runner/assemble-result.d.ts +2 -1
  245. package/dist/core/runner/assemble-result.js +1 -1
  246. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  247. package/dist/core/runner/caller-roster.d.ts +21 -2
  248. package/dist/core/runner/caller-roster.js +38 -0
  249. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  250. package/dist/core/runner/capability-withheld-seat.js +24 -0
  251. package/dist/core/runner/classifier-ladder.d.ts +33 -13
  252. package/dist/core/runner/classifier-ladder.js +15 -14
  253. package/dist/core/runner/compaction-restate.d.ts +10 -6
  254. package/dist/core/runner/compaction-restate.js +9 -3
  255. package/dist/core/runner/construction-doors.js +3 -0
  256. package/dist/core/runner/contracts.d.ts +40 -33
  257. package/dist/core/runner/conversation-segment.d.ts +28 -0
  258. package/dist/core/runner/conversation-segment.js +42 -0
  259. package/dist/core/runner/cross-boundary-lane.d.ts +21 -16
  260. package/dist/core/runner/cross-boundary-lane.js +58 -34
  261. package/dist/core/runner/decide-continuation.d.ts +7 -4
  262. package/dist/core/runner/decide-continuation.js +2 -2
  263. package/dist/core/runner/denial-limit-arms.d.ts +4 -4
  264. package/dist/core/runner/denial-limit-arms.js +1 -1
  265. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  266. package/dist/core/runner/derived-route-fallback.js +9 -7
  267. package/dist/core/runner/file-history-request.d.ts +18 -0
  268. package/dist/core/runner/file-history-request.js +21 -13
  269. package/dist/core/runner/file-history-restore.d.ts +45 -0
  270. package/dist/core/runner/file-history-restore.js +46 -0
  271. package/dist/core/runner/gate-exit.d.ts +9 -3
  272. package/dist/core/runner/gate-exit.js +11 -5
  273. package/dist/core/runner/image.d.ts +7 -17
  274. package/dist/core/runner/image.js +9 -60
  275. package/dist/core/runner/initial-run-state.js +1 -1
  276. package/dist/core/runner/permission-rule-lanes.d.ts +6 -6
  277. package/dist/core/runner/permission-rule-lanes.js +38 -15
  278. package/dist/core/runner/person-path-rows.d.ts +12 -9
  279. package/dist/core/runner/person-path-rows.js +19 -8
  280. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  281. package/dist/core/runner/prepare-advisor.js +77 -0
  282. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  283. package/dist/core/runner/prepare-ask-lane.js +5 -2
  284. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  285. package/dist/core/runner/prepare-caps-and-workflow.js +5 -4
  286. package/dist/core/runner/prepare-config-doors.d.ts +31 -38
  287. package/dist/core/runner/prepare-config-doors.js +57 -34
  288. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  289. package/dist/core/runner/prepare-defer-classify.js +7 -8
  290. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  291. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  292. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  293. package/dist/core/runner/prepare-file-history.js +41 -73
  294. package/dist/core/runner/prepare-gate-stations.d.ts +2 -5
  295. package/dist/core/runner/prepare-gate-stations.js +12 -8
  296. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  297. package/dist/core/runner/prepare-hands-readface.js +15 -14
  298. package/dist/core/runner/prepare-inherited-gate.d.ts +11 -7
  299. package/dist/core/runner/prepare-inherited-gate.js +8 -6
  300. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  301. package/dist/core/runner/prepare-park-ask.js +12 -12
  302. package/dist/core/runner/prepare-policy-chain.d.ts +7 -4
  303. package/dist/core/runner/prepare-policy-chain.js +68 -81
  304. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  305. package/dist/core/runner/prepare-project-context.js +6 -3
  306. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  307. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  308. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  309. package/dist/core/runner/prepare-prompt-inputs.js +4 -6
  310. package/dist/core/runner/prepare-protocol-tools.d.ts +4 -2
  311. package/dist/core/runner/prepare-protocol-tools.js +5 -4
  312. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  313. package/dist/core/runner/prepare-safety-scan.js +8 -23
  314. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  315. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  316. package/dist/core/runner/prepare-task.d.ts +1 -1
  317. package/dist/core/runner/prepare-task.js +41 -35
  318. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  319. package/dist/core/runner/prepare-tool-disclosure-mount.js +24 -18
  320. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  321. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  322. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -4
  323. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  324. package/dist/core/runner/resume-admission.js +1 -1
  325. package/dist/core/runner/resume-apply.js +11 -12
  326. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  327. package/dist/core/runner/resume-claim.d.ts +4 -2
  328. package/dist/core/runner/resume-claim.js +15 -8
  329. package/dist/core/runner/resume-policy-outcome.js +1 -1
  330. package/dist/core/runner/retired-runner-deps.js +2 -1
  331. package/dist/core/runner/rewind-files.d.ts +15 -0
  332. package/dist/core/runner/rewind-files.js +132 -0
  333. package/dist/core/runner/run-attachment-seats.js +2 -2
  334. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  335. package/dist/core/runner/run-brain-sinks.js +4 -2
  336. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  337. package/dist/core/runner/run-compaction-machinery.js +2 -12
  338. package/dist/core/runner/run-git-lane.d.ts +1 -0
  339. package/dist/core/runner/run-harness-handlers.js +14 -7
  340. package/dist/core/runner/run-leg.d.ts +1 -1
  341. package/dist/core/runner/run-leg.js +43 -18
  342. package/dist/core/runner/run-settle-and-teardown.js +3 -2
  343. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  344. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  345. package/dist/core/runner/run-turn-boundary.js +15 -22
  346. package/dist/core/runner/runtask.d.ts +3 -0
  347. package/dist/core/runner/runtask.js +8 -9
  348. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  349. package/dist/core/runner/session-read-file-states.js +28 -0
  350. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  351. package/dist/core/runner/session-rule-policy.js +17 -31
  352. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  353. package/dist/core/runner/shell-env-withheld.js +51 -0
  354. package/dist/core/runner/side-call-account.d.ts +32 -8
  355. package/dist/core/runner/side-call-account.js +23 -1
  356. package/dist/core/runner/skills-seat.js +6 -2
  357. package/dist/core/runner/stream-settle-backstop.js +1 -1
  358. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  359. package/dist/core/runner/sub-agent-deny-lists.js +4 -6
  360. package/dist/core/runner/synthetic-tools.d.ts +16 -13
  361. package/dist/core/runner/synthetic-tools.js +8 -3
  362. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  363. package/dist/core/runner/tool-disclosure.js +3 -4
  364. package/dist/core/runner/tool-end-body.d.ts +1 -1
  365. package/dist/core/runner/tool-end-body.js +10 -9
  366. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  367. package/dist/core/runner/tool-face-overlay.js +17 -1
  368. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  369. package/dist/core/runner/tool-not-executed.js +11 -0
  370. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  371. package/dist/core/runner/tool-occurrence.js +7 -0
  372. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  373. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  374. package/dist/core/runner/turn-attachments.d.ts +91 -80
  375. package/dist/core/runner/turn-attachments.js +62 -37
  376. package/dist/core/runner-deps.d.ts +42 -42
  377. package/dist/core/runtime-caps.d.ts +4 -4
  378. package/dist/core/safety-axis-vocab.d.ts +6 -4
  379. package/dist/core/safety-axis-vocab.js +6 -5
  380. package/dist/core/safety-merge-corpus.js +26 -2
  381. package/dist/core/same-plain-value.d.ts +40 -0
  382. package/dist/core/same-plain-value.js +49 -0
  383. package/dist/core/scheduler.d.ts +1 -1
  384. package/dist/core/secret-env.d.ts +26 -3
  385. package/dist/core/secret-env.js +44 -8
  386. package/dist/core/select-model.js +3 -3
  387. package/dist/core/sensitive-path-policy.d.ts +1 -1
  388. package/dist/core/sensitive-path-policy.js +1 -1
  389. package/dist/core/session-policy-store.d.ts +102 -35
  390. package/dist/core/session-policy-store.js +210 -48
  391. package/dist/core/session-reconcile.d.ts +2 -2
  392. package/dist/core/session-store.d.ts +106 -37
  393. package/dist/core/session-store.js +165 -91
  394. package/dist/core/session.d.ts +101 -57
  395. package/dist/core/session.js +53 -0
  396. package/dist/core/shared-memory/tools.js +3 -1
  397. package/dist/core/shared-memory/types.d.ts +1 -1
  398. package/dist/core/shell-read-silence.d.ts +11 -12
  399. package/dist/core/shell-read-silence.js +9 -5
  400. package/dist/core/shell-run-candidates.js +3 -1
  401. package/dist/core/shell-wrapper-projection.js +1 -1
  402. package/dist/core/shell-wrapper-table.d.ts +14 -7
  403. package/dist/core/shell-wrapper-table.js +5 -4
  404. package/dist/core/side-query.d.ts +10 -0
  405. package/dist/core/side-query.js +15 -1
  406. package/dist/core/skill-grant.d.ts +7 -2
  407. package/dist/core/skill-grant.js +5 -0
  408. package/dist/core/skills-directory.js +6 -2
  409. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  410. package/dist/core/store-contracts/checkpoint-store-contract.js +168 -3
  411. package/dist/core/store-contracts/file-history-store-contract.js +74 -4
  412. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  413. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  414. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  415. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  416. package/dist/core/store-contracts/session-repo-contract.js +176 -0
  417. package/dist/core/store-contracts/session-store-contract.d.ts +6 -8
  418. package/dist/core/store-contracts/session-store-contract.js +361 -51
  419. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  420. package/dist/core/stub-env.d.ts +2 -0
  421. package/dist/core/stub-env.js +1 -0
  422. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  423. package/dist/core/synthetic-read-verdict.js +3 -3
  424. package/dist/core/task-event.d.ts +42 -8
  425. package/dist/core/task-notification.d.ts +19 -15
  426. package/dist/core/task-registry-agent.d.ts +4 -4
  427. package/dist/core/task-registry-shared.d.ts +4 -4
  428. package/dist/core/task-registry-shared.js +1 -0
  429. package/dist/core/task-registry.d.ts +13 -4
  430. package/dist/core/task-registry.js +14 -2
  431. package/dist/core/task-result.d.ts +21 -3
  432. package/dist/core/task-spec.d.ts +69 -64
  433. package/dist/core/task-stream.d.ts +6 -6
  434. package/dist/core/task-tool-shape.d.ts +4 -4
  435. package/dist/core/tighten-task-spec.d.ts +1 -1
  436. package/dist/core/tighten-task-spec.js +2 -1
  437. package/dist/core/tool-catalog-entries.d.ts +36 -2
  438. package/dist/core/tool-catalog-entries.js +69 -43
  439. package/dist/core/tool-check-reading.d.ts +11 -0
  440. package/dist/core/tool-check-reading.js +11 -6
  441. package/dist/core/tool-conformance.js +1 -0
  442. package/dist/core/tool-errors.d.ts +2 -2
  443. package/dist/core/tool-face-reader.js +5 -3
  444. package/dist/core/tool-face.d.ts +21 -2
  445. package/dist/core/tool-face.js +1 -1
  446. package/dist/core/tool-model-gate.d.ts +5 -5
  447. package/dist/core/tool-name-aliases.d.ts +29 -8
  448. package/dist/core/tool-name-aliases.js +22 -4
  449. package/dist/core/tool-name-readings.d.ts +10 -43
  450. package/dist/core/tool-name-readings.js +2 -11
  451. package/dist/core/tool-policy.d.ts +85 -196
  452. package/dist/core/tool-policy.js +150 -175
  453. package/dist/core/tool-registry.d.ts +14 -7
  454. package/dist/core/tool-registry.js +17 -7
  455. package/dist/core/tool-result-store.js +5 -1
  456. package/dist/core/tool-roster.d.ts +57 -33
  457. package/dist/core/tool-roster.js +56 -68
  458. package/dist/core/tool-spec-members.js +8 -3
  459. package/dist/core/tool-spec.d.ts +53 -31
  460. package/dist/core/tools.js +51 -10
  461. package/dist/core/trace.d.ts +6 -2
  462. package/dist/core/types.d.ts +1 -1
  463. package/dist/core/untrusted-egress.d.ts +1 -1
  464. package/dist/core/untrusted-text.d.ts +1 -1
  465. package/dist/core/user-attachment.d.ts +8 -1
  466. package/dist/core/user-attachment.js +64 -4
  467. package/dist/core/warm-resume.d.ts +1 -1
  468. package/dist/core/wiring-manifest.d.ts +58 -0
  469. package/dist/core/wiring-manifest.js +14 -5
  470. package/dist/core/workflow-journal-store.d.ts +62 -0
  471. package/dist/core/workflow-journal-store.js +78 -2
  472. package/dist/core/workflow-run-store.d.ts +6 -0
  473. package/dist/core/workflow-run-store.js +2 -0
  474. package/dist/engine/compaction/compaction.d.ts +9 -9
  475. package/dist/engine/compaction/compaction.js +3 -2
  476. package/dist/engine/execution-env/node-execution-env.d.ts +26 -8
  477. package/dist/engine/execution-env/node-execution-env.js +54 -24
  478. package/dist/engine/harness/agent-harness.d.ts +39 -9
  479. package/dist/engine/harness/agent-harness.js +87 -33
  480. package/dist/engine/harness/types.d.ts +58 -9
  481. package/dist/engine/harness/types.js +12 -1
  482. package/dist/engine/llm/types.d.ts +36 -19
  483. package/dist/engine/llm/validation.d.ts +4 -1
  484. package/dist/engine/llm/validation.js +13 -1
  485. package/dist/engine/loop/agent-loop.d.ts +23 -1
  486. package/dist/engine/loop/agent-loop.js +26 -34
  487. package/dist/engine/loop/types.d.ts +31 -19
  488. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  489. package/dist/engine/session/memory-repo.d.ts +18 -12
  490. package/dist/engine/session/memory-repo.js +24 -9
  491. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  492. package/dist/engine/session/parent-chain-guard.js +1 -1
  493. package/dist/engine/session/repo-utils.d.ts +32 -3
  494. package/dist/engine/session/repo-utils.js +50 -5
  495. package/dist/index.d.ts +47 -23
  496. package/dist/index.js +35 -17
  497. package/dist/internal/harness-types.d.ts +1 -1
  498. package/dist/internal/harness.d.ts +3 -3
  499. package/dist/internal/harness.js +2 -2
  500. package/dist/internal/llm.d.ts +2 -2
  501. package/dist/internal/llm.js +1 -1
  502. package/dist/orchestration/goal.js +2 -2
  503. package/dist/orchestration/run-workflow-tool.d.ts +8 -6
  504. package/dist/orchestration/run-workflow-tool.js +10 -6
  505. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  506. package/dist/orchestration/workflow-types.d.ts +18 -0
  507. package/dist/orchestration/workflow-types.js +6 -0
  508. package/dist/orchestration/workflow.d.ts +5 -13
  509. package/dist/orchestration/workflow.js +57 -49
  510. package/dist/prompt-assembly/artifact.d.ts +2 -2
  511. package/dist/prompt-assembly/artifact.js +5 -3
  512. package/dist/prompt-assembly/assemble.d.ts +3 -2
  513. package/dist/prompt-assembly/assemble.js +1 -1
  514. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  515. package/dist/prompt-assembly/catalog/schema.js +34 -2
  516. package/dist/prompt-assembly/catalog/sections.js +0 -1
  517. package/dist/prompt-assembly/composer.d.ts +3 -1
  518. package/dist/prompt-assembly/composer.js +1 -1
  519. package/dist/prompt-assembly/event-registry.js +2 -0
  520. package/dist/prompt-assembly/overlay.js +3 -3
  521. package/dist/prompt-assembly/renderers.d.ts +1 -1
  522. package/dist/prompt-assembly/renderers.js +0 -3
  523. package/dist/prompt-assembly/role-base.d.ts +15 -0
  524. package/dist/prompt-assembly/role-base.js +9 -0
  525. package/dist/prompt-assembly/select.d.ts +39 -14
  526. package/dist/prompt-assembly/select.js +47 -16
  527. package/dist/prompt-assembly/sugar.d.ts +17 -11
  528. package/dist/prompt-assembly/sugar.js +8 -3
  529. package/dist/prompt-assembly/tool-catalog.d.ts +39 -2
  530. package/dist/prompt-assembly/tool-catalog.js +117 -4
  531. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  532. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  533. package/dist/prompt-assembly/types.d.ts +0 -7
  534. package/dist/prompts/default.d.ts +14 -14
  535. package/dist/scenarios/full-body.d.ts +15 -15
  536. package/dist/scenarios/full-body.js +4 -3
  537. package/dist/shell/lex.js +10 -1
  538. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  539. package/dist/stores/file/adoption/adopt.js +27 -33
  540. package/dist/stores/file/adoption/marker.d.ts +6 -13
  541. package/dist/stores/file/adoption/marker.js +9 -17
  542. package/dist/stores/file/checkpoint-store.d.ts +24 -0
  543. package/dist/stores/file/checkpoint-store.js +45 -7
  544. package/dist/stores/file/file-history-store.d.ts +20 -19
  545. package/dist/stores/file/file-history-store.js +157 -141
  546. package/dist/stores/file/fs-atomic.d.ts +15 -0
  547. package/dist/stores/file/fs-atomic.js +89 -14
  548. package/dist/stores/file/index.d.ts +1 -1
  549. package/dist/stores/file/index.js +2 -1
  550. package/dist/stores/file/mailbox-store.d.ts +3 -0
  551. package/dist/stores/file/mailbox-store.js +3 -1
  552. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  553. package/dist/stores/file/permission-rule-adopt.js +18 -18
  554. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  555. package/dist/stores/file/permission-rule-store.js +31 -18
  556. package/dist/stores/file/session-policy-store.d.ts +3 -3
  557. package/dist/stores/file/session-store.d.ts +54 -16
  558. package/dist/stores/file/session-store.js +114 -85
  559. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  560. package/dist/stores/file/workflow-journal-store.js +28 -13
  561. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  562. package/dist/tools/artifact/artifact-tool.js +5 -3
  563. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  564. package/dist/tools/fs/bash-program-position.js +56 -9
  565. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  566. package/dist/tools/fs/fs-bash.d.ts +2 -2
  567. package/dist/tools/fs/fs-bash.js +8 -6
  568. package/dist/tools/fs/fs-glob.d.ts +86 -0
  569. package/dist/tools/fs/fs-glob.js +226 -0
  570. package/dist/tools/fs/fs-read.js +14 -14
  571. package/dist/tools/fs/fs-search-tools.js +7 -7
  572. package/dist/tools/fs/fs-shared.d.ts +8 -8
  573. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  574. package/dist/tools/fs/notebook.d.ts +2 -2
  575. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  576. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  577. package/dist/tools/fs/pdf.d.ts +9 -6
  578. package/dist/tools/fs/pdf.js +3 -3
  579. package/dist/tools/fs/program-read-model.d.ts +57 -7
  580. package/dist/tools/fs/program-read-model.js +11 -1
  581. package/dist/tools/fs/program-read-model.rows.js +78 -21
  582. package/dist/tools/fs/read-deny-home.js +3 -2
  583. package/dist/tools/fs/read-deny.d.ts +29 -7
  584. package/dist/tools/fs/read-deny.js +63 -22
  585. package/dist/tools/fs/removal-targets.d.ts +18 -8
  586. package/dist/tools/fs/removal-targets.js +47 -20
  587. package/dist/tools/fs/safety.d.ts +9 -9
  588. package/dist/tools/fs/search.d.ts +16 -6
  589. package/dist/tools/fs/search.js +20 -26
  590. package/dist/tools/fs/shell-read-argv.js +89 -12
  591. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  592. package/dist/tools/fs/shell-read-bindings.js +41 -0
  593. package/dist/tools/fs/shell-read-check.js +12 -20
  594. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  595. package/dist/tools/fs/shell-read-environment.js +3 -2
  596. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  597. package/dist/tools/fs/shell-read-establish.js +19 -20
  598. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  599. package/dist/tools/fs/shell-read-judge.js +5 -2
  600. package/dist/tools/fs/shell-read-plan.js +24 -16
  601. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  602. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  603. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  604. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  605. package/dist/tools/fs/shell-reentry-text.js +40 -2
  606. package/dist/tools/loop-tick.d.ts +2 -2
  607. package/dist/tools/scheduler-tools.js +5 -1
  608. package/dist/tools/task-list.d.ts +7 -7
  609. package/dist/tools/task-list.js +5 -1
  610. package/dist/tools/todo.js +65 -64
  611. package/dist/tools/web.d.ts +20 -15
  612. package/dist/tools/web.js +55 -69
  613. package/dist/tools/worktree.d.ts +3 -3
  614. package/dist/tools/worktree.js +3 -1
  615. package/package.json +1 -1
  616. package/test/export-surface.snapshot.json +5894 -5638
  617. package/wire-changes/core@7.55.0.json +3318 -0
  618. package/wire-changes/core@7.56.0.json +3891 -0
  619. package/wire-changes/mods-kernel@7.56.0.json +303 -0
  620. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  621. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -8,10 +8,12 @@
8
8
  * must match this InMemory one byte-for-byte — a cross-backend equivalence test is the contract).
9
9
  *
10
10
  * Safety model:
11
- * - **tighten-only by default**: a NORMAL write may only ADD denies / NARROW allowlists / NARROW allowDirs. A
12
- * write that LOOSENS (removes a deny, widens an allowlist/allowDirs) is REFUSED unless it is an OPERATOR
13
- * write. core has NO role system — `operator` is a boolean the caller FREEZES from a verified principal
14
- * (mirrors `steer.trusted`); core never adjudicates operator-ness, it only honors the flag.
11
+ * - **tighten-only below what an operator wrote**: a NORMAL write may not loosen the row's operator part
12
+ * ({@link StoredSessionRules.operatorRules}: what the last operator write set; absent, the whole row) — above it, it
13
+ * may take back what normal writes added (a deny, its own allowlist or allowDirs narrowing). The one `putRules` is
14
+ * the write port and the delete port alike: a rule leaves every gate that reads the row when the row stops holding it.
15
+ * core has NO role system — `operator` is a boolean the caller FREEZES from a verified principal (mirrors
16
+ * `steer.trusted`); core never adjudicates operator-ness, it only honors the flag.
15
17
  * - **CAS rev** (optimistic concurrency): a `putRules` with a stale `expectedRev` is rejected, so two replicas
16
18
  * can't lose an update (mirrors the checkpoint store's `resolve` OCC).
17
19
  * - **one grammar**: the two rule buckets hold rule ENTRIES — the grammar every entry list reads, through its one reader
@@ -19,8 +21,9 @@
19
21
  * path rule, a name or host rule. Entries are stored as written; every station that validates, compares, matches or
20
22
  * names one reads that reader's answer ({@link judgeSessionRulesWrite}, {@link loosenReasons}, the run-time layer).
21
23
  * - **a row keeps its grammar**: the write judge stamps the grammar it read the entries in ({@link SESSION_RULES_GRAMMAR}), and
22
- * every station reads a row's entries in the grammar the row carries ({@link readSessionRulesShape}) — a row stored before
23
- * the stamp keeps the reading it was written under, so an upgrade never turns a stored entry into a grant.
24
+ * every station reads a row's entries in the grammar the row carries ({@link readSessionRulesShape}) — an entry keeps the meaning
25
+ * its writer's grammar gave it, one that grammar could not read takes this engine's, and a row whose entries the two grammars
26
+ * read differently is announced ({@link earlierGrammarReads}).
24
27
  * - **rules are read as rules or not at all**: rules whose shape cannot be read, or whose toolDeny holds an entry no grammar
25
28
  * reads ({@link unreadableDenyEntries}), refuse every call until an operator writes them afresh — never read as fewer.
26
29
  * - **NOT A SANDBOX**: a shell command rule reads the command line the call carries (every program run in its connector
@@ -60,10 +63,33 @@ export type SessionRuleEntryField = {
60
63
  * `*`, one more name no tool carried, which voided nothing beside it;
61
64
  * - 1, the one entry reader taking its tool name from the lenient rule parser (trimmed before a `(`, any character but a
62
65
  * blank, a parenthesis or a control / format character);
63
- * - 2, the rule syntax's tool-name head (`ruleSpellingOf`): a name is read as written, in the characters names are minted in.
64
- * An entry this grammar reads as no rule in a row an earlier grammar wrote reads as `earlier_grammar` ({@link compileSessionRuleBucket}).
66
+ * - 2, the rule syntax's tool-name head (`ruleSpellingOf`): a name is read as written, in the characters names are minted in;
67
+ * - 3, the whole-protocol names (`mcp__*`, `mcp__*__*`, see `wholeProtocolOf`) read as a deny rule in `toolDeny` — every tool of the
68
+ * protocol — where grammar 2 read them as an entry that names nothing. An engine of grammar 2 given a row written in grammar 3
69
+ * refuses it ({@link grammarOf}) rather than read the deny as nothing;
70
+ * - 4, the delegation tool's type rules (`Agent(<subagent_type>)`) read as a rule on the agent type the call runs — where grammar 3
71
+ * read them as an entry with no rule form (and its write judge refused one) — and a Bash pattern (`Bash(git * main)`, a star
72
+ * anywhere but the two trailing markers) reads as the `pattern` match form — where grammar 3 had no form for it — so an engine of
73
+ * grammar 3 given a row written in grammar 4 refuses it rather than read an `Agent(…)` or `Bash(<pattern>)` deny as nothing;
74
+ * - 5, a `*` in a tool name is the name grammar's pattern: in `toolDeny` anywhere in the name, over the whole name (`Re*d`, `*` —
75
+ * every tool), where grammar 4 read `*` and a `*` in a protocol peer as entries that name nothing, `Re*d` as an exact name and a
76
+ * name starting with `*` as no rule; in `toolAllow` it grants nothing by itself and the entries beside it keep their reading,
77
+ * where grammars 1–4 voided a list holding it. An engine of grammar 4 given a row written in grammar 5 refuses it rather than
78
+ * read a `*` deny as nothing. In the same revision a host pattern with an empty label (`WebFetch(domain:.evil.test)`) or a `*`
79
+ * the URL parser folds (`*.`) is no rule, where grammar 4 read the exact host it spelled; an earlier row's such entry reads as no rule.
80
+ * A row an earlier grammar wrote keeps the meaning that grammar gave its entries, and an entry that grammar could not read takes
81
+ * this one's ({@link earlierGrammarReads}, over the revisions above as one table); an entry this grammar reads as no rule reads as
82
+ * `earlier_grammar` ({@link compileSessionRuleBucket}).
83
+ *
84
+ * The persisted rule store stamps the same number on each bucket it writes (and the rule-sync wire on each state it sends):
85
+ * a stored rule's text is a `Tool(content)` entry read by the same parser, so every revision of what such a text means is a
86
+ * revision counted here. A revision that touches only the entry list (a tool-name head, a protocol name) moves the persisted
87
+ * stamp too, and an engine before it then refuses a bucket it could have read — the refusing side. The persisted store keeps
88
+ * no earlier reading: its rows are read in this grammar whatever stamp at or below it they carry, so a revision that changes
89
+ * what an existing persisted rule text means owes that store a reading of its earlier stamps, as {@link earlierGrammarReads}
90
+ * is for entries. Every stamp is judged by {@link readRuleGrammarStamp}.
65
91
  */
66
- export declare const SESSION_RULES_GRAMMAR = 2;
92
+ export declare const SESSION_RULES_GRAMMAR = 5;
67
93
  /** {@link SessionPermissionRules} plus the monotonic `rev` the store stamps (the OCC key). */
68
94
  export interface StoredSessionRules extends SessionPermissionRules {
69
95
  rev: number;
@@ -75,18 +101,31 @@ export interface StoredSessionRules extends SessionPermissionRules {
75
101
  /** The rule grammar the row's entries are read in ({@link SESSION_RULES_GRAMMAR}), stamped by the write judge. Absent =
76
102
  * a row stored before the stamp: grammar 0. */
77
103
  grammar?: number;
104
+ /** The row's OPERATOR PART: the buckets (and their grammar) the last operator write set — the line a non-operator write
105
+ * may not loosen ({@link judgeSessionRulesWrite}). Minted by the write judge alone, and present only once a non-operator
106
+ * write stamped the row (it carries the part it was judged against; over no row, the part of the value it wrote when that
107
+ * value is a stored row — a rev from 1 — else an empty part). ABSENT = the whole row is the operator's: an operator write, and a row stored before
108
+ * the member, read fail-closed. Never enforced itself — the row's buckets are what every gate reads. */
109
+ operatorRules?: SessionPermissionRules & {
110
+ grammar: number;
111
+ };
78
112
  }
79
- /** A rules value as the shape reading hands it on ({@link readSessionRulesShape}): its buckets, and the grammar its entries
80
- * are read in — resolved, so a store that serves it on beside its own counters serves the row's grammar with it. */
113
+ /** A rules value as the shape reading hands it on ({@link readSessionRulesShape}): its buckets, the grammar its entries
114
+ * are read in — resolved, so a store that serves it on beside its own counters serves the row's grammar with it — and the
115
+ * row's operator part when it carries one ({@link StoredSessionRules.operatorRules}). */
81
116
  export type SessionRulesInGrammar = SessionPermissionRules & {
82
117
  grammar: number;
118
+ operatorRules?: SessionPermissionRules & {
119
+ grammar: number;
120
+ };
83
121
  };
84
122
  /** Options for {@link SessionPolicyStore.putRules}. */
85
123
  export interface PutRulesOptions {
86
124
  /** CAS: reject the write if the stored `rev` is not this (optimistic concurrency). Omit to skip the check. */
87
125
  expectedRev?: number;
88
- /** When true, this write MAY loosen the rules (remove a deny / widen an allowlist or allowDirs). A NORMAL
89
- * (non-operator) write is TIGHTEN-ONLY. core does NOT verify operator-ness — the caller (service) FREEZES
126
+ /** When true, this write MAY loosen the rules (remove a deny / widen an allowlist or allowDirs), and what it writes is
127
+ * the operator's whole. A NORMAL (non-operator) write may not loosen the row's operator part
128
+ * ({@link StoredSessionRules.operatorRules}). core does NOT verify operator-ness — the caller (service) FREEZES
90
129
  * this from a verified, role-checked principal (mirrors `steer.trusted`). */
91
130
  operator?: boolean;
92
131
  }
@@ -105,7 +144,7 @@ export interface SessionRuleEntryRefusal extends AllowEntryInertDetail {
105
144
  reason: AllowEntryInertReason;
106
145
  }
107
146
  /** Typed error from {@link SessionPolicyStore.putRules}. `conflict` = stale `expectedRev`; `loosen_forbidden`
108
- * = a non-operator write tried to relax the rules; `corrupt` = a backend could not read what it stored (a row, or the
147
+ * = a non-operator write tried to relax what an operator wrote; `corrupt` = a backend could not read what it stored (a row, or the
109
148
  * erase-surviving rev mark of {@link SessionPolicyStore.deleteBySession}) and refuses rather than read it as fewer rules or
110
149
  * stamp an unproven rev; `invalid_shape` = the rules value is not an object of buckets, each a list of strings
111
150
  * ({@link readSessionRulesShape}); `inert_entry` = a bucket holds an entry the entry reader reads as nothing. `detail` is
@@ -142,8 +181,9 @@ export interface SessionRulesRecord {
142
181
  export interface SessionPolicyStore {
143
182
  getRules(sessionId: string, principal?: string): Promise<StoredSessionRules | null>;
144
183
  /** Write the rules for a key through the one write judge ({@link judgeSessionRulesWrite}): CAS on `expectedRev`, the
145
- * shape, every entry's reading (operator writes included), then, for a non-operator write over an existing row, the
146
- * tighten-only check — each refusal a {@link SessionPolicyError}, and nothing is written. */
184
+ * shape, every entry's reading (operator writes included), then, for a non-operator write, the check against the row's
185
+ * operator part — each refusal a {@link SessionPolicyError}, and nothing is written. The same call is the delete port: a
186
+ * value without an entry takes it out of every gate that reads the row. */
147
187
  putRules(sessionId: string, principal: string | undefined, rules: SessionPermissionRules, opts?: PutRulesOptions): Promise<StoredSessionRules>;
148
188
  /**
149
189
  * 2c session-sync: every (principal, rules) record for `sessionId` across ALL principals — `getRules`
@@ -193,13 +233,33 @@ export interface SessionPolicyStore {
193
233
  * backend should keep `allowDirs` to real directories; a future symlink-aware write-time canonicalize closes it.
194
234
  */
195
235
  declare function lexWithin(root: string, p: string): boolean;
236
+ /**
237
+ * THE ONE JUDGE of a rule grammar stamp, whichever store carries it — a session-rules row ({@link readSessionRulesShape}),
238
+ * the persisted rule store's bucket and the rule-sync wire: the grammar the stamped rules are read in, or the fault that
239
+ * makes them unreadable. `absent` is what a missing stamp reads as (each store says what its unstamped rules were written
240
+ * in). A stamp is a whole number no greater than {@link SESSION_RULES_GRAMMAR}: a later grammar is one this engine cannot
241
+ * read the rules in, and reading them in an older one could grant what their writer refused or drop a refusal it cannot
242
+ * name — so they are refused WHOLE (`later`), never read in part. `rules` names the stamped rules in the sentence, `held`
243
+ * what they hold (`entries`, `rows`).
244
+ */
245
+ export declare function readRuleGrammarStamp(stamp: unknown, absent: number, words: {
246
+ readonly rules: string;
247
+ readonly held: string;
248
+ }): {
249
+ grammar: number;
250
+ } | {
251
+ got: string;
252
+ sentence: string;
253
+ later?: true;
254
+ };
196
255
  /**
197
256
  * THE ONE SHAPE READING of a rules value — what every station that takes one reads it through: the write (incoming rules),
198
257
  * a store's read-back of its own rows, the tighten comparison's prior, the run-time layer's served row. A rules value is an
199
258
  * object whose keys are buckets ({@link SessionPermissionRules}); each bucket present is a list of strings (`allowDirs`: of
200
259
  * non-blank strings — a directory is no blank). A bucket's TYPE is all this reads: what an entry means is the entry reader's,
201
260
  * in the grammar the value is written in ({@link grammarOf}), handed on as `grammar`. The store's counters (`rev`, `gen`) are
202
- * passed over, and a key holding `undefined` holds nothing. Anything else is a fault, named by key and by TYPE, never by value —
261
+ * passed over, the row's operator part is read as rules of its own and handed on ({@link readOperatorPart}), and a key
262
+ * holding `undefined` holds nothing. Anything else is a fault, named by key and by TYPE, never by value —
203
263
  * a bare string is never one rule and never its characters (`"rm"` spread into `["r","m"]`), and a key outside the buckets is
204
264
  * never dropped (a dropped deny is a deny nobody enforces).
205
265
  */
@@ -227,15 +287,17 @@ export declare function normalizeRules(rules: unknown): SessionPermissionRules;
227
287
  export declare function unreadableDenyEntries(rules: SessionRulesInGrammar, roster?: ReadonlySet<string>): AllowEntryInert[];
228
288
  /**
229
289
  * THE LIST READING of one rule bucket of a rules value the shape reading read — what the run-time layer enforces, the tighten
230
- * comparison compares and the write judge refuses on: `compileAllowList` over the one entry reader, in the bucket's direction,
231
- * against `roster` when given, in the grammar the value is written in. An entry its grammar reads as nothing
232
- * ({@link earlierGrammarReads}) is moved to the entries that read as nothing, reason `earlier_grammar`, before the list is
233
- * compiled: it is one entry that reads as nothing, and the list beside it is read as written. The move is an ENTRY's reading and
234
- * never the list's: an allow list a `*` voids (in any spelling the voiding test reads as `*`, `* (*)` included) is voided in
235
- * every grammar from 1 on, so in such a row the list is read whole, as written — only grammar 0, where `*` was one more name, takes
236
- * it out alone.
290
+ * comparison compares and the write judge refuses on: the one entry reader over each entry, in the bucket's direction, against
291
+ * `roster` when given, in the grammar the value is written in ({@link earlierGrammarReads}: an entry keeps the meaning its
292
+ * writer's grammar gave it, and one that grammar could not read takes this engine's). The reading is an entry's — save the one
293
+ * list reading a row keeps: grammars 1–4 voided an allow list holding `*` (in any spelling their voiding test read as `*`, `* (*)`
294
+ * included), so such a row's allow list grants nothing; from grammar 5 a `*` grants nothing by itself and the list beside it is read
295
+ * as written. The entries that read as nothing are listed in order, those an earlier grammar reads so (`earlier_grammar`) last.
237
296
  */
238
297
  export declare function compileSessionRuleBucket(rules: SessionRulesInGrammar, field: SessionRuleEntryField, roster?: ReadonlySet<string>): ReturnType<typeof compileAllowList>;
298
+ /** The entries of one bucket a stored row's earlier grammar announces ({@link earlierGrammarReads}: its writer's meaning and this
299
+ * grammar's differ) — what `config.session_rules_earlier_grammar` names, one bucket at a time. */
300
+ export declare function earlierGrammarEntries(rules: SessionRulesInGrammar, field: SessionRuleEntryField): string[];
239
301
  /**
240
302
  * The advisory for the entries of one bucket a stored row's earlier grammar reads as nothing ({@link compileSessionRuleBucket},
241
303
  * `earlier_grammar`; `grammar` = the row's): the session, the bucket, the entries as written, what they do and the way out. An
@@ -245,9 +307,10 @@ export declare function compileSessionRuleBucket(rules: SessionRulesInGrammar, f
245
307
  * to make a parenthesized one the rule it now spells, or (`*`, which is no allow rule in any grammar) to leave it out.
246
308
  */
247
309
  export declare function earlierGrammarAdvisory(sessionId: string, entries: readonly string[], field: SessionRuleEntryField, grammar: number): string;
248
- /** The reader's word for one entry an earlier grammar reads as nothing: `no_rule` — this engine's rule grammar reads it as no
249
- * rule; `named_no_tool` — a grammar-0 allow entry the bare-name comparison of its day read as naming no tool. */
250
- export type EarlierGrammarReader = "no_rule" | "named_no_tool";
310
+ /** The reader's word for one entry an earlier grammar announces: `no_rule` — this engine's rule grammar reads it as no rule;
311
+ * `named_no_tool` — a grammar-0 allow entry the bare-name comparison of its day read as naming no tool; `grammar_revised` — a
312
+ * grammar revision after the row's gave the entry another meaning, and the message names both and which one the rules enforce. */
313
+ export type EarlierGrammarReader = "no_rule" | "named_no_tool" | "grammar_revised";
251
314
  /**
252
315
  * The notice for the entries of one bucket a stored row's earlier grammar reads as nothing (`config.session_rules_earlier_grammar`,
253
316
  * audience `user` — the session's rules are what the person's calls are judged by): the message is {@link earlierGrammarAdvisory}
@@ -277,14 +340,18 @@ export declare function earlierGrammarAnnouncer(sink: ((entries: readonly string
277
340
  * the rules to stamp, or a {@link SessionPolicyError}, in this order — `conflict` (a stale `expectedRev` against `prior`'s rev),
278
341
  * `invalid_shape` ({@link normalizeRules}), `inert_entry` (an entry that reads as nothing in the grammar the rules are written
279
342
  * in; operator writes included — a rule that names nothing guards nothing whoever writes it), then, for a non-operator write
280
- * over an existing row, `loosen_forbidden` ({@link loosenReasons}) — or `corrupt` when that prior cannot be read as rules,
281
- * which the comparison never reads as fewer. The rules to stamp carry `grammar` = {@link SESSION_RULES_GRAMMAR}: what passed
282
- * the judge means the same in this engine's grammar, and THIS is the one place the stamp is minted, so every store that
283
- * stores what the judge returns keeps it. `mountedToolNames` = the store's declaration ({@link SessionPolicyStoreOptions.mountedToolNames}).
343
+ * over a row, `loosen_forbidden` ({@link loosenReasons}) against the row's OPERATOR PART ({@link StoredSessionRules.operatorRules};
344
+ * absent, the whole row) — or `corrupt` when that prior cannot be read as rules, which the comparison never reads as fewer.
345
+ * Over no row there is no rev to compare and no tighten gate, and a judge called with `prior = null` (a host's pre-read of a
346
+ * value's shape and entries) answers only those two content refusals. Below what an operator wrote nothing moves; above it,
347
+ * a non-operator takes back what non-operator writes added. The
348
+ * rules to stamp carry `grammar` = {@link SESSION_RULES_GRAMMAR} — what passed the judge means the same in this engine's
349
+ * grammar — and, from a non-operator write, the operator part it was judged against: over no row, the value's own when it is a
350
+ * stored row handed in ({@link isStoredRow}), else an empty one (an operator write's whole value is the operator's, so it
351
+ * carries none). THIS is the one place both stamps are minted, so every store that stores what the judge
352
+ * returns keeps them. `mountedToolNames` = the store's declaration ({@link SessionPolicyStoreOptions.mountedToolNames}).
284
353
  */
285
- export declare function judgeSessionRulesWrite(prior: StoredSessionRules | null, rules: unknown, opts: PutRulesOptions | undefined, mountedToolNames?: ReadonlySet<string>): SessionPermissionRules & {
286
- grammar: number;
287
- };
354
+ export declare function judgeSessionRulesWrite(prior: StoredSessionRules | null, rules: unknown, opts: PutRulesOptions | undefined, mountedToolNames?: ReadonlySet<string>): SessionRulesInGrammar;
288
355
  /**
289
356
  * Pure tighten-only diff: the reasons `next` LOOSENS `prior` (empty ⇒ `next` is a pure tightening or no-op), over the EFFECTIVE
290
357
  * entries of each rule bucket — the list as the run-time layer enforces it ({@link effectiveEntries}). Rules whose toolDeny holds
@@ -321,7 +388,7 @@ export declare function continuesLineage(a: {
321
388
  }): boolean;
322
389
  /**
323
390
  * In-process default {@link SessionPolicyStore} (single-replica). A deployment that needs cross-replica
324
- * durability supplies its own backend with the SAME CAS-rev + tighten-only semantics. Single-threaded JS makes
391
+ * durability supplies its own backend with the SAME CAS-rev + write-judge semantics. Single-threaded JS makes
325
392
  * the read-check-write trivially atomic here; a durable backend folds it into a CAS WHERE clause.
326
393
  */
327
394
  export declare class InMemorySessionPolicyStore implements SessionPolicyStore {
@@ -4,12 +4,15 @@ import { NAMESPACED_NAME_SHAPES } from "./protocol-table.js";
4
4
  import { callerToolNameProblem } from "./caller-tool-name.js";
5
5
  import { compileAllowList, compiledEntryName, inertEntryPhrase, readRuleEntry, renderListEntry, rootFacingToolNames } from "./allow-entry.js";
6
6
  import { valueTypeLabel } from "./tool-name-list.js";
7
- import { noticeRuleText } from "./permission-rule-model.js";
7
+ import { NAME_RULE_FACES, noticeRuleText } from "./permission-rule-model.js";
8
+ import { parsePermissionRule, ruleSpellingOf } from "./permission-rule-syntax.js";
9
+ import { splitNamespacedName } from "./tool-name-aliases.js";
8
10
  const SESSION_RULE_BUCKETS = { toolAllow: "allow", toolDeny: "deny", allowDirs: "dirs" };
9
11
  const BUCKETS = Object.keys(SESSION_RULE_BUCKETS);
10
12
  const ENTRY_FIELDS = BUCKETS.filter((f) => SESSION_RULE_BUCKETS[f] !== "dirs");
11
13
  const STORE_STAMPS = new Set(["rev", "gen", "grammar"]);
12
- export const SESSION_RULES_GRAMMAR = 2;
14
+ const OPERATOR_PART = "operatorRules";
15
+ export const SESSION_RULES_GRAMMAR = 5;
13
16
  export class SessionPolicyError extends Error {
14
17
  code;
15
18
  detail;
@@ -53,18 +56,26 @@ function lexWithin(root, p) {
53
56
  return true;
54
57
  return np === nr || np.startsWith(nr + "/");
55
58
  }
59
+ function isStoredRow(value) {
60
+ const rev = value.rev;
61
+ return typeof rev === "number" && Number.isInteger(rev) && rev >= 1;
62
+ }
56
63
  function grammarOf(value) {
57
64
  const stamp = value.grammar;
65
+ return readRuleGrammarStamp(stamp, stamp === undefined && isStoredRow(value) ? 0 : SESSION_RULES_GRAMMAR, { rules: "session rules", held: "entries" });
66
+ }
67
+ export function readRuleGrammarStamp(stamp, absent, words) {
58
68
  if (stamp === undefined)
59
- return { grammar: value.rev !== undefined ? 0 : SESSION_RULES_GRAMMAR };
69
+ return { grammar: absent };
60
70
  if (typeof stamp !== "number" || !Number.isInteger(stamp) || stamp < 0) {
61
71
  const got = typeof stamp === "number" ? "a number that is not a whole number of 0 or more" : valueTypeLabel(stamp);
62
- return { got, sentence: `session rules carry a grammar stamp that is ${got} — the stamp is the whole number of the rule grammar the rules were written in (this engine reads grammar ${SESSION_RULES_GRAMMAR})` };
72
+ return { got, sentence: `${words.rules} carry a grammar stamp that is ${got} — the stamp is the whole number of the rule grammar the rules were written in (this engine reads grammar ${SESSION_RULES_GRAMMAR})` };
63
73
  }
64
74
  if (stamp > SESSION_RULES_GRAMMAR) {
65
75
  return {
66
76
  got: `${stamp}, a grammar newer than this engine's (${SESSION_RULES_GRAMMAR})`,
67
- sentence: `session rules were written in rule grammar ${stamp}, newer than this engine reads (grammar ${SESSION_RULES_GRAMMAR}) — refusing rather than read their entries in an older grammar; an engine that reads grammar ${stamp} reads them`,
77
+ sentence: `${words.rules} were written in rule grammar ${stamp}, newer than this engine reads (grammar ${SESSION_RULES_GRAMMAR}) — refusing rather than read their ${words.held} in an older grammar; an engine that reads grammar ${stamp} reads them`,
78
+ later: true,
68
79
  };
69
80
  }
70
81
  return { grammar: stamp };
@@ -82,6 +93,13 @@ export function readSessionRulesShape(value) {
82
93
  for (const [key, v] of Object.entries(value)) {
83
94
  if (STORE_STAMPS.has(key) || v === undefined)
84
95
  continue;
96
+ if (key === OPERATOR_PART) {
97
+ const part = readOperatorPart(v);
98
+ if ("fault" in part)
99
+ return part;
100
+ rules.operatorRules = part.rules;
101
+ continue;
102
+ }
85
103
  if (!Object.hasOwn(SESSION_RULE_BUCKETS, key)) {
86
104
  return fault(key, "not a rule bucket", `session rules hold ${JSON.stringify(key)}, which is not a rule bucket — the buckets are ${BUCKETS.join(", ")}, and a shell command rule is a toolDeny / toolAllow entry written Bash(<command>) (Bash(rm:*) matches a command whose first word is rm)`);
87
105
  }
@@ -100,6 +118,20 @@ export function readSessionRulesShape(value) {
100
118
  }
101
119
  return { rules };
102
120
  }
121
+ function readOperatorPart(value) {
122
+ const read = readSessionRulesShape(value);
123
+ if ("fault" in read) {
124
+ const field = read.fault.field === "" ? OPERATOR_PART : `${OPERATOR_PART}.${read.fault.field}`;
125
+ return { fault: { field, got: read.fault.got }, sentence: `the session rules' operator part: ${read.sentence}` };
126
+ }
127
+ const { operatorRules: nested, ...part } = read.rules;
128
+ const unstamped = value.grammar === undefined;
129
+ if (unstamped || nested !== undefined) {
130
+ const got = unstamped ? "rules without a grammar stamp" : "an operator part of its own";
131
+ return { fault: { field: OPERATOR_PART, got }, sentence: `session rules carry an operator part holding ${got} — the part is the rules the last operator write set, stamped with their grammar by the write judge` };
132
+ }
133
+ return { rules: part };
134
+ }
103
135
  export function normalizeRules(rules) {
104
136
  return canonicalRules(shapeOrRefuse(rules));
105
137
  }
@@ -119,42 +151,142 @@ function canonicalRules(read) {
119
151
  }
120
152
  return out;
121
153
  }
122
- function earlierGrammarReads(grammar, field, entry, reading) {
123
- if (grammar >= SESSION_RULES_GRAMMAR)
124
- return false;
125
- if (reading.kind === "inert" && reading.reason === "grammar")
126
- return true;
127
- if (grammar !== 0 || SESSION_RULE_BUCKETS[field] !== "allow")
128
- return false;
129
- return reading.kind === "row" ? compiledEntryName(reading.compiled) !== entry : reading.reason === "wildcard_all";
154
+ const NAMES_NO_TOOL = "an entry naming no tool, so it refused nothing";
155
+ const NO_RULE_THEN = (direction) => (direction === "allow" ? "no rule, so it admitted nothing" : "no rule, so the rules could not be read and refused every call");
156
+ const NAME_PATTERN_NOW = "a pattern over the whole tool name, every tool it matches";
157
+ function spellsWholeProtocol(name) {
158
+ const split = splitNamespacedName(name);
159
+ return split !== undefined && split.peer === "*" && (split.tool === undefined || split.tool === "*");
130
160
  }
131
- function readsAsNoRule(entry, field) {
132
- const reading = readRuleEntry(entry, SESSION_RULE_BUCKETS[field]);
133
- return reading.kind === "inert" && reading.reason === "grammar";
161
+ const GRAMMAR_REVISIONS = [
162
+ {
163
+ grammar: 1,
164
+ answer: ({ direction, entry, reading }) => {
165
+ const otherName = reading.kind === "row" ? compiledEntryName(reading.compiled) !== entry : reading.reason === "wildcard_all";
166
+ if (!otherName)
167
+ return undefined;
168
+ if (direction === "allow")
169
+ return { was: "a tool name compared as written, naming no tool", now: "the rule it spells", keep: { kind: "inert", reason: "earlier_grammar" }, reader: "named_no_tool" };
170
+ return reading.kind === "row" ? { was: "a tool name compared as written, naming no tool, so it refused nothing", now: "the rule it spells", reader: "grammar_revised" } : undefined;
171
+ },
172
+ },
173
+ {
174
+ grammar: 3,
175
+ answer: ({ direction, reading }) => direction === "deny" && reading.kind === "row" && reading.compiled.kind === "covering" && spellsWholeProtocol(reading.compiled.pattern)
176
+ ? { was: NAMES_NO_TOOL, now: "a deny of every tool of the protocol", reader: "grammar_revised" }
177
+ : undefined,
178
+ },
179
+ {
180
+ grammar: 4,
181
+ answer: ({ direction, reading }) => {
182
+ if (reading.kind !== "row")
183
+ return undefined;
184
+ const { compiled } = reading;
185
+ if (compiled.kind === "name" && NAME_RULE_FACES[compiled.rule.tool]?.values === "mounted") {
186
+ return { was: direction === "allow" ? "an entry with no rule form, so it admitted nothing" : "an entry with no rule form, so it refused nothing", now: "a rule on the agent type it names", reader: "grammar_revised" };
187
+ }
188
+ return compiled.kind === "command" && compiled.rule.match === "pattern" ? { was: NO_RULE_THEN(direction), now: "the Bash pattern rule it spells", reader: "grammar_revised" } : undefined;
189
+ },
190
+ },
191
+ {
192
+ grammar: 5,
193
+ answer: ({ row, direction, entry, reading, list }) => {
194
+ if (direction === "allow") {
195
+ if (row >= 1 && list.some(readsAsWildcard))
196
+ return { was: "voided by the `*` its list holds", now: "one entry that grants nothing, the entries beside it read as written", keep: { kind: "inert", reason: "wildcard_all" } };
197
+ const parsed = reading.kind === "inert" ? ruleSpellingOf(entry) : undefined;
198
+ const name = parsed?.ruleContent === undefined ? parsed?.toolName : undefined;
199
+ if (name === undefined || name === "*" || !name.includes("*") || name.startsWith("*") || splitNamespacedName(name) !== undefined)
200
+ return undefined;
201
+ return { was: `the exact tool name ${JSON.stringify(name)}`, now: "no rule (an allow reads a `*` only in a protocol name's tool segment)", keep: { kind: "row", compiled: { kind: "tool", name } }, reader: "grammar_revised" };
202
+ }
203
+ if (reading.kind !== "row" || reading.compiled.kind !== "covering")
204
+ return undefined;
205
+ const { pattern } = reading.compiled;
206
+ const split = splitNamespacedName(pattern);
207
+ if (!pattern.includes("*") || spellsWholeProtocol(pattern) || (split !== undefined && !split.peer.includes("*")))
208
+ return undefined;
209
+ const answer = { now: NAME_PATTERN_NOW, reader: "grammar_revised" };
210
+ if (pattern === "*")
211
+ return { ...answer, was: NAMES_NO_TOOL, keep: { kind: "inert", reason: "wildcard_all" } };
212
+ if (split !== undefined)
213
+ return { ...answer, was: NAMES_NO_TOOL, keep: { kind: "inert", reason: "namespace_wildcard" } };
214
+ if (pattern.startsWith("*"))
215
+ return { ...answer, was: NO_RULE_THEN(direction) };
216
+ return { ...answer, was: `the exact tool name ${JSON.stringify(pattern)}, so it refused only a tool of that name`, keep: { kind: "row", compiled: { kind: "tool", name: pattern } } };
217
+ },
218
+ },
219
+ ];
220
+ function earlierGrammarReads(row, direction, entry, reading, list) {
221
+ if (row >= SESSION_RULES_GRAMMAR)
222
+ return { reading };
223
+ let first;
224
+ let last;
225
+ let kept;
226
+ for (const revision of GRAMMAR_REVISIONS) {
227
+ if (revision.grammar <= row)
228
+ continue;
229
+ const answer = revision.answer({ row, direction, entry, reading, list });
230
+ if (answer === undefined)
231
+ continue;
232
+ first ??= answer;
233
+ last = answer;
234
+ if (answer.keep !== undefined) {
235
+ kept = answer.keep;
236
+ break;
237
+ }
238
+ }
239
+ const read = kept ?? reading;
240
+ if (read.kind === "inert" && read.reason === "grammar")
241
+ return { reading: { kind: "inert", reason: "earlier_grammar" }, reader: "no_rule" };
242
+ if (first === undefined || last === undefined)
243
+ return { reading: read };
244
+ const reader = first.reader === "named_no_tool" ? first.reader : last.reader;
245
+ if (reader === undefined)
246
+ return { reading: read };
247
+ return { reading: read, reader, ...(reader === "grammar_revised" ? { revised: { was: first.was, now: last.now, stands: kept !== undefined } } : {}) };
134
248
  }
135
249
  const NO_RULE_REASONS = new Set(["grammar", "earlier_grammar"]);
136
250
  export function unreadableDenyEntries(rules, roster) {
137
251
  return compileSessionRuleBucket(rules, "toolDeny", roster).inert.filter((i) => NO_RULE_REASONS.has(i.reason));
138
252
  }
139
- function readsAsWildcard(entry) {
140
- return compileAllowList([entry], "allow").inert.some((i) => i.reason === "wildcard_all");
141
- }
142
253
  const STAR_IS_NO_ALLOW_RULE = "it is no allow rule in any grammar and a write holding it is refused";
143
254
  function starWayOut(onlyStars, others, left) {
144
255
  return onlyStars
145
256
  ? `"*" is no allow rule in any grammar (a write holding it is refused); to drop it, write the session's rules afresh without it ${REWRITE_THROUGH}; ${left}`
146
257
  : `${others}, leaving "*" out — ${STAR_IS_NO_ALLOW_RULE}; ${left}`;
147
258
  }
148
- export function compileSessionRuleBucket(rules, field, roster) {
259
+ function readsAsWildcard(entry) {
260
+ return typeof entry === "string" && entry === entry.trim() && parsePermissionRule(entry).toolName === "*";
261
+ }
262
+ function entryBucketDirection(field) {
149
263
  const direction = SESSION_RULE_BUCKETS[field];
264
+ if (direction === "allow" || direction === "deny")
265
+ return direction;
266
+ throw new SessionPolicyError("invalid_shape", `${JSON.stringify(field)} is no rule-entry bucket of the session rules — the entry buckets are ${ENTRY_FIELDS.join(" and ")}`);
267
+ }
268
+ function bucketReadings(rules, field, roster) {
269
+ const direction = entryBucketDirection(field);
150
270
  const entries = rules[field] ?? [];
151
- const earlier = new Set(entries.filter((e) => earlierGrammarReads(rules.grammar, field, e, readRuleEntry(e, direction, roster))));
152
- const whole = compileAllowList(entries, direction, roster);
153
- const voided = direction === "allow" && whole.inert.some((i) => i.reason === "wildcard_all");
154
- if (earlier.size === 0 || (voided && rules.grammar > 0))
155
- return whole;
156
- const list = compileAllowList(entries.filter((e) => !earlier.has(e)), direction, roster);
157
- return { rows: list.rows, inert: [...list.inert, ...entries.filter((e) => earlier.has(e)).map((entry) => ({ entry, reason: "earlier_grammar" }))] };
271
+ return entries.map((entry) => ({ entry, ...earlierGrammarReads(rules.grammar, direction, entry, readRuleEntry(entry, direction, roster), entries) }));
272
+ }
273
+ export function compileSessionRuleBucket(rules, field, roster) {
274
+ const rows = [];
275
+ const inert = [];
276
+ const earlier = [];
277
+ for (const { entry, reading } of bucketReadings(rules, field, roster)) {
278
+ if (reading.kind === "row")
279
+ rows.push({ entry, compiled: reading.compiled });
280
+ else {
281
+ const { kind: _kind, ...why } = reading;
282
+ void _kind;
283
+ (why.reason === "earlier_grammar" ? earlier : inert).push({ entry, ...why });
284
+ }
285
+ }
286
+ return { rows, inert: [...inert, ...earlier] };
287
+ }
288
+ export function earlierGrammarEntries(rules, field) {
289
+ return bucketReadings(rules, field).flatMap((r) => (r.reader === undefined ? [] : [r.entry]));
158
290
  }
159
291
  const ADVISORY_ENTRIES_SHOWN = 5;
160
292
  function shownEntries(entries, render) {
@@ -163,14 +295,33 @@ function shownEntries(entries, render) {
163
295
  }
164
296
  const REWRITE_THROUGH = `through this engine (an operator write of a new value without the stored row's rev; the write stamps grammar ${SESSION_RULES_GRAMMAR})`;
165
297
  export function earlierGrammarAdvisory(sessionId, entries, field, grammar) {
166
- const read = earlierGrammarReadings(entries, field);
298
+ const read = earlierGrammarReadings(entries, field, grammar);
167
299
  const noRule = read.filter((r) => r.reader === "no_rule").map((r) => r.entry);
168
300
  const namedNoTool = read.filter((r) => r.reader === "named_no_tool").map((r) => r.entry);
169
- const sentences = [...(namedNoTool.length > 0 ? [namedNoToolInGrammar0(namedNoTool)] : []), ...(noRule.length > 0 ? [noRuleInThisGrammar(noRule, field, grammar)] : [])];
301
+ const revised = read.flatMap((r) => (r.revised === undefined ? [] : [{ entry: r.entry, ...r.revised }]));
302
+ const sentences = [
303
+ ...(namedNoTool.length > 0 ? [namedNoToolInGrammar0(namedNoTool)] : []),
304
+ ...(noRule.length > 0 ? [noRuleInThisGrammar(noRule, field, grammar)] : []),
305
+ ...(revised.length > 0 ? [revisedSinceGrammar(revised, field, grammar)] : []),
306
+ ];
170
307
  return `session permission rules of session ${JSON.stringify(sessionId)}: ${sentences.join(" ")}`;
171
308
  }
172
- function earlierGrammarReadings(entries, field) {
173
- return entries.map((entry) => ({ entry, reader: readsAsNoRule(entry, field) ? "no_rule" : "named_no_tool" }));
309
+ function earlierGrammarReadings(entries, field, grammar) {
310
+ const direction = entryBucketDirection(field);
311
+ return entries.map((entry) => {
312
+ const read = earlierGrammarReads(grammar, direction, entry, readRuleEntry(entry, direction), entries);
313
+ return { entry, reader: read.reader ?? "no_rule", ...(read.revised !== undefined ? { revised: read.revised } : {}) };
314
+ });
315
+ }
316
+ function revisedSinceGrammar(entries, field, grammar) {
317
+ const one = entries.length === 1;
318
+ const said = entries
319
+ .slice(0, ADVISORY_ENTRIES_SHOWN)
320
+ .map((e) => `${renderListEntry(e.entry)} meant ${e.was} there; this engine's rule grammar (${SESSION_RULES_GRAMMAR}) reads it as ${e.now}, and ${e.stands ? "the stored meaning stands" : "this grammar's reading applies"}`)
321
+ .join("; ");
322
+ const rest = entries.length > ADVISORY_ENTRIES_SHOWN ? `; and ${entries.length - ADVISORY_ENTRIES_SHOWN} more` : "";
323
+ return (`${field} ${one ? "holds an entry" : "holds entries"} stored in rule grammar ${grammar}${grammar === 0 ? " (before the rule grammar stamp)" : ""} whose meaning a later grammar revised — ${said}${rest}. ` +
324
+ `To give ${one ? "it" : "them"} this grammar's reading, write the session's rules afresh ${REWRITE_THROUGH}; left as stored, ${one ? "it reads" : "they read"} as said.`);
174
325
  }
175
326
  export function earlierGrammarNotice(input) {
176
327
  const { rulesSessionId, sessionId, entries, field, grammar } = input;
@@ -180,7 +331,7 @@ export function earlierGrammarNotice(input) {
180
331
  detail: {
181
332
  bucket: field,
182
333
  storedGrammar: grammar,
183
- entries: earlierGrammarReadings(entries, field).map((r) => ({ entry: noticeRuleText(r.entry), reader: r.reader })),
334
+ entries: earlierGrammarReadings(entries, field, grammar).map((r) => ({ entry: noticeRuleText(r.entry), reader: r.reader })),
184
335
  rewrite: { by: "operator_write_without_rev", stampsGrammar: SESSION_RULES_GRAMMAR },
185
336
  rulesSessionId,
186
337
  sessionId,
@@ -215,8 +366,9 @@ function noRuleInThisGrammar(entries, field, grammar) {
215
366
  export function earlierGrammarRefusalClause(entries, grammar) {
216
367
  if (entries.length === 0)
217
368
  return "";
218
- const noRule = entries.filter((e) => readsAsNoRule(e, "toolAllow")).length;
219
- const namedNoTool = entries.filter((e) => !readsAsNoRule(e, "toolAllow"));
369
+ const read = earlierGrammarReadings(entries, "toolAllow", grammar);
370
+ const noRule = read.filter((r) => r.reader === "no_rule").length;
371
+ const namedNoTool = read.filter((r) => r.reader !== "no_rule").map((r) => r.entry);
220
372
  const stars = namedNoTool.filter(readsAsWildcard).length;
221
373
  const others = namedNoTool.length - stars;
222
374
  const named = [...(stars > 0 ? ['"*"'] : []), ...(others > 0 ? [`${others} parenthesized ${others === 1 ? "entry" : "entries"}`] : [])];
@@ -246,15 +398,13 @@ function effectiveEntries(rules, field, mountedToolNames) {
246
398
  function assertEntriesRead(rules, mountedToolNames) {
247
399
  const known = rootFacingToolNames(mountedToolNames);
248
400
  for (const field of ENTRY_FIELDS) {
249
- for (const entry of rules[field] ?? []) {
250
- const reading = readRuleEntry(entry, SESSION_RULE_BUCKETS[field], known);
251
- const read = earlierGrammarReads(rules.grammar, field, entry, reading) ? { kind: "inert", reason: "earlier_grammar" } : reading;
401
+ for (const { entry, reading: read, reader } of bucketReadings(rules, field, known)) {
252
402
  if (read.kind === "row")
253
403
  continue;
254
404
  const { kind: _kind, ...why } = read;
255
405
  void _kind;
256
406
  const way = why.reason === "earlier_grammar"
257
- ? readsAsNoRule(entry, field)
407
+ ? reader === "no_rule"
258
408
  ? ` These rules are written in grammar ${rules.grammar} (a stored row), and this engine's grammar (${SESSION_RULES_GRAMMAR}) reads this entry as no rule (grammar) — ` +
259
409
  (field === "toolAllow" && readsAsWildcard(entry) ? `leave the entry out: it spells "*", and ${STAR_IS_NO_ALLOW_RULE}.` : "leave the entry out, or spell the tool's name as a rule spells one.")
260
410
  : ` These rules are written in grammar ${rules.grammar} (a stored row from before the grammar stamp), in which this entry names no tool.` +
@@ -284,17 +434,29 @@ export function judgeSessionRulesWrite(prior, rules, opts, mountedToolNames = NO
284
434
  const read = shapeOrRefuse(rules);
285
435
  const clean = canonicalRules(read);
286
436
  assertEntriesRead(read, mountedToolNames);
287
- if (prior !== null && opts?.operator !== true) {
288
- const stored = readSessionRulesShape(prior);
289
- if ("fault" in stored) {
290
- throw new SessionPolicyError("corrupt", `the stored session rules cannot be read as rules (${stored.sentence}) — refusing to judge a non-operator write against them as fewer rules; an operator write replaces them`);
291
- }
292
- const loosens = loosenReasons(stored.rules, clean, mountedToolNames);
293
- if (loosens.length > 0) {
294
- throw new SessionPolicyError("loosen_forbidden", `a non-operator session-rule write may only tighten; refused: ${loosens.join("; ")}`);
295
- }
437
+ if (opts?.operator === true)
438
+ return { ...clean, grammar: SESSION_RULES_GRAMMAR };
439
+ if (prior === null) {
440
+ return { ...clean, grammar: SESSION_RULES_GRAMMAR, operatorRules: isStoredRow(rules) ? operatorPartOf(read) : { grammar: SESSION_RULES_GRAMMAR } };
441
+ }
442
+ const operatorRules = operatorPartOf(readStoredOrRefuse(prior));
443
+ const loosens = loosenReasons(operatorRules, clean, mountedToolNames);
444
+ if (loosens.length > 0) {
445
+ throw new SessionPolicyError("loosen_forbidden", `a non-operator session-rule write may not loosen what an operator wrote; refused: ${loosens.join("; ")}`);
446
+ }
447
+ return { ...clean, grammar: SESSION_RULES_GRAMMAR, operatorRules };
448
+ }
449
+ function operatorPartOf(read) {
450
+ const { operatorRules, ...whole } = read;
451
+ const part = operatorRules ?? whole;
452
+ return { ...canonicalRules(part), grammar: part.grammar };
453
+ }
454
+ function readStoredOrRefuse(prior) {
455
+ const stored = readSessionRulesShape(prior);
456
+ if ("fault" in stored) {
457
+ throw new SessionPolicyError("corrupt", `the stored session rules cannot be read as rules (${stored.sentence}) — refusing to judge a non-operator write against them as fewer rules; an operator write replaces them`);
296
458
  }
297
- return { ...clean, grammar: SESSION_RULES_GRAMMAR };
459
+ return stored.rules;
298
460
  }
299
461
  export function loosenReasons(priorValue, nextValue, mountedToolNames = NO_DECLARED_TOOLS) {
300
462
  const shapeOf = (side, value) => {