pi-gsd 1.1.0 → 1.2.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.
Files changed (61) hide show
  1. package/.gsd/extensions/gsd-hooks.ts +212 -212
  2. package/README.md +45 -44
  3. package/dist/{gsd-tools.js → pi-gsd-tools.js} +54 -54
  4. package/package.json +6 -6
  5. package/scripts/postinstall.js +253 -293
  6. package/skills/gsd-add-backlog/SKILL.md +3 -3
  7. package/skills/gsd-add-phase/SKILL.md +2 -2
  8. package/skills/gsd-add-tests/SKILL.md +2 -2
  9. package/skills/gsd-add-todo/SKILL.md +2 -2
  10. package/skills/gsd-audit-milestone/SKILL.md +2 -2
  11. package/skills/gsd-audit-uat/SKILL.md +1 -1
  12. package/skills/gsd-autonomous/SKILL.md +4 -4
  13. package/skills/gsd-check-todos/SKILL.md +2 -2
  14. package/skills/gsd-cleanup/SKILL.md +2 -2
  15. package/skills/gsd-complete-milestone/SKILL.md +2 -2
  16. package/skills/gsd-debug/SKILL.md +2 -2
  17. package/skills/gsd-discuss-phase/SKILL.md +6 -6
  18. package/skills/gsd-do/SKILL.md +3 -3
  19. package/skills/gsd-execute-phase/SKILL.md +4 -4
  20. package/skills/gsd-fast/SKILL.md +2 -2
  21. package/skills/gsd-forensics/SKILL.md +2 -2
  22. package/skills/gsd-health/SKILL.md +4 -4
  23. package/skills/gsd-help/SKILL.md +2 -2
  24. package/skills/gsd-insert-phase/SKILL.md +2 -2
  25. package/skills/gsd-list-phase-assumptions/SKILL.md +1 -1
  26. package/skills/gsd-list-workspaces/SKILL.md +3 -3
  27. package/skills/gsd-manager/SKILL.md +4 -4
  28. package/skills/gsd-map-codebase/SKILL.md +1 -1
  29. package/skills/gsd-milestone-summary/SKILL.md +2 -2
  30. package/skills/gsd-new-milestone/SKILL.md +6 -6
  31. package/skills/gsd-new-project/SKILL.md +6 -6
  32. package/skills/gsd-new-workspace/SKILL.md +3 -3
  33. package/skills/gsd-next/SKILL.md +2 -2
  34. package/skills/gsd-note/SKILL.md +3 -3
  35. package/skills/gsd-pause-work/SKILL.md +2 -2
  36. package/skills/gsd-plan-milestone-gaps/SKILL.md +2 -2
  37. package/skills/gsd-plan-phase/SKILL.md +3 -3
  38. package/skills/gsd-plant-seed/SKILL.md +2 -2
  39. package/skills/gsd-pr-branch/SKILL.md +2 -2
  40. package/skills/gsd-profile-user/SKILL.md +2 -2
  41. package/skills/gsd-progress/SKILL.md +4 -4
  42. package/skills/gsd-quick/SKILL.md +2 -2
  43. package/skills/gsd-remove-phase/SKILL.md +2 -2
  44. package/skills/gsd-remove-workspace/SKILL.md +3 -3
  45. package/skills/gsd-research-phase/SKILL.md +3 -3
  46. package/skills/gsd-resume-work/SKILL.md +2 -2
  47. package/skills/gsd-review/SKILL.md +2 -2
  48. package/skills/gsd-review-backlog/SKILL.md +2 -2
  49. package/skills/gsd-session-report/SKILL.md +2 -2
  50. package/skills/gsd-set-profile/SKILL.md +1 -1
  51. package/skills/gsd-settings/SKILL.md +2 -2
  52. package/skills/gsd-setup-pi/SKILL.md +15 -13
  53. package/skills/gsd-ship/SKILL.md +2 -2
  54. package/skills/gsd-stats/SKILL.md +4 -4
  55. package/skills/gsd-thread/SKILL.md +2 -2
  56. package/skills/gsd-ui-phase/SKILL.md +3 -3
  57. package/skills/gsd-ui-review/SKILL.md +3 -3
  58. package/skills/gsd-update/SKILL.md +2 -2
  59. package/skills/gsd-validate-phase/SKILL.md +2 -2
  60. package/skills/gsd-verify-work/SKILL.md +3 -3
  61. package/skills/gsd-workstreams/SKILL.md +1 -1
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "pi-gsd",
3
- "version": "1.1.0",
3
+ "version": "1.2.2",
4
4
  "description": "Get Shit Done - Unofficial port of the renowned AI-native project-planning spec-driven toolkit",
