@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
|
@@ -12,8 +12,8 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
12
12
|
syncComment: syncPlatformComment,
|
|
13
13
|
addWarning: applyWorkflowWarningIntent
|
|
14
14
|
};
|
|
15
|
-
function verifyCreatedTask(repoRoot, taskId) {
|
|
16
|
-
const verification = verifyTaskEvent({ taskRef: taskId, event: 'create-task.completed' }, { repoRoot });
|
|
15
|
+
async function verifyCreatedTask(repoRoot, taskId) {
|
|
16
|
+
const verification = await verifyTaskEvent({ taskRef: taskId, event: 'create-task.completed' }, { repoRoot });
|
|
17
17
|
if (verification.status === 'pass') {
|
|
18
18
|
return { operation: { name: 'task:verify', status: 'pass', reasonCode: null }, error: null };
|
|
19
19
|
}
|
|
@@ -42,7 +42,7 @@ function issueFromTask(repoRoot, taskId) {
|
|
|
42
42
|
const match = /^issue_number:\s*(\d+)\s*$/m.exec(content);
|
|
43
43
|
return match ? { number: Number(match[1]), url: '' } : null;
|
|
44
44
|
}
|
|
45
|
-
function createTask(value, options) {
|
|
45
|
+
async function createTask(value, options) {
|
|
46
46
|
const dependencies = { ...DEFAULT_DEPENDENCIES, ...options.dependencies };
|
|
47
47
|
let candidate;
|
|
48
48
|
let local;
|
|
@@ -65,13 +65,13 @@ function createTask(value, options) {
|
|
|
65
65
|
name: 'task:local', status: local.status, reasonCode: null
|
|
66
66
|
}];
|
|
67
67
|
let issue = issueFromTask(options.repoRoot, local.task.id);
|
|
68
|
-
const created = dependencies.createIssue(local.task.id, { cwd: options.repoRoot, agent: candidate.agent });
|
|
68
|
+
const created = await dependencies.createIssue(local.task.id, { cwd: options.repoRoot, agent: candidate.agent });
|
|
69
69
|
operations.push(...platformOperations('platform-create', created.operations));
|
|
70
70
|
if (created.issue)
|
|
71
71
|
issue = { number: created.issue.number, url: created.issue.url };
|
|
72
72
|
let platformFailure = created.status === 'failed' || created.status === 'blocked' ? created : null;
|
|
73
73
|
if (!platformFailure && (created.task.issueNumber || issue)) {
|
|
74
|
-
const synced = dependencies.syncIssue(local.task.id, {
|
|
74
|
+
const synced = await dependencies.syncIssue(local.task.id, {
|
|
75
75
|
cwd: options.repoRoot,
|
|
76
76
|
agent: candidate.agent,
|
|
77
77
|
status: 'waiting-for-triage',
|
|
@@ -86,7 +86,7 @@ function createTask(value, options) {
|
|
|
86
86
|
if (synced.status === 'failed' || synced.status === 'blocked')
|
|
87
87
|
platformFailure = synced;
|
|
88
88
|
if (!platformFailure) {
|
|
89
|
-
const commented = dependencies.syncComment(local.task.id, { cwd: options.repoRoot, kind: 'task', agent: candidate.agent });
|
|
89
|
+
const commented = await dependencies.syncComment(local.task.id, { cwd: options.repoRoot, kind: 'task', agent: candidate.agent });
|
|
90
90
|
operations.push(...platformOperations('platform-comment', commented.operations));
|
|
91
91
|
if (commented.status === 'failed' || commented.status === 'blocked')
|
|
92
92
|
platformFailure = commented;
|
|
@@ -99,7 +99,7 @@ function createTask(value, options) {
|
|
|
99
99
|
code: 'ISSUE_CREATE_FAILED', target: 'issue', message: `${error.code}: ${error.message}`,
|
|
100
100
|
action: 'Fix platform authentication or connectivity, then retry Issue creation for this task.'
|
|
101
101
|
}, { repoRoot: options.repoRoot });
|
|
102
|
-
const verified = verifyCreatedTask(options.repoRoot, local.task.id);
|
|
102
|
+
const verified = await verifyCreatedTask(options.repoRoot, local.task.id);
|
|
103
103
|
operations.push(verified.operation);
|
|
104
104
|
if (verified.error)
|
|
105
105
|
return {
|
|
@@ -116,7 +116,7 @@ function createTask(value, options) {
|
|
|
116
116
|
error
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
const verified = verifyCreatedTask(options.repoRoot, local.task.id);
|
|
119
|
+
const verified = await verifyCreatedTask(options.repoRoot, local.task.id);
|
|
120
120
|
operations.push(verified.operation);
|
|
121
121
|
if (verified.error)
|
|
122
122
|
return {
|
package/dist/lib/task/create.js
CHANGED
|
@@ -4,6 +4,8 @@ import path from 'node:path';
|
|
|
4
4
|
import { isValidAgentInfraVersion, VERSION } from '../version.js';
|
|
5
5
|
import { loadShortIdByTaskId, mutateShortIdRegistry } from './short-id.js';
|
|
6
6
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
7
|
+
import { readDeliveryDefaults, validateBaseRef, validateRemote } from './delivery-target.js';
|
|
8
|
+
import { buildUnboundFact, encodePrDeliveryFact } from './pr-delivery-fact.js';
|
|
7
9
|
const AGENTS = ['claude', 'codex', 'antigravity', 'opencode', 'cursor'];
|
|
8
10
|
const TYPES = ['feature', 'bugfix', 'refactor', 'docs', 'chore'];
|
|
9
11
|
const PRIORITIES = ['Urgent', 'High', 'Medium', 'Low'];
|
|
@@ -15,12 +17,15 @@ const TASK_INPUT_KEYS = [
|
|
|
15
17
|
function payloadError(message) {
|
|
16
18
|
throw new Error(`TASK_CREATE_PAYLOAD_INVALID: ${message}`);
|
|
17
19
|
}
|
|
18
|
-
function exactKeys(value, expected, label) {
|
|
20
|
+
function exactKeys(value, expected, label, optional = []) {
|
|
19
21
|
const actual = Object.keys(value).sort();
|
|
20
22
|
const wanted = [...expected].sort();
|
|
21
|
-
|
|
23
|
+
const allowed = new Set([...expected, ...optional]);
|
|
24
|
+
if (actual.some((key) => !allowed.has(key))) {
|
|
22
25
|
payloadError(`${label} has unknown or missing fields`);
|
|
23
26
|
}
|
|
27
|
+
if (expected.some((key) => !actual.includes(key)))
|
|
28
|
+
payloadError(`${label} has unknown or missing fields`);
|
|
24
29
|
}
|
|
25
30
|
function cleanString(value, label, maxBytes, oneLine = false) {
|
|
26
31
|
if (typeof value !== 'string' || value.length === 0 || Buffer.byteLength(value, 'utf8') > maxBytes) {
|
|
@@ -43,7 +48,7 @@ function validateTaskCreateCandidate(value) {
|
|
|
43
48
|
exactKeys(candidate, [
|
|
44
49
|
'version', 'idempotencyKey', 'agent', 'title', 'type', 'branchSlug',
|
|
45
50
|
'priority', 'effort', 'description', 'taskInput'
|
|
46
|
-
], 'candidate');
|
|
51
|
+
], 'candidate', ['deliveryRemote', 'deliveryBaseRef']);
|
|
47
52
|
if (candidate.version !== 1)
|
|
48
53
|
payloadError('version must be 1');
|
|
49
54
|
const idempotencyKey = cleanString(candidate.idempotencyKey, 'idempotencyKey', 64, true);
|
|
@@ -58,6 +63,16 @@ function validateTaskCreateCandidate(value) {
|
|
|
58
63
|
payloadError('branchSlug must be lowercase ASCII kebab-case with length 3-64');
|
|
59
64
|
}
|
|
60
65
|
const description = cleanString(candidate.description, 'description', 8 * 1024);
|
|
66
|
+
const deliveryRemote = candidate.deliveryRemote === undefined
|
|
67
|
+
? undefined
|
|
68
|
+
: cleanString(candidate.deliveryRemote, 'deliveryRemote', 200, true);
|
|
69
|
+
const deliveryBaseRef = candidate.deliveryBaseRef === undefined
|
|
70
|
+
? undefined
|
|
71
|
+
: cleanString(candidate.deliveryBaseRef, 'deliveryBaseRef', 200, true);
|
|
72
|
+
if (deliveryRemote !== undefined && !validateRemote(deliveryRemote))
|
|
73
|
+
payloadError('deliveryRemote is invalid');
|
|
74
|
+
if (deliveryBaseRef !== undefined && !validateBaseRef(deliveryBaseRef))
|
|
75
|
+
payloadError('deliveryBaseRef is invalid');
|
|
61
76
|
if (!candidate.taskInput || typeof candidate.taskInput !== 'object' || Array.isArray(candidate.taskInput)) {
|
|
62
77
|
payloadError('taskInput must be an object');
|
|
63
78
|
}
|
|
@@ -79,6 +94,8 @@ function validateTaskCreateCandidate(value) {
|
|
|
79
94
|
priority: enumValue(candidate.priority, PRIORITIES, 'priority'),
|
|
80
95
|
effort: enumValue(candidate.effort, EFFORTS, 'effort'),
|
|
81
96
|
description,
|
|
97
|
+
...(deliveryRemote === undefined ? {} : { deliveryRemote }),
|
|
98
|
+
...(deliveryBaseRef === undefined ? {} : { deliveryBaseRef }),
|
|
82
99
|
taskInput
|
|
83
100
|
};
|
|
84
101
|
}
|
|
@@ -94,6 +111,8 @@ function canonicalTaskCreateCandidate(candidate) {
|
|
|
94
111
|
priority: valid.priority,
|
|
95
112
|
effort: valid.effort,
|
|
96
113
|
description: valid.description,
|
|
114
|
+
deliveryRemote: valid.deliveryRemote ?? null,
|
|
115
|
+
deliveryBaseRef: valid.deliveryBaseRef ?? null,
|
|
97
116
|
taskInput: Object.fromEntries(TASK_INPUT_KEYS.map((key) => [key, valid.taskInput[key]]))
|
|
98
117
|
});
|
|
99
118
|
}
|
|
@@ -145,7 +164,11 @@ function renderTask(params) {
|
|
|
145
164
|
'target_date:',
|
|
146
165
|
'current_step: requirement-analysis',
|
|
147
166
|
`assigned_to: ${candidate.agent}`,
|
|
148
|
-
|
|
167
|
+
`pr_delivery_fact: ${JSON.stringify(encodePrDeliveryFact(buildUnboundFact()))}`,
|
|
168
|
+
`delivery_remote: ${candidate.deliveryRemote ?? params.delivery.remote}`,
|
|
169
|
+
`delivery_base_ref: ${candidate.deliveryBaseRef ?? params.delivery.baseRef}`,
|
|
170
|
+
'checkpoint_commit:',
|
|
171
|
+
'delivery_remote_head:',
|
|
149
172
|
`task_create_key_digest: ${params.keyDigest}`,
|
|
150
173
|
`task_create_candidate_digest: ${params.candidateDigest}`,
|
|
151
174
|
'---'
|
|
@@ -175,7 +198,10 @@ function readProject(repoRoot) {
|
|
|
175
198
|
if (typeof config.project !== 'string' || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(config.project)) {
|
|
176
199
|
throw new Error('TASK_CREATE_CONFIG_INVALID: project is missing or invalid');
|
|
177
200
|
}
|
|
178
|
-
|
|
201
|
+
const delivery = readDeliveryDefaults(repoRoot);
|
|
202
|
+
if (!delivery.ok)
|
|
203
|
+
throw new Error(`TASK_CREATE_CONFIG_INVALID: ${delivery.message}`);
|
|
204
|
+
return { project: config.project, delivery: delivery.value };
|
|
179
205
|
}
|
|
180
206
|
function assertRealDirectory(directory, code) {
|
|
181
207
|
const stat = fs.lstatSync(directory);
|
|
@@ -269,7 +295,7 @@ function createLocalTask(value, options) {
|
|
|
269
295
|
ensureRealDirectory(path.join(repoRoot, '.agents'), 'TASK_CREATE_WORKSPACE_INVALID');
|
|
270
296
|
ensureRealDirectory(workspaceRoot, 'TASK_CREATE_WORKSPACE_INVALID');
|
|
271
297
|
ensureRealDirectory(activeRoot, 'TASK_CREATE_WORKSPACE_INVALID');
|
|
272
|
-
const
|
|
298
|
+
const projectConfig = readProject(repoRoot);
|
|
273
299
|
const canonical = canonicalTaskCreateCandidate(candidate);
|
|
274
300
|
const candidateDigest = sha256(canonical);
|
|
275
301
|
const keyDigest = sha256(candidate.idempotencyKey);
|
|
@@ -312,7 +338,7 @@ function createLocalTask(value, options) {
|
|
|
312
338
|
if (!templateStat.isFile() || templateStat.isSymbolicLink())
|
|
313
339
|
throw new Error('TASK_CREATE_TEMPLATE_INVALID');
|
|
314
340
|
const rendered = renderTask({
|
|
315
|
-
template: fs.readFileSync(templatePath, 'utf8'), candidate, taskId, project, timestamp,
|
|
341
|
+
template: fs.readFileSync(templatePath, 'utf8'), candidate, taskId, project: projectConfig.project, delivery: projectConfig.delivery, timestamp,
|
|
316
342
|
agentInfraVersion, keyDigest, candidateDigest
|
|
317
343
|
});
|
|
318
344
|
const temporary = path.join(workspaceRoot, `.task-create.tmp.${process.pid}.${randomUUID()}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isValidAgentInfraVersion } from '../version.js';
|
|
2
2
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
3
3
|
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, validateLedgerRows } from './ledger.js';
|
|
4
|
+
import { parseInvalidationDocument } from './invalidation.js';
|
|
4
5
|
function validateCurrentTaskContract(content) {
|
|
5
6
|
let metadata;
|
|
6
7
|
try {
|
|
@@ -29,7 +30,10 @@ function validateCurrentTaskContract(content) {
|
|
|
29
30
|
const invalid = validateLedgerRows(ledger.rows);
|
|
30
31
|
if (invalid)
|
|
31
32
|
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${invalid.code}: ${invalid.message}` };
|
|
32
|
-
|
|
33
|
+
const invalidation = parseInvalidationDocument(content);
|
|
34
|
+
if (!invalidation.ok)
|
|
35
|
+
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${invalidation.code}: ${invalidation.message}` };
|
|
36
|
+
return { ok: true, metadata, ledger, invalidation: invalidation.document };
|
|
33
37
|
}
|
|
34
38
|
export { validateCurrentTaskContract };
|
|
35
39
|
//# sourceMappingURL=current-contract.js.map
|
|
@@ -109,31 +109,8 @@ function resolveDecisionDetail(content, rowId, anchor) {
|
|
|
109
109
|
}
|
|
110
110
|
return { status: 'found', block: matches[0] };
|
|
111
111
|
}
|
|
112
|
-
const INFORMAL_SHORT_HEADING = /^(?:AN|PL|CD|HD)-[1-9]\d*[::]\s*(?:上一轮)?简短复核$/i;
|
|
113
|
-
const INFORMAL_SHORT_FRAGMENT = /^简短(?:结论|说明)$/;
|
|
114
|
-
function isInformalShortBlock(block) {
|
|
115
|
-
if (block.canonical || block.content.length > 600)
|
|
116
|
-
return false;
|
|
117
|
-
if (!INFORMAL_SHORT_HEADING.test(block.heading))
|
|
118
|
-
return false;
|
|
119
|
-
const scanned = scanVisibleMarkdown(block.content);
|
|
120
|
-
const bodyLines = scanned.lines
|
|
121
|
-
.filter((line) => !scanned.headings.some((heading) => heading.start === line.start) && line.text.trim())
|
|
122
|
-
.map((line) => line.text);
|
|
123
|
-
if (bodyLines.length === 0 || bodyLines.length > 2)
|
|
124
|
-
return false;
|
|
125
|
-
const fragments = bodyLines.map((line) => line.match(/^\s*[-*]\s+([^\s].*?)\s*$/)?.[1] ?? null);
|
|
126
|
-
if (fragments.some((fragment) => fragment === null))
|
|
127
|
-
return false;
|
|
128
|
-
return fragments.every((fragment) => INFORMAL_SHORT_FRAGMENT.test(fragment));
|
|
129
|
-
}
|
|
130
|
-
function hasDirectPrecedingAnchor(block, scanned) {
|
|
131
|
-
return scanned.anchors.some((anchor) => (anchor.end < block.start
|
|
132
|
-
&& !scanned.lines.some((line) => line.start > anchor.end && line.start < block.start && line.text.trim())));
|
|
133
|
-
}
|
|
134
112
|
function inspectDecisionDetailDuplicates(content) {
|
|
135
113
|
const blocks = parseDecisionDetailBlocks(content);
|
|
136
|
-
const scanned = scanVisibleMarkdown(content);
|
|
137
114
|
const grouped = new Map();
|
|
138
115
|
for (const block of blocks) {
|
|
139
116
|
const key = block.id.toUpperCase();
|
|
@@ -145,15 +122,13 @@ function inspectDecisionDetailDuplicates(content) {
|
|
|
145
122
|
for (const group of grouped.values()) {
|
|
146
123
|
if (group.length < 2)
|
|
147
124
|
continue;
|
|
148
|
-
|
|
149
|
-
const repairable = canonical.length === 1 && group.every((block) => (block.canonical || (!hasDirectPrecedingAnchor(block, scanned) && isInformalShortBlock(block))));
|
|
150
|
-
duplicates.push({ id: canonical[0]?.id ?? group[0].id, blocks: group, repairable });
|
|
125
|
+
duplicates.push({ id: group[0].id, blocks: group });
|
|
151
126
|
}
|
|
152
127
|
if (duplicates.length === 0)
|
|
153
128
|
return { ok: true, blocks };
|
|
154
129
|
const summary = duplicates.map((duplicate) => {
|
|
155
130
|
const types = duplicate.blocks.map((block) => block.canonical ? 'canonical' : 'informal').join(', ');
|
|
156
|
-
return `${duplicate.id} (${duplicate.blocks.length} blocks: ${types}
|
|
131
|
+
return `${duplicate.id} (${duplicate.blocks.length} blocks: ${types})`;
|
|
157
132
|
}).join(', ');
|
|
158
133
|
return {
|
|
159
134
|
ok: false,
|
|
@@ -163,26 +138,6 @@ function inspectDecisionDetailDuplicates(content) {
|
|
|
163
138
|
duplicates
|
|
164
139
|
};
|
|
165
140
|
}
|
|
166
|
-
function repairDecisionDetailDuplicates(content) {
|
|
167
|
-
const inspection = inspectDecisionDetailDuplicates(content);
|
|
168
|
-
if (inspection.ok)
|
|
169
|
-
return { ok: true, changed: false, content };
|
|
170
|
-
const unsafe = inspection.duplicates.filter((duplicate) => !duplicate.repairable);
|
|
171
|
-
if (unsafe.length > 0) {
|
|
172
|
-
return {
|
|
173
|
-
ok: false,
|
|
174
|
-
code: 'DECISION_DETAIL_AMBIGUOUS',
|
|
175
|
-
message: `Cannot safely repair duplicate decision detail ids: ${unsafe.map((duplicate) => duplicate.id).join(', ')}`,
|
|
176
|
-
content
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
const removals = inspection.duplicates.flatMap((duplicate) => duplicate.blocks.filter((block) => !block.canonical));
|
|
180
|
-
let repaired = content;
|
|
181
|
-
for (const block of removals.sort((left, right) => right.start - left.start)) {
|
|
182
|
-
repaired = repaired.slice(0, block.start) + repaired.slice(block.end);
|
|
183
|
-
}
|
|
184
|
-
return { ok: true, changed: repaired !== content, content: repaired };
|
|
185
|
-
}
|
|
186
141
|
const FIELD_KEYS = {
|
|
187
142
|
'为什么现在要决定': 'why', 'why decide now': 'why', 'why a decision is needed now': 'why',
|
|
188
143
|
'要决定什么': 'decision', 'what to decide': 'decision', 'what needs a decision': 'decision',
|
|
@@ -259,5 +214,5 @@ function normalizeDecisionDetailForDisplay(block) {
|
|
|
259
214
|
ordered.push(byKey.get('implementation'));
|
|
260
215
|
return [body.slice(heading.start, heading.end).trim(), ...ordered].join('\n\n').trim();
|
|
261
216
|
}
|
|
262
|
-
export { inspectDecisionDetailDuplicates, normalizeDecisionDetailForDisplay, parseDecisionDetailBlocks, parseDecisionEvidence,
|
|
217
|
+
export { inspectDecisionDetailDuplicates, normalizeDecisionDetailForDisplay, parseDecisionDetailBlocks, parseDecisionEvidence, resolveDecisionDetail, scanVisibleMarkdown };
|
|
263
218
|
//# sourceMappingURL=decision-details.js.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
const REMOTE_RE = /^(?!-)(?!.*\.\.)(?!.*[~^:?*\\\s])[A-Za-z0-9._/-]+$/;
|
|
5
|
+
const REF_RE = /^(?!-)(?!.*\.\.)(?!.*(?:^|\/)\.)(?!.*[~^:?*\\\s])[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/;
|
|
6
|
+
function validateRemote(value) {
|
|
7
|
+
return typeof value === 'string' && value.length > 0 && REMOTE_RE.test(value);
|
|
8
|
+
}
|
|
9
|
+
function validateBaseRef(value) {
|
|
10
|
+
return typeof value === 'string' && value.length > 0 && !value.startsWith('refs/') && REF_RE.test(value);
|
|
11
|
+
}
|
|
12
|
+
function invalid(field, value) {
|
|
13
|
+
return { ok: false, code: 'DELIVERY_TARGET_INVALID', message: `${field} is invalid: ${String(value ?? '')}` };
|
|
14
|
+
}
|
|
15
|
+
function bindDeliveryTarget(input) {
|
|
16
|
+
const remote = input.existing?.remote ?? input.explicit?.remote ?? input.defaults?.remote;
|
|
17
|
+
const baseRef = input.existing?.baseRef ?? input.explicit?.baseRef ?? input.defaults?.baseRef;
|
|
18
|
+
if (input.existing?.remote !== undefined && input.explicit?.remote !== undefined && input.existing.remote !== input.explicit.remote) {
|
|
19
|
+
return { ok: false, code: 'DELIVERY_TARGET_CONFLICT', message: 'Explicit delivery remote does not match the task binding' };
|
|
20
|
+
}
|
|
21
|
+
if (input.existing?.baseRef !== undefined && input.explicit?.baseRef !== undefined && input.existing.baseRef !== input.explicit.baseRef) {
|
|
22
|
+
return { ok: false, code: 'DELIVERY_TARGET_CONFLICT', message: 'Explicit delivery base ref does not match the task binding' };
|
|
23
|
+
}
|
|
24
|
+
if (!validateRemote(remote))
|
|
25
|
+
return invalid('delivery remote', remote);
|
|
26
|
+
if (!validateBaseRef(baseRef))
|
|
27
|
+
return invalid('delivery base ref', baseRef);
|
|
28
|
+
return { ok: true, value: { remote, baseRef } };
|
|
29
|
+
}
|
|
30
|
+
function readDeliveryDefaults(repoRoot) {
|
|
31
|
+
try {
|
|
32
|
+
const configPath = path.join(repoRoot, '.agents', '.airc.json');
|
|
33
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
34
|
+
if (!config.delivery || typeof config.delivery !== 'object' || Array.isArray(config.delivery)) {
|
|
35
|
+
return { ok: false, code: 'DELIVERY_CONFIG_INVALID', message: 'delivery config must declare remote and baseRef' };
|
|
36
|
+
}
|
|
37
|
+
const delivery = config.delivery;
|
|
38
|
+
if (typeof delivery.remote !== 'string' || typeof delivery.baseRef !== 'string') {
|
|
39
|
+
return { ok: false, code: 'DELIVERY_CONFIG_INVALID', message: 'delivery config must declare remote and baseRef' };
|
|
40
|
+
}
|
|
41
|
+
return bindDeliveryTarget({
|
|
42
|
+
defaults: {
|
|
43
|
+
remote: delivery.remote,
|
|
44
|
+
baseRef: delivery.baseRef
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return { ok: false, code: 'DELIVERY_CONFIG_INVALID', message: error instanceof Error ? error.message : String(error) };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function resolveDeliveryTarget(repoRoot, existing = {}, explicit = {}) {
|
|
53
|
+
const defaults = readDeliveryDefaults(repoRoot);
|
|
54
|
+
if (!defaults.ok)
|
|
55
|
+
return defaults;
|
|
56
|
+
return bindDeliveryTarget({ defaults: defaults.value, existing, explicit });
|
|
57
|
+
}
|
|
58
|
+
function gitText(repoRoot, args) {
|
|
59
|
+
return execFileSync('git', [...args], {
|
|
60
|
+
cwd: repoRoot,
|
|
61
|
+
encoding: 'utf8',
|
|
62
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
63
|
+
}).trim();
|
|
64
|
+
}
|
|
65
|
+
function resolveTargetHead(repoRoot, target) {
|
|
66
|
+
try {
|
|
67
|
+
const output = gitText(repoRoot, ['ls-remote', '--refs', target.remote, `refs/heads/${target.baseRef}`]);
|
|
68
|
+
const head = output.split(/\s+/)[0] ?? '';
|
|
69
|
+
if (!/^[a-f0-9]{40}$/i.test(head)) {
|
|
70
|
+
return { ok: false, code: 'DELIVERY_TARGET_UNAVAILABLE', message: `Delivery target ${target.remote}/${target.baseRef} is unavailable` };
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
gitText(repoRoot, ['cat-file', '-e', `${head}^{commit}`]);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return { ok: false, code: 'DELIVERY_TARGET_OBJECT_MISSING', message: `Delivery target commit ${head} is not available locally` };
|
|
77
|
+
}
|
|
78
|
+
return { ok: true, value: target, head };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return { ok: false, code: 'DELIVERY_TARGET_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function resolveDiffBase(repoRoot, reviewedHead, targetHead) {
|
|
85
|
+
try {
|
|
86
|
+
const diffBase = gitText(repoRoot, ['merge-base', reviewedHead, targetHead]);
|
|
87
|
+
if (!/^[a-f0-9]{40}$/i.test(diffBase)) {
|
|
88
|
+
return { ok: false, code: 'DELIVERY_DIFF_BASE_UNAVAILABLE', message: 'Git returned an invalid diff base' };
|
|
89
|
+
}
|
|
90
|
+
return { ok: true, diffBase };
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return { ok: false, code: 'DELIVERY_DIFF_BASE_UNAVAILABLE', message: error instanceof Error ? error.message : String(error) };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export { bindDeliveryTarget, readDeliveryDefaults, resolveDeliveryTarget, resolveTargetHead, resolveDiffBase, validateBaseRef, validateRemote };
|
|
97
|
+
//# sourceMappingURL=delivery-target.js.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { parseTaskFrontmatter } from './frontmatter.js';
|
|
5
|
+
import { resolveTaskRef } from './resolve-ref.js';
|
|
6
|
+
import { resolveDeliveryTarget, resolveDiffBase, resolveTargetHead, validateBaseRef, validateRemote } from './delivery-target.js';
|
|
7
|
+
import { extractReviewBaseline, extractReviewDiffBase, extractReviewTargetHead, extractReviewedHead, findAuthoritativeReviewCodeArtifact } from './review-fingerprint.js';
|
|
8
|
+
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
9
|
+
import { withRepositoryMutationLock, withTaskExecutionLock } from './task-execution-lock.js';
|
|
10
|
+
function classifyDeliveryState(localHead, remoteHead, lastDelivered) {
|
|
11
|
+
if (remoteHead === null)
|
|
12
|
+
return { state: 'absent', shouldPush: true };
|
|
13
|
+
if (remoteHead === localHead)
|
|
14
|
+
return { state: 'same', shouldPush: false };
|
|
15
|
+
if (lastDelivered && remoteHead === lastDelivered)
|
|
16
|
+
return { state: 'known-old', shouldPush: true };
|
|
17
|
+
return { state: 'unknown-drift', shouldPush: false };
|
|
18
|
+
}
|
|
19
|
+
function git(cwd, args) {
|
|
20
|
+
const result = spawnSync('git', [...args], { cwd, encoding: 'utf8' });
|
|
21
|
+
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
|
|
22
|
+
}
|
|
23
|
+
function gitValue(cwd, args) {
|
|
24
|
+
const result = git(cwd, args);
|
|
25
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
26
|
+
}
|
|
27
|
+
function validateBranch(cwd, branch) {
|
|
28
|
+
return git(cwd, ['check-ref-format', `refs/heads/${branch}`]).status === 0;
|
|
29
|
+
}
|
|
30
|
+
function validateReviewTargetCompatibility(repoRoot, taskDir, target, reviewedHead) {
|
|
31
|
+
const artifact = findAuthoritativeReviewCodeArtifact(taskDir);
|
|
32
|
+
if (!artifact.ok || !artifact.path)
|
|
33
|
+
return { ok: false, code: 'DELIVERY_REVIEW_REQUIRED', message: 'A current review-code artifact is required before delivery' };
|
|
34
|
+
let content;
|
|
35
|
+
try {
|
|
36
|
+
content = fs.readFileSync(artifact.path, 'utf8');
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return { ok: false, code: 'DELIVERY_REVIEW_REQUIRED', message: error instanceof Error ? error.message : String(error) };
|
|
40
|
+
}
|
|
41
|
+
const savedReviewedHead = extractReviewedHead(content) || extractReviewBaseline(content);
|
|
42
|
+
const savedTargetHead = extractReviewTargetHead(content);
|
|
43
|
+
const savedDiffBase = extractReviewDiffBase(content);
|
|
44
|
+
if (!savedReviewedHead || !savedTargetHead || !savedDiffBase) {
|
|
45
|
+
return { ok: false, code: 'DELIVERY_REVIEW_TARGET_INVALID', message: 'review-code must save reviewed head, target head, and diff base before delivery' };
|
|
46
|
+
}
|
|
47
|
+
if (savedReviewedHead !== reviewedHead) {
|
|
48
|
+
return { ok: false, code: 'DELIVERY_REVIEW_REQUIRED', message: 'review-code reviewed head does not match last_reviewed_commit' };
|
|
49
|
+
}
|
|
50
|
+
const saved = resolveDiffBase(repoRoot, reviewedHead, savedTargetHead);
|
|
51
|
+
if (!saved.ok || saved.diffBase !== savedDiffBase) {
|
|
52
|
+
return { ok: false, code: 'DELIVERY_REVIEW_TARGET_INVALID', message: saved.ok ? 'saved review diff base does not match saved target head' : saved.message };
|
|
53
|
+
}
|
|
54
|
+
const currentTarget = resolveTargetHead(repoRoot, target);
|
|
55
|
+
if (!currentTarget.ok)
|
|
56
|
+
return { ok: false, code: currentTarget.code, message: currentTarget.message };
|
|
57
|
+
const current = resolveDiffBase(repoRoot, reviewedHead, currentTarget.head);
|
|
58
|
+
if (!current.ok)
|
|
59
|
+
return { ok: false, code: current.code, message: current.message };
|
|
60
|
+
if (current.diffBase !== savedDiffBase) {
|
|
61
|
+
return { ok: false, code: 'DELIVERY_REVIEW_TARGET_CHANGED', message: 'current delivery target changed the reviewed diff base; re-run review-code' };
|
|
62
|
+
}
|
|
63
|
+
return { ok: true };
|
|
64
|
+
}
|
|
65
|
+
function failure(taskId, code, message, retryable = false, status = retryable ? 'blocked' : 'failed') {
|
|
66
|
+
return { status, changed: false, taskId, remoteHead: null, localHead: null, state: null, error: { code, message, retryable } };
|
|
67
|
+
}
|
|
68
|
+
function deliverUnlocked(taskId, taskDir, repoRoot, options) {
|
|
69
|
+
let frontmatter;
|
|
70
|
+
try {
|
|
71
|
+
frontmatter = parseTaskFrontmatter(fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8'));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return failure(taskId, 'TASK_CONTEXT_UNREADABLE', error instanceof Error ? error.message : String(error));
|
|
75
|
+
}
|
|
76
|
+
if (frontmatter.status !== 'active')
|
|
77
|
+
return failure(taskId, 'TASK_STATE_INVALID', 'task branch delivery requires an active task');
|
|
78
|
+
const branch = frontmatter.branch ?? '';
|
|
79
|
+
if (!branch)
|
|
80
|
+
return failure(taskId, 'DELIVERY_BRANCH_MISSING', 'task branch is missing');
|
|
81
|
+
if (!validateBranch(repoRoot, branch))
|
|
82
|
+
return failure(taskId, 'DELIVERY_BRANCH_INVALID', 'task branch is invalid');
|
|
83
|
+
if (!frontmatter.delivery_remote || !frontmatter.delivery_base_ref) {
|
|
84
|
+
return failure(taskId, 'DELIVERY_TARGET_MISSING', 'task delivery target is not bound; recreate or repair task metadata before delivery');
|
|
85
|
+
}
|
|
86
|
+
const target = resolveDeliveryTarget(repoRoot, {
|
|
87
|
+
remote: frontmatter.delivery_remote,
|
|
88
|
+
baseRef: frontmatter.delivery_base_ref
|
|
89
|
+
}, {
|
|
90
|
+
...(options.remote === undefined ? {} : { remote: options.remote }),
|
|
91
|
+
...(options.baseRef === undefined ? {} : { baseRef: options.baseRef })
|
|
92
|
+
});
|
|
93
|
+
if (!target.ok)
|
|
94
|
+
return failure(taskId, target.code, target.message);
|
|
95
|
+
if (!validateRemote(target.value.remote) || !validateBaseRef(target.value.baseRef))
|
|
96
|
+
return failure(taskId, 'DELIVERY_TARGET_INVALID', 'task delivery target is invalid');
|
|
97
|
+
const localHead = gitValue(repoRoot, ['rev-parse', 'HEAD']);
|
|
98
|
+
if (!localHead)
|
|
99
|
+
return failure(taskId, 'DELIVERY_LOCAL_HEAD_UNAVAILABLE', 'Unable to resolve local HEAD');
|
|
100
|
+
const status = git(repoRoot, ['status', '--porcelain=v1']);
|
|
101
|
+
if (status.status !== 0)
|
|
102
|
+
return failure(taskId, 'DELIVERY_GIT_INSPECT_FAILED', status.stderr.trim() || 'Unable to inspect Git state');
|
|
103
|
+
if (status.stdout.trim())
|
|
104
|
+
return failure(taskId, 'DELIVERY_WORKTREE_DIRTY', 'Working tree must be clean before branch delivery');
|
|
105
|
+
const reviewed = frontmatter.last_reviewed_commit ?? '';
|
|
106
|
+
if (reviewed !== localHead)
|
|
107
|
+
return failure(taskId, 'DELIVERY_REVIEW_REQUIRED', 'Local HEAD must equal last_reviewed_commit before delivery');
|
|
108
|
+
const reviewTarget = validateReviewTargetCompatibility(repoRoot, taskDir, target.value, reviewed);
|
|
109
|
+
if (!reviewTarget.ok)
|
|
110
|
+
return failure(taskId, reviewTarget.code, reviewTarget.message, reviewTarget.code.includes('UNAVAILABLE'), reviewTarget.code.includes('UNAVAILABLE') ? 'blocked' : 'failed');
|
|
111
|
+
const ref = `refs/heads/${branch}`;
|
|
112
|
+
const remoteOutput = git(repoRoot, ['ls-remote', '--refs', target.value.remote, ref]);
|
|
113
|
+
if (remoteOutput.status !== 0)
|
|
114
|
+
return failure(taskId, 'DELIVERY_REMOTE_UNAVAILABLE', remoteOutput.stderr.trim() || 'Unable to inspect the delivery remote', true);
|
|
115
|
+
const remoteHead = remoteOutput.stdout.trim().split(/\s+/)[0] || null;
|
|
116
|
+
const classification = classifyDeliveryState(localHead, remoteHead, frontmatter.delivery_remote_head ?? null);
|
|
117
|
+
if (classification.state === 'unknown-drift')
|
|
118
|
+
return failure(taskId, 'DELIVERY_REMOTE_DRIFT', `Remote branch ${branch} has an unexpected head; refusing to overwrite it`);
|
|
119
|
+
if (options.dryRun)
|
|
120
|
+
return { status: 'planned', changed: classification.shouldPush, taskId, remoteHead, localHead, state: classification.state, error: null };
|
|
121
|
+
if (classification.shouldPush) {
|
|
122
|
+
const args = classification.state === 'known-old'
|
|
123
|
+
? ['push', `--force-with-lease=${ref}:${frontmatter.delivery_remote_head}`, target.value.remote, `HEAD:${ref}`]
|
|
124
|
+
: ['push', `--force-with-lease=${ref}:`, target.value.remote, `HEAD:${ref}`];
|
|
125
|
+
const pushed = git(repoRoot, args);
|
|
126
|
+
if (pushed.status !== 0)
|
|
127
|
+
return failure(taskId, 'DELIVERY_PUSH_FAILED', pushed.stderr.trim() || 'Task branch delivery was rejected', true, 'blocked');
|
|
128
|
+
}
|
|
129
|
+
const verified = gitValue(repoRoot, ['ls-remote', '--refs', target.value.remote, ref])?.split(/\s+/)[0] ?? null;
|
|
130
|
+
if (verified !== localHead)
|
|
131
|
+
return failure(taskId, 'DELIVERY_REMOTE_VERIFY_FAILED', `Expected remote head ${localHead}, received ${verified ?? 'unavailable'}`, true, 'blocked');
|
|
132
|
+
const written = writeTask({
|
|
133
|
+
taskRef: taskId,
|
|
134
|
+
expectedState: 'active',
|
|
135
|
+
mutations: [{ kind: 'frontmatter', set: { delivery_remote: target.value.remote, delivery_base_ref: target.value.baseRef, delivery_remote_head: localHead, assigned_to: options.agent } }]
|
|
136
|
+
}, { repoRoot, metadataProvider: captureTaskWriteMetadata });
|
|
137
|
+
if (written.status === 'failed')
|
|
138
|
+
return failure(taskId, 'DELIVERY_TASK_SYNC_FAILED', written.error.message, true, 'blocked');
|
|
139
|
+
return { status: classification.shouldPush ? 'applied' : 'no-op', changed: classification.shouldPush || written.changed, taskId, remoteHead: localHead, localHead, state: classification.state, error: null };
|
|
140
|
+
}
|
|
141
|
+
function deliverTaskBranch(taskRef, options) {
|
|
142
|
+
const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
|
|
143
|
+
if (!resolved.ok)
|
|
144
|
+
return failure(resolved.taskId, resolved.code, resolved.message);
|
|
145
|
+
try {
|
|
146
|
+
return withRepositoryMutationLock(resolved.repoRoot, () => withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-delivery', () => deliverUnlocked(resolved.taskId, resolved.taskDir, resolved.repoRoot, options)));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return failure(resolved.taskId, 'DELIVERY_LOCK_FAILED', error instanceof Error ? error.message : String(error), true, 'blocked');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export { classifyDeliveryState, deliverTaskBranch };
|
|
153
|
+
//# sourceMappingURL=delivery.js.map
|