@hegemonart/get-design-done 1.19.6 → 1.21.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 (140) hide show
  1. package/.claude-plugin/marketplace.json +11 -14
  2. package/.claude-plugin/plugin.json +9 -32
  3. package/CHANGELOG.md +138 -0
  4. package/README.md +54 -1
  5. package/agents/design-reflector.md +13 -0
  6. package/bin/gdd-sdk +55 -0
  7. package/connections/connections.md +3 -0
  8. package/connections/figma.md +2 -0
  9. package/connections/gdd-state.md +186 -0
  10. package/hooks/budget-enforcer.ts +716 -0
  11. package/hooks/context-exhaustion.ts +251 -0
  12. package/hooks/gdd-read-injection-scanner.ts +172 -0
  13. package/hooks/hooks.json +3 -3
  14. package/package.json +32 -51
  15. package/reference/codex-tools.md +53 -0
  16. package/reference/config-schema.md +2 -2
  17. package/reference/error-recovery.md +58 -0
  18. package/reference/gemini-tools.md +53 -0
  19. package/reference/registry.json +21 -0
  20. package/reference/schemas/budget.schema.json +42 -0
  21. package/reference/schemas/events.schema.json +55 -0
  22. package/reference/schemas/generated.d.ts +419 -0
  23. package/reference/schemas/iteration-budget.schema.json +36 -0
  24. package/reference/schemas/mcp-gdd-state-tools.schema.json +89 -0
  25. package/reference/schemas/rate-limits.schema.json +31 -0
  26. package/scripts/aggregate-agent-metrics.ts +282 -0
  27. package/scripts/codegen-schema-types.ts +149 -0
  28. package/scripts/e2e/run-headless.ts +514 -0
  29. package/scripts/lib/cli/commands/audit.ts +382 -0
  30. package/scripts/lib/cli/commands/init.ts +217 -0
  31. package/scripts/lib/cli/commands/query.ts +329 -0
  32. package/scripts/lib/cli/commands/run.ts +656 -0
  33. package/scripts/lib/cli/commands/stage.ts +468 -0
  34. package/scripts/lib/cli/index.ts +167 -0
  35. package/scripts/lib/cli/parse-args.ts +336 -0
  36. package/scripts/lib/context-engine/index.ts +116 -0
  37. package/scripts/lib/context-engine/manifest.ts +69 -0
  38. package/scripts/lib/context-engine/truncate.ts +282 -0
  39. package/scripts/lib/context-engine/types.ts +59 -0
  40. package/scripts/lib/discuss-parallel-runner/aggregator.ts +448 -0
  41. package/scripts/lib/discuss-parallel-runner/discussants.ts +430 -0
  42. package/scripts/lib/discuss-parallel-runner/index.ts +223 -0
  43. package/scripts/lib/discuss-parallel-runner/types.ts +184 -0
  44. package/scripts/lib/error-classifier.cjs +232 -0
  45. package/scripts/lib/error-classifier.d.cts +44 -0
  46. package/scripts/lib/event-stream/emitter.ts +88 -0
  47. package/scripts/lib/event-stream/index.ts +164 -0
  48. package/scripts/lib/event-stream/types.ts +127 -0
  49. package/scripts/lib/event-stream/writer.ts +154 -0
  50. package/scripts/lib/explore-parallel-runner/index.ts +294 -0
  51. package/scripts/lib/explore-parallel-runner/mappers.ts +290 -0
  52. package/scripts/lib/explore-parallel-runner/synthesizer.ts +295 -0
  53. package/scripts/lib/explore-parallel-runner/types.ts +139 -0
  54. package/scripts/lib/gdd-errors/classification.ts +124 -0
  55. package/scripts/lib/gdd-errors/index.ts +218 -0
  56. package/scripts/lib/gdd-state/gates.ts +216 -0
  57. package/scripts/lib/gdd-state/index.ts +167 -0
  58. package/scripts/lib/gdd-state/lockfile.ts +232 -0
  59. package/scripts/lib/gdd-state/mutator.ts +574 -0
  60. package/scripts/lib/gdd-state/parser.ts +523 -0
  61. package/scripts/lib/gdd-state/types.ts +179 -0
  62. package/scripts/lib/harness/detect.ts +90 -0
  63. package/scripts/lib/harness/index.ts +64 -0
  64. package/scripts/lib/harness/tool-map.ts +142 -0
  65. package/scripts/lib/init-runner/index.ts +396 -0
  66. package/scripts/lib/init-runner/researchers.ts +245 -0
  67. package/scripts/lib/init-runner/scaffold.ts +224 -0
  68. package/scripts/lib/init-runner/synthesizer.ts +224 -0
  69. package/scripts/lib/init-runner/types.ts +143 -0
  70. package/scripts/lib/iteration-budget.cjs +205 -0
  71. package/scripts/lib/iteration-budget.d.cts +32 -0
  72. package/scripts/lib/jittered-backoff.cjs +112 -0
  73. package/scripts/lib/jittered-backoff.d.cts +38 -0
  74. package/scripts/lib/lockfile.cjs +177 -0
  75. package/scripts/lib/lockfile.d.cts +21 -0
  76. package/scripts/lib/logger/index.ts +251 -0
  77. package/scripts/lib/logger/sinks.ts +269 -0
  78. package/scripts/lib/logger/types.ts +110 -0
  79. package/scripts/lib/pipeline-runner/human-gate.ts +134 -0
  80. package/scripts/lib/pipeline-runner/index.ts +527 -0
  81. package/scripts/lib/pipeline-runner/stage-handlers.ts +339 -0
  82. package/scripts/lib/pipeline-runner/state-machine.ts +144 -0
  83. package/scripts/lib/pipeline-runner/types.ts +183 -0
  84. package/scripts/lib/prompt-sanitizer/index.ts +435 -0
  85. package/scripts/lib/prompt-sanitizer/patterns.ts +173 -0
  86. package/scripts/lib/rate-guard.cjs +365 -0
  87. package/scripts/lib/rate-guard.d.cts +38 -0
  88. package/scripts/lib/session-runner/errors.ts +406 -0
  89. package/scripts/lib/session-runner/index.ts +715 -0
  90. package/scripts/lib/session-runner/transcript.ts +189 -0
  91. package/scripts/lib/session-runner/types.ts +144 -0
  92. package/scripts/lib/tool-scoping/index.ts +219 -0
  93. package/scripts/lib/tool-scoping/parse-agent-tools.ts +207 -0
  94. package/scripts/lib/tool-scoping/stage-scopes.ts +139 -0
  95. package/scripts/lib/tool-scoping/types.ts +77 -0
  96. package/scripts/mcp-servers/gdd-state/schemas/add_blocker.schema.json +67 -0
  97. package/scripts/mcp-servers/gdd-state/schemas/add_decision.schema.json +68 -0
  98. package/scripts/mcp-servers/gdd-state/schemas/add_must_have.schema.json +68 -0
  99. package/scripts/mcp-servers/gdd-state/schemas/checkpoint.schema.json +51 -0
  100. package/scripts/mcp-servers/gdd-state/schemas/frontmatter_update.schema.json +62 -0
  101. package/scripts/mcp-servers/gdd-state/schemas/get.schema.json +51 -0
  102. package/scripts/mcp-servers/gdd-state/schemas/probe_connections.schema.json +75 -0
  103. package/scripts/mcp-servers/gdd-state/schemas/resolve_blocker.schema.json +66 -0
  104. package/scripts/mcp-servers/gdd-state/schemas/set_status.schema.json +47 -0
  105. package/scripts/mcp-servers/gdd-state/schemas/transition_stage.schema.json +70 -0
  106. package/scripts/mcp-servers/gdd-state/schemas/update_progress.schema.json +58 -0
  107. package/scripts/mcp-servers/gdd-state/server.ts +288 -0
  108. package/scripts/mcp-servers/gdd-state/tools/add_blocker.ts +72 -0
  109. package/scripts/mcp-servers/gdd-state/tools/add_decision.ts +89 -0
  110. package/scripts/mcp-servers/gdd-state/tools/add_must_have.ts +113 -0
  111. package/scripts/mcp-servers/gdd-state/tools/checkpoint.ts +60 -0
  112. package/scripts/mcp-servers/gdd-state/tools/frontmatter_update.ts +91 -0
  113. package/scripts/mcp-servers/gdd-state/tools/get.ts +51 -0
  114. package/scripts/mcp-servers/gdd-state/tools/index.ts +51 -0
  115. package/scripts/mcp-servers/gdd-state/tools/probe_connections.ts +73 -0
  116. package/scripts/mcp-servers/gdd-state/tools/resolve_blocker.ts +84 -0
  117. package/scripts/mcp-servers/gdd-state/tools/set_status.ts +54 -0
  118. package/scripts/mcp-servers/gdd-state/tools/shared.ts +194 -0
  119. package/scripts/mcp-servers/gdd-state/tools/transition_stage.ts +80 -0
  120. package/scripts/mcp-servers/gdd-state/tools/update_progress.ts +81 -0
  121. package/scripts/validate-frontmatter.ts +114 -0
  122. package/scripts/validate-schemas.ts +401 -0
  123. package/skills/brief/SKILL.md +15 -6
  124. package/skills/design/SKILL.md +31 -13
  125. package/skills/explore/SKILL.md +41 -17
  126. package/skills/health/SKILL.md +15 -4
  127. package/skills/optimize/SKILL.md +3 -3
  128. package/skills/pause/SKILL.md +16 -10
  129. package/skills/plan/SKILL.md +33 -17
  130. package/skills/progress/SKILL.md +15 -11
  131. package/skills/resume/SKILL.md +19 -10
  132. package/skills/settings/SKILL.md +11 -3
  133. package/skills/todo/SKILL.md +12 -3
  134. package/skills/verify/SKILL.md +65 -29
  135. package/hooks/budget-enforcer.js +0 -329
  136. package/hooks/context-exhaustion.js +0 -127
  137. package/hooks/gdd-read-injection-scanner.js +0 -39
  138. package/scripts/aggregate-agent-metrics.js +0 -173
  139. package/scripts/validate-frontmatter.cjs +0 -68
  140. package/scripts/validate-schemas.cjs +0 -242
