@sema-agent/server 7.43.0 → 7.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- package/dist/capabilities/scenario-alias.js +0 -61
|
@@ -9,46 +9,15 @@ import { basename, resolve } from "node:path";
|
|
|
9
9
|
import { stat as fsStat, readFile as fsReadFile } from "node:fs/promises";
|
|
10
10
|
export function createLiveCoordinators(ctx) {
|
|
11
11
|
const { config, logger, backend, sendUserFileTaskEnvs, ruleConsent, ruleScopeRootFor, getParkedRedeem } = ctx;
|
|
12
|
-
// E23 (shell-host contract): inbound MCP elicitation coordinator (live-only HITL). Present ONLY when MCP_ELICITATION_ENABLED
|
|
13
|
-
// — absent ⇒ onElicit is not wired ⇒ core advertises no elicitation capability to any server (fail-closed). Shared
|
|
14
|
-
// by the runner (the onElicit seam) and the HTTP layer (the respond route + the per-run ALS context wraps).
|
|
15
12
|
const elicitation = config.mcpElicitation.enabled ? new ElicitationCoordinator(config.mcpElicitation.throttle) : undefined;
|
|
16
|
-
// §4④: AskUserQuestion LIVE-stream HITL coordinator — the sibling of `elicitation`. Present ⇒ wired onto
|
|
17
|
-
// `RunnerDeps.onQuestion` (core mounts the AskUserQuestion tool + routes live asks here) AND consumed by the HTTP layer
|
|
18
|
-
// (the `POST /v1/questions/:id/respond` route + the per-run ALS context wraps on the streaming legs). Absent ⇒ core
|
|
19
|
-
// mounts the tool with the headless default (a run never hangs; the model just can't get a live answer).
|
|
20
|
-
// #166 裁2 接线:三旋钮(QUESTION_TTL_MS / QUESTION_MAX_*_PER_RUN)从 config 通到协调器;缺席=构造器
|
|
21
|
-
// 内建 DEFAULT_QUESTION_THROTTLE,默认值恒等钉在 test/question-unavailable.test.ts。
|
|
22
13
|
const question = config.askQuestionEnabled ? new QuestionCoordinator(config.questionThrottle) : undefined;
|
|
23
|
-
// [816]/[820]②: the live tool-approval HITL coordinator — the sibling of `question` on core's `RunnerDeps.onAsk`
|
|
24
|
-
// seam (1.290 sync-ask leg). Present ⇒ a policy `ask` on a LIVE streaming leg becomes a `tool_approval` frame the
|
|
25
|
-
// shell renders as the CC three-choice card, answered via POST /v1/tool-approvals/:id/respond.
|
|
26
|
-
// [1535] 正名(旧文「background/workflow ⇒ headless auto-deny stands」已过时):宿主 sync 腿现同时装
|
|
27
|
-
// `spec.onAsk = boundAsk(ctx)`(装配点在 `http/routes/tasks.ts`,design/158 A9 从 server.ts 拆出后
|
|
28
|
-
// 的全树唯一装配点)——core 继承链把闭包冻给委派子代,**bg/嵌套子代的
|
|
29
|
-
// ask 浮到宿主 live 流**(带 sourceTaskId);真正无宿主流的腿(durable-submit/headless resume)才留
|
|
30
|
-
// 「unavailable → durable park;无 park 设施 core fail-closed deny」。durable 部署 G1 语义不变。
|
|
31
|
-
// [1.294 G1] durable 姿势必须在 runnerDeps 字面量之前可判(onAsk 的「在场性」本身就是 core suspendAsk 的
|
|
32
|
-
// 分路条件,不能再靠闭包惰性读)——判据与 checkpointStore 的构造条件同源(backend?.checkpoint 存在 ∧
|
|
33
|
-
// DURABLE_APPROVAL;store 本体已上移至 subRunner 构造前,[1535] 断点② 双 Runner 挂载)。
|
|
34
|
-
// 🔴 #151 车3 刀 3b:本行**上移**到协调器构造之前 —— 它同时是流内审批协议的「park 设施在场性」判据
|
|
35
|
-
// (§8.4),而协调器要在构造那一刻就知道自己带不带 askStore。位置即契约的原约束(必须在 RunnerDeps
|
|
36
|
-
// 字面量之前)不变,只是又提前了几行。
|
|
37
14
|
const durableEnabled = backend?.checkpoint !== undefined && config.durableApproval === true;
|
|
38
|
-
// #151 车3 刀 3b(设计稿 §2.3 + §8.4):协议上场判据走**单一谓词**(与 /v1/capabilities 的
|
|
39
|
-
// `streamApproval` 格、与回决端点的 501 门同一个符号,见 resolveStreamApprovalGate 顶注)。
|
|
40
15
|
const streamApprovalGate = resolveStreamApprovalGate({
|
|
41
16
|
toolApprovalEnabled: config.toolApprovalEnabled === true,
|
|
42
17
|
streamApprovalEnabled: config.streamApproval.enabled,
|
|
43
18
|
backend,
|
|
44
19
|
parkFacility: durableEnabled,
|
|
45
20
|
});
|
|
46
|
-
// §8.4:协议**开着**却上不了场 = 合法部署形(不是配置错误)⇒ 一行 **info**(不是 warn),把原因说明白。
|
|
47
|
-
// 反过来「开关本来就没开」不打日志:显式关掉的部署自己知道为什么关,一行噪音没有信息量。
|
|
48
|
-
// ⚠️ 读数已反转:总开关默认在树上已是 ON(版本坐标见 config.ts 的 `streamApprovalConfig()` 头注),
|
|
49
|
-
// 所以这一行在**默认部署**上是常态 —— 任何没有 durable
|
|
50
|
-
// backend / park 设施的默认部署每次启动都会打一行 `stream_approval_disabled`(每次启动一行,不是每
|
|
51
|
-
// tick)。写这条判据时的前提「默认形绕开本路径」已不成立;要收紧,收紧点在本 if 而不是在开关处。
|
|
52
21
|
if (config.streamApproval.enabled && !streamApprovalGate.active) {
|
|
53
22
|
logger.info("stream_approval_disabled", {
|
|
54
23
|
reason: streamApprovalGate.reason,
|
|
@@ -60,65 +29,31 @@ export function createLiveCoordinators(ctx) {
|
|
|
60
29
|
}
|
|
61
30
|
const toolApproval = config.toolApprovalEnabled
|
|
62
31
|
? new ToolApprovalCoordinator({
|
|
63
|
-
// 协议上场 ⇒ 持久层 + 配置窗(§7:`STREAM_ASK_WINDOW_MS` **只在开关内**生效,
|
|
64
|
-
// `DEFAULT_APPROVAL_TTL_MS` 一个字不动);不上场 ⇒ 两者都不传,窗保持既有 5min(D1 逐字不变)。
|
|
65
|
-
// ⚠️ 两臂的窗**默认已同长**:窗默认自 7.5.0 起 = 300000 = `DEFAULT_APPROVAL_TTL_MS`(clay 同裁把
|
|
66
|
-
// 「窗变短」从翻真里摘出去)。原注画的「上场 = 60s / 不上场 = 5min」这个对比在默认配置下不存在
|
|
67
|
-
// 了,别据它得出「开了协议窗会缩短」的运维结论:上场与否改变的是**持久层与协议帧**,窗只有在
|
|
68
|
-
// 部署显式设了 `STREAM_ASK_WINDOW_MS` 时才分叉。
|
|
69
32
|
...(streamApprovalGate.active ? { askStore: streamApprovalGate.askStore, ttlMs: config.streamApproval.windowMs } : {}),
|
|
70
|
-
// 余量旋钮恒传(既有键,窗长三元公式的第二项;legDeadlineMonotonic 缺席时它不参与计算)。
|
|
71
33
|
windowMarginMs: config.streamAskWindowMarginMs,
|
|
72
|
-
// X-2 写侧准入门两帽(协议未上场时门本身不参与,见 ToolApprovalCoordinator.admit)。
|
|
73
34
|
admitMaxPerTask: config.streamApproval.admitMaxPerTask,
|
|
74
35
|
admitMaxPerOwner: config.streamApproval.admitMaxPerOwner,
|
|
75
|
-
// #154 车二:同意车道(缺席 = 规则店没装配 ⇒ 帧上零候选、回决的 persistRule 如实拒)。
|
|
76
36
|
...(ruleConsent !== undefined ? { ruleConsent } : {}),
|
|
77
|
-
// #295(F-1):卡批规则 project root 解析器(缺席 ⇒ 落 global,修前行为)。
|
|
78
37
|
...(ruleScopeRootFor !== undefined ? { ruleScopeRootFor } : {}),
|
|
79
|
-
// #280 R-13 C:无人值守政策(闭集 park|deny)。**恒传**(不挂任何在场性推断):它是纯部署级的一位,
|
|
80
|
-
// 语义/三问/射程边界一处成文见 `config-types.ts` 的 `unattendedApprovalPolicy` 域注。
|
|
81
|
-
// ⚠️ 恒传是**刻意**的,不是顺手(codex R2-F2 点过这一行):`streamApprovalGate.active` 为假时只
|
|
82
|
-
// 省略 askStore/窗,协调器照常在场,R-13 的 D1 窗到期臂照样按政策走 —— 那正是设计稿点名的主受益
|
|
83
|
-
// 部署(park 的承载是 core checkpoint,不是 ask 行)。把政策挂到协议开关上会把它整个切掉。
|
|
84
|
-
// 协调器本身缺席时(`TOOL_APPROVAL_ENABLED` 关)本旋钮无处施加 —— 成文事实,不是推断腿。
|
|
85
38
|
unattendedPolicy: config.unattendedApprovalPolicy,
|
|
86
|
-
// #329:PARKED 行迟到决议的赎回席(晚绑取值口,见 LiveCoordinatorsCtx.getParkedRedeem)。
|
|
87
39
|
...(getParkedRedeem !== undefined ? { parkedRedeem: getParkedRedeem } : {}),
|
|
88
40
|
})
|
|
89
41
|
: undefined;
|
|
90
|
-
// SendUserFile(真 CC 契约,clay 2026-07-14)两种 lane 形态,其余缺席=诚实(工具不进 roster):
|
|
91
|
-
// - host lane:本地盘读+服务端上传,【单用户 only】——host 多租户=任意路径读→公网 URL 的 exfil 面,
|
|
92
|
-
// clay 拍永久关死,不留口子。路径=绝对或相对 process.cwd(用户目录语义,与 CC 一致)。
|
|
93
|
-
// - e2b/k8s lane(v2,Plan B 直传):沙箱内 stat+`curl -T` 打 server 预签的单对象 PUT(字节不中转、
|
|
94
|
-
// 凭据不进沙箱);沙箱自身文件系统=租户边界,故任意租户可用。
|
|
95
|
-
// - ssh lane(后补 2026-07-14):同一直传链,但 peer=跨任务共享的真实主机(非租户边界)→
|
|
96
|
-
// 【单用户 only】,租户门在 sandboxSendLaneEnabled(多租户下注册表不建,工具诚实缺席)。
|
|
97
|
-
// adb/local-docker 仍后补。
|
|
98
|
-
// 签发面缺 S3_PUBLIC_ENDPOINT 时 issue-time fail-loud(工具在但用即报修法);100MiB/文件帽在各 send 面。
|
|
99
42
|
const sendUserFileEmitter = (() => {
|
|
100
43
|
if (!config.sendUserFile)
|
|
101
44
|
return undefined;
|
|
102
45
|
if (sendUserFileTaskEnvs)
|
|
103
|
-
return new SendUserFileEmitter();
|
|
104
|
-
// unset REMOTE_EXEC(in-process/TOC 本地形态)有意归入 host 语义:exec 与文件都在本机,单用户门
|
|
105
|
-
// 同样把关(codex 复审提出收紧到显式 "host";判定=不收——unset 单机+配了 S3 是合法 dev/TOC 场景,
|
|
106
|
-
// 且与 1.187.0 已发行为一致;真正的红线是 requirePrincipal 多租户,这里恒关)。
|
|
46
|
+
return new SendUserFileEmitter();
|
|
107
47
|
const provider = config.remoteExec?.provider ?? "host";
|
|
108
48
|
if (provider === "host" && config.requirePrincipal !== true)
|
|
109
49
|
return new SendUserFileEmitter();
|
|
110
50
|
return undefined;
|
|
111
51
|
})();
|
|
112
|
-
// SendUserFile 账本(多租户治理面,[768]②a 后半):key 里的 scope 段是哈希(URL 不泄 principal),
|
|
113
|
-
// 按租户列/撤销的 scope↔对象映射记在 server 侧账本(四后端孪生,sendfile_link / JSONL)。有 backend 即建
|
|
114
|
-
// (签发面也配了才有写点);无 backend(env-only worker)= 无账本 = 不记账不 501 治理面(诚实缺席,
|
|
115
|
-
// capabilities.sendUserFileLedger=false)。
|
|
116
52
|
const sendFileLedger = config.sendUserFile && backend ? backend.sendFileLedger() : undefined;
|
|
117
53
|
const sendUserFileToolSpec = (() => {
|
|
118
54
|
if (!sendUserFileEmitter || !config.sendUserFile)
|
|
119
55
|
return undefined;
|
|
120
56
|
const issuer = createSendUserFileIssuer(config.sendUserFile);
|
|
121
|
-
// 两条 lane 的 send 都把 ctx.principal(core VERIFIED)传给签发面 → key 带哈希 scope 段 + link 携原文 scope。
|
|
122
57
|
const rawSend = sendUserFileTaskEnvs
|
|
123
58
|
? createSandboxFileSend({
|
|
124
59
|
registry: sendUserFileTaskEnvs,
|
|
@@ -133,13 +68,10 @@ export function createLiveCoordinators(ctx) {
|
|
|
133
68
|
if (st.size > SEND_USER_FILE_MAX_BYTES)
|
|
134
69
|
throw new Error(`file exceeds the ${Math.floor(SEND_USER_FILE_MAX_BYTES / (1024 * 1024))} MiB per-file cap (${st.size} bytes)`);
|
|
135
70
|
const bytes = await fsReadFile(resolved);
|
|
136
|
-
// 读后复验(codex 复审 MED):stat→read 间文件可增长——上传的是读到的字节,帽必须按真实字节数把关。
|
|
137
71
|
if (bytes.byteLength > SEND_USER_FILE_MAX_BYTES)
|
|
138
72
|
throw new Error(`file exceeds the ${Math.floor(SEND_USER_FILE_MAX_BYTES / (1024 * 1024))} MiB per-file cap (${bytes.byteLength} bytes)`);
|
|
139
73
|
return issuer.issue(bytes, basename(resolved), undefined, sendCtx.principal);
|
|
140
74
|
};
|
|
141
|
-
// 账本写点(两 lane 同语义):上传+verify 成功后、file_link 帧前记账;记账失败=该文件 fail-loud +
|
|
142
|
-
// best-effort 删已传对象(治理面必须有行;删失败 warn)。无账本(env-only)= 直通,行为与 1.189 一致。
|
|
143
75
|
const send = sendFileLedger
|
|
144
76
|
? withLedgerRecording(rawSend, {
|
|
145
77
|
ledger: sendFileLedger,
|
package/dist/boot/crash-last.js
CHANGED
|
@@ -1,32 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #320①([4728] clay 五点令)—— 崩溃遗言面 `crash-last.json`。
|
|
3
|
-
*
|
|
4
|
-
* 契约:**文件在场 ⇔ 上一次退出=崩溃**。铸点唯一=shutdown.ts 的 uncaught 双钩(写完仍 exit(1),
|
|
5
|
-
* 不吞崩溃);受控退(hardShutdown 收尾链)`clearCrashLast` 删文件——两形可判别就靠这一删:不删的话
|
|
6
|
-
* 文件语义退化成「历史上最后一次崩溃」,运维无从判「上次到底怎么退的」。
|
|
7
|
-
*
|
|
8
|
-
* 写路径全同步(`writeFileSync`):崩溃现场没有事件循环可信赖,async 写在 exit 前不保证落盘。
|
|
9
|
-
* err 只取**首行**且过 `redactSecrets`——崩溃消息常含连接串/token(DSN 在 error.message 里是
|
|
10
|
-
* 常见形,#305 同病),遗言是**判别位**不是取证档,stack 不落盘。
|
|
11
|
-
*/
|
|
12
1
|
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
13
2
|
import { join } from "node:path";
|
|
14
3
|
import { z } from "zod";
|
|
15
4
|
import { redactSecrets } from "../trace/redact.js";
|
|
16
|
-
/** 遗言文件的读回 schema(宪法 [2704] §2:边界读一律 safeParse,不裸铸)。写侧五键同形。 */
|
|
17
5
|
const CrashLastSchema = z.object({
|
|
18
6
|
at: z.string(),
|
|
19
7
|
version: z.string(),
|
|
20
8
|
pid: z.number(),
|
|
21
9
|
uptimeMs: z.number(),
|
|
22
|
-
/** 崩溃瞬间的在飞腿数(inflight getter 可用时);拿不到=键缺席,不编 0。 */
|
|
23
10
|
inflight: z.number().optional(),
|
|
24
11
|
err: z.string(),
|
|
25
12
|
});
|
|
26
13
|
export function crashLastPath(dataRoot) {
|
|
27
14
|
return join(dataRoot, "crash-last.json");
|
|
28
15
|
}
|
|
29
|
-
/** 崩溃现场写遗言(同步;自身绝不抛——遗言写失败不能遮蔽原崩溃)。 */
|
|
30
16
|
export function writeCrashLast(dataRoot, info) {
|
|
31
17
|
try {
|
|
32
18
|
const raw = info.err instanceof Error ? info.err.message : String(info.err);
|
|
@@ -42,19 +28,15 @@ export function writeCrashLast(dataRoot, info) {
|
|
|
42
28
|
writeFileSync(crashLastPath(dataRoot), JSON.stringify(body) + "\n");
|
|
43
29
|
}
|
|
44
30
|
catch {
|
|
45
|
-
// 遗言面自身故障(只读 FS 等)静默——崩溃路径上没有更好的去处,原错误仍会打到 stderr。
|
|
46
31
|
}
|
|
47
32
|
}
|
|
48
|
-
/** 受控退收尾:删遗言(幂等,缺席零抛)。 */
|
|
49
33
|
export function clearCrashLast(dataRoot) {
|
|
50
34
|
try {
|
|
51
35
|
unlinkSync(crashLastPath(dataRoot));
|
|
52
36
|
}
|
|
53
37
|
catch {
|
|
54
|
-
// ENOENT(本就没有)与其余失败同置:清不掉只意味着下次 boot 多一行提示,绝不阻塞停机。
|
|
55
38
|
}
|
|
56
39
|
}
|
|
57
|
-
/** boot 提示腿:在场读回、缺席/坏字节/坏形回 `undefined`(绝不抛——遗言坏了不能挡启动)。 */
|
|
58
40
|
export function readCrashLast(dataRoot) {
|
|
59
41
|
try {
|
|
60
42
|
const p = crashLastPath(dataRoot);
|
|
@@ -1,87 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #165 —— 沙箱 lane(e2b/k8s/ssh/adb/local-docker)写门的**真 env 裁决**接法。
|
|
3
|
-
*
|
|
4
|
-
* ## 缺口与它的形状
|
|
5
|
-
*
|
|
6
|
-
* core 的 `createFsWriteGatePolicy` / `createSensitivePathPolicy` 把每一个写目标交给
|
|
7
|
-
* `canonicalizeTarget(env, …)` 去问 fs 要真身(`absolutePath` → `exists` → `canonicalPath` →
|
|
8
|
-
* `fileInfo`/`readLink` 逐跳,dist 亲读)。host lane 上那个 env 就是 hand 工具真正写的那块盘。
|
|
9
|
-
* 沙箱 lane 不是:per-task 的沙箱 env 由 core 的 `executionEnvFactory` 在 spec **之后**才铸,
|
|
10
|
-
* 而写门 wiring 必须在 spec 期就交出去。
|
|
11
|
-
*
|
|
12
|
-
* 出路不是把裁决搬去 hook 层(那要在本仓复刻 `canonicalizeTarget` 的逐级 exists / symlink 解析 /
|
|
13
|
-
* 段匹配 / 折叠序——复制 core 的裁决逻辑=同源谎),而是利用一个部署事实:**那个 per-task 沙箱 env
|
|
14
|
-
* 本来就是本仓铸的**。于是本模块给写门一个 ExecutionEnv **代理**:它在**调用时刻**(runToolGate 裁决,
|
|
15
|
-
* 必在 prepare 之后)去 slot 里取该 task 的真 env 并转发 fs 读原语。call-time 转发消除了时序问题,
|
|
16
|
-
* 与「从调用上下文读 env」是同一性质。
|
|
17
|
-
*
|
|
18
|
-
* ## 三条不可动的裁定
|
|
19
|
-
*
|
|
20
|
-
* 1. **`absolutePath` 一面不转发**,沿用词法规则(POSIX 绝对形归一 / NUL 拒 / 非绝对形 err)。
|
|
21
|
-
* 真 env 的 `absolutePath` 会按 **env 自己的 cwd** 解析相对路径,而工具真写处按 engine 跟踪的
|
|
22
|
-
* cwd 解析——两个基准不同,转发它等于拿错基准铸 canonical key,而**错误的 allow 比没有门更糟**。
|
|
23
|
-
* 相对形 / `~` / 盘符形因此照旧 err ⇒ `canonicalizeTarget` 失败 ⇒ 写门 `ask`(fail-closed)。
|
|
24
|
-
* 「不猜沙箱工作目录」这条公理不随真 env 到场而松。
|
|
25
|
-
* 2. **slot 空 = fail-closed 且响亮**:转发面返回错误 ⇒ core 把 `exists` 报错读成
|
|
26
|
-
* `unresolvedSymlink` ⇒ `createSensitivePathPolicy` 判 deny、写门判 ask,折叠后 deny 恒赢。
|
|
27
|
-
* 保护型缺席的失败方向必须与能力语义同向。留痕走结构化 `warn`(每实例一次)而**不**走
|
|
28
|
-
* `observability/fail-open.ts`:那个词表按其模块头是 `F`(体验/缓存回退)与 `P-DEBT`(明知方向
|
|
29
|
-
* 不对的保护型欠账)两类的准入面,本臂方向是**对的**(fail-closed),登记进去会把「已收口的
|
|
30
|
-
* 保护臂」混进「待还的债」计数里。
|
|
31
|
-
* 3. **slot 只认「当前活腿」**:同一 session 同时只有一条活腿(HTTP `conflict.session_active_run` +
|
|
32
|
-
* core session acquire 双重串行化;委派子代另用一个 sessionId),所以同键改铸即顶替旧登记——
|
|
33
|
-
* 那些旧登记来自 park-only 之类「不 destroy 也不 suspend」的终局,留着只会让 resume 腿失去真身裁决。
|
|
34
|
-
*
|
|
35
|
-
* ## slot 的键 = sessionId
|
|
36
|
-
*
|
|
37
|
-
* 工厂 ctx 只有 `{sessionId, taskId?, isolation?, parentCwd?}`(core `ExecutionEnvFactoryContext`),
|
|
38
|
-
* 而 `/v1/runs` 会在 resolveSpec **之后**铸自己的持久 taskId 覆盖 `spec.taskId`,所以 taskId 在主路径
|
|
39
|
-
* 上对不上——sessionId 是两侧都稳的那一个(per-task 镜像登记簿是同一个先例)。
|
|
40
|
-
* 委派子任务(Agent / workflow 子代)拿的是**另一个** sessionId,所以父的 slot 不会被子代覆盖(「不许
|
|
41
|
-
* 最后写赢」由此成立)。**残余面**:子代的写仍按**父**的 env 裁决——子代的 policy 就是父的那一个实例
|
|
42
|
-
* (core `inheritedGateForChildren` 把它当 parentConstraint 继承),而 policy 收到的只有
|
|
43
|
-
* `{toolName, args, toolCallId}`,读侧根本没有腿身份可键控。方向上它逼近真相而非远离(过渡形是「谁的盘
|
|
44
|
-
* 都不看」),但有一条**新的松面**:父盘上一个名叫守卫段、真身良性的软链,会让子代在自己盘上指向真守卫段
|
|
45
|
-
* 的同名路径拿到父盘的宽松答案。收口需要一条「按当前工具调用的 env 裁决」的引擎缝,属设计件;
|
|
46
|
-
* 该面由 test/task-settings.test.ts 的「真身胜过名字」特征化钉机器可见。
|
|
47
|
-
*/
|
|
48
1
|
import { posix } from "node:path";
|
|
49
2
|
import { FileError, StubExecutionEnv, err, ok } from "@sema-agent/core";
|
|
50
|
-
/** 哪些 lane 用本模块的代理裁决写门 —— `REMOTE_EXEC` 未设(进程内 host)与显式 `host` 之外的全部。
|
|
51
|
-
* 与 resolve-spec 的 `hostSemanticsLane` 是同一判别式的两面,取值处**只此一个**(两处各写一份正是漂移的成因)。 */
|
|
52
3
|
export function isSandboxPathAdjudicationLane(provider) {
|
|
53
4
|
return provider !== undefined && provider !== "host";
|
|
54
5
|
}
|
|
55
|
-
/** 词法归一:纯字符串运算,折 `.` / `..` / 重复分隔符,不碰 fs。
|
|
56
|
-
* `posix.normalize` 把 `..` 在根部截断(`/../x` → `/x`),与「沙箱根之上没有东西」的语义一致。
|
|
57
|
-
* 尾部分隔符统一剥掉(根 `/` 除外),让同一目标只有一个 key ——前缀判域靠的就是 key 的唯一性。
|
|
58
|
-
* (core 内部有同形的 `normalizeAbsPathLexically`,但未从包根导出;此处是 Node 标准库的等价运算,
|
|
59
|
-
* 不是它的抄本——若日后 core 导出,这里应改为直接复用。) */
|
|
60
6
|
function normalizeAbsolutePathLexically(path) {
|
|
61
7
|
const collapsed = posix.normalize(path.replace(/^\/+/, "/"));
|
|
62
8
|
return collapsed.length > 1 ? collapsed.replace(/\/+$/, "") : collapsed;
|
|
63
9
|
}
|
|
64
|
-
/** 同时可登记的 session 数上限。到顶后先清死条目,仍满则**拒收新键、绝不驱逐在场者**:被拒的 session
|
|
65
|
-
* 只是拿不到真 env(⇒ fail-closed),而驱逐一个在场者会让一个正在跑的 task 的写门突然失去真身裁决。 */
|
|
66
10
|
const MAX_BOUND_SESSIONS = 4096;
|
|
67
|
-
/**
|
|
68
|
-
* per-session 的真 env 登记簿 —— 工厂装饰器写,写门代理读。
|
|
69
|
-
*
|
|
70
|
-
* **同键改铸 = 顶替**(不排队、不判歧义)。依据是一条被两道门执法的不变量:一个 session 同时只有一条
|
|
71
|
-
* 活腿(HTTP 层 `conflict.session_active_run` + core 的 session acquire),而委派子代用的是**另一个**
|
|
72
|
-
* sessionId。所以工厂为某 session 铸出新 env 的那一刻,同键上还留着的登记按构造已经是死腿——最典型的
|
|
73
|
-
* 产地是 **park-only 车道**(非 suspendable 的远程 env:durable park 既不 `suspendVM` 也不 `destroy`,
|
|
74
|
-
* core 的 `teardownOwnedEnv` 在 checkpoint token 在场时整条跳过)。留着它只会让 resume 腿整轮拿不到
|
|
75
|
-
* 真 env(写门恒 fail-closed);顶替按**实例身份**收口,被顶掉那一方迟到的注销全部落空,不误伤后继。
|
|
76
|
-
*/
|
|
77
11
|
export class SandboxPathEnvSlots {
|
|
78
|
-
/** **弱持有**:登记簿只在「别人还用着这个 env」期间指向它。跑着的任务由 core 强持有(`prepared.ownedEnv`),
|
|
79
|
-
* 所以在场腿的裁决永远解得出;而一条 park 后再没人来 resume 的死腿,其 env 一旦无人引用即可被回收,
|
|
80
|
-
* 条目在下一次清扫时消失。强持有会把它们连同各自的 adapter 连接一起钉死到进程结束,并在 4096 条之后
|
|
81
|
-
* 让**每一个**新 session 拿不到真 env(守卫集下 = 每一次结构化写都 deny)—— 那是一道会自己关上的门。 */
|
|
82
12
|
bySession = new Map();
|
|
83
|
-
/** 登记一个刚铸出的 env(同键顶替),返回**幂等**的注销闭包;到达上限而拒收时返回 `undefined`。
|
|
84
|
-
* 注销按**实例身份**摘除,所以一个迟到的 destroy 不会误伤同键的后继 env。 */
|
|
85
13
|
bind(sessionId, env) {
|
|
86
14
|
if (!this.bySession.has(sessionId) && this.bySession.size >= MAX_BOUND_SESSIONS) {
|
|
87
15
|
this.sweepCollected();
|
|
@@ -102,46 +30,21 @@ export class SandboxPathEnvSlots {
|
|
|
102
30
|
const env = ref?.deref();
|
|
103
31
|
if (env === undefined) {
|
|
104
32
|
if (ref !== undefined)
|
|
105
|
-
this.bySession.delete(sessionId);
|
|
33
|
+
this.bySession.delete(sessionId);
|
|
106
34
|
return { ok: false, reason: "unbound" };
|
|
107
35
|
}
|
|
108
36
|
return { ok: true, env };
|
|
109
37
|
}
|
|
110
|
-
/** 登记簿规模(上限行为的可观测面;测试与运维探针用)。含尚未清扫的死条目。 */
|
|
111
38
|
get boundSessions() {
|
|
112
39
|
return this.bySession.size;
|
|
113
40
|
}
|
|
114
|
-
/** 清掉 env 已被回收的条目。只在触到上限时跑一遍(O(n) 的代价换掉一次拒收)。 */
|
|
115
41
|
sweepCollected() {
|
|
116
42
|
for (const [sid, ref] of this.bySession)
|
|
117
43
|
if (ref.deref() === undefined)
|
|
118
44
|
this.bySession.delete(sid);
|
|
119
45
|
}
|
|
120
46
|
}
|
|
121
|
-
/** 进程内唯一的登记簿:工厂装饰器(boot/execution-env.ts)与写门 wiring(boot/resolve-spec.ts)分处
|
|
122
|
-
* 装配链两端,而中间的 core 只肯传 `ExecutionEnvFactoryContext`——两端共享同一个实例是它们唯一的会合点。
|
|
123
|
-
* 测试要隔离时自建 {@link SandboxPathEnvSlots} 实例注入即可(两个消费点都收可选参)。 */
|
|
124
47
|
export const sandboxPathEnvSlots = new SandboxPathEnvSlots();
|
|
125
|
-
/**
|
|
126
|
-
* 装饰工厂:每铸出一个 env 就按 `ctx.sessionId` 登记(同键顶替,见 {@link SandboxPathEnvSlots}),
|
|
127
|
-
* 终态时注销。
|
|
128
|
-
*
|
|
129
|
-
* 挂**最外层**(装配链尾):内层装饰器可能**换掉**env 实例(worktree 隔离的 `rootEnvAt`)或改写它的
|
|
130
|
-
* 方法(scratchpad 的 exec/canonicalPath 前置),写门要裁决的是 core 最终拿到手的那一个。
|
|
131
|
-
*
|
|
132
|
-
* 生命周期三面(顺序即语义):
|
|
133
|
-
* · `destroy` ⇒ 注销。
|
|
134
|
-
* · `suspendVM` 成功 ⇒ 注销。core 在挂起时**跳过** destroy(runtask 留着 env 做快照),所以这是可挂起
|
|
135
|
-
* 车道唯一的及时腾位点:挂起期该 session 没有活腿,登记留着只是白占登记簿容量。
|
|
136
|
-
* · `resumeVM` 成功 ⇒ **重新登记**。挂起并不必然终结这一轮:`commitSuspendSaga` 的 checkpoint 写失败
|
|
137
|
-
* 臂会 `resumeVM` + `postResumeInit` 把**同一个实例**复活,然后作废本次挂起让 run 继续跑
|
|
138
|
-
* (core dist 亲读)。只注销不复登记,一次瞬时 checkpoint 故障就会让这条 run 之后每一次写都失去真身
|
|
139
|
-
* 裁决(方向 fail-closed,但整轮写面被毒死)。复登记幂等:仍在场时是 no-op,所以正常 resume 腿
|
|
140
|
-
* (新 env 在工厂处已登记、随后被 core `resumeVM` 复原快照)照旧不动;后继腿已接管该 session 时也不抢回。
|
|
141
|
-
*
|
|
142
|
-
* 两个终态面都缺席的 env(五条沙箱 adapter 都不是这一形)照样登记——正确性优先于回收:不登记等于
|
|
143
|
-
* 让那条 lane 的写门恒 fail-closed。回收兜底=登记簿自己的上限。
|
|
144
|
-
*/
|
|
145
48
|
export function withSandboxPathEnvSlot(factory, slots, logger) {
|
|
146
49
|
return async (ctx) => {
|
|
147
50
|
const env = await factory(ctx);
|
|
@@ -150,7 +53,6 @@ export function withSandboxPathEnvSlot(factory, slots, logger) {
|
|
|
150
53
|
const sessionId = ctx.sessionId;
|
|
151
54
|
let release = slots.bind(sessionId, env);
|
|
152
55
|
if (release === undefined) {
|
|
153
|
-
// 上限拒收:该 task 的写门会落 fail-closed 而不是拿别人的盘裁决,但运维得知道为什么。
|
|
154
56
|
logger?.warn?.("sandbox_path_env_slot_at_capacity", { sessionId, boundSessions: slots.boundSessions });
|
|
155
57
|
return env;
|
|
156
58
|
}
|
|
@@ -160,9 +62,9 @@ export function withSandboxPathEnvSlot(factory, slots, logger) {
|
|
|
160
62
|
};
|
|
161
63
|
const revive = () => {
|
|
162
64
|
if (release !== undefined)
|
|
163
|
-
return;
|
|
65
|
+
return;
|
|
164
66
|
if (slots.resolve(sessionId).ok)
|
|
165
|
-
return;
|
|
67
|
+
return;
|
|
166
68
|
release = slots.bind(sessionId, env);
|
|
167
69
|
if (release === undefined)
|
|
168
70
|
logger?.warn?.("sandbox_path_env_slot_at_capacity", { sessionId, boundSessions: slots.boundSessions });
|
|
@@ -197,18 +99,10 @@ export function withSandboxPathEnvSlot(factory, slots, logger) {
|
|
|
197
99
|
return env;
|
|
198
100
|
};
|
|
199
101
|
}
|
|
200
|
-
/**
|
|
201
|
-
* 写门用的 ExecutionEnv 代理(见文件头)。fs **读**原语转发 slot 里的真 env,`absolutePath` 保留词法形,
|
|
202
|
-
* 其余一切(写面 / shell 面 / listDir …)继承 `StubExecutionEnv` 的 `not_supported`。
|
|
203
|
-
*
|
|
204
|
-
* **继承而非逐一手写**是刻意的:core 日后给 `ExecutionEnv` 加必填面时,新面会随 `StubExecutionEnv`
|
|
205
|
-
* 一起到位并保持同一个诚实答案,不会在这里留下一个悄悄编出来的假答案。
|
|
206
|
-
*/
|
|
207
102
|
export class DeferredSandboxPathEnv extends StubExecutionEnv {
|
|
208
103
|
sessionId;
|
|
209
104
|
slots;
|
|
210
105
|
logger;
|
|
211
|
-
/** 每实例一次的留痕闸:裁决面每个写目标要走 3-4 次转发,逐次 warn 会把日志刷成噪声。 */
|
|
212
106
|
warned = false;
|
|
213
107
|
constructor(opts) {
|
|
214
108
|
super();
|
|
@@ -216,7 +110,6 @@ export class DeferredSandboxPathEnv extends StubExecutionEnv {
|
|
|
216
110
|
this.slots = opts.slots;
|
|
217
111
|
this.logger = opts.logger;
|
|
218
112
|
}
|
|
219
|
-
/** 取真 env;取不到就地铸 fail-closed 错误(并留痕一次)。 */
|
|
220
113
|
bound(path, face) {
|
|
221
114
|
const found = this.slots.resolve(this.sessionId);
|
|
222
115
|
if (found.ok)
|
|
@@ -235,16 +128,10 @@ export class DeferredSandboxPathEnv extends StubExecutionEnv {
|
|
|
235
128
|
error: new FileError("not_supported", `no sandbox execution environment is bound for this task (${found.reason}) — the write gate cannot inspect the real filesystem`, path),
|
|
236
129
|
};
|
|
237
130
|
}
|
|
238
|
-
/** 词法一面,**不**转发 —— 理由见文件头裁定 1。 */
|
|
239
131
|
absolutePath(path) {
|
|
240
|
-
// 含 NUL 的字符串不是合法 POSIX 路径(任何 fs 面都写不进去),但词法归一会照样给它铸出 canonical
|
|
241
|
-
// key——`\0` 尾巴让守卫段 glob 失配,豁免会话下还能拿 allow。拒收让 canon 在豁免咨询**之前**就失败。
|
|
242
132
|
if (path.includes("\u0000")) {
|
|
243
133
|
return Promise.resolve(err(new FileError("not_supported", "this gate resolves paths lexically and rejects a path containing a NUL byte (not a representable POSIX path)", path)));
|
|
244
134
|
}
|
|
245
|
-
// POSIX 绝对形是沙箱 lane(全 Linux)上 hand 工具的书面契约形。相对路径 / `~` / `C:\…` 都要一个
|
|
246
|
-
// 沙箱工作目录才能解析,而那个基准与工具真写处的基准不是同一个,不猜。
|
|
247
|
-
// (反斜杠 UNC 形根本到不了这里:core 在 canonicalizeTarget 入口就短路了。)
|
|
248
135
|
if (!path.startsWith("/")) {
|
|
249
136
|
return Promise.resolve(err(new FileError("not_supported", "this gate cannot resolve a non-absolute path (the sandbox working directory is not the gate's to guess)", path)));
|
|
250
137
|
}
|
|
@@ -262,9 +149,6 @@ export class DeferredSandboxPathEnv extends StubExecutionEnv {
|
|
|
262
149
|
const b = this.bound(path, "fileInfo");
|
|
263
150
|
return b.ok ? b.env.fileInfo(path, abortSignal) : b;
|
|
264
151
|
}
|
|
265
|
-
/** `readLink` 在 `ExecutionEnv` 上是**可选**面。本代理恒定义它,于是 core 永远走不到自己的
|
|
266
|
-
* 「env 没有 readLink」腿——真 env 缺这一面时由此处答错误,落到 core 同一条 `unresolvedSymlink` 出口,
|
|
267
|
-
* 裁决结果与那条腿完全一致。 */
|
|
268
152
|
async readLink(path, abortSignal) {
|
|
269
153
|
const b = this.bound(path, "readLink");
|
|
270
154
|
if (!b.ok)
|