pi-gsd 1.6.1 → 1.6.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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * gsd-hooks.ts - GSD pi Extension
3
- * gsd-extension-version: 1.30.0
2
+ * pi-gsd-hooks.ts pi-gsd Extension
3
+ * pi-gsd-extension-version: 1.6.2
4
4
  *
5
5
  * Pi lifecycle extension for the Get Shit Done (GSD) workflow framework.
6
6
  * Provides three non-blocking hooks:
@@ -128,7 +128,7 @@ export default function (pi: ExtensionAPI) {
128
128
  /\.env/,
129
129
  /AGENTS\.md$/,
130
130
  /settings\.json$/,
131
- /gsd-hooks\.ts$/,
131
+ /pi-gsd-hooks\.ts$/,
132
132
  ];
133
133
  if (allowed.some((p) => p.test(filePath))) return undefined;
134
134
 
@@ -517,7 +517,6 @@ export default function (pi: ExtensionAPI) {
517
517
  },
518
518
  });
519
519
 
520
-
521
520
  // ── tool_result: context usage monitor ───────────────────────────────────
522
521
  const WARNING_THRESHOLD = 35; // warn when remaining % ≤ 35
523
522
  const CRITICAL_THRESHOLD = 25; // critical when remaining % ≤ 25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gsd",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
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": {
@@ -5,7 +5,7 @@
5
5
  * Runs automatically after `npm install pi-gsd`.
6
6
  * Copies the pi harness from this package's
