@straiffi/archon 1.7.5 → 1.7.6

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.
Files changed (73) hide show
  1. package/dist/client/assets/{ActivityView-CT9iCPyc.js → ActivityView-BrZY8vYf.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-BA6xyQeX.js → GitHubActionsDialog-CUfdVw97.js} +1 -1
  3. package/dist/client/assets/{TestsDialog-D2qrW5Ug.js → TestsDialog-FXcnLOyf.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-3BPJPVTR-R6v7w0Nl.js → architectureDiagram-3BPJPVTR-D0PXGvSL.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-GPEHLZMM-CHlBlnJq.js → blockDiagram-GPEHLZMM-BCLAxnp5.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-AAUBKEIU-BvZKqUc6.js → c4Diagram-AAUBKEIU-DVZ5yZWV.js} +1 -1
  7. package/dist/client/assets/channel-BCPCrThZ.js +1 -0
  8. package/dist/client/assets/{chunk-2J33WTMH-2gsIkBeO.js → chunk-2J33WTMH-BGJYj1Lu.js} +1 -1
  9. package/dist/client/assets/{chunk-3OPIFGDE-CcqPBjqx.js → chunk-3OPIFGDE-DI5-yK3m.js} +1 -1
  10. package/dist/client/assets/{chunk-5ZQYHXKU-DX_wK5Rp.js → chunk-5ZQYHXKU-Dnr5DDsb.js} +1 -1
  11. package/dist/client/assets/{chunk-727SXJPM-B9WUxzJL.js → chunk-727SXJPM-8HdFwn-P.js} +1 -1
  12. package/dist/client/assets/{chunk-AQP2D5EJ-BG0s75_H.js → chunk-AQP2D5EJ-C7x9t2uJ.js} +1 -1
  13. package/dist/client/assets/{chunk-CSCIHK7Q-CyNcvvqW.js → chunk-CSCIHK7Q-CrhwRPh5.js} +1 -1
  14. package/dist/client/assets/{chunk-KSCS5N6A-CWVy_Wi0.js → chunk-KSCS5N6A-CdD62r5U.js} +1 -1
  15. package/dist/client/assets/{chunk-L5ZTLDWV-3dsXRB0X.js → chunk-L5ZTLDWV-CqQVvwc_.js} +1 -1
  16. package/dist/client/assets/{chunk-LZXEDZCA-B09QSB9z.js → chunk-LZXEDZCA-DLHrqoJ4.js} +2 -2
  17. package/dist/client/assets/{chunk-ND2GUHAM-BxzAdxTN.js → chunk-ND2GUHAM-B0yOdiPF.js} +1 -1
  18. package/dist/client/assets/{chunk-NZK2D7GU-D4ZfFwbB.js → chunk-NZK2D7GU-boM-MocY.js} +1 -1
  19. package/dist/client/assets/{chunk-O5CBEL6O-BxQULuKS.js → chunk-O5CBEL6O-B0jgJn0t.js} +1 -1
  20. package/dist/client/assets/{chunk-WU5MYG2G-CEJwp0Ry.js → chunk-WU5MYG2G-C_S_v-m2.js} +1 -1
  21. package/dist/client/assets/classDiagram-4FO5ZUOK-BdJlc_1i.js +1 -0
  22. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Bidw5Zc1.js +1 -0
  23. package/dist/client/assets/{dagre-BM42HDAG-Dx_V7OMy.js → dagre-BM42HDAG-DKl6Y8ya.js} +1 -1
  24. package/dist/client/assets/{diagram-2AECGRRQ-Cc3VTg9P.js → diagram-2AECGRRQ-6Lyn9DBp.js} +1 -1
  25. package/dist/client/assets/{diagram-5GNKFQAL-mJ1xhs2G.js → diagram-5GNKFQAL-wdS1vEkN.js} +1 -1
  26. package/dist/client/assets/{diagram-KO2AKTUF-CLyT9ac8.js → diagram-KO2AKTUF-CPih29jF.js} +1 -1
  27. package/dist/client/assets/{diagram-LMA3HP47-CVr47yij.js → diagram-LMA3HP47-Cr5Px74d.js} +1 -1
  28. package/dist/client/assets/{diagram-OG6HWLK6-Dp5TJ8lM.js → diagram-OG6HWLK6-i0PjSScd.js} +1 -1
  29. package/dist/client/assets/{erDiagram-TEJ5UH35-BBxwyu0r.js → erDiagram-TEJ5UH35-Dt4yOC9J.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-I6XJVG4X-CuFYzVQ-.js → flowDiagram-I6XJVG4X-Bf6kvajC.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-6RSMTGT7-aRQarcQY.js → ganttDiagram-6RSMTGT7-DgxePMk_.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-B3mHSkBv.js → gitGraphDiagram-PVQCEYII-BZq2cmFS.js} +1 -1
  33. package/dist/client/assets/{index-Oz0S7bcT.js → index-CjRMYO1U.js} +67 -67
  34. package/dist/client/assets/{infoDiagram-5YYISTIA-BSyryQJ9.js → infoDiagram-5YYISTIA-Chij69KN.js} +1 -1
  35. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BAGbrtSG.js → ishikawaDiagram-YF4QCWOH-3qHCLFgD.js} +1 -1
  36. package/dist/client/assets/{journeyDiagram-JHISSGLW-CDTht6k6.js → journeyDiagram-JHISSGLW-DvRW8tbA.js} +1 -1
  37. package/dist/client/assets/{kanban-definition-UN3LZRKU-BDtuMp0H.js → kanban-definition-UN3LZRKU-DjR2T5I1.js} +1 -1
  38. package/dist/client/assets/{line-n0aNicmA.js → line-B9OzrQ1Y.js} +1 -1
  39. package/dist/client/assets/{mermaid-parser.core-CdE4vZ4k.js → mermaid-parser.core-DYcDor4d.js} +1 -1
  40. package/dist/client/assets/{mermaid.core-C546CQj1.js → mermaid.core-DG8QYo2u.js} +3 -3
  41. package/dist/client/assets/{mindmap-definition-RKZ34NQL-BwO779am.js → mindmap-definition-RKZ34NQL-f4QPF6b3.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-4H26LBE5-DU1k71kn.js → pieDiagram-4H26LBE5-CMkl2jBu.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CvM5lyQg.js → quadrantDiagram-W4KKPZXB-BXaUHzJi.js} +1 -1
  44. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DDBdSq0B.js → requirementDiagram-4Y6WPE33-B-Inuj_6.js} +1 -1
  45. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-ELM2mu81.js → sankeyDiagram-5OEKKPKP-BjsmZFYI.js} +1 -1
  46. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D7uF-nRR.js → sequenceDiagram-3UESZ5HK-B1PAm6sX.js} +1 -1
  47. package/dist/client/assets/{stateDiagram-AJRCARHV-IhaGRCbG.js → stateDiagram-AJRCARHV-pLONNEN8.js} +1 -1
  48. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-kWPDF3wr.js +1 -0
  49. package/dist/client/assets/{timeline-definition-PNZ67QCA-zHJGFvZ8.js → timeline-definition-PNZ67QCA-BLMkSXo_.js} +1 -1
  50. package/dist/client/assets/{vennDiagram-CIIHVFJN-EG1HFfD7.js → vennDiagram-CIIHVFJN-CEwGRegG.js} +1 -1
  51. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DdQevxXg.js → wardleyDiagram-YWT4CUSO-_md2IBXC.js} +1 -1
  52. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BjihNG0E.js → xychartDiagram-2RQKCTM6-DVzwfXHc.js} +1 -1
  53. package/dist/client/index.html +1 -1
  54. package/dist/server/index.js +62 -76
  55. package/dist/server/index.js.map +1 -1
  56. package/dist/server/lib/automationResumeDecision.js +141 -0
  57. package/dist/server/lib/automationResumeDecision.js.map +1 -0
  58. package/dist/server/lib/buildSequences.js +27 -0
  59. package/dist/server/lib/buildSequences.js.map +1 -1
  60. package/dist/server/lib/ticketFollowUpOperations.js +19 -15
  61. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  62. package/dist/server/lib/ticketUndo.js +83 -31
  63. package/dist/server/lib/ticketUndo.js.map +1 -1
  64. package/dist/server/lib/tickets.js +67 -6
  65. package/dist/server/lib/tickets.js.map +1 -1
  66. package/dist/server/lib/types.js.map +1 -1
  67. package/dist/server/workers/review.js +1 -0
  68. package/dist/server/workers/review.js.map +1 -1
  69. package/package.json +1 -1
  70. package/dist/client/assets/channel-Ckv8cPSf.js +0 -1
  71. package/dist/client/assets/classDiagram-4FO5ZUOK-B-N-arsi.js +0 -1
  72. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-PTX7YrlL.js +0 -1
  73. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-ceHFQMIT.js +0 -1
