@hegemonart/get-design-done 1.31.0 → 1.31.5

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 (163) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +44 -0
  4. package/NOTICE +224 -0
  5. package/README.md +1 -1
  6. package/agents/design-authority-watcher.md +1 -1
  7. package/agents/perf-analyzer.md +2 -2
  8. package/bin/gdd-mcp +78 -0
  9. package/bin/gdd-sdk +34 -24
  10. package/bin/gdd-state-mcp +78 -0
  11. package/{README.de.md → docs/i18n/README.de.md} +1 -1
  12. package/{README.fr.md → docs/i18n/README.fr.md} +1 -1
  13. package/{README.it.md → docs/i18n/README.it.md} +1 -1
  14. package/{README.ja.md → docs/i18n/README.ja.md} +1 -1
  15. package/{README.ko.md → docs/i18n/README.ko.md} +1 -1
  16. package/{README.zh-CN.md → docs/i18n/README.zh-CN.md} +1 -1
  17. package/hooks/_hook-emit.js +1 -1
  18. package/hooks/budget-enforcer.ts +5 -5
  19. package/hooks/context-exhaustion.ts +2 -2
  20. package/hooks/gdd-precompact-snapshot.js +3 -3
  21. package/hooks/gdd-read-injection-scanner.ts +2 -2
  22. package/hooks/gdd-sessionstart-recap.js +1 -1
  23. package/hooks/gdd-turn-closeout.js +1 -1
  24. package/package.json +20 -9
  25. package/recipes/.gitkeep +0 -0
  26. package/reference/schemas/recipe.schema.json +33 -0
  27. package/scripts/cli/gdd-events.mjs +5 -5
  28. package/scripts/lib/cache/gdd-cache-manager.cjs +1 -1
  29. package/scripts/lib/cli/index.ts +22 -160
  30. package/scripts/lib/connection-probe/index.cjs +1 -1
  31. package/scripts/lib/discuss-parallel-runner/aggregator.ts +1 -1
  32. package/scripts/lib/discuss-parallel-runner/index.ts +1 -1
  33. package/scripts/lib/error-classifier.cjs +24 -227
  34. package/scripts/lib/event-stream/index.ts +25 -193
  35. package/scripts/lib/gdd-errors/index.ts +24 -213
  36. package/scripts/lib/gdd-state/index.ts +23 -161
  37. package/scripts/lib/iteration-budget.cjs +23 -199
  38. package/scripts/lib/jittered-backoff.cjs +24 -107
  39. package/scripts/lib/lockfile.cjs +23 -195
  40. package/scripts/lib/logger/index.ts +1 -1
  41. package/scripts/lib/parallelism-engine/concurrency-tuner.cjs +1 -1
  42. package/scripts/lib/perf-analyzer/index.cjs +1 -1
  43. package/scripts/lib/pipeline-runner/index.ts +4 -4
  44. package/scripts/lib/pipeline-runner/state-machine.ts +1 -1
  45. package/scripts/lib/prompt-dedup/index.cjs +1 -1
  46. package/scripts/lib/rate-guard.cjs +2 -2
  47. package/scripts/lib/recipe-loader.cjs +142 -0
  48. package/scripts/lib/session-runner/errors.ts +3 -3
  49. package/scripts/lib/session-runner/index.ts +3 -3
  50. package/scripts/lib/session-runner/transcript.ts +1 -1
  51. package/scripts/lib/tool-scoping/index.ts +1 -1
  52. package/scripts/mcp-servers/gdd-mcp/server.ts +29 -311
  53. package/scripts/mcp-servers/gdd-state/server.ts +28 -282
  54. package/sdk/README.md +45 -0
  55. package/{scripts/lib → sdk}/cli/commands/audit.ts +3 -3
  56. package/{scripts/lib → sdk}/cli/commands/init.ts +3 -3
  57. package/{scripts/lib → sdk}/cli/commands/query.ts +4 -4
  58. package/{scripts/lib → sdk}/cli/commands/run.ts +5 -5
  59. package/{scripts/lib → sdk}/cli/commands/stage.ts +5 -5
  60. package/sdk/cli/index.js +8091 -0
  61. package/sdk/cli/index.ts +172 -0
  62. package/{scripts/lib → sdk}/cli/parse-args.ts +2 -2
  63. package/{scripts/lib/gdd-errors → sdk/errors}/classification.ts +1 -1
  64. package/sdk/errors/index.ts +218 -0
  65. package/{scripts/lib → sdk}/event-stream/emitter.ts +1 -1
  66. package/sdk/event-stream/index.ts +197 -0
  67. package/{scripts/lib → sdk}/event-stream/reader.ts +1 -1
  68. package/{scripts/lib → sdk}/event-stream/types.ts +2 -2
  69. package/{scripts/lib → sdk}/event-stream/writer.ts +1 -1
  70. package/sdk/index.ts +19 -0
  71. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/README.md +3 -3
  72. package/sdk/mcp/gdd-mcp/server.js +1924 -0
  73. package/sdk/mcp/gdd-mcp/server.ts +325 -0
  74. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_cycle_recap.ts +3 -3
  75. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_decisions_list.ts +2 -2
  76. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_events_tail.ts +3 -3
  77. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_health.ts +2 -2
  78. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_intel_get.ts +2 -2
  79. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_learnings_digest.ts +2 -2
  80. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_phase_current.ts +2 -2
  81. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_phases_list.ts +2 -2
  82. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_plans_list.ts +2 -2
  83. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_reflections_latest.ts +2 -2
  84. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_status.ts +3 -3
  85. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_telemetry_query.ts +3 -3
  86. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/index.ts +2 -2
  87. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/shared.ts +3 -3
  88. package/sdk/mcp/gdd-state/server.js +2790 -0
  89. package/sdk/mcp/gdd-state/server.ts +294 -0
  90. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_blocker.ts +3 -3
  91. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_decision.ts +3 -3
  92. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_must_have.ts +3 -3
  93. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/checkpoint.ts +2 -2
  94. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/frontmatter_update.ts +2 -2
  95. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/get.ts +3 -3
  96. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/index.ts +1 -1
  97. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/probe_connections.ts +3 -3
  98. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/resolve_blocker.ts +3 -3
  99. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/set_status.ts +2 -2
  100. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/shared.ts +8 -8
  101. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/transition_stage.ts +4 -4
  102. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/update_progress.ts +2 -2
  103. package/sdk/primitives/error-classifier.cjs +232 -0
  104. package/sdk/primitives/iteration-budget.cjs +205 -0
  105. package/sdk/primitives/jittered-backoff.cjs +112 -0
  106. package/sdk/primitives/lockfile.cjs +201 -0
  107. package/{scripts/lib/gdd-state → sdk/state}/gates.ts +1 -1
  108. package/sdk/state/index.ts +167 -0
  109. package/{scripts/lib/gdd-state → sdk/state}/lockfile.ts +1 -1
  110. package/{scripts/lib/gdd-state → sdk/state}/mutator.ts +1 -1
  111. package/{scripts/lib/gdd-state → sdk/state}/parser.ts +1 -1
  112. package/{scripts/lib/gdd-state → sdk/state}/types.ts +4 -4
  113. package/skills/quality-gate/SKILL.md +2 -2
  114. package/scripts/aggregate-agent-metrics.ts +0 -282
  115. package/scripts/bootstrap-manifest.txt +0 -3
  116. package/scripts/bootstrap.sh +0 -80
  117. package/scripts/build-distribution-bundles.cjs +0 -549
  118. package/scripts/build-intel.cjs +0 -486
  119. package/scripts/codegen-schema-types.ts +0 -149
  120. package/scripts/detect-stale-refs.cjs +0 -107
  121. package/scripts/e2e/run-headless.ts +0 -514
  122. package/scripts/extract-changelog-section.cjs +0 -58
  123. package/scripts/gsd-cleanup-incubator.cjs +0 -367
  124. package/scripts/injection-patterns.cjs +0 -58
  125. package/scripts/lint-agentskills-spec.cjs +0 -457
  126. package/scripts/release-smoke-test.cjs +0 -200
  127. package/scripts/rollback-release.sh +0 -42
  128. package/scripts/run-injection-scanner-ci.cjs +0 -83
  129. package/scripts/tests/test-authority-rejected-kinds.sh +0 -58
  130. package/scripts/tests/test-authority-watcher-diff.sh +0 -113
  131. package/scripts/tests/test-motion-provenance.sh +0 -64
  132. package/scripts/validate-frontmatter.ts +0 -409
  133. package/scripts/validate-incubator-scope.cjs +0 -133
  134. package/scripts/validate-schemas.ts +0 -401
  135. package/scripts/validate-skill-length.cjs +0 -283
  136. package/scripts/verify-version-sync.cjs +0 -30
  137. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_cycle_recap.schema.json +0 -0
  138. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_decisions_list.schema.json +0 -0
  139. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_events_tail.schema.json +0 -0
  140. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_health.schema.json +0 -0
  141. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_intel_get.schema.json +0 -0
  142. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_learnings_digest.schema.json +0 -0
  143. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_phase_current.schema.json +0 -0
  144. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_phases_list.schema.json +0 -0
  145. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_plans_list.schema.json +0 -0
  146. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_reflections_latest.schema.json +0 -0
  147. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_status.schema.json +0 -0
  148. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_telemetry_query.schema.json +0 -0
  149. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_blocker.schema.json +0 -0
  150. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_decision.schema.json +0 -0
  151. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_must_have.schema.json +0 -0
  152. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/checkpoint.schema.json +0 -0
  153. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/frontmatter_update.schema.json +0 -0
  154. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/get.schema.json +0 -0
  155. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/probe_connections.schema.json +0 -0
  156. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/resolve_blocker.schema.json +0 -0
  157. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/set_status.schema.json +0 -0
  158. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/transition_stage.schema.json +0 -0
  159. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/update_progress.schema.json +0 -0
  160. /package/{scripts/lib → sdk/primitives}/error-classifier.d.cts +0 -0
  161. /package/{scripts/lib → sdk/primitives}/iteration-budget.d.cts +0 -0
  162. /package/{scripts/lib → sdk/primitives}/jittered-backoff.d.cts +0 -0
  163. /package/{scripts/lib → sdk/primitives}/lockfile.d.cts +0 -0
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env -S node --experimental-strip-types
2
+ // sdk/mcp/gdd-mcp/server.ts
3
+ //
4
+ // MCP server `gdd-mcp` — read-mostly project-state surface (Phase 27.7).
5
+ // Exposes STATE.md sections, phases, decisions, plans, telemetry, intel
6
+ // slices, and the latest reflection as typed MCP tools backed by the
7
+ // same `scripts/lib/*` + `sdk/*` modules the CLI uses.
8
+ // (Moved from scripts/mcp-servers/gdd-mcp/ to sdk/mcp/gdd-mcp/ in Plan
9
+ // 31-5-05 for MCP-server symmetry with sdk/mcp/gdd-state/ — D-08.)
10
+ //
11
+ // Lifecycle (mirrors Phase 20 `gdd-state` server):
12
+ // 1. Construct a low-level Server (we use the low-level surface so we
13
+ // can speak JSON Schema directly — the high-level McpServer wants
14
+ // Zod shapes, and our per-tool schemas are Draft-07 JSON.)
15
+ // 2. Register `tools/list` — returns the registered tools with their
16
+ // input JSON Schemas loaded from disk. Scaffold ships with 0
17
+ // tools; Plan 27.7-02 populates `TOOL_MODULES` with 12 entries.
18
+ // 3. Register `tools/call` — dispatches by name to the matching
19
+ // handler. Each handler returns a typed ToolResponse; the server
20
+ // wraps it into the MCP CallToolResult shape. Unknown tool names
21
+ // return `isError: true` with a structured payload.
22
+ // 4. Attach StdioServerTransport; await connect. NO port allocation
23
+ // (D-05 stdio-only).
24
+ // 5. On SIGINT / SIGTERM: close the transport, exit 0. Re-entrant
25
+ // shutdown is guarded with a module-level `SHUTTING_DOWN` flag.
26
+ //
27
+ // Project-root discovery (D-05): `resolveProjectRoot()` lives in
28
+ // `./tools/shared.ts` and walks up from `process.cwd()` looking for
29
+ // `.design/` OR `.planning/` OR `.claude-plugin/plugin.json`. Server
30
+ // infrastructure is allowed to import `node:fs`/`node:path` directly;
31
+ // only individual TOOL files are bound by the thin-wrapper rule (D-06).
32
+ //
33
+ // Invariant: handler throws are contained. The dispatcher wraps every
34
+ // call in a try/catch that funnels through `toToolError()` — the MCP
35
+ // harness never sees an uncaught throw from our tools.
36
+
37
+ import { readFileSync, existsSync } from 'node:fs';
38
+ import { dirname, join, resolve } from 'node:path';
39
+
40
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
41
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
42
+ import {
43
+ CallToolRequestSchema,
44
+ ListToolsRequestSchema,
45
+ } from '@modelcontextprotocol/sdk/types.js';
46
+
47
+ import { toToolError } from '../../errors/classification.ts';
48
+ import { TOOL_MODULES, type ToolModule } from './tools/index.ts';
49
+
50
+ /** Server metadata advertised on initialize. */
51
+ export const SERVER_NAME = 'gdd-mcp';
52
+ export const SERVER_VERSION = '1.27.7';
53
+
54
+ /**
55
+ * Resolve this module's directory. We deliberately avoid `import.meta.url`
56
+ * (not permitted by our tsconfig's Node16+CommonJS-compatible module
57
+ * resolution) and `__dirname` (not portable under strip-types ESM).
58
+ *
59
+ * Strategy: when this module is invoked as a script, `process.argv[1]`
60
+ * points at this file; resolve its dirname. When it is imported for
61
+ * tests, we fall back to walking from `process.cwd()` — tests run
62
+ * from the repo root by convention, so `sdk/mcp/gdd-mcp`
63
+ * resolves reliably. Both branches are canonicalized against the
64
+ * on-disk tools directory.
65
+ */
66
+ function here(): string {
67
+ const expectedRel = join('sdk', 'mcp', 'gdd-mcp');
68
+ // Script invocation: process.argv[1] === .../server.ts (or a shim).
69
+ const entry = process.argv[1];
70
+ if (typeof entry === 'string' && entry.length > 0) {
71
+ const entryDir = dirname(resolve(entry));
72
+ if (existsSync(join(entryDir, 'tools', 'index.ts'))) {
73
+ return entryDir;
74
+ }
75
+ }
76
+ // Library-import path (tests): walk cwd forward.
77
+ const candidate = resolve(process.cwd(), expectedRel);
78
+ if (existsSync(join(candidate, 'tools', 'index.ts'))) {
79
+ return candidate;
80
+ }
81
+ // Last-resort: return the expected path even if it does not exist —
82
+ // the subsequent readFileSync() call will produce a clear error.
83
+ return candidate;
84
+ }
85
+
86
+ /** Eager cache of input schemas keyed by tool name. We load them once at
87
+ * startup so a tool-call handler never hits the filesystem in the hot
88
+ * path; subsequent schema edits (JSON file on disk) require a server
89
+ * restart, which matches every other part of the pipeline.
90
+ *
91
+ * Scaffold ships with 0 tools — loadTools() returns []. Plan 27.7-02
92
+ * adds 12 tool modules, each with its own `schemaPath` pointing into
93
+ * `sdk/mcp/gdd-mcp/schemas/`. */
94
+ interface LoadedTool extends ToolModule {
95
+ inputSchema: Record<string, unknown>;
96
+ }
97
+
98
+ function loadTools(): LoadedTool[] {
99
+ const baseDir = here();
100
+ return TOOL_MODULES.map((m) => {
101
+ const absPath = join(baseDir, 'tools', m.schemaPath);
102
+ const raw = readFileSync(absPath, 'utf8');
103
+ const parsed = JSON.parse(raw) as {
104
+ properties?: {
105
+ input?: { type?: string; properties?: Record<string, unknown> };
106
+ };
107
+ };
108
+ // The per-tool schema files are Draft-07 wrappers shaped as:
109
+ // { type: "object", properties: { input: {...}, output: {...} } }
110
+ // MCP's tools/list advertises only the INPUT half. We project
111
+ // `properties.input` here; when the schema is malformed we fall
112
+ // back to an open object so the tool is still listable.
113
+ const rawInput = parsed.properties?.input;
114
+ const inputSchema: Record<string, unknown> =
115
+ rawInput !== undefined && typeof rawInput === 'object'
116
+ ? (rawInput as Record<string, unknown>)
117
+ : { type: 'object' };
118
+ if (!('type' in inputSchema)) inputSchema['type'] = 'object';
119
+ return { ...m, inputSchema };
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Tool descriptions — short, scannable, lifted from the plan. Skill
125
+ * prose uses these verbatim when suggesting a tool to the model.
126
+ *
127
+ * Plan 27.7-02 populates 12 entries — one per tool name in the canonical
128
+ * 12-tool list.
129
+ */
130
+ export const TOOL_DESCRIPTIONS: Record<string, string> = {
131
+ gdd_status:
132
+ 'gdd_status: current cycle phase, branch, last-3 decisions, last-3 completed plans, blocker count.',
133
+ gdd_phase_current:
134
+ 'gdd_phase_current: STATE.md <position> block (phase, stage, task_progress, status).',
135
+ gdd_phases_list:
136
+ 'gdd_phases_list: parsed ROADMAP.md overview (phase number, name, target version, shipped/planned).',
137
+ gdd_plans_list:
138
+ 'gdd_plans_list: plans tracked in STATE.md must_haves (optionally filtered by input.phase).',
139
+ gdd_decisions_list:
140
+ 'gdd_decisions_list: decisions from STATE.md (optionally filtered by input.status).',
141
+ gdd_intel_get:
142
+ 'gdd_intel_get: read a slice from .design/intel/ (input.slice_id required); directory_not_found if absent.',
143
+ gdd_telemetry_query:
144
+ 'gdd_telemetry_query: typed reader over .design/telemetry/*.jsonl with type/since/limit filters.',
145
+ gdd_cycle_recap:
146
+ 'gdd_cycle_recap: diff current STATE against latest .design/snapshots/ snapshot; directory_not_found if absent.',
147
+ gdd_reflections_latest:
148
+ 'gdd_reflections_latest: newest .design/reflections/ file (excerpt <= 4 KB); directory_not_found if absent.',
149
+ gdd_learnings_digest:
150
+ 'gdd_learnings_digest: aggregate last N reflections into a compact digest (<= 5 KB).',
151
+ gdd_events_tail:
152
+ 'gdd_events_tail: last-N events from .design/telemetry/events.jsonl with optional type filter.',
153
+ gdd_health:
154
+ 'gdd_health: read-only mirror of gdd-health SKILL — 4 checks (CLAUDE.md, .planning/, .design/, package.json).',
155
+ };
156
+
157
+ /** Human-readable annotation hints (MCP clients use these to style the
158
+ * tool in UI). `readOnlyHint: true` — tells clients this tool does NOT
159
+ * modify disk. v1 is read-only (D-04) so every entry is `true`. */
160
+ export const TOOL_READONLY: Record<string, boolean> = {
161
+ gdd_status: true,
162
+ gdd_phase_current: true,
163
+ gdd_phases_list: true,
164
+ gdd_plans_list: true,
165
+ gdd_decisions_list: true,
166
+ gdd_intel_get: true,
167
+ gdd_telemetry_query: true,
168
+ gdd_cycle_recap: true,
169
+ gdd_reflections_latest: true,
170
+ gdd_learnings_digest: true,
171
+ gdd_events_tail: true,
172
+ gdd_health: true,
173
+ };
174
+
175
+ /**
176
+ * Build the MCP server. The tools list and call handlers are the only
177
+ * two request handlers we register; everything else (initialize, ping,
178
+ * cancellation, shutdown) is handled internally by the Protocol class.
179
+ */
180
+ export function buildServer(): Server {
181
+ const tools = loadTools();
182
+ const byName: Map<string, LoadedTool> = new Map();
183
+ for (const t of tools) byName.set(t.name, t);
184
+
185
+ const server = new Server(
186
+ { name: SERVER_NAME, version: SERVER_VERSION },
187
+ {
188
+ capabilities: { tools: {} },
189
+ },
190
+ );
191
+
192
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
193
+ return {
194
+ tools: tools.map((t) => {
195
+ const description = TOOL_DESCRIPTIONS[t.name] ?? t.name;
196
+ const readOnly = TOOL_READONLY[t.name] ?? true;
197
+ return {
198
+ name: t.name,
199
+ description,
200
+ inputSchema: t.inputSchema as {
201
+ type: 'object';
202
+ properties?: Record<string, unknown>;
203
+ required?: string[];
204
+ },
205
+ annotations: {
206
+ readOnlyHint: readOnly,
207
+ destructiveHint: !readOnly,
208
+ idempotentHint: false,
209
+ },
210
+ };
211
+ }),
212
+ };
213
+ });
214
+
215
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
216
+ const { name: toolName, arguments: args } = req.params;
217
+ const tool = byName.get(toolName);
218
+ if (tool === undefined) {
219
+ // Unknown tool — return as CallToolResult isError=true so the
220
+ // client gets a structured error rather than a JSON-RPC error.
221
+ const payload = toToolError(
222
+ new Error(`unknown tool: ${toolName}`),
223
+ );
224
+ return {
225
+ isError: true,
226
+ content: [
227
+ {
228
+ type: 'text' as const,
229
+ text: JSON.stringify({ success: false, error: payload.error }),
230
+ },
231
+ ],
232
+ structuredContent: { success: false, error: payload.error },
233
+ };
234
+ }
235
+
236
+ let response;
237
+ try {
238
+ response = await tool.handle(args ?? {});
239
+ } catch (err) {
240
+ // Defensive catch — handlers shouldn't throw, but if one does
241
+ // we translate rather than crashing the server.
242
+ const payload = toToolError(err);
243
+ response = { success: false as const, error: payload.error };
244
+ }
245
+
246
+ const text = JSON.stringify(response);
247
+ if (response.success === true) {
248
+ return {
249
+ content: [{ type: 'text' as const, text }],
250
+ structuredContent: response as unknown as Record<string, unknown>,
251
+ };
252
+ }
253
+ return {
254
+ isError: true,
255
+ content: [{ type: 'text' as const, text }],
256
+ structuredContent: response as unknown as Record<string, unknown>,
257
+ };
258
+ });
259
+
260
+ return server;
261
+ }
262
+
263
+ /**
264
+ * Run the server against stdio and block until the transport closes.
265
+ * Called from CLI when this file is invoked as a script.
266
+ */
267
+ export async function runStdio(): Promise<void> {
268
+ const server = buildServer();
269
+ const transport = new StdioServerTransport();
270
+
271
+ const shutdown = async (signal: string): Promise<void> => {
272
+ // Re-entrant: signal handlers can fire more than once on flaky
273
+ // shells. Guard with a module-level flag.
274
+ if (SHUTTING_DOWN) return;
275
+ SHUTTING_DOWN = true;
276
+ try {
277
+ await server.close();
278
+ } catch {
279
+ // best-effort; we're exiting anyway.
280
+ }
281
+ // SIGTERM / SIGINT convention: exit(0) — orderly shutdown.
282
+ process.exit(signal === 'SIGTERM' ? 0 : 0);
283
+ };
284
+
285
+ process.on('SIGINT', () => {
286
+ void shutdown('SIGINT');
287
+ });
288
+ process.on('SIGTERM', () => {
289
+ void shutdown('SIGTERM');
290
+ });
291
+
292
+ await server.connect(transport);
293
+ }
294
+
295
+ /** Re-entrancy guard for `shutdown()`. */
296
+ let SHUTTING_DOWN = false;
297
+
298
+ /**
299
+ * Are we being invoked as a script? We compare the argv[1] file path's
300
+ * basename to `server.ts` — test imports never match this because
301
+ * `node --test tests/*.ts` sets argv[1] to the test runner entry, not
302
+ * our file. A direct `node sdk/mcp/gdd-mcp/server.ts`
303
+ * invocation DOES match. The Windows-safe path normalization uses
304
+ * `.replace(/\\/g, '/')` before the endsWith check.
305
+ */
306
+ // Extension-agnostic (.ts | .js | .cjs | .mjs): the dual-mode bin trampoline
307
+ // (Plan 31-5-9.5, D-16) runs the raw `.ts` in-repo via --experimental-strip-types
308
+ // AND the esbuild-bundled `.js` from a packed/installed tarball. argv[1] ends in
309
+ // `.js` in the compiled path, so a `.ts`-only check would never start the server.
310
+ function isMain(): boolean {
311
+ const entry = process.argv[1];
312
+ if (typeof entry !== 'string' || entry.length === 0) return false;
313
+ return /sdk\/mcp\/gdd-mcp\/server\.(ts|js|cjs|mjs)$/.test(
314
+ entry.replace(/\\/g, '/'),
315
+ );
316
+ }
317
+
318
+ if (isMain()) {
319
+ runStdio().catch((err) => {
320
+ const msg = err instanceof Error ? err.message : String(err);
321
+ // eslint-disable-next-line no-console
322
+ console.error(`[gdd-mcp] fatal: ${msg}`);
323
+ process.exit(1);
324
+ });
325
+ }
@@ -1,10 +1,10 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_cycle_recap.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_cycle_recap.ts
2
2
  //
