pi-gsd 1.0.3 → 1.0.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/postinstall.js +199 -169
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gsd",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "Get Shit Done - Unofficial port of the renowned AI-native project-planning spec-driven toolkit",
5
5
  "main": "dist/gsd-tools.js",
6
6
  "bin": {
@@ -30,21 +30,20 @@
30
30
  * @see README.md §3 (Installation) for usage details.
31
31
  */
32
32
 
33
- 'use strict';
34
-
35
- const fs = require('fs');
36
- const path = require('path');
33
+ const fs = require("fs");
34
+ const path = require("path");
37
35
 
38
36
  // ─── Constants ────────────────────────────────────────────────────────────────
39
37
 
40
- const FORCE = process.env.GSD_FORCE_REINSTALL === '1'
41
- || process.argv.includes('--force-reinstall');
38
+ const FORCE =
39
+ process.env.GSD_FORCE_REINSTALL === "1" ||
40
+ process.argv.includes("--force-reinstall");
42
41
 
43
42
  /**
44
43
  * Directory that contains this package's files.
45
44
  * When executed via npm postinstall, __dirname is the package root.
46
45
  */
47
- const PKG_DIR = path.resolve(__dirname, '..');
46
+ const PKG_DIR = path.resolve(__dirname, "..");
48
47
 
49
48
  /**
50
49
  * The consuming project's root.
@@ -62,21 +61,22 @@ const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
62
61
  * hooks - whether this platform supports GSD hooks (copied from .gsd/hooks/)
63
62
  */
64
63
  const HARNESSES = [
65
- { src: 'agent', dest: '.agent', 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 },
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 },
73
73
  ];
74
74
 
75
75
  /**
76
76
  * Subdirectory name used inside each harness's dest folder for
77
77
  * GSD-specific content (workflows, bin, references, templates …).
78
78
  */
79
- const GSD_SUBDIR = 'get-shit-done';
79
+ const GSD_SUBDIR = "get-shit-done";
80
80
 
81
81
  // ─── Helpers ──────────────────────────────────────────────────────────────────
82
82
 
@@ -90,32 +90,32 @@ const GSD_SUBDIR = 'get-shit-done';
90
90
  * @returns {{ copied: number, skipped: number }}
91
91
  */
92
92
  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 };
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 };
119
119
  }
120
120
 
121
121
  /**
@@ -126,130 +126,160 @@ function copyDir(src, dest, overwrite) {
126
126
  * @param {string} msg
127
127
  */
128
128
  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}`);
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}`);
137
137
  }
138
138
 
139
139
  // ─── Main ─────────────────────────────────────────────────────────────────────
140
140
 
141
141
  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('skip', 'Running inside package source tree - skipping harness install.');
