@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,256 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Integration tests for file linking functionality
|
3
|
-
*
|
4
|
-
* Tests the complete file linking workflow including path validation,
|
5
|
-
* file detection, and symlink creation.
|
6
|
-
*/
|
7
|
-
|
8
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
9
|
-
import { PathValidationUtils } from '@codemcp/workflows-core';
|
10
|
-
import { FileDetectionManager } from '@codemcp/workflows-core';
|
11
|
-
import { ProjectDocsManager } from '@codemcp/workflows-core';
|
12
|
-
import { join } from 'node:path';
|
13
|
-
import { tmpdir } from 'node:os';
|
14
|
-
import { mkdir, writeFile, rmdir, lstat } from 'node:fs/promises';
|
15
|
-
|
16
|
-
describe('File Linking Integration', () => {
|
17
|
-
let testProjectPath: string;
|
18
|
-
let projectDocsManager: ProjectDocsManager;
|
19
|
-
let fileDetectionManager: FileDetectionManager;
|
20
|
-
|
21
|
-
beforeEach(async () => {
|
22
|
-
// Create test project directory
|
23
|
-
testProjectPath = join(tmpdir(), `file-linking-test-${Date.now()}`);
|
24
|
-
await mkdir(testProjectPath, { recursive: true });
|
25
|
-
|
26
|
-
// Create test files
|
27
|
-
await writeFile(
|
28
|
-
join(testProjectPath, 'README.md'),
|
29
|
-
'# Test Project\n\nThis is a test project with requirements and architecture info.'
|
30
|
-
);
|
31
|
-
await writeFile(
|
32
|
-
join(testProjectPath, 'ARCHITECTURE.md'),
|
33
|
-
'# Architecture\n\nSystem architecture details.'
|
34
|
-
);
|
35
|
-
|
36
|
-
// Create docs directory with files
|
37
|
-
await mkdir(join(testProjectPath, 'docs'), { recursive: true });
|
38
|
-
await writeFile(
|
39
|
-
join(testProjectPath, 'docs', 'design.md'),
|
40
|
-
'# Design\n\nDetailed design specifications.'
|
41
|
-
);
|
42
|
-
|
43
|
-
projectDocsManager = new ProjectDocsManager();
|
44
|
-
fileDetectionManager = new FileDetectionManager(testProjectPath);
|
45
|
-
});
|
46
|
-
|
47
|
-
afterEach(async () => {
|
48
|
-
// Clean up test directory
|
49
|
-
try {
|
50
|
-
await rmdir(testProjectPath, { recursive: true });
|
51
|
-
} catch {
|
52
|
-
// Ignore cleanup errors
|
53
|
-
}
|
54
|
-
});
|
55
|
-
|
56
|
-
describe('PathValidationUtils', () => {
|
57
|
-
it('should validate template names correctly', () => {
|
58
|
-
const availableTemplates = ['arc42', 'freestyle'];
|
59
|
-
|
60
|
-
expect(
|
61
|
-
PathValidationUtils.isTemplateName('arc42', availableTemplates)
|
62
|
-
).toBe(true);
|
63
|
-
expect(
|
64
|
-
PathValidationUtils.isTemplateName('freestyle', availableTemplates)
|
65
|
-
).toBe(true);
|
66
|
-
expect(
|
67
|
-
PathValidationUtils.isTemplateName('invalid', availableTemplates)
|
68
|
-
).toBe(false);
|
69
|
-
});
|
70
|
-
|
71
|
-
it('should validate file paths correctly', async () => {
|
72
|
-
const result = await PathValidationUtils.validateFilePath(
|
73
|
-
'README.md',
|
74
|
-
testProjectPath
|
75
|
-
);
|
76
|
-
|
77
|
-
expect(result.isValid).toBe(true);
|
78
|
-
expect(result.resolvedPath).toBe(join(testProjectPath, 'README.md'));
|
79
|
-
});
|
80
|
-
|
81
|
-
it('should reject non-existent files', async () => {
|
82
|
-
const result = await PathValidationUtils.validateFilePath(
|
83
|
-
'nonexistent.md',
|
84
|
-
testProjectPath
|
85
|
-
);
|
86
|
-
|
87
|
-
expect(result.isValid).toBe(false);
|
88
|
-
expect(result.error).toContain('File not found');
|
89
|
-
});
|
90
|
-
|
91
|
-
it('should validate mixed parameters correctly', async () => {
|
92
|
-
const availableTemplates = ['arc42', 'freestyle'];
|
93
|
-
|
94
|
-
// Template name
|
95
|
-
const templateResult = await PathValidationUtils.validateParameter(
|
96
|
-
'arc42',
|
97
|
-
availableTemplates,
|
98
|
-
testProjectPath
|
99
|
-
);
|
100
|
-
expect(templateResult.isTemplate).toBe(true);
|
101
|
-
expect(templateResult.isFilePath).toBe(false);
|
102
|
-
|
103
|
-
// File path
|
104
|
-
const fileResult = await PathValidationUtils.validateParameter(
|
105
|
-
'README.md',
|
106
|
-
availableTemplates,
|
107
|
-
testProjectPath
|
108
|
-
);
|
109
|
-
expect(fileResult.isTemplate).toBe(false);
|
110
|
-
expect(fileResult.isFilePath).toBe(true);
|
111
|
-
expect(fileResult.resolvedPath).toBe(join(testProjectPath, 'README.md'));
|
112
|
-
|
113
|
-
// Invalid parameter
|
114
|
-
const invalidResult = await PathValidationUtils.validateParameter(
|
115
|
-
'invalid',
|
116
|
-
availableTemplates,
|
117
|
-
testProjectPath
|
118
|
-
);
|
119
|
-
expect(invalidResult.isTemplate).toBe(false);
|
120
|
-
expect(invalidResult.isFilePath).toBe(false);
|
121
|
-
expect(invalidResult.error).toBeDefined();
|
122
|
-
});
|
123
|
-
});
|
124
|
-
|
125
|
-
describe('FileDetectionManager', () => {
|
126
|
-
it('should detect existing documentation files', async () => {
|
127
|
-
const result = await fileDetectionManager.detectDocumentationFiles();
|
128
|
-
|
129
|
-
expect(result.architecture.length).toBeGreaterThan(0);
|
130
|
-
expect(result.requirements.length).toBeGreaterThan(0);
|
131
|
-
expect(result.design.length).toBeGreaterThan(0);
|
132
|
-
|
133
|
-
// Check that README.md is detected for multiple types
|
134
|
-
const readmeInRequirements = result.requirements.some(
|
135
|
-
file => file.relativePath === 'README.md'
|
136
|
-
);
|
137
|
-
expect(readmeInRequirements).toBe(true);
|
138
|
-
});
|
139
|
-
|
140
|
-
it('should format suggestions correctly', async () => {
|
141
|
-
const result = await fileDetectionManager.detectDocumentationFiles();
|
142
|
-
const suggestions = fileDetectionManager.formatSuggestions(result);
|
143
|
-
|
144
|
-
expect(suggestions).toContain('Existing documentation files detected');
|
145
|
-
expect(suggestions).toContain('README.md');
|
146
|
-
expect(suggestions).toContain('setup_project_docs');
|
147
|
-
});
|
148
|
-
});
|
149
|
-
|
150
|
-
describe('ProjectDocsManager Symlink Creation', () => {
|
151
|
-
it('should create symlinks for file paths', async () => {
|
152
|
-
const result = await projectDocsManager.createOrLinkProjectDocs(
|
153
|
-
testProjectPath,
|
154
|
-
{}, // No templates
|
155
|
-
{
|
156
|
-
architecture: join(testProjectPath, 'ARCHITECTURE.md'),
|
157
|
-
requirements: join(testProjectPath, 'README.md'),
|
158
|
-
design: join(testProjectPath, 'docs', 'design.md'),
|
159
|
-
}
|
160
|
-
);
|
161
|
-
|
162
|
-
expect(result.created).toEqual([]);
|
163
|
-
expect(result.linked).toEqual([
|
164
|
-
'architecture.md',
|
165
|
-
'requirements.md',
|
166
|
-
'design.md',
|
167
|
-
]);
|
168
|
-
expect(result.skipped).toEqual([]);
|
169
|
-
|
170
|
-
// Verify symlinks were created
|
171
|
-
const paths = projectDocsManager.getDocumentPaths(testProjectPath);
|
172
|
-
|
173
|
-
const archStats = await lstat(paths.architecture);
|
174
|
-
expect(archStats.isSymbolicLink()).toBe(true);
|
175
|
-
|
176
|
-
const reqStats = await lstat(paths.requirements);
|
177
|
-
expect(reqStats.isSymbolicLink()).toBe(true);
|
178
|
-
|
179
|
-
const designStats = await lstat(paths.design);
|
180
|
-
expect(designStats.isSymbolicLink()).toBe(true);
|
181
|
-
});
|
182
|
-
|
183
|
-
it('should handle mixed template and file path scenarios', async () => {
|
184
|
-
const result = await projectDocsManager.createOrLinkProjectDocs(
|
185
|
-
testProjectPath,
|
186
|
-
{
|
187
|
-
architecture: 'freestyle', // Template
|
188
|
-
},
|
189
|
-
{
|
190
|
-
requirements: join(testProjectPath, 'README.md'), // File path
|
191
|
-
design: join(testProjectPath, 'docs', 'design.md'), // File path
|
192
|
-
}
|
193
|
-
);
|
194
|
-
|
195
|
-
expect(result.created).toEqual(['architecture.md']);
|
196
|
-
expect(result.linked).toEqual(['requirements.md', 'design.md']);
|
197
|
-
expect(result.skipped).toEqual([]);
|
198
|
-
});
|
199
|
-
|
200
|
-
it('should check if documents are symlinks', async () => {
|
201
|
-
// Create a symlink
|
202
|
-
await projectDocsManager.createOrLinkProjectDocs(
|
203
|
-
testProjectPath,
|
204
|
-
{},
|
205
|
-
{ requirements: join(testProjectPath, 'README.md') }
|
206
|
-
);
|
207
|
-
|
208
|
-
const isSymlink = await projectDocsManager.isSymlink(
|
209
|
-
testProjectPath,
|
210
|
-
'requirements'
|
211
|
-
);
|
212
|
-
expect(isSymlink).toBe(true);
|
213
|
-
|
214
|
-
const isArchSymlink = await projectDocsManager.isSymlink(
|
215
|
-
testProjectPath,
|
216
|
-
'architecture'
|
217
|
-
);
|
218
|
-
expect(isArchSymlink).toBe(false);
|
219
|
-
});
|
220
|
-
});
|
221
|
-
|
222
|
-
describe('End-to-End File Linking', () => {
|
223
|
-
it('should support complete file linking workflow', async () => {
|
224
|
-
// 1. Detect existing files
|
225
|
-
const detectionResult =
|
226
|
-
await fileDetectionManager.detectDocumentationFiles();
|
227
|
-
expect(detectionResult.requirements.length).toBeGreaterThan(0);
|
228
|
-
|
229
|
-
// 2. Validate file paths
|
230
|
-
const readmePath = join(testProjectPath, 'README.md');
|
231
|
-
const validation = await PathValidationUtils.validateFilePath(
|
232
|
-
'README.md',
|
233
|
-
testProjectPath
|
234
|
-
);
|
235
|
-
expect(validation.isValid).toBe(true);
|
236
|
-
|
237
|
-
// 3. Create symlinks
|
238
|
-
const linkResult = await projectDocsManager.createOrLinkProjectDocs(
|
239
|
-
testProjectPath,
|
240
|
-
{ architecture: 'freestyle' }, // Mix of template and file
|
241
|
-
{ requirements: readmePath }
|
242
|
-
);
|
243
|
-
|
244
|
-
expect(linkResult.created).toContain('architecture.md');
|
245
|
-
expect(linkResult.linked).toContain('requirements.md');
|
246
|
-
|
247
|
-
// 4. Verify symlinks work
|
248
|
-
const requirementsPath = await projectDocsManager.readDocument(
|
249
|
-
testProjectPath,
|
250
|
-
'requirements'
|
251
|
-
);
|
252
|
-
expect(requirementsPath).toContain('requirements.md');
|
253
|
-
expect(requirementsPath).toContain('.vibe/docs');
|
254
|
-
});
|
255
|
-
});
|
256
|
-
});
|
@@ -1,91 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Git Commit Integration Tests
|
3
|
-
*
|
4
|
-
* Simple tests to verify that the commit_behaviour parameter is handled correctly
|
5
|
-
* and that the dynamic tool descriptions work as expected
|
6
|
-
*/
|
7
|
-
|
8
|
-
import { describe, it, expect } from 'vitest';
|
9
|
-
import { GitManager } from '@codemcp/workflows-core';
|
10
|
-
|
11
|
-
describe('Git Commit Integration', () => {
|
12
|
-
describe('GitManager Repository Detection', () => {
|
13
|
-
it('should detect git repositories correctly', () => {
|
14
|
-
// This test verifies that GitManager can detect git repositories
|
15
|
-
// The actual detection logic is tested in git-manager.test.ts
|
16
|
-
expect(typeof GitManager.isGitRepository).toBe('function');
|
17
|
-
expect(typeof GitManager.getCurrentBranch).toBe('function');
|
18
|
-
expect(typeof GitManager.getCurrentCommitHash).toBe('function');
|
19
|
-
});
|
20
|
-
});
|
21
|
-
|
22
|
-
describe('Commit Behaviour Parameter', () => {
|
23
|
-
it('should define all expected commit behaviour options', () => {
|
24
|
-
// This test verifies that all expected commit behaviour options are available
|
25
|
-
const expectedOptions = ['step', 'phase', 'end', 'none'];
|
26
|
-
|
27
|
-
// These are the options that should be available in the MCP tool description
|
28
|
-
for (const option of expectedOptions) {
|
29
|
-
expect(typeof option).toBe('string');
|
30
|
-
expect(option.length).toBeGreaterThan(0);
|
31
|
-
}
|
32
|
-
});
|
33
|
-
|
34
|
-
it('should have meaningful option descriptions', () => {
|
35
|
-
// This test verifies that the commit behaviour options have meaningful descriptions
|
36
|
-
const optionDescriptions = {
|
37
|
-
step: 'commit after each development step',
|
38
|
-
phase: 'commit before phase transitions',
|
39
|
-
end: 'final commit only',
|
40
|
-
none: 'no automatic commits',
|
41
|
-
};
|
42
|
-
|
43
|
-
for (const [option, description] of Object.entries(optionDescriptions)) {
|
44
|
-
expect(typeof option).toBe('string');
|
45
|
-
expect(typeof description).toBe('string');
|
46
|
-
expect(description.length).toBeGreaterThan(10);
|
47
|
-
}
|
48
|
-
});
|
49
|
-
});
|
50
|
-
|
51
|
-
describe('Dynamic Tool Description Logic', () => {
|
52
|
-
it('should provide different guidance for git vs non-git projects', () => {
|
53
|
-
// This test verifies the core logic of our dynamic tool descriptions
|
54
|
-
|
55
|
-
// Simulate git repository detection
|
56
|
-
const isGitRepo = true;
|
57
|
-
const gitDescription = isGitRepo
|
58
|
-
? 'Use "end" unless the user specifically requests different behavior.'
|
59
|
-
: 'Use "none" as this is not a git repository. Other options are not applicable for non-git projects.';
|
60
|
-
|
61
|
-
expect(gitDescription).toContain('Use "end"');
|
62
|
-
expect(gitDescription).toContain('unless the user specifically requests');
|
63
|
-
|
64
|
-
// Simulate non-git directory detection
|
65
|
-
const isNonGitRepo = false;
|
66
|
-
const nonGitDescription = isNonGitRepo
|
67
|
-
? 'Use "end" unless the user specifically requests different behavior.'
|
68
|
-
: 'Use "none" as this is not a git repository. Other options are not applicable for non-git projects.';
|
69
|
-
|
70
|
-
expect(nonGitDescription).toContain('Use "none"');
|
71
|
-
expect(nonGitDescription).toContain('not a git repository');
|
72
|
-
expect(nonGitDescription).toContain('not applicable');
|
73
|
-
|
74
|
-
// Verify the descriptions are different
|
75
|
-
expect(gitDescription).not.toBe(nonGitDescription);
|
76
|
-
});
|
77
|
-
|
78
|
-
it('should maintain all commit behavior options regardless of project type', () => {
|
79
|
-
// This test verifies that all options remain available regardless of git detection
|
80
|
-
const allOptions = ['step', 'phase', 'end', 'none'];
|
81
|
-
|
82
|
-
// Both git and non-git projects should have access to all options
|
83
|
-
// (the difference is in the guidance, not the available options)
|
84
|
-
for (const option of allOptions) {
|
85
|
-
expect(allOptions).toContain(option);
|
86
|
-
}
|
87
|
-
|
88
|
-
expect(allOptions).toHaveLength(4);
|
89
|
-
});
|
90
|
-
});
|
91
|
-
});
|
@@ -1,86 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* GitManager Tests
|
3
|
-
*/
|
4
|
-
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
6
|
-
import { GitManager } from '@codemcp/workflows-core';
|
7
|
-
import { execSync } from 'node:child_process';
|
8
|
-
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
9
|
-
import { resolve } from 'node:path';
|
10
|
-
|
11
|
-
describe('GitManager', () => {
|
12
|
-
const testDir = resolve(__dirname, 'test-git-repo');
|
13
|
-
|
14
|
-
beforeEach(() => {
|
15
|
-
// Clean up any existing test directory
|
16
|
-
try {
|
17
|
-
rmSync(testDir, { recursive: true, force: true });
|
18
|
-
} catch {
|
19
|
-
// Ignore if directory doesn't exist
|
20
|
-
}
|
21
|
-
|
22
|
-
// Create test directory
|
23
|
-
mkdirSync(testDir, { recursive: true });
|
24
|
-
|
25
|
-
// Initialize git repository
|
26
|
-
execSync('git init', { cwd: testDir, stdio: 'ignore' });
|
27
|
-
execSync('git config user.name "Test User"', {
|
28
|
-
cwd: testDir,
|
29
|
-
stdio: 'ignore',
|
30
|
-
});
|
31
|
-
execSync('git config user.email "test@example.com"', {
|
32
|
-
cwd: testDir,
|
33
|
-
stdio: 'ignore',
|
34
|
-
});
|
35
|
-
|
36
|
-
// Create initial commit
|
37
|
-
writeFileSync(resolve(testDir, 'README.md'), '# Test Repository');
|
38
|
-
execSync('git add .', { cwd: testDir, stdio: 'ignore' });
|
39
|
-
execSync('git commit -m "Initial commit"', {
|
40
|
-
cwd: testDir,
|
41
|
-
stdio: 'ignore',
|
42
|
-
});
|
43
|
-
});
|
44
|
-
|
45
|
-
afterEach(() => {
|
46
|
-
// Clean up test directory
|
47
|
-
try {
|
48
|
-
rmSync(testDir, { recursive: true, force: true });
|
49
|
-
} catch {
|
50
|
-
// Ignore cleanup errors
|
51
|
-
}
|
52
|
-
});
|
53
|
-
|
54
|
-
describe('isGitRepository', () => {
|
55
|
-
it('should detect git repository', () => {
|
56
|
-
expect(GitManager.isGitRepository(testDir)).toBe(true);
|
57
|
-
});
|
58
|
-
|
59
|
-
it('should detect non-git directory', () => {
|
60
|
-
const nonGitDir = resolve(__dirname, 'non-git-dir');
|
61
|
-
mkdirSync(nonGitDir, { recursive: true });
|
62
|
-
|
63
|
-
try {
|
64
|
-
expect(GitManager.isGitRepository(nonGitDir)).toBe(false);
|
65
|
-
} finally {
|
66
|
-
rmSync(nonGitDir, { recursive: true, force: true });
|
67
|
-
}
|
68
|
-
});
|
69
|
-
});
|
70
|
-
|
71
|
-
describe('getCurrentBranch', () => {
|
72
|
-
it('should get current branch name', () => {
|
73
|
-
const branch = GitManager.getCurrentBranch(testDir);
|
74
|
-
// CI environments may use different default branch names
|
75
|
-
expect(['main', 'master']).toContain(branch);
|
76
|
-
});
|
77
|
-
});
|
78
|
-
|
79
|
-
describe('getCurrentCommitHash', () => {
|
80
|
-
it('should get current commit hash', () => {
|
81
|
-
const hash = GitManager.getCurrentCommitHash(testDir);
|
82
|
-
expect(hash).toBeTruthy();
|
83
|
-
expect(hash).toMatch(/^[a-f0-9]{40}$/); // SHA-1 hash format
|
84
|
-
});
|
85
|
-
});
|
86
|
-
});
|
@@ -1,138 +0,0 @@
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
2
|
-
import { InstallWorkflowHandler } from '../../packages/mcp-server/src/tool-handlers/install-workflow.js';
|
3
|
-
import { WorkflowManager } from '@codemcp/workflows-core';
|
4
|
-
import fs from 'node:fs';
|
5
|
-
import path from 'node:path';
|
6
|
-
import { tmpdir } from 'node:os';
|
7
|
-
|
8
|
-
describe('Install Workflow', () => {
|
9
|
-
let testProjectPath: string;
|
10
|
-
let originalEnv: string | undefined;
|
11
|
-
|
12
|
-
beforeEach(() => {
|
13
|
-
originalEnv = process.env.VIBE_WORKFLOW_DOMAINS;
|
14
|
-
testProjectPath = fs.mkdtempSync(
|
15
|
-
path.join(tmpdir(), 'install-workflow-test-')
|
16
|
-
);
|
17
|
-
});
|
18
|
-
|
19
|
-
afterEach(() => {
|
20
|
-
if (originalEnv !== undefined) {
|
21
|
-
process.env.VIBE_WORKFLOW_DOMAINS = originalEnv;
|
22
|
-
} else {
|
23
|
-
delete process.env.VIBE_WORKFLOW_DOMAINS;
|
24
|
-
}
|
25
|
-
|
26
|
-
// Clean up test directory
|
27
|
-
fs.rmSync(testProjectPath, { recursive: true, force: true });
|
28
|
-
});
|
29
|
-
|
30
|
-
it('should install workflow and make it immediately available', async () => {
|
31
|
-
process.env.VIBE_WORKFLOW_DOMAINS = 'code';
|
32
|
-
|
33
|
-
const handler = new InstallWorkflowHandler();
|
34
|
-
const workflowManager = new WorkflowManager();
|
35
|
-
const context = { workflowManager, projectPath: testProjectPath } as {
|
36
|
-
workflowManager: WorkflowManager;
|
37
|
-
projectPath: string;
|
38
|
-
};
|
39
|
-
|
40
|
-
// Before installation - posts should not be available (office domain)
|
41
|
-
let workflows =
|
42
|
-
workflowManager.getAvailableWorkflowsForProject(testProjectPath);
|
43
|
-
expect(workflows.some(w => w.name === 'posts')).toBe(false);
|
44
|
-
|
45
|
-
// Install posts workflow
|
46
|
-
const result = await handler.executeHandler({ source: 'posts' }, context);
|
47
|
-
expect(result.success).toBe(true);
|
48
|
-
|
49
|
-
// After installation - posts should be available (project workflows ignore domain filtering)
|
50
|
-
workflows =
|
51
|
-
workflowManager.getAvailableWorkflowsForProject(testProjectPath);
|
52
|
-
expect(workflows.some(w => w.name === 'posts')).toBe(true);
|
53
|
-
});
|
54
|
-
|
55
|
-
it('should prevent overwriting existing workflows', async () => {
|
56
|
-
const handler = new InstallWorkflowHandler();
|
57
|
-
const workflowManager = new WorkflowManager();
|
58
|
-
const context = { workflowManager, projectPath: testProjectPath } as {
|
59
|
-
workflowManager: WorkflowManager;
|
60
|
-
projectPath: string;
|
61
|
-
};
|
62
|
-
|
63
|
-
// Install workflow first time
|
64
|
-
const result1 = await handler.executeHandler({ source: 'posts' }, context);
|
65
|
-
expect(result1.success).toBe(true);
|
66
|
-
|
67
|
-
// Try to install same workflow again
|
68
|
-
const result2 = await handler.executeHandler({ source: 'posts' }, context);
|
69
|
-
expect(result2.success).toBe(false);
|
70
|
-
expect(result2.message).toContain('already exists');
|
71
|
-
});
|
72
|
-
|
73
|
-
it('should install with custom name', async () => {
|
74
|
-
const handler = new InstallWorkflowHandler();
|
75
|
-
const workflowManager = new WorkflowManager();
|
76
|
-
const context = { workflowManager, projectPath: testProjectPath } as {
|
77
|
-
workflowManager: WorkflowManager;
|
78
|
-
projectPath: string;
|
79
|
-
};
|
80
|
-
|
81
|
-
// Install with custom name
|
82
|
-
const result = await handler.executeHandler(
|
83
|
-
{
|
84
|
-
source: 'posts',
|
85
|
-
name: 'my-posts',
|
86
|
-
},
|
87
|
-
context
|
88
|
-
);
|
89
|
-
|
90
|
-
expect(result.success).toBe(true);
|
91
|
-
expect(result.installedPath).toContain('my-posts.yaml');
|
92
|
-
|
93
|
-
// Check file exists with custom name
|
94
|
-
const customFile = path.join(
|
95
|
-
testProjectPath,
|
96
|
-
'.vibe',
|
97
|
-
'workflows',
|
98
|
-
'my-posts.yaml'
|
99
|
-
);
|
100
|
-
expect(fs.existsSync(customFile)).toBe(true);
|
101
|
-
});
|
102
|
-
|
103
|
-
it('should handle non-existent workflow', async () => {
|
104
|
-
const handler = new InstallWorkflowHandler();
|
105
|
-
const workflowManager = new WorkflowManager();
|
106
|
-
const context = { workflowManager, projectPath: testProjectPath } as {
|
107
|
-
workflowManager: WorkflowManager;
|
108
|
-
projectPath: string;
|
109
|
-
};
|
110
|
-
|
111
|
-
const result = await handler.executeHandler(
|
112
|
-
{ source: 'nonexistent' },
|
113
|
-
context
|
114
|
-
);
|
115
|
-
expect(result.success).toBe(false);
|
116
|
-
expect(result.message).toContain('not found');
|
117
|
-
});
|
118
|
-
|
119
|
-
it('should create .vibe/workflows directory if it does not exist', async () => {
|
120
|
-
const handler = new InstallWorkflowHandler();
|
121
|
-
const workflowManager = new WorkflowManager();
|
122
|
-
const context = { workflowManager, projectPath: testProjectPath } as {
|
123
|
-
workflowManager: WorkflowManager;
|
124
|
-
projectPath: string;
|
125
|
-
};
|
126
|
-
|
127
|
-
// Ensure directory doesn't exist
|
128
|
-
const workflowsDir = path.join(testProjectPath, '.vibe', 'workflows');
|
129
|
-
expect(fs.existsSync(workflowsDir)).toBe(false);
|
130
|
-
|
131
|
-
// Install workflow
|
132
|
-
const result = await handler.executeHandler({ source: 'posts' }, context);
|
133
|
-
expect(result.success).toBe(true);
|
134
|
-
|
135
|
-
// Directory should now exist
|
136
|
-
expect(fs.existsSync(workflowsDir)).toBe(true);
|
137
|
-
});
|
138
|
-
});
|