pi-gsd 1.0.3 → 1.0.5
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.
- package/package.json +1 -1
- package/scripts/postinstall.js +199 -169
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -30,21 +30,20 @@
|
|
|
30
30
|
* @see README.md §3 (Installation) for usage details.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
|
|
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 =
|
|
41
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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 =
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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();
|