@autocode-cli/autocode 0.1.14 → 0.1.17

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 (211) hide show
  1. package/README.md +38 -38
  2. package/dist/cli/commands/comment.d.ts +1 -1
  3. package/dist/cli/commands/comment.js +11 -11
  4. package/dist/cli/commands/comment.js.map +1 -1
  5. package/dist/cli/commands/init.js +1 -1
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/commands/list.d.ts +1 -1
  8. package/dist/cli/commands/list.d.ts.map +1 -1
  9. package/dist/cli/commands/list.js +65 -22
  10. package/dist/cli/commands/list.js.map +1 -1
  11. package/dist/cli/commands/move.d.ts +1 -1
  12. package/dist/cli/commands/move.js +12 -12
  13. package/dist/cli/commands/move.js.map +1 -1
  14. package/dist/cli/commands/new.d.ts +1 -1
  15. package/dist/cli/commands/new.d.ts.map +1 -1
  16. package/dist/cli/commands/new.js +26 -13
  17. package/dist/cli/commands/new.js.map +1 -1
  18. package/dist/cli/commands/next.d.ts +1 -1
  19. package/dist/cli/commands/next.js +15 -15
  20. package/dist/cli/commands/next.js.map +1 -1
  21. package/dist/cli/commands/parent.d.ts +9 -0
  22. package/dist/cli/commands/parent.d.ts.map +1 -0
  23. package/dist/cli/commands/parent.js +94 -0
  24. package/dist/cli/commands/parent.js.map +1 -0
  25. package/dist/cli/commands/serve.js +8 -8
  26. package/dist/cli/commands/serve.js.map +1 -1
  27. package/dist/cli/commands/show.d.ts +1 -1
  28. package/dist/cli/commands/show.d.ts.map +1 -1
  29. package/dist/cli/commands/show.js +51 -31
  30. package/dist/cli/commands/show.js.map +1 -1
  31. package/dist/cli/commands/stats.js +2 -2
  32. package/dist/cli/commands/stats.js.map +1 -1
  33. package/dist/cli/commands/sync.js +3 -3
  34. package/dist/cli/commands/sync.js.map +1 -1
  35. package/dist/cli/parser.d.ts.map +1 -1
  36. package/dist/cli/parser.js +5 -3
  37. package/dist/cli/parser.js.map +1 -1
  38. package/dist/core/column.js +2 -2
  39. package/dist/core/column.js.map +1 -1
  40. package/dist/core/hierarchy.d.ts +97 -0
  41. package/dist/core/hierarchy.d.ts.map +1 -0
  42. package/dist/core/hierarchy.js +274 -0
  43. package/dist/core/hierarchy.js.map +1 -0
  44. package/dist/core/issue.d.ts +62 -0
  45. package/dist/core/issue.d.ts.map +1 -0
  46. package/dist/core/issue.js +247 -0
  47. package/dist/core/issue.js.map +1 -0
  48. package/dist/core/sync.d.ts +9 -9
  49. package/dist/core/sync.d.ts.map +1 -1
  50. package/dist/core/sync.js +61 -58
  51. package/dist/core/sync.js.map +1 -1
  52. package/dist/core/workflow.d.ts +22 -20
  53. package/dist/core/workflow.d.ts.map +1 -1
  54. package/dist/core/workflow.js +68 -51
  55. package/dist/core/workflow.js.map +1 -1
  56. package/dist/index.d.ts +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/server/api-autocomplete.test.d.ts +6 -0
  59. package/dist/server/api-autocomplete.test.d.ts.map +1 -0
  60. package/dist/server/api-autocomplete.test.js +249 -0
  61. package/dist/server/api-autocomplete.test.js.map +1 -0
  62. package/dist/server/api.d.ts.map +1 -1
  63. package/dist/server/api.js +216 -106
  64. package/dist/server/api.js.map +1 -1
  65. package/dist/server/dashboard/pages/column-prompt.d.ts +1 -1
  66. package/dist/server/dashboard/pages/column-prompt.d.ts.map +1 -1
  67. package/dist/server/dashboard/pages/column-prompt.js +11 -11
  68. package/dist/server/dashboard/pages/column-prompt.js.map +1 -1
  69. package/dist/server/dashboard/pages/column-terminal.d.ts +1 -1
  70. package/dist/server/dashboard/pages/column-terminal.d.ts.map +1 -1
  71. package/dist/server/dashboard/pages/column-terminal.js +14 -14
  72. package/dist/server/dashboard/pages/column-terminal.js.map +1 -1
  73. package/dist/server/dashboard/pages/index.d.ts +3 -1
  74. package/dist/server/dashboard/pages/index.d.ts.map +1 -1
  75. package/dist/server/dashboard/pages/index.js +3 -1
  76. package/dist/server/dashboard/pages/index.js.map +1 -1
  77. package/dist/server/dashboard/pages/issue-graph.d.ts +9 -0
  78. package/dist/server/dashboard/pages/issue-graph.d.ts.map +1 -0
  79. package/dist/server/dashboard/pages/issue-graph.js +581 -0
  80. package/dist/server/dashboard/pages/issue-graph.js.map +1 -0
  81. package/dist/server/dashboard/pages/issue-view.d.ts +8 -0
  82. package/dist/server/dashboard/pages/issue-view.d.ts.map +1 -0
  83. package/dist/server/dashboard/pages/{ticket-view.js → issue-view.js} +128 -128
  84. package/dist/server/dashboard/pages/issue-view.js.map +1 -0
  85. package/dist/server/dashboard/pages/main-dashboard.js +21 -21
  86. package/dist/server/dashboard/pages/main-dashboard.js.map +1 -1
  87. package/dist/server/dashboard/pages/new-issue.d.ts +8 -0
  88. package/dist/server/dashboard/pages/new-issue.d.ts.map +1 -0
  89. package/dist/server/dashboard/pages/new-issue.js +648 -0
  90. package/dist/server/dashboard/pages/new-issue.js.map +1 -0
  91. package/dist/server/dashboard/pages/new-issue.test.d.ts +6 -0
  92. package/dist/server/dashboard/pages/new-issue.test.d.ts.map +1 -0
  93. package/dist/server/dashboard/pages/new-issue.test.js +349 -0
  94. package/dist/server/dashboard/pages/new-issue.test.js.map +1 -0
  95. package/dist/server/dashboard/pages/pipeline-configurator.js +1 -1
  96. package/dist/server/dashboard/pages/shared.d.ts +2 -2
  97. package/dist/server/dashboard/pages/shared.d.ts.map +1 -1
  98. package/dist/server/dashboard/pages/shared.js +5 -5
  99. package/dist/server/dashboard/pages/shared.js.map +1 -1
  100. package/dist/server/dashboard/pages/stats-page.js +11 -11
  101. package/dist/server/dashboard/scripts/index.js +134 -134
  102. package/dist/server/dashboard/styles/board.d.ts +1 -1
  103. package/dist/server/dashboard/styles/board.js +10 -10
  104. package/dist/server/dashboard.d.ts +1 -1
  105. package/dist/server/dashboard.d.ts.map +1 -1
  106. package/dist/server/dashboard.js +1 -1
  107. package/dist/server/dashboard.js.map +1 -1
  108. package/dist/server/index.d.ts.map +1 -1
  109. package/dist/server/index.js +40 -24
  110. package/dist/server/index.js.map +1 -1
  111. package/dist/server/websocket.d.ts +6 -6
  112. package/dist/server/websocket.d.ts.map +1 -1
  113. package/dist/server/websocket.js +10 -10
  114. package/dist/server/websocket.js.map +1 -1
  115. package/dist/services/claude.d.ts +13 -13
  116. package/dist/services/claude.d.ts.map +1 -1
  117. package/dist/services/claude.js +98 -98
  118. package/dist/services/claude.js.map +1 -1
  119. package/dist/services/issue-io.d.ts +81 -0
  120. package/dist/services/issue-io.d.ts.map +1 -0
  121. package/dist/services/{ticket-io.js → issue-io.js} +54 -53
  122. package/dist/services/issue-io.js.map +1 -0
  123. package/dist/services/stats.d.ts +2 -0
  124. package/dist/services/stats.d.ts.map +1 -1
  125. package/dist/services/stats.js.map +1 -1
  126. package/dist/types/index.d.ts +6 -4
  127. package/dist/types/index.d.ts.map +1 -1
  128. package/dist/utils/fs.d.ts +2 -2
  129. package/dist/utils/fs.d.ts.map +1 -1
  130. package/dist/utils/fs.js +2 -2
  131. package/dist/utils/fs.js.map +1 -1
  132. package/package.json +3 -3
  133. package/templates/catalog.yaml +2 -2
  134. package/templates/prompts/api-endpoints-test.en.md +2 -2
  135. package/templates/prompts/api-endpoints-test.fr.md +2 -2
  136. package/templates/prompts/backlog.en.md +6 -6
  137. package/templates/prompts/backlog.fr.md +1 -1
  138. package/templates/prompts/changelog.en.md +6 -6
  139. package/templates/prompts/changelog.fr.md +3 -3
  140. package/templates/prompts/dashboard-responsive.en.md +1 -1
  141. package/templates/prompts/deploy-prod.en.md +3 -3
  142. package/templates/prompts/deploy-prod.fr.md +3 -3
  143. package/templates/prompts/deploy-staging.en.md +3 -3
  144. package/templates/prompts/deploy-staging.fr.md +3 -3
  145. package/templates/prompts/design.en.md +5 -5
  146. package/templates/prompts/design.fr.md +3 -3
  147. package/templates/prompts/dev.en.md +4 -4
  148. package/templates/prompts/dev.fr.md +3 -3
  149. package/templates/prompts/done.en.md +5 -5
  150. package/templates/prompts/done.fr.md +2 -2
  151. package/templates/prompts/error-handling-review.en.md +1 -1
  152. package/templates/prompts/error-handling-review.fr.md +1 -1
  153. package/templates/prompts/file-watcher-test.en.md +4 -4
  154. package/templates/prompts/file-watcher-test.fr.md +1 -1
  155. package/templates/prompts/git-commit.en.md +5 -5
  156. package/templates/prompts/git-commit.fr.md +3 -3
  157. package/templates/prompts/git-push.en.md +3 -3
  158. package/templates/prompts/git-push.fr.md +3 -3
  159. package/templates/prompts/git-tag.en.md +3 -3
  160. package/templates/prompts/git-tag.fr.md +3 -3
  161. package/templates/prompts/in-progress.en.md +6 -6
  162. package/templates/prompts/in-progress.fr.md +3 -3
  163. package/templates/prompts/qualification.en.md +8 -8
  164. package/templates/prompts/qualification.fr.md +3 -3
  165. package/templates/prompts/retest-cypress.en.md +3 -3
  166. package/templates/prompts/retest-cypress.fr.md +3 -3
  167. package/templates/prompts/retest-playwright.en.md +4 -4
  168. package/templates/prompts/retest-playwright.fr.md +3 -3
  169. package/templates/prompts/retest.en.md +4 -4
  170. package/templates/prompts/retest.fr.md +3 -3
  171. package/templates/prompts/review-best-practices.en.md +3 -3
  172. package/templates/prompts/review-best-practices.fr.md +3 -3
  173. package/templates/prompts/review-code.en.md +4 -4
  174. package/templates/prompts/review-code.fr.md +3 -3
  175. package/templates/prompts/review-consistency.en.md +3 -3
  176. package/templates/prompts/review-consistency.fr.md +3 -3
  177. package/templates/prompts/review-no-duplication.en.md +3 -3
  178. package/templates/prompts/review-no-duplication.fr.md +3 -3
  179. package/templates/prompts/review-security.en.md +4 -4
  180. package/templates/prompts/review-security.fr.md +3 -3
  181. package/templates/prompts/specification.en.md +5 -5
  182. package/templates/prompts/specification.fr.md +3 -3
  183. package/templates/prompts/splitter.en.md +13 -13
  184. package/templates/prompts/splitter.fr.md +3 -3
  185. package/templates/prompts/template-validation.en.md +1 -1
  186. package/templates/prompts/template-validation.fr.md +1 -1
  187. package/templates/prompts/testing-coverage.en.md +1 -1
  188. package/templates/prompts/testing-coverage.fr.md +1 -1
  189. package/templates/prompts/testing-cypress.en.md +4 -4
  190. package/templates/prompts/testing-cypress.fr.md +3 -3
  191. package/templates/prompts/testing-integration.en.md +4 -4
  192. package/templates/prompts/testing-integration.fr.md +3 -3
  193. package/templates/prompts/testing-playwright.en.md +4 -4
  194. package/templates/prompts/testing-playwright.fr.md +3 -3
  195. package/templates/prompts/testing-unit.en.md +4 -4
  196. package/templates/prompts/testing-unit.fr.md +3 -3
  197. package/templates/prompts/update-docs.en.md +3 -3
  198. package/templates/prompts/update-docs.fr.md +3 -3
  199. package/templates/prompts/validate-staging.en.md +3 -3
  200. package/templates/prompts/validate-staging.fr.md +3 -3
  201. package/templates/prompts/websocket-test.en.md +1 -1
  202. package/dist/core/ticket.d.ts +0 -50
  203. package/dist/core/ticket.d.ts.map +0 -1
  204. package/dist/core/ticket.js +0 -224
  205. package/dist/core/ticket.js.map +0 -1
  206. package/dist/server/dashboard/pages/ticket-view.d.ts +0 -8
  207. package/dist/server/dashboard/pages/ticket-view.d.ts.map +0 -1
  208. package/dist/server/dashboard/pages/ticket-view.js.map +0 -1
  209. package/dist/services/ticket-io.d.ts +0 -80
  210. package/dist/services/ticket-io.d.ts.map +0 -1
  211. package/dist/services/ticket-io.js.map +0 -1
