@opengsd/gsd-core 1.2.0 → 1.3.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 (532) hide show
  1. package/README.ja-JP.md +46 -791
  2. package/README.ko-KR.md +44 -780
  3. package/README.md +42 -218
  4. package/README.pt-BR.md +47 -414
  5. package/README.zh-CN.md +46 -763
  6. package/agents/gsd-ai-researcher.md +2 -2
  7. package/agents/gsd-debug-session-manager.md +1 -1
  8. package/agents/gsd-debugger.md +8 -8
  9. package/agents/gsd-doc-writer.md +7 -6
  10. package/agents/gsd-domain-researcher.md +15 -2
  11. package/agents/gsd-eval-auditor.md +1 -1
  12. package/agents/gsd-eval-planner.md +2 -2
  13. package/agents/gsd-executor.md +21 -8
  14. package/agents/gsd-framework-selector.md +1 -1
  15. package/agents/gsd-intel-updater.md +4 -4
  16. package/agents/gsd-phase-researcher.md +19 -6
  17. package/agents/gsd-plan-checker.md +3 -3
  18. package/agents/gsd-planner.md +36 -23
  19. package/agents/gsd-project-researcher.md +13 -0
  20. package/agents/gsd-research-synthesizer.md +6 -2
  21. package/agents/gsd-roadmapper.md +6 -6
  22. package/agents/gsd-ui-researcher.md +16 -3
  23. package/agents/gsd-user-profiler.md +2 -2
  24. package/agents/gsd-verifier.md +8 -8
  25. package/assets/gsd-logo-2000-transparent.png +0 -0
  26. package/assets/gsd-logo-2000-transparent.svg +17 -0
  27. package/assets/gsd-logo-2000.png +0 -0
  28. package/assets/gsd-logo-2000.svg +21 -0
  29. package/assets/terminal.svg +68 -0
  30. package/bin/install.js +255 -103
  31. package/commands/gsd/add-tests.md +1 -1
  32. package/commands/gsd/ai-integration-phase.md +3 -3
  33. package/commands/gsd/audit-fix.md +1 -1
  34. package/commands/gsd/audit-milestone.md +1 -1
  35. package/commands/gsd/audit-uat.md +1 -1
  36. package/commands/gsd/autonomous.md +2 -2
  37. package/commands/gsd/capture.md +6 -6
  38. package/commands/gsd/cleanup.md +1 -1
  39. package/commands/gsd/code-review.md +1 -1
  40. package/commands/gsd/complete-milestone.md +2 -2
  41. package/commands/gsd/config.md +3 -3
  42. package/commands/gsd/debug.md +1 -1
  43. package/commands/gsd/discuss-phase.md +5 -4
  44. package/commands/gsd/docs-update.md +1 -1
  45. package/commands/gsd/eval-review.md +2 -2
  46. package/commands/gsd/execute-phase.md +2 -2
  47. package/commands/gsd/explore.md +1 -1
  48. package/commands/gsd/extract-learnings.md +2 -2
  49. package/commands/gsd/fast.md +1 -1
  50. package/commands/gsd/forensics.md +1 -1
  51. package/commands/gsd/graphify.md +9 -9
  52. package/commands/gsd/health.md +1 -1
  53. package/commands/gsd/help.md +2 -2
  54. package/commands/gsd/import.md +5 -5
  55. package/commands/gsd/inbox.md +1 -1
  56. package/commands/gsd/ingest-docs.md +4 -4
  57. package/commands/gsd/manager.md +3 -3
  58. package/commands/gsd/map-codebase.md +1 -1
  59. package/commands/gsd/milestone-summary.md +1 -1
  60. package/commands/gsd/mvp-phase.md +4 -4
  61. package/commands/gsd/new-milestone.md +5 -5
  62. package/commands/gsd/new-project.md +5 -5
  63. package/commands/gsd/pause-work.md +2 -2
  64. package/commands/gsd/phase.md +4 -4
  65. package/commands/gsd/plan-phase.md +2 -2
  66. package/commands/gsd/plan-review-convergence.md +4 -4
  67. package/commands/gsd/pr-branch.md +1 -1
  68. package/commands/gsd/profile-user.md +2 -2
  69. package/commands/gsd/progress.md +4 -4
  70. package/commands/gsd/quick.md +1 -1
  71. package/commands/gsd/resume-work.md +1 -1
  72. package/commands/gsd/review.md +3 -2
  73. package/commands/gsd/secure-phase.md +1 -1
  74. package/commands/gsd/settings.md +1 -1
  75. package/commands/gsd/ship.md +2 -2
  76. package/commands/gsd/sketch.md +7 -7
  77. package/commands/gsd/spec-phase.md +2 -2
  78. package/commands/gsd/spike.md +3 -3
  79. package/commands/gsd/stats.md +1 -1
  80. package/commands/gsd/surface.md +4 -4
  81. package/commands/gsd/thread.md +1 -1
  82. package/commands/gsd/ui-phase.md +2 -2
  83. package/commands/gsd/ui-review.md +2 -2
  84. package/commands/gsd/ultraplan-phase.md +2 -2
  85. package/commands/gsd/undo.md +3 -3
  86. package/commands/gsd/update.md +3 -3
  87. package/commands/gsd/validate-phase.md +1 -1
  88. package/commands/gsd/verify-work.md +2 -2
  89. package/commands/gsd/workspace.md +4 -4
  90. package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
  91. package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +50 -4
  92. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  93. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  94. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  95. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  96. package/gsd-core/bin/lib/audit.cjs +743 -0
  97. package/gsd-core/bin/lib/check-command-router.cjs +342 -0
  98. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  99. package/gsd-core/bin/lib/clock.cjs +95 -0
  100. package/gsd-core/bin/lib/clusters.cjs +128 -0
  101. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  102. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  103. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  104. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  105. package/gsd-core/bin/lib/commands.cjs +1202 -0
  106. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  107. package/gsd-core/bin/lib/config-types.cjs +19 -0
  108. package/gsd-core/bin/lib/config.cjs +714 -0
  109. package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
  110. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  111. package/gsd-core/bin/lib/core.cjs +2007 -0
  112. package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
  113. package/gsd-core/bin/lib/docs.cjs +252 -0
  114. package/gsd-core/bin/lib/drift.cjs +364 -0
  115. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  116. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  117. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  118. package/gsd-core/bin/lib/graphify.cjs +496 -0
  119. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  120. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  121. package/gsd-core/bin/lib/init.cjs +1799 -0
  122. package/gsd-core/bin/lib/install-profiles.cjs +526 -0
  123. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  124. package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
  125. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  126. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  127. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  128. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  129. package/gsd-core/bin/lib/installer-migrations.cjs +784 -0
  130. package/gsd-core/bin/lib/intel.cjs +607 -0
  131. package/gsd-core/bin/lib/learnings.cjs +270 -0
  132. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  133. package/gsd-core/bin/lib/milestone.cjs +373 -0
  134. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  135. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  136. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  137. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  138. package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
  139. package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
  140. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  141. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  142. package/gsd-core/bin/lib/phase.cjs +1307 -0
  143. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  144. package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
  145. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  146. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  147. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  148. package/gsd-core/bin/lib/project-root.cjs +119 -0
  149. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  150. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  151. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  152. package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
  153. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  154. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
  155. package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  157. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  158. package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
  159. package/gsd-core/bin/lib/secrets.cjs +34 -0
  160. package/gsd-core/bin/lib/security.cjs +407 -0
  161. package/gsd-core/bin/lib/semver-compare.cjs +42 -0
  162. package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
  163. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  164. package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -82
  165. package/gsd-core/bin/lib/state.cjs +2010 -0
  166. package/gsd-core/bin/lib/surface.cjs +406 -0
  167. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  168. package/gsd-core/bin/lib/template.cjs +237 -0
  169. package/gsd-core/bin/lib/uat.cjs +297 -0
  170. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  171. package/gsd-core/bin/lib/update-context.cjs +218 -0
  172. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  173. package/gsd-core/bin/lib/validate.cjs +112 -0
  174. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  175. package/gsd-core/bin/lib/verify.cjs +1451 -0
  176. package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
  177. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  178. package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
  179. package/gsd-core/bin/lib/workstream.cjs +380 -0
  180. package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
  181. package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +1 -0
  182. package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +17 -1
  183. package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +27 -0
  184. package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
  185. package/{get-shit-done → gsd-core}/references/checkpoints.md +1 -1
  186. package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
  187. package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
  188. package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
  189. package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
  190. package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
  191. package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +1 -1
  192. package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
  193. package/{get-shit-done → gsd-core}/references/ui-brand.md +4 -2
  194. package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
  195. package/gsd-core/references/worktree-branch-check.md +38 -0
  196. package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
  197. package/{get-shit-done → gsd-core}/templates/README.md +2 -2
  198. package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
  199. package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
  200. package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
  201. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  202. package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
  203. package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
  204. package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
  205. package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
  206. package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
  207. package/{get-shit-done → gsd-core}/workflows/audit-fix.md +2 -2
  208. package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +3 -1
  209. package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
  210. package/{get-shit-done → gsd-core}/workflows/autonomous.md +10 -8
  211. package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
  212. package/{get-shit-done → gsd-core}/workflows/cleanup.md +44 -4
  213. package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +4 -4
  214. package/{get-shit-done → gsd-core}/workflows/code-review.md +6 -4
  215. package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
  216. package/{get-shit-done → gsd-core}/workflows/debug.md +7 -2
  217. package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +6 -2
  218. package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
  219. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +5 -5
  220. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
  221. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
  222. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
  223. package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +4 -4
  224. package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
  225. package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
  226. package/{get-shit-done → gsd-core}/workflows/docs-update.md +19 -5
  227. package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
  228. package/{get-shit-done → gsd-core}/workflows/eval-review.md +3 -3
  229. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +16 -3
  230. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  231. package/{get-shit-done → gsd-core}/workflows/execute-phase.md +89 -57
  232. package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
  233. package/{get-shit-done → gsd-core}/workflows/explore.md +5 -3
  234. package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
  235. package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
  236. package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
  237. package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
  238. package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +3 -3
  239. package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +6 -6
  240. package/{get-shit-done → gsd-core}/workflows/import.md +3 -1
  241. package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +5 -5
  242. package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
  243. package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
  244. package/{get-shit-done → gsd-core}/workflows/manager.md +3 -3
  245. package/{get-shit-done → gsd-core}/workflows/map-codebase.md +3 -1
  246. package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
  247. package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
  248. package/{get-shit-done → gsd-core}/workflows/new-milestone.md +5 -5
  249. package/{get-shit-done → gsd-core}/workflows/new-project.md +8 -8
  250. package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
  251. package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
  252. package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
  253. package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
  254. package/{get-shit-done → gsd-core}/workflows/plan-phase.md +29 -28
  255. package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +10 -10
  256. package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
  257. package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
  258. package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
  259. package/{get-shit-done → gsd-core}/workflows/quick.md +7 -29
  260. package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
  261. package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
  262. package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
  263. package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
  264. package/{get-shit-done → gsd-core}/workflows/review.md +110 -2
  265. package/{get-shit-done → gsd-core}/workflows/scan.md +3 -1
  266. package/{get-shit-done → gsd-core}/workflows/secure-phase.md +5 -3
  267. package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +196 -6
  268. package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
  269. package/{get-shit-done → gsd-core}/workflows/settings.md +16 -2
  270. package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
  271. package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
  272. package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
  273. package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
  274. package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
  275. package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
  276. package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
  277. package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
  278. package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
  279. package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
  280. package/{get-shit-done → gsd-core}/workflows/ui-phase.md +5 -5
  281. package/{get-shit-done → gsd-core}/workflows/ui-review.md +3 -3
  282. package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
  283. package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
  284. package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
  285. package/{get-shit-done → gsd-core}/workflows/validate-phase.md +5 -3
  286. package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
  287. package/{get-shit-done → gsd-core}/workflows/verify-work.md +7 -7
  288. package/hooks/dist/gsd-check-update-worker.js +16 -3
  289. package/hooks/dist/gsd-check-update.js +7 -5
  290. package/hooks/dist/gsd-context-monitor.js +2 -2
  291. package/hooks/dist/gsd-statusline.js +39 -21
  292. package/hooks/dist/gsd-update-banner.js +6 -2
  293. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  294. package/hooks/dist/managed-hooks-registry.cjs +35 -0
  295. package/hooks/gsd-check-update-worker.js +16 -3
  296. package/hooks/gsd-check-update.js +7 -5
  297. package/hooks/gsd-context-monitor.js +2 -2
  298. package/hooks/gsd-statusline.js +39 -21
  299. package/hooks/gsd-update-banner.js +6 -2
  300. package/hooks/gsd-worktree-path-guard.js +169 -0
  301. package/hooks/managed-hooks-registry.cjs +1 -0
  302. package/package.json +17 -11
  303. package/scripts/affected-tests-lib.cjs +1 -1
  304. package/scripts/base64-scan.sh +12 -0
  305. package/scripts/build-hooks.js +5 -1
  306. package/scripts/changeset/cli.cjs +2 -2
  307. package/scripts/changeset/github-release-notes.cjs +1 -1
  308. package/scripts/changeset/lint.cjs +1 -1
  309. package/scripts/check-alias-drift.cjs +8 -8
  310. package/scripts/check-env.cjs +5 -1
  311. package/scripts/ci-test-scope.cjs +34 -9
  312. package/scripts/command-contract-helpers.cjs +1 -1
  313. package/scripts/fix-slash-commands.cjs +5 -5
  314. package/scripts/gen-inventory-manifest.cjs +3 -3
  315. package/scripts/generate-package-identity.cjs +28 -7
  316. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  317. package/scripts/lint-command-contract.cjs +1 -1
  318. package/scripts/lint-legacy-dir-name.cjs +156 -0
  319. package/scripts/lint-package-identity-drift.cjs +8 -8
  320. package/scripts/lint-pr-check-project-dir.cjs +0 -1
  321. package/scripts/lint-shell-command-projection-drift.cjs +1 -1
  322. package/scripts/lint-skill-deps.cjs +1 -1
  323. package/scripts/lint-test-file-count.allowlist.json +129 -32
  324. package/scripts/lint-test-file-count.cjs +85 -30
  325. package/scripts/mutation-matrix.cjs +219 -0
  326. package/scripts/prompt-injection-scan.sh +5 -1
  327. package/scripts/release-notes/format-github-release-notes.cjs +256 -0
  328. package/scripts/release-tarball-smoke.cjs +9 -9
  329. package/scripts/run-tests.cjs +34 -2
  330. package/scripts/strip-prose-atrefs.cjs +2 -2
  331. package/scripts/sync-runtime-launcher.cjs +2 -2
  332. package/scripts/verify-npm-publish.cjs +252 -0
  333. package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
  334. package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
  335. package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
  336. package/get-shit-done/bin/lib/artifacts.cjs +0 -53
  337. package/get-shit-done/bin/lib/audit.cjs +0 -755
  338. package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
  339. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
  340. package/get-shit-done/bin/lib/clock.cjs +0 -96
  341. package/get-shit-done/bin/lib/clusters.cjs +0 -135
  342. package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
  343. package/get-shit-done/bin/lib/command-aliases.cjs +0 -815
  344. package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
  345. package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
  346. package/get-shit-done/bin/lib/commands.cjs +0 -1188
  347. package/get-shit-done/bin/lib/config-schema.cjs +0 -31
  348. package/get-shit-done/bin/lib/config.cjs +0 -728
  349. package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
  350. package/get-shit-done/bin/lib/core.cjs +0 -2121
  351. package/get-shit-done/bin/lib/docs.cjs +0 -270
  352. package/get-shit-done/bin/lib/drift.cjs +0 -388
  353. package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
  354. package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
  355. package/get-shit-done/bin/lib/gap-checker.cjs +0 -205
  356. package/get-shit-done/bin/lib/graphify.cjs +0 -592
  357. package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
  358. package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
  359. package/get-shit-done/bin/lib/init.cjs +0 -2112
  360. package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
  361. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
  362. package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -354
  363. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
  364. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
  365. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
  366. package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
  367. package/get-shit-done/bin/lib/intel.cjs +0 -708
  368. package/get-shit-done/bin/lib/learnings.cjs +0 -421
  369. package/get-shit-done/bin/lib/milestone.cjs +0 -314
  370. package/get-shit-done/bin/lib/model-catalog.cjs +0 -212
  371. package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
  372. package/get-shit-done/bin/lib/observability/event.cjs +0 -82
  373. package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
  374. package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
  375. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -80
  376. package/get-shit-done/bin/lib/phase.cjs +0 -1607
  377. package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
  378. package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
  379. package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
  380. package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
  381. package/get-shit-done/bin/lib/project-root.cjs +0 -112
  382. package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
  383. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -125
  384. package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -28
  385. package/get-shit-done/bin/lib/roadmap.cjs +0 -650
  386. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
  387. package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
  388. package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
  389. package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
  390. package/get-shit-done/bin/lib/secrets.cjs +0 -32
  391. package/get-shit-done/bin/lib/security.cjs +0 -600
  392. package/get-shit-done/bin/lib/semver-compare.cjs +0 -35
  393. package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -500
  394. package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
  395. package/get-shit-done/bin/lib/state.cjs +0 -2038
  396. package/get-shit-done/bin/lib/surface.cjs +0 -470
  397. package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
  398. package/get-shit-done/bin/lib/template.cjs +0 -228
  399. package/get-shit-done/bin/lib/uat.cjs +0 -289
  400. package/get-shit-done/bin/lib/update-context.cjs +0 -209
  401. package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
  402. package/get-shit-done/bin/lib/validate.cjs +0 -92
  403. package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
  404. package/get-shit-done/bin/lib/verify.cjs +0 -1511
  405. package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
  406. package/get-shit-done/bin/lib/workstream.cjs +0 -389
  407. package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
  408. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
  409. package/scripts/lint-no-source-grep-extras.cjs +0 -81
  410. package/scripts/lint-no-source-grep.cjs +0 -174
  411. package/scripts/lint-shared-module-handsync.cjs +0 -388
  412. package/scripts/shared-module-handsync-allowlist.json +0 -183
  413. /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
  414. /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
  415. /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
  416. /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
  417. /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
  418. /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
  419. /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
  420. /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
  421. /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
  422. /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
  423. /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
  424. /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
  425. /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
  426. /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
  427. /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
  428. /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
  429. /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
  430. /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
  431. /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
  432. /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
  433. /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
  434. /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
  435. /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
  436. /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
  437. /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
  438. /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
  439. /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
  440. /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
  441. /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
  442. /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
  443. /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
  444. /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
  445. /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
  446. /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
  447. /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
  448. /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
  449. /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
  450. /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
  451. /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
  452. /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
  453. /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
  454. /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
  455. /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
  456. /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
  457. /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
  458. /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
  459. /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
  460. /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
  461. /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
  462. /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
  463. /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
  464. /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
  465. /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
  466. /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
  467. /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
  468. /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
  469. /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
  470. /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
  471. /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
  472. /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
  473. /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
  474. /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
  475. /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
  476. /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
  477. /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
  478. /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
  479. /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
  480. /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
  481. /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
  482. /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
  483. /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
  484. /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
  485. /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
  486. /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
  487. /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
  488. /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
  489. /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
  490. /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
  491. /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
  492. /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
  493. /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
  494. /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
  495. /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
  496. /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
  497. /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
  498. /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
  499. /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
  500. /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
  501. /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
  502. /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
  503. /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
  504. /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
  505. /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
  506. /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
  507. /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
  508. /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
  509. /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
  510. /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
  511. /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
  512. /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
  513. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
  514. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
  515. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
  516. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
  517. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
  518. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
  519. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
  520. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
  521. /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
  522. /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
  523. /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
  524. /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
  525. /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
  526. /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
  527. /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
  528. /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
  529. /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
  530. /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
  531. /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
  532. /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
