pi-gsd 1.3.0 → 1.3.2

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.
@@ -254,18 +254,15 @@ export default function (pi: ExtensionAPI) {
254
254
  return lines;
255
255
  };
256
256
 
257
- const formatProgress = (cwd: string): string => {
257
+ const formatProgress = (cwd: string): { text: string; data: GsdProgress | null } => {
258
258
  const data = runJson<GsdProgress>("progress json", cwd);
259
259
  if (!data)
260
- return "❌ No GSD project found. Run /gsd-new-project to initialise.";
260
+ return { text: "❌ No GSD project found. Run /gsd-new-project to initialise.", data: null };
261
261
 
262
- const phasePct = data.percent ?? 0;
263
- const planPct =
264
- data.total_plans > 0
265
- ? Math.round((data.total_summaries / data.total_plans) * 100)
266
- : 0;
267
262
  const done = data.phases.filter((p) => p.status === "Complete").length;
268
263
  const total = data.phases.length;
264
+ const phasePct = total > 0 ? Math.round((done / total) * 100) : 0;
265
+ const planPct =
269
266
 
270
267
  const lines = [
271
268
  `━━ GSD Progress ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
@@ -279,13 +276,13 @@ export default function (pi: ExtensionAPI) {
279
276
  ``,
280
277
  `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
281
278
  ];
282
- return lines.join("\n");
279
+ return { text: lines.join("\n"), data };
283
280
  };
284
281
 
285
- const formatStats = (cwd: string): string => {
282
+ const formatStats = (cwd: string): { text: string; data: GsdStats | null } => {
286
283
  const data = runJson<GsdStats>("stats json", cwd);
287
284
  if (!data)
288
- return "❌ No GSD project found. Run /gsd-new-project to initialise.";
285
+ return { text: "❌ No GSD project found. Run /gsd-new-project to initialise.", data: null };
289
286
 
290
287
  const reqPct =
291
288
  data.requirements_total > 0
@@ -311,7 +308,7 @@ export default function (pi: ExtensionAPI) {
311
308
  ``,
312
309
  `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
313
310
  ];
314
- return lines.join("\n");
311
+ return { text: lines.join("\n"), data };
315
312
  };
316
313
 
317
314
  const formatHealth = (cwd: string, repair: boolean): string => {
@@ -349,17 +346,40 @@ export default function (pi: ExtensionAPI) {
349
346
  return lines.join("\n");
350
347
  };
351
348
 
349
+ /** Derive the suggested next command string from phase data. */
350
+ const nextCommand = (phases: GsdPhase[]): string | null => {
351
+ const pending = phases.filter((p) => p.status !== "Complete");
352
+ if (pending.length === 0) return "/gsd-audit-milestone";
353
+ const next = pending[0];
354
+ const n = next.number;
355
+ if (next.plans === 0) return `/gsd-discuss-phase ${n}`;
356
+ if (next.summaries < next.plans) return `/gsd-execute-phase ${n}`;
357
+ return `/gsd-verify-work ${n}`;
358
+ };
359
+
352
360
  pi.registerCommand("gsd-progress", {
353
361
  description: "Show project progress with next steps (instant)",
354
362
  handler: async (_args, ctx) => {
355
- ctx.ui.notify(formatProgress(ctx.cwd), "info");
363
+ const { text, data } = formatProgress(ctx.cwd);
364
+ ctx.ui.notify(text, "info");
365
+ // Pivot affordance: pre-fill the editor with the most relevant next action
366
+ // so the user can run it, modify it, or just type something else entirely
367
+ if (data) {
368
+ const cmd = nextCommand(data.phases);
369
+ if (cmd) ctx.ui.setEditorText(cmd);
370
+ }
356
371
  },
357
372
  });
358
373
 
359
374
  pi.registerCommand("gsd-stats", {
360
375
  description: "Show project statistics (instant)",
361
376
  handler: async (_args, ctx) => {
362
- ctx.ui.notify(formatStats(ctx.cwd), "info");
377
+ const { text, data } = formatStats(ctx.cwd);
378
+ ctx.ui.notify(text, "info");
379
+ if (data) {
380
+ const cmd = nextCommand(data.phases);
381
+ if (cmd) ctx.ui.setEditorText(cmd);
382
+ }
363
383
  },
364
384
  });
365
385
 
@@ -374,6 +394,67 @@ export default function (pi: ExtensionAPI) {
374
394
  },
375
395
  });
376
396
 
397
+ pi.registerCommand("gsd-next", {
398
+ description: "Auto-advance to the next GSD action (instant, no LLM)",
399
+ handler: async (_args, ctx) => {
400
+ const data = runJson<GsdProgress>("progress json", ctx.cwd);
401
+ if (!data) {
402
+ ctx.ui.notify(
403
+ "❌ No GSD project found. Run /gsd-new-project to initialise.",
404
+ "error",
405
+ );
406
+ ctx.ui.setEditorText("/gsd-new-project");
407
+ return;
408
+ }
409
+
410
+ const pending = data.phases.filter((p) => p.status !== "Complete");
411
+
412
+ if (pending.length === 0) {
413
+ ctx.ui.notify(
414
+ [
415
+ `━━ GSD Next ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
416
+ `✅ All phases complete!`,
417
+ `→ /gsd-audit-milestone`,
418
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
419
+ ].join("\n"),
420
+ "info",
421
+ );
422
+ ctx.ui.setEditorText("/gsd-audit-milestone");
423
+ return;
424
+ }
425
+
426
+ const next = pending[0];
427
+ const n = next.number;
428
+ let action: string;
429
+ let reason: string;
430
+
431
+ if (next.plans === 0) {
432
+ action = `/gsd-discuss-phase ${n}`;
433
+ reason = `Phase ${n} has no plans yet — start with discussion`;
434
+ } else if (next.summaries < next.plans) {
435
+ action = `/gsd-execute-phase ${n}`;
436
+ reason = `Phase ${n}: ${next.summaries}/${next.plans} plans done — continue execution`;
437
+ } else {
438
+ action = `/gsd-verify-work ${n}`;
439
+ reason = `Phase ${n}: all plans done — verify UAT`;
440
+ }
441
+
442
+ ctx.ui.notify(
443
+ [
444
+ `━━ GSD Next ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
445
+ `⏩ ${reason}`,
446
+ `→ ${action}`,
447
+ ...(pending.length > 1
448
+ ? [` (${pending.length - 1} more phase${pending.length > 2 ? "s" : ""} pending after this)`]
449
+ : []),
450
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
451
+ ].join("\n"),
452
+ "info",
453
+ );
454
+ ctx.ui.setEditorText(action);
455
+ },
456
+ });
457
+
377
458
  pi.registerCommand("gsd-help", {
378
459
  description: "List all GSD commands (instant)",
379
460
  handler: async (_args, ctx) => {
package/README.md CHANGED
@@ -133,14 +133,12 @@ Switch profile: `/gsd-set-profile <profile>`
133
133
  | `[-o\|--output] [toon\|json]` output | ❌ | ⚡ | Token-efficient toon renderer output (or json, if LLM absolutely needs it...) |
134
134
  | `[-p\|--pick] {JSONPath}` extraction | ❌ | ⚡ | Field extraction from CLI output |
135
135
  | TypeScript source | ❌ | ⚡ | Full TS port of gsd-tools (~9k lines) |
136
- | Compile-time type safety | ❌ | | Fully typed - no `any`, only Zod-inferred types |
137
- | Runtime validation (Zod) | ❌ | | Schema-driven `validate health` with field-path errors |
138
- | Smarter `--repair` | ❌ | | Zod schema defaults fill all missing/invalid fields at once |
139
- | Instant commands (no LLM cost) | ❌ | ✔️ | `/gsd-progress`, `/gsd-stats`, `/gsd-health`, `/gsd-help` — formatted output + deterministic next steps, zero LLM |
140
- | Prompt-dispatch for all skills | ❌ | ✔️ | 54 pi prompt templates clean autocomplete, arg hints, direct workflow dispatch |
141
-
142
- <!-- | Pi harness config entry | ❌ | ✔️ | `HARNESS_CONFIG` pi entry - generates `AGENTS.md` via `/gsd-profile-user` | -->
143
- <!-- | Toon output in skills | ❌ | ✔️ | `gsd-progress`, `gsd-stats`, `gsd-health` use `--output toon` | -->
136
+ | Compile-time type safety | ❌ | ⚠️ | Zod schemas defined; ~25 loose `any` casts remain in lib modules |
137
+ | Runtime validation (Zod) | ❌ | ⚠️ | Zod schemas for all `.planning/` types; wired to `config.json` + `validate health` full coverage in progress |
138
+ | Smarter `--repair` | ❌ | | Schema-driven repair not yet implemented |
139
+ | Instant commands (no LLM cost) | ❌ | ✔️ | `/gsd-progress`, `/gsd-stats`, `/gsd-health`, `/gsd-help`, `/gsd-next` — zero LLM, editor pivot |
140
+ | `/gsd-next` auto-advance | ❌ | ✔️ | Deterministic phase routing, pre-fills editor with the correct next command |
141
+ | Prompt-dispatch for all skills | ❌ | ✔️ | 54 pi prompt templates — clean autocomplete, arg hints, direct workflow dispatch |
144
142
 
145
143
  ---
146
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gsd",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Get Shit Done - Unofficial port of the renowned AI-native project-planning spec-driven toolkit",
5
5
  "main": "dist/pi-gsd-tools.js",
6
6
  "bin": {