@sema-agent/server 7.132.0 → 7.133.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 (402) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +174 -55
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +79 -19
  24. package/dist/approval-card.js +44 -13
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +27 -10
  29. package/dist/audit.js +12 -16
  30. package/dist/bake-runner/main.js +3 -2
  31. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  32. package/dist/boot/execution-env.js +9 -7
  33. package/dist/boot/execution-lane.js +11 -0
  34. package/dist/boot/leader.js +2 -0
  35. package/dist/boot/memory-boundary.js +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +5 -4
  37. package/dist/boot/memory-consolidation.js +7 -6
  38. package/dist/boot/org-delivery.d.ts +28 -0
  39. package/dist/boot/org-delivery.js +20 -0
  40. package/dist/boot/reapers.d.ts +3 -0
  41. package/dist/boot/reapers.js +21 -1
  42. package/dist/boot/resolve-spec.d.ts +3 -0
  43. package/dist/boot/resolve-spec.js +60 -81
  44. package/dist/boot/runner-deps.js +1 -0
  45. package/dist/boot/session-faces.d.ts +1 -0
  46. package/dist/boot/session-faces.js +4 -2
  47. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  48. package/dist/boot/stage-06-runners.d.ts +2 -0
  49. package/dist/boot/stage-06-runners.js +6 -3
  50. package/dist/boot/stage-07-capability-layer.d.ts +2 -0
  51. package/dist/boot/stage-07-capability-layer.js +24 -3
  52. package/dist/boot/stage-08-reapers.d.ts +2 -0
  53. package/dist/boot/stage-08-reapers.js +2 -2
  54. package/dist/boot/stage-09-leader.d.ts +3 -0
  55. package/dist/boot/stage-10-http-server.d.ts +3 -0
  56. package/dist/boot/stage-10-http-server.js +5 -6
  57. package/dist/boot/stores.js +2 -2
  58. package/dist/boot/web-admin.d.ts +4 -0
  59. package/dist/boot/web-admin.js +151 -63
  60. package/dist/boot/workflow-orchestration.d.ts +2 -0
  61. package/dist/boot/workflow-orchestration.js +2 -1
  62. package/dist/brain.js +8 -3
  63. package/dist/breaker-key.d.ts +6 -0
  64. package/dist/breaker-key.js +29 -0
  65. package/dist/caller-text-echo.d.ts +9 -6
  66. package/dist/caller-text-echo.js +8 -11
  67. package/dist/capabilities/center-plugins.d.ts +7 -0
  68. package/dist/capabilities/center-plugins.js +1 -1
  69. package/dist/capabilities/composite-members.d.ts +1 -1
  70. package/dist/capabilities/composite-members.js +1 -1
  71. package/dist/capabilities/execution-lane.js +2 -2
  72. package/dist/capabilities/hands-lane.d.ts +21 -0
  73. package/dist/capabilities/hands-lane.js +10 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -4
  75. package/dist/capabilities/mcp-probe.js +27 -4
  76. package/dist/capabilities/scenarios.d.ts +63 -7
  77. package/dist/capabilities/scenarios.js +39 -7
  78. package/dist/capability-facts.d.ts +34 -4
  79. package/dist/capability-facts.js +28 -2
  80. package/dist/center-config-tier.d.ts +69 -0
  81. package/dist/center-config-tier.js +42 -0
  82. package/dist/checkpoint-identity.d.ts +16 -0
  83. package/dist/checkpoint-identity.js +19 -0
  84. package/dist/config-catalog.d.ts +17 -10
  85. package/dist/config-catalog.js +43 -28
  86. package/dist/config-d-migration.d.ts +3 -1
  87. package/dist/config-d-migration.js +2 -2
  88. package/dist/config-dir-trust.d.ts +114 -0
  89. package/dist/config-dir-trust.js +388 -0
  90. package/dist/config-invariants.d.ts +18 -5
  91. package/dist/config-invariants.js +35 -3
  92. package/dist/config-provider.d.ts +6 -1
  93. package/dist/config-provider.js +6 -2
  94. package/dist/config-types.d.ts +71 -14
  95. package/dist/config-types.js +8 -0
  96. package/dist/config.d.ts +13 -0
  97. package/dist/config.js +121 -59
  98. package/dist/delegated-session-owner.d.ts +185 -0
  99. package/dist/delegated-session-owner.js +119 -0
  100. package/dist/device-protocol.d.ts +5 -3
  101. package/dist/device-protocol.js +1 -1
  102. package/dist/device-ws-hub.js +21 -2
  103. package/dist/device-ws-protocol.d.ts +70 -6
  104. package/dist/device-ws-protocol.js +50 -23
  105. package/dist/elicitation.js +3 -2
  106. package/dist/entry-problems.d.ts +34 -0
  107. package/dist/entry-problems.js +14 -0
  108. package/dist/execution-lane-caps.d.ts +49 -10
  109. package/dist/execution-lane-caps.js +43 -4
  110. package/dist/field-conflict.d.ts +43 -0
  111. package/dist/field-conflict.js +20 -0
  112. package/dist/fleet/fleet-bus.d.ts +80 -6
  113. package/dist/fleet/fleet-bus.js +41 -9
  114. package/dist/hooks/classic-stations.d.ts +10 -5
  115. package/dist/hooks/classic-stations.js +4 -4
  116. package/dist/hooks/command-spawn.d.ts +57 -0
  117. package/dist/hooks/command-spawn.js +139 -0
  118. package/dist/hooks/hook-llm.js +2 -2
  119. package/dist/hooks/hook-runner.d.ts +127 -25
  120. package/dist/hooks/hook-runner.js +668 -287
  121. package/dist/hooks/hook-source.d.ts +44 -0
  122. package/dist/hooks/hook-source.js +40 -0
  123. package/dist/http/active-run-conflict.d.ts +5 -13
  124. package/dist/http/active-run-conflict.js +17 -27
  125. package/dist/http/admission.js +103 -60
  126. package/dist/http/approval-sweeps.js +55 -18
  127. package/dist/http/caller-trust.d.ts +77 -0
  128. package/dist/http/caller-trust.js +143 -0
  129. package/dist/http/checkpoint-ctx.d.ts +16 -16
  130. package/dist/http/checkpoint-ctx.js +13 -10
  131. package/dist/http/claimed-run.d.ts +4 -3
  132. package/dist/http/device-placement.d.ts +2 -4
  133. package/dist/http/device-placement.js +2 -1
  134. package/dist/http/dispatch.js +10 -4
  135. package/dist/http/durable-run-leg.d.ts +4 -32
  136. package/dist/http/durable-run-leg.js +34 -10
  137. package/dist/http/owner-access.d.ts +56 -0
  138. package/dist/http/owner-access.js +42 -0
  139. package/dist/http/principal-gate.d.ts +48 -23
  140. package/dist/http/principal-gate.js +39 -12
  141. package/dist/http/readiness.d.ts +11 -5
  142. package/dist/http/readiness.js +10 -3
  143. package/dist/http/request-guards.d.ts +16 -23
  144. package/dist/http/request-guards.js +30 -15
  145. package/dist/http/resume-ctx-read.d.ts +2 -5
  146. package/dist/http/resume-ctx-read.js +7 -4
  147. package/dist/http/resume-legs.d.ts +3 -4
  148. package/dist/http/resume-legs.js +126 -69
  149. package/dist/http/retired-service-deps.d.ts +43 -0
  150. package/dist/http/retired-service-deps.js +18 -0
  151. package/dist/http/route-ctx.d.ts +44 -28
  152. package/dist/http/route-ctx.js +4 -0
  153. package/dist/http/route-table.js +2 -0
  154. package/dist/http/routes/a2a-serve.js +3 -4
  155. package/dist/http/routes/admin-config-refresh.js +1 -1
  156. package/dist/http/routes/admin-drain.js +1 -1
  157. package/dist/http/routes/admin-memory-optout.js +5 -1
  158. package/dist/http/routes/adoption.js +2 -9
  159. package/dist/http/routes/approvals-assistant.js +49 -48
  160. package/dist/http/routes/background.js +3 -2
  161. package/dist/http/routes/capabilities.js +20 -4
  162. package/dist/http/routes/config-catalog.d.ts +3 -3
  163. package/dist/http/routes/config-catalog.js +1 -1
  164. package/dist/http/routes/devices.js +3 -17
  165. package/dist/http/routes/diagnostics.js +5 -1
  166. package/dist/http/routes/images.js +6 -7
  167. package/dist/http/routes/leader.js +1 -8
  168. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  169. package/dist/http/routes/mcp-reconnect.js +3 -2
  170. package/dist/http/routes/memory-bundle.js +1 -1
  171. package/dist/http/routes/memory-compliance.js +1 -1
  172. package/dist/http/routes/memory-consolidation.js +1 -1
  173. package/dist/http/routes/memory-origin.js +1 -1
  174. package/dist/http/routes/memory-policy.d.ts +1 -1
  175. package/dist/http/routes/memory-policy.js +3 -2
  176. package/dist/http/routes/notify-wake.js +8 -21
  177. package/dist/http/routes/observability.js +2 -2
  178. package/dist/http/routes/principal-inbox.d.ts +39 -0
  179. package/dist/http/routes/principal-inbox.js +76 -0
  180. package/dist/http/routes/retention-ops.js +2 -9
  181. package/dist/http/routes/rules.js +5 -18
  182. package/dist/http/routes/runs.d.ts +5 -0
  183. package/dist/http/routes/runs.js +33 -106
  184. package/dist/http/routes/session-sync.js +15 -28
  185. package/dist/http/routes/sessions.js +30 -40
  186. package/dist/http/routes/side-query.js +6 -4
  187. package/dist/http/routes/tasks.js +50 -14
  188. package/dist/http/routes/workflows.d.ts +351 -0
  189. package/dist/http/routes/workflows.js +153 -119
  190. package/dist/http/send.d.ts +24 -3
  191. package/dist/http/send.js +14 -2
  192. package/dist/http/server.d.ts +17 -18
  193. package/dist/http/server.js +15 -13
  194. package/dist/http/stored-body-replay.js +17 -4
  195. package/dist/http/submit-ctx.js +4 -3
  196. package/dist/http/submit-replay.d.ts +4 -3
  197. package/dist/http/submit-replay.js +5 -4
  198. package/dist/http/wire-types.d.ts +10 -7
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/lane-home-probe.d.ts +78 -9
  202. package/dist/lane-home-probe.js +78 -12
  203. package/dist/leader/endpoint.d.ts +4 -1
  204. package/dist/leader/endpoint.js +11 -10
  205. package/dist/limit-refusal.d.ts +17 -5
  206. package/dist/limit-refusal.js +4 -1
  207. package/dist/mcp-assertion-header.d.ts +31 -10
  208. package/dist/mcp-assertion-header.js +10 -3
  209. package/dist/mcp-tool-faces.js +1 -3
  210. package/dist/memory-project-layer.d.ts +37 -0
  211. package/dist/memory-project-layer.js +46 -0
  212. package/dist/memory-scope.d.ts +23 -16
  213. package/dist/memory-scope.js +24 -8
  214. package/dist/memory-sync-client.d.ts +27 -13
  215. package/dist/memory-sync-client.js +107 -18
  216. package/dist/model-entry-refusal.d.ts +9 -1
  217. package/dist/model-entry-refusal.js +6 -1
  218. package/dist/model-plane-face.d.ts +51 -0
  219. package/dist/model-plane-face.js +24 -0
  220. package/dist/model-provider.d.ts +5 -0
  221. package/dist/model-provider.js +4 -2
  222. package/dist/model-route-endpoint.d.ts +8 -11
  223. package/dist/model-route-endpoint.js +4 -7
  224. package/dist/model-route-env.d.ts +22 -0
  225. package/dist/model-route-env.js +2 -0
  226. package/dist/model-route-gap.d.ts +60 -30
  227. package/dist/model-route-gap.js +21 -15
  228. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  229. package/dist/observability/corrupt-read-seat.js +9 -0
  230. package/dist/observability/err-text.d.ts +6 -0
  231. package/dist/observability/err-text.js +18 -4
  232. package/dist/observability/fail-open.d.ts +35 -9
  233. package/dist/observability/fail-open.js +35 -9
  234. package/dist/observability/metrics.js +1 -0
  235. package/dist/observability/prompt-manifest.d.ts +3 -17
  236. package/dist/observability/prompt-manifest.js +45 -42
  237. package/dist/observability/tool-trace.js +9 -9
  238. package/dist/operator-ask.d.ts +10 -0
  239. package/dist/operator-ask.js +3 -0
  240. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  241. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  242. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  243. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  244. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  245. package/dist/orchestration/workflow-notify-journal.js +27 -34
  246. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  247. package/dist/orchestration/workflow-park-decision.js +118 -0
  248. package/dist/org-delivery-gate.d.ts +81 -0
  249. package/dist/org-delivery-gate.js +59 -0
  250. package/dist/panel-tool-names.d.ts +23 -0
  251. package/dist/panel-tool-names.js +8 -0
  252. package/dist/parked-decide.d.ts +39 -6
  253. package/dist/parked-decide.js +98 -51
  254. package/dist/parked-revive-surface.d.ts +9 -2
  255. package/dist/parked-revive-surface.js +11 -8
  256. package/dist/permission-rule-list.d.ts +1 -1
  257. package/dist/permission-rule-list.js +2 -2
  258. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  259. package/dist/plugins/approval-ask-store-file.js +21 -0
  260. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  261. package/dist/plugins/approval-ask-store-memory.js +34 -2
  262. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  263. package/dist/plugins/approval-ask-store-sql.js +37 -1
  264. package/dist/plugins/blob-backend.d.ts +38 -25
  265. package/dist/plugins/blob-backend.js +29 -19
  266. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  267. package/dist/plugins/breaker-state-sql.js +4 -4
  268. package/dist/plugins/caching-session-store.d.ts +3 -0
  269. package/dist/plugins/caching-session-store.js +3 -0
  270. package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
  271. package/dist/plugins/checkpoint-store-sql.js +20 -2
  272. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  273. package/dist/plugins/file-history-store-sql.js +3 -1
  274. package/dist/plugins/file-run-store.d.ts +5 -13
  275. package/dist/plugins/file-run-store.js +9 -0
  276. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  277. package/dist/plugins/fork-routing-session-store.js +12 -1
  278. package/dist/plugins/host-platform.d.ts +2 -0
  279. package/dist/plugins/host-platform.js +2 -1
  280. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  281. package/dist/plugins/local-checkpoint-store.js +6 -1
  282. package/dist/plugins/local-session-store.d.ts +1 -1
  283. package/dist/plugins/local-session-window.d.ts +39 -0
  284. package/dist/plugins/local-session-window.js +54 -0
  285. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  286. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  287. package/dist/plugins/mailbox-store-sql.js +77 -52
  288. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  289. package/dist/plugins/memory-run-store.d.ts +5 -13
  290. package/dist/plugins/memory-run-store.js +8 -0
  291. package/dist/plugins/one-time-migrations.d.ts +110 -5
  292. package/dist/plugins/one-time-migrations.js +320 -8
  293. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  294. package/dist/plugins/org-delivery-quota-store.js +228 -0
  295. package/dist/plugins/pg-pool.js +39 -7
  296. package/dist/plugins/pg-session-storage.d.ts +17 -4
  297. package/dist/plugins/pg-session-storage.js +29 -6
  298. package/dist/plugins/remote-env-adb.d.ts +6 -12
  299. package/dist/plugins/remote-env-adb.js +12 -2
  300. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  301. package/dist/plugins/remote-env-k8s.js +23 -5
  302. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  303. package/dist/plugins/remote-env-local-docker.js +12 -9
  304. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  305. package/dist/plugins/remote-env-ssh.js +17 -11
  306. package/dist/plugins/run-store-sql.d.ts +16 -14
  307. package/dist/plugins/run-store-sql.js +22 -2
  308. package/dist/plugins/schema-indexes.js +2 -0
  309. package/dist/plugins/send-user-file.js +2 -2
  310. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  311. package/dist/plugins/session-epoch-anchor.js +2 -3
  312. package/dist/plugins/session-store.d.ts +18 -8
  313. package/dist/plugins/session-store.js +15 -4
  314. package/dist/plugins/sql-driver.d.ts +74 -11
  315. package/dist/plugins/sql-driver.js +210 -12
  316. package/dist/plugins/sql-errors.d.ts +23 -0
  317. package/dist/plugins/sql-errors.js +21 -0
  318. package/dist/plugins/store-backend.d.ts +36 -1
  319. package/dist/plugins/store-backend.js +40 -14
  320. package/dist/plugins/store-contracts.d.ts +42 -0
  321. package/dist/plugins/store-contracts.js +1 -0
  322. package/dist/plugins/tidb-pool.d.ts +6 -1
  323. package/dist/plugins/tidb-pool.js +44 -10
  324. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  325. package/dist/plugins/tidb-session-storage.js +2 -2
  326. package/dist/plugins/tidb-session-store.d.ts +24 -4
  327. package/dist/plugins/tidb-session-store.js +28 -4
  328. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  329. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  330. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  331. package/dist/plugins/workflow-run-store-sql.js +50 -9
  332. package/dist/posture-source.d.ts +18 -10
  333. package/dist/posture-source.js +4 -1
  334. package/dist/project-identity.d.ts +45 -6
  335. package/dist/project-identity.js +162 -8
  336. package/dist/project-layer-key.d.ts +28 -0
  337. package/dist/project-layer-key.js +29 -0
  338. package/dist/question.js +3 -2
  339. package/dist/read-deny-entry.d.ts +25 -0
  340. package/dist/read-deny-entry.js +12 -0
  341. package/dist/read-face-posture.d.ts +37 -11
  342. package/dist/read-face-posture.js +32 -3
  343. package/dist/request-key-closure.d.ts +7 -0
  344. package/dist/request-key-closure.js +9 -1
  345. package/dist/request-value-closure.d.ts +5 -0
  346. package/dist/request-value-closure.js +11 -3
  347. package/dist/rule-entry-list.d.ts +26 -2
  348. package/dist/rule-entry-list.js +72 -12
  349. package/dist/rules-consent.js +3 -4
  350. package/dist/run-acceptance.d.ts +19 -3
  351. package/dist/run-acceptance.js +13 -1
  352. package/dist/run-local.js +36 -6
  353. package/dist/runs.d.ts +10 -9
  354. package/dist/runs.js +21 -3
  355. package/dist/runtime-caps-resolver.d.ts +16 -6
  356. package/dist/runtime-caps-resolver.js +18 -5
  357. package/dist/sandbox-pkg-source.d.ts +19 -1
  358. package/dist/sandbox-pkg-source.js +29 -7
  359. package/dist/security.d.ts +87 -9
  360. package/dist/security.js +52 -9
  361. package/dist/session-error-wire.d.ts +19 -2
  362. package/dist/session-error-wire.js +5 -1
  363. package/dist/session-titled-frame.d.ts +33 -0
  364. package/dist/session-titled-frame.js +4 -0
  365. package/dist/session-titler.d.ts +9 -1
  366. package/dist/session-titler.js +15 -4
  367. package/dist/spec-fields.js +21 -2
  368. package/dist/sql-engine-posture.d.ts +3 -1
  369. package/dist/task-cwd.d.ts +1 -1
  370. package/dist/task-mcp.d.ts +3 -3
  371. package/dist/task-mcp.js +7 -66
  372. package/dist/task-settings.d.ts +89 -88
  373. package/dist/task-settings.js +71 -63
  374. package/dist/text-bidi.d.ts +0 -4
  375. package/dist/text-bidi.js +1 -3
  376. package/dist/tighten-only-seats.d.ts +150 -0
  377. package/dist/tighten-only-seats.js +196 -0
  378. package/dist/tool-approval.d.ts +303 -87
  379. package/dist/tool-approval.js +623 -239
  380. package/dist/trace/core-keyset-guard.d.ts +104 -22
  381. package/dist/trace/exit-seat.d.ts +28 -0
  382. package/dist/trace/exit-seat.js +76 -0
  383. package/dist/trace/ledger-events.d.ts +3 -2
  384. package/dist/trace/project.d.ts +80 -12
  385. package/dist/trace/project.js +41 -28
  386. package/dist/trace/projection-table.d.ts +100 -0
  387. package/dist/trace/projection-table.js +130 -0
  388. package/dist/trace/redact.d.ts +54 -0
  389. package/dist/trace/redact.js +778 -152
  390. package/dist/trace/self-minted-wire.d.ts +345 -1
  391. package/dist/trace/self-minted-wire.js +117 -1
  392. package/dist/trace/wire-projection-faces.d.ts +298 -2
  393. package/dist/trace/wire-projection-faces.js +154 -13
  394. package/dist/url-refusal.js +2 -0
  395. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  396. package/dist/web-admin-client/apply-effective.js +56 -5
  397. package/dist/web-admin-client/facade.d.ts +1 -1
  398. package/dist/web-admin-client/facade.js +1 -1
  399. package/dist/web-admin-client/read-face.js +5 -9
  400. package/dist/web-admin-client/skills-mcp.js +4 -5
  401. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  402. package/package.json +7 -3
