@sema-agent/server 7.43.0 → 7.44.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 (345) hide show
  1. package/USAGE.md +18 -0
  2. package/dist/adoption/plan.js +31 -192
  3. package/dist/adoption/quiesce.js +3 -86
  4. package/dist/adoption/runner.js +3 -140
  5. package/dist/adoption/sql.js +0 -74
  6. package/dist/adoption/wire.js +0 -80
  7. package/dist/approval-ask-machine.js +0 -75
  8. package/dist/approval-card.js +0 -323
  9. package/dist/approval-deny-reasons.js +0 -42
  10. package/dist/approval-hmac.js +0 -35
  11. package/dist/approval-reconciler.js +8 -166
  12. package/dist/approval.js +4 -67
  13. package/dist/audit.js +1 -44
  14. package/dist/auth-bridge.js +4 -47
  15. package/dist/auth-keys.js +0 -23
  16. package/dist/bake-runner/main.js +4 -65
  17. package/dist/bake-runner/protocol.js +3 -58
  18. package/dist/bake-runner/runner.js +5 -91
  19. package/dist/bench/l8/artifact.js +2 -61
  20. package/dist/bench/l8/escape.js +0 -25
  21. package/dist/bench/l8/index.js +0 -14
  22. package/dist/bench/l8/probes.js +0 -60
  23. package/dist/bench/l8/run-probes.js +2 -45
  24. package/dist/bench/s1/arms.js +14 -189
  25. package/dist/bench/s1/live-deps.js +11 -253
  26. package/dist/bench/s1/oracle.js +1 -36
  27. package/dist/bench/s1/repair-oracle-adapter.js +0 -30
  28. package/dist/bench/s1/reviewer.js +0 -34
  29. package/dist/bench/s1/row.js +0 -62
  30. package/dist/bench/s1/run-firm.js +4 -70
  31. package/dist/bench/s1/runner-ctx.js +0 -40
  32. package/dist/bench/s1/tasks.js +0 -115
  33. package/dist/boot/adoption.js +0 -20
  34. package/dist/boot/budget-tracing.js +3 -55
  35. package/dist/boot/config-center.js +43 -551
  36. package/dist/boot/coordinators.js +1 -69
  37. package/dist/boot/crash-last.js +0 -18
  38. package/dist/boot/deferred-sandbox-path-env.js +3 -119
  39. package/dist/boot/execution-env.js +5 -171
  40. package/dist/boot/governance-seams.js +0 -92
  41. package/dist/boot/leader.js +0 -69
  42. package/dist/boot/limit-sync.js +0 -2
  43. package/dist/boot/memory-boundary.js +3 -91
  44. package/dist/boot/org-memory.js +1 -25
  45. package/dist/boot/parked-revive-gate.js +0 -150
  46. package/dist/boot/permission-rules-audit.js +1 -56
  47. package/dist/boot/reapers.js +15 -273
  48. package/dist/boot/resolve-spec.js +9 -768
  49. package/dist/boot/retention-lane.js +4 -87
  50. package/dist/boot/runner-deps.js +3 -297
  51. package/dist/boot/runtime-caps.js +0 -40
  52. package/dist/boot/session-faces.js +2 -133
  53. package/dist/boot/shutdown.js +9 -83
  54. package/dist/boot/side-query-lane.js +2 -137
  55. package/dist/boot/stores.js +15 -215
  56. package/dist/boot/task-list-lane.js +0 -18
  57. package/dist/boot/webfetch-summarize-lane.js +0 -47
  58. package/dist/boot/workflow-orchestration.js +3 -99
  59. package/dist/boot-reclaim.js +0 -20
  60. package/dist/bounded-session-map.js +0 -19
  61. package/dist/brain.js +2 -139
  62. package/dist/budget.js +9 -244
  63. package/dist/capabilities/builtin-tools.js +0 -3
  64. package/dist/capabilities/center-plugins.js +6 -51
  65. package/dist/capabilities/center-prompts.js +6 -71
  66. package/dist/capabilities/code-review-council.js +7 -40
  67. package/dist/capabilities/collab-workflows.js +1 -44
  68. package/dist/capabilities/hands-lane.js +0 -65
  69. package/dist/capabilities/memory-notice.js +0 -70
  70. package/dist/capabilities/prompt.js +0 -14
  71. package/dist/capabilities/prompts/code-review.js +0 -14
  72. package/dist/capabilities/prompts/identity.js +0 -6
  73. package/dist/capabilities/prompts/team.js +0 -4
  74. package/dist/capabilities/repo-tools.js +0 -34
  75. package/dist/capabilities/sandbox-file-send.js +3 -92
  76. package/dist/capabilities/scenarios.d.ts +0 -1
  77. package/dist/capabilities/scenarios.js +18 -279
  78. package/dist/capabilities/select-environment-tool.js +0 -32
  79. package/dist/capabilities/send-user-file-tool.js +2 -66
  80. package/dist/capabilities/skills.d.ts +1 -2
  81. package/dist/capabilities/skills.js +3 -21
  82. package/dist/capabilities/team.d.ts +3 -11
  83. package/dist/capabilities/team.js +3 -51
  84. package/dist/capabilities/tool-defer.js +0 -3
  85. package/dist/config-center/apply-effective.js +15 -330
  86. package/dist/config-center/apply-ledger.js +5 -38
  87. package/dist/config-center/facade.js +0 -41
  88. package/dist/config-center/hot-keys-registry.js +0 -20
  89. package/dist/config-center/http-client.js +2 -125
  90. package/dist/config-center/mcp-revocation.js +2 -34
  91. package/dist/config-center/read-face.js +0 -59
  92. package/dist/config-center/restart-signal.js +1 -85
  93. package/dist/config-center/skills-mcp.d.ts +1 -1
  94. package/dist/config-center/skills-mcp.js +9 -76
  95. package/dist/config-center/stage-limits.js +8 -35
  96. package/dist/config-invariants.js +0 -16
  97. package/dist/config-lkg.js +0 -42
  98. package/dist/config-provider.js +3 -186
  99. package/dist/config-types.js +0 -5
  100. package/dist/config.js +107 -1145
  101. package/dist/degenerate-instrument.js +3 -67
  102. package/dist/deployment-governance.js +0 -124
  103. package/dist/digest-form.js +0 -12
  104. package/dist/elicitation.js +3 -86
  105. package/dist/env-facts.js +7 -75
  106. package/dist/fleet/fleet-bus.js +34 -507
  107. package/dist/fleet/fleet-reconciler.js +9 -149
  108. package/dist/fleet/fleet-terminal-window.js +10 -178
  109. package/dist/fleet/subagent-tail-bus.js +3 -72
  110. package/dist/fleet-client.js +10 -70
  111. package/dist/fleet-lease.js +5 -79
  112. package/dist/git-api-kind.js +0 -3
  113. package/dist/governance-ask-marks.js +2 -78
  114. package/dist/hooks/branch-transcript.js +0 -74
  115. package/dist/hooks/cc-agent-hook-prompt.js +0 -29
  116. package/dist/hooks/cc-stop-prompt.js +1 -46
  117. package/dist/hooks/hook-llm.js +1 -53
  118. package/dist/hooks/hook-runner.js +20 -414
  119. package/dist/http/active-run-conflict.js +4 -129
  120. package/dist/http/cursor-fingerprint.d.ts +5 -0
  121. package/dist/http/cursor-fingerprint.js +5 -0
  122. package/dist/http/idempotency.js +0 -37
  123. package/dist/http/principal-gate.js +3 -40
  124. package/dist/http/route-ctx.js +0 -9
  125. package/dist/http/routes/a2a-serve.js +7 -319
  126. package/dist/http/routes/admin-config-refresh.js +0 -4
  127. package/dist/http/routes/admin-drain.js +0 -10
  128. package/dist/http/routes/adoption.js +1 -29
  129. package/dist/http/routes/agents-roster.js +1 -47
  130. package/dist/http/routes/approvals-assistant.js +32 -395
  131. package/dist/http/routes/attachments.js +4 -22
  132. package/dist/http/routes/capabilities.js +3 -420
  133. package/dist/http/routes/diagnostics.js +1 -81
  134. package/dist/http/routes/fleet.js +9 -185
  135. package/dist/http/routes/images.js +14 -239
  136. package/dist/http/routes/leader.js +0 -13
  137. package/dist/http/routes/memory-bundle.js +1 -61
  138. package/dist/http/routes/memory-policy.js +9 -99
  139. package/dist/http/routes/notify-wake.js +3 -37
  140. package/dist/http/routes/observability.js +2 -19
  141. package/dist/http/routes/retention-ops.js +2 -34
  142. package/dist/http/routes/rules.js +1 -93
  143. package/dist/http/routes/runs.js +64 -873
  144. package/dist/http/routes/session-sync.js +19 -258
  145. package/dist/http/routes/sessions-list.js +17 -43
  146. package/dist/http/routes/sessions.js +34 -226
  147. package/dist/http/routes/shared-memory.js +5 -36
  148. package/dist/http/routes/side-query.js +1 -87
  149. package/dist/http/routes/tasks.js +52 -722
  150. package/dist/http/routes/trace-usage.js +32 -195
  151. package/dist/http/routes/workflows.js +19 -195
  152. package/dist/http/run-meta.js +0 -6
  153. package/dist/http/send.js +0 -32
  154. package/dist/http/server.js +92 -1597
  155. package/dist/http/sse-lifecycle.js +2 -13
  156. package/dist/http/sse-log.js +3 -48
  157. package/dist/http/tar.js +5 -21
  158. package/dist/http/verify-rounds.js +0 -5
  159. package/dist/http/wire-gate.js +0 -9
  160. package/dist/http/workspace-content.js +0 -10
  161. package/dist/images/bake-validate.js +1 -70
  162. package/dist/images/manifest.js +1 -6
  163. package/dist/index.js +0 -21
  164. package/dist/key-resolver.js +2 -17
  165. package/dist/leader/diffout.js +1 -20
  166. package/dist/leader/diffup.js +0 -47
  167. package/dist/leader/endpoint.js +2 -57
  168. package/dist/leader/fanout.js +3 -45
  169. package/dist/leader/grader-env-factory.js +3 -72
  170. package/dist/leader/leader.js +5 -156
  171. package/dist/leader/merge.js +8 -115
  172. package/dist/leader/planner.js +3 -54
  173. package/dist/leader/repair-oracle.js +1 -60
  174. package/dist/leader/repair-wire.js +2 -79
  175. package/dist/leader/wire.js +8 -307
  176. package/dist/lsp/e2b-bridge.js +4 -64
  177. package/dist/lsp/e2b-manager.js +6 -94
  178. package/dist/lsp/lsp-frames.js +0 -12
  179. package/dist/lsp/manager.js +4 -96
  180. package/dist/lsp/ws-transport.js +5 -55
  181. package/dist/lsp-evict.js +1 -15
  182. package/dist/main.js +57 -765
  183. package/dist/memory-bundle-engine.js +0 -55
  184. package/dist/memory-export.js +0 -4
  185. package/dist/memory-posture.js +1 -15
  186. package/dist/memory-scope.js +11 -148
  187. package/dist/memory-sync-client.js +2 -44
  188. package/dist/memory-sync.js +1 -80
  189. package/dist/model-select.js +3 -80
  190. package/dist/observability/cost-quota.js +1 -17
  191. package/dist/observability/cost-taxonomy.js +0 -34
  192. package/dist/observability/fail-open.js +7 -86
  193. package/dist/observability/logger.js +0 -6
  194. package/dist/observability/metrics.js +0 -94
  195. package/dist/observability/otel-exporter.js +3 -13
  196. package/dist/observability/principal-context.js +0 -9
  197. package/dist/observability/prompt-manifest.js +1 -37
  198. package/dist/observability/rate-limit.js +0 -4
  199. package/dist/observability/secret-env-scrub.js +2 -56
  200. package/dist/observability/tool-trace.js +1 -70
  201. package/dist/orchestration/hardened-vm-runner.js +4 -118
  202. package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
  203. package/dist/orchestration/hardened-vm-worker.js +0 -27
  204. package/dist/orchestration/subagent-steer.js +1 -45
  205. package/dist/orchestration/workflow-agent-steer.js +1 -80
  206. package/dist/orchestration/workflow-completion-inbox.js +32 -285
  207. package/dist/orchestration/workflow-notify-journal.js +16 -259
  208. package/dist/org-memory-admission.js +3 -47
  209. package/dist/parent-watch.js +2 -48
  210. package/dist/parked-decide.js +1 -109
  211. package/dist/per-task-image.js +0 -57
  212. package/dist/plan-cache-probe.js +3 -27
  213. package/dist/plugins/adoption-log-sql.js +2 -119
  214. package/dist/plugins/approval-ask-store-memory.js +3 -38
  215. package/dist/plugins/approval-ask-store-sql.js +6 -188
  216. package/dist/plugins/approval-exemption-store.js +2 -28
  217. package/dist/plugins/background-agent-store-sql.js +4 -105
  218. package/dist/plugins/background-shell-support.js +14 -122
  219. package/dist/plugins/blob-backend.js +6 -169
  220. package/dist/plugins/breaker-state-sql.js +8 -46
  221. package/dist/plugins/caching-session-store.js +4 -106
  222. package/dist/plugins/checkpoint-store-sql.js +18 -505
  223. package/dist/plugins/e2b-orphan-reclaim.js +0 -45
  224. package/dist/plugins/file-outcome-sink.js +0 -9
  225. package/dist/plugins/file-resume-anchor-store.js +4 -43
  226. package/dist/plugins/file-run-store.js +26 -364
  227. package/dist/plugins/file-snapshot-store-sql.js +10 -181
  228. package/dist/plugins/fork-routing-session-store.js +8 -111
  229. package/dist/plugins/host-platform.js +2 -91
  230. package/dist/plugins/image-bake-store-sql.js +7 -250
  231. package/dist/plugins/image-index-sql.js +4 -123
  232. package/dist/plugins/k8s-bg-scripts.js +4 -88
  233. package/dist/plugins/k8s-exec-protocol.js +0 -41
  234. package/dist/plugins/leader-run-store-sql.js +0 -101
  235. package/dist/plugins/local-checkpoint-store.js +8 -128
  236. package/dist/plugins/local-session-store.js +34 -296
  237. package/dist/plugins/local-task-attachment-store.js +2 -16
  238. package/dist/plugins/mailbox-store-sql.js +8 -65
  239. package/dist/plugins/memory-embedder-fingerprint.js +5 -166
  240. package/dist/plugins/memory-embedder.js +4 -70
  241. package/dist/plugins/memory-engine-pg.js +6 -170
  242. package/dist/plugins/memory-engine-tidb.js +7 -155
  243. package/dist/plugins/memory-engine-vector-util.js +0 -10
  244. package/dist/plugins/memory-key-guards.js +0 -34
  245. package/dist/plugins/memory-origin-law.js +0 -187
  246. package/dist/plugins/memory-resume-anchor-store.js +0 -17
  247. package/dist/plugins/memory-run-store.js +12 -89
  248. package/dist/plugins/memory-session-policy-store.js +0 -17
  249. package/dist/plugins/memory-sync-store-pg.js +4 -49
  250. package/dist/plugins/memory-sync-store-tidb.js +3 -35
  251. package/dist/plugins/outcome-ledger-sql.js +3 -97
  252. package/dist/plugins/permission-rule-store-file.js +5 -133
  253. package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
  254. package/dist/plugins/permission-rule-store-sql.js +50 -307
  255. package/dist/plugins/pg-cost-quota.js +0 -7
  256. package/dist/plugins/pg-pool.js +0 -92
  257. package/dist/plugins/pg-rate-limiter.js +2 -13
  258. package/dist/plugins/pg-safe-json.js +4 -40
  259. package/dist/plugins/pg-session-storage.js +25 -189
  260. package/dist/plugins/posix-shell-fs.js +1 -31
  261. package/dist/plugins/remote-env-adb.js +12 -101
  262. package/dist/plugins/remote-env-e2b.js +40 -371
  263. package/dist/plugins/remote-env-file-error.js +0 -37
  264. package/dist/plugins/remote-env-host.js +63 -483
  265. package/dist/plugins/remote-env-k8s.js +32 -326
  266. package/dist/plugins/remote-env-local-docker.js +24 -157
  267. package/dist/plugins/remote-env-ssh.js +20 -128
  268. package/dist/plugins/remote-scratchpad.js +2 -32
  269. package/dist/plugins/remote-shell.js +1 -32
  270. package/dist/plugins/resume-anchor-store-sql.js +0 -11
  271. package/dist/plugins/retention-lane-store-sql.js +0 -108
  272. package/dist/plugins/retention-store-sql.js +4 -383
  273. package/dist/plugins/roster-store-sql.js +0 -55
  274. package/dist/plugins/run-store-sql.js +14 -251
  275. package/dist/plugins/s3-presign.js +2 -49
  276. package/dist/plugins/scheduler-support.js +3 -80
  277. package/dist/plugins/send-file-ledger.js +4 -53
  278. package/dist/plugins/send-user-file.js +4 -94
  279. package/dist/plugins/session-placement.js +1 -89
  280. package/dist/plugins/session-policy-store-sql.js +3 -81
  281. package/dist/plugins/session-store.js +0 -57
  282. package/dist/plugins/shared-memory-store-sql.js +4 -167
  283. package/dist/plugins/sql-driver.js +0 -17
  284. package/dist/plugins/sql-errors.js +0 -7
  285. package/dist/plugins/sql-escape.js +0 -8
  286. package/dist/plugins/sql-row-helpers.js +0 -25
  287. package/dist/plugins/store-backend.js +42 -222
  288. package/dist/plugins/store-contracts.js +2 -46
  289. package/dist/plugins/task-attachment-store.js +3 -49
  290. package/dist/plugins/task-list-store-sql.js +0 -79
  291. package/dist/plugins/tidb-cost-quota.js +1 -4
  292. package/dist/plugins/tidb-pool.js +1 -207
  293. package/dist/plugins/tidb-rate-limiter.js +3 -9
  294. package/dist/plugins/tidb-session-storage.js +4 -70
  295. package/dist/plugins/tidb-session-store.js +19 -341
  296. package/dist/plugins/tool-result-store-sql.js +4 -179
  297. package/dist/plugins/usage-window-store-sql.js +0 -8
  298. package/dist/plugins/web-search.js +10 -132
  299. package/dist/plugins/workflow-journal-store-sql.js +2 -58
  300. package/dist/plugins/workflow-run-store-sql.js +6 -91
  301. package/dist/plugins/worktree-isolation.js +6 -126
  302. package/dist/plugins/write-behind-counter.js +16 -75
  303. package/dist/principal-jwt.js +5 -60
  304. package/dist/project-memory.js +15 -146
  305. package/dist/prompts-domain-validate.js +1 -51
  306. package/dist/question.js +2 -111
  307. package/dist/resource-suspend.js +0 -18
  308. package/dist/router/route-orchestration.js +0 -77
  309. package/dist/rules-consent.d.ts +44 -5
  310. package/dist/rules-consent.js +75 -215
  311. package/dist/run-local.js +14 -381
  312. package/dist/runs.js +29 -617
  313. package/dist/runtime-caps-resolver.js +6 -132
  314. package/dist/runtime-governance.js +1 -232
  315. package/dist/sandbox-pkg-source.js +0 -37
  316. package/dist/sealed-key.js +3 -68
  317. package/dist/security.js +6 -291
  318. package/dist/session-leaf-bus.js +0 -32
  319. package/dist/session-sync-content.js +1 -69
  320. package/dist/session-sync-kernel.js +3 -60
  321. package/dist/session-sync.js +3 -66
  322. package/dist/session-titler.js +7 -41
  323. package/dist/session-watch.js +9 -73
  324. package/dist/shared-memory-scope-authorizer.js +0 -18
  325. package/dist/sighup-idle.js +1 -12
  326. package/dist/spec-fields.js +4 -143
  327. package/dist/store-live-probe.js +3 -49
  328. package/dist/task-a2a.js +1 -126
  329. package/dist/task-cwd.js +1 -103
  330. package/dist/task-mcp.js +1 -89
  331. package/dist/task-settings.js +10 -300
  332. package/dist/task-workflow.js +8 -75
  333. package/dist/tool-approval.d.ts +28 -1
  334. package/dist/tool-approval.js +70 -1430
  335. package/dist/trace/artifacts.js +5 -20
  336. package/dist/trace/engine-notice-wire.js +6 -138
  337. package/dist/trace/ledger-sink.js +7 -96
  338. package/dist/trace/project.js +4 -448
  339. package/dist/trace/redact.js +9 -77
  340. package/dist/turn-activity.js +1 -27
  341. package/dist/usage-analytics.js +4 -34
  342. package/dist/wall-clock-jump-guard.js +1 -68
  343. package/package.json +3 -3
  344. package/dist/capabilities/scenario-alias.d.ts +0 -27
  345. package/dist/capabilities/scenario-alias.js +0 -61
