@sema-agent/server 7.123.0 → 7.124.1

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 (224) hide show
  1. package/MIGRATION.md +138 -0
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/USAGE.md +53 -51
  5. package/dist/approval-ask-audit-store.d.ts +27 -32
  6. package/dist/approval-ask-audit-store.js +10 -9
  7. package/dist/approval-crash-convergence.d.ts +2 -2
  8. package/dist/approval-crash-convergence.js +5 -5
  9. package/dist/approval-deny-reasons.d.ts +163 -51
  10. package/dist/approval-deny-reasons.js +79 -8
  11. package/dist/approval-policy-settlement.d.ts +4 -1
  12. package/dist/approval-policy-settlement.js +3 -2
  13. package/dist/approval-reconciler.d.ts +3 -3
  14. package/dist/approval-reconciler.js +10 -10
  15. package/dist/approval.d.ts +1 -1
  16. package/dist/approval.js +1 -1
  17. package/dist/audit.js +1 -1
  18. package/dist/auth-bridge.d.ts +8 -8
  19. package/dist/auth-bridge.js +6 -6
  20. package/dist/auth-keys.d.ts +2 -2
  21. package/dist/auto-mode-face.d.ts +1 -1
  22. package/dist/boot/budget-tracing.js +1 -1
  23. package/dist/boot/execution-env.js +1 -0
  24. package/dist/boot/leader.d.ts +1 -1
  25. package/dist/boot/memory-consolidation.d.ts +4 -4
  26. package/dist/boot/org-memory.d.ts +3 -3
  27. package/dist/boot/org-memory.js +5 -5
  28. package/dist/boot/resolve-spec.js +7 -7
  29. package/dist/boot/runner-deps.d.ts +1 -1
  30. package/dist/boot/runtime-caps.d.ts +1 -1
  31. package/dist/boot/runtime-caps.js +10 -10
  32. package/dist/boot/shutdown.d.ts +2 -2
  33. package/dist/boot/shutdown.js +2 -2
  34. package/dist/boot/side-query-lane.d.ts +3 -3
  35. package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
  36. package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
  37. package/dist/boot/stage-03-store-backend.d.ts +2 -2
  38. package/dist/boot/stage-04-stores.d.ts +1 -1
  39. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  40. package/dist/boot/stage-06-runners.d.ts +2 -2
  41. package/dist/boot/stage-06-runners.js +6 -6
  42. package/dist/boot/stage-07-capability-layer.d.ts +2 -2
  43. package/dist/boot/stage-07-capability-layer.js +6 -5
  44. package/dist/boot/stage-08-reapers.d.ts +3 -3
  45. package/dist/boot/stage-08-reapers.js +3 -3
  46. package/dist/boot/stage-09-leader.d.ts +3 -3
  47. package/dist/boot/stage-09-leader.js +7 -7
  48. package/dist/boot/stage-10-http-server.d.ts +3 -3
  49. package/dist/boot/stage-10-http-server.js +19 -19
  50. package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
  51. package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
  52. package/dist/boot/{config-center.js → web-admin.js} +38 -22
  53. package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
  54. package/dist/brain.d.ts +1 -1
  55. package/dist/brain.js +1 -1
  56. package/dist/budget.d.ts +3 -3
  57. package/dist/canonical-json.d.ts +2 -2
  58. package/dist/capabilities/center-plugins.d.ts +1 -1
  59. package/dist/capabilities/center-wiring.d.ts +12 -5
  60. package/dist/capabilities/center-wiring.js +11 -2
  61. package/dist/capabilities/composite-members.d.ts +1 -1
  62. package/dist/capabilities/composite-members.js +1 -1
  63. package/dist/capabilities/scenarios.js +2 -2
  64. package/dist/capabilities/team.d.ts +1 -1
  65. package/dist/capabilities/tool-defer.d.ts +1 -1
  66. package/dist/center-credential-renewer.d.ts +1 -1
  67. package/dist/center-credential-renewer.js +7 -7
  68. package/dist/center-credential.d.ts +9 -9
  69. package/dist/center-credential.js +6 -6
  70. package/dist/config-catalog.d.ts +7 -10
  71. package/dist/config-catalog.js +15 -15
  72. package/dist/config-d-migration.d.ts +32 -0
  73. package/dist/config-d-migration.js +59 -0
  74. package/dist/config-invariants.d.ts +14 -4
  75. package/dist/config-invariants.js +31 -2
  76. package/dist/config-lkg.d.ts +26 -6
  77. package/dist/config-lkg.js +43 -14
  78. package/dist/config-provider.d.ts +23 -19
  79. package/dist/config-provider.js +24 -26
  80. package/dist/config-types.d.ts +52 -51
  81. package/dist/config.d.ts +9 -46
  82. package/dist/config.js +33 -92
  83. package/dist/execution-lane-caps.d.ts +1 -1
  84. package/dist/fleet/drain-entry.d.ts +1 -1
  85. package/dist/fleet/engine-signal.d.ts +8 -8
  86. package/dist/fleet/fleet-bus.d.ts +12 -3
  87. package/dist/fleet/fleet-bus.js +13 -9
  88. package/dist/fleet/serving-lease.d.ts +3 -3
  89. package/dist/fleet/serving-lease.js +1 -1
  90. package/dist/fleet-client.d.ts +7 -7
  91. package/dist/fleet-client.js +5 -4
  92. package/dist/fleet-lease.d.ts +3 -3
  93. package/dist/fleet-lease.js +2 -2
  94. package/dist/host-lsp-manager.d.ts +1 -1
  95. package/dist/hosted-posture.d.ts +4 -4
  96. package/dist/http/admission.js +4 -4
  97. package/dist/http/checkpoint-ctx.d.ts +20 -3
  98. package/dist/http/checkpoint-ctx.js +13 -5
  99. package/dist/http/dispatch.js +2 -2
  100. package/dist/http/durable-run-leg.js +2 -1
  101. package/dist/http/health-self-report.d.ts +4 -4
  102. package/dist/http/health-self-report.js +3 -3
  103. package/dist/http/idempotency.d.ts +1 -1
  104. package/dist/http/resume-legs.d.ts +4 -3
  105. package/dist/http/resume-legs.js +31 -18
  106. package/dist/http/route-ctx.d.ts +8 -0
  107. package/dist/http/routes/admin-config-refresh.d.ts +1 -1
  108. package/dist/http/routes/admin-config-refresh.js +1 -1
  109. package/dist/http/routes/admin-drain.d.ts +1 -1
  110. package/dist/http/routes/admin-drain.js +5 -4
  111. package/dist/http/routes/approvals-assistant.js +4 -4
  112. package/dist/http/routes/capabilities.js +5 -5
  113. package/dist/http/routes/config-catalog.js +2 -3
  114. package/dist/http/routes/diagnostics.js +1 -1
  115. package/dist/http/routes/runs.js +8 -4
  116. package/dist/http/routes/sessions-list.js +2 -1
  117. package/dist/http/routes/sessions.js +1 -1
  118. package/dist/http/routes/side-query.js +3 -3
  119. package/dist/http/routes/tasks.js +3 -2
  120. package/dist/http/run-meta.d.ts +1 -1
  121. package/dist/http/run-meta.js +2 -2
  122. package/dist/http/server.d.ts +7 -7
  123. package/dist/http/server.js +1 -1
  124. package/dist/http/stored-body-replay.js +3 -2
  125. package/dist/index.d.ts +0 -1
  126. package/dist/index.js +0 -1
  127. package/dist/key-resolver.d.ts +1 -1
  128. package/dist/leader/wire.d.ts +2 -2
  129. package/dist/leader/wire.js +2 -1
  130. package/dist/main.js +1 -1
  131. package/dist/mcp-tool-faces.d.ts +2 -2
  132. package/dist/model-entry-refusal.d.ts +3 -3
  133. package/dist/model-entry-refusal.js +4 -4
  134. package/dist/model-provider.d.ts +2 -2
  135. package/dist/model-route-endpoint.d.ts +1 -1
  136. package/dist/model-route-url.d.ts +1 -1
  137. package/dist/model-route-url.js +2 -1
  138. package/dist/model-select.d.ts +24 -21
  139. package/dist/model-select.js +22 -17
  140. package/dist/observability/metrics.d.ts +1 -1
  141. package/dist/org-memory-admission.d.ts +1 -1
  142. package/dist/plugins/approval-ask-store-file.d.ts +4 -2
  143. package/dist/plugins/approval-ask-store-file.js +3 -3
  144. package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
  145. package/dist/plugins/approval-ask-store-memory.js +10 -4
  146. package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
  147. package/dist/plugins/approval-ask-store-sql.js +20 -13
  148. package/dist/plugins/caching-session-store.d.ts +0 -10
  149. package/dist/plugins/caching-session-store.js +0 -3
  150. package/dist/plugins/file-run-store.js +9 -3
  151. package/dist/plugins/leader-run-store-sql.d.ts +3 -2
  152. package/dist/plugins/leader-run-store-sql.js +3 -2
  153. package/dist/plugins/local-session-store.d.ts +20 -27
  154. package/dist/plugins/local-session-store.js +19 -17
  155. package/dist/plugins/memory-run-store.js +9 -3
  156. package/dist/plugins/one-time-migrations.js +26 -2
  157. package/dist/plugins/scheduler-support.d.ts +26 -7
  158. package/dist/plugins/scheduler-support.js +96 -53
  159. package/dist/plugins/store-backend.js +1 -1
  160. package/dist/plugins/store-contracts.d.ts +20 -4
  161. package/dist/plugins/web-search.d.ts +1 -1
  162. package/dist/plugins/web-search.js +2 -1
  163. package/dist/posture-source.d.ts +1 -1
  164. package/dist/read-face-posture.d.ts +3 -3
  165. package/dist/read-face-posture.js +1 -1
  166. package/dist/run-local.js +6 -3
  167. package/dist/runtime-caps-resolver.d.ts +4 -4
  168. package/dist/runtime-caps-resolver.js +2 -2
  169. package/dist/runtime-governance.d.ts +5 -5
  170. package/dist/sealed-key.d.ts +4 -4
  171. package/dist/sealed-key.js +3 -2
  172. package/dist/security.d.ts +3 -3
  173. package/dist/service-version.d.ts +1 -1
  174. package/dist/service-version.js +5 -0
  175. package/dist/session-titler.d.ts +0 -11
  176. package/dist/session-titler.js +3 -5
  177. package/dist/shared-memory-scope-authorizer.d.ts +4 -4
  178. package/dist/task-a2a.d.ts +1 -1
  179. package/dist/tool-approval.d.ts +43 -4
  180. package/dist/tool-approval.js +147 -98
  181. package/dist/trace/core-keyset-guard.d.ts +1 -1
  182. package/dist/trace/project.d.ts +3 -3
  183. package/dist/trace/redact.d.ts +2 -23
  184. package/dist/trace/redact.js +17 -15
  185. package/dist/trace/self-minted-wire.d.ts +134 -3
  186. package/dist/trace/self-minted-wire.js +46 -9
  187. package/dist/url-refusal.d.ts +35 -0
  188. package/dist/url-refusal.js +15 -0
  189. package/dist/user-authored-text.d.ts +31 -0
  190. package/dist/user-authored-text.js +18 -0
  191. package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
  192. package/dist/{config-center → web-admin-client}/apply-effective.js +100 -119
  193. package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
  194. package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
  195. package/dist/{config-center → web-admin-client}/center-request.js +5 -4
  196. package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
  197. package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
  198. package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
  199. package/dist/{config-center → web-admin-client}/facade.js +2 -2
  200. package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
  201. package/dist/{config-center → web-admin-client}/http-client.js +12 -12
  202. package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
  203. package/dist/{config-center → web-admin-client}/read-face.js +4 -4
  204. package/dist/{config-center → web-admin-client}/read-warnings.d.ts +23 -16
  205. package/dist/{config-center → web-admin-client}/read-warnings.js +33 -23
  206. package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
  207. package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
  208. package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
  209. package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
  210. package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
  211. package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
  212. package/dist/{config-center → web-admin-client}/types.d.ts +12 -39
  213. package/package.json +2 -2
  214. package/skills/find-skills.md +2 -2
  215. package/dist/url-shape.d.ts +0 -31
  216. package/dist/url-shape.js +0 -41
  217. /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
  218. /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
  219. /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
  220. /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
  221. /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
  222. /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
  223. /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
  224. /package/dist/{config-center → web-admin-client}/types.js +0 -0
