sdd-mcp-server 1.4.5 → 1.5.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.
package/mcp-server.js CHANGED
@@ -2,22 +2,22 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
- import fs from 'fs/promises';
6
- import path from 'path';
7
- import {
8
- analyzeProject,
9
- generateProductDocument,
10
- generateTechDocument,
11
- generateStructureDocument
12
- } from './documentGenerator.js';
5
+ import fs from "fs/promises";
6
+ import path from "path";
7
+ import {
8
+ analyzeProject,
9
+ generateProductDocument,
10
+ generateTechDocument,
11
+ generateStructureDocument,
12
+ } from "./documentGenerator.js";
13
13
 
14
14
  // Best-effort dynamic loader for spec generators (requirements/design/tasks)
15
15
  async function loadSpecGenerator() {
16
16
  const tried = [];
17
17
  const attempts = [
18
- './specGenerator.js', // root-level JS (dev/runtime)
19
- './dist/utils/specGenerator.js', // compiled TS output
20
- './utils/specGenerator.js' // TS runtime (when transpiled on-the-fly)
18
+ "./specGenerator.js", // root-level JS (dev/runtime)
19
+ "./dist/utils/specGenerator.js", // compiled TS output
20
+ "./utils/specGenerator.js", // TS runtime (when transpiled on-the-fly)
21
21
  ];
22
22
  for (const p of attempts) {
23
23
  try {
@@ -28,46 +28,52 @@ async function loadSpecGenerator() {
28
28
  tried.push(`${p}: ${(e && e.message) || e}`);
29
29
  }
30
30
  }
31
- throw new Error(`Unable to load specGenerator from known paths. Tried: \n- ${tried.join('\n- ')}`);
31
+ throw new Error(
32
+ `Unable to load specGenerator from known paths. Tried: \n- ${tried.join("\n- ")}`,
33
+ );
32
34
  }
33
35
 
34
36
  // Resolve version dynamically from package.json when possible
35
37
  async function resolveVersion() {
36
38
  try {
37
- const pkgUrl = new URL('./package.json', import.meta.url);
38
- const pkgText = await fs.readFile(pkgUrl, 'utf8');
39
+ const pkgUrl = new URL("./package.json", import.meta.url);
40
+ const pkgText = await fs.readFile(pkgUrl, "utf8");
39
41
  const pkg = JSON.parse(pkgText);
40
- return pkg.version || '0.0.0';
42
+ return pkg.version || "0.0.0";
41
43
  } catch {
42
- return '0.0.0';
44
+ return "0.0.0";
43
45
  }
44
46
  }
45
47
 
46
- const server = new McpServer({
47
- name: 'sdd-mcp-server',
48
- version: await resolveVersion()
49
- }, {
50
- instructions: 'Use this server for spec-driven development workflows'
51
- });
48
+ const server = new McpServer(
49
+ {
50
+ name: "sdd-mcp-server",
51
+ version: await resolveVersion(),
52
+ },
53
+ {
54
+ instructions: "Use this server for spec-driven development workflows",
55
+ },
56
+ );
52
57
 
53
58
  // Helper functions for file operations
54
59
  async function createKiroDirectory(projectPath) {
55
- const kiroPath = path.join(projectPath, '.kiro');
56
- const specsPath = path.join(kiroPath, 'specs');
57
- const steeringPath = path.join(kiroPath, 'steering');
58
-
60
+ const kiroPath = path.join(projectPath, ".kiro");
61
+ const specsPath = path.join(kiroPath, "specs");
62
+ const steeringPath = path.join(kiroPath, "steering");
63
+
59
64
  await fs.mkdir(kiroPath, { recursive: true });
60
65
  await fs.mkdir(specsPath, { recursive: true });
61
66
  await fs.mkdir(steeringPath, { recursive: true });
62
-
67
+
63
68
  return { kiroPath, specsPath, steeringPath };
64
69
  }
65
70
 
66
71
  async function generateFeatureName(description) {
67
72
  // Simple feature name generation from description
68
- return description.toLowerCase()
69
- .replace(/[^a-z0-9\s]/g, '')
70
- .replace(/\s+/g, '-')
73
+ return description
74
+ .toLowerCase()
75
+ .replace(/[^a-z0-9\s]/g, "")
76
+ .replace(/\s+/g, "-")
71
77
  .substring(0, 50);
72
78
  }
73
79
 
@@ -75,277 +81,637 @@ async function getCurrentTimestamp() {
75
81
  return new Date().toISOString();
76
82
  }
77
83
 
84
+ // Requirements Clarification helpers
85
+ function analyzeDescriptionQuality(description) {
86
+ const analysis = {
87
+ hasWhy:
88
+ /\b(problem|solve[sd]?|challenge|pain\s+point|issue|why|because|enables?|value\s+proposition|benefit|justification|goal|objective|purpose)\b/i.test(
89
+ description,
90
+ ),
91
+ hasWho:
92
+ /\b(user[s]?|customer[s]?|target\s+(audience|users?|customers?)|persona[s]?|stakeholder[s]?|(developer|designer|admin|manager)[s]?|for\s+(teams?|companies|individuals))\b/i.test(
93
+ description,
94
+ ),
95
+ hasWhat:
96
+ /\b(feature[s]?|functionality|capabilit(y|ies)|provides?|include[s]?|support[s]?|allow[s]?|enable[s]?|MVP|scope)\b/i.test(
97
+ description,
98
+ ),
99
+ hasSuccessCriteria:
100
+ /\b(metric[s]?|KPI[s]?|measure[sd]?|success\s+(criteria|metric)|\d+%|performance\s+target|goal[s]?\s+.*\d+)\b/i.test(
101
+ description,
102
+ ),
103
+ ambiguousTerms: [],
104
+ };
105
+
106
+ // Detect ambiguous terms
107
+ const ambiguityChecks = [
108
+ {
109
+ pattern: /\bfast\b/gi,
110
+ suggestion: "Can you specify a target response time?",
111
+ },
112
+ {
113
+ pattern: /\bscalable\b/gi,
114
+ suggestion: "What scale do you need to support?",
115
+ },
116
+ {
117
+ pattern: /\buser[- ]friendly\b/gi,
118
+ suggestion: "What makes it user-friendly?",
119
+ },
120
+ {
121
+ pattern: /\beasy\s+to\s+use\b/gi,
122
+ suggestion: "What does easy mean for your users?",
123
+ },
124
+ {
125
+ pattern: /\bhigh\s+quality\b/gi,
126
+ suggestion: "How do you define quality?",
127
+ },
128
+ {
129
+ pattern: /\breliable\b/gi,
130
+ suggestion: "What reliability level do you need?",
131
+ },
132
+ {
133
+ pattern: /\bsecure\b/gi,
134
+ suggestion: "What security requirements apply?",
135
+ },
136
+ {
137
+ pattern: /\bmodern\b/gi,
138
+ suggestion: "What technologies are you considering?",
139
+ },
140
+ ];
141
+
142
+ for (const { pattern, suggestion } of ambiguityChecks) {
143
+ const matches = description.match(pattern);
144
+ if (matches) {
145
+ analysis.ambiguousTerms.push({ term: matches[0], suggestion });
146
+ }
147
+ }
148
+
149
+ // Calculate quality score
150
+ let score = 0;
151
+ if (analysis.hasWhy) score += 30;
152
+ if (analysis.hasWho) score += 20;
153
+ if (analysis.hasWhat) score += 20;
154
+ if (analysis.hasSuccessCriteria) score += 15;
155
+ if (description.length > 100) score += 5;
156
+ if (description.length > 300) score += 5;
157
+ if (description.length > 500) score += 5;
158
+ score -= Math.min(15, analysis.ambiguousTerms.length * 5);
159
+
160
+ analysis.qualityScore = Math.max(0, Math.min(100, score));
161
+ analysis.needsClarification = score < 70;
162
+
163
+ return analysis;
164
+ }
165
+
166
+ function generateClarificationQuestions(analysis) {
167
+ const questions = [];
168
+
169
+ if (!analysis.hasWhy) {
170
+ questions.push({
171
+ id: "why_problem",
172
+ category: "why",
173
+ question:
174
+ "What business problem does this project solve? Why is it needed?",
175
+ examples: [
176
+ "Our customer support team spends 5 hours/day on repetitive inquiries",
177
+ "Users are abandoning checkout because the process takes too long",
178
+ ],
179
+ required: true,
180
+ });
181
+ questions.push({
182
+ id: "why_value",
183
+ category: "why",
184
+ question:
185
+ "What value does this project provide to users or the business?",
186
+ examples: [
187
+ "Reduce support ticket volume by 40%",
188
+ "Increase conversion rate by improving checkout speed",
189
+ ],
190
+ required: true,
191
+ });
192
+ }
193
+
194
+ if (!analysis.hasWho) {
195
+ questions.push({
196
+ id: "who_users",
197
+ category: "who",
198
+ question: "Who are the primary users of this project?",
199
+ examples: [
200
+ "Customer support agents using ticketing systems",
201
+ "E-commerce shoppers on mobile devices",
202
+ "Backend developers integrating APIs",
203
+ ],
204
+ required: true,
205
+ });
206
+ }
207
+
208
+ if (!analysis.hasWhat) {
209
+ questions.push({
210
+ id: "what_features",
211
+ category: "what",
212
+ question: "What are the 3-5 core features for the MVP?",
213
+ examples: [
214
+ "Auto-response system, ticket categorization, analytics dashboard",
215
+ "Product search, cart management, payment integration",
216
+ ],
217
+ required: true,
218
+ });
219
+ questions.push({
220
+ id: "what_scope",
221
+ category: "what",
222
+ question: "What is explicitly OUT OF SCOPE for this project?",
223
+ examples: ["Admin panel (future phase)", "Mobile app (web only for MVP)"],
224
+ required: false,
225
+ });
226
+ }
227
+
228
+ if (!analysis.hasSuccessCriteria) {
229
+ questions.push({
230
+ id: "success_metrics",
231
+ category: "success",
232
+ question: "How will you measure if this project is successful?",
233
+ examples: [
234
+ "Support ticket volume reduced by 30% within 3 months",
235
+ "Page load time under 2 seconds, conversion rate > 3%",
236
+ ],
237
+ required: true,
238
+ });
239
+ }
240
+
241
+ // Add questions for ambiguous terms (max 2)
242
+ for (const ambiguous of analysis.ambiguousTerms.slice(0, 2)) {
243
+ questions.push({
244
+ id: `ambiguous_${ambiguous.term.toLowerCase().replace(/\s+/g, "_")}`,
245
+ category: "what",
246
+ question: `You mentioned "${ambiguous.term}". ${ambiguous.suggestion}`,
247
+ required: false,
248
+ });
249
+ }
250
+
251
+ return questions;
252
+ }
253
+
254
+ function formatQuestionsForUser(questions) {
255
+ let output = "## Requirements Clarification Needed\n\n";
256
+ output +=
257
+ "Your project description needs more detail to ensure we build the right solution.\n\n";
258
+ output += `**Quality Score**: ${Math.round(questions.analysis?.qualityScore || 0)}/100 (need 70+ to proceed)\n\n`;
259
+ output += "### Please answer these questions:\n\n";
260
+
261
+ let questionNum = 1;
262
+ for (const q of questions) {
263
+ output += `**${questionNum}. ${q.question}**${q.required ? " *(required)*" : ""}\n`;
264
+ if (q.examples && q.examples.length > 0) {
265
+ output += ` Examples:\n`;
266
+ for (const ex of q.examples) {
267
+ output += ` - ${ex}\n`;
268
+ }
269
+ }
270
+ output += ` Answer ID: \`${q.id}\`\n\n`;
271
+ questionNum++;
272
+ }
273
+
274
+ output += "\n### How to Provide Answers\n\n";
275
+ output +=
276
+ "Call sdd-init again with the `clarificationAnswers` parameter:\n\n";
277
+ output += "```json\n{\n";
278
+ output += ' "projectName": "your-project-name",\n';
279
+ output += ' "description": "your original description",\n';
280
+ output += ' "clarificationAnswers": {\n';
281
+ for (let i = 0; i < questions.length; i++) {
282
+ const q = questions[i];
283
+ output += ` "${q.id}": "your answer here"${i < questions.length - 1 ? "," : ""}\n`;
284
+ }
285
+ output += " }\n}\n```\n";
286
+
287
+ return output;
288
+ }
289
+
78
290
  // Register all SDD tools matching README and kiro command templates
79
291
 
80
- // 1. sdd-init - Initialize new SDD project
81
- server.registerTool("sdd-init", {
82
- title: "Initialize SDD Project",
83
- description: "Initialize a new SDD project",
84
- inputSchema: {
85
- projectName: z.string().describe('The name of the project to initialize'),
86
- description: z.string().optional().describe('Optional project description')
292
+ // 1. sdd-init - Initialize new SDD project with interactive clarification
293
+ server.registerTool(
294
+ "sdd-init",
295
+ {
296
+ title: "Initialize SDD Project",
297
+ description:
298
+ "Initialize a new SDD project with interactive requirements clarification",
299
+ inputSchema: {
300
+ projectName: z.string().describe("The name of the project to initialize"),
301
+ description: z.string().optional().describe("Project description"),
302
+ clarificationAnswers: z
303
+ .record(z.string())
304
+ .optional()
305
+ .describe("Answers to clarification questions (second pass)"),
306
+ },
87
307
  },
88
- }, async ({ projectName, description = '' }) => {
89
- try {
90
- const currentPath = process.cwd();
91
-
92
- // Create .kiro directory structure in current directory (not in a subdirectory)
93
- const { specsPath, steeringPath } = await createKiroDirectory(currentPath);
94
-
95
- // Generate feature name from description
96
- const featureName = await generateFeatureName(description || projectName);
97
- const featurePath = path.join(specsPath, featureName);
98
- await fs.mkdir(featurePath, { recursive: true });
99
-
100
- // Create spec.json
101
- const specJson = {
102
- "feature_name": featureName,
103
- "created_at": await getCurrentTimestamp(),
104
- "updated_at": await getCurrentTimestamp(),
105
- "language": "en",
106
- "phase": "initialized",
107
- "approvals": {
108
- "requirements": {
109
- "generated": false,
110
- "approved": false
111
- },
112
- "design": {
113
- "generated": false,
114
- "approved": false
308
+ async ({ projectName, description = "", clarificationAnswers }) => {
309
+ try {
310
+ const currentPath = process.cwd();
311
+
312
+ // FIRST PASS: Analyze description quality and generate clarification questions if needed
313
+ if (!clarificationAnswers) {
314
+ const analysis = analyzeDescriptionQuality(description);
315
+
316
+ // If description is vague or incomplete, BLOCK and ask for clarification
317
+ if (analysis.needsClarification) {
318
+ const questions = generateClarificationQuestions(analysis);
319
+ questions.analysis = analysis; // Attach analysis for formatting
320
+
321
+ return {
322
+ content: [
323
+ {
324
+ type: "text",
325
+ text: formatQuestionsForUser(questions),
326
+ },
327
+ ],
328
+ };
329
+ }
330
+ }
331
+
332
+ // SECOND PASS: Validate answers if provided
333
+ if (clarificationAnswers) {
334
+ const analysis = analyzeDescriptionQuality(description);
335
+ const questions = generateClarificationQuestions(analysis);
336
+
337
+ // Validate required questions are answered
338
+ const missingRequired = questions
339
+ .filter((q) => q.required && !clarificationAnswers[q.id])
340
+ .map((q) => q.question);
341
+
342
+ if (missingRequired.length > 0) {
343
+ return {
344
+ content: [
345
+ {
346
+ type: "text",
347
+ text: `## Missing Required Answers\n\nThe following required questions were not answered:\n\n${missingRequired.map((q, i) => `${i + 1}. ${q}`).join("\n")}\n\nPlease provide answers for all required questions.`,
348
+ },
349
+ ],
350
+ };
351
+ }
352
+
353
+ // Build enriched description from answers
354
+ const whyAnswers = questions
355
+ .filter((q) => q.category === "why")
356
+ .map((q) => clarificationAnswers[q.id])
357
+ .filter((a) => a)
358
+ .join(" ");
359
+
360
+ const whoAnswers = questions
361
+ .filter((q) => q.category === "who")
362
+ .map((q) => clarificationAnswers[q.id])
363
+ .filter((a) => a)
364
+ .join(" ");
365
+
366
+ const whatAnswers = questions
367
+ .filter((q) => q.category === "what")
368
+ .map((q) => clarificationAnswers[q.id])
369
+ .filter((a) => a)
370
+ .join(" ");
371
+
372
+ const successAnswers = questions
373
+ .filter((q) => q.category === "success")
374
+ .map((q) => clarificationAnswers[q.id])
375
+ .filter((a) => a)
376
+ .join(" ");
377
+
378
+ // Synthesize enriched description
379
+ const enrichedParts = [];
380
+ if (description)
381
+ enrichedParts.push(`## Original Description\n${description}`);
382
+ if (whyAnswers)
383
+ enrichedParts.push(`## Business Justification (Why)\n${whyAnswers}`);
384
+ if (whoAnswers)
385
+ enrichedParts.push(`## Target Users (Who)\n${whoAnswers}`);
386
+ if (whatAnswers)
387
+ enrichedParts.push(`## Core Features (What)\n${whatAnswers}`);
388
+ if (successAnswers)
389
+ enrichedParts.push(`## Success Criteria\n${successAnswers}`);
390
+
391
+ description = enrichedParts.join("\n\n");
392
+ }
393
+
394
+ // Proceed with spec creation (either quality is good or answers were provided)
395
+ // Create .kiro directory structure in current directory (not in a subdirectory)
396
+ const { specsPath, steeringPath } =
397
+ await createKiroDirectory(currentPath);
398
+
399
+ // Generate feature name from description
400
+ const featureName = await generateFeatureName(description || projectName);
401
+ const featurePath = path.join(specsPath, featureName);
402
+ await fs.mkdir(featurePath, { recursive: true });
403
+
404
+ // Create spec.json
405
+ const specJson = {
406
+ feature_name: featureName,
407
+ created_at: await getCurrentTimestamp(),
408
+ updated_at: await getCurrentTimestamp(),
409
+ language: "en",
410
+ phase: "initialized",
411
+ approvals: {
412
+ requirements: {
413
+ generated: false,
414
+ approved: false,
415
+ },
416
+ design: {
417
+ generated: false,
418
+ approved: false,
419
+ },
420
+ tasks: {
421
+ generated: false,
422
+ approved: false,
423
+ },
115
424
  },
116
- "tasks": {
117
- "generated": false,
118
- "approved": false
425
+ ready_for_implementation: false,
426
+ };
427
+
428
+ await fs.writeFile(
429
+ path.join(featurePath, "spec.json"),
430
+ JSON.stringify(specJson, null, 2),
431
+ );
432
+
433
+ // Create requirements.md template
434
+ const requirementsTemplate = `# Requirements Document\n\n## Project Description (Input)\n${description}\n\n## Requirements\n<!-- Will be generated in /kiro:spec-requirements phase -->`;
435
+ await fs.writeFile(
436
+ path.join(featurePath, "requirements.md"),
437
+ requirementsTemplate,
438
+ );
439
+
440
+ // Ensure AGENTS.md exists in steering directory based on CLAUDE.md (static exception)
441
+ const agentsPath = path.join(steeringPath, "AGENTS.md");
442
+ const claudePath = path.join(currentPath, "CLAUDE.md");
443
+ const agentsExists = await fs
444
+ .access(agentsPath)
445
+ .then(() => true)
446
+ .catch(() => false);
447
+ if (!agentsExists) {
448
+ let agentsContent = "";
449
+ const claudeExists = await fs
450
+ .access(claudePath)
451
+ .then(() => true)
452
+ .catch(() => false);
453
+ if (claudeExists) {
454
+ const claude = await fs.readFile(claudePath, "utf8");
455
+ agentsContent = claude
456
+ .replace(
457
+ /# Claude Code Spec-Driven Development/g,
458
+ "# AI Agent Spec-Driven Development",
459
+ )
460
+ .replace(/Claude Code/g, "AI Agent")
461
+ .replace(/claude code/g, "ai agent")
462
+ .replace(/Claude/g, "AI Agent")
463
+ .replace(/claude/g, "ai agent");
464
+ } else {
465
+ agentsContent =
466
+ "# AI Agent Spec-Driven Development\n\nKiro-style Spec Driven Development implementation for AI agents across different CLIs and IDEs.";
119
467
  }
120
- },
121
- "ready_for_implementation": false
122
- };
123
-
124
- await fs.writeFile(path.join(featurePath, 'spec.json'), JSON.stringify(specJson, null, 2));
125
-
126
- // Create requirements.md template
127
- const requirementsTemplate = `# Requirements Document\n\n## Project Description (Input)\n${description}\n\n## Requirements\n<!-- Will be generated in /kiro:spec-requirements phase -->`;
128
- await fs.writeFile(path.join(featurePath, 'requirements.md'), requirementsTemplate);
129
-
130
- // Ensure AGENTS.md exists in steering directory based on CLAUDE.md (static exception)
131
- const agentsPath = path.join(steeringPath, 'AGENTS.md');
132
- const claudePath = path.join(currentPath, 'CLAUDE.md');
133
- const agentsExists = await fs.access(agentsPath).then(() => true).catch(() => false);
134
- if (!agentsExists) {
135
- let agentsContent = '';
136
- const claudeExists = await fs.access(claudePath).then(() => true).catch(() => false);
137
- if (claudeExists) {
138
- const claude = await fs.readFile(claudePath, 'utf8');
139
- agentsContent = claude
140
- .replace(/# Claude Code Spec-Driven Development/g, '# AI Agent Spec-Driven Development')
141
- .replace(/Claude Code/g, 'AI Agent')
142
- .replace(/claude code/g, 'ai agent')
143
- .replace(/Claude/g, 'AI Agent')
144
- .replace(/claude/g, 'ai agent');
145
- } else {
146
- agentsContent = '# AI Agent Spec-Driven Development\n\nKiro-style Spec Driven Development implementation for AI agents across different CLIs and IDEs.';
468
+ await fs.writeFile(agentsPath, agentsContent);
147
469
  }
148
- await fs.writeFile(agentsPath, agentsContent);
149
- }
150
-
151
- return {
152
- content: [{
153
- type: 'text',
154
- text: `## Spec Initialization Complete\n\n**Generated Feature Name**: ${featureName}\n**Project Name**: ${projectName}\n**Project Description**: ${description}\n\n**Created Files**:\n- \`.kiro/specs/${featureName}/spec.json\` - Metadata and approval tracking\n- \`.kiro/specs/${featureName}/requirements.md\` - Requirements template\n\n**Next Step**: Use \`sdd-requirements ${featureName}\` to generate comprehensive requirements\n\nThe spec has been initialized following stage-by-stage development principles.`
155
- }]
156
- };
157
- } catch (error) {
158
- return {
159
- content: [{
160
- type: 'text',
161
- text: `Error initializing SDD project: ${error.message}`
162
- }]
163
- };
164
- }
165
- });
166
470
 
167
- // 2. sdd-requirements - Generate requirements doc
168
- server.registerTool("sdd-requirements", {
169
- title: "Generate Requirements Document",
170
- description: "Generate requirements doc",
171
- inputSchema: {
172
- featureName: z.string().describe('Feature name from spec initialization')
173
- },
174
- }, async ({ featureName }) => {
175
- try {
176
- const currentPath = process.cwd();
177
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
178
-
179
- // Check if spec exists
180
- const specPath = path.join(featurePath, 'spec.json');
181
- const specExists = await fs.access(specPath).then(() => true).catch(() => false);
182
- if (!specExists) {
471
+ const clarificationNote = clarificationAnswers
472
+ ? "\n\n✅ **Requirements Clarification**: Your answers have been incorporated into an enriched project description."
473
+ : "";
474
+
183
475
  return {
184
- content: [{
185
- type: 'text',
186
- text: `Error: Spec not found for feature "${featureName}". Use sdd-init first.`
187
- }]
476
+ content: [
477
+ {
478
+ type: "text",
479
+ text: `## Spec Initialization Complete\n\n**Generated Feature Name**: ${featureName}\n**Project Name**: ${projectName}\n**Project Description**: ${description}${clarificationNote}\n\n**Created Files**:\n- \`.kiro/specs/${featureName}/spec.json\` - Metadata and approval tracking\n- \`.kiro/specs/${featureName}/requirements.md\` - Requirements template with enriched description\n\n**Next Step**: Use \`sdd-requirements ${featureName}\` to generate comprehensive requirements\n\nThe spec has been initialized following stage-by-stage development principles.`,
480
+ },
481
+ ],
482
+ };
483
+ } catch (error) {
484
+ return {
485
+ content: [
486
+ {
487
+ type: "text",
488
+ text: `Error initializing SDD project: ${error.message}`,
489
+ },
490
+ ],
188
491
  };
189
492
  }
190
-
191
- // Read existing spec
192
- const specContent = await fs.readFile(specPath, 'utf8');
193
- const spec = JSON.parse(specContent);
194
-
195
- // Generate requirements using specGenerator with fallback
196
- let requirementsContent;
197
- try {
198
- const { mod } = await loadSpecGenerator();
199
- requirementsContent = await mod.generateRequirementsDocument(currentPath, featureName);
200
- } catch (e) {
201
- requirementsContent = `# Requirements Document\n\n<!-- Warning: Analysis-backed generation failed. Using fallback template. -->\n<!-- Error: ${e && e.message ? e.message : String(e)} -->\n\n## Project Context\n**Feature**: ${spec.feature_name}\n**Description**: ${spec.description || 'Feature to be implemented'}\n`;
202
- }
203
-
204
- await fs.writeFile(path.join(featurePath, 'requirements.md'), requirementsContent);
205
-
206
- // Update spec.json
207
- spec.phase = "requirements-generated";
208
- spec.approvals.requirements.generated = true;
209
- spec.updated_at = await getCurrentTimestamp();
210
-
211
- await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
212
-
213
- return {
214
- content: [{
215
- type: 'text',
216
- text: `## Requirements Generated\n\nRequirements document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/requirements.md\n**Status**: Requirements phase completed\n\n**Next Step**: Review the requirements, then use \`sdd-design\` to proceed to design phase`
217
- }]
218
- };
219
- } catch (error) {
220
- return {
221
- content: [{
222
- type: 'text',
223
- text: `Error generating requirements: ${error.message}`
224
- }]
225
- };
226
- }
227
- });
493
+ },
494
+ );
228
495
 
229
- // 3. sdd-design - Create design specifications
230
- server.registerTool("sdd-design", {
231
- title: "Create Design Specifications",
232
- description: "Create design specifications",
233
- inputSchema: {
234
- featureName: z.string().describe('Feature name from spec initialization')
496
+ // 2. sdd-requirements - Generate requirements doc
497
+ server.registerTool(
498
+ "sdd-requirements",
499
+ {
500
+ title: "Generate Requirements Document",
501
+ description: "Generate requirements doc",
502
+ inputSchema: {
503
+ featureName: z.string().describe("Feature name from spec initialization"),
504
+ },
235
505
  },
236
- }, async ({ featureName }) => {
237
- try {
238
- const currentPath = process.cwd();
239
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
240
- const specPath = path.join(featurePath, 'spec.json');
241
-
242
- // Read and validate spec
243
- const specContent = await fs.readFile(specPath, 'utf8');
244
- const spec = JSON.parse(specContent);
245
-
246
- if (!spec.approvals.requirements.generated) {
506
+ async ({ featureName }) => {
507
+ try {
508
+ const currentPath = process.cwd();
509
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
510
+
511
+ // Check if spec exists
512
+ const specPath = path.join(featurePath, "spec.json");
513
+ const specExists = await fs
514
+ .access(specPath)
515
+ .then(() => true)
516
+ .catch(() => false);
517
+ if (!specExists) {
518
+ return {
519
+ content: [
520
+ {
521
+ type: "text",
522
+ text: `Error: Spec not found for feature "${featureName}". Use sdd-init first.`,
523
+ },
524
+ ],
525
+ };
526
+ }
527
+
528
+ // Read existing spec
529
+ const specContent = await fs.readFile(specPath, "utf8");
530
+ const spec = JSON.parse(specContent);
531
+
532
+ // Generate requirements using specGenerator with fallback
533
+ let requirementsContent;
534
+ try {
535
+ const { mod } = await loadSpecGenerator();
536
+ requirementsContent = await mod.generateRequirementsDocument(
537
+ currentPath,
538
+ featureName,
539
+ );
540
+ } catch (e) {
541
+ requirementsContent = `# Requirements Document\n\n<!-- Warning: Analysis-backed generation failed. Using fallback template. -->\n<!-- Error: ${e && e.message ? e.message : String(e)} -->\n\n## Project Context\n**Feature**: ${spec.feature_name}\n**Description**: ${spec.description || "Feature to be implemented"}\n`;
542
+ }
543
+
544
+ await fs.writeFile(
545
+ path.join(featurePath, "requirements.md"),
546
+ requirementsContent,
547
+ );
548
+
549
+ // Update spec.json
550
+ spec.phase = "requirements-generated";
551
+ spec.approvals.requirements.generated = true;
552
+ spec.updated_at = await getCurrentTimestamp();
553
+
554
+ await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
555
+
247
556
  return {
248
- content: [{
249
- type: 'text',
250
- text: `Error: Requirements must be generated before design. Run \`sdd-requirements ${featureName}\` first.`
251
- }]
557
+ content: [
558
+ {
559
+ type: "text",
560
+ text: `## Requirements Generated\n\nRequirements document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/requirements.md\n**Status**: Requirements phase completed\n\n**Next Step**: Review the requirements, then use \`sdd-design\` to proceed to design phase`,
561
+ },
562
+ ],
252
563
  };
253
- }
254
-
255
- // Read requirements for context
256
- const requirementsPath = path.join(featurePath, 'requirements.md');
257
- let requirementsContext = '';
258
- try {
259
- requirementsContext = await fs.readFile(requirementsPath, 'utf8');
260
564
  } catch (error) {
261
- requirementsContext = 'Requirements document not available';
565
+ return {
566
+ content: [
567
+ {
568
+ type: "text",
569
+ text: `Error generating requirements: ${error.message}`,
570
+ },
571
+ ],
572
+ };
262
573
  }
574
+ },
575
+ );
263
576
 
264
- // Generate design using specGenerator with fallback
265
- let designContent;
577
+ // 3. sdd-design - Create design specifications
578
+ server.registerTool(
579
+ "sdd-design",
580
+ {
581
+ title: "Create Design Specifications",
582
+ description: "Create design specifications",
583
+ inputSchema: {
584
+ featureName: z.string().describe("Feature name from spec initialization"),
585
+ },
586
+ },
587
+ async ({ featureName }) => {
266
588
  try {
267
- const { mod } = await loadSpecGenerator();
268
- designContent = await mod.generateDesignDocument(currentPath, featureName);
269
- } catch (e) {
270
- designContent = `# Technical Design Document\n\n<!-- Warning: Analysis-backed generation failed. Using fallback template. -->\n<!-- Error: ${e && e.message ? e.message : String(e)} -->\n\n## Project Context\n**Feature**: ${spec.feature_name}\n**Phase**: ${spec.phase}`;
271
- }
272
-
273
- await fs.writeFile(path.join(featurePath, 'design.md'), designContent);
274
-
275
- // Update spec.json
276
- spec.phase = "design-generated";
277
- spec.approvals.design.generated = true;
278
- spec.updated_at = await getCurrentTimestamp();
279
-
280
- await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
281
-
282
- return {
283
- content: [{
284
- type: 'text',
285
- text: `## Design Generated\n\nTechnical design document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/design.md\n**Status**: Design phase completed\n\n**Next Step**: Review the design document, then use \`sdd-tasks\` to proceed to task planning phase`
286
- }]
287
- };
288
- } catch (error) {
289
- return {
290
- content: [{
291
- type: 'text',
292
- text: `Error generating design: ${error.message}`
293
- }]
294
- };
295
- }
296
- });
589
+ const currentPath = process.cwd();
590
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
591
+ const specPath = path.join(featurePath, "spec.json");
592
+
593
+ // Read and validate spec
594
+ const specContent = await fs.readFile(specPath, "utf8");
595
+ const spec = JSON.parse(specContent);
596
+
597
+ if (!spec.approvals.requirements.generated) {
598
+ return {
599
+ content: [
600
+ {
601
+ type: "text",
602
+ text: `Error: Requirements must be generated before design. Run \`sdd-requirements ${featureName}\` first.`,
603
+ },
604
+ ],
605
+ };
606
+ }
607
+
608
+ // Read requirements for context
609
+ const requirementsPath = path.join(featurePath, "requirements.md");
610
+ let requirementsContext = "";
611
+ try {
612
+ requirementsContext = await fs.readFile(requirementsPath, "utf8");
613
+ } catch (error) {
614
+ requirementsContext = "Requirements document not available";
615
+ }
616
+
617
+ // Generate design using specGenerator with fallback
618
+ let designContent;
619
+ try {
620
+ const { mod } = await loadSpecGenerator();
621
+ designContent = await mod.generateDesignDocument(
622
+ currentPath,
623
+ featureName,
624
+ );
625
+ } catch (e) {
626
+ designContent = `# Technical Design Document\n\n<!-- Warning: Analysis-backed generation failed. Using fallback template. -->\n<!-- Error: ${e && e.message ? e.message : String(e)} -->\n\n## Project Context\n**Feature**: ${spec.feature_name}\n**Phase**: ${spec.phase}`;
627
+ }
628
+
629
+ await fs.writeFile(path.join(featurePath, "design.md"), designContent);
630
+
631
+ // Update spec.json
632
+ spec.phase = "design-generated";
633
+ spec.approvals.design.generated = true;
634
+ spec.updated_at = await getCurrentTimestamp();
635
+
636
+ await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
297
637
 
298
- // 4. sdd-tasks - Generate task breakdown
299
- server.registerTool("sdd-tasks", {
300
- title: "Generate Task Breakdown",
301
- description: "Generate task breakdown",
302
- inputSchema: {
303
- featureName: z.string().describe('Feature name from spec initialization')
304
- },
305
- }, async ({ featureName }) => {
306
- try {
307
- const currentPath = process.cwd();
308
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
309
- const specPath = path.join(featurePath, 'spec.json');
310
-
311
- // Read and validate spec
312
- const specContent = await fs.readFile(specPath, 'utf8');
313
- const spec = JSON.parse(specContent);
314
-
315
- if (!spec.approvals.design.generated) {
316
638
  return {
317
- content: [{
318
- type: 'text',
319
- text: `Error: Design must be generated before tasks. Run \`sdd-design ${featureName}\` first.`
320
- }]
639
+ content: [
640
+ {
641
+ type: "text",
642
+ text: `## Design Generated\n\nTechnical design document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/design.md\n**Status**: Design phase completed\n\n**Next Step**: Review the design document, then use \`sdd-tasks\` to proceed to task planning phase`,
643
+ },
644
+ ],
321
645
  };
322
- }
323
-
324
- // Read design and requirements for context
325
- const designPath = path.join(featurePath, 'design.md');
326
- const requirementsPath = path.join(featurePath, 'requirements.md');
327
- let designContext = '';
328
- let requirementsContext = '';
329
-
330
- try {
331
- designContext = await fs.readFile(designPath, 'utf8');
332
646
  } catch (error) {
333
- designContext = 'Design document not available';
647
+ return {
648
+ content: [
649
+ {
650
+ type: "text",
651
+ text: `Error generating design: ${error.message}`,
652
+ },
653
+ ],
654
+ };
334
655
  }
656
+ },
657
+ );
335
658
 
659
+ // 4. sdd-tasks - Generate task breakdown
660
+ server.registerTool(
661
+ "sdd-tasks",
662
+ {
663
+ title: "Generate Task Breakdown",
664
+ description: "Generate task breakdown",
665
+ inputSchema: {
666
+ featureName: z.string().describe("Feature name from spec initialization"),
667
+ },
668
+ },
669
+ async ({ featureName }) => {
336
670
  try {
337
- requirementsContext = await fs.readFile(requirementsPath, 'utf8');
338
- } catch (error) {
339
- requirementsContext = 'Requirements document not available';
340
- }
671
+ const currentPath = process.cwd();
672
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
673
+ const specPath = path.join(featurePath, "spec.json");
674
+
675
+ // Read and validate spec
676
+ const specContent = await fs.readFile(specPath, "utf8");
677
+ const spec = JSON.parse(specContent);
678
+
679
+ if (!spec.approvals.design.generated) {
680
+ return {
681
+ content: [
682
+ {
683
+ type: "text",
684
+ text: `Error: Design must be generated before tasks. Run \`sdd-design ${featureName}\` first.`,
685
+ },
686
+ ],
687
+ };
688
+ }
689
+
690
+ // Read design and requirements for context
691
+ const designPath = path.join(featurePath, "design.md");
692
+ const requirementsPath = path.join(featurePath, "requirements.md");
693
+ let designContext = "";
694
+ let requirementsContext = "";
695
+
696
+ try {
697
+ designContext = await fs.readFile(designPath, "utf8");
698
+ } catch (error) {
699
+ designContext = "Design document not available";
700
+ }
701
+
702
+ try {
703
+ requirementsContext = await fs.readFile(requirementsPath, "utf8");
704
+ } catch (error) {
705
+ requirementsContext = "Requirements document not available";
706
+ }
341
707
 
342
- // Generate tasks document based on requirements and design
343
- const tasksContent = `# Implementation Plan
708
+ // Generate tasks document based on requirements and design
709
+ const tasksContent = `# Implementation Plan
344
710
 
345
711
  ## Project Context
346
712
  **Feature**: ${spec.feature_name}
347
- **Description**: ${spec.description || 'Feature to be implemented'}
348
- **Design Phase**: ${spec.approvals.design.generated ? 'Completed' : 'Pending'}
713
+ **Description**: ${spec.description || "Feature to be implemented"}
714
+ **Design Phase**: ${spec.approvals.design.generated ? "Completed" : "Pending"}
349
715
 
350
716
  ## Instructions for AI Agent
351
717
 
@@ -370,12 +736,12 @@ Create tasks that:
370
736
 
371
737
  ## Requirements Context
372
738
  \`\`\`
373
- ${requirementsContext.substring(0, 1000)}${requirementsContext.length > 1000 ? '...\n[Requirements truncated - see requirements.md for full content]' : ''}
739
+ ${requirementsContext.substring(0, 1000)}${requirementsContext.length > 1000 ? "...\n[Requirements truncated - see requirements.md for full content]" : ""}
374
740
  \`\`\`
375
741
 
376
742
  ## Design Context
377
743
  \`\`\`
378
- ${designContext.substring(0, 1000)}${designContext.length > 1000 ? '...\n[Design truncated - see design.md for full content]' : ''}
744
+ ${designContext.substring(0, 1000)}${designContext.length > 1000 ? "...\n[Design truncated - see design.md for full content]" : ""}
379
745
  \`\`\`
380
746
 
381
747
  ## Current Project Information
@@ -386,504 +752,635 @@ ${designContext.substring(0, 1000)}${designContext.length > 1000 ? '...\n[Design
386
752
 
387
753
  **Note**: This template will be replaced by AI-generated implementation tasks specific to your project requirements and design.`;
388
754
 
389
- // Try to replace template with analysis-backed tasks
390
- try {
391
- const { mod } = await loadSpecGenerator();
392
- tasksContent = await mod.generateTasksDocument(currentPath, featureName);
393
- } catch (e) {
394
- // Keep template; include debug info in file header already
755
+ // Try to replace template with analysis-backed tasks
756
+ try {
757
+ const { mod } = await loadSpecGenerator();
758
+ tasksContent = await mod.generateTasksDocument(
759
+ currentPath,
760
+ featureName,
761
+ );
762
+ } catch (e) {
763
+ // Keep template; include debug info in file header already
764
+ }
765
+
766
+ await fs.writeFile(path.join(featurePath, "tasks.md"), tasksContent);
767
+
768
+ // Update spec.json
769
+ spec.phase = "tasks-generated";
770
+ spec.approvals.tasks.generated = true;
771
+ spec.ready_for_implementation = true;
772
+ spec.updated_at = await getCurrentTimestamp();
773
+
774
+ await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
775
+
776
+ return {
777
+ content: [
778
+ {
779
+ type: "text",
780
+ text: `## Implementation Tasks Generated\n\nImplementation tasks document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/tasks.md\n**Status**: Tasks phase completed\n**Ready for Implementation**: Yes\n\n**Next Step**: Review tasks, then use \`sdd-implement\` to begin implementation or \`sdd-status\` to check progress`,
781
+ },
782
+ ],
783
+ };
784
+ } catch (error) {
785
+ return {
786
+ content: [
787
+ {
788
+ type: "text",
789
+ text: `Error generating tasks: ${error.message}`,
790
+ },
791
+ ],
792
+ };
395
793
  }
396
-
397
- await fs.writeFile(path.join(featurePath, 'tasks.md'), tasksContent);
398
-
399
- // Update spec.json
400
- spec.phase = "tasks-generated";
401
- spec.approvals.tasks.generated = true;
402
- spec.ready_for_implementation = true;
403
- spec.updated_at = await getCurrentTimestamp();
404
-
405
- await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
406
-
407
- return {
408
- content: [{
409
- type: 'text',
410
- text: `## Implementation Tasks Generated\n\nImplementation tasks document generated for feature: **${featureName}**\n\n**Generated**: .kiro/specs/${featureName}/tasks.md\n**Status**: Tasks phase completed\n**Ready for Implementation**: Yes\n\n**Next Step**: Review tasks, then use \`sdd-implement\` to begin implementation or \`sdd-status\` to check progress`
411
- }]
412
- };
413
- } catch (error) {
414
- return {
415
- content: [{
416
- type: 'text',
417
- text: `Error generating tasks: ${error.message}`
418
- }]
419
- };
420
- }
421
- });
794
+ },
795
+ );
422
796
 
423
797
  // 5. sdd-implement - Implementation guidelines
424
- server.registerTool("sdd-implement", {
425
- title: "Implementation Guidelines",
426
- description: "Implementation guidelines",
427
- inputSchema: {
428
- featureName: z.string().describe('Feature name from spec initialization')
798
+ server.registerTool(
799
+ "sdd-implement",
800
+ {
801
+ title: "Implementation Guidelines",
802
+ description: "Implementation guidelines",
803
+ inputSchema: {
804
+ featureName: z.string().describe("Feature name from spec initialization"),
805
+ },
429
806
  },
430
- }, async ({ featureName }) => {
431
- try {
432
- const currentPath = process.cwd();
433
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
434
- const specPath = path.join(featurePath, 'spec.json');
435
-
436
- // Read spec
437
- const specContent = await fs.readFile(specPath, 'utf8');
438
- const spec = JSON.parse(specContent);
439
-
440
- if (!spec.ready_for_implementation) {
807
+ async ({ featureName }) => {
808
+ try {
809
+ const currentPath = process.cwd();
810
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
811
+ const specPath = path.join(featurePath, "spec.json");
812
+
813
+ // Read spec
814
+ const specContent = await fs.readFile(specPath, "utf8");
815
+ const spec = JSON.parse(specContent);
816
+
817
+ if (!spec.ready_for_implementation) {
818
+ return {
819
+ content: [
820
+ {
821
+ type: "text",
822
+ text: `Error: Project not ready for implementation. Complete requirements, design, and tasks phases first.`,
823
+ },
824
+ ],
825
+ };
826
+ }
827
+
828
+ return {
829
+ content: [
830
+ {
831
+ type: "text",
832
+ text: `## Implementation Guidelines for ${featureName}\n\n**Project Status**: Ready for implementation\n**Current Phase**: ${spec.phase}\n\n**Implementation Instructions**:\n1. Work through tasks sequentially as defined in tasks.md\n2. Follow the technical design specifications in design.md\n3. Ensure all requirements from requirements.md are satisfied\n4. Use \`sdd-quality-check\` to validate code quality\n5. Mark tasks as completed in tasks.md as you progress\n\n**Key Principles**:\n- Follow established coding patterns and conventions\n- Implement comprehensive error handling\n- Add appropriate logging and monitoring\n- Write tests for each component\n- Validate against requirements at each step\n\n**Next Steps**:\n- Begin with Task 1: Set up MCP server foundation\n- Use the design document as your implementation guide\n- Run quality checks regularly during development`,
833
+ },
834
+ ],
835
+ };
836
+ } catch (error) {
441
837
  return {
442
- content: [{
443
- type: 'text',
444
- text: `Error: Project not ready for implementation. Complete requirements, design, and tasks phases first.`
445
- }]
838
+ content: [
839
+ {
840
+ type: "text",
841
+ text: `Error getting implementation guidelines: ${error.message}`,
842
+ },
843
+ ],
446
844
  };
447
845
  }
448
-
449
- return {
450
- content: [{
451
- type: 'text',
452
- text: `## Implementation Guidelines for ${featureName}\n\n**Project Status**: Ready for implementation\n**Current Phase**: ${spec.phase}\n\n**Implementation Instructions**:\n1. Work through tasks sequentially as defined in tasks.md\n2. Follow the technical design specifications in design.md\n3. Ensure all requirements from requirements.md are satisfied\n4. Use \`sdd-quality-check\` to validate code quality\n5. Mark tasks as completed in tasks.md as you progress\n\n**Key Principles**:\n- Follow established coding patterns and conventions\n- Implement comprehensive error handling\n- Add appropriate logging and monitoring\n- Write tests for each component\n- Validate against requirements at each step\n\n**Next Steps**:\n- Begin with Task 1: Set up MCP server foundation\n- Use the design document as your implementation guide\n- Run quality checks regularly during development`
453
- }]
454
- };
455
- } catch (error) {
456
- return {
457
- content: [{
458
- type: 'text',
459
- text: `Error getting implementation guidelines: ${error.message}`
460
- }]
461
- };
462
- }
463
- });
846
+ },
847
+ );
464
848
 
465
849
  // 6. sdd-status - Check workflow progress
466
- server.registerTool("sdd-status", {
467
- title: "Check Workflow Progress",
468
- description: "Check workflow progress",
469
- inputSchema: {
470
- featureName: z.string().optional().describe('Feature name (optional - shows all if not provided)')
850
+ server.registerTool(
851
+ "sdd-status",
852
+ {
853
+ title: "Check Workflow Progress",
854
+ description: "Check workflow progress",
855
+ inputSchema: {
856
+ featureName: z
857
+ .string()
858
+ .optional()
859
+ .describe("Feature name (optional - shows all if not provided)"),
860
+ },
471
861
  },
472
- }, async ({ featureName }) => {
473
- try {
474
- const currentPath = process.cwd();
475
- const kiroPath = path.join(currentPath, '.kiro');
476
-
477
- // Check if .kiro directory exists
478
- const kiroExists = await fs.access(kiroPath).then(() => true).catch(() => false);
479
- if (!kiroExists) {
480
- return {
481
- content: [{
482
- type: 'text',
483
- text: 'SDD project status: No active project found. Use sdd-init to create a new project.'
484
- }]
485
- };
486
- }
487
-
488
- const specsPath = path.join(kiroPath, 'specs');
489
-
490
- if (featureName) {
491
- // Show status for specific feature
492
- const featurePath = path.join(specsPath, featureName);
493
- const specPath = path.join(featurePath, 'spec.json');
494
-
495
- const specExists = await fs.access(specPath).then(() => true).catch(() => false);
496
- if (!specExists) {
862
+ async ({ featureName }) => {
863
+ try {
864
+ const currentPath = process.cwd();
865
+ const kiroPath = path.join(currentPath, ".kiro");
866
+
867
+ // Check if .kiro directory exists
868
+ const kiroExists = await fs
869
+ .access(kiroPath)
870
+ .then(() => true)
871
+ .catch(() => false);
872
+ if (!kiroExists) {
497
873
  return {
498
- content: [{
499
- type: 'text',
500
- text: `Feature "${featureName}" not found. Use sdd-init to create it.`
501
- }]
874
+ content: [
875
+ {
876
+ type: "text",
877
+ text: "SDD project status: No active project found. Use sdd-init to create a new project.",
878
+ },
879
+ ],
502
880
  };
503
881
  }
504
-
505
- const specContent = await fs.readFile(specPath, 'utf8');
506
- const spec = JSON.parse(specContent);
507
-
508
- let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
509
- status += `**Current Phase**: ${spec.phase}\n`;
510
- status += `**Language**: ${spec.language}\n`;
511
- status += `**Created**: ${spec.created_at}\n`;
512
- status += `**Updated**: ${spec.updated_at}\n\n`;
513
-
514
- status += `**Phase Progress**:\n`;
515
- status += `- Requirements: ${spec.approvals.requirements.generated ? '✅ Generated' : '❌ Not Generated'}${spec.approvals.requirements.approved ? ', ✅ Approved' : ', ❌ Not Approved'}\n`;
516
- status += `- Design: ${spec.approvals.design.generated ? '✅ Generated' : '❌ Not Generated'}${spec.approvals.design.approved ? ', ✅ Approved' : ', ❌ Not Approved'}\n`;
517
- status += `- Tasks: ${spec.approvals.tasks.generated ? '✅ Generated' : '❌ Not Generated'}${spec.approvals.tasks.approved ? ', ✅ Approved' : ', ❌ Not Approved'}\n\n`;
518
-
519
- status += `**Ready for Implementation**: ${spec.ready_for_implementation ? '✅ Yes' : '❌ No'}\n\n`;
520
-
521
- // Suggest next steps
522
- if (!spec.approvals.requirements.generated) {
523
- status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
524
- } else if (!spec.approvals.design.generated) {
525
- status += `**Next Step**: Run \`sdd-design ${featureName}\``;
526
- } else if (!spec.approvals.tasks.generated) {
527
- status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
528
- } else {
529
- status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
530
- }
531
-
532
- return {
533
- content: [{
534
- type: 'text',
535
- text: status
536
- }]
537
- };
538
- } else {
539
- // Show all features
540
- const features = await fs.readdir(specsPath).catch(() => []);
541
-
542
- if (features.length === 0) {
882
+
883
+ const specsPath = path.join(kiroPath, "specs");
884
+
885
+ if (featureName) {
886
+ // Show status for specific feature
887
+ const featurePath = path.join(specsPath, featureName);
888
+ const specPath = path.join(featurePath, "spec.json");
889
+
890
+ const specExists = await fs
891
+ .access(specPath)
892
+ .then(() => true)
893
+ .catch(() => false);
894
+ if (!specExists) {
895
+ return {
896
+ content: [
897
+ {
898
+ type: "text",
899
+ text: `Feature "${featureName}" not found. Use sdd-init to create it.`,
900
+ },
901
+ ],
902
+ };
903
+ }
904
+
905
+ const specContent = await fs.readFile(specPath, "utf8");
906
+ const spec = JSON.parse(specContent);
907
+
908
+ let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
909
+ status += `**Current Phase**: ${spec.phase}\n`;
910
+ status += `**Language**: ${spec.language}\n`;
911
+ status += `**Created**: ${spec.created_at}\n`;
912
+ status += `**Updated**: ${spec.updated_at}\n\n`;
913
+
914
+ status += `**Phase Progress**:\n`;
915
+ status += `- Requirements: ${spec.approvals.requirements.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.requirements.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
916
+ status += `- Design: ${spec.approvals.design.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.design.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
917
+ status += `- Tasks: ${spec.approvals.tasks.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.tasks.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n\n`;
918
+
919
+ status += `**Ready for Implementation**: ${spec.ready_for_implementation ? "✅ Yes" : "❌ No"}\n\n`;
920
+
921
+ // Suggest next steps
922
+ if (!spec.approvals.requirements.generated) {
923
+ status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
924
+ } else if (!spec.approvals.design.generated) {
925
+ status += `**Next Step**: Run \`sdd-design ${featureName}\``;
926
+ } else if (!spec.approvals.tasks.generated) {
927
+ status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
928
+ } else {
929
+ status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
930
+ }
931
+
543
932
  return {
544
- content: [{
545
- type: 'text',
546
- text: 'No SDD features found. Use sdd-init to create a new project.'
547
- }]
933
+ content: [
934
+ {
935
+ type: "text",
936
+ text: status,
937
+ },
938
+ ],
548
939
  };
549
- }
550
-
551
- let status = `## SDD Project Status - All Features\n\n`;
552
-
553
- for (const feature of features) {
554
- const specPath = path.join(specsPath, feature, 'spec.json');
555
- const specExists = await fs.access(specPath).then(() => true).catch(() => false);
556
-
557
- if (specExists) {
558
- const specContent = await fs.readFile(specPath, 'utf8');
559
- const spec = JSON.parse(specContent);
560
-
561
- status += `**${spec.feature_name}**:\n`;
562
- status += `- Phase: ${spec.phase}\n`;
563
- status += `- Requirements: ${spec.approvals.requirements.generated ? '✅' : '❌'}\n`;
564
- status += `- Design: ${spec.approvals.design.generated ? '✅' : '❌'}\n`;
565
- status += `- Tasks: ${spec.approvals.tasks.generated ? '✅' : '❌'}\n`;
566
- status += `- Ready: ${spec.ready_for_implementation ? '✅' : '❌'}\n\n`;
940
+ } else {
941
+ // Show all features
942
+ const features = await fs.readdir(specsPath).catch(() => []);
943
+
944
+ if (features.length === 0) {
945
+ return {
946
+ content: [
947
+ {
948
+ type: "text",
949
+ text: "No SDD features found. Use sdd-init to create a new project.",
950
+ },
951
+ ],
952
+ };
953
+ }
954
+
955
+ let status = `## SDD Project Status - All Features\n\n`;
956
+
957
+ for (const feature of features) {
958
+ const specPath = path.join(specsPath, feature, "spec.json");
959
+ const specExists = await fs
960
+ .access(specPath)
961
+ .then(() => true)
962
+ .catch(() => false);
963
+
964
+ if (specExists) {
965
+ const specContent = await fs.readFile(specPath, "utf8");
966
+ const spec = JSON.parse(specContent);
967
+
968
+ status += `**${spec.feature_name}**:\n`;
969
+ status += `- Phase: ${spec.phase}\n`;
970
+ status += `- Requirements: ${spec.approvals.requirements.generated ? "✅" : "❌"}\n`;
971
+ status += `- Design: ${spec.approvals.design.generated ? "✅" : "❌"}\n`;
972
+ status += `- Tasks: ${spec.approvals.tasks.generated ? "✅" : "❌"}\n`;
973
+ status += `- Ready: ${spec.ready_for_implementation ? "✅" : "❌"}\n\n`;
974
+ }
567
975
  }
976
+
977
+ return {
978
+ content: [
979
+ {
980
+ type: "text",
981
+ text: status,
982
+ },
983
+ ],
984
+ };
568
985
  }
569
-
986
+ } catch (error) {
570
987
  return {
571
- content: [{
572
- type: 'text',
573
- text: status
574
- }]
988
+ content: [
989
+ {
990
+ type: "text",
991
+ text: `Error checking status: ${error.message}`,
992
+ },
993
+ ],
575
994
  };
576
995
  }
577
- } catch (error) {
578
- return {
579
- content: [{
580
- type: 'text',
581
- text: `Error checking status: ${error.message}`
582
- }]
583
- };
584
- }
585
- });
996
+ },
997
+ );
586
998
 
587
999
  // 7. sdd-approve - Approve workflow phases
588
- server.registerTool("sdd-approve", {
589
- title: "Approve Workflow Phases",
590
- description: "Approve workflow phases",
591
- inputSchema: {
592
- featureName: z.string().describe('Feature name from spec initialization'),
593
- phase: z.enum(['requirements', 'design', 'tasks']).describe('Phase to approve')
1000
+ server.registerTool(
1001
+ "sdd-approve",
1002
+ {
1003
+ title: "Approve Workflow Phases",
1004
+ description: "Approve workflow phases",
1005
+ inputSchema: {
1006
+ featureName: z.string().describe("Feature name from spec initialization"),
1007
+ phase: z
1008
+ .enum(["requirements", "design", "tasks"])
1009
+ .describe("Phase to approve"),
1010
+ },
594
1011
  },
595
- }, async ({ featureName, phase }) => {
596
- try {
597
- const currentPath = process.cwd();
598
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
599
- const specPath = path.join(featurePath, 'spec.json');
600
-
601
- // Read spec
602
- const specContent = await fs.readFile(specPath, 'utf8');
603
- const spec = JSON.parse(specContent);
604
-
605
- if (!spec.approvals[phase].generated) {
1012
+ async ({ featureName, phase }) => {
1013
+ try {
1014
+ const currentPath = process.cwd();
1015
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
1016
+ const specPath = path.join(featurePath, "spec.json");
1017
+
1018
+ // Read spec
1019
+ const specContent = await fs.readFile(specPath, "utf8");
1020
+ const spec = JSON.parse(specContent);
1021
+
1022
+ if (!spec.approvals[phase].generated) {
1023
+ return {
1024
+ content: [
1025
+ {
1026
+ type: "text",
1027
+ text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`,
1028
+ },
1029
+ ],
1030
+ };
1031
+ }
1032
+
1033
+ // Approve the phase
1034
+ spec.approvals[phase].approved = true;
1035
+ spec.updated_at = await getCurrentTimestamp();
1036
+
1037
+ await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
1038
+
606
1039
  return {
607
- content: [{
608
- type: 'text',
609
- text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`
610
- }]
1040
+ content: [
1041
+ {
1042
+ type: "text",
1043
+ text: `## Phase Approved\n\n**Feature**: ${featureName}\n**Phase**: ${phase}\n**Status**: ✅ Approved\n\nPhase has been marked as approved and workflow can proceed to the next phase.`,
1044
+ },
1045
+ ],
1046
+ };
1047
+ } catch (error) {
1048
+ return {
1049
+ content: [
1050
+ {
1051
+ type: "text",
1052
+ text: `Error approving phase: ${error.message}`,
1053
+ },
1054
+ ],
611
1055
  };
612
1056
  }
613
-
614
- // Approve the phase
615
- spec.approvals[phase].approved = true;
616
- spec.updated_at = await getCurrentTimestamp();
617
-
618
- await fs.writeFile(specPath, JSON.stringify(spec, null, 2));
619
-
620
- return {
621
- content: [{
622
- type: 'text',
623
- text: `## Phase Approved\n\n**Feature**: ${featureName}\n**Phase**: ${phase}\n**Status**: ✅ Approved\n\nPhase has been marked as approved and workflow can proceed to the next phase.`
624
- }]
625
- };
626
- } catch (error) {
627
- return {
628
- content: [{
629
- type: 'text',
630
- text: `Error approving phase: ${error.message}`
631
- }]
632
- };
633
- }
634
- });
1057
+ },
1058
+ );
635
1059
 
636
1060
  // 8. sdd-quality-check - Code quality analysis
637
- server.registerTool("sdd-quality-check", {
638
- title: "Code Quality Analysis",
639
- description: "Code quality analysis",
640
- inputSchema: {
641
- code: z.string().describe('Code to analyze'),
642
- language: z.string().optional().describe('Programming language (default: javascript)')
1061
+ server.registerTool(
1062
+ "sdd-quality-check",
1063
+ {
1064
+ title: "Code Quality Analysis",
1065
+ description: "Code quality analysis",
1066
+ inputSchema: {
1067
+ code: z.string().describe("Code to analyze"),
1068
+ language: z
1069
+ .string()
1070
+ .optional()
1071
+ .describe("Programming language (default: javascript)"),
1072
+ },
643
1073
  },
644
- }, async ({ code, language = 'javascript' }) => {
645
- try {
646
- // Simple quality analysis (Linus-style 5-layer approach)
647
- const lines = code.split('\n');
648
- const issues = [];
649
-
650
- // Layer 1: Syntax and Basic Structure
651
- if (code.includes('console.log')) {
652
- issues.push('L1: Remove debug console.log statements');
653
- }
654
- if (code.includes('var ')) {
655
- issues.push('L1: Use let/const instead of var');
656
- }
657
-
658
- // Layer 2: Code Style and Conventions
659
- if (!/^[a-z]/.test(code.split('function ')[1]?.split('(')[0] || '')) {
660
- if (code.includes('function ')) {
661
- issues.push('L2: Function names should start with lowercase');
1074
+ async ({ code, language = "javascript" }) => {
1075
+ try {
1076
+ // Simple quality analysis (Linus-style 5-layer approach)
1077
+ const lines = code.split("\n");
1078
+ const issues = [];
1079
+
1080
+ // Layer 1: Syntax and Basic Structure
1081
+ if (code.includes("console.log")) {
1082
+ issues.push("L1: Remove debug console.log statements");
662
1083
  }
663
- }
664
-
665
- // Layer 3: Logic and Algorithm
666
- if (code.includes('for') && !code.includes('const')) {
667
- issues.push('L3: Consider using const in for loops for immutable iteration variables');
668
- }
669
-
670
- // Layer 4: Architecture and Design
671
- if (lines.length > 50) {
672
- issues.push('L4: Function/module is too long, consider breaking into smaller parts');
673
- }
674
-
675
- // Layer 5: Business Logic and Requirements
676
- if (!code.includes('error') && code.includes('try')) {
677
- issues.push('L5: Missing proper error handling in try block');
678
- }
679
-
680
- const qualityScore = Math.max(0, 100 - (issues.length * 15));
681
-
682
- let report = `## Linus-Style Code Quality Analysis\n\n`;
683
- report += `**Language**: ${language}\n`;
684
- report += `**Lines of Code**: ${lines.length}\n`;
685
- report += `**Quality Score**: ${qualityScore}/100\n\n`;
686
-
687
- if (issues.length === 0) {
688
- report += `**Status**: Code quality is excellent\n\n`;
689
- report += `**Analysis**: No significant issues found. Code follows good practices.`;
690
- } else {
691
- report += `**Issues Found**: ${issues.length}\n\n`;
692
- report += `**Quality Issues**:\n`;
693
- for (const issue of issues) {
694
- report += `- ${issue}\n`;
1084
+ if (code.includes("var ")) {
1085
+ issues.push("L1: Use let/const instead of var");
1086
+ }
1087
+
1088
+ // Layer 2: Code Style and Conventions
1089
+ if (!/^[a-z]/.test(code.split("function ")[1]?.split("(")[0] || "")) {
1090
+ if (code.includes("function ")) {
1091
+ issues.push("L2: Function names should start with lowercase");
1092
+ }
1093
+ }
1094
+
1095
+ // Layer 3: Logic and Algorithm
1096
+ if (code.includes("for") && !code.includes("const")) {
1097
+ issues.push(
1098
+ "L3: Consider using const in for loops for immutable iteration variables",
1099
+ );
1100
+ }
1101
+
1102
+ // Layer 4: Architecture and Design
1103
+ if (lines.length > 50) {
1104
+ issues.push(
1105
+ "L4: Function/module is too long, consider breaking into smaller parts",
1106
+ );
1107
+ }
1108
+
1109
+ // Layer 5: Business Logic and Requirements
1110
+ if (!code.includes("error") && code.includes("try")) {
1111
+ issues.push("L5: Missing proper error handling in try block");
1112
+ }
1113
+
1114
+ const qualityScore = Math.max(0, 100 - issues.length * 15);
1115
+
1116
+ let report = `## Linus-Style Code Quality Analysis\n\n`;
1117
+ report += `**Language**: ${language}\n`;
1118
+ report += `**Lines of Code**: ${lines.length}\n`;
1119
+ report += `**Quality Score**: ${qualityScore}/100\n\n`;
1120
+
1121
+ if (issues.length === 0) {
1122
+ report += `**Status**: ✅ Code quality is excellent\n\n`;
1123
+ report += `**Analysis**: No significant issues found. Code follows good practices.`;
1124
+ } else {
1125
+ report += `**Issues Found**: ${issues.length}\n\n`;
1126
+ report += `**Quality Issues**:\n`;
1127
+ for (const issue of issues) {
1128
+ report += `- ${issue}\n`;
1129
+ }
1130
+ report += `\n**Recommendation**: Address the identified issues to improve code quality.`;
695
1131
  }
696
- report += `\n**Recommendation**: Address the identified issues to improve code quality.`;
1132
+
1133
+ return {
1134
+ content: [
1135
+ {
1136
+ type: "text",
1137
+ text: report,
1138
+ },
1139
+ ],
1140
+ };
1141
+ } catch (error) {
1142
+ return {
1143
+ content: [
1144
+ {
1145
+ type: "text",
1146
+ text: `Error analyzing code quality: ${error.message}`,
1147
+ },
1148
+ ],
1149
+ };
697
1150
  }
698
-
699
- return {
700
- content: [{
701
- type: 'text',
702
- text: report
703
- }]
704
- };
705
- } catch (error) {
706
- return {
707
- content: [{
708
- type: 'text',
709
- text: `Error analyzing code quality: ${error.message}`
710
- }]
711
- };
712
- }
713
- });
1151
+ },
1152
+ );
714
1153
 
715
1154
  // 9. sdd-context-load - Load project context
716
- server.registerTool("sdd-context-load", {
717
- title: "Load Project Context",
718
- description: "Load project context",
719
- inputSchema: {
720
- featureName: z.string().describe('Feature name to load context for')
1155
+ server.registerTool(
1156
+ "sdd-context-load",
1157
+ {
1158
+ title: "Load Project Context",
1159
+ description: "Load project context",
1160
+ inputSchema: {
1161
+ featureName: z.string().describe("Feature name to load context for"),
1162
+ },
721
1163
  },
722
- }, async ({ featureName }) => {
723
- try {
724
- const currentPath = process.cwd();
725
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
726
-
727
- // Load all context files
728
- const files = ['spec.json', 'requirements.md', 'design.md', 'tasks.md'];
729
- const context = {};
730
-
731
- for (const file of files) {
732
- const filePath = path.join(featurePath, file);
733
- const fileExists = await fs.access(filePath).then(() => true).catch(() => false);
734
-
735
- if (fileExists) {
736
- const content = await fs.readFile(filePath, 'utf8');
737
- context[file] = file.endsWith('.json') ? JSON.parse(content) : content;
1164
+ async ({ featureName }) => {
1165
+ try {
1166
+ const currentPath = process.cwd();
1167
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
1168
+
1169
+ // Load all context files
1170
+ const files = ["spec.json", "requirements.md", "design.md", "tasks.md"];
1171
+ const context = {};
1172
+
1173
+ for (const file of files) {
1174
+ const filePath = path.join(featurePath, file);
1175
+ const fileExists = await fs
1176
+ .access(filePath)
1177
+ .then(() => true)
1178
+ .catch(() => false);
1179
+
1180
+ if (fileExists) {
1181
+ const content = await fs.readFile(filePath, "utf8");
1182
+ context[file] = file.endsWith(".json")
1183
+ ? JSON.parse(content)
1184
+ : content;
1185
+ }
738
1186
  }
739
- }
740
-
741
- let contextReport = `## Project Context Loaded: ${featureName}\n\n`;
742
-
743
- if (context['spec.json']) {
744
- const spec = context['spec.json'];
745
- contextReport += `**Project Metadata**:\n`;
746
- contextReport += `- Feature: ${spec.feature_name}\n`;
747
- contextReport += `- Phase: ${spec.phase}\n`;
748
- contextReport += `- Language: ${spec.language}\n`;
749
- contextReport += `- Ready for Implementation: ${spec.ready_for_implementation ? 'Yes' : 'No'}\n\n`;
750
- }
751
-
752
- contextReport += `**Available Documents**:\n`;
753
- for (const [file, content] of Object.entries(context)) {
754
- if (file !== 'spec.json') {
755
- const preview = typeof content === 'string' ? content.substring(0, 100) + '...' : 'JSON data';
756
- contextReport += `- **${file}**: ${preview}\n`;
1187
+
1188
+ let contextReport = `## Project Context Loaded: ${featureName}\n\n`;
1189
+
1190
+ if (context["spec.json"]) {
1191
+ const spec = context["spec.json"];
1192
+ contextReport += `**Project Metadata**:\n`;
1193
+ contextReport += `- Feature: ${spec.feature_name}\n`;
1194
+ contextReport += `- Phase: ${spec.phase}\n`;
1195
+ contextReport += `- Language: ${spec.language}\n`;
1196
+ contextReport += `- Ready for Implementation: ${spec.ready_for_implementation ? "Yes" : "No"}\n\n`;
1197
+ }
1198
+
1199
+ contextReport += `**Available Documents**:\n`;
1200
+ for (const [file, content] of Object.entries(context)) {
1201
+ if (file !== "spec.json") {
1202
+ const preview =
1203
+ typeof content === "string"
1204
+ ? content.substring(0, 100) + "..."
1205
+ : "JSON data";
1206
+ contextReport += `- **${file}**: ${preview}\n`;
1207
+ }
757
1208
  }
1209
+
1210
+ contextReport += `\n**Context Status**: Project memory restored successfully\n`;
1211
+ contextReport += `**Total Files Loaded**: ${Object.keys(context).length}`;
1212
+
1213
+ return {
1214
+ content: [
1215
+ {
1216
+ type: "text",
1217
+ text: contextReport,
1218
+ },
1219
+ ],
1220
+ };
1221
+ } catch (error) {
1222
+ return {
1223
+ content: [
1224
+ {
1225
+ type: "text",
1226
+ text: `Error loading project context: ${error.message}`,
1227
+ },
1228
+ ],
1229
+ };
758
1230
  }
759
-
760
- contextReport += `\n**Context Status**: Project memory restored successfully\n`;
761
- contextReport += `**Total Files Loaded**: ${Object.keys(context).length}`;
762
-
763
- return {
764
- content: [{
765
- type: 'text',
766
- text: contextReport
767
- }]
768
- };
769
- } catch (error) {
770
- return {
771
- content: [{
772
- type: 'text',
773
- text: `Error loading project context: ${error.message}`
774
- }]
775
- };
776
- }
777
- });
1231
+ },
1232
+ );
778
1233
 
779
1234
  // 10. sdd-template-render - Render templates
780
- server.registerTool("sdd-template-render", {
781
- title: "Render Templates",
782
- description: "Render templates",
783
- inputSchema: {
784
- templateType: z.enum(['requirements', 'design', 'tasks', 'custom']).describe('Type of template to render'),
785
- featureName: z.string().describe('Feature name for template context'),
786
- customTemplate: z.string().optional().describe('Custom template content (if templateType is custom)')
1235
+ server.registerTool(
1236
+ "sdd-template-render",
1237
+ {
1238
+ title: "Render Templates",
1239
+ description: "Render templates",
1240
+ inputSchema: {
1241
+ templateType: z
1242
+ .enum(["requirements", "design", "tasks", "custom"])
1243
+ .describe("Type of template to render"),
1244
+ featureName: z.string().describe("Feature name for template context"),
1245
+ customTemplate: z
1246
+ .string()
1247
+ .optional()
1248
+ .describe("Custom template content (if templateType is custom)"),
1249
+ },
787
1250
  },
788
- }, async ({ templateType, featureName, customTemplate }) => {
789
- try {
790
- const currentPath = process.cwd();
791
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
792
- const specPath = path.join(featurePath, 'spec.json');
793
-
794
- // Load spec for context
795
- const specExists = await fs.access(specPath).then(() => true).catch(() => false);
796
- let spec = {};
797
- if (specExists) {
798
- const specContent = await fs.readFile(specPath, 'utf8');
799
- spec = JSON.parse(specContent);
800
- }
801
-
802
- let renderedContent = '';
803
-
804
- switch (templateType) {
805
- case 'requirements':
806
- renderedContent = `# Requirements Template for ${featureName}\n\n## Project Context\n- Feature: ${spec.feature_name || featureName}\n- Language: ${spec.language || 'en'}\n\n## Requirements Sections\n1. Functional Requirements\n2. Non-Functional Requirements\n3. Business Rules\n4. Acceptance Criteria (EARS format)`;
807
- break;
808
-
809
- case 'design':
810
- renderedContent = `# Design Template for ${featureName}\n\n## Architecture Overview\n- System Architecture\n- Component Design\n- Data Models\n- Interface Specifications\n\n## Technology Decisions\n- Stack Selection\n- Framework Choices\n- Integration Patterns`;
811
- break;
812
-
813
- case 'tasks':
814
- renderedContent = `# Tasks Template for ${featureName}\n\n## Implementation Tasks\n\n- [ ] 1. Foundation Setup\n - Project initialization\n - Dependencies setup\n - Basic structure\n\n- [ ] 2. Core Implementation\n - Main functionality\n - Business logic\n - Data handling\n\n- [ ] 3. Integration & Testing\n - System integration\n - Testing implementation\n - Quality validation`;
815
- break;
816
-
817
- case 'custom':
818
- if (!customTemplate) {
819
- throw new Error('Custom template content is required for custom template type');
820
- }
821
- // Simple template variable replacement
822
- renderedContent = customTemplate
823
- .replace(/\{\{featureName\}\}/g, featureName)
824
- .replace(/\{\{language\}\}/g, spec.language || 'en')
825
- .replace(/\{\{phase\}\}/g, spec.phase || 'initialized')
826
- .replace(/\{\{timestamp\}\}/g, new Date().toISOString());
827
- break;
1251
+ async ({ templateType, featureName, customTemplate }) => {
1252
+ try {
1253
+ const currentPath = process.cwd();
1254
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
1255
+ const specPath = path.join(featurePath, "spec.json");
1256
+
1257
+ // Load spec for context
1258
+ const specExists = await fs
1259
+ .access(specPath)
1260
+ .then(() => true)
1261
+ .catch(() => false);
1262
+ let spec = {};
1263
+ if (specExists) {
1264
+ const specContent = await fs.readFile(specPath, "utf8");
1265
+ spec = JSON.parse(specContent);
1266
+ }
1267
+
1268
+ let renderedContent = "";
1269
+
1270
+ switch (templateType) {
1271
+ case "requirements":
1272
+ renderedContent = `# Requirements Template for ${featureName}\n\n## Project Context\n- Feature: ${spec.feature_name || featureName}\n- Language: ${spec.language || "en"}\n\n## Requirements Sections\n1. Functional Requirements\n2. Non-Functional Requirements\n3. Business Rules\n4. Acceptance Criteria (EARS format)`;
1273
+ break;
1274
+
1275
+ case "design":
1276
+ renderedContent = `# Design Template for ${featureName}\n\n## Architecture Overview\n- System Architecture\n- Component Design\n- Data Models\n- Interface Specifications\n\n## Technology Decisions\n- Stack Selection\n- Framework Choices\n- Integration Patterns`;
1277
+ break;
1278
+
1279
+ case "tasks":
1280
+ renderedContent = `# Tasks Template for ${featureName}\n\n## Implementation Tasks\n\n- [ ] 1. Foundation Setup\n - Project initialization\n - Dependencies setup\n - Basic structure\n\n- [ ] 2. Core Implementation\n - Main functionality\n - Business logic\n - Data handling\n\n- [ ] 3. Integration & Testing\n - System integration\n - Testing implementation\n - Quality validation`;
1281
+ break;
1282
+
1283
+ case "custom":
1284
+ if (!customTemplate) {
1285
+ throw new Error(
1286
+ "Custom template content is required for custom template type",
1287
+ );
1288
+ }
1289
+ // Simple template variable replacement
1290
+ renderedContent = customTemplate
1291
+ .replace(/\{\{featureName\}\}/g, featureName)
1292
+ .replace(/\{\{language\}\}/g, spec.language || "en")
1293
+ .replace(/\{\{phase\}\}/g, spec.phase || "initialized")
1294
+ .replace(/\{\{timestamp\}\}/g, new Date().toISOString());
1295
+ break;
1296
+ }
1297
+
1298
+ return {
1299
+ content: [
1300
+ {
1301
+ type: "text",
1302
+ text: `## Template Rendered: ${templateType}\n\n**Feature**: ${featureName}\n**Template Type**: ${templateType}\n\n**Rendered Content**:\n\`\`\`markdown\n${renderedContent}\n\`\`\`\n\n**Usage**: Copy the rendered content to create your ${templateType} document`,
1303
+ },
1304
+ ],
1305
+ };
1306
+ } catch (error) {
1307
+ return {
1308
+ content: [
1309
+ {
1310
+ type: "text",
1311
+ text: `Error rendering template: ${error.message}`,
1312
+ },
1313
+ ],
1314
+ };
828
1315
  }
829
-
830
- return {
831
- content: [{
832
- type: 'text',
833
- text: `## Template Rendered: ${templateType}\n\n**Feature**: ${featureName}\n**Template Type**: ${templateType}\n\n**Rendered Content**:\n\`\`\`markdown\n${renderedContent}\n\`\`\`\n\n**Usage**: Copy the rendered content to create your ${templateType} document`
834
- }]
835
- };
836
- } catch (error) {
837
- return {
838
- content: [{
839
- type: 'text',
840
- text: `Error rendering template: ${error.message}`
841
- }]
842
- };
843
- }
844
- });
1316
+ },
1317
+ );
845
1318
 
846
1319
  // 11. sdd-steering - Create/update steering documents
847
- server.registerTool("sdd-steering", {
848
- title: "Create/Update Steering Documents",
849
- description: "Create or update steering documents",
850
- inputSchema: {
851
- updateMode: z.enum(['create', 'update']).optional().describe('Whether to create new or update existing documents (auto-detected if not specified)')
1320
+ server.registerTool(
1321
+ "sdd-steering",
1322
+ {
1323
+ title: "Create/Update Steering Documents",
1324
+ description: "Create or update steering documents",
1325
+ inputSchema: {
1326
+ updateMode: z
1327
+ .enum(["create", "update"])
1328
+ .optional()
1329
+ .describe(
1330
+ "Whether to create new or update existing documents (auto-detected if not specified)",
1331
+ ),
1332
+ },
852
1333
  },
853
- }, async ({ updateMode }) => {
854
- try {
855
- const currentPath = process.cwd();
856
- const steeringPath = path.join(currentPath, '.kiro', 'steering');
857
-
858
- // Create steering directory if it doesn't exist
859
- await fs.mkdir(steeringPath, { recursive: true });
860
-
861
- // Analyze existing files
862
- const productExists = await fs.access(path.join(steeringPath, 'product.md')).then(() => true).catch(() => false);
863
- const techExists = await fs.access(path.join(steeringPath, 'tech.md')).then(() => true).catch(() => false);
864
- const structureExists = await fs.access(path.join(steeringPath, 'structure.md')).then(() => true).catch(() => false);
865
-
866
- // Auto-detect mode if not specified
867
- if (!updateMode) {
868
- updateMode = (productExists || techExists || structureExists) ? 'update' : 'create';
869
- }
870
-
871
- // Generate actual analyzed content using documentGenerator functions
872
- const analysis = await analyzeProject(currentPath);
873
- const productContent = generateProductDocument(analysis);
874
- const techContent = generateTechDocument(analysis);
875
- const structureContent = generateStructureDocument(analysis);
876
-
877
- // Write the analyzed steering documents
878
- await fs.writeFile(path.join(steeringPath, 'product.md'), productContent);
879
- await fs.writeFile(path.join(steeringPath, 'tech.md'), techContent);
880
- await fs.writeFile(path.join(steeringPath, 'structure.md'), structureContent);
881
-
882
- // Ensure static steering docs exist (full content)
883
- const linusPath = path.join(steeringPath, 'linus-review.md');
884
- const linusExists = await fs.access(linusPath).then(() => true).catch(() => false);
885
- if (!linusExists) {
886
- const fullLinusContent = `# Linus Torvalds Code Review Steering Document
1334
+ async ({ updateMode }) => {
1335
+ try {
1336
+ const currentPath = process.cwd();
1337
+ const steeringPath = path.join(currentPath, ".kiro", "steering");
1338
+
1339
+ // Create steering directory if it doesn't exist
1340
+ await fs.mkdir(steeringPath, { recursive: true });
1341
+
1342
+ // Analyze existing files
1343
+ const productExists = await fs
1344
+ .access(path.join(steeringPath, "product.md"))
1345
+ .then(() => true)
1346
+ .catch(() => false);
1347
+ const techExists = await fs
1348
+ .access(path.join(steeringPath, "tech.md"))
1349
+ .then(() => true)
1350
+ .catch(() => false);
1351
+ const structureExists = await fs
1352
+ .access(path.join(steeringPath, "structure.md"))
1353
+ .then(() => true)
1354
+ .catch(() => false);
1355
+
1356
+ // Auto-detect mode if not specified
1357
+ if (!updateMode) {
1358
+ updateMode =
1359
+ productExists || techExists || structureExists ? "update" : "create";
1360
+ }
1361
+
1362
+ // Generate actual analyzed content using documentGenerator functions
1363
+ const analysis = await analyzeProject(currentPath);
1364
+ const productContent = generateProductDocument(analysis);
1365
+ const techContent = generateTechDocument(analysis);
1366
+ const structureContent = generateStructureDocument(analysis);
1367
+
1368
+ // Write the analyzed steering documents
1369
+ await fs.writeFile(path.join(steeringPath, "product.md"), productContent);
1370
+ await fs.writeFile(path.join(steeringPath, "tech.md"), techContent);
1371
+ await fs.writeFile(
1372
+ path.join(steeringPath, "structure.md"),
1373
+ structureContent,
1374
+ );
1375
+
1376
+ // Ensure static steering docs exist (full content)
1377
+ const linusPath = path.join(steeringPath, "linus-review.md");
1378
+ const linusExists = await fs
1379
+ .access(linusPath)
1380
+ .then(() => true)
1381
+ .catch(() => false);
1382
+ if (!linusExists) {
1383
+ const fullLinusContent = `# Linus Torvalds Code Review Steering Document
887
1384
 
888
1385
  ## Role Definition
889
1386
 
@@ -1036,12 +1533,15 @@ This steering document is applied when:
1036
1533
  - Code review: Apply taste scoring and improvement recommendations
1037
1534
 
1038
1535
  Remember: "Good taste" comes from experience. Question everything. Simplify ruthlessly. Never break userspace.`;
1039
- await fs.writeFile(linusPath, fullLinusContent);
1040
- }
1041
- const commitPath = path.join(steeringPath, 'commit.md');
1042
- const commitExists = await fs.access(commitPath).then(() => true).catch(() => false);
1043
- if (!commitExists) {
1044
- const fullCommitContent = `# Commit Message Guidelines
1536
+ await fs.writeFile(linusPath, fullLinusContent);
1537
+ }
1538
+ const commitPath = path.join(steeringPath, "commit.md");
1539
+ const commitExists = await fs
1540
+ .access(commitPath)
1541
+ .then(() => true)
1542
+ .catch(() => false);
1543
+ if (!commitExists) {
1544
+ const fullCommitContent = `# Commit Message Guidelines
1045
1545
 
1046
1546
  Commit messages should follow a consistent format to improve readability and provide clear context about changes. Each commit message should start with a type prefix that indicates the nature of the change.
1047
1547
 
@@ -1100,26 +1600,35 @@ refactor(module): simplify EKS node group module
1100
1600
  6. Reference issues and pull requests in the footer
1101
1601
 
1102
1602
  These guidelines help maintain a clean and useful git history that makes it easier to track changes and understand the project's evolution.`;
1103
- await fs.writeFile(commitPath, fullCommitContent);
1104
- }
1603
+ await fs.writeFile(commitPath, fullCommitContent);
1604
+ }
1105
1605
 
1106
- // Ensure AGENTS.md exists in steering directory (create from CLAUDE.md if available)
1107
- const agentsPath = path.join(steeringPath, 'AGENTS.md');
1108
- const claudePath = path.join(currentPath, 'CLAUDE.md');
1109
- const agentsExists = await fs.access(agentsPath).then(() => true).catch(() => false);
1110
- if (!agentsExists) {
1111
- let agentsContent = '';
1112
- const claudeExists = await fs.access(claudePath).then(() => true).catch(() => false);
1113
- if (claudeExists) {
1114
- const claude = await fs.readFile(claudePath, 'utf8');
1115
- agentsContent = claude
1116
- .replace(/# Claude Code Spec-Driven Development/g, '# AI Agent Spec-Driven Development')
1117
- .replace(/Claude Code/g, 'AI Agent')
1118
- .replace(/claude code/g, 'ai agent')
1119
- .replace(/\.claude\//g, '.ai agent/')
1120
- .replace(/\/claude/g, '/agent');
1121
- } else {
1122
- agentsContent = `# AI Agent Spec-Driven Development
1606
+ // Ensure AGENTS.md exists in steering directory (create from CLAUDE.md if available)
1607
+ const agentsPath = path.join(steeringPath, "AGENTS.md");
1608
+ const claudePath = path.join(currentPath, "CLAUDE.md");
1609
+ const agentsExists = await fs
1610
+ .access(agentsPath)
1611
+ .then(() => true)
1612
+ .catch(() => false);
1613
+ if (!agentsExists) {
1614
+ let agentsContent = "";
1615
+ const claudeExists = await fs
1616
+ .access(claudePath)
1617
+ .then(() => true)
1618
+ .catch(() => false);
1619
+ if (claudeExists) {
1620
+ const claude = await fs.readFile(claudePath, "utf8");
1621
+ agentsContent = claude
1622
+ .replace(
1623
+ /# Claude Code Spec-Driven Development/g,
1624
+ "# AI Agent Spec-Driven Development",
1625
+ )
1626
+ .replace(/Claude Code/g, "AI Agent")
1627
+ .replace(/claude code/g, "ai agent")
1628
+ .replace(/\.claude\//g, ".ai agent/")
1629
+ .replace(/\/claude/g, "/agent");
1630
+ } else {
1631
+ agentsContent = `# AI Agent Spec-Driven Development
1123
1632
 
1124
1633
  Kiro-style Spec Driven Development implementation using ai agent slash commands, hooks and agents.
1125
1634
 
@@ -1195,15 +1704,18 @@ Managed by \`/kiro:steering\` command. Updates here reflect command changes.
1195
1704
  - **Always**: Loaded in every interaction (default)
1196
1705
  - **Conditional**: Loaded for specific file patterns (e.g., "*.test.js")
1197
1706
  - **Manual**: Reference with \`@filename.md\` syntax`;
1707
+ }
1708
+ await fs.writeFile(agentsPath, agentsContent);
1198
1709
  }
1199
- await fs.writeFile(agentsPath, agentsContent);
1200
- }
1201
1710
 
1202
- // Ensure security-check.md exists (static)
1203
- const securityPath = path.join(steeringPath, 'security-check.md');
1204
- const securityExists = await fs.access(securityPath).then(() => true).catch(() => false);
1205
- if (!securityExists) {
1206
- const securityContent = `# Security Check (OWASP Top 10 Aligned)
1711
+ // Ensure security-check.md exists (static)
1712
+ const securityPath = path.join(steeringPath, "security-check.md");
1713
+ const securityExists = await fs
1714
+ .access(securityPath)
1715
+ .then(() => true)
1716
+ .catch(() => false);
1717
+ if (!securityExists) {
1718
+ const securityContent = `# Security Check (OWASP Top 10 Aligned)
1207
1719
 
1208
1720
  Use this checklist during code generation and review. Avoid OWASP Top 10 issues by design.
1209
1721
 
@@ -1253,13 +1765,16 @@ Use this checklist during code generation and review. Avoid OWASP Top 10 issues
1253
1765
  - Use content security best practices for templates/HTML
1254
1766
  - Add security tests where feasible (authz, input validation)
1255
1767
  `;
1256
- await fs.writeFile(securityPath, securityContent);
1257
- }
1768
+ await fs.writeFile(securityPath, securityContent);
1769
+ }
1258
1770
 
1259
- const tddPath = path.join(steeringPath, 'tdd-guideline.md');
1260
- const tddExists = await fs.access(tddPath).then(() => true).catch(() => false);
1261
- if (!tddExists) {
1262
- const tddContent = `# Test-Driven Development (TDD) Guideline
1771
+ const tddPath = path.join(steeringPath, "tdd-guideline.md");
1772
+ const tddExists = await fs
1773
+ .access(tddPath)
1774
+ .then(() => true)
1775
+ .catch(() => false);
1776
+ if (!tddExists) {
1777
+ const tddContent = `# Test-Driven Development (TDD) Guideline
1263
1778
 
1264
1779
  ## Purpose
1265
1780
  This steering document defines TDD practices and workflow to ensure test-first development throughout the project lifecycle.
@@ -1503,13 +2018,16 @@ npm test path/to/test.test.ts
1503
2018
  ## Enforcement
1504
2019
  This document is **always** active and applies to all development phases. Every code change should follow TDD principles as defined here.
1505
2020
  `;
1506
- await fs.writeFile(tddPath, tddContent);
1507
- }
2021
+ await fs.writeFile(tddPath, tddContent);
2022
+ }
1508
2023
 
1509
- const principlesPath = path.join(steeringPath, 'principles.md');
1510
- const principlesExists = await fs.access(principlesPath).then(() => true).catch(() => false);
1511
- if (!principlesExists) {
1512
- const principlesContent = `# Core Coding Principles and Patterns
2024
+ const principlesPath = path.join(steeringPath, "principles.md");
2025
+ const principlesExists = await fs
2026
+ .access(principlesPath)
2027
+ .then(() => true)
2028
+ .catch(() => false);
2029
+ if (!principlesExists) {
2030
+ const principlesContent = `# Core Coding Principles and Patterns
1513
2031
 
1514
2032
  Follow SOLID, DRY, KISS, YAGNI, Separation of Concerns, and Modularity in all code.
1515
2033
 
@@ -1547,15 +2065,16 @@ High cohesion, low coupling. Encapsulate implementation details.
1547
2065
 
1548
2066
  Refer to full principles.md for detailed examples and language-specific guidance.
1549
2067
  `;
1550
- await fs.writeFile(principlesPath, principlesContent);
1551
- }
1552
-
1553
- const mode = updateMode === 'update' ? 'Updated' : 'Created';
1554
-
1555
- return {
1556
- content: [{
1557
- type: 'text',
1558
- text: `## Steering Documents ${mode}
2068
+ await fs.writeFile(principlesPath, principlesContent);
2069
+ }
2070
+
2071
+ const mode = updateMode === "update" ? "Updated" : "Created";
2072
+
2073
+ return {
2074
+ content: [
2075
+ {
2076
+ type: "text",
2077
+ text: `## Steering Documents ${mode}
1559
2078
 
1560
2079
  **Project Path**: ${currentPath}
1561
2080
  **Mode**: ${updateMode}
@@ -1584,66 +2103,88 @@ The steering documents now contain analysis instructions for AI agents rather th
1584
2103
  3. Content will be tailored to your specific technology stack and architecture
1585
2104
  4. Documents will provide accurate, up-to-date guidance for development
1586
2105
 
1587
- These steering documents provide instructions for AI agents to analyze your project and generate appropriate guidance, eliminating the language-dependency issues of template-based approaches.`
1588
- }]
1589
- };
1590
- } catch (error) {
1591
- return {
1592
- content: [{
1593
- type: 'text',
1594
- text: `Error creating/updating steering documents: ${error.message}`
1595
- }]
1596
- };
1597
- }
1598
- });
2106
+ These steering documents provide instructions for AI agents to analyze your project and generate appropriate guidance, eliminating the language-dependency issues of template-based approaches.`,
2107
+ },
2108
+ ],
2109
+ };
2110
+ } catch (error) {
2111
+ return {
2112
+ content: [
2113
+ {
2114
+ type: "text",
2115
+ text: `Error creating/updating steering documents: ${error.message}`,
2116
+ },
2117
+ ],
2118
+ };
2119
+ }
2120
+ },
2121
+ );
1599
2122
 
1600
2123
  // 12. sdd-steering-custom - Create custom steering documents
1601
- server.registerTool("sdd-steering-custom", {
1602
- title: "Create Custom Steering Document",
1603
- description: "Create custom steering documents",
1604
- inputSchema: {
1605
- fileName: z.string().describe('Filename for the custom steering document (e.g., "api-standards.md")'),
1606
- topic: z.string().describe('Topic/purpose of the custom steering document'),
1607
- inclusionMode: z.enum(['always', 'conditional', 'manual']).describe('How this steering document should be included'),
1608
- filePattern: z.string().optional().describe('File pattern for conditional inclusion (e.g., "*.test.js", "src/api/**/*")')
2124
+ server.registerTool(
2125
+ "sdd-steering-custom",
2126
+ {
2127
+ title: "Create Custom Steering Document",
2128
+ description: "Create custom steering documents",
2129
+ inputSchema: {
2130
+ fileName: z
2131
+ .string()
2132
+ .describe(
2133
+ 'Filename for the custom steering document (e.g., "api-standards.md")',
2134
+ ),
2135
+ topic: z
2136
+ .string()
2137
+ .describe("Topic/purpose of the custom steering document"),
2138
+ inclusionMode: z
2139
+ .enum(["always", "conditional", "manual"])
2140
+ .describe("How this steering document should be included"),
2141
+ filePattern: z
2142
+ .string()
2143
+ .optional()
2144
+ .describe(
2145
+ 'File pattern for conditional inclusion (e.g., "*.test.js", "src/api/**/*")',
2146
+ ),
2147
+ },
1609
2148
  },
1610
- }, async ({ fileName, topic, inclusionMode, filePattern }) => {
1611
- try {
1612
- const currentPath = process.cwd();
1613
- const steeringPath = path.join(currentPath, '.kiro', 'steering');
1614
-
1615
- // Create steering directory if it doesn't exist
1616
- await fs.mkdir(steeringPath, { recursive: true });
1617
-
1618
- // Ensure filename ends with .md
1619
- if (!fileName.endsWith('.md')) {
1620
- fileName += '.md';
1621
- }
1622
-
1623
- // Generate inclusion mode comment
1624
- let inclusionComment = '<!-- Inclusion Mode: ';
1625
- if (inclusionMode === 'always') {
1626
- inclusionComment += 'Always -->';
1627
- } else if (inclusionMode === 'conditional') {
1628
- inclusionComment += `Conditional: "${filePattern || '**/*'}" -->`;
1629
- } else {
1630
- inclusionComment += 'Manual -->';
1631
- }
1632
-
1633
- // Generate content based on topic
1634
- let content = `${inclusionComment}
1635
-
2149
+ async ({ fileName, topic, inclusionMode, filePattern }) => {
2150
+ try {
2151
+ const currentPath = process.cwd();
2152
+ const steeringPath = path.join(currentPath, ".kiro", "steering");
2153
+
2154
+ // Create steering directory if it doesn't exist
2155
+ await fs.mkdir(steeringPath, { recursive: true });
2156
+
2157
+ // Ensure filename ends with .md
2158
+ if (!fileName.endsWith(".md")) {
2159
+ fileName += ".md";
2160
+ }
2161
+
2162
+ // Generate inclusion mode comment
2163
+ let inclusionComment = "<!-- Inclusion Mode: ";
2164
+ if (inclusionMode === "always") {
2165
+ inclusionComment += "Always -->";
2166
+ } else if (inclusionMode === "conditional") {
2167
+ inclusionComment += `Conditional: "${filePattern || "**/*"}" -->`;
2168
+ } else {
2169
+ inclusionComment += "Manual -->";
2170
+ }
2171
+
2172
+ // Generate content based on topic
2173
+ let content = `${inclusionComment}
2174
+
1636
2175
  # ${topic}
1637
2176
 
1638
2177
  ## Purpose
1639
2178
  This document provides specialized guidance for ${topic.toLowerCase()} within the project context.
1640
2179
 
1641
2180
  ## When This Document Applies
1642
- ${inclusionMode === 'conditional' ?
1643
- `This guidance applies when working with files matching: \`${filePattern || '**/*'}\`` :
1644
- inclusionMode === 'always' ?
1645
- 'This guidance applies to all development work in this project.' :
1646
- 'Reference this document manually using @${fileName} when needed.'}
2181
+ ${
2182
+ inclusionMode === "conditional"
2183
+ ? `This guidance applies when working with files matching: \`${filePattern || "**/*"}\``
2184
+ : inclusionMode === "always"
2185
+ ? "This guidance applies to all development work in this project."
2186
+ : "Reference this document manually using @${fileName} when needed."
2187
+ }
1647
2188
 
1648
2189
  ## Guidelines
1649
2190
 
@@ -1679,545 +2220,666 @@ ${inclusionMode === 'conditional' ?
1679
2220
  - [Testing requirements]
1680
2221
  - [Review checklist items]`;
1681
2222
 
1682
- const filePath = path.join(steeringPath, fileName);
1683
- await fs.writeFile(filePath, content);
1684
-
1685
- return {
1686
- content: [{
1687
- type: 'text',
1688
- text: `## Custom Steering Document Created
2223
+ const filePath = path.join(steeringPath, fileName);
2224
+ await fs.writeFile(filePath, content);
2225
+
2226
+ return {
2227
+ content: [
2228
+ {
2229
+ type: "text",
2230
+ text: `## Custom Steering Document Created
1689
2231
 
1690
2232
  **File**: .kiro/steering/${fileName}
1691
2233
  **Topic**: ${topic}
1692
- **Inclusion Mode**: ${inclusionMode}${inclusionMode === 'conditional' ? ` (Pattern: "${filePattern}")` : ''}
2234
+ **Inclusion Mode**: ${inclusionMode}${inclusionMode === "conditional" ? ` (Pattern: "${filePattern}")` : ""}
1693
2235
 
1694
2236
  **Created**: Custom steering document with template structure
1695
2237
  **Usage**: ${
1696
- inclusionMode === 'always' ? 'Will be loaded in all AI interactions' :
1697
- inclusionMode === 'conditional' ? `Will be loaded when working with files matching "${filePattern}"` :
1698
- `Reference manually with @${fileName} when needed`
1699
- }
1700
-
1701
- The document has been created with a standard template structure. Edit the file to add your specific guidelines, examples, and best practices for ${topic.toLowerCase()}.`
1702
- }]
1703
- };
1704
- } catch (error) {
1705
- return {
1706
- content: [{
1707
- type: 'text',
1708
- text: `Error creating custom steering document: ${error.message}`
1709
- }]
1710
- };
1711
- }
1712
- });
2238
+ inclusionMode === "always"
2239
+ ? "Will be loaded in all AI interactions"
2240
+ : inclusionMode === "conditional"
2241
+ ? `Will be loaded when working with files matching "${filePattern}"`
2242
+ : `Reference manually with @${fileName} when needed`
2243
+ }
2244
+
2245
+ The document has been created with a standard template structure. Edit the file to add your specific guidelines, examples, and best practices for ${topic.toLowerCase()}.`,
2246
+ },
2247
+ ],
2248
+ };
2249
+ } catch (error) {
2250
+ return {
2251
+ content: [
2252
+ {
2253
+ type: "text",
2254
+ text: `Error creating custom steering document: ${error.message}`,
2255
+ },
2256
+ ],
2257
+ };
2258
+ }
2259
+ },
2260
+ );
1713
2261
 
1714
2262
  // 13. sdd-validate-design - Interactive design quality review
1715
- server.registerTool("sdd-validate-design", {
1716
- title: "Validate Design Quality",
1717
- description: "Interactive design quality review and validation",
1718
- inputSchema: {
1719
- featureName: z.string().describe('Feature name to validate design for')
2263
+ server.registerTool(
2264
+ "sdd-validate-design",
2265
+ {
2266
+ title: "Validate Design Quality",
2267
+ description: "Interactive design quality review and validation",
2268
+ inputSchema: {
2269
+ featureName: z.string().describe("Feature name to validate design for"),
2270
+ },
1720
2271
  },
1721
- }, async ({ featureName }) => {
1722
- try {
1723
- const currentPath = process.cwd();
1724
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
1725
- const designPath = path.join(featurePath, 'design.md');
1726
- const specPath = path.join(featurePath, 'spec.json');
1727
-
1728
- // Check if design document exists
1729
- const designExists = await fs.access(designPath).then(() => true).catch(() => false);
1730
- if (!designExists) {
2272
+ async ({ featureName }) => {
2273
+ try {
2274
+ const currentPath = process.cwd();
2275
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
2276
+ const designPath = path.join(featurePath, "design.md");
2277
+ const specPath = path.join(featurePath, "spec.json");
2278
+
2279
+ // Check if design document exists
2280
+ const designExists = await fs
2281
+ .access(designPath)
2282
+ .then(() => true)
2283
+ .catch(() => false);
2284
+ if (!designExists) {
2285
+ return {
2286
+ content: [
2287
+ {
2288
+ type: "text",
2289
+ text: `Error: Design document not found. Run \`sdd-design ${featureName}\` first to generate design document.`,
2290
+ },
2291
+ ],
2292
+ };
2293
+ }
2294
+
2295
+ // Load design and spec
2296
+ const designContent = await fs.readFile(designPath, "utf8");
2297
+ const specContent = await fs.readFile(specPath, "utf8");
2298
+ const spec = JSON.parse(specContent);
2299
+
2300
+ // Analyze design for critical issues
2301
+ const issues = [];
2302
+
2303
+ // Check for type safety (if TypeScript patterns detected)
2304
+ if (designContent.includes("any") || designContent.includes(": any")) {
2305
+ issues.push({
2306
+ title: "Type Safety Concern",
2307
+ concern: "Design mentions 'any' types which compromises type safety",
2308
+ impact: "Reduces code reliability and IDE support",
2309
+ suggestion:
2310
+ "Define explicit interfaces and types for all data structures",
2311
+ });
2312
+ }
2313
+
2314
+ // Check for architectural patterns
2315
+ if (
2316
+ !designContent.includes("Component") &&
2317
+ !designContent.includes("Service") &&
2318
+ !designContent.includes("Module")
2319
+ ) {
2320
+ issues.push({
2321
+ title: "Architecture Clarity",
2322
+ concern: "Design lacks clear component or service boundaries",
2323
+ impact: "May lead to monolithic or poorly organized code",
2324
+ suggestion:
2325
+ "Define clear components, services, or modules with specific responsibilities",
2326
+ });
2327
+ }
2328
+
2329
+ // Check for error handling
2330
+ if (
2331
+ !designContent.includes("error") &&
2332
+ !designContent.includes("Error")
2333
+ ) {
2334
+ issues.push({
2335
+ title: "Error Handling Strategy",
2336
+ concern: "Design doesn't address error handling patterns",
2337
+ impact: "Runtime errors may not be properly managed",
2338
+ suggestion:
2339
+ "Add comprehensive error handling strategy and exception management",
2340
+ });
2341
+ }
2342
+
2343
+ // Limit to 3 most critical issues
2344
+ const criticalIssues = issues.slice(0, 3);
2345
+
2346
+ // Identify design strengths
2347
+ const strengths = [];
2348
+ if (designContent.includes("mermaid") || designContent.includes("```")) {
2349
+ strengths.push("Visual documentation with diagrams and code examples");
2350
+ }
2351
+ if (
2352
+ designContent.includes("interface") ||
2353
+ designContent.includes("Interface")
2354
+ ) {
2355
+ strengths.push("Clear interface definitions and contracts");
2356
+ }
2357
+
2358
+ // Make GO/NO-GO decision
2359
+ const hasBlockingIssues =
2360
+ criticalIssues.length > 2 ||
2361
+ criticalIssues.some(
2362
+ (issue) =>
2363
+ issue.title.includes("Architecture") ||
2364
+ issue.title.includes("Type Safety"),
2365
+ );
2366
+
2367
+ const decision = hasBlockingIssues ? "NO-GO" : "GO";
2368
+ const nextStep =
2369
+ decision === "GO"
2370
+ ? `Run \`sdd-tasks ${featureName}\` to generate implementation tasks`
2371
+ : `Address critical issues in design document before proceeding`;
2372
+
2373
+ let report = `## Design Validation Review: ${featureName}\n\n`;
2374
+ report += `**Overall Assessment**: ${decision === "GO" ? "✅ Design ready for implementation" : "❌ Design needs revision"}\n\n`;
2375
+
2376
+ if (criticalIssues.length > 0) {
2377
+ report += `### Critical Issues (${criticalIssues.length})\n\n`;
2378
+ criticalIssues.forEach((issue, index) => {
2379
+ report += `🔴 **Critical Issue ${index + 1}**: ${issue.title}\n`;
2380
+ report += `**Concern**: ${issue.concern}\n`;
2381
+ report += `**Impact**: ${issue.impact}\n`;
2382
+ report += `**Suggestion**: ${issue.suggestion}\n\n`;
2383
+ });
2384
+ }
2385
+
2386
+ if (strengths.length > 0) {
2387
+ report += `### Design Strengths\n\n`;
2388
+ strengths.forEach((strength) => {
2389
+ report += `✅ ${strength}\n`;
2390
+ });
2391
+ report += `\n`;
2392
+ }
2393
+
2394
+ report += `### Final Assessment\n`;
2395
+ report += `**Decision**: ${decision}\n`;
2396
+ report += `**Rationale**: ${
2397
+ decision === "GO"
2398
+ ? "Design addresses core requirements with acceptable architectural approach and manageable risks."
2399
+ : "Critical architectural or technical issues need resolution before implementation can proceed safely."
2400
+ }\n`;
2401
+ report += `**Next Steps**: ${nextStep}\n\n`;
2402
+
2403
+ report += `### Interactive Discussion\n`;
2404
+ report += `Questions for design review:\n`;
2405
+ report += `1. Do you agree with the identified issues and their severity?\n`;
2406
+ report += `2. Are there alternative approaches to address the concerns?\n`;
2407
+ report += `3. What are your thoughts on the overall design complexity?\n`;
2408
+ report += `4. Are there any design decisions that need clarification?\n`;
2409
+
1731
2410
  return {
1732
- content: [{
1733
- type: 'text',
1734
- text: `Error: Design document not found. Run \`sdd-design ${featureName}\` first to generate design document.`
1735
- }]
2411
+ content: [
2412
+ {
2413
+ type: "text",
2414
+ text: report,
2415
+ },
2416
+ ],
2417
+ };
2418
+ } catch (error) {
2419
+ return {
2420
+ content: [
2421
+ {
2422
+ type: "text",
2423
+ text: `Error validating design: ${error.message}`,
2424
+ },
2425
+ ],
1736
2426
  };
1737
2427
  }
1738
-
1739
- // Load design and spec
1740
- const designContent = await fs.readFile(designPath, 'utf8');
1741
- const specContent = await fs.readFile(specPath, 'utf8');
1742
- const spec = JSON.parse(specContent);
1743
-
1744
- // Analyze design for critical issues
1745
- const issues = [];
1746
-
1747
- // Check for type safety (if TypeScript patterns detected)
1748
- if (designContent.includes('any') || designContent.includes(': any')) {
1749
- issues.push({
1750
- title: "Type Safety Concern",
1751
- concern: "Design mentions 'any' types which compromises type safety",
1752
- impact: "Reduces code reliability and IDE support",
1753
- suggestion: "Define explicit interfaces and types for all data structures"
1754
- });
1755
- }
1756
-
1757
- // Check for architectural patterns
1758
- if (!designContent.includes('Component') && !designContent.includes('Service') && !designContent.includes('Module')) {
1759
- issues.push({
1760
- title: "Architecture Clarity",
1761
- concern: "Design lacks clear component or service boundaries",
1762
- impact: "May lead to monolithic or poorly organized code",
1763
- suggestion: "Define clear components, services, or modules with specific responsibilities"
1764
- });
1765
- }
1766
-
1767
- // Check for error handling
1768
- if (!designContent.includes('error') && !designContent.includes('Error')) {
1769
- issues.push({
1770
- title: "Error Handling Strategy",
1771
- concern: "Design doesn't address error handling patterns",
1772
- impact: "Runtime errors may not be properly managed",
1773
- suggestion: "Add comprehensive error handling strategy and exception management"
1774
- });
1775
- }
1776
-
1777
- // Limit to 3 most critical issues
1778
- const criticalIssues = issues.slice(0, 3);
1779
-
1780
- // Identify design strengths
1781
- const strengths = [];
1782
- if (designContent.includes('mermaid') || designContent.includes('```')) {
1783
- strengths.push("Visual documentation with diagrams and code examples");
1784
- }
1785
- if (designContent.includes('interface') || designContent.includes('Interface')) {
1786
- strengths.push("Clear interface definitions and contracts");
1787
- }
1788
-
1789
- // Make GO/NO-GO decision
1790
- const hasBlockingIssues = criticalIssues.length > 2 ||
1791
- criticalIssues.some(issue => issue.title.includes('Architecture') || issue.title.includes('Type Safety'));
1792
-
1793
- const decision = hasBlockingIssues ? 'NO-GO' : 'GO';
1794
- const nextStep = decision === 'GO' ?
1795
- `Run \`sdd-tasks ${featureName}\` to generate implementation tasks` :
1796
- `Address critical issues in design document before proceeding`;
1797
-
1798
- let report = `## Design Validation Review: ${featureName}\n\n`;
1799
- report += `**Overall Assessment**: ${decision === 'GO' ? '✅ Design ready for implementation' : '❌ Design needs revision'}\n\n`;
1800
-
1801
- if (criticalIssues.length > 0) {
1802
- report += `### Critical Issues (${criticalIssues.length})\n\n`;
1803
- criticalIssues.forEach((issue, index) => {
1804
- report += `🔴 **Critical Issue ${index + 1}**: ${issue.title}\n`;
1805
- report += `**Concern**: ${issue.concern}\n`;
1806
- report += `**Impact**: ${issue.impact}\n`;
1807
- report += `**Suggestion**: ${issue.suggestion}\n\n`;
1808
- });
1809
- }
1810
-
1811
- if (strengths.length > 0) {
1812
- report += `### Design Strengths\n\n`;
1813
- strengths.forEach(strength => {
1814
- report += `✅ ${strength}\n`;
1815
- });
1816
- report += `\n`;
1817
- }
1818
-
1819
- report += `### Final Assessment\n`;
1820
- report += `**Decision**: ${decision}\n`;
1821
- report += `**Rationale**: ${
1822
- decision === 'GO' ?
1823
- 'Design addresses core requirements with acceptable architectural approach and manageable risks.' :
1824
- 'Critical architectural or technical issues need resolution before implementation can proceed safely.'
1825
- }\n`;
1826
- report += `**Next Steps**: ${nextStep}\n\n`;
1827
-
1828
- report += `### Interactive Discussion\n`;
1829
- report += `Questions for design review:\n`;
1830
- report += `1. Do you agree with the identified issues and their severity?\n`;
1831
- report += `2. Are there alternative approaches to address the concerns?\n`;
1832
- report += `3. What are your thoughts on the overall design complexity?\n`;
1833
- report += `4. Are there any design decisions that need clarification?\n`;
1834
-
1835
- return {
1836
- content: [{
1837
- type: 'text',
1838
- text: report
1839
- }]
1840
- };
1841
- } catch (error) {
1842
- return {
1843
- content: [{
1844
- type: 'text',
1845
- text: `Error validating design: ${error.message}`
1846
- }]
1847
- };
1848
- }
1849
- });
2428
+ },
2429
+ );
1850
2430
 
1851
2431
  // 14. sdd-validate-gap - Analyze implementation gap
1852
- server.registerTool("sdd-validate-gap", {
1853
- title: "Validate Implementation Gap",
1854
- description: "Analyze implementation gap between requirements and codebase",
1855
- inputSchema: {
1856
- featureName: z.string().describe('Feature name to analyze implementation gap for')
2432
+ server.registerTool(
2433
+ "sdd-validate-gap",
2434
+ {
2435
+ title: "Validate Implementation Gap",
2436
+ description: "Analyze implementation gap between requirements and codebase",
2437
+ inputSchema: {
2438
+ featureName: z
2439
+ .string()
2440
+ .describe("Feature name to analyze implementation gap for"),
2441
+ },
1857
2442
  },
1858
- }, async ({ featureName }) => {
1859
- try {
1860
- const currentPath = process.cwd();
1861
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
1862
- const requirementsPath = path.join(featurePath, 'requirements.md');
1863
- const specPath = path.join(featurePath, 'spec.json');
1864
-
1865
- // Check if requirements exist
1866
- const requirementsExist = await fs.access(requirementsPath).then(() => true).catch(() => false);
1867
- if (!requirementsExist) {
1868
- return {
1869
- content: [{
1870
- type: 'text',
1871
- text: `Error: Requirements document not found. Run \`sdd-requirements ${featureName}\` first to generate requirements.`
1872
- }]
2443
+ async ({ featureName }) => {
2444
+ try {
2445
+ const currentPath = process.cwd();
2446
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
2447
+ const requirementsPath = path.join(featurePath, "requirements.md");
2448
+ const specPath = path.join(featurePath, "spec.json");
2449
+
2450
+ // Check if requirements exist
2451
+ const requirementsExist = await fs
2452
+ .access(requirementsPath)
2453
+ .then(() => true)
2454
+ .catch(() => false);
2455
+ if (!requirementsExist) {
2456
+ return {
2457
+ content: [
2458
+ {
2459
+ type: "text",
2460
+ text: `Error: Requirements document not found. Run \`sdd-requirements ${featureName}\` first to generate requirements.`,
2461
+ },
2462
+ ],
2463
+ };
2464
+ }
2465
+
2466
+ // Load requirements and spec
2467
+ const requirementsContent = await fs.readFile(requirementsPath, "utf8");
2468
+ const specContent = await fs.readFile(specPath, "utf8");
2469
+ const spec = JSON.parse(specContent);
2470
+
2471
+ // Analyze current codebase
2472
+ const codebaseAnalysis = {
2473
+ hasPackageJson: await fs
2474
+ .access("package.json")
2475
+ .then(() => true)
2476
+ .catch(() => false),
2477
+ hasSourceCode: false,
2478
+ techStack: [],
2479
+ architecture: "Unknown",
1873
2480
  };
1874
- }
1875
-
1876
- // Load requirements and spec
1877
- const requirementsContent = await fs.readFile(requirementsPath, 'utf8');
1878
- const specContent = await fs.readFile(specPath, 'utf8');
1879
- const spec = JSON.parse(specContent);
1880
-
1881
- // Analyze current codebase
1882
- const codebaseAnalysis = {
1883
- hasPackageJson: await fs.access('package.json').then(() => true).catch(() => false),
1884
- hasSourceCode: false,
1885
- techStack: [],
1886
- architecture: 'Unknown'
1887
- };
1888
-
1889
- if (codebaseAnalysis.hasPackageJson) {
1890
- const packageContent = await fs.readFile('package.json', 'utf8');
1891
- const packageJson = JSON.parse(packageContent);
1892
- codebaseAnalysis.techStack = Object.keys(packageJson.dependencies || {});
1893
- codebaseAnalysis.architecture = 'Node.js Application';
1894
- }
1895
-
1896
- // Check for source directories
1897
- const srcExists = await fs.access('src').then(() => true).catch(() => false);
1898
- const libExists = await fs.access('lib').then(() => true).catch(() => false);
1899
- codebaseAnalysis.hasSourceCode = srcExists || libExists;
1900
-
1901
- // Extract requirements complexity
1902
- const requirements = requirementsContent.match(/WHEN|IF|WHILE|WHERE/g) || [];
1903
- const complexity = requirements.length > 10 ? 'XL' :
1904
- requirements.length > 6 ? 'L' :
1905
- requirements.length > 3 ? 'M' : 'S';
1906
-
1907
- // Identify gaps and implementation approaches
1908
- const gaps = [];
1909
- if (!codebaseAnalysis.hasSourceCode) {
1910
- gaps.push("No existing source code structure - requires full implementation from scratch");
1911
- }
1912
- if (!codebaseAnalysis.techStack.includes('@modelcontextprotocol/sdk')) {
1913
- gaps.push("MCP SDK integration required for AI tool compatibility");
1914
- }
1915
- if (requirementsContent.includes('database') || requirementsContent.includes('storage')) {
1916
- gaps.push("Data storage layer needs to be designed and implemented");
1917
- }
1918
-
1919
- // Implementation strategy options
1920
- const strategies = [
1921
- {
1922
- approach: "Extension",
1923
- rationale: codebaseAnalysis.hasSourceCode ?
1924
- "Extend existing codebase with new functionality" :
1925
- "Not applicable - no existing codebase to extend",
1926
- applicable: codebaseAnalysis.hasSourceCode,
1927
- complexity: codebaseAnalysis.hasSourceCode ? 'M' : 'N/A',
1928
- tradeoffs: codebaseAnalysis.hasSourceCode ?
1929
- "Pros: Maintains consistency, faster development. Cons: May introduce technical debt" :
1930
- "N/A"
1931
- },
1932
- {
1933
- approach: "New Implementation",
1934
- rationale: "Create new components following established patterns",
1935
- applicable: true,
1936
- complexity: complexity,
1937
- tradeoffs: "Pros: Clean architecture, full control. Cons: More development time, integration complexity"
1938
- },
1939
- {
1940
- approach: "Hybrid",
1941
- rationale: "Combine extension of existing components with new development where needed",
1942
- applicable: codebaseAnalysis.hasSourceCode,
1943
- complexity: codebaseAnalysis.hasSourceCode ? 'L' : 'M',
1944
- tradeoffs: "Pros: Balanced approach, optimal resource usage. Cons: Requires careful integration planning"
2481
+
2482
+ if (codebaseAnalysis.hasPackageJson) {
2483
+ const packageContent = await fs.readFile("package.json", "utf8");
2484
+ const packageJson = JSON.parse(packageContent);
2485
+ codebaseAnalysis.techStack = Object.keys(
2486
+ packageJson.dependencies || {},
2487
+ );
2488
+ codebaseAnalysis.architecture = "Node.js Application";
2489
+ }
2490
+
2491
+ // Check for source directories
2492
+ const srcExists = await fs
2493
+ .access("src")
2494
+ .then(() => true)
2495
+ .catch(() => false);
2496
+ const libExists = await fs
2497
+ .access("lib")
2498
+ .then(() => true)
2499
+ .catch(() => false);
2500
+ codebaseAnalysis.hasSourceCode = srcExists || libExists;
2501
+
2502
+ // Extract requirements complexity
2503
+ const requirements =
2504
+ requirementsContent.match(/WHEN|IF|WHILE|WHERE/g) || [];
2505
+ const complexity =
2506
+ requirements.length > 10
2507
+ ? "XL"
2508
+ : requirements.length > 6
2509
+ ? "L"
2510
+ : requirements.length > 3
2511
+ ? "M"
2512
+ : "S";
2513
+
2514
+ // Identify gaps and implementation approaches
2515
+ const gaps = [];
2516
+ if (!codebaseAnalysis.hasSourceCode) {
2517
+ gaps.push(
2518
+ "No existing source code structure - requires full implementation from scratch",
2519
+ );
2520
+ }
2521
+ if (!codebaseAnalysis.techStack.includes("@modelcontextprotocol/sdk")) {
2522
+ gaps.push("MCP SDK integration required for AI tool compatibility");
2523
+ }
2524
+ if (
2525
+ requirementsContent.includes("database") ||
2526
+ requirementsContent.includes("storage")
2527
+ ) {
2528
+ gaps.push("Data storage layer needs to be designed and implemented");
2529
+ }
2530
+
2531
+ // Implementation strategy options
2532
+ const strategies = [
2533
+ {
2534
+ approach: "Extension",
2535
+ rationale: codebaseAnalysis.hasSourceCode
2536
+ ? "Extend existing codebase with new functionality"
2537
+ : "Not applicable - no existing codebase to extend",
2538
+ applicable: codebaseAnalysis.hasSourceCode,
2539
+ complexity: codebaseAnalysis.hasSourceCode ? "M" : "N/A",
2540
+ tradeoffs: codebaseAnalysis.hasSourceCode
2541
+ ? "Pros: Maintains consistency, faster development. Cons: May introduce technical debt"
2542
+ : "N/A",
2543
+ },
2544
+ {
2545
+ approach: "New Implementation",
2546
+ rationale: "Create new components following established patterns",
2547
+ applicable: true,
2548
+ complexity: complexity,
2549
+ tradeoffs:
2550
+ "Pros: Clean architecture, full control. Cons: More development time, integration complexity",
2551
+ },
2552
+ {
2553
+ approach: "Hybrid",
2554
+ rationale:
2555
+ "Combine extension of existing components with new development where needed",
2556
+ applicable: codebaseAnalysis.hasSourceCode,
2557
+ complexity: codebaseAnalysis.hasSourceCode ? "L" : "M",
2558
+ tradeoffs:
2559
+ "Pros: Balanced approach, optimal resource usage. Cons: Requires careful integration planning",
2560
+ },
2561
+ ];
2562
+
2563
+ const applicableStrategies = strategies.filter((s) => s.applicable);
2564
+ const recommendedStrategy =
2565
+ applicableStrategies.find((s) => s.approach === "Hybrid") ||
2566
+ applicableStrategies.find((s) => s.approach === "New Implementation");
2567
+
2568
+ let report = `## Implementation Gap Analysis: ${featureName}\n\n`;
2569
+
2570
+ report += `### Analysis Summary\n`;
2571
+ report += `- **Feature Complexity**: ${complexity} (based on ${requirements.length} requirements)\n`;
2572
+ report += `- **Existing Codebase**: ${codebaseAnalysis.hasSourceCode ? "Source code detected" : "No source code structure"}\n`;
2573
+ report += `- **Technology Stack**: ${codebaseAnalysis.techStack.length} dependencies\n`;
2574
+ report += `- **Architecture Type**: ${codebaseAnalysis.architecture}\n\n`;
2575
+
2576
+ report += `### Existing Codebase Insights\n`;
2577
+ report += `- **Package Management**: ${codebaseAnalysis.hasPackageJson ? "npm/package.json configured" : "No package.json found"}\n`;
2578
+ report += `- **Source Structure**: ${codebaseAnalysis.hasSourceCode ? "Established source directories" : "No conventional source structure"}\n`;
2579
+ report += `- **Key Dependencies**: ${codebaseAnalysis.techStack.slice(0, 5).join(", ") || "None detected"}\n\n`;
2580
+
2581
+ if (gaps.length > 0) {
2582
+ report += `### Implementation Gaps Identified\n`;
2583
+ gaps.forEach((gap) => (report += `- ${gap}\n`));
2584
+ report += `\n`;
2585
+ }
2586
+
2587
+ report += `### Implementation Strategy Options\n\n`;
2588
+ applicableStrategies.forEach((strategy) => {
2589
+ report += `**${strategy.approach} Approach**:\n`;
2590
+ report += `- **Rationale**: ${strategy.rationale}\n`;
2591
+ report += `- **Complexity**: ${strategy.complexity}\n`;
2592
+ report += `- **Trade-offs**: ${strategy.tradeoffs}\n\n`;
2593
+ });
2594
+
2595
+ report += `### Technical Research Needs\n`;
2596
+ const researchNeeds = [];
2597
+ if (!codebaseAnalysis.techStack.includes("@modelcontextprotocol/sdk")) {
2598
+ researchNeeds.push("MCP SDK integration patterns and best practices");
2599
+ }
2600
+ if (
2601
+ requirementsContent.includes("template") ||
2602
+ requirementsContent.includes("generation")
2603
+ ) {
2604
+ researchNeeds.push("Template engine selection and implementation");
2605
+ }
2606
+ if (
2607
+ requirementsContent.includes("workflow") ||
2608
+ requirementsContent.includes("state")
2609
+ ) {
2610
+ researchNeeds.push("State machine or workflow engine patterns");
2611
+ }
2612
+
2613
+ if (researchNeeds.length > 0) {
2614
+ researchNeeds.forEach((need) => (report += `- ${need}\n`));
2615
+ } else {
2616
+ report += `- No significant research dependencies identified\n`;
1945
2617
  }
1946
- ];
1947
-
1948
- const applicableStrategies = strategies.filter(s => s.applicable);
1949
- const recommendedStrategy = applicableStrategies.find(s => s.approach === 'Hybrid') ||
1950
- applicableStrategies.find(s => s.approach === 'New Implementation');
1951
-
1952
- let report = `## Implementation Gap Analysis: ${featureName}\n\n`;
1953
-
1954
- report += `### Analysis Summary\n`;
1955
- report += `- **Feature Complexity**: ${complexity} (based on ${requirements.length} requirements)\n`;
1956
- report += `- **Existing Codebase**: ${codebaseAnalysis.hasSourceCode ? 'Source code detected' : 'No source code structure'}\n`;
1957
- report += `- **Technology Stack**: ${codebaseAnalysis.techStack.length} dependencies\n`;
1958
- report += `- **Architecture Type**: ${codebaseAnalysis.architecture}\n\n`;
1959
-
1960
- report += `### Existing Codebase Insights\n`;
1961
- report += `- **Package Management**: ${codebaseAnalysis.hasPackageJson ? 'npm/package.json configured' : 'No package.json found'}\n`;
1962
- report += `- **Source Structure**: ${codebaseAnalysis.hasSourceCode ? 'Established source directories' : 'No conventional source structure'}\n`;
1963
- report += `- **Key Dependencies**: ${codebaseAnalysis.techStack.slice(0, 5).join(', ') || 'None detected'}\n\n`;
1964
-
1965
- if (gaps.length > 0) {
1966
- report += `### Implementation Gaps Identified\n`;
1967
- gaps.forEach(gap => report += `- ${gap}\n`);
1968
2618
  report += `\n`;
2619
+
2620
+ report += `### Recommendations for Design Phase\n`;
2621
+ report += `- **Preferred Approach**: ${recommendedStrategy.approach} (${recommendedStrategy.complexity} complexity)\n`;
2622
+ report += `- **Key Decisions**: Architecture patterns, technology integration, component boundaries\n`;
2623
+ report += `- **Risk Mitigation**: ${complexity === "XL" || complexity === "L" ? "Consider phased implementation approach" : "Standard development approach acceptable"}\n`;
2624
+ report += `- **Next Step**: Use this analysis to inform technical design decisions\n`;
2625
+
2626
+ return {
2627
+ content: [
2628
+ {
2629
+ type: "text",
2630
+ text: report,
2631
+ },
2632
+ ],
2633
+ };
2634
+ } catch (error) {
2635
+ return {
2636
+ content: [
2637
+ {
2638
+ type: "text",
2639
+ text: `Error analyzing implementation gap: ${error.message}`,
2640
+ },
2641
+ ],
2642
+ };
1969
2643
  }
1970
-
1971
- report += `### Implementation Strategy Options\n\n`;
1972
- applicableStrategies.forEach(strategy => {
1973
- report += `**${strategy.approach} Approach**:\n`;
1974
- report += `- **Rationale**: ${strategy.rationale}\n`;
1975
- report += `- **Complexity**: ${strategy.complexity}\n`;
1976
- report += `- **Trade-offs**: ${strategy.tradeoffs}\n\n`;
1977
- });
1978
-
1979
- report += `### Technical Research Needs\n`;
1980
- const researchNeeds = [];
1981
- if (!codebaseAnalysis.techStack.includes('@modelcontextprotocol/sdk')) {
1982
- researchNeeds.push("MCP SDK integration patterns and best practices");
1983
- }
1984
- if (requirementsContent.includes('template') || requirementsContent.includes('generation')) {
1985
- researchNeeds.push("Template engine selection and implementation");
1986
- }
1987
- if (requirementsContent.includes('workflow') || requirementsContent.includes('state')) {
1988
- researchNeeds.push("State machine or workflow engine patterns");
1989
- }
1990
-
1991
- if (researchNeeds.length > 0) {
1992
- researchNeeds.forEach(need => report += `- ${need}\n`);
1993
- } else {
1994
- report += `- No significant research dependencies identified\n`;
1995
- }
1996
- report += `\n`;
1997
-
1998
- report += `### Recommendations for Design Phase\n`;
1999
- report += `- **Preferred Approach**: ${recommendedStrategy.approach} (${recommendedStrategy.complexity} complexity)\n`;
2000
- report += `- **Key Decisions**: Architecture patterns, technology integration, component boundaries\n`;
2001
- report += `- **Risk Mitigation**: ${complexity === 'XL' || complexity === 'L' ? 'Consider phased implementation approach' : 'Standard development approach acceptable'}\n`;
2002
- report += `- **Next Step**: Use this analysis to inform technical design decisions\n`;
2003
-
2004
- return {
2005
- content: [{
2006
- type: 'text',
2007
- text: report
2008
- }]
2009
- };
2010
- } catch (error) {
2011
- return {
2012
- content: [{
2013
- type: 'text',
2014
- text: `Error analyzing implementation gap: ${error.message}`
2015
- }]
2016
- };
2017
- }
2018
- });
2644
+ },
2645
+ );
2019
2646
 
2020
2647
  // 15. sdd-spec-impl - Execute spec tasks using TDD
2021
- server.registerTool("sdd-spec-impl", {
2022
- title: "Execute Spec Tasks with TDD",
2023
- description: "Execute spec tasks using TDD methodology",
2024
- inputSchema: {
2025
- featureName: z.string().describe('Feature name to execute tasks for'),
2026
- taskNumbers: z.string().optional().describe('Specific task numbers to execute (e.g., "1.1,2.3" or leave empty for all pending)')
2648
+ server.registerTool(
2649
+ "sdd-spec-impl",
2650
+ {
2651
+ title: "Execute Spec Tasks with TDD",
2652
+ description: "Execute spec tasks using TDD methodology",
2653
+ inputSchema: {
2654
+ featureName: z.string().describe("Feature name to execute tasks for"),
2655
+ taskNumbers: z
2656
+ .string()
2657
+ .optional()
2658
+ .describe(
2659
+ 'Specific task numbers to execute (e.g., "1.1,2.3" or leave empty for all pending)',
2660
+ ),
2661
+ },
2027
2662
  },
2028
- }, async ({ featureName, taskNumbers }) => {
2029
- try {
2030
- const currentPath = process.cwd();
2031
- const featurePath = path.join(currentPath, '.kiro', 'specs', featureName);
2032
- const tasksPath = path.join(featurePath, 'tasks.md');
2033
- const requirementsPath = path.join(featurePath, 'requirements.md');
2034
- const designPath = path.join(featurePath, 'design.md');
2035
- const specPath = path.join(featurePath, 'spec.json');
2036
-
2037
- // Validate required files exist
2038
- const requiredFiles = [
2039
- { path: requirementsPath, name: 'requirements.md' },
2040
- { path: designPath, name: 'design.md' },
2041
- { path: tasksPath, name: 'tasks.md' },
2042
- { path: specPath, name: 'spec.json' }
2043
- ];
2044
-
2045
- for (const file of requiredFiles) {
2046
- const exists = await fs.access(file.path).then(() => true).catch(() => false);
2047
- if (!exists) {
2048
- return {
2049
- content: [{
2050
- type: 'text',
2051
- text: `Error: Required file ${file.name} not found. Complete the full spec workflow first:\n1. sdd-requirements ${featureName}\n2. sdd-design ${featureName}\n3. sdd-tasks ${featureName}`
2052
- }]
2053
- };
2054
- }
2055
- }
2056
-
2057
- // Load all context documents
2058
- const tasksContent = await fs.readFile(tasksPath, 'utf8');
2059
- const specContent = await fs.readFile(specPath, 'utf8');
2060
- const spec = JSON.parse(specContent);
2061
-
2062
- // Parse tasks to find pending ones
2063
- const taskLines = tasksContent.split('\n');
2064
- const tasks = [];
2065
- let currentMajorTask = null;
2066
-
2067
- for (let i = 0; i < taskLines.length; i++) {
2068
- const line = taskLines[i].trim();
2069
-
2070
- // Match major tasks (- [ ] 1. Task name)
2071
- const majorMatch = line.match(/^- \[([ x])\] (\d+)\. (.+)$/);
2072
- if (majorMatch) {
2073
- currentMajorTask = {
2074
- number: majorMatch[2],
2075
- description: majorMatch[3],
2076
- completed: majorMatch[1] === 'x',
2077
- subtasks: []
2078
- };
2079
- tasks.push(currentMajorTask);
2080
- continue;
2081
- }
2082
-
2083
- // Match sub-tasks (- [ ] 1.1 Subtask name)
2084
- const subMatch = line.match(/^- \[([ x])\] (\d+\.\d+) (.+)$/);
2085
- if (subMatch && currentMajorTask) {
2086
- currentMajorTask.subtasks.push({
2087
- number: subMatch[2],
2088
- description: subMatch[3],
2089
- completed: subMatch[1] === 'x'
2090
- });
2663
+ async ({ featureName, taskNumbers }) => {
2664
+ try {
2665
+ const currentPath = process.cwd();
2666
+ const featurePath = path.join(currentPath, ".kiro", "specs", featureName);
2667
+ const tasksPath = path.join(featurePath, "tasks.md");
2668
+ const requirementsPath = path.join(featurePath, "requirements.md");
2669
+ const designPath = path.join(featurePath, "design.md");
2670
+ const specPath = path.join(featurePath, "spec.json");
2671
+
2672
+ // Validate required files exist
2673
+ const requiredFiles = [
2674
+ { path: requirementsPath, name: "requirements.md" },
2675
+ { path: designPath, name: "design.md" },
2676
+ { path: tasksPath, name: "tasks.md" },
2677
+ { path: specPath, name: "spec.json" },
2678
+ ];
2679
+
2680
+ for (const file of requiredFiles) {
2681
+ const exists = await fs
2682
+ .access(file.path)
2683
+ .then(() => true)
2684
+ .catch(() => false);
2685
+ if (!exists) {
2686
+ return {
2687
+ content: [
2688
+ {
2689
+ type: "text",
2690
+ text: `Error: Required file ${file.name} not found. Complete the full spec workflow first:\n1. sdd-requirements ${featureName}\n2. sdd-design ${featureName}\n3. sdd-tasks ${featureName}`,
2691
+ },
2692
+ ],
2693
+ };
2694
+ }
2091
2695
  }
2092
- }
2093
-
2094
- // Filter tasks based on taskNumbers parameter
2095
- let tasksToExecute = [];
2096
- if (taskNumbers) {
2097
- const requestedNumbers = taskNumbers.split(',').map(n => n.trim());
2098
- for (const task of tasks) {
2099
- if (requestedNumbers.includes(task.number) && !task.completed) {
2100
- tasksToExecute.push({ type: 'major', task });
2696
+
2697
+ // Load all context documents
2698
+ const tasksContent = await fs.readFile(tasksPath, "utf8");
2699
+ const specContent = await fs.readFile(specPath, "utf8");
2700
+ const spec = JSON.parse(specContent);
2701
+
2702
+ // Parse tasks to find pending ones
2703
+ const taskLines = tasksContent.split("\n");
2704
+ const tasks = [];
2705
+ let currentMajorTask = null;
2706
+
2707
+ for (let i = 0; i < taskLines.length; i++) {
2708
+ const line = taskLines[i].trim();
2709
+
2710
+ // Match major tasks (- [ ] 1. Task name)
2711
+ const majorMatch = line.match(/^- \[([ x])\] (\d+)\. (.+)$/);
2712
+ if (majorMatch) {
2713
+ currentMajorTask = {
2714
+ number: majorMatch[2],
2715
+ description: majorMatch[3],
2716
+ completed: majorMatch[1] === "x",
2717
+ subtasks: [],
2718
+ };
2719
+ tasks.push(currentMajorTask);
2720
+ continue;
2101
2721
  }
2102
- for (const subtask of task.subtasks) {
2103
- if (requestedNumbers.includes(subtask.number) && !subtask.completed) {
2104
- tasksToExecute.push({ type: 'subtask', task: subtask, parent: task });
2105
- }
2722
+
2723
+ // Match sub-tasks (- [ ] 1.1 Subtask name)
2724
+ const subMatch = line.match(/^- \[([ x])\] (\d+\.\d+) (.+)$/);
2725
+ if (subMatch && currentMajorTask) {
2726
+ currentMajorTask.subtasks.push({
2727
+ number: subMatch[2],
2728
+ description: subMatch[3],
2729
+ completed: subMatch[1] === "x",
2730
+ });
2106
2731
  }
2107
2732
  }
2108
- } else {
2109
- // Get all pending tasks
2110
- for (const task of tasks) {
2111
- if (!task.completed) {
2112
- tasksToExecute.push({ type: 'major', task });
2733
+
2734
+ // Filter tasks based on taskNumbers parameter
2735
+ let tasksToExecute = [];
2736
+ if (taskNumbers) {
2737
+ const requestedNumbers = taskNumbers.split(",").map((n) => n.trim());
2738
+ for (const task of tasks) {
2739
+ if (requestedNumbers.includes(task.number) && !task.completed) {
2740
+ tasksToExecute.push({ type: "major", task });
2741
+ }
2742
+ for (const subtask of task.subtasks) {
2743
+ if (
2744
+ requestedNumbers.includes(subtask.number) &&
2745
+ !subtask.completed
2746
+ ) {
2747
+ tasksToExecute.push({
2748
+ type: "subtask",
2749
+ task: subtask,
2750
+ parent: task,
2751
+ });
2752
+ }
2753
+ }
2113
2754
  }
2114
- for (const subtask of task.subtasks) {
2115
- if (!subtask.completed) {
2116
- tasksToExecute.push({ type: 'subtask', task: subtask, parent: task });
2755
+ } else {
2756
+ // Get all pending tasks
2757
+ for (const task of tasks) {
2758
+ if (!task.completed) {
2759
+ tasksToExecute.push({ type: "major", task });
2760
+ }
2761
+ for (const subtask of task.subtasks) {
2762
+ if (!subtask.completed) {
2763
+ tasksToExecute.push({
2764
+ type: "subtask",
2765
+ task: subtask,
2766
+ parent: task,
2767
+ });
2768
+ }
2117
2769
  }
2118
2770
  }
2119
2771
  }
2120
- }
2121
-
2122
- if (tasksToExecute.length === 0) {
2772
+
2773
+ if (tasksToExecute.length === 0) {
2774
+ return {
2775
+ content: [
2776
+ {
2777
+ type: "text",
2778
+ text: `## No Pending Tasks Found\n\n**Feature**: ${featureName}\n**Status**: ${taskNumbers ? "Specified tasks already completed or not found" : "All tasks already completed"}\n\n${taskNumbers ? `**Requested**: ${taskNumbers}` : "**All tasks**: ✅ Completed"}\n\nUse \`sdd-status ${featureName}\` to check current progress.`,
2779
+ },
2780
+ ],
2781
+ };
2782
+ }
2783
+
2784
+ // Generate TDD implementation guidance for the tasks
2785
+ let report = `## TDD Implementation Execution: ${featureName}\n\n`;
2786
+ report += `**Tasks to Execute**: ${tasksToExecute.length} pending tasks\n`;
2787
+ report += `**TDD Methodology**: Kent Beck's Red → Green → Refactor cycle\n\n`;
2788
+
2789
+ report += `### Context Loaded\n`;
2790
+ report += `- ✅ Requirements: .kiro/specs/${featureName}/requirements.md\n`;
2791
+ report += `- ✅ Design: .kiro/specs/${featureName}/design.md\n`;
2792
+ report += `- ✅ Tasks: .kiro/specs/${featureName}/tasks.md\n`;
2793
+ report += `- ✅ Metadata: .kiro/specs/${featureName}/spec.json\n\n`;
2794
+
2795
+ report += `### TDD Implementation Plan\n\n`;
2796
+
2797
+ tasksToExecute.slice(0, 5).forEach((item, index) => {
2798
+ const task = item.task;
2799
+ const taskNumber = item.type === "subtask" ? task.number : task.number;
2800
+ const taskDesc = task.description;
2801
+
2802
+ report += `**Task ${taskNumber}**: ${taskDesc}\n\n`;
2803
+ report += `**TDD Cycle for this task**:\n`;
2804
+ report += `1. 🔴 **RED**: Write failing tests for "${taskDesc}"\n`;
2805
+ report += ` - Define test cases that specify expected behavior\n`;
2806
+ report += ` - Ensure tests fail initially (no implementation yet)\n`;
2807
+ report += ` - Verify test framework and setup is working\n\n`;
2808
+
2809
+ report += `2. 🟢 **GREEN**: Write minimal code to pass tests\n`;
2810
+ report += ` - Implement only what's needed to make tests pass\n`;
2811
+ report += ` - Focus on making it work, not making it perfect\n`;
2812
+ report += ` - Avoid over-engineering at this stage\n\n`;
2813
+
2814
+ report += `3. 🔵 **REFACTOR**: Clean up and improve code structure\n`;
2815
+ report += ` - Improve code quality while keeping tests green\n`;
2816
+ report += ` - Remove duplication and improve naming\n`;
2817
+ report += ` - Ensure code follows project conventions\n\n`;
2818
+
2819
+ report += `4. ✅ **VERIFY**: Complete task verification\n`;
2820
+ report += ` - All tests pass (new and existing)\n`;
2821
+ report += ` - Code quality meets standards\n`;
2822
+ report += ` - No regressions in existing functionality\n`;
2823
+ report += ` - Mark task as completed: \`- [x] ${taskNumber} ${taskDesc}\`\n\n`;
2824
+ });
2825
+
2826
+ if (tasksToExecute.length > 5) {
2827
+ report += `... and ${tasksToExecute.length - 5} more tasks\n\n`;
2828
+ }
2829
+
2830
+ report += `### Implementation Guidelines\n`;
2831
+ report += `- **Follow design specifications**: Implement exactly what's specified in design.md\n`;
2832
+ report += `- **Test-first approach**: Always write tests before implementation code\n`;
2833
+ report += `- **Incremental progress**: Complete one task fully before moving to next\n`;
2834
+ report += `- **Update task status**: Mark checkboxes as completed in tasks.md\n`;
2835
+ report += `- **Quality focus**: Maintain code quality and test coverage\n\n`;
2836
+
2837
+ report += `### Next Steps\n`;
2838
+ report += `1. Start with the first pending task: "${tasksToExecute[0].task.description}"\n`;
2839
+ report += `2. Follow the TDD cycle: Red → Green → Refactor → Verify\n`;
2840
+ report += `3. Update tasks.md to mark completed tasks with [x]\n`;
2841
+ report += `4. Run \`sdd-quality-check\` to validate code quality\n`;
2842
+ report += `5. Continue with remaining tasks sequentially\n\n`;
2843
+
2844
+ report += `**Remember**: TDD is about building confidence through tests. Write tests that clearly specify the expected behavior, then implement the simplest solution that makes those tests pass.`;
2845
+
2123
2846
  return {
2124
- content: [{
2125
- type: 'text',
2126
- text: `## No Pending Tasks Found\n\n**Feature**: ${featureName}\n**Status**: ${taskNumbers ? 'Specified tasks already completed or not found' : 'All tasks already completed'}\n\n${taskNumbers ? `**Requested**: ${taskNumbers}` : '**All tasks**: ✅ Completed'}\n\nUse \`sdd-status ${featureName}\` to check current progress.`
2127
- }]
2847
+ content: [
2848
+ {
2849
+ type: "text",
2850
+ text: report,
2851
+ },
2852
+ ],
2853
+ };
2854
+ } catch (error) {
2855
+ return {
2856
+ content: [
2857
+ {
2858
+ type: "text",
2859
+ text: `Error executing spec implementation: ${error.message}`,
2860
+ },
2861
+ ],
2128
2862
  };
2129
2863
  }
2130
-
2131
- // Generate TDD implementation guidance for the tasks
2132
- let report = `## TDD Implementation Execution: ${featureName}\n\n`;
2133
- report += `**Tasks to Execute**: ${tasksToExecute.length} pending tasks\n`;
2134
- report += `**TDD Methodology**: Kent Beck's Red → Green → Refactor cycle\n\n`;
2135
-
2136
- report += `### Context Loaded\n`;
2137
- report += `- ✅ Requirements: .kiro/specs/${featureName}/requirements.md\n`;
2138
- report += `- ✅ Design: .kiro/specs/${featureName}/design.md\n`;
2139
- report += `- ✅ Tasks: .kiro/specs/${featureName}/tasks.md\n`;
2140
- report += `- ✅ Metadata: .kiro/specs/${featureName}/spec.json\n\n`;
2141
-
2142
- report += `### TDD Implementation Plan\n\n`;
2143
-
2144
- tasksToExecute.slice(0, 5).forEach((item, index) => {
2145
- const task = item.task;
2146
- const taskNumber = item.type === 'subtask' ? task.number : task.number;
2147
- const taskDesc = task.description;
2148
-
2149
- report += `**Task ${taskNumber}**: ${taskDesc}\n\n`;
2150
- report += `**TDD Cycle for this task**:\n`;
2151
- report += `1. 🔴 **RED**: Write failing tests for "${taskDesc}"\n`;
2152
- report += ` - Define test cases that specify expected behavior\n`;
2153
- report += ` - Ensure tests fail initially (no implementation yet)\n`;
2154
- report += ` - Verify test framework and setup is working\n\n`;
2155
-
2156
- report += `2. 🟢 **GREEN**: Write minimal code to pass tests\n`;
2157
- report += ` - Implement only what's needed to make tests pass\n`;
2158
- report += ` - Focus on making it work, not making it perfect\n`;
2159
- report += ` - Avoid over-engineering at this stage\n\n`;
2160
-
2161
- report += `3. 🔵 **REFACTOR**: Clean up and improve code structure\n`;
2162
- report += ` - Improve code quality while keeping tests green\n`;
2163
- report += ` - Remove duplication and improve naming\n`;
2164
- report += ` - Ensure code follows project conventions\n\n`;
2165
-
2166
- report += `4. ✅ **VERIFY**: Complete task verification\n`;
2167
- report += ` - All tests pass (new and existing)\n`;
2168
- report += ` - Code quality meets standards\n`;
2169
- report += ` - No regressions in existing functionality\n`;
2170
- report += ` - Mark task as completed: \`- [x] ${taskNumber} ${taskDesc}\`\n\n`;
2171
- });
2172
-
2173
- if (tasksToExecute.length > 5) {
2174
- report += `... and ${tasksToExecute.length - 5} more tasks\n\n`;
2175
- }
2176
-
2177
- report += `### Implementation Guidelines\n`;
2178
- report += `- **Follow design specifications**: Implement exactly what's specified in design.md\n`;
2179
- report += `- **Test-first approach**: Always write tests before implementation code\n`;
2180
- report += `- **Incremental progress**: Complete one task fully before moving to next\n`;
2181
- report += `- **Update task status**: Mark checkboxes as completed in tasks.md\n`;
2182
- report += `- **Quality focus**: Maintain code quality and test coverage\n\n`;
2183
-
2184
- report += `### Next Steps\n`;
2185
- report += `1. Start with the first pending task: "${tasksToExecute[0].task.description}"\n`;
2186
- report += `2. Follow the TDD cycle: Red → Green → Refactor → Verify\n`;
2187
- report += `3. Update tasks.md to mark completed tasks with [x]\n`;
2188
- report += `4. Run \`sdd-quality-check\` to validate code quality\n`;
2189
- report += `5. Continue with remaining tasks sequentially\n\n`;
2190
-
2191
- report += `**Remember**: TDD is about building confidence through tests. Write tests that clearly specify the expected behavior, then implement the simplest solution that makes those tests pass.`;
2192
-
2193
- return {
2194
- content: [{
2195
- type: 'text',
2196
- text: report
2197
- }]
2198
- };
2199
- } catch (error) {
2200
- return {
2201
- content: [{
2202
- type: 'text',
2203
- text: `Error executing spec implementation: ${error.message}`
2204
- }]
2205
- };
2206
- }
2207
- });
2864
+ },
2865
+ );
2208
2866
 
2209
2867
  const transport = new StdioServerTransport();
2210
2868
  // Helper functions for validation
2211
2869
  function isAnalysisInsufficient(analysis) {
2212
- return analysis.name === 'Unknown Project' &&
2213
- analysis.description === 'No description available' &&
2214
- analysis.dependencies.length === 0;
2870
+ return (
2871
+ analysis.name === "Unknown Project" &&
2872
+ analysis.description === "No description available" &&
2873
+ analysis.dependencies.length === 0
2874
+ );
2215
2875
  }
2216
2876
 
2217
2877
  function contentContainsGenericPlaceholders(content) {
2218
- return content.includes('Unknown Project') ||
2219
- content.includes('No description available') ||
2220
- content.includes('unknown');
2878
+ return (
2879
+ content.includes("Unknown Project") ||
2880
+ content.includes("No description available") ||
2881
+ content.includes("unknown")
2882
+ );
2221
2883
  }
2222
2884
 
2223
2885
  await server.connect(transport);