sdd-mcp-server 3.5.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +92 -683
  2. package/agents/architect.md +15 -93
  3. package/agents/implementer.md +16 -141
  4. package/agents/planner.md +16 -84
  5. package/agents/reviewer.md +16 -239
  6. package/agents/security-auditor.md +16 -114
  7. package/agents/tdd-guide.md +17 -228
  8. package/dist/adapters/cli/SDDToolAdapter.d.ts +14 -8
  9. package/dist/adapters/cli/SDDToolAdapter.js +188 -405
  10. package/dist/adapters/cli/SDDToolAdapter.js.map +1 -1
  11. package/dist/application/services/ContextCompactionService.d.ts +88 -16
  12. package/dist/application/services/ContextCompactionService.js +474 -187
  13. package/dist/application/services/ContextCompactionService.js.map +1 -1
  14. package/dist/application/services/ProjectService.js +3 -3
  15. package/dist/application/services/ProjectService.js.map +1 -1
  16. package/dist/application/services/SpecPathResolver.d.ts +24 -0
  17. package/dist/application/services/SpecPathResolver.js +70 -0
  18. package/dist/application/services/SpecPathResolver.js.map +1 -0
  19. package/dist/application/services/WorkflowEngineService.d.ts +214 -50
  20. package/dist/application/services/WorkflowEngineService.js +1447 -292
  21. package/dist/application/services/WorkflowEngineService.js.map +1 -1
  22. package/dist/application/services/WorkflowErrors.d.ts +16 -0
  23. package/dist/application/services/WorkflowErrors.js +53 -0
  24. package/dist/application/services/WorkflowErrors.js.map +1 -0
  25. package/dist/application/services/WorkflowValidationService.d.ts +25 -46
  26. package/dist/application/services/WorkflowValidationService.js +284 -627
  27. package/dist/application/services/WorkflowValidationService.js.map +1 -1
  28. package/dist/cli/install-skills.d.ts +3 -9
  29. package/dist/cli/install-skills.js +129 -174
  30. package/dist/cli/install-skills.js.map +1 -1
  31. package/dist/cli/install-target.d.ts +42 -8
  32. package/dist/cli/install-target.js +27 -9
  33. package/dist/cli/install-target.js.map +1 -1
  34. package/dist/cli/sdd-mcp-cli.d.ts +1 -1
  35. package/dist/cli/sdd-mcp-cli.js +7 -6
  36. package/dist/cli/sdd-mcp-cli.js.map +1 -1
  37. package/dist/cli/tool-support/claude-code.js +17 -34
  38. package/dist/cli/tool-support/claude-code.js.map +1 -1
  39. package/dist/cli/tool-support/codex.d.ts +0 -53
  40. package/dist/cli/tool-support/codex.js +10 -94
  41. package/dist/cli/tool-support/codex.js.map +1 -1
  42. package/dist/cli/tool-support/index.d.ts +3 -2
  43. package/dist/cli/tool-support/index.js +3 -1
  44. package/dist/cli/tool-support/index.js.map +1 -1
  45. package/dist/cli/tool-support/mcp-registration.d.ts +22 -0
  46. package/dist/cli/tool-support/mcp-registration.js +275 -0
  47. package/dist/cli/tool-support/mcp-registration.js.map +1 -0
  48. package/dist/cli/tool-support/omp.d.ts +5 -0
  49. package/dist/cli/tool-support/omp.js +47 -0
  50. package/dist/cli/tool-support/omp.js.map +1 -0
  51. package/dist/cli/tool-support/root-guidance.d.ts +2 -9
  52. package/dist/cli/tool-support/root-guidance.js +44 -37
  53. package/dist/cli/tool-support/root-guidance.js.map +1 -1
  54. package/dist/cli/tool-support/target-agent-renderer.d.ts +1 -0
  55. package/dist/cli/tool-support/target-agent-renderer.js +37 -4
  56. package/dist/cli/tool-support/target-agent-renderer.js.map +1 -1
  57. package/dist/cli/tool-support/target-installer.d.ts +9 -3
  58. package/dist/cli/tool-support/target-installer.js +100 -26
  59. package/dist/cli/tool-support/target-installer.js.map +1 -1
  60. package/dist/cli/utils/preserving-writer.d.ts +56 -0
  61. package/dist/cli/utils/preserving-writer.js +603 -10
  62. package/dist/cli/utils/preserving-writer.js.map +1 -1
  63. package/dist/domain/ports.d.ts +4 -0
  64. package/dist/domain/types.d.ts +52 -7
  65. package/dist/domain/types.js +5 -4
  66. package/dist/domain/types.js.map +1 -1
  67. package/dist/index.d.ts +13 -10
  68. package/dist/index.js +16 -1199
  69. package/dist/index.js.map +1 -1
  70. package/dist/infrastructure/adapters/NodeFileSystemAdapter.d.ts +3 -0
  71. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js +10 -0
  72. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js.map +1 -1
  73. package/dist/infrastructure/mcp/CapabilityNegotiator.js +3 -3
  74. package/dist/infrastructure/mcp/CapabilityNegotiator.js.map +1 -1
  75. package/dist/infrastructure/mcp/MCPServer.js +13 -13
  76. package/dist/infrastructure/mcp/MCPServer.js.map +1 -1
  77. package/dist/infrastructure/mcp/ToolRegistry.d.ts +5 -1
  78. package/dist/infrastructure/mcp/ToolRegistry.js +11 -4
  79. package/dist/infrastructure/mcp/ToolRegistry.js.map +1 -1
  80. package/dist/infrastructure/mcp/sddToolDefinitions.d.ts +6 -0
  81. package/dist/infrastructure/mcp/sddToolDefinitions.js +110 -0
  82. package/dist/infrastructure/mcp/sddToolDefinitions.js.map +1 -0
  83. package/dist/infrastructure/schemas/project.schema.d.ts +2 -2
  84. package/dist/infrastructure/schemas/project.schema.js +2 -2
  85. package/dist/infrastructure/schemas/project.schema.js.map +1 -1
  86. package/dist/shared/version.d.ts +3 -0
  87. package/dist/shared/version.js +4 -0
  88. package/dist/shared/version.js.map +1 -0
  89. package/dist/utils/atomicWrite.d.ts +8 -35
  90. package/dist/utils/atomicWrite.js +24 -57
  91. package/dist/utils/atomicWrite.js.map +1 -1
  92. package/dist/utils/withFilesystemLock.d.ts +22 -0
  93. package/dist/utils/withFilesystemLock.js +219 -0
  94. package/dist/utils/withFilesystemLock.js.map +1 -0
  95. package/mcp-server.js +5 -2883
  96. package/package.json +8 -3
  97. package/scripts/context-usage-report.mjs +602 -0
  98. package/sdd-entry.js +17 -6
  99. package/skills/sdd-commit/REFERENCE.md +31 -0
  100. package/skills/sdd-commit/SKILL.md +17 -273
  101. package/skills/sdd-design/REFERENCE.md +51 -0
  102. package/skills/sdd-design/SKILL.md +25 -262
  103. package/skills/sdd-implement/REFERENCE.md +30 -0
  104. package/skills/sdd-implement/SKILL.md +27 -284
  105. package/skills/sdd-requirements/REFERENCE.md +39 -0
  106. package/skills/sdd-requirements/SKILL.md +28 -132
  107. package/skills/sdd-review/REFERENCE.md +26 -0
  108. package/skills/sdd-review/SKILL.md +17 -181
  109. package/skills/sdd-security-check/REFERENCE.md +19 -0
  110. package/skills/sdd-security-check/SKILL.md +18 -184
  111. package/skills/sdd-steering/REFERENCE.md +25 -0
  112. package/skills/sdd-steering/SKILL.md +18 -216
  113. package/skills/sdd-steering-custom/REFERENCE.md +27 -0
  114. package/skills/sdd-steering-custom/SKILL.md +19 -203
  115. package/skills/sdd-tasks/REFERENCE.md +25 -0
  116. package/skills/sdd-tasks/SKILL.md +27 -244
  117. package/skills/sdd-test-gen/REFERENCE.md +15 -0
  118. package/skills/sdd-test-gen/SKILL.md +17 -287
  119. package/skills/simple-task/REFERENCE.md +22 -0
  120. package/skills/simple-task/SKILL.md +17 -138
  121. package/templates/CLAUDE.md +13 -31
  122. package/templates/codex-AGENTS.md +7 -9
  123. package/rules/git-workflow.md +0 -92
  124. package/rules/sdd-workflow.md +0 -116
package/mcp-server.js CHANGED
@@ -1,2886 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
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";
13
- import { atomicWriteJSON } from "./atomicWrite.js";
14
2
 
15
- // Best-effort dynamic loader for spec generators (requirements/design/tasks)
16
- async function loadSpecGenerator() {
17
- const tried = [];
18
- const attempts = [
19
- "./specGenerator.js", // root-level JS (dev/runtime)
20
- "./dist/utils/specGenerator.js", // compiled TS output
21
- "./utils/specGenerator.js", // TS runtime (when transpiled on-the-fly)
22
- ];
23
- for (const p of attempts) {
24
- try {
25
- // eslint-disable-next-line no-await-in-loop
26
- const mod = await import(p);
27
- return { mod, path: p };
28
- } catch (e) {
29
- tried.push(`${p}: ${(e && e.message) || e}`);
30
- }
31
- }
32
- throw new Error(
33
- `Unable to load specGenerator from known paths. Tried: \n- ${tried.join("\n- ")}`,
34
- );
35
- }
3
+ import { startMCPServer } from './dist/index.js';
36
4
 
