@hegemonart/get-design-done 1.20.0 → 1.22.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 (69) hide show
  1. package/.claude-plugin/marketplace.json +9 -12
  2. package/.claude-plugin/plugin.json +8 -31
  3. package/CHANGELOG.md +200 -0
  4. package/README.md +48 -7
  5. package/bin/gdd-sdk +55 -0
  6. package/hooks/_hook-emit.js +81 -0
  7. package/hooks/gdd-bash-guard.js +8 -0
  8. package/hooks/gdd-decision-injector.js +2 -0
  9. package/hooks/gdd-protected-paths.js +8 -0
  10. package/hooks/gdd-trajectory-capture.js +64 -0
  11. package/hooks/hooks.json +9 -0
  12. package/package.json +19 -47
  13. package/reference/codex-tools.md +53 -0
  14. package/reference/gemini-tools.md +53 -0
  15. package/reference/registry.json +14 -0
  16. package/scripts/cli/gdd-events.mjs +283 -0
  17. package/scripts/e2e/run-headless.ts +514 -0
  18. package/scripts/lib/cli/commands/audit.ts +382 -0
  19. package/scripts/lib/cli/commands/init.ts +217 -0
  20. package/scripts/lib/cli/commands/query.ts +329 -0
  21. package/scripts/lib/cli/commands/run.ts +656 -0
  22. package/scripts/lib/cli/commands/stage.ts +468 -0
  23. package/scripts/lib/cli/index.ts +167 -0
  24. package/scripts/lib/cli/parse-args.ts +336 -0
  25. package/scripts/lib/connection-probe/index.cjs +263 -0
  26. package/scripts/lib/context-engine/index.ts +116 -0
  27. package/scripts/lib/context-engine/manifest.ts +69 -0
  28. package/scripts/lib/context-engine/truncate.ts +282 -0
  29. package/scripts/lib/context-engine/types.ts +59 -0
  30. package/scripts/lib/discuss-parallel-runner/aggregator.ts +448 -0
  31. package/scripts/lib/discuss-parallel-runner/discussants.ts +430 -0
  32. package/scripts/lib/discuss-parallel-runner/index.ts +223 -0
  33. package/scripts/lib/discuss-parallel-runner/types.ts +184 -0
  34. package/scripts/lib/event-chain.cjs +177 -0
  35. package/scripts/lib/event-stream/index.ts +31 -1
  36. package/scripts/lib/event-stream/reader.ts +139 -0
  37. package/scripts/lib/event-stream/types.ts +155 -1
  38. package/scripts/lib/event-stream/writer.ts +65 -8
  39. package/scripts/lib/explore-parallel-runner/index.ts +294 -0
  40. package/scripts/lib/explore-parallel-runner/mappers.ts +290 -0
  41. package/scripts/lib/explore-parallel-runner/synthesizer.ts +295 -0
  42. package/scripts/lib/explore-parallel-runner/types.ts +139 -0
  43. package/scripts/lib/harness/detect.ts +90 -0
  44. package/scripts/lib/harness/index.ts +64 -0
  45. package/scripts/lib/harness/tool-map.ts +142 -0
  46. package/scripts/lib/init-runner/index.ts +396 -0
  47. package/scripts/lib/init-runner/researchers.ts +245 -0
  48. package/scripts/lib/init-runner/scaffold.ts +224 -0
  49. package/scripts/lib/init-runner/synthesizer.ts +224 -0
  50. package/scripts/lib/init-runner/types.ts +143 -0
  51. package/scripts/lib/logger/index.ts +251 -0
  52. package/scripts/lib/logger/sinks.ts +269 -0
  53. package/scripts/lib/logger/types.ts +110 -0
  54. package/scripts/lib/pipeline-runner/human-gate.ts +134 -0
  55. package/scripts/lib/pipeline-runner/index.ts +527 -0
  56. package/scripts/lib/pipeline-runner/stage-handlers.ts +339 -0
  57. package/scripts/lib/pipeline-runner/state-machine.ts +144 -0
  58. package/scripts/lib/pipeline-runner/types.ts +183 -0
  59. package/scripts/lib/redact.cjs +122 -0
  60. package/scripts/lib/session-runner/errors.ts +406 -0
  61. package/scripts/lib/session-runner/index.ts +715 -0
  62. package/scripts/lib/session-runner/transcript.ts +189 -0
  63. package/scripts/lib/session-runner/types.ts +144 -0
  64. package/scripts/lib/tool-scoping/index.ts +219 -0
  65. package/scripts/lib/tool-scoping/parse-agent-tools.ts +207 -0
  66. package/scripts/lib/tool-scoping/stage-scopes.ts +139 -0
  67. package/scripts/lib/tool-scoping/types.ts +77 -0
  68. package/scripts/lib/trajectory/index.cjs +126 -0
  69. package/scripts/lib/transports/ws.cjs +179 -0
