@sema-agent/server 7.114.0 → 7.116.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 (159) hide show
  1. package/MIGRATION.md +237 -2
  2. package/USAGE.md +39 -3
  3. package/deploy/sema-up/cluster-up.sh +13 -1
  4. package/deploy/sema-up/kube-up.sh +13 -1
  5. package/deploy/sema-up/preflight.sh +13 -1
  6. package/deploy/sema-up/sema-up.sh +13 -1
  7. package/deploy/sema-up/smoke.sh +13 -1
  8. package/dist/adoption/wire.d.ts +0 -3
  9. package/dist/approval-ask-audit-store.d.ts +25 -6
  10. package/dist/approval-ask-audit-store.js +6 -1
  11. package/dist/approval-card.d.ts +25 -24
  12. package/dist/approval-card.js +14 -0
  13. package/dist/approval-crash-convergence.d.ts +60 -0
  14. package/dist/approval-crash-convergence.js +75 -0
  15. package/dist/approval-deny-reasons.d.ts +13 -0
  16. package/dist/approval-deny-reasons.js +2 -0
  17. package/dist/approval.js +7 -3
  18. package/dist/boot/coordinators.js +0 -12
  19. package/dist/boot/execution-env.js +2 -1
  20. package/dist/boot/exit-boundary.d.ts +3 -2
  21. package/dist/boot/exit-boundary.js +3 -0
  22. package/dist/boot/resolve-spec.js +5 -1
  23. package/dist/boot/shutdown.d.ts +19 -0
  24. package/dist/boot/shutdown.js +12 -1
  25. package/dist/boot/stage-07-capability-layer.js +21 -15
  26. package/dist/boot/stores.js +4 -4
  27. package/dist/capabilities/composite-members.d.ts +1 -0
  28. package/dist/capabilities/composite-members.js +1 -0
  29. package/dist/capabilities/hands-lane.d.ts +0 -23
  30. package/dist/capabilities/hands-lane.js +3 -2
  31. package/dist/capabilities/send-user-file-tool.d.ts +10 -22
  32. package/dist/capabilities/send-user-file-tool.js +1 -8
  33. package/dist/capability-facts.d.ts +296 -0
  34. package/dist/capability-facts.js +354 -0
  35. package/dist/config-catalog.js +2 -1
  36. package/dist/config-center/apply-effective.js +11 -11
  37. package/dist/config-provider.d.ts +16 -0
  38. package/dist/config-provider.js +11 -2
  39. package/dist/config-types.d.ts +20 -1
  40. package/dist/config.d.ts +55 -29
  41. package/dist/config.js +48 -25
  42. package/dist/deployment-governance.d.ts +15 -4
  43. package/dist/deployment-governance.js +20 -2
  44. package/dist/fleet/fleet-bus.d.ts +1 -22
  45. package/dist/hooks/hook-runner.d.ts +29 -3
  46. package/dist/hooks/hook-runner.js +30 -17
  47. package/dist/http/admission.d.ts +6 -0
  48. package/dist/http/admission.js +29 -7
  49. package/dist/http/approval-sweeps.js +20 -0
  50. package/dist/http/checkpoint-ctx.d.ts +68 -0
  51. package/dist/http/checkpoint-ctx.js +36 -0
  52. package/dist/http/durable-run-leg.js +2 -1
  53. package/dist/http/principal-gate.d.ts +3 -0
  54. package/dist/http/principal-gate.js +3 -0
  55. package/dist/http/resume-legs.js +19 -1
  56. package/dist/http/retired-skill-manifest.d.ts +23 -0
  57. package/dist/http/retired-skill-manifest.js +22 -0
  58. package/dist/http/route-ctx.d.ts +7 -0
  59. package/dist/http/route-table.d.ts +3 -2
  60. package/dist/http/route-table.js +5 -5
  61. package/dist/http/routes/a2a-serve.d.ts +1 -3
  62. package/dist/http/routes/a2a-serve.js +14 -23
  63. package/dist/http/routes/admin-config-refresh.js +7 -2
  64. package/dist/http/routes/admin-drain.js +7 -2
  65. package/dist/http/routes/admin-memory-optout.d.ts +0 -2
  66. package/dist/http/routes/admin-memory-optout.js +20 -7
  67. package/dist/http/routes/adoption.js +19 -5
  68. package/dist/http/routes/agents-roster.js +4 -2
  69. package/dist/http/routes/approvals-assistant.js +41 -18
  70. package/dist/http/routes/background.d.ts +0 -2
  71. package/dist/http/routes/background.js +4 -5
  72. package/dist/http/routes/capabilities.d.ts +2 -1
  73. package/dist/http/routes/capabilities.js +63 -65
  74. package/dist/http/routes/config-catalog.d.ts +4 -5
  75. package/dist/http/routes/config-catalog.js +16 -2
  76. package/dist/http/routes/devices.js +17 -11
  77. package/dist/http/routes/diagnostics.d.ts +5 -0
  78. package/dist/http/routes/diagnostics.js +8 -1
  79. package/dist/http/routes/fleet.js +4 -2
  80. package/dist/http/routes/images.js +30 -3
  81. package/dist/http/routes/leader.js +7 -1
  82. package/dist/http/routes/mcp-reconnect.js +17 -10
  83. package/dist/http/routes/memory-bundle.js +20 -6
  84. package/dist/http/routes/memory-compliance.js +19 -5
  85. package/dist/http/routes/memory-consolidation.d.ts +9 -12
  86. package/dist/http/routes/memory-consolidation.js +17 -3
  87. package/dist/http/routes/memory-origin.js +19 -5
  88. package/dist/http/routes/notify-wake.js +5 -3
  89. package/dist/http/routes/observability.js +19 -5
  90. package/dist/http/routes/retention-ops.js +6 -1
  91. package/dist/http/routes/rules.js +49 -21
  92. package/dist/http/routes/run-memory-capture.js +5 -2
  93. package/dist/http/routes/runs.js +90 -60
  94. package/dist/http/routes/session-sync.js +64 -53
  95. package/dist/http/routes/sessions-list.js +8 -5
  96. package/dist/http/routes/sessions.js +40 -25
  97. package/dist/http/routes/shared-memory.js +5 -3
  98. package/dist/http/routes/tasks.js +5 -3
  99. package/dist/http/routes/trace-usage.js +18 -11
  100. package/dist/http/routes/workflows.js +36 -13
  101. package/dist/http/server.js +4 -1
  102. package/dist/http/wire-types.d.ts +6 -0
  103. package/dist/index.d.ts +1 -1
  104. package/dist/leader/wire.js +2 -1
  105. package/dist/local-data-root.d.ts +1 -1
  106. package/dist/mcp-content-origin.d.ts +0 -8
  107. package/dist/model-entry-refusal.d.ts +10 -2
  108. package/dist/model-entry-refusal.js +19 -3
  109. package/dist/namespaced-rule-name.d.ts +54 -0
  110. package/dist/namespaced-rule-name.js +33 -0
  111. package/dist/observability/corrupt-read-seat.d.ts +4 -3
  112. package/dist/observability/corrupt-read-seat.js +4 -3
  113. package/dist/observability/fail-open.d.ts +10 -9
  114. package/dist/observability/fail-open.js +5 -1
  115. package/dist/observability/permission-rule-events.d.ts +3 -0
  116. package/dist/observability/permission-rule-events.js +4 -0
  117. package/dist/permission-rule-list.d.ts +81 -0
  118. package/dist/permission-rule-list.js +17 -0
  119. package/dist/plugins/file-run-store.d.ts +7 -1
  120. package/dist/plugins/file-run-store.js +20 -7
  121. package/dist/plugins/memory-run-store.js +2 -1
  122. package/dist/plugins/one-time-migrations.d.ts +4 -2
  123. package/dist/plugins/one-time-migrations.js +26 -3
  124. package/dist/plugins/pg-session-storage.js +1 -1
  125. package/dist/plugins/run-store-sql.js +4 -4
  126. package/dist/plugins/session-policy-store-sql.js +4 -2
  127. package/dist/plugins/store-backend.d.ts +6 -1
  128. package/dist/plugins/store-backend.js +2 -1
  129. package/dist/plugins/store-contracts.d.ts +27 -8
  130. package/dist/plugins/store-contracts.js +12 -3
  131. package/dist/plugins/tidb-session-store.js +1 -1
  132. package/dist/request-key-closure.js +1 -1
  133. package/dist/run-local.d.ts +37 -3
  134. package/dist/run-local.js +52 -6
  135. package/dist/runs.d.ts +0 -58
  136. package/dist/runs.js +15 -20
  137. package/dist/runtime-governance.d.ts +21 -1
  138. package/dist/runtime-governance.js +6 -1
  139. package/dist/security.js +2 -2
  140. package/dist/session-policy-wire.d.ts +40 -59
  141. package/dist/session-policy-wire.js +60 -32
  142. package/dist/spec-fields.d.ts +32 -0
  143. package/dist/spec-fields.js +31 -16
  144. package/dist/standing-answer-grant.d.ts +8 -0
  145. package/dist/standing-answer-grant.js +5 -0
  146. package/dist/task-settings.d.ts +17 -6
  147. package/dist/task-settings.js +16 -30
  148. package/dist/tool-approval.d.ts +32 -4
  149. package/dist/tool-approval.js +31 -8
  150. package/dist/trace/core-keyset-guard.d.ts +13 -8
  151. package/dist/trace/project.js +9 -0
  152. package/dist/trace/self-minted-wire.d.ts +42 -0
  153. package/dist/trace/self-minted-wire.js +13 -0
  154. package/dist/user-input-ledger.d.ts +8 -5
  155. package/package.json +6 -4
  156. package/scripts/drain-check-local.mjs +528 -0
  157. package/scripts/drain-check.mysql.sql +67 -0
  158. package/scripts/drain-check.pg.sql +71 -0
  159. package/scripts/retired-mode-seed-drain-local.mjs +0 -317
