@sema-agent/server 7.51.0 → 7.52.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.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +103 -24
- package/dist/adoption/plan.d.ts +4 -4
- package/dist/adoption/plan.js +11 -0
- package/dist/approval-card.d.ts +26 -2
- package/dist/approval-card.js +9 -0
- package/dist/approval-hmac.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +2 -2
- package/dist/approval-reconciler.js +1 -1
- package/dist/bench/l8/artifact.d.ts +1 -1
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/oracle.d.ts +1 -1
- package/dist/bench/s1/row.d.ts +1 -1
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/budget-tracing.js +2 -5
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +1 -1
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +6 -6
- package/dist/boot/org-memory.d.ts +1 -1
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/reapers.d.ts +2 -2
- package/dist/boot/reapers.js +17 -4
- package/dist/boot/resolve-spec.d.ts +12 -0
- package/dist/boot/resolve-spec.js +29 -7
- package/dist/boot/retention-lane.d.ts +2 -2
- package/dist/boot/runner-deps.d.ts +17 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/runtime-caps.d.ts +23 -0
- package/dist/boot/runtime-caps.js +24 -2
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +14 -3
- package/dist/boot/stores.js +31 -1
- package/dist/boot/task-list-lane.d.ts +2 -2
- package/dist/brain.js +51 -31
- package/dist/budget.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/collab-workflows.d.ts +1 -1
- package/dist/capabilities/hands-lane.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +3 -3
- package/dist/capabilities/skills.d.ts +1 -1
- package/dist/config-center/hot-keys-registry.js +5 -0
- package/dist/config-center/http-client.d.ts +2 -2
- package/dist/config-center/read-face.d.ts +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-types.d.ts +100 -25
- package/dist/config.d.ts +11 -3
- package/dist/config.js +91 -15
- package/dist/deployment-governance.d.ts +1 -1
- package/dist/device-enrollment.d.ts +2 -2
- package/dist/device-store.d.ts +3 -3
- package/dist/device-ws-hub.d.ts +4 -2
- package/dist/device-ws-hub.js +9 -3
- package/dist/device-ws-protocol.d.ts +2 -2
- package/dist/env-facts.d.ts +1 -1
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/fleet-bus.d.ts +5 -2
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/fleet-terminal-window.d.ts +1 -1
- package/dist/hooks/hook-runner.d.ts +8 -1
- package/dist/http/active-run-conflict.d.ts +2 -2
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +27 -5
- package/dist/http/routes/admin-memory-optout.d.ts +48 -0
- package/dist/http/routes/admin-memory-optout.js +75 -0
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +21 -21
- package/dist/http/routes/capabilities.js +20 -9
- package/dist/http/routes/diagnostics.d.ts +1 -1
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/memory-bundle.d.ts +1 -1
- package/dist/http/routes/memory-bundle.js +2 -1
- package/dist/http/routes/memory-compliance.d.ts +4 -4
- package/dist/http/routes/memory-origin.d.ts +4 -4
- package/dist/http/routes/memory-origin.js +3 -1
- package/dist/http/routes/memory-policy.js +6 -2
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/rules.d.ts +5 -2
- package/dist/http/routes/rules.js +84 -5
- package/dist/http/routes/run-memory-capture.d.ts +34 -0
- package/dist/http/routes/run-memory-capture.js +97 -0
- package/dist/http/routes/runs.d.ts +1 -0
- package/dist/http/routes/runs.js +212 -6
- package/dist/http/routes/session-sync.d.ts +4 -6
- package/dist/http/routes/session-sync.js +60 -47
- package/dist/http/routes/sessions.js +61 -188
- package/dist/http/routes/shared-memory.d.ts +1 -1
- package/dist/http/routes/tasks.js +1 -1
- package/dist/http/routes/workflows.js +19 -0
- package/dist/http/server.d.ts +35 -13
- package/dist/http/server.js +110 -14
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +41 -8
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/leader.d.ts +1 -1
- package/dist/leader/repair-oracle.d.ts +2 -2
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/main.js +14 -6
- package/dist/memory-bundle-engine.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +5 -5
- package/dist/memory-origin-fence.d.ts +35 -0
- package/dist/memory-origin-fence.js +66 -0
- package/dist/memory-posture.d.ts +13 -1
- package/dist/memory-posture.js +1 -0
- package/dist/memory-scope.d.ts +6 -1
- package/dist/memory-scope.js +3 -2
- package/dist/model-select.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +17 -5
- package/dist/observability/fail-open.js +17 -5
- package/dist/orchestration/hardened-vm-runner.d.ts +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +2 -2
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +7 -2
- package/dist/plugins/blob-backend.js +22 -18
- package/dist/plugins/caching-session-store.d.ts +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.d.ts +170 -0
- package/dist/plugins/file-history-store-sql.js +827 -0
- package/dist/plugins/file-run-store.d.ts +44 -5
- package/dist/plugins/file-run-store.js +85 -13
- package/dist/plugins/fork-routing-session-store.d.ts +1 -1
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-session-store.d.ts +9 -1
- package/dist/plugins/memory-embedder-fingerprint.d.ts +1 -1
- package/dist/plugins/memory-optout-grant-store-sql.d.ts +139 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +157 -0
- package/dist/plugins/memory-origin-law.d.ts +2 -2
- package/dist/plugins/memory-run-store.d.ts +4 -3
- package/dist/plugins/memory-run-store.js +2 -1
- package/dist/plugins/permission-rule-store-file.d.ts +16 -6
- package/dist/plugins/permission-rule-store-file.js +77 -13
- package/dist/plugins/permission-rule-store-sql.d.ts +156 -8
- package/dist/plugins/permission-rule-store-sql.js +123 -21
- package/dist/plugins/pg-pool.js +59 -0
- package/dist/plugins/pg-safe-json.d.ts +1 -1
- package/dist/plugins/remote-env-device.d.ts +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.d.ts +3 -3
- package/dist/plugins/retention-store-sql.d.ts +7 -7
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.d.ts +9 -3
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/send-user-file.d.ts +1 -1
- package/dist/plugins/session-placement.d.ts +1 -1
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +59 -29
- package/dist/plugins/store-backend.js +75 -15
- package/dist/plugins/store-contracts.d.ts +5 -3
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.js +59 -0
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/prompts-domain-validate.js +1 -1
- package/dist/resource-suspend.d.ts +1 -1
- package/dist/resource-window.d.ts +3 -3
- package/dist/rules-consent.d.ts +231 -9
- package/dist/rules-consent.js +411 -13
- package/dist/run-local.js +29 -4
- package/dist/runs.d.ts +15 -1
- package/dist/runs.js +19 -0
- package/dist/runtime-caps-resolver.d.ts +36 -1
- package/dist/runtime-caps-resolver.js +25 -0
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +5 -5
- package/dist/security.js +1 -1
- package/dist/session-sync.d.ts +52 -37
- package/dist/session-sync.js +19 -16
- package/dist/shared-memory-scope-authorizer.d.ts +1 -1
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/spec-fields.d.ts +22 -1
- package/dist/spec-fields.js +11 -0
- package/dist/store-live-probe.d.ts +2 -2
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-settings.d.ts +3 -3
- package/dist/task-workflow.d.ts +1 -1
- package/dist/text-bidi.d.ts +2 -2
- package/dist/tool-approval.d.ts +191 -9
- package/dist/tool-approval.js +248 -29
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/project.d.ts +8 -2
- package/dist/trace/project.js +10 -0
- package/dist/turn-activity.d.ts +1 -1
- package/dist/wall-clock-jump-guard.d.ts +3 -3
- package/package.json +3 -3
- package/dist/http/tar.d.ts +0 -17
- package/dist/http/tar.js +0 -53
- package/dist/http/workspace-content.d.ts +0 -11
- package/dist/http/workspace-content.js +0 -20
- package/dist/plugins/file-snapshot-store-sql.d.ts +0 -170
- package/dist/plugins/file-snapshot-store-sql.js +0 -213
package/dist/config-types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* compiling unchanged. All imports below are top-level `import type` (erased — never a load edge,
|
|
7
7
|
* see test/module-cycle-gate.test.ts header on verbatimModuleSyntax). */
|
|
8
8
|
import type { SealedKeyPoison } from "./sealed-key.js";
|
|
9
|
-
import type { A2aServerSpec, CompliancePosture, LockedKey, McpServerSpec, Model, ModelRoles, RetentionPolicy } from "@sema-agent/core";
|
|
9
|
+
import type { A2aServerSpec, CompliancePosture, FileHistoryRetentionPolicy, LockedKey, McpServerSpec, Model, ModelRoles, RetentionPolicy } from "@sema-agent/core";
|
|
10
10
|
import type { ApprovalHmacKey, PrincipalJwtKey } from "./auth-keys.js";
|
|
11
11
|
import type { ElicitationThrottle } from "./elicitation.js";
|
|
12
12
|
import type { QuestionThrottle } from "./question.js";
|
|
@@ -183,6 +183,26 @@ export interface StreamApprovalConfig {
|
|
|
183
183
|
/** 判据 5(遗孤最终可判)的上界,量 immutable 的 `createdAtMs`。`STREAM_APPROVAL_ORPHAN_TTL_MS`,
|
|
184
184
|
* 默认 **7d**,有界 [60000, 90d]。 */
|
|
185
185
|
orphanTtlMs: number;
|
|
186
|
+
/**
|
|
187
|
+
* S-43(案A,#374 / core #481)—— **零活流铸造**的 ask 的悬挂窗。`UNREACHED_ASK_TTL_MS`,
|
|
188
|
+
* 默认 **3600000**(1h),有界 [60000, 86400000](60s ~ 24h),坏值/越界**拒启**(#210 A 档)。
|
|
189
|
+
*
|
|
190
|
+
* 三问(behavior-facing 硬条款):
|
|
191
|
+
* · **谁需要**:workflow 恒后台跑(CC 220 parity)⇒ 子代 ask 到达时 (owner, session) 键域常无活 SSE。
|
|
192
|
+
* 改形前那一刻即答 `"unavailable"`,合成整条命令死拒([5443] 车道2 实证)。悬挂让人稍后经
|
|
193
|
+
* `/v1/approvals` / 壳队列 / attach 补投三通道回来答它。1h 是「人不在场但当天会回来」的尺度。
|
|
194
|
+
* · **谁被伤**:悬挂 ask 占一格写侧准入配额(`STREAM_APPROVAL_ADMIT_MAX_PER_TASK`,默认 32)且占一条
|
|
195
|
+
* 持久行,窗越长积压越久;显式声明无人值守的部署(`UNATTENDED_APPROVAL_POLICY=deny`)**完全不受
|
|
196
|
+
* 本键影响**(那条腿在铸造时刻即拒,追记 F1)。
|
|
197
|
+
* · **补偿**:本键本身(调小即回到接近旧行为;60s 下界不给「等于零窗」的形——那等价于关掉案A,
|
|
198
|
+
* 要那个语义请用 `deny` 政策或 `STREAM_ASK_WINDOW_MS=0` 的 windowZero 腿)。
|
|
199
|
+
*
|
|
200
|
+
* 🔴 跨旋钮不变量(与 `WINDOW + ADHOC_GRACE < ORPHAN_TTL` 同族、同理由):
|
|
201
|
+
* **`UNREACHED_ASK_TTL_MS + ADHOC_GRACE` 必须严格小于 `ORPHAN_TTL`** —— 悬挂行的 `expiresAtMs ≈
|
|
202
|
+
* createdAtMs + 本键`,判据 4 在 `expiresAtMs + 宽限` 触发而判据 5 在 `createdAtMs + orphanTtl` 触发;
|
|
203
|
+
* 不等式不成立 ⇒ 遗孤兜底必先到,每条悬挂行的归因都被写成 `orphan_ttl_exceeded`。boot 期校验,拒启。
|
|
204
|
+
*/
|
|
205
|
+
unreachedTtlMs: number;
|
|
186
206
|
}
|
|
187
207
|
export interface ImageBakeConfig {
|
|
188
208
|
enabled: boolean;
|
|
@@ -251,7 +271,7 @@ export interface ServiceConfigFlat {
|
|
|
251
271
|
/** Prompt-cache breakpoints on system + last tool (stable prefix). Default true. */
|
|
252
272
|
cacheBreakpoints: boolean;
|
|
253
273
|
/** `ANTHROPIC_MAX_RETRIES` —— **缺席不铸键**,同 `gatewayMaxRetries` 的理由(见其顶注):
|
|
254
|
-
* env 没配时以前会铸成 `2`
|
|
274
|
+
* env 没配时以前会铸成 `2` 再显式传给引擎,把引擎默认写死在 server 这一层。 */
|
|
255
275
|
maxRetries?: number;
|
|
256
276
|
};
|
|
257
277
|
/** Resilience brain stack (1.38, design/27): tiered timeouts + an optional circuit breaker layered
|
|
@@ -348,10 +368,6 @@ export interface ServiceConfigFlat {
|
|
|
348
368
|
/** B1 /health 活体 store 探测:后台缓存探针间隔 ms(STORE_PROBE_INTERVAL_MS;0=显式关,负/非数 boot
|
|
349
369
|
* 响亮拒)。只对 SQL 后端接线;探针原语=backend.dbNowMs()(S10 时钟探针的真 DB 往返,零新 SQL 面)。 */
|
|
350
370
|
storeProbeIntervalMs: number;
|
|
351
|
-
/** Rewind snapshot bounds: byte cap in MB (env REWIND_SNAPSHOT_MAX_MB). Unset = core DEFAULT_SNAPSHOT_BOUNDS
|
|
352
|
-
* (256 MiB / 10000 files as of core 2026-06-26 — was 2000/64MiB). BYTE-ONLY knob: raises OR lowers just the byte
|
|
353
|
-
* cap; file-count/ignoreDirs stay core defaults (more knobs when a case shows up). */
|
|
354
|
-
rewindSnapshotMaxMb?: number;
|
|
355
371
|
/** Long-term memory (design/138 S1, clay 2026-07-08): the injection-first file-based memory ENGINE
|
|
356
372
|
* (core `RunnerDeps.memoryBackend` + `MemoryEngine`) is the ONLY memory plane — the legacy MemoryStore
|
|
357
373
|
* path (MEMORY_BACKEND/EMBEDDING_* SQL/file note stores) was dropped without migration. Default ON;
|
|
@@ -378,13 +394,13 @@ export interface ServiceConfigFlat {
|
|
|
378
394
|
* · `true` ⇒ 部署自证有推断**看不见**的持久通道(自定义 writer / MCP 记忆服务 / remote lane 与记忆根
|
|
379
395
|
* 共享挂载)。它撤回引擎的只读披露,并在 remote lane 上**恢复** `# Memory` 写指令(core 5.26.0 r13/r14
|
|
380
396
|
* 收窄的官方恢复路径);
|
|
381
|
-
* · `false` ⇒ 强制披露只读/无持久面,并关掉文件工具往记忆根的写通道(
|
|
397
|
+
* · `false` ⇒ 强制披露只读/无持久面,并关掉文件工具往记忆根的写通道(披露不会被存储事实推翻)。
|
|
382
398
|
*
|
|
383
399
|
* 🔴 **`false` 自 core 5.27.0 起还多一层**([3612] F2,#231 提货):declared-false 的会话是**受限会话**
|
|
384
400
|
* —— materialize/search/harvest 一律按**已提交账**(ledger + shadow)供给,磁盘上无事务背书的分歧
|
|
385
401
|
* 既不收编也不供给,而是留盘 + 响亮点名(`restricted_divergence`,`HarvestRejectionCode` 新成员),
|
|
386
402
|
* 等下一次**非受限**会话走正常门收编。这补上了 5.26.0 自己登记的那条残余(读侧入站同步收编磁盘分歧
|
|
387
|
-
* **与会话意图无关**)
|
|
403
|
+
* **与会话意图无关**)——在那之前,这里写的「披露不会被存储事实推翻」只是半真话:披露说「本机存不下」,
|
|
388
404
|
* 引擎却仍可能把别处落进记忆根的字节收进这次会话的账。
|
|
389
405
|
* ⚠️ **这一层的射程 = file 记忆引擎**(`MEMORY_ENGINE_BACKEND` 未设的默认单机形):受限视图是
|
|
390
406
|
* `FileMemoryEngineBackend.restrictedAdoptionView` 的实装,而 `engine.materialize` 取它走的是
|
|
@@ -482,6 +498,28 @@ export interface ServiceConfigFlat {
|
|
|
482
498
|
* ⚠️ **不冻进 checkpoint**:resume 的那条腿跟**当前**部署配置走(core 成文)。
|
|
483
499
|
* 运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.provenance`(`null`=本部署未设)。 */
|
|
484
500
|
memoryProvenance?: "off" | "carry";
|
|
501
|
+
/** design/383 §3.1(core 7.0.0 片3,S-49 S-1b):本部署的记忆 **capture 姿态** —— per-principal
|
|
502
|
+
* `RuntimeCaps.allowMemoryOptOut` verdict 被读进的那个框。env `MEMORY_CAPTURE_POLICY`,三词闭集:
|
|
503
|
+
* · `open`(≡ 缺席时 core 的缺省)—— `TaskSpec.memory.capture:"off"` 声明按面值生效;只有 resolver 的
|
|
504
|
+
* **显式** `false` 拒它(`memory.capture_optout_denied`,terminal)。resolver **故障**(throw / 非
|
|
505
|
+
* boolean / 缺席)⇒ opt-out **仍生效** + `onError({phase:"config"})` 具名披露 —— 极性反转臂:隐私轴上
|
|
506
|
+
* 不可逆的一侧是「把用户明说不要记的会话记进去」,fail-safe 朝它的反面;
|
|
507
|
+
* · `governed` —— per-principal verdict **必答**(混合车队:部分用户强制留存)。`true` 放行、`false` 拒;
|
|
508
|
+
* resolver 故障/verdict 缺席 ⇒ **拒跑任务**(fail-closed:部署显式声明合规侧的不可逆更重);
|
|
509
|
+
* · `capture-required` —— 全体声明具名拒(部署级强制留存,一行配置,不依赖 resolver)。
|
|
510
|
+
*
|
|
511
|
+
* 🔴 **缺席 = 不铸键**(不复制上游缺省;`memoryProvenance` 同姿态)。坏值 ⇒ 启动期响亮拒:`governed` 与
|
|
512
|
+
* `open` 的故障极性**相反**,一个被静默折成缺省的拼写错误会让合规部署在故障窗里放行留存必需用户的 opt-out。
|
|
513
|
+
* core 侧 `prepareConfigDoors` 另有同判门(`config.memory_capture_policy`),两道同向不冲突。
|
|
514
|
+
*
|
|
515
|
+
* 🔴 **`governed` 的半配置拒启**:该姿态要求本部署有 per-principal verdict 源。本批唯一源 = SQL 后端上的
|
|
516
|
+
* `memory_optout_grant` 表(S-2;center 键 `EntitlementRuntimeCaps.allowMemoryOptOut` 是 settings-schema
|
|
517
|
+
* 的独立小件,到货前不算源)。governed 而无源 ⇒ 每个 opt-out 声明都被 core 拒且没人知道为什么 ⇒
|
|
518
|
+
* `boot/runtime-caps.ts` 的 `assertMemoryCapturePolicyWirable` 在启动期拒启(与 consolidation 阀门 D1 同姿态)。
|
|
519
|
+
*
|
|
520
|
+
* ⚠️ **部署席 ONLY**:TaskSpec 无同名键;不冻进 checkpoint(resume 腿跟当前部署配置走,core 成文)。
|
|
521
|
+
* 运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.capturePolicy`(`null`=本部署未设)。 */
|
|
522
|
+
memoryCapturePolicy?: "open" | "governed" | "capture-required";
|
|
485
523
|
/**
|
|
486
524
|
* design/378(core 5.58 design/376 片②)—— 记忆 **consolidation driver 阀门**的三根旋钮。
|
|
487
525
|
* **恒在场**(不是可选块,与 {@link retentionSweep} 同姿态):三根都有文档化的缺省,而缺省本身
|
|
@@ -587,6 +625,11 @@ export interface ServiceConfigFlat {
|
|
|
587
625
|
execTimeoutMs?: number;
|
|
588
626
|
/** `DEVICE_MAX_INFLIGHT_PER_DEVICE`(§11-O3 clay 已裁 = 4)。 */
|
|
589
627
|
maxInflightPerDevice?: number;
|
|
628
|
+
/** `DEVICE_MAX_PREAUTH_PER_REMOTE`(默认 8;字面 `off` = 显式停用 per-remote 层)= 未鉴权
|
|
629
|
+
* 握手的 per-remote 并发帽(S-04/A-075.52:帽键是裸 remoteAddress——XFF 反代 / 公司 NAT 部署
|
|
630
|
+
* 形会把全员折叠成单键,per-remote 层退化成共享预算而非公平层,`off` + 全局帽 64 是诚实形)。
|
|
631
|
+
* 坏值拒启(#210 A 档),词表与拒因见 config.ts `parseDevicePreAuthPerRemoteEnv`。 */
|
|
632
|
+
maxPreAuthPerRemote?: number | "off";
|
|
590
633
|
/** `DEVICE_SUPERSEDE`(默认 `stale_only`)= 同 deviceId 二连的顶替策略(§5.2)。 */
|
|
591
634
|
supersede?: "stale_only" | "deny";
|
|
592
635
|
} | {
|
|
@@ -662,6 +705,19 @@ export interface ServiceConfigFlat {
|
|
|
662
705
|
* service and a run-local on the same box agree on one data dir (boot-locked single-instance). Only the
|
|
663
706
|
* `local` backend reads it. */
|
|
664
707
|
localDataRoot?: string;
|
|
708
|
+
/**
|
|
709
|
+
* S-46 件B(`RUN_STORE_STRICT_HYDRATE`,普查表第 29 行的**终局格**)—— file 后端的**可选** fail-closed
|
|
710
|
+
* 启动门。`true` ⇒ `FileRunStore.hydrate()` 列不出 `runs/` 时**拒启**(error 级遗言带绝对路径 + 异常
|
|
711
|
+
* 文案,然后抛);缺省 **false** ⇒ 件6 的既有形逐字不变(带病起动 + 一行 error + P-DEBT 计数)。
|
|
712
|
+
*
|
|
713
|
+
* 为什么默认是 off:件6 当年把「不拒启」写成了刻意保留的行为,默认翻面等于替所有存量部署做主。
|
|
714
|
+
* 为什么值得有这根旋钮:空账起动之后每一次 `getRun` 恒 miss,而「恒 miss」与「本来就没有这条 run」
|
|
715
|
+
* 在 wire 上同形(#43 现场就是这么被误读的)—— 把 run 账本当真账本用的部署有权要求「读不出就别起」。
|
|
716
|
+
* 坏值**拒启**(#210 A 档):静默回默认会让 operator 要的 fail-closed 被无声吃掉。
|
|
717
|
+
*
|
|
718
|
+
* 只有 `local`(file)后端读它;SQL 后端的 hydrate 不经这条路。
|
|
719
|
+
*/
|
|
720
|
+
runStoreStrictHydrate: boolean;
|
|
665
721
|
/** PostgreSQL connection (used iff dbBackend === "pg"). Mirror of `tidb`. Env: PG_HOST/PG_PORT/PG_USER/
|
|
666
722
|
* PG_PASSWORD/PG_DATABASE/PG_POOL_SIZE. */
|
|
667
723
|
pg?: {
|
|
@@ -703,6 +759,15 @@ export interface ServiceConfigFlat {
|
|
|
703
759
|
* 实证,大字节归对象存储);`SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true` 显式接受 SQL 店 + (a) 的帽
|
|
704
760
|
* (单机/测试台形)。严格 "true" 判——这是安全姿势开关,不收宽松真值。 */
|
|
705
761
|
snapshotBlobAllowSql: boolean;
|
|
762
|
+
/** S-15 twin 保留条款(core design/381 §片2):per-file rewind 历史的**边界上限**,键形与 core
|
|
763
|
+
* `FileStorageBackendOptions.fileHistory.retention.keep` **同域同名**(local 腿原样透传给 core 的 File 店;
|
|
764
|
+
* SQL 双生店构造期同调 core `resolveFileHistoryRetention` —— 一套语义,三条车道)。缺席 = core 缺省
|
|
765
|
+
* (100,由 core 兑现,本仓不复制那个数);`{ keep: "unbounded" }` 是唯一的「不剪」拼法。坏值在
|
|
766
|
+
* loadConfig 就以 core 的 `config.retention_policy_invalid` 拒(运维接线处),绝不静默回落。
|
|
767
|
+
* env:`FILE_HISTORY_RETENTION_KEEP`。 */
|
|
768
|
+
fileHistory?: {
|
|
769
|
+
retention?: FileHistoryRetentionPolicy;
|
|
770
|
+
};
|
|
706
771
|
/** plugins 域 clone host 白名单(`PLUGINS_ALLOW_HOSTS`,缺省 github.com;契约 [1361]① 双保险面,
|
|
707
772
|
* 消费在 capabilities/center-plugins.ts)。 */
|
|
708
773
|
pluginsAllowHosts: string[];
|
|
@@ -718,8 +783,8 @@ export interface ServiceConfigFlat {
|
|
|
718
783
|
* 复审 F10:同 tick 邻居(workflowOrphanGraceMs/attachmentUnboundTtlMs/scratchpadSweepTtlMs)都有
|
|
719
784
|
* 旋钮——存量对象巨大的部署要调慢/停掉,不该被迫取消 MinIO 配置(那会连带关掉整个附件面)。 */
|
|
720
785
|
attachmentOrphanGraceMs: number;
|
|
721
|
-
/** workspace
|
|
722
|
-
*
|
|
786
|
+
/** ⚠️ INERT since S-15(workspace 浏览面随整树快照纪元退役,消费点归零)。键**保留**:center 热推
|
|
787
|
+
* 可能仍携带它,删键会让整份推送按未知键处置——正式摘除走 settings-schema 的弃用车道。 */
|
|
723
788
|
workspaceFileMaxBytes: number;
|
|
724
789
|
/** SendUserFile dual-track public-link issuance (design settled cross-repo 2026-07-14; S3_PUBLIC_* are
|
|
725
790
|
* [766]② cross-repo contract names — never rename). Enabled iff the adapter-held MinIO/S3 creds are set:
|
|
@@ -764,7 +829,7 @@ export interface ServiceConfigFlat {
|
|
|
764
829
|
* service-to-service token, else anything in-cluster can submit & bill directly). `ALLOW_UNAUTHED_WRITES`.
|
|
765
830
|
* 有意设计(文档化):本开关只豁免「零凭证形态」的 fail-closed 503;一旦配了凭证
|
|
766
831
|
* (SERVICE_AUTH_TOKEN 或 TOKENS 名录),凭证必须使用——unauthed 仍 401,两 env 不叠加
|
|
767
|
-
* (
|
|
832
|
+
* (半配置绕行=隐藏入口,刻意优先级)。 */
|
|
768
833
|
allowUnauthedWrites?: boolean;
|
|
769
834
|
/** Optional READ-ONLY token that ALSO authorizes GET /metrics + /metrics/summary (in addition to
|
|
770
835
|
* authToken). Set the SAME value fleet-wide so a control plane (sema-registry) can pull every worker's
|
|
@@ -893,7 +958,7 @@ export interface ServiceConfigFlat {
|
|
|
893
958
|
* 它是**零进展 slice 循环**的兜底(两条总额才是主约束),与重启环的 `maxSuspends` 是两个独立计数。
|
|
894
959
|
* core 的 JSDoc 逐字点名了本仓这个角色:"a host driving resumes unattended **should set this**"。
|
|
895
960
|
*
|
|
896
|
-
* 🔴 **它与两条 totals 的冻结语义不同**(codex
|
|
961
|
+
* 🔴 **它与两条 totals 的冻结语义不同**(codex 交叉复审 R1-[medium],验真后改口):core **不把它写进
|
|
897
962
|
* 账本**(`debitLedger` 的返回形里没有这一格),每片现读 `spec.resourceSuspend.maxSlices` 去比账本上
|
|
898
963
|
* 累计的 `sliceCount`。⇒ 本仓在**每一片**(含续跑)供值是**载荷不是冗余**:只在首片供值等于让续跑腿
|
|
899
964
|
* 供 `undefined` = 上限当场消失。代价如实登记:滚动部署改这根 env,已 park 的链按**新**值判 —— 部署
|
|
@@ -1081,20 +1146,30 @@ export interface ServiceConfigFlat {
|
|
|
1081
1146
|
* Running rows are never reaped (that is the orphan-grace sweep's job). Default 30 days, floor 1m.
|
|
1082
1147
|
* `WORKFLOW_RUN_RETENTION_MS`. */
|
|
1083
1148
|
workflowRunRetentionMs: number;
|
|
1084
|
-
/** design/166-T1 — core 5.8.0
|
|
1085
|
-
*
|
|
1086
|
-
* `USAGE_WINDOWS` 单键 JSON 数组(每项 {windowMs,maxTokens
|
|
1087
|
-
* 缺省未设=关(零行为变化)。
|
|
1088
|
-
* (
|
|
1149
|
+
/** design/166-T1 — core 5.8.0 部署级治理窗(`RunnerDeps.usageWindows`):滑动窗内跨任务预算,
|
|
1150
|
+
* key=principal(缺席=GLOBAL 一口锅,per-key 各一份额度——混流部署语义见 USAGE.md)。
|
|
1151
|
+
* `USAGE_WINDOWS` 单键 JSON 数组(每项 {windowMs, maxTokens?, maxCostUsd?, anchor});
|
|
1152
|
+
* 缺省未设=关(零行为变化)。S-18(core 7.0.0):`maxCostUsd` 是与 maxTokens **对等**的第二只
|
|
1153
|
+
* ceiling(绝对美元;whichever fills first 即耗尽;缺席的 ceiling 不参与——非 0、非 ∞)——两者
|
|
1154
|
+
* each optional on its own、**at least one required**(双缺=parseUsageWindows 响亮拒)。fail-loud:
|
|
1155
|
+
* 坏 JSON/空数组/坏值/未知 anchor → boot throw(parseUsageWindows)。窗形变更≈重开账(first-use
|
|
1156
|
+
* 桶按 windowMs 配对,老桶下次 charge 即弃)。$ 窗要求 run 可计价:无价目模型撞 $ 窗=core 门口拒
|
|
1157
|
+
* (`config.usage_window_unpriced`),USAGE.md §9.2。 */
|
|
1089
1158
|
usageWindows?: readonly {
|
|
1090
1159
|
windowMs: number;
|
|
1091
|
-
maxTokens
|
|
1160
|
+
maxTokens?: number;
|
|
1161
|
+
maxCostUsd?: number;
|
|
1092
1162
|
anchor: "first-use" | "rolling";
|
|
1093
1163
|
}[];
|
|
1094
1164
|
/** core 1.364 durable background agents([1503] 提货单③):reaper 经 `TaskRegistry.reapDurableAgents`
|
|
1095
1165
|
* (联合 reap——条件删赢了才 release 转录 session;裸 store.reap 会 strand 转录)按 scope 清 TERMINAL
|
|
1096
1166
|
* `a*` 行,老于此值的删。SQL twins 走 DISTINCT-scope 枚举;local FileBackgroundAgentStore 单租户
|
|
1097
|
-
* scope="default"。Default 7 days, floor 1m。`BG_AGENT_RETENTION_MS`。
|
|
1167
|
+
* scope="default"。Default 7 days, floor 1m。`BG_AGENT_RETENTION_MS`。
|
|
1168
|
+
* 🔴 S-03(#292②,设计判定 2026-08-30):这根旋钮**同时是子代转录(placed 分区)的生效留存视界**——
|
|
1169
|
+
* 联合 reap 行赢删才 release 转录,分区孤儿腿 `olderThanMs` 同源(core `reapDurableAgentsLane` 亲核),
|
|
1170
|
+
* retention lane 对 placed 显式让权(retention-store-sql.ts 第五腿)。core 词表常量
|
|
1171
|
+
* `SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT`(30d)在 core dist 零消费,本服务未按它跑;天数形
|
|
1172
|
+
* 专用旋钮无 core policy 座,候 core 扩座后再铸(生效值已投 wiring_static 日志)。 */
|
|
1098
1173
|
backgroundAgentRetentionMs: number;
|
|
1099
1174
|
/** 同批:stale-running 翻转窗——running 行的写者心跳(core 60s)断更超过此值 = 宿主进程死,行翻
|
|
1100
1175
|
* failed/stoppedBy=system(诚实终态,跨实例读面永不虚构存活)。core 契约要求 ≥10min(60s 心跳的
|
|
@@ -1289,7 +1364,7 @@ export interface ServiceConfigFlat {
|
|
|
1289
1364
|
* 放行、不会减**,而车二**没有撤销面**——列出 / 删除自己已存规则的口子没建,core 的
|
|
1290
1365
|
* `removePersistedRule` 在包里但本仓零调用点。一次误导入的全局规则因此会一直生效,租户自己拿它没
|
|
1291
1366
|
* 办法,只能找运维改库。#203 交付的正是那条撤销面本身(`GET /v1/rules` + `DELETE /v1/rules`,后者
|
|
1292
|
-
* 恒经 `removePersistedRule` 产墓碑)加上 operator
|
|
1367
|
+
* 恒经 `removePersistedRule` 产墓碑)加上 operator 的超范围回收腿 ⇒ **前置条件兑现,默认翻转**。
|
|
1293
1368
|
* 记这段史不是怀旧:哪天有人想把某条「只加放行」的车道默认打开,判据就是这一条 —— 收得回来才敢开。
|
|
1294
1369
|
*
|
|
1295
1370
|
* 显式 `PERMISSION_RULES_ENABLED=false` 仍然关得掉(默认翻转不吃部署侧的表态);升级到本版的既有
|
|
@@ -1357,7 +1432,7 @@ export interface ServiceConfigFlat {
|
|
|
1357
1432
|
* 🔴 **射程边界(成文,不是遗漏)**:
|
|
1358
1433
|
* · 唯一让本旋钮**无处施加**的键是 `TOOL_APPROVAL_ENABLED=false`(协调器整体不构造,core 走它自己的
|
|
1359
1434
|
* headless 姿态)。**不造推断腿**:旋钮只在协调器在场时有意义,这一句是成文而不是代码分支。
|
|
1360
|
-
* · ⚠️ **与 `STREAM_APPROVAL_ENABLED` 正交**(codex
|
|
1435
|
+
* · ⚠️ **与 `STREAM_APPROVAL_ENABLED` 正交**(codex 交叉复审 R2-F2 验真后纠正 —— 本注上一版把两者
|
|
1361
1436
|
* 写成了一回事,是错的):协议开关关掉只是不注入 `askStore`/协议窗,协调器照常在场,于是 R-13 的
|
|
1362
1437
|
* D1 窗到期臂**照样**走 park 路由。这不是漏网:设计稿 §2 明写 park 的承载是 **core checkpoint**
|
|
1363
1438
|
* 而不是 server 的 ask 行,「无 askStore 但有 durable 设施」正是 R-13 点名的**主受益部署**。
|
|
@@ -1382,7 +1457,7 @@ export interface ServiceConfigFlat {
|
|
|
1382
1457
|
workflowAgentsReadOnly: boolean;
|
|
1383
1458
|
/** Sandbox-image-pool BAKE job API (IMAGE-API-DESIGN.md §P2): enable /v1/images/bakes* (operator-submit + the
|
|
1384
1459
|
* bake-runner claim/ingest control plane). Requires a TiDB pool (the durable bake row/event/lease tables) AND
|
|
1385
|
-
* a NON-EMPTY `operatorPrincipals` (boot-asserted — never
|
|
1460
|
+
* a NON-EMPTY `operatorPrincipals` (boot-asserted — never an unrestricted-write build-host exec door). Default OFF.
|
|
1386
1461
|
* `IMAGE_BAKES_ENABLED=true`. */
|
|
1387
1462
|
imageBakes: ImageBakeConfig;
|
|
1388
1463
|
/** prove-before-scale stopgap: log every tool call (pre+post, incl. resumed legs) for diagnosis. `TOOL_TRACE=true`. Default OFF. */
|
|
@@ -1390,7 +1465,7 @@ export interface ServiceConfigFlat {
|
|
|
1390
1465
|
/** Task Trace API (S1): persist the agent's reasoning/thinking into the durable run event log (for the CC-style
|
|
1391
1466
|
* trace UI). Default ON; `TRACE_THINKING=false` disables capture for sensitive deployments. Redacted on persist. */
|
|
1392
1467
|
traceThinking: boolean;
|
|
1393
|
-
/** #246(core 5.30.0 readFace 部署座席):READ 容纳面。缺席=不铸(core 引擎默认 roots,server
|
|
1468
|
+
/** #246(core 5.30.0 readFace 部署座席):READ 容纳面。缺席=不铸(core 引擎默认 roots,server 不写死
|
|
1394
1469
|
* 上游默认);显式坏词启动期响亮拒。只影响读面,写面永不受它管(core 契约)。 */
|
|
1395
1470
|
readFace?: "open" | "roots";
|
|
1396
1471
|
/** #246:部署级 READ deny 追加表(additive-only,core 内建表永不可缩)。env=JSON 数组
|
|
@@ -1509,14 +1584,14 @@ export interface ServiceConfigFlat {
|
|
|
1509
1584
|
configLocalDir?: string;
|
|
1510
1585
|
}
|
|
1511
1586
|
/** 组:store(持久化)—— DB 引擎三态、session 后端、SQL coords、快照 BLOB / SendUserFile 对象存储。 */
|
|
1512
|
-
export type ServiceStoreConfig = Pick<ServiceConfigFlat, "sessionBackend" | "sessionCacheTtlSec" | "storeProbeIntervalMs" | "
|
|
1587
|
+
export type ServiceStoreConfig = Pick<ServiceConfigFlat, "sessionBackend" | "sessionCacheTtlSec" | "storeProbeIntervalMs" | "dbBackend" | "dbBackendExplicit" | "localDataRoot" | "runStoreStrictHydrate" | "tidb" | "pg" | "dbQueryTimeoutMs" | "snapshotBlobStore" | "snapshotBlobSqlMaxBytes" | "snapshotBlobAllowSql" | "fileHistory" | "sendUserFile">;
|
|
1513
1588
|
/** 组:modelPlane(模型面)—— 网关坐标、Anthropic 路线、韧性旋钮、主/廉价 model entry、role 表、降级梯。 */
|
|
1514
1589
|
export type ServiceModelPlaneConfig = Pick<ServiceConfigFlat, "gatewayBaseUrl" | "gatewayApiKey" | "gatewayFallbackUrls" | "gatewayMaxRetries" | "anthropic" | "resilience" | "model" | "models" | "modelApiKeyEnv" | "modelApiKeys" | "modelQuotaWeights" | "tiers" | "projects" | "roles" | "atModelAllowlist" | "cascadeLadder" | "degrade">;
|
|
1515
1590
|
/** 组:approval(审批 / HITL 门)。`directDoorActive` 无 env 解析腿(装配层三域合取的产物),但语义上
|
|
1516
1591
|
* 就是本组的门状态,故进组;`parseApprovalDomain` 的返回类型相应是 `Omit<…, "directDoorActive">`。 */
|
|
1517
1592
|
export type ServiceApprovalConfig = Pick<ServiceConfigFlat, "approvalRequire" | "approvalDeny" | "approvalTimeoutSec" | "approvalAutoBudget" | "approvalNeverAuto" | "approvalHmacKeys" | "durableApproval" | "directApprovalDoor" | "directDoorActive" | "resourceSuspend" | "resourceSuspendTtlSec" | "resourceSuspendTotalTokens" | "resourceSuspendTotalBudgetUsd" | "resourceSuspendMaxSlices" | "askQuestionEnabled" | "questionThrottle" | "toolApprovalEnabled" | "permissionRulesEnabled" | "permissionRulesEnabledExplicit" | "streamAskWindowMarginMs" | "streamApproval" | "unattendedApprovalPolicy" | "mcpElicitation" | "sensitiveWritePatterns" | "manualModeShellGate">;
|
|
1518
1593
|
/** 组:memory(记忆面 + TOC 同步腿)。 */
|
|
1519
|
-
export type ServiceMemoryConfig = Pick<ServiceConfigFlat, "memoryEngineEnabled" | "memoryEngineDir" | "memoryEngineRemoteLaneAllowed" | "memoryEngineBackend" | "memoryScope" | "memoryPersistenceCapable" | "memorySync" | "memoryEmbedder" | "memoryOrgAdmissionMode" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryConsolidationDriver" | "memoryOrgDirectoryJson" | "memoryOrgGrantTtlMs" | "memoryOrgUnavailableBackoffMs" | "projectMemoryEnabled" | "syncImportLeaseStaleSec">;
|
|
1594
|
+
export type ServiceMemoryConfig = Pick<ServiceConfigFlat, "memoryEngineEnabled" | "memoryEngineDir" | "memoryEngineRemoteLaneAllowed" | "memoryEngineBackend" | "memoryScope" | "memoryPersistenceCapable" | "memorySync" | "memoryEmbedder" | "memoryOrgAdmissionMode" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "memoryConsolidationDriver" | "memoryOrgDirectoryJson" | "memoryOrgGrantTtlMs" | "memoryOrgUnavailableBackoffMs" | "projectMemoryEnabled" | "syncImportLeaseStaleSec">;
|
|
1520
1595
|
/** 组:auth(鉴权 / 身份 / 治理棒)。`commandPolicy` 只有 sema-registry 腿(无 env 标量形),故 env 解析
|
|
1521
1596
|
* 函数不产出它,但它与 `autonomy` 是同一根治理棒的两半,归本组。
|
|
1522
1597
|
* design/170 的三件部署治理声明(`compliancePosture`/`lockedConfigKeys`/`retentionPolicy`)同归本组:
|
package/dist/config.d.ts
CHANGED
|
@@ -15,11 +15,19 @@ export { RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC } from "./config
|
|
|
15
15
|
export declare function parseAutonomy(raw: string | undefined): Autonomy | undefined;
|
|
16
16
|
/** design/166-T1 — parse `USAGE_WINDOWS`(单键 JSON 数组;逐窗散键在窗数可变时组合爆炸,JSON 是唯一
|
|
17
17
|
* 封闭形)。unset/空串 → undefined(关)。fail-loud 族(numEnv 同纪律):坏 JSON/非数组/空数组/
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* 坏值/未知 anchor 全部 boot throw 点名——「设了但无意义」静默关掉=部署方以为有治理实际没有。
|
|
19
|
+
* S-18(core 7.0.0 `UsageWindow.maxCostUsd`,dist/core/usage-window-store.d.ts:44-68 亲读):
|
|
20
|
+
* `maxTokens` 与 `maxCostUsd` 是两只**独立** ceiling——each optional on its own、**at least one
|
|
21
|
+
* required**(双缺=拒:a window with neither admits nothing it can govern),whichever fills first
|
|
22
|
+
* 即耗尽;缺席的 ceiling 不参与(非 0、非 ∞)。修前这里的白名单重铸只认三键,$ 键配了也被静默
|
|
23
|
+
* 剥掉——正是本函数要消灭的那族病自己。
|
|
24
|
+
* server 严于 core(core 允两 ceiling 取 0=恒满锁死窗;这里都要求正数,0 配置显然是笔误不是意图);
|
|
25
|
+
* `maxCostUsd` 另提前执行 core 的 micro-USD 门(×1e6 仍有限——超界 ceiling 在账本单位里读作 ∞,
|
|
26
|
+
* 「看起来被治理、实际什么都不拦」,core 在门口拒,这里拒在 boot)。 */
|
|
20
27
|
export declare function parseUsageWindows(raw: string | undefined): readonly {
|
|
21
28
|
windowMs: number;
|
|
22
|
-
maxTokens
|
|
29
|
+
maxTokens?: number;
|
|
30
|
+
maxCostUsd?: number;
|
|
23
31
|
anchor: "first-use" | "rolling";
|
|
24
32
|
}[] | undefined;
|
|
25
33
|
/** Numeric env with validation: a non-numeric value FAILS at startup instead of silently becoming `NaN`
|
package/dist/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, formatUserScope, isThinkingLevel, PROTOCOL_TABLE, protocolOf, RECOMMENDED_SENSITIVE_PATTERNS, RETIRED_TOOL_NAMES, resolveLockedKeys, validatePermissionRules } from "@sema-agent/core";
|
|
5
|
+
import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, formatUserScope, isThinkingLevel, PROTOCOL_TABLE, protocolOf, RECOMMENDED_SENSITIVE_PATTERNS, RETIRED_TOOL_NAMES, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules } from "@sema-agent/core";
|
|
6
6
|
import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES } from "@sema-agent/settings-schema";
|
|
7
7
|
import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
|
|
8
8
|
import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
|
|
@@ -38,18 +38,38 @@ export function parseUsageWindows(raw) {
|
|
|
38
38
|
parsed = JSON.parse(v);
|
|
39
39
|
}
|
|
40
40
|
catch (e) {
|
|
41
|
-
throw new Error(`env USAGE_WINDOWS is not valid JSON: ${String(e)} — expected e.g. [{"windowMs":18000000,"maxTokens":5000000,"anchor":"first-use"}]`);
|
|
41
|
+
throw new Error(`env USAGE_WINDOWS is not valid JSON: ${String(e)} — expected e.g. [{"windowMs":18000000,"maxTokens":5000000,"anchor":"first-use"}] or [{"windowMs":604800000,"maxCostUsd":25,"anchor":"rolling"}]`);
|
|
42
42
|
}
|
|
43
43
|
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
44
|
-
throw new Error(`env USAGE_WINDOWS must be a NON-EMPTY JSON array of {windowMs,maxTokens
|
|
44
|
+
throw new Error(`env USAGE_WINDOWS must be a NON-EMPTY JSON array of {windowMs, maxTokens?, maxCostUsd?, anchor} (an empty array is a governance no-op nobody chose — unset the env to turn windows off)`);
|
|
45
45
|
}
|
|
46
46
|
const out = parsed.map((w, i) => {
|
|
47
47
|
const o = w;
|
|
48
48
|
const posInt = (n) => typeof n === "number" && Number.isInteger(n) && n > 0;
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const posUsd = (n) => typeof n === "number" && Number.isFinite(n) && n > 0 && Number.isFinite(n * 1e6);
|
|
50
|
+
if (typeof w !== "object" || w === null || !posInt(o.windowMs) || (o.anchor !== "first-use" && o.anchor !== "rolling")) {
|
|
51
|
+
throw new Error(`env USAGE_WINDOWS[${i}] is invalid: expected {windowMs: positive int ms, maxTokens?: positive int, maxCostUsd?: positive USD, anchor: "first-use"|"rolling"} (got ${JSON.stringify(w)})`);
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
for (const k of Object.keys(w)) {
|
|
54
|
+
if (k !== "windowMs" && k !== "maxTokens" && k !== "maxCostUsd" && k !== "anchor") {
|
|
55
|
+
throw new Error(`env USAGE_WINDOWS[${i}] is invalid: unknown key \`${k}\` — the window shape is the CLOSED set {windowMs, maxTokens?, maxCostUsd?, anchor}; a misspelled ceiling (e.g. \`maxCostUSD\`) must not silently leave the deployment ungoverned (got ${JSON.stringify(w)})`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (o.maxTokens === undefined && o.maxCostUsd === undefined) {
|
|
59
|
+
throw new Error(`env USAGE_WINDOWS[${i}] is invalid: at least one ceiling is required — \`maxTokens\` (tokens) and/or \`maxCostUsd\` (absolute USD); a window with neither admits nothing it can govern (got ${JSON.stringify(w)})`);
|
|
60
|
+
}
|
|
61
|
+
if (o.maxTokens !== undefined && !posInt(o.maxTokens)) {
|
|
62
|
+
throw new Error(`env USAGE_WINDOWS[${i}] is invalid: \`maxTokens\` (when present) must be a positive integer (got ${JSON.stringify(w)})`);
|
|
63
|
+
}
|
|
64
|
+
if (o.maxCostUsd !== undefined && !posUsd(o.maxCostUsd)) {
|
|
65
|
+
throw new Error(`env USAGE_WINDOWS[${i}] is invalid: \`maxCostUsd\` (when present) must be a positive finite USD amount that stays finite in micro-USD (× 1e6) (got ${JSON.stringify(w)})`);
|
|
66
|
+
}
|
|
67
|
+
return Object.freeze({
|
|
68
|
+
windowMs: o.windowMs,
|
|
69
|
+
...(o.maxTokens !== undefined ? { maxTokens: o.maxTokens } : {}),
|
|
70
|
+
...(o.maxCostUsd !== undefined ? { maxCostUsd: o.maxCostUsd } : {}),
|
|
71
|
+
anchor: o.anchor,
|
|
72
|
+
});
|
|
53
73
|
});
|
|
54
74
|
return Object.freeze(out);
|
|
55
75
|
}
|
|
@@ -252,6 +272,35 @@ function optNumEnvStrict(name) {
|
|
|
252
272
|
return undefined;
|
|
253
273
|
return parseNumOrFail(name, raw);
|
|
254
274
|
}
|
|
275
|
+
function parseDevicePreAuthPerRemoteEnv() {
|
|
276
|
+
const raw = process.env.DEVICE_MAX_PREAUTH_PER_REMOTE;
|
|
277
|
+
if (raw === undefined || raw === "")
|
|
278
|
+
return undefined;
|
|
279
|
+
if (raw === "off")
|
|
280
|
+
return "off";
|
|
281
|
+
if (!/^[1-9]\d*$/.test(raw)) {
|
|
282
|
+
throw new Error(`env DEVICE_MAX_PREAUTH_PER_REMOTE=${JSON.stringify(raw)} must be a positive integer or the literal "off" — ` +
|
|
283
|
+
`a malformed cap would otherwise run as the default (8) while the operator believes their value is in force ` +
|
|
284
|
+
`(#210: deployment knobs never fall back silently). "0" is not a valid cap (it would refuse every device handshake); ` +
|
|
285
|
+
`use "off" to disable the per-remote layer explicitly (reverse-proxy / NAT deployments collapse source IPs, A-075.52).`);
|
|
286
|
+
}
|
|
287
|
+
const n = Number(raw);
|
|
288
|
+
if (!Number.isSafeInteger(n)) {
|
|
289
|
+
throw new Error(`env DEVICE_MAX_PREAUTH_PER_REMOTE=${raw.length > 24 ? `${raw.slice(0, 24)}…(${raw.length} digits)` : raw} overflows the safe-integer range — ` +
|
|
290
|
+
`Number() would read it as ${n}, and a cap of Infinity silently disables the per-remote layer without taking the explicit "off" arm. ` +
|
|
291
|
+
`Use a value within Number.MAX_SAFE_INTEGER, or the literal "off".`);
|
|
292
|
+
}
|
|
293
|
+
return n;
|
|
294
|
+
}
|
|
295
|
+
function parseFileHistoryRetention() {
|
|
296
|
+
const raw = process.env.FILE_HISTORY_RETENTION_KEEP;
|
|
297
|
+
if (raw === undefined || raw === "")
|
|
298
|
+
return undefined;
|
|
299
|
+
const keep = raw === "unbounded" ? "unbounded" : /^(?:0|[1-9]\d*)$/.test(raw) ? Number(raw) : raw;
|
|
300
|
+
const policy = { keep };
|
|
301
|
+
resolveFileHistoryRetention("FILE_HISTORY_RETENTION_KEEP", policy);
|
|
302
|
+
return { retention: policy };
|
|
303
|
+
}
|
|
255
304
|
function optFinitePositiveEnv(name) {
|
|
256
305
|
const raw = process.env[name];
|
|
257
306
|
if (raw === undefined || raw === "")
|
|
@@ -503,10 +552,10 @@ function parseStoreDomain(ctx) {
|
|
|
503
552
|
sessionBackend,
|
|
504
553
|
sessionCacheTtlSec: numEnv("SESSION_CACHE_TTL_SEC", "300"),
|
|
505
554
|
storeProbeIntervalMs: numEnvBounded("STORE_PROBE_INTERVAL_MS", "15000", 0, 3_600_000),
|
|
506
|
-
rewindSnapshotMaxMb: optFinitePositiveEnv("REWIND_SNAPSHOT_MAX_MB"),
|
|
507
555
|
dbBackend,
|
|
508
556
|
dbBackendExplicit: dbBackendSet,
|
|
509
557
|
localDataRoot,
|
|
558
|
+
runStoreStrictHydrate: parseRunStoreStrictHydrate(process.env.RUN_STORE_STRICT_HYDRATE),
|
|
510
559
|
tidb: needsDb && dbBackend === "mysql"
|
|
511
560
|
? {
|
|
512
561
|
host: env("MYSQL_HOST"),
|
|
@@ -541,6 +590,7 @@ function parseStoreDomain(ctx) {
|
|
|
541
590
|
: undefined,
|
|
542
591
|
snapshotBlobSqlMaxBytes: optFinitePositiveEnv("SNAPSHOT_BLOB_SQL_MAX_BYTES"),
|
|
543
592
|
snapshotBlobAllowSql: boolEnv("SNAPSHOT_BLOB_ALLOW_SQL_BYTES", false),
|
|
593
|
+
fileHistory: parseFileHistoryRetention(),
|
|
544
594
|
sendUserFile: (process.env.MINIO_ENDPOINT || process.env.S3_ENDPOINT) && process.env.MINIO_ACCESS_KEY && process.env.MINIO_SECRET_KEY
|
|
545
595
|
? {
|
|
546
596
|
endpoint: (process.env.MINIO_ENDPOINT || process.env.S3_ENDPOINT),
|
|
@@ -803,7 +853,7 @@ export function formatUnmatchableToolNames(source, bad) {
|
|
|
803
853
|
return (`${source} names tool(s) that can never match a live tool (these lists are RAW whole-name comparisons — core 5.0.0 RB-476 removed the alias/auto-prefix folds): ` +
|
|
804
854
|
bad.map((b) => `${presentToolName(b.name)} → ${b.guidance}`).join("; ")).replace(CONTROL_AND_BIDI_STRIP_RE, "");
|
|
805
855
|
}
|
|
806
|
-
function streamApprovalConfig() {
|
|
856
|
+
function streamApprovalConfig(gates) {
|
|
807
857
|
const cfg = {
|
|
808
858
|
enabled: boolEnv("STREAM_APPROVAL_ENABLED", true),
|
|
809
859
|
windowMs: numEnv("STREAM_ASK_WINDOW_MS", "300000"),
|
|
@@ -814,10 +864,15 @@ function streamApprovalConfig() {
|
|
|
814
864
|
pendingGraceMs: numEnvBounded("STREAM_APPROVAL_PENDING_GRACE_MS", "30000", 0, 3_600_000),
|
|
815
865
|
adhocGraceMs: numEnvBounded("STREAM_APPROVAL_ADHOC_GRACE_MS", "60000", 0, 86_400_000),
|
|
816
866
|
orphanTtlMs: numEnvBounded("STREAM_APPROVAL_ORPHAN_TTL_MS", String(7 * 24 * 60 * 60 * 1000), 60_000, 90 * 24 * 60 * 60 * 1000),
|
|
867
|
+
unreachedTtlMs: numEnvBounded("UNREACHED_ASK_TTL_MS", String(60 * 60 * 1000), 60_000, 24 * 60 * 60 * 1000),
|
|
817
868
|
};
|
|
818
869
|
if (cfg.windowMs + cfg.adhocGraceMs >= cfg.orphanTtlMs) {
|
|
819
870
|
throw new Error(`env STREAM_ASK_WINDOW_MS=${cfg.windowMs} + STREAM_APPROVAL_ADHOC_GRACE_MS=${cfg.adhocGraceMs} must be STRICTLY LESS than STREAM_APPROVAL_ORPHAN_TTL_MS=${cfg.orphanTtlMs} — the adhoc arm fires at (createdAt + window + grace) while the orphan backstop fires at (createdAt + ttl); if the backstop wins, every adhoc-leg row is attributed "orphan_ttl_exceeded" instead of "adhoc_leg_no_durable_domain" (attribution honesty, design/172 §6.1)`);
|
|
820
871
|
}
|
|
872
|
+
const suspendedRowsPossible = cfg.enabled && gates.toolApprovalEnabled && gates.unattendedPolicy !== "deny";
|
|
873
|
+
if (suspendedRowsPossible && cfg.unreachedTtlMs + cfg.adhocGraceMs >= cfg.orphanTtlMs) {
|
|
874
|
+
throw new Error(`env UNREACHED_ASK_TTL_MS=${cfg.unreachedTtlMs} + STREAM_APPROVAL_ADHOC_GRACE_MS=${cfg.adhocGraceMs} must be STRICTLY LESS than STREAM_APPROVAL_ORPHAN_TTL_MS=${cfg.orphanTtlMs} — an ask minted with NO live stream (case A: a workflow child ask) waits UNREACHED_ASK_TTL_MS, so its row expires at (createdAt + that window); the orphan backstop fires at (createdAt + ttl). If the backstop wins, every suspended row is attributed "orphan_ttl_exceeded" instead of its real cause (attribution honesty, same rule as the STREAM_ASK_WINDOW_MS line above)`);
|
|
875
|
+
}
|
|
821
876
|
if (!Number.isInteger(cfg.reconcileBatch)) {
|
|
822
877
|
throw new Error(`env STREAM_APPROVAL_RECONCILE_BATCH=${cfg.reconcileBatch} must be an INTEGER row count`);
|
|
823
878
|
}
|
|
@@ -836,6 +891,8 @@ function unattendedApprovalPolicyEnv() {
|
|
|
836
891
|
}
|
|
837
892
|
function parseApprovalDomain(ctx) {
|
|
838
893
|
const { postureOn } = ctx;
|
|
894
|
+
const unattendedPolicy = unattendedApprovalPolicyEnv();
|
|
895
|
+
const toolApprovalEnabled = postureOn("TOOL_APPROVAL_ENABLED");
|
|
839
896
|
const directApprovalDoor = boolEnv("DIRECT_APPROVAL_DOOR", false);
|
|
840
897
|
const dgHmacKeys = parseApprovalHmacKeys(process.env.APPROVAL_HMAC_KEYS, announceKeySetRejection("APPROVAL_HMAC_KEYS"));
|
|
841
898
|
const durableApproval = boolEnv("DURABLE_APPROVAL", false);
|
|
@@ -903,12 +960,12 @@ function parseApprovalDomain(ctx) {
|
|
|
903
960
|
maxTotalPerRun: numEnvBounded("QUESTION_MAX_TOTAL_PER_RUN", String(DEFAULT_QUESTION_THROTTLE.maxTotalPerRun), 1, 10_000),
|
|
904
961
|
ttlMs: numEnvBounded("QUESTION_TTL_MS", String(DEFAULT_QUESTION_THROTTLE.ttlMs), 1_000, 3_600_000),
|
|
905
962
|
},
|
|
906
|
-
toolApprovalEnabled
|
|
963
|
+
toolApprovalEnabled,
|
|
907
964
|
permissionRulesEnabled: boolEnv("PERMISSION_RULES_ENABLED", true),
|
|
908
965
|
permissionRulesEnabledExplicit: parseBoolWord("PERMISSION_RULES_ENABLED", process.env["PERMISSION_RULES_ENABLED"]) !== undefined,
|
|
909
966
|
streamAskWindowMarginMs: numEnv("STREAM_ASK_WINDOW_MARGIN_MS", "10000"),
|
|
910
|
-
streamApproval: streamApprovalConfig(),
|
|
911
|
-
unattendedApprovalPolicy:
|
|
967
|
+
streamApproval: streamApprovalConfig({ unattendedPolicy, toolApprovalEnabled }),
|
|
968
|
+
unattendedApprovalPolicy: unattendedPolicy,
|
|
912
969
|
approvalTimeoutSec: numEnv("APPROVAL_TIMEOUT_SEC", "0"),
|
|
913
970
|
};
|
|
914
971
|
}
|
|
@@ -939,6 +996,20 @@ function parseMemoryPersistenceCapable(raw) {
|
|
|
939
996
|
`\`# Memory\` write instruction on a remote execution lane) or ${MEMORY_ENGINE_OFF_WORDS.join(" | ")} (it CANNOT — ` +
|
|
940
997
|
`forces the read-only disclosure). Leave it UNSET to let the engine infer from the mounted roster.`);
|
|
941
998
|
}
|
|
999
|
+
function parseRunStoreStrictHydrate(raw) {
|
|
1000
|
+
const w = (raw ?? "").trim().toLowerCase();
|
|
1001
|
+
if (w === "")
|
|
1002
|
+
return false;
|
|
1003
|
+
if (MEMORY_ENGINE_ON_WORDS.includes(w))
|
|
1004
|
+
return true;
|
|
1005
|
+
if (MEMORY_ENGINE_OFF_WORDS.includes(w))
|
|
1006
|
+
return false;
|
|
1007
|
+
throw new Error(`env RUN_STORE_STRICT_HYDRATE="${raw}" is not a known on/off word — use one of: ${MEMORY_ENGINE_ON_WORDS.join(" | ")} ` +
|
|
1008
|
+
"(the file run-store REFUSES TO BOOT when it cannot list its runs/ directory) or " +
|
|
1009
|
+
`${MEMORY_ENGINE_OFF_WORDS.join(" | ")} (the default: boot anyway with an empty ledger, disclosed by the ` +
|
|
1010
|
+
"file_run_store_hydrate_unreadable error line + the server.run-store.file-hydrate-unreadable counter). " +
|
|
1011
|
+
"An unrecognized value must not fold to the default: that would silently swallow an operator's explicit fail-closed request.");
|
|
1012
|
+
}
|
|
942
1013
|
const SANDBOX_PKG_SOURCES = ["global", "cn", "custom", "none"];
|
|
943
1014
|
function pkgSourceEnv() {
|
|
944
1015
|
const v = env("SANDBOX_PKG_SOURCE", "global");
|
|
@@ -1144,6 +1215,9 @@ function parseMemoryDomain(ctx) {
|
|
|
1144
1215
|
...(process.env.MEMORY_PROVENANCE !== undefined
|
|
1145
1216
|
? { memoryProvenance: enumEnv("MEMORY_PROVENANCE", "carry", ["off", "carry"]) }
|
|
1146
1217
|
: {}),
|
|
1218
|
+
...(process.env.MEMORY_CAPTURE_POLICY !== undefined
|
|
1219
|
+
? { memoryCapturePolicy: enumEnv("MEMORY_CAPTURE_POLICY", "open", ["open", "governed", "capture-required"]) }
|
|
1220
|
+
: {}),
|
|
1147
1221
|
memoryConsolidationDriver: parseMemoryConsolidationDriver(),
|
|
1148
1222
|
...(process.env.DELEGATION_MAX_CONCURRENT !== undefined || process.env.DELEGATION_MAX_PER_SESSION !== undefined
|
|
1149
1223
|
? {
|
|
@@ -1400,6 +1474,7 @@ function parseOrchestrationDomain(ctx) {
|
|
|
1400
1474
|
...((n) => (n !== undefined ? { reconnectGraceMs: n } : {}))(optNumEnvStrict("DEVICE_RECONNECT_GRACE_MS")),
|
|
1401
1475
|
...((n) => (n !== undefined ? { execTimeoutMs: n } : {}))(optNumEnvStrict("DEVICE_EXEC_TIMEOUT_MS")),
|
|
1402
1476
|
...((n) => (n !== undefined ? { maxInflightPerDevice: n } : {}))(optNumEnvStrict("DEVICE_MAX_INFLIGHT_PER_DEVICE")),
|
|
1477
|
+
...((n) => (n !== undefined ? { maxPreAuthPerRemote: n } : {}))(parseDevicePreAuthPerRemoteEnv()),
|
|
1403
1478
|
...(process.env.DEVICE_SUPERSEDE ? { supersede: enumEnv("DEVICE_SUPERSEDE", "stale_only", ["stale_only", "deny"]) } : {}),
|
|
1404
1479
|
}
|
|
1405
1480
|
:
|
|
@@ -1669,8 +1744,9 @@ function parseA2aServeSkills(raw) {
|
|
|
1669
1744
|
});
|
|
1670
1745
|
}
|
|
1671
1746
|
const STORE_GROUP_KEYS = [
|
|
1672
|
-
"sessionBackend", "sessionCacheTtlSec", "storeProbeIntervalMs", "
|
|
1673
|
-
"
|
|
1747
|
+
"sessionBackend", "sessionCacheTtlSec", "storeProbeIntervalMs", "dbBackend", "dbBackendExplicit", "localDataRoot",
|
|
1748
|
+
"runStoreStrictHydrate",
|
|
1749
|
+
"tidb", "pg", "dbQueryTimeoutMs", "snapshotBlobStore", "snapshotBlobSqlMaxBytes", "snapshotBlobAllowSql", "fileHistory", "sendUserFile",
|
|
1674
1750
|
];
|
|
1675
1751
|
const MODEL_PLANE_GROUP_KEYS = [
|
|
1676
1752
|
"gatewayBaseUrl", "gatewayApiKey", "gatewayFallbackUrls", "gatewayMaxRetries", "anthropic", "resilience", "model", "models",
|
|
@@ -1684,7 +1760,7 @@ const APPROVAL_GROUP_KEYS = [
|
|
|
1684
1760
|
];
|
|
1685
1761
|
const MEMORY_GROUP_KEYS = [
|
|
1686
1762
|
"memoryEngineEnabled", "memoryEngineDir", "memoryEngineRemoteLaneAllowed", "memoryEngineBackend", "memoryScope",
|
|
1687
|
-
"memoryPersistenceCapable", "memorySync", "memoryEmbedder", "memoryOrgAdmissionMode", "memoryDelegationEvidence", "memoryProvenance", "memoryConsolidationDriver", "memoryOrgDirectoryJson", "memoryOrgGrantTtlMs", "memoryOrgUnavailableBackoffMs",
|
|
1763
|
+
"memoryPersistenceCapable", "memorySync", "memoryEmbedder", "memoryOrgAdmissionMode", "memoryDelegationEvidence", "memoryProvenance", "memoryCapturePolicy", "memoryConsolidationDriver", "memoryOrgDirectoryJson", "memoryOrgGrantTtlMs", "memoryOrgUnavailableBackoffMs",
|
|
1688
1764
|
"projectMemoryEnabled", "syncImportLeaseStaleSec",
|
|
1689
1765
|
];
|
|
1690
1766
|
const AUTH_GROUP_KEYS = [
|
|
@@ -1792,7 +1868,7 @@ export function loadConfig() {
|
|
|
1792
1868
|
if (dgOperators.length === 0)
|
|
1793
1869
|
missing.push("OPERATOR_PRINCIPALS (else isOperator is true-for-all)");
|
|
1794
1870
|
if (!requirePrincipal)
|
|
1795
|
-
missing.push("REQUIRE_PRINCIPAL=true (a direct door is multi-tenant; without it an absent principal is anonymous and the
|
|
1871
|
+
missing.push("REQUIRE_PRINCIPAL=true (a direct door is multi-tenant; without it an absent principal is anonymous and the self-asserted header governs owner/quota checks)");
|
|
1796
1872
|
if (missing.length) {
|
|
1797
1873
|
throw new Error(`DIRECT_APPROVAL_DOOR=true but D-G anchors are missing: ${missing.join(", ")} — refusing to start a half-open direct door (design/80 D-G boot invariant)`);
|
|
1798
1874
|
}
|
|
@@ -57,7 +57,7 @@ export interface DurableApprovalSeat {
|
|
|
57
57
|
*/
|
|
58
58
|
export declare function createDurableQuestionGate(live: LiveQuestionFace | undefined): ToolPolicy;
|
|
59
59
|
/**
|
|
60
|
-
* 沙箱 lane 上**相对形**写目标的守卫补层用 env(codex
|
|
60
|
+
* 沙箱 lane 上**相对形**写目标的守卫补层用 env(codex 交叉复审 round1 finding 1,红先复现)。
|
|
61
61
|
*
|
|
62
62
|
* 缺口:沙箱 lane 的守卫策略拿不到 `rootPath`(沙箱 cwd 不是 server 能猜的,#165 裁定 1),而
|
|
63
63
|
* `DeferredSandboxPathEnv.absolutePath` 对相对形一律报错。core 的 `canonicalizeTarget` 在
|
|
@@ -52,7 +52,7 @@ export interface DeviceEnrollRateLimiter {
|
|
|
52
52
|
export interface EnrollDeviceInput {
|
|
53
53
|
/** 明文 token(**只**在这里出现,落库前立刻摘要)。 */
|
|
54
54
|
token: string;
|
|
55
|
-
/** 请求方**验证过**的复合身份(SSO
|
|
55
|
+
/** 请求方**验证过**的复合身份(SSO/凭据链产出,恒不取自可自造头)。 */
|
|
56
56
|
requester: DeviceOwner;
|
|
57
57
|
/** 🔴 `deviceId` 与 `owner` **不在**这里:前者恒由 server 铸(调用方选 id = 让请求方挑自己的设备身份,
|
|
58
58
|
* 与 §6「server 铸 dev_<ulid>」相悖),后者恒取自**验证过的** requester —— 两个字段都不接受请求体供给。
|
|
@@ -76,7 +76,7 @@ export interface AdmitSessionValue {
|
|
|
76
76
|
/**
|
|
77
77
|
* 判决**当刻**的连接世代(§4.6 fencing token)。
|
|
78
78
|
*
|
|
79
|
-
* 🔴 **准入判决是一个快照,不是一把锁**(codex
|
|
79
|
+
* 🔴 **准入判决是一个快照,不是一把锁**(codex 交叉轮 F4,判真但归属下一车):`admitSession` 返回后、
|
|
80
80
|
* 调用方真正下发指令前,一次 `revokeDevice` 可以提交 —— 它会作废租约并把 `conn_generation` 推进一格,
|
|
81
81
|
* 但它**追不回**已经基于旧判决发出去的指令。这不是本层能关掉的窗(§6 注③ 刻意不落指令表,所以持久层
|
|
82
82
|
* 没有「派发」这个写点可以带谓词);设计给的答案是**在下发边界重新断言世代**(§4.6 步 2/3:每一次带
|
package/dist/device-store.d.ts
CHANGED
|
@@ -146,7 +146,7 @@ export declare function assertIssueTokenShape(input: IssueEnrollTokenInput): voi
|
|
|
146
146
|
export declare function assertRevokeShape(input: RevokeDeviceInput): void;
|
|
147
147
|
export declare function assertAcquireShape(input: AcquireConnectionInput): void;
|
|
148
148
|
/** token 摘要必须是**规范形**(小写 sha256 hex):大小写混形在 VARBINARY/COLLATE "C" 下是两个键,
|
|
149
|
-
* 于是同一个明文 token 能被消费两次 —— 这是 §7-T5 ③「一次性 CAS
|
|
149
|
+
* 于是同一个明文 token 能被消费两次 —— 这是 §7-T5 ③「一次性 CAS」的直接跳过面。 */
|
|
150
150
|
export declare function assertEnrollTokenHashShape(tokenHash: string): void;
|
|
151
151
|
/**
|
|
152
152
|
* 闭集列的**读侧**解码 —— 三个 `parse*` 是这些词表的唯一解码点(SQL 店读回的字符串必须经此)。
|
|
@@ -154,7 +154,7 @@ export declare function assertEnrollTokenHashShape(tokenHash: string): void;
|
|
|
154
154
|
* 🔴 认不出的值 = **抛**,不是静默 cast(#157:安全轴的未知词是 fail-loud 而不是 fail-open)。
|
|
155
155
|
* 一行 `status='disabled'` 的设备如果被 `as DeviceStatus` 静默放行,准入链的 `status === "revoked"`
|
|
156
156
|
* 判据就对它返回「不是吊销的」⇒ 一台被管理面停用的设备照常领活。写侧不可能产出这些值(入参是
|
|
157
|
-
* TS 闭集)
|
|
157
|
+
* TS 闭集),所以出现即「有人跳过本店直接写库」或「跨版本降级读新词」,两者都必须响亮。
|
|
158
158
|
*/
|
|
159
159
|
export declare function parseDeviceStatus(v: string): DeviceStatus;
|
|
160
160
|
export declare function parseDevicePlatformOs(v: string): DevicePlatformOs;
|
|
@@ -189,7 +189,7 @@ export interface IssueEnrollTokenInput {
|
|
|
189
189
|
}
|
|
190
190
|
export interface ConsumeEnrollTokenInput {
|
|
191
191
|
tokenHash: string;
|
|
192
|
-
/** 请求方**验证过**的复合身份(
|
|
192
|
+
/** 请求方**验证过**的复合身份(不取自可自造头);与 token 的 target 逐字节比对。 */
|
|
193
193
|
requester: DeviceOwner;
|
|
194
194
|
device: NewDeviceInput;
|
|
195
195
|
}
|
package/dist/device-ws-hub.d.ts
CHANGED
|
@@ -151,8 +151,10 @@ export interface DeviceWsHubOptions {
|
|
|
151
151
|
chunkBufferMaxBytes?: number;
|
|
152
152
|
/** codex R1-F3:本副本**未鉴权**连接的并发帽(超额在 upgrade 阶段就 503 拒)。 */
|
|
153
153
|
maxPreAuthConnections?: number;
|
|
154
|
-
/** codex R1-F3:单来源地址的未鉴权连接并发帽。
|
|
155
|
-
|
|
154
|
+
/** codex R1-F3:单来源地址的未鉴权连接并发帽。S-04(A-075.52):字面 `off` = 显式停用该层——
|
|
155
|
+
* 帽键是裸 remoteAddress,XFF 反代 / 公司 NAT 部署形把全员折叠成单键,这层从公平层退化成
|
|
156
|
+
* 「全员共享一份预算」;停层后全局帽(`maxPreAuthConnections`)照常兜底。 */
|
|
157
|
+
maxPreAuthConnectionsPerRemote?: number | "off";
|
|
156
158
|
}
|
|
157
159
|
export interface DeviceWsHub {
|
|
158
160
|
/** 把 `GET /v1/device/ws` 的 upgrade 处理器挂到裸 `http.Server` 上。 */
|