@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,116 +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 Override by Name', () => {
8
- let testProjectPath: string;
9
- let originalEnv: string | undefined;
10
-
11
- beforeEach(() => {
12
- originalEnv = process.env.VIBE_WORKFLOW_DOMAINS;
13
- testProjectPath = fs.mkdtempSync(
14
- path.join(tmpdir(), 'workflow-override-test-')
15
- );
16
- });
17
-
18
- afterEach(() => {
19
- if (originalEnv !== undefined) {
20
- process.env.VIBE_WORKFLOW_DOMAINS = originalEnv;
21
- } else {
22
- delete process.env.VIBE_WORKFLOW_DOMAINS;
23
- }
24
-
25
- fs.rmSync(testProjectPath, { recursive: true, force: true });
26
- });
27
-
28
- it('should override predefined workflow by YAML name, not filename', () => {
29
- process.env.VIBE_WORKFLOW_DOMAINS = 'code';
30
-
31
- const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
32
- fs.mkdirSync(workflowsDir, { recursive: true });
33
-
34
- // Copy existing waterfall workflow but change description
35
- const waterfallPath = path.join(
36
- __dirname,
37
- '..',
38
- '..',
39
- 'resources',
40
- 'workflows',
41
- 'waterfall.yaml'
42
- );
43
- const originalContent = fs.readFileSync(waterfallPath, 'utf8');
44
- const customContent = originalContent.replace(
45
- /description: .*/,
46
- "description: 'Custom company waterfall'"
47
- );
48
-
49
- fs.writeFileSync(
50
- path.join(workflowsDir, 'company-waterfall.yaml'),
51
- customContent
52
- );
53
-
54
- const manager = new WorkflowManager();
55
-
56
- // Load project workflows to trigger override
57
- const workflows = manager.getAvailableWorkflowsForProject(testProjectPath);
58
-
59
- // Should override predefined waterfall workflow
60
- const workflow = manager.getWorkflow('waterfall');
61
- expect(workflow?.name).toBe('waterfall');
62
- expect(workflow?.description).toBe('Custom company waterfall');
63
-
64
- // Should be available in workflow list
65
- const waterfallWorkflow = workflows.find(w => w.name === 'waterfall');
66
- expect(waterfallWorkflow?.description).toBe('Custom company waterfall');
67
- });
68
-
69
- it('should use YAML name as workflow key, not filename', () => {
70
- process.env.VIBE_WORKFLOW_DOMAINS = 'code';
71
-
72
- const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
73
- fs.mkdirSync(workflowsDir, { recursive: true });
74
-
75
- // Copy existing waterfall workflow with different filename
76
- const waterfallPath = path.join(
77
- __dirname,
78
- '..',
79
- '..',
80
- 'resources',
81
- 'workflows',
82
- 'waterfall.yaml'
83
- );
84
- const originalContent = fs.readFileSync(waterfallPath, 'utf8');
85
- const customContent = originalContent.replace(
86
- /description: .*/,
87
- "description: 'Different filename, same name'"
88
- );
89
-
90
- // Use completely different filename but keep YAML name as 'waterfall'
91
- fs.writeFileSync(
92
- path.join(workflowsDir, 'totally-different-filename.yaml'),
93
- customContent
94
- );
95
-
96
- const manager = new WorkflowManager();
97
-
98
- // Load project workflows
99
- const workflows = manager.getAvailableWorkflowsForProject(testProjectPath);
100
-
101
- // Should still be accessible as 'waterfall' (YAML name), not 'totally-different-filename'
102
- const workflow = manager.getWorkflow('waterfall');
103
- expect(workflow?.name).toBe('waterfall');
104
- expect(workflow?.description).toBe('Different filename, same name');
105
-
106
- // Should not be accessible by filename
107
- const byFilename = manager.getWorkflow('totally-different-filename');
108
- expect(byFilename).toBeUndefined();
109
-
110
- // Should be in workflow list with correct name
111
- const waterfallWorkflow = workflows.find(w => w.name === 'waterfall');
112
- expect(waterfallWorkflow?.description).toBe(
113
- 'Different filename, same name'
114
- );
115
- });
116
- });
@@ -1,38 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { WorkflowManager } from '@codemcp/workflows-core';
3
-
4
- describe('Workflow Prioritization', () => {
5
- it('should prioritize project workflows over predefined ones in getWorkflow method', () => {
6
- const manager = new WorkflowManager();
7
-
8
- // Get original waterfall workflow
9
- const originalWaterfall = manager.getWorkflow('waterfall');
10
- expect(originalWaterfall?.name).toBe('waterfall');
11
-
12
- // Simulate adding a project workflow with same name
13
- // Access private property for testing (this simulates successful loading)
14
- const projectWorkflows = (manager as unknown).projectWorkflows;
15
- const workflowInfos = (manager as unknown).workflowInfos;
16
-
17
- const customWorkflow = {
18
- name: 'custom-waterfall',
19
- description: 'Custom override',
20
- initial_state: 'custom-start',
21
- states: { 'custom-start': { description: 'test' } },
22
- };
23
-
24
- projectWorkflows.set('waterfall', customWorkflow);
25
- workflowInfos.set('waterfall', {
26
- name: 'waterfall',
27
- displayName: 'custom-waterfall',
28
- description: 'Custom override',
29
- initialState: 'custom-start',
30
- phases: ['custom-start'],
31
- });
32
-
33
- // Now getWorkflow should return the project workflow
34
- const prioritizedWorkflow = manager.getWorkflow('waterfall');
35
- expect(prioritizedWorkflow?.name).toBe('custom-waterfall');
36
- expect(prioritizedWorkflow?.description).toBe('Custom override');
37
- });
38
- });
@@ -1,303 +0,0 @@
1
- /**
2
- * Workflow Validation Tests
3
- *
4
- * Comprehensive tests to ensure all workflow files are valid and meet formal criteria:
5
- * - All workflows can be loaded without errors
6
- * - Every state is reachable through transition chains
7
- * - Workflow structure integrity (initial state exists, phases defined, etc.)
8
- * - No orphaned states or unreachable phases
9
- */
10
-
11
- import { describe, it, expect, beforeEach } from 'vitest';
12
- import { WorkflowInfo, WorkflowManager } from '@codemcp/workflows-core';
13
- import { readdirSync } from 'node:fs';
14
- import { join } from 'node:path';
15
- import { YamlStateMachine, YamlState } from '@codemcp/workflows-core';
16
-
17
- describe('Workflow Validation', () => {
18
- const workflowsDir = join(__dirname, '..', '..', 'resources', 'workflows');
19
- const workflowFiles = readdirSync(workflowsDir).filter(
20
- file => file.endsWith('.yaml') || file.endsWith('.yml')
21
- );
22
-
23
- describe('Workflow Loading', () => {
24
- it('should load all workflow files without errors', () => {
25
- const workflowManager = new WorkflowManager();
26
-
27
- // Get all available workflows
28
- const workflows = workflowManager.getAvailableWorkflows();
29
-
30
- // Should have loaded workflows (at least the core ones)
31
- expect(workflows.length).toBeGreaterThan(0);
32
-
33
- // Check that we have the expected core workflows
34
- const expectedCoreWorkflows = ['bugfix', 'waterfall', 'epcc', 'minor'];
35
- const workflowNames = workflows.map(w => w.name);
36
- for (const workflow of expectedCoreWorkflows) {
37
- expect(workflowNames).toContain(workflow);
38
- }
39
- });
40
-
41
- it('should load ALL workflow files from resources directory', () => {
42
- // Temporarily disable domain filtering for this test
43
- const originalEnv = process.env.VIBE_WORKFLOW_DOMAINS;
44
- process.env.VIBE_WORKFLOW_DOMAINS = 'code,architecture,office';
45
-
46
- try {
47
- // Create manager after setting env var to include all domains
48
- const workflowManager = new WorkflowManager();
49
- const loadedWorkflows = workflowManager.getAvailableWorkflows();
50
- const loadedWorkflowNames = loadedWorkflows.map(w => w.name);
51
-
52
- // Count expected workflow files
53
- const expectedWorkflowCount = workflowFiles.length;
54
-
55
- // Should load exactly the same number of workflows as files
56
- expect(loadedWorkflows.length).toBe(expectedWorkflowCount);
57
-
58
- // Each workflow file should correspond to a loaded workflow
59
- for (const file of workflowFiles) {
60
- const workflowName = file.replace(/\.(yaml|yml)$/, '');
61
- expect(loadedWorkflowNames).toContain(workflowName);
62
- }
63
- } finally {
64
- if (originalEnv !== undefined) {
65
- process.env.VIBE_WORKFLOW_DOMAINS = originalEnv;
66
- } else {
67
- delete process.env.VIBE_WORKFLOW_DOMAINS;
68
- }
69
- }
70
- });
71
-
72
- it('should have valid workflow files in resources directory', () => {
73
- expect(workflowFiles.length).toBeGreaterThan(0);
74
-
75
- // Check that all files have valid extensions
76
- for (const file of workflowFiles) {
77
- expect(file.endsWith('.yaml') || file.endsWith('.yml')).toBe(true);
78
- }
79
- });
80
- });
81
-
82
- describe('Workflow Structure Validation', () => {
83
- let workflowManager: WorkflowManager;
84
- let workflows: WorkflowInfo[];
85
-
86
- beforeEach(() => {
87
- workflowManager = new WorkflowManager();
88
- workflows = workflowManager.getAvailableWorkflows();
89
- });
90
-
91
- it('should have required fields for each workflow', () => {
92
- for (const workflow of workflows) {
93
- expect(workflow).toBeDefined();
94
- expect(workflow.name).toBeDefined();
95
- expect(typeof workflow.name).toBe('string');
96
- expect(workflow.displayName).toBeDefined();
97
- expect(typeof workflow.displayName).toBe('string');
98
- expect(workflow.phases).toBeDefined();
99
- expect(Array.isArray(workflow.phases)).toBe(true);
100
- expect(workflow.phases.length).toBeGreaterThan(0);
101
- }
102
- });
103
-
104
- it('should have valid state machines for each workflow', () => {
105
- for (const workflow of workflows) {
106
- // Get the state machine for this workflow
107
- const stateMachine = workflowManager.getWorkflow(workflow.name);
108
-
109
- expect(stateMachine).toBeDefined();
110
- expect(stateMachine!.name).toBe(workflow.name);
111
- expect(stateMachine!.description).toBeDefined();
112
- expect(stateMachine!.initial_state).toBeDefined();
113
- expect(stateMachine!.states).toBeDefined();
114
- expect(typeof stateMachine!.states).toBe('object');
115
- }
116
- });
117
-
118
- it('should have initial state defined in states', () => {
119
- for (const workflow of workflows) {
120
- const stateMachine = workflowManager.getWorkflow(workflow.name);
121
-
122
- expect(stateMachine!.states[stateMachine!.initial_state]).toBeDefined();
123
- }
124
- });
125
-
126
- it('should have all phases represented as states', () => {
127
- for (const workflow of workflows) {
128
- const stateMachine = workflowManager.getWorkflow(workflow.name);
129
-
130
- // Every phase should exist as a state
131
- for (const phase of workflow.phases) {
132
- expect(stateMachine!.states[phase]).toBeDefined();
133
- }
134
- }
135
- });
136
- });
137
-
138
- describe('State Reachability Analysis', () => {
139
- let workflowManager: WorkflowManager;
140
- let workflows: WorkflowInfo[];
141
-
142
- beforeEach(() => {
143
- workflowManager = new WorkflowManager();
144
- workflows = workflowManager.getAvailableWorkflows();
145
- });
146
-
147
- /**
148
- * Build a graph of state transitions and check reachability
149
- */
150
- function analyzeStateReachability(stateMachine: YamlStateMachine) {
151
- const states = Object.keys(stateMachine.states);
152
- const reachableStates = new Set<string>();
153
- const visited = new Set<string>();
154
-
155
- // Start from initial state
156
- const queue = [stateMachine.initial_state];
157
- reachableStates.add(stateMachine.initial_state);
158
-
159
- while (queue.length > 0) {
160
- const currentState = queue.shift()!;
161
-
162
- if (visited.has(currentState)) continue;
163
- visited.add(currentState);
164
-
165
- const stateConfig = stateMachine.states[currentState];
166
- if (stateConfig.transitions) {
167
- for (const transition of stateConfig.transitions) {
168
- if (transition.to && !reachableStates.has(transition.to)) {
169
- reachableStates.add(transition.to);
170
- queue.push(transition.to);
171
- }
172
- }
173
- }
174
- }
175
-
176
- return {
177
- allStates: states,
178
- reachableStates: Array.from(reachableStates),
179
- unreachableStates: states.filter(state => !reachableStates.has(state)),
180
- };
181
- }
182
-
183
- it('should have all states reachable from initial state', () => {
184
- for (const workflow of workflows) {
185
- const stateMachine = workflowManager.getWorkflow(workflow.name);
186
- const analysis = analyzeStateReachability(stateMachine!);
187
-
188
- expect(analysis.unreachableStates).toEqual([]);
189
-
190
- // All states should be reachable
191
- expect(analysis.reachableStates.length).toBe(analysis.allStates.length);
192
- }
193
- });
194
-
195
- it('should have valid transition targets', () => {
196
- for (const workflow of workflows) {
197
- const stateMachine = workflowManager.getWorkflow(workflow.name);
198
-
199
- for (const [_stateName, stateConfig] of Object.entries(
200
- stateMachine!.states
201
- ) as [string, YamlState][]) {
202
- if (stateConfig.transitions) {
203
- for (const transition of stateConfig.transitions) {
204
- if (transition.to) {
205
- // Target state must exist
206
- expect(stateMachine!.states[transition.to]).toBeDefined();
207
- }
208
- }
209
- }
210
- }
211
- }
212
- });
213
-
214
- it('should have meaningful transition triggers', () => {
215
- for (const workflow of workflows) {
216
- const stateMachine = workflowManager.getWorkflow(workflow.name);
217
-
218
- for (const [_stateName, stateConfig] of Object.entries(
219
- stateMachine!.states
220
- ) as [string, YamlState][]) {
221
- if (stateConfig.transitions) {
222
- for (const transition of stateConfig.transitions) {
223
- // Each transition should have a trigger
224
- expect(transition.trigger).toBeDefined();
225
- expect(typeof transition.trigger).toBe('string');
226
- expect(transition.trigger.length).toBeGreaterThan(0);
227
-
228
- // Trigger should be meaningful (not just whitespace)
229
- expect(transition.trigger.trim()).toBe(transition.trigger);
230
- expect(transition.trigger.trim().length).toBeGreaterThan(0);
231
- }
232
- }
233
- }
234
- }
235
- });
236
- });
237
-
238
- describe('Workflow Content Quality', () => {
239
- let workflowManager: WorkflowManager;
240
- let workflows: WorkflowInfo[];
241
-
242
- beforeEach(() => {
243
- workflowManager = new WorkflowManager();
244
- workflows = workflowManager.getAvailableWorkflows();
245
- });
246
-
247
- it('should have meaningful descriptions for all states', () => {
248
- for (const workflow of workflows) {
249
- const stateMachine = workflowManager.getWorkflow(workflow.name);
250
-
251
- for (const [_stateName, stateConfig] of Object.entries(
252
- stateMachine!.states
253
- ) as [string, YamlState][]) {
254
- expect(stateConfig.description).toBeDefined();
255
- expect(typeof stateConfig.description).toBe('string');
256
- expect(stateConfig.description.length).toBeGreaterThan(10); // Meaningful description
257
- }
258
- }
259
- });
260
-
261
- it('should have default instructions for all states', () => {
262
- for (const workflow of workflows) {
263
- const stateMachine = workflowManager.getWorkflow(workflow.name);
264
-
265
- for (const [_stateName, stateConfig] of Object.entries(
266
- stateMachine!.states
267
- ) as [string, YamlState][]) {
268
- expect(stateConfig.default_instructions).toBeDefined();
269
- expect(typeof stateConfig.default_instructions).toBe('string');
270
- expect(stateConfig.default_instructions.length).toBeGreaterThan(20); // Substantial instructions
271
- }
272
- }
273
- });
274
-
275
- it('should have workflow metadata', () => {
276
- for (const workflow of workflows) {
277
- const stateMachine = workflowManager.getWorkflow(workflow.name);
278
-
279
- // Should have basic metadata
280
- expect(stateMachine!.name).toBeDefined();
281
- expect(stateMachine!.description).toBeDefined();
282
- expect(typeof stateMachine!.description).toBe('string');
283
- expect(stateMachine!.description.length).toBeGreaterThan(10);
284
- }
285
- });
286
- });
287
-
288
- describe('Workflow Integration', () => {
289
- it('should be able to create workflow instances', () => {
290
- const workflowManager = new WorkflowManager();
291
- const workflows = workflowManager.getAvailableWorkflows();
292
-
293
- // Should be able to get workflow info for each workflow
294
- for (const workflow of workflows) {
295
- const workflowInfo = workflowManager.getWorkflowInfo(workflow.name);
296
- expect(workflowInfo).toBeDefined();
297
- expect(workflowInfo!.name).toBe(workflow.name);
298
- expect(workflowInfo!.phases).toBeDefined();
299
- expect(Array.isArray(workflowInfo!.phases)).toBe(true);
300
- }
301
- });
302
- });
303
- });