@pareto4/pp-core 1.5.0

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 (618) hide show
  1. package/.claude-plugin/plugin.json +23 -0
  2. package/GEMINI.md +53 -0
  3. package/LICENSE +22 -0
  4. package/README.md +100 -0
  5. package/agents/pp-advisor-researcher.md +108 -0
  6. package/agents/pp-ai-researcher.md +114 -0
  7. package/agents/pp-assumptions-analyzer.md +105 -0
  8. package/agents/pp-code-fixer.md +669 -0
  9. package/agents/pp-code-reviewer.md +387 -0
  10. package/agents/pp-codebase-mapper.md +853 -0
  11. package/agents/pp-debug-session-manager.md +315 -0
  12. package/agents/pp-debugger.md +1453 -0
  13. package/agents/pp-doc-classifier.md +168 -0
  14. package/agents/pp-doc-synthesizer.md +204 -0
  15. package/agents/pp-doc-verifier.md +217 -0
  16. package/agents/pp-doc-writer.md +616 -0
  17. package/agents/pp-domain-researcher.md +147 -0
  18. package/agents/pp-eval-auditor.md +191 -0
  19. package/agents/pp-eval-planner.md +154 -0
  20. package/agents/pp-executor.md +808 -0
  21. package/agents/pp-framework-selector.md +160 -0
  22. package/agents/pp-integration-checker.md +470 -0
  23. package/agents/pp-intel-updater.md +339 -0
  24. package/agents/pp-mempalace-curator.md +47 -0
  25. package/agents/pp-nyquist-auditor.md +204 -0
  26. package/agents/pp-pattern-mapper.md +335 -0
  27. package/agents/pp-phase-researcher.md +867 -0
  28. package/agents/pp-plan-checker.md +988 -0
  29. package/agents/pp-planner.md +1052 -0
  30. package/agents/pp-project-researcher.md +612 -0
  31. package/agents/pp-research-synthesizer.md +260 -0
  32. package/agents/pp-roadmapper.md +741 -0
  33. package/agents/pp-security-auditor.md +156 -0
  34. package/agents/pp-ui-auditor.md +495 -0
  35. package/agents/pp-ui-checker.md +309 -0
  36. package/agents/pp-ui-researcher.md +375 -0
  37. package/agents/pp-user-profiler.md +171 -0
  38. package/agents/pp-verifier.md +967 -0
  39. package/assets/gsd-logo-2000-transparent.png +0 -0
  40. package/assets/gsd-logo-2000-transparent.svg +17 -0
  41. package/assets/gsd-logo-2000.png +0 -0
  42. package/assets/gsd-logo-2000.svg +21 -0
  43. package/assets/terminal.svg +68 -0
  44. package/bin/install.js +12370 -0
  45. package/bin/lib/ui-safety-gate.cjs +107 -0
  46. package/commands/pp-add-tests.md +42 -0
  47. package/commands/pp-ai-integration-phase.md +37 -0
  48. package/commands/pp-audit-fix.md +34 -0
  49. package/commands/pp-audit-milestone.md +37 -0
  50. package/commands/pp-audit-uat.md +24 -0
  51. package/commands/pp-autonomous.md +51 -0
  52. package/commands/pp-capture.md +62 -0
  53. package/commands/pp-cleanup.md +24 -0
  54. package/commands/pp-code-review.md +59 -0
  55. package/commands/pp-complete-milestone.md +143 -0
  56. package/commands/pp-config.md +56 -0
  57. package/commands/pp-debug.md +52 -0
  58. package/commands/pp-discovery.md +34 -0
  59. package/commands/pp-discuss-phase.md +77 -0
  60. package/commands/pp-docs-update.md +49 -0
  61. package/commands/pp-eval-review.md +33 -0
  62. package/commands/pp-execute-phase.md +65 -0
  63. package/commands/pp-explore.md +27 -0
  64. package/commands/pp-extract-learnings.md +23 -0
  65. package/commands/pp-fast.md +31 -0
  66. package/commands/pp-forensics.md +57 -0
  67. package/commands/pp-graphify.md +204 -0
  68. package/commands/pp-health.md +31 -0
  69. package/commands/pp-help.md +28 -0
  70. package/commands/pp-import.md +45 -0
  71. package/commands/pp-inbox.md +39 -0
  72. package/commands/pp-ingest-docs.md +42 -0
  73. package/commands/pp-manager.md +45 -0
  74. package/commands/pp-map-codebase.md +83 -0
  75. package/commands/pp-mempalace-capture.md +71 -0
  76. package/commands/pp-mempalace-recall.md +102 -0
  77. package/commands/pp-milestone-summary.md +51 -0
  78. package/commands/pp-mvp-phase.md +45 -0
  79. package/commands/pp-new-milestone.md +45 -0
  80. package/commands/pp-new-project.md +47 -0
  81. package/commands/pp-ns-context.md +25 -0
  82. package/commands/pp-ns-ideate.md +24 -0
  83. package/commands/pp-ns-manage.md +36 -0
  84. package/commands/pp-ns-project.md +27 -0
  85. package/commands/pp-ns-review.md +29 -0
  86. package/commands/pp-ns-workflow.md +35 -0
  87. package/commands/pp-pause-work.md +43 -0
  88. package/commands/pp-phase.md +56 -0
  89. package/commands/pp-plan-phase.md +63 -0
  90. package/commands/pp-plan-review-convergence.md +60 -0
  91. package/commands/pp-pr-branch.md +26 -0
  92. package/commands/pp-profile-user.md +46 -0
  93. package/commands/pp-progress.md +49 -0
  94. package/commands/pp-quick.md +174 -0
  95. package/commands/pp-resume-work.md +30 -0
  96. package/commands/pp-review-backlog.md +63 -0
  97. package/commands/pp-review.md +42 -0
  98. package/commands/pp-secure-phase.md +36 -0
  99. package/commands/pp-settings.md +29 -0
  100. package/commands/pp-ship.md +24 -0
  101. package/commands/pp-sketch.md +60 -0
  102. package/commands/pp-spec-phase.md +63 -0
  103. package/commands/pp-spike.md +57 -0
  104. package/commands/pp-stats.md +20 -0
  105. package/commands/pp-surface.md +162 -0
  106. package/commands/pp-thread.md +24 -0
  107. package/commands/pp-ui-phase.md +35 -0
  108. package/commands/pp-ui-review.md +33 -0
  109. package/commands/pp-ultraplan-phase.md +34 -0
  110. package/commands/pp-undo.md +35 -0
  111. package/commands/pp-update.md +49 -0
  112. package/commands/pp-validate-phase.md +36 -0
  113. package/commands/pp-verify-work.md +39 -0
  114. package/commands/pp-workspace.md +52 -0
  115. package/commands/pp-workstreams.md +70 -0
  116. package/gemini-extension.json +6 -0
  117. package/hooks/dist/lib/git-cmd.js +150 -0
  118. package/hooks/dist/lib/pp-graphify-rebuild.sh +65 -0
  119. package/hooks/dist/managed-hooks-registry.cjs +39 -0
  120. package/hooks/dist/pp-check-update-worker.js +108 -0
  121. package/hooks/dist/pp-check-update.js +66 -0
  122. package/hooks/dist/pp-config-reload.js +133 -0
  123. package/hooks/dist/pp-context-monitor.js +196 -0
  124. package/hooks/dist/pp-cursor-post-tool.js +75 -0
  125. package/hooks/dist/pp-cursor-session-start.js +52 -0
  126. package/hooks/dist/pp-ensure-canonical-path.js +305 -0
  127. package/hooks/dist/pp-graphify-update.sh +158 -0
  128. package/hooks/dist/pp-phase-boundary.sh +47 -0
  129. package/hooks/dist/pp-prompt-guard.js +97 -0
  130. package/hooks/dist/pp-read-guard.js +101 -0
  131. package/hooks/dist/pp-read-injection-scanner.js +203 -0
  132. package/hooks/dist/pp-session-state.sh +59 -0
  133. package/hooks/dist/pp-statusline.js +566 -0
  134. package/hooks/dist/pp-update-banner.js +138 -0
  135. package/hooks/dist/pp-validate-commit.sh +57 -0
  136. package/hooks/dist/pp-workflow-guard.js +167 -0
  137. package/hooks/dist/pp-worktree-path-guard.js +185 -0
  138. package/hooks/hooks.json +70 -0
  139. package/hooks/lib/git-cmd.js +150 -0
  140. package/hooks/lib/pp-graphify-rebuild.sh +65 -0
  141. package/hooks/managed-hooks-registry.cjs +39 -0
  142. package/hooks/pp-check-update-worker.js +108 -0
  143. package/hooks/pp-check-update.js +66 -0
  144. package/hooks/pp-config-reload.js +133 -0
  145. package/hooks/pp-context-monitor.js +196 -0
  146. package/hooks/pp-cursor-post-tool.js +75 -0
  147. package/hooks/pp-cursor-session-start.js +52 -0
  148. package/hooks/pp-ensure-canonical-path.js +305 -0
  149. package/hooks/pp-graphify-update.sh +158 -0
  150. package/hooks/pp-phase-boundary.sh +47 -0
  151. package/hooks/pp-prompt-guard.js +97 -0
  152. package/hooks/pp-read-guard.js +101 -0
  153. package/hooks/pp-read-injection-scanner.js +203 -0
  154. package/hooks/pp-session-state.sh +59 -0
  155. package/hooks/pp-statusline.js +566 -0
  156. package/hooks/pp-update-banner.js +138 -0
  157. package/hooks/pp-validate-commit.sh +57 -0
  158. package/hooks/pp-workflow-guard.js +167 -0
  159. package/hooks/pp-worktree-path-guard.js +185 -0
  160. package/package.json +125 -0
  161. package/pp-core/bin/check-latest-version.cjs +161 -0
  162. package/pp-core/bin/lib/active-workstream-store.cjs +297 -0
  163. package/pp-core/bin/lib/adr-parser.cjs +399 -0
  164. package/pp-core/bin/lib/agent-command-router.cjs +68 -0
  165. package/pp-core/bin/lib/agent-install-check.cjs +143 -0
  166. package/pp-core/bin/lib/artifacts.cjs +51 -0
  167. package/pp-core/bin/lib/audit-command-router.cjs +61 -0
  168. package/pp-core/bin/lib/audit.cjs +743 -0
  169. package/pp-core/bin/lib/capability-activation.cjs +113 -0
  170. package/pp-core/bin/lib/capability-registry.cjs +3727 -0
  171. package/pp-core/bin/lib/capability-state.cjs +497 -0
  172. package/pp-core/bin/lib/capability-writer.cjs +355 -0
  173. package/pp-core/bin/lib/check-command-router.cjs +800 -0
  174. package/pp-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  175. package/pp-core/bin/lib/cli-exit.cjs +61 -0
  176. package/pp-core/bin/lib/clock.cjs +95 -0
  177. package/pp-core/bin/lib/clusters.cjs +131 -0
  178. package/pp-core/bin/lib/code-review-flags.cjs +59 -0
  179. package/pp-core/bin/lib/command-aliases.cjs +809 -0
  180. package/pp-core/bin/lib/command-arg-projection.cjs +55 -0
  181. package/pp-core/bin/lib/command-roster.cjs +19 -0
  182. package/pp-core/bin/lib/command-routing-hub.cjs +300 -0
  183. package/pp-core/bin/lib/commands.cjs +1244 -0
  184. package/pp-core/bin/lib/config-loader.cjs +714 -0
  185. package/pp-core/bin/lib/config-schema.cjs +58 -0
  186. package/pp-core/bin/lib/config-types.cjs +20 -0
  187. package/pp-core/bin/lib/config.cjs +796 -0
  188. package/pp-core/bin/lib/configuration.cjs +209 -0
  189. package/pp-core/bin/lib/context-utilization.cjs +48 -0
  190. package/pp-core/bin/lib/core-utils.cjs +198 -0
  191. package/pp-core/bin/lib/decisions.cjs +136 -0
  192. package/pp-core/bin/lib/docs.cjs +264 -0
  193. package/pp-core/bin/lib/drift.cjs +364 -0
  194. package/pp-core/bin/lib/edge-probe.cjs +196 -0
  195. package/pp-core/bin/lib/fallow-runner.cjs +153 -0
  196. package/pp-core/bin/lib/federated-config.cjs +182 -0
  197. package/pp-core/bin/lib/frontmatter.cjs +494 -0
  198. package/pp-core/bin/lib/gap-checker.cjs +260 -0
  199. package/pp-core/bin/lib/git-base-branch.cjs +220 -0
  200. package/pp-core/bin/lib/graphify-command-router.cjs +72 -0
  201. package/pp-core/bin/lib/graphify.cjs +472 -0
  202. package/pp-core/bin/lib/gsd2-import.cjs +456 -0
  203. package/pp-core/bin/lib/init-command-router.cjs +62 -0
  204. package/pp-core/bin/lib/init.cjs +1912 -0
  205. package/pp-core/bin/lib/install-profiles.cjs +814 -0
  206. package/pp-core/bin/lib/installer-migration-authoring.cjs +122 -0
  207. package/pp-core/bin/lib/installer-migration-report.cjs +351 -0
  208. package/pp-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +225 -0
  209. package/pp-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  210. package/pp-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  211. package/pp-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  212. package/pp-core/bin/lib/installer-migrations/004-prune-stale-pristine-snapshots.cjs +123 -0
  213. package/pp-core/bin/lib/installer-migrations/005-rename-gsd-core-to-pp-core.cjs +109 -0
  214. package/pp-core/bin/lib/installer-migrations/006-rename-gsd-command-namespace.cjs +135 -0
  215. package/pp-core/bin/lib/installer-migrations.cjs +823 -0
  216. package/pp-core/bin/lib/intel-command-router.cjs +119 -0
  217. package/pp-core/bin/lib/intel.cjs +584 -0
  218. package/pp-core/bin/lib/io.cjs +220 -0
  219. package/pp-core/bin/lib/learnings.cjs +270 -0
  220. package/pp-core/bin/lib/legacy-cleanup.cjs +253 -0
  221. package/pp-core/bin/lib/loop-host-contract.cjs +105 -0
  222. package/pp-core/bin/lib/loop-resolver.cjs +479 -0
  223. package/pp-core/bin/lib/milestone.cjs +381 -0
  224. package/pp-core/bin/lib/model-catalog.cjs +154 -0
  225. package/pp-core/bin/lib/model-profiles.cjs +24 -0
  226. package/pp-core/bin/lib/model-resolver.cjs +467 -0
  227. package/pp-core/bin/lib/observability/event.cjs +51 -0
  228. package/pp-core/bin/lib/observability/logger.cjs +146 -0
  229. package/pp-core/bin/lib/observability/redaction.cjs +48 -0
  230. package/pp-core/bin/lib/package-identity.cjs +35 -0
  231. package/pp-core/bin/lib/package-legitimacy.cjs +368 -0
  232. package/pp-core/bin/lib/phase-command-router.cjs +209 -0
  233. package/pp-core/bin/lib/phase-id.cjs +213 -0
  234. package/pp-core/bin/lib/phase-lifecycle.cjs +74 -0
  235. package/pp-core/bin/lib/phase-locator.cjs +145 -0
  236. package/pp-core/bin/lib/phase.cjs +1446 -0
  237. package/pp-core/bin/lib/phases-command-router.cjs +43 -0
  238. package/pp-core/bin/lib/plan-drift-guard.cjs +117 -0
  239. package/pp-core/bin/lib/plan-scan.cjs +91 -0
  240. package/pp-core/bin/lib/planning-workspace.cjs +245 -0
  241. package/pp-core/bin/lib/probe-core.cjs +402 -0
  242. package/pp-core/bin/lib/profile-output.cjs +1164 -0
  243. package/pp-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
  244. package/pp-core/bin/lib/profile-pipeline.cjs +519 -0
  245. package/pp-core/bin/lib/prohibition-enforcement.cjs +660 -0
  246. package/pp-core/bin/lib/project-root.cjs +119 -0
  247. package/pp-core/bin/lib/prompt-budget.cjs +305 -0
  248. package/pp-core/bin/lib/research-provider.cjs +137 -0
  249. package/pp-core/bin/lib/research-store.cjs +167 -0
  250. package/pp-core/bin/lib/review-reviewer-selection.cjs +121 -0
  251. package/pp-core/bin/lib/roadmap-command-router.cjs +166 -0
  252. package/pp-core/bin/lib/roadmap-parser.cjs +456 -0
  253. package/pp-core/bin/lib/roadmap-upgrade.cjs +476 -0
  254. package/pp-core/bin/lib/roadmap.cjs +738 -0
  255. package/pp-core/bin/lib/runtime-artifact-conversion.cjs +1966 -0
  256. package/pp-core/bin/lib/runtime-artifact-layout.cjs +342 -0
  257. package/pp-core/bin/lib/runtime-config-adapter-registry.cjs +103 -0
  258. package/pp-core/bin/lib/runtime-homes.cjs +272 -0
  259. package/pp-core/bin/lib/runtime-hooks-surface.cjs +1460 -0
  260. package/pp-core/bin/lib/runtime-name-policy.cjs +97 -0
  261. package/pp-core/bin/lib/runtime-slash.cjs +137 -0
  262. package/pp-core/bin/lib/schema-detect.cjs +159 -0
  263. package/pp-core/bin/lib/secrets.cjs +34 -0
  264. package/pp-core/bin/lib/security.cjs +480 -0
  265. package/pp-core/bin/lib/semver-compare.cjs +42 -0
  266. package/pp-core/bin/lib/shell-command-projection.cjs +550 -0
  267. package/pp-core/bin/lib/state-command-router.cjs +172 -0
  268. package/pp-core/bin/lib/state-document.cjs +312 -0
  269. package/pp-core/bin/lib/state.cjs +2587 -0
  270. package/pp-core/bin/lib/surface.cjs +505 -0
  271. package/pp-core/bin/lib/task-command-router.cjs +85 -0
  272. package/pp-core/bin/lib/teams-status.cjs +74 -0
  273. package/pp-core/bin/lib/template.cjs +246 -0
  274. package/pp-core/bin/lib/uat-predicate.cjs +329 -0
  275. package/pp-core/bin/lib/uat.cjs +359 -0
  276. package/pp-core/bin/lib/ui-safety-gate.cjs +98 -0
  277. package/pp-core/bin/lib/update-context.cjs +221 -0
  278. package/pp-core/bin/lib/validate-command-router.cjs +91 -0
  279. package/pp-core/bin/lib/validate.cjs +122 -0
  280. package/pp-core/bin/lib/verification-command-router.cjs +31 -0
  281. package/pp-core/bin/lib/verification.cjs +196 -0
  282. package/pp-core/bin/lib/verify-command-router.cjs +44 -0
  283. package/pp-core/bin/lib/verify.cjs +1932 -0
  284. package/pp-core/bin/lib/workstream-inventory-builder.cjs +81 -0
  285. package/pp-core/bin/lib/workstream-inventory.cjs +147 -0
  286. package/pp-core/bin/lib/workstream-name-policy.cjs +91 -0
  287. package/pp-core/bin/lib/workstream.cjs +386 -0
  288. package/pp-core/bin/lib/worktree-base-ref.cjs +350 -0
  289. package/pp-core/bin/lib/worktree-safety.cjs +985 -0
  290. package/pp-core/bin/pp-tools.cjs +2239 -0
  291. package/pp-core/bin/pp_run +20 -0
  292. package/pp-core/bin/shared/config-defaults.manifest.json +97 -0
  293. package/pp-core/bin/shared/config-schema.manifest.json +176 -0
  294. package/pp-core/bin/shared/model-catalog.json +160 -0
  295. package/pp-core/bin/shared/runtime-aliases.manifest.json +79 -0
  296. package/pp-core/bin/verify-reapply-patches.cjs +400 -0
  297. package/pp-core/contexts/dev.md +21 -0
  298. package/pp-core/contexts/research.md +22 -0
  299. package/pp-core/contexts/review.md +23 -0
  300. package/pp-core/references/agent-contracts.md +79 -0
  301. package/pp-core/references/ai-evals.md +156 -0
  302. package/pp-core/references/ai-frameworks.md +186 -0
  303. package/pp-core/references/artifact-types.md +131 -0
  304. package/pp-core/references/autonomous-smart-discuss.md +277 -0
  305. package/pp-core/references/checkpoints.md +814 -0
  306. package/pp-core/references/common-bug-patterns.md +114 -0
  307. package/pp-core/references/context-budget.md +85 -0
  308. package/pp-core/references/continuation-format.md +253 -0
  309. package/pp-core/references/debugger-philosophy.md +76 -0
  310. package/pp-core/references/decimal-phase-calculation.md +64 -0
  311. package/pp-core/references/doc-conflict-engine.md +91 -0
  312. package/pp-core/references/domain-probes.md +125 -0
  313. package/pp-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +7 -0
  314. package/pp-core/references/edge-probe-fixtures/01-round-half-even/requirements.json +1 -0
  315. package/pp-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +8 -0
  316. package/pp-core/references/edge-probe-fixtures/02-merge-intervals/requirements.json +1 -0
  317. package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +7 -0
  318. package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/requirements.json +1 -0
  319. package/pp-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +7 -0
  320. package/pp-core/references/edge-probe-fixtures/04-money-rounding/requirements.json +1 -0
  321. package/pp-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +8 -0
  322. package/pp-core/references/edge-probe-fixtures/05-list-dedupe/requirements.json +1 -0
  323. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +8 -0
  324. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/requirements.json +1 -0
  325. package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/resolutions.json +4 -0
  326. package/pp-core/references/edge-probe.md +272 -0
  327. package/pp-core/references/execute-mvp-tdd.md +81 -0
  328. package/pp-core/references/executor-examples.md +110 -0
  329. package/pp-core/references/few-shot-examples/plan-checker.md +73 -0
  330. package/pp-core/references/few-shot-examples/verifier.md +109 -0
  331. package/pp-core/references/gate-prompts.md +100 -0
  332. package/pp-core/references/gates.md +70 -0
  333. package/pp-core/references/git-integration.md +298 -0
  334. package/pp-core/references/git-planning-commit.md +40 -0
  335. package/pp-core/references/ios-scaffold.md +123 -0
  336. package/pp-core/references/loop-hook-dispatch.md +61 -0
  337. package/pp-core/references/mandatory-initial-read.md +2 -0
  338. package/pp-core/references/model-profile-resolution.md +38 -0
  339. package/pp-core/references/model-profiles.md +245 -0
  340. package/pp-core/references/mvp-concepts.md +49 -0
  341. package/pp-core/references/phase-argument-parsing.md +61 -0
  342. package/pp-core/references/planner-antipatterns.md +176 -0
  343. package/pp-core/references/planner-chunked.md +49 -0
  344. package/pp-core/references/planner-gap-closure.md +62 -0
  345. package/pp-core/references/planner-graphify-auto-update.md +67 -0
  346. package/pp-core/references/planner-guidance.md +186 -0
  347. package/pp-core/references/planner-human-verify-mode.md +57 -0
  348. package/pp-core/references/planner-interface-context.md +62 -0
  349. package/pp-core/references/planner-load-graph-context.md +36 -0
  350. package/pp-core/references/planner-mvp-mode.md +53 -0
  351. package/pp-core/references/planner-reviews.md +42 -0
  352. package/pp-core/references/planner-revision.md +87 -0
  353. package/pp-core/references/planner-source-audit.md +73 -0
  354. package/pp-core/references/planning-config.md +477 -0
  355. package/pp-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
  356. package/pp-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
  357. package/pp-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
  358. package/pp-core/references/prohibition-probe.md +326 -0
  359. package/pp-core/references/project-skills-discovery.md +19 -0
  360. package/pp-core/references/questioning.md +162 -0
  361. package/pp-core/references/research-documentation-lookup.md +29 -0
  362. package/pp-core/references/research-philosophy.md +29 -0
  363. package/pp-core/references/research-verification-protocol.md +27 -0
  364. package/pp-core/references/revision-loop.md +97 -0
  365. package/pp-core/references/scout-codebase.md +51 -0
  366. package/pp-core/references/skeleton-template.md +48 -0
  367. package/pp-core/references/sketch-interactivity.md +41 -0
  368. package/pp-core/references/sketch-theme-system.md +94 -0
  369. package/pp-core/references/sketch-tooling.md +45 -0
  370. package/pp-core/references/sketch-variant-patterns.md +81 -0
  371. package/pp-core/references/spidr-splitting.md +69 -0
  372. package/pp-core/references/tdd.md +330 -0
  373. package/pp-core/references/thinking-models-debug.md +44 -0
  374. package/pp-core/references/thinking-models-execution.md +50 -0
  375. package/pp-core/references/thinking-models-planning.md +62 -0
  376. package/pp-core/references/thinking-models-research.md +50 -0
  377. package/pp-core/references/thinking-models-verification.md +55 -0
  378. package/pp-core/references/thinking-partner.md +96 -0
  379. package/pp-core/references/ui-brand.md +162 -0
  380. package/pp-core/references/universal-anti-patterns.md +63 -0
  381. package/pp-core/references/user-profiling.md +681 -0
  382. package/pp-core/references/user-story-template.md +58 -0
  383. package/pp-core/references/verification-overrides.md +227 -0
  384. package/pp-core/references/verification-patterns.md +612 -0
  385. package/pp-core/references/verify-mvp-mode.md +85 -0
  386. package/pp-core/references/workstream-flag.md +111 -0
  387. package/pp-core/references/worktree-branch-check.md +44 -0
  388. package/pp-core/references/worktree-path-safety.md +67 -0
  389. package/pp-core/templates/AI-SPEC.md +246 -0
  390. package/pp-core/templates/DEBUG.md +169 -0
  391. package/pp-core/templates/README.md +77 -0
  392. package/pp-core/templates/SECURITY.md +61 -0
  393. package/pp-core/templates/UAT.md +265 -0
  394. package/pp-core/templates/UI-SPEC.md +100 -0
  395. package/pp-core/templates/VALIDATION.md +76 -0
  396. package/pp-core/templates/claude-md.md +145 -0
  397. package/pp-core/templates/codebase/architecture.md +255 -0
  398. package/pp-core/templates/codebase/concerns.md +310 -0
  399. package/pp-core/templates/codebase/conventions.md +307 -0
  400. package/pp-core/templates/codebase/integrations.md +280 -0
  401. package/pp-core/templates/codebase/stack.md +186 -0
  402. package/pp-core/templates/codebase/structure.md +285 -0
  403. package/pp-core/templates/codebase/testing.md +480 -0
  404. package/pp-core/templates/config.json +62 -0
  405. package/pp-core/templates/context.md +352 -0
  406. package/pp-core/templates/continue-here.md +78 -0
  407. package/pp-core/templates/copilot-instructions.md +7 -0
  408. package/pp-core/templates/debug-subagent-prompt.md +91 -0
  409. package/pp-core/templates/dev-preferences.md +21 -0
  410. package/pp-core/templates/discovery.md +146 -0
  411. package/pp-core/templates/discussion-log.md +63 -0
  412. package/pp-core/templates/milestone-archive.md +123 -0
  413. package/pp-core/templates/milestone.md +115 -0
  414. package/pp-core/templates/phase-prompt.md +610 -0
  415. package/pp-core/templates/planner-subagent-prompt.md +117 -0
  416. package/pp-core/templates/project.md +203 -0
  417. package/pp-core/templates/requirements.md +231 -0
  418. package/pp-core/templates/research-project/ARCHITECTURE.md +204 -0
  419. package/pp-core/templates/research-project/FEATURES.md +147 -0
  420. package/pp-core/templates/research-project/PITFALLS.md +200 -0
  421. package/pp-core/templates/research-project/STACK.md +120 -0
  422. package/pp-core/templates/research-project/SUMMARY.md +170 -0
  423. package/pp-core/templates/research.md +592 -0
  424. package/pp-core/templates/retrospective.md +54 -0
  425. package/pp-core/templates/roadmap.md +202 -0
  426. package/pp-core/templates/spec.md +333 -0
  427. package/pp-core/templates/state.md +195 -0
  428. package/pp-core/templates/summary-complex.md +60 -0
  429. package/pp-core/templates/summary-minimal.md +42 -0
  430. package/pp-core/templates/summary-standard.md +49 -0
  431. package/pp-core/templates/summary.md +249 -0
  432. package/pp-core/templates/user-profile.md +146 -0
  433. package/pp-core/templates/user-setup.md +311 -0
  434. package/pp-core/templates/verification-report.md +335 -0
  435. package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -0
  436. package/pp-core/workflows/add-backlog.md +91 -0
  437. package/pp-core/workflows/add-phase.md +113 -0
  438. package/pp-core/workflows/add-tests.md +355 -0
  439. package/pp-core/workflows/add-todo.md +161 -0
  440. package/pp-core/workflows/ai-integration-phase.md +295 -0
  441. package/pp-core/workflows/analyze-dependencies.md +96 -0
  442. package/pp-core/workflows/audit-fix.md +178 -0
  443. package/pp-core/workflows/audit-milestone.md +362 -0
  444. package/pp-core/workflows/audit-uat.md +110 -0
  445. package/pp-core/workflows/autonomous.md +886 -0
  446. package/pp-core/workflows/check-todos.md +180 -0
  447. package/pp-core/workflows/cleanup.md +195 -0
  448. package/pp-core/workflows/code-review-fix.md +506 -0
  449. package/pp-core/workflows/code-review.md +696 -0
  450. package/pp-core/workflows/complete-milestone.md +857 -0
  451. package/pp-core/workflows/debug.md +237 -0
  452. package/pp-core/workflows/diagnose-issues.md +245 -0
  453. package/pp-core/workflows/discovery-phase.md +291 -0
  454. package/pp-core/workflows/discovery-sprint.md +1546 -0
  455. package/pp-core/workflows/discuss-phase/modes/advisor.md +176 -0
  456. package/pp-core/workflows/discuss-phase/modes/all.md +28 -0
  457. package/pp-core/workflows/discuss-phase/modes/analyze.md +44 -0
  458. package/pp-core/workflows/discuss-phase/modes/auto.md +57 -0
  459. package/pp-core/workflows/discuss-phase/modes/batch.md +52 -0
  460. package/pp-core/workflows/discuss-phase/modes/chain.md +98 -0
  461. package/pp-core/workflows/discuss-phase/modes/default.md +141 -0
  462. package/pp-core/workflows/discuss-phase/modes/power.md +44 -0
  463. package/pp-core/workflows/discuss-phase/modes/text.md +55 -0
  464. package/pp-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
  465. package/pp-core/workflows/discuss-phase/templates/context.md +136 -0
  466. package/pp-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
  467. package/pp-core/workflows/discuss-phase-assumptions.md +675 -0
  468. package/pp-core/workflows/discuss-phase-power.md +291 -0
  469. package/pp-core/workflows/discuss-phase.md +520 -0
  470. package/pp-core/workflows/do.md +111 -0
  471. package/pp-core/workflows/docs-update.md +1168 -0
  472. package/pp-core/workflows/edit-phase.md +295 -0
  473. package/pp-core/workflows/eval-review.md +159 -0
  474. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
  475. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  476. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  477. package/pp-core/workflows/execute-phase/steps/worktree-recovery-policy.md +9 -0
  478. package/pp-core/workflows/execute-phase.md +1707 -0
  479. package/pp-core/workflows/execute-plan.md +541 -0
  480. package/pp-core/workflows/explore.md +146 -0
  481. package/pp-core/workflows/extract-learnings.md +243 -0
  482. package/pp-core/workflows/fast.md +124 -0
  483. package/pp-core/workflows/forensics.md +279 -0
  484. package/pp-core/workflows/graduation.md +196 -0
  485. package/pp-core/workflows/health.md +224 -0
  486. package/pp-core/workflows/help/modes/brief.md +22 -0
  487. package/pp-core/workflows/help/modes/default.md +50 -0
  488. package/pp-core/workflows/help/modes/full.md +791 -0
  489. package/pp-core/workflows/help/modes/topic.md +74 -0
  490. package/pp-core/workflows/help.md +24 -0
  491. package/pp-core/workflows/import.md +256 -0
  492. package/pp-core/workflows/inbox.md +387 -0
  493. package/pp-core/workflows/ingest-docs.md +340 -0
  494. package/pp-core/workflows/insert-phase.md +152 -0
  495. package/pp-core/workflows/list-phase-assumptions.md +178 -0
  496. package/pp-core/workflows/list-workspaces.md +57 -0
  497. package/pp-core/workflows/manager.md +435 -0
  498. package/pp-core/workflows/map-codebase.md +444 -0
  499. package/pp-core/workflows/milestone-summary.md +224 -0
  500. package/pp-core/workflows/mvp-phase.md +222 -0
  501. package/pp-core/workflows/new-milestone.md +643 -0
  502. package/pp-core/workflows/new-project.md +1563 -0
  503. package/pp-core/workflows/new-workspace.md +240 -0
  504. package/pp-core/workflows/next.md +347 -0
  505. package/pp-core/workflows/node-repair.md +92 -0
  506. package/pp-core/workflows/note.md +158 -0
  507. package/pp-core/workflows/pause-work.md +250 -0
  508. package/pp-core/workflows/plan-milestone-gaps.md +281 -0
  509. package/pp-core/workflows/plan-phase.md +1755 -0
  510. package/pp-core/workflows/plan-review-convergence.md +369 -0
  511. package/pp-core/workflows/plant-seed.md +230 -0
  512. package/pp-core/workflows/pr-branch.md +159 -0
  513. package/pp-core/workflows/profile-user.md +455 -0
  514. package/pp-core/workflows/progress.md +756 -0
  515. package/pp-core/workflows/quick.md +1045 -0
  516. package/pp-core/workflows/reapply-patches.md +443 -0
  517. package/pp-core/workflows/remove-phase.md +156 -0
  518. package/pp-core/workflows/remove-workspace.md +108 -0
  519. package/pp-core/workflows/resume-project.md +348 -0
  520. package/pp-core/workflows/review.md +765 -0
  521. package/pp-core/workflows/scan.md +107 -0
  522. package/pp-core/workflows/secure-phase.md +184 -0
  523. package/pp-core/workflows/session-report.md +146 -0
  524. package/pp-core/workflows/settings-advanced.md +816 -0
  525. package/pp-core/workflows/settings-integrations.md +312 -0
  526. package/pp-core/workflows/settings.md +592 -0
  527. package/pp-core/workflows/ship.md +465 -0
  528. package/pp-core/workflows/sketch-wrap-up.md +286 -0
  529. package/pp-core/workflows/sketch.md +361 -0
  530. package/pp-core/workflows/spec-phase.md +495 -0
  531. package/pp-core/workflows/spike-wrap-up.md +307 -0
  532. package/pp-core/workflows/spike.md +453 -0
  533. package/pp-core/workflows/stats.md +80 -0
  534. package/pp-core/workflows/sync-skills.md +182 -0
  535. package/pp-core/workflows/thread.md +222 -0
  536. package/pp-core/workflows/transition.md +694 -0
  537. package/pp-core/workflows/ui-phase.md +328 -0
  538. package/pp-core/workflows/ui-review.md +193 -0
  539. package/pp-core/workflows/ultraplan-phase.md +199 -0
  540. package/pp-core/workflows/undo.md +314 -0
  541. package/pp-core/workflows/update.md +501 -0
  542. package/pp-core/workflows/validate-phase.md +183 -0
  543. package/pp-core/workflows/verify-phase.md +569 -0
  544. package/pp-core/workflows/verify-work.md +804 -0
  545. package/scripts/affected-tests-lib.cjs +554 -0
  546. package/scripts/audit-workflow-script-paths.cjs +73 -0
  547. package/scripts/base64-scan.sh +351 -0
  548. package/scripts/build-hooks.js +254 -0
  549. package/scripts/changeset/README.md +129 -0
  550. package/scripts/changeset/cli.cjs +597 -0
  551. package/scripts/changeset/github-release-notes.cjs +199 -0
  552. package/scripts/changeset/lint.cjs +147 -0
  553. package/scripts/changeset/new.cjs +151 -0
  554. package/scripts/changeset/parse.cjs +114 -0
  555. package/scripts/changeset/render.cjs +34 -0
  556. package/scripts/changeset/serialize.cjs +130 -0
  557. package/scripts/check-alias-drift.cjs +114 -0
  558. package/scripts/check-env.cjs +312 -0
  559. package/scripts/check-npm-integrity.cjs +215 -0
  560. package/scripts/ci-guard-runner.cjs +22 -0
  561. package/scripts/ci-prepare-test-scope.cjs +93 -0
  562. package/scripts/ci-rebase-check.cjs +86 -0
  563. package/scripts/ci-test-scope.cjs +441 -0
  564. package/scripts/command-contract-helpers.cjs +64 -0
  565. package/scripts/diff-touches-shipped-paths.cjs +149 -0
  566. package/scripts/fix-slash-commands.cjs +161 -0
  567. package/scripts/gen-capability-registry.cjs +2646 -0
  568. package/scripts/gen-commands-reference.cjs +139 -0
  569. package/scripts/gen-inventory-manifest.cjs +114 -0
  570. package/scripts/gen-loop-host-contract.cjs +526 -0
  571. package/scripts/gen-research-agents.cjs +276 -0
  572. package/scripts/generate-package-identity.cjs +134 -0
  573. package/scripts/issue-dedupe.cjs +278 -0
  574. package/scripts/issue-version-gate.cjs +140 -0
  575. package/scripts/lib/allowlist-ratchet.cjs +236 -0
  576. package/scripts/lib/cli-exit.cjs +56 -0
  577. package/scripts/lint-allow-test-rule-refs.allowlist.json +328 -0
  578. package/scripts/lint-allow-test-rule-refs.cjs +162 -0
  579. package/scripts/lint-command-contract.cjs +118 -0
  580. package/scripts/lint-descriptions.cjs +87 -0
  581. package/scripts/lint-docs-required.cjs +222 -0
  582. package/scripts/lint-legacy-dir-name.cjs +166 -0
  583. package/scripts/lint-package-identity-drift.cjs +141 -0
  584. package/scripts/lint-pr-check-project-dir.cjs +99 -0
  585. package/scripts/lint-regression-test-names.allowlist.json +269 -0
  586. package/scripts/lint-regression-test-names.cjs +117 -0
  587. package/scripts/lint-shell-command-projection-drift.cjs +62 -0
  588. package/scripts/lint-skill-deps.cjs +185 -0
  589. package/scripts/lint-test-file-count.allowlist.json +181 -0
  590. package/scripts/lint-test-file-count.cjs +246 -0
  591. package/scripts/lint-windows-test-portability.cjs +178 -0
  592. package/scripts/mutation-matrix.cjs +323 -0
  593. package/scripts/pr-target-policy.cjs +63 -0
  594. package/scripts/pr-template-policy.cjs +268 -0
  595. package/scripts/prompt-injection-scan.sh +207 -0
  596. package/scripts/registry-smoke.cjs +337 -0
  597. package/scripts/release-notes/discord-release-summary.cjs +373 -0
  598. package/scripts/release-notes/format-github-release-notes.cjs +261 -0
  599. package/scripts/release-tarball-smoke.cjs +763 -0
  600. package/scripts/research-profiles.cjs +149 -0
  601. package/scripts/run-affected-tests.cjs +7 -0
  602. package/scripts/run-tests.cjs +589 -0
  603. package/scripts/secret-scan-lint.sh +231 -0
  604. package/scripts/secret-scan.sh +358 -0
  605. package/scripts/setup-branch-protection.sh +234 -0
  606. package/scripts/strip-prose-atrefs.cjs +106 -0
  607. package/scripts/sync-manifest-versions.cjs +119 -0
  608. package/scripts/sync-next-version.cjs +133 -0
  609. package/scripts/sync-rulesets.sh +34 -0
  610. package/scripts/sync-runtime-launcher.cjs +425 -0
  611. package/scripts/test-failure-reasons.cjs +34 -0
  612. package/scripts/update-size-baseline.cjs +68 -0
  613. package/scripts/verify-npm-publish.cjs +240 -0
  614. package/scripts/verify-opengsd-sweep.cjs +288 -0
  615. package/scripts/verify-phase-02-rename.sh +258 -0
  616. package/scripts/verify-phase-03-rename.sh +376 -0
  617. package/scripts/workflow-policy.cjs +483 -0
  618. package/scripts/workflow-size.cjs +90 -0
