@codemcp/workflows 4.10.0 → 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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/components/beads/beads-instruction-generator.d.ts +3 -4
- package/dist/components/beads/beads-instruction-generator.d.ts.map +1 -1
- package/dist/components/beads/beads-instruction-generator.js +12 -7
- 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/proceed-to-phase.d.ts +0 -5
- package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -1
- package/dist/tool-handlers/proceed-to-phase.js +15 -93
- package/dist/tool-handlers/proceed-to-phase.js.map +1 -1
- package/dist/tool-handlers/start-development.d.ts +0 -13
- package/dist/tool-handlers/start-development.d.ts.map +1 -1
- package/dist/tool-handlers/start-development.js +29 -124
- package/dist/tool-handlers/start-development.js.map +1 -1
- package/dist/tool-handlers/whats-next.d.ts.map +1 -1
- package/dist/tool-handlers/whats-next.js +1 -0
- 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 +12 -12
- 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/proceed-to-phase.ts +19 -135
- package/src/tool-handlers/start-development.ts +35 -205
- package/src/tool-handlers/whats-next.ts +1 -0
- package/src/types.ts +2 -0
- package/test/e2e/beads-plugin-integration.test.ts +1609 -0
- package/test/e2e/plugin-system-integration.test.ts +1729 -0
- 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/server-config-plugin-registry.test.ts +81 -0
- 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
|
|
@@ -213,15 +210,39 @@ export class StartDevelopmentHandler extends BaseToolHandler<
|
|
|
213
210
|
conversationContext.gitBranch
|
|
214
211
|
);
|
|
215
212
|
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
/**
|