7
7
  * \`.gsd/harnesses/pi/\` into the consumer project's \`.pi/gsd/\`
8
- * and installs the \`gsd-hooks.ts\` extension into \`.pi/extensions/\`.
8
+ * and installs the \`pi-gsd-hooks.ts\` extension into \`.pi/extensions/\`.
9
9
  *
10
10
  * Safe to re-run — files are skipped if already present (unless GSD_FORCE=1).
11
11
  */
@@ -219,7 +219,7 @@ function main() {
219
219
  installed++;
220
220
  }
221
221
 
222
- // ── Pi extension (.pi/extensions/gsd-hooks.ts) ─────────────────────────────
222
+ // ── Pi extension (.pi/extensions/pi-gsd-hooks.ts) ─────────────────────────────
223
223
  // Install the GSD pi lifecycle extension (session_start, tool_call, tool_result hooks).
224
224
  // The extension is auto-discovered by pi from .pi/extensions/ - no manual wiring needed.
225
225
  installPiExtension(PROJECT_ROOT, PKG_DIR, FORCE, (copied) => {
@@ -227,19 +227,32 @@ function main() {
227
227
  else totalSkipped++;
228
228
  });
229
229
 
230
- // ── Pi prompt templates (.pi/prompts/gsd-*.md) ──────────────────────────────
231
- const promptsSrc = path.join(PKG_DIR, "prompts");
230
+ // ── Pi prompt templates cleanup stale local copies ───────────────────────
231
+ // Prompts are served directly from the npm package (user scope).
232
+ // Local copies in .pi/prompts/ cause collision warnings on every pi update.
233
+ // Remove any gsd-*.md files previously installed there.
234
+ // Also remove the old gsd-hooks.ts if present (renamed to pi-gsd-hooks.ts).
232
235
  const promptsDest = path.join(PROJECT_ROOT, ".pi", "prompts");
233
- if (fs.existsSync(promptsSrc)) {
234
- const p = copyDir(promptsSrc, promptsDest, FORCE);
235
- totalCopied += p.copied;
236
- totalSkipped += p.skipped;
237
- if (p.copied > 0) {
238
- log("ok", `.pi/prompts (${p.copied} template${p.copied === 1 ? "" : "s"} installed)`);
239
- } else {
240
- log("skip", `.pi/prompts (already up-to-date)`);
236
+ if (fs.existsSync(promptsDest)) {
237
+ const stale = fs
238
+ .readdirSync(promptsDest)
239
+ .filter((f) => f.startsWith("gsd-") && f.endsWith(".md"));
240
+ if (stale.length > 0) {
241
+ for (const f of stale) fs.rmSync(path.join(promptsDest, f));
242
+ log(
243
+ "ok",
244
+ `.pi/prompts (removed ${stale.length} stale local gsd-*.md — served from package instead)`,
245
+ );
241
246
  }
242
247
  }
248
+ const oldExt = path.join(PROJECT_ROOT, ".pi", "extensions", "gsd-hooks.ts");
249
+ if (fs.existsSync(oldExt)) {
250
+ fs.rmSync(oldExt);
251
+ log(
252
+ "ok",
253
+ ".pi/extensions/gsd-hooks.ts (removed — renamed to pi-gsd-hooks.ts)",
254
+ );
255
+ }
243
256
 
244
257
  console.log("");
245
258
 
@@ -299,17 +312,33 @@ function getPackageVersion() {
299
312
  function installPiExtension(projectRoot, pkgDir, force, callback) {
300
313
  const piDir = path.join(projectRoot, ".pi");
301
314
  const extDir = path.join(piDir, "extensions");
302
- const extDest = path.join(extDir, "gsd-hooks.ts");
303
- const extSrc = path.join(pkgDir, ".gsd", "extensions", "gsd-hooks.ts");
315
+ const extDest = path.join(extDir, "pi-gsd-hooks.ts");
316
+ const extSrc = path.join(pkgDir, ".gsd", "extensions", "pi-gsd-hooks.ts");
304
317
 
305
318
  if (!fs.existsSync(extSrc)) {
306
- log("warn", ".pi/extensions/gsd-hooks.ts (source absent - skipped)");
319
+ log("warn", ".pi/extensions/pi-gsd-hooks.ts (source absent - skipped)");
307
320
  callback(false);
308
321
  return;
309
322
  }
310
323
 
311
- if (!force && fs.existsSync(extDest)) {
312
- log("skip", ".pi/extensions/gsd-hooks.ts (already exists)");
324
+ // Always update the extension — it is owned by pi-gsd, not the user.
325
+ // Compare pi-gsd-extension-version comments to detect staleness.
326
+ const extractVersion = (file) => {
327
+ try {
328
+ const match = fs
329
+ .readFileSync(file, "utf8")
330
+ .match(/pi-gsd-extension-version:\s*([\d.]+)/);
331
+ return match ? match[1] : null;
332
+ } catch {
333
+ return null;
334
+ }
335
+ };
336
+ const srcVersion = extractVersion(extSrc);
337
+ const destVersion = fs.existsSync(extDest) ? extractVersion(extDest) : null;
338
+ const needsUpdate = force || !destVersion || destVersion !== srcVersion;
339
+
340
+ if (!needsUpdate) {
341
+ log("skip", `.pi/extensions/pi-gsd-hooks.ts (up-to-date v${destVersion})`);
313
342
  callback(false);
314
343
  } else {
315
344
  try {
@@ -317,13 +346,13 @@ function installPiExtension(projectRoot, pkgDir, force, callback) {
317
346
  fs.copyFileSync(extSrc, extDest);
318
347
  log(
319
348
  "ok",
320
- ".pi/extensions/gsd-hooks.ts (GSD lifecycle extension installed)",
349
+ ".pi/extensions/pi-gsd-hooks.ts (GSD lifecycle extension installed)",
321
350
  );
322
351
  callback(true);
323
352
  } catch (e) {
324
353
  log(
325
354
  "warn",
326
- ".pi/extensions/gsd-hooks.ts (install failed: " + e.message + ")",
355
+ ".pi/extensions/pi-gsd-hooks.ts (install failed: " + e.message + ")",
327
356
  );
328
357
  callback(false);
329
358
  return;
@@ -348,9 +377,13 @@ function installPiExtension(projectRoot, pkgDir, force, callback) {
348
377
  ? settings.extensions
349
378
  : [];
350
379
 
380
+ // Remove stale gsd-hooks.ts entry if present (renamed to pi-gsd-hooks.ts)
381
+ const oldExtPath = path.join(extDir, "gsd-hooks.ts");
382
+ const cleaned = extensions.filter((e) => e !== oldExtPath);
383
+
351
384
  // Avoid duplicate entries
352
- if (!extensions.includes(extDest)) {
353
- settings.extensions = [...extensions, extDest];
385
+ if (!cleaned.includes(extDest)) {
386
+ settings.extensions = [...cleaned, extDest];
354
387
  fs.mkdirSync(piDir, { recursive: true });
355
388
  fs.writeFileSync(
356
389
  settingsFile,
@@ -358,6 +391,11 @@ function installPiExtension(projectRoot, pkgDir, force, callback) {
358
391
  "utf8",
359
392
  );
360
393
  log("ok", ".pi/settings.json (extensions array updated)");
394
+ } else if (cleaned.length !== extensions.length) {
395
+ // Removed stale entry but extDest already present
396
+ settings.extensions = cleaned;
397
+ fs.writeFileSync(settingsFile, JSON.stringify(settings, null, "\t"), "utf8");
398
+ log("ok", ".pi/settings.json (removed stale gsd-hooks.ts entry)");
361
399
  }
362
400
  } catch (e) {
363
401
  log("warn", ".pi/settings.json (could not update: " + e.message + ")");
@@ -4,7 +4,7 @@ description: Check and repair GSD hook wiring for pi. Use when postinstall was s
4
4
  ---
5
5
 
6
6
  <objective>
7
- Verify that the GSD pi extension (`gsd-hooks.ts`) is correctly installed in the current project.
7
+ Verify that the GSD pi extension (`pi-gsd-hooks.ts`) is correctly installed in the current project.
8
8
  If the extension is missing, install it and update `.pi/settings.json`.
9
9
  If already present, confirm hook wiring and report status.
10
10
  Always route first-time users to `/gsd-new-project` at the end.
@@ -12,7 +12,7 @@ Always route first-time users to `/gsd-new-project` at the end.
12
12
 
13
13
  <context>
14
14
  **Why this skill exists:**
15
- `bun install` does not run npm `postinstall` scripts, so `gsd-hooks.ts` may not be
15
+ `bun install` does not run npm `postinstall` scripts, so `pi-gsd-hooks.ts` may not be
16
16
  automatically copied into the consumer project's `.pi/extensions/` directory.
17
17
  This skill provides a manual fallback that performs the same wiring as `postinstall.js`.
18
18
 
@@ -23,34 +23,34 @@ This skill provides a manual fallback that performs the same wiring as `postinst
23
23
  - `tool_result` → context-usage monitor with debounced warnings
