@fitlab-ai/agent-infra 0.8.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.ts +2 -2
- package/dist/bin/cli.js +2 -2
- package/dist/bin/internal-cli.js +98 -0
- package/dist/lib/decide.js +81 -90
- package/dist/lib/defaults.json +9 -0
- package/dist/lib/git/review-snapshot.js +79 -0
- package/dist/lib/git/workflow.js +101 -0
- package/dist/lib/init.js +5 -0
- package/dist/lib/internal/git-workflow.js +42 -0
- package/dist/lib/internal/platform-checks.js +119 -0
- package/dist/lib/internal/platform-comment.js +129 -0
- package/dist/lib/internal/platform-context.js +46 -0
- package/dist/lib/internal/platform-issue.js +142 -0
- package/dist/lib/internal/platform-pr.js +146 -0
- package/dist/lib/internal/release-workflow.js +217 -0
- package/dist/lib/internal/task-artifact.js +67 -0
- package/dist/lib/internal/task-context.js +43 -0
- package/dist/lib/internal/task-event.js +70 -0
- package/dist/lib/internal/task-ledger.js +114 -0
- package/dist/lib/internal/task-lifecycle.js +58 -0
- package/dist/lib/internal/task-short-id.js +83 -0
- package/dist/lib/internal/task-snapshot.js +47 -0
- package/dist/lib/internal/task-verify.js +50 -0
- package/dist/lib/internal/task-warning.js +74 -0
- package/dist/lib/platform/adapters.js +14 -0
- package/dist/lib/platform/context.js +146 -0
- package/dist/lib/platform/github-client.js +124 -0
- package/dist/lib/platform/issue-comments.js +409 -0
- package/dist/lib/platform/issue-metadata.js +183 -0
- package/dist/lib/platform/issues.js +617 -0
- package/dist/lib/platform/metadata-labels.js +28 -0
- package/dist/lib/platform/pr-checks.js +216 -0
- package/dist/lib/platform/pr-summary.js +88 -0
- package/dist/lib/platform/pull-request-metadata.js +38 -0
- package/dist/lib/platform/pull-requests.js +338 -0
- package/dist/lib/platform/releases.js +82 -0
- package/dist/lib/platform/types.js +22 -0
- package/dist/lib/platform/verification-required.js +78 -0
- package/dist/lib/platform/verification-sync.js +1014 -0
- package/dist/lib/platform/verification.js +6 -0
- package/dist/lib/release/channels.js +31 -0
- package/dist/lib/release/workflow.js +32 -0
- package/dist/lib/render.js +3 -2
- package/dist/lib/run/index.js +24 -7
- package/dist/lib/sandbox/capture.js +25 -3
- package/dist/lib/sandbox/commands/create.js +66 -26
- package/dist/lib/sandbox/commands/enter.js +34 -11
- package/dist/lib/sandbox/commands/list-running.js +10 -8
- package/dist/lib/sandbox/commands/show.js +2 -2
- package/dist/lib/sandbox/commands/start.js +53 -15
- package/dist/lib/sandbox/engine.js +33 -3
- package/dist/lib/sandbox/engines/colima.js +2 -2
- package/dist/lib/sandbox/index.js +6 -6
- package/dist/lib/sandbox/mounts.js +36 -0
- package/dist/lib/sandbox/recovery.js +562 -0
- package/dist/lib/sandbox/runtimes/base.dockerfile +4 -0
- package/dist/lib/sandbox/task-resolver.js +5 -1
- package/dist/lib/sandbox/tools.js +19 -0
- package/dist/lib/server/daemon.js +9 -0
- package/dist/lib/server/process-control.js +66 -73
- package/dist/lib/server/process-state.js +168 -0
- package/dist/lib/server/protocol.js +5 -5
- package/dist/lib/task/activity-log.js +61 -0
- package/dist/lib/task/artifact-lifecycle.js +427 -0
- package/dist/lib/task/command-options.js +30 -0
- package/dist/lib/task/commands/cat.js +36 -6
- package/dist/lib/task/commands/decisions.js +80 -46
- package/dist/lib/task/commands/files.js +21 -7
- package/dist/lib/task/commands/grep.js +55 -7
- package/dist/lib/task/commands/issue-body.js +23 -14
- package/dist/lib/task/commands/log.js +27 -70
- package/dist/lib/task/commands/show.js +20 -7
- package/dist/lib/task/commands/status.js +18 -8
- package/dist/lib/task/decision-intents.js +154 -0
- package/dist/lib/task/decision-items.js +53 -0
- package/dist/lib/task/events.js +318 -0
- package/dist/lib/task/frontmatter.js +159 -1
- package/dist/lib/task/implementation-inputs.js +117 -0
- package/dist/lib/task/index.js +12 -9
- package/dist/lib/task/issue-form.js +19 -6
- package/dist/lib/task/ledger-intents.js +185 -0
- package/dist/lib/task/ledger.js +65 -35
- package/dist/lib/task/lifecycle.js +484 -0
- package/dist/lib/task/resolve-ref.js +152 -32
- package/dist/lib/task/review-artifacts.js +101 -0
- package/dist/lib/task/review-fingerprint.js +46 -0
- package/dist/lib/task/sections.js +358 -4
- package/dist/lib/task/short-id.js +292 -7
- package/dist/lib/task/snapshot.js +95 -0
- package/dist/lib/task/verification-checks.js +8 -0
- package/dist/lib/task/verification-config.js +14 -0
- package/dist/lib/task/verification-engine.js +906 -0
- package/dist/lib/task/verification-review.js +3 -0
- package/dist/lib/task/verification-types.js +2 -0
- package/dist/lib/task/verification.js +113 -0
- package/dist/lib/task/workflow-warning-intents.js +131 -0
- package/dist/lib/task/workflow-warnings.js +10 -78
- package/dist/lib/task/write.js +241 -0
- package/dist/lib/update.js +2 -0
- package/lib/decide.ts +57 -97
- package/lib/defaults.json +9 -0
- package/lib/git/review-snapshot.ts +73 -0
- package/lib/git/workflow.ts +101 -0
- package/lib/init.ts +9 -0
- package/lib/internal/git-workflow.ts +37 -0
- package/lib/internal/platform-checks.ts +101 -0
- package/lib/internal/platform-comment.ts +99 -0
- package/lib/internal/platform-context.ts +33 -0
- package/lib/internal/platform-issue.ts +116 -0
- package/lib/internal/platform-pr.ts +119 -0
- package/lib/internal/release-workflow.ts +186 -0
- package/lib/internal/task-artifact.ts +47 -0
- package/lib/internal/task-context.ts +35 -0
- package/lib/internal/task-event.ts +51 -0
- package/lib/internal/task-ledger.ts +86 -0
- package/lib/internal/task-lifecycle.ts +41 -0
- package/lib/internal/task-short-id.ts +55 -0
- package/lib/internal/task-snapshot.ts +32 -0
- package/lib/internal/task-verify.ts +33 -0
- package/lib/internal/task-warning.ts +50 -0
- package/lib/platform/adapters.ts +30 -0
- package/lib/platform/context.ts +164 -0
- package/lib/platform/github-client.ts +146 -0
- package/lib/platform/issue-comments.ts +479 -0
- package/lib/platform/issue-metadata.ts +250 -0
- package/lib/platform/issues.ts +691 -0
- package/lib/platform/metadata-labels.ts +33 -0
- package/lib/platform/pr-checks.ts +246 -0
- package/lib/platform/pr-summary.ts +90 -0
- package/lib/platform/pull-request-metadata.ts +69 -0
- package/lib/platform/pull-requests.ts +380 -0
- package/lib/platform/releases.ts +71 -0
- package/lib/platform/types.ts +74 -0
- package/lib/platform/verification-required.ts +83 -0
- package/{templates/.agents/scripts/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +221 -363
- package/lib/platform/verification.ts +11 -0
- package/lib/release/channels.ts +30 -0
- package/lib/release/workflow.ts +31 -0
- package/lib/render.ts +3 -2
- package/lib/run/index.ts +25 -7
- package/lib/sandbox/capture.ts +29 -3
- package/lib/sandbox/commands/create.ts +75 -28
- package/lib/sandbox/commands/enter.ts +38 -11
- package/lib/sandbox/commands/list-running.ts +10 -8
- package/lib/sandbox/commands/show.ts +2 -2
- package/lib/sandbox/commands/start.ts +50 -16
- package/lib/sandbox/engine.ts +37 -3
- package/lib/sandbox/engines/colima.ts +2 -2
- package/lib/sandbox/index.ts +6 -6
- package/lib/sandbox/mounts.ts +55 -0
- package/lib/sandbox/recovery.ts +828 -0
- package/lib/sandbox/runtimes/base.dockerfile +4 -0
- package/lib/sandbox/task-resolver.ts +5 -1
- package/lib/sandbox/tools.ts +31 -0
- package/lib/server/daemon.ts +9 -0
- package/lib/server/process-control.ts +70 -71
- package/lib/server/process-state.ts +183 -0
- package/lib/server/protocol.ts +5 -5
- package/lib/task/activity-log.ts +62 -0
- package/lib/task/artifact-lifecycle.ts +484 -0
- package/lib/task/command-options.ts +32 -0
- package/lib/task/commands/cat.ts +22 -9
- package/lib/task/commands/decisions.ts +49 -47
- package/lib/task/commands/files.ts +14 -6
- package/lib/task/commands/grep.ts +34 -7
- package/lib/task/commands/issue-body.ts +16 -16
- package/lib/task/commands/log.ts +17 -70
- package/lib/task/commands/show.ts +14 -6
- package/lib/task/commands/status.ts +17 -7
- package/lib/task/decision-intents.ts +163 -0
- package/lib/task/decision-items.ts +64 -0
- package/lib/task/events.ts +320 -0
- package/lib/task/frontmatter.ts +202 -2
- package/lib/task/implementation-inputs.ts +137 -0
- package/lib/task/index.ts +12 -9
- package/lib/task/issue-form.ts +20 -6
- package/lib/task/ledger-intents.ts +201 -0
- package/lib/task/ledger.ts +77 -31
- package/lib/task/lifecycle.ts +458 -0
- package/lib/task/resolve-ref.ts +197 -36
- package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
- package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +20 -10
- package/lib/task/sections.ts +486 -4
- package/lib/task/short-id.ts +403 -9
- package/lib/task/snapshot.ts +143 -0
- package/lib/task/verification-checks.ts +9 -0
- package/lib/task/verification-config.ts +20 -0
- package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +257 -451
- package/lib/task/verification-review.ts +9 -0
- package/lib/task/verification-types.ts +29 -0
- package/lib/task/verification.ts +156 -0
- package/lib/task/workflow-warning-intents.ts +142 -0
- package/lib/task/workflow-warnings.ts +10 -78
- package/lib/task/write.ts +468 -0
- package/lib/update.ts +6 -0
- package/package.json +5 -2
- package/templates/.agents/README.en.md +6 -3
- package/templates/.agents/README.zh-CN.md +6 -3
- package/templates/.agents/rules/README.en.md +6 -5
- package/templates/.agents/rules/README.zh-CN.md +6 -5
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +5 -184
- package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/human-decision-context.en.md +36 -0
- package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
- package/templates/.agents/rules/issue-fields.github.en.md +4 -148
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
- package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
- package/templates/.agents/rules/issue-sync.en.md +1 -1
- package/templates/.agents/rules/issue-sync.github.en.md +14 -301
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
- package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/milestone-inference.en.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
- package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +12 -11
- package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
- package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
- package/templates/.agents/rules/pr-sync.en.md +30 -3
- package/templates/.agents/rules/pr-sync.github.en.md +12 -115
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
- package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
- package/templates/.agents/rules/review-handshake.en.md +13 -9
- package/templates/.agents/rules/review-handshake.zh-CN.md +13 -9
- package/templates/.agents/rules/task-management.en.md +11 -2
- package/templates/.agents/rules/task-management.zh-CN.md +11 -3
- package/templates/.agents/rules/task-short-id.en.md +25 -29
- package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
- package/templates/.agents/scripts/lib/agent-infra-package.js +141 -0
- package/templates/.agents/scripts/task-short-id.js +71 -533
- package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
- package/templates/.agents/skills/block-task/config/verify.json +1 -2
- package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
- package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
- package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
- package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/SKILL.en.md +18 -14
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +18 -14
- package/templates/.agents/skills/commit/config/verify.json +1 -2
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +42 -2
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +42 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
- package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
- package/templates/.agents/skills/complete-task/config/verify.en.json +11 -6
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -6
- package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
- package/templates/.agents/skills/create-pr/config/verify.json +1 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
- package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
- package/templates/.agents/skills/create-task/config/verify.json +1 -2
- package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
- package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
- package/templates/.agents/skills/import-issue/config/verify.json +1 -2
- package/templates/.agents/skills/init-milestones/SKILL.en.md +2 -2
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +5 -4
- package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +16 -163
- package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
- package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
- package/templates/.agents/skills/restore-task/config/verify.json +1 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
- package/templates/.agents/skills/review-code/config/verify.en.json +5 -5
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +5 -5
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
- package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -4
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -4
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +6 -3
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +6 -3
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +177 -151
- package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
- package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
- package/templates/.agents/templates/task.en.md +6 -1
- package/templates/.agents/templates/task.zh-CN.md +6 -1
- package/templates/.claude/commands/analyze-task.en.md +1 -1
- package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.claude/commands/block-task.en.md +1 -1
- package/templates/.claude/commands/block-task.zh-CN.md +1 -1
- package/templates/.claude/commands/cancel-task.en.md +1 -1
- package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
- package/templates/.claude/commands/check-task.en.md +1 -1
- package/templates/.claude/commands/check-task.zh-CN.md +1 -1
- package/templates/.claude/commands/code-task.en.md +1 -1
- package/templates/.claude/commands/code-task.zh-CN.md +1 -1
- package/templates/.claude/commands/commit.en.md +1 -0
- package/templates/.claude/commands/commit.zh-CN.md +1 -0
- package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
- package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
- package/templates/.claude/commands/complete-task.en.md +1 -1
- package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
- package/templates/.claude/commands/create-pr.en.md +1 -1
- package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
- package/templates/.claude/commands/plan-task.en.md +1 -1
- package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
- package/templates/.claude/commands/review-analysis.en.md +1 -1
- package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.claude/commands/review-code.en.md +1 -1
- package/templates/.claude/commands/review-code.zh-CN.md +1 -1
- package/templates/.claude/commands/review-plan.en.md +1 -1
- package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
- package/templates/.git-hooks/check-large-files.cjs +92 -0
- package/templates/.git-hooks/check-version-format.sh +5 -1
- package/templates/.git-hooks/pre-commit +1 -0
- package/templates/.opencode/commands/analyze-task.en.md +1 -1
- package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/check-task.en.md +1 -1
- package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/code-task.en.md +1 -1
- package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/commit.en.md +2 -0
- package/templates/.opencode/commands/commit.zh-CN.md +2 -0
- package/templates/.opencode/commands/complete-task.en.md +1 -1
- package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/plan-task.en.md +1 -1
- package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-analysis.en.md +1 -1
- package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-code.en.md +1 -1
- package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-plan.en.md +1 -1
- package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
- package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
- package/templates/.agents/scripts/review-diff-fingerprint.js +0 -99
- package/templates/.agents/scripts/workflow-warnings.js +0 -290
- package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
- package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
- package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { inspectRequiredChecks } from './pr-checks.ts';
|
|
2
|
+
|
|
3
|
+
type VerificationStatus = 'pass' | 'fail' | 'blocked';
|
|
4
|
+
type VerificationCheck = { type: string; status: VerificationStatus; message: string; fail_type?: string };
|
|
5
|
+
|
|
6
|
+
function verificationCheck(type: string, status: VerificationStatus, message: string, failType?: string): VerificationCheck {
|
|
7
|
+
return { type, status, message, ...(failType ? { fail_type: failType } : {}) };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { inspectRequiredChecks, verificationCheck };
|
|
11
|
+
export type { VerificationCheck, VerificationStatus };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type FetchResponse = { ok: boolean; status: number; json(): Promise<unknown>; text(): Promise<string> };
|
|
2
|
+
type Fetcher = (url: string) => Promise<FetchResponse>;
|
|
3
|
+
|
|
4
|
+
async function inspectNpmChannel(name: string, version: string, fetcher: Fetcher = fetch as unknown as Fetcher) {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetcher(`https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(version)}`);
|
|
7
|
+
if (response.status === 404) return { status: 'no-op' as const, published: false, version, error: null };
|
|
8
|
+
if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: `npm registry returned ${response.status}` } };
|
|
9
|
+
const body = await response.json() as Record<string, unknown>;
|
|
10
|
+
return { status: 'no-op' as const, published: body.version === version, version, error: null };
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return { status: 'blocked' as const, published: null, version, error: { code: 'NPM_REGISTRY_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function inspectHomebrewChannel(url: string, version: string, fetcher: Fetcher = fetch as unknown as Fetcher) {
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetcher(url);
|
|
19
|
+
if (response.status === 404) return { status: 'no-op' as const, published: false, version, error: null };
|
|
20
|
+
if (!response.ok) return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: `formula endpoint returned ${response.status}` } };
|
|
21
|
+
const formula = await response.text();
|
|
22
|
+
const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
23
|
+
return { status: 'no-op' as const, published: new RegExp(`(?:version\\s+["']${escaped}["']|/v?${escaped}\\.)`).test(formula), version, error: null };
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return { status: 'blocked' as const, published: null, version, error: { code: 'HOMEBREW_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) } };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { inspectHomebrewChannel, inspectNpmChannel };
|
|
30
|
+
export type { Fetcher, FetchResponse };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type ReleasePhase = 'unprepared' | 'prepared' | 'partially-published' | 'published' | 'post-pending' | 'complete';
|
|
2
|
+
type ReleaseFacts = { localTag: boolean; localTagConflict?: boolean; remoteBranch: boolean; remoteTag: boolean; githubRelease: boolean | null; npm: boolean | null; homebrew: boolean | null; smoke: 'success' | 'pending' | 'failed' | null; postCommit: boolean };
|
|
3
|
+
|
|
4
|
+
function deriveReleasePhase(facts: ReleaseFacts): ReleasePhase {
|
|
5
|
+
if (!facts.localTag) return 'unprepared';
|
|
6
|
+
if (!facts.remoteBranch && !facts.remoteTag) return 'prepared';
|
|
7
|
+
if (!facts.remoteBranch || !facts.remoteTag) return 'partially-published';
|
|
8
|
+
if (facts.githubRelease !== true || facts.npm !== true || facts.homebrew !== true) return 'published';
|
|
9
|
+
if (facts.smoke !== 'success' || !facts.postCommit) return 'post-pending';
|
|
10
|
+
return 'complete';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function releaseSnapshot(version: string, facts: ReleaseFacts) {
|
|
14
|
+
return { version, tag: `v${version.replace(/^v/, '')}`, phase: deriveReleasePhase(facts), facts };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function runReleaseAction(input: { version: string; action: 'inspect' | 'prepare' | 'publish' | 'post'; inspect: () => Promise<ReleaseFacts>; prepare?: () => Promise<void>; publish?: () => Promise<void>; post?: () => Promise<void> }) {
|
|
18
|
+
const before = releaseSnapshot(input.version, await input.inspect());
|
|
19
|
+
if (input.action === 'inspect') return { status: 'no-op' as const, changed: false, before, snapshot: before, error: null };
|
|
20
|
+
const allowed = input.action === 'prepare' ? before.phase === 'unprepared'
|
|
21
|
+
: input.action === 'publish' ? ['prepared', 'partially-published'].includes(before.phase)
|
|
22
|
+
: ['published', 'post-pending'].includes(before.phase);
|
|
23
|
+
if (!allowed) return { status: before.phase === 'complete' ? 'no-op' as const : 'failed' as const, changed: false, before, snapshot: before, error: before.phase === 'complete' ? null : { code: 'RELEASE_PHASE_INVALID', message: `Cannot ${input.action} from ${before.phase}` } };
|
|
24
|
+
await input[input.action]?.();
|
|
25
|
+
const snapshot = releaseSnapshot(input.version, await input.inspect());
|
|
26
|
+
const progressed = snapshot.phase !== before.phase;
|
|
27
|
+
return { status: progressed ? 'applied' as const : 'blocked' as const, changed: progressed, before, snapshot, error: progressed ? null : { code: 'RELEASE_PROGRESS_PENDING', message: `${input.action} has not reached the next observable phase` } };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { deriveReleasePhase, releaseSnapshot, runReleaseAction };
|
|
31
|
+
export type { ReleaseFacts, ReleasePhase };
|
package/lib/render.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
|
|
4
|
+
// Built-in platform strategies. "none" deliberately selects generic templates
|
|
5
|
+
// and the no-op runtime adapter instead of requiring .none.* variants.
|
|
6
|
+
const KNOWN_PLATFORMS = new Set(['github', 'none']);
|
|
6
7
|
const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
|
|
7
8
|
|
|
8
9
|
type Replacements = {
|
package/lib/run/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type ParsedRunArgs = {
|
|
|
13
13
|
taskRef: string | null;
|
|
14
14
|
args: string[];
|
|
15
15
|
tui: string | null;
|
|
16
|
+
recreate?: true;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export type SandboxRunRequest = {
|
|
@@ -20,6 +21,7 @@ export type SandboxRunRequest = {
|
|
|
20
21
|
branch: string;
|
|
21
22
|
command: string[];
|
|
22
23
|
runId?: string;
|
|
24
|
+
recreate?: boolean;
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export type SandboxRunResult = RunProcessResult & {
|
|
@@ -35,14 +37,15 @@ export type RunSkillOptions = {
|
|
|
35
37
|
writeStderr?: (chunk: string) => void;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
|
-
const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>]
|
|
40
|
+
const USAGE = `Usage: ai run <skill> [task-ref] [args...] [--tui <name>] [--recreate]
|
|
39
41
|
|
|
40
42
|
Task skills are scheduled inside the sandbox tmux session; ai run returns once
|
|
41
|
-
the tmux window is created.
|
|
43
|
+
the tmux window is created. --recreate authorizes container-only replacement
|
|
44
|
+
when in-place sandbox recovery fails; it is not included in the TUI prompt.
|
|
42
45
|
|
|
43
46
|
Examples:
|
|
44
47
|
ai run create-task "describe the task" --tui codex
|
|
45
|
-
ai run code-task #7 --tui codex`;
|
|
48
|
+
ai run code-task #7 --tui codex --recreate`;
|
|
46
49
|
|
|
47
50
|
function extractTui(args: string[]): { rest: string[]; tui: string | null } {
|
|
48
51
|
const rest: string[] = [];
|
|
@@ -65,17 +68,26 @@ export function parseRunArgs(args: string[]): ParsedRunArgs {
|
|
|
65
68
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
66
69
|
throw new Error(USAGE);
|
|
67
70
|
}
|
|
68
|
-
const { rest, tui } = extractTui(args);
|
|
71
|
+
const { rest: withRecoveryFlags, tui } = extractTui(args);
|
|
72
|
+
const recreate = withRecoveryFlags.includes('--recreate');
|
|
73
|
+
const rest = withRecoveryFlags.filter((arg) => arg !== '--recreate');
|
|
69
74
|
const [skill = '', maybeTaskRef, ...remaining] = rest;
|
|
70
75
|
const spec = getSkillRunSpec(skill);
|
|
71
76
|
if (!spec) throw new Error(`Unknown skill '${skill}'`);
|
|
72
77
|
if (spec.kind === 'create') {
|
|
78
|
+
if (recreate) throw new Error('--recreate is only valid for sandbox task runs');
|
|
73
79
|
const createArgs = rest.slice(1);
|
|
74
80
|
if (createArgs.length === 0) throw new Error('create-task requires a description');
|
|
75
81
|
return { skill, taskRef: null, args: createArgs, tui };
|
|
76
82
|
}
|
|
77
83
|
if (!maybeTaskRef) throw new Error(`${skill} requires a task-ref`);
|
|
78
|
-
return {
|
|
84
|
+
return {
|
|
85
|
+
skill,
|
|
86
|
+
taskRef: maybeTaskRef,
|
|
87
|
+
args: remaining,
|
|
88
|
+
tui,
|
|
89
|
+
...(recreate ? { recreate: true as const } : {})
|
|
90
|
+
};
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
function assertAllowedByConfig(skill: string, commandConfig: Record<string, unknown>): void {
|
|
@@ -129,7 +141,7 @@ function resolveActiveTaskIdentity(taskRef: string, repoRoot: string): ActiveTas
|
|
|
129
141
|
const normalized = normalizeShortIdInput(taskRef, { shortIdLength: readShortIdLength(repoRoot) });
|
|
130
142
|
if (normalized.kind !== 'shortId') return null;
|
|
131
143
|
resolvedTaskRef = normalized.value;
|
|
132
|
-
taskId = readActiveShortIdRegistry(repoRoot)[normalized.value
|
|
144
|
+
taskId = readActiveShortIdRegistry(repoRoot)[normalized.value] ?? null;
|
|
133
145
|
}
|
|
134
146
|
|
|
135
147
|
if (!taskId) return null;
|
|
@@ -207,7 +219,13 @@ export async function runSkill(args: string[], options: RunSkillOptions = {}): P
|
|
|
207
219
|
const runSandbox =
|
|
208
220
|
options.runSandbox ??
|
|
209
221
|
((request: SandboxRunRequest) => runInSandbox(request));
|
|
210
|
-
const result = await runSandbox({
|
|
222
|
+
const result = await runSandbox({
|
|
223
|
+
taskRef: parsed.taskRef,
|
|
224
|
+
branch,
|
|
225
|
+
command,
|
|
226
|
+
runId,
|
|
227
|
+
recreate: parsed.recreate
|
|
228
|
+
});
|
|
211
229
|
if (result.stdout) {
|
|
212
230
|
writeStdout(result.stdout);
|
|
213
231
|
}
|
package/lib/sandbox/capture.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { loadConfig } from './config.ts';
|
|
|
3
3
|
import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.ts';
|
|
4
4
|
import { detectEngine } from './engine.ts';
|
|
5
5
|
import { commandForEngine } from './shell.ts';
|
|
6
|
+
import { ensureSandboxReady, type SandboxReadyResult } from './recovery.ts';
|
|
6
7
|
import { hostTimezoneEnvFlags, terminalEnvFlags } from './commands/enter.ts';
|
|
7
8
|
import {
|
|
8
9
|
fetchSandboxRows,
|
|
@@ -16,6 +17,7 @@ export type SandboxCaptureRequest = {
|
|
|
16
17
|
branch: string;
|
|
17
18
|
command: string[];
|
|
18
19
|
timeoutMs?: number;
|
|
20
|
+
recreate?: boolean;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
export type SandboxCaptureResult = {
|
|
@@ -40,6 +42,11 @@ export type SandboxCaptureOptions = {
|
|
|
40
42
|
containerCandidates?: string[];
|
|
41
43
|
rows?: SandboxRow[];
|
|
42
44
|
startContainer?: (name: string) => void;
|
|
45
|
+
ensureReady?: (params: {
|
|
46
|
+
branch: string;
|
|
47
|
+
row: SandboxRow;
|
|
48
|
+
allowRecreate: boolean;
|
|
49
|
+
}) => Promise<SandboxReadyResult>;
|
|
43
50
|
spawn?: (file: string, args: string[]) => Promise<SandboxCaptureResult>;
|
|
44
51
|
};
|
|
45
52
|
|
|
@@ -189,7 +196,26 @@ export async function runInSandbox(
|
|
|
189
196
|
`Sandbox for ${request.branch} not found. Create it first with ai sandbox create ${request.taskRef}.`
|
|
190
197
|
);
|
|
191
198
|
}
|
|
192
|
-
|
|
199
|
+
let container = found.name;
|
|
200
|
+
if (options.ensureReady) {
|
|
201
|
+
container = (await options.ensureReady({
|
|
202
|
+
branch: request.branch,
|
|
203
|
+
row: found,
|
|
204
|
+
allowRecreate: request.recreate ?? false
|
|
205
|
+
})).container;
|
|
206
|
+
} else if (config) {
|
|
207
|
+
container = (await ensureSandboxReady({
|
|
208
|
+
config,
|
|
209
|
+
engine,
|
|
210
|
+
branch: request.branch,
|
|
211
|
+
row: found,
|
|
212
|
+
allowRecreate: request.recreate,
|
|
213
|
+
recreate: async (targetBranch) => {
|
|
214
|
+
const { create } = await import('./commands/create.ts');
|
|
215
|
+
await create([targetBranch, '--no-refresh']);
|
|
216
|
+
}
|
|
217
|
+
})).container;
|
|
218
|
+
} else if (!found.running) {
|
|
193
219
|
(options.startContainer ?? ((name: string) => startSandboxContainer(engine, name)))(found.name);
|
|
194
220
|
}
|
|
195
221
|
const runId = options.runId ?? createRunId();
|
|
@@ -198,7 +224,7 @@ export async function runInSandbox(
|
|
|
198
224
|
'exec',
|
|
199
225
|
...terminalEnvFlags(),
|
|
200
226
|
...hostTimezoneEnvFlags(),
|
|
201
|
-
|
|
227
|
+
container,
|
|
202
228
|
'bash',
|
|
203
229
|
'-lc',
|
|
204
230
|
buildTmuxLauncher({ request, runId })
|
|
@@ -210,7 +236,7 @@ export async function runInSandbox(
|
|
|
210
236
|
run: {
|
|
211
237
|
runId,
|
|
212
238
|
engine,
|
|
213
|
-
container
|
|
239
|
+
container,
|
|
214
240
|
runDir
|
|
215
241
|
}
|
|
216
242
|
};
|
|
@@ -39,10 +39,18 @@ import {
|
|
|
39
39
|
import { resolveTaskBranch } from '../task-resolver.ts';
|
|
40
40
|
import {
|
|
41
41
|
resolveTools,
|
|
42
|
+
tmpfsSeedStagingPath,
|
|
43
|
+
tmpfsSeedTargetPath,
|
|
42
44
|
toolConfigDirCandidates
|
|
43
45
|
} from '../tools.ts';
|
|
44
|
-
import type { SandboxTool } from '../tools.ts';
|
|
46
|
+
import type { SandboxTool, TmpfsSeedEntry } from '../tools.ts';
|
|
47
|
+
import {
|
|
48
|
+
assertFreshSandboxReady,
|
|
49
|
+
hydrateTmpfsSeedEntries,
|
|
50
|
+
prepareTmpfsMounts
|
|
51
|
+
} from '../recovery.ts';
|
|
45
52
|
import { hostJoin, toEnginePath, volumeArg } from '../engines/wsl2-paths.ts';
|
|
53
|
+
import { sandboxCoreBindMounts } from '../mounts.ts';
|
|
46
54
|
import { clipboardHostDir, CONTAINER_CLIPBOARD_MOUNT } from '../clipboard/paths.ts';
|
|
47
55
|
import { validateSelinuxDisableEnv } from '../engines/selinux.ts';
|
|
48
56
|
import { dotfilesCacheDir, materializeDotfiles } from '../dotfiles.ts';
|
|
@@ -87,20 +95,32 @@ alias gy='gemini --yolo; tput ed'
|
|
|
87
95
|
`;
|
|
88
96
|
const CONTAINER_HOME = '/home/devuser';
|
|
89
97
|
const CONTAINER_SHELL_CONFIG_MOUNT = `${CONTAINER_HOME}/.host-shell-config`;
|
|
90
|
-
const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh]
|
|
98
|
+
const USAGE = `Usage: ai sandbox create <branch> [base] [--cpu <n>] [--memory <n>] [--no-refresh] [--inherit-proxy|-P]
|
|
91
99
|
|
|
92
100
|
Host aliases:
|
|
93
101
|
${'~'}/.agent-infra/aliases/sandbox.sh is auto-created on first run and exposed
|
|
94
102
|
as ${CONTAINER_HOME}/.bash_aliases inside the sandbox container (the host
|
|
95
103
|
shell-config directory is bind-mounted at ${CONTAINER_SHELL_CONFIG_MOUNT} and
|
|
96
|
-
symlinked into $HOME)
|
|
104
|
+
symlinked into $HOME).
|
|
105
|
+
|
|
106
|
+
Proxy:
|
|
107
|
+
--inherit-proxy, -P Copy non-empty standard host proxy variables into the
|
|
108
|
+
container environment through the private env file.`;
|
|
109
|
+
const HOST_PROXY_ENV_KEYS = [
|
|
110
|
+
'http_proxy',
|
|
111
|
+
'HTTP_PROXY',
|
|
112
|
+
'https_proxy',
|
|
113
|
+
'HTTPS_PROXY',
|
|
114
|
+
'all_proxy',
|
|
115
|
+
'ALL_PROXY',
|
|
116
|
+
'no_proxy',
|
|
117
|
+
'NO_PROXY'
|
|
118
|
+
] as const;
|
|
97
119
|
|
|
98
120
|
type SandboxCreateConfig = ReturnType<typeof loadConfig>;
|
|
99
121
|
type PreparedDockerfile = ReturnType<typeof prepareDockerfile>;
|
|
100
122
|
type ResolvedTool = { tool: SandboxTool; dir: string };
|
|
101
|
-
type TmpfsSeedPlanEntry = {
|
|
102
|
-
stagingPath: string;
|
|
103
|
-
targetPath: string;
|
|
123
|
+
type TmpfsSeedPlanEntry = TmpfsSeedEntry & {
|
|
104
124
|
volumeArgs: string[];
|
|
105
125
|
};
|
|
106
126
|
type RuntimeCheck = { name: string; cmd: string[] };
|
|
@@ -626,11 +646,20 @@ function formatEnvFileEntry(key: string, value: string): string {
|
|
|
626
646
|
return `${key}=${value}`;
|
|
627
647
|
}
|
|
628
648
|
|
|
649
|
+
export function collectHostProxyEntries(env: NodeJS.ProcessEnv): Array<[string, string]> {
|
|
650
|
+
const entriesByExactKey = new Map(Object.entries(env));
|
|
651
|
+
return HOST_PROXY_ENV_KEYS.flatMap((key) => {
|
|
652
|
+
const value = entriesByExactKey.get(key);
|
|
653
|
+
return typeof value === 'string' && value !== '' ? [[key, value]] : [];
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
629
657
|
export function buildContainerEnvFile(
|
|
630
658
|
resolvedTools: ResolvedTool[],
|
|
631
659
|
engine: string,
|
|
632
660
|
runSafeEngineFn: EngineRunSafeFn = runSafeEngine,
|
|
633
661
|
options: {
|
|
662
|
+
additionalEntries?: Array<[string, string]>;
|
|
634
663
|
mkdtempFn?: typeof fs.mkdtempSync;
|
|
635
664
|
writeFileFn?: typeof fs.writeFileSync;
|
|
636
665
|
chmodFn?: typeof fs.chmodSync;
|
|
@@ -640,6 +669,7 @@ export function buildContainerEnvFile(
|
|
|
640
669
|
} = {}
|
|
641
670
|
): { dockerArgs: string[]; cleanup: () => void } {
|
|
642
671
|
const {
|
|
672
|
+
additionalEntries = [],
|
|
643
673
|
mkdtempFn = fs.mkdtempSync,
|
|
644
674
|
writeFileFn = fs.writeFileSync,
|
|
645
675
|
chmodFn = fs.chmodSync,
|
|
@@ -649,6 +679,7 @@ export function buildContainerEnvFile(
|
|
|
649
679
|
} = options;
|
|
650
680
|
|
|
651
681
|
const entries: Array<[string, string]> = resolvedTools.flatMap(({ tool }) => Object.entries(tool.envVars ?? {}));
|
|
682
|
+
entries.push(...additionalEntries);
|
|
652
683
|
let ghToken = runSafeEngineFn(engine, 'gh', ['auth', 'token']);
|
|
653
684
|
if (!ghToken && engine === 'wsl2') {
|
|
654
685
|
ghToken = runSafeFn('gh', ['auth', 'token']);
|
|
@@ -1246,6 +1277,7 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1246
1277
|
cpu: { type: 'string' },
|
|
1247
1278
|
memory: { type: 'string' },
|
|
1248
1279
|
'no-refresh': { type: 'boolean' },
|
|
1280
|
+
'inherit-proxy': { type: 'boolean', short: 'P' },
|
|
1249
1281
|
help: { type: 'boolean', short: 'h' }
|
|
1250
1282
|
}
|
|
1251
1283
|
});
|
|
@@ -1297,6 +1329,7 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1297
1329
|
const baseBranch = base ?? runSafe('git', ['-C', effectiveConfig.repoRoot, 'branch', '--show-current']);
|
|
1298
1330
|
const expectedImageSignature = buildImageSignature(preparedDockerfile, tools);
|
|
1299
1331
|
const engine = detectEngine(effectiveConfig);
|
|
1332
|
+
let createdTmpfsSeedPlan: TmpfsSeedPlanEntry[] = [];
|
|
1300
1333
|
|
|
1301
1334
|
p.intro(pc.cyan('AI Sandbox'));
|
|
1302
1335
|
p.log.info(
|
|
@@ -1503,7 +1536,10 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1503
1536
|
signingKey
|
|
1504
1537
|
)
|
|
1505
1538
|
: null;
|
|
1506
|
-
const
|
|
1539
|
+
const proxyEntries = values['inherit-proxy'] ? collectHostProxyEntries(process.env) : [];
|
|
1540
|
+
const envFile = buildContainerEnvFile(effectiveResolvedTools, engine, undefined, {
|
|
1541
|
+
additionalEntries: proxyEntries
|
|
1542
|
+
});
|
|
1507
1543
|
let hostShellConfig: HostShellConfig;
|
|
1508
1544
|
let tmpfsSeedPlan: TmpfsSeedPlanEntry[] = [];
|
|
1509
1545
|
try {
|
|
@@ -1542,9 +1578,12 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1542
1578
|
branch,
|
|
1543
1579
|
repoRoot: effectiveConfig.repoRoot
|
|
1544
1580
|
});
|
|
1545
|
-
const
|
|
1581
|
+
const coreVolumes = sandboxCoreBindMounts(effectiveConfig, branch, {
|
|
1582
|
+
worktree,
|
|
1583
|
+
shellConfigHostDir: hostShellConfig.hostDir
|
|
1584
|
+
}).flatMap(({ hostPaths, containerPath, readOnly }) => [
|
|
1546
1585
|
'-v',
|
|
1547
|
-
volumeArg(engine,
|
|
1586
|
+
volumeArg(engine, hostPaths[0]!, containerPath, readOnly ? ':ro' : '')
|
|
1548
1587
|
]);
|
|
1549
1588
|
// Mount each declared seed read-only at an isolated staging path.
|
|
1550
1589
|
// After docker run mounts the empty tmpfs, the container's default
|
|
@@ -1554,14 +1593,17 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1554
1593
|
// being exposed or written through.
|
|
1555
1594
|
tmpfsSeedPlan = effectiveResolvedTools.flatMap(({ tool, dir }) =>
|
|
1556
1595
|
(tool.tmpfs?.seed ?? []).flatMap((entry, index) => {
|
|
1596
|
+
const targetPath = tmpfsSeedTargetPath(tool.containerMount, entry);
|
|
1557
1597
|
const hostPath = path.join(dir, entry);
|
|
1558
1598
|
if (!fs.existsSync(hostPath)) {
|
|
1559
1599
|
return [];
|
|
1560
1600
|
}
|
|
1561
|
-
const stagingPath =
|
|
1601
|
+
const stagingPath = tmpfsSeedStagingPath(tool.id, index);
|
|
1562
1602
|
return [{
|
|
1603
|
+
toolId: tool.id,
|
|
1604
|
+
containerMount: tool.containerMount,
|
|
1563
1605
|
stagingPath,
|
|
1564
|
-
targetPath
|
|
1606
|
+
targetPath,
|
|
1565
1607
|
volumeArgs: ['-v', volumeArg(engine, hostPath, stagingPath, ':ro')]
|
|
1566
1608
|
}];
|
|
1567
1609
|
})
|
|
@@ -1601,14 +1643,7 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1601
1643
|
sandboxLabel(effectiveConfig),
|
|
1602
1644
|
'--label',
|
|
1603
1645
|
`${sandboxBranchLabel(effectiveConfig)}=${branch}`,
|
|
1604
|
-
|
|
1605
|
-
volumeArg(engine, worktree, '/workspace'),
|
|
1606
|
-
'-v',
|
|
1607
|
-
volumeArg(engine, workspaceDir, '/workspace/.agents/workspace'),
|
|
1608
|
-
'-v',
|
|
1609
|
-
volumeArg(engine, shareCommon, '/share/common'),
|
|
1610
|
-
'-v',
|
|
1611
|
-
volumeArg(engine, shareBranch, '/share/branch'),
|
|
1646
|
+
...coreVolumes,
|
|
1612
1647
|
...buildClipboardVolumeArgs(engine, effectiveConfig.home),
|
|
1613
1648
|
'-v',
|
|
1614
1649
|
volumeArg(
|
|
@@ -1621,25 +1656,30 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1621
1656
|
...tmpfsArgs,
|
|
1622
1657
|
...tmpfsSeedPlan.flatMap(({ volumeArgs }) => volumeArgs),
|
|
1623
1658
|
...liveMountVolumes,
|
|
1624
|
-
...shellConfigVolumes,
|
|
1625
1659
|
...envFile.dockerArgs,
|
|
1626
1660
|
...tzFlags,
|
|
1627
1661
|
'-w',
|
|
1628
1662
|
'/workspace',
|
|
1629
1663
|
effectiveConfig.imageName
|
|
1630
1664
|
]);
|
|
1665
|
+
createdTmpfsSeedPlan = tmpfsSeedPlan;
|
|
1631
1666
|
} finally {
|
|
1632
1667
|
envFile.cleanup();
|
|
1633
1668
|
}
|
|
1634
1669
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1670
|
+
prepareTmpfsMounts({
|
|
1671
|
+
engine,
|
|
1672
|
+
container,
|
|
1673
|
+
mountPaths: effectiveResolvedTools
|
|
1674
|
+
.filter(({ tool }) => tool.tmpfs)
|
|
1675
|
+
.map(({ tool }) => tool.containerMount)
|
|
1676
|
+
});
|
|
1677
|
+
hydrateTmpfsSeedEntries({
|
|
1678
|
+
engine,
|
|
1679
|
+
container,
|
|
1680
|
+
entries: tmpfsSeedPlan,
|
|
1681
|
+
replace: true
|
|
1682
|
+
});
|
|
1643
1683
|
|
|
1644
1684
|
// Belt-and-suspenders: re-create the four shell-config symlinks at
|
|
1645
1685
|
// runtime so users with a custom `sandbox.dockerfile` (which won't
|
|
@@ -1708,6 +1748,13 @@ export async function create(args: string[]): Promise<void> {
|
|
|
1708
1748
|
}
|
|
1709
1749
|
|
|
1710
1750
|
p.log.step('Verifying setup...');
|
|
1751
|
+
assertFreshSandboxReady({
|
|
1752
|
+
config: effectiveConfig,
|
|
1753
|
+
engine,
|
|
1754
|
+
branch,
|
|
1755
|
+
container,
|
|
1756
|
+
copiedEntries: createdTmpfsSeedPlan
|
|
1757
|
+
});
|
|
1711
1758
|
const runningContainers = runSafeEngine(engine, 'docker', ['ps', '--format', '{{.Names}}']).split('\n');
|
|
1712
1759
|
const checks = [
|
|
1713
1760
|
{ name: 'Container running', ok: runningContainers.includes(container) },
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
sandboxLabel
|
|
7
7
|
} from '../constants.ts';
|
|
8
8
|
import { detectEngine } from '../engine.ts';
|
|
9
|
+
import { ensureSandboxReady } from '../recovery.ts';
|
|
9
10
|
import {
|
|
10
11
|
formatCredentialWarnings,
|
|
11
12
|
formatRemaining,
|
|
@@ -22,15 +23,15 @@ import {
|
|
|
22
23
|
fetchSandboxRows,
|
|
23
24
|
resolveBranchArg,
|
|
24
25
|
selectSandboxContainer,
|
|
25
|
-
startSandboxContainer
|
|
26
26
|
} from './list-running.ts';
|
|
27
27
|
|
|
28
|
-
const USAGE = `Usage: ai sandbox exec <branch | TASK-id | N
|
|
28
|
+
const USAGE = `Usage: ai sandbox exec [--recreate] <branch | TASK-id | N> [cmd...]
|
|
29
29
|
|
|
30
|
-
N
|
|
30
|
+
N references an active task short id from
|
|
31
31
|
.agents/workspace/active/.short-ids.json. They resolve only via that
|
|
32
32
|
registry — they do not reference a container's row position in
|
|
33
|
-
'ai sandbox ls' output
|
|
33
|
+
'ai sandbox ls' output. --recreate is a host recovery flag only before the
|
|
34
|
+
target; the same token after the target is passed to the container command.`;
|
|
34
35
|
const TMUX_ENTRY_PATH = '/usr/local/bin/sandbox-tmux-entry';
|
|
35
36
|
|
|
36
37
|
// Terminal-detection variables that interactive TUIs (e.g. claude-code)
|
|
@@ -123,6 +124,24 @@ export function formatCredentialSyncStatus(
|
|
|
123
124
|
return null;
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
export function parseEnterArgs(args: string[]): {
|
|
128
|
+
target: string;
|
|
129
|
+
command: string[];
|
|
130
|
+
recreate: boolean;
|
|
131
|
+
} {
|
|
132
|
+
let recreate = false;
|
|
133
|
+
let index = 0;
|
|
134
|
+
while (args[index] === '--recreate') {
|
|
135
|
+
recreate = true;
|
|
136
|
+
index += 1;
|
|
137
|
+
}
|
|
138
|
+
const target = args[index] ?? '';
|
|
139
|
+
if (!target) {
|
|
140
|
+
throw new Error(USAGE);
|
|
141
|
+
}
|
|
142
|
+
return { target, command: args.slice(index + 1), recreate };
|
|
143
|
+
}
|
|
144
|
+
|
|
126
145
|
export async function enter(args: string[]): Promise<number> {
|
|
127
146
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
128
147
|
process.stdout.write(`${USAGE}\n`);
|
|
@@ -135,8 +154,8 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
135
154
|
const config = loadConfig();
|
|
136
155
|
validateClaudeCredentialsEnvOverride();
|
|
137
156
|
const engine = detectEngine(config);
|
|
138
|
-
const
|
|
139
|
-
const branch = resolveBranchArg(
|
|
157
|
+
const parsed = parseEnterArgs(args);
|
|
158
|
+
const branch = resolveBranchArg(parsed.target, { repoRoot: config.repoRoot });
|
|
140
159
|
assertValidBranchName(branch);
|
|
141
160
|
|
|
142
161
|
const { running, nonRunning } = fetchSandboxRows(
|
|
@@ -154,11 +173,19 @@ export async function enter(args: string[]): Promise<number> {
|
|
|
154
173
|
`No sandbox found for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`
|
|
155
174
|
);
|
|
156
175
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
const ready = await ensureSandboxReady({
|
|
177
|
+
config,
|
|
178
|
+
engine,
|
|
179
|
+
branch,
|
|
180
|
+
row: found,
|
|
181
|
+
allowRecreate: parsed.recreate,
|
|
182
|
+
recreate: async (targetBranch) => {
|
|
183
|
+
const { create } = await import('./create.ts');
|
|
184
|
+
await create([targetBranch, '--no-refresh']);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
const container = ready.container;
|
|
188
|
+
const cmd = parsed.command;
|
|
162
189
|
|
|
163
190
|
if (config.tools.includes('claude-code')) {
|
|
164
191
|
try {
|
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { runSafeEngine, runVerboseEngine } from '../shell.ts';
|
|
5
5
|
import { resolveTaskBranch } from '../task-resolver.ts';
|
|
6
|
+
import { isRemovedHashShortIdInput } from '../../task/short-id.ts';
|
|
6
7
|
|
|
7
8
|
export type SandboxRow = {
|
|
8
9
|
name: string;
|
|
@@ -90,13 +91,13 @@ export function fetchSandboxRows(
|
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
93
|
* Returns true iff `arg` is a syntactically valid task short reference.
|
|
93
|
-
* Accepts
|
|
94
|
+
* Accepts bare numeric ('11') task short ids.
|
|
94
95
|
* Zero IO. Callers MUST use this as the gate before constructing any context
|
|
95
96
|
* for resolveTaskShortRef — that way non-matching arguments (e.g. '#abc',
|
|
96
97
|
* '#1.5', '#') never trigger sandbox list IO.
|
|
97
98
|
*/
|
|
98
99
|
export function isTaskShortRef(arg: string): boolean {
|
|
99
|
-
return
|
|
100
|
+
return /^\d+$/.test(arg);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
type RegistryLookup =
|
|
@@ -115,9 +116,7 @@ type RegistryLookup =
|
|
|
115
116
|
function tryResolveFromRegistry(arg: string, repoRoot: string): RegistryLookup {
|
|
116
117
|
const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
|
|
117
118
|
if (!fs.existsSync(scriptPath)) return { status: 'miss' };
|
|
118
|
-
//
|
|
119
|
-
// (Script accepts both forms, but this avoids shell quoting confusion in error
|
|
120
|
-
// messages echoed back to the user.)
|
|
119
|
+
// Forward the bare-numeric short ref to the registry script for ID resolution.
|
|
121
120
|
const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
|
|
122
121
|
if (result.status !== 0) return { status: 'miss' };
|
|
123
122
|
const taskId = (result.stdout || '').trim();
|
|
@@ -149,7 +148,7 @@ function tryResolveFromRegistry(arg: string, repoRoot: string): RegistryLookup {
|
|
|
149
148
|
|
|
150
149
|
/**
|
|
151
150
|
/**
|
|
152
|
-
* Resolve a task short reference
|
|
151
|
+
* Resolve a bare task short reference to a branch name for the
|
|
153
152
|
* sandbox entrypoint.
|
|
154
153
|
*
|
|
155
154
|
* Resolution: registry-only. Look up the short id in the global task-short-id
|
|
@@ -169,13 +168,13 @@ export function resolveTaskShortRef(
|
|
|
169
168
|
if (lookup.status === 'hit') return lookup.branch;
|
|
170
169
|
throw new Error(
|
|
171
170
|
`short ref '${arg}' is not in the active task registry. ` +
|
|
172
|
-
`
|
|
171
|
+
`bare N resolves only via the registry (not by row position in 'ai sandbox ls'); ` +
|
|
173
172
|
`use a task short id (e.g. 'ai sandbox exec 11'), a TASK-id, or a branch name.`
|
|
174
173
|
);
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
/**
|
|
178
|
-
* Resolve a sandbox command argument (`<branch | TASK-id | N
|
|
177
|
+
* Resolve a sandbox command argument (`<branch | TASK-id | N>`) to a
|
|
179
178
|
* branch name, mirroring `ai sandbox exec` so that `start` and `exec` share one
|
|
180
179
|
* input contract. Short refs go through the registry-only resolver (which throws
|
|
181
180
|
* an actionable error on a miss); everything else flows through resolveTaskBranch
|
|
@@ -183,6 +182,9 @@ export function resolveTaskShortRef(
|
|
|
183
182
|
* Callers still run assertValidBranchName on the result.
|
|
184
183
|
*/
|
|
185
184
|
export function resolveBranchArg(arg: string, ctx: { repoRoot: string }): string {
|
|
185
|
+
if (isRemovedHashShortIdInput(arg)) {
|
|
186
|
+
throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
|
|
187
|
+
}
|
|
186
188
|
return isTaskShortRef(arg)
|
|
187
189
|
? resolveTaskShortRef(arg, ctx)
|
|
188
190
|
: resolveTaskBranch(arg, ctx.repoRoot);
|
|
@@ -7,12 +7,12 @@ import { assertValidBranchName, worktreeDirCandidates } from '../constants.ts';
|
|
|
7
7
|
import { resolveBranchArg } from './list-running.ts';
|
|
8
8
|
import { resolveTools, toolConfigDirCandidates } from '../tools.ts';
|
|
9
9
|
|
|
10
|
-
const USAGE = `Usage: ai sandbox show <branch | TASK-id | N
|
|
10
|
+
const USAGE = `Usage: ai sandbox show <branch | TASK-id | N>
|
|
11
11
|
|
|
12
12
|
Shows one sandbox's worktree path and per-tool state paths (Claude Code,
|
|
13
13
|
Codex, Gemini CLI, OpenCode). The argument follows the same contract as
|
|
14
14
|
'ai sandbox exec' and 'ai sandbox start': N (bare) is the recommended form
|
|
15
|
-
for task short ids (e.g. 'ai sandbox show 11');
|
|
15
|
+
for task short ids (e.g. 'ai sandbox show 11'); a TASK-id or a plain
|
|
16
16
|
branch name are also accepted. Use 'ai sandbox ls' for the container list.`;
|
|
17
17
|
|
|
18
18
|
export type SandboxDetail = {
|