@fitlab-ai/agent-infra 0.11.8 → 0.11.10
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/bin/internal-cli.js +0 -6
- package/dist/lib/agent-clients/custom-tool-invocations.js +92 -0
- package/dist/lib/agent-clients/next-steps.js +1 -1
- package/dist/lib/agent-clients/reconcile.js +3 -3
- package/dist/lib/agent-clients/schema.js +18 -10
- package/dist/lib/git/workflow.js +1 -1
- package/dist/lib/init.js +2 -2
- package/dist/lib/internal/agent-client.js +3 -3
- package/dist/lib/internal/cli-route-inventory.js +0 -3
- package/dist/lib/internal/sandbox-control.js +30 -5
- package/dist/lib/internal/task-finalization.js +14 -23
- package/dist/lib/internal/task-operation-registry.js +2 -3
- package/dist/lib/internal/task-platform-recovery.js +9 -4
- package/dist/lib/platform/completion-backfill.js +2 -1
- package/dist/lib/platform/context.js +4 -2
- package/dist/lib/platform/github-client.js +20 -17
- package/dist/lib/platform/github-provider.js +42 -22
- package/dist/lib/platform/github-release-notes.js +4 -2
- package/dist/lib/platform/in-label-sync.js +2 -1
- package/dist/lib/platform/issue-comments.js +13 -9
- package/dist/lib/platform/operation-coordinator.js +1 -1
- package/dist/lib/platform/pr-review.js +2 -1
- package/dist/lib/platform/provider-bridge.js +4 -5
- package/dist/lib/platform/provider-contract.d.ts +3 -6
- package/dist/lib/platform/provider-contract.js +3 -15
- package/dist/lib/platform/provider-validation.js +9 -4
- package/dist/lib/platform/pull-requests.js +4 -2
- package/dist/lib/sandbox/control/client.js +54 -6
- package/dist/lib/sandbox/control/executor.js +8 -3
- package/dist/lib/sandbox/recovery.js +1 -22
- package/dist/lib/sandbox/removal.js +0 -1
- package/dist/lib/sandbox/tools.js +2 -0
- package/dist/lib/task/artifact-command.js +11 -1
- package/dist/lib/task/artifact-lifecycle.js +119 -62
- package/dist/lib/task/artifact-selection.js +1 -1
- package/dist/lib/task/capabilities.js +55 -21
- package/dist/lib/task/commands/status.js +0 -27
- package/dist/lib/task/commit-identity.js +22 -7
- package/dist/lib/task/commit-intent.js +67 -26
- package/dist/lib/task/commit-operation.js +19 -8
- package/dist/lib/task/completion-facts.js +32 -10
- package/dist/lib/task/control-authority.js +2 -4
- package/dist/lib/task/current-contract.js +1 -5
- package/dist/lib/task/events.js +8 -274
- package/dist/lib/task/execution-inputs.js +14 -0
- package/dist/lib/task/finalization-envelope.js +4 -0
- package/dist/lib/task/finalization.js +100 -129
- package/dist/lib/task/frontmatter.js +1 -1
- package/dist/lib/task/ledger-intents.js +4 -7
- package/dist/lib/task/orchestration.js +11 -10
- package/dist/lib/task/platform-operation-journal.js +17 -10
- package/dist/lib/task/platform-operation-recovery.js +95 -28
- package/dist/lib/task/review-fingerprint.js +4 -26
- package/dist/lib/task/verification-engine.js +95 -6
- package/dist/lib/task/verification.js +0 -1
- package/dist/lib/task/write.js +0 -11
- package/dist/lib/update.js +2 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/custom-tool-invocations.ts +129 -0
- package/lib/agent-clients/next-steps.ts +3 -3
- package/lib/agent-clients/reconcile.ts +3 -3
- package/lib/agent-clients/schema.ts +18 -10
- package/lib/git/workflow.ts +1 -1
- package/lib/init.ts +2 -2
- package/lib/internal/agent-client.ts +3 -3
- package/lib/internal/cli-route-inventory.ts +0 -2
- package/lib/internal/sandbox-control.ts +39 -6
- package/lib/internal/task-finalization.ts +16 -24
- package/lib/internal/task-operation-registry.ts +2 -3
- package/lib/internal/task-platform-recovery.ts +9 -4
- package/lib/platform/completion-backfill.ts +2 -1
- package/lib/platform/context.ts +8 -4
- package/lib/platform/github-client.ts +24 -20
- package/lib/platform/github-provider.ts +47 -26
- package/lib/platform/github-release-notes.ts +5 -3
- package/lib/platform/in-label-sync.ts +2 -1
- package/lib/platform/issue-comments.ts +14 -9
- package/lib/platform/operation-coordinator.ts +1 -1
- package/lib/platform/pr-review.ts +2 -1
- package/lib/platform/provider-bridge.ts +10 -9
- package/lib/platform/provider-contract.ts +6 -21
- package/lib/platform/provider-loader.ts +7 -6
- package/lib/platform/provider-validation.ts +30 -8
- package/lib/platform/pull-requests.ts +4 -2
- package/lib/platform/repository-metadata.ts +3 -2
- package/lib/platform/security-alerts.ts +1 -1
- package/lib/platform/types.ts +2 -0
- package/lib/sandbox/control/client.ts +57 -6
- package/lib/sandbox/control/executor.ts +8 -3
- package/lib/sandbox/recovery.ts +0 -25
- package/lib/sandbox/removal.ts +2 -10
- package/lib/sandbox/tool-types.ts +1 -0
- package/lib/sandbox/tools.ts +2 -0
- package/lib/task/artifact-command.ts +10 -1
- package/lib/task/artifact-lifecycle.ts +100 -52
- package/lib/task/artifact-selection.ts +1 -1
- package/lib/task/capabilities.ts +47 -24
- package/lib/task/commands/status.ts +0 -31
- package/lib/task/commit-identity.ts +24 -7
- package/lib/task/commit-intent.ts +58 -24
- package/lib/task/commit-operation.ts +17 -8
- package/lib/task/completion-facts.ts +31 -9
- package/lib/task/control-authority.ts +1 -4
- package/lib/task/current-contract.ts +1 -6
- package/lib/task/events.ts +8 -247
- package/lib/task/execution-inputs.ts +25 -0
- package/lib/task/finalization-envelope.ts +21 -0
- package/lib/task/finalization.ts +101 -123
- package/lib/task/frontmatter.ts +1 -1
- package/lib/task/ledger-intents.ts +4 -7
- package/lib/task/orchestration.ts +11 -17
- package/lib/task/platform-operation-journal.ts +18 -11
- package/lib/task/platform-operation-recovery.ts +90 -31
- package/lib/task/review-fingerprint.ts +4 -26
- package/lib/task/verification-engine.ts +103 -9
- package/lib/task/verification.ts +1 -2
- package/lib/task/write.ts +0 -19
- package/lib/update.ts +2 -3
- package/package.json +1 -1
- package/templates/.agents/README.en.md +2 -50
- package/templates/.agents/README.zh-CN.md +2 -50
- package/templates/.agents/rules/commit-and-pr.en.md +5 -5
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +5 -5
- package/templates/.agents/rules/decision-qualification.en.md +1 -1
- package/templates/.agents/rules/decision-qualification.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +1 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +1 -1
- package/templates/.agents/scripts/lib/agent-infra-package.js +0 -7
- package/templates/.agents/skills/code-task/SKILL.en.md +25 -9
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +26 -9
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +5 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +5 -16
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +15 -12
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -10
- 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/review-code/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +15 -6
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +15 -6
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +2 -268
- package/templates/.agents/templates/task.zh-CN.md +0 -12
- package/templates/.github/workflows/pr-label.yml +1 -2
- package/dist/lib/agent-clients/custom-tuis.js +0 -99
- package/dist/lib/internal/task-invalidation.js +0 -63
- package/dist/lib/task/intermediate-cleanup.js +0 -327
- package/dist/lib/task/invalidation-command.js +0 -88
- package/dist/lib/task/invalidation.js +0 -242
- package/lib/agent-clients/custom-tuis.ts +0 -149
- package/lib/internal/task-invalidation.ts +0 -41
- package/lib/task/intermediate-cleanup.ts +0 -393
- package/lib/task/invalidation-command.ts +0 -88
- package/lib/task/invalidation.ts +0 -313
|
@@ -619,9 +619,12 @@ function terminalResult(taskId, receipt, steps, changed, error = null) {
|
|
|
619
619
|
const blocked = [steps.backfill, steps.lifecycle, steps.taskComment, steps.verification, steps.summary].some((step) => step?.status === 'blocked');
|
|
620
620
|
const warnings = openWarnings(receipt);
|
|
621
621
|
const postLifecyclePending = receipt.lifecycle === 'done' && (pending.some((step) => step !== 'lifecycle') || receipt.warningProjection === 'pending');
|
|
622
|
-
const
|
|
622
|
+
const terminalVerificationPending = receipt.lifecycle === 'done' && receipt.verification === 'pending';
|
|
623
|
+
const resultError = error ?? (terminalVerificationPending ? steps.verification?.error : null) ?? null;
|
|
624
|
+
const hardError = error?.code.startsWith('FINALIZATION_') || error?.code === 'TASK_FINALIZATION_RECEIPT_INVALID'
|
|
625
|
+
|| terminalVerificationPending;
|
|
623
626
|
return {
|
|
624
|
-
status: hardError ? (
|
|
627
|
+
status: hardError ? (resultError?.retryable ? 'blocked' : 'failed') : pending.length === 0 ? 'completed' : postLifecyclePending ? 'completed' : blocked ? 'blocked' : 'failed',
|
|
625
628
|
changed,
|
|
626
629
|
taskId,
|
|
627
630
|
backfill: steps.backfill ?? null,
|
|
@@ -632,7 +635,7 @@ function terminalResult(taskId, receipt, steps, changed, error = null) {
|
|
|
632
635
|
completedSteps: completedSteps(receipt),
|
|
633
636
|
pendingSteps: pending,
|
|
634
637
|
result: hardError
|
|
635
|
-
? (
|
|
638
|
+
? (resultError?.retryable ? 'blocked' : 'failed')
|
|
636
639
|
: postLifecyclePending
|
|
637
640
|
? 'completed_with_warnings'
|
|
638
641
|
: pending.length === 0
|
|
@@ -641,7 +644,7 @@ function terminalResult(taskId, receipt, steps, changed, error = null) {
|
|
|
641
644
|
? 'blocked'
|
|
642
645
|
: 'failed',
|
|
643
646
|
warnings,
|
|
644
|
-
error: hardError ?
|
|
647
|
+
error: hardError ? resultError : postLifecyclePending ? null : resultError
|
|
645
648
|
};
|
|
646
649
|
}
|
|
647
650
|
function preparedResult(taskId, receipt, steps, changed) {
|
|
@@ -663,7 +666,6 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
663
666
|
const commentSync = options.commentSync ?? syncPlatformComment;
|
|
664
667
|
const issueSync = options.issueSync ?? syncPlatformIssue;
|
|
665
668
|
const issueInspect = options.issueInspect ?? inspectPlatformIssue;
|
|
666
|
-
const verify = options.verify ?? verifyTaskEvent;
|
|
667
669
|
const consumedCapabilities = new Set();
|
|
668
670
|
let receipt;
|
|
669
671
|
try {
|
|
@@ -676,16 +678,6 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
676
678
|
catch (error) {
|
|
677
679
|
return failed(taskId, errorOf(error, 'TASK_FINALIZATION_RECEIPT_INVALID'));
|
|
678
680
|
}
|
|
679
|
-
if (options.controlBinding && (receipt.controlBinding?.generation !== options.controlBinding.generation
|
|
680
|
-
|| receipt.controlBinding.requestId !== options.controlBinding.requestId)) {
|
|
681
|
-
const state = resolveTaskRef(taskId, { repoRoot });
|
|
682
|
-
if (!(receipt.lifecycle === 'done' && state.ok && state.state === 'completed')) {
|
|
683
|
-
return failed(taskId, {
|
|
684
|
-
code: 'TASK_FINALIZATION_RECOVERY_PROOF_UNAVAILABLE',
|
|
685
|
-
message: 'canonical receipt is not bound to the current sandbox request', retryable: false
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
681
|
const preflightState = resolveTaskRef(taskId, { repoRoot });
|
|
690
682
|
if (options.preflight && preflightState.ok && preflightState.state === 'active') {
|
|
691
683
|
try {
|
|
@@ -708,7 +700,7 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
708
700
|
if (preflightState.ok && preflightState.state === 'active') {
|
|
709
701
|
const recovery = await recoverPlatformOperations(taskId, 'all', { agent: request.agent, cwd: repoRoot });
|
|
710
702
|
if (recovery.status !== 'applied' && recovery.status !== 'no-op') {
|
|
711
|
-
return failed(taskId, recovery.error
|
|
703
|
+
return failed(taskId, recovery.error ? { ...recovery.error, retryable: true } : {
|
|
712
704
|
code: 'PLATFORM_OPERATION_RECOVERY_PENDING',
|
|
713
705
|
message: 'Pending platform operations remain unresolved',
|
|
714
706
|
retryable: true
|
|
@@ -718,12 +710,10 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
718
710
|
const taskFrontmatter = parseTaskFrontmatter(taskContent);
|
|
719
711
|
const issueIdentity = taskIssueIdentity(taskFrontmatter);
|
|
720
712
|
if (issueIdentity) {
|
|
721
|
-
const base = typeof taskFrontmatter.delivery_base_ref === 'string' ? taskFrontmatter.delivery_base_ref.trim() : '';
|
|
722
713
|
let synced;
|
|
723
714
|
try {
|
|
724
715
|
synced = await issueSync(taskId, {
|
|
725
|
-
agent: request.agent, cwd: repoRoot, requirements: true, issueType: true, fields: true,
|
|
726
|
-
...(base ? { inLabels: 'from-diff', base } : {}), dependency: 'required'
|
|
716
|
+
agent: request.agent, cwd: repoRoot, requirements: true, issueType: true, fields: true, dependency: 'required'
|
|
727
717
|
});
|
|
728
718
|
}
|
|
729
719
|
catch (error) {
|
|
@@ -731,8 +721,9 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
731
721
|
return failed(taskId, detail);
|
|
732
722
|
}
|
|
733
723
|
const issueOperations = synced.operations;
|
|
734
|
-
const badOperation = issueOperations?.find((operation) => ['requirements', 'issue-type', 'fields'
|
|
735
|
-
&& operation.status !== 'applied' && operation.status !== 'no-op'
|
|
724
|
+
const badOperation = issueOperations?.find((operation) => ['requirements', 'issue-type', 'fields'].includes(operation.name)
|
|
725
|
+
&& operation.status !== 'applied' && operation.status !== 'no-op'
|
|
726
|
+
&& !(operation.name === 'requirements' && operation.status === 'skipped' && operation.reasonCode === 'NO_REQUIREMENTS_ANCHOR'));
|
|
736
727
|
if ((synced.status !== 'applied' && synced.status !== 'no-op') || synced.error || badOperation) {
|
|
737
728
|
const error = synced.error ?? {
|
|
738
729
|
code: badOperation?.reasonCode || 'FINALIZATION_ISSUE_METADATA_UNCONFIRMED',
|
|
@@ -756,7 +747,7 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
756
747
|
retryable: true
|
|
757
748
|
});
|
|
758
749
|
}
|
|
759
|
-
for (const name of ['requirements', 'issue-type', 'fields'
|
|
750
|
+
for (const name of ['requirements', 'issue-type', 'fields']) {
|
|
760
751
|
const operation = issueOperations?.find((candidate) => candidate.name === name);
|
|
761
752
|
if (!operation)
|
|
762
753
|
return failed(taskId, {
|
|
@@ -779,14 +770,6 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
779
770
|
code: 'FINALIZATION_ISSUE_TYPE_UNCONFIRMED', message: 'Issue Type did not match the verified target', retryable: true
|
|
780
771
|
});
|
|
781
772
|
}
|
|
782
|
-
else if (name === 'labels:in') {
|
|
783
|
-
const expected = Array.isArray(operation.value) ? operation.value : before?.labels;
|
|
784
|
-
if (!expected || expected.filter((label) => label.startsWith('in:')).sort().join('\0')
|
|
785
|
-
!== remote.labels.filter((label) => label.startsWith('in:')).sort().join('\0'))
|
|
786
|
-
return failed(taskId, {
|
|
787
|
-
code: 'FINALIZATION_IN_LABELS_UNCONFIRMED', message: 'Issue in-labels did not match the verified target', retryable: true
|
|
788
|
-
});
|
|
789
|
-
}
|
|
790
773
|
else {
|
|
791
774
|
const expected = operation.value && typeof operation.value === 'object'
|
|
792
775
|
? operation.value
|
|
@@ -907,88 +890,9 @@ async function prepareUnderLock(request, taskId, options) {
|
|
|
907
890
|
metadataProvider: () => ({ timestamp: projection.timestamp, agentInfraVersion: projection.agentInfraVersion })
|
|
908
891
|
})
|
|
909
892
|
: undefined;
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
else {
|
|
915
|
-
try {
|
|
916
|
-
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
917
|
-
const verificationState = resolveTaskRef(taskId, { repoRoot });
|
|
918
|
-
const verificationEvent = verificationState.ok && verificationState.state === 'completed'
|
|
919
|
-
? 'complete-task.completed'
|
|
920
|
-
: 'complete-task.prepared';
|
|
921
|
-
const result = await verify({ taskRef: taskId, event: verificationEvent }, { repoRoot });
|
|
922
|
-
verification = verificationStep(result);
|
|
923
|
-
if (result.status === 'pass') {
|
|
924
|
-
const resolvedTaskWarning = receipt.warnings.some((warning) => warning.step === 'verification' && warning.status === 'open');
|
|
925
|
-
const warnings = applyVerificationWarnings(receipt, result);
|
|
926
|
-
receipt = updateReceipt(repoRoot, receipt, {
|
|
927
|
-
verification: 'done', taskComment: resolvedTaskWarning ? 'pending' : receipt.taskComment,
|
|
928
|
-
warningProjection: warnings.length > 0 ? 'pending' : 'done', warnings, lastError: null
|
|
929
|
-
});
|
|
930
|
-
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
931
|
-
const finalComment = await syncPendingTaskComment({
|
|
932
|
-
repoRoot, taskId, agent: request.agent, receipt, projection: currentProjection(), refreshProjection: currentProjection, commentSync, consumedCapabilities
|
|
933
|
-
});
|
|
934
|
-
receipt = finalComment.receipt;
|
|
935
|
-
if (finalComment.step.status !== 'no-op')
|
|
936
|
-
taskComment = finalComment.step;
|
|
937
|
-
changed = changed || finalComment.changed;
|
|
938
|
-
if (finalComment.error) {
|
|
939
|
-
return terminalResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification }, changed, finalComment.error);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
else {
|
|
943
|
-
const detail = verification.error ?? { code: 'VERIFY_FAILED', message: 'verification failed', retryable: true };
|
|
944
|
-
const warnings = applyVerificationWarnings(receipt, result);
|
|
945
|
-
receipt = updateReceipt(repoRoot, receipt, {
|
|
946
|
-
verification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: detail
|
|
947
|
-
});
|
|
948
|
-
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
949
|
-
const warningComment = await syncPendingTaskComment({
|
|
950
|
-
repoRoot, taskId, agent: request.agent, receipt, projection: currentProjection(), refreshProjection: currentProjection, commentSync, consumedCapabilities
|
|
951
|
-
});
|
|
952
|
-
receipt = warningComment.receipt;
|
|
953
|
-
taskComment = warningComment.step;
|
|
954
|
-
changed = changed || warningComment.changed;
|
|
955
|
-
if (warningComment.error) {
|
|
956
|
-
return terminalResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification }, changed, warningComment.error);
|
|
957
|
-
}
|
|
958
|
-
return terminalResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification }, changed, detail);
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
catch (error) {
|
|
962
|
-
const detail = errorOf(error, 'VERIFY_FAILED', true);
|
|
963
|
-
try {
|
|
964
|
-
const warnings = replaceWarning(receipt, warningFromError('verification', detail), 'open');
|
|
965
|
-
receipt = updateReceipt(repoRoot, receipt, {
|
|
966
|
-
verification: 'pending', taskComment: 'pending', warningProjection: 'pending', warnings, lastError: detail
|
|
967
|
-
});
|
|
968
|
-
receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
|
|
969
|
-
}
|
|
970
|
-
catch (writeError) {
|
|
971
|
-
const persistence = errorOf(writeError, 'FINALIZATION_RECEIPT_WRITE_FAILED', true);
|
|
972
|
-
const hardError = {
|
|
973
|
-
code: 'FINALIZATION_RECEIPT_WRITE_FAILED',
|
|
974
|
-
message: `Unable to persist verification failure (${detail.code}: ${detail.message}): ${persistence.message}`,
|
|
975
|
-
retryable: true
|
|
976
|
-
};
|
|
977
|
-
return terminalResult(taskId, receipt, {
|
|
978
|
-
backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification: { status: 'blocked', changed: false, error: detail }
|
|
979
|
-
}, changed, hardError);
|
|
980
|
-
}
|
|
981
|
-
try {
|
|
982
|
-
const warningComment = await syncPendingTaskComment({ repoRoot, taskId, agent: request.agent, receipt, projection: currentProjection(), refreshProjection: currentProjection, commentSync, consumedCapabilities });
|
|
983
|
-
receipt = warningComment.receipt;
|
|
984
|
-
if (warningComment.step.status !== 'no-op')
|
|
985
|
-
taskComment = warningComment.step;
|
|
986
|
-
changed = changed || warningComment.changed;
|
|
987
|
-
}
|
|
988
|
-
catch { /* preserve the primary error */ }
|
|
989
|
-
return terminalResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification: { status: 'blocked', changed: false, error: detail } }, changed, detail);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
893
|
+
const verification = receipt.verification === 'done'
|
|
894
|
+
? { status: 'no-op', changed: false, error: null }
|
|
895
|
+
: { status: 'skipped', changed: false, error: null };
|
|
992
896
|
let summary = receipt.summary === 'pending'
|
|
993
897
|
? await syncPendingSummary({ repoRoot, taskId, agent: request.agent, receipt, commentSync })
|
|
994
898
|
: { receipt, step: { status: 'no-op', changed: false, error: null }, changed: false, error: null };
|
|
@@ -1039,7 +943,7 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1039
943
|
if (!resolved.ok)
|
|
1040
944
|
return failed(resolved.taskId, { code: resolved.code, message: resolved.message, retryable: false });
|
|
1041
945
|
try {
|
|
1042
|
-
return await withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.commit', () => {
|
|
946
|
+
return await withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.commit', async () => {
|
|
1043
947
|
if (options.controlBinding && options.manifestPath) {
|
|
1044
948
|
try {
|
|
1045
949
|
const manifest = readSandboxControlManifest(options.manifestPath);
|
|
@@ -1065,6 +969,7 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1065
969
|
}
|
|
1066
970
|
}
|
|
1067
971
|
let receipt = readReceipt(repoRoot, resolved.taskId);
|
|
972
|
+
let importedHandoff = false;
|
|
1068
973
|
if (!receipt && options.controlBinding && options.handoffDirectory && request.handoffSha256) {
|
|
1069
974
|
try {
|
|
1070
975
|
const handoff = readTaskFinalizationHandoff(options.handoffDirectory, resolved.taskId, options.controlBinding, request.handoffSha256);
|
|
@@ -1075,6 +980,7 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1075
980
|
throw new Error('TASK_FINALIZATION_RECOVERY_PROOF_UNAVAILABLE');
|
|
1076
981
|
}
|
|
1077
982
|
writeReceipt(repoRoot, receipt);
|
|
983
|
+
importedHandoff = true;
|
|
1078
984
|
try {
|
|
1079
985
|
handoff.cleanup();
|
|
1080
986
|
}
|
|
@@ -1091,32 +997,24 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1091
997
|
return failed(resolved.taskId, {
|
|
1092
998
|
code: 'TASK_FINALIZATION_PREPARATION_REQUIRED', message: 'sandbox preparation receipt is unavailable', retryable: true
|
|
1093
999
|
});
|
|
1094
|
-
if (receipt.lifecycle === 'done' && resolved.state === 'completed') {
|
|
1000
|
+
if (receipt.lifecycle === 'done' && receipt.verification !== 'pending' && resolved.state === 'completed') {
|
|
1095
1001
|
return terminalResult(resolved.taskId, receipt, { lifecycle: { status: 'no-op', changed: false, error: null } }, false);
|
|
1096
1002
|
}
|
|
1097
1003
|
if (options.controlBinding) {
|
|
1098
1004
|
const proof = inspectTaskLifecycleProgress(repoRoot, resolved.taskId, request.agent);
|
|
1099
|
-
|
|
1100
|
-
if (!oldBinding || oldBinding.generation !== options.controlBinding.generation || proof === 'unknown') {
|
|
1005
|
+
if (proof === 'unknown') {
|
|
1101
1006
|
return failed(resolved.taskId, {
|
|
1102
1007
|
code: 'TASK_FINALIZATION_RECOVERY_PROOF_UNAVAILABLE',
|
|
1103
|
-
message: '
|
|
1008
|
+
message: 'task lifecycle progress cannot be verified', retryable: false
|
|
1104
1009
|
});
|
|
1105
1010
|
}
|
|
1106
|
-
if (
|
|
1107
|
-
if (receipt.lifecycle !== 'pending' || !options.handoffDirectory || !request.handoffSha256) {
|
|
1108
|
-
return failed(resolved.taskId, {
|
|
1109
|
-
code: 'TASK_FINALIZATION_RECOVERY_PROOF_UNAVAILABLE',
|
|
1110
|
-
message: 'pending receipt cannot be rebound without a current handoff', retryable: false
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1011
|
+
if (!importedHandoff && options.handoffDirectory && request.handoffSha256) {
|
|
1113
1012
|
try {
|
|
1114
1013
|
const handoff = readTaskFinalizationHandoff(options.handoffDirectory, resolved.taskId, options.controlBinding, request.handoffSha256);
|
|
1115
1014
|
const nextReceipt = validateReceipt(handoff.receipt, resolved.taskId);
|
|
1116
1015
|
if (nextReceipt.receiptId !== receipt.receiptId || nextReceipt.intent !== receipt.intent
|
|
1117
|
-
|| nextReceipt.lifecycle !==
|
|
1016
|
+
|| nextReceipt.lifecycle !== receipt.lifecycle)
|
|
1118
1017
|
throw new Error('handoff is not continuous with canonical receipt');
|
|
1119
|
-
receipt = updateReceipt(repoRoot, receipt, { controlBinding: options.controlBinding });
|
|
1120
1018
|
try {
|
|
1121
1019
|
handoff.cleanup();
|
|
1122
1020
|
}
|
|
@@ -1130,7 +1028,7 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1130
1028
|
}
|
|
1131
1029
|
}
|
|
1132
1030
|
}
|
|
1133
|
-
if (receipt.taskComment === 'pending' || receipt.
|
|
1031
|
+
if (receipt.taskComment === 'pending' || receipt.summary === 'pending' || receipt.warningProjection === 'pending') {
|
|
1134
1032
|
return failed(resolved.taskId, {
|
|
1135
1033
|
code: 'TASK_FINALIZATION_PREPARATION_REQUIRED', message: 'sandbox preparation has pending external steps', retryable: true
|
|
1136
1034
|
}, { completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt), warnings: openWarnings(receipt) });
|
|
@@ -1142,6 +1040,7 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1142
1040
|
message: `cannot verify canonical short-id registry: ${registry.error.code}: ${registry.error.message}`,
|
|
1143
1041
|
retryable: false
|
|
1144
1042
|
});
|
|
1043
|
+
receipt = updateReceipt(repoRoot, receipt, { verification: 'pending' });
|
|
1145
1044
|
const lifecycle = options.lifecycle ?? applyTaskLifecycle;
|
|
1146
1045
|
const result = lifecycle({ taskRef: resolved.taskId, intent: 'complete', agent: request.agent }, { repoRoot, ...(options.metadataProvider ? { metadataProvider: options.metadataProvider } : {}) });
|
|
1147
1046
|
const step = lifecycleStep(result);
|
|
@@ -1149,8 +1048,80 @@ async function commitPreparedTaskFinalization(request, options) {
|
|
|
1149
1048
|
const updated = updateReceipt(repoRoot, receipt, { lifecycle: 'pending', lastError: step.error });
|
|
1150
1049
|
return terminalResult(resolved.taskId, updated, { lifecycle: step }, result.changed, step.error);
|
|
1151
1050
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1051
|
+
let verificationResult;
|
|
1052
|
+
try {
|
|
1053
|
+
verificationResult = await (options.verify ?? verifyTaskEvent)({ taskRef: resolved.taskId, event: 'complete-task.completed' }, { repoRoot });
|
|
1054
|
+
}
|
|
1055
|
+
catch (error) {
|
|
1056
|
+
const detail = errorOf(error, 'VERIFY_FAILED', true);
|
|
1057
|
+
const warnings = replaceWarning(receipt, warningFromError('verification', detail), 'open');
|
|
1058
|
+
let updated;
|
|
1059
|
+
try {
|
|
1060
|
+
updated = updateReceipt(repoRoot, receipt, {
|
|
1061
|
+
lifecycle: 'done', verification: 'pending', taskComment: 'pending', warningProjection: 'pending',
|
|
1062
|
+
warnings, lastError: detail
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
catch (persistCause) {
|
|
1066
|
+
const persistError = errorOf(persistCause, 'FINALIZATION_RECEIPT_WRITE_FAILED', true);
|
|
1067
|
+
persistError.code = 'FINALIZATION_RECEIPT_WRITE_FAILED';
|
|
1068
|
+
persistError.message = `${persistError.message}; verification also failed: ${detail.code}: ${detail.message}`;
|
|
1069
|
+
return failed(resolved.taskId, persistError, {
|
|
1070
|
+
changed: result.changed,
|
|
1071
|
+
lifecycle: step,
|
|
1072
|
+
verification: { status: 'blocked', changed: false, error: persistError },
|
|
1073
|
+
completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt), warnings: openWarnings(receipt)
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
const verification = { status: detail.retryable ? 'blocked' : 'failed', changed: false, error: detail };
|
|
1077
|
+
return terminalResult(resolved.taskId, updated, { lifecycle: step, verification }, result.changed, detail);
|
|
1078
|
+
}
|
|
1079
|
+
const verification = verificationStep(verificationResult);
|
|
1080
|
+
if (verificationResult.status === 'pass') {
|
|
1081
|
+
const resolvedVerificationWarning = receipt.warnings.some((warning) => warning.step === 'verification' && warning.status === 'open');
|
|
1082
|
+
const warnings = applyVerificationWarnings(receipt, verificationResult);
|
|
1083
|
+
const hasOpenWarnings = warnings.some((warning) => warning.status === 'open');
|
|
1084
|
+
let updated;
|
|
1085
|
+
try {
|
|
1086
|
+
updated = updateReceipt(repoRoot, receipt, {
|
|
1087
|
+
lifecycle: 'done', verification: 'done',
|
|
1088
|
+
taskComment: resolvedVerificationWarning ? 'pending' : receipt.taskComment,
|
|
1089
|
+
warningProjection: hasOpenWarnings ? 'pending' : 'done', warnings, lastError: null
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
catch (persistCause) {
|
|
1093
|
+
const persistError = errorOf(persistCause, 'FINALIZATION_RECEIPT_WRITE_FAILED', true);
|
|
1094
|
+
persistError.code = 'FINALIZATION_RECEIPT_WRITE_FAILED';
|
|
1095
|
+
return failed(resolved.taskId, persistError, {
|
|
1096
|
+
changed: result.changed,
|
|
1097
|
+
lifecycle: step,
|
|
1098
|
+
verification,
|
|
1099
|
+
completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt), warnings: openWarnings(receipt)
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
return terminalResult(resolved.taskId, updated, { lifecycle: step, verification }, result.changed);
|
|
1103
|
+
}
|
|
1104
|
+
const detail = verification.error ?? { code: 'VERIFY_FAILED', message: 'verification failed', retryable: true };
|
|
1105
|
+
const warnings = applyVerificationWarnings(receipt, verificationResult);
|
|
1106
|
+
let updated;
|
|
1107
|
+
try {
|
|
1108
|
+
updated = updateReceipt(repoRoot, receipt, {
|
|
1109
|
+
lifecycle: 'done', verification: 'pending', taskComment: 'pending', warningProjection: 'pending',
|
|
1110
|
+
warnings, lastError: detail
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
catch (persistCause) {
|
|
1114
|
+
const persistError = errorOf(persistCause, 'FINALIZATION_RECEIPT_WRITE_FAILED', true);
|
|
1115
|
+
persistError.code = 'FINALIZATION_RECEIPT_WRITE_FAILED';
|
|
1116
|
+
persistError.message = `${persistError.message}; verification also failed: ${detail.code}: ${detail.message}`;
|
|
1117
|
+
return failed(resolved.taskId, persistError, {
|
|
1118
|
+
changed: result.changed,
|
|
1119
|
+
lifecycle: step,
|
|
1120
|
+
verification: { status: 'blocked', changed: false, error: persistError },
|
|
1121
|
+
completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt), warnings: openWarnings(receipt)
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
return terminalResult(resolved.taskId, updated, { lifecycle: step, verification }, result.changed, detail);
|
|
1154
1125
|
});
|
|
1155
1126
|
}
|
|
1156
1127
|
catch (error) {
|
|
@@ -47,7 +47,7 @@ function serializeScalar(value) {
|
|
|
47
47
|
}
|
|
48
48
|
if (value === '')
|
|
49
49
|
return '';
|
|
50
|
-
const serialized = stringify(value).trimEnd();
|
|
50
|
+
const serialized = stringify(value, { lineWidth: 0 }).trimEnd();
|
|
51
51
|
if (serialized.includes('\n') || serialized.includes('\r')) {
|
|
52
52
|
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter values must be scalar');
|
|
53
53
|
}
|
|
@@ -10,6 +10,7 @@ import { parseLegacyReworkIntentDocument, parseReworkIntentDocument, reworkInten
|
|
|
10
10
|
import { extractSection, extractSubSection } from './sections.js';
|
|
11
11
|
import { parseLifecyclePathDecision } from './lifecycle-path.js';
|
|
12
12
|
import { scanVisibleMarkdown } from './markdown.js';
|
|
13
|
+
import { inspectArtifactDirectory } from './artifact-lifecycle.js';
|
|
13
14
|
const PREFIX = { analysis: 'AN', plan: 'PL', code: 'CD' };
|
|
14
15
|
const RESPONSE = new Set(['accepted', 'adjusted', 'refuted', 'cannot-judge']);
|
|
15
16
|
const DISPOSITION = new Set(['confirmed', 'closed', 'open', 'needs-human-decision']);
|
|
@@ -61,9 +62,8 @@ function findingEvidence(reviewContent, evidence) {
|
|
|
61
62
|
return semanticFindingEvidence(reviewContent, heading, next?.start ?? reviewContent.length);
|
|
62
63
|
}
|
|
63
64
|
function taskFactDigest(taskDir, content) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const flow = latest ? parseLifecyclePathDecision(fs.readFileSync(path.join(taskDir, latest.name), 'utf8')) : null;
|
|
65
|
+
const latest = inspectArtifactDirectory(taskDir, 'analysis').latest;
|
|
66
|
+
const flow = latest ? parseLifecyclePathDecision(fs.readFileSync(latest.path, 'utf8'), latest.name) : null;
|
|
67
67
|
return semanticDigest(JSON.stringify({
|
|
68
68
|
taskInput: normalizedTaskFact(extractSection(content, ['任务输入', 'Task Input'])),
|
|
69
69
|
requirements: normalizedTaskFact(extractSection(content, ['需求', 'Requirements'])),
|
|
@@ -220,10 +220,7 @@ function applyLedgerIntent(intent, options = {}) {
|
|
|
220
220
|
}
|
|
221
221
|
const sourceIdentity = parseArtifactName(intent.sourceArtifact);
|
|
222
222
|
const expectedFamily = `review-${finding.stage}`;
|
|
223
|
-
const latestSource =
|
|
224
|
-
.map((name) => parseArtifactName(name))
|
|
225
|
-
.filter((identity) => identity?.family === expectedFamily)
|
|
226
|
-
.sort((left, right) => right.round - left.round || left.name.localeCompare(right.name))[0];
|
|
223
|
+
const latestSource = inspectArtifactDirectory(resolved.taskDir, expectedFamily).latest;
|
|
227
224
|
if (!sourceIdentity || sourceIdentity.family !== expectedFamily || latestSource?.name !== sourceIdentity.name) {
|
|
228
225
|
return failed(intent, 'LEDGER_IDENTITY_CONFLICT', 'rebuild source artifact is not the latest review for the finding stage', resolved.taskId);
|
|
229
226
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
-
import {
|
|
4
|
+
import { inspectArtifactDirectory } from './artifact-lifecycle.js';
|
|
5
5
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
6
6
|
import { validateCurrentTaskContract } from './current-contract.js';
|
|
7
7
|
import { parseReviewSummary } from './review-artifacts.js';
|
|
@@ -20,7 +20,6 @@ import { extractReviewBaseline, extractReviewDiffBase, extractReviewTargetHead,
|
|
|
20
20
|
import { resolveDeliveryTarget, resolveDiffBase, resolveTargetHead } from './delivery-target.js';
|
|
21
21
|
import { buildLifecycleFacts, canStart, recommendNext } from './capabilities.js';
|
|
22
22
|
import { hasOpenLifecycleExecution } from './activity-log.js';
|
|
23
|
-
import { reconcileTaskInvalidation } from './invalidation-command.js';
|
|
24
23
|
import { normalizeAgentToken } from '../agent-clients/tokens.js';
|
|
25
24
|
import { resolveArtifactContext } from './artifact-lifecycle.js';
|
|
26
25
|
function supportsLifecycleDelegation(client) {
|
|
@@ -441,8 +440,11 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
|
|
|
441
440
|
return { status: 'running', changed: true, taskId: resolved.taskId, run, next: null, error: null };
|
|
442
441
|
}
|
|
443
442
|
function validateSavedCurrentDiffBase(repoRoot, metadata, taskDir, reviewedHead) {
|
|
444
|
-
const
|
|
445
|
-
|
|
443
|
+
const reviewInventory = inspectArtifactDirectory(taskDir, 'review-code');
|
|
444
|
+
if (reviewInventory.status !== 'ready' || !reviewInventory.latest) {
|
|
445
|
+
return { code: 'ORCHESTRATION_REVIEW_INVALID', message: 'latest completed review-code artifact is unavailable' };
|
|
446
|
+
}
|
|
447
|
+
const reviewContent = fs.readFileSync(reviewInventory.latest.path, 'utf8');
|
|
446
448
|
const savedTargetHead = extractReviewTargetHead(reviewContent);
|
|
447
449
|
const savedDiffBase = extractReviewDiffBase(reviewContent);
|
|
448
450
|
const savedReviewedHead = extractReviewedHead(reviewContent) || extractReviewBaseline(reviewContent);
|
|
@@ -540,8 +542,11 @@ function routeOrchestration(taskRef, options = {}) {
|
|
|
540
542
|
if (facts.facts.executionBusy && !run?.pendingDelegation) {
|
|
541
543
|
return failed('ORCHESTRATION_EXECUTION_BUSY', 'clean completion requires no open lifecycle execution', resolved.taskId);
|
|
542
544
|
}
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
+
const reviewInventory = inspectArtifactDirectory(resolved.taskDir, 'review-code');
|
|
546
|
+
if (reviewInventory.status !== 'ready' || !reviewInventory.latest) {
|
|
547
|
+
return failed('ORCHESTRATION_REVIEW_INVALID', 'latest completed review-code artifact is unavailable', resolved.taskId);
|
|
548
|
+
}
|
|
549
|
+
const review = parseReviewSummary(fs.readFileSync(reviewInventory.latest.path, 'utf8'));
|
|
545
550
|
if (!review.ok || review.summary.manualValidation === null) {
|
|
546
551
|
return failed('ORCHESTRATION_REVIEW_INVALID', 'latest code review has no numeric manual-validation count', resolved.taskId);
|
|
547
552
|
}
|
|
@@ -678,10 +683,6 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
|
|
|
678
683
|
}
|
|
679
684
|
if (run.stepCount >= run.maxSteps)
|
|
680
685
|
return pauseOrchestration(taskRef, 'ORCHESTRATION_MAX_STEPS', 'maximum orchestration steps reached', true, options);
|
|
681
|
-
const invalidation = reconcileTaskInvalidation(taskRef, { repoRoot: resolved.repoRoot });
|
|
682
|
-
if (invalidation.status === 'failed') {
|
|
683
|
-
return failed('ORCHESTRATION_INVALIDATION_RECONCILE_FAILED', `${invalidation.error?.code ?? 'UNKNOWN'}: ${invalidation.error?.message ?? ''}`, resolved.taskId);
|
|
684
|
-
}
|
|
685
686
|
const routed = routeOrchestration(taskRef, options);
|
|
686
687
|
if (!routed.next)
|
|
687
688
|
return routed;
|
|
@@ -4,7 +4,6 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
4
4
|
import { isResourceIdentity } from '../platform/resource-identity.js';
|
|
5
5
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
6
6
|
const JOURNAL_FILE = '.platform-operations.json';
|
|
7
|
-
const MAX_ATTEMPTS = 3;
|
|
8
7
|
function operationId(input) {
|
|
9
8
|
return createHash('sha256')
|
|
10
9
|
.update(`${input.kind}\0${input.target}\0${input.expectedDigest}`)
|
|
@@ -36,8 +35,7 @@ function parseJournal(file, taskId) {
|
|
|
36
35
|
|| !/^[a-f0-9]{64}$/u.test(item.expectedDigest)
|
|
37
36
|
|| !['deferred', 'required'].includes(item.dependency)
|
|
38
37
|
|| !['queued', 'pending', 'unknown', 'succeeded', 'failed'].includes(item.state)
|
|
39
|
-
|| !Number.isSafeInteger(item.attempts) || item.attempts < 0
|
|
40
|
-
|| item.maxAttempts !== MAX_ATTEMPTS
|
|
38
|
+
|| !Number.isSafeInteger(item.attempts) || item.attempts < 0
|
|
41
39
|
|| !(item.lastCode === null || typeof item.lastCode === 'string')
|
|
42
40
|
|| (item.kind === 'issue-metadata'
|
|
43
41
|
? !item.issueMetadata || typeof item.issueMetadata.requirements !== 'boolean'
|
|
@@ -120,7 +118,13 @@ function recordPlatformOperation(input) {
|
|
|
120
118
|
const { taskId, file } = resolveJournal(input.taskRef, input.cwd);
|
|
121
119
|
const journal = parseJournal(file, taskId);
|
|
122
120
|
const id = operationId(input);
|
|
123
|
-
const
|
|
121
|
+
const targetIndex = journal.operations.findIndex((item) => item.id === id);
|
|
122
|
+
const replacementIndex = input.replaceOperationId
|
|
123
|
+
? journal.operations.findIndex((item) => item.id === input.replaceOperationId)
|
|
124
|
+
: -1;
|
|
125
|
+
const target = targetIndex >= 0 ? journal.operations[targetIndex] : undefined;
|
|
126
|
+
const replacement = replacementIndex >= 0 ? journal.operations[replacementIndex] : undefined;
|
|
127
|
+
const previousAttempts = Math.max(target?.attempts ?? 0, replacement?.attempts ?? 0);
|
|
124
128
|
const next = {
|
|
125
129
|
id,
|
|
126
130
|
kind: input.kind,
|
|
@@ -128,8 +132,7 @@ function recordPlatformOperation(input) {
|
|
|
128
132
|
expectedDigest: input.expectedDigest,
|
|
129
133
|
dependency: input.dependency,
|
|
130
134
|
state: input.state,
|
|
131
|
-
attempts:
|
|
132
|
-
maxAttempts: MAX_ATTEMPTS,
|
|
135
|
+
attempts: previousAttempts + (input.state === 'pending' ? 1 : 0),
|
|
133
136
|
lastCode: input.lastCode ?? null,
|
|
134
137
|
...(input.issueMetadata ? { issueMetadata: input.issueMetadata } : {}),
|
|
135
138
|
...(input.issueCreate ? { issueCreate: input.issueCreate } : {}),
|
|
@@ -138,9 +141,13 @@ function recordPlatformOperation(input) {
|
|
|
138
141
|
...(input.pullRequestReview ? { pullRequestReview: input.pullRequestReview } : {}),
|
|
139
142
|
updatedAt: new Date().toISOString()
|
|
140
143
|
};
|
|
141
|
-
const operations =
|
|
142
|
-
? journal.operations.
|
|
143
|
-
|
|
144
|
+
const operations = replacementIndex >= 0
|
|
145
|
+
? journal.operations.flatMap((item, index) => index === replacementIndex
|
|
146
|
+
? [next]
|
|
147
|
+
: index === targetIndex ? [] : [item])
|
|
148
|
+
: targetIndex >= 0
|
|
149
|
+
? journal.operations.map((item, index) => index === targetIndex ? next : item)
|
|
150
|
+
: [...journal.operations, next];
|
|
144
151
|
writeJournal(file, { version: 1, taskId, operations });
|
|
145
152
|
return next;
|
|
146
153
|
}
|
|
@@ -148,5 +155,5 @@ function readPlatformOperationJournal(taskRef, cwd) {
|
|
|
148
155
|
const { taskId, file } = resolveJournal(taskRef, cwd);
|
|
149
156
|
return parseJournal(file, taskId);
|
|
150
157
|
}
|
|
151
|
-
export { JOURNAL_FILE as PLATFORM_OPERATION_JOURNAL_FILE,
|
|
158
|
+
export { JOURNAL_FILE as PLATFORM_OPERATION_JOURNAL_FILE, operationId, recordPlatformOperation, readPlatformOperationJournal };
|
|
152
159
|
//# sourceMappingURL=platform-operation-journal.js.map
|