@@ -49,8 +49,9 @@ import { formatBuildOpenQuestionAnswersPrompt, getLatestBuildOpenQuestionBatchSt
49
49
  import { acceptBuildOpenQuestionResolution } from './lib/buildOpenQuestionOperations.js';
50
50
  import { completeAutomationProgression, createAutomationReviewFix, finishAutomationReviewFix, getAutomationProgression, recoverLegacyAutomationProgression, recoverStoppedSideEffectProgression, runAutomationProgression, stopAutomationProgression, waitAutomationProgression } from './lib/automationProgression.js';
51
51
  import { reconcileAutomationStage } from './lib/automationReconciliation.js';
52
+ import { pausedRunBelongsToProgression, resolveAutomationResumeDecision } from './lib/automationResumeDecision.js';
52
53
  import { getAutomationStageDetails, } from './lib/automationStageDetails.js';
53
- import { clearAutomationPause, countBlockingFindings, depthAtLeast, getBundleAutomationState, isAutomationDepth, recordAutomationPause, resolveAutomationConfig, upsertBundleAutomationState, } from './lib/ticketAutomation.js';
54
+ import { buildAutomationFixInstruction, clearAutomationPause, countBlockingFindings, depthAtLeast, getBundleAutomationState, isAutomationDepth, recordAutomationPause, resolveAutomationConfig, upsertBundleAutomationState, } from './lib/ticketAutomation.js';
54
55
  import { runAutomationCommitChain } from './lib/ticketAutomationCommit.js';
55
56
  import { getDiscoveredSkills, normalizeSkillNames } from './lib/skills.js';
56
57
  import { clearAllPreviewProxies } from './lib/previewProxy.js';
@@ -3954,25 +3955,6 @@ app.post('/bundles/:id/follow-up', (req, res) => {
3954
3955
  });
3955
3956
  const AUTOMATION_SIDE_EFFECT_KINDS = new Set(['automation_commit', 'automation_push', 'automation_pull_request']);
3956
3957
  const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix']);
3957
- const pausedRunBelongsToProgression = (projectId, bundleId, progressionRunId, pausedRunId) => {
3958
- const pausedRun = getExecutionRun(projectId, pausedRunId);
3959
- const progression = getExecutionRun(projectId, progressionRunId);
3960
- if (!pausedRun || !progression || progression.kind !== 'automation_progression') {
3961
- return false;
3962
- }
3963
- const ownsBundle = listExecutionRunLinks(projectId, pausedRun.id).some(link => (link.entity_type === 'bundle'
3964
- && link.entity_id === bundleId
3965
- && (link.relationship === 'primary' || link.relationship === 'context')));
3966
- if (!ownsBundle) {
3967
- return false;
3968
- }
3969
- if (pausedRun.parent_run_id === progressionRunId) {
3970
- return true;
3971
- }
3972
- const parent = pausedRun.parent_run_id ? getExecutionRun(projectId, pausedRun.parent_run_id) : null;
3973
- return parent?.kind === 'automation_review_fix' && parent.parent_run_id === progressionRunId
3974
- || progression.parent_run_id === pausedRun.id;
3975
- };
3976
3958
  app.post('/bundles/:id/resume-automation', async (req, res) => {
3977
3959
  const result = getRequiredProject(req);
3978
3960
  if ('error' in result) {
@@ -3986,15 +3968,38 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
3986
3968
  if (!bundleState || !bundleState.automation_paused_reason) {
3987
3969
  return res.status(409).json({ error: 'Bundle automation is not paused' });
3988
3970
  }
3989
- const liveAutomationConfig = resolveAutomationConfig(bundle, result.project);
3990
- if (hasActiveBuildOpenQuestionBatch(result.project.id, bundle.id)) {
3991
- return res.status(409).json({ error: 'Build open question resolution is still in progress' });
3992
- }
3993
- if (bundleState.automation_paused_code === 'open_questions'
3994
- && liveAutomationConfig.pauseOnOpenQuestions
3995
- && listBuildOpenQuestionsForBundle(result.project.id, bundle.id).length > 0) {
3996
- return res.status(409).json({ error: 'Resolve or dismiss all Build open questions before resuming automation' });
3997
- }
3971
+ const resolveCurrentDecision = () => {
3972
+ const currentState = getBundleAutomationState(result.project.id, bundle.id);
3973
+ if (!currentState?.automation_paused_reason) {
3974
+ return null;
3975
+ }
3976
+ return resolveAutomationResumeDecision({
3977
+ projectId: result.project.id,
3978
+ bundleId: bundle.id,
3979
+ state: currentState,
3980
+ config: resolveAutomationConfig(getBundle(bundle.id, result.project.id), getProjectById(result.project.id)),
3981
+ tickets: listDetailedBundleTickets(result.project.id, bundle.id),
3982
+ openQuestionCount: listBuildOpenQuestionsForBundle(result.project.id, bundle.id).length,
3983
+ questionResolutionActive: hasActiveBuildOpenQuestionBatch(result.project.id, bundle.id),
3984
+ });
3985
+ };
3986
+ const decision = resolveCurrentDecision();
3987
+ if (!decision || decision.status !== 'enabled') {
3988
+ const error = decision?.status === 'hidden' && decision.reason === 'question_resolution_active'
3989
+ ? 'Build open question resolution is still in progress'
3990
+ : decision?.status === 'hidden' && decision.reason === 'resolve_open_questions'
3991
+ ? 'Resolve or dismiss all Build open questions before resuming automation'
3992
+ : decision?.status === 'disabled' && decision.reason === 'invalid_stage_lineage'
3993
+ ? 'The paused automation stage does not belong to the active progression'
3994
+ : 'Bundle automation cannot be resumed in its current state';
3995
+ return res.status(409).json({ error, automation_resume_decision: decision });
3996
+ }
3997
+ const revalidateDecision = () => {
3998
+ const current = resolveCurrentDecision();
3999
+ return current?.status === 'enabled'
4000
+ && current.outcome === decision.outcome
4001
+ && current.owner_ticket_id === decision.owner_ticket_id;
4002
+ };
3998
4003
  let progressionRunId = bundleState.automation_progression_run_id;
3999
4004
  if (!progressionRunId) {
4000
4005
  try {
@@ -4022,12 +4027,13 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4022
4027
  catch (error) {
4023
4028
  return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
4024
4029
  }
4030
+ if (!revalidateDecision()) {
4031
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4032
+ }
4025
4033
  let sideEffectResume = null;
4026
- let pausedRunKind = null;
4027
4034
  if (bundleState.automation_paused_stage_run_id) {
4028
4035
  const stageRunId = bundleState.automation_paused_stage_run_id;
4029
4036
  const stage = getExecutionRun(result.project.id, stageRunId);
4030
- pausedRunKind = stage?.kind ?? null;
4031
4037
  if (!stage
4032
4038
  || (!AUTOMATION_SIDE_EFFECT_KINDS.has(stage.kind) && !AUTOMATION_WORKER_PAUSE_KINDS.has(stage.kind))
4033
4039
  || !pausedRunBelongsToProgression(result.project.id, bundle.id, progressionRunId, stageRunId)) {
@@ -4091,33 +4097,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4091
4097
  }
4092
4098
  }
4093
4099
  }
4094
- if (liveAutomationConfig.depth === 'manual') {
4095
- completeAutomationProgression({
4096
- projectId: result.project.id,
4097
- bundleId: bundle.id,
4098
- progressionRunId,
4099
- domainStatus: 'manual_boundary_reached',
4100
- broadcaster: io,
4101
- });
4102
- for (const ticket of listDetailedBundleTickets(result.project.id, bundle.id)) {
4103
- io.emit('ticket:updated', ticket);
4104
- }
4105
- return res.json(serializeBundleDetails(result.project, bundle));
4106
- }
4107
- const reviewOwnerSource = bundleState.automation_paused_code === 'open_questions'
4108
- ? listBundleSliceTickets(result.project.id, bundle.id, 'build')
4109
- .find(ticket => ticket.agent_status === 'done') ?? null
4110
- : resolveBundleReviewOwner(result.project.id, bundle.id)
4111
- ?? listBundleSliceTickets(result.project.id, bundle.id, 'review')[0]
4112
- ?? (bundleState.automation_paused_code === 'review' && (pausedRunKind === 'build' || pausedRunKind === 'build_follow_up')
4113
- ? listBundleSliceTickets(result.project.id, bundle.id, 'build')
4114
- .find(ticket => ticket.agent_status === 'done') ?? null
4115
- : null)
4116
- ?? null;
4117
- if (!reviewOwnerSource) {
4118
- return res.status(409).json({ error: 'No review ticket to resume from' });
4119
- }
4120
- const owner = getTicket(reviewOwnerSource.id);
4100
+ const owner = getTicket(decision.owner_ticket_id);
4121
4101
  if (!owner) {
4122
4102
  return res.status(409).json({ error: 'No review ticket to resume from' });
4123
4103
  }
@@ -4151,6 +4131,9 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4151
4131
  };
4152
4132
  };
4153
4133
  if (sideEffectResume) {
4134
+ if (!decision.outcome.startsWith('reconcile_') || !revalidateDecision()) {
4135
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4136
+ }
4154
4137
  try {
4155
4138
  runAutomationProgression({
4156
4139
  projectId: result.project.id,
@@ -4169,27 +4152,17 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4169
4152
  }
4170
4153
  return res.json(serializeBundleDetails(result.project, bundle));
4171
4154
  }
4172
- if (owner.state === 'review' && owner.agent_status === 'running') {
4173
- return res.status(409).json({ error: 'Review already running' });
4174
- }
4175
4155
  if (owner.state === 'review' && owner.agent_status !== 'running') {
4176
- const latestRun = getLatestReviewRunForContext({
4177
- ticketId: owner.id,
4178
- projectId: owner.project_id,
4179
- worktreeBundleId: owner.worktree_bundle_id,
4180
- });
4181
- const findings = latestRun ? listReviewFindings(latestRun.id) : [];
4182
- const blockingCount = countBlockingFindings(findings, automationConfig);
4183
4156
  const iteration = bundleState.review_iteration_count ?? 0;
4184
- if (owner.can_re_review
4185
- && automationConfig.reviewFixEnabled
4186
- && blockingCount > 0
4187
- && iteration < automationConfig.reviewMaxIterations) {
4157
+ if (decision.outcome === 'start_review_fix') {
4188
4158
  let reviewFixRunId = null;
4189
4159
  let followUpResult;
4190
4160
  const previousIteration = bundleState.review_iteration_count ?? 0;
4191
4161
  const previousFixLoopActive = bundleState.fix_loop_active;
4192
4162
  try {
4163
+ if (!revalidateDecision()) {
4164
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4165
+ }
4193
4166
  const progression = getAutomationProgression(result.project.id, bundle.id);
4194
4167
  if (!progression || progression.id !== progressionRunId) {
4195
4168
  return res.status(409).json({ error: 'Automation progression ownership is invalid' });
@@ -4219,10 +4192,11 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4219
4192
  ticketId: owner.id,
4220
4193
  requestedProjectId: result.project.id,
4221
4194
  payload: {
4222
- instruction: `Fix the code review findings at or above "${automationConfig.reviewSeverity}" severity. Address each blocking finding directly and minimally. Do not introduce unrelated changes, reformatting, or refactors. Do not commit.`,
4195
+ instruction: buildAutomationFixInstruction(automationConfig.reviewSeverity),
4223
4196
  mode: 'build',
4224
4197
  },
4225
4198
  broadcaster: io,
4199
+ persistTriggerMessage: false,
4226
4200
  initiation: {
4227
4201
  initiator: 'automation',
4228
4202
  causalParentRunId: reviewFix.runId,
@@ -4276,8 +4250,11 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4276
4250
  return res.status(followUpResult.status).json({ error: followUpResult.error });
4277
4251
  }
4278
4252
  }
4279
- else if (depthAtLeast(automationConfig.depth, 'auto_commit')) {
4253
+ else if (decision.outcome === 'continue_commit_chain') {
4280
4254
  try {
4255
+ if (!revalidateDecision()) {
4256
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4257
+ }
4281
4258
  runAutomationProgression({
4282
4259
  projectId: result.project.id,
4283
4260
  bundleId: bundle.id,
@@ -4290,7 +4267,10 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4290
4267
  return res.status(409).json({ error: error instanceof Error ? error.message : String(error) });
4291
4268
  }
4292
4269
  }
4293
- else {
4270
+ else if (decision.outcome === 'rerun_review') {
4271
+ if (!revalidateDecision()) {
4272
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4273
+ }
4294
4274
  const reviewResult = rerunTicketReviewOperation(owner, io, {
4295
4275
  automatic: true,
4296
4276
  initiation: { causalParentRunId: progressionRunId },
@@ -4300,8 +4280,14 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4300
4280
  return res.status(reviewResult.status).json({ error: reviewResult.error });
4301
4281
  }
4302
4282
  }
4283
+ else {
4284
+ return res.status(409).json({ error: 'The selected Resume outcome no longer matches the bundle state' });
4285
+ }
4303
4286
  }
4304
- else if (owner.state === 'build' && owner.agent_status === 'done') {
4287
+ else if (owner.state === 'build' && owner.agent_status === 'done' && decision.outcome === 'start_review') {
4288
+ if (!revalidateDecision()) {
4289
+ return res.status(409).json({ error: 'Bundle automation state changed before Resume could start' });
4290
+ }
4305
4291
  const reviewResult = transitionBundleToReview(result.project.id, bundle.id, io, {
4306
4292
  automatic: true,
4307
4293
  initiation: { causalParentRunId: progressionRunId },