@@ -3,19 +3,20 @@
3
3
  */
4
4
  import { join } from 'node:path';
5
5
  import { URL } from 'node:url';
6
- import { listTickets, getTicket, createTicket, updateTicket, addComment, findTicketDir, } from '../core/ticket.js';
6
+ import { listIssues, getIssue, createIssue, updateIssue, addComment, findIssueDir, } from '../core/issue.js';
7
+ import { getChildren, getSubtree, setParent, } from '../core/hierarchy.js';
7
8
  import { getColumns, getColumnBySlug } from '../core/column.js';
8
- import { moveAndProcessTicket, buildPrompt, getActionContent, executeClaudePrompt } from '../services/claude.js';
9
+ import { moveAndProcessIssue, buildPrompt, getActionContent, executeClaudePrompt } from '../services/claude.js';
9
10
  import { getStats } from '../services/stats.js';
10
11
  import { getWorkflowSummary } from '../core/workflow.js';
11
- import { getProcessingTickets } from './websocket.js';
12
+ import { getProcessingIssues } from './websocket.js';
12
13
  import { getConfig, getTemplatesDir } from '../utils/config.js';
13
14
  import { readFileSafe, writeFileSafe, pathExists, getFileMtime, ensureDir } from '../utils/fs.js';
14
- import { readAttachments } from '../services/ticket-io.js';
15
+ import { readAttachments } from '../services/issue-io.js';
15
16
  import { writeFileSync, unlinkSync, readdirSync } from 'node:fs';