@@ -0,0 +1,139 @@
1
+ import { mkdir, stat } from "node:fs/promises";
2
+ import { isAbsoluteHostPath } from "@sema-agent/settings-schema";
3
+ const PLUGIN_MEMBERS = new Set(["name", "root", "dataDir", "options"]);
4
+ const OPTION_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
5
+ function isRecord(v) {
6
+ if (v === null || typeof v !== "object" || Array.isArray(v))
7
+ return false;
8
+ const proto = Object.getPrototypeOf(v);
9
+ return proto === Object.prototype || proto === null;
10
+ }
11
+ export function readHookArgs(raw) {
12
+ if (!Array.isArray(raw))
13
+ return undefined;
14
+ const out = [];
15
+ for (const a of raw) {
16
+ if (typeof a !== "string" || a.includes("\0"))
17
+ return undefined;
18
+ out.push(a);
19
+ }
20
+ return out;
21
+ }
22
+ export function readHookPlugin(raw) {
23
+ if (!isRecord(raw))
24
+ return undefined;
25
+ for (const k of Object.keys(raw))
26
+ if (!PLUGIN_MEMBERS.has(k))
27
+ return undefined;
28
+ const { name, root, dataDir, options } = raw;
29
+ if (typeof name !== "string" || name.length === 0 || name.includes("\0"))
30
+ return undefined;
31
+ if (!isAbsoluteHostPath(root))
32
+ return undefined;
33
+ if (dataDir !== undefined && !isAbsoluteHostPath(dataDir))
34
+ return undefined;
35
+ let opts;
36
+ if (options !== undefined) {
37
+ if (!isRecord(options))
38
+ return undefined;
39
+ const entries = Object.entries(options);
40
+ for (const [k, v] of entries)
41
+ if (!OPTION_KEY.test(k) || typeof v !== "string" || v.includes("\0"))
42
+ return undefined;
43
+ opts = Object.fromEntries(entries);
44
+ }
45
+ return { name, root: root, ...(dataDir !== undefined ? { dataDir: dataDir } : {}), ...(opts !== undefined ? { options: opts } : {}) };
46
+ }
47
+ export function hookPluginChars(p) {
48
+ return p.name.length + p.root.length + (p.dataDir?.length ?? 0) + Object.entries(p.options ?? {}).reduce((n, [k, v]) => n + k.length + v.length, 0);
49
+ }
50
+ export function commandLineChars(entry) {
51
+ return entry.command.length + (entry.args ?? []).reduce((n, a) => n + 1 + a.length, 0);
52
+ }
53
+ export function hookPluginEnv(p) {
54
+ if (p === undefined)
55
+ return {};
56
+ const env = { CLAUDE_PLUGIN_ROOT: p.root };
57
+ if (p.dataDir !== undefined)
58
+ env.CLAUDE_PLUGIN_DATA = p.dataDir;
59
+ for (const [k, v] of Object.entries(p.options ?? {}))
60
+ env[`CLAUDE_PLUGIN_OPTION_${k.toUpperCase()}`] = v;
61
+ return env;
62
+ }
63
+ const CONTEXT_VARS = [
64
+ ["CLAUDE_PLUGIN_ROOT", "${CLAUDE_PLUGIN_ROOT}"],
65
+ ["CLAUDE_PLUGIN_DATA", "${CLAUDE_PLUGIN_DATA}"],
66
+ ];
67
+ const ROOT_REF = CONTEXT_VARS[0][1];
68
+ const SUBSTITUTION_NAMES = ["CLAUDE_PROJECT_DIR", "CLAUDE_PLUGIN_ROOT", "CLAUDE_PLUGIN_DATA"];
69
+ const refOf = (name) => "${" + name + "}";
70
+ export function composeHookEnvLayer(requestEnv, cwd, plugin) {
71
+ return { ...requestEnv, CLAUDE_PROJECT_DIR: requestEnv?.CLAUDE_PROJECT_DIR ?? cwd, ...hookPluginEnv(plugin) };
72
+ }
73
+ function contextVarValue(name, layer) {
74
+ const v = layer[name];
75
+ return v !== undefined && v.length > 0 ? v : undefined;
76
+ }
77
+ export async function planCommandSpawn(entry, cwd, requestEnv) {
78
+ const texts = [entry.command, ...(entry.args ?? [])];
79
+ const p = entry.plugin;
80
+ const env = composeHookEnvLayer(requestEnv, cwd, p);
81
+ const values = new Map([["CLAUDE_PROJECT_DIR", env.CLAUDE_PROJECT_DIR]]);
82
+ for (const [name, ref] of CONTEXT_VARS) {
83
+ const value = contextVarValue(name, env);
84
+ if (value !== undefined) {
85
+ values.set(name, value);
86
+ continue;
87
+ }
88
+ if (!texts.some((t) => t.includes(ref)))
89
+ continue;
90
+ return {
91
+ kind: "refused",
92
+ error: p !== undefined
93
+ ? `hook command references ${ref} but only ${ROOT_REF} is available for this hook (it carries no plugin data directory and the request settings.env does not set ${name})`
94
+ : `hook command references ${ref} but the hook is not associated with a plugin and the request settings.env does not set ${name} (the variable is only available to hooks that carry a plugin context, or to a request that sets it in settings.env)`,
95
+ };
96
+ }
97
+ if (p !== undefined) {
98
+ const isDir = await stat(p.root).then((s) => s.isDirectory(), () => false);
99
+ if (!isDir)
100
+ return { kind: "refused", error: `plugin directory does not exist: ${p.root} (${p.name} — reinstall the plugin)` };
101
+ if (p.dataDir !== undefined) {
102
+ try {
103
+ await mkdir(p.dataDir, { recursive: true });
104
+ }
105
+ catch (e) {
106
+ return { kind: "refused", error: `plugin data directory could not be created: ${p.dataDir} (${e instanceof Error ? e.message : String(e)})` };
107
+ }
108
+ }
109
+ }
110
+ if (entry.args === undefined)
111
+ return { kind: "shell", command: entry.command, env };
112
+ const substitute = (s) => {
113
+ if (!s.includes("${"))
114
+ return s;
115
+ let out = "";
116
+ let i = 0;
117
+ while (i < s.length) {
118
+ const at = s.indexOf("${", i);
119
+ if (at === -1) {
120
+ out += s.slice(i);
121
+ break;
122
+ }
123
+ out += s.slice(i, at);
124
+ const hit = SUBSTITUTION_NAMES.find((name) => s.startsWith(refOf(name), at));
125
+ const v = hit === undefined ? undefined : values.get(hit);
126
+ if (hit !== undefined && v !== undefined) {
127
+ out += v;
128
+ i = at + refOf(hit).length;
129
+ }
130
+ else {
131
+ out += "${";
132
+ i = at + 2;
133
+ }
134
+ }
135
+ return out;
136
+ };
137
+ return { kind: "exec", file: substitute(entry.command), args: entry.args.map(substitute), env };
138
+ }
139
+ //# sourceMappingURL=command-spawn.js.map
@@ -1,6 +1,6 @@
1
1
  import { admitRouteRequest, BrainError, joinRequestUrl, resolveRouteCredential, routeKeyOf } from "@sema-agent/core";
