@pareto4/pp-core 1.5.0 → 1.5.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pp-core",
3
3
  "displayName": "PP Core",
4
- "version": "1.5.0",
4
+ "version": "1.5.2",
5
5
  "description": "PP Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
6
6
  "author": {
7
7
  "name": "pareto4",
package/bin/install.js CHANGED
@@ -7714,6 +7714,15 @@ function cleanupOrphanedHooks(settings) {
7714
7714
  'gsd-intel-prune.js', // Removed in v1.9.2
7715
7715
  ];
7716
7716
 
7717
+ // pareto4/pp-core#1: prune the entire predecessor OpenGSD hook namespace.
7718
+ // pp-core ships hooks/pp-*.{js,sh} and deletes the old hooks/gsd-*.{js,sh}
7719
+ // files on install — but the matching settings.json entries were left behind,
7720
+ // dangling (target file removed) and duplicating the freshly-added pp-* hooks.
7721
+ // Any command pointing into hooks/gsd-*.{js,sh,cmd} is therefore stale: pp-core
7722
+ // never registers gsd-* hooks. Match generically rather than enumerating each
7723
+ // basename so future predecessor hooks are covered automatically.
7724
+ const legacyGsdManagedHookRe = /hooks[\\/]gsd-[a-z0-9-]+\.(?:js|sh|cmd)(?=$|["'`\s])/i;
7725
+
7717
7726
  let cleanedHooks = false;
7718
7727
 
7719
7728
  // Check all hook event types (Stop, SessionStart, etc.)
@@ -7724,9 +7733,13 @@ function cleanupOrphanedHooks(settings) {
7724
7733
  // Filter out entries that contain orphaned hooks
7725
7734
  const filtered = hookEntries.filter(entry => {
7726
7735
  if (entry.hooks && Array.isArray(entry.hooks)) {
7727
- // Check if any hook in this entry matches orphaned patterns
7736
+ // Check if any hook in this entry matches orphaned patterns or the
7737
+ // predecessor gsd-* managed-hook namespace.
7728
7738
  const hasOrphaned = entry.hooks.some(h =>
7729
- h.command && orphanedHookPatterns.some(pattern => h.command.includes(pattern))
7739
+ h.command && (
7740
+ orphanedHookPatterns.some(pattern => h.command.includes(pattern)) ||
7741
+ legacyGsdManagedHookRe.test(h.command)
7742
+ )
7730
7743
  );
7731
7744
  if (hasOrphaned) {
7732
7745
  cleanedHooks = true;
@@ -7736,6 +7749,11 @@ function cleanupOrphanedHooks(settings) {
7736
7749
  return true; // Keep this entry
7737
7750
  });
7738
7751
  settings.hooks[eventType] = filtered;
7752
+ // Drop the event key entirely once all its matcher groups are gone, so
7753
+ // no empty hook arrays linger in settings.json.
7754
+ if (settings.hooks[eventType].length === 0) {
7755
+ delete settings.hooks[eventType];
7756
+ }
7739
7757
  }
7740
7758
  }
7741
7759
  }
@@ -7744,16 +7762,21 @@ function cleanupOrphanedHooks(settings) {
7744
7762
  console.log(` ${green}✓${reset} Removed orphaned hook registrations`);
7745
7763
  }
7746
7764
 
7747
- // Fix #330: Update statusLine if it points to old GSD statusline.js path
7748
- // Only match the specific old GSD path pattern (hooks/statusline.js),
7749
- // not third-party statusline scripts that happen to contain 'statusline.js'
7765
+ // Fix #330 + pareto4/pp-core#1: Update statusLine if it points to a stale
7766
+ // managed statusline path — both the pre-rename `hooks/statusline.js` and the
7767
+ // OpenGSD-era `hooks/gsd-statusline.js` (deleted on the pp-core upgrade, which
7768
+ // otherwise leaves the statusline pointing at a missing file). Match only
7769
+ // these specific managed basenames, not third-party scripts that merely
7770
+ // contain 'statusline.js'.
7750
7771
  if (settings.statusLine && settings.statusLine.command &&
7751
- /hooks[\/\\]statusline\.js/.test(settings.statusLine.command)) {
7772
+ /hooks[\/\\](?:gsd-)?statusline\.js/.test(settings.statusLine.command)) {
7773
+ const wasGsd = /hooks[\/\\]gsd-statusline\.js/.test(settings.statusLine.command);
7752
7774
  settings.statusLine.command = settings.statusLine.command.replace(
7753
- /hooks([\/\\])statusline\.js/,
7775
+ /hooks([\/\\])(?:gsd-)?statusline\.js/,
7754
7776
  'hooks$1pp-statusline.js'
7755
7777
  );
7756
- console.log(` ${green}✓${reset} Updated statusline path (hooks/statusline.js → hooks/pp-statusline.js)`);
7778
+ const from = wasGsd ? 'hooks/gsd-statusline.js' : 'hooks/statusline.js';
7779
+ console.log(` ${green}✓${reset} Updated statusline path (${from} → hooks/pp-statusline.js)`);
7757
7780
  }
7758
7781
 
7759
7782
  return settings;
@@ -12167,6 +12190,7 @@ module.exports = {
12167
12190
  stripGsdFromCodexConfig,
12168
12191
  migrateCodexHooksMapFormat,
12169
12192
  stripStaleGsdHookBlocks,
12193
+ cleanupOrphanedHooks,
12170
12194
  hasUserNamespacedAotHooks,
12171
12195
  parseTomlToObject,
12172
12196
  validateCodexConfigSchema,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pp-core",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "PP Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads pp-core's operating context into every Gemini CLI session.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pareto4/pp-core",
3
- "version": "1.5.0",
4
- "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
3
+ "version": "1.5.2",
4
+ "description": "Pareto pp-core — The Pareto Project's AI-assisted engineering framework: meta-prompting, context engineering, and spec-driven development for AI coding agents.",
5
5
  "bin": {
6
6
  "pp-core": "bin/install.js",
7
7
  "pp-tools": "pp-core/bin/pp-tools.cjs",
@@ -31,7 +31,7 @@
31
31
  "codex",
32
32
  "codex-cli"
33
33
  ],
34
- "author": "OpenGSD",
34
+ "author": "The Pareto Project",
35
35
  "license": "MIT",
36
36
  "repository": {
37
37
  "type": "git",
@@ -41,6 +41,16 @@ const ROOT = path.resolve(__dirname, '..');
41
41
  /** Matches any recognised OpenGSD spelling in a line of text. */
42
42
  const OPENGSD_RE = /opengsd|open-gsd/i;
43
43
 
44
+ /**
45
+ * Broader brand pattern for npm-facing manifest metadata (package.json
46
+ * `description` / `author`). Catches the upstream product name ("GSD Core")
47
+ * and the org spelling ("OpenGSD") that leaked into the published 1.5.0
48
+ * description/author. Applied ONLY to those manifest fields — not the code/docs
49
+ * surface — so legitimate `gsd-core` references in carved-out provenance files
50
+ * are unaffected.
51
+ */
52
+ const MANIFEST_BRAND_RE = /opengsd|open-gsd|gsd[\s-]?core/i;
53
+
44
54
  // ── Carve-out allowlists (all paths are absolute) ───────────────────────────
45
55
 
46
56
  /**
@@ -224,6 +234,44 @@ function collectDocsFiles() {
224
234
  return files;
225
235
  }
226
236
 
237
+ // ── Manifest metadata surface ────────────────────────────────────────────────
238
+
239
+ const PACKAGE_JSON = path.join(ROOT, 'package.json');
240
+
241
+ /**
242
+ * Scan package.json's npm-facing branding fields (`description`, `author`) for
243
+ * leftover upstream branding. npm renders these on the public package page, and
244
+ * a published version's metadata is immutable — so a leak here can only be fixed
245
+ * by a new release. Guarding it keeps the class from recurring (the 1.5.0
246
+ * description shipped "GSD Core ..." / author "OpenGSD" past the file-surface
247
+ * sweep, which never read package.json).
248
+ *
249
+ * @returns {Array<{file: string, line: number, text: string}>}
250
+ */
251
+ function scanManifestBranding() {
252
+ const hits = [];
253
+ let pkg;
254
+ try {
255
+ pkg = JSON.parse(fs.readFileSync(PACKAGE_JSON, 'utf8'));
256
+ } catch {
257
+ return hits; // no/unreadable package.json — nothing to scan
258
+ }
259
+
260
+ const fields = [
261
+ ['description', pkg.description],
262
+ // `author` may be a string or an { name, ... } object
263
+ ['author', typeof pkg.author === 'object' && pkg.author ? pkg.author.name : pkg.author],
264
+ ];
265
+
266
+ for (const [field, value] of fields) {
267
+ if (typeof value === 'string' && MANIFEST_BRAND_RE.test(value)) {
268
+ hits.push({ file: 'package.json', line: `${field} field`, text: value });
269
+ }
270
+ }
271
+
272
+ return hits;
273
+ }
274
+
227
275
  // ── Main sweep logic ─────────────────────────────────────────────────────────
228
276
 
229
277
  /**
@@ -247,7 +295,8 @@ function runSweep(opts) {
247
295
 
248
296
  const codeHits = scanFiles(codeFiles);
249
297
  const docsHits = scanFiles(docsFiles);
250
- const hits = [...codeHits, ...docsHits];
298
+ const manifestHits = scanManifestBranding();
299
+ const hits = [...codeHits, ...docsHits, ...manifestHits];
251
300
 
252
301
  return { hits, clean: hits.length === 0 };
253
302
  }
@@ -259,7 +308,7 @@ function cliMain() {
259
308
 
260
309
  if (clean) {
261
310
  process.stdout.write(
262
- '[verify-opengsd-sweep] PASS — live code+docs surface is OpenGSD-free (carve-outs intact).\n'
311
+ '[verify-opengsd-sweep] PASS — live code+docs surface and package.json branding are OpenGSD-free (carve-outs intact).\n'
263
312
  );
264
313
  return 0;
265
314
  }
@@ -281,7 +330,7 @@ function cliMain() {
281
330
 
282
331
  // ── Exports + guard ──────────────────────────────────────────────────────────
283
332
 
284
- module.exports = { runSweep, OPENGSD_RE, isCarvedOut };
333
+ module.exports = { runSweep, OPENGSD_RE, MANIFEST_BRAND_RE, isCarvedOut, scanManifestBranding };
285
334
 
286
335
  if (require.main === module) {
287
336
  runMain(cliMain);