@pareto4/pp-core 1.7.1 → 1.8.1

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 (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/install.js +197 -81
  3. package/commands/pp-build-handoff.md +8 -2
  4. package/commands/pp-discovery-to-build.md +40 -0
  5. package/commands/pp-ns-project.md +3 -1
  6. package/gemini-extension.json +1 -1
  7. package/package.json +2 -1
  8. package/pareto-skills/_shared/create-project-board.sh +195 -0
  9. package/pareto-skills/_shared/pp-claude-md-protocol.md +306 -0
  10. package/pareto-skills/_shared/sync-phase-status.sh +139 -0
  11. package/pareto-skills/pp-brand/SKILL.md +644 -0
  12. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.inline.html +120 -0
  13. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.tsx +239 -0
  14. package/pareto-skills/pp-brand/assets/crew/build.svg +11 -0
  15. package/pareto-skills/pp-brand/assets/crew/deploy.svg +11 -0
  16. package/pareto-skills/pp-brand/assets/crew/discovery.svg +11 -0
  17. package/pareto-skills/pp-brand/assets/crew/plan.svg +11 -0
  18. package/pareto-skills/pp-brand/assets/crew/run.svg +11 -0
  19. package/pareto-skills/pp-brand/assets/crew/validate.svg +11 -0
  20. package/pareto-skills/pp-brand/assets/pareto-brand-preview.html +547 -0
  21. package/pareto-skills/pp-obsidian-notes/SKILL.md +127 -0
  22. package/pareto-skills/pp-obsidian-notes/templates/CLAUDE.md +29 -0
  23. package/pareto-skills/pp-obsidian-notes/templates/client-context.md +116 -0
  24. package/pareto-skills/pp-obsidian-notes/templates/meeting-note.md +66 -0
  25. package/pareto-skills/pp-obsidian-notes/templates/pareto-context.md +102 -0
  26. package/pareto-skills/pp-obsidian-notes/templates/proposal.md +117 -0
  27. package/pareto-skills/pp-project-setup/SKILL.md +1364 -0
  28. package/pp-core/bin/lib/clusters.cjs +4 -0
  29. package/pp-core/bin/lib/intel.cjs +1 -1
  30. package/pp-core/bin/lib/io.cjs +120 -0
  31. package/pp-core/bin/lib/profile-pipeline-command-router.cjs +1 -1
  32. package/pp-core/bin/lib/roadmap-parser.cjs +1 -1
  33. package/pp-core/bin/lib/runtime-artifact-conversion.cjs +2 -2
  34. package/pp-core/bin/lib/surface.cjs +1 -1
  35. package/pp-core/bin/lib/worktree-safety.cjs +2 -2
  36. package/pp-core/bin/pp-tools.cjs +23 -0
  37. package/pp-core/references/ui-brand.md +73 -11
  38. package/pp-core/templates/codebase/structure.md +5 -5
  39. package/pp-core/templates/spec.md +7 -7
  40. package/pp-core/workflows/add-backlog.md +1 -1
  41. package/pp-core/workflows/autonomous.md +4 -4
  42. package/pp-core/workflows/debug.md +1 -1
  43. package/pp-core/workflows/{build-handoff.md → discovery-to-build.md} +6 -3
  44. package/pp-core/workflows/execute-phase.md +9 -1
  45. package/pp-core/workflows/plan-phase.md +14 -12
  46. package/pp-core/workflows/pr-branch.md +5 -4
  47. package/pp-core/workflows/reapply-patches.md +1 -1
  48. package/pp-core/workflows/ship.md +1 -1
  49. package/pp-core/workflows/thread.md +1 -1
  50. package/pp-core/workflows/verify-work.md +6 -5
  51. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -0
package/bin/install.js CHANGED
@@ -216,7 +216,7 @@ const GSD_CURSOR_POST_TOOL_HOOK_SCRIPT = 'pp-cursor-post-tool.js';
216
216
  // Marker comment embedded in managed hook entries so GSD can find+remove them.
217
217
  const GSD_CURSOR_HOOK_MARKER = 'gsd-managed';
218
218
 
219
- // GSD-managed files under hooks/lib/ (helpers required by gsd-*.sh hooks).
219
+ // pp-core-managed files under hooks/lib/ (helpers required by gsd-*.sh hooks).
220
220
  // git-cmd.js does not start with "gsd-" (shared classifier for #3129), pp-graphify-rebuild.sh does.
221
221
  const GSD_HOOK_LIB_FILES = ['git-cmd.js', 'pp-graphify-rebuild.sh'];
222
222
 
@@ -297,7 +297,7 @@ function _getGsdEffortCatalog() {
297
297
  } catch (_err) {
298
298
  // Fail loudly — a missing manifest is a broken install, not a soft degradation.
299
299
  throw new Error(
300
- `gsd install: cannot load config-defaults.manifest.json at ${manifestPath}: ${_err.message}`
300
+ `pp-core install: cannot load config-defaults.manifest.json at ${manifestPath}: ${_err.message}`
301
301
  );
302
302
  }
303
303
 
@@ -601,7 +601,7 @@ if (hasUninstall) {
601
601
 
602
602
  // Show help if requested
603
603
  if (hasHelp) {
604
- console.log(` ${yellow}Usage:${reset} npx ${pkg.name} [options]\n\n ${yellow}Options:${reset}\n ${cyan}-g, --global${reset} Install globally (to config directory)\n ${cyan}-l, --local${reset} Install locally (to current directory)\n ${cyan}--claude${reset} Install for Claude Code only\n ${cyan}--opencode${reset} Install for OpenCode only\n ${cyan}--gemini${reset} Install for Gemini only\n ${cyan}--kilo${reset} Install for Kilo only\n ${cyan}--codex${reset} Install for Codex only\n ${cyan}--kimi${reset} Install for Kimi CLI only\n ${cyan}--copilot${reset} Install for Copilot only\n ${cyan}--antigravity${reset} Install for Antigravity only\n ${cyan}--cursor${reset} Install for Cursor only\n ${cyan}--windsurf${reset} Install for Windsurf only\n ${cyan}--augment${reset} Install for Augment only\n ${cyan}--trae${reset} Install for Trae only\n ${cyan}--qwen${reset} Install for Qwen Code only\n ${cyan}--hermes${reset} Install for Hermes Agent only\n ${cyan}--cline${reset} Install for Cline only\n ${cyan}--codebuddy${reset} Install for CodeBuddy only\n ${cyan}--all${reset} Install for all runtimes\n ${cyan}-u, --uninstall${reset} Uninstall pp-core (remove all pp-core files)\n ${cyan}-c, --config-dir <path>${reset} Specify custom config directory\n ${cyan}-h, --help${reset} Show this help message\n ${cyan}--force-statusline${reset} Replace existing statusline config\n ${cyan}--portable-hooks${reset} Emit \$HOME-relative hook paths in settings.json\n (for WSL/Docker bind-mount setups; also GSD_PORTABLE_HOOKS=1)\n ${cyan}--profile=<name>${reset} Install a named skill profile. Profiles:\n core — ${PROFILES.core.length} main-loop skills incl. phase (~130 desc tokens)\n standard — ${PROFILES.standard.length} skills incl. phase, review, config (~700)\n full — all skills (default)\n Composable: --profile=core,audit installs union of closures.\n Profile is persisted and respected by \`gsd update\`.\n ${cyan}--minimal${reset} Alias for --profile=core (back-compat).\n Cuts cold-start overhead from ~12k tokens to ~700.\n Alias: --core-only.\n\n ${yellow}Examples:${reset}\n ${dim}# Interactive install (prompts for runtime and location)${reset}\n npx ${pkg.name}\n\n ${dim}# Install for Claude Code globally${reset}\n npx ${pkg.name} --claude --global\n\n ${dim}# Install for Gemini globally${reset}\n npx ${pkg.name} --gemini --global\n\n ${dim}# Install for Kilo globally${reset}\n npx ${pkg.name} --kilo --global\n\n ${dim}# Install for Codex globally${reset}\n npx ${pkg.name} --codex --global\n\n ${dim}# Install for Kimi CLI globally${reset}\n npx ${pkg.name} --kimi --global\n\n ${dim}# Install for Kimi CLI under ~/.kimi-code${reset}\n npx ${pkg.name} --kimi --global --config-dir ~/.kimi-code\n\n ${dim}# Install for Copilot globally${reset}\n npx ${pkg.name} --copilot --global\n\n ${dim}# Install for Copilot locally${reset}\n npx ${pkg.name} --copilot --local\n\n ${dim}# Install for Antigravity globally${reset}\n npx ${pkg.name} --antigravity --global\n\n ${dim}# Install for Antigravity locally${reset}\n npx ${pkg.name} --antigravity --local\n\n ${dim}# Install for Cursor globally${reset}\n npx ${pkg.name} --cursor --global\n\n ${dim}# Install for Cursor locally${reset}\n npx ${pkg.name} --cursor --local\n\n ${dim}# Install for Windsurf globally${reset}\n npx ${pkg.name} --windsurf --global\n\n ${dim}# Install for Windsurf locally${reset}\n npx ${pkg.name} --windsurf --local\n\n ${dim}# Install for Augment globally${reset}\n npx ${pkg.name} --augment --global\n\n ${dim}# Install for Augment locally${reset}\n npx ${pkg.name} --augment --local\n\n ${dim}# Install for Trae globally${reset}\n npx ${pkg.name} --trae --global\n\n ${dim}# Install for Trae locally${reset}\n npx ${pkg.name} --trae --local\n\n ${dim}# Install for Hermes Agent globally${reset}\n npx ${pkg.name} --hermes --global\n\n ${dim}# Install for Hermes Agent locally${reset}\n npx ${pkg.name} --hermes --local\n\n ${dim}# Install for Cline globally${reset}\n npx ${pkg.name} --cline --global\n\n ${dim}# Install for Cline locally${reset}\n npx ${pkg.name} --cline --local\n\n ${dim}# Install for CodeBuddy globally${reset}\n npx ${pkg.name} --codebuddy --global\n\n ${dim}# Install for CodeBuddy locally${reset}\n npx ${pkg.name} --codebuddy --local\n\n ${dim}# Install for all runtimes globally${reset}\n npx ${pkg.name} --all --global\n\n ${dim}# Install to custom config directory${reset}\n npx ${pkg.name} --kilo --global --config-dir ~/.kilo-work\n\n ${dim}# Install to current project only${reset}\n npx ${pkg.name} --claude --local\n\n ${dim}# Uninstall pp-core from Cursor globally${reset}\n npx ${pkg.name} --cursor --global --uninstall\n\n ${yellow}Notes:${reset}\n The --config-dir option is useful when you have multiple configurations.\n It takes priority over CLAUDE_CONFIG_DIR / OPENCODE_CONFIG_DIR / GEMINI_CONFIG_DIR / KILO_CONFIG_DIR / CODEX_HOME / KIMI_CONFIG_DIR / COPILOT_CONFIG_DIR / COPILOT_HOME / ANTIGRAVITY_CONFIG_DIR / CURSOR_CONFIG_DIR / WINDSURF_CONFIG_DIR / AUGMENT_CONFIG_DIR / TRAE_CONFIG_DIR / QWEN_CONFIG_DIR / HERMES_HOME / CLINE_CONFIG_DIR / CODEBUDDY_CONFIG_DIR environment variables.\n Kimi CLI defaults to the first existing generic skills root: ${cyan}~/.config/agents/skills${reset}, then ${cyan}~/.agents/skills${reset}; if neither exists, pp-core creates ${cyan}~/.config/agents${reset}.\n Use ${cyan}--config-dir ~/.kimi-code${reset} or ${cyan}KIMI_CONFIG_DIR=~/.kimi-code${reset} for brand-specific Kimi installs.\n`);
604
+ console.log(` ${yellow}Usage:${reset} npx ${pkg.name} [options]\n\n ${yellow}Options:${reset}\n ${cyan}-g, --global${reset} Install globally (to config directory)\n ${cyan}-l, --local${reset} Install locally (to current directory)\n ${cyan}--claude${reset} Install for Claude Code only\n ${cyan}--opencode${reset} Install for OpenCode only\n ${cyan}--gemini${reset} Install for Gemini only\n ${cyan}--kilo${reset} Install for Kilo only\n ${cyan}--codex${reset} Install for Codex only\n ${cyan}--kimi${reset} Install for Kimi CLI only\n ${cyan}--copilot${reset} Install for Copilot only\n ${cyan}--antigravity${reset} Install for Antigravity only\n ${cyan}--cursor${reset} Install for Cursor only\n ${cyan}--windsurf${reset} Install for Windsurf only\n ${cyan}--augment${reset} Install for Augment only\n ${cyan}--trae${reset} Install for Trae only\n ${cyan}--qwen${reset} Install for Qwen Code only\n ${cyan}--hermes${reset} Install for Hermes Agent only\n ${cyan}--cline${reset} Install for Cline only\n ${cyan}--codebuddy${reset} Install for CodeBuddy only\n ${cyan}--all${reset} Install for all runtimes\n ${cyan}-u, --uninstall${reset} Uninstall pp-core (remove all pp-core files)\n ${cyan}-c, --config-dir <path>${reset} Specify custom config directory\n ${cyan}-h, --help${reset} Show this help message\n ${cyan}--force-statusline${reset} Replace existing statusline config\n ${cyan}--portable-hooks${reset} Emit \$HOME-relative hook paths in settings.json\n (for WSL/Docker bind-mount setups; also GSD_PORTABLE_HOOKS=1)\n ${cyan}--profile=<name>${reset} Install a named skill profile. Profiles:\n core — ${PROFILES.core.length} main-loop skills incl. phase (~130 desc tokens)\n standard — ${PROFILES.standard.length} skills incl. phase, review, config (~700)\n full — all skills (default)\n Composable: --profile=core,audit installs union of closures.\n Profile is persisted and respected by \`pp update\`.\n ${cyan}--minimal${reset} Alias for --profile=core (back-compat).\n Cuts cold-start overhead from ~12k tokens to ~700.\n Alias: --core-only.\n\n ${yellow}Examples:${reset}\n ${dim}# Interactive install (prompts for runtime and location)${reset}\n npx ${pkg.name}\n\n ${dim}# Install for Claude Code globally${reset}\n npx ${pkg.name} --claude --global\n\n ${dim}# Install for Gemini globally${reset}\n npx ${pkg.name} --gemini --global\n\n ${dim}# Install for Kilo globally${reset}\n npx ${pkg.name} --kilo --global\n\n ${dim}# Install for Codex globally${reset}\n npx ${pkg.name} --codex --global\n\n ${dim}# Install for Kimi CLI globally${reset}\n npx ${pkg.name} --kimi --global\n\n ${dim}# Install for Kimi CLI under ~/.kimi-code${reset}\n npx ${pkg.name} --kimi --global --config-dir ~/.kimi-code\n\n ${dim}# Install for Copilot globally${reset}\n npx ${pkg.name} --copilot --global\n\n ${dim}# Install for Copilot locally${reset}\n npx ${pkg.name} --copilot --local\n\n ${dim}# Install for Antigravity globally${reset}\n npx ${pkg.name} --antigravity --global\n\n ${dim}# Install for Antigravity locally${reset}\n npx ${pkg.name} --antigravity --local\n\n ${dim}# Install for Cursor globally${reset}\n npx ${pkg.name} --cursor --global\n\n ${dim}# Install for Cursor locally${reset}\n npx ${pkg.name} --cursor --local\n\n ${dim}# Install for Windsurf globally${reset}\n npx ${pkg.name} --windsurf --global\n\n ${dim}# Install for Windsurf locally${reset}\n npx ${pkg.name} --windsurf --local\n\n ${dim}# Install for Augment globally${reset}\n npx ${pkg.name} --augment --global\n\n ${dim}# Install for Augment locally${reset}\n npx ${pkg.name} --augment --local\n\n ${dim}# Install for Trae globally${reset}\n npx ${pkg.name} --trae --global\n\n ${dim}# Install for Trae locally${reset}\n npx ${pkg.name} --trae --local\n\n ${dim}# Install for Hermes Agent globally${reset}\n npx ${pkg.name} --hermes --global\n\n ${dim}# Install for Hermes Agent locally${reset}\n npx ${pkg.name} --hermes --local\n\n ${dim}# Install for Cline globally${reset}\n npx ${pkg.name} --cline --global\n\n ${dim}# Install for Cline locally${reset}\n npx ${pkg.name} --cline --local\n\n ${dim}# Install for CodeBuddy globally${reset}\n npx ${pkg.name} --codebuddy --global\n\n ${dim}# Install for CodeBuddy locally${reset}\n npx ${pkg.name} --codebuddy --local\n\n ${dim}# Install for all runtimes globally${reset}\n npx ${pkg.name} --all --global\n\n ${dim}# Install to custom config directory${reset}\n npx ${pkg.name} --kilo --global --config-dir ~/.kilo-work\n\n ${dim}# Install to current project only${reset}\n npx ${pkg.name} --claude --local\n\n ${dim}# Uninstall pp-core from Cursor globally${reset}\n npx ${pkg.name} --cursor --global --uninstall\n\n ${yellow}Notes:${reset}\n The --config-dir option is useful when you have multiple configurations.\n It takes priority over CLAUDE_CONFIG_DIR / OPENCODE_CONFIG_DIR / GEMINI_CONFIG_DIR / KILO_CONFIG_DIR / CODEX_HOME / KIMI_CONFIG_DIR / COPILOT_CONFIG_DIR / COPILOT_HOME / ANTIGRAVITY_CONFIG_DIR / CURSOR_CONFIG_DIR / WINDSURF_CONFIG_DIR / AUGMENT_CONFIG_DIR / TRAE_CONFIG_DIR / QWEN_CONFIG_DIR / HERMES_HOME / CLINE_CONFIG_DIR / CODEBUDDY_CONFIG_DIR environment variables.\n Kimi CLI defaults to the first existing generic skills root: ${cyan}~/.config/agents/skills${reset}, then ${cyan}~/.agents/skills${reset}; if neither exists, pp-core creates ${cyan}~/.config/agents${reset}.\n Use ${cyan}--config-dir ~/.kimi-code${reset} or ${cyan}KIMI_CONFIG_DIR=~/.kimi-code${reset} for brand-specific Kimi installs.\n`);
605
605
  process.exit(0);
606
606
  }
607
607
 
@@ -640,7 +640,7 @@ const resolveBashRunner = hooksSurface.resolveBashRunner;
640
640
  // referencesHook: pure predicate over hook entry objects, shared between
641
641
  // install() and finishInstall() (ADR-857 phase 5f-1b).
642
642
  const referencesHook = hooksSurface.referencesHook;
643
- // applySettingsJsonHooks: mutates settings.hooks.* in place with all GSD-managed
643
+ // applySettingsJsonHooks: mutates settings.hooks.* in place with all pp-core-managed
644
644
  // hook registrations for settings.json-surface runtimes (ADR-857 phase 5f-1b).
645
645
  const applySettingsJsonHooks = hooksSurface.applySettingsJsonHooks;
646
646
 
@@ -649,7 +649,7 @@ function rewriteLegacyManagedNodeHookCommands(settings, absoluteRunner, opts) {
649
649
  }
650
650
 
651
651
  /**
652
- * Build the GSD-managed Codex SessionStart hook block for config.toml.
652
+ * Build the pp-core-managed Codex SessionStart hook block for config.toml.
653
653
  *
654
654
  * Issue #3017: the previous shape inlined `command = "node ${path}"` which
655
655
  * fails under GUI/minimal-PATH runtimes where bare `node` doesn't resolve
@@ -715,7 +715,7 @@ function reconcileCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
715
715
  }
716
716
 
717
717
  /**
718
- * Reconcile the GSD-managed SessionStart hook entry in hooks.json.
718
+ * Reconcile the pp-core-managed SessionStart hook entry in hooks.json.
719
719
  * Delegates to the generic reconcileCodexHooksJsonEvent helper.
720
720
  *
721
721
  * @param {string} targetDir
@@ -818,7 +818,7 @@ function ensureCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
818
818
  }
819
819
 
820
820
  /**
821
- * Remove a GSD-managed event entry from hooks.json. Called during uninstall.
821
+ * Remove a pp-core-managed event entry from hooks.json. Called during uninstall.
822
822
  *
823
823
  * @param {string} targetDir
824
824
  * @param {string} eventName
@@ -1483,7 +1483,7 @@ const claudeToGeminiTools = {
1483
1483
  TodoWrite: 'write_todos',
1484
1484
  };
1485
1485
 
1486
- // Tool name mapping from Claude/GSD agents to Kimi CLI module paths.
1486
+ // Tool name mapping from Claude/pp-core agents to Kimi CLI module paths.
1487
1487
  // Kimi custom agent YAML requires fully-qualified module paths.
1488
1488
  const claudeToKimiTools = {
1489
1489
  Read: 'kimi_cli.tools.file:ReadFile',
@@ -3025,7 +3025,7 @@ Typed mapping (agent_type-capable schema only):
3025
3025
  to \`spawn_agent\` when the runtime/tool supports it. Omit missing, empty,
3026
3026
  inherited, or unsupported values; do not invent one-off effort literals in
3027
3027
  workflow prose.
3028
- - \`fork_context: false\` by default — GSD agents load their own context via \`<files_to_read>\` blocks
3028
+ - \`fork_context: false\` by default — pp-core agents load their own context via \`<files_to_read>\` blocks
3029
3029
  - \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct Codex mapping.
3030
3030
  Codex \`spawn_agent\` does not create or bind a git worktree automatically.
3031
3031
  Workflows that require this isolation must fail closed or use an explicit
@@ -3035,7 +3035,7 @@ Generic-agent workaround (multi_agent_v1 schema — NO agent_type field):
3035
3035
  When only the generic \`multi_agent_v1\` schema is available, typed GSD agent dispatch
3036
3036
  (\`pp-planner\`, \`pp-executor\`, etc.) is NOT possible. This is a known Codex limitation
3037
3037
  (openai/codex#15250). **This workaround is NOT equivalent to typed pp-planner/pp-executor
3038
- execution** — GSD agents carry project-aware prompts, audit logging, and workflow context
3038
+ execution** — pp-core agents carry project-aware prompts, audit logging, and workflow context
3039
3039
  that a generic subagent lacks. Use the following fallback:
3040
3040
  1. Resolve your active Codex config root — the directory that contains your \`config.toml\`.
3041
3041
  This directory is determined in priority order: \`$CODEX_HOME\` (if set), the path given
@@ -3198,11 +3198,11 @@ function generateCodexAgentToml(agentName, agentContent, modelOverrides = null,
3198
3198
  }
3199
3199
 
3200
3200
  /**
3201
- * Remove stale agents/openai.yaml sidecar files from GSD-managed Codex skill dirs.
3201
+ * Remove stale agents/openai.yaml sidecar files from pp-core-managed Codex skill dirs.
3202
3202
  *
3203
3203
  * Prior to #1326, GSD's Codex install path wrote an agents/openai.yaml file
3204
3204
  * alongside each gsd-* SKILL.md. Recent Codex builds index BOTH SKILL.md and
3205
- * the sidecar, causing each GSD skill to appear twice in autocomplete. This
3205
+ * the sidecar, causing each pp-core skill to appear twice in autocomplete. This
3206
3206
  * function removes those stale sidecars and — if the agents/ subdirectory is
3207
3207
  * now empty — prunes it too.
3208
3208
  *
@@ -4066,7 +4066,7 @@ function stripLeakedGsdCodexSections(content) {
4066
4066
  }
4067
4067
 
4068
4068
  /**
4069
- * Strip GSD-managed legacy Codex hook blocks from a config.toml string
4069
+ * Strip pp-core-managed legacy Codex hook blocks from a config.toml string
4070
4070
  * using the TOML AST already used elsewhere in this file
4071
4071
  * (`getTomlTableSections` + `removeContentRanges`). The earlier regex-based
4072
4072
  * implementation required a precise key order, exact single-space padding
@@ -4084,7 +4084,7 @@ function stripLeakedGsdCodexSections(content) {
4084
4084
  * removal range backward through any single preceding comment line.
4085
4085
  *
4086
4086
  * Pure function, exported for test coverage. Returns the input unchanged
4087
- * if no GSD-managed hook section is present.
4087
+ * if no pp-core-managed hook section is present.
4088
4088
  */
4089
4089
  function stripStaleGsdHookBlocks(configContent) {
4090
4090
  const sections = getTomlTableSections(configContent);
@@ -4096,7 +4096,7 @@ function stripStaleGsdHookBlocks(configContent) {
4096
4096
  return configContent;
4097
4097
  }
4098
4098
 
4099
- // A section is GSD-managed if any structural `command` key inside its
4099
+ // A section is pp-core-managed if any structural `command` key inside its
4100
4100
  // body parses to a string whose basename matches `gsd-(check-update|
4101
4101
  // update-check).js`. The TOML line parser already classified each line's
4102
4102
  // `keySegments`, so we never inspect raw text — this handles arbitrary
@@ -4431,7 +4431,7 @@ function migrateCodexHooksMapFormat(content) {
4431
4431
  /**
4432
4432
  * Detect whether the user already uses the namespaced AoT hooks form
4433
4433
  * (`[[hooks.<EVENT>]]`) for the given event in the config. When true,
4434
- * the GSD-managed hook block must be emitted in the same shape so it
4434
+ * the pp-core-managed hook block must be emitted in the same shape so it
4435
4435
  * coexists cleanly — mixing `[[hooks]]` (flat) with `[[hooks.SessionStart]]`
4436
4436
  * (namespaced) in the same file confuses round-trip writers and can
4437
4437
  * produce a config that Codex rejects (#2760, defect 3).
@@ -5145,7 +5145,7 @@ function mergeCodexConfig(configPath, gsdBlock) {
5145
5145
  if (markerIndex !== -1) {
5146
5146
  let before = existing.substring(0, markerIndex).trimEnd();
5147
5147
  if (before) {
5148
- // Strip any GSD-managed sections that leaked above the marker from previous installs
5148
+ // Strip any pp-core-managed sections that leaked above the marker from previous installs
5149
5149
  before = stripLeakedGsdCodexSections(before).trimEnd();
5150
5150
 
5151
5151
  atomicWriteFileSync(configPath, before + eol + eol + normalizedGsdBlock + eol);
@@ -5420,7 +5420,7 @@ function mergeCopilotInstructions(filePath, gsdContent) {
5420
5420
 
5421
5421
  /**
5422
5422
  * Strip GSD section from copilot-instructions.md content.
5423
- * Returns cleaned content, or null if file should be deleted (was GSD-only).
5423
+ * Returns cleaned content, or null if file should be deleted (was pp-core-only).
5424
5424
  * @param {string} content - File content
5425
5425
  * @returns {string|null} - Cleaned content or null if empty
5426
5426
  */
@@ -5492,7 +5492,7 @@ function mergeGsdAgentsMd(filePath, gsdContent) {
5492
5492
 
5493
5493
  /**
5494
5494
  * Strip the GSD block from AGENTS.md content. Returns null if the file became
5495
- * empty (was GSD-only), the unchanged content if no markers were found, or the
5495
+ * empty (was pp-core-only), the unchanged content if no markers were found, or the
5496
5496
  * cleaned content otherwise.
5497
5497
  */
5498
5498
  function stripGsdFromAgentsMd(content) {
@@ -5551,7 +5551,7 @@ function buildCursorHookEntry(scriptPath) {
5551
5551
  }
5552
5552
 
5553
5553
  /**
5554
- * Return true if a Cursor hook entry is GSD-managed.
5554
+ * Return true if a Cursor hook entry is pp-core-managed.
5555
5555
  * Detection: presence of the GSD_CURSOR_HOOK_MARKER sentinel field.
5556
5556
  *
5557
5557
  * @param {object} entry - A hooks array element from hooks.json
@@ -5562,7 +5562,7 @@ function isManagedCursorHookEntry(entry) {
5562
5562
  }
5563
5563
 
5564
5564
  /**
5565
- * Reconcile the GSD-managed entries in a Cursor hooks.json file.
5565
+ * Reconcile the pp-core-managed entries in a Cursor hooks.json file.
5566
5566
  *
5567
5567
  * Supports both known hooks.json shapes:
5568
5568
  * 1) { "version": 1, "hooks": { "sessionStart": [...], "postToolUse": [...] } }
@@ -5583,10 +5583,10 @@ function reconcileCursorHooksJson(hooksJsonPath, managedEntries) {
5583
5583
  }
5584
5584
 
5585
5585
  /**
5586
- * #777 — Write GSD-managed Cursor lifecycle hooks into <targetDir>/hooks.json.
5586
+ * #777 — Write pp-core-managed Cursor lifecycle hooks into <targetDir>/hooks.json.
5587
5587
  *
5588
5588
  * Both managed hook scripts (pp-cursor-session-start.js, pp-cursor-post-tool.js)
5589
- * are copied from the GSD hooks/ source to <targetDir>/hooks/ first, so the
5589
+ * are copied from the pp-core hooks/ source to <targetDir>/hooks/ first, so the
5590
5590
  * hooks.json entries never reference a script that wasn't installed.
5591
5591
  *
5592
5592
  * @param {string} targetDir - The Cursor config dir (global: ~/.cursor; local: .cursor)
@@ -5599,7 +5599,7 @@ function writeCursorHooksJson(targetDir, src, opts) {
5599
5599
  }
5600
5600
 
5601
5601
  /**
5602
- * Remove all GSD-managed Cursor lifecycle hook entries from hooks.json.
5602
+ * Remove all pp-core-managed Cursor lifecycle hook entries from hooks.json.
5603
5603
  * User-owned entries are preserved. If the file becomes empty, it is removed.
5604
5604
  *
5605
5605
  * @param {string} targetDir - The Cursor config dir
@@ -5610,7 +5610,7 @@ function removeCursorHooksJson(targetDir) {
5610
5610
  }
5611
5611
 
5612
5612
  /**
5613
- * #786 — Build the GSD-managed GitHub Copilot lifecycle hook config object.
5613
+ * #786 — Build the pp-core-managed GitHub Copilot lifecycle hook config object.
5614
5614
  *
5615
5615
  * Returns the verbatim JSON shape Copilot CLI expects:
5616
5616
  * { version: 1, hooks: { sessionStart: [ <hook entry> ] } }
@@ -5628,7 +5628,7 @@ function buildCopilotHookConfig() {
5628
5628
  }
5629
5629
 
5630
5630
  /**
5631
- * #786 — Write the GSD-managed Copilot lifecycle hook config under the runtime
5631
+ * #786 — Write the pp-core-managed Copilot lifecycle hook config under the runtime
5632
5632
  * config dir (`<targetDir>/hooks/gsd-session.json`). For local installs
5633
5633
  * targetDir is `.github` (→ `.github/hooks/`); for global installs it is
5634
5634
  * `~/.copilot` (→ `~/.copilot/hooks/`) — both are valid Copilot hook locations.
@@ -5922,7 +5922,7 @@ function convertClaudeToGeminiAgent(content) {
5922
5922
  // Escape ${VAR} patterns in agent body for Gemini CLI compatibility.
5923
5923
  // Gemini's templateString() treats all ${word} patterns as template variables
5924
5924
  // and throws "Template validation failed: Missing required input parameters"
5925
- // when they can't be resolved. GSD agents use ${PHASE}, ${PLAN}, etc. as
5925
+ // when they can't be resolved. pp-core agents use ${PHASE}, ${PLAN}, etc. as
5926
5926
  // shell variables in bash code blocks — convert to $VAR (no braces) which
5927
5927
  // is equivalent bash and invisible to Gemini's /\$\{(\w+)\}/g regex.
5928
5928
  const escapedBody = body.replace(/\$\{(\w+)\}/g, '$$$1');
@@ -6585,7 +6585,7 @@ function writeHermesCategoryDescription(categoryDir) {
6585
6585
  * /gsd-profile-user) and must be preserved across reinstalls. Critically, they
6586
6586
  * MUST be excluded from gsd-file-manifest.json — otherwise saveLocalPatches()
6587
6587
  * will compare a refreshed file against a stale manifest hash and emit a
6588
- * spurious "locally modified GSD file" warning (bug #2771).
6588
+ * spurious "locally modified pp-core file" warning (bug #2771).
6589
6589
  *
6590
6590
  * Invariant: a file is either distribution (manifest-tracked, diff'd against
6591
6591
  * manifest) or user artifact (preserved across installs, never diff'd). Never
@@ -7251,7 +7251,7 @@ function _restoreDir(dir, snapshot) {
7251
7251
  *
7252
7252
  * The removal set is derived from the ACTUAL installed skill dirs (every
7253
7253
  * entry starting with 'gsd-' that is a directory), so it covers ALL shipped
7254
- * GSD skills — including 'dev-preferences' and future additions — without
7254
+ * pp-core skills — including 'dev-preferences' and future additions — without
7255
7255
  * relying on readGsdCommandNames() which only enumerates the commands source
7256
7256
  * tree and can miss skills that ship outside that directory.
7257
7257
  *
@@ -7387,6 +7387,120 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile) {
7387
7387
  const nestedGsdDirForCleanup = path.join(configDir, 'skills', 'gsd');
7388
7388
  _removeHermesBareStemDirs(nestedGsdDirForCleanup);
7389
7389
  }
7390
+
7391
+ // Verbatim Pareto skill payload — MUST be the LAST step (post-prune ordering
7392
+ // is load-bearing, Pitfall 1). The skills-kind loop above runs _removeGsdEntries,
7393
+ // which unconditionally deletes EVERY pp-* skill dir; running the verbatim copy
7394
+ // here (delete-then-recopy) makes the payload self-healing across repeated
7395
+ // `npx` installs. Copies are byte-for-byte with NO content-rewrite pass (D-03).
7396
+ installVerbatimSkills(runtime, configDir, scope);
7397
+ }
7398
+
7399
+ /**
7400
+ * Locate the bundled `pareto-skills/` source directory.
7401
+ *
7402
+ * Walks up from `__dirname` (up to 6 ancestors) looking for the sentinel
7403
+ * `pareto-skills/pp-brand/SKILL.md`, mirroring the source-root walk-up the
7404
+ * installer already uses to anchor `commands/`. Returns the absolute path to
7405
+ * the `pareto-skills/` directory. Throws a clear error if it cannot be found.
7406
+ *
7407
+ * @returns {string} absolute path to the bundled `pareto-skills/` directory
7408
+ */
7409
+ function findParetoSkillsSrc() {
7410
+ let dir = __dirname;
7411
+ for (let i = 0; i < 6; i += 1) {
7412
+ const candidate = path.join(dir, 'pareto-skills');
7413
+ if (fs.existsSync(path.join(candidate, 'pp-brand', 'SKILL.md'))) return candidate;
7414
+ const parent = path.dirname(dir);
7415
+ if (parent === dir) break;
7416
+ dir = parent;
7417
+ }
7418
+ throw new Error(`findParetoSkillsSrc: could not locate pareto-skills/ from ${__dirname}`);
7419
+ }
7420
+
7421
+ /**
7422
+ * Place the verbatim Pareto skill payload into a runtime's resolved skills dir.
7423
+ *
7424
+ * This is the "second channel" for shipping skills: unlike command-derived
7425
+ * skills (generated from commands/pp-*.md via the converter), these three
7426
+ * `pp-*` skill dirs — plus a peer `_shared/` — are copied byte-for-byte with
7427
+ * NO content-rewrite pass (D-03/D-07). That keeps them out of docs/COMMANDS.md
7428
+ * and prevents the rewrite walker from corrupting templates or the protocol
7429
+ * file (Pitfall 3). The payload is binary-safe (Crew assets), so we use a plain
7430
+ * recursive fs.cpSync — never applyRuntimeContentRewritesInPlace,
7431
+ * stageSkillsForRuntimeAsSkills, or the skillsKind converter.
7432
+ *
7433
+ * The destination is resolved from the artifact layout's skills-kind
7434
+ * destSubpath (never a hardcoded `skills/`), so Hermes' nested `skills/gsd/`
7435
+ * base is honoured automatically. Runtimes with no skills kind (gemini has only
7436
+ * a commands kind; grok has no skills-layout descriptor) are skipped gracefully
7437
+ * with an early `return 0` — never a throw (Pitfall 5).
7438
+ *
7439
+ * The skill names are a FIXED, package-owned allowlist — never interpolated
7440
+ * input (V5 / T-16-03). No manifest entry is added, so `/pp-surface` pruning
7441
+ * leaves these non-manifest pp-* dirs untouched (Pitfall 2). `_shared/*.sh`
7442
+ * regain their exec bit after copy, because a content-level cpSync does not
7443
+ * reliably preserve the exec bit cross-platform.
7444
+ *
7445
+ * @param {string} runtime - target runtime id
7446
+ * @param {string} configDir - resolved runtime config directory
7447
+ * @param {string} scope - 'local' | 'global'
7448
+ * @returns {number} number of skill dirs placed (0 if the runtime has no skills kind)
7449
+ */
7450
+ function installVerbatimSkills(runtime, configDir, scope) {
7451
+ // Resolve the runtime's artifact layout. Two graceful-skip cases (Pitfall 5,
7452
+ // no throw): gemini's layout has only a commands kind (skillsKindEntry
7453
+ // undefined below); grok is not in the layout registry at all, so
7454
+ // resolveRuntimeArtifactLayout throws 'Unknown runtime' — treat that as
7455
+ // "no skills surface" and skip. In the production call path
7456
+ // installRuntimeArtifacts has already resolved the layout, but this function
7457
+ // is exported and called standalone by test harnesses (Plan 16-03), so the
7458
+ // guard lives here too.
7459
+ let layout;
7460
+ try {
7461
+ layout = resolveRuntimeArtifactLayout(runtime, configDir, scope);
7462
+ } catch {
7463
+ return 0;
7464
+ }
7465
+ const skillsKindEntry = layout.kinds.find((k) => k.kind === 'skills');
7466
+ // gemini (commands-only): no skills surface — skip, don't throw.
7467
+ if (!skillsKindEntry) return 0;
7468
+
7469
+ const src = findParetoSkillsSrc();
7470
+ // destSubpath already encodes Hermes' nested `skills/gsd` — never hardcode `skills/`.
7471
+ const skillsBase = path.join(configDir, skillsKindEntry.destSubpath);
7472
+ fs.mkdirSync(skillsBase, { recursive: true });
7473
+
7474
+ // FIXED, package-owned allowlist — never interpolated input (V5 / T-16-03).
7475
+ const BUNDLED = ['pp-brand', 'pp-project-setup', 'pp-obsidian-notes'];
7476
+ let placed = 0;
7477
+ for (const name of BUNDLED) {
7478
+ const skillDest = path.join(skillsBase, name);
7479
+ // Plain recursive, binary-safe copy — NO content-rewrite pass (D-03/Pitfall 3).
7480
+ fs.cpSync(path.join(src, name), skillDest, { recursive: true });
7481
+ if (verifyInstalled(skillDest, `skill ${name}`)) {
7482
+ placed += 1;
7483
+ }
7484
+ }
7485
+
7486
+ // Copy _shared/ as a PEER of the skill dirs so `../_shared/` resolves from any
7487
+ // skill body (D-04). Verbatim copy, no rewrite pass.
7488
+ const sharedDest = path.join(skillsBase, '_shared');
7489
+ fs.cpSync(path.join(src, '_shared'), sharedDest, { recursive: true });
7490
+ verifyInstalled(sharedDest, 'skill _shared');
7491
+
7492
+ // Restore the exec bit on bundled *.sh — cpSync content copy does not reliably
7493
+ // preserve it cross-platform (PATTERNS "No Analog Found").
7494
+ try {
7495
+ for (const entry of fs.readdirSync(sharedDest)) {
7496
+ if (entry.endsWith('.sh')) {
7497
+ fs.chmodSync(path.join(sharedDest, entry), 0o755);
7498
+ }
7499
+ }
7500
+ } catch { /* best-effort: non-fatal if _shared has no scripts */ }
7501
+
7502
+ console.log(` ${green}✓${reset} Placed ${placed} verbatim Pareto skill(s) + _shared into ${skillsKindEntry.destSubpath}`);
7503
+ return placed;
7390
7504
  }
7391
7505
 
7392
7506
  /**
@@ -7496,7 +7610,7 @@ function uninstallRuntimeArtifacts(runtime, configDir, scope) {
7496
7610
  }
7497
7611
 
7498
7612
  // Hermes: after removing gsd-* skill dirs from skills/gsd/, also remove
7499
- // the GSD-managed DESCRIPTION.md and then the category dir itself if it
7613
+ // the pp-core-managed DESCRIPTION.md and then the category dir itself if it
7500
7614
  // contains no user content (#947). _removeGsdEntries removed gsd-* dirs
7501
7615
  // but left the category container and DESCRIPTION.md intact.
7502
7616
  if (runtime === 'hermes') {
@@ -7936,7 +8050,7 @@ function uninstall(isGlobal, runtime = 'claude') {
7936
8050
  if (runtime === 'kimi') runtimeLabel = 'Kimi CLI';
7937
8051
  if (runtime === 'codebuddy') runtimeLabel = 'CodeBuddy';
7938
8052
 
7939
- console.log(` Uninstalling GSD from ${cyan}${runtimeLabel}${reset} at ${cyan}${locationLabel}${reset}\n`);
8053
+ console.log(` Uninstalling pp-core from ${cyan}${runtimeLabel}${reset} at ${cyan}${locationLabel}${reset}\n`);
7940
8054
 
7941
8055
  // #786: AGENTS.md lives at the repo root (outside targetDir) for local Copilot
7942
8056
  // installs, so its cleanup must run even when .github (targetDir) was already
@@ -7948,10 +8062,10 @@ function uninstall(isGlobal, runtime = 'claude') {
7948
8062
  const cleaned = stripGsdFromCopilotInstructions(content);
7949
8063
  if (cleaned === null) {
7950
8064
  fs.unlinkSync(agentsMdPath);
7951
- console.log(` ${green}✓${reset} Removed AGENTS.md (was GSD-only)`);
8065
+ console.log(` ${green}✓${reset} Removed AGENTS.md (was pp-core-only)`);
7952
8066
  } else if (cleaned !== content) {
7953
8067
  fs.writeFileSync(agentsMdPath, cleaned);
7954
- console.log(` ${green}✓${reset} Cleaned GSD section from AGENTS.md`);
8068
+ console.log(` ${green}✓${reset} Cleaned pp-core section from AGENTS.md`);
7955
8069
  }
7956
8070
  }
7957
8071
  }
@@ -8002,11 +8116,11 @@ function uninstall(isGlobal, runtime = 'claude') {
8002
8116
  if (cleaned === null) {
8003
8117
  fs.unlinkSync(codexConfigPath);
8004
8118
  removedCount++;
8005
- console.log(` ${green}✓${reset} Removed config.toml (was GSD-only)`);
8119
+ console.log(` ${green}✓${reset} Removed config.toml (was pp-core-only)`);
8006
8120
  } else if (cleaned !== content) {
8007
8121
  fs.writeFileSync(codexConfigPath, cleaned);
8008
8122
  removedCount++;
8009
- console.log(` ${green}✓${reset} Cleaned GSD sections from config.toml`);
8123
+ console.log(` ${green}✓${reset} Cleaned pp-core sections from config.toml`);
8010
8124
  }
8011
8125
  }
8012
8126
 
@@ -8035,15 +8149,15 @@ function uninstall(isGlobal, runtime = 'claude') {
8035
8149
  if (cleaned === null) {
8036
8150
  fs.unlinkSync(instructionsPath);
8037
8151
  removedCount++;
8038
- console.log(` ${green}✓${reset} Removed copilot-instructions.md (was GSD-only)`);
8152
+ console.log(` ${green}✓${reset} Removed copilot-instructions.md (was pp-core-only)`);
8039
8153
  } else if (cleaned !== content) {
8040
8154
  fs.writeFileSync(instructionsPath, cleaned);
8041
8155
  removedCount++;
8042
- console.log(` ${green}✓${reset} Cleaned GSD section from copilot-instructions.md`);
8156
+ console.log(` ${green}✓${reset} Cleaned pp-core section from copilot-instructions.md`);
8043
8157
  }
8044
8158
  }
8045
8159
 
8046
- // #786: remove the GSD-managed Copilot lifecycle hook config and prune the
8160
+ // #786: remove the pp-core-managed Copilot lifecycle hook config and prune the
8047
8161
  // hooks dir if we left it empty.
8048
8162
  const hookPath = path.join(targetDir, 'hooks', GSD_COPILOT_HOOK_FILE);
8049
8163
  if (fs.existsSync(hookPath)) {
@@ -8099,24 +8213,24 @@ function uninstall(isGlobal, runtime = 'claude') {
8099
8213
  if (cleaned === null) {
8100
8214
  fs.unlinkSync(agentsPath);
8101
8215
  removedCount++;
8102
- console.log(` ${green}✓${reset} Removed ~/.agents/AGENTS.md (was GSD-only)`);
8216
+ console.log(` ${green}✓${reset} Removed ~/.agents/AGENTS.md (was pp-core-only)`);
8103
8217
  } else if (cleaned !== content) {
8104
8218
  fs.writeFileSync(agentsPath, cleaned);
8105
8219
  removedCount++;
8106
- console.log(` ${green}✓${reset} Cleaned GSD section from ~/.agents/AGENTS.md`);
8220
+ console.log(` ${green}✓${reset} Cleaned pp-core section from ~/.agents/AGENTS.md`);
8107
8221
  }
8108
8222
  }
8109
8223
  } catch { /* best-effort */ }
8110
8224
  }
8111
8225
  }
8112
8226
 
8113
- // 1b-cursor. Non-layout Cursor side-effects (issue #777): remove GSD-managed
8227
+ // 1b-cursor. Non-layout Cursor side-effects (issue #777): remove pp-core-managed
8114
8228
  // hook entries from hooks.json and clean up the managed hook scripts.
8115
8229
  if (isCursor) {
8116
8230
  const hooksJsonCleanup = removeCursorHooksJson(targetDir);
8117
8231
  if (hooksJsonCleanup.changed) {
8118
8232
  removedCount++;
8119
- console.log(` ${green}✓${reset} Removed GSD-managed Cursor hooks from hooks.json`);
8233
+ console.log(` ${green}✓${reset} Removed pp-core-managed Cursor hooks from hooks.json`);
8120
8234
  }
8121
8235
  // Remove the managed hook scripts (session-start + post-tool).
8122
8236
  const hooksDir = path.join(targetDir, 'hooks');
@@ -8265,7 +8379,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8265
8379
  }
8266
8380
  }
8267
8381
 
8268
- // 3. Remove GSD agents (gsd-*.md files only)
8382
+ // 3. Remove pp-core agents (gsd-*.md files only)
8269
8383
  const agentsDir = path.join(targetDir, 'agents');
8270
8384
  if (fs.existsSync(agentsDir)) {
8271
8385
  const files = fs.readdirSync(agentsDir);
@@ -8278,11 +8392,11 @@ function uninstall(isGlobal, runtime = 'claude') {
8278
8392
  }
8279
8393
  if (agentCount > 0) {
8280
8394
  removedCount++;
8281
- console.log(` ${green}✓${reset} Removed ${agentCount} GSD agents`);
8395
+ console.log(` ${green}✓${reset} Removed ${agentCount} pp-core agents`);
8282
8396
  }
8283
8397
  }
8284
8398
 
8285
- // 4. Remove GSD hooks
8399
+ // 4. Remove pp-core hooks
8286
8400
  const hooksDir = path.join(targetDir, 'hooks');
8287
8401
  if (fs.existsSync(hooksDir)) {
8288
8402
  let hookCount = 0;
@@ -8295,10 +8409,10 @@ function uninstall(isGlobal, runtime = 'claude') {
8295
8409
  }
8296
8410
  if (hookCount > 0) {
8297
8411
  removedCount++;
8298
- console.log(` ${green}✓${reset} Removed ${hookCount} GSD hooks`);
8412
+ console.log(` ${green}✓${reset} Removed ${hookCount} pp-core hooks`);
8299
8413
  }
8300
8414
 
8301
- // Remove only the GSD-managed files from hooks/lib/ (git-cmd.js + pp-graphify-rebuild.sh).
8415
+ // Remove only the pp-core-managed files from hooks/lib/ (git-cmd.js + pp-graphify-rebuild.sh).
8302
8416
  // hooks/lib/ lives inside the user's runtime hooks directory (shared space) and
8303
8417
  // may contain user-owned custom helpers. We must not recursively delete the dir.
8304
8418
  const hooksLibDir = path.join(hooksDir, 'lib');
@@ -8327,9 +8441,9 @@ function uninstall(isGlobal, runtime = 'claude') {
8327
8441
  }
8328
8442
 
8329
8443
  // 4a. Remove scripts/changeset/ and scripts/lib/ (#935)
8330
- // GSD-managed files only: enumerate the exact set the installer writes.
8444
+ // pp-core-managed files only: enumerate the exact set the installer writes.
8331
8445
  // Any file NOT in this set is user-owned and must survive uninstall.
8332
- // After removing GSD files, attempt to rmdir — if the directory is still
8446
+ // After removing pp-core files, attempt to rmdir — if the directory is still
8333
8447
  // non-empty (user has custom helpers) it stays; otherwise it goes cleanly.
8334
8448
  const GSD_CHANGESET_FILES = [
8335
8449
  'cli.cjs', 'parse.cjs', 'render.cjs', 'serialize.cjs',
@@ -8349,7 +8463,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8349
8463
  try { fs.rmdirSync(changesetUninstallDir); } catch (_) { /* Not empty — user content present */ }
8350
8464
  if (removedChangeset > 0) {
8351
8465
  removedCount++;
8352
- console.log(` ${green}✓${reset} Removed scripts/changeset/ GSD files`);
8466
+ console.log(` ${green}✓${reset} Removed scripts/changeset/ pp-core files`);
8353
8467
  }
8354
8468
  }
8355
8469
  const scriptsLibUninstallDir = path.join(targetDir, 'scripts', 'lib');
@@ -8363,7 +8477,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8363
8477
  try { fs.rmdirSync(scriptsLibUninstallDir); } catch (_) { /* Not empty — user content present */ }
8364
8478
  if (removedScriptsLib > 0) {
8365
8479
  removedCount++;
8366
- console.log(` ${green}✓${reset} Removed scripts/lib/ GSD files`);
8480
+ console.log(` ${green}✓${reset} Removed scripts/lib/ pp-core files`);
8367
8481
  }
8368
8482
  }
8369
8483
  // Remove scripts/fix-slash-commands.cjs (#1223) — must come before the scripts/ rmdir
@@ -8376,7 +8490,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8376
8490
  try { fs.rmdirSync(scriptsUninstallDir); } catch (_) { /* Not empty — leave it */ }
8377
8491
  }
8378
8492
 
8379
- // 5. Remove GSD package.json (CommonJS mode marker)
8493
+ // 5. Remove pp-core package.json (CommonJS mode marker)
8380
8494
  const pkgJsonPath = path.join(targetDir, 'package.json');
8381
8495
  if (fs.existsSync(pkgJsonPath)) {
8382
8496
  try {
@@ -8385,14 +8499,14 @@ function uninstall(isGlobal, runtime = 'claude') {
8385
8499
  if (content === '{"type":"commonjs"}') {
8386
8500
  fs.unlinkSync(pkgJsonPath);
8387
8501
  removedCount++;
8388
- console.log(` ${green}✓${reset} Removed GSD package.json`);
8502
+ console.log(` ${green}✓${reset} Removed pp-core package.json`);
8389
8503
  }
8390
8504
  } catch (e) {
8391
8505
  // Ignore read errors
8392
8506
  }
8393
8507
  }
8394
8508
 
8395
- // 6. Clean up settings.json (remove GSD hooks and statusline)
8509
+ // 6. Clean up settings.json (remove pp-core hooks and statusline)
8396
8510
  const settingsPath = path.join(targetDir, 'settings.json');
8397
8511
  if (fs.existsSync(settingsPath)) {
8398
8512
  let settings = readSettings(settingsPath);
@@ -8402,15 +8516,15 @@ function uninstall(isGlobal, runtime = 'claude') {
8402
8516
  }
8403
8517
  let settingsModified = false;
8404
8518
 
8405
- // Remove GSD statusline if it references our hook
8519
+ // Remove pp-core statusline if it references our hook
8406
8520
  if (settings.statusLine && settings.statusLine.command &&
8407
8521
  settings.statusLine.command.includes('pp-statusline')) {
8408
8522
  delete settings.statusLine;
8409
8523
  settingsModified = true;
8410
- console.log(` ${green}✓${reset} Removed GSD statusline from settings`);
8524
+ console.log(` ${green}✓${reset} Removed pp-core statusline from settings`);
8411
8525
  }
8412
8526
 
8413
- // Remove GSD hooks from settings — per-hook granularity to preserve
8527
+ // Remove pp-core hooks from settings — per-hook granularity to preserve
8414
8528
  // user hooks that share an entry with a GSD hook (#1755 followup).
8415
8529
  // Includes the 3 Qwen-only events added in #788 (SubagentStop, Stop,
8416
8530
  // PreCompact, also registered for Claude in #770), the 3 Gemini-only
@@ -8424,7 +8538,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8424
8538
  settings.hooks[eventName] = settings.hooks[eventName]
8425
8539
  .map(entry => {
8426
8540
  if (!entry || typeof entry !== 'object' || !Array.isArray(entry.hooks)) return entry;
8427
- // Filter out individual GSD hooks, keep user hooks
8541
+ // Filter out individual pp-core hooks, keep user hooks
8428
8542
  entry.hooks = entry.hooks.filter((h) => {
8429
8543
  if (!h || typeof h.command !== 'string') return true;
8430
8544
  return !isManagedHookCommand(h.command, {
@@ -8443,7 +8557,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8443
8557
  }
8444
8558
  }
8445
8559
  if (settingsModified) {
8446
- console.log(` ${green}✓${reset} Removed GSD hooks from settings`);
8560
+ console.log(` ${green}✓${reset} Removed pp-core hooks from settings`);
8447
8561
  }
8448
8562
 
8449
8563
  // Clean up empty hooks object
@@ -8455,7 +8569,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8455
8569
  // Applies only to Claude uninstalls. Filter only the exact GSD-owned entries
8456
8570
  // to preserve any user-added allow/deny entries.
8457
8571
  // Uses a local flag to avoid the shared `settingsModified` producing a false
8458
- // "Removed GSD permissions" message when only hooks/statusline changed.
8572
+ // "Removed pp-core permissions" message when only hooks/statusline changed.
8459
8573
  if (runtime === 'claude' && settings.permissions) {
8460
8574
  let permissionsModified = false;
8461
8575
  if (Array.isArray(settings.permissions.allow)) {
@@ -8478,7 +8592,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8478
8592
  }
8479
8593
  if (permissionsModified) {
8480
8594
  settingsModified = true;
8481
- console.log(` ${green}✓${reset} Removed GSD permissions from settings.json`);
8595
+ console.log(` ${green}✓${reset} Removed pp-core permissions from settings.json`);
8482
8596
  }
8483
8597
  }
8484
8598
 
@@ -8521,7 +8635,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8521
8635
  if (modified) {
8522
8636
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
8523
8637
  removedCount++;
8524
- console.log(` ${green}✓${reset} Removed GSD permissions from ${path.basename(configPath)}`);
8638
+ console.log(` ${green}✓${reset} Removed pp-core permissions from ${path.basename(configPath)}`);
8525
8639
  }
8526
8640
  } catch (e) {
8527
8641
  // Ignore JSON parse errors
@@ -8562,7 +8676,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8562
8676
  if (modified) {
8563
8677
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
8564
8678
  removedCount++;
8565
- console.log(` ${green}✓${reset} Removed GSD permissions from ${path.basename(configPath)}`);
8679
+ console.log(` ${green}✓${reset} Removed pp-core permissions from ${path.basename(configPath)}`);
8566
8680
  }
8567
8681
  } catch (e) {
8568
8682
  // Ignore JSON parse errors
@@ -8580,7 +8694,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8580
8694
  }
8581
8695
 
8582
8696
  if (removedCount === 0) {
8583
- console.log(` ${yellow}⚠${reset} No GSD files found to remove.`);
8697
+ console.log(` ${yellow}⚠${reset} No pp-core files found to remove.`);
8584
8698
  }
8585
8699
 
8586
8700
  console.log(`
@@ -8727,7 +8841,7 @@ function configureOpencodePermissions(isGlobal = true, configDir = null) {
8727
8841
 
8728
8842
  // Write config back
8729
8843
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
8730
- console.log(` ${green}✓${reset} Configured read permission for GSD docs`);
8844
+ console.log(` ${green}✓${reset} Configured read permission for pp-core docs`);
8731
8845
  }
8732
8846
 
8733
8847
  /**
@@ -8801,7 +8915,7 @@ function configureKiloPermissions(isGlobal = true, configDir = null) {
8801
8915
 
8802
8916
  // Write config back
8803
8917
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
8804
- console.log(` ${green}✓${reset} Configured read permission for GSD docs`);
8918
+ console.log(` ${green}✓${reset} Configured read permission for pp-core docs`);
8805
8919
  }
8806
8920
 
8807
8921
  /**
@@ -8949,7 +9063,7 @@ function writeManifest(configDir, runtime = 'claude', options = {}) {
8949
9063
  // Flat-hyphen layout: pp-*.md files live directly in commands/ (no gsd/ subdir).
8950
9064
  const commandsDir = path.join(configDir, 'commands');
8951
9065
  const opencodeCommandDir = path.join(configDir, 'command');
8952
- // Hermes nests GSD skills under skills/gsd/ as a single category (#2841).
9066
+ // Hermes nests pp-core skills under skills/gsd/ as a single category (#2841).
8953
9067
  // All other runtimes that use the Codex-style skills layout use a flat skills/ root.
8954
9068
  const codexSkillsDir = isHermes
8955
9069
  ? path.join(configDir, 'skills', 'gsd')
@@ -9184,7 +9298,7 @@ function populatePristineDir({ packageSrc, pristineDir, modified, runtime, pathP
9184
9298
  }
9185
9299
 
9186
9300
  /**
9187
- * Detect user-modified GSD files by comparing against install manifest.
9301
+ * Detect user-modified pp-core files by comparing against install manifest.
9188
9302
  * Backs up modified files to gsd-local-patches/ for reapply after update.
9189
9303
  * Also saves pristine copies (from manifest) to gsd-pristine/ to enable
9190
9304
  * three-way merge during reapply-patches (pristine vs user vs new).
@@ -9252,7 +9366,7 @@ function saveLocalPatches(configDir, pristineCtx) {
9252
9366
  meta.pristine_hashes[relPath] = pristineHashes[relPath];
9253
9367
  }
9254
9368
  fs.writeFileSync(path.join(patchesDir, 'backup-meta.json'), JSON.stringify(meta, null, 2));
9255
- console.log(' ' + yellow + 'i' + reset + ' Found ' + modified.length + ' locally modified GSD file(s) — backed up to ' + PATCHES_DIR_NAME + '/');
9369
+ console.log(' ' + yellow + 'i' + reset + ' Found ' + modified.length + ' locally modified pp-core file(s) — backed up to ' + PATCHES_DIR_NAME + '/');
9256
9370
  for (const f of modified) {
9257
9371
  console.log(' ' + dim + f + reset);
9258
9372
  }
@@ -9611,7 +9725,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
9611
9725
  rollback();
9612
9726
  };
9613
9727
 
9614
- // Save any locally modified GSD files before they get wiped.
9728
+ // Save any locally modified pp-core files before they get wiped.
9615
9729
  // The pristine context lets saveLocalPatches populate gsd-pristine/ via
9616
9730
  // the install transform pipeline, giving the reapply-patches Step 5
9617
9731
  // verifier a real diff baseline (#2998).
@@ -9817,7 +9931,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
9817
9931
  // #3541: non-interactive runs (typical /gsd-update via Claude Code) have
9818
9932
  // no stdin TTY and therefore no way to answer prompt-user migration
9819
9933
  // actions. Resolve safe categories by classification (stale SDK build
9820
- // artifacts → remove; user-facing skills → keep; bundled GSD hooks →
9934
+ // artifacts → remove; user-facing skills → keep; bundled pp-core hooks →
9821
9935
  // remove [#3610]) and log every resolution; anything that cannot be
9822
9936
  // safely defaulted falls through to assertInstallerMigrationsUnblocked,
9823
9937
  // which now emits a grouped error with the documented resolution path.
@@ -9825,7 +9939,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
9825
9939
  // #3610: the classifier-based resolution must run regardless of TTY.
9826
9940
  // For unambiguous categories (e.g. `hooks/gsd-*` bundled hooks left
9827
9941
  // behind by a previous version), there is no actual "user choice" to
9828
- // make — the file is a known GSD-managed artifact and the installer is
9942
+ // make — the file is a known pp-core-managed artifact and the installer is
9829
9943
  // about to write the fresh bundled version. Gating the resolver on
9830
9944
  // `!isTTY` made `npx @opengsd/gsd-core@latest --codex` hard-abort with
9831
9945
  // 12 blocked bundled hooks. The env-override branch (operator-supplied
@@ -9897,7 +10011,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
9897
10011
  // #1326 — Codex only: remove stale agents/openai.yaml sidecars from managed
9898
10012
  // gsd-* skill dirs. Prior installs wrote these files so Codex would show a
9899
10013
  // display name and description in the /skills TUI popup. Recent Codex builds
9900
- // index BOTH SKILL.md and the sidecar, causing each GSD skill to appear twice
10014
+ // index BOTH SKILL.md and the sidecar, causing each pp-core skill to appear twice
9901
10015
  // in autocomplete. Cleaning them up fixes the duplication; SKILL.md alone is
9902
10016
  // sufficient for Codex discovery. User-owned dirs are never touched.
9903
10017
  if (isCodex) {
@@ -10036,7 +10150,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10036
10150
  // Global installs are handled above by _isSkillsRuntime (#782).
10037
10151
  console.log(` ${green}✓${reset} Cline: commands will be available via .clinerules`);
10038
10152
  } else if (isGemini) {
10039
- // #3037: when running --local --gemini and a GSD-managed user-scope
10153
+ // #3037: when running --local --gemini and a pp-core-managed user-scope
10040
10154
  // command directory already exists at ~/.gemini/commands/gsd/, skip
10041
10155
  // the local copy. Gemini conflict-detects by command name across
10042
10156
  // scopes and renames every overlapping /gsd:* command to
@@ -10112,7 +10226,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10112
10226
  fs.rmSync(path.join(staleSkillsDir, e.name), { recursive: true });
10113
10227
  }
10114
10228
  if (staleGsd.length > 0) {
10115
- console.log(` ${green}✓${reset} Removed ${staleGsd.length} stale GSD skill(s) from skills/`);
10229
+ console.log(` ${green}✓${reset} Removed ${staleGsd.length} stale pp-core skill(s) from skills/`);
10116
10230
  }
10117
10231
  }
10118
10232
  }
@@ -10835,7 +10949,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10835
10949
  let configContent = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf-8') : '';
10836
10950
  const eol = detectLineEnding(configContent);
10837
10951
 
10838
- // Strip ALL prior GSD-managed hook blocks BEFORE migration so the migration
10952
+ // Strip ALL prior pp-core-managed hook blocks BEFORE migration so the migration
10839
10953
  // only touches user-authored hooks, not GSD-owned stale entries. Running
10840
10954
  // strip after migration causes Shape 1 (legacy gsd-update-check filename)
10841
10955
  // to be converted by migration before the strip regex can match it (#2698).
@@ -10848,7 +10962,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10848
10962
  configContent = stripStaleGsdHookBlocks(configContent);
10849
10963
 
10850
10964
  // Migrate legacy [hooks] map format and flat [[hooks]] AoT entries to the
10851
- // namespaced [[hooks.<EVENT>]] form after stripping GSD-managed stale blocks.
10965
+ // namespaced [[hooks.<EVENT>]] form after stripping pp-core-managed stale blocks.
10852
10966
  // Running migration after strip ensures only user-authored hooks are migrated
10853
10967
  // (#2698 regression: migration before strip converts stale GSD blocks before
10854
10968
  // the strip regexes can match their original shape).
@@ -10861,7 +10975,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10861
10975
  const codexHooksFeature = ensureCodexHooksFeature(configContent);
10862
10976
  configContent = setManagedCodexHooksOwnership(codexHooksFeature.content, codexHooksFeature.ownership);
10863
10977
 
10864
- // GSD-managed Codex hook payloads now live in hooks.json to avoid mixed
10978
+ // pp-core-managed Codex hook payloads now live in hooks.json to avoid mixed
10865
10979
  // representation warnings when a single layer contains both hooks.json
10866
10980
  // and inline [hooks] entries. Keep config.toml focused on feature flags
10867
10981
  // and agent metadata.
@@ -11129,7 +11243,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
11129
11243
  }
11130
11244
  }
11131
11245
  writeSettings(sharedSettingsPath, sharedRaw);
11132
- console.log(` ${green}✓${reset} Migrated GSD hook entries from settings.json to settings.local.json (#338)`);
11246
+ console.log(` ${green}✓${reset} Migrated pp-core hook entries from settings.json to settings.local.json (#338)`);
11133
11247
  }
11134
11248
  }
11135
11249
  }
@@ -11227,7 +11341,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
11227
11341
  }
11228
11342
  }
11229
11343
 
11230
- // Register all GSD-managed hook entries into settings.hooks.* for runtimes
11344
+ // Register all pp-core-managed hook entries into settings.hooks.* for runtimes
11231
11345
  // that use the settings.json hook surface (ADR-857 phase 5f-1b).
11232
11346
  // settings is mutated in place by applySettingsJsonHooks.
11233
11347
  applySettingsJsonHooks(settings, {
@@ -11562,7 +11676,7 @@ function handleStatusline(settings, isInteractive, callback) {
11562
11676
  • Context window usage (color-coded)
11563
11677
 
11564
11678
  ${cyan}1${reset}) Keep existing
11565
- ${cyan}2${reset}) Replace with GSD statusline
11679
+ ${cyan}2${reset}) Replace with pp-core statusline
11566
11680
  `);
11567
11681
 
11568
11682
  rl.question(` Choice ${dim}[1]${reset}: `, (answer) => {
@@ -12309,6 +12423,8 @@ module.exports = {
12309
12423
  readGsdCommandNames,
12310
12424
  installRuntimeArtifacts,
12311
12425
  installOpencodeFamilySkills,
12426
+ installVerbatimSkills,
12427
+ findParetoSkillsSrc,
12312
12428
  uninstallRuntimeArtifacts,
12313
12429
  parseConfigDirFromArgs,
12314
12430
  cleanupLegacyGsdCc,