2
2
  import { matchCatalogModel, refusedCatalogEntry, servedModelTableLeg } from "../model-select.js";
3
- import { modelUnavailableMessage } from "../model-entry-refusal.js";
3
+ import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
4
4
  import { resolveOpenaiRouteEndpoint } from "../model-route-endpoint.js";
5
5
  import { anthropicRouteRoot, brainLaneFor, routeTableOf } from "../model-provider.js";
6
6
  import { egressRedirectRefusal } from "../egress-redirect.js";
@@ -72,7 +72,7 @@ export function createHookLlm(deps) {
72
72
  return unavailable("hook model", requested);
73
73
  if (requested === config.model.id)
74
74
  return shapeFrom(config.model);
75
- return unavailable("hook model", requested) ?? unresolvedPick(`hook model "${requested}" is not in this deployment's catalog`);
75
+ return unavailable("hook model", requested) ?? unresolvedPick(`hook model "${echoModelRef(requested)}" is not in this deployment's catalog`);
76
76
  };
77
77
  const judgeRoute = (pick, perModelKey, deploymentKey, declaredRoot) => {
78
78
  const credential = resolveRouteCredential({
@@ -3,8 +3,10 @@ import { type ConfigPath } from "@sema-agent/settings-schema";
3
3
  import { ENGINE_OWNED_HOOK_EVENTS } from "@sema-agent/settings-schema/hooks";
4
4
  import type { EngineDollar, ModRegistration } from "@sema-agent/core";
5
5
  import type { Logger } from "../observability/logger.js";
6
- import type { HookNoticeObservation } from "../fleet/fleet-bus.js";
7
- import { type LimitReason } from "../limit-refusal.js";
6
+ import type { HookManagedUnrun, HookNoticeObservation } from "../fleet/fleet-bus.js";
7
+ import { LIMIT_REASONS, type LimitMeasure } from "../limit-refusal.js";
8
+ import { type HookGroupSource } from "./hook-source.js";
9
+ import { type RunnableCommandHookEntry } from "./command-spawn.js";
8
10
  /** 服务侧防线上限(契约本身不设量纲;不设界=单请求可塞任意大配置/任意长命令)。超界=校验错(fail-loud)。 */
9
11
  export declare const MAX_HOOK_ENTRIES_PER_EVENT = 32;
10
12
  export declare const MAX_HOOK_COMMAND_CHARS = 8192;
@@ -56,14 +58,29 @@ export declare const SETTINGS_HOOK_STATIONS: {
56
58
  /** 这张注册的名字 —— wire 可见(`wiring_manifest.mods[].name`、`allowRuleShadowed[].entries`),也是 handler 失败时引擎拒句点名的扩展名。 */
57
59
  export declare const SETTINGS_HOOKS_REGISTRATION = "settings.hooks";
58
60
  /**
59
- * 律四 · `HOOKS_TIMEOUT_MS` 未设时本注册每个 handler 的预算(ms)= 本服务跑钩子子进程的界:单条命令超时的上限
60
- * {@link MAX_HOOK_TIMEOUT_SECONDS}。不是抄引擎缺省(引擎缺省是 10 s,一条跑 11 s 的 PreToolUse 钩子会因此被 fail-closed 拒)。
61
+ * 律四 · `HOOKS_TIMEOUT_MS` 未设时本注册每个 handler 的预算(ms)。
62
+ *
63
+ * **这只数是引擎的钟,不是本服务跑钩子子进程的墙钟。** 引擎对 `budgetMs` 的定义(core `ModRegistration.budgetMs` 的注释,逐字)是
64
+ * "Each handler's own time" —— 每个 handler 自己的时间:一只在 handler 等 `next` / `$` 调用时暂停的钟(core 的 `SelfBudget`),
65
+ * 到点 ⇒ 这个 handler 失败(PreToolUse / UserPromptSubmit 上 fail-closed 拒,其余站跳过)。命令钩子子进程自己的墙钟另有两只,都在本文件:
66
+ * 单条命令的 `timeout`(上限 {@link MAX_HOOK_TIMEOUT_SECONDS})与一个事件里同步条目的总墙钟({@link MAX_HOOK_EVENT_TOTAL_SECONDS},到点不再起下一条)。
67
+ *
68
+ * 缺省取单条命令超时的上限 {@link MAX_HOOK_TIMEOUT_SECONDS} × 1000(两只钟起点不同:引擎的钟在 handler 起跑时就开始走,命令的 `timeout` 钟要等 shell 解析和 spawn 之后,
69
+ * 同一 handler 里串行的几条还共用这一只钟 —— 配到 600 s 的命令跑满时预算会先到)。不是抄引擎缺省(10 s):一条跑 11 s 的 PreToolUse 钩子会因此被 fail-closed 拒。
70
+ *
71
+ * 两只钟的交汇:预算到,与任务被取消一样,引擎对这个 handler 的信号({@link ClassicAnswer} 的 `signal`)触发 ——
72
+ * 在跑的命令钩子的进程组被叫停(SIGTERM → {@link HOOK_KILL_GRACE_MS} → 组长还在则组 SIGKILL),这个 handler 里还没起的条目不再起。
61
73
  */
62
74
  export declare const DEFAULT_SETTINGS_HOOKS_BUDGET_MS: number;
63
75
  /** 时限的唯一读法:`HOOKS_TIMEOUT_MS` 设了就是它(`0` 按字面 = 零预算);未设 ⇒ {@link DEFAULT_SETTINGS_HOOKS_BUDGET_MS}。 */
64
76
  export declare function settingsHooksBudgetMs(config: {
65
77
  readonly hooksTimeoutMs?: number | undefined;
66
78
  }): number;
79
+ /**
80
+ * 命令钩子的进程组被叫停(预算到 / 任务取消)时,SIGTERM 之后给它收尾的宽限(ms):到点组长还在就补一发组 SIGKILL(组长在宽限内退了则不再发)。
81
+ * 零旋钮 —— 命令要的收尾窗长于此值的,在命令里自己兜(trap 里快速落盘)。
82
+ */
83
+ export declare const HOOK_KILL_GRACE_MS = 1000;
67
84
  /**
68
85
  * 本仓对契约每一种 hook 条目类型的表态 —— **一张表**:受理面({@link parseHooksConfig})与执行侧({@link RunnableHookEntry},以及每个按条目类型分派的臂)读的都是它。
69
86
  *
@@ -84,13 +101,16 @@ export type SupportedHookEntryType = {
84
101
  }[HookEntryType];
85
102
  /** 本仓会真跑的条目类型闭集(契约 {@link HOOK_ENTRY_TYPES} 的次序)—— 拒句 `supported: …` 的词表与 {@link RunnableHookEntry} 的类型都出自这一张表。 */
86
103
  export declare const SUPPORTED_HOOK_ENTRY_TYPES: readonly SupportedHookEntryType[];
87
- /** 本 runner 会真跑的条目(契约 `HookEntry` 取表态为 `true` 的那几型)。 */
88
- export type RunnableHookEntry = Extract<HookEntry, {
89
- type: SupportedHookEntryType;
90
- }>;
91
- /** 一个匹配器组,条目只含 {@link RunnableHookEntry}。 */
104
+ /** 本 runner 会真跑的条目(契约 `HookEntry` 取表态为 `true` 的那几型;command 条目另带本仓读的两只 wire 键 `args` / `plugin`,见 `command-spawn.ts`)。 */
105
+ export type RunnableHookEntry = {
106
+ [T in SupportedHookEntryType]: T extends "command" ? RunnableCommandHookEntry : Extract<HookEntry, {
107
+ type: T;
108
+ }>;
109
+ }[SupportedHookEntryType];
110
+ /** 一个匹配器组,条目只含 {@link RunnableHookEntry}。`source` = 这一组是谁写的(wire 键,闭集见 `hook-source.ts`;缺席 = 非托管),决定它在哪一相跑。 */
92
111
  export interface RunnableMatcherGroup {
93
112
  matcher?: string;
113
+ source?: HookGroupSource;
94
114
  hooks: RunnableHookEntry[];
95
115
  }
96
116
  /** 受理面通过后的 hooks 配置:每个事件下的条目都是本仓会跑的型 —— 执行侧({@link createSettingsHooksRegistration})只收这一型,「不认识的类型」到不了它手里。 */
@@ -123,7 +143,7 @@ export type ParseHooksConfigResult = {
123
143
  *
124
144
  * 规则(一条;字面形是它的特例):{@link hooksMatcherIssue} 对 core 静态目录里**每一条退役别名**问「这只 matcher 选不选它 / 选不选它的正名」:
125
145
  * matcher **命中别名 ∧ 不命中它的正名** ⇒ `400 request.field_invalid`(`admission.ts` fresh 门)。「选不选」**只有一只读法**:契约包的 `hookMatcherSelects`
126
- * (名字表 / 空 / `*` / 正则三形都由它答;正则形**不锚定**,与壳同形;运行期 {@link hookMatcherMatches} 问的也是它,本仓不留副本)。按**一条顺序**判(两档共用,7.114.0 修复轮):
146
+ * (名字表 / 空 / `*` / 正则三形都由它答;正则形**不锚定**,与壳同形;运行期 {@link hookMatcherMatches} 问的也是它 —— 经同一只带预算的求值口,本仓不留副本)。按**一条顺序**判(两档共用,7.114.0 修复轮):
127
147
  * ① **长度上限**:超 {@link MAX_MATCHER_EVAL_CHARS} 的 matcher 两档都不读 ⇒ 未判(reason = oversize);
128
148
  * ② **形只问契约包的 `hookMatcherForm`**(与 `hookMatcherSelects` 同一只解析步,本仓不留形判),闭集三词、两档一张表:
129
149
  * · `literal`(缺席 / 空 / `*` / 名字表形;契约不编、不跑调用方的正则)⇒ 两档都**直接问契约函数**、**不占求值预算**;
@@ -161,8 +181,8 @@ export type ParseHooksConfigResult = {
161
181
  * `detail.reason = budget_exceeded`({@link BudgetExceededMatcherIssue},点名越线的那一组与总额度)。单次超时先到、先判 `over_budget`(更具体)。一次受理的最坏占用 ≤ 总额度 + 一次求值的额度。
162
182
  * 总额度这一只读钟,但良性设置离它近三个数量级(一份最大的良性配置 —— 3 工具事件 × 16 组 —— 总耗时在毫秒级),所以良性设置的结局仍不随机器忙闲翻转;只有求值总耗时逼近总额度的病态设置才可能落在边界两侧。
163
183
  * **超时 ⇒ 确定拒绝**:`400 request.field_invalid`({@link OverBudgetMatcherIssue}),句子点名**哪一只 matcher**(事件 + 组下标,不回显原字节)与**预算**;**按配置顺序遇到的第一只超时 / 命中别名的 matcher 定结局**。
164
- * 为什么是拒绝而不是放行:运行期 {@link hookMatcherMatches} 在**每次工具调用**里直接问同一只契约函数、**没有任何预算** —— 一只在受理面都跑不完的 matcher 放进去,
165
- * 每次调用都会把事件循环卡住;放行 = 把一个确定的坏配置推迟成运行期的随机卡死。这条拒不是「越界即拒」的新检测面:被拒的恰是**无法被求值**的 matcher,与 `hook_matcher_invalid`(编不过 ⇒ 该组不跑)同属「这只 matcher 不可用」,
184
+ * 为什么是拒绝而不是放行:运行期 {@link hookMatcherMatches} 在**每次工具调用**里问同一只带预算的口(S-1017 起;此前是裸调、无预算)—— 一只在受理面连目录里几个短名字都求不完的 matcher 放进去,
185
+ * 运行期每次调用都要白烧一整份预算(超预算的组按选中处理并登记,守卫不丢,但每次调用卡一份预算);放行 = 把一个确定的坏配置推迟成运行期每次调用的卡顿。这条拒不是「越界即拒」的新检测面:被拒的恰是**无法被求值**的 matcher,与 `hook_matcher_invalid`(编不过 ⇒ 该组不跑)同属「这只 matcher 不可用」,
166
186
  * 只是编不过的运行期自己安全地不跑它,跑不完的不行。
167
187
  * 总用时的上界:首个超时 / 总额度越线即拒、不再往下求值;未超时的求值各自 < 预算,其和 ≤ 总额度 + 一次求值的额度。regex 档只在单用户车道(`taskHooksHonored`,hooks 会装配的那条;调用方就是进程属主,本来就能配任意 `command` 钩子)运行,
168
188
  * 多租户车道走 literal 档、零调用方正则执行 —— 受理面的 DoS 面不因此重开。
@@ -193,8 +213,9 @@ export type ParseHooksConfigResult = {
193
213
  /** 超此长度的 matcher 不在受理面读(两档同一个上限;未判,reason = oversize)。与 {@link MAX_HOOK_COMMAND_CHARS} 同量纲的服务侧防线:真实 matcher(精确名 / 交替 / `mcp__.*`)远在其内;目录全部工具名交替 ~0.5 KiB。 */
194
214
  export declare const MAX_MATCHER_EVAL_CHARS = 8192;
195
215
  /**
196
- * regex 档的**求值预算表**(毫秒)—— 两个数同出这一张表,判据与测试注入都不另持第二份:
216
+ * 正则形 matcher 的**求值预算表**(毫秒)—— 两个数同出这一张表,判据与测试注入都不另持第二份(名字里的 `ADMISSION` 是历史:`budgetMs` 自 S-1017 起**受理面与运行期共用**,`totalMs` 只属受理面):
197
217
  * · `budgetMs` = **每一次**正则形求值各一份的固定墙钟额度(S-1455;vm `timeout`)。**不共享、额度不随受理里别的 matcher 缩水、这一份不读钟**;字面形不占它。
218
+ * **运行期读同一个数**(S-1017;{@link hookMatcherMatches} 每次现读本对象):运行期每次工具调用对正则形 matcher 的每次求值也各拿这一份,超了 ⇒ 该组按选中处理并登记,不另设运行期额度。
198
219
  * 良性求值 ~0.1 ms;灾难回溯(指数级)吃满它也跑不完 ⇒ 这只 matcher 被 400 拒(`over_budget`)。取值是「良性求值之上数个数量级」的余量 —— 小了,忙机上的调度停顿会把良性 matcher 读成灾难(受理结局随负载翻转,正是 S-1455 要根除的形)。
199
220
  * · `totalMs` = **一次受理**里所有已完成的正则形求值的**耗时之和**的总额度(S-1503):之和一旦超过它 ⇒ `400`,`detail.reason = budget_exceeded`。每次求值的额度只界住「一只 matcher 不会无限算」,
200
221
  * 界不住「刚好低于它的病态 matcher × 别名数 × 2 × 组数」—— 今天 3 事件 × 16 组 × 1 别名 × 2 = 96 次,每次 0.99 s 可占住事件循环 96 s(单用户车道上持 token 的调用方)。
@@ -207,6 +228,8 @@ export declare const ADMISSION_MATCHER_BUDGET: {
207
228
  };
208
229
  /** 拒句里回显的 matcher 原文 / 引擎编译错误句、运行期 `hook_matcher_invalid` 日志行的 `matcher` 字段,各自的字符上限(都过回显的一只口径 `echoCallerText`,截断记号 `…`;S-1455 收尾 / S-1735)。真实 matcher 远在其内;上限只防一只 8 KiB 的坏 matcher 把拒句撑成一屏。 */
209
230
  export declare const MATCHER_ECHO_CHARS = 200;
231
+ /** 运行期 `hook_entries_skipped` 日志行的 `if` 字段(配置写的权限规则表达式)的字符上限;与 matcher 同口径(`echoCallerText`),截断记号 `…`。 */
232
+ export declare const IF_ECHO_CHARS = 200;
210
233
  /** 受理面判据的求值深度(见上头注):`"regex"` = 契约字面形直接问、正则形带预算问同一只契约函数;`"literal"` = 7.112.0 的字面判(只判契约字面形,零调用方正则执行;正则形 / 编不过的形不适用)。 */
211
234
  export type MatcherEvalDepth = "regex" | "literal";
212
235
  /**
@@ -219,6 +242,11 @@ export interface MatcherEvalBudget {
219
242
  readonly totalMs?: number;
220
243
  readonly now?: () => number;
221
244
  }
245
+ /**
246
+ * 一次 matcher 求值的答案(闭集四词;**受理面与运行期同一张**):`true` 选中 · `false` 不选 · `"invalid"` 契约答编不过 · `"over_budget"` 这一次求值没在预算内结束(灾难回溯)。
247
+ * 处置它的 switch 都是穷举的(加一词 = 这里加、每个处置点编译红)。
248
+ */
249
+ export type MatcherAnswer = boolean | "invalid" | "over_budget";
222
250
  /** 一条受理面判决(纯数据)· 死别名:`event` 事件下第 `groupIndex` 组(从 0 起)的 matcher 选中了退役别名 `alias`、却选不中它的正名 `canonical`。`alias` / `canonical` 恒取自 core 静态目录(闭集字符串,不含调用方原字节)。 */
223
251
  export interface DeadToolMatcherIssue {
224
252
  readonly reason: "dead_alias";
@@ -272,14 +300,17 @@ export interface UnsupportedEntryTypeIssue {
272
300
  readonly path: ConfigPath;
273
301
  readonly type: HookEntryType;
274
302
  }
303
+ /** hooks 的服务侧上限只有条数与字符数两种量纲(没有字节帽):`reason` 的词随量纲从 {@link LIMIT_REASONS} 取,本面的读者穷举读这两个词。 */
304
+ type HooksCapMeasure = Extract<LimitMeasure, "entries" | "characters">;
305
+ type HooksCapReason = (typeof LIMIT_REASONS)[HooksCapMeasure];
275
306
  /** 服务侧上限的哪一条(只供铸句;机读位只出 `reason` / `path` / `count` / `cap`)。帽的量纲与数在 {@link HOOKS_CAPS} 一张表。 */
276
- type HooksCap = "matcher_groups" | "event_entries" | "command" | "url" | "headers" | "header_chars" | "allowed_env_vars";
307
+ type HooksCap = "matcher_groups" | "event_entries" | "command" | "url" | "headers" | "header_chars" | "allowed_env_vars" | "plugin";
277
308
  /**
278
309
  * 服务侧上限撞帽:`path` = 撞帽处的坐标(组数 ⇒ 那个事件;一个事件的条目总数 ⇒ 第一条超出的条目;命令 / URL ⇒ 那个字段;header 条数 / 总字符数 ⇒ `headers`;
279
310
  * `allowedEnvVars` ⇒ 那个字段),`count` = 送来的量,`cap` = 帽,`reason` 由量纲定。
280
311
  */
281
312
  export interface HooksCapIssue {
282
- readonly reason: LimitReason;
313
+ readonly reason: HooksCapReason;
283
314
  readonly limit: HooksCap;
284
315
  readonly event: HookEventName;
285
316
  readonly path: ConfigPath;
@@ -291,8 +322,19 @@ export interface UnnamedHooksRefusalIssue {
291
322
  readonly reason: "unnamed_refusal";
292
323
  readonly path: ConfigPath;
293
324
  }
325
+ /** 本仓读的 wire 键(契约分类器不认、会剥掉的那三只)。 */
326
+ export type HooksWireKey = "source" | "plugin" | "args";
327
+ /**
328
+ * 本仓的 wire 键形错(`path` 指那只键:组的 `source` / command 条目的 `plugin` / `args`)。这三只键分类器不认(它对未知键一律剥除),
329
+ * 由 {@link parseHooksConfig} 在分类器装上的同一坐标上读 —— 形错 = 拒,**不**再被静默剥掉(剥掉 `source` = 托管组落进非托管道;剥掉 `args` = exec 形只剩可执行名)。
330
+ */
331
+ export interface HooksWireKeyIssue {
332
+ readonly reason: "wire_key_invalid";
333
+ readonly path: ConfigPath;
334
+ readonly key: HooksWireKey;
335
+ }
294
336
  /** 受理面 hooks 配置读者的拒判决。 */
295
- export type HooksConfigIssue = HooksPieceIssue | UnsupportedEntryTypeIssue | HooksCapIssue | UnnamedHooksRefusalIssue;
337
+ export type HooksConfigIssue = HooksPieceIssue | UnsupportedEntryTypeIssue | HooksCapIssue | UnnamedHooksRefusalIssue | HooksWireKeyIssue;
296
338
  /** `settings.hooks` 这一面的全部拒判决:配置读者的({@link HooksConfigIssue})与 fresh 提交面 matcher 判据的({@link HooksMatcherIssue})。 */
297
339
  export type HooksIssue = HooksConfigIssue | HooksMatcherIssue;
298
340
  /**
@@ -331,13 +373,17 @@ export type HooksRefusalDetail = {
331
373
  readonly path: ConfigPath;
332
374
  readonly type: HookEntryType;
333
375
  } | {
334
- readonly reason: LimitReason;
376
+ readonly reason: HooksCapReason;
335
377
  readonly path: ConfigPath;
336
378
  readonly count: number;
337
379
  readonly cap: number;
338
380
  } | {
339
381
  readonly reason: "unnamed_refusal";
340
382
  readonly path: ConfigPath;
383
+ } | {
384
+ readonly reason: "wire_key_invalid";
385
+ readonly path: ConfigPath;
386
+ readonly key: HooksWireKey;
341
387
  };
342
388
  /** {@link buildHooksRefusal} 的返回(纯数据):拒句 + 400 体上的两个机读位。`field` 恒为字面 `"settings.hooks"`。 */
343
389
  export interface HooksRefusal {
@@ -373,25 +419,36 @@ export declare function hooksCoordinate(path: ConfigPath): string;
373
419
  * 一块被剔(`loaded-partial`)或整份被拒(`rejected`)都是拒 —— wire 面「剔掉坏块、其余照装」会让写的人以为生效的钩子无声消失(分类器的宽松粒度是读设置文件的宿主用的)。
374
420
  * 拒的判决 = 分类器给的**码 + 坐标 + 坏字段**({@link HooksPieceIssue};分类器不写句子,句子与 400 体的机读位由 {@link buildHooksRefusal} 铸)。
375
421
  * · **本仓不执行的条目类型整份拒**:分类器受理契约的全部五型,而本仓只跑 {@link SUPPORTED_HOOK_ENTRY_TYPES}。含其余类型的配置整份拒,不留跳过臂。
376
- * · **服务侧上限**(广度闸;契约本身不设量纲)。
422
+ * · **本仓的 wire 键**(分类器不认、会剥掉的三只):组上的 `source`(来源闭集,`hook-source.ts`)、command 条目上的 `plugin` / `args`(执行上下文,`command-spawn.ts`)——
423
+ * 在分类器装上的**同一坐标**上读原值(分类器只在 `loaded` 时放行,装上的件与原值逐位对齐),形错 ⇒ {@link HooksWireKeyIssue}。
424
+ * `plugin` / `args` 只在 command 条目上有义:别的条目上它们与任何未知键一样被分类器剥掉(CC 同形)。值为 `undefined` 与缺席同读(与分类器读可选字段同一口径)。
425
+ * · **服务侧上限**(广度闸;契约本身不设量纲)。exec 形的命令行(`command` + 各 `args`)计入 `command` 帽;插件上下文一道总字符帽。
377
426
  *
378
427
  * 拒返回判决(`issue`)与它的句子(`error`)而不 throw —— submit 路径 400 fail-loud(体带 `field: "settings.hooks"` + `detail`)、resume 防御路径 warn-drop(hooks 整只不采纳),由调用方选;
379
428
  * **读者、判决与句子两腿同一只**,后果按腿分。
380
429
  */
381
430
  export declare function parseHooksConfig(raw: unknown): ParseHooksConfigResult;
382
431
  /**
383
- * 运行期的 matcher 读法席位:**问契约包的 `hookMatcherSelects`,别无其它**(壳与服务端都问这一只,谁都不留副本;读法全文见它的头注,这里不重述)。
432
+ * 运行期的 matcher 读法席位:**问契约包的 `hookMatcherSelects`,经受理面同一只带预算的求值口({@link matcherSelectsBy})**(壳与服务端都问这一只契约函数,谁都不留副本;读法全文见它的头注,这里不重述)。
384
433
  * 三形(名字表 / 空 `*` 缺省 / 不锚定的 JS 正则)与「编不过 ⇒ `"invalid"`」都由它答;**对所有带 matcher 的事件同一只读法**(工具事件 / StopFailure 的 `error` 词 /
385
- * PreCompact·PostCompact 的 `trigger` 词 / `if` 条件的名部),不按事件分档。`"invalid"` ⇒ 该组不跑(fail-closed 到「不跑」),由调用方记账一次(`hook_matcher_invalid`);
386
- * 受理面({@link hooksMatcherIssue})问的是同一只函数。
434
+ * PreCompact·PostCompact 的 `trigger` 词 / `if` 条件的名部),不按事件分档。
435
+ *
436
+ * 🔴 **预算(S-1017)**:求法与受理面 `"regex"` 档同一格表({@link MATCHER_EVALUATION}):字面形(名字表 / 空 / `*` / 缺省)直接问契约函数,不进 vm、不占额度;
437
+ * 正则形**每一次求值**进 vm、各拿一份固定的 {@link ADMISSION_MATCHER_BUDGET}`.budgetMs`(不共享、不读钟、不新造第二只预算常量)。受理面只对 core 目录里的别名 / 正名这几个短名字求过值,
438
+ * 运行期要对**任意别的工具名**求值 —— 受理过了的 matcher 在某个名字上灾难回溯,不能再同步占住事件循环。
439
+ * 四个答案(闭集,{@link MatcherAnswer}),调用方各用一条穷举 switch 处置({@link matcherGroupSelected} / {@link hookIfMatches}):
440
+ * · `true` / `false` —— 选中 / 不选;
441
+ * · `"invalid"` —— 该组不跑(fail-closed 到「不跑」),调用方记账一次(`hook_matcher_invalid`);
442
+ * · `"over_budget"` —— 这一次求值没在预算内结束 ⇒ **按选中处理 + 登记**(`hook_matcher_over_budget` 一行日志 + `matcher_over_budget` 一帧):不选 = 守卫 hook 被静默放过 = fail-open,
443
+ * 所以方向是「多跑」不是「少跑」;不静默 —— 每次发生各登记一次,一直在坏就一直说。
387
444
  */
388
- export declare function hookMatcherMatches(matcher: string | undefined, value: string): boolean | "invalid";
445
+ export declare function hookMatcherMatches(matcher: string | undefined, value: string): MatcherAnswer;
389
446
  /** `if` 条目条件(CC-exact,对照 CC 2.1.187/198 实测行为核验的真语义,两版一致):
390
447
  * 值 = permission-rule 模式(`ToolName` 或 `ToolName(arg-模式)`),【不是】表达式语言——按当前工具调用
391
448
  * 求值:名部走 permission matcher(交替/正则同 matcher 字段),括号内 arg-模式(`*` 通配)匹配工具输入的
392
449
  * 主字符串(Bash=command,文件工具=file_path/path)。CC 行为逐条目:不匹配 → 跳过该条目(记日志);
393
450
  * 非工具事件(payload 无 tool_name)→ "cannot be evaluated" 跳过;解析失败 → 跳过。返回:
394
- * true=跑 / "not_matched" / "unevaluable"(调用方分别记账;跳过永不静默)。
451
+ * true=跑 / "not_matched" / "unevaluable"(调用方分别记账;跳过永不静默)/ "over_budget"(S-1017:名部求值没在预算内结束 ⇒ 调用方按**选中**处理 + 登记,见 {@link hookMatcherMatches})。
395
452
  *
396
453
  * 2.1.250 复核([ref],2026-08-30;语料=sema-internal `blueprints/cc-decoded/cli250.js`):求值器与 220
397
454
  * 逐字同构——五种工具事件之外「cannot be evaluated for non-tool event」跳过、「Skipping hook due to if
@@ -399,7 +456,7 @@ export declare function hookMatcherMatches(matcher: string | undefined, value: s
399
456
  * 本实现同向。差异登记(不改行为):①250 证据里名部=**规范化后等值比对**(`vd(toolName)!==o`),
400
457
  * 「交替/正则」是 matcher 字段的文法——本实现名部走 hookMatcherMatches 属**超集**(alternation 也认),
401
458
  * 如实登记不收窄;②250 的 `if` 已扩到 prompt/agent/http/mcp_tool 条目(本 runner 只翻 command,不涉)。 */
402
- export declare function hookIfMatches(cond: string, payload: unknown): true | "not_matched" | "unevaluable";
459
+ export declare function hookIfMatches(cond: string, payload: unknown): true | "not_matched" | "unevaluable" | "over_budget";
403
460
  /** createSettingsHooksRegistration 的装配上下文(payload 的 CC-verbatim 字段来源)。 */
404
461
  export interface HookRunnerContext {
405
462
  logger: Logger;
@@ -471,6 +528,49 @@ export type HookLlmCall = (opts: {
471
528
  * · `unreachable`:连不上 / 网络层失败 / 超时(没有应答)
472
529
  * 载体层面的整体硬顶(`hard_timeout`)不在这里:它由 runner 自己的 `Promise.race` 铸、只在 runner 内部读,不是载体的失败码。 */
473
530
  export type HookLlmFailureCode = "model_unresolved" | "route_refused" | "credential_custody_failed" | "redirect_refused" | "bad_response" | "no_content" | "unreachable";
531
+ /** 托管相「未跑成」的原因闭集(= 帧 `hook_managed_unrun.reason`;每个词对应一条既有的跳过 / 故障臂,见 `fleet-bus.ts` 的 {@link HookManagedUnrun})。 */
532
+ export type ManagedUnrunReason = HookManagedUnrun["reason"];
533
+ /**
534
+ * 有放行 / 改写判词的事件(翻译器读 `permissionDecision: "allow"` / `updatedInput` 的那一个:PreToolUse)。判词不可信这条律(否决算数,放行与改写不作数)
535
+ * 只在这里有东西可不采信 ⇒ 只在这里铸 `distrust`;别的事件没有放行词,判词照收,不发「放行与改写不作数」的帧(那会说一件没发生的事)。
536
+ * 按事件名穷举(`satisfies Record<HookEventName, boolean>`,与 `HOOK_EVENT_OWNER` / `HOOK_EVENT_MATCHER_FIELD` 同形):契约加一个事件而这里没表态 = 编译红 ——
537
+ * 不缺省倒向「照收放行」(安全轴的闭集律)。壳属事件不在本服务跑,恒 `false`。
538
+ */
539
+ export declare const PERMISSIVE_VERDICT_EVENTS: {
540
+ readonly PreToolUse: true;
541
+ readonly PostToolUse: false;
542
+ readonly PostToolUseFailure: false;
543
+ readonly PostToolBatch: false;
544
+ readonly Notification: false;
545
+ readonly UserPromptSubmit: false;
546
+ readonly UserPromptExpansion: false;
547
+ readonly SessionStart: false;
548
+ readonly SessionEnd: false;
549
+ readonly Stop: false;
550
+ readonly StopFailure: false;
551
+ readonly SubagentStart: false;
552
+ readonly SubagentStop: false;
553
+ readonly PreCompact: false;
554
+ readonly PostCompact: false;
555
+ readonly PermissionRequest: false;
556
+ readonly PermissionDenied: false;
557
+ readonly Setup: false;
558
+ readonly TeammateIdle: false;
559
+ readonly TaskCreated: false;
560
+ readonly TaskCompleted: false;
561
+ readonly Elicitation: false;
562
+ readonly ElicitationResult: false;
563
+ readonly ConfigChange: false;
564
+ readonly WorktreeCreate: false;
565
+ readonly WorktreeRemove: false;
566
+ readonly InstructionsLoaded: false;
567
+ readonly CwdChanged: false;
568
+ readonly FileChanged: false;
569
+ readonly MessageDisplay: false;
570
+ readonly DirectoryAdded: false;
571
+ readonly PreModelSwitch: false;
572
+ readonly PostModelSwitch: false;
573
+ };
474
574
  /**
475
575
  * hook 上下文片段 → 喂给模型的单串。**所有** `additionalContext` 聚合点的唯一属主(此前是同一个
476
576
  * `contexts.join("\n")` 表达式抄在二十余处,总量帽无处可挂 —— 那正是漂移成因)。
@@ -532,7 +632,9 @@ export interface LlmHookExtra {
532
632
  * · 答案全部由本仓从 CC JSON 铸,引擎在 handler 边界屏(唯一判官),本仓不预屏;
533
633
  * · 无意见 ⇒ `next(e)`(链 handler 返回 `undefined` 是站点违约,PreToolUse / UserPromptSubmit 的失败列是 refuse ⇒ 每次都会被拒);
534
634
  * 观察站的 handler 恒返回 `undefined` —— 两条都在 {@link hangClassic} 成形;
535
- * · `uses.calls: []`(必填;本仓的 handler 不调 `$`),`uses.events` 从 {@link SETTINGS_HOOK_STATIONS} 派生。
635
+ * · `uses.calls: []`(必填;本仓的 handler 不调 `$`),`uses.events` 从 {@link SETTINGS_HOOK_STATIONS} 派生;
636
+ * · 每只翻译的第二个入参是引擎的 `next.signal`(这只 handler 的预算 ∪ 这次派发被取消;见 {@link DEFAULT_SETTINGS_HOOKS_BUDGET_MS}):
637
+ * 一路贯穿到命令腿的 spawn({@link runCommandHook}),本仓不自合成第二只、不另设钟。
536
638
  */
537
639
  export declare function createSettingsHooksRegistration(config: RunnableHooksConfig, ctx: HookRunnerContext, budgetMs: number): ModRegistration<EngineDollar> | undefined;
538
640
  export {};