@straiffi/archon 1.4.2 → 1.4.4

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 (105) hide show
  1. package/dist/client/assets/{TestsDialog-B1uwgeQE.js → TestsDialog-X-Nwi_to.js} +1 -1
  2. package/dist/client/assets/{architectureDiagram-3BPJPVTR-ae8dFJ9T.js → architectureDiagram-3BPJPVTR-9cLrE2K2.js} +1 -1
  3. package/dist/client/assets/{blockDiagram-GPEHLZMM-D7pbEjha.js → blockDiagram-GPEHLZMM-DUM8c9h0.js} +1 -1
  4. package/dist/client/assets/{c4Diagram-AAUBKEIU-Bv5inUss.js → c4Diagram-AAUBKEIU-BGzZZCWM.js} +1 -1
  5. package/dist/client/assets/channel-DtQkY6QR.js +1 -0
  6. package/dist/client/assets/{chunk-2J33WTMH-Dv8A9yde.js → chunk-2J33WTMH-vFN6QhTD.js} +1 -1
  7. package/dist/client/assets/{chunk-3OPIFGDE-C50OENMg.js → chunk-3OPIFGDE-DyKBRc1-.js} +1 -1
  8. package/dist/client/assets/{chunk-5ZQYHXKU-eVqo0pH1.js → chunk-5ZQYHXKU-CLfCScSV.js} +1 -1
  9. package/dist/client/assets/{chunk-727SXJPM-CGkzoG8B.js → chunk-727SXJPM-23L0srRA.js} +1 -1
  10. package/dist/client/assets/{chunk-AQP2D5EJ-BbYVRsCk.js → chunk-AQP2D5EJ-DImlAQ4d.js} +1 -1
  11. package/dist/client/assets/{chunk-CSCIHK7Q-DU7aZK8a.js → chunk-CSCIHK7Q-Du0bMpx1.js} +1 -1
  12. package/dist/client/assets/{chunk-KSCS5N6A-DA8KY2-g.js → chunk-KSCS5N6A-DusjvFEv.js} +1 -1
  13. package/dist/client/assets/{chunk-L5ZTLDWV-DM9-zYjF.js → chunk-L5ZTLDWV-BkNG3ci7.js} +1 -1
  14. package/dist/client/assets/{chunk-LZXEDZCA-DR69oZWS.js → chunk-LZXEDZCA-HAqn5vCc.js} +2 -2
  15. package/dist/client/assets/{chunk-ND2GUHAM-PgSjipvy.js → chunk-ND2GUHAM-CVtgPH-i.js} +1 -1
  16. package/dist/client/assets/{chunk-NZK2D7GU-X2ffkm-l.js → chunk-NZK2D7GU-BdFIPyHI.js} +1 -1
  17. package/dist/client/assets/{chunk-O5CBEL6O-BwTuL5Ds.js → chunk-O5CBEL6O-CVnV_Ag4.js} +1 -1
  18. package/dist/client/assets/{chunk-WU5MYG2G-3A60YtJe.js → chunk-WU5MYG2G-Bqm-URRz.js} +1 -1
  19. package/dist/client/assets/classDiagram-4FO5ZUOK-B164EwUZ.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BaJIWqCk.js +1 -0
  21. package/dist/client/assets/{dagre-BM42HDAG-97Lmzo1v.js → dagre-BM42HDAG-lryAYrqb.js} +1 -1
  22. package/dist/client/assets/{diagram-2AECGRRQ-Bsf_NTtC.js → diagram-2AECGRRQ-8YC8laRI.js} +1 -1
  23. package/dist/client/assets/{diagram-5GNKFQAL-CkDPOt_3.js → diagram-5GNKFQAL-Bc6zrWaM.js} +1 -1
  24. package/dist/client/assets/{diagram-KO2AKTUF-ByLp_tLp.js → diagram-KO2AKTUF-CaNxCLHP.js} +1 -1
  25. package/dist/client/assets/{diagram-LMA3HP47-DgIOCtSf.js → diagram-LMA3HP47-DHZbYXil.js} +1 -1
  26. package/dist/client/assets/{diagram-OG6HWLK6-Dij1QR8M.js → diagram-OG6HWLK6-Bo2ybDbE.js} +1 -1
  27. package/dist/client/assets/{erDiagram-TEJ5UH35-uTgrdKRM.js → erDiagram-TEJ5UH35-Dngj8c9N.js} +1 -1
  28. package/dist/client/assets/{flowDiagram-I6XJVG4X-D3VYp11z.js → flowDiagram-I6XJVG4X-D9eoNVrR.js} +1 -1
  29. package/dist/client/assets/{ganttDiagram-6RSMTGT7-BznyqZ31.js → ganttDiagram-6RSMTGT7-C9Dv9jgg.js} +1 -1
  30. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-GsstcxtF.js → gitGraphDiagram-PVQCEYII-BJ9GHSWC.js} +1 -1
  31. package/dist/client/assets/index-Cxa-1X6y.js +260 -0
  32. package/dist/client/assets/index-D6gWjd6J.css +2 -0
  33. package/dist/client/assets/{infoDiagram-5YYISTIA-BS3PqCd3.js → infoDiagram-5YYISTIA-BnG_mdvj.js} +1 -1
  34. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BeWmiFk3.js → ishikawaDiagram-YF4QCWOH-Dpk-UT12.js} +1 -1
  35. package/dist/client/assets/{journeyDiagram-JHISSGLW-CWXtsbWR.js → journeyDiagram-JHISSGLW-CWoQGCIh.js} +1 -1
  36. package/dist/client/assets/{kanban-definition-UN3LZRKU-CTNXURgY.js → kanban-definition-UN3LZRKU-SIKXWRFj.js} +1 -1
  37. package/dist/client/assets/{line-B-Egb4Pn.js → line-4KWMDey-.js} +1 -1
  38. package/dist/client/assets/{mermaid-parser.core-B8ZZbty_.js → mermaid-parser.core-Cy8gNeWH.js} +1 -1
  39. package/dist/client/assets/{mermaid.core-BSugEkw8.js → mermaid.core-CEM9Gusm.js} +3 -3
  40. package/dist/client/assets/{mindmap-definition-RKZ34NQL-4raxG21B.js → mindmap-definition-RKZ34NQL-Ce4w7wL-.js} +1 -1
  41. package/dist/client/assets/{pieDiagram-4H26LBE5-BtA7Ukd1.js → pieDiagram-4H26LBE5-7NcRaO35.js} +1 -1
  42. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-AHK7Q6xb.js → quadrantDiagram-W4KKPZXB-DZt5U_Wu.js} +1 -1
  43. package/dist/client/assets/{requirementDiagram-4Y6WPE33-CLjXFJnk.js → requirementDiagram-4Y6WPE33-DKlIYJf4.js} +1 -1
  44. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BCPQIPdV.js → sankeyDiagram-5OEKKPKP-XW6nJ-ly.js} +1 -1
  45. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BkYCIWVq.js → sequenceDiagram-3UESZ5HK-C8tANUtY.js} +1 -1
  46. package/dist/client/assets/{stateDiagram-AJRCARHV-CRKkkMY5.js → stateDiagram-AJRCARHV-BYeTtdTK.js} +1 -1
  47. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-f8Il8rBQ.js +1 -0
  48. package/dist/client/assets/{timeline-definition-PNZ67QCA-i5lwfxwF.js → timeline-definition-PNZ67QCA-CXj_kQwk.js} +1 -1
  49. package/dist/client/assets/{vennDiagram-CIIHVFJN-CAOpbfYt.js → vennDiagram-CIIHVFJN-LOxc4qfX.js} +1 -1
  50. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-PLngUKdt.js → wardleyDiagram-YWT4CUSO-CL9KwWu1.js} +1 -1
  51. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BZenFdgF.js → xychartDiagram-2RQKCTM6-TUtub4Ek.js} +1 -1
  52. package/dist/client/index.html +2 -2
  53. package/dist/server/db.js +56 -2
  54. package/dist/server/db.js.map +1 -1
  55. package/dist/server/index.js +123 -37
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/lib/agent.js +32 -10
  58. package/dist/server/lib/agent.js.map +1 -1
  59. package/dist/server/lib/buildSequences.js +16 -4
  60. package/dist/server/lib/buildSequences.js.map +1 -1
  61. package/dist/server/lib/integrations/assignedIssues.js +116 -0
  62. package/dist/server/lib/integrations/assignedIssues.js.map +1 -0
  63. package/dist/server/lib/integrations/assignedIssuesCache.js +81 -0
  64. package/dist/server/lib/integrations/assignedIssuesCache.js.map +1 -0
  65. package/dist/server/lib/integrations/github-issues.js +45 -7
  66. package/dist/server/lib/integrations/github-issues.js.map +1 -1
  67. package/dist/server/lib/integrations/github.js +26 -0
  68. package/dist/server/lib/integrations/github.js.map +1 -1
  69. package/dist/server/lib/integrations/jira.js +28 -1
  70. package/dist/server/lib/integrations/jira.js.map +1 -1
  71. package/dist/server/lib/planModeQuestions.js +1 -0
  72. package/dist/server/lib/planModeQuestions.js.map +1 -1
  73. package/dist/server/lib/projects.js +10 -0
  74. package/dist/server/lib/projects.js.map +1 -1
  75. package/dist/server/lib/reviewFindings.js +11 -0
  76. package/dist/server/lib/reviewFindings.js.map +1 -1
  77. package/dist/server/lib/specCoverageContext.js +50 -0
  78. package/dist/server/lib/specCoverageContext.js.map +1 -0
  79. package/dist/server/lib/specOperations.js +6 -2
  80. package/dist/server/lib/specOperations.js.map +1 -1
  81. package/dist/server/lib/ticketAutomation.js +5 -5
  82. package/dist/server/lib/ticketAutomation.js.map +1 -1
  83. package/dist/server/lib/ticketSettingsOperations.js +2 -35
  84. package/dist/server/lib/ticketSettingsOperations.js.map +1 -1
  85. package/dist/server/lib/tickets.js +21 -14
  86. package/dist/server/lib/tickets.js.map +1 -1
  87. package/dist/server/workers/build.js +6 -3
  88. package/dist/server/workers/build.js.map +1 -1
  89. package/dist/server/workers/chat.js +14 -10
  90. package/dist/server/workers/chat.js.map +1 -1
  91. package/dist/server/workers/followUp.js +6 -3
  92. package/dist/server/workers/followUp.js.map +1 -1
  93. package/dist/server/workers/plan.js +24 -7
  94. package/dist/server/workers/plan.js.map +1 -1
  95. package/dist/server/workers/review.js +134 -24
  96. package/dist/server/workers/review.js.map +1 -1
  97. package/dist/server/workers/specSession.js +27 -16
  98. package/dist/server/workers/specSession.js.map +1 -1
  99. package/package.json +1 -1
  100. package/dist/client/assets/channel-Bzb5_GUt.js +0 -1
  101. package/dist/client/assets/classDiagram-4FO5ZUOK-DHGZaJVi.js +0 -1
  102. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BN7x7YaI.js +0 -1
  103. package/dist/client/assets/index-D6fbF563.js +0 -260
  104. package/dist/client/assets/index-jWPkSR4C.css +0 -2
  105. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-B4u1psZz.js +0 -1
