@codemcp/workflows-core 3.1.21 → 3.2.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 (80) hide show
  1. package/package.json +9 -5
  2. package/resources/templates/architecture/arc42/arc42-template-EN.md +1077 -0
  3. package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio-2023.png +0 -0
  4. package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio.png +0 -0
  5. package/resources/templates/architecture/arc42/images/05_building_blocks-EN.png +0 -0
  6. package/resources/templates/architecture/arc42/images/08-concepts-EN.drawio.png +0 -0
  7. package/resources/templates/architecture/arc42/images/arc42-logo.png +0 -0
  8. package/resources/templates/architecture/c4.md +224 -0
  9. package/resources/templates/architecture/freestyle.md +53 -0
  10. package/resources/templates/architecture/none.md +17 -0
  11. package/resources/templates/design/comprehensive.md +207 -0
  12. package/resources/templates/design/freestyle.md +37 -0
  13. package/resources/templates/design/none.md +17 -0
  14. package/resources/templates/requirements/ears.md +90 -0
  15. package/resources/templates/requirements/freestyle.md +42 -0
  16. package/resources/templates/requirements/none.md +17 -0
  17. package/resources/workflows/big-bang-conversion.yaml +539 -0
  18. package/resources/workflows/boundary-testing.yaml +334 -0
  19. package/resources/workflows/bugfix.yaml +185 -0
  20. package/resources/workflows/business-analysis.yaml +671 -0
  21. package/resources/workflows/c4-analysis.yaml +485 -0
  22. package/resources/workflows/epcc.yaml +161 -0
  23. package/resources/workflows/greenfield.yaml +189 -0
  24. package/resources/workflows/minor.yaml +127 -0
  25. package/resources/workflows/posts.yaml +207 -0
  26. package/resources/workflows/slides.yaml +256 -0
  27. package/resources/workflows/tdd.yaml +157 -0
  28. package/resources/workflows/waterfall.yaml +195 -0
  29. package/.turbo/turbo-build.log +0 -4
  30. package/src/config-manager.ts +0 -96
  31. package/src/conversation-manager.ts +0 -489
  32. package/src/database.ts +0 -427
  33. package/src/file-detection-manager.ts +0 -302
  34. package/src/git-manager.ts +0 -64
  35. package/src/index.ts +0 -28
  36. package/src/instruction-generator.ts +0 -210
  37. package/src/interaction-logger.ts +0 -109
  38. package/src/logger.ts +0 -353
  39. package/src/path-validation-utils.ts +0 -261
  40. package/src/plan-manager.ts +0 -323
  41. package/src/project-docs-manager.ts +0 -523
  42. package/src/state-machine-loader.ts +0 -365
  43. package/src/state-machine-types.ts +0 -72
  44. package/src/state-machine.ts +0 -370
  45. package/src/system-prompt-generator.ts +0 -122
  46. package/src/template-manager.ts +0 -328
  47. package/src/transition-engine.ts +0 -386
  48. package/src/types.ts +0 -60
  49. package/src/workflow-manager.ts +0 -606
  50. package/test/unit/conversation-manager.test.ts +0 -179
  51. package/test/unit/custom-workflow-loading.test.ts +0 -174
  52. package/test/unit/directory-linking-and-extensions.test.ts +0 -338
  53. package/test/unit/file-linking-integration.test.ts +0 -256
  54. package/test/unit/git-commit-integration.test.ts +0 -91
  55. package/test/unit/git-manager.test.ts +0 -86
  56. package/test/unit/install-workflow.test.ts +0 -138
  57. package/test/unit/instruction-generator.test.ts +0 -247
  58. package/test/unit/list-workflows-filtering.test.ts +0 -68
  59. package/test/unit/none-template-functionality.test.ts +0 -224
  60. package/test/unit/project-docs-manager.test.ts +0 -337
  61. package/test/unit/state-machine-loader.test.ts +0 -234
  62. package/test/unit/template-manager.test.ts +0 -217
  63. package/test/unit/validate-workflow-name.test.ts +0 -150
  64. package/test/unit/workflow-domain-filtering.test.ts +0 -75
  65. package/test/unit/workflow-enum-generation.test.ts +0 -92
  66. package/test/unit/workflow-manager-enhanced-path-resolution.test.ts +0 -369
  67. package/test/unit/workflow-manager-path-resolution.test.ts +0 -150
  68. package/test/unit/workflow-migration.test.ts +0 -155
  69. package/test/unit/workflow-override-by-name.test.ts +0 -116
  70. package/test/unit/workflow-prioritization.test.ts +0 -38
  71. package/test/unit/workflow-validation.test.ts +0 -303
  72. package/test/utils/e2e-test-setup.ts +0 -453
  73. package/test/utils/run-server-in-dir.sh +0 -27
  74. package/test/utils/temp-files.ts +0 -308
  75. package/test/utils/test-access.ts +0 -79
  76. package/test/utils/test-helpers.ts +0 -286
  77. package/test/utils/test-setup.ts +0 -78
  78. package/tsconfig.build.json +0 -21
  79. package/tsconfig.json +0 -8
  80. package/vitest.config.ts +0 -18
