@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
@@ -2,6 +2,7 @@ import { PROTOCOL_TABLE, compileAllowList, parsePermissionRule } from "@sema-age
2
2
  import { displayListEntry } from "./list-entry-display.js";
3
3
  import { limitRefusal } from "./limit-refusal.js";
4
4
  import { TOOL_NAME_ROSTER } from "./namespaced-rule-name.js";
5
+ import { NOT_IN_ROSTER, entryProblem, entryProblemsFacts } from "./entry-problems.js";
5
6
  export const ruleEntryListShapeOk = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
6
7
  export const MAX_ALLOW_LAYER_ENTRIES = 1_000;
7
8
  const ALLOW_LAYER_OVER_CAP_TAIL = "Refused rather than truncated: a truncated list silently drops the entries past the cap. Merge entries into broader ones (mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**)) or trim the list";
@@ -76,14 +77,17 @@ function selectorEntryName(entry) {
76
77
  }
77
78
  const isProtocolWideName = (name) => PROTOCOL_TABLE.some((e) => name === `${e.prefix}*`);
78
79
  function selectorInertEntriesOf(list, side) {
80
+ const readings = selectorReadings(list, side);
81
+ return side === "allow" ? readings.filter((i) => allowSideReadsAsNothing(i.reason)) : readings;
82
+ }
83
+ function selectorReadings(list, side) {
79
84
  return list.flatMap((entry) => {
80
85
  if (entry === "*" && side === "allow")
81
86
  return [];
82
87
  const name = selectorEntryName(entry);
83
88
  if (side === "deny" && isProtocolWideName(name))
84
89
  return [];
85
- const inert = compileAllowList([name], "deny", TOOL_NAME_ROSTER).inert.map((i) => ({ ...i, entry }));
86
- return side === "allow" ? inert.filter((i) => allowSideReadsAsNothing(i.reason)) : inert;
90
+ return compileAllowList([name], "deny", TOOL_NAME_ROSTER).inert.map((i) => ({ ...i, entry }));
87
91
  });
88
92
  }
