@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/components/beads/beads-instruction-generator.d.ts +4 -8
- package/dist/components/beads/beads-instruction-generator.d.ts.map +1 -1
- package/dist/components/beads/beads-instruction-generator.js +28 -51
- package/dist/components/beads/beads-instruction-generator.js.map +1 -1
- package/dist/components/beads/beads-task-backend-client.d.ts.map +1 -1
- package/dist/components/beads/beads-task-backend-client.js +1 -4
- package/dist/components/beads/beads-task-backend-client.js.map +1 -1
- package/dist/plugin-system/beads-plugin.d.ts +70 -0
- package/dist/plugin-system/beads-plugin.d.ts.map +1 -0
- package/dist/plugin-system/beads-plugin.js +459 -0
- package/dist/plugin-system/beads-plugin.js.map +1 -0
- package/dist/plugin-system/index.d.ts +9 -0
- package/dist/plugin-system/index.d.ts.map +1 -0
- package/dist/plugin-system/index.js +9 -0
- package/dist/plugin-system/index.js.map +1 -0
- package/dist/plugin-system/plugin-interfaces.d.ts +99 -0
- package/dist/plugin-system/plugin-interfaces.d.ts.map +1 -0
- package/dist/plugin-system/plugin-interfaces.js +9 -0
- package/dist/plugin-system/plugin-interfaces.js.map +1 -0
- package/dist/plugin-system/plugin-registry.d.ts +44 -0
- package/dist/plugin-system/plugin-registry.d.ts.map +1 -0
- package/dist/plugin-system/plugin-registry.js +132 -0
- package/dist/plugin-system/plugin-registry.js.map +1 -0
- package/dist/server-config.d.ts.map +1 -1
- package/dist/server-config.js +28 -8
- package/dist/server-config.js.map +1 -1
- package/dist/tool-handlers/conduct-review.d.ts.map +1 -1
- package/dist/tool-handlers/conduct-review.js +1 -2
- package/dist/tool-handlers/conduct-review.js.map +1 -1
- package/dist/tool-handlers/get-tool-info.d.ts +0 -1
- package/dist/tool-handlers/get-tool-info.d.ts.map +1 -1
- package/dist/tool-handlers/get-tool-info.js +0 -1
- package/dist/tool-handlers/get-tool-info.js.map +1 -1
- package/dist/tool-handlers/proceed-to-phase.d.ts +0 -7
- package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -1
- package/dist/tool-handlers/proceed-to-phase.js +15 -95
- package/dist/tool-handlers/proceed-to-phase.js.map +1 -1
- package/dist/tool-handlers/resume-workflow.d.ts +0 -1
- package/dist/tool-handlers/resume-workflow.d.ts.map +1 -1
- package/dist/tool-handlers/resume-workflow.js +0 -1
- package/dist/tool-handlers/resume-workflow.js.map +1 -1
- package/dist/tool-handlers/start-development.d.ts +0 -16
- package/dist/tool-handlers/start-development.d.ts.map +1 -1
- package/dist/tool-handlers/start-development.js +29 -130
- package/dist/tool-handlers/start-development.js.map +1 -1
- package/dist/tool-handlers/whats-next.d.ts +0 -2
- package/dist/tool-handlers/whats-next.d.ts.map +1 -1
- package/dist/tool-handlers/whats-next.js +1 -2
- package/dist/tool-handlers/whats-next.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/beads/beads-instruction-generator.ts +32 -64
- package/src/components/beads/beads-task-backend-client.ts +1 -4
- package/src/plugin-system/beads-plugin.ts +641 -0
- package/src/plugin-system/index.ts +20 -0
- package/src/plugin-system/plugin-interfaces.ts +154 -0
- package/src/plugin-system/plugin-registry.ts +190 -0
- package/src/server-config.ts +30 -8
- package/src/tool-handlers/conduct-review.ts +1 -2
- package/src/tool-handlers/get-tool-info.ts +0 -2
- package/src/tool-handlers/proceed-to-phase.ts +19 -139
- package/src/tool-handlers/resume-workflow.ts +0 -2
- package/src/tool-handlers/start-development.ts +35 -213
- package/src/tool-handlers/whats-next.ts +1 -4
- package/src/types.ts +2 -0
- package/test/e2e/beads-plugin-integration.test.ts +1594 -0
- package/test/e2e/core-functionality.test.ts +3 -12
- package/test/e2e/mcp-contract.test.ts +0 -31
- package/test/e2e/plugin-system-integration.test.ts +1421 -0
- package/test/e2e/state-management.test.ts +1 -5
- package/test/e2e/workflow-integration.test.ts +2 -11
- package/test/unit/beads-instruction-generator.test.ts +235 -103
- package/test/unit/beads-phase-task-id-integration.test.ts +7 -29
- package/test/unit/beads-plugin-behavioral.test.ts +512 -0
- package/test/unit/beads-plugin.test.ts +94 -0
- package/test/unit/plugin-error-handling.test.ts +240 -0
- package/test/unit/proceed-to-phase-plugin-integration.test.ts +150 -0
- package/test/unit/resume-workflow.test.ts +0 -1
- package/test/unit/server-config-plugin-registry.test.ts +81 -0
- package/test/unit/server-tools.test.ts +0 -1
- package/test/unit/start-development-goal-extraction.test.ts +22 -16
- package/test/utils/test-helpers.ts +3 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/components/server-components-factory.d.ts +0 -39
- package/dist/components/server-components-factory.d.ts.map +0 -1
- package/dist/components/server-components-factory.js +0 -62
- package/dist/components/server-components-factory.js.map +0 -1
- package/src/components/server-components-factory.ts +0 -86
- package/test/e2e/component-substitution.test.ts +0 -208
- package/test/unit/beads-integration-filename.test.ts +0 -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
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
/**
|