@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,378 +0,0 @@
1
- /**
2
- * ResumeWorkflow Tool Handler
3
- *
4
- * Handles resuming development workflow after conversation compression.
5
- * Returns comprehensive project context, current state, system prompt instructions,
6
- * and next steps to seamlessly continue development.
7
- */
8
-
9
- import { ConversationRequiredToolHandler } from './base-tool-handler.js';
10
- import { generateSystemPrompt } from '@codemcp/workflows-core';
11
- import type { YamlStateMachine, YamlState } from '@codemcp/workflows-core';
12
- import { ServerContext } from '../types.js';
13
-
14
- /**
15
- * Arguments for the resume_workflow tool
16
- */
17
- export interface ResumeWorkflowArgs {
18
- include_system_prompt?: boolean;
19
- }
20
-
21
- /**
22
- * Plan file analysis result
23
- */
24
- interface PlanAnalysis {
25
- sections: string[];
26
- tasks_completed: number;
27
- tasks_total: number;
28
- key_decisions: string[];
29
- recent_updates: string[];
30
- active_tasks?: string[];
31
- completed_tasks?: string[];
32
- }
33
-
34
- /**
35
- * Conversation context for resume workflow
36
- */
37
- interface ConversationContext {
38
- conversationId: string;
39
- currentPhase: string;
40
- projectPath: string;
41
- workflowName: string;
42
- gitBranch: string;
43
- planFilePath: string;
44
- current_phase?: string;
45
- workflow_name?: string;
46
- project_context?: string;
47
- recent_activity?: string[];
48
- }
49
-
50
- /**
51
- * Recommendations for resuming workflow
52
- */
53
- interface WorkflowRecommendations {
54
- immediate_actions: string[];
55
- phase_guidance: string;
56
- potential_issues: string[];
57
- }
58
-
59
- /**
60
- * Response from the resume_workflow tool
61
- */
62
- export interface ResumeWorkflowResult {
63
- workflow_status: {
64
- current_phase: string;
65
- project_path: string;
66
- git_branch: string;
67
- state_machine: YamlStateMachine;
68
- };
69
- plan_status: {
70
- exists: boolean;
71
- path: string;
72
- analysis?: PlanAnalysis | null;
73
- };
74
- system_prompt?: string | null;
75
- recommendations: {
76
- immediate_actions: string[];
77
- phase_guidance: string;
78
- potential_issues: string[];
79
- };
80
- generated_at: string;
81
- tool_version: string;
82
- }
83
-
84
- /**
85
- * ResumeWorkflow tool handler implementation
86
- */
87
- export class ResumeWorkflowHandler extends ConversationRequiredToolHandler<
88
- ResumeWorkflowArgs,
89
- ResumeWorkflowResult
90
- > {
91
- protected async executeWithConversation(
92
- args: ResumeWorkflowArgs,
93
- context: ServerContext,
94
- conversationContext: ConversationContext
95
- ): Promise<ResumeWorkflowResult> {
96
- const includeSystemPrompt = args.include_system_prompt !== false; // Default to true
97
-
98
- this.logger.debug('Processing resume_workflow request', {
99
- conversationId: conversationContext.conversationId,
100
- includeSystemPrompt,
101
- });
102
-
103
- // Get plan file information
104
- const planInfo = await context.planManager.getPlanFileInfo(
105
- conversationContext.planFilePath
106
- );
107
-
108
- // Analyze plan file content for key information
109
- const planAnalysis =
110
- planInfo.exists && planInfo.content
111
- ? this.analyzePlanFile(planInfo.content)
112
- : null;
113
-
114
- // Get current state machine information
115
- const stateMachineInfo = await this.getStateMachineInfo(
116
- context,
117
- conversationContext.projectPath,
118
- conversationContext.workflowName
119
- );
120
- const stateMachine = context.transitionEngine.getStateMachine(
121
- conversationContext.projectPath,
122
- conversationContext.workflowName
123
- );
124
-
125
- // Generate system prompt if requested
126
- const systemPrompt = includeSystemPrompt
127
- ? generateSystemPrompt(stateMachine)
128
- : null;
129
-
130
- // Build comprehensive response
131
- const response: ResumeWorkflowResult = {
132
- // Core workflow resumption info
133
- workflow_status: {
134
- current_phase: conversationContext.currentPhase,
135
- project_path: conversationContext.projectPath,
136
- git_branch: conversationContext.gitBranch,
137
- state_machine: stateMachineInfo as YamlStateMachine,
138
- },
139
-
140
- // Plan file analysis
141
- plan_status: {
142
- exists: planInfo.exists,
143
- path: conversationContext.planFilePath,
144
- analysis: planAnalysis,
145
- },
146
-
147
- // System prompt (if requested)
148
- system_prompt: systemPrompt,
149
-
150
- // Next steps and recommendations
151
- recommendations: this.generateRecommendations(
152
- conversationContext,
153
- planAnalysis,
154
- context
155
- ),
156
-
157
- // Metadata
158
- generated_at: new Date().toISOString(),
159
- tool_version: '1.0.0',
160
- };
161
-
162
- this.logger.debug('resume_workflow response generated', {
163
- conversationId: conversationContext.conversationId,
164
- phase: conversationContext.currentPhase,
165
- planExists: planInfo.exists,
166
- includeSystemPrompt,
167
- });
168
-
169
- return response;
170
- }
171
-
172
- /**
173
- * Analyze plan file content to extract key information
174
- */
175
- private analyzePlanFile(content: string): PlanAnalysis {
176
- const analysis = {
177
- active_tasks: [] as string[],
178
- completed_tasks: [] as string[],
179
- recent_decisions: [] as string[],
180
- next_steps: [] as string[],
181
- };
182
-
183
- const lines = content.split('\n');
184
- let inTaskSection = false;
185
- let currentSection = '';
186
-
187
- for (const line of lines) {
188
- const trimmed = line.trim();
189
-
190
- // Detect sections
191
- if (trimmed.startsWith('##')) {
192
- currentSection = trimmed.toLowerCase();
193
- inTaskSection =
194
- currentSection.includes('task') || currentSection.includes('todo');
195
- }
196
-
197
- // Extract tasks
198
- if (inTaskSection) {
199
- if (trimmed.startsWith('- [x]')) {
200
- analysis.completed_tasks.push(trimmed.substring(5).trim());
201
- } else if (trimmed.startsWith('- [ ]')) {
202
- analysis.active_tasks.push(trimmed.substring(5).trim());
203
- }
204
- }
205
-
206
- // Extract decisions (look for decision log sections)
207
- if (currentSection.includes('decision') && trimmed.startsWith('- ')) {
208
- analysis.recent_decisions.push(trimmed.substring(2).trim());
209
- }
210
- }
211
-
212
- return {
213
- sections: [currentSection],
214
- tasks_completed: analysis.completed_tasks.length,
215
- tasks_total:
216
- analysis.active_tasks.length + analysis.completed_tasks.length,
217
- key_decisions: analysis.recent_decisions,
218
- recent_updates: analysis.next_steps,
219
- active_tasks: analysis.active_tasks,
220
- completed_tasks: analysis.completed_tasks,
221
- };
222
- }
223
-
224
- /**
225
- * Get state machine information
226
- */
227
- private async getStateMachineInfo(
228
- context: ServerContext,
229
- projectPath: string,
230
- workflowName?: string
231
- ): Promise<unknown> {
232
- try {
233
- // Get the actual state machine for this project
234
- const stateMachine = context.transitionEngine.getStateMachine(
235
- projectPath,
236
- workflowName
237
- );
238
-
239
- return {
240
- name: stateMachine.name,
241
- description: stateMachine.description,
242
- initial_state: stateMachine.initial_state,
243
- phases: Object.keys(stateMachine.states),
244
- phase_descriptions: Object.fromEntries(
245
- Object.entries(stateMachine.states).map(([phase, definition]) => [
246
- phase,
247
- (definition as YamlState).description,
248
- ])
249
- ),
250
- };
251
- } catch (error) {
252
- const err = error as Error;
253
- this.logger.warn('Could not determine state machine info', {
254
- error: err.message,
255
- });
256
- return {
257
- name: 'unknown',
258
- description: 'Could not load workflow',
259
- initial_state: 'unknown',
260
- phases: [],
261
- phase_descriptions: {},
262
- };
263
- }
264
- }
265
-
266
- /**
267
- * Generate recommendations for next steps based on state machine transitions
268
- */
269
- private generateRecommendations(
270
- conversationContext: ConversationContext,
271
- planAnalysis: PlanAnalysis | null,
272
- context: ServerContext
273
- ): WorkflowRecommendations {
274
- const recommendations = {
275
- immediate_actions: [] as string[],
276
- phase_guidance: '',
277
- potential_issues: [] as string[],
278
- };
279
-
280
- try {
281
- // Get the state machine for this project
282
- const stateMachine = context.transitionEngine.getStateMachine(
283
- conversationContext.projectPath,
284
- conversationContext.workflowName
285
- );
286
- const currentPhase = conversationContext.currentPhase;
287
- const phaseDefinition = stateMachine.states[currentPhase];
288
-
289
- if (phaseDefinition) {
290
- // Set phase guidance from state machine description
291
- recommendations.phase_guidance = `Current phase: ${(phaseDefinition as YamlState).description}`;
292
-
293
- // Generate transition-based recommendations
294
- if (
295
- (phaseDefinition as YamlState).transitions &&
296
- (phaseDefinition as YamlState).transitions.length > 0
297
- ) {
298
- recommendations.immediate_actions.push(
299
- 'From here, you can transition to:'
300
- );
301
-
302
- for (const transition of phaseDefinition.transitions) {
303
- const targetPhase = stateMachine.states[transition.to];
304
- const targetDescription = targetPhase
305
- ? targetPhase.description
306
- : transition.to;
307
- recommendations.immediate_actions.push(
308
- `• ${transition.to}: ${targetDescription}`
309
- );
310
- }
311
-
312
- // Add instruction on how to transition
313
- recommendations.immediate_actions.push(
314
- 'Use proceed_to_phase() tool when ready to transition'
315
- );
316
- } else {
317
- recommendations.immediate_actions.push(
318
- 'Continue working in current phase'
319
- );
320
- }
321
-
322
- // Add current phase specific guidance
323
- recommendations.immediate_actions.push(
324
- `Focus on: ${(phaseDefinition as YamlState).description}`
325
- );
326
- } else {
327
- // Fallback if phase not found in state machine
328
- recommendations.phase_guidance = `Current phase: ${currentPhase}`;
329
- recommendations.immediate_actions.push(
330
- 'Continue working in current phase'
331
- );
332
- }
333
- } catch (error) {
334
- const err = error as Error;
335
- this.logger.warn('Could not generate state machine recommendations', {
336
- error: err.message,
337
- });
338
- // Basic fallback
339
- recommendations.phase_guidance = `Current phase: ${conversationContext.currentPhase}`;
340
- recommendations.immediate_actions.push(
341
- 'Continue working in current phase'
342
- );
343
- }
344
-
345
- // Plan-based recommendations
346
- if (planAnalysis) {
347
- if (planAnalysis.active_tasks && planAnalysis.active_tasks.length > 0) {
348
- recommendations.immediate_actions.push(
349
- `Continue working on active tasks: ${planAnalysis.active_tasks.slice(0, 2).join(', ')}`
350
- );
351
- }
352
-
353
- if (
354
- (!planAnalysis.active_tasks ||
355
- planAnalysis.active_tasks.length === 0) &&
356
- planAnalysis.completed_tasks &&
357
- planAnalysis.completed_tasks.length > 0
358
- ) {
359
- recommendations.potential_issues.push(
360
- 'No active tasks found - may be ready to transition to next phase'
361
- );
362
- }
363
- }
364
-
365
- // Always recommend calling whats_next
366
- if (
367
- !recommendations.immediate_actions.some(action =>
368
- action.includes('whats_next')
369
- )
370
- ) {
371
- recommendations.immediate_actions.unshift(
372
- 'Call whats_next() to get current phase-specific guidance'
373
- );
374
- }
375
-
376
- return recommendations;
377
- }
378
- }
@@ -1,232 +0,0 @@
1
- /**
2
- * Setup Project Docs Handler
3
- *
4
- * Creates project documentation artifacts (architecture.md, requirements.md, design.md)
5
- * using configurable templates OR by linking existing files via symlinks.
6
- * Supports different template formats for each document type and file path linking.
7
- */
8
-
9
- import { BaseToolHandler } from './base-tool-handler.js';
10
- import { stripVibePathSuffix } from '../server-helpers.js';
11
- import { ProjectDocsManager } from '@codemcp/workflows-core';
12
- import { TemplateOptions } from '@codemcp/workflows-core';
13
- import { PathValidationUtils } from '@codemcp/workflows-core';
14
- import { ServerContext } from '../types.js';
15
-
16
- export interface SetupProjectDocsArgs {
17
- architecture: string; // Template name OR file path
18
- requirements: string; // Template name OR file path
19
- design: string; // Template name OR file path
20
- project_path?: string; // Optional project path override
21
- }
22
-
23
- export interface SetupProjectDocsResult {
24
- success: boolean;
25
- created: string[];
26
- linked: string[];
27
- skipped: string[];
28
- paths: {
29
- architecture: string;
30
- requirements: string;
31
- design: string;
32
- };
33
- message: string;
34
- }
35
-
36
- export class SetupProjectDocsHandler extends BaseToolHandler<
37
- SetupProjectDocsArgs,
38
- SetupProjectDocsResult
39
- > {
40
- private projectDocsManager: ProjectDocsManager;
41
-
42
- constructor() {
43
- super();
44
- this.projectDocsManager = new ProjectDocsManager();
45
- }
46
-
47
- protected async executeHandler(
48
- args: SetupProjectDocsArgs,
49
- context: ServerContext
50
- ): Promise<SetupProjectDocsResult> {
51
- // Normalize project path - strip /.vibe suffix if present
52
- const projectPath = stripVibePathSuffix(
53
- args.project_path,
54
- context.projectPath || process.cwd()
55
- );
56
-
57
- this.logger.info(
58
- 'Setting up project docs with enhanced file linking support',
59
- { args, projectPath }
60
- );
61
-
62
- try {
63
- // Get available templates for validation
64
- const availableTemplates =
65
- await this.projectDocsManager.templateManager.getAvailableTemplates();
66
-
67
- // Validate and process each parameter
68
- const processedArgs = await this.validateAndProcessArgs(
69
- args,
70
- availableTemplates,
71
- projectPath
72
- );
73
-
74
- if (!processedArgs.success) {
75
- return {
76
- success: false,
77
- created: [],
78
- linked: [],
79
- skipped: [],
80
- paths: this.projectDocsManager.getDocumentPaths(projectPath),
81
- message: processedArgs.error || 'Unknown error during validation',
82
- };
83
- }
84
-
85
- // Create/link project documents
86
- if (!processedArgs.templateOptions || !processedArgs.filePaths) {
87
- throw new Error(
88
- 'Invalid processed args: missing templateOptions or filePaths'
89
- );
90
- }
91
-
92
- const result = await this.projectDocsManager.createOrLinkProjectDocs(
93
- projectPath,
94
- processedArgs.templateOptions,
95
- processedArgs.filePaths
96
- );
97
-
98
- // Get document paths for response
99
- const paths = this.projectDocsManager.getDocumentPaths(projectPath);
100
-
101
- // Create success message
102
- let message = 'Project documentation setup completed.';
103
- if (result.created.length > 0) {
104
- message += ` Created: ${result.created.join(', ')}.`;
105
- }
106
- if (result.linked.length > 0) {
107
- message += ` Linked: ${result.linked.join(', ')}.`;
108
- }
109
- if (result.skipped.length > 0) {
110
- message += ` Skipped existing: ${result.skipped.join(', ')}.`;
111
- }
112
-
113
- this.logger.info('Project docs setup completed', {
114
- created: result.created,
115
- linked: result.linked,
116
- skipped: result.skipped,
117
- paths,
118
- });
119
-
120
- return {
121
- success: true,
122
- created: result.created,
123
- linked: result.linked,
124
- skipped: result.skipped,
125
- paths,
126
- message,
127
- };
128
- } catch (error) {
129
- this.logger.error('Failed to setup project docs', error as Error, {
130
- args,
131
- projectPath,
132
- });
133
-
134
- return {
135
- success: false,
136
- created: [],
137
- linked: [],
138
- skipped: [],
139
- paths: this.projectDocsManager.getDocumentPaths(projectPath),
140
- message: `Failed to setup project docs: ${error instanceof Error ? error.message : 'Unknown error'}`,
141
- };
142
- }
143
- }
144
-
145
- /**
146
- * Validate and process arguments to determine templates vs file paths
147
- */
148
- private async validateAndProcessArgs(
149
- args: SetupProjectDocsArgs,
150
- availableTemplates: {
151
- architecture: string[];
152
- requirements: string[];
153
- design: string[];
154
- },
155
- projectPath: string
156
- ): Promise<{
157
- success: boolean;
158
- error?: string;
159
- templateOptions?: Partial<TemplateOptions>;
160
- filePaths?: Partial<{
161
- architecture: string;
162
- requirements: string;
163
- design: string;
164
- }>;
165
- }> {
166
- const templateOptions: Partial<TemplateOptions> = {};
167
- const filePaths: Partial<{
168
- architecture: string;
169
- requirements: string;
170
- design: string;
171
- }> = {};
172
- const errors: string[] = [];
173
-
174
- // Validate architecture parameter
175
- const archValidation = await PathValidationUtils.validateParameter(
176
- args.architecture,
177
- availableTemplates.architecture,
178
- projectPath
179
- );
180
-
181
- if (archValidation.isTemplate) {
182
- templateOptions.architecture = args.architecture;
183
- } else if (archValidation.isFilePath && archValidation.resolvedPath) {
184
- filePaths.architecture = archValidation.resolvedPath;
185
- } else {
186
- errors.push(`Architecture: ${archValidation.error}`);
187
- }
188
-
189
- // Validate requirements parameter
190
- const reqValidation = await PathValidationUtils.validateParameter(
191
- args.requirements,
192
- availableTemplates.requirements,
193
- projectPath
194
- );
195
-
196
- if (reqValidation.isTemplate) {
197
- templateOptions.requirements = args.requirements;
198
- } else if (reqValidation.isFilePath && reqValidation.resolvedPath) {
199
- filePaths.requirements = reqValidation.resolvedPath;
200
- } else {
201
- errors.push(`Requirements: ${reqValidation.error}`);
202
- }
203
-
204
- // Validate design parameter
205
- const designValidation = await PathValidationUtils.validateParameter(
206
- args.design,
207
- availableTemplates.design,
208
- projectPath
209
- );
210
-
211
- if (designValidation.isTemplate) {
212
- templateOptions.design = args.design;
213
- } else if (designValidation.isFilePath && designValidation.resolvedPath) {
214
- filePaths.design = designValidation.resolvedPath;
215
- } else {
216
- errors.push(`Design: ${designValidation.error}`);
217
- }
218
-
219
- if (errors.length > 0) {
220
- return {
221
- success: false,
222
- error: `Parameter validation failed:\n${errors.join('\n')}`,
223
- };
224
- }
225
-
226
- return {
227
- success: true,
228
- templateOptions,
229
- filePaths,
230
- };
231
- }
232
- }