@@ -2,11 +2,18 @@ import { Runner } from "@sema-agent/core";
2
2
  import { writeCrashLast, clearCrashLast, readCrashLast } from "./crash-last.js";
3
3
  import { createSighupIdleHandler } from "../sighup-idle.js";
4
4
  import { createParentWatch } from "../parent-watch.js";
5
+ import { setTimeout as delay } from "node:timers/promises";
6
+ import { HOST_BG_KILL_GRACE_MS } from "../plugins/remote-env-host.js";
5
7
  import { installProcessExitBoundary } from "./exit-boundary.js";
6
8
  import { createEngineLeaseTracker } from "./engine-lease.js";
7
9
  import { writeExitLast, readExitLast, clearExitLast } from "./exit-last.js";
8
10
  import { isScriptRealmRejection, describeRejectionReason } from "../orchestration/hardened-vm-runner.js";
9
11
  const HARD_STOP_GRACE_MS = 10_000;
12
+ export function backgroundGraceRemainingMs(a) {
13
+ if (a.softStopped <= 0)
14
+ return 0;
15
+ return Math.max(0, Math.min(a.softStoppedAt + a.graceMs, a.deadlineMs) - a.now);
16
+ }
10
17
  export function installShutdownHandlers(ctx) {
11
18
  const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, toolApproval, parkCommits, } = ctx;
12
19
  const dataRoot = config.localDataRoot;
