@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
package/lib/merge.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { info, ok } from './log.ts';
|
|
4
3
|
import { removeDirRecursive } from './remove-dir.ts';
|
|
4
|
+
import { validateCurrentTaskContract } from './task/current-contract.ts';
|
|
5
5
|
|
|
6
6
|
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
7
7
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
|
|
8
8
|
const TITLE_RE = /^# (.+)$/m;
|
|
9
|
-
const DATE_FROM_PATH_RE = /(?:^|[/\\])(\d{4})[/\\](\d{2})[/\\](\d{2})(?:[/\\]|$)/;
|
|
10
9
|
const MUTABLE_SECTIONS = ['active', 'blocked', 'completed'] as const;
|
|
11
10
|
const ALL_SECTIONS = [...MUTABLE_SECTIONS, 'archive'] as const;
|
|
12
11
|
type MutableSection = typeof MUTABLE_SECTIONS[number];
|
|
13
12
|
type Section = typeof ALL_SECTIONS[number];
|
|
14
13
|
type MutableAction = 'copied' | 'updated' | 'moved' | 'skipped';
|
|
15
14
|
type ArchiveAction = 'copied' | 'skipped';
|
|
16
|
-
type SourceMode = 'workspace'
|
|
15
|
+
type SourceMode = 'workspace';
|
|
17
16
|
type DateParts = {
|
|
18
17
|
year: string;
|
|
19
18
|
month: string;
|
|
@@ -129,40 +128,6 @@ function normalizeTaskRecord(taskDir: string, taskFile: string, dateParts: DateP
|
|
|
129
128
|
};
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
function fallbackDateParts(taskDir: string, content: string): DateParts | null {
|
|
133
|
-
const pathMatch = taskDir.match(DATE_FROM_PATH_RE);
|
|
134
|
-
if (pathMatch) {
|
|
135
|
-
const [, year, month, day] = pathMatch;
|
|
136
|
-
if (!year || !month || !day) {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
year,
|
|
141
|
-
month,
|
|
142
|
-
day
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const completedAt = extractField(content, 'completed_at');
|
|
147
|
-
const updatedAt = extractField(content, 'updated_at');
|
|
148
|
-
const source = completedAt || updatedAt;
|
|
149
|
-
const dateMatch = source?.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
150
|
-
|
|
151
|
-
if (dateMatch) {
|
|
152
|
-
const [, year, month, day] = dateMatch;
|
|
153
|
-
if (!year || !month || !day) {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
year,
|
|
158
|
-
month,
|
|
159
|
-
day
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
131
|
function scanSourceTasks(sourceDir: string): TaskRecord[] {
|
|
167
132
|
const tasks: TaskRecord[] = [];
|
|
168
133
|
const years = fs.existsSync(sourceDir) ? fs.readdirSync(sourceDir, { withFileTypes: true }) : [];
|
|
@@ -206,44 +171,6 @@ function scanSourceTasks(sourceDir: string): TaskRecord[] {
|
|
|
206
171
|
}
|
|
207
172
|
}
|
|
208
173
|
|
|
209
|
-
if (tasks.length > 0) {
|
|
210
|
-
return tasks;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Fall back to a deeper scan if the source layout is unusual but still contains archived tasks.
|
|
214
|
-
const stack = [sourceDir];
|
|
215
|
-
while (stack.length > 0) {
|
|
216
|
-
const currentDir = stack.pop();
|
|
217
|
-
if (!currentDir || !fs.existsSync(currentDir)) {
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
for (const entry of fs.readdirSync(currentDir, { withFileTypes: true })) {
|
|
222
|
-
const entryPath = path.join(currentDir, entry.name);
|
|
223
|
-
if (!entry.isDirectory()) {
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (TASK_ID_RE.test(entry.name)) {
|
|
228
|
-
const taskFile = path.join(entryPath, 'task.md');
|
|
229
|
-
if (!fs.existsSync(taskFile)) {
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const content = fs.readFileSync(taskFile, 'utf8');
|
|
234
|
-
const dateParts = fallbackDateParts(entryPath, content);
|
|
235
|
-
if (!dateParts) {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
tasks.push(normalizeTaskRecord(entryPath, taskFile, dateParts));
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
stack.push(entryPath);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
174
|
return tasks.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
248
175
|
}
|
|
249
176
|
|
|
@@ -624,15 +551,230 @@ function copyTaskToSection(sourceTask: WorkspaceRecord, workspaceDir: string): s
|
|
|
624
551
|
return destinationDir;
|
|
625
552
|
}
|
|
626
553
|
|
|
554
|
+
function invalidSource(message: string): never {
|
|
555
|
+
throw new Error(`Invalid merge source: ${message}`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function sourceRelativePath(sourceRoot: string, targetPath: string): string {
|
|
559
|
+
return path.relative(sourceRoot, targetPath).split(path.sep).join('/') || '.';
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function isMissingPathError(error: unknown): boolean {
|
|
563
|
+
return Boolean(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT');
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function assertSourcePathContained(sourceRoot: string, targetPath: string): void {
|
|
567
|
+
let sourceRealPath: string;
|
|
568
|
+
let targetRealPath: string;
|
|
569
|
+
try {
|
|
570
|
+
sourceRealPath = fs.realpathSync(sourceRoot);
|
|
571
|
+
targetRealPath = fs.realpathSync(targetPath);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
invalidSource(`${sourceRelativePath(sourceRoot, targetPath)} cannot be resolved: ${error instanceof Error ? error.message : String(error)}`);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const relativePath = path.relative(sourceRealPath, targetRealPath);
|
|
577
|
+
if (relativePath === '..' || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath)) {
|
|
578
|
+
invalidSource(`${sourceRelativePath(sourceRoot, targetPath)} resolves outside the source workspace`);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function sourcePathStat(sourceRoot: string, targetPath: string): fs.Stats | null {
|
|
583
|
+
let stat: fs.Stats;
|
|
584
|
+
try {
|
|
585
|
+
stat = fs.lstatSync(targetPath);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (isMissingPathError(error)) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
throw error;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (stat.isSymbolicLink()) {
|
|
594
|
+
invalidSource(`${sourceRelativePath(sourceRoot, targetPath)} must not be a symbolic link`);
|
|
595
|
+
}
|
|
596
|
+
assertSourcePathContained(sourceRoot, targetPath);
|
|
597
|
+
return stat;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function validateTaskTree(sourceRoot: string, taskDir: string): void {
|
|
601
|
+
for (const entry of fs.readdirSync(taskDir, { withFileTypes: true })) {
|
|
602
|
+
const entryPath = path.join(taskDir, entry.name);
|
|
603
|
+
const entryStat = sourcePathStat(sourceRoot, entryPath);
|
|
604
|
+
if (!entryStat) {
|
|
605
|
+
invalidSource(`${sourceRelativePath(sourceRoot, entryPath)} disappeared during validation`);
|
|
606
|
+
}
|
|
607
|
+
if (entryStat.isDirectory()) {
|
|
608
|
+
validateTaskTree(sourceRoot, entryPath);
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
if (!entryStat.isFile()) {
|
|
612
|
+
invalidSource(`${sourceRelativePath(sourceRoot, entryPath)} must be a regular file or directory`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function validateSourceRoot(sourceRoot: string): void {
|
|
618
|
+
const stat = sourcePathStat(sourceRoot, sourceRoot);
|
|
619
|
+
if (!stat || !stat.isDirectory()) {
|
|
620
|
+
invalidSource('source path must be a real directory');
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function validateTaskDirectory(
|
|
625
|
+
sourceRoot: string,
|
|
626
|
+
taskDir: string,
|
|
627
|
+
seenTaskIds: Map<string, string>
|
|
628
|
+
): void {
|
|
629
|
+
const taskId = path.basename(taskDir);
|
|
630
|
+
const taskFile = path.join(taskDir, 'task.md');
|
|
631
|
+
const taskDirStat = sourcePathStat(sourceRoot, taskDir);
|
|
632
|
+
if (!taskDirStat || !taskDirStat.isDirectory()) {
|
|
633
|
+
invalidSource(`${sourceRelativePath(sourceRoot, taskDir)} must be a directory`);
|
|
634
|
+
}
|
|
635
|
+
const taskFileStat = sourcePathStat(sourceRoot, taskFile);
|
|
636
|
+
if (!taskFileStat || !taskFileStat.isFile()) {
|
|
637
|
+
invalidSource(`${sourceRelativePath(sourceRoot, taskDir)} requires a regular task.md file`);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const content = fs.readFileSync(taskFile, 'utf8');
|
|
641
|
+
const contract = validateCurrentTaskContract(content);
|
|
642
|
+
if (!contract.ok) {
|
|
643
|
+
invalidSource(`${sourceRelativePath(sourceRoot, taskFile)} is not a valid current task: ${contract.message}`);
|
|
644
|
+
}
|
|
645
|
+
if (contract.metadata.id !== taskId) {
|
|
646
|
+
invalidSource(`${sourceRelativePath(sourceRoot, taskFile)} id '${String(contract.metadata.id ?? 'missing')}' does not match directory '${taskId}'`);
|
|
647
|
+
}
|
|
648
|
+
validateTaskTree(sourceRoot, taskDir);
|
|
649
|
+
|
|
650
|
+
const previousPath = seenTaskIds.get(taskId);
|
|
651
|
+
if (previousPath) {
|
|
652
|
+
invalidSource(`duplicate task ID ${taskId} at ${previousPath} and ${sourceRelativePath(sourceRoot, taskDir)}`);
|
|
653
|
+
}
|
|
654
|
+
seenTaskIds.set(taskId, sourceRelativePath(sourceRoot, taskDir));
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function validateMutableSection(
|
|
658
|
+
sourceRoot: string,
|
|
659
|
+
section: MutableSection,
|
|
660
|
+
seenTaskIds: Map<string, string>
|
|
661
|
+
): void {
|
|
662
|
+
const sectionDir = path.join(sourceRoot, section);
|
|
663
|
+
const sectionStat = sourcePathStat(sourceRoot, sectionDir);
|
|
664
|
+
if (!sectionStat) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (!sectionStat.isDirectory()) {
|
|
668
|
+
invalidSource(`${section} must be a directory`);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
for (const entry of fs.readdirSync(sectionDir, { withFileTypes: true })) {
|
|
672
|
+
const entryPath = path.join(sectionDir, entry.name);
|
|
673
|
+
const entryStat = sourcePathStat(sourceRoot, entryPath);
|
|
674
|
+
if (!entryStat) {
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
if (!entryStat.isDirectory()) {
|
|
678
|
+
if (TASK_ID_RE.test(entry.name)) {
|
|
679
|
+
invalidSource(`${sourceRelativePath(sourceRoot, entryPath)} is not a directory`);
|
|
680
|
+
}
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (!TASK_ID_RE.test(entry.name)) {
|
|
684
|
+
invalidSource(`${sourceRelativePath(sourceRoot, entryPath)} is not a direct TASK-YYYYMMDD-HHMMSS directory`);
|
|
685
|
+
}
|
|
686
|
+
validateTaskDirectory(sourceRoot, entryPath, seenTaskIds);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function validateArchiveSection(
|
|
691
|
+
sourceRoot: string,
|
|
692
|
+
seenTaskIds: Map<string, string>
|
|
693
|
+
): void {
|
|
694
|
+
const archiveDir = path.join(sourceRoot, 'archive');
|
|
695
|
+
const archiveStat = sourcePathStat(sourceRoot, archiveDir);
|
|
696
|
+
if (!archiveStat) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (!archiveStat.isDirectory()) {
|
|
700
|
+
invalidSource('archive must be a directory');
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const allowManifest = (directory: string, entry: fs.Dirent): boolean => {
|
|
704
|
+
const entryPath = path.join(directory, entry.name);
|
|
705
|
+
const entryStat = sourcePathStat(sourceRoot, entryPath);
|
|
706
|
+
return Boolean(entryStat?.isFile() && entry.name === 'manifest.md');
|
|
707
|
+
};
|
|
708
|
+
const years = fs.readdirSync(archiveDir, { withFileTypes: true });
|
|
709
|
+
for (const yearEntry of years) {
|
|
710
|
+
const yearPath = path.join(archiveDir, yearEntry.name);
|
|
711
|
+
if (allowManifest(archiveDir, yearEntry)) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
const yearStat = sourcePathStat(sourceRoot, yearPath);
|
|
715
|
+
if (!yearStat?.isDirectory() || !/^\d{4}$/.test(yearEntry.name)) {
|
|
716
|
+
invalidSource(`${sourceRelativePath(sourceRoot, yearPath)} is not a YYYY directory or manifest.md`);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const yearDir = yearPath;
|
|
720
|
+
for (const monthEntry of fs.readdirSync(yearDir, { withFileTypes: true })) {
|
|
721
|
+
const monthPath = path.join(yearDir, monthEntry.name);
|
|
722
|
+
if (allowManifest(yearDir, monthEntry)) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
const monthStat = sourcePathStat(sourceRoot, monthPath);
|
|
726
|
+
if (!monthStat?.isDirectory() || !/^\d{2}$/.test(monthEntry.name)) {
|
|
727
|
+
invalidSource(`${sourceRelativePath(sourceRoot, monthPath)} is not a MM directory or manifest.md`);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const monthDir = monthPath;
|
|
731
|
+
for (const dayEntry of fs.readdirSync(monthDir, { withFileTypes: true })) {
|
|
732
|
+
const dayPath = path.join(monthDir, dayEntry.name);
|
|
733
|
+
if (allowManifest(monthDir, dayEntry)) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
const dayStat = sourcePathStat(sourceRoot, dayPath);
|
|
737
|
+
if (!dayStat?.isDirectory() || !/^\d{2}$/.test(dayEntry.name)) {
|
|
738
|
+
invalidSource(`${sourceRelativePath(sourceRoot, dayPath)} is not a DD directory or manifest.md`);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const dayDir = dayPath;
|
|
742
|
+
for (const taskEntry of fs.readdirSync(dayDir, { withFileTypes: true })) {
|
|
743
|
+
const taskPath = path.join(dayDir, taskEntry.name);
|
|
744
|
+
const taskStat = sourcePathStat(sourceRoot, taskPath);
|
|
745
|
+
if (!taskStat?.isDirectory() || !TASK_ID_RE.test(taskEntry.name)) {
|
|
746
|
+
invalidSource(`${sourceRelativePath(sourceRoot, taskPath)} is not a TASK-YYYYMMDD-HHMMSS directory`);
|
|
747
|
+
}
|
|
748
|
+
validateTaskDirectory(sourceRoot, taskPath, seenTaskIds);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function validateSourceWorkspace(sourcePath: string): void {
|
|
756
|
+
validateSourceRoot(sourcePath);
|
|
757
|
+
const seenTaskIds = new Map<string, string>();
|
|
758
|
+
for (const section of MUTABLE_SECTIONS) {
|
|
759
|
+
validateMutableSection(sourcePath, section, seenTaskIds);
|
|
760
|
+
}
|
|
761
|
+
validateArchiveSection(sourcePath, seenTaskIds);
|
|
762
|
+
}
|
|
763
|
+
|
|
627
764
|
function detectSourceMode(sourcePath: string): SourceMode {
|
|
765
|
+
validateSourceRoot(sourcePath);
|
|
628
766
|
for (const section of ALL_SECTIONS) {
|
|
629
767
|
const sectionDir = path.join(sourcePath, section);
|
|
630
|
-
|
|
768
|
+
const sectionStat = sourcePathStat(sourcePath, sectionDir);
|
|
769
|
+
if (sectionStat?.isDirectory()) {
|
|
631
770
|
return 'workspace';
|
|
632
771
|
}
|
|
772
|
+
if (sectionStat) {
|
|
773
|
+
invalidSource(`${section} must be a directory`);
|
|
774
|
+
}
|
|
633
775
|
}
|
|
634
776
|
|
|
635
|
-
|
|
777
|
+
invalidSource('expected a current workspace containing active, blocked, completed, or archive sections');
|
|
636
778
|
}
|
|
637
779
|
|
|
638
780
|
function createReport(sourcePath: string, backupRoot: string): MergeReport {
|
|
@@ -778,29 +920,6 @@ function mergeArchiveSection(sourceArchive: string, localArchive: string, report
|
|
|
778
920
|
return sourceTasks.length;
|
|
779
921
|
}
|
|
780
922
|
|
|
781
|
-
function printLegacyArchiveMessages(report: MergeReport, sourcePath: string): void {
|
|
782
|
-
const merged = report.sections.archive.copied;
|
|
783
|
-
const skipped = report.sections.archive.skipped;
|
|
784
|
-
|
|
785
|
-
if (merged.length === 0 && skipped.length === 0) {
|
|
786
|
-
info(`No archived tasks found in ${sourcePath}`);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
for (const task of merged) {
|
|
790
|
-
ok(`Merged ${task.taskId} -> ${task.relativePath}`);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
for (const task of skipped) {
|
|
794
|
-
info(`Skipped ${task.taskId} (already exists at ${task.relativePath})`);
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
process.stdout.write('\n');
|
|
798
|
-
info('Merge summary');
|
|
799
|
-
info(`- Merged: ${merged.length}`);
|
|
800
|
-
info(`- Skipped: ${skipped.length}`);
|
|
801
|
-
process.stdout.write('\n');
|
|
802
|
-
}
|
|
803
|
-
|
|
804
923
|
function printSection(lines: string[], name: MutableSection, counts: MutableCounts): void {
|
|
805
924
|
const title = `${SECTION_LABELS[name].padEnd(9, ' ')} (.agents/workspace/${name}/):`;
|
|
806
925
|
lines.push(title);
|
|
@@ -910,7 +1029,11 @@ async function cmdMerge(args: string[]): Promise<void> {
|
|
|
910
1029
|
throw new Error(`Source path does not exist: ${sourcePath}`);
|
|
911
1030
|
}
|
|
912
1031
|
|
|
913
|
-
if (
|
|
1032
|
+
if (fs.lstatSync(resolvedSource).isSymbolicLink()) {
|
|
1033
|
+
throw new Error(`Invalid merge source: source path must be a real directory: ${sourcePath}`);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (!fs.lstatSync(resolvedSource).isDirectory()) {
|
|
914
1037
|
throw new Error(`Source path is not a directory: ${sourcePath}`);
|
|
915
1038
|
}
|
|
916
1039
|
|
|
@@ -920,35 +1043,28 @@ async function cmdMerge(args: string[]): Promise<void> {
|
|
|
920
1043
|
const backupRootRelative = `.agents/workspace/.merge-backup/${backupStamp}/`;
|
|
921
1044
|
const backupRoot = path.join(workspaceDir, '.merge-backup', backupStamp);
|
|
922
1045
|
const report = createReport(resolvedSource, backupRootRelative);
|
|
923
|
-
|
|
1046
|
+
detectSourceMode(resolvedSource);
|
|
1047
|
+
validateSourceWorkspace(resolvedSource);
|
|
924
1048
|
|
|
925
1049
|
for (const section of ALL_SECTIONS) {
|
|
926
1050
|
fs.mkdirSync(path.join(workspaceDir, section), { recursive: true });
|
|
927
1051
|
}
|
|
928
1052
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
localWorkspace: workspaceDir,
|
|
936
|
-
backupRoot,
|
|
937
|
-
report
|
|
938
|
-
});
|
|
1053
|
+
mergeMutableSections({
|
|
1054
|
+
sourceWorkspace: resolvedSource,
|
|
1055
|
+
localWorkspace: workspaceDir,
|
|
1056
|
+
backupRoot,
|
|
1057
|
+
report
|
|
1058
|
+
});
|
|
939
1059
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1060
|
+
const sourceArchive = path.join(resolvedSource, 'archive');
|
|
1061
|
+
const sourceArchiveStat = sourcePathStat(resolvedSource, sourceArchive);
|
|
1062
|
+
if (sourceArchiveStat?.isDirectory()) {
|
|
1063
|
+
mergeArchiveSection(sourceArchive, archiveDir, report);
|
|
944
1064
|
}
|
|
945
1065
|
|
|
946
1066
|
rebuildManifests(archiveDir);
|
|
947
1067
|
|
|
948
|
-
if (mode === 'legacy-archive') {
|
|
949
|
-
printLegacyArchiveMessages(report, sourcePath);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
1068
|
printReport(report);
|
|
953
1069
|
}
|
|
954
1070
|
|
|
@@ -37,8 +37,15 @@ const MINIMUM_GITHUB_CLI_VERSION = '2.72.0';
|
|
|
37
37
|
const GITHUB_CLI_MAX_BUFFER = 64 * 1024 * 1024;
|
|
38
38
|
const ERROR_DETAIL_LIMIT = 4096;
|
|
39
39
|
|
|
40
|
+
function redactDiagnostic(value: string): string {
|
|
41
|
+
return value
|
|
42
|
+
.replace(/\b(?:gh[pousr]_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+)\b/g, '[REDACTED_TOKEN]')
|
|
43
|
+
.replace(/\b(bearer|token)\s+[A-Za-z0-9._~+\/-]+/gi, '$1 [REDACTED_TOKEN]')
|
|
44
|
+
.replace(/([?&](?:access_token|token|client_secret|password)=)[^&\s]+/gi, '$1[REDACTED]');
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
function boundedFailureDetail(result: RunResult): string {
|
|
41
|
-
const diagnostic = `${result.stderr}\n${result.error?.message || ''}
|
|
48
|
+
const diagnostic = redactDiagnostic(`${result.stderr}\n${result.error?.message || ''}`).trim() || redactDiagnostic(result.stdout.trim());
|
|
42
49
|
return diagnostic.length <= ERROR_DETAIL_LIMIT
|
|
43
50
|
? diagnostic
|
|
44
51
|
: `${diagnostic.slice(0, ERROR_DETAIL_LIMIT)}… [truncated]`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
|
|
4
4
|
import { resolveTaskRef } from '../task/resolve-ref.ts';
|
|
5
5
|
import {
|
|
6
6
|
inspectPlatformRequiredChecks,
|
|
@@ -14,6 +14,7 @@ import { inspectPlatformPullRequest } from './pull-requests.ts';
|
|
|
14
14
|
import { platformResult } from './types.ts';
|
|
15
15
|
import type { PlatformResult } from './types.ts';
|
|
16
16
|
import type { PullRequestSnapshot } from './pull-requests.ts';
|
|
17
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.ts';
|
|
17
18
|
|
|
18
19
|
type CheckBucket = 'pass' | 'fail' | 'pending' | 'cancel';
|
|
19
20
|
type CheckState = 'passed' | 'failed' | 'pending' | 'timed-out' | 'cancelled' | 'no-required';
|
|
@@ -121,10 +122,11 @@ registerPlatformCapabilities('github', {
|
|
|
121
122
|
function resolvedTask(taskRef: string, options: InspectionOptions) {
|
|
122
123
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
123
124
|
if (!resolved.ok) return { ok: false as const, output: checksResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }) };
|
|
124
|
-
const frontmatter =
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
126
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
127
|
+
if (fact.status === 'invalid') return { ok: false as const, output: checksResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }) };
|
|
128
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
129
|
+
if (!prNumber) return { ok: false as const, output: checksResult('failed', { error: { code: fact.status === 'missing' ? 'PR_DELIVERY_FACT_MISSING' : 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false } }) };
|
|
128
130
|
const client = (options.client as GitHubClient | undefined) || createGitHubClient();
|
|
129
131
|
const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
|
|
130
132
|
if (!context.platform.repository || !['no-op', 'degraded'].includes(context.status)) return { ok: false as const, output: checksResult(context.status, { platform: context.platform, capabilities: context.capabilities, error: context.error }) };
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
3
|
|
|
4
4
|
import { enumerateArtifacts } from '../task/artifacts.ts';
|
|
5
|
-
import {
|
|
5
|
+
import { parseTypedTaskFrontmatter } from '../task/frontmatter.ts';
|
|
6
6
|
import { renderHumanOverrideAudit } from '../task/human-override.ts';
|
|
7
7
|
import { resolveTaskRef } from '../task/resolve-ref.ts';
|
|
8
8
|
import { resolvePlatformContext } from './context.ts';
|
|
@@ -12,6 +12,7 @@ import { listRemoteComments, normalizeCommentContent, writeComment } from './iss
|
|
|
12
12
|
import { platformResult } from './types.ts';
|
|
13
13
|
import type { PlatformResult } from './types.ts';
|
|
14
14
|
import type { OperationWarning } from '../task/operation-outcome.ts';
|
|
15
|
+
import { readPrDeliveryFact } from '../task/pr-delivery-fact.ts';
|
|
15
16
|
|
|
16
17
|
type SummaryComment = { id: number; body: string };
|
|
17
18
|
type SummaryContextResult = PlatformResult & {
|
|
@@ -67,9 +68,9 @@ function canonicalArtifacts(taskDir: string) {
|
|
|
67
68
|
function summaryContext(taskRef: string, options: { cwd?: string; client?: GitHubClient } = {}): SummaryContextResult {
|
|
68
69
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
69
70
|
if (!resolved.ok) return { ...platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }), task: { id: resolved.taskId, prNumber: null }, artifacts: [] };
|
|
70
|
-
const frontmatter =
|
|
71
|
-
const
|
|
72
|
-
const prNumber =
|
|
71
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
72
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
73
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
73
74
|
return { ...platformResult('no-op'), task: { id: resolved.taskId, prNumber }, artifacts: canonicalArtifacts(resolved.taskDir) };
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -105,9 +106,11 @@ function syncPullRequestSummary(taskRef: string, options: { agent: string; body:
|
|
|
105
106
|
};
|
|
106
107
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
107
108
|
if (!resolved.ok) return softenFailure(platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }));
|
|
108
|
-
const frontmatter =
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
109
|
+
const frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
110
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
111
|
+
if (fact.status === 'invalid') return softenFailure(platformResult('failed', { error: { code: 'PR_DELIVERY_FACT_INVALID', message: fact.error.message, retryable: false } }));
|
|
112
|
+
const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
|
|
113
|
+
if (!prNumber) return softenFailure(platformResult('failed', { error: { code: fact.status === 'missing' ? 'PR_DELIVERY_FACT_MISSING' : 'PR_NOT_LINKED', message: 'Task has no verified bound pull request', retryable: false } }));
|
|
111
114
|
knownPrNumber = prNumber;
|
|
112
115
|
const client = options.client || createGitHubClient();
|
|
113
116
|
const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
|