@sema-agent/server 7.149.0 → 7.151.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/MIGRATION.md +307 -9
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +92 -40
- package/deploy/sema-up/README.md +7 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +3 -3
- package/dist/approval-gate-currency.d.ts +2 -2
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +2 -2
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +7 -8
- package/dist/boot/resolve-spec.js +80 -35
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +28 -24
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +16 -8
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +44 -6
- package/dist/boot/stage-10-http-server.js +12 -10
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/boot/web-admin.js +3 -1
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capability-facts.d.ts +84 -66
- package/dist/capability-facts.js +58 -41
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +15 -12
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +22 -15
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +66 -29
- package/dist/device-ws-protocol.d.ts +79 -12
- package/dist/device-ws-protocol.js +64 -26
- package/dist/engine-identity.d.ts +23 -5
- package/dist/engine-identity.js +13 -0
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +3 -3
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +19 -4
- package/dist/http/approval-sweeps.js +7 -6
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +20 -63
- package/dist/http/checkpoint-ctx.js +2 -24
- package/dist/http/claim-heartbeat.d.ts +4 -4
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +36 -29
- package/dist/http/durable-run-leg.js +17 -17
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +264 -20
- package/dist/http/owner-access.js +215 -5
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.js +38 -1
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +273 -89
- package/dist/http/route-ctx.d.ts +41 -19
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/a2a-serve.js +15 -14
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +12 -12
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +10 -6
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/projects.d.ts +4 -2
- package/dist/http/routes/projects.js +7 -6
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +125 -66
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +174 -83
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +26 -48
- package/dist/http/routes/tasks.js +38 -23
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +28 -30
- package/dist/http/server.js +7 -3
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +1 -2
- package/dist/http/submit-ctx.js +8 -6
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +19 -6
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/endpoint.js +9 -8
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +19 -5
- package/dist/leg-facts.js +3 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +12 -8
- package/dist/observability/fail-open.js +12 -8
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/owner-faces.d.ts +28 -4
- package/dist/owner-faces.js +2 -0
- package/dist/parked-decide.d.ts +104 -53
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/permission-mode-admission.d.ts +41 -5
- package/dist/permission-mode-admission.js +29 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -1
- package/dist/plugins/local-checkpoint-store.js +3 -0
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +80 -61
- package/dist/plugins/one-time-migrations.js +241 -104
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +28 -1
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +8 -3
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +44 -17
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +114 -14
- package/dist/plugins/remote-env-e2b.d.ts +18 -7
- package/dist/plugins/remote-env-e2b.js +53 -40
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +18 -1
- package/dist/plugins/remote-env-host.js +48 -47
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +56 -32
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +37 -43
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +64 -62
- package/dist/plugins/remote-shell.d.ts +101 -2
- package/dist/plugins/remote-shell.js +221 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +22 -3
- package/dist/plugins/run-store-sql.js +33 -9
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
- package/dist/plugins/schema-consistency.d.ts +9 -5
- package/dist/plugins/schema-consistency.js +48 -18
- package/dist/plugins/schema-drift-sentence.js +1 -1
- package/dist/plugins/send-file-ledger.js +3 -0
- package/dist/plugins/serving-requirement.d.ts +68 -0
- package/dist/plugins/serving-requirement.js +60 -0
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/stop-then-start-sentence.d.ts +48 -3
- package/dist/plugins/stop-then-start-sentence.js +48 -0
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +40 -13
- package/dist/plugins/store-backend.js +169 -27
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +29 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.js +9 -0
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +6 -1
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +64 -0
- package/dist/project-context.js +66 -0
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-cancel-card.d.ts +1 -1
- package/dist/run-cancel-card.js +2 -1
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +31 -33
- package/dist/security.js +41 -7
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-agent.d.ts +1 -10
- package/dist/session-agent.js +0 -6
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +28 -4
- package/dist/session-incarnation.js +14 -2
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +4 -98
- package/dist/session-sync.js +4 -74
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
- package/dist/stores-sql/checkpoint-store-sql.js +106 -18
- package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +2 -10
- package/dist/stores-sql/retention-store-sql.js +2 -10
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +6 -5
- package/dist/task-settings.d.ts +19 -5
- package/dist/task-settings.js +13 -7
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +147 -12
- package/dist/tool-approval.js +206 -109
- package/dist/trace/engine-notice-wire.d.ts +14 -0
- package/dist/trace/engine-notice-wire.js +18 -1
- package/dist/trace/project.d.ts +4 -3
- package/dist/trace/project.js +3 -2
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/self-minted-wire.d.ts +422 -26
- package/dist/trace/self-minted-wire.js +149 -23
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +120 -41
- package/package.json +3 -3
- package/wire-changes/server@7.150.0.json +335 -0
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { RemoteExecutionError, isRetryableRemoteErrorCode } from "@sema-agent/core";
|
|
2
|
+
export const CONNECT_REFUSAL_CODE = {
|
|
3
|
+
home_unconfirmed: "env.home_unconfirmed",
|
|
4
|
+
snapshot_bucket_missing: "env.snapshot_bucket_missing",
|
|
5
|
+
occupant_missing: "env.occupant_missing",
|
|
6
|
+
pod_admission_refused: "env.sandbox_refused",
|
|
7
|
+
credential_broker_refused: "env.sandbox_refused",
|
|
8
|
+
archive_unrecoverable: "env.sandbox_refused",
|
|
9
|
+
workspace_fill_refused: "env.sandbox_refused",
|
|
10
|
+
host_key_rejected: "env.host_key_rejected",
|
|
11
|
+
pod_quota_exceeded: "connect_failed",
|
|
12
|
+
occupant_unreadable: "connect_failed",
|
|
13
|
+
target_settling: "connect_failed",
|
|
14
|
+
};
|
|
15
|
+
const ENGINE_FIELD_STILL_CLOSED = true;
|
|
16
|
+
void ENGINE_FIELD_STILL_CLOSED;
|
|
17
|
+
function mintRefusalError(code, message, cause) {
|
|
18
|
+
return new RemoteExecutionError(code, message, cause);
|
|
19
|
+
}
|
|
20
|
+
function standsFor(code) {
|
|
21
|
+
return !isRetryableRemoteErrorCode(code);
|
|
22
|
+
}
|
|
23
|
+
export function connectRefusal(fact, message, cause) {
|
|
24
|
+
const code = CONNECT_REFUSAL_CODE[fact];
|
|
25
|
+
const error = mintRefusalError(code, message, cause);
|
|
26
|
+
return standsFor(code) ? { ok: false, error, standing: true } : { ok: false, error, standing: false };
|
|
27
|
+
}
|
|
28
|
+
export function withdrawOnAbort(walk, signal) {
|
|
29
|
+
if (signal === undefined)
|
|
30
|
+
return walk;
|
|
31
|
+
if (signal.aborted)
|
|
32
|
+
return Promise.resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted") });
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const onAbort = () => resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted while waiting") });
|
|
35
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
36
|
+
walk.then((r) => {
|
|
37
|
+
signal.removeEventListener("abort", onAbort);
|
|
38
|
+
resolve(r);
|
|
39
|
+
}, (e) => {
|
|
40
|
+
signal.removeEventListener("abort", onAbort);
|
|
41
|
+
reject(e);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export function createConnectSeat(lane) {
|
|
46
|
+
let held;
|
|
47
|
+
return {
|
|
48
|
+
get held() {
|
|
49
|
+
return held;
|
|
50
|
+
},
|
|
51
|
+
answer(refusal) {
|
|
52
|
+
if (refusal.standing && held === undefined)
|
|
53
|
+
held = refusal;
|
|
54
|
+
return refusal;
|
|
55
|
+
},
|
|
56
|
+
connect(config) {
|
|
57
|
+
if (held !== undefined)
|
|
58
|
+
return Promise.resolve(held);
|
|
59
|
+
const signal = config?.abortSignal;
|
|
60
|
+
const walking = lane.inFlight();
|
|
61
|
+
if (walking !== undefined)
|
|
62
|
+
return withdrawOnAbort(walking, signal);
|
|
63
|
+
const handle = lane.live();
|
|
64
|
+
if (handle !== undefined)
|
|
65
|
+
return Promise.resolve({ ok: true, value: handle });
|
|
66
|
+
if (signal?.aborted)
|
|
67
|
+
return Promise.resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted") });
|
|
68
|
+
return lane.establish(config);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=remote-env-connect-seat.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecutionError, FileError, RemoteExecutionError, type ExecutionEnv, type ExecutionEnvFactory, type ExecStreamOptions, type FileInfo, type OutputChunk, type RemoteConnectConfig, type RemoteExecutionEnv, type Result, type SessionToken, type SnapshotId, type VmLifecycleOptions, type WorkspaceHandle, type WriteExpectation, type WriteReceipt } from "@sema-agent/core";
|
|
1
|
+
import { ExecutionError, FileError, RemoteExecutionError, type ExecutionEnv, type ExecutionEnvFactory, type ExecStreamOptions, type FileInfo, type OutputChunk, type RemoteConnectConfig, type RemoteExecutionEnv, type Result, type SessionToken, type SnapshotId, type VmLifecycleOptions, type WorkspaceHandle, type WriteExpectation, type WriteReceipt, type BoundFileObject } from "@sema-agent/core";
|
|
2
2
|
import { type DeviceOwner, type DeviceRejectCode, type DeviceRow, type DeviceStore } from "../device-store.js";
|
|
3
3
|
import type { DeviceEnrollment } from "../device-enrollment.js";
|
|
4
4
|
import { type ExecutionPlacementSeat } from "../execution-placement.js";
|
|
@@ -48,6 +48,13 @@ type RejectCode = DeviceRejectCode;
|
|
|
48
48
|
*/
|
|
49
49
|
export declare const DEVICE_REJECT_TO_EXEC_ERROR: Readonly<Record<RejectCode, ExecutionError["code"]>>;
|
|
50
50
|
export declare const DEVICE_REJECT_TO_FILE_ERROR: Readonly<Record<RejectCode, FileError["code"]>>;
|
|
51
|
+
/**
|
|
52
|
+
* 生命周期面(connect/reconnect)的 typed 拒 → `RemoteExecutionErrorCode`。
|
|
53
|
+
*
|
|
54
|
+
* `connect_failed` = 本次到不了(**可重试**,core `RETRYABLE_REMOTE_ERROR_CODES` 含它);
|
|
55
|
+
* `auth_failed` = 永久拒(NEVER retry —— 换绑/吊销/不是你的设备,重试一万次也是同一答)。
|
|
56
|
+
*/
|
|
57
|
+
export declare const DEVICE_REJECT_TO_REMOTE_ERROR: Readonly<Record<RejectCode, RemoteExecutionError["code"]>>;
|
|
51
58
|
export interface DeviceEnvLogger {
|
|
52
59
|
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
53
60
|
info?(msg: string, fields?: Record<string, unknown>): void;
|
|
@@ -102,9 +109,15 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
|
102
109
|
readLink?: (path: string, abortSignal?: AbortSignal) => Promise<Result<string, FileError>>;
|
|
103
110
|
writeFileExclusive?: (path: string, content: string | Uint8Array, abortSignal?: AbortSignal) => Promise<Result<void, FileError>>;
|
|
104
111
|
writeFileGuarded?: (path: string, content: string | Uint8Array, expect: WriteExpectation, abortSignal?: AbortSignal) => Promise<Result<WriteReceipt, FileError>>;
|
|
112
|
+
openBound?: (path: string, abortSignal?: AbortSignal) => Promise<Result<BoundFileObject, FileError>>;
|
|
105
113
|
private connected;
|
|
106
114
|
/** 在飞的那一次准入(单飞记忆)——见 {@link admitShared}。settle 即清,**不缓存败诺**。 */
|
|
107
115
|
private connectPromise?;
|
|
116
|
+
/**
|
|
117
|
+
* 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序 —— 准入在飞 ⇒ 等那一次(调用方的取消只退它自己的等待)· 已连 ⇒ 当下的把手、不再准入 · 否则准入一次。
|
|
118
|
+
* 本车道不记拒:准入每次都是对绑定 / 吊销 / 在线的一次新读(拒码按生命周期表拼:{@link DEVICE_REJECT_TO_REMOTE_ERROR})。
|
|
119
|
+
*/
|
|
120
|
+
private readonly seat;
|
|
108
121
|
/** 拆除是**终态**(六条兄弟腿同纪律:destroy 之后 connect/exec/读面一律 fail-closed,不复活)。 */
|
|
109
122
|
private destroyed;
|
|
110
123
|
constructor(cfg: DeviceEnvConfig);
|
|
@@ -170,10 +183,8 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
|
170
183
|
/**
|
|
171
184
|
* 懒连接:**首次调用任一面**(exec / execStream / 文件面)时自动走一次准入。
|
|
172
185
|
*
|
|
173
|
-
* 🔴 为什么这条必须在 adapter 里(而不是「谁用谁先 connect」)
|
|
174
|
-
*
|
|
175
|
-
* `.connect()` 只有 bench 与生命周期面自己)。所以一条「设了未连闸、又不自连」的腿,它的每一次工具
|
|
176
|
-
* 调用都被自家的闸挡回,而设备侧一条指令帧都收不到。e2b(首用建 VM)/ k8s(`connectPromise ??=`)/
|
|
186
|
+
* 🔴 为什么这条必须在 adapter 里(而不是「谁用谁先 connect」):面可能在任何人连它之前就被调到(工厂交出之前的附件物化层、
|
|
187
|
+
* 委派子代的放置检查)。所以一条「设了未连闸、又不自连」的腿,它的每一次工具调用都被自家的闸挡回,而设备侧一条指令帧都收不到。e2b(首用建 VM)/ k8s(`connectPromise ??=`)/
|
|
177
188
|
* ssh(single-flight join)/ local-docker 四腿早就是懒连接;本腿从此同形,`connect()` 的语义
|
|
178
189
|
* (准入 + 取活连接 + 保护面对拍)一个字不动,只是触发时机与兄弟一致。
|
|
179
190
|
*
|
|
@@ -262,6 +273,12 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
|
|
|
262
273
|
canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
263
274
|
fileInfo(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo, FileError>>;
|
|
264
275
|
private doReadLink;
|
|
276
|
+
private doOpenBound;
|
|
277
|
+
/**
|
|
278
|
+
* 逐答重绑的答者:每一答一条 `openBound` 指令,结局 kind **按 op 精确对拍**(`open` / `size` / `list` ⇒ `stat`,`readBytes` ⇒ `read`;答错 = 协议违约,不猜)。
|
|
279
|
+
* 开答之后的三答带开答时的 `identity` + `kind`,执行器在本机核对这一次打开的对象与它们都相等;每一答前照文件面同一道门(已拆 ⇒ 拒;首用准入)。
|
|
280
|
+
*/
|
|
281
|
+
private boundAnswers;
|
|
265
282
|
readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
|
|
266
283
|
readTextFile(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
267
284
|
readTextLines(p: string, options?: {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
|
+
import { anchoredPath, anchorUnder, joinedPath } from "./exec-path-law.js";
|
|
2
3
|
import { ExecutionError, FileError, RemoteExecutionError, } from "@sema-agent/core";
|
|
4
|
+
import { openRebinding } from "./remote-shell.js";
|
|
3
5
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
4
6
|
import { DEVICE_ERROR_CODES, isDeviceAbsolutePath, } from "../device-store.js";
|
|
5
7
|
import { boundDeviceOf } from "../execution-placement.js";
|
|
6
8
|
import { createCutError, createExecFailure } from "../exec-cut.js";
|
|
9
|
+
import { createConnectSeat, withdrawOnAbort } from "./remote-env-connect-seat.js";
|
|
7
10
|
export const DEVICE_PROVIDER = "device";
|
|
8
11
|
const ok = (value) => ({ ok: true, value });
|
|
9
12
|
const STREAM_PENDING_MAX_BYTES = 2 * 1024 * 1024;
|
|
@@ -88,12 +91,12 @@ export const DEVICE_REJECT_TO_FILE_ERROR = {
|
|
|
88
91
|
"limit.rate_exceeded": "target_unavailable",
|
|
89
92
|
"draining": "target_unavailable",
|
|
90
93
|
};
|
|
91
|
-
const DEVICE_REJECT_TO_REMOTE_ERROR = {
|
|
94
|
+
export const DEVICE_REJECT_TO_REMOTE_ERROR = {
|
|
92
95
|
"device.not_bound": "connect_failed",
|
|
93
96
|
"device.offline": "connect_failed",
|
|
94
97
|
"device.busy": "connect_failed",
|
|
95
98
|
"device.attached_elsewhere": "connect_failed",
|
|
96
|
-
"device.claim_conflict": "
|
|
99
|
+
"device.claim_conflict": "connect_failed",
|
|
97
100
|
"device.provider_mismatch": "auth_failed",
|
|
98
101
|
"device.identity_mismatch": "auth_failed",
|
|
99
102
|
"device.revoked": "auth_failed",
|
|
@@ -109,6 +112,9 @@ function rejectText(reject) {
|
|
|
109
112
|
}
|
|
110
113
|
const ENV_TERMINAL = { kind: "env_terminal" };
|
|
111
114
|
const ENV_TERMINAL_MESSAGE = "execution env already destroyed";
|
|
115
|
+
function connectAnswerOf(admitted) {
|
|
116
|
+
return admitted.ok ? { ok: true, value: admitted.value } : { ok: false, error: new RemoteExecutionError(admitted.failure.remote, admitted.failure.message) };
|
|
117
|
+
}
|
|
112
118
|
function failureFor(code, message) {
|
|
113
119
|
return { remote: DEVICE_REJECT_TO_REMOTE_ERROR[code], exec: DEVICE_REJECT_TO_EXEC_ERROR[code], file: DEVICE_REJECT_TO_FILE_ERROR[code], message };
|
|
114
120
|
}
|
|
@@ -136,8 +142,14 @@ export class RemoteDeviceExecutionEnv {
|
|
|
136
142
|
readLink;
|
|
137
143
|
writeFileExclusive;
|
|
138
144
|
writeFileGuarded;
|
|
145
|
+
openBound;
|
|
139
146
|
connected = false;
|
|
140
147
|
connectPromise;
|
|
148
|
+
seat = createConnectSeat({
|
|
149
|
+
live: () => (this.connected && !this.destroyed ? this.workspaceHandle() : undefined),
|
|
150
|
+
inFlight: () => this.connectPromise?.then(connectAnswerOf),
|
|
151
|
+
establish: (config) => withdrawOnAbort(this.admitShared().then(connectAnswerOf), config?.abortSignal),
|
|
152
|
+
});
|
|
141
153
|
destroyed = false;
|
|
142
154
|
constructor(cfg) {
|
|
143
155
|
this.cfg = cfg;
|
|
@@ -149,6 +161,8 @@ export class RemoteDeviceExecutionEnv {
|
|
|
149
161
|
this.writeFileExclusive = (p, c, s) => this.doWrite("writeFileExclusive", p, c, undefined, s);
|
|
150
162
|
if (cfg.supports?.has("writeFileGuarded") === true)
|
|
151
163
|
this.writeFileGuarded = (p, c, e, s) => this.doGuardedWrite(p, c, e, s);
|
|
164
|
+
if (cfg.supports?.has("openBound") === true)
|
|
165
|
+
this.openBound = (p, s) => this.doOpenBound(p, s);
|
|
152
166
|
}
|
|
153
167
|
guardFaceSnapshot() {
|
|
154
168
|
const out = new Set();
|
|
@@ -174,7 +188,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
174
188
|
"performing a NON-atomic write here is exactly the silent downgrade guarded writes exist to prevent (#157). Refusing; the per-task factory mints a correctly-shaped env on the next task.", absPath);
|
|
175
189
|
}
|
|
176
190
|
resolve(p) {
|
|
177
|
-
return
|
|
191
|
+
return anchoredPath(DEVICE_PATH_FAMILY, this.cwd, p);
|
|
178
192
|
}
|
|
179
193
|
instructionCwd(requested) {
|
|
180
194
|
return requested === undefined ? this.cwd : this.resolve(requested);
|
|
@@ -183,7 +197,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
183
197
|
return ok(this.resolve(p));
|
|
184
198
|
}
|
|
185
199
|
async joinPath(parts) {
|
|
186
|
-
return ok(
|
|
200
|
+
return ok(joinedPath(DEVICE_PATH_FAMILY, parts));
|
|
187
201
|
}
|
|
188
202
|
workspaceHandle() {
|
|
189
203
|
return {
|
|
@@ -195,12 +209,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
195
209
|
};
|
|
196
210
|
}
|
|
197
211
|
async connect(config) {
|
|
198
|
-
|
|
199
|
-
return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted") };
|
|
200
|
-
const admitted = await this.admitShared();
|
|
201
|
-
if (admitted.ok)
|
|
202
|
-
return ok(admitted.value);
|
|
203
|
-
return { ok: false, error: new RemoteExecutionError(admitted.failure.remote, admitted.failure.message) };
|
|
212
|
+
return this.seat.connect(config);
|
|
204
213
|
}
|
|
205
214
|
async admitShared() {
|
|
206
215
|
const inflight = this.connectPromise;
|
|
@@ -557,7 +566,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
557
566
|
return this.wrongOutcome("stat", o.kind, abs);
|
|
558
567
|
if (!o.info)
|
|
559
568
|
return { ok: false, error: new FileError("unknown", "device returned a stat outcome without info — protocol violation", abs) };
|
|
560
|
-
return ok(toFileInfo(o.info));
|
|
569
|
+
return ok(toFileInfo(o.info, abs));
|
|
561
570
|
});
|
|
562
571
|
}
|
|
563
572
|
async doReadLink(p, abortSignal) {
|
|
@@ -576,6 +585,96 @@ export class RemoteDeviceExecutionEnv {
|
|
|
576
585
|
return ok(o.linkTarget);
|
|
577
586
|
});
|
|
578
587
|
}
|
|
588
|
+
async doOpenBound(p, abortSignal) {
|
|
589
|
+
const gated = await this.fsGate(p);
|
|
590
|
+
if (gated)
|
|
591
|
+
return gated;
|
|
592
|
+
const abs = this.resolve(p);
|
|
593
|
+
return openRebinding(abs, this.boundAnswers(abs), abortSignal);
|
|
594
|
+
}
|
|
595
|
+
boundAnswers(abs) {
|
|
596
|
+
const send = async (args, signal, onChunk) => {
|
|
597
|
+
const gated = await this.fsGate(abs);
|
|
598
|
+
if (gated)
|
|
599
|
+
return gated;
|
|
600
|
+
return this.dispatch("openBound", { path: abs, ...args }, { timeoutMs: this.cfg.execTimeoutMs, ...(signal === undefined ? {} : { signal }), ...(onChunk === undefined ? {} : { onChunk }) });
|
|
601
|
+
};
|
|
602
|
+
const violation = (what) => ({ ok: false, error: new FileError("unknown", `device returned an openBound outcome ${what} — protocol violation`, abs) });
|
|
603
|
+
return {
|
|
604
|
+
open: async (signal) => {
|
|
605
|
+
const res = await send({ op: "open" }, signal);
|
|
606
|
+
if ("ok" in res)
|
|
607
|
+
return res;
|
|
608
|
+
return this.fileOutcome(res, abs, (o) => {
|
|
609
|
+
if (o.kind !== "stat")
|
|
610
|
+
return this.wrongOutcome("stat", o.kind, abs);
|
|
611
|
+
if (typeof o.identity !== "string" || o.identity === "" || o.info === undefined)
|
|
612
|
+
return violation("without identity and info for the open answer");
|
|
613
|
+
if (o.info.kind !== "file" && o.info.kind !== "dir")
|
|
614
|
+
return violation(`naming a ${o.info.kind} (an executor refuses anything but a regular file or a directory with invalid)`);
|
|
615
|
+
return ok({ identity: o.identity, kind: o.info.kind === "dir" ? "directory" : "file" });
|
|
616
|
+
});
|
|
617
|
+
},
|
|
618
|
+
size: async (bound) => {
|
|
619
|
+
const res = await send({ op: "size", identity: bound.identity, kind: bound.kind }, undefined);
|
|
620
|
+
if ("ok" in res)
|
|
621
|
+
return res;
|
|
622
|
+
return this.fileOutcome(res, abs, (o) => {
|
|
623
|
+
if (o.kind !== "stat")
|
|
624
|
+
return this.wrongOutcome("stat", o.kind, abs);
|
|
625
|
+
if (o.info === undefined)
|
|
626
|
+
return violation("without info for the size answer");
|
|
627
|
+
return ok(o.info.size);
|
|
628
|
+
});
|
|
629
|
+
},
|
|
630
|
+
readBytes: async (bound, max, signal) => {
|
|
631
|
+
const parts = [];
|
|
632
|
+
let got = 0;
|
|
633
|
+
let stray;
|
|
634
|
+
const res = await send({ op: "readBytes", identity: bound.identity, kind: bound.kind, max }, signal, (c) => {
|
|
635
|
+
if (c.kind !== "data") {
|
|
636
|
+
stray ??= c.kind;
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (c.data === undefined || c.data.length === 0)
|
|
640
|
+
return;
|
|
641
|
+
got += c.data.length;
|
|
642
|
+
if (got <= max)
|
|
643
|
+
parts.push(c.data);
|
|
644
|
+
});
|
|
645
|
+
if ("ok" in res)
|
|
646
|
+
return res;
|
|
647
|
+
return this.fileOutcome(res, abs, (o) => {
|
|
648
|
+
if (o.kind !== "read")
|
|
649
|
+
return this.wrongOutcome("read", o.kind, abs);
|
|
650
|
+
if (stray !== undefined)
|
|
651
|
+
return violation(`carrying a ${stray} chunk for a readBytes answer (only data chunks belong to it)`);
|
|
652
|
+
if (got > max)
|
|
653
|
+
return { ok: false, error: new FileError("invalid", `The held file is over the ${max}-byte read cap (${got} bytes or more arrived); it was not read`, abs) };
|
|
654
|
+
return ok(new Uint8Array(Buffer.concat(parts)));
|
|
655
|
+
});
|
|
656
|
+
},
|
|
657
|
+
list: async (bound, signal) => {
|
|
658
|
+
const res = await send({ op: "list", identity: bound.identity, kind: bound.kind }, signal);
|
|
659
|
+
if ("ok" in res)
|
|
660
|
+
return res;
|
|
661
|
+
return this.fileOutcome(res, abs, (o) => {
|
|
662
|
+
if (o.kind !== "stat")
|
|
663
|
+
return this.wrongOutcome("stat", o.kind, abs);
|
|
664
|
+
if (o.entries === undefined)
|
|
665
|
+
return violation("without entries for the list answer");
|
|
666
|
+
const entries = [];
|
|
667
|
+
for (const w of o.entries) {
|
|
668
|
+
const kind = w.kind === "dir" ? "directory" : w.kind === "symlink" ? "symlink" : w.kind === "file" ? "file" : undefined;
|
|
669
|
+
if (kind === undefined)
|
|
670
|
+
continue;
|
|
671
|
+
entries.push({ name: posix.basename(w.path), kind, size: w.size, mtimeMs: w.mtimeMs });
|
|
672
|
+
}
|
|
673
|
+
return ok(entries);
|
|
674
|
+
});
|
|
675
|
+
},
|
|
676
|
+
};
|
|
677
|
+
}
|
|
579
678
|
async readBinaryFile(p, abortSignal) {
|
|
580
679
|
const gated = await this.fsGate(p);
|
|
581
680
|
if (gated)
|
|
@@ -642,7 +741,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
642
741
|
return this.wrongOutcome("stat", o.kind, abs);
|
|
643
742
|
if (!o.entries)
|
|
644
743
|
return { ok: false, error: new FileError("unknown", "device returned a stat outcome without entries — protocol violation", abs) };
|
|
645
|
-
return ok(o.entries.map(toFileInfo));
|
|
744
|
+
return ok(o.entries.map((w) => toFileInfo(w, anchorUnder(DEVICE_PATH_FAMILY, abs, posix.basename(w.path)))));
|
|
646
745
|
});
|
|
647
746
|
}
|
|
648
747
|
async writeFile(p, content, abortSignal) {
|
|
@@ -738,8 +837,9 @@ function mergedEnv(taskEnv, commandEnv) {
|
|
|
738
837
|
function markTruncated(text, truncated) {
|
|
739
838
|
return truncated === true ? `${text}\n[output truncated by the device executor]` : text;
|
|
740
839
|
}
|
|
741
|
-
|
|
742
|
-
|
|
840
|
+
const DEVICE_PATH_FAMILY = { sep: posix.sep, isAbsolute: isDeviceAbsolutePath };
|
|
841
|
+
function toFileInfo(w, at) {
|
|
842
|
+
return { name: posix.basename(at), path: at, kind: w.kind === "dir" ? "directory" : w.kind === "symlink" ? "symlink" : "file", size: w.size, mtimeMs: w.mtimeMs };
|
|
743
843
|
}
|
|
744
844
|
function toWireExpectation(e) {
|
|
745
845
|
return {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* iterator MAY throw `RemoteExecutionError` mid-stream before an `exit` chunk (seam contract, OutputChunk).
|
|
21
21
|
*/
|
|
22
22
|
import { Sandbox, type SandboxOpts, type SandboxConnectOpts } from "e2b";
|
|
23
|
-
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type ExecResult, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
23
|
+
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type ExecResult, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
24
24
|
import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
|
|
25
25
|
import { type SandboxReadFloor } from "./sandbox-read-floor.js";
|
|
26
26
|
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
@@ -45,7 +45,7 @@ export interface RemoteContainerEnvConfig extends RemoteEnvObservers, LaneHomeCo
|
|
|
45
45
|
template?: string;
|
|
46
46
|
/** Sandbox lifetime in ms (E2B billing window). Default {@link DEFAULT_TIMEOUT_MS}. */
|
|
47
47
|
timeoutMs?: number;
|
|
48
|
-
/** Workspace root inside the VM;
|
|
48
|
+
/** Workspace root inside the VM; a relative path is anchored at it (`exec-path-law.ts`: anchored, never folded). Default {@link DEFAULT_MOUNT_PATH}. */
|
|
49
49
|
mountPath?: string;
|
|
50
50
|
/** Outbound network for the sandbox (clay: service needs external-network capability). Default `true`. */
|
|
51
51
|
allowInternetAccess?: boolean;
|
|
@@ -127,9 +127,12 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
127
127
|
private destroyed;
|
|
128
128
|
/** 家目录的座(主张在场 ⇒ 每只沙箱对证 · 否则建沙箱那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。 */
|
|
129
129
|
private readonly homeSeat;
|
|
130
|
-
/**
|
|
131
|
-
*
|
|
132
|
-
|
|
130
|
+
/**
|
|
131
|
+
* 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序(记住的拒 ⇒ 原样再答 · 一走在飞 ⇒ 等它 · 已连 ⇒ 当下的把手 · 否则建一只沙箱),并持有这只环境记住的拒 ——
|
|
132
|
+
* 记一次、此后每次连接 / 恢复原样回它(同一模板同一个答案:不再建沙箱、不再问)。两件立定的事实写它:家目录(沙箱答了而与主张不一致,或答的不是绝对路径;`env.home_unconfirmed`)
|
|
133
|
+
* 与恢复点的填充(换一台沙箱也是同一个答的拒:种子不是项目包、摘要不符、镜像没有 `tar`、镜像预置撞名 —— `FillOutcome.standing`;`env.sandbox_refused`)。
|
|
134
|
+
*/
|
|
135
|
+
private readonly seat;
|
|
133
136
|
/** In-flight connect/resume, memoized so concurrent lazy first-use OR resume provisions exactly one VM (no double-bill). `target` = the snapshot a resume
|
|
134
137
|
* restores (`undefined` = a fresh sandbox): {@link resumeVM} shares only a resume of the SAME snapshot — a connect for anything else is not the
|
|
135
138
|
* workspace it is asked to restore (it waits that one out, then releases the sandbox it left). */
|
|
@@ -223,8 +226,9 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
223
226
|
}>;
|
|
224
227
|
/**
|
|
225
228
|
* 家目录:座要问({@link LaneHomeSeat.asks}:主张在场 ⇒ 对证;没主张 ⇒ 量到绝对路径为止)⇒ 在这只沙箱里问一次 `$HOME`(前台 `commands.run`,与命令同一个
|
|
226
|
-
* 模板缺省用户、同一份沙箱 env),读数交座。返回这只沙箱的拒(
|
|
227
|
-
*
|
|
229
|
+
* 模板缺省用户、同一份沙箱 env),读数交座。返回这只沙箱的拒(拒句 = 同一只判官的句子),或 `undefined`(照用)。
|
|
230
|
+
* 沙箱答了的拒是立定的拒(`env.home_unconfirmed`,建连座记住它:同一模板同一个答案);没答上(非零退出 / RPC 失败 / 输出里没有标记行)⇒ 这一次不开、不记(`connect_failed`),
|
|
231
|
+
* 下一次重问;调用方中止 ⇒ `aborted`、不交座。
|
|
228
232
|
* 上界 = 控制面 RPC 的墙钟(`rpcTimeoutMs`:问一个环境变量,不是跑用户命令)。
|
|
229
233
|
*/
|
|
230
234
|
private homeVerdict;
|
|
@@ -295,6 +299,11 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
295
299
|
* 🔴 exit≠0 归 `unknown` 而不是 `not_found`(与本腿 `readLink` 那一格刻意分家,同 `posix-shell-fs` 的理由):
|
|
296
300
|
* 「叶不是软链」与「叶不存在」在这条命令上都是 exit 0 + 空 stdout,所以 exit≠0 一定不是「文件不在」。 */
|
|
297
301
|
canonicalChain(p: string, abortSignal?: AbortSignal): Promise<Result<SymlinkChain, FileError>>;
|
|
302
|
+
/** 绑定读(逐答重绑,Linux 读法)。本腿不并进 `posix-shell-fs` 基座(原生 SDK 腿),但脚本、读法与工厂与四条 shell 腿**是同一只**
|
|
303
|
+
* (`remote-shell.ts` `openBoundOverShell`),这里只多一条传输:{@link execInternal}(适配器自己的固定命令那一起动,与链脚本同一形)、数据界。
|
|
304
|
+
* 🔴 字节只经 stdout 的 base64 回来 —— `files.read` 按路径读,不能用;也不「拷进暂存件再按路径读」(同身份进程可换暂存件或它的祖先目录)。 */
|
|
305
|
+
openBound(p: string, abortSignal?: AbortSignal): Promise<Result<BoundFileObject, FileError>>;
|
|
306
|
+
private get boundLane();
|
|
298
307
|
canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
299
308
|
exists(p: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
|
|
300
309
|
createDir(p: string, options?: {
|
|
@@ -365,6 +374,8 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
365
374
|
private ensureConnected;
|
|
366
375
|
private fsReady;
|
|
367
376
|
private tempResult;
|
|
377
|
+
/** 提供方的条目 → `FileInfo`。`path` 取本环境的拼法(`at`:被问的那只路径 / 列目录时锚在它之下的条目),不取提供方回报的那一份
|
|
378
|
+
* —— 提供方可能已把 `..` 折掉,而执行缝路径律(`exec-path-law.ts`)要求条目名在交来的路径之下、能原样再交回来。 */
|
|
368
379
|
private toFileInfo;
|
|
369
380
|
private fileError;
|
|
370
381
|
/** A thrown provider error → this exec's error. The two cuts (aborted, the provider's own command deadline) are a command that RAN: they carry what it had
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { anchoredPath, anchorUnder, joinedPath } from "./exec-path-law.js";
|
|
2
3
|
import { Sandbox, CommandExitError, FileType } from "e2b";
|
|
3
4
|
import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
4
5
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
@@ -6,7 +7,8 @@ import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
|
|
|
6
7
|
import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, e2bFloorCommand, engineStart, } from "./sandbox-read-floor.js";
|
|
7
8
|
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
8
9
|
import { fileErrorFromExec } from "./remote-env-file-error.js";
|
|
9
|
-
import {
|
|
10
|
+
import { connectRefusal, createConnectSeat } from "./remote-env-connect-seat.js";
|
|
11
|
+
import { appendFileStaged, openBoundOverShell, readyUpload, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
|
|
10
12
|
import { buildLivenessCut, commandBoundsOf, firstBoundOf, laneLivenessOf, LIVENESS_MS_DEFAULT } from "../exec-bounds.js";
|
|
11
13
|
import { createCutError } from "../exec-cut.js";
|
|
12
14
|
import { BackgroundShellManager } from "./background-shell-support.js";
|
|
@@ -36,7 +38,22 @@ export class RemoteContainerExecutionEnv {
|
|
|
36
38
|
handle;
|
|
37
39
|
destroyed = false;
|
|
38
40
|
homeSeat;
|
|
39
|
-
|
|
41
|
+
seat = createConnectSeat({
|
|
42
|
+
live: () => (this.sbx !== undefined && !this.paused ? this.workspaceHandle() : undefined),
|
|
43
|
+
inFlight: () => this.connecting?.promise,
|
|
44
|
+
establish: (config) => {
|
|
45
|
+
if (this.paused)
|
|
46
|
+
return Promise.resolve({ ok: false, error: new RemoteExecutionError("connect_failed", "execution env is suspended (paused) — resumeVM(snapshotId) before use") });
|
|
47
|
+
const mine = { target: undefined, promise: this.doConnect(config) };
|
|
48
|
+
this.connecting = mine;
|
|
49
|
+
const settled = () => {
|
|
50
|
+
if (this.connecting === mine)
|
|
51
|
+
this.connecting = undefined;
|
|
52
|
+
};
|
|
53
|
+
void mine.promise.then(settled, settled);
|
|
54
|
+
return mine.promise;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
40
57
|
connecting;
|
|
41
58
|
activeCommands = 0;
|
|
42
59
|
paused = false;
|
|
@@ -155,20 +172,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
155
172
|
}
|
|
156
173
|
if (this.destroyed)
|
|
157
174
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
158
|
-
|
|
159
|
-
return { ok: false, error: this.connectRefusal };
|
|
160
|
-
if (this.paused)
|
|
161
|
-
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env is suspended (paused) — resumeVM(snapshotId) before use") };
|
|
162
|
-
if (this.sbx)
|
|
163
|
-
return ok(this.workspaceHandle());
|
|
164
|
-
if (this.connecting)
|
|
165
|
-
return this.connecting.promise;
|
|
166
|
-
const mine = { target: undefined, promise: this.doConnect(config) };
|
|
167
|
-
this.connecting = mine;
|
|
168
|
-
const r = await mine.promise;
|
|
169
|
-
if (!r.ok && this.connecting === mine)
|
|
170
|
-
this.connecting = undefined;
|
|
171
|
-
return r;
|
|
175
|
+
return this.seat.connect(config);
|
|
172
176
|
}
|
|
173
177
|
async doConnect(config) {
|
|
174
178
|
try {
|
|
@@ -199,9 +203,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
199
203
|
if (!filled.ok || this.destroyed) {
|
|
200
204
|
await sbx.kill().catch(() => { });
|
|
201
205
|
this.cfg.metrics?.inc("remote_env_connect_total", { provider: PROVIDER, result: "error" });
|
|
202
|
-
|
|
203
|
-
this.connectRefusal = filled.error;
|
|
204
|
-
return { ok: false, error: filled.ok ? new RemoteExecutionError("connect_failed", "execution env destroyed during connect") : filled.error };
|
|
206
|
+
return filled.ok ? { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") } : this.seat.answer(filled);
|
|
205
207
|
}
|
|
206
208
|
this.sbx = sbx;
|
|
207
209
|
this.paused = false;
|
|
@@ -255,8 +257,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
255
257
|
resumeVM(snapshotId, options) {
|
|
256
258
|
if (this.destroyed)
|
|
257
259
|
return Promise.resolve({ ok: false, error: new RemoteExecutionError("connect_failed", "env already destroyed") });
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
const held = this.seat.held;
|
|
261
|
+
if (held)
|
|
262
|
+
return Promise.resolve(held);
|
|
260
263
|
if (this.sbx && !this.paused && this.sbx.sandboxId === snapshotId)
|
|
261
264
|
return Promise.resolve(ok(this.workspaceHandle()));
|
|
262
265
|
const inFlight = this.connecting;
|
|
@@ -268,10 +271,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
268
271
|
if (this.connecting === mine)
|
|
269
272
|
this.connecting = undefined;
|
|
270
273
|
};
|
|
271
|
-
mine.promise.then(
|
|
272
|
-
if (!r.ok)
|
|
273
|
-
forget();
|
|
274
|
-
}, forget);
|
|
274
|
+
mine.promise.then(forget, forget);
|
|
275
275
|
return mine.promise;
|
|
276
276
|
}
|
|
277
277
|
async resumeWalk(inFlight, snapshotId, options) {
|
|
@@ -279,6 +279,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
279
279
|
await inFlight.promise;
|
|
280
280
|
if (this.destroyed)
|
|
281
281
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "env already destroyed") };
|
|
282
|
+
const held = this.seat.held;
|
|
283
|
+
if (held)
|
|
284
|
+
return held;
|
|
282
285
|
if (this.sbx && !this.paused && this.sbx.sandboxId === snapshotId)
|
|
283
286
|
return ok(this.workspaceHandle());
|
|
284
287
|
}
|
|
@@ -328,9 +331,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
328
331
|
if (!filled.ok) {
|
|
329
332
|
await this.rpc("sandbox.pause", (signal) => sbx.pause({ signal }), undefined, this.cfg.dataTimeoutMs).catch((e) => this.cfg.logger?.warn?.("remote_env_fill_refused_repause_failed", { sandboxId: sbx.sandboxId, error: errMsg(e) }));
|
|
330
333
|
this.cfg.metrics?.inc("remote_env_resume_total", { provider: PROVIDER, result: "error" });
|
|
331
|
-
|
|
332
|
-
this.connectRefusal = filled.error;
|
|
333
|
-
return { ok: false, error: filled.error };
|
|
334
|
+
return this.seat.answer(filled);
|
|
334
335
|
}
|
|
335
336
|
this.sbx = sbx;
|
|
336
337
|
this.paused = false;
|
|
@@ -382,10 +383,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
382
383
|
const verdict = this.homeSeat.settle(probe);
|
|
383
384
|
if (verdict === undefined)
|
|
384
385
|
return undefined;
|
|
385
|
-
|
|
386
|
-
if (verdict.answered)
|
|
387
|
-
this.connectRefusal = error;
|
|
388
|
-
return error;
|
|
386
|
+
return verdict.answered ? this.seat.answer(connectRefusal("home_unconfirmed", verdict.refusal)).error : new RemoteExecutionError("connect_failed", verdict.refusal);
|
|
389
387
|
}
|
|
390
388
|
fillAt(sbx, root, origin) {
|
|
391
389
|
return this.cfg.workspaceFill === undefined ? Promise.resolve({ ok: true }) : this.cfg.workspaceFill.fill(this.fillChannel(sbx), root, origin);
|
|
@@ -862,7 +860,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
862
860
|
return ok(this.resolve(p));
|
|
863
861
|
}
|
|
864
862
|
async joinPath(parts) {
|
|
865
|
-
return ok(path.posix
|
|
863
|
+
return ok(joinedPath(path.posix, parts));
|
|
866
864
|
}
|
|
867
865
|
async readTextFile(p, abortSignal) {
|
|
868
866
|
const sbx = await this.fsReady(p);
|
|
@@ -934,8 +932,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
934
932
|
if (!sbx.ok)
|
|
935
933
|
return sbx;
|
|
936
934
|
try {
|
|
937
|
-
const
|
|
938
|
-
|
|
935
|
+
const abs = this.resolve(p);
|
|
936
|
+
const info = await this.rpc("files.getInfo", (signal) => sbx.value.files.getInfo(abs, { signal }), abortSignal);
|
|
937
|
+
return ok(this.toFileInfo(info, abs));
|
|
939
938
|
}
|
|
940
939
|
catch (e) {
|
|
941
940
|
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
@@ -946,8 +945,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
946
945
|
if (!sbx.ok)
|
|
947
946
|
return sbx;
|
|
948
947
|
try {
|
|
949
|
-
const
|
|
950
|
-
|
|
948
|
+
const abs = this.resolve(p);
|
|
949
|
+
const entries = await this.rpc("files.list", (signal) => sbx.value.files.list(abs, { signal }), abortSignal);
|
|
950
|
+
return ok(entries.map((e) => this.toFileInfo(e, anchorUnder(path.posix, abs, e.name))));
|
|
951
951
|
}
|
|
952
952
|
catch (e) {
|
|
953
953
|
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
@@ -965,6 +965,19 @@ export class RemoteContainerExecutionEnv {
|
|
|
965
965
|
async canonicalChain(p, abortSignal) {
|
|
966
966
|
return runSymlinkChain(this.resolve(p), (cmd) => this.execInternal(cmd, { abortSignal }));
|
|
967
967
|
}
|
|
968
|
+
async openBound(p, abortSignal) {
|
|
969
|
+
return openBoundOverShell(this.resolve(p), this.boundLane, abortSignal);
|
|
970
|
+
}
|
|
971
|
+
get boundLane() {
|
|
972
|
+
return {
|
|
973
|
+
run: async (cmd, _cap, abortSignal) => {
|
|
974
|
+
const r = await this.execInternal(cmd, { cwd: "/", timeout: this.cfg.dataTimeoutMs / 1000, ...(abortSignal !== undefined ? { abortSignal } : {}) });
|
|
975
|
+
return r.ok ? { ok: true, value: { stdout: Buffer.from(r.value.stdout, "utf8"), stderr: r.value.stderr, exitCode: r.value.exitCode } } : r;
|
|
976
|
+
},
|
|
977
|
+
payload: "base64",
|
|
978
|
+
boundSec: this.cfg.dataTimeoutMs / 1000,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
968
981
|
async canonicalPath(p, abortSignal) {
|
|
969
982
|
const abs = this.resolve(p);
|
|
970
983
|
const r = await this.execInternal(`realpath -- ${shellQuote(abs)}`, { abortSignal });
|
|
@@ -1044,7 +1057,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
1044
1057
|
return this.tempResult(r, "mktemp");
|
|
1045
1058
|
}
|
|
1046
1059
|
resolve(p) {
|
|
1047
|
-
return
|
|
1060
|
+
return anchoredPath(path.posix, this.cwd, p);
|
|
1048
1061
|
}
|
|
1049
1062
|
async rpc(label, op, userSignal, timeoutMs = this.cfg.rpcTimeoutMs) {
|
|
1050
1063
|
const deadline = new AbortController();
|
|
@@ -1163,11 +1176,11 @@ export class RemoteContainerExecutionEnv {
|
|
|
1163
1176
|
return { ok: false, error: new FileError("unknown", r.value.stderr.trim() || `${op} failed`) };
|
|
1164
1177
|
return ok(r.value.stdout.trim());
|
|
1165
1178
|
}
|
|
1166
|
-
toFileInfo(e) {
|
|
1179
|
+
toFileInfo(e, at) {
|
|
1167
1180
|
const kind = e.symlinkTarget ? "symlink" : e.type === FileType.DIR ? "directory" : "file";
|
|
1168
1181
|
return {
|
|
1169
1182
|
name: e.name,
|
|
1170
|
-
path:
|
|
1183
|
+
path: at,
|
|
1171
1184
|
kind,
|
|
1172
1185
|
size: e.size ?? 0,
|
|
1173
1186
|
mtimeMs: e.modifiedTime ? e.modifiedTime.getTime() : 0,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { FileError, RemoteExecutionError } from "@sema-agent/core";
|
|
2
|
+
import { isExecutionEnvRefusalCode } from "../execution-env-refusal.js";
|
|
3
|
+
function sayEnvNotOpened(code) {
|
|
4
|
+
return code === "connect_failed" || isExecutionEnvRefusalCode(code);
|
|
5
|
+
}
|
|
2
6
|
function neverOpened(e) {
|
|
3
|
-
if (e.code
|
|
7
|
+
if (sayEnvNotOpened(e.code))
|
|
4
8
|
return true;
|
|
5
9
|
const cause = e.cause;
|
|
6
|
-
return cause instanceof RemoteExecutionError && cause.code
|
|
10
|
+
return cause instanceof RemoteExecutionError && sayEnvNotOpened(cause.code);
|
|
7
11
|
}
|
|
8
12
|
export function fileErrorFromExec(e, path) {
|
|
9
13
|
const code = e.code === "aborted" ? "aborted" : neverOpened(e) ? "target_unavailable" : "unknown";
|