@sema-agent/server 7.136.0 → 7.138.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 (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -27,8 +27,12 @@ import type { CapabilitiesLocal } from "./routes/capabilities.js";
27
27
  import type { SessionsLocal } from "./routes/sessions.js";
28
28
  import type { SessionSyncLocal } from "./routes/session-sync.js";
29
29
  import type { PlanApprovePermissionModeAfter } from "../task-settings.js";
30
+ import type { GateSighting } from "../approval-gate-currency.js";
30
31
  import type { VerifyRoundsSpec } from "./verify-rounds.js";
31
32
  import type { RunAbort } from "../run-cancel-context.js";
33
+ import type { RunIdentity } from "../identity-source.js";
34
+ import type { PeerLease } from "../peer-seat.js";
35
+ import type { GateCommitment, GateSettlementEvidence } from "../gate-settlement.js";
32
36
  /** 跨域可变状态 = lens1 §C2 实测的那 8 条「运行期登记簿」,一个对象。
33
37
  * [ref]:`cancelledViaVerb`(按 taskId 键控的「这次是取消动词」旁表)删除 —— 中止成因改挂在每条腿自己的
34
38
  * {@link RunAbort} 句柄上(`inflightRuns` 的值),同寿同删,不再有一张与腿不同寿的旁表。 */
@@ -146,6 +150,12 @@ export interface PreparedTaskSubmission {
146
150
  * 不经提交门的内部车道(`/decide` 的宿主新 turn)铸一只不带标题器的座:不起标题。
147
151
  */
148
152
  acceptance: import("../run-acceptance.js").RunAcceptance;
153
+ /**
154
+ * 这次装配的**宿主租约**:受理漏斗在装配之前开(`peerDesk.lease("fresh")`),装配在它之下登记交给引擎的对端声明;漏斗成功即把它交到这里 ——
155
+ * 拿到本产物的那只函数紧接着写 `try { … } finally { prepared.peerLease.release() }`,其后每个出口(早退、合流败方、建行拒、驱动返回)按构造都放。
156
+ * 活过那段作用域的驱动(后台腿)经 `heldFor(prepared.peerLease, () => …)` 自持一只,自己落定才放。续跑家族的内部车道交它自己漏斗开的那一只。
157
+ */
158
+ peerLease: PeerLease;
149
159
  }
150
160
  /**
151
161
  * 一条会话的**续跑重建输入**(`checkpoint_ctx` 的行体)—— 提交腿写一次,续跑腿读它重建 spec。
@@ -250,6 +260,11 @@ export interface DriveResumeArgs {
250
260
  sessionId: string;
251
261
  ctx: CheckpointCtx;
252
262
  };
263
+ /**
264
+ * 这条续跑的**宿主租约**(续跑漏斗 `resolveResumeSpecOrBlocked` 开、装配在它之下登记对端声明;调用方作用域的 `finally` 放)。
265
+ * 驱动腿经 `heldFor(args.peerLease, () => driveResumeLeg(…))` 自持一只:受理早回的那一形里,腿活过调用方作用域,自己落定才放。
266
+ */
267
+ peerLease: PeerLease;
253
268
  /** [ref]:续跑腿的执行 Runner。resume 会用同一条 resolveSpec 重解析场景,故与首跑选同一只 —— 否则
254
269
  * 一次续跑就把手带 band 重新 mount 回来(收窄只在首跑成立 = 没成立)。 */
255
270
  runner: Runner;
@@ -259,6 +274,12 @@ export interface DriveResumeArgs {
259
274
  taskConfig: Omit<TaskSpec, "objective" | "sessionId">;
260
275
  resumeObjective: string;
261
276
  outcome: ResumeOutcome;
277
+ /**
278
+ * 🔴 **这条腿到达边界时能证什么**(必填 —— 缺 = 编译错;闭集,语义属主 = `gate-settlement.ts` 的 {@link GateCommitment})。同一条驱动路径既续本请求点名的门
279
+ * (`/decide` 引擎臂、`/resume`、`/plan_review` ⇒ `gate_resolved`,带执行**前**从选中那一行捕获、过了信任边界的身份),也替宿主投递(wake ⇒ `delivered`)。
280
+ * 它只是分类:位由受理点与终局体两个边界按它铸,从不只凭这一句声明铸;缺席的取消出口(`checkpoint.resume_aborted` / 抛出臂)不铸。
281
+ */
282
+ commitment: GateCommitment;
262
283
  verifyRounds: VerifyRoundsSpec | undefined;
263
284
  /**
264
285
  * **R-1**(车CJ 收车档 §10 R-1;[ref] 批落地)—— 本条 resume 腿**装配期**铸下的用户面通告
@@ -281,11 +302,13 @@ export interface DriveResumeArgs {
281
302
  /** [ref]/[ref]:调用方声明「本腿的 park 是终局后纯 park,session claim 已随终局 finalize 删除」——
282
303
  * getActiveTaskId 缺席时**铸新 canonical taskId + createRun 全生命周期行**(wake 续跑=同 session 新一轮
283
304
  * turn),而不是无行裸跑(不可取消/无计费归因/无 durable append/fleet 不可见,且 core `spec.taskId ??
284
- * sessionId` fallback 会把 lastRunId 铸成 sessionId)。`source` 进 run 行元数据(runMeta 同列)。
305
+ * sessionId` fallback 会把 lastRunId 铸成 sessionId)。`source` 进 run 行元数据(runMeta 同列,只作归因);`identity` = 新行的身份元组(调用方经
306
+ * `runIdentityOf(req, config, 卡属主)` 读凭据门铸下的那一份:按下按钮的就是卡属主才有,否则空)。
285
307
  * decide/answer/plan_review 腿**不设**此位:它们的 claim 在 park 期间特意保留,缺席=行被 reap 的竞态,
286
308
  * 维持既有兜底(checkpoint token 同拍过期 ⇒ resumeStream 拒),不铸新行。 */
287
309
  mintFreshRun?: {
288
310
  source: string;
311
+ identity: RunIdentity | null;
289
312
  };
290
313
  /** `/decide` 第三条车道交给本腿的那一件决定投递(语义属主 = {@link WorkflowDecisionDelivery} 顶注)。缺席 ⇒ 只摊决定行(其余四条 resume 腿恒缺席)。 */
291
314
  workflowDecision?: WorkflowDecisionDelivery;
@@ -429,10 +452,7 @@ export interface RouteLegs {
429
452
  decider?: {
430
453
  principal?: string;
431
454
  explicitOperator: boolean;
432
- }): Promise<{
433
- status: number;
434
- body: object;
435
- }>;
455
+ }): Promise<ResumeLegOutcome>;
436
456
  /** notify-wake 域:唤醒一条 parked checkpoint。 */