5
- "main": "dist/gsd-tools.js",
5
+ "main": "dist/pi-gsd-tools.js",
6
6
  "bin": {
7
- "gsd-tools": "./dist/gsd-tools.js",
8
- "pi-gsd": "./dist/gsd-tools.js"
7
+ "pi-gsd-tools": "./dist/pi-gsd-tools.js",
8
+ "pi-gsd": "./dist/pi-gsd-tools.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "tsup src/cli.ts --format cjs --out-dir dist --minify --no-splitting && mv dist/cli.js dist/gsd-tools.js && chmod +x dist/gsd-tools.js",
11
+ "build": "tsup src/cli.ts --format cjs --out-dir dist --minify --no-splitting && mv dist/cli.js dist/pi-gsd-tools.js && chmod +x dist/pi-gsd-tools.js",
12
12
  "dev": "tsup src/cli.ts --format cjs --out-dir dist --watch",
13
13
  "typecheck": "tsc --noEmit",
14
14
  "postinstall": "node scripts/postinstall.js",
15
- "prepublishOnly": "npm run build && node scripts/build-harnesses.js --clean"
15
+ "prepublishOnly": "npm run build"
16
16
  },
17
17
  "files": [
18
18
  "skills",
@@ -2,32 +2,12 @@
2
2
  /**
3
3
  * postinstall.js - GSD harness installer
4
4
  *
5
- * Runs automatically after `npm install get-shit-done-cc`.
6
- * Copies each AI-platform harness directory from this package's
7
- * `.gsd/harnesses/<harness>/` into the consumer project's root
8
- * so the AI agent can discover the GSD workflows, commands, hooks,
9
- * and CLI binary at the expected platform-native paths.
5
+ * Runs automatically after `npm install pi-gsd`.
6
+ * Copies the pi harness from this package's
7
+ * \`.gsd/harnesses/pi/\` into the consumer project's \`.pi/gsd/\`
8
+ * and installs the \`gsd-hooks.ts\` extension into \`.pi/extensions/\`.
10
9
  *
11
- * Harness layout inside this package (source):
12
- * .gsd/harnesses/
13
- * agent/ → consumer project root: .agent/get-shit-done/
14
- * claude/ → consumer project root: .claude/get-shit-done/
15
- * codex/ → consumer project root: .codex/get-shit-done/
16
- * cursor/ → consumer project root: .cursor/get-shit-done/
17
- * gemini/ → consumer project root: .gemini/get-shit-done/
18
- * github/ → consumer project root: .github/get-shit-done/
19
- * opencode/ → consumer project root: .opencode/get-shit-done/
20
- * windsurf/ → consumer project root: .windsurf/get-shit-done/
21
- *
22
- * Hook files are also copied from `.gsd/hooks/` into each harness
23
- * that supports the GSD hook system.
24
- *
25
- * The script is intentionally defensive: it never overwrites files
26
- * that already exist (use --force-reinstall env flag to override),
27
- * and it skips silently if a harness source directory is absent
28
- * from the package (forward-compatibility).
29
- *
30
- * @see README.md §3 (Installation) for usage details.
10
+ * Safe to re-run files are skipped if already present (unless GSD_FORCE=1).
31
11
  */
32
12
 
33
13
  const fs = require("fs");
@@ -36,8 +16,8 @@ const path = require("path");
36
16
  // ─── Constants ────────────────────────────────────────────────────────────────
37
17
 
38
18
  const FORCE =
39
- process.env.GSD_FORCE_REINSTALL === "1" ||
40
- process.argv.includes("--force-reinstall");
19
+ process.env.GSD_FORCE_REINSTALL === "1" ||
20
+ process.argv.includes("--force-reinstall");
41
21
 
42
22
  /**
43
23
  * Directory that contains this package's files.
@@ -61,22 +41,14 @@ const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
61
41
  * hooks - whether this platform supports GSD hooks (copied from .gsd/hooks/)
62
42
  */
63
43
  const HARNESSES = [
64
- { src: "agent", dest: ".agent", hooks: true },
65
- { src: "agent", dest: ".pi", hooks: true },
66
- { src: "claude", dest: ".claude", hooks: true },
67
- { src: "codex", dest: ".codex", hooks: false },
68
- { src: "cursor", dest: ".cursor", hooks: false },
69
- { src: "gemini", dest: ".gemini", hooks: true },
70
- { src: "github", dest: ".github", hooks: false },
71
- { src: "opencode", dest: ".opencode", hooks: true },
72
- { src: "windsurf", dest: ".windsurf", hooks: false },
44
+ { src: "pi", dest: ".pi", hooks: true, subdir: "gsd" },
73
45
  ];
74
46
 
75
47
  /**
76
48
  * Subdirectory name used inside each harness's dest folder for
77
49
  * GSD-specific content (workflows, bin, references, templates …).
78
50
  */
79
- const GSD_SUBDIR = "get-shit-done";
51
+ // subdir is now per-harness (see harness config above)
80
52
 
81
53
  // ─── Helpers ──────────────────────────────────────────────────────────────────
82
54
 
@@ -90,32 +62,32 @@ const GSD_SUBDIR = "get-shit-done";
90
62
  * @returns {{ copied: number, skipped: number }}
91
63
  */
92
64
  function copyDir(src, dest, overwrite) {
93
- let copied = 0;
94
- let skipped = 0;
95
-
96
- if (!fs.existsSync(src)) return { copied, skipped };
97
-
98
- fs.mkdirSync(dest, { recursive: true });
99
-
100
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
101
- const srcEntry = path.join(src, entry.name);
102
- const destEntry = path.join(dest, entry.name);
103
-
104
- if (entry.isDirectory()) {
105
- const sub = copyDir(srcEntry, destEntry, overwrite);
106
- copied += sub.copied;
107
- skipped += sub.skipped;
108
- } else if (entry.isFile()) {
109
- if (!overwrite && fs.existsSync(destEntry)) {
110
- skipped++;
111
- } else {
112
- fs.copyFileSync(srcEntry, destEntry);
113
- copied++;
114
- }
115
- }
116
- }
117
-
118
- return { copied, skipped };
65
+ let copied = 0;
66
+ let skipped = 0;
67
+
68
+ if (!fs.existsSync(src)) return { copied, skipped };
69
+
70
+ fs.mkdirSync(dest, { recursive: true });
71
+
72
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
73
+ const srcEntry = path.join(src, entry.name);
74
+ const destEntry = path.join(dest, entry.name);
75
+
76
+ if (entry.isDirectory()) {
77
+ const sub = copyDir(srcEntry, destEntry, overwrite);
78
+ copied += sub.copied;
79
+ skipped += sub.skipped;
80
+ } else if (entry.isFile()) {
81
+ if (!overwrite && fs.existsSync(destEntry)) {
82
+ skipped++;
83
+ } else {
84
+ fs.copyFileSync(srcEntry, destEntry);
85
+ copied++;
86
+ }
87
+ }
88
+ }
89
+
90
+ return { copied, skipped };
119
91
  }
