@sema-agent/server 7.4.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +18 -3
- package/README.zh-CN.md +14 -3
- package/USAGE.md +80 -1
- package/dist/approval-card.d.ts +15 -3
- package/dist/approval-card.js +41 -7
- package/dist/approval-reconciler.d.ts +109 -12
- package/dist/approval-reconciler.js +152 -24
- package/dist/boot/config-center.js +15 -2
- package/dist/boot/coordinators.js +10 -2
- package/dist/boot/execution-env.js +1 -1
- package/dist/boot/org-memory.d.ts +6 -0
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/parked-revive-gate.d.ts +78 -0
- package/dist/boot/parked-revive-gate.js +114 -0
- package/dist/boot/reapers.d.ts +2 -0
- package/dist/boot/reapers.js +11 -4
- package/dist/boot/resolve-spec.d.ts +3 -19
- package/dist/boot/resolve-spec.js +73 -67
- package/dist/boot/runner-deps.d.ts +23 -1
- package/dist/boot/runner-deps.js +8 -11
- package/dist/boot/workflow-orchestration.d.ts +8 -3
- package/dist/boot/workflow-orchestration.js +23 -1
- package/dist/budget.d.ts +1 -1
- package/dist/budget.js +1 -1
- package/dist/capabilities/repo-tools.d.ts +1 -1
- package/dist/capabilities/repo-tools.js +8 -2
- package/dist/config-center/apply-effective.js +33 -10
- package/dist/config-provider.d.ts +1 -0
- package/dist/config-provider.js +23 -3
- package/dist/config-types.d.ts +27 -9
- package/dist/config.d.ts +6 -1
- package/dist/config.js +61 -15
- package/dist/deployment-governance.d.ts +168 -0
- package/dist/deployment-governance.js +206 -0
- package/dist/env-facts.d.ts +3 -1
- package/dist/env-facts.js +3 -1
- package/dist/fleet/fleet-bus.d.ts +17 -2
- package/dist/fleet/fleet-bus.js +68 -3
- package/dist/fleet/fleet-terminal-window.d.ts +98 -0
- package/dist/fleet/fleet-terminal-window.js +316 -0
- package/dist/governance-ask-marks.d.ts +31 -0
- package/dist/governance-ask-marks.js +122 -0
- package/dist/hooks/hook-runner.d.ts +28 -0
- package/dist/hooks/hook-runner.js +149 -25
- package/dist/http/routes/approvals-assistant.js +6 -7
- package/dist/http/routes/diagnostics.js +10 -5
- package/dist/http/routes/fleet.js +160 -14
- package/dist/http/routes/memory-policy.d.ts +2 -1
- package/dist/http/routes/memory-policy.js +77 -13
- package/dist/http/routes/runs.js +6 -2
- package/dist/http/routes/tasks.js +59 -22
- package/dist/http/routes/trace-usage.js +3 -4
- package/dist/http/send.d.ts +23 -0
- package/dist/http/send.js +23 -0
- package/dist/http/server.d.ts +9 -0
- package/dist/http/server.js +28 -14
- package/dist/http/sse-log.js +3 -4
- package/dist/http/wire-types.d.ts +7 -2
- package/dist/leader/diffout.d.ts +10 -0
- package/dist/leader/diffout.js +14 -2
- package/dist/leader/diffup.js +3 -2
- package/dist/leader/planner.js +7 -0
- package/dist/main.js +39 -31
- package/dist/observability/fail-open.d.ts +17 -2
- package/dist/observability/fail-open.js +19 -4
- package/dist/observability/prompt-manifest.d.ts +5 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +58 -2
- package/dist/orchestration/workflow-notify-journal.js +130 -45
- package/dist/parked-decide.js +9 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -2
- package/dist/plugins/approval-ask-store-memory.js +3 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +60 -5
- package/dist/plugins/approval-ask-store-sql.js +75 -35
- package/dist/plugins/background-agent-store-sql.js +16 -16
- package/dist/plugins/background-shell-support.d.ts +1 -1
- package/dist/plugins/background-shell-support.js +2 -2
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +67 -8
- package/dist/plugins/checkpoint-store-sql.js +76 -13
- package/dist/plugins/image-bake-store-sql.d.ts +1 -1
- package/dist/plugins/image-bake-store-sql.js +27 -27
- package/dist/plugins/image-index-sql.js +15 -15
- package/dist/plugins/local-checkpoint-store.d.ts +20 -1
- package/dist/plugins/local-checkpoint-store.js +19 -0
- package/dist/plugins/mailbox-store-sql.d.ts +4 -10
- package/dist/plugins/mailbox-store-sql.js +59 -6
- package/dist/plugins/memory-engine-pg.js +9 -9
- package/dist/plugins/memory-engine-tidb.js +7 -7
- package/dist/plugins/memory-sync-store-pg.js +13 -13
- package/dist/plugins/memory-sync-store-tidb.js +5 -5
- package/dist/plugins/outcome-ledger-sql.js +7 -7
- package/dist/plugins/pg-cost-quota.js +3 -3
- package/dist/plugins/pg-pool.js +84 -75
- package/dist/plugins/pg-rate-limiter.js +3 -3
- package/dist/plugins/pg-session-storage.d.ts +1 -1
- package/dist/plugins/pg-session-storage.js +12 -13
- package/dist/plugins/remote-env-host.js +3 -1
- package/dist/plugins/remote-env-local-docker.js +6 -3
- package/dist/plugins/remote-env-ssh.d.ts +13 -1
- package/dist/plugins/roster-store-sql.js +8 -8
- package/dist/plugins/store-contracts.d.ts +19 -0
- package/dist/plugins/store-contracts.js +42 -0
- package/dist/plugins/task-attachment-store.js +5 -5
- package/dist/plugins/task-list-store-sql.js +1 -1
- package/dist/plugins/tidb-cost-quota.js +1 -1
- package/dist/plugins/tidb-pool.js +83 -60
- package/dist/plugins/tidb-rate-limiter.js +1 -1
- package/dist/plugins/tidb-session-store.js +2 -5
- package/dist/plugins/tool-result-store-sql.js +2 -2
- package/dist/plugins/usage-window-store-sql.js +13 -13
- package/dist/plugins/write-behind-counter.d.ts +10 -2
- package/dist/plugins/write-behind-counter.js +13 -3
- package/dist/resource-suspend.d.ts +3 -1
- package/dist/resource-suspend.js +3 -1
- package/dist/run-local.d.ts +73 -1
- package/dist/run-local.js +146 -5
- package/dist/runs.d.ts +11 -1
- package/dist/runs.js +18 -3
- package/dist/runtime-governance.d.ts +18 -0
- package/dist/runtime-governance.js +90 -3
- package/dist/security.d.ts +12 -0
- package/dist/security.js +12 -0
- package/dist/session-sync-kernel.d.ts +13 -0
- package/dist/session-sync-kernel.js +13 -0
- package/dist/task-settings.d.ts +3 -9
- package/dist/task-settings.js +16 -13
- package/dist/tool-approval.d.ts +33 -6
- package/dist/tool-approval.js +80 -23
- package/dist/trace/core-keyset-guard.d.ts +18 -4
- package/dist/trace/project.d.ts +10 -1
- package/dist/trace/project.js +31 -0
- package/package.json +3 -3
- package/dist/boot/lexical-path-env.d.ts +0 -10
- package/dist/boot/lexical-path-env.js +0 -88
- package/dist/capabilities/oa-tools.d.ts +0 -15
- package/dist/capabilities/oa-tools.js +0 -54
- package/dist/finance/cost-taxonomy.d.ts +0 -34
- package/dist/finance/cost-taxonomy.js +0 -26
- package/dist/plugins/approval-store-sql.d.ts +0 -116
- package/dist/plugins/approval-store-sql.js +0 -151
- package/dist/plugins/file-workflow-journal-store.d.ts +0 -12
- package/dist/plugins/file-workflow-journal-store.js +0 -12
- package/dist/plugins/pg-approval-store.d.ts +0 -9
- package/dist/plugins/pg-approval-store.js +0 -9
- package/dist/plugins/pg-breaker-state.d.ts +0 -8
- package/dist/plugins/pg-breaker-state.js +0 -8
- package/dist/plugins/pg-checkpoint-store.d.ts +0 -10
- package/dist/plugins/pg-checkpoint-store.js +0 -10
- package/dist/plugins/pg-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/pg-file-snapshot-store.js +0 -8
- package/dist/plugins/pg-image-bake.d.ts +0 -12
- package/dist/plugins/pg-image-bake.js +0 -11
- package/dist/plugins/pg-image-index.d.ts +0 -12
- package/dist/plugins/pg-image-index.js +0 -11
- package/dist/plugins/pg-outcome-ledger.d.ts +0 -12
- package/dist/plugins/pg-outcome-ledger.js +0 -11
- package/dist/plugins/pg-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/pg-resume-anchor-store.js +0 -7
- package/dist/plugins/pg-run-store.d.ts +0 -9
- package/dist/plugins/pg-run-store.js +0 -9
- package/dist/plugins/pg-session-policy-store.d.ts +0 -7
- package/dist/plugins/pg-session-policy-store.js +0 -7
- package/dist/plugins/pg-session-store.d.ts +0 -12
- package/dist/plugins/pg-session-store.js +0 -12
- package/dist/plugins/pg-tool-result-store.d.ts +0 -9
- package/dist/plugins/pg-tool-result-store.js +0 -9
- package/dist/plugins/pg-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-journal-store.js +0 -9
- package/dist/plugins/pg-workflow-run-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-run-store.js +0 -9
- package/dist/plugins/tidb-approval-store.d.ts +0 -8
- package/dist/plugins/tidb-approval-store.js +0 -8
- package/dist/plugins/tidb-breaker-state.d.ts +0 -7
- package/dist/plugins/tidb-breaker-state.js +0 -7
- package/dist/plugins/tidb-checkpoint-store.d.ts +0 -9
- package/dist/plugins/tidb-checkpoint-store.js +0 -9
- package/dist/plugins/tidb-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/tidb-file-snapshot-store.js +0 -8
- package/dist/plugins/tidb-image-bake.d.ts +0 -12
- package/dist/plugins/tidb-image-bake.js +0 -11
- package/dist/plugins/tidb-image-index.d.ts +0 -12
- package/dist/plugins/tidb-image-index.js +0 -11
- package/dist/plugins/tidb-outcome-ledger.d.ts +0 -12
- package/dist/plugins/tidb-outcome-ledger.js +0 -12
- package/dist/plugins/tidb-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/tidb-resume-anchor-store.js +0 -7
- package/dist/plugins/tidb-run-store.d.ts +0 -10
- package/dist/plugins/tidb-run-store.js +0 -9
- package/dist/plugins/tidb-session-policy-store.d.ts +0 -7
- package/dist/plugins/tidb-session-policy-store.js +0 -7
- package/dist/plugins/tidb-tool-result-store.d.ts +0 -8
- package/dist/plugins/tidb-tool-result-store.js +0 -10
- package/dist/plugins/tidb-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/tidb-workflow-journal-store.js +0 -9
- package/dist/plugins/tidb-workflow-run-store.d.ts +0 -10
- package/dist/plugins/tidb-workflow-run-store.js +0 -10
- package/dist/plugins/workflow-journal-limits.d.ts +0 -12
- package/dist/plugins/workflow-journal-limits.js +0 -12
- package/dist/sema-registry.d.ts +0 -41
- package/dist/sema-registry.js +0 -40
package/dist/config-types.d.ts
CHANGED
|
@@ -25,12 +25,12 @@ export interface ScopedMcpServer {
|
|
|
25
25
|
/** #151 车3(design/172 流内审批协议)的配置面。总开关默认 **false**;四个从属旋钮只在开关为真时生效
|
|
26
26
|
* (语义与「谁需要 / 谁被伤 / 什么补偿」三问见 `ServiceConfigFlat.streamApproval` 的注)。 */
|
|
27
27
|
export interface StreamApprovalConfig {
|
|
28
|
-
/** 协议总开关。`STREAM_APPROVAL_ENABLED`,默认 **false
|
|
28
|
+
/** 协议总开关。`STREAM_APPROVAL_ENABLED`,默认 **true**(clay 裁 2026-08-08,#164 翻真验证后;7.5.0 起)。显式 false ⇒ 全链逐字 7.3.0 前行为(唯一干净还原键)。
|
|
29
29
|
* 翻真要等回决端点(车4)与对账收敛器(车5)到位——在此之前是个不完整协议(有卡无正规回决口、
|
|
30
30
|
* 有 PARKING 无收敛器、跨副本回决无唤醒路径)。 */
|
|
31
31
|
enabled: boolean;
|
|
32
32
|
/** 开关为真时作为 `ToolApprovalCoordinator` 的 `ttlMs`(design/172 §3.3 的「配置窗默认」)。
|
|
33
|
-
* `STREAM_ASK_WINDOW_MS`,默认 **
|
|
33
|
+
* `STREAM_ASK_WINDOW_MS`,默认 **300000**(同裁与 sync 腿既有 5min 活卡窗对齐)。`0` = 运维显式关窗 ⇒ 恒 park(§3.3 窗=0 语义)。
|
|
34
34
|
* 开关为假 ⇒ 本值不参与,窗保持既有 `DEFAULT_APPROVAL_TTL_MS`(5min)。 */
|
|
35
35
|
windowMs: number;
|
|
36
36
|
/** 开流重放(§5)每次最多投几张未决卡——**读面**的帽,超出只投最新的并记一次 warn,开流不失败。
|
|
@@ -70,7 +70,8 @@ export interface ImageBakeConfig {
|
|
|
70
70
|
* `repo = ${registry}/${profile}` matches the P1 seed convention (seed-image-index.ts) and the index id
|
|
71
71
|
* `sha256(repo@digest)` is stable across seed and bake. `BAKE_IMAGE_REGISTRY` env; **code default = null**
|
|
72
72
|
* ⇒ the host-less `sema-images/<profile>` (node-local, documented non-pullable). Fleet posture (clay 拍
|
|
73
|
-
* 2026-07-13, SWR
|
|
73
|
+
* 2026-07-13, SWR 弃用; 2026-08 内网 Gitea registry 容器已下线全删): `docker.io/claybobby`(唯一在跑
|
|
74
|
+
* 的公共源;无内建 CN 兜底,国内网络不通的部署需自行配置 dockerd `registry-mirrors` 或自建 registry)。 */
|
|
74
75
|
registry: string | null;
|
|
75
76
|
/** The build-host promoted fetch-once cache base injected as `--cache-base` (NEVER caller-settable — a foreign
|
|
76
77
|
* origin would defeat the domestic-only iron rule). `BAKE_CACHE_BASE` (e.g. `http://<build-host>:<port>`). */
|
|
@@ -749,12 +750,29 @@ export interface ServiceConfigFlat {
|
|
|
749
750
|
* facts only ride when the deployment actually knows them (image binding/pkgSource/egress), absent = block
|
|
750
751
|
* unchanged. `SANDBOX_ENV_FACTS=false` opts out. */
|
|
751
752
|
envFactsEnabled: boolean;
|
|
752
|
-
/** ③ sensitive-path write DENY set (core 1.295 `createSensitivePathPolicy
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
*
|
|
753
|
+
/** ③ sensitive-path write DENY set (core 1.295 `createSensitivePathPolicy`). The PATTERN SET is core's call
|
|
754
|
+
* (RECOMMENDED_SENSITIVE_PATTERNS — .env/.ssh/keys/.git hooks+config/cloud creds/histories, rationale
|
|
755
|
+
* documented core-side); the server only passes it through. `SENSITIVE_WRITE_PATTERNS` (comma-separated):
|
|
756
|
+
* explicitly set = FULL REPLACEMENT of the recommended set (not a merge); `off` or an empty value = disabled
|
|
757
|
+
* (empty array); unset = core's recommended set.
|
|
758
|
+
* 🔴 **施加点 = governance 层,无条件(#177 / [2951] issue #29;搬家前「composed into the fs-write gate fold
|
|
759
|
+
* on host-semantics lanes — task-settings.ts」的旧描述已作废)**:与 `AUTONOMY`/`MANUAL_MODE_SHELL_GATE`
|
|
760
|
+
* 同拍,resolve-spec 预铸成一条纯 DENY policy 递给 `applyRuntimeGovernance`,**不看客户端 settings/
|
|
761
|
+
* permissionMode 的在场性、不看落在哪个模式臂、不看执行 lane**。旧家把它唯一的合成点挂在
|
|
762
|
+
* `deriveSettingsPolicy` 的 fs-write gate 闭包里,而那个闭包只在 default/auto/acceptEdits 三臂被调用 ⇒
|
|
763
|
+
* `bypassPermissions` / `permissionMode` 键缺席(headless `-p` 的默认姿势)/ body 连 settings 都没有
|
|
764
|
+
* 这三形整条 DENY 腿不建(邻仓 46 格真机矩阵实证)。裁决 env 仍按 lane 分形(host 真 fs / 沙箱
|
|
765
|
+
* `DeferredSandboxPathEnv` 代理),与 fs-write ask 门同一份、单点构造。
|
|
766
|
+
* 折叠仍是 deny-wins(tightenTaskSpec ⇒ combinePolicies),所以会话豁免 / acceptEdits 自动 allow /
|
|
767
|
+
* 客户端 settings allow 一律越不过它;非守卫目标该 policy 返回 `action:"allow"`(core 的 ToolPolicy
|
|
768
|
+
* 没有「无意见」第三态;这个 allow 在 combinePolicies 的 deny/ask 优先折叠里不构成一票,故在折叠
|
|
769
|
+
* 语境下等价于弃权)⇒ 不给 bypass 加 ask 门。
|
|
770
|
+
* ⚠️ 非法模式(不含任何路径段,如 `"/"`)在 boot 期 fail-loud(createResolveSpec 先编译一次)——
|
|
771
|
+
* **对存量部署是行为变更**:搬家前这种坏值只在 default/auto/acceptEdits 三臂上每请求炸,只跑
|
|
772
|
+
* headless 的部署带着坏值也能起服务;现在起不来(方向=运维当场看见,而不是每任务一条 500)。
|
|
773
|
+
* ✅ 旧注写的「沙箱 lane 相对形有一格无人裁决(cwd 里的守卫段看不见)」自 core 5.19.0(#108)起
|
|
774
|
+
* 已收口:守卫按 `ToolCallRequest.cwd` 解析写目标,两条 lane 同得。剩余射程边界(引擎未盖戳的直接
|
|
775
|
+
* 调用形)成文在 `deployment-governance.ts` 的 `RelativeTargetLexicalEnv` 类注。 */
|
|
758
776
|
sensitiveWritePatterns: string[];
|
|
759
777
|
/** [1557]§四 opt-in (cli[1555]② finding, core[1556] suggested mechanism): the CC manual-family permission
|
|
760
778
|
* modes (default/auto/acceptEdits) gate every fs WRITE hand tool (Write/Edit/NotebookEdit) but never touched
|
package/dist/config.d.ts
CHANGED
|
@@ -137,7 +137,11 @@ export declare function applyAutoCompactWindow(m: Model, explicit?: number): voi
|
|
|
137
137
|
* (常驻进程不 crash);
|
|
138
138
|
* ③ per-request 腿(`settings.permissions.{ask,deny}`,task-settings.ts)—— 该请求 422。
|
|
139
139
|
*
|
|
140
|
-
*
|
|
140
|
+
* 四种拼法:
|
|
141
|
+
* - CC 形规则条目(`Bash(ps:*)`/`Edit(src/**)`,#186 [3047]§七 装机实测):CC 的权限规则 DSL 写法。这些
|
|
142
|
+
* 名单比的是**整串工具名**,带括号那串不是任何活工具的名字 ⇒ 永不匹配。指引=按命令名走
|
|
143
|
+
* `runtime.commandPolicy`,整条 shell 进门走 `MANUAL_MODE_SHELL_GATE=always`。判别式见
|
|
144
|
+
* {@link findCcRuleFormNames}(它同时是 `allow` 腿的**唯一**判据,见下方例外说明)。
|
|
141
145
|
* - 退役名(`bash`/`Task`/`KillShell`…):core `RETIRED_TOOL_NAMES` 静态表,指引=现役名。
|
|
142
146
|
* - pre-prefix 短名(`figma__x`):v4 自动加前缀的折叠面已删,实挂名恒带 `mcp__`,指引=补全前缀。
|
|
143
147
|
* - 不完整 MCP 名(`mcp__`、`mcp__figma`):前缀对但缺段——MCP 实挂名恒是 `mcp__<server>__<tool>` 三段形,
|
|
@@ -151,6 +155,7 @@ export interface UnmatchableToolName {
|
|
|
151
155
|
name: string;
|
|
152
156
|
guidance: string;
|
|
153
157
|
}
|
|
158
|
+
export declare function findCcRuleFormNames(names: readonly string[]): UnmatchableToolName[];
|
|
154
159
|
export declare function findUnmatchableToolNames(names: readonly string[]): UnmatchableToolName[];
|
|
155
160
|
/** {@link findUnmatchableToolNames} 的成句形——三条腿的文案同源(只有前缀/出口不同)。 */
|
|
156
161
|
export declare function formatUnmatchableToolNames(source: string, bad: readonly UnmatchableToolName[]): string;
|
package/dist/config.js
CHANGED
|
@@ -879,9 +879,43 @@ function parseDegradeOn(words) {
|
|
|
879
879
|
}
|
|
880
880
|
return words;
|
|
881
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* #186 — the CC-rule-form arm, split out because it is the ONE arm that also judges an **allow** list.
|
|
884
|
+
*
|
|
885
|
+
* The general "unmatchable name" judgment deliberately spares `allow` (a mistyped live name leaves the allowlist
|
|
886
|
+
* effectively empty ⇒ everything is denied ⇒ fail-CLOSED and immediately visible). A CC-form entry is a different
|
|
887
|
+
* animal: `allow: ["Bash(ps:*)"]` is what a CC user writes to get FEWER prompts, and what they actually get is
|
|
888
|
+
* "only a tool literally named `Bash(ps:*)` may run" ⇒ Bash unavailable, with no warning anywhere. That is a
|
|
889
|
+
* spelling-FAMILY error, not a typo, so it is refused on every list — with the two knobs that really do the job.
|
|
890
|
+
*
|
|
891
|
+
* 本批**不实现** CC 形语义(参数级规则是扩面,另候裁);判据只认括号的在场,残形(`Bash(ps`)同样拒——
|
|
892
|
+
* 半个括号一样永不匹配活名。
|
|
893
|
+
*/
|
|
894
|
+
function ccRuleFormGuidance(name) {
|
|
895
|
+
if (!name.includes("(") && !name.includes(")"))
|
|
896
|
+
return undefined;
|
|
897
|
+
return (`CC-form rule specifier — this list matches the WHOLE tool name verbatim, so it can only ever match a tool literally named "${name}". ` +
|
|
898
|
+
`Drop the parentheses to gate the tool itself ("${name.split("(")[0] ?? name}"); ` +
|
|
899
|
+
`to decide per COMMAND use \`runtime.commandPolicy\` ({command, decision} — bare argv[0] names); ` +
|
|
900
|
+
`to put every shell call behind an approval use MANUAL_MODE_SHELL_GATE=always`);
|
|
901
|
+
}
|
|
902
|
+
export function findCcRuleFormNames(names) {
|
|
903
|
+
const out = [];
|
|
904
|
+
for (const name of names) {
|
|
905
|
+
const guidance = ccRuleFormGuidance(name);
|
|
906
|
+
if (guidance !== undefined)
|
|
907
|
+
out.push({ name, guidance });
|
|
908
|
+
}
|
|
909
|
+
return out;
|
|
910
|
+
}
|
|
882
911
|
export function findUnmatchableToolNames(names) {
|
|
883
912
|
const out = [];
|
|
884
913
|
for (const name of names) {
|
|
914
|
+
const ccGuidance = ccRuleFormGuidance(name);
|
|
915
|
+
if (ccGuidance !== undefined) {
|
|
916
|
+
out.push({ name, guidance: ccGuidance });
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
885
919
|
const retired = RETIRED_TOOL_NAMES.get(name);
|
|
886
920
|
if (retired !== undefined) {
|
|
887
921
|
out.push({ name, guidance: retired });
|
|
@@ -903,26 +937,36 @@ export function findUnmatchableToolNames(names) {
|
|
|
903
937
|
}
|
|
904
938
|
/** {@link findUnmatchableToolNames} 的成句形——三条腿的文案同源(只有前缀/出口不同)。 */
|
|
905
939
|
export function formatUnmatchableToolNames(source, bad) {
|
|
906
|
-
return (`${source} names tool(s) that can never match a live tool (core 5.0.0 RB-476
|
|
940
|
+
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): ` +
|
|
907
941
|
bad.map((b) => `${b.name} → ${b.guidance}`).join("; "));
|
|
908
942
|
}
|
|
909
943
|
/**
|
|
910
944
|
* #151 流内审批协议(design/172)的九键段(车3 刀 3a 五键 + 车5 收敛器四键)。
|
|
911
945
|
*
|
|
912
|
-
* **总开关默认
|
|
913
|
-
*
|
|
946
|
+
* **总开关默认 true**(clay 裁 2026-08-08 走 (a),#164 翻真验证后)。⚠️ 版本坐标:翻转**已在树上生效**,
|
|
947
|
+
* 发布线上它落在 7.4.0 之后的下一个发布(CHANGELOG `Unreleased` 段,预计 7.5.0)—— 所以一台自报 7.4.0
|
|
948
|
+
* 的**已发布** worker 仍是 OFF,而拿 main 构建的 worker 已是 ON。别只按 `/health` 的版本号推默认。显式
|
|
949
|
+
* `STREAM_APPROVAL_ENABLED=false` 是**唯一干净还原键** ⇒ 全链逐字回到翻转前行为(不发
|
|
950
|
+
* approval_request、不落 ask 行、不起收敛器腿、窗仍是 `DEFAULT_APPROVAL_TTL_MS`)。同一裁定把窗默认
|
|
951
|
+
* 从 60s 抬到 300000(= `DEFAULT_APPROVAL_TTL_MS` 的 5min),于是「开协议」不再顺带把窗砍短 ——
|
|
952
|
+
* 当年默认 false + 60s 窗那一版的「谁需要 / 谁被伤 / 什么补偿」成文记录在 `config-types.ts` 的
|
|
953
|
+
* `ServiceConfigFlat.streamApproval` 注里(读它时记得它记的是**翻转前**的前提)。
|
|
954
|
+
* 窗/帽四键沿用 `numEnv` fail-loud 形(坏形启动期炸,不静默折 NaN);
|
|
914
955
|
* 车5 的四键一律 **`numEnvBounded`**(§9 C6:batch 整数 ≥1 有上帽,grace/TTL 非负有界)——它们直接
|
|
915
956
|
* 决定 reaper 每 tick 的库压与「多久算遗孤」,一个手滑的 `0` 或 `1e12` 都是运维事故面。
|
|
916
957
|
*
|
|
917
|
-
* 🔴 跨旋钮不变量(§9 C6,`#157` 三分类 P 族姿势)
|
|
918
|
-
*
|
|
958
|
+
* 🔴 跨旋钮不变量(§9 C6,`#157` 三分类 P 族姿势):**`WINDOW + ADHOC_GRACE < ORPHAN_TTL`**。破坏形
|
|
959
|
+
* **拒启** —— 判据 4 在 `expiresAtMs + ADHOC_GRACE` 触发而 `expiresAtMs ≈ createdAtMs + WINDOW`,判据 5
|
|
960
|
+
* 在 `createdAtMs + ORPHAN_TTL` 触发;不等式不成立时判据 5 会先于判据 4 到,一条 adhoc 腿拿到的归因就成了
|
|
919
961
|
* `orphan_ttl_exceeded`(「遗孤兜底」)而不是 `adhoc_leg_no_durable_domain`(「结构上无对账域」),
|
|
920
|
-
*
|
|
962
|
+
* 审计面从此读不出真实成因。⚠️ **窗那一项不能省**(本注上一版只写 `ADHOC_GRACE < ORPHAN_TTL`,与下方
|
|
963
|
+
* 真校验和它的 codex C7 论证矛盾):只比宽限会漏掉窗,例如 WINDOW 与 ORPHAN_TTL 等长时校验放行但遗孤
|
|
964
|
+
* 兜底必定先到。默认值(300s + 60s vs 7d)自然满足;只有显式改坏才会撞上。
|
|
921
965
|
*/
|
|
922
966
|
function streamApprovalConfig() {
|
|
923
967
|
const cfg = {
|
|
924
|
-
enabled: boolEnv("STREAM_APPROVAL_ENABLED",
|
|
925
|
-
windowMs: numEnv("STREAM_ASK_WINDOW_MS", "
|
|
968
|
+
enabled: boolEnv("STREAM_APPROVAL_ENABLED", true), // clay 裁 2026-08-08 走 (a):#164 翻真验证后默认 ON;false=唯一干净还原键
|
|
969
|
+
windowMs: numEnv("STREAM_ASK_WINDOW_MS", "300000"), // 同裁抬 5min:「窗变短」从翻真里摘出,与 sync 腿既有活卡窗对齐
|
|
926
970
|
replayMax: numEnv("STREAM_APPROVAL_REPLAY_MAX", "50"),
|
|
927
971
|
admitMaxPerTask: numEnv("STREAM_APPROVAL_ADMIT_MAX_PER_TASK", "32"),
|
|
928
972
|
admitMaxPerOwner: numEnv("STREAM_APPROVAL_ADMIT_MAX_PER_OWNER", "256"),
|
|
@@ -1010,9 +1054,10 @@ function parseApprovalDomain(ctx) {
|
|
|
1010
1054
|
// #151 车2(design/172 §3.3 D3):ToolApprovalCoordinator 窗长三元的安全余量。numEnv fail-loud 形,
|
|
1011
1055
|
// 照邻居旋钮(approvalTimeoutSec 等)抄——坏形(非数字)在启动期炸,不静默折成 NaN。
|
|
1012
1056
|
streamAskWindowMarginMs: numEnv("STREAM_ASK_WINDOW_MARGIN_MS", "10000"),
|
|
1013
|
-
// #151 车3 刀 3a(design/172 流内审批协议)
|
|
1014
|
-
//
|
|
1015
|
-
//
|
|
1057
|
+
// #151 车3 刀 3a + 车5(design/172 流内审批协议):九键。默认极性 / 窗值 / 解析形 / 跨旋钮不变量
|
|
1058
|
+
// **一处成文** = 本文件 `streamApprovalConfig()` 的头注,这里不复述 —— 复述的两份必然各自漂,这条注
|
|
1059
|
+
// 的上一版正是这么漂的(默认翻 ON 之后它还写着「总开关默认 false」整整一版)。
|
|
1060
|
+
// 三问记录(翻转前那一版)见 config-types.ts 的 StreamApprovalConfig。
|
|
1016
1061
|
streamApproval: streamApprovalConfig(),
|
|
1017
1062
|
// [875]a 成文:0(缺省)= durable HITL 无限期等人,时间型 reapSuspended 不跑;file/memory lane 的回收
|
|
1018
1063
|
// 探针只在 DURABLE_APPROVAL=true 时注入(无 durable 的部署两只 suspended 回收器恒 NO-OP,parked 行的
|
|
@@ -1170,7 +1215,7 @@ function parseOrchestrationDomain(ctx) {
|
|
|
1170
1215
|
hostBackgroundShellEnabled();
|
|
1171
1216
|
hostExecSpoolEnabled();
|
|
1172
1217
|
// ── design/158 B4 ③ — LSP: one knob per lane. `LSP_ENABLED` used to drive BOTH the sandbox lane (opt-in,
|
|
1173
|
-
// default OFF — it needs a baked `
|
|
1218
|
+
// default OFF — it needs a baked `ai-agent-code-lsp` template) and the host lane (opt-out, default ON — it needs
|
|
1174
1219
|
// nothing and degrades to grep/read), i.e. one env name with two OPPOSITE defaults and no way to silence the
|
|
1175
1220
|
// host lane without also naming the sandbox knob. `LSP_HOST_ENABLED` now owns the host lane; an explicit
|
|
1176
1221
|
// `LSP_ENABLED=false` keeps working as a host opt-out (it was the only one operators ever had) with a notice
|
|
@@ -1302,8 +1347,9 @@ function parseOrchestrationDomain(ctx) {
|
|
|
1302
1347
|
}
|
|
1303
1348
|
: // DUAL-MODE §5: `local-docker` = a per-task container on THIS machine's docker daemon (isolation:true,
|
|
1304
1349
|
// suspendable:false). DOCKER_IMAGE is REQUIRED — no docker.io default (domestic-images iron rule); a
|
|
1305
|
-
// deployment points it at the docker.io/claybobby public pool or
|
|
1306
|
-
// deprecated
|
|
1350
|
+
// deployment points it at the docker.io/claybobby public pool or its own private registry (SWR
|
|
1351
|
+
// deprecated; the in-network Gitea registry container was retired 2026-08, no CN fallback baked
|
|
1352
|
+
// in). Secrets are env-NAMEs the worker resolves from its
|
|
1307
1353
|
// own process.env (DOCKER_SANDBOX_ENV, a CSV of NAMEs) — never the values in the spec/center.
|
|
1308
1354
|
process.env.REMOTE_EXEC === "local-docker" && process.env.DOCKER_IMAGE
|
|
1309
1355
|
? {
|
|
@@ -1382,7 +1428,7 @@ function parseOrchestrationDomain(ctx) {
|
|
|
1382
1428
|
selectEnvironmentTool: boolEnv("SELECT_ENVIRONMENT_TOOL", true), // RFC A2: default ON (mount additionally gated on k8s+catalog)
|
|
1383
1429
|
envFactsEnabled: boolEnv("SANDBOX_ENV_FACTS", true), // RFC A1: default ON (core 1.240.0 TaskSpec.envFacts; no-facts = no field)
|
|
1384
1430
|
toolDeferLongtail: boolEnv("TOOL_DEFER_LONGTAIL", false), // [803]④ defer face: EXPERIMENTAL, default OFF
|
|
1385
|
-
lspEnabled: boolEnv("LSP_ENABLED", false), // sandbox lane: opt-in (needs a baked
|
|
1431
|
+
lspEnabled: boolEnv("LSP_ENABLED", false), // sandbox lane: opt-in (needs a baked ai-agent-code-lsp template)
|
|
1386
1432
|
lspHostEnabled, // host lane: LSP_HOST_ENABLED, DEFAULT ON (CC-parity, degrades gracefully) — see the derivation above
|
|
1387
1433
|
workflowAgentsReadOnly: boolEnv("WORKFLOW_AGENTS_READONLY", false), // [824]① TOB 保守旋钮:默认 off = workflow 子 agent 同权(CC parity)
|
|
1388
1434
|
imageBakes: {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { FileError, StubExecutionEnv, type ExecutionEnv, type Result, type ToolPolicy } from "@sema-agent/core";
|
|
2
|
+
import { type DurableAskOptions } from "./approval.js";
|
|
3
|
+
import type { ServiceConfig } from "./config.js";
|
|
4
|
+
import type { applyRuntimeGovernance } from "./runtime-governance.js";
|
|
5
|
+
/** `applyRuntimeGovernance` 的 governance 实参 —— 从折叠属主的签名位**推导**,不复制形状
|
|
6
|
+
* (改一处签名,本口跟着变;两份手写形状正是漂移的成因)。 */
|
|
7
|
+
export type DeploymentGovernanceInputs = Parameters<typeof applyRuntimeGovernance>[1];
|
|
8
|
+
/** 本口读的部署配置切面(`ServiceConfig` 结构满足;窄接口让消费腿与测试不必铸整只 config)。 */
|
|
9
|
+
export interface DeploymentGovernanceConfigView {
|
|
10
|
+
readonly autonomy?: ServiceConfig["autonomy"];
|
|
11
|
+
readonly commandPolicy?: ServiceConfig["commandPolicy"];
|
|
12
|
+
readonly manualModeShellGate?: ServiceConfig["manualModeShellGate"];
|
|
13
|
+
readonly sensitiveWritePatterns: ServiceConfig["sensitiveWritePatterns"];
|
|
14
|
+
}
|
|
15
|
+
/** 审批基线读的配置切面(同上,窄接口)。 */
|
|
16
|
+
export interface ApprovalBaselineConfigView {
|
|
17
|
+
readonly approvalRequire: ServiceConfig["approvalRequire"];
|
|
18
|
+
readonly approvalDeny: ServiceConfig["approvalDeny"];
|
|
19
|
+
readonly approvalAutoBudget: ServiceConfig["approvalAutoBudget"];
|
|
20
|
+
readonly approvalNeverAuto: ServiceConfig["approvalNeverAuto"];
|
|
21
|
+
}
|
|
22
|
+
/** 守卫集裁决的 env/cwd 基准。**lane 分形归调用腿**(host 真 fs / 沙箱 deferred 代理 / run-local
|
|
23
|
+
* workspace)—— 那是消费腿的属主知识,本口不重复它,只按 cwd 的在场性决定要不要补词法臂。 */
|
|
24
|
+
export interface PathAdjudication {
|
|
25
|
+
/** 守卫策略 canonicalize 每一个写目标用的 env。 */
|
|
26
|
+
readonly env: ExecutionEnv;
|
|
27
|
+
/** 相对路径基准(core 的 `rootPath`)。缺席 ⇒ 相对形在真身那层判不了,补词法臂(见下)。 */
|
|
28
|
+
readonly cwd?: string;
|
|
29
|
+
}
|
|
30
|
+
/** #152([2703] 案二):durable 部署上的 AskUserQuestion 门的活体面探针(QuestionCoordinator 的切面)。 */
|
|
31
|
+
export interface LiveQuestionFace {
|
|
32
|
+
hasLiveContext(): boolean;
|
|
33
|
+
}
|
|
34
|
+
/** durable 轴的审批基线入参。缺席 ⇒ adjudicated allow-all 基线(见 {@link createApprovalBaselinePolicy})。 */
|
|
35
|
+
export interface DurableApprovalSeat {
|
|
36
|
+
/** 活体问答面;`undefined` ⇒ 恒 durable park 的原形门。 */
|
|
37
|
+
readonly question: LiveQuestionFace | undefined;
|
|
38
|
+
/** 每会话「本会话不再询问」探针(canonical toolName 键空间)。 */
|
|
39
|
+
readonly exempt?: DurableAskOptions["exempt"];
|
|
40
|
+
/** 豁免短路时的审计钩子。 */
|
|
41
|
+
readonly onExempted?: DurableAskOptions["onExempted"];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* #152([2703] 案二):durable 部署上的 AskUserQuestion 门。活体面(QuestionCoordinator)缺席 ⇒ 原形
|
|
45
|
+
* `createDurableQuestionPolicy()`(恒 ask ⇒ 恒 durable park)。在场 ⇒ **判决时**按活流上下文分腿:
|
|
46
|
+
* 活流腿(bg/SSE,coordinator.runWithContext 包裹且投递面此刻可达,ALS 判)allow——工具执行落到
|
|
47
|
+
* RunnerDeps.onQuestion 的 coordinator,问正在 tail 流的活人;无活流腿(sync /v1/tasks、verify/cascade、
|
|
48
|
+
* durable resume 驱动、断连后的 detach 腿)ask——durable park 原语义逐字保留(#166 后无活流腿放行执行
|
|
49
|
+
* 也不会产出空答:coordinator 无 ALS ctx ⇒ 冻结 `{kind:"unavailable"}`(src/question.ts),永不悬挂;
|
|
50
|
+
* park 仍是把问题送到人面前的唯一那条腿,正当性不变、只是反事实前提换了)。
|
|
51
|
+
* 工具名字面量与 server.ts 的 pre-CAS 守卫同源("AskUserQuestion",core 未根导出常量)。
|
|
52
|
+
* ⚠️ **单一属主**(复审 A2):AskUserQuestion 的 durable 判决只有这一处。任何需要「同参重建」这条判决的
|
|
53
|
+
* 地方(main.ts 的 parkedReviveInheritedGate 父约束链)必须调本工厂,不得自折 core 原形——两份拷贝里
|
|
54
|
+
* 只改一份正是本条 finding 的成因。**登记豁免一处**:leader worker 腿(src/leader/wire.ts provisionWorker)
|
|
55
|
+
* 自折 core 原形——该腿无活体问答面可装且 leader 不 import boot 层(分层),core 原形+sentinel 即其完整
|
|
56
|
+
* 语义;豁免注在彼处互指,接活体面之日必须并回本工厂。
|
|
57
|
+
*/
|
|
58
|
+
export declare function createDurableQuestionGate(live: LiveQuestionFace | undefined): ToolPolicy;
|
|
59
|
+
/**
|
|
60
|
+
* 沙箱 lane 上**相对形**写目标的守卫补层用 env(codex 对抗复审 round1 finding 1,红先复现)。
|
|
61
|
+
*
|
|
62
|
+
* 缺口:沙箱 lane 的守卫策略拿不到 `rootPath`(沙箱 cwd 不是 server 能猜的,#165 裁定 1),而
|
|
63
|
+
* `DeferredSandboxPathEnv.absolutePath` 对相对形一律报错。core 的 `canonicalizeTarget` 在
|
|
64
|
+
* **absolutePath 失败**这一支不置 `unresolvedSymlink`,于是守卫策略走的是
|
|
65
|
+
* 「判不了就弃权」的 `allow`(dist 亲读)。写门在场时这条腿被门的 `ask` 兜住;而
|
|
66
|
+
* `bypassPermissions` / settings 缺席这几形**根本没有门**,于是 `Write(file_path: ".env")` 一路放行——
|
|
67
|
+
* 而 core 的结构化写工具会把相对形按 engine 跟踪的 cwd 解析后真写下去(fs-write.js `resolveKey`)。
|
|
68
|
+
*
|
|
69
|
+
* 补法:**同一只**守卫策略工厂再铸一个实例,只把「路径→canonical key」这一步换成
|
|
70
|
+
* 纯词法基准(本 env)。判定与提取(哪个参数是写目标、NotebookEdit 的 notebook_path 优先、段匹配)
|
|
71
|
+
* 全部仍是 core 的,server 侧零复刻——复刻 core 的裁决逻辑正是「同源谎」那一类错误。
|
|
72
|
+
*
|
|
73
|
+
* 三条不可动的边界:
|
|
74
|
+
* · **绝对形一律弃权**(absolutePath 报错 ⇒ canon 失败且非 unresolvedSymlink ⇒ core 判 allow):
|
|
75
|
+
* 绝对形归真身裁决那一层,#165「真身胜过名字」的裁定(域内良性软链名叫 `.ssh` 只 ask)不受影响。
|
|
76
|
+
* · **只会 deny,不会放行**:相对形自身拼写里出现的段,解析成绝对路径后仍在,所以词法命中即真命中;
|
|
77
|
+
* 反过来一条名叫 `.env` 而真身良性的相对软链会被误 deny —— 方向是 fail-closed,与守卫集语义同向。
|
|
78
|
+
* · **覆盖面(2026-08-08 按 core 5.19.0 #108 校正;旧文见下方「历史」段)**:本层只在
|
|
79
|
+
* `ToolCallRequest.cwd` **缺席**那一形上说话。core 5.19.0 起每条路径解析型守卫按 `req.cwd ?? rootPath`
|
|
80
|
+
* 解析写目标(dist `core/sensitive-path-policy.js`),而 `canonicalizeTarget` 拿到 baseCwd 后会先把
|
|
81
|
+
* 相对形**拼成绝对形**再交给 env(dist `tools/fs/safety.js` 的 `baseCwd && !isAbsolutePathForm(...)`
|
|
82
|
+
* 分支)—— 本层的 `absolutePath` 对绝对形一律报错弃权 ⇒ **有戳时本层自动让位**,由真身那一层
|
|
83
|
+
* (沙箱 `DeferredSandboxPathEnv` / host `NodeExecutionEnv`)按活 cwd 裁决,cwd 里的守卫段现在真看得见。
|
|
84
|
+
* ⇒ 本层今天的射程 = 「引擎没盖戳」的调用:相对形**自身拼写**里带守卫段的那一类(`Write(".env")`、
|
|
85
|
+
* `Write("cfg/.ssh/id_rsa")`),仍由本层 fail-closed 兜住。**不删臂**:让位与冗余不是一回事——
|
|
86
|
+
* 删掉它等于把「缺戳即无守卫」写死,而缺戳形在契约上是 core 明确保留的回落语义(直接调用形)。
|
|
87
|
+
* 两处特征化钉现在各带两臂(带戳 deny / 缺戳 allow):test/task-settings.test.ts 与
|
|
88
|
+
* test/run-local.test.ts(后者是真引擎端到端,已翻成 🔴 正控)。
|
|
89
|
+
*
|
|
90
|
+
* 📜 **历史(留档,别当现状读)**:2026-08-08 之前本层的覆盖面到「cwd 里的守卫段看不见」为止——
|
|
91
|
+
* 本层把相对形挂在 `/` 上,而工具挂在 engine 活 cwd 上,`cd .git` 后 `Write("config")` 真写
|
|
92
|
+
* `<root>/.git/config` 而本层只看得到 `/config` ⇒ 弃权。design/181 刀3 的口径更正查明这条残余面
|
|
93
|
+
* **不是沙箱 lane 局部的**:host 腿虽供了 `rootPath`,那也是装配期的静态值,一样追不上被 Bash `cd`
|
|
94
|
+
* 就地改写的 `cwdRef.current`(run-local 端到端真复现:`cd .git/hooks` 后 `Write("pre-commit")` 真落盘)。
|
|
95
|
+
* 当年判定属主是引擎那条缝(不是任何一条消费腿——在消费腿里自己拿静态 cwd 追 `cd`,是拿会漂的复制品
|
|
96
|
+
* 追引擎的真值,本文件反复点名的病),并把两条钉写成「引擎缝落地后一起翻面」。**该缝即 core backlog
|
|
97
|
+
* #108,已在 5.19.0 到货**,两条钉按上述翻面完毕。另一条备选收口(守卫集开启即把沙箱 lane 相对写
|
|
98
|
+
* 一律 deny,有真受损方且无对应旋钮)因此作废,无需部署方拍板。
|
|
99
|
+
*/
|
|
100
|
+
export declare class RelativeTargetLexicalEnv extends StubExecutionEnv {
|
|
101
|
+
/** 相对形 → `/<词法归一>`;绝对形 / 空串 / 含 NUL 一律报错(= 弃权,见类注)。 */
|
|
102
|
+
absolutePath(path: string): Promise<Result<string, FileError>>;
|
|
103
|
+
/** 恒「不存在」⇒ core 的 `canonicalizeNewPath` 逐级回退,最终把词法归一形当 canonical key 交给段匹配。
|
|
104
|
+
* 这里绝不能报错:报错会被 core 读成 `unresolvedSymlink` 而对**每一个**相对目标 deny(含普通文件)。 */
|
|
105
|
+
exists(_path: string, _abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* boot 期的守卫集**可编译性**门(#177 收口①,随 design/181 件一搬进本口 —— 三条消费腿同得)。
|
|
109
|
+
*
|
|
110
|
+
* 守卫集的编译发生在**每个请求**上。core 的 `compilePatterns` 对「一个路径段都没有」的模式(`"/"`、
|
|
111
|
+
* `"//"`)THROW,那条 throw 会变成**每一个任务一条 500**,且运维从错误里看不出是自己的 env 写错了。
|
|
112
|
+
* 消费腿在装配期先编译一次:非法旋钮值当场炸在启动上(与 config.ts 的 env fail-loud 同族),指名键与
|
|
113
|
+
* core 的原因。env 只是编译期的占位(compilePatterns 不碰它),真裁决用的是每请求按 lane 铸的那一个。
|
|
114
|
+
*/
|
|
115
|
+
export declare function assertGuardPatternsUsable(config: Pick<DeploymentGovernanceConfigView, "sensitiveWritePatterns">): void;
|
|
116
|
+
/** 一条 boot 期运维告警的**载荷**(纯数据 ⇒ `build*`;打给谁、用哪只 logger 归消费腿)。 */
|
|
117
|
+
export interface OperatorWarning {
|
|
118
|
+
readonly event: string;
|
|
119
|
+
readonly fields: Record<string, unknown>;
|
|
120
|
+
}
|
|
121
|
+
/** {@link buildOnlySensitiveBaselineWarning} 读的座位量 —— 「这个部署到底有没有一道**真**门」。 */
|
|
122
|
+
export interface GateSeatView {
|
|
123
|
+
/** durable 审批门(checkpoint suspend/resume)是否在这条腿上真装。 */
|
|
124
|
+
readonly durableEnabled: boolean;
|
|
125
|
+
/** 单用户 turnkey 的 auto-accept 基线是否适用(= 零门意图的既定姿势,不是 misconfig)。 */
|
|
126
|
+
readonly singleUserAutoAcceptBaseline: boolean;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* UNGATED 信号的**补偿**(design/181 件一收编 / 件三三腿同得)。
|
|
130
|
+
*
|
|
131
|
+
* 审批基线铺开之后 core 的 `hasEffectAwareGate` 恒真,于是它那条 "write-capable hand tools are present
|
|
132
|
+
* but UNGATED" 的 onError 不再触发(判据是 `policyLayers.length > 0`,prepare-task dist 亲读)。那条信号
|
|
133
|
+
* 此前是「这个部署一个门都没接」这个 misconfig 的**唯一**提示,而守卫集只挡那二十来个路径段、其余写
|
|
134
|
+
* 目标照旧无裁决 —— 信号不能因为我们铺了基线就静默消失,所以由我们自己按同一判据说一次。
|
|
135
|
+
*
|
|
136
|
+
* 判据(与信号消失的条件逐字互补):守卫集在场 ∧ 两条产**真**门的腿都不在场(durable 门关 ∧ 单用户
|
|
137
|
+
* auto-accept 基线不适用)。三个量都是部署常量 ⇒ 消费腿在 boot 期说一次,不是每任务一次。
|
|
138
|
+
*
|
|
139
|
+
* ⚠️ 单一属主(design/181 件三):HTTP 腿与 run-local 腿共用本判据与文案。两处各写一份 = 一处改了另一处
|
|
140
|
+
* 没改,而两份都长得像对的 —— 那正是本文件存在的理由。
|
|
141
|
+
*/
|
|
142
|
+
export declare function buildOnlySensitiveBaselineWarning(config: Pick<DeploymentGovernanceConfigView, "sensitiveWritePatterns">, seat: GateSeatView): OperatorWarning | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* `applyRuntimeGovernance` 的 governance 实参预铸(design/181 件一)。
|
|
145
|
+
*
|
|
146
|
+
* 键存在性 profile 逐字保持消费腿原样:`autonomy`/`commandPolicy` 恒在场(值可为 `undefined`),
|
|
147
|
+
* `manualModeShellGate`/`sensitivePathPolicy` 按在场性条件展开 —— `applyRuntimeGovernance` 的
|
|
148
|
+
* `!== undefined` 判据对两者等价,但 profile 是折叠面的可观测字节,搬家不许顺手改。
|
|
149
|
+
*/
|
|
150
|
+
export declare function createDeploymentGovernanceInputs(config: DeploymentGovernanceConfigView, pathAdjudication: PathAdjudication): DeploymentGovernanceInputs;
|
|
151
|
+
/**
|
|
152
|
+
* 审批基线 —— `applyRuntimeGovernance` 那个 base 的 `toolPolicy` 座(design/181 件一)。**恒非
|
|
153
|
+
* `undefined`**:治理层是 tighten-only 的叠加层,没有基线可叠时它自己也产不出「门在场」这件事。
|
|
154
|
+
*
|
|
155
|
+
* 两形:
|
|
156
|
+
* · `durable` 在场 ⇒ durable 轴 = AskUserQuestion 判决门 + F4 高危写审批门(deny/neverAuto/预算/
|
|
157
|
+
* 会话豁免全在 `createDurableAskPolicy` 里)。gated `ask` 由 core 变成 durable checkpoint suspend。
|
|
158
|
+
* · `durable` 缺席 ⇒ **adjudicated allow-all**(`createAllowDenyPolicy({})`):一条**在场的**、
|
|
159
|
+
* effect-aware 的策略。CC 的信任模型是 auto-accept,但门**机制**必须在场(core 原则「机制留、默认
|
|
160
|
+
* 可更宽」)—— 满足 core 的 `hasEffectAwareGate`,恢复可观测性与 hook/tighten 点,而运维照旧用
|
|
161
|
+
* `AUTONOMY`/`commandPolicy` 收紧不可逆操作(由 `applyRuntimeGovernance` tighten-only 叠上)。
|
|
162
|
+
*
|
|
163
|
+
* ⚠️ 「零门意图才铺 allow-all」这条准入判据**不在本口**:它是消费腿的部署形判断(单用户/多租户、
|
|
164
|
+
* 有无 checkpoint 店),属主是 `hasOperatorGateIntent`/`assertGateIntentServiceable`(src/approval.ts)。
|
|
165
|
+
* 本口只按调用方给的形铸策略,绝不替它判「这个部署该不该有门」。
|
|
166
|
+
*/
|
|
167
|
+
export declare function createApprovalBaselinePolicy(config: ApprovalBaselineConfigView, durable?: DurableApprovalSeat): ToolPolicy;
|
|
168
|
+
//# sourceMappingURL=deployment-governance.d.ts.map
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/181 件一:**部署治理链的单一构造口**。
|
|
3
|
+
*
|
|
4
|
+
* 三条腿要装同一条「部署 ⊇ 操作员」治理链 —— HTTP 的 `resolveSpec`(boot/resolve-spec.ts)、durable park
|
|
5
|
+
* 的赎回腿(main.ts 的父约束重建)、`run-local`。此前只有第一条腿真装,另外两条各自手拼一小截,于是
|
|
6
|
+
* 「同一个部署旋钮在这条腿上生效、在那条腿上不存在」成了结构性可能。本文件把**构造**收成单一属主。
|
|
7
|
+
*
|
|
8
|
+
* 🔒 **折叠属主不在这里**:合成仍是 core 的 `tightenTaskSpec`,经由既有的 `applyRuntimeGovernance`
|
|
9
|
+
* (src/runtime-governance.ts)。本口**只产入参与基线**,一条 policy 都不合成 —— 折叠有六条规则
|
|
10
|
+
* (excludeTools/deferTools 并集、handsReadOnly/shellGate 放松即 throw、onAsk/hooks 冲突、键存在性
|
|
11
|
+
* profile),且 `applyRuntimeGovernance` 的 shellGate delete 臂读的是 `base.shellGate`、`governanceForced`
|
|
12
|
+
* 观察器包在其内部 —— 一个 base-free 的「已折好」新口复现不了这些,照抄=在 server 侧重写 core 的折叠。
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ **禁 memoize**:`autonomy` / `commandPolicy` / `manualModeShellGate` / `sensitiveWritePatterns` 都是
|
|
15
|
+
* 热改字段(registry 热应用换 config 引用,resume 腿按**当前** config 重折 —— 与审批基线读活
|
|
16
|
+
* `config.approvalRequire` 同一姿势)。每次调用现取,boot 期缓存一份 = 把热改静默冻住。
|
|
17
|
+
*/
|
|
18
|
+
import { posix } from "node:path";
|
|
19
|
+
import { FileError, StubExecutionEnv, combinePolicies, createAllowDenyPolicy, createDurableQuestionPolicy, createSensitivePathPolicy, err, ok, } from "@sema-agent/core";
|
|
20
|
+
import { createDurableAskPolicy } from "./approval.js";
|
|
21
|
+
/**
|
|
22
|
+
* #152([2703] 案二):durable 部署上的 AskUserQuestion 门。活体面(QuestionCoordinator)缺席 ⇒ 原形
|
|
23
|
+
* `createDurableQuestionPolicy()`(恒 ask ⇒ 恒 durable park)。在场 ⇒ **判决时**按活流上下文分腿:
|
|
24
|
+
* 活流腿(bg/SSE,coordinator.runWithContext 包裹且投递面此刻可达,ALS 判)allow——工具执行落到
|
|
25
|
+
* RunnerDeps.onQuestion 的 coordinator,问正在 tail 流的活人;无活流腿(sync /v1/tasks、verify/cascade、
|
|
26
|
+
* durable resume 驱动、断连后的 detach 腿)ask——durable park 原语义逐字保留(#166 后无活流腿放行执行
|
|
27
|
+
* 也不会产出空答:coordinator 无 ALS ctx ⇒ 冻结 `{kind:"unavailable"}`(src/question.ts),永不悬挂;
|
|
28
|
+
* park 仍是把问题送到人面前的唯一那条腿,正当性不变、只是反事实前提换了)。
|
|
29
|
+
* 工具名字面量与 server.ts 的 pre-CAS 守卫同源("AskUserQuestion",core 未根导出常量)。
|
|
30
|
+
* ⚠️ **单一属主**(复审 A2):AskUserQuestion 的 durable 判决只有这一处。任何需要「同参重建」这条判决的
|
|
31
|
+
* 地方(main.ts 的 parkedReviveInheritedGate 父约束链)必须调本工厂,不得自折 core 原形——两份拷贝里
|
|
32
|
+
* 只改一份正是本条 finding 的成因。**登记豁免一处**:leader worker 腿(src/leader/wire.ts provisionWorker)
|
|
33
|
+
* 自折 core 原形——该腿无活体问答面可装且 leader 不 import boot 层(分层),core 原形+sentinel 即其完整
|
|
34
|
+
* 语义;豁免注在彼处互指,接活体面之日必须并回本工厂。
|
|
35
|
+
*/
|
|
36
|
+
export function createDurableQuestionGate(live) {
|
|
37
|
+
if (live === undefined)
|
|
38
|
+
return createDurableQuestionPolicy();
|
|
39
|
+
return {
|
|
40
|
+
check(req) {
|
|
41
|
+
if (req.toolName !== "AskUserQuestion")
|
|
42
|
+
return { action: "allow" };
|
|
43
|
+
return live.hasLiveContext()
|
|
44
|
+
? { action: "allow" }
|
|
45
|
+
: { action: "ask", message: "AskUserQuestion: awaiting a human answer (durable)" };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 沙箱 lane 上**相对形**写目标的守卫补层用 env(codex 对抗复审 round1 finding 1,红先复现)。
|
|
51
|
+
*
|
|
52
|
+
* 缺口:沙箱 lane 的守卫策略拿不到 `rootPath`(沙箱 cwd 不是 server 能猜的,#165 裁定 1),而
|
|
53
|
+
* `DeferredSandboxPathEnv.absolutePath` 对相对形一律报错。core 的 `canonicalizeTarget` 在
|
|
54
|
+
* **absolutePath 失败**这一支不置 `unresolvedSymlink`,于是守卫策略走的是
|
|
55
|
+
* 「判不了就弃权」的 `allow`(dist 亲读)。写门在场时这条腿被门的 `ask` 兜住;而
|
|
56
|
+
* `bypassPermissions` / settings 缺席这几形**根本没有门**,于是 `Write(file_path: ".env")` 一路放行——
|
|
57
|
+
* 而 core 的结构化写工具会把相对形按 engine 跟踪的 cwd 解析后真写下去(fs-write.js `resolveKey`)。
|
|
58
|
+
*
|
|
59
|
+
* 补法:**同一只**守卫策略工厂再铸一个实例,只把「路径→canonical key」这一步换成
|
|
60
|
+
* 纯词法基准(本 env)。判定与提取(哪个参数是写目标、NotebookEdit 的 notebook_path 优先、段匹配)
|
|
61
|
+
* 全部仍是 core 的,server 侧零复刻——复刻 core 的裁决逻辑正是「同源谎」那一类错误。
|
|
62
|
+
*
|
|
63
|
+
* 三条不可动的边界:
|
|
64
|
+
* · **绝对形一律弃权**(absolutePath 报错 ⇒ canon 失败且非 unresolvedSymlink ⇒ core 判 allow):
|
|
65
|
+
* 绝对形归真身裁决那一层,#165「真身胜过名字」的裁定(域内良性软链名叫 `.ssh` 只 ask)不受影响。
|
|
66
|
+
* · **只会 deny,不会放行**:相对形自身拼写里出现的段,解析成绝对路径后仍在,所以词法命中即真命中;
|
|
67
|
+
* 反过来一条名叫 `.env` 而真身良性的相对软链会被误 deny —— 方向是 fail-closed,与守卫集语义同向。
|
|
68
|
+
* · **覆盖面(2026-08-08 按 core 5.19.0 #108 校正;旧文见下方「历史」段)**:本层只在
|
|
69
|
+
* `ToolCallRequest.cwd` **缺席**那一形上说话。core 5.19.0 起每条路径解析型守卫按 `req.cwd ?? rootPath`
|
|
70
|
+
* 解析写目标(dist `core/sensitive-path-policy.js`),而 `canonicalizeTarget` 拿到 baseCwd 后会先把
|
|
71
|
+
* 相对形**拼成绝对形**再交给 env(dist `tools/fs/safety.js` 的 `baseCwd && !isAbsolutePathForm(...)`
|
|
72
|
+
* 分支)—— 本层的 `absolutePath` 对绝对形一律报错弃权 ⇒ **有戳时本层自动让位**,由真身那一层
|
|
73
|
+
* (沙箱 `DeferredSandboxPathEnv` / host `NodeExecutionEnv`)按活 cwd 裁决,cwd 里的守卫段现在真看得见。
|
|
74
|
+
* ⇒ 本层今天的射程 = 「引擎没盖戳」的调用:相对形**自身拼写**里带守卫段的那一类(`Write(".env")`、
|
|
75
|
+
* `Write("cfg/.ssh/id_rsa")`),仍由本层 fail-closed 兜住。**不删臂**:让位与冗余不是一回事——
|
|
76
|
+
* 删掉它等于把「缺戳即无守卫」写死,而缺戳形在契约上是 core 明确保留的回落语义(直接调用形)。
|
|
77
|
+
* 两处特征化钉现在各带两臂(带戳 deny / 缺戳 allow):test/task-settings.test.ts 与
|
|
78
|
+
* test/run-local.test.ts(后者是真引擎端到端,已翻成 🔴 正控)。
|
|
79
|
+
*
|
|
80
|
+
* 📜 **历史(留档,别当现状读)**:2026-08-08 之前本层的覆盖面到「cwd 里的守卫段看不见」为止——
|
|
81
|
+
* 本层把相对形挂在 `/` 上,而工具挂在 engine 活 cwd 上,`cd .git` 后 `Write("config")` 真写
|
|
82
|
+
* `<root>/.git/config` 而本层只看得到 `/config` ⇒ 弃权。design/181 刀3 的口径更正查明这条残余面
|
|
83
|
+
* **不是沙箱 lane 局部的**:host 腿虽供了 `rootPath`,那也是装配期的静态值,一样追不上被 Bash `cd`
|
|
84
|
+
* 就地改写的 `cwdRef.current`(run-local 端到端真复现:`cd .git/hooks` 后 `Write("pre-commit")` 真落盘)。
|
|
85
|
+
* 当年判定属主是引擎那条缝(不是任何一条消费腿——在消费腿里自己拿静态 cwd 追 `cd`,是拿会漂的复制品
|
|
86
|
+
* 追引擎的真值,本文件反复点名的病),并把两条钉写成「引擎缝落地后一起翻面」。**该缝即 core backlog
|
|
87
|
+
* #108,已在 5.19.0 到货**,两条钉按上述翻面完毕。另一条备选收口(守卫集开启即把沙箱 lane 相对写
|
|
88
|
+
* 一律 deny,有真受损方且无对应旋钮)因此作废,无需部署方拍板。
|
|
89
|
+
*/
|
|
90
|
+
export class RelativeTargetLexicalEnv extends StubExecutionEnv {
|
|
91
|
+
/** 相对形 → `/<词法归一>`;绝对形 / 空串 / 含 NUL 一律报错(= 弃权,见类注)。 */
|
|
92
|
+
absolutePath(path) {
|
|
93
|
+
if (path.length === 0 || path.startsWith("/") || path.includes("\u0000")) {
|
|
94
|
+
return Promise.resolve(err(new FileError("not_supported", "this guard layer only adjudicates RELATIVE write targets (absolute forms are adjudicated against the real sandbox filesystem)", path)));
|
|
95
|
+
}
|
|
96
|
+
return Promise.resolve(ok(posix.normalize(`/${path}`)));
|
|
97
|
+
}
|
|
98
|
+
/** 恒「不存在」⇒ core 的 `canonicalizeNewPath` 逐级回退,最终把词法归一形当 canonical key 交给段匹配。
|
|
99
|
+
* 这里绝不能报错:报错会被 core 读成 `unresolvedSymlink` 而对**每一个**相对目标 deny(含普通文件)。 */
|
|
100
|
+
exists(_path, _abortSignal) {
|
|
101
|
+
return Promise.resolve(ok(false));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* boot 期的守卫集**可编译性**门(#177 收口①,随 design/181 件一搬进本口 —— 三条消费腿同得)。
|
|
106
|
+
*
|
|
107
|
+
* 守卫集的编译发生在**每个请求**上。core 的 `compilePatterns` 对「一个路径段都没有」的模式(`"/"`、
|
|
108
|
+
* `"//"`)THROW,那条 throw 会变成**每一个任务一条 500**,且运维从错误里看不出是自己的 env 写错了。
|
|
109
|
+
* 消费腿在装配期先编译一次:非法旋钮值当场炸在启动上(与 config.ts 的 env fail-loud 同族),指名键与
|
|
110
|
+
* core 的原因。env 只是编译期的占位(compilePatterns 不碰它),真裁决用的是每请求按 lane 铸的那一个。
|
|
111
|
+
*/
|
|
112
|
+
export function assertGuardPatternsUsable(config) {
|
|
113
|
+
if (config.sensitiveWritePatterns.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
try {
|
|
116
|
+
createSensitivePathPolicy({ env: new StubExecutionEnv(), patterns: config.sensitiveWritePatterns });
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
throw new Error(`SENSITIVE_WRITE_PATTERNS is not a usable guard set: ${e instanceof Error ? e.message : String(e)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* UNGATED 信号的**补偿**(design/181 件一收编 / 件三三腿同得)。
|
|
124
|
+
*
|
|
125
|
+
* 审批基线铺开之后 core 的 `hasEffectAwareGate` 恒真,于是它那条 "write-capable hand tools are present
|
|
126
|
+
* but UNGATED" 的 onError 不再触发(判据是 `policyLayers.length > 0`,prepare-task dist 亲读)。那条信号
|
|
127
|
+
* 此前是「这个部署一个门都没接」这个 misconfig 的**唯一**提示,而守卫集只挡那二十来个路径段、其余写
|
|
128
|
+
* 目标照旧无裁决 —— 信号不能因为我们铺了基线就静默消失,所以由我们自己按同一判据说一次。
|
|
129
|
+
*
|
|
130
|
+
* 判据(与信号消失的条件逐字互补):守卫集在场 ∧ 两条产**真**门的腿都不在场(durable 门关 ∧ 单用户
|
|
131
|
+
* auto-accept 基线不适用)。三个量都是部署常量 ⇒ 消费腿在 boot 期说一次,不是每任务一次。
|
|
132
|
+
*
|
|
133
|
+
* ⚠️ 单一属主(design/181 件三):HTTP 腿与 run-local 腿共用本判据与文案。两处各写一份 = 一处改了另一处
|
|
134
|
+
* 没改,而两份都长得像对的 —— 那正是本文件存在的理由。
|
|
135
|
+
*/
|
|
136
|
+
export function buildOnlySensitiveBaselineWarning(config, seat) {
|
|
137
|
+
if (config.sensitiveWritePatterns.length === 0 || seat.durableEnabled || seat.singleUserAutoAcceptBaseline)
|
|
138
|
+
return undefined;
|
|
139
|
+
return {
|
|
140
|
+
event: "tool_policy_only_sensitive_baseline",
|
|
141
|
+
fields: {
|
|
142
|
+
detail: "the sensitive-path DENY baseline (SENSITIVE_WRITE_PATTERNS) is this deployment's ONLY tool policy — writes outside the guarded segments are unadjudicated, and core's own UNGATED warning no longer fires because a policy is now always present",
|
|
143
|
+
remedy: "wire an approval face (DURABLE_APPROVAL / APPROVAL_REQUIRE with a store) or accept the single-user auto-accept baseline",
|
|
144
|
+
guardedPatterns: config.sensitiveWritePatterns.length,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* `applyRuntimeGovernance` 的 governance 实参预铸(design/181 件一)。
|
|
150
|
+
*
|
|
151
|
+
* 键存在性 profile 逐字保持消费腿原样:`autonomy`/`commandPolicy` 恒在场(值可为 `undefined`),
|
|
152
|
+
* `manualModeShellGate`/`sensitivePathPolicy` 按在场性条件展开 —— `applyRuntimeGovernance` 的
|
|
153
|
+
* `!== undefined` 判据对两者等价,但 profile 是折叠面的可观测字节,搬家不许顺手改。
|
|
154
|
+
*/
|
|
155
|
+
export function createDeploymentGovernanceInputs(config, pathAdjudication) {
|
|
156
|
+
const sensitivePathPolicy = config.sensitiveWritePatterns.length > 0
|
|
157
|
+
? (() => {
|
|
158
|
+
const realTarget = createSensitivePathPolicy({
|
|
159
|
+
env: pathAdjudication.env,
|
|
160
|
+
patterns: config.sensitiveWritePatterns,
|
|
161
|
+
...(pathAdjudication.cwd !== undefined ? { rootPath: pathAdjudication.cwd } : {}),
|
|
162
|
+
});
|
|
163
|
+
// cwd 在场(host 形)⇒ 相对形已被 core 按 rootPath 解析进真身裁决,一层就够。
|
|
164
|
+
// cwd 缺席(沙箱形)⇒ 相对形在真身那一层是「判不了 ⇒ 弃权 allow」,而写门恰恰在
|
|
165
|
+
// bypass/settings 缺席这几形不在场 ⇒ 补一层纯词法的相对形守卫(见 RelativeTargetLexicalEnv)。
|
|
166
|
+
if (pathAdjudication.cwd !== undefined)
|
|
167
|
+
return realTarget;
|
|
168
|
+
return combinePolicies(realTarget, createSensitivePathPolicy({ env: new RelativeTargetLexicalEnv(), patterns: config.sensitiveWritePatterns }));
|
|
169
|
+
})()
|
|
170
|
+
: undefined;
|
|
171
|
+
return {
|
|
172
|
+
autonomy: config.autonomy,
|
|
173
|
+
commandPolicy: config.commandPolicy,
|
|
174
|
+
...(config.manualModeShellGate ? { manualModeShellGate: config.manualModeShellGate } : {}),
|
|
175
|
+
...(sensitivePathPolicy ? { sensitivePathPolicy } : {}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* 审批基线 —— `applyRuntimeGovernance` 那个 base 的 `toolPolicy` 座(design/181 件一)。**恒非
|
|
180
|
+
* `undefined`**:治理层是 tighten-only 的叠加层,没有基线可叠时它自己也产不出「门在场」这件事。
|
|
181
|
+
*
|
|
182
|
+
* 两形:
|
|
183
|
+
* · `durable` 在场 ⇒ durable 轴 = AskUserQuestion 判决门 + F4 高危写审批门(deny/neverAuto/预算/
|
|
184
|
+
* 会话豁免全在 `createDurableAskPolicy` 里)。gated `ask` 由 core 变成 durable checkpoint suspend。
|
|
185
|
+
* · `durable` 缺席 ⇒ **adjudicated allow-all**(`createAllowDenyPolicy({})`):一条**在场的**、
|
|
186
|
+
* effect-aware 的策略。CC 的信任模型是 auto-accept,但门**机制**必须在场(core 原则「机制留、默认
|
|
187
|
+
* 可更宽」)—— 满足 core 的 `hasEffectAwareGate`,恢复可观测性与 hook/tighten 点,而运维照旧用
|
|
188
|
+
* `AUTONOMY`/`commandPolicy` 收紧不可逆操作(由 `applyRuntimeGovernance` tighten-only 叠上)。
|
|
189
|
+
*
|
|
190
|
+
* ⚠️ 「零门意图才铺 allow-all」这条准入判据**不在本口**:它是消费腿的部署形判断(单用户/多租户、
|
|
191
|
+
* 有无 checkpoint 店),属主是 `hasOperatorGateIntent`/`assertGateIntentServiceable`(src/approval.ts)。
|
|
192
|
+
* 本口只按调用方给的形铸策略,绝不替它判「这个部署该不该有门」。
|
|
193
|
+
*/
|
|
194
|
+
export function createApprovalBaselinePolicy(config, durable) {
|
|
195
|
+
if (durable === undefined)
|
|
196
|
+
return createAllowDenyPolicy({});
|
|
197
|
+
return combinePolicies(createDurableQuestionGate(durable.question), createDurableAskPolicy({
|
|
198
|
+
requireApproval: config.approvalRequire,
|
|
199
|
+
deny: config.approvalDeny,
|
|
200
|
+
autoBudget: config.approvalAutoBudget,
|
|
201
|
+
neverAuto: config.approvalNeverAuto,
|
|
202
|
+
...(durable.exempt ? { exempt: durable.exempt } : {}),
|
|
203
|
+
...(durable.onExempted ? { onExempted: durable.onExempted } : {}),
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=deployment-governance.js.map
|
package/dist/env-facts.d.ts
CHANGED
|
@@ -78,7 +78,9 @@ export declare function ensureScratchpadDir(localDataRoot: string, sessionId: st
|
|
|
78
78
|
* - 绝对路径 + ≤{@link MAX_PATH}(core 渲染上限同源,超限=core 只能给模型假路径)+ canonical
|
|
79
79
|
* 深度 ≥3(裸 /、/tmp、/home 一整块系统目录不能当豁免域;穿越形按 resolve 归一后判);
|
|
80
80
|
* - mkdir -p 确保存在(gate 的 canonicalize 与 core 根围栏都要真目录)。
|
|
81
|
-
*
|
|
81
|
+
* 敏感路径的最后一道**不在**写门折叠里(#177 起搬家):守卫集 `SENSITIVE_WRITE_PATTERNS` 由
|
|
82
|
+
* governance 拍(boot/resolve-spec.ts → applyRuntimeGovernance)无条件铸成 DENY 基线,经 tightenTaskSpec
|
|
83
|
+
* 与写门 deny-wins 折叠 —— 结论不变(deny 恒赢,本函数放出的 exemptDirs 越不过它),但施加点已换。 */
|
|
82
84
|
export declare function acceptShellScratchpadDir(raw: unknown, opts: {
|
|
83
85
|
requirePrincipal: boolean;
|
|
84
86
|
hostSemanticsLane: boolean;
|