@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,380 @@
1
+ /**
2
+ * ResumeWorkflow Tool Handler
3
+ *
4
+ * Handles resuming development workflow after conversation compression.
5
+ * Returns comprehensive project context, current state, system prompt instructions,
6
+ * and next steps to seamlessly continue development.
7
+ */
8
+
9
+ import { ConversationRequiredToolHandler } from './base-tool-handler.js';
10
+ import { generateSystemPrompt } from '@codemcp/workflows-core';
11
+ import type { YamlStateMachine, YamlState } from '@codemcp/workflows-core';
12
+ import { ServerContext } from '../types.js';
13
+
14
+ /**
15
+ * Arguments for the resume_workflow tool
16
+ */
17
+ export interface ResumeWorkflowArgs {
18
+ include_system_prompt?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Plan file analysis result
23
+ */
24
+ interface PlanAnalysis {
25
+ sections: string[];
26
+ tasks_completed: number;
27
+ tasks_total: number;
28
+ key_decisions: string[];
29
+ recent_updates: string[];
30
+ active_tasks?: string[];
31
+ completed_tasks?: string[];
32
+ }
33
+
34
+ /**
35
+ * Conversation context for resume workflow
36
+ */
37
+ interface ConversationContext {
38
+ conversationId: string;
39
+ currentPhase: string;
40
+ projectPath: string;
41
+ workflowName: string;
42
+ gitBranch: string;
43
+ planFilePath: string;
44
+ current_phase?: string;
45
+ workflow_name?: string;
46
+ project_context?: string;
47
+ recent_activity?: string[];
48
+ }
49
+
50
+ /**
51
+ * Recommendations for resuming workflow
52
+ */
53
+ interface WorkflowRecommendations {
54
+ immediate_actions: string[];
55
+ phase_guidance: string;
56
+ potential_issues: string[];
57
+ }
58
+
59
+ /**
60
+ * Response from the resume_workflow tool
61
+ */
62
+ export interface ResumeWorkflowResult {
63
+ workflow_status: {
64
+ conversation_id: string;
65
+ current_phase: string;
66
+ project_path: string;
67
+ git_branch: string;
68
+ state_machine: YamlStateMachine;
69
+ };
70
+ plan_status: {
71
+ exists: boolean;
72
+ path: string;
73
+ analysis?: PlanAnalysis | null;
74
+ };
75
+ system_prompt?: string | null;
76
+ recommendations: {
77
+ immediate_actions: string[];
78
+ phase_guidance: string;
79
+ potential_issues: string[];
80
+ };
81
+ generated_at: string;
82
+ tool_version: string;
83
+ }
84
+
85
+ /**
86
+ * ResumeWorkflow tool handler implementation
87
+ */
88
+ export class ResumeWorkflowHandler extends ConversationRequiredToolHandler<
89
+ ResumeWorkflowArgs,
90
+ ResumeWorkflowResult
91
+ > {
92
+ protected async executeWithConversation(
93
+ args: ResumeWorkflowArgs,
94
+ context: ServerContext,
95
+ conversationContext: ConversationContext
96
+ ): Promise<ResumeWorkflowResult> {
97
+ const includeSystemPrompt = args.include_system_prompt !== false; // Default to true
98
+
99
+ this.logger.debug('Processing resume_workflow request', {
100
+ conversationId: conversationContext.conversationId,
101
+ includeSystemPrompt,
102
+ });
103
+
104
+ // Get plan file information
105
+ const planInfo = await context.planManager.getPlanFileInfo(
106
+ conversationContext.planFilePath
107
+ );
108
+
109
+ // Analyze plan file content for key information
110
+ const planAnalysis =
111
+ planInfo.exists && planInfo.content
112
+ ? this.analyzePlanFile(planInfo.content)
113
+ : null;
114
+
115
+ // Get current state machine information
116
+ const stateMachineInfo = await this.getStateMachineInfo(
117
+ context,
118
+ conversationContext.projectPath,
119
+ conversationContext.workflowName
120
+ );
121
+ const stateMachine = context.transitionEngine.getStateMachine(
122
+ conversationContext.projectPath,
123
+ conversationContext.workflowName
124
+ );
125
+
126
+ // Generate system prompt if requested
127
+ const systemPrompt = includeSystemPrompt
128
+ ? generateSystemPrompt(stateMachine)
129
+ : null;
130
+
131
+ // Build comprehensive response
132
+ const response: ResumeWorkflowResult = {
133
+ // Core workflow resumption info
134
+ workflow_status: {
135
+ conversation_id: conversationContext.conversationId,
136
+ current_phase: conversationContext.currentPhase,
137
+ project_path: conversationContext.projectPath,
138
+ git_branch: conversationContext.gitBranch,
139
+ state_machine: stateMachineInfo as YamlStateMachine,
140
+ },
141
+
142
+ // Plan file analysis
143
+ plan_status: {
144
+ exists: planInfo.exists,
145
+ path: conversationContext.planFilePath,
146
+ analysis: planAnalysis,
147
+ },
148
+
149
+ // System prompt (if requested)
150
+ system_prompt: systemPrompt,
151
+
152
+ // Next steps and recommendations
153
+ recommendations: this.generateRecommendations(
154
+ conversationContext,
155
+ planAnalysis,
156
+ context
157
+ ),
158
+
159
+ // Metadata
160
+ generated_at: new Date().toISOString(),
161
+ tool_version: '1.0.0',
162
+ };
163
+
164
+ this.logger.debug('resume_workflow response generated', {
165
+ conversationId: conversationContext.conversationId,
166
+ phase: conversationContext.currentPhase,
167
+ planExists: planInfo.exists,
168
+ includeSystemPrompt,
169
+ });
170
+
171
+ return response;
172
+ }
173
+
174
+ /**
175
+ * Analyze plan file content to extract key information
176
+ */
177
+ private analyzePlanFile(content: string): PlanAnalysis {
178
+ const analysis = {
179
+ active_tasks: [] as string[],
180
+ completed_tasks: [] as string[],
181
+ recent_decisions: [] as string[],
182
+ next_steps: [] as string[],
183
+ };
184
+
185
+ const lines = content.split('\n');
186
+ let inTaskSection = false;
187
+ let currentSection = '';
188
+
189
+ for (const line of lines) {
190
+ const trimmed = line.trim();
191
+
192
+ // Detect sections
193
+ if (trimmed.startsWith('##')) {
194
+ currentSection = trimmed.toLowerCase();
195
+ inTaskSection =
196
+ currentSection.includes('task') || currentSection.includes('todo');
197
+ }
198
+
199
+ // Extract tasks
200
+ if (inTaskSection) {
201
+ if (trimmed.startsWith('- [x]')) {
202
+ analysis.completed_tasks.push(trimmed.substring(5).trim());
203
+ } else if (trimmed.startsWith('- [ ]')) {
204
+ analysis.active_tasks.push(trimmed.substring(5).trim());
205
+ }
206
+ }
207
+
208
+ // Extract decisions (look for decision log sections)
209
+ if (currentSection.includes('decision') && trimmed.startsWith('- ')) {
210
+ analysis.recent_decisions.push(trimmed.substring(2).trim());
211
+ }
212
+ }
213
+
214
+ return {
215
+ sections: [currentSection],
216
+ tasks_completed: analysis.completed_tasks.length,
217
+ tasks_total:
218
+ analysis.active_tasks.length + analysis.completed_tasks.length,
219
+ key_decisions: analysis.recent_decisions,
220
+ recent_updates: analysis.next_steps,
221
+ active_tasks: analysis.active_tasks,
222
+ completed_tasks: analysis.completed_tasks,
223
+ };
224
+ }
225
+
226
+ /**
227
+ * Get state machine information
228
+ */
229
+ private async getStateMachineInfo(
230
+ context: ServerContext,
231
+ projectPath: string,
232
+ workflowName?: string
233
+ ): Promise<unknown> {
234
+ try {
235
+ // Get the actual state machine for this project
236
+ const stateMachine = context.transitionEngine.getStateMachine(
237
+ projectPath,
238
+ workflowName
239
+ );
240
+
241
+ return {
242
+ name: stateMachine.name,
243
+ description: stateMachine.description,
244
+ initial_state: stateMachine.initial_state,
245
+ phases: Object.keys(stateMachine.states),
246
+ phase_descriptions: Object.fromEntries(
247
+ Object.entries(stateMachine.states).map(([phase, definition]) => [
248
+ phase,
249
+ (definition as YamlState).description,
250
+ ])
251
+ ),
252
+ };
253
+ } catch (error) {
254
+ const err = error as Error;
255
+ this.logger.warn('Could not determine state machine info', {
256
+ error: err.message,
257
+ });
258
+ return {
259
+ name: 'unknown',
260
+ description: 'Could not load workflow',
261
+ initial_state: 'unknown',
262
+ phases: [],
263
+ phase_descriptions: {},
264
+ };
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Generate recommendations for next steps based on state machine transitions
270
+ */
271
+ private generateRecommendations(
272
+ conversationContext: ConversationContext,
273
+ planAnalysis: PlanAnalysis | null,
274
+ context: ServerContext
275
+ ): WorkflowRecommendations {
276
+ const recommendations = {
277
+ immediate_actions: [] as string[],
278
+ phase_guidance: '',
279
+ potential_issues: [] as string[],
280
+ };
281
+
282
+ try {
283
+ // Get the state machine for this project
284
+ const stateMachine = context.transitionEngine.getStateMachine(
285
+ conversationContext.projectPath,
286
+ conversationContext.workflowName
287
+ );
288
+ const currentPhase = conversationContext.currentPhase;
289
+ const phaseDefinition = stateMachine.states[currentPhase];
290
+
291
+ if (phaseDefinition) {
292
+ // Set phase guidance from state machine description
293
+ recommendations.phase_guidance = `Current phase: ${(phaseDefinition as YamlState).description}`;
294
+
295
+ // Generate transition-based recommendations
296
+ if (
297
+ (phaseDefinition as YamlState).transitions &&
298
+ (phaseDefinition as YamlState).transitions.length > 0
299
+ ) {
300
+ recommendations.immediate_actions.push(
301
+ 'From here, you can transition to:'
302
+ );
303
+
304
+ for (const transition of phaseDefinition.transitions) {
305
+ const targetPhase = stateMachine.states[transition.to];
306
+ const targetDescription = targetPhase
307
+ ? targetPhase.description
308
+ : transition.to;
309
+ recommendations.immediate_actions.push(
310
+ `• ${transition.to}: ${targetDescription}`
311
+ );
312
+ }
313
+
314
+ // Add instruction on how to transition
315
+ recommendations.immediate_actions.push(
316
+ 'Use proceed_to_phase() tool when ready to transition'
317
+ );
318
+ } else {
319
+ recommendations.immediate_actions.push(
320
+ 'Continue working in current phase'
321
+ );
322
+ }
323
+
324
+ // Add current phase specific guidance
325
+ recommendations.immediate_actions.push(
326
+ `Focus on: ${(phaseDefinition as YamlState).description}`
327
+ );
328
+ } else {
329
+ // Fallback if phase not found in state machine
330
+ recommendations.phase_guidance = `Current phase: ${currentPhase}`;
331
+ recommendations.immediate_actions.push(
332
+ 'Continue working in current phase'
333
+ );
334
+ }
335
+ } catch (error) {
336
+ const err = error as Error;
337
+ this.logger.warn('Could not generate state machine recommendations', {
338
+ error: err.message,
339
+ });
340
+ // Basic fallback
341
+ recommendations.phase_guidance = `Current phase: ${conversationContext.currentPhase}`;
342
+ recommendations.immediate_actions.push(
343
+ 'Continue working in current phase'
344
+ );
345
+ }
346
+
347
+ // Plan-based recommendations
348
+ if (planAnalysis) {
349
+ if (planAnalysis.active_tasks && planAnalysis.active_tasks.length > 0) {
350
+ recommendations.immediate_actions.push(
351
+ `Continue working on active tasks: ${planAnalysis.active_tasks.slice(0, 2).join(', ')}`
352
+ );
353
+ }
354
+
355
+ if (
356
+ (!planAnalysis.active_tasks ||
357
+ planAnalysis.active_tasks.length === 0) &&
358
+ planAnalysis.completed_tasks &&
359
+ planAnalysis.completed_tasks.length > 0
360
+ ) {
361
+ recommendations.potential_issues.push(
362
+ 'No active tasks found - may be ready to transition to next phase'
363
+ );
364
+ }
365
+ }
366
+
367
+ // Always recommend calling whats_next
368
+ if (
369
+ !recommendations.immediate_actions.some(action =>
370
+ action.includes('whats_next')
371
+ )
372
+ ) {
373
+ recommendations.immediate_actions.unshift(
374
+ 'Call whats_next() to get current phase-specific guidance'
375
+ );
376
+ }
377
+
378
+ return recommendations;
379
+ }
380
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Setup Project Docs Handler
3
+ *
4
+ * Creates project documentation artifacts (architecture.md, requirements.md, design.md)
5
+ * using configurable templates OR by linking existing files via symlinks.
6
+ * Supports different template formats for each document type and file path linking.
7
+ */
8
+
9
+ import { BaseToolHandler } from './base-tool-handler.js';
10
+ import { ProjectDocsManager } from '@codemcp/workflows-core';
11
+ import { TemplateOptions } from '@codemcp/workflows-core';
12
+ import { PathValidationUtils } from '@codemcp/workflows-core';
13
+ import { ServerContext } from '../types.js';
14
+
15
+ export interface SetupProjectDocsArgs {
16
+ architecture: string; // Template name OR file path
17
+ requirements: string; // Template name OR file path
18
+ design: string; // Template name OR file path
19
+ }
20
+
21
+ export interface SetupProjectDocsResult {
22
+ success: boolean;
23
+ created: string[];
24
+ linked: string[];
25
+ skipped: string[];
26
+ paths: {
27
+ architecture: string;
28
+ requirements: string;
29
+ design: string;
30
+ };
31
+ message: string;
32
+ }
33
+
34
+ export class SetupProjectDocsHandler extends BaseToolHandler<
35
+ SetupProjectDocsArgs,
36
+ SetupProjectDocsResult
37
+ > {
38
+ private projectDocsManager: ProjectDocsManager;
39
+
40
+ constructor() {
41
+ super();
42
+ this.projectDocsManager = new ProjectDocsManager();
43
+ }
44
+
45
+ protected async executeHandler(
46
+ args: SetupProjectDocsArgs,
47
+ context: ServerContext
48
+ ): Promise<SetupProjectDocsResult> {
49
+ const projectPath = context.projectPath || process.cwd();
50
+
51
+ this.logger.info(
52
+ 'Setting up project docs with enhanced file linking support',
53
+ { args, projectPath }
54
+ );
55
+
56
+ try {
57
+ // Get available templates for validation
58
+ const availableTemplates =
59
+ await this.projectDocsManager.templateManager.getAvailableTemplates();
60
+
61
+ // Validate and process each parameter
62
+ const processedArgs = await this.validateAndProcessArgs(
63
+ args,
64
+ availableTemplates,
65
+ projectPath
66
+ );
67
+
68
+ if (!processedArgs.success) {
69
+ return {
70
+ success: false,
71
+ created: [],
72
+ linked: [],
73
+ skipped: [],
74
+ paths: this.projectDocsManager.getDocumentPaths(projectPath),
75
+ message: processedArgs.error || 'Unknown error during validation',
76
+ };
77
+ }
78
+
79
+ // Create/link project documents
80
+ if (!processedArgs.templateOptions || !processedArgs.filePaths) {
81
+ throw new Error(
82
+ 'Invalid processed args: missing templateOptions or filePaths'
83
+ );
84
+ }
85
+
86
+ const result = await this.projectDocsManager.createOrLinkProjectDocs(
87
+ projectPath,
88
+ processedArgs.templateOptions,
89
+ processedArgs.filePaths
90
+ );
91
+
92
+ // Get document paths for response
93
+ const paths = this.projectDocsManager.getDocumentPaths(projectPath);
94
+
95
+ // Create success message
96
+ let message = 'Project documentation setup completed.';
97
+ if (result.created.length > 0) {
98
+ message += ` Created: ${result.created.join(', ')}.`;
99
+ }
100
+ if (result.linked.length > 0) {
101
+ message += ` Linked: ${result.linked.join(', ')}.`;
102
+ }
103
+ if (result.skipped.length > 0) {
104
+ message += ` Skipped existing: ${result.skipped.join(', ')}.`;
105
+ }
106
+
107
+ this.logger.info('Project docs setup completed', {
108
+ created: result.created,
109
+ linked: result.linked,
110
+ skipped: result.skipped,
111
+ paths,
112
+ });
113
+
114
+ return {
115
+ success: true,
116
+ created: result.created,
117
+ linked: result.linked,
118
+ skipped: result.skipped,
119
+ paths,
120
+ message,
121
+ };
122
+ } catch (error) {
123
+ this.logger.error('Failed to setup project docs', error as Error, {
124
+ args,
125
+ projectPath,
126
+ });
127
+
128
+ return {
129
+ success: false,
130
+ created: [],
131
+ linked: [],
132
+ skipped: [],
133
+ paths: this.projectDocsManager.getDocumentPaths(projectPath),
134
+ message: `Failed to setup project docs: ${error instanceof Error ? error.message : 'Unknown error'}`,
135
+ };
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Validate and process arguments to determine templates vs file paths
141
+ */
142
+ private async validateAndProcessArgs(
143
+ args: SetupProjectDocsArgs,
144
+ availableTemplates: {
145
+ architecture: string[];
146
+ requirements: string[];
147
+ design: string[];
148
+ },
149
+ projectPath: string
150
+ ): Promise<{
151
+ success: boolean;
152
+ error?: string;
153
+ templateOptions?: Partial<TemplateOptions>;
154
+ filePaths?: Partial<{
155
+ architecture: string;
156
+ requirements: string;
157
+ design: string;
158
+ }>;
159
+ }> {
160
+ const templateOptions: Partial<TemplateOptions> = {};
161
+ const filePaths: Partial<{
162
+ architecture: string;
163
+ requirements: string;
164
+ design: string;
165
+ }> = {};
166
+ const errors: string[] = [];
167
+
168
+ // Validate architecture parameter
169
+ const archValidation = await PathValidationUtils.validateParameter(
170
+ args.architecture,
171
+ availableTemplates.architecture,
172
+ projectPath
173
+ );
174
+
175
+ if (archValidation.isTemplate) {
176
+ templateOptions.architecture = args.architecture;
177
+ } else if (archValidation.isFilePath && archValidation.resolvedPath) {
178
+ filePaths.architecture = archValidation.resolvedPath;
179
+ } else {
180
+ errors.push(`Architecture: ${archValidation.error}`);
181
+ }
182
+
183
+ // Validate requirements parameter
184
+ const reqValidation = await PathValidationUtils.validateParameter(
185
+ args.requirements,
186
+ availableTemplates.requirements,
187
+ projectPath
188
+ );
189
+
190
+ if (reqValidation.isTemplate) {
191
+ templateOptions.requirements = args.requirements;
192
+ } else if (reqValidation.isFilePath && reqValidation.resolvedPath) {
193
+ filePaths.requirements = reqValidation.resolvedPath;
194
+ } else {
195
+ errors.push(`Requirements: ${reqValidation.error}`);
196
+ }
197
+
198
+ // Validate design parameter
199
+ const designValidation = await PathValidationUtils.validateParameter(
200
+ args.design,
201
+ availableTemplates.design,
202
+ projectPath
203
+ );
204
+
205
+ if (designValidation.isTemplate) {
206
+ templateOptions.design = args.design;
207
+ } else if (designValidation.isFilePath && designValidation.resolvedPath) {
208
+ filePaths.design = designValidation.resolvedPath;
209
+ } else {
210
+ errors.push(`Design: ${designValidation.error}`);
211
+ }
212
+
213
+ if (errors.length > 0) {
214
+ return {
215
+ success: false,
216
+ error: `Parameter validation failed:\n${errors.join('\n')}`,
217
+ };
218
+ }
219
+
220
+ return {
221
+ success: true,
222
+ templateOptions,
223
+ filePaths,
224
+ };
225
+ }
226
+ }