package/src/database.ts DELETED
@@ -1,427 +0,0 @@
1
- /**
2
- * Database Manager
3
- *
4
- * Handles SQLite database operations for conversation state persistence.
5
- * Uses @sqlite.org/sqlite-wasm for reliable cross-platform WebAssembly bindings.
6
- */
7
-
8
- import sqlite3InitModule, {
9
- type Database as SqliteDatabase,
10
- type Sqlite3Static,
11
- } from '@sqlite.org/sqlite-wasm';
12
- import { mkdir } from 'node:fs/promises';
13
- import { dirname } from 'node:path';
14
- import { createLogger } from './logger.js';
15
- import type { ConversationState, InteractionLog } from './types.js';
16
-
17
- const logger = createLogger('Database');
18
-
19
- /**
20
- * Database connection and operations manager
21
- */
22
- export class Database {
23
- private db: SqliteDatabase | null = null;
24
- private sqlite3: Sqlite3Static | null = null;
25
- private dbPath: string;
26
-
27
- constructor(dbPath: string) {
28
- this.dbPath = dbPath;
29
- }
30
-
31
- /**
32
- * Initialize database connection and create tables
33
- */
34
- async initialize(): Promise<void> {
35
- try {
36
- // Initialize SQLite WASM
37
- this.sqlite3 = await sqlite3InitModule();
38
-
39
- // Always use in-memory database (sqlite-wasm Node.js limitation)
40
- this.db = new this.sqlite3.oo1.DB();
41
- logger.debug('Database connection established (in-memory)', {
42
- originalPath: this.dbPath,
43
- });
44
-
45
- // Create tables
46
- await this.createTables();
47
-
48
- // Load existing data from file if it exists
49
- if (this.dbPath !== ':memory:' && this.dbPath) {
50
- await this.loadFromFile();
51
- }
52
-
53
- logger.info('Database initialized successfully', { dbPath: this.dbPath });
54
- } catch (error) {
55
- logger.error('Failed to initialize database', error as Error);
56
- throw error;
57
- }
58
- }
59
-
60
- /**
61
- * Load database content from file
62
- */
63
- private async loadFromFile(): Promise<void> {
64
- if (!this.db || !this.dbPath || this.dbPath === ':memory:') {
65
- return;
66
- }
67
-
68
- try {
69
- const { readFile, access } = await import('node:fs/promises');
70
- await access(this.dbPath);
71
-
72
- const data = await readFile(this.dbPath);
73
- if (data.length > 0) {
74
- // Close current in-memory DB and create new one from file data
75
- this.db.close();
76
- // Create new DB and deserialize data into it
77
-
78
- //eslint-disable-next-line @typescript-eslint/no-non-null-assertion
79
- this.db = new this.sqlite3!.oo1.DB();
80
- if (!this.db.pointer) {
81
- throw new Error('Failed to create database');
82
- }
83
-
84
- // Convert Buffer to Uint8Array
85
- const uint8Data = new Uint8Array(data);
86
-
87
- //eslint-disable-next-line @typescript-eslint/no-non-null-assertion
88
- const wasmPtr = this.sqlite3!.wasm.allocFromTypedArray(uint8Data);
89
-
90
- //eslint-disable-next-line @typescript-eslint/no-non-null-assertion
91
- this.sqlite3!.capi.sqlite3_deserialize(
92
- this.db.pointer,
93
- 'main',
94
- wasmPtr,
95
- data.length,
96
- data.length,
97
- 0x01 // SQLITE_DESERIALIZE_FREEONCLOSE
98
- );
99
- logger.debug('Loaded database from file', {
100
- dbPath: this.dbPath,
101
- size: data.length,
102
- });
103
- }
104
- } catch {
105
- // File doesn't exist - that's OK for new databases
106
- logger.debug('No existing database file to load', {
107
- dbPath: this.dbPath,
108
- });
109
- }
110
- }
111
-
112
- /**
113
- * Save database content to file
114
- */
115
- private async saveToFile(): Promise<void> {
116
- if (!this.db || !this.dbPath || this.dbPath === ':memory:') {
117
- return;
118
- }
119
-
120
- try {
121
- const { writeFile } = await import('node:fs/promises');
122
- const dbDir = dirname(this.dbPath);
123
- await mkdir(dbDir, { recursive: true });
124
-
125
- // Export database to Uint8Array and save to file
126
- if (!this.db.pointer) {
127
- throw new Error('Database pointer is invalid');
128
- }
129
- //eslint-disable-next-line @typescript-eslint/no-non-null-assertion
130
- const data = this.sqlite3!.capi.sqlite3_js_db_export(this.db.pointer);
131
- await writeFile(this.dbPath, data);
132
- logger.debug('Saved database to file', {
133
- dbPath: this.dbPath,
134
- size: data.length,
135
- });
136
- } catch (error) {
137
- logger.warn('Failed to save database to file', {
138
- error: error as Error,
139
- dbPath: this.dbPath,
140
- });
141
- }
142
- }
143
-
144
- /**
145
- * Create database tables if they don't exist
146
- */
147
- private async createTables(): Promise<void> {
148
- if (!this.db) {
149
- throw new Error('Database not initialized');
150
- }
151
-
152
- const createConversationStateTable = `
153
- CREATE TABLE IF NOT EXISTS conversation_state (
154
- conversationId TEXT PRIMARY KEY,
155
- projectPath TEXT NOT NULL,
156
- gitBranch TEXT NOT NULL,
157
- currentPhase TEXT NOT NULL,
158
- planFilePath TEXT NOT NULL,
159
- workflowName TEXT NOT NULL,
160
- gitCommitConfig TEXT,
161
- requireReviewsBeforePhaseTransition INTEGER NOT NULL DEFAULT 0,
162
- createdAt TEXT NOT NULL,
163
- updatedAt TEXT NOT NULL
164
- )
165
- `;
166
-
167
- const createInteractionLogTable = `
168
- CREATE TABLE IF NOT EXISTS interaction_log (
169
- id INTEGER PRIMARY KEY AUTOINCREMENT,
170
- conversationId TEXT NOT NULL,
171
- toolName TEXT NOT NULL,
172
- inputParams TEXT NOT NULL,
173
- responseData TEXT NOT NULL,
174
- currentPhase TEXT NOT NULL,
175
- timestamp TEXT NOT NULL,
176
- FOREIGN KEY (conversationId) REFERENCES conversation_state(conversationId)
177
- )
178
- `;
179
-
180
- this.db.exec(createConversationStateTable);
181
- this.db.exec(createInteractionLogTable);
182
-
183
- logger.debug('Database tables created');
184
- }
185
-
186
- /**
187
- * Save conversation state to database
188
- */
189
- async saveConversationState(state: ConversationState): Promise<void> {
190
- if (!this.db) {
191
- throw new Error('Database not initialized');
192
- }
193
-
194
- this.db.exec({
195
- sql: `INSERT OR REPLACE INTO conversation_state
196
- (conversationId, projectPath, gitBranch, currentPhase, planFilePath, workflowName,
197
- gitCommitConfig, requireReviewsBeforePhaseTransition, createdAt, updatedAt)
198
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
199
- bind: [
200
- state.conversationId,
201
- state.projectPath,
202
- state.gitBranch,
203
- state.currentPhase,
204
- state.planFilePath,
205
- state.workflowName,
206
- state.gitCommitConfig ? JSON.stringify(state.gitCommitConfig) : null,
207
- state.requireReviewsBeforePhaseTransition ? 1 : 0,
208
- state.createdAt,
209
- state.updatedAt,
210
- ],
211
- });
212
-
213
- // Persist to file
214
- await this.saveToFile();
215
-
216
- logger.debug('Conversation state saved', {
217
- conversationId: state.conversationId,
218
- currentPhase: state.currentPhase,
219
- });
220
- }
221
-
222
- /**
223
- * Get conversation state by ID
224
- */
225
- async getConversationState(
226
- conversationId: string
227
- ): Promise<ConversationState | null> {
228
- if (!this.db) {
229
- throw new Error('Database not initialized');
230
- }
231
-
232
- const result = this.db.exec({
233
- sql: 'SELECT * FROM conversation_state WHERE conversationId = ?',
234
- bind: [conversationId],
235
- returnValue: 'resultRows',
236
- });
237
-
238
- if (!result || result.length === 0) {
239
- return null;
240
- }
241
-
242
- const row = result[0];
243
- return {
244
- conversationId: row[0] as string,
245
- projectPath: row[1] as string,
246
- gitBranch: row[2] as string,
247
- currentPhase: row[3] as string,
248
- planFilePath: row[4] as string,
249
- workflowName: row[5] as string,
250
- gitCommitConfig: row[6] ? JSON.parse(row[6] as string) : null,
251
- requireReviewsBeforePhaseTransition: Boolean(row[7]),
252
- createdAt: row[8] as string,
253
- updatedAt: row[9] as string,
254
- };
255
- }
256
-
257
- /**
258
- * Get all conversation states
259
- */
260
- async getAllConversationStates(): Promise<ConversationState[]> {
261
- if (!this.db) {
262
- throw new Error('Database not initialized');
263
- }
264
-
265
- const result = this.db.exec({
266
- sql: 'SELECT * FROM conversation_state ORDER BY updatedAt DESC',
267
- returnValue: 'resultRows',
268
- });
269
-
270
- if (!result) {
271
- return [];
272
- }
273
-
274
- return result.map(row => ({
275
- conversationId: row[0] as string,
276
- projectPath: row[1] as string,
277
- gitBranch: row[2] as string,
278
- currentPhase: row[3] as string,
279
- planFilePath: row[4] as string,
280
- workflowName: row[5] as string,
281
- gitCommitConfig: row[6] ? JSON.parse(row[6] as string) : null,
282
- requireReviewsBeforePhaseTransition: Boolean(row[7]),
283
- createdAt: row[8] as string,
284
- updatedAt: row[9] as string,
285
- }));
286
- }
287
-
288
- /**
289
- * Delete conversation state
290
- */
291
- async deleteConversationState(conversationId: string): Promise<boolean> {
292
- if (!this.db) {
293
- throw new Error('Database not initialized');
294
- }
295
-
296
- this.db.exec({
297
- sql: 'DELETE FROM conversation_state WHERE conversationId = ?',
298
- bind: [conversationId],
299
- });
300
-
301
- // Persist to file
302
- await this.saveToFile();
303
-
304
- logger.debug('Conversation state deleted', { conversationId });
305
- return true;
306
- }
307
-
308
- /**
309
- * Log interaction
310
- */
311
- async logInteraction(log: InteractionLog): Promise<void> {
312
- if (!this.db) {
313
- throw new Error('Database not initialized');
314
- }
315
-
316
- this.db.exec({
317
- sql: `INSERT INTO interaction_log
318
- (conversationId, toolName, inputParams, responseData, currentPhase, timestamp)
319
- VALUES (?, ?, ?, ?, ?, ?)`,
320
- bind: [
321
- log.conversationId,
322
- log.toolName,
323
- JSON.stringify(log.inputParams),
324
- JSON.stringify(log.responseData),
325
- log.currentPhase,
326
- log.timestamp,
327
- ],
328
- });
329
-
330
- // Persist to file
331
- await this.saveToFile();
332
-
333
- logger.debug('Interaction logged', {
334
- conversationId: log.conversationId,
335
- toolName: log.toolName,
336
- });
337
- }
338
-
339
- /**
340
- * Get interaction logs for a conversation
341
- */
342
- async getInteractionLogs(conversationId: string): Promise<InteractionLog[]> {
343
- if (!this.db) {
344
- throw new Error('Database not initialized');
345
- }
346
-
347
- const result = this.db.exec({
348
- sql: 'SELECT * FROM interaction_log WHERE conversationId = ? ORDER BY timestamp ASC',
349
- bind: [conversationId],
350
- returnValue: 'resultRows',
351
- });
352
-
353
- if (!result) {
354
- return [];
355
- }
356
-
357
- return result.map(row => ({
358
- id: row[0] as number,
359
- conversationId: row[1] as string,
360
- toolName: row[2] as string,
361
- inputParams: JSON.parse(row[3] as string),
362
- responseData: JSON.parse(row[4] as string),
363
- currentPhase: row[5] as string,
364
- timestamp: row[6] as string,
365
- }));
366
- }
367
-
368
- /**
369
- * Get interaction logs for a conversation (alias for compatibility)
370
- */
371
- async getInteractionsByConversationId(
372
- conversationId: string
373
- ): Promise<InteractionLog[]> {
374
- return this.getInteractionLogs(conversationId);
375
- }
376
-
377
- /**
378
- * Soft delete interaction logs (for compatibility - actually deletes them)
379
- */
380
- async softDeleteInteractionLogs(conversationId: string): Promise<void> {
381
- if (!this.db) {
382
- throw new Error('Database not initialized');
383
- }
384
-
385
- this.db.exec({
386
- sql: 'DELETE FROM interaction_log WHERE conversationId = ?',
387
- bind: [conversationId],
388
- });
389
-
390
- // Persist to file
391
- await this.saveToFile();
392
-
393
- logger.debug('Interaction logs deleted', { conversationId });
394
- }
395
-
396
- /**
397
- * Reset conversation state (for testing)
398
- */
399
- async resetConversationState(conversationId: string): Promise<void> {
400
- if (!this.db) {
401
- throw new Error('Database not initialized');
402
- }
403
-
404
- const resetAt = new Date().toISOString();
405
-
406
- this.db.exec({
407
- sql: 'UPDATE conversation_state SET updatedAt = ? WHERE conversationId = ?',
408
- bind: [resetAt, conversationId],
409
- });
410
-
411
- // Persist to file
412
- await this.saveToFile();
413
-
414
- logger.debug('Conversation state reset', { conversationId, resetAt });
415
- }
416
-
417
- /**
418
- * Close database connection
419
- */
420
- async close(): Promise<void> {
421
- if (this.db) {
422
- this.db.close();
423
- this.db = null;
424
- logger.debug('Database connection closed');
425
- }
426
- }
427
- }