package/dist/config.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { DEFAULT_MODEL_REF } from "./model-select.js";
2
+ import { DEFAULT_AT_MENTION, DEFAULT_MODEL_REF } from "./model-select.js";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, isModelPriced, PROTOCOL_TABLE, RECOMMENDED_SENSITIVE_PATTERNS, judgeRuleToolName, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules, WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable } from "@sema-agent/core";
7
- import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES, CENTER_CREDENTIAL_ENV } from "@sema-agent/settings-schema";
7
+ import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES, WEB_ADMIN_ENV, retiredEnvRefusal } from "@sema-agent/settings-schema";
8
8
  import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
9
9
  import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
10
10
  import { isV2ScopeKey, memoryReplicationCoverage, replicationCovers } from "./memory-scope.js";
@@ -13,7 +13,7 @@ import { GIT_API_KINDS, isGitApiKind } from "./git-api-kind.js";
13
13
  import { CONFIG_PROVIDER_WORDS, RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC, RESILIENCE_DEFAULTS, TASK_WRITE_FACE_ESCALATIONS, MAX_TIMER_DELAY_MS, AUTO_MODE_CLASSIFIER_TIMEOUT_BOUNDS, DRAIN_GRACE_FLOOR_MS, DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS, DRAIN_SECOND_SIGNAL_MIN_GAP_DEFAULT_MS, FIRST_BYTE_TIMEOUT_BOUNDS, FLEET_LEASE_OUTAGE_MAX_DEFAULT_MS, fleetScopeOf } from "./config-types.js";
14
14
  import { FLEET_GENERATION_ENV, FLEET_SCOPE_ENV, SERVING_LEASE_TTL_FLOOR_MS, isCanonicalGeneration } from "@sema-agent/settings-schema/fleet";
15
15
  import { ScopeId } from "@sema-agent/settings-schema/api/scopes";
16
- import { centerLaneConfigured, pathBaseUrlRefusal } from "./config-center/center-request.js";
16
+ import { centerLaneConfigured, pathBaseUrlRefusal } from "./web-admin-client/center-request.js";
17
17
  import { resolveLocalDataRoot } from "./local-data-root.js";
18
18
  import { buildWriteProtectionPosture } from "./write-protection.js";
19
19
  import { normalizeSshFingerprint } from "./ssh-host-key.js";
@@ -22,7 +22,7 @@ import { THINKING_LEVELS, THINKING_FORMATS, buildModelCompat, isThinkingFormat,
22
22
  import {} from "./posture-source.js";
23
23
  import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
24
24
  import { describeUnmatchableRuleName, ruleEntryToolName, unmatchableRuleNameOf } from "./namespaced-rule-name.js";
25
- import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal } from "./config-invariants.js";
25
+ import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal } from "./config-invariants.js";
26
26
  import { declaredSemaConfigDir } from "./sema-config-dir.js";
27
27
  import { lkgPathOverrideOf } from "./config-lkg.js";
28
28
  import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneOf, executionLaneRequiredRefusal, isSingleMachineDefaultLane, laneRequiredEnv } from "./execution-lane-caps.js";
@@ -33,7 +33,8 @@ import { createCenterCredentialSource, readCenterCredentialDeclaration } from ".
33
33
  import { parseCenterCredentialRenewLeadMs } from "./center-credential-renewer.js";
34
34
  import { modelProviderRefusal } from "./model-provider.js";
35
35
  import { modelRouteUrlRefusal } from "./model-route-url.js";
36
- import { buildHttpUrlRefusal, httpUrlFlaws } from "./url-shape.js";
36
+ import { httpUrlFlaws } from "@sema-agent/settings-schema";
37
+ import { buildHttpUrlRefusal } from "./url-refusal.js";
37
38
  import { csvOf, envLaneTable, judgeModelRouteGap, mintedCheapId, readModelRouteEnv } from "./model-route-gap.js";
38
39
  import { displayListEntry } from "./list-entry-display.js";
39
40
  import { buildDisplaySafeUrl, redactSecrets } from "./trace/redact.js";
@@ -113,74 +114,10 @@ function defaultSkillsDir() {
113
114
  return "skills";
114
115
  }
115
116
  }
