@codemcp/workflows 4.10.1 → 4.10.3

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 (93) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/components/beads/beads-instruction-generator.d.ts +4 -8
  3. package/dist/components/beads/beads-instruction-generator.d.ts.map +1 -1
  4. package/dist/components/beads/beads-instruction-generator.js +28 -51
  5. package/dist/components/beads/beads-instruction-generator.js.map +1 -1
  6. package/dist/components/beads/beads-task-backend-client.d.ts.map +1 -1
  7. package/dist/components/beads/beads-task-backend-client.js +1 -4
  8. package/dist/components/beads/beads-task-backend-client.js.map +1 -1
  9. package/dist/plugin-system/beads-plugin.d.ts +70 -0
  10. package/dist/plugin-system/beads-plugin.d.ts.map +1 -0
  11. package/dist/plugin-system/beads-plugin.js +459 -0
  12. package/dist/plugin-system/beads-plugin.js.map +1 -0
  13. package/dist/plugin-system/index.d.ts +9 -0
  14. package/dist/plugin-system/index.d.ts.map +1 -0
  15. package/dist/plugin-system/index.js +9 -0
  16. package/dist/plugin-system/index.js.map +1 -0
  17. package/dist/plugin-system/plugin-interfaces.d.ts +99 -0
  18. package/dist/plugin-system/plugin-interfaces.d.ts.map +1 -0
  19. package/dist/plugin-system/plugin-interfaces.js +9 -0
  20. package/dist/plugin-system/plugin-interfaces.js.map +1 -0
  21. package/dist/plugin-system/plugin-registry.d.ts +44 -0
  22. package/dist/plugin-system/plugin-registry.d.ts.map +1 -0
  23. package/dist/plugin-system/plugin-registry.js +132 -0
  24. package/dist/plugin-system/plugin-registry.js.map +1 -0
  25. package/dist/server-config.d.ts.map +1 -1
  26. package/dist/server-config.js +28 -8
  27. package/dist/server-config.js.map +1 -1
  28. package/dist/tool-handlers/conduct-review.d.ts.map +1 -1
  29. package/dist/tool-handlers/conduct-review.js +1 -2
  30. package/dist/tool-handlers/conduct-review.js.map +1 -1
  31. package/dist/tool-handlers/get-tool-info.d.ts +0 -1
  32. package/dist/tool-handlers/get-tool-info.d.ts.map +1 -1
  33. package/dist/tool-handlers/get-tool-info.js +0 -1
  34. package/dist/tool-handlers/get-tool-info.js.map +1 -1
  35. package/dist/tool-handlers/proceed-to-phase.d.ts +0 -7
  36. package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -1
  37. package/dist/tool-handlers/proceed-to-phase.js +15 -95
  38. package/dist/tool-handlers/proceed-to-phase.js.map +1 -1
  39. package/dist/tool-handlers/resume-workflow.d.ts +0 -1
  40. package/dist/tool-handlers/resume-workflow.d.ts.map +1 -1
  41. package/dist/tool-handlers/resume-workflow.js +0 -1
  42. package/dist/tool-handlers/resume-workflow.js.map +1 -1
  43. package/dist/tool-handlers/start-development.d.ts +0 -16
  44. package/dist/tool-handlers/start-development.d.ts.map +1 -1
  45. package/dist/tool-handlers/start-development.js +29 -130
  46. package/dist/tool-handlers/start-development.js.map +1 -1
  47. package/dist/tool-handlers/whats-next.d.ts +0 -2
  48. package/dist/tool-handlers/whats-next.d.ts.map +1 -1
  49. package/dist/tool-handlers/whats-next.js +1 -2
  50. package/dist/tool-handlers/whats-next.js.map +1 -1
  51. package/dist/types.d.ts +2 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/package.json +2 -2
  54. package/src/components/beads/beads-instruction-generator.ts +32 -64
  55. package/src/components/beads/beads-task-backend-client.ts +1 -4
  56. package/src/plugin-system/beads-plugin.ts +641 -0
  57. package/src/plugin-system/index.ts +20 -0
  58. package/src/plugin-system/plugin-interfaces.ts +154 -0
  59. package/src/plugin-system/plugin-registry.ts +190 -0
  60. package/src/server-config.ts +30 -8
  61. package/src/tool-handlers/conduct-review.ts +1 -2
  62. package/src/tool-handlers/get-tool-info.ts +0 -2
  63. package/src/tool-handlers/proceed-to-phase.ts +19 -139
  64. package/src/tool-handlers/resume-workflow.ts +0 -2
  65. package/src/tool-handlers/start-development.ts +35 -213
  66. package/src/tool-handlers/whats-next.ts +1 -4
  67. package/src/types.ts +2 -0
  68. package/test/e2e/beads-plugin-integration.test.ts +1594 -0
  69. package/test/e2e/core-functionality.test.ts +3 -12
  70. package/test/e2e/mcp-contract.test.ts +0 -31
  71. package/test/e2e/plugin-system-integration.test.ts +1421 -0
  72. package/test/e2e/state-management.test.ts +1 -5
  73. package/test/e2e/workflow-integration.test.ts +2 -11
  74. package/test/unit/beads-instruction-generator.test.ts +235 -103
  75. package/test/unit/beads-phase-task-id-integration.test.ts +7 -29
  76. package/test/unit/beads-plugin-behavioral.test.ts +512 -0
  77. package/test/unit/beads-plugin.test.ts +94 -0
  78. package/test/unit/plugin-error-handling.test.ts +240 -0
  79. package/test/unit/proceed-to-phase-plugin-integration.test.ts +150 -0
  80. package/test/unit/resume-workflow.test.ts +0 -1
  81. package/test/unit/server-config-plugin-registry.test.ts +81 -0
  82. package/test/unit/server-tools.test.ts +0 -1
  83. package/test/unit/start-development-goal-extraction.test.ts +22 -16
  84. package/test/utils/test-helpers.ts +3 -1
  85. package/tsconfig.build.tsbuildinfo +1 -1
  86. package/dist/components/server-components-factory.d.ts +0 -39
  87. package/dist/components/server-components-factory.d.ts.map +0 -1
  88. package/dist/components/server-components-factory.js +0 -62
  89. package/dist/components/server-components-factory.js.map +0 -1
  90. package/src/components/server-components-factory.ts +0 -86
  91. package/test/e2e/component-substitution.test.ts +0 -208
  92. package/test/unit/beads-integration-filename.test.ts +0 -93
  93. package/test/unit/server-components-factory.test.ts +0 -279
