@fitlab-ai/agent-infra 0.9.13 → 0.9.15
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 +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/cli.ts +26 -9
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +126 -42
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +37 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +154 -0
- package/dist/lib/internal/codex-lifecycle.js +15 -12
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +322 -0
- package/dist/lib/internal/platform-checks.js +16 -4
- package/dist/lib/internal/platform-comment.js +16 -4
- package/dist/lib/internal/platform-context.js +4 -1
- package/dist/lib/internal/platform-issue.js +12 -4
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +16 -3
- package/dist/lib/internal/platform-pr.js +42 -14
- package/dist/lib/internal/platform-release-notes.js +6 -3
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +14 -3
- package/dist/lib/internal/release-workflow.js +82 -89
- package/dist/lib/internal/sandbox-control.js +171 -7
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +19 -107
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -14
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +38 -35
- package/dist/lib/internal/task-finalization.js +4 -1
- package/dist/lib/internal/task-invalidation.js +4 -1
- package/dist/lib/internal/task-ledger.js +12 -1
- package/dist/lib/internal/task-lifecycle.js +4 -1
- package/dist/lib/internal/task-operation-registry.js +519 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +10 -3
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +10 -52
- 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 +37 -12
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +229 -0
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +248 -26
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/issues.js +1 -179
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +83 -10
- package/dist/lib/platform/provider-contract.d.ts +67 -1
- package/dist/lib/platform/provider-contract.js +6 -2
- package/dist/lib/platform/provider-validation.js +76 -3
- package/dist/lib/platform/pull-requests.js +117 -275
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/verification-sync.js +154 -162
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/run/index.js +5 -0
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +39 -8
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +3 -807
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +125 -12
- 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 +233 -34
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +656 -128
- package/dist/lib/sandbox/control/native-file-lock.js +85 -0
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +720 -79
- package/dist/lib/sandbox/control/state.js +63 -3
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +99 -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 +7 -2
- package/dist/lib/sandbox/recovery.js +49 -5
- package/dist/lib/sandbox/removal.js +1717 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-view.js +15 -15
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +101 -0
- package/dist/lib/task/artifact-lifecycle.js +71 -40
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +474 -0
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-repair-intent.js +130 -0
- package/dist/lib/task/artifact-schema.js +127 -0
- package/dist/lib/task/capabilities.js +83 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +2 -16
- package/dist/lib/task/control-authority.js +375 -5
- package/dist/lib/task/control-recovery.js +128 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +80 -2
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/events.js +306 -76
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +3 -6
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/intermediate-cleanup.js +383 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle.js +19 -1
- package/dist/lib/task/local-artifact-finalization.js +190 -290
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +101 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +206 -69
- package/dist/lib/task/qualification-audit.js +476 -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 +23 -40
- package/dist/lib/task/review-command.js +25 -0
- package/dist/lib/task/review-finalization.js +146 -97
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -54
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +170 -327
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +17 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
- package/lib/fs/durable-write.ts +29 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +142 -0
- package/lib/internal/codex-lifecycle.ts +14 -12
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +306 -0
- package/lib/internal/platform-checks.ts +12 -4
- package/lib/internal/platform-comment.ts +12 -4
- package/lib/internal/platform-context.ts +3 -1
- package/lib/internal/platform-issue.ts +11 -4
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/platform-pr.ts +38 -14
- package/lib/internal/platform-release-notes.ts +5 -3
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +10 -3
- package/lib/internal/release-workflow.ts +91 -87
- package/lib/internal/sandbox-control.ts +181 -6
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +15 -79
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +76 -15
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +21 -10
- package/lib/internal/task-finalization.ts +3 -1
- package/lib/internal/task-invalidation.ts +3 -1
- package/lib/internal/task-ledger.ts +11 -1
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +590 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +9 -3
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +7 -50
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +32 -12
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +255 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +244 -27
- package/lib/platform/issue-comments.ts +159 -35
- package/lib/platform/issues.ts +4 -245
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +88 -11
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +129 -348
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/verification-sync.ts +171 -177
- package/lib/process-data/index.ts +7 -0
- package/lib/release/workflow.ts +3 -3
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +53 -12
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +3 -996
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +150 -13
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +262 -37
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +672 -18
- package/lib/sandbox/control/native-file-lock.ts +108 -0
- package/lib/sandbox/control/protocol.ts +80 -8
- package/lib/sandbox/control/server.ts +779 -82
- package/lib/sandbox/control/state.ts +84 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +102 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +9 -2
- package/lib/sandbox/recovery.ts +49 -6
- package/lib/sandbox/removal.ts +2144 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-view.ts +26 -18
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +104 -0
- package/lib/task/artifact-lifecycle.ts +66 -39
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +580 -0
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-repair-intent.ts +152 -0
- package/lib/task/artifact-schema.ts +163 -0
- package/lib/task/capabilities.ts +82 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +2 -16
- package/lib/task/control-authority.ts +513 -6
- package/lib/task/control-recovery.ts +174 -0
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +83 -1
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/events.ts +292 -75
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +3 -8
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/index.ts +16 -3
- package/lib/task/intermediate-cleanup.ts +455 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle.ts +17 -1
- package/lib/task/local-artifact-finalization.ts +223 -388
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +152 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +191 -68
- package/lib/task/qualification-audit.ts +588 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -41
- package/lib/task/review-command.ts +23 -0
- package/lib/task/review-finalization.ts +154 -153
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -52
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +165 -370
- package/lib/task/verification-types.ts +17 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +18 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/package.json +7 -2
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- 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/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 +5 -1
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
- 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/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
- 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/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 +14 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -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/complete-manual-validation/SKILL.en.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
- 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 +14 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
- 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/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
- 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 +14 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
- 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 +14 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
- 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 +25 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +29 -7
- package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/templates/task.en.md +6 -0
- package/templates/.agents/templates/task.zh-CN.md +6 -0
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
- 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 './markdown.js';
|
|
3
4
|
const SUMMARY_HEADINGS = new Set(['审查摘要', 'Review Summary']);
|
|
4
5
|
const PLACEHOLDERS = [
|
|
5
6
|
'{unresolved-blockers}',
|
|
@@ -9,22 +10,6 @@ const PLACEHOLDERS = [
|
|
|
9
10
|
function escapeRegExp(value) {
|
|
10
11
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
11
12
|
}
|
|
12
|
-
function maxRound(entries, stem) {
|
|
13
|
-
let max = 0;
|
|
14
|
-
for (const entry of entries) {
|
|
15
|
-
if (entry === `${stem}.md`) {
|
|
16
|
-
max = Math.max(max, 1);
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
|
|
20
|
-
if (match)
|
|
21
|
-
max = Math.max(max, Number(match[1]));
|
|
22
|
-
}
|
|
23
|
-
return max;
|
|
24
|
-
}
|
|
25
|
-
function artifactName(stem, round) {
|
|
26
|
-
return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
|
|
27
|
-
}
|
|
28
13
|
function normalizeVerdict(raw) {
|
|
29
14
|
const value = String(raw).trim().toLowerCase();
|
|
30
15
|
if (value === '通过' || value === 'approved')
|
|
@@ -36,42 +21,40 @@ function normalizeVerdict(raw) {
|
|
|
36
21
|
return '';
|
|
37
22
|
}
|
|
38
23
|
function extractSection(content, names) {
|
|
39
|
-
const lines = content.split(/\r?\n/);
|
|
40
24
|
const nameSet = new Set(names);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
if (start === -1)
|
|
25
|
+
const scanned = scanVisibleMarkdown(content);
|
|
26
|
+
const heading = scanned.headings.find((item) => item.level === 2 && nameSet.has(item.text));
|
|
27
|
+
if (!heading)
|
|
46
28
|
return '';
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (/^##\s+/.test(lines[index]))
|
|
50
|
-
break;
|
|
51
|
-
sectionLines.push(lines[index]);
|
|
52
|
-
}
|
|
53
|
-
return sectionLines.join('\n');
|
|
29
|
+
const next = scanned.headings.find((item) => item.start > heading.start && item.level <= 2);
|
|
30
|
+
return content.slice(heading.end, next?.start ?? content.length);
|
|
54
31
|
}
|
|
55
32
|
function summaryBounds(content) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
|
|
33
|
+
const scanned = scanVisibleMarkdown(content);
|
|
34
|
+
const summaries = scanned.headings.filter((heading) => heading.level === 2 && SUMMARY_HEADINGS.has(heading.text));
|
|
59
35
|
if (summaries.length !== 1)
|
|
60
36
|
return null;
|
|
61
37
|
const summary = summaries[0];
|
|
62
|
-
const next = headings.find((heading) => heading.
|
|
63
|
-
return { start: summary.end, end: next?.
|
|
38
|
+
const next = scanned.headings.find((heading) => heading.start > summary.start && heading.level <= 2);
|
|
39
|
+
return { start: summary.end, end: next?.start ?? content.length };
|
|
64
40
|
}
|
|
65
41
|
function uniqueLine(content, bounds, pattern) {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
42
|
+
const matches = [];
|
|
43
|
+
for (const line of scanVisibleMarkdown(content).lines) {
|
|
44
|
+
if (line.start < bounds.start || line.start >= bounds.end)
|
|
45
|
+
continue;
|
|
46
|
+
pattern.lastIndex = 0;
|
|
47
|
+
const match = pattern.exec(line.text);
|
|
48
|
+
if (match)
|
|
49
|
+
matches.push({ value: match[1], index: line.start + match.index, length: match[0].length });
|
|
50
|
+
}
|
|
68
51
|
if (matches.length !== 1)
|
|
69
52
|
return null;
|
|
70
53
|
const match = matches[0];
|
|
71
54
|
return {
|
|
72
|
-
value: match
|
|
73
|
-
start:
|
|
74
|
-
end:
|
|
55
|
+
value: match.value,
|
|
56
|
+
start: match.index,
|
|
57
|
+
end: match.index + match.length
|
|
75
58
|
};
|
|
76
59
|
}
|
|
77
60
|
function parseCounts(value) {
|
|
@@ -200,5 +183,5 @@ function parseVerdict(reviewPath) {
|
|
|
200
183
|
}
|
|
201
184
|
return resolveCanonicalVerdict(parsed.summary);
|
|
202
185
|
}
|
|
203
|
-
export {
|
|
186
|
+
export { equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, normalizeVerdict, parseReviewSummary, parseVerdict, resolveCanonicalVerdict };
|
|
204
187
|
//# sourceMappingURL=review-artifacts.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function parseReviewCommand(args) {
|
|
2
|
+
if (!args[0] || args[1] !== 'finalize-summary')
|
|
3
|
+
throw new Error('task ref and finalize-summary are required');
|
|
4
|
+
const values = {};
|
|
5
|
+
const flags = {
|
|
6
|
+
'--stage': 'stage', '--artifact': 'artifact', '--orchestrated': 'orchestrated', '--dry-run': 'dryRun',
|
|
7
|
+
'--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
|
|
8
|
+
};
|
|
9
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
10
|
+
const flag = args[index];
|
|
11
|
+
if (!Object.hasOwn(flags, flag))
|
|
12
|
+
throw new Error(`unknown option '${flag}'`);
|
|
13
|
+
const key = flags[flag];
|
|
14
|
+
if (Object.hasOwn(values, key))
|
|
15
|
+
throw new Error(`duplicate option '${flag}'`);
|
|
16
|
+
const value = flag === '--orchestrated' || flag === '--dry-run' ? true : args[++index];
|
|
17
|
+
if (!value || typeof value === 'string' && value.startsWith('--'))
|
|
18
|
+
throw new Error(`option '${flag}' requires a value`);
|
|
19
|
+
values[key] = value;
|
|
20
|
+
}
|
|
21
|
+
if (!values.stage || !values.artifact)
|
|
22
|
+
throw new Error("options '--stage' and '--artifact' are required");
|
|
23
|
+
return { taskRef: args[0], ...values };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=review-command.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { parseArtifactName } from './artifact-name.js';
|
|
5
|
+
import { validateCompletedArtifact, hasOpenArtifactRound, validateArtifactPublication } from './artifact-lifecycle.js';
|
|
6
6
|
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
7
7
|
import { finalizeReviewSummaryContent } from './review-artifacts.js';
|
|
8
8
|
import { inspectDecisionDetailDuplicates } from './decision-details.js';
|
|
@@ -10,10 +10,13 @@ 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
|
-
analysis: { family: 'review-analysis'
|
|
15
|
-
plan: { family: 'review-plan'
|
|
16
|
-
code: { family: 'review-code'
|
|
17
|
+
analysis: { family: 'review-analysis' },
|
|
18
|
+
plan: { family: 'review-plan' },
|
|
19
|
+
code: { family: 'review-code' }
|
|
17
20
|
};
|
|
18
21
|
const DEFAULT_FILE_SYSTEM = {
|
|
19
22
|
readFileSync: (file) => fs.readFileSync(file, 'utf8'),
|
|
@@ -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,17 +35,15 @@ 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
|
-
function openReviewRound(content, action, round) {
|
|
40
|
-
const section = locateActivityLog(content);
|
|
41
|
-
if (!section)
|
|
42
|
-
return false;
|
|
43
|
-
const expected = `${action} (Round ${round})`;
|
|
44
|
-
return startedBackedRows(pairEntries(section.entries)).filter((row) => (row.step === expected && !row.done)).length === 1;
|
|
45
|
-
}
|
|
46
47
|
function cleanupTemp(fileSystem, tempPath) {
|
|
47
48
|
try {
|
|
48
49
|
fileSystem.unlinkSync(tempPath);
|
|
@@ -51,131 +52,179 @@ function cleanupTemp(fileSystem, tempPath) {
|
|
|
51
52
|
// Best-effort cleanup preserves the primary failure.
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
/** Prepare domain validation, summary bytes and provenance before any publication. */
|
|
56
|
+
function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
|
|
57
|
+
let taskId = null;
|
|
58
|
+
let stageStatus = null;
|
|
59
|
+
const reject = (code, message, extra = {}) => ({
|
|
60
|
+
result: failed(request, code, message, taskId, stageStatus, extra), content: artifactContent
|
|
61
|
+
});
|
|
55
62
|
const stage = request.stage;
|
|
56
63
|
const spec = STAGES[stage];
|
|
57
64
|
if (!spec)
|
|
58
|
-
return
|
|
59
|
-
if (!request.taskRef || !request.artifact)
|
|
60
|
-
return
|
|
61
|
-
}
|
|
65
|
+
return reject('REVIEW_STAGE_INVALID', `unsupported review stage '${request.stage}'`);
|
|
66
|
+
if (!request.taskRef || !request.artifact)
|
|
67
|
+
return reject('REVIEW_PAYLOAD_INVALID', 'taskRef, stage, and artifact are required');
|
|
62
68
|
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
69
|
+
taskId = resolved.taskId ?? null;
|
|
63
70
|
if (!resolved.ok)
|
|
64
|
-
return
|
|
71
|
+
return reject(resolved.code, resolved.message);
|
|
65
72
|
if (resolved.state !== 'active' && !allowsManualOverride(options.manualOverride, 'review-finalization', 'TASK_STATE_MISMATCH')) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
70
|
-
return
|
|
73
|
+
return reject('TASK_STATE_MISMATCH', `task ${taskId} is ${resolved.state}, expected active`);
|
|
74
|
+
}
|
|
75
|
+
const parsed = parseArtifactName(request.artifact);
|
|
76
|
+
if (!parsed || parsed.family !== spec.family)
|
|
77
|
+
return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${spec.family}`);
|
|
78
|
+
const publicationError = validateArtifactPublication(resolved.taskDir, spec.family, request.artifact);
|
|
79
|
+
if (publicationError)
|
|
80
|
+
return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', publicationError.message);
|
|
81
|
+
let taskContent;
|
|
82
|
+
try {
|
|
83
|
+
taskContent = (options.fileSystem?.readFileSync ?? DEFAULT_FILE_SYSTEM.readFileSync)(resolved.taskMdPath);
|
|
71
84
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const code = validated.error.code === 'ARTIFACT_NOT_REGULAR'
|
|
75
|
-
? 'REVIEW_ARTIFACT_NOT_REGULAR'
|
|
76
|
-
: 'REVIEW_ARTIFACT_IDENTITY_INVALID';
|
|
77
|
-
return failed(request, code, validated.error.message, resolved.taskId);
|
|
85
|
+
catch (error) {
|
|
86
|
+
return reject('REVIEW_ARTIFACT_NOT_REGULAR', String(error));
|
|
78
87
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
const artifactSha256 = sha256Content(artifactContent);
|
|
89
|
+
const semanticDigest = canonicalSemanticDigest(artifactContent);
|
|
90
|
+
const digests = { artifactSha256, semanticDigest };
|
|
91
|
+
let repairIntent;
|
|
82
92
|
try {
|
|
83
|
-
|
|
84
|
-
artifactContent = fileSystem.readFileSync(validated.artifact.path);
|
|
93
|
+
repairIntent = readArtifactRepairIntent(resolved.repoRoot, taskId, spec.family, request.artifact);
|
|
85
94
|
}
|
|
86
95
|
catch (error) {
|
|
87
|
-
return
|
|
96
|
+
return reject('REVIEW_PROVENANCE_INVALID', String(error), digests);
|
|
97
|
+
}
|
|
98
|
+
const schema = getArtifactSchema(spec.family);
|
|
99
|
+
const structure = inspectArtifactContract(artifactContent, schema);
|
|
100
|
+
if (!structure.ok) {
|
|
101
|
+
const repairable = structure.repair !== null && structure.diagnostics.length === 1 && structure.diagnostics[0]?.repairable === true;
|
|
102
|
+
if (repairable && repairIntent && (repairIntent.state !== 'awaiting-repair'
|
|
103
|
+
|| repairIntent.artifactSha256 !== artifactSha256 || repairIntent.semanticDigest !== structure.semanticDigest)) {
|
|
104
|
+
return reject('REVIEW_PROVENANCE_INVALID', 'a different review repair baseline is already recorded for this artifact', digests);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
...reject('REVIEW_ARTIFACT_STRUCTURE_INVALID', structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; '), {
|
|
108
|
+
artifactSha256, semanticDigest: structure.semanticDigest, repairable, operation: structure.repair
|
|
109
|
+
}),
|
|
110
|
+
...(repairable && !repairIntent ? { provenance: {
|
|
111
|
+
version: 2, taskId: taskId, family: spec.family, artifact: request.artifact,
|
|
112
|
+
state: 'awaiting-repair', baselineSemanticDigest: structure.semanticDigest,
|
|
113
|
+
artifactSha256, semanticDigest: structure.semanticDigest,
|
|
114
|
+
recoveryOperationId: null, phase: null, authorityDigest: null,
|
|
115
|
+
requestId: `review-finalize:${taskId}`, createdAt: Date.now(), updatedAt: Date.now()
|
|
116
|
+
}, expectedIntent: null } : {})
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (repairIntent?.state === 'awaiting-repair' && repairIntent.baselineSemanticDigest !== semanticDigest) {
|
|
120
|
+
return reject('REVIEW_PROVENANCE_INVALID', 'the repaired review artifact semantic digest does not match the recorded repair baseline', digests);
|
|
121
|
+
}
|
|
122
|
+
if ((repairIntent?.state === 'passed' || repairIntent?.state === 'consumed')
|
|
123
|
+
&& (repairIntent.artifactSha256 !== artifactSha256 || repairIntent.semanticDigest !== semanticDigest)) {
|
|
124
|
+
return reject('REVIEW_PROVENANCE_INVALID', 'the review artifact changed after its finalization provenance was recorded', digests);
|
|
88
125
|
}
|
|
89
|
-
if (!
|
|
90
|
-
return
|
|
126
|
+
if (!hasOpenArtifactRound(taskContent, spec.family, parsed.round)) {
|
|
127
|
+
return reject('REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`);
|
|
91
128
|
}
|
|
92
129
|
const execution = validateLifecycleExecution(request.taskRef, {
|
|
93
130
|
mode: request.orchestrated ? 'orchestrated' : 'standalone',
|
|
94
|
-
identity: {
|
|
95
|
-
stage: spec.family,
|
|
96
|
-
round: parsedArtifact.round,
|
|
97
|
-
artifact: request.artifact,
|
|
98
|
-
role: 'reviewer'
|
|
99
|
-
},
|
|
131
|
+
identity: { stage: spec.family, round: parsed.round, artifact: request.artifact, role: 'reviewer' },
|
|
100
132
|
dryRun: request.dryRun
|
|
101
133
|
}, { repoRoot: options.repoRoot });
|
|
102
134
|
if (!execution.ok) {
|
|
103
|
-
return
|
|
135
|
+
return reject('REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`);
|
|
104
136
|
}
|
|
105
|
-
let rows;
|
|
106
137
|
try {
|
|
107
138
|
const ledger = parseLedgerDocument(taskContent);
|
|
108
|
-
if (!ledger.present)
|
|
109
|
-
return
|
|
110
|
-
|
|
111
|
-
|
|
139
|
+
if (!ledger.present)
|
|
140
|
+
return reject('REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
|
|
141
|
+
const error = validateLedgerRows(ledger.rows);
|
|
142
|
+
if (error)
|
|
143
|
+
return reject('REVIEW_LEDGER_INVALID', `${error.code}: ${error.message}`);
|
|
144
|
+
stageStatus = summarizeLedgerStage(ledger.rows, stage);
|
|
112
145
|
}
|
|
113
146
|
catch (error) {
|
|
114
|
-
return
|
|
147
|
+
return reject('REVIEW_LEDGER_INVALID', String(error));
|
|
115
148
|
}
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
return
|
|
149
|
+
const detail = inspectDecisionDetailDuplicates(artifactContent);
|
|
150
|
+
if (!detail.ok)
|
|
151
|
+
return reject('REVIEW_DECISION_DETAIL_INVALID', `${detail.code}: ${detail.message}`);
|
|
152
|
+
const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
|
|
153
|
+
if (!transformed.ok)
|
|
154
|
+
return reject(transformed.code, transformed.message);
|
|
155
|
+
const finalDigests = { artifactSha256: sha256Content(transformed.content), semanticDigest: canonicalSemanticDigest(transformed.content) };
|
|
156
|
+
return {
|
|
157
|
+
content: transformed.content,
|
|
158
|
+
result: {
|
|
159
|
+
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', taskId, stageStatus, finalDigests),
|
|
160
|
+
status: transformed.changed ? request.dryRun ? 'planned' : 'applied' : 'no-op',
|
|
161
|
+
changed: transformed.changed,
|
|
162
|
+
operations: transformed.changed ? [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }] : [],
|
|
163
|
+
error: null
|
|
164
|
+
},
|
|
165
|
+
...(repairIntent?.state === 'awaiting-repair' ? {
|
|
166
|
+
provenance: { ...repairIntent, state: 'passed', ...finalDigests },
|
|
167
|
+
expectedIntent: repairIntent
|
|
168
|
+
} : {})
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function commitReviewSummaryProvenance(prepared, repoRoot) {
|
|
172
|
+
try {
|
|
173
|
+
if (prepared.provenance) {
|
|
174
|
+
writeArtifactRepairIntent(repoRoot, prepared.provenance, { expected: prepared.expectedIntent ?? null });
|
|
175
|
+
}
|
|
176
|
+
return prepared.result;
|
|
119
177
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
178
|
+
catch (error) {
|
|
179
|
+
return { ...prepared.result, status: 'failed', error: {
|
|
180
|
+
code: 'REVIEW_PROVENANCE_INVALID', message: `cannot record review provenance: ${String(error)}`
|
|
181
|
+
} };
|
|
124
182
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
183
|
+
}
|
|
184
|
+
function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
185
|
+
const spec = STAGES[request.stage];
|
|
186
|
+
if (!spec || !request.taskRef || !request.artifact)
|
|
187
|
+
return prepareReviewSummaryCandidate(request, '', options).result;
|
|
188
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
189
|
+
if (!resolved.ok)
|
|
190
|
+
return failed(request, resolved.code, resolved.message, resolved.taskId);
|
|
191
|
+
const validated = validateCompletedArtifact(resolved.taskDir, spec.family, request.artifact);
|
|
192
|
+
if (!validated.ok) {
|
|
193
|
+
return failed(request, validated.error.code === 'ARTIFACT_NOT_REGULAR' ? 'REVIEW_ARTIFACT_NOT_REGULAR' : 'REVIEW_ARTIFACT_IDENTITY_INVALID', validated.error.message, resolved.taskId);
|
|
128
194
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
error: null
|
|
134
|
-
};
|
|
195
|
+
const fileSystem = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
|
|
196
|
+
let content;
|
|
197
|
+
try {
|
|
198
|
+
content = fileSystem.readFileSync(validated.artifact.path);
|
|
135
199
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
|
|
140
|
-
status: 'planned',
|
|
141
|
-
changed: true,
|
|
142
|
-
operations,
|
|
143
|
-
error: null
|
|
144
|
-
};
|
|
200
|
+
catch (error) {
|
|
201
|
+
return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
|
|
145
202
|
}
|
|
203
|
+
const prepared = prepareReviewSummaryCandidate(request, content, options);
|
|
204
|
+
if (request.dryRun)
|
|
205
|
+
return prepared.result;
|
|
206
|
+
if (prepared.result.status !== 'applied')
|
|
207
|
+
return commitReviewSummaryProvenance(prepared, resolved.repoRoot);
|
|
146
208
|
const tempPath = path.join(resolved.taskDir, `.${request.artifact}.tmp-${process.pid}-${(options.randomSuffix ?? randomUUID)()}`);
|
|
147
|
-
let mode;
|
|
148
209
|
try {
|
|
149
|
-
|
|
150
|
-
fileSystem.writeFileSync(tempPath, transformed.content, mode);
|
|
210
|
+
fileSystem.writeFileSync(tempPath, prepared.content, fileSystem.statModeSync(validated.artifact.path));
|
|
151
211
|
}
|
|
152
212
|
catch (error) {
|
|
153
213
|
cleanupTemp(fileSystem, tempPath);
|
|
154
|
-
return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, stageStatus);
|
|
214
|
+
return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, prepared.result.stageStatus);
|
|
155
215
|
}
|
|
156
216
|
try {
|
|
157
|
-
if (fileSystem.readFileSync(validated.artifact.path) !==
|
|
217
|
+
if (fileSystem.readFileSync(validated.artifact.path) !== content) {
|
|
158
218
|
cleanupTemp(fileSystem, tempPath);
|
|
159
|
-
return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, stageStatus);
|
|
219
|
+
return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, prepared.result.stageStatus);
|
|
160
220
|
}
|
|
161
221
|
fileSystem.renameSync(tempPath, validated.artifact.path);
|
|
162
222
|
}
|
|
163
223
|
catch (error) {
|
|
164
224
|
cleanupTemp(fileSystem, tempPath);
|
|
165
|
-
return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, stageStatus);
|
|
225
|
+
return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, prepared.result.stageStatus);
|
|
166
226
|
}
|
|
167
|
-
return
|
|
168
|
-
status: 'applied',
|
|
169
|
-
changed: true,
|
|
170
|
-
intent: 'finalize-summary',
|
|
171
|
-
requestRef: request.taskRef,
|
|
172
|
-
taskId: resolved.taskId,
|
|
173
|
-
stage,
|
|
174
|
-
artifact: request.artifact,
|
|
175
|
-
stageStatus,
|
|
176
|
-
operations,
|
|
177
|
-
error: null
|
|
178
|
-
};
|
|
227
|
+
return commitReviewSummaryProvenance(prepared, resolved.repoRoot);
|
|
179
228
|
}
|
|
180
229
|
function finalizeReviewSummary(request, options = {}) {
|
|
181
230
|
if (request.dryRun || options.lockAlreadyHeld)
|
|
@@ -192,5 +241,5 @@ function finalizeReviewSummary(request, options = {}) {
|
|
|
192
241
|
return failed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
|
|
193
242
|
}
|
|
194
243
|
}
|
|
195
|
-
export { finalizeReviewSummary };
|
|
244
|
+
export { finalizeReviewSummary, prepareReviewSummaryCandidate, commitReviewSummaryProvenance };
|
|
196
245
|
//# sourceMappingURL=review-finalization.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { artifactName,
|
|
3
|
+
import { artifactName, maxArtifactRound } from "./artifact-name.js";
|
|
4
4
|
import { invalidationBlocks, isArtifactInvalidated, parseInvalidationDocument } from "./invalidation.js";
|
|
5
5
|
const REVIEWED_TREE_RE = /^[a-f0-9]{40,64}$/;
|
|
6
6
|
export function parseReviewedGitTree(value) {
|
|
@@ -29,7 +29,7 @@ export function resolvePostReviewGlobs(config = {}, reviewConfig = {}) {
|
|
|
29
29
|
}
|
|
30
30
|
export function findAuthoritativeReviewCodeArtifact(taskDir) {
|
|
31
31
|
const entries = fs.existsSync(taskDir) ? fs.readdirSync(taskDir) : [];
|
|
32
|
-
const round =
|
|
32
|
+
const round = maxArtifactRound(entries, "review-code");
|
|
33
33
|
if (round === 0) {
|
|
34
34
|
return { ok: false, round: 0, fileName: null, path: null, error: null };
|
|
35
35
|
}
|