@fitlab-ai/agent-infra 0.9.10 → 0.9.12
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 +19 -9
- package/README.zh-CN.md +19 -9
- package/bin/cli.ts +17 -4
- package/dist/bin/cli.js +19 -4
- package/dist/bin/internal-cli.js +55 -4
- package/dist/lib/agent-client.js +0 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
- package/dist/lib/agent-clients/adapters/opencode-sandbox.js +0 -4
- package/dist/lib/agent-clients/adapters/traecli.js +7 -8
- package/dist/lib/agent-clients/config.js +14 -99
- package/dist/lib/agent-clients/reconcile.js +1 -11
- package/dist/lib/agent-clients/schema.js +5 -4
- package/dist/lib/agent-clients/tokens.js +5 -15
- package/dist/lib/decide.js +14 -30
- package/dist/lib/defaults.json +8 -0
- package/dist/lib/git/workflow.js +43 -1
- package/dist/lib/init.js +3 -2
- package/dist/lib/internal/git-workflow.js +8 -1
- package/dist/lib/internal/platform-pr.js +8 -2
- package/dist/lib/internal/release-workflow.js +0 -1
- package/dist/lib/internal/task-delivery.js +59 -0
- package/dist/lib/internal/task-finalization.js +19 -9
- package/dist/lib/internal/task-ledger.js +8 -2
- package/dist/lib/internal/task-lifecycle.js +17 -93
- package/dist/lib/internal/task-orchestration.js +30 -216
- package/dist/lib/internal/task-validate.js +2 -1
- package/dist/lib/merge.js +205 -103
- package/dist/lib/platform/github-client.js +7 -1
- package/dist/lib/platform/pr-checks.js +8 -5
- package/dist/lib/platform/pr-summary.js +12 -8
- package/dist/lib/platform/pull-requests.js +393 -91
- package/dist/lib/platform/verification-required.js +13 -2
- package/dist/lib/platform/verification-sync.js +9 -4
- package/dist/lib/pr-review/evidence-grading.js +12 -4
- package/dist/lib/process-data/normalize.js +2 -9
- package/dist/lib/run/host.js +46 -16
- package/dist/lib/sandbox/agent-client-reconciler.js +4 -12
- package/dist/lib/sandbox/commands/create.js +3 -3
- package/dist/lib/sandbox/commands/enter.js +18 -4
- package/dist/lib/sandbox/config.js +8 -12
- package/dist/lib/sandbox/control/executor.js +131 -39
- package/dist/lib/sandbox/control/lifecycle.js +55 -24
- package/dist/lib/sandbox/control/server.js +18 -16
- package/dist/lib/sandbox/mounts.js +3 -2
- package/dist/lib/sandbox/recovery.js +123 -22
- package/dist/lib/sandbox/workspace-identity.js +14 -0
- package/dist/lib/sandbox/workspace-view.js +8 -9
- package/dist/lib/self-update.js +278 -0
- package/dist/lib/server/process-state.js +2 -2
- package/dist/lib/server/protocol.js +5 -5
- package/dist/lib/task/activity-log.js +4 -1
- package/dist/lib/task/artifact-lifecycle.js +6 -4
- package/dist/lib/task/codex-orchestration.js +1 -1
- package/dist/lib/task/command-options.js +1 -3
- package/dist/lib/task/commands/cat.js +0 -5
- package/dist/lib/task/commands/decisions.js +76 -92
- package/dist/lib/task/commands/files.js +6 -6
- package/dist/lib/task/commands/grep.js +25 -61
- package/dist/lib/task/commands/issue-body.js +6 -6
- package/dist/lib/task/commands/log.js +25 -10
- package/dist/lib/task/commands/show.js +5 -6
- package/dist/lib/task/commands/status.js +8 -8
- package/dist/lib/task/commit-intent.js +100 -0
- package/dist/lib/task/commit-operation.js +181 -91
- package/dist/lib/task/commit-policy.js +1 -1
- package/dist/lib/task/control-authority.js +431 -0
- package/dist/lib/task/create.js +39 -8
- package/dist/lib/task/current-contract.js +35 -0
- package/dist/lib/task/decision-details.js +218 -0
- package/dist/lib/task/decision-intents.js +5 -2
- package/dist/lib/task/delivery-target.js +97 -0
- package/dist/lib/task/delivery.js +153 -0
- package/dist/lib/task/events.js +11 -5
- package/dist/lib/task/human-override.js +5 -2
- package/dist/lib/task/index.js +19 -20
- package/dist/lib/task/ledger-intents.js +8 -9
- package/dist/lib/task/ledger.js +13 -6
- package/dist/lib/task/lifecycle.js +122 -9
- package/dist/lib/task/orchestration.js +105 -75
- package/dist/lib/task/pr-delivery-fact.js +182 -0
- package/dist/lib/task/review-artifacts.js +31 -12
- package/dist/lib/task/review-finalization.js +13 -4
- package/dist/lib/task/review-fingerprint.js +8 -0
- package/dist/lib/task/verification-engine.js +86 -39
- package/dist/lib/task/verification-review.js +2 -2
- package/dist/lib/task/workspace-snapshot.js +5 -11
- package/dist/lib/task/write.js +11 -1
- package/dist/lib/update.js +13 -35
- package/dist/lib/version.js +5 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +0 -1
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
- package/lib/agent-clients/adapters/opencode-sandbox.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +7 -8
- package/lib/agent-clients/config.ts +14 -144
- package/lib/agent-clients/reconcile.ts +1 -12
- package/lib/agent-clients/schema.ts +5 -4
- package/lib/agent-clients/tokens.ts +5 -18
- package/lib/decide.ts +12 -22
- package/lib/defaults.json +8 -0
- package/lib/git/workflow.ts +38 -1
- package/lib/init.ts +5 -2
- package/lib/internal/git-workflow.ts +7 -1
- package/lib/internal/platform-pr.ts +8 -1
- package/lib/internal/release-workflow.ts +0 -1
- package/lib/internal/task-delivery.ts +53 -0
- package/lib/internal/task-finalization.ts +27 -13
- package/lib/internal/task-ledger.ts +8 -2
- package/lib/internal/task-lifecycle.ts +33 -76
- package/lib/internal/task-orchestration.ts +33 -190
- package/lib/internal/task-validate.ts +3 -2
- package/lib/merge.ts +236 -120
- package/lib/platform/github-client.ts +8 -1
- package/lib/platform/pr-checks.ts +7 -5
- package/lib/platform/pr-summary.ts +10 -7
- package/lib/platform/pull-requests.ts +425 -87
- package/lib/platform/verification-required.ts +12 -2
- package/lib/platform/verification-sync.ts +9 -4
- package/lib/pr-review/evidence-grading.ts +7 -4
- package/lib/process-data/normalize.ts +2 -8
- package/lib/run/host.ts +63 -14
- package/lib/sandbox/agent-client-reconciler.ts +5 -15
- package/lib/sandbox/commands/create.ts +4 -4
- package/lib/sandbox/commands/enter.ts +24 -4
- package/lib/sandbox/config.ts +9 -14
- package/lib/sandbox/control/container-identity.ts +2 -2
- package/lib/sandbox/control/executor.ts +148 -51
- package/lib/sandbox/control/lifecycle.ts +59 -31
- package/lib/sandbox/control/protocol.ts +1 -3
- package/lib/sandbox/control/server.ts +15 -12
- package/lib/sandbox/control/state.ts +7 -7
- package/lib/sandbox/mounts.ts +4 -3
- package/lib/sandbox/recovery.ts +162 -34
- package/lib/sandbox/tools.ts +1 -1
- package/lib/sandbox/workspace-identity.ts +28 -0
- package/lib/sandbox/workspace-view.ts +14 -10
- package/lib/self-update.ts +341 -0
- package/lib/server/process-state.ts +2 -2
- package/lib/server/protocol.ts +5 -5
- package/lib/task/activity-log.ts +6 -1
- package/lib/task/artifact-lifecycle.ts +7 -5
- package/lib/task/codex-orchestration.ts +2 -1
- package/lib/task/command-options.ts +1 -2
- package/lib/task/commands/cat.ts +0 -4
- package/lib/task/commands/decisions.ts +80 -75
- package/lib/task/commands/files.ts +6 -6
- package/lib/task/commands/grep.ts +23 -51
- package/lib/task/commands/issue-body.ts +6 -6
- package/lib/task/commands/log.ts +22 -10
- package/lib/task/commands/show.ts +5 -6
- package/lib/task/commands/status.ts +8 -8
- package/lib/task/commit-intent.ts +137 -0
- package/lib/task/commit-operation.ts +161 -79
- package/lib/task/commit-policy.ts +1 -2
- package/lib/task/control-authority.ts +563 -0
- package/lib/task/create.ts +40 -10
- package/lib/task/current-contract.ts +49 -0
- package/lib/task/decision-details.ts +280 -0
- package/lib/task/decision-intents.ts +7 -2
- package/lib/task/delivery-target.ts +130 -0
- package/lib/task/delivery.ts +160 -0
- package/lib/task/events.ts +10 -5
- package/lib/task/human-override.ts +5 -2
- package/lib/task/index.ts +19 -20
- package/lib/task/ledger-intents.ts +6 -8
- package/lib/task/ledger.ts +17 -7
- package/lib/task/lifecycle.ts +113 -4
- package/lib/task/orchestration.ts +102 -80
- package/lib/task/pr-delivery-fact.ts +254 -0
- package/lib/task/review-artifacts.ts +53 -15
- package/lib/task/review-finalization.ts +21 -5
- package/lib/task/review-fingerprint.ts +10 -0
- package/lib/task/verification-engine.ts +78 -46
- package/lib/task/verification-review.ts +3 -1
- package/lib/task/workspace-snapshot.ts +4 -13
- package/lib/task/write.ts +20 -1
- package/lib/update.ts +14 -38
- package/lib/version.ts +6 -1
- package/package.json +1 -1
- package/templates/.agents/README.en.md +5 -3
- package/templates/.agents/README.zh-CN.md +5 -3
- package/templates/.agents/rules/README.en.md +4 -2
- package/templates/.agents/rules/README.zh-CN.md +4 -2
- package/templates/.agents/rules/compatibility-policy.en.md +5 -4
- package/templates/.agents/rules/compatibility-policy.zh-CN.md +5 -4
- package/templates/.agents/rules/create-issue.en.md +11 -2
- package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
- package/templates/.agents/rules/human-decision-context.en.md +9 -7
- package/templates/.agents/rules/human-decision-context.zh-CN.md +9 -7
- package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +1 -1
- package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +1 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +5 -18
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +26 -5
- package/templates/.agents/rules/issue-sync.zh-CN.md +62 -5
- package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
- package/templates/.agents/rules/local-artifact-repair.en.md +46 -0
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +46 -0
- package/templates/.agents/rules/milestone-inference.en.md +12 -2
- package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
- package/templates/.agents/rules/next-step-output.en.md +3 -3
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -3
- package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -1
- package/templates/.agents/rules/pr-sync.en.md +23 -14
- package/templates/.agents/rules/pr-sync.zh-CN.md +23 -2
- package/templates/.agents/rules/release-commands.en.md +42 -3
- package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
- package/templates/.agents/rules/review-handshake.en.md +1 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
- package/templates/.agents/rules/security-alerts.en.md +17 -2
- package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
- package/templates/.agents/rules/sync-content-generation.en.md +8 -0
- package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
- package/templates/.agents/rules/task-management.en.md +2 -3
- package/templates/.agents/rules/task-management.zh-CN.md +2 -3
- package/templates/.agents/scripts/security-alerts.github.sh +151 -0
- package/templates/.agents/scripts/security-alerts.sh +31 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +4 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +4 -3
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/check-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -3
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -3
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.en.md +8 -5
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +9 -6
- package/templates/.agents/skills/commit/SKILL.en.md +30 -10
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +6 -7
- package/templates/.agents/skills/commit/config/verify.json +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
- 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 +2 -2
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +7 -6
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -6
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- 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 +13 -13
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +13 -13
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +9 -11
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -4
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +203 -0
- package/templates/.agents/skills/create-release-note/SKILL.en.md +5 -6
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +5 -6
- package/templates/.agents/skills/create-task/SKILL.en.md +2 -1
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +2 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
- package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
- package/templates/.agents/skills/plan-task/SKILL.en.md +4 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -3
- package/templates/.agents/skills/restore-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +8 -5
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
- 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/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +2 -1
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +2 -1
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +8 -5
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +5 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +144 -109
- package/templates/.agents/skills/watch-pr/SKILL.en.md +5 -5
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +5 -5
- package/templates/.agents/templates/task.en.md +6 -2
- package/templates/.agents/templates/task.zh-CN.md +6 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/feature-development.en.yaml +9 -8
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/refactoring.en.yaml +9 -8
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
- 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 -1
- package/templates/.claude/commands/commit.zh-CN.md +1 -1
- 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/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/templates/.claude/commands/run-task.en.md +1 -1
- package/templates/.claude/commands/run-task.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/{.trae/skills → .traecli/commands}/update-agent-infra.en.md +0 -1
- package/templates/{.trae/skills → .traecli/commands}/update-agent-infra.zh-CN.md +0 -1
- package/dist/lib/builtin-tuis.js +0 -40
- package/lib/builtin-tuis.ts +0 -56
- package/templates/.agents/rules/create-issue.github.en.md +0 -14
- package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
- package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
- package/templates/.agents/rules/issue-sync.github.en.md +0 -40
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
- package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
- package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
- package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
- package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
- package/templates/.agents/rules/pr-sync.github.en.md +0 -43
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
- package/templates/.agents/rules/release-commands.github.en.md +0 -38
- package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -38
- package/templates/.agents/rules/security-alerts.github.en.md +0 -43
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
|
@@ -5,6 +5,7 @@ import { hasPlatformCapability } from "./adapters.js";
|
|
|
5
5
|
import { inspectRequiredChecks } from "./pr-checks.js";
|
|
6
6
|
import { resolvePlatformContext } from "./context.js";
|
|
7
7
|
import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.js";
|
|
8
|
+
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
8
9
|
const CHECK_TYPE = "required-checks";
|
|
9
10
|
const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
|
|
10
11
|
function validPrNumber(value) {
|
|
@@ -30,7 +31,13 @@ function readHead(repoRoot) {
|
|
|
30
31
|
}
|
|
31
32
|
export function evaluateRequiredChecks(context, shared) {
|
|
32
33
|
const { metadata, localHead, inspection, prFlow } = context;
|
|
33
|
-
|
|
34
|
+
const factRead = readPrDeliveryFact(metadata);
|
|
35
|
+
if (factRead.status === "invalid") {
|
|
36
|
+
return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
|
|
37
|
+
}
|
|
38
|
+
const fact = factRead.status === "valid" ? factRead.fact : null;
|
|
39
|
+
const prNumber = fact?.state === "bound" ? fact.identity.number : null;
|
|
40
|
+
if (prFlow === "disabled" || fact?.state === "skipped" || !validPrNumber(prNumber)) {
|
|
34
41
|
return shared.passResult(CHECK_TYPE, "Skipped: required checks are not applicable to this task");
|
|
35
42
|
}
|
|
36
43
|
const reviewedHead = String(metadata.last_reviewed_commit || "");
|
|
@@ -78,7 +85,11 @@ export function check({ taskDir }, shared) {
|
|
|
78
85
|
if (!task.ok)
|
|
79
86
|
return shared.failResult(CHECK_TYPE, task.message);
|
|
80
87
|
const prFlow = readPrFlow(shared.repoRoot);
|
|
81
|
-
|
|
88
|
+
const factRead = readPrDeliveryFact(task.metadata);
|
|
89
|
+
if (factRead.status === "invalid")
|
|
90
|
+
return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
|
|
91
|
+
const bound = factRead.status === "valid" && factRead.fact.state === "bound";
|
|
92
|
+
if (prFlow === "disabled" || (factRead.status === "valid" && factRead.fact.state === "skipped") || !bound) {
|
|
82
93
|
return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
|
|
83
94
|
}
|
|
84
95
|
const platform = resolvePlatformContext({ cwd: shared.repoRoot });
|
|
@@ -9,6 +9,7 @@ import { inspectGitHubIssueMetadata, requirementSectionAnchors } from "./issues.
|
|
|
9
9
|
import { listRemoteComments } from "./issue-comments.js";
|
|
10
10
|
import { taskTypeLabel } from "./metadata-labels.js";
|
|
11
11
|
import { inspectGitHubPullRequest } from "./pull-requests.js";
|
|
12
|
+
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
12
13
|
const CHECK_TYPE = "platform-sync";
|
|
13
14
|
const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
|
|
14
15
|
const FRONTMATTER_FIELD_MAP = {
|
|
@@ -127,12 +128,16 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
|
127
128
|
return { earlyReturn: failResult(CHECK_TYPE, task.message) };
|
|
128
129
|
}
|
|
129
130
|
const issueNumber = parseIssueNumber(task.metadata.issue_number);
|
|
130
|
-
const
|
|
131
|
+
const fact = readPrDeliveryFact(task.metadata);
|
|
132
|
+
if (fact.status === "invalid") {
|
|
133
|
+
return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
|
|
134
|
+
}
|
|
135
|
+
const prNumber = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.number : null;
|
|
131
136
|
if (config.when === "issue_number_exists" && !issueNumber) {
|
|
132
137
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
|
|
133
138
|
}
|
|
134
|
-
if (config.when === "
|
|
135
|
-
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no
|
|
139
|
+
if (config.when === "pr_fact_bound" && !prNumber) {
|
|
140
|
+
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
|
|
136
141
|
}
|
|
137
142
|
if (!issueNumber) {
|
|
138
143
|
return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
|
|
@@ -276,7 +281,7 @@ function fetchRemoteData(context) {
|
|
|
276
281
|
if (context.prMarker) {
|
|
277
282
|
if (!context.prNumber) {
|
|
278
283
|
return {
|
|
279
|
-
earlyReturn: failResult(CHECK_TYPE, "Expected a
|
|
284
|
+
earlyReturn: failResult(CHECK_TYPE, "Expected a verified bound pull request for PR comment verification", "check_failed")
|
|
280
285
|
};
|
|
281
286
|
}
|
|
282
287
|
const prCommentsResult = listRemoteComments(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
4
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
|
|
4
5
|
export class HostResolutionError extends Error {
|
|
5
6
|
code;
|
|
6
7
|
constructor(code, message) {
|
|
@@ -38,7 +39,7 @@ export function extractClosingIssueNumbers(body) {
|
|
|
38
39
|
/**
|
|
39
40
|
* Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
|
|
40
41
|
* PR number or to one of the PR's closing issues. A task is emitted at most once;
|
|
41
|
-
* a
|
|
42
|
+
* a verified fact identity hit takes priority over the issue-number reverse lookup.
|
|
42
43
|
*/
|
|
43
44
|
export function collectHostCandidates(input) {
|
|
44
45
|
const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
|
|
@@ -62,9 +63,16 @@ export function collectHostCandidates(input) {
|
|
|
62
63
|
catch {
|
|
63
64
|
continue;
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
let frontmatter;
|
|
67
|
+
try {
|
|
68
|
+
frontmatter = parseTypedTaskFrontmatter(content);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
66
73
|
const issueNumber = toPositiveNumber(frontmatter.issue_number);
|
|
67
|
-
const
|
|
74
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
75
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
68
76
|
if (prNumber === input.prNumber) {
|
|
69
77
|
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
|
|
70
78
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sha256 } from './store.js';
|
|
2
|
+
import { normalizeAgentToken } from '../agent-clients/tokens.js';
|
|
2
3
|
const TASK_ID_RE = /TASK-\d{8}-\d{6}/;
|
|
3
4
|
const ACTIVITY_RE = /^- (\d{4}-\d{2}-\d{2} [^ ]+) — \*\*(.+?)\*\* by ([^ ]+) — (.+)$/gm;
|
|
4
5
|
const LEDGER_RE = /^\|\s*((?:AN|PL|CD)-\d+)\s*\|\s*(analysis|plan|code)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|$/gm;
|
|
@@ -9,15 +10,7 @@ function recordId(kind, identity, suffix = '') {
|
|
|
9
10
|
}
|
|
10
11
|
function canonicalActor(raw) {
|
|
11
12
|
const lowered = raw.toLowerCase();
|
|
12
|
-
|
|
13
|
-
'claude-code': 'claude',
|
|
14
|
-
'antigravity-cli': 'antigravity',
|
|
15
|
-
'gemini-cli': 'gemini',
|
|
16
|
-
gemini: 'gemini'
|
|
17
|
-
};
|
|
18
|
-
if (['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'human'].includes(lowered))
|
|
19
|
-
return lowered;
|
|
20
|
-
return aliases[lowered] ?? null;
|
|
13
|
+
return normalizeAgentToken(lowered);
|
|
21
14
|
}
|
|
22
15
|
function nextOccurrence(occurrences, identity) {
|
|
23
16
|
const occurrence = (occurrences.get(identity) ?? 0) + 1;
|
package/dist/lib/run/host.js
CHANGED
|
@@ -1,26 +1,55 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
function
|
|
5
|
-
if (
|
|
6
|
-
return file;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
function resolveCommandDetails(file, platform = process.platform, env = process.env) {
|
|
5
|
+
if (path.isAbsolute(file))
|
|
6
|
+
return { path: file, source: 'absolute' };
|
|
7
|
+
const pathValue = platform === 'win32'
|
|
8
|
+
? env.Path || env.PATH || ''
|
|
9
|
+
: env.PATH || '';
|
|
10
|
+
const extensions = platform === 'win32'
|
|
11
|
+
? (path.extname(file)
|
|
12
|
+
? ['']
|
|
13
|
+
: (env.PATHEXT || '.COM;.EXE;.BAT;.CMD').split(';').filter(Boolean))
|
|
14
|
+
: [''];
|
|
15
|
+
for (const dir of pathValue.split(path.delimiter)) {
|
|
11
16
|
for (const extension of extensions) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const candidates = extension
|
|
18
|
+
? [`${file}${extension.toLowerCase()}`, `${file}${extension.toUpperCase()}`]
|
|
19
|
+
: [file];
|
|
20
|
+
for (const candidateName of candidates) {
|
|
21
|
+
const candidate = path.resolve(dir || '.', candidateName);
|
|
22
|
+
try {
|
|
23
|
+
const stat = fs.statSync(candidate);
|
|
24
|
+
if (!stat.isFile())
|
|
25
|
+
continue;
|
|
26
|
+
if (platform !== 'win32' && (stat.mode & 0o111) === 0)
|
|
27
|
+
continue;
|
|
28
|
+
return {
|
|
29
|
+
path: candidate,
|
|
30
|
+
source: dir ? 'path' : 'current-directory',
|
|
31
|
+
pathEntry: dir
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Keep searching the remaining PATH entries.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
18
38
|
}
|
|
19
39
|
}
|
|
20
|
-
return file;
|
|
40
|
+
return { path: file, source: 'unresolved' };
|
|
41
|
+
}
|
|
42
|
+
function resolveCommand(file, platform = process.platform, env = process.env) {
|
|
43
|
+
return resolveCommandDetails(file, platform, env).path;
|
|
44
|
+
}
|
|
45
|
+
function resolveCommandFromAbsolutePath(file, platform = process.platform, env = process.env) {
|
|
46
|
+
const resolution = resolveCommandDetails(file, platform, env);
|
|
47
|
+
return resolution.source === 'path' && resolution.pathEntry && path.isAbsolute(resolution.pathEntry)
|
|
48
|
+
? resolution.path
|
|
49
|
+
: null;
|
|
21
50
|
}
|
|
22
|
-
function needsShell(file) {
|
|
23
|
-
return
|
|
51
|
+
function needsShell(file, platform = process.platform) {
|
|
52
|
+
return platform === 'win32' && /\.(?:bat|cmd)$/i.test(file);
|
|
24
53
|
}
|
|
25
54
|
export async function runHostCommand(command) {
|
|
26
55
|
const [file, ...args] = command;
|
|
@@ -36,4 +65,5 @@ export async function runHostCommand(command) {
|
|
|
36
65
|
child.on('close', (exitCode, signal) => resolve({ exitCode, signal }));
|
|
37
66
|
});
|
|
38
67
|
}
|
|
68
|
+
export { needsShell, resolveCommand, resolveCommandFromAbsolutePath };
|
|
39
69
|
//# sourceMappingURL=host.js.map
|
|
@@ -15,15 +15,6 @@ function agentInfraTool(home) {
|
|
|
15
15
|
setupHint: 'Provides the ai and agent-infra CLI commands inside the sandbox.'
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
-
function compatAgentClientState(tools) {
|
|
19
|
-
return Object.fromEntries(listAgentClientAdapters().map((adapter) => [
|
|
20
|
-
adapter.id,
|
|
21
|
-
{
|
|
22
|
-
enabled: true,
|
|
23
|
-
installInSandbox: tools.includes(adapter.id)
|
|
24
|
-
}
|
|
25
|
-
]));
|
|
26
|
-
}
|
|
27
18
|
function stableValue(value) {
|
|
28
19
|
if (Array.isArray(value)) {
|
|
29
20
|
return value.map(stableValue);
|
|
@@ -96,7 +87,7 @@ function hooksByPhase(adapters) {
|
|
|
96
87
|
])));
|
|
97
88
|
}
|
|
98
89
|
function createSandboxCapabilityPlan(config) {
|
|
99
|
-
const state = config.agentClientState
|
|
90
|
+
const state = config.agentClientState;
|
|
100
91
|
const selectedAgentClients = listInstalledAgentClientAdapters(state);
|
|
101
92
|
const context = { home: config.home, project: config.project };
|
|
102
93
|
const selectedTools = selectedAgentClients.map((adapter) => adapter.sandbox.createTool(context));
|
|
@@ -113,8 +104,9 @@ function createSandboxCapabilityPlan(config) {
|
|
|
113
104
|
const nonClientTools = [];
|
|
114
105
|
const selectedCustomTools = [];
|
|
115
106
|
for (const id of config.tools) {
|
|
116
|
-
if (isAgentClientId(id))
|
|
117
|
-
|
|
107
|
+
if (isAgentClientId(id)) {
|
|
108
|
+
throw new Error(`Agent Client '${id}' must be provided by agentClientState`);
|
|
109
|
+
}
|
|
118
110
|
if (id === 'agent-infra') {
|
|
119
111
|
if (!nonClientTools.some((tool) => tool.id === id)) {
|
|
120
112
|
nonClientTools.push(agentInfraTool(config.home));
|
|
@@ -17,7 +17,7 @@ import { parseSandboxWorkspaceIdentity, resolveSandboxTarget, sameSandboxWorkspa
|
|
|
17
17
|
import { createSandboxCapabilityPlan, runSandboxHooks, runBoundedSandboxHookCommand } from '../agent-client-reconciler.js';
|
|
18
18
|
import { resolveTools, tmpfsSeedStagingPath, tmpfsSeedTargetPath, toolConfigDirCandidates } from '../tools.js';
|
|
19
19
|
import { assertFreshSandboxReady, hydrateTmpfsSeedEntries, prepareTmpfsMounts, startSandboxControlBroker } from '../recovery.js';
|
|
20
|
-
import { acquireSandboxControlReplacement, assertSandboxControlCutoverSnapshot, beginSandboxControlReplacement, captureSandboxControlCutoverSnapshot, commitSandboxControlReplacement, quiesceSandboxControlRoot, recoverSandboxControlReplacement,
|
|
20
|
+
import { acquireSandboxControlReplacement, assertSandboxControlCutoverSnapshot, beginSandboxControlReplacement, captureSandboxControlCutoverSnapshot, commitSandboxControlReplacement, quiesceSandboxControlRoot, recoverSandboxControlReplacement, readSandboxControlManifest } from '../control/lifecycle.js';
|
|
21
21
|
import { inspectSandboxControlContainer } from '../control/container-identity.js';
|
|
22
22
|
import { hostJoin, toEnginePath, volumeArg } from '../engines/wsl2-paths.js';
|
|
23
23
|
import { sandboxCoreBindMounts } from '../mounts.js';
|
|
@@ -879,7 +879,7 @@ export async function create(args) {
|
|
|
879
879
|
const recoveryResult = await recoverSandboxControlReplacement(controlPaths.root, replacementLease);
|
|
880
880
|
const hadExistingControlRoot = hadControlRootBeforeAcquire || recoveryResult === 'restored';
|
|
881
881
|
const previousManifest = fs.existsSync(controlPaths.manifestPath)
|
|
882
|
-
?
|
|
882
|
+
? readSandboxControlManifest(controlPaths.manifestPath)
|
|
883
883
|
: null;
|
|
884
884
|
if (hadExistingControlRoot) {
|
|
885
885
|
await quiesceSandboxControlRoot(controlPaths.root);
|
|
@@ -1031,7 +1031,7 @@ export async function create(args) {
|
|
|
1031
1031
|
...(target.workspace.mode === 'task-bound' ? { runtimeDir: control.runtimeDir } : {}),
|
|
1032
1032
|
...(target.workspace.mode === 'task-bound'
|
|
1033
1033
|
? {
|
|
1034
|
-
|
|
1034
|
+
taskSources: [assertSandboxTaskSource(effectiveConfig.repoRoot, target.workspace.taskId)],
|
|
1035
1035
|
taskId: target.workspace.taskId
|
|
1036
1036
|
}
|
|
1037
1037
|
: {})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadConfig } from '../config.js';
|
|
2
|
-
import { assertValidBranchName, containerNameCandidates, sandboxBranchLabel, sandboxLabel } from '../constants.js';
|
|
2
|
+
import { assertValidBranchName, containerNameCandidates, sandboxBranchLabel, sandboxLabel, sandboxTaskIdLabel, sandboxWorkspaceModeLabel } from '../constants.js';
|
|
3
3
|
import { detectEngine } from '../engine.js';
|
|
4
4
|
import { ensureSandboxReady } from '../recovery.js';
|
|
5
5
|
import { createSandboxCapabilityPlan, runBoundedSandboxHookCommand, runSandboxHooks } from '../agent-client-reconciler.js';
|
|
@@ -9,7 +9,7 @@ import { redactCommandError } from '../redaction.js';
|
|
|
9
9
|
import { runInteractiveWithClipboardBridge } from '../clipboard/bridge.js';
|
|
10
10
|
import { detectHostTimezone } from '../host-timezone.js';
|
|
11
11
|
import { fetchSandboxRows, selectSandboxContainer, } from './list-running.js';
|
|
12
|
-
import { resolveSandboxTarget } from '../workspace-identity.js';
|
|
12
|
+
import { resolveSandboxReentryContext, resolveSandboxTarget } from '../workspace-identity.js';
|
|
13
13
|
const USAGE = `Usage: ai sandbox exec [--recreate] <branch | TASK-id | N> [cmd...]
|
|
14
14
|
|
|
15
15
|
N references an active task short id from
|
|
@@ -81,16 +81,30 @@ export async function enter(args) {
|
|
|
81
81
|
const target = resolveSandboxTarget(parsed.target, config.repoRoot);
|
|
82
82
|
const branch = target.branch;
|
|
83
83
|
assertValidBranchName(branch);
|
|
84
|
-
const { running, nonRunning } = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config)
|
|
84
|
+
const { running, nonRunning } = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config), {
|
|
85
|
+
mode: sandboxWorkspaceModeLabel(config),
|
|
86
|
+
taskId: sandboxTaskIdLabel(config)
|
|
87
|
+
});
|
|
85
88
|
const found = selectSandboxContainer([...running, ...nonRunning], containerNameCandidates(config, branch));
|
|
86
89
|
if (!found) {
|
|
87
90
|
throw new Error(`No sandbox found for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`);
|
|
88
91
|
}
|
|
92
|
+
const containerWorkspace = found.workspaceMode === 'task-bound' && found.taskId
|
|
93
|
+
? { mode: 'task-bound', taskId: found.taskId }
|
|
94
|
+
: found.workspaceMode === 'branch-only'
|
|
95
|
+
? { mode: 'branch-only' }
|
|
96
|
+
: { mode: 'legacy-invalid' };
|
|
97
|
+
const reentry = resolveSandboxReentryContext({
|
|
98
|
+
target,
|
|
99
|
+
containerWorkspace,
|
|
100
|
+
repoRoot: config.repoRoot
|
|
101
|
+
});
|
|
89
102
|
const ready = await ensureSandboxReady({
|
|
90
103
|
config,
|
|
91
104
|
engine,
|
|
92
105
|
branch,
|
|
93
|
-
workspace:
|
|
106
|
+
workspace: reentry.workspace,
|
|
107
|
+
reentry: reentry.reentry,
|
|
94
108
|
row: found,
|
|
95
109
|
allowRecreate: parsed.recreate,
|
|
96
110
|
recreate: async () => {
|
|
@@ -4,7 +4,6 @@ import { homedir, platform } from 'node:os';
|
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
5
|
import pc from 'picocolors';
|
|
6
6
|
import { normalizeAgentClients } from '../agent-clients/config.js';
|
|
7
|
-
import { isAgentClientId } from '../agent-clients/types.js';
|
|
8
7
|
import { validateSandboxEngine } from './engine.js';
|
|
9
8
|
import { hostJoin } from './engines/wsl2-paths.js';
|
|
10
9
|
import { findRuntimeEngineMismatches } from './runtime-engines.js';
|
|
@@ -48,15 +47,9 @@ function cloneDefaults() {
|
|
|
48
47
|
vm: { ...DEFAULTS.vm }
|
|
49
48
|
};
|
|
50
49
|
}
|
|
51
|
-
function resolveSandboxToolIds(sandbox,
|
|
50
|
+
function resolveSandboxToolIds(sandbox, defaults) {
|
|
52
51
|
if (Array.isArray(sandbox.tools)) {
|
|
53
|
-
|
|
54
|
-
return agentClients.source === 'canonical'
|
|
55
|
-
? tools.filter((tool) => !isAgentClientId(tool))
|
|
56
|
-
: tools;
|
|
57
|
-
}
|
|
58
|
-
if (agentClients.remainingSandboxTools !== undefined) {
|
|
59
|
-
return [...agentClients.remainingSandboxTools];
|
|
52
|
+
return sandbox.tools.filter((tool) => typeof tool === 'string');
|
|
60
53
|
}
|
|
61
54
|
return [...defaults];
|
|
62
55
|
}
|
|
@@ -71,10 +64,10 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
71
64
|
throw new Error('No .agents/.airc.json found. Run "ai init" first.');
|
|
72
65
|
}
|
|
73
66
|
const airc = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
74
|
-
const sandboxInput = airc.sandbox;
|
|
75
67
|
const agentClients = normalizeAgentClients(airc);
|
|
76
68
|
const defaults = cloneDefaults();
|
|
77
69
|
const sandbox = airc.sandbox ?? {};
|
|
70
|
+
const delivery = airc.delivery ?? {};
|
|
78
71
|
const engine = validateSandboxEngine(sandbox.engine ?? defaults.engine, { platformFn });
|
|
79
72
|
const project = airc.project;
|
|
80
73
|
if (!project || typeof project !== 'string') {
|
|
@@ -99,7 +92,7 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
99
92
|
}
|
|
100
93
|
}
|
|
101
94
|
const customTools = parseCustomTools(sandbox.customTools, { home });
|
|
102
|
-
const tools = resolveSandboxToolIds(sandbox,
|
|
95
|
+
const tools = resolveSandboxToolIds(sandbox, defaults.tools);
|
|
103
96
|
return {
|
|
104
97
|
repoRoot,
|
|
105
98
|
configPath,
|
|
@@ -119,7 +112,10 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
119
112
|
tools,
|
|
120
113
|
customTools,
|
|
121
114
|
agentClientState: agentClients.state,
|
|
122
|
-
|
|
115
|
+
delivery: {
|
|
116
|
+
remote: typeof delivery.remote === 'string' ? delivery.remote : 'origin',
|
|
117
|
+
baseRef: typeof delivery.baseRef === 'string' ? delivery.baseRef : 'main'
|
|
118
|
+
},
|
|
123
119
|
refreshIntervalDays: asNonNegativeIntegerOrDefault(sandbox.refreshIntervalDays, defaults.refreshIntervalDays),
|
|
124
120
|
dockerfile,
|
|
125
121
|
vm: {
|
|
@@ -1,15 +1,32 @@
|
|
|
1
|
-
import { spawn
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import { getProcessStartTime } from '../../server/process-state.js';
|
|
6
6
|
import { createTask } from '../../task/create-service.js';
|
|
7
7
|
import { applyTaskFinalization } from '../../task/finalization.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { bindSandboxControlTask, validateSandboxControlRequest } from './protocol.js';
|
|
9
|
+
import { atomicWriteJson, executionPath, readActiveLease, terminateSandboxControlExecution } from './state.js';
|
|
10
|
+
import { createSandboxExecutorExecutionContext, dispatchTaskControlOperation, parseTaskControlOperation } from '../../task/control-authority.js';
|
|
11
|
+
import { assertSandboxControlBrokerOwner, readSandboxControlManifest } from './lifecycle.js';
|
|
11
12
|
import { computeLifecycleBuildIdentity } from '../../agent-clients/adapters/codex-lifecycle/build-identity.js';
|
|
12
13
|
import { closeCodexControllerRegistration, CodexControllerRegistrationError, openCodexControllerRegistration, resolveCodexControllerBinding } from './controller-registration.js';
|
|
14
|
+
function sameBrokerOwner(left, right) {
|
|
15
|
+
return left.version === right.version
|
|
16
|
+
&& left.pid === right.pid
|
|
17
|
+
&& left.startTime === right.startTime
|
|
18
|
+
&& left.brokerId === right.brokerId
|
|
19
|
+
&& left.token === right.token
|
|
20
|
+
&& left.generation === right.generation;
|
|
21
|
+
}
|
|
22
|
+
export function assertSandboxControlExecutorAuthority(manifest, gateOwner) {
|
|
23
|
+
const owner = assertSandboxControlBrokerOwner(manifest);
|
|
24
|
+
if (gateOwner && !sameBrokerOwner(owner, gateOwner)) {
|
|
25
|
+
throw new Error('SANDBOX_CONTROL_GATE_OWNER_MISMATCH');
|
|
26
|
+
}
|
|
27
|
+
if (readActiveLease(manifest))
|
|
28
|
+
throw new Error('SANDBOX_CONTROL_HANDOFF_ACTIVE');
|
|
29
|
+
}
|
|
13
30
|
function safeEnv(env) {
|
|
14
31
|
return Object.fromEntries(Object.entries(env).filter(([key]) => !key.toUpperCase().startsWith('AGENT_INFRA_CONTROL_')));
|
|
15
32
|
}
|
|
@@ -74,12 +91,15 @@ export async function prepareSandboxControlExecution(params) {
|
|
|
74
91
|
start(canWrite = () => true) {
|
|
75
92
|
if (!child.connected)
|
|
76
93
|
throw new Error('SANDBOX_CONTROL_EXECUTOR_GATE_CLOSED');
|
|
94
|
+
if (!canWrite())
|
|
95
|
+
throw new Error('SANDBOX_CONTROL_OWNER_LOST');
|
|
96
|
+
const gateOwner = assertSandboxControlBrokerOwner(params.manifest);
|
|
77
97
|
if (!canWrite())
|
|
78
98
|
throw new Error('SANDBOX_CONTROL_OWNER_LOST');
|
|
79
99
|
atomicWriteJson(executionPath(params.manifest, params.request.id), { ...execution, phase: 'running', updatedAt: Date.now() });
|
|
80
100
|
if (!canWrite())
|
|
81
101
|
throw new Error('SANDBOX_CONTROL_OWNER_LOST');
|
|
82
|
-
child.send({ version: 1, nonce });
|
|
102
|
+
child.send({ version: 1, nonce, owner: gateOwner });
|
|
83
103
|
},
|
|
84
104
|
completion,
|
|
85
105
|
terminate(updateState = true) {
|
|
@@ -104,11 +124,16 @@ function waitForGate(nonce, timeoutMs = 2_000) {
|
|
|
104
124
|
clearTimeout(timer);
|
|
105
125
|
process.off('disconnect', onDisconnect);
|
|
106
126
|
const value = message;
|
|
107
|
-
|
|
127
|
+
const owner = value?.owner;
|
|
128
|
+
if (!value || value.version !== 1 || value.nonce !== nonce
|
|
129
|
+
|| !owner || owner.version !== 3 || !Number.isSafeInteger(owner.pid) || (owner.pid ?? 0) <= 0
|
|
130
|
+
|| typeof owner.startTime !== 'number' || !Number.isSafeInteger(owner.startTime)
|
|
131
|
+
|| typeof owner.brokerId !== 'string' || owner.brokerId.length === 0
|
|
132
|
+
|| typeof owner.token !== 'string' || typeof owner.generation !== 'string') {
|
|
108
133
|
reject(new Error('SANDBOX_CONTROL_EXECUTOR_GATE_INVALID'));
|
|
109
134
|
return;
|
|
110
135
|
}
|
|
111
|
-
resolve();
|
|
136
|
+
resolve(owner);
|
|
112
137
|
});
|
|
113
138
|
});
|
|
114
139
|
}
|
|
@@ -139,6 +164,16 @@ function orchestrationFailure(code, message) {
|
|
|
139
164
|
stderr: ''
|
|
140
165
|
};
|
|
141
166
|
}
|
|
167
|
+
function lifecycleFailure(code, message) {
|
|
168
|
+
return {
|
|
169
|
+
exitCode: 1,
|
|
170
|
+
stdout: `${JSON.stringify({
|
|
171
|
+
status: 'failed', changed: false,
|
|
172
|
+
error: { code, message }
|
|
173
|
+
})}\n`,
|
|
174
|
+
stderr: ''
|
|
175
|
+
};
|
|
176
|
+
}
|
|
142
177
|
function finalizationResult(result) {
|
|
143
178
|
const payload = {
|
|
144
179
|
version: 1,
|
|
@@ -154,19 +189,7 @@ function finalizationResult(result) {
|
|
|
154
189
|
stderr: ''
|
|
155
190
|
};
|
|
156
191
|
}
|
|
157
|
-
function
|
|
158
|
-
if (args[1] !== 'prepare')
|
|
159
|
-
return false;
|
|
160
|
-
const values = [];
|
|
161
|
-
for (let index = 2; index < args.length; index += 1) {
|
|
162
|
-
if (args[index] === '--client')
|
|
163
|
-
values.push(args[index + 1] ?? '');
|
|
164
|
-
else if (args[index]?.startsWith('--client='))
|
|
165
|
-
values.push(args[index].slice('--client='.length));
|
|
166
|
-
}
|
|
167
|
-
return values.length === 1 && values[0] === 'codex';
|
|
168
|
-
}
|
|
169
|
-
export function executeRequest(manifest, manifestPath, request, options = {}) {
|
|
192
|
+
export async function executeRequest(manifest, manifestPath, request, options = {}) {
|
|
170
193
|
if (request.family === 'task-create') {
|
|
171
194
|
const result = createTask(request.candidate, { repoRoot: manifest.repoRoot });
|
|
172
195
|
return {
|
|
@@ -220,12 +243,41 @@ export function executeRequest(manifest, manifestPath, request, options = {}) {
|
|
|
220
243
|
}
|
|
221
244
|
}
|
|
222
245
|
if (request.family === 'task-finalization') {
|
|
223
|
-
|
|
246
|
+
const operation = parseTaskControlOperation('task-finalization', [manifest.taskId, 'complete', '--agent', request.agent]);
|
|
247
|
+
if (operation.family !== 'task-finalization')
|
|
248
|
+
throw new Error('SANDBOX_CONTROL_FINALIZATION_OPERATION_INVALID');
|
|
249
|
+
const result = dispatchTaskControlOperation(createSandboxExecutorExecutionContext({
|
|
250
|
+
repoRoot: manifest.repoRoot,
|
|
251
|
+
worktreeRoot: manifest.worktreeRoot,
|
|
252
|
+
runtimeDir: manifest.runtimeDir,
|
|
253
|
+
taskId: manifest.taskId,
|
|
254
|
+
generation: manifest.generation,
|
|
255
|
+
manifestPath,
|
|
256
|
+
requestId: request.id
|
|
257
|
+
}), operation);
|
|
258
|
+
return finalizationResult(result);
|
|
224
259
|
}
|
|
225
260
|
const boundArgs = bindSandboxControlTask(request, manifest.taskId);
|
|
261
|
+
if (request.family === 'task-orchestration') {
|
|
262
|
+
boundArgs.push('--git-worktree-root', manifest.worktreeRoot);
|
|
263
|
+
}
|
|
264
|
+
let operation;
|
|
265
|
+
try {
|
|
266
|
+
operation = parseTaskControlOperation(request.family, boundArgs);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
270
|
+
const code = /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_CONTROL_OPERATION_INVALID';
|
|
271
|
+
return request.family === 'task-lifecycle'
|
|
272
|
+
? lifecycleFailure('LIFECYCLE_PAYLOAD_INVALID', message)
|
|
273
|
+
: orchestrationFailure(code, message);
|
|
274
|
+
}
|
|
226
275
|
let controllerBinding = null;
|
|
227
276
|
if (request.family === 'task-orchestration') {
|
|
228
|
-
|
|
277
|
+
const codexPrepare = operation.family === 'task-orchestration'
|
|
278
|
+
&& operation.intent === 'prepare'
|
|
279
|
+
&& operation.input.client === 'codex';
|
|
280
|
+
if (codexPrepare) {
|
|
229
281
|
if (!request.controllerProof) {
|
|
230
282
|
return orchestrationFailure('CODEX_SANDBOX_CONTROLLER_PROOF_REQUIRED', 'Codex prepare requires a current controller lease proof');
|
|
231
283
|
}
|
|
@@ -247,33 +299,73 @@ export function executeRequest(manifest, manifestPath, request, options = {}) {
|
|
|
247
299
|
else if (request.controllerProof !== null) {
|
|
248
300
|
return orchestrationFailure('CODEX_SANDBOX_CONTROLLER_PROOF_INVALID', 'Controller proof is only accepted for canonical Codex prepare');
|
|
249
301
|
}
|
|
250
|
-
boundArgs.push('--git-worktree-root', manifest.worktreeRoot);
|
|
251
302
|
}
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
303
|
+
const context = createSandboxExecutorExecutionContext({
|
|
304
|
+
repoRoot: manifest.repoRoot,
|
|
305
|
+
worktreeRoot: manifest.worktreeRoot,
|
|
306
|
+
runtimeDir: manifest.runtimeDir,
|
|
307
|
+
taskId: manifest.taskId,
|
|
308
|
+
generation: manifest.generation,
|
|
309
|
+
manifestPath,
|
|
310
|
+
requestId: request.id,
|
|
311
|
+
...(controllerBinding ? { controllerBinding } : {})
|
|
262
312
|
});
|
|
263
|
-
|
|
313
|
+
const format = (value) => {
|
|
314
|
+
const result = value;
|
|
315
|
+
return {
|
|
316
|
+
exitCode: result.status === 'failed' ? 1 : 0,
|
|
317
|
+
stdout: `${JSON.stringify(value)}\n`,
|
|
318
|
+
stderr: ''
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
if (request.family === 'task-orchestration') {
|
|
322
|
+
if (operation.family !== 'task-orchestration')
|
|
323
|
+
throw new Error('SANDBOX_CONTROL_ORCHESTRATION_OPERATION_INVALID');
|
|
324
|
+
return format(await dispatchTaskControlOperation(context, operation));
|
|
325
|
+
}
|
|
326
|
+
if (operation.family !== 'task-lifecycle')
|
|
327
|
+
throw new Error('SANDBOX_CONTROL_LIFECYCLE_OPERATION_INVALID');
|
|
328
|
+
return format(dispatchTaskControlOperation(context, operation));
|
|
264
329
|
}
|
|
265
330
|
export async function runSandboxControlExecutor(requestPath, nonce) {
|
|
266
|
-
await waitForGate(nonce);
|
|
331
|
+
const gateOwner = await waitForGate(nonce);
|
|
267
332
|
process.disconnect?.();
|
|
268
|
-
const root = fs.realpathSync.native(process.cwd());
|
|
269
|
-
const request = JSON.parse(fs.readFileSync(requestPath, 'utf8'));
|
|
270
333
|
const manifestPath = process.env.AGENT_INFRA_EXECUTOR_MANIFEST;
|
|
271
334
|
if (!manifestPath)
|
|
272
335
|
throw new Error('SANDBOX_CONTROL_EXECUTOR_MANIFEST_MISSING');
|
|
273
|
-
const manifest =
|
|
336
|
+
const manifest = readSandboxControlManifest(manifestPath);
|
|
337
|
+
const root = fs.realpathSync.native(process.cwd());
|
|
274
338
|
if (fs.realpathSync.native(manifest.repoRoot) !== root)
|
|
275
339
|
throw new Error('SANDBOX_CONTROL_EXECUTOR_ROOT_INVALID');
|
|
276
|
-
const
|
|
340
|
+
const raw = JSON.parse(fs.readFileSync(requestPath, 'utf8'));
|
|
341
|
+
const request = validateSandboxControlRequest(raw, manifest);
|
|
342
|
+
const requestDirectory = path.resolve(path.dirname(requestPath));
|
|
343
|
+
const processingDirectory = path.resolve(path.join(manifest.processingDir, request.id));
|
|
344
|
+
const channelRequestDirectory = path.resolve(path.join(manifest.channelDir, 'requests'));
|
|
345
|
+
if (requestDirectory !== processingDirectory && requestDirectory !== channelRequestDirectory) {
|
|
346
|
+
throw new Error('SANDBOX_CONTROL_EXECUTOR_REQUEST_INVALID');
|
|
347
|
+
}
|
|
348
|
+
let result;
|
|
349
|
+
try {
|
|
350
|
+
assertSandboxControlExecutorAuthority(manifest, gateOwner);
|
|
351
|
+
result = await executeRequest(manifest, manifestPath, request);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
355
|
+
const code = /^([A-Z][A-Z0-9_]+)/u.exec(detail)?.[1] ?? 'SANDBOX_CONTROL_EXECUTOR_FAILED';
|
|
356
|
+
result = request.family === 'task-finalization'
|
|
357
|
+
? {
|
|
358
|
+
exitCode: 1,
|
|
359
|
+
stdout: `${JSON.stringify({
|
|
360
|
+
version: 1, status: 'failed', changed: false, accepted: true, result: null,
|
|
361
|
+
error: { code, message: detail, retryable: false }
|
|
362
|
+
})}\n`,
|
|
363
|
+
stderr: ''
|
|
364
|
+
}
|
|
365
|
+
: request.family === 'task-lifecycle'
|
|
366
|
+
? lifecycleFailure(code, detail)
|
|
367
|
+
: orchestrationFailure(code, detail);
|
|
368
|
+
}
|
|
277
369
|
process.stdout.write(result.stdout);
|
|
278
370
|
process.stderr.write(result.stderr);
|
|
279
371
|
process.exitCode = result.exitCode;
|