@@ -17,12 +17,9 @@ import { GitCommitConfig } from '@codemcp/workflows-core';
17
17
  import { GitManager } from '@codemcp/workflows-core';
18
18
  import type { YamlStateMachine } from '@codemcp/workflows-core';
19
19
  import { ProjectDocsManager, ProjectDocsInfo } from '@codemcp/workflows-core';
20
- import {
21
- TaskBackendManager,
22
- BeadsIntegration,
23
- BeadsStateManager,
24
- } from '@codemcp/workflows-core';
20
+ import { TaskBackendManager } from '@codemcp/workflows-core';
25
21
  import { ServerContext } from '../types.js';
22
+ import type { PluginHookContext } from '../plugin-system/plugin-interfaces.js';
26
23
 
27
24
  /**
28
25
  * Arguments for the start_development tool
@@ -41,8 +38,6 @@ export interface StartDevelopmentResult {
41
38
  phase: string;
42
39
  instructions: string;
43
40
  plan_file_path: string;
44
- conversation_id: string;
45
- workflow: YamlStateMachine;
46
41
  workflowDocumentationUrl?: string;
47
42
  }
48
43
 
@@ -137,8 +132,6 @@ export class StartDevelopmentHandler extends BaseToolHandler<
137
132
  phase: 'branch-prompt',
138
133
  instructions: `You're currently on the ${currentBranch} branch. It's recommended to create a feature branch for development. Propose a branch creation by suggesting a branch command to the user call start_development again.\n\nSuggested command: \`git checkout -b ${suggestedBranchName}\`\n\nPlease create a new branch and then call start_development again to begin development.`,
139
134
  plan_file_path: '',
140
- conversation_id: '',
141
- workflow: {} as YamlStateMachine,
142
135
  };
143
136
 
144
137
  this.logger.debug(
@@ -213,15 +206,39 @@ export class StartDevelopmentHandler extends BaseToolHandler<
213
206
  conversationContext.gitBranch
214
207
  );
215
208
 
216
- // Handle beads integration if beads backend is configured
217
- if (taskBackendConfig.backend === 'beads') {
218
- await this.setupBeadsIntegration(
219
- projectPath,
220
- stateMachine,
221
- selectedWorkflow,
222
- conversationContext.planFilePath,
223
- conversationContext.conversationId,
224
- context
209
+ // Execute plugin hooks after successful development start
210
+ const pluginContext: PluginHookContext = {
211
+ conversationId: conversationContext.conversationId,
212
+ planFilePath: conversationContext.planFilePath,
213
+ currentPhase: conversationContext.currentPhase,
214
+ workflow: selectedWorkflow,
215
+ projectPath,
216
+ gitBranch: conversationContext.gitBranch,
217
+ stateMachine: {
218
+ name: stateMachine.name,
219
+ description: stateMachine.description,
220
+ initial_state: stateMachine.initial_state,
221
+ states: stateMachine.states,
222
+ },
223
+ };
224
+
225
+ // Execute plugin hooks safely - guard against missing plugin registry
226
+ if (context.pluginRegistry) {
227
+ await context.pluginRegistry.executeHook(
228
+ 'afterStartDevelopment',
229
+ pluginContext,
230
+ {
231
+ workflow: selectedWorkflow,
232
+ commit_behaviour: args.commit_behaviour ?? 'end',
233
+ require_reviews: args.require_reviews,
234
+ project_path: projectPath,
235
+ },
236
+ {
237
+ conversationId: conversationContext.conversationId,
238
+ planFilePath: conversationContext.planFilePath,
239
+ phase: conversationContext.currentPhase,
240
+ workflow: selectedWorkflow,
241
+ }
225
242
  );
226
243
  }
227
244
 
@@ -249,8 +266,6 @@ export class StartDevelopmentHandler extends BaseToolHandler<
249
266
  phase: transitionResult.newPhase,
250
267
  instructions: finalInstructions,
251
268
  plan_file_path: conversationContext.planFilePath,
252
- conversation_id: conversationContext.conversationId,
253
- workflow: stateMachine,
254
269
  workflowDocumentationUrl,
255
270
  };
256
271
 
@@ -356,8 +371,6 @@ export class StartDevelopmentHandler extends BaseToolHandler<
356
371
  phase: 'artifact-setup',
357
372
  instructions: setupGuidance,
358
373
  plan_file_path: '',
359
- conversation_id: '',
360
- workflow: {} as YamlStateMachine,
361
374
  };
362
375
  } catch (error) {
363
376
  this.logger.warn(
@@ -646,146 +659,6 @@ ${templateOptionsText}
646
659
  return `feature/development-${timestamp}`;
647
660
  }
648
661
 
649
- /**
650
- * Setup beads integration - create project epic and phase tasks
651
- */
652
- private async setupBeadsIntegration(
653
- projectPath: string,
654
- stateMachine: YamlStateMachine,
655
- workflowName: string,
656
- planFilePath: string,
657
- conversationId: string,
658
- context: ServerContext
659
- ): Promise<void> {
660
- try {
661
- const beadsIntegration = new BeadsIntegration(projectPath);
662
- const projectName = projectPath.split('/').pop() || 'Unknown Project';
663
-
664
- // Extract goal from plan file if it exists and has meaningful content
665
- let goalDescription: string | undefined;
666
- try {
667
- const planFileContent =
668
- await context.planManager.getPlanFileContent(planFilePath);
669
- goalDescription = this.extractGoalFromPlan(planFileContent);
670
- } catch (error) {
671
- this.logger.warn('Could not extract goal from plan file', {
672
- error: error instanceof Error ? error.message : String(error),
673
- planFilePath,
674
- });
675
- }
676
-
677
- // Extract plan filename for use in epic title
678
- const planFilename = planFilePath.split('/').pop();
679
-
680
- // Create project epic
681
- const epicId = await beadsIntegration.createProjectEpic(
682
- projectName,
683
- workflowName,
684
- goalDescription,
685
- planFilename
686
- );
687
-
688
- // Create phase tasks for all workflow phases
689
- const phaseTasks = await beadsIntegration.createPhaseTasks(
690
- epicId,
691
- stateMachine.states,
692
- workflowName
693
- );
694
-
695
- // Create sequential dependencies between phases
696
- await beadsIntegration.createPhaseDependencies(phaseTasks);
697
-
698
- // Update plan file with phase task IDs
699
- await this.updatePlanFileWithPhaseTaskIds(planFilePath, phaseTasks);
700
-
701
- // Create beads state for this conversation
702
- const beadsStateManager = new BeadsStateManager(projectPath);
703
- await beadsStateManager.createState(conversationId, epicId, phaseTasks);
704
-
705
- this.logger.info('Beads integration setup complete', {
706
- projectPath,
707
- epicId,
708
- phaseCount: phaseTasks.length,
709
- planFilePath,
710
- conversationId,
711
- });
712
- } catch (error) {
713
- this.logger.error(
714
- 'Failed to setup beads integration',
715
- error instanceof Error ? error : new Error(String(error)),
716
- {
717
- projectPath,
718
- workflowName,
719
- }
720
- );
721
- throw new Error(
722
- `Failed to setup beads integration: ${error instanceof Error ? error.message : String(error)}`
723
- );
724
- }
725
- }
726
-
727
- /**
728
- * Update plan file to include beads phase task IDs in comments
729
- */
730
- private async updatePlanFileWithPhaseTaskIds(
731
- planFilePath: string,
732
- phaseTasks: Array<{ phaseId: string; phaseName: string; taskId: string }>
733
- ): Promise<void> {
734
- try {
735
- const { readFile, writeFile } = await import('node:fs/promises');
736
- let content = await readFile(planFilePath, 'utf-8');
737
-
738
- // Replace TBD placeholders with actual task IDs
739
- for (const phaseTask of phaseTasks) {
740
- const phaseHeader = `## ${phaseTask.phaseName}`;
741
- const placeholderPattern = new RegExp(
742
- `(${phaseHeader.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*\n)<!-- beads-phase-id: TBD -->`,
743
- 'g'
744
- );
745
- content = content.replace(
746
- placeholderPattern,
747
- `$1<!-- beads-phase-id: ${phaseTask.taskId} -->`
748
- );
749
- }
750
-
751
- // Validate that all TBD placeholders were replaced
752
- const remainingTBDs = content.match(/<!-- beads-phase-id: TBD -->/g);
753
- if (remainingTBDs && remainingTBDs.length > 0) {
754
- throw new Error(
755
- `Failed to replace ${remainingTBDs.length} TBD placeholder(s) in plan file. ` +
756
- `This indicates that phase names in the plan file don't match the workflow phases, ` +
757
- `or the beads task creation process failed for some phases.`
758
- );
759
- }
760
-
761
- await writeFile(planFilePath, content, 'utf-8');
762
-
763
- this.logger.info(
764
- 'Successfully updated plan file with beads phase task IDs',
765
- {
766
- planFilePath,
767
- phaseTaskCount: phaseTasks.length,
768
- replacedTasks: phaseTasks.map(
769
- task => `${task.phaseName}: ${task.taskId}`
770
- ),
771
- }
772
- );
773
- } catch (error) {
774
- this.logger.error(
775
- 'Failed to update plan file with phase task IDs',
776
- error instanceof Error ? error : new Error(String(error)),
777
- {
778
- planFilePath,
779
- }
780
- );
781
- // For beads integration, TBD replacement failure is critical
782
- throw new Error(
783
- `Failed to update plan file with beads task IDs: ${error instanceof Error ? error.message : String(error)}. ` +
784
- `This indicates beads integration setup is incomplete. Check that beads CLI is working and task IDs were created successfully.`
785
- );
786
- }
787
- }
788
-
789
662
  /**
790
663
  * Ensure .gitignore exists in .vibe folder to exclude SQLite files
791
664
  * This function is idempotent and self-contained within the .vibe directory
@@ -860,55 +733,4 @@ conversations/
860
733
  );
861
734
  }
862
735
  }
863
-
864
- /**
865
- * Extract Goal section content from plan file
866
- * Returns the goal content if it exists and is meaningful, otherwise undefined
867
- */
868
- private extractGoalFromPlan(planContent: string): string | undefined {
869
- if (!planContent || typeof planContent !== 'string') {
870
- return undefined;
871
- }
872
-
873
- // Split content into lines for more reliable parsing
874
- const lines = planContent.split('\n');
875
- const goalIndex = lines.findIndex(line => line.trim() === '## Goal');
876
-
877
- if (goalIndex === -1) {
878
- return undefined;
879
- }
880
-
881
- // Find the next section (## anything) after the Goal section
882
- const nextSectionIndex = lines.findIndex(
883
- (line, index) => index > goalIndex && line.trim().startsWith('## ')
884
- );
885
-
886
- // Extract content between Goal and next section (or end of content)
887
- const contentLines =
888
- nextSectionIndex === -1
889
- ? lines.slice(goalIndex + 1)
890
- : lines.slice(goalIndex + 1, nextSectionIndex);
891
-
892
- const goalContent = contentLines.join('\n').trim();
893
-
894
- // Check if the goal content is meaningful (not just a placeholder or comment)
895
- const meaninglessPatterns = [
896
- /^\*.*\*$/, // Enclosed in asterisks like "*Define what you're building...*"
897
- /^To be defined/i,
898
- /^TBD$/i,
899
- /^TODO/i,
900
- /^Define what you're building/i,
901
- /^This will be updated/i,
902
- ];
903
-
904
- const isMeaningless = meaninglessPatterns.some(pattern =>
905
- pattern.test(goalContent)
906
- );
907
-
908
- if (isMeaningless || goalContent.length < 10) {
909
- return undefined;
910
- }
911
-
912
- return goalContent;
913
- }
914
736
  }
