@therocketcode/gsd-core 1.7.2 → 1.7.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,7 +1,7 @@
1
1
  {
2
2
  "name": "gsd-core",
3
3
  "displayName": "GSD Core",
4
- "version": "1.7.2",
4
+ "version": "1.7.3",
5
5
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
6
6
  "author": {
7
7
  "name": "TheRocketCodeMX",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-core",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "GSD Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads gsd's operating context into every Gemini CLI session.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
@@ -56,6 +56,18 @@ const LEGACY_CACHE_FILENAMES = [
56
56
  'gsd-update-check-opengsd-gsd-core.json',
57
57
  ];
58
58
 
59
+ /**
60
+ * Legacy runtime directory names left inside a runtime config dir by a
61
+ * superseded install. The current fork installs its runtime under `gsd-core/`;
62
+ * the pre-rename upstream used `get-shit-done/`. When a user migrates, the
63
+ * file-level migration deletes the OLD dir's files but leaves the emptied
64
+ * directory tree behind — harmless, but untidy. We prune such a dir ONLY when
65
+ * it contains zero files (a strict emptiness guard, re-checked at apply time),
66
+ * so we can never delete a directory that still holds user-authored content.
67
+ * NEVER list 'gsd-core' here — that is the CURRENT runtime dir.
68
+ */
69
+ const LEGACY_RUNTIME_DIR_NAMES = ['get-shit-done'];
70
+
59
71
  /**
60
72
  * Subtrees within a configDir that GSD actively scans for old-package content.
61
73
  * Deliberately excludes 'gsd-core' — the current package's own infra and
@@ -151,6 +163,8 @@ function fileContainsOldPackageSignal(absPath, fsMod) {
151
163
  * - 'content-references-old-package': a code file whose content contains
152
164
  * the old package name signal (hooks/ and commands/ subtrees only).
153
165
  * - 'legacy-shared-cache': the old package's shared update-check cache file.
166
+ * - 'empty-legacy-runtime-dir': a superseded runtime dir (e.g. get-shit-done/)
167
+ * left empty after a migration deleted its files.
154
168
  *
155
169
  * @param {string[]} configDirs - absolute paths to runtime config dirs to scan
156
170
  * @param {object} [opts]
@@ -207,6 +221,25 @@ function planLegacyCleanup(configDirs, opts = {}) {
207
221
  }
208
222
  }
209
223
 
224
+ // Emptied legacy runtime directories left behind after a migration deleted
225
+ // their files. Flag ONLY when the dir exists and contains zero files — a
226
+ // dir that still holds any file is left untouched (its code files are caught
227
+ // by the content scan above instead).
228
+ for (const configDir of configDirs) {
229
+ for (const legacyDirName of LEGACY_RUNTIME_DIR_NAMES) {
230
+ const legacyDir = path.join(configDir, legacyDirName);
231
+ let stat;
232
+ try {
233
+ stat = fsMod.statSync(legacyDir);
234
+ } catch {
235
+ continue; // absent — skip
236
+ }
237
+ if (stat.isDirectory() && collectFilesUnder(legacyDir, fsMod).length === 0) {
238
+ addCandidate(legacyDir, 'empty-legacy-runtime-dir');
239
+ }
240
+ }
241
+ }
242
+
210
243
  // Sort deterministically by path
211
244
  const sorted = [...candidates.entries()]
212
245
  .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
@@ -246,6 +279,16 @@ function applyLegacyCleanup(plan, opts = {}) {
246
279
  const errors = [];
247
280
 
248
281
  for (const item of plan) {
282
+ // Legacy runtime dirs are removed recursively, but ONLY after re-verifying
283
+ // they are still empty at apply time — a defensive guard so a file that
284
+ // appeared between scan and apply is never destroyed.
285
+ const isLegacyDir = item.reason === 'empty-legacy-runtime-dir';
286
+ if (isLegacyDir && collectFilesUnder(item.path, fsMod).length > 0) {
287
+ errors.push({ path: item.path, error: 'legacy runtime dir not empty at apply time; skipped' });
288
+ continue;
289
+ }
290
+ const rmOpts = isLegacyDir ? { recursive: true, force: true } : { force: true };
291
+
249
292
  let lastErr;
250
293
  const maxAttempts = process.platform === 'win32' ? 3 : 1;
251
294
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
@@ -254,7 +297,7 @@ function applyLegacyCleanup(plan, opts = {}) {
254
297
  // Synchronous 100ms delay before retry (win32 EBUSY/EPERM from Defender)
255
298
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100);
256
299
  }
257
- fsMod.rmSync(item.path, { force: true });
300
+ fsMod.rmSync(item.path, rmOpts);
258
301
  lastErr = undefined;
259
302
  break;
260
303
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@therocketcode/gsd-core",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
5
5
  "bin": {
6
6
  "gsd-core": "bin/install.js",