37
- // Resolve version dynamically from package.json when possible
38
- async function resolveVersion() {
39
- try {
40
- const pkgUrl = new URL("./package.json", import.meta.url);
41
- const pkgText = await fs.readFile(pkgUrl, "utf8");
42
- const pkg = JSON.parse(pkgText);
43
- return pkg.version || "0.0.0";
44
- } catch {
45
- return "0.0.0";
46
- }
47
- }
48
-
49
- const server = new McpServer(
50
- {
51
- name: "sdd-mcp-server",
52
- version: await resolveVersion(),
53
- },
54
- {
55
- instructions: "Use this server for spec-driven development workflows",
56
- },
57
- );
58
-
59
- // Helper functions for file operations
60
- async function createKiroDirectory(projectPath) {
61
- const kiroPath = path.join(projectPath, ".spec");
62
- const specsPath = path.join(kiroPath, "specs");
63
- const steeringPath = path.join(kiroPath, "steering");
64
-
65
- await fs.mkdir(kiroPath, { recursive: true });
66
- await fs.mkdir(specsPath, { recursive: true });
67
- await fs.mkdir(steeringPath, { recursive: true });
68
-
69
- return { kiroPath, specsPath, steeringPath };
70
- }
71
-
72
- async function generateFeatureName(description) {
73
- // Simple feature name generation from description
74
- return description
75
- .toLowerCase()
76
- .replace(/[^a-z0-9\s]/g, "")
77
- .replace(/\s+/g, "-")
78
- .substring(0, 50);
79
- }
80
-
81
- async function getCurrentTimestamp() {
82
- return new Date().toISOString();
83
- }
84
-
85
- // Requirements Clarification helpers
86
- function analyzeDescriptionQuality(description) {
87
- const analysis = {
88
- hasWhy:
89
- /\b(problem|solve[sd]?|challenge|pain\s+point|issue|why|because|enables?|value\s+proposition|benefit|justification|goal|objective|purpose)\b/i.test(
90
- description,
91
- ),
92
- hasWho:
93
- /\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(
94
- description,
95
- ),
96
- hasWhat:
97
- /\b(feature[s]?|functionality|capabilit(y|ies)|provides?|include[s]?|support[s]?|allow[s]?|enable[s]?|MVP|scope)\b/i.test(
98
- description,
99
- ),
100
- hasSuccessCriteria:
101
- /\b(metric[s]?|KPI[s]?|measure[sd]?|success\s+(criteria|metric)|\d+%|performance\s+target|goal[s]?\s+.*\d+)\b/i.test(
102
- description,
103
- ),
104
- ambiguousTerms: [],
105
- };
106
-
107
- // Detect ambiguous terms
108
- const ambiguityChecks = [
109
- {
110
- pattern: /\bfast\b/gi,
111
- suggestion: "Can you specify a target response time?",
112
- },
113
- {
114
- pattern: /\bscalable\b/gi,
115
- suggestion: "What scale do you need to support?",
116
- },
117
- {
118
- pattern: /\buser[- ]friendly\b/gi,
119
- suggestion: "What makes it user-friendly?",
120
- },
121
- {
122
- pattern: /\beasy\s+to\s+use\b/gi,
123
- suggestion: "What does easy mean for your users?",
124
- },
125
- {
126
- pattern: /\bhigh\s+quality\b/gi,
127
- suggestion: "How do you define quality?",
128
- },
129
- {
130
- pattern: /\breliable\b/gi,
131
- suggestion: "What reliability level do you need?",
132
- },
133
- {
134
- pattern: /\bsecure\b/gi,
135
- suggestion: "What security requirements apply?",
136
- },
137
- {
138
- pattern: /\bmodern\b/gi,
139
- suggestion: "What technologies are you considering?",
140
- },
141
- ];
142
-
143
- for (const { pattern, suggestion } of ambiguityChecks) {
144
- const matches = description.match(pattern);
145
- if (matches) {
146
- analysis.ambiguousTerms.push({ term: matches[0], suggestion });
147
- }
148
- }
149
-
150
- // Calculate quality score
151
- let score = 0;
152
- if (analysis.hasWhy) score += 30;
153
- if (analysis.hasWho) score += 20;
154
- if (analysis.hasWhat) score += 20;
155
- if (analysis.hasSuccessCriteria) score += 15;
156
- if (description.length > 100) score += 5;
157
- if (description.length > 300) score += 5;
158
- if (description.length > 500) score += 5;
159
- score -= Math.min(15, analysis.ambiguousTerms.length * 5);
160
-
161
- analysis.qualityScore = Math.max(0, Math.min(100, score));
162
- analysis.needsClarification = score < 70;
163
-
164
- return analysis;
165
- }
166
-
167
- function generateClarificationQuestions(analysis) {
168
- const questions = [];
169
-
170
- if (!analysis.hasWhy) {
171
- questions.push({
172
- id: "why_problem",
173
- category: "why",
174
- question:
175
- "What business problem does this project solve? Why is it needed?",
176
- examples: [
177
- "Our customer support team spends 5 hours/day on repetitive inquiries",
178
- "Users are abandoning checkout because the process takes too long",
179
- ],
180
- required: true,
181
- });
182
- questions.push({
183
- id: "why_value",
184
- category: "why",
185
- question:
186
- "What value does this project provide to users or the business?",
187
- examples: [
188
- "Reduce support ticket volume by 40%",
189
- "Increase conversion rate by improving checkout speed",
190
- ],
191
- required: true,
192
- });
193
- }
194
-
195
- if (!analysis.hasWho) {
196
- questions.push({
197
- id: "who_users",
198
- category: "who",
199
- question: "Who are the primary users of this project?",
200
- examples: [
201
- "Customer support agents using ticketing systems",
202
- "E-commerce shoppers on mobile devices",
203
- "Backend developers integrating APIs",
204
- ],
205
- required: true,
206
- });
207
- }
208
-
209
- if (!analysis.hasWhat) {
210
- questions.push({
211
- id: "what_features",
212
- category: "what",
213
- question: "What are the 3-5 core features for the MVP?",
214
- examples: [
215
- "Auto-response system, ticket categorization, analytics dashboard",
216
- "Product search, cart management, payment integration",
217
- ],
218
- required: true,
219
- });
220
- questions.push({
221
- id: "what_scope",
222
- category: "what",
223
- question: "What is explicitly OUT OF SCOPE for this project?",
224
- examples: ["Admin panel (future phase)", "Mobile app (web only for MVP)"],
225
- required: false,
226
- });
227
- }
228
-
229
- if (!analysis.hasSuccessCriteria) {
230
- questions.push({
231
- id: "success_metrics",
232
- category: "success",
233
- question: "How will you measure if this project is successful?",
234
- examples: [
235
- "Support ticket volume reduced by 30% within 3 months",
236
- "Page load time under 2 seconds, conversion rate > 3%",
237
- ],
238
- required: true,
239
- });
240
- }
241
-
242
- // Add questions for ambiguous terms (max 2)
243
- for (const ambiguous of analysis.ambiguousTerms.slice(0, 2)) {
244
- questions.push({
245
- id: `ambiguous_${ambiguous.term.toLowerCase().replace(/\s+/g, "_")}`,
246
- category: "what",
247
- question: `You mentioned "${ambiguous.term}". ${ambiguous.suggestion}`,
248
- required: false,
249
- });
250
- }
251
-
252
- return questions;
253
- }
254
-
255
- function formatQuestionsForUser(questions) {
256
- let output = "## Requirements Clarification Needed\n\n";
257
- output +=
258
- "Your project description needs more detail to ensure we build the right solution.\n\n";
259
- output += `**Quality Score**: ${Math.round(questions.analysis?.qualityScore || 0)}/100 (need 70+ to proceed)\n\n`;
260
- output += "### Please answer these questions:\n\n";
261
-
262
- let questionNum = 1;
263
- for (const q of questions) {
264
- output += `**${questionNum}. ${q.question}**${q.required ? " *(required)*" : ""}\n`;
265
- if (q.examples && q.examples.length > 0) {
266
- output += ` Examples:\n`;
267
- for (const ex of q.examples) {
268
- output += ` - ${ex}\n`;
269
- }
270
- }
271
- output += ` Answer ID: \`${q.id}\`\n\n`;
272
- questionNum++;
273
- }
274
-
275
- output += "\n### How to Provide Answers\n\n";
276
- output +=
277
- "Call sdd-init again with the `clarificationAnswers` parameter:\n\n";
278
- output += "```json\n{\n";
279
- output += ' "projectName": "your-project-name",\n';
280
- output += ' "description": "your original description",\n';
281
- output += ' "clarificationAnswers": {\n';
282
- for (let i = 0; i < questions.length; i++) {
283
- const q = questions[i];
284
- output += ` "${q.id}": "your answer here"${i < questions.length - 1 ? "," : ""}\n`;
285
- }
286
- output += " }\n}\n```\n";
287
-
288
- return output;
289
- }
290
-
291
- // Register all SDD tools matching README and kiro command templates
292
-
293
- // 1. sdd-init - Initialize new SDD project with interactive clarification
294
- server.registerTool(
295
- "sdd-init",
296
- {
297
- title: "Initialize SDD Project",
298
- description:
299
- "Initialize a new SDD project with interactive requirements clarification",
300
- inputSchema: {
301
- projectName: z.string().describe("The name of the project to initialize"),
302
- description: z.string().optional().describe("Project description"),
303
- clarificationAnswers: z
304
- .record(z.string())
305
- .optional()
306
- .describe("Answers to clarification questions (second pass)"),
307
- },
308
- },
309
- async ({ projectName, description = "", clarificationAnswers }) => {
310
- try {
311
- const currentPath = process.cwd();
312
-
313
- // FIRST PASS: Analyze description quality and generate clarification questions if needed
314
- if (!clarificationAnswers) {
315
- const analysis = analyzeDescriptionQuality(description);
316
-
317
- // If description is vague or incomplete, BLOCK and ask for clarification
318
- if (analysis.needsClarification) {
319
- const questions = generateClarificationQuestions(analysis);
320
- questions.analysis = analysis; // Attach analysis for formatting
321
-
322
- return {
323
- content: [
324
- {
325
- type: "text",
326
- text: formatQuestionsForUser(questions),
327
- },
328
- ],
329
- };
330
- }
331
- }
332
-
333
- // SECOND PASS: Validate answers if provided
334
- if (clarificationAnswers) {
335
- const analysis = analyzeDescriptionQuality(description);
336
- const questions = generateClarificationQuestions(analysis);
337
-
338
- // Validate required questions are answered
339
- const missingRequired = questions
340
- .filter((q) => q.required && !clarificationAnswers[q.id])
341
- .map((q) => q.question);
342
-
343
- if (missingRequired.length > 0) {
344
- return {
345
- content: [
346
- {
347
- type: "text",
348
- 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.`,
349
- },
350
- ],
351
- };
352
- }
353
-
354
- // Build enriched description from answers
355
- const whyAnswers = questions
356
- .filter((q) => q.category === "why")
357
- .map((q) => clarificationAnswers[q.id])
358
- .filter((a) => a)
359
- .join(" ");
360
-
361
- const whoAnswers = questions
362
- .filter((q) => q.category === "who")
363
- .map((q) => clarificationAnswers[q.id])
364
- .filter((a) => a)
365
- .join(" ");
366
-
367
- const whatAnswers = questions
368
- .filter((q) => q.category === "what")
369
- .map((q) => clarificationAnswers[q.id])
370
- .filter((a) => a)
371
- .join(" ");
372
-
373
- const successAnswers = questions
374
- .filter((q) => q.category === "success")
375
- .map((q) => clarificationAnswers[q.id])
376
- .filter((a) => a)
377
- .join(" ");
378
-
379
- // Synthesize enriched description
380
- const enrichedParts = [];
381
- if (description)
382
- enrichedParts.push(`## Original Description\n${description}`);
383
- if (whyAnswers)
384
- enrichedParts.push(`## Business Justification (Why)\n${whyAnswers}`);
385
- if (whoAnswers)
386
- enrichedParts.push(`## Target Users (Who)\n${whoAnswers}`);
387
- if (whatAnswers)
388
- enrichedParts.push(`## Core Features (What)\n${whatAnswers}`);
389
- if (successAnswers)
390
- enrichedParts.push(`## Success Criteria\n${successAnswers}`);
391
-
392
- description = enrichedParts.join("\n\n");
393
- }
394
-
395
- // Proceed with spec creation (either quality is good or answers were provided)
396
- // Create .spec directory structure in current directory (not in a subdirectory)
397
- const { specsPath, steeringPath } =
398
- await createKiroDirectory(currentPath);
399
-
400
- // Generate feature name from description
401
- const featureName = projectName || await generateFeatureName(description);
402
- const featurePath = path.join(specsPath, featureName);
403
- await fs.mkdir(featurePath, { recursive: true });
404
-
405
- // Create spec.json
406
- const specJson = {
407
- feature_name: featureName,
408
- created_at: await getCurrentTimestamp(),
409
- updated_at: await getCurrentTimestamp(),
410
- language: "en",
411
- phase: "initialized",
412
- approvals: {
413
- requirements: {
414
- generated: false,
415
- approved: false,
416
- },
417
- design: {
418
- generated: false,
419
- approved: false,
420
- },
421
- tasks: {
422
- generated: false,
423
- approved: false,
424
- },
425
- },
426
- ready_for_implementation: false,
427
- };
428
-
429
- await fs.writeFile(
430
- path.join(featurePath, "spec.json"),
431
- JSON.stringify(specJson, null, 2),
432
- );
433
-
434
- // Create requirements.md template
435
- const requirementsTemplate = `# Requirements Document\n\n## Project Description (Input)\n${description}\n\n## Requirements\n<!-- Will be generated in /kiro:spec-requirements phase -->`;
436
- await fs.writeFile(
437
- path.join(featurePath, "requirements.md"),
438
- requirementsTemplate,
439
- );
440
-
441
- // Ensure AGENTS.md exists in steering directory based on CLAUDE.md (static exception)
442
- const agentsPath = path.join(steeringPath, "AGENTS.md");
443
- const claudePath = path.join(currentPath, "CLAUDE.md");
444
- const agentsExists = await fs
445
- .access(agentsPath)
446
- .then(() => true)
447
- .catch(() => false);
448
- if (!agentsExists) {
449
- let agentsContent = "";
450
- const claudeExists = await fs
451
- .access(claudePath)
452
- .then(() => true)
453
- .catch(() => false);
454
- if (claudeExists) {
455
- const claude = await fs.readFile(claudePath, "utf8");
456
- agentsContent = claude
457
- .replace(
458
- /# Claude Code Spec-Driven Development/g,
459
- "# AI Agent Spec-Driven Development",
460
- )
461
- .replace(/Claude Code/g, "AI Agent")
462
- .replace(/claude code/g, "ai agent")
463
- .replace(/Claude/g, "AI Agent")
464
- .replace(/claude/g, "ai agent");
465
- } else {
466
- agentsContent =
467
- "# AI Agent Spec-Driven Development\n\nKiro-style Spec Driven Development implementation for AI agents across different CLIs and IDEs.";
468
- }
469
- await fs.writeFile(agentsPath, agentsContent);
470
- }
471
-
472
- const clarificationNote = clarificationAnswers
473
- ? "\n\n✅ **Requirements Clarification**: Your answers have been incorporated into an enriched project description."
474
- : "";
475
-
476
- return {
477
- content: [
478
- {
479
- type: "text",
480
- text: `## Spec Initialization Complete\n\n**Generated Feature Name**: ${featureName}\n**Project Name**: ${projectName}\n**Project Description**: ${description}${clarificationNote}\n\n**Created Files**:\n- \`.spec/specs/${featureName}/spec.json\` - Metadata and approval tracking\n- \`.spec/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.`,
481
- },
482
- ],
483
- };
484
- } catch (error) {
485
- return {
486
- content: [
487
- {
488
- type: "text",
489
- text: `Error initializing SDD project: ${error.message}`,
490
- },
491
- ],
492
- };
493
- }
494
- },
495
- );
496
-
497
- // 2. sdd-requirements - Generate requirements doc
498
- server.registerTool(
499
- "sdd-requirements",
500
- {
501
- title: "Generate Requirements Document",
502
- description: "Generate requirements doc",
503
- inputSchema: {
504
- featureName: z.string().describe("Feature name from spec initialization"),
505
- },
506
- },
507
- async ({ featureName }) => {
508
- try {
509
- const currentPath = process.cwd();
510
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
511
-
512
- // Check if spec exists
513
- const specPath = path.join(featurePath, "spec.json");
514
- const specExists = await fs
515
- .access(specPath)
516
- .then(() => true)
517
- .catch(() => false);
518
- if (!specExists) {
519
- return {
520
- content: [
521
- {
522
- type: "text",
523
- text: `Error: Spec not found for feature "${featureName}". Use sdd-init first.`,
524
- },
525
- ],
526
- };
527
- }
528
-
529
- // Read existing spec
530
- const specContent = await fs.readFile(specPath, "utf8");
531
- const spec = JSON.parse(specContent);
532
-
533
- // Generate requirements using specGenerator with fallback
534
- let requirementsContent;
535
- try {
536
- const { mod } = await loadSpecGenerator();
537
- requirementsContent = await mod.generateRequirementsDocument(
538
- currentPath,
539
- featureName,
540
- );
541
- } catch (e) {
542
- 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`;
543
- }
544
-
545
- await fs.writeFile(
546
- path.join(featurePath, "requirements.md"),
547
- requirementsContent,
548
- );
549
-
550
- // Update spec.json
551
- spec.phase = "requirements-generated";
552
- spec.approvals.requirements.generated = true;
553
- spec.updated_at = await getCurrentTimestamp();
554
-
555
- await atomicWriteJSON(specPath, spec);
556
-
557
- return {
558
- content: [
559
- {
560
- type: "text",
561
- text: `## Requirements Generated\n\nRequirements document generated for feature: **${featureName}**\n\n**Generated**: .spec/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`,
562
- },
563
- ],
564
- };
565
- } catch (error) {
566
- return {
567
- content: [
568
- {
569
- type: "text",
570
- text: `Error generating requirements: ${error.message}`,
571
- },
572
- ],
573
- };
574
- }
575
- },
576
- );
577
-
578
- // 3. sdd-design - Create design specifications
579
- server.registerTool(
580
- "sdd-design",
581
- {
582
- title: "Create Design Specifications",
583
- description: "Create design specifications",
584
- inputSchema: {
585
- featureName: z.string().describe("Feature name from spec initialization"),
586
- },
587
- },
588
- async ({ featureName }) => {
589
- try {
590
- const currentPath = process.cwd();
591
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
592
- const specPath = path.join(featurePath, "spec.json");
593
-
594
- // Read and validate spec
595
- const specContent = await fs.readFile(specPath, "utf8");
596
- const spec = JSON.parse(specContent);
597
-
598
- if (!spec.approvals.requirements.generated) {
599
- return {
600
- content: [
601
- {
602
- type: "text",
603
- text: `Error: Requirements must be generated before design. Run \`sdd-requirements ${featureName}\` first.`,
604
- },
605
- ],
606
- };
607
- }
608
-
609
- // Read requirements for context
610
- const requirementsPath = path.join(featurePath, "requirements.md");
611
- let requirementsContext = "";
612
- try {
613
- requirementsContext = await fs.readFile(requirementsPath, "utf8");
614
- } catch (error) {
615
- requirementsContext = "Requirements document not available";
616
- }
617
-
618
- // Generate design using specGenerator with fallback
619
- let designContent;
620
- try {
621
- const { mod } = await loadSpecGenerator();
622
- designContent = await mod.generateDesignDocument(
623
- currentPath,
624
- featureName,
625
- );
626
- } catch (e) {
627
- 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}`;
628
- }
629
-
630
- await fs.writeFile(path.join(featurePath, "design.md"), designContent);
631
-
632
- // Update spec.json
633
- spec.phase = "design-generated";
634
- spec.approvals.design.generated = true;
635
- spec.updated_at = await getCurrentTimestamp();
636
-
637
- await atomicWriteJSON(specPath, spec);
638
-
639
- return {
640
- content: [
641
- {
642
- type: "text",
643
- text: `## Design Generated\n\nTechnical design document generated for feature: **${featureName}**\n\n**Generated**: .spec/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`,
644
- },
645
- ],
646
- };
647
- } catch (error) {
648
- return {
649
- content: [
650
- {
651
- type: "text",
652
- text: `Error generating design: ${error.message}`,
653
- },
654
- ],
655
- };
656
- }
657
- },
658
- );
659
-
660
- // 4. sdd-tasks - Generate task breakdown
661
- server.registerTool(
662
- "sdd-tasks",
663
- {
664
- title: "Generate Task Breakdown",
665
- description: "Generate task breakdown",
666
- inputSchema: {
667
- featureName: z.string().describe("Feature name from spec initialization"),
668
- },
669
- },
670
- async ({ featureName }) => {
671
- try {
672
- const currentPath = process.cwd();
673
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
674
- const specPath = path.join(featurePath, "spec.json");
675
-
676
- // Read and validate spec
677
- const specContent = await fs.readFile(specPath, "utf8");
678
- const spec = JSON.parse(specContent);
679
-
680
- if (!spec.approvals.design.generated) {
681
- return {
682
- content: [
683
- {
684
- type: "text",
685
- text: `Error: Design must be generated before tasks. Run \`sdd-design ${featureName}\` first.`,
686
- },
687
- ],
688
- };
689
- }
690
-
691
- // Read design and requirements for context
692
- const designPath = path.join(featurePath, "design.md");
693
- const requirementsPath = path.join(featurePath, "requirements.md");
694
- let designContext = "";
695
- let requirementsContext = "";
696
-
697
- try {
698
- designContext = await fs.readFile(designPath, "utf8");
699
- } catch (error) {
700
- designContext = "Design document not available";
701
- }
702
-
703
- try {
704
- requirementsContext = await fs.readFile(requirementsPath, "utf8");
705
- } catch (error) {
706
- requirementsContext = "Requirements document not available";
707
- }
708
-
709
- // Generate tasks document based on requirements and design
710
- const tasksContent = `# Implementation Plan
711
-
712
- ## Project Context
713
- **Feature**: ${spec.feature_name}
714
- **Description**: ${spec.description || "Feature to be implemented"}
715
- **Design Phase**: ${spec.approvals.design.generated ? "Completed" : "Pending"}
716
-
717
- ## Instructions for AI Agent
718
-
719
- Please analyze the requirements and design documents to create a comprehensive implementation plan. Consider:
720
-
721
- 1. **Requirements Review**: Understand all requirements that need to be implemented
722
- 2. **Design Analysis**: Review the technical design and architecture decisions
723
- 3. **Implementation Strategy**: Break down the work into logical, sequential tasks
724
- 4. **Dependencies**: Identify task dependencies and prerequisites
725
- 5. **Acceptance Criteria**: Ensure each task maps to testable requirements
726
- 6. **Integration Points**: Consider how tasks integrate with existing codebase
727
-
728
- ## Task Generation Guidelines
729
-
730
- Create tasks that:
731
- - Are specific and actionable
732
- - Map directly to requirements and design components
733
- - Include clear acceptance criteria
734
- - Consider the existing codebase and architecture
735
- - Are appropriately sized (not too large or too small)
736
- - Include proper sequencing and dependencies
737
-
738
- ## Requirements Context
739
- \`\`\`
740
- ${requirementsContext.substring(0, 1000)}${requirementsContext.length > 1000 ? "...\n[Requirements truncated - see requirements.md for full content]" : ""}
741
- \`\`\`
742
-
743
- ## Design Context
744
- \`\`\`
745
- ${designContext.substring(0, 1000)}${designContext.length > 1000 ? "...\n[Design truncated - see design.md for full content]" : ""}
746
- \`\`\`
747
-
748
- ## Current Project Information
749
- - Project Path: ${process.cwd()}
750
- - Feature Name: ${spec.feature_name}
751
- - Phase: ${spec.phase}
752
- - Created: ${spec.created_at}
753
-
754
- **Note**: This template will be replaced by AI-generated implementation tasks specific to your project requirements and design.`;
755
-
756
- // Try to replace template with analysis-backed tasks
757
- try {
758
- const { mod } = await loadSpecGenerator();
759
- tasksContent = await mod.generateTasksDocument(
760
- currentPath,
761
- featureName,
762
- );
763
- } catch (e) {
764
- // Keep template; include debug info in file header already
765
- }
766
-
767
- await fs.writeFile(path.join(featurePath, "tasks.md"), tasksContent);
768
-
769
- // Update spec.json
770
- spec.phase = "tasks-generated";
771
- spec.approvals.tasks.generated = true;
772
- spec.ready_for_implementation = true;
773
- spec.updated_at = await getCurrentTimestamp();
774
-
775
- await atomicWriteJSON(specPath, spec);
776
-
777
- return {
778
- content: [
779
- {
780
- type: "text",
781
- text: `## Implementation Tasks Generated\n\nImplementation tasks document generated for feature: **${featureName}**\n\n**Generated**: .spec/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`,
782
- },
783
- ],
784
- };
785
- } catch (error) {
786
- return {
787
- content: [
788
- {
789
- type: "text",
790
- text: `Error generating tasks: ${error.message}`,
791
- },
792
- ],
793
- };
794
- }
795
- },
796
- );
797
-
798
- // 5. sdd-implement - Implementation guidelines
799
- server.registerTool(
800
- "sdd-implement",
801
- {
802
- title: "Implementation Guidelines",
803
- description: "Implementation guidelines",
804
- inputSchema: {
805
- featureName: z.string().describe("Feature name from spec initialization"),
806
- },
807
- },
808
- async ({ featureName }) => {
809
- try {
810
- const currentPath = process.cwd();
811
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
812
- const specPath = path.join(featurePath, "spec.json");
813
-
814
- // Read spec
815
- const specContent = await fs.readFile(specPath, "utf8");
816
- const spec = JSON.parse(specContent);
817
-
818
- if (!spec.ready_for_implementation) {
819
- return {
820
- content: [
821
- {
822
- type: "text",
823
- text: `Error: Project not ready for implementation. Complete requirements, design, and tasks phases first.`,
824
- },
825
- ],
826
- };
827
- }
828
-
829
- return {
830
- content: [
831
- {
832
- type: "text",
833
- 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`,
834
- },
835
- ],
836
- };
837
- } catch (error) {
838
- return {
839
- content: [
840
- {
841
- type: "text",
842
- text: `Error getting implementation guidelines: ${error.message}`,
843
- },
844
- ],
845
- };
846
- }
847
- },
848
- );
849
-
850
- // 6. sdd-status - Check workflow progress
851
- server.registerTool(
852
- "sdd-status",
853
- {
854
- title: "Check Workflow Progress",
855
- description: "Check workflow progress",
856
- inputSchema: {
857
- featureName: z
858
- .string()
859
- .optional()
860
- .describe("Feature name (optional - shows all if not provided)"),
861
- },
862
- },
863
- async ({ featureName }) => {
864
- try {
865
- const currentPath = process.cwd();
866
- const kiroPath = path.join(currentPath, ".spec");
867
-
868
- // Check if .spec directory exists
869
- const kiroExists = await fs
870
- .access(kiroPath)
871
- .then(() => true)
872
- .catch(() => false);
873
- if (!kiroExists) {
874
- return {
875
- content: [
876
- {
877
- type: "text",
878
- text: "SDD project status: No active project found. Use sdd-init to create a new project.",
879
- },
880
- ],
881
- };
882
- }
883
-
884
- const specsPath = path.join(kiroPath, "specs");
885
-
886
- if (featureName) {
887
- // Show status for specific feature
888
- const featurePath = path.join(specsPath, featureName);
889
- const specPath = path.join(featurePath, "spec.json");
890
-
891
- const specExists = await fs
892
- .access(specPath)
893
- .then(() => true)
894
- .catch(() => false);
895
- if (!specExists) {
896
- return {
897
- content: [
898
- {
899
- type: "text",
900
- text: `Feature "${featureName}" not found. Use sdd-init to create it.`,
901
- },
902
- ],
903
- };
904
- }
905
-
906
- const specContent = await fs.readFile(specPath, "utf8");
907
- const spec = JSON.parse(specContent);
908
-
909
- let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
910
- status += `**Current Phase**: ${spec.phase}\n`;
911
- status += `**Language**: ${spec.language}\n`;
912
- status += `**Created**: ${spec.created_at}\n`;
913
- status += `**Updated**: ${spec.updated_at}\n\n`;
914
-
915
- status += `**Phase Progress**:\n`;
916
- status += `- Requirements: ${spec.approvals.requirements.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.requirements.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
917
- status += `- Design: ${spec.approvals.design.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.design.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
918
- status += `- Tasks: ${spec.approvals.tasks.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.tasks.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n\n`;
919
-
920
- status += `**Ready for Implementation**: ${spec.ready_for_implementation ? "✅ Yes" : "❌ No"}\n\n`;
921
-
922
- // Suggest next steps
923
- if (!spec.approvals.requirements.generated) {
924
- status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
925
- } else if (!spec.approvals.design.generated) {
926
- status += `**Next Step**: Run \`sdd-design ${featureName}\``;
927
- } else if (!spec.approvals.tasks.generated) {
928
- status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
929
- } else {
930
- status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
931
- }
932
-
933
- return {
934
- content: [
935
- {
936
- type: "text",
937
- text: status,
938
- },
939
- ],
940
- };
941
- } else {
942
- // Show all features
943
- const features = await fs.readdir(specsPath).catch(() => []);
944
-
945
- if (features.length === 0) {
946
- return {
947
- content: [
948
- {
949
- type: "text",
950
- text: "No SDD features found. Use sdd-init to create a new project.",
951
- },
952
- ],
953
- };
954
- }
955
-
956
- let status = `## SDD Project Status - All Features\n\n`;
957
-
958
- for (const feature of features) {
959
- const specPath = path.join(specsPath, feature, "spec.json");
960
- const specExists = await fs
961
- .access(specPath)
962
- .then(() => true)
963
- .catch(() => false);
964
-
965
- if (specExists) {
966
- const specContent = await fs.readFile(specPath, "utf8");
967
- const spec = JSON.parse(specContent);
968
-
969
- status += `**${spec.feature_name}**:\n`;
970
- status += `- Phase: ${spec.phase}\n`;
971
- status += `- Requirements: ${spec.approvals.requirements.generated ? "✅" : "❌"}\n`;
972
- status += `- Design: ${spec.approvals.design.generated ? "✅" : "❌"}\n`;
973
- status += `- Tasks: ${spec.approvals.tasks.generated ? "✅" : "❌"}\n`;
974
- status += `- Ready: ${spec.ready_for_implementation ? "✅" : "❌"}\n\n`;
975
- }
976
- }
977
-
978
- return {
979
- content: [
980
- {
981
- type: "text",
982
- text: status,
983
- },
984
- ],
985
- };
986
- }
987
- } catch (error) {
988
- return {
989
- content: [
990
- {
991
- type: "text",
992
- text: `Error checking status: ${error.message}`,
993
- },
994
- ],
995
- };
996
- }
997
- },
998
- );
999
-
1000
- // 7. sdd-approve - Approve workflow phases
1001
- server.registerTool(
1002
- "sdd-approve",
1003
- {
1004
- title: "Approve Workflow Phases",
1005
- description: "Approve workflow phases",
1006
- inputSchema: {
1007
- featureName: z.string().describe("Feature name from spec initialization"),
1008
- phase: z
1009
- .enum(["requirements", "design", "tasks"])
1010
- .describe("Phase to approve"),
1011
- },
1012
- },
1013
- async ({ featureName, phase }) => {
1014
- try {
1015
- const currentPath = process.cwd();
1016
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
1017
- const specPath = path.join(featurePath, "spec.json");
1018
-
1019
- // Read spec
1020
- const specContent = await fs.readFile(specPath, "utf8");
1021
- const spec = JSON.parse(specContent);
1022
-
1023
- if (!spec.approvals[phase].generated) {
1024
- return {
1025
- content: [
1026
- {
1027
- type: "text",
1028
- text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`,
1029
- },
1030
- ],
1031
- };
1032
- }
1033
-
1034
- // Approve the phase
1035
- spec.approvals[phase].approved = true;
1036
- spec.updated_at = await getCurrentTimestamp();
1037
-
1038
- await atomicWriteJSON(specPath, spec);
1039
-
1040
- return {
1041
- content: [
1042
- {
1043
- type: "text",
1044
- 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.`,
1045
- },
1046
- ],
1047
- };
1048
- } catch (error) {
1049
- return {
1050
- content: [
1051
- {
1052
- type: "text",
1053
- text: `Error approving phase: ${error.message}`,
1054
- },
1055
- ],
1056
- };
1057
- }
1058
- },
1059
- );
1060
-
1061
- // 8. sdd-quality-check - Code quality analysis
1062
- server.registerTool(
1063
- "sdd-quality-check",
1064
- {
1065
- title: "Code Quality Analysis",
1066
- description: "Code quality analysis",
1067
- inputSchema: {
1068
- code: z.string().describe("Code to analyze"),
1069
- language: z
1070
- .string()
1071
- .optional()
1072
- .describe("Programming language (default: javascript)"),
1073
- },
1074
- },
1075
- async ({ code, language = "javascript" }) => {
1076
- try {
1077
- // Simple quality analysis (Linus-style 5-layer approach)
1078
- const lines = code.split("\n");
1079
- const issues = [];
1080
-
1081
- // Layer 1: Syntax and Basic Structure
1082
- if (code.includes("console.log")) {
1083
- issues.push("L1: Remove debug console.log statements");
1084
- }
1085
- if (code.includes("var ")) {
1086
- issues.push("L1: Use let/const instead of var");
1087
- }
1088
-
1089
- // Layer 2: Code Style and Conventions
1090
- if (!/^[a-z]/.test(code.split("function ")[1]?.split("(")[0] || "")) {
1091
- if (code.includes("function ")) {
1092
- issues.push("L2: Function names should start with lowercase");
1093
- }
1094
- }
1095
-
1096
- // Layer 3: Logic and Algorithm
1097
- if (code.includes("for") && !code.includes("const")) {
1098
- issues.push(
1099
- "L3: Consider using const in for loops for immutable iteration variables",
1100
- );
1101
- }
1102
-
1103
- // Layer 4: Architecture and Design
1104
- if (lines.length > 50) {
1105
- issues.push(
1106
- "L4: Function/module is too long, consider breaking into smaller parts",
1107
- );
1108
- }
1109
-
1110
- // Layer 5: Business Logic and Requirements
1111
- if (!code.includes("error") && code.includes("try")) {
1112
- issues.push("L5: Missing proper error handling in try block");
1113
- }
1114
-
1115
- const qualityScore = Math.max(0, 100 - issues.length * 15);
1116
-
1117
- let report = `## Linus-Style Code Quality Analysis\n\n`;
1118
- report += `**Language**: ${language}\n`;
1119
- report += `**Lines of Code**: ${lines.length}\n`;
1120
- report += `**Quality Score**: ${qualityScore}/100\n\n`;
1121
-
1122
- if (issues.length === 0) {
1123
- report += `**Status**: ✅ Code quality is excellent\n\n`;
1124
- report += `**Analysis**: No significant issues found. Code follows good practices.`;
1125
- } else {
1126
- report += `**Issues Found**: ${issues.length}\n\n`;
1127
- report += `**Quality Issues**:\n`;
1128
- for (const issue of issues) {
1129
- report += `- ${issue}\n`;
1130
- }
1131
- report += `\n**Recommendation**: Address the identified issues to improve code quality.`;
1132
- }
1133
-
1134
- return {
1135
- content: [
1136
- {
1137
- type: "text",
1138
- text: report,
1139
- },
1140
- ],
1141
- };
1142
- } catch (error) {
1143
- return {
1144
- content: [
1145
- {
1146
- type: "text",
1147
- text: `Error analyzing code quality: ${error.message}`,
1148
- },
1149
- ],
1150
- };
1151
- }
1152
- },
1153
- );
1154
-
1155
- // 9. sdd-context-load - Load project context
1156
- server.registerTool(
1157
- "sdd-context-load",
1158
- {
1159
- title: "Load Project Context",
1160
- description: "Load project context",
1161
- inputSchema: {
1162
- featureName: z.string().describe("Feature name to load context for"),
1163
- },
1164
- },
1165
- async ({ featureName }) => {
1166
- try {
1167
- const currentPath = process.cwd();
1168
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
1169
-
1170
- // Load all context files
1171
- const files = ["spec.json", "requirements.md", "design.md", "tasks.md"];
1172
- const context = {};
1173
-
1174
- for (const file of files) {
1175
- const filePath = path.join(featurePath, file);
1176
- const fileExists = await fs
1177
- .access(filePath)
1178
- .then(() => true)
1179
- .catch(() => false);
1180
-
1181
- if (fileExists) {
1182
- const content = await fs.readFile(filePath, "utf8");
1183
- context[file] = file.endsWith(".json")
1184
- ? JSON.parse(content)
1185
- : content;
1186
- }
1187
- }
1188
-
1189
- let contextReport = `## Project Context Loaded: ${featureName}\n\n`;
1190
-
1191
- if (context["spec.json"]) {
1192
- const spec = context["spec.json"];
1193
- contextReport += `**Project Metadata**:\n`;
1194
- contextReport += `- Feature: ${spec.feature_name}\n`;
1195
- contextReport += `- Phase: ${spec.phase}\n`;
1196
- contextReport += `- Language: ${spec.language}\n`;
1197
- contextReport += `- Ready for Implementation: ${spec.ready_for_implementation ? "Yes" : "No"}\n\n`;
1198
- }
1199
-
1200
- contextReport += `**Available Documents**:\n`;
1201
- for (const [file, content] of Object.entries(context)) {
1202
- if (file !== "spec.json") {
1203
- const preview =
1204
- typeof content === "string"
1205
- ? content.substring(0, 100) + "..."
1206
- : "JSON data";
1207
- contextReport += `- **${file}**: ${preview}\n`;
1208
- }
1209
- }
1210
-
1211
- contextReport += `\n**Context Status**: Project memory restored successfully\n`;
1212
- contextReport += `**Total Files Loaded**: ${Object.keys(context).length}`;
1213
-
1214
- return {
1215
- content: [
1216
- {
1217
- type: "text",
1218
- text: contextReport,
1219
- },
1220
- ],
1221
- };
1222
- } catch (error) {
1223
- return {
1224
- content: [
1225
- {
1226
- type: "text",
1227
- text: `Error loading project context: ${error.message}`,
1228
- },
1229
- ],
1230
- };
1231
- }
1232
- },
1233
- );
1234
-
1235
- // 10. sdd-template-render - Render templates
1236
- server.registerTool(
1237
- "sdd-template-render",
1238
- {
1239
- title: "Render Templates",
1240
- description: "Render templates",
1241
- inputSchema: {
1242
- templateType: z
1243
- .enum(["requirements", "design", "tasks", "custom"])
1244
- .describe("Type of template to render"),
1245
- featureName: z.string().describe("Feature name for template context"),
1246
- customTemplate: z
1247
- .string()
1248
- .optional()
1249
- .describe("Custom template content (if templateType is custom)"),
1250
- },
1251
- },
1252
- async ({ templateType, featureName, customTemplate }) => {
1253
- try {
1254
- const currentPath = process.cwd();
1255
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
1256
- const specPath = path.join(featurePath, "spec.json");
1257
-
1258
- // Load spec for context
1259
- const specExists = await fs
1260
- .access(specPath)
1261
- .then(() => true)
1262
- .catch(() => false);
1263
- let spec = {};
1264
- if (specExists) {
1265
- const specContent = await fs.readFile(specPath, "utf8");
1266
- spec = JSON.parse(specContent);
1267
- }
1268
-
1269
- let renderedContent = "";
1270
-
1271
- switch (templateType) {
1272
- case "requirements":
1273
- 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)`;
1274
- break;
1275
-
1276
- case "design":
1277
- 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`;
1278
- break;
1279
-
1280
- case "tasks":
1281
- 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`;
1282
- break;
1283
-
1284
- case "custom":
1285
- if (!customTemplate) {
1286
- throw new Error(
1287
- "Custom template content is required for custom template type",
1288
- );
1289
- }
1290
- // Simple template variable replacement
1291
- renderedContent = customTemplate
1292
- .replace(/\{\{featureName\}\}/g, featureName)
1293
- .replace(/\{\{language\}\}/g, spec.language || "en")
1294
- .replace(/\{\{phase\}\}/g, spec.phase || "initialized")
1295
- .replace(/\{\{timestamp\}\}/g, new Date().toISOString());
1296
- break;
1297
- }
1298
-
1299
- return {
1300
- content: [
1301
- {
1302
- type: "text",
1303
- 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`,
1304
- },
1305
- ],
1306
- };
1307
- } catch (error) {
1308
- return {
1309
- content: [
1310
- {
1311
- type: "text",
1312
- text: `Error rendering template: ${error.message}`,
1313
- },
1314
- ],
1315
- };
1316
- }
1317
- },
1318
- );
1319
-
1320
- // 11. sdd-steering - Create/update steering documents
1321
- server.registerTool(
1322
- "sdd-steering",
1323
- {
1324
- title: "Create/Update Steering Documents",
1325
- description: "Create or update steering documents",
1326
- inputSchema: {
1327
- updateMode: z
1328
- .enum(["create", "update"])
1329
- .optional()
1330
- .describe(
1331
- "Whether to create new or update existing documents (auto-detected if not specified)",
1332
- ),
1333
- },
1334
- },
1335
- async ({ updateMode }) => {
1336
- try {
1337
- const currentPath = process.cwd();
1338
- const steeringPath = path.join(currentPath, ".spec", "steering");
1339
-
1340
- // Create steering directory if it doesn't exist
1341
- await fs.mkdir(steeringPath, { recursive: true });
1342
-
1343
- // Analyze existing files
1344
- const productExists = await fs
1345
- .access(path.join(steeringPath, "product.md"))
1346
- .then(() => true)
1347
- .catch(() => false);
1348
- const techExists = await fs
1349
- .access(path.join(steeringPath, "tech.md"))
1350
- .then(() => true)
1351
- .catch(() => false);
1352
- const structureExists = await fs
1353
- .access(path.join(steeringPath, "structure.md"))
1354
- .then(() => true)
1355
- .catch(() => false);
1356
-
1357
- // Auto-detect mode if not specified
1358
- if (!updateMode) {
1359
- updateMode =
1360
- productExists || techExists || structureExists ? "update" : "create";
1361
- }
1362
-
1363
- // Generate actual analyzed content using documentGenerator functions
1364
- const analysis = await analyzeProject(currentPath);
1365
- const productContent = generateProductDocument(analysis);
1366
- const techContent = generateTechDocument(analysis);
1367
- const structureContent = generateStructureDocument(analysis);
1368
-
1369
- // Write the analyzed steering documents
1370
- await fs.writeFile(path.join(steeringPath, "product.md"), productContent);
1371
- await fs.writeFile(path.join(steeringPath, "tech.md"), techContent);
1372
- await fs.writeFile(
1373
- path.join(steeringPath, "structure.md"),
1374
- structureContent,
1375
- );
1376
-
1377
- // Ensure static steering docs exist (full content)
1378
- const linusPath = path.join(steeringPath, "linus-review.md");
1379
- const linusExists = await fs
1380
- .access(linusPath)
1381
- .then(() => true)
1382
- .catch(() => false);
1383
- if (!linusExists) {
1384
- const fullLinusContent = `# Linus Torvalds Code Review Steering Document
1385
-
1386
- ## Role Definition
1387
-
1388
- You are channeling Linus Torvalds, creator and chief architect of the Linux kernel. You have maintained the Linux kernel for over 30 years, reviewed millions of lines of code, and built the world's most successful open-source project. Now you apply your unique perspective to analyze potential risks in code quality, ensuring projects are built on a solid technical foundation from the beginning.
1389
-
1390
- ## Core Philosophy
1391
-
1392
- **1. "Good Taste" - The First Principle**
1393
- "Sometimes you can look at a problem from a different angle, rewrite it to make special cases disappear and become normal cases."
1394
- - Classic example: Linked list deletion, optimized from 10 lines with if statements to 4 lines without conditional branches
1395
- - Good taste is an intuition that requires accumulated experience
1396
- - Eliminating edge cases is always better than adding conditional checks
1397
-
1398
- **2. "Never break userspace" - The Iron Rule**
1399
- "We do not break userspace!"
1400
- - Any change that crashes existing programs is a bug, no matter how "theoretically correct"
1401
- - The kernel's duty is to serve users, not educate them
1402
- - Backward compatibility is sacred and inviolable
1403
-
1404
- **3. Pragmatism - The Belief**
1405
- "I'm a damn pragmatist."
1406
- - Solve actual problems, not imagined threats
1407
- - Reject "theoretically perfect" but practically complex solutions like microkernels
1408
- - Code should serve reality, not papers
1409
-
1410
- **4. Simplicity Obsession - The Standard**
1411
- "If you need more than 3 levels of indentation, you're screwed and should fix your program."
1412
- - Functions must be short and focused, do one thing and do it well
1413
- - C is a Spartan language, naming should be too
1414
- - Complexity is the root of all evil
1415
-
1416
- ## Communication Principles
1417
-
1418
- ### Basic Communication Standards
1419
-
1420
- - **Expression Style**: Direct, sharp, zero nonsense. If code is garbage, call it garbage and explain why.
1421
- - **Technical Priority**: Criticism is always about technical issues, not personal. Don't blur technical judgment for "niceness."
1422
-
1423
- ### Requirements Confirmation Process
1424
-
1425
- When analyzing any code or technical need, follow these steps:
1426
-
1427
- #### 0. **Thinking Premise - Linus's Three Questions**
1428
- Before starting any analysis, ask yourself:
1429
- 1. "Is this a real problem or imagined?" - Reject over-engineering
1430
- 2. "Is there a simpler way?" - Always seek the simplest solution
1431
- 3. "Will it break anything?" - Backward compatibility is the iron rule
1432
-
1433
- #### 1. **Requirements Understanding**
1434
- Based on the existing information, understand the requirement and restate it using Linus's thinking/communication style.
1435
-
1436
- #### 2. **Linus-style Problem Decomposition Thinking**
1437
-
1438
- **First Layer: Data Structure Analysis**
1439
- "Bad programmers worry about the code. Good programmers worry about data structures."
1440
-
1441
- - What is the core data? How do they relate?
1442
- - Where does data flow? Who owns it? Who modifies it?
1443
- - Is there unnecessary data copying or transformation?
1444
-
1445
- **Second Layer: Special Case Identification**
1446
- "Good code has no special cases"
1447
-
1448
- - Find all if/else branches
1449
- - Which are real business logic? Which are patches for bad design?
1450
- - Can we redesign data structures to eliminate these branches?
1451
-
1452
- **Third Layer: Complexity Review**
1453
- "If implementation needs more than 3 levels of indentation, redesign it"
1454
-
1455
- - What's the essence of this feature? (Explain in one sentence)
1456
- - How many concepts does the current solution use?
1457
- - Can it be reduced by half? Half again?
1458
-
1459
- **Fourth Layer: Breaking Change Analysis**
1460
- "Never break userspace" - Backward compatibility is the iron rule
1461
-
1462
- - List all existing features that might be affected
1463
- - Which dependencies will break?
1464
- - How to improve without breaking anything?
1465
-
1466
- **Fifth Layer: Practicality Validation**
1467
- "Theory and practice sometimes clash. Theory loses. Every single time."
1468
-
1469
- - Does this problem really exist in production?
1470
- - How many users actually encounter this problem?
1471
- - Does the solution's complexity match the problem's severity?
1472
-
1473
- ## Decision Output Pattern
1474
-
1475
- After the above 5 layers of thinking, output must include:
1476
-
1477
- \`\`\`
1478
- 【Core Judgment】
1479
- ✅ Worth doing: [reason] / ❌ Not worth doing: [reason]
1480
-
1481
- 【Key Insights】
1482
- - Data structure: [most critical data relationships]
1483
- - Complexity: [complexity that can be eliminated]
1484
- - Risk points: [biggest breaking risk]
1485
-
1486
- 【Linus-style Solution】
1487
- If worth doing:
1488
- 1. First step is always simplifying data structures
1489
- 2. Eliminate all special cases
1490
- 3. Implement in the dumbest but clearest way
1491
- 4. Ensure zero breaking changes
1492
-
1493
- If not worth doing:
1494
- "This is solving a non-existent problem. The real problem is [XXX]."
1495
- \`\`\`
1496
-
1497
- ## Code Review Output
1498
-
1499
- When reviewing code, immediately make three-level judgment:
1500
-
1501
- \`\`\`
1502
- 【Taste Score】
1503
- 🟢 Good taste / 🟡 Passable / 🔴 Garbage
1504
-
1505
- 【Fatal Issues】
1506
- - [If any, directly point out the worst parts]
1507
-
1508
- 【Improvement Direction】
1509
- "Eliminate this special case"
1510
- "These 10 lines can become 3 lines"
1511
- "Data structure is wrong, should be..."
1512
- \`\`\`
1513
-
1514
- ## Integration with SDD Workflow
1515
-
1516
- ### Requirements Phase
1517
- Apply Linus's 5-layer thinking to validate if requirements solve real problems and can be implemented simply.
1518
-
1519
- ### Design Phase
1520
- Focus on data structures first, eliminate special cases, ensure backward compatibility.
1521
-
1522
- ### Implementation Phase
1523
- Enforce simplicity standards: short functions, minimal indentation, clear naming.
1524
-
1525
- ### Code Review
1526
- Apply Linus's taste criteria to identify and eliminate complexity, special cases, and potential breaking changes.
1527
-
1528
- ## Usage in SDD Commands
1529
-
1530
- This steering document is applied when:
1531
- - Generating requirements: Validate problem reality and simplicity
1532
- - Creating technical design: Data-first approach, eliminate edge cases
1533
- - Implementation guidance: Enforce simplicity and compatibility
1534
- - Code review: Apply taste scoring and improvement recommendations
1535
-
1536
- Remember: "Good taste" comes from experience. Question everything. Simplify ruthlessly. Never break userspace.`;
1537
- await fs.writeFile(linusPath, fullLinusContent);
1538
- }
1539
- const commitPath = path.join(steeringPath, "commit.md");
1540
- const commitExists = await fs
1541
- .access(commitPath)
1542
- .then(() => true)
1543
- .catch(() => false);
1544
- if (!commitExists) {
1545
- const fullCommitContent = `# Commit Message Guidelines
1546
-
1547
- 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.
1548
-
1549
- ## Format
1550
-
1551
- \`\`\`
1552
- <type>(<scope>): <subject>
1553
-
1554
- <body>
1555
-
1556
- <footer>
1557
- \`\`\`
1558
-
1559
- ## Type Prefixes
1560
-
1561
- All commit messages must begin with one of these type prefixes:
1562
-
1563
- - **docs**: Documentation changes (README, comments, etc.)
1564
- - **chore**: Maintenance tasks, dependency updates, etc.
1565
- - **feat**: New features or enhancements
1566
- - **fix**: Bug fixes
1567
- - **refactor**: Code changes that neither fix bugs nor add features
1568
- - **test**: Adding or modifying tests
1569
- - **style**: Changes that don't affect code functionality (formatting, whitespace)
1570
- - **perf**: Performance improvements
1571
- - **ci**: Changes to CI/CD configuration files and scripts
1572
-
1573
- ## Scope (Optional)
1574
-
1575
- The scope provides additional context about which part of the codebase is affected:
1576
-
1577
- - **cluster**: Changes to EKS cluster configuration
1578
- - **db**: Database-related changes
1579
- - **iam**: Identity and access management changes
1580
- - **net**: Networking changes (VPC, security groups, etc.)
1581
- - **k8s**: Kubernetes resource changes
1582
- - **module**: Changes to reusable Terraform modules
1583
-
1584
- ## Examples
1585
-
1586
- \`\`\`
1587
- feat(cluster): add node autoscaling for billing namespace
1588
- fix(db): correct MySQL parameter group settings
1589
- docs(k8s): update network policy documentation
1590
- chore: update terraform provider versions
1591
- refactor(module): simplify EKS node group module
1592
- \`\`\`
1593
-
1594
- ## Best Practices
1595
-
1596
- 1. Keep the subject line under 72 characters
1597
- 2. Use imperative mood in the subject line ("add" not "added")
1598
- 3. Don't end the subject line with a period
1599
- 4. Separate subject from body with a blank line
1600
- 5. Use the body to explain what and why, not how
1601
- 6. Reference issues and pull requests in the footer
1602
-
1603
- These guidelines help maintain a clean and useful git history that makes it easier to track changes and understand the project's evolution.`;
1604
- await fs.writeFile(commitPath, fullCommitContent);
1605
- }
1606
-
1607
- // Ensure AGENTS.md exists in steering directory (create from CLAUDE.md if available)
1608
- const agentsPath = path.join(steeringPath, "AGENTS.md");
1609
- const claudePath = path.join(currentPath, "CLAUDE.md");
1610
- const agentsExists = await fs
1611
- .access(agentsPath)
1612
- .then(() => true)
1613
- .catch(() => false);
1614
- if (!agentsExists) {
1615
- let agentsContent = "";
1616
- const claudeExists = await fs
1617
- .access(claudePath)
1618
- .then(() => true)
1619
- .catch(() => false);
1620
- if (claudeExists) {
1621
- const claude = await fs.readFile(claudePath, "utf8");
1622
- agentsContent = claude
1623
- .replace(
1624
- /# Claude Code Spec-Driven Development/g,
1625
- "# AI Agent Spec-Driven Development",
1626
- )
1627
- .replace(/Claude Code/g, "AI Agent")
1628
- .replace(/claude code/g, "ai agent")
1629
- .replace(/\.claude\//g, ".ai agent/")
1630
- .replace(/\/claude/g, "/agent");
1631
- } else {
1632
- agentsContent = `# AI Agent Spec-Driven Development
1633
-
1634
- Kiro-style Spec Driven Development implementation using ai agent slash commands, hooks and agents.
1635
-
1636
- ## Project Context
1637
-
1638
- ### Paths
1639
- - Steering: \`.spec/steering/\`
1640
- - Specs: \`.spec/specs/\`
1641
- - Commands: \`.ai agent/commands/\`
1642
-
1643
- ### Steering vs Specification
1644
-
1645
- **Steering** (\`.spec/steering/\`) - Guide AI with project-wide rules and context
1646
- **Specs** (\`.spec/specs/\`) - Formalize development process for individual features
1647
-
1648
- ### Active Specifications
1649
- - Check \`.spec/specs/\` for active specifications
1650
- - Use \`/kiro:spec-status [feature-name]\` to check progress
1651
-
1652
- **Current Specifications:**
1653
- - \`mcp-sdd-server\`: MCP server for spec-driven development across AI-agent CLIs and IDEs
1654
-
1655
- ## Development Guidelines
1656
- - Think in English, generate responses in English
1657
-
1658
- ## Workflow
1659
-
1660
- ### Phase 0: Steering (Optional)
1661
- \`/kiro:steering\` - Create/update steering documents
1662
- \`/kiro:steering-custom\` - Create custom steering for specialized contexts
1663
-
1664
- Note: Optional for new features or small additions. You can proceed directly to spec-init.
1665
-
1666
- ### Phase 1: Specification Creation
1667
- 1. \`/kiro:spec-init [detailed description]\` - Initialize spec with detailed project description
1668
- 2. \`/kiro:spec-requirements [feature]\` - Generate requirements document
1669
- 3. \`/kiro:spec-design [feature]\` - Interactive: "Have you reviewed requirements.md? [y/N]"
1670
- 4. \`/kiro:spec-tasks [feature]\` - Interactive: Confirms both requirements and design review
1671
-
1672
- ### Phase 2: Progress Tracking
1673
- \`/kiro:spec-status [feature]\` - Check current progress and phases
1674
-
1675
- ## Development Rules
1676
- 1. **Consider steering**: Run \`/kiro:steering\` before major development (optional for new features)
1677
- 2. **Follow 3-phase approval workflow**: Requirements → Design → Tasks → Implementation
1678
- 3. **Approval required**: Each phase requires human review (interactive prompt or manual)
1679
- 4. **No skipping phases**: Design requires approved requirements; Tasks require approved design
1680
- 5. **Update task status**: Mark tasks as completed when working on them
1681
- 6. **Keep steering current**: Run \`/kiro:steering\` after significant changes
1682
- 7. **Check spec compliance**: Use \`/kiro:spec-status\` to verify alignment
1683
-
1684
- ## Steering Configuration
1685
-
1686
- ### Current Steering Files
1687
- Managed by \`/kiro:steering\` command. Updates here reflect command changes.
1688
-
1689
- ### Active Steering Files
1690
- - \`product.md\`: Always included - Product context and business objectives
1691
- - \`tech.md\`: Always included - Technology stack and architectural decisions
1692
- - \`structure.md\`: Always included - File organization and code patterns
1693
- - \`linus-review.md\`: Always included - Ensuring code quality of the projects
1694
- - \`commit.md\`: Always included - Ensuring the commit / merge request / pull request title and message context.
1695
-
1696
- ### Custom Steering Files
1697
- <!-- Added by /kiro:steering-custom command -->
1698
- <!-- Format:
1699
- - \`filename.md\`: Mode - Pattern(s) - Description
1700
- Mode: Always|Conditional|Manual
1701
- Pattern: File patterns for Conditional mode
1702
- -->
1703
-
1704
- ### Inclusion Modes
1705
- - **Always**: Loaded in every interaction (default)
1706
- - **Conditional**: Loaded for specific file patterns (e.g., "*.test.js")
1707
- - **Manual**: Reference with \`@filename.md\` syntax`;
1708
- }
1709
- await fs.writeFile(agentsPath, agentsContent);
1710
- }
1711
-
1712
- // Ensure security-check.md exists (static)
1713
- const securityPath = path.join(steeringPath, "security-check.md");
1714
- const securityExists = await fs
1715
- .access(securityPath)
1716
- .then(() => true)
1717
- .catch(() => false);
1718
- if (!securityExists) {
1719
- const securityContent = `# Security Check (OWASP Top 10 Aligned)
1720
-
1721
- Use this checklist during code generation and review. Avoid OWASP Top 10 issues by design.
1722
-
1723
- ## A01: Broken Access Control
1724
- - Enforce least privilege; validate authorization on every request/path
1725
- - No client-side trust; never rely on hidden fields or disabled UI
1726
-
1727
- ## A02: Cryptographic Failures
1728
- - Use HTTPS/TLS; do not roll your own crypto
1729
- - Store secrets in env vars/secret stores; never commit secrets
1730
-
1731
- ## A03: Injection
1732
- - Use parameterized queries/ORM and safe template APIs
1733
- - Sanitize/validate untrusted input; avoid string concatenation in queries
1734
-
1735
- ## A04: Insecure Design
1736
- - Threat model critical flows; add security requirements to design
1737
- - Fail secure; disable features by default until explicitly enabled
1738
-
1739
- ## A05: Security Misconfiguration
1740
- - Disable debug modes in prod; set secure headers (CSP, HSTS, X-Content-Type-Options)
1741
- - Pin dependencies and lock versions; no default credentials
1742
-
1743
- ## A06: Vulnerable & Outdated Components
1744
- - Track SBOM/dependencies; run npm audit or a scanner regularly and patch
1745
- - Prefer maintained libraries; remove unused deps
1746
-
1747
- ## A07: Identification & Authentication Failures
1748
- - Use vetted auth (OIDC/OAuth2); enforce MFA where applicable
1749
- - Secure session handling (HttpOnly, Secure, SameSite cookies)
1750
-
1751
- ## A08: Software & Data Integrity Failures
1752
- - Verify integrity of third-party artifacts; signed releases when possible
1753
- - Protect CI/CD: signed commits/tags, restricted tokens, principle of least privilege
1754
-
1755
- ## A09: Security Logging & Monitoring Failures
1756
- - Log authz/authn events and errors without sensitive data
1757
- - Add alerts for suspicious activity; retain logs per policy
1758
-
1759
- ## A10: Server-Side Request Forgery (SSRF)
1760
- - Validate/deny-list outbound destinations; no direct fetch to arbitrary URLs
1761
- - Use network egress controls; fetch via vetted proxies when needed
1762
-
1763
- ## General Practices
1764
- - Validate inputs (schema, length, type) and outputs (encoding)
1765
- - Handle errors without leaking stack traces or secrets
1766
- - Use content security best practices for templates/HTML
1767
- - Add security tests where feasible (authz, input validation)
1768
- `;
1769
- await fs.writeFile(securityPath, securityContent);
1770
- }
1771
-
1772
- const tddPath = path.join(steeringPath, "tdd-guideline.md");
1773
- const tddExists = await fs
1774
- .access(tddPath)
1775
- .then(() => true)
1776
- .catch(() => false);
1777
- if (!tddExists) {
1778
- const tddContent = `# Test-Driven Development (TDD) Guideline
1779
-
1780
- ## Purpose
1781
- This steering document defines TDD practices and workflow to ensure test-first development throughout the project lifecycle.
1782
-
1783
- ## TDD Fundamentals
1784
-
1785
- ### Red-Green-Refactor Cycle
1786
- 1. **Red**: Write a failing test that defines desired behavior
1787
- 2. **Green**: Write minimal code to make the test pass
1788
- 3. **Refactor**: Improve code quality while keeping tests green
1789
-
1790
- ### Core Principles
1791
- - Write tests before implementation code
1792
- - Test one thing at a time
1793
- - Keep tests simple, readable, and maintainable
1794
- - Run tests frequently during development
1795
- - Never commit failing tests
1796
-
1797
- ## Test-First Development Approach
1798
-
1799
- ### Before Writing Code
1800
- 1. Understand the requirement/user story
1801
- 2. Define expected behavior and edge cases
1802
- 3. Write test cases that verify the behavior
1803
- 4. Run tests to confirm they fail (Red phase)
1804
-
1805
- ### Implementation Flow
1806
- \`\`\`
1807
- Requirement → Test Case → Failing Test → Implementation → Passing Test → Refactor → Commit
1808
- \`\`\`
1809
-
1810
- ### Test Pyramid Strategy
1811
- - **Unit Tests (70%)**: Test individual functions/methods in isolation
1812
- - **Integration Tests (20%)**: Test component interactions and workflows
1813
- - **E2E Tests (10%)**: Test complete user scenarios
1814
-
1815
- ## Test Organization
1816
-
1817
- ### Directory Structure
1818
- \`\`\`
1819
- src/
1820
- ├── module/
1821
- │ ├── service.ts
1822
- │ └── service.test.ts # Unit tests co-located
1823
- └── __tests__/
1824
- ├── integration/ # Integration tests
1825
- └── e2e/ # End-to-end tests
1826
- \`\`\`
1827
-
1828
- ### Naming Conventions
1829
- - Test files: \`*.test.ts\` or \`*.spec.ts\`
1830
- - Test suites: \`describe('ComponentName', () => {...})\`
1831
- - Test cases: \`it('should behave in expected way', () => {...})\` or \`test('description', () => {...})\`
1832
- - Use clear, descriptive names that explain what is being tested
1833
-
1834
- ## Coverage Requirements
1835
-
1836
- ### Minimum Thresholds
1837
- - **Overall Coverage**: ≥ 80%
1838
- - **Statements**: ≥ 80%
1839
- - **Branches**: ≥ 75%
1840
- - **Functions**: ≥ 80%
1841
- - **Lines**: ≥ 80%
1842
-
1843
- ### Critical Code Requirements
1844
- - All public APIs: 100% coverage
1845
- - Business logic: ≥ 90% coverage
1846
- - Error handling: All error paths tested
1847
- - Edge cases: All identified edge cases tested
1848
-
1849
- ## Best Practices
1850
-
1851
- ### Writing Good Tests
1852
- - **Arrange-Act-Assert (AAA)**: Structure tests clearly
1853
- - **Single Assertion**: Focus each test on one behavior
1854
- - **Independence**: Tests should not depend on each other
1855
- - **Repeatability**: Tests should produce same results every time
1856
- - **Fast Execution**: Keep tests fast (< 100ms for unit tests)
1857
-
1858
- ### Test Data Management
1859
- - Use factories or builders for test data creation
1860
- - Avoid hardcoded values; use constants or fixtures
1861
- - Clean up test data after execution
1862
- - Mock external dependencies (APIs, databases, file system)
1863
-
1864
- ### Mocking and Stubbing
1865
- - Mock external dependencies to isolate unit under test
1866
- - Use dependency injection to enable testability
1867
- - Stub time-dependent functions for deterministic tests
1868
- - Verify mock interactions when testing behavior
1869
-
1870
- ### Assertion Guidelines
1871
- - Use specific, meaningful assertions
1872
- - Prefer semantic matchers (\`toEqual\`, \`toContain\`, \`toThrow\`)
1873
- - Include error messages for custom assertions
1874
- - Test both positive and negative cases
1875
-
1876
- ## Anti-Patterns to Avoid
1877
-
1878
- ### Test Smells
1879
- - ❌ **Testing Implementation Details**: Test behavior, not internals
1880
- - ❌ **Fragile Tests**: Tests that break with minor refactoring
1881
- - ❌ **Slow Tests**: Tests that take too long to execute
1882
- - ❌ **Flaky Tests**: Tests with inconsistent results
1883
- - ❌ **Overmocking**: Excessive mocking that tests mocks instead of code
1884
-
1885
- ### Bad Practices
1886
- - ❌ Writing tests after code is complete
1887
- - ❌ Skipping tests for "simple" functions
1888
- - ❌ Ignoring failing tests
1889
- - ❌ Writing tests that depend on execution order
1890
- - ❌ Testing framework code instead of application code
1891
-
1892
- ## Integration with SDD Workflow
1893
-
1894
- ### Requirements Phase
1895
- - Define testability requirements
1896
- - Identify test scenarios in acceptance criteria
1897
- - Document edge cases that need testing
1898
- - Specify performance/quality test requirements
1899
-
1900
- ### Design Phase
1901
- - Design for testability (SOLID principles)
1902
- - Plan test strategy (unit/integration/e2e mix)
1903
- - Identify mockable dependencies
1904
- - Document test data requirements
1905
-
1906
- ### Tasks Phase
1907
- - Break down implementation tasks with test-first approach
1908
- - Each task includes: Write test → Implement → Refactor
1909
- - Estimate includes time for writing tests
1910
- - Define "done" criteria including test coverage
1911
-
1912
- ### Implementation Phase
1913
- - Follow TDD cycle strictly: Red → Green → Refactor
1914
- - Write failing test before any production code
1915
- - Run tests continuously (watch mode recommended)
1916
- - Commit only when all tests pass
1917
-
1918
- ### Code Review Phase
1919
- - Verify test coverage meets thresholds
1920
- - Review test quality and clarity
1921
- - Check for test smells and anti-patterns
1922
- - Ensure tests validate requirements
1923
-
1924
- ## Testing Tools and Configuration
1925
-
1926
- ### Recommended Tools
1927
- - **Test Framework**: Jest (for JavaScript/TypeScript projects)
1928
- - **Assertion Library**: Jest built-in matchers
1929
- - **Mocking**: Jest mock functions
1930
- - **Coverage**: Jest coverage reporting
1931
- - **Watch Mode**: \`npm test -- --watch\`
1932
-
1933
- ### Running Tests
1934
- \`\`\`bash
1935
- # Run all tests
1936
- npm test
1937
-
1938
- # Run tests in watch mode
1939
- npm test -- --watch
1940
-
1941
- # Run with coverage
1942
- npm test -- --coverage
1943
-
1944
- # Run specific test file
1945
- npm test path/to/test.test.ts
1946
- \`\`\`
1947
-
1948
- ## Quality Gates
1949
-
1950
- ### Pre-Commit
1951
- - All tests must pass
1952
- - Coverage thresholds must be met
1953
- - No skipped or pending tests
1954
-
1955
- ### Pre-Merge
1956
- - Full test suite passes
1957
- - Integration tests pass
1958
- - Coverage report reviewed
1959
- - No decrease in coverage percentage
1960
-
1961
- ### Continuous Integration
1962
- - Automated test execution on every push
1963
- - Coverage reporting in CI pipeline
1964
- - Block merge if tests fail
1965
- - Publish test results for visibility
1966
-
1967
- ## TDD Benefits
1968
-
1969
- ### Code Quality
1970
- - Higher code quality through upfront design
1971
- - Better error handling (tested edge cases)
1972
- - More maintainable code
1973
- - Self-documenting through tests
1974
-
1975
- ### Development Speed
1976
- - Faster debugging (tests pinpoint issues)
1977
- - Confident refactoring with safety net
1978
- - Reduced regression bugs
1979
- - Earlier defect detection
1980
-
1981
- ### Design Improvement
1982
- - Forces modular, testable design
1983
- - Encourages loose coupling
1984
- - Promotes single responsibility
1985
- - Results in cleaner interfaces
1986
-
1987
- ## Getting Started with TDD
1988
-
1989
- ### For New Features
1990
- 1. Read and understand the requirement
1991
- 2. Write test cases covering expected behavior
1992
- 3. Run tests to see them fail
1993
- 4. Implement minimal code to pass tests
1994
- 5. Refactor and improve while keeping tests green
1995
- 6. Commit when all tests pass
1996
-
1997
- ### For Bug Fixes
1998
- 1. Write a test that reproduces the bug (failing test)
1999
- 2. Fix the bug to make test pass
2000
- 3. Add additional tests for related edge cases
2001
- 4. Refactor if needed
2002
- 5. Commit fix with passing tests
2003
-
2004
- ### For Legacy Code
2005
- 1. Identify the module/function to modify
2006
- 2. Write characterization tests (document current behavior)
2007
- 3. Refactor for testability if needed
2008
- 4. Add new tests for new behavior
2009
- 5. Implement changes following TDD cycle
2010
- 6. Ensure all tests pass
2011
-
2012
- ## Continuous Improvement
2013
- - Review test failures to improve test quality
2014
- - Refactor tests as code evolves
2015
- - Update coverage thresholds as project matures
2016
- - Share TDD learnings with team
2017
- - Celebrate improved code quality metrics
2018
-
2019
- ## Enforcement
2020
- This document is **always** active and applies to all development phases. Every code change should follow TDD principles as defined here.
2021
- `;
2022
- await fs.writeFile(tddPath, tddContent);
2023
- }
2024
-
2025
- const principlesPath = path.join(steeringPath, "principles.md");
2026
- const principlesExists = await fs
2027
- .access(principlesPath)
2028
- .then(() => true)
2029
- .catch(() => false);
2030
- if (!principlesExists) {
2031
- const principlesContent = `# Core Coding Principles and Patterns
2032
-
2033
- Follow SOLID, DRY, KISS, YAGNI, Separation of Concerns, and Modularity in all code.
2034
-
2035
- ## SOLID Principles
2036
- - **S**ingle Responsibility: One class, one reason to change
2037
- - **O**pen/Closed: Open for extension, closed for modification
2038
- - **L**iskov Substitution: Subtypes must be substitutable for base types
2039
- - **I**nterface Segregation: Small, focused interfaces
2040
- - **D**ependency Inversion: Depend on abstractions, not concretions
2041
-
2042
- ## DRY (Don't Repeat Yourself)
2043
- Extract common logic. Every knowledge piece has one authoritative representation.
2044
-
2045
- ## KISS (Keep It Simple, Stupid)
2046
- Simplicity over complexity. Avoid over-engineering.
2047
-
2048
- ## YAGNI (You Aren't Gonna Need It)
2049
- Implement only what's needed now. No speculative features.
2050
-
2051
- ## Separation of Concerns
2052
- Separate presentation, business logic, and data access layers.
2053
-
2054
- ## Modularity
2055
- High cohesion, low coupling. Encapsulate implementation details.
2056
-
2057
- ## Review Checklist
2058
- - [ ] Single Responsibility (SRP)
2059
- - [ ] Can extend without modifying (OCP)
2060
- - [ ] Dependencies use abstractions (DIP)
2061
- - [ ] No duplicated logic (DRY)
2062
- - [ ] Simple solution (KISS)
2063
- - [ ] Only needed features (YAGNI)
2064
- - [ ] Concerns separated (SoC)
2065
- - [ ] Modules cohesive & loosely coupled
2066
-
2067
- Refer to full principles.md for detailed examples and language-specific guidance.
2068
- `;
2069
- await fs.writeFile(principlesPath, principlesContent);
2070
- }
2071
-
2072
- const mode = updateMode === "update" ? "Updated" : "Created";
2073
-
2074
- return {
2075
- content: [
2076
- {
2077
- type: "text",
2078
- text: `## Steering Documents ${mode}
2079
-
2080
- **Project Path**: ${currentPath}
2081
- **Mode**: ${updateMode}
2082
- **Generated**: ${new Date().toISOString()}
2083
-
2084
- **${mode} Files**:
2085
- - \`.spec/steering/product.md\` - Product overview and business context (AI analysis template)
2086
- - \`.spec/steering/tech.md\` - Technology stack and development environment (AI analysis template)
2087
- - \`.spec/steering/structure.md\` - Project organization and architectural decisions (AI analysis template)
2088
- - \`.spec/steering/linus-review.md\` - Code review guidelines (full content)
2089
- - \`.spec/steering/commit.md\` - Commit message standards (full content)
2090
- - \`.spec/steering/tdd-guideline.md\` - Test-Driven Development practices and workflow (full content)
2091
- - \`.spec/steering/security-check.md\` - Security checklist aligned to OWASP Top 10 (full content)
2092
- - \`.spec/steering/AGENTS.md\` - Universal AI agent workflow guidance
2093
-
2094
- **AI-Driven Approach**:
2095
- The steering documents now contain analysis instructions for AI agents rather than hardcoded templates. This ensures:
2096
- - **Language Agnostic**: Works with any programming language or framework
2097
- - **Project Specific**: AI analyzes your actual codebase and generates appropriate content
2098
- - **Universal Compatibility**: No hardcoded assumptions about technology stack
2099
- - **Dynamic Analysis**: Content reflects your actual project structure and patterns
2100
-
2101
- **Next Steps**:
2102
- 1. The AI agent will analyze your project structure when viewing these documents
2103
- 2. AI will generate project-specific content based on actual codebase analysis
2104
- 3. Content will be tailored to your specific technology stack and architecture
2105
- 4. Documents will provide accurate, up-to-date guidance for development
2106
-
2107
- 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.`,
2108
- },
2109
- ],
2110
- };
2111
- } catch (error) {
2112
- return {
2113
- content: [
2114
- {
2115
- type: "text",
2116
- text: `Error creating/updating steering documents: ${error.message}`,
2117
- },
2118
- ],
2119
- };
2120
- }
2121
- },
2122
- );
2123
-
2124
- // 12. sdd-steering-custom - Create custom steering documents
2125
- server.registerTool(
2126
- "sdd-steering-custom",
2127
- {
2128
- title: "Create Custom Steering Document",
2129
- description: "Create custom steering documents",
2130
- inputSchema: {
2131
- fileName: z
2132
- .string()
2133
- .describe(
2134
- 'Filename for the custom steering document (e.g., "api-standards.md")',
2135
- ),
2136
- topic: z
2137
- .string()
2138
- .describe("Topic/purpose of the custom steering document"),
2139
- inclusionMode: z
2140
- .enum(["always", "conditional", "manual"])
2141
- .describe("How this steering document should be included"),
2142
- filePattern: z
2143
- .string()
2144
- .optional()
2145
- .describe(
2146
- 'File pattern for conditional inclusion (e.g., "*.test.js", "src/api/**/*")',
2147
- ),
2148
- },
2149
- },
2150
- async ({ fileName, topic, inclusionMode, filePattern }) => {
2151
- try {
2152
- const currentPath = process.cwd();
2153
- const steeringPath = path.join(currentPath, ".spec", "steering");
2154
-
2155
- // Create steering directory if it doesn't exist
2156
- await fs.mkdir(steeringPath, { recursive: true });
2157
-
2158
- // Ensure filename ends with .md
2159
- if (!fileName.endsWith(".md")) {
2160
- fileName += ".md";
2161
- }
2162
-
2163
- // Generate inclusion mode comment
2164
- let inclusionComment = "<!-- Inclusion Mode: ";
2165
- if (inclusionMode === "always") {
2166
- inclusionComment += "Always -->";
2167
- } else if (inclusionMode === "conditional") {
2168
- inclusionComment += `Conditional: "${filePattern || "**/*"}" -->`;
2169
- } else {
2170
- inclusionComment += "Manual -->";
2171
- }
2172
-
2173
- // Generate content based on topic
2174
- let content = `${inclusionComment}
2175
-
2176
- # ${topic}
2177
-
2178
- ## Purpose
2179
- This document provides specialized guidance for ${topic.toLowerCase()} within the project context.
2180
-
2181
- ## When This Document Applies
2182
- ${
2183
- inclusionMode === "conditional"
2184
- ? `This guidance applies when working with files matching: \`${filePattern || "**/*"}\``
2185
- : inclusionMode === "always"
2186
- ? "This guidance applies to all development work in this project."
2187
- : "Reference this document manually using @${fileName} when needed."
2188
- }
2189
-
2190
- ## Guidelines
2191
-
2192
- ### Key Principles
2193
- - [Add specific principles for ${topic.toLowerCase()}]
2194
- - [Include concrete rules and patterns]
2195
- - [Provide rationale for important decisions]
2196
-
2197
- ### Implementation Patterns
2198
- \`\`\`
2199
- // Example code patterns for ${topic.toLowerCase()}
2200
- // Include specific examples relevant to your project
2201
- \`\`\`
2202
-
2203
- ### Best Practices
2204
- 1. **Practice 1**: Description and rationale
2205
- 2. **Practice 2**: Description and rationale
2206
- 3. **Practice 3**: Description and rationale
2207
-
2208
- ## Integration Points
2209
- - Related to core steering: product.md, tech.md, structure.md
2210
- - Dependencies: [List any prerequisites or related documents]
2211
- - Conflicts: [Note any potential conflicts with other guidance]
2212
-
2213
- ## Examples
2214
- \`\`\`
2215
- // Concrete examples of correct implementation
2216
- // Show both correct patterns and counter-examples if helpful
2217
- \`\`\`
2218
-
2219
- ## Quality Standards
2220
- - [Specific quality criteria for ${topic.toLowerCase()}]
2221
- - [Testing requirements]
2222
- - [Review checklist items]`;
2223
-
2224
- const filePath = path.join(steeringPath, fileName);
2225
- await fs.writeFile(filePath, content);
2226
-
2227
- return {
2228
- content: [
2229
- {
2230
- type: "text",
2231
- text: `## Custom Steering Document Created
2232
-
2233
- **File**: .spec/steering/${fileName}
2234
- **Topic**: ${topic}
2235
- **Inclusion Mode**: ${inclusionMode}${inclusionMode === "conditional" ? ` (Pattern: "${filePattern}")` : ""}
2236
-
2237
- **Created**: Custom steering document with template structure
2238
- **Usage**: ${
2239
- inclusionMode === "always"
2240
- ? "Will be loaded in all AI interactions"
2241
- : inclusionMode === "conditional"
2242
- ? `Will be loaded when working with files matching "${filePattern}"`
2243
- : `Reference manually with @${fileName} when needed`
2244
- }
2245
-
2246
- 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()}.`,
2247
- },
2248
- ],
2249
- };
2250
- } catch (error) {
2251
- return {
2252
- content: [
2253
- {
2254
- type: "text",
2255
- text: `Error creating custom steering document: ${error.message}`,
2256
- },
2257
- ],
2258
- };
2259
- }
2260
- },
2261
- );
2262
-
2263
- // 13. sdd-validate-design - Interactive design quality review
2264
- server.registerTool(
2265
- "sdd-validate-design",
2266
- {
2267
- title: "Validate Design Quality",
2268
- description: "Interactive design quality review and validation",
2269
- inputSchema: {
2270
- featureName: z.string().describe("Feature name to validate design for"),
2271
- },
2272
- },
2273
- async ({ featureName }) => {
2274
- try {
2275
- const currentPath = process.cwd();
2276
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
2277
- const designPath = path.join(featurePath, "design.md");
2278
- const specPath = path.join(featurePath, "spec.json");
2279
-
2280
- // Check if design document exists
2281
- const designExists = await fs
2282
- .access(designPath)
2283
- .then(() => true)
2284
- .catch(() => false);
2285
- if (!designExists) {
2286
- return {
2287
- content: [
2288
- {
2289
- type: "text",
2290
- text: `Error: Design document not found. Run \`sdd-design ${featureName}\` first to generate design document.`,
2291
- },
2292
- ],
2293
- };
2294
- }
2295
-
2296
- // Load design and spec
2297
- const designContent = await fs.readFile(designPath, "utf8");
2298
- const specContent = await fs.readFile(specPath, "utf8");
2299
- const spec = JSON.parse(specContent);
2300
-
2301
- // Analyze design for critical issues
2302
- const issues = [];
2303
-
2304
- // Check for type safety (if TypeScript patterns detected)
2305
- if (designContent.includes("any") || designContent.includes(": any")) {
2306
- issues.push({
2307
- title: "Type Safety Concern",
2308
- concern: "Design mentions 'any' types which compromises type safety",
2309
- impact: "Reduces code reliability and IDE support",
2310
- suggestion:
2311
- "Define explicit interfaces and types for all data structures",
2312
- });
2313
- }
2314
-
2315
- // Check for architectural patterns
2316
- if (
2317
- !designContent.includes("Component") &&
2318
- !designContent.includes("Service") &&
2319
- !designContent.includes("Module")
2320
- ) {
2321
- issues.push({
2322
- title: "Architecture Clarity",
2323
- concern: "Design lacks clear component or service boundaries",
2324
- impact: "May lead to monolithic or poorly organized code",
2325
- suggestion:
2326
- "Define clear components, services, or modules with specific responsibilities",
2327
- });
2328
- }
2329
-
2330
- // Check for error handling
2331
- if (
2332
- !designContent.includes("error") &&
2333
- !designContent.includes("Error")
2334
- ) {
2335
- issues.push({
2336
- title: "Error Handling Strategy",
2337
- concern: "Design doesn't address error handling patterns",
2338
- impact: "Runtime errors may not be properly managed",
2339
- suggestion:
2340
- "Add comprehensive error handling strategy and exception management",
2341
- });
2342
- }
2343
-
2344
- // Limit to 3 most critical issues
2345
- const criticalIssues = issues.slice(0, 3);
2346
-
2347
- // Identify design strengths
2348
- const strengths = [];
2349
- if (designContent.includes("mermaid") || designContent.includes("```")) {
2350
- strengths.push("Visual documentation with diagrams and code examples");
2351
- }
2352
- if (
2353
- designContent.includes("interface") ||
2354
- designContent.includes("Interface")
2355
- ) {
2356
- strengths.push("Clear interface definitions and contracts");
2357
- }
2358
-
2359
- // Make GO/NO-GO decision
2360
- const hasBlockingIssues =
2361
- criticalIssues.length > 2 ||
2362
- criticalIssues.some(
2363
- (issue) =>
2364
- issue.title.includes("Architecture") ||
2365
- issue.title.includes("Type Safety"),
2366
- );
2367
-
2368
- const decision = hasBlockingIssues ? "NO-GO" : "GO";
2369
- const nextStep =
2370
- decision === "GO"
2371
- ? `Run \`sdd-tasks ${featureName}\` to generate implementation tasks`
2372
- : `Address critical issues in design document before proceeding`;
2373
-
2374
- let report = `## Design Validation Review: ${featureName}\n\n`;
2375
- report += `**Overall Assessment**: ${decision === "GO" ? "✅ Design ready for implementation" : "❌ Design needs revision"}\n\n`;
2376
-
2377
- if (criticalIssues.length > 0) {
2378
- report += `### Critical Issues (${criticalIssues.length})\n\n`;
2379
- criticalIssues.forEach((issue, index) => {
2380
- report += `🔴 **Critical Issue ${index + 1}**: ${issue.title}\n`;
2381
- report += `**Concern**: ${issue.concern}\n`;
2382
- report += `**Impact**: ${issue.impact}\n`;
2383
- report += `**Suggestion**: ${issue.suggestion}\n\n`;
2384
- });
2385
- }
2386
-
2387
- if (strengths.length > 0) {
2388
- report += `### Design Strengths\n\n`;
2389
- strengths.forEach((strength) => {
2390
- report += `✅ ${strength}\n`;
2391
- });
2392
- report += `\n`;
2393
- }
2394
-
2395
- report += `### Final Assessment\n`;
2396
- report += `**Decision**: ${decision}\n`;
2397
- report += `**Rationale**: ${
2398
- decision === "GO"
2399
- ? "Design addresses core requirements with acceptable architectural approach and manageable risks."
2400
- : "Critical architectural or technical issues need resolution before implementation can proceed safely."
2401
- }\n`;
2402
- report += `**Next Steps**: ${nextStep}\n\n`;
2403
-
2404
- report += `### Interactive Discussion\n`;
2405
- report += `Questions for design review:\n`;
2406
- report += `1. Do you agree with the identified issues and their severity?\n`;
2407
- report += `2. Are there alternative approaches to address the concerns?\n`;
2408
- report += `3. What are your thoughts on the overall design complexity?\n`;
2409
- report += `4. Are there any design decisions that need clarification?\n`;
2410
-
2411
- return {
2412
- content: [
2413
- {
2414
- type: "text",
2415
- text: report,
2416
- },
2417
- ],
2418
- };
2419
- } catch (error) {
2420
- return {
2421
- content: [
2422
- {
2423
- type: "text",
2424
- text: `Error validating design: ${error.message}`,
2425
- },
2426
- ],
2427
- };
2428
- }
2429
- },
2430
- );
2431
-
2432
- // 14. sdd-validate-gap - Analyze implementation gap
2433
- server.registerTool(
2434
- "sdd-validate-gap",
2435
- {
2436
- title: "Validate Implementation Gap",
2437
- description: "Analyze implementation gap between requirements and codebase",
2438
- inputSchema: {
2439
- featureName: z
2440
- .string()
2441
- .describe("Feature name to analyze implementation gap for"),
2442
- },
2443
- },
2444
- async ({ featureName }) => {
2445
- try {
2446
- const currentPath = process.cwd();
2447
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
2448
- const requirementsPath = path.join(featurePath, "requirements.md");
2449
- const specPath = path.join(featurePath, "spec.json");
2450
-
2451
- // Check if requirements exist
2452
- const requirementsExist = await fs
2453
- .access(requirementsPath)
2454
- .then(() => true)
2455
- .catch(() => false);
2456
- if (!requirementsExist) {
2457
- return {
2458
- content: [
2459
- {
2460
- type: "text",
2461
- text: `Error: Requirements document not found. Run \`sdd-requirements ${featureName}\` first to generate requirements.`,
2462
- },
2463
- ],
2464
- };
2465
- }
2466
-
2467
- // Load requirements and spec
2468
- const requirementsContent = await fs.readFile(requirementsPath, "utf8");
2469
- const specContent = await fs.readFile(specPath, "utf8");
2470
- const spec = JSON.parse(specContent);
2471
-
2472
- // Analyze current codebase
2473
- const codebaseAnalysis = {
2474
- hasPackageJson: await fs
2475
- .access("package.json")
2476
- .then(() => true)
2477
- .catch(() => false),
2478
- hasSourceCode: false,
2479
- techStack: [],
2480
- architecture: "Unknown",
2481
- };
2482
-
2483
- if (codebaseAnalysis.hasPackageJson) {
2484
- const packageContent = await fs.readFile("package.json", "utf8");
2485
- const packageJson = JSON.parse(packageContent);
2486
- codebaseAnalysis.techStack = Object.keys(
2487
- packageJson.dependencies || {},
2488
- );
2489
- codebaseAnalysis.architecture = "Node.js Application";
2490
- }
2491
-
2492
- // Check for source directories
2493
- const srcExists = await fs
2494
- .access("src")
2495
- .then(() => true)
2496
- .catch(() => false);
2497
- const libExists = await fs
2498
- .access("lib")
2499
- .then(() => true)
2500
- .catch(() => false);
2501
- codebaseAnalysis.hasSourceCode = srcExists || libExists;
2502
-
2503
- // Extract requirements complexity
2504
- const requirements =
2505
- requirementsContent.match(/WHEN|IF|WHILE|WHERE/g) || [];
2506
- const complexity =
2507
- requirements.length > 10
2508
- ? "XL"
2509
- : requirements.length > 6
2510
- ? "L"
2511
- : requirements.length > 3
2512
- ? "M"
2513
- : "S";
2514
-
2515
- // Identify gaps and implementation approaches
2516
- const gaps = [];
2517
- if (!codebaseAnalysis.hasSourceCode) {
2518
- gaps.push(
2519
- "No existing source code structure - requires full implementation from scratch",
2520
- );
2521
- }
2522
- if (!codebaseAnalysis.techStack.includes("@modelcontextprotocol/sdk")) {
2523
- gaps.push("MCP SDK integration required for AI tool compatibility");
2524
- }
2525
- if (
2526
- requirementsContent.includes("database") ||
2527
- requirementsContent.includes("storage")
2528
- ) {
2529
- gaps.push("Data storage layer needs to be designed and implemented");
2530
- }
2531
-
2532
- // Implementation strategy options
2533
- const strategies = [
2534
- {
2535
- approach: "Extension",
2536
- rationale: codebaseAnalysis.hasSourceCode
2537
- ? "Extend existing codebase with new functionality"
2538
- : "Not applicable - no existing codebase to extend",
2539
- applicable: codebaseAnalysis.hasSourceCode,
2540
- complexity: codebaseAnalysis.hasSourceCode ? "M" : "N/A",
2541
- tradeoffs: codebaseAnalysis.hasSourceCode
2542
- ? "Pros: Maintains consistency, faster development. Cons: May introduce technical debt"
2543
- : "N/A",
2544
- },
2545
- {
2546
- approach: "New Implementation",
2547
- rationale: "Create new components following established patterns",
2548
- applicable: true,
2549
- complexity: complexity,
2550
- tradeoffs:
2551
- "Pros: Clean architecture, full control. Cons: More development time, integration complexity",
2552
- },
2553
- {
2554
- approach: "Hybrid",
2555
- rationale:
2556
- "Combine extension of existing components with new development where needed",
2557
- applicable: codebaseAnalysis.hasSourceCode,
2558
- complexity: codebaseAnalysis.hasSourceCode ? "L" : "M",
2559
- tradeoffs:
2560
- "Pros: Balanced approach, optimal resource usage. Cons: Requires careful integration planning",
2561
- },
2562
- ];
2563
-
2564
- const applicableStrategies = strategies.filter((s) => s.applicable);
2565
- const recommendedStrategy =
2566
- applicableStrategies.find((s) => s.approach === "Hybrid") ||
2567
- applicableStrategies.find((s) => s.approach === "New Implementation");
2568
-
2569
- let report = `## Implementation Gap Analysis: ${featureName}\n\n`;
2570
-
2571
- report += `### Analysis Summary\n`;
2572
- report += `- **Feature Complexity**: ${complexity} (based on ${requirements.length} requirements)\n`;
2573
- report += `- **Existing Codebase**: ${codebaseAnalysis.hasSourceCode ? "Source code detected" : "No source code structure"}\n`;
2574
- report += `- **Technology Stack**: ${codebaseAnalysis.techStack.length} dependencies\n`;
2575
- report += `- **Architecture Type**: ${codebaseAnalysis.architecture}\n\n`;
2576
-
2577
- report += `### Existing Codebase Insights\n`;
2578
- report += `- **Package Management**: ${codebaseAnalysis.hasPackageJson ? "npm/package.json configured" : "No package.json found"}\n`;
2579
- report += `- **Source Structure**: ${codebaseAnalysis.hasSourceCode ? "Established source directories" : "No conventional source structure"}\n`;
2580
- report += `- **Key Dependencies**: ${codebaseAnalysis.techStack.slice(0, 5).join(", ") || "None detected"}\n\n`;
2581
-
2582
- if (gaps.length > 0) {
2583
- report += `### Implementation Gaps Identified\n`;
2584
- gaps.forEach((gap) => (report += `- ${gap}\n`));
2585
- report += `\n`;
2586
- }
2587
-
2588
- report += `### Implementation Strategy Options\n\n`;
2589
- applicableStrategies.forEach((strategy) => {
2590
- report += `**${strategy.approach} Approach**:\n`;
2591
- report += `- **Rationale**: ${strategy.rationale}\n`;
2592
- report += `- **Complexity**: ${strategy.complexity}\n`;
2593
- report += `- **Trade-offs**: ${strategy.tradeoffs}\n\n`;
2594
- });
2595
-
2596
- report += `### Technical Research Needs\n`;
2597
- const researchNeeds = [];
2598
- if (!codebaseAnalysis.techStack.includes("@modelcontextprotocol/sdk")) {
2599
- researchNeeds.push("MCP SDK integration patterns and best practices");
2600
- }
2601
- if (
2602
- requirementsContent.includes("template") ||
2603
- requirementsContent.includes("generation")
2604
- ) {
2605
- researchNeeds.push("Template engine selection and implementation");
2606
- }
2607
- if (
2608
- requirementsContent.includes("workflow") ||
2609
- requirementsContent.includes("state")
2610
- ) {
2611
- researchNeeds.push("State machine or workflow engine patterns");
2612
- }
2613
-
2614
- if (researchNeeds.length > 0) {
2615
- researchNeeds.forEach((need) => (report += `- ${need}\n`));
2616
- } else {
2617
- report += `- No significant research dependencies identified\n`;
2618
- }
2619
- report += `\n`;
2620
-
2621
- report += `### Recommendations for Design Phase\n`;
2622
- report += `- **Preferred Approach**: ${recommendedStrategy.approach} (${recommendedStrategy.complexity} complexity)\n`;
2623
- report += `- **Key Decisions**: Architecture patterns, technology integration, component boundaries\n`;
2624
- report += `- **Risk Mitigation**: ${complexity === "XL" || complexity === "L" ? "Consider phased implementation approach" : "Standard development approach acceptable"}\n`;
2625
- report += `- **Next Step**: Use this analysis to inform technical design decisions\n`;
2626
-
2627
- return {
2628
- content: [
2629
- {
2630
- type: "text",
2631
- text: report,
2632
- },
2633
- ],
2634
- };
2635
- } catch (error) {
2636
- return {
2637
- content: [
2638
- {
2639
- type: "text",
2640
- text: `Error analyzing implementation gap: ${error.message}`,
2641
- },
2642
- ],
2643
- };
2644
- }
2645
- },
2646
- );
2647
-
2648
- // 15. sdd-spec-impl - Execute spec tasks using TDD
2649
- server.registerTool(
2650
- "sdd-spec-impl",
2651
- {
2652
- title: "Execute Spec Tasks with TDD",
2653
- description: "Execute spec tasks using TDD methodology",
2654
- inputSchema: {
2655
- featureName: z.string().describe("Feature name to execute tasks for"),
2656
- taskNumbers: z
2657
- .string()
2658
- .optional()
2659
- .describe(
2660
- 'Specific task numbers to execute (e.g., "1.1,2.3" or leave empty for all pending)',
2661
- ),
2662
- },
2663
- },
2664
- async ({ featureName, taskNumbers }) => {
2665
- try {
2666
- const currentPath = process.cwd();
2667
- const featurePath = path.join(currentPath, ".spec", "specs", featureName);
2668
- const tasksPath = path.join(featurePath, "tasks.md");
2669
- const requirementsPath = path.join(featurePath, "requirements.md");
2670
- const designPath = path.join(featurePath, "design.md");
2671
- const specPath = path.join(featurePath, "spec.json");
2672
-
2673
- // Validate required files exist
2674
- const requiredFiles = [
2675
- { path: requirementsPath, name: "requirements.md" },
2676
- { path: designPath, name: "design.md" },
2677
- { path: tasksPath, name: "tasks.md" },
2678
- { path: specPath, name: "spec.json" },
2679
- ];
2680
-
2681
- for (const file of requiredFiles) {
2682
- const exists = await fs
2683
- .access(file.path)
2684
- .then(() => true)
2685
- .catch(() => false);
2686
- if (!exists) {
2687
- return {
2688
- content: [
2689
- {
2690
- type: "text",
2691
- 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}`,
2692
- },
2693
- ],
2694
- };
2695
- }
2696
- }
2697
-
2698
- // Load all context documents
2699
- const tasksContent = await fs.readFile(tasksPath, "utf8");
2700
- const specContent = await fs.readFile(specPath, "utf8");
2701
- const spec = JSON.parse(specContent);
2702
-
2703
- // Parse tasks to find pending ones
2704
- const taskLines = tasksContent.split("\n");
2705
- const tasks = [];
2706
- let currentMajorTask = null;
2707
-
2708
- for (let i = 0; i < taskLines.length; i++) {
2709
- const line = taskLines[i].trim();
2710
-
2711
- // Match major tasks (- [ ] 1. Task name)
2712
- const majorMatch = line.match(/^- \[([ x])\] (\d+)\. (.+)$/);
2713
- if (majorMatch) {
2714
- currentMajorTask = {
2715
- number: majorMatch[2],
2716
- description: majorMatch[3],
2717
- completed: majorMatch[1] === "x",
2718
- subtasks: [],
2719
- };
2720
- tasks.push(currentMajorTask);
2721
- continue;
2722
- }
2723
-
2724
- // Match sub-tasks (- [ ] 1.1 Subtask name)
2725
- const subMatch = line.match(/^- \[([ x])\] (\d+\.\d+) (.+)$/);
2726
- if (subMatch && currentMajorTask) {
2727
- currentMajorTask.subtasks.push({
2728
- number: subMatch[2],
2729
- description: subMatch[3],
2730
- completed: subMatch[1] === "x",
2731
- });
2732
- }
2733
- }
2734
-
2735
- // Filter tasks based on taskNumbers parameter
2736
- let tasksToExecute = [];
2737
- if (taskNumbers) {
2738
- const requestedNumbers = taskNumbers.split(",").map((n) => n.trim());
2739
- for (const task of tasks) {
2740
- if (requestedNumbers.includes(task.number) && !task.completed) {
2741
- tasksToExecute.push({ type: "major", task });
2742
- }
2743
- for (const subtask of task.subtasks) {
2744
- if (
2745
- requestedNumbers.includes(subtask.number) &&
2746
- !subtask.completed
2747
- ) {
2748
- tasksToExecute.push({
2749
- type: "subtask",
2750
- task: subtask,
2751
- parent: task,
2752
- });
2753
- }
2754
- }
2755
- }
2756
- } else {
2757
- // Get all pending tasks
2758
- for (const task of tasks) {
2759
- if (!task.completed) {
2760
- tasksToExecute.push({ type: "major", task });
2761
- }
2762
- for (const subtask of task.subtasks) {
2763
- if (!subtask.completed) {
2764
- tasksToExecute.push({
2765
- type: "subtask",
2766
- task: subtask,
2767
- parent: task,
2768
- });
2769
- }
2770
- }
2771
- }
2772
- }
2773
-
2774
- if (tasksToExecute.length === 0) {
2775
- return {
2776
- content: [
2777
- {
2778
- type: "text",
2779
- 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.`,
2780
- },
2781
- ],
2782
- };
2783
- }
2784
-
2785
- // Generate TDD implementation guidance for the tasks
2786
- let report = `## TDD Implementation Execution: ${featureName}\n\n`;
2787
- report += `**Tasks to Execute**: ${tasksToExecute.length} pending tasks\n`;
2788
- report += `**TDD Methodology**: Kent Beck's Red → Green → Refactor cycle\n\n`;
2789
-
2790
- report += `### Context Loaded\n`;
2791
- report += `- ✅ Requirements: .spec/specs/${featureName}/requirements.md\n`;
2792
- report += `- ✅ Design: .spec/specs/${featureName}/design.md\n`;
2793
- report += `- ✅ Tasks: .spec/specs/${featureName}/tasks.md\n`;
2794
- report += `- ✅ Metadata: .spec/specs/${featureName}/spec.json\n\n`;
2795
-
2796
- report += `### TDD Implementation Plan\n\n`;
2797
-
2798
- tasksToExecute.slice(0, 5).forEach((item, index) => {
2799
- const task = item.task;
2800
- const taskNumber = item.type === "subtask" ? task.number : task.number;
2801
- const taskDesc = task.description;
2802
-
2803
- report += `**Task ${taskNumber}**: ${taskDesc}\n\n`;
2804
- report += `**TDD Cycle for this task**:\n`;
2805
- report += `1. 🔴 **RED**: Write failing tests for "${taskDesc}"\n`;
2806
- report += ` - Define test cases that specify expected behavior\n`;
2807
- report += ` - Ensure tests fail initially (no implementation yet)\n`;
2808
- report += ` - Verify test framework and setup is working\n\n`;
2809
-
2810
- report += `2. 🟢 **GREEN**: Write minimal code to pass tests\n`;
2811
- report += ` - Implement only what's needed to make tests pass\n`;
2812
- report += ` - Focus on making it work, not making it perfect\n`;
2813
- report += ` - Avoid over-engineering at this stage\n\n`;
2814
-
2815
- report += `3. 🔵 **REFACTOR**: Clean up and improve code structure\n`;
2816
- report += ` - Improve code quality while keeping tests green\n`;
2817
- report += ` - Remove duplication and improve naming\n`;
2818
- report += ` - Ensure code follows project conventions\n\n`;
2819
-
2820
- report += `4. ✅ **VERIFY**: Complete task verification\n`;
2821
- report += ` - All tests pass (new and existing)\n`;
2822
- report += ` - Code quality meets standards\n`;
2823
- report += ` - No regressions in existing functionality\n`;
2824
- report += ` - Mark task as completed: \`- [x] ${taskNumber} ${taskDesc}\`\n\n`;
2825
- });
2826
-
2827
- if (tasksToExecute.length > 5) {
2828
- report += `... and ${tasksToExecute.length - 5} more tasks\n\n`;
2829
- }
2830
-
2831
- report += `### Implementation Guidelines\n`;
2832
- report += `- **Follow design specifications**: Implement exactly what's specified in design.md\n`;
2833
- report += `- **Test-first approach**: Always write tests before implementation code\n`;
2834
- report += `- **Incremental progress**: Complete one task fully before moving to next\n`;
2835
- report += `- **Update task status**: Mark checkboxes as completed in tasks.md\n`;
2836
- report += `- **Quality focus**: Maintain code quality and test coverage\n\n`;
2837
-
2838
- report += `### Next Steps\n`;
2839
- report += `1. Start with the first pending task: "${tasksToExecute[0].task.description}"\n`;
2840
- report += `2. Follow the TDD cycle: Red → Green → Refactor → Verify\n`;
2841
- report += `3. Update tasks.md to mark completed tasks with [x]\n`;
2842
- report += `4. Run \`sdd-quality-check\` to validate code quality\n`;
2843
- report += `5. Continue with remaining tasks sequentially\n\n`;
2844
-
2845
- 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.`;
2846
-
2847
- return {
2848
- content: [
2849
- {
2850
- type: "text",
2851
- text: report,
2852
- },
2853
- ],
2854
- };
2855
- } catch (error) {
2856
- return {
2857
- content: [
2858
- {
2859
- type: "text",
2860
- text: `Error executing spec implementation: ${error.message}`,
2861
- },
2862
- ],
2863
- };
2864
- }
2865
- },
2866
- );
2867
-
2868
- const transport = new StdioServerTransport();
2869
- // Helper functions for validation
2870
- function isAnalysisInsufficient(analysis) {
2871
- return (
2872
- analysis.name === "Unknown Project" &&
2873
- analysis.description === "No description available" &&
2874
- analysis.dependencies.length === 0
2875
- );
2876
- }
2877
-
2878
- function contentContainsGenericPlaceholders(content) {
2879
- return (
2880
- content.includes("Unknown Project") ||
2881
- content.includes("No description available") ||
2882
- content.includes("unknown")
2883
- );
2884
- }
2885
-
2886
- await server.connect(transport);
5
+ startMCPServer().catch((error) => {
6
+ process.stderr.write(`Failed to start MCP server: ${error instanceof Error ? error.message : String(error)}\n`);
7
+ process.exitCode = 1;
8
+ });