120
92
 
121
93
  /**
@@ -126,168 +98,156 @@ function copyDir(src, dest, overwrite) {
126
98
  * @param {string} msg
127
99
  */
128
100
  function log(level, msg) {
129
- const isTTY = process.stdout.isTTY;
130
- const colours = {
131
- ok: isTTY ? "\x1b[32m✓\x1b[0m" : "✓",
132
- skip: isTTY ? "\x1b[33m–\x1b[0m" : "–",
133
- warn: isTTY ? "\x1b[33m⚠\x1b[0m" : "⚠",
134
- err: isTTY ? "\x1b[31m✗\x1b[0m" : "✗",
135
- };
136
- console.log(` ${colours[level] || " "} ${msg}`);
101
+ const isTTY = process.stdout.isTTY;
102
+ const colours = {
103
+ ok: isTTY ? "\x1b[32m✓\x1b[0m" : "✓",
104
+ skip: isTTY ? "\x1b[33m–\x1b[0m" : "–",
105
+ warn: isTTY ? "\x1b[33m⚠\x1b[0m" : "⚠",
106
+ err: isTTY ? "\x1b[31m✗\x1b[0m" : "✗",
107
+ };
108
+ console.log(` ${colours[level] || " "} ${msg}`);
137
109
  }
138
110
 