24
24
 
25
25
  **Extension source inside the pi-gsd package:**
26
- `.gsd/extensions/gsd-hooks.ts`
26
+ `.gsd/extensions/pi-gsd-hooks.ts`
27
27
 
28
28
  **Target location in the consumer project:**
29
- `.pi/extensions/gsd-hooks.ts`
29
+ `.pi/extensions/pi-gsd-hooks.ts`
30
30
 
31
31
  **settings.json entry (belt-and-suspenders - pi also auto-discovers from `.pi/extensions/`):**
32
- `{ "extensions": ["<absolute-path-to-.pi/extensions/gsd-hooks.ts>"] }`
32
+ `{ "extensions": ["<absolute-path-to-.pi/extensions/pi-gsd-hooks.ts>"] }`
33
33
  </context>
34
34
 
35
35
  <process>
36
36
 
37
37
  ## Step 1 - Locate the pi-gsd package
38
38
 
39
- Resolve the pi-gsd package root (where `gsd-hooks.ts` lives):
39
+ Resolve the pi-gsd package root (where `pi-gsd-hooks.ts` lives):
40
40
 
41
41
  1. Try `node -e "console.log(require.resolve('pi-gsd/package.json'))"` - strip `/package.json` suffix to get PKG_DIR.
42
42
  2. If that fails, try common global paths:
43
43
  - `~/.bun/install/global/node_modules/pi-gsd`
44
44
  - `/home/linuxbrew/.linuxbrew/lib/node_modules/pi-gsd`
