sdd-mcp-server 1.6.0 → 1.6.2
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 +5 -5
- package/dist/index.d.ts +7 -7
- package/dist/index.js +825 -580
- package/dist/index.js.map +1 -1
- package/dist/utils/moduleLoader.d.ts +78 -0
- package/dist/utils/moduleLoader.js +81 -0
- package/dist/utils/moduleLoader.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// MCP SDD Server entry point
|
|
3
3
|
// IMPORTANT: Detect MCP mode and silence console output BEFORE any imports
|
|
4
4
|
// Check multiple indicators for MCP mode
|
|
5
|
-
const isMCPMode = process.argv[1]?.includes(
|
|
6
|
-
process.argv[0]?.includes(
|
|
7
|
-
process.env.npm_execpath?.includes(
|
|
8
|
-
|
|
9
|
-
process.argv.includes(
|
|
10
|
-
process.argv.includes(
|
|
5
|
+
const isMCPMode = process.argv[1]?.includes("sdd-mcp-server") ||
|
|
6
|
+
process.argv[0]?.includes("sdd-mcp-server") ||
|
|
7
|
+
process.env.npm_execpath?.includes("npx") || // Executed via npx
|
|
8
|
+
process.stdin.isTTY === false || // MCP servers communicate via stdio pipes
|
|
9
|
+
process.argv.includes("--mcp-mode") || // Explicit MCP mode flag
|
|
10
|
+
process.argv.includes("--simplified") || // Use simplified mode flag
|
|
11
11
|
false; // Default to full server for better functionality
|
|
12
12
|
if (isMCPMode) {
|
|
13
13
|
// Completely silence all console output for MCP mode
|
|
@@ -17,12 +17,13 @@ if (isMCPMode) {
|
|
|
17
17
|
console.debug = () => { };
|
|
18
18
|
// Keep error for debugging but send to stderr
|
|
19
19
|
const originalError = console.error;
|
|
20
|
-
console.error = (...args) => originalError(
|
|
20
|
+
console.error = (...args) => originalError("[SDD-DEBUG]", ...args);
|
|
21
21
|
}
|
|
22
|
-
import
|
|
23
|
-
import { createContainer } from
|
|
24
|
-
import { TYPES } from
|
|
25
|
-
import { ensureStaticSteeringDocuments } from
|
|
22
|
+
import "reflect-metadata";
|
|
23
|
+
import { createContainer } from "./infrastructure/di/container.js";
|
|
24
|
+
import { TYPES } from "./infrastructure/di/types.js";
|
|
25
|
+
import { ensureStaticSteeringDocuments } from "./application/services/staticSteering.js";
|
|
26
|
+
import { loadDocumentGenerator, loadSpecGenerator, } from "./utils/moduleLoader.js";
|
|
26
27
|
export async function createMCPServer() {
|
|
27
28
|
const container = createContainer();
|
|
28
29
|
const logger = container.get(TYPES.LoggerPort);
|
|
@@ -46,21 +47,21 @@ export async function createMCPServer() {
|
|
|
46
47
|
},
|
|
47
48
|
async close() {
|
|
48
49
|
await mcpServer.stop();
|
|
49
|
-
}
|
|
50
|
+
},
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
async function createSimpleMCPServer() {
|
|
53
|
-
const { Server } = await import(
|
|
54
|
-
const { StdioServerTransport } = await import(
|
|
55
|
-
const { ListToolsRequestSchema, CallToolRequestSchema, InitializedNotificationSchema } = await import(
|
|
54
|
+
const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
|
|
55
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
56
|
+
const { ListToolsRequestSchema, CallToolRequestSchema, InitializedNotificationSchema, } = await import("@modelcontextprotocol/sdk/types.js");
|
|
56
57
|
// Resolve version dynamically from package.json when possible
|
|
57
|
-
let pkgVersion =
|
|
58
|
+
let pkgVersion = "0.0.0";
|
|
58
59
|
try {
|
|
59
|
-
const fs = await import(
|
|
60
|
-
const path = await import(
|
|
61
|
-
const pkgPath = path.join(process.cwd(),
|
|
60
|
+
const fs = await import("fs");
|
|
61
|
+
const path = await import("path");
|
|
62
|
+
const pkgPath = path.join(process.cwd(), "package.json");
|
|
62
63
|
if (fs.existsSync(pkgPath)) {
|
|
63
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath,
|
|
64
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
64
65
|
pkgVersion = pkg.version || pkgVersion;
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -68,248 +69,270 @@ async function createSimpleMCPServer() {
|
|
|
68
69
|
// fall back to hardcoded default if needed
|
|
69
70
|
}
|
|
70
71
|
const server = new Server({
|
|
71
|
-
name:
|
|
72
|
-
version: pkgVersion
|
|
72
|
+
name: "sdd-mcp-server",
|
|
73
|
+
version: pkgVersion,
|
|
73
74
|
}, {
|
|
74
75
|
capabilities: {
|
|
75
|
-
tools: {}
|
|
76
|
-
}
|
|
76
|
+
tools: {},
|
|
77
|
+
},
|
|
77
78
|
});
|
|
78
79
|
// Add ALL SDD tools (not just basic ones)
|
|
79
80
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
80
81
|
return {
|
|
81
82
|
tools: [
|
|
82
83
|
{
|
|
83
|
-
name:
|
|
84
|
-
description:
|
|
84
|
+
name: "sdd-init",
|
|
85
|
+
description: "Initialize a new SDD project from description",
|
|
85
86
|
inputSchema: {
|
|
86
|
-
type:
|
|
87
|
+
type: "object",
|
|
87
88
|
properties: {
|
|
88
|
-
description: {
|
|
89
|
+
description: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "Detailed project description",
|
|
92
|
+
},
|
|
89
93
|
},
|
|
90
|
-
required: [
|
|
91
|
-
}
|
|
94
|
+
required: ["description"],
|
|
95
|
+
},
|
|
92
96
|
},
|
|
93
97
|
{
|
|
94
|
-
name:
|
|
95
|
-
description:
|
|
98
|
+
name: "sdd-requirements",
|
|
99
|
+
description: "Generate requirements doc",
|
|
96
100
|
inputSchema: {
|
|
97
|
-
type:
|
|
101
|
+
type: "object",
|
|
98
102
|
properties: {
|
|
99
|
-
featureName: { type:
|
|
103
|
+
featureName: { type: "string" },
|
|
100
104
|
},
|
|
101
|
-
required: [
|
|
102
|
-
}
|
|
105
|
+
required: ["featureName"],
|
|
106
|
+
},
|
|
103
107
|
},
|
|
104
108
|
{
|
|
105
|
-
name:
|
|
106
|
-
description:
|
|
109
|
+
name: "sdd-design",
|
|
110
|
+
description: "Create design specifications",
|
|
107
111
|
inputSchema: {
|
|
108
|
-
type:
|
|
112
|
+
type: "object",
|
|
109
113
|
properties: {
|
|
110
|
-
featureName: { type:
|
|
114
|
+
featureName: { type: "string" },
|
|
111
115
|
},
|
|
112
|
-
required: [
|
|
113
|
-
}
|
|
116
|
+
required: ["featureName"],
|
|
117
|
+
},
|
|
114
118
|
},
|
|
115
119
|
{
|
|
116
|
-
name:
|
|
117
|
-
description:
|
|
120
|
+
name: "sdd-tasks",
|
|
121
|
+
description: "Generate task breakdown",
|
|
118
122
|
inputSchema: {
|
|
119
|
-
type:
|
|
123
|
+
type: "object",
|
|
120
124
|
properties: {
|
|
121
|
-
featureName: { type:
|
|
125
|
+
featureName: { type: "string" },
|
|
122
126
|
},
|
|
123
|
-
required: [
|
|
124
|
-
}
|
|
127
|
+
required: ["featureName"],
|
|
128
|
+
},
|
|
125
129
|
},
|
|
126
130
|
{
|
|
127
|
-
name:
|
|
128
|
-
description:
|
|
131
|
+
name: "sdd-status",
|
|
132
|
+
description: "Check workflow progress",
|
|
129
133
|
inputSchema: {
|
|
130
|
-
type:
|
|
134
|
+
type: "object",
|
|
131
135
|
properties: {
|
|
132
|
-
featureName: { type:
|
|
133
|
-
}
|
|
134
|
-
}
|
|
136
|
+
featureName: { type: "string" },
|
|
137
|
+
},
|
|
138
|
+
},
|
|
135
139
|
},
|
|
136
140
|
{
|
|
137
|
-
name:
|
|
138
|
-
description:
|
|
141
|
+
name: "sdd-steering",
|
|
142
|
+
description: "Create/update steering documents",
|
|
139
143
|
inputSchema: {
|
|
140
|
-
type:
|
|
144
|
+
type: "object",
|
|
141
145
|
properties: {
|
|
142
|
-
updateMode: { type:
|
|
143
|
-
}
|
|
144
|
-
}
|
|
146
|
+
updateMode: { type: "string", enum: ["create", "update"] },
|
|
147
|
+
},
|
|
148
|
+
},
|
|
145
149
|
},
|
|
146
150
|
{
|
|
147
|
-
name:
|
|
148
|
-
description:
|
|
151
|
+
name: "sdd-steering-custom",
|
|
152
|
+
description: "Create custom steering documents",
|
|
149
153
|
inputSchema: {
|
|
150
|
-
type:
|
|
154
|
+
type: "object",
|
|
151
155
|
properties: {
|
|
152
|
-
fileName: { type:
|
|
153
|
-
topic: { type:
|
|
154
|
-
inclusionMode: {
|
|
155
|
-
|
|
156
|
+
fileName: { type: "string" },
|
|
157
|
+
topic: { type: "string" },
|
|
158
|
+
inclusionMode: {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: ["always", "conditional", "manual"],
|
|
161
|
+
},
|
|
162
|
+
filePattern: { type: "string" },
|
|
156
163
|
},
|
|
157
|
-
required: [
|
|
158
|
-
}
|
|
164
|
+
required: ["fileName", "topic", "inclusionMode"],
|
|
165
|
+
},
|
|
159
166
|
},
|
|
160
167
|
{
|
|
161
|
-
name:
|
|
162
|
-
description:
|
|
168
|
+
name: "sdd-quality-check",
|
|
169
|
+
description: "Code quality analysis",
|
|
163
170
|
inputSchema: {
|
|
164
|
-
type:
|
|
171
|
+
type: "object",
|
|
165
172
|
properties: {
|
|
166
|
-
code: { type:
|
|
167
|
-
language: { type:
|
|
173
|
+
code: { type: "string" },
|
|
174
|
+
language: { type: "string" },
|
|
168
175
|
},
|
|
169
|
-
required: [
|
|
170
|
-
}
|
|
176
|
+
required: ["code"],
|
|
177
|
+
},
|
|
171
178
|
},
|
|
172
179
|
{
|
|
173
|
-
name:
|
|
174
|
-
description:
|
|
180
|
+
name: "sdd-approve",
|
|
181
|
+
description: "Approve workflow phases",
|
|
175
182
|
inputSchema: {
|
|
176
|
-
type:
|
|
183
|
+
type: "object",
|
|
177
184
|
properties: {
|
|
178
|
-
featureName: { type:
|
|
179
|
-
phase: {
|
|
185
|
+
featureName: { type: "string" },
|
|
186
|
+
phase: {
|
|
187
|
+
type: "string",
|
|
188
|
+
enum: ["requirements", "design", "tasks"],
|
|
189
|
+
},
|
|
180
190
|
},
|
|
181
|
-
required: [
|
|
182
|
-
}
|
|
191
|
+
required: ["featureName", "phase"],
|
|
192
|
+
},
|
|
183
193
|
},
|
|
184
194
|
{
|
|
185
|
-
name:
|
|
186
|
-
description:
|
|
195
|
+
name: "sdd-implement",
|
|
196
|
+
description: "Implementation guidelines",
|
|
187
197
|
inputSchema: {
|
|
188
|
-
type:
|
|
198
|
+
type: "object",
|
|
189
199
|
properties: {
|
|
190
|
-
featureName: { type:
|
|
200
|
+
featureName: { type: "string" },
|
|
191
201
|
},
|
|
192
|
-
required: [
|
|
193
|
-
}
|
|
202
|
+
required: ["featureName"],
|
|
203
|
+
},
|
|
194
204
|
},
|
|
195
205
|
{
|
|
196
|
-
name:
|
|
197
|
-
description:
|
|
206
|
+
name: "sdd-context-load",
|
|
207
|
+
description: "Load project context",
|
|
198
208
|
inputSchema: {
|
|
199
|
-
type:
|
|
209
|
+
type: "object",
|
|
200
210
|
properties: {
|
|
201
|
-
featureName: { type:
|
|
211
|
+
featureName: { type: "string" },
|
|
202
212
|
},
|
|
203
|
-
required: [
|
|
204
|
-
}
|
|
213
|
+
required: ["featureName"],
|
|
214
|
+
},
|
|
205
215
|
},
|
|
206
216
|
{
|
|
207
|
-
name:
|
|
208
|
-
description:
|
|
217
|
+
name: "sdd-template-render",
|
|
218
|
+
description: "Render templates",
|
|
209
219
|
inputSchema: {
|
|
210
|
-
type:
|
|
220
|
+
type: "object",
|
|
211
221
|
properties: {
|
|
212
|
-
templateType: {
|
|
213
|
-
|
|
214
|
-
|
|
222
|
+
templateType: {
|
|
223
|
+
type: "string",
|
|
224
|
+
enum: ["requirements", "design", "tasks", "custom"],
|
|
225
|
+
},
|
|
226
|
+
featureName: { type: "string" },
|
|
227
|
+
customTemplate: { type: "string" },
|
|
215
228
|
},
|
|
216
|
-
required: [
|
|
217
|
-
}
|
|
229
|
+
required: ["templateType", "featureName"],
|
|
230
|
+
},
|
|
218
231
|
},
|
|
219
232
|
{
|
|
220
|
-
name:
|
|
221
|
-
description:
|
|
233
|
+
name: "sdd-validate-design",
|
|
234
|
+
description: "Validate design quality",
|
|
222
235
|
inputSchema: {
|
|
223
|
-
type:
|
|
236
|
+
type: "object",
|
|
224
237
|
properties: {
|
|
225
|
-
featureName: { type:
|
|
238
|
+
featureName: { type: "string" },
|
|
226
239
|
},
|
|
227
|
-
required: [
|
|
228
|
-
}
|
|
240
|
+
required: ["featureName"],
|
|
241
|
+
},
|
|
229
242
|
},
|
|
230
243
|
{
|
|
231
|
-
name:
|
|
232
|
-
description:
|
|
244
|
+
name: "sdd-validate-gap",
|
|
245
|
+
description: "Validate implementation gap",
|
|
233
246
|
inputSchema: {
|
|
234
|
-
type:
|
|
247
|
+
type: "object",
|
|
235
248
|
properties: {
|
|
236
|
-
featureName: { type:
|
|
249
|
+
featureName: { type: "string" },
|
|
237
250
|
},
|
|
238
|
-
required: [
|
|
239
|
-
}
|
|
251
|
+
required: ["featureName"],
|
|
252
|
+
},
|
|
240
253
|
},
|
|
241
254
|
{
|
|
242
|
-
name:
|
|
243
|
-
description:
|
|
255
|
+
name: "sdd-spec-impl",
|
|
256
|
+
description: "Execute spec tasks using TDD",
|
|
244
257
|
inputSchema: {
|
|
245
|
-
type:
|
|
258
|
+
type: "object",
|
|
246
259
|
properties: {
|
|
247
|
-
featureName: { type:
|
|
248
|
-
taskNumbers: { type:
|
|
260
|
+
featureName: { type: "string" },
|
|
261
|
+
taskNumbers: { type: "string" },
|
|
249
262
|
},
|
|
250
|
-
required: [
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
]
|
|
263
|
+
required: ["featureName"],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
],
|
|
254
267
|
};
|
|
255
268
|
});
|
|
256
269
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
257
270
|
const { name, arguments: args } = request.params;
|
|
258
271
|
switch (name) {
|
|
259
|
-
case
|
|
272
|
+
case "sdd-init":
|
|
260
273
|
return await handleInitSimplified(args);
|
|
261
|
-
case
|
|
274
|
+
case "sdd-status":
|
|
262
275
|
return await handleStatusSimplified(args);
|
|
263
|
-
case
|
|
276
|
+
case "sdd-steering":
|
|
264
277
|
return await handleSteeringSimplified(args);
|
|
265
|
-
case
|
|
278
|
+
case "sdd-steering-custom":
|
|
266
279
|
return await handleSteeringCustomSimplified(args);
|
|
267
|
-
case
|
|
280
|
+
case "sdd-requirements":
|
|
268
281
|
return await handleRequirementsSimplified(args);
|
|
269
|
-
case
|
|
282
|
+
case "sdd-design":
|
|
270
283
|
return await handleDesignSimplified(args);
|
|
271
|
-
case
|
|
284
|
+
case "sdd-tasks":
|
|
272
285
|
return await handleTasksSimplified(args);
|
|
273
|
-
case
|
|
286
|
+
case "sdd-quality-check":
|
|
274
287
|
return await handleQualityCheckSimplified(args);
|
|
275
|
-
case
|
|
288
|
+
case "sdd-approve":
|
|
276
289
|
return await handleApproveSimplified(args);
|
|
277
|
-
case
|
|
290
|
+
case "sdd-implement":
|
|
278
291
|
return await handleImplementSimplified(args);
|
|
279
|
-
case
|
|
292
|
+
case "sdd-context-load":
|
|
280
293
|
return {
|
|
281
|
-
content: [
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
294
|
+
content: [
|
|
295
|
+
{
|
|
296
|
+
type: "text",
|
|
297
|
+
text: `Project context loaded for ${args.featureName}. (Simplified MCP mode)`,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
285
300
|
};
|
|
286
|
-
case
|
|
301
|
+
case "sdd-template-render":
|
|
287
302
|
return {
|
|
288
|
-
content: [
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
303
|
+
content: [
|
|
304
|
+
{
|
|
305
|
+
type: "text",
|
|
306
|
+
text: `Template ${args.templateType} rendered for ${args.featureName}. (Simplified MCP mode)`,
|
|
307
|
+
},
|
|
308
|
+
],
|
|
292
309
|
};
|
|
293
|
-
case
|
|
310
|
+
case "sdd-validate-design":
|
|
294
311
|
return {
|
|
295
|
-
content: [
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
312
|
+
content: [
|
|
313
|
+
{
|
|
314
|
+
type: "text",
|
|
315
|
+
text: `Design validation for ${args.featureName}. (Simplified MCP mode)`,
|
|
316
|
+
},
|
|
317
|
+
],
|
|
299
318
|
};
|
|
300
|
-
case
|
|
319
|
+
case "sdd-validate-gap":
|
|
301
320
|
return {
|
|
302
|
-
content: [
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
321
|
+
content: [
|
|
322
|
+
{
|
|
323
|
+
type: "text",
|
|
324
|
+
text: `Implementation gap analysis for ${args.featureName}. (Simplified MCP mode)`,
|
|
325
|
+
},
|
|
326
|
+
],
|
|
306
327
|
};
|
|
307
|
-
case
|
|
328
|
+
case "sdd-spec-impl":
|
|
308
329
|
return {
|
|
309
|
-
content: [
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
330
|
+
content: [
|
|
331
|
+
{
|
|
332
|
+
type: "text",
|
|
333
|
+
text: `TDD implementation for ${args.featureName}. (Simplified MCP mode)`,
|
|
334
|
+
},
|
|
335
|
+
],
|
|
313
336
|
};
|
|
314
337
|
default:
|
|
315
338
|
throw new Error(`Unknown tool: ${name}`);
|
|
@@ -324,15 +347,15 @@ async function createSimpleMCPServer() {
|
|
|
324
347
|
}
|
|
325
348
|
// Simplified steering implementation for MCP mode
|
|
326
349
|
async function handleSteeringSimplified(args) {
|
|
327
|
-
const fs = await import(
|
|
328
|
-
const path = await import(
|
|
350
|
+
const fs = await import("fs");
|
|
351
|
+
const path = await import("path");
|
|
329
352
|
const fsPromises = fs.promises;
|
|
330
353
|
const projectPath = process.cwd();
|
|
331
354
|
const stubSteeringService = {
|
|
332
355
|
async createSteeringDocument(projectDir, config) {
|
|
333
|
-
const docPath = path.join(projectDir,
|
|
356
|
+
const docPath = path.join(projectDir, ".kiro", "steering", config.name);
|
|
334
357
|
await fsPromises.mkdir(path.dirname(docPath), { recursive: true });
|
|
335
|
-
await fsPromises.writeFile(docPath, config.content,
|
|
358
|
+
await fsPromises.writeFile(docPath, config.content, "utf8");
|
|
336
359
|
return {
|
|
337
360
|
name: config.name,
|
|
338
361
|
path: docPath,
|
|
@@ -342,13 +365,13 @@ async function handleSteeringSimplified(args) {
|
|
|
342
365
|
patterns: config.patterns ?? [],
|
|
343
366
|
priority: config.priority ?? 50,
|
|
344
367
|
lastModified: new Date(),
|
|
345
|
-
isValid: true
|
|
368
|
+
isValid: true,
|
|
346
369
|
};
|
|
347
|
-
}
|
|
370
|
+
},
|
|
348
371
|
};
|
|
349
372
|
try {
|
|
350
373
|
// Create .kiro/steering directory if it doesn't exist
|
|
351
|
-
const steeringDir = path.join(projectPath,
|
|
374
|
+
const steeringDir = path.join(projectPath, ".kiro", "steering");
|
|
352
375
|
if (!fs.existsSync(steeringDir)) {
|
|
353
376
|
fs.mkdirSync(steeringDir, { recursive: true });
|
|
354
377
|
}
|
|
@@ -357,36 +380,36 @@ async function handleSteeringSimplified(args) {
|
|
|
357
380
|
let structureContent;
|
|
358
381
|
let projectAnalysis;
|
|
359
382
|
try {
|
|
360
|
-
// Attempt to import and use the dynamic document generator (
|
|
361
|
-
console.error(
|
|
362
|
-
const { analyzeProject, generateProductDocument, generateTechDocument, generateStructureDocument } = await
|
|
363
|
-
console.error(
|
|
383
|
+
// Attempt to import and use the dynamic document generator (using unified module loader)
|
|
384
|
+
console.error("[SDD-DEBUG] Attempting to load documentGenerator using moduleLoader");
|
|
385
|
+
const { analyzeProject, generateProductDocument, generateTechDocument, generateStructureDocument, } = await loadDocumentGenerator();
|
|
386
|
+
console.error("[SDD-DEBUG] DocumentGenerator imported successfully, analyzing project...");
|
|
364
387
|
// Analyze project dynamically
|
|
365
388
|
projectAnalysis = await analyzeProject(projectPath);
|
|
366
|
-
console.error(
|
|
389
|
+
console.error("[SDD-DEBUG] Project analysis completed, generating documents...");
|
|
367
390
|
// Generate documents dynamically
|
|
368
391
|
productContent = generateProductDocument(projectAnalysis);
|
|
369
392
|
techContent = generateTechDocument(projectAnalysis);
|
|
370
393
|
structureContent = generateStructureDocument(projectAnalysis);
|
|
371
|
-
console.error(
|
|
394
|
+
console.error("[SDD-DEBUG] Dynamic document generation completed successfully");
|
|
372
395
|
}
|
|
373
396
|
catch (importError) {
|
|
374
|
-
console.error(
|
|
375
|
-
console.error(
|
|
376
|
-
console.error(
|
|
397
|
+
console.error("[SDD-DEBUG] Failed to import or use documentGenerator:", importError.message);
|
|
398
|
+
console.error("[SDD-DEBUG] Attempted import path: ./utils/documentGenerator.js");
|
|
399
|
+
console.error("[SDD-DEBUG] Falling back to basic templates with warning...");
|
|
377
400
|
// Fallback to basic templates
|
|
378
|
-
const packageJsonPath = path.join(projectPath,
|
|
379
|
-
let projectName =
|
|
380
|
-
let projectVersion =
|
|
401
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
402
|
+
let projectName = "Unknown Project";
|
|
403
|
+
let projectVersion = "0.0.0";
|
|
381
404
|
try {
|
|
382
405
|
if (fs.existsSync(packageJsonPath)) {
|
|
383
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath,
|
|
406
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
384
407
|
projectName = packageJson.name || projectName;
|
|
385
408
|
projectVersion = packageJson.version || projectVersion;
|
|
386
409
|
}
|
|
387
410
|
}
|
|
388
411
|
catch (pkgError) {
|
|
389
|
-
console.error(
|
|
412
|
+
console.error("[SDD-DEBUG] Could not read package.json, using defaults");
|
|
390
413
|
}
|
|
391
414
|
productContent = `# Product Overview
|
|
392
415
|
|
|
@@ -468,38 +491,38 @@ Generated on: ${new Date().toISOString()}
|
|
|
468
491
|
const fallbackAnalysis = {
|
|
469
492
|
name: projectName,
|
|
470
493
|
version: projectVersion,
|
|
471
|
-
architecture:
|
|
472
|
-
language:
|
|
473
|
-
framework:
|
|
494
|
+
architecture: "MCP Server Application",
|
|
495
|
+
language: "typescript",
|
|
496
|
+
framework: "MCP SDK",
|
|
474
497
|
dependencies: [],
|
|
475
498
|
devDependencies: [],
|
|
476
499
|
testFramework: null,
|
|
477
|
-
buildTool:
|
|
478
|
-
directories: [
|
|
500
|
+
buildTool: "TypeScript Compiler",
|
|
501
|
+
directories: ["src", "dist"],
|
|
479
502
|
hasCI: false,
|
|
480
|
-
hasDocker: false
|
|
503
|
+
hasDocker: false,
|
|
481
504
|
};
|
|
482
505
|
// Use fallback analysis for the return message
|
|
483
506
|
projectAnalysis = fallbackAnalysis;
|
|
484
507
|
}
|
|
485
508
|
// Write the dynamically generated files
|
|
486
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
487
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
488
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
509
|
+
fs.writeFileSync(path.join(steeringDir, "product.md"), productContent);
|
|
510
|
+
fs.writeFileSync(path.join(steeringDir, "tech.md"), techContent);
|
|
511
|
+
fs.writeFileSync(path.join(steeringDir, "structure.md"), structureContent);
|
|
489
512
|
await ensureStaticSteeringDocuments(projectPath, stubSteeringService);
|
|
490
513
|
// Ensure AGENTS.md exists (based on CLAUDE.md if available)
|
|
491
|
-
const agentsPath = path.join(projectPath,
|
|
514
|
+
const agentsPath = path.join(projectPath, "AGENTS.md");
|
|
492
515
|
if (!fs.existsSync(agentsPath)) {
|
|
493
|
-
const claudePath = path.join(projectPath,
|
|
494
|
-
let agentsContent =
|
|
516
|
+
const claudePath = path.join(projectPath, "CLAUDE.md");
|
|
517
|
+
let agentsContent = "";
|
|
495
518
|
if (fs.existsSync(claudePath)) {
|
|
496
|
-
const claudeContent = fs.readFileSync(claudePath,
|
|
519
|
+
const claudeContent = fs.readFileSync(claudePath, "utf8");
|
|
497
520
|
agentsContent = claudeContent
|
|
498
|
-
.replace(/# Claude Code Spec-Driven Development/g,
|
|
499
|
-
.replace(/Claude Code/g,
|
|
500
|
-
.replace(/claude code/g,
|
|
501
|
-
.replace(/\.claude\//g,
|
|
502
|
-
.replace(/\/claude/g,
|
|
521
|
+
.replace(/# Claude Code Spec-Driven Development/g, "# AI Agent Spec-Driven Development")
|
|
522
|
+
.replace(/Claude Code/g, "AI Agent")
|
|
523
|
+
.replace(/claude code/g, "ai agent")
|
|
524
|
+
.replace(/\.claude\//g, ".ai agent/")
|
|
525
|
+
.replace(/\/claude/g, "/agent");
|
|
503
526
|
}
|
|
504
527
|
else {
|
|
505
528
|
agentsContent = `# AI Agent Spec-Driven Development
|
|
@@ -585,8 +608,9 @@ Generated on: ${new Date().toISOString()}
|
|
|
585
608
|
fs.writeFileSync(agentsPath, agentsContent);
|
|
586
609
|
}
|
|
587
610
|
return {
|
|
588
|
-
content: [
|
|
589
|
-
|
|
611
|
+
content: [
|
|
612
|
+
{
|
|
613
|
+
type: "text",
|
|
590
614
|
text: `## Steering Documents Updated
|
|
591
615
|
|
|
592
616
|
**Project**: ${projectAnalysis.name}
|
|
@@ -604,39 +628,42 @@ Generated on: ${new Date().toISOString()}
|
|
|
604
628
|
- \`.kiro/steering/principles.md\` - Core coding principles: SOLID, DRY, KISS, YAGNI, SoC, Modularity (static)
|
|
605
629
|
|
|
606
630
|
**Dynamic Analysis Results**:
|
|
607
|
-
- **Language**: ${projectAnalysis.language ===
|
|
608
|
-
- **Framework**: ${projectAnalysis.framework ||
|
|
631
|
+
- **Language**: ${projectAnalysis.language === "typescript" ? "TypeScript" : "JavaScript"}
|
|
632
|
+
- **Framework**: ${projectAnalysis.framework || "None detected"}
|
|
609
633
|
- **Dependencies**: ${projectAnalysis.dependencies.length} production, ${projectAnalysis.devDependencies.length} development
|
|
610
|
-
- **Test Framework**: ${projectAnalysis.testFramework ||
|
|
611
|
-
- **Build Tool**: ${projectAnalysis.buildTool ||
|
|
634
|
+
- **Test Framework**: ${projectAnalysis.testFramework || "None detected"}
|
|
635
|
+
- **Build Tool**: ${projectAnalysis.buildTool || "None detected"}
|
|
612
636
|
- **Project Structure**: ${projectAnalysis.directories.length} directories analyzed
|
|
613
|
-
- **CI/CD**: ${projectAnalysis.hasCI ?
|
|
614
|
-
- **Docker**: ${projectAnalysis.hasDocker ?
|
|
637
|
+
- **CI/CD**: ${projectAnalysis.hasCI ? "Configured" : "Not configured"}
|
|
638
|
+
- **Docker**: ${projectAnalysis.hasDocker ? "Configured" : "Not configured"}
|
|
615
639
|
|
|
616
|
-
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions
|
|
617
|
-
}
|
|
640
|
+
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions.`,
|
|
641
|
+
},
|
|
642
|
+
],
|
|
618
643
|
};
|
|
619
644
|
}
|
|
620
645
|
catch (error) {
|
|
621
646
|
return {
|
|
622
|
-
content: [
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
647
|
+
content: [
|
|
648
|
+
{
|
|
649
|
+
type: "text",
|
|
650
|
+
text: `Error generating steering documents: ${error.message}`,
|
|
651
|
+
},
|
|
652
|
+
],
|
|
653
|
+
isError: true,
|
|
627
654
|
};
|
|
628
655
|
}
|
|
629
656
|
}
|
|
630
657
|
async function handleSteeringCustomSimplified(args) {
|
|
631
|
-
const fs = await import(
|
|
632
|
-
const path = await import(
|
|
658
|
+
const fs = await import("fs");
|
|
659
|
+
const path = await import("path");
|
|
633
660
|
try {
|
|
634
661
|
const { fileName, topic, inclusionMode, filePattern } = args;
|
|
635
662
|
if (!fileName || !topic || !inclusionMode) {
|
|
636
|
-
throw new Error(
|
|
663
|
+
throw new Error("fileName, topic, and inclusionMode are required");
|
|
637
664
|
}
|
|
638
665
|
const projectPath = process.cwd();
|
|
639
|
-
const steeringDir = path.join(projectPath,
|
|
666
|
+
const steeringDir = path.join(projectPath, ".kiro", "steering");
|
|
640
667
|
if (!fs.existsSync(steeringDir)) {
|
|
641
668
|
fs.mkdirSync(steeringDir, { recursive: true });
|
|
642
669
|
}
|
|
@@ -653,59 +680,85 @@ Define the purpose and scope of this steering document.
|
|
|
653
680
|
Describe when and how this steering document should be applied.
|
|
654
681
|
|
|
655
682
|
## Inclusion Mode
|
|
656
|
-
Mode: ${inclusionMode}${filePattern
|
|
657
|
-
|
|
683
|
+
Mode: ${inclusionMode}${filePattern
|
|
684
|
+
? `
|
|
685
|
+
Pattern: ${filePattern}`
|
|
686
|
+
: ""}
|
|
658
687
|
|
|
659
688
|
Generated on: ${new Date().toISOString()}
|
|
660
689
|
`;
|
|
661
690
|
fs.writeFileSync(path.join(steeringDir, fileName), content);
|
|
662
691
|
return {
|
|
663
|
-
content: [
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
692
|
+
content: [
|
|
693
|
+
{
|
|
694
|
+
type: "text",
|
|
695
|
+
text: `Custom steering document "${fileName}" created successfully with ${inclusionMode} inclusion mode.`,
|
|
696
|
+
},
|
|
697
|
+
],
|
|
667
698
|
};
|
|
668
699
|
}
|
|
669
700
|
catch (error) {
|
|
670
701
|
return {
|
|
671
|
-
content: [
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
702
|
+
content: [
|
|
703
|
+
{
|
|
704
|
+
type: "text",
|
|
705
|
+
text: `Error creating custom steering document: ${error.message}`,
|
|
706
|
+
},
|
|
707
|
+
],
|
|
708
|
+
isError: true,
|
|
676
709
|
};
|
|
677
710
|
}
|
|
678
711
|
}
|
|
679
712
|
// Status handler aligned with full server behavior
|
|
680
713
|
async function handleStatusSimplified(args) {
|
|
681
|
-
const fs = await import(
|
|
682
|
-
const path = await import(
|
|
714
|
+
const fs = await import("fs");
|
|
715
|
+
const path = await import("path");
|
|
683
716
|
const { featureName } = args || {};
|
|
684
717
|
const currentPath = process.cwd();
|
|
685
|
-
const kiroPath = path.join(currentPath,
|
|
686
|
-
const exists = await fs.promises
|
|
718
|
+
const kiroPath = path.join(currentPath, ".kiro");
|
|
719
|
+
const exists = await fs.promises
|
|
720
|
+
.access(kiroPath)
|
|
721
|
+
.then(() => true)
|
|
722
|
+
.catch(() => false);
|
|
687
723
|
if (!exists) {
|
|
688
|
-
return {
|
|
724
|
+
return {
|
|
725
|
+
content: [
|
|
726
|
+
{
|
|
727
|
+
type: "text",
|
|
728
|
+
text: "SDD project status: No active project found. Use sdd-init to create a new project.",
|
|
729
|
+
},
|
|
730
|
+
],
|
|
731
|
+
};
|
|
689
732
|
}
|
|
690
|
-
const specsPath = path.join(kiroPath,
|
|
733
|
+
const specsPath = path.join(kiroPath, "specs");
|
|
691
734
|
if (featureName) {
|
|
692
735
|
const featurePath = path.join(specsPath, featureName);
|
|
693
|
-
const specPath = path.join(featurePath,
|
|
694
|
-
const specExists = await fs.promises
|
|
736
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
737
|
+
const specExists = await fs.promises
|
|
738
|
+
.access(specPath)
|
|
739
|
+
.then(() => true)
|
|
740
|
+
.catch(() => false);
|
|
695
741
|
if (!specExists) {
|
|
696
|
-
return {
|
|
742
|
+
return {
|
|
743
|
+
content: [
|
|
744
|
+
{
|
|
745
|
+
type: "text",
|
|
746
|
+
text: `Feature "${featureName}" not found. Use sdd-init to create it.`,
|
|
747
|
+
},
|
|
748
|
+
],
|
|
749
|
+
};
|
|
697
750
|
}
|
|
698
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
751
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
699
752
|
let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
|
|
700
753
|
status += `**Current Phase**: ${spec.phase}\n`;
|
|
701
754
|
status += `**Language**: ${spec.language}\n`;
|
|
702
755
|
status += `**Created**: ${spec.created_at}\n`;
|
|
703
756
|
status += `**Updated**: ${spec.updated_at}\n\n`;
|
|
704
757
|
status += `**Phase Progress**:\n`;
|
|
705
|
-
status += `- Requirements: ${spec.approvals.requirements.generated ?
|
|
706
|
-
status += `- Design: ${spec.approvals.design.generated ?
|
|
707
|
-
status += `- Tasks: ${spec.approvals.tasks.generated ?
|
|
708
|
-
status += `**Ready for Implementation**: ${spec.ready_for_implementation ?
|
|
758
|
+
status += `- Requirements: ${spec.approvals.requirements.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.requirements.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
|
|
759
|
+
status += `- Design: ${spec.approvals.design.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.design.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
|
|
760
|
+
status += `- Tasks: ${spec.approvals.tasks.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.tasks.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n\n`;
|
|
761
|
+
status += `**Ready for Implementation**: ${spec.ready_for_implementation ? "✅ Yes" : "❌ No"}\n\n`;
|
|
709
762
|
if (!spec.approvals.requirements.generated)
|
|
710
763
|
status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
|
|
711
764
|
else if (!spec.approvals.design.generated)
|
|
@@ -714,95 +767,168 @@ async function handleStatusSimplified(args) {
|
|
|
714
767
|
status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
|
|
715
768
|
else
|
|
716
769
|
status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
|
|
717
|
-
return { content: [{ type:
|
|
770
|
+
return { content: [{ type: "text", text: status }] };
|
|
718
771
|
}
|
|
719
|
-
const features = await fs.promises
|
|
772
|
+
const features = await fs.promises
|
|
773
|
+
.readdir(specsPath)
|
|
774
|
+
.catch(() => []);
|
|
720
775
|
if (features.length === 0) {
|
|
721
|
-
return {
|
|
776
|
+
return {
|
|
777
|
+
content: [
|
|
778
|
+
{
|
|
779
|
+
type: "text",
|
|
780
|
+
text: "No SDD features found. Use sdd-init to create a new project.",
|
|
781
|
+
},
|
|
782
|
+
],
|
|
783
|
+
};
|
|
722
784
|
}
|
|
723
|
-
let status =
|
|
785
|
+
let status = "## SDD Project Status - All Features\n\n";
|
|
724
786
|
for (const feature of features) {
|
|
725
|
-
const specPath = path.join(specsPath, feature,
|
|
726
|
-
const specExists = await fs.promises
|
|
787
|
+
const specPath = path.join(specsPath, feature, "spec.json");
|
|
788
|
+
const specExists = await fs.promises
|
|
789
|
+
.access(specPath)
|
|
790
|
+
.then(() => true)
|
|
791
|
+
.catch(() => false);
|
|
727
792
|
if (specExists) {
|
|
728
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
793
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
729
794
|
status += `**${spec.feature_name}**:\n`;
|
|
730
795
|
status += `- Phase: ${spec.phase}\n`;
|
|
731
|
-
status += `- Requirements: ${spec.approvals.requirements.generated ?
|
|
732
|
-
status += `- Design: ${spec.approvals.design.generated ?
|
|
733
|
-
status += `- Tasks: ${spec.approvals.tasks.generated ?
|
|
734
|
-
status += `- Ready: ${spec.ready_for_implementation ?
|
|
796
|
+
status += `- Requirements: ${spec.approvals.requirements.generated ? "✅" : "❌"}\n`;
|
|
797
|
+
status += `- Design: ${spec.approvals.design.generated ? "✅" : "❌"}\n`;
|
|
798
|
+
status += `- Tasks: ${spec.approvals.tasks.generated ? "✅" : "❌"}\n`;
|
|
799
|
+
status += `- Ready: ${spec.ready_for_implementation ? "✅" : "❌"}\n\n`;
|
|
735
800
|
}
|
|
736
801
|
}
|
|
737
|
-
return { content: [{ type:
|
|
802
|
+
return { content: [{ type: "text", text: status }] };
|
|
738
803
|
}
|
|
739
804
|
// Approve handler to update spec.json
|
|
740
805
|
async function handleApproveSimplified(args) {
|
|
741
|
-
const fs = await import(
|
|
742
|
-
const path = await import(
|
|
806
|
+
const fs = await import("fs");
|
|
807
|
+
const path = await import("path");
|
|
743
808
|
const { featureName, phase } = args || {};
|
|
744
809
|
if (!featureName || !phase) {
|
|
745
|
-
return {
|
|
810
|
+
return {
|
|
811
|
+
content: [{ type: "text", text: "featureName and phase are required" }],
|
|
812
|
+
isError: true,
|
|
813
|
+
};
|
|
746
814
|
}
|
|
747
815
|
try {
|
|
748
|
-
const featurePath = path.join(process.cwd(),
|
|
749
|
-
const specPath = path.join(featurePath,
|
|
750
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
816
|
+
const featurePath = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
817
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
818
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
751
819
|
if (!spec.approvals?.[phase]?.generated) {
|
|
752
|
-
return {
|
|
820
|
+
return {
|
|
821
|
+
content: [
|
|
822
|
+
{
|
|
823
|
+
type: "text",
|
|
824
|
+
text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`,
|
|
825
|
+
},
|
|
826
|
+
],
|
|
827
|
+
};
|
|
753
828
|
}
|
|
754
829
|
spec.approvals[phase].approved = true;
|
|
755
830
|
spec.updated_at = new Date().toISOString();
|
|
756
831
|
fs.writeFileSync(specPath, JSON.stringify(spec, null, 2));
|
|
757
|
-
return {
|
|
832
|
+
return {
|
|
833
|
+
content: [
|
|
834
|
+
{
|
|
835
|
+
type: "text",
|
|
836
|
+
text: `## Phase Approved\n\n**Feature**: ${featureName}\n**Phase**: ${phase}\n**Status**: ✅ Approved`,
|
|
837
|
+
},
|
|
838
|
+
],
|
|
839
|
+
};
|
|
758
840
|
}
|
|
759
841
|
catch (error) {
|
|
760
|
-
return {
|
|
842
|
+
return {
|
|
843
|
+
content: [
|
|
844
|
+
{
|
|
845
|
+
type: "text",
|
|
846
|
+
text: `Error approving phase: ${error.message}`,
|
|
847
|
+
},
|
|
848
|
+
],
|
|
849
|
+
isError: true,
|
|
850
|
+
};
|
|
761
851
|
}
|
|
762
852
|
}
|
|
763
853
|
// Simple quality check aligned with full server
|
|
764
854
|
async function handleQualityCheckSimplified(args) {
|
|
765
|
-
const { code =
|
|
855
|
+
const { code = "", language = "javascript" } = args || {};
|
|
766
856
|
try {
|
|
767
|
-
const lines = String(code).split(
|
|
857
|
+
const lines = String(code).split("\n");
|
|
768
858
|
const issues = [];
|
|
769
|
-
if (code.includes(
|
|
770
|
-
issues.push(
|
|
771
|
-
if (code.includes(
|
|
772
|
-
issues.push(
|
|
773
|
-
if (!/^[a-z]/.test(code.split(
|
|
774
|
-
if (code.includes(
|
|
775
|
-
issues.push(
|
|
859
|
+
if (code.includes("console.log"))
|
|
860
|
+
issues.push("L1: Remove debug console.log statements");
|
|
861
|
+
if (code.includes("var "))
|
|
862
|
+
issues.push("L1: Use let/const instead of var");
|
|
863
|
+
if (!/^[a-z]/.test(code.split("function ")[1]?.split("(")[0] || "")) {
|
|
864
|
+
if (code.includes("function "))
|
|
865
|
+
issues.push("L2: Function names should start with lowercase");
|
|
776
866
|
}
|
|
777
|
-
if (code.includes(
|
|
778
|
-
issues.push(
|
|
867
|
+
if (code.includes("for") && !code.includes("const"))
|
|
868
|
+
issues.push("L3: Prefer const in for loops");
|
|
779
869
|
if (lines.length > 50)
|
|
780
|
-
issues.push(
|
|
781
|
-
const report = `## Code Quality Analysis (${language})\n\n` +
|
|
782
|
-
|
|
870
|
+
issues.push("L4: Consider splitting large blocks into smaller functions");
|
|
871
|
+
const report = `## Code Quality Analysis (${language})\n\n` +
|
|
872
|
+
(issues.length
|
|
873
|
+
? issues.map((i) => `- ${i}`).join("\n")
|
|
874
|
+
: "No significant issues detected");
|
|
875
|
+
return { content: [{ type: "text", text: report }] };
|
|
783
876
|
}
|
|
784
877
|
catch (error) {
|
|
785
|
-
return {
|
|
878
|
+
return {
|
|
879
|
+
content: [
|
|
880
|
+
{
|
|
881
|
+
type: "text",
|
|
882
|
+
text: `Error analyzing code quality: ${error.message}`,
|
|
883
|
+
},
|
|
884
|
+
],
|
|
885
|
+
isError: true,
|
|
886
|
+
};
|
|
786
887
|
}
|
|
787
888
|
}
|
|
788
889
|
// Implement guidelines check
|
|
789
890
|
async function handleImplementSimplified(args) {
|
|
790
|
-
const fs = await import(
|
|
791
|
-
const path = await import(
|
|
891
|
+
const fs = await import("fs");
|
|
892
|
+
const path = await import("path");
|
|
792
893
|
const { featureName } = args || {};
|
|
793
894
|
if (!featureName)
|
|
794
|
-
return {
|
|
895
|
+
return {
|
|
896
|
+
content: [{ type: "text", text: "featureName is required" }],
|
|
897
|
+
isError: true,
|
|
898
|
+
};
|
|
795
899
|
try {
|
|
796
|
-
const featurePath = path.join(process.cwd(),
|
|
797
|
-
const specPath = path.join(featurePath,
|
|
798
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
900
|
+
const featurePath = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
901
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
902
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
799
903
|
if (!spec.ready_for_implementation) {
|
|
800
|
-
return {
|
|
904
|
+
return {
|
|
905
|
+
content: [
|
|
906
|
+
{
|
|
907
|
+
type: "text",
|
|
908
|
+
text: "Error: Project not ready for implementation. Complete requirements, design, and tasks phases first.",
|
|
909
|
+
},
|
|
910
|
+
],
|
|
911
|
+
};
|
|
801
912
|
}
|
|
802
|
-
return {
|
|
913
|
+
return {
|
|
914
|
+
content: [
|
|
915
|
+
{
|
|
916
|
+
type: "text",
|
|
917
|
+
text: `## Implementation Guidelines for ${featureName}\n\nFollow tasks in tasks.md, implement per design.md, and validate against requirements.md. Use sdd-quality-check during development.`,
|
|
918
|
+
},
|
|
919
|
+
],
|
|
920
|
+
};
|
|
803
921
|
}
|
|
804
922
|
catch (error) {
|
|
805
|
-
return {
|
|
923
|
+
return {
|
|
924
|
+
content: [
|
|
925
|
+
{
|
|
926
|
+
type: "text",
|
|
927
|
+
text: `Error getting implementation guidelines: ${error.message}`,
|
|
928
|
+
},
|
|
929
|
+
],
|
|
930
|
+
isError: true,
|
|
931
|
+
};
|
|
806
932
|
}
|
|
807
933
|
}
|
|
808
934
|
// Helper functions for simplified analysis
|
|
@@ -811,73 +937,79 @@ function extractFeaturesSimplified(packageJson) {
|
|
|
811
937
|
// Extract features from scripts
|
|
812
938
|
if (packageJson.scripts) {
|
|
813
939
|
if (packageJson.scripts.test)
|
|
814
|
-
features.push(
|
|
940
|
+
features.push("Testing framework");
|
|
815
941
|
if (packageJson.scripts.build)
|
|
816
|
-
features.push(
|
|
942
|
+
features.push("Build system");
|
|
817
943
|
if (packageJson.scripts.dev || packageJson.scripts.start)
|
|
818
|
-
features.push(
|
|
944
|
+
features.push("Development server");
|
|
819
945
|
if (packageJson.scripts.lint)
|
|
820
|
-
features.push(
|
|
946
|
+
features.push("Code linting");
|
|
821
947
|
if (packageJson.scripts.typecheck)
|
|
822
|
-
features.push(
|
|
948
|
+
features.push("Type checking");
|
|
823
949
|
}
|
|
824
950
|
// Extract features from dependencies
|
|
825
951
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
826
952
|
if (deps?.express || deps?.fastify || deps?.koa)
|
|
827
|
-
features.push(
|
|
953
|
+
features.push("Web server");
|
|
828
954
|
if (deps?.react || deps?.vue || deps?.angular)
|
|
829
|
-
features.push(
|
|
955
|
+
features.push("Frontend framework");
|
|
830
956
|
if (deps?.typescript)
|
|
831
|
-
features.push(
|
|
957
|
+
features.push("TypeScript support");
|
|
832
958
|
if (deps?.jest || deps?.mocha || deps?.vitest)
|
|
833
|
-
features.push(
|
|
959
|
+
features.push("Unit testing");
|
|
834
960
|
if (deps?.eslint)
|
|
835
|
-
features.push(
|
|
836
|
-
return features.length > 0 ? features : [
|
|
961
|
+
features.push("Code quality enforcement");
|
|
962
|
+
return features.length > 0 ? features : ["Core functionality"];
|
|
837
963
|
}
|
|
838
964
|
function generateTargetUsersSimplified(packageJson) {
|
|
839
|
-
if (packageJson.keywords?.includes(
|
|
840
|
-
return
|
|
965
|
+
if (packageJson.keywords?.includes("cli")) {
|
|
966
|
+
return "- Command-line tool users\n- Developers and system administrators";
|
|
841
967
|
}
|
|
842
|
-
if (packageJson.keywords?.includes(
|
|
843
|
-
return
|
|
968
|
+
if (packageJson.keywords?.includes("api")) {
|
|
969
|
+
return "- API consumers\n- Third-party integrators";
|
|
844
970
|
}
|
|
845
|
-
return
|
|
971
|
+
return "- Primary user persona\n- Secondary user persona";
|
|
846
972
|
}
|
|
847
973
|
function generateTechStackSimplified(packageJson) {
|
|
848
974
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
849
975
|
const stack = [];
|
|
850
976
|
if (deps?.typescript)
|
|
851
|
-
stack.push(
|
|
977
|
+
stack.push("TypeScript");
|
|
852
978
|
if (deps?.node || packageJson.engines?.node)
|
|
853
|
-
stack.push(
|
|
979
|
+
stack.push("Node.js");
|
|
854
980
|
if (deps?.express)
|
|
855
|
-
stack.push(
|
|
981
|
+
stack.push("Express.js");
|
|
856
982
|
if (deps?.react)
|
|
857
|
-
stack.push(
|
|
983
|
+
stack.push("React");
|
|
858
984
|
if (deps?.vue)
|
|
859
|
-
stack.push(
|
|
860
|
-
return stack.length > 0 ? stack.join(
|
|
985
|
+
stack.push("Vue.js");
|
|
986
|
+
return stack.length > 0 ? stack.join(", ") : "Technology stack to be defined";
|
|
861
987
|
}
|
|
862
988
|
function generateDependencyListSimplified(packageJson) {
|
|
863
989
|
const deps = packageJson.dependencies || {};
|
|
864
990
|
const devDeps = packageJson.devDependencies || {};
|
|
865
|
-
let list =
|
|
991
|
+
let list = "";
|
|
866
992
|
const depList = Object.keys(deps);
|
|
867
993
|
const devDepList = Object.keys(devDeps);
|
|
868
994
|
if (depList.length > 0) {
|
|
869
|
-
list +=
|
|
870
|
-
list += depList
|
|
995
|
+
list += "### Production Dependencies\n";
|
|
996
|
+
list += depList
|
|
997
|
+
.slice(0, 10)
|
|
998
|
+
.map((dep) => `- ${dep}`)
|
|
999
|
+
.join("\n");
|
|
871
1000
|
}
|
|
872
1001
|
if (devDepList.length > 0) {
|
|
873
|
-
list +=
|
|
874
|
-
list += devDepList
|
|
1002
|
+
list += "\n### Development Dependencies\n";
|
|
1003
|
+
list += devDepList
|
|
1004
|
+
.slice(0, 10)
|
|
1005
|
+
.map((dep) => `- ${dep}`)
|
|
1006
|
+
.join("\n");
|
|
875
1007
|
}
|
|
876
|
-
return list ||
|
|
1008
|
+
return list || "Dependencies to be analyzed";
|
|
877
1009
|
}
|
|
878
1010
|
function generateWorkflowSimplified(packageJson) {
|
|
879
1011
|
const scripts = packageJson.scripts || {};
|
|
880
|
-
let workflow =
|
|
1012
|
+
let workflow = "## Development Commands\n";
|
|
881
1013
|
if (scripts.dev)
|
|
882
1014
|
workflow += `- \`npm run dev\` - Start development server\n`;
|
|
883
1015
|
if (scripts.build)
|
|
@@ -889,27 +1021,29 @@ function generateWorkflowSimplified(packageJson) {
|
|
|
889
1021
|
return workflow;
|
|
890
1022
|
}
|
|
891
1023
|
function generateDirectoryStructureSimplified(projectPath) {
|
|
892
|
-
const fs = require(
|
|
1024
|
+
const fs = require("fs");
|
|
893
1025
|
try {
|
|
894
1026
|
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
895
1027
|
const directories = items
|
|
896
|
-
.filter((item) => item.isDirectory() &&
|
|
1028
|
+
.filter((item) => item.isDirectory() &&
|
|
1029
|
+
!item.name.startsWith(".") &&
|
|
1030
|
+
item.name !== "node_modules")
|
|
897
1031
|
.map((item) => `- ${item.name}/`)
|
|
898
|
-
.join(
|
|
899
|
-
return directories ||
|
|
1032
|
+
.join("\n");
|
|
1033
|
+
return directories || "Directory structure to be analyzed";
|
|
900
1034
|
}
|
|
901
1035
|
catch (error) {
|
|
902
|
-
return
|
|
1036
|
+
return "Directory structure to be analyzed";
|
|
903
1037
|
}
|
|
904
1038
|
}
|
|
905
1039
|
// Additional context-aware SDD tools
|
|
906
1040
|
async function handleRequirementsSimplified(args) {
|
|
907
|
-
const fs = await import(
|
|
908
|
-
const path = await import(
|
|
1041
|
+
const fs = await import("fs");
|
|
1042
|
+
const path = await import("path");
|
|
909
1043
|
try {
|
|
910
1044
|
const { featureName } = args;
|
|
911
|
-
if (!featureName || typeof featureName !==
|
|
912
|
-
throw new Error(
|
|
1045
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1046
|
+
throw new Error("Feature name is required for requirements generation");
|
|
913
1047
|
}
|
|
914
1048
|
// Load spec context
|
|
915
1049
|
const { spec, requirements } = await loadSpecContext(featureName);
|
|
@@ -917,7 +1051,7 @@ async function handleRequirementsSimplified(args) {
|
|
|
917
1051
|
throw new Error(`Feature "${featureName}" not found. Run sdd-init first.`);
|
|
918
1052
|
}
|
|
919
1053
|
// Extract project description from spec
|
|
920
|
-
let projectDescription =
|
|
1054
|
+
let projectDescription = "Feature requirements specification";
|
|
921
1055
|
if (requirements) {
|
|
922
1056
|
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
923
1057
|
if (descMatch) {
|
|
@@ -928,17 +1062,17 @@ async function handleRequirementsSimplified(args) {
|
|
|
928
1062
|
let requirementsContent;
|
|
929
1063
|
let analysisUsed = false;
|
|
930
1064
|
try {
|
|
931
|
-
console.error(
|
|
932
|
-
const { generateRequirementsDocument } = await
|
|
933
|
-
console.error(
|
|
1065
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive analysis...");
|
|
1066
|
+
const { generateRequirementsDocument } = await loadSpecGenerator();
|
|
1067
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating requirements...");
|
|
934
1068
|
requirementsContent = await generateRequirementsDocument(process.cwd(), featureName);
|
|
935
1069
|
analysisUsed = true;
|
|
936
|
-
console.error(
|
|
1070
|
+
console.error("[SDD-DEBUG] ✅ Requirements generated using comprehensive codebase analysis");
|
|
937
1071
|
}
|
|
938
1072
|
catch (genErr) {
|
|
939
|
-
console.error(
|
|
940
|
-
console.error(
|
|
941
|
-
console.error(
|
|
1073
|
+
console.error("[SDD-DEBUG] ⚠️ Comprehensive analysis failed, using fallback template");
|
|
1074
|
+
console.error("[SDD-DEBUG] Error details:", genErr.message);
|
|
1075
|
+
console.error("[SDD-DEBUG] Stack:", genErr.stack);
|
|
942
1076
|
requirementsContent = `# Requirements Document
|
|
943
1077
|
|
|
944
1078
|
<!-- Note: Using basic template due to analysis error: ${genErr.message} -->
|
|
@@ -952,7 +1086,9 @@ ${generateIntroductionFromDescription(projectDescription)}
|
|
|
952
1086
|
**Objective:** As a user, I want ${extractPrimaryObjective(projectDescription)}, so that ${extractPrimaryBenefit(projectDescription)}
|
|
953
1087
|
|
|
954
1088
|
#### Acceptance Criteria
|
|
955
|
-
${generateEARSRequirements(projectDescription)
|
|
1089
|
+
${generateEARSRequirements(projectDescription)
|
|
1090
|
+
.map((req, index) => `${index + 1}. ${req}`)
|
|
1091
|
+
.join("\n")}
|
|
956
1092
|
|
|
957
1093
|
### Requirement 2: System Quality
|
|
958
1094
|
**Objective:** As a user, I want the system to be reliable and performant, so that I can depend on it for my work
|
|
@@ -972,60 +1108,64 @@ ${generateEARSRequirements(projectDescription).map((req, index) => `${index + 1}
|
|
|
972
1108
|
`;
|
|
973
1109
|
}
|
|
974
1110
|
// Update spec.json with phase information
|
|
975
|
-
const specDir = path.join(process.cwd(),
|
|
1111
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
976
1112
|
const updatedSpec = {
|
|
977
1113
|
...spec,
|
|
978
|
-
phase:
|
|
1114
|
+
phase: "requirements-generated",
|
|
979
1115
|
approvals: {
|
|
980
1116
|
...spec.approvals,
|
|
981
1117
|
requirements: {
|
|
982
1118
|
generated: true,
|
|
983
|
-
approved: false
|
|
984
|
-
}
|
|
1119
|
+
approved: false,
|
|
1120
|
+
},
|
|
985
1121
|
},
|
|
986
|
-
updated_at: new Date().toISOString()
|
|
1122
|
+
updated_at: new Date().toISOString(),
|
|
987
1123
|
};
|
|
988
|
-
fs.writeFileSync(path.join(specDir,
|
|
989
|
-
fs.writeFileSync(path.join(specDir,
|
|
1124
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1125
|
+
fs.writeFileSync(path.join(specDir, "requirements.md"), requirementsContent);
|
|
990
1126
|
return {
|
|
991
|
-
content: [
|
|
992
|
-
|
|
1127
|
+
content: [
|
|
1128
|
+
{
|
|
1129
|
+
type: "text",
|
|
993
1130
|
text: `## Requirements Document Generated
|
|
994
1131
|
|
|
995
1132
|
**Feature**: \`${featureName}\`
|
|
996
1133
|
**File**: \`.kiro/specs/${featureName}/requirements.md\`
|
|
997
1134
|
|
|
998
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1135
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (multi-language support)" : "⚠️ Basic template (analysis failed)"}
|
|
999
1136
|
|
|
1000
1137
|
**Generated Requirements**:
|
|
1001
1138
|
- Core functionality requirements with EARS format
|
|
1002
1139
|
- System quality and reliability requirements
|
|
1003
1140
|
- Usability and user experience requirements
|
|
1004
1141
|
|
|
1005
|
-
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ?
|
|
1142
|
+
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? "..." : ""}"
|
|
1006
1143
|
|
|
1007
1144
|
**Workflow Phase**: Requirements Generated
|
|
1008
|
-
**Next Step**: Run \`sdd-design ${featureName}\` to create technical design (after requirements review)
|
|
1009
|
-
}
|
|
1145
|
+
**Next Step**: Run \`sdd-design ${featureName}\` to create technical design (after requirements review)`,
|
|
1146
|
+
},
|
|
1147
|
+
],
|
|
1010
1148
|
};
|
|
1011
1149
|
}
|
|
1012
1150
|
catch (error) {
|
|
1013
1151
|
return {
|
|
1014
|
-
content: [
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1152
|
+
content: [
|
|
1153
|
+
{
|
|
1154
|
+
type: "text",
|
|
1155
|
+
text: `Error generating requirements document: ${error.message}`,
|
|
1156
|
+
},
|
|
1157
|
+
],
|
|
1158
|
+
isError: true,
|
|
1019
1159
|
};
|
|
1020
1160
|
}
|
|
1021
1161
|
}
|
|
1022
1162
|
async function handleDesignSimplified(args) {
|
|
1023
|
-
const fs = await import(
|
|
1024
|
-
const path = await import(
|
|
1163
|
+
const fs = await import("fs");
|
|
1164
|
+
const path = await import("path");
|
|
1025
1165
|
try {
|
|
1026
1166
|
const { featureName } = args;
|
|
1027
|
-
if (!featureName || typeof featureName !==
|
|
1028
|
-
throw new Error(
|
|
1167
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1168
|
+
throw new Error("Feature name is required for design generation");
|
|
1029
1169
|
}
|
|
1030
1170
|
// Load spec context
|
|
1031
1171
|
const { spec, requirements } = await loadSpecContext(featureName);
|
|
@@ -1037,7 +1177,7 @@ async function handleDesignSimplified(args) {
|
|
|
1037
1177
|
throw new Error(`Requirements must be generated before design. Run sdd-requirements ${featureName} first.`);
|
|
1038
1178
|
}
|
|
1039
1179
|
// Extract project description from requirements
|
|
1040
|
-
let projectDescription =
|
|
1180
|
+
let projectDescription = "Technical design specification";
|
|
1041
1181
|
if (requirements) {
|
|
1042
1182
|
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
1043
1183
|
if (descMatch) {
|
|
@@ -1048,16 +1188,16 @@ async function handleDesignSimplified(args) {
|
|
|
1048
1188
|
let designContent;
|
|
1049
1189
|
let analysisUsed = false;
|
|
1050
1190
|
try {
|
|
1051
|
-
console.error(
|
|
1052
|
-
const { generateDesignDocument } = await
|
|
1053
|
-
console.error(
|
|
1191
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive design analysis...");
|
|
1192
|
+
const { generateDesignDocument } = await loadSpecGenerator();
|
|
1193
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating design...");
|
|
1054
1194
|
designContent = await generateDesignDocument(process.cwd(), featureName);
|
|
1055
1195
|
analysisUsed = true;
|
|
1056
|
-
console.error(
|
|
1196
|
+
console.error("[SDD-DEBUG] ✅ Design generated using comprehensive codebase analysis");
|
|
1057
1197
|
}
|
|
1058
1198
|
catch (genErr) {
|
|
1059
|
-
console.error(
|
|
1060
|
-
console.error(
|
|
1199
|
+
console.error("[SDD-DEBUG] ⚠️ Comprehensive analysis failed, using fallback template");
|
|
1200
|
+
console.error("[SDD-DEBUG] Error details:", genErr.message);
|
|
1061
1201
|
designContent = `# Technical Design Document
|
|
1062
1202
|
|
|
1063
1203
|
<!-- Note: Using basic template due to analysis error: ${genErr.message} -->
|
|
@@ -1075,30 +1215,31 @@ This design document specifies the technical implementation approach for ${spec.
|
|
|
1075
1215
|
`;
|
|
1076
1216
|
}
|
|
1077
1217
|
// Update spec.json with phase information
|
|
1078
|
-
const specDir = path.join(process.cwd(),
|
|
1218
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1079
1219
|
const updatedSpec = {
|
|
1080
1220
|
...spec,
|
|
1081
|
-
phase:
|
|
1221
|
+
phase: "design-generated",
|
|
1082
1222
|
approvals: {
|
|
1083
1223
|
...spec.approvals,
|
|
1084
1224
|
design: {
|
|
1085
1225
|
generated: true,
|
|
1086
|
-
approved: false
|
|
1087
|
-
}
|
|
1226
|
+
approved: false,
|
|
1227
|
+
},
|
|
1088
1228
|
},
|
|
1089
|
-
updated_at: new Date().toISOString()
|
|
1229
|
+
updated_at: new Date().toISOString(),
|
|
1090
1230
|
};
|
|
1091
|
-
fs.writeFileSync(path.join(specDir,
|
|
1092
|
-
fs.writeFileSync(path.join(specDir,
|
|
1231
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1232
|
+
fs.writeFileSync(path.join(specDir, "design.md"), designContent);
|
|
1093
1233
|
return {
|
|
1094
|
-
content: [
|
|
1095
|
-
|
|
1234
|
+
content: [
|
|
1235
|
+
{
|
|
1236
|
+
type: "text",
|
|
1096
1237
|
text: `## Design Document Generated
|
|
1097
1238
|
|
|
1098
1239
|
**Feature**: \`${featureName}\`
|
|
1099
1240
|
**File**: \`.kiro/specs/${featureName}/design.md\`
|
|
1100
1241
|
|
|
1101
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1242
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (architecture patterns detected)" : "⚠️ Basic template (analysis failed)"}
|
|
1102
1243
|
|
|
1103
1244
|
**Design Elements**:
|
|
1104
1245
|
- Modular architecture with clear component separation
|
|
@@ -1106,30 +1247,33 @@ This design document specifies the technical implementation approach for ${spec.
|
|
|
1106
1247
|
- Data models and error handling strategy
|
|
1107
1248
|
- Complete testing approach
|
|
1108
1249
|
|
|
1109
|
-
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ?
|
|
1250
|
+
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? "..." : ""}"
|
|
1110
1251
|
|
|
1111
1252
|
**Workflow Phase**: Design Generated
|
|
1112
|
-
**Next Step**: Run \`sdd-tasks ${featureName}\` to generate implementation tasks (after design review)
|
|
1113
|
-
}
|
|
1253
|
+
**Next Step**: Run \`sdd-tasks ${featureName}\` to generate implementation tasks (after design review)`,
|
|
1254
|
+
},
|
|
1255
|
+
],
|
|
1114
1256
|
};
|
|
1115
1257
|
}
|
|
1116
1258
|
catch (error) {
|
|
1117
1259
|
return {
|
|
1118
|
-
content: [
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1260
|
+
content: [
|
|
1261
|
+
{
|
|
1262
|
+
type: "text",
|
|
1263
|
+
text: `Error generating design document: ${error.message}`,
|
|
1264
|
+
},
|
|
1265
|
+
],
|
|
1266
|
+
isError: true,
|
|
1123
1267
|
};
|
|
1124
1268
|
}
|
|
1125
1269
|
}
|
|
1126
1270
|
async function handleTasksSimplified(args) {
|
|
1127
|
-
const fs = await import(
|
|
1128
|
-
const path = await import(
|
|
1271
|
+
const fs = await import("fs");
|
|
1272
|
+
const path = await import("path");
|
|
1129
1273
|
try {
|
|
1130
1274
|
const { featureName } = args;
|
|
1131
|
-
if (!featureName || typeof featureName !==
|
|
1132
|
-
throw new Error(
|
|
1275
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1276
|
+
throw new Error("Feature name is required for tasks generation");
|
|
1133
1277
|
}
|
|
1134
1278
|
// Load spec context
|
|
1135
1279
|
const { spec } = await loadSpecContext(featureName);
|
|
@@ -1144,16 +1288,16 @@ async function handleTasksSimplified(args) {
|
|
|
1144
1288
|
let tasksContent;
|
|
1145
1289
|
let analysisUsed = false;
|
|
1146
1290
|
try {
|
|
1147
|
-
console.error(
|
|
1148
|
-
const { generateTasksDocument } = await
|
|
1149
|
-
console.error(
|
|
1291
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive task analysis...");
|
|
1292
|
+
const { generateTasksDocument } = await loadSpecGenerator();
|
|
1293
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating tasks...");
|
|
1150
1294
|
tasksContent = await generateTasksDocument(process.cwd(), featureName);
|
|
1151
1295
|
analysisUsed = true;
|
|
1152
|
-
console.error(
|
|
1296
|
+
console.error("[SDD-DEBUG] ✅ Tasks generated using comprehensive codebase analysis");
|
|
1153
1297
|
}
|
|
1154
1298
|
catch (genErr) {
|
|
1155
|
-
console.error(
|
|
1156
|
-
console.error(
|
|
1299
|
+
console.error("[SDD-DEBUG] ⚠️ Comprehensive analysis failed, using fallback template");
|
|
1300
|
+
console.error("[SDD-DEBUG] Error details:", genErr.message);
|
|
1157
1301
|
tasksContent = `# Implementation Plan
|
|
1158
1302
|
|
|
1159
1303
|
<!-- Note: Using basic template due to analysis error: ${genErr.message} -->
|
|
@@ -1166,31 +1310,32 @@ async function handleTasksSimplified(args) {
|
|
|
1166
1310
|
`;
|
|
1167
1311
|
}
|
|
1168
1312
|
// Update spec.json with phase information
|
|
1169
|
-
const specDir = path.join(process.cwd(),
|
|
1313
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1170
1314
|
const updatedSpec = {
|
|
1171
1315
|
...spec,
|
|
1172
|
-
phase:
|
|
1316
|
+
phase: "tasks-generated",
|
|
1173
1317
|
approvals: {
|
|
1174
1318
|
...spec.approvals,
|
|
1175
1319
|
tasks: {
|
|
1176
1320
|
generated: true,
|
|
1177
|
-
approved: false
|
|
1178
|
-
}
|
|
1321
|
+
approved: false,
|
|
1322
|
+
},
|
|
1179
1323
|
},
|
|
1180
1324
|
ready_for_implementation: true,
|
|
1181
|
-
updated_at: new Date().toISOString()
|
|
1325
|
+
updated_at: new Date().toISOString(),
|
|
1182
1326
|
};
|
|
1183
|
-
fs.writeFileSync(path.join(specDir,
|
|
1184
|
-
fs.writeFileSync(path.join(specDir,
|
|
1327
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1328
|
+
fs.writeFileSync(path.join(specDir, "tasks.md"), tasksContent);
|
|
1185
1329
|
return {
|
|
1186
|
-
content: [
|
|
1187
|
-
|
|
1330
|
+
content: [
|
|
1331
|
+
{
|
|
1332
|
+
type: "text",
|
|
1188
1333
|
text: `## Implementation Tasks Generated
|
|
1189
1334
|
|
|
1190
1335
|
**Feature**: \`${featureName}\`
|
|
1191
1336
|
**File**: \`.kiro/specs/${featureName}/tasks.md\`
|
|
1192
1337
|
|
|
1193
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1338
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (tech stack-aware tasks)" : "⚠️ Basic template (analysis failed)"}
|
|
1194
1339
|
|
|
1195
1340
|
**Generated Tasks**:
|
|
1196
1341
|
- Development, integration, quality, and deployment phases
|
|
@@ -1200,31 +1345,42 @@ async function handleTasksSimplified(args) {
|
|
|
1200
1345
|
|
|
1201
1346
|
**Workflow Phase**: Tasks Generated
|
|
1202
1347
|
**Status**: Ready for Implementation
|
|
1203
|
-
**Next Step**: Begin implementation following the task sequence
|
|
1204
|
-
}
|
|
1348
|
+
**Next Step**: Begin implementation following the task sequence`,
|
|
1349
|
+
},
|
|
1350
|
+
],
|
|
1205
1351
|
};
|
|
1206
1352
|
}
|
|
1207
1353
|
catch (error) {
|
|
1208
1354
|
return {
|
|
1209
|
-
content: [
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1355
|
+
content: [
|
|
1356
|
+
{
|
|
1357
|
+
type: "text",
|
|
1358
|
+
text: `Error generating tasks document: ${error.message}`,
|
|
1359
|
+
},
|
|
1360
|
+
],
|
|
1361
|
+
isError: true,
|
|
1214
1362
|
};
|
|
1215
1363
|
}
|
|
1216
1364
|
}
|
|
1217
1365
|
// Helper functions for simplified tool implementations
|
|
1218
1366
|
function analyzeProjectStructureSync(projectPath) {
|
|
1219
|
-
const fs = require(
|
|
1367
|
+
const fs = require("fs");
|
|
1220
1368
|
try {
|
|
1221
1369
|
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
1222
1370
|
return {
|
|
1223
|
-
directories: items
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1371
|
+
directories: items
|
|
1372
|
+
.filter((item) => item.isDirectory() &&
|
|
1373
|
+
!item.name.startsWith(".") &&
|
|
1374
|
+
item.name !== "node_modules")
|
|
1375
|
+
.map((item) => item.name),
|
|
1376
|
+
files: items
|
|
1377
|
+
.filter((item) => item.isFile())
|
|
1378
|
+
.map((item) => item.name),
|
|
1379
|
+
hasSource: items.some((item) => item.isDirectory() && item.name === "src"),
|
|
1380
|
+
hasTests: items.some((item) => item.isDirectory() &&
|
|
1381
|
+
(item.name === "test" || item.name === "__tests__")),
|
|
1382
|
+
hasDocs: items.some((item) => item.isDirectory() &&
|
|
1383
|
+
(item.name === "docs" || item.name === "documentation")),
|
|
1228
1384
|
};
|
|
1229
1385
|
}
|
|
1230
1386
|
catch (error) {
|
|
@@ -1236,149 +1392,180 @@ function generateCoreObjectiveSimplified(packageJson, projectAnalysis) {
|
|
|
1236
1392
|
return `Deliver ${packageJson.description} with full functionality and reliability`;
|
|
1237
1393
|
}
|
|
1238
1394
|
if (packageJson.keywords?.length > 0) {
|
|
1239
|
-
return `Implement ${packageJson.keywords.join(
|
|
1395
|
+
return `Implement ${packageJson.keywords.join(", ")} functionality`;
|
|
1240
1396
|
}
|
|
1241
|
-
return
|
|
1397
|
+
return "Deliver core application functionality";
|
|
1242
1398
|
}
|
|
1243
1399
|
function generateAcceptanceCriteriaSimplified(packageJson, projectAnalysis) {
|
|
1244
1400
|
const criteria = [];
|
|
1245
1401
|
if (packageJson.scripts?.test) {
|
|
1246
|
-
criteria.push(
|
|
1402
|
+
criteria.push("WHEN tests are run THEN all tests SHALL pass");
|
|
1247
1403
|
}
|
|
1248
1404
|
if (packageJson.scripts?.build) {
|
|
1249
|
-
criteria.push(
|
|
1405
|
+
criteria.push("WHEN build is executed THEN system SHALL compile without errors");
|
|
1250
1406
|
}
|
|
1251
1407
|
if (packageJson.scripts?.lint) {
|
|
1252
|
-
criteria.push(
|
|
1408
|
+
criteria.push("WHERE code quality is checked THE system SHALL meet linting standards");
|
|
1253
1409
|
}
|
|
1254
1410
|
if (packageJson.main || packageJson.bin) {
|
|
1255
|
-
criteria.push(
|
|
1411
|
+
criteria.push("WHEN application starts THEN system SHALL initialize successfully");
|
|
1256
1412
|
}
|
|
1257
|
-
criteria.push(
|
|
1258
|
-
return criteria.length > 0
|
|
1413
|
+
criteria.push("IF errors occur THEN system SHALL handle them gracefully");
|
|
1414
|
+
return criteria.length > 0
|
|
1415
|
+
? criteria
|
|
1416
|
+
: ["System SHALL meet functional requirements"];
|
|
1259
1417
|
}
|
|
1260
1418
|
function generateTechRequirementsSimplified(packageJson) {
|
|
1261
1419
|
const requirements = [];
|
|
1262
1420
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
1263
1421
|
if (deps?.typescript) {
|
|
1264
|
-
requirements.push(
|
|
1422
|
+
requirements.push("System SHALL use TypeScript for type safety");
|
|
1265
1423
|
}
|
|
1266
1424
|
if (deps?.express || deps?.fastify) {
|
|
1267
|
-
requirements.push(
|
|
1425
|
+
requirements.push("System SHALL implement RESTful API endpoints");
|
|
1268
1426
|
}
|
|
1269
1427
|
if (deps?.react || deps?.vue || deps?.angular) {
|
|
1270
|
-
requirements.push(
|
|
1428
|
+
requirements.push("System SHALL provide responsive user interface");
|
|
1271
1429
|
}
|
|
1272
1430
|
if (deps?.jest || deps?.mocha || deps?.vitest) {
|
|
1273
|
-
requirements.push(
|
|
1431
|
+
requirements.push("System SHALL include comprehensive test coverage");
|
|
1274
1432
|
}
|
|
1275
|
-
return requirements.length > 0
|
|
1433
|
+
return requirements.length > 0
|
|
1434
|
+
? requirements
|
|
1435
|
+
: ["System SHALL integrate required technologies"];
|
|
1276
1436
|
}
|
|
1277
1437
|
function generateQualityRequirementsSimplified(packageJson) {
|
|
1278
1438
|
const requirements = [];
|
|
1279
1439
|
if (packageJson.scripts?.lint) {
|
|
1280
|
-
requirements.push(
|
|
1440
|
+
requirements.push("Code SHALL pass linting checks");
|
|
1281
1441
|
}
|
|
1282
1442
|
if (packageJson.scripts?.typecheck) {
|
|
1283
|
-
requirements.push(
|
|
1443
|
+
requirements.push("Code SHALL pass type checking");
|
|
1284
1444
|
}
|
|
1285
1445
|
if (packageJson.scripts?.test) {
|
|
1286
|
-
requirements.push(
|
|
1446
|
+
requirements.push("Code SHALL maintain test coverage standards");
|
|
1287
1447
|
}
|
|
1288
|
-
requirements.push(
|
|
1448
|
+
requirements.push("Code SHALL follow established conventions");
|
|
1289
1449
|
return requirements;
|
|
1290
1450
|
}
|
|
1291
1451
|
function generateArchitectureDescriptionSimplified(packageJson, projectAnalysis) {
|
|
1292
|
-
let description =
|
|
1293
|
-
if (packageJson.type ===
|
|
1294
|
-
description +=
|
|
1452
|
+
let description = "";
|
|
1453
|
+
if (packageJson.type === "module") {
|
|
1454
|
+
description += "Modern ES Module-based architecture. ";
|
|
1295
1455
|
}
|
|
1296
1456
|
if (projectAnalysis.hasSource) {
|
|
1297
|
-
description +=
|
|
1457
|
+
description +=
|
|
1458
|
+
"Modular source code organization with clear separation of concerns. ";
|
|
1298
1459
|
}
|
|
1299
1460
|
if (packageJson.dependencies?.express) {
|
|
1300
|
-
description +=
|
|
1461
|
+
description +=
|
|
1462
|
+
"RESTful API server architecture using Express.js framework. ";
|
|
1301
1463
|
}
|
|
1302
|
-
if (packageJson.dependencies?.typescript ||
|
|
1303
|
-
|
|
1464
|
+
if (packageJson.dependencies?.typescript ||
|
|
1465
|
+
packageJson.devDependencies?.typescript) {
|
|
1466
|
+
description += "Type-safe development with TypeScript compilation. ";
|
|
1304
1467
|
}
|
|
1305
|
-
return description ||
|
|
1468
|
+
return (description ||
|
|
1469
|
+
"Application architecture to be defined based on requirements.");
|
|
1306
1470
|
}
|
|
1307
1471
|
function generateComponentDescriptionsSimplified(projectAnalysis) {
|
|
1308
1472
|
const components = [];
|
|
1309
1473
|
if (projectAnalysis.hasSource) {
|
|
1310
|
-
components.push({
|
|
1474
|
+
components.push({
|
|
1475
|
+
name: "Core Module",
|
|
1476
|
+
description: "Main application logic and business rules",
|
|
1477
|
+
});
|
|
1311
1478
|
}
|
|
1312
1479
|
if (projectAnalysis.hasTests) {
|
|
1313
|
-
components.push({
|
|
1480
|
+
components.push({
|
|
1481
|
+
name: "Test Suite",
|
|
1482
|
+
description: "Automated testing framework and test cases",
|
|
1483
|
+
});
|
|
1314
1484
|
}
|
|
1315
1485
|
if (projectAnalysis.hasDocs) {
|
|
1316
|
-
components.push({
|
|
1486
|
+
components.push({
|
|
1487
|
+
name: "Documentation",
|
|
1488
|
+
description: "Project documentation and API specifications",
|
|
1489
|
+
});
|
|
1317
1490
|
}
|
|
1318
|
-
return components.length > 0
|
|
1319
|
-
|
|
1320
|
-
|
|
1491
|
+
return components.length > 0
|
|
1492
|
+
? components
|
|
1493
|
+
: [
|
|
1494
|
+
{
|
|
1495
|
+
name: "Application Core",
|
|
1496
|
+
description: "Main application functionality",
|
|
1497
|
+
},
|
|
1498
|
+
];
|
|
1321
1499
|
}
|
|
1322
1500
|
function generateDataModelsSimplified(packageJson, projectAnalysis) {
|
|
1323
1501
|
const models = [];
|
|
1324
1502
|
if (packageJson.dependencies?.mongoose || packageJson.dependencies?.mongodb) {
|
|
1325
|
-
models.push(
|
|
1503
|
+
models.push("MongoDB Document Models");
|
|
1326
1504
|
}
|
|
1327
|
-
if (packageJson.dependencies?.sequelize ||
|
|
1328
|
-
|
|
1505
|
+
if (packageJson.dependencies?.sequelize ||
|
|
1506
|
+
packageJson.dependencies?.typeorm) {
|
|
1507
|
+
models.push("Relational Database Models");
|
|
1329
1508
|
}
|
|
1330
1509
|
if (packageJson.dependencies?.graphql) {
|
|
1331
|
-
models.push(
|
|
1510
|
+
models.push("GraphQL Schema Models");
|
|
1332
1511
|
}
|
|
1333
|
-
return models.length > 0 ? models : [
|
|
1512
|
+
return models.length > 0 ? models : ["Application Data Models"];
|
|
1334
1513
|
}
|
|
1335
1514
|
function generateDetailedTechStackSimplified(packageJson) {
|
|
1336
1515
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
1337
1516
|
const stack = [];
|
|
1338
1517
|
if (deps?.typescript)
|
|
1339
|
-
stack.push(
|
|
1518
|
+
stack.push("- **TypeScript**: Type-safe JavaScript development");
|
|
1340
1519
|
if (deps?.node || packageJson.engines?.node)
|
|
1341
|
-
stack.push(`- **Node.js**: ${packageJson.engines?.node ||
|
|
1520
|
+
stack.push(`- **Node.js**: ${packageJson.engines?.node || "Runtime environment"}`);
|
|
1342
1521
|
if (deps?.express)
|
|
1343
|
-
stack.push(
|
|
1522
|
+
stack.push("- **Express.js**: Web application framework");
|
|
1344
1523
|
if (deps?.react)
|
|
1345
|
-
stack.push(
|
|
1524
|
+
stack.push("- **React**: User interface library");
|
|
1346
1525
|
if (deps?.vue)
|
|
1347
|
-
stack.push(
|
|
1526
|
+
stack.push("- **Vue.js**: Progressive frontend framework");
|
|
1348
1527
|
if (deps?.jest)
|
|
1349
|
-
stack.push(
|
|
1350
|
-
return stack.length > 0
|
|
1528
|
+
stack.push("- **Jest**: Testing framework");
|
|
1529
|
+
return stack.length > 0
|
|
1530
|
+
? stack.join("\n")
|
|
1531
|
+
: "- Technology stack to be defined";
|
|
1351
1532
|
}
|
|
1352
1533
|
function generateDesignPatternsSimplified(packageJson, projectAnalysis) {
|
|
1353
1534
|
const patterns = [];
|
|
1354
1535
|
if (packageJson.dependencies?.inversify) {
|
|
1355
|
-
patterns.push(
|
|
1536
|
+
patterns.push("Dependency Injection");
|
|
1356
1537
|
}
|
|
1357
1538
|
if (projectAnalysis.hasSource) {
|
|
1358
|
-
patterns.push(
|
|
1539
|
+
patterns.push("Modular Architecture");
|
|
1359
1540
|
}
|
|
1360
1541
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1361
|
-
patterns.push(
|
|
1542
|
+
patterns.push("MVC Pattern");
|
|
1362
1543
|
}
|
|
1363
|
-
return patterns.length > 0 ? patterns : [
|
|
1544
|
+
return patterns.length > 0 ? patterns : ["Standard Design Patterns"];
|
|
1364
1545
|
}
|
|
1365
1546
|
function generateDependencyAnalysisSimplified(packageJson) {
|
|
1366
1547
|
const production = Object.keys(packageJson.dependencies || {});
|
|
1367
1548
|
const development = Object.keys(packageJson.devDependencies || {});
|
|
1368
|
-
let analysis =
|
|
1549
|
+
let analysis = "";
|
|
1369
1550
|
if (production.length > 0) {
|
|
1370
1551
|
analysis += `**Production Dependencies:** ${production.length} packages\n`;
|
|
1371
|
-
analysis += production
|
|
1552
|
+
analysis += production
|
|
1553
|
+
.slice(0, 5)
|
|
1554
|
+
.map((dep) => `- ${dep}`)
|
|
1555
|
+
.join("\n");
|
|
1372
1556
|
if (production.length > 5)
|
|
1373
1557
|
analysis += `\n- ... and ${production.length - 5} more`;
|
|
1374
1558
|
}
|
|
1375
1559
|
if (development.length > 0) {
|
|
1376
1560
|
analysis += `\n\n**Development Dependencies:** ${development.length} packages\n`;
|
|
1377
|
-
analysis += development
|
|
1561
|
+
analysis += development
|
|
1562
|
+
.slice(0, 5)
|
|
1563
|
+
.map((dep) => `- ${dep}`)
|
|
1564
|
+
.join("\n");
|
|
1378
1565
|
if (development.length > 5)
|
|
1379
1566
|
analysis += `\n- ... and ${development.length - 5} more`;
|
|
1380
1567
|
}
|
|
1381
|
-
return analysis ||
|
|
1568
|
+
return analysis || "Dependencies to be analyzed";
|
|
1382
1569
|
}
|
|
1383
1570
|
function generateAPIInterfacesSimplified(packageJson, projectAnalysis) {
|
|
1384
1571
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
@@ -1388,7 +1575,7 @@ function generateAPIInterfacesSimplified(packageJson, projectAnalysis) {
|
|
|
1388
1575
|
- Request/response validation
|
|
1389
1576
|
- Error handling middleware`;
|
|
1390
1577
|
}
|
|
1391
|
-
return
|
|
1578
|
+
return "Interface specifications to be defined";
|
|
1392
1579
|
}
|
|
1393
1580
|
function generateModuleInterfacesSimplified(projectAnalysis) {
|
|
1394
1581
|
if (projectAnalysis.hasSource) {
|
|
@@ -1397,87 +1584,115 @@ function generateModuleInterfacesSimplified(projectAnalysis) {
|
|
|
1397
1584
|
- Consistent API patterns across modules
|
|
1398
1585
|
- Type definitions for all public interfaces`;
|
|
1399
1586
|
}
|
|
1400
|
-
return
|
|
1587
|
+
return "Module interfaces to be defined";
|
|
1401
1588
|
}
|
|
1402
1589
|
function generateEnvVarSpecsSimplified(packageJson) {
|
|
1403
1590
|
const envVars = [];
|
|
1404
1591
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1405
|
-
envVars.push(
|
|
1406
|
-
envVars.push(
|
|
1592
|
+
envVars.push("- `PORT`: Server port (default: 3000)");
|
|
1593
|
+
envVars.push("- `NODE_ENV`: Environment mode (development/production)");
|
|
1407
1594
|
}
|
|
1408
|
-
envVars.push(
|
|
1409
|
-
return envVars.join(
|
|
1595
|
+
envVars.push("- `LOG_LEVEL`: Logging level (debug/info/warn/error)");
|
|
1596
|
+
return envVars.join("\n");
|
|
1410
1597
|
}
|
|
1411
1598
|
function generateBuildConfigSimplified(packageJson) {
|
|
1412
|
-
let config =
|
|
1599
|
+
let config = "";
|
|
1413
1600
|
if (packageJson.scripts?.build) {
|
|
1414
1601
|
config += `Build process: \`${packageJson.scripts.build}\`\n`;
|
|
1415
1602
|
}
|
|
1416
1603
|
if (packageJson.scripts?.start) {
|
|
1417
1604
|
config += `Start command: \`${packageJson.scripts.start}\`\n`;
|
|
1418
1605
|
}
|
|
1419
|
-
if (packageJson.type ===
|
|
1420
|
-
config +=
|
|
1606
|
+
if (packageJson.type === "module") {
|
|
1607
|
+
config += "Module type: ES Modules\n";
|
|
1421
1608
|
}
|
|
1422
|
-
return config ||
|
|
1609
|
+
return config || "Build configuration to be defined";
|
|
1423
1610
|
}
|
|
1424
1611
|
function generateImplementationTasksSimplified(packageJson, projectAnalysis) {
|
|
1425
1612
|
const tasks = {
|
|
1426
1613
|
development: [],
|
|
1427
1614
|
integration: [],
|
|
1428
1615
|
quality: [],
|
|
1429
|
-
deployment: []
|
|
1616
|
+
deployment: [],
|
|
1430
1617
|
};
|
|
1431
1618
|
// Development tasks
|
|
1432
1619
|
if (projectAnalysis.hasSource) {
|
|
1433
1620
|
tasks.development.push({
|
|
1434
|
-
title:
|
|
1435
|
-
subtasks: [
|
|
1436
|
-
|
|
1621
|
+
title: "Implement Core Modules",
|
|
1622
|
+
subtasks: [
|
|
1623
|
+
"Set up module structure",
|
|
1624
|
+
"Implement business logic",
|
|
1625
|
+
"Add error handling",
|
|
1626
|
+
],
|
|
1627
|
+
requirements: "FR-1, FR-2",
|
|
1437
1628
|
});
|
|
1438
1629
|
}
|
|
1439
1630
|
if (packageJson.dependencies?.express) {
|
|
1440
1631
|
tasks.development.push({
|
|
1441
|
-
title:
|
|
1442
|
-
subtasks: [
|
|
1443
|
-
|
|
1632
|
+
title: "Develop API Endpoints",
|
|
1633
|
+
subtasks: [
|
|
1634
|
+
"Create route handlers",
|
|
1635
|
+
"Add middleware",
|
|
1636
|
+
"Implement validation",
|
|
1637
|
+
],
|
|
1638
|
+
requirements: "FR-2",
|
|
1444
1639
|
});
|
|
1445
1640
|
}
|
|
1446
1641
|
// Integration tasks
|
|
1447
1642
|
if (packageJson.dependencies?.mongodb || packageJson.dependencies?.mongoose) {
|
|
1448
1643
|
tasks.integration.push({
|
|
1449
|
-
title:
|
|
1450
|
-
subtasks: [
|
|
1451
|
-
|
|
1644
|
+
title: "Database Integration",
|
|
1645
|
+
subtasks: [
|
|
1646
|
+
"Set up database connection",
|
|
1647
|
+
"Create data models",
|
|
1648
|
+
"Implement queries",
|
|
1649
|
+
],
|
|
1650
|
+
requirements: "NFR-2",
|
|
1452
1651
|
});
|
|
1453
1652
|
}
|
|
1454
1653
|
// Quality tasks
|
|
1455
1654
|
if (packageJson.scripts?.test) {
|
|
1456
1655
|
tasks.quality.push({
|
|
1457
|
-
title:
|
|
1458
|
-
subtasks: [
|
|
1459
|
-
|
|
1656
|
+
title: "Test Implementation",
|
|
1657
|
+
subtasks: [
|
|
1658
|
+
"Write unit tests",
|
|
1659
|
+
"Add integration tests",
|
|
1660
|
+
"Ensure test coverage",
|
|
1661
|
+
],
|
|
1662
|
+
requirements: "FR-3, NFR-3",
|
|
1460
1663
|
});
|
|
1461
1664
|
}
|
|
1462
1665
|
if (packageJson.scripts?.lint) {
|
|
1463
1666
|
tasks.quality.push({
|
|
1464
|
-
title:
|
|
1465
|
-
subtasks: [
|
|
1466
|
-
|
|
1667
|
+
title: "Code Quality Assurance",
|
|
1668
|
+
subtasks: [
|
|
1669
|
+
"Run linting checks",
|
|
1670
|
+
"Fix code style issues",
|
|
1671
|
+
"Add documentation",
|
|
1672
|
+
],
|
|
1673
|
+
requirements: "NFR-3",
|
|
1467
1674
|
});
|
|
1468
1675
|
}
|
|
1469
1676
|
// Deployment tasks
|
|
1470
1677
|
if (packageJson.scripts?.build) {
|
|
1471
1678
|
tasks.deployment.push({
|
|
1472
|
-
title:
|
|
1473
|
-
subtasks: [
|
|
1474
|
-
|
|
1679
|
+
title: "Build and Package",
|
|
1680
|
+
subtasks: [
|
|
1681
|
+
"Run build process",
|
|
1682
|
+
"Optimize for production",
|
|
1683
|
+
"Create deployment artifacts",
|
|
1684
|
+
],
|
|
1685
|
+
requirements: "NFR-1",
|
|
1475
1686
|
});
|
|
1476
1687
|
}
|
|
1477
1688
|
tasks.deployment.push({
|
|
1478
|
-
title:
|
|
1479
|
-
subtasks: [
|
|
1480
|
-
|
|
1689
|
+
title: "Deployment Configuration",
|
|
1690
|
+
subtasks: [
|
|
1691
|
+
"Set up environment variables",
|
|
1692
|
+
"Configure production settings",
|
|
1693
|
+
"Deploy to target environment",
|
|
1694
|
+
],
|
|
1695
|
+
requirements: "NFR-1, NFR-2",
|
|
1481
1696
|
});
|
|
1482
1697
|
return tasks;
|
|
1483
1698
|
}
|
|
@@ -1488,45 +1703,49 @@ function generateIntroductionFromDescription(description) {
|
|
|
1488
1703
|
}
|
|
1489
1704
|
function extractSystemName(description) {
|
|
1490
1705
|
// Extract a system name from description
|
|
1491
|
-
const words = description.split(
|
|
1706
|
+
const words = description.split(" ");
|
|
1492
1707
|
if (words.length >= 2) {
|
|
1493
|
-
return `the ${words.slice(0, 3).join(
|
|
1708
|
+
return `the ${words.slice(0, 3).join(" ")}`;
|
|
1494
1709
|
}
|
|
1495
|
-
return
|
|
1710
|
+
return "the system";
|
|
1496
1711
|
}
|
|
1497
1712
|
function extractPrimaryObjective(description) {
|
|
1498
1713
|
// Convert description into user objective
|
|
1499
|
-
if (description.toLowerCase().includes(
|
|
1714
|
+
if (description.toLowerCase().includes("tool") ||
|
|
1715
|
+
description.toLowerCase().includes("cli")) {
|
|
1500
1716
|
return `use a tool that ${description.toLowerCase()}`;
|
|
1501
1717
|
}
|
|
1502
|
-
if (description.toLowerCase().includes(
|
|
1718
|
+
if (description.toLowerCase().includes("system") ||
|
|
1719
|
+
description.toLowerCase().includes("application")) {
|
|
1503
1720
|
return `access a system that ${description.toLowerCase()}`;
|
|
1504
1721
|
}
|
|
1505
1722
|
return `have functionality that ${description.toLowerCase()}`;
|
|
1506
1723
|
}
|
|
1507
1724
|
function extractPrimaryBenefit(description) {
|
|
1508
1725
|
// Infer benefit from description
|
|
1509
|
-
if (description.toLowerCase().includes(
|
|
1510
|
-
return
|
|
1726
|
+
if (description.toLowerCase().includes("automate")) {
|
|
1727
|
+
return "I can save time and reduce manual effort";
|
|
1511
1728
|
}
|
|
1512
|
-
if (description.toLowerCase().includes(
|
|
1513
|
-
|
|
1729
|
+
if (description.toLowerCase().includes("analyze") ||
|
|
1730
|
+
description.toLowerCase().includes("review")) {
|
|
1731
|
+
return "I can make better informed decisions";
|
|
1514
1732
|
}
|
|
1515
|
-
if (description.toLowerCase().includes(
|
|
1516
|
-
|
|
1733
|
+
if (description.toLowerCase().includes("manage") ||
|
|
1734
|
+
description.toLowerCase().includes("organize")) {
|
|
1735
|
+
return "I can maintain better control and organization";
|
|
1517
1736
|
}
|
|
1518
|
-
return
|
|
1737
|
+
return "I can accomplish my goals more effectively";
|
|
1519
1738
|
}
|
|
1520
1739
|
function generateEARSRequirements(description) {
|
|
1521
1740
|
const requirements = [];
|
|
1522
1741
|
// Core functional requirement
|
|
1523
1742
|
requirements.push(`WHEN I use the system THEN it SHALL provide ${description.toLowerCase()} functionality`);
|
|
1524
1743
|
// Input/output handling
|
|
1525
|
-
requirements.push(
|
|
1744
|
+
requirements.push("WHEN I provide input THEN the system SHALL validate and process it correctly");
|
|
1526
1745
|
// Error handling
|
|
1527
|
-
requirements.push(
|
|
1746
|
+
requirements.push("IF invalid input is provided THEN the system SHALL reject it with clear error messages");
|
|
1528
1747
|
// Success condition
|
|
1529
|
-
requirements.push(
|
|
1748
|
+
requirements.push("WHEN all inputs are valid THEN the system SHALL complete the requested operation successfully");
|
|
1530
1749
|
return requirements;
|
|
1531
1750
|
}
|
|
1532
1751
|
// Helper functions for kiro-style workflow
|
|
@@ -1534,18 +1753,18 @@ function generateFeatureName(description) {
|
|
|
1534
1753
|
// Extract feature name from description - similar to kiro spec-init
|
|
1535
1754
|
const cleaned = description
|
|
1536
1755
|
.toLowerCase()
|
|
1537
|
-
.replace(/[^a-z0-9\s]/g,
|
|
1756
|
+
.replace(/[^a-z0-9\s]/g, "")
|
|
1538
1757
|
.trim()
|
|
1539
1758
|
.split(/\s+/)
|
|
1540
1759
|
.slice(0, 4) // Take first 4 words
|
|
1541
|
-
.join(
|
|
1760
|
+
.join("-");
|
|
1542
1761
|
// Ensure it's not empty
|
|
1543
|
-
return cleaned ||
|
|
1762
|
+
return cleaned || "new-feature";
|
|
1544
1763
|
}
|
|
1545
1764
|
async function ensureUniqueFeatureName(baseName) {
|
|
1546
|
-
const fs = await import(
|
|
1547
|
-
const path = await import(
|
|
1548
|
-
const specsDir = path.join(process.cwd(),
|
|
1765
|
+
const fs = await import("fs");
|
|
1766
|
+
const path = await import("path");
|
|
1767
|
+
const specsDir = path.join(process.cwd(), ".kiro", "specs");
|
|
1549
1768
|
if (!fs.existsSync(specsDir)) {
|
|
1550
1769
|
return baseName;
|
|
1551
1770
|
}
|
|
@@ -1558,16 +1777,16 @@ async function ensureUniqueFeatureName(baseName) {
|
|
|
1558
1777
|
return featureName;
|
|
1559
1778
|
}
|
|
1560
1779
|
async function loadSpecContext(featureName) {
|
|
1561
|
-
const fs = await import(
|
|
1562
|
-
const path = await import(
|
|
1563
|
-
const specDir = path.join(process.cwd(),
|
|
1564
|
-
const specJsonPath = path.join(specDir,
|
|
1565
|
-
const requirementsPath = path.join(specDir,
|
|
1780
|
+
const fs = await import("fs");
|
|
1781
|
+
const path = await import("path");
|
|
1782
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1783
|
+
const specJsonPath = path.join(specDir, "spec.json");
|
|
1784
|
+
const requirementsPath = path.join(specDir, "requirements.md");
|
|
1566
1785
|
let spec = null;
|
|
1567
1786
|
let requirements = null;
|
|
1568
1787
|
try {
|
|
1569
1788
|
if (fs.existsSync(specJsonPath)) {
|
|
1570
|
-
const specContent = fs.readFileSync(specJsonPath,
|
|
1789
|
+
const specContent = fs.readFileSync(specJsonPath, "utf8");
|
|
1571
1790
|
spec = JSON.parse(specContent);
|
|
1572
1791
|
}
|
|
1573
1792
|
}
|
|
@@ -1576,7 +1795,7 @@ async function loadSpecContext(featureName) {
|
|
|
1576
1795
|
}
|
|
1577
1796
|
try {
|
|
1578
1797
|
if (fs.existsSync(requirementsPath)) {
|
|
1579
|
-
requirements = fs.readFileSync(requirementsPath,
|
|
1798
|
+
requirements = fs.readFileSync(requirementsPath, "utf8");
|
|
1580
1799
|
}
|
|
1581
1800
|
}
|
|
1582
1801
|
catch (error) {
|
|
@@ -1585,19 +1804,19 @@ async function loadSpecContext(featureName) {
|
|
|
1585
1804
|
return { spec, requirements };
|
|
1586
1805
|
}
|
|
1587
1806
|
async function handleInitSimplified(args) {
|
|
1588
|
-
const fs = await import(
|
|
1589
|
-
const path = await import(
|
|
1807
|
+
const fs = await import("fs");
|
|
1808
|
+
const path = await import("path");
|
|
1590
1809
|
try {
|
|
1591
1810
|
const { description } = args;
|
|
1592
|
-
if (!description || typeof description !==
|
|
1593
|
-
throw new Error(
|
|
1811
|
+
if (!description || typeof description !== "string") {
|
|
1812
|
+
throw new Error("Description is required for project initialization");
|
|
1594
1813
|
}
|
|
1595
1814
|
const projectPath = process.cwd();
|
|
1596
1815
|
// Generate feature name from description
|
|
1597
1816
|
const baseFeatureName = generateFeatureName(description);
|
|
1598
1817
|
const featureName = await ensureUniqueFeatureName(baseFeatureName);
|
|
1599
1818
|
// Create .kiro/specs/[feature-name] directory
|
|
1600
|
-
const specDir = path.join(projectPath,
|
|
1819
|
+
const specDir = path.join(projectPath, ".kiro", "specs", featureName);
|
|
1601
1820
|
if (!fs.existsSync(specDir)) {
|
|
1602
1821
|
fs.mkdirSync(specDir, { recursive: true });
|
|
1603
1822
|
}
|
|
@@ -1606,25 +1825,25 @@ async function handleInitSimplified(args) {
|
|
|
1606
1825
|
feature_name: featureName,
|
|
1607
1826
|
created_at: new Date().toISOString(),
|
|
1608
1827
|
updated_at: new Date().toISOString(),
|
|
1609
|
-
language:
|
|
1610
|
-
phase:
|
|
1828
|
+
language: "en",
|
|
1829
|
+
phase: "initialized",
|
|
1611
1830
|
approvals: {
|
|
1612
1831
|
requirements: {
|
|
1613
1832
|
generated: false,
|
|
1614
|
-
approved: false
|
|
1833
|
+
approved: false,
|
|
1615
1834
|
},
|
|
1616
1835
|
design: {
|
|
1617
1836
|
generated: false,
|
|
1618
|
-
approved: false
|
|
1837
|
+
approved: false,
|
|
1619
1838
|
},
|
|
1620
1839
|
tasks: {
|
|
1621
1840
|
generated: false,
|
|
1622
|
-
approved: false
|
|
1623
|
-
}
|
|
1841
|
+
approved: false,
|
|
1842
|
+
},
|
|
1624
1843
|
},
|
|
1625
|
-
ready_for_implementation: false
|
|
1844
|
+
ready_for_implementation: false,
|
|
1626
1845
|
};
|
|
1627
|
-
fs.writeFileSync(path.join(specDir,
|
|
1846
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(specContent, null, 2));
|
|
1628
1847
|
// Create requirements.md template with project description
|
|
1629
1848
|
const requirementsTemplate = `# Requirements Document
|
|
1630
1849
|
|
|
@@ -1634,20 +1853,20 @@ ${description}
|
|
|
1634
1853
|
## Requirements
|
|
1635
1854
|
<!-- Will be generated in sdd-requirements phase -->
|
|
1636
1855
|
`;
|
|
1637
|
-
fs.writeFileSync(path.join(specDir,
|
|
1856
|
+
fs.writeFileSync(path.join(specDir, "requirements.md"), requirementsTemplate);
|
|
1638
1857
|
// Ensure AGENTS.md exists (static, derived from CLAUDE.md when available)
|
|
1639
|
-
const agentsPath = path.join(process.cwd(),
|
|
1858
|
+
const agentsPath = path.join(process.cwd(), "AGENTS.md");
|
|
1640
1859
|
if (!fs.existsSync(agentsPath)) {
|
|
1641
|
-
const claudePath = path.join(process.cwd(),
|
|
1642
|
-
let agentsContent =
|
|
1860
|
+
const claudePath = path.join(process.cwd(), "CLAUDE.md");
|
|
1861
|
+
let agentsContent = "";
|
|
1643
1862
|
if (fs.existsSync(claudePath)) {
|
|
1644
|
-
const claudeContent = fs.readFileSync(claudePath,
|
|
1863
|
+
const claudeContent = fs.readFileSync(claudePath, "utf8");
|
|
1645
1864
|
agentsContent = claudeContent
|
|
1646
|
-
.replace(/# Claude Code Spec-Driven Development/g,
|
|
1647
|
-
.replace(/Claude Code/g,
|
|
1648
|
-
.replace(/claude code/g,
|
|
1649
|
-
.replace(/Claude/g,
|
|
1650
|
-
.replace(/claude/g,
|
|
1865
|
+
.replace(/# Claude Code Spec-Driven Development/g, "# AI Agent Spec-Driven Development")
|
|
1866
|
+
.replace(/Claude Code/g, "AI Agent")
|
|
1867
|
+
.replace(/claude code/g, "ai agent")
|
|
1868
|
+
.replace(/Claude/g, "AI Agent")
|
|
1869
|
+
.replace(/claude/g, "ai agent");
|
|
1651
1870
|
}
|
|
1652
1871
|
else {
|
|
1653
1872
|
agentsContent = `# AI Agent Spec-Driven Development
|
|
@@ -1730,8 +1949,9 @@ Managed by \`/kiro:steering\` command. Updates here reflect command changes.
|
|
|
1730
1949
|
fs.writeFileSync(agentsPath, agentsContent);
|
|
1731
1950
|
}
|
|
1732
1951
|
return {
|
|
1733
|
-
content: [
|
|
1734
|
-
|
|
1952
|
+
content: [
|
|
1953
|
+
{
|
|
1954
|
+
type: "text",
|
|
1735
1955
|
text: `## SDD Project Initialized Successfully
|
|
1736
1956
|
|
|
1737
1957
|
**Feature Name**: \`${featureName}\`
|
|
@@ -1746,17 +1966,20 @@ Managed by \`/kiro:steering\` command. Updates here reflect command changes.
|
|
|
1746
1966
|
2. Follow the SDD workflow: Requirements → Design → Tasks → Implementation
|
|
1747
1967
|
|
|
1748
1968
|
**Workflow Phase**: Initialized
|
|
1749
|
-
**Ready for**: Requirements generation
|
|
1750
|
-
}
|
|
1969
|
+
**Ready for**: Requirements generation`,
|
|
1970
|
+
},
|
|
1971
|
+
],
|
|
1751
1972
|
};
|
|
1752
1973
|
}
|
|
1753
1974
|
catch (error) {
|
|
1754
1975
|
return {
|
|
1755
|
-
content: [
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1976
|
+
content: [
|
|
1977
|
+
{
|
|
1978
|
+
type: "text",
|
|
1979
|
+
text: `Error initializing SDD project: ${error.message}`,
|
|
1980
|
+
},
|
|
1981
|
+
],
|
|
1982
|
+
isError: true,
|
|
1760
1983
|
};
|
|
1761
1984
|
}
|
|
1762
1985
|
}
|
|
@@ -1769,11 +1992,11 @@ async function main() {
|
|
|
1769
1992
|
else {
|
|
1770
1993
|
// Use full featured server for development/testing mode
|
|
1771
1994
|
const server = await createMCPServer();
|
|
1772
|
-
const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry } = server;
|
|
1773
|
-
logger.info(
|
|
1774
|
-
version: process.env.npm_package_version ??
|
|
1995
|
+
const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry, } = server;
|
|
1996
|
+
logger.info("MCP SDD Server starting...", {
|
|
1997
|
+
version: process.env.npm_package_version ?? "1.0.0",
|
|
1775
1998
|
nodeVersion: process.version,
|
|
1776
|
-
pid: process.pid
|
|
1999
|
+
pid: process.pid,
|
|
1777
2000
|
});
|
|
1778
2001
|
await mcpServer.start();
|
|
1779
2002
|
// Get plugin system statistics
|
|
@@ -1781,41 +2004,63 @@ async function main() {
|
|
|
1781
2004
|
const hookStats = await hookSystem.getAllHooks();
|
|
1782
2005
|
const toolStats = await toolRegistry.getAllTools();
|
|
1783
2006
|
const steeringStats = await steeringRegistry.getSteeringStatistics();
|
|
1784
|
-
logger.info(
|
|
2007
|
+
logger.info("MCP SDD Server ready for connections", {
|
|
1785
2008
|
capabilities: {
|
|
1786
|
-
workflow:
|
|
1787
|
-
validation:
|
|
1788
|
-
initialization:
|
|
1789
|
-
context:
|
|
1790
|
-
steering:
|
|
1791
|
-
quality:
|
|
1792
|
-
i18n:
|
|
2009
|
+
workflow: "5-phase SDD workflow state machine (INIT→REQUIREMENTS→DESIGN→TASKS→IMPLEMENTATION)",
|
|
2010
|
+
validation: "Cross-phase validation with approval gates and rollback support",
|
|
2011
|
+
initialization: "Project setup with .kiro directory structure and spec.json",
|
|
2012
|
+
context: "Project memory with codebase analysis and context persistence",
|
|
2013
|
+
steering: "Dynamic steering document management with Always/Conditional/Manual modes",
|
|
2014
|
+
quality: "Linus-style code review with 5-layer analysis framework",
|
|
2015
|
+
i18n: "10-language support with cultural adaptation",
|
|
1793
2016
|
plugins: `${pluginStats.length} plugins loaded with extensibility framework`,
|
|
1794
|
-
templates:
|
|
2017
|
+
templates: "Handlebars-based template generation with inheritance",
|
|
1795
2018
|
},
|
|
1796
2019
|
tools: {
|
|
1797
2020
|
count: 10,
|
|
1798
|
-
categories: [
|
|
1799
|
-
|
|
2021
|
+
categories: [
|
|
2022
|
+
"sdd-init",
|
|
2023
|
+
"sdd-requirements",
|
|
2024
|
+
"sdd-design",
|
|
2025
|
+
"sdd-tasks",
|
|
2026
|
+
"sdd-implement",
|
|
2027
|
+
"sdd-status",
|
|
2028
|
+
"sdd-approve",
|
|
2029
|
+
"sdd-quality-check",
|
|
2030
|
+
"sdd-context-load",
|
|
2031
|
+
"sdd-template-render",
|
|
2032
|
+
],
|
|
2033
|
+
pluginTools: Object.keys(toolStats).length,
|
|
1800
2034
|
},
|
|
1801
2035
|
hooks: {
|
|
1802
2036
|
registered: Object.keys(hookStats).length,
|
|
1803
|
-
phases: [
|
|
2037
|
+
phases: [
|
|
2038
|
+
"PRE_INIT",
|
|
2039
|
+
"POST_INIT",
|
|
2040
|
+
"PRE_REQUIREMENTS",
|
|
2041
|
+
"POST_REQUIREMENTS",
|
|
2042
|
+
"PRE_DESIGN",
|
|
2043
|
+
"POST_DESIGN",
|
|
2044
|
+
"PRE_TASKS",
|
|
2045
|
+
"POST_TASKS",
|
|
2046
|
+
"PRE_IMPLEMENTATION",
|
|
2047
|
+
"POST_IMPLEMENTATION",
|
|
2048
|
+
],
|
|
1804
2049
|
},
|
|
1805
2050
|
steering: {
|
|
1806
2051
|
documents: steeringStats.totalDocuments,
|
|
1807
2052
|
plugins: Object.keys(steeringStats.documentsByPlugin).length,
|
|
1808
|
-
modes: steeringStats.documentsByMode
|
|
1809
|
-
}
|
|
2053
|
+
modes: steeringStats.documentsByMode,
|
|
2054
|
+
},
|
|
1810
2055
|
});
|
|
1811
2056
|
// Handle graceful shutdown
|
|
1812
|
-
process.on(
|
|
1813
|
-
logger.info(
|
|
2057
|
+
process.on("SIGINT", async () => {
|
|
2058
|
+
logger.info("Received SIGINT, shutting down gracefully...");
|
|
1814
2059
|
await mcpServer.stop();
|
|
1815
2060
|
process.exit(0);
|
|
1816
2061
|
});
|
|
1817
|
-
process.on(
|
|
1818
|
-
logger.info(
|
|
2062
|
+
process.on("SIGTERM", async () => {
|
|
2063
|
+
logger.info("Received SIGTERM, shutting down gracefully...");
|
|
1819
2064
|
await mcpServer.stop();
|
|
1820
2065
|
process.exit(0);
|
|
1821
2066
|
});
|
|
@@ -1824,7 +2069,7 @@ async function main() {
|
|
|
1824
2069
|
catch (error) {
|
|
1825
2070
|
// Only log startup errors in non-MCP mode
|
|
1826
2071
|
if (!isMCPMode) {
|
|
1827
|
-
console.error(
|
|
2072
|
+
console.error("Failed to start MCP SDD Server:", error);
|
|
1828
2073
|
}
|
|
1829
2074
|
process.exit(1);
|
|
1830
2075
|
}
|