3
3
  // Plan 27.7-02. Diffs current STATE.md against the latest .design/snapshots/
4
4
  // snapshot. SnapshotNotFoundError → directory_not_found via errorResponse.
5
5
 
6
- import { read } from '../../../lib/gdd-state/index.ts';
7
- import { readLatestSnapshot } from '../../../lib/snapshot-reader/index.cjs';
6
+ import { read } from '../../../state/index.ts';
7
+ import { readLatestSnapshot } from '../../../../scripts/lib/snapshot-reader/index.cjs';
8
8
  import { errorResponse, okResponse, resolveProjectRoot, resolveStatePath, type ToolResponse } from './shared.ts';
9
9
 
10
10
  export const name = 'gdd_cycle_recap';
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_decisions_list.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_decisions_list.ts
2
2
  //
3
3
  // Plan 27.7-02. Reads <decisions> block from STATE.md. Optional
4
4
  // input.status filter narrows the list to one DecisionStatus.
5
5
 
6
- import { read } from '../../../lib/gdd-state/index.ts';
6
+ import { read } from '../../../state/index.ts';
7
7
  import {
8
8
  errorResponse,
9
9
  okResponse,
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_events_tail.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_events_tail.ts
2
2
  //
3
3
  // Plan 27.7-02. Last-N events from .design/telemetry/events.jsonl with
4
- // optional type filter. Uses scripts/lib/event-stream readEvents.
4
+ // optional type filter. Uses sdk/event-stream readEvents.
5
5
 
6
- import { readEvents } from '../../../lib/event-stream/index.ts';
6
+ import { readEvents } from '../../../event-stream/index.ts';
7
7
  import { errorResponse, okResponse, resolveTelemetryDir, type ToolResponse } from './shared.ts';
8
8
 
9
9
  export const name = 'gdd_events_tail';
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_health.ts
2
2
  //
3
3
  // Plan 27.7-02 (lib renamed to health-mirror in Phase 30.6-08 per D-10).
4
4
  // Read-only mirror of skills/health/SKILL.md output. No subprocess spawn — pure inspection.
5
5
 
6
- import { getHealthChecks } from '../../../lib/health-mirror/index.cjs';
6
+ import { getHealthChecks } from '../../../../scripts/lib/health-mirror/index.cjs';
7
7
  import { errorResponse, okResponse, resolveProjectRoot, type ToolResponse } from './shared.ts';
8
8
 
9
9
  export const name = 'gdd_health';
@@ -1,10 +1,10 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_intel_get.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_intel_get.ts
2
2
  //
3
3
  // Plan 27.7-02. Reads a .design/intel/ slice via scripts/lib/intel-store/
4
4
  // (Warning #7: NOT design-search.cjs). IntelNotFoundError surfaces
5
5
  // gracefully via errorResponse's mcp_code projection (Warning #5).
6
6
 
7
- import { readSlice } from '../../../lib/intel-store/index.cjs';
7
+ import { readSlice } from '../../../../scripts/lib/intel-store/index.cjs';
8
8
  import { errorResponse, okResponse, resolveProjectRoot, type ToolResponse } from './shared.ts';
9
9
 
10
10
  export const name = 'gdd_intel_get';
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_learnings_digest.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_learnings_digest.ts
2
2
  //
3
3
  // Plan 27.7-02. Aggregates last N reflections into a <= 5 KB digest
4
4
  // via scripts/lib/reflections-reader/.
5
5
 
6
- import { readNReflections, digestReflections } from '../../../lib/reflections-reader/index.cjs';
6
+ import { readNReflections, digestReflections } from '../../../../scripts/lib/reflections-reader/index.cjs';
7
7
  import { errorResponse, okResponse, resolveProjectRoot, type ToolResponse } from './shared.ts';
8
8
 
9
9
  export const name = 'gdd_learnings_digest';
@@ -1,8 +1,8 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_phase_current.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_phase_current.ts
2
2
  //
3
3
  // Plan 27.7-02. Returns the <position> block from STATE.md.
4
4
 
5
- import { read } from '../../../lib/gdd-state/index.ts';
5
+ import { read } from '../../../state/index.ts';
6
6
  import {
7
7
  errorResponse,
8
8
  okResponse,
@@ -1,11 +1,11 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_phases_list.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_phases_list.ts
2
2
  //
3
3
  // Plan 27.7-02. Parses .planning/ROADMAP.md via scripts/lib/roadmap-reader.
4
4
 
5
5
  import {
6
6
  readRoadmapMd,
7
7
  parsePhases,
8
- } from '../../../lib/roadmap-reader/index.cjs';
8
+ } from '../../../../scripts/lib/roadmap-reader/index.cjs';
9
9
  import {
10
10
  errorResponse,
11
11
  okResponse,
@@ -1,11 +1,11 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_plans_list.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_plans_list.ts
2
2
  //
3
3
  // Plan 27.7-02. STATE.md does not have a dedicated <plans> block — we
4
4
  // surface must_haves as the closest analog (the per-plan acceptance
5
5
  // criteria the pipeline tracks). Input.phase is reserved for future
6
6
  // multi-phase indexing.
7
7
 
8
- import { read } from '../../../lib/gdd-state/index.ts';
8
+ import { read } from '../../../state/index.ts';
9
9
  import {
10
10
  errorResponse,
11
11
  okResponse,
@@ -1,10 +1,10 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_reflections_latest.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_reflections_latest.ts
2
2
  //
3
3
  // Plan 27.7-02. Reads newest reflection under .design/reflections/.
4
4
  // ReflectionsNotFoundError surfaces as mcp_code='directory_not_found'
5
5
  // via errorResponse (Warning #5).
6
6
 
7
- import { readLatestReflection } from '../../../lib/reflections-reader/index.cjs';
7
+ import { readLatestReflection } from '../../../../scripts/lib/reflections-reader/index.cjs';
8
8
  import { errorResponse, okResponse, resolveProjectRoot, type ToolResponse } from './shared.ts';
9
9
 
10
10
  export const name = 'gdd_reflections_latest';
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_status.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_status.ts
2
2
  //
3
- // Plan 27.7-02. Thin wrapper over scripts/lib/gdd-state. NO fs/path
3
+ // Plan 27.7-02. Thin wrapper over sdk/state. NO fs/path
4
4
  // imports here — all I/O via gdd-state.read() + shared.ts helpers.
5
5
 
6
- import { read } from '../../../lib/gdd-state/index.ts';
6
+ import { read } from '../../../state/index.ts';
7
7
  import {
8
8
  errorResponse,
9
9
  okResponse,
@@ -1,9 +1,9 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/gdd_telemetry_query.ts
1
+ // sdk/mcp/gdd-mcp/tools/gdd_telemetry_query.ts
2
2
  //
3
3
  // Plan 27.7-02. Typed reader over .design/telemetry/*.jsonl via
4
- // scripts/lib/event-stream/index.ts readEvents.
4
+ // sdk/event-stream/index.ts readEvents.
5
5
 
6
- import { readEvents } from '../../../lib/event-stream/index.ts';
6
+ import { readEvents } from '../../../event-stream/index.ts';
7
7
  import { errorResponse, okResponse, resolveTelemetryDir, type ToolResponse } from './shared.ts';
8
8
 
9
9
  export const name = 'gdd_telemetry_query';
@@ -1,4 +1,4 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/index.ts
1
+ // sdk/mcp/gdd-mcp/tools/index.ts
2
2
  //
3
3
  // Tool registry for `gdd-mcp`. Plan 27.7-02 populates with 12 read-only
4
4
  // tools. The 12-tool cap is D-03 (hard); enforced at module load by a
@@ -8,7 +8,7 @@
8
8
  // - Each tool exports `name`, `schemaPath`, and `handle` from its own
9
9
  // module (e.g. `./gdd_status.ts`).
10
10
  // - `schemaPath` is relative to THIS file's directory and points into
11
- // `scripts/mcp-servers/gdd-mcp/schemas/`. Server.ts joins it
11
+ // `sdk/mcp/gdd-mcp/schemas/`. Server.ts joins it
12
12
  // against `<baseDir>/tools/` to load the Draft-07 JSON.
13
13
  // - `TOOL_MODULES` is the canonical registry — server.ts iterates it
14
14
  // once at startup to populate the dispatch map.
@@ -1,4 +1,4 @@
1
- // scripts/mcp-servers/gdd-mcp/tools/shared.ts
1
+ // sdk/mcp/gdd-mcp/tools/shared.ts
2
2
  //
3
3
  // Shared helpers for gdd-mcp tools. resolveProjectRoot() implements the
4
4
  // D-05 walk-up algorithm: scan from process.cwd() upward looking for
@@ -15,8 +15,8 @@
15
15
  import { existsSync } from 'node:fs';
16
16
  import { dirname, join, resolve } from 'node:path';
17
17
 
18
- import { toToolError } from '../../../lib/gdd-errors/classification.ts';
19
- import type { ToolErrorPayload } from '../../../lib/gdd-errors/classification.ts';
18
+ import { toToolError } from '../../../errors/classification.ts';
19
+ import type { ToolErrorPayload } from '../../../errors/classification.ts';
20
20
 
21
21
  /** Public tool-handler response shape (consistent across all tools). */
22
22
  export type ToolResponse =