@straiffi/archon 1.7.3 → 1.7.5
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-CT9iCPyc.js +1 -0
- package/dist/client/assets/GitHubActionsDialog-BA6xyQeX.js +1 -0
- package/dist/client/assets/TestsDialog-D2qrW5Ug.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-BzzGotac.js → architectureDiagram-3BPJPVTR-R6v7w0Nl.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DIcqLHKg.js → blockDiagram-GPEHLZMM-CHlBlnJq.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-Hc1Sqmhs.js → c4Diagram-AAUBKEIU-BvZKqUc6.js} +1 -1
- package/dist/client/assets/channel-Ckv8cPSf.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CWSwjsgk.js → chunk-2J33WTMH-2gsIkBeO.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-BnX3DljN.js → chunk-3OPIFGDE-CcqPBjqx.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-EyyJlI-d.js → chunk-5ZQYHXKU-DX_wK5Rp.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-Ci6CfxWj.js → chunk-727SXJPM-B9WUxzJL.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-RKZNsJTm.js → chunk-AQP2D5EJ-BG0s75_H.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-DBf0Euoj.js → chunk-CSCIHK7Q-CyNcvvqW.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-BmLQI_2S.js → chunk-KSCS5N6A-CWVy_Wi0.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-DKwVAb8G.js → chunk-L5ZTLDWV-3dsXRB0X.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-axotKkbz.js → chunk-LZXEDZCA-B09QSB9z.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-BBlJ4nXC.js → chunk-ND2GUHAM-BxzAdxTN.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-BKJGoZZt.js → chunk-NZK2D7GU-D4ZfFwbB.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-C-Ghigo1.js → chunk-O5CBEL6O-BxQULuKS.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-CCzVWYcd.js → chunk-WU5MYG2G-CEJwp0Ry.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-B-N-arsi.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-PTX7YrlL.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-rwIdPcjI.js → dagre-BM42HDAG-Dx_V7OMy.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-DJWxOQsg.js → diagram-2AECGRRQ-Cc3VTg9P.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-C-mQeFtd.js → diagram-5GNKFQAL-mJ1xhs2G.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BAu6u4sR.js → diagram-KO2AKTUF-CLyT9ac8.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-U6CbvBn0.js → diagram-LMA3HP47-CVr47yij.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-DNTwFcs1.js → diagram-OG6HWLK6-Dp5TJ8lM.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-DaHX6Xw5.js → erDiagram-TEJ5UH35-BBxwyu0r.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-B9hKqL2l.js → flowDiagram-I6XJVG4X-CuFYzVQ-.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-BQ1HPHVO.js → ganttDiagram-6RSMTGT7-aRQarcQY.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-BBRcsmMK.js → gitGraphDiagram-PVQCEYII-B3mHSkBv.js} +1 -1
- package/dist/client/assets/index-BJGHMaMz.css +2 -0
- package/dist/client/assets/index-Oz0S7bcT.js +273 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-DUoNiSGC.js → infoDiagram-5YYISTIA-BSyryQJ9.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DJN1y2w8.js → ishikawaDiagram-YF4QCWOH-BAGbrtSG.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BxLLMT70.js → journeyDiagram-JHISSGLW-CDTht6k6.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BdCPistJ.js → kanban-definition-UN3LZRKU-BDtuMp0H.js} +1 -1
- package/dist/client/assets/{line-4mIgXsZd.js → line-n0aNicmA.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-Pu1QGWJ-.js → mermaid-parser.core-CdE4vZ4k.js} +1 -1
- package/dist/client/assets/{mermaid.core-DnH9DrgZ.js → mermaid.core-C546CQj1.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-DqE4ba3C.js → mindmap-definition-RKZ34NQL-BwO779am.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-Crjy9ejf.js → pieDiagram-4H26LBE5-DU1k71kn.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BUSZ2VB7.js → quadrantDiagram-W4KKPZXB-CvM5lyQg.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-CBhFKEoV.js → requirementDiagram-4Y6WPE33-DDBdSq0B.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-CgdbY41v.js → sankeyDiagram-5OEKKPKP-ELM2mu81.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-hkp_H7AE.js → sequenceDiagram-3UESZ5HK-D7uF-nRR.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-C6x45RWp.js → stateDiagram-AJRCARHV-IhaGRCbG.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-ceHFQMIT.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CjnZWttQ.js → timeline-definition-PNZ67QCA-zHJGFvZ8.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DU5ZyYju.js → vennDiagram-CIIHVFJN-EG1HFfD7.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CaCEnCB0.js → wardleyDiagram-YWT4CUSO-DdQevxXg.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-Ce3xa37U.js → xychartDiagram-2RQKCTM6-BjihNG0E.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +283 -0
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +390 -117
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/attachments.js +40 -0
- package/dist/server/lib/attachments.js.map +1 -1
- package/dist/server/lib/buildOpenQuestionOperations.js +17 -2
- package/dist/server/lib/buildOpenQuestionOperations.js.map +1 -1
- package/dist/server/lib/buildSequences.js +25 -0
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/bundleReviewOperations.js +9 -0
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatOperations.js +40 -16
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/executionArtifactCleanupState.js +12 -0
- package/dist/server/lib/executionArtifactCleanupState.js.map +1 -0
- package/dist/server/lib/executionArtifactRetention.js +405 -0
- package/dist/server/lib/executionArtifactRetention.js.map +1 -0
- package/dist/server/lib/executionArtifacts.js +705 -0
- package/dist/server/lib/executionArtifacts.js.map +1 -0
- package/dist/server/lib/executionRetry.js +702 -0
- package/dist/server/lib/executionRetry.js.map +1 -0
- package/dist/server/lib/executionRetryContext.js +510 -0
- package/dist/server/lib/executionRetryContext.js.map +1 -0
- package/dist/server/lib/executionRetryPredicates.js +74 -0
- package/dist/server/lib/executionRetryPredicates.js.map +1 -0
- package/dist/server/lib/executionRuns.js +203 -40
- package/dist/server/lib/executionRuns.js.map +1 -1
- package/dist/server/lib/executionTimeline.js +73 -0
- package/dist/server/lib/executionTimeline.js.map +1 -0
- package/dist/server/lib/lightweightPrompt.js +2 -2
- package/dist/server/lib/lightweightPrompt.js.map +1 -1
- package/dist/server/lib/projects.js +16 -3
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/pullRequestContent.js +148 -25
- package/dist/server/lib/pullRequestContent.js.map +1 -1
- package/dist/server/lib/queue.js +1 -0
- package/dist/server/lib/queue.js.map +1 -1
- package/dist/server/lib/runtimePaths.js +7 -0
- package/dist/server/lib/runtimePaths.js.map +1 -1
- package/dist/server/lib/specOperations.js +51 -16
- package/dist/server/lib/specOperations.js.map +1 -1
- package/dist/server/lib/specReviewContext.js +10 -4
- package/dist/server/lib/specReviewContext.js.map +1 -1
- package/dist/server/lib/specReviewOperations.js +33 -5
- package/dist/server/lib/specReviewOperations.js.map +1 -1
- package/dist/server/lib/testSessions.js +2 -5
- package/dist/server/lib/testSessions.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +11 -4
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +74 -27
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketMessages.js +16 -0
- package/dist/server/lib/ticketMessages.js.map +1 -1
- package/dist/server/lib/types.js +12 -0
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +1 -1
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +26 -20
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +118 -15
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +23 -4
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +12 -9
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +2 -2
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specReview.js +2 -2
- package/dist/server/workers/specReview.js.map +1 -1
- package/dist/server/workers/specSession.js +29 -22
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/ActivityView-DTEenQas.js +0 -1
- package/dist/client/assets/GitHubActionsDialog-BKWHonUS.js +0 -1
- package/dist/client/assets/TestsDialog-cBaoffCs.js +0 -4
- package/dist/client/assets/channel-Cym17waa.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BcigvvIC.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-3AdSuE0N.js +0 -1
- package/dist/client/assets/index-CEMaJCPS.js +0 -273
- package/dist/client/assets/index-lWftq65U.css +0 -2
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DVzPjRPN.js +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const RETRYABLE_AGENT_STATUSES = new Set(['failed', 'interrupted']);
|
|
2
|
+
export const RETRYABLE_TEST_STATUSES = new Set(['failed', 'cancelled', 'interrupted']);
|
|
3
|
+
export const RETRYABLE_EXECUTION_KINDS = new Set([
|
|
4
|
+
'test',
|
|
5
|
+
'plan',
|
|
6
|
+
'build',
|
|
7
|
+
'review',
|
|
8
|
+
'build_follow_up',
|
|
9
|
+
'plan_follow_up',
|
|
10
|
+
'chat_turn',
|
|
11
|
+
'spec_turn',
|
|
12
|
+
'spec_review',
|
|
13
|
+
]);
|
|
14
|
+
export const LATER_RUN_SUPERSEDED_KINDS = new Set([
|
|
15
|
+
'plan',
|
|
16
|
+
'build',
|
|
17
|
+
'review',
|
|
18
|
+
'build_follow_up',
|
|
19
|
+
'plan_follow_up',
|
|
20
|
+
'chat_turn',
|
|
21
|
+
'spec_turn',
|
|
22
|
+
]);
|
|
23
|
+
export const isLaterRunSupersededKind = (kind) => LATER_RUN_SUPERSEDED_KINDS.has(kind);
|
|
24
|
+
export const isRetryableExecutionStatus = (kind, status) => ((kind === 'test' ? RETRYABLE_TEST_STATUSES : RETRYABLE_AGENT_STATUSES).has(status));
|
|
25
|
+
export const parseExecutionRetryTestSelection = (value) => {
|
|
26
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const selection = value;
|
|
30
|
+
if (selection.kind === 'all') {
|
|
31
|
+
return { kind: 'all' };
|
|
32
|
+
}
|
|
33
|
+
if (selection.kind === 'file' && typeof selection.path === 'string') {
|
|
34
|
+
return { kind: 'file', path: selection.path };
|
|
35
|
+
}
|
|
36
|
+
if (selection.kind === 'case' && typeof selection.path === 'string' && typeof selection.name === 'string') {
|
|
37
|
+
return { kind: 'case', path: selection.path, name: selection.name };
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
export const resolveExecutionRetryRunConfig = (source) => {
|
|
42
|
+
const tool = source.metadata?.retry_tool;
|
|
43
|
+
const model = source.metadata?.retry_model;
|
|
44
|
+
const variant = source.metadata?.retry_variant;
|
|
45
|
+
const skills = source.metadata?.retry_skills;
|
|
46
|
+
if ((tool !== 'opencode' && tool !== 'claude')
|
|
47
|
+
|| (model !== null && typeof model !== 'string')
|
|
48
|
+
|| (variant !== null && typeof variant !== 'string')
|
|
49
|
+
|| !Array.isArray(skills)
|
|
50
|
+
|| skills.some(skill => typeof skill !== 'string')) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return { tool: tool, model, variant, skills: skills };
|
|
54
|
+
};
|
|
55
|
+
export const resolveExecutionRetrySessionMode = (source) => {
|
|
56
|
+
const mode = source.metadata?.retry_mode;
|
|
57
|
+
if (source.kind === 'chat_turn') {
|
|
58
|
+
return mode === 'plan' || mode === 'build' ? mode : null;
|
|
59
|
+
}
|
|
60
|
+
if (source.kind === 'spec_turn') {
|
|
61
|
+
return mode === 'standard' || mode === 'grill' ? mode : null;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
};
|
|
65
|
+
export const hasExecutionRetryAutomationOwnership = ({ source, parentKind, automationPausedStageRunId, }) => {
|
|
66
|
+
if (source.initiated_by !== 'user' || source.metadata?.build_open_question_batch_id) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (source.parent_run_id && (parentKind === 'automation_progression' || parentKind === 'automation_review_fix')) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return automationPausedStageRunId === source.id;
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=executionRetryPredicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executionRetryPredicates.js","sourceRoot":"","sources":["../../../server/lib/executionRetryPredicates.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,12 @@ const GENERIC_RETRY_DENIED_KINDS = new Set([
|
|
|
17
17
|
'automation_push',
|
|
18
18
|
'automation_pull_request',
|
|
19
19
|
]);
|
|
20
|
+
const ARTIFACT_AUDIT_EVENT_TYPES = new Set([
|
|
21
|
+
'artifact_created',
|
|
22
|
+
'artifact_availability_changed',
|
|
23
|
+
'artifact_deletion_failed',
|
|
24
|
+
'artifact_expired',
|
|
25
|
+
]);
|
|
20
26
|
export class GitHubActionsDispatchConflictError extends Error {
|
|
21
27
|
executionRunId;
|
|
22
28
|
constructor(executionRunId) {
|
|
@@ -27,7 +33,7 @@ export class GitHubActionsDispatchConflictError extends Error {
|
|
|
27
33
|
}
|
|
28
34
|
const getRunStatement = db.prepare('SELECT * FROM execution_runs WHERE id = ? AND project_id = ?');
|
|
29
35
|
const getRunByIdStatement = db.prepare('SELECT * FROM execution_runs WHERE id = ?');
|
|
30
|
-
const projectExistsStatement = db.prepare('SELECT 1 FROM projects WHERE id = ?');
|
|
36
|
+
const projectExistsStatement = db.prepare('SELECT 1 FROM projects WHERE id = ? AND deletion_started_at IS NULL');
|
|
31
37
|
const insertRunStatement = db.prepare(`
|
|
32
38
|
INSERT INTO execution_runs (
|
|
33
39
|
id, project_id, kind, status, domain_status, source_kind, source_id, source_label, source_url,
|
|
@@ -62,6 +68,44 @@ const getRunLinkStatement = db.prepare(`
|
|
|
62
68
|
WHERE execution_run_id = ? AND project_id = ? AND entity_type = ? AND entity_id = ? AND relationship = ?
|
|
63
69
|
`);
|
|
64
70
|
const getDirectRetryChildStatement = db.prepare('SELECT id FROM execution_runs WHERE retry_of_run_id = ? LIMIT 1');
|
|
71
|
+
const hasLaterRunForPrimaryEntityStatement = db.prepare(`
|
|
72
|
+
SELECT 1
|
|
73
|
+
FROM execution_runs candidate
|
|
74
|
+
INNER JOIN execution_run_links candidate_primary
|
|
75
|
+
ON candidate_primary.execution_run_id = candidate.id
|
|
76
|
+
AND candidate_primary.project_id = candidate.project_id
|
|
77
|
+
AND candidate_primary.relationship = 'primary'
|
|
78
|
+
INNER JOIN execution_runs source ON source.id = ? AND source.project_id = ?
|
|
79
|
+
WHERE candidate.project_id = ?
|
|
80
|
+
AND candidate.kind = ?
|
|
81
|
+
AND candidate_primary.entity_type = ?
|
|
82
|
+
AND candidate_primary.entity_id = ?
|
|
83
|
+
AND candidate.rowid > source.rowid
|
|
84
|
+
AND candidate.retry_of_run_id IS NOT source.id
|
|
85
|
+
LIMIT 1
|
|
86
|
+
`);
|
|
87
|
+
const hasLaterSpecReviewForSnapshotStatement = db.prepare(`
|
|
88
|
+
SELECT 1
|
|
89
|
+
FROM execution_runs candidate
|
|
90
|
+
INNER JOIN execution_run_links candidate_primary
|
|
91
|
+
ON candidate_primary.execution_run_id = candidate.id
|
|
92
|
+
AND candidate_primary.project_id = candidate.project_id
|
|
93
|
+
AND candidate_primary.relationship = 'primary'
|
|
94
|
+
AND candidate_primary.entity_type = 'spec_session'
|
|
95
|
+
INNER JOIN execution_run_links candidate_snapshot
|
|
96
|
+
ON candidate_snapshot.execution_run_id = candidate.id
|
|
97
|
+
AND candidate_snapshot.project_id = candidate.project_id
|
|
98
|
+
AND candidate_snapshot.relationship = 'context'
|
|
99
|
+
AND candidate_snapshot.entity_type = 'spec_snapshot'
|
|
100
|
+
INNER JOIN execution_runs source ON source.id = ? AND source.project_id = ?
|
|
101
|
+
WHERE candidate.project_id = ?
|
|
102
|
+
AND candidate.kind = 'spec_review'
|
|
103
|
+
AND candidate_primary.entity_id = ?
|
|
104
|
+
AND candidate_snapshot.entity_id = ?
|
|
105
|
+
AND candidate.rowid > source.rowid
|
|
106
|
+
AND candidate.retry_of_run_id IS NOT source.id
|
|
107
|
+
LIMIT 1
|
|
108
|
+
`);
|
|
65
109
|
const getEventStatement = db.prepare('SELECT * FROM lifecycle_events WHERE id = ? AND project_id = ?');
|
|
66
110
|
const insertTestDetailsStatement = db.prepare(`
|
|
67
111
|
INSERT INTO test_execution_details (
|
|
@@ -183,26 +227,34 @@ const boundTestOutput = (output, alreadyTruncated = false) => {
|
|
|
183
227
|
outputTruncated: true,
|
|
184
228
|
};
|
|
185
229
|
};
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
230
|
+
const SOURCE_TABLES = {
|
|
231
|
+
ticket: 'tickets',
|
|
232
|
+
project: 'projects',
|
|
233
|
+
bundle: 'worktree_bundles',
|
|
234
|
+
chat_session: 'chat_sessions',
|
|
235
|
+
spec_session: 'spec_sessions',
|
|
236
|
+
};
|
|
237
|
+
const loadSourceAvailability = (rows) => {
|
|
238
|
+
const availability = new Map();
|
|
239
|
+
for (const [sourceKind, table] of Object.entries(SOURCE_TABLES)) {
|
|
240
|
+
const sourceRows = rows.filter(row => row.source_kind === sourceKind && row.source_id);
|
|
241
|
+
const ids = [...new Set(sourceRows.map(row => row.source_id))];
|
|
242
|
+
if (ids.length === 0) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const projectIds = [...new Set(sourceRows.map(row => row.project_id))];
|
|
246
|
+
const records = db.prepare(`
|
|
247
|
+
SELECT id, ${sourceKind === 'project' ? 'id' : 'project_id'} AS project_id
|
|
248
|
+
FROM ${table}
|
|
249
|
+
WHERE id IN (${ids.map(() => '?').join(', ')})
|
|
250
|
+
AND ${sourceKind === 'project' ? 'id' : 'project_id'} IN (${projectIds.map(() => '?').join(', ')})
|
|
251
|
+
`).all(...ids, ...projectIds);
|
|
252
|
+
const availableKeys = new Set(records.map(record => `${record.project_id}:${sourceKind}:${record.id}`));
|
|
253
|
+
for (const row of sourceRows) {
|
|
254
|
+
availability.set(`${row.project_id}:${sourceKind}:${row.source_id}`, availableKeys.has(`${row.project_id}:${sourceKind}:${row.source_id}`));
|
|
255
|
+
}
|
|
204
256
|
}
|
|
205
|
-
return
|
|
257
|
+
return availability;
|
|
206
258
|
};
|
|
207
259
|
const safeSnapshotUrl = (value) => {
|
|
208
260
|
if (!value) {
|
|
@@ -216,7 +268,7 @@ const safeSnapshotUrl = (value) => {
|
|
|
216
268
|
return null;
|
|
217
269
|
}
|
|
218
270
|
};
|
|
219
|
-
const serializeRun = (row) => ({
|
|
271
|
+
const serializeRun = (row, sourceAvailability) => ({
|
|
220
272
|
id: row.id,
|
|
221
273
|
project_id: row.project_id,
|
|
222
274
|
kind: row.kind,
|
|
@@ -227,7 +279,7 @@ const serializeRun = (row) => ({
|
|
|
227
279
|
kind: row.source_kind,
|
|
228
280
|
id: row.source_id,
|
|
229
281
|
label: row.source_label,
|
|
230
|
-
available:
|
|
282
|
+
available: sourceAvailability?.get(`${row.project_id}:${row.source_kind}:${row.source_id}`) ?? loadSourceAvailability([row]).get(`${row.project_id}:${row.source_kind}:${row.source_id}`) ?? Boolean(safeSnapshotUrl(row.source_url)),
|
|
231
283
|
url: safeSnapshotUrl(row.source_url),
|
|
232
284
|
}
|
|
233
285
|
: null,
|
|
@@ -255,10 +307,12 @@ const serializeEvent = (row) => ({
|
|
|
255
307
|
metadata: parseStoredObject(row.metadata_json),
|
|
256
308
|
});
|
|
257
309
|
const PUBLIC_EVENT_METADATA_KEYS = new Set([
|
|
310
|
+
'artifact_id',
|
|
258
311
|
'candidate_run_ids',
|
|
259
312
|
'conclusion',
|
|
260
313
|
'input_names',
|
|
261
314
|
'provider_run_id',
|
|
315
|
+
'prior_availability',
|
|
262
316
|
'ref',
|
|
263
317
|
'resolution_attempts',
|
|
264
318
|
'trigger',
|
|
@@ -266,7 +320,18 @@ const PUBLIC_EVENT_METADATA_KEYS = new Set([
|
|
|
266
320
|
]);
|
|
267
321
|
export const toCanonicalLifecycleEvent = (event) => {
|
|
268
322
|
const metadata = event.metadata
|
|
269
|
-
? Object.fromEntries(Object.entries(event.metadata).filter(([key]) =>
|
|
323
|
+
? Object.fromEntries(Object.entries(event.metadata).filter(([key, value]) => {
|
|
324
|
+
if (!PUBLIC_EVENT_METADATA_KEYS.has(key)) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (key === 'artifact_id') {
|
|
328
|
+
return typeof value === 'string' && value.length > 0 && value.length <= 255;
|
|
329
|
+
}
|
|
330
|
+
if (key === 'prior_availability') {
|
|
331
|
+
return value === 'available' || value === 'missing';
|
|
332
|
+
}
|
|
333
|
+
return true;
|
|
334
|
+
}))
|
|
270
335
|
: null;
|
|
271
336
|
return {
|
|
272
337
|
...event,
|
|
@@ -567,6 +632,12 @@ const assertTestTarget = (projectId, details) => {
|
|
|
567
632
|
}
|
|
568
633
|
};
|
|
569
634
|
export const hasDirectRetryChild = (runId) => Boolean(getDirectRetryChildStatement.get(runId));
|
|
635
|
+
export const getDirectRetryChild = (projectId, runId) => {
|
|
636
|
+
const child = getDirectRetryChildStatement.get(runId);
|
|
637
|
+
return child ? getExecutionRun(projectId, child.id) : null;
|
|
638
|
+
};
|
|
639
|
+
export const hasLaterExecutionRunForPrimaryEntity = ({ projectId, sourceRunId, kind, entityType, entityId, }) => Boolean(hasLaterRunForPrimaryEntityStatement.get(sourceRunId, projectId, projectId, kind, entityType, entityId));
|
|
640
|
+
export const hasLaterSpecReviewForSnapshot = ({ projectId, sourceRunId, sessionId, snapshotId, }) => Boolean(hasLaterSpecReviewForSnapshotStatement.get(sourceRunId, projectId, projectId, sessionId, snapshotId));
|
|
570
641
|
const insertTestDetails = (runId, details) => {
|
|
571
642
|
const boundedOutput = boundTestOutput(details.output ?? '', details.outputTruncated);
|
|
572
643
|
insertTestDetailsStatement.run(runId, details.commandId ?? null, details.commandName ?? null, details.commandRunner ?? null, details.commandSnapshot ?? null, details.activeCommand ?? null, details.targetKind ?? null, details.targetBundleId ?? null, details.targetLabel ?? null, details.ticketId ?? null, serializeBoundedObject(details.selection, 'Test selection'), serializeBoundedObject(details.summary, 'Test summary'), details.exitCode ?? null, details.durationMs ?? null, boundedOutput.output, boundedOutput.outputTruncated ? 1 : 0, Buffer.byteLength(boundedOutput.output, 'utf8'));
|
|
@@ -747,7 +818,33 @@ const createExecutionRunInTransaction = (input, allowAutomationSideEffectRetry =
|
|
|
747
818
|
metadataJson: serializeBoundedObject(input.eventMetadata, 'Lifecycle event metadata'),
|
|
748
819
|
createdAt: now,
|
|
749
820
|
});
|
|
750
|
-
|
|
821
|
+
const retryEvents = retrySource
|
|
822
|
+
? [
|
|
823
|
+
createEvent({
|
|
824
|
+
projectId: input.projectId,
|
|
825
|
+
runId: retrySource.id,
|
|
826
|
+
eventType: 'retry_requested',
|
|
827
|
+
fromStatus: retrySource.status,
|
|
828
|
+
toStatus: retrySource.status,
|
|
829
|
+
domainStatus: retrySource.domain_status,
|
|
830
|
+
metadataJson: serializeBoundedObject({ replacement_run_id: id }, 'Lifecycle event metadata'),
|
|
831
|
+
createdAt: now,
|
|
832
|
+
}),
|
|
833
|
+
...(event.event_type === 'retry_started'
|
|
834
|
+
? []
|
|
835
|
+
: [createEvent({
|
|
836
|
+
projectId: input.projectId,
|
|
837
|
+
runId: id,
|
|
838
|
+
eventType: 'retry_started',
|
|
839
|
+
fromStatus: 'queued',
|
|
840
|
+
toStatus: 'queued',
|
|
841
|
+
domainStatus: input.domainStatus ?? null,
|
|
842
|
+
metadataJson: serializeBoundedObject({ retry_of_run_id: retrySource.id }, 'Lifecycle event metadata'),
|
|
843
|
+
createdAt: now,
|
|
844
|
+
})]),
|
|
845
|
+
]
|
|
846
|
+
: [];
|
|
847
|
+
return { run: serializeRun(getRunRow(input.projectId, id)), event, retryEvents };
|
|
751
848
|
};
|
|
752
849
|
const insertRunLink = (input) => {
|
|
753
850
|
if (input.link.relationship === 'primary') {
|
|
@@ -861,11 +958,17 @@ export const withExecutionRunTransaction = (callback, emitter) => {
|
|
|
861
958
|
createExecutionRun: input => {
|
|
862
959
|
const result = createExecutionRunInTransaction(input);
|
|
863
960
|
enqueueRunAndEvent(notifications, result.run, result.event, emitter);
|
|
961
|
+
for (const retryEvent of result.retryEvents) {
|
|
962
|
+
notifications.push({ event: 'lifecycle-event:created', payload: retryEvent, emitter });
|
|
963
|
+
}
|
|
864
964
|
return result.run;
|
|
865
965
|
},
|
|
866
966
|
createAutomationRetryExecutionRun: input => {
|
|
867
967
|
const result = createExecutionRunInTransaction(input, true);
|
|
868
968
|
enqueueRunAndEvent(notifications, result.run, result.event, emitter);
|
|
969
|
+
for (const retryEvent of result.retryEvents) {
|
|
970
|
+
notifications.push({ event: 'lifecycle-event:created', payload: retryEvent, emitter });
|
|
971
|
+
}
|
|
869
972
|
return result.run;
|
|
870
973
|
},
|
|
871
974
|
transitionExecutionRun: input => {
|
|
@@ -931,6 +1034,18 @@ export const getExecutionRun = (projectId, runId) => {
|
|
|
931
1034
|
const row = getRunStatement.get(runId, projectId);
|
|
932
1035
|
return row ? serializeRun(row) : null;
|
|
933
1036
|
};
|
|
1037
|
+
export const getExecutionRunsByIds = (projectId, runIds) => {
|
|
1038
|
+
const ids = [...new Set(runIds)];
|
|
1039
|
+
if (ids.length === 0) {
|
|
1040
|
+
return [];
|
|
1041
|
+
}
|
|
1042
|
+
const rows = db.prepare(`
|
|
1043
|
+
SELECT * FROM execution_runs
|
|
1044
|
+
WHERE project_id = ? AND id IN (${ids.map(() => '?').join(', ')})
|
|
1045
|
+
`).all(projectId, ...ids);
|
|
1046
|
+
const sourceAvailability = loadSourceAvailability(rows);
|
|
1047
|
+
return rows.map(row => serializeRun(row, sourceAvailability));
|
|
1048
|
+
};
|
|
934
1049
|
export const getQueuedSpecReviewExecutionRun = (projectId, snapshotId) => {
|
|
935
1050
|
const row = db.prepare(`
|
|
936
1051
|
SELECT execution_runs.id
|
|
@@ -989,20 +1104,23 @@ export const hasActiveBuildExecutionRunForTicket = (projectId, ticketId) => {
|
|
|
989
1104
|
LIMIT 1
|
|
990
1105
|
`).get(projectId, ticketId));
|
|
991
1106
|
};
|
|
992
|
-
const purgeTestExecutionRunTransaction = db.transaction((projectId, runId) => {
|
|
993
|
-
return db.prepare(`
|
|
994
|
-
DELETE FROM execution_runs
|
|
995
|
-
WHERE id = ? AND project_id = ? AND kind = 'test'
|
|
996
|
-
`).run(runId, projectId).changes > 0;
|
|
997
|
-
});
|
|
998
|
-
export const purgeTestExecutionRun = (projectId, runId) => {
|
|
999
|
-
return purgeTestExecutionRunTransaction(projectId, runId);
|
|
1000
|
-
};
|
|
1001
1107
|
export const listExecutionRunLinks = (projectId, runId) => {
|
|
1002
1108
|
getRunRow(projectId, runId);
|
|
1003
1109
|
const links = getRunLinksStatement.all(runId, projectId);
|
|
1004
1110
|
return links.map(link => ({ ...link, url_snapshot: safeSnapshotUrl(link.url_snapshot) }));
|
|
1005
1111
|
};
|
|
1112
|
+
export const listExecutionRunLinksForRuns = (projectId, runIds) => {
|
|
1113
|
+
const ids = [...new Set(runIds)];
|
|
1114
|
+
if (ids.length === 0) {
|
|
1115
|
+
return [];
|
|
1116
|
+
}
|
|
1117
|
+
const links = db.prepare(`
|
|
1118
|
+
SELECT * FROM execution_run_links
|
|
1119
|
+
WHERE project_id = ? AND execution_run_id IN (${ids.map(() => '?').join(', ')})
|
|
1120
|
+
ORDER BY execution_run_id ASC, created_at ASC, entity_type ASC, entity_id ASC, relationship ASC
|
|
1121
|
+
`).all(projectId, ...ids);
|
|
1122
|
+
return links.map(link => ({ ...link, url_snapshot: safeSnapshotUrl(link.url_snapshot) }));
|
|
1123
|
+
};
|
|
1006
1124
|
const testDetailsSelect = `
|
|
1007
1125
|
SELECT td.*, er.project_id, er.status AS execution_status
|
|
1008
1126
|
FROM test_execution_details td
|
|
@@ -1175,30 +1293,41 @@ export const listExecutionRuns = (input) => {
|
|
|
1175
1293
|
}
|
|
1176
1294
|
const statuses = [...new Set(input.statuses ?? [])];
|
|
1177
1295
|
const cursor = input.cursor ? decodeCursor(input.cursor) : null;
|
|
1178
|
-
const clauses = ['project_id = ?'];
|
|
1296
|
+
const clauses = ['er.project_id = ?'];
|
|
1179
1297
|
const parameters = [input.projectId];
|
|
1180
1298
|
if (input.kind) {
|
|
1181
|
-
clauses.push('kind = ?');
|
|
1299
|
+
clauses.push('er.kind = ?');
|
|
1182
1300
|
parameters.push(input.kind);
|
|
1183
1301
|
}
|
|
1184
1302
|
if (statuses.length > 0) {
|
|
1185
|
-
clauses.push(`status IN (${statuses.map(() => '?').join(', ')})`);
|
|
1303
|
+
clauses.push(`er.status IN (${statuses.map(() => '?').join(', ')})`);
|
|
1186
1304
|
parameters.push(...statuses);
|
|
1187
1305
|
}
|
|
1188
1306
|
if (cursor) {
|
|
1189
|
-
clauses.push('(created_at < ? OR (created_at = ? AND id < ?))');
|
|
1307
|
+
clauses.push('(er.created_at < ? OR (er.created_at = ? AND er.id < ?))');
|
|
1190
1308
|
parameters.push(cursor.created_at, cursor.created_at, cursor.id);
|
|
1191
1309
|
}
|
|
1310
|
+
if (input.scopeEntity) {
|
|
1311
|
+
clauses.push(`EXISTS (
|
|
1312
|
+
SELECT 1 FROM execution_run_links scope_link
|
|
1313
|
+
WHERE scope_link.execution_run_id = er.id
|
|
1314
|
+
AND scope_link.project_id = er.project_id
|
|
1315
|
+
AND scope_link.entity_type = ?
|
|
1316
|
+
AND scope_link.entity_id = ?
|
|
1317
|
+
)`);
|
|
1318
|
+
parameters.push(input.scopeEntity.type, input.scopeEntity.id);
|
|
1319
|
+
}
|
|
1192
1320
|
const rows = db.prepare(`
|
|
1193
|
-
SELECT
|
|
1321
|
+
SELECT er.* FROM execution_runs er
|
|
1194
1322
|
WHERE ${clauses.join(' AND ')}
|
|
1195
|
-
ORDER BY created_at DESC, id DESC
|
|
1323
|
+
ORDER BY er.created_at DESC, er.id DESC
|
|
1196
1324
|
LIMIT ?
|
|
1197
1325
|
`).all(...parameters, limit + 1);
|
|
1198
1326
|
const pageRows = rows.slice(0, limit);
|
|
1327
|
+
const sourceAvailability = loadSourceAvailability(pageRows);
|
|
1199
1328
|
const lastRow = pageRows.at(-1);
|
|
1200
1329
|
return {
|
|
1201
|
-
runs: pageRows.map(serializeRun),
|
|
1330
|
+
runs: pageRows.map(row => serializeRun(row, sourceAvailability)),
|
|
1202
1331
|
next_cursor: rows.length > limit && lastRow
|
|
1203
1332
|
? encodeCursor({ created_at: lastRow.created_at, id: lastRow.id })
|
|
1204
1333
|
: null,
|
|
@@ -1213,6 +1342,40 @@ export const listLifecycleEvents = (projectId, runId) => {
|
|
|
1213
1342
|
`).all(projectId, runId);
|
|
1214
1343
|
return rows.map(serializeEvent);
|
|
1215
1344
|
};
|
|
1345
|
+
export const listLatestLifecycleEventsForRuns = (projectId, runIds) => {
|
|
1346
|
+
const ids = [...new Set(runIds)];
|
|
1347
|
+
if (ids.length === 0) {
|
|
1348
|
+
return [];
|
|
1349
|
+
}
|
|
1350
|
+
const rows = db.prepare(`
|
|
1351
|
+
SELECT * FROM (
|
|
1352
|
+
SELECT lifecycle_events.*,
|
|
1353
|
+
ROW_NUMBER() OVER (PARTITION BY execution_run_id ORDER BY sequence DESC, id DESC) AS timeline_rank
|
|
1354
|
+
FROM lifecycle_events
|
|
1355
|
+
WHERE project_id = ? AND execution_run_id IN (${ids.map(() => '?').join(', ')})
|
|
1356
|
+
)
|
|
1357
|
+
WHERE timeline_rank = 1
|
|
1358
|
+
`).all(projectId, ...ids);
|
|
1359
|
+
return rows.map(({ timeline_rank: _timelineRank, ...row }) => serializeEvent(row));
|
|
1360
|
+
};
|
|
1361
|
+
export const listLatestMeaningfulLifecycleEventsForRuns = (projectId, runIds) => {
|
|
1362
|
+
const ids = [...new Set(runIds)];
|
|
1363
|
+
if (ids.length === 0) {
|
|
1364
|
+
return [];
|
|
1365
|
+
}
|
|
1366
|
+
const excludedEventTypes = [...ARTIFACT_AUDIT_EVENT_TYPES];
|
|
1367
|
+
const rows = db.prepare(`
|
|
1368
|
+
SELECT * FROM (
|
|
1369
|
+
SELECT lifecycle_events.*,
|
|
1370
|
+
ROW_NUMBER() OVER (PARTITION BY execution_run_id ORDER BY sequence DESC, id DESC) AS timeline_rank
|
|
1371
|
+
FROM lifecycle_events
|
|
1372
|
+
WHERE project_id = ? AND execution_run_id IN (${ids.map(() => '?').join(', ')})
|
|
1373
|
+
AND event_type NOT IN (${excludedEventTypes.map(() => '?').join(', ')})
|
|
1374
|
+
)
|
|
1375
|
+
WHERE timeline_rank = 1
|
|
1376
|
+
`).all(projectId, ...ids, ...excludedEventTypes);
|
|
1377
|
+
return rows.map(({ timeline_rank: _timelineRank, ...row }) => serializeEvent(row));
|
|
1378
|
+
};
|
|
1216
1379
|
export const listProjectLifecycleEvents = (input) => {
|
|
1217
1380
|
const limit = input.limit ?? 50;
|
|
1218
1381
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200) {
|