@fitlab-ai/agent-infra 0.9.11 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/README.zh-CN.md +13 -13
- package/dist/bin/internal-cli.js +29 -19
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
- package/dist/lib/agent-clients/next-steps.js +6 -1
- package/dist/lib/decide.js +3 -3
- package/dist/lib/defaults.json +4 -0
- package/dist/lib/git/workflow.js +43 -1
- package/dist/lib/init.js +1 -0
- package/dist/lib/internal/git-workflow.js +8 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +9 -9
- package/dist/lib/internal/platform-context.js +2 -2
- package/dist/lib/internal/platform-issue.js +8 -9
- package/dist/lib/internal/platform-pr-review.js +10 -10
- package/dist/lib/internal/platform-pr.js +68 -23
- package/dist/lib/internal/platform-release-notes.js +3 -3
- package/dist/lib/internal/pr-review-grade.js +11 -9
- package/dist/lib/internal/release-workflow.js +4 -4
- package/dist/lib/internal/sandbox-control.js +30 -4
- package/dist/lib/internal/task-activity.js +3 -3
- package/dist/lib/internal/task-artifact.js +76 -24
- package/dist/lib/internal/task-create.js +2 -2
- package/dist/lib/internal/task-delivery.js +59 -0
- package/dist/lib/internal/task-event.js +6 -3
- package/dist/lib/internal/task-finalization.js +2 -2
- package/dist/lib/internal/task-invalidation.js +60 -0
- package/dist/lib/internal/task-ledger.js +9 -6
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-override.js +4 -4
- package/dist/lib/internal/task-review.js +3 -3
- package/dist/lib/internal/task-verify.js +6 -6
- package/dist/lib/internal/task-warning.js +3 -3
- package/dist/lib/platform/adapters.js +1 -3
- package/dist/lib/platform/change-request-git-evidence.js +27 -7
- package/dist/lib/platform/completion-backfill.js +6 -5
- package/dist/lib/platform/context.js +70 -130
- package/dist/lib/platform/github-client.js +8 -2
- package/dist/lib/platform/github-provider.js +903 -0
- package/dist/lib/platform/in-label-sync.js +143 -0
- package/dist/lib/platform/issue-comments.js +94 -41
- package/dist/lib/platform/issues.js +335 -189
- package/dist/lib/platform/metadata-labels.js +6 -2
- package/dist/lib/platform/none-provider.js +28 -0
- package/dist/lib/platform/pr-change-report.js +551 -0
- package/dist/lib/platform/pr-checks.js +124 -106
- package/dist/lib/platform/pr-review.js +88 -72
- package/dist/lib/platform/pr-summary.js +523 -49
- package/dist/lib/platform/provider-bridge.js +45 -0
- package/dist/lib/platform/provider-contract.d.ts +487 -0
- package/dist/lib/platform/provider-contract.js +95 -0
- package/dist/lib/platform/provider-loader.js +251 -0
- package/dist/lib/platform/provider-validation.js +504 -0
- package/dist/lib/platform/pull-request-metadata.js +8 -6
- package/dist/lib/platform/pull-requests.js +1050 -502
- package/dist/lib/platform/release-notes.js +78 -55
- package/dist/lib/platform/releases.js +79 -50
- package/dist/lib/platform/resource-identity.d.ts +26 -0
- package/dist/lib/platform/resource-identity.js +92 -0
- package/dist/lib/platform/task-identities.js +31 -0
- package/dist/lib/platform/verification-required.js +22 -12
- package/dist/lib/platform/verification-sync.js +118 -239
- package/dist/lib/pr-review/evidence-grading.js +30 -9
- package/dist/lib/run/index.js +63 -23
- package/dist/lib/sandbox/config.js +5 -0
- package/dist/lib/sandbox/control/client.js +96 -15
- package/dist/lib/sandbox/control/executor.js +3 -3
- package/dist/lib/sandbox/control/lifecycle.js +29 -7
- package/dist/lib/sandbox/control/protocol.js +77 -0
- package/dist/lib/sandbox/control/server.js +398 -25
- package/dist/lib/sandbox/control/state.js +204 -1
- package/dist/lib/server/process-state.js +2 -2
- package/dist/lib/server/protocol.js +38 -1
- package/dist/lib/task/activity-log.js +8 -1
- package/dist/lib/task/artifact-lifecycle.js +35 -7
- package/dist/lib/task/capabilities.js +239 -0
- package/dist/lib/task/commands/status.js +32 -0
- package/dist/lib/task/commit-intent.js +100 -0
- package/dist/lib/task/commit-operation.js +207 -102
- package/dist/lib/task/control-authority.js +8 -5
- package/dist/lib/task/create-service.js +8 -8
- package/dist/lib/task/create.js +33 -7
- package/dist/lib/task/current-contract.js +5 -1
- package/dist/lib/task/decision-details.js +3 -48
- package/dist/lib/task/delivery-target.js +97 -0
- package/dist/lib/task/delivery.js +153 -0
- package/dist/lib/task/events.js +297 -17
- package/dist/lib/task/finalization.js +37 -13
- package/dist/lib/task/human-override.js +61 -36
- package/dist/lib/task/invalidation-command.js +86 -0
- package/dist/lib/task/invalidation.js +260 -0
- package/dist/lib/task/ledger-intents.js +37 -0
- package/dist/lib/task/lifecycle.js +106 -9
- package/dist/lib/task/local-artifact-finalization.js +374 -0
- package/dist/lib/task/orchestration.js +100 -151
- package/dist/lib/task/pr-delivery-fact.js +183 -0
- package/dist/lib/task/review-finalization.js +4 -8
- package/dist/lib/task/review-fingerprint.js +32 -2
- package/dist/lib/task/rework-intent.js +138 -0
- package/dist/lib/task/skill-scope.js +23 -0
- package/dist/lib/task/task-execution-lock.js +27 -17
- package/dist/lib/task/verification-engine.js +89 -38
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +3 -3
- package/dist/lib/task/workflow-warning-intents.js +1 -1
- package/dist/lib/task/write.js +11 -0
- package/dist/lib/update.js +9 -0
- package/dist/lib/version.js +11 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
- package/lib/agent-clients/next-steps.ts +6 -1
- package/lib/decide.ts +3 -3
- package/lib/defaults.json +4 -0
- package/lib/git/workflow.ts +38 -1
- package/lib/init.ts +4 -1
- package/lib/internal/git-workflow.ts +7 -1
- package/lib/internal/platform-checks.ts +3 -3
- package/lib/internal/platform-comment.ts +8 -8
- package/lib/internal/platform-context.ts +2 -2
- package/lib/internal/platform-issue.ts +7 -8
- package/lib/internal/platform-pr-review.ts +9 -9
- package/lib/internal/platform-pr.ts +53 -21
- package/lib/internal/platform-release-notes.ts +3 -3
- package/lib/internal/pr-review-grade.ts +10 -8
- package/lib/internal/release-workflow.ts +4 -4
- package/lib/internal/sandbox-control.ts +27 -3
- package/lib/internal/task-activity.ts +3 -3
- package/lib/internal/task-artifact.ts +65 -22
- package/lib/internal/task-create.ts +2 -2
- package/lib/internal/task-delivery.ts +53 -0
- package/lib/internal/task-event.ts +6 -3
- package/lib/internal/task-finalization.ts +3 -3
- package/lib/internal/task-invalidation.ts +39 -0
- package/lib/internal/task-ledger.ts +11 -8
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-override.ts +6 -6
- package/lib/internal/task-review.ts +3 -3
- package/lib/internal/task-verify.ts +6 -6
- package/lib/internal/task-warning.ts +3 -3
- package/lib/platform/adapters.ts +3 -2
- package/lib/platform/change-request-git-evidence.ts +36 -9
- package/lib/platform/completion-backfill.ts +9 -8
- package/lib/platform/context.ts +97 -134
- package/lib/platform/github-client.ts +10 -3
- package/lib/platform/github-provider.ts +910 -0
- package/lib/platform/in-label-sync.ts +208 -0
- package/lib/platform/issue-comments.ts +97 -47
- package/lib/platform/issues.ts +344 -174
- package/lib/platform/metadata-labels.ts +5 -2
- package/lib/platform/none-provider.ts +35 -0
- package/lib/platform/pr-change-report.ts +645 -0
- package/lib/platform/pr-checks.ts +129 -107
- package/lib/platform/pr-review.ts +88 -85
- package/lib/platform/pr-summary.ts +562 -52
- package/lib/platform/provider-bridge.ts +82 -0
- package/lib/platform/provider-contract.ts +536 -0
- package/lib/platform/provider-loader.ts +307 -0
- package/lib/platform/provider-validation.ts +529 -0
- package/lib/platform/pull-request-metadata.ts +10 -7
- package/lib/platform/pull-requests.ts +1126 -505
- package/lib/platform/release-notes.ts +76 -59
- package/lib/platform/releases.ts +77 -43
- package/lib/platform/resource-identity.ts +121 -0
- package/lib/platform/task-identities.ts +40 -0
- package/lib/platform/types.ts +4 -2
- package/lib/platform/verification-required.ts +21 -13
- package/lib/platform/verification-sync.ts +118 -293
- package/lib/pr-review/evidence-grading.ts +31 -11
- package/lib/run/index.ts +57 -22
- package/lib/sandbox/config.ts +7 -0
- package/lib/sandbox/control/client.ts +105 -15
- package/lib/sandbox/control/executor.ts +4 -4
- package/lib/sandbox/control/lifecycle.ts +30 -8
- package/lib/sandbox/control/protocol.ts +113 -0
- package/lib/sandbox/control/server.ts +431 -23
- package/lib/sandbox/control/state.ts +251 -1
- package/lib/server/process-state.ts +2 -2
- package/lib/server/protocol.ts +36 -1
- package/lib/task/activity-log.ts +8 -0
- package/lib/task/artifact-lifecycle.ts +34 -8
- package/lib/task/capabilities.ts +262 -0
- package/lib/task/commands/status.ts +38 -0
- package/lib/task/commit-intent.ts +137 -0
- package/lib/task/commit-operation.ts +186 -88
- package/lib/task/control-authority.ts +11 -8
- package/lib/task/create-service.ts +8 -8
- package/lib/task/create.ts +34 -9
- package/lib/task/current-contract.ts +6 -1
- package/lib/task/decision-details.ts +8 -64
- package/lib/task/delivery-target.ts +130 -0
- package/lib/task/delivery.ts +160 -0
- package/lib/task/events.ts +296 -16
- package/lib/task/finalization.ts +50 -14
- package/lib/task/human-override.ts +73 -46
- package/lib/task/invalidation-command.ts +86 -0
- package/lib/task/invalidation.ts +332 -0
- package/lib/task/ledger-intents.ts +35 -1
- package/lib/task/lifecycle.ts +93 -4
- package/lib/task/local-artifact-finalization.ts +563 -0
- package/lib/task/orchestration.ts +110 -146
- package/lib/task/pr-delivery-fact.ts +237 -0
- package/lib/task/review-finalization.ts +4 -14
- package/lib/task/review-fingerprint.ts +33 -2
- package/lib/task/rework-intent.ts +165 -0
- package/lib/task/skill-scope.ts +24 -0
- package/lib/task/task-execution-lock.ts +23 -14
- package/lib/task/verification-engine.ts +95 -43
- package/lib/task/verification-review.ts +2 -0
- package/lib/task/verification.ts +4 -4
- package/lib/task/workflow-warning-intents.ts +1 -1
- package/lib/task/write.ts +19 -0
- package/lib/update.ts +11 -1
- package/lib/version.ts +15 -1
- package/package.json +7 -1
- package/templates/.agents/rules/README.en.md +4 -2
- package/templates/.agents/rules/README.zh-CN.md +4 -2
- package/templates/.agents/rules/create-issue.en.md +11 -2
- package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
- package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +28 -5
- package/templates/.agents/rules/issue-sync.zh-CN.md +64 -5
- package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
- package/templates/.agents/rules/local-artifact-repair.en.md +53 -0
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +53 -0
- package/templates/.agents/rules/milestone-inference.en.md +12 -2
- package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
- package/templates/.agents/rules/pr-sync.en.md +28 -13
- package/templates/.agents/rules/pr-sync.zh-CN.md +39 -5
- package/templates/.agents/rules/release-commands.en.md +42 -3
- package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
- package/templates/.agents/rules/security-alerts.en.md +17 -2
- package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
- package/templates/.agents/rules/sync-content-generation.en.md +8 -0
- package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
- package/templates/.agents/rules/task-management.en.md +1 -1
- package/templates/.agents/rules/task-management.zh-CN.md +1 -1
- package/templates/.agents/rules/task-short-id.en.md +1 -4
- package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
- package/templates/.agents/scripts/security-alerts.github.sh +151 -0
- package/templates/.agents/scripts/security-alerts.sh +31 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +14 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +32 -10
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +35 -13
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/commit/SKILL.en.md +3 -3
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/config/verify.json +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +4 -4
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +7 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +5 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +5 -4
- package/templates/.agents/skills/complete-task/SKILL.en.md +31 -13
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +30 -13
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.en.md +11 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/create-pr/config/verify.json +1 -0
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
- package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
- package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +11 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +6 -5
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +6 -5
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +10 -9
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +10 -9
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +6 -5
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +6 -5
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +6 -6
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
- package/templates/.agents/templates/task.en.md +23 -2
- package/templates/.agents/templates/task.zh-CN.md +23 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/feature-development.en.yaml +9 -8
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
- package/templates/.agents/workflows/refactoring.en.yaml +9 -8
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
- package/templates/.github/workflows/pr-label.yml +7 -26
- package/templates/.agents/rules/create-issue.github.en.md +0 -14
- package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
- package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
- package/templates/.agents/rules/issue-sync.github.en.md +0 -40
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
- package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
- package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
- package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
- package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
- package/templates/.agents/rules/pr-sync.github.en.md +0 -43
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
- package/templates/.agents/rules/release-commands.github.en.md +0 -44
- package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
- package/templates/.agents/rules/security-alerts.github.en.md +0 -43
- package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
- /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
- /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
|
@@ -15,7 +15,7 @@ import { inspectLifecycleExecution } from './lifecycle-execution.ts';
|
|
|
15
15
|
import { applyLedgerIntent } from './ledger-intents.ts';
|
|
16
16
|
import { bindPlatformIssue } from '../platform/issues.ts';
|
|
17
17
|
import { bindPlatformPullRequest } from '../platform/pull-requests.ts';
|
|
18
|
-
import type {
|
|
18
|
+
import type { PlatformClient } from '../platform/context.ts';
|
|
19
19
|
import { finalizeReviewSummary } from './review-finalization.ts';
|
|
20
20
|
import { resolveTaskRef } from './resolve-ref.ts';
|
|
21
21
|
import { DocumentMutationError, parseTable } from './sections.ts';
|
|
@@ -24,6 +24,10 @@ import { verifyTaskEvent } from './verification.ts';
|
|
|
24
24
|
import { verifyInProcess } from './verification-engine.ts';
|
|
25
25
|
import { canonicalTimestamp, writeTask } from './write.ts';
|
|
26
26
|
import type { TaskFileSystem, TaskWriteMetadata, TaskWriteResult } from './write.ts';
|
|
27
|
+
import { readPrDeliveryFact } from './pr-delivery-fact.ts';
|
|
28
|
+
import { resourceIdentity, resourceIdentityNumber } from '../platform/provider-bridge.ts';
|
|
29
|
+
import type { ResourceIdentity } from '../platform/resource-identity.ts';
|
|
30
|
+
import { taskIssueIdentity } from '../platform/task-identities.ts';
|
|
27
31
|
|
|
28
32
|
type Eligibility = 'eligible' | 'repair-only' | 'runtime-recovery-only' | 'never-overridable';
|
|
29
33
|
type OutcomeEffect = 'apply-target' | 'retry-same-intent' | 'record-only' | 'no-write';
|
|
@@ -95,8 +99,8 @@ type HumanOverrideOptions = Readonly<{
|
|
|
95
99
|
probeIssueNumber?: number;
|
|
96
100
|
probePullRequestNumber?: number;
|
|
97
101
|
probeStagingDir?: string;
|
|
98
|
-
platformClient?:
|
|
99
|
-
effectExecutor?: (capability: ManualOverrideCapability) => OverrideError | null
|
|
102
|
+
platformClient?: PlatformClient;
|
|
103
|
+
effectExecutor?: (capability: ManualOverrideCapability) => OverrideError | null | Promise<OverrideError | null>;
|
|
100
104
|
}>;
|
|
101
105
|
|
|
102
106
|
type FailureSnapshot = Readonly<{
|
|
@@ -583,7 +587,7 @@ function snapshotEvidence(
|
|
|
583
587
|
content: string,
|
|
584
588
|
frontmatter: Record<string, unknown> | null,
|
|
585
589
|
producer: ProducerFailure,
|
|
586
|
-
resource: Readonly<{ kind: 'issue' | 'pull-request'; number: number }> | null
|
|
590
|
+
resource: Readonly<{ kind: 'issue' | 'pull-request'; identity: ResourceIdentity; number: number | null }> | null
|
|
587
591
|
): string {
|
|
588
592
|
const stableFrontmatter = frontmatter
|
|
589
593
|
? Object.fromEntries(Object.entries(frontmatter).filter(([key]) => !['updated_at', 'agent_infra_version', 'status', 'blocked_at', 'completed_at', 'cancelled_at'].includes(key)))
|
|
@@ -608,14 +612,22 @@ function resourceForSnapshot(
|
|
|
608
612
|
policy: FailurePolicy,
|
|
609
613
|
options: HumanOverrideOptions,
|
|
610
614
|
frontmatter: Record<string, unknown> | null
|
|
611
|
-
): Readonly<{ kind: 'issue' | 'pull-request'; number: number }> | null {
|
|
615
|
+
): Readonly<{ kind: 'issue' | 'pull-request'; identity: ResourceIdentity; number: number | null }> | null {
|
|
612
616
|
if (policy.producerId === 'platform.issue') {
|
|
613
|
-
const
|
|
614
|
-
|
|
617
|
+
const identity = options.probeIssueNumber !== undefined
|
|
618
|
+
? resourceIdentity(options.probeIssueNumber)
|
|
619
|
+
: taskIssueIdentity((frontmatter || {}) as Record<string, string | number | boolean | null>) || (() => {
|
|
620
|
+
const number = toPositiveInteger(frontmatter?.issue_number);
|
|
621
|
+
return number === null ? null : resourceIdentity(number);
|
|
622
|
+
})();
|
|
623
|
+
return identity ? { kind: 'issue', identity, number: resourceIdentityNumber(identity) } : null;
|
|
615
624
|
}
|
|
616
625
|
if (policy.producerId === 'platform.pull-request') {
|
|
617
|
-
const
|
|
618
|
-
|
|
626
|
+
const fact = frontmatter ? readPrDeliveryFact(frontmatter) : null;
|
|
627
|
+
const identity = options.probePullRequestNumber !== undefined
|
|
628
|
+
? resourceIdentity(options.probePullRequestNumber)
|
|
629
|
+
: fact?.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
|
|
630
|
+
return identity ? { kind: 'pull-request', identity, number: resourceIdentityNumber(identity) } : null;
|
|
619
631
|
}
|
|
620
632
|
return null;
|
|
621
633
|
}
|
|
@@ -692,40 +704,52 @@ function probeNotObserved(policy: FailurePolicy): OverrideError {
|
|
|
692
704
|
return error('OVERRIDE_FAILURE_NOT_PRESENT', `producer ${policy.producerId} did not produce ${policy.code}`);
|
|
693
705
|
}
|
|
694
706
|
|
|
695
|
-
function probePlatformFailure(
|
|
707
|
+
async function probePlatformFailure(
|
|
696
708
|
taskRef: string,
|
|
697
709
|
policy: FailurePolicy,
|
|
698
710
|
resolved: ProbeTask,
|
|
699
711
|
options: HumanOverrideOptions
|
|
700
|
-
): ProducerFailure | OverrideError {
|
|
712
|
+
): Promise<ProducerFailure | OverrideError> {
|
|
701
713
|
let frontmatter: ReturnType<typeof parseTypedTaskFrontmatter>;
|
|
702
714
|
try {
|
|
703
715
|
frontmatter = parseTypedTaskFrontmatter(fs.readFileSync(path.join(resolved.taskDir, 'task.md'), 'utf8'));
|
|
704
716
|
} catch (cause) {
|
|
705
717
|
return error('OVERRIDE_DOCUMENT_INVALID', cause instanceof Error ? cause.message : String(cause));
|
|
706
718
|
}
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
719
|
+
const issueIdentity = options.probeIssueNumber !== undefined
|
|
720
|
+
? resourceIdentity(options.probeIssueNumber)
|
|
721
|
+
: taskIssueIdentity(frontmatter) || (() => {
|
|
722
|
+
const number = toPositiveInteger(frontmatter.issue_number);
|
|
723
|
+
return number === null ? null : resourceIdentity(number);
|
|
724
|
+
})();
|
|
725
|
+
const fact = readPrDeliveryFact(frontmatter);
|
|
726
|
+
const pullRequestIdentity = options.probePullRequestNumber !== undefined
|
|
727
|
+
? resourceIdentity(options.probePullRequestNumber)
|
|
728
|
+
: fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.resource : null;
|
|
729
|
+
const token = (identity: ResourceIdentity | null): string | null => identity ? String(identity.value) : null;
|
|
730
|
+
const issueToken = token(issueIdentity);
|
|
731
|
+
const pullRequestToken = token(pullRequestIdentity);
|
|
732
|
+
const operation = await (policy.producerId === 'platform.issue'
|
|
733
|
+
? issueToken === null
|
|
711
734
|
? null
|
|
712
735
|
: bindPlatformIssue(taskRef, {
|
|
713
|
-
issue:
|
|
736
|
+
issue: issueToken,
|
|
714
737
|
agent: options.probeOperator ?? 'local-operator',
|
|
715
738
|
dryRun: true,
|
|
716
739
|
cwd: resolved.repoRoot,
|
|
717
740
|
...(options.platformClient ? { client: options.platformClient } : {})
|
|
718
741
|
})
|
|
719
|
-
:
|
|
742
|
+
: pullRequestToken === null
|
|
720
743
|
? null
|
|
721
744
|
: bindPlatformPullRequest(taskRef, {
|
|
722
|
-
pr:
|
|
745
|
+
pr: pullRequestToken,
|
|
723
746
|
agent: options.probeOperator ?? 'local-operator',
|
|
724
747
|
dryRun: true,
|
|
725
748
|
cwd: resolved.repoRoot,
|
|
726
749
|
...(options.platformClient ? { client: options.platformClient } : {})
|
|
727
|
-
})
|
|
728
|
-
|
|
750
|
+
})
|
|
751
|
+
);
|
|
752
|
+
if (!operation) return error('OVERRIDE_PROBE_INPUT_MISSING', `${policy.producerId} requires a bound issue or pull request identity`);
|
|
729
753
|
if (operation.status !== 'failed' && operation.status !== 'blocked') return probeNotObserved(policy);
|
|
730
754
|
if (!operation.error) return error('OVERRIDE_PROBE_INPUT_MISSING', `${policy.producerId} returned no platform error evidence`);
|
|
731
755
|
return {
|
|
@@ -763,6 +787,9 @@ function probeTaskEventFailure(taskRef: string, policy: FailurePolicy, resolved:
|
|
|
763
787
|
event: candidate.event,
|
|
764
788
|
agent: 'codex',
|
|
765
789
|
dryRun: true,
|
|
790
|
+
initiator: 'model',
|
|
791
|
+
requestId: `override-probe:${taskRef}:${candidate.event}`,
|
|
792
|
+
reasonCode: 'user-request',
|
|
766
793
|
...(candidate.artifact ? { artifact: candidate.artifact } : {})
|
|
767
794
|
}, { repoRoot: resolved.repoRoot, lockAlreadyHeld: true });
|
|
768
795
|
const matched = probeResult(policy, result, resolved.state);
|
|
@@ -771,8 +798,8 @@ function probeTaskEventFailure(taskRef: string, policy: FailurePolicy, resolved:
|
|
|
771
798
|
return probeNotObserved(policy);
|
|
772
799
|
}
|
|
773
800
|
|
|
774
|
-
function probeVerificationFailure(taskRef: string, policy: FailurePolicy, resolved: ProbeTask): ProducerFailure | OverrideError {
|
|
775
|
-
const result = verifyTaskEvent(
|
|
801
|
+
async function probeVerificationFailure(taskRef: string, policy: FailurePolicy, resolved: ProbeTask): Promise<ProducerFailure | OverrideError> {
|
|
802
|
+
const result = await verifyTaskEvent(
|
|
776
803
|
{
|
|
777
804
|
taskRef,
|
|
778
805
|
event: 'review-code.completed',
|
|
@@ -792,12 +819,12 @@ function latestArtifact(taskDir: string, family: string): string | undefined {
|
|
|
792
819
|
));
|
|
793
820
|
candidates.sort((a, b) => {
|
|
794
821
|
const round = (name: string) => Number(/-r(\d+)\.md$/.exec(name)?.[1] ?? 1);
|
|
795
|
-
|
|
796
|
-
|
|
822
|
+
return round(b) - round(a);
|
|
823
|
+
});
|
|
797
824
|
return candidates[0];
|
|
798
825
|
}
|
|
799
826
|
|
|
800
|
-
function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTask): ProducerFailure | OverrideError {
|
|
827
|
+
async function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTask): Promise<ProducerFailure | OverrideError> {
|
|
801
828
|
const candidates = [
|
|
802
829
|
{ skillName: 'review-code', family: 'review-code' },
|
|
803
830
|
{ skillName: 'review-plan', family: 'review-plan' },
|
|
@@ -811,7 +838,7 @@ function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTa
|
|
|
811
838
|
const artifactFile = candidate.family ? latestArtifact(resolved.taskDir, candidate.family) : undefined;
|
|
812
839
|
if (candidate.family && !artifactFile) continue;
|
|
813
840
|
try {
|
|
814
|
-
const payload = verifyInProcess({
|
|
841
|
+
const payload = await verifyInProcess({
|
|
815
842
|
mode: 'gate',
|
|
816
843
|
skillName: candidate.skillName,
|
|
817
844
|
taskDir: resolved.taskDir,
|
|
@@ -835,12 +862,12 @@ function probeVerificationEngineFailure(policy: FailurePolicy, resolved: ProbeTa
|
|
|
835
862
|
return probeNotObserved(policy);
|
|
836
863
|
}
|
|
837
864
|
|
|
838
|
-
function probeGenericFailure(
|
|
865
|
+
async function probeGenericFailure(
|
|
839
866
|
taskRef: string,
|
|
840
867
|
policy: FailurePolicy,
|
|
841
868
|
resolved: ProbeTask,
|
|
842
869
|
options: HumanOverrideOptions = {}
|
|
843
|
-
): ProducerFailure | OverrideError {
|
|
870
|
+
): Promise<ProducerFailure | OverrideError> {
|
|
844
871
|
switch (policy.producerId) {
|
|
845
872
|
case 'task.resolve':
|
|
846
873
|
return probeNotObserved(policy);
|
|
@@ -849,9 +876,9 @@ function probeGenericFailure(
|
|
|
849
876
|
case 'task-event':
|
|
850
877
|
return probeTaskEventFailure(taskRef, policy, resolved);
|
|
851
878
|
case 'task-verify':
|
|
852
|
-
return probeVerificationFailure(taskRef, policy, resolved);
|
|
879
|
+
return await probeVerificationFailure(taskRef, policy, resolved);
|
|
853
880
|
case 'verification-engine':
|
|
854
|
-
return probeVerificationEngineFailure(policy, resolved);
|
|
881
|
+
return await probeVerificationEngineFailure(policy, resolved);
|
|
855
882
|
case 'activity-intent':
|
|
856
883
|
return probeResult(policy, applyPrReviewActivityIntent({
|
|
857
884
|
kind: 'pr-review-start', taskRef, agent: 'codex', artifact: 'pr-review.md', head: '0'.repeat(40), dryRun: true
|
|
@@ -886,7 +913,7 @@ function probeGenericFailure(
|
|
|
886
913
|
}
|
|
887
914
|
case 'platform.issue':
|
|
888
915
|
case 'platform.pull-request':
|
|
889
|
-
return probePlatformFailure(taskRef, policy, resolved, options);
|
|
916
|
+
return await probePlatformFailure(taskRef, policy, resolved, options);
|
|
890
917
|
default:
|
|
891
918
|
return error('OVERRIDE_PROBE_INPUT_MISSING', `no producer probe is registered for ${policy.producerId}`);
|
|
892
919
|
}
|
|
@@ -896,7 +923,7 @@ function isProducerFailure(value: ProducerFailure | OverrideError): value is Pro
|
|
|
896
923
|
return 'observedFacts' in value && 'state' in value && Array.isArray(value.observedFacts);
|
|
897
924
|
}
|
|
898
925
|
|
|
899
|
-
function captureFailureSnapshot(taskRef: string, failureIdValue: string, target: string, options: HumanOverrideOptions = {}): FailureSnapshot | OverrideError {
|
|
926
|
+
async function captureFailureSnapshot(taskRef: string, failureIdValue: string, target: string, options: HumanOverrideOptions = {}): Promise<FailureSnapshot | OverrideError> {
|
|
900
927
|
const policy = policyFor(failureIdValue);
|
|
901
928
|
if (!policy) return error('OVERRIDE_FAILURE_UNKNOWN', `failure policy '${failureIdValue}' is not registered`);
|
|
902
929
|
if (!policy.targets.includes(target)) return error('OVERRIDE_TARGET_INVALID', `target '${target}' is not registered for ${failureIdValue}`);
|
|
@@ -912,7 +939,7 @@ function captureFailureSnapshot(taskRef: string, failureIdValue: string, target:
|
|
|
912
939
|
try { frontmatter = parseTypedTaskFrontmatter(content); } catch { /* probe reports an unconfirmed identity */ }
|
|
913
940
|
const producer: ProducerFailure | OverrideError = policy.producerId === LIFECYCLE_PRODUCER
|
|
914
941
|
? probeLifecycleFailure(taskRef, policy, resolved, options)
|
|
915
|
-
: probeGenericFailure(taskRef, policy, resolved, options);
|
|
942
|
+
: await probeGenericFailure(taskRef, policy, resolved, options);
|
|
916
943
|
if (!isProducerFailure(producer)) return producer;
|
|
917
944
|
const digest = computeFailureDigest(snapshotEvidence(
|
|
918
945
|
resolved.taskId,
|
|
@@ -981,7 +1008,7 @@ function validateResourceNumbers(request: HumanOverrideRequest): OverrideError |
|
|
|
981
1008
|
return null;
|
|
982
1009
|
}
|
|
983
1010
|
|
|
984
|
-
function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrideOptions = {}): HumanOverrideIssueResult {
|
|
1011
|
+
async function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrideOptions = {}): Promise<HumanOverrideIssueResult> {
|
|
985
1012
|
const invalid = validateCommon(request);
|
|
986
1013
|
if (invalid) return failedIssue(invalid.code, invalid.message);
|
|
987
1014
|
const policy = policyFor(request.failureId);
|
|
@@ -1002,7 +1029,7 @@ function issueHumanOverride(request: HumanOverrideRequest, options: HumanOverrid
|
|
|
1002
1029
|
const document = readTask(resolved.taskMdPath);
|
|
1003
1030
|
if ('code' in document) return failedIssue(document.code, document.message, resolved.taskId);
|
|
1004
1031
|
if (document.frontmatter.id !== resolved.taskId) return failedIssue('OVERRIDE_DOCUMENT_INVALID', 'task frontmatter id does not match resolved task', resolved.taskId);
|
|
1005
|
-
const snapshotResult = captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
|
|
1032
|
+
const snapshotResult = await captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
|
|
1006
1033
|
...options,
|
|
1007
1034
|
probeIntent: request.intent,
|
|
1008
1035
|
probeOperator: request.operator,
|
|
@@ -1124,18 +1151,18 @@ function lifecycleRequestFor(
|
|
|
1124
1151
|
return { taskRef, intent: 'restore', agent: operator, stagingDir, issueNumber };
|
|
1125
1152
|
}
|
|
1126
1153
|
|
|
1127
|
-
function applyOutcomeEffect(
|
|
1154
|
+
async function applyOutcomeEffect(
|
|
1128
1155
|
request: ConsumeHumanOverrideRequest,
|
|
1129
1156
|
row: Readonly<Record<string, string>>,
|
|
1130
1157
|
snapshot: FailureSnapshot,
|
|
1131
1158
|
outcome: Outcome,
|
|
1132
1159
|
options: HumanOverrideOptions
|
|
1133
|
-
): OverrideError | null {
|
|
1160
|
+
): Promise<OverrideError | null> {
|
|
1134
1161
|
if (outcome.effect === 'no-write' || outcome.effect === 'record-only') return null;
|
|
1135
1162
|
const intent = outcome.target === 'safe-close' ? 'cancel' : row.intent || request.intent;
|
|
1136
1163
|
if (!intent && outcome.target === 'continue-local') {
|
|
1137
1164
|
if (!options.effectExecutor) return error('OVERRIDE_EFFECT_EXECUTOR_MISSING', 'the producer must supply an effect executor for a continue-local outcome');
|
|
1138
|
-
return options.effectExecutor({
|
|
1165
|
+
return await options.effectExecutor({
|
|
1139
1166
|
failureId: request.failureId,
|
|
1140
1167
|
operator: row.operator ?? 'local-operator',
|
|
1141
1168
|
reason: row.reason ?? snapshot.message
|
|
@@ -1239,7 +1266,7 @@ function snapshotFromTicket(taskId: string, row: Readonly<Record<string, string>
|
|
|
1239
1266
|
};
|
|
1240
1267
|
}
|
|
1241
1268
|
|
|
1242
|
-
function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: HumanOverrideOptions = {}): HumanOverrideConsumeResult {
|
|
1269
|
+
async function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: HumanOverrideOptions = {}): Promise<HumanOverrideConsumeResult> {
|
|
1243
1270
|
const values = [request.taskRef, request.ticketId, request.failureId, request.target, request.scope];
|
|
1244
1271
|
if (values.some((value) => !singleLine(value))) {
|
|
1245
1272
|
return failedConsume('OVERRIDE_PAYLOAD_INVALID', 'consume fields must be non-empty single-line values', request.ticketId || null);
|
|
@@ -1275,7 +1302,7 @@ function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: Hum
|
|
|
1275
1302
|
if (isOverrideError(recoverySnapshot)) return failedConsume(recoverySnapshot.code, recoverySnapshot.message, request.ticketId, resolved.taskId);
|
|
1276
1303
|
snapshot = recoverySnapshot;
|
|
1277
1304
|
} else {
|
|
1278
|
-
const snapshotResult = captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
|
|
1305
|
+
const snapshotResult = await captureFailureSnapshot(request.taskRef, request.failureId, request.target, {
|
|
1279
1306
|
...options,
|
|
1280
1307
|
probeIntent: row.values.intent ? row.values.intent as TaskLifecycleIntent : request.intent,
|
|
1281
1308
|
probeOperator: row.values.operator,
|
|
@@ -1320,7 +1347,7 @@ function consumeHumanOverride(request: ConsumeHumanOverrideRequest, options: Hum
|
|
|
1320
1347
|
if (staged.status === 'planned') return failedConsume('OVERRIDE_WRITE_INVALID', 'override writes cannot be planned', request.ticketId, resolved.taskId);
|
|
1321
1348
|
effectRow = { ...row.values, status: 'consuming', effect: outcome.effect, result: outcome.result, context_id: outcome.contextId, residual: `effect pending: ${outcome.residual}` };
|
|
1322
1349
|
}
|
|
1323
|
-
const effectError = applyOutcomeEffect(request, effectRow, snapshot, outcome, options);
|
|
1350
|
+
const effectError = await applyOutcomeEffect(request, effectRow, snapshot, outcome, options);
|
|
1324
1351
|
if (effectError) return failedConsume(effectError.code, effectError.message, request.ticketId, resolved.taskId);
|
|
1325
1352
|
const after = resolveTask(request.taskRef, options);
|
|
1326
1353
|
if (!after.ok) return failedConsume(after.code, after.message, request.ticketId, after.taskId);
|
|
@@ -1356,7 +1383,7 @@ function diagnoseHumanOverride(failure: string, target?: string) {
|
|
|
1356
1383
|
};
|
|
1357
1384
|
}
|
|
1358
1385
|
|
|
1359
|
-
function diagnoseHumanOverrideForTask(
|
|
1386
|
+
async function diagnoseHumanOverrideForTask(
|
|
1360
1387
|
taskRef: string,
|
|
1361
1388
|
failure?: string,
|
|
1362
1389
|
target?: string,
|
|
@@ -1400,12 +1427,12 @@ function diagnoseHumanOverrideForTask(
|
|
|
1400
1427
|
error: error('OVERRIDE_FAILURE_UNKNOWN', `failure policy '${failure}' is not registered`)
|
|
1401
1428
|
};
|
|
1402
1429
|
}
|
|
1403
|
-
const probes = policies
|
|
1430
|
+
const probes = await Promise.all(policies
|
|
1404
1431
|
.filter((policy) => !target || policy.targets.includes(target))
|
|
1405
|
-
.map((policy) => {
|
|
1432
|
+
.map(async (policy) => {
|
|
1406
1433
|
const producer = policy.producerId === LIFECYCLE_PRODUCER
|
|
1407
1434
|
? probeLifecycleFailure(taskRef, policy, resolved, options)
|
|
1408
|
-
|
|
1435
|
+
: await probeGenericFailure(taskRef, policy, resolved, options);
|
|
1409
1436
|
const observed = isProducerFailure(producer);
|
|
1410
1437
|
return {
|
|
1411
1438
|
failureId: policy.id,
|
|
@@ -1419,7 +1446,7 @@ function diagnoseHumanOverrideForTask(
|
|
|
1419
1446
|
message: observed ? producer.message : producer.message,
|
|
1420
1447
|
errorCode: observed ? null : producer.code
|
|
1421
1448
|
};
|
|
1422
|
-
});
|
|
1449
|
+
}));
|
|
1423
1450
|
const blockedBy = probes.filter((probe) => probe.status === 'observed');
|
|
1424
1451
|
return {
|
|
1425
1452
|
status: 'ready' as const,
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { parseArtifactReceipts, sha256File } from './artifact-receipts.ts';
|
|
5
|
+
import { invalidationMutation, parseInvalidationDocument, reconcileInvalidation } from './invalidation.ts';
|
|
6
|
+
import { resolveTaskRef } from './resolve-ref.ts';
|
|
7
|
+
import { writeTask } from './write.ts';
|
|
8
|
+
import type { TaskWriteOptions } from './write.ts';
|
|
9
|
+
|
|
10
|
+
type InvalidationCommandOptions = TaskWriteOptions & { now?: () => string; maxTargets?: number; dryRun?: boolean };
|
|
11
|
+
type InvalidationCommandResult = {
|
|
12
|
+
status: 'applied' | 'planned' | 'no-op' | 'failed';
|
|
13
|
+
changed: boolean;
|
|
14
|
+
taskId: string | null;
|
|
15
|
+
processed: number;
|
|
16
|
+
remaining: number;
|
|
17
|
+
error: { code: string; message: string } | null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function reconcileTaskInvalidation(taskRef: string, options: InvalidationCommandOptions = {}): InvalidationCommandResult {
|
|
21
|
+
const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
|
|
22
|
+
if (!resolved.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: resolved.code, message: resolved.message } };
|
|
23
|
+
let content: string;
|
|
24
|
+
try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); }
|
|
25
|
+
catch (error) { return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: 'TASK_READ_FAILED', message: error instanceof Error ? error.message : String(error) } }; }
|
|
26
|
+
const parsed = parseInvalidationDocument(content);
|
|
27
|
+
if (!parsed.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: { code: parsed.code, message: parsed.message } };
|
|
28
|
+
if (!parsed.present) return { status: 'no-op', changed: false, taskId: resolved.taskId, processed: 0, remaining: 0, error: null };
|
|
29
|
+
const beforePending = parsed.document.targets.filter((target) => target.status !== 'completed').length;
|
|
30
|
+
let receipts;
|
|
31
|
+
try { receipts = parseArtifactReceipts(content).rows; }
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (parsed.document.targets.some((target) => target.status !== 'completed' && target.targetKind === 'receipt')) {
|
|
34
|
+
return {
|
|
35
|
+
status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
|
|
36
|
+
error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: error instanceof Error ? error.message : String(error) }
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
receipts = [];
|
|
40
|
+
}
|
|
41
|
+
for (const target of parsed.document.targets) {
|
|
42
|
+
if (target.status === 'completed') continue;
|
|
43
|
+
if (target.targetKind === 'receipt') {
|
|
44
|
+
const receipt = receipts.find((candidate) => candidate.output === target.targetArtifact);
|
|
45
|
+
if (!receipt || receipt.inputSha256 !== target.targetSha256) {
|
|
46
|
+
return {
|
|
47
|
+
status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
|
|
48
|
+
error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation receipt target '${target.targetArtifact}' changed before reconcile` }
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const targetPath = path.join(resolved.taskDir, target.targetArtifact);
|
|
54
|
+
try {
|
|
55
|
+
const stat = fs.lstatSync(targetPath);
|
|
56
|
+
if (!stat.isFile() || stat.isSymbolicLink() || sha256File(targetPath) !== target.targetSha256) {
|
|
57
|
+
return {
|
|
58
|
+
status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
|
|
59
|
+
error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation target '${target.targetArtifact}' changed before reconcile` }
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
return {
|
|
64
|
+
status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending,
|
|
65
|
+
error: { code: 'INVALIDATION_TARGET_HASH_CONFLICT', message: `invalidation target '${target.targetArtifact}' is unavailable before reconcile` }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const reconciled = reconcileInvalidation(parsed.document, (options.now ?? (() => new Date().toISOString()))(), options.maxTargets);
|
|
70
|
+
if (!reconciled.ok) return { status: 'failed', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending, error: { code: reconciled.code, message: reconciled.message } };
|
|
71
|
+
if (!reconciled.changed) return { status: 'no-op', changed: false, taskId: resolved.taskId, processed: 0, remaining: beforePending, error: null };
|
|
72
|
+
const result = writeTask({
|
|
73
|
+
taskRef, expectedState: resolved.state, dryRun: options.dryRun,
|
|
74
|
+
mutations: [invalidationMutation(content, reconciled.document)]
|
|
75
|
+
}, { ...options, invalidationContext: 'reconcile', taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
|
|
76
|
+
if (result.status === 'failed') return { status: 'failed', changed: false, taskId: resolved.taskId, processed: beforePending - reconciled.document.targets.filter((target) => target.status !== 'completed').length, remaining: reconciled.document.targets.filter((target) => target.status !== 'completed').length, error: result.error };
|
|
77
|
+
return {
|
|
78
|
+
status: result.status, changed: result.changed, taskId: resolved.taskId,
|
|
79
|
+
processed: beforePending - reconciled.document.targets.filter((target) => target.status !== 'completed').length,
|
|
80
|
+
remaining: reconciled.document.targets.filter((target) => target.status !== 'completed').length,
|
|
81
|
+
error: null
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { reconcileTaskInvalidation };
|
|
86
|
+
export type { InvalidationCommandOptions, InvalidationCommandResult };
|