@@ -52,6 +52,7 @@ import { createGitHubPullRequest, createOrFindGitHubPullRequest, findOpenGitHubP
52
52
  import { importJiraIssue, JiraApiError, validateJiraConnection } from './lib/integrations/jira.js';
53
53
  import { importGitHubIssue } from './lib/integrations/github-issues.js';
54
54
  import { PlanningReferenceError, resolveExternalPlanningDescription } from './lib/integrations/planning.js';
55
+ import { refreshIfNeeded as refreshAssignedIssues } from './lib/integrations/assignedIssuesCache.js';
55
56
  import { buildCommitMessagePrompt, normalizeGeneratedCommitMessage } from './lib/commitMessage.js';
56
57
  import { BUNDLE_PULL_REQUEST_SYNC_TTL_MS, getBundlePullRequestRecord, hasOpenBundlePullRequest, serializeBundlePullRequest, shouldSyncBundlePullRequest, syncTrackedBundlePullRequestIfNeeded, upsertBundlePullRequest, upsertBundlePullRequestFromGitHub, } from './lib/bundlePullRequests.js';
57
58
  import { countInboundProjectLinks, getEffectiveProject, getProjectById, getProjectTicketStats, hasProjectRunIde, listProjects, replaceProjectLinks, serializeProject, updateProjectActiveTarget, validateProjectPayload, } from './lib/projects.js';
@@ -64,7 +65,7 @@ import { isTicketAgentSettingsPayload, updateTicketAgentSettings, } from './lib/
64
65
  import { resolveBundleReviewOwner, transitionBundleToReview } from './lib/bundleReviewOperations.js';
65
66
  import { getActiveBundleStageChangeHead, undoTicketStage } from './lib/ticketUndo.js';
66
67
  import { closeAllTerminalSessions, createProjectTerminalSession, createTerminalSessionForWorkspace, destroyTerminalSessionById, registerTerminalSocketHandlers, } from './lib/terminal.js';
67
- import { countBundleTickets, createTicketRecord, createBundle, deleteBundle, ensureProjectRootBundle, autoParkTicketIfStale, autoParkSettledBundleTicket, isBundleSettledForAutoPark, clearAutoParkDismissalIfNeeded, assignTicketDoneOrder, assignTicketLaneOrder, getBundle, getBundleByName, getBundleByBranch, getBundleRepresentativeTicketContext, isProjectRootBundle, getTicket, isBundledTicket, listTicketsInRunContext, listBundles, listBoardTicketEnrichment, listTickets, resolveTicketBranch, resolveTicketTool, } from './lib/tickets.js';
68
+ import { countBundleTickets, createTicketRecord, createBundle, deleteBundle, ensureProjectRootBundle, autoParkTicketIfStale, autoParkSettledBundleTicket, isBundleSettledForAutoPark, clearAutoParkDismissalIfNeeded, assignTicketDoneOrder, assignTicketLaneOrder, getBundle, getBundleByName, getBundleByBranch, getBundleRepresentativeTicketContext, isProjectRootBundle, getTicket, isBundledTicket, listTicketsInRunContext, listBundles, listBoardTicketEnrichment, listTickets, resolveTicketBranch, resolveTicketTool, updateBundleAutomationConfig, } from './lib/tickets.js';
68
69
  import { createTicketMessage, upsertTicketDescriptionMessage } from './lib/ticketMessages.js';
69
70
  import { HttpError } from './lib/httpError.js';
70
71
  import { parseIncomingExternalSource } from './lib/externalSource.js';
@@ -1039,6 +1040,7 @@ const serializeBundleRow = (projectId, bundle) => {
1039
1040
  pull_request: getGitHubConnectionConfig(projectId)
1040
1041
  ? serializeBundlePullRequest(getBundlePullRequestRecord(bundle.id, projectId))
1041
1042
  : null,
1043
+ automation_config: resolveAutomationConfig(bundle, project),
1042
1044
  };
1043
1045
  };