139
111
  // ─── Main ─────────────────────────────────────────────────────────────────────
140
112
 
141
113
  function main() {
142
- // Skip when running inside the package's own development tree
143
- // (i.e. when INIT_CWD === the package directory itself).
144
- if (path.resolve(PROJECT_ROOT) === path.resolve(PKG_DIR)) {
145
- log(
146
- "skip",
147
- "Running inside package source tree - skipping harness install.",
148
- );
149
- return;
150
- }
151
-
152
- // Skip when explicitly opted out
153
- if (process.env.GSD_SKIP_INSTALL === "1") {
154
- log("skip", "GSD_SKIP_INSTALL=1 - skipping harness install.");
155
- return;
156
- }
157
-
158
- const harnessesRoot = path.join(PKG_DIR, ".gsd", "harnesses");
159
- const hooksRoot = path.join(PKG_DIR, ".gsd", "hooks");
160
-
161
- console.log("");
162
- console.log(" GSD - installing harness files into your project…");
163
- if (FORCE)
164
- console.log(" (force-reinstall mode: existing files will be overwritten)");
165
- console.log("");
166
-
167
- let totalCopied = 0;
168
- let totalSkipped = 0;
169
- let installed = 0;
170
-
171
- for (const harness of HARNESSES) {
172
- const srcHarness = path.join(harnessesRoot, harness.src);
173
- const destHarness = path.join(PROJECT_ROOT, harness.dest);
174
-
175
- // ── get-shit-done/ content ──────────────────────────────────────────────
176
- const srcGsd = path.join(srcHarness, GSD_SUBDIR);
177
- const destGsd = path.join(destHarness, GSD_SUBDIR);
178
-
179
- if (!fs.existsSync(srcHarness)) {
180
- log("skip", `${harness.dest}/${GSD_SUBDIR} (source absent - skipped)`);
181
- continue;
182
- }
183
-
184
- const { copied, skipped } = copyDir(srcGsd, destGsd, FORCE);
185
- totalCopied += copied;
186
- totalSkipped += skipped;
187
-
188
- if (copied > 0 || skipped === 0) {
189
- log(
190
- "ok",
191
- `${harness.dest}/${GSD_SUBDIR} (${copied} file${copied === 1 ? "" : "s"} installed)`,
192
- );
193
- } else {
194
- log(
195
- "skip",
196
- `${harness.dest}/${GSD_SUBDIR} (already up-to-date, ${skipped} file${skipped === 1 ? "" : "s"} skipped)`,
197
- );
198
- }
199
-
200
- // ── gsd-file-manifest.json ──────────────────────────────────────────────
201
- const manifestSrc = path.join(srcHarness, "gsd-file-manifest.json");
202
- const manifestDest = path.join(destHarness, "gsd-file-manifest.json");
203
-
204
- if (fs.existsSync(manifestSrc)) {
205
- if (!FORCE && fs.existsSync(manifestDest)) {
206
- totalSkipped++;
207
- } else {
208
- fs.mkdirSync(destHarness, { recursive: true });
209
- fs.copyFileSync(manifestSrc, manifestDest);
210
- totalCopied++;
211
- }
212
- }
213
-
214
- // ── hooks/ (platform-selective) ─────────────────────────────────────────
215
- if (harness.hooks && fs.existsSync(hooksRoot)) {
216
- const destHooks = path.join(destHarness, "hooks");
217
- const h = copyDir(hooksRoot, destHooks, FORCE);
218
- totalCopied += h.copied;
219
- totalSkipped += h.skipped;
220
-
221
- if (h.copied > 0) {
222
- log(
223
- "ok",
224
- `${harness.dest}/hooks (${h.copied} hook${h.copied === 1 ? "" : "s"} installed)`,
225
- );
226
- }
227
- }
228
-
229
- // ── skills/ (opencode only - present in .gsd/harnesses/opencode/skills) ─
230
- const srcSkills = path.join(srcHarness, "skills");
231
- const destSkills = path.join(destHarness, "skills");
232
-
233
- if (fs.existsSync(srcSkills)) {
234
- const s = copyDir(srcSkills, destSkills, FORCE);
235
- totalCopied += s.copied;
236
- totalSkipped += s.skipped;
237
-
238
- if (s.copied > 0) {
239
- log(
240
- "ok",
241
- `${harness.dest}/skills (${s.copied} skill file${s.copied === 1 ? "" : "s"} installed)`,
242
- );
243
- }
244
- }
245
-
246
- installed++;
247
- }
248
-
249
- // ── Pi extension (.pi/extensions/gsd-hooks.ts) ─────────────────────────────
250
- // Install the GSD pi lifecycle extension (session_start, tool_call, tool_result hooks).
251
- // The extension is auto-discovered by pi from .pi/extensions/ no manual wiring needed.
252
- installPiExtension(PROJECT_ROOT, PKG_DIR, FORCE, (copied) => {
253
- if (copied) totalCopied++;
254
- else totalSkipped++;
255
- });
256
-
257
- console.log("");
258
-
259
- if (installed === 0) {
260
- log("warn", "No harness source directories found inside the package.");
261
- log(
262
- "warn",
263
- "The package may be incomplete. Try: npm install --force get-shit-done-cc",
264
- );
265
- console.log("");
266
- return;
267
- }
268
-
269
- console.log(` GSD v${getPackageVersion()} installed successfully.`);
270
- console.log(
271
- ` ${totalCopied} file${totalCopied === 1 ? "" : "s"} copied, ${totalSkipped} skipped.`,
272
- );
273
- console.log("");
274
- console.log(" Next steps:");
275
- console.log(
276
- " • Claude / Gemini / Cursor / OpenCode: run /gsd:new-project",
277
- );
278
- console.log(" • pi (.pi): run /gsd-new-project");
279
- console.log(
280
- " • Claude Code (.agent): run /gsd-new-project",
281
- );
282
- console.log(
283
- " • Codex: run $gsd-new-project",
284
- );
285
- console.log(
286
- " • GitHub Copilot: run /gsd:new-project",
287
- );
288
- console.log("");
289
- console.log(" Docs: https://github.com/fulgidus/pi-gsd#readme");
290
- console.log("");
114
+ // Skip when running inside the package's own development tree
115
+ // (i.e. when INIT_CWD === the package directory itself).
116
+ if (path.resolve(PROJECT_ROOT) === path.resolve(PKG_DIR)) {
117
+ log(
118
+ "skip",
119
+ "Running inside package source tree - skipping harness install.",
120
+ );
121
+ return;
122
+ }
123
+
124
+ // Skip when explicitly opted out
125
+ if (process.env.GSD_SKIP_INSTALL === "1") {
126
+ log("skip", "GSD_SKIP_INSTALL=1 - skipping harness install.");
127
+ return;
128
+ }
129
+
130
+ const harnessesRoot = path.join(PKG_DIR, ".gsd", "harnesses");
131
+ const hooksRoot = path.join(PKG_DIR, ".gsd", "hooks");
132
+
133
+ console.log("");
134
+ console.log(" GSD - installing harness files into your project…");
135
+ if (FORCE)
136
+ console.log(" (force-reinstall mode: existing files will be overwritten)");
137
+ console.log("");
138
+
139
+ let totalCopied = 0;
140
+ let totalSkipped = 0;
141
+ let installed = 0;
142
+
143
+ for (const harness of HARNESSES) {
144
+ const srcHarness = path.join(harnessesRoot, harness.src);
145
+ const destHarness = path.join(PROJECT_ROOT, harness.dest);
146
+
147
+ // ── get-shit-done/ content ──────────────────────────────────────────────
148
+ const srcGsd = path.join(srcHarness, harness.subdir);
149
+ const destGsd = path.join(destHarness, harness.subdir);
150
+
151
+ if (!fs.existsSync(srcHarness)) {
152
+ log("skip", `${harness.dest}/${harness.subdir} (source absent - skipped)`);
153
+ continue;
154
+ }
155
+
156
+ const { copied, skipped } = copyDir(srcGsd, destGsd, FORCE);
157
+ totalCopied += copied;
158
+ totalSkipped += skipped;
159
+
160
+ if (copied > 0 || skipped === 0) {
161
+ log(
162
+ "ok",
163
+ `${harness.dest}/${harness.subdir} (${copied} file${copied === 1 ? "" : "s"} installed)`,
164
+ );
165
+ } else {
166
+ log(
167
+ "skip",
168
+ `${harness.dest}/${harness.subdir} (already up-to-date, ${skipped} file${skipped === 1 ? "" : "s"} skipped)`,
169
+ );
170
+ }
171
+
172
+ // ── gsd-file-manifest.json ──────────────────────────────────────────────
173
+ const manifestSrc = path.join(srcHarness, "gsd-file-manifest.json");
174
+ const manifestDest = path.join(destHarness, "gsd-file-manifest.json");
175
+
176
+ if (fs.existsSync(manifestSrc)) {
177
+ if (!FORCE && fs.existsSync(manifestDest)) {
178
+ totalSkipped++;
179
+ } else {
180
+ fs.mkdirSync(destHarness, { recursive: true });
181
+ fs.copyFileSync(manifestSrc, manifestDest);
182
+ totalCopied++;
183
+ }
184
+ }
185
+
186
+ // ── hooks/ (platform-selective) ─────────────────────────────────────────
187
+ if (harness.hooks && fs.existsSync(hooksRoot)) {
188
+ const destHooks = path.join(destHarness, "hooks");
189
+ const h = copyDir(hooksRoot, destHooks, FORCE);
190
+ totalCopied += h.copied;
191
+ totalSkipped += h.skipped;
192
+
193
+ if (h.copied > 0) {
194
+ log(
195
+ "ok",
196
+ `${harness.dest}/hooks (${h.copied} hook${h.copied === 1 ? "" : "s"} installed)`,
197
+ );
198
+ }
199
+ }
200
+
201
+ // ── skills/ (opencode only - present in .gsd/harnesses/opencode/skills) ─
202
+ const srcSkills = path.join(srcHarness, "skills");
203
+ const destSkills = path.join(destHarness, "skills");
204
+
205
+ if (fs.existsSync(srcSkills)) {
206
+ const s = copyDir(srcSkills, destSkills, FORCE);
207
+ totalCopied += s.copied;
208
+ totalSkipped += s.skipped;
209
+
210
+ if (s.copied > 0) {
211
+ log(
212
+ "ok",
213
+ `${harness.dest}/skills (${s.copied} skill file${s.copied === 1 ? "" : "s"} installed)`,
214
+ );
215
+ }
216
+ }
217
+
218
+ installed++;
219
+ }
220
+
221
+ // ── Pi extension (.pi/extensions/gsd-hooks.ts) ─────────────────────────────
222
+ // Install the GSD pi lifecycle extension (session_start, tool_call, tool_result hooks).
223
+ // The extension is auto-discovered by pi from .pi/extensions/ - no manual wiring needed.
224
+ installPiExtension(PROJECT_ROOT, PKG_DIR, FORCE, (copied) => {
225
+ if (copied) totalCopied++;
226
+ else totalSkipped++;
227
+ });
228
+
229
+ console.log("");
230
+
231
+ if (installed === 0) {
232
+ log("warn", "No harness source directories found inside the package.");
233
+ log(
234
+ "warn",
235
+ "The package may be incomplete. Try: npm install --force get-shit-done-cc",
236
+ );
237
+ console.log("");
238
+ return;
239
+ }
240
+
241
+ console.log(` GSD v${getPackageVersion()} installed successfully.`);
242
+ console.log(
243
+ ` ${totalCopied} file${totalCopied === 1 ? "" : "s"} copied, ${totalSkipped} skipped.`,
244
+ );
245
+ console.log("");
246
+ console.log(" Next steps:");
247
+ console.log(" Run /gsd-new-project to initialise a project.");
248
+ console.log("");
249
+ console.log(" Docs: https://github.com/fulgidus/pi-gsd#readme");
250
+ console.log("");
291
251
  }
