@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,165 @@
|
|
|
1
|
+
const REWORK_INTENT_HEADINGS = ['返工意图', 'Rework Intent'] as const;
|
|
2
|
+
const REWORK_INTENT_COLUMNS = [
|
|
3
|
+
'intent_id', 'finding_id', 'source_artifact', 'source_sha256', 'target',
|
|
4
|
+
'status', 'declared_at', 'consumed_at'
|
|
5
|
+
] as const;
|
|
6
|
+
type ReworkTarget = 'analysis' | 'plan' | 'code';
|
|
7
|
+
type ReworkIntentStatus = 'pending' | 'consumed' | 'superseded';
|
|
8
|
+
type ReworkIntent = {
|
|
9
|
+
intentId: string;
|
|
10
|
+
findingId: string;
|
|
11
|
+
sourceArtifact: string;
|
|
12
|
+
sourceSha256: string;
|
|
13
|
+
target: ReworkTarget;
|
|
14
|
+
status: ReworkIntentStatus;
|
|
15
|
+
declaredAt: string;
|
|
16
|
+
consumedAt: string;
|
|
17
|
+
};
|
|
18
|
+
type ReworkIntentParseResult =
|
|
19
|
+
| { ok: true; present: boolean; intents: readonly ReworkIntent[] }
|
|
20
|
+
| { ok: false; code: 'TASK_REWORK_INTENT_INVALID'; message: string };
|
|
21
|
+
|
|
22
|
+
function cells(line: string): string[] | null {
|
|
23
|
+
const first = line.indexOf('|');
|
|
24
|
+
const last = line.lastIndexOf('|');
|
|
25
|
+
if (first < 0 || first === last || line.slice(0, first).trim() || line.slice(last + 1).trim()) return null;
|
|
26
|
+
const inner = line.slice(first + 1, last);
|
|
27
|
+
const result: string[] = [];
|
|
28
|
+
let start = 0;
|
|
29
|
+
let escaped = false;
|
|
30
|
+
for (let index = 0; index < inner.length; index += 1) {
|
|
31
|
+
const char = inner[index]!;
|
|
32
|
+
if (char === '|' && !escaped) {
|
|
33
|
+
result.push(inner.slice(start, index));
|
|
34
|
+
start = index + 1;
|
|
35
|
+
}
|
|
36
|
+
escaped = char === '\\' && !escaped;
|
|
37
|
+
if (char !== '\\') escaped = false;
|
|
38
|
+
}
|
|
39
|
+
result.push(inner.slice(start));
|
|
40
|
+
return result.map((cell) => cell.replace(/\\([\\|])/g, '$1').trim());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sectionBody(content: string): string | null {
|
|
44
|
+
const heading = REWORK_INTENT_HEADINGS.map((value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
45
|
+
const match = new RegExp(`^##\\s+(${heading})\\s*$`, 'm').exec(content);
|
|
46
|
+
if (!match) return null;
|
|
47
|
+
const start = (match.index ?? 0) + match[0].length;
|
|
48
|
+
const rest = content.slice(start);
|
|
49
|
+
const end = rest.search(/^##\s+/m);
|
|
50
|
+
return rest.slice(0, end < 0 ? rest.length : end);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseReworkIntentDocument(content: string): ReworkIntentParseResult {
|
|
54
|
+
const body = sectionBody(content);
|
|
55
|
+
if (body === null) return { ok: true, present: false, intents: [] };
|
|
56
|
+
const lines = body.split(/\r?\n/).filter((line) => line.trim());
|
|
57
|
+
const header = lines[0] ? cells(lines[0]) : null;
|
|
58
|
+
const separator = lines[1] ? cells(lines[1]) : null;
|
|
59
|
+
if (!header || !separator || header.length !== REWORK_INTENT_COLUMNS.length || !header.every((value, index) => value === REWORK_INTENT_COLUMNS[index]) || !separator.every((value) => /^:?-{3,}:?$/.test(value))) {
|
|
60
|
+
return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: 'rework intent section must contain its canonical table' };
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const intents = lines.slice(2).map((line) => {
|
|
64
|
+
const values = cells(line);
|
|
65
|
+
if (!values || values.length !== REWORK_INTENT_COLUMNS.length) throw new Error('rework intent row has the wrong column count');
|
|
66
|
+
const row = Object.fromEntries(REWORK_INTENT_COLUMNS.map((column, index) => [column, values[index]!])) as Record<string, string>;
|
|
67
|
+
if (!/^RI-[1-9]\d*$/.test(row.intent_id!)) throw new Error(`invalid intent id '${row.intent_id}'`);
|
|
68
|
+
if (!/^(AN|PL|CD)-[1-9]\d*$/.test(row.finding_id!)) throw new Error(`invalid finding id '${row.finding_id}'`);
|
|
69
|
+
if (!['analysis', 'plan', 'code'].includes(row.target!)) throw new Error(`invalid rework target '${row.target}'`);
|
|
70
|
+
if (!['pending', 'consumed', 'superseded'].includes(row.status!)) throw new Error(`invalid rework status '${row.status}'`);
|
|
71
|
+
if (!/^[a-f0-9]{64}$/.test(row.source_sha256!)) throw new Error(`invalid source hash for '${row.intent_id}'`);
|
|
72
|
+
if (!row.source_artifact || !row.declared_at) throw new Error(`rework intent '${row.intent_id}' has invalid required fields`);
|
|
73
|
+
const terminal = row.status === 'consumed' || row.status === 'superseded';
|
|
74
|
+
if (terminal !== Boolean(row.consumed_at)) throw new Error(`rework intent '${row.intent_id}' has invalid consumed_at`);
|
|
75
|
+
return {
|
|
76
|
+
intentId: row.intent_id!, findingId: row.finding_id!, sourceArtifact: row.source_artifact!,
|
|
77
|
+
sourceSha256: row.source_sha256!, target: row.target as ReworkTarget,
|
|
78
|
+
status: row.status as ReworkIntentStatus, declaredAt: row.declared_at!, consumedAt: row.consumed_at!
|
|
79
|
+
} satisfies ReworkIntent;
|
|
80
|
+
});
|
|
81
|
+
const ids = new Set<string>();
|
|
82
|
+
for (const intent of intents) {
|
|
83
|
+
if (ids.has(intent.intentId)) throw new Error(`duplicate intent '${intent.intentId}'`);
|
|
84
|
+
ids.add(intent.intentId);
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, present: true, intents };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return { ok: false, code: 'TASK_REWORK_INTENT_INVALID', message: error instanceof Error ? error.message : String(error) };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function renderReworkIntents(intents: readonly ReworkIntent[]): string {
|
|
93
|
+
const escape = (value: string) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' ');
|
|
94
|
+
return [
|
|
95
|
+
`| ${REWORK_INTENT_COLUMNS.join(' | ')} |`,
|
|
96
|
+
`| ${REWORK_INTENT_COLUMNS.map(() => '---').join(' | ')} |`,
|
|
97
|
+
...intents.map((intent) => `| ${[
|
|
98
|
+
intent.intentId, intent.findingId, intent.sourceArtifact, intent.sourceSha256,
|
|
99
|
+
intent.target, intent.status, intent.declaredAt, intent.consumedAt
|
|
100
|
+
].map(escape).join(' | ')} |`)
|
|
101
|
+
].join('\n');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function upsertReworkIntent(intents: readonly ReworkIntent[], intent: ReworkIntent): { changed: boolean; intents: readonly ReworkIntent[] } {
|
|
105
|
+
const existing = intents.find((candidate) => candidate.intentId === intent.intentId);
|
|
106
|
+
if (!existing) return { changed: true, intents: [...intents, intent] };
|
|
107
|
+
const identity = (value: ReworkIntent) => [value.intentId, value.findingId, value.sourceArtifact, value.sourceSha256, value.target];
|
|
108
|
+
if (JSON.stringify(identity(existing)) !== JSON.stringify(identity(intent))) throw new Error(`intent '${intent.intentId}' identity conflicts with existing state`);
|
|
109
|
+
return { changed: false, intents };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function consumeReworkIntents(
|
|
113
|
+
intents: readonly ReworkIntent[],
|
|
114
|
+
target: ReworkTarget,
|
|
115
|
+
sourceHashes: Readonly<Record<string, string>>,
|
|
116
|
+
consumedAt: string
|
|
117
|
+
): { changed: boolean; intents: readonly ReworkIntent[] } {
|
|
118
|
+
let changed = false;
|
|
119
|
+
const next = intents.map((intent) => {
|
|
120
|
+
if (
|
|
121
|
+
intent.status !== 'pending'
|
|
122
|
+
|| intent.target !== target
|
|
123
|
+
|| sourceHashes[intent.sourceArtifact] !== intent.sourceSha256
|
|
124
|
+
) return intent;
|
|
125
|
+
changed = true;
|
|
126
|
+
return { ...intent, status: 'consumed' as const, consumedAt };
|
|
127
|
+
});
|
|
128
|
+
return { changed, intents: next };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function supersedeReworkIntents(
|
|
132
|
+
intents: readonly ReworkIntent[],
|
|
133
|
+
sourceArtifact: string,
|
|
134
|
+
sourceSha256: string,
|
|
135
|
+
supersededAt: string
|
|
136
|
+
): { changed: boolean; intents: readonly ReworkIntent[] } {
|
|
137
|
+
let changed = false;
|
|
138
|
+
const next = intents.map((intent) => {
|
|
139
|
+
if (intent.status !== 'pending' || intent.sourceArtifact !== sourceArtifact || intent.sourceSha256 === sourceSha256) return intent;
|
|
140
|
+
changed = true;
|
|
141
|
+
return { ...intent, status: 'superseded' as const, consumedAt: supersededAt };
|
|
142
|
+
});
|
|
143
|
+
return { changed, intents: next };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function reworkIntentMutation(content: string, intents: readonly ReworkIntent[]) {
|
|
147
|
+
return {
|
|
148
|
+
kind: 'section' as const,
|
|
149
|
+
aliases: REWORK_INTENT_HEADINGS,
|
|
150
|
+
heading: /^##\s+Rework Intent\s*$/m.test(content) ? REWORK_INTENT_HEADINGS[1] : REWORK_INTENT_HEADINGS[0],
|
|
151
|
+
body: renderReworkIntents(intents)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
REWORK_INTENT_COLUMNS,
|
|
157
|
+
REWORK_INTENT_HEADINGS,
|
|
158
|
+
parseReworkIntentDocument,
|
|
159
|
+
renderReworkIntents,
|
|
160
|
+
reworkIntentMutation,
|
|
161
|
+
consumeReworkIntents,
|
|
162
|
+
supersedeReworkIntents,
|
|
163
|
+
upsertReworkIntent
|
|
164
|
+
};
|
|
165
|
+
export type { ReworkIntent, ReworkIntentParseResult, ReworkIntentStatus, ReworkTarget };
|
package/lib/task/sections.ts
CHANGED
|
@@ -175,16 +175,18 @@ function matchingSections(content: string, aliases: readonly string[]) {
|
|
|
175
175
|
const allowed = new Set(aliases);
|
|
176
176
|
return linesOf(content)
|
|
177
177
|
.map((line, index, lines) => {
|
|
178
|
-
const match =
|
|
179
|
-
if (!match?.[
|
|
178
|
+
const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line.text);
|
|
179
|
+
if (!match?.[2] || !allowed.has(match[2])) return null;
|
|
180
|
+
const level = match[1]!.length;
|
|
180
181
|
let end = content.length;
|
|
181
182
|
for (let i = index + 1; i < lines.length; i += 1) {
|
|
182
|
-
|
|
183
|
+
const nextHeading = /^(#{2,3})\s+/.exec(lines[i]!.text);
|
|
184
|
+
if (nextHeading && nextHeading[1]!.length <= level) {
|
|
183
185
|
end = lines[i]!.start;
|
|
184
186
|
break;
|
|
185
187
|
}
|
|
186
188
|
}
|
|
187
|
-
return { heading: match[
|
|
189
|
+
return { heading: match[2]!, line, bodyStart: line.end, end };
|
|
188
190
|
})
|
|
189
191
|
.filter((match): match is NonNullable<typeof match> => match !== null);
|
|
190
192
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const TASK_SCOPE_SKILLS: ReadonlySet<string> = 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
|
+
|
|
20
|
+
function isTaskScopeSkill(skillName: string): boolean {
|
|
21
|
+
return TASK_SCOPE_SKILLS.has(skillName);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { TASK_SCOPE_SKILLS, isTaskScopeSkill };
|
|
@@ -224,6 +224,22 @@ function withTaskExecutionLock<T>(
|
|
|
224
224
|
};
|
|
225
225
|
const serialized = `${JSON.stringify(owner)}\n`;
|
|
226
226
|
let ownsFixed = false;
|
|
227
|
+
let deferRelease = false;
|
|
228
|
+
const release = (): void => {
|
|
229
|
+
try {
|
|
230
|
+
unlinkIfPresent(candidate);
|
|
231
|
+
} catch {
|
|
232
|
+
// Candidate cleanup is best-effort and must not replace the primary result.
|
|
233
|
+
}
|
|
234
|
+
if (ownsFixed) {
|
|
235
|
+
try {
|
|
236
|
+
const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
|
|
237
|
+
if (current.token === token) unlinkIfPresent(fixed);
|
|
238
|
+
} catch {
|
|
239
|
+
// A missing or replaced fixed lock is not owned by this invocation.
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
227
243
|
try {
|
|
228
244
|
fs.mkdirSync(lockRoot, { recursive: true });
|
|
229
245
|
cleanStaleCandidates(lockRoot, key, options.identityMatches ?? processIdentityMatches);
|
|
@@ -269,7 +285,12 @@ function withTaskExecutionLock<T>(
|
|
|
269
285
|
);
|
|
270
286
|
}
|
|
271
287
|
unlinkIfPresent(candidate);
|
|
272
|
-
|
|
288
|
+
const value = callback();
|
|
289
|
+
if (value && typeof (value as { then?: unknown }).then === 'function') {
|
|
290
|
+
deferRelease = true;
|
|
291
|
+
return (value as unknown as Promise<unknown>).finally(release) as T;
|
|
292
|
+
}
|
|
293
|
+
return value;
|
|
273
294
|
} catch (error) {
|
|
274
295
|
if (error instanceof TaskExecutionLockError) throw error;
|
|
275
296
|
if (error instanceof Error && error.name === 'OrchestrationStateError') throw error;
|
|
@@ -279,19 +300,7 @@ function withTaskExecutionLock<T>(
|
|
|
279
300
|
{ operation: ownsFixed ? 'callback' : 'acquire', errno: errno(error), key }
|
|
280
301
|
);
|
|
281
302
|
} finally {
|
|
282
|
-
|
|
283
|
-
unlinkIfPresent(candidate);
|
|
284
|
-
} catch {
|
|
285
|
-
// Candidate cleanup is best-effort and must not replace the primary result.
|
|
286
|
-
}
|
|
287
|
-
if (ownsFixed) {
|
|
288
|
-
try {
|
|
289
|
-
const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
|
|
290
|
-
if (current.token === token) unlinkIfPresent(fixed);
|
|
291
|
-
} catch {
|
|
292
|
-
// A missing or replaced fixed lock is not owned by this invocation.
|
|
293
|
-
}
|
|
294
|
-
}
|
|
303
|
+
if (!deferRelease) release();
|
|
295
304
|
}
|
|
296
305
|
}
|
|
297
306
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
import { getArtifactSchema } from './artifact-schema.ts';
|
|
5
|
+
|
|
4
6
|
type VerificationConfig = {
|
|
5
7
|
skill?: string;
|
|
6
8
|
checks: Record<string, Record<string, unknown> | null>;
|
|
@@ -13,6 +15,16 @@ function loadVerificationConfig(repositoryRoot: string, skillName: string): Veri
|
|
|
13
15
|
if (!parsed.checks || typeof parsed.checks !== 'object' || Array.isArray(parsed.checks)) {
|
|
14
16
|
throw new Error(`config/verify.json has invalid checks for skill '${skillName}'`);
|
|
15
17
|
}
|
|
18
|
+
const artifact = parsed.checks.artifact;
|
|
19
|
+
if (artifact && typeof artifact === 'object' && !Array.isArray(artifact)) {
|
|
20
|
+
const schema = artifact.schema;
|
|
21
|
+
if (schema !== undefined && (typeof schema !== 'string' || !getArtifactSchema(schema))) {
|
|
22
|
+
throw new Error(`config/verify.json has unknown artifact schema '${String(schema)}' for skill '${skillName}'`);
|
|
23
|
+
}
|
|
24
|
+
if (schema !== undefined && 'required_patterns' in artifact) {
|
|
25
|
+
throw new Error(`config/verify.json must not duplicate required_patterns for schema '${String(schema)}' in skill '${skillName}'`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
16
28
|
return { ...(parsed.skill ? { skill: parsed.skill } : {}), checks: parsed.checks };
|
|
17
29
|
}
|
|
18
30
|
|
|
@@ -34,6 +34,10 @@ import { snapshotReview } from "../git/review-snapshot.ts";
|
|
|
34
34
|
import { OrchestrationStateError, readRun } from "./orchestration.ts";
|
|
35
35
|
import { resolveDeliveryTarget } from "./delivery-target.ts";
|
|
36
36
|
import { readPrDeliveryFact } from "./pr-delivery-fact.ts";
|
|
37
|
+
import { validateLocalArtifact } from "./local-artifact-finalization.ts";
|
|
38
|
+
import { validateQualificationAudit } from "./qualification-audit.ts";
|
|
39
|
+
import { getArtifactSchema } from "./artifact-schema.ts";
|
|
40
|
+
import { inspectArtifactContract } from "./artifact-operations.ts";
|
|
37
41
|
|
|
38
42
|
const TASK_ENUMS = {
|
|
39
43
|
type: ["feature", "bugfix", "refactor", "docs", "chore"],
|
|
@@ -88,7 +92,7 @@ let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
|
|
|
88
92
|
|
|
89
93
|
const PLATFORM_ADAPTERS: Record<string, (context: any, shared: any) => any> = {
|
|
90
94
|
"platform-sync": checkPlatformSync,
|
|
91
|
-
"platform-sync-preflight": (context: any, shared: any) => ({ ...checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
95
|
+
"platform-sync-preflight": async (context: any, shared: any) => ({ ...await checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
|
|
92
96
|
"required-checks": checkRequiredChecks
|
|
93
97
|
};
|
|
94
98
|
const OPTIONAL_PLATFORM_CHECKS = new Set(["platform-sync"]);
|
|
@@ -107,7 +111,7 @@ const sharedUtils = {
|
|
|
107
111
|
parsePrNumber
|
|
108
112
|
};
|
|
109
113
|
|
|
110
|
-
function runCheck(type: any, context: any, shared: any): any {
|
|
114
|
+
async function runCheck(type: any, context: any, shared: any): Promise<any> {
|
|
111
115
|
switch (type) {
|
|
112
116
|
case "task-meta":
|
|
113
117
|
return checkTaskMeta(context);
|
|
@@ -147,7 +151,7 @@ function runCheck(type: any, context: any, shared: any): any {
|
|
|
147
151
|
return failResult(type, `Unsupported check type '${type}'.`);
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
return adapter(context, shared);
|
|
154
|
+
return await adapter(context, shared);
|
|
151
155
|
}
|
|
152
156
|
}
|
|
153
157
|
}
|
|
@@ -488,7 +492,7 @@ function checkTaskMeta({ taskDir, config }: any): any {
|
|
|
488
492
|
);
|
|
489
493
|
}
|
|
490
494
|
|
|
491
|
-
function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
|
|
495
|
+
async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): Promise<any> {
|
|
492
496
|
const task = loadTask(taskDir);
|
|
493
497
|
if (!task.ok) return failResult('required-pr-delivery', task.message);
|
|
494
498
|
let projectConfig: any = {};
|
|
@@ -503,9 +507,10 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
|
|
|
503
507
|
if (factRead.status === 'invalid') return failResult('required-pr-delivery', factRead.error.message);
|
|
504
508
|
const fact = factRead.status === 'valid' ? factRead.fact : null;
|
|
505
509
|
const status = fact?.state || 'unbound';
|
|
506
|
-
const
|
|
510
|
+
const prIdentity = fact?.state === 'bound' ? fact.identity.resource : null;
|
|
511
|
+
const prNumber = prIdentity?.kind === 'number' ? prIdentity.value : null;
|
|
507
512
|
if (flow === 'disabled') return passResult('required-pr-delivery', 'Pull request delivery is disabled by project policy');
|
|
508
|
-
if (flow === 'required' && (status !== 'bound' ||
|
|
513
|
+
if (flow === 'required' && (status !== 'bound' || !prIdentity)) {
|
|
509
514
|
return failResult('required-pr-delivery', 'Project policy requires a bound pull request before completion');
|
|
510
515
|
}
|
|
511
516
|
if (flow !== 'required' && status === 'unbound') {
|
|
@@ -515,7 +520,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
|
|
|
515
520
|
if (mode === 'gate') {
|
|
516
521
|
return passResult('required-pr-delivery', 'Bound pull request shape is valid; merged-state inspection is reserved for hard preflight');
|
|
517
522
|
}
|
|
518
|
-
const inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
|
|
523
|
+
const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
|
|
519
524
|
if (inspected.status === 'blocked') {
|
|
520
525
|
return blockedResult(
|
|
521
526
|
'required-pr-delivery',
|
|
@@ -527,7 +532,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
|
|
|
527
532
|
const repository = inspected.platform.repository?.toLowerCase() || '';
|
|
528
533
|
const taskBranch = String(task.metadata.branch || '').trim();
|
|
529
534
|
const deliveryBaseRef = String(task.metadata.delivery_base_ref || projectConfig.delivery?.baseRef || '').trim();
|
|
530
|
-
if (inspected.status !== 'no-op' || !pullRequest
|
|
535
|
+
if (inspected.status !== 'no-op' || !pullRequest) {
|
|
531
536
|
return failResult('required-pr-delivery', 'Bound pull request identity could not be verified');
|
|
532
537
|
}
|
|
533
538
|
if (
|
|
@@ -542,7 +547,7 @@ function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any): any {
|
|
|
542
547
|
if (pullRequest.state !== 'closed' || !pullRequest.mergedAt || !pullRequest.mergeCommitSha) {
|
|
543
548
|
return failResult('required-pr-delivery', 'Project policy requires the bound pull request to be merged');
|
|
544
549
|
}
|
|
545
|
-
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR
|
|
550
|
+
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (merged PR ${prNumber === null ? 'identity' : `#${prNumber}`})`);
|
|
546
551
|
}
|
|
547
552
|
return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
|
|
548
553
|
}
|
|
@@ -581,7 +586,7 @@ function loadProjectName(): any {
|
|
|
581
586
|
}
|
|
582
587
|
}
|
|
583
588
|
|
|
584
|
-
function checkArtifact({ taskDir, config, artifactFile }: any): any {
|
|
589
|
+
function checkArtifact({ taskDir, config, artifactFile, skillName }: any): any {
|
|
585
590
|
const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
|
|
586
591
|
if (!resolvedArtifact.ok) {
|
|
587
592
|
return failResult("artifact", resolvedArtifact.message);
|
|
@@ -598,6 +603,63 @@ function checkArtifact({ taskDir, config, artifactFile }: any): any {
|
|
|
598
603
|
}
|
|
599
604
|
|
|
600
605
|
const content = fs.readFileSync(artifactPath, "utf8");
|
|
606
|
+
let taskContent = "";
|
|
607
|
+
const taskPath = path.join(taskDir, "task.md");
|
|
608
|
+
if (fs.existsSync(taskPath)) {
|
|
609
|
+
try {
|
|
610
|
+
taskContent = fs.readFileSync(taskPath, "utf8");
|
|
611
|
+
} catch (error) {
|
|
612
|
+
return failResult("artifact", `Cannot read task qualification contract: ${error instanceof Error ? error.message : String(error)}`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (taskContent && /^review-(?:analysis|plan|code)$/.test(skillName)) {
|
|
616
|
+
const qualification = validateQualificationAudit(taskContent, content, { artifact: path.basename(artifactPath) });
|
|
617
|
+
if (!qualification.ok) return failResult("artifact", `${path.basename(artifactPath)} has qualification audit errors: ${qualification.code}: ${qualification.message}`);
|
|
618
|
+
}
|
|
619
|
+
const schemaFamily = skillName === "analyze-task"
|
|
620
|
+
? "analysis"
|
|
621
|
+
: skillName === "review-analysis"
|
|
622
|
+
? "review-analysis"
|
|
623
|
+
: skillName === "plan-task"
|
|
624
|
+
? "plan"
|
|
625
|
+
: skillName === "review-plan"
|
|
626
|
+
? "review-plan"
|
|
627
|
+
: skillName === "code-task"
|
|
628
|
+
? "code"
|
|
629
|
+
: skillName === "review-code" ? "review-code" : null;
|
|
630
|
+
const schema = schemaFamily ? getArtifactSchema(schemaFamily) : null;
|
|
631
|
+
const localFamily = skillName === "analyze-task"
|
|
632
|
+
? "analysis"
|
|
633
|
+
: skillName === "plan-task" ? "plan" : skillName === "code-task" ? "code" : null;
|
|
634
|
+
if (schema) {
|
|
635
|
+
const structure = inspectArtifactContract(content, schema);
|
|
636
|
+
if (!structure.ok && !localFamily) {
|
|
637
|
+
return failResult("artifact", `${path.basename(artifactPath)} has shared structural errors: ${structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (localFamily) {
|
|
641
|
+
const local = validateLocalArtifact(content, {
|
|
642
|
+
family: localFamily,
|
|
643
|
+
...(taskContent ? { taskContent } : {}),
|
|
644
|
+
artifact: path.basename(artifactPath)
|
|
645
|
+
});
|
|
646
|
+
if (!local.ok) {
|
|
647
|
+
return failResult(
|
|
648
|
+
"artifact",
|
|
649
|
+
`${path.basename(artifactPath)} has local structural errors: ${local.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
return passResult(
|
|
653
|
+
"artifact",
|
|
654
|
+
`${path.basename(artifactPath)} passed (${schema?.sections.length ?? 0} sections)`
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
if (schema) {
|
|
658
|
+
return passResult(
|
|
659
|
+
"artifact",
|
|
660
|
+
`${path.basename(artifactPath)} passed (${schema.sections.length} sections)`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
601
663
|
const requiredSections = config.required_sections || [];
|
|
602
664
|
const missingSections = requiredSections.filter(
|
|
603
665
|
(section: any) => !new RegExp(`^##\\s+${escapeRegExp(section)}\\s*$`, "m").test(content)
|
|
@@ -764,6 +826,7 @@ function checkActivityLog({ taskDir, config }: any): any {
|
|
|
764
826
|
let previousTimestamp = "";
|
|
765
827
|
let latestAction = "";
|
|
766
828
|
let latestTimestamp = "";
|
|
829
|
+
const doneActions: string[] = [];
|
|
767
830
|
|
|
768
831
|
for (const entry of entries) {
|
|
769
832
|
const match = entry.match(ACTIVITY_LOG_PATTERN);
|
|
@@ -783,6 +846,16 @@ function checkActivityLog({ taskDir, config }: any): any {
|
|
|
783
846
|
if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
|
|
784
847
|
latestTimestamp = timestamp;
|
|
785
848
|
latestAction = action;
|
|
849
|
+
doneActions.push(action);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (config.expected_action_pattern && !new RegExp(config.expected_action_pattern).test(latestAction)) {
|
|
854
|
+
const expected = new RegExp(config.expected_action_pattern);
|
|
855
|
+
let index = doneActions.length - 1;
|
|
856
|
+
while (index >= 0 && doneActions[index] === 'Commit' && !expected.test(doneActions[index]!)) index -= 1;
|
|
857
|
+
if (index >= 0 && expected.test(doneActions[index]!)) {
|
|
858
|
+
latestAction = doneActions[index]!;
|
|
786
859
|
}
|
|
787
860
|
}
|
|
788
861
|
|
|
@@ -1031,6 +1104,7 @@ function checkManualValidation({ taskDir }: any): any {
|
|
|
1031
1104
|
// 1. Latest review-code artifact; none -> pass (no review, check not applicable).
|
|
1032
1105
|
const review = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
1033
1106
|
if (!review.ok) {
|
|
1107
|
+
if (review.error) return failResult("manual-validation", `Review-code artifact is unavailable: ${review.error}`);
|
|
1034
1108
|
return passResult("manual-validation", "No review-code artifact; manual validation not applicable");
|
|
1035
1109
|
}
|
|
1036
1110
|
// 2. Parse the numeric manual-validation count; unparseable/null -> fail closed
|
|
@@ -1096,9 +1170,10 @@ function checkManualValidation({ taskDir }: any): any {
|
|
|
1096
1170
|
return passResult("manual-validation", `Manual validation completed → ${artifactName}`);
|
|
1097
1171
|
}
|
|
1098
1172
|
|
|
1099
|
-
function checkPostReviewCommit({ taskDir, config }: any): any {
|
|
1173
|
+
async function checkPostReviewCommit({ taskDir, config }: any): Promise<any> {
|
|
1100
1174
|
const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
1101
1175
|
if (!reviewArtifact.ok) {
|
|
1176
|
+
if (reviewArtifact.error) return failResult("post-review-commit", `Review-code artifact is unavailable: ${reviewArtifact.error}`);
|
|
1102
1177
|
return passResult("post-review-commit", "No review-code artifact; check inactive");
|
|
1103
1178
|
}
|
|
1104
1179
|
|
|
@@ -1117,9 +1192,9 @@ function checkPostReviewCommit({ taskDir, config }: any): any {
|
|
|
1117
1192
|
const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
|
|
1118
1193
|
const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
|
|
1119
1194
|
const hasPullRequest = fact?.state === 'bound';
|
|
1120
|
-
let inspected: ReturnType<typeof inspectPlatformPullRequest
|
|
1195
|
+
let inspected: Awaited<ReturnType<typeof inspectPlatformPullRequest>> | null = null;
|
|
1121
1196
|
if (hasPullRequest) {
|
|
1122
|
-
inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
|
|
1197
|
+
inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
|
|
1123
1198
|
if (!inspected.pullRequest) {
|
|
1124
1199
|
const message = inspected.error?.message || "PR merge snapshot is unavailable";
|
|
1125
1200
|
const code = inspected.error?.code || "PR_INSPECTION_INVALID";
|
|
@@ -1132,7 +1207,7 @@ function checkPostReviewCommit({ taskDir, config }: any): any {
|
|
|
1132
1207
|
inspected.pullRequest.mergedAt &&
|
|
1133
1208
|
inspected.pullRequest.mergeCommitSha
|
|
1134
1209
|
) {
|
|
1135
|
-
const relation = resolveMaterializedReviewedHeadRelation({
|
|
1210
|
+
const relation = await resolveMaterializedReviewedHeadRelation({
|
|
1136
1211
|
cwd: gitRoot,
|
|
1137
1212
|
platformType: inspected.platform.type,
|
|
1138
1213
|
lastReviewedCommit,
|
|
@@ -1299,6 +1374,17 @@ function checkReviewFact({ taskDir, artifactFile }: any): any {
|
|
|
1299
1374
|
return failResult("review-fact", resolvedArtifact.message);
|
|
1300
1375
|
}
|
|
1301
1376
|
|
|
1377
|
+
const authoritative = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
1378
|
+
if (!authoritative.ok) {
|
|
1379
|
+
return failResult("review-fact", authoritative.error ?? "No active review-code artifact is available");
|
|
1380
|
+
}
|
|
1381
|
+
if (path.basename(resolvedArtifact.path) !== authoritative.fileName) {
|
|
1382
|
+
return failResult(
|
|
1383
|
+
"review-fact",
|
|
1384
|
+
`review-code artifact ${path.basename(resolvedArtifact.path)} is not the current active artifact ${authoritative.fileName}; re-run review-code`
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1302
1388
|
const task = loadTask(taskDir);
|
|
1303
1389
|
if (!task.ok) {
|
|
1304
1390
|
return failResult("review-fact", task.message);
|
|
@@ -1655,7 +1741,7 @@ function isBlank(value: any): any {
|
|
|
1655
1741
|
return value === undefined || value === null || String(value).trim() === "";
|
|
1656
1742
|
}
|
|
1657
1743
|
|
|
1658
|
-
function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): any {
|
|
1744
|
+
async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): Promise<any> {
|
|
1659
1745
|
if (repositoryRoot) repoRoot = path.resolve(repositoryRoot);
|
|
1660
1746
|
else {
|
|
1661
1747
|
let cursor = path.resolve(taskDir);
|
|
@@ -1668,7 +1754,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
|
|
|
1668
1754
|
const checks = [];
|
|
1669
1755
|
for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {
|
|
1670
1756
|
if (checkConfig === null) continue;
|
|
1671
|
-
const result = runCheck(type, {
|
|
1757
|
+
const result = await runCheck(type, {
|
|
1672
1758
|
mode,
|
|
1673
1759
|
skillName,
|
|
1674
1760
|
taskDir: path.resolve(taskDir),
|
|
@@ -1688,7 +1774,7 @@ function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: reque
|
|
|
1688
1774
|
if (config === null) return { skill: skillName, ...passResult(type, `Check '${type}' is disabled for skill '${skillName}'.`) };
|
|
1689
1775
|
return {
|
|
1690
1776
|
skill: skillName,
|
|
1691
|
-
...runCheck(type, {
|
|
1777
|
+
...await runCheck(type, {
|
|
1692
1778
|
skillName,
|
|
1693
1779
|
taskDir: path.resolve(taskDir),
|
|
1694
1780
|
artifactFile,
|
package/lib/task/verification.ts
CHANGED
|
@@ -49,7 +49,7 @@ type TaskVerificationResult = {
|
|
|
49
49
|
};
|
|
50
50
|
type VerificationOptions = {
|
|
51
51
|
repoRoot?: string;
|
|
52
|
-
engine?: typeof verifyInProcess
|
|
52
|
+
engine?: (input: Parameters<typeof verifyInProcess>[0]) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
53
53
|
manualOverride?: ManualOverrideCapability;
|
|
54
54
|
};
|
|
55
55
|
|
|
@@ -91,7 +91,7 @@ function failure(request: { taskRef: string; event: string; artifact?: string },
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: string }, options: VerificationOptions = {}): TaskVerificationResult {
|
|
94
|
+
async function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: string }, options: VerificationOptions = {}): Promise<TaskVerificationResult> {
|
|
95
95
|
const spec = VERIFICATION_CATALOG[request.event as VerificationEvent];
|
|
96
96
|
if (!spec) return failure(request, 'VERIFY_EVENT_UNKNOWN', `unknown verification event '${request.event}'`);
|
|
97
97
|
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
@@ -113,7 +113,7 @@ function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: s
|
|
|
113
113
|
const invocations: VerificationInvocation[] = [];
|
|
114
114
|
const engine = options.engine ?? verifyInProcess;
|
|
115
115
|
if (spec.mode === 'gate') {
|
|
116
|
-
const payload = engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot })
|
|
116
|
+
const payload = await engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot });
|
|
117
117
|
const status = payload.gate as 'pass' | 'fail' | 'blocked';
|
|
118
118
|
if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
|
|
119
119
|
invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, gate: 'pass', humanOverride: 'human-approved', originalGate: status } });
|
|
@@ -125,7 +125,7 @@ function verifyTaskEvent(request: { taskRef: string; event: string; artifact?: s
|
|
|
125
125
|
invocations.push({ status, exitCode: ({ pass: 0, fail: 1, blocked: 2 } as const)[status], payload });
|
|
126
126
|
} else {
|
|
127
127
|
for (const check of spec.checks ?? []) {
|
|
128
|
-
const payload = engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot })
|
|
128
|
+
const payload = await engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot });
|
|
129
129
|
const status = payload.status as 'pass' | 'fail' | 'blocked';
|
|
130
130
|
if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
|
|
131
131
|
invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, status: 'pass', humanOverride: 'human-approved', originalStatus: status } });
|
|
@@ -68,7 +68,7 @@ function sectionMutation(content: string): TaskMutation[] {
|
|
|
68
68
|
const english = /^##\s+Activity Log\s*$/m.test(content);
|
|
69
69
|
return [{
|
|
70
70
|
kind: 'section', aliases: WORKFLOW_WARNING_HEADINGS, heading: english ? 'Workflow Warnings' : '工作流告警',
|
|
71
|
-
body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n
|
|
71
|
+
body: `| ${WORKFLOW_WARNING_COLUMNS.join(' | ')} |\n|----|------|------|----------|------|--------|---------|--------|-------------|------------|------------|`
|
|
72
72
|
}];
|
|
73
73
|
}
|
|
74
74
|
|
package/lib/task/write.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { allowsManualOverride } from './guard-override.ts';
|
|
|
16
16
|
import type { ManualOverrideCapability } from './guard-override.ts';
|
|
17
17
|
import { mutateTableRow, upsertSection } from './sections.ts';
|
|
18
18
|
import { validateCurrentTaskContract } from './current-contract.ts';
|
|
19
|
+
import { invalidationBlocks, parseInvalidationDocument } from './invalidation.ts';
|
|
19
20
|
import type {
|
|
20
21
|
TableRowDeleteMutation,
|
|
21
22
|
TableRowUpsertMutation
|
|
@@ -86,6 +87,8 @@ type TaskWriteErrorCode =
|
|
|
86
87
|
| ResolveTaskRefErrorCode
|
|
87
88
|
| 'TASK_STATE_MISMATCH'
|
|
88
89
|
| 'TASK_CURRENT_CONTRACT_INVALID'
|
|
90
|
+
| 'TASK_INVALIDATION_INVALID'
|
|
91
|
+
| 'TASK_INVALIDATION_BLOCKED'
|
|
89
92
|
| 'TASK_READ_FAILED'
|
|
90
93
|
| 'TASK_DOCUMENT_INVALID'
|
|
91
94
|
| 'MUTATION_INVALID'
|
|
@@ -161,6 +164,7 @@ type TaskWriteOptions = {
|
|
|
161
164
|
randomSuffix?: () => string;
|
|
162
165
|
fileSystem?: Partial<TaskFileSystem>;
|
|
163
166
|
manualOverride?: ManualOverrideCapability;
|
|
167
|
+
invalidationContext?: 'standard' | 'source-completion' | 'reconcile';
|
|
164
168
|
};
|
|
165
169
|
|
|
166
170
|
const DEFAULT_FILE_SYSTEM: TaskFileSystem = {
|
|
@@ -275,6 +279,21 @@ function writeTask(request: TaskWriteRequest, options: TaskWriteOptions = {}): T
|
|
|
275
279
|
if (!contract.ok) {
|
|
276
280
|
return failure(request, identity, contract.code, contract.message);
|
|
277
281
|
}
|
|
282
|
+
if (
|
|
283
|
+
invalidationBlocks(contract.invalidation)
|
|
284
|
+
&& options.invalidationContext !== 'source-completion'
|
|
285
|
+
&& options.invalidationContext !== 'reconcile'
|
|
286
|
+
) {
|
|
287
|
+
return failure(
|
|
288
|
+
request,
|
|
289
|
+
identity,
|
|
290
|
+
'TASK_INVALIDATION_BLOCKED',
|
|
291
|
+
'task has an incomplete artifact invalidation operation; reconcile it before writing downstream state'
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
const invalidation = parseInvalidationDocument(original);
|
|
296
|
+
if (!invalidation.ok) return failure(request, identity, 'TASK_INVALIDATION_INVALID', invalidation.message);
|
|
278
297
|
}
|
|
279
298
|
|
|
280
299
|
let candidate = original;
|
package/lib/update.ts
CHANGED
|
@@ -19,7 +19,7 @@ type UpdateConfig = {
|
|
|
19
19
|
project: string;
|
|
20
20
|
org: string;
|
|
21
21
|
language: string;
|
|
22
|
-
platform?: { type?: string };
|
|
22
|
+
platform?: { type?: string; providers?: Record<string, unknown> };
|
|
23
23
|
prFlow?: 'required' | 'disabled';
|
|
24
24
|
sandbox?: Record<string, unknown>;
|
|
25
25
|
task?: { shortIdLength: number };
|