1044
1046
  const serializeGitHubPullRequestSummary = (pullRequest) => {
@@ -3168,6 +3170,57 @@ app.delete('/bundles/:id', (req, res) => {
3168
3170
  });
3169
3171
  res.status(204).end();
3170
3172
  });
3173
+ app.patch('/bundles/:id', (req, res) => {
3174
+ const result = getRequiredProject(req);
3175
+ if ('error' in result) {
3176
+ return res.status(400).json({ error: result.error });
3177
+ }
3178
+ const bundle = getBundle(req.params.id, result.project.id);
3179
+ if (!bundle) {
3180
+ return res.status(404).json({ error: 'Bundle not found' });
3181
+ }
3182
+ if (isProjectRootBundle(bundle)) {
3183
+ return res.status(409).json({ error: 'Project root bundle automation cannot be overridden' });
3184
+ }
3185
+ let automationDepth = bundle.automation_depth ?? null;
3186
+ if (hasOwn(req.body, 'automation_depth')) {
3187
+ const value = req.body.automation_depth;
3188
+ if (value == null || value === '') {
3189
+ automationDepth = null;
3190
+ }
3191
+ else if (isAutomationDepth(value)) {
3192
+ automationDepth = value;
3193
+ }
3194
+ else {
3195
+ return res.status(400).json({
3196
+ error: 'automation_depth must be one of: manual, auto_review, auto_commit, auto_push, auto_pr',
3197
+ });
3198
+ }
3199
+ }
3200
+ let automationReviewFixEnabled = bundle.automation_review_fix_enabled ?? null;
3201
+ if (hasOwn(req.body, 'automation_review_fix_enabled')) {
3202
+ const value = req.body.automation_review_fix_enabled;
3203
+ if (value == null) {
3204
+ automationReviewFixEnabled = null;
3205
+ }
3206
+ else if (typeof value === 'boolean') {
3207
+ automationReviewFixEnabled = value ? 1 : 0;
3208
+ }
3209
+ else {
3210
+ return res.status(400).json({ error: 'automation_review_fix_enabled must be a boolean' });
3211
+ }
3212
+ }
3213
+ const updated = updateBundleAutomationConfig({
3214
+ bundleId: bundle.id,
3215
+ projectId: result.project.id,
3216
+ automationDepth,
3217
+ automationReviewFixEnabled,
3218
+ });
3219
+ listBundleTickets(result.project.id, bundle.id).forEach(ticket => {
3220
+ io.emit('ticket:updated', ticket);
3221
+ });
3222
+ res.json(serializeBundleRow(result.project.id, updated));
3223
+ });
3171
3224
  app.post('/bundles/:id/build', (req, res) => {
3172
3225
  const result = getRequiredProject(req);
3173
3226
  if ('error' in result) {
@@ -3312,7 +3365,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
3312
3365
  if (!project) {
3313
3366
  return res.status(400).json({ error: 'Ticket project no longer exists' });
3314
3367
  }
3315
- const automationConfig = resolveAutomationConfig(owner, project);
3368
+ const automationConfig = resolveAutomationConfig(owner.bundle ?? null, project);
3316
3369
  if (owner.state === 'review' && owner.agent_status === 'running') {
3317
3370
  return res.status(409).json({ error: 'Review already running' });
3318
3371
  }
@@ -3714,6 +3767,67 @@ app.post('/integrations/github/resolve/issue', async (req, res) => {
3714
3767
  return res.status(500).json({ error: getErrorMessage(error) || 'Unable to import the GitHub issue.' });
3715
3768
  }
3716
3769
  });
3770
+ const ASSIGNED_ISSUES_CACHE_TTL_MS = 60 * 1000;
3771
+ app.get('/integrations/assigned', async (req, res) => {
3772
+ const result = getRequiredProject(req);
3773
+ if ('error' in result) {
3774
+ return res.status(400).json({ error: result.error });
3775
+ }
3776
+ const force = req.query.force === '1' || req.query.force === 'true';
3777
+ try {
3778
+ const entry = await refreshAssignedIssues(result.project.id, { force });
3779
+ const now = Date.now();
3780
+ const isFresh = entry.error === null && now - entry.fetchedAt < ASSIGNED_ISSUES_CACHE_TTL_MS;
3781
+ if (entry.error && entry.fetchedAt === 0) {
3782
+ return res.status(503).json({
3783
+ error: entry.error,
3784
+ retry_after_ms: ASSIGNED_ISSUES_CACHE_TTL_MS,
3785
+ });
3786
+ }
3787
+ return res.json({
3788
+ drafts: entry.summary.drafts,
3789
+ providers: entry.summary.counts,
3790
+ stale: !isFresh,
3791
+ error: entry.error,
3792
+ });
3793
+ }
3794
+ catch (error) {
3795
+ return res.status(503).json({
3796
+ error: getErrorMessage(error) || 'Unable to load assigned issues right now.',
3797
+ retry_after_ms: ASSIGNED_ISSUES_CACHE_TTL_MS,
3798
+ });
3799
+ }
3800
+ });
3801
+ app.get('/integrations/assigned/count', async (req, res) => {
3802
+ const result = getRequiredProject(req);
3803
+ if ('error' in result) {
3804
+ return res.status(400).json({ error: result.error });
3805
+ }
3806
+ const force = req.query.force === '1' || req.query.force === 'true';
3807
+ try {
3808
+ const entry = await refreshAssignedIssues(result.project.id, { force });
3809
+ const now = Date.now();
3810
+ const isFresh = entry.error === null && now - entry.fetchedAt < ASSIGNED_ISSUES_CACHE_TTL_MS;
3811
+ if (entry.error && entry.fetchedAt === 0) {
3812
+ return res.status(503).json({
3813
+ error: entry.error,
3814
+ retry_after_ms: ASSIGNED_ISSUES_CACHE_TTL_MS,
3815
+ });
3816
+ }
3817
+ return res.json({
3818
+ count: entry.summary.untrackedCount,
3819
+ providers: entry.summary.counts,
3820
+ stale: !isFresh,
3821
+ error: entry.error,
3822
+ });
3823
+ }
3824
+ catch (error) {
3825
+ return res.status(503).json({
3826
+ error: getErrorMessage(error) || 'Unable to load assigned issues right now.',
3827
+ retry_after_ms: ASSIGNED_ISSUES_CACHE_TTL_MS,
3828
+ });
3829
+ }
3830
+ });
3717
3831
  app.post('/plan', async (req, res) => {
3718
3832
  const { title, description, model, variant, project_id } = req.body;
3719
3833
  if (typeof title !== 'string' || !title.trim()) {
@@ -3860,7 +3974,7 @@ app.post('/projects', (req, res) => {
3860
3974
  return res.status(400).json({ error: validation.error });
3861
3975
  }
3862
3976
  const projectCount = Number(db.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count ?? 0);
3863
- const { name, repo_path, linked_project_ids, run_setup, run_services, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, auto_park_stale_tickets, memory_enabled, worktree_sync, automation_depth, automation_review_fix_enabled, automation_review_severity, automation_review_max_iterations, } = validation.values;
3977
+ const { name, repo_path, linked_project_ids, run_setup, run_services, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, auto_park_stale_tickets, memory_enabled, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_review_severity, automation_review_max_iterations, } = validation.values;
3864
3978
  if (!repo_path) {
3865
3979
  return res.status(400).json({ error: 'repo_path must be a non-empty string' });
3866
3980
  }
@@ -3891,13 +4005,14 @@ app.post('/projects', (req, res) => {
3891
4005
  auto_park_stale_tickets,
3892
4006
  memory_enabled,
3893
4007
  worktree_sync,
4008
+ spec_aware_code_review_enabled,
3894
4009
  automation_depth,
3895
4010
  automation_review_fix_enabled,
3896
4011
  automation_review_severity,
3897
4012
  automation_review_max_iterations
3898
4013
  )
3899
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3900
- `).run(id, name, normalizedRepoPath, run_setup, run_services, 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, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, worktree_sync ?? null, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
4014
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
4015
+ `).run(id, name, normalizedRepoPath, run_setup, run_services, 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, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, worktree_sync ?? null, spec_aware_code_review_enabled ?? 0, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
3901
4016
  replaceProjectLinks(id, linked_project_ids ?? []);
3902
4017
  ensureProjectRootBundle(id);
3903
4018
  if (projectCount === 0) {
@@ -4872,7 +4987,7 @@ app.patch('/projects/:id', (req, res) => {
4872
4987
  });
4873
4988
  }
4874
4989
  }
4875
- const { name, repo_path, linked_project_ids, run_setup, run_services, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, auto_park_stale_tickets, memory_enabled, worktree_sync, automation_depth, automation_review_fix_enabled, automation_review_severity, automation_review_max_iterations, } = validation.values;
4990
+ const { name, repo_path, linked_project_ids, run_setup, run_services, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, auto_park_stale_tickets, memory_enabled, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_review_severity, automation_review_max_iterations, } = validation.values;
4876
4991
  db.prepare(`
4877
4992
  UPDATE projects SET
4878
4993
  name = ?,
@@ -4890,13 +5005,14 @@ app.patch('/projects/:id', (req, res) => {
4890
5005
  auto_park_stale_tickets = ?,
4891
5006
  memory_enabled = ?,
4892
5007
  worktree_sync = ?,
5008
+ spec_aware_code_review_enabled = ?,
4893
5009
  automation_depth = ?,
4894
5010
  automation_review_fix_enabled = ?,
4895
5011
  automation_review_severity = ?,
4896
5012
  automation_review_max_iterations = ?,
4897
5013
  updated_at = CURRENT_TIMESTAMP
4898
5014
  WHERE id = ?
4899
- `).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, 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, '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, 'worktree_sync') ? worktree_sync : project.worktree_sync, 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_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);
5015
+ `).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, 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, '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, '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_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);
4900
5016
  if (hasOwn(validation.values, 'linked_project_ids')) {
4901
5017
  replaceProjectLinks(project.id, linked_project_ids ?? []);
4902
5018
  }
@@ -4945,34 +5061,6 @@ app.post('/tickets', (req, res) => {
4945
5061
  const bundleId = typeof req.body.worktree_bundle_id === 'string'
4946
5062
  ? req.body.worktree_bundle_id.trim()
4947
5063
  : '';
4948
- let automationDepth = null;
4949
- if (hasOwn(req.body, 'automation_depth')) {
4950
- const value = req.body.automation_depth;
4951
- if (value == null || value === '') {
4952
- automationDepth = null;
4953
- }
4954
- else if (isAutomationDepth(value)) {
4955
- automationDepth = value;
4956
- }
4957
- else {
4958
- return res.status(400).json({
4959
- error: 'automation_depth must be one of: manual, auto_review, auto_commit, auto_push, auto_pr',
4960
- });
4961
- }
4962
- }
4963
- let automationReviewFixEnabled = null;
4964
- if (hasOwn(req.body, 'automation_review_fix_enabled')) {
4965
- const value = req.body.automation_review_fix_enabled;
4966
- if (value == null) {
4967
- automationReviewFixEnabled = null;
4968
- }
4969
- else if (typeof value === 'boolean') {
4970
- automationReviewFixEnabled = value ? 1 : 0;
4971
- }
4972
- else {
4973
- return res.status(400).json({ error: 'automation_review_fix_enabled must be a boolean' });
4974
- }
4975
- }
4976
5064
  try {
4977
5065
  const externalSource = parseIncomingExternalSource(req.body.external_source);
4978
5066
  const resolvedBundleId = (() => {
@@ -4999,8 +5087,6 @@ app.post('/tickets', (req, res) => {
4999
5087
  projectId: project_id,
5000
5088
  worktreeBundleId: resolvedBundleId,
5001
5089
  externalSource,
5002
- automationDepth,
5003
- automationReviewFixEnabled,
5004
5090
  });
5005
5091
  io.emit('ticket:created', ticket);
5006
5092
  res.status(201).json(ticket);