116
- export const RETIRED_ENV_REFUSAL_CODE = "config.env_key_retired";
117
- export const RETIRED_ENVS = [
118
- ["TIDB_HOST", "MYSQL_HOST", "renamed"], ["TIDB_PORT", "MYSQL_PORT", "renamed"], ["TIDB_USER", "MYSQL_USER", "renamed"],
119
- ["TIDB_PASSWORD", "MYSQL_PASSWORD", "renamed"], ["TIDB_DATABASE", "MYSQL_DATABASE", "renamed"], ["TIDB_POOL_SIZE", "MYSQL_POOL_SIZE", "renamed"],
120
- ["CONFIG_CENTER_URL", "SEMA_REGISTRY_URL", "renamed"], ["CONFIG_CENTER_TOKEN", CENTER_CREDENTIAL_ENV.token, "renamed"],
121
- ["CONFIG_CENTER_DRY_RUN", "SEMA_REGISTRY_DRY_RUN", "renamed"], ["CONFIG_CENTER_WORKER", "SEMA_REGISTRY_WORKER", "renamed"],
122
- ["ANTHROPIC_BASEURL", "ANTHROPIC_BASE_URL", "renamed"],
123
- ["REGISTRY_ADMIN_TOKEN", "SEMA_REGISTRY_ADMIN_TOKEN", "renamed"],
124
- ["OA_API_BASEURL", "the OA scenario was removed in 5.0.0", "removed"],
125
- ["OA_SERVICE_TOKEN", "the OA scenario was removed in 5.0.0", "removed"],
126
- ["OA_ISSUE_TOKEN", "the OA scenario was removed in 5.0.0", "removed"],
127
- ["OA_ISSUE_BASEURL", "the OA scenario was removed in 5.0.0", "removed"],
128
- ["OA_ISSUE_OWNER", "the OA scenario was removed in 5.0.0", "removed"],
129
- ["OA_ISSUE_REPO", "the OA scenario was removed in 5.0.0", "removed"],
130
- ["OA_ISSUE_LABELS", "the OA scenario was removed in 5.0.0", "removed"],
131
- ["APPROVAL_POLL_MS", "the OA poll-approval lane was removed in 5.0.0; the durable checkpoint lane is the only gate", "removed"],
132
- ["LEADER_CONFLICT_ROUNDS", "the bounded merge-conflict-resolution agent was deleted in 7.83.0 按 C-R63 删除,合不上交用户:leader 交回 result.conflict(分支 + 冲突文件),run 状态 needs_human", "removed"],
133
- [
134
- "MODEL_CONNECT_TIMEOUT_MS",
135
- "MODEL_FIRST_BYTE_TIMEOUT_MS",
136
- "replaced",
137
- "since core 7.33.0 the TCP + TLS connect clock is the transport's own; the wait from sending the request to its response headers — " +
138
- "what this key really bounded — is MODEL_FIRST_BYTE_TIMEOUT_MS (unset = core's own default, plus an upload allowance and one " +
139
- "widened retry; 0 = no engine clock on that segment and the transport's header / body clocks off too — the TCP + TLS connect " +
140
- "keeps the transport's own clock)",
141
- ],
142
- ["PROJECT_MEMORY_DISABLED", "PROJECT_MEMORY_ENABLED", "replaced", "negative-name alias retired in server 3.0.0 — unset it; the polarity is inverted: PROJECT_MEMORY_DISABLED=true is PROJECT_MEMORY_ENABLED=false (the positive name defaults on)"],
143
- ["CONFIG_LKG_DISABLED", "CONFIG_LKG_ENABLED", "replaced", "negative-name alias retired in server 3.0.0 — unset it; the polarity is inverted: CONFIG_LKG_DISABLED=true is CONFIG_LKG_ENABLED=false (the positive name defaults on)"],
144
- ["HOST_BG_DISABLED", "HOST_BG_ENABLED", "replaced", "negative-name alias retired in server 3.0.0 — unset it; the polarity is inverted: HOST_BG_DISABLED=true is HOST_BG_ENABLED=false (the positive name defaults on)"],
145
- ["HOST_EXEC_SPOOL_DISABLED", "HOST_EXEC_SPOOL_ENABLED", "replaced", "negative-name alias retired in server 3.0.0 — unset it; the polarity is inverted: HOST_EXEC_SPOOL_DISABLED=true is HOST_EXEC_SPOOL_ENABLED=false (the positive name defaults on)"],
146
- ["UNATTENDED_PERMISSION_MODE", "since server 7.109.0 the unattended legs (leader workers and their repair legs, run-local, and their durable resumes) always run permissionMode \"default\" with an approver that answers by ask class: a machine answers only \"ordinary\" asks, and every other class goes to the leg's approver seat (run-local's terminal prompt) or parks / is refused — there is no mode to choose", "removed"],
147
- ];
148
- for (const row of RETIRED_ENVS)
149
- Object.freeze(row);
150
- Object.freeze(RETIRED_ENVS);
151
- export function buildRetiredEnvWire() {
152
- return RETIRED_ENVS.map((row) => {
153
- switch (row[2]) {
154
- case "renamed":
155
- return { name: row[0], kind: row[2], replacement: row[1] };
156
- case "replaced":
157
- return { name: row[0], kind: row[2], replacement: row[1], reason: row[3] };
158
- case "removed":
159
- return { name: row[0], kind: row[2], reason: row[1] };
160
- default: {
161
- const unhandled = row;
162
- throw new Error(`unhandled retired-env kind: ${String(unhandled[2])}`);
163
- }
164
- }
165
- });
166
- }
167
- const RETIRED_ENV_SENTENCE = {
168
- renamed: (hits) => `${hits.map(([old, to]) => `${old} → use ${to}`).join("; ")} — rename the env key(s); the value semantics are unchanged`,
169
- replaced: (hits) => `${hits.map(([old, to, , why]) => `${old} → ${to} (${why})`).join("; ")} — set the replacement deliberately: ` +
170
- `its value semantics differ from the retired key's, so do not copy the old value across unread`,
171
- removed: (hits) => `${hits.map(([old, why]) => `${old} (${why})`).join("; ")} — remove the env key(s): the capability itself was retired, ` +
172
- `there is no replacement name and no rename that restores it`,
173
- };
174
- function retiredEnvSentence(kind, hit) {
175
- const ofKind = hit.filter((h) => h[2] === kind);
176
- return ofKind.length > 0 ? [RETIRED_ENV_SENTENCE[kind](ofKind)] : [];
177
- }
178
117
  function rejectRetiredEnvs() {
179
- const hit = RETIRED_ENVS.filter(([o]) => process.env[o] !== undefined && process.env[o] !== "");
180
- if (hit.length === 0)
181
- return;
182
- const parts = Object.keys(RETIRED_ENV_SENTENCE).flatMap((kind) => retiredEnvSentence(kind, hit));
183
- throw new Error(`retired env name(s) set [${RETIRED_ENV_REFUSAL_CODE}] — refused while present, whether or not the replacement is also set: ${parts.join(" | ")}.`);
118
+ const refusal = retiredEnvRefusal(process.env);
119
+ if (refusal !== undefined)
120
+ throw new Error(refusal);
184
121
  }