16
17
  import { loadCatalog, getPromptContent } from '../core/catalog.js';
17
18
  import { pipelineExists, loadPipelinesConfig, getActivePipeline, setActivePipeline, createPipeline, deletePipeline, listPipelines, } from '../core/pipeline.js';
18
- import { previewSync, applySync, hasTransitionTickets, getTransitionTickets, resolveTransitionTickets, } from '../core/sync.js';
19
+ import { previewSync, applySync, hasTransitionIssues, getTransitionIssues, resolveTransitionIssues, } from '../core/sync.js';
19
20
  import { executeAutocreate, isClaudeAvailable } from '../services/autocreate.js';
20
21
  /**
21
22
  * Parse URL parameters from pattern
@@ -146,7 +147,7 @@ async function buildAnalysisPrompt(pipeline, catalog, lang) {
146
147
  * Define API routes
147
148
  */
148
149
  const routes = [
149
- // GET /api/status - Get server status including processing tickets
150
+ // GET /api/status - Get server status including processing issues
150
151
  {
151
152
  method: 'GET',
152
153
  pattern: /^\/api\/status$/,
@@ -154,7 +155,7 @@ const routes = [
154
155
  sendJson(res, {
155
156
  success: true,
156
157
  data: {
157
- processingTickets: getProcessingTickets()
158
+ processingIssues: getProcessingIssues()
158
159
  }
159
160
  });
160
161
  },
@@ -173,40 +174,140 @@ const routes = [
173
174
  totals: stats.totals,
174
175
  session: stats.session,
175
176
  history: stats.history.slice(0, 20), // Limit to last 20 calls in API
176
- processingTickets: getProcessingTickets()
177
+ processingIssues: getProcessingIssues()
177
178
  }
178
179
  });