146
- return;
147
- }
148
-
149
- // Skip when explicitly opted out
150
- if (process.env.GSD_SKIP_INSTALL === '1') {
151
- log('skip', 'GSD_SKIP_INSTALL=1 - skipping harness install.');
152
- return;
153
- }
154
-
155
- const harnessesRoot = path.join(PKG_DIR, '.gsd', 'harnesses');
156
- const hooksRoot = path.join(PKG_DIR, '.gsd', 'hooks');
157
-
158
- console.log('');
159
- console.log(' GSD - installing harness files into your project…');
160
- if (FORCE) console.log(' (force-reinstall mode: existing files will be overwritten)');
161
- console.log('');
162
-
163
- let totalCopied = 0;
164
- let totalSkipped = 0;
165
- let installed = 0;
166
-
167
- for (const harness of HARNESSES) {
168
- const srcHarness = path.join(harnessesRoot, harness.src);
169
- const destHarness = path.join(PROJECT_ROOT, harness.dest);
170
-
171
- // ── get-shit-done/ content ──────────────────────────────────────────────
172
- const srcGsd = path.join(srcHarness, GSD_SUBDIR);
173
- const destGsd = path.join(destHarness, GSD_SUBDIR);
174
-
175
- if (!fs.existsSync(srcHarness)) {
176
- log('skip', `${harness.dest}/${GSD_SUBDIR} (source absent - skipped)`);
177
- continue;
178
- }
179
-
180
- const { copied, skipped } = copyDir(srcGsd, destGsd, FORCE);
181
- totalCopied += copied;
182
- totalSkipped += skipped;
183
-
184
- if (copied > 0 || skipped === 0) {
185
- log('ok', `${harness.dest}/${GSD_SUBDIR} (${copied} file${copied === 1 ? '' : 's'} installed)`);
186
- } else {
187
- log('skip', `${harness.dest}/${GSD_SUBDIR} (already up-to-date, ${skipped} file${skipped === 1 ? '' : 's'} skipped)`);
188
- }
189
-
190
- // ── gsd-file-manifest.json ──────────────────────────────────────────────
191
- const manifestSrc = path.join(srcHarness, 'gsd-file-manifest.json');
192
- const manifestDest = path.join(destHarness, 'gsd-file-manifest.json');
193
-
194
- if (fs.existsSync(manifestSrc)) {
195
- if (!FORCE && fs.existsSync(manifestDest)) {
196
- totalSkipped++;
197
- } else {
198
- fs.mkdirSync(destHarness, { recursive: true });
199
- fs.copyFileSync(manifestSrc, manifestDest);
200
- totalCopied++;
201
- }
202
- }
203
-
204
- // ── hooks/ (platform-selective) ─────────────────────────────────────────
205
- if (harness.hooks && fs.existsSync(hooksRoot)) {
206
- const destHooks = path.join(destHarness, 'hooks');
207
- const h = copyDir(hooksRoot, destHooks, FORCE);
208
- totalCopied += h.copied;
209
- totalSkipped += h.skipped;
210
-
211
- if (h.copied > 0) {
212
- log('ok', `${harness.dest}/hooks (${h.copied} hook${h.copied === 1 ? '' : 's'} installed)`);
213
- }
214
- }
215
-
216
- // ── skills/ (opencode only - present in .gsd/harnesses/opencode/skills)
217
- const srcSkills = path.join(srcHarness, 'skills');
218
- const destSkills = path.join(destHarness, 'skills');
219
-
220
- if (fs.existsSync(srcSkills)) {
221
- const s = copyDir(srcSkills, destSkills, FORCE);
222
- totalCopied += s.copied;
223
- totalSkipped += s.skipped;
224
-
225
- if (s.copied > 0) {
226
- log('ok', `${harness.dest}/skills (${s.copied} skill file${s.copied === 1 ? '' : 's'} installed)`);
227
- }
228
- }
229
-
230
- installed++;
231
- }
232
-
233
- console.log('');
234
-
235
- if (installed === 0) {
236
- log('warn', 'No harness source directories found inside the package.');
237
- log('warn', 'The package may be incomplete. Try: npm install --force get-shit-done-cc');
238
- console.log('');
239
- return;
240
- }
241
-
242
- console.log(` GSD v${getPackageVersion()} installed successfully.`);
243
- console.log(` ${totalCopied} file${totalCopied === 1 ? '' : 's'} copied, ${totalSkipped} skipped.`);
244
- console.log('');
245
- console.log(' Next steps:');
246
- console.log(' • Claude / Gemini / Cursor / OpenCode: run /gsd:new-project');
247
- console.log(' • Claude Code (.agent): run /gsd-new-project');
248
- console.log(' • Codex: run $gsd-new-project');
249
- console.log(' • GitHub Copilot: run /gsd:new-project');
250
- console.log('');
251
- console.log(' Docs: https://github.com/fulgidus/pi-gsd#readme');
252
- console.log('');
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
+ console.log("");
250
+
251
+ if (installed === 0) {
252
+ log("warn", "No harness source directories found inside the package.");
253
+ log(
254
+ "warn",
255
+ "The package may be incomplete. Try: npm install --force get-shit-done-cc",
256
+ );
257
+ console.log("");
258
+ return;
259
+ }
260
+
261
+ console.log(` GSD v${getPackageVersion()} installed successfully.`);
262
+ console.log(
263
+ ` ${totalCopied} file${totalCopied === 1 ? "" : "s"} copied, ${totalSkipped} skipped.`,
264
+ );
265
+ console.log("");
266
+ console.log(" Next steps:");
267
+ console.log(
268
+ " • Claude / Gemini / Cursor / OpenCode: run /gsd:new-project",
269
+ );
270
+ console.log(" • pi (.pi): run /gsd-new-project");
271
+ console.log(
272
+ " • Claude Code (.agent): run /gsd-new-project",
273
+ );
274
+ console.log(
275
+ " • Codex: run $gsd-new-project",
276
+ );
277
+ console.log(
278
+ " • GitHub Copilot: run /gsd:new-project",
279
+ );
280
+ console.log("");
281
+ console.log(" Docs: https://github.com/fulgidus/pi-gsd#readme");
282
+ console.log("");
253
283
  }
254
284
 
255
285
  /**
@@ -259,14 +289,14 @@ function main() {
259
289
  * @returns {string}
260
290
  */
261
291
  function getPackageVersion() {
262
- try {
263
- const pkg = JSON.parse(
264
- fs.readFileSync(path.join(PKG_DIR, 'package.json'), 'utf8')
265
- );
266
- return pkg.version || 'unknown';
267
- } catch {
268
- return 'unknown';
269
- }
292
+ try {
293
+ const pkg = JSON.parse(
294
+ fs.readFileSync(path.join(PKG_DIR, "package.json"), "utf8"),
295
+ );
296
+ return pkg.version || "unknown";
297
+ } catch {
298
+ return "unknown";
299
+ }
270
300
  }
271
301
 
272
302
  main();