@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,246 +0,0 @@
1
- /**
2
- * WhatsNext Tool Handler
3
- *
4
- * Handles the whats_next tool which analyzes conversation context and
5
- * determines the next development phase with specific instructions for the LLM.
6
- */
7
-
8
- import { ConversationRequiredToolHandler } from './base-tool-handler.js';
9
- import type { ConversationContext } from '@codemcp/workflows-core';
10
- // TaskBackendManager and BeadsIntegration functionality now handled by injected components
11
- import { ServerContext } from '../types.js';
12
-
13
- /**
14
- * Arguments for the whats_next tool
15
- */
16
- export interface WhatsNextArgs {
17
- context?: string;
18
- user_input?: string;
19
- conversation_summary?: string;
20
- recent_messages?: Array<{
21
- role: 'user' | 'assistant';
22
- content: string;
23
- }>;
24
- }
25
-
26
- /**
27
- * Response from the whats_next tool
28
- */
29
- export interface WhatsNextResult {
30
- phase: string;
31
- instructions: string;
32
- plan_file_path: string;
33
- }
34
-
35
- /**
36
- * WhatsNext tool handler implementation
37
- */
38
- export class WhatsNextHandler extends ConversationRequiredToolHandler<
39
- WhatsNextArgs,
40
- WhatsNextResult
41
- > {
42
- protected override async executeHandler(
43
- args: WhatsNextArgs,
44
- context: ServerContext
45
- ): Promise<WhatsNextResult> {
46
- let conversationContext;
47
-
48
- try {
49
- conversationContext = await this.getConversationContext(context);
50
- } catch (_error) {
51
- // Use standard CONVERSATION_NOT_FOUND error
52
- throw new Error('CONVERSATION_NOT_FOUND');
53
- }
54
-
55
- return this.executeWithConversation(args, context, conversationContext);
56
- }
57
-
58
- protected async executeWithConversation(
59
- args: WhatsNextArgs,
60
- context: ServerContext,
61
- conversationContext: ConversationContext
62
- ): Promise<WhatsNextResult> {
63
- const {
64
- context: requestContext = '',
65
- user_input = '',
66
- conversation_summary = '',
67
- recent_messages = [],
68
- } = args;
69
-
70
- const conversationId = conversationContext.conversationId;
71
- const currentPhase = conversationContext.currentPhase;
72
-
73
- this.logger.debug('Processing whats_next request', {
74
- conversationId,
75
- currentPhase,
76
- hasContext: !!requestContext,
77
- hasUserInput: !!user_input,
78
- });
79
-
80
- // Ensure state machine is loaded for this project
81
- this.ensureStateMachineForProject(
82
- context,
83
- conversationContext.projectPath,
84
- conversationContext.workflowName
85
- );
86
-
87
- // Ensure plan file exists
88
- await context.planManager.ensurePlanFile(
89
- conversationContext.planFilePath,
90
- conversationContext.projectPath,
91
- conversationContext.gitBranch
92
- );
93
-
94
- // Analyze phase transition
95
- const transitionResult =
96
- await context.transitionEngine.analyzePhaseTransition({
97
- currentPhase,
98
- projectPath: conversationContext.projectPath,
99
- userInput: user_input,
100
- context: requestContext,
101
- conversationSummary: conversation_summary,
102
- recentMessages: recent_messages,
103
- conversationId: conversationContext.conversationId,
104
- });
105
-
106
- // Update conversation state if phase changed
107
- if (transitionResult.newPhase !== currentPhase) {
108
- const shouldUpdateState = await this.shouldUpdateConversationState(
109
- currentPhase,
110
- transitionResult.newPhase,
111
- conversationContext,
112
- context
113
- );
114
-
115
- if (shouldUpdateState) {
116
- await context.conversationManager.updateConversationState(
117
- conversationId,
118
- { currentPhase: transitionResult.newPhase }
119
- );
120
- }
121
-
122
- // If this was a first-call auto-transition, regenerate the plan file
123
- if (
124
- transitionResult.transitionReason.includes(
125
- 'Starting development - defining criteria'
126
- )
127
- ) {
128
- this.logger.info(
129
- 'Regenerating plan file after first-call auto-transition',
130
- {
131
- from: currentPhase,
132
- to: transitionResult.newPhase,
133
- planFilePath: conversationContext.planFilePath,
134
- }
135
- );
136
-
137
- await context.planManager.ensurePlanFile(
138
- conversationContext.planFilePath,
139
- conversationContext.projectPath,
140
- conversationContext.gitBranch
141
- );
142
- }
143
-
144
- this.logger.info('Phase transition completed', {
145
- from: currentPhase,
146
- to: transitionResult.newPhase,
147
- reason: transitionResult.transitionReason,
148
- });
149
- }
150
-
151
- // Check if plan file exists
152
- const planInfo = await context.planManager.getPlanFileInfo(
153
- conversationContext.planFilePath
154
- );
155
-
156
- // Generate enhanced instructions
157
- const instructions =
158
- await context.instructionGenerator.generateInstructions(
159
- transitionResult.instructions,
160
- {
161
- phase: transitionResult.newPhase,
162
- conversationContext: {
163
- ...conversationContext,
164
- currentPhase: transitionResult.newPhase,
165
- },
166
- transitionReason: transitionResult.transitionReason,
167
- isModeled: transitionResult.isModeled,
168
- planFileExists: planInfo.exists,
169
- instructionSource: 'whats_next',
170
- }
171
- );
172
-
173
- // Note: Commit behavior now handled by CommitPlugin
174
- // Note: Beads-specific instructions are now handled by BeadsInstructionGenerator via strategy pattern
175
-
176
- // Prepare response
177
- const response: WhatsNextResult = {
178
- phase: transitionResult.newPhase,
179
- instructions: instructions.instructions,
180
- plan_file_path: conversationContext.planFilePath,
181
- };
182
-
183
- // Log interaction
184
- await this.logInteraction(
185
- context,
186
- conversationId,
187
- 'whats_next',
188
- args,
189
- response,
190
- transitionResult.newPhase
191
- );
192
-
193
- return response;
194
- }
195
-
196
- /**
197
- * Determines whether conversation state should be updated for a phase transition
198
- */
199
- private async shouldUpdateConversationState(
200
- currentPhase: string,
201
- newPhase: string,
202
- conversationContext: ConversationContext,
203
- context: ServerContext
204
- ): Promise<boolean> {
205
- if (!conversationContext.requireReviewsBeforePhaseTransition) {
206
- return true;
207
- }
208
-
209
- const stateMachine = context.workflowManager.loadWorkflowForProject(
210
- conversationContext.projectPath,
211
- conversationContext.workflowName
212
- );
213
-
214
- const currentState = stateMachine.states[currentPhase];
215
- if (!currentState) {
216
- return true;
217
- }
218
-
219
- const transition = currentState.transitions.find(t => t.to === newPhase);
220
- if (!transition) {
221
- return true;
222
- }
223
-
224
- const hasReviewPerspectives =
225
- transition.review_perspectives &&
226
- transition.review_perspectives.length > 0;
227
-
228
- if (hasReviewPerspectives) {
229
- this.logger.debug(
230
- 'Preventing state update - review required for transition',
231
- {
232
- from: currentPhase,
233
- to: newPhase,
234
- reviewPerspectives: transition.review_perspectives?.length || 0,
235
- }
236
- );
237
- return false;
238
- }
239
-
240
- return true;
241
- }
242
-
243
- // Beads-specific instruction logic has been moved to BeadsInstructionGenerator strategy
244
-
245
- // Utility methods moved to strategy implementations where needed
246
- }
package/src/types.ts DELETED
@@ -1,135 +0,0 @@
1
- /**
2
- * Core types and interfaces for the refactored server architecture
3
- */
4
-
5
- import { ConversationManager } from '@codemcp/workflows-core';
6
- import { TransitionEngine } from '@codemcp/workflows-core';
7
- import { IPlanManager } from '@codemcp/workflows-core';
8
- import { IInstructionGenerator } from '@codemcp/workflows-core';
9
- import { WorkflowManager } from '@codemcp/workflows-core';
10
- import { InteractionLogger } from '@codemcp/workflows-core';
11
- import type { TaskBackendConfig } from '@codemcp/workflows-core';
12
- import type { IPluginRegistry } from './plugin-system/plugin-interfaces.js';
13
-
14
- /**
15
- * Server context shared across all handlers
16
- * Contains all the core dependencies needed by tool and resource handlers
17
- */
18
- export interface ServerContext {
19
- conversationManager: ConversationManager;
20
- transitionEngine: TransitionEngine;
21
- planManager: IPlanManager;
22
- instructionGenerator: IInstructionGenerator;
23
- workflowManager: WorkflowManager;
24
- interactionLogger?: InteractionLogger;
25
- projectPath: string;
26
- pluginRegistry?: IPluginRegistry;
27
- }
28
-
29
- /**
30
- * Standard result format for all handler operations
31
- * Separates business logic results from MCP protocol concerns
32
- */
33
- export interface HandlerResult<T = unknown> {
34
- success: boolean;
35
- data?: T;
36
- error?: string;
37
- metadata?: Record<string, unknown>;
38
- }
39
-
40
- /**
41
- * Resource content structure
42
- */
43
- export interface ResourceContent {
44
- uri: string;
45
- text: string;
46
- mimeType: string;
47
- }
48
-
49
- /**
50
- * MCP Tool Response format (compatible with MCP SDK)
51
- */
52
- export interface McpToolResponse {
53
- [x: string]: unknown;
54
- content: Array<{
55
- type: 'text';
56
- text: string;
57
- }>;
58
- isError?: boolean;
59
- }
60
-
61
- /**
62
- * MCP Resource Response format (compatible with MCP SDK)
63
- */
64
- export interface McpResourceResponse {
65
- [x: string]: unknown;
66
- contents: Array<{
67
- uri: string;
68
- text: string;
69
- mimeType: string;
70
- }>;
71
- }
72
-
73
- /**
74
- * Tool handler interface
75
- * All tool handlers must implement this interface
76
- */
77
- export interface ToolHandler<TArgs = unknown, TResult = unknown> {
78
- handle(args: TArgs, context: ServerContext): Promise<HandlerResult<TResult>>;
79
- }
80
-
81
- /**
82
- * Resource handler interface
83
- * All resource handlers must implement this interface
84
- */
85
- export interface ResourceHandler {
86
- handle(
87
- uri: URL,
88
- context: ServerContext
89
- ): Promise<HandlerResult<ResourceContent>>;
90
- }
91
-
92
- /**
93
- * Response renderer interface
94
- * Handles translation between domain results and MCP protocol responses
95
- */
96
- export interface ResponseRenderer {
97
- renderToolResponse<T>(result: HandlerResult<T>): McpToolResponse;
98
- renderResourceResponse(
99
- result: HandlerResult<ResourceContent>
100
- ): McpResourceResponse;
101
- renderError(error: Error | string): McpToolResponse;
102
- }
103
-
104
- /**
105
- * Tool registry interface
106
- * Manages registration and lookup of tool handlers
107
- */
108
- export interface ToolRegistry {
109
- register<T extends ToolHandler>(name: string, handler: T): void;
110
- get(name: string): ToolHandler | undefined;
111
- list(): string[];
112
- }
113
-
114
- /**
115
- * Resource registry interface
116
- * Manages registration and lookup of resource handlers
117
- */
118
- export interface ResourceRegistry {
119
- register(pattern: string, handler: ResourceHandler): void;
120
- resolve(uri: string): ResourceHandler | undefined;
121
- }
122
-
123
- /**
124
- * Server configuration options
125
- */
126
- export interface ServerConfig {
127
- /** Project path to operate on (defaults to process.cwd()) */
128
- projectPath?: string;
129
- /** Database path override */
130
- databasePath?: string;
131
- /** Enable interaction logging */
132
- enableLogging?: boolean;
133
- /** Task backend configuration override (for testing) */
134
- taskBackend?: TaskBackendConfig;
135
- }
@@ -1,213 +0,0 @@
1
- /**
2
- * Version Information Utility
3
- *
4
- * Provides version information for the MCP server, supporting both
5
- * build-time injection and runtime determination for local development.
6
- */
7
-
8
- import { execSync } from 'node:child_process';
9
- import { readFileSync } from 'node:fs';
10
- import { join, dirname } from 'node:path';
11
- import { fileURLToPath } from 'node:url';
12
- import { createLogger } from '@codemcp/workflows-core';
13
-
14
- const logger = createLogger('VersionInfo');
15
-
16
- /**
17
- * Structure for version information
18
- */
19
- export interface VersionInfo {
20
- /** The semantic version (e.g., "4.8.0") */
21
- version: string;
22
- /** Git commit hash (short form, e.g., "bbb06ba") */
23
- commit?: string;
24
- /** Whether working directory has uncommitted changes */
25
- isDirty?: boolean;
26
- /** Full git describe output (e.g., "v4.8.0-1-gbbb06ba-dirty") */
27
- gitDescribe?: string;
28
- /** Source of version information */
29
- source: 'package.json' | 'git' | 'build-time' | 'fallback';
30
- }
31
-
32
- /**
33
- * Build-time version information (injected during build process)
34
- * This will be replaced by the build system with actual values
35
- */
36
- // @ts-ignore - This is replaced at build time
37
- const BUILD_TIME_VERSION: VersionInfo | null = null;
38
-
39
- /**
40
- * Gets version information from package.json
41
- */
42
- function getVersionFromPackageJson(): VersionInfo | null {
43
- try {
44
- // Get the directory of this module
45
- const currentDir = dirname(fileURLToPath(import.meta.url));
46
-
47
- // Try to find package.json - first in the mcp-server package, then root
48
- const packageJsonPaths = [
49
- join(currentDir, '..', 'package.json'),
50
- join(currentDir, '..', '..', '..', 'package.json'),
51
- ];
52
-
53
- for (const packageJsonPath of packageJsonPaths) {
54
- try {
55
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
56
- if (packageJson.version) {
57
- logger.debug('Found version in package.json', {
58
- path: packageJsonPath,
59
- version: packageJson.version,
60
- });
61
-
62
- return {
63
- version: packageJson.version,
64
- source: 'package.json',
65
- };
66
- }
67
- } catch (error) {
68
- logger.debug('Could not read package.json', {
69
- path: packageJsonPath,
70
- error: error instanceof Error ? error.message : String(error),
71
- });
72
- }
73
- }
74
-
75
- return null;
76
- } catch (error) {
77
- logger.debug('Error getting version from package.json', { error });
78
- return null;
79
- }
80
- }
81
-
82
- /**
83
- * Gets version information from git
84
- */
85
- function getVersionFromGit(): VersionInfo | null {
86
- try {
87
- // Get git describe output
88
- const gitDescribe = execSync('git describe --tags --always --dirty', {
89
- encoding: 'utf-8',
90
- stdio: 'pipe',
91
- }).trim();
92
-
93
- logger.debug('Git describe output', { gitDescribe });
94
-
95
- // Parse git describe output (e.g., "v4.8.0-1-gbbb06ba-dirty")
96
- const isDirty = gitDescribe.endsWith('-dirty');
97
- const cleanDescribe = isDirty ? gitDescribe.slice(0, -6) : gitDescribe;
98
-
99
- // Try to extract version and commit
100
- const parts = cleanDescribe.split('-');
101
- let version: string;
102
- let commit: string | undefined;
103
-
104
- if (parts.length >= 3 && parts[0]?.startsWith('v')) {
105
- // Format: v4.8.0-1-gbbb06ba
106
- version = parts[0].slice(1); // Remove 'v' prefix
107
- commit = parts[2]?.startsWith('g') ? parts[2].slice(1) : parts[2];
108
- } else if (parts.length === 1 && parts[0]?.startsWith('v')) {
109
- // Format: v4.8.0 (exact tag)
110
- version = parts[0].slice(1);
111
- } else if (parts.length === 1) {
112
- // Format: commit hash only
113
- version = 'unknown';
114
- commit = parts[0];
115
- } else {
116
- // Fallback
117
- version = 'unknown';
118
- }
119
-
120
- return {
121
- version,
122
- commit,
123
- isDirty,
124
- gitDescribe,
125
- source: 'git',
126
- };
127
- } catch (error) {
128
- logger.debug('Error getting version from git', {
129
- error: error instanceof Error ? error.message : String(error),
130
- });
131
- return null;
132
- }
133
- }
134
-
135
- /**
136
- * Gets comprehensive version information, trying multiple sources
137
- */
138
- export function getVersionInfo(): VersionInfo {
139
- logger.debug('Determining version information');
140
-
141
- // Try build-time version first (will be null in development)
142
- if (BUILD_TIME_VERSION) {
143
- logger.info('Using build-time version information', {
144
- version: BUILD_TIME_VERSION.version,
145
- source: BUILD_TIME_VERSION.source,
146
- });
147
- return BUILD_TIME_VERSION;
148
- }
149
-
150
- // Try git version info (best for development)
151
- const gitVersion = getVersionFromGit();
152
- if (gitVersion) {
153
- // If we have git info, try to enhance with package.json version
154
- const packageVersion = getVersionFromPackageJson();
155
- if (packageVersion && gitVersion.version === 'unknown') {
156
- logger.info('Using package.json version with git commit info', {
157
- version: packageVersion.version,
158
- commit: gitVersion.commit || 'unknown',
159
- isDirty: String(gitVersion.isDirty || false),
160
- });
161
-
162
- return {
163
- ...gitVersion,
164
- version: packageVersion.version,
165
- source: 'git' as const,
166
- };
167
- }
168
-
169
- logger.info('Using git version information', {
170
- version: gitVersion.version,
171
- source: gitVersion.source,
172
- commit: gitVersion.commit || 'none',
173
- isDirty: String(gitVersion.isDirty || false),
174
- });
175
- return gitVersion;
176
- }
177
-
178
- // Fallback to package.json only
179
- const packageVersion = getVersionFromPackageJson();
180
- if (packageVersion) {
181
- logger.info('Using package.json version information', {
182
- version: packageVersion.version,
183
- source: packageVersion.source,
184
- });
185
- return packageVersion;
186
- }
187
-
188
- // Final fallback
189
- logger.warn('Could not determine version information, using fallback');
190
- return {
191
- version: 'unknown',
192
- source: 'fallback',
193
- };
194
- }
195
-
196
- /**
197
- * Gets a formatted version string suitable for display
198
- */
199
- export function getFormattedVersion(): string {
200
- const versionInfo = getVersionInfo();
201
-
202
- let formatted = versionInfo.version;
203
-
204
- if (versionInfo.commit) {
205
- formatted += `+${versionInfo.commit}`;
206
- }
207
-
208
- if (versionInfo.isDirty) {
209
- formatted += '.dirty';
210
- }
211
-
212
- return formatted;
213
- }