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.
- package/README.md +92 -683
- package/agents/architect.md +15 -93
- package/agents/implementer.md +16 -141
- package/agents/planner.md +16 -84
- package/agents/reviewer.md +16 -239
- package/agents/security-auditor.md +16 -114
- package/agents/tdd-guide.md +17 -228
- package/dist/adapters/cli/SDDToolAdapter.d.ts +14 -8
- package/dist/adapters/cli/SDDToolAdapter.js +188 -405
- package/dist/adapters/cli/SDDToolAdapter.js.map +1 -1
- package/dist/application/services/ContextCompactionService.d.ts +88 -16
- package/dist/application/services/ContextCompactionService.js +474 -187
- package/dist/application/services/ContextCompactionService.js.map +1 -1
- package/dist/application/services/ProjectService.js +3 -3
- package/dist/application/services/ProjectService.js.map +1 -1
- package/dist/application/services/SpecPathResolver.d.ts +24 -0
- package/dist/application/services/SpecPathResolver.js +70 -0
- package/dist/application/services/SpecPathResolver.js.map +1 -0
- package/dist/application/services/WorkflowEngineService.d.ts +214 -50
- package/dist/application/services/WorkflowEngineService.js +1447 -292
- package/dist/application/services/WorkflowEngineService.js.map +1 -1
- package/dist/application/services/WorkflowErrors.d.ts +16 -0
- package/dist/application/services/WorkflowErrors.js +53 -0
- package/dist/application/services/WorkflowErrors.js.map +1 -0
- package/dist/application/services/WorkflowValidationService.d.ts +25 -46
- package/dist/application/services/WorkflowValidationService.js +284 -627
- package/dist/application/services/WorkflowValidationService.js.map +1 -1
- package/dist/cli/install-skills.d.ts +3 -9
- package/dist/cli/install-skills.js +129 -174
- package/dist/cli/install-skills.js.map +1 -1
- package/dist/cli/install-target.d.ts +42 -8
- package/dist/cli/install-target.js +27 -9
- package/dist/cli/install-target.js.map +1 -1
- package/dist/cli/sdd-mcp-cli.d.ts +1 -1
- package/dist/cli/sdd-mcp-cli.js +7 -6
- package/dist/cli/sdd-mcp-cli.js.map +1 -1
- package/dist/cli/tool-support/claude-code.js +17 -34
- package/dist/cli/tool-support/claude-code.js.map +1 -1
- package/dist/cli/tool-support/codex.d.ts +0 -53
- package/dist/cli/tool-support/codex.js +10 -94
- package/dist/cli/tool-support/codex.js.map +1 -1
- package/dist/cli/tool-support/index.d.ts +3 -2
- package/dist/cli/tool-support/index.js +3 -1
- package/dist/cli/tool-support/index.js.map +1 -1
- package/dist/cli/tool-support/mcp-registration.d.ts +22 -0
- package/dist/cli/tool-support/mcp-registration.js +275 -0
- package/dist/cli/tool-support/mcp-registration.js.map +1 -0
- package/dist/cli/tool-support/omp.d.ts +5 -0
- package/dist/cli/tool-support/omp.js +47 -0
- package/dist/cli/tool-support/omp.js.map +1 -0
- package/dist/cli/tool-support/root-guidance.d.ts +2 -9
- package/dist/cli/tool-support/root-guidance.js +44 -37
- package/dist/cli/tool-support/root-guidance.js.map +1 -1
- package/dist/cli/tool-support/target-agent-renderer.d.ts +1 -0
- package/dist/cli/tool-support/target-agent-renderer.js +37 -4
- package/dist/cli/tool-support/target-agent-renderer.js.map +1 -1
- package/dist/cli/tool-support/target-installer.d.ts +9 -3
- package/dist/cli/tool-support/target-installer.js +100 -26
- package/dist/cli/tool-support/target-installer.js.map +1 -1
- package/dist/cli/utils/preserving-writer.d.ts +56 -0
- package/dist/cli/utils/preserving-writer.js +603 -10
- package/dist/cli/utils/preserving-writer.js.map +1 -1
- package/dist/domain/ports.d.ts +4 -0
- package/dist/domain/types.d.ts +52 -7
- package/dist/domain/types.js +5 -4
- package/dist/domain/types.js.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.js +16 -1199
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.d.ts +3 -0
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.js +10 -0
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.js.map +1 -1
- package/dist/infrastructure/mcp/CapabilityNegotiator.js +3 -3
- package/dist/infrastructure/mcp/CapabilityNegotiator.js.map +1 -1
- package/dist/infrastructure/mcp/MCPServer.js +13 -13
- package/dist/infrastructure/mcp/MCPServer.js.map +1 -1
- package/dist/infrastructure/mcp/ToolRegistry.d.ts +5 -1
- package/dist/infrastructure/mcp/ToolRegistry.js +11 -4
- package/dist/infrastructure/mcp/ToolRegistry.js.map +1 -1
- package/dist/infrastructure/mcp/sddToolDefinitions.d.ts +6 -0
- package/dist/infrastructure/mcp/sddToolDefinitions.js +110 -0
- package/dist/infrastructure/mcp/sddToolDefinitions.js.map +1 -0
- package/dist/infrastructure/schemas/project.schema.d.ts +2 -2
- package/dist/infrastructure/schemas/project.schema.js +2 -2
- package/dist/infrastructure/schemas/project.schema.js.map +1 -1
- package/dist/shared/version.d.ts +3 -0
- package/dist/shared/version.js +4 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/utils/atomicWrite.d.ts +8 -35
- package/dist/utils/atomicWrite.js +24 -57
- package/dist/utils/atomicWrite.js.map +1 -1
- package/dist/utils/withFilesystemLock.d.ts +22 -0
- package/dist/utils/withFilesystemLock.js +219 -0
- package/dist/utils/withFilesystemLock.js.map +1 -0
- package/mcp-server.js +5 -2883
- package/package.json +8 -3
- package/scripts/context-usage-report.mjs +602 -0
- package/sdd-entry.js +17 -6
- package/skills/sdd-commit/REFERENCE.md +31 -0
- package/skills/sdd-commit/SKILL.md +17 -273
- package/skills/sdd-design/REFERENCE.md +51 -0
- package/skills/sdd-design/SKILL.md +25 -262
- package/skills/sdd-implement/REFERENCE.md +30 -0
- package/skills/sdd-implement/SKILL.md +27 -284
- package/skills/sdd-requirements/REFERENCE.md +39 -0
- package/skills/sdd-requirements/SKILL.md +28 -132
- package/skills/sdd-review/REFERENCE.md +26 -0
- package/skills/sdd-review/SKILL.md +17 -181
- package/skills/sdd-security-check/REFERENCE.md +19 -0
- package/skills/sdd-security-check/SKILL.md +18 -184
- package/skills/sdd-steering/REFERENCE.md +25 -0
- package/skills/sdd-steering/SKILL.md +18 -216
- package/skills/sdd-steering-custom/REFERENCE.md +27 -0
- package/skills/sdd-steering-custom/SKILL.md +19 -203
- package/skills/sdd-tasks/REFERENCE.md +25 -0
- package/skills/sdd-tasks/SKILL.md +27 -244
- package/skills/sdd-test-gen/REFERENCE.md +15 -0
- package/skills/sdd-test-gen/SKILL.md +17 -287
- package/skills/simple-task/REFERENCE.md +22 -0
- package/skills/simple-task/SKILL.md +17 -138
- package/templates/CLAUDE.md +13 -31
- package/templates/codex-AGENTS.md +7 -9
- package/rules/git-workflow.md +0 -92
- 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
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
});
|