@codemcp/workflows 5.0.0 → 5.1.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 (77) hide show
  1. package/SKILL.md +23 -0
  2. package/package.json +6 -2
  3. package/.prettierignore +0 -2
  4. package/.turbo/turbo-build.log +0 -4
  5. package/.vibe/conversation-state.sqlite +0 -0
  6. package/src/components/beads/beads-instruction-generator.ts +0 -230
  7. package/src/components/beads/beads-plan-manager.ts +0 -333
  8. package/src/components/beads/beads-task-backend-client.ts +0 -229
  9. package/src/index.ts +0 -93
  10. package/src/notification-service.ts +0 -23
  11. package/src/plugin-system/beads-plugin.ts +0 -649
  12. package/src/plugin-system/commit-plugin.ts +0 -252
  13. package/src/plugin-system/index.ts +0 -20
  14. package/src/plugin-system/plugin-interfaces.ts +0 -153
  15. package/src/plugin-system/plugin-registry.ts +0 -190
  16. package/src/resource-handlers/conversation-state.ts +0 -55
  17. package/src/resource-handlers/development-plan.ts +0 -48
  18. package/src/resource-handlers/index.ts +0 -73
  19. package/src/resource-handlers/system-prompt.ts +0 -55
  20. package/src/resource-handlers/workflow-resource.ts +0 -132
  21. package/src/response-renderer.ts +0 -116
  22. package/src/server-config.ts +0 -760
  23. package/src/server-helpers.ts +0 -245
  24. package/src/server-implementation.ts +0 -277
  25. package/src/server.ts +0 -9
  26. package/src/tool-handlers/base-tool-handler.ts +0 -151
  27. package/src/tool-handlers/conduct-review.ts +0 -190
  28. package/src/tool-handlers/get-tool-info.ts +0 -273
  29. package/src/tool-handlers/index.ts +0 -115
  30. package/src/tool-handlers/list-workflows.ts +0 -78
  31. package/src/tool-handlers/no-idea.ts +0 -47
  32. package/src/tool-handlers/proceed-to-phase.ts +0 -296
  33. package/src/tool-handlers/reset-development.ts +0 -90
  34. package/src/tool-handlers/resume-workflow.ts +0 -378
  35. package/src/tool-handlers/setup-project-docs.ts +0 -232
  36. package/src/tool-handlers/start-development.ts +0 -746
  37. package/src/tool-handlers/whats-next.ts +0 -246
  38. package/src/types.ts +0 -135
  39. package/src/version-info.ts +0 -213
  40. package/test/e2e/beads-plugin-integration.test.ts +0 -1623
  41. package/test/e2e/commit-plugin-integration.test.ts +0 -222
  42. package/test/e2e/core-functionality.test.ts +0 -167
  43. package/test/e2e/git-branch-detection.test.ts +0 -351
  44. package/test/e2e/mcp-contract.test.ts +0 -509
  45. package/test/e2e/plan-management.test.ts +0 -334
  46. package/test/e2e/plugin-system-integration.test.ts +0 -1410
  47. package/test/e2e/state-management.test.ts +0 -387
  48. package/test/e2e/workflow-integration.test.ts +0 -498
  49. package/test/unit/beads-instruction-generator.test.ts +0 -979
  50. package/test/unit/beads-phase-task-id-integration.test.ts +0 -535
  51. package/test/unit/beads-plugin-behavioral.test.ts +0 -545
  52. package/test/unit/beads-plugin.test.ts +0 -117
  53. package/test/unit/commit-plugin.test.ts +0 -196
  54. package/test/unit/conduct-review.test.ts +0 -151
  55. package/test/unit/conversation-not-found-error.test.ts +0 -120
  56. package/test/unit/plugin-error-handling.test.ts +0 -240
  57. package/test/unit/proceed-to-phase-plugin-integration.test.ts +0 -150
  58. package/test/unit/reset-functionality.test.ts +0 -72
  59. package/test/unit/resume-workflow.test.ts +0 -193
  60. package/test/unit/server-config-plugin-registry.test.ts +0 -99
  61. package/test/unit/server-tools.test.ts +0 -310
  62. package/test/unit/setup-project-docs-handler.test.ts +0 -268
  63. package/test/unit/start-development-artifact-detection.test.ts +0 -387
  64. package/test/unit/start-development-gitignore.test.ts +0 -178
  65. package/test/unit/start-development-goal-extraction.test.ts +0 -226
  66. package/test/unit/system-prompt-resource.test.ts +0 -102
  67. package/test/unit/tool-handlers/no-idea.test.ts +0 -40
  68. package/test/utils/e2e-test-setup.ts +0 -451
  69. package/test/utils/run-server-in-dir.sh +0 -27
  70. package/test/utils/temp-files.ts +0 -320
  71. package/test/utils/test-access.ts +0 -79
  72. package/test/utils/test-helpers.ts +0 -288
  73. package/test/utils/test-setup.ts +0 -77
  74. package/tsconfig.build.json +0 -10
  75. package/tsconfig.build.tsbuildinfo +0 -1
  76. package/tsconfig.json +0 -12
  77. package/vitest.config.ts +0 -19
