@autocode-cli/autocode 0.0.22

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 (125) hide show
  1. package/README.md +172 -0
  2. package/bin/autocode +2 -0
  3. package/dist/cli/commands/comment.d.ts +9 -0
  4. package/dist/cli/commands/comment.d.ts.map +1 -0
  5. package/dist/cli/commands/comment.js +37 -0
  6. package/dist/cli/commands/comment.js.map +1 -0
  7. package/dist/cli/commands/init.d.ts +9 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/init.js +41 -0
  10. package/dist/cli/commands/init.js.map +1 -0
  11. package/dist/cli/commands/list.d.ts +9 -0
  12. package/dist/cli/commands/list.d.ts.map +1 -0
  13. package/dist/cli/commands/list.js +78 -0
  14. package/dist/cli/commands/list.js.map +1 -0
  15. package/dist/cli/commands/move.d.ts +9 -0
  16. package/dist/cli/commands/move.d.ts.map +1 -0
  17. package/dist/cli/commands/move.js +59 -0
  18. package/dist/cli/commands/move.js.map +1 -0
  19. package/dist/cli/commands/new.d.ts +9 -0
  20. package/dist/cli/commands/new.d.ts.map +1 -0
  21. package/dist/cli/commands/new.js +74 -0
  22. package/dist/cli/commands/new.js.map +1 -0
  23. package/dist/cli/commands/next.d.ts +9 -0
  24. package/dist/cli/commands/next.d.ts.map +1 -0
  25. package/dist/cli/commands/next.js +46 -0
  26. package/dist/cli/commands/next.js.map +1 -0
  27. package/dist/cli/commands/serve.d.ts +9 -0
  28. package/dist/cli/commands/serve.d.ts.map +1 -0
  29. package/dist/cli/commands/serve.js +55 -0
  30. package/dist/cli/commands/serve.js.map +1 -0
  31. package/dist/cli/commands/show.d.ts +9 -0
  32. package/dist/cli/commands/show.d.ts.map +1 -0
  33. package/dist/cli/commands/show.js +91 -0
  34. package/dist/cli/commands/show.js.map +1 -0
  35. package/dist/cli/parser.d.ts +13 -0
  36. package/dist/cli/parser.d.ts.map +1 -0
  37. package/dist/cli/parser.js +54 -0
  38. package/dist/cli/parser.js.map +1 -0
  39. package/dist/core/column.d.ts +53 -0
  40. package/dist/core/column.d.ts.map +1 -0
  41. package/dist/core/column.js +128 -0
  42. package/dist/core/column.js.map +1 -0
  43. package/dist/core/ticket.d.ts +50 -0
  44. package/dist/core/ticket.d.ts.map +1 -0
  45. package/dist/core/ticket.js +228 -0
  46. package/dist/core/ticket.js.map +1 -0
  47. package/dist/core/workflow.d.ts +66 -0
  48. package/dist/core/workflow.d.ts.map +1 -0
  49. package/dist/core/workflow.js +176 -0
  50. package/dist/core/workflow.js.map +1 -0
  51. package/dist/index.d.ts +8 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +9 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/server/api.d.ts +9 -0
  56. package/dist/server/api.d.ts.map +1 -0
  57. package/dist/server/api.js +313 -0
  58. package/dist/server/api.js.map +1 -0
  59. package/dist/server/dashboard.d.ts +8 -0
  60. package/dist/server/dashboard.d.ts.map +1 -0
  61. package/dist/server/dashboard.js +1865 -0
  62. package/dist/server/dashboard.js.map +1 -0
  63. package/dist/server/index.d.ts +8 -0
  64. package/dist/server/index.d.ts.map +1 -0
  65. package/dist/server/index.js +94 -0
  66. package/dist/server/index.js.map +1 -0
  67. package/dist/server/watcher.d.ts +13 -0
  68. package/dist/server/watcher.d.ts.map +1 -0
  69. package/dist/server/watcher.js +62 -0
  70. package/dist/server/watcher.js.map +1 -0
  71. package/dist/server/websocket.d.ts +26 -0
  72. package/dist/server/websocket.d.ts.map +1 -0
  73. package/dist/server/websocket.js +165 -0
  74. package/dist/server/websocket.js.map +1 -0
  75. package/dist/services/claude.d.ts +52 -0
  76. package/dist/services/claude.d.ts.map +1 -0
  77. package/dist/services/claude.js +304 -0
  78. package/dist/services/claude.js.map +1 -0
  79. package/dist/services/ticket-io.d.ts +76 -0
  80. package/dist/services/ticket-io.d.ts.map +1 -0
  81. package/dist/services/ticket-io.js +248 -0
  82. package/dist/services/ticket-io.js.map +1 -0
  83. package/dist/types/index.d.ts +79 -0
  84. package/dist/types/index.d.ts.map +1 -0
  85. package/dist/types/index.js +5 -0
  86. package/dist/types/index.js.map +1 -0
  87. package/dist/utils/config.d.ts +93 -0
  88. package/dist/utils/config.d.ts.map +1 -0
  89. package/dist/utils/config.js +96 -0
  90. package/dist/utils/config.js.map +1 -0
  91. package/dist/utils/fs.d.ts +60 -0
  92. package/dist/utils/fs.d.ts.map +1 -0
  93. package/dist/utils/fs.js +129 -0
  94. package/dist/utils/fs.js.map +1 -0
  95. package/dist/utils/logger.d.ts +23 -0
  96. package/dist/utils/logger.d.ts.map +1 -0
  97. package/dist/utils/logger.js +56 -0
  98. package/dist/utils/logger.js.map +1 -0
  99. package/package.json +57 -0
  100. package/templates/columns/00_backlog.en.md +31 -0
  101. package/templates/columns/00_backlog.fr.md +31 -0
  102. package/templates/columns/01_ready.en.md +30 -0
  103. package/templates/columns/01_ready.fr.md +30 -0
  104. package/templates/columns/02_in-progress.en.md +30 -0
  105. package/templates/columns/02_in-progress.fr.md +30 -0
  106. package/templates/columns/03_review-best-practices.en.md +31 -0
  107. package/templates/columns/03_review-best-practices.fr.md +31 -0
  108. package/templates/columns/04_review-no-duplication.en.md +30 -0
  109. package/templates/columns/04_review-no-duplication.fr.md +30 -0
  110. package/templates/columns/05_review-consistency.en.md +31 -0
  111. package/templates/columns/05_review-consistency.fr.md +31 -0
  112. package/templates/columns/06_review-security.en.md +32 -0
  113. package/templates/columns/06_review-security.fr.md +32 -0
  114. package/templates/columns/07_testing-playwright.en.md +30 -0
  115. package/templates/columns/07_testing-playwright.fr.md +30 -0
  116. package/templates/columns/08_testing-cypress.en.md +31 -0
  117. package/templates/columns/08_testing-cypress.fr.md +31 -0
  118. package/templates/columns/09_update-docs.en.md +29 -0
  119. package/templates/columns/09_update-docs.fr.md +29 -0
  120. package/templates/columns/10_deploy-staging.en.md +29 -0
  121. package/templates/columns/10_deploy-staging.fr.md +29 -0
  122. package/templates/columns/11_validate-staging.en.md +32 -0
  123. package/templates/columns/11_validate-staging.fr.md +32 -0
  124. package/templates/columns/12_done.en.md +23 -0
  125. package/templates/columns/12_done.fr.md +23 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Claude CLI integration service