292
252
 
293
253
  /**
@@ -297,14 +257,14 @@ function main() {
297
257
  * @returns {string}
298
258
  */
299
259
  function getPackageVersion() {
300
- try {
301
- const pkg = JSON.parse(
302
- fs.readFileSync(path.join(PKG_DIR, "package.json"), "utf8"),
303
- );
304
- return pkg.version || "unknown";
305
- } catch {
306
- return "unknown";
307
- }
260
+ try {
261
+ const pkg = JSON.parse(
262
+ fs.readFileSync(path.join(PKG_DIR, "package.json"), "utf8"),
263
+ );
264
+ return pkg.version || "unknown";
265
+ } catch {
266
+ return "unknown";
267
+ }
308
268
  }
309
269
 
310
270
  /**
@@ -322,71 +282,71 @@ function getPackageVersion() {
322
282
  * @param {function} callback Called with (copied: boolean)
323
283
  */
324
284
  function installPiExtension(projectRoot, pkgDir, force, callback) {
325
- const piDir = path.join(projectRoot, ".pi");
326
- const extDir = path.join(piDir, "extensions");
327
- const extDest = path.join(extDir, "gsd-hooks.ts");
328
- const extSrc = path.join(pkgDir, ".gsd", "extensions", "gsd-hooks.ts");
329
-
330
- if (!fs.existsSync(extSrc)) {
331
- log("warn", ".pi/extensions/gsd-hooks.ts (source absent - skipped)");
332
- callback(false);
333
- return;
334
- }
335
-
336
- if (!force && fs.existsSync(extDest)) {
337
- log("skip", ".pi/extensions/gsd-hooks.ts (already exists)");
338
- callback(false);
339
- } else {
340
- try {
341
- fs.mkdirSync(extDir, { recursive: true });
342
- fs.copyFileSync(extSrc, extDest);
343
- log(
344
- "ok",
345
- ".pi/extensions/gsd-hooks.ts (GSD lifecycle extension installed)",
346
- );
347
- callback(true);
348
- } catch (e) {
349
- log(
350
- "warn",
351
- ".pi/extensions/gsd-hooks.ts (install failed: " + e.message + ")",
352
- );
353
- callback(false);
354
- return;
355
- }
356
- }
357
-
358
- // Update .pi/settings.json to include the extension path in the extensions array.
359
- // The file is already auto-discovered from .pi/extensions/, but explicit registration
360
- // is added as a belt-and-suspenders measure.
361
- const settingsFile = path.join(piDir, "settings.json");
362
- try {
363
- let settings = {};
364
- if (fs.existsSync(settingsFile)) {
365
- try {
366
- settings = JSON.parse(fs.readFileSync(settingsFile, "utf8"));
367
- } catch {
368
- // Unreadable settings start fresh object
369
- }
370
- }
371
-
372
- const extensions = Array.isArray(settings.extensions)
373
- ? settings.extensions
374
- : [];
375
-
376
- // Avoid duplicate entries
377
- if (!extensions.includes(extDest)) {
378
- settings.extensions = [...extensions, extDest];
379
- fs.mkdirSync(piDir, { recursive: true });
380
- fs.writeFileSync(
381
- settingsFile,
382
- JSON.stringify(settings, null, "\t"),
383
- "utf8",
384
- );
385
- log("ok", ".pi/settings.json (extensions array updated)");
386
- }
387
- } catch (e) {
388
- log("warn", ".pi/settings.json (could not update: " + e.message + ")");
389
- }
285
+ const piDir = path.join(projectRoot, ".pi");
286
+ const extDir = path.join(piDir, "extensions");
287
+ const extDest = path.join(extDir, "gsd-hooks.ts");
288
+ const extSrc = path.join(pkgDir, ".gsd", "extensions", "gsd-hooks.ts");
289
+
290
+ if (!fs.existsSync(extSrc)) {
291
+ log("warn", ".pi/extensions/gsd-hooks.ts (source absent - skipped)");
292
+ callback(false);
293
+ return;
294
+ }
295
+
296
+ if (!force && fs.existsSync(extDest)) {
297
+ log("skip", ".pi/extensions/gsd-hooks.ts (already exists)");
298
+ callback(false);
299
+ } else {
300
+ try {
301
+ fs.mkdirSync(extDir, { recursive: true });
302
+ fs.copyFileSync(extSrc, extDest);
303
+ log(
304
+ "ok",
305
+ ".pi/extensions/gsd-hooks.ts (GSD lifecycle extension installed)",
306
+ );
307
+ callback(true);
308
+ } catch (e) {
309
+ log(
310
+ "warn",
311
+ ".pi/extensions/gsd-hooks.ts (install failed: " + e.message + ")",
312
+ );
313
+ callback(false);
314
+ return;
315
+ }
316
+ }
317
+
318
+ // Update .pi/settings.json to include the extension path in the extensions array.
319
+ // The file is already auto-discovered from .pi/extensions/, but explicit registration
320
+ // is added as a belt-and-suspenders measure.
321
+ const settingsFile = path.join(piDir, "settings.json");
322
+ try {
323
+ let settings = {};
324
+ if (fs.existsSync(settingsFile)) {
325
+ try {
326
+ settings = JSON.parse(fs.readFileSync(settingsFile, "utf8"));
327
+ } catch {
328
+ // Unreadable settings - start fresh object
329
+ }
330
+ }
331
+
332
+ const extensions = Array.isArray(settings.extensions)
333
+ ? settings.extensions
334
+ : [];
335
+
336
+ // Avoid duplicate entries
337
+ if (!extensions.includes(extDest)) {
338
+ settings.extensions = [...extensions, extDest];
339
+ fs.mkdirSync(piDir, { recursive: true });
340
+ fs.writeFileSync(
341
+ settingsFile,
342
+ JSON.stringify(settings, null, "\t"),
343
+ "utf8",
344
+ );
345
+ log("ok", ".pi/settings.json (extensions array updated)");
346
+ }
347
+ } catch (e) {
348
+ log("warn", ".pi/settings.json (could not update: " + e.message + ")");
349
+ }
390
350
  }
