@fitlab-ai/agent-infra 0.9.11 → 0.9.13
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 +13 -13
- package/README.zh-CN.md +13 -13
- package/dist/bin/internal-cli.js +29 -19
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
- package/dist/lib/agent-clients/next-steps.js +6 -1
- package/dist/lib/decide.js +3 -3
- package/dist/lib/defaults.json +4 -0
- package/dist/lib/git/workflow.js +43 -1
- package/dist/lib/init.js +1 -0
- package/dist/lib/internal/git-workflow.js +8 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +9 -9
- package/dist/lib/internal/platform-context.js +2 -2
- package/dist/lib/internal/platform-issue.js +8 -9
- package/dist/lib/internal/platform-pr-review.js +10 -10
- package/dist/lib/internal/platform-pr.js +68 -23
- package/dist/lib/internal/platform-release-notes.js +3 -3
- package/dist/lib/internal/pr-review-grade.js +11 -9
- package/dist/lib/internal/release-workflow.js +4 -4
- package/dist/lib/internal/sandbox-control.js +30 -4
- package/dist/lib/internal/task-activity.js +3 -3
- package/dist/lib/internal/task-artifact.js +76 -24
- package/dist/lib/internal/task-create.js +2 -2
- package/dist/lib/internal/task-delivery.js +59 -0
- package/dist/lib/internal/task-event.js +6 -3
- package/dist/lib/internal/task-finalization.js +2 -2
- package/dist/lib/internal/task-invalidation.js +60 -0
- package/dist/lib/internal/task-ledger.js +9 -6
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-override.js +4 -4
- package/dist/lib/internal/task-review.js +3 -3
- package/dist/lib/internal/task-verify.js +6 -6
- package/dist/lib/internal/task-warning.js +3 -3
- package/dist/lib/platform/adapters.js +1 -3
- package/dist/lib/platform/change-request-git-evidence.js +27 -7
- package/dist/lib/platform/completion-backfill.js +6 -5
- package/dist/lib/platform/context.js +70 -130
- package/dist/lib/platform/github-client.js +8 -2
- package/dist/lib/platform/github-provider.js +903 -0
- package/dist/lib/platform/in-label-sync.js +143 -0
- package/dist/lib/platform/issue-comments.js +94 -41
- package/dist/lib/platform/issues.js +335 -189
- package/dist/lib/platform/metadata-labels.js +6 -2
- package/dist/lib/platform/none-provider.js +28 -0
- package/dist/lib/platform/pr-change-report.js +551 -0
- package/dist/lib/platform/pr-checks.js +124 -106
- package/dist/lib/platform/pr-review.js +88 -72
- package/dist/lib/platform/pr-summary.js +523 -49
- package/dist/lib/platform/provider-bridge.js +45 -0
- package/dist/lib/platform/provider-contract.d.ts +487 -0
- package/dist/lib/platform/provider-contract.js +95 -0
- package/dist/lib/platform/provider-loader.js +251 -0
- package/dist/lib/platform/provider-validation.js +504 -0
- package/dist/lib/platform/pull-request-metadata.js +8 -6
- package/dist/lib/platform/pull-requests.js +1050 -502
- package/dist/lib/platform/release-notes.js +78 -55
- package/dist/lib/platform/releases.js +79 -50
- package/dist/lib/platform/resource-identity.d.ts +26 -0
- package/dist/lib/platform/resource-identity.js +92 -0
- package/dist/lib/platform/task-identities.js +31 -0
- package/dist/lib/platform/verification-required.js +22 -12
- package/dist/lib/platform/verification-sync.js +118 -239
- package/dist/lib/pr-review/evidence-grading.js +30 -9
- package/dist/lib/run/index.js +63 -23
- package/dist/lib/sandbox/config.js +5 -0
- package/dist/lib/sandbox/control/client.js +96 -15
- package/dist/lib/sandbox/control/executor.js +3 -3
- package/dist/lib/sandbox/control/lifecycle.js +29 -7
- package/dist/lib/sandbox/control/protocol.js +77 -0
- package/dist/lib/sandbox/control/server.js +398 -25
- package/dist/lib/sandbox/control/state.js +204 -1
- package/dist/lib/server/process-state.js +2 -2
- package/dist/lib/server/protocol.js +38 -1
- package/dist/lib/task/activity-log.js +8 -1
- package/dist/lib/task/artifact-lifecycle.js +35 -7
- package/dist/lib/task/capabilities.js +239 -0
- package/dist/lib/task/commands/status.js +32 -0
- package/dist/lib/task/commit-intent.js +100 -0
- package/dist/lib/task/commit-operation.js +207 -102
- package/dist/lib/task/control-authority.js +8 -5
- package/dist/lib/task/create-service.js +8 -8
- package/dist/lib/task/create.js +33 -7
- package/dist/lib/task/current-contract.js +5 -1
- package/dist/lib/task/decision-details.js +3 -48
- package/dist/lib/task/delivery-target.js +97 -0
- package/dist/lib/task/delivery.js +153 -0
- package/dist/lib/task/events.js +297 -17
- package/dist/lib/task/finalization.js +37 -13
- package/dist/lib/task/human-override.js +61 -36
- package/dist/lib/task/invalidation-command.js +86 -0
- package/dist/lib/task/invalidation.js +260 -0
- package/dist/lib/task/ledger-intents.js +37 -0
- package/dist/lib/task/lifecycle.js +106 -9
- package/dist/lib/task/local-artifact-finalization.js +374 -0
- package/dist/lib/task/orchestration.js +100 -151
- package/dist/lib/task/pr-delivery-fact.js +183 -0
- package/dist/lib/task/review-finalization.js +4 -8
- package/dist/lib/task/review-fingerprint.js +32 -2
- package/dist/lib/task/rework-intent.js +138 -0
- package/dist/lib/task/skill-scope.js +23 -0
- package/dist/lib/task/task-execution-lock.js +27 -17
- package/dist/lib/task/verification-engine.js +89 -38
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +3 -3
- package/dist/lib/task/workflow-warning-intents.js +1 -1
- package/dist/lib/task/write.js +11 -0
- package/dist/lib/update.js +9 -0
- package/dist/lib/version.js +11 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- 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/next-steps.ts +6 -1
- package/lib/decide.ts +3 -3
- package/lib/defaults.json +4 -0
- package/lib/git/workflow.ts +38 -1
- package/lib/init.ts +4 -1
- package/lib/internal/git-workflow.ts +7 -1
- package/lib/internal/platform-checks.ts +3 -3
- package/lib/internal/platform-comment.ts +8 -8
- package/lib/internal/platform-context.ts +2 -2
- package/lib/internal/platform-issue.ts +7 -8
- package/lib/internal/platform-pr-review.ts +9 -9
- package/lib/internal/platform-pr.ts +53 -21
- package/lib/internal/platform-release-notes.ts +3 -3
- package/lib/internal/pr-review-grade.ts +10 -8
- package/lib/internal/release-workflow.ts +4 -4
- package/lib/internal/sandbox-control.ts +27 -3
- package/lib/internal/task-activity.ts +3 -3
- package/lib/internal/task-artifact.ts +65 -22
- package/lib/internal/task-create.ts +2 -2
- package/lib/internal/task-delivery.ts +53 -0
- package/lib/internal/task-event.ts +6 -3
- package/lib/internal/task-finalization.ts +3 -3
- package/lib/internal/task-invalidation.ts +39 -0
- package/lib/internal/task-ledger.ts +11 -8
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-override.ts +6 -6
- package/lib/internal/task-review.ts +3 -3
- package/lib/internal/task-verify.ts +6 -6
- package/lib/internal/task-warning.ts +3 -3
- package/lib/platform/adapters.ts +3 -2
- package/lib/platform/change-request-git-evidence.ts +36 -9
- package/lib/platform/completion-backfill.ts +9 -8
- package/lib/platform/context.ts +97 -134
- package/lib/platform/github-client.ts +10 -3
- package/lib/platform/github-provider.ts +910 -0
- package/lib/platform/in-label-sync.ts +208 -0
- package/lib/platform/issue-comments.ts +97 -47
- package/lib/platform/issues.ts +344 -174
- package/lib/platform/metadata-labels.ts +5 -2
- package/lib/platform/none-provider.ts +35 -0
- package/lib/platform/pr-change-report.ts +645 -0
- package/lib/platform/pr-checks.ts +129 -107
- package/lib/platform/pr-review.ts +88 -85
- package/lib/platform/pr-summary.ts +562 -52
- package/lib/platform/provider-bridge.ts +82 -0
- package/lib/platform/provider-contract.ts +536 -0
- package/lib/platform/provider-loader.ts +307 -0
- package/lib/platform/provider-validation.ts +529 -0
- package/lib/platform/pull-request-metadata.ts +10 -7
- package/lib/platform/pull-requests.ts +1126 -505
- package/lib/platform/release-notes.ts +76 -59
- package/lib/platform/releases.ts +77 -43
- package/lib/platform/resource-identity.ts +121 -0
- package/lib/platform/task-identities.ts +40 -0
- package/lib/platform/types.ts +4 -2
- package/lib/platform/verification-required.ts +21 -13
- package/lib/platform/verification-sync.ts +118 -293
- package/lib/pr-review/evidence-grading.ts +31 -11
- package/lib/run/index.ts +57 -22
- package/lib/sandbox/config.ts +7 -0
- package/lib/sandbox/control/client.ts +105 -15
- package/lib/sandbox/control/executor.ts +4 -4
- package/lib/sandbox/control/lifecycle.ts +30 -8
- package/lib/sandbox/control/protocol.ts +113 -0
- package/lib/sandbox/control/server.ts +431 -23
- package/lib/sandbox/control/state.ts +251 -1
- package/lib/server/process-state.ts +2 -2
- package/lib/server/protocol.ts +36 -1
- package/lib/task/activity-log.ts +8 -0
- package/lib/task/artifact-lifecycle.ts +34 -8
- package/lib/task/capabilities.ts +262 -0
- package/lib/task/commands/status.ts +38 -0
- package/lib/task/commit-intent.ts +137 -0
- package/lib/task/commit-operation.ts +186 -88
- package/lib/task/control-authority.ts +11 -8
- package/lib/task/create-service.ts +8 -8
- package/lib/task/create.ts +34 -9
- package/lib/task/current-contract.ts +6 -1
- package/lib/task/decision-details.ts +8 -64
- package/lib/task/delivery-target.ts +130 -0
- package/lib/task/delivery.ts +160 -0
- package/lib/task/events.ts +296 -16
- package/lib/task/finalization.ts +50 -14
- package/lib/task/human-override.ts +73 -46
- package/lib/task/invalidation-command.ts +86 -0
- package/lib/task/invalidation.ts +332 -0
- package/lib/task/ledger-intents.ts +35 -1
- package/lib/task/lifecycle.ts +93 -4
- package/lib/task/local-artifact-finalization.ts +563 -0
- package/lib/task/orchestration.ts +110 -146
- package/lib/task/pr-delivery-fact.ts +237 -0
- package/lib/task/review-finalization.ts +4 -14
- package/lib/task/review-fingerprint.ts +33 -2
- package/lib/task/rework-intent.ts +165 -0
- package/lib/task/skill-scope.ts +24 -0
- package/lib/task/task-execution-lock.ts +23 -14
- package/lib/task/verification-engine.ts +95 -43
- package/lib/task/verification-review.ts +2 -0
- package/lib/task/verification.ts +4 -4
- package/lib/task/workflow-warning-intents.ts +1 -1
- package/lib/task/write.ts +19 -0
- package/lib/update.ts +11 -1
- package/lib/version.ts +15 -1
- package/package.json +7 -1
- package/templates/.agents/rules/README.en.md +4 -2
- package/templates/.agents/rules/README.zh-CN.md +4 -2
- 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/issue-pr-commands.en.md +4 -17
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +28 -5
- package/templates/.agents/rules/issue-sync.zh-CN.md +64 -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 +53 -0
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +53 -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/pr-sync.en.md +28 -13
- package/templates/.agents/rules/pr-sync.zh-CN.md +39 -5
- 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/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 +1 -1
- package/templates/.agents/rules/task-management.zh-CN.md +1 -1
- package/templates/.agents/rules/task-short-id.en.md +1 -4
- package/templates/.agents/rules/task-short-id.zh-CN.md +1 -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 +14 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +32 -10
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +35 -13
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/commit/SKILL.en.md +3 -3
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
- 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/issue-metadata-sync.en.md +2 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +4 -4
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +4 -4
- 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 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -4
- 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 +5 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +5 -4
- package/templates/.agents/skills/complete-task/SKILL.en.md +31 -13
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +30 -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 +11 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/create-pr/config/verify.json +1 -0
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
- package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
- 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/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 +14 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +6 -5
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +6 -5
- 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 +10 -9
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +10 -9
- 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 +6 -5
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +6 -5
- 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 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +6 -6
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
- package/templates/.agents/templates/task.en.md +23 -2
- package/templates/.agents/templates/task.zh-CN.md +23 -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/.github/workflows/pr-label.yml +7 -26
- 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 -44
- package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
- package/templates/.agents/rules/security-alerts.github.en.md +0 -43
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
- /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
- /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const REWORK_INTENT_HEADINGS = ['返工意图', 'Rework Intent'];
|
|
2
|
+
const REWORK_INTENT_COLUMNS = [
|
|
3
|
+
'intent_id', 'finding_id', 'source_artifact', 'source_sha256', 'target',
|
|
4
|
+
'status', 'declared_at', 'consumed_at'
|
|
5
|
+
];
|
|
6
|
+
function cells(line) {
|
|
7
|
+
const first = line.indexOf('|');
|
|
8
|
+
const last = line.lastIndexOf('|');
|
|
9
|
+
if (first < 0 || first === last || line.slice(0, first).trim() || line.slice(last + 1).trim())
|
|
10
|
+
return null;
|
|
11
|
+
const inner = line.slice(first + 1, last);
|
|
12
|
+
const result = [];
|
|
13
|
+
let start = 0;
|
|
14
|
+
let escaped = false;
|
|
15
|
+
for (let index = 0; index < inner.length; index += 1) {
|
|
16
|
+
const char = inner[index];
|
|
17
|
+
if (char === '|' && !escaped) {
|
|
18
|
+
result.push(inner.slice(start, index));
|
|
19
|
+
start = index + 1;
|
|
20
|
+
}
|
|
21
|
+
escaped = char === '\\' && !escaped;
|
|
22
|
+
if (char !== '\\')
|
|
23
|
+
escaped = false;
|
|
24
|
+
}
|
|
25
|
+
result.push(inner.slice(start));
|
|
26
|
+
return result.map((cell) => cell.replace(/\\([\\|])/g, '$1').trim());
|
|
27
|
+
}
|
|
28
|
+
function sectionBody(content) {
|
|
29
|
+
const heading = REWORK_INTENT_HEADINGS.map((value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
30
|
+
const match = new RegExp(`^##\\s+(${heading})\\s*$`, 'm').exec(content);
|
|
31
|
+
if (!match)
|
|
32
|
+
return null;
|
|
33
|
+
const start = (match.index ?? 0) + match[0].length;
|
|
34
|
+
const rest = content.slice(start);
|
|
35
|
+
const end = rest.search(/^##\s+/m);
|
|
36
|
+
return rest.slice(0, end < 0 ? rest.length : end);
|
|
37
|
+
}
|
|
38
|
+
function parseReworkIntentDocument(content) {
|
|
39
|
+
const body = sectionBody(content);
|
|
40
|
+
if (body === null)
|
|
41
|
+
return { ok: true, present: false, intents: [] };
|
|
42
|
+
const lines = body.split(/\r?\n/).filter((line) => line.trim());
|
|
43
|
+
const header = lines[0] ? cells(lines[0]) : null;
|
|
44
|
+
const separator = lines[1] ? cells(lines[1]) : null;
|
|
45
|
+
if (!header || !separator || header.length !== REWORK_INTENT_COLUMNS.length || !header.every((value, index) => value === REWORK_INTENT_COLUMNS[index]) || !separator.every((value) => /^:?-{3,}:?$/.test(value))) {
|
|
46
|
+
return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: 'rework intent section must contain its canonical table' };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const intents = lines.slice(2).map((line) => {
|
|
50
|
+
const values = cells(line);
|
|
51
|
+
if (!values || values.length !== REWORK_INTENT_COLUMNS.length)
|
|
52
|
+
throw new Error('rework intent row has the wrong column count');
|
|
53
|
+
const row = Object.fromEntries(REWORK_INTENT_COLUMNS.map((column, index) => [column, values[index]]));
|
|
54
|
+
if (!/^RI-[1-9]\d*$/.test(row.intent_id))
|
|
55
|
+
throw new Error(`invalid intent id '${row.intent_id}'`);
|
|
56
|
+
if (!/^(AN|PL|CD)-[1-9]\d*$/.test(row.finding_id))
|
|
57
|
+
throw new Error(`invalid finding id '${row.finding_id}'`);
|
|
58
|
+
if (!['analysis', 'plan', 'code'].includes(row.target))
|
|
59
|
+
throw new Error(`invalid rework target '${row.target}'`);
|
|
60
|
+
if (!['pending', 'consumed', 'superseded'].includes(row.status))
|
|
61
|
+
throw new Error(`invalid rework status '${row.status}'`);
|
|
62
|
+
if (!/^[a-f0-9]{64}$/.test(row.source_sha256))
|
|
63
|
+
throw new Error(`invalid source hash for '${row.intent_id}'`);
|
|
64
|
+
if (!row.source_artifact || !row.declared_at)
|
|
65
|
+
throw new Error(`rework intent '${row.intent_id}' has invalid required fields`);
|
|
66
|
+
const terminal = row.status === 'consumed' || row.status === 'superseded';
|
|
67
|
+
if (terminal !== Boolean(row.consumed_at))
|
|
68
|
+
throw new Error(`rework intent '${row.intent_id}' has invalid consumed_at`);
|
|
69
|
+
return {
|
|
70
|
+
intentId: row.intent_id, findingId: row.finding_id, sourceArtifact: row.source_artifact,
|
|
71
|
+
sourceSha256: row.source_sha256, target: row.target,
|
|
72
|
+
status: row.status, declaredAt: row.declared_at, consumedAt: row.consumed_at
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
const ids = new Set();
|
|
76
|
+
for (const intent of intents) {
|
|
77
|
+
if (ids.has(intent.intentId))
|
|
78
|
+
throw new Error(`duplicate intent '${intent.intentId}'`);
|
|
79
|
+
ids.add(intent.intentId);
|
|
80
|
+
}
|
|
81
|
+
return { ok: true, present: true, intents };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: error instanceof Error ? error.message : String(error) };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function renderReworkIntents(intents) {
|
|
88
|
+
const escape = (value) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' ');
|
|
89
|
+
return [
|
|
90
|
+
`| ${REWORK_INTENT_COLUMNS.join(' | ')} |`,
|
|
91
|
+
`| ${REWORK_INTENT_COLUMNS.map(() => '---').join(' | ')} |`,
|
|
92
|
+
...intents.map((intent) => `| ${[
|
|
93
|
+
intent.intentId, intent.findingId, intent.sourceArtifact, intent.sourceSha256,
|
|
94
|
+
intent.target, intent.status, intent.declaredAt, intent.consumedAt
|
|
95
|
+
].map(escape).join(' | ')} |`)
|
|
96
|
+
].join('\n');
|
|
97
|
+
}
|
|
98
|
+
function upsertReworkIntent(intents, intent) {
|
|
99
|
+
const existing = intents.find((candidate) => candidate.intentId === intent.intentId);
|
|
100
|
+
if (!existing)
|
|
101
|
+
return { changed: true, intents: [...intents, intent] };
|
|
102
|
+
const identity = (value) => [value.intentId, value.findingId, value.sourceArtifact, value.sourceSha256, value.target];
|
|
103
|
+
if (JSON.stringify(identity(existing)) !== JSON.stringify(identity(intent)))
|
|
104
|
+
throw new Error(`intent '${intent.intentId}' identity conflicts with existing state`);
|
|
105
|
+
return { changed: false, intents };
|
|
106
|
+
}
|
|
107
|
+
function consumeReworkIntents(intents, target, sourceHashes, consumedAt) {
|
|
108
|
+
let changed = false;
|
|
109
|
+
const next = intents.map((intent) => {
|
|
110
|
+
if (intent.status !== 'pending'
|
|
111
|
+
|| intent.target !== target
|
|
112
|
+
|| sourceHashes[intent.sourceArtifact] !== intent.sourceSha256)
|
|
113
|
+
return intent;
|
|
114
|
+
changed = true;
|
|
115
|
+
return { ...intent, status: 'consumed', consumedAt };
|
|
116
|
+
});
|
|
117
|
+
return { changed, intents: next };
|
|
118
|
+
}
|
|
119
|
+
function supersedeReworkIntents(intents, sourceArtifact, sourceSha256, supersededAt) {
|
|
120
|
+
let changed = false;
|
|
121
|
+
const next = intents.map((intent) => {
|
|
122
|
+
if (intent.status !== 'pending' || intent.sourceArtifact !== sourceArtifact || intent.sourceSha256 === sourceSha256)
|
|
123
|
+
return intent;
|
|
124
|
+
changed = true;
|
|
125
|
+
return { ...intent, status: 'superseded', consumedAt: supersededAt };
|
|
126
|
+
});
|
|
127
|
+
return { changed, intents: next };
|
|
128
|
+
}
|
|
129
|
+
function reworkIntentMutation(content, intents) {
|
|
130
|
+
return {
|
|
131
|
+
kind: 'section',
|
|
132
|
+
aliases: REWORK_INTENT_HEADINGS,
|
|
133
|
+
heading: /^##\s+Rework Intent\s*$/m.test(content) ? REWORK_INTENT_HEADINGS[1] : REWORK_INTENT_HEADINGS[0],
|
|
134
|
+
body: renderReworkIntents(intents)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
export { REWORK_INTENT_COLUMNS, REWORK_INTENT_HEADINGS, parseReworkIntentDocument, renderReworkIntents, reworkIntentMutation, consumeReworkIntents, supersedeReworkIntents, upsertReworkIntent };
|
|
138
|
+
//# sourceMappingURL=rework-intent.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const TASK_SCOPE_SKILLS = new Set([
|
|
2
|
+
'analyze-task',
|
|
3
|
+
'block-task',
|
|
4
|
+
'cancel-task',
|
|
5
|
+
'check-task',
|
|
6
|
+
'code-task',
|
|
7
|
+
'commit',
|
|
8
|
+
'complete-manual-validation',
|
|
9
|
+
'complete-task',
|
|
10
|
+
'create-pr',
|
|
11
|
+
'plan-task',
|
|
12
|
+
'review-analysis',
|
|
13
|
+
'review-code',
|
|
14
|
+
'review-plan',
|
|
15
|
+
'run-manual-validation',
|
|
16
|
+
'run-task',
|
|
17
|
+
'watch-pr'
|
|
18
|
+
]);
|
|
19
|
+
function isTaskScopeSkill(skillName) {
|
|
20
|
+
return TASK_SCOPE_SKILLS.has(skillName);
|
|
21
|
+
}
|
|
22
|
+
export { TASK_SCOPE_SKILLS, isTaskScopeSkill };
|
|
23
|
+
//# sourceMappingURL=skill-scope.js.map
|
|
@@ -160,6 +160,25 @@ function withTaskExecutionLock(repoRoot, taskId, ownerName, callback, options =
|
|
|
160
160
|
};
|
|
161
161
|
const serialized = `${JSON.stringify(owner)}\n`;
|
|
162
162
|
let ownsFixed = false;
|
|
163
|
+
let deferRelease = false;
|
|
164
|
+
const release = () => {
|
|
165
|
+
try {
|
|
166
|
+
unlinkIfPresent(candidate);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Candidate cleanup is best-effort and must not replace the primary result.
|
|
170
|
+
}
|
|
171
|
+
if (ownsFixed) {
|
|
172
|
+
try {
|
|
173
|
+
const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
|
|
174
|
+
if (current.token === token)
|
|
175
|
+
unlinkIfPresent(fixed);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// A missing or replaced fixed lock is not owned by this invocation.
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
163
182
|
try {
|
|
164
183
|
fs.mkdirSync(lockRoot, { recursive: true });
|
|
165
184
|
cleanStaleCandidates(lockRoot, key, options.identityMatches ?? processIdentityMatches);
|
|
@@ -202,7 +221,12 @@ function withTaskExecutionLock(repoRoot, taskId, ownerName, callback, options =
|
|
|
202
221
|
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_BUSY', 'lifecycle task lock could not be acquired after stale recovery', { operation: 'acquire', errno: 'EEXIST', key });
|
|
203
222
|
}
|
|
204
223
|
unlinkIfPresent(candidate);
|
|
205
|
-
|
|
224
|
+
const value = callback();
|
|
225
|
+
if (value && typeof value.then === 'function') {
|
|
226
|
+
deferRelease = true;
|
|
227
|
+
return value.finally(release);
|
|
228
|
+
}
|
|
229
|
+
return value;
|
|
206
230
|
}
|
|
207
231
|
catch (error) {
|
|
208
232
|
if (error instanceof TaskExecutionLockError)
|
|
@@ -212,22 +236,8 @@ function withTaskExecutionLock(repoRoot, taskId, ownerName, callback, options =
|
|
|
212
236
|
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'lifecycle task lock operation failed', { operation: ownsFixed ? 'callback' : 'acquire', errno: errno(error), key });
|
|
213
237
|
}
|
|
214
238
|
finally {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
// Candidate cleanup is best-effort and must not replace the primary result.
|
|
220
|
-
}
|
|
221
|
-
if (ownsFixed) {
|
|
222
|
-
try {
|
|
223
|
-
const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
|
|
224
|
-
if (current.token === token)
|
|
225
|
-
unlinkIfPresent(fixed);
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
// A missing or replaced fixed lock is not owned by this invocation.
|
|
229
|
-
}
|
|
230
|
-
}
|
|
239
|
+
if (!deferRelease)
|
|
240
|
+
release();
|
|
231
241
|
}
|
|
232
242
|
}
|
|
233
243
|
function withRepositoryMutationLock(repoRoot, callback, options = {}) {
|
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from "./verification-review.js";
|
|
7
|
+
import { extractReviewBaseline, extractReviewTargetHead, extractReviewedHead, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from "./verification-review.js";
|
|
8
8
|
import { check as checkPlatformSync } from "../platform/verification-sync.js";
|
|
9
9
|
import { check as checkRequiredChecks } from "../platform/verification-required.js";
|
|
10
10
|
import { inspectPlatformPullRequest } from "../platform/pull-requests.js";
|
|
@@ -19,6 +19,9 @@ import { inspectDecisionDetailDuplicates } from "./decision-details.js";
|
|
|
19
19
|
import { loadVerificationConfig } from "./verification-config.js";
|
|
20
20
|
import { snapshotReview } from "../git/review-snapshot.js";
|
|
21
21
|
import { OrchestrationStateError, readRun } from "./orchestration.js";
|
|
22
|
+
import { resolveDeliveryTarget } from "./delivery-target.js";
|
|
23
|
+
import { readPrDeliveryFact } from "./pr-delivery-fact.js";
|
|
24
|
+
import { validateLocalArtifact } from "./local-artifact-finalization.js";
|
|
22
25
|
const TASK_ENUMS = {
|
|
23
26
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
24
27
|
workflow: ["feature-development", "bug-fix", "refactoring"],
|
|
@@ -67,7 +70,7 @@ const scriptPath = fileURLToPath(import.meta.url);
|
|
|
67
70
|
let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
|
|
68
71
|
const PLATFORM_ADAPTERS = {
|
|
69
72
|
"platform-sync": checkPlatformSync,
|
|
70
|
-
"platform-sync-preflight": (context, shared) => ({ ...checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
73
|
+
"platform-sync-preflight": async (context, shared) => ({ ...await checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
71
74
|
"required-checks": checkRequiredChecks
|
|
72
75
|
};
|
|
73
76
|
const OPTIONAL_PLATFORM_CHECKS = new Set(["platform-sync"]);
|
|
@@ -84,7 +87,7 @@ const sharedUtils = {
|
|
|
84
87
|
parseIssueNumber,
|
|
85
88
|
parsePrNumber
|
|
86
89
|
};
|
|
87
|
-
function runCheck(type, context, shared) {
|
|
90
|
+
async function runCheck(type, context, shared) {
|
|
88
91
|
switch (type) {
|
|
89
92
|
case "task-meta":
|
|
90
93
|
return checkTaskMeta(context);
|
|
@@ -122,7 +125,7 @@ function runCheck(type, context, shared) {
|
|
|
122
125
|
}
|
|
123
126
|
return failResult(type, `Unsupported check type '${type}'.`);
|
|
124
127
|
}
|
|
125
|
-
return adapter(context, shared);
|
|
128
|
+
return await adapter(context, shared);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
@@ -176,13 +179,12 @@ function validateCleanCompletionEvidence(run) {
|
|
|
176
179
|
|| !shaPattern.test(evidence.headTree)
|
|
177
180
|
|| !shaPattern.test(evidence.worktreeTree)
|
|
178
181
|
|| !shaPattern.test(evidence.lastReviewedCommit)
|
|
179
|
-
|| !Number.isInteger(evidence.prNumber)
|
|
180
|
-
|| evidence.
|
|
181
|
-
|| !shaPattern.test(evidence.prHead)) {
|
|
182
|
+
|| !(evidence.prNumber === null || (Number.isInteger(evidence.prNumber) && evidence.prNumber > 0))
|
|
183
|
+
|| !(evidence.prHead === null || shaPattern.test(evidence.prHead))) {
|
|
182
184
|
return 'Clean completion evidence has an invalid structure';
|
|
183
185
|
}
|
|
184
186
|
if (evidence.head !== evidence.lastReviewedCommit
|
|
185
|
-
|| evidence.head !== evidence.prHead
|
|
187
|
+
|| (evidence.prHead !== null && evidence.head !== evidence.prHead)
|
|
186
188
|
|| evidence.headTree !== evidence.worktreeTree) {
|
|
187
189
|
return 'Clean completion evidence does not bind matching commit and tree identities';
|
|
188
190
|
}
|
|
@@ -251,10 +253,8 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
251
253
|
if (evidenceError)
|
|
252
254
|
return failResult('orchestration-evidence', evidenceError);
|
|
253
255
|
}
|
|
254
|
-
else if (run.status === 'completed'
|
|
255
|
-
|
|
256
|
-
|| run.receipts.at(-1)?.status !== 'consumed')) {
|
|
257
|
-
return failResult('orchestration-evidence', 'Completed run requires a final consumed commit receipt');
|
|
256
|
+
else if (run.status === 'completed') {
|
|
257
|
+
return failResult('orchestration-evidence', 'Completed run requires reviewed-head-clean completion evidence');
|
|
258
258
|
}
|
|
259
259
|
if (run.pendingDelegation && !['prepared', 'activated', 'stage-completed'].includes(run.pendingDelegation.status)) {
|
|
260
260
|
return failResult('orchestration-evidence', `Pending receipt has unsafe status '${run.pendingDelegation.status}'`);
|
|
@@ -420,7 +420,7 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
420
420
|
const warningSuffix = warnings.length > 0 ? `; warnings: ${warnings.join("; ")}` : "";
|
|
421
421
|
return passResult("task-meta", `Task metadata valid (${requiredFields.length} required fields checked${warningSuffix})`, warnings);
|
|
422
422
|
}
|
|
423
|
-
function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }) {
|
|
423
|
+
async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }) {
|
|
424
424
|
const task = loadTask(taskDir);
|
|
425
425
|
if (!task.ok)
|
|
426
426
|
return failResult('required-pr-delivery', task.message);
|
|
@@ -434,43 +434,47 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }) {
|
|
|
434
434
|
return failResult('required-pr-delivery', 'Project configuration is invalid');
|
|
435
435
|
}
|
|
436
436
|
const flow = projectConfig.prFlow;
|
|
437
|
-
const
|
|
438
|
-
|
|
437
|
+
const factRead = readPrDeliveryFact(task.metadata);
|
|
438
|
+
if (factRead.status === 'invalid')
|
|
439
|
+
return failResult('required-pr-delivery', factRead.error.message);
|
|
440
|
+
const fact = factRead.status === 'valid' ? factRead.fact : null;
|
|
441
|
+
const status = fact?.state || 'unbound';
|
|
442
|
+
const prIdentity = fact?.state === 'bound' ? fact.identity.resource : null;
|
|
443
|
+
const prNumber = prIdentity?.kind === 'number' ? prIdentity.value : null;
|
|
439
444
|
if (flow === 'disabled')
|
|
440
445
|
return passResult('required-pr-delivery', 'Pull request delivery is disabled by project policy');
|
|
441
|
-
if (flow === 'required' && (status !== '
|
|
446
|
+
if (flow === 'required' && (status !== 'bound' || !prIdentity)) {
|
|
442
447
|
return failResult('required-pr-delivery', 'Project policy requires a bound pull request before completion');
|
|
443
448
|
}
|
|
444
|
-
if (flow !== 'required' && status === '
|
|
449
|
+
if (flow !== 'required' && status === 'unbound') {
|
|
445
450
|
return failResult('required-pr-delivery', 'Pull request delivery is pending; create a PR or explicitly skip it');
|
|
446
451
|
}
|
|
447
|
-
if (status === 'created' && prNumber === null) {
|
|
448
|
-
return failResult('required-pr-delivery', 'Task claims a created pull request without a valid pr_number');
|
|
449
|
-
}
|
|
450
452
|
if (flow === 'required') {
|
|
451
453
|
if (mode === 'gate') {
|
|
452
454
|
return passResult('required-pr-delivery', 'Bound pull request shape is valid; merged-state inspection is reserved for hard preflight');
|
|
453
455
|
}
|
|
454
|
-
const inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
|
|
456
|
+
const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
|
|
455
457
|
if (inspected.status === 'blocked') {
|
|
456
458
|
return blockedResult('required-pr-delivery', inspected.error?.message || 'Unable to inspect the required pull request', inspected.error?.code || 'PR_INSPECTION_BLOCKED');
|
|
457
459
|
}
|
|
458
460
|
const pullRequest = inspected.pullRequest;
|
|
459
461
|
const repository = inspected.platform.repository?.toLowerCase() || '';
|
|
460
462
|
const taskBranch = String(task.metadata.branch || '').trim();
|
|
461
|
-
|
|
463
|
+
const deliveryBaseRef = String(task.metadata.delivery_base_ref || projectConfig.delivery?.baseRef || '').trim();
|
|
464
|
+
if (inspected.status !== 'no-op' || !pullRequest) {
|
|
462
465
|
return failResult('required-pr-delivery', 'Bound pull request identity could not be verified');
|
|
463
466
|
}
|
|
464
467
|
if (!repository
|
|
465
468
|
|| pullRequest.repository.toLowerCase() !== repository
|
|
466
469
|
|| pullRequest.base.repository.toLowerCase() !== repository
|
|
467
|
-
|| (taskBranch && pullRequest.head.ref !== taskBranch)
|
|
470
|
+
|| (taskBranch && pullRequest.head.ref !== taskBranch)
|
|
471
|
+
|| (deliveryBaseRef && pullRequest.base.ref !== deliveryBaseRef)) {
|
|
468
472
|
return failResult('required-pr-delivery', 'Bound pull request identity does not match the task');
|
|
469
473
|
}
|
|
470
474
|
if (pullRequest.state !== 'closed' || !pullRequest.mergedAt || !pullRequest.mergeCommitSha) {
|
|
471
475
|
return failResult('required-pr-delivery', 'Project policy requires the bound pull request to be merged');
|
|
472
476
|
}
|
|
473
|
-
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR
|
|
477
|
+
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR ${prNumber === null ? 'identity' : `#${prNumber}`})`);
|
|
474
478
|
}
|
|
475
479
|
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
|
|
476
480
|
}
|
|
@@ -502,7 +506,7 @@ function loadProjectName() {
|
|
|
502
506
|
return "";
|
|
503
507
|
}
|
|
504
508
|
}
|
|
505
|
-
function checkArtifact({ taskDir, config, artifactFile }) {
|
|
509
|
+
function checkArtifact({ taskDir, config, artifactFile, skillName }) {
|
|
506
510
|
const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
|
|
507
511
|
if (!resolvedArtifact.ok) {
|
|
508
512
|
return failResult("artifact", resolvedArtifact.message);
|
|
@@ -517,6 +521,20 @@ function checkArtifact({ taskDir, config, artifactFile }) {
|
|
|
517
521
|
}
|
|
518
522
|
const content = fs.readFileSync(artifactPath, "utf8");
|
|
519
523
|
const requiredSections = config.required_sections || [];
|
|
524
|
+
const localFamily = skillName === "analyze-task"
|
|
525
|
+
? "analysis"
|
|
526
|
+
: skillName === "plan-task" ? "plan" : skillName === "code-task" ? "code" : null;
|
|
527
|
+
if (localFamily) {
|
|
528
|
+
const local = validateLocalArtifact(content, {
|
|
529
|
+
family: localFamily,
|
|
530
|
+
requiredSections: requiredSections.filter((section) => typeof section === "string"),
|
|
531
|
+
requiredPatterns: (config.required_patterns || []).filter((pattern) => typeof pattern === "string")
|
|
532
|
+
});
|
|
533
|
+
if (!local.ok) {
|
|
534
|
+
return failResult("artifact", `${path.basename(artifactPath)} has local structural errors: ${local.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`);
|
|
535
|
+
}
|
|
536
|
+
return passResult("artifact", `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`);
|
|
537
|
+
}
|
|
520
538
|
const missingSections = requiredSections.filter((section) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content));
|
|
521
539
|
if (missingSections.length > 0) {
|
|
522
540
|
return failResult("artifact", `${path.basename(artifactPath)} is missing sections: ${missingSections.join(", ")}`);
|
|
@@ -900,6 +918,8 @@ function checkManualValidation({ taskDir }) {
|
|
|
900
918
|
// 1. Latest review-code artifact; none -> pass (no review, check not applicable).
|
|
901
919
|
const review = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
902
920
|
if (!review.ok) {
|
|
921
|
+
if (review.error)
|
|
922
|
+
return failResult("manual-validation", `Review-code artifact is unavailable: ${review.error}`);
|
|
903
923
|
return passResult("manual-validation", "No review-code artifact; manual validation not applicable");
|
|
904
924
|
}
|
|
905
925
|
// 2. Parse the numeric manual-validation count; unparseable/null -> fail closed
|
|
@@ -951,9 +971,11 @@ function checkManualValidation({ taskDir }) {
|
|
|
951
971
|
}
|
|
952
972
|
return passResult("manual-validation", `Manual validation completed → ${artifactName}`);
|
|
953
973
|
}
|
|
954
|
-
function checkPostReviewCommit({ taskDir, config }) {
|
|
974
|
+
async function checkPostReviewCommit({ taskDir, config }) {
|
|
955
975
|
const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
956
976
|
if (!reviewArtifact.ok) {
|
|
977
|
+
if (reviewArtifact.error)
|
|
978
|
+
return failResult("post-review-commit", `Review-code artifact is unavailable: ${reviewArtifact.error}`);
|
|
957
979
|
return passResult("post-review-commit", "No review-code artifact; check inactive");
|
|
958
980
|
}
|
|
959
981
|
let gitRoot;
|
|
@@ -966,12 +988,16 @@ function checkPostReviewCommit({ taskDir, config }) {
|
|
|
966
988
|
const task = loadTask(taskDir);
|
|
967
989
|
if (!task.ok)
|
|
968
990
|
return failResult("post-review-commit", task.message);
|
|
991
|
+
const factRead = readPrDeliveryFact(task.metadata);
|
|
992
|
+
if (factRead.status === 'invalid')
|
|
993
|
+
return failResult("post-review-commit", factRead.error.message);
|
|
994
|
+
const fact = factRead.status === 'valid' ? factRead.fact : null;
|
|
969
995
|
const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
|
|
970
996
|
const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
|
|
971
|
-
const hasPullRequest =
|
|
997
|
+
const hasPullRequest = fact?.state === 'bound';
|
|
972
998
|
let inspected = null;
|
|
973
999
|
if (hasPullRequest) {
|
|
974
|
-
inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
|
|
1000
|
+
inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
|
|
975
1001
|
if (!inspected.pullRequest) {
|
|
976
1002
|
const message = inspected.error?.message || "PR merge snapshot is unavailable";
|
|
977
1003
|
const code = inspected.error?.code || "PR_INSPECTION_INVALID";
|
|
@@ -982,7 +1008,7 @@ function checkPostReviewCommit({ taskDir, config }) {
|
|
|
982
1008
|
if (inspected.pullRequest.state === "closed" &&
|
|
983
1009
|
inspected.pullRequest.mergedAt &&
|
|
984
1010
|
inspected.pullRequest.mergeCommitSha) {
|
|
985
|
-
const relation = resolveMaterializedReviewedHeadRelation({
|
|
1011
|
+
const relation = await resolveMaterializedReviewedHeadRelation({
|
|
986
1012
|
cwd: gitRoot,
|
|
987
1013
|
platformType: inspected.platform.type,
|
|
988
1014
|
lastReviewedCommit,
|
|
@@ -1118,34 +1144,59 @@ function checkReviewFact({ taskDir, artifactFile }) {
|
|
|
1118
1144
|
if (!resolvedArtifact.ok) {
|
|
1119
1145
|
return failResult("review-fact", resolvedArtifact.message);
|
|
1120
1146
|
}
|
|
1147
|
+
const authoritative = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
1148
|
+
if (!authoritative.ok) {
|
|
1149
|
+
return failResult("review-fact", authoritative.error ?? "No active review-code artifact is available");
|
|
1150
|
+
}
|
|
1151
|
+
if (path.basename(resolvedArtifact.path) !== authoritative.fileName) {
|
|
1152
|
+
return failResult("review-fact", `review-code artifact ${path.basename(resolvedArtifact.path)} is not the current active artifact ${authoritative.fileName}; re-run review-code`);
|
|
1153
|
+
}
|
|
1121
1154
|
const task = loadTask(taskDir);
|
|
1122
1155
|
if (!task.ok) {
|
|
1123
1156
|
return failResult("review-fact", task.message);
|
|
1124
1157
|
}
|
|
1125
1158
|
const content = fs.readFileSync(resolvedArtifact.path, "utf8");
|
|
1126
1159
|
const verdict = parseReviewVerdict(content);
|
|
1127
|
-
const
|
|
1160
|
+
const reviewTargetHead = extractReviewTargetHead(content);
|
|
1161
|
+
const reviewReviewedHead = extractReviewedHead(content);
|
|
1128
1162
|
const reviewDiffBase = extractReviewDiffBase(content);
|
|
1129
1163
|
const reviewedFingerprint = extractReviewDiffFingerprint(content);
|
|
1130
1164
|
const reviewedTree = extractReviewedSnapshotTree(content);
|
|
1131
1165
|
if (!["通过", "需要修改", "拒绝", "Approved", "Changes Requested", "Rejected"].includes(verdict)) {
|
|
1132
1166
|
return failResult("review-fact", `Unsupported review verdict '${verdict}'`);
|
|
1133
1167
|
}
|
|
1168
|
+
const deliveryRemote = String(task.metadata.delivery_remote || "").trim();
|
|
1169
|
+
const deliveryBaseRef = String(task.metadata.delivery_base_ref || "").trim();
|
|
1170
|
+
if (!deliveryRemote || !deliveryBaseRef) {
|
|
1171
|
+
return failResult("review-fact", "Task delivery target is not bound; re-run task branch preparation before review-code");
|
|
1172
|
+
}
|
|
1173
|
+
if (!reviewTargetHead || !reviewReviewedHead || !reviewDiffBase) {
|
|
1174
|
+
return failResult("review-fact", "Review fact must record target head, reviewed head, and diff base");
|
|
1175
|
+
}
|
|
1134
1176
|
let gitRoot;
|
|
1135
1177
|
let head;
|
|
1136
1178
|
let baseline;
|
|
1179
|
+
let targetHead;
|
|
1137
1180
|
let diffBase;
|
|
1138
1181
|
try {
|
|
1139
1182
|
gitRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
|
|
1140
1183
|
head = execFileSync("git", ["-C", gitRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
|
|
1141
|
-
|
|
1142
|
-
|
|
1184
|
+
const target = resolveDeliveryTarget(gitRoot, { remote: deliveryRemote, baseRef: deliveryBaseRef });
|
|
1185
|
+
if (!target.ok)
|
|
1186
|
+
throw new Error(target.message);
|
|
1187
|
+
const reviewedRef = reviewReviewedHead;
|
|
1188
|
+
baseline = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewedRef}^{commit}`], { encoding: "utf8" }).trim();
|
|
1189
|
+
targetHead = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewTargetHead}^{commit}`], { encoding: "utf8" }).trim();
|
|
1190
|
+
const computed = execFileSync("git", ["-C", gitRoot, "merge-base", baseline, targetHead], { encoding: "utf8" }).trim();
|
|
1191
|
+
diffBase = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewDiffBase}^{commit}`], { encoding: "utf8" }).trim();
|
|
1192
|
+
if (diffBase !== computed)
|
|
1193
|
+
throw new Error('saved review diff base does not match merge-base(reviewed head, target head)');
|
|
1143
1194
|
}
|
|
1144
1195
|
catch {
|
|
1145
|
-
return blockedResult("review-fact", `Unable to resolve review
|
|
1196
|
+
return blockedResult("review-fact", `Unable to resolve saved review commits in the task repository; re-run review-code`);
|
|
1146
1197
|
}
|
|
1147
1198
|
if (baseline !== head) {
|
|
1148
|
-
return failResult("review-fact", `
|
|
1199
|
+
return failResult("review-fact", `Reviewed head ${baseline.slice(0, 8)} does not match current HEAD ${head.slice(0, 8)}; re-run review-code`);
|
|
1149
1200
|
}
|
|
1150
1201
|
let actualSnapshot;
|
|
1151
1202
|
try {
|
|
@@ -1170,7 +1221,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
|
|
|
1170
1221
|
const lastReviewedCommit = String(task.metadata.last_reviewed_commit || "").trim();
|
|
1171
1222
|
const cleanSnapshot = actualSnapshot.tree === execFileSync("git", ["-C", gitRoot, "rev-parse", `${baseline}^{tree}`], { encoding: "utf8" }).trim();
|
|
1172
1223
|
if (cleanSnapshot && lastReviewedCommit !== baseline) {
|
|
1173
|
-
return failResult("review-fact", `Approved clean review must set task last_reviewed_commit to
|
|
1224
|
+
return failResult("review-fact", `Approved clean review must set task last_reviewed_commit to reviewed head ${baseline.slice(0, 8)}`);
|
|
1174
1225
|
}
|
|
1175
1226
|
if (!cleanSnapshot && lastReviewedCommit) {
|
|
1176
1227
|
return failResult("review-fact", "Approved review with uncommitted changes must remain unanchored until commit");
|
|
@@ -1377,7 +1428,7 @@ function escapeRegExp(value) {
|
|
|
1377
1428
|
function isBlank(value) {
|
|
1378
1429
|
return value === undefined || value === null || String(value).trim() === "";
|
|
1379
1430
|
}
|
|
1380
|
-
function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }) {
|
|
1431
|
+
async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }) {
|
|
1381
1432
|
if (repositoryRoot)
|
|
1382
1433
|
repoRoot = path.resolve(repositoryRoot);
|
|
1383
1434
|
else {
|
|
@@ -1394,7 +1445,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
|
|
|
1394
1445
|
for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
|
|
1395
1446
|
if (checkConfig === null)
|
|
1396
1447
|
continue;
|
|
1397
|
-
const result = runCheck(type, {
|
|
1448
|
+
const result = await runCheck(type, {
|
|
1398
1449
|
mode,
|
|
1399
1450
|
skillName,
|
|
1400
1451
|
taskDir: path.resolve(taskDir),
|
|
@@ -1417,7 +1468,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
|
|
|
1417
1468
|
return { skill: skillName, ...passResult(type, `Check '${type}' is disabled for skill '${skillName}'.`) };
|
|
1418
1469
|
return {
|
|
1419
1470
|
skill: skillName,
|
|
1420
|
-
...runCheck(type, {
|
|
1471
|
+
...await runCheck(type, {
|
|
1421
1472
|
skillName,
|
|
1422
1473
|
taskDir: path.resolve(taskDir),
|
|
1423
1474
|
artifactFile,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
|
|
1
|
+
export { extractReviewBaseline, extractReviewTargetHead, extractReviewedHead, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
|
|
2
2
|
export { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
3
3
|
//# sourceMappingURL=verification-review.js.map
|
|
@@ -41,7 +41,7 @@ function failure(request, code, message, extra = {}) {
|
|
|
41
41
|
artifact: request.artifact ?? null, invocations: [], error: { code, message }, ...extra
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
function verifyTaskEvent(request, options = {}) {
|
|
44
|
+
async function verifyTaskEvent(request, options = {}) {
|
|
45
45
|
const spec = VERIFICATION_CATALOG[request.event];
|
|
46
46
|
if (!spec)
|
|
47
47
|
return failure(request, 'VERIFY_EVENT_UNKNOWN', `unknown verification event '${request.event}'`);
|
|
@@ -66,7 +66,7 @@ function verifyTaskEvent(request, options = {}) {
|
|
|
66
66
|
const invocations = [];
|
|
67
67
|
const engine = options.engine ?? verifyInProcess;
|
|
68
68
|
if (spec.mode === 'gate') {
|
|
69
|
-
const payload = engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot });
|
|
69
|
+
const payload = await engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot });
|
|
70
70
|
const status = payload.gate;
|
|
71
71
|
if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
|
|
72
72
|
invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, gate: 'pass', humanOverride: 'human-approved', originalGate: status } });
|
|
@@ -79,7 +79,7 @@ function verifyTaskEvent(request, options = {}) {
|
|
|
79
79
|
}
|
|
80
80
|
else {
|
|
81
81
|
for (const check of spec.checks ?? []) {
|
|
82
|
-
const payload = engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot });
|
|
82
|
+
const payload = await engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot });
|
|
83
83
|
const status = payload.status;
|
|
84
84
|
if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
|
|
85
85
|
invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, status: 'pass', humanOverride: 'human-approved', originalStatus: status } });
|
|
@@ -38,7 +38,7 @@ function sectionMutation(content) {
|
|
|
38
38
|
const english = /^##\s+Activity Log\s*$/m.test(content);
|
|
39
39
|
return [{
|
|
40
40
|
kind: 'section', aliases: WORKFLOW_WARNING_HEADINGS, heading: english ? 'Workflow Warnings' : '工作流告警',
|
|
41
|
-
body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n
|
|
41
|
+
body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n|----|------|------|----------|------|--------|---------|--------|-------------|------------|------------|`
|
|
42
42
|
}];
|
|
43
43
|
}
|
|
44
44
|
function rowMutation(row) {
|
package/dist/lib/task/write.js
CHANGED
|
@@ -6,6 +6,7 @@ import { resolveTaskRef } from './resolve-ref.js';
|
|
|
6
6
|
import { allowsManualOverride } from './guard-override.js';
|
|
7
7
|
import { mutateTableRow, upsertSection } from './sections.js';
|
|
8
8
|
import { validateCurrentTaskContract } from './current-contract.js';
|
|
9
|
+
import { invalidationBlocks, parseInvalidationDocument } from './invalidation.js';
|
|
9
10
|
const DEFAULT_FILE_SYSTEM = {
|
|
10
11
|
readFileSync: (file) => fs.readFileSync(file, 'utf8'),
|
|
11
12
|
statModeSync: (file) => fs.statSync(file).mode,
|
|
@@ -90,6 +91,16 @@ function writeTask(request, options = {}) {
|
|
|
90
91
|
if (!contract.ok) {
|
|
91
92
|
return failure(request, identity, contract.code, contract.message);
|
|
92
93
|
}
|
|
94
|
+
if (invalidationBlocks(contract.invalidation)
|
|
95
|
+
&& options.invalidationContext !== 'source-completion'
|
|
96
|
+
&& options.invalidationContext !== 'reconcile') {
|
|
97
|
+
return failure(request, identity, 'TASK_INVALIDATION_BLOCKED', 'task has an incomplete artifact invalidation operation; reconcile it before writing downstream state');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const invalidation = parseInvalidationDocument(original);
|
|
102
|
+
if (!invalidation.ok)
|
|
103
|
+
return failure(request, identity, 'TASK_INVALIDATION_INVALID', invalidation.message);
|
|
93
104
|
}
|
|
94
105
|
let candidate = original;
|
|
95
106
|
const operations = [];
|