437
457
  resumeWake(sessionId: string, message: string | undefined, caller: string | undefined, req: IncomingMessage | undefined,
438
458
  /** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
@@ -440,7 +460,7 @@ export interface RouteLegs {
440
460
  acceptEarly?: boolean,
441
461
  /** 透传给 {@link DriveResumeArgs.workflowDecision}。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道投递腿的专用席,
442
462
  * 而两条腿共用这一条驱动路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿」的成文纪律。 */
443
- workflowDecision?: WorkflowDecisionDelivery): Promise<HostLegOutcome>;
463
+ workflowDecision?: WorkflowDecisionDelivery): Promise<ResumeLegOutcome>;
444
464
  /**
445
465
  * assistant plan_review 三态腿的**纯读段**([ref],7.97.0):选卡 → 属主轻读 → 载入 → 行级 scope → 门类 → 这条决断
446
466
  * 唯一的一次 ctx 读。任何一步拒 ⇒ `{ok:false, answer}`(不改任何状态;端点在消费一次性 nonce **之前**把它答出去);
@@ -457,7 +477,9 @@ export interface RouteLegs {
457
477
  decider?: {
458
478
  principal?: string;
459
479
  explicitOperator: boolean;
460
- }): Promise<{
480
+ },
481
+ /** [ref]:决断方看到的那道门(决断体的 `checkpointId`);不是当前门 ⇒ `409 approval_stale`(`approval_stale` 律,语义属主 = `resume-legs.ts` 的同名形参顶注)。 */
482
+ sighting?: GateSighting): Promise<{
461
483
  readonly ok: false;
462
484
  readonly answer: {
463
485
  status: number;
@@ -475,10 +497,7 @@ export interface RouteLegs {
475
497
  acceptEarly?: boolean,
476
498
  /** [ref]:批准之后这条会话继续用的 permission mode(闭集 `PLAN_APPROVE_PERMISSION_MODES_AFTER`;只在把计划带出 plan 的决定
477
499
  * —— `approve` / `edit` —— 上有意义,缺席 ⇒ `"default"`)。语义与判据的唯一属主 = `resume-legs.ts` 的同名形参顶注。 */
478
- permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<{
479
- status: number;
480
- body: object;
481
- }>;
500
+ permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<ResumeLegOutcome>;
482
501
  }
483
502
  /**
484
503
  * [ref] 件 S-2 —— resume 族**受理点的断连留痕**(裁定:维持 detach,补观察面)。
@@ -667,48 +686,13 @@ export type RouteDecl = RouteDispatchDecl | RouteGateDecl;
667
686
  * api-error-text-freeze 基线流程。
668
687
  */
669
688
  /**
670
- * resume 家族**引擎腿**的结局:HTTP 应答(`status` / `body`)+ 一位**进程内**事实(不上 wire)。workflow 宿主腿的结局另型({@link HostLegOutcome}),并集 = {@link ResumeLegOutcome}。
671
- *
672
- * `decisionCommitted` —— **这条腿的终局是在引擎受理了这次决定之后才结出来的**([ref] X5,7.112.0):本腿走到了「引擎交回结果」那一步
673
- * (`resumeStream` / `resumeWithVerification` 解析 = core 的全部 pre-CAS 门 + checkpoint resolve CAS 都过了 —— 受理点的判据属主
674
- * = {@link DriveResumeArgs.acceptEarly} 顶注),之后才收场。只由 `driveResumeLeg` 走完引擎那一步的终局出口铸;`CheckpointError` 臂、
675
- * 「中止抛穿」臂、一切 4xx / 拒绝出口一律**不铸**(缺席 ⇒ 证不出提交,读者按「没提交」读 —— fail-closed)。
676
- *
677
- * 读者:`/decide` 的两道「这次决定提交了没有」门 —— [ref] 迟到结算留痕(`noteLateSettleIfAccepted`)与 remember 豁免落店
678
- * (`routes/approvals-assistant.ts`)。它们原先只读 wire 体的 `errorCode !== "cancelled"`(「取消 = 决定没提交」),[ref] 给续跑腿补了
679
- * 「引擎受理之后才被取消」的取消终局之后,`cancelled` 不再等价「没提交」⇒ 两门改读本位:`200 ∧ (errorCode≠cancelled ∨ decisionCommitted)`。
680
- * 🔴 为什么不放进 `result.cancelContext`(主会话初稿的落点):那只快照的契约是「分诊材料,不是状态机输入:任何门 / CAS / resume 判定都不许
681
- * 读它」(`plugins/store-contracts.ts` `RunCancelContext` 顶注)—— 这两道门正是判定;而且门读的是 `/decide` 的平面体、看不到结果对象。
682
- * 受理与否是腿自己的控制流事实,在腿上说,零 wire 变更。
683
- */
684
- export interface EngineLegOutcome {
685
- status: number;
686
- body: object;
687
- decisionCommitted?: true;
688
- }
689
- /**
690
- * **workflow 宿主腿的结局(wake / fresh)—— 型上就没有 `decisionCommitted`**([ref] ②,7.113.0;`never` 让「这条路径不铸」成为**编译事实**,不是靠人记)。
691
- *
692
- * 为什么这条路径不该有该位:`/decide` 的 workflow 第三条车道(`resumeCheckpoint` 的 parked 分流,`planWorkflowParkedDecide` 之后)与 `POST /v1/sessions/:id/wake`
693
- * 把决定 / 消息交给**宿主会话的下一跑**(`resumeWake` / `startFreshHostTurn`)。它们的 200 只到「已交给宿主的下一跑」—— 子代 checkpoint 的 resolve CAS 发生在
694
- * workflow 引擎自己驱动那一步,server 观察不到(`resume-legs.ts` 该分流处「刻意不落 `late_settle`」同源)。「这次决定被引擎受理了」这句话在这里**没有可说的对象**,
695
- * 于是 `decisionCommitted` 在这条路径上语义含混(修前:`resumeWake` 的收尾是 `driveResumeIntoRunLog` 的 `ResumeLegOutcome`,非受理点早返形(无 `acceptEarly`)下它会把
696
- * 引擎腿的 `decisionCommitted:true` 原样带出去 —— 型被声明返回型 `{status, body}` 擦掉了,运行期仍在)。读者核实:两道提交门(`noteLateSettleIfAccepted` 迟到结算留痕、
697
- * `/decide` 的 remember 豁免落店)在这条路径上今天**零读取**(前者该分流直接 `return`、不调;后者的 `pendingGrant` 只由引擎腿的 `onResumeCommitted` 回调置位,宿主腿不调它,且 `planWorkflowParkedDecide` 对 workflow 车道的 `remember` 本就 fail-closed 拒 —— `decide.workflow_remember_unsupported`,`parked-decide.ts`)——
698
- * 无读者 ⇒ 剥掉该位,而不是留一个「铸了也没人读、读了不知道什么意思」的位。出口经 {@link buildHostLegOutcome} 只带 `status` / `body`。
689
+ * resume 家族一条腿的结局:HTTP 应答(`status` / `body`)。「这次决定提交了没有」只有一种说法 —— 体上的结清证据 `decisionCommitted`
690
+ * (唯一铸点 / 唯一读法 = `gate-settlement.ts`);进程内不另带第二个提交位。
699
691
  */
700
- export interface HostLegOutcome {
692
+ export interface ResumeLegOutcome {
701
693
  status: number;
702
694
  body: object;
703
- decisionCommitted?: never;
704
695
  }
705
- /** resume 家族一条腿的结局:引擎腿(可带 `decisionCommitted`)∪ workflow 宿主腿(型上没有)。`out.decisionCommitted === true` 同时收窄到引擎腿。 */
706
- export type ResumeLegOutcome = EngineLegOutcome | HostLegOutcome;
707
- /** 把任意腿的结局折成宿主腿结局:**只带 `status` / `body`**(丢掉引擎腿的 `decisionCommitted` —— 见 {@link HostLegOutcome})。纯数据。 */
708
- export declare function buildHostLegOutcome(out: {
709
- status: number;
710
- body: object;
711
- }): HostLegOutcome;
712
696
  /**
713
697
  * **「决定/续跑已受理」那一枚 200 收据的单一铸点**([ref])。
714
698
  *
@@ -718,11 +702,12 @@ export declare function buildHostLegOutcome(out: {
718
702
  * 都不该加**;写成两份字面量,漂开的那天没有任何东西会说话。
719
703
  *
720
704
  * `bindingEnforced` 的语义不因铸点而变(「这次决定按绑定坐标受理,不是盲目放行」),故两腿同带。
705
+ *
706
+ * `evidence` = 结清证据(`gate-settlement.ts`):引擎续跑腿的受理点交 `buildSettlementEvidence({ at: "engine_accepted", … })` 铸的那一份
707
+ * (`gate_resolved` 腿 ⇒ 位 + 身份;wake 的 `delivered` ⇒ 空);没跨过任何边界的回执(宿主新一跑、同一决定重投)交 `NO_SETTLEMENT_EVIDENCE`。
708
+ * 调用方不手写证据键 —— 体上的两键只有那一只铸点。
721
709
  */
722
- export declare function acceptedResumingReceipt(taskId: string, sessionId: string): {
723
- status: number;
724
- body: object;
725
- };
710
+ export declare function acceptedResumingReceipt(taskId: string, sessionId: string, evidence: GateSettlementEvidence): ResumeLegOutcome;
726
711
  /** 一条腿的结局是不是一张「已受理」回执,是 ⇒ 回执上那一跑的 `taskId`(同一张回执的读法与 {@link acceptedResumingReceipt} 住在一起;
727
712
  * `/decide` 的 workflow 车道据它把投递那一跑记在决定行上)。 */
728
713
  export declare function acceptedTaskIdOf(out: {
@@ -21,11 +21,8 @@ export function assertNever(x) {
21
21
  throw new Error(`unreachable route id: ${String(x)}`);
22
22
  }
23
23
  export const ROUTE_METHOD_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE"];
24
- export function buildHostLegOutcome(out) {
25
- return { status: out.status, body: out.body };
26
- }
27
- export function acceptedResumingReceipt(taskId, sessionId) {
28
- return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
24
+ export function acceptedResumingReceipt(taskId, sessionId, evidence) {
25
+ return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true, ...evidence } };
29
26
  }
30
27
  export function acceptedTaskIdOf(out) {
31
28
  const body = out.body;
@@ -272,11 +272,17 @@ async function handleMessageSend({ req, res, ctx, params, serve, runStore }) {
272
272
  const prepared = await ctx.legs.prepareSpec(req, res, body, (e) => {
273
273
  typed = e;
274
274
  });
275
- if (typed)
276
- throw rpcErrorFromTypedFailure(typed, skillId);
277
- if (!prepared)
275
+ if (!prepared) {
276
+ if (typed)
277
+ throw rpcErrorFromTypedFailure(typed, skillId);
278
278
  return undefined;
279
- receipt = await createDurableRun(req, res, ctx, prepared, idem);
279
+ }
280
+ try {
281
+ receipt = await createDurableRun(req, res, ctx, prepared, idem);
282
+ }
283
+ finally {
284
+ prepared.peerLease.release();
285
+ }
280
286
  }
281
287
  if (!receipt)
282
288
  return undefined;
@@ -25,7 +25,7 @@
25
25
  * · **能力位同源**:`capabilities.agentRoster` 与这里的 501 谓词是同一个 `deps.backgroundAgentStore`。
26
26
  */
27
27
  import type { IncomingMessage, ServerResponse } from "node:http";
28
- import type { BackgroundAgentRowSummary } from "@sema-agent/core";
28
+ import { type BackgroundAgentRowSummary } from "@sema-agent/core";
29
29
  import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
30
30
  /** 名册窗的扫描上限(与 fleet 的终态窗同姿势:读面要有界)。窗满时回体带 `truncated:true`,
31
31
  * `total` 于是诚实地是「窗内行数」而不是租户全量 —— 一个悄悄封顶的 total 比没有 total 更坏。 */
@@ -1,7 +1,9 @@
1
+ import { chosenAgentName } from "@sema-agent/core";
1
2
  import { sendJson, sendError } from "../send.js";
2
3
  import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
3
4
  import { assertNever } from "../route-ctx.js";
4
5
  import * as facts from "../../capability-facts.js";
6
+ import { backgroundAgentNameOf } from "../../background-agent-name.js";
5
7
  export const ROSTER_SCAN_LIMIT = 500;
6
8
  const ROSTER_STATUSES = ["running", "parked", "completed", "failed", "killed"];
7
9
  const ROSTER_KEY_DISPOSITION = {
@@ -24,9 +26,11 @@ export function rosterAgentId(row) {
24
26
  return row.handle;
25
27
  }
26
28
  function projectRow(r) {
29
+ const name = backgroundAgentNameOf(r);
27
30
  return {
28
31
  handle: rosterAgentId(r),
29
- ...(r.name !== undefined ? { name: r.name } : {}),
32
+ name,
33
+ ...(chosenAgentName(r.handle, name) === undefined ? { anonymous: true } : {}),
30
34
  ...(r.agentType !== undefined ? { agentType: r.agentType } : {}),
31
35
  status: r.status,
32
36
  spawnedAt: r.spawnedAt,
@@ -22,29 +22,31 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCaller
22
22
  import { readOwnedRun, readOwnedSession } from "../owner-access.js";
23
23
  import { governanceOriginOf } from "../../runtime-governance.js";
24
24
  import { deploymentListAsks } from "../../approval.js";
25
- import { callGrantBindingOf, questionGrantBindingOf } from "../../standing-answer-grant.js";
25
+ import { grantBindingOf } from "../../standing-answer-grant.js";
26
26
  import { sendResumeOutcome } from "../route-ctx.js";
27
27
  import { assertNever } from "../route-ctx.js";
28
28
  import * as facts from "../../capability-facts.js";
29
29
  import { storeFaultClassOf } from "../../plugins/store-fault.js";
30
30
  import { recordFailOpen } from "../../observability/fail-open.js";
31
- import { durableRowIdentity } from "../../checkpoint-identity.js";
31
+ import { MAX_CHECKPOINT_ID_CHARS, durableRowIdentity } from "../../checkpoint-identity.js";
32
32
  import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
33
33
  import { fieldConflictFacts } from "../../field-conflict.js";
34
+ import { buildSettlementEvidence, decisionCommittedOf } from "../../gate-settlement.js";
34
35
  const DECIDE_BODY_DECLARED_KEYS = [
35
36
  "answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "feedback", "reason", "remember", "updatedInput",
36
37
  ];
37
38
  const DECIDE_PROOF_COVERED_KEYS = ["answer", "boundCallId", "boundInputHash", "decision", "reason"];
38
39
  const DECIDE_NOT_IN_PROOF_KEYS = ["checkpointToken", "decidedBy", "feedback", "remember", "updatedInput"];
39
40
  const PLAN_REVIEW_BODY_DECLARED_KEYS = [
40
- "boundCallId", "decidedBy", "decision", "editedPlan", "permissionModeAfter", "reason",
41
+ "boundCallId", "checkpointId", "decidedBy", "decision", "editedPlan", "permissionModeAfter", "reason",
41
42
  ];
42
- const PLAN_REVIEW_PROOF_COVERED_KEYS = ["boundCallId", "decision", "editedPlan", "permissionModeAfter", "reason"];
43
+ const PLAN_REVIEW_PROOF_COVERED_KEYS = ["boundCallId", "checkpointId", "decision", "editedPlan", "permissionModeAfter", "reason"];
43
44
  const PLAN_REVIEW_NOT_IN_PROOF_KEYS = ["decidedBy"];
44
45
  const PROOF_SLOT_OF = {
45
46
  answer: "answer",
46
47
  boundCallId: "boundCallId",
47
48
  boundInputHash: "boundInputHash",
49
+ checkpointId: "checkpointId",
48
50
  decision: "decision",
49
51
  editedPlan: "boundInputHash",
50
52
  permissionModeAfter: "permissionModeAfter",
@@ -258,6 +260,7 @@ async function decideIdempotentReplay(cs, args) {
258
260
  decision,
259
261
  bindingEnforced: true,
260
262
  ...(executionOutcome !== undefined ? { executionOutcome } : {}),
263
+ ...buildSettlementEvidence({ at: "replay_matched" }),
261
264
  },
262
265
  };
263
266
  }
@@ -351,8 +354,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
351
354
  sendError(res, 404, "request.route_unsupported", "not found");
352
355
  return;
353
356
  }
354
- const rows = await deps.approvalExemptionStore.list(exSessionId);
355
- sendJson(res, 200, { exemptions: rows.filter((r) => callGrantBindingOf({ toolName: r.toolName }).kind === "none") });
357
+ sendJson(res, 200, { exemptions: await deps.approvalExemptionStore.list(exSessionId) });
356
358
  return;
357
359
  }
358
360
  if (exToolName === undefined) {
@@ -625,6 +627,17 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
625
627
  }
626
628
  }
627
629
  const planNonce = typeof body.boundCallId === "string" ? body.boundCallId : undefined;
630
+ if (body.checkpointId !== undefined) {
631
+ if (typeof body.checkpointId !== "string" || body.checkpointId.length === 0) {
632
+ sendError(res, 400, "request.field_invalid", "checkpointId must be a non-empty string (the identity of the plan gate you decided on: read terminal.checkpointId on the run result, or the checkpointId on its approvals / inbox entry)");
633
+ return;
634
+ }
635
+ if (body.checkpointId.length > MAX_CHECKPOINT_ID_CHARS) {
636
+ sendError(res, 400, "request.field_invalid", `checkpointId too large (max ${MAX_CHECKPOINT_ID_CHARS} chars)`);
637
+ return;
638
+ }
639
+ }
640
+ const sighting = typeof body.checkpointId === "string" ? { face: "checkpointId", value: body.checkpointId } : undefined;
628
641
  const run = await runStore.getRun(taskId);
629
642
  if (!run) {
630
643
  if (deps.config.directDoorActive) {
@@ -647,6 +660,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
647
660
  const hdr = (n) => { const h = req.headers[n]; return Array.isArray(h) ? h[0] : h; };
648
661
  const proof = verifyDirectDoorProof({ jwt: hdr(PRINCIPAL_TOKEN_HEADER), mac: hdr(APPROVAL_MAC_HEADER), kid: hdr(APPROVAL_MAC_KID_HEADER) }, buildApprovalEnvelope(run.sessionId, PLAN_REVIEW_PROOF_COVERED_KEYS, {
649
662
  boundCallId: planNonce ?? null,
663
+ checkpointId: sighting?.value,
650
664
  decision,
651
665
  editedPlan: decision === "edit" ? editedPlanBinding(body.editedPlan) : null,
652
666
  permissionModeAfter: isPlanApprovePermissionModeAfter(body.permissionModeAfter) ? body.permissionModeAfter : undefined,
@@ -665,7 +679,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
665
679
  sendError(res, 404, "not_found.run", "task not found");
666
680
  return;
667
681
  }
668
- const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator });
682
+ const plan = await preparePlanReview(run.sessionId, { taskId, principalPresent: principal !== undefined }, { principal: deciderPrincipal, explicitOperator }, sighting);
669
683
  if (!plan.ok) {
670
684
  sendResumeOutcome(res, plan.answer, deps.logger);
671
685
  return;
@@ -857,8 +871,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
857
871
  }
858
872
  : undefined;
859
873
  const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, hostDecisionFacts(decidedBy, deciderPrincipal), req, answer, binding, grantOnCommit, true, { principal: deciderPrincipal, explicitOperator });
860
- const outErrorCode = out.body.errorCode;
861
- if (pendingGrant !== undefined && out.status === 200 && (outErrorCode !== "cancelled" || out.decisionCommitted === true) && deps.approvalExemptionStore) {
874
+ if (pendingGrant !== undefined && decisionCommittedOf(out) && deps.approvalExemptionStore) {
862
875
  try {
863
876
  await deps.approvalExemptionStore.grant(pendingGrant.sessionId, pendingGrant.toolName, deciderPrincipal ?? null);
864
877
  rememberApplied = true;
@@ -900,6 +913,7 @@ function approvalsReadFailureOf(err) {
900
913
  case "corrupt":
901
914
  return "approvals.read_corrupt";
902
915
  case "connection":
916
+ case "deployment":
903
917
  case "unclassified":
904
918
  return "approvals.read_unavailable";
905
919
  default: {
@@ -940,7 +954,7 @@ function projectPendingForWire(row, deployment) {
940
954
  governanceForced: governanceForced === true,
941
955
  requiresRealApproval: row.requiresRealApproval === true,
942
956
  mandated: row.mandated === true || row.ruleOffersAbsence === "mandated",
943
- grantBinding: questionGrantBindingOf(row, deploymentListQuestion),
957
+ grantBinding: grantBindingOf(row),
944
958
  classes: row.classes,
945
959
  deploymentListQuestion,
946
960
  });
@@ -1,4 +1,4 @@
1
- import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
1
+ import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus, thinkingOffSpelled } from "@sema-agent/core";
2
2
  import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableAliasNames, selectableCatalog } from "../../model-select.js";
3
3
  import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
4
4
  import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
@@ -12,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
12
12
  import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
13
13
  import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
14
14
  import { a2aInjectionHonored } from "../../task-a2a.js";
15
- import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
15
+ import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, countMcpProbeDeclarations, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
16
16
  import { mcpForScenario } from "../../web-admin-client/facade.js";
17
17
  import { sendScenarioNotFound } from "../scenario-read-face.js";
18
18
  import { sendJson, sendError } from "../send.js";
@@ -23,6 +23,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
23
23
  import { projectStoreCapability } from "../../store-posture.js";
24
24
  import { projectWebSearchCapability } from "../../plugins/web-search.js";
25
25
  import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
26
+ import { judgeSandboxGitPlane, sandboxGitPlanePremisesOf } from "../../sandbox-git-plane.js";
26
27
  import { MCP_ASSERTION_HEADER_SENT } from "../../mcp-assertion-header.js";
27
28
  import { gateCompositeMembers } from "../../capabilities/composite-members.js";
28
29
  import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
@@ -86,9 +87,17 @@ export async function handleCapabilities(req, res, match, ctx) {
86
87
  artifacts: facts.durableRuns(deps).available,
87
88
  approvals: facts.checkpointPark(deps).available,
88
89
  approvalReadRootGrant: facts.readRootGrant(deps).available,
90
+ modsDeploymentPackages: facts.deploymentModPackages(deps).available ? true : undefined,
89
91
  sessions: facts.sessionAuditView(deps).available,
90
92
  deviceExecutor: facts.deviceLane(deps).available
91
- ? { enabled: true, protocolVersion: DEVICE_PROTOCOL_VERSION, maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4, wsPath: DEVICE_WS_PATH, management: facts.deviceManagement(deps).available }
93
+ ? {
94
+ enabled: true,
95
+ protocolVersion: DEVICE_PROTOCOL_VERSION,
96
+ maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4,
97
+ wsPath: DEVICE_WS_PATH,
98
+ management: facts.deviceManagement(deps).available,
99
+ ...(deps.config.remoteExec?.provider === "device" && deps.config.remoteExec.relayUrl !== undefined ? { relayUrl: deps.config.remoteExec.relayUrl } : {}),
100
+ }
92
101
  : false,
93
102
  sessionEvents: facts.sessionEventStream(deps).available,
94
103
  fleet: facts.fleetStream(deps).available
@@ -180,6 +189,7 @@ export async function handleCapabilities(req, res, match, ctx) {
180
189
  approvalFrameFamilies: [...facts.approvalFrameFamilies(streamApprovalFact)],
181
190
  approvalDecisionNote: true,
182
191
  approvalDecidedBy: true,
192
+ planReviewCheckpointId: true,
183
193
  permissionModes: [...PERMISSION_MODES],
184
194
  sessionReadRedaction: true,
185
195
  sideQuery: true,
@@ -224,6 +234,7 @@ export async function handleCapabilities(req, res, match, ctx) {
224
234
  configCatalog: facts.configCatalog(deps).available,
225
235
  sealedKey: projectSealedKeyCapability(deps.sealedKeyPublic),
226
236
  workspaceSync: ((space, cache) => space.available || cache.available ? { ...(space.available ? space.policy : {}), ...(cache.available ? { cache: cache.cache } : {}) } : undefined)(facts.workspaceSpace(deps.config), facts.workspaceCache(deps.config)),
237
+ credentialPlane: { sandboxGit: deps.sandboxGitPlane ?? judgeSandboxGitPlane(sandboxGitPlanePremisesOf(deps.config, {})) },
227
238
  }));
228
239
  return;
229
240
  }
@@ -239,7 +250,7 @@ export async function handleCapabilities(req, res, match, ctx) {
239
250
  return;
240
251
  }
241
252
  const scenarioName = await deps.scenarioGate(principal, scenarioParams[0]);
242
- await serveMcpProbeFace(res, ctx, principal, mcpForScenario(deps.config.mcpServers, scenarioName) ?? [], "deployment");
253
+ await serveMcpProbeFace(res, ctx, principal, { declaredBy: "deployment", specs: mcpForScenario(deps.config.mcpServers, scenarioName) ?? [] });
243
254
  return;
244
255
  }
245
256
  case "capability-mcp-probe": {
@@ -257,7 +268,7 @@ export async function handleCapabilities(req, res, match, ctx) {
257
268
  sendMcpProbeRefusal(res, ctx, parsed.refusal, "bad_request");
258
269
  return;
259
270
  }
260
- await serveMcpProbeFace(res, ctx, principal, parsed.specs, "caller");
271
+ await serveMcpProbeFace(res, ctx, principal, { declaredBy: "caller", drafts: parsed.drafts });
261
272
  return;
262
273
  }
263
274
  case "models": {
@@ -272,6 +283,7 @@ export async function handleCapabilities(req, res, match, ctx) {
272
283
  provider: m.provider,
273
284
  ...(modelReasoningDecl(m) !== undefined ? { reasoning: modelReasoningDecl(m) } : {}),
274
285
  ...(modelImageInput(m) !== "undeclared" ? { vision: modelImageInput(m) === "yes" } : {}),
286
+ supportsThinkingOff: thinkingOffSpelled(m),
275
287
  ...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
276
288
  ...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
277
289
  ...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
@@ -312,18 +324,18 @@ function sendMcpProbeRefusal(res, ctx, refusal, outcome, retryAfterSec) {
312
324
  ...(retryAfterSec !== undefined ? { retryAfterSec } : {}),
313
325
  });
314
326
  }
315
- async function serveMcpProbeFace(res, ctx, principal, specs, declaredBy) {
327
+ async function serveMcpProbeFace(res, ctx, principal, input) {
316
328
  const { deps } = ctx;
317
329
  const local = ctx.local.capabilities.mcpProbe;
318
- if (specs.length === 0) {
330
+ if (countMcpProbeDeclarations(input) === 0) {
319
331
  deps.metrics?.inc("mcp_probe_total", { outcome: "empty" });
320
332
  sendJson(res, 200, buildEmptyMcpProbeFace());
321
333
  return;
322
334
  }
323
- const key = buildMcpProbeCacheKey(principal, specs);
335
+ const key = buildMcpProbeCacheKey(principal, input);
324
336
  const hit = local.cached(key, Date.now());
325
337
  if (hit !== undefined) {
326
- await answerMcpProbe(res, ctx, hit, "cached", declaredBy);
338
+ await answerMcpProbe(res, ctx, hit, "cached", input.declaredBy);
327
339
  return;
328
340
  }
329
341
  if (local.inflight() >= MCP_PROBE_MAX_INFLIGHT) {
@@ -335,9 +347,9 @@ async function serveMcpProbeFace(res, ctx, principal, specs, declaredBy) {
335
347
  sendMcpProbeRefusal(res, ctx, buildMcpProbeRateRefusal(), "rate_limited", verdict.retryAfterSec);
336
348
  return;
337
349
  }
338
- const walk = createMcpProbeWalk(specs, principal);
350
+ const walk = createMcpProbeWalk(input, principal, deps.peerDesk);
339
351
  local.remember(key, Date.now(), walk);
340
- await answerMcpProbe(res, ctx, walk.answer, "probed", declaredBy);
352
+ await answerMcpProbe(res, ctx, walk.answer, "probed", input.declaredBy);
341
353
  }
342
354
  async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
343
355
  const { deps } = ctx;
@@ -25,8 +25,9 @@
25
25
  * `unsupported` 挂 409 更会把「这条 run 没有 MCP 面」谎报成一个活性问题。
26
26
  *
27
27
  * ── 下一步动作按 `status`,不解析 `reason`(core [ref] 键表逐字)────────────────────────────────
28
- * `status.errorCode` / `status.httpStatus` 是机器面(`http_status` 401 是一扇重新授权的门,`spawn_failed` 是
29
- * 缺二进制);`reason` 是**人读**的一句话,经本仓 `redactSecrets` + 定长截断后投出(它可能嵌远端文本),
28
+ * `status.errorCode` / `status.httpStatus` 是机器面(`unauthorized` 是一扇要用户授权的门 —— 引擎 7.59.0 起 401 与带 `insufficient_scope` 的 403 读这个词、不再是
29
+ * `http_status` + 状态数;`spawn_failed` 是
30
+ * 缺二进制);`reason` 是**人读**的一句话(它可能嵌远端文本:引擎铸点抹过请求回显与同主体词表,出门经出口座 `mcp-remote-text` 行 —— 同一个脱敏器、界 200 —— 投出),
30
31
  * 消费端**不许**解析它。名册**按 `tools` 的在场性**投成 `toolNames`(present-iff),**不按 `outcome`**。
31
32
  *
32
33
  * ── 查找与拒绝形(与 steer / capture-optout **同一只**,不新造)───────────────────────────────────
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { isParkedRunStatus, isTerminalRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
3
- import { redactSecrets } from "../../trace/redact.js";
4
3
  import { DeadlineExceeded, MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
5
4
  import { sendJson, sendError } from "../send.js";
6
5
  import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../principal-gate.js";
@@ -8,9 +7,9 @@ import {} from "../route-ctx.js";
8
7
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
9
8
  import * as facts from "../../capability-facts.js";
10
9
  import { sessionOwnerCellOf } from "../../security.js";
10
+ import { seatText } from "../../trace/exit-seat.js";
11
+ import { projectMcpAuthorization } from "../../mcp-authorization-face.js";
11
12
  const BodySchema = z.object({ server: z.string().min(1).max(190) }).strict();
12
- const NEUTRALIZED_TEXT_MAX = 200;
13
- const humanText = (s) => redactSecrets(s).slice(0, NEUTRALIZED_TEXT_MAX);
14
13
  function outcomeOf(coreOutcome) {
15
14
  switch (coreOutcome) {
16
15
  case "reconnected": return "accepted";
@@ -26,8 +25,9 @@ function projectStatus(s) {
26
25
  ...(s.errorCode !== undefined ? { errorCode: s.errorCode } : {}),
27
26
  ...(s.httpStatus !== undefined ? { httpStatus: s.httpStatus } : {}),
28
27
  ...(s.delivered !== undefined ? { delivered: s.delivered } : {}),
28
+ ...((a) => (a !== undefined ? { authorization: a } : {}))(projectMcpAuthorization(s.authorization)),
29
29
  ...(s.serverInfo !== undefined ? { serverInfo: s.serverInfo } : {}),
30
- ...(s.error !== undefined ? { error: humanText(String(s.error)) } : {}),
30
+ ...(s.error !== undefined ? { error: seatText("mcp-remote-text", String(s.error)) } : {}),
31
31
  ...(s.transportClosed !== undefined ? { transportClosed: s.transportClosed } : {}),
32
32
  };
33
33
  }
@@ -36,7 +36,7 @@ function projectListingIncomplete(l) {
36
36
  reason: l.reason,
37
37
  pages: l.pages,
38
38
  ...(l.budgetMs !== undefined ? { budgetMs: l.budgetMs } : {}),
39
- ...(l.error !== undefined ? { error: humanText(l.error) } : {}),
39
+ ...(l.error !== undefined ? { error: seatText("mcp-remote-text", l.error) } : {}),
40
40
  };
41
41
  }
42
42
  function projectResult(r) {
@@ -48,7 +48,7 @@ function projectResult(r) {
48
48
  added: r.added,
49
49
  removed: r.removed,
50
50
  ...(r.tools !== undefined ? { toolNames: r.tools.map((t) => t.name) } : {}),
51
- ...(r.reason !== undefined ? { reason: humanText(r.reason) } : {}),
51
+ ...(r.reason !== undefined ? { reason: seatText("mcp-remote-text", r.reason) } : {}),
52
52
  ...(r.status !== undefined ? { status: projectStatus(r.status) } : {}),
53
53
  ...(r.listingIncomplete !== undefined ? { listingIncomplete: projectListingIncomplete(r.listingIncomplete) } : {}),
54
54
  };
@@ -114,7 +114,7 @@ export async function handleMcpReconnect(req, res, match, ctx) {
114
114
  const msg = e instanceof Error ? e.message : String(e);
115
115
  switch (code) {
116
116
  case "mcp.reconnect_unavailable":
117
- sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason: humanText(msg) });
117
+ sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason: seatText("mcp-remote-text", msg) });
118
118
  return;
119
119
  case "steering.invalid_content":
120
120
  sendError(res, 422, "steering.invalid_content", msg);
@@ -24,7 +24,7 @@
24
24
  * · 调用方显式给 `scope` ⇒ 用它 —— 哪怕它不在 `MEMORY_CONSOLIDATION_SCOPES` 里。
25
25
  * 🔴 那张表**不是授权边界**:本仓今天没有任何授权源能对一个 operator 收窄 scope(`gateMemoryScope`
26
26
  * 的 operator 支在查目录之前就 allow;`org-memory-admission` 明写 v1 不中央收窄 operator 声明的
27
- * scope —— 全文见 `src/memory-operator-faces.ts` 的 `erasureEnvelopeRefusal` 头注)。在本层拿它当
27
+ * scope —— 全文见 `src/memory-operator-faces.ts` `MemoryComplianceFaces.erase` 的「授权座只有一只」段)。在本层拿它当
28
28
  * 白名单就是**发明第二套授权语义**,与 `gateMemoryScope` 对同一个身份给出相反答案;
29
29
  * · 省略 `scope` ⇒ 只有表**恰好一条**时才有缺省(那条就是这台部署的库);零条或两条以上一律 400,
30
30
  * 并把候选列进文案 —— 让运维一眼看到「我该点哪一个」。
@@ -114,7 +114,7 @@ export declare function buildClearanceRowWire(r: OriginClearanceRow): {
114
114
  baseRev: string;
115
115
  origin: {
116
116
  at: number;
117
- cause?: "static" | "observed" | "unattributed" | "derived" | undefined;
117
+ cause?: "static" | "unattributed" | "observed" | "derived" | undefined;
118
118
  taint: "external";
119
119
  };
120
120
  };
@@ -7,7 +7,7 @@ import { createLogger } from "../../observability/logger.js";
7
7
  import { RULE_IMPORT_RETRY_AFTER_SEC, RULE_SCOPE_REFUSAL_SENTENCE, MAX_RULE_SCOPE_CHARS, buildCcImportLayerRootRefusal, parseRuleScope, serializeRuleScope } from "../../rules-consent.js";
8
8
  import { hasControlOrBidi } from "@sema-agent/settings-schema";
9
9
  import { IMPORTED_SETTINGS_LAYERS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, RULE_ADD_ORIGINS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
10
- import { isPersistedRuleTool, isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
10
+ import { isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
11
11
  const logger = createLogger();
12
12
  export const RULES_CC_IMPORT_PREPARE_PATH = "/v1/rules/cc-import/prepare";
13
13
  export const RULES_CC_IMPORT_REDEEM_PATH = "/v1/rules/cc-import/redeem";
@@ -50,9 +50,9 @@ const LocalImportRowSchema = z
50
50
  rule: z.string().min(1).max(MAX_RULE_TEXT_CHARS),
51
51
  scope: z.string().min(1).max(MAX_RULE_SCOPE_CHARS),
52
52
  behavior: z.enum(RULE_BEHAVIORS),
53
- tool: z.string().min(1).max(190).refine(isPersistedRuleTool, { message: "not a tool the persisted-rule grammar speaks for" }),
53
+ tool: z.string().min(1).max(190),
54
54
  match: z.enum(PERSISTED_RULE_MATCHES),
55
- command: z.string().min(1).max(MAX_RULE_TEXT_CHARS),
55
+ command: z.string().max(MAX_RULE_TEXT_CHARS),
56
56
  adds: z.array(LocalImportAddSchema).max(64),
57
57
  })
58
58
  .strict();