@@ -0,0 +1,207 @@
1
+ // scripts/lib/tool-scoping/parse-agent-tools.ts — extract the `tools:`
2
+ // list from an agent markdown file's YAML frontmatter.
3
+ //
4
+ // Why a hand-rolled parser instead of pulling in js-yaml:
5
+ // * No new npm deps (Plan 21-03 hard constraint).
6
+ // * The `tools:` field grammar is narrow (4 YAML shapes + wildcard +
7
+ // empty). A minimal parser covering exactly those shapes is
8
+ // maintainable and keeps the surface area tight.
9
+ //
10
+ // Supported frontmatter shapes:
11
+ // tools: Read, Write, Grep → ['Read','Write','Grep']
12
+ // tools: [Read, Write] → ['Read','Write']
13
+ // tools: "*" → null (wildcard fallback)
14
+ // tools: [] → [] (MCP-only narrow)
15
+ // tools:
16
+ // - Read
17
+ // - Write → ['Read','Write']
18
+ //
19
+ // Return contract:
20
+ // null — file missing, no frontmatter, tools key absent, OR wildcard.
21
+ // [] — tools: [] OR tools: (no children).
22
+ // string[] — the declared, trimmed, de-quoted list.
23
+
24
+ import { readFileSync } from 'node:fs';
25
+ import { resolve } from 'node:path';
26
+
27
+ /**
28
+ * Read the `tools:` field from an agent markdown file's YAML
29
+ * frontmatter. See module header for the full grammar.
30
+ *
31
+ * @param agentMdPath absolute or cwd-relative path to an `agents/*.md`.
32
+ * @returns readonly string[] | null per the contract above.
33
+ */
34
+ export function parseAgentTools(
35
+ agentMdPath: string,
36
+ ): readonly string[] | null {
37
+ let raw: string;
38
+ try {
39
+ raw = readFileSync(agentMdPath, 'utf8');
40
+ } catch (err) {
41
+ // ENOENT or any read error → treat as "no override" (null).
42
+ if (
43
+ err !== null &&
44
+ typeof err === 'object' &&
45
+ 'code' in err &&
46
+ (err as { code: string }).code === 'ENOENT'
47
+ ) {
48
+ return null;
49
+ }
50
+ // Permission/IO errors also fall through to null — a parser that
51
+ // throws on any fs hiccup would crash the entire session at scope
52
+ // computation time; fail-closed (null = stage default) is safer.
53
+ return null;
54
+ }
55
+
56
+ const frontmatter: string | null = extractFrontmatter(raw);
57
+ if (frontmatter === null) return null;
58
+
59
+ return extractToolsField(frontmatter);
60
+ }
61
+
62
+ /**
63
+ * Convenience: look up an agent by bare name under `<agentsRoot>/<name>.md`
64
+ * and delegate to `parseAgentTools`. Defaults to `./agents` when no root
65
+ * is supplied.
66
+ */
67
+ export function parseAgentToolsByName(
68
+ name: string,
69
+ agentsRoot: string = 'agents',
70
+ ): readonly string[] | null {
71
+ const path: string = resolve(agentsRoot, `${name}.md`);
72
+ return parseAgentTools(path);
73
+ }
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // Internal — frontmatter splitter
77
+ // ---------------------------------------------------------------------------
78
+
79
+ /**
80
+ * Return the text between the opening `---\n` and closing `---\n` lines,
81
+ * or null when no valid frontmatter block exists.
82
+ *
83
+ * Matches the splitter in `scripts/lib/prompt-sanitizer/index.ts` — kept
84
+ * local (rather than imported) to avoid coupling the tool-scoping module
85
+ * to prompt-sanitizer internals.
86
+ */
87
+ function extractFrontmatter(raw: string): string | null {
88
+ // Accept LF or CRLF. First line must be exactly `---`.
89
+ const match: RegExpExecArray | null = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/.exec(
90
+ raw,
91
+ );
92
+ if (match === null) return null;
93
+ const body: string | undefined = match[1];
94
+ return body ?? null;
95
+ }
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Internal — tools field extractor
99
+ // ---------------------------------------------------------------------------
100
+
101
+ /**
102
+ * Given the frontmatter body (text between `---` fences), return the
103
+ * parsed `tools:` field per the contract. Absence returns null.
104
+ */
105
+ function extractToolsField(frontmatter: string): readonly string[] | null {
106
+ const lines: string[] = frontmatter.split(/\r?\n/);
107
+ const toolsLineRe = /^tools:\s*(.*)$/;
108
+
109
+ for (let i = 0; i < lines.length; i += 1) {
110
+ const line: string = lines[i] ?? '';
111
+ const m: RegExpExecArray | null = toolsLineRe.exec(line);
112
+ if (m === null) continue;
113
+
114
+ const rest: string = (m[1] ?? '').trim();
115
+
116
+ // Case 1: wildcard — `tools: "*"` or `tools: *`.
117
+ // Per the Plan 21-03 frontmatter contract, this is a forward-compat
118
+ // escape that falls back to stage default (NOT "everything"), so we
119
+ // return null to signal "no override".
120
+ if (rest === '*' || rest === '"*"' || rest === "'*'") {
121
+ return null;
122
+ }
123
+
124
+ // Case 2: flow-style `tools: [...]` or empty `tools: []`.
125
+ if (rest.startsWith('[') && rest.endsWith(']')) {
126
+ const inner: string = rest.slice(1, -1).trim();
127
+ if (inner === '') return Object.freeze([]);
128
+ return Object.freeze(splitAndClean(inner));
129
+ }
130
+
131
+ // Case 3: YAML list (empty value on tools: line, items follow).
132
+ if (rest === '') {
133
+ const items: string[] = [];
134
+ for (let j = i + 1; j < lines.length; j += 1) {
135
+ const next: string = lines[j] ?? '';
136
+ // A blank line or a non-list-item line ends the block.
137
+ if (next.trim() === '') continue;
138
+ const listItem: RegExpExecArray | null = /^\s*-\s*(\S.*)$/.exec(next);
139
+ if (listItem === null) break;
140
+ const entry: string | undefined = listItem[1];
141
+ if (entry === undefined) break;
142
+ items.push(cleanToken(entry));
143
+ }
144
+ return Object.freeze(items);
145
+ }
146
+
147
+ // Case 4: inline comma-separated list (may have quoted entries).
148
+ return Object.freeze(splitAndClean(rest));
149
+ }
150
+
151
+ return null;
152
+ }
153
+
154
+ /**
155
+ * Split a comma-separated list while honoring double-quoted entries
156
+ * (so `"Read, with-comma", "Write"` stays a 2-element list). Trims
157
+ * whitespace and strips surrounding single / double quotes from each
158
+ * token.
159
+ */
160
+ function splitAndClean(input: string): string[] {
161
+ const out: string[] = [];
162
+ let buf: string[] = [];
163
+ let inDouble = false;
164
+ let inSingle = false;
165
+
166
+ for (const ch of input) {
167
+ if (ch === '"' && !inSingle) {
168
+ inDouble = !inDouble;
169
+ buf.push(ch);
170
+ continue;
171
+ }
172
+ if (ch === "'" && !inDouble) {
173
+ inSingle = !inSingle;
174
+ buf.push(ch);
175
+ continue;
176
+ }
177
+ if (ch === ',' && !inDouble && !inSingle) {
178
+ out.push(cleanToken(buf.join('')));
179
+ buf = [];
180
+ continue;
181
+ }
182
+ buf.push(ch);
183
+ }
184
+
185
+ const tail: string = cleanToken(buf.join(''));
186
+ if (tail !== '' || out.length === 0) {
187
+ out.push(tail);
188
+ }
189
+
190
+ return out.filter((t) => t !== '');
191
+ }
192
+
193
+ /**
194
+ * Trim whitespace + strip matching leading/trailing quote pairs.
195
+ * Applied to each split list entry.
196
+ */
197
+ function cleanToken(token: string): string {
198
+ let t: string = token.trim();
199
+ if (t.length >= 2) {
200
+ const first: string = t[0] ?? '';
201
+ const last: string = t[t.length - 1] ?? '';
202
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
203
+ t = t.slice(1, -1).trim();
204
+ }
205
+ }
206
+ return t;
207
+ }
@@ -0,0 +1,139 @@
1
+ // scripts/lib/tool-scoping/stage-scopes.ts — frozen per-stage default
2
+ // scope registry and native-tool classifier.
3
+ //
4
+ // The locked table below is the single source of truth for what each
5
+ // pipeline stage is permitted. DO NOT MODIFY without a follow-up plan:
6
+ // widening a stage here silently expands every headless session that
7
+ // falls back to defaults.
8
+ //
9
+ // MCP tools (`mcp__*`) are NEVER in this registry — they're always
10
+ // permitted and bypass the native filter entirely. See `isMcpTool`.
11
+
12
+ import type { Stage } from './types.ts';
13
+
14
+ /**
15
+ * Shape of a single registry entry. Frozen at module load.
16
+ */
17
+ interface StageDefault {
18
+ readonly allowed: readonly string[];
19
+ readonly bashMutation: boolean;
20
+ }
21
+
22
+ /**
23
+ * Per-stage default scope table. Every `Stage` key must have an entry —
24
+ * `computeScope` relies on this for invariant lookup.
25
+ *
26
+ * Locked contract (see PLAN 21-03):
27
+ * brief — Read/Write/Edit/Grep/Glob/Bash (Bash read-only, advisory)
28
+ * explore — Read/Grep/Glob/Bash/WebSearch/WebFetch/Task (Bash read-only)
29
+ * plan — Read/Write/Edit/Grep/Glob/Bash/Task (Bash read-only)
30
+ * design — Read/Write/Edit/Grep/Glob/Bash/Task (Bash mutation ALLOWED)
31
+ * verify — Read/Grep/Glob/Bash (NO Write/Edit/Task; Bash read-only)
32
+ * init — Read/Write/Grep/Glob/Bash/Task/WebSearch/WebFetch (bootstrap)
33
+ * custom — empty (caller-provided only; no defaults)
34
+ */
35
+ export const STAGE_SCOPES: Readonly<Record<Stage, StageDefault>> =
36
+ Object.freeze({
37
+ brief: Object.freeze({
38
+ allowed: Object.freeze(['Read', 'Write', 'Edit', 'Grep', 'Glob', 'Bash']),
39
+ bashMutation: false,
40
+ }),
41
+ explore: Object.freeze({
42
+ allowed: Object.freeze([
43
+ 'Read',
44
+ 'Grep',
45
+ 'Glob',
46
+ 'Bash',
47
+ 'WebSearch',
48
+ 'WebFetch',
49
+ 'Task',
50
+ ]),
51
+ bashMutation: false,
52
+ }),
53
+ plan: Object.freeze({
54
+ allowed: Object.freeze([
55
+ 'Read',
56
+ 'Write',
57
+ 'Edit',
58
+ 'Grep',
59
+ 'Glob',
60
+ 'Bash',
61
+ 'Task',
62
+ ]),
63
+ bashMutation: false,
64
+ }),
65
+ design: Object.freeze({
66
+ allowed: Object.freeze([
67
+ 'Read',
68
+ 'Write',
69
+ 'Edit',
70
+ 'Grep',
71
+ 'Glob',
72
+ 'Bash',
73
+ 'Task',
74
+ ]),
75
+ bashMutation: true,
76
+ }),
77
+ verify: Object.freeze({
78
+ allowed: Object.freeze(['Read', 'Grep', 'Glob', 'Bash']),
79
+ bashMutation: false,
80
+ }),
81
+ init: Object.freeze({
82
+ allowed: Object.freeze([
83
+ 'Read',
84
+ 'Write',
85
+ 'Grep',
86
+ 'Glob',
87
+ 'Bash',
88
+ 'Task',
89
+ 'WebSearch',
90
+ 'WebFetch',
91
+ ]),
92
+ bashMutation: false,
93
+ }),
94
+ custom: Object.freeze({
95
+ allowed: Object.freeze([]),
96
+ bashMutation: false,
97
+ }),
98
+ });
99
+
100
+ /**
101
+ * Authoritative list of native (harness-managed) tool names. Anything
102
+ * NOT in this list and NOT MCP-prefixed is unknown and treated as a
103
+ * native miss by `checkTool`.
104
+ *
105
+ * Order matches the documented stage scopes; tests assert that every
106
+ * tool referenced in STAGE_SCOPES is a member of NATIVE_TOOLS.
107
+ */
108
+ export const NATIVE_TOOLS: readonly string[] = Object.freeze([
109
+ 'Read',
110
+ 'Write',
111
+ 'Edit',
112
+ 'Grep',
113
+ 'Glob',
114
+ 'Bash',
115
+ 'Task',
116
+ 'WebSearch',
117
+ 'WebFetch',
118
+ ]);
119
+
120
+ /** MCP tools carry the `mcp__` prefix by convention. */
121
+ const MCP_PREFIX = 'mcp__';
122
+
123
+ /**
124
+ * True when `name` is an MCP tool. MCP tools always pass scope checks —
125
+ * each MCP server declares its own security perimeter, so the stage
126
+ * filter only gates native harness tools.
127
+ */
128
+ export function isMcpTool(name: string): boolean {
129
+ return typeof name === 'string' && name.startsWith(MCP_PREFIX);
130
+ }
131
+
132
+ /**
133
+ * True when `name` is a known native harness tool. Used by
134
+ * `computeScope` to split caller-supplied lists into native vs MCP
135
+ * buckets.
136
+ */
137
+ export function isNativeTool(name: string): boolean {
138
+ return NATIVE_TOOLS.includes(name);
139
+ }
@@ -0,0 +1,77 @@
1
+ // scripts/lib/tool-scoping/types.ts — type definitions for per-stage
2
+ // allowed-tools enforcement.
3
+ //
4
+ // See ./index.ts for the public API surface. Types are kept in this file
5
+ // so fixtures, tests, and callers can import them without pulling the
6
+ // full parser/compute machinery.
7
+
8
+ /**
9
+ * Canonical pipeline stage name. `custom` is the escape valve for
10
+ * callers that manage their own scope entirely; it has no defaults.
11
+ */
12
+ export type Stage =
13
+ | 'brief'
14
+ | 'explore'
15
+ | 'plan'
16
+ | 'design'
17
+ | 'verify'
18
+ | 'init'
19
+ | 'custom';
20
+
21
+ /**
22
+ * Computed scope for a headless Agent SDK session. Produced by
23
+ * `computeScope`; consumed by `checkTool`, `enforceScope`, and
24
+ * `session-runner`'s `allowedTools` parameter.
25
+ *
26
+ * `allowed` is a flattened, deduplicated, alphabetically sorted list
27
+ * (deterministic output — stable across runs).
28
+ *
29
+ * `denied` is `NATIVE_TOOLS \ allowed_native`: the set of native
30
+ * harness tools explicitly NOT permitted on this session. MCP tools
31
+ * are never in `denied` — they always pass.
32
+ */
33
+ export interface Scope {
34
+ readonly stage: Stage;
35
+ /** Flattened, deduplicated, sorted list of allowed tool names. */
36
+ readonly allowed: readonly string[];
37
+ /** Native tools explicitly denied by the stage (e.g., verify denies Write). */
38
+ readonly denied: readonly string[];
39
+ /**
40
+ * Whether bash mutations are permitted (stage-level flag, advisory —
41
+ * hard gating is future work in Phase 22's `gdd-router`).
42
+ */
43
+ readonly bashMutation: boolean;
44
+ }
45
+
46
+ /**
47
+ * Input to `computeScope` / `enforceScope`.
48
+ *
49
+ * `agentTools` precedence rules (documented in stage-scopes.ts):
50
+ * undefined / null → stage default applies
51
+ * [] → scope narrows to MCP-only (empty native list)
52
+ * string[] (non-empty)→ overrides stage defaults entirely
53
+ *
54
+ * `additional` is unioned with the scope (caller-supplied, e.g.,
55
+ * `mcp__gdd_state__*` tool names the session needs access to).
56
+ */
57
+ export interface ScopeInput {
58
+ readonly stage: Stage;
59
+ /** Optional agent-frontmatter override (from parseAgentTools). */
60
+ readonly agentTools?: readonly string[] | null;
61
+ /** Additional tools to union with the scope (caller-supplied). */
62
+ readonly additional?: readonly string[];
63
+ }
64
+
65
+ /**
66
+ * Structured denial record returned by `checkTool`. `enforceScope`
67
+ * lifts these into `ValidationError` instances (from gdd-errors).
68
+ *
69
+ * `tool` is absent when the violation is not tool-specific
70
+ * (e.g., `INVALID_STAGE`, `EMPTY_SCOPE`).
71
+ */
72
+ export interface ScopeViolation {
73
+ readonly code: 'TOOL_NOT_ALLOWED' | 'INVALID_STAGE' | 'EMPTY_SCOPE';
74
+ readonly tool?: string;
75
+ readonly stage: Stage;
76
+ readonly message: string;
77
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/hegemonart/get-design-done/main/scripts/mcp-servers/gdd-state/schemas/add_blocker.schema.json",
4
+ "title": "GddStateAddBlocker",
5
+ "description": "MCP tool gdd_state__add_blocker — append one entry to <blockers>. Emits state.mutation.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["input", "output"],
9
+ "properties": {
10
+ "input": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["text"],
14
+ "properties": {
15
+ "text": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "description": "Human-readable blocker description."
19
+ },
20
+ "stage": {
21
+ "type": "string",
22
+ "description": "Optional. Defaults to <position>.stage."
23
+ },
24
+ "date": {
25
+ "type": "string",
26
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
27
+ "description": "Optional ISO date (YYYY-MM-DD). Defaults to today (UTC)."
28
+ }
29
+ }
30
+ },
31
+ "output": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["success"],
35
+ "properties": {
36
+ "success": { "type": "boolean" },
37
+ "data": {
38
+ "type": "object",
39
+ "additionalProperties": true,
40
+ "properties": {
41
+ "blocker": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["stage", "date", "text"],
45
+ "properties": {
46
+ "stage": { "type": "string" },
47
+ "date": { "type": "string" },
48
+ "text": { "type": "string" }
49
+ }
50
+ },
51
+ "count": { "type": "integer", "minimum": 1 }
52
+ }
53
+ },
54
+ "error": {
55
+ "type": "object",
56
+ "additionalProperties": true,
57
+ "required": ["code", "message", "kind"],
58
+ "properties": {
59
+ "code": { "type": "string" },
60
+ "message": { "type": "string" },
61
+ "kind": { "type": "string", "enum": ["validation", "state_conflict", "operation_failed", "unknown"] }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/hegemonart/get-design-done/main/scripts/mcp-servers/gdd-state/schemas/add_decision.schema.json",
4
+ "title": "GddStateAddDecision",
5
+ "description": "MCP tool gdd_state__add_decision — append one entry to <decisions>. Emits state.mutation.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["input", "output"],
9
+ "properties": {
10
+ "input": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["text"],
14
+ "properties": {
15
+ "text": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "description": "Human-readable decision text."
19
+ },
20
+ "status": {
21
+ "type": "string",
22
+ "enum": ["locked", "tentative"],
23
+ "description": "Defaults to tentative."
24
+ },
25
+ "id": {
26
+ "type": "string",
27
+ "pattern": "^D-[0-9]+$",
28
+ "description": "Optional. Defaults to next available D-N based on existing decisions."
29
+ }
30
+ }
31
+ },
32
+ "output": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["success"],
36
+ "properties": {
37
+ "success": { "type": "boolean" },
38
+ "data": {
39
+ "type": "object",
40
+ "additionalProperties": true,
41
+ "properties": {
42
+ "decision": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "required": ["id", "text", "status"],
46
+ "properties": {
47
+ "id": { "type": "string" },
48
+ "text": { "type": "string" },
49
+ "status": { "type": "string", "enum": ["locked", "tentative"] }
50
+ }
51
+ },
52
+ "count": { "type": "integer", "minimum": 1 }
53
+ }
54
+ },
55
+ "error": {
56
+ "type": "object",
57
+ "additionalProperties": true,
58
+ "required": ["code", "message", "kind"],
59
+ "properties": {
60
+ "code": { "type": "string" },
61
+ "message": { "type": "string" },
62
+ "kind": { "type": "string", "enum": ["validation", "state_conflict", "operation_failed", "unknown"] }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/hegemonart/get-design-done/main/scripts/mcp-servers/gdd-state/schemas/add_must_have.schema.json",
4
+ "title": "GddStateAddMustHave",
5
+ "description": "MCP tool gdd_state__add_must_have — append one entry to <must_haves>. Emits state.mutation.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["input", "output"],
9
+ "properties": {
10
+ "input": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["text"],
14
+ "properties": {
15
+ "text": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "description": "Human-readable must-have criterion."
19
+ },
20
+ "status": {
21
+ "type": "string",
22
+ "enum": ["pending", "pass", "fail"],
23
+ "description": "Defaults to pending."
24
+ },
25
+ "id": {
26
+ "type": "string",
27
+ "pattern": "^M-[0-9]+$",
28
+ "description": "Optional. Defaults to next available M-N based on existing must_haves."
29
+ }
30
+ }
31
+ },
32
+ "output": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["success"],
36
+ "properties": {
37
+ "success": { "type": "boolean" },
38
+ "data": {
39
+ "type": "object",
40
+ "additionalProperties": true,
41
+ "properties": {
42
+ "must_have": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "required": ["id", "text", "status"],
46
+ "properties": {
47
+ "id": { "type": "string" },
48
+ "text": { "type": "string" },
49
+ "status": { "type": "string", "enum": ["pending", "pass", "fail"] }
50
+ }
51
+ },
52
+ "count": { "type": "integer", "minimum": 1 }
53
+ }
54
+ },
55
+ "error": {
56
+ "type": "object",
57
+ "additionalProperties": true,
58
+ "required": ["code", "message", "kind"],
59
+ "properties": {
60
+ "code": { "type": "string" },
61
+ "message": { "type": "string" },
62
+ "kind": { "type": "string", "enum": ["validation", "state_conflict", "operation_failed", "unknown"] }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/hegemonart/get-design-done/main/scripts/mcp-servers/gdd-state/schemas/checkpoint.schema.json",
4
+ "title": "GddStateCheckpoint",
5
+ "description": "MCP tool gdd_state__checkpoint — bump frontmatter.last_checkpoint + append a <timestamps> entry. Emits state.mutation.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["input", "output"],
9
+ "properties": {
10
+ "input": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "properties": {
14
+ "label": {
15
+ "type": "string",
16
+ "minLength": 1,
17
+ "description": "Optional label for the timestamp entry key. When absent the key is `<stage>_checkpoint_at`."
18
+ }
19
+ }
20
+ },
21
+ "output": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "required": ["success"],
25
+ "properties": {
26
+ "success": { "type": "boolean" },
27
+ "data": {
28
+ "type": "object",
29
+ "additionalProperties": true,
30
+ "properties": {
31
+ "last_checkpoint": {
32
+ "type": "string",
33
+ "format": "date-time"
34
+ },
35
+ "timestamp_key": { "type": "string" }
36
+ }
37
+ },
38
+ "error": {
39
+ "type": "object",
40
+ "additionalProperties": true,
41
+ "required": ["code", "message", "kind"],
42
+ "properties": {
43
+ "code": { "type": "string" },
44
+ "message": { "type": "string" },
45
+ "kind": { "type": "string", "enum": ["validation", "state_conflict", "operation_failed", "unknown"] }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }