@compilr-dev/cli 0.4.0

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 (152) hide show
  1. package/README.md +110 -0
  2. package/dist/agent.d.ts +62 -0
  3. package/dist/agent.js +317 -0
  4. package/dist/agents/registry.d.ts +66 -0
  5. package/dist/agents/registry.js +238 -0
  6. package/dist/agents/types.d.ts +40 -0
  7. package/dist/agents/types.js +94 -0
  8. package/dist/commands/custom-registry.d.ts +69 -0
  9. package/dist/commands/custom-registry.js +246 -0
  10. package/dist/commands/index.d.ts +7 -0
  11. package/dist/commands/index.js +7 -0
  12. package/dist/commands/types.d.ts +31 -0
  13. package/dist/commands/types.js +26 -0
  14. package/dist/commands.d.ts +63 -0
  15. package/dist/commands.js +324 -0
  16. package/dist/db/index.d.ts +42 -0
  17. package/dist/db/index.js +146 -0
  18. package/dist/db/repositories/document-repository.d.ts +63 -0
  19. package/dist/db/repositories/document-repository.js +184 -0
  20. package/dist/db/repositories/index.d.ts +9 -0
  21. package/dist/db/repositories/index.js +6 -0
  22. package/dist/db/repositories/project-repository.d.ts +132 -0
  23. package/dist/db/repositories/project-repository.js +337 -0
  24. package/dist/db/repositories/work-item-repository.d.ts +115 -0
  25. package/dist/db/repositories/work-item-repository.js +389 -0
  26. package/dist/db/schema.d.ts +83 -0
  27. package/dist/db/schema.js +143 -0
  28. package/dist/debug.d.ts +8 -0
  29. package/dist/debug.js +48 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +348 -0
  32. package/dist/index.old.d.ts +7 -0
  33. package/dist/index.old.js +1014 -0
  34. package/dist/repl.d.ts +121 -0
  35. package/dist/repl.js +1878 -0
  36. package/dist/settings/index.d.ts +80 -0
  37. package/dist/settings/index.js +195 -0
  38. package/dist/shared-handlers.d.ts +63 -0
  39. package/dist/shared-handlers.js +57 -0
  40. package/dist/slash-autocomplete.d.ts +41 -0
  41. package/dist/slash-autocomplete.js +638 -0
  42. package/dist/state.d.ts +75 -0
  43. package/dist/state.js +130 -0
  44. package/dist/tabbed-menu.d.ts +11 -0
  45. package/dist/tabbed-menu.js +328 -0
  46. package/dist/templates/backlog-md.d.ts +7 -0
  47. package/dist/templates/backlog-md.js +94 -0
  48. package/dist/templates/claude-md.d.ts +7 -0
  49. package/dist/templates/claude-md.js +189 -0
  50. package/dist/templates/coding-standards.d.ts +7 -0
  51. package/dist/templates/coding-standards.js +299 -0
  52. package/dist/templates/compilr-md.d.ts +7 -0
  53. package/dist/templates/compilr-md.js +189 -0
  54. package/dist/templates/config-json.d.ts +38 -0
  55. package/dist/templates/config-json.js +39 -0
  56. package/dist/templates/gitignore.d.ts +7 -0
  57. package/dist/templates/gitignore.js +85 -0
  58. package/dist/templates/index.d.ts +19 -0
  59. package/dist/templates/index.js +302 -0
  60. package/dist/templates/package-json.d.ts +7 -0
  61. package/dist/templates/package-json.js +111 -0
  62. package/dist/templates/readme-md.d.ts +7 -0
  63. package/dist/templates/readme-md.js +161 -0
  64. package/dist/templates/tsconfig.d.ts +7 -0
  65. package/dist/templates/tsconfig.js +61 -0
  66. package/dist/templates/types.d.ts +33 -0
  67. package/dist/templates/types.js +24 -0
  68. package/dist/test-autocomplete.d.ts +7 -0
  69. package/dist/test-autocomplete.js +85 -0
  70. package/dist/test-tabbed-menu.d.ts +7 -0
  71. package/dist/test-tabbed-menu.js +25 -0
  72. package/dist/themes/colors.d.ts +49 -0
  73. package/dist/themes/colors.js +135 -0
  74. package/dist/themes/index.d.ts +23 -0
  75. package/dist/themes/index.js +24 -0
  76. package/dist/themes/registry.d.ts +60 -0
  77. package/dist/themes/registry.js +195 -0
  78. package/dist/themes/types.d.ts +82 -0
  79. package/dist/themes/types.js +7 -0
  80. package/dist/tool-selector.d.ts +71 -0
  81. package/dist/tool-selector.js +184 -0
  82. package/dist/tools/ask-user-simple.d.ts +19 -0
  83. package/dist/tools/ask-user-simple.js +86 -0
  84. package/dist/tools/ask-user.d.ts +32 -0
  85. package/dist/tools/ask-user.js +113 -0
  86. package/dist/tools/backlog.d.ts +53 -0
  87. package/dist/tools/backlog.js +709 -0
  88. package/dist/tools.d.ts +15 -0
  89. package/dist/tools.js +121 -0
  90. package/dist/ui/agents-overlay.d.ts +12 -0
  91. package/dist/ui/agents-overlay.js +501 -0
  92. package/dist/ui/arch-type-overlay.d.ts +20 -0
  93. package/dist/ui/arch-type-overlay.js +229 -0
  94. package/dist/ui/ask-user-overlay.d.ts +26 -0
  95. package/dist/ui/ask-user-overlay.js +647 -0
  96. package/dist/ui/ask-user-simple-overlay.d.ts +25 -0
  97. package/dist/ui/ask-user-simple-overlay.js +242 -0
  98. package/dist/ui/backlog-overlay.d.ts +17 -0
  99. package/dist/ui/backlog-overlay.js +786 -0
  100. package/dist/ui/commands-overlay.d.ts +11 -0
  101. package/dist/ui/commands-overlay.js +410 -0
  102. package/dist/ui/config-overlay.d.ts +34 -0
  103. package/dist/ui/config-overlay.js +977 -0
  104. package/dist/ui/conversation.d.ts +82 -0
  105. package/dist/ui/conversation.js +508 -0
  106. package/dist/ui/diff.d.ts +38 -0
  107. package/dist/ui/diff.js +182 -0
  108. package/dist/ui/ephemeral.d.ts +111 -0
  109. package/dist/ui/ephemeral.js +413 -0
  110. package/dist/ui/file-autocomplete.d.ts +45 -0
  111. package/dist/ui/file-autocomplete.js +237 -0
  112. package/dist/ui/footer.d.ts +153 -0
  113. package/dist/ui/footer.js +422 -0
  114. package/dist/ui/index.d.ts +12 -0
  115. package/dist/ui/index.js +15 -0
  116. package/dist/ui/init-overlay.d.ts +24 -0
  117. package/dist/ui/init-overlay.js +525 -0
  118. package/dist/ui/input-prompt-v2.d.ts +179 -0
  119. package/dist/ui/input-prompt-v2.js +991 -0
  120. package/dist/ui/input-prompt.d.ts +97 -0
  121. package/dist/ui/input-prompt.js +800 -0
  122. package/dist/ui/iteration-limit-overlay.d.ts +21 -0
  123. package/dist/ui/iteration-limit-overlay.js +150 -0
  124. package/dist/ui/keys-overlay.d.ts +14 -0
  125. package/dist/ui/keys-overlay.js +181 -0
  126. package/dist/ui/model-warning-overlay.d.ts +30 -0
  127. package/dist/ui/model-warning-overlay.js +171 -0
  128. package/dist/ui/overlay-controller.d.ts +25 -0
  129. package/dist/ui/overlay-controller.js +35 -0
  130. package/dist/ui/overlays.d.ts +47 -0
  131. package/dist/ui/overlays.js +627 -0
  132. package/dist/ui/permission-overlay.d.ts +16 -0
  133. package/dist/ui/permission-overlay.js +494 -0
  134. package/dist/ui/terminal.d.ts +117 -0
  135. package/dist/ui/terminal.js +237 -0
  136. package/dist/ui/todo-zone.d.ts +112 -0
  137. package/dist/ui/todo-zone.js +353 -0
  138. package/dist/ui/tools-overlay.d.ts +26 -0
  139. package/dist/ui/tools-overlay.js +278 -0
  140. package/dist/ui/tutorial-overlay.d.ts +10 -0
  141. package/dist/ui/tutorial-overlay.js +936 -0
  142. package/dist/ui/types.d.ts +103 -0
  143. package/dist/ui/types.js +33 -0
  144. package/dist/utils/credentials.d.ts +55 -0
  145. package/dist/utils/credentials.js +268 -0
  146. package/dist/utils/model-tiers.d.ts +37 -0
  147. package/dist/utils/model-tiers.js +118 -0
  148. package/dist/utils/project-memory.d.ts +47 -0
  149. package/dist/utils/project-memory.js +117 -0
  150. package/dist/utils/project-status.d.ts +56 -0
  151. package/dist/utils/project-status.js +237 -0
  152. package/package.json +66 -0
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Work Item Repository
3
+ *
4
+ * Handles all database operations for work items (backlog items, tasks, bugs).
5
+ */
6
+ import { getDb } from '../index.js';
7
+ /**
8
+ * Convert database record to WorkItem object
9
+ */
10
+ function recordToWorkItem(record) {
11
+ return {
12
+ id: record.id,
13
+ projectId: record.project_id,
14
+ itemNumber: record.item_number,
15
+ itemId: record.item_id,
16
+ type: record.type,
17
+ status: record.status,
18
+ priority: record.priority,
19
+ guidedStep: record.guided_step,
20
+ title: record.title,
21
+ description: record.description,
22
+ estimatedEffort: record.estimated_effort,
23
+ actualMinutes: record.actual_minutes,
24
+ completedAt: record.completed_at ? new Date(record.completed_at) : null,
25
+ completedBy: record.completed_by,
26
+ commitHash: record.commit_hash,
27
+ createdAt: new Date(record.created_at),
28
+ updatedAt: new Date(record.updated_at),
29
+ };
30
+ }
31
+ /**
32
+ * Get prefix for item ID based on type
33
+ */
34
+ function getTypePrefix(type) {
35
+ const prefixes = {
36
+ feature: 'REQ',
37
+ bug: 'BUG',
38
+ 'tech-debt': 'TEC',
39
+ chore: 'CHR',
40
+ };
41
+ return prefixes[type];
42
+ }
43
+ export const workItemRepository = {
44
+ /**
45
+ * Create a new work item
46
+ */
47
+ create(input) {
48
+ const db = getDb();
49
+ const now = new Date().toISOString();
50
+ // Get next item number for this project
51
+ const maxResult = db
52
+ .prepare('SELECT MAX(item_number) as max_num FROM work_items WHERE project_id = ?')
53
+ .get(input.project_id);
54
+ const itemNumber = (maxResult.max_num ?? 0) + 1;
55
+ const itemId = `${getTypePrefix(input.type)}-${String(itemNumber).padStart(3, '0')}`;
56
+ const result = db
57
+ .prepare(`
58
+ INSERT INTO work_items (
59
+ project_id, item_number, item_id, type, status, priority,
60
+ title, description, estimated_effort,
61
+ created_at, updated_at
62
+ ) VALUES (
63
+ @project_id, @item_number, @item_id, @type, @status, @priority,
64
+ @title, @description, @estimated_effort,
65
+ @created_at, @updated_at
66
+ )
67
+ `)
68
+ .run({
69
+ project_id: input.project_id,
70
+ item_number: itemNumber,
71
+ item_id: itemId,
72
+ type: input.type,
73
+ status: 'backlog',
74
+ priority: input.priority ?? 'medium',
75
+ title: input.title,
76
+ description: input.description ?? null,
77
+ estimated_effort: input.estimated_effort ?? null,
78
+ created_at: now,
79
+ updated_at: now,
80
+ });
81
+ const item = this.getById(Number(result.lastInsertRowid));
82
+ if (!item)
83
+ throw new Error('Failed to create work item');
84
+ return item;
85
+ },
86
+ /**
87
+ * Get work item by database ID
88
+ */
89
+ getById(id) {
90
+ const db = getDb();
91
+ const record = db
92
+ .prepare('SELECT * FROM work_items WHERE id = ?')
93
+ .get(id);
94
+ return record ? recordToWorkItem(record) : null;
95
+ },
96
+ /**
97
+ * Get work item by item_id (e.g., "REQ-001")
98
+ */
99
+ getByItemId(projectId, itemId) {
100
+ const db = getDb();
101
+ const record = db
102
+ .prepare('SELECT * FROM work_items WHERE project_id = ? AND item_id = ?')
103
+ .get(projectId, itemId);
104
+ return record ? recordToWorkItem(record) : null;
105
+ },
106
+ /**
107
+ * Query work items with filters
108
+ */
109
+ query(input) {
110
+ const db = getDb();
111
+ const conditions = [];
112
+ const params = {};
113
+ if (input.project_id) {
114
+ conditions.push('project_id = @project_id');
115
+ params.project_id = input.project_id;
116
+ }
117
+ if (input.status && input.status !== 'all') {
118
+ conditions.push('status = @status');
119
+ params.status = input.status;
120
+ }
121
+ if (input.type && input.type !== 'all') {
122
+ conditions.push('type = @type');
123
+ params.type = input.type;
124
+ }
125
+ if (input.priority && input.priority !== 'all') {
126
+ conditions.push('priority = @priority');
127
+ params.priority = input.priority;
128
+ }
129
+ if (input.search) {
130
+ conditions.push('(title LIKE @search OR description LIKE @search)');
131
+ params.search = `%${input.search}%`;
132
+ }
133
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
134
+ // Get total count
135
+ const countResult = db
136
+ .prepare(`SELECT COUNT(*) as count FROM work_items ${whereClause}`)
137
+ .get(params);
138
+ // Priority order: critical > high > medium > low
139
+ const priorityOrder = `
140
+ CASE priority
141
+ WHEN 'critical' THEN 1
142
+ WHEN 'high' THEN 2
143
+ WHEN 'medium' THEN 3
144
+ WHEN 'low' THEN 4
145
+ ELSE 5
146
+ END
147
+ `;
148
+ // Get items with pagination
149
+ let query = `
150
+ SELECT * FROM work_items ${whereClause}
151
+ ORDER BY
152
+ CASE status WHEN 'in_progress' THEN 0 ELSE 1 END,
153
+ ${priorityOrder},
154
+ created_at ASC
155
+ `;
156
+ const limit = input.limit ?? 50;
157
+ const offset = input.offset ?? 0;
158
+ query += ` LIMIT @limit OFFSET @offset`;
159
+ params.limit = limit;
160
+ params.offset = offset;
161
+ const records = db.prepare(query).all(params);
162
+ return {
163
+ items: records.map(recordToWorkItem),
164
+ total: countResult.count,
165
+ hasMore: offset + records.length < countResult.count,
166
+ };
167
+ },
168
+ /**
169
+ * Get next work item (highest priority backlog item)
170
+ */
171
+ getNext(projectId, type) {
172
+ const db = getDb();
173
+ const priorityOrder = `
174
+ CASE priority
175
+ WHEN 'critical' THEN 1
176
+ WHEN 'high' THEN 2
177
+ WHEN 'medium' THEN 3
178
+ WHEN 'low' THEN 4
179
+ ELSE 5
180
+ END
181
+ `;
182
+ let query = `
183
+ SELECT * FROM work_items
184
+ WHERE project_id = ? AND status = 'backlog'
185
+ `;
186
+ const params = [projectId];
187
+ if (type) {
188
+ query += ' AND type = ?';
189
+ params.push(type);
190
+ }
191
+ query += ` ORDER BY ${priorityOrder}, created_at ASC LIMIT 1`;
192
+ const record = db.prepare(query).get(...params);
193
+ return record ? recordToWorkItem(record) : null;
194
+ },
195
+ /**
196
+ * Update a work item
197
+ */
198
+ update(id, input) {
199
+ const db = getDb();
200
+ const updates = [];
201
+ const params = { id };
202
+ const oldItem = this.getById(id);
203
+ if (!oldItem)
204
+ return null;
205
+ if (input.type !== undefined) {
206
+ updates.push('type = @type');
207
+ params.type = input.type;
208
+ }
209
+ if (input.status !== undefined) {
210
+ updates.push('status = @status');
211
+ params.status = input.status;
212
+ // Handle status transitions
213
+ if (input.status === 'completed' && oldItem.status !== 'completed') {
214
+ updates.push('completed_at = @completed_at');
215
+ params.completed_at = new Date().toISOString();
216
+ }
217
+ if (input.status === 'in_progress' && oldItem.status === 'backlog') {
218
+ // Starting work - could track start time here
219
+ }
220
+ }
221
+ if (input.priority !== undefined) {
222
+ updates.push('priority = @priority');
223
+ params.priority = input.priority;
224
+ }
225
+ if (input.guided_step !== undefined) {
226
+ updates.push('guided_step = @guided_step');
227
+ params.guided_step = input.guided_step;
228
+ }
229
+ if (input.title !== undefined) {
230
+ updates.push('title = @title');
231
+ params.title = input.title;
232
+ }
233
+ if (input.description !== undefined) {
234
+ updates.push('description = @description');
235
+ params.description = input.description;
236
+ }
237
+ if (input.estimated_effort !== undefined) {
238
+ updates.push('estimated_effort = @estimated_effort');
239
+ params.estimated_effort = input.estimated_effort;
240
+ }
241
+ if (input.actual_minutes !== undefined) {
242
+ updates.push('actual_minutes = @actual_minutes');
243
+ params.actual_minutes = input.actual_minutes;
244
+ }
245
+ if (input.commit_hash !== undefined) {
246
+ updates.push('commit_hash = @commit_hash');
247
+ params.commit_hash = input.commit_hash;
248
+ }
249
+ if (updates.length === 0) {
250
+ return oldItem;
251
+ }
252
+ // Always update updated_at
253
+ updates.push('updated_at = @updated_at');
254
+ params.updated_at = new Date().toISOString();
255
+ const query = `UPDATE work_items SET ${updates.join(', ')} WHERE id = @id`;
256
+ db.prepare(query).run(params);
257
+ // Record history
258
+ this.recordHistory(id, oldItem.projectId, input, oldItem);
259
+ return this.getById(id);
260
+ },
261
+ /**
262
+ * Record change in history
263
+ */
264
+ recordHistory(workItemId, projectId, changes, oldItem) {
265
+ const db = getDb();
266
+ const now = new Date().toISOString();
267
+ // Record status changes
268
+ if (changes.status && changes.status !== oldItem.status) {
269
+ db.prepare(`
270
+ INSERT INTO work_item_history (work_item_id, project_id, action, old_value, new_value, changed_by, changed_at)
271
+ VALUES (?, ?, 'status_change', ?, ?, 'agent', ?)
272
+ `).run(workItemId, projectId, oldItem.status, changes.status, now);
273
+ }
274
+ // Record priority changes
275
+ if (changes.priority && changes.priority !== oldItem.priority) {
276
+ db.prepare(`
277
+ INSERT INTO work_item_history (work_item_id, project_id, action, old_value, new_value, changed_by, changed_at)
278
+ VALUES (?, ?, 'priority_change', ?, ?, 'agent', ?)
279
+ `).run(workItemId, projectId, oldItem.priority, changes.priority, now);
280
+ }
281
+ // Record guided step changes
282
+ if (changes.guided_step !== undefined && changes.guided_step !== oldItem.guidedStep) {
283
+ db.prepare(`
284
+ INSERT INTO work_item_history (work_item_id, project_id, action, old_value, new_value, changed_by, changed_at)
285
+ VALUES (?, ?, 'step_advance', ?, ?, 'agent', ?)
286
+ `).run(workItemId, projectId, oldItem.guidedStep ?? 'none', changes.guided_step ?? 'none', now);
287
+ }
288
+ },
289
+ /**
290
+ * Delete a work item
291
+ */
292
+ delete(id) {
293
+ const db = getDb();
294
+ const result = db.prepare('DELETE FROM work_items WHERE id = ?').run(id);
295
+ return result.changes > 0;
296
+ },
297
+ /**
298
+ * Get work item counts by status for a project
299
+ */
300
+ getStatusCounts(projectId) {
301
+ const db = getDb();
302
+ const results = db
303
+ .prepare(`
304
+ SELECT status, COUNT(*) as count
305
+ FROM work_items
306
+ WHERE project_id = ?
307
+ GROUP BY status
308
+ `)
309
+ .all(projectId);
310
+ const counts = {
311
+ backlog: 0,
312
+ in_progress: 0,
313
+ completed: 0,
314
+ skipped: 0,
315
+ };
316
+ for (const row of results) {
317
+ counts[row.status] = row.count;
318
+ }
319
+ return counts;
320
+ },
321
+ /**
322
+ * Get history for a work item
323
+ */
324
+ getHistory(workItemId) {
325
+ const db = getDb();
326
+ const records = db
327
+ .prepare(`
328
+ SELECT * FROM work_item_history
329
+ WHERE work_item_id = ?
330
+ ORDER BY changed_at DESC
331
+ `)
332
+ .all(workItemId);
333
+ return records.map((r) => ({
334
+ action: r.action,
335
+ oldValue: r.old_value,
336
+ newValue: r.new_value,
337
+ notes: r.notes,
338
+ changedBy: r.changed_by,
339
+ changedAt: new Date(r.changed_at),
340
+ }));
341
+ },
342
+ /**
343
+ * Bulk import work items (for /promote command)
344
+ */
345
+ bulkCreate(projectId, items) {
346
+ const db = getDb();
347
+ const now = new Date().toISOString();
348
+ const createdIds = [];
349
+ // Get starting item number
350
+ const maxResult = db
351
+ .prepare('SELECT MAX(item_number) as max_num FROM work_items WHERE project_id = ?')
352
+ .get(projectId);
353
+ let itemNumber = (maxResult.max_num ?? 0) + 1;
354
+ const insertStmt = db.prepare(`
355
+ INSERT INTO work_items (
356
+ project_id, item_number, item_id, type, status, priority,
357
+ title, description, created_at, updated_at
358
+ ) VALUES (
359
+ @project_id, @item_number, @item_id, @type, @status, @priority,
360
+ @title, @description, @created_at, @updated_at
361
+ )
362
+ `);
363
+ // Use transaction for atomicity
364
+ const insertAll = db.transaction(() => {
365
+ for (const item of items) {
366
+ const itemId = `${getTypePrefix(item.type)}-${String(itemNumber).padStart(3, '0')}`;
367
+ const result = insertStmt.run({
368
+ project_id: projectId,
369
+ item_number: itemNumber,
370
+ item_id: itemId,
371
+ type: item.type,
372
+ status: 'backlog',
373
+ priority: item.priority ?? 'medium',
374
+ title: item.title,
375
+ description: item.description ?? null,
376
+ created_at: now,
377
+ updated_at: now,
378
+ });
379
+ createdIds.push(Number(result.lastInsertRowid));
380
+ itemNumber++;
381
+ }
382
+ });
383
+ insertAll();
384
+ // Fetch all created items
385
+ return createdIds
386
+ .map((id) => this.getById(id))
387
+ .filter((item) => item !== null);
388
+ },
389
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Database Schema for compilr-cli workflow system
3
+ *
4
+ * Based on: db-workflow-architecture.md
5
+ * Database: SQLite via better-sqlite3
6
+ */
7
+ export declare const SCHEMA_VERSION = 1;
8
+ export declare const SCHEMA_SQL = "\n-- Schema version tracking\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at DATETIME DEFAULT CURRENT_TIMESTAMP\n);\n\n-- Projects table\nCREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n display_name TEXT NOT NULL,\n description TEXT,\n\n -- Project type and status\n type TEXT DEFAULT 'general',\n status TEXT DEFAULT 'active',\n\n -- Paths\n path TEXT NOT NULL,\n docs_path TEXT,\n repo_pattern TEXT DEFAULT 'single',\n\n -- Tech stack (auto-detected)\n language TEXT,\n framework TEXT,\n package_manager TEXT,\n runtime_version TEXT,\n\n -- Commands (JSON)\n commands TEXT,\n\n -- Git info\n git_remote TEXT,\n git_branch TEXT DEFAULT 'main',\n\n -- Workflow\n workflow_mode TEXT DEFAULT 'flexible',\n lifecycle_state TEXT DEFAULT 'setup',\n current_item_id TEXT,\n\n -- Context & Metadata (JSON)\n last_context TEXT,\n metadata TEXT,\n\n -- Timestamps\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n last_activity_at DATETIME\n);\n\n-- Work items (backlog items, tasks, bugs)\nCREATE TABLE IF NOT EXISTS work_items (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n\n -- Identity\n item_number INTEGER NOT NULL,\n item_id TEXT NOT NULL,\n\n -- Classification\n type TEXT NOT NULL,\n status TEXT DEFAULT 'backlog',\n priority TEXT DEFAULT 'medium',\n\n -- Guided mode: current step in work item cycle\n guided_step TEXT,\n\n -- Content\n title TEXT NOT NULL,\n description TEXT,\n\n -- Effort tracking\n estimated_effort TEXT,\n actual_minutes INTEGER,\n\n -- Completion\n completed_at DATETIME,\n completed_by TEXT,\n commit_hash TEXT,\n\n -- Timestamps\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,\n UNIQUE (project_id, item_id)\n);\n\n-- Project documents (PRD, architecture, etc.)\nCREATE TABLE IF NOT EXISTS project_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n\n doc_type TEXT NOT NULL,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\n\n-- Work item history (audit trail)\nCREATE TABLE IF NOT EXISTS work_item_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n work_item_id INTEGER NOT NULL,\n project_id INTEGER NOT NULL,\n\n action TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT,\n notes TEXT,\n\n changed_by TEXT,\n changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n\n FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n);\n\n-- Indexes for common queries\nCREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);\nCREATE INDEX IF NOT EXISTS idx_projects_docs_path ON projects(docs_path);\nCREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);\n\nCREATE INDEX IF NOT EXISTS idx_work_items_project ON work_items(project_id);\nCREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status);\nCREATE INDEX IF NOT EXISTS idx_work_items_priority ON work_items(priority);\n\nCREATE INDEX IF NOT EXISTS idx_project_documents_project ON project_documents(project_id);\nCREATE INDEX IF NOT EXISTS idx_project_documents_type ON project_documents(doc_type);\n\nCREATE INDEX IF NOT EXISTS idx_work_item_history_item ON work_item_history(work_item_id);\n";
9
+ export interface ProjectRecord {
10
+ id: number;
11
+ name: string;
12
+ display_name: string;
13
+ description: string | null;
14
+ type: string;
15
+ status: string;
16
+ path: string;
17
+ docs_path: string | null;
18
+ repo_pattern: string;
19
+ language: string | null;
20
+ framework: string | null;
21
+ package_manager: string | null;
22
+ runtime_version: string | null;
23
+ commands: string | null;
24
+ git_remote: string | null;
25
+ git_branch: string;
26
+ workflow_mode: string;
27
+ lifecycle_state: string;
28
+ current_item_id: string | null;
29
+ last_context: string | null;
30
+ metadata: string | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ last_activity_at: string | null;
34
+ }
35
+ export interface WorkItemRecord {
36
+ id: number;
37
+ project_id: number;
38
+ item_number: number;
39
+ item_id: string;
40
+ type: string;
41
+ status: string;
42
+ priority: string;
43
+ guided_step: string | null;
44
+ title: string;
45
+ description: string | null;
46
+ estimated_effort: string | null;
47
+ actual_minutes: number | null;
48
+ completed_at: string | null;
49
+ completed_by: string | null;
50
+ commit_hash: string | null;
51
+ created_at: string;
52
+ updated_at: string;
53
+ }
54
+ export interface ProjectDocumentRecord {
55
+ id: number;
56
+ project_id: number;
57
+ doc_type: string;
58
+ title: string;
59
+ content: string;
60
+ created_at: string;
61
+ updated_at: string;
62
+ }
63
+ export interface WorkItemHistoryRecord {
64
+ id: number;
65
+ work_item_id: number;
66
+ project_id: number;
67
+ action: string;
68
+ old_value: string | null;
69
+ new_value: string | null;
70
+ notes: string | null;
71
+ changed_by: string | null;
72
+ changed_at: string;
73
+ }
74
+ export type ProjectType = 'general' | 'web' | 'cli' | 'library' | 'api';
75
+ export type ProjectStatus = 'active' | 'paused' | 'completed' | 'archived';
76
+ export type RepoPattern = 'single' | 'two-repo';
77
+ export type WorkflowMode = 'flexible' | 'guided';
78
+ export type LifecycleState = 'setup' | 'active' | 'maintenance' | 'complete';
79
+ export type WorkItemType = 'feature' | 'bug' | 'tech-debt' | 'chore';
80
+ export type WorkItemStatus = 'backlog' | 'in_progress' | 'completed' | 'skipped';
81
+ export type WorkItemPriority = 'critical' | 'high' | 'medium' | 'low';
82
+ export type GuidedStep = 'plan' | 'implement' | 'test' | 'commit' | 'review';
83
+ export type DocumentType = 'prd' | 'architecture' | 'design' | 'notes';
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Database Schema for compilr-cli workflow system
3
+ *
4
+ * Based on: db-workflow-architecture.md
5
+ * Database: SQLite via better-sqlite3
6
+ */
7
+ export const SCHEMA_VERSION = 1;
8
+ export const SCHEMA_SQL = `
9
+ -- Schema version tracking
10
+ CREATE TABLE IF NOT EXISTS schema_version (
11
+ version INTEGER PRIMARY KEY,
12
+ applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
13
+ );
14
+
15
+ -- Projects table
16
+ CREATE TABLE IF NOT EXISTS projects (
17
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
18
+ name TEXT UNIQUE NOT NULL,
19
+ display_name TEXT NOT NULL,
20
+ description TEXT,
21
+
22
+ -- Project type and status
23
+ type TEXT DEFAULT 'general',
24
+ status TEXT DEFAULT 'active',
25
+
26
+ -- Paths
27
+ path TEXT NOT NULL,
28
+ docs_path TEXT,
29
+ repo_pattern TEXT DEFAULT 'single',
30
+
31
+ -- Tech stack (auto-detected)
32
+ language TEXT,
33
+ framework TEXT,
34
+ package_manager TEXT,
35
+ runtime_version TEXT,
36
+
37
+ -- Commands (JSON)
38
+ commands TEXT,
39
+
40
+ -- Git info
41
+ git_remote TEXT,
42
+ git_branch TEXT DEFAULT 'main',
43
+
44
+ -- Workflow
45
+ workflow_mode TEXT DEFAULT 'flexible',
46
+ lifecycle_state TEXT DEFAULT 'setup',
47
+ current_item_id TEXT,
48
+
49
+ -- Context & Metadata (JSON)
50
+ last_context TEXT,
51
+ metadata TEXT,
52
+
53
+ -- Timestamps
54
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
55
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
56
+ last_activity_at DATETIME
57
+ );
58
+
59
+ -- Work items (backlog items, tasks, bugs)
60
+ CREATE TABLE IF NOT EXISTS work_items (
61
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
62
+ project_id INTEGER NOT NULL,
63
+
64
+ -- Identity
65
+ item_number INTEGER NOT NULL,
66
+ item_id TEXT NOT NULL,
67
+
68
+ -- Classification
69
+ type TEXT NOT NULL,
70
+ status TEXT DEFAULT 'backlog',
71
+ priority TEXT DEFAULT 'medium',
72
+
73
+ -- Guided mode: current step in work item cycle
74
+ guided_step TEXT,
75
+
76
+ -- Content
77
+ title TEXT NOT NULL,
78
+ description TEXT,
79
+
80
+ -- Effort tracking
81
+ estimated_effort TEXT,
82
+ actual_minutes INTEGER,
83
+
84
+ -- Completion
85
+ completed_at DATETIME,
86
+ completed_by TEXT,
87
+ commit_hash TEXT,
88
+
89
+ -- Timestamps
90
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
91
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
92
+
93
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
94
+ UNIQUE (project_id, item_id)
95
+ );
96
+
97
+ -- Project documents (PRD, architecture, etc.)
98
+ CREATE TABLE IF NOT EXISTS project_documents (
99
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
100
+ project_id INTEGER NOT NULL,
101
+
102
+ doc_type TEXT NOT NULL,
103
+ title TEXT NOT NULL,
104
+ content TEXT NOT NULL,
105
+
106
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
107
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
108
+
109
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
110
+ );
111
+
112
+ -- Work item history (audit trail)
113
+ CREATE TABLE IF NOT EXISTS work_item_history (
114
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
115
+ work_item_id INTEGER NOT NULL,
116
+ project_id INTEGER NOT NULL,
117
+
118
+ action TEXT NOT NULL,
119
+ old_value TEXT,
120
+ new_value TEXT,
121
+ notes TEXT,
122
+
123
+ changed_by TEXT,
124
+ changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
125
+
126
+ FOREIGN KEY (work_item_id) REFERENCES work_items(id) ON DELETE CASCADE,
127
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
128
+ );
129
+
130
+ -- Indexes for common queries
131
+ CREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);
132
+ CREATE INDEX IF NOT EXISTS idx_projects_docs_path ON projects(docs_path);
133
+ CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);
134
+
135
+ CREATE INDEX IF NOT EXISTS idx_work_items_project ON work_items(project_id);
136
+ CREATE INDEX IF NOT EXISTS idx_work_items_status ON work_items(status);
137
+ CREATE INDEX IF NOT EXISTS idx_work_items_priority ON work_items(priority);
138
+
139
+ CREATE INDEX IF NOT EXISTS idx_project_documents_project ON project_documents(project_id);
140
+ CREATE INDEX IF NOT EXISTS idx_project_documents_type ON project_documents(doc_type);
141
+
142
+ CREATE INDEX IF NOT EXISTS idx_work_item_history_item ON work_item_history(work_item_id);
143
+ `;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Debug Logger
3
+ *
4
+ * Writes debug output to a file for troubleshooting.
5
+ * Enable with DEBUG=1 environment variable.
6
+ */
7
+ export declare function debug(category: string, message: string, data?: unknown): void;
8
+ export declare function debugError(category: string, error: unknown): void;
package/dist/debug.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Debug Logger
3
+ *
4
+ * Writes debug output to a file for troubleshooting.
5
+ * Enable with DEBUG=1 environment variable.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ const DEBUG_ENABLED = process.env.DEBUG === '1';
10
+ const LOG_FILE = path.join(process.cwd(), 'compilr-debug.log');
11
+ let initialized = false;
12
+ function ensureInit() {
13
+ if (!initialized && DEBUG_ENABLED) {
14
+ // Clear log file on start
15
+ fs.writeFileSync(LOG_FILE, `=== Debug Log Started: ${new Date().toISOString()} ===\n`);
16
+ initialized = true;
17
+ }
18
+ }
19
+ export function debug(category, message, data) {
20
+ if (!DEBUG_ENABLED)
21
+ return;
22
+ ensureInit();
23
+ const timestamp = new Date().toISOString();
24
+ let line = `[${timestamp}] [${category}] ${message}`;
25
+ if (data !== undefined) {
26
+ try {
27
+ line += '\n ' + JSON.stringify(data, null, 2).replace(/\n/g, '\n ');
28
+ }
29
+ catch {
30
+ line += '\n [Unstringifiable data]';
31
+ }
32
+ }
33
+ fs.appendFileSync(LOG_FILE, line + '\n');
34
+ }
35
+ export function debugError(category, error) {
36
+ if (!DEBUG_ENABLED)
37
+ return;
38
+ ensureInit();
39
+ const timestamp = new Date().toISOString();
40
+ let line = `[${timestamp}] [${category}] ERROR: `;
41
+ if (error instanceof Error) {
42
+ line += `${error.message}\n Stack: ${error.stack ?? 'no stack'}`;
43
+ }
44
+ else {
45
+ line += String(error);
46
+ }
47
+ fs.appendFileSync(LOG_FILE, line + '\n');
48
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};