@codemcp/workflows-core 3.1.22 → 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 +8 -3
  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
@@ -1,369 +0,0 @@
1
- /**
2
- * Enhanced unit tests for WorkflowManager path resolution strategies
3
- *
4
- * Tests the comprehensive workflow directory finding functionality
5
- * including npx scenarios and various npm installation patterns
6
- */
7
-
8
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
9
- import { existsSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
10
- import { resolve, join } from 'node:path';
11
- import { tmpdir } from 'node:os';
12
- import { WorkflowManager } from '@codemcp/workflows-core';
13
-
14
- describe('WorkflowManager enhanced path resolution', () => {
15
- let tempDir: string;
16
- let originalNodePath: string | undefined;
17
- let originalHome: string | undefined;
18
- let originalUserProfile: string | undefined;
19
-
20
- beforeEach(() => {
21
- // Create temporary directory for testing
22
- tempDir = resolve(tmpdir(), `workflow-enhanced-test-${Date.now()}`);
23
- mkdirSync(tempDir, { recursive: true });
24
-
25
- // Store original environment variables
26
- originalNodePath = process.env.NODE_PATH;
27
- originalHome = process.env.HOME;
28
- originalUserProfile = process.env.USERPROFILE;
29
- });
30
-
31
- afterEach(() => {
32
- // Clean up temporary directory
33
- if (existsSync(tempDir)) {
34
- rmSync(tempDir, { recursive: true, force: true });
35
- }
36
-
37
- // Restore environment variables
38
- if (originalNodePath !== undefined) {
39
- process.env.NODE_PATH = originalNodePath;
40
- } else {
41
- delete process.env.NODE_PATH;
42
- }
43
-
44
- if (originalHome !== undefined) {
45
- process.env.HOME = originalHome;
46
- } else {
47
- delete process.env.HOME;
48
- }
49
-
50
- if (originalUserProfile !== undefined) {
51
- process.env.USERPROFILE = originalUserProfile;
52
- } else {
53
- delete process.env.USERPROFILE;
54
- }
55
- });
56
-
57
- function createWorkflowFile(dir: string, name: string = 'test.yaml') {
58
- const content = `name: ${name.replace('.yaml', '')}
59
- description: Test workflow
60
- initial_state: start
61
- states:
62
- start:
63
- description: Test state
64
- instructions: Test instructions
65
- transitions:
66
- - to: end
67
- condition: always
68
- end:
69
- description: End state
70
- instructions: Complete
71
- `;
72
- writeFileSync(join(dir, name), content);
73
- }
74
-
75
- function createPackageJson(
76
- dir: string,
77
- name: string = 'responsible-vibe-mcp'
78
- ) {
79
- const packageJson = {
80
- name,
81
- version: '1.0.0',
82
- description: 'Test package',
83
- };
84
- writeFileSync(
85
- join(dir, 'package.json'),
86
- JSON.stringify(packageJson, null, 2)
87
- );
88
- }
89
-
90
- describe('Strategy 1: Relative to current file', () => {
91
- it('should find workflows relative to dist directory', () => {
92
- // Simulate dist/workflow-manager.js -> ../resources/workflows structure
93
- const projectRoot = join(tempDir, 'project');
94
- const distDir = join(projectRoot, 'dist');
95
- const workflowsDir = join(projectRoot, 'resources', 'workflows');
96
-
97
- mkdirSync(distDir, { recursive: true });
98
- mkdirSync(workflowsDir, { recursive: true });
99
-
100
- createWorkflowFile(workflowsDir, 'waterfall.yaml');
101
- createPackageJson(projectRoot);
102
-
103
- const workflowManager = new WorkflowManager();
104
- const workflows = workflowManager.getAvailableWorkflows();
105
-
106
- // Should find at least the predefined workflows
107
- expect(workflows.length).toBeGreaterThan(0);
108
- const workflowNames = workflows.map(w => w.name);
109
- expect(workflowNames).toContain('waterfall');
110
- });
111
- });
112
-
113
- describe('Strategy 2: Package root discovery', () => {
114
- it('should find workflows by traversing up to package.json', () => {
115
- // Create nested structure where we need to traverse up
116
- const projectRoot = join(tempDir, 'project');
117
- const deepDir = join(projectRoot, 'dist', 'server', 'handlers');
118
- const workflowsDir = join(projectRoot, 'resources', 'workflows');
119
-
120
- mkdirSync(deepDir, { recursive: true });
121
- mkdirSync(workflowsDir, { recursive: true });
122
-
123
- createWorkflowFile(workflowsDir, 'epcc.yaml');
124
- createPackageJson(projectRoot);
125
-
126
- const workflowManager = new WorkflowManager();
127
- const workflows = workflowManager.getAvailableWorkflows();
128
-
129
- expect(workflows.length).toBeGreaterThan(0);
130
- const workflowNames = workflows.map(w => w.name);
131
- expect(workflowNames).toContain('epcc');
132
- });
133
-
134
- it('should ignore package.json files from other packages', () => {
135
- // Create structure with multiple package.json files
136
- const projectRoot = join(tempDir, 'project');
137
- const nodeModulesDir = join(projectRoot, 'node_modules', 'other-package');
138
- const workflowsDir = join(projectRoot, 'resources', 'workflows');
139
-
140
- mkdirSync(nodeModulesDir, { recursive: true });
141
- mkdirSync(workflowsDir, { recursive: true });
142
-
143
- createWorkflowFile(workflowsDir, 'bugfix.yaml');
144
- createPackageJson(projectRoot); // Our package
145
- createPackageJson(nodeModulesDir, 'other-package'); // Different package
146
-
147
- const workflowManager = new WorkflowManager();
148
- const workflows = workflowManager.getAvailableWorkflows();
149
-
150
- expect(workflows.length).toBeGreaterThan(0);
151
- const workflowNames = workflows.map(w => w.name);
152
- expect(workflowNames).toContain('bugfix');
153
- });
154
- });
155
-
156
- describe('Strategy 3: Common npm installation paths', () => {
157
- it('should find workflows in local node_modules', () => {
158
- // Note: We can't actually create files in the real node_modules during tests,
159
- // but we can verify the path resolution logic works
160
- const workflowManager = new WorkflowManager();
161
- const workflows = workflowManager.getAvailableWorkflows();
162
-
163
- // Should still find predefined workflows from the actual package
164
- expect(workflows.length).toBeGreaterThan(0);
165
- });
166
-
167
- it('should handle NODE_PATH environment variable', () => {
168
- // Set up NODE_PATH scenario
169
- const nodePath = join(tempDir, 'global-modules');
170
- const packageDir = join(nodePath, 'responsible-vibe-mcp');
171
- const workflowsDir = join(packageDir, 'resources', 'workflows');
172
-
173
- mkdirSync(workflowsDir, { recursive: true });
174
- createWorkflowFile(workflowsDir, 'greenfield.yaml');
175
- createPackageJson(packageDir);
176
-
177
- // Set NODE_PATH
178
- process.env.NODE_PATH = nodePath;
179
-
180
- const workflowManager = new WorkflowManager();
181
- const workflows = workflowManager.getAvailableWorkflows();
182
-
183
- expect(workflows.length).toBeGreaterThan(0);
184
- const workflowNames = workflows.map(w => w.name);
185
- expect(workflowNames).toContain('greenfield');
186
- });
187
- });
188
-
189
- describe('Strategy 4: npx cache locations', () => {
190
- it('should search in HOME-based npx cache directories', () => {
191
- // Simulate npx cache structure
192
- const homeDir = join(tempDir, 'home');
193
- const npxCacheDir = join(homeDir, '.npm/_npx');
194
- const cacheEntry = join(npxCacheDir, 'abc123');
195
- const packageDir = join(
196
- cacheEntry,
197
- 'node_modules',
198
- 'responsible-vibe-mcp'
199
- );
200
- const workflowsDir = join(packageDir, 'resources', 'workflows');
201
-
202
- mkdirSync(workflowsDir, { recursive: true });
203
- createWorkflowFile(workflowsDir, 'minor.yaml');
204
- createPackageJson(packageDir);
205
-
206
- // Set HOME environment variable
207
- process.env.HOME = homeDir;
208
-
209
- const workflowManager = new WorkflowManager();
210
- const workflows = workflowManager.getAvailableWorkflows();
211
-
212
- expect(workflows.length).toBeGreaterThan(0);
213
- const workflowNames = workflows.map(w => w.name);
214
- expect(workflowNames).toContain('minor');
215
- });
216
-
217
- it('should search in USERPROFILE-based cache directories (Windows)', () => {
218
- // Simulate Windows npx cache structure
219
- const userProfile = join(tempDir, 'Users', 'testuser');
220
- const npxCacheDir = join(userProfile, 'AppData/Local/npm-cache/_npx');
221
- const cacheEntry = join(npxCacheDir, 'def456');
222
- const packageDir = join(cacheEntry, 'responsible-vibe-mcp');
223
- const workflowsDir = join(packageDir, 'resources', 'workflows');
224
-
225
- mkdirSync(workflowsDir, { recursive: true });
226
- createWorkflowFile(workflowsDir, 'waterfall.yaml');
227
- createPackageJson(packageDir);
228
-
229
- // Set USERPROFILE environment variable (Windows)
230
- process.env.USERPROFILE = userProfile;
231
- delete process.env.HOME; // Remove HOME to simulate Windows
232
-
233
- const workflowManager = new WorkflowManager();
234
- const workflows = workflowManager.getAvailableWorkflows();
235
-
236
- expect(workflows.length).toBeGreaterThan(0);
237
- const workflowNames = workflows.map(w => w.name);
238
- expect(workflowNames).toContain('waterfall');
239
- });
240
-
241
- it('should handle macOS Library cache directories', () => {
242
- // Simulate macOS cache structure
243
- const homeDir = join(tempDir, 'Users', 'testuser');
244
- const npxCacheDir = join(homeDir, 'Library/Caches/npm/_npx');
245
- const cacheEntry = join(npxCacheDir, 'ghi789');
246
- const packageDir = join(
247
- cacheEntry,
248
- 'node_modules',
249
- 'responsible-vibe-mcp'
250
- );
251
- const workflowsDir = join(packageDir, 'resources', 'workflows');
252
-
253
- mkdirSync(workflowsDir, { recursive: true });
254
- createWorkflowFile(workflowsDir, 'epcc.yaml');
255
- createPackageJson(packageDir);
256
-
257
- // Set HOME environment variable
258
- process.env.HOME = homeDir;
259
-
260
- const workflowManager = new WorkflowManager();
261
- const workflows = workflowManager.getAvailableWorkflows();
262
-
263
- expect(workflows.length).toBeGreaterThan(0);
264
- const workflowNames = workflows.map(w => w.name);
265
- expect(workflowNames).toContain('epcc');
266
- });
267
- });
268
-
269
- describe('Strategy 5: Executable directory', () => {
270
- it('should find workflows relative to executable location', () => {
271
- // This strategy uses process.argv[1] which is set by Node.js
272
- // We can't easily mock this in tests, but we can verify the logic
273
- const workflowManager = new WorkflowManager();
274
- const workflows = workflowManager.getAvailableWorkflows();
275
-
276
- // Should find predefined workflows
277
- expect(workflows.length).toBeGreaterThan(0);
278
- });
279
- });
280
-
281
- describe('Strategy 6: require.resolve', () => {
282
- it('should use require.resolve to find package location', () => {
283
- // This strategy attempts to resolve our own package
284
- // In the test environment, this should work since we're running from the package
285
- const workflowManager = new WorkflowManager();
286
- const workflows = workflowManager.getAvailableWorkflows();
287
-
288
- expect(workflows.length).toBeGreaterThan(0);
289
- const workflowNames = workflows.map(w => w.name);
290
-
291
- // Should find all predefined workflows
292
- expect(workflowNames).toContain('waterfall');
293
- expect(workflowNames).toContain('bugfix');
294
- expect(workflowNames).toContain('epcc');
295
- });
296
- });
297
-
298
- describe('Fallback behavior', () => {
299
- it('should handle gracefully when no workflows directory is found', () => {
300
- // Create a scenario where no workflows can be found
301
- // This is difficult to test since our actual package has workflows
302
- // But we can verify the manager doesn't crash
303
- const workflowManager = new WorkflowManager();
304
-
305
- expect(() => {
306
- const workflows = workflowManager.getAvailableWorkflows();
307
- expect(workflows).toBeDefined();
308
- expect(Array.isArray(workflows)).toBe(true);
309
- }).not.toThrow();
310
- });
311
-
312
- it('should deduplicate strategies and filter invalid paths', () => {
313
- // The implementation should remove duplicates and invalid paths
314
- const workflowManager = new WorkflowManager();
315
- const workflows = workflowManager.getAvailableWorkflows();
316
-
317
- // Should work without errors despite potential duplicate strategies
318
- expect(workflows).toBeDefined();
319
- expect(Array.isArray(workflows)).toBe(true);
320
- });
321
- });
322
-
323
- describe('Integration with actual workflows', () => {
324
- it('should load all predefined workflows correctly', () => {
325
- const workflowManager = new WorkflowManager();
326
- const workflows = workflowManager.getAvailableWorkflows();
327
-
328
- // Verify all expected workflows are present
329
- const workflowNames = workflows.map(w => w.name).sort();
330
- expect(workflowNames).toContain('waterfall');
331
- expect(workflowNames).toContain('bugfix');
332
- expect(workflowNames).toContain('epcc');
333
-
334
- // Verify each workflow has required properties
335
- for (const workflow of workflows) {
336
- expect(workflow.name).toBeDefined();
337
- expect(workflow.displayName).toBeDefined();
338
- expect(workflow.description).toBeDefined();
339
- expect(workflow.initialState).toBeDefined();
340
- expect(workflow.phases).toBeDefined();
341
- expect(Array.isArray(workflow.phases)).toBe(true);
342
- expect(workflow.phases.length).toBeGreaterThan(0);
343
- }
344
- });
345
-
346
- it('should load specific workflows with correct structure', () => {
347
- const workflowManager = new WorkflowManager();
348
-
349
- // Test waterfall workflow
350
- const waterfall = workflowManager.getWorkflow('waterfall');
351
- expect(waterfall).toBeDefined();
352
- expect(waterfall?.name).toBe('waterfall');
353
- expect(waterfall?.initial_state).toBe('requirements');
354
- expect(Object.keys(waterfall?.states || {})).toContain('requirements');
355
- expect(Object.keys(waterfall?.states || {})).toContain('design');
356
- expect(Object.keys(waterfall?.states || {})).toContain('implementation');
357
-
358
- // Test bugfix workflow
359
- const bugfix = workflowManager.getWorkflow('bugfix');
360
- expect(bugfix).toBeDefined();
361
- expect(bugfix?.name).toBe('bugfix');
362
- expect(bugfix?.initial_state).toBe('reproduce');
363
- expect(Object.keys(bugfix?.states || {})).toContain('reproduce');
364
- expect(Object.keys(bugfix?.states || {})).toContain('analyze');
365
- expect(Object.keys(bugfix?.states || {})).toContain('fix');
366
- expect(Object.keys(bugfix?.states || {})).toContain('verify');
367
- });
368
- });
369
- });
@@ -1,150 +0,0 @@
1
- /**
2
- * Unit tests for WorkflowManager path resolution
3
- *
4
- * Tests the robust workflow directory finding functionality
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import { existsSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
9
- import { resolve, join } from 'node:path';
10
- import { tmpdir } from 'node:os';
11
- import { WorkflowManager } from '@codemcp/workflows-core';
12
-
13
- describe('WorkflowManager path resolution', () => {
14
- let tempDir: string;
15
- let originalNodePath: string | undefined;
16
-
17
- beforeEach(() => {
18
- // Create temporary directory for testing
19
- tempDir = resolve(tmpdir(), `workflow-test-${Date.now()}`);
20
- mkdirSync(tempDir, { recursive: true });
21
-
22
- // Store original NODE_PATH
23
- originalNodePath = process.env.NODE_PATH;
24
- });
25
-
26
- afterEach(() => {
27
- // Clean up temporary directory
28
- if (existsSync(tempDir)) {
29
- rmSync(tempDir, { recursive: true, force: true });
30
- }
31
-
32
- // Restore NODE_PATH
33
- if (originalNodePath !== undefined) {
34
- process.env.NODE_PATH = originalNodePath;
35
- } else {
36
- delete process.env.NODE_PATH;
37
- }
38
- });
39
-
40
- describe('findWorkflowsDirectory', () => {
41
- it('should find workflows in development environment structure', () => {
42
- // Create development-like structure
43
- const projectRoot = join(tempDir, 'project');
44
- const srcDir = join(projectRoot, 'src');
45
- const workflowsDir = join(projectRoot, 'resources', 'workflows');
46
-
47
- mkdirSync(srcDir, { recursive: true });
48
- mkdirSync(workflowsDir, { recursive: true });
49
-
50
- // Create a sample workflow file
51
- writeFileSync(
52
- join(workflowsDir, 'test.yaml'),
53
- 'name: test\ndescription: test workflow\ninitial_state: start\nstates:\n start:\n description: test'
54
- );
55
-
56
- // Create package.json to identify the project
57
- writeFileSync(
58
- join(projectRoot, 'package.json'),
59
- JSON.stringify({
60
- name: 'responsible-vibe-mcp',
61
- version: '1.0.0',
62
- })
63
- );
64
-
65
- const workflowManager = new WorkflowManager();
66
-
67
- // The method should find workflows
68
- const workflows = workflowManager.getAvailableWorkflows();
69
- expect(workflows.length).toBeGreaterThan(0);
70
- });
71
-
72
- it('should handle missing workflows directory gracefully', () => {
73
- // Create a project without workflows directory
74
- const projectRoot = join(tempDir, 'no-workflows');
75
- mkdirSync(projectRoot, { recursive: true });
76
-
77
- const workflowManager = new WorkflowManager();
78
-
79
- // Should not throw error, just return empty workflows
80
- const workflows = workflowManager.getAvailableWorkflows();
81
- expect(workflows).toBeDefined();
82
- // Note: In real implementation, it might still find predefined workflows from the actual package
83
- });
84
-
85
- it('should load predefined workflows successfully', () => {
86
- const workflowManager = new WorkflowManager();
87
- const workflows = workflowManager.getAvailableWorkflows();
88
-
89
- // Should have the standard predefined workflows
90
- const workflowNames = workflows.map(w => w.name);
91
- expect(workflowNames).toContain('waterfall');
92
- expect(workflowNames).toContain('bugfix');
93
- expect(workflowNames).toContain('epcc');
94
- expect(workflowNames).toContain('minor');
95
- expect(workflowNames).toContain('greenfield');
96
- });
97
-
98
- it('should load specific workflows correctly', () => {
99
- const workflowManager = new WorkflowManager();
100
-
101
- // Test loading a specific workflow
102
- const waterfall = workflowManager.getWorkflow('waterfall');
103
- expect(waterfall).toBeDefined();
104
- expect(waterfall?.name).toBe('waterfall');
105
- expect(waterfall?.initial_state).toBe('requirements');
106
-
107
- const bugfix = workflowManager.getWorkflow('bugfix');
108
- expect(bugfix).toBeDefined();
109
- expect(bugfix?.name).toBe('bugfix');
110
- expect(bugfix?.initial_state).toBe('reproduce');
111
- });
112
-
113
- it('should validate workflow names correctly', () => {
114
- const workflowManager = new WorkflowManager();
115
-
116
- // Test predefined workflows
117
- expect(workflowManager.validateWorkflowName('waterfall', tempDir)).toBe(
118
- true
119
- );
120
- expect(workflowManager.validateWorkflowName('bugfix', tempDir)).toBe(
121
- true
122
- );
123
- expect(workflowManager.validateWorkflowName('nonexistent', tempDir)).toBe(
124
- false
125
- );
126
- });
127
- });
128
-
129
- describe('workflow loading from different directories', () => {
130
- it('should work when called from different working directories', () => {
131
- // Change to temp directory (different from package location)
132
- const originalCwd = process.cwd();
133
-
134
- try {
135
- process.chdir(tempDir);
136
-
137
- const workflowManager = new WorkflowManager();
138
- const workflows = workflowManager.getAvailableWorkflows();
139
-
140
- // Should still find predefined workflows
141
- expect(workflows.length).toBeGreaterThan(0);
142
-
143
- const workflowNames = workflows.map(w => w.name);
144
- expect(workflowNames).toContain('waterfall');
145
- } finally {
146
- process.chdir(originalCwd);
147
- }
148
- });
149
- });
150
- });
@@ -1,155 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { WorkflowManager } from '@codemcp/workflows-core';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { tmpdir } from 'node:os';
6
-
7
- describe('Workflow Migration', () => {
8
- let testProjectPath: string;
9
-
10
- beforeEach(() => {
11
- testProjectPath = fs.mkdtempSync(
12
- path.join(tmpdir(), 'workflow-migration-test-')
13
- );
14
- });
15
-
16
- afterEach(() => {
17
- fs.rmSync(testProjectPath, { recursive: true, force: true });
18
- });
19
-
20
- it('should migrate workflow.yaml to workflows/custom.yaml', () => {
21
- // Create .vibe directory and legacy workflow file
22
- const vibeDir = path.join(testProjectPath, '.vibe');
23
- fs.mkdirSync(vibeDir, { recursive: true });
24
-
25
- const legacyWorkflow = `
26
- name: my-custom-workflow
27
- description: 'Legacy custom workflow'
28
- initial_state: start
29
- states:
30
- start:
31
- description: 'Start phase'
32
- default_instructions: 'Start instructions'
33
- transitions:
34
- - target: end
35
- condition: 'always'
36
- end:
37
- description: 'End phase'
38
- default_instructions: 'End instructions'
39
- transitions: []
40
- `;
41
-
42
- const legacyPath = path.join(vibeDir, 'workflow.yaml');
43
- fs.writeFileSync(legacyPath, legacyWorkflow);
44
-
45
- const manager = new WorkflowManager();
46
-
47
- // Load project workflows (this should trigger migration)
48
- manager.loadProjectWorkflows(testProjectPath);
49
-
50
- // Check that legacy file was moved
51
- expect(fs.existsSync(legacyPath)).toBe(false);
52
-
53
- // Check that new file exists
54
- const newPath = path.join(vibeDir, 'workflows', 'custom.yaml');
55
- expect(fs.existsSync(newPath)).toBe(true);
56
-
57
- // Check content is preserved
58
- const newContent = fs.readFileSync(newPath, 'utf8');
59
- expect(newContent).toContain('my-custom-workflow');
60
- expect(newContent).toContain('Legacy custom workflow');
61
- });
62
-
63
- it('should migrate workflow.yml to workflows/custom.yaml', () => {
64
- // Create .vibe directory and legacy workflow file with .yml extension
65
- const vibeDir = path.join(testProjectPath, '.vibe');
66
- fs.mkdirSync(vibeDir, { recursive: true });
67
-
68
- const legacyWorkflow = `
69
- name: yml-workflow
70
- description: 'YML extension workflow'
71
- initial_state: start
72
- states:
73
- start:
74
- description: 'Start phase'
75
- default_instructions: 'Start instructions'
76
- transitions:
77
- - target: end
78
- condition: 'always'
79
- end:
80
- description: 'End phase'
81
- default_instructions: 'End instructions'
82
- transitions: []
83
- `;
84
-
85
- const legacyPath = path.join(vibeDir, 'workflow.yml');
86
- fs.writeFileSync(legacyPath, legacyWorkflow);
87
-
88
- const manager = new WorkflowManager();
89
-
90
- // Load project workflows (this should trigger migration)
91
- manager.loadProjectWorkflows(testProjectPath);
92
-
93
- // Check that legacy file was moved
94
- expect(fs.existsSync(legacyPath)).toBe(false);
95
-
96
- // Check that new file exists
97
- const newPath = path.join(vibeDir, 'workflows', 'custom.yaml');
98
- expect(fs.existsSync(newPath)).toBe(true);
99
-
100
- // Check content is preserved
101
- const newContent = fs.readFileSync(newPath, 'utf8');
102
- expect(newContent).toContain('yml-workflow');
103
- });
104
-
105
- it('should not migrate if target file already exists', () => {
106
- // Create .vibe directory and both legacy and new workflow files
107
- const vibeDir = path.join(testProjectPath, '.vibe');
108
- const workflowsDir = path.join(vibeDir, 'workflows');
109
- fs.mkdirSync(workflowsDir, { recursive: true });
110
-
111
- const legacyWorkflow = 'name: legacy\ndescription: Legacy';
112
- const newWorkflow = 'name: existing\ndescription: Existing';
113
-
114
- const legacyPath = path.join(vibeDir, 'workflow.yaml');
115
- const newPath = path.join(workflowsDir, 'custom.yaml');
116
-
117
- fs.writeFileSync(legacyPath, legacyWorkflow);
118
- fs.writeFileSync(newPath, newWorkflow);
119
-
120
- const manager = new WorkflowManager();
121
-
122
- // Load project workflows (should not migrate because target exists)
123
- manager.loadProjectWorkflows(testProjectPath);
124
-
125
- // Check that legacy file still exists
126
- expect(fs.existsSync(legacyPath)).toBe(true);
127
-
128
- // Check that new file is unchanged
129
- const newContent = fs.readFileSync(newPath, 'utf8');
130
- expect(newContent).toContain('existing');
131
- expect(newContent).not.toContain('legacy');
132
- });
133
-
134
- it('should handle migration errors gracefully', () => {
135
- // Create .vibe directory and legacy workflow file
136
- const vibeDir = path.join(testProjectPath, '.vibe');
137
- fs.mkdirSync(vibeDir, { recursive: true });
138
-
139
- const legacyPath = path.join(vibeDir, 'workflow.yaml');
140
- fs.writeFileSync(legacyPath, 'name: test');
141
-
142
- // Make the .vibe directory read-only to cause migration failure
143
- fs.chmodSync(vibeDir, 0o444);
144
-
145
- const manager = new WorkflowManager();
146
-
147
- // Should not throw error even if migration fails
148
- expect(() => {
149
- manager.loadProjectWorkflows(testProjectPath);
150
- }).not.toThrow();
151
-
152
- // Restore permissions for cleanup
153
- fs.chmodSync(vibeDir, 0o755);
154
- });
155
- });