@@ -0,0 +1,329 @@
1
+ // scripts/lib/cli/commands/query.ts — Plan 21-09 Task 4 (SDK-21).
2
+ //
3
+ // `gdd-sdk query <op>` — typed STATE.md read operations. Mirrors the
4
+ // read side of the gdd-state MCP server. Never mutates — use the
5
+ // dedicated MCP tools (via Claude Code) for writes.
6
+ //
7
+ // Operations:
8
+ // get → full ParsedState (JSON).
9
+ // stage → frontmatter.stage.
10
+ // position → { cycle, stage, task_progress }.
11
+ // decisions → decisions[].
12
+ // must-haves → must_haves[].
13
+ // blockers → blockers[].
14
+ // status → position.status.
15
+ // events [--tail N] → last N events from .design/events.jsonl.
16
+ // can-transition <to> → { ok, blockers? } gate result.
17
+ //
18
+ // Exit codes: 0 ok, 1 tool error (missing STATE.md, etc.), 3 arg error.
19
+
20
+ import { existsSync, readFileSync } from 'node:fs';
21
+ import { resolve as resolvePath } from 'node:path';
22
+
23
+ import { read } from '../../gdd-state/index.ts';
24
+ import { gateFor } from '../../gdd-state/gates.ts';
25
+ import { isStage, type ParsedState, type Stage } from '../../gdd-state/types.ts';
26
+
27
+ import {
28
+ coerceFlags,
29
+ COMMON_FLAGS,
30
+ type FlagSpec,
31
+ type ParsedArgs,
32
+ } from '../parse-args.ts';
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Flag spec + help.
36
+ // ---------------------------------------------------------------------------
37
+
38
+ const QUERY_FLAGS: readonly FlagSpec[] = [
39
+ ...COMMON_FLAGS,
40
+ { name: 'tail', type: 'number', default: 20 },
41
+ { name: 'state-path', type: 'string' },
42
+ { name: 'events-path', type: 'string' },
43
+ ];
44
+
45
+ const USAGE = `gdd-sdk query <op> [args] [flags]
46
+
47
+ Typed STATE.md read operations.
48
+
49
+ Operations:
50
+ get Full parsed STATE.md as JSON.
51
+ stage Current stage name.
52
+ position { cycle, stage, task_progress }.
53
+ decisions Locked + tentative decisions.
54
+ must-haves Must-haves list with statuses.
55
+ blockers Active blockers.
56
+ status Current position status.
57
+ events [--tail N] Last N events from .design/events.jsonl (default 20).
58
+ can-transition <to> Gate check for stage "<to>".
59
+
60
+ Flags:
61
+ --cwd <dir> Working directory (resolves .design/STATE.md)
62
+ --state-path <path> Override STATE.md path directly
63
+ --events-path <path> Override events.jsonl path directly
64
+ --tail <n> Number of tail events (default 20)
65
+ --json JSON output (default)
66
+ --text Human-readable output (only for simple scalars)
67
+
68
+ Exit codes:
69
+ 0 ok
70
+ 1 tool error (missing STATE.md / parse error)
71
+ 3 arg error (unknown op, bad --tail value)
72
+ `;
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Deps.
76
+ // ---------------------------------------------------------------------------
77
+
78
+ export type ReadFn = typeof read;
79
+
80
+ export interface QueryCommandDeps {
81
+ readonly readState?: ReadFn;
82
+ readonly stdout?: NodeJS.WritableStream;
83
+ readonly stderr?: NodeJS.WritableStream;
84
+ }
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Entry point.
88
+ // ---------------------------------------------------------------------------
89
+
90
+ const KNOWN_OPS = new Set<string>([
91
+ 'get',
92
+ 'stage',
93
+ 'position',
94
+ 'decisions',
95
+ 'must-haves',
96
+ 'blockers',
97
+ 'status',
98
+ 'events',
99
+ 'can-transition',
100
+ ]);
101
+
102
+ export async function queryCommand(
103
+ args: ParsedArgs,
104
+ deps: QueryCommandDeps = {},
105
+ ): Promise<number> {
106
+ const stdout = deps.stdout ?? process.stdout;
107
+ const stderr = deps.stderr ?? process.stderr;
108
+
109
+ if (args.flags['help'] === true || args.flags['h'] === true) {
110
+ stdout.write(USAGE);
111
+ return 0;
112
+ }
113
+
114
+ const op: string | undefined = args.positionals[0];
115
+ if (op === undefined || op.length === 0) {
116
+ stderr.write('gdd-sdk query: missing operation\n');
117
+ stderr.write(USAGE);
118
+ return 3;
119
+ }
120
+ if (!KNOWN_OPS.has(op)) {
121
+ stderr.write(
122
+ `gdd-sdk query: unknown operation "${op}"\n` +
123
+ `Valid: get | stage | position | decisions | must-haves | blockers | status | events | can-transition\n`,
124
+ );
125
+ return 3;
126
+ }
127
+
128
+ let flags: Record<string, unknown>;
129
+ try {
130
+ flags = coerceFlags(args, QUERY_FLAGS);
131
+ } catch (err) {
132
+ stderr.write(`gdd-sdk query: ${errMessage(err)}\n`);
133
+ return 3;
134
+ }
135
+
136
+ const cwd: string =
137
+ typeof flags['cwd'] === 'string' ? (flags['cwd'] as string) : process.cwd();
138
+ const statePath: string =
139
+ typeof flags['state-path'] === 'string' && (flags['state-path'] as string).length > 0
140
+ ? resolvePath(cwd, flags['state-path'] as string)
141
+ : resolvePath(cwd, '.design', 'STATE.md');
142
+
143
+ // `events` has no dependency on STATE.md, so resolve it before the
144
+ // STATE-read guard below.
145
+ if (op === 'events') {
146
+ return handleEvents(flags, cwd, stdout, stderr);
147
+ }
148
+
149
+ // Every other op needs STATE.md.
150
+ if (!existsSync(statePath)) {
151
+ stderr.write(
152
+ `gdd-sdk query: STATE.md not found at ${statePath}\n`,
153
+ );
154
+ return 1;
155
+ }
156
+
157
+ const readFn: ReadFn = deps.readState ?? read;
158
+ let state: ParsedState;
159
+ try {
160
+ state = await readFn(statePath);
161
+ } catch (err) {
162
+ stderr.write(`gdd-sdk query: failed to read STATE.md: ${errMessage(err)}\n`);
163
+ return 1;
164
+ }
165
+
166
+ // Dispatch by op.
167
+ switch (op) {
168
+ case 'get':
169
+ writeResult(stdout, flags, state);
170
+ return 0;
171
+ case 'stage':
172
+ writeResult(stdout, flags, state.frontmatter.stage);
173
+ return 0;
174
+ case 'position':
175
+ writeResult(stdout, flags, {
176
+ cycle: state.frontmatter.cycle,
177
+ stage: state.position.stage,
178
+ task_progress: state.position.task_progress,
179
+ });
180
+ return 0;
181
+ case 'decisions':
182
+ writeResult(stdout, flags, state.decisions);
183
+ return 0;
184
+ case 'must-haves':
185
+ writeResult(stdout, flags, state.must_haves);
186
+ return 0;
187
+ case 'blockers':
188
+ writeResult(stdout, flags, state.blockers);
189
+ return 0;
190
+ case 'status':
191
+ writeResult(stdout, flags, state.position.status);
192
+ return 0;
193
+ case 'can-transition':
194
+ return handleCanTransition(args, state, stdout, stderr, flags);
195
+ default: {
196
+ stderr.write(`gdd-sdk query: unhandled op "${op}"\n`);
197
+ return 3;
198
+ }
199
+ }
200
+ }
201
+
202
+ // ---------------------------------------------------------------------------
203
+ // Handlers.
204
+ // ---------------------------------------------------------------------------
205
+
206
+ function handleCanTransition(
207
+ args: ParsedArgs,
208
+ state: ParsedState,
209
+ stdout: NodeJS.WritableStream,
210
+ stderr: NodeJS.WritableStream,
211
+ flags: Record<string, unknown>,
212
+ ): number {
213
+ const to: string | undefined = args.positionals[1];
214
+ if (to === undefined || to.length === 0) {
215
+ stderr.write('gdd-sdk query can-transition: missing target stage\n');
216
+ return 3;
217
+ }
218
+ if (!isStage(to)) {
219
+ stderr.write(
220
+ `gdd-sdk query can-transition: "${to}" is not a valid Stage (brief|explore|plan|design|verify)\n`,
221
+ );
222
+ return 3;
223
+ }
224
+ const from: string = state.position.stage;
225
+ if (!isStage(from)) {
226
+ writeResult(stdout, flags, {
227
+ ok: false,
228
+ blockers: [`Invalid transition: from="${from}" is not a recognized Stage`],
229
+ });
230
+ return 0;
231
+ }
232
+ const gate = gateFor(from, to as Stage);
233
+ if (gate === null) {
234
+ writeResult(stdout, flags, {
235
+ ok: false,
236
+ blockers: [`Invalid transition: ${from} → ${to}`],
237
+ });
238
+ return 0;
239
+ }
240
+ const result = gate(state);
241
+ writeResult(
242
+ stdout,
243
+ flags,
244
+ result.pass ? { ok: true } : { ok: false, blockers: result.blockers },
245
+ );
246
+ return 0;
247
+ }
248
+
249
+ function handleEvents(
250
+ flags: Record<string, unknown>,
251
+ cwd: string,
252
+ stdout: NodeJS.WritableStream,
253
+ stderr: NodeJS.WritableStream,
254
+ ): number {
255
+ const eventsPath: string =
256
+ typeof flags['events-path'] === 'string' && (flags['events-path'] as string).length > 0
257
+ ? resolvePath(cwd, flags['events-path'] as string)
258
+ : resolvePath(cwd, '.design', 'events.jsonl');
259
+
260
+ const tail: number =
261
+ typeof flags['tail'] === 'number' ? (flags['tail'] as number) : 20;
262
+ if (!Number.isFinite(tail) || tail < 0) {
263
+ stderr.write(`gdd-sdk query events: --tail must be a non-negative integer\n`);
264
+ return 3;
265
+ }
266
+
267
+ if (!existsSync(eventsPath)) {
268
+ // Missing events file is a tool error: operator expected events but
269
+ // the stream was never written.
270
+ stderr.write(`gdd-sdk query events: events.jsonl not found at ${eventsPath}\n`);
271
+ return 1;
272
+ }
273
+
274
+ let raw: string;
275
+ try {
276
+ raw = readFileSync(eventsPath, 'utf8');
277
+ } catch (err) {
278
+ stderr.write(
279
+ `gdd-sdk query events: failed to read events.jsonl: ${errMessage(err)}\n`,
280
+ );
281
+ return 1;
282
+ }
283
+
284
+ const lines = raw.split(/\r?\n/).filter((l) => l.length > 0);
285
+ const slice = lines.slice(-tail);
286
+ const parsed: unknown[] = [];
287
+ for (const line of slice) {
288
+ try {
289
+ parsed.push(JSON.parse(line));
290
+ } catch {
291
+ // Malformed event line — surface as raw string to avoid losing data.
292
+ parsed.push({ malformed: true, raw: line });
293
+ }
294
+ }
295
+ writeResult({ write: (s: string) => stdout.write(s) } as NodeJS.WritableStream, flags, parsed);
296
+ return 0;
297
+ }
298
+
299
+ // ---------------------------------------------------------------------------
300
+ // Output helper.
301
+ // ---------------------------------------------------------------------------
302
+
303
+ function writeResult(
304
+ stdout: NodeJS.WritableStream,
305
+ flags: Record<string, unknown>,
306
+ value: unknown,
307
+ ): void {
308
+ // JSON is the default; --text prints scalars / simple arrays more plainly.
309
+ if (flags['text'] === true) {
310
+ if (typeof value === 'string') {
311
+ stdout.write(value + '\n');
312
+ return;
313
+ }
314
+ if (
315
+ Array.isArray(value) &&
316
+ value.every((v) => typeof v === 'string')
317
+ ) {
318
+ stdout.write((value as string[]).join('\n') + '\n');
319
+ return;
320
+ }
321
+ // Complex values fall through to JSON.
322
+ }
323
+ stdout.write(JSON.stringify(value, null, 2) + '\n');
324
+ }
325
+
326
+ function errMessage(err: unknown): string {
327
+ if (err instanceof Error) return err.message;
328
+ return String(err);
329
+ }