@straiffi/archon 1.7.9 → 1.8.0
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/dist/client/assets/{ActivityView-CDLQOXZm.js → ActivityView-EVy76nes.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-DYxLX2HS.js → GitHubActionsDialog-D53aA0Fv.js} +1 -1
- package/dist/client/assets/VerificationDialog-Dm5DcY8F.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-ByNXcCIO.js → architectureDiagram-3BPJPVTR-CmMRkze6.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-ByykLAaG.js → blockDiagram-GPEHLZMM-BgLsRgxM.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CmWA4Pli.js → c4Diagram-AAUBKEIU-C3WJl13c.js} +1 -1
- package/dist/client/assets/channel-xqaERdN6.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CTgbXRh4.js → chunk-2J33WTMH-BfH4_PkQ.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-D3FajVfq.js → chunk-3OPIFGDE-CkVGPLM4.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-CUMg_Vfo.js → chunk-5ZQYHXKU-CDTwT753.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-Oc9MgxZD.js → chunk-727SXJPM-CKEhBrr_.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-5JZboHeP.js → chunk-AQP2D5EJ-D5QPK_k7.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-BpkSMHjB.js → chunk-CSCIHK7Q-BU4Ysr_2.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-BPBMAswO.js → chunk-KSCS5N6A-B9lHLGg1.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-BA2sHmu7.js → chunk-L5ZTLDWV-BrNsmxtD.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-Blc9q-fQ.js → chunk-LZXEDZCA-CVgZc1nv.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-GlVS74JP.js → chunk-ND2GUHAM-DWWdi42a.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-fctBFnAm.js → chunk-NZK2D7GU-46-aRMvO.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-eGs4DDLJ.js → chunk-O5CBEL6O-BW6wHmzD.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-vxa50E7g.js → chunk-WU5MYG2G-Wfk15Qtf.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BdwFrsZE.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DxAuXA1L.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-DXGXNVUp.js → dagre-BM42HDAG-CZ_BDahz.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-BRYr1GvB.js → diagram-2AECGRRQ-CQKXQvjO.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-BcwgMag4.js → diagram-5GNKFQAL-Dgsh82oA.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-Delk7lbr.js → diagram-KO2AKTUF-DUwmm3sV.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BVtc_fjo.js → diagram-LMA3HP47-DLGz0g10.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-weIPvUz5.js → diagram-OG6HWLK6-CjS6v8Zz.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-DKde70dA.js → erDiagram-TEJ5UH35-DHaCFHn9.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-B7Jrk-6c.js → flowDiagram-I6XJVG4X-E4LSVqs6.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-CDzWDgnA.js → ganttDiagram-6RSMTGT7-BWywa_xn.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DYZCryuN.js → gitGraphDiagram-PVQCEYII-BK4kWKuB.js} +1 -1
- package/dist/client/assets/index-CS2arNNP.js +274 -0
- package/dist/client/assets/index-Cb_ZVYaw.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-DmQOgVKK.js → infoDiagram-5YYISTIA-BX7HzDWX.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DCpu-q-Z.js → ishikawaDiagram-YF4QCWOH-CEnWCNes.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-DhBoglhI.js → journeyDiagram-JHISSGLW-MQPDgPxD.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BSjvGFTY.js → kanban-definition-UN3LZRKU-PwVLKAnN.js} +1 -1
- package/dist/client/assets/{line-ClKBZwDr.js → line-BJMnG1sl.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-BRA4mJ40.js → mermaid-parser.core-Bwv8qN83.js} +1 -1
- package/dist/client/assets/{mermaid.core-BZ7kSfEt.js → mermaid.core-DpFOXZmb.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-DoUdLHgj.js → mindmap-definition-RKZ34NQL-Dt-9JT_z.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-NVnzqltb.js → pieDiagram-4H26LBE5-aD3cg6m3.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DOITgkan.js → quadrantDiagram-W4KKPZXB-DUh4hgmW.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-D0VPxrFE.js → requirementDiagram-4Y6WPE33-DOgz-iLT.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Bx0uU7xV.js → sankeyDiagram-5OEKKPKP-BqpDXW6-.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B4lFL6cO.js → sequenceDiagram-3UESZ5HK-BM0Gvqia.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CsLVsMZ4.js → stateDiagram-AJRCARHV-XZMyDtEy.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C0Qe8FiL.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-BkcYpPFI.js → timeline-definition-PNZ67QCA-gqiDwxVu.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-Xc5f2sRQ.js → vennDiagram-CIIHVFJN-MxeqqqyG.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-n3Dpk02Q.js → wardleyDiagram-YWT4CUSO-pMgGO6cB.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BTMzF8zg.js → xychartDiagram-2RQKCTM6-_VK_NZDn.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +467 -11
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +356 -150
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/activeAutomationChild.js +6 -1
- package/dist/server/lib/activeAutomationChild.js.map +1 -1
- package/dist/server/lib/agent.js +5 -4
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/automationCheckGate.js +211 -59
- package/dist/server/lib/automationCheckGate.js.map +1 -1
- package/dist/server/lib/automationProgression.js +78 -10
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/automationReconciliation.js +65 -0
- package/dist/server/lib/automationReconciliation.js.map +1 -1
- package/dist/server/lib/automationResumeDecision.js +82 -20
- package/dist/server/lib/automationResumeDecision.js.map +1 -1
- package/dist/server/lib/automationReviewGate.js +147 -0
- package/dist/server/lib/automationReviewGate.js.map +1 -0
- package/dist/server/lib/bundleActivity.js +20 -0
- package/dist/server/lib/bundleActivity.js.map +1 -1
- package/dist/server/lib/bundleReviewOperations.js +36 -5
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatTicketProposals.js +2 -1
- package/dist/server/lib/chatTicketProposals.js.map +1 -1
- package/dist/server/lib/checkDefinitions.js +11 -0
- package/dist/server/lib/checkDefinitions.js.map +1 -1
- package/dist/server/lib/checkDiagnosticParsers.js +301 -0
- package/dist/server/lib/checkDiagnosticParsers.js.map +1 -0
- package/dist/server/lib/checkDiagnostics.js +142 -0
- package/dist/server/lib/checkDiagnostics.js.map +1 -0
- package/dist/server/lib/checkGateEvaluations.js +92 -4
- package/dist/server/lib/checkGateEvaluations.js.map +1 -1
- package/dist/server/lib/checkRepair.js +1031 -0
- package/dist/server/lib/checkRepair.js.map +1 -0
- package/dist/server/lib/checkRepairLifecycle.js +56 -0
- package/dist/server/lib/checkRepairLifecycle.js.map +1 -0
- package/dist/server/lib/checkRepairReconciliation.js +145 -0
- package/dist/server/lib/checkRepairReconciliation.js.map +1 -0
- package/dist/server/lib/checkRunner.js +142 -25
- package/dist/server/lib/checkRunner.js.map +1 -1
- package/dist/server/lib/checkRuns.js +75 -9
- package/dist/server/lib/checkRuns.js.map +1 -1
- package/dist/server/lib/executionReconciliation.js +21 -11
- package/dist/server/lib/executionReconciliation.js.map +1 -1
- package/dist/server/lib/executionRetryPredicates.js +3 -1
- package/dist/server/lib/executionRetryPredicates.js.map +1 -1
- package/dist/server/lib/executionRunRetention.js +24 -3
- package/dist/server/lib/executionRunRetention.js.map +1 -1
- package/dist/server/lib/executionRuns.js +5 -2
- package/dist/server/lib/executionRuns.js.map +1 -1
- package/dist/server/lib/git.js +5 -1
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/lightweightPrompt.js +2 -1
- package/dist/server/lib/lightweightPrompt.js.map +1 -1
- package/dist/server/lib/planModeQuestions.js +2 -0
- package/dist/server/lib/planModeQuestions.js.map +1 -1
- package/dist/server/lib/planQuestions.js +39 -7
- package/dist/server/lib/planQuestions.js.map +1 -1
- package/dist/server/lib/projectAutoConfig.js +2 -1
- package/dist/server/lib/projectAutoConfig.js.map +1 -1
- package/dist/server/lib/projectMemorySuggestions.js +2 -1
- package/dist/server/lib/projectMemorySuggestions.js.map +1 -1
- package/dist/server/lib/projects.js +57 -9
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/pullRequestContent.js +14 -0
- package/dist/server/lib/pullRequestContent.js.map +1 -1
- package/dist/server/lib/requiredCheckPolicy.js +88 -18
- package/dist/server/lib/requiredCheckPolicy.js.map +1 -1
- package/dist/server/lib/requiredCheckPolicyPrompt.js +46 -0
- package/dist/server/lib/requiredCheckPolicyPrompt.js.map +1 -0
- package/dist/server/lib/run.js +3 -2
- package/dist/server/lib/run.js.map +1 -1
- package/dist/server/lib/specDraft.js +6 -0
- package/dist/server/lib/specDraft.js.map +1 -1
- package/dist/server/lib/specResources.js +42 -0
- package/dist/server/lib/specResources.js.map +1 -0
- package/dist/server/lib/specs.js +9 -5
- package/dist/server/lib/specs.js.map +1 -1
- package/dist/server/lib/terminal.js +5 -7
- package/dist/server/lib/terminal.js.map +1 -1
- package/dist/server/lib/testSessions.js +2 -2
- package/dist/server/lib/testSessions.js.map +1 -1
- package/dist/server/lib/ticketAutomation.js +10 -3
- package/dist/server/lib/ticketAutomation.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +37 -11
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +24 -9
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +18 -0
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/types.js +1 -0
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/lib/workspaceProcessEnvironment.js +21 -0
- package/dist/server/lib/workspaceProcessEnvironment.js.map +1 -0
- package/dist/server/workers/build.js +41 -28
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +4 -3
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +99 -103
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +9 -4
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +5 -6
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +38 -6
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specSession.js +10 -4
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/VerificationDialog-DEKvZG75.js +0 -4
- package/dist/client/assets/channel-BvcRv90i.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-IuovJyxl.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BBJ3avX6.js +0 -1
- package/dist/client/assets/index-BlKOx9Vf.css +0 -2
- package/dist/client/assets/index-CmaBDvIB.js +0 -273
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CvrvaIdF.js +0 -1
package/dist/server/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import { runLightweightPrompt } from './lib/lightweightPrompt.js';
|
|
|
31
31
|
import { advanceBuildChain, startBuildChain, stopBuildChain } from './lib/buildChains.js';
|
|
32
32
|
import { activateQueuedBuildSequenceTicket, compensateBuildSequenceAcceptance, enqueueBundledBuild, getDependencyOrderedBundleTicketIds, getBuildSequenceIdForTicket, hasActiveSequenceForBundle, removeTicketFromBuildSequence, stopBuildSequence, } from './lib/buildSequences.js';
|
|
33
33
|
import { prepareTicketForBuild } from './lib/buildFlow.js';
|
|
34
|
-
import { getBundlePlanMutationBlockerById, shouldBlockPlanForBundleMutationById, } from './lib/bundleActivity.js';
|
|
34
|
+
import { getActiveBundleRepairBlocker, getBundlePlanMutationBlockerById, shouldBlockPlanForBundleMutationById, } from './lib/bundleActivity.js';
|
|
35
35
|
import { getDiscoveredModels, normalizeModelId, normalizeTicketModelId } from './lib/models.js';
|
|
36
36
|
import { upgradeTool, UpgradeInProgressError } from './lib/toolUpgrade.js';
|
|
37
37
|
import { acceptProjectMemorySuggestion, applyProjectMemorySuggestionToDecision, applyProjectMemorySuggestionToConvention, archiveProjectConvention, archiveProjectDecision, createProjectConvention, createProjectDecision, dismissProjectMemorySuggestion, getProjectMemoryById, getProjectMemorySuggestionById, isProjectMemoryEnabled, listProjectConventions, listLatestSuccessfulProjectContextArtifacts, listProjectDecisions, listProjectMemories, listProjectMemorySuggestions, restoreProjectConvention, restoreProjectDecision, serializeProjectMemoryFromConventionValue, serializeProjectMemoryFromDecisionValue, serializeProjectMemoryFromSuggestionValue, supersedeProjectDecision, supersedeProjectDecisionFromSuggestion, updateProjectConvention, updateProjectDecision, validateProjectConventionPayload, validateProjectDecisionPayload, } from './lib/projectMemory.js';
|
|
@@ -47,8 +47,10 @@ import { exportProjectMemoryArchive, importProjectMemoryArchive } from './lib/pr
|
|
|
47
47
|
import { buildReviewFindingsResponse, computeDiffSignature, getLatestReviewRunForContext, listReviewFindings } from './lib/reviewFindings.js';
|
|
48
48
|
import { formatBuildOpenQuestionAnswersPrompt, getLatestBuildOpenQuestionBatchStatus, hasActiveBuildOpenQuestionBatch, listBuildOpenQuestionsForBundle, loadBuildOpenQuestionsByBundleIds, } from './lib/buildOpenQuestions.js';
|
|
49
49
|
import { acceptBuildOpenQuestionResolution } from './lib/buildOpenQuestionOperations.js';
|
|
50
|
-
import {
|
|
50
|
+
import { areBundleTicketsReadyForAutomaticReview } from './lib/bundleAutomationReadiness.js';
|
|
51
|
+
import { abandonAutomationPause, completeAutomationProgression, createAutomationReviewFix, ensureAutomationProgression, finishAutomationReviewFix, getAutomationProgression, recoverLegacyAutomationProgression, recoverStoppedSideEffectProgression, runAutomationProgression, stopAutomationProgression, waitAutomationProgression } from './lib/automationProgression.js';
|
|
51
52
|
import { reconcileAutomationStage } from './lib/automationReconciliation.js';
|
|
53
|
+
import { runAutomationReviewGateOrPause } from './lib/automationReviewGate.js';
|
|
52
54
|
import { pausedRunBelongsToProgression, resolveAutomationResumeDecision } from './lib/automationResumeDecision.js';
|
|
53
55
|
import { getAutomationStageDetails, } from './lib/automationStageDetails.js';
|
|
54
56
|
import { buildAutomationFixInstruction, clearAutomationPause, countBlockingFindings, depthAtLeast, getBundleAutomationState, isAutomationDepth, recordAutomationPause, resolveAutomationConfig, upsertBundleAutomationState, } from './lib/ticketAutomation.js';
|
|
@@ -77,14 +79,17 @@ import { PlanningReferenceError, resolveExternalPlanningDescription } from './li
|
|
|
77
79
|
import { refreshIfNeeded as refreshAssignedIssues, clearCachedAssignedIssues } from './lib/integrations/assignedIssuesCache.js';
|
|
78
80
|
import { buildCommitMessagePrompt, normalizeGeneratedCommitMessage } from './lib/commitMessage.js';
|
|
79
81
|
import { BUNDLE_PULL_REQUEST_SYNC_TTL_MS, getBundlePullRequestRecord, hasOpenBundlePullRequest, serializeBundlePullRequest, shouldSyncBundlePullRequest, syncTrackedBundlePullRequestIfNeeded, upsertBundlePullRequest, upsertBundlePullRequestFromGitHub, } from './lib/bundlePullRequests.js';
|
|
80
|
-
import { countInboundProjectLinks, getEffectiveProject, getProjectCheckDefinitions, getProjectById, getProjectTestCommands, getProjectTicketStats, hasProjectRunIde, listInterruptedProjectDeletions, listProjects, releaseInterruptedProjectDeletionClaims, replaceProjectLinks, serializeProject, updateProjectActiveTarget, validateProjectPayload, } from './lib/projects.js';
|
|
82
|
+
import { countInboundProjectLinks, getEffectiveProject, getProjectCheckDefinitions, getProjectById, getProjectTestCommands, getProjectTicketStats, hasProjectRunIde, listInterruptedProjectDeletions, listProjects, releaseInterruptedProjectDeletionClaims, replaceProjectLinks, serializeProject, updateProjectActiveTarget, validateProjectRequiredCheckPolicyReferences, validateProjectPayload, } from './lib/projects.js';
|
|
81
83
|
import { getActiveRunStatus, getActiveRunStatusForProject, getPreviewStatusForProject, hasRunConfig, isRunning, openIde, openTicketIdeInWorkspace, resolveProjectRunContextKey, runSetupCommandsInWorkspace, runTicketInWorkspace, stopAllTickets, stopTicket } from './lib/run.js';
|
|
82
84
|
import { clearAllTestSessions, createTestSession, deleteTestSession, discoverTestsForSession, doesTestFileExistForSession, getTestSession, isTestSelectionSupported, startTestSessionRun, stopTestSessionRun } from './lib/testSessions.js';
|
|
83
85
|
import { closeCheckRunnerAdmissions, getCheckBatchAttempts, openCheckRunnerAdmissions, rerunCheckBatchAndSchedule, shutdownCheckRunner, startCheckBatch, stopCheckBatch } from './lib/checkRunner.js';
|
|
86
|
+
import { CheckRepairError, getCheckRepairCandidateState, getCheckRepairDetails, getLatestCheckRepairForBatch, retryCheckRepair, startCheckRepair, stopCheckRepair } from './lib/checkRepair.js';
|
|
84
87
|
import { findActiveCheckBatchForTarget, getCheckAttemptDetails, getCheckBatchDetails, hasActiveProjectCheckBatch, isCheckAttemptCurrent, resolveCheckBatchRerunEligibility } from './lib/checkRuns.js';
|
|
88
|
+
import { getCheckAttemptDiagnosticResponse, getCheckBatchDiagnosticResponse } from './lib/checkDiagnostics.js';
|
|
85
89
|
import { getCheckDefinitionFingerprint } from './lib/checkDefinitions.js';
|
|
86
|
-
import { getCheckGateEvaluation } from './lib/checkGateEvaluations.js';
|
|
90
|
+
import { getCheckGateEvaluation, hydrateCheckGatePresentApplicability } from './lib/checkGateEvaluations.js';
|
|
87
91
|
import { captureCheckWorkspaceIdentity } from './lib/checkWorkspaceIdentity.js';
|
|
92
|
+
import { resolveEffectiveRequiredCheckPolicyMembership, resolveRequiredCheckPolicy } from './lib/requiredCheckPolicy.js';
|
|
88
93
|
import { getBundleBuildBlockerResponse, shouldStartBundleBuildNow, transitionTicketState, } from './lib/ticketWorkflowOperations.js';
|
|
89
94
|
import { submitPlanTicketFollowUp, submitTicketFollowUp, } from './lib/ticketFollowUpOperations.js';
|
|
90
95
|
import { closePendingTicketPlanQuestionSet, listPendingTicketPlanQuestionSetMessageIds, resolveTicketPlanQuestionSet, restoreClosedTicketPlanQuestionSets, } from './lib/planQuestionOperations.js';
|
|
@@ -101,9 +106,9 @@ import { HttpError } from './lib/httpError.js';
|
|
|
101
106
|
import { parseIncomingExternalSource } from './lib/externalSource.js';
|
|
102
107
|
import { materializeTicketsWithDependencies } from './lib/ticketBatch.js';
|
|
103
108
|
import { IMPLEMENTATION_READY_DESCRIPTION_SECTION_HEADINGS } from './lib/ticketDescriptionContract.js';
|
|
104
|
-
import { buildSpecImplementationDraft, buildVisualizationAppendix } from './lib/specDraft.js';
|
|
109
|
+
import { buildImplementationResourcesAppendix, buildSpecImplementationDraft, buildVisualizationAppendix } from './lib/specDraft.js';
|
|
105
110
|
import { exportSpecToDocs, checkSpecExportCollision } from './lib/specExport.js';
|
|
106
|
-
import { createTicketDependency, deleteTicketDependenciesForTicket, deleteTicketDependency, getTicketDependency, isTicketRunSetupReady, listTicketDependencies, validateCreateTicketDependency, } from './lib/ticketDependencies.js';
|
|
111
|
+
import { createTicketDependency, deleteTicketDependenciesForTicket, deleteTicketDependency, getTicketDependency, isTicketBuildComplete, isTicketRunSetupReady, listTicketDependencies, validateCreateTicketDependency, } from './lib/ticketDependencies.js';
|
|
107
112
|
import { startBuild } from './workers/build.js';
|
|
108
113
|
import { expandPlanningTicketOutline, generatePlanningTicketOutline, generatePlanText, prepareLinkedPlanningResearch, startPlan, stopAllPlanAgents, } from './workers/plan.js';
|
|
109
114
|
import { EXECUTION_RUN_KINDS, MAX_ARTIFACTS_PER_RUN, validateWorkflowContext } from './lib/types.js';
|
|
@@ -378,11 +383,19 @@ const buildExecutionRunDetailResponse = async (project, run) => {
|
|
|
378
383
|
retry_eligibility: retryEligibility,
|
|
379
384
|
action_kind: null,
|
|
380
385
|
}
|
|
381
|
-
: run.kind === '
|
|
382
|
-
? {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
:
|
|
386
|
+
: run.kind === 'check_repair'
|
|
387
|
+
? {
|
|
388
|
+
kind: 'check_repair',
|
|
389
|
+
available: true,
|
|
390
|
+
check_repair: getCheckRepairDetails(project.id, run.id),
|
|
391
|
+
retry_eligibility: retryEligibility,
|
|
392
|
+
action_kind: null,
|
|
393
|
+
}
|
|
394
|
+
: run.kind === 'github_actions'
|
|
395
|
+
? { ...serializeGitHubActionsExecutionDetail(getGitHubActionsExecutionDetails(project.id, run.id)), retry_eligibility: retryEligibility }
|
|
396
|
+
: ['automation_commit', 'automation_push', 'automation_pull_request'].includes(run.kind)
|
|
397
|
+
? { kind: run.kind, available: true, automation_stage: getAutomationStageDetails(project.id, run.id), retry_eligibility: retryEligibility }
|
|
398
|
+
: { kind: run.kind, available: true, retry_eligibility: retryEligibility };
|
|
386
399
|
const artifacts = loadExecutionArtifactSummariesForRuns(project.id, [run.id], MAX_ARTIFACTS_PER_RUN).get(run.id)
|
|
387
400
|
?? { artifacts: [], artifact_count: 0 };
|
|
388
401
|
return {
|
|
@@ -442,7 +455,14 @@ const getParkTicketError = (ticket) => {
|
|
|
442
455
|
const getBundlePlanBlockerError = () => {
|
|
443
456
|
return 'AI planning is blocked because this bundle worktree is currently being modified.';
|
|
444
457
|
};
|
|
458
|
+
const hasActiveBundleCheckWork = (projectId, bundleId) => Boolean(getActiveBundleRepairBlocker(bundleId)
|
|
459
|
+
|| findActiveCheckBatchForTarget(projectId, 'bundle', bundleId));
|
|
445
460
|
const deleteTicketRecord = async (ticket) => {
|
|
461
|
+
if (ticket.project_id
|
|
462
|
+
&& ticket.worktree_bundle_id
|
|
463
|
+
&& hasActiveBundleCheckWork(ticket.project_id, ticket.worktree_bundle_id)) {
|
|
464
|
+
return { ok: false, status: 409, error: 'Cannot delete a ticket while its bundle has active check work' };
|
|
465
|
+
}
|
|
446
466
|
if (ticket.agent_status === 'running'
|
|
447
467
|
|| (ticket.project_id && hasActiveBuildExecutionRunForTicket(ticket.project_id, ticket.id))) {
|
|
448
468
|
return { ok: false, status: 409, error: 'Cannot delete a ticket while the agent is running' };
|
|
@@ -810,6 +830,9 @@ const cleanupBundleIfEmpty = (bundleId, project) => {
|
|
|
810
830
|
if (isProjectRootBundle(bundle)) {
|
|
811
831
|
return;
|
|
812
832
|
}
|
|
833
|
+
if (hasActiveBundleCheckWork(project.id, bundle.id)) {
|
|
834
|
+
throw new HttpError(409, 'Cannot delete a bundle while check work is active');
|
|
835
|
+
}
|
|
813
836
|
try {
|
|
814
837
|
deleteWorktree(bundle.branch, project);
|
|
815
838
|
}
|
|
@@ -1462,6 +1485,7 @@ const serializeBundleRow = (projectId, bundle, openQuestions = bundle ? loadBuil
|
|
|
1462
1485
|
const hasPreparedWorktree = bundle.kind === 'project_root'
|
|
1463
1486
|
? true
|
|
1464
1487
|
: Boolean(project && resolveExistingWorktreePath(bundle.branch, project));
|
|
1488
|
+
const effectivePolicy = resolveEffectiveRequiredCheckPolicyMembership(project);
|
|
1465
1489
|
return {
|
|
1466
1490
|
...bundle,
|
|
1467
1491
|
has_prepared_worktree: hasPreparedWorktree,
|
|
@@ -1469,6 +1493,13 @@ const serializeBundleRow = (projectId, bundle, openQuestions = bundle ? loadBuil
|
|
|
1469
1493
|
? serializeBundlePullRequest(getBundlePullRequestRecord(bundle.id, projectId))
|
|
1470
1494
|
: null,
|
|
1471
1495
|
automation_config: resolveAutomationConfig(bundle, project),
|
|
1496
|
+
required_check_policy: 'error' in effectivePolicy
|
|
1497
|
+
? undefined
|
|
1498
|
+
: {
|
|
1499
|
+
source: effectivePolicy.source,
|
|
1500
|
+
required_check_definition_ids: effectivePolicy.required_check_definition_ids,
|
|
1501
|
+
pre_review_check_definition_ids: effectivePolicy.pre_review_check_definition_ids,
|
|
1502
|
+
},
|
|
1472
1503
|
open_questions: openQuestions,
|
|
1473
1504
|
build_open_question_batch_status: getLatestBuildOpenQuestionBatchStatus(projectId, bundle.id),
|
|
1474
1505
|
};
|
|
@@ -3034,11 +3065,14 @@ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/create-ti
|
|
|
3034
3065
|
? createAutoBundleForName(bundleName, project.id)
|
|
3035
3066
|
: createAutoPlanningBundle(project.id);
|
|
3036
3067
|
const ticketsForMaterialization = snapshot.tickets.map(ticket => {
|
|
3037
|
-
const
|
|
3068
|
+
const appendices = [
|
|
3069
|
+
buildVisualizationAppendix(ticket.relevant_visualizations ?? [], snapshot),
|
|
3070
|
+
buildImplementationResourcesAppendix(snapshot.resource_urls),
|
|
3071
|
+
].filter(Boolean);
|
|
3038
3072
|
return {
|
|
3039
3073
|
key: ticket.key,
|
|
3040
3074
|
title: ticket.title,
|
|
3041
|
-
description:
|
|
3075
|
+
description: appendices.length > 0 ? `${ticket.description}\n\n${appendices.join('\n\n')}` : ticket.description,
|
|
3042
3076
|
};
|
|
3043
3077
|
});
|
|
3044
3078
|
const { createdTickets, createdDependencies } = materializeTicketsWithDependencies({
|
|
@@ -3704,15 +3738,15 @@ app.delete('/bundles/:id', (req, res) => {
|
|
|
3704
3738
|
if (isProjectRootBundle(bundle)) {
|
|
3705
3739
|
return res.status(409).json({ error: 'Project root cannot be deleted' });
|
|
3706
3740
|
}
|
|
3741
|
+
if (hasActiveBundleCheckWork(result.project.id, bundle.id)) {
|
|
3742
|
+
return res.status(409).json({ error: 'Cannot delete a bundle while check work is active' });
|
|
3743
|
+
}
|
|
3707
3744
|
if (countBundleTickets(bundle.id, result.project.id) > 0) {
|
|
3708
3745
|
return res.status(409).json({ error: 'Cannot delete a bundle that is still used by tickets' });
|
|
3709
3746
|
}
|
|
3710
3747
|
if (result.project.active_target_kind === 'bundle' && result.project.active_target_bundle_id === bundle.id) {
|
|
3711
3748
|
return res.status(409).json({ error: 'Cannot delete the currently selected target bundle' });
|
|
3712
3749
|
}
|
|
3713
|
-
if (findActiveCheckBatchForTarget(result.project.id, 'bundle', bundle.id)) {
|
|
3714
|
-
return res.status(409).json({ error: 'Cannot delete a bundle while checks are running' });
|
|
3715
|
-
}
|
|
3716
3750
|
const affectedChatSessionIds = listChatSessions(result.project.id)
|
|
3717
3751
|
.filter(chatSession => chatSession.target_bundle_id === bundle.id)
|
|
3718
3752
|
.map(chatSession => chatSession.id);
|
|
@@ -3743,6 +3777,9 @@ app.patch('/bundles/:id', (req, res) => {
|
|
|
3743
3777
|
return res.status(404).json({ error: 'Bundle not found' });
|
|
3744
3778
|
}
|
|
3745
3779
|
const hasNameUpdate = hasOwn(req.body, 'name');
|
|
3780
|
+
if (hasOwn(req.body, 'required_check_policy_override')) {
|
|
3781
|
+
return res.status(400).json({ error: 'Bundle required-check policy overrides are no longer supported; configure required checks on the project' });
|
|
3782
|
+
}
|
|
3746
3783
|
if (isProjectRootBundle(bundle)) {
|
|
3747
3784
|
return res.status(409).json({
|
|
3748
3785
|
error: hasNameUpdate
|
|
@@ -3876,7 +3913,7 @@ app.post('/bundles/:id/review', (req, res) => {
|
|
|
3876
3913
|
}
|
|
3877
3914
|
return res.json(reviewResult.details);
|
|
3878
3915
|
});
|
|
3879
|
-
app.post('/bundles/:id/build-open-questions/resolve', (req, res) => {
|
|
3916
|
+
app.post('/bundles/:id/build-open-questions/resolve', async (req, res) => {
|
|
3880
3917
|
const result = getRequiredProject(req);
|
|
3881
3918
|
if ('error' in result) {
|
|
3882
3919
|
return res.status(400).json({ error: result.error });
|
|
@@ -3919,54 +3956,70 @@ app.post('/bundles/:id/build-open-questions/resolve', (req, res) => {
|
|
|
3919
3956
|
}
|
|
3920
3957
|
if (accepted.kind === 'dismissed') {
|
|
3921
3958
|
const automationConfig = resolveAutomationConfig(bundle, result.project);
|
|
3922
|
-
|
|
3923
|
-
? transitionBundleToReview(result.project.id, bundle.id, io, {
|
|
3924
|
-
automatic: true,
|
|
3925
|
-
initiation: {
|
|
3926
|
-
causalParentRunId: accepted.progressionRunId,
|
|
3927
|
-
workflowContext: validateWorkflowContext({ build_open_question_batch_id: accepted.batchId }),
|
|
3928
|
-
},
|
|
3929
|
-
})
|
|
3930
|
-
: null;
|
|
3931
|
-
if (!reviewResult) {
|
|
3959
|
+
if (!depthAtLeast(automationConfig.depth, 'auto_review')) {
|
|
3932
3960
|
completeAutomationProgression({
|
|
3933
3961
|
projectId: result.project.id,
|
|
3934
3962
|
bundleId: bundle.id,
|
|
3935
3963
|
progressionRunId: accepted.progressionRunId,
|
|
3936
3964
|
broadcaster: io,
|
|
3937
3965
|
});
|
|
3966
|
+
for (const ticket of listDetailedBundleTickets(result.project.id, bundle.id)) {
|
|
3967
|
+
io.emit('ticket:updated', ticket);
|
|
3968
|
+
}
|
|
3969
|
+
return res.json(serializeBundleDetails(result.project, bundle));
|
|
3938
3970
|
}
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
});
|
|
3950
|
-
for (const ticket of listDetailedBundleTickets(result.project.id, bundle.id)) {
|
|
3951
|
-
io.emit('ticket:updated', ticket);
|
|
3952
|
-
}
|
|
3953
|
-
return res.json(serializeBundleDetails(result.project, bundle));
|
|
3971
|
+
const ticketsBeforeReview = listDetailedBundleTickets(result.project.id, bundle.id);
|
|
3972
|
+
if (!areBundleTicketsReadyForAutomaticReview(ticketsBeforeReview, bundle.id)) {
|
|
3973
|
+
completeAutomationProgression({
|
|
3974
|
+
projectId: result.project.id,
|
|
3975
|
+
bundleId: bundle.id,
|
|
3976
|
+
progressionRunId: accepted.progressionRunId,
|
|
3977
|
+
broadcaster: io,
|
|
3978
|
+
});
|
|
3979
|
+
for (const ticket of ticketsBeforeReview) {
|
|
3980
|
+
io.emit('ticket:updated', ticket);
|
|
3954
3981
|
}
|
|
3982
|
+
return res.json(serializeBundleDetails(result.project, bundle));
|
|
3983
|
+
}
|
|
3984
|
+
let reviewStartFailureStatus = null;
|
|
3985
|
+
let reviewStartFailureError = null;
|
|
3986
|
+
const reviewStarted = await runAutomationReviewGateOrPause({
|
|
3987
|
+
projectId: result.project.id,
|
|
3988
|
+
bundleId: bundle.id,
|
|
3989
|
+
progressionRunId: accepted.progressionRunId,
|
|
3990
|
+
broadcaster: io,
|
|
3991
|
+
pausedStageRunId: null,
|
|
3992
|
+
initiation: {
|
|
3993
|
+
workflowContext: validateWorkflowContext({ build_open_question_batch_id: accepted.batchId }),
|
|
3994
|
+
},
|
|
3995
|
+
onReviewStartFailure: failure => {
|
|
3996
|
+
reviewStartFailureStatus = failure.status;
|
|
3997
|
+
reviewStartFailureError = failure.error;
|
|
3998
|
+
},
|
|
3999
|
+
});
|
|
4000
|
+
if (reviewStartFailureStatus !== null && reviewStartFailureError !== null) {
|
|
3955
4001
|
waitAutomationProgression({
|
|
3956
4002
|
projectId: result.project.id,
|
|
3957
4003
|
bundleId: bundle.id,
|
|
3958
4004
|
progressionRunId: accepted.progressionRunId,
|
|
3959
4005
|
pauseCode: 'review',
|
|
3960
|
-
pauseReason:
|
|
4006
|
+
pauseReason: reviewStartFailureError,
|
|
3961
4007
|
reasonCode: 'stage_failed',
|
|
3962
4008
|
pausedStageRunId: null,
|
|
3963
4009
|
broadcaster: io,
|
|
3964
4010
|
});
|
|
3965
|
-
return res.status(
|
|
4011
|
+
return res.status(reviewStartFailureStatus).json({ error: reviewStartFailureError });
|
|
4012
|
+
}
|
|
4013
|
+
const updatedTickets = listDetailedBundleTickets(result.project.id, bundle.id);
|
|
4014
|
+
for (const ticket of updatedTickets) {
|
|
4015
|
+
io.emit('ticket:updated', ticket);
|
|
3966
4016
|
}
|
|
4017
|
+
const reviewOwner = reviewStarted
|
|
4018
|
+
? updatedTickets.find(ticket => ticket.state === 'review' && ticket.parked_at === null)
|
|
4019
|
+
: null;
|
|
3967
4020
|
return res.json(serializeBundleDetails(result.project, bundle, {
|
|
3968
|
-
review_owner_ticket_id:
|
|
3969
|
-
target_ticket_id:
|
|
4021
|
+
review_owner_ticket_id: reviewOwner?.id,
|
|
4022
|
+
target_ticket_id: reviewOwner?.id,
|
|
3970
4023
|
}));
|
|
3971
4024
|
}
|
|
3972
4025
|
for (const ticket of listDetailedBundleTickets(result.project.id, bundle.id)) {
|
|
@@ -4073,7 +4126,7 @@ app.post('/bundles/:id/follow-up', (req, res) => {
|
|
|
4073
4126
|
return res.status(response.status).json(response.value);
|
|
4074
4127
|
});
|
|
4075
4128
|
const AUTOMATION_SIDE_EFFECT_KINDS = new Set(['automation_commit', 'automation_push', 'automation_pull_request']);
|
|
4076
|
-
const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix', 'check_batch']);
|
|
4129
|
+
const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix', 'check_repair', 'check_batch']);
|
|
4077
4130
|
app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
4078
4131
|
const result = getRequiredProject(req);
|
|
4079
4132
|
if ('error' in result) {
|
|
@@ -4156,7 +4209,11 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4156
4209
|
});
|
|
4157
4210
|
if (checkpointLineage) {
|
|
4158
4211
|
const owner = getTicket(decision.owner_ticket_id);
|
|
4159
|
-
if (!owner
|
|
4212
|
+
if (!owner
|
|
4213
|
+
|| owner.id !== checkpointLineage.ticket.id
|
|
4214
|
+
|| owner.state !== 'build'
|
|
4215
|
+
|| owner.parked_at !== null
|
|
4216
|
+
|| !isTicketBuildComplete(owner)) {
|
|
4160
4217
|
return res.status(409).json({ error: 'Checkpoint progression owner is no longer the active Build ticket' });
|
|
4161
4218
|
}
|
|
4162
4219
|
let retryOfRunId;
|
|
@@ -4310,25 +4367,14 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4310
4367
|
workflowContext,
|
|
4311
4368
|
broadcaster: io,
|
|
4312
4369
|
});
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4370
|
+
await runAutomationReviewGateOrPause({
|
|
4371
|
+
projectId: owner.project_id,
|
|
4372
|
+
bundleId: owner.worktree_bundle_id,
|
|
4373
|
+
progressionRunId: reviewProgression.runId,
|
|
4374
|
+
broadcaster: io,
|
|
4375
|
+
pausedStageRunId: checkpointLineage.parent.id,
|
|
4376
|
+
initiation: { workflowContext },
|
|
4319
4377
|
});
|
|
4320
|
-
if (!reviewResult.ok) {
|
|
4321
|
-
waitAutomationProgression({
|
|
4322
|
-
projectId: owner.project_id,
|
|
4323
|
-
bundleId: owner.worktree_bundle_id,
|
|
4324
|
-
progressionRunId: reviewProgression.runId,
|
|
4325
|
-
pauseCode: 'review',
|
|
4326
|
-
pauseReason: reviewResult.error,
|
|
4327
|
-
reasonCode: 'stage_failed',
|
|
4328
|
-
pausedStageRunId: checkpointLineage.parent.id,
|
|
4329
|
-
broadcaster: io,
|
|
4330
|
-
});
|
|
4331
|
-
}
|
|
4332
4378
|
}
|
|
4333
4379
|
}
|
|
4334
4380
|
const resumedOwner = getTicket(owner.id);
|
|
@@ -4422,6 +4468,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4422
4468
|
pauseReason: bundleState.automation_paused_reason ?? 'Automation paused',
|
|
4423
4469
|
reasonCode: bundleState.automation_pause_reason_code ?? 'manual_transition',
|
|
4424
4470
|
pausedStageRunId: bundleState.automation_paused_stage_run_id,
|
|
4471
|
+
pausedBoundaryPurpose: bundleState.automation_paused_boundary_purpose,
|
|
4425
4472
|
broadcaster: io,
|
|
4426
4473
|
});
|
|
4427
4474
|
};
|
|
@@ -4459,7 +4506,62 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4459
4506
|
}
|
|
4460
4507
|
return res.json(serializeBundleDetails(result.project, bundle));
|
|
4461
4508
|
}
|
|
4462
|
-
if (
|
|
4509
|
+
if (decision.outcome === 'complete_manual_boundary') {
|
|
4510
|
+
if (!revalidateDecision()) {
|
|
4511
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4512
|
+
}
|
|
4513
|
+
completeAutomationProgression({
|
|
4514
|
+
projectId: result.project.id,
|
|
4515
|
+
bundleId: bundle.id,
|
|
4516
|
+
progressionRunId,
|
|
4517
|
+
domainStatus: 'manual_boundary_reached',
|
|
4518
|
+
broadcaster: io,
|
|
4519
|
+
});
|
|
4520
|
+
return res.json(serializeBundleDetails(result.project, bundle));
|
|
4521
|
+
}
|
|
4522
|
+
if ((decision.outcome === 'start_review' || decision.outcome === 'rerun_review_checks')
|
|
4523
|
+
&& owner.parked_at === null
|
|
4524
|
+
&& isTicketBuildComplete(owner)
|
|
4525
|
+
&& (owner.state === 'build' || (decision.outcome === 'rerun_review_checks' && owner.state === 'review'))) {
|
|
4526
|
+
if (!revalidateDecision()) {
|
|
4527
|
+
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4528
|
+
}
|
|
4529
|
+
const progression = getAutomationProgression(result.project.id, bundle.id);
|
|
4530
|
+
if (!progression || progression.id !== progressionRunId) {
|
|
4531
|
+
return res.status(409).json({ error: 'Automation progression ownership is invalid' });
|
|
4532
|
+
}
|
|
4533
|
+
const workflowContext = validateWorkflowContext(progression.metadata);
|
|
4534
|
+
let reviewStartFailureStatus = null;
|
|
4535
|
+
let reviewStartFailureError = null;
|
|
4536
|
+
try {
|
|
4537
|
+
runAutomationProgression({
|
|
4538
|
+
projectId: result.project.id,
|
|
4539
|
+
bundleId: bundle.id,
|
|
4540
|
+
progressionRunId,
|
|
4541
|
+
broadcaster: io,
|
|
4542
|
+
});
|
|
4543
|
+
await runAutomationReviewGateOrPause({
|
|
4544
|
+
projectId: result.project.id,
|
|
4545
|
+
bundleId: bundle.id,
|
|
4546
|
+
progressionRunId,
|
|
4547
|
+
broadcaster: io,
|
|
4548
|
+
pausedStageRunId: bundleState.automation_paused_stage_run_id,
|
|
4549
|
+
initiation: { workflowContext },
|
|
4550
|
+
onReviewStartFailure: failure => {
|
|
4551
|
+
reviewStartFailureStatus = failure.status;
|
|
4552
|
+
reviewStartFailureError = failure.error;
|
|
4553
|
+
restoreWaitingProgression();
|
|
4554
|
+
},
|
|
4555
|
+
});
|
|
4556
|
+
}
|
|
4557
|
+
catch (error) {
|
|
4558
|
+
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4559
|
+
}
|
|
4560
|
+
if (reviewStartFailureStatus !== null && reviewStartFailureError !== null) {
|
|
4561
|
+
return res.status(reviewStartFailureStatus).json({ error: reviewStartFailureError });
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4564
|
+
else if (owner.state === 'review' && owner.agent_status !== 'running') {
|
|
4463
4565
|
const iteration = bundleState.review_iteration_count ?? 0;
|
|
4464
4566
|
if (decision.outcome === 'start_review_fix') {
|
|
4465
4567
|
let reviewFixRunId = null;
|
|
@@ -4569,7 +4671,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4569
4671
|
broadcaster: io,
|
|
4570
4672
|
});
|
|
4571
4673
|
const checkGateResume = decision.outcome === 'rerun_required_checks'
|
|
4572
|
-
? resolveAutomationCheckGateResume(result.project.id, progressionRunId)
|
|
4674
|
+
? resolveAutomationCheckGateResume(result.project.id, progressionRunId, owner.bundle?.kind === 'project_root' ? project.repo_path : resolveWorktreePath(bundle.branch, project))
|
|
4573
4675
|
: undefined;
|
|
4574
4676
|
await runAutomationCommitChain(owner, project, owner.bundle ?? null, automationConfig, io, progressionRunId, checkGateResume);
|
|
4575
4677
|
}
|
|
@@ -4594,19 +4696,6 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
|
|
|
4594
4696
|
return res.status(409).json({ error: 'The selected Resume outcome no longer matches the bundle state' });
|
|
4595
4697
|
}
|
|
4596
4698
|
}
|
|
4597
|
-
else if (owner.state === 'build' && owner.agent_status === 'done' && decision.outcome === 'start_review') {
|
|
4598
|
-
if (!revalidateDecision()) {
|
|
4599
|
-
return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
|
|
4600
|
-
}
|
|
4601
|
-
const reviewResult = transitionBundleToReview(result.project.id, bundle.id, io, {
|
|
4602
|
-
automatic: true,
|
|
4603
|
-
initiation: { causalParentRunId: progressionRunId },
|
|
4604
|
-
accept: acceptResumedReview,
|
|
4605
|
-
});
|
|
4606
|
-
if (!reviewResult.ok) {
|
|
4607
|
-
return res.status(reviewResult.status).json({ error: reviewResult.error });
|
|
4608
|
-
}
|
|
4609
|
-
}
|
|
4610
4699
|
else {
|
|
4611
4700
|
return res.status(409).json({ error: 'Ticket is not in a resumable state' });
|
|
4612
4701
|
}
|
|
@@ -4637,72 +4726,31 @@ app.post('/bundles/:id/dismiss-automation-pause', async (req, res) => {
|
|
|
4637
4726
|
&& listBuildOpenQuestionsForBundle(result.project.id, bundle.id).length > 0) {
|
|
4638
4727
|
return res.status(409).json({ error: 'Resolve or dismiss all Build open questions before dismissing this pause' });
|
|
4639
4728
|
}
|
|
4640
|
-
|
|
4641
|
-
|
|
4729
|
+
const progressionRunId = bundleState.automation_progression_run_id;
|
|
4730
|
+
const checkpointLineage = progressionRunId
|
|
4731
|
+
? resolveBuildTicketCommitCheckpointLineage({
|
|
4732
|
+
projectId: result.project.id,
|
|
4733
|
+
bundleId: bundle.id,
|
|
4734
|
+
progressionRunId,
|
|
4735
|
+
})
|
|
4736
|
+
: null;
|
|
4737
|
+
if (progressionRunId) {
|
|
4642
4738
|
try {
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
: recoverLegacyAutomationProgression({
|
|
4650
|
-
projectId: result.project.id,
|
|
4651
|
-
bundleId: bundle.id,
|
|
4652
|
-
broadcaster: io,
|
|
4653
|
-
})).runId;
|
|
4654
|
-
}
|
|
4655
|
-
catch (error) {
|
|
4656
|
-
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4657
|
-
}
|
|
4658
|
-
}
|
|
4659
|
-
try {
|
|
4660
|
-
if (getAutomationProgression(result.project.id, bundle.id)?.id !== progressionRunId) {
|
|
4661
|
-
return res.status(409).json({ error: 'Automation progression ownership is invalid' });
|
|
4662
|
-
}
|
|
4663
|
-
}
|
|
4664
|
-
catch (error) {
|
|
4665
|
-
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4666
|
-
}
|
|
4667
|
-
const checkpointLineage = resolveBuildTicketCommitCheckpointLineage({
|
|
4668
|
-
projectId: result.project.id,
|
|
4669
|
-
bundleId: bundle.id,
|
|
4670
|
-
progressionRunId,
|
|
4671
|
-
});
|
|
4672
|
-
if (bundleState.automation_paused_stage_run_id) {
|
|
4673
|
-
const stage = getExecutionRun(result.project.id, bundleState.automation_paused_stage_run_id);
|
|
4674
|
-
if (!stage
|
|
4675
|
-
|| (!AUTOMATION_SIDE_EFFECT_KINDS.has(stage.kind) && !AUTOMATION_WORKER_PAUSE_KINDS.has(stage.kind))
|
|
4676
|
-
|| !pausedRunBelongsToProgression(result.project.id, bundle.id, progressionRunId, stage.id)) {
|
|
4677
|
-
return res.status(409).json({ error: 'The paused automation stage does not belong to the active progression' });
|
|
4739
|
+
await stopAutomationProgression({
|
|
4740
|
+
projectId: result.project.id,
|
|
4741
|
+
bundleId: bundle.id,
|
|
4742
|
+
broadcaster: io,
|
|
4743
|
+
stopLocalWorker: worker => (worker.kind === 'review' ? stopReviewAgent(worker.ticket_id) : stopBuildAgent(worker.ticket_id)),
|
|
4744
|
+
});
|
|
4678
4745
|
}
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
try {
|
|
4682
|
-
reconciled = await reconcileAutomationStage({
|
|
4683
|
-
projectId: result.project.id,
|
|
4684
|
-
bundleId: bundle.id,
|
|
4685
|
-
progressionRunId,
|
|
4686
|
-
stageRunId: stage.id,
|
|
4687
|
-
});
|
|
4688
|
-
}
|
|
4689
|
-
catch (error) {
|
|
4690
|
-
return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
|
|
4691
|
-
}
|
|
4692
|
-
if (reconciled.domainStatus === 'ambiguous') {
|
|
4693
|
-
return res.status(409).json({ error: 'The paused automation side effect is ambiguous and cannot be dismissed safely.' });
|
|
4694
|
-
}
|
|
4695
|
-
if (!(reconciled.status === 'completed' && reconciled.domainStatus === 'reconciled_completed')
|
|
4696
|
-
&& !(reconciled.status === 'interrupted' && reconciled.domainStatus === 'reconciled_absent')) {
|
|
4697
|
-
return res.status(409).json({ error: 'The paused automation side effect has no safely dismissible outcome.' });
|
|
4698
|
-
}
|
|
4746
|
+
catch {
|
|
4747
|
+
// Explicit abandonment also repairs a stale progression pointer.
|
|
4699
4748
|
}
|
|
4700
4749
|
}
|
|
4701
|
-
|
|
4750
|
+
abandonAutomationPause({
|
|
4702
4751
|
projectId: result.project.id,
|
|
4703
4752
|
bundleId: bundle.id,
|
|
4704
4753
|
broadcaster: io,
|
|
4705
|
-
stopLocalWorker: worker => (worker.kind === 'review' ? stopReviewAgent(worker.ticket_id) : stopBuildAgent(worker.ticket_id)),
|
|
4706
4754
|
});
|
|
4707
4755
|
if (checkpointLineage) {
|
|
4708
4756
|
const stoppedSequence = stopBuildSequence(checkpointLineage.ticket.id);
|
|
@@ -5792,7 +5840,7 @@ app.post('/projects', (req, res) => {
|
|
|
5792
5840
|
return res.status(400).json({ error: validation.error });
|
|
5793
5841
|
}
|
|
5794
5842
|
const projectCount = Number(db.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count ?? 0);
|
|
5795
|
-
const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
|
|
5843
|
+
const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
|
|
5796
5844
|
if (!repo_path) {
|
|
5797
5845
|
return res.status(400).json({ error: 'repo_path must be a non-empty string' });
|
|
5798
5846
|
}
|
|
@@ -5814,6 +5862,7 @@ app.post('/projects', (req, res) => {
|
|
|
5814
5862
|
run_services,
|
|
5815
5863
|
check_definitions,
|
|
5816
5864
|
required_check_definition_ids,
|
|
5865
|
+
pre_review_check_definition_ids,
|
|
5817
5866
|
test_commands,
|
|
5818
5867
|
run_ide,
|
|
5819
5868
|
preview_service_name,
|
|
@@ -5835,8 +5884,8 @@ app.post('/projects', (req, res) => {
|
|
|
5835
5884
|
automation_review_severity,
|
|
5836
5885
|
automation_review_max_iterations
|
|
5837
5886
|
)
|
|
5838
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5839
|
-
`).run(id, name, normalizedRepoPath, run_setup, run_services, check_definitions, required_check_definition_ids ?? '[]', test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, commit_message_rules ?? null, commit_after_each_ticket ?? 0, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, scan_include_globs_json ?? null, scan_exclude_globs_json ?? null, worktree_sync ?? null, spec_aware_code_review_enabled ?? 0, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_pause_on_open_questions ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
|
|
5887
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5888
|
+
`).run(id, name, normalizedRepoPath, run_setup, run_services, check_definitions, required_check_definition_ids ?? '[]', pre_review_check_definition_ids ?? '[]', test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, commit_message_rules ?? null, commit_after_each_ticket ?? 0, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, scan_include_globs_json ?? null, scan_exclude_globs_json ?? null, worktree_sync ?? null, spec_aware_code_review_enabled ?? 0, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_pause_on_open_questions ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
|
|
5840
5889
|
replaceProjectLinks(id, linked_project_ids ?? []);
|
|
5841
5890
|
ensureProjectRootBundle(id);
|
|
5842
5891
|
if (projectCount === 0) {
|
|
@@ -7002,8 +7051,8 @@ app.patch('/projects/:id', (req, res) => {
|
|
|
7002
7051
|
});
|
|
7003
7052
|
}
|
|
7004
7053
|
}
|
|
7005
|
-
const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
|
|
7006
|
-
db.prepare(`
|
|
7054
|
+
const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
|
|
7055
|
+
const updateProject = db.prepare(`
|
|
7007
7056
|
UPDATE projects SET
|
|
7008
7057
|
name = ?,
|
|
7009
7058
|
repo_path = ?,
|
|
@@ -7011,6 +7060,7 @@ app.patch('/projects/:id', (req, res) => {
|
|
|
7011
7060
|
run_services = ?,
|
|
7012
7061
|
check_definitions = ?,
|
|
7013
7062
|
required_check_definition_ids = ?,
|
|
7063
|
+
pre_review_check_definition_ids = ?,
|
|
7014
7064
|
test_commands = ?,
|
|
7015
7065
|
run_ide = ?,
|
|
7016
7066
|
preview_service_name = ?,
|
|
@@ -7033,9 +7083,32 @@ app.patch('/projects/:id', (req, res) => {
|
|
|
7033
7083
|
automation_review_max_iterations = ?,
|
|
7034
7084
|
updated_at = CURRENT_TIMESTAMP
|
|
7035
7085
|
WHERE id = ?
|
|
7036
|
-
`)
|
|
7037
|
-
|
|
7038
|
-
|
|
7086
|
+
`);
|
|
7087
|
+
const nextCheckDefinitions = hasOwn(validation.values, 'check_definitions') ? check_definitions ?? null : project.check_definitions;
|
|
7088
|
+
const nextRequiredCheckDefinitionIds = hasOwn(validation.values, 'required_check_definition_ids')
|
|
7089
|
+
? required_check_definition_ids ?? '[]'
|
|
7090
|
+
: project.required_check_definition_ids;
|
|
7091
|
+
const nextPreReviewCheckDefinitionIds = hasOwn(validation.values, 'pre_review_check_definition_ids')
|
|
7092
|
+
? pre_review_check_definition_ids ?? '[]'
|
|
7093
|
+
: project.pre_review_check_definition_ids;
|
|
7094
|
+
const updateResult = db.transaction(() => {
|
|
7095
|
+
const policyReferences = validateProjectRequiredCheckPolicyReferences({
|
|
7096
|
+
projectId: project.id,
|
|
7097
|
+
checkDefinitionsJson: nextCheckDefinitions,
|
|
7098
|
+
requiredCheckDefinitionIdsJson: nextRequiredCheckDefinitionIds,
|
|
7099
|
+
preReviewCheckDefinitionIdsJson: nextPreReviewCheckDefinitionIds,
|
|
7100
|
+
});
|
|
7101
|
+
if ('error' in policyReferences) {
|
|
7102
|
+
return policyReferences;
|
|
7103
|
+
}
|
|
7104
|
+
updateProject.run(name ?? project.name, repo_path ?? project.repo_path, hasOwn(validation.values, 'run_setup') ? run_setup : project.run_setup, hasOwn(validation.values, 'run_services') ? run_services : project.run_services, nextCheckDefinitions, nextRequiredCheckDefinitionIds, nextPreReviewCheckDefinitionIds, hasOwn(validation.values, 'test_commands') ? test_commands : project.test_commands, hasOwn(validation.values, 'run_ide') ? run_ide : project.run_ide, hasOwn(validation.values, 'preview_service_name') ? preview_service_name : project.preview_service_name, hasOwn(validation.values, 'preview_path') ? preview_path : project.preview_path, hasOwn(validation.values, 'preview_capability_mode') ? preview_capability_mode : project.preview_capability_mode, hasOwn(validation.values, 'helper_model') ? helper_model : project.helper_model, hasOwn(validation.values, 'helper_variant') ? helper_variant : project.helper_variant, hasOwn(validation.values, 'commit_message_rules') ? commit_message_rules : project.commit_message_rules, hasOwn(validation.values, 'commit_after_each_ticket') ? commit_after_each_ticket : project.commit_after_each_ticket, hasOwn(validation.values, 'auto_park_stale_tickets') ? auto_park_stale_tickets : project.auto_park_stale_tickets, hasOwn(validation.values, 'memory_enabled') ? memory_enabled : project.memory_enabled, hasOwn(validation.values, 'scan_include_globs_json') ? scan_include_globs_json : project.scan_include_globs_json, hasOwn(validation.values, 'scan_exclude_globs_json') ? scan_exclude_globs_json : project.scan_exclude_globs_json, hasOwn(validation.values, 'worktree_sync') ? worktree_sync : project.worktree_sync, hasOwn(validation.values, 'spec_aware_code_review_enabled') ? spec_aware_code_review_enabled : project.spec_aware_code_review_enabled, hasOwn(validation.values, 'automation_depth') ? automation_depth : project.automation_depth, hasOwn(validation.values, 'automation_review_fix_enabled') ? automation_review_fix_enabled : project.automation_review_fix_enabled, hasOwn(validation.values, 'automation_pause_on_open_questions') ? automation_pause_on_open_questions : project.automation_pause_on_open_questions, hasOwn(validation.values, 'automation_review_severity') ? automation_review_severity : project.automation_review_severity, hasOwn(validation.values, 'automation_review_max_iterations') ? automation_review_max_iterations : project.automation_review_max_iterations, req.params.id);
|
|
7105
|
+
if (hasOwn(validation.values, 'linked_project_ids')) {
|
|
7106
|
+
replaceProjectLinks(project.id, linked_project_ids ?? []);
|
|
7107
|
+
}
|
|
7108
|
+
return { ok: true };
|
|
7109
|
+
})();
|
|
7110
|
+
if ('error' in updateResult) {
|
|
7111
|
+
return res.status(400).json({ error: updateResult.error });
|
|
7039
7112
|
}
|
|
7040
7113
|
const updated = db.prepare('SELECT * FROM projects WHERE id = ?').get(req.params.id);
|
|
7041
7114
|
res.json(serializeProject(updated ?? null));
|
|
@@ -7095,6 +7168,12 @@ const completeClaimedProjectDeletion = async (projectId, claimId) => {
|
|
|
7095
7168
|
WHERE evaluation_id IN (SELECT id FROM check_gate_evaluations WHERE project_id = ?)
|
|
7096
7169
|
`).run(projectId);
|
|
7097
7170
|
db.prepare('DELETE FROM check_gate_evaluations WHERE project_id = ?').run(projectId);
|
|
7171
|
+
if (db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'check_repair_details'").get()) {
|
|
7172
|
+
db.prepare(`
|
|
7173
|
+
DELETE FROM check_repair_details
|
|
7174
|
+
WHERE execution_run_id IN (SELECT id FROM execution_runs WHERE project_id = ?)
|
|
7175
|
+
`).run(projectId);
|
|
7176
|
+
}
|
|
7098
7177
|
db.prepare(`
|
|
7099
7178
|
DELETE FROM check_attempt_details
|
|
7100
7179
|
WHERE execution_run_id IN (SELECT id FROM execution_runs WHERE project_id = ?)
|
|
@@ -8039,6 +8118,98 @@ app.post('/projects/:id/check-batches', async (req, res) => {
|
|
|
8039
8118
|
return res.status(409).json({ error: getErrorMessage(error) });
|
|
8040
8119
|
}
|
|
8041
8120
|
});
|
|
8121
|
+
app.post('/projects/:id/check-repairs', async (req, res) => {
|
|
8122
|
+
const project = getProjectById(req.params.id);
|
|
8123
|
+
if (!project) {
|
|
8124
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8125
|
+
}
|
|
8126
|
+
const body = req.body && typeof req.body === 'object' && !Array.isArray(req.body)
|
|
8127
|
+
? req.body
|
|
8128
|
+
: null;
|
|
8129
|
+
if (!body || Object.keys(body).some(key => !['diagnostic_ids', 'raw_output_attempt_run_ids', 'ticket_id'].includes(key))) {
|
|
8130
|
+
return res.status(400).json({ error: 'Only diagnostic_ids, raw_output_attempt_run_ids, and optional ticket_id are accepted' });
|
|
8131
|
+
}
|
|
8132
|
+
const diagnosticIds = body.diagnostic_ids === undefined
|
|
8133
|
+
? []
|
|
8134
|
+
: Array.isArray(body.diagnostic_ids)
|
|
8135
|
+
&& body.diagnostic_ids.length <= 32
|
|
8136
|
+
&& body.diagnostic_ids.every(id => typeof id === 'string' && id.trim().length > 0 && id.trim().length <= 100)
|
|
8137
|
+
? body.diagnostic_ids.map(id => id.trim())
|
|
8138
|
+
: null;
|
|
8139
|
+
const rawOutputAttemptRunIds = body.raw_output_attempt_run_ids === undefined
|
|
8140
|
+
? []
|
|
8141
|
+
: Array.isArray(body.raw_output_attempt_run_ids)
|
|
8142
|
+
&& body.raw_output_attempt_run_ids.length <= 8
|
|
8143
|
+
&& body.raw_output_attempt_run_ids.every(id => typeof id === 'string' && id.trim().length > 0 && id.trim().length <= 100)
|
|
8144
|
+
? body.raw_output_attempt_run_ids.map(id => id.trim())
|
|
8145
|
+
: null;
|
|
8146
|
+
if (!diagnosticIds
|
|
8147
|
+
|| diagnosticIds.length !== new Set(diagnosticIds).size
|
|
8148
|
+
|| !rawOutputAttemptRunIds
|
|
8149
|
+
|| rawOutputAttemptRunIds.length !== new Set(rawOutputAttemptRunIds).size
|
|
8150
|
+
|| diagnosticIds.length + rawOutputAttemptRunIds.length === 0) {
|
|
8151
|
+
return res.status(400).json({ error: 'At least one unique diagnostic_ids or raw_output_attempt_run_ids evidence reference is required' });
|
|
8152
|
+
}
|
|
8153
|
+
if (body.ticket_id !== undefined && (typeof body.ticket_id !== 'string'
|
|
8154
|
+
|| body.ticket_id.trim().length === 0
|
|
8155
|
+
|| body.ticket_id.trim().length > 100)) {
|
|
8156
|
+
return res.status(400).json({ error: 'ticket_id must be a non-empty opaque ticket ID' });
|
|
8157
|
+
}
|
|
8158
|
+
try {
|
|
8159
|
+
return res.status(202).json(await startCheckRepair({
|
|
8160
|
+
projectId: project.id,
|
|
8161
|
+
diagnosticIds,
|
|
8162
|
+
rawOutputAttemptRunIds,
|
|
8163
|
+
ticketId: typeof body.ticket_id === 'string' ? body.ticket_id.trim() : null,
|
|
8164
|
+
io,
|
|
8165
|
+
}));
|
|
8166
|
+
}
|
|
8167
|
+
catch (error) {
|
|
8168
|
+
if (error instanceof CheckRepairError) {
|
|
8169
|
+
return res.status(error.status).json({ error: error.message });
|
|
8170
|
+
}
|
|
8171
|
+
return res.status(409).json({ error: getErrorMessage(error) });
|
|
8172
|
+
}
|
|
8173
|
+
});
|
|
8174
|
+
app.get('/projects/:id/check-repairs/:repairRunId', (req, res) => {
|
|
8175
|
+
const project = getProjectById(req.params.id);
|
|
8176
|
+
if (!project) {
|
|
8177
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8178
|
+
}
|
|
8179
|
+
const repair = getCheckRepairDetails(project.id, req.params.repairRunId);
|
|
8180
|
+
return repair ? res.json(repair) : res.status(404).json({ error: 'Check repair not found' });
|
|
8181
|
+
});
|
|
8182
|
+
app.post('/projects/:id/check-repairs/:repairRunId/stop', async (req, res) => {
|
|
8183
|
+
if (!getProjectById(req.params.id)) {
|
|
8184
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8185
|
+
}
|
|
8186
|
+
try {
|
|
8187
|
+
return res.json(await stopCheckRepair(req.params.id, req.params.repairRunId, io));
|
|
8188
|
+
}
|
|
8189
|
+
catch (error) {
|
|
8190
|
+
if (error instanceof CheckRepairError) {
|
|
8191
|
+
return res.status(error.status).json({ error: error.message });
|
|
8192
|
+
}
|
|
8193
|
+
return res.status(409).json({ error: getErrorMessage(error) });
|
|
8194
|
+
}
|
|
8195
|
+
});
|
|
8196
|
+
app.post('/projects/:id/check-repairs/:repairRunId/retry', async (req, res) => {
|
|
8197
|
+
if (!getProjectById(req.params.id)) {
|
|
8198
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8199
|
+
}
|
|
8200
|
+
if (req.body && typeof req.body === 'object' && Object.keys(req.body).length > 0) {
|
|
8201
|
+
return res.status(400).json({ error: 'Check repair retries do not accept client-supplied repair context' });
|
|
8202
|
+
}
|
|
8203
|
+
try {
|
|
8204
|
+
return res.status(202).json(await retryCheckRepair(req.params.id, req.params.repairRunId, io));
|
|
8205
|
+
}
|
|
8206
|
+
catch (error) {
|
|
8207
|
+
if (error instanceof CheckRepairError) {
|
|
8208
|
+
return res.status(error.status).json({ error: error.message });
|
|
8209
|
+
}
|
|
8210
|
+
return res.status(409).json({ error: getErrorMessage(error) });
|
|
8211
|
+
}
|
|
8212
|
+
});
|
|
8042
8213
|
const parseCheckDefinitionIds = (value) => {
|
|
8043
8214
|
if (!Array.isArray(value) || value.length === 0 || value.some(id => typeof id !== 'string' || id.trim() === '')) {
|
|
8044
8215
|
return null;
|
|
@@ -8138,12 +8309,47 @@ app.get('/projects/:id/check-batches/:batchRunId', async (req, res) => {
|
|
|
8138
8309
|
attempts: await hydrateCheckAttemptCurrency(project, batch, getCheckBatchAttempts(req.params.id, req.params.batchRunId)),
|
|
8139
8310
|
});
|
|
8140
8311
|
});
|
|
8141
|
-
app.get('/projects/:id/check-
|
|
8312
|
+
app.get('/projects/:id/check-batches/:batchRunId/diagnostics', async (req, res) => {
|
|
8313
|
+
const project = getProjectById(req.params.id);
|
|
8314
|
+
if (!project) {
|
|
8315
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8316
|
+
}
|
|
8317
|
+
const diagnostics = getCheckBatchDiagnosticResponse(project.id, req.params.batchRunId);
|
|
8318
|
+
if (!diagnostics) {
|
|
8319
|
+
return res.status(404).json({ error: 'Check batch not found' });
|
|
8320
|
+
}
|
|
8321
|
+
return res.json({
|
|
8322
|
+
...diagnostics,
|
|
8323
|
+
repair: await getCheckRepairCandidateState(project.id, req.params.batchRunId),
|
|
8324
|
+
latest_repair: getLatestCheckRepairForBatch(project.id, req.params.batchRunId),
|
|
8325
|
+
});
|
|
8326
|
+
});
|
|
8327
|
+
app.get('/projects/:id/check-attempts/:attemptRunId/diagnostics', (req, res) => {
|
|
8328
|
+
const project = getProjectById(req.params.id);
|
|
8329
|
+
if (!project) {
|
|
8330
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8331
|
+
}
|
|
8332
|
+
const diagnostics = getCheckAttemptDiagnosticResponse(project.id, req.params.attemptRunId);
|
|
8333
|
+
if (!diagnostics) {
|
|
8334
|
+
return res.status(404).json({ error: 'Check attempt diagnostics not found' });
|
|
8335
|
+
}
|
|
8336
|
+
return res.json(diagnostics);
|
|
8337
|
+
});
|
|
8338
|
+
app.get('/projects/:id/check-gate-evaluations/:evaluationId', async (req, res) => {
|
|
8339
|
+
const project = getProjectById(req.params.id);
|
|
8340
|
+
if (!project) {
|
|
8341
|
+
return res.status(404).json({ error: 'Not found' });
|
|
8342
|
+
}
|
|
8142
8343
|
const evaluation = getCheckGateEvaluation(req.params.id, req.params.evaluationId);
|
|
8143
8344
|
if (!evaluation) {
|
|
8144
8345
|
return res.status(404).json({ error: 'Check gate evaluation not found' });
|
|
8145
8346
|
}
|
|
8146
|
-
|
|
8347
|
+
const workspace = resolveExplicitProjectTestWorkspace(project, evaluation.target.targetKind, evaluation.target.targetBundleId);
|
|
8348
|
+
const currentWorkspaceIdentity = 'error' in workspace
|
|
8349
|
+
? null
|
|
8350
|
+
: await captureCheckWorkspaceIdentity(workspace.cwd);
|
|
8351
|
+
const currentPolicyResolution = resolveRequiredCheckPolicy(project, { boundaryKind: evaluation.boundaryKind });
|
|
8352
|
+
return res.json(hydrateCheckGatePresentApplicability(evaluation, currentWorkspaceIdentity, currentPolicyResolution));
|
|
8147
8353
|
});
|
|
8148
8354
|
app.post('/projects/:id/check-batches/:batchRunId/stop', async (req, res) => {
|
|
8149
8355
|
if (!getCheckBatchDetails(req.params.id, req.params.batchRunId)) {
|