@codemcp/workflows 3.1.21

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 (159) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.vibe/conversation-state.sqlite +0 -0
  3. package/LICENSE +674 -0
  4. package/dist/index.d.ts +9 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +74 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/notification-service.d.ts +14 -0
  9. package/dist/notification-service.d.ts.map +1 -0
  10. package/dist/notification-service.js +18 -0
  11. package/dist/notification-service.js.map +1 -0
  12. package/dist/resource-handlers/conversation-state.d.ts +15 -0
  13. package/dist/resource-handlers/conversation-state.d.ts.map +1 -0
  14. package/dist/resource-handlers/conversation-state.js +40 -0
  15. package/dist/resource-handlers/conversation-state.js.map +1 -0
  16. package/dist/resource-handlers/development-plan.d.ts +14 -0
  17. package/dist/resource-handlers/development-plan.d.ts.map +1 -0
  18. package/dist/resource-handlers/development-plan.js +31 -0
  19. package/dist/resource-handlers/development-plan.js.map +1 -0
  20. package/dist/resource-handlers/index.d.ts +24 -0
  21. package/dist/resource-handlers/index.d.ts.map +1 -0
  22. package/dist/resource-handlers/index.js +62 -0
  23. package/dist/resource-handlers/index.js.map +1 -0
  24. package/dist/resource-handlers/system-prompt.d.ts +15 -0
  25. package/dist/resource-handlers/system-prompt.d.ts.map +1 -0
  26. package/dist/resource-handlers/system-prompt.js +40 -0
  27. package/dist/resource-handlers/system-prompt.js.map +1 -0
  28. package/dist/resource-handlers/workflow-resource.d.ts +15 -0
  29. package/dist/resource-handlers/workflow-resource.d.ts.map +1 -0
  30. package/dist/resource-handlers/workflow-resource.js +85 -0
  31. package/dist/resource-handlers/workflow-resource.js.map +1 -0
  32. package/dist/response-renderer.d.ts +30 -0
  33. package/dist/response-renderer.d.ts.map +1 -0
  34. package/dist/response-renderer.js +94 -0
  35. package/dist/response-renderer.js.map +1 -0
  36. package/dist/server-config.d.ts +34 -0
  37. package/dist/server-config.d.ts.map +1 -0
  38. package/dist/server-config.js +486 -0
  39. package/dist/server-config.js.map +1 -0
  40. package/dist/server-helpers.d.ts +62 -0
  41. package/dist/server-helpers.d.ts.map +1 -0
  42. package/dist/server-helpers.js +156 -0
  43. package/dist/server-helpers.js.map +1 -0
  44. package/dist/server-implementation.d.ts +74 -0
  45. package/dist/server-implementation.d.ts.map +1 -0
  46. package/dist/server-implementation.js +201 -0
  47. package/dist/server-implementation.js.map +1 -0
  48. package/dist/server.d.ts +6 -0
  49. package/dist/server.d.ts.map +1 -0
  50. package/dist/server.js +5 -0
  51. package/dist/server.js.map +1 -0
  52. package/dist/tool-handlers/base-tool-handler.d.ts +50 -0
  53. package/dist/tool-handlers/base-tool-handler.d.ts.map +1 -0
  54. package/dist/tool-handlers/base-tool-handler.js +74 -0
  55. package/dist/tool-handlers/base-tool-handler.js.map +1 -0
  56. package/dist/tool-handlers/conduct-review.d.ts +49 -0
  57. package/dist/tool-handlers/conduct-review.d.ts.map +1 -0
  58. package/dist/tool-handlers/conduct-review.js +105 -0
  59. package/dist/tool-handlers/conduct-review.js.map +1 -0
  60. package/dist/tool-handlers/get-tool-info.d.ts +76 -0
  61. package/dist/tool-handlers/get-tool-info.d.ts.map +1 -0
  62. package/dist/tool-handlers/get-tool-info.js +168 -0
  63. package/dist/tool-handlers/get-tool-info.js.map +1 -0
  64. package/dist/tool-handlers/index.d.ts +42 -0
  65. package/dist/tool-handlers/index.d.ts.map +1 -0
  66. package/dist/tool-handlers/index.js +74 -0
  67. package/dist/tool-handlers/index.js.map +1 -0
  68. package/dist/tool-handlers/install-workflow.d.ts +48 -0
  69. package/dist/tool-handlers/install-workflow.d.ts.map +1 -0
  70. package/dist/tool-handlers/install-workflow.js +131 -0
  71. package/dist/tool-handlers/install-workflow.js.map +1 -0
  72. package/dist/tool-handlers/list-workflows.d.ts +47 -0
  73. package/dist/tool-handlers/list-workflows.d.ts.map +1 -0
  74. package/dist/tool-handlers/list-workflows.js +58 -0
  75. package/dist/tool-handlers/list-workflows.js.map +1 -0
  76. package/dist/tool-handlers/no-idea.d.ts +41 -0
  77. package/dist/tool-handlers/no-idea.d.ts.map +1 -0
  78. package/dist/tool-handlers/no-idea.js +29 -0
  79. package/dist/tool-handlers/no-idea.js.map +1 -0
  80. package/dist/tool-handlers/proceed-to-phase.d.ts +39 -0
  81. package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -0
  82. package/dist/tool-handlers/proceed-to-phase.js +109 -0
  83. package/dist/tool-handlers/proceed-to-phase.js.map +1 -0
  84. package/dist/tool-handlers/reset-development.d.ts +31 -0
  85. package/dist/tool-handlers/reset-development.d.ts.map +1 -0
  86. package/dist/tool-handlers/reset-development.js +48 -0
  87. package/dist/tool-handlers/reset-development.js.map +1 -0
  88. package/dist/tool-handlers/resume-workflow.d.ts +88 -0
  89. package/dist/tool-handlers/resume-workflow.d.ts.map +1 -0
  90. package/dist/tool-handlers/resume-workflow.js +213 -0
  91. package/dist/tool-handlers/resume-workflow.js.map +1 -0
  92. package/dist/tool-handlers/setup-project-docs.d.ts +36 -0
  93. package/dist/tool-handlers/setup-project-docs.d.ts.map +1 -0
  94. package/dist/tool-handlers/setup-project-docs.js +136 -0
  95. package/dist/tool-handlers/setup-project-docs.js.map +1 -0
  96. package/dist/tool-handlers/start-development.d.ts +82 -0
  97. package/dist/tool-handlers/start-development.d.ts.map +1 -0
  98. package/dist/tool-handlers/start-development.js +448 -0
  99. package/dist/tool-handlers/start-development.js.map +1 -0
  100. package/dist/tool-handlers/whats-next.d.ts +42 -0
  101. package/dist/tool-handlers/whats-next.d.ts.map +1 -0
  102. package/dist/tool-handlers/whats-next.js +118 -0
  103. package/dist/tool-handlers/whats-next.js.map +1 -0
  104. package/dist/types.d.ts +114 -0
  105. package/dist/types.d.ts.map +1 -0
  106. package/dist/types.js +5 -0
  107. package/dist/types.js.map +1 -0
  108. package/package.json +29 -0
  109. package/src/index.ts +93 -0
  110. package/src/notification-service.ts +23 -0
  111. package/src/resource-handlers/conversation-state.ts +55 -0
  112. package/src/resource-handlers/development-plan.ts +48 -0
  113. package/src/resource-handlers/index.ts +73 -0
  114. package/src/resource-handlers/system-prompt.ts +55 -0
  115. package/src/resource-handlers/workflow-resource.ts +126 -0
  116. package/src/response-renderer.ts +116 -0
  117. package/src/server-config.ts +744 -0
  118. package/src/server-helpers.ts +225 -0
  119. package/src/server-implementation.ts +277 -0
  120. package/src/server.ts +9 -0
  121. package/src/tool-handlers/base-tool-handler.ts +141 -0
  122. package/src/tool-handlers/conduct-review.ts +191 -0
  123. package/src/tool-handlers/get-tool-info.ts +274 -0
  124. package/src/tool-handlers/index.ts +117 -0
  125. package/src/tool-handlers/install-workflow.ts +185 -0
  126. package/src/tool-handlers/list-workflows.ts +94 -0
  127. package/src/tool-handlers/no-idea.ts +47 -0
  128. package/src/tool-handlers/proceed-to-phase.ts +205 -0
  129. package/src/tool-handlers/reset-development.ts +90 -0
  130. package/src/tool-handlers/resume-workflow.ts +380 -0
  131. package/src/tool-handlers/setup-project-docs.ts +226 -0
  132. package/src/tool-handlers/start-development.ts +685 -0
  133. package/src/tool-handlers/whats-next.ts +235 -0
  134. package/src/types.ts +130 -0
  135. package/test/e2e/core-functionality.test.ts +176 -0
  136. package/test/e2e/mcp-contract.test.ts +540 -0
  137. package/test/e2e/plan-management.test.ts +331 -0
  138. package/test/e2e/state-management.test.ts +392 -0
  139. package/test/e2e/workflow-integration.test.ts +506 -0
  140. package/test/unit/commit-behaviour-interface.test.ts +244 -0
  141. package/test/unit/conduct-review.test.ts +151 -0
  142. package/test/unit/reset-functionality.test.ts +72 -0
  143. package/test/unit/resume-workflow.test.ts +192 -0
  144. package/test/unit/server-tools.test.ts +311 -0
  145. package/test/unit/setup-project-docs-handler.test.ts +267 -0
  146. package/test/unit/start-development-artifact-detection.test.ts +387 -0
  147. package/test/unit/start-development-gitignore.test.ts +178 -0
  148. package/test/unit/system-prompt-resource.test.ts +101 -0
  149. package/test/unit/tool-handlers/no-idea.test.ts +40 -0
  150. package/test/utils/e2e-test-setup.ts +453 -0
  151. package/test/utils/run-server-in-dir.sh +27 -0
  152. package/test/utils/temp-files.ts +308 -0
  153. package/test/utils/test-access.ts +79 -0
  154. package/test/utils/test-helpers.ts +286 -0
  155. package/test/utils/test-setup.ts +78 -0
  156. package/tsconfig.build.json +9 -0
  157. package/tsconfig.build.tsbuildinfo +1 -0
  158. package/tsconfig.json +12 -0
  159. package/vitest.config.ts +17 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Install Workflow Tool Handler