45
45
  - Output of `npm root -g` + `/pi-gsd`
46
- 3. Confirm the extension source exists at `<PKG_DIR>/.gsd/extensions/gsd-hooks.ts`.
46
+ 3. Confirm the extension source exists at `<PKG_DIR>/.gsd/extensions/pi-gsd-hooks.ts`.
47
47
  If the source cannot be found, report the error clearly and stop - do not proceed to Step 2.
48
48
 
49
49
  ## Step 2 - Check current project extension status
50
50
 
51
51
  In the current working directory (the consumer project):
52
52
 
53
- - **Check A:** Does `.pi/extensions/gsd-hooks.ts` exist?
53
+ - **Check A:** Does `.pi/extensions/pi-gsd-hooks.ts` exist?
54
54
  - **Check B:** Does `.pi/settings.json` exist? If yes, does `extensions` array include an absolute path to the extension file?
55
55
  - **Check C:** Does `.pi/extensions/` directory exist?
56
56
 
@@ -59,21 +59,21 @@ In the current working directory (the consumer project):
59
59
  ### If extension is MISSING (Check A failed):
60
60
 
61
61
  1. Create `.pi/extensions/` directory if it does not exist.
62
- 2. Copy `<PKG_DIR>/.gsd/extensions/gsd-hooks.ts` → `.pi/extensions/gsd-hooks.ts`.
62
+ 2. Copy `<PKG_DIR>/.gsd/extensions/pi-gsd-hooks.ts` → `.pi/extensions/pi-gsd-hooks.ts`.
63
63
  3. Update `.pi/settings.json`:
64
- - If the file does not exist, create it as `{ "extensions": ["<absolute-path>/.pi/extensions/gsd-hooks.ts"] }`.
64
+ - If the file does not exist, create it as `{ "extensions": ["<absolute-path>/.pi/extensions/pi-gsd-hooks.ts"] }`.
65
65
  - If the file exists but `extensions` array is missing or does not include the path, add the absolute path.
66
66
  - Preserve all other existing settings - merge, do not overwrite.
67
- 4. Report: `✓ GSD extension installed at .pi/extensions/gsd-hooks.ts`
67
+ 4. Report: `✓ GSD extension installed at .pi/extensions/pi-gsd-hooks.ts`
68
68
  5. Report: `✓ .pi/settings.json updated`
69
69
 
70
70
  ### If extension is PRESENT (Check A passed):
71
71
 
72
72
  1. Confirm the file is non-empty (not a zero-byte stub).
73
- 2. Confirm it contains the marker comment `gsd-extension-version:` - indicating it is the genuine GSD extension, not a stale copy from another tool.
73
+ 2. Confirm it contains the marker comment `pi-gsd-extension-version:` - indicating it is the genuine GSD extension, not a stale copy from another tool.
74
74
  3. Check Check B - if `settings.json` is missing or the extension path is absent, add it now (same logic as missing case, step 3).
75
75
  4. Report:
76
- - `✓ GSD extension present at .pi/extensions/gsd-hooks.ts`
76
+ - `✓ GSD extension present at .pi/extensions/pi-gsd-hooks.ts`
77
77
  - `✓ hooks: session_start (update-check), tool_call (workflow-guard), tool_result (context-monitor)`
78
78
  - `✓ .pi/settings.json` - either "already registered" or "path added"
79
79
 
@@ -84,9 +84,9 @@ Print a concise status table:
84
84
  ```
85
85
  GSD pi hook wiring status
86
86
  ──────────────────────────────────────────────────────────
87
- Extension file .pi/extensions/gsd-hooks.ts ✓ / ✗
87
+ Extension file .pi/extensions/pi-gsd-hooks.ts ✓ / ✗
88
88
  Settings entry .pi/settings.json extensions ✓ / ✗
89
- Extension version gsd-extension-version: X.Y.Z (value)
89
+ Extension version pi-gsd-extension-version: X.Y.Z (value)
90
90
  ──────────────────────────────────────────────────────────
91
91
  ```
92
92