185
122
  export function numEnv(name, fallback) {
186
123
  return parseNumOrFail(name, env(name, fallback));
@@ -247,7 +184,7 @@ function parseConfigProvider() {
247
184
  return undefined;
248
185
  const word = CONFIG_PROVIDER_WORDS.find((w) => w === raw);
249
186
  if (word === undefined) {
250
- throw new Error(`env CONFIG_PROVIDER="${raw.slice(0, 120)}" must be one of: ${CONFIG_PROVIDER_WORDS.join(", ")} — or leave it unset (then SEMA_REGISTRY_URL, if set, selects the center as the config source; otherwise this worker is env-only). ` +
187
+ throw new Error(`env CONFIG_PROVIDER="${raw.slice(0, 120)}" must be one of: ${CONFIG_PROVIDER_WORDS.join(", ")} — or leave it unset (then ${WEB_ADMIN_ENV.url}, if set, selects the center as the config source; otherwise this worker is env-only). ` +
251
188
  `The word is matched exactly (no trimming, no case folding). Refusing to boot rather than guessing: the config source, the execution-lane default and the local config root all key on this one word.`);
252
189
  }
253
190
  return word;
@@ -937,8 +874,8 @@ function parseStoreDomain(ctx) {
937
874
  : undefined,
938
875
  };
939
876
  }
940
- export function isRosterGateArmed(configCenter) {
941
- return configCenter !== undefined && !configCenter.dryRun && process.env.CONFIG_REQUIRE_ROSTER === "true";
877
+ export function isRosterGateArmed(webAdmin) {
878
+ return webAdmin !== undefined && !webAdmin.dryRun && process.env.CONFIG_REQUIRE_ROSTER === "true";
942
879
  }
943
880
  function parseModelDomain() {
944
881
  const route = readModelRouteEnv(process.env);
@@ -1009,7 +946,7 @@ function parseModelDomain() {
1009
946
  CONFIG_NOTICES.push({
1010
947
  level: "warn",
1011
948
  event: "model_cheap_slot_without_main",
1012
- fields: { hint: "MODEL_CHEAP_ID is set but MODEL_ID is not — the env cheap slot derives from the env main model, so it is not minted; the catalog (config.d/models.json or the config center) serves the roles. Set MODEL_ID to use the env slots, or unset MODEL_CHEAP_ID to silence this line." },
949
+ fields: { hint: "MODEL_CHEAP_ID is set but MODEL_ID is not — the env cheap slot derives from the env main model, so it is not minted; the catalog (config.d/models.json or the web-admin) serves the roles. Set MODEL_ID to use the env slots, or unset MODEL_CHEAP_ID to silence this line." },
1013
950
  });
1014
951
  break;
1015
952
  case "same_as_main":
@@ -1145,7 +1082,7 @@ function parseModelDomain() {
1145
1082
  tiers: {},
1146
1083
  projects: {},
1147
1084
  roles,
1148
- atModelAllowlist: [],
1085
+ atMention: DEFAULT_AT_MENTION,
1149
1086
  cascadeLadder: csv("MODEL_CASCADE_LADDER"),
1150
1087
  degrade: process.env.MODEL_DEGRADE_TO
1151
1088
  ? {
@@ -2108,7 +2045,7 @@ function parseLimitsHttpDomain() {
2108
2045
  toolResultTtlSec: (() => {
2109
2046
  const ttl = numEnv("TOOL_RESULT_TTL_SEC", "86400");
2110
2047
  if (ttl <= 0) {
2111
- throw new Error(`env TOOL_RESULT_TTL_SEC=${ttl} must be > 0 — it is the age (seconds) after which an offloaded tool result is reaped, so 0 or less puts the cutoff at or after now and every reaper tick would delete ALL of them; there is no "off": set a larger value to keep results longer (the config center refuses the same value)`);
2048
+ throw new Error(`env TOOL_RESULT_TTL_SEC=${ttl} must be > 0 — it is the age (seconds) after which an offloaded tool result is reaped, so 0 or less puts the cutoff at or after now and every reaper tick would delete ALL of them; there is no "off": set a larger value to keep results longer (the web-admin refuses the same value)`);
2112
2049
  }
2113
2050
  return ttl;
2114
2051
  })(),
@@ -2165,13 +2102,13 @@ function parseGitApiKind(raw, baseUrl) {
2165
2102
  }
2166
2103
  function parseIntegrationsDomain(ctx) {
2167
2104
  const { requirePrincipal, configProvider } = ctx;
2168
- const registryUrl = parseCenterBaseUrl("SEMA_REGISTRY_URL", process.env.SEMA_REGISTRY_URL, `It is the center base every config pull, fleet and lease request is sent to; setting it selects the center as the config source.`);
2169
- const registryLiveUrl = parseCenterBaseUrl("SEMA_REGISTRY_LIVE_URL", process.env.SEMA_REGISTRY_LIVE_URL, `It is the center base the fleet liveness endpoints (heartbeat, serving lease) are sent to; unset it to send them to SEMA_REGISTRY_URL.`);
2170
- const registryWebUrl = parseCenterBaseUrl("SEMA_REGISTRY_WEB_URL", process.env.SEMA_REGISTRY_WEB_URL, `It is the center's web console base this engine reports on GET /health (center.webBaseUrl); unset it if the center has no web console to link to.`);
2171
- const configCenter = registryUrl !== undefined ? parseConfigCenter(registryUrl, requirePrincipal, registryLiveUrl, registryWebUrl) : undefined;
2105
+ const baseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.url, process.env[WEB_ADMIN_ENV.url], `It is the center base every config pull, fleet and lease request is sent to; setting it selects the center as the config source.`);
2106
+ const liveBaseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.liveUrl, process.env[WEB_ADMIN_ENV.liveUrl], `It is the center base the fleet liveness endpoints (heartbeat, serving lease) are sent to; unset it to send them to ${WEB_ADMIN_ENV.url}.`);
2107
+ const webBaseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.webUrl, process.env[WEB_ADMIN_ENV.webUrl], `It is the center's web console base this engine reports on GET /health (center.webBaseUrl); unset it if the center has no web console to link to.`);
2108
+ const webAdmin = baseUrl !== undefined ? parseWebAdmin(baseUrl, requirePrincipal, liveBaseUrl, webBaseUrl) : undefined;
2172
2109
  const fleetGeneration = parseFleetGeneration(process.env.FLEET_GENERATION);
2173
2110
  const fleetAdvertiseAddress = parseFleetAdvertiseAddress(process.env.FLEET_ADVERTISE_ADDRESS);
2174
- fleetFenceLaneOf({ ...fleetGeneration, configCenter, ...fleetAdvertiseAddress });
2111
+ fleetFenceLaneOf({ ...fleetGeneration, webAdmin, ...fleetAdvertiseAddress });
2175
2112
  return {
2176
2113
  pluginsAllowHosts: csvOf(process.env.PLUGINS_ALLOW_HOSTS ?? "github.com"),
2177
2114
  configBootFetchBudgetMs: clampEnvWithWarn("CONFIG_BOOT_FETCH_BUDGET_MS", "1500", 0),
@@ -2181,7 +2118,7 @@ function parseIntegrationsDomain(ctx) {
2181
2118
  defaultScenario: env("DEFAULT_SCENARIO", "code"),
2182
2119
  skillsDir: env("SKILLS_DIR", defaultSkillsDir()),
2183
2120
  centerCredentialRenewLeadMs: parseCenterCredentialRenewLeadMs(process.env.CENTER_CREDENTIAL_RENEW_LEAD_MS),
2184
- configCenter,
2121
+ webAdmin,
2185
2122
  fleetLeaseFailClosed: parseFleetLeaseFailClosed(process.env.FLEET_LEASE_FAIL_CLOSED, requirePrincipal),
2186
2123
  ...fleetGeneration,
2187
2124
  fleetScope: parseFleetScope(process.env.FLEET_SCOPE),
@@ -2239,9 +2176,9 @@ export function fleetFenceLaneOf(cfg) {
2239
2176
  return undefined;
2240
2177
  const laneConfigured = centerLaneConfigured(cfg);
2241
2178
  if (laneConfigured && cfg.fleetAdvertiseAddress !== undefined)
2242
- return { center: cfg.configCenter, generation };
2179
+ return { center: cfg.webAdmin, generation };
2243
2180
  const missing = [
2244
- ...(laneConfigured ? [] : [`the center lane (SEMA_REGISTRY_URL + ${CENTER_CREDENTIAL_ENV.token} or ${CENTER_CREDENTIAL_ENV.tokenFile} + SEMA_REGISTRY_WORKER)`]),
2181
+ ...(laneConfigured ? [] : [`the center lane (${WEB_ADMIN_ENV.url} + ${WEB_ADMIN_ENV.token} or ${WEB_ADMIN_ENV.tokenFile} + ${WEB_ADMIN_ENV.worker})`]),
2245
2182
  ...(cfg.fleetAdvertiseAddress === undefined ? ["the announce address (FLEET_ADVERTISE_ADDRESS)"] : []),
2246
2183
  ];
2247
2184
  throw fleetEnvRefusal("member_unfenced", `fleet member cannot be fenced — env FLEET_GENERATION=${JSON.stringify(generation)} makes this engine a fleet member, ` +
@@ -2276,15 +2213,15 @@ function parseCenterBaseUrl(name, raw, role) {
2276
2213
  throw new Error(`${refusal}. ${role}`);
2277
2214
  return raw;
2278
2215
  }
2279
- function parseConfigCenter(baseUrl, requirePrincipal, liveBaseUrl, webBaseUrl) {
2280
- const worker = process.env.SEMA_REGISTRY_WORKER || undefined;
2216
+ function parseWebAdmin(baseUrl, requirePrincipal, liveBaseUrl, webBaseUrl) {
2217
+ const worker = process.env[WEB_ADMIN_ENV.worker] || undefined;
2281
2218
  const declared = readCenterCredentialDeclaration();
2282
2219
  return {
2283
2220
  baseUrl,
2284
2221
  ...(liveBaseUrl !== undefined ? { liveBaseUrl } : {}),
2285
2222
  ...(webBaseUrl !== undefined ? { webBaseUrl } : {}),
2286
2223
  credential: createCenterCredentialSource(declared.from === "file" ? { ...declared, multiTenant: requirePrincipal } : declared, worker),
2287
- dryRun: boolEnv("SEMA_REGISTRY_DRY_RUN", false),
2224
+ dryRun: boolEnv(WEB_ADMIN_ENV.dryRun, false),
2288
2225
  worker,
2289
2226
  };
2290
2227
  }
@@ -2371,7 +2308,7 @@ const STORE_GROUP_KEYS = [
2371
2308
  ];
2372
2309
  const MODEL_PLANE_GROUP_KEYS = [
2373
2310
  "gatewayBaseUrl", "gatewayApiKey", "gatewayFallbackUrls", "gatewayMaxRetries", "anthropic", "resilience", "model", "envModel", "models",
2374
- "modelApiKeyEnv", "modelApiKeys", "modelRefusals", "droppedCatalogEntries", "modelQuotaWeights", "tiers", "projects", "roles", "atModelAllowlist", "cascadeLadder", "degrade",
2311
+ "modelApiKeyEnv", "modelApiKeys", "modelRefusals", "droppedCatalogEntries", "modelQuotaWeights", "tiers", "projects", "roles", "atMention", "cascadeLadder", "degrade",
2375
2312
  ];
2376
2313
  const APPROVAL_GROUP_KEYS = [
2377
2314
  "approvalRequire", "approvalDeny", "approvalTimeoutSec", "approvalAutoBudget", "approvalNeverAuto", "approvalGrant",
@@ -2411,7 +2348,7 @@ const LIMITS_HTTP_GROUP_KEYS = [
2411
2348
  const OBSERVABILITY_GROUP_KEYS = ["metricsToken", "traceToken", "toolTrace", "traceThinking", "logLevel", "otel"];
2412
2349
  const INTEGRATIONS_GROUP_KEYS = [
2413
2350
  "pluginsAllowHosts", "mcpServers", "a2aPeers", "a2aServe", "configBootFetchBudgetMs", "gitApiBaseUrl", "gitApiToken", "gitApiKind", "defaultScenario",
2414
- "skillsDir", "centerCredentialRenewLeadMs", "configCenter", "fleetLeaseFailClosed", "fleetGeneration", "fleetScope", "fleetAdvertiseAddress", "fleetLeaseOutageMaxMs", "configProvider", "configLocalDir",
2351
+ "skillsDir", "centerCredentialRenewLeadMs", "webAdmin", "fleetLeaseFailClosed", "fleetGeneration", "fleetScope", "fleetAdvertiseAddress", "fleetLeaseOutageMaxMs", "configProvider", "configLocalDir",
2415
2352
  ];
2416
2353
  export const CONFIG_GROUP_KEYS = {
2417
2354
  store: STORE_GROUP_KEYS,
@@ -2473,6 +2410,10 @@ export function loadConfig() {
2473
2410
  const limitsHttp = parseLimitsHttpDomain();
2474
2411
  const observability = parseObservabilityDomain();
2475
2412
  const integrations = parseIntegrationsDomain({ requirePrincipal, configProvider });
2413
+ const centerIdentity = centerIdentityRefusal({ authBridgeIssuer: auth.authBridgeIssuer, webAdmin: integrations.webAdmin });
2414
+ if (centerIdentity !== undefined) {
2415
+ throw new Error(centerIdentity);
2416
+ }
2476
2417
  const { directApprovalDoor, durableApproval: dgDurable, approvalHmacKeys: dgHmacKeys } = approval;
2477
2418
  const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, authTokens } = auth;
2478
2419
  const directDoorActive = directApprovalDoor && dgDurable && dgHmacKeys.length > 0 && principalJwtPubkeys.length > 0 && !!principalJwtIss && !!principalJwtAud;
@@ -2510,7 +2451,7 @@ export function loadConfig() {
2510
2451
  throw new Error(laneRequiredRefusal);
2511
2452
  }
2512
2453
  {
2513
- const routeGap = judgeModelRouteGap(process.env, { envLaneDispatchable: !isRosterGateArmed(integrations.configCenter) });
2454
+ const routeGap = judgeModelRouteGap(process.env, { envLaneDispatchable: !isRosterGateArmed(integrations.webAdmin) });
2514
2455
  if (routeGap.gap !== "none") {
2515
2456
  throw new Error(routeGap.reason);
2516
2457
  }
@@ -144,7 +144,7 @@ export declare function laneRequiredEnv(lane: RemoteExecProvider): readonly stri
144
144
  *
145
145
  * 🔴 病(S-1008,test d327-g6-engine-7112 OBS-4 / OBS-5;2026-10-03 亲核):修前**两份句子**。运行期真拒启的是 `config.ts` 手写 throw
146
146
  * (点名 `REQUIRE_EXECUTION_LANE` / `REMOTE_EXEC` + 修法,用户在 stderr 读到的就是它);注册表条目另写了一句短的
147
- * 「the deployment asked to refuse this state」,而它只在 `config-center/stage-limits.ts` 的全表校验里被调 —— 候选视图只装
147
+ * 「the deployment asked to refuse this state」,而它只在 `web-admin-client/stage-limits.ts` 的全表校验里被调 —— 候选视图只装
148
148
  * `BATCH1_LIMIT_KEYS` 的限额键,带不上这两键 ⇒ 对本条恒 `next === live`,**那一句没有任何读者**(test 六个拒启格 stderr 里零命中)。
149
149
  * 改一份另一份不跟。现形:boot 的 throw 与注册表条目的 `check` **都**调本函数 —— 一只判据、一句话,没有第二份文本可漂。
150
150
  *
@@ -21,7 +21,7 @@
21
21
  * · `worker` / `expectedGeneration`:缺席对缺席(非 fleet 成员没有代际,不带 `expectedGeneration` 的请求是单机形,不是通配)。
22
22
  * · `instanceId`:请求带了才比(它是引擎每进程自铸的身份,`/health` 上可读);「点名的是不是别的进程」与 run 行同一只判据
23
23
  * `runProvenElsewhere`。
24
- * 引擎自己的 worker / instanceId 读不出 ⇒ 带了这一项的请求不符(认不出自己就不认任何点名;没配 `SEMA_REGISTRY_WORKER` 的引擎因此
24
+ * 引擎自己的 worker / instanceId 读不出 ⇒ 带了这一项的请求不符(认不出自己就不认任何点名;没配 `SEMA_WEB_ADMIN_WORKER` 的引擎因此
25
25
  * 只能用停止信号排空)。
26
26
  * 5. **进入那一拍让出在飞**:本副本可抢占的在飞腿经 core `TaskSpec.preemptSignal` 让出(在下一个干净的回合边界耐久停驻,
27
27
  * `resource_limit` / `preempt`;不合格的腿上 core 静默不动,等到期限硬停 —— 既有 `crashed` 臂);活的审批卡按断连同路改路耐久停驻
@@ -10,7 +10,7 @@
10
10
  * `ready ∧ ¬draining ∧ leaseState ≠ denied` —— 后两项不是新判据:`draining` 本来就是就绪原因,而租约被拒**同一拍**经
11
11
  * 唯一的排空入口进入排空(`fleet/serving-lease.ts`),所以「被拒 ⇒ 排空 ⇒ 不就绪」是构造出来的,不靠第二只谓词。
12
12
  * `leaseState = expired` **不**进就绪(中心不可达不是本实例的病,见租约模块头注)。
13
- * 3. **重启**:`restart` = 已发布的重启信号;没有已发布信号而有一只**扣着**的候选(config-center 的保留候选状态机)且它确有被扣的片时,
13
+ * 3. **重启**:`restart` = 已发布的重启信号;没有已发布信号而有一只**扣着**的候选(web-admin 的保留候选状态机)且它确有被扣的片时,
14
14
  * 铸 `{reasons: 被扣的片, version, since, withheld: true}`(「要重启,但此刻换掉本实例会丢它手里的候选」)。已发布的信号恒胜(那几片
15
15
  * 是安全可重启的,扣着的片不阻止它们);被扣的片为空(只差发布重试)⇒ 不是重启事实,不铸(契约 `RestartSignal.reasons` 至少一词;
16
16
  * 那一形的面只有每拍一行运维 warn + 计数)。「扣着」在两出口上只有这一种读法(7.120.x 的 `/health.modelPlaneDeferred` 本版删除)。
@@ -54,7 +54,7 @@ export type ServingLeaseView = {
54
54
  export type FleetMembershipKeys = Pick<InstanceAnnouncement, "generation" | "leaseState" | "leaseUntil">;
55
55
  /** 非 fleet 成员 / 没装租约客户端时的读数(唯一拼法)。 */
56
56
  export declare const LEASE_NONE: ServingLeaseView;
57
- /** 扣着的候选(config-center 的 `planeDeferredNoHandoff` 投影):版本、起扣时刻、被扣的重启片。 */
57
+ /** 扣着的候选(web-admin 的 `planeDeferredNoHandoff` 投影):版本、起扣时刻、被扣的重启片。 */
58
58
  export interface RetainedCandidate {
59
59
  readonly version: number;
60
60
  readonly since: number;
@@ -62,7 +62,7 @@ export interface RetainedCandidate {
62
62
  }
63
63
  /**
64
64
  * 重启事实的**唯一**合成点(规则 3):已发布信号恒胜;否则扣着的候选有被扣的片 ⇒ `withheld:true` 的信号;否则缺席。
65
- * `build*` = 纯数据。泛型让 config-center 交进来的窄型(`EngineRestartSignal`,`reasons` 是片闭集)原样回来。
65
+ * `build*` = 纯数据。泛型让 web-admin 交进来的窄型(`EngineRestartSignal`,`reasons` 是片闭集)原样回来。
66
66
  */
67
67
  export declare function buildRestartSignal<R extends RestartSignal>(published: R | undefined, retained: (RetainedCandidate & {
68
68
  readonly blocked?: readonly R["reasons"][number][];
@@ -72,8 +72,8 @@ export declare const CONFIG_HANDOFF_STATES: readonly ["missing"];
72
72
  export type ConfigHandoffState = (typeof CONFIG_HANDOFF_STATES)[number];
73
73
  /**
74
74
  * `/health.configHandoff`(只在 `/health`,不上心跳)—— 一件**事故**:**在场 ⇔ 部署声明了耐久接力 ∧ 应用着的那一代没在下一次起服将用的身份的桶里确认耐久落盘**
75
- * (config-center 的接力账 {@link ConfigHandoffLedger}:最后确认耐久的那一代 + 写进的那只身份桶,对比应用着的那一代 + 此刻的凭证身份 —— 离线起服按此刻
76
- * 的身份选桶;部署形门在 config-center 的取值口,读判「handoff confirmed」的同一只谓词)。凭证换了人(换了身份)而新身份的桶里没有这一代 ⇒ 在场。覆盖 LKG 发布失败(含保留候选、启动期技能债)与部分应用(某组被整拒、其余组已热应用,LKG 停在上一个完整世代)两形。**部署形**不在这里报:
75
+ * (web-admin 的接力账 {@link ConfigHandoffLedger}:最后确认耐久的那一代 + 写进的那只身份桶,对比应用着的那一代 + 此刻的凭证身份 —— 离线起服按此刻
76
+ * 的身份选桶;部署形门在 web-admin 的取值口,读判「handoff confirmed」的同一只谓词)。凭证换了人(换了身份)而新身份的桶里没有这一代 ⇒ 在场。覆盖 LKG 发布失败(含保留候选、启动期技能债)与部分应用(某组被整拒、其余组已热应用,LKG 停在上一个完整世代)两形。**部署形**不在这里报:
77
77
  * 没有耐久声明(`CONFIG_LKG_DURABLE` 不真 / LKG 关)的部署「重启靠中心重拉」是配置时声明的事实 ⇒ 恒缺席;本地腿 / 没有配置管道 ⇒ 缺席。
78
78
  * 与 `restart.withheld` 两个事实两张脸(可同在):要不要重启归 `restart`,声明了的接力缺不缺归本键。
79
79
  * `version` = 应用着的那一代;`since` = 这一代开始没有确认接力的时刻(持续缺着时不刷新,确认即清)。
@@ -83,7 +83,7 @@ export interface ConfigHandoff {
83
83
  readonly version: number;
84
84
  readonly since: number;
85
85
  }
86
- /** 配置接力账(config-center 持有,`/health.configHandoff` 的唯一来源):应用着的那一代、最后一次确认耐久接力的那一代与它写进的身份桶、
86
+ /** 配置接力账(web-admin 持有,`/health.configHandoff` 的唯一来源):应用着的那一代、最后一次确认耐久接力的那一代与它写进的身份桶、
87
87
  * 下一次起服将用的身份(此刻的凭证身份 —— 离线起服选桶读的同一只)。 */
88
88
  export interface ConfigHandoffLedger {
89
89
  readonly applied?: number;
@@ -96,9 +96,9 @@ export interface ConfigHandoffLedger {
96
96
  /** 「接力缺着」的**唯一**判据(纯):应用过一代 ∧ 最后确认耐久的不是「这一代 ∧ 下一次起服将用的身份桶」。 */
97
97
  export declare function configHandoffMissing(ledger: ConfigHandoffLedger): boolean;
98
98
  /** `configHandoff` 的**唯一**合成点(纯):缺着 ⇒ `{ state: "missing", version: 应用着的那一代, since }`;否则缺席。`since` 由持账方锁存(发现缺着的那一拍)。
99
- * `build*` = 纯数据;config-center 的 `configHandoffState()` 是唯一调用方。 */
99
+ * `build*` = 纯数据;web-admin 的 `configHandoffState()` 是唯一调用方。 */
100
100
  export declare function buildConfigHandoff(ledger: ConfigHandoffLedger, since: number | undefined): ConfigHandoff | undefined;
101
- /** 世代账的一次读数(config-center 的 `configApplyState()` 交出的那一份里本模块读的五键;`/health` 扁平五键与嵌套形的两键读同一份)。 */
101
+ /** 世代账的一次读数(web-admin 的 `configApplyState()` 交出的那一份里本模块读的五键;`/health` 扁平五键与嵌套形的两键读同一份)。 */
102
102
  export interface ConfigLedgerReading {
103
103
  readonly configTargetVersion: number;
104
104
  readonly configAppliedVersion: number;
@@ -566,6 +566,7 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
566
566
  name?: string;
567
567
  toolName?: string;
568
568
  parentToolCallId?: string;
569
+ workflowRunId?: string;
569
570
  status?: string;
570
571
  seq?: number;
571
572
  }) => void;
@@ -576,6 +577,7 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
576
577
  name?: string;
577
578
  usage?: unknown;
578
579
  parentToolCallId?: string;
580
+ workflowRunId?: string;
579
581
  status?: string;
580
582
  seq?: number;
581
583
  }) => void;
@@ -639,13 +641,20 @@ export declare function fleetRunResiduals(result: {
639
641
  * session attribution → unscoped, back-compat visible). Names ride the same redactSecrets discipline.
640
642
  */
641
643
  export declare function fleetBackgroundChildPublisher(bus?: FleetEventBus, log?: (msg: string, fields: Record<string, unknown>) => void): (e: import("@sema-agent/core").BackgroundChildEvent) => void;
644
+ /**
645
+ * 🔴 **run 的短名 —— 一只折法、一个输入**:输入 = run 行的预览(`user-authored-text.ts` 的 `buildRunObjectivePreview` 的产物,run 行上存的就是它);
646
+ * fleet 行的 `name`(发布时由 objective 现算同一只预览)与 `GET /v1/assistant/tasks` 的 `name`(读 run 行上存的预览)读同一只,
647
+ * 同一个 run 两面同名。预览是 `""`(有记录、剥完没有用户正文)⇒ `(notification turn)`;否则单行折叠、超过 48 字截断带 `…`。预览已脱敏。
648
+ * 入参只收「有记录」的预览:列上的 NULL(没记录)不是通告轮,由读面自己按契约缺席,不进这只折法。
649
+ */
650
+ export declare function buildRunName(preview: string): string;
642
651
  /** BC-1 (clay-decided 2026-06-27): a top-level run's fleet-row `name` = a SHORT, single-line **objective preview**
643
652
  * (the readable "what is this task" label) — NOT the full objective dumped in, and NOT duplicated into `description`.
644
653
  * `description` is left to the publisher's LIVE-ACTIVITY update (`onEvent` tool_start → the current tool), so the row
645
654
  * shows `name`=objective + `description`=current activity (two DISTINCT things, killing the earlier "objective shown
646
- * twice" dup). Whitespace-collapsed + capped ≤48. (A subagent CHILD row's name = its agent-type — BC-2.)
647
- * SECRET-SAFE: redact secret shapes (redactSecrets) BEFORE truncating — a secret in the objective must not leak in
648
- * the row name. The durable objective is already redacted; the name preview was asymmetric (raw) until this. */
655
+ * twice" dup). (A subagent CHILD row's name = its agent-type — BC-2.)
656
+ * 一只折法({@link buildRunName}),输入 = 与 run 行同一只预览(用户写的那段 → 脱敏 → 截):`GET /v1/assistant/tasks`
657
+ * 读 run 行上存的预览、过同一只折法 ⇒ 同一个 run 两面同名。剥完没有用户正文 ⇒ `(notification turn)`;闭集外的 XML 头当普通正文标。 */
649
658
  export declare function fleetRunLabels(objective: string | undefined): {
650
659
  name: string;
651
660
  };
@@ -3,6 +3,7 @@ import { DURABLE_AGENT_HANDLE_RE, deriveAgentDisplayStatus, isDelegatedAgentTerm
3
3
  import { persistedPlaneOf } from "../terminal.js";
4
4
  import { recordFailOpen } from "../observability/fail-open.js";
5
5
  import { redactSecrets } from "../trace/redact.js";
6
+ import { buildRunObjectivePreview } from "../user-authored-text.js";
6
7
  export function isFleetAgentTerminalNotification(n) {
7
8
  return isDelegatedAgentTerminal(n);
8
9
  }
@@ -206,6 +207,7 @@ export function fleetRunPublisher(bus, run) {
206
207
  let settledLeg = false;
207
208
  const childId = (taskId) => `${run.runId} ${taskId}`;
208
209
  const tickStatus = (st) => (st === "completed" ? "completed" : st === "failed" ? "failed" : "running");
210
+ const workflowRunIdField = (ev) => (ev.workflowRunId ? { workflowRunId: ev.workflowRunId } : {});
209
211
  const toolUsesOf = (usage) => {
210
212
  const t = usage?.toolUses;
211
213
  return typeof t === "number" ? t : undefined;
@@ -269,7 +271,7 @@ export function fleetRunPublisher(bus, run) {
269
271
  childStartedAt.set(cid, Date.now());
270
272
  if (ev.parentToolCallId)
271
273
  childByToolCall.set(ev.parentToolCallId, cid);
272
- bus.publishTask({ id: cid, sourceLane: "run-leg", ...(childName !== undefined ? { name: childName, agentType: childName } : {}), parentId: run.runId, scope: run.scope, ...sessionField, status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
274
+ bus.publishTask({ id: cid, sourceLane: "run-leg", ...(childName !== undefined ? { name: childName, agentType: childName } : {}), parentId: run.runId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
273
275
  }
274
276
  else if (ev.type === "tool_start" && ev.toolName) {
275
277
  bus.publishTask({ id: run.runId, description: ev.toolName });
@@ -290,7 +292,7 @@ export function fleetRunPublisher(bus, run) {
290
292
  childStartedAt.set(cid, Date.now());
291
293
  if (ev.parentToolCallId)
292
294
  childByToolCall.set(ev.parentToolCallId, cid);
293
- bus.publishTask({ id: cid, sourceLane: "run-leg", ...(fwdName !== undefined ? { name: fwdName, agentType: fwdName } : {}), parentId, scope: run.scope, ...sessionField, status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
295
+ bus.publishTask({ id: cid, sourceLane: "run-leg", ...(fwdName !== undefined ? { name: fwdName, agentType: fwdName } : {}), parentId, scope: run.scope, ...sessionField, ...workflowRunIdField(ev), status: tickStatus(ev.status), tokens: sumTokens(ev.usage), ...(typeof ev.seq === "number" ? { cycleSeq: ev.seq } : {}), ...(() => { const t = toolUsesOf(ev.usage); return t !== undefined ? { toolUses: t } : {}; })(), elapsedMs: Date.now() - childStartedAt.get(cid) });
294
296
  },
295
297
  onChildTerminal(taskId, status, altId, toolUseId) {
296
298
  if (settledLeg)
@@ -612,14 +614,16 @@ export function fleetBackgroundChildPublisher(bus, log) {
612
614
  handleTerminal(e, m);
613
615
  };
614
616
  }
617
+ const NOTIFICATION_TURN_NAME = "(notification turn)";
618
+ const RUN_NAME_CHARS = 48;
619
+ export function buildRunName(preview) {
620
+ const oneLine = preview.replace(/\s+/g, " ").trim();
621
+ if (oneLine === "")
622
+ return NOTIFICATION_TURN_NAME;
623
+ return oneLine.length > RUN_NAME_CHARS ? `${oneLine.slice(0, RUN_NAME_CHARS - 1)}…` : oneLine;
624
+ }
615
625
  export function fleetRunLabels(objective) {
616
- const oneLine = redactSecrets((objective ?? "").replace(/\s+/g, " ")).trim();
617
- if (!oneLine)
618
- return { name: "task" };
619
- if (/^<[a-z][a-z0-9_-]*[\s>/]/i.test(oneLine))
620
- return { name: "(notification turn)" };
621
- const name = oneLine.length > 48 ? `${oneLine.slice(0, 47)}…` : oneLine;
622
- return { name };
626
+ return { name: buildRunName(buildRunObjectivePreview(objective ?? "")) };
623
627
  }
624
628
  export function isTerminalFleetStatus(status) {
625
629
  switch (status) {
@@ -1,5 +1,5 @@
1
- import { type CenterCapabilities } from "@sema-agent/settings-schema/fleet";
2
- import { type CenterEndpoint } from "../config-center/center-request.js";
1
+ import { type WebAdminCapabilities } from "@sema-agent/settings-schema/fleet";
2
+ import { type CenterEndpoint } from "../web-admin-client/center-request.js";
3
3
  import { type DrainEntry } from "./drain-entry.js";
4
4
  import type { ServingLeaseView } from "./engine-signal.js";
5
5
  /** 续租请求的上界(ms)—— 与 fleet 心跳同量级(不在提交热路径上)。 */
@@ -34,7 +34,7 @@ export interface ServingLeaseClientOpts {
34
34
  }
35
35
  export interface ServingLeaseClient {
36
36
  /** 一次中心能力读数(`undefined` = `undeclared`,中心没宣告 = 不支持)。每一次读数调一次;`unreadable` 不是读数,不调(`fleet-client.ts` `capabilityReadingOf`)。 */
37
- noteCenterCapabilities(caps: CenterCapabilities | undefined): void;
37
+ noteCenterCapabilities(caps: WebAdminCapabilities | undefined): void;
38
38
  /** 此刻的租约读数(铸点与准入判读它)。 */
39
39
  view(): ServingLeaseView;
40
40
  /** 起步读黏性拒(装配层在唯一排空入口装好之后调一次)。 */
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { SERVING_LEASE_TTL_DEFAULT_MS, readServingLeaseResponse } from "@sema-agent/settings-schema/fleet";
4
- import { centerFetch } from "../config-center/center-request.js";
4
+ import { centerFetch } from "../web-admin-client/center-request.js";
5
5
  import { recordFailOpen } from "../observability/fail-open.js";
6
6
  import { leaseDrainActionId } from "./drain-entry.js";
7
7
  export const SERVING_LEASE_FETCH_TIMEOUT_MS = 5_000;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Fleet worker-side wiring(announce/heartbeat + usage 批报;契约 = registry-core 0.1.48+
3
- * `/fleet`,center 端点 = sema-registry `/api/fleet/*`)。设计要点:
3
+ * `/fleet`,center 端点 = web-admin `/api/fleet/*`)。设计要点:
4
4
  * - **可选分层(D3),两条环各自有门(S-866 ④)**:客户端在中心车道配齐时启动(`centerLaneConfigured` —— baseUrl + 声明了
5
5
  * 凭证 + worker,与租约管理器、用量累加器**同一只**谓词);**用量环**只要这三件;**公告环**(announce / 心跳 / 注销)另要
6
6
  * 配置席 `fleetAdvertiseAddress`(env `FLEET_ADVERTISE_ADDRESS`,`loadConfig` 解析一次;可达性是运维的话,不自猜:k8s pod IP /
@@ -13,13 +13,13 @@
13
13
  * - **`engineSignal`(7.123.0)**:引擎态整只(契约 `EngineSignal`),与扁平键同一次读数;契约包 10.x 的心跳形没有它的座位(10.x 中心
14
14
  * 默认 strip 解析丢掉它、照收心跳);扁平布尔 `draining` settings-schema 12.0.0 删、本引擎 7.124.0+ 删发。
15
15
  * - **`restart?`(S-741)**:在场 ⇔ 本副本必须重启才能应用配置 —— 取自 `/health.restart` **同一只**取值口(装配层接
16
- * `deployment.restartState`,config-center 的 `restartState()`),同一个对象,形 = settings-schema `RestartSignal`;
16
+ * `deployment.restartState`,web-admin 的 `restartState()`),同一个对象,形 = settings-schema `RestartSignal`;
17
17
  * 缺席即键缺席(中心按行整体替换,不合并 —— 一条不带它的心跳就是「不再需要」)。
18
18
  * - **`modelRefusals?`(S-768)**:在场 ⇔ 本副本对最近一次被判的中心候选目录有可报的拒(逐条名 → 码 / 模型面组拒码)—— 取自
19
19
  * `/health.modelRefusals` **同一只**取值口(装配层接 `deployment.modelRefusalsState`),同一个对象,形 = settings-schema
20
20
  * `ModelRefusalsSignal`;缺席即键缺席(同 `restart`)。
21
21
  * - **自报状态翻转即刻再 announce**(第一时间自摘流 / 自挂流 / 报重启 / 报拒因,比任何观测都快):draining 翻转由收尾链直调
22
- * `announceNow`;roster 落地、restart 信号与模型拒因变化由装配层把 config-center 的 `onSelfReportChange` 接到 `announceNow`
22
+ * `announceNow`;roster 落地、restart 信号与模型拒因变化由装配层把 web-admin 的 `onSelfReportChange` 接到 `announceNow`
23
23
  * (两处 = 两类输入各自的唯一写者,触发都是 `announceNow`)。退出前 DELETE(显式注销,幂等)。
24
24
  * - **usage 批报**:tracer 的 `brain.call` 已带 ALS principal —— FleetUsageAccumulator 按 principal×model
25
25
  * 累计,每窗口(默认 60s,半开 [windowStartMs, windowEndMs))POST /api/fleet/usage。幂等键
@@ -27,9 +27,9 @@
27
27
  * 向前合并不会双计 —— 只延迟,不丢量)。
28
28
  * - 全部 fire-and-forget + swallow-guarded:fleet 面是运维旁路,绝不影响任务面;网络错误只 warn 一次/连败类。
29
29
  */
30
- import { UsageReport, type CapabilityReading, type CenterCapabilities, type ModelRefusalsSignal } from "@sema-agent/settings-schema/fleet";
30
+ import { UsageReport, type CapabilityReading, type WebAdminCapabilities, type ModelRefusalsSignal } from "@sema-agent/settings-schema/fleet";
31
31
  import { type EngineSignalFacts } from "./fleet/engine-signal.js";
32
- import { type CenterEndpoint } from "./config-center/center-request.js";
32
+ import { type CenterEndpoint } from "./web-admin-client/center-request.js";
33
33
  /** Bound on distinct principal×model keys per window — a runaway/multi-tenant burst collapses into
34
34
  * `__other__` instead of growing unbounded (same posture as budget.ts cardinalityGuard). */
35
35
  export declare const FLEET_USAGE_KEY_CAP = 1024;
@@ -91,7 +91,7 @@ export interface FleetClientOpts {
91
91
  /** 编排器片 2:每一次**能力读数**交出去一次(装配层接服务租约客户端的 `noteCenterCapabilities`)。规则见 {@link capabilityReadingOf}:
92
92
  * 只有 `declared`(交出宣告的位)与 `undeclared`(交 `undefined` = 老中心没宣告)是读数;`unreadable`(体读不出 / 不是对象 /
93
93
  * `capabilities` 键在场而形坏)不是读数 ⇒ 不调,上一次读数与它的钟原样。失败的公告同样不调(没听到 ≠ 没有)。 */
94
- onCenterCapabilities?: (caps: CenterCapabilities | undefined) => void;
94
+ onCenterCapabilities?: (caps: WebAdminCapabilities | undefined) => void;
95
95
  usage?: FleetUsageAccumulator;
96
96
  heartbeatMs?: number;
97
97
  usageWindowMs?: number;
@@ -148,7 +148,7 @@ export declare function startFleetClient(opts: FleetClientOpts): FleetClient;
148
148
  * deployments); an address set while only the worker is missing is warned (half-configured announce).
149
149
  */
150
150
  export declare function startFleetClientFromConfig(cfg: {
151
- configCenter?: (CenterEndpoint & {
151
+ webAdmin?: (CenterEndpoint & {
152
152
  worker?: string;
153
153
  }) | undefined;
154
154
  fleetAdvertiseAddress?: string | undefined;
@@ -1,7 +1,8 @@
1
1
  import { InstanceAnnouncement, UsageReport, DEFAULT_HEARTBEAT_MS, readCapabilityReading } from "@sema-agent/settings-schema/fleet";
2
2
  import { ENGINE_SIGNAL_KEY, buildEngineSignal, fleetMembershipKeys, heartbeatReadinessKeys } from "./fleet/engine-signal.js";
3
- import { centerFetch, centerLaneConfigured } from "./config-center/center-request.js";
3
+ import { centerFetch, centerLaneConfigured } from "./web-admin-client/center-request.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
+ import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
5
6
  export const FLEET_USAGE_KEY_CAP = 1024;
6
7
  export const FLEET_CLIENT_FETCH_TIMEOUT_MS = 5000;
7
8
  export class FleetUsageAccumulator {
@@ -230,14 +231,14 @@ export function startFleetClient(opts) {
230
231
  return { announceNow, stopRouting, flushFinalUsage };
231
232
  }
232
233
  export function startFleetClientFromConfig(cfg, opts) {
233
- const cc = cfg.configCenter;
234
+ const cc = cfg.webAdmin;
234
235
  const address = cfg.fleetAdvertiseAddress;
235
236
  if (!centerLaneConfigured(cfg)) {
236
237
  if (address !== undefined && cc?.baseUrl && cc.credential.declared) {
237
- opts.logger?.warn("fleet_client_no_worker_scope", { note: "FLEET_ADVERTISE_ADDRESS set but SEMA_REGISTRY_WORKER missing — announce needs the worker (dispatch key); fleet client not started" });
238
+ opts.logger?.warn("fleet_client_no_worker_scope", { note: `FLEET_ADVERTISE_ADDRESS set but ${WEB_ADMIN_ENV.worker} missing — announce needs the worker (dispatch key); fleet client not started` });
238
239
  }
239
240
  return undefined;
240
241
  }
241
- return startFleetClient({ ...opts, center: cfg.configCenter, advertiseAddress: address });
242
+ return startFleetClient({ ...opts, center: cfg.webAdmin, advertiseAddress: address });
242
243
  }
243
244
  //# sourceMappingURL=fleet-client.js.map
@@ -1,4 +1,4 @@
1
- import { type CenterEndpoint } from "./config-center/center-request.js";
1
+ import { type CenterEndpoint } from "./web-admin-client/center-request.js";
2
2
  /** 负缓存 TTL:非 lease-enforced 的 principal 多久后再问一次 center(entitlement 升级为 lease 的收敛上界)。 */
3
3
  export declare const NOT_LEASE_TTL_MS: number;
4
4
  /** center 判 budget exhausted 后,多久内的重复提交直接拒绝而不再打 center(防 per-request 打爆)。 */
@@ -141,11 +141,11 @@ export declare class FleetLeaseManager {
141
141
  /**
142
142
  * Env/config gate:中心车道配齐({@link centerLaneConfigured} —— 与 fleet 用量环 / 用量累加器**同一只**谓词,S-866 ④)即启;
143
143
  * 不需要 FLEET_ADVERTISE_ADDRESS(它是出站消费面,不是入站可达性声明)。缺任一件 → undefined,非 fleet 部署零行为变化。
144
- * S-651:按**声明**装、不按内容装 —— `SEMA_REGISTRY_TOKEN_FILE`(`CENTER_CREDENTIAL_ENV.tokenFile`)在场而
144
+ * S-651:按**声明**装、不按内容装 —— `SEMA_WEB_ADMIN_TOKEN_FILE`(`WEB_ADMIN_ENV.tokenFile`)在场而
145
145
  * 文件此刻不可读,管理器照样装上(每次协商取值,失败走响亮的鉴权失败臂;文件恢复即恢复)。
146
146
  */
147
147
  export declare function createFleetLeaseFromEnv(cfg: {
148
- configCenter?: (CenterEndpoint & {
148
+ webAdmin?: (CenterEndpoint & {
149
149
  worker?: string;
150
150
  }) | undefined;
151
151
  fleetLeaseFailClosed: boolean;
@@ -1,6 +1,6 @@
1
1
  import { QuotaLease, leaseExhausted, shouldRenewLease } from "@sema-agent/settings-schema/fleet";
2
2
  import { CenterCredentialUnavailableError } from "./center-credential.js";
3
- import { centerFetch, centerLaneConfigured } from "./config-center/center-request.js";
3
+ import { centerFetch, centerLaneConfigured } from "./web-admin-client/center-request.js";
4
4
  export const NOT_LEASE_TTL_MS = 10 * 60 * 1000;
5
5
  export const EXHAUSTED_RETRY_MS = 30 * 1000;
6
6
  export const LEASE_PRINCIPAL_CAP = 4096;
@@ -174,7 +174,7 @@ export class FleetLeaseManager {
174
174
  export function createFleetLeaseFromEnv(cfg, opts) {
175
175
  if (!centerLaneConfigured(cfg))
176
176
  return undefined;
177
- const cc = cfg.configCenter;
177
+ const cc = cfg.webAdmin;
178
178
  return new FleetLeaseManager({ ...opts, center: { baseUrl: cc.baseUrl, credential: cc.credential, worker: cc.worker }, failMode: cfg.fleetLeaseFailClosed ? "closed" : "open" });
179
179
  }
180
180
  //# sourceMappingURL=fleet-lease.js.map
@@ -18,7 +18,7 @@
18
18
  *
19
19
  * ## 时刻
20
20
  * env 在**构造时**取一次快照(boot / run-local 起腿时),而不是 core 默认那样每次 spawn 现取:`NodeLspManagerOptions.env`
21
- * 是一份静态记录。本仓的 `process.env` 是 boot 期输入(热配置走配置中心,不改 `process.env`),两者在本仓部署上同值。
21
+ * 是一份静态记录。本仓的 `process.env` 是 boot 期输入(热配置走 web-admin,不改 `process.env`),两者在本仓部署上同值。
22
22
  *
23
23
  * ## 点名放行(S-699,`LSP_ENV_ALLOW`)
24
24
  * 剥除会连语言服务器自己的真实依赖一起剥掉(`.npmrc` 的 `${NPM_TOKEN}` 插值、rust-analyzer `cargo metadata` 私有 registry 的