@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
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { runSafeEngine, runVerboseEngine } from '../shell.ts';
|
|
5
5
|
import { resolveTaskBranch } from '../task-resolver.ts';
|
|
6
6
|
import { isRemovedHashShortIdInput } from '../../task/short-id.ts';
|
|
7
|
+
import { parseSandboxWorkspaceIdentity } from '../workspace-identity.ts';
|
|
7
8
|
|
|
8
9
|
export type SandboxRow = {
|
|
9
10
|
name: string;
|
|
@@ -11,6 +12,8 @@ export type SandboxRow = {
|
|
|
11
12
|
branch: string;
|
|
12
13
|
running: boolean;
|
|
13
14
|
index: number | null;
|
|
15
|
+
workspaceMode?: 'task-bound' | 'branch-only' | 'legacy-invalid';
|
|
16
|
+
taskId?: string | null;
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
export function containerListFormat(): string {
|
|
@@ -36,19 +39,32 @@ export function parseLabels(csv: string): Record<string, string> {
|
|
|
36
39
|
return labels;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
export function parseSandboxRows(
|
|
42
|
+
export function parseSandboxRows(
|
|
43
|
+
rawOutput: string,
|
|
44
|
+
branchKey: string,
|
|
45
|
+
workspaceKeys?: Readonly<{ mode: string; taskId: string }>
|
|
46
|
+
): SandboxRow[] {
|
|
40
47
|
if (!rawOutput) {
|
|
41
48
|
return [];
|
|
42
49
|
}
|
|
43
50
|
return rawOutput.split('\n').map((line) => {
|
|
44
51
|
const [name = '', status = '', labelsCsv = ''] = line.split('\t');
|
|
45
|
-
const
|
|
52
|
+
const labels = parseLabels(labelsCsv);
|
|
53
|
+
const workspace = workspaceKeys
|
|
54
|
+
? parseSandboxWorkspaceIdentity(labels, workspaceKeys)
|
|
55
|
+
: null;
|
|
46
56
|
return {
|
|
47
57
|
name,
|
|
48
58
|
status,
|
|
49
|
-
branch,
|
|
59
|
+
branch: labels[branchKey] ?? '',
|
|
50
60
|
running: status.startsWith('Up '),
|
|
51
|
-
index: null
|
|
61
|
+
index: null,
|
|
62
|
+
...(workspace
|
|
63
|
+
? {
|
|
64
|
+
workspaceMode: workspace.mode,
|
|
65
|
+
taskId: workspace.mode === 'task-bound' ? workspace.taskId : null
|
|
66
|
+
}
|
|
67
|
+
: {})
|
|
52
68
|
};
|
|
53
69
|
});
|
|
54
70
|
}
|
|
@@ -76,7 +92,8 @@ export function sortAndIndexSandboxRows(rows: SandboxRow[]): {
|
|
|
76
92
|
export function fetchSandboxRows(
|
|
77
93
|
engine: string,
|
|
78
94
|
label: string,
|
|
79
|
-
branchKey: string
|
|
95
|
+
branchKey: string,
|
|
96
|
+
workspaceKeys?: Readonly<{ mode: string; taskId: string }>
|
|
80
97
|
): { running: SandboxRow[]; nonRunning: SandboxRow[] } {
|
|
81
98
|
const raw = runSafeEngine(engine, 'docker', [
|
|
82
99
|
'ps',
|
|
@@ -86,7 +103,7 @@ export function fetchSandboxRows(
|
|
|
86
103
|
'--format',
|
|
87
104
|
containerListFormat()
|
|
88
105
|
]);
|
|
89
|
-
return sortAndIndexSandboxRows(parseSandboxRows(raw, branchKey));
|
|
106
|
+
return sortAndIndexSandboxRows(parseSandboxRows(raw, branchKey, workspaceKeys));
|
|
90
107
|
}
|
|
91
108
|
|
|
92
109
|
/**
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
3
|
import { loadConfig } from '../config.ts';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
sandboxBranchLabel,
|
|
6
|
+
sandboxLabel,
|
|
7
|
+
sandboxTaskIdLabel,
|
|
8
|
+
sandboxWorkspaceModeLabel
|
|
9
|
+
} from '../constants.ts';
|
|
5
10
|
import { detectEngine } from '../engine.ts';
|
|
6
11
|
import { formatTable } from '../../table.ts';
|
|
7
|
-
import {
|
|
12
|
+
import { loadShortIdByTaskId } from '../../task/short-id.ts';
|
|
8
13
|
import { fetchSandboxRows } from './list-running.ts';
|
|
9
14
|
|
|
10
15
|
export { containerListFormat, parseLabels } from './list-running.ts';
|
|
@@ -22,20 +27,22 @@ to remove with "ai sandbox rm <branch>".
|
|
|
22
27
|
Use "ai sandbox show <ref>" for a single sandbox's worktree and per-tool
|
|
23
28
|
state paths.`;
|
|
24
29
|
|
|
25
|
-
const CONTAINER_TABLE_HEADERS = ['#', 'SHORT', 'NAMES', 'STATUS', 'BRANCH'] as const;
|
|
30
|
+
const CONTAINER_TABLE_HEADERS = ['#', 'SHORT', 'NAMES', 'STATUS', 'WORKSPACE', 'TASK', 'BRANCH'] as const;
|
|
26
31
|
|
|
27
32
|
type ContainerTableRow = {
|
|
28
33
|
row: string;
|
|
29
34
|
shortId: string;
|
|
30
35
|
name: string;
|
|
31
36
|
status: string;
|
|
37
|
+
workspace: string;
|
|
38
|
+
taskId: string;
|
|
32
39
|
branch: string;
|
|
33
40
|
};
|
|
34
41
|
|
|
35
42
|
export function formatContainerTable(rows: ContainerTableRow[], zebra = false): string[] {
|
|
36
43
|
return formatTable(
|
|
37
44
|
CONTAINER_TABLE_HEADERS,
|
|
38
|
-
rows.map((r) => [r.row, r.shortId, r.name, r.status, r.branch]),
|
|
45
|
+
rows.map((r) => [r.row, r.shortId, r.name, r.status, r.workspace, r.taskId, r.branch]),
|
|
39
46
|
{ zebra }
|
|
40
47
|
);
|
|
41
48
|
}
|
|
@@ -49,7 +56,12 @@ export function ls(args: string[] = []): void {
|
|
|
49
56
|
const config = loadConfig();
|
|
50
57
|
const engine = detectEngine(config);
|
|
51
58
|
const label = sandboxLabel(config);
|
|
52
|
-
const { running, nonRunning } = fetchSandboxRows(
|
|
59
|
+
const { running, nonRunning } = fetchSandboxRows(
|
|
60
|
+
engine,
|
|
61
|
+
label,
|
|
62
|
+
sandboxBranchLabel(config),
|
|
63
|
+
{ mode: sandboxWorkspaceModeLabel(config), taskId: sandboxTaskIdLabel(config) }
|
|
64
|
+
);
|
|
53
65
|
|
|
54
66
|
p.intro(pc.cyan(`Sandbox status for ${config.project}`));
|
|
55
67
|
|
|
@@ -59,12 +71,16 @@ export function ls(args: string[] = []): void {
|
|
|
59
71
|
p.log.warn(' No sandbox containers');
|
|
60
72
|
} else {
|
|
61
73
|
const tableRows: ContainerTableRow[] = ordered.map((container, i) => {
|
|
62
|
-
const shortId = container.
|
|
74
|
+
const shortId = container.taskId
|
|
75
|
+
? loadShortIdByTaskId(config.repoRoot).get(container.taskId) ?? null
|
|
76
|
+
: null;
|
|
63
77
|
return {
|
|
64
78
|
row: String(i + 1),
|
|
65
79
|
shortId: shortId ?? '-',
|
|
66
80
|
name: container.name,
|
|
67
81
|
status: container.status,
|
|
82
|
+
workspace: container.workspaceMode ?? 'legacy-invalid',
|
|
83
|
+
taskId: container.taskId ?? '-',
|
|
68
84
|
branch: container.branch
|
|
69
85
|
};
|
|
70
86
|
});
|
|
@@ -8,8 +8,8 @@ import { sandboxImageRefreshLabel } from '../constants.ts';
|
|
|
8
8
|
import { detectEngine, ensureDocker } from '../engine.ts';
|
|
9
9
|
import { runEngine, runOkEngine, runSafeEngine, runVerboseEngine } from '../shell.ts';
|
|
10
10
|
import { pruneSandboxDanglingImages } from '../image-prune.ts';
|
|
11
|
-
import { resolveTools } from '../tools.ts';
|
|
12
11
|
import type { SandboxTool } from '../tools.ts';
|
|
12
|
+
import { createSandboxCapabilityPlan } from '../agent-client-reconciler.ts';
|
|
13
13
|
import {
|
|
14
14
|
buildImageSignature,
|
|
15
15
|
buildSandboxImageArgs,
|
|
@@ -97,8 +97,9 @@ export async function rebuild(args: string[]): Promise<void> {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
const config = loadConfig();
|
|
100
|
-
const
|
|
101
|
-
const
|
|
100
|
+
const capabilityPlan = createSandboxCapabilityPlan(config);
|
|
101
|
+
const tools = [...capabilityPlan.tools];
|
|
102
|
+
const preparedDockerfile = prepareDockerfile(config, capabilityPlan.image);
|
|
102
103
|
const imageSignature = buildImageSignature(preparedDockerfile, tools);
|
|
103
104
|
const quiet = values.quiet ?? false;
|
|
104
105
|
const refresh = values.refresh ?? false;
|
|
@@ -1,128 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseArgs } from 'node:util';
|
|
3
|
-
import {
|
|
4
|
-
buildLockedGuidance,
|
|
5
|
-
discoverProjects,
|
|
6
|
-
formatCredentialWarnings,
|
|
7
|
-
formatRemaining,
|
|
8
|
-
reconcileClaudeCredentials,
|
|
9
|
-
redactCommandError,
|
|
10
|
-
validateClaudeCredentialsEnvOverride
|
|
11
|
-
} from '../credentials.ts';
|
|
12
|
-
import { runProbe } from '../shell.ts';
|
|
1
|
+
import { runClaudeCodeRefresh } from '../../agent-clients/adapters/claude-code-refresh.ts';
|
|
13
2
|
|
|
14
|
-
const
|
|
3
|
+
const refresh = runClaudeCodeRefresh;
|
|
15
4
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type RefreshDeps = Partial<ReconcileOptions> & {
|
|
19
|
-
spawnFn?: typeof runProbe;
|
|
20
|
-
discoverFn?: typeof discoverProjects;
|
|
21
|
-
writeStdout?: (chunk: string) => unknown;
|
|
22
|
-
writeStderr?: (chunk: string) => unknown;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export function probeClaudeStatus(spawnFn: typeof runProbe = runProbe): { ok: boolean; stderr: string; error: string | null } {
|
|
26
|
-
const result = spawnFn('claude', ['/status'], {
|
|
27
|
-
encoding: 'utf8',
|
|
28
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
|
-
timeout: 30_000
|
|
30
|
-
});
|
|
31
|
-
return {
|
|
32
|
-
ok: result.status === 0,
|
|
33
|
-
stderr: result.stderr?.toString() ?? '',
|
|
34
|
-
error: result.error?.message ?? null
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function refresh(args: string[], deps: RefreshDeps = {}): Promise<number> {
|
|
39
|
-
const {
|
|
40
|
-
spawnFn = runProbe,
|
|
41
|
-
execFn,
|
|
42
|
-
readFn,
|
|
43
|
-
existsFn,
|
|
44
|
-
writeFn,
|
|
45
|
-
writeHostFn,
|
|
46
|
-
discoverFn = discoverProjects,
|
|
47
|
-
writeStdout = (chunk: string) => process.stdout.write(chunk),
|
|
48
|
-
writeStderr = (chunk: string) => process.stderr.write(chunk)
|
|
49
|
-
} = deps;
|
|
50
|
-
|
|
51
|
-
if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
|
|
52
|
-
writeStdout(`${USAGE}\n`);
|
|
53
|
-
return 0;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const { positionals } = parseArgs({ args, allowPositionals: true, strict: true });
|
|
57
|
-
if (positionals.length > 0) {
|
|
58
|
-
throw new Error(USAGE);
|
|
59
|
-
}
|
|
60
|
-
validateClaudeCredentialsEnvOverride();
|
|
61
|
-
|
|
62
|
-
const home = homedir();
|
|
63
|
-
if (!home) {
|
|
64
|
-
throw new Error('sandbox: home directory is required');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const projects = discoverFn(home);
|
|
68
|
-
if (projects.length === 0) {
|
|
69
|
-
writeStdout('No project credentials to refresh.\n');
|
|
70
|
-
return 0;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const reconcileOptions = { execFn, readFn, existsFn, writeFn, writeHostFn, projects };
|
|
74
|
-
let result = reconcileClaudeCredentials(home, reconcileOptions);
|
|
75
|
-
if (result.status === 'STALE_ACCESS' && result.authoritative === null) {
|
|
76
|
-
writeStdout('Host credentials appear stale; probing claude /status to trigger refresh...\n');
|
|
77
|
-
const probe = probeClaudeStatus(spawnFn);
|
|
78
|
-
if (!probe.ok) {
|
|
79
|
-
writeStderr(`Probe failed: ${redactCommandError(probe.stderr || probe.error || 'unknown error')}\n`);
|
|
80
|
-
writeStderr('Run "claude /login" on the host to renew credentials.\n');
|
|
81
|
-
return 1;
|
|
82
|
-
}
|
|
83
|
-
writeStdout('Probe succeeded; re-inspecting host credentials.\n');
|
|
84
|
-
result = reconcileClaudeCredentials(home, reconcileOptions);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (result.status === 'MISSING') {
|
|
88
|
-
writeStderr('No Claude Code credentials found on host.\n');
|
|
89
|
-
writeStderr('Run "claude /login" on the host to authenticate.\n');
|
|
90
|
-
return 1;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (result.status === 'KEYCHAIN_LOCKED') {
|
|
94
|
-
writeStderr(`${buildLockedGuidance()}\n`);
|
|
95
|
-
return 1;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (result.status === 'KEYCHAIN_ERROR') {
|
|
99
|
-
writeStderr(`Host keychain error: ${redactCommandError(result.detail || 'unknown error')}\n`);
|
|
100
|
-
writeStderr(`${buildLockedGuidance()}\n`);
|
|
101
|
-
return 1;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (result.status === 'KEYCHAIN_WRITE_FAILED') {
|
|
105
|
-
writeStderr(`[host] keychain write failed: ${formatCredentialWarnings(result.warnings) || 'unknown error'}\n`);
|
|
106
|
-
return 1;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (result.status !== 'OK') {
|
|
110
|
-
writeStderr('Host credentials still invalid after probe; run "claude /login".\n');
|
|
111
|
-
return 1;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (result.authoritative && result.authoritative !== 'host' && result.hostWritten) {
|
|
115
|
-
writeStdout(`[host] reconciled from ${result.authoritative}\n`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
for (const project of projects) {
|
|
119
|
-
const action = result.filesWritten.includes(project) ? 'updated' : 'unchanged';
|
|
120
|
-
writeStdout(`[${project}] ${action}; expires in ${formatRemaining(result.expiresAt)}\n`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
for (const failure of result.fileErrors) {
|
|
124
|
-
writeStderr(`[${failure.project}] sync failed: ${failure.error}\n`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return result.fileErrors.length > 0 ? 1 : 0;
|
|
128
|
-
}
|
|
5
|
+
export { probeClaudeStatus, runClaudeCodeRefresh } from '../../agent-clients/adapters/claude-code-refresh.ts';
|
|
6
|
+
export { refresh };
|
|
@@ -18,7 +18,7 @@ import { ENGINES, detectEngine, engineDisplayName, isManagedEngine, stopManagedV
|
|
|
18
18
|
import { pruneSandboxDanglingImages } from '../image-prune.ts';
|
|
19
19
|
import { removeManagedDir, removeWorktreeDir } from '../managed-fs.ts';
|
|
20
20
|
import { runOk, runSafe, runSafeEngine } from '../shell.ts';
|
|
21
|
-
import {
|
|
21
|
+
import { resolveSandboxTarget } from '../workspace-identity.ts';
|
|
22
22
|
import { toolConfigDirCandidates, toolProjectDirCandidates } from '../tools.ts';
|
|
23
23
|
import { createSandboxCapabilityPlan } from '../agent-client-reconciler.ts';
|
|
24
24
|
import type { SandboxTool } from '../tools.ts';
|
|
@@ -81,6 +81,16 @@ async function rmOne(
|
|
|
81
81
|
for (const name of matchedContainers) {
|
|
82
82
|
runSafeEngine(engine, 'docker', ['stop', name]);
|
|
83
83
|
runSafeEngine(engine, 'docker', ['rm', name]);
|
|
84
|
+
for (const [base, label] of [
|
|
85
|
+
[path.join(config.workspaceViewBase, config.project), 'Workspace view'],
|
|
86
|
+
[path.join(config.controlBase, config.project), 'Control channel']
|
|
87
|
+
] as const) {
|
|
88
|
+
const directory = path.join(base, name);
|
|
89
|
+
if (fs.existsSync(directory)) {
|
|
90
|
+
removeManagedDir(base, directory);
|
|
91
|
+
if (!options.quiet) p.log.success(`${label} removed: ${directory}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
spinner.stop(pc.green(`Removed container(s): ${matchedContainers.join(', ')}`));
|
|
86
96
|
} else {
|
|
@@ -224,6 +234,17 @@ async function rmPurge(config: SandboxConfig, tools: SandboxTool[]): Promise<voi
|
|
|
224
234
|
}
|
|
225
235
|
}
|
|
226
236
|
|
|
237
|
+
for (const [base, label] of [
|
|
238
|
+
[config.workspaceViewBase, 'workspace views'],
|
|
239
|
+
[config.controlBase, 'control channels']
|
|
240
|
+
] as const) {
|
|
241
|
+
const projectDir = path.join(base, config.project);
|
|
242
|
+
if (fs.existsSync(projectDir)) {
|
|
243
|
+
removeManagedDir(base, projectDir);
|
|
244
|
+
p.log.success(`Removed project ${label}: ${projectDir}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
227
248
|
const shouldRemoveImage = await p.confirm({
|
|
228
249
|
message: `Remove image ${config.imageName}?`,
|
|
229
250
|
initialValue: false
|
|
@@ -369,6 +390,6 @@ export async function rm(args: string[]): Promise<void> {
|
|
|
369
390
|
return;
|
|
370
391
|
}
|
|
371
392
|
|
|
372
|
-
const
|
|
373
|
-
await rmOne(config, tools, branch);
|
|
393
|
+
const target = resolveSandboxTarget(positionals[0] ?? '', config.repoRoot);
|
|
394
|
+
await rmOne(config, tools, target.branch);
|
|
374
395
|
}
|
|
@@ -3,14 +3,24 @@ import * as p from '@clack/prompts';
|
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import type { SandboxConfig } from '../config.ts';
|
|
5
5
|
import { loadConfig } from '../config.ts';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
assertValidBranchName,
|
|
8
|
+
containerNameCandidates,
|
|
9
|
+
sandboxBranchLabel,
|
|
10
|
+
sandboxLabel,
|
|
11
|
+
sandboxTaskIdLabel,
|
|
12
|
+
sandboxWorkspaceModeLabel,
|
|
13
|
+
worktreeDirCandidates
|
|
14
|
+
} from '../constants.ts';
|
|
15
|
+
import { fetchSandboxRows, selectSandboxContainer } from './list-running.ts';
|
|
8
16
|
import { resolveTools, toolConfigDirCandidates } from '../tools.ts';
|
|
17
|
+
import { detectEngine } from '../engine.ts';
|
|
18
|
+
import { resolveSandboxTarget } from '../workspace-identity.ts';
|
|
9
19
|
|
|
10
20
|
const USAGE = `Usage: ai sandbox show <branch | TASK-id | N>
|
|
11
21
|
|
|
12
22
|
Shows one sandbox's worktree path and per-tool state paths (Claude Code,
|
|
13
|
-
Codex,
|
|
23
|
+
Codex, Antigravity CLI, OpenCode). The argument follows the same contract as
|
|
14
24
|
'ai sandbox exec' and 'ai sandbox start': N (bare) is the recommended form
|
|
15
25
|
for task short ids (e.g. 'ai sandbox show 11'); a TASK-id or a plain
|
|
16
26
|
branch name are also accepted. Use 'ai sandbox ls' for the container list.`;
|
|
@@ -51,10 +61,22 @@ export function show(args: string[] = []): void {
|
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
const config = loadConfig();
|
|
54
|
-
const
|
|
64
|
+
const target = resolveSandboxTarget(args[0]!, config.repoRoot);
|
|
65
|
+
const branch = target.branch;
|
|
55
66
|
assertValidBranchName(branch);
|
|
56
67
|
|
|
57
68
|
const detail = collectSandboxDetail(config, branch);
|
|
69
|
+
const engine = detectEngine(config);
|
|
70
|
+
const rows = fetchSandboxRows(
|
|
71
|
+
engine,
|
|
72
|
+
sandboxLabel(config),
|
|
73
|
+
sandboxBranchLabel(config),
|
|
74
|
+
{ mode: sandboxWorkspaceModeLabel(config), taskId: sandboxTaskIdLabel(config) }
|
|
75
|
+
);
|
|
76
|
+
const container = selectSandboxContainer(
|
|
77
|
+
[...rows.running, ...rows.nonRunning],
|
|
78
|
+
containerNameCandidates(config, branch)
|
|
79
|
+
);
|
|
58
80
|
|
|
59
81
|
p.intro(pc.cyan(`Sandbox detail for ${config.project} · ${branch}`));
|
|
60
82
|
|
|
@@ -67,6 +89,10 @@ export function show(args: string[] = []): void {
|
|
|
67
89
|
}
|
|
68
90
|
}
|
|
69
91
|
|
|
92
|
+
p.log.step('Workspace identity');
|
|
93
|
+
process.stdout.write(` Mode: ${container?.workspaceMode ?? 'legacy-invalid'}\n`);
|
|
94
|
+
process.stdout.write(` Task: ${container?.taskId ?? '-'}\n`);
|
|
95
|
+
|
|
70
96
|
for (const tool of detail.toolStates) {
|
|
71
97
|
p.log.step(`${tool.name} state`);
|
|
72
98
|
if (tool.entries.length === 0) {
|
|
@@ -9,9 +9,9 @@ import { detectEngine } from '../engine.ts';
|
|
|
9
9
|
import { ensureSandboxReady } from '../recovery.ts';
|
|
10
10
|
import {
|
|
11
11
|
fetchSandboxRows,
|
|
12
|
-
resolveBranchArg,
|
|
13
12
|
selectSandboxContainer,
|
|
14
13
|
} from './list-running.ts';
|
|
14
|
+
import { resolveSandboxTarget } from '../workspace-identity.ts';
|
|
15
15
|
|
|
16
16
|
const USAGE = `Usage: ai sandbox start [--recreate] <branch | TASK-id | N>
|
|
17
17
|
|
|
@@ -56,7 +56,8 @@ export async function start(args: string[]): Promise<void> {
|
|
|
56
56
|
|
|
57
57
|
const config = loadConfig();
|
|
58
58
|
const engine = detectEngine(config);
|
|
59
|
-
const
|
|
59
|
+
const target = resolveSandboxTarget(parsed.target, config.repoRoot);
|
|
60
|
+
const branch = target.branch;
|
|
60
61
|
assertValidBranchName(branch);
|
|
61
62
|
|
|
62
63
|
const { running, nonRunning } = fetchSandboxRows(
|
|
@@ -79,11 +80,12 @@ export async function start(args: string[]): Promise<void> {
|
|
|
79
80
|
config,
|
|
80
81
|
engine,
|
|
81
82
|
branch,
|
|
83
|
+
workspace: target.workspace,
|
|
82
84
|
row: found,
|
|
83
85
|
allowRecreate: parsed.recreate,
|
|
84
|
-
recreate: async (
|
|
86
|
+
recreate: async () => {
|
|
85
87
|
const { create } = await import('./create.ts');
|
|
86
|
-
await create([
|
|
88
|
+
await create([target.requestedRef, '--no-refresh']);
|
|
87
89
|
}
|
|
88
90
|
});
|
|
89
91
|
const message = ready.path === 'healthy'
|
package/lib/sandbox/config.ts
CHANGED
|
@@ -55,6 +55,8 @@ export type SandboxConfig = {
|
|
|
55
55
|
worktreeBase: string;
|
|
56
56
|
shareBase: string;
|
|
57
57
|
shellConfigBase: string;
|
|
58
|
+
workspaceViewBase: string;
|
|
59
|
+
controlBase: string;
|
|
58
60
|
dotfilesDir: string;
|
|
59
61
|
engine: string | null;
|
|
60
62
|
runtimes: string[];
|
|
@@ -188,6 +190,8 @@ export function loadConfig({
|
|
|
188
190
|
worktreeBase: hostJoin(home, '.agent-infra', 'worktrees', project),
|
|
189
191
|
shareBase: hostJoin(home, '.agent-infra', 'share', project),
|
|
190
192
|
shellConfigBase: hostJoin(home, '.agent-infra', 'config', project),
|
|
193
|
+
workspaceViewBase: hostJoin(home, '.agent-infra', 'workspace-views'),
|
|
194
|
+
controlBase: hostJoin(home, '.agent-infra', 'sandbox-control'),
|
|
191
195
|
dotfilesDir: hostJoin(home, '.agent-infra', 'dotfiles'),
|
|
192
196
|
engine,
|
|
193
197
|
runtimes,
|
package/lib/sandbox/constants.ts
CHANGED
|
@@ -103,6 +103,14 @@ export function sandboxBranchLabel(config: Pick<SandboxPathConfig, 'project'>):
|
|
|
103
103
|
return `${sandboxLabel(config)}.branch`;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
export function sandboxWorkspaceModeLabel(config: Pick<SandboxPathConfig, 'project'>): string {
|
|
107
|
+
return `${sandboxLabel(config)}.workspace-mode`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function sandboxTaskIdLabel(config: Pick<SandboxPathConfig, 'project'>): string {
|
|
111
|
+
return `${sandboxLabel(config)}.task-id`;
|
|
112
|
+
}
|
|
113
|
+
|
|
106
114
|
export function sandboxImageConfigLabel(config: Pick<SandboxPathConfig, 'project'>): string {
|
|
107
115
|
return `${sandboxLabel(config)}.image-config`;
|
|
108
116
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import {
|
|
5
|
+
SANDBOX_CONTROL_MAX_BYTES,
|
|
6
|
+
isSandboxControlFamily,
|
|
7
|
+
type SandboxControlRequest,
|
|
8
|
+
type SandboxControlResponse
|
|
9
|
+
} from './protocol.ts';
|
|
10
|
+
|
|
11
|
+
function sleep(milliseconds: number): void {
|
|
12
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function requestSandboxControl(params: Readonly<{
|
|
16
|
+
family: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
channelDir?: string;
|
|
19
|
+
token?: string;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
}>): SandboxControlResponse {
|
|
22
|
+
if (!isSandboxControlFamily(params.family)) {
|
|
23
|
+
throw new Error(`SANDBOX_CONTROL_COMMAND_DENIED: '${params.family}' is not allowed`);
|
|
24
|
+
}
|
|
25
|
+
const channelDir = params.channelDir ?? process.env.AGENT_INFRA_CONTROL_DIR ?? '/run/agent-infra/control';
|
|
26
|
+
const token = params.token ?? process.env.AGENT_INFRA_CONTROL_TOKEN;
|
|
27
|
+
if (!token) throw new Error('SANDBOX_CONTROL_UNAVAILABLE: control token is missing');
|
|
28
|
+
const requestsDir = path.join(channelDir, 'requests');
|
|
29
|
+
const responsesDir = path.join(channelDir, 'responses');
|
|
30
|
+
const id = randomUUID();
|
|
31
|
+
const request: SandboxControlRequest = { version: 1, id, token, family: params.family, args: params.args };
|
|
32
|
+
const encoded = `${JSON.stringify(request)}\n`;
|
|
33
|
+
if (Buffer.byteLength(encoded, 'utf8') > SANDBOX_CONTROL_MAX_BYTES) {
|
|
34
|
+
throw new Error('SANDBOX_CONTROL_REQUEST_TOO_LARGE: request exceeds the control limit');
|
|
35
|
+
}
|
|
36
|
+
const temporary = path.join(requestsDir, `.${id}.tmp`);
|
|
37
|
+
const requestPath = path.join(requestsDir, `${id}.json`);
|
|
38
|
+
const responsePath = path.join(responsesDir, `${id}.json`);
|
|
39
|
+
fs.writeFileSync(temporary, encoded, { mode: 0o600, flag: 'wx' });
|
|
40
|
+
fs.renameSync(temporary, requestPath);
|
|
41
|
+
const deadline = Date.now() + (params.timeoutMs ?? 30_000);
|
|
42
|
+
while (Date.now() < deadline) {
|
|
43
|
+
if (fs.existsSync(responsePath)) {
|
|
44
|
+
const raw = fs.readFileSync(responsePath, 'utf8');
|
|
45
|
+
fs.unlinkSync(responsePath);
|
|
46
|
+
const response = JSON.parse(raw) as SandboxControlResponse;
|
|
47
|
+
if (response.version !== 1 || response.id !== id || !Number.isInteger(response.exitCode)) {
|
|
48
|
+
throw new Error('SANDBOX_CONTROL_RESPONSE_INVALID: broker response is invalid');
|
|
49
|
+
}
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
sleep(25);
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`SANDBOX_CONTROL_TIMEOUT: broker did not respond within ${params.timeoutMs ?? 30_000}ms`);
|
|
55
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const SANDBOX_CONTROL_MAX_BYTES = 64 * 1024;
|
|
2
|
+
export const SANDBOX_CONTROL_FAMILIES = ['task-lifecycle', 'task-orchestration'] as const;
|
|
3
|
+
|
|
4
|
+
export type SandboxControlFamily = typeof SANDBOX_CONTROL_FAMILIES[number];
|
|
5
|
+
|
|
6
|
+
export type SandboxControlManifest = Readonly<{
|
|
7
|
+
version: 1;
|
|
8
|
+
repoRoot: string;
|
|
9
|
+
project: string;
|
|
10
|
+
container: string;
|
|
11
|
+
branch: string;
|
|
12
|
+
mode: 'task-bound' | 'branch-only';
|
|
13
|
+
taskId: string | null;
|
|
14
|
+
token: string;
|
|
15
|
+
channelDir: string;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
export type SandboxControlRequest = Readonly<{
|
|
19
|
+
version: 1;
|
|
20
|
+
id: string;
|
|
21
|
+
token: string;
|
|
22
|
+
family: SandboxControlFamily;
|
|
23
|
+
args: string[];
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export type SandboxControlResponse = Readonly<{
|
|
27
|
+
version: 1;
|
|
28
|
+
id: string;
|
|
29
|
+
exitCode: number;
|
|
30
|
+
stdout: string;
|
|
31
|
+
stderr: string;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
34
|
+
export function isSandboxControlFamily(value: string): value is SandboxControlFamily {
|
|
35
|
+
return SANDBOX_CONTROL_FAMILIES.includes(value as SandboxControlFamily);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function validateSandboxControlRequest(
|
|
39
|
+
value: unknown,
|
|
40
|
+
manifest: SandboxControlManifest
|
|
41
|
+
): SandboxControlRequest {
|
|
42
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
43
|
+
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: request must be an object');
|
|
44
|
+
}
|
|
45
|
+
const request = value as Partial<SandboxControlRequest>;
|
|
46
|
+
if (
|
|
47
|
+
request.version !== 1
|
|
48
|
+
|| typeof request.id !== 'string'
|
|
49
|
+
|| !/^[a-f0-9-]{16,64}$/.test(request.id)
|
|
50
|
+
|| request.token !== manifest.token
|
|
51
|
+
|| typeof request.family !== 'string'
|
|
52
|
+
|| !isSandboxControlFamily(request.family)
|
|
53
|
+
|| !Array.isArray(request.args)
|
|
54
|
+
|| !request.args.every((arg) => typeof arg === 'string')
|
|
55
|
+
) {
|
|
56
|
+
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: request schema or authorization is invalid');
|
|
57
|
+
}
|
|
58
|
+
if (manifest.mode !== 'task-bound' || !manifest.taskId) {
|
|
59
|
+
throw new Error('SANDBOX_CONTROL_BRANCH_ONLY: branch-only sandboxes cannot coordinate tasks');
|
|
60
|
+
}
|
|
61
|
+
if (Buffer.byteLength(JSON.stringify(request), 'utf8') > SANDBOX_CONTROL_MAX_BYTES) {
|
|
62
|
+
throw new Error('SANDBOX_CONTROL_REQUEST_TOO_LARGE: request exceeds the control limit');
|
|
63
|
+
}
|
|
64
|
+
return request as SandboxControlRequest;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function bindSandboxControlTask(
|
|
68
|
+
request: SandboxControlRequest,
|
|
69
|
+
taskId: string
|
|
70
|
+
): string[] {
|
|
71
|
+
if (request.args.length === 0) {
|
|
72
|
+
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: command arguments are required');
|
|
73
|
+
}
|
|
74
|
+
return [taskId, ...request.args.slice(1)];
|
|
75
|
+
}
|