@codemcp/workflows 5.0.1 → 5.1.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.
Files changed (77) hide show
  1. package/package.json +6 -2
  2. package/skill/SKILL.md +23 -0
  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,498 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import {
3
- TempProject,
4
- createTempProjectWithDefaultStateMachine,
5
- } from '../utils/temp-files';
6
- import {
7
- DirectServerInterface,
8
- createSuiteIsolatedE2EScenario,
9
- assertToolSuccess,
10
- initializeDevelopment,
11
- } from '../utils/e2e-test-setup';
12
- import { promises as fs } from 'node:fs';
13
- import path from 'node:path';
14
- import { McpToolResponse } from '../../src/types';
15
-
16
- vi.unmock('fs');
17
- vi.unmock('fs/promises');
18
-
19
- /**
20
- * Workflow Integration Tests
21
- *
22
- * Tests complete end-to-end workflows including:
23
- * - Full development lifecycle scenarios
24
- * - Multi-phase project progression
25
- * - Real-world usage patterns
26
- * - Integration between all components
27
- */
28
- describe('Workflow Integration', () => {
29
- let client: DirectServerInterface;
30
- let tempProject: TempProject;
31
- let cleanup: () => Promise<void>;
32
-
33
- beforeEach(async () => {
34
- const scenario = await createSuiteIsolatedE2EScenario({
35
- suiteName: 'workflow-integration',
36
- tempProjectFactory: createTempProjectWithDefaultStateMachine,
37
- });
38
- client = scenario.client;
39
- tempProject = scenario.tempProject;
40
- cleanup = scenario.cleanup;
41
-
42
- // Start development for all workflow integration tests
43
- await initializeDevelopment(client, 'waterfall');
44
- });
45
-
46
- afterEach(async () => {
47
- if (cleanup) {
48
- await cleanup();
49
- }
50
- });
51
-
52
- describe('Complete Development Lifecycle', () => {
53
- it('should handle full feature development workflow', async () => {
54
- // 1. Start with requirements
55
- const requirements = await client.callTool('whats_next', {
56
- user_input: 'implement user authentication system',
57
- context: 'new feature request',
58
- conversation_summary: 'User wants to add authentication to their app',
59
- });
60
- const reqResponse = assertToolSuccess(requirements);
61
- expect(reqResponse.phase).toBe('requirements');
62
- expect(reqResponse.instructions).toContain('requirements');
63
-
64
- // 2. Transition to design
65
- const design = await client.callTool('proceed_to_phase', {
66
- target_phase: 'design',
67
- reason: 'requirements analysis complete',
68
- review_state: 'not-required',
69
- });
70
- const designResponse = assertToolSuccess(design);
71
- expect(designResponse.phase).toBe('design');
72
- expect(designResponse.instructions).toContain('design');
73
-
74
- // 3. Move to implementation
75
- const implementation = await client.callTool('proceed_to_phase', {
76
- target_phase: 'implementation',
77
- reason: 'design approved',
78
- review_state: 'not-required',
79
- });
80
- const implResponse = assertToolSuccess(implementation);
81
- expect(implResponse.phase).toBe('implementation');
82
-
83
- // 4. Quality assurance
84
- const qa = await client.callTool('proceed_to_phase', {
85
- target_phase: 'qa',
86
- reason: 'implementation complete',
87
- review_state: 'not-required',
88
- });
89
- const qaResponse = assertToolSuccess(qa);
90
- expect(qaResponse.phase).toBe('qa');
91
-
92
- // 5. Testing phase
93
- const testing = await client.callTool('proceed_to_phase', {
94
- target_phase: 'testing',
95
- reason: 'qa passed',
96
- review_state: 'not-required',
97
- });
98
- const testResponse = assertToolSuccess(testing);
99
- expect(testResponse.phase).toBe('testing');
100
-
101
- // 6. Finalize
102
- const finalize = await client.callTool('proceed_to_phase', {
103
- target_phase: 'finalize',
104
- reason: 'all tests passed',
105
- review_state: 'not-required',
106
- });
107
- const finalizeResponse = assertToolSuccess(finalize);
108
- expect(finalizeResponse.phase).toBe('finalize');
109
-
110
- // Verify final state
111
- const stateResource = await client.readResource('state://current');
112
- const stateData = JSON.parse(stateResource.contents[0].text);
113
- expect(stateData.currentPhase).toBe('finalize');
114
- });
115
-
116
- it('should handle iterative development with phase revisiting', async () => {
117
- // Start project
118
- await client.callTool('whats_next', { user_input: 'start project' });
119
-
120
- // Go to implementation
121
- await client.callTool('proceed_to_phase', {
122
- target_phase: 'implementation',
123
- reason: 'quick prototype',
124
- review_state: 'not-required',
125
- });
126
-
127
- // Realize need to go back to design
128
- const backToDesign = await client.callTool('proceed_to_phase', {
129
- target_phase: 'design',
130
- reason: 'need to revise architecture',
131
- review_state: 'not-required',
132
- });
133
- expect(assertToolSuccess(backToDesign).phase).toBe('design');
134
-
135
- // Forward to implementation again
136
- const backToImpl = await client.callTool('proceed_to_phase', {
137
- target_phase: 'implementation',
138
- reason: 'design revised',
139
- review_state: 'not-required',
140
- });
141
- expect(assertToolSuccess(backToImpl).phase).toBe('implementation');
142
-
143
- // Verify state consistency throughout
144
- const stateResource = await client.readResource('state://current');
145
- const stateData = JSON.parse(stateResource.contents[0].text);
146
- expect(stateData.currentPhase).toBe('implementation');
147
- });
148
-
149
- it('should maintain plan file consistency throughout workflow', async () => {
150
- // Start workflow
151
- const start = await client.callTool('whats_next', {
152
- user_input: 'comprehensive project',
153
- });
154
- const startResponse = assertToolSuccess(start);
155
- const planPath = startResponse.plan_file_path;
156
-
157
- // Progress through phases
158
- await client.callTool('proceed_to_phase', {
159
- target_phase: 'design',
160
- reason: 'test',
161
- review_state: 'not-required',
162
- });
163
- await client.callTool('proceed_to_phase', {
164
- target_phase: 'implementation',
165
- reason: 'test',
166
- review_state: 'not-required',
167
- });
168
- await client.callTool('proceed_to_phase', {
169
- target_phase: 'qa',
170
- reason: 'test',
171
- review_state: 'not-required',
172
- });
173
-
174
- // Verify plan file exists and is updated
175
- const planExists = await fs
176
- .access(planPath)
177
- .then(() => true)
178
- .catch(() => false);
179
- expect(planExists).toBe(true);
180
-
181
- const planResource = await client.readResource('plan://current');
182
- const planContent = planResource.contents[0].text;
183
-
184
- // Should contain all phase sections
185
- expect(planContent).toContain('Requirements');
186
- expect(planContent).toContain('Design');
187
- expect(planContent).toContain('Implementation');
188
- expect(planContent).toContain('## Qa');
189
- });
190
- });
191
-
192
- describe('Multi-Project Scenarios', () => {
193
- it('should handle project context switching', async () => {
194
- // Start first project context
195
- const project1 = await client.callTool('whats_next', {
196
- user_input: 'project 1 feature',
197
- context: 'first project',
198
- });
199
- assertToolSuccess(project1);
200
-
201
- // Continue with same project
202
- const project1Continue = await client.callTool('whats_next', {
203
- user_input: 'continue project 1',
204
- context: 'same project context',
205
- });
206
- assertToolSuccess(project1Continue);
207
- });
208
-
209
- it('should maintain separate plan files for different contexts', async () => {
210
- const result = await client.callTool('whats_next', {
211
- user_input: 'test plan separation',
212
- });
213
- const response = assertToolSuccess(result);
214
-
215
- // Plan file should be specific to this project/branch context
216
- expect(response.plan_file_path).toContain(tempProject.projectPath);
217
- expect(response.plan_file_path).toContain('.vibe');
218
- });
219
- });
220
-
221
- describe('Real-World Usage Patterns', () => {
222
- it('should handle typical user interaction patterns', async () => {
223
- // User starts with vague request
224
- const vague = await client.callTool('whats_next', {
225
- user_input: 'I need to add some features',
226
- context: 'user has general idea',
227
- });
228
- expect(assertToolSuccess(vague).phase).toBe('requirements');
229
-
230
- // User provides more specific information
231
- const specific = await client.callTool('whats_next', {
232
- user_input: 'I need user login and dashboard',
233
- context: 'user clarified requirements',
234
- conversation_summary: 'User wants login and dashboard features',
235
- });
236
- const specificResponse = assertToolSuccess(specific);
237
- expect(specificResponse.phase).toBe('requirements');
238
-
239
- // User ready to move forward
240
- const ready = await client.callTool('proceed_to_phase', {
241
- target_phase: 'design',
242
- reason: 'requirements clear',
243
- review_state: 'not-required',
244
- });
245
- expect(assertToolSuccess(ready).phase).toBe('design');
246
- });
247
-
248
- it('should handle context-rich conversations', async () => {
249
- const result = await client.callTool('whats_next', {
250
- user_input: 'implement OAuth integration',
251
- context: 'user wants third-party authentication',
252
- conversation_summary:
253
- 'Discussed authentication options, user prefers OAuth with Google and GitHub',
254
- recent_messages: [
255
- { role: 'user', content: 'What authentication options do we have?' },
256
- {
257
- role: 'assistant',
258
- content: 'We can use OAuth, JWT, or traditional sessions',
259
- },
260
- {
261
- role: 'user',
262
- content: 'OAuth sounds good, especially Google and GitHub',
263
- },
264
- {
265
- role: 'assistant',
266
- content: 'Great choice! OAuth is secure and user-friendly',
267
- },
268
- ],
269
- });
270
-
271
- const response = assertToolSuccess(result);
272
- expect(response.phase).toBeTruthy();
273
- expect(response.instructions).toBeTruthy();
274
- });
275
-
276
- it('should handle rapid development iterations', async () => {
277
- // Quick succession of development activities
278
- await client.callTool('whats_next', { user_input: 'rapid prototype' });
279
- const impl1 = await client.callTool('proceed_to_phase', {
280
- target_phase: 'implementation',
281
- reason: 'skip to coding',
282
- review_state: 'not-required',
283
- });
284
- const impl1Response = assertToolSuccess(impl1);
285
- expect(impl1Response.phase).toBe('implementation');
286
-
287
- await client.callTool('whats_next', { user_input: 'found issues' });
288
- const designResult = await client.callTool('proceed_to_phase', {
289
- target_phase: 'design',
290
- reason: 'need better design',
291
- review_state: 'not-required',
292
- });
293
- const designResponse = assertToolSuccess(designResult);
294
- expect(designResponse.phase).toBe('design');
295
-
296
- const impl2 = await client.callTool('proceed_to_phase', {
297
- target_phase: 'implementation',
298
- reason: 'design fixed',
299
- review_state: 'not-required',
300
- });
301
- const impl2Response = assertToolSuccess(impl2);
302
- expect(impl2Response.phase).toBe('implementation');
303
- });
304
- });
305
-
306
- describe('Error Recovery and Resilience', () => {
307
- it('should recover from invalid phase transitions', async () => {
308
- await client.callTool('whats_next', { user_input: 'start' });
309
-
310
- // Try invalid transition
311
- const result: McpToolResponse = await client.callTool(
312
- 'proceed_to_phase',
313
- {
314
- target_phase: 'invalid_phase',
315
- reason: 'test error handling',
316
- review_state: 'not-required',
317
- }
318
- );
319
-
320
- // Verify error was handled properly
321
- expect(result.error).toBeDefined();
322
- expect(result.error).toContain('Invalid target phase');
323
-
324
- // Should still be able to continue normally
325
- const recovery = await client.callTool('whats_next', {
326
- user_input: 'continue after error',
327
- });
328
- const recoveryResponse = assertToolSuccess(recovery);
329
-
330
- expect(recoveryResponse.phase).toBeTruthy();
331
- expect(recoveryResponse.instructions).toBeTruthy();
332
-
333
- // Note: Error logging is mocked and suppressed for this test
334
- });
335
-
336
- it('should handle file system issues gracefully', async () => {
337
- const result = await client.callTool('whats_next', {
338
- user_input: 'test file system resilience',
339
- });
340
- const response = assertToolSuccess(result);
341
-
342
- // Even if there are file system issues, basic functionality should work
343
- expect(response.phase).toBeTruthy();
344
- });
345
-
346
- it('should maintain functionality under stress', async () => {
347
- // Rapid fire requests
348
- const promises = Array.from({ length: 10 }, (_, i) =>
349
- client.callTool('whats_next', {
350
- user_input: `stress test ${i}`,
351
- context: `iteration ${i}`,
352
- })
353
- );
354
-
355
- const results = await Promise.all(promises);
356
-
357
- // All requests should succeed
358
- for (const result of results) {
359
- const response = assertToolSuccess(result);
360
- expect(response.phase).toBeTruthy();
361
- }
362
-
363
- // Final state should be consistent
364
- const stateResource = await client.readResource('state://current');
365
- const stateData = JSON.parse(stateResource.contents[0].text);
366
- expect(stateData.currentPhase).toBeTruthy();
367
- });
368
- });
369
- });
370
-
371
- // Custom Workflow Integration tests need their own setup without start_development in beforeEach
372
- describe('Workflow Integration - Custom State Machines', () => {
373
- let client: DirectServerInterface;
374
- let tempProject: TempProject;
375
- let cleanup: () => Promise<void>;
376
-
377
- beforeEach(async () => {
378
- const scenario = await createSuiteIsolatedE2EScenario({
379
- suiteName: 'workflow-integration-custom',
380
- tempProjectFactory: createTempProjectWithDefaultStateMachine,
381
- });
382
- client = scenario.client;
383
- tempProject = scenario.tempProject;
384
- cleanup = scenario.cleanup;
385
- // Note: NOT calling start_development here - custom workflow tests need to start fresh
386
- });
387
-
388
- afterEach(async () => {
389
- if (cleanup) {
390
- await cleanup();
391
- }
392
- });
393
-
394
- describe('Custom Workflow Integration', () => {
395
- it('should integrate custom state machines with full workflow', async () => {
396
- // Create custom state machine
397
- const vibeDir = path.join(tempProject.projectPath, '.vibe');
398
- await fs.mkdir(vibeDir, { recursive: true });
399
-
400
- const customWorkflow = `
401
- name: "custom"
402
- description: "Custom agile development workflow"
403
- initial_state: "backlog"
404
- states:
405
- backlog:
406
- description: "Feature backlog"
407
- default_instructions: "Manage feature backlog and prioritize items"
408
- transitions:
409
- - trigger: "ready_for_sprint"
410
- to: "sprint_planning"
411
- instructions: "Backlog prioritized, ready for sprint planning"
412
- transition_reason: "Backlog items prioritized and ready for sprint"
413
- sprint_planning:
414
- description: "Sprint planning"
415
- default_instructions: "Plan sprint activities and estimate effort"
416
- transitions:
417
- - trigger: "sprint_planned"
418
- to: "development"
419
- instructions: "Sprint planned, ready to start development"
420
- transition_reason: "Sprint planning complete, ready to develop"
421
- development:
422
- description: "Active development"
423
- default_instructions: "Implement features according to sprint plan"
424
- transitions:
425
- - trigger: "development_complete"
426
- to: "review"
427
- instructions: "Development complete, ready for code review"
428
- transition_reason: "Development phase finished, ready for review"
429
- review:
430
- description: "Code review"
431
- default_instructions: "Review code and validate implementation"
432
- transitions:
433
- - trigger: "review_approved"
434
- to: "done"
435
- instructions: "Review approved, sprint complete"
436
- transition_reason: "Code review passed, ready to complete sprint"
437
- done:
438
- description: "Sprint complete"
439
- default_instructions: "Sprint complete, prepare for next iteration"
440
- transitions: []
441
- `;
442
-
443
- await fs.writeFile(path.join(vibeDir, 'workflow.yaml'), customWorkflow);
444
-
445
- // First, initialize development with the custom workflow
446
- const initResult = await client.callTool('start_development', {
447
- workflow: 'custom',
448
- commit_behaviour: 'none',
449
- });
450
- assertToolSuccess(initResult);
451
-
452
- // Then call whats_next to get instructions
453
- const start = await client.callTool('whats_next', {
454
- user_input: 'start agile sprint development',
455
- context: 'new feature request',
456
- });
457
- const startResponse = assertToolSuccess(start);
458
-
459
- // The server may start at any valid phase in the custom state machine
460
- // Let's accept any of the valid phases from our custom workflow
461
- expect([
462
- 'backlog',
463
- 'sprint_planning',
464
- 'development',
465
- 'review',
466
- 'done',
467
- ]).toContain(startResponse.phase);
468
-
469
- // Progress through custom phases - start from whatever phase we're in
470
- let currentPhase = startResponse.phase;
471
-
472
- // If we're not already at development, try to get there
473
- if (currentPhase !== 'development') {
474
- const development = await client.callTool('proceed_to_phase', {
475
- target_phase: 'development',
476
- reason: 'ready to develop',
477
- review_state: 'not-required',
478
- });
479
- const devResponse = assertToolSuccess(development);
480
- expect(devResponse.phase).toBe('development');
481
- currentPhase = 'development';
482
- }
483
-
484
- // Verify we can transition to review
485
- const review = await client.callTool('proceed_to_phase', {
486
- target_phase: 'review',
487
- reason: 'development complete',
488
- review_state: 'not-required',
489
- });
490
- expect(assertToolSuccess(review).phase).toBe('review');
491
-
492
- // Verify plan file integration
493
- const planResource = await client.readResource('plan://current');
494
- const planContent = planResource.contents[0].text;
495
- expect(planContent).toContain('Development Plan');
496
- });
497
- });
498
- });