@@ -8,17 +8,8 @@ import { resolveStreamApprovalGate } from "../../tool-approval.js";
8
8
  import { projectMemoryEngineCapability } from "../../memory-posture.js";
9
9
  import { centerEntitlementSourceWired } from "../../runtime-caps-resolver.js";
10
10
  import { gatedPrincipal } from "../principal-gate.js";
11
- /**
12
- * #270 车2 —— 能力位 `retention` 的**唯一**判据(`{mode, maxAgeDays} | null`)。
13
- *
14
- * 谓词为什么可以只看 config 而不合取"执行器在场"(「说 yes ⟺ 面真能用」的结构性论证):
15
- * `intervalSec > 0` 且没有真执行器的那台**根本起不来** —— `boot/retention-lane.ts` 的
16
- * `assertRetentionLaneWirable` 在 boot 期就拒了(policy 缺 / 执行器缺 / 有店声明 "none" 三条臂,
17
- * 且**不看 locked**)。所以在一个已经在应答 HTTP 的进程里,那个合取式恒真;再写一遍只会让读者以为
18
- * 这里还有第二道门。policy 在场仍显式合取:它是 `maxAgeDays` 那一格的来源。
19
- */
20
11
  function retentionAdvertisement(config) {
21
- const sweep = config.retentionSweep; // 见调用点注:遗留双重断言 config 可能真缺这一格
12
+ const sweep = config.retentionSweep;
22
13
  const policy = config.retentionPolicy;
23
14
  if (sweep === undefined || sweep.intervalSec <= 0 || policy === undefined)
24
15
  return null;
@@ -29,66 +20,29 @@ export async function handleCapabilities(req, res, url, ctx) {
29
20
  await handleCapabilitiesBody(req, res, url, ctx, miss);
30
21
  return !miss.fell;
31
22
  }
32
- /** 路由体 = 从 `server.ts` 的 `handle()` 里**整段剪切**过来的原文(唯一改动:统一去缩进两格)。裸 `return;`
33
- * 的语义原样 =「本域已应答」;走到函数尾才是「没匹配上」,置 `miss.fell` 交回装配器继续下一个域。
34
- * 跨域的东西(deps / 助手 / 单域状态 / 每请求量)一律在首行解构出来,于是下面每一行都逐字不变。 */
35
23
  async function handleCapabilitiesBody(req, res, url, ctx, miss) {
36
24
  const { deps } = ctx;
37
- // E5 定稿:场景详情只读端点——web 专家模式渲染工具面选项+提示词概览。source 语义=selectScenario
38
- // 实际取用的定义(main.ts 组装时 center 条目与 overlay 同判定源盖同名,约定①)。鉴权=与 /v1/capabilities
39
- // 同门(全局 service-credential 门后,config 面非密);未知名 404 typed code(人话归壳/web)。
40
25
  if (req.method === "GET" && url.startsWith("/v1/capabilities/scenarios/")) {
41
26
  const name = url.slice("/v1/capabilities/scenarios/".length).split("?")[0];
42
27
  const detail = deps.scenarioDetails?.[name];
43
28
  if (!detail) {
44
- // [939] 信封统一:本路曾是全站唯一对象形 error(`{error:{code}}`)——SDK toApiError 对它特判过一轮
45
- // TypeError 加固。统一为「字符串 error + 顶层 errorCode」邻位形(cancel/decide 同款),机器判据保留。
46
29
  sendError(res, 404, "scenario_not_found", "scenario not found");
47
30
  return;
48
31
  }
49
32
  sendJson(res, 200, detail);
50
33
  return;
51
34
  }
52
- // Capability discovery: one call tells a consumer which surfaces this worker has,
53
- // instead of probing each verb for a 501. Open set — unknown keys must be ignored by consumers.
54
- // Auth'd like /v1/models (config surface, non-secret). Booleans derive from the SAME deps that gate
55
- // the routes, so this can never drift from actual 501 behavior.
56
35
  if (req.method === "GET" && url === "/v1/capabilities") {
57
- // Deployment bag first, derived booleans LAST: the bag extends the set but can never shadow the
58
- // route-gating truths (a config typo must not make capabilities lie about what 501s).
59
36
  sendJson(res, 200, {
60
37
  ...deps.capabilities,
61
38
  asyncRuns: Boolean(deps.runStore),
62
39
  artifacts: Boolean(deps.runStore),
63
- // TRUE when durable HITL can FIRE = checkpointStore present (DURABLE_APPROVAL=true): it mounts
64
- // AskUserQuestion-suspend + the approval center + resumable checkpoints, independent of whether any
65
- // TOOL is gated (APPROVAL_REQUIRE = the additive F4 layer). ([2354] A-5:legacy 轮询门已退役,
66
- // durable 是唯一门形——本谓词自然成为 approvals 面唯一的挂载条件。)
67
- //
68
- // 🔴 **辖域比名字宽**(2026-08-01,web [C33]③.3 踩出来的):这个谓词同时是 `/v1/assistant/*`
69
- // 整条车道的挂载条件 —— `routes/approvals-assistant.ts` 的分支头逐字是
70
- // `if (deps.checkpointStore && (url.startsWith("/v1/approvals") || url.startsWith("/v1/assistant")))`。
71
- // 所以 **`GET /v1/assistant/tasks`(计划运行/调度视图)也由这个键判**,而不是由 `scheduler`
72
- // (那个键说的是 host 腿的自唤醒 cron 工具,与本视图无关)。
73
- // web 因为按名字猜、用 `scheduler` 判这个面,在 local 部署形上永久渲「不可达」——名字窄、谓词宽
74
- // 就是这么伤人的。键名不改(改名是 wire 破坏性变更),改成把辖域写在这里 + 附录 A,
75
- // 让「says yes ⟺ route works」这句话对**读文档的人**也成立,而不只对写代码的人。
76
40
  approvals: Boolean(deps.checkpointStore),
77
41
  sessions: Boolean(deps.sessionAudit),
78
- // [1196] session 级 SSE 订阅面:与 /v1/sessions/:id/events 的 501 谓词同源(sessionWatch 只在
79
- // sessionStorage 具备 getLeafId/ownerOf 时由 main.ts 构建)。[2373]A-5:截至 2026-08-02 无消费端接线
80
- // (web 未按此换轨)——本位是预备位;「web 据此换轨」是当年的预期,不是已核实的现状。
81
42
  sessionEvents: Boolean(deps.sessionWatch && deps.sessionStorage?.getLeafId && deps.sessionStorage?.ownerOf),
82
- // #13([1871] web asks,clay 排批 2026-07-27):fleet 面能力族——一个诚实对象或 false(无 fleetBus=
83
- // 无 /v1/fleet/stream,路由 501 同谓词)。`resume:"snapshot"` 是刻意的语义广告而非搪塞:总线是
84
- // latest-state 不是事件日志,**每次连接开头就是全量 snapshot 帧** ⇒ 重连=重快照,行状态不存在
85
- // 「丢帧」;通知帧(bg_notification)另有 durable inbox 兜底重投。做 last-event-id 重放缓冲=与
86
- // snapshot 机制重复建设,收益为零(SDK streamFleet 的「NOT RESUMABLE」旧自述按此口径改写)。
87
- // `steerPriority:"advisory"` 诚实:steer body.priority 收下+枚举校验但 no-op(E15,候 core 队列 seam)。
88
43
  fleet: deps.fleetBus
89
44
  ? { stream: true, sessionScope: true, observe: true, resume: "snapshot", bgNotifyFailClosed: true, steerPriority: "advisory" }
90
45
  : false,
91
- // #3 workspace 浏览面([1894]④:与 fleet 同姿势——对象=面在场,false=501 同谓词)。
92
46
  workspace: (() => {
93
47
  const wfs = deps.fileSnapshotStore;
94
48
  return wfs && typeof wfs.listKeys === "function" && typeof wfs.exportManifest === "function" && typeof wfs.getBlob === "function" && Boolean(deps.sessionStorage?.ownerOf)
@@ -96,444 +50,88 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
96
50
  : false;
97
51
  })(),
98
52
  leader: Boolean(deps.leaderEndpoint),
99
- // #F1([3397]-5 同族):sandbox-image-pool 的 P1 面(`GET /v1/images`、`/v1/images/:profile`、
100
- // `/v1/images/digests/:digest`、`POST /v1/images/select`)。谓词**逐字**是 routes/images.ts 里那条
101
- // 挂载合取式的 `deps.imageIndex` —— 缺席时该域整个不挂载,同文件的能力臂回 501
102
- // `capability.image_index_required`(此前是与拼错路由同码的 404,消费端只能 trial-by-404)。
103
- // local 后端刻意不实现 `imageIndex()`(池是 cloud/fleet-only),所以单机形上这一位诚实为 false。
104
- // ⚠️ 辖域**只到 P1**:`/v1/images/bakes*`(P2 烤制控制面)由独立的 `imageBakes` 依赖挂载,
105
- // 且是 operator/runner 内部面,不在本位的承诺里。
106
53
  images: Boolean(deps.imageIndex),
107
- // design/138 S1 (clay 2026-07-08): the legacy MemoryStore surface (GET/DELETE /v1/memory + the MF-30
108
- // session write verbs) was DEPRECATED with the store itself — the new memory engine is model file skills
109
- // over the injected memory dir, with NO service HTTP verbs. Hard-coded false so a shell that still knows
110
- // the old caps honestly hides the affordances (the adaptation was pre-announced).
111
54
  memory: false,
112
55
  memoryWrite: false,
113
- // #252 件3(黑板 [3921] cli 记忆 UX 的读面前置):记忆**引擎**位 —— 对象 = 本部署的记忆面真点亮
114
- // (`backend` 形 + `vectorMode` 检索档),`false` = 暗。判据**逐字**是 boot 的 `memoryPosture`
115
- // (boot/stores.ts 的单一推导点)的窄投影,与 operator 诊断面 `GET /v1/diagnostics/wiring` 的
116
- // `memoryPosture` 段同源 —— 「诊断页说亮、能力位说暗」结构上不可能。
117
- // ⚠️ 与上面两个 legacy 位**不是**一回事:`memory`/`memoryWrite` 说的是退役的 MemoryStore HTTP 动词
118
- // (恒假,且会一直恒假);本位说的是引擎接线,它没有 HTTP 动词面 —— 记忆是模型在注入目录上的文件
119
- // 技能。所以本位为真**不**意味着有记忆的读写端点可打(那正是 legacy 两位在否认的东西)。
120
- // `vectorMode: null` = 这条腿没有档位指示面(file 引擎),不是「档位是词面」。
121
56
  memoryEngine: projectMemoryEngineCapability(deps.memoryPosture),
122
- // [3928]/[3929]/[3931](clay 准并入 #252 车窗):**远端车道可 detach**。零新机制 —— 说的就是本仓
123
- // 早已有的那条腿:`POST /v1/tasks/stream` 带请求头 `x-detach-on-disconnect: true` ⇒ 客户端断连**不杀**
124
- // run,它在 server 跑完;回来按响应头 `X-Task-Id` 走 `GET /v1/runs/:id` 与 `/events`(durable 事件日志
125
- // 重放 + `Last-Event-ID` 续流)拿全离开期间的帧。
126
- //
127
- // 谓词 = **部署半场**:`deps.runStore` —— 逐字就是那条腿自己的前置判据(`routes/tasks.ts` 的
128
- // `earlyDurableTid = deps.runStore && prepared.spec.sessionId`,缺则 400 `request.precondition_unmet`
129
- // 「detached 的结果无处可查」)。**per-request 半场(调用方必须带 sessionId)不在本位里**:那是每次
130
- // 调用自己的事,部署级布尔对它说不了话 —— 本位说的是「这台 worker 支不支持」。
131
- // 今天它与 `asyncRuns` 取值相同,这是诚实记账而不是冗余:那一位问「异步 run API 在不在」,本位问
132
- // 「壳的转后台键在远端车道该不该映射成 detach」(与 `workflows`/`workflowsList` 同族先例)。
133
- // ⚠️ **辖域只到远端车道**([3929] 精确化 1):本地车道的转后台归壳自己的判据,本位不覆盖、也不许被
134
- // 拿去禁本地(本地转后台今天是好的)。
135
- // ⚠️ **不承诺** detach 期间流内审批的存活:那条(优雅断连 ⇒ 转 durable park,#241)是另一根轴,由
136
- // `approvals` / `streamApproval` 两位各自广告 —— 本位为真而它们为假的部署上,detach 照常工作,
137
- // 只是断连那一刻挂起的审批走 core 的 fail-closed 臂。
138
57
  sessionBackgroundable: Boolean(deps.runStore),
139
- // design/177 —— org 共享记忆库只读面。判据**逐字**等于 server.ts 里那个域的挂载合取式(供给面 ∧
140
- // org 折叠面),所以"说 yes ⟺ 面真能用"是结构性的:少一个,域不挂载、这里也翻假,消费方看到的
141
- // 与它真能打通的永远一致。折叠面缺席时刻意不报 true —— 一个没有成员性判据的共享读面比没有更糟。
142
58
  sharedMemory: Boolean(deps.sharedMemoryStore && deps.orgMemoryDirectory),
143
- // design/183 form b:收编面(operator lane)。谓词 = **两项合取**,逐项对着 handleAdoption 的
144
- // 拒绝臂写:①`adoptionLog` 工厂在场(local backend 刻意不实现——单用户数据根没有多租身份轴可
145
- // 重绑)⇒ 否则 501;②operator 名单**非空** ⇒ 否则 `explicitOperatorOk` 对任何身份都返回 false,
146
- // 那条路由**恒 403**。
147
- // 🔴 第二项是 [3397]-4(黑板 cli 审计)逮到的真缺口:旧谓词只查 ① ⇒ 「装了 SQL 后端但没配
148
- // OPERATOR_PRINCIPALS」的部署位报 true、路由恒 403 —— 本仓「says yes ⟺ route works」被实测证否。
149
- // 空名单在这条轴上**刻意**不走 `isOperator` 的「人人都是 operator」旧义(那是一道世界可写的门,
150
- // 见 principal-gate.ts 的 `explicitOperatorOk` 头注),所以补的是能力位、不是放宽授权。
151
59
  adoption: Boolean(deps.backend?.adoptionLog) && deps.config.operatorPrincipals.length > 0,
152
- // #264 v2-c:治理携出 bundle 两口(`POST /v1/memory/{export,import}`,operator lane)。谓词**逐项**
153
- // 对着 routes/memory-bundle.ts 的拒绝臂写,与 adoption 同族两项合取:
154
- // ①引擎两面都接线(`memoryBundle{Export,Import}`;记忆引擎没接线的部署 ⇒ 501);
155
- // ②operator 名单**非空** —— 否则 `explicitOperatorOk` 对任何身份恒假,两口**恒 403**
156
- // ([3397]-4 逮到的那条真缺口,adoption 同病,这里从第一天就带上)。
157
- // ⚠️ 位为真**只**保证「门能过 + 引擎在场」,不保证这台部署的记忆后端真有 bundle 复合面:本仓两只
158
- // SQL 记忆孪生没实现 `exportSnapshotOf`/`importBundleCommit`,那时 core 自己响亮拒
159
- // (`memory.export_incomplete`)。刻意不把「后端有没有复合面」编进本位:那是一次**运行期**能力探测
160
- // (要真打一次店面才知道),把它做成部署级布尔就会变成一个会撒谎的位 —— 诚实的边界写在这里,
161
- // 而不是让位去猜。消费方按码分支(附录 A 已收录该码),不是 trial-by-501。
162
60
  memoryBundle: Boolean(deps.memoryBundleExport && deps.memoryBundleImport) && deps.config.operatorPrincipals.length > 0,
163
- // [3397]-5:`GET /v1/outcomes`(design/73 §7.2 机械信号只读聚合)。此前**有 501 拒而无能力位** ——
164
- // 消费端只能 trial-by-501,与本仓「gate-don't-trial-by-501」的姿势相反。谓词逐项对着该路由的
165
- // 拒绝臂:①可查询的账面在场(`outcomeSink.summary`;File sink 只写 JSONL,没有查询面 ⇒ 501);
166
- // ②多租户下 operator 名单非空(单用户形无此门 —— 唯一的用户就是 operator,路由那侧的
167
- // `if (deps.config.requirePrincipal)` 逐字如此)。②与 adoption 是**同一族**缺口,同批一起补。
168
61
  outcomeLedger: Boolean(deps.outcomeSink?.summary) && (deps.config.requirePrincipal !== true || deps.config.operatorPrincipals.length > 0),
169
- // #154 车二 + #203 §2:规则车道(cc-import 两口 + 撤销面两口 + respond 的 persistRule 兑付口)。
170
- // 谓词与 `/v1/rules/*` 全族的 501 同源:ruleConsent lane 在场 ⟺ 总开关未被显式关 ∧ 规则店 wired
171
- // (SQL 双方言,或 #203 起 local 的 File 三面束)。说 yes ⟺ **四口都活**,不是「有一口活」。
172
- //
173
- // 🔴 A-010.20(验真后修,补第二条合取项):店在场**不等于**这四口活。规则车道是
174
- // **principal 寻址**的 —— `routes/rules.ts` 的域头逐字是 `if (principal === undefined) 401`
175
- // (无条件,与 `requirePrincipal` 无关),而铸卡侧 `buildRuleLaneMaterial` 与回决侧
176
- // `persistRuleAfterDecision` 都有同源的 `owner === null ⇒ 不进车道 / rule_lane_unavailable` 一门。
177
- // 于是「装了店、但调用方没有可验证身份」的部署上,旧谓词报 true 而**四口全废**:两口恒 401、
178
- // 卡上恒无候选、`persistRule` 恒被拒。#203 给 local 车道接上 File 店之后,「单机 + 无 principal」
179
- // 第一次同时满足其余条件 —— 这不再是纸面形。
180
- //
181
- // 🔴 为什么这一位是**按调用方**算而不是按部署算:`requirePrincipal=false` 的部署上,带 principal
182
- // 的调用方与不带的调用方**答案真的不同**(前者四口全活,后者全废),没有任何一个部署级布尔能同时
183
- // 对两者不说谎。`/v1/capabilities` 是每请求读面且与 `/v1/rules` 走同一道全局凭证门,所以
184
- // 「这一位说 yes」⟺「**你**拿同一份头去打那四口真的能用」——这正是本文件顶注承诺的那条等价。
185
- // ⚠️ 与下面的 `permissionRulesRevoke` **刻意不同源**:那一位是**存在性/版本**信号(见其注),
186
- // 必须与调用方身份无关,否则老版本探测会把「我没带 principal」误读成「这个 worker 太老」。
187
62
  permissionRules: Boolean(deps.ruleConsent) && gatedPrincipal(req, deps.config) !== undefined,
188
- // #205 SDK 车上游请托二连(2026-08-10):
189
- // · `permissionRulesRevoke` —— 撤销面两口(GET/DELETE /v1/rules)**存在性**的独立信号。谓词与
190
- // `permissionRules` 同源,但**在场性**本身就是版本信号:≤7.11.0 的 worker `permissionRules` 已为
191
- // true 而这两口 404(位早于路由),消费端无从区分「面没开」与「版本太老」——本位缺席 = 老版本,
192
- // 探 404 即可;在场 = 路由已铸。不折进 `permissionRules`:那个位的成文语义(「四口都活」)在
193
- // ≤7.11.0 的已发布包上已经是谎,只能加位不能改位。
194
63
  permissionRulesRevoke: Boolean(deps.ruleConsent),
195
- // · `oneShot` —— server 消费 `TaskRequest.oneShot`(缺席不写透传 + 非 boolean 400)。旧 server 对
196
- // 未知键静默容忍 ⇒ 调用方声明了一次性形却拿不到 core 的 block-wait 指引而不自知;本位在场 = 键
197
- // 真被消费。恒 true(消费不依赖任何可选设施)。
64
+ respondFreeFormRules: true,
198
65
  oneShot: true,
199
- // CLI surfaces: /v1/policy is always served (config surface); /v1/usage returns real
200
- // cumulative spend only when a per-principal quota is configured (else enabled:false).
201
66
  policy: true,
202
67
  usage: Boolean(deps.costQuota),
203
- // E5 (shell-host contract): permission-mode WRITE is not a cloud-worker capability. Autonomy is
204
- // compile-time tighten-only + worker-global config (a cloud supervisor shell CANNOT change server-side
205
- // gating, ~L2075; "autonomy is CONFIG, not steer", core checkpoint-store.ts:513). The READ side is served
206
- // honestly via GET /v1/policy (PolicyInfo.autonomy). A runtime per-session mutation verb + mode_changed push
207
- // need a core seam (SERVICE-GAP-DOSSIER §2 row 5) — advertise false so the shell keeps a read-only mode
208
- // banner instead of a 501-able write affordance ("says yes but 501s" must be impossible).
209
68
  permissionModeWrite: false,
210
- // E7 (shell-host contract): model selection (body.model) + reasoning-effort selection
211
- // (body.reasoningEffort→TaskSpec.thinking) are accepted on every task request → both true.
212
- // 🔴 CORRECTION (2026-07-25, blackboard [1664]→[1668]): this used to say "the RESOLVED effectiveModel ECHO
213
- // is a separate, still-core-blocked cap (SERVICE-GAP-DOSSIER §2 row 7)". THAT WAS WRONG, and it was wrong in
214
- // an instructive way — the capability exists, it just isn't SPELLED `effectiveModel`. core's `TaskResult.model`
215
- // (core `src/core/types.ts:1871`, design/99 MF-25) is documented verbatim as "the EFFECTIVE model id that
216
- // served this task — the RESOLVED `Model.id`, not the requested `TaskSpec.model` ref … Lets a UI echo
217
- // 'served by X'". A grep for the identifier `effectiveModel` returns zero hits in core and that was mistaken
218
- // for "core doesn't have it" (search by SEMANTICS, not by identifier name). It already reaches the wire:
219
- // `POST /v1/tasks` returns the TaskResult verbatim (`routes/tasks.ts` `sendSubmitResult` — the sync submit
220
- // leg's one response mouth; design/158 A9 moved the whole sync-submit surface OUT of `http/server.ts`, so the
221
- // old `~L1852` anchor into that file is dead), the SDK declares `TaskResult.model`, and this server already
222
- // consumes the resolved id internally for cache-family accounting (`budget.ts` `cacheFamilyOfMirror` + its
223
- // caller in `routes/side-query.ts`, NOT `http/server.ts`). Pinned by
224
- // `test/effective-model-echo-wire.test.ts` (real HTTP: resolved id echoed, absent key stays absent) so a
225
- // future projection/whitelist on this leg can't silently drop it — the `toolEndEventData`-label bug class.
226
- // Nothing is advertised as a capability BIT here because an additive result field needs no gate
227
- // (gate-don't-trial-by-501 governs endpoints/verbs, not additive response fields).
228
69
  modelSelection: true,
229
70
  effortSelection: true,
230
- // E1 (shell-host contract): tool_end now carries the model-facing `output` (core 1.121.0) — wired onto the durable +
231
- // live + replay streams (redacted at every boundary). E2: content events carry `eventId` (+ `parentToolCallId`
232
- // for sub-agent tasks). Both true now that the pinned core emits them and the service threads them through.
233
71
  toolOutput: true,
234
72
  messageIdentity: true,
235
- // C1/C2 (core 1.219): `forwardSubagentEvents` = body flag accepted (a delegated child's live
236
- // content events ride the run stream, parentToolCallId-attributed); `subagentSteer` = the
237
- // POST /v1/runs/:id/subagents/:target/steer verb routes (requires the run store the route 501s without —
238
- // same derive-from-deps discipline as the rest of this block; the registry itself is always constructed).
239
73
  forwardSubagentEvents: true,
240
- // G3([820]③):TaskRequest.scratchpadDir 壳供半场已接(env-facts.acceptShellScratchpadDir 验收门;
241
- // 单用户 + host lane 生效,拒收形回落自算)。TRUE=键会被消费(而非静默丢),不是「必然生效」。
242
74
  scratchpadDir: true,
243
75
  subagentSteer: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
244
- // design/122 (core 1.225): body.retainSubagentSessions accepted + POST /v1/runs/:id/subagents/:target/resume
245
- // routes (same gate as steer — the verbs share the registry + run store; retain-off runs 409 resume.retain_off).
246
76
  subagentResume: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
247
- // TaskRequest.settings (client per-request SemaSettings stamp) → projected into the engine TIGHTEN-ONLY
248
- // (deny-wins, after the deployment + operator baseline). v1 wires permissions + permissionMode + model +
249
- // outputStyle.
250
- // 🔴 保鲜(design/201 施工期自查):旧文「`bypassPermissions` is NEVER honored from settings」是
251
- // **pre-[816] 拍照,已作废** —— `parseTaskSettings` 自 [816]/[820] 起白名单收**五**模式,bundle 形的
252
- // bypass 与顶层键同权(两者的优先序由 `effectivePermissionMode` 单点裁定)。语义不是「开门」而是
253
- // 「不加模式派生的那道门」:部署/运维基线在此之外合成,settings 掀不掉(tightenTaskSpec deny-wins)。
254
- // 留着那句过期的否定句比留个欠账更伤:消费方会据此以为 bundle 形 bypass 无效而改用别的写法。
255
- // `env`([2400] X-8):与真消费点同谓词——resolve-spec 的 setSessionShellEnv 只在 cwdHonored
256
- // (单用户 host lane)注入 shell env;其余 lane 收到即警告忽略。此前硬编码 false 是「TaskSpec 无
257
- // per-task env 注入」时代的陈旧断言(R-survey shellEnv seam 落地后失真=说没有但其实有,活能力被藏)。
258
- // `hooks`(hook-runner 阶段一):TRUE 当本部署会真跑 hook 命令 = 单用户闸(hook 命令跑在
259
- // worker host,class ② 能力授予;resolveSpec 的 taskHooks 装配同一谓词)。多租户 = false(收到警告忽略)。
260
77
  taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config), hooks: deps.config.requirePrincipal !== true },
261
- // design/201 §3 前提②:显式 `permissionMode` 会被翻译成 `spec.shellGate` 档
262
- // (bypassPermissions ⇒ off,auto/default/acceptEdits/plan ⇒ classify;表态缺席 ⇒ 不写键)。
263
- // **恒 true 且与翻译表同一个 commit** —— 这一位不是"配置在不在",而是"这份二进制里有没有那张表",
264
- // 所以 says yes ⟺ 翻译真在,是结构性的(某个 deps 缺席不会让它变假)。
265
- // 消费半场:壳(cli #223)据此撤掉它对 `MANUAL_MODE_SHELL_GATE` 的无条件注入。判据必须是
266
- // **所连 server 广告本位**,不是壳自身版本 —— 新壳连老 server / 回滚到旧二进制的副本 / 混版 fleet
267
- // 三形下,壳看见本位缺席就继续注 env,于是"翻译还没到货但壳已经撤注"那个放宽窗结构上不存在。
268
78
  modeShellGateTranslation: true,
269
- // #A5([4147] 件2;[4074] DELIVERY A5「auto dark 武装可见性」):`permissionMode:"auto"` 的**缺省态**
270
- // 披露。自查结论(施工期亲读 core dist + 本仓装配):
271
- // · 收词是真的 —— 提交面按五词闭集 400,`shellGateForMode("auto")==="classify"`,而
272
- // `deriveSettingsPolicy` 的 auto 与 default 走**同一条臂**(同一只 fs-write ask 门)。
273
- // · 真正让 auto ≠ default 的是 core 的 auto 分类器,而它**两半才武装**:per-principal
274
- // `runtimeCaps.autoMode === true`(center 解出的 entitlement)∧ `RunnerDeps.autoMode` 席位在场。
275
- // · 席位这一半在**服务端装配**里无条件挂(`boot/runner-deps.ts` 的 `createRunnerDeps` —— 那是唯一
276
- // 会去 serve 本能力面的装配路径;run-local 的一次性 CLI 不挂它,但它也不发这张表,所以本位不说谎);
277
- // entitlement 那一半只有在配了 center 且
278
- // 非 dry-run 时才可能存在 ⇒ **缺省态是暗的**,而此前 wire 上一个字都没有(taskSettings.permissionMode
279
- // 只说「键被消费」;core 的 WiringManifest 没有 autoMode 段,诊断面也不报;而诊断面还是 operator-only)。
280
- // 🔴 三项不合成一个布尔:合成后「这份二进制不认识 auto」与「认识但本机没有 entitlement 源」会得到
281
- // 同一个 false,而壳对这两种要做的事不同(前者别给这一档;后者给,但别宣称在筛)。
282
- // 🔴 `entitlementSource` 只说**源在不在**,绝不冒充「你被授权了」——授权是 per-principal 的,部署级
283
- // 布尔对它说不了话(与 `permissionRules` 那一位刻意相反的方向,见其注)。谓词与 boot 的 caps 客户端
284
- // 装配点**同一只函数**,两面不可能分家。
285
79
  permissionModeAuto: {
286
80
  accepted: true,
287
81
  classifierSeat: true,
288
82
  entitlementSource: centerEntitlementSourceWired(deps.config),
289
83
  },
290
- // #A4([4147] 件1):READ 容纳面的**生效档**披露位。值 = 本部署**显式**表态的那一档
291
- // (env `READ_FACE`,或 config-center 的 `readFace.face` —— 两条腿落的是同一个 config 键,
292
- // 所以这一位对「组织下发」与「本机 env」不做区分,它说的就是最终生效值)。
293
- // 🔴 `null` = **本部署没有钉这一档**,由引擎默认接管。刻意不把 `null` 折成 `"roots"`:server 在
294
- // 这条轴上从不复制上游默认(config-types.ts `readFace` 的「缺席=不铸」同一句),把引擎默认抄进 wire
295
- // 会在 core 改默认的那天变成一句谎,而消费端无从察觉。
296
- // 🔴 **最小披露**:deny 表(pattern 表 / 内建档位 / 排除行名)**不上**能力面 —— 那是策略内容,
297
- // 与 governance 段同判(能力面回答「这台机器的 READ 面是什么姿态」,不回答「它具体挡了哪些路径」)。
298
- // 定界:core 的 `WiringManifest`(GET /v1/diagnostics/wiring 的 `static` 段)**没有** READ-face 段,
299
- // 诊断面也从不报它 —— 本位不是复制既有披露,是这条轴上第一次有可读面;且诊断面是 operator-only,
300
- // 壳读不到,所以这一位必须在能力面上。
301
84
  readFace: deps.config.readFace ?? null,
302
- // [1476] R1 / [1478] R2: TaskRequest.appendSystemPrompt is accepted top-level → TaskSpec.appendSystemPrompt
303
- // (first-class lane for the shell's product-knowledge block). A shell probes THIS flag: false/absent ⇒ fall
304
- // back to the settings.outputStyle ride-along (older servers fold that into the same spec field).
305
85
  appendSystemPrompt: true,
306
- // [1479]① TaskRequest.compactionModel → TaskSpec.compactionModel (design/145 cheap compaction gear;
307
- // catalog-gated like body.model). Probe this before offering the picker — older servers drop the field.
308
86
  compactionModel: true,
309
- // [1488]③(b): GET /v1/runs/:id/subagents/:handle/output — a BACKGROUND child's (a… agent handle) final
310
- // report body + status via the core TaskRegistry (the TaskOutput-tool face over HTTP; bg children are
311
- // never in the run store and bg_notification only carries a summary). background_agent ONLY (codex R1
312
- // type gate — wa… workflow rows read via the workflow journal). Replica-local like steer.
313
87
  subagentOutput: Boolean(deps.subagentTaskOutput) && Boolean(deps.runStore),
314
- // S2([1520]{core},server 1.251): GET /v1/runs/:id/subagents/:handle/stream — per-agent live tail
315
- // (SSE;core 1.370 bgAgentId 路由键)。「replay+tail」的 tail 半场(replay=subagentOutput 面);
316
- // live 帧 replica-local(帧只在宿主 run 所在副本产生),meta 帧如实声明。同门同寻址同 404 形。
317
88
  subagentStream: Boolean(deps.subagentTaskOutput) && Boolean(deps.runStore),
318
- // [1499] CC TaskOutput/TaskStop 人侧对位: GET/POST /v1/runs/:id/tasks/:handle/{output,stop} — the
319
- // GENERIC background task-handle verbs (b* bash stdout consuming the cursor, m* monitor batches, a*
320
- // agent final report; workflow handles refused — journal face owns them). SESSION-enforced from birth
321
- // (?session= required on a session-bound run). Replica-local like subagentOutput.
322
89
  taskHandles: Boolean(deps.taskHandleOutput) && Boolean(deps.taskHandleStop) && Boolean(deps.runStore),
323
- // [876] per-task subagents (core 1.295 body.agents → TaskSpec.agents): honored on SINGLE-USER deployments
324
- // only — multi-tenant has no per-tenant caps face yet, so it's fail-closed there (resolveSpec warns +
325
- // ignores; same predicate as mcpInjection/hooks so the shell never pretends its agent bundle took effect).
326
- // ⚠️ Semantics = "the HTTP face accepts + forwards the field", NOT "every scenario honors it": scenarios
327
- // without a delegation tool (scan/oa/…) fail-loud in core prepare (`config.agents.no_delegation_tool`) —
328
- // a per-scenario projection needs the capability face to know the requested scenario (it doesn't; next batch).
329
90
  taskAgents: deps.config.requirePrincipal !== true,
330
- // [854]② body.retainBackgroundProcesses → TaskSpec.retainBackgroundProcesses: a resource-residency grant
331
- // (task-end keeps session bg processes alive), single-user gate like backgroundShell/hooks — multi-tenant
332
- // warns + ignores, advertised false here so the shell greys the affordance.
333
- // ⚠️ Best-effort per env lifecycle: on an isolated env destroyed at task end (e2b/k8s/local-docker/ephemeral
334
- // host) core skips retention (`ownedEnvDying`, dist-read) — the grant only means anything where the env outlives the task.
335
91
  retainBackgroundProcesses: deps.config.requirePrincipal !== true,
336
- // [922]①/[915]② core 1.296 interactiveTools 三态旋钮经 body 透传(per-run 工具面选择,无租户门)——
337
- // 壳 capability 探测门用(旧 server 剥字段,壳 fail-soft 白发;此旗=真转发)。
338
92
  interactiveTools: true,
339
- // [#40 / TOC cwd seam] TRUE when this deployment HONORS a caller-supplied `cwd` (the agent's host workspace =
340
- // the TOC launch dir) — only the single-user `host` lane (task-cwd.ts cwdHonored). FALSE on cloud/container
341
- // lanes + multi-tenant (cwd ignored there) so the shell never pretends `sema` operates on the project dir.
342
- // Also gates `body.additionalDirectories` (CC --add-dir, design/119) — SAME host-lane trust boundary (extra
343
- // host paths the file tools may read), so one flag covers both project-context host seams (no fragmentation).
344
93
  projectContext: cwdHonored(deps.config),
345
- // [R3 / TOC MCP seam] TRUE when this deployment HONORS a caller-supplied `mcpServers` (the TOC local
346
- // `.mcp.json`) — any SINGLE-USER deployment (task-mcp.ts mcpInjectionHonored = `requirePrincipal!==true`), on
347
- // ANY execution lane. FALSE on multi-tenant (per-request MCP ignored) so the shell never pretends its `.mcp.json` took effect.
348
94
  mcpInjection: mcpInjectionHonored(deps.config),
349
- // [DESIGN-269 车1 件4] A2A client seam, two bits with deliberately DIFFERENT predicates (they answer
350
- // different questions — one bit could not be honest about both):
351
- // · `a2a` = the READ face `GET /v1/sessions/:id/a2a` exists. Unconditional, exactly like `mcp`: with
352
- // no peers configured it returns an honest empty panel, so there is no 501 path to gate on.
353
- // · `a2aInjection` = this deployment HONORS a caller-supplied `body.a2aPeers`. Three vetoes, all owned
354
- // by `task-a2a.ts a2aInjectionHonored` (single-user ∧ `a2a` unlocked ∧ compliance permits) — false
355
- // means the request still 200s and the field is warned+ignored (「字段门」形, 附录 B 判据 3②),
356
- // EXCEPT under a lock, where the submit refuses 400 `config.locked_key` (the lock veto is what keeps
357
- // "says yes ⟺ route works" true in that shape).
358
95
  a2a: true,
359
96
  a2aInjection: a2aInjectionHonored(deps.config),
360
- // [DESIGN-269 车2] server-as-peer 半场的**旋钮实况**:这台 worker 是否作为一个 A2A agent 对外
361
- // 存在。true ⟺ `A2A_SERVE_ENABLED` 开 ⟺ `GET /.well-known/agent-card.json` 与 `POST /v1/a2a`
362
- // 两条路由存在;false ⟺ 两条都 404(设计稿 §3.3「卡都不发=对外不存在」)。缺席即关,所以
363
- // 「说 yes ⟺ 路由在」是结构性的,不靠人盯。
364
- // ⚠️ 辖域说明:本位说的是**路由在不在**,不是「每个方法都能跑」——`message/send` / `tasks/get`
365
- // 还需要 durable run store(缺它时两个方法回具名 JSON-RPC -32004,不是静默降级)。把 runStore
366
- // 折进本位会让「卡还在发、位却是 false」这种更糟的谎出现。
367
97
  a2aServe: deps.config.a2aServe !== undefined,
368
- // E8 (shell-host contract): per-model usage echo on TaskStats.modelUsage — sourced from durable model_usage events,
369
- // so it requires BOTH the durable run store AND the tracker that feeds them (a store-without-
370
- // tracker deploy would otherwise lie). Absent either → the shell shows aggregate cost only.
371
98
  modelUsage: Boolean(deps.runStore && deps.modelUsage),
372
- // E11 (shell-host contract): GET /v1/sessions/:id/init startup bundle. Pure config assembly (model+mode), always
373
- // served (no 501 path) — safe unconditionally, like policy:true.
374
99
  sessionInit: true,
375
- // E9 (shell-host contract): GET /v1/sessions/:id/mcp materializes MCP server status on demand. The route is always
376
- // served (returns an empty panel when no MCP is configured), so the query capability is unconditional.
377
100
  mcp: true,
378
- // E23 (shell-host contract): inbound MCP elicitation HITL — true ONLY when the onElicit producing path is wired
379
- // (MCP_ELICITATION_ENABLED), so "says yes but no-ops" is impossible. Per-server opt-in (McpServerSpec.
380
- // elicitation, default OFF) is the second, orthogonal gate; this flag advertises the deployment capability.
381
- // SCOPE: elicitation fires only on the streaming + durable run legs (POST /v1/tasks/stream, POST /v1/runs,
382
- // and a durable resume) — a synchronous POST /v1/tasks, a verify/cascade attempt, and leader sub-tasks have
383
- // no live stream to surface a prompt on, so an elicitation there fail-closed DECLINES (honest, not a hang).
384
101
  mcpElicitation: Boolean(deps.elicitation),
385
- // §4④: AskUserQuestion LIVE HITL — true ONLY when the onQuestion producing path is wired
386
- // (ASK_QUESTION_ENABLED). Same SCOPE as mcpElicitation (streaming + durable legs; a synchronous /v1/tasks or a
387
- // sub-task with no live stream headless-defaults — honest, not a hang). #152: on a DURABLE deployment the
388
- // disconnected-human leg (checkpoint park + /decide) is no longer unconditional — it is what a leg with NO
389
- // reachable live face adjudicates to, while a live-stream leg asks the human over the stream instead. So this
390
- // flag being true also means "a live leg's question does NOT park"; a leg with no live face still parks.
391
102
  askUserQuestion: Boolean(deps.question),
392
- // [816]/[820]②: live tool-approval HITL — true ONLY when the onAsk producing path is wired
393
- // (TOOL_APPROVAL_ENABLED). LIVE sync-stream leg only; since [879] G1 (OnAsk 三值化) every other leg
394
- // (no ALS context / undeliverable card) returns "unavailable" → core durable-parks where a checkpoint
395
- // exists, and only fail-closed denies without one ([819]⑤). The durable-approval leg (checkpoint park +
396
- // /decide) is independent of this.
397
- // 🔴 A-054.10/.8:上面那句「→ core durable-parks」是**缺省 `park` 政策**下的话。#280 R-13 C 之后
398
- // `UNATTENDED_APPROVAL_POLICY=deny` 的部署上,那些腿(以及 deny 部署上**同步流腿自己的窗到期**)
399
- // 是当场 fail-closed deny,checkpoint 在不在场都一样 —— 「有 checkpoint 就 park」在那种部署上整句
400
- // 为假。⚠️ 本应答里**没有**任何 unattended-policy 位(刻意:那是部署级停机姿态,不是能力面),所以
401
- // 壳在 wire 上判不出自己连的是 park 还是 deny 部署 ⇒ **别按 park 写分支**,终局一律读 done 帧的
402
- // status/errorCode(附录 A 的成文原则)。机器门(capabilities-doc-appendix)只对拍键集与谓词类词
403
- // 表,语义列不在门内 —— 这正是本句能静默漂一整批的原因,所以它只能靠人守,别指望门。
404
103
  toolApproval: Boolean(deps.toolApproval),
405
- // #151 车3 刀 3b(设计稿 §2.4):design/172 **流内审批协议**(`approval_request` 呈卡帧 + 开流
406
- // preamble 对账基准 + durable 回决端点)。判据走**单一谓词** `resolveStreamApprovalGate` —— 与协调器
407
- // 的 askStore 注入、与 `POST /v1/tasks/:taskId/asks/:askId/decision` 的 501 门同一个符号,所以
408
- // 「这里说 true」⟺「协议真的在场」是结构成立的,壳不必 trial-by-帧(诚实缺席纪律,同上文各格)。
409
- // 五个合取项里最容易被忽略的两条:**账必须是持久的**(local 的 InMemory 形重启即丢已接受的决议)
410
- // 与 **park 设施必须在场**(缺席时窗到期没有降级目的地,结局是 core fail-closed deny —— 比现行
411
- // 5min 活卡更差,所以协议诚实地不上场、活卡腿逐字保留)。
412
104
  streamApproval: resolveStreamApprovalGate({
413
105
  toolApprovalEnabled: Boolean(deps.toolApproval),
414
106
  streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
415
107
  backend: deps.backend,
416
108
  parkFacility: deps.checkpointStore !== undefined,
417
109
  }).active,
418
- // #229(设计稿 233 稿B v2 §3):回决**理由**位在本二进制里存在的探测位 —— live
419
- // `POST /v1/tool-approvals/:id/respond` 收 `note` + 回执带 `noteRecorded`,durable 回决口的三个回体
420
- // 投 `decisionNote`。
421
- // 🔴 **恒 true,且必须与 `noteRecorded` 同车**:老 server 对未知请求键**静默忽略 + 照回 200**
422
- // (live 腿的 parser 是非 strict 的手写形),所以没有这一位时,「理由记上了」与「这台压根不认识
423
- // 这个键」在 wire 上不可判别 —— 壳只能拿一个 200 猜。位在场 ⇒ 按 `noteRecorded` 逐次读结果;
424
- // 位缺席 ⇒ 老 server,别渲这一格。
425
- // 🔴 谓词**刻意不挂任何设施**(不是 `Boolean(deps.backend)` 之类):本位声明的是「这个二进制认识
426
- // 这个键」这件版本事实,**不是**「你的理由一定会被记下」——后者是 per-call 的,由 `noteRecorded`
427
- // 逐次如实回答(店缺席/店抖动时它就是 `false`)。把部署条件混进版本位,会让「says yes ⟺ 面真能用」
428
- // 这句话在两个不同的问题上各说一半(与 `permissionRulesRevoke` 的存在性信号同族,见其注)。
429
110
  approvalDecisionNote: true,
430
- // [1469] POST /v1/side-query(core 的一次性 brain 路由问答,无 session 副作用)。恒可用 —— 探测位
431
- // 供壳判「引擎腿在」而非 trial-by-404。
432
- // #303 起出口是 `deps.sideQuery`(boot/side-query-lane.ts:真 runSideQuery + per-model key 注入 brain),
433
- // 不再是 Runner.sideQuery;能力位语义不变(必填席,恒在场)。
434
111
  sideQuery: true,
435
- // E16/E17/E21 (§0.5 session-ownership): list/fork/delete are homed on the durable SESSION abstraction.
436
- // Each flag is true ONLY when its PRODUCING path exists (never a bare const) — list needs an enumerator
437
- // (session store OR legacy run-store aggregate), fork needs sessionStorage.fork, delete needs the
438
- // purgeSession coordinator. Absent backend (in-memory dev) ⇒ false, so "says yes but 501s" can't happen.
439
- // #A1([4147] 件3;C-R13 链):`GET /v1/agents/roster` —— 后台 agent 名册读面。谓词**逐字**是那条
440
- // 路由的 501 门(`deps.backgroundAgentStore`),所以「说 yes ⟺ 路由真能用」是结构性的。
441
- // ⚠️ 辖域=**列举面**:名册回的是 content-free 投影(handle/name/agentType/status/三个时间戳);
442
- // 要子代产物正文走 `/v1/runs/:id/subagents/:handle/output`(那条口有它自己的谓词 `subagentOutput`)。
443
112
  agentRoster: Boolean(deps.backgroundAgentStore),
444
- // #270 车2:**托管留存**的部署事实(设计稿 §7 能力位)。`null` = sweep lane 关着(缺省);
445
- // 在场 = `{mode, maxAgeDays}` —— 两格都是**部署事实不是秘密**(策略数值本来就要告诉用户"你的
446
- // 数据留多久"),消费端(web admin 面 / test)按位渲染。
447
- //
448
- // 🔴 谓词为什么可以只看 config 而不合取"执行器在场"(「说 yes ⟺ 面真能用」的结构性论证):
449
- // `intervalSec > 0` 且没有真执行器的那台**根本起不来** —— `boot/retention-lane.ts` 的
450
- // `assertRetentionLaneWirable` 在 boot 期就拒了(policy 缺 / 执行器缺 / 有店声明 "none" 三条臂,
451
- // 且**不看 locked**)。所以在一个已经在应答 HTTP 的进程里,这个合取式恒真;再写一遍只会让读者
452
- // 以为这里还有第二道门。policy 缺席仍显式合取:它是那句 `{mode, maxAgeDays}` 里第二格的来源。
453
- // ⚠️ `retentionSweep` 在类型上是**必填**(`loadConfig` 恒产出它),这里仍显式判在场:本仓还有一批
454
- // 遗留测试用 `as unknown as ServiceDeps["config"]` 手搓 config 字面量 —— 那种双重断言把字段检查
455
- // 整个关掉,于是一个必填字段在它们手里可以真的缺席。缺席臂的方向是**保守**的(`null` = 本部署
456
- // 没有托管留存),不是放宽,所以它不是一处静默 fail-open;生产路径根本到不了这一臂。
457
113
  retention: retentionAdvertisement(deps.config),
458
114
  sessionList: Boolean(deps.sessionStorage?.listSessions ?? deps.runStore?.listSessions),
459
- sessionSearch: Boolean(deps.sessionStorage?.listSessions ?? deps.runStore?.listSessions), // GET /v1/sessions?q= (all lister backends carry it)
115
+ sessionSearch: Boolean(deps.sessionStorage?.listSessions ?? deps.runStore?.listSessions),
460
116
  sessionFork: Boolean(deps.sessionStorage?.fork),
461
117
  sessionDelete: Boolean(deps.purgeSession),
462
- // E18 (shell-host contract): resume-at (rewind to a prior message). True ONLY when BOTH the eventId→entryId anchor map
463
- // (resumeAnchorStore) AND the leaf-read path (sessionStorage.getLeafId, the §0.5 durable session abstraction)
464
- // exist — so a `resumeAt` submit can be resolved + captured. "Says yes but 4xx/no-ops" is impossible. Works
465
- // local + cloud (the anchor store is present on all backends); false only on the env-only/no-backend worker.
466
118
  resumeAt: Boolean(deps.resumeAnchorStore && deps.sessionStorage?.getLeafId),
467
- // E12 (shell-host contract): opt-in post-completion prompt suggestions (body.suggestNextPrompts → a `suggestions` event
468
- // on the run's events tail). A core 1.128 runner feature, no store dependency → always available on a worker.
469
119
  promptSuggestions: true,
470
- // E6 (shell-host contract): operator-tightened per-session tool rules (PUT/GET /v1/sessions/:id/policy + core reads them
471
- // at prepare-time, subtract-only). True when the durable/local SessionPolicyStore is wired.
472
120
  sessionPolicy: Boolean(deps.sessionPolicyStore),
473
- // E19 (shell-host contract): rewind-files (body.rewindFiles → snapshot per turn + restore on a resumeAt branch). core's
474
- // gate-split (1.134.0) snapshots for ANY ExecutionEnv when fileSnapshotStore is wired (host/local-mode +
475
- // e2b/k8s/ssh/adb/local-docker all active) → advertise whenever the store is wired.
476
121
  rewindFiles: Boolean(deps.fileSnapshotStore),
477
- // R8 code-only rewind (CC "Restore code", core 1.166 body.rewindFilesTo → restore files to a prior user message
478
- // WITHOUT forking). Needs BOTH the snapshot store (to restore) AND the anchor map (to resolve the target handle),
479
- // so it's the conjunction of `rewindFiles` and `resumeAt` — "says yes ⟺ the code-only submit resolves + restores".
480
122
  rewindFilesTo: Boolean(deps.fileSnapshotStore && deps.resumeAnchorStore && deps.sessionStorage?.getLeafId),
481
- // R7 自唤醒 (CC parity): the self-wake scheduler is LIVE — the host env exposes core's SchedulerCapability
482
- // (CronCreate/CronDelete/CronList mount——L8 订正旧名) and the TOC shell daemon should run to fire due intents. True
483
- // only on the single-user host lane with SCHEDULER_ENABLED (multi-tenant routes scheduling to center).
484
123
  scheduler: Boolean(deps.config.schedulerEnabled && deps.config.requirePrincipal !== true && deps.config.remoteExec?.provider === "host"),
485
- // 2c session-sync (P1d): the /v1/sessions/:id/sync/* peer routes (manifest/blobs/import/plan). True only when
486
- // the whole backend + the entry export seam + the STAGED-import seam + a snapshot store are all wired (so
487
- // export/import + blob transfer all resolve) — absent backend ⇒ false (the routes 501); "says yes ⟺ route works".
488
- // [2024](cli 取证)beginImportStaging 必须入谓词:此前只查旧三项,而暖缓存包装店恰好转发了那三项、
489
- // 漏了 staging 族 ⇒ caps 报 true 而 PUSH Phase A 恒 501 —— 「says yes ⟺ route works」被实测证否。
490
- // 功能半场(包装店补转发)已同批修;这里是诚实半场,兜住任何「能导出但不能 staged 导入」的店形。
491
124
  sessionSync: Boolean(deps.backend && deps.sessionStorage?.exportEntries && deps.sessionStorage?.beginImportStaging && deps.fileSnapshotStore),
492
- // SendUserFile(S3 双轨公网直链,契约 settled 2026-07-14):flag=READY 语义(F7 codex 审)——
493
- // emitter 存在(=工具真挂载,lane/租户/签发面三门在 main.ts 已判)∧ 公网端点在场(publicEndpoint
494
- // 缺席时 issue()/prepareDirectUpload() 一律 fail-loud,工具挂着也必失败)。"says yes ⟺ 调用真能
495
- // 成功":只看 config.sendUserFile(签发面已配)会在工具缺席的形态(adb/local-docker lane、多租户
496
- // host/ssh)假 yes(配置自查 agent 抓获 2026-07-14);只看 emitter 会在无公网端点时假 yes。
497
- // s3PublicEndpoint=公网 base 的单一真源透出(server 透出,消费端不猜、不走 registry env 双源;
498
- // 纯感知面)。[2373]A-5:截至 2026-08-02 无消费端读它——预备位,「web 渲染要用」是预期非现状。
499
125
  sendUserFile: Boolean(deps.sendUserFile && deps.config.sendUserFile?.publicEndpoint),
500
126
  s3PublicEndpoint: deps.config.sendUserFile?.publicEndpoint ?? null,
501
- // SendUserFile 账本(多租户治理面):true ⇔ 签发面已配 + store backend 在(记账写点活 + GET
502
- // /v1/sendfile-links 可列)。false = env-only worker(不记账,读面 501)——诚实缺席。
503
127
  sendUserFileLedger: Boolean(deps.sendFileLedger),
504
- // K-2 (shell §K) — core ruling = SPLIT into two ORTHOGONAL axes so the shell gates each honestly:
505
- // • `workflows` = ENGINE-CAN (can the engine self-orchestrate / run ultracode) = core's single-source
506
- // `workflowsCapability(deps)` (hardened script runner ∧ governance), boot-computed in main.ts. Falls back
507
- // to the `Boolean(workflowRunStore)` proxy when the boot flag isn't wired (older callers / tests).
508
- // • `workflowsList` = can durably LIST workflow runs = `Boolean(workflowRunStore)` (GET /v1/workflows* 501s
509
- // without it — list AND detail/stream, see the store gate in `routes/workflows.ts`, the
510
- // `if (!deps.workflowRunStore)` → 501 `capability.self_orchestration_required` arm).
511
- // ⚠️ In the CURRENT service wiring these two COINCIDE: `workflowRunStore` is built IFF self-orchestration is on
512
- // (InMemoryWorkflowRunStore when WORKFLOW_RUN_STORE=memory, else File — built in
513
- // `boot/workflow-orchestration.ts`, which design/158 A10 split out of main.ts; main.ts itself no longer
514
- // mentions InMemoryWorkflowRunStore at all, so the old `main.ts ~L527` anchor is dead), the SAME gate that
515
- // wires the safe script runner `workflowsCapability` checks → `Boolean(workflowRunStore)` ≡ `workflowsCapability`
516
- // always today. So this split is core's FORWARD-LOOKING orthogonal-axes CONTRACT, NOT a fix for a live
517
- // divergence (the earlier "memory backend → no store → divergence" framing was WRONG — InMemory IS a store;
518
- // double-review caught it). It becomes load-bearing only if a future wiring decouples them (e.g. a run store
519
- // present without a safe runner → engine-not-capable but listable). Both values are correct today.
520
128
  workflows: deps.workflowsCapable ?? Boolean(deps.workflowRunStore),
521
129
  workflowsList: Boolean(deps.workflowRunStore),
522
- // K-1c (shell §K): manual /compact verb (POST /v1/runs/:id/compact → core 1.156 TaskStream.compact()). Needs
523
- // the runs ledger (live-run lookup); advertise on runStore presence so the shell un-greys /compact only where
524
- // the endpoint exists (it 409s for a non-live run, 501s without the store). core ≥1.156 guaranteed by the pin.
525
130
  manualCompact: Boolean(deps.runStore),
526
131
  });
527
132
  return;
528
133
  }