3
+ *
4
+ * Installs workflows to .vibe/workflows/ directory from various sources
5
+ */
6
+
7
+ import { z } from 'zod';
8
+ import { BaseToolHandler } from './base-tool-handler.js';
9
+ import { createLogger } from '@codemcp/workflows-core';
10
+ import { notificationService } from '../notification-service.js';
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import { ServerContext } from '../types.js';
14
+
15
+ const logger = createLogger('InstallWorkflowHandler');
16
+
17
+ /**
18
+ * Schema for install_workflow tool arguments
19
+ */
20
+ const InstallWorkflowArgsSchema = z.object({
21
+ source: z
22
+ .string()
23
+ .describe(
24
+ 'Source workflow name (from unloaded workflows) or URL to workflow file'
25
+ ),
26
+ name: z
27
+ .string()
28
+ .optional()
29
+ .describe('Custom name for installed workflow (defaults to source name)'),
30
+ });
31
+
32
+ type InstallWorkflowArgs = z.infer<typeof InstallWorkflowArgsSchema>;
33
+
34
+ interface InstallWorkflowResponse {
35
+ success: boolean;
36
+ message: string;
37
+ installedPath?: string;
38
+ }
39
+
40
+ /**
41
+ * Tool handler for installing workflows
42
+ */
43
+ export class InstallWorkflowHandler extends BaseToolHandler<
44
+ InstallWorkflowArgs,
45
+ InstallWorkflowResponse
46
+ > {
47
+ protected readonly argsSchema = InstallWorkflowArgsSchema;
48
+
49
+ async executeHandler(
50
+ args: InstallWorkflowArgs,
51
+ context: ServerContext
52
+ ): Promise<InstallWorkflowResponse> {
53
+ logger.info('Installing workflow', {
54
+ source: args.source,
55
+ name: args.name,
56
+ projectPath: context.projectPath,
57
+ });
58
+
59
+ try {
60
+ // Create .vibe/workflows directory if it doesn't exist
61
+ const workflowsDir = path.join(context.projectPath, '.vibe', 'workflows');
62
+ fs.mkdirSync(workflowsDir, { recursive: true });
63
+
64
+ // Determine if source is a workflow name or URL
65
+ const isUrl =
66
+ args.source.startsWith('http://') || args.source.startsWith('https://');
67
+
68
+ if (isUrl) {
69
+ return await this.installFromUrl(args.source, args.name, workflowsDir);
70
+ } else {
71
+ return await this.installFromPredefined(
72
+ args.source,
73
+ args.name,
74
+ workflowsDir,
75
+ context
76
+ );
77
+ }
78
+ } catch (error) {
79
+ const errorMessage = `Failed to install workflow: ${error instanceof Error ? error.message : 'Unknown error'}`;
80
+ logger.error('Workflow installation failed', error as Error, {
81
+ source: args.source,
82
+ name: args.name,
83
+ });
84
+
85
+ return {
86
+ success: false,
87
+ message: errorMessage,
88
+ };
89
+ }
90
+ }
91
+
92
+ private async installFromUrl(
93
+ _url: string,
94
+ _customName: string | undefined,
95
+ _workflowsDir: string
96
+ ): Promise<InstallWorkflowResponse> {
97
+ // For now, return not implemented for URLs
98
+ return {
99
+ success: false,
100
+ message:
101
+ 'URL-based workflow installation not yet implemented. Use predefined workflow names.',
102
+ };
103
+ }
104
+
105
+ private async installFromPredefined(
106
+ workflowName: string,
107
+ customName: string | undefined,
108
+ workflowsDir: string,
109
+ context: ServerContext
110
+ ): Promise<InstallWorkflowResponse> {
111
+ // Get all available workflows (including unloaded ones)
112
+ const allWorkflows = context.workflowManager.getAllAvailableWorkflows();
113
+ const sourceWorkflow = allWorkflows.find(w => w.name === workflowName);
114
+
115
+ if (!sourceWorkflow) {
116
+ return {
117
+ success: false,
118
+ message: `Workflow '${workflowName}' not found. Use list_workflows({include_unloaded: true}) to see available workflows.`,
119
+ };
120
+ }
121
+
122
+ // Find the source workflow file
123
+ const workflowsSourceDir = this.findWorkflowsDirectory();
124
+ const sourceFile = path.join(workflowsSourceDir, `${workflowName}.yaml`);
125
+
126
+ if (!fs.existsSync(sourceFile)) {
127
+ return {
128
+ success: false,
129
+ message: `Source workflow file not found: ${sourceFile}`,
130
+ };
131
+ }
132
+
133
+ // Determine target filename
134
+ const targetName = customName || workflowName;
135
+ const targetFile = path.join(workflowsDir, `${targetName}.yaml`);
136
+
137
+ // Check if target already exists
138
+ if (fs.existsSync(targetFile)) {
139
+ return {
140
+ success: false,
141
+ message: `Workflow '${targetName}' already exists in .vibe/workflows/. Remove it first or use a different name.`,
142
+ };
143
+ }
144
+
145
+ // Copy the workflow file
146
+ fs.copyFileSync(sourceFile, targetFile);
147
+
148
+ // Reload project workflows to make the installed workflow immediately available
149
+ context.workflowManager.loadProjectWorkflows(context.projectPath);
150
+
151
+ logger.info('Workflow installed successfully', {
152
+ source: workflowName,
153
+ target: targetName,
154
+ path: targetFile,
155
+ });
156
+
157
+ // Notify MCP client that tool list has changed. There is no specific
158
+ // notification for parameter description changes, so we reuse tool list change.
159
+ // most MCP hosts will however not support this properly, thus we'll instruct the user to restart the server.
160
+ await notificationService.notifyToolListChanged();
161
+
162
+ return {
163
+ success: true,
164
+ message: `Workflow '${workflowName}' installed as '${targetName}' in .vibe/workflows/ . You may need to restart your agent to use it.`,
165
+ installedPath: targetFile,
166
+ };
167
+ }
168
+
169
+ private findWorkflowsDirectory(): string {
170
+ // Same logic as WorkflowManager
171
+ const possiblePaths = [
172
+ path.join(process.cwd(), 'resources', 'workflows'),
173
+ path.join(process.cwd(), 'dist', '..', 'resources', 'workflows'),
174
+ path.join(process.cwd(), 'src', '..', 'resources', 'workflows'),
175
+ ];
176
+
177
+ for (const workflowsPath of possiblePaths) {
178
+ if (fs.existsSync(workflowsPath)) {
179
+ return workflowsPath;
180
+ }
181
+ }
182
+
183
+ throw new Error('Workflows directory not found');
184
+ }
185
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * List Workflows Tool Handler
3
+ *
4
+ * Provides an overview of all available workflows with their descriptions
5
+ * and resource URIs for detailed information.
6
+ */
7
+
8
+ import { z } from 'zod';
9
+ import { BaseToolHandler } from './base-tool-handler.js';
10
+ import { createLogger } from '@codemcp/workflows-core';
11
+ import { ServerContext } from '../types.js';
12
+
13
+ const logger = createLogger('ListWorkflowsHandler');
14
+
15
+ /**
16
+ * Schema for list_workflows tool arguments
17
+ */
18
+ const ListWorkflowsArgsSchema = z.object({
19
+ include_unloaded: z
20
+ .boolean()
21
+ .optional()
22
+ .describe(
23
+ 'Include workflows not loaded due to domain filtering. Default: false'
24
+ ),
25
+ });
26
+
27
+ type ListWorkflowsArgs = z.infer<typeof ListWorkflowsArgsSchema>;
28
+
29
+ /**
30
+ * Response format for workflow information
31
+ */
32
+ interface WorkflowOverview {
33
+ name: string;
34
+ displayName: string;
35
+ description: string;
36
+ resourceUri: string;
37
+ }
38
+
39
+ interface ListWorkflowsResponse {
40
+ workflows: WorkflowOverview[];
41
+ }
42
+
43
+ /**
44
+ * Tool handler for listing available workflows
45
+ */
46
+ export class ListWorkflowsHandler extends BaseToolHandler<
47
+ ListWorkflowsArgs,
48
+ ListWorkflowsResponse
49
+ > {
50
+ protected readonly argsSchema = ListWorkflowsArgsSchema;
51
+
52
+ async executeHandler(
53
+ args: ListWorkflowsArgs,
54
+ context: ServerContext
55
+ ): Promise<ListWorkflowsResponse> {
56
+ logger.info('Listing available workflows', {
57
+ projectPath: context.projectPath,
58
+ includeUnloaded: args.include_unloaded,
59
+ });
60
+
61
+ let availableWorkflows;
62
+
63
+ if (args.include_unloaded) {
64
+ // Get all workflows regardless of domain filtering
65
+ availableWorkflows = context.workflowManager.getAllAvailableWorkflows();
66
+ } else {
67
+ // Get only loaded workflows (respects current domain filtering)
68
+ availableWorkflows =
69
+ context.workflowManager.getAvailableWorkflowsForProject(
70
+ context.projectPath
71
+ );
72
+ }
73
+
74
+ // Transform to response format with resource URIs
75
+ const workflows: WorkflowOverview[] = availableWorkflows.map(workflow => ({
76
+ name: workflow.name,
77
+ displayName: workflow.displayName,
78
+ description: workflow.description,
79
+ resourceUri: `workflow://${workflow.name}`,
80
+ }));
81
+
82
+ const response: ListWorkflowsResponse = {
83
+ workflows,
84
+ };
85
+
86
+ logger.info('Successfully listed workflows', {
87
+ count: workflows.length,
88
+ includeUnloaded: args.include_unloaded,
89
+ workflows: workflows.map(w => w.name),
90
+ });
91
+
92
+ return response;
93
+ }
94
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * No Idea Tool Handler
3
+ *
4
+ * Provides instructions for LLMs to acknowledge knowledge gaps
5
+ * instead of hallucinating responses.
6
+ */
7
+
8
+ import { z } from 'zod';
9
+ import { BaseToolHandler } from './base-tool-handler.js';
10
+ import { ServerContext } from '../types.js';
11
+
12
+ /**
13
+ * Schema for no_idea tool arguments
14
+ */
15
+ const NoIdeaArgsSchema = z.object({
16
+ context: z
17
+ .string()
18
+ .optional()
19
+ .describe('Optional context about what you have no knowledge of'),
20
+ });
21
+
22
+ export type NoIdeaArgs = z.infer<typeof NoIdeaArgsSchema>;
23
+
24
+ /**
25
+ * Response format for no_idea tool
26
+ */
27
+ export interface NoIdeaResponse {
28
+ instructions: string;
29
+ }
30
+
31
+ /**
32
+ * Tool handler for acknowledging knowledge gaps
33
+ */
34
+ export class NoIdeaHandler extends BaseToolHandler<NoIdeaArgs, NoIdeaResponse> {
35
+ protected readonly argsSchema = NoIdeaArgsSchema;
36
+
37
+ async executeHandler(
38
+ args: NoIdeaArgs,
39
+ _context: ServerContext
40
+ ): Promise<NoIdeaResponse> {
41
+ const context = args.context?.trim() || 'this topic';
42
+
43
+ const instructions = `You have no clue how to respond to ${context}. Admit it. Ask the user clarifying questions which might help you get new ideas.`;
44
+
45
+ return { instructions };
46
+ }
47
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * ProceedToPhase Tool Handler
3
+ *
4
+ * Handles explicit transitions to specific development phases when the current
5
+ * phase is complete or when a direct phase change is needed.
6
+ */
7
+
8
+ import { ConversationRequiredToolHandler } from './base-tool-handler.js';
9
+ import { validateRequiredArgs } from '../server-helpers.js';
10
+ import type { ConversationContext } from '@codemcp/workflows-core';
11
+ import { ServerContext } from '../types.js';
12
+
13
+ /**
14
+ * Arguments for the proceed_to_phase tool
15
+ */
16
+ export interface ProceedToPhaseArgs {
17
+ target_phase: string;
18
+ reason?: string;
19
+ review_state: 'not-required' | 'pending' | 'performed';
20
+ }
21
+
22
+ /**
23
+ * Response from the proceed_to_phase tool
24
+ */
25
+ export interface ProceedToPhaseResult {
26
+ phase: string;
27
+ instructions: string;
28
+ plan_file_path: string;
29
+ transition_reason: string;
30
+ is_modeled_transition: boolean;
31
+ conversation_id: string;
32
+ }
33
+
34
+ /**
35
+ * ProceedToPhase tool handler implementation
36
+ */
37
+ export class ProceedToPhaseHandler extends ConversationRequiredToolHandler<
38
+ ProceedToPhaseArgs,
39
+ ProceedToPhaseResult
40
+ > {
41
+ protected async executeWithConversation(
42
+ args: ProceedToPhaseArgs,
43
+ context: ServerContext,
44
+ conversationContext: ConversationContext
45
+ ): Promise<ProceedToPhaseResult> {
46
+ // Validate required arguments
47
+ validateRequiredArgs(args, ['target_phase', 'review_state']);
48
+
49
+ const { target_phase, reason = '', review_state } = args;
50
+ const conversationId = conversationContext.conversationId;
51
+ const currentPhase = conversationContext.currentPhase;
52
+
53
+ this.logger.debug('Processing proceed_to_phase request', {
54
+ conversationId,
55
+ currentPhase,
56
+ targetPhase: target_phase,
57
+ reason,
58
+ reviewState: review_state,
59
+ });
60
+
61
+ // Validate review state if reviews are required
62
+ if (conversationContext.requireReviewsBeforePhaseTransition) {
63
+ await this.validateReviewState(
64
+ review_state,
65
+ currentPhase,
66
+ target_phase,
67
+ conversationContext.workflowName,
68
+ context
69
+ );
70
+ }
71
+
72
+ // Ensure state machine is loaded for this project
73
+ this.ensureStateMachineForProject(context, conversationContext.projectPath);
74
+
75
+ // Perform explicit transition
76
+ const transitionResult = context.transitionEngine.handleExplicitTransition(
77
+ currentPhase,
78
+ target_phase,
79
+ conversationContext.projectPath,
80
+ reason,
81
+ conversationContext.workflowName
82
+ );
83
+
84
+ // Update conversation state
85
+ await context.conversationManager.updateConversationState(conversationId, {
86
+ currentPhase: transitionResult.newPhase,
87
+ });
88
+
89
+ this.logger.info('Explicit phase transition completed', {
90
+ from: currentPhase,
91
+ to: transitionResult.newPhase,
92
+ reason: transitionResult.transitionReason,
93
+ });
94
+
95
+ // Ensure plan file exists
96
+ await context.planManager.ensurePlanFile(
97
+ conversationContext.planFilePath,
98
+ conversationContext.projectPath,
99
+ conversationContext.gitBranch
100
+ );
101
+
102
+ // Check if plan file exists
103
+ const planInfo = await context.planManager.getPlanFileInfo(
104
+ conversationContext.planFilePath
105
+ );
106
+
107
+ // Generate enhanced instructions
108
+ const instructions =
109
+ await context.instructionGenerator.generateInstructions(
110
+ transitionResult.instructions,
111
+ {
112
+ phase: transitionResult.newPhase,
113
+ conversationContext: {
114
+ ...conversationContext,
115
+ currentPhase: transitionResult.newPhase,
116
+ },
117
+ transitionReason: transitionResult.transitionReason,
118
+ isModeled: transitionResult.isModeled,
119
+ planFileExists: planInfo.exists,
120
+ }
121
+ );
122
+
123
+ // Add commit instructions if configured
124
+ let finalInstructions = instructions.instructions;
125
+ if (
126
+ conversationContext.gitCommitConfig?.enabled &&
127
+ conversationContext.gitCommitConfig.commitOnPhase
128
+ ) {
129
+ const commitMessage = `Phase transition: ${currentPhase} → ${target_phase}`;
130
+ finalInstructions += `\n\n**Git Commit Required**: Create a commit for this phase transition using:\n\`\`\`bash\ngit add . && git commit -m "${commitMessage}"\n\`\`\``;
131
+ }
132
+
133
+ // Prepare response
134
+ const response: ProceedToPhaseResult = {
135
+ phase: transitionResult.newPhase,
136
+ instructions: finalInstructions,
137
+ plan_file_path: conversationContext.planFilePath,
138
+ transition_reason: transitionResult.transitionReason,
139
+ is_modeled_transition: transitionResult.isModeled,
140
+ conversation_id: conversationContext.conversationId,
141
+ };
142
+
143
+ // Log interaction
144
+ await this.logInteraction(
145
+ context,
146
+ conversationId,
147
+ 'proceed_to_phase',
148
+ args,
149
+ response,
150
+ transitionResult.newPhase
151
+ );
152
+
153
+ return response;
154
+ }
155
+
156
+ /**
157
+ * Validate review state for transitions that require reviews
158
+ */
159
+ private async validateReviewState(
160
+ reviewState: string,
161
+ currentPhase: string,
162
+ targetPhase: string,
163
+ workflowName: string,
164
+ context: ServerContext
165
+ ): Promise<void> {
166
+ // Get transition configuration from workflow
167
+ const stateMachine = context.workflowManager.loadWorkflowForProject(
168
+ context.projectPath,
169
+ workflowName
170
+ );
171
+ const currentState = stateMachine.states[currentPhase];
172
+
173
+ if (!currentState) {
174
+ throw new Error(`Invalid current phase: ${currentPhase}`);
175
+ }
176
+
177
+ const transition = currentState.transitions.find(t => t.to === targetPhase);
178
+ if (!transition) {
179
+ throw new Error(
180
+ `No transition found from ${currentPhase} to ${targetPhase}`
181
+ );
182
+ }
183
+
184
+ const hasReviewPerspectives =
185
+ transition.review_perspectives &&
186
+ transition.review_perspectives.length > 0;
187
+
188
+ if (hasReviewPerspectives) {
189
+ // This transition has review perspectives defined
190
+ if (reviewState === 'pending') {
191
+ throw new Error(
192
+ `Review is required before proceeding to ${targetPhase}. Please use the conduct_review tool first.`
193
+ );
194
+ }
195
+ if (reviewState === 'not-required') {
196
+ throw new Error(
197
+ `This transition requires review, but review_state is 'not-required'. Use 'pending' or 'performed'.`
198
+ );
199
+ }
200
+ } else {
201
+ // No review perspectives defined - transition proceeds normally
202
+ // Note: No error thrown when hasReviewPerspectives is false, as per user feedback
203
+ }
204
+ }
205
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * ResetDevelopment Tool Handler
3
+ *
4
+ * Handles resetting conversation state and development progress.
5
+ * This permanently deletes conversation state and plan file, while
6
+ * soft-deleting interaction logs for audit trail.
7
+ */
8
+
9
+ import { BaseToolHandler } from './base-tool-handler.js';
10
+ import { validateRequiredArgs } from '../server-helpers.js';
11
+ import { ServerContext } from '../types.js';
12
+
13
+ /**
14
+ * Arguments for the reset_development tool
15
+ */
16
+ export interface ResetDevelopmentArgs {
17
+ confirm: boolean;
18
+ reason?: string;
19
+ }
20
+
21
+ /**
22
+ * Response from the reset_development tool
23
+ */
24
+ export interface ResetDevelopmentResult {
25
+ success: boolean;
26
+ resetItems: string[];
27
+ message: string;
28
+ }
29
+
30
+ /**
31
+ * ResetDevelopment tool handler implementation
32
+ */
33
+ export class ResetDevelopmentHandler extends BaseToolHandler<
34
+ ResetDevelopmentArgs,
35
+ ResetDevelopmentResult
36
+ > {
37
+ protected async executeHandler(
38
+ args: ResetDevelopmentArgs,
39
+ context: ServerContext
40
+ ): Promise<ResetDevelopmentResult> {
41
+ // Validate required arguments
42
+ validateRequiredArgs(args, ['confirm']);
43
+
44
+ const { confirm, reason } = args;
45
+
46
+ this.logger.debug('Processing reset_development request', {
47
+ confirm,
48
+ hasReason: !!reason,
49
+ });
50
+
51
+ // Validate parameters
52
+ if (typeof confirm !== 'boolean') {
53
+ throw new Error('confirm parameter must be a boolean');
54
+ }
55
+
56
+ if (!confirm) {
57
+ throw new Error(
58
+ 'Reset operation requires explicit confirmation. Set confirm parameter to true.'
59
+ );
60
+ }
61
+
62
+ // Ensure state machine is loaded for current project
63
+ this.ensureStateMachineForProject(context, context.projectPath);
64
+
65
+ // Perform the reset
66
+ const resetResult = await context.conversationManager.resetConversation(
67
+ confirm,
68
+ reason
69
+ );
70
+
71
+ // Transform to match our interface
72
+ const result: ResetDevelopmentResult = {
73
+ success: resetResult.success,
74
+ resetItems: resetResult.resetItems,
75
+ message: resetResult.message,
76
+ };
77
+
78
+ // Add conversationId for backward compatibility with tests
79
+ (
80
+ result as ResetDevelopmentResult & { conversationId: string }
81
+ ).conversationId = resetResult.conversationId;
82
+
83
+ this.logger.info('Reset development completed successfully', {
84
+ resetItems: result.resetItems,
85
+ reason,
86
+ });
87
+
88
+ return result;
89
+ }
90
+ }