@fitlab-ai/agent-infra 0.9.2 → 0.9.4
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 +12 -9
- package/README.zh-CN.md +12 -9
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +134 -108
- package/dist/lib/agent-clients/adapter.js +137 -4
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
- package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
- package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
- package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
- package/dist/lib/agent-clients/adapters/codex.js +9 -0
- package/dist/lib/agent-clients/adapters/index.js +2 -2
- package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
- package/dist/lib/agent-clients/adapters/opencode.js +24 -3
- package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/dist/lib/agent-clients/config.js +42 -4
- package/dist/lib/agent-clients/next-steps.js +11 -2
- package/dist/lib/agent-clients/reconcile.js +2 -1
- package/dist/lib/agent-clients/registry.js +16 -2
- package/dist/lib/agent-clients/schema.js +18 -0
- package/dist/lib/agent-clients/tokens.js +49 -0
- package/dist/lib/agent-clients/types.js +1 -1
- package/dist/lib/defaults.json +1 -1
- package/dist/lib/git/workflow.js +54 -1
- package/dist/lib/internal/agent-client.js +61 -4
- package/dist/lib/internal/git-workflow.js +6 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +29 -2
- package/dist/lib/internal/platform-issue.js +7 -0
- package/dist/lib/internal/platform-pr-review.js +132 -0
- package/dist/lib/internal/platform-pr.js +20 -2
- package/dist/lib/internal/platform-release-notes.js +52 -16
- package/dist/lib/internal/pr-review-grade.js +140 -0
- package/dist/lib/internal/release-workflow.js +13 -6
- package/dist/lib/internal/sandbox-control.js +24 -0
- package/dist/lib/internal/task-activity.js +105 -0
- package/dist/lib/internal/task-event.js +17 -1
- package/dist/lib/internal/task-ledger.js +12 -3
- package/dist/lib/internal/task-lifecycle.js +26 -1
- package/dist/lib/internal/task-orchestration.js +167 -18
- package/dist/lib/internal/task-review.js +8 -3
- package/dist/lib/platform/adapters.js +8 -1
- package/dist/lib/platform/completion-backfill.js +122 -0
- package/dist/lib/platform/github-client.js +19 -2
- package/dist/lib/platform/issue-comments.js +3 -2
- package/dist/lib/platform/merged-pr-equivalence.js +115 -5
- package/dist/lib/platform/pr-checks.js +65 -42
- package/dist/lib/platform/pr-review.js +166 -0
- package/dist/lib/platform/pull-requests.js +371 -4
- package/dist/lib/platform/release-notes.js +85 -3
- package/dist/lib/platform/releases.js +13 -5
- package/dist/lib/pr-review/evidence-grading.js +229 -0
- package/dist/lib/process-data/index.js +239 -0
- package/dist/lib/process-data/normalize.js +198 -0
- package/dist/lib/process-data/privacy.js +33 -0
- package/dist/lib/process-data/reconcile.js +95 -0
- package/dist/lib/process-data/repair.js +58 -0
- package/dist/lib/process-data/sources.js +345 -0
- package/dist/lib/process-data/store.js +282 -0
- package/dist/lib/process-data/types.js +2 -0
- package/dist/lib/run/index.js +4 -3
- package/dist/lib/run/tui.js +10 -13
- package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
- package/dist/lib/sandbox/capture.js +7 -2
- package/dist/lib/sandbox/commands/create.js +109 -248
- package/dist/lib/sandbox/commands/enter.js +15 -47
- package/dist/lib/sandbox/commands/list-running.js +16 -6
- package/dist/lib/sandbox/commands/ls.js +10 -6
- package/dist/lib/sandbox/commands/rebuild.js +4 -3
- package/dist/lib/sandbox/commands/refresh.js +4 -84
- package/dist/lib/sandbox/commands/rm.js +24 -3
- package/dist/lib/sandbox/commands/show.js +13 -4
- package/dist/lib/sandbox/commands/start.js +7 -4
- package/dist/lib/sandbox/config.js +2 -0
- package/dist/lib/sandbox/constants.js +6 -0
- package/dist/lib/sandbox/control/client.js +44 -0
- package/dist/lib/sandbox/control/protocol.js +35 -0
- package/dist/lib/sandbox/control/server.js +109 -0
- package/dist/lib/sandbox/dockerfile.js +36 -13
- package/dist/lib/sandbox/mounts.js +17 -4
- package/dist/lib/sandbox/recovery.js +128 -5
- package/dist/lib/sandbox/redaction.js +12 -0
- package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/dist/lib/sandbox/workspace-identity.js +95 -0
- package/dist/lib/sandbox/workspace-view.js +103 -0
- package/dist/lib/task/activity-intent.js +307 -0
- package/dist/lib/task/artifact-lifecycle.js +2 -1
- package/dist/lib/task/commands/log.js +15 -14
- package/dist/lib/task/commit-finalization.js +267 -0
- package/dist/lib/task/commit-intent.js +165 -0
- package/dist/lib/task/decision-intents.js +31 -17
- package/dist/lib/task/delegation-receipts.js +25 -4
- package/dist/lib/task/events.js +67 -28
- package/dist/lib/task/finalization-artifacts.js +35 -0
- package/dist/lib/task/implementation-inputs.js +54 -7
- package/dist/lib/task/ledger-intents.js +35 -1
- package/dist/lib/task/lifecycle-execution.js +46 -0
- package/dist/lib/task/orchestration.js +753 -54
- package/dist/lib/task/resolve-ref.js +41 -1
- package/dist/lib/task/review-finalization.js +29 -9
- package/dist/lib/task/task-execution-lock.js +231 -0
- package/dist/lib/task/verification-checks.js +1 -1
- package/dist/lib/task/verification-engine.js +218 -2
- package/dist/lib/task/verification.js +4 -3
- package/dist/lib/task/workspace-snapshot.js +17 -5
- package/lib/agent-clients/adapter.ts +201 -4
- package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
- package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
- package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
- package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
- package/lib/agent-clients/adapters/claude-code.ts +31 -4
- package/lib/agent-clients/adapters/codex.ts +9 -0
- package/lib/agent-clients/adapters/index.ts +2 -2
- package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
- package/lib/agent-clients/adapters/opencode.ts +27 -3
- package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/lib/agent-clients/config.ts +49 -4
- package/lib/agent-clients/next-steps.ts +15 -2
- package/lib/agent-clients/reconcile.ts +2 -1
- package/lib/agent-clients/registry.ts +19 -1
- package/lib/agent-clients/schema.ts +18 -0
- package/lib/agent-clients/tokens.ts +53 -0
- package/lib/agent-clients/types.ts +15 -1
- package/lib/defaults.json +1 -1
- package/lib/git/workflow.ts +66 -2
- package/lib/internal/agent-client.ts +59 -4
- package/lib/internal/git-workflow.ts +5 -1
- package/lib/internal/platform-checks.ts +4 -4
- package/lib/internal/platform-comment.ts +17 -2
- package/lib/internal/platform-issue.ts +4 -0
- package/lib/internal/platform-pr-review.ts +104 -0
- package/lib/internal/platform-pr.ts +14 -1
- package/lib/internal/platform-release-notes.ts +59 -16
- package/lib/internal/pr-review-grade.ts +130 -0
- package/lib/internal/release-workflow.ts +13 -6
- package/lib/internal/sandbox-control.ts +24 -0
- package/lib/internal/task-activity.ts +91 -0
- package/lib/internal/task-event.ts +9 -1
- package/lib/internal/task-ledger.ts +12 -3
- package/lib/internal/task-lifecycle.ts +26 -1
- package/lib/internal/task-orchestration.ts +123 -14
- package/lib/internal/task-review.ts +8 -3
- package/lib/platform/adapters.ts +29 -2
- package/lib/platform/completion-backfill.ts +134 -0
- package/lib/platform/github-client.ts +20 -2
- package/lib/platform/issue-comments.ts +3 -2
- package/lib/platform/merged-pr-equivalence.ts +127 -5
- package/lib/platform/pr-checks.ts +73 -46
- package/lib/platform/pr-review.ts +201 -0
- package/lib/platform/pull-requests.ts +444 -3
- package/lib/platform/release-notes.ts +100 -4
- package/lib/platform/releases.ts +16 -4
- package/lib/pr-review/evidence-grading.ts +318 -0
- package/lib/process-data/index.ts +224 -0
- package/lib/process-data/normalize.ts +202 -0
- package/lib/process-data/privacy.ts +41 -0
- package/lib/process-data/reconcile.ts +110 -0
- package/lib/process-data/repair.ts +64 -0
- package/lib/process-data/sources.ts +354 -0
- package/lib/process-data/store.ts +315 -0
- package/lib/process-data/types.ts +135 -0
- package/lib/run/index.ts +5 -3
- package/lib/run/tui.ts +14 -12
- package/lib/sandbox/agent-client-reconciler.ts +44 -2
- package/lib/sandbox/capture.ts +9 -2
- package/lib/sandbox/commands/create.ts +126 -280
- package/lib/sandbox/commands/enter.ts +13 -59
- package/lib/sandbox/commands/list-running.ts +23 -6
- package/lib/sandbox/commands/ls.ts +22 -6
- package/lib/sandbox/commands/rebuild.ts +4 -3
- package/lib/sandbox/commands/refresh.ts +4 -126
- package/lib/sandbox/commands/rm.ts +24 -3
- package/lib/sandbox/commands/show.ts +30 -4
- package/lib/sandbox/commands/start.ts +6 -4
- package/lib/sandbox/config.ts +4 -0
- package/lib/sandbox/constants.ts +8 -0
- package/lib/sandbox/control/client.ts +55 -0
- package/lib/sandbox/control/protocol.ts +75 -0
- package/lib/sandbox/control/server.ts +117 -0
- package/lib/sandbox/dockerfile.ts +66 -13
- package/lib/sandbox/mounts.ts +24 -4
- package/lib/sandbox/recovery.ts +163 -6
- package/lib/sandbox/redaction.ts +14 -0
- package/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/lib/sandbox/tool-types.ts +16 -0
- package/lib/sandbox/workspace-identity.ts +123 -0
- package/lib/sandbox/workspace-view.ts +143 -0
- package/lib/server/server.schema.json +2 -2
- package/lib/task/activity-intent.ts +417 -0
- package/lib/task/artifact-lifecycle.ts +2 -1
- package/lib/task/commands/log.ts +15 -14
- package/lib/task/commit-finalization.ts +356 -0
- package/lib/task/commit-intent.ts +230 -0
- package/lib/task/decision-intents.ts +32 -12
- package/lib/task/delegation-receipts.ts +34 -5
- package/lib/task/events.ts +75 -30
- package/lib/task/finalization-artifacts.ts +58 -0
- package/lib/task/implementation-inputs.ts +62 -8
- package/lib/task/ledger-intents.ts +43 -3
- package/lib/task/lifecycle-execution.ts +106 -0
- package/lib/task/orchestration.ts +1019 -72
- package/lib/task/resolve-ref.ts +46 -1
- package/lib/task/review-finalization.ts +40 -9
- package/lib/task/task-execution-lock.ts +296 -0
- package/lib/task/verification-checks.ts +1 -1
- package/lib/task/verification-engine.ts +249 -2
- package/lib/task/verification.ts +5 -3
- package/lib/task/workspace-snapshot.ts +26 -5
- package/package.json +3 -3
- package/templates/.agents/QUICKSTART.en.md +25 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
- package/templates/.agents/README.en.md +10 -7
- package/templates/.agents/README.zh-CN.md +10 -7
- package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
- package/templates/.agents/rules/README.en.md +1 -1
- package/templates/.agents/rules/README.zh-CN.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +4 -2
- package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
- package/templates/.agents/rules/human-decision-context.en.md +11 -2
- package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
- package/templates/.agents/rules/issue-fields.github.en.md +3 -1
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-sync.github.en.md +7 -3
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
- package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
- package/templates/.agents/rules/next-step-output.en.md +3 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
- package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-sync.en.md +3 -1
- package/templates/.agents/rules/pr-sync.github.en.md +11 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
- package/templates/.agents/rules/release-commands.en.md +1 -1
- package/templates/.agents/rules/release-commands.github.en.md +12 -2
- package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
- package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +13 -0
- package/templates/.agents/rules/task-management.zh-CN.md +13 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
- package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
- package/templates/.agents/skills/commit/SKILL.en.md +23 -11
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
- package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/release/SKILL.en.md +16 -10
- package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
- package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
- package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
- package/templates/.agents/workflows/code-review.en.yaml +1 -1
- package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +4 -4
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
- package/templates/.agents/workflows/refactoring.en.yaml +3 -3
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
- package/templates/.claude/commands/post-release.en.md +1 -0
- package/templates/.claude/commands/post-release.zh-CN.md +1 -0
- package/templates/.claude/commands/review-pr.en.md +8 -0
- package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.claude/rules/tool-preferences.en.md +20 -0
- package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
- package/templates/.opencode/commands/post-release.en.md +2 -0
- package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
- package/templates/.opencode/commands/review-pr.en.md +11 -0
- package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
- package/templates/.opencode/commands/watch-pr.en.md +1 -1
- package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
- package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
- package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
- package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
- package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/release.en.toml +0 -8
- package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/test.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
- package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
- package/templates/.gemini/settings.json +0 -3
|
@@ -2,9 +2,10 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
-
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
6
6
|
import type { ExecFileSyncOptions, StdioOptions } from 'node:child_process';
|
|
7
7
|
import { parseArgs } from 'node:util';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
8
9
|
import * as p from '@clack/prompts';
|
|
9
10
|
import pc from 'picocolors';
|
|
10
11
|
import { listAgentClientAdapters } from '../../agent-clients/registry.ts';
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
sandboxImageRefreshLabel,
|
|
21
22
|
sandboxLabel,
|
|
22
23
|
sandboxRuntimeCapabilityLabel,
|
|
24
|
+
sandboxTaskIdLabel,
|
|
25
|
+
sandboxWorkspaceModeLabel,
|
|
23
26
|
shareBranchDir,
|
|
24
27
|
shareCommonDir,
|
|
25
28
|
shellConfigDir,
|
|
@@ -44,7 +47,11 @@ import {
|
|
|
44
47
|
runSafeEngine,
|
|
45
48
|
runVerboseEngine
|
|
46
49
|
} from '../shell.ts';
|
|
47
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
parseSandboxWorkspaceIdentity,
|
|
52
|
+
resolveSandboxTarget,
|
|
53
|
+
sameSandboxWorkspaceIdentity
|
|
54
|
+
} from '../workspace-identity.ts';
|
|
48
55
|
import {
|
|
49
56
|
createSandboxCapabilityPlan,
|
|
50
57
|
runSandboxHooks,
|
|
@@ -64,16 +71,17 @@ import {
|
|
|
64
71
|
} from '../recovery.ts';
|
|
65
72
|
import { hostJoin, toEnginePath, volumeArg } from '../engines/wsl2-paths.ts';
|
|
66
73
|
import { sandboxCoreBindMounts } from '../mounts.ts';
|
|
74
|
+
import {
|
|
75
|
+
assertSandboxTaskSource,
|
|
76
|
+
materializeSandboxControl,
|
|
77
|
+
materializeSandboxWorkspaceView
|
|
78
|
+
} from '../workspace-view.ts';
|
|
67
79
|
import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.ts';
|
|
68
80
|
import { validateSelinuxDisableEnv } from '../engines/selinux.ts';
|
|
69
81
|
import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.ts';
|
|
70
82
|
import { ensureSandboxDiscoveryReadmes } from '../readme-scaffold.ts';
|
|
71
83
|
import { removeDirRecursive } from '../../remove-dir.ts';
|
|
72
|
-
import {
|
|
73
|
-
prepareClaudeCredentials,
|
|
74
|
-
redactCommandError,
|
|
75
|
-
validateClaudeCredentialsEnvOverride
|
|
76
|
-
} from '../credentials.ts';
|
|
84
|
+
import { redactCommandError } from '../redaction.ts';
|
|
77
85
|
import { detectHostTimezone } from '../host-timezone.ts';
|
|
78
86
|
import {
|
|
79
87
|
buildImageSignature,
|
|
@@ -84,10 +92,6 @@ import {
|
|
|
84
92
|
parseRefreshTimestamp
|
|
85
93
|
} from '../image-build.ts';
|
|
86
94
|
|
|
87
|
-
export {
|
|
88
|
-
ensureCodexModelInheritance,
|
|
89
|
-
ensureCodexWorkspaceTrust
|
|
90
|
-
} from '../../agent-clients/adapters/codex-sandbox.ts';
|
|
91
95
|
|
|
92
96
|
const SANDBOX_ALIAS_BLOCK_BEGIN = '# >>> agent-infra managed aliases >>>';
|
|
93
97
|
const SANDBOX_ALIAS_BLOCK_END = '# <<< agent-infra managed aliases <<<';
|
|
@@ -133,7 +137,6 @@ type TmpfsSeedPlanEntry = TmpfsSeedEntry & {
|
|
|
133
137
|
volumeArgs: string[];
|
|
134
138
|
};
|
|
135
139
|
type RuntimeCheck = { name: string; cmd: string[] };
|
|
136
|
-
type JsonObject = Record<string, unknown>;
|
|
137
140
|
type GpgCache = { pub: Buffer; sec: Buffer } | null;
|
|
138
141
|
type ExecSyncOptions = ExecFileSyncOptions & {
|
|
139
142
|
input?: Buffer | string;
|
|
@@ -154,6 +157,12 @@ type HostShellConfig = {
|
|
|
154
157
|
mounts: Array<{ hostPath: string; containerPath: string }>;
|
|
155
158
|
};
|
|
156
159
|
|
|
160
|
+
function internalCliPath(): string {
|
|
161
|
+
const directory = path.dirname(fileURLToPath(import.meta.url));
|
|
162
|
+
const extension = path.extname(fileURLToPath(import.meta.url));
|
|
163
|
+
return path.resolve(directory, '..', '..', '..', 'bin', `internal-cli${extension}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
157
166
|
function resolveToolDirs(config: Pick<SandboxCreateConfig, 'project'>, tools: SandboxTool[], branch: string): ResolvedTool[] {
|
|
158
167
|
return tools.map((tool) => {
|
|
159
168
|
const candidates = toolConfigDirCandidates(tool, config.project, branch);
|
|
@@ -807,225 +816,6 @@ export function assertBranchAvailable(
|
|
|
807
816
|
}
|
|
808
817
|
}
|
|
809
818
|
|
|
810
|
-
function readHostJsonSafe(filePath: string): JsonObject | null {
|
|
811
|
-
if (!filePath || !fs.existsSync(filePath)) {
|
|
812
|
-
return null;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
try {
|
|
816
|
-
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as unknown;
|
|
817
|
-
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as JsonObject : null;
|
|
818
|
-
} catch {
|
|
819
|
-
return null;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
const CLAUDE_SETTINGS_INHERIT_TOP_LEVEL_KEYS = [
|
|
824
|
-
'model',
|
|
825
|
-
'fallbackModel',
|
|
826
|
-
'availableModels',
|
|
827
|
-
'modelOverrides',
|
|
828
|
-
'enforceAvailableModels',
|
|
829
|
-
'advisorModel',
|
|
830
|
-
'apiKeyHelper',
|
|
831
|
-
'effortLevel'
|
|
832
|
-
];
|
|
833
|
-
|
|
834
|
-
function isJsonObjectRecord(value: unknown): value is JsonObject {
|
|
835
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
function mergeMissingStringEnvFields(target: JsonObject, source: JsonObject): boolean {
|
|
839
|
-
if (!isJsonObjectRecord(source.env)) {
|
|
840
|
-
return false;
|
|
841
|
-
}
|
|
842
|
-
if (Object.hasOwn(target, 'env') && !isJsonObjectRecord(target.env)) {
|
|
843
|
-
return false;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
let targetEnv = target.env as JsonObject | undefined;
|
|
847
|
-
let changed = false;
|
|
848
|
-
for (const [key, value] of Object.entries(source.env)) {
|
|
849
|
-
if (typeof value !== 'string' || value === '') {
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
if (!targetEnv) {
|
|
853
|
-
targetEnv = {};
|
|
854
|
-
target.env = targetEnv;
|
|
855
|
-
}
|
|
856
|
-
if (!Object.hasOwn(targetEnv, key)) {
|
|
857
|
-
targetEnv[key] = value;
|
|
858
|
-
changed = true;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
return changed;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
function mergeMissingTopLevelSettings(target: JsonObject, source: JsonObject): boolean {
|
|
865
|
-
let changed = false;
|
|
866
|
-
for (const key of CLAUDE_SETTINGS_INHERIT_TOP_LEVEL_KEYS) {
|
|
867
|
-
if (!Object.hasOwn(source, key) || Object.hasOwn(target, key)) {
|
|
868
|
-
continue;
|
|
869
|
-
}
|
|
870
|
-
const value = source[key];
|
|
871
|
-
if (value === null || value === undefined || value === '') {
|
|
872
|
-
continue;
|
|
873
|
-
}
|
|
874
|
-
target[key] = value;
|
|
875
|
-
changed = true;
|
|
876
|
-
}
|
|
877
|
-
return changed;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
export function ensureClaudeOnboarding(toolDir: string, hostHomeDir?: string): void {
|
|
881
|
-
const claudeJsonPath = path.join(toolDir, '.claude.json');
|
|
882
|
-
let data: JsonObject & {
|
|
883
|
-
hasCompletedOnboarding?: boolean;
|
|
884
|
-
projects?: Record<string, { hasTrustDialogAccepted?: boolean }>;
|
|
885
|
-
model?: string;
|
|
886
|
-
} = {};
|
|
887
|
-
if (fs.existsSync(claudeJsonPath)) {
|
|
888
|
-
try {
|
|
889
|
-
data = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf8')) as typeof data;
|
|
890
|
-
} catch {
|
|
891
|
-
// malformed JSON, start fresh
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
let changed = false;
|
|
895
|
-
if (!data.hasCompletedOnboarding) {
|
|
896
|
-
data.hasCompletedOnboarding = true;
|
|
897
|
-
changed = true;
|
|
898
|
-
}
|
|
899
|
-
if (!data.projects) {
|
|
900
|
-
data.projects = {};
|
|
901
|
-
changed = true;
|
|
902
|
-
}
|
|
903
|
-
if (!data.projects['/workspace']) {
|
|
904
|
-
data.projects['/workspace'] = {};
|
|
905
|
-
changed = true;
|
|
906
|
-
}
|
|
907
|
-
if (!data.projects['/workspace'].hasTrustDialogAccepted) {
|
|
908
|
-
data.projects['/workspace'].hasTrustDialogAccepted = true;
|
|
909
|
-
changed = true;
|
|
910
|
-
}
|
|
911
|
-
if (hostHomeDir) {
|
|
912
|
-
const hostClaudeJson = readHostJsonSafe(path.join(hostHomeDir, '.claude.json'));
|
|
913
|
-
if (
|
|
914
|
-
hostClaudeJson
|
|
915
|
-
&& typeof hostClaudeJson.model === 'string'
|
|
916
|
-
&& hostClaudeJson.model !== ''
|
|
917
|
-
&& !Object.hasOwn(data, 'model')
|
|
918
|
-
) {
|
|
919
|
-
data.model = hostClaudeJson.model;
|
|
920
|
-
changed = true;
|
|
921
|
-
}
|
|
922
|
-
// Claude Code launch-pins a default effort per model generation (for
|
|
923
|
-
// example xhigh for Opus 4.7). The saved effortLevel is honored only after
|
|
924
|
-
// a top-level boolean `unpin*LaunchEffort: true` flag unlocks it, so mirror
|
|
925
|
-
// those flags here with the existing first-write semantics.
|
|
926
|
-
//
|
|
927
|
-
// Pattern matching avoids one patch per future model generation. If
|
|
928
|
-
// Anthropic changes the naming convention, this block will no-op and should
|
|
929
|
-
// be revisited.
|
|
930
|
-
if (hostClaudeJson) {
|
|
931
|
-
for (const key of Object.keys(hostClaudeJson)) {
|
|
932
|
-
if (
|
|
933
|
-
/^unpin.*LaunchEffort$/.test(key)
|
|
934
|
-
&& hostClaudeJson[key] === true
|
|
935
|
-
&& !Object.hasOwn(data, key)
|
|
936
|
-
) {
|
|
937
|
-
data[key] = true;
|
|
938
|
-
changed = true;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
if (changed) {
|
|
944
|
-
fs.writeFileSync(claudeJsonPath, JSON.stringify(data, null, 4), 'utf8');
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
export function ensureClaudeSettings(toolDir: string, hostHomeDir?: string): void {
|
|
949
|
-
const settingsPath = path.join(toolDir, 'settings.json');
|
|
950
|
-
let data: JsonObject & { skipDangerousModePermissionPrompt?: boolean } = {};
|
|
951
|
-
if (fs.existsSync(settingsPath)) {
|
|
952
|
-
try {
|
|
953
|
-
data = JSON.parse(fs.readFileSync(settingsPath, 'utf8')) as typeof data;
|
|
954
|
-
} catch {
|
|
955
|
-
// malformed JSON, start fresh
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
let changed = false;
|
|
959
|
-
if (data.skipDangerousModePermissionPrompt !== true) {
|
|
960
|
-
data.skipDangerousModePermissionPrompt = true;
|
|
961
|
-
changed = true;
|
|
962
|
-
}
|
|
963
|
-
if (hostHomeDir) {
|
|
964
|
-
const hostSettings = readHostJsonSafe(path.join(hostHomeDir, '.claude', 'settings.json'));
|
|
965
|
-
if (hostSettings) {
|
|
966
|
-
changed = mergeMissingStringEnvFields(data, hostSettings) || changed;
|
|
967
|
-
changed = mergeMissingTopLevelSettings(data, hostSettings) || changed;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
if (changed) {
|
|
971
|
-
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 4), 'utf8');
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
export function ensureOpenCodeModelInheritance(toolDir: string, hostHomeDir?: string): void {
|
|
976
|
-
if (!hostHomeDir) {
|
|
977
|
-
return;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
const hostConfigPath = path.join(hostHomeDir, '.config', 'opencode', 'opencode.json');
|
|
981
|
-
const hostJson = readHostJsonSafe(hostConfigPath);
|
|
982
|
-
if (!hostJson) {
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
const sandboxConfigPath = path.join(toolDir, 'opencode.json');
|
|
987
|
-
let sandboxJson: JsonObject = {};
|
|
988
|
-
if (fs.existsSync(sandboxConfigPath)) {
|
|
989
|
-
const existing = readHostJsonSafe(sandboxConfigPath);
|
|
990
|
-
if (!existing) {
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
|
-
sandboxJson = existing;
|
|
994
|
-
}
|
|
995
|
-
let changed = false;
|
|
996
|
-
for (const key of ['model', 'small_model']) {
|
|
997
|
-
if (Object.hasOwn(sandboxJson, key)) {
|
|
998
|
-
continue;
|
|
999
|
-
}
|
|
1000
|
-
const value = hostJson[key];
|
|
1001
|
-
if (typeof value !== 'string' || value === '') {
|
|
1002
|
-
continue;
|
|
1003
|
-
}
|
|
1004
|
-
sandboxJson[key] = value;
|
|
1005
|
-
changed = true;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
if (changed) {
|
|
1009
|
-
fs.writeFileSync(sandboxConfigPath, JSON.stringify(sandboxJson, null, 2), 'utf8');
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
export function ensureGeminiWorkspaceTrust(toolDir: string): void {
|
|
1014
|
-
const trustPath = path.join(toolDir, 'trustedFolders.json');
|
|
1015
|
-
let data: Record<string, string> = {};
|
|
1016
|
-
if (fs.existsSync(trustPath)) {
|
|
1017
|
-
try {
|
|
1018
|
-
data = JSON.parse(fs.readFileSync(trustPath, 'utf8')) as Record<string, string>;
|
|
1019
|
-
} catch {
|
|
1020
|
-
// malformed JSON, start fresh
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
if (data['/workspace'] !== 'TRUST_FOLDER') {
|
|
1024
|
-
data['/workspace'] = 'TRUST_FOLDER';
|
|
1025
|
-
fs.writeFileSync(trustPath, JSON.stringify(data, null, 2), 'utf8');
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
819
|
export function sandboxAliasesPath(home: string): string {
|
|
1030
820
|
return hostJoin(home, '.agent-infra', 'aliases', 'sandbox.sh');
|
|
1031
821
|
}
|
|
@@ -1211,11 +1001,10 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1211
1001
|
}
|
|
1212
1002
|
|
|
1213
1003
|
validateSelinuxDisableEnv();
|
|
1214
|
-
validateClaudeCredentialsEnvOverride();
|
|
1215
|
-
|
|
1216
1004
|
const config = loadConfig();
|
|
1217
1005
|
const [branchOrTaskId = '', base] = positionals;
|
|
1218
|
-
const
|
|
1006
|
+
const target = resolveSandboxTarget(branchOrTaskId, config.repoRoot);
|
|
1007
|
+
const branch = target.branch;
|
|
1219
1008
|
assertValidBranchName(branch);
|
|
1220
1009
|
const effectiveConfig = {
|
|
1221
1010
|
...config,
|
|
@@ -1230,20 +1019,31 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1230
1019
|
const capabilityPlan = createSandboxCapabilityPlan(effectiveConfig);
|
|
1231
1020
|
const tools = [...capabilityPlan.tools];
|
|
1232
1021
|
const resolvedTools = resolveToolDirs(effectiveConfig, tools, branch);
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1022
|
+
const prepareHookResults = await runSandboxHooks({
|
|
1023
|
+
hooks: capabilityPlan.hooksByPhase.prepare,
|
|
1024
|
+
phase: 'prepare',
|
|
1025
|
+
context: {
|
|
1026
|
+
config: effectiveConfig,
|
|
1027
|
+
plan: capabilityPlan,
|
|
1028
|
+
create: {
|
|
1029
|
+
hostHome: effectiveConfig.home,
|
|
1030
|
+
hostEnv: { ...process.env },
|
|
1031
|
+
project: effectiveConfig.project,
|
|
1032
|
+
resolvedTools
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
runCommand: runBoundedSandboxHookCommand
|
|
1036
|
+
});
|
|
1037
|
+
const prepareFailure = prepareHookResults.find((result) => result.status === 'fatal');
|
|
1038
|
+
if (prepareFailure) {
|
|
1039
|
+
throw new Error(prepareFailure.message ?? `Sandbox hook '${prepareFailure.hookId}' failed.`);
|
|
1040
|
+
}
|
|
1241
1041
|
const effectiveResolvedTools = resolvedTools;
|
|
1242
1042
|
const container = containerName(effectiveConfig, branch);
|
|
1243
1043
|
const worktree = worktreeCandidates.find((candidate) => fs.existsSync(candidate)) ?? worktreeCandidates[0] ?? '';
|
|
1244
1044
|
const shareCommon = shareCommonDir(effectiveConfig);
|
|
1245
1045
|
const shareBranch = shareBranchDir(effectiveConfig, branch);
|
|
1246
|
-
const preparedDockerfile = prepareDockerfile(effectiveConfig);
|
|
1046
|
+
const preparedDockerfile = prepareDockerfile(effectiveConfig, capabilityPlan.image);
|
|
1247
1047
|
const baseBranch = base ?? runSafe('git', ['-C', effectiveConfig.repoRoot, 'branch', '--show-current']);
|
|
1248
1048
|
const expectedImageSignature = buildImageSignature(preparedDockerfile, tools);
|
|
1249
1049
|
const engine = detectEngine(effectiveConfig);
|
|
@@ -1253,26 +1053,12 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1253
1053
|
p.log.info(
|
|
1254
1054
|
`Project: ${pc.bold(effectiveConfig.project)} | Branch: ${pc.bold(branch)} | Base: ${pc.bold(baseBranch || 'HEAD')}`
|
|
1255
1055
|
);
|
|
1256
|
-
|
|
1257
|
-
p.log.warn(
|
|
1258
|
-
'Claude Code credentials not found on host - creating this sandbox WITHOUT Claude Code credentials.\n'
|
|
1259
|
-
+ ' Claude Code is still installed in the image but will not be authenticated.\n'
|
|
1260
|
-
+ ' To enable it: run "claude" once on the host to complete login, then re-run "ai sandbox create".'
|
|
1261
|
-
);
|
|
1056
|
+
for (const result of prepareHookResults) {
|
|
1057
|
+
if (result.status === 'warning' && result.message) p.log.warn(result.message);
|
|
1262
1058
|
}
|
|
1263
1059
|
|
|
1264
1060
|
try {
|
|
1265
1061
|
p.log.step('Checking container engine...');
|
|
1266
|
-
const prepareHookResults = await runSandboxHooks({
|
|
1267
|
-
hooks: capabilityPlan.hooksByPhase.prepare,
|
|
1268
|
-
phase: 'prepare',
|
|
1269
|
-
context: { config: effectiveConfig, plan: capabilityPlan },
|
|
1270
|
-
runCommand: runBoundedSandboxHookCommand
|
|
1271
|
-
});
|
|
1272
|
-
const prepareFailure = prepareHookResults.find((result) => result.status === 'fatal');
|
|
1273
|
-
if (prepareFailure) {
|
|
1274
|
-
throw new Error(prepareFailure.message ?? `Sandbox hook '${prepareFailure.hookId}' failed.`);
|
|
1275
|
-
}
|
|
1276
1062
|
await ensureDocker(effectiveConfig, (detail: string) => {
|
|
1277
1063
|
p.log.info(` ${detail}`);
|
|
1278
1064
|
});
|
|
@@ -1447,6 +1233,33 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1447
1233
|
.filter((name) => existing.includes(name));
|
|
1448
1234
|
|
|
1449
1235
|
if (matchedContainers.length > 0) {
|
|
1236
|
+
for (const name of matchedContainers) {
|
|
1237
|
+
const rawLabels = runSafeEngine(engine, 'docker', [
|
|
1238
|
+
'inspect', '--format', '{{json .Config.Labels}}', name
|
|
1239
|
+
]).trim();
|
|
1240
|
+
let labels: Record<string, string> = {};
|
|
1241
|
+
try {
|
|
1242
|
+
labels = JSON.parse(rawLabels) as Record<string, string>;
|
|
1243
|
+
} catch {
|
|
1244
|
+
labels = {};
|
|
1245
|
+
}
|
|
1246
|
+
const existingIdentity = parseSandboxWorkspaceIdentity(labels, {
|
|
1247
|
+
mode: sandboxWorkspaceModeLabel(effectiveConfig),
|
|
1248
|
+
taskId: sandboxTaskIdLabel(effectiveConfig)
|
|
1249
|
+
});
|
|
1250
|
+
if (!sameSandboxWorkspaceIdentity(existingIdentity, target.workspace)) {
|
|
1251
|
+
const existingDescription = existingIdentity.mode === 'task-bound'
|
|
1252
|
+
? `task-bound:${existingIdentity.taskId}`
|
|
1253
|
+
: existingIdentity.mode;
|
|
1254
|
+
const requestedDescription = target.workspace.mode === 'task-bound'
|
|
1255
|
+
? `task-bound:${target.workspace.taskId}`
|
|
1256
|
+
: target.workspace.mode;
|
|
1257
|
+
throw new Error(
|
|
1258
|
+
`SANDBOX_WORKSPACE_IDENTITY_CONFLICT: container '${name}' is ${existingDescription}, `
|
|
1259
|
+
+ `but this request is ${requestedDescription}. Run 'ai sandbox rm ${branch}' and retry.`
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1450
1263
|
message('Removing old container instance...');
|
|
1451
1264
|
for (const name of matchedContainers) {
|
|
1452
1265
|
runSafeEngine(engine, 'docker', ['stop', name]);
|
|
@@ -1501,6 +1314,8 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1501
1314
|
plan: capabilityPlan,
|
|
1502
1315
|
create: {
|
|
1503
1316
|
hostHome: effectiveConfig.home,
|
|
1317
|
+
hostEnv: { ...process.env },
|
|
1318
|
+
project: effectiveConfig.project,
|
|
1504
1319
|
resolvedTools: effectiveResolvedTools
|
|
1505
1320
|
}
|
|
1506
1321
|
},
|
|
@@ -1515,30 +1330,26 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1515
1330
|
?? `Sandbox hook '${beforeCreateFailure.hookId}' failed.`
|
|
1516
1331
|
);
|
|
1517
1332
|
}
|
|
1518
|
-
const claudeCodeEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'claude-code');
|
|
1519
|
-
if (claudeCodeEntry) {
|
|
1520
|
-
ensureClaudeOnboarding(claudeCodeEntry.dir, effectiveConfig.home);
|
|
1521
|
-
ensureClaudeSettings(claudeCodeEntry.dir, effectiveConfig.home);
|
|
1522
|
-
// prepareClaudeCredentials wrote OAuth credentials or confirmed
|
|
1523
|
-
// provider/API settings are enough for Claude Code. If no usable
|
|
1524
|
-
// auth was present, the claude-code entry was removed above.
|
|
1525
|
-
}
|
|
1526
|
-
const geminiEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'gemini-cli');
|
|
1527
|
-
if (geminiEntry) {
|
|
1528
|
-
ensureGeminiWorkspaceTrust(geminiEntry.dir);
|
|
1529
|
-
}
|
|
1530
|
-
const opencodeEntry = effectiveResolvedTools.find(({ tool }) => tool.id === 'opencode');
|
|
1531
|
-
if (opencodeEntry) {
|
|
1532
|
-
// The TUI reads <toolDir>/opencode.json via OPENCODE_CONFIG pinned in tools.js.
|
|
1533
|
-
ensureOpenCodeModelInheritance(opencodeEntry.dir, effectiveConfig.home);
|
|
1534
|
-
}
|
|
1535
1333
|
const toolVolumes = effectiveResolvedTools.flatMap(({ tool, dir }) =>
|
|
1536
1334
|
tool.tmpfs ? [] : ['-v', volumeArg(engine, dir, tool.containerMount)]
|
|
1537
1335
|
);
|
|
1538
1336
|
const tmpfsArgs = effectiveResolvedTools.flatMap(({ tool }) =>
|
|
1539
1337
|
tool.tmpfs ? buildTmpfsRunArgs(tool.containerMount, tool.tmpfs) : []
|
|
1540
1338
|
);
|
|
1541
|
-
const
|
|
1339
|
+
const workspaceView = materializeSandboxWorkspaceView({
|
|
1340
|
+
base: effectiveConfig.workspaceViewBase,
|
|
1341
|
+
project: effectiveConfig.project,
|
|
1342
|
+
container,
|
|
1343
|
+
identity: target.workspace
|
|
1344
|
+
});
|
|
1345
|
+
const control = materializeSandboxControl({
|
|
1346
|
+
base: effectiveConfig.controlBase,
|
|
1347
|
+
repoRoot: effectiveConfig.repoRoot,
|
|
1348
|
+
project: effectiveConfig.project,
|
|
1349
|
+
container,
|
|
1350
|
+
branch,
|
|
1351
|
+
identity: target.workspace
|
|
1352
|
+
});
|
|
1542
1353
|
hostShellConfig = prepareHostShellConfig({
|
|
1543
1354
|
home: effectiveConfig.home,
|
|
1544
1355
|
project: effectiveConfig.project,
|
|
@@ -1547,7 +1358,18 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1547
1358
|
});
|
|
1548
1359
|
const coreVolumes = sandboxCoreBindMounts(effectiveConfig, branch, {
|
|
1549
1360
|
worktree,
|
|
1550
|
-
shellConfigHostDir: hostShellConfig.hostDir
|
|
1361
|
+
shellConfigHostDir: hostShellConfig.hostDir,
|
|
1362
|
+
workspaceViewRoot: workspaceView.root,
|
|
1363
|
+
controlDir: control.channelDir,
|
|
1364
|
+
...(target.workspace.mode === 'task-bound'
|
|
1365
|
+
? {
|
|
1366
|
+
taskSource: assertSandboxTaskSource(
|
|
1367
|
+
effectiveConfig.repoRoot,
|
|
1368
|
+
target.workspace.taskId
|
|
1369
|
+
),
|
|
1370
|
+
taskId: target.workspace.taskId
|
|
1371
|
+
}
|
|
1372
|
+
: {})
|
|
1551
1373
|
}).flatMap(({ hostPaths, containerPath, readOnly }) => [
|
|
1552
1374
|
'-v',
|
|
1553
1375
|
volumeArg(engine, hostPaths[0]!, containerPath, readOnly ? ':ro' : '')
|
|
@@ -1584,7 +1406,6 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1584
1406
|
])
|
|
1585
1407
|
);
|
|
1586
1408
|
|
|
1587
|
-
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
1588
1409
|
fs.mkdirSync(shareCommon, { recursive: true });
|
|
1589
1410
|
fs.mkdirSync(shareBranch, { recursive: true });
|
|
1590
1411
|
fs.mkdirSync(clipboardHostDir(effectiveConfig.home), { recursive: true, mode: 0o700 });
|
|
@@ -1611,6 +1432,20 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1611
1432
|
'--label',
|
|
1612
1433
|
`${sandboxBranchLabel(effectiveConfig)}=${branch}`,
|
|
1613
1434
|
'--label',
|
|
1435
|
+
`${sandboxWorkspaceModeLabel(effectiveConfig)}=${target.workspace.mode}`,
|
|
1436
|
+
...(target.workspace.mode === 'task-bound'
|
|
1437
|
+
? [
|
|
1438
|
+
'--label',
|
|
1439
|
+
`${sandboxTaskIdLabel(effectiveConfig)}=${target.workspace.taskId}`,
|
|
1440
|
+
'-e',
|
|
1441
|
+
`AGENT_INFRA_TASK_ID=${target.workspace.taskId}`
|
|
1442
|
+
]
|
|
1443
|
+
: []),
|
|
1444
|
+
'-e',
|
|
1445
|
+
`AGENT_INFRA_CONTROL_TOKEN=${control.token}`,
|
|
1446
|
+
'-e',
|
|
1447
|
+
'AGENT_INFRA_CONTROL_DIR=/run/agent-infra/control',
|
|
1448
|
+
'--label',
|
|
1614
1449
|
`${sandboxRuntimeCapabilityLabel(effectiveConfig)}=${capabilityPlan.runtimeSignature}`,
|
|
1615
1450
|
...coreVolumes,
|
|
1616
1451
|
...buildClipboardVolumeArgs(engine, effectiveConfig.home),
|
|
@@ -1631,6 +1466,16 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1631
1466
|
'/workspace',
|
|
1632
1467
|
effectiveConfig.imageName
|
|
1633
1468
|
]);
|
|
1469
|
+
const broker = spawn(
|
|
1470
|
+
process.execPath,
|
|
1471
|
+
[internalCliPath(), 'sandbox-control', 'serve', '--manifest', control.manifestPath],
|
|
1472
|
+
{ cwd: effectiveConfig.repoRoot, detached: true, stdio: 'ignore' }
|
|
1473
|
+
);
|
|
1474
|
+
broker.once('error', () => {
|
|
1475
|
+
// Fresh readiness verification below remains the source of truth;
|
|
1476
|
+
// consume detached spawn errors so they cannot crash the command.
|
|
1477
|
+
});
|
|
1478
|
+
broker.unref();
|
|
1634
1479
|
createdTmpfsSeedPlan = tmpfsSeedPlan;
|
|
1635
1480
|
} finally {
|
|
1636
1481
|
envFile.cleanup();
|
|
@@ -1733,10 +1578,11 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1733
1578
|
}
|
|
1734
1579
|
|
|
1735
1580
|
p.log.step('Verifying setup...');
|
|
1736
|
-
assertFreshSandboxReady({
|
|
1581
|
+
await assertFreshSandboxReady({
|
|
1737
1582
|
config: effectiveConfig,
|
|
1738
1583
|
engine,
|
|
1739
1584
|
branch,
|
|
1585
|
+
workspace: target.workspace,
|
|
1740
1586
|
container,
|
|
1741
1587
|
copiedEntries: createdTmpfsSeedPlan
|
|
1742
1588
|
});
|
|
@@ -12,23 +12,16 @@ import {
|
|
|
12
12
|
runBoundedSandboxHookCommand,
|
|
13
13
|
runSandboxHooks
|
|
14
14
|
} from '../agent-client-reconciler.ts';
|
|
15
|
-
import {
|
|
16
|
-
formatCredentialWarnings,
|
|
17
|
-
formatRemaining,
|
|
18
|
-
hasClaudeProviderAuth,
|
|
19
|
-
reconcileClaudeCredentials,
|
|
20
|
-
redactCommandError,
|
|
21
|
-
validateClaudeCredentialsEnvOverride
|
|
22
|
-
} from '../credentials.ts';
|
|
23
15
|
import { runInteractiveEngine } from '../shell.ts';
|
|
24
16
|
import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.ts';
|
|
17
|
+
import { redactCommandError } from '../redaction.ts';
|
|
25
18
|
import { runInteractiveWithClipboardBridge } from '../clipboard/bridge.ts';
|
|
26
19
|
import { detectHostTimezone } from '../host-timezone.ts';
|
|
27
20
|
import {
|
|
28
21
|
fetchSandboxRows,
|
|
29
|
-
resolveBranchArg,
|
|
30
22
|
selectSandboxContainer,
|
|
31
23
|
} from './list-running.ts';
|
|
24
|
+
import { resolveSandboxTarget } from '../workspace-identity.ts';
|
|
32
25
|
|
|
33
26
|
const USAGE = `Usage: ai sandbox exec [--recreate] <branch | TASK-id | N> [cmd...]
|
|
34
27
|
|
|
@@ -98,37 +91,6 @@ export function runSandboxInteractive(params: {
|
|
|
98
91
|
return runBridge({ engine, dockerArgs, container, home });
|
|
99
92
|
}
|
|
100
93
|
|
|
101
|
-
export function formatCredentialSyncStatus(
|
|
102
|
-
result: ReturnType<typeof reconcileClaudeCredentials>,
|
|
103
|
-
isTTY = process.stderr.isTTY,
|
|
104
|
-
providerAuthAvailable = false
|
|
105
|
-
): string | null {
|
|
106
|
-
if (providerAuthAvailable && (result.status === 'STALE_ACCESS' || result.status === 'MISSING')) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
if (result.status === 'STALE_ACCESS') {
|
|
110
|
-
return 'Warning: Claude Code credentials on host appear stale. Run "ai sandbox refresh" or "claude /login" to renew.\n';
|
|
111
|
-
}
|
|
112
|
-
if (result.status === 'MISSING') {
|
|
113
|
-
return 'Warning: Claude Code credentials missing on host. Run "claude /login" to authenticate.\n';
|
|
114
|
-
}
|
|
115
|
-
if (result.status === 'KEYCHAIN_WRITE_FAILED') {
|
|
116
|
-
return `Warning: A sandbox refresh produced newer credentials but host Keychain write failed (${formatCredentialWarnings(result.warnings)}). Run "ai sandbox refresh" again or "claude /status" on the host to retry.\n`;
|
|
117
|
-
}
|
|
118
|
-
if (result.status === 'KEYCHAIN_LOCKED' || result.status === 'KEYCHAIN_ERROR') {
|
|
119
|
-
return 'Warning: Host keychain is unavailable; Claude credential sync skipped. Run "ai sandbox refresh" for details.\n';
|
|
120
|
-
}
|
|
121
|
-
if (result.status === 'OK' && result.authoritative !== 'host') {
|
|
122
|
-
const message = `Synced Claude Code credentials from sandbox refresh back to host (expires in ${formatRemaining(result.expiresAt)})`;
|
|
123
|
-
return isTTY ? `\x1b[2m${message}\x1b[0m\n` : `${message}\n`;
|
|
124
|
-
}
|
|
125
|
-
if (result.status === 'OK' && result.filesWritten.length > 0) {
|
|
126
|
-
const message = `Synced Claude Code credentials from host Keychain (expires in ${formatRemaining(result.expiresAt)})`;
|
|
127
|
-
return isTTY ? `\x1b[2m${message}\x1b[0m\n` : `${message}\n`;
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
94
|
export function parseEnterArgs(args: string[]): {
|
|
133
95
|
target: string;
|
|
134
96
|
command: string[];
|
|
@@ -157,10 +119,10 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
157
119
|
}
|
|
158
120
|
|
|
159
121
|
const config = loadConfig();
|
|
160
|
-
validateClaudeCredentialsEnvOverride();
|
|
161
122
|
const engine = detectEngine(config);
|
|
162
123
|
const parsed = parseEnterArgs(args);
|
|
163
|
-
const
|
|
124
|
+
const target = resolveSandboxTarget(parsed.target, config.repoRoot);
|
|
125
|
+
const branch = target.branch;
|
|
164
126
|
assertValidBranchName(branch);
|
|
165
127
|
|
|
166
128
|
const { running, nonRunning } = fetchSandboxRows(
|
|
@@ -182,11 +144,12 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
182
144
|
config,
|
|
183
145
|
engine,
|
|
184
146
|
branch,
|
|
147
|
+
workspace: target.workspace,
|
|
185
148
|
row: found,
|
|
186
149
|
allowRecreate: parsed.recreate,
|
|
187
|
-
recreate: async (
|
|
150
|
+
recreate: async () => {
|
|
188
151
|
const { create } = await import('./create.ts');
|
|
189
|
-
await create([
|
|
152
|
+
await create([target.requestedRef, '--no-refresh']);
|
|
190
153
|
}
|
|
191
154
|
});
|
|
192
155
|
const container = ready.container;
|
|
@@ -195,7 +158,11 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
195
158
|
const enterHookResults = await runSandboxHooks({
|
|
196
159
|
hooks: capabilityPlan.hooksByPhase['before-enter'],
|
|
197
160
|
phase: 'before-enter',
|
|
198
|
-
context: {
|
|
161
|
+
context: {
|
|
162
|
+
config,
|
|
163
|
+
plan: capabilityPlan,
|
|
164
|
+
enter: { hostHome: config.home, hostEnv: { ...process.env } }
|
|
165
|
+
},
|
|
199
166
|
runCommand: runBoundedSandboxHookCommand
|
|
200
167
|
});
|
|
201
168
|
for (const result of enterHookResults) {
|
|
@@ -207,20 +174,7 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
207
174
|
`Warning: ${result.message ?? `Sandbox hook '${result.hookId}' did not complete.`}\n`
|
|
208
175
|
);
|
|
209
176
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (capabilityPlan.selectedAgentClients.some((adapter) => adapter.id === 'claude-code')) {
|
|
213
|
-
try {
|
|
214
|
-
// Scan all projects so a refresh from a neighbouring sandbox can still flow back to the host.
|
|
215
|
-
const providerAuthAvailable = hasClaudeProviderAuth(config.home);
|
|
216
|
-
const result = reconcileClaudeCredentials(config.home);
|
|
217
|
-
const message = formatCredentialSyncStatus(result, process.stderr.isTTY, providerAuthAvailable);
|
|
218
|
-
if (message) {
|
|
219
|
-
process.stderr.write(message);
|
|
220
|
-
}
|
|
221
|
-
} catch (error) {
|
|
222
|
-
process.stderr.write(`Warning: Failed to sync Claude Code credentials: ${redactCommandError(error instanceof Error ? error.message : 'unknown error')}\n`);
|
|
223
|
-
}
|
|
177
|
+
if (result.message && result.status !== 'warning') process.stderr.write(result.message);
|
|
224
178
|
}
|
|
225
179
|
|
|
226
180
|
const envFlags = [...terminalEnvFlags(), ...hostTimezoneEnvFlags()];
|