529
- // Model catalog for consumers (e.g. OA's @-model autocomplete). NON-secret: names/capabilities
530
- // only — never baseUrl/apiKey. `name` is the `@handle`; any of these may be @-mentioned. Source
531
- // today = env-derived config.models; later the sema registry (sema-registry). The internal
532
- // `default` alias is hidden (it's a fallback ref, not a user-pickable model).
533
134
  if (req.method === "GET" && url === "/v1/models") {
534
- // #233 / A-002.8 读面:名单**在场时**每行补 `atMentionable`(名单缺席/空 ⇒ 整个键不发 —— 缺省形的
535
- // 字节逐字不变,消费端"没有这个键"= 这台没开名单治理,而不是"这行不能点")。判定与三个执法点同源
536
- // (isModelAllowlisted + 增广目录):壳面板上灰掉的行与服务端真会拒的行永远是同一批。
537
135
  const atCatalog = expandTiers(deps.config.models, deps.config.tiers ?? {}) ?? deps.config.models;
538
136
  const atAllowlist = deps.config.atModelAllowlist ?? [];
539
137
  const models = Object.entries(deps.config.models)
@@ -544,26 +142,11 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
544
142
  provider: m.provider,
545
143
  reasoning: m.reasoning,
546
144
  vision: Array.isArray(m.input) ? m.input.includes("image") : false,
547
- // E4 (shell-host contract): the context-window DENOMINATOR for the "% context used / N tokens until
548
- // compact / low-context warning" gauge. Pure passthrough of the Model the service already holds
549
- // (config.ts:603-604). Soft-degrade — omit when unknown (0) so the shell renders a raw token count
550
- // without a %. The NUMERATOR (turn_end.usage.contextTokens) is core-blocked (SERVICE-GAP-DOSSIER §2 row 4);
551
- // the denominator ships now with zero core dependency.
552
145
  ...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
553
146
  ...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
554
- // E7 (shell-host contract): the `/effort` picker's options. core's authoritative default tier set
555
- // (DEFAULT_EFFORT_LEVELS = minimal/low/medium/high) for a reasoning model; omitted for a non-reasoning
556
- // model (effort doesn't apply). The accept-set on a request is broader (any core ThinkingLevel) — this is
557
- // the advertised picker default, not a hard allow-list.
558
147
  ...(m.reasoning ? { supportedEffortLevels: [...DEFAULT_EFFORT_LEVELS] } : {}),
559
148
  ...(atAllowlist.length > 0 ? { atMentionable: isModelAllowlisted(name, atCatalog, atAllowlist) } : {}),
560
149
  }));
561
- // [865]③ id/name 撕裂消解:`default` 历史上是 **id 形**(壳面板行 value 却是 name 形,壳侧只能打补丁
562
- // 拼回)。additive 双给:`default` 保持 id 形字节不动(既有消费者),新 `defaultModel = { id, name }`
563
- // 一次给全。name = 目录里与 config.model 同一实例的键("default" 别名除外;registry 未生效的 env 单模型
564
- // 目录也可能无命中 → 退 id 匹配,再退 undefined 时省略 name)。
565
- // 双程匹配(codex M1):先引用相等(applyEffective 后 config.model 与目录真身同实例——重复 id 目录下
566
- // 唯一无歧义的判据),仅 env 单模型 lane 等无引用命中时才退 id 匹配(目录序第一,确定性)。
567
150
  const nonAlias = Object.entries(deps.config.models).filter(([n]) => n !== "default");
568
151
  const defaultName = (nonAlias.find(([, m]) => m === deps.config.model) ?? nonAlias.find(([, m]) => m.id === deps.config.model.id))?.[0];
569
152
  sendJson(res, 200, { models, default: deps.config.model.id, defaultModel: { id: deps.config.model.id, ...(defaultName ? { name: defaultName } : {}) } });