@@ -102,7 +109,10 @@ export function installShutdownHandlers(ctx) {
102
109
  subRunner.sessions.dispose();
103
110
  void lspManager?.dispose?.();
104
111
  void workflowNotifyJournal?.close?.();
105
- exitBoundary.reapChildProcessesEarly();
112
+ const backgroundSoftStopped = exitBoundary.reapChildProcessesEarly();
113
+ const softStoppedAt = Date.now();
114
+ const backgroundGraceMs = backgroundGraceRemainingMs({ softStopped: backgroundSoftStopped, softStoppedAt, now: softStoppedAt, graceMs: HOST_BG_KILL_GRACE_MS, deadlineMs: graceDeadlineMs });
115
+ const backgroundGrace = backgroundGraceMs > 0 ? delay(backgroundGraceMs) : Promise.resolve();
106
116
  const drained = approvalDrain
107
117
  .then(() => parkCommits?.quiesce(graceDeadlineMs))
108
118
  .then((q) => {
@@ -120,6 +130,7 @@ export function installShutdownHandlers(ctx) {
120
130
  void Promise.all([retentionTeardown, ledgerStopped])
121
131
  .then(() => (backend ? backend.close() : Promise.resolve()))
122
132
  .then(() => routingStopped)
133
+ .finally(() => backgroundGrace)
123
134
  .finally(() => process.exit(0));
124
135
  });
125
136
  const finalExit = setTimeout(() => { logger.warn("hard_shutdown_final_deadline", { afterMs: 15_000 }); process.exit(0); }, 15_000);
@@ -16,6 +16,7 @@ import { explicitOperatorOk } from "../http/server.js";
16
16
  import { selfOrchestrationDenial } from "../task-workflow.js";
17
17
  import { centerEntitlementSourceWired } from "../runtime-caps-resolver.js";
18
18
  import { reclaimOrphansAtBoot } from "../boot-reclaim.js";
19
+ import { runBootCrashConvergence } from "../approval-crash-convergence.js";
19
20
  import { createUserInputLedgerAtBoot, writerGoneEvidenceFor } from "../user-input-ledger.js";
20
21
  import { createParkedReviveInheritedGate } from "./parked-revive-gate.js";
21
22
  import { createParkedReviveSurface } from "../parked-revive-surface.js";
@@ -23,8 +24,9 @@ import { createWebFetchSummarizeLane } from "./webfetch-summarize-lane.js";
23
24
  import { createRunnerDepsOnAsk } from "./runner-deps.js";
24
25
  import { bindRateLimiter, bindRunStore } from "./late-binds.js";
25
26
  import { buildDisplaySafeUrl } from "../trace/redact.js";
27
+ import * as facts from "../capability-facts.js";
26
28
  export async function runStage07(ctx) {
27
- const { approvalExemptionStore, backend, backgroundAgentStore, brain, checkpointStore, config, configCenter, counterDegradeHook, durableEnabled, handslessSubRunner, instanceId, localRoot, logger, memoryEngine, metrics, question, runner, runnerDeps, sendUserFileToolSpec, sessionEnvSelection, sessionStore, subRunner, subRunnerSessions, taskListLane, toolApproval } = ctx;
29
+ const { approvalAskAudit, approvalExemptionStore, backend, backgroundAgentStore, brain, checkpointStore, config, configCenter, counterDegradeHook, durableEnabled, handslessSubRunner, instanceId, localRoot, logger, memoryEngine, metrics, question, runner, runnerDeps, sendUserFileToolSpec, sessionEnvSelection, sessionStore, subRunner, subRunnerSessions, taskListLane, toolApproval } = ctx;
28
30
  const authorize = createAuthorizer(config, sessionStore);
29
31
  const runStore = backend ? backend.run() : undefined;
30
32
  bindRunStore(runStore);
@@ -51,6 +53,7 @@ export async function runStage07(ctx) {
51
53
  if (gateRefusal !== undefined)
52
54
  throw new Error(gateRefusal);
53
55
  await reclaimOrphansAtBoot(runStore, checkpointStore, logger);
56
+ await runBootCrashConvergence({ backend, runStore, liveAudit: approvalAskAudit, localDataRoot: config.localDataRoot, logger });
54
57
  const userInputLedgerStore = backend && runStore ? backend.userInputLedger() : undefined;
55
58
  const userInputLedger = backend && runStore && userInputLedgerStore
56
59
  ? await (async () => {
@@ -79,14 +82,22 @@ export async function runStage07(ctx) {
79
82
  if (durableEnabled)
80
83
  logger.info("durable_approval_enabled", { toolApprovalGate: config.approvalRequire.length });
81
84
  if (config.a2aServe) {
82
- logger.info("a2a_serve_enabled", {
83
- card: "/.well-known/agent-card.json",
84
- rpc: "/v1/a2a",
85
- advertisedUrl: buildDisplaySafeUrl(config.a2aServe.url),
86
- skills: config.a2aServe.skills.length,
87
- blockingWaitMs: config.a2aServe.blockingWaitMs,
88
- tasksUsable: runStore !== undefined,
89
- });
85
+ const peer = facts.a2aServe({ config, runStore });
86
+ if (peer.available) {
87
+ logger.info("a2a_serve_enabled", {
88
+ card: "/.well-known/agent-card.json",
89
+ rpc: "/v1/a2a",
90
+ advertisedUrl: buildDisplaySafeUrl(config.a2aServe.url),
91
+ skills: config.a2aServe.skills.length,
92
+ blockingWaitMs: config.a2aServe.blockingWaitMs,
93
+ });
94
+ }
95
+ else {
96
+ logger.warn("a2a_serve_not_served", {
97
+ reason: peer.why,
98
+ detail: "A2A_SERVE_ENABLED is on but this worker has no durable run store, so the agent card and POST /v1/a2a answer 404 (message/send and tasks/get both need it) — set DB_BACKEND=mysql|pg|local, or turn A2A_SERVE_ENABLED off",
99
+ });
100
+ }
90
101
  }
91
102
  for (const w of buildNoResponderBootWarns({
92
103
  lane: executionLaneOf(config.remoteExec?.provider),
@@ -148,12 +159,7 @@ export async function runStage07(ctx) {
148
159
  ensureChildSessionDurable: ensureChildSessionDurable ? ensureChildSessionDurable : undefined,
149
160
  taskListStoreFor: taskListLane.storeFor,
150
161
  brandIdentity: config.configProvider === "local",
151
- subagentExtraTools: sendUserFileToolSpec
152
- ? subagentSendUserFileExtraTools({
153
- spec: sendUserFileToolSpec,
154
- approvalGate: () => ({ deny: config.approvalDeny, require: config.approvalRequire, neverAuto: config.approvalNeverAuto }),
155
- })
156
- : undefined,
162
+ subagentExtraTools: sendUserFileToolSpec ? subagentSendUserFileExtraTools({ spec: sendUserFileToolSpec }) : undefined,
157
163
  };
158
164
  const scenarios = buildScenarios(scenarioDeps);
159
165
  const builtinDefaultScenario = scenarios.default;
@@ -1,5 +1,5 @@
1
1
  import { join } from "node:path";
2
- import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, FileUsageWindowStore, InMemoryUsageWindowStore, mailboxCrossProcessMountVerdict } from "@sema-agent/core";
2
+ import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, InMemoryUsageWindowStore, mailboxCrossProcessMountVerdict } from "@sema-agent/core";
3
3
  import { createCorruptReadFailOpenSeat } from "../observability/corrupt-read-seat.js";
4
4
  import { createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
5
5
  import { memoryEmbedderFor } from "../plugins/memory-embedder.js";
@@ -333,13 +333,13 @@ export async function openStores(ctx) {
333
333
  await ensureTiDBUsageWindowSchema(mysqlPool);
334
334
  usageWindowStore = new TiDBUsageWindowStore(mysqlPool);
335
335
  }
336
- else if (backend?.kind === "local") {
337
- usageWindowStore = new FileUsageWindowStore(config.localDataRoot ?? localRoot);
336
+ else if (backend?.fileUsageWindowStore !== undefined) {
337
+ usageWindowStore = backend.fileUsageWindowStore();
338
338
  }
339
339
  else {
340
340
  usageWindowStore = new InMemoryUsageWindowStore();
341
341
  }
342
- logger.info("usage_window_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : backend?.kind === "local" ? "file" : "memory", windows: config.usageWindows.length });
342
+ logger.info("usage_window_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : backend?.fileUsageWindowStore !== undefined ? "file" : "memory", windows: config.usageWindows.length });
343
343
  }
344
344
  const memoryExportBackend = config.memoryEngineBackend !== "file" ? memoryEngine?.backend : undefined;
345
345
  const memoryLane = memoryEngineRemoteLanePosture(config);
@@ -46,6 +46,7 @@ export declare const COMPOSITE_CAPABILITY_MEMBERS: {
46
46
  readonly webSearch: readonly ["backend"];
47
47
  readonly background: readonly ["listFace", "exitFaces"];
48
48
  readonly taskSettings: readonly ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"];
49
+ readonly settings: readonly ["permissions"];
49
50
  readonly permissionModeAuto: readonly ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"];
50
51
  readonly writeProtection: readonly ["armed", "rows", "replaced"];
51
52
  readonly executionLane: readonly ["provider", "toolsOnThisHost", "isolated"];
@@ -7,6 +7,7 @@ export const COMPOSITE_CAPABILITY_MEMBERS = {
7
7
  webSearch: ["backend"],
8
8
  background: ["listFace", "exitFaces"],
9
9
  taskSettings: ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"],
10
+ settings: ["permissions"],
10
11
  permissionModeAuto: ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"],
11
12
  writeProtection: ["armed", "rows", "replaced"],
12
13
  executionLane: ["provider", "toolsOnThisHost", "isolated"],
@@ -33,29 +33,6 @@ export interface HandsRunnerPair {
33
33
  }
34
34
  /** 按场景表态取 Runner。**穷举 switch**:`ScenarioHands` 加词而此处不改 = 编译错(无 default 臂)。 */
35
35
  export declare function pickHandsRunner(hands: ScenarioHands, pair: HandsRunnerPair): Runner;
36
- /**
37
- * core 手带 band 的工具名**全集** —— 「挂 executionEnvFactory 才出现、不挂就消失」的那一批。
38
- *
39
- * 两段来源,都不是拍脑袋:
40
- * · `handBandEffects()`(core 7.8.0 B1 起的导出面;此前是手抄表常量 `HAND_TOOL_EFFECTS`)—— band 的
41
- * effect 表,由**静态工具目录**按 `mountedBy.includes("hands")` 派生。名册单源之后这张表不再是一张
42
- * 手抄名表,加/退工具由目录一处说了算。
43
- * · 下方锚定补集 —— `createHandsToolkit` / 手带块还会铸但**不在** effect 表里的 5 名(实测差集,见
44
- * test/scenario-hands-lane.test.ts 的对表格:它用真 Runner 跑「有手 roster ∖ 无手 roster」,与本常量逐名对账,
45
- * core 加/改 band 成员时红,防漂移)。
46
- *
47
- * ⚠️ 本全集是**观测口径**(用于防漂移对账),**不是** deny 名单 —— deny 用下面的
48
- * {@link HANDS_EXCLUSIVE_TOOL_NAMES},理由见那里。
49
- *
50
- * 🚨 [ref] P0(2026-08-09):派生时必须过滤 core 的 `RETIRED_TOOL_NAMES` —— core 5.21.0 的
51
- * `HAND_TOOL_EFFECTS` 里残留已退役的 `MultiEdit`,而 core `prepare-task` 的策略名审计见退役名
52
- * **无条件 throw**(`config.legacy_tool_name`);不过滤,deny 名单一进 `spec.toolPolicy`,
53
- * `hands: none` 三场景(scan/code-review/team)在**所有部署**上零 turn 全灭。core 5.21.1 已删
54
- * 那条死条目([ref]),这道 filter 是结构性防御:将来 core 再退役任何 band 名都不会重演
55
- * (test/scenario-hands-lane.test.ts 格7/格8 双钉:真 Runner 过审计 + 零交集门)。
56
- * filter 打在**整表**(effect 表 + 锚定补集)之后 —— caret floor 下装置会解析到更新的 core,
57
- * 补集名哪天被退役,只滤前半就是同一次故障换个名字(codex 复审 finding,2026-08-09)。
58
- */
59
36
  export declare const HANDS_BAND_TOOL_NAMES: readonly string[];
60
37
  /**
61
38
  * band 里**只有手才可能出现**的那批(= deny 名单)。
@@ -1,4 +1,4 @@
1
- import { handBandEffects, RETIRED_TOOL_NAMES, combinePolicies, createAllowDenyPolicy } from "@sema-agent/core";
1
+ import { handBandEffects, judgeRuleToolName, combinePolicies, createAllowDenyPolicy } from "@sema-agent/core";
2
2
  export function withoutExecutionEnv(deps) {
3
3
  const { executionEnvFactory: _handsDropped, ...rest } = deps;
4
4
  return rest;
@@ -11,6 +11,7 @@ export function pickHandsRunner(hands, pair) {
11
11
  return pair.handsless;
12
12
  }
13
13
  }
14
+ const NO_DECLARED_TOOL_NAMES = new Set();
14
15
  export const HANDS_BAND_TOOL_NAMES = Object.freeze([
15
16
  ...handBandEffects().keys(),
16
17
  "SendMessage",
@@ -19,7 +20,7 @@ export const HANDS_BAND_TOOL_NAMES = Object.freeze([
19
20
  "EnterWorktree",
20
21
  "ExitWorktree",
21
22
  "ListAgents",
22
- ].filter((n, i, all) => !RETIRED_TOOL_NAMES.has(n) && all.indexOf(n) === i));
23
+ ].filter((n, i, all) => judgeRuleToolName(n, NO_DECLARED_TOOL_NAMES).kind === "current" && all.indexOf(n) === i));
23
24
  export const HANDS_DUAL_USE_TOOL_NAMES = Object.freeze(["TaskOutput", "TaskStop", "SendMessage", "AgentTranscript", "ListAgents"]);
24
25
  export const HANDS_EXCLUSIVE_TOOL_NAMES = Object.freeze(HANDS_BAND_TOOL_NAMES.filter((n) => !HANDS_DUAL_USE_TOOL_NAMES.includes(n)));
25
26
  export function handsDenyPolicy() {
@@ -44,32 +44,20 @@ export declare function sendUserFileTool(deps: {
44
44
  }): ToolSpec;
45
45
  export declare const SEND_USER_FILE_TOOL_NAME = "SendUserFile";
46
46
  /**
47
- * Build the `SubagentToolOptions.extraTools` factory that injects SendUserFile into delegated-child rosters —
48
- * WITH the two gates the bare `() => [spec]` wiring lacked:
47
+ * Build the `SubagentToolOptions.extraTools` factory that injects SendUserFile into delegated-child rosters.
49
48
  *
50
- * F1 (HIGH, codex): the subRunner carries NO tool policy and core's child spec does not inherit the parent's
51
- * `toolPolicy`, so an extraTools-injected SendUserFile BYPASSED the deployment approval gate (evidence: with
52
- * `APPROVAL_DENY=SendUserFile` the top-level call is denied but a delegated child could still call it). Until
53
- * core lands a child-policy propagation seam, the CONSERVATIVE server-side stopgap is a deployment-policy
54
- * PRE-CHECK: if the deployment's approval face gates SendUserFile at all (deny OR ask — approvalDeny /
55
- * approvalRequire / approvalNeverAuto, matched in canonical space exactly like src/approval.ts), the factory
56
- * injects NOTHING. deny obviously must not reach children; ask-gated is ALSO withheld because the child leg has
57
- * no policy to route the ask (injecting would silently auto-allow — the exact bypass). The gate is read LIVE per
58
- * spawn (a getter, not a boot snapshot) so center/env hot-applied governance is honored, mirroring how the
59
- * per-request approval baseline reads live config. A deployment with no gate intent is unchanged.
49
+ * F2 (MED, codex; a product judgment of this server, kept): read-only builtin agents (Explore/Plan) must NOT get
50
+ * SendUserFile — a read-only agent that can read sensitive files AND mint public links off them breaks the read-only
51
+ * posture (their denyTools sets predate this tool, so core's resolveToolSubset would let it through). `ctx.agentType`
52
+ * carries the spawned definition's name (core subagent.js); membership in core's builtin catalog ⇒ inject nothing.
60
53
  *
61
- * F2 (MED, codex): read-only builtin agents (Explore/Plan) must NOT get SendUserFile — a read-only agent that
62
- * can read sensitive files AND mint public links off them breaks the read-only posture (their denyTools sets
63
- * predate this tool, so core's resolveToolSubset would let it through). `ctx.agentType` carries the spawned
64
- * definition's name (core subagent.js); membership in core's builtin catalog ⇒ inject nothing for that spawn.
54
+ * 🔴 S-1058(7.116.0):修前这里还有一道 **F1 部署策略预判** —— 部署审批面(`APPROVAL_DENY` / `REQUIRE` / `NEVER_AUTO`)点名 SendUserFile 就一只都
55
+ * 不注入,前提是「subRunner 不带策略、core 的子代不继承父的 toolPolicy」(core 1.287 时的事实)。core 自 7.40.1 起顶层 run 解析后的调用方策略
56
+ * (`spec.toolPolicy ?? deps.toolPolicy`)与它冻结的审批席经继承链(`InheritedGate.parentConstraints`)判子代的注入工具:deny ⇒ 零执行;ask ⇒ 顶层
57
+ * 审批席被问一次;无审批席 ⇒ 拒(core 7.41.0 钉)。本仓在真实装配上亲跑十格(spec / deps 两槽 × deny / ask 允 / ask 拒 / 无审批席 / 耐久车道无活席,
58
+ * `test/subagent-extra-tools-ancestor-policy-s1058.test.ts`)全部成立 ⇒ 预判整段删:部署的判决在继承链上由策略本身做,本仓不再复刻一份「按名单猜」。
65
59
  */
66
60
  export declare function subagentSendUserFileExtraTools(deps: {
67
61
  spec: ToolSpec;
68
- /** LIVE deployment approval face (config.approvalDeny/approvalRequire/approvalNeverAuto) — evaluated per spawn. */
69
- approvalGate: () => {
70
- deny?: string[];
71
- require?: string[];
72
- neverAuto?: string[];
73
- };
74
62
  }): (ctx: SubagentSpawnContext) => ToolSpec[];
75
63
  //# sourceMappingURL=send-user-file-tool.d.ts.map
@@ -94,13 +94,6 @@ export function sendUserFileTool(deps) {
94
94
  export const SEND_USER_FILE_TOOL_NAME = "SendUserFile";
95
95
  const READONLY_BUILTIN_AGENT_TYPES = new Set(builtinAgentDefinitions().map((d) => d.name));
96
96
  export function subagentSendUserFileExtraTools(deps) {
97
- const canonical = SEND_USER_FILE_TOOL_NAME;
98
- return (ctx) => {
99
- if (ctx.agentType !== undefined && READONLY_BUILTIN_AGENT_TYPES.has(ctx.agentType))
100
- return [];
101
- const gate = deps.approvalGate();
102
- const gated = [...(gate.deny ?? []), ...(gate.require ?? []), ...(gate.neverAuto ?? [])].some((t) => t === canonical);
103
- return gated ? [] : [deps.spec];
104
- };
97
+ return (ctx) => (ctx.agentType !== undefined && READONLY_BUILTIN_AGENT_TYPES.has(ctx.agentType) ? [] : [deps.spec]);
105
98
  }
106
99
  //# sourceMappingURL=send-user-file-tool.js.map
@@ -0,0 +1,296 @@
1
+ /**
2
+ * 能力事实 —— 「这台部署上,这一面能不能用」的**唯一**判据家。
3
+ *
4
+ * 一条规则,三个读者:
5
+ * · 每个事实 = 这里**一只**纯函数。入 = 服务 deps 的只读切片(签名里的 `Pick` 就是它读哪几格的完整清单);
6
+ * 出 = `{ available: true }` 或 `{ available: false; why }`。零 I/O、零 await、零副作用。
7
+ * · `GET /v1/capabilities` 的位只**投影**事实(布尔位 = `.available`;对象位写明投影规则)。
8
+ * · 回答「这台部署上不可用」的每一道门(HTTP 501;a2a 两条路由的 404)调**同一只**事实;拒句可以按端点各写,
9
+ * 谓词不再写第二遍。
10
+ * 于是「位说有而端点恒拒」在结构上不可能:两边读的是同一个值。
11
+ *
12
+ * `why` 是一张闭集表({@link CAPABILITY_FACT_WHY}):每只事实的 why 类型被约束在这张表的键里(用了表外词 = 编译红),
13
+ * 多 why 的事实在门里按 `switch (f.why)` 收口(给事实添一个 why 而门没跟 = 编译红)。
14
+ *
15
+ * **见证**:携设施的事实在 available 臂上另带被判在场的那只设施引用(结构上仍是 `{ available: true }` 的子型)。
16
+ * 门在拒臂之后从见证取店,不再读 `deps.X` 第二遍 —— 否则只剩两条路:非空断言,或者把谓词再写一遍。
17
+ * 能力位只读 `.available`,见证不上 wire。
18
+ *
19
+ * 复合事实(一个位管一族、族内要几只事实都在)也住这里:能力面只读一只事实的 `.available`,不写 `a && b`。
20
+ */
21
+ import type { FlatServiceDeps } from "./http/server.js";
22
+ import type { ServiceConfig } from "./config.js";
23
+ import type { OwnerAwareSessionStore } from "./security.js";
24
+ import type { ServiceFileHistoryStore } from "./plugins/store-backend.js";
25
+ import { resolveStreamApprovalGate } from "./tool-approval.js";
26
+ /** why 闭集:词 → 给运维看的一句义(诊断 / 测试读它;wire 上的拒句由各门自写)。 */
27
+ export declare const CAPABILITY_FACT_WHY: {
28
+ readonly run_store_absent: "no durable run store is wired (DB_BACKEND=mysql|pg|local)";
29
+ readonly subagent_registry_absent: "the sub-agent steer registry is not wired";
30
+ readonly subagent_output_face_absent: "the background sub-agent output face is not wired";
31
+ readonly task_handle_faces_absent: "the background task-handle output/stop faces are not wired";
32
+ readonly session_owner_face_absent: "the session store has no ownership face (sessionStorage.ownerOf)";
33
+ readonly checkpoint_store_absent: "no durable checkpoint store is wired (DURABLE_APPROVAL)";
34
+ readonly session_audit_absent: "no session audit view is wired (needs a durable session store)";
35
+ readonly session_watch_absent: "the session watch registry is not wired";
36
+ readonly session_leaf_face_absent: "the session store has no leaf-read face (sessionStorage.getLeafId)";
37
+ readonly session_lister_absent: "no session enumerator is wired (session store or run store listSessions)";
38
+ readonly session_fork_face_absent: "the session store has no fork face";
39
+ readonly session_purge_absent: "no session purge coordinator is wired";
40
+ readonly session_policy_store_absent: "no session policy store is wired";
41
+ readonly store_backend_absent: "no store backend is wired (DB_BACKEND=memory, multi-tenant bare boot, or half-configured SQL)";
42
+ readonly file_history_store_absent: "no file-history store is wired";
43
+ readonly session_export_absent: "the session store has no entry export faces (exportEntries / exportEntriesStream)";
44
+ readonly session_import_staging_absent: "the session store has no staged-import face (beginImportStaging)";
45
+ readonly policy_purge_absent: "the session policy store has no deleteBySession purge verb";
46
+ readonly sync_blob_faces_absent: "the file-history store has no blob transfer faces (SQL backends only)";
47
+ readonly device_hub_absent: "the device lane hub is not wired";
48
+ readonly device_store_absent: "the device store is not wired";
49
+ readonly device_enrollment_absent: "device enrollment is not wired";
50
+ readonly fleet_bus_absent: "the fleet event bus is not wired";
51
+ readonly workspace_retired: "the workspace browse face was retired with the whole-tree snapshot epoch";
52
+ readonly leader_endpoint_absent: "the leader endpoint is not wired";
53
+ readonly image_index_absent: "no image index is wired (SQL backends only)";
54
+ readonly shared_memory_store_absent: "no shared memory store provider is wired";
55
+ readonly org_memory_directory_absent: "no org memory directory (membership fold) is wired";
56
+ readonly operator_principals_empty: "OPERATOR_PRINCIPALS is empty, so no caller can ever be an operator";
57
+ readonly adoption_store_absent: "no adoption log store is wired (SQL backends only)";
58
+ readonly memory_bundle_faces_absent: "the memory engine's governance bundle faces are not wired";
59
+ readonly memory_compliance_faces_absent: "the memory engine's provenance/erasure faces are not wired";
60
+ readonly memory_origin_faces_absent: "the memory engine's origin marking faces are not wired";
61
+ readonly consolidation_valve_closed: "the memory consolidation valve is closed (MEMORY_CONSOLIDATION_DRIVER)";
62
+ readonly memory_optout_grant_absent: "no memory-capture opt-out grant store is wired (SQL backends only)";
63
+ readonly outcome_ledger_unqueryable: "the outcome sink has no query face (File sink)";
64
+ readonly config_catalog_disabled: "the config catalog is switched off (CONFIG_CATALOG_ENABLED=false)";
65
+ readonly rule_store_absent: "no permission-rule store is wired";
66
+ readonly caller_principal_absent: "this request carries no verified principal";
67
+ readonly caller_mcp_injection_refused: "this deployment does not honor caller-supplied MCP servers";
68
+ readonly a2a_serve_off: "A2A_SERVE_ENABLED is off";
69
+ readonly elicitation_disabled: "inbound MCP elicitation is off (MCP_ELICITATION_ENABLED)";
70
+ readonly ask_question_disabled: "AskUserQuestion live HITL is off (ASK_QUESTION_ENABLED)";
71
+ readonly tool_approval_disabled: "live tool approval is off (TOOL_APPROVAL_ENABLED)";
72
+ readonly stream_approval_disabled: "the stream approval protocol is off (STREAM_APPROVAL_ENABLED)";
73
+ readonly background_agent_store_absent: "no background-agent store is wired";
74
+ readonly sendfile_ledger_absent: "no SendUserFile ledger is wired";
75
+ readonly workflow_engine_absent: "the workflow engine is not available on this worker";
76
+ readonly entitlement_resolver_absent: "self-orchestration is on for a multi-tenant worker with no per-principal entitlement source";
77
+ readonly workflow_run_store_absent: "no workflow run store is wired (SELF_ORCHESTRATION_ENABLED)";
78
+ readonly workflow_journal_store_absent: "no workflow journal store is wired (needs a store backend)";
79
+ readonly scheduler_disabled: "the self-wake scheduler is off (SCHEDULER_ENABLED)";
80
+ readonly multi_tenant_deployment: "this is a multi-tenant deployment (REQUIRE_PRINCIPAL=true)";
81
+ readonly not_host_lane: "the execution lane is not the single-user host lane (REMOTE_EXEC=host)";
82
+ };
83
+ export type CapabilityFactWhy = keyof typeof CAPABILITY_FACT_WHY;
84
+ /** 不可用臂。 */
85
+ export interface FactUnavailable<Why extends CapabilityFactWhy> {
86
+ readonly available: false;
87
+ readonly why: Why;
88
+ }
89
+ /** 一只事实的出形(`W` = available 臂上的见证;无见证的事实取默认空对象 = 只有 `available: true`)。 */
90
+ export type Fact<Why extends CapabilityFactWhy, W extends object = {}> = ({
91
+ readonly available: true;
92
+ } & Readonly<W>) | FactUnavailable<Why>;
93
+ type Deps = FlatServiceDeps;
94
+ type Store<K extends keyof Deps> = NonNullable<Deps[K]>;
95
+ type WithMethods<T, K extends keyof T> = T & {
96
+ [P in K]-?: NonNullable<T[P]>;
97
+ };
98
+ /** 持久 run 账面在场 —— `/v1/runs/*` 族、trace / 用量统计、assistant 的 preempt / resume / plan-review、
99
+ * 会话 detach、设备换绑都站在这一只事实上。 */
100
+ export declare function durableRuns(d: Pick<Deps, "runStore">): Fact<"run_store_absent", {
101
+ runStore: Store<"runStore">;
102
+ }>;
103
+ export declare function subagentSteer(d: Pick<Deps, "runStore" | "subagentSteerRegistry">): Fact<"run_store_absent" | "subagent_registry_absent", {
104
+ runStore: Store<"runStore">;
105
+ registry: Store<"subagentSteerRegistry">;
106
+ }>;
107
+ export declare function subagentOutput(d: Pick<Deps, "runStore" | "subagentTaskOutput">): Fact<"run_store_absent" | "subagent_output_face_absent", {
108
+ runStore: Store<"runStore">;
109
+ output: Store<"subagentTaskOutput">;
110
+ }>;
111
+ export declare function taskHandles(d: Pick<Deps, "runStore" | "taskHandleOutput" | "taskHandleStop">): Fact<"run_store_absent" | "task_handle_faces_absent", {
112
+ runStore: Store<"runStore">;
113
+ output: Store<"taskHandleOutput">;
114
+ stop: Store<"taskHandleStop">;
115
+ }>;
116
+ type OwnedSessionStore = WithMethods<OwnerAwareSessionStore, "ownerOf">;
117
+ /** 会话属主面在场(入站 owner 门的地基;缺它,带会话的门一律 fail-closed)。 */
118
+ export declare function sessionOwnership(d: Pick<Deps, "sessionStorage">): Fact<"session_owner_face_absent", {
119
+ sessionStorage: OwnedSessionStore;
120
+ }>;
121
+ export declare function mcpReconnect(d: Pick<Deps, "runStore" | "sessionStorage">): Fact<"run_store_absent" | "session_owner_face_absent", {
122
+ runStore: Store<"runStore">;
123
+ sessionStorage: OwnedSessionStore;
124
+ }>;
125
+ export declare function sessionAuditView(d: Pick<Deps, "sessionAudit">): Fact<"session_audit_absent", {
126
+ sessionAudit: Store<"sessionAudit">;
127
+ }>;
128
+ export declare function sessionEventStream(d: Pick<Deps, "sessionWatch" | "sessionStorage">): Fact<"session_watch_absent" | "session_leaf_face_absent" | "session_owner_face_absent", {
129
+ watch: Store<"sessionWatch">;
130
+ sessionStorage: WithMethods<OwnerAwareSessionStore, "ownerOf" | "getLeafId">;
131
+ }>;
132
+ type SessionLister = NonNullable<OwnerAwareSessionStore["listSessions"]>;
133
+ /** 会话枚举面:session 店的 `listSessions`,否则老形 run 店聚合。见证 = 已绑好宿主的那一只。 */
134
+ export declare function sessionList(d: Pick<Deps, "sessionStorage" | "runStore">): Fact<"session_lister_absent", {
135
+ lister: SessionLister;
136
+ }>;
137
+ export declare function sessionFork(d: Pick<Deps, "sessionStorage">): Fact<"session_fork_face_absent" | "session_owner_face_absent", {
138
+ sessionStorage: WithMethods<OwnerAwareSessionStore, "ownerOf" | "fork">;
139
+ }>;
140
+ export declare function sessionDelete(d: Pick<Deps, "purgeSession" | "sessionStorage">): Fact<"session_purge_absent" | "session_owner_face_absent", {
141
+ purge: Store<"purgeSession">;
142
+ sessionStorage: OwnedSessionStore;
143
+ }>;
144
+ export declare function sessionPolicy(d: Pick<Deps, "sessionPolicyStore" | "sessionStorage">): Fact<"session_policy_store_absent" | "session_owner_face_absent", {
145
+ policyStore: Store<"sessionPolicyStore">;
146
+ sessionStorage: OwnedSessionStore;
147
+ }>;
148
+ type SyncSessionStore = WithMethods<OwnerAwareSessionStore, "ownerOf" | "exportEntries" | "exportEntriesStream" | "beginImportStaging">;
149
+ type SessionSyncWhy = "store_backend_absent" | "session_owner_face_absent" | "file_history_store_absent" | "session_export_absent" | "session_import_staging_absent" | "policy_purge_absent";
150
+ /** 会话对等同步的**对话半族**(manifest / entries / plan / import 两相):后端 ∧ 属主面 ∧ 文件历史店 ∧ 导出两面 ∧
151
+ * staged 导入面 ∧ policy 店能清(overwrite-dst 的 commit 要擦目的端旧 policy 行)。文件历史的 blob 搬运是另一只事实。 */
152
+ export declare function sessionSync(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy, {
153
+ backend: Store<"backend">;
154
+ sessionStorage: SyncSessionStore;
155
+ historyStore: ServiceFileHistoryStore;
156
+ }>;
157
+ /** blob 两面齐备的文件历史店(marker 门,不做名字探测:local 的引擎文件店带一只同名私有助手)。 */
158
+ export type SyncBlobHistoryStore = ServiceFileHistoryStore & {
159
+ readonly syncBlobFaces: true;
160
+ } & {
161
+ [P in "putBlob" | "getBlob"]-?: NonNullable<ServiceFileHistoryStore[P]>;
162
+ };
163
+ /** 会话同步的**文件历史半族**:对话半族 ∧ 文件历史店有 blob 搬运面(只有 SQL 两只店有)。 */
164
+ export declare function sessionSyncFileHistory(d: Pick<Deps, "backend" | "sessionStorage" | "fileHistoryStore" | "sessionPolicyStore">): Fact<SessionSyncWhy | "sync_blob_faces_absent", {
165
+ historyStore: SyncBlobHistoryStore;
166
+ }>;
167
+ /** 持久审批底座(checkpoint 店)在场 —— `/v1/approvals/*` 与 `/v1/assistant/*` 整条车道、会话 wake 都站在它上面。 */
168
+ export declare function checkpointPark(d: Pick<Deps, "checkpointStore">): Fact<"checkpoint_store_absent", {
169
+ checkpointStore: Store<"checkpointStore">;
170
+ }>;
171
+ export declare function elicitation(d: Pick<Deps, "elicitation">): Fact<"elicitation_disabled", {
172
+ coordinator: Store<"elicitation">;
173
+ }>;
174
+ export declare function askUserQuestion(d: Pick<Deps, "question">): Fact<"ask_question_disabled", {
175
+ coordinator: Store<"question">;
176
+ }>;
177
+ export declare function toolApproval(d: Pick<Deps, "toolApproval">): Fact<"tool_approval_disabled", {
178
+ coordinator: Store<"toolApproval">;
179
+ }>;
180
+ type StreamApprovalWhy = "tool_approval_disabled" | "stream_approval_disabled" | "store_backend_absent" | "checkpoint_store_absent";
181
+ type ActiveStreamApproval = Extract<ReturnType<typeof resolveStreamApprovalGate>, {
182
+ active: true;
183
+ }>;
184
+ /** 流内审批协议在场 —— 判据的属主仍是 `resolveStreamApprovalGate`(三条执行腿的装配也读它);本事实把它的拒因译进 why 闭集。 */
185
+ export declare function streamApproval(d: Pick<Deps, "toolApproval" | "config" | "backend" | "checkpointStore">): Fact<StreamApprovalWhy, {
186
+ askStore: ActiveStreamApproval["askStore"];
187
+ }>;
188
+ export declare function deviceLane(d: Pick<Deps, "deviceHub">): Fact<"device_hub_absent", {
189
+ hub: Store<"deviceHub">;
190
+ }>;
191
+ /** 设备管理三动词(列 / 读 / 换绑):hub ∧ 设备店 ∧ 入网 ∧ 持久 run 账面(换绑的「无在飞 run」门要它)。 */
192
+ export declare function deviceManagement(d: Pick<Deps, "deviceHub" | "deviceStore" | "deviceEnrollment" | "runStore">): Fact<"device_hub_absent" | "device_store_absent" | "device_enrollment_absent" | "run_store_absent", {
193
+ hub: Store<"deviceHub">;
194
+ store: Store<"deviceStore">;
195
+ enrollment: Store<"deviceEnrollment">;
196
+ runStore: Store<"runStore">;
197
+ }>;
198
+ export declare function fleetStream(d: Pick<Deps, "fleetBus">): Fact<"fleet_bus_absent", {
199
+ fleetBus: Store<"fleetBus">;
200
+ }>;
201
+ /** workspace 浏览面:随整树快照纪元退役,恒不可用(位恒 false、路由恒 501,两边读这同一句)。**结构上**没有可用臂(型 = `FactUnavailable`,
202
+ * 不是 `Fact`)—— 调用方不写「可用时」那一臂,端点只按 why 穷举作答。 */
203
+ export declare function workspaceBrowse(): FactUnavailable<"workspace_retired">;
204
+ export declare function leaderLane(d: Pick<Deps, "leaderEndpoint">): Fact<"leader_endpoint_absent", {
205
+ endpoint: Store<"leaderEndpoint">;
206
+ }>;
207
+ export declare function imagePool(d: Pick<Deps, "imageIndex">): Fact<"image_index_absent", {
208
+ imageIndex: Store<"imageIndex">;
209
+ }>;
210
+ export declare function agentRoster(d: Pick<Deps, "backgroundAgentStore">): Fact<"background_agent_store_absent", {
211
+ store: Store<"backgroundAgentStore">;
212
+ }>;
213
+ export declare function sendFileLedger(d: Pick<Deps, "sendFileLedger">): Fact<"sendfile_ledger_absent", {
214
+ ledger: Store<"sendFileLedger">;
215
+ }>;
216
+ /** org 共享记忆只读面:供给面 ∧ org 折叠面(没有成员性判据的共享读面比没有更糟)。 */
217
+ export declare function sharedMemoryRead(d: Pick<Deps, "sharedMemoryStore" | "orgMemoryDirectory">): Fact<"shared_memory_store_absent" | "org_memory_directory_absent", {
218
+ provider: Store<"sharedMemoryStore">;
219
+ directory: Store<"orgMemoryDirectory">;
220
+ }>;
221
+ /** operator 名单非空。空名单下 `explicitOperatorOk` 对任何身份恒假 ⇒ 这一族的口对谁都打不通 = 部署不可用(不是鉴权拒)。
222
+ *
223
+ * operator 族的复合事实**先判名单、再判设施**:门序是「身份 → 名单空(501)→ 授权(403)→ 设施缺席(501)」——
224
+ * 名单空时没有人过得了授权,不先判它,这一形就永远答成 403;设施缺席则留在授权之后答(不对非 operator 透露部署形态)。 */
225
+ export declare function operatorLane(d: {
226
+ readonly config: Pick<ServiceConfig, "operatorPrincipals">;
227
+ }): Fact<"operator_principals_empty">;
228
+ type AdoptionCapableBackend = Store<"backend"> & {
229
+ adoptionLog(): ReturnType<NonNullable<Store<"backend">["adoptionLog"]>>;
230
+ };
231
+ export declare function adoption(d: Pick<Deps, "config" | "backend">): Fact<"operator_principals_empty" | "adoption_store_absent", {
232
+ backend: AdoptionCapableBackend;
233
+ }>;
234
+ export declare function memoryBundle(d: Pick<Deps, "config" | "memoryBundleExport" | "memoryBundleImport">): Fact<"operator_principals_empty" | "memory_bundle_faces_absent", {
235
+ exportScopes: Store<"memoryBundleExport">;
236
+ importBundle: Store<"memoryBundleImport">;
237
+ }>;
238
+ export declare function memoryCompliance(d: Pick<Deps, "config" | "memoryCompliance">): Fact<"operator_principals_empty" | "memory_compliance_faces_absent", {
239
+ faces: Store<"memoryCompliance">;
240
+ }>;
241
+ export declare function memoryOrigin(d: Pick<Deps, "config" | "memoryOriginFace">): Fact<"operator_principals_empty" | "memory_origin_faces_absent", {
242
+ faces: Store<"memoryOriginFace">;
243
+ }>;
244
+ /** 记忆整理阀门的两口。阀门关是一句旋钮表态(不是授权问题),所以它**先于**名单判:关着就对谁都答「关着」。 */
245
+ export declare function memoryConsolidation(d: Pick<Deps, "config" | "memoryConsolidation">): Fact<"consolidation_valve_closed" | "operator_principals_empty", {
246
+ valve: Store<"memoryConsolidation">;
247
+ }>;
248
+ export declare function memoryOptOutGrant(d: Pick<Deps, "config" | "memoryOptOutGrant">): Fact<"operator_principals_empty" | "memory_optout_grant_absent", {
249
+ store: Store<"memoryOptOutGrant">;
250
+ }>;
251
+ type QueryableOutcomeSink = WithMethods<Store<"outcomeSink">, "summary">;
252
+ /** 可查询的 outcome 账面 ∧(单用户 ∨ operator 名单非空)—— 单用户形唯一的用户就是 operator,这一口不判名单。 */
253
+ export declare function outcomeLedger(d: Pick<Deps, "config" | "outcomeSink">): Fact<"operator_principals_empty" | "outcome_ledger_unqueryable", {
254
+ sink: QueryableOutcomeSink;
255
+ }>;
256
+ /** 配置目录。旋钮关是一句表态(合规部署不想让部署事实上 wire),先于名单判。 */
257
+ export declare function configCatalog(d: Pick<Deps, "config">): Fact<"config_catalog_disabled" | "operator_principals_empty">;
258
+ export declare function ruleLane(d: Pick<Deps, "ruleConsent">): Fact<"rule_store_absent", {
259
+ lane: Store<"ruleConsent">;
260
+ }>;
261
+ /** 规则车道**对这个调用方**够不够得着:车道在场 ∧ 本请求有已验 principal(规则车道按 principal 寻址,
262
+ * `routes/rules.ts` 的域头对无 principal 一律 401)。按调用方算 —— 同一台 worker 对不同请求答案不同。 */
263
+ export declare function ruleLaneForCaller(d: Pick<Deps, "ruleConsent">, principal: string | undefined): Fact<"rule_store_absent" | "caller_principal_absent">;
264
+ /** 调用方自带 MCP 规格兑不兑现 —— 判据属主仍是 `mcpInjectionHonored`(提交腿的字段门也读它)。 */
265
+ export declare function mcpInjection(d: Pick<Deps, "config">): Fact<"caller_mcp_injection_refused">;
266
+ /** server-as-peer:旋钮开 ∧ 持久 run 账面在场。两只 JSON-RPC 方法(`message/send` / `tasks/get`)都要 run 店 ——
267
+ * 没有它,这个 peer 什么都做不了,对外就不该存在(卡与 RPC 一起 404)。 */
268
+ export declare function a2aServe(d: Pick<Deps, "config" | "runStore">): Fact<"a2a_serve_off" | "run_store_absent", {
269
+ serve: NonNullable<ServiceConfig["a2aServe"]>;
270
+ runStore: Store<"runStore">;
271
+ }>;
272
+ /** 引擎能不能自编排(core 单源 `workflowsCapability`,boot 算好经 `workflowsCapable` 递来;缺席回落行店代理)。 */
273
+ export declare function selfOrchestrationEngine(d: Pick<Deps, "workflowsCapable" | "workflowRunStore">): Fact<"workflow_engine_absent">;
274
+ /** 部署级准入:引擎在、而本部署对任何 principal 都授不出去(多租户 + 没接 entitlement 源)⇒ 不可用。
275
+ * 判据属主仍是 `selfOrchestrationDenial`(与提交面准入同一只)。 */
276
+ export declare function selfOrchestrationAdmission(d: Pick<Deps, "config">): Fact<"entitlement_resolver_absent">;
277
+ /** 「这台机器上真跑得起来」的自编排 = 引擎能 ∧ 准入不拒。 */
278
+ export declare function selfOrchestration(d: Pick<Deps, "config" | "workflowsCapable" | "workflowRunStore">): Fact<"workflow_engine_absent" | "entitlement_resolver_absent">;
279
+ /** workflow run 的持久列举三口(list / detail / stream)= 行店(能力位 `workflowsList` 投影这一只)。 */
280
+ export declare function workflowRuns(d: Pick<Deps, "workflowRunStore">): Fact<"workflow_run_store_absent", {
281
+ store: Store<"workflowRunStore">;
282
+ }>;
283
+ export declare function workflowJournal(d: Pick<Deps, "workflowJournalStore">): Fact<"workflow_journal_store_absent", {
284
+ journal: Store<"workflowJournalStore">;
285
+ }>;
286
+ /** workflow run 的 **journal 口**(`GET /v1/workflows/:id/journal`;能力位 `workflowsJournal` 投影这一只)= 行店 ∧ journal 店 —— journal 口要先按行判属主。
287
+ * 与 `workflowRuns` 是**拆开**的两只(照 `sessionSync` / `sessionSyncFileHistory`):无后端 + 自编排的三形上行店在、journal 店不在,
288
+ * 三口真能用而 journal 口恒 501 —— 合成一位总有一半在说假话。 */
289
+ export declare function workflowsJournal(d: Pick<Deps, "workflowRunStore" | "workflowJournalStore">): Fact<"workflow_run_store_absent" | "workflow_journal_store_absent", {
290
+ store: Store<"workflowRunStore">;
291
+ journal: Store<"workflowJournalStore">;
292
+ }>;
293
+ /** 自唤醒调度器挂在宿主 env 上:`SCHEDULER_ENABLED` ∧ 单用户 ∧ host 车道。装配(`boot/execution-env.ts`)与能力位同调。 */
294
+ export declare function hostScheduler(c: Pick<ServiceConfig, "schedulerEnabled" | "requirePrincipal" | "remoteExec">): Fact<"scheduler_disabled" | "multi_tenant_deployment" | "not_host_lane">;
295
+ export {};
296
+ //# sourceMappingURL=capability-facts.d.ts.map