@fitlab-ai/agent-infra 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +18 -10
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +1 -16
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +1 -4
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +11 -519
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +44 -8
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +67 -24
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +16 -9
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +0 -21
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +0 -5
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +11 -696
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +41 -9
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +50 -26
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -15,7 +15,7 @@ import { detectEngine, ensureDocker } from '../engine.js';
|
|
|
15
15
|
import { commandForEngine, execEngine, run, runEngine, runOk, runOkEngine, runSafe, runSafeEngine, runVerboseEngine } from '../shell.js';
|
|
16
16
|
import { parseSandboxWorkspaceIdentity, resolveSandboxTarget, sameSandboxWorkspaceIdentity } from '../workspace-identity.js';
|
|
17
17
|
import { createSandboxCapabilityPlan, runSandboxHooks, runBoundedSandboxHookCommand } from '../agent-client-reconciler.js';
|
|
18
|
-
import {
|
|
18
|
+
import { tmpfsSeedStagingPath, tmpfsSeedTargetPath, toolConfigDirCandidates } from '../tools.js';
|
|
19
19
|
import { assertFreshSandboxReady, hydrateTmpfsSeedEntries, prepareTmpfsMounts, startSandboxControlBroker } from '../recovery.js';
|
|
20
20
|
import { acquireSandboxControlReplacement, assertSandboxControlCutoverSnapshot, beginSandboxControlReplacement, captureSandboxControlCutoverSnapshot, commitSandboxControlReplacement, quiesceSandboxControlRoot, recoverSandboxControlReplacement, readSandboxControlManifest } from '../control/lifecycle.js';
|
|
21
21
|
import { atomicWriteJson } from '../control/state.js';
|
|
@@ -26,7 +26,6 @@ import { materializeSandboxGitMetadata } from '../git-metadata.js';
|
|
|
26
26
|
import { assertSandboxTaskSource, finalizeSandboxControlManifest, materializeSandboxControl, materializeSandboxWorkspaceView, prepareSandboxWorkspaceMountTargets, prepareSandboxCompletedTaskMountSource, sandboxControlPaths, } from '../workspace-view.js';
|
|
27
27
|
import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.js';
|
|
28
28
|
import { validateSelinuxDisableEnv } from '../engines/selinux.js';
|
|
29
|
-
import { captureSandboxAuthority, commandForSandboxAuthority, verifySandboxAuthority } from '../engines/authority.js';
|
|
30
29
|
import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.js';
|
|
31
30
|
import { ensureSandboxDiscoveryReadmes } from '../readme-scaffold.js';
|
|
32
31
|
import { removeDirRecursive } from '../../remove-dir.js';
|
|
@@ -619,14 +618,6 @@ function runEngineTaskCommand(engine, cmd, args, opts = {}) {
|
|
|
619
618
|
const command = commandForEngine(engine, cmd, args);
|
|
620
619
|
return runTaskCommand(command.cmd, command.args, opts);
|
|
621
620
|
}
|
|
622
|
-
function runSandboxAuthorityTaskCommand(authority, cmd, args, opts = {}) {
|
|
623
|
-
const command = commandForSandboxAuthority(authority, cmd, args);
|
|
624
|
-
return runTaskCommand(command.cmd, command.args, opts);
|
|
625
|
-
}
|
|
626
|
-
function runSandboxAuthoritySafeCommand(authority, args) {
|
|
627
|
-
const command = commandForSandboxAuthority(authority, 'docker', args);
|
|
628
|
-
return runSafe(command.cmd, command.args);
|
|
629
|
-
}
|
|
630
621
|
// `docker run` args for mounting a tool's containerMount as an in-container
|
|
631
622
|
// tmpfs. containerMount is an in-container path, so it is NOT engine-converted.
|
|
632
623
|
export function buildTmpfsRunArgs(containerMount, tmpfs) {
|
|
@@ -923,17 +914,28 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
923
914
|
const previousManifest = fs.existsSync(controlPaths.manifestPath)
|
|
924
915
|
? readSandboxControlManifest(controlPaths.manifestPath)
|
|
925
916
|
: null;
|
|
926
|
-
if (hadExistingControlRoot) {
|
|
927
|
-
await quiesceSandboxControlRoot(controlPaths.root);
|
|
928
|
-
}
|
|
929
|
-
const previousCutoverSnapshot = hadExistingControlRoot
|
|
930
|
-
? captureSandboxControlCutoverSnapshot(controlPaths.root)
|
|
931
|
-
: null;
|
|
932
917
|
const existing = runSafeEngine(engine, 'docker', ['ps', '-a', '--format', '{{.Names}}']).split('\n').filter(Boolean);
|
|
933
918
|
const matchedContainers = containerNameCandidates(effectiveConfig, branch)
|
|
934
919
|
.filter((name) => existing.includes(name));
|
|
920
|
+
const oldContainer = previousManifest ? await inspectSandboxControlContainer(previousManifest) : null;
|
|
921
|
+
if (oldContainer?.state === 'unknown') {
|
|
922
|
+
throw new Error(`SANDBOX_CONTROL_CONTAINER_UNKNOWN: ${oldContainer.reason}`);
|
|
923
|
+
}
|
|
924
|
+
if (previousManifest && (previousManifest.branch !== branch
|
|
925
|
+
|| previousManifest.mode !== target.workspace.mode
|
|
926
|
+
|| previousManifest.taskId !== (target.workspace.mode === 'task-bound' ? target.workspace.taskId : null)
|
|
927
|
+
|| fs.realpathSync.native(previousManifest.worktreeRoot) !== fs.realpathSync.native(worktree))) {
|
|
928
|
+
throw new Error('SANDBOX_WORKSPACE_IDENTITY_CONFLICT: recorded sandbox binding does not match the requested worktree');
|
|
929
|
+
}
|
|
930
|
+
const removalIds = [];
|
|
935
931
|
if (matchedContainers.length > 0) {
|
|
936
932
|
for (const name of matchedContainers) {
|
|
933
|
+
const id = runSafeEngine(engine, 'docker', ['inspect', '--format', '{{.Id}}', name]).trim();
|
|
934
|
+
if (!/^[a-f0-9]{64}$/u.test(id)
|
|
935
|
+
|| (previousManifest && id !== previousManifest.containerIdentity.id)) {
|
|
936
|
+
throw new Error('SANDBOX_CONTROL_CONTAINER_IDENTITY_MISMATCH');
|
|
937
|
+
}
|
|
938
|
+
removalIds.push(id);
|
|
937
939
|
const rawLabels = runSafeEngine(engine, 'docker', [
|
|
938
940
|
'inspect', '--format', '{{json .Config.Labels}}', name
|
|
939
941
|
]).trim();
|
|
@@ -963,19 +965,9 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
963
965
|
+ `Run 'ai sandbox start --recreate ${recoveryTarget}' on the host, then retry.`);
|
|
964
966
|
}
|
|
965
967
|
}
|
|
966
|
-
message('Removing old container instance...');
|
|
967
|
-
for (const name of matchedContainers) {
|
|
968
|
-
runSafeEngine(engine, 'docker', ['stop', name]);
|
|
969
|
-
runSafeEngine(engine, 'docker', ['rm', name]);
|
|
970
|
-
}
|
|
971
968
|
}
|
|
972
|
-
if (
|
|
973
|
-
|
|
974
|
-
if (oldContainer.state !== 'absent') {
|
|
975
|
-
throw new Error(oldContainer.state === 'unknown'
|
|
976
|
-
? `SANDBOX_CONTROL_CONTAINER_UNKNOWN: ${oldContainer.reason}`
|
|
977
|
-
: 'SANDBOX_CONTROL_CONTAINER_STILL_EXISTS');
|
|
978
|
-
}
|
|
969
|
+
if (oldContainer?.state === 'found' && !removalIds.includes(oldContainer.id)) {
|
|
970
|
+
throw new Error('SANDBOX_CONTROL_CONTAINER_IDENTITY_MISMATCH');
|
|
979
971
|
}
|
|
980
972
|
const aliasesFile = ensureSandboxAliasesFile(effectiveConfig.home, capabilityPlan.aliases);
|
|
981
973
|
if (aliasesFile.created) {
|
|
@@ -1041,8 +1033,20 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1041
1033
|
? prepareSandboxCompletedTaskMountSource(effectiveConfig.repoRoot, target.workspace.taskId)
|
|
1042
1034
|
: null;
|
|
1043
1035
|
prepareSandboxWorkspaceMountTargets(effectiveConfig.repoRoot);
|
|
1044
|
-
if (
|
|
1036
|
+
if (hadExistingControlRoot)
|
|
1037
|
+
await quiesceSandboxControlRoot(controlPaths.root);
|
|
1038
|
+
const previousCutoverSnapshot = hadExistingControlRoot
|
|
1039
|
+
? captureSandboxControlCutoverSnapshot(controlPaths.root)
|
|
1040
|
+
: null;
|
|
1041
|
+
if (previousCutoverSnapshot)
|
|
1045
1042
|
assertSandboxControlCutoverSnapshot(previousCutoverSnapshot);
|
|
1043
|
+
if (removalIds.length > 0)
|
|
1044
|
+
message('Removing old container instance...');
|
|
1045
|
+
for (const id of removalIds) {
|
|
1046
|
+
runEngineTaskCommand(engine, 'docker', ['stop', id]);
|
|
1047
|
+
runEngineTaskCommand(engine, 'docker', ['rm', id]);
|
|
1048
|
+
}
|
|
1049
|
+
if (previousCutoverSnapshot) {
|
|
1046
1050
|
if (previousManifest) {
|
|
1047
1051
|
const finalOldContainer = await inspectSandboxControlContainer(previousManifest);
|
|
1048
1052
|
if (finalOldContainer.state !== 'absent') {
|
|
@@ -1133,11 +1137,8 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1133
1137
|
const hostTz = detectHostTimezone();
|
|
1134
1138
|
const tzFlags = hostTz ? ['-e', `TZ=${hostTz}`] : [];
|
|
1135
1139
|
let createdContainerRef = null;
|
|
1136
|
-
let creationAuthority = null;
|
|
1137
1140
|
try {
|
|
1138
|
-
|
|
1139
|
-
commandForSandboxAuthority(creationAuthority, 'docker');
|
|
1140
|
-
const dockerRunId = runSandboxAuthorityTaskCommand(creationAuthority, 'docker', [
|
|
1141
|
+
const dockerRunId = runEngineTaskCommand(engine, 'docker', [
|
|
1141
1142
|
'run',
|
|
1142
1143
|
'-d',
|
|
1143
1144
|
'--init',
|
|
@@ -1196,12 +1197,12 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1196
1197
|
effectiveConfig.imageName
|
|
1197
1198
|
]);
|
|
1198
1199
|
createdContainerRef = dockerRunId.trim();
|
|
1199
|
-
const containerId =
|
|
1200
|
+
const containerId = runEngineTaskCommand(engine, 'docker', [
|
|
1200
1201
|
'inspect', '--format', '{{.Id}}', dockerRunId.trim()
|
|
1201
1202
|
]).trim();
|
|
1202
|
-
if (
|
|
1203
|
+
if (!/^[a-f0-9]{64}$/u.test(containerId))
|
|
1203
1204
|
throw new Error('SANDBOX_CONTROL_CONTAINER_ID_INVALID');
|
|
1204
|
-
const rawContainerLabels =
|
|
1205
|
+
const rawContainerLabels = runEngineTaskCommand(engine, 'docker', [
|
|
1205
1206
|
'inspect', '--format', '{{json .Config.Labels}}', containerId
|
|
1206
1207
|
]).trim();
|
|
1207
1208
|
let inspectedLabels;
|
|
@@ -1228,18 +1229,10 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1228
1229
|
if (labels[key] !== expected)
|
|
1229
1230
|
throw new Error('SANDBOX_CONTROL_CONTAINER_IDENTITY_MISMATCH');
|
|
1230
1231
|
}
|
|
1231
|
-
const authorityEvidence = captureSandboxAuthority(engine, {
|
|
1232
|
-
route: creationAuthority,
|
|
1233
|
-
lockDomain: creationAuthority.lockDomain
|
|
1234
|
-
});
|
|
1235
|
-
if (verifySandboxAuthority(creationAuthority, authorityEvidence).state !== 'verified') {
|
|
1236
|
-
throw new Error('SANDBOX_AUTHORITY_DRIFT_DURING_CREATE');
|
|
1237
|
-
}
|
|
1238
1232
|
finalizeSandboxControlManifest(control, {
|
|
1239
1233
|
engine,
|
|
1240
1234
|
id: containerId,
|
|
1241
|
-
labels: expectedLabels
|
|
1242
|
-
authorityEvidence
|
|
1235
|
+
labels: expectedLabels
|
|
1243
1236
|
});
|
|
1244
1237
|
replacementLease.clearQuiescing();
|
|
1245
1238
|
await startSandboxControlBroker(effectiveConfig.repoRoot, control.manifestPath);
|
|
@@ -1251,14 +1244,8 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1251
1244
|
}
|
|
1252
1245
|
catch (error) {
|
|
1253
1246
|
if (createdContainerRef) {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
runSandboxAuthoritySafeCommand(creationAuthority, ['rm', createdContainerRef]);
|
|
1257
|
-
}
|
|
1258
|
-
else {
|
|
1259
|
-
runSafeEngine(engine, 'docker', ['stop', createdContainerRef]);
|
|
1260
|
-
runSafeEngine(engine, 'docker', ['rm', createdContainerRef]);
|
|
1261
|
-
}
|
|
1247
|
+
runSafeEngine(engine, 'docker', ['stop', createdContainerRef]);
|
|
1248
|
+
runSafeEngine(engine, 'docker', ['rm', createdContainerRef]);
|
|
1262
1249
|
}
|
|
1263
1250
|
if (!hadExistingControlRoot)
|
|
1264
1251
|
removeDirRecursive(control.root);
|
|
@@ -2,8 +2,6 @@ import { spawnSync } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { runSafeEngine, runVerboseEngine } from '../shell.js';
|
|
5
|
-
import { resolveTaskBranch } from '../task-resolver.js';
|
|
6
|
-
import { isRemovedHashShortIdInput } from '../../task/short-id.js';
|
|
7
5
|
import { parseSandboxWorkspaceIdentity } from '../workspace-identity.js';
|
|
8
6
|
import { resolveProjectTaskWorkspaceRoot } from '../../task/workspace-root.js';
|
|
9
7
|
export function containerListFormat() {
|
|
@@ -150,22 +148,6 @@ export function resolveTaskShortRef(arg, ctx) {
|
|
|
150
148
|
`bare N resolves only via the registry (not by row position in 'ai sandbox ls'); ` +
|
|
151
149
|
`use a task short id (e.g. 'ai sandbox exec 11'), a TASK-id, or a branch name.`);
|
|
152
150
|
}
|
|
153
|
-
/**
|
|
154
|
-
* Resolve a sandbox command argument (`<branch | TASK-id | N>`) to a
|
|
155
|
-
* branch name, mirroring `ai sandbox exec` so that `start` and `exec` share one
|
|
156
|
-
* input contract. Short refs go through the registry-only resolver (which throws
|
|
157
|
-
* an actionable error on a miss); everything else flows through resolveTaskBranch
|
|
158
|
-
* (plain branch names pass through unchanged, TASK-ids resolve via task.md).
|
|
159
|
-
* Callers still run assertValidBranchName on the result.
|
|
160
|
-
*/
|
|
161
|
-
export function resolveBranchArg(arg, ctx) {
|
|
162
|
-
if (isRemovedHashShortIdInput(arg)) {
|
|
163
|
-
throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
|
|
164
|
-
}
|
|
165
|
-
return isTaskShortRef(arg)
|
|
166
|
-
? resolveTaskShortRef(arg, ctx)
|
|
167
|
-
: resolveTaskBranch(arg, ctx.repoRoot);
|
|
168
|
-
}
|
|
169
151
|
/**
|
|
170
152
|
* Pick the sandbox container row whose name matches one of the candidate
|
|
171
153
|
* container names (covers both the '..' and legacy '-' branch sanitizations).
|
|
@@ -6,11 +6,10 @@ import { fetchSandboxRows, selectSandboxContainer, } from './list-running.js';
|
|
|
6
6
|
import { resolveSandboxTarget } from '../workspace-identity.js';
|
|
7
7
|
const USAGE = `Usage: ai sandbox start [--recreate] <branch | TASK-id | N>
|
|
8
8
|
|
|
9
|
-
Start an existing sandbox
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
state. --recreate replaces the existing container even when it is healthy.`;
|
|
9
|
+
Start or check an existing sandbox without replacing it. A missing container
|
|
10
|
+
leaves its task and control data intact. --recreate explicitly restores a missing
|
|
11
|
+
container from its existing worktree or replaces an existing container, preserving
|
|
12
|
+
the worktree and host-managed data.`;
|
|
14
13
|
export function parseStartArgs(args) {
|
|
15
14
|
let recreate = false;
|
|
16
15
|
let help = false;
|
|
@@ -52,15 +51,15 @@ export async function start(args) {
|
|
|
52
51
|
assertValidBranchName(branch);
|
|
53
52
|
const { running, nonRunning } = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config));
|
|
54
53
|
const found = selectSandboxContainer([...running, ...nonRunning], containerNameCandidates(config, branch));
|
|
55
|
-
if (!found) {
|
|
56
|
-
throw new Error(`No sandbox container for branch '${branch}'.
|
|
54
|
+
if (!found && !parsed.recreate) {
|
|
55
|
+
throw new Error(`No sandbox container for branch '${branch}'. Existing task and control data were preserved; use --recreate to explicitly restore the container.`);
|
|
57
56
|
}
|
|
58
57
|
const ready = await ensureSandboxReady({
|
|
59
58
|
config,
|
|
60
59
|
engine,
|
|
61
60
|
branch,
|
|
62
61
|
workspace: target.workspace,
|
|
63
|
-
row: found,
|
|
62
|
+
row: found ?? null,
|
|
64
63
|
allowRecreate: parsed.recreate,
|
|
65
64
|
forceRecreate: parsed.recreate,
|
|
66
65
|
recreate: async () => {
|
|
@@ -42,15 +42,9 @@ export function containerName(config, branch) {
|
|
|
42
42
|
export function containerNameCandidates(config, branch) {
|
|
43
43
|
return safeNameCandidates(branch).map((name) => `${config.containerPrefix}-${name}`);
|
|
44
44
|
}
|
|
45
|
-
export function worktreeDir(config, branch) {
|
|
46
|
-
return hostJoin(config.worktreeBase, sanitizeBranchName(branch));
|
|
47
|
-
}
|
|
48
45
|
export function worktreeDirCandidates(config, branch) {
|
|
49
46
|
return safeNameCandidates(branch).map((name) => hostJoin(config.worktreeBase, name));
|
|
50
47
|
}
|
|
51
|
-
export function shareDir(config) {
|
|
52
|
-
return config.shareBase;
|
|
53
|
-
}
|
|
54
48
|
export function shareCommonDir(config) {
|
|
55
49
|
return hostJoin(config.shareBase, 'common');
|
|
56
50
|
}
|
|
@@ -155,7 +155,6 @@ function exchangeSandboxControl(request, params) {
|
|
|
155
155
|
const statusDir = params.statusDir ?? process.env.AGENT_INFRA_CONTROL_STATUS_DIR ?? '/run/agent-infra/control-status';
|
|
156
156
|
const taskViewEffect = taskViewEffectForRequest(request);
|
|
157
157
|
const hostGeneration = preflight(statusDir, taskViewEffect);
|
|
158
|
-
const identityPath = path.join(statusDir, 'identity.json');
|
|
159
158
|
if (fs.existsSync(statusDir)) {
|
|
160
159
|
const identity = readSandboxControlIdentitySentinel(statusDir);
|
|
161
160
|
const requestTask = canonicalRequestTask(request);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { runProbe } from '../shell.js';
|
|
2
|
-
import { captureSandboxAuthority, isSandboxAuthorityEvidence, verifySandboxAuthority } from '../engines/authority.js';
|
|
3
2
|
import { discoverExactContainer } from '../engines/docker-exact-discovery.js';
|
|
4
3
|
export function classifySandboxContainerInspection(expected, inspection) {
|
|
5
4
|
if ('notFound' in inspection)
|
|
@@ -26,24 +25,10 @@ export function classifySandboxContainerInspection(expected, inspection) {
|
|
|
26
25
|
};
|
|
27
26
|
}
|
|
28
27
|
export async function inspectSandboxControlContainer(manifest, options = {}) {
|
|
29
|
-
if (!isSandboxAuthorityEvidence(manifest.authorityEvidence)) {
|
|
30
|
-
return { state: 'unknown', reason: 'SANDBOX_AUTHORITY_EVIDENCE_MISSING' };
|
|
31
|
-
}
|
|
32
28
|
try {
|
|
33
|
-
const authority = captureSandboxAuthority(manifest.engine, {
|
|
34
|
-
probe: options.probe,
|
|
35
|
-
timeoutMs: options.timeoutMs,
|
|
36
|
-
lockDomain: manifest.authorityEvidence.lockDomain,
|
|
37
|
-
route: manifest.authorityEvidence
|
|
38
|
-
});
|
|
39
|
-
const authorityState = verifySandboxAuthority(manifest.authorityEvidence, authority);
|
|
40
|
-
if (authorityState.state !== 'verified') {
|
|
41
|
-
return { state: 'unknown', reason: authorityState.reason ?? 'SANDBOX_AUTHORITY_UNAVAILABLE' };
|
|
42
|
-
}
|
|
43
29
|
const discovered = discoverExactContainer(manifest.engine, manifest.containerIdentity.id, {
|
|
44
30
|
probe: options.probe,
|
|
45
|
-
timeoutMs: options.timeoutMs
|
|
46
|
-
authority: manifest.authorityEvidence
|
|
31
|
+
timeoutMs: options.timeoutMs
|
|
47
32
|
});
|
|
48
33
|
if (discovered.state === 'absent')
|
|
49
34
|
return { state: 'absent', id: discovered.id };
|
|
@@ -357,8 +357,4 @@ function readJsonExecution(filePath) {
|
|
|
357
357
|
throw new Error('SANDBOX_CONTROL_EXECUTION_INVALID');
|
|
358
358
|
return value;
|
|
359
359
|
}
|
|
360
|
-
export function disconnectExecutor(child) {
|
|
361
|
-
if (child.connected)
|
|
362
|
-
child.disconnect();
|
|
363
|
-
}
|
|
364
360
|
//# sourceMappingURL=executor.js.map
|
|
@@ -97,11 +97,4 @@ export function validateSandboxControlIdentity(params) {
|
|
|
97
97
|
}
|
|
98
98
|
return { state: 'valid', sentinel };
|
|
99
99
|
}
|
|
100
|
-
export function assertSandboxControlIdentity(params) {
|
|
101
|
-
const result = validateSandboxControlIdentity(params);
|
|
102
|
-
if (result.state !== 'valid' || !result.sentinel) {
|
|
103
|
-
throw new Error(`SANDBOX_CONTROL_IDENTITY_${result.state.replaceAll('-', '_').toUpperCase()}`);
|
|
104
|
-
}
|
|
105
|
-
return result.sentinel;
|
|
106
|
-
}
|
|
107
100
|
//# sourceMappingURL=identity-sentinel.js.map
|
|
@@ -8,7 +8,6 @@ import { getProcessIdentityState, getProcessStartTime } from '../../server/proce
|
|
|
8
8
|
import { DEFAULT_SANDBOX_CONTROL_TIMING } from './protocol.js';
|
|
9
9
|
import { inspectSandboxControlContainer } from './container-identity.js';
|
|
10
10
|
import { acquireSandboxResourceLock, resolveSandboxLockNamespace } from './native-file-lock.js';
|
|
11
|
-
import { isSandboxAuthorityEvidence } from '../engines/authority.js';
|
|
12
11
|
import { validateSandboxControlIdentity } from './identity-sentinel.js';
|
|
13
12
|
import { parseSandboxControlStatus, readExecution, terminateSandboxControlExecution } from './state.js';
|
|
14
13
|
const DEFAULT_QUIESCE_TIMEOUT_MS = DEFAULT_SANDBOX_CONTROL_TIMING.quiesceDeadlineMs;
|
|
@@ -58,7 +57,16 @@ function removalJournalDomain(lockDomain, create = true) {
|
|
|
58
57
|
return domain;
|
|
59
58
|
}
|
|
60
59
|
function removalJournalPath(manifest) {
|
|
61
|
-
|
|
60
|
+
const digest = removalCarrierDigest(manifest.engine, manifest.containerIdentity.id, manifest.generation);
|
|
61
|
+
// Existing interrupted removals retain their original native lock namespace.
|
|
62
|
+
const existing = listSandboxRemovalJournals({ project: manifest.project, branch: manifest.branch })
|
|
63
|
+
.filter((record) => record.carrierIdentityDigest === digest);
|
|
64
|
+
if (existing.length > 1)
|
|
65
|
+
throw new Error('SANDBOX_CONTROL_REMOVAL_JOURNAL_IDENTITY_MISMATCH');
|
|
66
|
+
if (existing[0])
|
|
67
|
+
return removalJournalPathForRecord(existing[0]);
|
|
68
|
+
const namespace = resolveSandboxLockNamespace('sandbox-removal-journal');
|
|
69
|
+
return path.join(removalJournalDomain(namespace.lockDomain), `${digest}.json`);
|
|
62
70
|
}
|
|
63
71
|
function removalJournalPathForRecord(record) {
|
|
64
72
|
return path.join(removalJournalDomain(record.lockDomain, false), `${record.carrierIdentityDigest}.json`);
|
|
@@ -101,8 +109,11 @@ function parseRemovalJournal(raw) {
|
|
|
101
109
|
catch {
|
|
102
110
|
throw new Error('SANDBOX_CONTROL_REMOVAL_JOURNAL_INVALID');
|
|
103
111
|
}
|
|
112
|
+
// TODO(compat): Remove obsolete-field normalization after pre-simplification removal journals drain.
|
|
113
|
+
if (isRecord(value))
|
|
114
|
+
delete value.authorityFingerprint;
|
|
104
115
|
if (!isRecord(value) || !hasExactKeys(value, [
|
|
105
|
-
'
|
|
116
|
+
'carrierIdentityDigest', 'containerId', 'engine', 'expectedOldJournalRevision',
|
|
106
117
|
'generation', 'handoffId', 'lockDomain', 'newOperation', 'oldOperation', 'operation', 'owner', 'phase',
|
|
107
118
|
'recordedAt', 'revision', 'target', 'transitionId', 'version'
|
|
108
119
|
]) || !isRecord(value.owner) || !hasExactKeys(value.owner, ['leaseNonce', 'pid', 'startTime'])
|
|
@@ -117,7 +128,6 @@ function parseRemovalJournal(raw) {
|
|
|
117
128
|
|| typeof value.engine !== 'string' || value.engine.length === 0
|
|
118
129
|
|| typeof value.containerId !== 'string' || value.containerId.length === 0
|
|
119
130
|
|| typeof value.generation !== 'string' || value.generation.length === 0
|
|
120
|
-
|| typeof value.authorityFingerprint !== 'string' || !/^[a-f0-9]{64}$/u.test(value.authorityFingerprint)
|
|
121
131
|
|| typeof value.carrierIdentityDigest !== 'string' || !/^[a-f0-9]{64}$/u.test(value.carrierIdentityDigest)
|
|
122
132
|
|| typeof value.lockDomain !== 'string' || !/^[a-f0-9]{64}$/u.test(value.lockDomain)
|
|
123
133
|
|| !Number.isSafeInteger(value.owner.pid) || value.owner.pid <= 0
|
|
@@ -160,7 +170,6 @@ function parseRemovalJournal(raw) {
|
|
|
160
170
|
engine: value.engine,
|
|
161
171
|
containerId: value.containerId,
|
|
162
172
|
generation: value.generation,
|
|
163
|
-
authorityFingerprint: value.authorityFingerprint,
|
|
164
173
|
carrierIdentityDigest: value.carrierIdentityDigest,
|
|
165
174
|
lockDomain: value.lockDomain,
|
|
166
175
|
owner: {
|
|
@@ -342,9 +351,7 @@ function startRemovalJournal(manifest, options) {
|
|
|
342
351
|
const target = removalJournalPath(manifest);
|
|
343
352
|
const existing = readRemovalJournalAt(target);
|
|
344
353
|
if (existing && (existing.engine !== manifest.engine || existing.containerId !== manifest.containerIdentity.id
|
|
345
|
-
|| existing.generation !== manifest.generation
|
|
346
|
-
|| existing.authorityFingerprint !== manifest.authorityEvidence.authorityFingerprint
|
|
347
|
-
|| existing.lockDomain !== manifest.authorityEvidence.lockDomain)) {
|
|
354
|
+
|| existing.generation !== manifest.generation)) {
|
|
348
355
|
throw new Error('SANDBOX_CONTROL_REMOVAL_JOURNAL_IDENTITY_MISMATCH');
|
|
349
356
|
}
|
|
350
357
|
const targetCommit = options.target ?? existing?.target ?? defaultRemovalTarget(manifest);
|
|
@@ -371,9 +378,8 @@ function startRemovalJournal(manifest, options) {
|
|
|
371
378
|
engine: manifest.engine,
|
|
372
379
|
containerId: manifest.containerIdentity.id,
|
|
373
380
|
generation: manifest.generation,
|
|
374
|
-
authorityFingerprint: manifest.authorityEvidence.authorityFingerprint,
|
|
375
381
|
carrierIdentityDigest: removalCarrierDigest(manifest.engine, manifest.containerIdentity.id, manifest.generation),
|
|
376
|
-
lockDomain:
|
|
382
|
+
lockDomain: existing?.lockDomain ?? resolveSandboxLockNamespace('sandbox-removal-journal').lockDomain,
|
|
377
383
|
owner: { pid: process.pid, startTime, leaseNonce: randomUUID() },
|
|
378
384
|
target: targetCommit
|
|
379
385
|
};
|
|
@@ -440,17 +446,6 @@ export function advanceSandboxRemovalJournalPhase(journal, phase, options = {})
|
|
|
440
446
|
ownedLock?.release();
|
|
441
447
|
}
|
|
442
448
|
}
|
|
443
|
-
export function advanceSandboxRemovalJournalToPhase(journal, phase, resourceLock) {
|
|
444
|
-
let current = journal;
|
|
445
|
-
while (phaseIndex(current.phase) < phaseIndex(phase)) {
|
|
446
|
-
const next = current.phase === 'target-committed' && phase === 'container-absent'
|
|
447
|
-
? phase : SANDBOX_REMOVAL_JOURNAL_PHASES[phaseIndex(current.phase) + 1];
|
|
448
|
-
if (!next)
|
|
449
|
-
throw new Error('SANDBOX_CONTROL_REMOVAL_PHASE_TRANSITION_INVALID');
|
|
450
|
-
current = advanceSandboxRemovalJournalPhase(current, next, { resourceLock });
|
|
451
|
-
}
|
|
452
|
-
return current;
|
|
453
|
-
}
|
|
454
449
|
async function awaitWithDeadline(operation, deadlineAt, errorCode) {
|
|
455
450
|
const remaining = deadlineAt - Date.now();
|
|
456
451
|
if (remaining <= 0)
|
|
@@ -530,7 +525,6 @@ function recordSandboxRemovalPending(root, manifest, phase, journal) {
|
|
|
530
525
|
phase,
|
|
531
526
|
containerId: manifest.containerIdentity.id,
|
|
532
527
|
generation: manifest.generation,
|
|
533
|
-
authorityFingerprint: manifest.authorityEvidence.authorityFingerprint,
|
|
534
528
|
recordedAt: Date.now()
|
|
535
529
|
})}\n`, { mode: 0o600, flag: 'wx' });
|
|
536
530
|
fs.renameSync(temporary, pendingPath);
|
|
@@ -920,11 +914,13 @@ function readSandboxControlManifestValue(manifestPath) {
|
|
|
920
914
|
catch {
|
|
921
915
|
throw new Error('SANDBOX_CONTROL_MANIFEST_INVALID');
|
|
922
916
|
}
|
|
917
|
+
// TODO(compat): Remove obsolete-field normalization after existing sandbox manifests are rewritten by their lifecycle.
|
|
918
|
+
delete manifest.authorityEvidence;
|
|
923
919
|
const candidate = manifest;
|
|
924
920
|
const expectedKeys = [
|
|
925
921
|
'branch', 'channelDir', 'container', 'containerIdentity', 'engine', 'generation',
|
|
926
922
|
'mode', 'processingDir', 'project', 'publicStatusDir', 'repoRoot', 'runtimeDir',
|
|
927
|
-
'taskId', 'token', 'worktreeRoot', '
|
|
923
|
+
'taskId', 'token', 'worktreeRoot', 'controlRootId',
|
|
928
924
|
];
|
|
929
925
|
const actualKeys = Object.keys(manifest).sort().join(',');
|
|
930
926
|
if (actualKeys !== expectedKeys.sort().join(',')) {
|
|
@@ -951,8 +947,7 @@ function readSandboxControlManifestValue(manifestPath) {
|
|
|
951
947
|
|| typeof candidate.generation !== 'string'
|
|
952
948
|
|| typeof candidate.controlRootId !== 'string' || !/^[a-f0-9]{64,128}$/u.test(candidate.controlRootId)
|
|
953
949
|
|| (candidate.mode === 'task-bound' && (typeof candidate.taskId !== 'string' || candidate.taskId.length === 0))
|
|
954
|
-
|| (candidate.mode === 'branch-only' && candidate.taskId !== null)
|
|
955
|
-
|| !isSandboxAuthorityEvidence(candidate.authorityEvidence))
|
|
950
|
+
|| (candidate.mode === 'branch-only' && candidate.taskId !== null))
|
|
956
951
|
throw new Error('SANDBOX_CONTROL_MANIFEST_INVALID');
|
|
957
952
|
const root = path.dirname(path.resolve(manifestPath));
|
|
958
953
|
const canonicalRoot = fs.realpathSync.native(root);
|
|
@@ -999,7 +994,6 @@ function readSandboxControlManifestValue(manifestPath) {
|
|
|
999
994
|
id: containerIdentity.id,
|
|
1000
995
|
labels: { ...containerIdentity.labels }
|
|
1001
996
|
},
|
|
1002
|
-
authorityEvidence: candidate.authorityEvidence,
|
|
1003
997
|
branch: candidate.branch,
|
|
1004
998
|
mode: candidate.mode,
|
|
1005
999
|
taskId: candidate.taskId,
|
|
@@ -1287,7 +1281,7 @@ async function removeSandboxControlRootAttempt(root, options) {
|
|
|
1287
1281
|
const manifestPath = path.join(resolvedRoot, 'manifest.json');
|
|
1288
1282
|
const manifestRawBeforeLock = fs.readFileSync(manifestPath, 'utf8');
|
|
1289
1283
|
const manifest = readSandboxControlManifest(manifestPath);
|
|
1290
|
-
const resourceLock = options.resourceLock ?? acquireSandboxResourceLock(`${manifest.engine}:${manifest.containerIdentity.id}`, { lockDomain: manifest
|
|
1284
|
+
const resourceLock = options.resourceLock ?? acquireSandboxResourceLock(`${manifest.engine}:${manifest.containerIdentity.id}`, { lockDomain: readSandboxRemovalJournal(manifest)?.lockDomain });
|
|
1291
1285
|
try {
|
|
1292
1286
|
if (fs.readFileSync(manifestPath, 'utf8') !== manifestRawBeforeLock) {
|
|
1293
1287
|
throw new Error('SANDBOX_CONTROL_MANIFEST_CHANGED');
|
|
@@ -1394,7 +1388,6 @@ async function removeSandboxControlRootAttempt(root, options) {
|
|
|
1394
1388
|
if (currentManifestRaw !== manifestRawBeforeLock
|
|
1395
1389
|
|| currentManifest.engine !== manifest.engine
|
|
1396
1390
|
|| currentManifest.containerIdentity.id !== manifest.containerIdentity.id
|
|
1397
|
-
|| currentManifest.authorityEvidence.lockDomain !== manifest.authorityEvidence.lockDomain
|
|
1398
1391
|
|| currentManifest.token !== manifest.token || currentManifest.generation !== manifest.generation
|
|
1399
1392
|
|| !isSandboxControlRootQuiescing(resolvedRoot)) {
|
|
1400
1393
|
throw new Error('SANDBOX_CONTROL_MANIFEST_CHANGED');
|
|
@@ -1478,13 +1471,4 @@ async function removeSandboxControlRootAttempt(root, options) {
|
|
|
1478
1471
|
resourceLock.release();
|
|
1479
1472
|
}
|
|
1480
1473
|
}
|
|
1481
|
-
export async function garbageCollectSandboxControlRoot(root, options = {}) {
|
|
1482
|
-
await removeSandboxControlRoot(path.resolve(root), {
|
|
1483
|
-
...options,
|
|
1484
|
-
requireAbsent: true,
|
|
1485
|
-
removeContainer: async () => {
|
|
1486
|
-
throw new Error('SANDBOX_CONTROL_CONTAINER_REAPPEARED');
|
|
1487
|
-
}
|
|
1488
|
-
});
|
|
1489
|
-
}
|
|
1490
1474
|
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -69,9 +69,6 @@ export function resolveSandboxLockNamespace(carrierIdentity, options = {}) {
|
|
|
69
69
|
lockPath: path.join(domainDirectory, `${carrierIdentityDigest}.lock`)
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
export function stableSandboxLockPath(carrierIdentity, lockDomain, options = {}) {
|
|
73
|
-
return resolveSandboxLockNamespace(carrierIdentity, { lockDomain, home: options.home }).lockPath;
|
|
74
|
-
}
|
|
75
72
|
export function acquireSandboxResourceLock(carrierIdentity, options = {}) {
|
|
76
73
|
const namespace = resolveSandboxLockNamespace(carrierIdentity, options);
|
|
77
74
|
try {
|