@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
|
@@ -64,69 +64,9 @@ RUN printf '%s\n' \
|
|
|
64
64
|
'set -g mouse on' \
|
|
65
65
|
'set -g status-interval 1' \
|
|
66
66
|
'set -g status-right-length 80' \
|
|
67
|
-
"set -g status-right '
|
|
67
|
+
"set -g status-right '%H:%M'" \
|
|
68
68
|
> /etc/tmux.conf
|
|
69
69
|
|
|
70
|
-
RUN cat > /usr/local/bin/cc-token-status <<'SCRIPT' && chmod +x /usr/local/bin/cc-token-status
|
|
71
|
-
#!/bin/sh
|
|
72
|
-
set -eu
|
|
73
|
-
|
|
74
|
-
SETTINGS_FILE="/home/devuser/.claude/settings.json"
|
|
75
|
-
if [ -r "$SETTINGS_FILE" ] && jq -e '
|
|
76
|
-
def has_nonempty($v):
|
|
77
|
-
if ($v | type) == "string" then ($v | gsub("^\\s+|\\s+$"; "") | length) > 0 else false end;
|
|
78
|
-
(if type == "object" then . else {} end) as $settings
|
|
79
|
-
| (if ($settings.env | type) == "object" then $settings.env else {} end) as $env
|
|
80
|
-
| has_nonempty($env.ANTHROPIC_AUTH_TOKEN)
|
|
81
|
-
or has_nonempty($env.ANTHROPIC_API_KEY)
|
|
82
|
-
or has_nonempty($settings.apiKeyHelper)
|
|
83
|
-
' "$SETTINGS_FILE" >/dev/null 2>&1; then
|
|
84
|
-
exit 0
|
|
85
|
-
fi
|
|
86
|
-
|
|
87
|
-
CRED_FILE="/home/devuser/.claude/.credentials.json"
|
|
88
|
-
[ -r "$CRED_FILE" ] || exit 0
|
|
89
|
-
|
|
90
|
-
EXPIRES_MS=$(jq -r '(.claudeAiOauth.expiresAt // .expiresAt) // empty' "$CRED_FILE" 2>/dev/null || true)
|
|
91
|
-
case "$EXPIRES_MS" in
|
|
92
|
-
''|*[!0-9]*) exit 0 ;;
|
|
93
|
-
esac
|
|
94
|
-
|
|
95
|
-
NOW_MS=$(($(date +%s) * 1000))
|
|
96
|
-
DIFF_MS=$((EXPIRES_MS - NOW_MS))
|
|
97
|
-
DIFF_S=$((DIFF_MS / 1000))
|
|
98
|
-
|
|
99
|
-
DIM='#[fg=colour245]'
|
|
100
|
-
YELLOW='#[fg=yellow]'
|
|
101
|
-
YELLOW_BOLD='#[fg=yellow,bold]'
|
|
102
|
-
RED_BOLD='#[fg=red,bold]'
|
|
103
|
-
RED_REV='#[fg=red,reverse]'
|
|
104
|
-
RESET='#[default]'
|
|
105
|
-
|
|
106
|
-
if [ "$DIFF_S" -le 0 ]; then
|
|
107
|
-
ELAPSED=$(( -DIFF_S ))
|
|
108
|
-
M=$((ELAPSED / 60))
|
|
109
|
-
printf '%sClaude Code auth EXPIRED %dm ago%s' "$RED_REV" "$M" "$RESET"
|
|
110
|
-
elif [ "$DIFF_S" -lt 60 ]; then
|
|
111
|
-
printf '%sClaude Code auth expires in %ds%s' "$RED_BOLD" "$DIFF_S" "$RESET"
|
|
112
|
-
elif [ "$DIFF_S" -lt 300 ]; then
|
|
113
|
-
M=$((DIFF_S / 60))
|
|
114
|
-
S=$((DIFF_S % 60))
|
|
115
|
-
printf '%sClaude Code auth expires in %dm %ds%s' "$RED_BOLD" "$M" "$S" "$RESET"
|
|
116
|
-
elif [ "$DIFF_S" -lt 1800 ]; then
|
|
117
|
-
M=$((DIFF_S / 60))
|
|
118
|
-
printf '%sClaude Code auth expires in %dm%s' "$YELLOW_BOLD" "$M" "$RESET"
|
|
119
|
-
elif [ "$DIFF_S" -lt 3600 ]; then
|
|
120
|
-
M=$((DIFF_S / 60))
|
|
121
|
-
printf '%sClaude Code auth expires in %dm%s' "$YELLOW" "$M" "$RESET"
|
|
122
|
-
else
|
|
123
|
-
TOTAL_M=$((DIFF_S / 60))
|
|
124
|
-
H=$((TOTAL_M / 60))
|
|
125
|
-
M=$((TOTAL_M % 60))
|
|
126
|
-
printf '%sClaude Code auth expires in %dh %dm%s' "$DIM" "$H" "$M" "$RESET"
|
|
127
|
-
fi
|
|
128
|
-
SCRIPT
|
|
129
|
-
|
|
130
70
|
RUN cat > /usr/local/bin/sandbox-dotfiles-link <<'SCRIPT' && chmod +x /usr/local/bin/sandbox-dotfiles-link
|
|
131
71
|
#!/bin/sh
|
|
132
72
|
# Mirror /dotfiles/ tree as symlinks under $HOME/, overwriting any image-baked
|
|
@@ -136,23 +76,34 @@ set -eu
|
|
|
136
76
|
DOTFILES_SRC=/dotfiles
|
|
137
77
|
[ -d "$DOTFILES_SRC" ] || exit 0
|
|
138
78
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
target="$HOME/$rel"
|
|
143
|
-
case "$rel" in
|
|
79
|
+
is_dotfiles_excluded() {
|
|
80
|
+
candidate=$1
|
|
81
|
+
case "$candidate" in
|
|
144
82
|
.ssh|.ssh/*|\
|
|
145
83
|
.gnupg|.gnupg/*|\
|
|
146
|
-
.claude|.claude/*|\
|
|
147
|
-
.codex|.codex/*|\
|
|
148
|
-
.gemini|.gemini/*|\
|
|
149
|
-
.config/opencode|.config/opencode/*|\
|
|
150
|
-
.local/share/opencode|.local/share/opencode/*|\
|
|
151
84
|
.host-shell-config|.host-shell-config/*|\
|
|
152
85
|
.gitconfig|.gitignore_global|.stCommitMsg|.bash_aliases|README.md)
|
|
153
|
-
|
|
86
|
+
return 0 ;;
|
|
154
87
|
esac
|
|
155
88
|
|
|
89
|
+
[ -r /etc/agent-infra/dotfiles-exclusions ] || return 1
|
|
90
|
+
while IFS= read -r prefix; do
|
|
91
|
+
[ -n "$prefix" ] || continue
|
|
92
|
+
case "$candidate" in
|
|
93
|
+
"$prefix"|"$prefix"/*) return 0 ;;
|
|
94
|
+
esac
|
|
95
|
+
done < /etc/agent-infra/dotfiles-exclusions
|
|
96
|
+
return 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
cd "$DOTFILES_SRC"
|
|
100
|
+
find . -type f -print | while IFS= read -r rel; do
|
|
101
|
+
rel=${rel#./}
|
|
102
|
+
target="$HOME/$rel"
|
|
103
|
+
if is_dotfiles_excluded "$rel"; then
|
|
104
|
+
continue
|
|
105
|
+
fi
|
|
106
|
+
|
|
156
107
|
mkdir -p "$(dirname "$target")"
|
|
157
108
|
if [ -d "$target" ] && [ ! -L "$target" ]; then
|
|
158
109
|
printf 'sandbox-dotfiles-link: skipping %s (existing directory; use nested path like %s/<file> instead)\n' "$target" "$rel" >&2
|
|
@@ -198,8 +149,7 @@ fi
|
|
|
198
149
|
exec tmux new-session -s "$SESSION"
|
|
199
150
|
SCRIPT
|
|
200
151
|
|
|
201
|
-
RUN test -s /usr/local/bin/
|
|
202
|
-
test -s /usr/local/bin/sandbox-dotfiles-link && test -x /usr/local/bin/sandbox-dotfiles-link && \
|
|
152
|
+
RUN test -s /usr/local/bin/sandbox-dotfiles-link && test -x /usr/local/bin/sandbox-dotfiles-link && \
|
|
203
153
|
test -s /usr/local/bin/sandbox-tmux-entry && test -x /usr/local/bin/sandbox-tmux-entry
|
|
204
154
|
|
|
205
155
|
ENV LANG=en_US.UTF-8
|
|
@@ -64,15 +64,23 @@ type SandboxResolvedToolState = Readonly<{
|
|
|
64
64
|
|
|
65
65
|
type SandboxHookCreateContext = Readonly<{
|
|
66
66
|
hostHome: string;
|
|
67
|
+
hostEnv?: Readonly<NodeJS.ProcessEnv>;
|
|
68
|
+
project: string;
|
|
67
69
|
resolvedTools: readonly SandboxResolvedToolState[];
|
|
68
70
|
}>;
|
|
69
71
|
|
|
72
|
+
type SandboxHookEnterContext = Readonly<{
|
|
73
|
+
hostHome: string;
|
|
74
|
+
hostEnv?: Readonly<NodeJS.ProcessEnv>;
|
|
75
|
+
}>;
|
|
76
|
+
|
|
70
77
|
type AgentClientSandboxHookContext = Readonly<{
|
|
71
78
|
signal: AbortSignal;
|
|
72
79
|
runCommand(command: SandboxHookCommand): Promise<SandboxHookCommandResult>;
|
|
73
80
|
config?: Readonly<Record<string, unknown>>;
|
|
74
81
|
plan?: Readonly<Record<string, unknown>>;
|
|
75
82
|
create?: SandboxHookCreateContext;
|
|
83
|
+
enter?: SandboxHookEnterContext;
|
|
76
84
|
}>;
|
|
77
85
|
|
|
78
86
|
type AgentClientSandboxHook = Readonly<{
|
|
@@ -113,11 +121,17 @@ type AgentClientSandboxRecoveryCheck = Readonly<{
|
|
|
113
121
|
repair?: SandboxRecoveryRepair;
|
|
114
122
|
}>;
|
|
115
123
|
|
|
124
|
+
type AgentClientSandboxImageDescriptor = Readonly<{
|
|
125
|
+
dockerfileFragment?: string;
|
|
126
|
+
dotfilesExclusions?: readonly string[];
|
|
127
|
+
}>;
|
|
128
|
+
|
|
116
129
|
type AgentClientSandboxDescriptor = Readonly<{
|
|
117
130
|
createTool(context: SandboxToolContext): SandboxTool;
|
|
118
131
|
aliases: readonly SandboxAlias[];
|
|
119
132
|
hooks: readonly AgentClientSandboxHook[];
|
|
120
133
|
recoveryChecks?: readonly AgentClientSandboxRecoveryCheck[];
|
|
134
|
+
image?: AgentClientSandboxImageDescriptor;
|
|
121
135
|
}>;
|
|
122
136
|
|
|
123
137
|
export { SANDBOX_HOOK_PHASES };
|
|
@@ -126,6 +140,7 @@ export type {
|
|
|
126
140
|
AgentClientSandboxHook,
|
|
127
141
|
AgentClientSandboxHookContext,
|
|
128
142
|
AgentClientSandboxHookResult,
|
|
143
|
+
AgentClientSandboxImageDescriptor,
|
|
129
144
|
AgentClientSandboxRecoveryCheck,
|
|
130
145
|
SandboxAlias,
|
|
131
146
|
SandboxHookCommand,
|
|
@@ -133,6 +148,7 @@ export type {
|
|
|
133
148
|
SandboxHookPhase,
|
|
134
149
|
SandboxHookStatus,
|
|
135
150
|
SandboxHookCreateContext,
|
|
151
|
+
SandboxHookEnterContext,
|
|
136
152
|
SandboxRecoveryFindingDescriptor,
|
|
137
153
|
SandboxRecoveryProbe,
|
|
138
154
|
SandboxRecoveryRepair,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isRemovedHashShortIdInput } from '../task/short-id.ts';
|
|
4
|
+
|
|
5
|
+
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
6
|
+
const SHORT_ID_RE = /^\d+$/;
|
|
7
|
+
|
|
8
|
+
export type SandboxWorkspaceIdentity =
|
|
9
|
+
| Readonly<{ mode: 'task-bound'; taskId: string; shortId: string }>
|
|
10
|
+
| Readonly<{ mode: 'branch-only' }>;
|
|
11
|
+
|
|
12
|
+
export type SandboxContainerWorkspaceIdentity =
|
|
13
|
+
| Readonly<{ mode: 'task-bound'; taskId: string }>
|
|
14
|
+
| Readonly<{ mode: 'branch-only' }>
|
|
15
|
+
| Readonly<{ mode: 'legacy-invalid' }>;
|
|
16
|
+
|
|
17
|
+
export type SandboxTarget = Readonly<{
|
|
18
|
+
requestedRef: string;
|
|
19
|
+
branch: string;
|
|
20
|
+
workspace: SandboxWorkspaceIdentity;
|
|
21
|
+
}>;
|
|
22
|
+
|
|
23
|
+
function stripQuotes(value: string): string {
|
|
24
|
+
return value.replace(/^(?:"([^"]*)"|'([^']*)')$/, '$1$2');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function taskBranch(taskMd: string, taskId: string): string {
|
|
28
|
+
const content = fs.readFileSync(taskMd, 'utf8');
|
|
29
|
+
const value = content.match(/^branch:\s*(.+)$/m)?.[1]?.trim()
|
|
30
|
+
?? content.match(/^- \*\*(?:分支|Branch)\*\*:[ \t]*`?([^`\n]+)`?$/m)?.[1]?.trim();
|
|
31
|
+
if (!value) throw new Error(`Task ${taskId} has no branch field in task.md`);
|
|
32
|
+
return stripQuotes(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function activeRegistry(repoRoot: string): Record<string, string> {
|
|
36
|
+
const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', '.short-ids.json');
|
|
37
|
+
if (!fs.existsSync(registryPath)) return {};
|
|
38
|
+
const value = JSON.parse(fs.readFileSync(registryPath, 'utf8')) as unknown;
|
|
39
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40
|
+
throw new Error('Active task short-id registry is invalid');
|
|
41
|
+
}
|
|
42
|
+
const ids = 'ids' in value && value.ids && typeof value.ids === 'object' && !Array.isArray(value.ids)
|
|
43
|
+
? value.ids as Record<string, unknown>
|
|
44
|
+
: value as Record<string, unknown>;
|
|
45
|
+
return Object.fromEntries(
|
|
46
|
+
Object.entries(ids).filter((entry): entry is [string, string] =>
|
|
47
|
+
SHORT_ID_RE.test(entry[0]) && typeof entry[1] === 'string' && TASK_ID_RE.test(entry[1])
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function taskIdentity(repoRoot: string, taskId: string, registry: Record<string, string>): SandboxWorkspaceIdentity {
|
|
53
|
+
const taskMd = path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md');
|
|
54
|
+
if (!fs.existsSync(taskMd)) throw new Error(`Active task not found: ${taskId}`);
|
|
55
|
+
const shortIds = Object.entries(registry).filter(([, id]) => id === taskId).map(([shortId]) => shortId);
|
|
56
|
+
if (shortIds.length !== 1) {
|
|
57
|
+
throw new Error(`Task ${taskId} must have exactly one active short id`);
|
|
58
|
+
}
|
|
59
|
+
return { mode: 'task-bound', taskId, shortId: shortIds[0]! };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resolveSandboxTarget(requestedRef: string, repoRoot: string): SandboxTarget {
|
|
63
|
+
if (isRemovedHashShortIdInput(requestedRef)) {
|
|
64
|
+
throw new Error(`Invalid task short id '${requestedRef}': task short ids must use bare digits`);
|
|
65
|
+
}
|
|
66
|
+
const registry = activeRegistry(repoRoot);
|
|
67
|
+
if (SHORT_ID_RE.test(requestedRef)) {
|
|
68
|
+
const matchingShortIds = Object.keys(registry).filter((shortId) =>
|
|
69
|
+
shortId === requestedRef || Number(shortId) === Number(requestedRef)
|
|
70
|
+
);
|
|
71
|
+
if (matchingShortIds.length > 1) {
|
|
72
|
+
throw new Error(`Short id '${requestedRef}' is ambiguous in active task registry`);
|
|
73
|
+
}
|
|
74
|
+
const canonicalShortId = matchingShortIds[0];
|
|
75
|
+
const taskId = canonicalShortId ? registry[canonicalShortId] : undefined;
|
|
76
|
+
if (!taskId) throw new Error(`Short id '${requestedRef}' not found in active task registry`);
|
|
77
|
+
const workspace = taskIdentity(repoRoot, taskId, registry);
|
|
78
|
+
return { requestedRef, branch: taskBranch(path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md'), taskId), workspace };
|
|
79
|
+
}
|
|
80
|
+
if (TASK_ID_RE.test(requestedRef)) {
|
|
81
|
+
const workspace = taskIdentity(repoRoot, requestedRef, registry);
|
|
82
|
+
return { requestedRef, branch: taskBranch(path.join(repoRoot, '.agents', 'workspace', 'active', requestedRef, 'task.md'), requestedRef), workspace };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
|
|
86
|
+
const matches = fs.existsSync(activeRoot)
|
|
87
|
+
? fs.readdirSync(activeRoot, { withFileTypes: true }).flatMap((entry) => {
|
|
88
|
+
if (!entry.isDirectory() || !TASK_ID_RE.test(entry.name)) return [];
|
|
89
|
+
const taskMd = path.join(activeRoot, entry.name, 'task.md');
|
|
90
|
+
if (!fs.existsSync(taskMd)) return [];
|
|
91
|
+
return taskBranch(taskMd, entry.name) === requestedRef ? [entry.name] : [];
|
|
92
|
+
})
|
|
93
|
+
: [];
|
|
94
|
+
if (matches.length > 1) {
|
|
95
|
+
throw new Error(`SANDBOX_TASK_IDENTITY_AMBIGUOUS: branch '${requestedRef}' is bound to multiple active tasks`);
|
|
96
|
+
}
|
|
97
|
+
if (matches.length === 1) {
|
|
98
|
+
const taskId = matches[0]!;
|
|
99
|
+
return { requestedRef, branch: requestedRef, workspace: taskIdentity(repoRoot, taskId, registry) };
|
|
100
|
+
}
|
|
101
|
+
return { requestedRef, branch: requestedRef, workspace: { mode: 'branch-only' } };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function parseSandboxWorkspaceIdentity(
|
|
105
|
+
labels: Readonly<Record<string, string>>,
|
|
106
|
+
keys: Readonly<{ mode: string; taskId: string }>
|
|
107
|
+
): SandboxContainerWorkspaceIdentity {
|
|
108
|
+
const mode = labels[keys.mode];
|
|
109
|
+
const taskId = labels[keys.taskId];
|
|
110
|
+
if (mode === 'branch-only' && taskId === undefined) return { mode: 'branch-only' };
|
|
111
|
+
if (mode === 'task-bound' && typeof taskId === 'string' && TASK_ID_RE.test(taskId)) {
|
|
112
|
+
return { mode: 'task-bound', taskId };
|
|
113
|
+
}
|
|
114
|
+
return { mode: 'legacy-invalid' };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function sameSandboxWorkspaceIdentity(
|
|
118
|
+
left: SandboxWorkspaceIdentity | SandboxContainerWorkspaceIdentity,
|
|
119
|
+
right: SandboxWorkspaceIdentity | SandboxContainerWorkspaceIdentity
|
|
120
|
+
): boolean {
|
|
121
|
+
return left.mode === right.mode
|
|
122
|
+
&& (left.mode !== 'task-bound' || (right.mode === 'task-bound' && left.taskId === right.taskId));
|
|
123
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import type { SandboxWorkspaceIdentity } from './workspace-identity.ts';
|
|
5
|
+
import type { SandboxControlManifest } from './control/protocol.ts';
|
|
6
|
+
|
|
7
|
+
export type SandboxWorkspaceView = Readonly<{
|
|
8
|
+
root: string;
|
|
9
|
+
taskMountPath: string | null;
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
export function sandboxWorkspaceViewPaths(params: Readonly<{
|
|
13
|
+
base: string;
|
|
14
|
+
project: string;
|
|
15
|
+
container: string;
|
|
16
|
+
identity: SandboxWorkspaceIdentity;
|
|
17
|
+
}>): SandboxWorkspaceView {
|
|
18
|
+
const identityKey = params.identity.mode === 'task-bound'
|
|
19
|
+
? `task-bound:${params.identity.taskId}`
|
|
20
|
+
: 'branch-only';
|
|
21
|
+
const digest = createHash('sha256').update(identityKey).digest('hex').slice(0, 16);
|
|
22
|
+
const projectRoot = path.resolve(params.base, params.project);
|
|
23
|
+
const root = path.resolve(projectRoot, params.container, digest);
|
|
24
|
+
return {
|
|
25
|
+
root,
|
|
26
|
+
taskMountPath: params.identity.mode === 'task-bound'
|
|
27
|
+
? path.join(root, 'active', params.identity.taskId)
|
|
28
|
+
: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type SandboxControlSetup = Readonly<{
|
|
33
|
+
channelDir: string;
|
|
34
|
+
manifestPath: string;
|
|
35
|
+
token: string;
|
|
36
|
+
}>;
|
|
37
|
+
|
|
38
|
+
export function sandboxControlPaths(params: Readonly<{
|
|
39
|
+
base: string;
|
|
40
|
+
project: string;
|
|
41
|
+
container: string;
|
|
42
|
+
identity: SandboxWorkspaceIdentity;
|
|
43
|
+
}>): Readonly<{ root: string; channelDir: string; manifestPath: string }> {
|
|
44
|
+
const identityKey = params.identity.mode === 'task-bound'
|
|
45
|
+
? `task-bound:${params.identity.taskId}`
|
|
46
|
+
: 'branch-only';
|
|
47
|
+
const digest = createHash('sha256').update(identityKey).digest('hex').slice(0, 16);
|
|
48
|
+
const root = path.resolve(params.base, params.project, params.container, digest);
|
|
49
|
+
return { root, channelDir: path.join(root, 'channel'), manifestPath: path.join(root, 'manifest.json') };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assertSafeDirectory(directory: string, expectedBase: string): void {
|
|
53
|
+
const relative = path.relative(expectedBase, directory);
|
|
54
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
55
|
+
throw new Error(`Sandbox workspace view escapes its configured root: ${directory}`);
|
|
56
|
+
}
|
|
57
|
+
if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {
|
|
58
|
+
throw new Error(`Sandbox workspace view must not be a symbolic link: ${directory}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function assertSandboxTaskSource(repoRoot: string, taskId: string): string {
|
|
63
|
+
if (!/^TASK-\d{8}-\d{6}$/.test(taskId)) throw new Error('SANDBOX_TASK_SOURCE_INVALID');
|
|
64
|
+
const activeRoot = fs.realpathSync.native(path.join(repoRoot, '.agents', 'workspace', 'active'));
|
|
65
|
+
const source = path.join(activeRoot, taskId);
|
|
66
|
+
const stat = fs.lstatSync(source);
|
|
67
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
68
|
+
throw new Error(`SANDBOX_TASK_SOURCE_INVALID: ${source} must be a real directory`);
|
|
69
|
+
}
|
|
70
|
+
const canonical = fs.realpathSync.native(source);
|
|
71
|
+
if (path.dirname(canonical) !== activeRoot) {
|
|
72
|
+
throw new Error(`SANDBOX_TASK_SOURCE_INVALID: ${source} escapes the active workspace`);
|
|
73
|
+
}
|
|
74
|
+
return canonical;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function materializeSandboxWorkspaceView(params: Readonly<{
|
|
78
|
+
base: string;
|
|
79
|
+
project: string;
|
|
80
|
+
container: string;
|
|
81
|
+
identity: SandboxWorkspaceIdentity;
|
|
82
|
+
}>): SandboxWorkspaceView {
|
|
83
|
+
const projectRoot = path.resolve(params.base, params.project);
|
|
84
|
+
const { root, taskMountPath } = sandboxWorkspaceViewPaths(params);
|
|
85
|
+
assertSafeDirectory(projectRoot, path.resolve(params.base));
|
|
86
|
+
assertSafeDirectory(root, projectRoot);
|
|
87
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
88
|
+
for (const state of ['active', 'completed', 'blocked', 'archive']) {
|
|
89
|
+
const stateDir = path.join(root, state);
|
|
90
|
+
assertSafeDirectory(stateDir, root);
|
|
91
|
+
fs.rmSync(stateDir, { recursive: true, force: true });
|
|
92
|
+
fs.mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const active = path.join(root, 'active');
|
|
96
|
+
const registry = {
|
|
97
|
+
version: 1,
|
|
98
|
+
ids: params.identity.mode === 'task-bound'
|
|
99
|
+
? { [params.identity.shortId]: params.identity.taskId }
|
|
100
|
+
: {}
|
|
101
|
+
};
|
|
102
|
+
fs.writeFileSync(path.join(active, '.short-ids.json'), `${JSON.stringify(registry)}\n`, {
|
|
103
|
+
encoding: 'utf8',
|
|
104
|
+
mode: 0o600
|
|
105
|
+
});
|
|
106
|
+
if (taskMountPath) {
|
|
107
|
+
assertSafeDirectory(taskMountPath, active);
|
|
108
|
+
fs.mkdirSync(taskMountPath, { recursive: true, mode: 0o700 });
|
|
109
|
+
}
|
|
110
|
+
return { root, taskMountPath };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function materializeSandboxControl(params: Readonly<{
|
|
114
|
+
base: string;
|
|
115
|
+
repoRoot: string;
|
|
116
|
+
project: string;
|
|
117
|
+
container: string;
|
|
118
|
+
branch: string;
|
|
119
|
+
identity: SandboxWorkspaceIdentity;
|
|
120
|
+
}>): SandboxControlSetup {
|
|
121
|
+
const { root, channelDir, manifestPath } = sandboxControlPaths(params);
|
|
122
|
+
assertSafeDirectory(root, path.resolve(params.base));
|
|
123
|
+
for (const queue of ['requests', 'responses']) {
|
|
124
|
+
const directory = path.join(channelDir, queue);
|
|
125
|
+
assertSafeDirectory(directory, root);
|
|
126
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
127
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
128
|
+
}
|
|
129
|
+
const token = randomBytes(32).toString('hex');
|
|
130
|
+
const manifest: SandboxControlManifest = {
|
|
131
|
+
version: 1,
|
|
132
|
+
repoRoot: fs.realpathSync.native(params.repoRoot),
|
|
133
|
+
project: params.project,
|
|
134
|
+
container: params.container,
|
|
135
|
+
branch: params.branch,
|
|
136
|
+
mode: params.identity.mode,
|
|
137
|
+
taskId: params.identity.mode === 'task-bound' ? params.identity.taskId : null,
|
|
138
|
+
token,
|
|
139
|
+
channelDir
|
|
140
|
+
};
|
|
141
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest)}\n`, { mode: 0o600 });
|
|
142
|
+
return { channelDir, manifestPath, token };
|
|
143
|
+
}
|
|
@@ -75,14 +75,14 @@
|
|
|
75
75
|
"properties": {
|
|
76
76
|
"defaultTui": {
|
|
77
77
|
"type": "string",
|
|
78
|
-
"enum": ["claude", "codex", "
|
|
78
|
+
"enum": ["claude", "codex", "antigravity", "opencode"],
|
|
79
79
|
"default": "codex"
|
|
80
80
|
},
|
|
81
81
|
"skillTuiDefaults": {
|
|
82
82
|
"type": "object",
|
|
83
83
|
"additionalProperties": {
|
|
84
84
|
"type": "string",
|
|
85
|
-
"enum": ["claude", "codex", "
|
|
85
|
+
"enum": ["claude", "codex", "antigravity", "opencode"]
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"allowedSkills": {
|