pi-gsd 2.0.1 → 2.0.3

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 (66) hide show
  1. package/dist/pi-gsd-hooks.js +1533 -0
  2. package/dist/pi-gsd-tools.js +53 -52
  3. package/package.json +3 -5
  4. package/.gsd/extensions/pi-gsd-hooks.ts +0 -973
  5. package/src/cli.ts +0 -644
  6. package/src/commands/base.ts +0 -67
  7. package/src/commands/commit.ts +0 -22
  8. package/src/commands/config.ts +0 -71
  9. package/src/commands/frontmatter.ts +0 -51
  10. package/src/commands/index.ts +0 -76
  11. package/src/commands/init.ts +0 -43
  12. package/src/commands/milestone.ts +0 -37
  13. package/src/commands/phase.ts +0 -92
  14. package/src/commands/progress.ts +0 -71
  15. package/src/commands/roadmap.ts +0 -40
  16. package/src/commands/scaffold.ts +0 -19
  17. package/src/commands/state.ts +0 -102
  18. package/src/commands/template.ts +0 -52
  19. package/src/commands/verify.ts +0 -70
  20. package/src/commands/workstream.ts +0 -98
  21. package/src/commands/wxp.ts +0 -65
  22. package/src/lib/commands.ts +0 -1040
  23. package/src/lib/config.ts +0 -385
  24. package/src/lib/core.ts +0 -1167
  25. package/src/lib/frontmatter.ts +0 -462
  26. package/src/lib/init.ts +0 -517
  27. package/src/lib/milestone.ts +0 -290
  28. package/src/lib/model-profiles.ts +0 -272
  29. package/src/lib/phase.ts +0 -1012
  30. package/src/lib/profile-output.ts +0 -237
  31. package/src/lib/profile-pipeline.ts +0 -556
  32. package/src/lib/roadmap.ts +0 -378
  33. package/src/lib/schemas.ts +0 -290
  34. package/src/lib/security.ts +0 -176
  35. package/src/lib/state.ts +0 -1175
  36. package/src/lib/template.ts +0 -246
  37. package/src/lib/uat.ts +0 -289
  38. package/src/lib/verify.ts +0 -879
  39. package/src/lib/workstream.ts +0 -524
  40. package/src/output.ts +0 -45
  41. package/src/schemas/pi-gsd-settings.schema.json +0 -80
  42. package/src/schemas/wxp.xsd +0 -619
  43. package/src/schemas/wxp.zod.ts +0 -318
  44. package/src/wxp/__tests__/arguments.test.ts +0 -86
  45. package/src/wxp/__tests__/conditions.test.ts +0 -106
  46. package/src/wxp/__tests__/executor.test.ts +0 -95
  47. package/src/wxp/__tests__/helpers.ts +0 -26
  48. package/src/wxp/__tests__/integration.test.ts +0 -166
  49. package/src/wxp/__tests__/new-features.test.ts +0 -222
  50. package/src/wxp/__tests__/parser.test.ts +0 -159
  51. package/src/wxp/__tests__/paste.test.ts +0 -66
  52. package/src/wxp/__tests__/schema.test.ts +0 -120
  53. package/src/wxp/__tests__/security.test.ts +0 -87
  54. package/src/wxp/__tests__/shell.test.ts +0 -85
  55. package/src/wxp/__tests__/string-ops.test.ts +0 -25
  56. package/src/wxp/__tests__/variables.test.ts +0 -65
  57. package/src/wxp/arguments.ts +0 -89
  58. package/src/wxp/conditions.ts +0 -78
  59. package/src/wxp/executor.ts +0 -191
  60. package/src/wxp/index.ts +0 -191
  61. package/src/wxp/parser.ts +0 -198
  62. package/src/wxp/paste.ts +0 -51
  63. package/src/wxp/security.ts +0 -102
  64. package/src/wxp/shell.ts +0 -81
  65. package/src/wxp/string-ops.ts +0 -44
  66. package/src/wxp/variables.ts +0 -109
