@codemcp/workflows-core 3.1.22 → 3.2.1
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.
- package/package.json +8 -3
- package/resources/templates/architecture/arc42/arc42-template-EN.md +1077 -0
- package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio-2023.png +0 -0
- package/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio.png +0 -0
- package/resources/templates/architecture/arc42/images/05_building_blocks-EN.png +0 -0
- package/resources/templates/architecture/arc42/images/08-concepts-EN.drawio.png +0 -0
- package/resources/templates/architecture/arc42/images/arc42-logo.png +0 -0
- package/resources/templates/architecture/c4.md +224 -0
- package/resources/templates/architecture/freestyle.md +53 -0
- package/resources/templates/architecture/none.md +17 -0
- package/resources/templates/design/comprehensive.md +207 -0
- package/resources/templates/design/freestyle.md +37 -0
- package/resources/templates/design/none.md +17 -0
- package/resources/templates/requirements/ears.md +90 -0
- package/resources/templates/requirements/freestyle.md +42 -0
- package/resources/templates/requirements/none.md +17 -0
- package/resources/workflows/big-bang-conversion.yaml +539 -0
- package/resources/workflows/boundary-testing.yaml +334 -0
- package/resources/workflows/bugfix.yaml +185 -0
- package/resources/workflows/business-analysis.yaml +671 -0
- package/resources/workflows/c4-analysis.yaml +485 -0
- package/resources/workflows/epcc.yaml +161 -0
- package/resources/workflows/greenfield.yaml +189 -0
- package/resources/workflows/minor.yaml +127 -0
- package/resources/workflows/posts.yaml +207 -0
- package/resources/workflows/slides.yaml +256 -0
- package/resources/workflows/tdd.yaml +157 -0
- package/resources/workflows/waterfall.yaml +195 -0
- package/.turbo/turbo-build.log +0 -4
- package/src/config-manager.ts +0 -96
- package/src/conversation-manager.ts +0 -489
- package/src/database.ts +0 -427
- package/src/file-detection-manager.ts +0 -302
- package/src/git-manager.ts +0 -64
- package/src/index.ts +0 -28
- package/src/instruction-generator.ts +0 -210
- package/src/interaction-logger.ts +0 -109
- package/src/logger.ts +0 -353
- package/src/path-validation-utils.ts +0 -261
- package/src/plan-manager.ts +0 -323
- package/src/project-docs-manager.ts +0 -523
- package/src/state-machine-loader.ts +0 -365
- package/src/state-machine-types.ts +0 -72
- package/src/state-machine.ts +0 -370
- package/src/system-prompt-generator.ts +0 -122
- package/src/template-manager.ts +0 -328
- package/src/transition-engine.ts +0 -386
- package/src/types.ts +0 -60
- package/src/workflow-manager.ts +0 -606
- package/test/unit/conversation-manager.test.ts +0 -179
- package/test/unit/custom-workflow-loading.test.ts +0 -174
- package/test/unit/directory-linking-and-extensions.test.ts +0 -338
- package/test/unit/file-linking-integration.test.ts +0 -256
- package/test/unit/git-commit-integration.test.ts +0 -91
- package/test/unit/git-manager.test.ts +0 -86
- package/test/unit/install-workflow.test.ts +0 -138
- package/test/unit/instruction-generator.test.ts +0 -247
- package/test/unit/list-workflows-filtering.test.ts +0 -68
- package/test/unit/none-template-functionality.test.ts +0 -224
- package/test/unit/project-docs-manager.test.ts +0 -337
- package/test/unit/state-machine-loader.test.ts +0 -234
- package/test/unit/template-manager.test.ts +0 -217
- package/test/unit/validate-workflow-name.test.ts +0 -150
- package/test/unit/workflow-domain-filtering.test.ts +0 -75
- package/test/unit/workflow-enum-generation.test.ts +0 -92
- package/test/unit/workflow-manager-enhanced-path-resolution.test.ts +0 -369
- package/test/unit/workflow-manager-path-resolution.test.ts +0 -150
- package/test/unit/workflow-migration.test.ts +0 -155
- package/test/unit/workflow-override-by-name.test.ts +0 -116
- package/test/unit/workflow-prioritization.test.ts +0 -38
- package/test/unit/workflow-validation.test.ts +0 -303
- package/test/utils/e2e-test-setup.ts +0 -453
- package/test/utils/run-server-in-dir.sh +0 -27
- package/test/utils/temp-files.ts +0 -308
- package/test/utils/test-access.ts +0 -79
- package/test/utils/test-helpers.ts +0 -286
- package/test/utils/test-setup.ts +0 -78
- package/tsconfig.build.json +0 -21
- package/tsconfig.json +0 -8
- package/vitest.config.ts +0 -18
@@ -1,217 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Unit tests for TemplateManager
|
3
|
-
*
|
4
|
-
* Tests template loading, validation, and rendering functionality
|
5
|
-
*/
|
6
|
-
|
7
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
8
|
-
import { TestAccess } from '../utils/test-access.js';
|
9
|
-
import { TemplateManager } from '@codemcp/workflows-core';
|
10
|
-
import { mkdir, writeFile, rmdir } from 'node:fs/promises';
|
11
|
-
import { join } from 'node:path';
|
12
|
-
import { tmpdir } from 'node:os';
|
13
|
-
|
14
|
-
describe('TemplateManager', () => {
|
15
|
-
let templateManager: TemplateManager;
|
16
|
-
let testTemplatesPath: string;
|
17
|
-
|
18
|
-
beforeEach(async () => {
|
19
|
-
// Create a temporary directory for test templates
|
20
|
-
testTemplatesPath = join(tmpdir(), `template-test-${Date.now()}`);
|
21
|
-
await mkdir(testTemplatesPath, { recursive: true });
|
22
|
-
|
23
|
-
// Create test template directories
|
24
|
-
await mkdir(join(testTemplatesPath, 'architecture'), { recursive: true });
|
25
|
-
await mkdir(join(testTemplatesPath, 'requirements'), { recursive: true });
|
26
|
-
await mkdir(join(testTemplatesPath, 'design'), { recursive: true });
|
27
|
-
|
28
|
-
// Create test template files
|
29
|
-
await writeFile(
|
30
|
-
join(testTemplatesPath, 'architecture', 'freestyle.md'),
|
31
|
-
'# Test Architecture Template\n\nThis is a test template.'
|
32
|
-
);
|
33
|
-
|
34
|
-
await writeFile(
|
35
|
-
join(testTemplatesPath, 'requirements', 'ears.md'),
|
36
|
-
'# Test Requirements Template\n\n## REQ-1: Test Requirement'
|
37
|
-
);
|
38
|
-
|
39
|
-
await writeFile(
|
40
|
-
join(testTemplatesPath, 'requirements', 'freestyle.md'),
|
41
|
-
'# Freestyle Requirements Template\n\nFlexible requirements format.'
|
42
|
-
);
|
43
|
-
|
44
|
-
await writeFile(
|
45
|
-
join(testTemplatesPath, 'design', 'comprehensive.md'),
|
46
|
-
'# Test Design Template\n\n## Components\n\nTest components here.'
|
47
|
-
);
|
48
|
-
|
49
|
-
await writeFile(
|
50
|
-
join(testTemplatesPath, 'design', 'freestyle.md'),
|
51
|
-
'# Freestyle Design Template\n\nFlexible design format.'
|
52
|
-
);
|
53
|
-
|
54
|
-
// Create arc42 directory template with images
|
55
|
-
const arc42Path = join(testTemplatesPath, 'architecture', 'arc42');
|
56
|
-
await mkdir(arc42Path, { recursive: true });
|
57
|
-
await mkdir(join(arc42Path, 'images'), { recursive: true });
|
58
|
-
|
59
|
-
await writeFile(
|
60
|
-
join(arc42Path, 'arc42-template-EN.md'),
|
61
|
-
'# Arc42 Template\n\n## Introduction and Goals\n\nTest arc42 content.'
|
62
|
-
);
|
63
|
-
|
64
|
-
await writeFile(
|
65
|
-
join(arc42Path, 'images', 'test-image.png'),
|
66
|
-
Buffer.from('fake-image-data')
|
67
|
-
);
|
68
|
-
|
69
|
-
// Mock the templatesPath in TemplateManager
|
70
|
-
templateManager = new TemplateManager();
|
71
|
-
TestAccess.injectMock(templateManager, 'templatesPath', testTemplatesPath);
|
72
|
-
});
|
73
|
-
|
74
|
-
afterEach(async () => {
|
75
|
-
// Clean up test directory
|
76
|
-
try {
|
77
|
-
await rmdir(testTemplatesPath, { recursive: true });
|
78
|
-
} catch {
|
79
|
-
// Ignore cleanup errors
|
80
|
-
}
|
81
|
-
});
|
82
|
-
|
83
|
-
describe('getDefaults', () => {
|
84
|
-
it('should return correct default template options', async () => {
|
85
|
-
const defaults = await templateManager.getDefaults();
|
86
|
-
|
87
|
-
expect(defaults).toEqual({
|
88
|
-
architecture: 'arc42',
|
89
|
-
requirements: 'ears',
|
90
|
-
design: 'comprehensive',
|
91
|
-
});
|
92
|
-
});
|
93
|
-
});
|
94
|
-
|
95
|
-
describe('validateOptions', () => {
|
96
|
-
it('should validate correct template options', async () => {
|
97
|
-
await expect(
|
98
|
-
templateManager.validateOptions({
|
99
|
-
architecture: 'arc42',
|
100
|
-
requirements: 'ears',
|
101
|
-
design: 'comprehensive',
|
102
|
-
})
|
103
|
-
).resolves.not.toThrow();
|
104
|
-
});
|
105
|
-
|
106
|
-
it('should validate freestyle options', async () => {
|
107
|
-
await expect(
|
108
|
-
templateManager.validateOptions({
|
109
|
-
architecture: 'freestyle',
|
110
|
-
requirements: 'freestyle',
|
111
|
-
design: 'freestyle',
|
112
|
-
})
|
113
|
-
).resolves.not.toThrow();
|
114
|
-
});
|
115
|
-
|
116
|
-
it('should throw error for invalid architecture template', async () => {
|
117
|
-
await expect(
|
118
|
-
templateManager.validateOptions({
|
119
|
-
// @ts-ignore - testing invalid input
|
120
|
-
architecture: 'invalid',
|
121
|
-
})
|
122
|
-
).rejects.toThrow('Invalid architecture template: invalid');
|
123
|
-
});
|
124
|
-
|
125
|
-
it('should throw error for invalid requirements template', async () => {
|
126
|
-
await expect(
|
127
|
-
templateManager.validateOptions({
|
128
|
-
// @ts-ignore - testing invalid input
|
129
|
-
requirements: 'invalid',
|
130
|
-
})
|
131
|
-
).rejects.toThrow('Invalid requirements template: invalid');
|
132
|
-
});
|
133
|
-
|
134
|
-
it('should throw error for invalid design template', async () => {
|
135
|
-
await expect(
|
136
|
-
templateManager.validateOptions({
|
137
|
-
// @ts-ignore - testing invalid input
|
138
|
-
design: 'invalid',
|
139
|
-
})
|
140
|
-
).rejects.toThrow('Invalid design template: invalid');
|
141
|
-
});
|
142
|
-
});
|
143
|
-
|
144
|
-
describe('loadTemplate', () => {
|
145
|
-
it('should load freestyle architecture template', async () => {
|
146
|
-
const result = await templateManager.loadTemplate(
|
147
|
-
'architecture',
|
148
|
-
'freestyle'
|
149
|
-
);
|
150
|
-
|
151
|
-
expect(result.content).toContain('# Test Architecture Template');
|
152
|
-
expect(result.content).toContain('This is a test template.');
|
153
|
-
expect(result.additionalFiles).toBeUndefined();
|
154
|
-
});
|
155
|
-
|
156
|
-
it('should load ears requirements template', async () => {
|
157
|
-
const result = await templateManager.loadTemplate('requirements', 'ears');
|
158
|
-
|
159
|
-
expect(result.content).toContain('# Test Requirements Template');
|
160
|
-
expect(result.content).toContain('## REQ-1: Test Requirement');
|
161
|
-
expect(result.additionalFiles).toBeUndefined();
|
162
|
-
});
|
163
|
-
|
164
|
-
it('should load comprehensive design template', async () => {
|
165
|
-
const result = await templateManager.loadTemplate(
|
166
|
-
'design',
|
167
|
-
'comprehensive'
|
168
|
-
);
|
169
|
-
|
170
|
-
expect(result.content).toContain('# Test Design Template');
|
171
|
-
expect(result.content).toContain('## Components');
|
172
|
-
expect(result.additionalFiles).toBeUndefined();
|
173
|
-
});
|
174
|
-
|
175
|
-
it('should load arc42 directory template with images', async () => {
|
176
|
-
const result = await templateManager.loadTemplate(
|
177
|
-
'architecture',
|
178
|
-
'arc42'
|
179
|
-
);
|
180
|
-
|
181
|
-
expect(result.content).toContain('# Arc42 Template');
|
182
|
-
expect(result.content).toContain('## Introduction and Goals');
|
183
|
-
expect(result.additionalFiles).toBeDefined();
|
184
|
-
expect(result.additionalFiles).toHaveLength(1);
|
185
|
-
|
186
|
-
// Safe to access [0] after length check
|
187
|
-
const firstFile = result.additionalFiles?.[0];
|
188
|
-
expect(firstFile?.relativePath).toBe('images/test-image.png');
|
189
|
-
expect(firstFile?.content).toEqual(Buffer.from('fake-image-data'));
|
190
|
-
});
|
191
|
-
|
192
|
-
it('should throw error for non-existent template', async () => {
|
193
|
-
await expect(
|
194
|
-
templateManager.loadTemplate('architecture', 'nonexistent')
|
195
|
-
).rejects.toThrow('Template not found: architecture/nonexistent');
|
196
|
-
});
|
197
|
-
|
198
|
-
it('should throw error for non-existent template type', async () => {
|
199
|
-
await expect(
|
200
|
-
// @ts-ignore - testing invalid input
|
201
|
-
templateManager.loadTemplate('invalid', 'freestyle')
|
202
|
-
).rejects.toThrow('Template not found: invalid/freestyle');
|
203
|
-
});
|
204
|
-
});
|
205
|
-
|
206
|
-
describe('getAvailableTemplates', () => {
|
207
|
-
it('should return all available template options', async () => {
|
208
|
-
const templates = await templateManager.getAvailableTemplates();
|
209
|
-
|
210
|
-
expect(templates).toEqual({
|
211
|
-
architecture: ['arc42', 'freestyle'],
|
212
|
-
requirements: ['ears', 'freestyle'],
|
213
|
-
design: ['comprehensive', 'freestyle'],
|
214
|
-
});
|
215
|
-
});
|
216
|
-
});
|
217
|
-
});
|
@@ -1,150 +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('validateWorkflowName', () => {
|
8
|
-
let testProjectPath: string;
|
9
|
-
let manager: WorkflowManager;
|
10
|
-
|
11
|
-
beforeEach(() => {
|
12
|
-
testProjectPath = fs.mkdtempSync(
|
13
|
-
path.join(tmpdir(), 'validate-workflow-test-')
|
14
|
-
);
|
15
|
-
manager = new WorkflowManager();
|
16
|
-
});
|
17
|
-
|
18
|
-
afterEach(() => {
|
19
|
-
fs.rmSync(testProjectPath, { recursive: true, force: true });
|
20
|
-
});
|
21
|
-
|
22
|
-
it('should validate predefined workflows', () => {
|
23
|
-
expect(manager.validateWorkflowName('waterfall', testProjectPath)).toBe(
|
24
|
-
true
|
25
|
-
);
|
26
|
-
expect(manager.validateWorkflowName('epcc', testProjectPath)).toBe(true);
|
27
|
-
expect(manager.validateWorkflowName('bugfix', testProjectPath)).toBe(true);
|
28
|
-
});
|
29
|
-
|
30
|
-
it('should validate project workflows', () => {
|
31
|
-
// Create a project workflow using valid format from existing workflow
|
32
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
33
|
-
fs.mkdirSync(workflowsDir, { recursive: true });
|
34
|
-
|
35
|
-
// Copy minor workflow and customize it
|
36
|
-
const minorPath = path.join(
|
37
|
-
__dirname,
|
38
|
-
'..',
|
39
|
-
'..',
|
40
|
-
'resources',
|
41
|
-
'workflows',
|
42
|
-
'minor.yaml'
|
43
|
-
);
|
44
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
45
|
-
const customContent = originalContent
|
46
|
-
.replace("name: 'minor'", "name: 'my-project-workflow'")
|
47
|
-
.replace(/description: .*/, "description: 'Project specific workflow'");
|
48
|
-
|
49
|
-
fs.writeFileSync(path.join(workflowsDir, 'project.yaml'), customContent);
|
50
|
-
|
51
|
-
// Should validate the project workflow
|
52
|
-
expect(
|
53
|
-
manager.validateWorkflowName('my-project-workflow', testProjectPath)
|
54
|
-
).toBe(true);
|
55
|
-
});
|
56
|
-
|
57
|
-
it('should reject invalid workflow names', () => {
|
58
|
-
expect(manager.validateWorkflowName('nonexistent', testProjectPath)).toBe(
|
59
|
-
false
|
60
|
-
);
|
61
|
-
expect(
|
62
|
-
manager.validateWorkflowName('invalid-workflow', testProjectPath)
|
63
|
-
).toBe(false);
|
64
|
-
});
|
65
|
-
|
66
|
-
it('should validate "custom" workflow if it exists as project workflow', () => {
|
67
|
-
// Create a project workflow named "custom"
|
68
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
69
|
-
fs.mkdirSync(workflowsDir, { recursive: true });
|
70
|
-
|
71
|
-
// Copy minor workflow and name it "custom"
|
72
|
-
const minorPath = path.join(
|
73
|
-
__dirname,
|
74
|
-
'..',
|
75
|
-
'..',
|
76
|
-
'resources',
|
77
|
-
'workflows',
|
78
|
-
'minor.yaml'
|
79
|
-
);
|
80
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
81
|
-
const customContent = originalContent
|
82
|
-
.replace("name: 'minor'", "name: 'custom'")
|
83
|
-
.replace(/description: .*/, "description: 'Custom workflow'");
|
84
|
-
|
85
|
-
fs.writeFileSync(path.join(workflowsDir, 'custom.yaml'), customContent);
|
86
|
-
|
87
|
-
// Should validate the "custom" workflow as a normal project workflow
|
88
|
-
expect(manager.validateWorkflowName('custom', testProjectPath)).toBe(true);
|
89
|
-
});
|
90
|
-
|
91
|
-
it('should validate "custom" workflow if it exists as project workflow', () => {
|
92
|
-
// Create a project workflow named "custom"
|
93
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
94
|
-
fs.mkdirSync(workflowsDir, { recursive: true });
|
95
|
-
|
96
|
-
// Copy minor workflow and name it "custom"
|
97
|
-
const minorPath = path.join(
|
98
|
-
__dirname,
|
99
|
-
'..',
|
100
|
-
'..',
|
101
|
-
'resources',
|
102
|
-
'workflows',
|
103
|
-
'minor.yaml'
|
104
|
-
);
|
105
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
106
|
-
const customContent = originalContent
|
107
|
-
.replace("name: 'minor'", "name: 'custom'")
|
108
|
-
.replace(/description: .*/, "description: 'Custom workflow'");
|
109
|
-
|
110
|
-
fs.writeFileSync(path.join(workflowsDir, 'custom.yaml'), customContent);
|
111
|
-
|
112
|
-
// Should validate the "custom" workflow as a normal project workflow
|
113
|
-
expect(manager.validateWorkflowName('custom', testProjectPath)).toBe(true);
|
114
|
-
});
|
115
|
-
|
116
|
-
it('should validate project workflows after migration', () => {
|
117
|
-
// Create legacy workflow file using valid format
|
118
|
-
const vibeDir = path.join(testProjectPath, '.vibe');
|
119
|
-
fs.mkdirSync(vibeDir, { recursive: true });
|
120
|
-
|
121
|
-
// Copy minor workflow and customize it
|
122
|
-
const minorPath = path.join(
|
123
|
-
__dirname,
|
124
|
-
'..',
|
125
|
-
'..',
|
126
|
-
'resources',
|
127
|
-
'workflows',
|
128
|
-
'minor.yaml'
|
129
|
-
);
|
130
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
131
|
-
const legacyContent = originalContent
|
132
|
-
.replace("name: 'minor'", "name: 'migrated-workflow'")
|
133
|
-
.replace(/description: .*/, "description: 'Migrated workflow'");
|
134
|
-
|
135
|
-
fs.writeFileSync(path.join(vibeDir, 'workflow.yaml'), legacyContent);
|
136
|
-
|
137
|
-
// Should validate the migrated workflow (migration happens during validation)
|
138
|
-
expect(
|
139
|
-
manager.validateWorkflowName('migrated-workflow', testProjectPath)
|
140
|
-
).toBe(true);
|
141
|
-
|
142
|
-
// Legacy file should be gone
|
143
|
-
expect(fs.existsSync(path.join(vibeDir, 'workflow.yaml'))).toBe(false);
|
144
|
-
|
145
|
-
// New file should exist
|
146
|
-
expect(fs.existsSync(path.join(vibeDir, 'workflows', 'custom.yaml'))).toBe(
|
147
|
-
true
|
148
|
-
);
|
149
|
-
});
|
150
|
-
});
|
@@ -1,75 +0,0 @@
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
2
|
-
import { WorkflowManager } from '@codemcp/workflows-core';
|
3
|
-
|
4
|
-
describe('Workflow Domain Filtering', () => {
|
5
|
-
let originalEnv: string | undefined;
|
6
|
-
|
7
|
-
beforeEach(() => {
|
8
|
-
originalEnv = process.env.VIBE_WORKFLOW_DOMAINS;
|
9
|
-
});
|
10
|
-
|
11
|
-
afterEach(() => {
|
12
|
-
if (originalEnv !== undefined) {
|
13
|
-
process.env.VIBE_WORKFLOW_DOMAINS = originalEnv;
|
14
|
-
} else {
|
15
|
-
delete process.env.VIBE_WORKFLOW_DOMAINS;
|
16
|
-
}
|
17
|
-
});
|
18
|
-
|
19
|
-
it('should load only code workflows when no domain filter is set', () => {
|
20
|
-
delete process.env.VIBE_WORKFLOW_DOMAINS;
|
21
|
-
|
22
|
-
const manager = new WorkflowManager();
|
23
|
-
const workflows = manager.getAvailableWorkflows();
|
24
|
-
|
25
|
-
// Should only include code domain workflows and workflows without domain
|
26
|
-
const codeWorkflows = workflows.filter(
|
27
|
-
w => !w.metadata?.domain || w.metadata.domain === 'code'
|
28
|
-
);
|
29
|
-
const nonCodeWorkflows = workflows.filter(
|
30
|
-
w => w.metadata?.domain && w.metadata.domain !== 'code'
|
31
|
-
);
|
32
|
-
|
33
|
-
expect(codeWorkflows.length).toBeGreaterThan(0);
|
34
|
-
expect(nonCodeWorkflows.length).toBe(0);
|
35
|
-
});
|
36
|
-
|
37
|
-
it('should filter workflows by domain when VIBE_WORKFLOW_DOMAINS is set', () => {
|
38
|
-
process.env.VIBE_WORKFLOW_DOMAINS = 'code';
|
39
|
-
|
40
|
-
const manager = new WorkflowManager();
|
41
|
-
const workflows = manager.getAvailableWorkflows();
|
42
|
-
|
43
|
-
// Should only include code domain workflows
|
44
|
-
const codeWorkflows = workflows.filter(w => w.metadata?.domain === 'code');
|
45
|
-
const nonCodeWorkflows = workflows.filter(
|
46
|
-
w => w.metadata?.domain && w.metadata.domain !== 'code'
|
47
|
-
);
|
48
|
-
|
49
|
-
expect(codeWorkflows.length).toBeGreaterThan(0);
|
50
|
-
expect(nonCodeWorkflows.length).toBe(0);
|
51
|
-
});
|
52
|
-
|
53
|
-
it('should support multiple domains', () => {
|
54
|
-
process.env.VIBE_WORKFLOW_DOMAINS = 'code,office';
|
55
|
-
|
56
|
-
const manager = new WorkflowManager();
|
57
|
-
const workflows = manager.getAvailableWorkflows();
|
58
|
-
|
59
|
-
const allowedWorkflows = workflows.filter(
|
60
|
-
w => !w.metadata?.domain || ['code', 'office'].includes(w.metadata.domain)
|
61
|
-
);
|
62
|
-
|
63
|
-
expect(allowedWorkflows.length).toBe(workflows.length);
|
64
|
-
});
|
65
|
-
|
66
|
-
it('should handle invalid domains gracefully', () => {
|
67
|
-
process.env.VIBE_WORKFLOW_DOMAINS = 'code,invalid,office';
|
68
|
-
|
69
|
-
const manager = new WorkflowManager();
|
70
|
-
const workflows = manager.getAvailableWorkflows();
|
71
|
-
|
72
|
-
// Should still work with valid domains
|
73
|
-
expect(workflows.length).toBeGreaterThan(0);
|
74
|
-
});
|
75
|
-
});
|
@@ -1,92 +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 Enum Generation', () => {
|
8
|
-
let testProjectPath: string;
|
9
|
-
let manager: WorkflowManager;
|
10
|
-
|
11
|
-
beforeEach(() => {
|
12
|
-
testProjectPath = fs.mkdtempSync(
|
13
|
-
path.join(tmpdir(), 'workflow-enum-test-')
|
14
|
-
);
|
15
|
-
manager = new WorkflowManager();
|
16
|
-
});
|
17
|
-
|
18
|
-
afterEach(() => {
|
19
|
-
fs.rmSync(testProjectPath, { recursive: true, force: true });
|
20
|
-
});
|
21
|
-
|
22
|
-
it('should include predefined workflows in enum', () => {
|
23
|
-
const workflowNames = manager.getWorkflowNames();
|
24
|
-
|
25
|
-
// Should include common predefined workflows
|
26
|
-
expect(workflowNames).toContain('waterfall');
|
27
|
-
expect(workflowNames).toContain('epcc');
|
28
|
-
expect(workflowNames).toContain('bugfix');
|
29
|
-
});
|
30
|
-
|
31
|
-
it('should include project workflows in enum after loading', () => {
|
32
|
-
// Create a project workflow
|
33
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
34
|
-
fs.mkdirSync(workflowsDir, { recursive: true });
|
35
|
-
|
36
|
-
// Copy minor workflow and customize it
|
37
|
-
const minorPath = path.join(
|
38
|
-
__dirname,
|
39
|
-
'..',
|
40
|
-
'..',
|
41
|
-
'resources',
|
42
|
-
'workflows',
|
43
|
-
'minor.yaml'
|
44
|
-
);
|
45
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
46
|
-
const customContent = originalContent
|
47
|
-
.replace("name: 'minor'", "name: 'my-custom-workflow'")
|
48
|
-
.replace(/description: .*/, "description: 'Custom workflow for testing'");
|
49
|
-
|
50
|
-
fs.writeFileSync(path.join(workflowsDir, 'custom.yaml'), customContent);
|
51
|
-
|
52
|
-
// Load project workflows
|
53
|
-
manager.loadProjectWorkflows(testProjectPath);
|
54
|
-
|
55
|
-
const workflowNames = manager.getWorkflowNames();
|
56
|
-
|
57
|
-
// Should include both predefined and project workflows
|
58
|
-
expect(workflowNames).toContain('waterfall'); // predefined
|
59
|
-
expect(workflowNames).toContain('my-custom-workflow'); // project
|
60
|
-
});
|
61
|
-
|
62
|
-
it('should not duplicate workflow names when project overrides predefined', () => {
|
63
|
-
// Create a project workflow with same name as predefined
|
64
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
65
|
-
fs.mkdirSync(workflowsDir, { recursive: true });
|
66
|
-
|
67
|
-
// Copy minor workflow but keep the same name
|
68
|
-
const minorPath = path.join(
|
69
|
-
__dirname,
|
70
|
-
'..',
|
71
|
-
'..',
|
72
|
-
'resources',
|
73
|
-
'workflows',
|
74
|
-
'minor.yaml'
|
75
|
-
);
|
76
|
-
const originalContent = fs.readFileSync(minorPath, 'utf8');
|
77
|
-
|
78
|
-
fs.writeFileSync(
|
79
|
-
path.join(workflowsDir, 'minor-override.yaml'),
|
80
|
-
originalContent
|
81
|
-
);
|
82
|
-
|
83
|
-
// Load project workflows
|
84
|
-
manager.loadProjectWorkflows(testProjectPath);
|
85
|
-
|
86
|
-
const workflowNames = manager.getWorkflowNames();
|
87
|
-
|
88
|
-
// Should not have duplicates
|
89
|
-
const minorCount = workflowNames.filter(name => name === 'minor').length;
|
90
|
-
expect(minorCount).toBe(1);
|
91
|
-
});
|
92
|
-
});
|