@codemcp/workflows 4.10.1 → 4.10.2

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 (74) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/components/beads/beads-instruction-generator.d.ts +3 -4
  3. package/dist/components/beads/beads-instruction-generator.d.ts.map +1 -1
  4. package/dist/components/beads/beads-instruction-generator.js +12 -7
  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/proceed-to-phase.d.ts +0 -5
  32. package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -1
  33. package/dist/tool-handlers/proceed-to-phase.js +15 -93
  34. package/dist/tool-handlers/proceed-to-phase.js.map +1 -1
  35. package/dist/tool-handlers/start-development.d.ts +0 -13
  36. package/dist/tool-handlers/start-development.d.ts.map +1 -1
  37. package/dist/tool-handlers/start-development.js +29 -124
  38. package/dist/tool-handlers/start-development.js.map +1 -1
  39. package/dist/tool-handlers/whats-next.d.ts.map +1 -1
  40. package/dist/tool-handlers/whats-next.js +1 -0
  41. package/dist/tool-handlers/whats-next.js.map +1 -1
  42. package/dist/types.d.ts +2 -0
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +2 -2
  45. package/src/components/beads/beads-instruction-generator.ts +12 -12
  46. package/src/components/beads/beads-task-backend-client.ts +1 -4
  47. package/src/plugin-system/beads-plugin.ts +641 -0
  48. package/src/plugin-system/index.ts +20 -0
  49. package/src/plugin-system/plugin-interfaces.ts +154 -0
  50. package/src/plugin-system/plugin-registry.ts +190 -0
  51. package/src/server-config.ts +30 -8
  52. package/src/tool-handlers/conduct-review.ts +1 -2
  53. package/src/tool-handlers/proceed-to-phase.ts +19 -135
  54. package/src/tool-handlers/start-development.ts +35 -205
  55. package/src/tool-handlers/whats-next.ts +1 -0
  56. package/src/types.ts +2 -0
  57. package/test/e2e/beads-plugin-integration.test.ts +1609 -0
  58. package/test/e2e/plugin-system-integration.test.ts +1729 -0
  59. package/test/unit/beads-plugin-behavioral.test.ts +512 -0
  60. package/test/unit/beads-plugin.test.ts +94 -0
  61. package/test/unit/plugin-error-handling.test.ts +240 -0
  62. package/test/unit/proceed-to-phase-plugin-integration.test.ts +150 -0
  63. package/test/unit/server-config-plugin-registry.test.ts +81 -0
  64. package/test/unit/start-development-goal-extraction.test.ts +22 -16
  65. package/test/utils/test-helpers.ts +3 -1
  66. package/tsconfig.build.tsbuildinfo +1 -1
  67. package/dist/components/server-components-factory.d.ts +0 -39
  68. package/dist/components/server-components-factory.d.ts.map +0 -1
  69. package/dist/components/server-components-factory.js +0 -62
  70. package/dist/components/server-components-factory.js.map +0 -1
  71. package/src/components/server-components-factory.ts +0 -86
  72. package/test/e2e/component-substitution.test.ts +0 -208
  73. package/test/unit/beads-integration-filename.test.ts +0 -93
  74. 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
@@ -213,15 +210,39 @@ export class StartDevelopmentHandler extends BaseToolHandler<
213
210
  conversationContext.gitBranch
214
211
  );
215
212
 
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
213
+ // Execute plugin hooks after successful development start
214
+ const pluginContext: PluginHookContext = {
215
+ conversationId: conversationContext.conversationId,
216
+ planFilePath: conversationContext.planFilePath,
217
+ currentPhase: conversationContext.currentPhase,
218
+ workflow: selectedWorkflow,
219
+ projectPath,
220
+ gitBranch: conversationContext.gitBranch,
221
+ stateMachine: {
222
+ name: stateMachine.name,
223
+ description: stateMachine.description,
224
+ initial_state: stateMachine.initial_state,
225
+ states: stateMachine.states,
226
+ },
227
+ };
228
+
229
+ // Execute plugin hooks safely - guard against missing plugin registry
230
+ if (context.pluginRegistry) {
231
+ await context.pluginRegistry.executeHook(
232
+ 'afterStartDevelopment',
233
+ pluginContext,
234
+ {
235
+ workflow: selectedWorkflow,
236
+ commit_behaviour: args.commit_behaviour ?? 'end',
237
+ require_reviews: args.require_reviews,
238
+ project_path: projectPath,
239
+ },
240
+ {
241
+ conversationId: conversationContext.conversationId,
242
+ planFilePath: conversationContext.planFilePath,
243
+ phase: conversationContext.currentPhase,
244
+ workflow: selectedWorkflow,
245
+ }
225
246
  );
226
247
  }
227
248
 
@@ -646,146 +667,6 @@ ${templateOptionsText}
646
667
  return `feature/development-${timestamp}`;
647
668
  }
648
669
 
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
670
  /**
790
671
  * Ensure .gitignore exists in .vibe folder to exclude SQLite files
791
672
  * This function is idempotent and self-contained within the .vibe directory
@@ -860,55 +741,4 @@ conversations/
860
741
  );
861
742
  }
862
743
  }
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
744
  }
@@ -168,6 +168,7 @@ export class WhatsNextHandler extends ConversationRequiredToolHandler<
168
168
  transitionReason: transitionResult.transitionReason,
169
169
  isModeled: transitionResult.isModeled,
170
170
  planFileExists: planInfo.exists,
171
+ instructionSource: 'whats_next',
171
172
  }
172
173
  );
173
174
 
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
  /**