@@ -1,222 +0,0 @@
1
- /**
2
- * Integration test for CommitPlugin end-to-end behavior
3
- */
4
-
5
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
6
- import { execSync } from 'node:child_process';
7
- import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
8
- import { resolve } from 'node:path';
9
- import { initializeServerComponents } from '../../src/server-config.js';
10
-
11
- describe('CommitPlugin Integration', () => {
12
- const testDir = resolve(__dirname, 'test-commit-plugin');
13
- let originalEnv: Record<string, string | undefined>;
14
-
15
- beforeEach(() => {
16
- // Save original environment
17
- originalEnv = {
18
- COMMIT_BEHAVIOR: process.env.COMMIT_BEHAVIOR,
19
- COMMIT_MESSAGE_TEMPLATE: process.env.COMMIT_MESSAGE_TEMPLATE,
20
- };
21
-
22
- // Clean up any existing test directory
23
- try {
24
- rmSync(testDir, { recursive: true, force: true });
25
- } catch {
26
- // Ignore if directory doesn't exist
27
- }
28
-
29
- // Create test git repository
30
- mkdirSync(testDir, { recursive: true });
31
- execSync('git init', { cwd: testDir });
32
- execSync('git config user.name "Test User"', { cwd: testDir });
33
- execSync('git config user.email "test@example.com"', { cwd: testDir });
34
-
35
- // Create initial commit
36
- writeFileSync(resolve(testDir, 'README.md'), '# Test Project\n');
37
- execSync('git add .', { cwd: testDir });
38
- execSync('git commit -m "Initial commit"', { cwd: testDir });
39
- });
40
-
41
- afterEach(() => {
42
- // Restore original environment
43
- for (const [key, value] of Object.entries(originalEnv)) {
44
- if (value === undefined) {
45
- delete process.env[key];
46
- } else {
47
- process.env[key] = value;
48
- }
49
- }
50
-
51
- // Clean up test directory
52
- try {
53
- rmSync(testDir, { recursive: true, force: true });
54
- } catch {
55
- // Ignore cleanup errors
56
- }
57
- });
58
-
59
- it('should register CommitPlugin when COMMIT_BEHAVIOR is set', async () => {
60
- // Arrange
61
- process.env.COMMIT_BEHAVIOR = 'step';
62
-
63
- // Act
64
- const components = await initializeServerComponents({
65
- projectPath: testDir,
66
- });
67
-
68
- // Assert
69
- expect(components.context.pluginRegistry).toBeDefined();
70
- const plugins = components.context.pluginRegistry.getEnabledPlugins();
71
- const commitPlugin = plugins.find(p => p.getName() === 'CommitPlugin');
72
- expect(commitPlugin).toBeDefined();
73
- expect(commitPlugin?.getSequence()).toBe(50);
74
- });
75
-
76
- it('should not register CommitPlugin when COMMIT_BEHAVIOR is not set', async () => {
77
- // Arrange - no COMMIT_BEHAVIOR set
78
-
79
- // Act
80
- const components = await initializeServerComponents({
81
- projectPath: testDir,
82
- });
83
-
84
- // Assert
85
- const plugins = components.context.pluginRegistry.getEnabledPlugins();
86
- const commitPlugin = plugins.find(p => p.getName() === 'CommitPlugin');
87
- expect(commitPlugin).toBeUndefined();
88
- });
89
-
90
- it('should add final commit task to plan file when COMMIT_BEHAVIOR=end', async () => {
91
- // Arrange
92
- process.env.COMMIT_BEHAVIOR = 'end';
93
- // Don't set COMMIT_MESSAGE_TEMPLATE to use default message
94
-
95
- // Act
96
- const components = await initializeServerComponents({
97
- projectPath: testDir,
98
- });
99
-
100
- // Create a mock plan file content
101
- const mockPlanContent = `# Test Plan
102
-
103
- ## Explore
104
- ### Tasks
105
- - [ ] Research the problem
106
-
107
- ## Code
108
- ### Tasks
109
- - [ ] Implement solution
110
-
111
- ## Commit
112
- ### Tasks
113
- - [ ] Review implementation
114
- `;
115
-
116
- // Execute the afterPlanFileCreated hook
117
- const plugins = components.context.pluginRegistry.getEnabledPlugins();
118
- const commitPlugin = plugins.find(p => p.getName() === 'CommitPlugin');
119
- const hooks = commitPlugin?.getHooks();
120
-
121
- if (hooks?.afterPlanFileCreated) {
122
- const mockContext = {
123
- conversationId: 'test',
124
- planFilePath: resolve(testDir, 'plan.md'),
125
- currentPhase: 'explore',
126
- workflow: 'epcc',
127
- projectPath: testDir,
128
- gitBranch: 'main',
129
- };
130
-
131
- const updatedContent = await hooks.afterPlanFileCreated(
132
- mockContext,
133
- resolve(testDir, 'plan.md'),
134
- mockPlanContent
135
- );
136
-
137
- // Assert
138
- expect(updatedContent).toContain('Create a conventional commit');
139
- expect(updatedContent).toContain(
140
- 'summarize the intentions and key decisions'
141
- );
142
- }
143
- });
144
-
145
- it('should add squash commit task for step/phase modes', async () => {
146
- // Arrange
147
- process.env.COMMIT_BEHAVIOR = 'step';
148
-
149
- // Act
150
- const components = await initializeServerComponents({
151
- projectPath: testDir,
152
- });
153
-
154
- const mockPlanContent = `## Commit
155
- ### Tasks
156
- - [ ] Review implementation
157
- `;
158
-
159
- const plugins = components.context.pluginRegistry.getEnabledPlugins();
160
- const commitPlugin = plugins.find(p => p.getName() === 'CommitPlugin');
161
- const hooks = commitPlugin?.getHooks();
162
-
163
- if (hooks?.afterPlanFileCreated) {
164
- const mockContext = {
165
- conversationId: 'test',
166
- planFilePath: resolve(testDir, 'plan.md'),
167
- currentPhase: 'explore',
168
- workflow: 'epcc',
169
- projectPath: testDir,
170
- gitBranch: 'main',
171
- };
172
-
173
- const updatedContent = await hooks.afterPlanFileCreated(
174
- mockContext,
175
- resolve(testDir, 'plan.md'),
176
- mockPlanContent
177
- );
178
-
179
- // Assert
180
- expect(updatedContent).toContain('Squash WIP commits:');
181
- expect(updatedContent).toContain('git reset --soft');
182
- }
183
- });
184
-
185
- it('should create WIP commit on phase transition', async () => {
186
- // Arrange
187
- process.env.COMMIT_BEHAVIOR = 'phase';
188
-
189
- // Create some changes
190
- writeFileSync(resolve(testDir, 'test.txt'), 'test content');
191
-
192
- // Act
193
- const components = await initializeServerComponents({
194
- projectPath: testDir,
195
- });
196
-
197
- const plugins = components.context.pluginRegistry.getEnabledPlugins();
198
- const commitPlugin = plugins.find(p => p.getName() === 'CommitPlugin');
199
- const hooks = commitPlugin?.getHooks();
200
-
201
- if (hooks?.beforePhaseTransition) {
202
- const mockContext = {
203
- conversationId: 'test',
204
- planFilePath: resolve(testDir, 'plan.md'),
205
- currentPhase: 'explore',
206
- workflow: 'epcc',
207
- projectPath: testDir,
208
- gitBranch: 'main',
209
- targetPhase: 'plan',
210
- };
211
-
212
- await hooks.beforePhaseTransition(mockContext, 'explore', 'plan');
213
-
214
- // Assert - check git log for WIP commit
215
- const gitLog = execSync('git log --oneline', {
216
- cwd: testDir,
217
- encoding: 'utf-8',
218
- });
219
- expect(gitLog).toContain('WIP: transition to plan');
220
- }
221
- });
222
- });
@@ -1,167 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { createTempProjectWithDefaultStateMachine } from '../utils/temp-files';
3
- import {
4
- DirectServerInterface,
5
- createSuiteIsolatedE2EScenario,
6
- assertToolSuccess,
7
- initializeDevelopment,
8
- } from '../utils/e2e-test-setup';
9
-
10
- vi.unmock('fs');
11
- vi.unmock('fs/promises');
12
-
13
- /**
14
- * Core Functionality Tests
15
- *
16
- * Tests the essential server operations including:
17
- * - Server initialization and basic tool operations
18
- * - Resource access (plan and state resources)
19
- * - Basic conversation management
20
- * - Error handling and graceful failures
21
- */
22
- describe('Core Functionality', () => {
23
- let client: DirectServerInterface;
24
- let cleanup: () => Promise<void>;
25
-
26
- beforeEach(async () => {
27
- const scenario = await createSuiteIsolatedE2EScenario({
28
- suiteName: 'core-functionality',
29
- tempProjectFactory: createTempProjectWithDefaultStateMachine,
30
- });
31
- client = scenario.client;
32
- cleanup = scenario.cleanup;
33
-
34
- // Initialize development with default workflow before each test
35
- await initializeDevelopment(client);
36
- });
37
-
38
- afterEach(async () => {
39
- if (cleanup) {
40
- await cleanup();
41
- }
42
- });
43
-
44
- describe('Server Initialization', () => {
45
- it('should initialize server and provide tools', async () => {
46
- const tools = await client.listTools();
47
- expect(tools.tools).toBeTruthy();
48
- expect(tools.tools).toHaveLength(2);
49
- expect(tools.tools.map(t => t.name)).toContain('whats_next');
50
- expect(tools.tools.map(t => t.name)).toContain('proceed_to_phase');
51
- });
52
-
53
- it('should provide resources', async () => {
54
- const resources = await client.listResources();
55
- expect(resources.resources).toBeTruthy();
56
- expect(resources.resources).toHaveLength(3);
57
- expect(resources.resources.map(r => r.uri)).toContain('plan://current');
58
- expect(resources.resources.map(r => r.uri)).toContain('state://current');
59
- expect(resources.resources.map(r => r.uri)).toContain('system-prompt://');
60
- });
61
- });
62
-
63
- describe('Basic Tool Operations', () => {
64
- it('should handle whats_next tool calls', async () => {
65
- const result = await client.callTool('whats_next', {
66
- user_input: 'implement authentication',
67
- });
68
- const response = assertToolSuccess(result);
69
-
70
- expect(response.phase).toBeTruthy();
71
- expect(response.instructions).toBeTruthy();
72
- expect(response.plan_file_path).toBeTruthy();
73
- });
74
-
75
- it('should handle proceed_to_phase tool calls', async () => {
76
- // First establish a conversation
77
- await client.callTool('whats_next', { user_input: 'start project' });
78
-
79
- const result = await client.callTool('proceed_to_phase', {
80
- target_phase: 'design',
81
- reason: 'requirements complete',
82
- review_state: 'not-required',
83
- });
84
- const response = assertToolSuccess(result);
85
-
86
- expect(response.phase).toBe('design');
87
- expect(response.instructions).toBeTruthy();
88
- });
89
- });
90
-
91
- describe('Resource Access', () => {
92
- it('should provide plan resource as markdown', async () => {
93
- // Initialize conversation to create plan file
94
- await client.callTool('whats_next', { user_input: 'test project' });
95
-
96
- const planResource = await client.readResource('plan://current');
97
- expect(planResource.contents).toHaveLength(1);
98
- expect(planResource.contents[0].mimeType).toBe('text/markdown');
99
- expect(planResource.contents[0].text).toContain('# Development Plan');
100
- });
101
-
102
- it('should provide state resource as JSON', async () => {
103
- // Initialize conversation
104
- await client.callTool('whats_next', { user_input: 'test project' });
105
-
106
- const stateResource = await client.readResource('state://current');
107
- expect(stateResource.contents).toHaveLength(1);
108
- expect(stateResource.contents[0].mimeType).toBe('application/json');
109
-
110
- const stateData = JSON.parse(stateResource.contents[0].text);
111
- expect(stateData.conversationId).toBeTruthy();
112
- expect(stateData.currentPhase).toBeTruthy();
113
- });
114
- });
115
-
116
- describe('Error Handling', () => {
117
- it('should handle invalid tool parameters gracefully', async () => {
118
- const result = await client.callTool('proceed_to_phase', {
119
- target_phase: 'invalid_phase',
120
- reason: 'test',
121
- review_state: 'not-required',
122
- });
123
-
124
- // Should not throw, but may return error or fallback behavior
125
- expect(result).toBeTruthy();
126
- });
127
-
128
- it('should handle missing parameters gracefully', async () => {
129
- const result = await client.callTool('whats_next', {});
130
- const response = assertToolSuccess(result);
131
-
132
- // Should still work with empty parameters
133
- expect(response.phase).toBeTruthy();
134
- expect(response.instructions).toBeTruthy();
135
- });
136
-
137
- it('should handle database errors gracefully', async () => {
138
- // This test would require mocking database failures
139
- // For now, verify basic resilience
140
- const result = await client.callTool('whats_next', {
141
- user_input: 'test resilience',
142
- });
143
-
144
- expect(assertToolSuccess(result)).toBeTruthy();
145
- });
146
- });
147
-
148
- describe('Basic Conversation Management', () => {
149
- it('should create new conversations', async () => {
150
- await client.callTool('whats_next', {
151
- user_input: 'new feature request',
152
- });
153
- });
154
-
155
- it('should maintain conversation state across calls', async () => {
156
- const first = await client.callTool('whats_next', {
157
- user_input: 'start project',
158
- });
159
- assertToolSuccess(first);
160
-
161
- const second = await client.callTool('whats_next', {
162
- user_input: 'continue project',
163
- });
164
- assertToolSuccess(second);
165
- });
166
- });
167
- });