3
+ */
4
+ import { spawn } from 'node:child_process';
5
+ import { appendFileSync, writeFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { readFileSafe, writeFileSafe } from '../utils/fs.js';
8
+ import { getConfig } from '../utils/config.js';
9
+ import { getTicket, addComment, nextTicket, findTicketDir } from '../core/ticket.js';
10
+ import { getColumnBySlug } from '../core/column.js';
11
+ import { broadcast } from '../server/websocket.js';
12
+ import { logger } from '../utils/logger.js';
13
+ /**
14
+ * Get the ACTION.md content for a column
15
+ */
16
+ export function getActionContent(columnSlug, lang = 'fr') {
17
+ const config = getConfig();
18
+ const actionFile = join(config.root, columnSlug, `ACTION.${lang}.md`);
19
+ return readFileSafe(actionFile);
20
+ }
21
+ /**
22
+ * Build prompt for Claude based on ticket and column
23
+ */
24
+ export function buildPrompt(ticket, actionContent) {
25
+ const prompt = `# Task: Process Ticket ${ticket.key}
26
+
27
+ ## Ticket Information
28
+
29
+ - **Key**: ${ticket.key}
30
+ - **Title**: ${ticket.title}
31
+ - **Priority**: ${ticket.priority}
32
+ - **Status**: ${ticket.status}
33
+ - **Labels**: ${ticket.labels.join(', ') || 'None'}
34
+
35
+ ## Description
36
+
37
+ ${ticket.description}
38
+
39
+ ## Acceptance Criteria
40
+
41
+ ${ticket.acceptance_criteria.map(c => `- ${c}`).join('\n')}
42
+
43
+ ## Column Instructions
44
+
45
+ ${actionContent}
46
+
47
+ ## Previous Comments
48
+
49
+ ${ticket.comments.length > 0
50
+ ? ticket.comments.map(c => `[${c.column}] ${c.text}`).join('\n\n')
51
+ : 'No previous comments.'}
52
+
53
+ ## Your Task
54
+
55
+ Follow the column instructions above to process this ticket.
56
+ Provide a detailed response of what was done.
57
+ If any issues were encountered, explain them clearly.
58
+ `;
59
+ return prompt;
60
+ }
61
+ /**
62
+ * Write prompt to file for Claude
63
+ */
64
+ export function writePromptFile(ticket, prompt) {
65
+ const config = getConfig();
66
+ const column = getColumnBySlug(ticket.column_slug);
67
+ if (!column) {
68
+ throw new Error(`Column not found: ${ticket.column_slug}`);
69
+ }
70
+ const promptFile = join(config.root, column.slug, `.claude_prompt_${ticket.key}.md`);
71
+ writeFileSafe(promptFile, prompt);
72
+ return promptFile;
73
+ }
74
+ /**
75
+ * Execute Claude CLI with a prompt (with live logging to file)
76
+ */
77
+ export async function executeClaudeCLI(promptFile, ticketKey) {
78
+ const config = getConfig();
79
+ const startTime = Date.now();
80
+ // Find ticket directory for log file
81
+ let logPath = null;
82
+ if (ticketKey) {
83
+ const ticketDir = findTicketDir(config.root, ticketKey);
84
+ if (ticketDir) {
85
+ logPath = join(ticketDir, 'claude-code.log');
86
+ // Reset log file
87
+ writeFileSync(logPath, `[${new Date().toISOString()}] Starting Claude processing...\n`);
88
+ }
89
+ broadcast({ type: 'claude_start', ticket: ticketKey });
90
+ }
91
+ // Read prompt file content for stdin
92
+ const promptContent = readFileSafe(promptFile) || '';
93
+ return new Promise((resolve) => {
94
+ const child = spawn('claude', [
95
+ '--output-format', 'stream-json',
96
+ '--verbose',
97
+ '--dangerously-skip-permissions',
98
+ ], {
99
+ cwd: process.cwd(),
100
+ timeout: config.claudeTimeout,
101
+ });
102
+ // Send prompt via stdin
103
+ child.stdin.write(promptContent);
104
+ child.stdin.end();
105
+ let stdout = '';
106
+ let stderr = '';
107
+ child.stdout.on('data', (data) => {
108
+ const lines = data.toString().split('\n').filter(Boolean);
109
+ for (const line of lines) {
110
+ try {
111
+ const event = JSON.parse(line);
112
+ // Show system init status
113
+ if (event.type === 'system' && event.subtype === 'init') {
114
+ const initMsg = `🚀 Claude initialized (${event.mcp_servers?.length || 0} MCP servers)\n`;
115
+ process.stdout.write(initMsg);
116
+ if (logPath) {
117
+ appendFileSync(logPath, initMsg);
118
+ }
119
+ }
120
+ // Extract text from assistant message (full response)
121
+ if (event.type === 'assistant' && event.message?.content) {
122
+ for (const block of event.message.content) {
123
+ if (block.type === 'text' && block.text) {
124
+ const text = block.text + '\n\n'; // Add line breaks between messages
125
+ stdout += text;
126
+ process.stdout.write(text);
127
+ if (logPath) {
128
+ appendFileSync(logPath, text);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ // Extract text from content deltas (streaming)
134
+ if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
135
+ const text = event.delta.text;
136
+ stdout += text;
137
+ process.stdout.write(text);
138
+ if (logPath) {
139
+ appendFileSync(logPath, text);
140
+ }
141
+ }
142
+ // Mark tool calls
143
+ if (event.type === 'content_block_start' && event.content_block?.type === 'tool_use') {
144
+ const toolName = event.content_block.name;
145
+ const marker = `\n🔧 [${toolName}]\n`;
146
+ stdout += marker;
147
+ process.stdout.write(marker);
148
+ if (logPath) {
149
+ appendFileSync(logPath, marker);
150
+ }
151
+ }
152
+ }
153
+ catch {
154
+ // Non-JSON line, ignore
155
+ }
156
+ }
157
+ // Notify dashboard to refresh (without data)
158
+ if (ticketKey) {
159
+ broadcast({ type: 'claude_stream', ticket: ticketKey });
160
+ }
161
+ });
162
+ child.stderr.on('data', (data) => {
163
+ const chunk = data.toString();
164
+ stderr += chunk;
165
+ // Write errors to log file
166
+ if (logPath) {
167
+ appendFileSync(logPath, `[ERROR] ${chunk}`);
168
+ }
169
+ if (ticketKey) {
170
+ broadcast({ type: 'claude_stream', ticket: ticketKey });
171
+ }
172
+ });
173
+ child.on('close', (code) => {
174
+ const duration = Date.now() - startTime;
175
+ // Write completion to log
176
+ if (logPath) {
177
+ const status = code === 0 ? 'SUCCESS' : 'FAILED';
178
+ appendFileSync(logPath, `\n[${new Date().toISOString()}] ${status} (${duration}ms)\n`);
179
+ }
180
+ if (ticketKey) {
181
+ broadcast({
182
+ type: 'claude_end',
183
+ ticket: ticketKey,
184
+ success: code === 0,
185
+ duration,
186
+ });
187
+ }
188
+ if (code === 0) {
189
+ resolve({
190
+ success: true,
191
+ output: stdout,
192
+ duration,
193
+ });
194
+ }
195
+ else {
196
+ resolve({
197
+ success: false,
198
+ error: stderr || `Claude exited with code ${code}`,
199
+ duration,
200
+ });
201
+ }
202
+ });
203
+ child.on('error', (error) => {
204
+ if (logPath) {
205
+ appendFileSync(logPath, `\n[${new Date().toISOString()}] ERROR: ${error.message}\n`);
206
+ }
207
+ if (ticketKey) {
208
+ broadcast({
209
+ type: 'claude_end',
210
+ ticket: ticketKey,
211
+ success: false,
212
+ error: error.message,
213
+ });
214
+ }
215
+ resolve({
216
+ success: false,
217
+ error: error.message,
218
+ duration: Date.now() - startTime,
219
+ });
220
+ });
221
+ });
222
+ }
223
+ /**
224
+ * Process a ticket with Claude
225
+ */
226
+ export async function processTicketWithClaude(key, options = {}) {
227
+ const config = getConfig();
228
+ // Get ticket
229
+ const ticket = getTicket(config.root, key);
230
+ if (!ticket) {
231
+ return { success: false, error: `Ticket '${key}' not found` };
232
+ }
233
+ // Get action content
234
+ const actionContent = getActionContent(ticket.column_slug, config.lang);
235
+ if (!actionContent) {
236
+ return { success: false, error: `No ACTION file for column '${ticket.column_slug}'` };
237
+ }
238
+ logger.info(`Processing ${key} with Claude...`);
239
+ // Build and write prompt
240
+ const prompt = buildPrompt(ticket, actionContent);
241
+ const promptFile = writePromptFile(ticket, prompt);
242
+ // Execute Claude (with streaming to dashboard)
243
+ const result = await executeClaudeCLI(promptFile, key);
244
+ if (!result.success) {
245
+ logger.error(`Claude failed: ${result.error}`);
246
+ return { success: false, error: result.error };
247
+ }
248
+ // Add Claude's response as a comment
249
+ const comment = result.output || 'No output from Claude';
250
+ const updatedTicket = addComment(config.root, key, comment);
251
+ if (!updatedTicket) {
252
+ return { success: false, error: 'Failed to add comment' };
253
+ }
254
+ logger.success(`Claude processed ${key} in ${result.duration}ms`);
255
+ // Auto-advance if requested
256
+ if (options.autoAdvance) {
257
+ const advanced = nextTicket(config.root, key);
258
+ if (advanced) {
259
+ logger.info(`Advanced ${key} to ${advanced.status}`);
260
+ return { success: true, ticket: advanced };
261
+ }
262
+ }
263
+ return { success: true, ticket: updatedTicket };
264
+ }
265
+ /**
266
+ * Process all actionable tickets with Claude
267
+ */
268
+ export async function processAllTickets(options = {}) {
269
+ const config = getConfig();
270
+ const { findActionableTicket } = await import('../core/ticket.js');
271
+ let processed = 0;
272
+ let errors = 0;
273
+ const limit = options.limit || Infinity;
274
+ while (processed + errors < limit) {
275
+ const ticket = findActionableTicket(config.root);
276
+ if (!ticket) {
277
+ logger.info('No more actionable tickets');
278
+ break;
279
+ }
280
+ const result = await processTicketWithClaude(ticket.key, options);
281
+ if (result.success) {
282
+ processed++;
283
+ }
284
+ else {
285
+ errors++;
286
+ logger.error(`Failed to process ${ticket.key}: ${result.error}`);
287
+ }
288
+ }
289
+ logger.info(`Processed: ${processed}, Errors: ${errors}`);
290
+ return { processed, errors };
291
+ }
292
+ /**
293
+ * Check if Claude CLI is available
294
+ */
295
+ export function isClaudeAvailable() {
296
+ try {
297
+ const result = spawn('claude', ['--version'], { stdio: 'pipe' });
298
+ return result.pid !== undefined;
299
+ }
300
+ catch {
301
+ return false;
302
+ }
303
+ }
304
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/services/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Ticket I/O Service - Multi-file ticket storage
3
+ *
4
+ * Structure:
5
+ * tickets/AC-000001__titre/
6
+ * ├── metadata.json # JSON metadata
7
+ * ├── description.md # Pure markdown description
8
+ * └── comments/
9
+ * ├── 001.md # YAML frontmatter + markdown
10
+ * └── 002.md
11
+ */
12
+ import type { Ticket, Comment, HistoryEntry, Priority, SemverType } from '../types/index.js';
13
+ /**
14
+ * Metadata stored in metadata.json (without status/column_slug - derived from path)
15
+ */
16
+ export interface TicketMetadata {
17
+ key: string;
18
+ title: string;
19
+ priority: Priority;
20
+ labels: string[];
21
+ acceptance_criteria: string[];
22
+ semver: SemverType;
23
+ history: HistoryEntry[];
24
+ created_at: string;
25
+ updated_at: string;
26
+ }
27
+ /**
28
+ * Parse metadata.json from ticket directory
29
+ */
30
+ export declare function parseMetadata(ticketDir: string): TicketMetadata | null;
31
+ /**
32
+ * Read description.md from ticket directory
33
+ */
34
+ export declare function readDescription(ticketDir: string): string;
35
+ /**
36
+ * Read all comments from comments/ directory
37
+ */
38
+ export declare function readComments(ticketDir: string): Comment[];
39
+ /**
40
+ * Extract column_slug from ticket directory path
41
+ * e.g., /path/autodoc/02_in-progress/tickets/AC-000001__titre -> 02_in-progress
42
+ */
43
+ export declare function extractColumnSlug(ticketDir: string): string;
44
+ /**
45
+ * Load a complete Ticket from a ticket directory
46
+ */
47
+ export declare function loadTicket(ticketDir: string): Ticket | null;
48
+ /**
49
+ * Write metadata.json to ticket directory
50
+ */
51
+ export declare function writeMetadata(ticketDir: string, metadata: TicketMetadata): void;
52
+ /**
53
+ * Write description.md to ticket directory
54
+ */
55
+ export declare function writeDescription(ticketDir: string, title: string, description: string): void;
56
+ /**
57
+ * Add a new comment file to comments/ directory
58
+ */
59
+ export declare function addCommentFile(ticketDir: string, text: string, column: string): void;
60
+ /**
61
+ * Update specific fields in metadata.json
62
+ */
63
+ export declare function updateMetadata(ticketDir: string, updates: Partial<TicketMetadata>): void;
64
+ /**
65
+ * Add a history entry to metadata.json
66
+ */
67
+ export declare function addHistoryEntry(ticketDir: string, action: HistoryEntry['action'], from: string | null, to: string): void;
68
+ /**
69
+ * Update description in description.md (preserving title and structure)
70
+ */
71
+ export declare function updateDescription(ticketDir: string, newDescription: string): void;
72
+ /**
73
+ * Create a new ticket with full structure
74
+ */
75
+ export declare function createTicketStructure(ticketDir: string, metadata: TicketMetadata, description: string): void;
76
+ //# sourceMappingURL=ticket-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-io.d.ts","sourceRoot":"","sources":["../../src/services/ticket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAUtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AA+BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAezD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK3D;AAWD;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B3D;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAI/E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAY5F;AAgBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAiBpF;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAWxF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,EAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,EAAE,EAAE,MAAM,GACT,IAAI,CAeN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CASjF;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,MAAM,GAClB,IAAI,CAMN"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Ticket I/O Service - Multi-file ticket storage
3
+ *
4
+ * Structure:
5
+ * tickets/AC-000001__titre/
6
+ * ├── metadata.json # JSON metadata
7
+ * ├── description.md # Pure markdown description
8
+ * └── comments/
9
+ * ├── 001.md # YAML frontmatter + markdown
10
+ * └── 002.md
11
+ */
12
+ import { join, dirname, basename } from 'node:path';
13
+ import { parse as parseYaml } from 'yaml';
14
+ import { readFileSafe, writeFileSafe, pathExists, ensureDir, listFiles, } from '../utils/fs.js';
15
+ // ============================================
16
+ // READING
17
+ // ============================================
18
+ /**
19
+ * Parse metadata.json from ticket directory
20
+ */
21
+ export function parseMetadata(ticketDir) {
22
+ const metadataPath = join(ticketDir, 'metadata.json');
23
+ const content = readFileSafe(metadataPath);
24
+ if (!content)
25
+ return null;
26
+ try {
27
+ return JSON.parse(content);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ /**
34
+ * Read description.md from ticket directory
35
+ */
36
+ export function readDescription(ticketDir) {
37
+ const descPath = join(ticketDir, 'description.md');
38
+ return readFileSafe(descPath) || '';
39
+ }
40
+ /**
41
+ * Parse a single comment file with YAML frontmatter
42
+ */
43
+ function parseCommentFile(filePath) {
44
+ const content = readFileSafe(filePath);
45
+ if (!content)
46
+ return null;
47
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
48
+ if (!match) {
49
+ // No frontmatter, treat as plain text
50
+ return {
51
+ text: content.trim(),
52
+ column: 'N/A',
53
+ created_at: new Date().toISOString(),
54
+ };
55
+ }
56
+ try {
57
+ const frontMatter = parseYaml(match[1]);
58
+ return {
59
+ text: match[2].trim(),
60
+ column: String(frontMatter.column || 'N/A'),
61
+ created_at: String(frontMatter.created_at || new Date().toISOString()),
62
+ };
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ /**
69
+ * Read all comments from comments/ directory
70
+ */
71
+ export function readComments(ticketDir) {
72
+ const commentsDir = join(ticketDir, 'comments');
73
+ if (!pathExists(commentsDir))
74
+ return [];
75
+ const files = listFiles(commentsDir)
76
+ .filter(f => f.endsWith('.md'))
77
+ .sort(); // 001.md, 002.md, etc.
78
+ const comments = [];
79
+ for (const file of files) {
80
+ const comment = parseCommentFile(join(commentsDir, file));
81
+ if (comment)
82
+ comments.push(comment);
83
+ }
84
+ return comments;
85
+ }
86
+ /**
87
+ * Extract column_slug from ticket directory path
88
+ * e.g., /path/autodoc/02_in-progress/tickets/AC-000001__titre -> 02_in-progress
89
+ */
90
+ export function extractColumnSlug(ticketDir) {
91
+ // ticketDir = .../column_slug/tickets/ticketName
92
+ const ticketsDir = dirname(ticketDir); // .../column_slug/tickets
93
+ const columnDir = dirname(ticketsDir); // .../column_slug
94
+ return basename(columnDir); // column_slug
95
+ }
96
+ /**
97
+ * Get column name from slug
98
+ */
99
+ function getColumnNameFromSlug(slug) {
100
+ // Remove prefix like "02_" and convert to title case
101
+ const name = slug.replace(/^\d{2}_/, '').replace(/-/g, ' ');
102
+ return name.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
103
+ }
104
+ /**
105
+ * Load a complete Ticket from a ticket directory
106
+ */
107
+ export function loadTicket(ticketDir) {
108
+ const metadata = parseMetadata(ticketDir);
109
+ if (!metadata)
110
+ return null;
111
+ const description = readDescription(ticketDir);
112
+ const comments = readComments(ticketDir);
113
+ const columnSlug = extractColumnSlug(ticketDir);
114
+ return {
115
+ key: metadata.key,
116
+ title: metadata.title,
117
+ status: getColumnNameFromSlug(columnSlug),
118
+ column_slug: columnSlug,
119
+ priority: metadata.priority,
120
+ labels: metadata.labels,
121
+ description,
122
+ acceptance_criteria: metadata.acceptance_criteria,
123
+ semver: metadata.semver,
124
+ assignee: null, // Deprecated
125
+ reporter: null, // Deprecated
126
+ comments,
127
+ history: metadata.history,
128
+ created_at: metadata.created_at,
129
+ updated_at: metadata.updated_at,
130
+ _path: ticketDir,
131
+ };
132
+ }
133
+ // ============================================
134
+ // WRITING
135
+ // ============================================
136
+ /**
137
+ * Write metadata.json to ticket directory
138
+ */
139
+ export function writeMetadata(ticketDir, metadata) {
140
+ const metadataPath = join(ticketDir, 'metadata.json');
141
+ ensureDir(ticketDir);
142
+ writeFileSafe(metadataPath, JSON.stringify(metadata, null, 2));
143
+ }
144
+ /**
145
+ * Write description.md to ticket directory
146
+ */
147
+ export function writeDescription(ticketDir, title, description) {
148
+ const descPath = join(ticketDir, 'description.md');
149
+ const content = `# ${title}
150
+
151
+ ## Context
152
+
153
+ ${description || '[Description]'}
154
+
155
+ ## Notes
156
+
157
+ `;
158
+ writeFileSafe(descPath, content);
159
+ }
160
+ /**
161
+ * Get next comment number
162
+ */
163
+ function getNextCommentNumber(ticketDir) {
164
+ const commentsDir = join(ticketDir, 'comments');
165
+ if (!pathExists(commentsDir))
166
+ return 1;
167
+ const files = listFiles(commentsDir).filter(f => f.endsWith('.md'));
168
+ if (files.length === 0)
169
+ return 1;
170
+ const numbers = files.map(f => parseInt(f.replace('.md', ''), 10)).filter(n => !isNaN(n));
171
+ return numbers.length > 0 ? Math.max(...numbers) + 1 : 1;
172
+ }
173
+ /**
174
+ * Add a new comment file to comments/ directory
175
+ */
176
+ export function addCommentFile(ticketDir, text, column) {
177
+ const commentsDir = join(ticketDir, 'comments');
178
+ ensureDir(commentsDir);
179
+ const num = getNextCommentNumber(ticketDir);
180
+ const fileName = String(num).padStart(3, '0') + '.md';
181
+ const filePath = join(commentsDir, fileName);
182
+ const content = `---
183
+ column: ${column}
184
+ created_at: ${new Date().toISOString()}
185
+ ---
186
+
187
+ ${text}
188
+ `;
189
+ writeFileSafe(filePath, content);
190
+ }
191
+ // ============================================
192
+ // UPDATING
193
+ // ============================================
194
+ /**
195
+ * Update specific fields in metadata.json
196
+ */
197
+ export function updateMetadata(ticketDir, updates) {
198
+ const metadata = parseMetadata(ticketDir);
199
+ if (!metadata)
200
+ return;
201
+ const updated = {
202
+ ...metadata,
203
+ ...updates,
204
+ updated_at: new Date().toISOString(),
205
+ };
206
+ writeMetadata(ticketDir, updated);
207
+ }
208
+ /**
209
+ * Add a history entry to metadata.json
210
+ */
211
+ export function addHistoryEntry(ticketDir, action, from, to) {
212
+ const metadata = parseMetadata(ticketDir);
213
+ if (!metadata)
214
+ return;
215
+ const newEntry = {
216
+ at: new Date().toISOString(),
217
+ action,
218
+ from,
219
+ to,
220
+ };
221
+ metadata.history.push(newEntry);
222
+ metadata.updated_at = new Date().toISOString();
223
+ writeMetadata(ticketDir, metadata);
224
+ }
225
+ /**
226
+ * Update description in description.md (preserving title and structure)
227
+ */
228
+ export function updateDescription(ticketDir, newDescription) {
229
+ const descPath = join(ticketDir, 'description.md');
230
+ const currentContent = readFileSafe(descPath) || '';
231
+ // Extract title from current content
232
+ const titleMatch = currentContent.match(/^# (.+)$/m);
233
+ const title = titleMatch ? titleMatch[1] : 'Untitled';
234
+ writeDescription(ticketDir, title, newDescription);
235
+ }
236
+ // ============================================
237
+ // CREATION
238
+ // ============================================
239
+ /**
240
+ * Create a new ticket with full structure
241
+ */
242
+ export function createTicketStructure(ticketDir, metadata, description) {
243
+ ensureDir(ticketDir);
244
+ ensureDir(join(ticketDir, 'comments'));
245
+ writeMetadata(ticketDir, metadata);
246
+ writeDescription(ticketDir, metadata.title, description);
247
+ }
248
+ //# sourceMappingURL=ticket-io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-io.js","sourceRoot":"","sources":["../../src/services/ticket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,IAAI,SAAS,EAA8B,MAAM,MAAM,CAAC;AACtE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,EACT,SAAS,GACV,MAAM,gBAAgB,CAAC;AAkBxB,+CAA+C;AAC/C,UAAU;AACV,+CAA+C;AAE/C;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACnD,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,sCAAsC;QACtC,OAAO;YACL,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;YACpB,MAAM,EAAE,KAAK;YACb,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAA4B,CAAC;QACnE,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YACrB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC;YAC3C,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SACvE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAC9B,IAAI,EAAE,CAAC,CAAC,uBAAuB;IAElC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1D,IAAI,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,iDAAiD;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAQ,0BAA0B;IACxE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAS,kBAAkB;IACjE,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAoB,cAAc;AAC/D,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,IAAY;IACzC,qDAAqD;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,MAAM,WAAW,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAEhD,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,MAAM,EAAE,qBAAqB,CAAC,UAAU,CAAC;QACzC,WAAW,EAAE,UAAU;QACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,WAAW;QACX,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB;QACjD,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,QAAQ,EAAE,IAAI,EAAG,aAAa;QAC9B,QAAQ,EAAE,IAAI,EAAG,aAAa;QAC9B,QAAQ;QACR,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,KAAK,EAAE,SAAS;KACjB,CAAC;AACJ,CAAC;AAED,+CAA+C;AAC/C,UAAU;AACV,+CAA+C;AAE/C;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,QAAwB;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,KAAa,EAAE,WAAmB;IACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,KAAK,KAAK;;;;EAI1B,WAAW,IAAI,eAAe;;;;CAI/B,CAAC;IACA,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,SAAiB;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,CAAC,CAAC;IAEvC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEjC,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,IAAY,EAAE,MAAc;IAC5E,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,SAAS,CAAC,WAAW,CAAC,CAAC;IAEvB,MAAM,GAAG,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAE7C,MAAM,OAAO,GAAG;UACR,MAAM;cACF,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;;;EAGpC,IAAI;CACL,CAAC;IAEA,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,+CAA+C;AAC/C,WAAW;AACX,+CAA+C;AAE/C;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,OAAgC;IAChF,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,MAAM,OAAO,GAAG;QACd,GAAG,QAAQ;QACX,GAAG,OAAO;QACV,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IAEF,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,MAA8B,EAC9B,IAAmB,EACnB,EAAU;IAEV,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,MAAM,QAAQ,GAAiB;QAC7B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,MAAM;QACN,IAAI;QACJ,EAAE;KACH,CAAC;IAEF,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,QAAQ,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE/C,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,cAAsB;IACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEpD,qCAAqC;IACrC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAEtD,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AAED,+CAA+C;AAC/C,WAAW;AACX,+CAA+C;AAE/C;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,QAAwB,EACxB,WAAmB;IAEnB,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAEvC,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACnC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC3D,CAAC"}