sdd-mcp-server 3.5.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +97 -671
  2. package/agents/architect.md +15 -93
  3. package/agents/implementer.md +16 -141
  4. package/agents/planner.md +16 -84
  5. package/agents/reviewer.md +16 -239
  6. package/agents/security-auditor.md +16 -114
  7. package/agents/tdd-guide.md +17 -228
  8. package/dist/adapters/cli/SDDToolAdapter.d.ts +14 -5
  9. package/dist/adapters/cli/SDDToolAdapter.js +189 -362
  10. package/dist/adapters/cli/SDDToolAdapter.js.map +1 -1
  11. package/dist/application/services/ContextCompactionService.d.ts +81 -16
  12. package/dist/application/services/ContextCompactionService.js +370 -187
  13. package/dist/application/services/ContextCompactionService.js.map +1 -1
  14. package/dist/application/services/SpecPathResolver.d.ts +24 -0
  15. package/dist/application/services/SpecPathResolver.js +70 -0
  16. package/dist/application/services/SpecPathResolver.js.map +1 -0
  17. package/dist/application/services/WorkflowEngineService.d.ts +100 -46
  18. package/dist/application/services/WorkflowEngineService.js +468 -288
  19. package/dist/application/services/WorkflowEngineService.js.map +1 -1
  20. package/dist/cli/install-skills.d.ts +3 -9
  21. package/dist/cli/install-skills.js +130 -175
  22. package/dist/cli/install-skills.js.map +1 -1
  23. package/dist/cli/install-target.d.ts +45 -14
  24. package/dist/cli/install-target.js +26 -12
  25. package/dist/cli/install-target.js.map +1 -1
  26. package/dist/cli/sdd-mcp-cli.d.ts +1 -1
  27. package/dist/cli/sdd-mcp-cli.js +7 -6
  28. package/dist/cli/sdd-mcp-cli.js.map +1 -1
  29. package/dist/cli/tool-support/claude-code.js +13 -34
  30. package/dist/cli/tool-support/claude-code.js.map +1 -1
  31. package/dist/cli/tool-support/codex.d.ts +0 -53
  32. package/dist/cli/tool-support/codex.js +6 -94
  33. package/dist/cli/tool-support/codex.js.map +1 -1
  34. package/dist/cli/tool-support/index.d.ts +3 -2
  35. package/dist/cli/tool-support/index.js +3 -1
  36. package/dist/cli/tool-support/index.js.map +1 -1
  37. package/dist/cli/tool-support/omp.d.ts +5 -0
  38. package/dist/cli/tool-support/omp.js +43 -0
  39. package/dist/cli/tool-support/omp.js.map +1 -0
  40. package/dist/cli/tool-support/root-guidance.d.ts +2 -9
  41. package/dist/cli/tool-support/root-guidance.js +44 -37
  42. package/dist/cli/tool-support/root-guidance.js.map +1 -1
  43. package/dist/cli/tool-support/target-agent-renderer.d.ts +1 -0
  44. package/dist/cli/tool-support/target-agent-renderer.js +37 -4
  45. package/dist/cli/tool-support/target-agent-renderer.js.map +1 -1
  46. package/dist/cli/tool-support/target-installer.d.ts +8 -2
  47. package/dist/cli/tool-support/target-installer.js +94 -26
  48. package/dist/cli/tool-support/target-installer.js.map +1 -1
  49. package/dist/cli/utils/preserving-writer.d.ts +22 -0
  50. package/dist/cli/utils/preserving-writer.js +233 -11
  51. package/dist/cli/utils/preserving-writer.js.map +1 -1
  52. package/dist/domain/ports.d.ts +4 -0
  53. package/dist/index.d.ts +13 -10
  54. package/dist/index.js +16 -1199
  55. package/dist/index.js.map +1 -1
  56. package/dist/infrastructure/adapters/NodeFileSystemAdapter.d.ts +3 -0
  57. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js +10 -0
  58. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js.map +1 -1
  59. package/dist/infrastructure/mcp/CapabilityNegotiator.js +3 -3
  60. package/dist/infrastructure/mcp/CapabilityNegotiator.js.map +1 -1
  61. package/dist/infrastructure/mcp/sddToolDefinitions.d.ts +6 -0
  62. package/dist/infrastructure/mcp/sddToolDefinitions.js +124 -0
  63. package/dist/infrastructure/mcp/sddToolDefinitions.js.map +1 -0
  64. package/dist/utils/atomicWrite.d.ts +8 -35
  65. package/dist/utils/atomicWrite.js +12 -60
  66. package/dist/utils/atomicWrite.js.map +1 -1
  67. package/mcp-server.js +5 -2883
  68. package/package.json +5 -2
  69. package/scripts/context-usage-report.mjs +602 -0
  70. package/sdd-entry.js +17 -6
  71. package/skills/sdd-commit/REFERENCE.md +31 -0
  72. package/skills/sdd-commit/SKILL.md +17 -273
  73. package/skills/sdd-design/REFERENCE.md +35 -0
  74. package/skills/sdd-design/SKILL.md +19 -265
  75. package/skills/sdd-implement/REFERENCE.md +26 -0
  76. package/skills/sdd-implement/SKILL.md +22 -283
  77. package/skills/sdd-requirements/REFERENCE.md +31 -0
  78. package/skills/sdd-requirements/SKILL.md +23 -135
  79. package/skills/sdd-review/REFERENCE.md +26 -0
  80. package/skills/sdd-review/SKILL.md +17 -181
  81. package/skills/sdd-security-check/REFERENCE.md +19 -0
  82. package/skills/sdd-security-check/SKILL.md +18 -184
  83. package/skills/sdd-steering/REFERENCE.md +25 -0
  84. package/skills/sdd-steering/SKILL.md +18 -216
  85. package/skills/sdd-steering-custom/REFERENCE.md +27 -0
  86. package/skills/sdd-steering-custom/SKILL.md +19 -203
  87. package/skills/sdd-tasks/REFERENCE.md +25 -0
  88. package/skills/sdd-tasks/SKILL.md +19 -248
  89. package/skills/sdd-test-gen/REFERENCE.md +15 -0
  90. package/skills/sdd-test-gen/SKILL.md +17 -287
  91. package/skills/simple-task/REFERENCE.md +22 -0
  92. package/skills/simple-task/SKILL.md +17 -138
  93. package/templates/CLAUDE.md +18 -30
  94. package/rules/git-workflow.md +0 -92
  95. package/rules/sdd-workflow.md +0 -116
