@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,763 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/release-tarball-smoke.cjs
4
+ *
5
+ * Release tarball smoke test for issue #3686.
6
+ *
7
+ * Guards against the class of bugs that can't be caught by working-tree tests:
8
+ * - #3684: maskIfSecret import/export mismatch shipped in v1.42.3 (runtime
9
+ * crash on installed package, invisible to unit tests)
10
+ *
11
+ * Strategy: pack the working tree, install into a temp prefix, invoke the
12
+ * installed binary, assert the version matches package.json. Exercises the
13
+ * INSTALLED package, not the working tree.
14
+ *
15
+ * Exports:
16
+ * SMOKE — frozen enum of result codes
17
+ * runSmoke({ tarballPath, installPrefix, expectedVersion, fixtureDir,
18
+ * lifecycleCommands, dryRun })
19
+ * → { code: SMOKE.*, details: { version, tarball, ... } }
20
+ *
21
+ * CLI entry: node scripts/release-tarball-smoke.cjs --json
22
+ * Packs working tree, installs to a temp prefix, checks version.
23
+ * Exits 0 on SMOKE.OK, 1 otherwise.
24
+ * Always prints JSON to stdout when --json flag is present.
25
+ *
26
+ * Lifecycle command checks (Cycle 2):
27
+ * For each command name (other than 'init') in lifecycleCommands:
28
+ * - Assert commands/pp-<cmd>.md exists in the installed package
29
+ * (D-12 flat-hyphen namespace; replaced the legacy commands/gsd/<cmd>.md)
30
+ * - Parse the .md for a workflow @-import or inline reference
31
+ * - Assert the referenced workflow .md exists in the installed package
32
+ * If 'init' is in lifecycleCommands, runs 'pp-core --local --claude'
33
+ * in fixtureDir to verify the installer is callable (INIT_FAILED on crash).
34
+ * Non-interactive: --local --claude flags skip all prompts.
35
+ *
36
+ * Workflow-body checks (Cycle 3 — informational):
37
+ * - Scans all installed pp-core/workflows/*.md for /gsd:<known-cmd>
38
+ * colon-namespace leaks (WORKFLOW_BODY_COLON_LEAK).
39
+ * This check populates result.details with counters but does NOT return a
40
+ * failure code by default; it is informational until enforcement is enabled.
41
+ */
42
+
43
+ 'use strict';
44
+
45
+ const { execFileSync, spawnSync } = require('child_process');
46
+ const fs = require('fs');
47
+ const os = require('os');
48
+ const path = require('path');
49
+ const { PACKAGE_NAME } = require('../pp-core/bin/lib/package-identity.cjs');
50
+ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
51
+ // 120 s proved too tight on Windows GitHub-hosted runners: cold-cache
52
+ // `npm install -g` with a 1499-file tarball took ~120 s exactly, causing
53
+ // spawnSync to fire SIGTERM and return { status: null, stdout: '', stderr: '' }
54
+ // (Node docs: status is null when subprocess terminated due to a signal).
55
+ // The INSTALL_FAILED branch checks `status !== 0`, which null satisfies, so the
56
+ // test saw empty stdout/stderr and a spurious INSTALL_FAILED. Windows runners
57
+ // are slower than Linux/macOS for filesystem-heavy operations (
58
+ // https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
59
+ // ). Raise to 600 s (the same ceiling the before() helper uses for pack+install).
60
+ const CHILD_TIMEOUT_MS = process.platform === 'win32' ? 600_000 : 120_000;
61
+ const QUIET_NPM_ENV = Object.freeze({
62
+ npm_config_loglevel: 'error',
63
+ npm_config_update_notifier: 'false',
64
+ NO_UPDATE_NOTIFIER: '1',
65
+ });
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Frozen result-code enum
69
+ // ---------------------------------------------------------------------------
70
+
71
+ const SMOKE = Object.freeze({
72
+ OK: 'ok',
73
+ VERSION_MISMATCH: 'version_mismatch',
74
+ PACK_FAILED: 'pack_failed',
75
+ INSTALL_FAILED: 'install_failed',
76
+ BIN_NOT_CALLABLE: 'bin_not_callable',
77
+ // Cycle 2 codes
78
+ COMMAND_FILE_MISSING: 'command_file_missing',
79
+ WORKFLOW_FILE_MISSING: 'workflow_file_missing',
80
+ INIT_FAILED: 'init_failed',
81
+ // Cycle 3 code
82
+ WORKFLOW_BODY_COLON_LEAK: 'workflow_body_colon_leak',
83
+ });
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Exported helper: binInvocation
87
+ // ---------------------------------------------------------------------------
88
+
89
+ /**
90
+ * Build the { command, args, shell } descriptor needed to spawn an installed
91
+ * npm bin correctly on both Windows and POSIX.
92
+ *
93
+ * On Windows, npm installs a `.cmd` (or `.bat`) shim in .bin/. Node ≥18.20.2
94
+ * / ≥20.12.2 throws EINVAL when you try to spawnSync a .cmd/.bat without
95
+ * shell:true (CVE-2024-27980 mitigation). With shell:true, Node does NOT
96
+ * auto-quote argv, so a bin path that contains spaces must be wrapped in
97
+ * double-quotes to arrive at the shell as one token.
98
+ *
99
+ * On POSIX the bin is a regular shebang JS file; we invoke it directly via
100
+ * process.execPath (the same Node binary) without a shell.
101
+ *
102
+ * @param {string} binPath - Absolute path to the resolved bin file.
103
+ * @param {string[]} [args] - Additional arguments (e.g. ['--help']).
104
+ * @returns {{ command: string, args: string[], shell: boolean }}
105
+ */
106
+ function binInvocation(binPath, args = []) {
107
+ const lower = binPath.toLowerCase();
108
+ // Note: .ps1 shims are intentionally NOT handled here. The bin-resolution
109
+ // helpers (findGsdToolsBin / findInstallerBin) only ever surface a .cmd path
110
+ // on Windows — npm does not write .ps1 shims into .bin/ by default — so a
111
+ // .ps1 path never reaches this function in practice.
112
+ if (lower.endsWith('.cmd') || lower.endsWith('.bat')) {
113
+ // Quote the path if it contains a space so the Windows shell treats it as
114
+ // a single token. Simple double-quote wrap is sufficient because npm-
115
+ // generated shim paths don't contain embedded double-quotes.
116
+ const command = binPath.includes(' ') ? `"${binPath}"` : binPath;
117
+ return { command, args: [...args], shell: true };
118
+ }
119
+ // POSIX: invoke via node, no shell needed.
120
+ return { command: process.execPath, args: [binPath, ...args], shell: false };
121
+ }
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // Internal helpers
125
+ // ---------------------------------------------------------------------------
126
+
127
+ /**
128
+ * Locate the lib/node_modules/@opengsd/pp-core package root inside
129
+ * an npm --prefix install directory.
130
+ */
131
+ function pkgRoot(installPrefix) {
132
+ // POSIX: <prefix>/lib/node_modules/<scope>/<pkg>
133
+ // Windows: <prefix>/node_modules/<scope>/<pkg>
134
+ // PACKAGE_NAME is scoped (@scope/pkg), so split('/') yields the two path segments.
135
+ const pkgSegments = PACKAGE_NAME.split('/');
136
+ const posix = path.join(installPrefix, 'lib', 'node_modules', ...pkgSegments);
137
+ const win = path.join(installPrefix, 'node_modules', ...pkgSegments);
138
+ return fs.existsSync(posix) ? posix : win;
139
+ }
140
+
141
+ /**
142
+ * Return the ordered list of candidate paths to check when locating an npm
143
+ * global bin named `name` under `installPrefix`.
144
+ *
145
+ * On Windows, `npm install -g --prefix X` writes shims (*.cmd, *.ps1, bare)
146
+ * to the PREFIX ROOT (X\), NOT to X\node_modules\.bin\. We therefore probe
147
+ * the prefix root first, then fall back to node_modules\.bin in case a
148
+ * non-standard layout puts them there.
149
+ *
150
+ * On POSIX the shim lands in <prefix>/bin/ as a symlink; only one candidate.
151
+ */
152
+ function binCandidates(installPrefix, name) {
153
+ if (process.platform === 'win32') {
154
+ return [
155
+ // npm global --prefix on Windows writes shims to the prefix ROOT
156
+ path.join(installPrefix, `${name}.cmd`),
157
+ path.join(installPrefix, name),
158
+ // fallback: some layouts use node_modules/.bin
159
+ path.join(installPrefix, 'node_modules', '.bin', `${name}.cmd`),
160
+ path.join(installPrefix, 'node_modules', '.bin', name),
161
+ ];
162
+ }
163
+ return [path.join(installPrefix, 'bin', name)];
164
+ }
165
+
166
+ /**
167
+ * Locate the installed pp-tools binary (symlink in <prefix>/bin/).
168
+ */
169
+ function findGsdToolsBin(installPrefix) {
170
+ for (const c of binCandidates(installPrefix, 'pp-tools')) {
171
+ if (fs.existsSync(c)) return c;
172
+ }
173
+ return null;
174
+ }
175
+
176
+ /**
177
+ * Locate the pp-core installer binary (the symlink in <prefix>/bin/).
178
+ */
179
+ function findInstallerBin(installPrefix) {
180
+ for (const c of binCandidates(installPrefix, 'pp-core')) {
181
+ if (fs.existsSync(c)) return c;
182
+ }
183
+ return null;
184
+ }
185
+
186
+ // ---------------------------------------------------------------------------
187
+ // Install-probe machinery (05-05 Task 2 — D-09/D-10/D-11; INST-01/02/03/04)
188
+ // ---------------------------------------------------------------------------
189
+
190
+ /**
191
+ * The runtime flags the installer accepts, mirroring `selectRuntimesFromArgs`
192
+ * in bin/install.js (the `--all` set). Used to parametrize the non-gating
193
+ * runtime matrix (D-11). `claude` is the only launch-gating runtime; every
194
+ * other entry is best-effort and recorded, not asserted.
195
+ */
196
+ const RUNTIME_FLAGS = Object.freeze([
197
+ 'claude', 'kimi', 'kilo', 'opencode', 'gemini', 'codex', 'copilot', 'antigravity',
198
+ 'cursor', 'windsurf', 'augment', 'trae', 'qwen', 'hermes', 'codebuddy', 'cline',
199
+ ]);
200
+
201
+ /**
202
+ * Locate the installed `progress` command artifact under a runtime config root,
203
+ * tolerant of the per-scope layout asymmetry that 05-04 (D-12 flat-hyphen)
204
+ * produced:
205
+ * - Claude LOCAL → commands/pp-progress.md (flat-hyphen slash command)
206
+ * - Claude GLOBAL → skills/pp-progress/SKILL.md (skill surface)
207
+ * - (subdir form) → commands/pp/progress.md (defensive; not currently emitted)
208
+ *
209
+ * "Lands under the pp namespace" means the `pp-` prefixed artifact exists in any
210
+ * of these forms — the namespace is the `pp-` prefix, not a specific directory.
211
+ *
212
+ * @param {string} configRoot - The runtime config root the installer wrote into
213
+ * (e.g. <fixture>/.claude for --local, or the --config-dir value for --global).
214
+ * @returns {{ kind: string, path: string } | null}
215
+ */
216
+ function locateProgressArtifact(configRoot) {
217
+ const candidates = [
218
+ { kind: 'command-flat', path: path.join(configRoot, 'commands', 'pp-progress.md') },
219
+ { kind: 'command-subdir', path: path.join(configRoot, 'commands', 'pp', 'progress.md') },
220
+ { kind: 'skill', path: path.join(configRoot, 'skills', 'pp-progress', 'SKILL.md') },
221
+ ];
222
+ for (const c of candidates) {
223
+ if (fs.existsSync(c.path)) return c;
224
+ }
225
+ return null;
226
+ }
227
+
228
+ /**
229
+ * Locate any *legacy gsd-namespaced* progress artifact under a config root. Used
230
+ * to assert the remediated installer does NOT surface the old `gsd` namespace
231
+ * for its own progress command (INST-01). Returns the first found path or null.
232
+ *
233
+ * @param {string} configRoot
234
+ * @returns {string | null}
235
+ */
236
+ function locateLegacyGsdProgress(configRoot) {
237
+ const candidates = [
238
+ path.join(configRoot, 'commands', 'gsd', 'progress.md'),
239
+ path.join(configRoot, 'skills', 'gsd', 'progress', 'SKILL.md'),
240
+ path.join(configRoot, 'skills', 'gsd-progress', 'SKILL.md'),
241
+ ];
242
+ return candidates.find((p) => fs.existsSync(p)) || null;
243
+ }
244
+
245
+ /**
246
+ * Drive the INSTALLED pp-core installer bin (clean-room) with arbitrary flags,
247
+ * optionally pre-seeding sentinel files into the config root first (for the
248
+ * INST-04 coexistence probe). GSD_TEST_MODE is always stripped from the child
249
+ * env — install.js short-circuits its main() block when it is set, which would
250
+ * make the installer exit 0 without writing anything.
251
+ *
252
+ * @param {object} opts
253
+ * @param {string} opts.installPrefix - npm --prefix dir holding the installed pp-core bin.
254
+ * @param {string[]} opts.flags - Installer flags (e.g. ['--local','--claude']).
255
+ * @param {string} opts.cwd - Working dir to spawn the installer in.
256
+ * @param {string} opts.configRoot - Where artifacts land / where preseed files go.
257
+ * @param {Array<{relPath: string, content: string}>} [opts.preseed] - Sentinels to write
258
+ * under configRoot BEFORE the install (relative paths).
259
+ * @param {object} [opts.env] - Base env (HOME isolation etc.); GSD_TEST_MODE stripped.
260
+ * @returns {{ ok: boolean, status: number|null, stdout: string, stderr: string,
261
+ * signal: string|null, reason?: string, installerBin?: string }}
262
+ */
263
+ function driveInstaller({ installPrefix, flags, cwd, configRoot, preseed = [], env }) {
264
+ const installerBin = findInstallerBin(installPrefix);
265
+ if (!installerBin) {
266
+ return { ok: false, status: null, stdout: '', stderr: '', signal: null, reason: 'installer-bin-not-found' };
267
+ }
268
+
269
+ for (const { relPath, content } of preseed) {
270
+ const target = path.join(configRoot, relPath);
271
+ fs.mkdirSync(path.dirname(target), { recursive: true });
272
+ fs.writeFileSync(target, content);
273
+ }
274
+
275
+ const childEnv = { ...(env !== undefined ? env : process.env) };
276
+ delete childEnv.GSD_TEST_MODE;
277
+
278
+ const inv = binInvocation(installerBin, flags);
279
+ const res = spawnSync(inv.command, inv.args, {
280
+ encoding: 'utf-8',
281
+ cwd,
282
+ stdio: ['pipe', 'pipe', 'pipe'],
283
+ env: childEnv,
284
+ timeout: CHILD_TIMEOUT_MS,
285
+ shell: inv.shell,
286
+ });
287
+
288
+ return {
289
+ ok: res.status === 0,
290
+ status: res.status,
291
+ stdout: res.stdout || '',
292
+ stderr: res.stderr || '',
293
+ signal: res.signal ?? null,
294
+ installerBin,
295
+ };
296
+ }
297
+
298
+ /**
299
+ * Parse a command .md file and return the first workflow path it references.
300
+ *
301
+ * Structured parser — only inspects individual lines; never regexes on the
302
+ * whole-file string. Two recognised forms (in priority order):
303
+ *
304
+ * 1. @-import line: `@~/.claude/pp-core/workflows/<name>.md`
305
+ * 2. Inline mention: any line containing `~/.claude/pp-core/workflows/<name>.md`
306
+ * (takes the LAST occurrence so conditional-dispatch files resolve to the
307
+ * default / unconditional branch, e.g. discuss-phase.md)
308
+ *
309
+ * Returns the bare workflow filename (e.g. `"discuss-phase.md"`) or null.
310
+ */
311
+ function parseWorkflowRef(mdContent) {
312
+ const WORKFLOW_PREFIX = 'pp-core/workflows/';
313
+ let atImportResult = null;
314
+ let lastInlineResult = null;
315
+
316
+ const lines = mdContent.split(/\r?\n/);
317
+ for (const line of lines) {
318
+ const trimmed = line.trim();
319
+
320
+ // Form 1: @-import
321
+ if (trimmed.startsWith('@') && trimmed.includes(WORKFLOW_PREFIX)) {
322
+ const idx = trimmed.indexOf(WORKFLOW_PREFIX);
323
+ const rest = trimmed.slice(idx + WORKFLOW_PREFIX.length);
324
+ // rest is like "discuss-phase.md" or "discuss-phase.md end-to-end."
325
+ const name = rest.split(/[\s`"]/)[0];
326
+ if (name.endsWith('.md')) {
327
+ atImportResult = name;
328
+ break; // @-imports are authoritative; stop on first
329
+ }
330
+ }
331
+
332
+ // Form 2: inline mention (collect last)
333
+ if (trimmed.includes(WORKFLOW_PREFIX)) {
334
+ const idx = trimmed.indexOf(WORKFLOW_PREFIX);
335
+ const rest = trimmed.slice(idx + WORKFLOW_PREFIX.length);
336
+ const name = rest.split(/[\s`"]/)[0];
337
+ if (name.endsWith('.md')) {
338
+ lastInlineResult = name;
339
+ }
340
+ }
341
+ }
342
+
343
+ return atImportResult !== null ? atImportResult : lastInlineResult;
344
+ }
345
+
346
+ /**
347
+ * Read the list of known GSD command names from the installed package.
348
+ * Returns an array of strings like `['init', 'discuss-phase', ...]`.
349
+ */
350
+ function readInstalledCmdNames(pkg) {
351
+ // D-12 flat-hyphen: command files live at commands/pp-<cmd>.md (the legacy
352
+ // commands/gsd/ subdir was removed in 05-04). Read the flat dir, keep only the
353
+ // pp-prefixed command files, and return the BARE command name (strip 'pp-' and
354
+ // '.md') so the colon-leak scan still matches /gsd:<cmd> on the bare stem.
355
+ const commandsDir = path.join(pkg, 'commands');
356
+ if (!fs.existsSync(commandsDir)) return [];
357
+ return fs.readdirSync(commandsDir)
358
+ .filter((f) => f.startsWith('pp-') && f.endsWith('.md'))
359
+ .map((f) => f.slice(3, -3)); // strip leading 'pp-' and trailing '.md'
360
+ }
361
+
362
+ /**
363
+ * Scan a single workflow .md file for /gsd:<cmd> colon-namespace leaks.
364
+ *
365
+ * Uses the word-boundary-safe regex shape from scripts/fix-slash-commands.cjs:
366
+ * /gsd-(<cmd1>|<cmd2>|...)(?=[^a-zA-Z0-9_-]|$)/g — forward
367
+ * We check the colon form: /gsd:<cmd> leaking in installed workflow bodies.
368
+ *
369
+ * Returns the first leaking { line, lineNumber } or null.
370
+ */
371
+ function scanWorkflowColonLeak(filePath, cmdNames) {
372
+ if (!cmdNames || cmdNames.length === 0) return null;
373
+ const sorted = [...cmdNames].sort((a, b) => b.length - a.length);
374
+ const pattern = new RegExp(`/gsd:(${sorted.join('|')})(?=[^a-zA-Z0-9_-]|$)`, 'g');
375
+
376
+ const content = fs.readFileSync(filePath, 'utf-8');
377
+ const lines = content.split(/\r?\n/);
378
+ for (let i = 0; i < lines.length; i++) {
379
+ pattern.lastIndex = 0;
380
+ if (pattern.test(lines[i])) {
381
+ return { line: i + 1, content: lines[i].trim() };
382
+ }
383
+ }
384
+ return null;
385
+ }
386
+
387
+ // ---------------------------------------------------------------------------
388
+ // Pure function: runSmoke
389
+ // ---------------------------------------------------------------------------
390
+
391
+ /**
392
+ * @param {object} opts
393
+ * @param {string} opts.tarballPath - Absolute path to a pre-packed .tgz
394
+ * @param {string} opts.installPrefix - Temp directory to use as npm --prefix
395
+ * @param {string} opts.expectedVersion - semver string to assert (e.g. "1.50.0")
396
+ * @param {string} [opts.fixtureDir] - Temp dir to run `init` into (must NOT be HOME)
397
+ * @param {string[]} [opts.lifecycleCommands] - Commands to file-check (default: see below)
398
+ * @param {boolean} [opts.dryRun=false] - If true, skip actual npm install; validate input only
399
+ * @param {object} [opts.npmEnv] - Optional env dict for the internal npm install
400
+ * spawnSync call. Pass an isolated HOME env (e.g. from isolatedNpmEnv() in tests/helpers.cjs)
401
+ * to prevent npm from reading/writing the caller's $HOME — required on Docker hosts where HOME
402
+ * may be unwritable. Defaults to process.env. (#131)
403
+ * @returns {{ code: string, details: object }}
404
+ */
405
+ function runSmoke({
406
+ tarballPath,
407
+ installPrefix,
408
+ expectedVersion,
409
+ fixtureDir,
410
+ lifecycleCommands = ['init', 'discuss-phase', 'plan-phase', 'execute-phase'],
411
+ dryRun = false,
412
+ npmEnv = undefined,
413
+ }) {
414
+ const details = {
415
+ tarball: tarballPath,
416
+ prefix: installPrefix,
417
+ expectedVersion,
418
+ };
419
+
420
+ if (dryRun) {
421
+ return { code: SMOKE.OK, details: { ...details, version: expectedVersion, dryRun: true } };
422
+ }
423
+
424
+ // --- Install the tarball into the temp prefix ----------------------------
425
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
426
+ // Use the caller-supplied npmEnv if provided (allows HOME isolation on Docker
427
+ // hosts where HOME may be unwritable — same pattern as runNpm() in helpers.cjs).
428
+ // Falls back to process.env to preserve existing CLI / programmatic behaviour. (#131)
429
+ const effectiveNpmEnv = { ...(npmEnv !== undefined ? npmEnv : process.env), ...QUIET_NPM_ENV };
430
+ const installResult = spawnSync(
431
+ npmCmd,
432
+ ['install', '-g', '--prefix', installPrefix, tarballPath],
433
+ { encoding: 'utf-8', shell: process.platform === 'win32', timeout: CHILD_TIMEOUT_MS, env: effectiveNpmEnv },
434
+ );
435
+
436
+ if (installResult.status !== 0) {
437
+ return {
438
+ code: SMOKE.INSTALL_FAILED,
439
+ details: {
440
+ ...details,
441
+ stderr: installResult.stderr,
442
+ stdout: installResult.stdout,
443
+ // Expose signal + error so a timeout (status=null, signal='SIGTERM',
444
+ // stdout='', stderr='') is immediately diagnosable in CI logs.
445
+ signal: installResult.signal ?? null,
446
+ installError: installResult.error ? String(installResult.error) : null,
447
+ },
448
+ };
449
+ }
450
+
451
+ // --- Locate the installed pp-tools binary --------------------------------
452
+ const actualBin = findGsdToolsBin(installPrefix);
453
+
454
+ if (!actualBin) {
455
+ const searched = binCandidates(installPrefix, 'pp-tools');
456
+ return {
457
+ code: SMOKE.BIN_NOT_CALLABLE,
458
+ details: { ...details, searched },
459
+ };
460
+ }
461
+
462
+ // --- Invoke `pp-tools --help` to assert the shipped binary is callable ---
463
+ // Use effectiveNpmEnv so the installed binary sees an isolated HOME on Docker
464
+ // hosts where HOME may be unwritable (same isolation as the npm install). (#131)
465
+ const versionInvocation = binInvocation(actualBin, ['--help']);
466
+ const versionResult = spawnSync(
467
+ versionInvocation.command,
468
+ versionInvocation.args,
469
+ { encoding: 'utf-8', timeout: CHILD_TIMEOUT_MS, env: effectiveNpmEnv, shell: versionInvocation.shell },
470
+ );
471
+
472
+ if (versionResult.status !== 0) {
473
+ return {
474
+ code: SMOKE.BIN_NOT_CALLABLE,
475
+ details: {
476
+ ...details,
477
+ bin: actualBin,
478
+ stderr: versionResult.stderr,
479
+ stdout: versionResult.stdout,
480
+ },
481
+ };
482
+ }
483
+
484
+ // Source of truth for shipped version is the installed package.json.
485
+ const installedPkgPath = path.join(pkgRoot(installPrefix), 'package.json');
486
+ const installedPkg = JSON.parse(fs.readFileSync(installedPkgPath, 'utf-8'));
487
+ const installedVersion = String(installedPkg.version || '').trim();
488
+
489
+ details.version = installedVersion;
490
+ details.bin = actualBin;
491
+ details.installedPackageJson = installedPkgPath;
492
+
493
+ if (installedVersion !== expectedVersion) {
494
+ return {
495
+ code: SMOKE.VERSION_MISMATCH,
496
+ details: { ...details, installedVersion, expectedVersion },
497
+ };
498
+ }
499
+
500
+ // ─────────────────────────────────────────────────────────────────────────
501
+ // Cycle 2: lifecycle command file-resolution checks
502
+ // ─────────────────────────────────────────────────────────────────────────
503
+
504
+ const pkg = pkgRoot(installPrefix);
505
+ const shouldRunInit = lifecycleCommands.includes('init');
506
+ const commandsToCheck = lifecycleCommands.filter((c) => c !== 'init');
507
+
508
+ // --- Run init if requested -----------------------------------------------
509
+ if (shouldRunInit && fixtureDir) {
510
+ const installerBin = findInstallerBin(installPrefix);
511
+ if (!installerBin) {
512
+ return {
513
+ code: SMOKE.INIT_FAILED,
514
+ details: {
515
+ ...details,
516
+ reason: 'pp-core binary not found in installPrefix',
517
+ installPrefix,
518
+ },
519
+ };
520
+ }
521
+
522
+ // Non-interactive: --local --claude installs to .claude/ in cwd (fixtureDir).
523
+ // GSD_TEST_MODE must be cleared — install.js skips its main() block when
524
+ // GSD_TEST_MODE is set, which would cause the installer to exit 0 silently
525
+ // without actually creating any files.
526
+ const initEnv = { ...process.env };
527
+ delete initEnv.GSD_TEST_MODE;
528
+
529
+ const initInvocation = binInvocation(installerBin, ['--local', '--claude']);
530
+ const initResult = spawnSync(
531
+ initInvocation.command,
532
+ initInvocation.args,
533
+ {
534
+ encoding: 'utf-8',
535
+ cwd: fixtureDir,
536
+ // Ensure no TTY so the installer's non-interactive fallback fires
537
+ stdio: ['pipe', 'pipe', 'pipe'],
538
+ env: initEnv,
539
+ timeout: CHILD_TIMEOUT_MS,
540
+ shell: initInvocation.shell,
541
+ },
542
+ );
543
+
544
+ if (initResult.status !== 0) {
545
+ return {
546
+ code: SMOKE.INIT_FAILED,
547
+ details: {
548
+ ...details,
549
+ fixtureDir,
550
+ stderr: initResult.stderr,
551
+ stdout: initResult.stdout,
552
+ },
553
+ };
554
+ }
555
+
556
+ // Verify expected dirs were created
557
+ const expectedDirs = [
558
+ path.join(fixtureDir, '.claude', 'commands'),
559
+ path.join(fixtureDir, '.claude', 'pp-core'),
560
+ ];
561
+ for (const dir of expectedDirs) {
562
+ if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
563
+ return {
564
+ code: SMOKE.INIT_FAILED,
565
+ details: {
566
+ ...details,
567
+ fixtureDir,
568
+ reason: `expected dir not created: ${dir}`,
569
+ },
570
+ };
571
+ }
572
+ }
573
+ }
574
+
575
+ // --- Check command files and workflow references -------------------------
576
+ const lifecycleResolved = [];
577
+
578
+ for (const cmd of commandsToCheck) {
579
+ // D-12 flat-hyphen: commands/pp-<cmd>.md (was commands/gsd/<cmd>.md pre-05-04).
580
+ const cmdFilePath = path.join(pkg, 'commands', `pp-${cmd}.md`);
581
+
582
+ if (!fs.existsSync(cmdFilePath) || !fs.statSync(cmdFilePath).isFile()) {
583
+ return {
584
+ code: SMOKE.COMMAND_FILE_MISSING,
585
+ details: {
586
+ ...details,
587
+ command: cmd,
588
+ path: cmdFilePath,
589
+ },
590
+ };
591
+ }
592
+
593
+ // Parse workflow reference
594
+ const mdContent = fs.readFileSync(cmdFilePath, 'utf-8');
595
+ const workflowName = parseWorkflowRef(mdContent);
596
+
597
+ let workflowPath = null;
598
+ if (workflowName) {
599
+ // Workflow files live at pp-core/workflows/<name> in the package.
600
+ // Some live in subdirectories; try flat first then scan once.
601
+ const flat = path.join(pkg, 'pp-core', 'workflows', workflowName);
602
+ workflowPath = fs.existsSync(flat) ? flat : null;
603
+
604
+ if (!workflowPath) {
605
+ return {
606
+ code: SMOKE.WORKFLOW_FILE_MISSING,
607
+ details: {
608
+ ...details,
609
+ command: cmd,
610
+ path: flat,
611
+ },
612
+ };
613
+ }
614
+ }
615
+
616
+ lifecycleResolved.push({
617
+ command: cmd,
618
+ commandPath: cmdFilePath,
619
+ workflowPath,
620
+ });
621
+ }
622
+
623
+ details.lifecycleResolved = lifecycleResolved;
624
+
625
+ // ─────────────────────────────────────────────────────────────────────────
626
+ // Cycle 3: workflow-body validation (informational)
627
+ // ─────────────────────────────────────────────────────────────────────────
628
+
629
+ // --- Workflow-body checks (informational — #3668 not yet fixed) ----------
630
+ const workflowsDir = path.join(pkg, 'pp-core', 'workflows');
631
+ const installedCmdNames = readInstalledCmdNames(pkg);
632
+
633
+ let workflowsScanned = 0;
634
+ let colonLeakCount = 0;
635
+ // Store first finding for potential future enforcement mode.
636
+ let firstColonLeak = null;
637
+
638
+ if (fs.existsSync(workflowsDir)) {
639
+ // Collect all .md files (flat only — subdirs contain sub-workflows that
640
+ // follow the same contract, but the top-level .md files are the primary surface)
641
+ const entries = fs.readdirSync(workflowsDir, { withFileTypes: true });
642
+ for (const entry of entries) {
643
+ if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
644
+ const filePath = path.join(workflowsDir, entry.name);
645
+ workflowsScanned++;
646
+
647
+ const leak = scanWorkflowColonLeak(filePath, installedCmdNames);
648
+ if (leak) {
649
+ colonLeakCount++;
650
+ if (!firstColonLeak) {
651
+ firstColonLeak = { file: filePath, line: leak.line };
652
+ }
653
+ }
654
+
655
+ }
656
+ }
657
+
658
+ details.workflowsScanned = workflowsScanned;
659
+ details.colonLeakCount = colonLeakCount;
660
+ if (firstColonLeak) details.firstColonLeak = firstColonLeak;
661
+
662
+ // NOTE: colonLeakCount is informational here. Once the backlog is fixed,
663
+ // a future enforcement mode can fail on non-zero counts.
664
+
665
+ return { code: SMOKE.OK, details };
666
+ }
667
+
668
+ // ---------------------------------------------------------------------------
669
+ // CLI entry
670
+ // ---------------------------------------------------------------------------
671
+
672
+ function cliMain() {
673
+ const args = process.argv.slice(2);
674
+ const isJson = args.includes('--json');
675
+
676
+ const pkgPath = path.join(__dirname, '..', 'package.json');
677
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
678
+ const expectedVersion = process.env.SMOKE_FORCE_EXPECTED_VERSION || pkg.version;
679
+
680
+ // Pack the working tree into a temp directory
681
+ const packDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-smoke-pack-'));
682
+ const installPrefix = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-smoke-prefix-'));
683
+ const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-smoke-fixture-'));
684
+
685
+ let tarballPath;
686
+ try {
687
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
688
+ const packOutput = execFileSync(
689
+ npmCmd,
690
+ ['pack', '--pack-destination', packDir],
691
+ {
692
+ cwd: path.join(__dirname, '..'),
693
+ encoding: 'utf-8',
694
+ shell: process.platform === 'win32',
695
+ timeout: CHILD_TIMEOUT_MS,
696
+ env: { ...process.env, ...QUIET_NPM_ENV },
697
+ },
698
+ ).trim();
699
+ // npm pack outputs the filename on stdout (last line when verbose)
700
+ const lines = packOutput.split(/\r?\n/).filter(Boolean);
701
+ const tgzName = lines[lines.length - 1];
702
+ tarballPath = path.join(packDir, tgzName);
703
+ if (!fs.existsSync(tarballPath)) {
704
+ // npm 7+ may print just the filename without .tgz extension on some platforms
705
+ const found = fs.readdirSync(packDir).find((f) => f.endsWith('.tgz'));
706
+ if (found) {
707
+ tarballPath = path.join(packDir, found);
708
+ } else {
709
+ const result = {
710
+ code: SMOKE.PACK_FAILED,
711
+ details: { packDir, packOutput, reason: 'no .tgz in pack destination' },
712
+ };
713
+ if (isJson) process.stdout.write(JSON.stringify(result) + '\n');
714
+ cleanup(packDir, installPrefix, fixtureDir);
715
+ throw new ExitError(1);
716
+ }
717
+ }
718
+ } catch (err) {
719
+ if (err instanceof ExitError) throw err;
720
+ const result = {
721
+ code: SMOKE.PACK_FAILED,
722
+ details: { error: err.message, stderr: err.stderr },
723
+ };
724
+ if (isJson) process.stdout.write(JSON.stringify(result) + '\n');
725
+ cleanup(packDir, installPrefix, fixtureDir);
726
+ throw new ExitError(1);
727
+ }
728
+
729
+ const result = runSmoke({ tarballPath, installPrefix, expectedVersion, fixtureDir });
730
+ if (isJson) process.stdout.write(JSON.stringify(result) + '\n');
731
+ cleanup(packDir, installPrefix, fixtureDir);
732
+ return result.code === SMOKE.OK ? 0 : 1;
733
+ }
734
+
735
+ function cleanup(...dirs) {
736
+ for (const dir of dirs) {
737
+ try {
738
+ fs.rmSync(dir, { recursive: true, force: true });
739
+ } catch {
740
+ // best-effort
741
+ }
742
+ }
743
+ }
744
+
745
+ // ---------------------------------------------------------------------------
746
+ // Exports
747
+ // ---------------------------------------------------------------------------
748
+
749
+ module.exports = {
750
+ SMOKE,
751
+ runSmoke,
752
+ binInvocation,
753
+ // 05-05 Task 2 install-probe surface
754
+ RUNTIME_FLAGS,
755
+ locateProgressArtifact,
756
+ locateLegacyGsdProgress,
757
+ driveInstaller,
758
+ findInstallerBin,
759
+ };
760
+
761
+ if (require.main === module) {
762
+ runMain(cliMain);
763
+ }