sdd-mcp-server 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +861 -586
- package/dist/index.js.map +1 -1
- package/dist/utils/moduleLoader.d.ts +75 -0
- package/dist/utils/moduleLoader.js +82 -0
- package/dist/utils/moduleLoader.js.map +1 -0
- package/dist/utils/specGenerator.js +228 -160
- package/dist/utils/specGenerator.js.map +1 -1
- package/package.json +1 -1
- package/dist/__tests__/legacy/setup.d.ts +0 -44
- package/dist/__tests__/legacy/setup.js +0 -178
- package/dist/__tests__/legacy/setup.js.map +0 -1
- package/dist/__tests__/legacy/test-helpers/mock-factories.d.ts +0 -26
- package/dist/__tests__/legacy/test-helpers/mock-factories.js +0 -466
- package/dist/__tests__/legacy/test-helpers/mock-factories.js.map +0 -1
- package/dist/__tests__/setup.d.ts +0 -44
- package/dist/__tests__/setup.js +0 -178
- package/dist/__tests__/setup.js.map +0 -1
- package/dist/__tests__/test-helpers/mock-factories.d.ts +0 -26
- package/dist/__tests__/test-helpers/mock-factories.js +0 -466
- package/dist/__tests__/test-helpers/mock-factories.js.map +0 -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}`);
|
|
@@ -322,17 +345,37 @@ async function createSimpleMCPServer() {
|
|
|
322
345
|
const transport = new StdioServerTransport();
|
|
323
346
|
await server.connect(transport);
|
|
324
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Helper function to handle module loader failures consistently
|
|
350
|
+
*
|
|
351
|
+
* @param context - Description of what was being loaded (e.g., "documentGenerator", "specGenerator")
|
|
352
|
+
* @param error - The error that occurred during loading
|
|
353
|
+
* @param allowFallback - Whether to allow fallback templates (from env var or args)
|
|
354
|
+
* @returns Object with fallback content if allowed, or throws error
|
|
355
|
+
* @throws Error if fallback is not allowed
|
|
356
|
+
*/
|
|
357
|
+
function handleLoaderFailure(context, error, allowFallback = false) {
|
|
358
|
+
const errorMessage = `Failed to load ${context}: ${error.message}\n\nTo use template fallbacks, set SDD_ALLOW_TEMPLATE_FALLBACK=true environment variable or run 'npm run build' to generate required files.`;
|
|
359
|
+
console.error(`[SDD-DEBUG] Loader failure for ${context}:`, error.message);
|
|
360
|
+
console.error(`[SDD-DEBUG] Fallback allowed:`, allowFallback);
|
|
361
|
+
if (!allowFallback) {
|
|
362
|
+
// Propagate error - do not use fallback
|
|
363
|
+
throw new Error(errorMessage);
|
|
364
|
+
}
|
|
365
|
+
console.error(`[SDD-DEBUG] Using fallback templates for ${context}`);
|
|
366
|
+
return { useFallback: true, error };
|
|
367
|
+
}
|
|
325
368
|
// Simplified steering implementation for MCP mode
|
|
326
369
|
async function handleSteeringSimplified(args) {
|
|
327
|
-
const fs = await import(
|
|
328
|
-
const path = await import(
|
|
370
|
+
const fs = await import("fs");
|
|
371
|
+
const path = await import("path");
|
|
329
372
|
const fsPromises = fs.promises;
|
|
330
373
|
const projectPath = process.cwd();
|
|
331
374
|
const stubSteeringService = {
|
|
332
375
|
async createSteeringDocument(projectDir, config) {
|
|
333
|
-
const docPath = path.join(projectDir,
|
|
376
|
+
const docPath = path.join(projectDir, ".kiro", "steering", config.name);
|
|
334
377
|
await fsPromises.mkdir(path.dirname(docPath), { recursive: true });
|
|
335
|
-
await fsPromises.writeFile(docPath, config.content,
|
|
378
|
+
await fsPromises.writeFile(docPath, config.content, "utf8");
|
|
336
379
|
return {
|
|
337
380
|
name: config.name,
|
|
338
381
|
path: docPath,
|
|
@@ -342,13 +385,13 @@ async function handleSteeringSimplified(args) {
|
|
|
342
385
|
patterns: config.patterns ?? [],
|
|
343
386
|
priority: config.priority ?? 50,
|
|
344
387
|
lastModified: new Date(),
|
|
345
|
-
isValid: true
|
|
388
|
+
isValid: true,
|
|
346
389
|
};
|
|
347
|
-
}
|
|
390
|
+
},
|
|
348
391
|
};
|
|
349
392
|
try {
|
|
350
393
|
// Create .kiro/steering directory if it doesn't exist
|
|
351
|
-
const steeringDir = path.join(projectPath,
|
|
394
|
+
const steeringDir = path.join(projectPath, ".kiro", "steering");
|
|
352
395
|
if (!fs.existsSync(steeringDir)) {
|
|
353
396
|
fs.mkdirSync(steeringDir, { recursive: true });
|
|
354
397
|
}
|
|
@@ -356,42 +399,44 @@ async function handleSteeringSimplified(args) {
|
|
|
356
399
|
let techContent;
|
|
357
400
|
let structureContent;
|
|
358
401
|
let projectAnalysis;
|
|
402
|
+
// Check if fallback is allowed via environment variable or args
|
|
403
|
+
const allowFallback = process.env.SDD_ALLOW_TEMPLATE_FALLBACK === "true" ||
|
|
404
|
+
args?.allowFallback === true;
|
|
359
405
|
try {
|
|
360
|
-
// Attempt to import and use the dynamic document generator (
|
|
361
|
-
console.error(
|
|
362
|
-
const { analyzeProject, generateProductDocument, generateTechDocument, generateStructureDocument } = await
|
|
363
|
-
console.error(
|
|
406
|
+
// Attempt to import and use the dynamic document generator (using unified module loader)
|
|
407
|
+
console.error("[SDD-DEBUG] Attempting to load documentGenerator using moduleLoader");
|
|
408
|
+
const { analyzeProject, generateProductDocument, generateTechDocument, generateStructureDocument, } = await loadDocumentGenerator();
|
|
409
|
+
console.error("[SDD-DEBUG] DocumentGenerator imported successfully, analyzing project...");
|
|
364
410
|
// Analyze project dynamically
|
|
365
411
|
projectAnalysis = await analyzeProject(projectPath);
|
|
366
|
-
console.error(
|
|
412
|
+
console.error("[SDD-DEBUG] Project analysis completed, generating documents...");
|
|
367
413
|
// Generate documents dynamically
|
|
368
414
|
productContent = generateProductDocument(projectAnalysis);
|
|
369
415
|
techContent = generateTechDocument(projectAnalysis);
|
|
370
416
|
structureContent = generateStructureDocument(projectAnalysis);
|
|
371
|
-
console.error(
|
|
417
|
+
console.error("[SDD-DEBUG] Dynamic document generation completed successfully");
|
|
372
418
|
}
|
|
373
419
|
catch (importError) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
console.error('[SDD-DEBUG] Falling back to basic templates with warning...');
|
|
420
|
+
// Use shared error handler
|
|
421
|
+
const { useFallback, error } = handleLoaderFailure("documentGenerator", importError, allowFallback);
|
|
377
422
|
// Fallback to basic templates
|
|
378
|
-
const packageJsonPath = path.join(projectPath,
|
|
379
|
-
let projectName =
|
|
380
|
-
let projectVersion =
|
|
423
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
424
|
+
let projectName = "Unknown Project";
|
|
425
|
+
let projectVersion = "0.0.0";
|
|
381
426
|
try {
|
|
382
427
|
if (fs.existsSync(packageJsonPath)) {
|
|
383
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath,
|
|
428
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
384
429
|
projectName = packageJson.name || projectName;
|
|
385
430
|
projectVersion = packageJson.version || projectVersion;
|
|
386
431
|
}
|
|
387
432
|
}
|
|
388
433
|
catch (pkgError) {
|
|
389
|
-
console.error(
|
|
434
|
+
console.error("[SDD-DEBUG] Could not read package.json, using defaults");
|
|
390
435
|
}
|
|
391
436
|
productContent = `# Product Overview
|
|
392
437
|
|
|
393
438
|
⚠️ **Warning**: This document was generated using fallback templates due to documentGenerator import failure.
|
|
394
|
-
Error: ${
|
|
439
|
+
Error: ${error.message}
|
|
395
440
|
|
|
396
441
|
## Product Description
|
|
397
442
|
${projectName}
|
|
@@ -416,7 +461,7 @@ Generated on: ${new Date().toISOString()}
|
|
|
416
461
|
techContent = `# Technology Stack
|
|
417
462
|
|
|
418
463
|
⚠️ **Warning**: This document was generated using fallback templates due to documentGenerator import failure.
|
|
419
|
-
Error: ${
|
|
464
|
+
Error: ${error.message}
|
|
420
465
|
|
|
421
466
|
## Architecture
|
|
422
467
|
**Type**: MCP Server Application
|
|
@@ -440,7 +485,7 @@ Generated on: ${new Date().toISOString()}
|
|
|
440
485
|
structureContent = `# Project Structure
|
|
441
486
|
|
|
442
487
|
⚠️ **Warning**: This document was generated using fallback templates due to documentGenerator import failure.
|
|
443
|
-
Error: ${
|
|
488
|
+
Error: ${error.message}
|
|
444
489
|
|
|
445
490
|
## Directory Organization
|
|
446
491
|
\`\`\`
|
|
@@ -468,38 +513,38 @@ Generated on: ${new Date().toISOString()}
|
|
|
468
513
|
const fallbackAnalysis = {
|
|
469
514
|
name: projectName,
|
|
470
515
|
version: projectVersion,
|
|
471
|
-
architecture:
|
|
472
|
-
language:
|
|
473
|
-
framework:
|
|
516
|
+
architecture: "MCP Server Application",
|
|
517
|
+
language: "typescript",
|
|
518
|
+
framework: "MCP SDK",
|
|
474
519
|
dependencies: [],
|
|
475
520
|
devDependencies: [],
|
|
476
521
|
testFramework: null,
|
|
477
|
-
buildTool:
|
|
478
|
-
directories: [
|
|
522
|
+
buildTool: "TypeScript Compiler",
|
|
523
|
+
directories: ["src", "dist"],
|
|
479
524
|
hasCI: false,
|
|
480
|
-
hasDocker: false
|
|
525
|
+
hasDocker: false,
|
|
481
526
|
};
|
|
482
527
|
// Use fallback analysis for the return message
|
|
483
528
|
projectAnalysis = fallbackAnalysis;
|
|
484
529
|
}
|
|
485
530
|
// Write the dynamically generated files
|
|
486
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
487
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
488
|
-
fs.writeFileSync(path.join(steeringDir,
|
|
531
|
+
fs.writeFileSync(path.join(steeringDir, "product.md"), productContent);
|
|
532
|
+
fs.writeFileSync(path.join(steeringDir, "tech.md"), techContent);
|
|
533
|
+
fs.writeFileSync(path.join(steeringDir, "structure.md"), structureContent);
|
|
489
534
|
await ensureStaticSteeringDocuments(projectPath, stubSteeringService);
|
|
490
535
|
// Ensure AGENTS.md exists (based on CLAUDE.md if available)
|
|
491
|
-
const agentsPath = path.join(projectPath,
|
|
536
|
+
const agentsPath = path.join(projectPath, "AGENTS.md");
|
|
492
537
|
if (!fs.existsSync(agentsPath)) {
|
|
493
|
-
const claudePath = path.join(projectPath,
|
|
494
|
-
let agentsContent =
|
|
538
|
+
const claudePath = path.join(projectPath, "CLAUDE.md");
|
|
539
|
+
let agentsContent = "";
|
|
495
540
|
if (fs.existsSync(claudePath)) {
|
|
496
|
-
const claudeContent = fs.readFileSync(claudePath,
|
|
541
|
+
const claudeContent = fs.readFileSync(claudePath, "utf8");
|
|
497
542
|
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,
|
|
543
|
+
.replace(/# Claude Code Spec-Driven Development/g, "# AI Agent Spec-Driven Development")
|
|
544
|
+
.replace(/Claude Code/g, "AI Agent")
|
|
545
|
+
.replace(/claude code/g, "ai agent")
|
|
546
|
+
.replace(/\.claude\//g, ".ai agent/")
|
|
547
|
+
.replace(/\/claude/g, "/agent");
|
|
503
548
|
}
|
|
504
549
|
else {
|
|
505
550
|
agentsContent = `# AI Agent Spec-Driven Development
|
|
@@ -585,8 +630,9 @@ Generated on: ${new Date().toISOString()}
|
|
|
585
630
|
fs.writeFileSync(agentsPath, agentsContent);
|
|
586
631
|
}
|
|
587
632
|
return {
|
|
588
|
-
content: [
|
|
589
|
-
|
|
633
|
+
content: [
|
|
634
|
+
{
|
|
635
|
+
type: "text",
|
|
590
636
|
text: `## Steering Documents Updated
|
|
591
637
|
|
|
592
638
|
**Project**: ${projectAnalysis.name}
|
|
@@ -604,39 +650,42 @@ Generated on: ${new Date().toISOString()}
|
|
|
604
650
|
- \`.kiro/steering/principles.md\` - Core coding principles: SOLID, DRY, KISS, YAGNI, SoC, Modularity (static)
|
|
605
651
|
|
|
606
652
|
**Dynamic Analysis Results**:
|
|
607
|
-
- **Language**: ${projectAnalysis.language ===
|
|
608
|
-
- **Framework**: ${projectAnalysis.framework ||
|
|
653
|
+
- **Language**: ${projectAnalysis.language === "typescript" ? "TypeScript" : "JavaScript"}
|
|
654
|
+
- **Framework**: ${projectAnalysis.framework || "None detected"}
|
|
609
655
|
- **Dependencies**: ${projectAnalysis.dependencies.length} production, ${projectAnalysis.devDependencies.length} development
|
|
610
|
-
- **Test Framework**: ${projectAnalysis.testFramework ||
|
|
611
|
-
- **Build Tool**: ${projectAnalysis.buildTool ||
|
|
656
|
+
- **Test Framework**: ${projectAnalysis.testFramework || "None detected"}
|
|
657
|
+
- **Build Tool**: ${projectAnalysis.buildTool || "None detected"}
|
|
612
658
|
- **Project Structure**: ${projectAnalysis.directories.length} directories analyzed
|
|
613
|
-
- **CI/CD**: ${projectAnalysis.hasCI ?
|
|
614
|
-
- **Docker**: ${projectAnalysis.hasDocker ?
|
|
659
|
+
- **CI/CD**: ${projectAnalysis.hasCI ? "Configured" : "Not configured"}
|
|
660
|
+
- **Docker**: ${projectAnalysis.hasDocker ? "Configured" : "Not configured"}
|
|
615
661
|
|
|
616
|
-
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions
|
|
617
|
-
}
|
|
662
|
+
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions.`,
|
|
663
|
+
},
|
|
664
|
+
],
|
|
618
665
|
};
|
|
619
666
|
}
|
|
620
667
|
catch (error) {
|
|
621
668
|
return {
|
|
622
|
-
content: [
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
669
|
+
content: [
|
|
670
|
+
{
|
|
671
|
+
type: "text",
|
|
672
|
+
text: `Error generating steering documents: ${error.message}`,
|
|
673
|
+
},
|
|
674
|
+
],
|
|
675
|
+
isError: true,
|
|
627
676
|
};
|
|
628
677
|
}
|
|
629
678
|
}
|
|
630
679
|
async function handleSteeringCustomSimplified(args) {
|
|
631
|
-
const fs = await import(
|
|
632
|
-
const path = await import(
|
|
680
|
+
const fs = await import("fs");
|
|
681
|
+
const path = await import("path");
|
|
633
682
|
try {
|
|
634
683
|
const { fileName, topic, inclusionMode, filePattern } = args;
|
|
635
684
|
if (!fileName || !topic || !inclusionMode) {
|
|
636
|
-
throw new Error(
|
|
685
|
+
throw new Error("fileName, topic, and inclusionMode are required");
|
|
637
686
|
}
|
|
638
687
|
const projectPath = process.cwd();
|
|
639
|
-
const steeringDir = path.join(projectPath,
|
|
688
|
+
const steeringDir = path.join(projectPath, ".kiro", "steering");
|
|
640
689
|
if (!fs.existsSync(steeringDir)) {
|
|
641
690
|
fs.mkdirSync(steeringDir, { recursive: true });
|
|
642
691
|
}
|
|
@@ -653,59 +702,85 @@ Define the purpose and scope of this steering document.
|
|
|
653
702
|
Describe when and how this steering document should be applied.
|
|
654
703
|
|
|
655
704
|
## Inclusion Mode
|
|
656
|
-
Mode: ${inclusionMode}${filePattern
|
|
657
|
-
|
|
705
|
+
Mode: ${inclusionMode}${filePattern
|
|
706
|
+
? `
|
|
707
|
+
Pattern: ${filePattern}`
|
|
708
|
+
: ""}
|
|
658
709
|
|
|
659
710
|
Generated on: ${new Date().toISOString()}
|
|
660
711
|
`;
|
|
661
712
|
fs.writeFileSync(path.join(steeringDir, fileName), content);
|
|
662
713
|
return {
|
|
663
|
-
content: [
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
714
|
+
content: [
|
|
715
|
+
{
|
|
716
|
+
type: "text",
|
|
717
|
+
text: `Custom steering document "${fileName}" created successfully with ${inclusionMode} inclusion mode.`,
|
|
718
|
+
},
|
|
719
|
+
],
|
|
667
720
|
};
|
|
668
721
|
}
|
|
669
722
|
catch (error) {
|
|
670
723
|
return {
|
|
671
|
-
content: [
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
724
|
+
content: [
|
|
725
|
+
{
|
|
726
|
+
type: "text",
|
|
727
|
+
text: `Error creating custom steering document: ${error.message}`,
|
|
728
|
+
},
|
|
729
|
+
],
|
|
730
|
+
isError: true,
|
|
676
731
|
};
|
|
677
732
|
}
|
|
678
733
|
}
|
|
679
734
|
// Status handler aligned with full server behavior
|
|
680
735
|
async function handleStatusSimplified(args) {
|
|
681
|
-
const fs = await import(
|
|
682
|
-
const path = await import(
|
|
736
|
+
const fs = await import("fs");
|
|
737
|
+
const path = await import("path");
|
|
683
738
|
const { featureName } = args || {};
|
|
684
739
|
const currentPath = process.cwd();
|
|
685
|
-
const kiroPath = path.join(currentPath,
|
|
686
|
-
const exists = await fs.promises
|
|
740
|
+
const kiroPath = path.join(currentPath, ".kiro");
|
|
741
|
+
const exists = await fs.promises
|
|
742
|
+
.access(kiroPath)
|
|
743
|
+
.then(() => true)
|
|
744
|
+
.catch(() => false);
|
|
687
745
|
if (!exists) {
|
|
688
|
-
return {
|
|
746
|
+
return {
|
|
747
|
+
content: [
|
|
748
|
+
{
|
|
749
|
+
type: "text",
|
|
750
|
+
text: "SDD project status: No active project found. Use sdd-init to create a new project.",
|
|
751
|
+
},
|
|
752
|
+
],
|
|
753
|
+
};
|
|
689
754
|
}
|
|
690
|
-
const specsPath = path.join(kiroPath,
|
|
755
|
+
const specsPath = path.join(kiroPath, "specs");
|
|
691
756
|
if (featureName) {
|
|
692
757
|
const featurePath = path.join(specsPath, featureName);
|
|
693
|
-
const specPath = path.join(featurePath,
|
|
694
|
-
const specExists = await fs.promises
|
|
758
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
759
|
+
const specExists = await fs.promises
|
|
760
|
+
.access(specPath)
|
|
761
|
+
.then(() => true)
|
|
762
|
+
.catch(() => false);
|
|
695
763
|
if (!specExists) {
|
|
696
|
-
return {
|
|
764
|
+
return {
|
|
765
|
+
content: [
|
|
766
|
+
{
|
|
767
|
+
type: "text",
|
|
768
|
+
text: `Feature "${featureName}" not found. Use sdd-init to create it.`,
|
|
769
|
+
},
|
|
770
|
+
],
|
|
771
|
+
};
|
|
697
772
|
}
|
|
698
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
773
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
699
774
|
let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
|
|
700
775
|
status += `**Current Phase**: ${spec.phase}\n`;
|
|
701
776
|
status += `**Language**: ${spec.language}\n`;
|
|
702
777
|
status += `**Created**: ${spec.created_at}\n`;
|
|
703
778
|
status += `**Updated**: ${spec.updated_at}\n\n`;
|
|
704
779
|
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 ?
|
|
780
|
+
status += `- Requirements: ${spec.approvals.requirements.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.requirements.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
|
|
781
|
+
status += `- Design: ${spec.approvals.design.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.design.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
|
|
782
|
+
status += `- Tasks: ${spec.approvals.tasks.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.tasks.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n\n`;
|
|
783
|
+
status += `**Ready for Implementation**: ${spec.ready_for_implementation ? "✅ Yes" : "❌ No"}\n\n`;
|
|
709
784
|
if (!spec.approvals.requirements.generated)
|
|
710
785
|
status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
|
|
711
786
|
else if (!spec.approvals.design.generated)
|
|
@@ -714,95 +789,168 @@ async function handleStatusSimplified(args) {
|
|
|
714
789
|
status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
|
|
715
790
|
else
|
|
716
791
|
status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
|
|
717
|
-
return { content: [{ type:
|
|
792
|
+
return { content: [{ type: "text", text: status }] };
|
|
718
793
|
}
|
|
719
|
-
const features = await fs.promises
|
|
794
|
+
const features = await fs.promises
|
|
795
|
+
.readdir(specsPath)
|
|
796
|
+
.catch(() => []);
|
|
720
797
|
if (features.length === 0) {
|
|
721
|
-
return {
|
|
798
|
+
return {
|
|
799
|
+
content: [
|
|
800
|
+
{
|
|
801
|
+
type: "text",
|
|
802
|
+
text: "No SDD features found. Use sdd-init to create a new project.",
|
|
803
|
+
},
|
|
804
|
+
],
|
|
805
|
+
};
|
|
722
806
|
}
|
|
723
|
-
let status =
|
|
807
|
+
let status = "## SDD Project Status - All Features\n\n";
|
|
724
808
|
for (const feature of features) {
|
|
725
|
-
const specPath = path.join(specsPath, feature,
|
|
726
|
-
const specExists = await fs.promises
|
|
809
|
+
const specPath = path.join(specsPath, feature, "spec.json");
|
|
810
|
+
const specExists = await fs.promises
|
|
811
|
+
.access(specPath)
|
|
812
|
+
.then(() => true)
|
|
813
|
+
.catch(() => false);
|
|
727
814
|
if (specExists) {
|
|
728
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
815
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
729
816
|
status += `**${spec.feature_name}**:\n`;
|
|
730
817
|
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 ?
|
|
818
|
+
status += `- Requirements: ${spec.approvals.requirements.generated ? "✅" : "❌"}\n`;
|
|
819
|
+
status += `- Design: ${spec.approvals.design.generated ? "✅" : "❌"}\n`;
|
|
820
|
+
status += `- Tasks: ${spec.approvals.tasks.generated ? "✅" : "❌"}\n`;
|
|
821
|
+
status += `- Ready: ${spec.ready_for_implementation ? "✅" : "❌"}\n\n`;
|
|
735
822
|
}
|
|
736
823
|
}
|
|
737
|
-
return { content: [{ type:
|
|
824
|
+
return { content: [{ type: "text", text: status }] };
|
|
738
825
|
}
|
|
739
826
|
// Approve handler to update spec.json
|
|
740
827
|
async function handleApproveSimplified(args) {
|
|
741
|
-
const fs = await import(
|
|
742
|
-
const path = await import(
|
|
828
|
+
const fs = await import("fs");
|
|
829
|
+
const path = await import("path");
|
|
743
830
|
const { featureName, phase } = args || {};
|
|
744
831
|
if (!featureName || !phase) {
|
|
745
|
-
return {
|
|
832
|
+
return {
|
|
833
|
+
content: [{ type: "text", text: "featureName and phase are required" }],
|
|
834
|
+
isError: true,
|
|
835
|
+
};
|
|
746
836
|
}
|
|
747
837
|
try {
|
|
748
|
-
const featurePath = path.join(process.cwd(),
|
|
749
|
-
const specPath = path.join(featurePath,
|
|
750
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
838
|
+
const featurePath = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
839
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
840
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
751
841
|
if (!spec.approvals?.[phase]?.generated) {
|
|
752
|
-
return {
|
|
842
|
+
return {
|
|
843
|
+
content: [
|
|
844
|
+
{
|
|
845
|
+
type: "text",
|
|
846
|
+
text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`,
|
|
847
|
+
},
|
|
848
|
+
],
|
|
849
|
+
};
|
|
753
850
|
}
|
|
754
851
|
spec.approvals[phase].approved = true;
|
|
755
852
|
spec.updated_at = new Date().toISOString();
|
|
756
853
|
fs.writeFileSync(specPath, JSON.stringify(spec, null, 2));
|
|
757
|
-
return {
|
|
854
|
+
return {
|
|
855
|
+
content: [
|
|
856
|
+
{
|
|
857
|
+
type: "text",
|
|
858
|
+
text: `## Phase Approved\n\n**Feature**: ${featureName}\n**Phase**: ${phase}\n**Status**: ✅ Approved`,
|
|
859
|
+
},
|
|
860
|
+
],
|
|
861
|
+
};
|
|
758
862
|
}
|
|
759
863
|
catch (error) {
|
|
760
|
-
return {
|
|
864
|
+
return {
|
|
865
|
+
content: [
|
|
866
|
+
{
|
|
867
|
+
type: "text",
|
|
868
|
+
text: `Error approving phase: ${error.message}`,
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
isError: true,
|
|
872
|
+
};
|
|
761
873
|
}
|
|
762
874
|
}
|
|
763
875
|
// Simple quality check aligned with full server
|
|
764
876
|
async function handleQualityCheckSimplified(args) {
|
|
765
|
-
const { code =
|
|
877
|
+
const { code = "", language = "javascript" } = args || {};
|
|
766
878
|
try {
|
|
767
|
-
const lines = String(code).split(
|
|
879
|
+
const lines = String(code).split("\n");
|
|
768
880
|
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(
|
|
881
|
+
if (code.includes("console.log"))
|
|
882
|
+
issues.push("L1: Remove debug console.log statements");
|
|
883
|
+
if (code.includes("var "))
|
|
884
|
+
issues.push("L1: Use let/const instead of var");
|
|
885
|
+
if (!/^[a-z]/.test(code.split("function ")[1]?.split("(")[0] || "")) {
|
|
886
|
+
if (code.includes("function "))
|
|
887
|
+
issues.push("L2: Function names should start with lowercase");
|
|
776
888
|
}
|
|
777
|
-
if (code.includes(
|
|
778
|
-
issues.push(
|
|
889
|
+
if (code.includes("for") && !code.includes("const"))
|
|
890
|
+
issues.push("L3: Prefer const in for loops");
|
|
779
891
|
if (lines.length > 50)
|
|
780
|
-
issues.push(
|
|
781
|
-
const report = `## Code Quality Analysis (${language})\n\n` +
|
|
782
|
-
|
|
892
|
+
issues.push("L4: Consider splitting large blocks into smaller functions");
|
|
893
|
+
const report = `## Code Quality Analysis (${language})\n\n` +
|
|
894
|
+
(issues.length
|
|
895
|
+
? issues.map((i) => `- ${i}`).join("\n")
|
|
896
|
+
: "No significant issues detected");
|
|
897
|
+
return { content: [{ type: "text", text: report }] };
|
|
783
898
|
}
|
|
784
899
|
catch (error) {
|
|
785
|
-
return {
|
|
900
|
+
return {
|
|
901
|
+
content: [
|
|
902
|
+
{
|
|
903
|
+
type: "text",
|
|
904
|
+
text: `Error analyzing code quality: ${error.message}`,
|
|
905
|
+
},
|
|
906
|
+
],
|
|
907
|
+
isError: true,
|
|
908
|
+
};
|
|
786
909
|
}
|
|
787
910
|
}
|
|
788
911
|
// Implement guidelines check
|
|
789
912
|
async function handleImplementSimplified(args) {
|
|
790
|
-
const fs = await import(
|
|
791
|
-
const path = await import(
|
|
913
|
+
const fs = await import("fs");
|
|
914
|
+
const path = await import("path");
|
|
792
915
|
const { featureName } = args || {};
|
|
793
916
|
if (!featureName)
|
|
794
|
-
return {
|
|
917
|
+
return {
|
|
918
|
+
content: [{ type: "text", text: "featureName is required" }],
|
|
919
|
+
isError: true,
|
|
920
|
+
};
|
|
795
921
|
try {
|
|
796
|
-
const featurePath = path.join(process.cwd(),
|
|
797
|
-
const specPath = path.join(featurePath,
|
|
798
|
-
const spec = JSON.parse(fs.readFileSync(specPath,
|
|
922
|
+
const featurePath = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
923
|
+
const specPath = path.join(featurePath, "spec.json");
|
|
924
|
+
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
|
799
925
|
if (!spec.ready_for_implementation) {
|
|
800
|
-
return {
|
|
926
|
+
return {
|
|
927
|
+
content: [
|
|
928
|
+
{
|
|
929
|
+
type: "text",
|
|
930
|
+
text: "Error: Project not ready for implementation. Complete requirements, design, and tasks phases first.",
|
|
931
|
+
},
|
|
932
|
+
],
|
|
933
|
+
};
|
|
801
934
|
}
|
|
802
|
-
return {
|
|
935
|
+
return {
|
|
936
|
+
content: [
|
|
937
|
+
{
|
|
938
|
+
type: "text",
|
|
939
|
+
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.`,
|
|
940
|
+
},
|
|
941
|
+
],
|
|
942
|
+
};
|
|
803
943
|
}
|
|
804
944
|
catch (error) {
|
|
805
|
-
return {
|
|
945
|
+
return {
|
|
946
|
+
content: [
|
|
947
|
+
{
|
|
948
|
+
type: "text",
|
|
949
|
+
text: `Error getting implementation guidelines: ${error.message}`,
|
|
950
|
+
},
|
|
951
|
+
],
|
|
952
|
+
isError: true,
|
|
953
|
+
};
|
|
806
954
|
}
|
|
807
955
|
}
|
|
808
956
|
// Helper functions for simplified analysis
|
|
@@ -811,73 +959,79 @@ function extractFeaturesSimplified(packageJson) {
|
|
|
811
959
|
// Extract features from scripts
|
|
812
960
|
if (packageJson.scripts) {
|
|
813
961
|
if (packageJson.scripts.test)
|
|
814
|
-
features.push(
|
|
962
|
+
features.push("Testing framework");
|
|
815
963
|
if (packageJson.scripts.build)
|
|
816
|
-
features.push(
|
|
964
|
+
features.push("Build system");
|
|
817
965
|
if (packageJson.scripts.dev || packageJson.scripts.start)
|
|
818
|
-
features.push(
|
|
966
|
+
features.push("Development server");
|
|
819
967
|
if (packageJson.scripts.lint)
|
|
820
|
-
features.push(
|
|
968
|
+
features.push("Code linting");
|
|
821
969
|
if (packageJson.scripts.typecheck)
|
|
822
|
-
features.push(
|
|
970
|
+
features.push("Type checking");
|
|
823
971
|
}
|
|
824
972
|
// Extract features from dependencies
|
|
825
973
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
826
974
|
if (deps?.express || deps?.fastify || deps?.koa)
|
|
827
|
-
features.push(
|
|
975
|
+
features.push("Web server");
|
|
828
976
|
if (deps?.react || deps?.vue || deps?.angular)
|
|
829
|
-
features.push(
|
|
977
|
+
features.push("Frontend framework");
|
|
830
978
|
if (deps?.typescript)
|
|
831
|
-
features.push(
|
|
979
|
+
features.push("TypeScript support");
|
|
832
980
|
if (deps?.jest || deps?.mocha || deps?.vitest)
|
|
833
|
-
features.push(
|
|
981
|
+
features.push("Unit testing");
|
|
834
982
|
if (deps?.eslint)
|
|
835
|
-
features.push(
|
|
836
|
-
return features.length > 0 ? features : [
|
|
983
|
+
features.push("Code quality enforcement");
|
|
984
|
+
return features.length > 0 ? features : ["Core functionality"];
|
|
837
985
|
}
|
|
838
986
|
function generateTargetUsersSimplified(packageJson) {
|
|
839
|
-
if (packageJson.keywords?.includes(
|
|
840
|
-
return
|
|
987
|
+
if (packageJson.keywords?.includes("cli")) {
|
|
988
|
+
return "- Command-line tool users\n- Developers and system administrators";
|
|
841
989
|
}
|
|
842
|
-
if (packageJson.keywords?.includes(
|
|
843
|
-
return
|
|
990
|
+
if (packageJson.keywords?.includes("api")) {
|
|
991
|
+
return "- API consumers\n- Third-party integrators";
|
|
844
992
|
}
|
|
845
|
-
return
|
|
993
|
+
return "- Primary user persona\n- Secondary user persona";
|
|
846
994
|
}
|
|
847
995
|
function generateTechStackSimplified(packageJson) {
|
|
848
996
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
849
997
|
const stack = [];
|
|
850
998
|
if (deps?.typescript)
|
|
851
|
-
stack.push(
|
|
999
|
+
stack.push("TypeScript");
|
|
852
1000
|
if (deps?.node || packageJson.engines?.node)
|
|
853
|
-
stack.push(
|
|
1001
|
+
stack.push("Node.js");
|
|
854
1002
|
if (deps?.express)
|
|
855
|
-
stack.push(
|
|
1003
|
+
stack.push("Express.js");
|
|
856
1004
|
if (deps?.react)
|
|
857
|
-
stack.push(
|
|
1005
|
+
stack.push("React");
|
|
858
1006
|
if (deps?.vue)
|
|
859
|
-
stack.push(
|
|
860
|
-
return stack.length > 0 ? stack.join(
|
|
1007
|
+
stack.push("Vue.js");
|
|
1008
|
+
return stack.length > 0 ? stack.join(", ") : "Technology stack to be defined";
|
|
861
1009
|
}
|
|
862
1010
|
function generateDependencyListSimplified(packageJson) {
|
|
863
1011
|
const deps = packageJson.dependencies || {};
|
|
864
1012
|
const devDeps = packageJson.devDependencies || {};
|
|
865
|
-
let list =
|
|
1013
|
+
let list = "";
|
|
866
1014
|
const depList = Object.keys(deps);
|
|
867
1015
|
const devDepList = Object.keys(devDeps);
|
|
868
1016
|
if (depList.length > 0) {
|
|
869
|
-
list +=
|
|
870
|
-
list += depList
|
|
1017
|
+
list += "### Production Dependencies\n";
|
|
1018
|
+
list += depList
|
|
1019
|
+
.slice(0, 10)
|
|
1020
|
+
.map((dep) => `- ${dep}`)
|
|
1021
|
+
.join("\n");
|
|
871
1022
|
}
|
|
872
1023
|
if (devDepList.length > 0) {
|
|
873
|
-
list +=
|
|
874
|
-
list += devDepList
|
|
1024
|
+
list += "\n### Development Dependencies\n";
|
|
1025
|
+
list += devDepList
|
|
1026
|
+
.slice(0, 10)
|
|
1027
|
+
.map((dep) => `- ${dep}`)
|
|
1028
|
+
.join("\n");
|
|
875
1029
|
}
|
|
876
|
-
return list ||
|
|
1030
|
+
return list || "Dependencies to be analyzed";
|
|
877
1031
|
}
|
|
878
1032
|
function generateWorkflowSimplified(packageJson) {
|
|
879
1033
|
const scripts = packageJson.scripts || {};
|
|
880
|
-
let workflow =
|
|
1034
|
+
let workflow = "## Development Commands\n";
|
|
881
1035
|
if (scripts.dev)
|
|
882
1036
|
workflow += `- \`npm run dev\` - Start development server\n`;
|
|
883
1037
|
if (scripts.build)
|
|
@@ -889,27 +1043,29 @@ function generateWorkflowSimplified(packageJson) {
|
|
|
889
1043
|
return workflow;
|
|
890
1044
|
}
|
|
891
1045
|
function generateDirectoryStructureSimplified(projectPath) {
|
|
892
|
-
const fs = require(
|
|
1046
|
+
const fs = require("fs");
|
|
893
1047
|
try {
|
|
894
1048
|
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
895
1049
|
const directories = items
|
|
896
|
-
.filter((item) => item.isDirectory() &&
|
|
1050
|
+
.filter((item) => item.isDirectory() &&
|
|
1051
|
+
!item.name.startsWith(".") &&
|
|
1052
|
+
item.name !== "node_modules")
|
|
897
1053
|
.map((item) => `- ${item.name}/`)
|
|
898
|
-
.join(
|
|
899
|
-
return directories ||
|
|
1054
|
+
.join("\n");
|
|
1055
|
+
return directories || "Directory structure to be analyzed";
|
|
900
1056
|
}
|
|
901
1057
|
catch (error) {
|
|
902
|
-
return
|
|
1058
|
+
return "Directory structure to be analyzed";
|
|
903
1059
|
}
|
|
904
1060
|
}
|
|
905
1061
|
// Additional context-aware SDD tools
|
|
906
1062
|
async function handleRequirementsSimplified(args) {
|
|
907
|
-
const fs = await import(
|
|
908
|
-
const path = await import(
|
|
1063
|
+
const fs = await import("fs");
|
|
1064
|
+
const path = await import("path");
|
|
909
1065
|
try {
|
|
910
1066
|
const { featureName } = args;
|
|
911
|
-
if (!featureName || typeof featureName !==
|
|
912
|
-
throw new Error(
|
|
1067
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1068
|
+
throw new Error("Feature name is required for requirements generation");
|
|
913
1069
|
}
|
|
914
1070
|
// Load spec context
|
|
915
1071
|
const { spec, requirements } = await loadSpecContext(featureName);
|
|
@@ -917,7 +1073,7 @@ async function handleRequirementsSimplified(args) {
|
|
|
917
1073
|
throw new Error(`Feature "${featureName}" not found. Run sdd-init first.`);
|
|
918
1074
|
}
|
|
919
1075
|
// Extract project description from spec
|
|
920
|
-
let projectDescription =
|
|
1076
|
+
let projectDescription = "Feature requirements specification";
|
|
921
1077
|
if (requirements) {
|
|
922
1078
|
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
923
1079
|
if (descMatch) {
|
|
@@ -927,21 +1083,23 @@ async function handleRequirementsSimplified(args) {
|
|
|
927
1083
|
// Generate analysis-backed requirements with proper error handling
|
|
928
1084
|
let requirementsContent;
|
|
929
1085
|
let analysisUsed = false;
|
|
1086
|
+
// Check if fallback is allowed
|
|
1087
|
+
const allowFallback = process.env.SDD_ALLOW_TEMPLATE_FALLBACK === "true" ||
|
|
1088
|
+
args?.allowFallback === true;
|
|
930
1089
|
try {
|
|
931
|
-
console.error(
|
|
932
|
-
const { generateRequirementsDocument } = await
|
|
933
|
-
console.error(
|
|
1090
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive analysis...");
|
|
1091
|
+
const { generateRequirementsDocument } = await loadSpecGenerator();
|
|
1092
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating requirements...");
|
|
934
1093
|
requirementsContent = await generateRequirementsDocument(process.cwd(), featureName);
|
|
935
1094
|
analysisUsed = true;
|
|
936
|
-
console.error(
|
|
1095
|
+
console.error("[SDD-DEBUG] ✅ Requirements generated using comprehensive codebase analysis");
|
|
937
1096
|
}
|
|
938
1097
|
catch (genErr) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
console.error('[SDD-DEBUG] Stack:', genErr.stack);
|
|
1098
|
+
// Use shared error handler
|
|
1099
|
+
const { useFallback, error } = handleLoaderFailure("specGenerator", genErr, allowFallback);
|
|
942
1100
|
requirementsContent = `# Requirements Document
|
|
943
1101
|
|
|
944
|
-
<!-- Note: Using basic template due to analysis error: ${
|
|
1102
|
+
<!-- Note: Using basic template due to analysis error: ${error.message} -->
|
|
945
1103
|
|
|
946
1104
|
## Introduction
|
|
947
1105
|
${generateIntroductionFromDescription(projectDescription)}
|
|
@@ -952,7 +1110,9 @@ ${generateIntroductionFromDescription(projectDescription)}
|
|
|
952
1110
|
**Objective:** As a user, I want ${extractPrimaryObjective(projectDescription)}, so that ${extractPrimaryBenefit(projectDescription)}
|
|
953
1111
|
|
|
954
1112
|
#### Acceptance Criteria
|
|
955
|
-
${generateEARSRequirements(projectDescription)
|
|
1113
|
+
${generateEARSRequirements(projectDescription)
|
|
1114
|
+
.map((req, index) => `${index + 1}. ${req}`)
|
|
1115
|
+
.join("\n")}
|
|
956
1116
|
|
|
957
1117
|
### Requirement 2: System Quality
|
|
958
1118
|
**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 +1132,64 @@ ${generateEARSRequirements(projectDescription).map((req, index) => `${index + 1}
|
|
|
972
1132
|
`;
|
|
973
1133
|
}
|
|
974
1134
|
// Update spec.json with phase information
|
|
975
|
-
const specDir = path.join(process.cwd(),
|
|
1135
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
976
1136
|
const updatedSpec = {
|
|
977
1137
|
...spec,
|
|
978
|
-
phase:
|
|
1138
|
+
phase: "requirements-generated",
|
|
979
1139
|
approvals: {
|
|
980
1140
|
...spec.approvals,
|
|
981
1141
|
requirements: {
|
|
982
1142
|
generated: true,
|
|
983
|
-
approved: false
|
|
984
|
-
}
|
|
1143
|
+
approved: false,
|
|
1144
|
+
},
|
|
985
1145
|
},
|
|
986
|
-
updated_at: new Date().toISOString()
|
|
1146
|
+
updated_at: new Date().toISOString(),
|
|
987
1147
|
};
|
|
988
|
-
fs.writeFileSync(path.join(specDir,
|
|
989
|
-
fs.writeFileSync(path.join(specDir,
|
|
1148
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1149
|
+
fs.writeFileSync(path.join(specDir, "requirements.md"), requirementsContent);
|
|
990
1150
|
return {
|
|
991
|
-
content: [
|
|
992
|
-
|
|
1151
|
+
content: [
|
|
1152
|
+
{
|
|
1153
|
+
type: "text",
|
|
993
1154
|
text: `## Requirements Document Generated
|
|
994
1155
|
|
|
995
1156
|
**Feature**: \`${featureName}\`
|
|
996
1157
|
**File**: \`.kiro/specs/${featureName}/requirements.md\`
|
|
997
1158
|
|
|
998
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1159
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (multi-language support)" : "⚠️ Basic template (analysis failed)"}
|
|
999
1160
|
|
|
1000
1161
|
**Generated Requirements**:
|
|
1001
1162
|
- Core functionality requirements with EARS format
|
|
1002
1163
|
- System quality and reliability requirements
|
|
1003
1164
|
- Usability and user experience requirements
|
|
1004
1165
|
|
|
1005
|
-
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ?
|
|
1166
|
+
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? "..." : ""}"
|
|
1006
1167
|
|
|
1007
1168
|
**Workflow Phase**: Requirements Generated
|
|
1008
|
-
**Next Step**: Run \`sdd-design ${featureName}\` to create technical design (after requirements review)
|
|
1009
|
-
}
|
|
1169
|
+
**Next Step**: Run \`sdd-design ${featureName}\` to create technical design (after requirements review)`,
|
|
1170
|
+
},
|
|
1171
|
+
],
|
|
1010
1172
|
};
|
|
1011
1173
|
}
|
|
1012
1174
|
catch (error) {
|
|
1013
1175
|
return {
|
|
1014
|
-
content: [
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1176
|
+
content: [
|
|
1177
|
+
{
|
|
1178
|
+
type: "text",
|
|
1179
|
+
text: `Error generating requirements document: ${error.message}`,
|
|
1180
|
+
},
|
|
1181
|
+
],
|
|
1182
|
+
isError: true,
|
|
1019
1183
|
};
|
|
1020
1184
|
}
|
|
1021
1185
|
}
|
|
1022
1186
|
async function handleDesignSimplified(args) {
|
|
1023
|
-
const fs = await import(
|
|
1024
|
-
const path = await import(
|
|
1187
|
+
const fs = await import("fs");
|
|
1188
|
+
const path = await import("path");
|
|
1025
1189
|
try {
|
|
1026
1190
|
const { featureName } = args;
|
|
1027
|
-
if (!featureName || typeof featureName !==
|
|
1028
|
-
throw new Error(
|
|
1191
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1192
|
+
throw new Error("Feature name is required for design generation");
|
|
1029
1193
|
}
|
|
1030
1194
|
// Load spec context
|
|
1031
1195
|
const { spec, requirements } = await loadSpecContext(featureName);
|
|
@@ -1037,7 +1201,7 @@ async function handleDesignSimplified(args) {
|
|
|
1037
1201
|
throw new Error(`Requirements must be generated before design. Run sdd-requirements ${featureName} first.`);
|
|
1038
1202
|
}
|
|
1039
1203
|
// Extract project description from requirements
|
|
1040
|
-
let projectDescription =
|
|
1204
|
+
let projectDescription = "Technical design specification";
|
|
1041
1205
|
if (requirements) {
|
|
1042
1206
|
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
1043
1207
|
if (descMatch) {
|
|
@@ -1047,20 +1211,23 @@ async function handleDesignSimplified(args) {
|
|
|
1047
1211
|
// Generate analysis-backed design with proper error handling
|
|
1048
1212
|
let designContent;
|
|
1049
1213
|
let analysisUsed = false;
|
|
1214
|
+
// Check if fallback is allowed
|
|
1215
|
+
const allowFallback = process.env.SDD_ALLOW_TEMPLATE_FALLBACK === "true" ||
|
|
1216
|
+
args?.allowFallback === true;
|
|
1050
1217
|
try {
|
|
1051
|
-
console.error(
|
|
1052
|
-
const { generateDesignDocument } = await
|
|
1053
|
-
console.error(
|
|
1218
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive design analysis...");
|
|
1219
|
+
const { generateDesignDocument } = await loadSpecGenerator();
|
|
1220
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating design...");
|
|
1054
1221
|
designContent = await generateDesignDocument(process.cwd(), featureName);
|
|
1055
1222
|
analysisUsed = true;
|
|
1056
|
-
console.error(
|
|
1223
|
+
console.error("[SDD-DEBUG] ✅ Design generated using comprehensive codebase analysis");
|
|
1057
1224
|
}
|
|
1058
1225
|
catch (genErr) {
|
|
1059
|
-
|
|
1060
|
-
|
|
1226
|
+
// Use shared error handler
|
|
1227
|
+
const { useFallback, error } = handleLoaderFailure("specGenerator", genErr, allowFallback);
|
|
1061
1228
|
designContent = `# Technical Design Document
|
|
1062
1229
|
|
|
1063
|
-
<!-- Note: Using basic template due to analysis error: ${
|
|
1230
|
+
<!-- Note: Using basic template due to analysis error: ${error.message} -->
|
|
1064
1231
|
|
|
1065
1232
|
## Overview
|
|
1066
1233
|
This design document specifies the technical implementation approach for ${spec.feature_name}.
|
|
@@ -1075,30 +1242,31 @@ This design document specifies the technical implementation approach for ${spec.
|
|
|
1075
1242
|
`;
|
|
1076
1243
|
}
|
|
1077
1244
|
// Update spec.json with phase information
|
|
1078
|
-
const specDir = path.join(process.cwd(),
|
|
1245
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1079
1246
|
const updatedSpec = {
|
|
1080
1247
|
...spec,
|
|
1081
|
-
phase:
|
|
1248
|
+
phase: "design-generated",
|
|
1082
1249
|
approvals: {
|
|
1083
1250
|
...spec.approvals,
|
|
1084
1251
|
design: {
|
|
1085
1252
|
generated: true,
|
|
1086
|
-
approved: false
|
|
1087
|
-
}
|
|
1253
|
+
approved: false,
|
|
1254
|
+
},
|
|
1088
1255
|
},
|
|
1089
|
-
updated_at: new Date().toISOString()
|
|
1256
|
+
updated_at: new Date().toISOString(),
|
|
1090
1257
|
};
|
|
1091
|
-
fs.writeFileSync(path.join(specDir,
|
|
1092
|
-
fs.writeFileSync(path.join(specDir,
|
|
1258
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1259
|
+
fs.writeFileSync(path.join(specDir, "design.md"), designContent);
|
|
1093
1260
|
return {
|
|
1094
|
-
content: [
|
|
1095
|
-
|
|
1261
|
+
content: [
|
|
1262
|
+
{
|
|
1263
|
+
type: "text",
|
|
1096
1264
|
text: `## Design Document Generated
|
|
1097
1265
|
|
|
1098
1266
|
**Feature**: \`${featureName}\`
|
|
1099
1267
|
**File**: \`.kiro/specs/${featureName}/design.md\`
|
|
1100
1268
|
|
|
1101
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1269
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (architecture patterns detected)" : "⚠️ Basic template (analysis failed)"}
|
|
1102
1270
|
|
|
1103
1271
|
**Design Elements**:
|
|
1104
1272
|
- Modular architecture with clear component separation
|
|
@@ -1106,30 +1274,33 @@ This design document specifies the technical implementation approach for ${spec.
|
|
|
1106
1274
|
- Data models and error handling strategy
|
|
1107
1275
|
- Complete testing approach
|
|
1108
1276
|
|
|
1109
|
-
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ?
|
|
1277
|
+
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? "..." : ""}"
|
|
1110
1278
|
|
|
1111
1279
|
**Workflow Phase**: Design Generated
|
|
1112
|
-
**Next Step**: Run \`sdd-tasks ${featureName}\` to generate implementation tasks (after design review)
|
|
1113
|
-
}
|
|
1280
|
+
**Next Step**: Run \`sdd-tasks ${featureName}\` to generate implementation tasks (after design review)`,
|
|
1281
|
+
},
|
|
1282
|
+
],
|
|
1114
1283
|
};
|
|
1115
1284
|
}
|
|
1116
1285
|
catch (error) {
|
|
1117
1286
|
return {
|
|
1118
|
-
content: [
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1287
|
+
content: [
|
|
1288
|
+
{
|
|
1289
|
+
type: "text",
|
|
1290
|
+
text: `Error generating design document: ${error.message}`,
|
|
1291
|
+
},
|
|
1292
|
+
],
|
|
1293
|
+
isError: true,
|
|
1123
1294
|
};
|
|
1124
1295
|
}
|
|
1125
1296
|
}
|
|
1126
1297
|
async function handleTasksSimplified(args) {
|
|
1127
|
-
const fs = await import(
|
|
1128
|
-
const path = await import(
|
|
1298
|
+
const fs = await import("fs");
|
|
1299
|
+
const path = await import("path");
|
|
1129
1300
|
try {
|
|
1130
1301
|
const { featureName } = args;
|
|
1131
|
-
if (!featureName || typeof featureName !==
|
|
1132
|
-
throw new Error(
|
|
1302
|
+
if (!featureName || typeof featureName !== "string") {
|
|
1303
|
+
throw new Error("Feature name is required for tasks generation");
|
|
1133
1304
|
}
|
|
1134
1305
|
// Load spec context
|
|
1135
1306
|
const { spec } = await loadSpecContext(featureName);
|
|
@@ -1143,20 +1314,23 @@ async function handleTasksSimplified(args) {
|
|
|
1143
1314
|
// Generate analysis-backed tasks with proper error handling
|
|
1144
1315
|
let tasksContent;
|
|
1145
1316
|
let analysisUsed = false;
|
|
1317
|
+
// Check if fallback is allowed
|
|
1318
|
+
const allowFallback = process.env.SDD_ALLOW_TEMPLATE_FALLBACK === "true" ||
|
|
1319
|
+
args?.allowFallback === true;
|
|
1146
1320
|
try {
|
|
1147
|
-
console.error(
|
|
1148
|
-
const { generateTasksDocument } = await
|
|
1149
|
-
console.error(
|
|
1321
|
+
console.error("[SDD-DEBUG] Attempting to load specGenerator for comprehensive task analysis...");
|
|
1322
|
+
const { generateTasksDocument } = await loadSpecGenerator();
|
|
1323
|
+
console.error("[SDD-DEBUG] specGenerator imported successfully, generating tasks...");
|
|
1150
1324
|
tasksContent = await generateTasksDocument(process.cwd(), featureName);
|
|
1151
1325
|
analysisUsed = true;
|
|
1152
|
-
console.error(
|
|
1326
|
+
console.error("[SDD-DEBUG] ✅ Tasks generated using comprehensive codebase analysis");
|
|
1153
1327
|
}
|
|
1154
1328
|
catch (genErr) {
|
|
1155
|
-
|
|
1156
|
-
|
|
1329
|
+
// Use shared error handler
|
|
1330
|
+
const { useFallback, error } = handleLoaderFailure("specGenerator", genErr, allowFallback);
|
|
1157
1331
|
tasksContent = `# Implementation Plan
|
|
1158
1332
|
|
|
1159
|
-
<!-- Note: Using basic template due to analysis error: ${
|
|
1333
|
+
<!-- Note: Using basic template due to analysis error: ${error.message} -->
|
|
1160
1334
|
|
|
1161
1335
|
- [ ] 1. Set up project foundation and infrastructure
|
|
1162
1336
|
- [ ] 2. Implement core functionality
|
|
@@ -1166,31 +1340,32 @@ async function handleTasksSimplified(args) {
|
|
|
1166
1340
|
`;
|
|
1167
1341
|
}
|
|
1168
1342
|
// Update spec.json with phase information
|
|
1169
|
-
const specDir = path.join(process.cwd(),
|
|
1343
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1170
1344
|
const updatedSpec = {
|
|
1171
1345
|
...spec,
|
|
1172
|
-
phase:
|
|
1346
|
+
phase: "tasks-generated",
|
|
1173
1347
|
approvals: {
|
|
1174
1348
|
...spec.approvals,
|
|
1175
1349
|
tasks: {
|
|
1176
1350
|
generated: true,
|
|
1177
|
-
approved: false
|
|
1178
|
-
}
|
|
1351
|
+
approved: false,
|
|
1352
|
+
},
|
|
1179
1353
|
},
|
|
1180
1354
|
ready_for_implementation: true,
|
|
1181
|
-
updated_at: new Date().toISOString()
|
|
1355
|
+
updated_at: new Date().toISOString(),
|
|
1182
1356
|
};
|
|
1183
|
-
fs.writeFileSync(path.join(specDir,
|
|
1184
|
-
fs.writeFileSync(path.join(specDir,
|
|
1357
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(updatedSpec, null, 2));
|
|
1358
|
+
fs.writeFileSync(path.join(specDir, "tasks.md"), tasksContent);
|
|
1185
1359
|
return {
|
|
1186
|
-
content: [
|
|
1187
|
-
|
|
1360
|
+
content: [
|
|
1361
|
+
{
|
|
1362
|
+
type: "text",
|
|
1188
1363
|
text: `## Implementation Tasks Generated
|
|
1189
1364
|
|
|
1190
1365
|
**Feature**: \`${featureName}\`
|
|
1191
1366
|
**File**: \`.kiro/specs/${featureName}/tasks.md\`
|
|
1192
1367
|
|
|
1193
|
-
**Analysis Method**: ${analysisUsed ?
|
|
1368
|
+
**Analysis Method**: ${analysisUsed ? "✅ Comprehensive codebase analysis (tech stack-aware tasks)" : "⚠️ Basic template (analysis failed)"}
|
|
1194
1369
|
|
|
1195
1370
|
**Generated Tasks**:
|
|
1196
1371
|
- Development, integration, quality, and deployment phases
|
|
@@ -1200,31 +1375,42 @@ async function handleTasksSimplified(args) {
|
|
|
1200
1375
|
|
|
1201
1376
|
**Workflow Phase**: Tasks Generated
|
|
1202
1377
|
**Status**: Ready for Implementation
|
|
1203
|
-
**Next Step**: Begin implementation following the task sequence
|
|
1204
|
-
}
|
|
1378
|
+
**Next Step**: Begin implementation following the task sequence`,
|
|
1379
|
+
},
|
|
1380
|
+
],
|
|
1205
1381
|
};
|
|
1206
1382
|
}
|
|
1207
1383
|
catch (error) {
|
|
1208
1384
|
return {
|
|
1209
|
-
content: [
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1385
|
+
content: [
|
|
1386
|
+
{
|
|
1387
|
+
type: "text",
|
|
1388
|
+
text: `Error generating tasks document: ${error.message}`,
|
|
1389
|
+
},
|
|
1390
|
+
],
|
|
1391
|
+
isError: true,
|
|
1214
1392
|
};
|
|
1215
1393
|
}
|
|
1216
1394
|
}
|
|
1217
1395
|
// Helper functions for simplified tool implementations
|
|
1218
1396
|
function analyzeProjectStructureSync(projectPath) {
|
|
1219
|
-
const fs = require(
|
|
1397
|
+
const fs = require("fs");
|
|
1220
1398
|
try {
|
|
1221
1399
|
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
1222
1400
|
return {
|
|
1223
|
-
directories: items
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1401
|
+
directories: items
|
|
1402
|
+
.filter((item) => item.isDirectory() &&
|
|
1403
|
+
!item.name.startsWith(".") &&
|
|
1404
|
+
item.name !== "node_modules")
|
|
1405
|
+
.map((item) => item.name),
|
|
1406
|
+
files: items
|
|
1407
|
+
.filter((item) => item.isFile())
|
|
1408
|
+
.map((item) => item.name),
|
|
1409
|
+
hasSource: items.some((item) => item.isDirectory() && item.name === "src"),
|
|
1410
|
+
hasTests: items.some((item) => item.isDirectory() &&
|
|
1411
|
+
(item.name === "test" || item.name === "__tests__")),
|
|
1412
|
+
hasDocs: items.some((item) => item.isDirectory() &&
|
|
1413
|
+
(item.name === "docs" || item.name === "documentation")),
|
|
1228
1414
|
};
|
|
1229
1415
|
}
|
|
1230
1416
|
catch (error) {
|
|
@@ -1236,149 +1422,180 @@ function generateCoreObjectiveSimplified(packageJson, projectAnalysis) {
|
|
|
1236
1422
|
return `Deliver ${packageJson.description} with full functionality and reliability`;
|
|
1237
1423
|
}
|
|
1238
1424
|
if (packageJson.keywords?.length > 0) {
|
|
1239
|
-
return `Implement ${packageJson.keywords.join(
|
|
1425
|
+
return `Implement ${packageJson.keywords.join(", ")} functionality`;
|
|
1240
1426
|
}
|
|
1241
|
-
return
|
|
1427
|
+
return "Deliver core application functionality";
|
|
1242
1428
|
}
|
|
1243
1429
|
function generateAcceptanceCriteriaSimplified(packageJson, projectAnalysis) {
|
|
1244
1430
|
const criteria = [];
|
|
1245
1431
|
if (packageJson.scripts?.test) {
|
|
1246
|
-
criteria.push(
|
|
1432
|
+
criteria.push("WHEN tests are run THEN all tests SHALL pass");
|
|
1247
1433
|
}
|
|
1248
1434
|
if (packageJson.scripts?.build) {
|
|
1249
|
-
criteria.push(
|
|
1435
|
+
criteria.push("WHEN build is executed THEN system SHALL compile without errors");
|
|
1250
1436
|
}
|
|
1251
1437
|
if (packageJson.scripts?.lint) {
|
|
1252
|
-
criteria.push(
|
|
1438
|
+
criteria.push("WHERE code quality is checked THE system SHALL meet linting standards");
|
|
1253
1439
|
}
|
|
1254
1440
|
if (packageJson.main || packageJson.bin) {
|
|
1255
|
-
criteria.push(
|
|
1441
|
+
criteria.push("WHEN application starts THEN system SHALL initialize successfully");
|
|
1256
1442
|
}
|
|
1257
|
-
criteria.push(
|
|
1258
|
-
return criteria.length > 0
|
|
1443
|
+
criteria.push("IF errors occur THEN system SHALL handle them gracefully");
|
|
1444
|
+
return criteria.length > 0
|
|
1445
|
+
? criteria
|
|
1446
|
+
: ["System SHALL meet functional requirements"];
|
|
1259
1447
|
}
|
|
1260
1448
|
function generateTechRequirementsSimplified(packageJson) {
|
|
1261
1449
|
const requirements = [];
|
|
1262
1450
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
1263
1451
|
if (deps?.typescript) {
|
|
1264
|
-
requirements.push(
|
|
1452
|
+
requirements.push("System SHALL use TypeScript for type safety");
|
|
1265
1453
|
}
|
|
1266
1454
|
if (deps?.express || deps?.fastify) {
|
|
1267
|
-
requirements.push(
|
|
1455
|
+
requirements.push("System SHALL implement RESTful API endpoints");
|
|
1268
1456
|
}
|
|
1269
1457
|
if (deps?.react || deps?.vue || deps?.angular) {
|
|
1270
|
-
requirements.push(
|
|
1458
|
+
requirements.push("System SHALL provide responsive user interface");
|
|
1271
1459
|
}
|
|
1272
1460
|
if (deps?.jest || deps?.mocha || deps?.vitest) {
|
|
1273
|
-
requirements.push(
|
|
1461
|
+
requirements.push("System SHALL include comprehensive test coverage");
|
|
1274
1462
|
}
|
|
1275
|
-
return requirements.length > 0
|
|
1463
|
+
return requirements.length > 0
|
|
1464
|
+
? requirements
|
|
1465
|
+
: ["System SHALL integrate required technologies"];
|
|
1276
1466
|
}
|
|
1277
1467
|
function generateQualityRequirementsSimplified(packageJson) {
|
|
1278
1468
|
const requirements = [];
|
|
1279
1469
|
if (packageJson.scripts?.lint) {
|
|
1280
|
-
requirements.push(
|
|
1470
|
+
requirements.push("Code SHALL pass linting checks");
|
|
1281
1471
|
}
|
|
1282
1472
|
if (packageJson.scripts?.typecheck) {
|
|
1283
|
-
requirements.push(
|
|
1473
|
+
requirements.push("Code SHALL pass type checking");
|
|
1284
1474
|
}
|
|
1285
1475
|
if (packageJson.scripts?.test) {
|
|
1286
|
-
requirements.push(
|
|
1476
|
+
requirements.push("Code SHALL maintain test coverage standards");
|
|
1287
1477
|
}
|
|
1288
|
-
requirements.push(
|
|
1478
|
+
requirements.push("Code SHALL follow established conventions");
|
|
1289
1479
|
return requirements;
|
|
1290
1480
|
}
|
|
1291
1481
|
function generateArchitectureDescriptionSimplified(packageJson, projectAnalysis) {
|
|
1292
|
-
let description =
|
|
1293
|
-
if (packageJson.type ===
|
|
1294
|
-
description +=
|
|
1482
|
+
let description = "";
|
|
1483
|
+
if (packageJson.type === "module") {
|
|
1484
|
+
description += "Modern ES Module-based architecture. ";
|
|
1295
1485
|
}
|
|
1296
1486
|
if (projectAnalysis.hasSource) {
|
|
1297
|
-
description +=
|
|
1487
|
+
description +=
|
|
1488
|
+
"Modular source code organization with clear separation of concerns. ";
|
|
1298
1489
|
}
|
|
1299
1490
|
if (packageJson.dependencies?.express) {
|
|
1300
|
-
description +=
|
|
1491
|
+
description +=
|
|
1492
|
+
"RESTful API server architecture using Express.js framework. ";
|
|
1301
1493
|
}
|
|
1302
|
-
if (packageJson.dependencies?.typescript ||
|
|
1303
|
-
|
|
1494
|
+
if (packageJson.dependencies?.typescript ||
|
|
1495
|
+
packageJson.devDependencies?.typescript) {
|
|
1496
|
+
description += "Type-safe development with TypeScript compilation. ";
|
|
1304
1497
|
}
|
|
1305
|
-
return description ||
|
|
1498
|
+
return (description ||
|
|
1499
|
+
"Application architecture to be defined based on requirements.");
|
|
1306
1500
|
}
|
|
1307
1501
|
function generateComponentDescriptionsSimplified(projectAnalysis) {
|
|
1308
1502
|
const components = [];
|
|
1309
1503
|
if (projectAnalysis.hasSource) {
|
|
1310
|
-
components.push({
|
|
1504
|
+
components.push({
|
|
1505
|
+
name: "Core Module",
|
|
1506
|
+
description: "Main application logic and business rules",
|
|
1507
|
+
});
|
|
1311
1508
|
}
|
|
1312
1509
|
if (projectAnalysis.hasTests) {
|
|
1313
|
-
components.push({
|
|
1510
|
+
components.push({
|
|
1511
|
+
name: "Test Suite",
|
|
1512
|
+
description: "Automated testing framework and test cases",
|
|
1513
|
+
});
|
|
1314
1514
|
}
|
|
1315
1515
|
if (projectAnalysis.hasDocs) {
|
|
1316
|
-
components.push({
|
|
1516
|
+
components.push({
|
|
1517
|
+
name: "Documentation",
|
|
1518
|
+
description: "Project documentation and API specifications",
|
|
1519
|
+
});
|
|
1317
1520
|
}
|
|
1318
|
-
return components.length > 0
|
|
1319
|
-
|
|
1320
|
-
|
|
1521
|
+
return components.length > 0
|
|
1522
|
+
? components
|
|
1523
|
+
: [
|
|
1524
|
+
{
|
|
1525
|
+
name: "Application Core",
|
|
1526
|
+
description: "Main application functionality",
|
|
1527
|
+
},
|
|
1528
|
+
];
|
|
1321
1529
|
}
|
|
1322
1530
|
function generateDataModelsSimplified(packageJson, projectAnalysis) {
|
|
1323
1531
|
const models = [];
|
|
1324
1532
|
if (packageJson.dependencies?.mongoose || packageJson.dependencies?.mongodb) {
|
|
1325
|
-
models.push(
|
|
1533
|
+
models.push("MongoDB Document Models");
|
|
1326
1534
|
}
|
|
1327
|
-
if (packageJson.dependencies?.sequelize ||
|
|
1328
|
-
|
|
1535
|
+
if (packageJson.dependencies?.sequelize ||
|
|
1536
|
+
packageJson.dependencies?.typeorm) {
|
|
1537
|
+
models.push("Relational Database Models");
|
|
1329
1538
|
}
|
|
1330
1539
|
if (packageJson.dependencies?.graphql) {
|
|
1331
|
-
models.push(
|
|
1540
|
+
models.push("GraphQL Schema Models");
|
|
1332
1541
|
}
|
|
1333
|
-
return models.length > 0 ? models : [
|
|
1542
|
+
return models.length > 0 ? models : ["Application Data Models"];
|
|
1334
1543
|
}
|
|
1335
1544
|
function generateDetailedTechStackSimplified(packageJson) {
|
|
1336
1545
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
1337
1546
|
const stack = [];
|
|
1338
1547
|
if (deps?.typescript)
|
|
1339
|
-
stack.push(
|
|
1548
|
+
stack.push("- **TypeScript**: Type-safe JavaScript development");
|
|
1340
1549
|
if (deps?.node || packageJson.engines?.node)
|
|
1341
|
-
stack.push(`- **Node.js**: ${packageJson.engines?.node ||
|
|
1550
|
+
stack.push(`- **Node.js**: ${packageJson.engines?.node || "Runtime environment"}`);
|
|
1342
1551
|
if (deps?.express)
|
|
1343
|
-
stack.push(
|
|
1552
|
+
stack.push("- **Express.js**: Web application framework");
|
|
1344
1553
|
if (deps?.react)
|
|
1345
|
-
stack.push(
|
|
1554
|
+
stack.push("- **React**: User interface library");
|
|
1346
1555
|
if (deps?.vue)
|
|
1347
|
-
stack.push(
|
|
1556
|
+
stack.push("- **Vue.js**: Progressive frontend framework");
|
|
1348
1557
|
if (deps?.jest)
|
|
1349
|
-
stack.push(
|
|
1350
|
-
return stack.length > 0
|
|
1558
|
+
stack.push("- **Jest**: Testing framework");
|
|
1559
|
+
return stack.length > 0
|
|
1560
|
+
? stack.join("\n")
|
|
1561
|
+
: "- Technology stack to be defined";
|
|
1351
1562
|
}
|
|
1352
1563
|
function generateDesignPatternsSimplified(packageJson, projectAnalysis) {
|
|
1353
1564
|
const patterns = [];
|
|
1354
1565
|
if (packageJson.dependencies?.inversify) {
|
|
1355
|
-
patterns.push(
|
|
1566
|
+
patterns.push("Dependency Injection");
|
|
1356
1567
|
}
|
|
1357
1568
|
if (projectAnalysis.hasSource) {
|
|
1358
|
-
patterns.push(
|
|
1569
|
+
patterns.push("Modular Architecture");
|
|
1359
1570
|
}
|
|
1360
1571
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1361
|
-
patterns.push(
|
|
1572
|
+
patterns.push("MVC Pattern");
|
|
1362
1573
|
}
|
|
1363
|
-
return patterns.length > 0 ? patterns : [
|
|
1574
|
+
return patterns.length > 0 ? patterns : ["Standard Design Patterns"];
|
|
1364
1575
|
}
|
|
1365
1576
|
function generateDependencyAnalysisSimplified(packageJson) {
|
|
1366
1577
|
const production = Object.keys(packageJson.dependencies || {});
|
|
1367
1578
|
const development = Object.keys(packageJson.devDependencies || {});
|
|
1368
|
-
let analysis =
|
|
1579
|
+
let analysis = "";
|
|
1369
1580
|
if (production.length > 0) {
|
|
1370
1581
|
analysis += `**Production Dependencies:** ${production.length} packages\n`;
|
|
1371
|
-
analysis += production
|
|
1582
|
+
analysis += production
|
|
1583
|
+
.slice(0, 5)
|
|
1584
|
+
.map((dep) => `- ${dep}`)
|
|
1585
|
+
.join("\n");
|
|
1372
1586
|
if (production.length > 5)
|
|
1373
1587
|
analysis += `\n- ... and ${production.length - 5} more`;
|
|
1374
1588
|
}
|
|
1375
1589
|
if (development.length > 0) {
|
|
1376
1590
|
analysis += `\n\n**Development Dependencies:** ${development.length} packages\n`;
|
|
1377
|
-
analysis += development
|
|
1591
|
+
analysis += development
|
|
1592
|
+
.slice(0, 5)
|
|
1593
|
+
.map((dep) => `- ${dep}`)
|
|
1594
|
+
.join("\n");
|
|
1378
1595
|
if (development.length > 5)
|
|
1379
1596
|
analysis += `\n- ... and ${development.length - 5} more`;
|
|
1380
1597
|
}
|
|
1381
|
-
return analysis ||
|
|
1598
|
+
return analysis || "Dependencies to be analyzed";
|
|
1382
1599
|
}
|
|
1383
1600
|
function generateAPIInterfacesSimplified(packageJson, projectAnalysis) {
|
|
1384
1601
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
@@ -1388,7 +1605,7 @@ function generateAPIInterfacesSimplified(packageJson, projectAnalysis) {
|
|
|
1388
1605
|
- Request/response validation
|
|
1389
1606
|
- Error handling middleware`;
|
|
1390
1607
|
}
|
|
1391
|
-
return
|
|
1608
|
+
return "Interface specifications to be defined";
|
|
1392
1609
|
}
|
|
1393
1610
|
function generateModuleInterfacesSimplified(projectAnalysis) {
|
|
1394
1611
|
if (projectAnalysis.hasSource) {
|
|
@@ -1397,87 +1614,115 @@ function generateModuleInterfacesSimplified(projectAnalysis) {
|
|
|
1397
1614
|
- Consistent API patterns across modules
|
|
1398
1615
|
- Type definitions for all public interfaces`;
|
|
1399
1616
|
}
|
|
1400
|
-
return
|
|
1617
|
+
return "Module interfaces to be defined";
|
|
1401
1618
|
}
|
|
1402
1619
|
function generateEnvVarSpecsSimplified(packageJson) {
|
|
1403
1620
|
const envVars = [];
|
|
1404
1621
|
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1405
|
-
envVars.push(
|
|
1406
|
-
envVars.push(
|
|
1622
|
+
envVars.push("- `PORT`: Server port (default: 3000)");
|
|
1623
|
+
envVars.push("- `NODE_ENV`: Environment mode (development/production)");
|
|
1407
1624
|
}
|
|
1408
|
-
envVars.push(
|
|
1409
|
-
return envVars.join(
|
|
1625
|
+
envVars.push("- `LOG_LEVEL`: Logging level (debug/info/warn/error)");
|
|
1626
|
+
return envVars.join("\n");
|
|
1410
1627
|
}
|
|
1411
1628
|
function generateBuildConfigSimplified(packageJson) {
|
|
1412
|
-
let config =
|
|
1629
|
+
let config = "";
|
|
1413
1630
|
if (packageJson.scripts?.build) {
|
|
1414
1631
|
config += `Build process: \`${packageJson.scripts.build}\`\n`;
|
|
1415
1632
|
}
|
|
1416
1633
|
if (packageJson.scripts?.start) {
|
|
1417
1634
|
config += `Start command: \`${packageJson.scripts.start}\`\n`;
|
|
1418
1635
|
}
|
|
1419
|
-
if (packageJson.type ===
|
|
1420
|
-
config +=
|
|
1636
|
+
if (packageJson.type === "module") {
|
|
1637
|
+
config += "Module type: ES Modules\n";
|
|
1421
1638
|
}
|
|
1422
|
-
return config ||
|
|
1639
|
+
return config || "Build configuration to be defined";
|
|
1423
1640
|
}
|
|
1424
1641
|
function generateImplementationTasksSimplified(packageJson, projectAnalysis) {
|
|
1425
1642
|
const tasks = {
|
|
1426
1643
|
development: [],
|
|
1427
1644
|
integration: [],
|
|
1428
1645
|
quality: [],
|
|
1429
|
-
deployment: []
|
|
1646
|
+
deployment: [],
|
|
1430
1647
|
};
|
|
1431
1648
|
// Development tasks
|
|
1432
1649
|
if (projectAnalysis.hasSource) {
|
|
1433
1650
|
tasks.development.push({
|
|
1434
|
-
title:
|
|
1435
|
-
subtasks: [
|
|
1436
|
-
|
|
1651
|
+
title: "Implement Core Modules",
|
|
1652
|
+
subtasks: [
|
|
1653
|
+
"Set up module structure",
|
|
1654
|
+
"Implement business logic",
|
|
1655
|
+
"Add error handling",
|
|
1656
|
+
],
|
|
1657
|
+
requirements: "FR-1, FR-2",
|
|
1437
1658
|
});
|
|
1438
1659
|
}
|
|
1439
1660
|
if (packageJson.dependencies?.express) {
|
|
1440
1661
|
tasks.development.push({
|
|
1441
|
-
title:
|
|
1442
|
-
subtasks: [
|
|
1443
|
-
|
|
1662
|
+
title: "Develop API Endpoints",
|
|
1663
|
+
subtasks: [
|
|
1664
|
+
"Create route handlers",
|
|
1665
|
+
"Add middleware",
|
|
1666
|
+
"Implement validation",
|
|
1667
|
+
],
|
|
1668
|
+
requirements: "FR-2",
|
|
1444
1669
|
});
|
|
1445
1670
|
}
|
|
1446
1671
|
// Integration tasks
|
|
1447
1672
|
if (packageJson.dependencies?.mongodb || packageJson.dependencies?.mongoose) {
|
|
1448
1673
|
tasks.integration.push({
|
|
1449
|
-
title:
|
|
1450
|
-
subtasks: [
|
|
1451
|
-
|
|
1674
|
+
title: "Database Integration",
|
|
1675
|
+
subtasks: [
|
|
1676
|
+
"Set up database connection",
|
|
1677
|
+
"Create data models",
|
|
1678
|
+
"Implement queries",
|
|
1679
|
+
],
|
|
1680
|
+
requirements: "NFR-2",
|
|
1452
1681
|
});
|
|
1453
1682
|
}
|
|
1454
1683
|
// Quality tasks
|
|
1455
1684
|
if (packageJson.scripts?.test) {
|
|
1456
1685
|
tasks.quality.push({
|
|
1457
|
-
title:
|
|
1458
|
-
subtasks: [
|
|
1459
|
-
|
|
1686
|
+
title: "Test Implementation",
|
|
1687
|
+
subtasks: [
|
|
1688
|
+
"Write unit tests",
|
|
1689
|
+
"Add integration tests",
|
|
1690
|
+
"Ensure test coverage",
|
|
1691
|
+
],
|
|
1692
|
+
requirements: "FR-3, NFR-3",
|
|
1460
1693
|
});
|
|
1461
1694
|
}
|
|
1462
1695
|
if (packageJson.scripts?.lint) {
|
|
1463
1696
|
tasks.quality.push({
|
|
1464
|
-
title:
|
|
1465
|
-
subtasks: [
|
|
1466
|
-
|
|
1697
|
+
title: "Code Quality Assurance",
|
|
1698
|
+
subtasks: [
|
|
1699
|
+
"Run linting checks",
|
|
1700
|
+
"Fix code style issues",
|
|
1701
|
+
"Add documentation",
|
|
1702
|
+
],
|
|
1703
|
+
requirements: "NFR-3",
|
|
1467
1704
|
});
|
|
1468
1705
|
}
|
|
1469
1706
|
// Deployment tasks
|
|
1470
1707
|
if (packageJson.scripts?.build) {
|
|
1471
1708
|
tasks.deployment.push({
|
|
1472
|
-
title:
|
|
1473
|
-
subtasks: [
|
|
1474
|
-
|
|
1709
|
+
title: "Build and Package",
|
|
1710
|
+
subtasks: [
|
|
1711
|
+
"Run build process",
|
|
1712
|
+
"Optimize for production",
|
|
1713
|
+
"Create deployment artifacts",
|
|
1714
|
+
],
|
|
1715
|
+
requirements: "NFR-1",
|
|
1475
1716
|
});
|
|
1476
1717
|
}
|
|
1477
1718
|
tasks.deployment.push({
|
|
1478
|
-
title:
|
|
1479
|
-
subtasks: [
|
|
1480
|
-
|
|
1719
|
+
title: "Deployment Configuration",
|
|
1720
|
+
subtasks: [
|
|
1721
|
+
"Set up environment variables",
|
|
1722
|
+
"Configure production settings",
|
|
1723
|
+
"Deploy to target environment",
|
|
1724
|
+
],
|
|
1725
|
+
requirements: "NFR-1, NFR-2",
|
|
1481
1726
|
});
|
|
1482
1727
|
return tasks;
|
|
1483
1728
|
}
|
|
@@ -1488,45 +1733,49 @@ function generateIntroductionFromDescription(description) {
|
|
|
1488
1733
|
}
|
|
1489
1734
|
function extractSystemName(description) {
|
|
1490
1735
|
// Extract a system name from description
|
|
1491
|
-
const words = description.split(
|
|
1736
|
+
const words = description.split(" ");
|
|
1492
1737
|
if (words.length >= 2) {
|
|
1493
|
-
return `the ${words.slice(0, 3).join(
|
|
1738
|
+
return `the ${words.slice(0, 3).join(" ")}`;
|
|
1494
1739
|
}
|
|
1495
|
-
return
|
|
1740
|
+
return "the system";
|
|
1496
1741
|
}
|
|
1497
1742
|
function extractPrimaryObjective(description) {
|
|
1498
1743
|
// Convert description into user objective
|
|
1499
|
-
if (description.toLowerCase().includes(
|
|
1744
|
+
if (description.toLowerCase().includes("tool") ||
|
|
1745
|
+
description.toLowerCase().includes("cli")) {
|
|
1500
1746
|
return `use a tool that ${description.toLowerCase()}`;
|
|
1501
1747
|
}
|
|
1502
|
-
if (description.toLowerCase().includes(
|
|
1748
|
+
if (description.toLowerCase().includes("system") ||
|
|
1749
|
+
description.toLowerCase().includes("application")) {
|
|
1503
1750
|
return `access a system that ${description.toLowerCase()}`;
|
|
1504
1751
|
}
|
|
1505
1752
|
return `have functionality that ${description.toLowerCase()}`;
|
|
1506
1753
|
}
|
|
1507
1754
|
function extractPrimaryBenefit(description) {
|
|
1508
1755
|
// Infer benefit from description
|
|
1509
|
-
if (description.toLowerCase().includes(
|
|
1510
|
-
return
|
|
1756
|
+
if (description.toLowerCase().includes("automate")) {
|
|
1757
|
+
return "I can save time and reduce manual effort";
|
|
1511
1758
|
}
|
|
1512
|
-
if (description.toLowerCase().includes(
|
|
1513
|
-
|
|
1759
|
+
if (description.toLowerCase().includes("analyze") ||
|
|
1760
|
+
description.toLowerCase().includes("review")) {
|
|
1761
|
+
return "I can make better informed decisions";
|
|
1514
1762
|
}
|
|
1515
|
-
if (description.toLowerCase().includes(
|
|
1516
|
-
|
|
1763
|
+
if (description.toLowerCase().includes("manage") ||
|
|
1764
|
+
description.toLowerCase().includes("organize")) {
|
|
1765
|
+
return "I can maintain better control and organization";
|
|
1517
1766
|
}
|
|
1518
|
-
return
|
|
1767
|
+
return "I can accomplish my goals more effectively";
|
|
1519
1768
|
}
|
|
1520
1769
|
function generateEARSRequirements(description) {
|
|
1521
1770
|
const requirements = [];
|
|
1522
1771
|
// Core functional requirement
|
|
1523
1772
|
requirements.push(`WHEN I use the system THEN it SHALL provide ${description.toLowerCase()} functionality`);
|
|
1524
1773
|
// Input/output handling
|
|
1525
|
-
requirements.push(
|
|
1774
|
+
requirements.push("WHEN I provide input THEN the system SHALL validate and process it correctly");
|
|
1526
1775
|
// Error handling
|
|
1527
|
-
requirements.push(
|
|
1776
|
+
requirements.push("IF invalid input is provided THEN the system SHALL reject it with clear error messages");
|
|
1528
1777
|
// Success condition
|
|
1529
|
-
requirements.push(
|
|
1778
|
+
requirements.push("WHEN all inputs are valid THEN the system SHALL complete the requested operation successfully");
|
|
1530
1779
|
return requirements;
|
|
1531
1780
|
}
|
|
1532
1781
|
// Helper functions for kiro-style workflow
|
|
@@ -1534,18 +1783,18 @@ function generateFeatureName(description) {
|
|
|
1534
1783
|
// Extract feature name from description - similar to kiro spec-init
|
|
1535
1784
|
const cleaned = description
|
|
1536
1785
|
.toLowerCase()
|
|
1537
|
-
.replace(/[^a-z0-9\s]/g,
|
|
1786
|
+
.replace(/[^a-z0-9\s]/g, "")
|
|
1538
1787
|
.trim()
|
|
1539
1788
|
.split(/\s+/)
|
|
1540
1789
|
.slice(0, 4) // Take first 4 words
|
|
1541
|
-
.join(
|
|
1790
|
+
.join("-");
|
|
1542
1791
|
// Ensure it's not empty
|
|
1543
|
-
return cleaned ||
|
|
1792
|
+
return cleaned || "new-feature";
|
|
1544
1793
|
}
|
|
1545
1794
|
async function ensureUniqueFeatureName(baseName) {
|
|
1546
|
-
const fs = await import(
|
|
1547
|
-
const path = await import(
|
|
1548
|
-
const specsDir = path.join(process.cwd(),
|
|
1795
|
+
const fs = await import("fs");
|
|
1796
|
+
const path = await import("path");
|
|
1797
|
+
const specsDir = path.join(process.cwd(), ".kiro", "specs");
|
|
1549
1798
|
if (!fs.existsSync(specsDir)) {
|
|
1550
1799
|
return baseName;
|
|
1551
1800
|
}
|
|
@@ -1558,16 +1807,16 @@ async function ensureUniqueFeatureName(baseName) {
|
|
|
1558
1807
|
return featureName;
|
|
1559
1808
|
}
|
|
1560
1809
|
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,
|
|
1810
|
+
const fs = await import("fs");
|
|
1811
|
+
const path = await import("path");
|
|
1812
|
+
const specDir = path.join(process.cwd(), ".kiro", "specs", featureName);
|
|
1813
|
+
const specJsonPath = path.join(specDir, "spec.json");
|
|
1814
|
+
const requirementsPath = path.join(specDir, "requirements.md");
|
|
1566
1815
|
let spec = null;
|
|
1567
1816
|
let requirements = null;
|
|
1568
1817
|
try {
|
|
1569
1818
|
if (fs.existsSync(specJsonPath)) {
|
|
1570
|
-
const specContent = fs.readFileSync(specJsonPath,
|
|
1819
|
+
const specContent = fs.readFileSync(specJsonPath, "utf8");
|
|
1571
1820
|
spec = JSON.parse(specContent);
|
|
1572
1821
|
}
|
|
1573
1822
|
}
|
|
@@ -1576,7 +1825,7 @@ async function loadSpecContext(featureName) {
|
|
|
1576
1825
|
}
|
|
1577
1826
|
try {
|
|
1578
1827
|
if (fs.existsSync(requirementsPath)) {
|
|
1579
|
-
requirements = fs.readFileSync(requirementsPath,
|
|
1828
|
+
requirements = fs.readFileSync(requirementsPath, "utf8");
|
|
1580
1829
|
}
|
|
1581
1830
|
}
|
|
1582
1831
|
catch (error) {
|
|
@@ -1585,19 +1834,19 @@ async function loadSpecContext(featureName) {
|
|
|
1585
1834
|
return { spec, requirements };
|
|
1586
1835
|
}
|
|
1587
1836
|
async function handleInitSimplified(args) {
|
|
1588
|
-
const fs = await import(
|
|
1589
|
-
const path = await import(
|
|
1837
|
+
const fs = await import("fs");
|
|
1838
|
+
const path = await import("path");
|
|
1590
1839
|
try {
|
|
1591
1840
|
const { description } = args;
|
|
1592
|
-
if (!description || typeof description !==
|
|
1593
|
-
throw new Error(
|
|
1841
|
+
if (!description || typeof description !== "string") {
|
|
1842
|
+
throw new Error("Description is required for project initialization");
|
|
1594
1843
|
}
|
|
1595
1844
|
const projectPath = process.cwd();
|
|
1596
1845
|
// Generate feature name from description
|
|
1597
1846
|
const baseFeatureName = generateFeatureName(description);
|
|
1598
1847
|
const featureName = await ensureUniqueFeatureName(baseFeatureName);
|
|
1599
1848
|
// Create .kiro/specs/[feature-name] directory
|
|
1600
|
-
const specDir = path.join(projectPath,
|
|
1849
|
+
const specDir = path.join(projectPath, ".kiro", "specs", featureName);
|
|
1601
1850
|
if (!fs.existsSync(specDir)) {
|
|
1602
1851
|
fs.mkdirSync(specDir, { recursive: true });
|
|
1603
1852
|
}
|
|
@@ -1606,25 +1855,25 @@ async function handleInitSimplified(args) {
|
|
|
1606
1855
|
feature_name: featureName,
|
|
1607
1856
|
created_at: new Date().toISOString(),
|
|
1608
1857
|
updated_at: new Date().toISOString(),
|
|
1609
|
-
language:
|
|
1610
|
-
phase:
|
|
1858
|
+
language: "en",
|
|
1859
|
+
phase: "initialized",
|
|
1611
1860
|
approvals: {
|
|
1612
1861
|
requirements: {
|
|
1613
1862
|
generated: false,
|
|
1614
|
-
approved: false
|
|
1863
|
+
approved: false,
|
|
1615
1864
|
},
|
|
1616
1865
|
design: {
|
|
1617
1866
|
generated: false,
|
|
1618
|
-
approved: false
|
|
1867
|
+
approved: false,
|
|
1619
1868
|
},
|
|
1620
1869
|
tasks: {
|
|
1621
1870
|
generated: false,
|
|
1622
|
-
approved: false
|
|
1623
|
-
}
|
|
1871
|
+
approved: false,
|
|
1872
|
+
},
|
|
1624
1873
|
},
|
|
1625
|
-
ready_for_implementation: false
|
|
1874
|
+
ready_for_implementation: false,
|
|
1626
1875
|
};
|
|
1627
|
-
fs.writeFileSync(path.join(specDir,
|
|
1876
|
+
fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(specContent, null, 2));
|
|
1628
1877
|
// Create requirements.md template with project description
|
|
1629
1878
|
const requirementsTemplate = `# Requirements Document
|
|
1630
1879
|
|
|
@@ -1634,20 +1883,20 @@ ${description}
|
|
|
1634
1883
|
## Requirements
|
|
1635
1884
|
<!-- Will be generated in sdd-requirements phase -->
|
|
1636
1885
|
`;
|
|
1637
|
-
fs.writeFileSync(path.join(specDir,
|
|
1886
|
+
fs.writeFileSync(path.join(specDir, "requirements.md"), requirementsTemplate);
|
|
1638
1887
|
// Ensure AGENTS.md exists (static, derived from CLAUDE.md when available)
|
|
1639
|
-
const agentsPath = path.join(process.cwd(),
|
|
1888
|
+
const agentsPath = path.join(process.cwd(), "AGENTS.md");
|
|
1640
1889
|
if (!fs.existsSync(agentsPath)) {
|
|
1641
|
-
const claudePath = path.join(process.cwd(),
|
|
1642
|
-
let agentsContent =
|
|
1890
|
+
const claudePath = path.join(process.cwd(), "CLAUDE.md");
|
|
1891
|
+
let agentsContent = "";
|
|
1643
1892
|
if (fs.existsSync(claudePath)) {
|
|
1644
|
-
const claudeContent = fs.readFileSync(claudePath,
|
|
1893
|
+
const claudeContent = fs.readFileSync(claudePath, "utf8");
|
|
1645
1894
|
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,
|
|
1895
|
+
.replace(/# Claude Code Spec-Driven Development/g, "# AI Agent Spec-Driven Development")
|
|
1896
|
+
.replace(/Claude Code/g, "AI Agent")
|
|
1897
|
+
.replace(/claude code/g, "ai agent")
|
|
1898
|
+
.replace(/Claude/g, "AI Agent")
|
|
1899
|
+
.replace(/claude/g, "ai agent");
|
|
1651
1900
|
}
|
|
1652
1901
|
else {
|
|
1653
1902
|
agentsContent = `# AI Agent Spec-Driven Development
|
|
@@ -1730,8 +1979,9 @@ Managed by \`/kiro:steering\` command. Updates here reflect command changes.
|
|
|
1730
1979
|
fs.writeFileSync(agentsPath, agentsContent);
|
|
1731
1980
|
}
|
|
1732
1981
|
return {
|
|
1733
|
-
content: [
|
|
1734
|
-
|
|
1982
|
+
content: [
|
|
1983
|
+
{
|
|
1984
|
+
type: "text",
|
|
1735
1985
|
text: `## SDD Project Initialized Successfully
|
|
1736
1986
|
|
|
1737
1987
|
**Feature Name**: \`${featureName}\`
|
|
@@ -1746,17 +1996,20 @@ Managed by \`/kiro:steering\` command. Updates here reflect command changes.
|
|
|
1746
1996
|
2. Follow the SDD workflow: Requirements → Design → Tasks → Implementation
|
|
1747
1997
|
|
|
1748
1998
|
**Workflow Phase**: Initialized
|
|
1749
|
-
**Ready for**: Requirements generation
|
|
1750
|
-
}
|
|
1999
|
+
**Ready for**: Requirements generation`,
|
|
2000
|
+
},
|
|
2001
|
+
],
|
|
1751
2002
|
};
|
|
1752
2003
|
}
|
|
1753
2004
|
catch (error) {
|
|
1754
2005
|
return {
|
|
1755
|
-
content: [
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
2006
|
+
content: [
|
|
2007
|
+
{
|
|
2008
|
+
type: "text",
|
|
2009
|
+
text: `Error initializing SDD project: ${error.message}`,
|
|
2010
|
+
},
|
|
2011
|
+
],
|
|
2012
|
+
isError: true,
|
|
1760
2013
|
};
|
|
1761
2014
|
}
|
|
1762
2015
|
}
|
|
@@ -1769,11 +2022,11 @@ async function main() {
|
|
|
1769
2022
|
else {
|
|
1770
2023
|
// Use full featured server for development/testing mode
|
|
1771
2024
|
const server = await createMCPServer();
|
|
1772
|
-
const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry } = server;
|
|
1773
|
-
logger.info(
|
|
1774
|
-
version: process.env.npm_package_version ??
|
|
2025
|
+
const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry, } = server;
|
|
2026
|
+
logger.info("MCP SDD Server starting...", {
|
|
2027
|
+
version: process.env.npm_package_version ?? "1.0.0",
|
|
1775
2028
|
nodeVersion: process.version,
|
|
1776
|
-
pid: process.pid
|
|
2029
|
+
pid: process.pid,
|
|
1777
2030
|
});
|
|
1778
2031
|
await mcpServer.start();
|
|
1779
2032
|
// Get plugin system statistics
|
|
@@ -1781,41 +2034,63 @@ async function main() {
|
|
|
1781
2034
|
const hookStats = await hookSystem.getAllHooks();
|
|
1782
2035
|
const toolStats = await toolRegistry.getAllTools();
|
|
1783
2036
|
const steeringStats = await steeringRegistry.getSteeringStatistics();
|
|
1784
|
-
logger.info(
|
|
2037
|
+
logger.info("MCP SDD Server ready for connections", {
|
|
1785
2038
|
capabilities: {
|
|
1786
|
-
workflow:
|
|
1787
|
-
validation:
|
|
1788
|
-
initialization:
|
|
1789
|
-
context:
|
|
1790
|
-
steering:
|
|
1791
|
-
quality:
|
|
1792
|
-
i18n:
|
|
2039
|
+
workflow: "5-phase SDD workflow state machine (INIT→REQUIREMENTS→DESIGN→TASKS→IMPLEMENTATION)",
|
|
2040
|
+
validation: "Cross-phase validation with approval gates and rollback support",
|
|
2041
|
+
initialization: "Project setup with .kiro directory structure and spec.json",
|
|
2042
|
+
context: "Project memory with codebase analysis and context persistence",
|
|
2043
|
+
steering: "Dynamic steering document management with Always/Conditional/Manual modes",
|
|
2044
|
+
quality: "Linus-style code review with 5-layer analysis framework",
|
|
2045
|
+
i18n: "10-language support with cultural adaptation",
|
|
1793
2046
|
plugins: `${pluginStats.length} plugins loaded with extensibility framework`,
|
|
1794
|
-
templates:
|
|
2047
|
+
templates: "Handlebars-based template generation with inheritance",
|
|
1795
2048
|
},
|
|
1796
2049
|
tools: {
|
|
1797
2050
|
count: 10,
|
|
1798
|
-
categories: [
|
|
1799
|
-
|
|
2051
|
+
categories: [
|
|
2052
|
+
"sdd-init",
|
|
2053
|
+
"sdd-requirements",
|
|
2054
|
+
"sdd-design",
|
|
2055
|
+
"sdd-tasks",
|
|
2056
|
+
"sdd-implement",
|
|
2057
|
+
"sdd-status",
|
|
2058
|
+
"sdd-approve",
|
|
2059
|
+
"sdd-quality-check",
|
|
2060
|
+
"sdd-context-load",
|
|
2061
|
+
"sdd-template-render",
|
|
2062
|
+
],
|
|
2063
|
+
pluginTools: Object.keys(toolStats).length,
|
|
1800
2064
|
},
|
|
1801
2065
|
hooks: {
|
|
1802
2066
|
registered: Object.keys(hookStats).length,
|
|
1803
|
-
phases: [
|
|
2067
|
+
phases: [
|
|
2068
|
+
"PRE_INIT",
|
|
2069
|
+
"POST_INIT",
|
|
2070
|
+
"PRE_REQUIREMENTS",
|
|
2071
|
+
"POST_REQUIREMENTS",
|
|
2072
|
+
"PRE_DESIGN",
|
|
2073
|
+
"POST_DESIGN",
|
|
2074
|
+
"PRE_TASKS",
|
|
2075
|
+
"POST_TASKS",
|
|
2076
|
+
"PRE_IMPLEMENTATION",
|
|
2077
|
+
"POST_IMPLEMENTATION",
|
|
2078
|
+
],
|
|
1804
2079
|
},
|
|
1805
2080
|
steering: {
|
|
1806
2081
|
documents: steeringStats.totalDocuments,
|
|
1807
2082
|
plugins: Object.keys(steeringStats.documentsByPlugin).length,
|
|
1808
|
-
modes: steeringStats.documentsByMode
|
|
1809
|
-
}
|
|
2083
|
+
modes: steeringStats.documentsByMode,
|
|
2084
|
+
},
|
|
1810
2085
|
});
|
|
1811
2086
|
// Handle graceful shutdown
|
|
1812
|
-
process.on(
|
|
1813
|
-
logger.info(
|
|
2087
|
+
process.on("SIGINT", async () => {
|
|
2088
|
+
logger.info("Received SIGINT, shutting down gracefully...");
|
|
1814
2089
|
await mcpServer.stop();
|
|
1815
2090
|
process.exit(0);
|
|
1816
2091
|
});
|
|
1817
|
-
process.on(
|
|
1818
|
-
logger.info(
|
|
2092
|
+
process.on("SIGTERM", async () => {
|
|
2093
|
+
logger.info("Received SIGTERM, shutting down gracefully...");
|
|
1819
2094
|
await mcpServer.stop();
|
|
1820
2095
|
process.exit(0);
|
|
1821
2096
|
});
|
|
@@ -1824,7 +2099,7 @@ async function main() {
|
|
|
1824
2099
|
catch (error) {
|
|
1825
2100
|
// Only log startup errors in non-MCP mode
|
|
1826
2101
|
if (!isMCPMode) {
|
|
1827
|
-
console.error(
|
|
2102
|
+
console.error("Failed to start MCP SDD Server:", error);
|
|
1828
2103
|
}
|
|
1829
2104
|
process.exit(1);
|
|
1830
2105
|
}
|