89
93
  function allowSideReadsAsNothing(reason) {
@@ -167,17 +171,18 @@ function* toolListsOf(body) {
167
171
  if (isPlainRecord(permissions))
168
172
  yield { layer: "settings.permissions.allow", field: "settings.permissions.allow", prefix: "", at: "settings.permissions.allow", list: permissions["allow"] };
169
173
  }
170
- function entryOfList(l) {
174
+ function inertReadingOfList(l) {
171
175
  const face = TOOL_LIST_FACES[l.layer];
172
- const over = overCapOfList(l);
173
- if (over !== undefined)
174
- return over;
175
176
  if (!ruleEntryListShapeOk(l.list))
176
177
  return undefined;
177
178
  const inert = inertEntriesOfList(l.list, l.layer);
178
179
  if (inert.length === 0)
179
180
  return undefined;
180
- return { layer: l.layer, side: face.side, code: face.code, message: `${l.prefix}${describeInertRuleEntries(l.field, inert)} — ${REFUSAL_TAIL[face.side]}` };
181
+ return { inert, entry: { layer: l.layer, side: face.side, code: face.code, message: `${l.prefix}${describeInertRuleEntries(l.field, inert)} — ${REFUSAL_TAIL[face.side]}` } };
182
+ }
183
+ function inertProblemsOf(l, inert) {
184
+ const face = TOOL_LIST_FACES[l.layer];
185
+ return inert.map((i) => entryProblem(face.code, l.at, i.entry, i.reason));
181
186
  }
182
187
  function overCapOfList(l) {
183
188
  if (!Array.isArray(l.list))
@@ -196,16 +201,24 @@ export function skillToolListsOverCap(skill, at, scope) {
196
201
  function firstInertEntry(body, acceptLayer, acceptSide) {
197
202
  if (!isPlainRecord(body))
198
203
  return undefined;
204
+ let first;
205
+ const problems = [];
199
206
  for (const l of toolListsOf(body)) {
200
207
  if (!acceptLayer(l.layer))
201
208
  continue;
202
- const entry = entryOfList(l);
203
- if (entry === undefined)
209
+ const over = overCapOfList(l);
210
+ if (over !== undefined) {
211
+ if (first === undefined)
212
+ return over;
213
+ continue;
214
+ }
215
+ const reading = inertReadingOfList(l);
216
+ if (reading === undefined || !acceptSide(reading.entry.side))
204
217
  continue;
205
- if (entry.extra !== undefined || acceptSide(entry.side))
206
- return entry;
218
+ first ??= reading.entry;
219
+ problems.push(...inertProblemsOf(l, reading.inert));
207
220
  }
208
- return undefined;
221
+ return first === undefined ? undefined : { ...first, extra: { ...entryProblemsFacts(problems) } };
209
222
  }
210
223
  export function skillDenyInertEntryOf(body) {
211
224
  return firstInertEntry(body, (layer) => layer === "skills" || layer === "agents.skills", () => true);
@@ -213,4 +226,51 @@ export function skillDenyInertEntryOf(body) {
213
226
  export function inertToolListEntryOf(body, sides = ["allow", "deny"]) {
214
227
  return firstInertEntry(body, () => true, (side) => sides.includes(side));
215
228
  }
229
+ function callerToolNameSet(tools) {
230
+ const names = new Set();
231
+ for (const t of tools) {
232
+ names.add(t.name);
233
+ for (const a of t.aliases ?? [])
234
+ names.add(a);
235
+ for (const row of t.agentToolPool ?? []) {
236
+ names.add(row.name);
237
+ for (const a of row.aliases ?? [])
238
+ names.add(a);
239
+ }
240
+ }
241
+ return names;
242
+ }
243
+ const isProtocolNamespacedName = (name) => PROTOCOL_TABLE.some((e) => name.startsWith(e.prefix));
244
+ function allowSelectorEntryWarning(entry, callerNames) {
245
+ if (entry === "*")
246
+ return undefined;
247
+ if (callerNames.has(selectorEntryName(entry)))
248
+ return undefined;
249
+ const read = selectorReadings([entry], "allow")[0];
250
+ if (read !== undefined)
251
+ return read.reason;
252
+ const name = selectorEntryName(entry);
253
+ if (isProtocolNamespacedName(name))
254
+ return undefined;
255
+ return TOOL_NAME_ROSTER.has(name) ? undefined : NOT_IN_ROSTER;
256
+ }
257
+ export function allowSelectorWarningsOf(body, tools) {
258
+ if (!isPlainRecord(body))
259
+ return [];
260
+ const callerNames = callerToolNameSet(tools);
261
+ const out = [];
262
+ for (const l of toolListsOf(body)) {
263
+ if (l.layer !== "allowTools" && l.layer !== "agents.allowTools")
264
+ continue;
265
+ if (!ruleEntryListShapeOk(l.list) || l.list.length > MAX_ALLOW_LAYER_ENTRIES)
266
+ continue;
267
+ const code = TOOL_LIST_FACES[l.layer].code;
268
+ for (const entry of l.list) {
269
+ const reason = allowSelectorEntryWarning(entry, callerNames);
270
+ if (reason !== undefined)
271
+ out.push(entryProblem(code, l.at, entry, reason));
272
+ }
273
+ }
274
+ return out;
275
+ }
216
276
  //# sourceMappingURL=rule-entry-list.js.map
@@ -2,9 +2,9 @@ import { randomUUID } from "node:crypto";
2
2
  import { z } from "zod";
3
3
  import { recordFailOpen } from "./observability/fail-open.js";
4
4
  import { createLogger } from "./observability/logger.js";
5
- import { ABSOLUTE_HOST_PATH_MAX } from "@sema-agent/settings-schema";
5
+ import { ABSOLUTE_HOST_PATH_MAX, hasControlOrBidi } from "@sema-agent/settings-schema";
6
6
  import { isDirectWritableRuleBehavior } from "./permission-rule-vocab.js";
7
- import { CONTROL_AND_BIDI_CHARS, hasBidiControls } from "./text-bidi.js";
7
+ import { hasBidiControls } from "./text-bidi.js";
8
8
  import { confirmRuleApproval, RULE_BEHAVIORS, parseRuleText, ruleReachesProgramRun, ruleToolGrammarOf, precheckEditedRuleText, prepareCardApproval, prepareCcImport, redeemRuleBatch, redeemRuleTicket, addPersistedRule, removePersistedRule, isValidDurableScope, effectiveOrThrow, readRowBehavior, } from "@sema-agent/core";
9
9
  import { buildRulePayloadHash } from "./plugins/permission-rule-store-sql.js";
10
10
  export const RULE_IMPORT_TICKET_TTL_MS = 10 * 60_000;
@@ -178,7 +178,7 @@ function screenLocalImportRow(row) {
178
178
  detail: "this project root carries bidirectional control characters — the directory a reader sees is not the directory the matcher would use",
179
179
  };
180
180
  }
181
- if (scope.kind === "project" && CONTROL_AND_BIDI_DETECT_RE.test(scope.root)) {
181
+ if (scope.kind === "project" && hasControlOrBidi(scope.root)) {
182
182
  return {
183
183
  reason: "scope_control_chars",
184
184
  detail: "this project root carries control bytes (C0/DEL) — it is not a path, one SQL dialect refuses to store it at all, and it breaks the separator assumption this lane's comparison keys rest on",
@@ -220,7 +220,6 @@ function screenLocalImportRow(row) {
220
220
  return consistent(written.rule);
221
221
  }
222
222
  const LOCAL_IMPORT_LAYER_PATH = "local-import:rules";
223
- const CONTROL_AND_BIDI_DETECT_RE = new RegExp(`[${CONTROL_AND_BIDI_CHARS}]`);
224
223
  const LOCAL_IMPORT_KEY_SEP = "\u0000";
225
224
  function buildLocalImportLayers(candidates) {
226
225
  const byRoot = new Map();
@@ -22,12 +22,26 @@
22
22
  * 三条提交腿(同步 / 流式 / durable)各在两处喂同一只:持流的那一形把每一帧交给 {@link RunAcceptance.observe};终局落行之后调一次
23
23
  * {@link RunAcceptance.settle}。腿上不再有「什么时候起标题」的判断,标题器的唯一调用点是本文件的闩。座由提交门在 `prepareSpec` 里
24
24
  * 随 spec 一起铸(`PreparedTaskSubmission.acceptance`);不经提交门的内部车道铸一只不带标题器的座,也就不起标题。
25
+ *
26
+ * ## 标题写成之后(`session_titled` 帧,契约 §4a-ttl)
27
+ * 标题器写成时把那一帧交回本座({@link RunAcceptanceDeps.sessionTitler} 的 `onTitled`);本座是这条 run 的流与标题器之间**唯一**的接缝:
28
+ * · 持**活流**的腿在开流时挂一只写口({@link RunAcceptance.attachStream};今天只有 `POST /v1/tasks/stream` 的 SSE 腿)—— 帧经它写到这条流上;
29
+ * · 没有活流的腿(同步 JSON 腿 / durable 后台腿:读者走账本 tail,账本里没有这一帧)不挂 ⇒ 帧丢弃,会话行是真源;
30
+ * · 终帧 `done` 已过 ⇒ 丢弃(终帧是流的最后一帧);连接已断 / 已结束(写口自报够不着)⇒ 丢弃。
31
+ * 丢弃不计失败:帧是「行刚刚变了」的活通知,读者随时可读行;唯一的读者门是「提交这条 run 的人」—— 写口只在本次提交自己的连接上,不广播。
25
32
  */
33
+ import type { SessionTitler } from "./session-titler.js";
34
+ import type { SessionTitledFrame } from "./session-titled-frame.js";
26
35
  export interface RunAcceptanceDeps {
27
36
  /** 标题器(缺席 = 本部署不自动起名)。 */
28
- sessionTitler?: {
29
- maybeTitle(sessionId: string, objective: string, model?: string): void;
30
- };
37
+ sessionTitler?: SessionTitler;
38
+ }
39
+ /** 一条活流的写口(持活流的腿自己造)。 */
40
+ export interface RunStreamSink {
41
+ /** 这条连接此刻还收得到帧(没结束、没断、腿没在收摊)。 */
42
+ reachable(): boolean;
43
+ /** 把一帧写到这条流上。 */
44
+ write(frame: SessionTitledFrame): void;
31
45
  }
32
46
  export interface RunAcceptanceInput {
33
47
  sessionId?: string;
@@ -46,6 +60,8 @@ export interface RunAcceptance {
46
60
  readonly turns: number;
47
61
  };
48
62
  }): void;
63
+ /** 持活流的腿开流时挂上它的写口(一次提交至多一条活流;重挂以最后一次为准)。不挂 = 本次提交没有可写的流,标题写成的帧丢弃。 */
64
+ attachStream(sink: RunStreamSink): void;
49
65
  }
50
66
  export declare function createRunAcceptance(deps: RunAcceptanceDeps, input: RunAcceptanceInput): RunAcceptance;
51
67
  //# sourceMappingURL=run-acceptance.d.ts.map
@@ -6,15 +6,24 @@ function isObjectiveApplied(ev) {
6
6
  }
7
7
  export function createRunAcceptance(deps, input) {
8
8
  let accepted = false;
9
+ let terminalSeen = false;
10
+ let stream;
11
+ const deliver = (frame) => {
12
+ if (stream === undefined || terminalSeen || !stream.reachable())
13
+ return;
14
+ stream.write(frame);
15
+ };
9
16
  const accept = () => {
10
17
  if (accepted)
11
18
  return;
12
19
  accepted = true;
13
20
  if (input.sessionId)
14
- deps.sessionTitler?.maybeTitle(input.sessionId, input.objective, input.model);
21
+ deps.sessionTitler?.maybeTitle(input.sessionId, input.objective, input.model, deliver);
15
22
  };
16
23
  return {
17
24
  observe(ev) {
25
+ if (ev.type === "done")
26
+ terminalSeen = true;
18
27
  if (!accepted && isObjectiveApplied(ev))
19
28
  accept();
20
29
  },
@@ -22,6 +31,9 @@ export function createRunAcceptance(deps, input) {
22
31
  if (result.stats.turns > 0)
23
32
  accept();
24
33
  },
34
+ attachStream(sink) {
35
+ stream = sink;
36
+ },
25
37
  };
26
38
  }
27
39
  //# sourceMappingURL=run-acceptance.js.map
package/dist/run-local.js CHANGED
@@ -28,6 +28,7 @@ import { buildUnreadConfigFileFields, buildUnreadConfigKeyFields } from "./web-a
28
28
  import { composeExecutionLane, settleHostLaneShell } from "./boot/execution-lane.js";
29
29
  import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
30
30
  import { logConfigDirMigration, migrateLocalConfigDirectory } from "./config-d-migration.js";
31
+ import { assertLocalConfigDirTrusted, ConfigDirUntrustedError } from "./config-dir-trust.js";
31
32
  import { applyEffective, applyCenterReadFace, applySkillsManifest, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./web-admin-client/facade.js";
32
33
  import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
33
34
  import { executionLaneHomeDir, executionLaneOf } from "./execution-lane-caps.js";
@@ -36,12 +37,14 @@ import { createInstructionSourceSeat } from "./instruction-source-notice.js";
36
37
  import { loadDeploymentSkills } from "./capabilities/skills.js";
37
38
  import { createRepoClient } from "./capabilities/repo-tools.js";
38
39
  import { webSearchConfigFromEnv, createWebSearchBackend } from "./plugins/web-search.js";
39
- import { buildPromptSeats, buildScenarios, createScenarioGate, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
40
+ import { buildExcludeToolsSeat, buildPromptSeats, buildScenarios, createScenarioGate, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
40
41
  import { createTaskListLane } from "./boot/task-list-lane.js";
41
42
  import { pickHandsRunner, withoutHands } from "./capabilities/hands-lane.js";
42
43
  import { HttpError, sessionIdShapeIssue } from "./security.js";
43
44
  import { createMemoryEngineIncidentSink } from "./memory-incident-sink.js";
44
- import { fileMemoryEngineRoot, memoryEngineBackendFor, memoryProjectKeyFor, memorySpecForRequest } from "./memory-scope.js";
45
+ import { fileMemoryEngineRoot, memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
46
+ import { createMemoryProjectLayers } from "./memory-project-layer.js";
47
+ import { assertProjectLayerOwnable } from "./project-identity.js";
45
48
  import { judgeServedModelRoute } from "./model-route-endpoint.js";
46
49
  import { createMemorySyncRunner, createMemorySyncTransport } from "./memory-sync-client.js";
47
50
  import { buildPricing, cappedCeiling, createTracer } from "./budget.js";
@@ -339,10 +342,18 @@ export async function runLocal(argv, deps = {}) {
339
342
  logConfigDiagnostics(logger);
340
343
  provisionSemaConfigDir(config, logger);
341
344
  installOutboundDispatcher(logger);
342
- const providerInput = { provider: config.configProvider ?? "local", localDir: root };
345
+ const providerInput = { provider: config.configProvider ?? "local", localDir: root, localOwnerUid: config.configLocalOwnerUid };
343
346
  const configSource = configProviderKind(providerInput);
344
- if (configSource === "local")
347
+ if (configSource === "local") {
348
+ try {
349
+ await assertLocalConfigDirTrusted({ root, declaredOwnerUid: config.configLocalOwnerUid });
350
+ }
351
+ catch (err) {
352
+ printErr(err instanceof Error ? err.message : String(err));
353
+ return 2;
354
+ }
345
355
  logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
356
+ }
346
357
  try {
347
358
  await composeExecutionLane(config, { configSource, localRoot: root, logger, drivesFromFile: ["host"] });
348
359
  }
@@ -384,6 +395,10 @@ export async function runLocal(argv, deps = {}) {
384
395
  }
385
396
  }
386
397
  catch (err) {
398
+ if (err instanceof ConfigDirUntrustedError) {
399
+ printErr(err.message);
400
+ return 2;
401
+ }
387
402
  if (applying)
388
403
  logger.warn("config_apply_refused", { source: configProvider.kind, err: String(err), note: "the candidate failed to apply at boot — running on env (run-local has no LKG); none of the candidate's domains is adopted; this is not a reachability failure" });
389
404
  else
@@ -478,7 +493,7 @@ export async function runLocal(argv, deps = {}) {
478
493
  ...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
479
494
  ...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
480
495
  });
481
- logger.info("memory_sync_enabled", { url: buildDisplaySafeUrl(config.memorySync.url), scope: config.memorySync.scope, cursorPath: memorySync.cursorPath });
496
+ logger.info("memory_sync_enabled", { url: buildDisplaySafeUrl(config.memorySync.url), scope: config.memorySync.scope, cursorPath: memorySync.cursorPathFor(config.memorySync.scope) });
482
497
  memorySync.trigger("boot");
483
498
  }
484
499
  else if (config.memorySync) {
@@ -649,6 +664,20 @@ export async function runLocal(argv, deps = {}) {
649
664
  return 2;
650
665
  }
651
666
  const scope = args.user ?? "local";
667
+ if (memoryEngine) {
668
+ try {
669
+ assertProjectLayerOwnable(scope, "--user");
670
+ }
671
+ catch (err) {
672
+ printErr(err instanceof Error ? err.message : String(err));
673
+ void lspManager?.dispose();
674
+ await fileBackend.dispose();
675
+ return 2;
676
+ }
677
+ }
678
+ const projectKey = memoryEngine
679
+ ? await createMemoryProjectLayers({ backend: memoryEngine.backend, syncRunner: memorySync, log: logger }).prepare(config, scope, workspaceDir)
680
+ : undefined;
652
681
  const taskTimeoutSec = Math.floor(parseNumOrFailNonNegative("TASK_TIMEOUT_SEC", process.env.TASK_TIMEOUT_SEC || "0"));
653
682
  const timeoutSec = taskWallClockSec(taskTimeoutSec, false);
654
683
  const mcp = mcpForScenario(config.mcpServers, scenarioName);
@@ -668,12 +697,13 @@ export async function runLocal(argv, deps = {}) {
668
697
  backgroundScope: "session",
669
698
  oneShot: true,
670
699
  principal: scope,
671
- ...(memoryEngine ? { memory: memorySpecForRequest(scope, memoryProjectKeyFor(config, scope, workspaceDir), undefined) } : {}),
700
+ ...(memoryEngine ? { memory: memorySpecForRequest(scope, projectKey, undefined) } : {}),
672
701
  model: mention.model,
673
702
  getApiKeyAndHeaders: keyResolver,
674
703
  tools: cap.tools,
675
704
  skills: cap.skills,
676
705
  ...buildPromptSeats(scenarioName, cap.prompt, undefined),
706
+ ...buildExcludeToolsSeat(cap.excludeTools, undefined),
677
707
  ...(cap.finalVerification === true ? { finalVerification: true } : {}),
678
708
  ...(mcp ? { mcp } : {}),
679
709
  ...(a2a ? { a2a } : {}),
package/dist/runs.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { defaultTaskRegistry, type CascadeConfig, type CheckpointToken, type RunInternals, type Runner, type SubagentSteerHandle, type TaskResult, type TaskSpec, type TaskStream, type TerminalCause } from "@sema-agent/core";
2
+ import { type EntryProblem } from "./entry-problems.js";
2
3
  import type { SendUserFileEmitter } from "./capabilities/send-user-file-tool.js";
3
4
  import type { RunStore } from "./plugins/store-backend.js";
4
5
  import type { Metrics } from "./observability/metrics.js";
@@ -113,8 +114,10 @@ export declare function syncRefusalHttpStatus(result: Pick<TaskResult, "terminal
113
114
  * 同步腿零工作拒体的机读事实(交 `refusalBody` 的 `facts`)—— 唯一一处。入参是**出口封口 + 脱敏后**的终局(调用方递 `redactTerminalResult(sealResultForExit(result)).terminal`,
114
115
  * 与 run 记录读面 / 流式 `done.result` 上的 `terminal` 同一只来源),本函数只按码取它的 `detail.detail`,不另读、不另脱。码不在登记表里、终局不是 `failed`、
115
116
  * 引擎没给 `coded` 因由 ⇒ `{}`(缺席不造键)。
117
+ * 两张工具名清单的码({@link ENGINE_TOOL_LIST_REFUSAL_CODES})是另一臂:体事实不取引擎的因由,取 `admissionReadings`(受理口对放行侧选择器清单的读数,`PreparedTaskSubmission.warnings`)
118
+ * 去掉 `not_in_roster`、且 `code` 与终局的码相同(同一族清单)的那些 —— 与受理口 400 同一只机读位形;没有读数 ⇒ `{}`。
116
119
  */
117
- export declare function zeroWorkRefusalFacts(terminal: unknown): Readonly<Record<string, unknown>>;
120
+ export declare function zeroWorkRefusalFacts(terminal: unknown, admissionReadings?: readonly EntryProblem[]): Readonly<Record<string, unknown>>;
118
121
  /**
119
122
  * 一条提交腿把引擎终局落行之后的**唯一**收尾:**零工作的拒不占提交幂等键**。判据就是上面这只 {@link syncRefusalHttpStatus}
120
123
  * (零 turn、零 token 且是 prepare 期的拒码)—— 三条提交腿(同步 / 流式 / durable)同调这一只,不另开判据。
@@ -347,17 +350,15 @@ pendingEngineNotices?: readonly {
347
350
  sessionId?: unknown;
348
351
  }[],
349
352
  /**
350
- * 🔴 **S-218:部署方铸的 TRUSTED run internals**(今天唯一成员 `workflowParkedResume`)。
353
+ * 🔴 **部署方铸的 TRUSTED run internals**(今天唯一成员 `workflowParkedResume` = 本会话已受理的 workflow 子代决定)。
351
354
  *
352
- * 它**不是** `TaskSpec` 字段、不是工具参数、不进请求体 —— 模型永远不能自己决定一次审批。铸点只有
353
- * 一个:`/decide` 的 workflow 第三条车道(判据属主 = `parked-decide.ts` 的 `planWorkflowParkedDecide`
354
- * 顶注 + `http/durable-run-leg.ts` 的 `TrustedRunInternals`)。本腿只负责把它摊进**下面那只**共享
355
- * 供给座席,core 的 `prepareTask` 据它给 Workflow 工具挂 `parkedResume` dep。
355
+ * 它**不是** `TaskSpec` 字段、不是工具参数、不进请求体 —— 模型永远不能自己决定一次审批。产自决定进引擎的唯一读者
356
+ * (`parked-decide.ts` 的 `heldWorkflowParkDecisions`),由本腿唯一的调用方 `mintAndDriveDurableRun` 开跑前读一次传进来。
357
+ * 本腿只负责把它摊进**下面那只**共享供给座席,core 的 `prepareTask` 据它给 Workflow 工具挂 `parkedResume` dep。
356
358
  *
357
359
  * 位置在座席对象的**最后**:座席里那几位(onActivity/onForwardEvent/onTaskNotification/onSubagentSpawn)
358
- * 是本腿自己的执行面供给,调用方无权覆盖它们 —— 真要撞名,撞的也只能是本腿自己新加的位,而那时
359
- * `TrustedRunInternals` 的白名单会在编译期先红一次(它只开部署方可以决定的那一格)。
360
- * 缺席 ⇒ 座席与本位存在之前逐字相同。
360
+ * 是本腿自己的执行面供给,调用方无权覆盖它们 —— 型只开 `workflowParkedResume` 这一格(`Pick`),新开一格必须在这里显式点名。
361
+ * 缺席 / 空对象 ⇒ 座席与本位存在之前逐字相同。
361
362
  */
362
363
  trustedInternals?: Pick<RunInternals, "workflowParkedResume">,
363
364
  /**
package/dist/runs.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { runWithVerification, runCascade, defaultTaskRegistry, taskNotificationDedupKey, DURABLE_AGENT_HANDLE_RE } from "@sema-agent/core";
2
2
  import { failureCodeOf, sealResultForExit, outwardPlane } from "./terminal.js";
3
+ import { NOT_IN_ROSTER, entryProblemsFacts } from "./entry-problems.js";
3
4
  import { GOVERNANCE_HTTP_STATUS } from "./governance-http-status.js";
4
5
  import { TOOL_DECLARATION_HTTP_STATUS } from "./tool-declaration-http-status.js";
5
6
  import { isSessionErrorCode, sessionErrorHttp } from "./session-error-wire.js";
@@ -110,11 +111,29 @@ export function syncRefusalHttpStatus(result) {
110
111
  return resumeAtHttpStatus(result);
111
112
  }
112
113
  const ZERO_WORK_REFUSAL_DETAIL_CODES = new Set(["config.user_attachment_invalid"]);
113
- export function zeroWorkRefusalFacts(terminal) {
114
+ const ENGINE_ENTRY_SPELLING_REASONS = new Set(["near_miss", "unknown_name"]);
115
+ function engineReasonOf(detail) {
116
+ if (detail === null || typeof detail !== "object")
117
+ return undefined;
118
+ const c = detail;
119
+ if (c.kind !== "coded" || c.detail === null || typeof c.detail !== "object")
120
+ return undefined;
121
+ const reason = c.detail.reason;
122
+ return typeof reason === "string" ? reason : undefined;
123
+ }
124
+ const ENGINE_TOOL_LIST_REFUSAL_CODES = new Set(["config.tool_face_control", "config.agent.unknown_tool"]);
125
+ export function zeroWorkRefusalFacts(terminal, admissionReadings = []) {
114
126
  if (terminal === null || typeof terminal !== "object")
115
127
  return {};
116
128
  const t = terminal;
117
- if (t.kind !== "failed" || typeof t.code !== "string" || !ZERO_WORK_REFUSAL_DETAIL_CODES.has(t.code))
129
+ if (t.kind !== "failed" || typeof t.code !== "string")
130
+ return {};
131
+ if (ENGINE_TOOL_LIST_REFUSAL_CODES.has(t.code)) {
132
+ const readings = admissionReadings.filter((p) => p.code === t.code && p.reason !== NOT_IN_ROSTER);
133
+ const engineReason = engineReasonOf(t.detail);
134
+ return readings.length > 0 && engineReason !== undefined && ENGINE_ENTRY_SPELLING_REASONS.has(engineReason) ? { ...entryProblemsFacts(readings) } : {};
135
+ }
136
+ if (!ZERO_WORK_REFUSAL_DETAIL_CODES.has(t.code))
118
137
  return {};
119
138
  const cause = t.detail;
120
139
  if (cause === null || typeof cause !== "object")
@@ -489,7 +508,6 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
489
508
  ? approval.coordinator.runWithContext({
490
509
  taskId,
491
510
  owner: elicitOwner ?? owner,
492
- emit: approvalEmit,
493
511
  abortSignal: cancelCtrl.signal,
494
512
  ...(spec.sessionId ? { sessionId: spec.sessionId } : {}),
495
513
  emitCard: createApprovalCardEmitter({ appendDurable: (f) => approvalEmit(f) }),
@@ -25,6 +25,9 @@
25
25
  * ⇒ **无 checkpoint 店的部署上这一面本就不成立**,该键在那里 inert)
26
26
  * · `autoMode` — prepare-task.js `=== true` **∧** `deps.autoMode !== undefined`(部署需先具备分类器;
27
27
  * 显式 opt-in 极性,且 [ref] 起本侧传的是三态 org deny 位,见 toCoreRuntimeCaps 头注)
28
+ * · `bypassPermissions` — `dist/core/mode-policy.js` 的模式折叠(请求 `bypassPermissions` ∧ 本位 `=== false` ⇒ 这条腿跑在
29
+ * `default`、发 `config.permission_mode_unavailable{by:"operator_deny"}`、回执 `foldedBy:"operator_deny"`);
30
+ * deny 形,缺席 = 不阻。S-900 D2 起由 center 的 `allowBypassPermissions` 写(此前本仓零写点)
28
31
  * · `allowMemoryOptOut` — prepare-memory.js `resolveCaptureEntitlementFresh`(+prepare-task.js
29
32
  * 的 value/faulted 投影);**极性反转,但只在 `open` 姿态下**——判决全表在
30
33
  * `dist/core/runner/memory-capture-optout.js` 的 `adjudicateCaptureOptOut`,按
@@ -34,7 +37,8 @@
34
37
  * · `"governed"` :14-23 要**显式 `true`** 才准;`false` / 缺席 / fault **一律拒**
35
38
  * (拒由分「answered false」与「verdict absent / resolver fault」两句)
36
39
  * · `"capture-required"`:4-12 **完全不看本 verdict**(逐字「resolver-independent」),恒拒
37
- * 只有 `allowUltracode` 是被 DROP 的那一个(下文)。
40
+ * center 的键里只有 `allowUltracode` 被 DROP(下文);center 的其余每一键都在 {@link toCoreRuntimeCaps} 的处置表里,
41
+ * settings-schema 加一键而这里没处置 ⇒ tsc 红(S-900 D2 之前 `allowBypassPermissions` / `allowAutoMode` 两键就是这样被静默丢掉的)。
38
42
  *
39
43
  * It pulls the PER-PRINCIPAL entitlement from center's `GET /api/config/effective?principal=` (via
40
44
  * {@link fetchPrincipalCaps}). center has ALREADY pre-resolved the tighten-only intersection (fleet defaults ∩
@@ -44,13 +48,16 @@
44
48
  *
45
49
  * 🔐 FAIL-CLOSED (core security mandate, prepare-task.ts): an entitlement-resolver outage must NEVER silently
46
50
  * GRANT a capability center may have denied. On a hard fetch error we mint `{ allowWorkflows: false, allowFork: false,
47
- * autoMode: false }` — the three OPTIONAL **amplification** caps — and do NOT force the durable gate (that could
51
+ * autoMode: false, autoModeDenySource: "org", bypassPermissions: false }` — the four OPTIONAL **amplification** caps
52
+ * (plus the auto bit's plane) — and do NOT force the durable gate (that could
48
53
  * strand an autonomous run on an absent operator). We never serve a STALE cached GRANT past its TTL on a
49
54
  * fresh-fetch failure (a revoked cap must not linger because center blipped).
50
55
  * ⚠️ [ref]① 纠失实:这段曾写作「降级为 `{ allowWorkflows: false }`」,与真码不符 —— 真铸点在本文件
51
- * `load()` 的 catch 臂(搜 `Caps face FAIL CLOSED`),逐字是上行那三键:`allowFork` 自提货批就在,
52
- * `autoMode` 由 [ref] / core [ref] 同车加入(org deny 位不能因一次抖动在 denyTtl 窗内抬起)。
53
- * 🔒 **三键以外的那三键刻意不铸**:`forceDurableGate` 同上(强挂人在环会搞死无人值守的 run);
56
+ * `load()` 的 catch 臂(搜 `Caps face FAIL CLOSED`),逐字是上行那几键:`allowFork` 自提货批就在,
57
+ * `autoMode` 由 [ref] / core [ref] 同车加入(org deny 位不能因一次抖动在 denyTtl 窗内抬起),`bypassPermissions`
58
+ * 由 S-900 D2 加入(同一条律:center 可能已经拒了的 bypass 不能因一次抖动放出来;core 自己的 resolver-throw 降级臂
59
+ * 铸的也是这四位拒,`dist/core/runner/prepare-caps-and-workflow.js`)。
60
+ * 🔒 **四只放大位以外的那三键刻意不铸**:`forceDurableGate` 同上(强挂人在环会搞死无人值守的 run);
54
61
  * `allowObservers` 是 `=== true` opt-in,缺席已等于关;`allowMemoryOptOut` 是隐私轴的 FAULT-TRANSIT 契约
55
62
  * (core types.d.ts 逐字禁止在 fault 上自造一个显式值)—— 铸 false 就是把故障臂默默换成判决臂。
56
63
  *
@@ -62,6 +69,9 @@
62
69
  * The resolver maps center's `EntitlementRuntimeCaps` → the SUBSET core enforces ({@link RuntimeCaps}): center
63
70
  * also carries `allowUltracode` (a shell/UX reasoning-tier cap the engine has no primitive for), which we DROP —
64
71
  * this seam feeds the ENGINE, and `allowUltracode` is enforced at the service settings-resolution layer, not here.
72
+ * center's two MODE kill-switches are NOT dropped: `allowBypassPermissions:false` ⇒ `bypassPermissions:false`,
73
+ * `allowAutoMode:false` ⇒ the same auto deny bit `autoMode:false` writes (S-900 D2 — a mode's every refusal is an engine
74
+ * deny bit; the engine folds, announces and reports it on `wiring_manifest.permissionMode`).
65
75
  */
66
76
  import type { RuntimeCaps } from "@sema-agent/core";
67
77
  import type { EntitlementRuntimeCaps } from "@sema-agent/settings-schema";
@@ -138,7 +148,7 @@ export declare function toCoreRuntimeCaps(ent: EntitlementRuntimeCaps | null | u
138
148
  export declare function centerEntitlementSourceWired(config: Pick<ServiceConfig, "webAdmin">): boolean;
139
149
  /** The two per-principal faces served off ONE caps fetch + cache. */
140
150
  export interface PrincipalEntitlementsClient {
141
- /** core's `RunnerDeps.runtimeCapsResolver` seam — FAIL-CLOSED on error (deny workflows/fork/autoMode;
151
+ /** core's `RunnerDeps.runtimeCapsResolver` seam — FAIL-CLOSED on error (deny workflows/fork/autoMode/bypassPermissions;
142
152
  * [ref]① 随批纠:此处是同一句降级声明的第二个写者,漏了 [ref] 加的 `autoMode`。真铸点同上)。 */
143
153
  resolveRuntimeCaps: (principal: string | undefined) => Promise<RuntimeCaps | undefined>;
144
154
  /**
@@ -27,12 +27,21 @@ function traceExecutionLaneDefault(form, ownLane, logger) {
27
27
  catch {
28
28
  }
29
29
  }
30
+ const CENTER_ENGINE_CAP_KEYS = [
31
+ "allowWorkflows",
32
+ "forceDurableGate",
33
+ "allowFork",
34
+ "allowObservers",
35
+ "autoMode",
36
+ "allowAutoMode",
37
+ "allowBypassPermissions",
38
+ "allowMemoryOptOut",
39
+ ];
30
40
  export function toCoreRuntimeCaps(ent) {
31
41
  if (!ent)
32
42
  return undefined;
33
- const autoMode = ent.autoMode;
34
43
  const badCap = (v) => v !== undefined && typeof v !== "boolean";
35
- if (badCap(ent.allowWorkflows) || badCap(ent.forceDurableGate) || badCap(ent.allowFork) || badCap(ent.allowObservers) || badCap(autoMode) || badCap(ent.allowMemoryOptOut)) {
44
+ if (CENTER_ENGINE_CAP_KEYS.some((k) => badCap(ent[k]))) {
36
45
  throw new Error("runtimeCaps from center carries a non-boolean cap (contract breach — fail closed)");
37
46
  }
38
47
  const caps = {};
@@ -44,10 +53,14 @@ export function toCoreRuntimeCaps(ent) {
44
53
  caps.allowFork = ent.allowFork;
45
54
  if (typeof ent.allowObservers === "boolean")
46
55
  caps.allowObservers = ent.allowObservers;
47
- if (typeof autoMode === "boolean")
48
- caps.autoMode = autoMode;
56
+ if (ent.autoMode === false || ent.allowAutoMode === false)
57
+ caps.autoMode = false;
58
+ else if (ent.autoMode === true)
59
+ caps.autoMode = true;
49
60
  if (caps.autoMode === false)
50
61
  caps.autoModeDenySource = "org";
62
+ if (ent.allowBypassPermissions === false)
63
+ caps.bypassPermissions = false;
51
64
  if (typeof ent.allowMemoryOptOut === "boolean")
52
65
  caps.allowMemoryOptOut = ent.allowMemoryOptOut;
53
66
  return Object.keys(caps).length ? caps : undefined;
@@ -146,7 +159,7 @@ export function createPrincipalEntitlementsClient(opts) {
146
159
  catch {
147
160
  e = new Error("center fetch failed with an unstringifiable rejection reason");
148
161
  }
149
- const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false, autoModeDenySource: "org" }, expiresAt: now() + denyTtlMs };
162
+ const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false, autoModeDenySource: "org", bypassPermissions: false }, expiresAt: now() + denyTtlMs };
150
163
  if (!recordDeny)
151
164
  readMintedDeny.add(entry);
152
165
  putCache(bin.cache, principal, entry);
@@ -14,7 +14,16 @@
14
14
  *
15
15
  * The marker `SEMA_PKG_SOURCE` always rides along: the image's pkg-source.sh hook (pod-start / profile.d)
16
16
  * materializes the file-bound pieces from it; images without the hook simply ignore it.
17
+ *
18
+ * ## One law: no URL that rides into the model-visible sandbox env carries userinfo
19
+ * Everything this module derives lands in the env of every sandbox process — including the ones the model drives
20
+ * (`env`, `printenv`) — so `https://user:pass@mirror/…` among the `custom` addresses would hand the deployment's
21
+ * package-source credential to the model. {@link customPkgSourceFromEnv} is the ONE reader of the six addresses and the
22
+ * one place that judges them: the shared URL-shape judge (`httpUrlFlaws`, the same one MEMORY_EMBEDDER_ENDPOINT /
23
+ * A2A_SERVE_URL answer to) says no ⇒ it throws, startup refuses. Never stripped, never rewritten, never forwarded
24
+ * quietly. The request face has no package-source address key at all (deployment face only).
17
25
  */
26
+ import { type HttpUrlFlaw } from "@sema-agent/settings-schema";
18
27
  /** Explicit URLs for `custom` (RFC B: 极端情况出口). Read from the service process env (operator-trusted). */
19
28
  export interface CustomPkgSource {
20
29
  aptMirror?: string;
@@ -29,6 +38,15 @@ export interface CustomPkgSource {
29
38
  * profile (unset = byte-identical sandbox — the B5 backward-compat contract).
30
39
  */
31
40
  export declare function derivePkgSourceEnv(profile: string | undefined, custom?: CustomPkgSource): Record<string, string>;
32
- /** Read the `custom` explicit-URL set from the service process env (operator-trusted deployment config). */
41
+ /**
42
+ * The refusal sentence for one address (pure data): the shared judge's rule words + the value's origin only
43
+ * ({@link buildHttpUrlRefusal}), then why it matters here and the two ways out. No byte of the credential can reach it.
44
+ */
45
+ export declare function buildCustomPkgSourceRefusal(envName: string, raw: string, flaws: readonly HttpUrlFlaw[]): string;
46
+ /**
47
+ * Read the `custom` explicit-URL set from the service process env (operator-trusted deployment config) — the ONE reader and
48
+ * the ONE judge of those six addresses (see the module header). An address the shared judge refuses (userinfo, or a shape
49
+ * that is not a parseable http(s) URL) throws {@link buildCustomPkgSourceRefusal}; empty / unset = not set.
50
+ */
33
51
  export declare function customPkgSourceFromEnv(env?: NodeJS.ProcessEnv): CustomPkgSource;
34
52
  //# sourceMappingURL=sandbox-pkg-source.d.ts.map
@@ -1,3 +1,5 @@
1
+ import { httpUrlFlaws } from "@sema-agent/settings-schema";
2
+ import { buildHttpUrlRefusal } from "./url-refusal.js";
1
3
  const GLOBAL_ENV = {
2
4
  PIP_INDEX_URL: "https://pypi.org/simple",
3
5
  UV_DEFAULT_INDEX: "https://pypi.org/simple",
@@ -43,14 +45,34 @@ export function derivePkgSourceEnv(profile, custom) {
43
45
  return { SEMA_PKG_SOURCE: profile };
44
46
  }
45
47
  }
48
+ export function buildCustomPkgSourceRefusal(envName, raw, flaws) {
49
+ return (`${buildHttpUrlRefusal(envName, raw, flaws)} — with SANDBOX_PKG_SOURCE=custom this address is written verbatim into the environment of every sandbox ` +
50
+ `(e2b VM / k8s pod), where any process the model can run reads it back with \`env\`; an address that carries userinfo, or whose shape cannot be judged ` +
51
+ `credential-free (not http(s)://host[:port][/path], or containing a backslash — the URL standard reads it as "/", package managers do not), would hand ` +
52
+ `the deployment's package-source credential to the model, so the server refuses to start rather than forward or rewrite it. ` +
53
+ `Way out: (1) set ${envName} to the credential-free address and give the package manager its credential through its own channel — a token variable ` +
54
+ `named in the lane's name list (E2B_SANDBOX_ENV / K8S_SANDBOX_ENV; naming it accepts that every process in the sandbox, the model included, can read it) ` +
55
+ `or a credential file baked into the sandbox image; (2) if the source needs no authentication, drop the userinfo.`);
56
+ }
46
57
  export function customPkgSourceFromEnv(env = process.env) {
47
- return {
48
- ...(env.SEMA_APT_MIRROR ? { aptMirror: env.SEMA_APT_MIRROR } : {}),
49
- ...(env.SEMA_PIP_INDEX ? { pipIndex: env.SEMA_PIP_INDEX } : {}),
50
- ...(env.SEMA_UV_INDEX ? { uvIndex: env.SEMA_UV_INDEX } : {}),
51
- ...(env.SEMA_UV_PY_MIRROR ? { uvPyMirror: env.SEMA_UV_PY_MIRROR } : {}),
52
- ...(env.SEMA_NPM_REGISTRY ? { npmRegistry: env.SEMA_NPM_REGISTRY } : {}),
53
- ...(env.SEMA_NODE_MIRROR ? { nodeMirror: env.SEMA_NODE_MIRROR } : {}),
58
+ const addresses = {
59
+ aptMirror: ["SEMA_APT_MIRROR", env.SEMA_APT_MIRROR],
60
+ pipIndex: ["SEMA_PIP_INDEX", env.SEMA_PIP_INDEX],
61
+ uvIndex: ["SEMA_UV_INDEX", env.SEMA_UV_INDEX],
62
+ uvPyMirror: ["SEMA_UV_PY_MIRROR", env.SEMA_UV_PY_MIRROR],
63
+ npmRegistry: ["SEMA_NPM_REGISTRY", env.SEMA_NPM_REGISTRY],
64
+ nodeMirror: ["SEMA_NODE_MIRROR", env.SEMA_NODE_MIRROR],
54
65
  };
66
+ const out = {};
67
+ for (const field of Object.keys(addresses)) {
68
+ const [name, raw] = addresses[field];
69
+ if (!raw)
70
+ continue;
71
+ const flaws = raw.includes("\\") ? ["not-http-url"] : httpUrlFlaws(raw, ["userinfo"]);
72
+ if (flaws.length > 0)
73
+ throw new Error(buildCustomPkgSourceRefusal(name, raw, flaws));
74
+ out[field] = raw;
75
+ }
76
+ return out;
55
77
  }
56
78
  //# sourceMappingURL=sandbox-pkg-source.js.map