@@ -11,17 +11,29 @@
11
11
 
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
- const { isSemverNewer } = require('../get-shit-done/bin/lib/semver-compare.cjs');
14
+ const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
15
15
  // Latest-version lookup is delegated to the single deterministic adapter
16
16
  // (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
17
17
  // policy, and the package name — sourced from the baked Package Identity seam.
18
18
  // The previous `require('../package.json').name` (#378) resolved to undefined
19
19
  // in the installed tree (only a {"type":"commonjs"} marker ships), so the
20
20
  // background check never reported updates.
21
- const { checkLatestVersion } = require('../get-shit-done/bin/check-latest-version.cjs');
21
+ const { checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs');
22
+ const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
22
23
  // Authoritative list of managed hooks — shared with tests to retire source-grep
23
24
  // assertions (pending-migration-to-typed-ir [#455]).
24
- const { MANAGED_HOOKS } = require('./managed-hooks-registry.cjs');
25
+ // NOTE: managed-hooks-registry.cjs must be in HOOKS_TO_COPY (scripts/build-hooks.js)
26
+ // so it is present in hooks/dist/ and ships to the installed runtime hooks/ dir.
27
+ // If it is missing (e.g., installed from an older dist), catch and degrade gracefully
28
+ // so the worker always proceeds to compute and write the result cache record.
29
+ let MANAGED_HOOKS = [];
30
+ try {
31
+ ({ MANAGED_HOOKS } = require('./managed-hooks-registry.cjs'));
32
+ } catch (e) {
33
+ // Module not found in installed runtime — stale-hook detection degrades to
34
+ // no-op (empty list means no hooks are checked for staleness). The worker
35
+ // still runs and writes package_name / installed / latest / update_available.
36
+ }
25
37
 
26
38
  const cacheFile = process.env.GSD_CACHE_FILE;
27
39
  const projectVersionFile = process.env.GSD_PROJECT_VERSION_FILE;
@@ -88,6 +100,7 @@ const result = {
88
100
  latest: latest || 'unknown',
89
101
  checked: Math.floor(Date.now() / 1000),
90
102
  stale_hooks: staleHooks.length > 0 ? staleHooks : undefined,
103
+ package_name: PACKAGE_NAME,
91
104
  };
92
105
 
93
106
  if (cacheFile) {
@@ -8,6 +8,8 @@ const path = require('path');
8
8
  const os = require('os');
9
9
  const { spawn } = require('child_process');
10
10
 
11
+ const { updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
12
+
11
13
  const homeDir = os.homedir();
12
14
  const cwd = process.cwd();
13
15
 
@@ -16,11 +18,11 @@ const cwd = process.cwd();
16
18
  function detectConfigDir(baseDir) {
17
19
  // Check env override first (supports multi-account setups)
18
20
  const envDir = process.env.CLAUDE_CONFIG_DIR;
19
- if (envDir && fs.existsSync(path.join(envDir, 'get-shit-done', 'VERSION'))) {
21
+ if (envDir && fs.existsSync(path.join(envDir, 'gsd-core', 'VERSION'))) {
20
22
  return envDir;
21
23
  }
22
24
  for (const dir of ['.claude', '.gemini', '.config/kilo', '.kilo', '.config/opencode', '.opencode']) {
23
- if (fs.existsSync(path.join(baseDir, dir, 'get-shit-done', 'VERSION'))) {
25
+ if (fs.existsSync(path.join(baseDir, dir, 'gsd-core', 'VERSION'))) {
24
26
  return path.join(baseDir, dir);
25
27
  }
26
28
  }
@@ -33,11 +35,11 @@ const projectConfigDir = detectConfigDir(cwd);
33
35
  // resolution mismatches where check-update writes to one runtime's cache
34
36
  // but statusline reads from another (#1421).
35
37
  const cacheDir = path.join(homeDir, '.cache', 'gsd');
36
- const cacheFile = path.join(cacheDir, 'gsd-update-check.json');
38
+ const cacheFile = path.join(cacheDir, updateCacheFileName);
37
39
 
38
40
  // VERSION file locations (check project first, then global)
39
- const projectVersionFile = path.join(projectConfigDir, 'get-shit-done', 'VERSION');
40
- const globalVersionFile = path.join(globalConfigDir, 'get-shit-done', 'VERSION');
41
+ const projectVersionFile = path.join(projectConfigDir, 'gsd-core', 'VERSION');
42
+ const globalVersionFile = path.join(globalConfigDir, 'gsd-core', 'VERSION');
41
43
 
42
44
  // Ensure cache directory exists
43
45
  if (!fs.existsSync(cacheDir)) {
@@ -140,10 +140,10 @@ process.stdin.on('end', () => {
140
140
  if (isCritical && isGsdActive && !warnData.criticalRecorded) {
141
141
  try {
142
142
  // Runtime-agnostic path: this hook lives at <runtime-config>/hooks/
143
- // and gsd-tools.cjs lives at <runtime-config>/get-shit-done/bin/.
143
+ // and gsd-tools.cjs lives at <runtime-config>/gsd-core/bin/.
144
144
  // Using __dirname makes this work on Claude Code, OpenCode, Gemini,
145
145
  // Kilo, etc. without hardcoding ~/.claude/.
146
- const gsdTools = path.join(__dirname, '..', 'get-shit-done', 'bin', 'gsd-tools.cjs');
146
+ const gsdTools = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
147
147
  // Coerce usedPct to a safe number in case bridge file is malformed
148
148
  const safeUsedPct = Number(usedPct) || 0;
149
149
  const stoppedAt = `context exhaustion at ${safeUsedPct}% (${new Date().toISOString().split('T')[0]})`;
@@ -6,7 +6,8 @@
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
  const os = require('os');
9
- const { isSemverNewer } = require('../get-shit-done/bin/lib/semver-compare.cjs');
9
+ const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
10
+ const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
10
11
 
11
12
  // --- Config + last-command readers ------------------------------------------
12
13
 
@@ -395,32 +396,22 @@ function runStatusline() {
395
396
  const gsdStateStr = task ? '' : formatGsdState(readGsdState(dir) || {});
396
397
 
397
398
  // GSD update available?
398
- // Check shared cache first (#1421), fall back to runtime-specific cache for
399
- // backward compatibility with older gsd-check-update.js versions.
399
+ // Read only the per-package shared cache file (#607). The legacy
400
+ // runtime-specific fallback has been removed — the per-package filename
401
+ // carries lineage and avoids multi-runtime resolution mismatches (#1421).
400
402
  let gsdUpdate = '';
401
- const sharedCacheFile = path.join(homeDir, '.cache', 'gsd', 'gsd-update-check.json');
402
- const legacyCacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json');
403
- const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile;
403
+ const cacheFile = path.join(homeDir, '.cache', 'gsd', updateCacheFileName);
404
404
  if (fs.existsSync(cacheFile)) {
405
405
  try {
406
406
  const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
407
- if (cache.update_available) {
407
+ const { showUpdate, staleWarning } = evaluateUpdateCache(cache);
408
+ if (showUpdate) {
408
409
  gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
409
410
  }
410
- if (cache.stale_hooks && cache.stale_hooks.length > 0) {
411
- // If installed version is ahead of npm latest, this is a dev install.
412
- // Running /gsd:update would downgrade — show a contextual warning instead.
413
- const isDevInstall = (
414
- cache.installed &&
415
- cache.latest &&
416
- cache.latest !== 'unknown' &&
417
- isInstalledAheadOfLatest(cache.installed, cache.latest)
418
- );
419
- if (isDevInstall) {
420
- gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
421
- } else {
422
- gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
423
- }
411
+ if (staleWarning === 'dev') {
412
+ gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
413
+ } else if (staleWarning === 'stale') {
414
+ gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
424
415
  }
425
416
  } catch (e) {}
426
417
  }
@@ -507,12 +498,39 @@ function isInstalledAheadOfLatest(installed, latest) {
507
498
  return isSemverNewer(installed, latest);
508
499
  }
509
500
 
501
+ /**
502
+ * Pure function: evaluate an update-check cache object and return display flags.
503
+ * Applies lineage guard — if package_name is absent or foreign, treats cache as absent.
504
+ *
505
+ * @param {object|null} cache Parsed cache object, or null.
506
+ * @returns {{ showUpdate: boolean, staleWarning: 'none'|'dev'|'stale' }}
507
+ */
508
+ function evaluateUpdateCache(cache) {
509
+ const none = { showUpdate: false, staleWarning: 'none' };
510
+ if (!cache) return none;
511
+ // Lineage guard: package_name must be present and match this package.
512
+ if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return none;
513
+ const showUpdate = Boolean(cache.update_available);
514
+ let staleWarning = 'none';
515
+ if (cache.stale_hooks && cache.stale_hooks.length > 0) {
516
+ const isDevInstall = (
517
+ cache.installed &&
518
+ cache.latest &&
519
+ cache.latest !== 'unknown' &&
520
+ isInstalledAheadOfLatest(cache.installed, cache.latest)
521
+ );
522
+ staleWarning = isDevInstall ? 'dev' : 'stale';
523
+ }
524
+ return { showUpdate, staleWarning };
525
+ }
526
+
510
527
  // Export helpers for unit tests. Harmless when run as a script.
511
528
  module.exports = {
512
529
  readGsdState, parseStateMd, formatGsdState,
513
530
  readGsdConfig, getConfigValue, readLastSlashCommand,
514
531
  composeStatusline,
515
532
  isInstalledAheadOfLatest,
533
+ evaluateUpdateCache,
516
534
  };
517
535
 
518
536
  /**
@@ -2,7 +2,7 @@
2
2
  // gsd-hook-version: {{GSD_VERSION}}
3
3
  // SessionStart banner that surfaces GSD update availability when GSD's
4
4
  // statusline isn't installed. Reads the cache that
5
- // gsd-check-update-worker.js writes to ~/.cache/gsd/gsd-update-check.json.
5
+ // gsd-check-update-worker.js writes to ~/.cache/gsd/<updateCacheFileName> (per-package).
6
6
  //
7
7
  // Opt-in by design: bin/install.js only registers this hook when the user
8
8
  // declines to install (or replace) the GSD statusline. The presence of the
@@ -15,6 +15,7 @@
15
15
  const fs = require('fs');
16
16
  const path = require('path');
17
17
  const os = require('os');
18
+ const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
18
19
 
19
20
  // Suppress repeat parse-error banners for 24 hours so a genuinely broken
20
21
  // cache file doesn't nag the user every session.
@@ -37,6 +38,9 @@ function buildBannerOutput(state) {
37
38
  return { systemMessage: 'GSD update check failed.' };
38
39
  }
39
40
  if (!cache) return null;
41
+ // Lineage guard: package_name must be present and match this package.
42
+ // Absent package_name means the cache predates lineage tracking — treat as untrusted.
43
+ if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return null;
40
44
  if (!cache.update_available) return null;
41
45
  const installed = cache.installed || 'unknown';
42
46
  const latest = cache.latest || 'unknown';
@@ -96,7 +100,7 @@ function recordFailureWarning(sentinelFile, nowSeconds) {
96
100
 
97
101
  function main() {
98
102
  const cacheDir = path.join(os.homedir(), '.cache', 'gsd');
99
- const cacheFile = path.join(cacheDir, 'gsd-update-check.json');
103
+ const cacheFile = path.join(cacheDir, updateCacheFileName);
100
104
  const sentinelFile = path.join(cacheDir, 'banner-failure-warned-at');
101
105
  const now = Math.floor(Date.now() / 1000);
102
106
 
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ // gsd-hook-version: {{GSD_VERSION}}
3
+ // GSD Worktree Path Guard — PreToolUse hook
4
+ // Blocks Edit/Write/MultiEdit tool calls that target absolute paths outside the worktree root.
5
+ //
6
+ // Problem: gsd-executor agents spawned with isolation="worktree" sometimes issue
7
+ // Edit/Write calls with absolute paths rooted at the MAIN repository instead of
8
+ // the worktree (issue #260). The prose guard in agents/gsd-executor.md step 0b
9
+ // is never enforced because the model under load skips it.
10
+ //
11
+ // This hook enforces the constraint at the tooling layer, making it HARD-BLOCKING.
12
+ //
13
+ // Triggers on: Edit, Write, and MultiEdit tool calls
14
+ // Action: BLOCK (exit 2) if file_path is absolute and outside the worktree root
15
+ // No-op: relative paths, non-worktree CWDs, hook errors (silent fail)
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const { spawnSync } = require('child_process');
20
+
21
+ const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000 };
22
+
23
+ function git(args, cwd) {
24
+ return spawnSync('git', args, { ...SPAWNOPT, cwd });
25
+ }
26
+
27
+ // Walk up from `start` to find the nearest existing directory.
28
+ // Returns null if we reach the filesystem root without finding one.
29
+ function nearestExistingDir(start) {
30
+ let dir = start;
31
+ let prev;
32
+ do {
33
+ prev = dir;
34
+ try { fs.accessSync(dir, fs.constants.F_OK); return dir; } catch { /* keep walking */ }
35
+ dir = path.dirname(dir);
36
+ } while (dir !== prev);
37
+ return null;
38
+ }
39
+
40
+ let input = '';
41
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
42
+ process.stdin.setEncoding('utf8');
43
+ process.stdin.on('data', chunk => input += chunk);
44
+ process.stdin.on('end', () => {
45
+ clearTimeout(stdinTimeout);
46
+ try {
47
+ const data = JSON.parse(input);
48
+ const toolName = data.tool_name;
49
+
50
+ // Only guard Edit, Write, and MultiEdit tool calls
51
+ if (toolName !== 'Edit' && toolName !== 'Write' && toolName !== 'MultiEdit') {
52
+ process.exit(0);
53
+ }
54
+
55
+ const cwd = data.cwd || process.cwd();
56
+
57
+ // Detect whether CWD is inside a linked git worktree by inspecting
58
+ // the git-dir path. In a linked worktree, git rev-parse --git-dir
59
+ // returns a path containing .git/worktrees/ as a component.
60
+ // In the main repo or a submodule it returns .git (or a path without /worktrees/).
61
+ // This approach works even when cwd is a subdirectory of the worktree.
62
+ const gitDirResult = git(['rev-parse', '--git-dir'], cwd);
63
+ if (gitDirResult.status !== 0 || !gitDirResult.stdout) {
64
+ process.exit(0); // not a git repo — pass through
65
+ }
66
+
67
+ const gitDir = gitDirResult.stdout.trim();
68
+ // A linked worktree's --git-dir contains .git/worktrees/ as a path component
69
+ const isLinkedWorktree = /[/\\]\.git[/\\]worktrees[/\\]/.test(gitDir);
70
+ if (!isLinkedWorktree) {
71
+ process.exit(0); // main repo, submodule, or separate-git-dir — no-op
72
+ }
73
+
74
+ // Get the raw --show-toplevel output for the worktree (cwd).
75
+ // We keep it raw (not path.resolve'd) to compare directly with the
76
+ // file's toplevel — same git binary, same format, no normalization needed.
77
+ const wtTopResult = git(['rev-parse', '--show-toplevel'], cwd);
78
+ if (wtTopResult.status !== 0 || !wtTopResult.stdout) {
79
+ process.exit(0); // can't determine root — fail open
80
+ }
81
+ const wtTopRaw = wtTopResult.stdout.trim();
82
+
83
+ const rawFilePath = data.tool_input?.file_path || '';
84
+ if (!rawFilePath) {
85
+ process.exit(0);
86
+ }
87
+
88
+ // Relative paths are always safe — they resolve relative to CWD inside the worktree
89
+ if (!path.isAbsolute(rawFilePath)) {
90
+ process.exit(0);
91
+ }
92
+
93
+ // Normalise .. traversal so /worktree/src/../../../main/file
94
+ // resolves to its true location before we check containment.
95
+ const filePath = path.resolve(rawFilePath);
96
+
97
+ // Find the nearest existing ancestor of filePath so we can ask git
98
+ // for its toplevel. The file itself may not exist yet (Write creates
99
+ // new files), but at least one ancestor directory must exist.
100
+ // We check the file itself first in case it already exists.
101
+ const checkDir = nearestExistingDir(
102
+ (() => {
103
+ try {
104
+ return fs.statSync(filePath).isDirectory() ? filePath : path.dirname(filePath);
105
+ } catch {
106
+ return path.dirname(filePath);
107
+ }
108
+ })()
109
+ );
110
+
111
+ if (!checkDir) {
112
+ // Walked to root without finding any directory — path is synthetic.
113
+ // Block conservatively.
114
+ const output = {
115
+ decision: 'block',
116
+ reason:
117
+ `Worktree path guard: '${filePath}' has no existing ancestor directory — ` +
118
+ `cannot verify it is inside the worktree '${wtTopRaw}'. Use a relative path instead.`,
119
+ };
120
+ process.stdout.write(JSON.stringify(output));
121
+ process.exit(2);
122
+ }
123
+
124
+ // Ask git for the toplevel of the file's location.
125
+ // Comparing two raw git --show-toplevel outputs avoids every
126
+ // platform-specific path normalisation pitfall (Windows 8.3 short names,
127
+ // case differences between realpathSync and path.resolve, forward- vs
128
+ // back-slash inconsistencies) — both values come from the same git binary
129
+ // in the same format by definition.
130
+ const fileTopResult = git(['rev-parse', '--show-toplevel'], checkDir);
131
+
132
+ if (fileTopResult.status !== 0 || !fileTopResult.stdout) {
133
+ // checkDir is not inside any git repo → cannot be inside the worktree.
134
+ const output = {
135
+ decision: 'block',
136
+ reason:
137
+ `Worktree path guard: '${filePath}' is not inside any git repository — ` +
138
+ `it cannot be inside the worktree at '${wtTopRaw}'. Use a relative path instead.`,
139
+ };
140
+ process.stdout.write(JSON.stringify(output));
141
+ process.exit(2);
142
+ }
143
+
144
+ const fileTopRaw = fileTopResult.stdout.trim();
145
+
146
+ // Same git toplevel → file is inside the worktree → allow
147
+ if (fileTopRaw === wtTopRaw) {
148
+ process.exit(0);
149
+ }
150
+
151
+ // BLOCK: file resolves to a different git root than the active worktree
152
+ const output = {
153
+ decision: 'block',
154
+ reason:
155
+ `Worktree path guard: '${filePath}' resolves to git root '${fileTopRaw}' which ` +
156
+ `differs from the active worktree root '${wtTopRaw}'. This likely means an ` +
157
+ `absolute path was derived from the orchestrator's main repository instead of ` +
158
+ `the active worktree. To fix: use a relative path, or re-derive the base ` +
159
+ `directory with \`git rev-parse --show-toplevel\` from within the worktree ` +
160
+ `(hook cwd: '${cwd}').`,
161
+ };
162
+
163
+ process.stdout.write(JSON.stringify(output));
164
+ process.exit(2);
165
+ } catch {
166
+ // Silent fail — never block valid tool calls due to hook errors
167
+ process.exit(0);
168
+ }
169
+ });
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Authoritative list of GSD-managed hook files.
5
+ *
6
+ * Extracted from the worker script into a shared CJS module so that:
7
+ * 1. gsd-check-update-worker.js can require() it directly (no source-level
8
+ * duplication).
9
+ * 2. Tests can assert against the exported array instead of regex-parsing
10
+ * the worker source (retiring the pending-migration-to-typed-ir token
11
+ * on managed-hooks.test.cjs and orphaned-hooks.test.cjs, per #455).
12
+ *
13
+ * These are the files GSD ships into ~/.claude/hooks/ (or equivalent) and
14
+ * checks for staleness after an update. Orphaned files from removed features
15
+ * (e.g., gsd-intel-*.js) must NOT be listed here — that would cause permanent
16
+ * stale warnings for users who haven't cleaned up manually (#1750).
17
+ */
18
+ const MANAGED_HOOKS = [
19
+ 'gsd-check-update-worker.js',
20
+ 'gsd-check-update.js',
21
+ 'gsd-context-monitor.js',
22
+ 'gsd-graphify-update.sh',
23
+ 'gsd-phase-boundary.sh',
24
+ 'gsd-prompt-guard.js',
25
+ 'gsd-read-guard.js',
26
+ 'gsd-read-injection-scanner.js',
27
+ 'gsd-session-state.sh',
28
+ 'gsd-statusline.js',
29
+ 'gsd-update-banner.js',
30
+ 'gsd-validate-commit.sh',
31
+ 'gsd-workflow-guard.js',
32
+ 'gsd-worktree-path-guard.js',
33
+ ];
34
+
35
+ module.exports = { MANAGED_HOOKS };
@@ -11,17 +11,29 @@
11
11
 
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
- const { isSemverNewer } = require('../get-shit-done/bin/lib/semver-compare.cjs');
14
+ const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
15
15
  // Latest-version lookup is delegated to the single deterministic adapter
16
16
  // (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
17
17
  // policy, and the package name — sourced from the baked Package Identity seam.
18
18
  // The previous `require('../package.json').name` (#378) resolved to undefined
19
19
  // in the installed tree (only a {"type":"commonjs"} marker ships), so the
20
20
  // background check never reported updates.
21
- const { checkLatestVersion } = require('../get-shit-done/bin/check-latest-version.cjs');
21
+ const { checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs');
22
+ const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
22
23
  // Authoritative list of managed hooks — shared with tests to retire source-grep
23
24
  // assertions (pending-migration-to-typed-ir [#455]).
24
- const { MANAGED_HOOKS } = require('./managed-hooks-registry.cjs');
25
+ // NOTE: managed-hooks-registry.cjs must be in HOOKS_TO_COPY (scripts/build-hooks.js)
26
+ // so it is present in hooks/dist/ and ships to the installed runtime hooks/ dir.
27
+ // If it is missing (e.g., installed from an older dist), catch and degrade gracefully
28
+ // so the worker always proceeds to compute and write the result cache record.
29
+ let MANAGED_HOOKS = [];
30
+ try {
31
+ ({ MANAGED_HOOKS } = require('./managed-hooks-registry.cjs'));
32
+ } catch (e) {
33
+ // Module not found in installed runtime — stale-hook detection degrades to
34
+ // no-op (empty list means no hooks are checked for staleness). The worker
35
+ // still runs and writes package_name / installed / latest / update_available.
36
+ }
25
37
 
26
38
  const cacheFile = process.env.GSD_CACHE_FILE;
27
39
  const projectVersionFile = process.env.GSD_PROJECT_VERSION_FILE;
@@ -88,6 +100,7 @@ const result = {
88
100
  latest: latest || 'unknown',
89
101
  checked: Math.floor(Date.now() / 1000),
90
102
  stale_hooks: staleHooks.length > 0 ? staleHooks : undefined,
103
+ package_name: PACKAGE_NAME,
91
104
  };
92
105
 
93
106
  if (cacheFile) {
@@ -8,6 +8,8 @@ const path = require('path');
8
8
  const os = require('os');
9
9
  const { spawn } = require('child_process');
10
10
 
11
+ const { updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
12
+
11
13
  const homeDir = os.homedir();
12
14
  const cwd = process.cwd();
13
15
 
@@ -16,11 +18,11 @@ const cwd = process.cwd();
16
18
  function detectConfigDir(baseDir) {
17
19
  // Check env override first (supports multi-account setups)
18
20
  const envDir = process.env.CLAUDE_CONFIG_DIR;
19
- if (envDir && fs.existsSync(path.join(envDir, 'get-shit-done', 'VERSION'))) {
21
+ if (envDir && fs.existsSync(path.join(envDir, 'gsd-core', 'VERSION'))) {
20
22
  return envDir;
21
23
  }
22
24
  for (const dir of ['.claude', '.gemini', '.config/kilo', '.kilo', '.config/opencode', '.opencode']) {
23
- if (fs.existsSync(path.join(baseDir, dir, 'get-shit-done', 'VERSION'))) {
25
+ if (fs.existsSync(path.join(baseDir, dir, 'gsd-core', 'VERSION'))) {
24
26
  return path.join(baseDir, dir);
25
27
  }
26
28
  }
@@ -33,11 +35,11 @@ const projectConfigDir = detectConfigDir(cwd);
33
35
  // resolution mismatches where check-update writes to one runtime's cache
34
36
  // but statusline reads from another (#1421).
35
37
  const cacheDir = path.join(homeDir, '.cache', 'gsd');
36
- const cacheFile = path.join(cacheDir, 'gsd-update-check.json');
38
+ const cacheFile = path.join(cacheDir, updateCacheFileName);
37
39
 
38
40
  // VERSION file locations (check project first, then global)
39
- const projectVersionFile = path.join(projectConfigDir, 'get-shit-done', 'VERSION');
40
- const globalVersionFile = path.join(globalConfigDir, 'get-shit-done', 'VERSION');
41
+ const projectVersionFile = path.join(projectConfigDir, 'gsd-core', 'VERSION');
42
+ const globalVersionFile = path.join(globalConfigDir, 'gsd-core', 'VERSION');
41
43
 
42
44
  // Ensure cache directory exists
43
45
  if (!fs.existsSync(cacheDir)) {
@@ -140,10 +140,10 @@ process.stdin.on('end', () => {
140
140
  if (isCritical && isGsdActive && !warnData.criticalRecorded) {
141
141
  try {
142
142
  // Runtime-agnostic path: this hook lives at <runtime-config>/hooks/
143
- // and gsd-tools.cjs lives at <runtime-config>/get-shit-done/bin/.
143
+ // and gsd-tools.cjs lives at <runtime-config>/gsd-core/bin/.
144
144
  // Using __dirname makes this work on Claude Code, OpenCode, Gemini,
145
145
  // Kilo, etc. without hardcoding ~/.claude/.
146
- const gsdTools = path.join(__dirname, '..', 'get-shit-done', 'bin', 'gsd-tools.cjs');
146
+ const gsdTools = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
147
147
  // Coerce usedPct to a safe number in case bridge file is malformed
148
148
  const safeUsedPct = Number(usedPct) || 0;
149
149
  const stoppedAt = `context exhaustion at ${safeUsedPct}% (${new Date().toISOString().split('T')[0]})`;
@@ -6,7 +6,8 @@
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
  const os = require('os');
9
- const { isSemverNewer } = require('../get-shit-done/bin/lib/semver-compare.cjs');
9
+ const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
10
+ const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
10
11
 
11
12
  // --- Config + last-command readers ------------------------------------------
12
13
 
@@ -395,32 +396,22 @@ function runStatusline() {
395
396
  const gsdStateStr = task ? '' : formatGsdState(readGsdState(dir) || {});
396
397
 
397
398
  // GSD update available?
398
- // Check shared cache first (#1421), fall back to runtime-specific cache for
399
- // backward compatibility with older gsd-check-update.js versions.
399
+ // Read only the per-package shared cache file (#607). The legacy
400
+ // runtime-specific fallback has been removed — the per-package filename
401
+ // carries lineage and avoids multi-runtime resolution mismatches (#1421).
400
402
  let gsdUpdate = '';
401
- const sharedCacheFile = path.join(homeDir, '.cache', 'gsd', 'gsd-update-check.json');
402
- const legacyCacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json');
403
- const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile;
403
+ const cacheFile = path.join(homeDir, '.cache', 'gsd', updateCacheFileName);
404
404
  if (fs.existsSync(cacheFile)) {
405
405
  try {
406
406
  const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
407
- if (cache.update_available) {
407
+ const { showUpdate, staleWarning } = evaluateUpdateCache(cache);
408
+ if (showUpdate) {
408
409
  gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
409
410
  }
410
- if (cache.stale_hooks && cache.stale_hooks.length > 0) {
411
- // If installed version is ahead of npm latest, this is a dev install.
412
- // Running /gsd:update would downgrade — show a contextual warning instead.
413
- const isDevInstall = (
414
- cache.installed &&
415
- cache.latest &&
416
- cache.latest !== 'unknown' &&
417
- isInstalledAheadOfLatest(cache.installed, cache.latest)
418
- );
419
- if (isDevInstall) {
420
- gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
421
- } else {
422
- gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
423
- }
411
+ if (staleWarning === 'dev') {
412
+ gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
413
+ } else if (staleWarning === 'stale') {
414
+ gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
424
415
  }
425
416
  } catch (e) {}
426
417
  }
@@ -507,12 +498,39 @@ function isInstalledAheadOfLatest(installed, latest) {
507
498
  return isSemverNewer(installed, latest);
508
499
  }
509
500
 
501
+ /**
502
+ * Pure function: evaluate an update-check cache object and return display flags.
503
+ * Applies lineage guard — if package_name is absent or foreign, treats cache as absent.
504
+ *
505
+ * @param {object|null} cache Parsed cache object, or null.
506
+ * @returns {{ showUpdate: boolean, staleWarning: 'none'|'dev'|'stale' }}
507
+ */
508
+ function evaluateUpdateCache(cache) {
509
+ const none = { showUpdate: false, staleWarning: 'none' };
510
+ if (!cache) return none;
511
+ // Lineage guard: package_name must be present and match this package.
512
+ if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return none;
513
+ const showUpdate = Boolean(cache.update_available);
514
+ let staleWarning = 'none';
515
+ if (cache.stale_hooks && cache.stale_hooks.length > 0) {
516
+ const isDevInstall = (
517
+ cache.installed &&
518
+ cache.latest &&
519
+ cache.latest !== 'unknown' &&
520
+ isInstalledAheadOfLatest(cache.installed, cache.latest)
521
+ );
522
+ staleWarning = isDevInstall ? 'dev' : 'stale';
523
+ }
524
+ return { showUpdate, staleWarning };
525
+ }
526
+
510
527
  // Export helpers for unit tests. Harmless when run as a script.
511
528
  module.exports = {
512
529
  readGsdState, parseStateMd, formatGsdState,
513
530
  readGsdConfig, getConfigValue, readLastSlashCommand,
514
531
  composeStatusline,
515
532
  isInstalledAheadOfLatest,
533
+ evaluateUpdateCache,
516
534
  };
517
535
 
518
536
  /**
@@ -2,7 +2,7 @@
2
2
  // gsd-hook-version: {{GSD_VERSION}}
3
3
  // SessionStart banner that surfaces GSD update availability when GSD's
4
4
  // statusline isn't installed. Reads the cache that
5
- // gsd-check-update-worker.js writes to ~/.cache/gsd/gsd-update-check.json.
5
+ // gsd-check-update-worker.js writes to ~/.cache/gsd/<updateCacheFileName> (per-package).
6
6
  //
7
7
  // Opt-in by design: bin/install.js only registers this hook when the user
8
8
  // declines to install (or replace) the GSD statusline. The presence of the
@@ -15,6 +15,7 @@
15
15
  const fs = require('fs');
16
16
  const path = require('path');
17
17
  const os = require('os');
18
+ const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
18
19
 
19
20
  // Suppress repeat parse-error banners for 24 hours so a genuinely broken
20
21
  // cache file doesn't nag the user every session.
@@ -37,6 +38,9 @@ function buildBannerOutput(state) {
37
38
  return { systemMessage: 'GSD update check failed.' };
38
39
  }
39
40
  if (!cache) return null;
41
+ // Lineage guard: package_name must be present and match this package.
42
+ // Absent package_name means the cache predates lineage tracking — treat as untrusted.
43
+ if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return null;
40
44
  if (!cache.update_available) return null;
41
45
  const installed = cache.installed || 'unknown';
42
46
  const latest = cache.latest || 'unknown';
@@ -96,7 +100,7 @@ function recordFailureWarning(sentinelFile, nowSeconds) {
96
100
 
97
101
  function main() {
98
102
  const cacheDir = path.join(os.homedir(), '.cache', 'gsd');
99
- const cacheFile = path.join(cacheDir, 'gsd-update-check.json');
103
+ const cacheFile = path.join(cacheDir, updateCacheFileName);
100
104
  const sentinelFile = path.join(cacheDir, 'banner-failure-warned-at');
101
105
  const now = Math.floor(Date.now() / 1000);
102
106