@@ -30,8 +30,6 @@ export interface WhatsNextResult {
30
30
  phase: string;
31
31
  instructions: string;
32
32
  plan_file_path: string;
33
- is_modeled_transition: boolean;
34
- conversation_id: string;
35
33
  }
36
34
 
37
35
  /**
@@ -168,6 +166,7 @@ export class WhatsNextHandler extends ConversationRequiredToolHandler<
168
166
  transitionReason: transitionResult.transitionReason,
169
167
  isModeled: transitionResult.isModeled,
170
168
  planFileExists: planInfo.exists,
169
+ instructionSource: 'whats_next',
171
170
  }
172
171
  );
173
172
 
@@ -188,8 +187,6 @@ export class WhatsNextHandler extends ConversationRequiredToolHandler<
188
187
  phase: transitionResult.newPhase,
189
188
  instructions: finalInstructions,
190
189
  plan_file_path: conversationContext.planFilePath,
191
- is_modeled_transition: transitionResult.isModeled,
192
- conversation_id: conversationContext.conversationId,
193
190
  };
194
191
 
195
192
  // Log interaction
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ import { IInstructionGenerator } from '@codemcp/workflows-core';
9
9
  import { WorkflowManager } from '@codemcp/workflows-core';
10
10
  import { InteractionLogger } from '@codemcp/workflows-core';
11
11
  import type { TaskBackendConfig } from '@codemcp/workflows-core';
12
+ import type { IPluginRegistry } from './plugin-system/plugin-interfaces.js';
12
13
 
13
14
  /**
14
15
  * Server context shared across all handlers
@@ -22,6 +23,7 @@ export interface ServerContext {
22
23
  workflowManager: WorkflowManager;
23
24
  interactionLogger?: InteractionLogger;
24
25
  projectPath: string;
26
+ pluginRegistry?: IPluginRegistry;
25
27
  }
26
28
 
27
29
  /**