391
351
 
392
352
  main();
@@ -20,7 +20,7 @@ the normal phase sequence and accumulate context over time.
20
20
  2. **Find next backlog number:**
21
21
 
22
22
  ```bash
23
- NEXT=$(node ".pi/get-shit-done/bin/gsd-tools.cjs" phase next-decimal 999 --raw)
23
+ NEXT=$(node ".pi/gsd/bin/pi-gsd-tools.cjs" phase next-decimal 999 --raw)
24
24
  ```
25
25
 
26
26
  If no 999.x phases exist, start at 999.1.
@@ -28,7 +28,7 @@ the normal phase sequence and accumulate context over time.
28
28
  3. **Create the phase directory:**
29
29
 
30
30
  ```bash
31
- SLUG=$(node ".pi/get-shit-done/bin/gsd-tools.cjs" generate-slug "$ARGUMENTS")
31
+ SLUG=$(node ".pi/gsd/bin/pi-gsd-tools.cjs" generate-slug "$ARGUMENTS")
32
32
  mkdir -p ".planning/phases/${NEXT}-${SLUG}"
33
33
  touch ".planning/phases/${NEXT}-${SLUG}/.gitkeep"
34
34
  ```
@@ -52,7 +52,7 @@ the normal phase sequence and accumulate context over time.
52
52
  5. **Commit:**
53
53
 
54
54
  ```bash
55
- node ".pi/get-shit-done/bin/gsd-tools.cjs" commit "docs: add backlog item ${NEXT} - ${ARGUMENTS}" --files .planning/ROADMAP.md ".planning/phases/${NEXT}-${SLUG}/.gitkeep"
55
+ node ".pi/gsd/bin/pi-gsd-tools.cjs" commit "docs: add backlog item ${NEXT} - ${ARGUMENTS}" --files .planning/ROADMAP.md ".planning/phases/${NEXT}-${SLUG}/.gitkeep"
56
56
  ```
57
57
 
58
58
  6. **Report:**