package/dist/index.js CHANGED
@@ -1,29 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // MCP SDD Server entry point
3
- // IMPORTANT: Detect MCP mode and silence console output BEFORE any imports
4
- // Check multiple indicators for MCP mode
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
- false; // Default to full server for better functionality
12
- if (isMCPMode) {
13
- // Completely silence all console output for MCP mode
14
- console.log = () => { };
15
- console.info = () => { };
16
- console.warn = () => { };
17
- console.debug = () => { };
18
- // Keep error for debugging but send to stderr
19
- const originalError = console.error;
20
- console.error = (...args) => originalError("[SDD-DEBUG]", ...args);
21
- }
22
- import "reflect-metadata";
23
- import { existsSync } from "fs";
24
- import nodePath from "path";
25
- import { createContainer } from "./infrastructure/di/container.js";
26
- import { TYPES } from "./infrastructure/di/types.js";
2
+ import 'reflect-metadata';
3
+ import { createContainer } from './infrastructure/di/container.js';
4
+ import { TYPES } from './infrastructure/di/types.js';
27
5
  export async function createMCPServer() {
28
6
  const container = createContainer();
29
7
  const logger = container.get(TYPES.LoggerPort);
@@ -32,7 +10,6 @@ export async function createMCPServer() {
32
10
  const hookSystem = container.get(TYPES.HookSystem);
33
11
  const toolRegistry = container.get(TYPES.PluginToolRegistry);
34
12
  const steeringRegistry = container.get(TYPES.PluginSteeringRegistry);
35
- // Initialize plugin system
36
13
  await pluginManager.initialize();
37
14
  return {
38
15
  container,
@@ -42,1185 +19,25 @@ export async function createMCPServer() {
42
19
  hookSystem,
43
20
  toolRegistry,
44
21
  steeringRegistry,
45
- async initialize() {
46
- // Already initialized above
47
- },
22
+ async initialize() { },
48
23
  async close() {
49
24
  await mcpServer.stop();
50
25
  },
51
26
  };
52
27
  }
53
- async function createSimpleMCPServer() {
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");
57
- // Resolve version dynamically from package.json when possible
58
- let pkgVersion = "0.0.0";
59
- try {
60
- const fs = await import("fs");
61
- const path = await import("path");
62
- const pkgPath = path.join(process.cwd(), "package.json");
63
- if (fs.existsSync(pkgPath)) {
64
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
65
- pkgVersion = pkg.version || pkgVersion;
66
- }
67
- }
68
- catch {
69
- // fall back to hardcoded default if needed
70
- }
71
- const server = new Server({
72
- name: "sdd-mcp-server",
73
- version: pkgVersion,
74
- }, {
75
- capabilities: {
76
- tools: {},
77
- },
78
- });
79
- // MCP Tools - Action-oriented tools only
80
- // Template/guidance tools have been moved to Agent Skills (use /sdd-requirements, /sdd-design, etc.)
81
- server.setRequestHandler(ListToolsRequestSchema, async () => {
82
- return {
83
- tools: [
84
- {
85
- name: "sdd-init",
86
- description: "Initialize a new SDD project with interactive requirements clarification",
87
- inputSchema: {
88
- type: "object",
89
- properties: {
90
- projectName: {
91
- type: "string",
92
- description: "The name of the project to initialize",
93
- },
94
- description: {
95
- type: "string",
96
- description: "Project description",
97
- },
98
- clarificationAnswers: {
99
- type: "object",
100
- description: "Answers to clarification questions (second pass)",
101
- additionalProperties: { type: "string" },
102
- },
103
- reviewTestCases: {
104
- type: "boolean",
105
- description: "Enable an optional TDD test-case review checkpoint before implementation",
106
- },
107
- },
108
- required: ["projectName"],
109
- },
110
- },
111
- {
112
- name: "sdd-status",
113
- description: "Check workflow progress",
114
- inputSchema: {
115
- type: "object",
116
- properties: {
117
- featureName: {
118
- type: "string",
119
- description: "Feature name (optional - shows all if not provided)",
120
- },
121
- },
122
- },
123
- },
124
- {
125
- name: "sdd-approve",
126
- description: "Approve workflow phases",
127
- inputSchema: {
128
- type: "object",
129
- properties: {
130
- featureName: {
131
- type: "string",
132
- description: "Feature name from spec initialization",
133
- },
134
- phase: {
135
- type: "string",
136
- description: "Phase to approve",
137
- enum: ["requirements", "design", "tasks"],
138
- },
139
- },
140
- required: ["featureName", "phase"],
141
- },
142
- },
143
- {
144
- name: "sdd-review-test-cases",
145
- description: "Mark optional TDD test-case review checkpoint as reviewed",
146
- inputSchema: {
147
- type: "object",
148
- properties: {
149
- featureName: {
150
- type: "string",
151
- description: "Feature name from spec initialization",
152
- },
153
- },
154
- required: ["featureName"],
155
- },
156
- },
157
- {
158
- name: "sdd-quality-check",
159
- description: "Code quality analysis",
160
- inputSchema: {
161
- type: "object",
162
- properties: {
163
- code: {
164
- type: "string",
165
- description: "Code to analyze",
166
- },
167
- language: {
168
- type: "string",
169
- description: "Programming language (default: javascript)",
170
- },
171
- },
172
- required: ["code"],
173
- },
174
- },
175
- {
176
- name: "sdd-context-load",
177
- description: "Load project context",
178
- inputSchema: {
179
- type: "object",
180
- properties: {
181
- featureName: {
182
- type: "string",
183
- description: "Feature name to load context for",
184
- },
185
- mode: {
186
- type: "string",
187
- enum: ["compact", "standard", "full"],
188
- description: "Context size mode. Defaults to compact handoff context.",
189
- },
190
- },
191
- required: ["featureName"],
192
- },
193
- },
194
- {
195
- name: "sdd-validate-design",
196
- description: "Interactive design quality review and validation",
197
- inputSchema: {
198
- type: "object",
199
- properties: {
200
- featureName: {
201
- type: "string",
202
- description: "Feature name to validate design for",
203
- },
204
- },
205
- required: ["featureName"],
206
- },
207
- },
208
- {
209
- name: "sdd-validate-gap",
210
- description: "Analyze implementation gap between requirements and codebase",
211
- inputSchema: {
212
- type: "object",
213
- properties: {
214
- featureName: {
215
- type: "string",
216
- description: "Feature name to analyze implementation gap for",
217
- },
218
- },
219
- required: ["featureName"],
220
- },
221
- },
222
- {
223
- name: "sdd-spec-impl",
224
- description: "Execute spec tasks using TDD methodology",
225
- inputSchema: {
226
- type: "object",
227
- properties: {
228
- featureName: {
229
- type: "string",
230
- description: "Feature name to execute tasks for",
231
- },
232
- taskNumbers: {
233
- type: "string",
234
- description: "Specific task numbers to execute (e.g., \"1.1,2.3\" or leave empty for all pending)",
235
- },
236
- },
237
- required: ["featureName"],
238
- },
239
- },
240
- {
241
- name: "sdd-list-skills",
242
- description: "List available SDD Agent Skills for Codex or Claude Code",
243
- inputSchema: {
244
- type: "object",
245
- properties: {},
246
- },
247
- },
248
- ],
249
- };
250
- });
251
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
252
- const { name, arguments: args } = request.params;
253
- switch (name) {
254
- case "sdd-init":
255
- return await handleInitSimplified(args);
256
- case "sdd-status":
257
- return await handleStatusSimplified(args);
258
- case "sdd-quality-check":
259
- return await handleQualityCheckSimplified(args);
260
- case "sdd-approve":
261
- return await handleApproveSimplified(args);
262
- case "sdd-review-test-cases":
263
- return await handleReviewTestCasesSimplified(args);
264
- case "sdd-context-load":
265
- return await handleContextLoadSimplified(args);
266
- case "sdd-validate-design":
267
- return {
268
- content: [
269
- {
270
- type: "text",
271
- text: `Design validation for ${args.featureName}. (Simplified MCP mode)`,
272
- },
273
- ],
274
- };
275
- case "sdd-validate-gap":
276
- return {
277
- content: [
278
- {
279
- type: "text",
280
- text: `Implementation gap analysis for ${args.featureName}. (Simplified MCP mode)`,
281
- },
282
- ],
283
- };
284
- case "sdd-spec-impl":
285
- return {
286
- content: [
287
- {
288
- type: "text",
289
- text: `TDD implementation for ${args.featureName}. (Simplified MCP mode)`,
290
- },
291
- ],
292
- };
293
- case "sdd-list-skills":
294
- return await handleListSkillsSimplified();
295
- default:
296
- throw new Error(`Unknown tool: ${name}`);
297
- }
298
- });
299
- // Handle initialized notification
300
- server.setNotificationHandler(InitializedNotificationSchema, async () => {
301
- // Client has completed initialization - server is ready
302
- });
303
- const transport = new StdioServerTransport();
304
- await server.connect(transport);
305
- }
306
- // List available SDD Agent Skills
307
- async function handleListSkillsSimplified() {
308
- const path = await import("path");
309
- const { SkillManager } = await import("./skills/SkillManager.js");
310
- try {
311
- // Determine skills path - check multiple locations
312
- const possiblePaths = [
313
- path.resolve(process.cwd(), "node_modules/sdd-mcp-server/skills"),
314
- path.resolve(process.cwd(), "skills"),
315
- path.resolve(__dirname, "../skills"),
316
- path.resolve(__dirname, "../../skills"),
317
- ];
318
- let skillsPath = possiblePaths[0];
319
- const fs = await import("fs");
320
- for (const p of possiblePaths) {
321
- if (fs.existsSync(p)) {
322
- skillsPath = p;
323
- break;
324
- }
325
- }
326
- const skillManager = new SkillManager(skillsPath);
327
- const skills = await skillManager.listSkills();
328
- if (skills.length === 0) {
329
- return {
330
- content: [
331
- {
332
- type: "text",
333
- text: `## SDD Agent Skills
334
-
335
- No skills found in the package. Skills may not be installed correctly.
336
-
337
- **Expected location**: \`${skillsPath}\`
338
-
339
- **Installation**: Run \`npx sdd-mcp-server install --target codex --skills\` or \`npx sdd-mcp-server install --target claude-code --skills\`.`,
340
- },
341
- ],
342
- };
343
- }
344
- const skillsList = skills
345
- .map((skill) => `- **${skill.name}**: ${skill.description || "No description"}`)
346
- .join("\n");
347
- return {
348
- content: [
349
- {
350
- type: "text",
351
- text: `## SDD Agent Skills
352
-
353
- Available skills for Codex or Claude Code:
354
-
355
- ${skillsList}
356
-
357
- **Total**: ${skills.length} skills
358
-
359
- **Installation**: Run \`npx sdd-mcp-server install --target codex --skills\` or \`npx sdd-mcp-server install --target claude-code --skills\`.
360
-
361
- After installation, use these skills in the selected target agent:
362
- - \`/sdd-requirements <feature-name>\`
363
- - \`/sdd-design <feature-name>\`
364
- - \`/sdd-tasks <feature-name>\`
365
- - \`/sdd-implement <feature-name>\`
366
- - \`/sdd-steering\`
367
- - \`/sdd-commit\``,
368
- },
369
- ],
370
- };
371
- }
372
- catch (error) {
373
- return {
374
- content: [
375
- {
376
- type: "text",
377
- text: `Error listing skills: ${error.message}`,
378
- },
379
- ],
380
- isError: true,
381
- };
382
- }
383
- }
384
- /**
385
- * Helper function to handle module loader failures consistently
386
- *
387
- * @param context - Description of what was being loaded (e.g., "documentGenerator", "specGenerator")
388
- * @param error - The error that occurred during loading
389
- * @param allowFallback - Whether to allow fallback templates (from env var or args)
390
- * @returns Object with fallback content if allowed, or throws error
391
- * @throws Error if fallback is not allowed
392
- */
393
- function handleLoaderFailure(context, error, allowFallback = false) {
394
- 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.`;
395
- console.error(`[SDD-DEBUG] Loader failure for ${context}:`, error.message);
396
- console.error(`[SDD-DEBUG] Fallback allowed:`, allowFallback);
397
- if (!allowFallback) {
398
- // Propagate error - do not use fallback
399
- throw new Error(errorMessage);
400
- }
401
- console.error(`[SDD-DEBUG] Using fallback templates for ${context}`);
402
- return { useFallback: true, error };
403
- }
404
- // Status handler aligned with full server behavior
405
- async function handleStatusSimplified(args) {
406
- const fs = await import("fs");
407
- const path = await import("path");
408
- const { featureName } = args || {};
409
- const currentPath = process.cwd();
410
- // Support both .spec (new) and .kiro (legacy)
411
- const specPath = path.join(currentPath, ".spec");
412
- const kiroPath = path.join(currentPath, ".kiro");
413
- const sddPath = await fs.promises.access(specPath).then(() => specPath).catch(() => kiroPath);
414
- const exists = await fs.promises
415
- .access(sddPath)
416
- .then(() => true)
417
- .catch(() => false);
418
- if (!exists) {
419
- return {
420
- content: [
421
- {
422
- type: "text",
423
- text: "SDD project status: No active project found. Use sdd-init to create a new project.",
424
- },
425
- ],
426
- };
427
- }
428
- const specsPath = path.join(sddPath, "specs");
429
- if (featureName) {
430
- const featurePath = path.join(specsPath, featureName);
431
- const specPath = path.join(featurePath, "spec.json");
432
- const specExists = await fs.promises
433
- .access(specPath)
434
- .then(() => true)
435
- .catch(() => false);
436
- if (!specExists) {
437
- return {
438
- content: [
439
- {
440
- type: "text",
441
- text: `Feature "${featureName}" not found. Use sdd-init to create it.`,
442
- },
443
- ],
444
- };
445
- }
446
- const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
447
- let status = `## SDD Project Status: ${spec.feature_name}\n\n`;
448
- status += `**Current Phase**: ${spec.phase}\n`;
449
- status += `**Language**: ${spec.language}\n`;
450
- status += `**Created**: ${spec.created_at}\n`;
451
- status += `**Updated**: ${spec.updated_at}\n\n`;
452
- status += `**Phase Progress**:\n`;
453
- status += `- Requirements: ${spec.approvals.requirements.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.requirements.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
454
- status += `- Design: ${spec.approvals.design.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.design.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n`;
455
- status += `- Tasks: ${spec.approvals.tasks.generated ? "✅ Generated" : "❌ Not Generated"}${spec.approvals.tasks.approved ? ", ✅ Approved" : ", ❌ Not Approved"}\n\n`;
456
- if (spec.checkpoints?.test_cases?.required) {
457
- status += `**TDD Test Case Review**: ${spec.checkpoints.test_cases.reviewed ? "✅ Reviewed" : "❌ Pending"}\n`;
458
- }
459
- status += `**Ready for Implementation**: ${spec.ready_for_implementation ? "✅ Yes" : "❌ No"}\n\n`;
460
- if (!spec.approvals.requirements.generated)
461
- status += `**Next Step**: Run \`sdd-requirements ${featureName}\``;
462
- else if (!spec.approvals.design.generated)
463
- status += `**Next Step**: Run \`sdd-design ${featureName}\``;
464
- else if (!spec.approvals.tasks.generated)
465
- status += `**Next Step**: Run \`sdd-tasks ${featureName}\``;
466
- else if (spec.checkpoints?.test_cases?.required && !spec.checkpoints.test_cases.reviewed)
467
- status += `**Next Step**: Review test cases, then run \`sdd-review-test-cases ${featureName}\``;
468
- else
469
- status += `**Next Step**: Run \`sdd-implement ${featureName}\` to begin implementation`;
470
- return { content: [{ type: "text", text: status }] };
471
- }
472
- const features = await fs.promises
473
- .readdir(specsPath)
474
- .catch(() => []);
475
- if (features.length === 0) {
476
- return {
477
- content: [
478
- {
479
- type: "text",
480
- text: "No SDD features found. Use sdd-init to create a new project.",
481
- },
482
- ],
483
- };
484
- }
485
- let status = "## SDD Project Status - All Features\n\n";
486
- for (const feature of features) {
487
- const specPath = path.join(specsPath, feature, "spec.json");
488
- const specExists = await fs.promises
489
- .access(specPath)
490
- .then(() => true)
491
- .catch(() => false);
492
- if (specExists) {
493
- const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
494
- status += `**${spec.feature_name}**:\n`;
495
- status += `- Phase: ${spec.phase}\n`;
496
- status += `- Requirements: ${spec.approvals.requirements.generated ? "✅" : "❌"}\n`;
497
- status += `- Design: ${spec.approvals.design.generated ? "✅" : "❌"}\n`;
498
- status += `- Tasks: ${spec.approvals.tasks.generated ? "✅" : "❌"}\n`;
499
- if (spec.checkpoints?.test_cases?.required) {
500
- status += `- Test cases reviewed: ${spec.checkpoints.test_cases.reviewed ? "✅" : "❌"}\n`;
501
- }
502
- status += `- Ready: ${spec.ready_for_implementation ? "✅" : "❌"}\n\n`;
503
- }
504
- }
505
- return { content: [{ type: "text", text: status }] };
506
- }
507
- // Approve handler to update spec.json
508
- async function handleApproveSimplified(args) {
509
- const fs = await import("fs");
510
- const path = await import("path");
511
- const { featureName, phase } = args || {};
512
- if (!featureName || !phase) {
513
- return {
514
- content: [{ type: "text", text: "featureName and phase are required" }],
515
- isError: true,
516
- };
517
- }
518
- try {
519
- // Support both .spec (new) and .kiro (legacy)
520
- const sddDir = fs.existsSync(path.join(process.cwd(), ".spec")) ? ".spec" : ".kiro";
521
- const featurePath = path.join(process.cwd(), sddDir, "specs", featureName);
522
- const specPath = path.join(featurePath, "spec.json");
523
- const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
524
- if (!spec.approvals?.[phase]?.generated) {
525
- return {
526
- content: [
527
- {
528
- type: "text",
529
- text: `Error: ${phase} must be generated before approval. Run sdd-${phase} ${featureName} first.`,
530
- },
531
- ],
532
- };
533
- }
534
- if (phase === "tasks" &&
535
- spec.checkpoints?.test_cases?.required &&
536
- !spec.checkpoints.test_cases.reviewed) {
537
- return {
538
- content: [
539
- {
540
- type: "text",
541
- text: `Error: TDD test cases must be reviewed before approving tasks. ` +
542
- `After review, run sdd-review-test-cases ${featureName}.`,
543
- },
544
- ],
545
- isError: true,
546
- };
547
- }
548
- spec.approvals[phase].approved = true;
549
- spec.updated_at = new Date().toISOString();
550
- spec.ready_for_implementation =
551
- spec.approvals.requirements?.approved === true &&
552
- spec.approvals.design?.approved === true &&
553
- spec.approvals.tasks?.approved === true &&
554
- (spec.checkpoints?.test_cases?.required !== true ||
555
- spec.checkpoints.test_cases.reviewed === true);
556
- fs.writeFileSync(specPath, JSON.stringify(spec, null, 2));
557
- const handoff = await generateCompactHandoffSimplified(featureName, phase);
558
- return {
559
- content: [
560
- {
561
- type: "text",
562
- text: `## Phase Approved\n\n` +
563
- `**Feature**: ${featureName}\n` +
564
- `**Phase**: ${phase}\n` +
565
- `**Status**: ✅ Approved\n` +
566
- `**Context Handoff**: ${handoff.relativePath}\n` +
567
- `**Estimated Context Reduction**: ${handoff.reductionPercentage}% ` +
568
- `(~${handoff.sourceTokens} → ~${handoff.compactTokens} tokens)`,
569
- },
570
- ],
571
- };
572
- }
573
- catch (error) {
574
- return {
575
- content: [
576
- {
577
- type: "text",
578
- text: `Error approving phase: ${error.message}`,
579
- },
580
- ],
581
- isError: true,
582
- };
583
- }
584
- }
585
- async function handleContextLoadSimplified(args) {
586
- const fs = await import("fs");
587
- const path = await import("path");
588
- const { featureName, mode = "compact" } = args || {};
589
- if (!featureName) {
590
- return {
591
- content: [{ type: "text", text: "featureName is required" }],
592
- isError: true,
593
- };
594
- }
595
- if (!["compact", "standard", "full"].includes(mode)) {
596
- return {
597
- content: [{ type: "text", text: "mode must be compact, standard, or full" }],
598
- isError: true,
599
- };
600
- }
601
- try {
602
- const { specDir, specPath } = ensureSimplifiedFeatureExists(featureName);
603
- const handoffPath = path.join(specDir, "context", "handoff.md");
604
- if (mode === "full") {
605
- const context = await loadFullContextSimplified(featureName);
606
- return { content: [{ type: "text", text: context }] };
607
- }
608
- if (!fs.existsSync(handoffPath)) {
609
- await generateCompactHandoffSimplified(featureName, "requirements");
610
- }
611
- let context = fs.readFileSync(handoffPath, "utf8");
612
- if (mode === "standard") {
613
- context += `\n\n## Current Spec Metadata\n\n\`\`\`json\n${fs.readFileSync(specPath, "utf8")}\n\`\`\``;
614
- }
615
- return { content: [{ type: "text", text: context }] };
616
- }
617
- catch (error) {
618
- return {
619
- content: [
620
- {
621
- type: "text",
622
- text: `Error loading context: ${error.message}`,
623
- },
624
- ],
625
- isError: true,
626
- };
627
- }
628
- }
629
- function getSimplifiedSpecDir(featureName) {
630
- const sddDir = existsSync(nodePath.join(process.cwd(), ".spec")) ? ".spec" : ".kiro";
631
- return nodePath.join(process.cwd(), sddDir, "specs", featureName);
632
- }
633
- function ensureSimplifiedFeatureExists(featureName) {
634
- const specDir = getSimplifiedSpecDir(featureName);
635
- const specPath = nodePath.join(specDir, "spec.json");
636
- if (!existsSync(specPath)) {
637
- throw new Error(`Feature "${featureName}" not found. Run sdd-init first or check the feature name.`);
638
- }
639
- return { specDir, specPath };
640
- }
641
- async function generateCompactHandoffSimplified(featureName, approvedPhase) {
642
- const fs = await import("fs");
643
- const path = await import("path");
644
- const { specDir } = ensureSimplifiedFeatureExists(featureName);
645
- const contextDir = path.join(specDir, "context");
646
- const documents = ["requirements.md", "design.md", "tasks.md", "spec.json"]
647
- .map((name) => {
648
- const filePath = path.join(specDir, name);
649
- return fs.existsSync(filePath)
650
- ? { name, filePath, content: fs.readFileSync(filePath, "utf8") }
651
- : null;
652
- })
653
- .filter(Boolean);
654
- if (documents.length === 0) {
655
- throw new Error(`Feature "${featureName}" has no source documents to compact.`);
656
- }
657
- fs.mkdirSync(contextDir, { recursive: true });
658
- const sourceCharacters = documents.reduce((sum, doc) => sum + doc.content.length, 0);
659
- const spec = documents.find((doc) => doc.name === "spec.json");
660
- const parsedSpec = spec ? JSON.parse(spec.content) : {};
661
- const summaries = documents.map((doc) => summarizeDocumentSimplified(doc.name, doc.content));
662
- const nextActions = getSimplifiedNextActions(approvedPhase, parsedSpec);
663
- const draft = [
664
- `# SDD Context Handoff: ${featureName}`,
665
- "",
666
- `Generated: ${new Date().toISOString()}`,
667
- `Approved phase: ${approvedPhase}`,
668
- "",
669
- "## Workflow State",
670
- "",
671
- `- Requirements: ${formatSimplifiedApproval(parsedSpec.approvals?.requirements)}`,
672
- `- Design: ${formatSimplifiedApproval(parsedSpec.approvals?.design)}`,
673
- `- Tasks: ${formatSimplifiedApproval(parsedSpec.approvals?.tasks)}`,
674
- parsedSpec.checkpoints?.test_cases?.required
675
- ? `- TDD test-case review: ${parsedSpec.checkpoints.test_cases.reviewed ? "reviewed" : "pending"}`
676
- : "- TDD test-case review: not required",
677
- "",
678
- "## Compact Phase Summaries",
679
- "",
680
- summaries.join("\n\n"),
681
- "",
682
- "## Next Actions",
683
- "",
684
- ...nextActions.map((action) => `- ${action}`),
685
- "",
686
- "## Source References",
687
- "",
688
- ...documents.map((doc) => `- ${doc.filePath}`),
689
- "",
690
- "## Context Budget Estimate",
691
- "",
692
- `- Full source context: ~${estimateTokensSimplified(sourceCharacters)} tokens`,
693
- "- Handoff context: ~0 tokens",
694
- "- Use `sdd-context-load` default compact mode for routine continuation.",
695
- '- Use `sdd-context-load` with `mode: "full"` only for audits or ambiguous decisions.'
696
- ].join("\n");
697
- const compactTokens = estimateTokensSimplified(draft.length);
698
- const sourceTokens = estimateTokensSimplified(sourceCharacters);
699
- const reductionPercentage = sourceTokens === 0
700
- ? 0
701
- : Math.max(0, Math.round((1 - compactTokens / sourceTokens) * 100));
702
- const content = draft.replace("- Handoff context: ~0 tokens", `- Handoff context: ~${compactTokens} tokens`);
703
- const handoffPath = path.join(contextDir, "handoff.md");
704
- fs.writeFileSync(handoffPath, content);
705
- fs.writeFileSync(path.join(contextDir, `${approvedPhase}-handoff.md`), content);
706
- return {
707
- relativePath: path.relative(process.cwd(), handoffPath),
708
- sourceTokens,
709
- compactTokens,
710
- reductionPercentage,
711
- };
712
- }
713
- async function loadFullContextSimplified(featureName) {
714
- const fs = await import("fs");
715
- const path = await import("path");
716
- const { specDir } = ensureSimplifiedFeatureExists(featureName);
717
- const parts = [`# Full SDD Context: ${featureName}`];
718
- for (const name of ["requirements.md", "design.md", "tasks.md", "spec.json"]) {
719
- const filePath = path.join(specDir, name);
720
- if (fs.existsSync(filePath)) {
721
- parts.push(`## ${name}\n\n${fs.readFileSync(filePath, "utf8")}`);
722
- }
723
- }
724
- return parts.join("\n\n");
725
- }
726
- function summarizeDocumentSimplified(name, content) {
727
- const lines = content
728
- .split(/\r?\n/)
729
- .map((line) => line.trim())
730
- .filter((line) => line.length > 0 && !line.startsWith("```"));
731
- const headings = lines
732
- .filter((line) => /^#{1,4}\s+/.test(line))
733
- .map((line) => line.replace(/^#{1,4}\s+/, "").trim())
734
- .filter(uniqueSimplifiedLine)
735
- .slice(0, 8);
736
- const bullets = lines
737
- .filter((line) => /^[-*]\s+/.test(line) || /^\d+\.\s+/.test(line))
738
- .map((line) => line.replace(/^[-*]\s+/, "").replace(/^\d+\.\s+/, "").trim())
739
- .filter((line) => line.length <= 220)
740
- .filter(uniqueSimplifiedLine)
741
- .slice(0, 8);
742
- const requirementLines = lines
743
- .filter((line) => /\b(SHALL|MUST|WHEN|IF|THEN|WHERE|constraint|risk|security|performance|error|edge case)\b/i.test(line))
744
- .map((line) => line.replace(/^[-*]\s+/, "").replace(/^\d+\.\s+/, "").trim())
745
- .filter((line) => line.length <= 240)
746
- .filter(uniqueSimplifiedLine)
747
- .slice(0, 8);
748
- return [
749
- `### ${name}`,
750
- headings.length > 0 ? "\n**Key sections:**" : "",
751
- ...headings.map((line) => `- ${line}`),
752
- bullets.length > 0 ? "\n**Important points:**" : "",
753
- ...bullets.map((line) => `- ${line}`),
754
- requirementLines.length > 0 ? "\n**Constraints and acceptance signals:**" : "",
755
- ...requirementLines.map((line) => `- ${line}`),
756
- headings.length === 0 && bullets.length === 0 && requirementLines.length === 0
757
- ? "- No structured summary points found; open source document if this phase is active."
758
- : "",
759
- ].filter(Boolean).join("\n");
760
- }
761
- function uniqueSimplifiedLine(line, index, lines) {
762
- return lines.findIndex((candidate) => candidate.toLowerCase() === line.toLowerCase()) === index;
763
- }
764
- function getSimplifiedNextActions(approvedPhase, spec) {
765
- if (approvedPhase === "requirements") {
766
- return ["Generate or review design using the approved requirements handoff."];
767
- }
768
- if (approvedPhase === "design") {
769
- return ["Generate TDD task breakdown from the approved design handoff."];
770
- }
771
- if (spec.checkpoints?.test_cases?.required && !spec.checkpoints.test_cases.reviewed) {
772
- return ["Review TDD test cases, then run sdd-review-test-cases before approving tasks."];
773
- }
774
- return ["Begin implementation with compact context loaded; open full docs only for ambiguous details."];
775
- }
776
- function formatSimplifiedApproval(status) {
777
- if (status?.generated && status?.approved)
778
- return "generated, approved";
779
- if (status?.generated)
780
- return "generated, pending approval";
781
- return "not generated";
782
- }
783
- function estimateTokensSimplified(characters) {
784
- return Math.max(1, Math.ceil(characters / 4));
28
+ export async function startMCPServer() {
29
+ const runtime = await createMCPServer();
30
+ await runtime.mcpServer.start();
31
+ return runtime;
785
32
  }
786
- async function handleReviewTestCasesSimplified(args) {
787
- const fs = await import("fs");
788
- const path = await import("path");
789
- const { featureName } = args || {};
790
- if (!featureName) {
791
- return {
792
- content: [{ type: "text", text: "featureName is required" }],
793
- isError: true,
794
- };
795
- }
796
- try {
797
- const sddDir = fs.existsSync(path.join(process.cwd(), ".spec")) ? ".spec" : ".kiro";
798
- const specPath = path.join(process.cwd(), sddDir, "specs", featureName, "spec.json");
799
- const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
800
- spec.workflow_options = {
801
- ...(spec.workflow_options ?? {}),
802
- review_test_cases: true,
803
- };
804
- spec.checkpoints = {
805
- ...(spec.checkpoints ?? {}),
806
- test_cases: {
807
- required: true,
808
- reviewed: true,
809
- reviewed_at: new Date().toISOString(),
810
- },
811
- };
812
- spec.updated_at = new Date().toISOString();
813
- spec.ready_for_implementation =
814
- spec.approvals?.requirements?.approved === true &&
815
- spec.approvals?.design?.approved === true &&
816
- spec.approvals?.tasks?.approved === true;
817
- fs.writeFileSync(specPath, JSON.stringify(spec, null, 2));
818
- return {
819
- content: [
820
- {
821
- type: "text",
822
- text: `## TDD Test Cases Reviewed\n\n**Feature**: ${featureName}\n**Status**: ✅ Reviewed`,
823
- },
824
- ],
825
- };
826
- }
827
- catch (error) {
828
- return {
829
- content: [
830
- {
831
- type: "text",
832
- text: `Error reviewing test cases: ${error.message}`,
833
- },
834
- ],
835
- isError: true,
836
- };
837
- }
33
+ function isDirectExecution() {
34
+ return process.argv[1]?.endsWith('/dist/index.js') === true ||
35
+ process.argv[1]?.endsWith('\\dist\\index.js') === true;
838
36
  }
839
- // Simple quality check aligned with full server
840
- async function handleQualityCheckSimplified(args) {
841
- const { code = "", language = "javascript" } = args || {};
842
- try {
843
- const lines = String(code).split("\n");
844
- const issues = [];
845
- if (code.includes("console.log"))
846
- issues.push("L1: Remove debug console.log statements");
847
- if (code.includes("var "))
848
- issues.push("L1: Use let/const instead of var");
849
- if (!/^[a-z]/.test(code.split("function ")[1]?.split("(")[0] || "")) {
850
- if (code.includes("function "))
851
- issues.push("L2: Function names should start with lowercase");
852
- }
853
- if (code.includes("for") && !code.includes("const"))
854
- issues.push("L3: Prefer const in for loops");
855
- if (lines.length > 50)
856
- issues.push("L4: Consider splitting large blocks into smaller functions");
857
- const report = `## Code Quality Analysis (${language})\n\n` +
858
- (issues.length
859
- ? issues.map((i) => `- ${i}`).join("\n")
860
- : "No significant issues detected");
861
- return { content: [{ type: "text", text: report }] };
862
- }
863
- catch (error) {
864
- return {
865
- content: [
866
- {
867
- type: "text",
868
- text: `Error analyzing code quality: ${error.message}`,
869
- },
870
- ],
871
- isError: true,
872
- };
873
- }
874
- }
875
- function generateFeatureName(description) {
876
- // Extract feature name from description - similar to kiro spec-init
877
- const cleaned = description
878
- .toLowerCase()
879
- .replace(/[^a-z0-9\s]/g, "")
880
- .trim()
881
- .split(/\s+/)
882
- .slice(0, 4) // Take first 4 words
883
- .join("-");
884
- // Ensure it's not empty
885
- return cleaned || "new-feature";
886
- }
887
- async function ensureUniqueFeatureName(baseName) {
888
- const fs = await import("fs");
889
- const path = await import("path");
890
- // Support both .spec (new) and .kiro (legacy)
891
- const sddDir = fs.existsSync(path.join(process.cwd(), ".spec")) ? ".spec" : ".kiro";
892
- const specsDir = path.join(process.cwd(), sddDir, "specs");
893
- if (!fs.existsSync(specsDir)) {
894
- return baseName;
895
- }
896
- let counter = 1;
897
- let featureName = baseName;
898
- while (fs.existsSync(path.join(specsDir, featureName))) {
899
- featureName = `${baseName}-${counter}`;
900
- counter++;
901
- }
902
- return featureName;
903
- }
904
- async function loadSpecContext(featureName) {
905
- const fs = await import("fs");
906
- const path = await import("path");
907
- // Support both .spec (new) and .kiro (legacy)
908
- const sddDir = fs.existsSync(path.join(process.cwd(), ".spec")) ? ".spec" : ".kiro";
909
- const specDir = path.join(process.cwd(), sddDir, "specs", featureName);
910
- const specJsonPath = path.join(specDir, "spec.json");
911
- const requirementsPath = path.join(specDir, "requirements.md");
912
- let spec = null;
913
- let requirements = null;
914
- try {
915
- if (fs.existsSync(specJsonPath)) {
916
- const specContent = fs.readFileSync(specJsonPath, "utf8");
917
- spec = JSON.parse(specContent);
918
- }
919
- }
920
- catch (error) {
921
- // Ignore spec.json parse errors
922
- }
923
- try {
924
- if (fs.existsSync(requirementsPath)) {
925
- requirements = fs.readFileSync(requirementsPath, "utf8");
926
- }
927
- }
928
- catch (error) {
929
- // Ignore requirements.md read errors
930
- }
931
- return { spec, requirements };
932
- }
933
- async function handleInitSimplified(args) {
934
- const fs = await import("fs");
935
- const path = await import("path");
936
- try {
937
- const { projectName, description, reviewTestCases = false } = args;
938
- if (!description || typeof description !== "string") {
939
- throw new Error("Description is required for project initialization");
940
- }
941
- const projectPath = process.cwd();
942
- // Generate feature name from projectName (if provided) or description
943
- const baseFeatureName = projectName && typeof projectName === "string"
944
- ? projectName
945
- : generateFeatureName(description);
946
- const featureName = await ensureUniqueFeatureName(baseFeatureName);
947
- // Create .spec/specs/[feature-name] directory (use .spec for new projects)
948
- const specDir = path.join(projectPath, ".spec", "specs", featureName);
949
- if (!fs.existsSync(specDir)) {
950
- fs.mkdirSync(specDir, { recursive: true });
951
- }
952
- // Create spec.json with metadata
953
- const specContent = {
954
- feature_name: featureName,
955
- created_at: new Date().toISOString(),
956
- updated_at: new Date().toISOString(),
957
- language: "en",
958
- phase: "initialized",
959
- approvals: {
960
- requirements: {
961
- generated: false,
962
- approved: false,
963
- },
964
- design: {
965
- generated: false,
966
- approved: false,
967
- },
968
- tasks: {
969
- generated: false,
970
- approved: false,
971
- },
972
- },
973
- workflow_options: {
974
- review_test_cases: reviewTestCases === true,
975
- },
976
- checkpoints: {
977
- test_cases: {
978
- required: reviewTestCases === true,
979
- reviewed: reviewTestCases !== true,
980
- },
981
- },
982
- ready_for_implementation: false,
983
- };
984
- fs.writeFileSync(path.join(specDir, "spec.json"), JSON.stringify(specContent, null, 2));
985
- // Create requirements.md template with project description
986
- const requirementsTemplate = `# Requirements Document
987
-
988
- ## Project Description (Input)
989
- ${description}
990
-
991
- ## Requirements
992
- <!-- Will be generated in sdd-requirements phase -->
993
- `;
994
- fs.writeFileSync(path.join(specDir, "requirements.md"), requirementsTemplate);
995
- // Ensure AGENTS.md exists (static, derived from CLAUDE.md when available)
996
- const agentsPath = path.join(process.cwd(), "AGENTS.md");
997
- if (!fs.existsSync(agentsPath)) {
998
- const claudePath = path.join(process.cwd(), "CLAUDE.md");
999
- let agentsContent = "";
1000
- if (fs.existsSync(claudePath)) {
1001
- const claudeContent = fs.readFileSync(claudePath, "utf8");
1002
- agentsContent = claudeContent
1003
- .replace(/# Claude Code Spec-Driven Development/g, "# AI Agent Spec-Driven Development")
1004
- .replace(/Claude Code/g, "AI Agent")
1005
- .replace(/claude code/g, "ai agent")
1006
- .replace(/Claude/g, "AI Agent")
1007
- .replace(/claude/g, "ai agent");
1008
- }
1009
- else {
1010
- agentsContent = `# AI Agent Spec-Driven Development
1011
-
1012
- Spec Driven Development implementation using MCP tools.
1013
-
1014
- ## Project Context
1015
-
1016
- ### Paths
1017
- - Steering: \`.spec/steering/\`
1018
- - Specs: \`.spec/specs/\`
1019
- - Skills: install with \`npx sdd-mcp-server install --target codex --skills\` or \`--target claude-code\`
1020
-
1021
- ### Steering vs Specification
1022
-
1023
- **Steering** (\`.spec/steering/\`) - Guide AI with project-wide rules and context
1024
- **Specs** (\`.spec/specs/\`) - Formalize development process for individual features
1025
-
1026
- ### Active Specifications
1027
- - Check \`.spec/specs/\` for active specifications
1028
- - Use \`sdd-status\` to check progress
1029
-
1030
- **Current Specifications:**
1031
- - (None active)
1032
-
1033
- ## Development Guidelines
1034
- - Think in English, generate responses in English
1035
-
1036
- ## Workflow
1037
-
1038
- ### Phase 0: Steering (Optional)
1039
- \`sdd-steering\` - Create/update steering documents
1040
- \`sdd-steering-custom\` - Create custom steering for specialized contexts
1041
-
1042
- Note: Optional for new features or small additions. You can proceed directly to sdd-init.
1043
-
1044
- ### Phase 1: Specification Creation
1045
- 1. \`sdd-init\` - Initialize spec with detailed project description
1046
- 2. \`sdd-requirements\` - Generate requirements document
1047
- 3. \`sdd-design\` - Interactive: "Have you reviewed requirements.md? [y/N]"
1048
- 4. \`sdd-tasks\` - Interactive: Confirms requirements/design review and asks whether TDD test cases need a review checkpoint
1049
-
1050
- ### Phase 2: Progress Tracking
1051
- \`sdd-status\` - Check current progress and phases
1052
-
1053
- ## Development Rules
1054
- 1. **Consider steering**: Run \`sdd-steering\` before major development (optional for new features)
1055
- 2. **Follow 3-phase approval workflow**: Requirements → Design → Tasks → Implementation
1056
- 3. **Approval required**: Each phase requires human review (interactive prompt or manual)
1057
- 4. **No skipping phases**: Design requires approved requirements; Tasks require approved design
1058
- 5. **Update task status**: Mark tasks as completed when working on them
1059
- 6. **Keep steering current**: Run \`sdd-steering\` after significant changes
1060
- 7. **Check spec compliance**: Use \`sdd-status\` to verify alignment
1061
-
1062
- ## Steering Configuration
1063
-
1064
- ### Current Steering Files
1065
- Managed by \`sdd-steering\` tool. Updates here reflect tool changes.
1066
-
1067
- ### Active Steering Files
1068
- Load steering documents on demand to control token usage:
1069
- - \`product.md\`: Product context and business objectives
1070
- - \`tech.md\`: Technology stack and architectural decisions
1071
- - \`structure.md\`: File organization and code patterns
1072
- - \`linus-review.md\`: Code quality review standards
1073
- - \`commit.md\`: Commit and PR conventions
1074
- - \`security-check.md\`: OWASP Top 10 checklist for code generation and review
1075
- - \`tdd-guideline.md\`: TDD workflow for new features
1076
- - \`principles.md\`: SOLID, DRY, KISS, YAGNI, Separation of Concerns, Modularity
1077
-
1078
- ### Custom Steering Files
1079
- <!-- Added by sdd-steering-custom tool -->
1080
- <!-- Format:
1081
- - \`filename.md\`: Mode - Pattern(s) - Description
1082
- Mode: Always|Conditional|Manual
1083
- Pattern: File patterns for Conditional mode
1084
- -->
1085
-
1086
- ### Inclusion Modes
1087
- - **Always**: Loaded in every interaction (default)
1088
- - **Conditional**: Loaded for specific file patterns (e.g., "*.test.js")
1089
- - **Manual**: Reference with \`@filename.md\` syntax
1090
- `;
1091
- }
1092
- fs.writeFileSync(agentsPath, agentsContent);
1093
- }
1094
- return {
1095
- content: [
1096
- {
1097
- type: "text",
1098
- text: `## SDD Project Initialized Successfully
1099
-
1100
- **Feature Name**: \`${featureName}\`
1101
- **Description**: ${description}
1102
- **TDD Test Case Review Checkpoint**: ${reviewTestCases === true ? "Enabled" : "Disabled"}
1103
-
1104
- **Created Files**:
1105
- - \`.spec/specs/${featureName}/spec.json\` - Project metadata and phase tracking
1106
- - \`.spec/specs/${featureName}/requirements.md\` - Initial requirements template
1107
-
1108
- **Next Steps**:
1109
- 1. Run \`sdd-requirements ${featureName}\` to generate detailed requirements
1110
- 2. Follow the SDD workflow: Requirements → Design → Tasks → Implementation
1111
-
1112
- **Workflow Phase**: Initialized
1113
- **Ready for**: Requirements generation`,
1114
- },
1115
- ],
1116
- };
1117
- }
1118
- catch (error) {
1119
- return {
1120
- content: [
1121
- {
1122
- type: "text",
1123
- text: `Error initializing SDD project: ${error.message}`,
1124
- },
1125
- ],
1126
- isError: true,
1127
- };
1128
- }
1129
- }
1130
- async function main() {
1131
- try {
1132
- if (isMCPMode) {
1133
- // Use simplified MCP server for MCP mode
1134
- await createSimpleMCPServer();
1135
- }
1136
- else {
1137
- // Use full featured server for development/testing mode
1138
- const server = await createMCPServer();
1139
- const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry, } = server;
1140
- logger.info("MCP SDD Server starting...", {
1141
- version: process.env.npm_package_version ?? "1.0.0",
1142
- nodeVersion: process.version,
1143
- pid: process.pid,
1144
- });
1145
- await mcpServer.start();
1146
- // Get plugin system statistics
1147
- const pluginStats = await pluginManager.getAllPlugins();
1148
- const hookStats = await hookSystem.getAllHooks();
1149
- const toolStats = await toolRegistry.getAllTools();
1150
- const steeringStats = await steeringRegistry.getSteeringStatistics();
1151
- logger.info("MCP SDD Server ready for connections", {
1152
- capabilities: {
1153
- workflow: "5-phase SDD workflow state machine (INIT→REQUIREMENTS→DESIGN→TASKS→IMPLEMENTATION)",
1154
- validation: "Cross-phase validation with approval gates and rollback support",
1155
- initialization: "Project setup with .spec directory structure and spec.json",
1156
- context: "Project memory with codebase analysis and context persistence",
1157
- steering: "Dynamic steering document management with Always/Conditional/Manual modes",
1158
- quality: "Linus-style code review with 5-layer analysis framework",
1159
- i18n: "10-language support with cultural adaptation",
1160
- plugins: `${pluginStats.length} plugins loaded with extensibility framework`,
1161
- templates: "Handlebars-based template generation with inheritance",
1162
- },
1163
- tools: {
1164
- count: 11,
1165
- categories: [
1166
- "sdd-init",
1167
- "sdd-requirements",
1168
- "sdd-design",
1169
- "sdd-tasks",
1170
- "sdd-implement",
1171
- "sdd-status",
1172
- "sdd-approve",
1173
- "sdd-review-test-cases",
1174
- "sdd-quality-check",
1175
- "sdd-context-load",
1176
- "sdd-template-render",
1177
- ],
1178
- pluginTools: Object.keys(toolStats).length,
1179
- },
1180
- hooks: {
1181
- registered: Object.keys(hookStats).length,
1182
- phases: [
1183
- "PRE_INIT",
1184
- "POST_INIT",
1185
- "PRE_REQUIREMENTS",
1186
- "POST_REQUIREMENTS",
1187
- "PRE_DESIGN",
1188
- "POST_DESIGN",
1189
- "PRE_TASKS",
1190
- "POST_TASKS",
1191
- "PRE_IMPLEMENTATION",
1192
- "POST_IMPLEMENTATION",
1193
- ],
1194
- },
1195
- steering: {
1196
- documents: steeringStats.totalDocuments,
1197
- plugins: Object.keys(steeringStats.documentsByPlugin).length,
1198
- modes: steeringStats.documentsByMode,
1199
- },
1200
- });
1201
- // Handle graceful shutdown
1202
- process.on("SIGINT", async () => {
1203
- logger.info("Received SIGINT, shutting down gracefully...");
1204
- await mcpServer.stop();
1205
- process.exit(0);
1206
- });
1207
- process.on("SIGTERM", async () => {
1208
- logger.info("Received SIGTERM, shutting down gracefully...");
1209
- await mcpServer.stop();
1210
- process.exit(0);
1211
- });
1212
- }
1213
- }
1214
- catch (error) {
1215
- // Only log startup errors in non-MCP mode
1216
- if (!isMCPMode) {
1217
- console.error("Failed to start MCP SDD Server:", error);
1218
- }
1219
- process.exit(1);
1220
- }
1221
- }
1222
- // Only run main if this file is executed directly
1223
- if (import.meta.url === `file://${process.argv[1]}`) {
1224
- void main();
37
+ if (isDirectExecution()) {
38
+ startMCPServer().catch((error) => {
39
+ process.stderr.write(`Failed to start MCP server: ${error instanceof Error ? error.message : String(error)}\n`);
40
+ process.exitCode = 1;
41
+ });
1225
42
  }
1226
43
  //# sourceMappingURL=index.js.map