@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,117 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { appendActivityEntry, locateActivityLog } from './activity-log.ts';
|
|
5
|
+
import { CONFIRMATION_COLUMNS, CONFIRMATION_HEADINGS, constraintDigest, parseQualificationConfirmations, parseTaskQualification } from './qualification-audit.ts';
|
|
6
|
+
import type { QualificationConfirmation } from './qualification-audit.ts';
|
|
7
|
+
import { findSectionHeading } from './sections.ts';
|
|
8
|
+
import { resolveTaskRef } from './resolve-ref.ts';
|
|
9
|
+
import { captureTaskWriteMetadata, writeTask } from './write.ts';
|
|
10
|
+
import type { TaskOperationSummary, TaskWriteOptions } from './write.ts';
|
|
11
|
+
|
|
12
|
+
type QualificationConfirmationRequest = {
|
|
13
|
+
taskRef: string;
|
|
14
|
+
constraintId: string;
|
|
15
|
+
expectedDigest: string;
|
|
16
|
+
rationale: string;
|
|
17
|
+
operation?: 'confirm' | 'supersede' | 'revoke';
|
|
18
|
+
dryRun?: boolean;
|
|
19
|
+
};
|
|
20
|
+
type QualificationConfirmationResult = {
|
|
21
|
+
status: 'planned' | 'applied' | 'no-op' | 'failed';
|
|
22
|
+
changed: boolean;
|
|
23
|
+
taskId: string | null;
|
|
24
|
+
qcrId: string | null;
|
|
25
|
+
requestId: string | null;
|
|
26
|
+
operations: readonly TaskOperationSummary[];
|
|
27
|
+
error: { code: string; message: string } | null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function failed(code: string, message: string, taskId: string | null = null): QualificationConfirmationResult {
|
|
31
|
+
return { status: 'failed', changed: false, taskId, qcrId: null, requestId: null, operations: [], error: { code, message } };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function nextQcrId(content: string): string {
|
|
35
|
+
let max = 0;
|
|
36
|
+
for (const match of content.matchAll(/^\|\s*(QCR-(\d+))\s*\|/gm)) max = Math.max(max, Number(match[2]));
|
|
37
|
+
return `QCR-${max + 1}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requestIdFor(taskId: string, constraintId: string, expectedDigest: string, rationale: string, timestamp: string): string {
|
|
41
|
+
const hash = createHash('sha256').update(JSON.stringify([taskId, constraintId, expectedDigest, rationale, timestamp])).digest('hex');
|
|
42
|
+
return `QCR-REQUEST-${hash.slice(0, 20)}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function renderConfirmations(rows: readonly QualificationConfirmation[]): string {
|
|
46
|
+
return [
|
|
47
|
+
`| ${CONFIRMATION_COLUMNS.join(' | ')} |`,
|
|
48
|
+
`| ${CONFIRMATION_COLUMNS.map(() => '---').join(' | ')} |`,
|
|
49
|
+
...rows.map((row) => [row.qcrId, row.constraintId, row.actor, row.entrypoint, row.requestId, row.approvedDigest, row.confirmedAt, row.rationale]
|
|
50
|
+
.map((value) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/[\r\n]/g, ' '))
|
|
51
|
+
.join(' | ')).map((line) => `| ${line} |`)
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function applyQualificationConfirmation(request: QualificationConfirmationRequest, options: TaskWriteOptions = {}): QualificationConfirmationResult {
|
|
56
|
+
if (!request || typeof request !== 'object' || !request.taskRef || !/^C-[1-9]\d*$/.test(request.constraintId) || !/^[a-f0-9]{64}$/i.test(request.expectedDigest) || !request.rationale?.trim() || /[\r\n]/.test(request.rationale)) {
|
|
57
|
+
return failed('QUALIFICATION_CONFIRMATION_INVALID', 'taskRef, constraintId, expectedDigest, and a single-line rationale are required');
|
|
58
|
+
}
|
|
59
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
60
|
+
if (!resolved.ok) return failed(resolved.code, resolved.message, resolved.taskId);
|
|
61
|
+
if (resolved.state !== 'active') return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
|
|
62
|
+
let content: string;
|
|
63
|
+
try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
|
|
64
|
+
catch (error) { return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
|
|
65
|
+
const parsed = parseTaskQualification(content);
|
|
66
|
+
if (!parsed.ok) return failed(parsed.code, parsed.message, resolved.taskId);
|
|
67
|
+
if (!parsed.qualification.present) return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
|
|
68
|
+
const constraint = parsed.qualification.constraints.find((row) => row.constraintId === request.constraintId);
|
|
69
|
+
if (!constraint) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `unknown constraint '${request.constraintId}'`, resolved.taskId);
|
|
70
|
+
const operation = request.operation ?? 'confirm';
|
|
71
|
+
const existing = parseQualificationConfirmations(content);
|
|
72
|
+
if (!existing.ok) return failed(existing.code, existing.message, resolved.taskId);
|
|
73
|
+
const previous = existing.confirmations.find((row) => row.qcrId === constraint.approvalEvidence);
|
|
74
|
+
if (operation === 'confirm' && constraint.status === 'confirmed') {
|
|
75
|
+
if (previous?.constraintId === constraint.constraintId && previous.approvedDigest === constraint.digest && previous.rationale === request.rationale.trim()) {
|
|
76
|
+
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: previous.qcrId, requestId: previous.requestId, operations: [], error: null };
|
|
77
|
+
}
|
|
78
|
+
return failed('QUALIFICATION_CONFIRMATION_CONFLICT', `constraint '${request.constraintId}' is already confirmed with different evidence`, resolved.taskId);
|
|
79
|
+
}
|
|
80
|
+
const transitionStatus = operation === 'supersede' ? 'superseded' : 'open';
|
|
81
|
+
if (operation !== 'confirm' && constraint.status === transitionStatus && !constraint.approvalEvidence) {
|
|
82
|
+
return { status: 'no-op', changed: false, taskId: resolved.taskId, qcrId: null, requestId: null, operations: [], error: null };
|
|
83
|
+
}
|
|
84
|
+
if (operation !== 'confirm' && constraint.status !== 'confirmed') return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `constraint '${request.constraintId}' is not confirmed`, resolved.taskId);
|
|
85
|
+
if (parsed.qualification.constraintDigest !== request.expectedDigest) return failed('QUALIFICATION_DIGEST_CONFLICT', 'constraint digest changed before human confirmation', resolved.taskId);
|
|
86
|
+
let metadata;
|
|
87
|
+
try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
|
|
88
|
+
catch (error) { return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
|
|
89
|
+
const qcrId = operation === 'confirm' ? nextQcrId(content) : null;
|
|
90
|
+
const requestId = operation === 'confirm' ? requestIdFor(resolved.taskId, request.constraintId, request.expectedDigest, request.rationale.trim(), metadata.timestamp) : null;
|
|
91
|
+
const confirmedConstraint = qcrId ? {
|
|
92
|
+
constraintId: constraint.constraintId, statement: constraint.statement, status: 'confirmed' as const,
|
|
93
|
+
authority: 'human-declared', source: constraint.source, evidence: constraint.evidence,
|
|
94
|
+
derivedFrom: constraint.derivedFrom, approvalEvidence: qcrId
|
|
95
|
+
} : null;
|
|
96
|
+
const confirmation = confirmedConstraint && qcrId && requestId ? {
|
|
97
|
+
qcrId, constraintId: request.constraintId, actor: 'human-declared' as const, entrypoint: 'task-qualification' as const,
|
|
98
|
+
requestId, approvedDigest: constraintDigest(confirmedConstraint), confirmedAt: metadata.timestamp, rationale: request.rationale.trim()
|
|
99
|
+
} : null;
|
|
100
|
+
const confirmations = confirmation ? [...existing.confirmations, confirmation] : existing.confirmations;
|
|
101
|
+
const activity = locateActivityLog(content);
|
|
102
|
+
if (!activity) return failed('QUALIFICATION_ACTIVITY_MISSING', 'task has no unique Activity Log section', resolved.taskId);
|
|
103
|
+
const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
|
|
104
|
+
{
|
|
105
|
+
kind: 'table-row', action: 'upsert', sectionAliases: ['约束', 'Constraints'], columns: ['constraint_id', 'statement', 'status', 'authority', 'source', 'evidence', 'derived_from', 'approval_evidence'], keyColumn: 'constraint_id', key: constraint.constraintId,
|
|
106
|
+
values: { statement: constraint.statement, status: operation === 'confirm' ? 'confirmed' : transitionStatus, authority: operation === 'confirm' ? 'human-declared' : constraint.authority, source: constraint.source, evidence: constraint.evidence, derived_from: constraint.derivedFrom.join(','), approval_evidence: qcrId ?? '' }
|
|
107
|
+
},
|
|
108
|
+
...(operation === 'confirm' ? [{ kind: 'section' as const, aliases: CONFIRMATION_HEADINGS, heading: findSectionHeading(content, [...CONFIRMATION_HEADINGS]), body: renderConfirmations(confirmations) }] : []),
|
|
109
|
+
{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading, body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Qualification Confirmation', agent: 'human', note: operation === 'confirm' ? `${request.constraintId} confirmed → ${qcrId}` : `${request.constraintId} ${operation}d` }) }
|
|
110
|
+
];
|
|
111
|
+
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 });
|
|
112
|
+
if (result.status === 'failed') return failed(result.error.code, result.error.message, result.taskId);
|
|
113
|
+
return { status: result.status, changed: result.changed, taskId: result.taskId, qcrId, requestId, operations: result.operations, error: null };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { applyQualificationConfirmation };
|
|
117
|
+
export type { QualificationConfirmationRequest, QualificationConfirmationResult };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
|
|
3
|
+
import { CONSTRAINT_COLUMNS, CANDIDATE_COLUMNS, parseTaskQualification } from './qualification-audit.ts';
|
|
4
|
+
import type { CandidateStatus, ConstraintStatus } from './qualification-audit.ts';
|
|
5
|
+
import { resolveTaskRef } from './resolve-ref.ts';
|
|
6
|
+
import { captureTaskWriteMetadata, writeTask } from './write.ts';
|
|
7
|
+
import type { TaskOperationSummary, TaskWriteOptions } from './write.ts';
|
|
8
|
+
|
|
9
|
+
type QualificationConstraintProposal = {
|
|
10
|
+
constraintId: string;
|
|
11
|
+
statement: string;
|
|
12
|
+
status: Exclude<ConstraintStatus, 'confirmed'>;
|
|
13
|
+
authority: string;
|
|
14
|
+
source: string;
|
|
15
|
+
evidence: string;
|
|
16
|
+
derivedFrom: readonly string[];
|
|
17
|
+
approvalEvidence: string;
|
|
18
|
+
};
|
|
19
|
+
type QualificationCandidateProposal = {
|
|
20
|
+
candidateId: string;
|
|
21
|
+
statement: string;
|
|
22
|
+
status: Extract<CandidateStatus, 'pending'>;
|
|
23
|
+
constraintIds: readonly string[];
|
|
24
|
+
impact: string;
|
|
25
|
+
evidence: string;
|
|
26
|
+
};
|
|
27
|
+
type QualificationProposalRequest = {
|
|
28
|
+
taskRef: string;
|
|
29
|
+
expectedTaskInputDigest: string;
|
|
30
|
+
constraints?: readonly QualificationConstraintProposal[];
|
|
31
|
+
candidates?: readonly QualificationCandidateProposal[];
|
|
32
|
+
dryRun?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type QualificationProposalResult = {
|
|
35
|
+
status: 'planned' | 'applied' | 'no-op' | 'failed';
|
|
36
|
+
changed: boolean;
|
|
37
|
+
taskId: string | null;
|
|
38
|
+
operations: readonly TaskOperationSummary[];
|
|
39
|
+
error: { code: string; message: string } | null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function failed(code: string, message: string, taskId: string | null = null): QualificationProposalResult {
|
|
43
|
+
return { status: 'failed', changed: false, taskId, operations: [], error: { code, message } };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validSingleLine(value: unknown): value is string {
|
|
47
|
+
return typeof value === 'string' && Boolean(value.trim()) && !/[\r\n]/.test(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function assertProposalKeys(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {
|
|
51
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object`);
|
|
52
|
+
const record = value as Record<string, unknown>;
|
|
53
|
+
const unexpected = Object.keys(record).find((key) => !keys.includes(key));
|
|
54
|
+
if (unexpected) throw new Error(`${label} does not accept '${unexpected}'`);
|
|
55
|
+
return record;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseConstraintProposal(value: unknown): QualificationConstraintProposal {
|
|
59
|
+
const row = assertProposalKeys(value, ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'derivedFrom', 'approvalEvidence'], 'constraint proposal');
|
|
60
|
+
for (const key of ['constraintId', 'statement', 'status', 'authority', 'source', 'evidence', 'approvalEvidence']) {
|
|
61
|
+
if (typeof row[key] !== 'string' || /[\r\n]/.test(row[key] as string)) throw new Error(`constraint proposal '${key}' must be a single-line string`);
|
|
62
|
+
}
|
|
63
|
+
if (!/^C-[1-9]\d*$/.test(row.constraintId as string)) throw new Error(`constraint proposal id '${row.constraintId as string}' is invalid`);
|
|
64
|
+
if (row.status === 'confirmed' || !['derived', 'assumption', 'open', 'conflicted', 'superseded'].includes(row.status as string)) throw new Error('proposal cannot write confirmed constraint status');
|
|
65
|
+
if ((row.approvalEvidence as string) !== '') throw new Error('proposal cannot write approval_evidence');
|
|
66
|
+
if (!Array.isArray(row.derivedFrom) || row.derivedFrom.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item))) throw new Error('constraint proposal derivedFrom is invalid');
|
|
67
|
+
return {
|
|
68
|
+
constraintId: row.constraintId as string, statement: row.statement as string, status: row.status as Exclude<ConstraintStatus, 'confirmed'>,
|
|
69
|
+
authority: row.authority as string, source: row.source as string, evidence: row.evidence as string,
|
|
70
|
+
derivedFrom: [...row.derivedFrom as string[]], approvalEvidence: ''
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseCandidateProposal(value: unknown): QualificationCandidateProposal {
|
|
75
|
+
const row = assertProposalKeys(value, ['candidateId', 'statement', 'status', 'constraintIds', 'impact', 'evidence'], 'candidate proposal');
|
|
76
|
+
for (const key of ['candidateId', 'statement', 'status', 'impact', 'evidence']) if (!validSingleLine(row[key])) throw new Error(`candidate proposal '${key}' must be a non-empty single-line string`);
|
|
77
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(row.candidateId as string)) throw new Error(`candidate proposal id '${row.candidateId as string}' is invalid`);
|
|
78
|
+
if (row.status !== 'pending') throw new Error('proposal can only write pending candidate status');
|
|
79
|
+
if (!Array.isArray(row.constraintIds) || row.constraintIds.some((item) => typeof item !== 'string' || !/^C-[1-9]\d*$/.test(item))) throw new Error('candidate proposal constraintIds is invalid');
|
|
80
|
+
return row as unknown as QualificationCandidateProposal;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function proposalValues(request: QualificationProposalRequest): { constraints: QualificationConstraintProposal[]; candidates: QualificationCandidateProposal[] } {
|
|
84
|
+
if (!/^[a-f0-9]{64}$/i.test(request.expectedTaskInputDigest)) throw new Error('expectedTaskInputDigest must be a sha256 digest');
|
|
85
|
+
if (Object.keys(request).some((key) => !['taskRef', 'expectedTaskInputDigest', 'constraints', 'candidates', 'dryRun'].includes(key))) throw new Error('proposal contains an unsupported field');
|
|
86
|
+
if (!Array.isArray(request.constraints) && request.constraints !== undefined) throw new Error('constraints must be an array');
|
|
87
|
+
if (!Array.isArray(request.candidates) && request.candidates !== undefined) throw new Error('candidates must be an array');
|
|
88
|
+
return {
|
|
89
|
+
constraints: (request.constraints ?? []).map(parseConstraintProposal),
|
|
90
|
+
candidates: (request.candidates ?? []).map(parseCandidateProposal)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function applyQualificationProposal(request: QualificationProposalRequest, options: TaskWriteOptions = {}): QualificationProposalResult {
|
|
95
|
+
if (!request || typeof request !== 'object' || !validSingleLine(request.taskRef)) return failed('QUALIFICATION_PROPOSAL_INVALID', 'taskRef is required');
|
|
96
|
+
let values: ReturnType<typeof proposalValues>;
|
|
97
|
+
try { values = proposalValues(request); }
|
|
98
|
+
catch (error) { return failed('QUALIFICATION_PROPOSAL_INVALID', error instanceof Error ? error.message : String(error)); }
|
|
99
|
+
if (values.constraints.length === 0 && values.candidates.length === 0) return failed('QUALIFICATION_PROPOSAL_INVALID', 'proposal must contain a constraint or candidate');
|
|
100
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
101
|
+
if (!resolved.ok) return failed(resolved.code, resolved.message, resolved.taskId);
|
|
102
|
+
if (resolved.state !== 'active') return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
|
|
103
|
+
let content: string;
|
|
104
|
+
try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
|
|
105
|
+
catch (error) { return failed('TASK_READ_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
|
|
106
|
+
const parsed = parseTaskQualification(content);
|
|
107
|
+
if (!parsed.ok) return failed(parsed.code, parsed.message, resolved.taskId);
|
|
108
|
+
if (!parsed.qualification.present) return failed('QUALIFICATION_TASK_CONTRACT_MISSING', 'task qualification contract is missing', resolved.taskId);
|
|
109
|
+
const currentConstraintMap = new Map(parsed.qualification.constraints.map((row) => [row.constraintId, row]));
|
|
110
|
+
const currentCandidateMap = new Map(parsed.qualification.candidates.map((row) => [row.candidateId, row]));
|
|
111
|
+
const proposalAlreadyApplied = values.constraints.every((row) => {
|
|
112
|
+
const current = currentConstraintMap.get(row.constraintId);
|
|
113
|
+
return current && current.statement === row.statement && current.status === row.status && current.authority === row.authority
|
|
114
|
+
&& current.source === row.source && current.evidence === row.evidence && current.derivedFrom.join(',') === row.derivedFrom.join(',') && current.approvalEvidence === '';
|
|
115
|
+
}) && values.candidates.every((row) => {
|
|
116
|
+
const current = currentCandidateMap.get(row.candidateId);
|
|
117
|
+
return current && current.statement === row.statement && current.status === row.status && current.constraintIds.join(',') === row.constraintIds.join(',')
|
|
118
|
+
&& current.impact === row.impact && current.evidence === row.evidence;
|
|
119
|
+
});
|
|
120
|
+
if (parsed.qualification.taskInputDigest !== request.expectedTaskInputDigest) {
|
|
121
|
+
return proposalAlreadyApplied
|
|
122
|
+
? { status: 'no-op', changed: false, taskId: resolved.taskId, operations: [], error: null }
|
|
123
|
+
: failed('QUALIFICATION_DIGEST_CONFLICT', 'task qualification input changed before proposal was applied', resolved.taskId);
|
|
124
|
+
}
|
|
125
|
+
for (const row of values.constraints) {
|
|
126
|
+
const current = currentConstraintMap.get(row.constraintId);
|
|
127
|
+
if (current?.status === 'confirmed') return failed('QUALIFICATION_CONFIRMATION_REQUIRED', `confirmed constraint '${row.constraintId}' must be superseded or revoked through task-qualification`, resolved.taskId);
|
|
128
|
+
}
|
|
129
|
+
const knownConstraintIds = new Set([...parsed.qualification.constraints.map((row) => row.constraintId), ...values.constraints.map((row) => row.constraintId)]);
|
|
130
|
+
for (const row of values.constraints) for (const parent of row.derivedFrom) if (!knownConstraintIds.has(parent)) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `constraint proposal '${row.constraintId}' references unknown '${parent}'`, resolved.taskId);
|
|
131
|
+
for (const row of values.candidates) for (const id of row.constraintIds) if (!knownConstraintIds.has(id)) return failed('QUALIFICATION_CONSTRAINT_UNKNOWN', `candidate proposal '${row.candidateId}' references unknown '${id}'`, resolved.taskId);
|
|
132
|
+
const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [];
|
|
133
|
+
for (const row of values.constraints) {
|
|
134
|
+
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: '' } });
|
|
135
|
+
}
|
|
136
|
+
for (const row of values.candidates) {
|
|
137
|
+
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 } });
|
|
138
|
+
}
|
|
139
|
+
// Only the submitted rows are mutated; no actor, confirmation, or QCR fields
|
|
140
|
+
// can be smuggled into this internal proposal operation.
|
|
141
|
+
let metadata;
|
|
142
|
+
try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
|
|
143
|
+
catch (error) { return failed('METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId); }
|
|
144
|
+
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 });
|
|
145
|
+
if (result.status === 'failed') return failed(result.error.code, result.error.message, result.taskId);
|
|
146
|
+
return { status: result.status, changed: result.changed, taskId: result.taskId, operations: result.operations, error: null };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { applyQualificationProposal };
|
|
150
|
+
export type { QualificationCandidateProposal, QualificationConstraintProposal, QualificationProposalRequest, QualificationProposalResult };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
import { scanVisibleMarkdown } from './markdown.ts';
|
|
5
|
+
|
|
4
6
|
type ReviewFindingCounts = {
|
|
5
7
|
blocker: number;
|
|
6
8
|
major: number;
|
|
@@ -51,23 +53,6 @@ function escapeRegExp(value: string): string {
|
|
|
51
53
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
function maxRound(entries: string[], stem: string): number {
|
|
55
|
-
let max = 0;
|
|
56
|
-
for (const entry of entries) {
|
|
57
|
-
if (entry === `${stem}.md`) {
|
|
58
|
-
max = Math.max(max, 1);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
|
|
62
|
-
if (match) max = Math.max(max, Number(match[1]));
|
|
63
|
-
}
|
|
64
|
-
return max;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function artifactName(stem: string, round: number): string {
|
|
68
|
-
return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
function normalizeVerdict(raw: unknown): ReviewVerdict | '' {
|
|
72
57
|
const value = String(raw).trim().toLowerCase();
|
|
73
58
|
if (value === '通过' || value === 'approved') return 'Approved';
|
|
@@ -77,29 +62,21 @@ function normalizeVerdict(raw: unknown): ReviewVerdict | '' {
|
|
|
77
62
|
}
|
|
78
63
|
|
|
79
64
|
function extractSection(content: string, names: string[]): string {
|
|
80
|
-
const lines = content.split(/\r?\n/);
|
|
81
65
|
const nameSet = new Set(names);
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const sectionLines = [];
|
|
88
|
-
for (let index = start + 1; index < lines.length; index += 1) {
|
|
89
|
-
if (/^##\s+/.test(lines[index]!)) break;
|
|
90
|
-
sectionLines.push(lines[index]);
|
|
91
|
-
}
|
|
92
|
-
return sectionLines.join('\n');
|
|
66
|
+
const scanned = scanVisibleMarkdown(content);
|
|
67
|
+
const heading = scanned.headings.find((item) => item.level === 2 && nameSet.has(item.text));
|
|
68
|
+
if (!heading) return '';
|
|
69
|
+
const next = scanned.headings.find((item) => item.start > heading.start && item.level <= 2);
|
|
70
|
+
return content.slice(heading.end, next?.start ?? content.length);
|
|
93
71
|
}
|
|
94
72
|
|
|
95
73
|
function summaryBounds(content: string): { start: number; end: number } | null {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
const summaries = headings.filter((heading) => SUMMARY_HEADINGS.has(heading.name));
|
|
74
|
+
const scanned = scanVisibleMarkdown(content);
|
|
75
|
+
const summaries = scanned.headings.filter((heading) => heading.level === 2 && SUMMARY_HEADINGS.has(heading.text));
|
|
99
76
|
if (summaries.length !== 1) return null;
|
|
100
77
|
const summary = summaries[0]!;
|
|
101
|
-
const next = headings.find((heading) => heading.
|
|
102
|
-
return { start: summary.end, end: next?.
|
|
78
|
+
const next = scanned.headings.find((heading) => heading.start > summary.start && heading.level <= 2);
|
|
79
|
+
return { start: summary.end, end: next?.start ?? content.length };
|
|
103
80
|
}
|
|
104
81
|
|
|
105
82
|
function uniqueLine(
|
|
@@ -107,14 +84,19 @@ function uniqueLine(
|
|
|
107
84
|
bounds: { start: number; end: number },
|
|
108
85
|
pattern: RegExp
|
|
109
86
|
): { value: string; start: number; end: number } | null {
|
|
110
|
-
const
|
|
111
|
-
const
|
|
87
|
+
const matches: Array<{ value: string; index: number; length: number }> = [];
|
|
88
|
+
for (const line of scanVisibleMarkdown(content).lines) {
|
|
89
|
+
if (line.start < bounds.start || line.start >= bounds.end) continue;
|
|
90
|
+
pattern.lastIndex = 0;
|
|
91
|
+
const match = pattern.exec(line.text);
|
|
92
|
+
if (match) matches.push({ value: match[1]!, index: line.start + match.index, length: match[0].length });
|
|
93
|
+
}
|
|
112
94
|
if (matches.length !== 1) return null;
|
|
113
95
|
const match = matches[0]!;
|
|
114
96
|
return {
|
|
115
|
-
value: match
|
|
116
|
-
start:
|
|
117
|
-
end:
|
|
97
|
+
value: match.value,
|
|
98
|
+
start: match.index,
|
|
99
|
+
end: match.index + match.length
|
|
118
100
|
};
|
|
119
101
|
}
|
|
120
102
|
|
|
@@ -261,12 +243,10 @@ function parseVerdict(reviewPath: string): PathVerdictResult {
|
|
|
261
243
|
}
|
|
262
244
|
|
|
263
245
|
export {
|
|
264
|
-
artifactName,
|
|
265
246
|
equalCounts,
|
|
266
247
|
escapeRegExp,
|
|
267
248
|
extractSection,
|
|
268
249
|
finalizeReviewSummaryContent,
|
|
269
|
-
maxRound,
|
|
270
250
|
normalizeVerdict,
|
|
271
251
|
parseReviewSummary,
|
|
272
252
|
parseVerdict,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReviewFinalizationRequest } from './review-finalization.ts';
|
|
2
|
+
|
|
3
|
+
export function parseReviewCommand(args: readonly string[]): ReviewFinalizationRequest & {
|
|
4
|
+
overrideTicket?: string; overrideTarget?: string; overrideScope?: string;
|
|
5
|
+
} {
|
|
6
|
+
if (!args[0] || args[1] !== 'finalize-summary') throw new Error('task ref and finalize-summary are required');
|
|
7
|
+
const values: Record<string, string | boolean> = {};
|
|
8
|
+
const flags = {
|
|
9
|
+
'--stage': 'stage', '--artifact': 'artifact', '--orchestrated': 'orchestrated', '--dry-run': 'dryRun',
|
|
10
|
+
'--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
|
|
11
|
+
} as const;
|
|
12
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
13
|
+
const flag = args[index]!;
|
|
14
|
+
if (!Object.hasOwn(flags, flag)) throw new Error(`unknown option '${flag}'`);
|
|
15
|
+
const key = flags[flag as keyof typeof flags];
|
|
16
|
+
if (Object.hasOwn(values, key)) throw new Error(`duplicate option '${flag}'`);
|
|
17
|
+
const value = flag === '--orchestrated' || flag === '--dry-run' ? true : args[++index];
|
|
18
|
+
if (!value || typeof value === 'string' && value.startsWith('--')) throw new Error(`option '${flag}' requires a value`);
|
|
19
|
+
values[key] = value;
|
|
20
|
+
}
|
|
21
|
+
if (!values.stage || !values.artifact) throw new Error("options '--stage' and '--artifact' are required");
|
|
22
|
+
return { taskRef: args[0], ...values } as ReturnType<typeof parseReviewCommand>;
|
|
23
|
+
}
|