package/src/cli.ts DELETED
@@ -1,644 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * cli.ts - GSD Tools CLI entry point.
4
- *
5
- * Oclif-based command router (CLI-01, CLI-02, CLI-03).
6
- * All commands are typed oclif classes in src/commands/.
7
- * Commander.js has been removed (CLI-05).
8
- */
9
-
10
- import fs from "fs";
11
- import path from "path";
12
- import {
13
- findProjectRoot,
14
- getActiveWorkstream,
15
- gsdError,
16
- resolveWorktreeRoot,
17
- } from "./lib/core.js";
18
- import { formatOutput, type OutputFormat } from "./output.js";
19
- import type { Command } from "@oclif/core";
20
-
21
- // ─── Oclif command map (CLI-01, CLI-02, CLI-03) ───────────────────────────────
22
-
23
- type CommandConstructor = typeof Command & { run(argv: string[]): Promise<void> };
24
-
25
- async function buildCommandMap(): Promise<Record<string, CommandConstructor>> {
26
- const {
27
- StateJsonCommand,
28
- StateGetCommand,
29
- StateUpdateCommand,
30
- StatePatchCommand,
31
- StateAdvancePlanCommand,
32
- StateLoadCommand,
33
- StateUpdateProgressCommand,
34
- InitCommand,
35
- RoadmapAnalyzeCommand,
36
- RoadmapGetPhaseCommand,
37
- RoadmapUpdatePlanProgressCommand,
38
- ConfigGetCommand,
39
- ConfigSetCommand,
40
- ConfigSetModelProfileCommand,
41
- ConfigNewProjectCommand,
42
- ConfigEnsureSectionCommand,
43
- PhaseNextDecimalCommand,
44
- PhaseAddCommand,
45
- PhaseInsertCommand,
46
- PhaseRemoveCommand,
47
- PhaseCompleteCommand,
48
- PhasePlanIndexCommand,
49
- MilestoneCompleteCommand,
50
- RequirementsMarkCompleteCommand,
51
- ValidateConsistencyCommand,
52
- ValidateHealthCommand,
53
- ValidateAgentsCommand,
54
- VerifyCommand,
55
- AuditUatCommand,
56
- WorkstreamCreateCommand,
57
- WorkstreamListCommand,
58
- WorkstreamStatusCommand,
59
- WorkstreamCompleteCommand,
60
- WorkstreamSetCommand,
61
- WorkstreamGetCommand,
62
- WorkstreamProgressCommand,
63
- ScaffoldCommand,
64
- CommitCommand,
65
- FrontmatterGetCommand,
66
- FrontmatterSetCommand,
67
- FrontmatterMergeCommand,
68
- TemplateSelectCommand,
69
- TemplateFillCommand,
70
- ProgressCommand,
71
- StatsCommand,
72
- TodoCompleteCommand,
73
- TodoMatchPhaseCommand,
74
- SummaryExtractCommand,
75
- WxpProcessCommand,
76
- } = await import("./commands/index.js");
77
-
78
- return {
79
- // state
80
- "state json": StateJsonCommand as unknown as CommandConstructor,
81
- "state get": StateGetCommand as unknown as CommandConstructor,
82
- "state update": StateUpdateCommand as unknown as CommandConstructor,
83
- "state patch": StatePatchCommand as unknown as CommandConstructor,
84
- "state advance-plan": StateAdvancePlanCommand as unknown as CommandConstructor,
85
- "state load": StateLoadCommand as unknown as CommandConstructor,
86
- "state update-progress": StateUpdateProgressCommand as unknown as CommandConstructor,
87
- // init
88
- "init": InitCommand as unknown as CommandConstructor,
89
- // roadmap
90
- "roadmap analyze": RoadmapAnalyzeCommand as unknown as CommandConstructor,
91
- "roadmap get-phase": RoadmapGetPhaseCommand as unknown as CommandConstructor,
92
- "roadmap update-plan-progress": RoadmapUpdatePlanProgressCommand as unknown as CommandConstructor,
93
- // config
94
- "config-get": ConfigGetCommand as unknown as CommandConstructor,
95
- "config-set": ConfigSetCommand as unknown as CommandConstructor,
96
- "config-set-model-profile": ConfigSetModelProfileCommand as unknown as CommandConstructor,
97
- "config-new-project": ConfigNewProjectCommand as unknown as CommandConstructor,
98
- "config-ensure-section": ConfigEnsureSectionCommand as unknown as CommandConstructor,
99
- // phase
100
- "phase next-decimal": PhaseNextDecimalCommand as unknown as CommandConstructor,
101
- "phase add": PhaseAddCommand as unknown as CommandConstructor,
102
- "phase insert": PhaseInsertCommand as unknown as CommandConstructor,
103
- "phase remove": PhaseRemoveCommand as unknown as CommandConstructor,
104
- "phase complete": PhaseCompleteCommand as unknown as CommandConstructor,
105
- "phase-plan-index": PhasePlanIndexCommand as unknown as CommandConstructor,
106
- // milestone
107
- "milestone complete": MilestoneCompleteCommand as unknown as CommandConstructor,
108
- "requirements mark-complete": RequirementsMarkCompleteCommand as unknown as CommandConstructor,
109
- // validate / verify
110
- "validate consistency": ValidateConsistencyCommand as unknown as CommandConstructor,
111
- "validate health": ValidateHealthCommand as unknown as CommandConstructor,
112
- "validate agents": ValidateAgentsCommand as unknown as CommandConstructor,
113
- "verify": VerifyCommand as unknown as CommandConstructor,
114
- "audit-uat": AuditUatCommand as unknown as CommandConstructor,
115
- // workstream
116
- "workstream create": WorkstreamCreateCommand as unknown as CommandConstructor,
117
- "workstream list": WorkstreamListCommand as unknown as CommandConstructor,
118
- "workstream status": WorkstreamStatusCommand as unknown as CommandConstructor,
119
- "workstream complete": WorkstreamCompleteCommand as unknown as CommandConstructor,
120
- "workstream set": WorkstreamSetCommand as unknown as CommandConstructor,
121
- "workstream get": WorkstreamGetCommand as unknown as CommandConstructor,
122
- "workstream progress": WorkstreamProgressCommand as unknown as CommandConstructor,
123
- // scaffold
124
- "scaffold": ScaffoldCommand as unknown as CommandConstructor,
125
- // commit
126
- "commit": CommitCommand as unknown as CommandConstructor,
127
- // frontmatter
128
- "frontmatter get": FrontmatterGetCommand as unknown as CommandConstructor,
129
- "frontmatter set": FrontmatterSetCommand as unknown as CommandConstructor,
130
- "frontmatter merge": FrontmatterMergeCommand as unknown as CommandConstructor,
131
- // template
132
- "template select": TemplateSelectCommand as unknown as CommandConstructor,
133
- "template fill": TemplateFillCommand as unknown as CommandConstructor,
134
- // progress / stats / todo
135
- "progress": ProgressCommand as unknown as CommandConstructor,
136
- "stats": StatsCommand as unknown as CommandConstructor,
137
- "todo complete": TodoCompleteCommand as unknown as CommandConstructor,
138
- "todo match-phase": TodoMatchPhaseCommand as unknown as CommandConstructor,
139
- "summary-extract": SummaryExtractCommand as unknown as CommandConstructor,
140
- // wxp (CLI-04)
141
- "wxp process": WxpProcessCommand as unknown as CommandConstructor,
142
- };
143
- }
144
-
145
- // ─── Legacy arg parsing (for remaining switch-based commands) ─────────────────
146
-
147
- function parseNamedArgs(
148
- args: string[],
149
- valueFlags: string[] = [],
150
- booleanFlags: string[] = [],
151
- ): Record<string, string | boolean | null> {
152
- const result: Record<string, string | boolean | null> = {};
153
- for (const flag of valueFlags) {
154
- const idx = args.indexOf(`--${flag}`);
155
- result[flag] =
156
- idx !== -1 && args[idx + 1] !== undefined && !args[idx + 1].startsWith("--")
157
- ? args[idx + 1]
158
- : null;
159
- }
160
- for (const flag of booleanFlags) {
161
- result[flag] = args.includes(`--${flag}`);
162
- }
163
- return result;
164
- }
165
-
166
- function parseMultiwordArg(args: string[], flag: string): string | null {
167
- const idx = args.indexOf(`--${flag}`);
168
- if (idx === -1) return null;
169
- const tokens: string[] = [];
170
- for (let i = idx + 1; i < args.length; i++) {
171
- if (args[i].startsWith("--")) break;
172
- tokens.push(args[i]);
173
- }
174
- return tokens.length > 0 ? tokens.join(" ") : null;
175
- }
176
-
177
- function extractField(obj: unknown, fieldPath: string): unknown {
178
- const parts = fieldPath.split(".");
179
- let current: unknown = obj;
180
- for (const part of parts) {
181
- if (current === null || current === undefined) return undefined;
182
- const bracketMatch = part.match(/^(.+?)\[(-?\d+)]$/);
183
- if (bracketMatch) {
184
- const key = bracketMatch[1];
185
- const index = parseInt(bracketMatch[2], 10);
186
- current = (current as Record<string, unknown>)[key];
187
- if (!Array.isArray(current)) return undefined;
188
- current = index < 0 ? current[current.length + index] : current[index];
189
- } else {
190
- current = (current as Record<string, unknown>)[part];
191
- }
192
- }
193
- return current;
194
- }
195
-
196
- // ─── Command key resolution ───────────────────────────────────────────────────
197
-
198
- function findCommandKey(
199
- argv: string[],
200
- map: Record<string, CommandConstructor>,
201
- ): string | null {
202
- // Try 2-token key first (e.g. "state json"), then 1-token (e.g. "commit")
203
- const twoToken = argv.slice(0, 2).join(" ");
204
- if (map[twoToken]) return twoToken;
205
- const oneToken = argv[0];
206
- if (oneToken && map[oneToken]) return oneToken;
207
- return null;
208
- }
209
-
210
- // ─── Main ─────────────────────────────────────────────────────────────────────
211
-
212
- async function main(): Promise<void> {
213
- const argv = process.argv.slice(2);
214
-
215
- // --help at top level
216
- if (argv[0] === "--help" || argv[0] === "-h") {
217
- printHelp();
218
- return;
219
- }
220
-
221
- // Strip --cwd
222
- let cwd = process.cwd();
223
- {
224
- const cwdEqArg = argv.find((a) => a.startsWith("--cwd="));
225
- const cwdIdx = argv.indexOf("--cwd");
226
- if (cwdEqArg) {
227
- const value = cwdEqArg.slice("--cwd=".length).trim();
228
- if (!value) gsdError("Missing value for --cwd");
229
- argv.splice(argv.indexOf(cwdEqArg), 1);
230
- cwd = path.resolve(value);
231
- } else if (cwdIdx !== -1) {
232
- const value = argv[cwdIdx + 1];
233
- if (!value || value.startsWith("--")) gsdError("Missing value for --cwd");
234
- argv.splice(cwdIdx, 2);
235
- cwd = path.resolve(value);
236
- }
237
- if (!fs.existsSync(cwd) || !fs.statSync(cwd).isDirectory())
238
- gsdError(`Invalid --cwd: ${cwd}`);
239
- }
240
-
241
- // Worktree resolution
242
- if (!fs.existsSync(path.join(cwd, ".planning"))) {
243
- const worktreeRoot = resolveWorktreeRoot(cwd);
244
- if (worktreeRoot !== cwd) cwd = worktreeRoot;
245
- }
246
-
247
- // --ws workstream
248
- {
249
- const wsEqArg = argv.find((a) => a.startsWith("--ws="));
250
- const wsIdx = argv.indexOf("--ws");
251
- let ws: string | null = null;
252
- if (wsEqArg) {
253
- ws = wsEqArg.slice("--ws=".length).trim();
254
- if (!ws) gsdError("Missing value for --ws");
255
- argv.splice(argv.indexOf(wsEqArg), 1);
256
- } else if (wsIdx !== -1) {
257
- ws = argv[wsIdx + 1];
258
- if (!ws || ws.startsWith("--")) gsdError("Missing value for --ws");
259
- argv.splice(wsIdx, 2);
260
- } else if (process.env["GSD_WORKSTREAM"]) {
261
- ws = process.env["GSD_WORKSTREAM"].trim();
262
- } else {
263
- ws = getActiveWorkstream(cwd);
264
- }
265
- if (ws && !/^[a-zA-Z0-9_-]+$/.test(ws)) gsdError("Invalid workstream name");
266
- if (ws) process.env["GSD_WORKSTREAM"] = ws;
267
- }
268
-
269
- // --raw
270
- const rawIndex = argv.indexOf("--raw");
271
- const raw = rawIndex !== -1;
272
- if (rawIndex !== -1) argv.splice(rawIndex, 1);
273
-
274
- // --output
275
- let outputFormat: OutputFormat = "json";
276
- {
277
- const outputIdx = argv.findIndex((a) => a === "--output" || a === "-o");
278
- if (outputIdx !== -1) {
279
- const fmt = argv[outputIdx + 1];
280
- if (!fmt || fmt.startsWith("--")) gsdError("Missing value for --output");
281
- if (fmt !== "json" && fmt !== "toon") gsdError('--output must be "json" or "toon"');
282
- outputFormat = fmt as OutputFormat;
283
- argv.splice(outputIdx, 2);
284
- }
285
- }
286
-
287
- // --pick
288
- let pickPath: string | null = null;
289
- let legacyPickField: string | null = null;
290
- {
291
- const pickIdx = argv.findIndex((a) => a === "--pick" || a === "-p");
292
- if (pickIdx !== -1) {
293
- pickPath = argv[pickIdx + 1];
294
- if (!pickPath || pickPath.startsWith("--")) gsdError("Missing value for --pick");
295
- argv.splice(pickIdx, 2);
296
- }
297
- }
298
-
299
- if (!argv[0]) {
300
- printHelp();
301
- return;
302
- }
303
-
304
- // Inject cwd back as --cwd for oclif commands (BaseCommand reads it from flags)
305
- const oclifArgv = [...argv, "--cwd", cwd];
306
- if (raw) oclifArgv.push("--raw");
307
-
308
- // ── Try oclif command map first ────────────────────────────────────────────
309
- const commandMap = await buildCommandMap();
310
- const key = findCommandKey(argv, commandMap);
311
-
312
- if (key) {
313
- // Build argv for the oclif command: strip the command key tokens, pass rest
314
- const keyTokenCount = key.split(" ").length;
315
- const cmdArgv = [...argv.slice(keyTokenCount), "--cwd", cwd];
316
- if (raw) cmdArgv.push("--raw");
317
-
318
- // Output interception for --pick / --output toon
319
- if (legacyPickField || pickPath || outputFormat !== "json") {
320
- const origWriteSync = fs.writeSync.bind(fs);
321
- const chunks: string[] = [];
322
- (fs as unknown as { writeSync: typeof fs.writeSync }).writeSync = (
323
- fd: number,
324
- data: string | Buffer | NodeJS.ArrayBufferView,
325
- ...rest: unknown[]
326
- ): number => {
327
- if (fd === 1) { chunks.push(String(data)); return String(data).length; }
328
- return (origWriteSync as (...args: unknown[]) => number)(fd, data, ...rest);
329
- };
330
- try {
331
- await commandMap[key].run(cmdArgv);
332
- } finally {
333
- (fs as unknown as { writeSync: typeof fs.writeSync }).writeSync =
334
- origWriteSync as typeof fs.writeSync;
335
- const captured = chunks.join("");
336
- try {
337
- const obj = JSON.parse(captured);
338
- let result: unknown = obj;
339
- if (legacyPickField) result = extractField(obj, legacyPickField) ?? "";
340
- origWriteSync(1, formatOutput(result, outputFormat, pickPath ?? undefined));
341
- } catch { origWriteSync(1, captured); }
342
- }
343
- return;
344
- }
345
-
346
- await commandMap[key].run(cmdArgv);
347
- return;
348
- }
349
-
350
- // ── Fall through to legacy switch for remaining commands ───────────────────
351
- const command = argv[0];
352
- const args = argv;
353
-
354
- // Root resolution
355
- const SKIP_ROOT_RESOLUTION = new Set([
356
- "generate-slug", "current-timestamp", "verify-path-exists",
357
- "verify-summary", "template", "frontmatter", "generate-model-profiles-md",
358
- ]);
359
- if (!SKIP_ROOT_RESOLUTION.has(command)) {
360
- cwd = findProjectRoot(cwd);
361
- }
362
-
363
- const runLegacy = async () => {
364
- await runLegacyCommand(command, args, cwd, raw);
365
- };
366
-
367
- if (legacyPickField || pickPath || outputFormat !== "json") {
368
- const origWriteSync = fs.writeSync.bind(fs);
369
- const chunks: string[] = [];
370
- (fs as unknown as { writeSync: typeof fs.writeSync }).writeSync = (
371
- fd: number,
372
- data: string | Buffer | NodeJS.ArrayBufferView,
373
- ...rest: unknown[]
374
- ): number => {
375
- if (fd === 1) { chunks.push(String(data)); return String(data).length; }
376
- return (origWriteSync as (...args: unknown[]) => number)(fd, data, ...rest);
377
- };
378
- try {
379
- await runLegacy();
380
- } finally {
381
- (fs as unknown as { writeSync: typeof fs.writeSync }).writeSync =
382
- origWriteSync as typeof fs.writeSync;
383
- const captured = chunks.join("");
384
- try {
385
- const obj = JSON.parse(captured);
386
- let result: unknown = obj;
387
- if (legacyPickField) result = extractField(obj, legacyPickField) ?? "";
388
- origWriteSync(1, formatOutput(result, outputFormat, pickPath ?? undefined));
389
- } catch { origWriteSync(1, captured); }
390
- }
391
- return;
392
- }
393
-
394
- await runLegacy();
395
- }
396
-
397
- function printHelp(): void {
398
- process.stdout.write([
399
- "Usage: pi-gsd-tools <command> [subcommand] [args] [--raw] [--cwd <path>] [--ws <name>]",
400
- "",
401
- "Commands: state, init, roadmap, config-get, config-set, phase, milestone,",
402
- " validate, verify, workstream, scaffold, commit, frontmatter, template,",
403
- " progress, stats, todo, summary-extract, wxp, resolve-model, find-phase,",
404
- " generate-slug, current-timestamp, list-todos, verify-path-exists,",
405
- " audit-uat, uat, generate-model-profiles-md, and more.",
406
- "",
407
- "Add --help to any command for details.",
408
- ].join("\n") + "\n");
409
- }
410
-
411
- // ─── Legacy command router (for commands not yet with oclif classes) ──────────
412
-
413
- async function runLegacyCommand(
414
- command: string,
415
- args: string[],
416
- cwd: string,
417
- raw: boolean,
418
- ): Promise<void> {
419
- switch (command) {
420
- case "resolve-model": {
421
- const { cmdResolveModel } = await import("./lib/commands.js");
422
- cmdResolveModel(cwd, args[1], raw);
423
- break;
424
- }
425
- case "find-phase": {
426
- const { cmdFindPhase } = await import("./lib/phase.js");
427
- cmdFindPhase(cwd, args[1], raw);
428
- break;
429
- }
430
- case "commit-to-subrepo": {
431
- const { cmdCommitToSubrepo } = await import("./lib/commands.js");
432
- const filesIndex = args.indexOf("--files");
433
- const messageArgs = args.slice(1, filesIndex !== -1 ? filesIndex : args.length)
434
- .filter((a) => !a.startsWith("--"));
435
- const files = filesIndex !== -1
436
- ? args.slice(filesIndex + 1).filter((a) => !a.startsWith("--"))
437
- : [];
438
- cmdCommitToSubrepo(cwd, messageArgs.join(" ") || undefined, files, raw);
439
- break;
440
- }
441
- case "verify-summary": {
442
- const { cmdVerifySummary } = await import("./lib/verify.js");
443
- const checkCount = args[2] ? parseInt(args[2], 10) : 2;
444
- cmdVerifySummary(cwd, args[1], checkCount, raw);
445
- break;
446
- }
447
- case "generate-slug": {
448
- const { cmdGenerateSlug } = await import("./lib/commands.js");
449
- cmdGenerateSlug(args[1], raw);
450
- break;
451
- }
452
- case "current-timestamp": {
453
- const { cmdCurrentTimestamp } = await import("./lib/commands.js");
454
- cmdCurrentTimestamp(args[1], raw);
455
- break;
456
- }
457
- case "list-todos": {
458
- const { cmdListTodos } = await import("./lib/commands.js");
459
- cmdListTodos(cwd, args[1], raw);
460
- break;
461
- }
462
- case "verify-path-exists": {
463
- const { cmdVerifyPathExists } = await import("./lib/commands.js");
464
- cmdVerifyPathExists(cwd, args[1], raw);
465
- break;
466
- }
467
- case "phases": {
468
- const { cmdPhasesList } = await import("./lib/phase.js");
469
- cmdPhasesList(cwd, {}, raw);
470
- break;
471
- }
472
- case "requirements": {
473
- const { cmdRequirementsMarkComplete } = await import("./lib/milestone.js");
474
- if (args[1] === "mark-complete") cmdRequirementsMarkComplete(cwd, args.slice(2), raw);
475
- else gsdError("Unknown requirements subcommand. Available: mark-complete");
476
- break;
477
- }
478
- case "uat": {
479
- const uat = await import("./lib/uat.js");
480
- if (args[1] === "render-checkpoint") {
481
- uat.cmdRenderCheckpoint(
482
- cwd,
483
- parseNamedArgs(args, ["file"]) as { file?: string | null },
484
- raw,
485
- );
486
- } else gsdError("Unknown uat subcommand. Available: render-checkpoint");
487
- break;
488
- }
489
- case "state-snapshot": {
490
- const { cmdStateSnapshot } = await import("./lib/state.js");
491
- cmdStateSnapshot(cwd, raw);
492
- break;
493
- }
494
- case "agent-skills": {
495
- const { cmdAgentSkills } = await import("./lib/init.js");
496
- cmdAgentSkills(cwd, args[1], raw);
497
- break;
498
- }
499
- case "history-digest": {
500
- const { cmdHistoryDigest } = await import("./lib/commands.js");
501
- cmdHistoryDigest(cwd, raw);
502
- break;
503
- }
504
- case "scan-sessions": {
505
- const { cmdScanSessions } = await import("./lib/profile-pipeline.js");
506
- const pathIdx = args.indexOf("--path"), harnessIdx = args.indexOf("--harness");
507
- await cmdScanSessions(
508
- pathIdx !== -1 ? args[pathIdx + 1] : null,
509
- { verbose: args.includes("--verbose"), json: args.includes("--json"),
510
- harness: harnessIdx !== -1 ? args[harnessIdx + 1] : null },
511
- raw,
512
- );
513
- break;
514
- }
515
- case "extract-messages": {
516
- const { cmdExtractMessages } = await import("./lib/profile-pipeline.js");
517
- const sessionIdx = args.indexOf("--session");
518
- const limitIdx = args.indexOf("--limit");
519
- const pathIdx = args.indexOf("--path");
520
- const isPiDirArg = (s: string) => s.startsWith("--") && s.endsWith("--") && s.length > 4;
521
- if (!args[1] || (args[1].startsWith("--") && !isPiDirArg(args[1])))
522
- gsdError("Usage: pi-gsd-tools extract-messages <project> [--session <id>] [--limit N]");
523
- await cmdExtractMessages(
524
- args[1],
525
- { sessionId: sessionIdx !== -1 ? args[sessionIdx + 1] : null,
526
- limit: limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : null },
527
- raw,
528
- pathIdx !== -1 ? args[pathIdx + 1] : null,
529
- );
530
- break;
531
- }
532
- case "profile-sample": {
533
- const { cmdProfileSample } = await import("./lib/profile-pipeline.js");
534
- const pathIdx = args.indexOf("--path"), limitIdx = args.indexOf("--limit");
535
- const maxPerIdx = args.indexOf("--max-per-project"), maxCharsIdx = args.indexOf("--max-chars");
536
- const harnessIdx = args.indexOf("--harness");
537
- await cmdProfileSample(
538
- pathIdx !== -1 ? args[pathIdx + 1] : null,
539
- { limit: limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : 150,
540
- maxPerProject: maxPerIdx !== -1 ? parseInt(args[maxPerIdx + 1], 10) : null,
541
- harness: harnessIdx !== -1 ? args[harnessIdx + 1] : null,
542
- maxChars: maxCharsIdx !== -1 ? parseInt(args[maxCharsIdx + 1], 10) : 500 },
543
- raw,
544
- );
545
- break;
546
- }
547
- case "write-profile": {
548
- const { cmdWriteProfile } = await import("./lib/profile-output.js");
549
- const inputIdx = args.indexOf("--input"), outputIdx = args.indexOf("--output");
550
- if (inputIdx === -1) gsdError("--input <analysis-json-path> is required");
551
- cmdWriteProfile(cwd, { input: args[inputIdx + 1], output: outputIdx !== -1 ? args[outputIdx + 1] : null }, raw);
552
- break;
553
- }
554
- case "profile-questionnaire": {
555
- const { cmdProfileQuestionnaire } = await import("./lib/profile-output.js");
556
- const answersIdx = args.indexOf("--answers");
557
- cmdProfileQuestionnaire({ answers: answersIdx !== -1 ? args[answersIdx + 1] : null }, raw);
558
- break;
559
- }
560
- case "generate-dev-preferences": {
561
- const { cmdGenerateDevPreferences } = await import("./lib/profile-output.js");
562
- const analysisIdx = args.indexOf("--analysis"), outputIdx = args.indexOf("--output");
563
- const stackIdx = args.indexOf("--stack");
564
- cmdGenerateDevPreferences(cwd, {
565
- analysis: analysisIdx !== -1 ? args[analysisIdx + 1] : null,
566
- output: outputIdx !== -1 ? args[outputIdx + 1] : null,
567
- stack: stackIdx !== -1 ? args[stackIdx + 1] : null,
568
- }, raw);
569
- break;
570
- }
571
- case "generate-claude-profile": {
572
- const { cmdGenerateClaudeProfile } = await import("./lib/profile-output.js");
573
- const analysisIdx = args.indexOf("--analysis"), outputIdx = args.indexOf("--output");
574
- cmdGenerateClaudeProfile(cwd, {
575
- analysis: analysisIdx !== -1 ? args[analysisIdx + 1] : null,
576
- output: outputIdx !== -1 ? args[outputIdx + 1] : null,
577
- global: args.includes("--global"),
578
- }, raw);
579
- break;
580
- }
581
- case "generate-claude-md": {
582
- const { cmdGenerateClaudeMd } = await import("./lib/profile-output.js");
583
- const outputIdx = args.indexOf("--output"), harnessIdx = args.indexOf("--harness");
584
- cmdGenerateClaudeMd(cwd, {
585
- output: outputIdx !== -1 ? args[outputIdx + 1] : null,
586
- auto: args.includes("--auto"),
587
- force: args.includes("--force"),
588
- harness: harnessIdx !== -1 ? args[harnessIdx + 1] : null,
589
- }, raw);
590
- break;
591
- }
592
- case "generate-model-profiles-md": {
593
- const { generateModelProfilesMd } = await import("./lib/model-profiles.js");
594
- const outputIdx = args.indexOf("--output");
595
- const content = generateModelProfilesMd();
596
- if (args.includes("--stdout")) { process.stdout.write(content); break; }
597
- const outPath = outputIdx !== -1
598
- ? path.resolve(args[outputIdx + 1])
599
- : path.resolve(__dirname, "..", "references", "model-profiles.md");
600
- fs.writeFileSync(outPath, content, "utf-8");
601
- raw ? process.stdout.write(outPath) : process.stdout.write(`Wrote ${outPath}\n`);
602
- break;
603
- }
604
- case "websearch": {
605
- const { cmdWebsearch } = await import("./lib/commands.js");
606
- const limitIdx = args.indexOf("--limit"), freshnessIdx = args.indexOf("--freshness");
607
- await cmdWebsearch(args[1], {
608
- limit: limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : 10,
609
- freshness: freshnessIdx !== -1 ? args[freshnessIdx + 1] : null,
610
- }, raw);
611
- break;
612
- }
613
- case "map-codebase": {
614
- const { cmdInitMapCodebase } = await import("./lib/init.js");
615
- await cmdInitMapCodebase(cwd, raw);
616
- break;
617
- }
618
- case "new-project":
619
- case "new-milestone":
620
- case "plan-phase":
621
- case "execute-phase":
622
- case "verify-work":
623
- case "phase-op":
624
- case "milestone-op":
625
- case "resume":
626
- case "quick":
627
- case "manager":
628
- case "progress":
629
- case "new-workspace":
630
- case "list-workspaces":
631
- case "remove-workspace": {
632
- // These are routed via 'init <workflow>' in the oclif map
633
- gsdError(`Use: pi-gsd-tools init ${command} [args]`);
634
- break;
635
- }
636
- default:
637
- gsdError(`Unknown command: ${command}`);
638
- }
639
- }
640
-
641
- main().catch((err) => {
642
- process.stderr.write("Fatal: " + (err as Error).message + "\n");
643
- process.exit(1);
644
- });