@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
|
@@ -11,6 +11,9 @@ import { getOpenWorkflowWarnings, formatWorkflowWarningSummary } from '../workfl
|
|
|
11
11
|
import { parseActivityLog, pairEntries, startedBackedRows } from '../activity-log.js';
|
|
12
12
|
import { readRun } from '../orchestration.js';
|
|
13
13
|
import { statusCard } from '../../server/display.js';
|
|
14
|
+
import { invalidationBlocks, parseInvalidationDocument } from '../invalidation.js';
|
|
15
|
+
import { parseReworkIntentDocument } from '../rework-intent.js';
|
|
16
|
+
import { buildLifecycleFacts, recommendNext } from '../capabilities.js';
|
|
14
17
|
const USAGE = `Usage: ai task status [--task <ref> | -t <ref>]
|
|
15
18
|
|
|
16
19
|
Prints an aggregated "health check" view for a task: header, metadata,
|
|
@@ -317,6 +320,12 @@ function renderStatus(model) {
|
|
|
317
320
|
else {
|
|
318
321
|
lines.push(...renderPairs(model.artifacts.groups.map((group) => [group.stage, group.files.join(', ')])));
|
|
319
322
|
}
|
|
323
|
+
lines.push('', 'Invalidation', ...renderPairs([
|
|
324
|
+
['status', model.invalidation?.status ?? 'unknown'],
|
|
325
|
+
['processed', `${model.invalidation?.processed ?? 0}/${model.invalidation?.total ?? 0}`],
|
|
326
|
+
['pending_intents', String(model.invalidation?.pendingIntents ?? 0)]
|
|
327
|
+
]));
|
|
328
|
+
lines.push('', 'Recommendation', ...renderPairs([['action', model.recommendation ?? DASH]]));
|
|
320
329
|
lines.push('', 'Orchestration', ...renderPairs([
|
|
321
330
|
['status', model.orchestration.status],
|
|
322
331
|
['run_id', model.orchestration.runId],
|
|
@@ -361,6 +370,10 @@ function renderStatus(model) {
|
|
|
361
370
|
return lines;
|
|
362
371
|
}
|
|
363
372
|
function modelTone(model) {
|
|
373
|
+
if (model.invalidation?.status === 'invalid')
|
|
374
|
+
return 'danger';
|
|
375
|
+
if (model.invalidation?.status === 'pending' || model.invalidation?.status === 'in-progress')
|
|
376
|
+
return 'warning';
|
|
364
377
|
if (model.orchestration.status === 'paused')
|
|
365
378
|
return 'warning';
|
|
366
379
|
if (model.orchestration.status === 'running')
|
|
@@ -382,6 +395,23 @@ function buildFromResolved(input) {
|
|
|
382
395
|
const run = input.run ?? makeRunner(input.repoRoot);
|
|
383
396
|
const artifacts = enumerateArtifacts(input.taskDir);
|
|
384
397
|
const workflow = collectWorkflow(content, input.now);
|
|
398
|
+
const invalidation = parseInvalidationDocument(content);
|
|
399
|
+
const rework = parseReworkIntentDocument(content);
|
|
400
|
+
const pendingIntents = rework.ok ? rework.intents.filter((intent) => intent.status === 'pending').length : 0;
|
|
401
|
+
const invalidationInfo = !invalidation.ok
|
|
402
|
+
? { status: 'invalid', processed: 0, total: 0, pendingIntents }
|
|
403
|
+
: {
|
|
404
|
+
status: invalidation.present
|
|
405
|
+
? invalidationBlocks(invalidation.document)
|
|
406
|
+
? invalidation.document.operations.some((operation) => operation.status === 'in-progress') ? 'in-progress' : 'pending'
|
|
407
|
+
: 'completed'
|
|
408
|
+
: 'none',
|
|
409
|
+
processed: invalidation.document.operations.reduce((sum, operation) => sum + operation.processed, 0),
|
|
410
|
+
total: invalidation.document.operations.reduce((sum, operation) => sum + operation.total, 0),
|
|
411
|
+
pendingIntents
|
|
412
|
+
};
|
|
413
|
+
const facts = buildLifecycleFacts(input.taskDir, content, fm.status ?? 'active');
|
|
414
|
+
const recommendation = facts.ok ? (recommendNext(facts.facts).action ?? DASH) : DASH;
|
|
385
415
|
return {
|
|
386
416
|
taskId: input.taskId,
|
|
387
417
|
shortId: input.shortId ?? loadShortIdByTaskId(input.repoRoot).get(input.taskId) ?? DASH,
|
|
@@ -392,6 +422,8 @@ function buildFromResolved(input) {
|
|
|
392
422
|
workflow,
|
|
393
423
|
runtime: collectRuntime(input.taskDir, workflow, run),
|
|
394
424
|
orchestration: collectOrchestration(input.taskDir),
|
|
425
|
+
invalidation: invalidationInfo,
|
|
426
|
+
recommendation,
|
|
395
427
|
git: collectGit(fm.branch ?? '', run)
|
|
396
428
|
};
|
|
397
429
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
function intentRoot(repoRoot) {
|
|
5
|
+
return path.join(repoRoot, '.agents', 'workspace', '.task-commit-intents');
|
|
6
|
+
}
|
|
7
|
+
function intentPath(repoRoot, taskId) {
|
|
8
|
+
return path.join(intentRoot(repoRoot), `${taskId}.json`);
|
|
9
|
+
}
|
|
10
|
+
function checkpointIntentDigest(identity) {
|
|
11
|
+
return createHash('sha256').update(JSON.stringify({
|
|
12
|
+
taskId: identity.taskId,
|
|
13
|
+
branch: identity.branch,
|
|
14
|
+
mode: identity.mode,
|
|
15
|
+
expectedHead: identity.expectedHead,
|
|
16
|
+
expectedTree: identity.expectedTree,
|
|
17
|
+
paths: [...identity.paths],
|
|
18
|
+
message: identity.message,
|
|
19
|
+
round: identity.round
|
|
20
|
+
})).digest('hex');
|
|
21
|
+
}
|
|
22
|
+
function isIntent(value) {
|
|
23
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
24
|
+
return false;
|
|
25
|
+
const intent = value;
|
|
26
|
+
return intent.version === 1
|
|
27
|
+
&& typeof intent.taskId === 'string' && intent.taskId.length > 0
|
|
28
|
+
&& typeof intent.branch === 'string' && intent.branch.length > 0
|
|
29
|
+
&& intent.mode === 'local'
|
|
30
|
+
&& typeof intent.expectedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedHead)
|
|
31
|
+
&& typeof intent.expectedTree === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedTree)
|
|
32
|
+
&& Array.isArray(intent.paths) && intent.paths.every((item) => typeof item === 'string' && item.length > 0)
|
|
33
|
+
&& typeof intent.message === 'string' && intent.message.length > 0
|
|
34
|
+
&& Number.isSafeInteger(intent.round) && Number(intent.round) > 0
|
|
35
|
+
&& typeof intent.digest === 'string' && /^[a-f0-9]{64}$/.test(intent.digest)
|
|
36
|
+
&& ['prepared', 'committed', 'synced'].includes(String(intent.state))
|
|
37
|
+
&& (intent.committedHead === null || (typeof intent.committedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.committedHead)))
|
|
38
|
+
&& typeof intent.createdAt === 'string' && intent.createdAt.length > 0
|
|
39
|
+
&& typeof intent.updatedAt === 'string' && intent.updatedAt.length > 0
|
|
40
|
+
&& intent.digest === checkpointIntentDigest(intent);
|
|
41
|
+
}
|
|
42
|
+
function readCheckpointIntent(repoRoot, taskId) {
|
|
43
|
+
const target = intentPath(repoRoot, taskId);
|
|
44
|
+
if (!fs.existsSync(target))
|
|
45
|
+
return null;
|
|
46
|
+
const value = JSON.parse(fs.readFileSync(target, 'utf8'));
|
|
47
|
+
if (!isIntent(value))
|
|
48
|
+
throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function writeCheckpointIntent(repoRoot, value) {
|
|
52
|
+
if (!isIntent(value))
|
|
53
|
+
throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
|
|
54
|
+
const directory = intentRoot(repoRoot);
|
|
55
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
56
|
+
const target = intentPath(repoRoot, value.taskId);
|
|
57
|
+
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
58
|
+
fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
59
|
+
try {
|
|
60
|
+
fs.renameSync(temporary, target);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
try {
|
|
64
|
+
fs.unlinkSync(temporary);
|
|
65
|
+
}
|
|
66
|
+
catch { /* preserve primary error */ }
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function updateCheckpointIntent(value, patch) {
|
|
71
|
+
const next = { ...value, ...patch };
|
|
72
|
+
if (next.state === 'prepared' && next.committedHead !== null)
|
|
73
|
+
throw new Error('COMMIT_INTENT_INVALID: prepared intent cannot have a committed head');
|
|
74
|
+
if (next.state !== 'prepared' && !next.committedHead)
|
|
75
|
+
throw new Error('COMMIT_INTENT_INVALID: committed intent requires a committed head');
|
|
76
|
+
return next;
|
|
77
|
+
}
|
|
78
|
+
function removeCheckpointIntent(repoRoot, taskId) {
|
|
79
|
+
const target = intentPath(repoRoot, taskId);
|
|
80
|
+
try {
|
|
81
|
+
fs.unlinkSync(target);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error.code !== 'ENOENT')
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function sameCheckpointIntent(left, right) {
|
|
89
|
+
return left.digest === checkpointIntentDigest(right)
|
|
90
|
+
&& left.taskId === right.taskId
|
|
91
|
+
&& left.branch === right.branch
|
|
92
|
+
&& left.mode === right.mode
|
|
93
|
+
&& left.expectedHead === right.expectedHead
|
|
94
|
+
&& left.expectedTree === right.expectedTree
|
|
95
|
+
&& left.message === right.message
|
|
96
|
+
&& left.round === right.round
|
|
97
|
+
&& JSON.stringify(left.paths) === JSON.stringify(right.paths);
|
|
98
|
+
}
|
|
99
|
+
export { checkpointIntentDigest, intentPath, intentRoot, isIntent, readCheckpointIntent, removeCheckpointIntent, sameCheckpointIntent, updateCheckpointIntent, writeCheckpointIntent };
|
|
100
|
+
//# sourceMappingURL=commit-intent.js.map
|
|
@@ -8,7 +8,7 @@ import { mergeOperationWarnings } from './operation-outcome.js';
|
|
|
8
8
|
import { TaskExecutionLockError, withRepositoryMutationLock, withTaskExecutionLock } from './task-execution-lock.js';
|
|
9
9
|
import { appendActivityEntry, locateActivityLog } from './activity-log.js';
|
|
10
10
|
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
11
|
-
import {
|
|
11
|
+
import { checkpointIntentDigest, readCheckpointIntent, removeCheckpointIntent, sameCheckpointIntent, updateCheckpointIntent, writeCheckpointIntent } from './commit-intent.js';
|
|
12
12
|
const HEAD_REF = /^refs\/heads\/(.+)$/;
|
|
13
13
|
function isCommitExecutionMode(value) {
|
|
14
14
|
return value === 'direct' || value === 'orchestrated';
|
|
@@ -20,6 +20,13 @@ function gitText(repoRoot, args) {
|
|
|
20
20
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
21
21
|
}).trim();
|
|
22
22
|
}
|
|
23
|
+
function effectiveDelivery(input) {
|
|
24
|
+
if (input.delivery)
|
|
25
|
+
return input.delivery;
|
|
26
|
+
if (input.push)
|
|
27
|
+
return { mode: 'push', remote: input.push.remote, refs: input.push.refs };
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
23
30
|
function canonicalRepositoryRoot(cwd) {
|
|
24
31
|
return gitText(cwd, ['rev-parse', '--show-toplevel']);
|
|
25
32
|
}
|
|
@@ -86,8 +93,9 @@ function validateCommon(input, branch) {
|
|
|
86
93
|
return { code: 'GIT_HEAD_EXPECTATION_REQUIRED', message: 'A valid expected HEAD is required' };
|
|
87
94
|
if (!/^[a-f0-9]{40,64}$/.test(input.expectedTree))
|
|
88
95
|
return { code: 'GIT_TREE_EXPECTATION_REQUIRED', message: 'A valid expected tree is required' };
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
const delivery = effectiveDelivery(input);
|
|
97
|
+
if (!delivery)
|
|
98
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Commit delivery requires a delivery policy' };
|
|
91
99
|
if (input.paths.some((candidate) => !candidate || candidate.startsWith('/') || candidate.split(/[\\/]/).includes('..'))) {
|
|
92
100
|
return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Commit paths must stay inside the repository' };
|
|
93
101
|
}
|
|
@@ -96,38 +104,16 @@ function validateCommon(input, branch) {
|
|
|
96
104
|
}
|
|
97
105
|
if (branch !== null && branch === '')
|
|
98
106
|
return { code: 'GIT_BRANCH_INVALID', message: 'A named branch is required' };
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
if (delivery.mode === 'push') {
|
|
108
|
+
if (!delivery.remote || delivery.refs.length !== 1)
|
|
109
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push requires one remote and one ref' };
|
|
110
|
+
const ref = delivery.refs[0] ?? '';
|
|
111
|
+
if (!HEAD_REF.test(ref) || HEAD_REF.exec(ref)?.[1] !== branch) {
|
|
112
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push ref must be the current full heads ref' };
|
|
113
|
+
}
|
|
104
114
|
}
|
|
105
115
|
return null;
|
|
106
116
|
}
|
|
107
|
-
function validateOrchestrated(input, task) {
|
|
108
|
-
if (!input.agent)
|
|
109
|
-
return { error: { code: 'ORCHESTRATION_PROVENANCE_MISMATCH', message: 'orchestrated commit requires an agent' } };
|
|
110
|
-
const planned = planOrchestrationStageCompletion(task.taskId, {
|
|
111
|
-
stage: 'commit',
|
|
112
|
-
round: 1,
|
|
113
|
-
artifact: 'commit',
|
|
114
|
-
role: 'executor',
|
|
115
|
-
agent: input.agent
|
|
116
|
-
}, { repoRoot: task.repoRoot });
|
|
117
|
-
const run = planned.result.run;
|
|
118
|
-
if (!planned.plan
|
|
119
|
-
|| !run
|
|
120
|
-
|| run.status !== 'running'
|
|
121
|
-
|| !run.commitAuthorization.issuedAt
|
|
122
|
-
|| run.commitAuthorization.consumedAt)
|
|
123
|
-
return {
|
|
124
|
-
error: {
|
|
125
|
-
code: planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH',
|
|
126
|
-
message: planned.result.error?.message ?? 'orchestrated commit requires one matching activated commit delegation'
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
return { plan: planned.plan };
|
|
130
|
-
}
|
|
131
117
|
function syncTaskCommit(input, task, committedHead) {
|
|
132
118
|
let content;
|
|
133
119
|
try {
|
|
@@ -137,7 +123,18 @@ function syncTaskCommit(input, task, committedHead) {
|
|
|
137
123
|
return warning('TASK_STATUS_SYNC_FAILED', 'task has no unique Activity Log section', true, 'task', task.taskId, 'ACTION_REQUIRED');
|
|
138
124
|
const metadata = captureTaskWriteMetadata();
|
|
139
125
|
const commitNote = gitText(task.repoRoot, ['show', '-s', '--format=%h %s', committedHead]);
|
|
140
|
-
|
|
126
|
+
let matchingCommitIndex = -1;
|
|
127
|
+
for (let index = activity.entries.length - 1; index >= 0; index -= 1) {
|
|
128
|
+
const entry = activity.entries[index];
|
|
129
|
+
if (entry.step === 'Commit' && entry.note === commitNote) {
|
|
130
|
+
matchingCommitIndex = index;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const reviewedAfterCommit = matchingCommitIndex >= 0 && activity.entries
|
|
135
|
+
.slice(matchingCommitIndex + 1)
|
|
136
|
+
.some((entry) => /^Review Code \(Round \d+\)$/.test(entry.step));
|
|
137
|
+
const alreadyLogged = matchingCommitIndex >= 0 && !reviewedAfterCommit;
|
|
141
138
|
const mutations = [];
|
|
142
139
|
if (!alreadyLogged)
|
|
143
140
|
mutations.push({
|
|
@@ -146,7 +143,10 @@ function syncTaskCommit(input, task, committedHead) {
|
|
|
146
143
|
heading: activity.heading,
|
|
147
144
|
body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Commit', agent: input.agent, note: commitNote })
|
|
148
145
|
});
|
|
149
|
-
const frontmatter = {
|
|
146
|
+
const frontmatter = {
|
|
147
|
+
assigned_to: input.agent,
|
|
148
|
+
checkpoint_commit: committedHead
|
|
149
|
+
};
|
|
150
150
|
mutations.push({ kind: 'frontmatter', set: frontmatter });
|
|
151
151
|
if (mutations.length === 0)
|
|
152
152
|
return null;
|
|
@@ -163,10 +163,44 @@ function syncTaskCommit(input, task, committedHead) {
|
|
|
163
163
|
return warning('TASK_STATUS_SYNC_FAILED', error instanceof Error ? error.message : String(error), true, 'task', task.taskId, 'ACTION_REQUIRED');
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
+
function checkpointChildMatches(task, intent, head) {
|
|
167
|
+
try {
|
|
168
|
+
const parent = gitText(task.repoRoot, ['rev-parse', `${head}^`]);
|
|
169
|
+
const tree = gitText(task.repoRoot, ['rev-parse', `${head}^{tree}`]);
|
|
170
|
+
const message = gitText(task.repoRoot, ['show', '-s', '--format=%s', head]);
|
|
171
|
+
const changed = gitText(task.repoRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', head]).split('\n').filter(Boolean).sort();
|
|
172
|
+
return parent === intent.expectedHead
|
|
173
|
+
&& tree === intent.expectedTree
|
|
174
|
+
&& message === intent.message
|
|
175
|
+
&& JSON.stringify(changed) === JSON.stringify([...intent.paths].sort());
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function checkpointIdentity(input, task, delivery) {
|
|
182
|
+
if (delivery.mode !== 'local')
|
|
183
|
+
throw new Error('checkpoint identity requires local delivery');
|
|
184
|
+
return {
|
|
185
|
+
taskId: task.taskId,
|
|
186
|
+
branch: task.branch,
|
|
187
|
+
mode: 'local',
|
|
188
|
+
expectedHead: input.expectedHead,
|
|
189
|
+
expectedTree: input.expectedTree,
|
|
190
|
+
paths: [...input.paths],
|
|
191
|
+
message: input.message,
|
|
192
|
+
round: input.round ?? 1
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function checkpointTimestamp() {
|
|
196
|
+
return new Date().toISOString();
|
|
197
|
+
}
|
|
166
198
|
function executeUnlocked(input, task, mode) {
|
|
167
199
|
const inspected = inspectGitWorkflow(input.cwd);
|
|
168
200
|
if (!inspected.snapshot)
|
|
169
201
|
return failure(input, mode, task?.taskId ?? null, 'GIT_INSPECT_FAILED', 'Unable to inspect Git repository');
|
|
202
|
+
if (mode === 'orchestrated')
|
|
203
|
+
return failure(input, mode, task?.taskId ?? null, 'ORCHESTRATED_COMMIT_REMOVED', 'Orchestrated commit is no longer a lifecycle stage; use local checkpoint delivery from code-task', 'blocked', inspected.snapshot);
|
|
170
204
|
const branch = inspected.snapshot.branch;
|
|
171
205
|
const commonError = validateCommon(input, branch);
|
|
172
206
|
if (commonError)
|
|
@@ -177,60 +211,131 @@ function executeUnlocked(input, task, mode) {
|
|
|
177
211
|
return failure(input, mode, task.taskId, 'GIT_BRANCH_MISMATCH', `Task branch '${task.branch}' does not match current branch '${branch}'`, 'blocked', inspected.snapshot);
|
|
178
212
|
if (task && !input.agent)
|
|
179
213
|
return failure(input, mode, task.taskId, 'COMMIT_AGENT_REQUIRED', 'task-bound commit requires an agent', 'blocked', inspected.snapshot);
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const error = orchestrationValidation.error;
|
|
187
|
-
return failure(input, mode, task?.taskId ?? null, error.code, error.message, 'blocked', inspected.snapshot);
|
|
188
|
-
}
|
|
189
|
-
const orchestrationCompletion = orchestrationValidation && 'plan' in orchestrationValidation
|
|
190
|
-
? orchestrationValidation.plan
|
|
191
|
-
: null;
|
|
192
|
-
const committed = input.paths.length === 0
|
|
214
|
+
const delivery = effectiveDelivery(input);
|
|
215
|
+
if (delivery.mode === 'local' && !task)
|
|
216
|
+
return failure(input, mode, null, 'CHECKPOINT_TASK_REQUIRED', 'local checkpoint delivery requires a task context', 'blocked', inspected.snapshot);
|
|
217
|
+
let pendingIntent = null;
|
|
218
|
+
let checkpointCommittedHead = null;
|
|
219
|
+
const committed = delivery.mode === 'local'
|
|
193
220
|
? (() => {
|
|
194
|
-
|
|
221
|
+
const identity = checkpointIdentity(input, task, delivery);
|
|
222
|
+
try {
|
|
223
|
+
pendingIntent = readCheckpointIntent(task.repoRoot, task.taskId);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
195
226
|
return {
|
|
196
|
-
status: 'failed',
|
|
197
|
-
|
|
198
|
-
snapshot: inspected.snapshot,
|
|
199
|
-
operations: [],
|
|
200
|
-
error: { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Push-only retry requires a clean working tree' }
|
|
227
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
228
|
+
error: { code: 'COMMIT_INTENT_INVALID', message: error instanceof Error ? error.message : String(error) }
|
|
201
229
|
};
|
|
202
|
-
|
|
230
|
+
}
|
|
231
|
+
if (pendingIntent && !sameCheckpointIntent(pendingIntent, identity))
|
|
203
232
|
return {
|
|
204
|
-
status: 'failed',
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
233
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
234
|
+
error: { code: 'COMMIT_INTENT_CONFLICT', message: 'A different checkpoint intent is still pending for this task' }
|
|
235
|
+
};
|
|
236
|
+
if (!pendingIntent) {
|
|
237
|
+
const timestamp = checkpointTimestamp();
|
|
238
|
+
pendingIntent = {
|
|
239
|
+
version: 1, ...identity, digest: checkpointIntentDigest(identity), state: 'prepared',
|
|
240
|
+
committedHead: null, createdAt: timestamp, updatedAt: timestamp
|
|
241
|
+
};
|
|
242
|
+
try {
|
|
243
|
+
writeCheckpointIntent(task.repoRoot, pendingIntent);
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
return {
|
|
247
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
248
|
+
error: { code: 'COMMIT_INTENT_WRITE_FAILED', message: error instanceof Error ? error.message : String(error) }
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (pendingIntent.state !== 'prepared') {
|
|
253
|
+
checkpointCommittedHead = pendingIntent.committedHead;
|
|
254
|
+
return {
|
|
255
|
+
status: 'no-op', changed: false, snapshot: inspected.snapshot,
|
|
256
|
+
operations: [{ name: 'commit', status: 'no-op' }], error: null
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (inspected.snapshot.head !== identity.expectedHead && !checkpointChildMatches(task, pendingIntent, inspected.snapshot.head))
|
|
260
|
+
return {
|
|
261
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
262
|
+
error: { code: 'COMMIT_INTENT_HEAD_CONFLICT', message: 'Current HEAD does not match the pending checkpoint intent' }
|
|
263
|
+
};
|
|
264
|
+
if (inspected.snapshot.head !== identity.expectedHead) {
|
|
265
|
+
checkpointCommittedHead = inspected.snapshot.head;
|
|
266
|
+
pendingIntent = updateCheckpointIntent(pendingIntent, {
|
|
267
|
+
state: 'committed', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
268
|
+
});
|
|
269
|
+
writeCheckpointIntent(task.repoRoot, pendingIntent);
|
|
270
|
+
return {
|
|
271
|
+
status: 'no-op', changed: false, snapshot: inspected.snapshot,
|
|
272
|
+
operations: [{ name: 'commit', status: 'no-op' }], error: null
|
|
209
273
|
};
|
|
210
|
-
|
|
211
|
-
if (
|
|
274
|
+
}
|
|
275
|
+
if (input.paths.length === 0)
|
|
276
|
+
return {
|
|
277
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
278
|
+
error: { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Local checkpoint requires explicit paths' }
|
|
279
|
+
};
|
|
280
|
+
const created = commitExplicitPaths({
|
|
281
|
+
cwd: input.cwd, paths: input.paths, message: input.message,
|
|
282
|
+
expectedHead: identity.expectedHead, expectedTree: identity.expectedTree
|
|
283
|
+
});
|
|
284
|
+
if (created.status === 'applied' && created.snapshot?.head) {
|
|
285
|
+
checkpointCommittedHead = created.snapshot.head;
|
|
286
|
+
pendingIntent = updateCheckpointIntent(pendingIntent, {
|
|
287
|
+
state: 'committed', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
288
|
+
});
|
|
289
|
+
writeCheckpointIntent(task.repoRoot, pendingIntent);
|
|
290
|
+
}
|
|
291
|
+
else if (created.status === 'no-op') {
|
|
292
|
+
removeCheckpointIntent(task.repoRoot, task.taskId);
|
|
293
|
+
pendingIntent = null;
|
|
294
|
+
}
|
|
295
|
+
return created;
|
|
296
|
+
})()
|
|
297
|
+
: input.paths.length === 0
|
|
298
|
+
? (() => {
|
|
299
|
+
if (inspected.snapshot.worktree.length > 0 || inspected.snapshot.staged.length > 0)
|
|
300
|
+
return {
|
|
301
|
+
status: 'failed',
|
|
302
|
+
changed: false,
|
|
303
|
+
snapshot: inspected.snapshot,
|
|
304
|
+
operations: [],
|
|
305
|
+
error: { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Push-only retry requires a clean working tree' }
|
|
306
|
+
};
|
|
307
|
+
if (inspected.snapshot.head !== input.expectedHead)
|
|
308
|
+
return {
|
|
309
|
+
status: 'failed',
|
|
310
|
+
changed: false,
|
|
311
|
+
snapshot: inspected.snapshot,
|
|
312
|
+
operations: [],
|
|
313
|
+
error: { code: 'GIT_HEAD_MISMATCH', message: `Expected HEAD ${input.expectedHead}, received ${inspected.snapshot.head}` }
|
|
314
|
+
};
|
|
315
|
+
const currentTree = gitText(input.cwd, ['rev-parse', 'HEAD^{tree}']);
|
|
316
|
+
if (currentTree !== input.expectedTree)
|
|
317
|
+
return {
|
|
318
|
+
status: 'failed',
|
|
319
|
+
changed: false,
|
|
320
|
+
snapshot: inspected.snapshot,
|
|
321
|
+
operations: [],
|
|
322
|
+
error: { code: 'GIT_TREE_MISMATCH', message: `Expected current tree ${input.expectedTree}, received ${currentTree}` }
|
|
323
|
+
};
|
|
212
324
|
return {
|
|
213
|
-
status: '
|
|
325
|
+
status: 'no-op',
|
|
214
326
|
changed: false,
|
|
215
327
|
snapshot: inspected.snapshot,
|
|
216
|
-
operations: [],
|
|
217
|
-
error:
|
|
328
|
+
operations: [{ name: 'commit', status: 'no-op' }],
|
|
329
|
+
error: null
|
|
218
330
|
};
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
: commitExplicitPaths({
|
|
228
|
-
cwd: input.cwd,
|
|
229
|
-
paths: input.paths,
|
|
230
|
-
message: input.message,
|
|
231
|
-
expectedHead: input.expectedHead,
|
|
232
|
-
expectedTree: input.expectedTree
|
|
233
|
-
});
|
|
331
|
+
})()
|
|
332
|
+
: commitExplicitPaths({
|
|
333
|
+
cwd: input.cwd,
|
|
334
|
+
paths: input.paths,
|
|
335
|
+
message: input.message,
|
|
336
|
+
expectedHead: input.expectedHead,
|
|
337
|
+
expectedTree: input.expectedTree
|
|
338
|
+
});
|
|
234
339
|
if (committed.status === 'failed')
|
|
235
340
|
return {
|
|
236
341
|
...committed,
|
|
@@ -241,42 +346,42 @@ function executeUnlocked(input, task, mode) {
|
|
|
241
346
|
snapshot: committed.snapshot
|
|
242
347
|
};
|
|
243
348
|
const warnings = [];
|
|
244
|
-
if (orchestrationCompletion) {
|
|
245
|
-
try {
|
|
246
|
-
commitOrchestrationStageCompletion(orchestrationCompletion);
|
|
247
|
-
}
|
|
248
|
-
catch (error) {
|
|
249
|
-
warnings.push(warning('ORCHESTRATION_COMPLETION_FAILED', error instanceof Error ? error.message : String(error), true, 'orchestration', task?.taskId ?? 'orchestration', 'ACTION_REQUIRED'));
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
349
|
let status = committed.status;
|
|
253
350
|
let result = committed.status === 'applied' ? 'committed' : 'no_op';
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
351
|
+
if (delivery.mode === 'push') {
|
|
352
|
+
const target = `${delivery.remote}:${delivery.refs[0]}`;
|
|
353
|
+
const decision = commitPushDecision({ branch }, target);
|
|
354
|
+
if (!decision.shouldPush) {
|
|
355
|
+
warnings.push(decision.warning);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
const pushed = pushGitRefs({
|
|
359
|
+
cwd: input.cwd, remote: delivery.remote, refs: delivery.refs,
|
|
360
|
+
expectedSha: committed.snapshot?.head ?? gitText(input.cwd, ['rev-parse', 'HEAD'])
|
|
361
|
+
});
|
|
362
|
+
if (pushed.status !== 'applied')
|
|
363
|
+
warnings.push(warning('COMMIT_PUSH_FAILED', pushed.error?.message ?? 'Git push failed', true, 'push', target, 'ACTION_REQUIRED'));
|
|
364
|
+
}
|
|
268
365
|
}
|
|
269
366
|
if (warnings.length > 0) {
|
|
270
367
|
status = 'applied';
|
|
271
368
|
result = 'committed_with_warnings';
|
|
272
369
|
}
|
|
273
370
|
if (task && (committed.status === 'applied' || committed.status === 'no-op')) {
|
|
274
|
-
const
|
|
371
|
+
const committedHead = checkpointCommittedHead ?? committed.snapshot?.head ?? gitText(task.repoRoot, ['rev-parse', 'HEAD']);
|
|
372
|
+
const taskWarning = syncTaskCommit(input, task, committedHead);
|
|
275
373
|
if (taskWarning) {
|
|
276
374
|
warnings.push(taskWarning);
|
|
277
375
|
status = 'applied';
|
|
278
376
|
result = 'committed_with_warnings';
|
|
279
377
|
}
|
|
378
|
+
if (delivery.mode === 'local' && !taskWarning && pendingIntent && checkpointCommittedHead) {
|
|
379
|
+
const synced = updateCheckpointIntent(pendingIntent, {
|
|
380
|
+
state: 'synced', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
381
|
+
});
|
|
382
|
+
writeCheckpointIntent(task.repoRoot, synced);
|
|
383
|
+
removeCheckpointIntent(task.repoRoot, task.taskId);
|
|
384
|
+
}
|
|
280
385
|
}
|
|
281
386
|
return {
|
|
282
387
|
status,
|
|
@@ -101,12 +101,12 @@ function lifecycleTaskId(request, repoRoot) {
|
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
function applyLifecycleWithAuthority(context, request) {
|
|
104
|
+
async function applyLifecycleWithAuthority(context, request) {
|
|
105
105
|
const conflict = overrideDryRunConflict(request);
|
|
106
106
|
if (conflict) {
|
|
107
107
|
return taskLifecycleFailure(request, { code: 'LIFECYCLE_PAYLOAD_INVALID', message: conflict.message });
|
|
108
108
|
}
|
|
109
|
-
const execute = () => {
|
|
109
|
+
const execute = async () => {
|
|
110
110
|
const lifecycleResult = applyTaskLifecycle(request, { repoRoot: context.repoRoot });
|
|
111
111
|
if (lifecycleResult.status !== 'failed' || !request.overrideTicket)
|
|
112
112
|
return lifecycleResult;
|
|
@@ -116,7 +116,7 @@ function applyLifecycleWithAuthority(context, request) {
|
|
|
116
116
|
error: { code: 'OVERRIDE_PAYLOAD_INVALID', message: 'override ticket requires --override-target and --override-scope' }
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
const override = consumeHumanOverride({
|
|
119
|
+
const override = await consumeHumanOverride({
|
|
120
120
|
taskRef: request.taskRef,
|
|
121
121
|
ticketId: request.overrideTicket,
|
|
122
122
|
failureId: failureId('lifecycle.apply', lifecycleResult.error?.code ?? 'LIFECYCLE_FAILED'),
|
|
@@ -133,9 +133,9 @@ function applyLifecycleWithAuthority(context, request) {
|
|
|
133
133
|
};
|
|
134
134
|
const taskId = lifecycleTaskId(request, context.repoRoot);
|
|
135
135
|
if (!taskId)
|
|
136
|
-
return execute();
|
|
136
|
+
return await execute();
|
|
137
137
|
try {
|
|
138
|
-
return withTaskExecutionLock(context.repoRoot, taskId, `task-lifecycle.${request.intent}`, execute);
|
|
138
|
+
return await withTaskExecutionLock(context.repoRoot, taskId, `task-lifecycle.${request.intent}`, execute);
|
|
139
139
|
}
|
|
140
140
|
catch (error) {
|
|
141
141
|
if (!(error instanceof TaskExecutionLockError))
|
|
@@ -210,6 +210,9 @@ export function dispatchTaskControlOperation(context, operation) {
|
|
|
210
210
|
operationTaskId(context, operation.request.taskRef);
|
|
211
211
|
return applyTaskFinalization(operation.request, {
|
|
212
212
|
repoRoot: context.repoRoot,
|
|
213
|
+
...(context.source === 'sandbox-executor' ? {
|
|
214
|
+
controlBinding: { generation: context.generation, requestId: context.requestId }
|
|
215
|
+
} : {}),
|
|
213
216
|
preflight: (request, options) => verifyTaskEvent({ ...request, event: 'complete-task.hard-preflight' }, options)
|
|
214
217
|
});
|
|
215
218
|
}
|