@fitlab-ai/agent-infra 0.9.12 → 0.9.14
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 +11 -11
- package/README.zh-CN.md +11 -11
- package/bin/cli.ts +26 -9
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +66 -40
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/next-steps.js +6 -1
- package/dist/lib/decide.js +3 -3
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +152 -0
- package/dist/lib/internal/codex-lifecycle.js +9 -6
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/platform-checks.js +19 -7
- package/dist/lib/internal/platform-comment.js +25 -13
- package/dist/lib/internal/platform-context.js +6 -3
- package/dist/lib/internal/platform-issue.js +20 -13
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +26 -13
- package/dist/lib/internal/platform-pr.js +84 -31
- package/dist/lib/internal/platform-release-notes.js +9 -6
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +25 -12
- package/dist/lib/internal/release-workflow.js +23 -9
- package/dist/lib/internal/sandbox-control.js +50 -7
- package/dist/lib/internal/task-activity.js +16 -7
- package/dist/lib/internal/task-artifact.js +235 -24
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +50 -17
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +10 -4
- package/dist/lib/internal/task-finalization.js +6 -3
- package/dist/lib/internal/task-invalidation.js +63 -0
- package/dist/lib/internal/task-ledger.js +20 -6
- package/dist/lib/internal/task-lifecycle.js +6 -3
- package/dist/lib/internal/task-operation-registry.js +421 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +14 -7
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +7 -4
- package/dist/lib/internal/task-short-id.js +11 -1
- package/dist/lib/internal/task-snapshot.js +4 -1
- package/dist/lib/internal/task-validate.js +7 -2
- package/dist/lib/internal/task-verify.js +11 -7
- package/dist/lib/internal/task-warning.js +11 -4
- package/dist/lib/platform/adapters.js +1 -3
- package/dist/lib/platform/change-request-git-evidence.js +27 -7
- package/dist/lib/platform/comment-safety.js +226 -0
- package/dist/lib/platform/completion-backfill.js +6 -5
- package/dist/lib/platform/context.js +70 -130
- package/dist/lib/platform/github-client.js +1 -1
- package/dist/lib/platform/github-provider.js +1130 -0
- package/dist/lib/platform/in-label-sync.js +143 -0
- package/dist/lib/platform/issue-comments.js +237 -72
- 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 +545 -0
- package/dist/lib/platform/pr-checks.js +119 -104
- package/dist/lib/platform/pr-review.js +88 -72
- package/dist/lib/platform/pr-summary.js +541 -50
- package/dist/lib/platform/provider-bridge.js +45 -0
- package/dist/lib/platform/provider-contract.d.ts +553 -0
- package/dist/lib/platform/provider-contract.js +99 -0
- package/dist/lib/platform/provider-loader.js +251 -0
- package/dist/lib/platform/provider-validation.js +577 -0
- package/dist/lib/platform/pull-request-metadata.js +8 -6
- package/dist/lib/platform/pull-requests.js +734 -543
- package/dist/lib/platform/release-notes.js +78 -55
- package/dist/lib/platform/releases.js +79 -50
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/resource-identity.d.ts +26 -0
- package/dist/lib/platform/resource-identity.js +92 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/task-identities.js +31 -0
- package/dist/lib/platform/verification-required.js +11 -12
- package/dist/lib/platform/verification-sync.js +129 -248
- package/dist/lib/pr-review/evidence-grading.js +19 -6
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/run/index.js +68 -23
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +32 -6
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +827 -120
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/client.js +174 -19
- package/dist/lib/sandbox/control/completed-reentry.js +85 -0
- package/dist/lib/sandbox/control/container-identity.js +28 -31
- package/dist/lib/sandbox/control/executor.js +151 -16
- package/dist/lib/sandbox/control/lifecycle.js +621 -127
- package/dist/lib/sandbox/control/native-file-lock.js +177 -0
- package/dist/lib/sandbox/control/protocol.js +77 -0
- package/dist/lib/sandbox/control/server.js +677 -34
- package/dist/lib/sandbox/control/state.js +209 -4
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/engines/authority.js +289 -0
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
- package/dist/lib/sandbox/index.js +5 -0
- package/dist/lib/sandbox/recovery.js +21 -1
- package/dist/lib/sandbox/workspace-view.js +2 -1
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/server/protocol.js +38 -1
- package/dist/lib/task/activity-log.js +8 -1
- package/dist/lib/task/artifact-lifecycle.js +75 -18
- package/dist/lib/task/artifact-operations.js +520 -0
- package/dist/lib/task/artifact-repair-intent.js +59 -0
- package/dist/lib/task/artifact-schema.js +135 -0
- package/dist/lib/task/capabilities.js +310 -0
- package/dist/lib/task/commands/status.js +32 -0
- package/dist/lib/task/commit-operation.js +12 -1
- package/dist/lib/task/control-authority.js +12 -5
- package/dist/lib/task/create-service.js +111 -12
- package/dist/lib/task/create.js +25 -0
- package/dist/lib/task/current-contract.js +5 -1
- package/dist/lib/task/decision-details.js +1 -1
- package/dist/lib/task/events.js +416 -17
- package/dist/lib/task/finalization.js +37 -13
- package/dist/lib/task/human-override.js +58 -36
- package/dist/lib/task/index.js +11 -3
- 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/local-artifact-finalization.js +299 -0
- package/dist/lib/task/orchestration.js +240 -144
- package/dist/lib/task/pr-delivery-fact.js +102 -101
- package/dist/lib/task/qualification-audit.js +490 -0
- package/dist/lib/task/qualification-confirmation.js +109 -0
- package/dist/lib/task/qualification-intents.js +148 -0
- package/dist/lib/task/review-artifacts.js +22 -23
- package/dist/lib/task/review-finalization.js +121 -4
- package/dist/lib/task/review-fingerprint.js +24 -2
- package/dist/lib/task/rework-intent.js +138 -0
- package/dist/lib/task/sections.js +6 -4
- package/dist/lib/task/skill-scope.js +23 -0
- package/dist/lib/task/task-execution-lock.js +27 -17
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +93 -16
- 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/version.js +11 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/next-steps.ts +6 -1
- package/lib/decide.ts +3 -3
- package/lib/init.ts +1 -1
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +140 -0
- package/lib/internal/codex-lifecycle.ts +8 -6
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/platform-checks.ts +14 -6
- package/lib/internal/platform-comment.ts +20 -12
- package/lib/internal/platform-context.ts +5 -3
- package/lib/internal/platform-issue.ts +17 -11
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +23 -12
- package/lib/internal/platform-pr.ts +65 -27
- package/lib/internal/platform-release-notes.ts +8 -6
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +20 -11
- package/lib/internal/release-workflow.ts +21 -9
- package/lib/internal/sandbox-control.ts +44 -6
- package/lib/internal/task-activity.ts +15 -7
- package/lib/internal/task-artifact.ts +204 -22
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +78 -17
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +9 -4
- package/lib/internal/task-finalization.ts +6 -4
- package/lib/internal/task-invalidation.ts +41 -0
- package/lib/internal/task-ledger.ts +21 -8
- package/lib/internal/task-lifecycle.ts +5 -3
- package/lib/internal/task-operation-registry.ts +482 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +15 -9
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +6 -4
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +6 -2
- package/lib/internal/task-verify.ts +10 -7
- package/lib/internal/task-warning.ts +10 -4
- package/lib/platform/adapters.ts +3 -2
- package/lib/platform/change-request-git-evidence.ts +36 -9
- package/lib/platform/comment-safety.ts +250 -0
- package/lib/platform/completion-backfill.ts +9 -8
- package/lib/platform/context.ts +97 -134
- package/lib/platform/github-client.ts +2 -2
- package/lib/platform/github-provider.ts +1132 -0
- package/lib/platform/in-label-sync.ts +208 -0
- package/lib/platform/issue-comments.ts +255 -80
- 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 +639 -0
- package/lib/platform/pr-checks.ts +126 -106
- package/lib/platform/pr-review.ts +88 -85
- package/lib/platform/pr-summary.ts +581 -53
- package/lib/platform/provider-bridge.ts +82 -0
- package/lib/platform/provider-contract.ts +611 -0
- package/lib/platform/provider-loader.ts +307 -0
- package/lib/platform/provider-validation.ts +611 -0
- package/lib/platform/pull-request-metadata.ts +10 -7
- package/lib/platform/pull-requests.ts +781 -550
- package/lib/platform/release-notes.ts +76 -59
- package/lib/platform/releases.ts +77 -43
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/resource-identity.ts +121 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/task-identities.ts +40 -0
- package/lib/platform/types.ts +4 -2
- package/lib/platform/verification-required.ts +11 -13
- package/lib/platform/verification-sync.ts +128 -304
- package/lib/pr-review/evidence-grading.ts +25 -8
- package/lib/process-data/index.ts +7 -0
- package/lib/run/index.ts +62 -22
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +46 -6
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +1000 -87
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/client.ts +203 -19
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +180 -15
- package/lib/sandbox/control/lifecycle.ts +629 -17
- package/lib/sandbox/control/native-file-lock.ts +209 -0
- package/lib/sandbox/control/protocol.ts +118 -2
- package/lib/sandbox/control/server.ts +724 -34
- package/lib/sandbox/control/state.ts +257 -4
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +7 -0
- package/lib/sandbox/recovery.ts +21 -1
- package/lib/sandbox/workspace-view.ts +9 -3
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/server/protocol.ts +36 -1
- package/lib/task/activity-log.ts +8 -0
- package/lib/task/artifact-lifecycle.ts +70 -22
- package/lib/task/artifact-operations.ts +626 -0
- package/lib/task/artifact-repair-intent.ts +71 -0
- package/lib/task/artifact-schema.ts +192 -0
- package/lib/task/capabilities.ts +331 -0
- package/lib/task/commands/status.ts +38 -0
- package/lib/task/commit-operation.ts +12 -1
- package/lib/task/control-authority.ts +22 -9
- package/lib/task/create-service.ts +139 -14
- package/lib/task/create.ts +27 -0
- package/lib/task/current-contract.ts +6 -1
- package/lib/task/decision-details.ts +6 -2
- package/lib/task/events.ts +392 -16
- package/lib/task/finalization.ts +50 -14
- package/lib/task/human-override.ts +70 -46
- package/lib/task/index.ts +16 -3
- 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/local-artifact-finalization.ts +432 -0
- package/lib/task/orchestration.ts +223 -133
- package/lib/task/pr-delivery-fact.ts +131 -148
- package/lib/task/qualification-audit.ts +599 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -22
- package/lib/task/review-finalization.ts +133 -4
- package/lib/task/review-fingerprint.ts +23 -2
- package/lib/task/rework-intent.ts +165 -0
- package/lib/task/sections.ts +6 -4
- package/lib/task/skill-scope.ts +24 -0
- package/lib/task/task-execution-lock.ts +23 -14
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +103 -17
- 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 +1 -1
- package/lib/version.ts +15 -1
- package/package.json +12 -1
- package/templates/.agents/rules/README.en.md +3 -1
- package/templates/.agents/rules/README.zh-CN.md +3 -1
- package/templates/.agents/rules/decision-qualification.en.md +22 -0
- package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
- package/templates/.agents/rules/evidence-reporting.en.md +28 -0
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
- package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +2 -0
- package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
- package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
- package/templates/.agents/rules/pr-sync.en.md +10 -4
- package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
- package/templates/.agents/rules/security-alerts.en.md +8 -8
- package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
- 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/skills/analyze-task/SKILL.en.md +28 -5
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
- 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 +41 -9
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
- package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
- 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 +3 -3
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
- package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
- package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
- 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 +8 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -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 +8 -8
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
- package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
- package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
- package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
- package/templates/.agents/skills/test/SKILL.en.md +13 -2
- package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
- 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 +24 -1
- package/templates/.agents/templates/task.zh-CN.md +24 -1
- package/templates/.github/workflows/pr-label.yml +7 -26
- package/templates/.agents/scripts/security-alerts.github.sh +0 -151
- package/templates/.agents/scripts/security-alerts.sh +0 -31
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { CONSTRAINT_COLUMNS, CANDIDATE_COLUMNS, parseTaskQualification } from './qualification-audit.js';
|
|
3
|
+
import { resolveTaskRef } from './resolve-ref.js';
|
|
4
|
+
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
5
|
+
function failed(code, message, taskId = null) {
|
|
6
|
+
return { status: 'failed', changed: false, taskId, operations: [], error: { code, message } };
|
|
7
|
+
}
|
|
8
|
+
function validSingleLine(value) {
|
|
9
|
+
return typeof value === 'string' && Boolean(value.trim()) && !/[\r\n]/.test(value);
|
|
10
|
+
}
|
|
11
|
+
function assertProposalKeys(value, keys, label) {
|
|
12
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
13
|
+
throw new Error(`${label} must be an object`);
|
|
14
|
+
const record = value;
|
|
15
|
+
const unexpected = Object.keys(record).find((key) => !keys.includes(key));
|
|
16
|
+
if (unexpected)
|
|
17
|
+
throw new Error(`${label} does not accept '${unexpected}'`);
|
|
18
|
+
return record;
|
|
19
|
+
}
|
|
20
|
+
function parseConstraintProposal(value) {
|
|
21
|
+
const row = assertProposalKeys(value, ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'derivedFrom', 'approvalEvidence'], 'constraint proposal');
|
|
22
|
+
for (const key of ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'approvalEvidence']) {
|
|
23
|
+
if (typeof row[key] !== 'string' || /[\r\n]/.test(row[key]))
|
|
24
|
+
throw new Error(`constraint proposal '${key}' must be a single-line string`);
|
|
25
|
+
}
|
|
26
|
+
if (!/^C-[1-9]\d*$/.test(row.constraintId))
|
|
27
|
+
throw new Error(`constraint proposal id '${row.constraintId}' is invalid`);
|
|
28
|
+
if (row.status === 'confirmed' || !['derived', 'assumption', 'open', 'conflicted', 'superseded'].includes(row.status))
|
|
29
|
+
throw new Error('proposal cannot write confirmed constraint status');
|
|
30
|
+
if (row.approvalEvidence !== '')
|
|
31
|
+
throw new Error('proposal cannot write approval_evidence');
|
|
32
|
+
if (!Array.isArray(row.derivedFrom) || row.derivedFrom.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item)))
|
|
33
|
+
throw new Error('constraint proposal derivedFrom is invalid');
|
|
34
|
+
return {
|
|
35
|
+
constraintId: row.constraintId, statement: row.statement, status: row.status,
|
|
36
|
+
authority: row.authority, source: row.source, evidence: row.evidence,
|
|
37
|
+
derivedFrom: [...row.derivedFrom], approvalEvidence: ''
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parseCandidateProposal(value) {
|
|
41
|
+
const row = assertProposalKeys(value, ['candidateId', 'statement', 'status', 'constraintIds', 'impact', 'evidence'], 'candidate proposal');
|
|
42
|
+
for (const key of ['candidateId', 'statement', 'status', 'impact', 'evidence'])
|
|
43
|
+
if (!validSingleLine(row[key]))
|
|
44
|
+
throw new Error(`candidate proposal '${key}' must be a non-empty single-line string`);
|
|
45
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(row.candidateId))
|
|
46
|
+
throw new Error(`candidate proposal id '${row.candidateId}' is invalid`);
|
|
47
|
+
if (row.status !== 'pending')
|
|
48
|
+
throw new Error('proposal can only write pending candidate status');
|
|
49
|
+
if (!Array.isArray(row.constraintIds) || row.constraintIds.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item)))
|
|
50
|
+
throw new Error('candidate proposal constraintIds is invalid');
|
|
51
|
+
return row;
|
|
52
|
+
}
|
|
53
|
+
function proposalValues(request) {
|
|
54
|
+
if (!/^[a-f0-9]{64}$/i.test(request.expectedTaskInputDigest))
|
|
55
|
+
throw new Error('expectedTaskInputDigest must be a sha256 digest');
|
|
56
|
+
if (Object.keys(request).some((key) => !['taskRef', 'expectedTaskInputDigest', 'constraints', 'candidates', 'dryRun'].includes(key)))
|
|
57
|
+
throw new Error('proposal contains an unsupported field');
|
|
58
|
+
if (!Array.isArray(request.constraints) && request.constraints !== undefined)
|
|
59
|
+
throw new Error('constraints must be an array');
|
|
60
|
+
if (!Array.isArray(request.candidates) && request.candidates !== undefined)
|
|
61
|
+
throw new Error('candidates must be an array');
|
|
62
|
+
return {
|
|
63
|
+
constraints: (request.constraints ?? []).map(parseConstraintProposal),
|
|
64
|
+
candidates: (request.candidates ?? []).map(parseCandidateProposal)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function applyQualificationProposal(request, options = {}) {
|
|
68
|
+
if (!request || typeof request !== 'object' || !validSingleLine(request.taskRef))
|
|
69
|
+
return failed('QUALIFICATION_PROPOSAL_INVALID', 'taskRef is required');
|
|
70
|
+
let values;
|
|
71
|
+
try {
|
|
72
|
+
values = proposalValues(request);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return failed('QUALIFICATION_PROPOSAL_INVALID', error instanceof Error ? error.message : String(error));
|
|
76
|
+
}
|
|
77
|
+
if (values.constraints.length === 0 && values.candidates.length === 0)
|
|
78
|
+
return failed('QUALIFICATION_PROPOSAL_INVALID', 'proposal must contain a constraint or candidate');
|
|
79
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
80
|
+
if (!resolved.ok)
|
|
81
|
+
return failed(resolved.code, resolved.message, resolved.taskId);
|
|
82
|
+
if (resolved.state !== 'active')
|
|
83
|
+
return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
|
|
84
|
+
let content;
|
|
85
|
+
try {
|
|
86
|
+
content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
|
|
90
|
+
}
|
|
91
|
+
const parsed = parseTaskQualification(content);
|
|
92
|
+
if (!parsed.ok)
|
|
93
|
+
return failed(parsed.code, parsed.message, resolved.taskId);
|
|
94
|
+
if (!parsed.qualification.present)
|
|
95
|
+
return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
|
|
96
|
+
const currentConstraintMap = new Map(parsed.qualification.constraints.map((row) => [row.constraintId, row]));
|
|
97
|
+
const currentCandidateMap = new Map(parsed.qualification.candidates.map((row) => [row.candidateId, row]));
|
|
98
|
+
const proposalAlreadyApplied = values.constraints.every((row) => {
|
|
99
|
+
const current = currentConstraintMap.get(row.constraintId);
|
|
100
|
+
return current && current.statement === row.statement && current.status === row.status && current.authority === row.authority
|
|
101
|
+
&& current.source === row.source && current.evidence === row.evidence && current.derivedFrom.join(',') === row.derivedFrom.join(',') && current.approvalEvidence === '';
|
|
102
|
+
}) && values.candidates.every((row) => {
|
|
103
|
+
const current = currentCandidateMap.get(row.candidateId);
|
|
104
|
+
return current && current.statement === row.statement && current.status === row.status && current.constraintIds.join(',') === row.constraintIds.join(',')
|
|
105
|
+
&& current.impact === row.impact && current.evidence === row.evidence;
|
|
106
|
+
});
|
|
107
|
+
if (parsed.qualification.taskInputDigest !== request.expectedTaskInputDigest) {
|
|
108
|
+
return proposalAlreadyApplied
|
|
109
|
+
? { status: 'no-op', changed: false, taskId: resolved.taskId, operations: [], error: null }
|
|
110
|
+
: failed('QUALIFICATION_DIGEST_CONFLICT', 'task qualification input changed before proposal was applied', resolved.taskId);
|
|
111
|
+
}
|
|
112
|
+
for (const row of values.constraints) {
|
|
113
|
+
const current = currentConstraintMap.get(row.constraintId);
|
|
114
|
+
if (current?.status === 'confirmed')
|
|
115
|
+
return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `confirmed constraint '${row.constraintId}' must be superseded or revoked through task-qualification`, resolved.taskId);
|
|
116
|
+
}
|
|
117
|
+
const knownConstraintIds = new Set([...parsed.qualification.constraints.map((row) => row.constraintId), ...values.constraints.map((row) => row.constraintId)]);
|
|
118
|
+
for (const row of values.constraints)
|
|
119
|
+
for (const parent of row.derivedFrom)
|
|
120
|
+
if (!knownConstraintIds.has(parent))
|
|
121
|
+
return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `constraint proposal '${row.constraintId}' references unknown '${parent}'`, resolved.taskId);
|
|
122
|
+
for (const row of values.candidates)
|
|
123
|
+
for (const id of row.constraintIds)
|
|
124
|
+
if (!knownConstraintIds.has(id))
|
|
125
|
+
return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `candidate proposal '${row.candidateId}' references unknown '${id}'`, resolved.taskId);
|
|
126
|
+
const mutations = [];
|
|
127
|
+
for (const row of values.constraints) {
|
|
128
|
+
mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: CONSTRAINT_COLUMNS, keyColumn: 'constraint_id', key: row.constraintId, values: { statement: row.statement, status: row.status, authority: row.authority, source: row.source, evidence: row.evidence, derived_from: row.derivedFrom.join(','), approval_evidence: '' } });
|
|
129
|
+
}
|
|
130
|
+
for (const row of values.candidates) {
|
|
131
|
+
mutations.push({ kind: 'table-row', action: 'upsert', sectionAliases: ['候选与否决方案', 'Candidate and Rejected Options', 'Candidates and Rejected Options', 'Candidates and Rejected Alternatives'], columns: CANDIDATE_COLUMNS, keyColumn: 'candidate_id', key: row.candidateId, values: { statement: row.statement, status: row.status, constraint_ids: row.constraintIds.join(','), impact: row.impact, evidence: row.evidence } });
|
|
132
|
+
}
|
|
133
|
+
// Only the submitted rows are mutated; no actor, confirmation, or QCR fields
|
|
134
|
+
// can be smuggled into this internal proposal operation.
|
|
135
|
+
let metadata;
|
|
136
|
+
try {
|
|
137
|
+
metadata = (options.metadataProvider ?? captureTaskWriteMetadata)();
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
|
|
141
|
+
}
|
|
142
|
+
const result = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state }, metadataProvider: () => metadata });
|
|
143
|
+
if (result.status === 'failed')
|
|
144
|
+
return failed(result.error.code, result.error.message, result.taskId);
|
|
145
|
+
return { status: result.status, changed: result.changed, taskId: result.taskId, operations: result.operations, error: null };
|
|
146
|
+
}
|
|
147
|
+
export { applyQualificationProposal };
|
|
148
|
+
//# sourceMappingURL=qualification-intents.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { scanVisibleMarkdown } from './decision-details.js';
|
|
3
4
|
const SUMMARY_HEADINGS = new Set(['审查摘要', 'Review Summary']);
|
|
4
5
|
const PLACEHOLDERS = [
|
|
5
6
|
'{unresolved-blockers}',
|
|
@@ -36,42 +37,40 @@ function normalizeVerdict(raw) {
|
|
|
36
37
|
return '';
|
|
37
38
|
}
|
|
38
39
|
function extractSection(content, names) {
|
|
39
|
-
const lines = content.split(/\r?\n/);
|
|
40
40
|
const nameSet = new Set(names);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
if (start === -1)
|
|
41
|
+
const scanned = scanVisibleMarkdown(content);
|
|
42
|
+
const heading = scanned.headings.find((item) => item.level === 2 && nameSet.has(item.text));
|
|
43
|
+
if (!heading)
|
|
46
44
|
return '';
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (/^##\s+/.test(lines[index]))
|
|
50
|
-
break;
|
|
51
|
-
sectionLines.push(lines[index]);
|
|
52
|
-
}
|
|
53
|
-
return sectionLines.join('\n');
|
|
45
|
+
const next = scanned.headings.find((item) => item.start > heading.start && item.level <= 2);
|
|
46
|
+
return content.slice(heading.end, next?.start ?? content.length);
|
|
54
47
|
}
|
|
55
48
|
function summaryBounds(content) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
|
|
49
|
+
const scanned = scanVisibleMarkdown(content);
|
|
50
|
+
const summaries = scanned.headings.filter((heading) => heading.level === 2 && SUMMARY_HEADINGS.has(heading.text));
|
|
59
51
|
if (summaries.length !== 1)
|
|
60
52
|
return null;
|
|
61
53
|
const summary = summaries[0];
|
|
62
|
-
const next = headings.find((heading) => heading.
|
|
63
|
-
return { start: summary.end, end: next?.
|
|
54
|
+
const next = scanned.headings.find((heading) => heading.start > summary.start && heading.level <= 2);
|
|
55
|
+
return { start: summary.end, end: next?.start ?? content.length };
|
|
64
56
|
}
|
|
65
57
|
function uniqueLine(content, bounds, pattern) {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
58
|
+
const matches = [];
|
|
59
|
+
for (const line of scanVisibleMarkdown(content).lines) {
|
|
60
|
+
if (line.start < bounds.start || line.start >= bounds.end)
|
|
61
|
+
continue;
|
|
62
|
+
pattern.lastIndex = 0;
|
|
63
|
+
const match = pattern.exec(line.text);
|
|
64
|
+
if (match)
|
|
65
|
+
matches.push({ value: match[1], index: line.start + match.index, length: match[0].length });
|
|
66
|
+
}
|
|
68
67
|
if (matches.length !== 1)
|
|
69
68
|
return null;
|
|
70
69
|
const match = matches[0];
|
|
71
70
|
return {
|
|
72
|
-
value: match
|
|
73
|
-
start:
|
|
74
|
-
end:
|
|
71
|
+
value: match.value,
|
|
72
|
+
start: match.index,
|
|
73
|
+
end: match.index + match.length
|
|
75
74
|
};
|
|
76
75
|
}
|
|
77
76
|
function parseCounts(value) {
|
|
@@ -10,6 +10,9 @@ import { resolveTaskRef } from './resolve-ref.js';
|
|
|
10
10
|
import { validateLifecycleExecution } from './lifecycle-execution.js';
|
|
11
11
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
12
12
|
import { allowsManualOverride } from './guard-override.js';
|
|
13
|
+
import { getArtifactSchema } from './artifact-schema.js';
|
|
14
|
+
import { canonicalSemanticDigest, inspectArtifactContract, sha256Content } from './artifact-operations.js';
|
|
15
|
+
import { readArtifactRepairIntent, writeArtifactRepairIntent } from './artifact-repair-intent.js';
|
|
13
16
|
const STAGES = {
|
|
14
17
|
analysis: { family: 'review-analysis', action: 'Review Analysis' },
|
|
15
18
|
plan: { family: 'review-plan', action: 'Review Plan' },
|
|
@@ -22,7 +25,7 @@ const DEFAULT_FILE_SYSTEM = {
|
|
|
22
25
|
renameSync: (from, to) => fs.renameSync(from, to),
|
|
23
26
|
unlinkSync: (file) => fs.unlinkSync(file)
|
|
24
27
|
};
|
|
25
|
-
function failed(request, code, message, taskId = null, stageStatus = null) {
|
|
28
|
+
function failed(request, code, message, taskId = null, stageStatus = null, extra = {}) {
|
|
26
29
|
return {
|
|
27
30
|
status: 'failed',
|
|
28
31
|
changed: false,
|
|
@@ -32,8 +35,13 @@ function failed(request, code, message, taskId = null, stageStatus = null) {
|
|
|
32
35
|
stage: request.stage,
|
|
33
36
|
artifact: request.artifact,
|
|
34
37
|
stageStatus,
|
|
38
|
+
artifactSha256: null,
|
|
39
|
+
semanticDigest: null,
|
|
40
|
+
repairable: false,
|
|
41
|
+
operation: null,
|
|
35
42
|
operations: [],
|
|
36
|
-
error: { code, message }
|
|
43
|
+
error: { code, message },
|
|
44
|
+
...extra
|
|
37
45
|
};
|
|
38
46
|
}
|
|
39
47
|
function openReviewRound(content, action, round) {
|
|
@@ -86,6 +94,73 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
86
94
|
catch (error) {
|
|
87
95
|
return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
|
|
88
96
|
}
|
|
97
|
+
const schema = getArtifactSchema(spec.family);
|
|
98
|
+
const structure = schema ? inspectArtifactContract(artifactContent, schema) : null;
|
|
99
|
+
const artifactSha256 = sha256Content(artifactContent);
|
|
100
|
+
const artifactSemanticDigest = canonicalSemanticDigest(artifactContent);
|
|
101
|
+
let repairIntent;
|
|
102
|
+
try {
|
|
103
|
+
repairIntent = readArtifactRepairIntent(resolved.repoRoot, resolved.taskId, spec.family, request.artifact);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', String(error), resolved.taskId, null, {
|
|
107
|
+
artifactSha256,
|
|
108
|
+
semanticDigest: artifactSemanticDigest
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (structure && !structure.ok) {
|
|
112
|
+
const repairable = structure.repair !== null && structure.diagnostics.length === 1 && structure.diagnostics[0]?.repairable === true;
|
|
113
|
+
if (repairable) {
|
|
114
|
+
if (repairIntent && (repairIntent.state !== 'awaiting-repair' ||
|
|
115
|
+
repairIntent.artifactSha256 !== artifactSha256 ||
|
|
116
|
+
repairIntent.semanticDigest !== structure.semanticDigest)) {
|
|
117
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', 'a different review repair baseline is already recorded for this artifact', resolved.taskId, null, {
|
|
118
|
+
artifactSha256,
|
|
119
|
+
semanticDigest: structure.semanticDigest
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
if (!repairIntent) {
|
|
124
|
+
writeArtifactRepairIntent(resolved.repoRoot, {
|
|
125
|
+
version: 1,
|
|
126
|
+
taskId: resolved.taskId,
|
|
127
|
+
family: spec.family,
|
|
128
|
+
artifact: request.artifact,
|
|
129
|
+
state: 'awaiting-repair',
|
|
130
|
+
baselineSemanticDigest: structure.semanticDigest,
|
|
131
|
+
artifactSha256,
|
|
132
|
+
semanticDigest: structure.semanticDigest
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', `cannot record repair provenance: ${String(error)}`, resolved.taskId, null, {
|
|
138
|
+
artifactSha256,
|
|
139
|
+
semanticDigest: structure.semanticDigest,
|
|
140
|
+
operation: structure.repair
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return failed(request, 'REVIEW_ARTIFACT_STRUCTURE_INVALID', structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; '), resolved.taskId, null, {
|
|
145
|
+
artifactSha256,
|
|
146
|
+
semanticDigest: structure.semanticDigest,
|
|
147
|
+
repairable,
|
|
148
|
+
operation: structure.repair
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (repairIntent?.state === 'awaiting-repair' && repairIntent.baselineSemanticDigest !== artifactSemanticDigest) {
|
|
152
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', 'the repaired review artifact semantic digest does not match the recorded repair baseline', resolved.taskId, null, {
|
|
153
|
+
artifactSha256,
|
|
154
|
+
semanticDigest: artifactSemanticDigest
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if ((repairIntent?.state === 'passed' || repairIntent?.state === 'consumed')
|
|
158
|
+
&& (repairIntent.artifactSha256 !== artifactSha256 || repairIntent.semanticDigest !== artifactSemanticDigest)) {
|
|
159
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', 'the review artifact changed after its finalization provenance was recorded', resolved.taskId, null, {
|
|
160
|
+
artifactSha256,
|
|
161
|
+
semanticDigest: artifactSemanticDigest
|
|
162
|
+
});
|
|
163
|
+
}
|
|
89
164
|
if (!openReviewRound(taskContent, spec.action, parsedArtifact.round)) {
|
|
90
165
|
return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`, resolved.taskId);
|
|
91
166
|
}
|
|
@@ -127,8 +202,27 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
127
202
|
return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
|
|
128
203
|
}
|
|
129
204
|
if (!transformed.changed) {
|
|
205
|
+
if (repairIntent?.state === 'awaiting-repair') {
|
|
206
|
+
try {
|
|
207
|
+
writeArtifactRepairIntent(resolved.repoRoot, {
|
|
208
|
+
...repairIntent,
|
|
209
|
+
state: 'passed',
|
|
210
|
+
artifactSha256,
|
|
211
|
+
semanticDigest: artifactSemanticDigest
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', `cannot record repaired review provenance: ${String(error)}`, resolved.taskId, stageStatus, {
|
|
216
|
+
artifactSha256,
|
|
217
|
+
semanticDigest: artifactSemanticDigest
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
130
221
|
return {
|
|
131
|
-
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus
|
|
222
|
+
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus, {
|
|
223
|
+
artifactSha256,
|
|
224
|
+
semanticDigest: artifactSemanticDigest
|
|
225
|
+
}),
|
|
132
226
|
status: 'no-op',
|
|
133
227
|
error: null
|
|
134
228
|
};
|
|
@@ -136,7 +230,10 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
136
230
|
const operations = [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }];
|
|
137
231
|
if (request.dryRun) {
|
|
138
232
|
return {
|
|
139
|
-
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus
|
|
233
|
+
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus, {
|
|
234
|
+
artifactSha256: sha256Content(transformed.content),
|
|
235
|
+
semanticDigest: canonicalSemanticDigest(transformed.content)
|
|
236
|
+
}),
|
|
140
237
|
status: 'planned',
|
|
141
238
|
changed: true,
|
|
142
239
|
operations,
|
|
@@ -164,6 +261,22 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
164
261
|
cleanupTemp(fileSystem, tempPath);
|
|
165
262
|
return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, stageStatus);
|
|
166
263
|
}
|
|
264
|
+
if (repairIntent?.state === 'awaiting-repair') {
|
|
265
|
+
try {
|
|
266
|
+
writeArtifactRepairIntent(resolved.repoRoot, {
|
|
267
|
+
...repairIntent,
|
|
268
|
+
state: 'passed',
|
|
269
|
+
artifactSha256: sha256Content(transformed.content),
|
|
270
|
+
semanticDigest: canonicalSemanticDigest(transformed.content)
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
return failed(request, 'REVIEW_PROVENANCE_INVALID', `cannot record repaired review provenance: ${String(error)}`, resolved.taskId, stageStatus, {
|
|
275
|
+
artifactSha256: sha256Content(transformed.content),
|
|
276
|
+
semanticDigest: canonicalSemanticDigest(transformed.content)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
167
280
|
return {
|
|
168
281
|
status: 'applied',
|
|
169
282
|
changed: true,
|
|
@@ -173,6 +286,10 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
173
286
|
stage,
|
|
174
287
|
artifact: request.artifact,
|
|
175
288
|
stageStatus,
|
|
289
|
+
artifactSha256: sha256Content(transformed.content),
|
|
290
|
+
semanticDigest: canonicalSemanticDigest(transformed.content),
|
|
291
|
+
repairable: false,
|
|
292
|
+
operation: null,
|
|
176
293
|
operations,
|
|
177
294
|
error: null
|
|
178
295
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { artifactName, maxRound } from "./review-artifacts.js";
|
|
4
|
+
import { invalidationBlocks, isArtifactInvalidated, parseInvalidationDocument } from "./invalidation.js";
|
|
4
5
|
const REVIEWED_TREE_RE = /^[a-f0-9]{40,64}$/;
|
|
5
6
|
export function parseReviewedGitTree(value) {
|
|
6
7
|
return REVIEWED_TREE_RE.test(value) ? value : null;
|
|
@@ -30,14 +31,35 @@ export function findAuthoritativeReviewCodeArtifact(taskDir) {
|
|
|
30
31
|
const entries = fs.existsSync(taskDir) ? fs.readdirSync(taskDir) : [];
|
|
31
32
|
const round = maxRound(entries, "review-code");
|
|
32
33
|
if (round === 0) {
|
|
33
|
-
return { ok: false, round: 0, fileName: null, path: null };
|
|
34
|
+
return { ok: false, round: 0, fileName: null, path: null, error: null };
|
|
34
35
|
}
|
|
35
36
|
const fileName = artifactName("review-code", round);
|
|
37
|
+
let taskContent;
|
|
38
|
+
try {
|
|
39
|
+
taskContent = fs.readFileSync(path.join(taskDir, "task.md"), "utf8");
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false, round, fileName, path: null,
|
|
44
|
+
error: error instanceof Error ? error.message : String(error)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const invalidation = parseInvalidationDocument(taskContent);
|
|
48
|
+
if (!invalidation.ok) {
|
|
49
|
+
return { ok: false, round, fileName, path: null, error: invalidation.message };
|
|
50
|
+
}
|
|
51
|
+
if (invalidationBlocks(invalidation.document)) {
|
|
52
|
+
return { ok: false, round, fileName, path: null, error: "artifact invalidation is incomplete; reconcile task.md before using review-code" };
|
|
53
|
+
}
|
|
54
|
+
if (isArtifactInvalidated(invalidation.document, "review-code", fileName)) {
|
|
55
|
+
return { ok: false, round, fileName, path: null, error: `${fileName} is invalidated; re-run review-code` };
|
|
56
|
+
}
|
|
36
57
|
return {
|
|
37
58
|
ok: true,
|
|
38
59
|
round,
|
|
39
60
|
fileName,
|
|
40
|
-
path: path.join(taskDir, fileName)
|
|
61
|
+
path: path.join(taskDir, fileName),
|
|
62
|
+
error: null
|
|
41
63
|
};
|
|
42
64
|
}
|
|
43
65
|
export function extractReviewBaseline(content) {
|
|
@@ -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
|
|
@@ -99,17 +99,19 @@ function matchingSections(content, aliases) {
|
|
|
99
99
|
const allowed = new Set(aliases);
|
|
100
100
|
return linesOf(content)
|
|
101
101
|
.map((line, index, lines) => {
|
|
102
|
-
const match =
|
|
103
|
-
if (!match?.[
|
|
102
|
+
const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line.text);
|
|
103
|
+
if (!match?.[2] || !allowed.has(match[2]))
|
|
104
104
|
return null;
|
|
105
|
+
const level = match[1].length;
|
|
105
106
|
let end = content.length;
|
|
106
107
|
for (let i = index + 1; i < lines.length; i += 1) {
|
|
107
|
-
|
|
108
|
+
const nextHeading = /^(#{2,3})\s+/.exec(lines[i].text);
|
|
109
|
+
if (nextHeading && nextHeading[1].length <= level) {
|
|
108
110
|
end = lines[i].start;
|
|
109
111
|
break;
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
|
-
return { heading: match[
|
|
114
|
+
return { heading: match[2], line, bodyStart: line.end, end };
|
|
113
115
|
})
|
|
114
116
|
.filter((match) => match !== null);
|
|
115
117
|
}
|
|
@@ -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
|