179
180
  },
180
181
  },
181
- // GET /api/tickets
182
+ // GET /api/issues
182
183
  {
183
184
  method: 'GET',
184
- pattern: /^\/api\/tickets$/,
185
+ pattern: /^\/api\/issues$/,
185
186
  handler: async (_req, res) => {
186
187
  const config = getConfig();
187
- const tickets = listTickets(config.root);
188
+ const issues = listIssues(config.root);
188
189
  const columns = getColumns();
189
- sendJson(res, { success: true, data: { tickets, columns } });
190
+ sendJson(res, { success: true, data: { issues, columns } });
190
191
  },
191
192
  },
192
- // GET /api/tickets/:key
193
+ // GET /api/issues/:key
193
194
  {
194
195
  method: 'GET',
195
- pattern: /^\/api\/tickets\/(AC-\d{6})$/,
196
+ pattern: /^\/api\/issues\/(AC-\d{6})$/,
196
197
  handler: async (_req, res, params) => {
197
198
  const config = getConfig();
198
- const ticket = getTicket(config.root, params.p0);
199
- if (!ticket) {
200
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
199
+ const issue = getIssue(config.root, params.p0);
200
+ if (!issue) {
201
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
201
202
  return;
202
203
  }
203
- sendJson(res, { success: true, data: ticket });
204
+ sendJson(res, { success: true, data: issue });
204
205
  },
205
206
  },
206
- // POST /api/tickets
207
+ // GET /api/issues/:key/children - Get direct children
208
+ {
209
+ method: 'GET',
210
+ pattern: /^\/api\/issues\/(AC-\d{6})\/children$/,
211
+ handler: async (_req, res, params) => {
212
+ const config = getConfig();
213
+ const issue = getIssue(config.root, params.p0);
214
+ if (!issue) {
215
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
216
+ return;
217
+ }
218
+ const children = getChildren(config.root, params.p0);
219
+ sendJson(res, { success: true, data: children });
220
+ },
221
+ },
222
+ // GET /api/issues/:key/subtree - Get all descendants
223
+ {
224
+ method: 'GET',
225
+ pattern: /^\/api\/issues\/(AC-\d{6})\/subtree$/,
226
+ handler: async (_req, res, params) => {
227
+ const config = getConfig();
228
+ const issue = getIssue(config.root, params.p0);
229
+ if (!issue) {
230
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
231
+ return;
232
+ }
233
+ const subtree = getSubtree(config.root, params.p0);
234
+ sendJson(res, { success: true, data: subtree });
235
+ },
236
+ },
237
+ // PATCH /api/issues/:key/parent - Set parent
238
+ {
239
+ method: 'PATCH',
240
+ pattern: /^\/api\/issues\/(AC-\d{6})\/parent$/,
241
+ handler: async (req, res, params) => {
242
+ const body = await parseBody(req);
243
+ const config = getConfig();
244
+ const issue = getIssue(config.root, params.p0);
245
+ if (!issue) {
246
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
247
+ return;
248
+ }
249
+ const result = setParent(config.root, params.p0, body?.parent_key ?? null);
250
+ if (!result.success) {
251
+ sendJson(res, { success: false, error: result.error }, 400);
252
+ return;
253
+ }
254
+ const updated = getIssue(config.root, params.p0);
255
+ sendJson(res, { success: true, data: updated });
256
+ },
257
+ },
258
+ // POST /api/issues/autocomplete - Generate issue fields using Claude
207
259
  {
208
260
  method: 'POST',
209
- pattern: /^\/api\/tickets$/,
261
+ pattern: /^\/api\/issues\/autocomplete$/,
262
+ handler: async (req, res) => {
263
+ const body = await parseBody(req);
264
+ if (!body || !body.title || !body.title.trim()) {
265
+ sendJson(res, { success: false, error: 'Title is required' }, 400);
266
+ return;
267
+ }
268
+ const lang = body.lang || 'fr';
269
+ const title = body.title.trim();
270
+ try {
271
+ const prompt = `Tu es un assistant qui aide à créer des tickets de développement.
272
+ À partir du titre suivant, génère les champs du ticket en JSON.
273
+
274
+ Titre: "${title}"
275
+
276
+ Génère un JSON avec:
277
+ - description: Une description détaillée (2-4 phrases) en ${lang === 'fr' ? 'français' : 'anglais'}
278
+ - priority: P0, P1, P2, ou P3 (P2 par défaut pour la plupart des tâches)
279
+ - labels: Un tableau de labels parmi [bug, feature, enhancement, documentation, urgent, refactoring, security, performance, ui, api] (1-3 labels pertinents)
280
+ - acceptance_criteria: Un tableau de 2-5 critères d'acceptation en ${lang === 'fr' ? 'français' : 'anglais'}
281
+ - semver: "patch", "minor", ou "major" selon l'impact
282
+
283
+ Réponds UNIQUEMENT avec le JSON, sans formatage markdown ni explication.`;
284
+ const result = executeClaudePrompt(prompt, 60000);
285
+ if (!result.success) {
286
+ sendJson(res, { success: false, error: result.error || 'Claude failed' }, 500);
287
+ return;
288
+ }
289
+ // Parse the JSON response
290
+ const output = result.output?.trim() || '';
291
+ // Remove potential markdown code blocks
292
+ const jsonStr = output.replace(/^```json?\n?/, '').replace(/\n?```$/, '').trim();
293
+ try {
294
+ const data = JSON.parse(jsonStr);
295
+ sendJson(res, { success: true, data });
296
+ }
297
+ catch {
298
+ sendJson(res, { success: false, error: 'Failed to parse Claude response' }, 500);
299
+ }
300
+ }
301
+ catch (error) {
302
+ const message = error instanceof Error ? error.message : 'Autocomplete failed';
303
+ sendJson(res, { success: false, error: message }, 500);
304
+ }
305
+ },
306
+ },
307
+ // POST /api/issues (accepts parent_key for hierarchy)
308
+ {
309
+ method: 'POST',
310
+ pattern: /^\/api\/issues$/,
210
311
  handler: async (req, res) => {
211
312
  const body = await parseBody(req);
212
313
  if (!body || !body.title) {
@@ -214,14 +315,23 @@ const routes = [
214
315
  return;
215
316
  }
216
317
  const config = getConfig();
217
- const ticket = createTicket(config.root, body);
218
- sendJson(res, { success: true, data: ticket }, 201);
318
+ try {
319
+ const issue = createIssue(config.root, {
320
+ ...body,
321
+ parent_key: body.parent_key,
322
+ });
323
+ sendJson(res, { success: true, data: issue }, 201);
324
+ }
325
+ catch (error) {
326
+ const message = error instanceof Error ? error.message : 'Failed to create issue';
327
+ sendJson(res, { success: false, error: message }, 400);
328
+ }
219
329
  },
220
330
  },
221
- // PATCH /api/tickets/:key
331
+ // PATCH /api/issues/:key
222
332
  {
223
333
  method: 'PATCH',
224
- pattern: /^\/api\/tickets\/(AC-\d{6})$/,
334
+ pattern: /^\/api\/issues\/(AC-\d{6})$/,
225
335
  handler: async (req, res, params) => {
226
336
  const body = await parseBody(req);
227
337
  if (!body) {
@@ -229,18 +339,18 @@ const routes = [
229
339
  return;
230
340
  }
231
341
  const config = getConfig();
232
- const ticket = updateTicket(config.root, params.p0, body);
233
- if (!ticket) {
234
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
342
+ const issue = updateIssue(config.root, params.p0, body);
343
+ if (!issue) {
344
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
235
345
  return;
236
346
  }
237
- sendJson(res, { success: true, data: ticket });
347
+ sendJson(res, { success: true, data: issue });
238
348
  },
239
349
  },
240
- // POST /api/tickets/:key/comments
350
+ // POST /api/issues/:key/comments
241
351
  {
242
352
  method: 'POST',
243
- pattern: /^\/api\/tickets\/(AC-\d{6})\/comments$/,
353
+ pattern: /^\/api\/issues\/(AC-\d{6})\/comments$/,
244
354
  handler: async (req, res, params) => {
245
355
  const body = await parseBody(req);
246
356
  if (!body || !body.text) {
@@ -249,25 +359,25 @@ const routes = [
249
359
  }
250
360
  const config = getConfig();
251
361
  const source = body.source === 'claude' ? 'claude' : 'user';
252
- const ticket = addComment(config.root, params.p0, body.text, undefined, source);
253
- if (!ticket) {
254
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
362
+ const issue = addComment(config.root, params.p0, body.text, undefined, source);
363
+ if (!issue) {
364
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
255
365
  return;
256
366
  }
257
- sendJson(res, { success: true, data: ticket });
367
+ sendJson(res, { success: true, data: issue });
258
368
  },
259
369
  },
260
- // POST /api/tickets/:key/move
370
+ // POST /api/issues/:key/move
261
371
  {
262
372
  method: 'POST',
263
- pattern: /^\/api\/tickets\/(AC-\d{6})\/move$/,
373
+ pattern: /^\/api\/issues\/(AC-\d{6})\/move$/,
264
374
  handler: async (req, res, params) => {
265
375
  const body = await parseBody(req);
266
376
  if (!body || !body.column) {
267
377
  sendJson(res, { success: false, error: 'Column is required' }, 400);
268
378
  return;
269
379
  }
270
- const ticketKey = params.p0;
380
+ const issueKey = params.p0;
271
381
  // Get target column slug
272
382
  const targetColumn = getColumnBySlug(body.column);
273
383
  if (!targetColumn) {
@@ -275,7 +385,7 @@ const routes = [
275
385
  return;
276
386
  }
277
387
  // Use new unified flow: move first, then execute action
278
- const result = await moveAndProcessTicket(ticketKey, targetColumn.slug, {
388
+ const result = await moveAndProcessIssue(issueKey, targetColumn.slug, {
279
389
  force: body.force,
280
390
  lang: body.lang,
281
391
  });
@@ -285,26 +395,26 @@ const routes = [
285
395
  }
286
396
  sendJson(res, {
287
397
  success: true,
288
- data: result.ticket,
398
+ data: result.issue,
289
399
  actionExecuted: result.actionExecuted,
290
400
  });
291
401
  },
292
402
  },
293
- // POST /api/tickets/:key/next
403
+ // POST /api/issues/:key/next
294
404
  {
295
405
  method: 'POST',
296
- pattern: /^\/api\/tickets\/(AC-\d{6})\/next$/,
406
+ pattern: /^\/api\/issues\/(AC-\d{6})\/next$/,
297
407
  handler: async (req, res, params) => {
298
408
  const config = getConfig();
299
- const ticketKey = params.p0;
409
+ const issueKey = params.p0;
300
410
  const body = await parseBody(req);
301
- // Get current ticket to find next column
302
- const ticket = getTicket(config.root, ticketKey);
303
- if (!ticket) {
304
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
411
+ // Get current issue to find next column
412
+ const issue = getIssue(config.root, issueKey);
413
+ if (!issue) {
414
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
305
415
  return;
306
416
  }
307
- const currentColumn = getColumnBySlug(ticket.column_slug);
417
+ const currentColumn = getColumnBySlug(issue.column_slug);
308
418
  if (!currentColumn) {
309
419
  sendJson(res, { success: false, error: 'Current column not found' }, 400);
310
420
  return;
@@ -316,28 +426,28 @@ const routes = [
316
426
  return;
317
427
  }
318
428
  // Use new unified flow: move first, then execute action
319
- const result = await moveAndProcessTicket(ticketKey, nextColumn.slug, { lang: body?.lang });
429
+ const result = await moveAndProcessIssue(issueKey, nextColumn.slug, { lang: body?.lang });
320
430
  if (!result.success) {
321
431
  sendJson(res, { success: false, error: result.error }, 400);
322
432
  return;
323
433
  }
324
434
  sendJson(res, {
325
435
  success: true,
326
- data: result.ticket,
436
+ data: result.issue,
327
437
  actionExecuted: result.actionExecuted,
328
438
  });
329
439
  },
330
440
  },
331
- // POST /api/tickets/:key/archive
441
+ // POST /api/issues/:key/archive
332
442
  {
333
443
  method: 'POST',
334
- pattern: /^\/api\/tickets\/(AC-\d{6})\/archive$/,
444
+ pattern: /^\/api\/issues\/(AC-\d{6})\/archive$/,
335
445
  handler: async (req, res, params) => {
336
- const ticketKey = params.p0;
446
+ const issueKey = params.p0;
337
447
  const body = await parseBody(req);
338
448
  const columns = getColumns();
339
449
  const lastColumn = columns[columns.length - 1];
340
- const result = await moveAndProcessTicket(ticketKey, lastColumn.slug, {
450
+ const result = await moveAndProcessIssue(issueKey, lastColumn.slug, {
341
451
  force: true,
342
452
  lang: body?.lang,
343
453
  });
@@ -347,30 +457,30 @@ const routes = [
347
457
  }
348
458
  sendJson(res, {
349
459
  success: true,
350
- data: result.ticket,
460
+ data: result.issue,
351
461
  });
352
462
  },
353
463
  },
354
- // GET /api/tickets/:key/log
464
+ // GET /api/issues/:key/log
355
465
  // Returns all column logs concatenated (since logs are per-column: claude-{columnSlug}.log)
356
466
  {
357
467
  method: 'GET',
358
- pattern: /^\/api\/tickets\/(AC-\d{6})\/log$/,
468
+ pattern: /^\/api\/issues\/(AC-\d{6})\/log$/,
359
469
  handler: async (_req, res, params) => {
360
470
  const config = getConfig();
361
- const ticketDir = findTicketDir(config.root, params.p0);
362
- if (!ticketDir) {
363
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
471
+ const issueDir = findIssueDir(config.root, params.p0);
472
+ if (!issueDir) {
473
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
364
474
  return;
365
475
  }
366
476
  // Find all claude-*.log files and sort by modification time
367
477
  let logFiles = [];
368
478
  try {
369
- const files = readdirSync(ticketDir);
479
+ const files = readdirSync(issueDir);
370
480
  logFiles = files
371
481
  .filter(f => f.startsWith('claude-') && f.endsWith('.log'))
372
482
  .map(f => {
373
- const filePath = join(ticketDir, f);
483
+ const filePath = join(issueDir, f);
374
484
  const mtime = getFileMtime(filePath);
375
485
  return { path: filePath, mtime: mtime || new Date(0) };
376
486
  })
@@ -408,20 +518,20 @@ const routes = [
408
518
  });
409
519
  },
410
520
  },
411
- // GET /api/tickets/:key/log/:columnSlug
521
+ // GET /api/issues/:key/log/:columnSlug
412
522
  {
413
523
  method: 'GET',
414
- pattern: /^\/api\/tickets\/(AC-\d{6})\/log\/([^/]+)$/,
524
+ pattern: /^\/api\/issues\/(AC-\d{6})\/log\/([^/]+)$/,
415
525
  handler: async (_req, res, params) => {
416
526
  const config = getConfig();
417
- const ticketKey = params.p0;
527
+ const issueKey = params.p0;
418
528
  const columnSlug = params.p1;
419
- const ticketDir = findTicketDir(config.root, ticketKey);
420
- if (!ticketDir) {
421
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
529
+ const issueDir = findIssueDir(config.root, issueKey);
530
+ if (!issueDir) {
531
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
422
532
  return;
423
533
  }
424
- const logFile = join(ticketDir, `claude-${columnSlug}.log`);
534
+ const logFile = join(issueDir, `claude-${columnSlug}.log`);
425
535
  if (!pathExists(logFile)) {
426
536
  sendJson(res, {
427
537
  success: true,
@@ -436,17 +546,17 @@ const routes = [
436
546
  });
437
547
  },
438
548
  },
439
- // GET /api/tickets/:key/prompt/:columnSlug
549
+ // GET /api/issues/:key/prompt/:columnSlug
440
550
  {
441
551
  method: 'GET',
442
- pattern: /^\/api\/tickets\/(AC-\d{6})\/prompt\/([^/]+)$/,
552
+ pattern: /^\/api\/issues\/(AC-\d{6})\/prompt\/([^/]+)$/,
443
553
  handler: async (_req, res, params) => {
444
554
  const config = getConfig();
445
- const ticketKey = params.p0;
555
+ const issueKey = params.p0;
446
556
  const columnSlug = params.p1;
447
- const ticket = getTicket(config.root, ticketKey);
448
- if (!ticket) {
449
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
557
+ const issue = getIssue(config.root, issueKey);
558
+ if (!issue) {
559
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
450
560
  return;
451
561
  }
452
562
  const column = getColumnBySlug(columnSlug);
@@ -459,8 +569,8 @@ const routes = [
459
569
  sendJson(res, { success: false, error: 'No ACTION file for this column' }, 404);
460
570
  return;
461
571
  }
462
- const ticketDir = findTicketDir(config.root, ticketKey);
463
- const prompt = buildPrompt(ticket, actionContent, ticketDir || undefined, config.lang);
572
+ const issueDir = findIssueDir(config.root, issueKey);
573
+ const prompt = buildPrompt(issue, actionContent, issueDir || undefined, config.lang);
464
574
  sendJson(res, {
465
575
  success: true,
466
576
  data: {
@@ -471,33 +581,33 @@ const routes = [
471
581
  });
472
582
  },
473
583
  },
474
- // GET /api/tickets/:key/attachments
584
+ // GET /api/issues/:key/attachments
475
585
  {
476
586
  method: 'GET',
477
- pattern: /^\/api\/tickets\/(AC-\d{6})\/attachments$/,
587
+ pattern: /^\/api\/issues\/(AC-\d{6})\/attachments$/,
478
588
  handler: async (_req, res, params) => {
479
589
  const config = getConfig();
480
- const ticketDir = findTicketDir(config.root, params.p0);
481
- if (!ticketDir) {
482
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
590
+ const issueDir = findIssueDir(config.root, params.p0);
591
+ if (!issueDir) {
592
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
483
593
  return;
484
594
  }
485
- const attachments = readAttachments(ticketDir);
595
+ const attachments = readAttachments(issueDir);
486
596
  sendJson(res, { success: true, data: attachments });
487
597
  },
488
598
  },
489
- // POST /api/tickets/:key/attachments
599
+ // POST /api/issues/:key/attachments
490
600
  {
491
601
  method: 'POST',
492
- pattern: /^\/api\/tickets\/(AC-\d{6})\/attachments$/,
602
+ pattern: /^\/api\/issues\/(AC-\d{6})\/attachments$/,
493
603
  handler: async (req, res, params) => {
494
604
  const config = getConfig();
495
- const ticketDir = findTicketDir(config.root, params.p0);
496
- if (!ticketDir) {
497
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
605
+ const issueDir = findIssueDir(config.root, params.p0);
606
+ if (!issueDir) {
607
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
498
608
  return;
499
609
  }
500
- const attachmentsDir = join(ticketDir, 'attachments');
610
+ const attachmentsDir = join(issueDir, 'attachments');
501
611
  ensureDir(attachmentsDir);
502
612
  try {
503
613
  const files = await parseMultipartBody(req);
@@ -521,19 +631,19 @@ const routes = [
521
631
  }
522
632
  },
523
633
  },
524
- // DELETE /api/tickets/:key/attachments/:filename
634
+ // DELETE /api/issues/:key/attachments/:filename
525
635
  {
526
636
  method: 'DELETE',
527
- pattern: /^\/api\/tickets\/(AC-\d{6})\/attachments\/([^/]+)$/,
637
+ pattern: /^\/api\/issues\/(AC-\d{6})\/attachments\/([^/]+)$/,
528
638
  handler: async (_req, res, params) => {
529
639
  const config = getConfig();
530
- const ticketDir = findTicketDir(config.root, params.p0);
531
- if (!ticketDir) {
532
- sendJson(res, { success: false, error: 'Ticket not found' }, 404);
640
+ const issueDir = findIssueDir(config.root, params.p0);
641
+ if (!issueDir) {
642
+ sendJson(res, { success: false, error: 'Issue not found' }, 404);
533
643
  return;
534
644
  }
535
645
  const filename = decodeURIComponent(params.p1);
536
- const filePath = join(ticketDir, 'attachments', filename);
646
+ const filePath = join(issueDir, 'attachments', filename);
537
647
  if (!pathExists(filePath)) {
538
648
  sendJson(res, { success: false, error: 'File not found' }, 404);
539
649
  return;
@@ -637,8 +747,8 @@ const routes = [
637
747
  pattern: /^\/api\/summary$/,
638
748
  handler: async (_req, res) => {
639
749
  const config = getConfig();
640
- const tickets = listTickets(config.root);
641
- const summary = getWorkflowSummary(tickets);
750
+ const issues = listIssues(config.root);
751
+ const summary = getWorkflowSummary(issues);
642
752
  sendJson(res, { success: true, data: summary });
643
753
  },
644
754
  },
@@ -722,10 +832,10 @@ Generate EXACTLY this format for EACH language, nothing else:
722
832
  2. [action 2]
723
833
  ...
724
834
  8. If out of scope work detected: \`autocode new "<title>" "<description>" --priority P2 --labels "<labels>" --acceptance "<criteria>" --semver patch --column backlog\`
725
- 9. Document: \`autocode comment <ticket-key> "[summary]"\`
726
- 10. Advance: \`autocode next <ticket-key>\`
835
+ 9. Document: \`autocode comment <issue-key> "[summary]"\`
836
+ 10. Advance: \`autocode next <issue-key>\`
727
837
 
728
- > Or return: \`autocode move <ticket-key> <target-column-slug>\`
838
+ > Or return: \`autocode move <issue-key> <target-column-slug>\`
729
839
 
730
840
  ## Validation Criteria
731
841
 
@@ -1037,26 +1147,26 @@ IMPORTANT: Output ONLY the two prompts separated by ===EN=== and ===FR===, nothi
1037
1147
  sendJson(res, { success: true, data: result });
1038
1148
  },
1039
1149
  },
1040
- // GET /api/transition - Get tickets in transition
1150
+ // GET /api/transition - Get issues in transition
1041
1151
  {
1042
1152
  method: 'GET',
1043
1153
  pattern: /^\/api\/transition$/,
1044
1154
  handler: async (_req, res) => {
1045
1155
  const config = getConfig();
1046
- const tickets = getTransitionTickets(config.root);
1047
- sendJson(res, { success: true, data: tickets });
1156
+ const issues = getTransitionIssues(config.root);
1157
+ sendJson(res, { success: true, data: issues });
1048
1158
  },
1049
1159
  },
1050
- // GET /api/transition/has - Check if there are transition tickets
1160
+ // GET /api/transition/has - Check if there are transition issues
1051
1161
  {
1052
1162
  method: 'GET',
1053
1163
  pattern: /^\/api\/transition\/has$/,
1054
1164
  handler: async (_req, res) => {
1055
1165
  const config = getConfig();
1056
- sendJson(res, { success: true, data: { hasTransition: hasTransitionTickets(config.root) } });
1166
+ sendJson(res, { success: true, data: { hasTransition: hasTransitionIssues(config.root) } });
1057
1167
  },
1058
1168
  },
1059
- // POST /api/transition/resolve - Resolve transition tickets
1169
+ // POST /api/transition/resolve - Resolve transition issues
1060
1170
  {
1061
1171
  method: 'POST',
1062
1172
  pattern: /^\/api\/transition\/resolve$/,
@@ -1067,7 +1177,7 @@ IMPORTANT: Output ONLY the two prompts separated by ===EN=== and ===FR===, nothi
1067
1177
  return;
1068
1178
  }
1069
1179
  const config = getConfig();
1070
- const result = resolveTransitionTickets(config.root, body.actions);
1180
+ const result = resolveTransitionIssues(config.root, body.actions);
1071
1181
  sendJson(res, { success: true, data: result });
1072
1182
  },
1073
1183
  },