@hegemonart/get-design-done 1.27.6 → 1.27.7
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +6 -3
- package/CHANGELOG.md +49 -0
- package/package.json +5 -4
- package/reference/registry.json +7 -0
- package/reference/schemas/mcp-gdd-tools.schema.json +381 -0
- package/scripts/install.cjs +42 -0
- package/scripts/lib/gsd-health-mirror/index.cjs +105 -0
- package/scripts/lib/gsd-health-mirror/index.d.cts +14 -0
- package/scripts/lib/install/mcp-register.cjs +235 -0
- package/scripts/lib/install/mcp-register.d.cts +64 -0
- package/scripts/lib/intel-store/index.cjs +55 -0
- package/scripts/lib/intel-store/index.d.cts +11 -0
- package/scripts/lib/mcp-tools-lint/index.cjs +216 -0
- package/scripts/lib/mcp-tools-lint/index.d.cts +74 -0
- package/scripts/lib/reflections-reader/index.cjs +107 -0
- package/scripts/lib/reflections-reader/index.d.cts +18 -0
- package/scripts/lib/roadmap-reader/index.cjs +81 -0
- package/scripts/lib/roadmap-reader/index.d.cts +13 -0
- package/scripts/lib/snapshot-reader/index.cjs +70 -0
- package/scripts/lib/snapshot-reader/index.d.cts +28 -0
- package/scripts/mcp-servers/gdd-mcp/README.md +66 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_cycle_recap.schema.json +30 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_decisions_list.schema.json +32 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_events_tail.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_health.schema.json +30 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_intel_get.schema.json +24 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_learnings_digest.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_phase_current.schema.json +22 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_phases_list.schema.json +31 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_plans_list.schema.json +33 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_reflections_latest.schema.json +21 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_status.schema.json +23 -0
- package/scripts/mcp-servers/gdd-mcp/schemas/gdd_telemetry_query.schema.json +23 -0
- package/scripts/mcp-servers/gdd-mcp/server.ts +317 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_cycle_recap.ts +37 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_decisions_list.ts +33 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_events_tail.ts +26 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_health.ts +19 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_intel_get.ts +32 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_learnings_digest.ts +23 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_phase_current.ts +29 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_phases_list.ts +26 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_plans_list.ts +39 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_reflections_latest.ts +25 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_status.ts +31 -0
- package/scripts/mcp-servers/gdd-mcp/tools/gdd_telemetry_query.ts +27 -0
- package/scripts/mcp-servers/gdd-mcp/tools/index.ts +75 -0
- package/scripts/mcp-servers/gdd-mcp/tools/shared.ts +134 -0
- package/skills/health/SKILL.md +36 -0
- package/skills/next/SKILL.md +28 -3
- package/skills/progress/SKILL.md +21 -6
- package/skills/resume/SKILL.md +26 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/gdd_phases_list.ts
|
|
2
|
+
//
|
|
3
|
+
// Plan 27.7-02. Parses .planning/ROADMAP.md via scripts/lib/roadmap-reader.
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
readRoadmapMd,
|
|
7
|
+
parsePhases,
|
|
8
|
+
} from '../../../lib/roadmap-reader/index.cjs';
|
|
9
|
+
import {
|
|
10
|
+
errorResponse,
|
|
11
|
+
okResponse,
|
|
12
|
+
resolveProjectRoot,
|
|
13
|
+
type ToolResponse,
|
|
14
|
+
} from './shared.ts';
|
|
15
|
+
|
|
16
|
+
export const name = 'gdd_phases_list';
|
|
17
|
+
export const schemaPath = '../schemas/gdd_phases_list.schema.json';
|
|
18
|
+
|
|
19
|
+
export async function handle(_input: unknown): Promise<ToolResponse> {
|
|
20
|
+
try {
|
|
21
|
+
const md = await readRoadmapMd(resolveProjectRoot());
|
|
22
|
+
return okResponse({ phases: parsePhases(md) });
|
|
23
|
+
} catch (err) {
|
|
24
|
+
return errorResponse(err);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/gdd_plans_list.ts
|
|
2
|
+
//
|
|
3
|
+
// Plan 27.7-02. STATE.md does not have a dedicated <plans> block — we
|
|
4
|
+
// surface must_haves as the closest analog (the per-plan acceptance
|
|
5
|
+
// criteria the pipeline tracks). Input.phase is reserved for future
|
|
6
|
+
// multi-phase indexing.
|
|
7
|
+
|
|
8
|
+
import { read } from '../../../lib/gdd-state/index.ts';
|
|
9
|
+
import {
|
|
10
|
+
errorResponse,
|
|
11
|
+
okResponse,
|
|
12
|
+
resolveStatePath,
|
|
13
|
+
type ToolResponse,
|
|
14
|
+
} from './shared.ts';
|
|
15
|
+
|
|
16
|
+
export const name = 'gdd_plans_list';
|
|
17
|
+
export const schemaPath = '../schemas/gdd_plans_list.schema.json';
|
|
18
|
+
|
|
19
|
+
interface PlansInput {
|
|
20
|
+
phase?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function handle(input: unknown): Promise<ToolResponse> {
|
|
24
|
+
try {
|
|
25
|
+
const typed = (input ?? {}) as PlansInput;
|
|
26
|
+
const state = await read(resolveStatePath());
|
|
27
|
+
const plans = (state.must_haves ?? []).map((m) => ({
|
|
28
|
+
id: m.id,
|
|
29
|
+
name: m.text,
|
|
30
|
+
status: m.status,
|
|
31
|
+
}));
|
|
32
|
+
return okResponse({
|
|
33
|
+
phase: typed.phase ?? state.frontmatter.cycle ?? null,
|
|
34
|
+
plans,
|
|
35
|
+
});
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return errorResponse(err);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/gdd_reflections_latest.ts
|
|
2
|
+
//
|
|
3
|
+
// Plan 27.7-02. Reads newest reflection under .design/reflections/.
|
|
4
|
+
// ReflectionsNotFoundError surfaces as mcp_code='directory_not_found'
|
|
5
|
+
// via errorResponse (Warning #5).
|
|
6
|
+
|
|
7
|
+
import { readLatestReflection } from '../../../lib/reflections-reader/index.cjs';
|
|
8
|
+
import { errorResponse, okResponse, resolveProjectRoot, type ToolResponse } from './shared.ts';
|
|
9
|
+
|
|
10
|
+
export const name = 'gdd_reflections_latest';
|
|
11
|
+
export const schemaPath = '../schemas/gdd_reflections_latest.schema.json';
|
|
12
|
+
|
|
13
|
+
export async function handle(_input: unknown): Promise<ToolResponse> {
|
|
14
|
+
try {
|
|
15
|
+
const r = await readLatestReflection(resolveProjectRoot());
|
|
16
|
+
if (r === null) return okResponse({ cycle: null, path: null, content_excerpt: '' });
|
|
17
|
+
return okResponse({
|
|
18
|
+
cycle: r.cycle,
|
|
19
|
+
path: r.path,
|
|
20
|
+
content_excerpt: r.content.slice(0, 4096),
|
|
21
|
+
});
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return errorResponse(err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/gdd_status.ts
|
|
2
|
+
//
|
|
3
|
+
// Plan 27.7-02. Thin wrapper over scripts/lib/gdd-state. NO fs/path
|
|
4
|
+
// imports here — all I/O via gdd-state.read() + shared.ts helpers.
|
|
5
|
+
|
|
6
|
+
import { read } from '../../../lib/gdd-state/index.ts';
|
|
7
|
+
import {
|
|
8
|
+
errorResponse,
|
|
9
|
+
okResponse,
|
|
10
|
+
resolveStatePath,
|
|
11
|
+
type ToolResponse,
|
|
12
|
+
} from './shared.ts';
|
|
13
|
+
|
|
14
|
+
export const name = 'gdd_status';
|
|
15
|
+
export const schemaPath = '../schemas/gdd_status.schema.json';
|
|
16
|
+
|
|
17
|
+
export async function handle(_input: unknown): Promise<ToolResponse> {
|
|
18
|
+
try {
|
|
19
|
+
const state = await read(resolveStatePath());
|
|
20
|
+
const completed = (state.must_haves ?? []).filter((m) => m.status === 'pass');
|
|
21
|
+
return okResponse({
|
|
22
|
+
phase: state.frontmatter.cycle ?? null,
|
|
23
|
+
branch: process.env['GIT_BRANCH'] ?? null,
|
|
24
|
+
last_decisions: (state.decisions ?? []).slice(-3),
|
|
25
|
+
last_completed_plans: completed.slice(-3),
|
|
26
|
+
blocker_count: (state.blockers ?? []).length,
|
|
27
|
+
});
|
|
28
|
+
} catch (err) {
|
|
29
|
+
return errorResponse(err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/gdd_telemetry_query.ts
|
|
2
|
+
//
|
|
3
|
+
// Plan 27.7-02. Typed reader over .design/telemetry/*.jsonl via
|
|
4
|
+
// scripts/lib/event-stream/index.ts readEvents.
|
|
5
|
+
|
|
6
|
+
import { readEvents } from '../../../lib/event-stream/index.ts';
|
|
7
|
+
import { errorResponse, okResponse, resolveTelemetryDir, type ToolResponse } from './shared.ts';
|
|
8
|
+
|
|
9
|
+
export const name = 'gdd_telemetry_query';
|
|
10
|
+
export const schemaPath = '../schemas/gdd_telemetry_query.schema.json';
|
|
11
|
+
|
|
12
|
+
interface TelemetryInput { type?: string; since?: string; limit?: number; }
|
|
13
|
+
|
|
14
|
+
export async function handle(input: unknown): Promise<ToolResponse> {
|
|
15
|
+
try {
|
|
16
|
+
const typed = (input ?? {}) as TelemetryInput;
|
|
17
|
+
const limit = typeof typed.limit === 'number' && typed.limit > 0 ? typed.limit : 100;
|
|
18
|
+
const events: unknown[] = [];
|
|
19
|
+
const opts: { path: string; type?: string; since?: string } = { path: resolveTelemetryDir() + '/events.jsonl' };
|
|
20
|
+
if (typeof typed.type === 'string' && typed.type.length > 0) opts.type = typed.type;
|
|
21
|
+
if (typeof typed.since === 'string' && typed.since.length > 0) opts.since = typed.since;
|
|
22
|
+
for await (const ev of readEvents(opts)) { events.push(ev); if (events.length >= limit) break; }
|
|
23
|
+
return okResponse({ events });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return errorResponse(err);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/index.ts
|
|
2
|
+
//
|
|
3
|
+
// Tool registry for `gdd-mcp`. Plan 27.7-02 populates with 12 read-only
|
|
4
|
+
// tools. The 12-tool cap is D-03 (hard); enforced at module load by a
|
|
5
|
+
// runtime check + by tests in Plan 27.7-03.
|
|
6
|
+
//
|
|
7
|
+
// Convention (mirrors Phase 20 `gdd-state`):
|
|
8
|
+
// - Each tool exports `name`, `schemaPath`, and `handle` from its own
|
|
9
|
+
// module (e.g. `./gdd_status.ts`).
|
|
10
|
+
// - `schemaPath` is relative to THIS file's directory and points into
|
|
11
|
+
// `scripts/mcp-servers/gdd-mcp/schemas/`. Server.ts joins it
|
|
12
|
+
// against `<baseDir>/tools/` to load the Draft-07 JSON.
|
|
13
|
+
// - `TOOL_MODULES` is the canonical registry — server.ts iterates it
|
|
14
|
+
// once at startup to populate the dispatch map.
|
|
15
|
+
|
|
16
|
+
import type { ToolResponse } from './shared.ts';
|
|
17
|
+
|
|
18
|
+
import * as gdd_cycle_recap from './gdd_cycle_recap.ts';
|
|
19
|
+
import * as gdd_decisions_list from './gdd_decisions_list.ts';
|
|
20
|
+
import * as gdd_events_tail from './gdd_events_tail.ts';
|
|
21
|
+
import * as gdd_health from './gdd_health.ts';
|
|
22
|
+
import * as gdd_intel_get from './gdd_intel_get.ts';
|
|
23
|
+
import * as gdd_learnings_digest from './gdd_learnings_digest.ts';
|
|
24
|
+
import * as gdd_phase_current from './gdd_phase_current.ts';
|
|
25
|
+
import * as gdd_phases_list from './gdd_phases_list.ts';
|
|
26
|
+
import * as gdd_plans_list from './gdd_plans_list.ts';
|
|
27
|
+
import * as gdd_reflections_latest from './gdd_reflections_latest.ts';
|
|
28
|
+
import * as gdd_status from './gdd_status.ts';
|
|
29
|
+
import * as gdd_telemetry_query from './gdd_telemetry_query.ts';
|
|
30
|
+
|
|
31
|
+
export interface ToolModule {
|
|
32
|
+
/** Public tool name exposed via MCP (e.g. "gdd_status"). */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Path to the input/output Draft-07 JSON Schema, relative to this
|
|
35
|
+
* module's directory. Per-tool entries under `../schemas/`. */
|
|
36
|
+
schemaPath: string;
|
|
37
|
+
/** Executes the tool. Never throws — always returns a ToolResponse. */
|
|
38
|
+
handle: (input: unknown) => Promise<ToolResponse>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Canonical tool registry. 12 tools (D-03 hard cap). Order is
|
|
43
|
+
* alphabetical (after `gdd_status` which leads as the canonical entry).
|
|
44
|
+
* All tools are advertised equivalently in `tools/list`.
|
|
45
|
+
*/
|
|
46
|
+
export const TOOL_MODULES: readonly ToolModule[] = [
|
|
47
|
+
gdd_status,
|
|
48
|
+
gdd_cycle_recap,
|
|
49
|
+
gdd_decisions_list,
|
|
50
|
+
gdd_events_tail,
|
|
51
|
+
gdd_health,
|
|
52
|
+
gdd_intel_get,
|
|
53
|
+
gdd_learnings_digest,
|
|
54
|
+
gdd_phase_current,
|
|
55
|
+
gdd_phases_list,
|
|
56
|
+
gdd_plans_list,
|
|
57
|
+
gdd_reflections_latest,
|
|
58
|
+
gdd_telemetry_query,
|
|
59
|
+
] as const;
|
|
60
|
+
|
|
61
|
+
/** Canonical count. The plan caps this at 12 — if you add a tool past
|
|
62
|
+
* that bound, update the plan, the combined schema, and the lint
|
|
63
|
+
* test (Plan 27.7-03). */
|
|
64
|
+
export const TOOL_COUNT: number = TOOL_MODULES.length;
|
|
65
|
+
|
|
66
|
+
// Module-load runtime assertion of the 12-tool cap (D-03). A compile-time
|
|
67
|
+
// type guard is fragile against `readonly ToolModule[]` (the length type
|
|
68
|
+
// widens to `number`); the runtime check is cheap, deterministic, and
|
|
69
|
+
// fails fast on server boot if the registry ever drifts past the cap.
|
|
70
|
+
if (TOOL_COUNT > 12) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`gdd-mcp: TOOL_COUNT=${TOOL_COUNT} exceeds the 12-tool cap (D-03). ` +
|
|
73
|
+
'Add tool past 12 requires re-scoping in a new plan.',
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// scripts/mcp-servers/gdd-mcp/tools/shared.ts
|
|
2
|
+
//
|
|
3
|
+
// Shared helpers for gdd-mcp tools. resolveProjectRoot() implements the
|
|
4
|
+
// D-05 walk-up algorithm: scan from process.cwd() upward looking for
|
|
5
|
+
// `.design/` OR `.planning/` OR `.claude-plugin/plugin.json` — first
|
|
6
|
+
// match wins. Override: if process.env.GDD_PROJECT_ROOT is set, return
|
|
7
|
+
// it without walking.
|
|
8
|
+
//
|
|
9
|
+
// shared.ts itself is server-side infrastructure (it's the helper layer
|
|
10
|
+
// for tools, not a tool); it MAY import `node:fs` and `node:path`
|
|
11
|
+
// directly. The thin-wrapper rule (D-06) and the lint that will land
|
|
12
|
+
// in Plan 27.7-03 target individual TOOL files in this same directory,
|
|
13
|
+
// NOT this shared helper module.
|
|
14
|
+
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { dirname, join, resolve } from 'node:path';
|
|
17
|
+
|
|
18
|
+
import { toToolError } from '../../../lib/gdd-errors/classification.ts';
|
|
19
|
+
import type { ToolErrorPayload } from '../../../lib/gdd-errors/classification.ts';
|
|
20
|
+
|
|
21
|
+
/** Public tool-handler response shape (consistent across all tools). */
|
|
22
|
+
export type ToolResponse =
|
|
23
|
+
| { success: true; data: Record<string, unknown> }
|
|
24
|
+
| { success: false; error: ToolErrorPayload['error'] };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Shorthand for a `{success:true, data}` return with a plain object.
|
|
28
|
+
*/
|
|
29
|
+
export function okResponse(data: Record<string, unknown>): ToolResponse {
|
|
30
|
+
return { success: true, data };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Map an error into a tool-response `{success:false, error}` object.
|
|
35
|
+
* Single entry point for every handler — keeps the error-shape decision
|
|
36
|
+
* in one place.
|
|
37
|
+
*
|
|
38
|
+
* Plan 27.7-02 Warning #5 projection: when the underlying error carries
|
|
39
|
+
* a `code === 'directory_not_found'` property (set by
|
|
40
|
+
* SnapshotNotFoundError / IntelNotFoundError / ReflectionsNotFoundError),
|
|
41
|
+
* we surface it as `error.mcp_code` so MCP clients can distinguish a
|
|
42
|
+
* missing-data-source from a genuine bug. The original `code`/`kind`
|
|
43
|
+
* pair stays intact for the GDD error taxonomy.
|
|
44
|
+
*/
|
|
45
|
+
export function errorResponse(err: unknown): ToolResponse {
|
|
46
|
+
const payload = toToolError(err);
|
|
47
|
+
if (
|
|
48
|
+
typeof err === 'object' &&
|
|
49
|
+
err !== null &&
|
|
50
|
+
'code' in err &&
|
|
51
|
+
(err as { code?: unknown }).code === 'directory_not_found'
|
|
52
|
+
) {
|
|
53
|
+
const error = { ...payload.error, mcp_code: 'directory_not_found' };
|
|
54
|
+
return { success: false, error: error as ToolErrorPayload['error'] };
|
|
55
|
+
}
|
|
56
|
+
return { success: false, error: payload.error };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve <root>/.design/STATE.md. State path can be pinned via
|
|
61
|
+
* `process.env.GDD_STATE_PATH` (mirrors the gdd-state server).
|
|
62
|
+
*/
|
|
63
|
+
export function resolveStatePath(): string {
|
|
64
|
+
const override = process.env['GDD_STATE_PATH'];
|
|
65
|
+
if (typeof override === 'string' && override.length > 0) {
|
|
66
|
+
return override;
|
|
67
|
+
}
|
|
68
|
+
return join(resolveProjectRoot(), '.design', 'STATE.md');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Resolve <root>/.planning/ROADMAP.md. */
|
|
72
|
+
export function resolveRoadmapPath(): string {
|
|
73
|
+
return join(resolveProjectRoot(), '.planning', 'ROADMAP.md');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Resolve <root>/.design/intel. */
|
|
77
|
+
export function resolveIntelDir(): string {
|
|
78
|
+
return join(resolveProjectRoot(), '.design', 'intel');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Resolve <root>/.design/telemetry. */
|
|
82
|
+
export function resolveTelemetryDir(): string {
|
|
83
|
+
return join(resolveProjectRoot(), '.design', 'telemetry');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Resolve <root>/.design/reflections. */
|
|
87
|
+
export function resolveReflectionsDir(): string {
|
|
88
|
+
return join(resolveProjectRoot(), '.design', 'reflections');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Resolve <root>/.design/snapshots. */
|
|
92
|
+
export function resolveSnapshotsDir(): string {
|
|
93
|
+
return join(resolveProjectRoot(), '.design', 'snapshots');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Walk up from a starting directory looking for any of the three GDD
|
|
98
|
+
* project markers: `.design/`, `.planning/`, or `.claude-plugin/plugin.json`.
|
|
99
|
+
* First match wins; resolves to the absolute path of the directory that
|
|
100
|
+
* contains the marker.
|
|
101
|
+
*
|
|
102
|
+
* Override: `process.env.GDD_PROJECT_ROOT` short-circuits the walk and
|
|
103
|
+
* is returned verbatim (after path resolution). This is useful for
|
|
104
|
+
* tests and for users who want to pin a project root explicitly.
|
|
105
|
+
*
|
|
106
|
+
* Throws `Error('gdd project root not found: ...')` when no marker is
|
|
107
|
+
* found before the filesystem root. Callers in tool handlers should
|
|
108
|
+
* catch and forward via `errorResponse()`.
|
|
109
|
+
*/
|
|
110
|
+
export function resolveProjectRoot(startCwd: string = process.cwd()): string {
|
|
111
|
+
const override = process.env['GDD_PROJECT_ROOT'];
|
|
112
|
+
if (typeof override === 'string' && override.length > 0) {
|
|
113
|
+
return resolve(override);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let dir = resolve(startCwd);
|
|
117
|
+
while (true) {
|
|
118
|
+
if (
|
|
119
|
+
existsSync(join(dir, '.design')) ||
|
|
120
|
+
existsSync(join(dir, '.planning')) ||
|
|
121
|
+
existsSync(join(dir, '.claude-plugin', 'plugin.json'))
|
|
122
|
+
) {
|
|
123
|
+
return dir;
|
|
124
|
+
}
|
|
125
|
+
const parent = dirname(dir);
|
|
126
|
+
if (parent === dir) {
|
|
127
|
+
// Reached filesystem root — give up.
|
|
128
|
+
throw new Error(
|
|
129
|
+
`gdd project root not found: walked up to ${dir} from ${startCwd}`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
dir = parent;
|
|
133
|
+
}
|
|
134
|
+
}
|
package/skills/health/SKILL.md
CHANGED
|
@@ -52,6 +52,42 @@ Health: 5 / 6 checks passing.
|
|
|
52
52
|
━━━━━━━━━━━━━━━━━━━━━
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
<step name="check-mcp-registration">
|
|
56
|
+
|
|
57
|
+
## Check MCP registration (gdd-mcp)
|
|
58
|
+
|
|
59
|
+
This step inspects whether `gdd-mcp` (Phase 27.7+) is registered with any installed harness and renders a one-line status row after the health table. Dismissable via `.design/config.json#mcp_nudge=false`. This step is non-blocking: a fail-safe fallback ensures malformed config or missing harness settings MUST NOT crash the SKILL — skip silently to `unknown` status when anything goes wrong.
|
|
60
|
+
|
|
61
|
+
### Dismissal check
|
|
62
|
+
|
|
63
|
+
1. Read `.design/config.json` (if present). Parse JSON inside a try/catch.
|
|
64
|
+
2. If `config.mcp_nudge === false`, SKIP this step entirely (render nothing).
|
|
65
|
+
3. On parse failure: default to `mcp_nudge=true` (show the row) — fail-safe per threat T-27.7-04-05.
|
|
66
|
+
|
|
67
|
+
### Detection
|
|
68
|
+
|
|
69
|
+
1. Read `.claude/settings.local.json` (or equivalent harness settings file) and inspect its `mcpServers` object — alternatively run `claude mcp list` / `codex mcp list` if a CLI is available (see fallback below).
|
|
70
|
+
2. Preferred invocation via the install-lib: call `detectMcpRegistration()` from `scripts/lib/install/mcp-register.cjs`. Returns `{harnesses: [{harness, present, registered}], summary}`.
|
|
71
|
+
|
|
72
|
+
### Row rendering
|
|
73
|
+
|
|
74
|
+
Based on the detection result, render exactly ONE of these row strings:
|
|
75
|
+
|
|
76
|
+
- When `claude` and `codex` both present + both registered:
|
|
77
|
+
`MCP server: registered with claude+codex`
|
|
78
|
+
- When only one harness is present and registered:
|
|
79
|
+
`MCP server: registered with claude` (or `MCP server: registered with codex`)
|
|
80
|
+
- When at least one harness is present but `gdd-mcp` is NOT in its registered list:
|
|
81
|
+
`MCP server: not registered (run: npx @hegemonart/get-design-done --register-mcp; dismiss: .design/config.json#mcp_nudge=false)`
|
|
82
|
+
- When neither harness CLI is found on PATH:
|
|
83
|
+
`MCP server: unknown (claude/codex CLI not found)`
|
|
84
|
+
|
|
85
|
+
### Fallback (if `mcp-register.cjs` not yet shipped)
|
|
86
|
+
|
|
87
|
+
Skip this step silently with status `MCP server: unknown`. This step is non-blocking — failures here MUST NOT crash the SKILL.
|
|
88
|
+
|
|
89
|
+
</step>
|
|
90
|
+
|
|
55
91
|
## Update notice (safe-window surface)
|
|
56
92
|
|
|
57
93
|
After the health table, emit the plugin-update banner if one is present:
|
package/skills/next/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gdd-next
|
|
3
3
|
description: "Routes to the next pipeline stage based on current STATE.md position"
|
|
4
|
-
tools: Read, Write
|
|
4
|
+
tools: Read, Write, mcp__gdd_status, mcp__gdd_phase_current, mcp__gdd_plans_list
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Get Design Done — Next
|
|
@@ -12,9 +12,32 @@ tools: Read, Write
|
|
|
12
12
|
|
|
13
13
|
## Logic
|
|
14
14
|
|
|
15
|
+
Two paths — MCP preferred when available, file-read fallback otherwise.
|
|
16
|
+
|
|
17
|
+
### MCP path (preferred)
|
|
18
|
+
|
|
19
|
+
When `mcp__gdd_phase_current` is exposed (Phase 27.7+, registered via `npx @hegemonart/get-design-done --register-mcp`):
|
|
20
|
+
|
|
21
|
+
1. Call `mcp__gdd_status` (no args) → `{phase, branch, last_decisions, last_completed_plans, blocker_count}`. Gives cycle + branch context for the output block in one call.
|
|
22
|
+
2. Call `mcp__gdd_phase_current` (no args) → `{phase, stage, task_progress, status}`. Use `stage` to drive the routing table below.
|
|
23
|
+
3. (Optional) Call `mcp__gdd_plans_list` (no args) → current phase plans + status, to identify the next incomplete plan and refine the recommendation.
|
|
24
|
+
4. If `mcp__gdd_status` returns a "STATE.md missing" error, print: "No STATE.md found. Run `/gdd:new-project` to initialize, or `@get-design-done brief` to start the pipeline." and stop. Otherwise, skip to the routing table.
|
|
25
|
+
|
|
26
|
+
Two to three MCP calls = full routing decision (~3s, ~32k tokens — Storybloq benchmark).
|
|
27
|
+
|
|
28
|
+
### File-read path (fallback)
|
|
29
|
+
|
|
30
|
+
When MCP tools are not available, fall back to the legacy flow:
|
|
31
|
+
|
|
15
32
|
1. Check if `.design/STATE.md` exists.
|
|
16
33
|
- **No STATE.md** → Print: "No STATE.md found. Run `/gdd:new-project` to initialize, or `@get-design-done brief` to start the pipeline."
|
|
17
|
-
2. If STATE.md exists, parse frontmatter `stage:` field
|
|
34
|
+
2. If STATE.md exists, parse frontmatter `stage:` field. Proceed to the routing table.
|
|
35
|
+
|
|
36
|
+
This path loads the same context in 1–2 file reads (~20s, ~46.5k tokens — file-reading baseline).
|
|
37
|
+
|
|
38
|
+
## Routing table
|
|
39
|
+
|
|
40
|
+
Map the `stage` (from either path above) to the next recommended command:
|
|
18
41
|
|
|
19
42
|
| Current `stage:` | Recommendation |
|
|
20
43
|
|---|---|
|
|
@@ -24,7 +47,9 @@ tools: Read, Write
|
|
|
24
47
|
| `design` | Run `@get-design-done verify` to audit and verify |
|
|
25
48
|
| `verify` | Pipeline complete. Run `/gdd:new-cycle` for next cycle or `/gdd:ship` to create PR |
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
## Output
|
|
51
|
+
|
|
52
|
+
Print the recommendation as a single formatted block:
|
|
28
53
|
|
|
29
54
|
```
|
|
30
55
|
━━━ Next step ━━━
|
package/skills/progress/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: gdd-progress
|
|
3
3
|
description: "Shows current pipeline position and routes to next action. --forensic runs 6-check integrity audit."
|
|
4
4
|
argument-hint: "[--forensic]"
|
|
5
|
-
tools: Read, Bash, Grep, Glob, mcp__gdd_state__get
|
|
5
|
+
tools: Read, Bash, Grep, Glob, mcp__gdd_state__get, mcp__gdd_status, mcp__gdd_phase_current
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
@reference/retrieval-contract.md
|
|
@@ -13,12 +13,27 @@ tools: Read, Bash, Grep, Glob, mcp__gdd_state__get
|
|
|
13
13
|
|
|
14
14
|
## Step 1 — Read state
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- `stage`, `cycle`, `last_checkpoint`
|
|
18
|
-
- `task_progress`, `status` (from `<position>`)
|
|
19
|
-
- `decisions.length`, open todos from `.design/TODO.md` (count unchecked `- [ ]` — this file is outside the MCP catalog, so `Read` is still used)
|
|
16
|
+
Two paths — MCP preferred when available, file-read fallback otherwise.
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
### MCP path (preferred)
|
|
19
|
+
|
|
20
|
+
When the harness exposes `mcp__gdd_status` (Phase 27.7+, registered via `npx @hegemonart/get-design-done --register-mcp`):
|
|
21
|
+
|
|
22
|
+
1. Call `mcp__gdd_status` (no args). Returns `{phase, branch, last_decisions, last_completed_plans, blocker_count}` in one call.
|
|
23
|
+
2. If you need `stage` / `task_progress` for the output line, call `mcp__gdd_phase_current` (no args). Returns `{phase, stage, task_progress, status}`.
|
|
24
|
+
3. Skip to Step 2.
|
|
25
|
+
|
|
26
|
+
This path loads the full priming context in 1–2 MCP calls (~3s, ~32k tokens — Storybloq benchmark).
|
|
27
|
+
|
|
28
|
+
### File-read path (fallback)
|
|
29
|
+
|
|
30
|
+
When MCP tools are not available, fall back to the legacy flow:
|
|
31
|
+
|
|
32
|
+
1. Call `mcp__gdd_state__get` if exposed (Phase 20 STATE.md mutator MCP) → parsed state object. Otherwise, `Read .design/STATE.md` and parse the frontmatter + `<position>`, `<decisions>`, `<plans>` sections.
|
|
33
|
+
2. Extract: `stage`, `cycle`, `last_checkpoint`, `task_progress`, `status`, `decisions.length`, open todos from `.design/TODO.md` (count unchecked `- [ ]` — outside the MCP catalog, so `Read` is still used).
|
|
34
|
+
3. If STATE.md is missing, print: "No pipeline state. Run `/gdd:brief` first." and stop.
|
|
35
|
+
|
|
36
|
+
This path loads the same context in 5–10 file reads (~100s, ~46.5k tokens — file-reading baseline).
|
|
22
37
|
|
|
23
38
|
## Step 2 — Default output
|
|
24
39
|
|
package/skills/resume/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: gdd-resume
|
|
3
3
|
description: "Restore session context from a numbered checkpoint. Lists available checkpoints when no argument given."
|
|
4
4
|
argument-hint: "[<N>]"
|
|
5
|
-
tools: Read, Write, Bash, Glob, AskUserQuestion, mcp__gdd_state__get, mcp__gdd_state__set_status, mcp__gdd_state__resolve_blocker, mcp__gdd_state__checkpoint
|
|
5
|
+
tools: Read, Write, Bash, Glob, AskUserQuestion, mcp__gdd_state__get, mcp__gdd_state__set_status, mcp__gdd_state__resolve_blocker, mcp__gdd_state__checkpoint, mcp__gdd_status, mcp__gdd_phase_current, mcp__gdd_plans_list, mcp__gdd_decisions_list
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
@reference/retrieval-contract.md
|
|
@@ -12,6 +12,31 @@ tools: Read, Write, Bash, Glob, AskUserQuestion, mcp__gdd_state__get, mcp__gdd_s
|
|
|
12
12
|
|
|
13
13
|
Inverse of `/gdd:pause`. Reads a checkpoint file, prints a clear "you were here" summary, and routes to the next command.
|
|
14
14
|
|
|
15
|
+
## Step 0 — Prime cycle context
|
|
16
|
+
|
|
17
|
+
Two paths — MCP preferred when available, file-read fallback otherwise. This runs BEFORE checkpoint restoration so the "you were here" summary has full cycle context (phase, plans, decisions).
|
|
18
|
+
|
|
19
|
+
### MCP path (preferred)
|
|
20
|
+
|
|
21
|
+
When `mcp__gdd_status` is exposed (Phase 27.7+, registered via `npx @hegemonart/get-design-done --register-mcp`):
|
|
22
|
+
|
|
23
|
+
1. Call `mcp__gdd_status` (no args) → `{phase, branch, last_decisions, last_completed_plans, blocker_count}`. One call replaces reading STATE.md + parsing frontmatter + extracting decisions.
|
|
24
|
+
2. Call `mcp__gdd_cycle_recap` (no args) → diff vs last cycle snapshot. Critical for session-restoration context: what changed since you paused?
|
|
25
|
+
3. Call `mcp__gdd_decisions_list` (no args) → full D-XX list with rationale. Use for the "decisions you made" line in the resume summary.
|
|
26
|
+
4. (Optional) Call `mcp__gdd_plans_list` (no args) → current phase plans + status, to identify next incomplete plan.
|
|
27
|
+
|
|
28
|
+
Three to four MCP calls = full resume priming (~5s, ~32k tokens — Storybloq benchmark). Proceed to Step 1.
|
|
29
|
+
|
|
30
|
+
### File-read path (fallback)
|
|
31
|
+
|
|
32
|
+
When MCP tools are not available:
|
|
33
|
+
|
|
34
|
+
1. `Read .design/STATE.md` and parse the frontmatter + `<position>`, `<decisions>`, `<plans>` sections. Extract `cycle`, `branch`, `last N decisions`, `completed plans`.
|
|
35
|
+
2. Also `Read .design/CYCLES.md` (if present) to see prior cycle state for the recap.
|
|
36
|
+
3. Proceed to Step 1.
|
|
37
|
+
|
|
38
|
+
This path loads the same context in 3–5 file reads (~60s, ~46.5k tokens — file-reading baseline).
|
|
39
|
+
|
|
15
40
|
## Steps
|
|
16
41
|
|
|
17
42
|
1. **Parse argument**:
|