@@ -0,0 +1,276 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * gen-research-agents.cjs — profile-driven drift guard for the 7 researcher agents.
6
+ *
7
+ * Usage:
8
+ * node scripts/gen-research-agents.cjs # same as --check
9
+ * node scripts/gen-research-agents.cjs --check # assert every agent matches its profile
10
+ * node scripts/gen-research-agents.cjs --write # regenerate frontmatter from profiles
11
+ *
12
+ * --check assertions per agent:
13
+ * (a) frontmatter name/description/color/tools exactly match the profile
14
+ * (b) every requiredInclude string is present in the body
15
+ * (c) every requiredSeamCall string is present in the body
16
+ * (d) every outputContract marker string is present in the body
17
+ *
18
+ * --write regenerates ONLY the opening `---\n...\n---` frontmatter block from the
19
+ * profile, leaving the body byte-identical. After --write, --check must pass and
20
+ * `git diff` must be empty (profiles were derived from current state).
21
+ */
22
+
23
+ const fs = require('node:fs');
24
+ const path = require('node:path');
25
+
26
+ const { PROFILES } = require('./research-profiles.cjs');
27
+ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
28
+
29
+ const ROOT = path.resolve(__dirname, '..');
30
+ const AGENTS_DIR = path.join(ROOT, 'agents');
31
+
32
+ // ─── Frontmatter serialization ────────────────────────────────────────────────
33
+
34
+ /**
35
+ * Build the frontmatter block for a profile.
36
+ *
37
+ * The agent files have two patterns for commented hooks:
38
+ * - Agents with Write in tools (file-writers): include the commented hooks block
39
+ * - The advisor-researcher (Read-only tools, no Write): no commented hooks
40
+ *
41
+ * We read the CURRENT commented-hooks block from the agent file and preserve it
42
+ * byte-for-byte; only name/description/tools/color are regenerated.
43
+ */
44
+ function buildFrontmatter(profile, existingFrontmatter) {
45
+ // Extract the commented hooks section from the existing frontmatter, if any.
46
+ // The hooks block starts at `# hooks:` and runs to (but not including) the
47
+ // closing `---`. In the committed files there is NO blank line between
48
+ // `color:` and `# hooks:`, so we append it directly after the color line's `\n`.
49
+ const hooksMatch = existingFrontmatter.match(/(# hooks:[\s\S]*?)(?=\n---)/);
50
+ // hooksSuffix: if present, the block followed by a newline so `---` is on its own line;
51
+ // if absent, empty string (the closing `---` follows directly after color's `\n`).
52
+ const hooksSuffix = hooksMatch ? hooksMatch[1] + '\n' : '';
53
+
54
+ return (
55
+ '---\n' +
56
+ 'name: ' + profile.name + '\n' +
57
+ 'description: ' + profile.description + '\n' +
58
+ 'tools: ' + profile.tools + '\n' +
59
+ 'color: ' + profile.color + '\n' +
60
+ hooksSuffix +
61
+ '---'
62
+ );
63
+ }
64
+
65
+ // ─── Parse agent file ─────────────────────────────────────────────────────────
66
+
67
+ /**
68
+ * Parse a .md file and return { frontmatterRaw, body, frontmatterFields }.
69
+ *
70
+ * frontmatterRaw: the raw text between the first and second `---` delimiters (exclusive)
71
+ * body: everything after the closing `---\n`
72
+ * frontmatterFields: { name, description, color, tools }
73
+ */
74
+ function parseAgentFile(filePath) {
75
+ const raw = fs.readFileSync(filePath, 'utf8');
76
+
77
+ // The frontmatter is between the first `---` line and the next `---` line.
78
+ const lines = raw.split('\n');
79
+ let start = -1;
80
+ let end = -1;
81
+ for (let i = 0; i < lines.length; i++) {
82
+ if (lines[i].trim() === '---') {
83
+ if (start === -1) {
84
+ start = i;
85
+ } else {
86
+ end = i;
87
+ break;
88
+ }
89
+ }
90
+ }
91
+
92
+ if (start === -1 || end === -1) {
93
+ throw new Error('No valid frontmatter delimiters found in ' + filePath);
94
+ }
95
+
96
+ const frontmatterLines = lines.slice(start + 1, end);
97
+ const frontmatterRaw = frontmatterLines.join('\n');
98
+ // body includes the closing `---` line and everything after
99
+ const fullFrontmatter = lines.slice(start, end + 1).join('\n');
100
+ const body = lines.slice(end + 1).join('\n');
101
+
102
+ const fields = {};
103
+ // Parse simple key: value pairs (not nested YAML, no multi-line values here)
104
+ for (const line of frontmatterLines) {
105
+ // Skip comment lines
106
+ if (line.trimStart().startsWith('#')) continue;
107
+ const m = line.match(/^(\w+):\s*(.*)/);
108
+ if (m) {
109
+ fields[m[1]] = m[2].trim();
110
+ }
111
+ }
112
+
113
+ return { raw, frontmatterRaw, fullFrontmatter, body, fields };
114
+ }
115
+
116
+ // ─── Check ────────────────────────────────────────────────────────────────────
117
+
118
+ /**
119
+ * Check one profile against its agent file.
120
+ * Returns an array of failure strings (empty = pass).
121
+ */
122
+ function checkAgent(profile) {
123
+ // Validate required array fields — return a clear failure rather than throwing TypeError.
124
+ for (const field of ['requiredIncludes', 'requiredSeamCalls', 'outputContract']) {
125
+ if (!Array.isArray(profile[field])) {
126
+ return ['profile ' + profile.name + ': missing required array field ' + field];
127
+ }
128
+ }
129
+
130
+ const agentPath = path.join(AGENTS_DIR, profile.name + '.md');
131
+ const failures = [];
132
+
133
+ if (!fs.existsSync(agentPath)) {
134
+ return ['agent file not found: ' + agentPath];
135
+ }
136
+
137
+ const { fields } = parseAgentFile(agentPath);
138
+ const fullContent = fs.readFileSync(agentPath, 'utf8');
139
+
140
+ // (a) frontmatter fields
141
+ if (fields.name !== profile.name) {
142
+ failures.push(
143
+ 'name mismatch: got "' + fields.name + '", want "' + profile.name + '"',
144
+ );
145
+ }
146
+ if (fields.description !== profile.description) {
147
+ failures.push(
148
+ 'description mismatch:\n got: "' + fields.description + '"\n want: "' + profile.description + '"',
149
+ );
150
+ }
151
+ if (fields.color !== profile.color) {
152
+ failures.push(
153
+ 'color mismatch: got "' + fields.color + '", want "' + profile.color + '"',
154
+ );
155
+ }
156
+ if (fields.tools !== profile.tools) {
157
+ failures.push(
158
+ 'tools mismatch:\n got: "' + fields.tools + '"\n want: "' + profile.tools + '"',
159
+ );
160
+ }
161
+
162
+ // (b) requiredIncludes
163
+ for (const include of profile.requiredIncludes) {
164
+ if (!fullContent.includes(include)) {
165
+ failures.push('missing required include: ' + include);
166
+ }
167
+ }
168
+
169
+ // (c) requiredSeamCalls
170
+ for (const seam of profile.requiredSeamCalls) {
171
+ if (!fullContent.includes(seam)) {
172
+ failures.push('missing required seam call: ' + seam);
173
+ }
174
+ }
175
+
176
+ // (d) outputContract
177
+ for (const marker of profile.outputContract) {
178
+ if (!fullContent.includes(marker)) {
179
+ failures.push('missing output contract marker: ' + marker);
180
+ }
181
+ }
182
+
183
+ return failures;
184
+ }
185
+
186
+ /**
187
+ * Run --check for all profiles. Prints pass/fail per agent.
188
+ * Returns true if all pass, false otherwise.
189
+ */
190
+ function runCheck() {
191
+ let allPassed = true;
192
+
193
+ for (const profile of PROFILES) {
194
+ const failures = checkAgent(profile);
195
+ if (failures.length === 0) {
196
+ process.stdout.write(' PASS ' + profile.name + '\n');
197
+ } else {
198
+ process.stdout.write(' FAIL ' + profile.name + '\n');
199
+ for (const f of failures) {
200
+ process.stdout.write(' ' + f.replace(/\n/g, '\n ') + '\n');
201
+ }
202
+ allPassed = false;
203
+ }
204
+ }
205
+
206
+ return allPassed;
207
+ }
208
+
209
+ // ─── Write ────────────────────────────────────────────────────────────────────
210
+
211
+ /**
212
+ * Regenerate the frontmatter block of one agent file from its profile.
213
+ * The body (everything after the closing ---) is preserved byte-for-byte.
214
+ */
215
+ function writeAgent(profile) {
216
+ const agentPath = path.join(AGENTS_DIR, profile.name + '.md');
217
+ const { fullFrontmatter, body } = parseAgentFile(agentPath);
218
+
219
+ const newFrontmatter = buildFrontmatter(profile, fullFrontmatter);
220
+ const newContent = newFrontmatter + '\n' + body;
221
+
222
+ fs.writeFileSync(agentPath, newContent, 'utf8');
223
+ }
224
+
225
+ function runWrite() {
226
+ for (const profile of PROFILES) {
227
+ const agentPath = path.join(AGENTS_DIR, profile.name + '.md');
228
+ if (!fs.existsSync(agentPath)) {
229
+ throw new ExitError(1, 'ERROR: agent file not found: ' + agentPath);
230
+ }
231
+ writeAgent(profile);
232
+ process.stdout.write(' wrote ' + profile.name + '.md\n');
233
+ }
234
+ process.stdout.write('\nRun --check to verify:\n');
235
+ process.stdout.write(' node scripts/gen-research-agents.cjs --check\n');
236
+ }
237
+
238
+ // ─── Exports (for tests) ──────────────────────────────────────────────────────
239
+
240
+ module.exports = { PROFILES, checkAgent, runCheck, parseAgentFile };
241
+
242
+ // ─── CLI entry point ──────────────────────────────────────────────────────────
243
+
244
+ function main() {
245
+ const flag = process.argv[2] || '--check';
246
+
247
+ if (flag === '--write') {
248
+ process.stdout.write('Writing frontmatter from profiles...\n');
249
+ runWrite();
250
+ process.stdout.write('\nVerifying...\n');
251
+ const ok = runCheck();
252
+ if (!ok) {
253
+ process.stderr.write('\nERROR: --check failed after --write. Fix serialization.\n');
254
+ throw new ExitError(1);
255
+ }
256
+ process.stdout.write('\nAll agents match their profiles.\n');
257
+ } else if (flag === '--check') {
258
+ process.stdout.write('Checking research agent profiles...\n');
259
+ const ok = runCheck();
260
+ if (!ok) {
261
+ process.stderr.write('\nSome agents do not match their profiles.\n');
262
+ process.stdout.write(
263
+ '\nTo regenerate frontmatter from profiles:\n' +
264
+ ' node scripts/gen-research-agents.cjs --write\n',
265
+ );
266
+ throw new ExitError(1);
267
+ }
268
+ process.stdout.write('\nAll 7 agents match their profiles.\n');
269
+ } else {
270
+ throw new ExitError(1, 'Unknown flag: ' + flag + '\nUsage: node scripts/gen-research-agents.cjs [--check|--write]');
271
+ }
272
+ }
273
+
274
+ if (require.main === module) {
275
+ runMain(main);
276
+ }
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Single source for GSD's published-package coordinates (issue #498).
6
+ *
7
+ * `deriveIdentity(pkg)` is the pure core: it turns a parsed package.json into
8
+ * the coordinate record every consumer needs. The generated runtime module
9
+ * `pp-core/bin/lib/package-identity.cjs` bakes those values at build
10
+ * time, because the installed tree carries only a synthetic
11
+ * `{"type":"commonjs"}` package.json (no `.name`) — so a runtime
12
+ * `require('package.json').name` resolves to `undefined` (the #378 bug this
13
+ * seam retires). Baking from package.json reconciles #378 (renames survive)
14
+ * with #2992 (the value is never an LLM runtime choice).
15
+ */
16
+
17
+ /**
18
+ * Parse `owner/name` out of a package.json `repository.url`, stripping the
19
+ * `git+` prefix and `.git` suffix npm conventionally adds.
20
+ */
21
+ function parseRepoSlug(repository) {
22
+ const url = typeof repository === 'string' ? repository : (repository && repository.url) || '';
23
+ const m = url.replace(/^git\+/, '').replace(/\.git$/, '').match(/((?:github|gitlab)\.com)[/:]([^/]+\/[^/]+)$/);
24
+ return m ? m[2] : '';
25
+ }
26
+
27
+ // Extract the git host (github.com or gitlab.com) from a repository URL
28
+ function parseRepoHost(repository) {
29
+ const url = typeof repository === 'string' ? repository : (repository && repository.url) || '';
30
+ const m = url.replace(/^git\+/, '').replace(/\.git$/, '').match(/((?:github|gitlab)\.com)[/:]([^/]+\/[^/]+)$/);
31
+ return m ? m[1] : 'github.com';
32
+ }
33
+
34
+ /**
35
+ * Pure: turn an npm package name into a filesystem-safe slug for cache filenames.
36
+ * Strips a leading `@`, replaces `/` with `-`, then collapses any run of
37
+ * characters that are NOT `[a-z0-9]` to a single `-`, and trims leading/trailing `-`.
38
+ */
39
+ function slugifyPackageName(name) {
40
+ if (!name) return '';
41
+ return name
42
+ .replace(/^@/, '')
43
+ .replace(/\//g, '-')
44
+ .toLowerCase()
45
+ .replace(/[^a-z0-9]+/g, '-')
46
+ .replace(/^-+|-+$/g, '');
47
+ }
48
+
49
+ /**
50
+ * Pure: package.json object -> the package identity coordinates.
51
+ */
52
+ function deriveIdentity(pkg = {}) {
53
+ const packageName = pkg.name || '';
54
+ const binName = pkg.bin ? Object.keys(pkg.bin)[0] || '' : '';
55
+ const repoSlug = parseRepoSlug(pkg.repository);
56
+ const repoHost = parseRepoHost(pkg.repository);
57
+ const isGitHub = repoHost === 'github.com';
58
+ const repoUrl = repoSlug ? `https://${repoHost}/${repoSlug}` : '';
59
+ const changelogRawUrl = repoSlug && isGitHub
60
+ ? `https://raw.githubusercontent.com/${repoSlug}/main/CHANGELOG.md`
61
+ : repoSlug ? `https://${repoHost}/${repoSlug}/-/raw/main/CHANGELOG.md` : '';
62
+ const cacheSlug = slugifyPackageName(packageName);
63
+ const updateCacheFileName = cacheSlug ? `pp-update-check-${cacheSlug}.json` : 'pp-update-check.json';
64
+ return { packageName, binName, repoSlug, repoUrl, changelogRawUrl, cacheSlug, updateCacheFileName };
65
+ }
66
+
67
+ /**
68
+ * Pure: format the `npx` fallback install command. Shape matches the literal
69
+ * the update workflow embeds: `npx -y --package=<pkg>@latest -- <bin>
70
+ * [--<runtime>] --<scope>`. The runtime flag is omitted when not supplied.
71
+ *
72
+ * This function is the canonical source — `render()` serializes it verbatim
73
+ * into the generated module, so the runtime copy can never drift from it.
74
+ */
75
+ function formatManualInstall({ packageName, binName, scope, runtime } = {}) {
76
+ const runtimeFlag = runtime ? ` --${runtime}` : '';
77
+ return `npx -y --package=${packageName}@latest -- ${binName}${runtimeFlag} --${scope}`;
78
+ }
79
+
80
+ const GENERATED_HEADER =
81
+ '// @generated by scripts/generate-package-identity.cjs from package.json — DO NOT EDIT.\n' +
82
+ '// Single source for PP package coordinates (issue #498). Regenerate with:\n' +
83
+ '// node scripts/generate-package-identity.cjs\n';
84
+
85
+ /**
86
+ * Render the generated runtime module text for a derived identity. Values are
87
+ * baked as literals; `formatManualInstall` is embedded by `.toString()` so the
88
+ * runtime command builder is byte-identical to the tested source above.
89
+ */
90
+ function render(identity) {
91
+ const { packageName, binName, repoSlug, repoUrl, changelogRawUrl, cacheSlug, updateCacheFileName } = identity;
92
+ const j = (v) => JSON.stringify(v);
93
+ return (
94
+ GENERATED_HEADER +
95
+ "'use strict';\n\n" +
96
+ `const packageName = ${j(packageName)};\n` +
97
+ `const binName = ${j(binName)};\n` +
98
+ `const repoSlug = ${j(repoSlug)};\n` +
99
+ `const repoUrl = ${j(repoUrl)};\n` +
100
+ `const changelogRawUrl = ${j(changelogRawUrl)};\n` +
101
+ `const cacheSlug = ${j(cacheSlug)};\n` +
102
+ `const updateCacheFileName = ${j(updateCacheFileName)};\n\n` +
103
+ `${formatManualInstall.toString()}\n\n` +
104
+ 'function manualInstallCommand(opts = {}) {\n' +
105
+ ' return formatManualInstall({ packageName, binName, scope: opts.scope, runtime: opts.runtime });\n' +
106
+ '}\n\n' +
107
+ 'module.exports = Object.freeze({\n' +
108
+ ' packageName,\n' +
109
+ ' // PACKAGE_NAME: back-compat alias for #516-era consumers. Baked here, so it\n' +
110
+ " // survives the installed tree's synthetic package.json (fixes the #378 undefined).\n" +
111
+ ' PACKAGE_NAME: packageName,\n' +
112
+ ' binName,\n' +
113
+ ' repoSlug,\n' +
114
+ ' repoUrl,\n' +
115
+ ' changelogRawUrl,\n' +
116
+ ' cacheSlug,\n' +
117
+ ' updateCacheFileName,\n' +
118
+ ' manualInstallCommand,\n' +
119
+ '});\n'
120
+ );
121
+ }
122
+
123
+ function main() {
124
+ const fs = require('node:fs');
125
+ const path = require('node:path');
126
+ const pkg = require(path.join(__dirname, '..', 'package.json'));
127
+ const out = path.join(__dirname, '..', 'pp-core', 'bin', 'lib', 'package-identity.cjs');
128
+ fs.writeFileSync(out, render(deriveIdentity(pkg)));
129
+ process.stdout.write(`wrote ${path.relative(path.join(__dirname, '..'), out)}\n`);
130
+ }
131
+
132
+ if (require.main === module) main();
133
+
134
+ module.exports = { deriveIdentity, parseRepoSlug, slugifyPackageName, formatManualInstall, render, main };
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Constants
6
+ // ---------------------------------------------------------------------------
7
+
8
+ const POSSIBLE_DUPLICATE_LABEL = 'possible-duplicate';
9
+ const HUMAN_REVIEW_LABEL = 'needs-maintainer-review';
10
+ const CHALLENGE_MARKER = '<!-- gsd-dedupe-challenge -->';
11
+ const DEFAULT_WINDOW_HOURS = 24;
12
+ const DEFAULT_THRESHOLD = 0.6;
13
+ const DEFAULT_MAX_CANDIDATES = 5;
14
+ const MIN_TOKEN_LENGTH = 3;
15
+
16
+ const EXEMPT_LABELS = [
17
+ 'priority: critical',
18
+ 'pinned',
19
+ 'confirmed-bug',
20
+ 'confirmed',
21
+ 'fix-pending',
22
+ 'needs-maintainer-review',
23
+ ];
24
+
25
+ const STOPWORDS = new Set([
26
+ 'the', 'a', 'an', 'and', 'or', 'but', 'if', 'then', 'is', 'are', 'was',
27
+ 'be', 'to', 'of', 'in', 'on', 'for', 'with', 'as', 'at', 'by', 'from',
28
+ 'this', 'that', 'it', 'its', 'not', 'no', 'when', 'what', 'why', 'how',
29
+ 'does', 'do', 'doing', 'did', 'can', 'will', 'would', 'should',
30
+ 'i', 'we', 'you', 'your', 'my', 'me',
31
+ 'issue', 'bug', 'error', 'problem', 'feature', 'request',
32
+ 'help', 'support', 'please', 'question',
33
+ 'after', 'before', 'into', 'only', 'then', 'than', 'them', 'they',
34
+ 'use', 'used', 'using',
35
+ ]);
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // tokenize(title) -> string[]
39
+ //
40
+ // Lowercase the title, replace any non-[a-z0-9] run with a space, split on
41
+ // whitespace, drop tokens shorter than MIN_TOKEN_LENGTH, drop STOPWORDS, and
42
+ // dedupe while preserving stable first-occurrence order.
43
+ //
44
+ // Non-string, null, or empty input returns []. Must not throw on any input.
45
+ // ---------------------------------------------------------------------------
46
+
47
+ function tokenize(title) {
48
+ if (typeof title !== 'string' || !title) return [];
49
+
50
+ const normalized = title.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
51
+ if (!normalized) return [];
52
+
53
+ const seen = new Set();
54
+ const result = [];
55
+
56
+ for (const token of normalized.split(' ')) {
57
+ if (!token || token.length < MIN_TOKEN_LENGTH) continue;
58
+ if (STOPWORDS.has(token)) continue;
59
+ if (seen.has(token)) continue;
60
+ seen.add(token);
61
+ result.push(token);
62
+ }
63
+
64
+ return result;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // diceSimilarity(aTokens, bTokens) -> number 0..1
69
+ //
70
+ // Sørensen–Dice over the token sets: 2 * |A ∩ B| / (|A| + |B|).
71
+ // Both inputs are treated as sets (duplicates ignored). Empty either side -> 0.
72
+ // Identical sets -> 1.
73
+ // ---------------------------------------------------------------------------
74
+
75
+ function diceSimilarity(aTokens, bTokens) {
76
+ const setA = new Set(aTokens);
77
+ const setB = new Set(bTokens);
78
+
79
+ if (setA.size === 0 || setB.size === 0) return 0;
80
+
81
+ let intersection = 0;
82
+ for (const token of setA) {
83
+ if (setB.has(token)) intersection += 1;
84
+ }
85
+
86
+ return (2 * intersection) / (setA.size + setB.size);
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // scoreCandidates(newTitle, candidates, opts) -> [{number, title, score}]
91
+ //
92
+ // opts: { threshold=DEFAULT_THRESHOLD, limit=DEFAULT_MAX_CANDIDATES, excludeNumber }
93
+ //
94
+ // Tokenizes newTitle once. If no tokens -> []. Filters out null/garbage
95
+ // candidates, those missing a number, and the excluded number. Scores each
96
+ // using diceSimilarity. Keeps score >= threshold. Sorts DESC by score,
97
+ // tie-break ASC by number. Caps to limit.
98
+ // ---------------------------------------------------------------------------
99
+
100
+ function scoreCandidates(newTitle, candidates, opts) {
101
+ const threshold = (opts && opts.threshold != null) ? opts.threshold : DEFAULT_THRESHOLD;
102
+ const limit = (opts && opts.limit != null) ? opts.limit : DEFAULT_MAX_CANDIDATES;
103
+ const excludeNumber = opts && opts.excludeNumber;
104
+
105
+ const newTokens = tokenize(newTitle);
106
+ if (newTokens.length === 0) return [];
107
+
108
+ const scored = [];
109
+
110
+ const safeCandidates = Array.isArray(candidates) ? candidates : [];
111
+ for (const candidate of safeCandidates) {
112
+ if (!candidate || typeof candidate !== 'object') continue;
113
+ if (!(typeof candidate.number === 'number' && Number.isFinite(candidate.number))) continue;
114
+ if (candidate.number === excludeNumber) continue;
115
+
116
+ const score = diceSimilarity(newTokens, tokenize(candidate.title));
117
+ if (score < threshold) continue;
118
+
119
+ scored.push({ number: candidate.number, title: candidate.title, score });
120
+ }
121
+
122
+ scored.sort((a, b) => {
123
+ if (Math.abs(a.score - b.score) > 1e-9) return b.score - a.score;
124
+ return a.number - b.number;
125
+ });
126
+
127
+ return scored.slice(0, limit);
128
+ }
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // renderChallengeComment(candidates, opts) -> string
132
+ //
133
+ // opts: { windowHours=DEFAULT_WINDOW_HOURS }
134
+ //
135
+ // Deterministic. Must start with CHALLENGE_MARKER on its own line. Must list
136
+ // each candidate as a line with #<number>, title, and percentage similarity.
137
+ // Must mention windowHours and the 👎 veto.
138
+ // ---------------------------------------------------------------------------
139
+
140
+ function renderChallengeComment(candidates, opts) {
141
+ const windowHours = (opts && opts.windowHours != null) ? opts.windowHours : DEFAULT_WINDOW_HOURS;
142
+
143
+ const lines = [CHALLENGE_MARKER, ''];
144
+
145
+ lines.push('**Possible duplicate detected.** This issue may already be reported:');
146
+ lines.push('');
147
+
148
+ for (const candidate of candidates) {
149
+ const pct = Math.round(candidate.score * 100);
150
+ lines.push(`- #${candidate.number} — ${candidate.title} (similarity ${pct}%)`);
151
+ }
152
+
153
+ lines.push('');
154
+ lines.push(
155
+ `If this is **not** a duplicate, react with 👎 on this comment to veto and keep the issue open. ` +
156
+ `If no response is received within ${windowHours} hours, this issue may be closed as a duplicate.`,
157
+ );
158
+
159
+ return lines.join('\n');
160
+ }
161
+
162
+ // ---------------------------------------------------------------------------
163
+ // isChallengeComment(body) -> boolean
164
+ //
165
+ // True iff body is a string containing CHALLENGE_MARKER.
166
+ // ---------------------------------------------------------------------------
167
+
168
+ function isChallengeComment(body) {
169
+ if (typeof body !== 'string') return false;
170
+ return body.includes(CHALLENGE_MARKER);
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // hasExemptLabel(labels) -> boolean
175
+ //
176
+ // labels may be an array of strings or array of {name}. True if any name is
177
+ // in EXEMPT_LABELS.
178
+ // ---------------------------------------------------------------------------
179
+
180
+ function hasExemptLabel(labels) {
181
+ if (!Array.isArray(labels)) return false;
182
+ const exemptSet = new Set(EXEMPT_LABELS);
183
+ for (const label of labels) {
184
+ const name = typeof label === 'string' ? label : (label && label.name);
185
+ if (name && exemptSet.has(name)) return true;
186
+ }
187
+ return false;
188
+ }
189
+
190
+ // ---------------------------------------------------------------------------
191
+ // toMs(value) -> number
192
+ //
193
+ // Coerce a Date, ISO string, or ms-number to milliseconds since epoch.
194
+ // ---------------------------------------------------------------------------
195
+
196
+ function toMs(value) {
197
+ if (value instanceof Date) return value.getTime();
198
+ if (typeof value === 'string') return new Date(value).getTime();
199
+ return Number(value);
200
+ }
201
+
202
+ // ---------------------------------------------------------------------------
203
+ // shouldClose(input) -> {close: boolean, reason: string}
204
+ //
205
+ // input: { now, labels, challengeComment, laterUserComments, windowHours=DEFAULT_WINDOW_HOURS }
206
+ //
207
+ // Decision order (returns first match):
208
+ // 1. hasExemptLabel(labels) -> {close:false, reason:'exempt-label'}
209
+ // 2. !challengeComment -> {close:false, reason:'no-challenge-comment'}
210
+ // 3. challengeComment.downvoted -> {close:false, reason:'vetoed'}
211
+ // 4. laterUserComments > 0 -> {close:false, reason:'reporter-responded'}
212
+ // 5. ageHours < windowHours -> {close:false, reason:'within-window'}
213
+ // 6. else -> {close:true, reason:'duplicate-no-response'}
214
+ // ---------------------------------------------------------------------------
215
+
216
+ function shouldClose(input) {
217
+ const {
218
+ now,
219
+ labels = [],
220
+ challengeComment,
221
+ laterUserComments = 0,
222
+ } = input;
223
+ const windowHours = (input.windowHours != null) ? input.windowHours : DEFAULT_WINDOW_HOURS;
224
+
225
+ if (hasExemptLabel(labels)) {
226
+ return { close: false, reason: 'exempt-label' };
227
+ }
228
+
229
+ if (!challengeComment) {
230
+ return { close: false, reason: 'no-challenge-comment' };
231
+ }
232
+
233
+ if (challengeComment.downvoted) {
234
+ return { close: false, reason: 'vetoed' };
235
+ }
236
+
237
+ if (laterUserComments > 0) {
238
+ return { close: false, reason: 'reporter-responded' };
239
+ }
240
+
241
+ const nowMs = toMs(now);
242
+ const createdMs = toMs(challengeComment.createdAt);
243
+
244
+ if (!Number.isFinite(nowMs) || !Number.isFinite(createdMs)) {
245
+ return { close: false, reason: 'invalid-timestamp' };
246
+ }
247
+
248
+ const ageHours = (nowMs - createdMs) / 3600000;
249
+
250
+ if (ageHours < windowHours) {
251
+ return { close: false, reason: 'within-window' };
252
+ }
253
+
254
+ return { close: true, reason: 'duplicate-no-response' };
255
+ }
256
+
257
+ // ---------------------------------------------------------------------------
258
+ // Exports
259
+ // ---------------------------------------------------------------------------
260
+
261
+ module.exports = {
262
+ POSSIBLE_DUPLICATE_LABEL,
263
+ HUMAN_REVIEW_LABEL,
264
+ CHALLENGE_MARKER,
265
+ DEFAULT_WINDOW_HOURS,
266
+ DEFAULT_THRESHOLD,
267
+ DEFAULT_MAX_CANDIDATES,
268
+ MIN_TOKEN_LENGTH,
269
+ EXEMPT_LABELS,
270
+ STOPWORDS,
271
+ tokenize,
272
+ diceSimilarity,
273
+ scoreCandidates,
274
+ renderChallengeComment,
275
+ isChallengeComment,
276
+ hasExemptLabel,
277
+ shouldClose,
278
+ };