@therocketcode/gsd-core 1.4.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 (568) hide show
  1. package/.claude-plugin/plugin.json +23 -0
  2. package/GEMINI.md +53 -0
  3. package/LICENSE +21 -0
  4. package/README.ja-JP.md +125 -0
  5. package/README.ko-KR.md +125 -0
  6. package/README.md +144 -0
  7. package/README.pt-BR.md +125 -0
  8. package/README.zh-CN.md +125 -0
  9. package/agents/gsd-advisor-researcher.md +108 -0
  10. package/agents/gsd-ai-researcher.md +114 -0
  11. package/agents/gsd-assumptions-analyzer.md +105 -0
  12. package/agents/gsd-code-fixer.md +668 -0
  13. package/agents/gsd-code-reviewer.md +387 -0
  14. package/agents/gsd-codebase-mapper.md +853 -0
  15. package/agents/gsd-debug-session-manager.md +314 -0
  16. package/agents/gsd-debugger.md +1452 -0
  17. package/agents/gsd-doc-classifier.md +168 -0
  18. package/agents/gsd-doc-synthesizer.md +204 -0
  19. package/agents/gsd-doc-verifier.md +217 -0
  20. package/agents/gsd-doc-writer.md +616 -0
  21. package/agents/gsd-domain-researcher.md +147 -0
  22. package/agents/gsd-eval-auditor.md +191 -0
  23. package/agents/gsd-eval-planner.md +154 -0
  24. package/agents/gsd-executor.md +785 -0
  25. package/agents/gsd-framework-selector.md +160 -0
  26. package/agents/gsd-integration-checker.md +470 -0
  27. package/agents/gsd-intel-updater.md +342 -0
  28. package/agents/gsd-nyquist-auditor.md +203 -0
  29. package/agents/gsd-pattern-mapper.md +335 -0
  30. package/agents/gsd-phase-researcher.md +867 -0
  31. package/agents/gsd-plan-checker.md +978 -0
  32. package/agents/gsd-planner.md +1204 -0
  33. package/agents/gsd-project-researcher.md +611 -0
  34. package/agents/gsd-research-synthesizer.md +259 -0
  35. package/agents/gsd-roadmapper.md +688 -0
  36. package/agents/gsd-security-auditor.md +155 -0
  37. package/agents/gsd-ui-auditor.md +495 -0
  38. package/agents/gsd-ui-checker.md +309 -0
  39. package/agents/gsd-ui-researcher.md +374 -0
  40. package/agents/gsd-user-profiler.md +171 -0
  41. package/agents/gsd-verifier.md +923 -0
  42. package/assets/gsd-logo-2000-transparent.png +0 -0
  43. package/assets/gsd-logo-2000-transparent.svg +17 -0
  44. package/assets/gsd-logo-2000.png +0 -0
  45. package/assets/gsd-logo-2000.svg +21 -0
  46. package/assets/terminal.svg +68 -0
  47. package/bin/install.js +12726 -0
  48. package/bin/lib/ui-safety-gate.cjs +107 -0
  49. package/commands/gsd/add-tests.md +42 -0
  50. package/commands/gsd/ai-integration-phase.md +37 -0
  51. package/commands/gsd/audit-fix.md +34 -0
  52. package/commands/gsd/audit-milestone.md +37 -0
  53. package/commands/gsd/audit-uat.md +24 -0
  54. package/commands/gsd/autonomous.md +48 -0
  55. package/commands/gsd/capture.md +62 -0
  56. package/commands/gsd/cleanup.md +24 -0
  57. package/commands/gsd/code-review.md +59 -0
  58. package/commands/gsd/complete-milestone.md +143 -0
  59. package/commands/gsd/config.md +56 -0
  60. package/commands/gsd/debug.md +52 -0
  61. package/commands/gsd/discover-product.md +65 -0
  62. package/commands/gsd/discuss-phase.md +77 -0
  63. package/commands/gsd/docs-update.md +49 -0
  64. package/commands/gsd/eval-review.md +33 -0
  65. package/commands/gsd/execute-phase.md +66 -0
  66. package/commands/gsd/explore.md +27 -0
  67. package/commands/gsd/extract-learnings.md +23 -0
  68. package/commands/gsd/fast.md +31 -0
  69. package/commands/gsd/forensics.md +57 -0
  70. package/commands/gsd/graphify.md +204 -0
  71. package/commands/gsd/health.md +31 -0
  72. package/commands/gsd/help.md +28 -0
  73. package/commands/gsd/import.md +45 -0
  74. package/commands/gsd/inbox.md +39 -0
  75. package/commands/gsd/ingest-docs.md +42 -0
  76. package/commands/gsd/manager.md +45 -0
  77. package/commands/gsd/map-codebase.md +83 -0
  78. package/commands/gsd/milestone-summary.md +51 -0
  79. package/commands/gsd/model-domain.md +65 -0
  80. package/commands/gsd/mvp-phase.md +45 -0
  81. package/commands/gsd/new-milestone.md +45 -0
  82. package/commands/gsd/new-project.md +47 -0
  83. package/commands/gsd/ns-context.md +23 -0
  84. package/commands/gsd/ns-ideate.md +24 -0
  85. package/commands/gsd/ns-manage.md +29 -0
  86. package/commands/gsd/ns-project.md +22 -0
  87. package/commands/gsd/ns-review.md +26 -0
  88. package/commands/gsd/ns-workflow.md +28 -0
  89. package/commands/gsd/pause-work.md +43 -0
  90. package/commands/gsd/phase.md +56 -0
  91. package/commands/gsd/plan-phase.md +64 -0
  92. package/commands/gsd/plan-review-convergence.md +59 -0
  93. package/commands/gsd/pr-branch.md +26 -0
  94. package/commands/gsd/profile-user.md +46 -0
  95. package/commands/gsd/progress.md +48 -0
  96. package/commands/gsd/quick.md +174 -0
  97. package/commands/gsd/recommend-architecture.md +64 -0
  98. package/commands/gsd/resume-work.md +30 -0
  99. package/commands/gsd/review-backlog.md +63 -0
  100. package/commands/gsd/review.md +42 -0
  101. package/commands/gsd/secure-phase.md +36 -0
  102. package/commands/gsd/settings.md +29 -0
  103. package/commands/gsd/ship.md +24 -0
  104. package/commands/gsd/sketch.md +60 -0
  105. package/commands/gsd/spec-phase.md +63 -0
  106. package/commands/gsd/spike.md +57 -0
  107. package/commands/gsd/stats.md +20 -0
  108. package/commands/gsd/surface.md +155 -0
  109. package/commands/gsd/testing-strategy.md +65 -0
  110. package/commands/gsd/thread.md +24 -0
  111. package/commands/gsd/ui-phase.md +35 -0
  112. package/commands/gsd/ui-review.md +33 -0
  113. package/commands/gsd/ultraplan-phase.md +34 -0
  114. package/commands/gsd/undo.md +35 -0
  115. package/commands/gsd/update.md +49 -0
  116. package/commands/gsd/validate-phase.md +36 -0
  117. package/commands/gsd/verify-work.md +39 -0
  118. package/commands/gsd/workspace.md +52 -0
  119. package/commands/gsd/workstreams.md +70 -0
  120. package/gemini-extension.json +6 -0
  121. package/gsd-core/bin/check-latest-version.cjs +161 -0
  122. package/gsd-core/bin/gsd-tools.cjs +1928 -0
  123. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  124. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  125. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  126. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  127. package/gsd-core/bin/lib/audit.cjs +743 -0
  128. package/gsd-core/bin/lib/check-command-router.cjs +343 -0
  129. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  130. package/gsd-core/bin/lib/cli-exit.cjs +42 -0
  131. package/gsd-core/bin/lib/clock.cjs +95 -0
  132. package/gsd-core/bin/lib/clusters.cjs +132 -0
  133. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  134. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  135. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  136. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  137. package/gsd-core/bin/lib/commands.cjs +1203 -0
  138. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  139. package/gsd-core/bin/lib/config-types.cjs +19 -0
  140. package/gsd-core/bin/lib/config.cjs +738 -0
  141. package/gsd-core/bin/lib/configuration.cjs +239 -0
  142. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  143. package/gsd-core/bin/lib/core.cjs +2051 -0
  144. package/gsd-core/bin/lib/decisions.cjs +118 -0
  145. package/gsd-core/bin/lib/docs.cjs +252 -0
  146. package/gsd-core/bin/lib/drift.cjs +364 -0
  147. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  148. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  149. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  150. package/gsd-core/bin/lib/graphify.cjs +496 -0
  151. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  152. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  153. package/gsd-core/bin/lib/init.cjs +1815 -0
  154. package/gsd-core/bin/lib/install-profiles.cjs +584 -0
  155. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  156. package/gsd-core/bin/lib/installer-migration-report.cjs +350 -0
  157. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  158. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  159. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  160. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  161. package/gsd-core/bin/lib/installer-migrations.cjs +823 -0
  162. package/gsd-core/bin/lib/intel.cjs +590 -0
  163. package/gsd-core/bin/lib/learnings.cjs +270 -0
  164. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  165. package/gsd-core/bin/lib/milestone.cjs +373 -0
  166. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  167. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  168. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  169. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  170. package/gsd-core/bin/lib/observability/redaction.cjs +48 -0
  171. package/gsd-core/bin/lib/package-identity.cjs +35 -0
  172. package/gsd-core/bin/lib/package-legitimacy.cjs +368 -0
  173. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  174. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  175. package/gsd-core/bin/lib/phase.cjs +1307 -0
  176. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  177. package/gsd-core/bin/lib/plan-scan.cjs +91 -0
  178. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  179. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  180. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  181. package/gsd-core/bin/lib/project-root.cjs +119 -0
  182. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  183. package/gsd-core/bin/lib/research-provider.cjs +137 -0
  184. package/gsd-core/bin/lib/research-store.cjs +167 -0
  185. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  186. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  187. package/gsd-core/bin/lib/roadmap-upgrade.cjs +476 -0
  188. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  189. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +312 -0
  190. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +56 -0
  191. package/gsd-core/bin/lib/runtime-homes.cjs +190 -0
  192. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  193. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  194. package/gsd-core/bin/lib/schema-detect.cjs +159 -0
  195. package/gsd-core/bin/lib/secrets.cjs +34 -0
  196. package/gsd-core/bin/lib/security.cjs +480 -0
  197. package/gsd-core/bin/lib/semver-compare.cjs +42 -0
  198. package/gsd-core/bin/lib/shell-command-projection.cjs +533 -0
  199. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  200. package/gsd-core/bin/lib/state-document.cjs +259 -0
  201. package/gsd-core/bin/lib/state.cjs +2010 -0
  202. package/gsd-core/bin/lib/surface.cjs +449 -0
  203. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  204. package/gsd-core/bin/lib/template.cjs +237 -0
  205. package/gsd-core/bin/lib/uat.cjs +297 -0
  206. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  207. package/gsd-core/bin/lib/update-context.cjs +218 -0
  208. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  209. package/gsd-core/bin/lib/validate.cjs +112 -0
  210. package/gsd-core/bin/lib/verification-command-router.cjs +31 -0
  211. package/gsd-core/bin/lib/verification.cjs +193 -0
  212. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  213. package/gsd-core/bin/lib/verify.cjs +1451 -0
  214. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +81 -0
  215. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  216. package/gsd-core/bin/lib/workstream-name-policy.cjs +91 -0
  217. package/gsd-core/bin/lib/workstream.cjs +380 -0
  218. package/gsd-core/bin/lib/worktree-base-ref.cjs +325 -0
  219. package/gsd-core/bin/lib/worktree-safety.cjs +943 -0
  220. package/gsd-core/bin/shared/config-defaults.manifest.json +98 -0
  221. package/gsd-core/bin/shared/config-schema.manifest.json +192 -0
  222. package/gsd-core/bin/shared/model-catalog.json +149 -0
  223. package/gsd-core/bin/shared/runtime-aliases.manifest.json +75 -0
  224. package/gsd-core/bin/verify-reapply-patches.cjs +349 -0
  225. package/gsd-core/contexts/dev.md +21 -0
  226. package/gsd-core/contexts/research.md +22 -0
  227. package/gsd-core/contexts/review.md +23 -0
  228. package/gsd-core/references/agent-contracts.md +79 -0
  229. package/gsd-core/references/ai-evals.md +156 -0
  230. package/gsd-core/references/ai-frameworks.md +186 -0
  231. package/gsd-core/references/architecture-decision.md +74 -0
  232. package/gsd-core/references/artifact-types.md +131 -0
  233. package/gsd-core/references/auth-in-tests.md +91 -0
  234. package/gsd-core/references/autonomous-smart-discuss.md +277 -0
  235. package/gsd-core/references/checkpoints.md +814 -0
  236. package/gsd-core/references/common-bug-patterns.md +114 -0
  237. package/gsd-core/references/context-budget.md +85 -0
  238. package/gsd-core/references/continuation-format.md +253 -0
  239. package/gsd-core/references/db-test-isolation.md +54 -0
  240. package/gsd-core/references/debugger-philosophy.md +76 -0
  241. package/gsd-core/references/decimal-phase-calculation.md +64 -0
  242. package/gsd-core/references/doc-conflict-engine.md +91 -0
  243. package/gsd-core/references/domain-modeling.md +80 -0
  244. package/gsd-core/references/domain-probes.md +125 -0
  245. package/gsd-core/references/e2e-tiering.md +35 -0
  246. package/gsd-core/references/execute-mvp-tdd.md +81 -0
  247. package/gsd-core/references/executor-examples.md +110 -0
  248. package/gsd-core/references/few-shot-examples/plan-checker.md +73 -0
  249. package/gsd-core/references/few-shot-examples/verifier.md +109 -0
  250. package/gsd-core/references/flaky-test-checklist.md +22 -0
  251. package/gsd-core/references/gate-prompts.md +100 -0
  252. package/gsd-core/references/gates.md +70 -0
  253. package/gsd-core/references/git-integration.md +298 -0
  254. package/gsd-core/references/git-planning-commit.md +40 -0
  255. package/gsd-core/references/ios-scaffold.md +123 -0
  256. package/gsd-core/references/mandatory-initial-read.md +2 -0
  257. package/gsd-core/references/model-profile-resolution.md +38 -0
  258. package/gsd-core/references/model-profiles.md +245 -0
  259. package/gsd-core/references/mvp-concepts.md +49 -0
  260. package/gsd-core/references/phase-argument-parsing.md +61 -0
  261. package/gsd-core/references/planner-antipatterns.md +89 -0
  262. package/gsd-core/references/planner-chunked.md +49 -0
  263. package/gsd-core/references/planner-gap-closure.md +62 -0
  264. package/gsd-core/references/planner-graphify-auto-update.md +67 -0
  265. package/gsd-core/references/planner-human-verify-mode.md +57 -0
  266. package/gsd-core/references/planner-interface-context.md +62 -0
  267. package/gsd-core/references/planner-load-graph-context.md +36 -0
  268. package/gsd-core/references/planner-mvp-mode.md +53 -0
  269. package/gsd-core/references/planner-reviews.md +39 -0
  270. package/gsd-core/references/planner-revision.md +87 -0
  271. package/gsd-core/references/planner-source-audit.md +73 -0
  272. package/gsd-core/references/planning-config.md +473 -0
  273. package/gsd-core/references/product-discovery.md +49 -0
  274. package/gsd-core/references/project-skills-discovery.md +19 -0
  275. package/gsd-core/references/questioning.md +162 -0
  276. package/gsd-core/references/realistic-test-data.md +44 -0
  277. package/gsd-core/references/research-documentation-lookup.md +29 -0
  278. package/gsd-core/references/research-philosophy.md +29 -0
  279. package/gsd-core/references/research-verification-protocol.md +27 -0
  280. package/gsd-core/references/revision-loop.md +97 -0
  281. package/gsd-core/references/scout-codebase.md +51 -0
  282. package/gsd-core/references/skeleton-template.md +48 -0
  283. package/gsd-core/references/sketch-interactivity.md +41 -0
  284. package/gsd-core/references/sketch-theme-system.md +94 -0
  285. package/gsd-core/references/sketch-tooling.md +45 -0
  286. package/gsd-core/references/sketch-variant-patterns.md +81 -0
  287. package/gsd-core/references/spidr-splitting.md +69 -0
  288. package/gsd-core/references/tdd.md +330 -0
  289. package/gsd-core/references/test-containers.md +55 -0
  290. package/gsd-core/references/test-strategy.md +75 -0
  291. package/gsd-core/references/thinking-models-debug.md +44 -0
  292. package/gsd-core/references/thinking-models-execution.md +50 -0
  293. package/gsd-core/references/thinking-models-planning.md +62 -0
  294. package/gsd-core/references/thinking-models-research.md +50 -0
  295. package/gsd-core/references/thinking-models-verification.md +55 -0
  296. package/gsd-core/references/thinking-partner.md +96 -0
  297. package/gsd-core/references/ui-brand.md +162 -0
  298. package/gsd-core/references/universal-anti-patterns.md +63 -0
  299. package/gsd-core/references/user-profiling.md +681 -0
  300. package/gsd-core/references/user-story-template.md +58 -0
  301. package/gsd-core/references/verification-overrides.md +227 -0
  302. package/gsd-core/references/verification-patterns.md +612 -0
  303. package/gsd-core/references/verify-mvp-mode.md +85 -0
  304. package/gsd-core/references/workstream-flag.md +111 -0
  305. package/gsd-core/references/worktree-branch-check.md +38 -0
  306. package/gsd-core/references/worktree-path-safety.md +67 -0
  307. package/gsd-core/templates/AI-SPEC.md +246 -0
  308. package/gsd-core/templates/DEBUG.md +169 -0
  309. package/gsd-core/templates/README.md +77 -0
  310. package/gsd-core/templates/SECURITY.md +61 -0
  311. package/gsd-core/templates/UAT.md +265 -0
  312. package/gsd-core/templates/UI-SPEC.md +100 -0
  313. package/gsd-core/templates/VALIDATION.md +76 -0
  314. package/gsd-core/templates/adr.md +58 -0
  315. package/gsd-core/templates/claude-md.md +145 -0
  316. package/gsd-core/templates/codebase/architecture.md +255 -0
  317. package/gsd-core/templates/codebase/concerns.md +310 -0
  318. package/gsd-core/templates/codebase/conventions.md +307 -0
  319. package/gsd-core/templates/codebase/integrations.md +280 -0
  320. package/gsd-core/templates/codebase/stack.md +186 -0
  321. package/gsd-core/templates/codebase/structure.md +285 -0
  322. package/gsd-core/templates/codebase/testing.md +480 -0
  323. package/gsd-core/templates/config.json +62 -0
  324. package/gsd-core/templates/context.md +352 -0
  325. package/gsd-core/templates/continue-here.md +78 -0
  326. package/gsd-core/templates/copilot-instructions.md +7 -0
  327. package/gsd-core/templates/debug-subagent-prompt.md +91 -0
  328. package/gsd-core/templates/dev-preferences.md +21 -0
  329. package/gsd-core/templates/discovery.md +146 -0
  330. package/gsd-core/templates/discussion-log.md +63 -0
  331. package/gsd-core/templates/domain-model.md +54 -0
  332. package/gsd-core/templates/milestone-archive.md +123 -0
  333. package/gsd-core/templates/milestone.md +115 -0
  334. package/gsd-core/templates/phase-prompt.md +610 -0
  335. package/gsd-core/templates/planner-subagent-prompt.md +117 -0
  336. package/gsd-core/templates/product-brief.md +55 -0
  337. package/gsd-core/templates/project.md +186 -0
  338. package/gsd-core/templates/requirements.md +231 -0
  339. package/gsd-core/templates/research-project/ARCHITECTURE.md +204 -0
  340. package/gsd-core/templates/research-project/FEATURES.md +147 -0
  341. package/gsd-core/templates/research-project/PITFALLS.md +200 -0
  342. package/gsd-core/templates/research-project/STACK.md +120 -0
  343. package/gsd-core/templates/research-project/SUMMARY.md +170 -0
  344. package/gsd-core/templates/research.md +592 -0
  345. package/gsd-core/templates/retrospective.md +54 -0
  346. package/gsd-core/templates/roadmap.md +202 -0
  347. package/gsd-core/templates/spec.md +307 -0
  348. package/gsd-core/templates/state.md +195 -0
  349. package/gsd-core/templates/summary-complex.md +59 -0
  350. package/gsd-core/templates/summary-minimal.md +41 -0
  351. package/gsd-core/templates/summary-standard.md +48 -0
  352. package/gsd-core/templates/summary.md +248 -0
  353. package/gsd-core/templates/test-strategy.md +50 -0
  354. package/gsd-core/templates/user-profile.md +146 -0
  355. package/gsd-core/templates/user-setup.md +311 -0
  356. package/gsd-core/templates/verification-report.md +322 -0
  357. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  358. package/gsd-core/workflows/add-backlog.md +91 -0
  359. package/gsd-core/workflows/add-phase.md +113 -0
  360. package/gsd-core/workflows/add-tests.md +355 -0
  361. package/gsd-core/workflows/add-todo.md +161 -0
  362. package/gsd-core/workflows/ai-integration-phase.md +295 -0
  363. package/gsd-core/workflows/analyze-dependencies.md +96 -0
  364. package/gsd-core/workflows/audit-fix.md +178 -0
  365. package/gsd-core/workflows/audit-milestone.md +360 -0
  366. package/gsd-core/workflows/audit-uat.md +110 -0
  367. package/gsd-core/workflows/autonomous.md +797 -0
  368. package/gsd-core/workflows/check-todos.md +180 -0
  369. package/gsd-core/workflows/cleanup.md +195 -0
  370. package/gsd-core/workflows/code-review-fix.md +502 -0
  371. package/gsd-core/workflows/code-review.md +658 -0
  372. package/gsd-core/workflows/complete-milestone.md +855 -0
  373. package/gsd-core/workflows/debug.md +237 -0
  374. package/gsd-core/workflows/diagnose-issues.md +245 -0
  375. package/gsd-core/workflows/discover-product.md +112 -0
  376. package/gsd-core/workflows/discovery-phase.md +291 -0
  377. package/gsd-core/workflows/discuss-phase/modes/advisor.md +176 -0
  378. package/gsd-core/workflows/discuss-phase/modes/all.md +28 -0
  379. package/gsd-core/workflows/discuss-phase/modes/analyze.md +44 -0
  380. package/gsd-core/workflows/discuss-phase/modes/auto.md +57 -0
  381. package/gsd-core/workflows/discuss-phase/modes/batch.md +52 -0
  382. package/gsd-core/workflows/discuss-phase/modes/chain.md +98 -0
  383. package/gsd-core/workflows/discuss-phase/modes/default.md +141 -0
  384. package/gsd-core/workflows/discuss-phase/modes/power.md +44 -0
  385. package/gsd-core/workflows/discuss-phase/modes/text.md +55 -0
  386. package/gsd-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
  387. package/gsd-core/workflows/discuss-phase/templates/context.md +136 -0
  388. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
  389. package/gsd-core/workflows/discuss-phase-assumptions.md +675 -0
  390. package/gsd-core/workflows/discuss-phase-power.md +291 -0
  391. package/gsd-core/workflows/discuss-phase.md +499 -0
  392. package/gsd-core/workflows/do.md +111 -0
  393. package/gsd-core/workflows/docs-update.md +1176 -0
  394. package/gsd-core/workflows/edit-phase.md +295 -0
  395. package/gsd-core/workflows/eval-review.md +156 -0
  396. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
  397. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  398. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  399. package/gsd-core/workflows/execute-phase.md +1752 -0
  400. package/gsd-core/workflows/execute-plan.md +526 -0
  401. package/gsd-core/workflows/explore.md +146 -0
  402. package/gsd-core/workflows/extract-learnings.md +243 -0
  403. package/gsd-core/workflows/fast.md +124 -0
  404. package/gsd-core/workflows/forensics.md +279 -0
  405. package/gsd-core/workflows/graduation.md +196 -0
  406. package/gsd-core/workflows/health.md +224 -0
  407. package/gsd-core/workflows/help/modes/brief.md +22 -0
  408. package/gsd-core/workflows/help/modes/default.md +50 -0
  409. package/gsd-core/workflows/help/modes/full.md +789 -0
  410. package/gsd-core/workflows/help/modes/topic.md +74 -0
  411. package/gsd-core/workflows/help.md +24 -0
  412. package/gsd-core/workflows/import.md +256 -0
  413. package/gsd-core/workflows/inbox.md +387 -0
  414. package/gsd-core/workflows/ingest-docs.md +340 -0
  415. package/gsd-core/workflows/insert-phase.md +152 -0
  416. package/gsd-core/workflows/list-phase-assumptions.md +178 -0
  417. package/gsd-core/workflows/list-workspaces.md +57 -0
  418. package/gsd-core/workflows/manager.md +393 -0
  419. package/gsd-core/workflows/map-codebase.md +446 -0
  420. package/gsd-core/workflows/milestone-summary.md +224 -0
  421. package/gsd-core/workflows/model-domain.md +162 -0
  422. package/gsd-core/workflows/mvp-phase.md +222 -0
  423. package/gsd-core/workflows/new-milestone.md +635 -0
  424. package/gsd-core/workflows/new-project.md +1555 -0
  425. package/gsd-core/workflows/new-workspace.md +240 -0
  426. package/gsd-core/workflows/next.md +299 -0
  427. package/gsd-core/workflows/node-repair.md +92 -0
  428. package/gsd-core/workflows/note.md +158 -0
  429. package/gsd-core/workflows/pause-work.md +244 -0
  430. package/gsd-core/workflows/plan-milestone-gaps.md +281 -0
  431. package/gsd-core/workflows/plan-phase.md +1814 -0
  432. package/gsd-core/workflows/plan-review-convergence.md +346 -0
  433. package/gsd-core/workflows/plant-seed.md +230 -0
  434. package/gsd-core/workflows/pr-branch.md +157 -0
  435. package/gsd-core/workflows/profile-user.md +453 -0
  436. package/gsd-core/workflows/progress.md +699 -0
  437. package/gsd-core/workflows/quick.md +1017 -0
  438. package/gsd-core/workflows/reapply-patches.md +426 -0
  439. package/gsd-core/workflows/recommend-architecture.md +135 -0
  440. package/gsd-core/workflows/remove-phase.md +156 -0
  441. package/gsd-core/workflows/remove-workspace.md +108 -0
  442. package/gsd-core/workflows/resume-project.md +332 -0
  443. package/gsd-core/workflows/review.md +748 -0
  444. package/gsd-core/workflows/scan.md +107 -0
  445. package/gsd-core/workflows/secure-phase.md +182 -0
  446. package/gsd-core/workflows/session-report.md +146 -0
  447. package/gsd-core/workflows/settings-advanced.md +810 -0
  448. package/gsd-core/workflows/settings-integrations.md +312 -0
  449. package/gsd-core/workflows/settings.md +566 -0
  450. package/gsd-core/workflows/ship.md +405 -0
  451. package/gsd-core/workflows/sketch-wrap-up.md +286 -0
  452. package/gsd-core/workflows/sketch.md +361 -0
  453. package/gsd-core/workflows/spec-phase.md +263 -0
  454. package/gsd-core/workflows/spike-wrap-up.md +307 -0
  455. package/gsd-core/workflows/spike.md +453 -0
  456. package/gsd-core/workflows/stats.md +80 -0
  457. package/gsd-core/workflows/sync-skills.md +182 -0
  458. package/gsd-core/workflows/testing-strategy.md +122 -0
  459. package/gsd-core/workflows/thread.md +222 -0
  460. package/gsd-core/workflows/transition.md +694 -0
  461. package/gsd-core/workflows/ui-phase.md +328 -0
  462. package/gsd-core/workflows/ui-review.md +193 -0
  463. package/gsd-core/workflows/ultraplan-phase.md +199 -0
  464. package/gsd-core/workflows/undo.md +314 -0
  465. package/gsd-core/workflows/update.md +496 -0
  466. package/gsd-core/workflows/validate-phase.md +181 -0
  467. package/gsd-core/workflows/verify-phase.md +544 -0
  468. package/gsd-core/workflows/verify-work.md +781 -0
  469. package/hooks/dist/gsd-check-update-worker.js +108 -0
  470. package/hooks/dist/gsd-check-update.js +66 -0
  471. package/hooks/dist/gsd-config-reload.js +133 -0
  472. package/hooks/dist/gsd-context-monitor.js +195 -0
  473. package/hooks/dist/gsd-cursor-post-tool.js +75 -0
  474. package/hooks/dist/gsd-cursor-session-start.js +52 -0
  475. package/hooks/dist/gsd-graphify-update.sh +158 -0
  476. package/hooks/dist/gsd-phase-boundary.sh +47 -0
  477. package/hooks/dist/gsd-prompt-guard.js +97 -0
  478. package/hooks/dist/gsd-read-guard.js +101 -0
  479. package/hooks/dist/gsd-read-injection-scanner.js +203 -0
  480. package/hooks/dist/gsd-session-state.sh +59 -0
  481. package/hooks/dist/gsd-statusline.js +566 -0
  482. package/hooks/dist/gsd-update-banner.js +138 -0
  483. package/hooks/dist/gsd-validate-commit.sh +57 -0
  484. package/hooks/dist/gsd-workflow-guard.js +167 -0
  485. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  486. package/hooks/dist/lib/git-cmd.js +150 -0
  487. package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
  488. package/hooks/dist/managed-hooks-registry.cjs +38 -0
  489. package/hooks/gsd-check-update-worker.js +108 -0
  490. package/hooks/gsd-check-update.js +66 -0
  491. package/hooks/gsd-config-reload.js +133 -0
  492. package/hooks/gsd-context-monitor.js +195 -0
  493. package/hooks/gsd-cursor-post-tool.js +75 -0
  494. package/hooks/gsd-cursor-session-start.js +52 -0
  495. package/hooks/gsd-graphify-update.sh +158 -0
  496. package/hooks/gsd-phase-boundary.sh +47 -0
  497. package/hooks/gsd-prompt-guard.js +97 -0
  498. package/hooks/gsd-read-guard.js +101 -0
  499. package/hooks/gsd-read-injection-scanner.js +203 -0
  500. package/hooks/gsd-session-state.sh +59 -0
  501. package/hooks/gsd-statusline.js +566 -0
  502. package/hooks/gsd-update-banner.js +138 -0
  503. package/hooks/gsd-validate-commit.sh +57 -0
  504. package/hooks/gsd-workflow-guard.js +167 -0
  505. package/hooks/gsd-worktree-path-guard.js +169 -0
  506. package/hooks/hooks.json +69 -0
  507. package/hooks/lib/git-cmd.js +150 -0
  508. package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
  509. package/hooks/managed-hooks-registry.cjs +38 -0
  510. package/package.json +115 -0
  511. package/scripts/affected-tests-lib.cjs +542 -0
  512. package/scripts/audit-workflow-script-paths.cjs +73 -0
  513. package/scripts/base64-scan.sh +351 -0
  514. package/scripts/build-hooks.js +247 -0
  515. package/scripts/changeset/README.md +129 -0
  516. package/scripts/changeset/cli.cjs +590 -0
  517. package/scripts/changeset/github-release-notes.cjs +199 -0
  518. package/scripts/changeset/lint.cjs +111 -0
  519. package/scripts/changeset/new.cjs +137 -0
  520. package/scripts/changeset/parse.cjs +114 -0
  521. package/scripts/changeset/render.cjs +34 -0
  522. package/scripts/changeset/serialize.cjs +130 -0
  523. package/scripts/check-alias-drift.cjs +114 -0
  524. package/scripts/check-env.cjs +312 -0
  525. package/scripts/check-npm-integrity.cjs +215 -0
  526. package/scripts/ci-guard-runner.cjs +22 -0
  527. package/scripts/ci-prepare-test-scope.cjs +51 -0
  528. package/scripts/ci-rebase-check.cjs +86 -0
  529. package/scripts/ci-test-scope.cjs +431 -0
  530. package/scripts/command-contract-helpers.cjs +64 -0
  531. package/scripts/diff-touches-shipped-paths.cjs +155 -0
  532. package/scripts/fix-slash-commands.cjs +147 -0
  533. package/scripts/gen-inventory-manifest.cjs +115 -0
  534. package/scripts/gen-research-agents.cjs +276 -0
  535. package/scripts/generate-package-identity.cjs +125 -0
  536. package/scripts/issue-dedupe.cjs +278 -0
  537. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  538. package/scripts/lib/cli-exit.cjs +56 -0
  539. package/scripts/lint-command-contract.cjs +114 -0
  540. package/scripts/lint-descriptions.cjs +87 -0
  541. package/scripts/lint-docs-required.cjs +222 -0
  542. package/scripts/lint-legacy-dir-name.cjs +160 -0
  543. package/scripts/lint-package-identity-drift.cjs +141 -0
  544. package/scripts/lint-pr-check-project-dir.cjs +99 -0
  545. package/scripts/lint-shell-command-projection-drift.cjs +62 -0
  546. package/scripts/lint-skill-deps.cjs +185 -0
  547. package/scripts/lint-test-file-count.allowlist.json +135 -0
  548. package/scripts/lint-test-file-count.cjs +246 -0
  549. package/scripts/mutation-matrix.cjs +222 -0
  550. package/scripts/pr-template-policy.cjs +268 -0
  551. package/scripts/prompt-injection-scan.sh +207 -0
  552. package/scripts/release-notes/discord-release-summary.cjs +373 -0
  553. package/scripts/release-notes/format-github-release-notes.cjs +261 -0
  554. package/scripts/release-tarball-smoke.cjs +629 -0
  555. package/scripts/research-profiles.cjs +149 -0
  556. package/scripts/run-affected-tests.cjs +7 -0
  557. package/scripts/run-cross-platform-tests.cjs +67 -0
  558. package/scripts/run-tests.cjs +315 -0
  559. package/scripts/secret-scan-lint.sh +231 -0
  560. package/scripts/secret-scan.sh +358 -0
  561. package/scripts/setup-branch-protection.sh +236 -0
  562. package/scripts/strip-prose-atrefs.cjs +106 -0
  563. package/scripts/sync-manifest-versions.cjs +119 -0
  564. package/scripts/sync-rulesets.sh +34 -0
  565. package/scripts/sync-runtime-launcher.cjs +399 -0
  566. package/scripts/test-failure-reasons.cjs +34 -0
  567. package/scripts/verify-npm-publish.cjs +240 -0
  568. package/scripts/workflow-policy.cjs +450 -0
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ /**
3
+ * prompt-budget.cts
4
+ *
5
+ * Pure functions for assembling and trimming review prompts to fit within
6
+ * a token budget (ADR-457 build-at-publish: the hand-written
7
+ * bin/lib/prompt-budget.cjs collapsed to a TypeScript source of truth).
8
+ * Behaviour is preserved byte-for-behaviour from the prior hand-written .cjs;
9
+ * only types are added.
10
+ *
11
+ * Used by the review pipeline to support small-context models.
12
+ *
13
+ * Trim priority (in order — never violate):
14
+ * 1. Instructions: ALWAYS kept verbatim
15
+ * 2. Reserve note tokens FIRST when any trim is anticipated
16
+ * 3. Roadmap: ALWAYS kept verbatim
17
+ * 4. PROJECT.md: head-shrink to projectMdHeadLines (default 40) if over budget
18
+ * 5. Plans: tail-truncate proportionally; never drop a whole plan
19
+ * 6. Context: DROP first if still over
20
+ * 7. Research: DROP second if still over
21
+ * 8. Requirements: DROP last (last-resort)
22
+ * 9. Hard-fail: if minimum-set exceeds effectiveBudget
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.estimateTokens = estimateTokens;
26
+ exports.applyBudget = applyBudget;
27
+ const NOTE_RESERVE_TOKENS = 80;
28
+ const DEFAULT_NOTE_TEMPLATE = [
29
+ '<note>',
30
+ 'Prompt automatically trimmed to fit a {budget}-token budget.',
31
+ 'Omitted sections: {omittedList}.',
32
+ 'Plan content truncated by approximately {planTruncationPct}%.',
33
+ 'Treat any missing context as out-of-scope rather than a review concern.',
34
+ '</note>',
35
+ ].join('\n');
36
+ /**
37
+ * Estimate tokens for a string. Chars / 4, rounded up.
38
+ */
39
+ function estimateTokens(text) {
40
+ if (!text)
41
+ return 0;
42
+ return Math.ceil(text.length / 4);
43
+ }
44
+ /**
45
+ * Render the trim-disclosure note.
46
+ */
47
+ function renderNote(template, budget, omitted, planTruncationPct) {
48
+ const omittedList = omitted.length > 0 ? omitted.join(', ') : 'none';
49
+ return template
50
+ .replace('{budget}', String(budget))
51
+ .replace('{omittedList}', omittedList)
52
+ .replace('{planTruncationPct}', String(Math.round(planTruncationPct)));
53
+ }
54
+ /**
55
+ * Head-shrink a string to at most `maxLines` lines.
56
+ */
57
+ function headShrink(text, maxLines) {
58
+ if (maxLines <= 0)
59
+ return '';
60
+ let idx = -1;
61
+ let seen = 0;
62
+ while (seen < maxLines) {
63
+ idx = text.indexOf('\n', idx + 1);
64
+ if (idx === -1)
65
+ return text;
66
+ seen += 1;
67
+ }
68
+ return text.slice(0, idx);
69
+ }
70
+ /**
71
+ * Tail-truncate a string to at most `maxChars` characters.
72
+ */
73
+ function tailTruncate(text, maxChars) {
74
+ if (text.length <= maxChars)
75
+ return text;
76
+ return text.slice(0, maxChars);
77
+ }
78
+ /**
79
+ * Assemble the final prompt string from its sections.
80
+ */
81
+ function assemblePrompt(parts) {
82
+ const { instructions, note, roadmap, projectMd, plans, context, research, requirements, } = parts;
83
+ const blocks = [];
84
+ blocks.push(instructions);
85
+ if (note)
86
+ blocks.push(note);
87
+ blocks.push('## Roadmap\n\n' + roadmap);
88
+ if (projectMd)
89
+ blocks.push('## Project\n\n' + projectMd);
90
+ const planBlocks = plans
91
+ .map((p) => '### ' + p.file + '\n\n' + p.content)
92
+ .join('\n\n');
93
+ blocks.push('## Plans\n\n' + planBlocks);
94
+ if (context)
95
+ blocks.push('## Context\n\n' + context);
96
+ if (research)
97
+ blocks.push('## Research\n\n' + research);
98
+ if (requirements)
99
+ blocks.push('## Requirements\n\n' + requirements);
100
+ return blocks.join('\n\n');
101
+ }
102
+ /**
103
+ * Apply a token budget to a set of review prompt sections.
104
+ * Returns the trimmed prompt and structured metadata.
105
+ */
106
+ function applyBudget({ sections, budget, options = {} }) {
107
+ const { safetyMarginPct = 10, noteTemplate = DEFAULT_NOTE_TEMPLATE, projectMdHeadLines = 40, } = options;
108
+ const effectiveBudget = Math.floor(budget * (1 - safetyMarginPct / 100));
109
+ const { instructions, roadmap, plans, projectMd: projectMdRaw = null, context: contextRaw = null, research: researchRaw = null, requirements: requirementsRaw = null, } = sections;
110
+ // Working mutable state
111
+ let projectMd = projectMdRaw;
112
+ let context = contextRaw;
113
+ let research = researchRaw;
114
+ let requirements = requirementsRaw;
115
+ let workingPlans = plans.map((p) => ({ file: p.file, content: p.content }));
116
+ const omitted = [];
117
+ let projectMdShrunk = false;
118
+ let planTruncationPct = 0;
119
+ let noteInjected = false;
120
+ let hardFailed = false;
121
+ // Minimum-set check: instructions + roadmap + 1KB per plan.
122
+ // NOTE_RESERVE_TOKENS is intentionally excluded here: a note is only injected
123
+ // when trimming actually occurs, and a prompt that fits without any trim needs
124
+ // no note at all. Including NOTE_RESERVE_TOKENS here would cause false hard-fails
125
+ // for prompts that genuinely fit the effective budget untrimmed.
126
+ const MIN_PLAN_BYTES = 1024;
127
+ const minPlanTokens = plans.reduce((sum, p) => {
128
+ return sum + estimateTokens(p.content.slice(0, MIN_PLAN_BYTES));
129
+ }, 0);
130
+ const minSet = estimateTokens(instructions) +
131
+ estimateTokens(roadmap) +
132
+ minPlanTokens;
133
+ if (minSet > effectiveBudget) {
134
+ return {
135
+ prompt: '',
136
+ metadata: {
137
+ budget,
138
+ effectiveBudget,
139
+ estimatedTokens: 0,
140
+ omitted: [],
141
+ projectMdShrunk: false,
142
+ planTruncationPct: 0,
143
+ hardFailed: true,
144
+ noteInjected: false,
145
+ },
146
+ };
147
+ }
148
+ // ── Budget accounting ──────────────────────────────────────────────────────
149
+ const TOKENS_ROADMAP_HEADER = estimateTokens('## Roadmap\n\n');
150
+ const TOKENS_PROJECT_HEADER = estimateTokens('## Project\n\n');
151
+ const TOKENS_PLANS_HEADER = estimateTokens('## Plans\n\n');
152
+ const TOKENS_CONTEXT_HEADER = estimateTokens('## Context\n\n');
153
+ const TOKENS_RESEARCH_HEADER = estimateTokens('## Research\n\n');
154
+ const TOKENS_REQUIREMENTS_HEADER = estimateTokens('## Requirements\n\n');
155
+ const TOKENS_PLAN_ITEM_HEADERS = workingPlans.reduce((sum, p) => sum + estimateTokens('### ' + p.file + '\n\n'), 0);
156
+ const staticBaseTokens = estimateTokens(instructions) +
157
+ TOKENS_ROADMAP_HEADER +
158
+ estimateTokens(roadmap) +
159
+ TOKENS_PLANS_HEADER +
160
+ TOKENS_PLAN_ITEM_HEADERS;
161
+ let projectTokens = projectMd
162
+ ? TOKENS_PROJECT_HEADER + estimateTokens(projectMd)
163
+ : 0;
164
+ let contextTokens = context
165
+ ? TOKENS_CONTEXT_HEADER + estimateTokens(context)
166
+ : 0;
167
+ let researchTokens = research
168
+ ? TOKENS_RESEARCH_HEADER + estimateTokens(research)
169
+ : 0;
170
+ let requirementsTokens = requirements
171
+ ? TOKENS_REQUIREMENTS_HEADER + estimateTokens(requirements)
172
+ : 0;
173
+ let planContentTokens = workingPlans.reduce((sum, p) => sum + estimateTokens(p.content), 0);
174
+ const getCurrentBaseTokens = () => staticBaseTokens +
175
+ projectTokens +
176
+ planContentTokens +
177
+ contextTokens +
178
+ researchTokens +
179
+ requirementsTokens;
180
+ let currentBaseTokens = getCurrentBaseTokens();
181
+ // Detect budget pressure: is ANY trim needed?
182
+ // Pressure exists when the current base tokens already exceed the effective
183
+ // budget. Only when pressure is real do we reserve NOTE_RESERVE_TOKENS so
184
+ // the note itself fits after trimming. Checking against
185
+ // effectiveBudget - NOTE_RESERVE_TOKENS (the old threshold) would cause
186
+ // spurious pressure 80 tokens early, dropping sections that fit fine.
187
+ const baseTokens = currentBaseTokens;
188
+ const budgetUnderPressure = baseTokens > effectiveBudget;
189
+ // Available for content (reserve note slot when under pressure)
190
+ const contentBudget = budgetUnderPressure
191
+ ? effectiveBudget - NOTE_RESERVE_TOKENS
192
+ : effectiveBudget;
193
+ // ── Trim step 1: head-shrink PROJECT.md ───────────────────────────────────
194
+ if (currentBaseTokens > contentBudget && projectMd) {
195
+ const shrunk = headShrink(projectMd, projectMdHeadLines);
196
+ if (shrunk !== projectMd) {
197
+ projectMd = shrunk;
198
+ projectMdShrunk = true;
199
+ projectTokens = TOKENS_PROJECT_HEADER + estimateTokens(projectMd);
200
+ currentBaseTokens = getCurrentBaseTokens();
201
+ }
202
+ }
203
+ // ── Trim step 2: proportional plan truncation ─────────────────────────────
204
+ if (currentBaseTokens > contentBudget) {
205
+ // Compute tokens available for plan content only
206
+ const overhead = staticBaseTokens +
207
+ projectTokens +
208
+ contextTokens +
209
+ researchTokens +
210
+ requirementsTokens;
211
+ const planBudgetTokens = contentBudget - overhead;
212
+ const totalPlanTokens = planContentTokens;
213
+ if (planBudgetTokens > 0 && planBudgetTokens < totalPlanTokens) {
214
+ // Proportional share per plan (at least 1KB per plan)
215
+ const totalOriginalChars = plans.reduce((sum, p) => sum + p.content.length, 0);
216
+ const totalPlanCharsBudget = planBudgetTokens * 4;
217
+ workingPlans = workingPlans.map((p) => {
218
+ const proportionalShare = totalOriginalChars > 0
219
+ ? Math.floor((p.content.length / totalOriginalChars) * totalPlanCharsBudget)
220
+ : 0;
221
+ const maxChars = Math.max(proportionalShare, MIN_PLAN_BYTES);
222
+ return { file: p.file, content: tailTruncate(p.content, maxChars) };
223
+ });
224
+ const newTotalChars = workingPlans.reduce((sum, p) => sum + p.content.length, 0);
225
+ if (totalOriginalChars > 0) {
226
+ planTruncationPct =
227
+ ((totalOriginalChars - newTotalChars) / totalOriginalChars) * 100;
228
+ }
229
+ planContentTokens = workingPlans.reduce((sum, p) => sum + estimateTokens(p.content), 0);
230
+ currentBaseTokens = getCurrentBaseTokens();
231
+ }
232
+ }
233
+ // ── Trim step 3: drop context ─────────────────────────────────────────────
234
+ if (currentBaseTokens > contentBudget && context) {
235
+ context = null;
236
+ omitted.push('context');
237
+ contextTokens = 0;
238
+ currentBaseTokens = getCurrentBaseTokens();
239
+ }
240
+ // ── Trim step 4: drop research ────────────────────────────────────────────
241
+ if (currentBaseTokens > contentBudget && research) {
242
+ research = null;
243
+ omitted.push('research');
244
+ researchTokens = 0;
245
+ currentBaseTokens = getCurrentBaseTokens();
246
+ }
247
+ // ── Trim step 5: drop requirements (last resort) ──────────────────────────
248
+ if (currentBaseTokens > contentBudget && requirements) {
249
+ requirements = null;
250
+ omitted.push('requirements');
251
+ requirementsTokens = 0;
252
+ currentBaseTokens = getCurrentBaseTokens();
253
+ }
254
+ // ── Decide whether note is actually needed ────────────────────────────────
255
+ const anyTrimOccurred = omitted.length > 0 || projectMdShrunk || planTruncationPct > 0;
256
+ let note = null;
257
+ if (anyTrimOccurred) {
258
+ note = renderNote(noteTemplate, budget, omitted, planTruncationPct);
259
+ noteInjected = true;
260
+ }
261
+ // Suppress unused variable warning — currentBaseTokens is used via the
262
+ // closure in getCurrentBaseTokens(); the final value is not used directly.
263
+ void currentBaseTokens;
264
+ // ── Assemble ──────────────────────────────────────────────────────────────
265
+ const prompt = assemblePrompt({
266
+ instructions,
267
+ note,
268
+ roadmap,
269
+ projectMd,
270
+ plans: workingPlans,
271
+ context,
272
+ research,
273
+ requirements,
274
+ });
275
+ const estimatedTokens = estimateTokens(prompt);
276
+ if (estimatedTokens > effectiveBudget) {
277
+ hardFailed = true;
278
+ return {
279
+ prompt: '',
280
+ metadata: {
281
+ budget,
282
+ effectiveBudget,
283
+ estimatedTokens,
284
+ omitted,
285
+ projectMdShrunk,
286
+ planTruncationPct,
287
+ hardFailed,
288
+ noteInjected,
289
+ },
290
+ };
291
+ }
292
+ return {
293
+ prompt,
294
+ metadata: {
295
+ budget,
296
+ effectiveBudget,
297
+ estimatedTokens,
298
+ omitted,
299
+ projectMdShrunk,
300
+ planTruncationPct,
301
+ hardFailed,
302
+ noteInjected,
303
+ },
304
+ };
305
+ }
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ /**
3
+ * Research Provider Module
4
+ *
5
+ * Encodes the Balanced-set provider decision: PROVIDER_WATERFALL constant,
6
+ * classifyConfidence, providerAvailability, and planResearch (with injectable
7
+ * store for testability).
8
+ *
9
+ * ADR-457 build-at-publish: authored as TypeScript .cts → emits .cjs via tsc.
10
+ */
11
+ // ---------------------------------------------------------------------------
12
+ // Cycle 1 / Cycle 6: PROVIDER_WATERFALL (Balanced-set decision)
13
+ // firecrawl appears ONLY in scrape — demoted to known-URL scrape, NOT in docs/web
14
+ // ---------------------------------------------------------------------------
15
+ const PROVIDER_WATERFALL = {
16
+ docs: ['context7', 'ref', 'jina', 'websearch'],
17
+ web: ['exa', 'tavily', 'perplexity', 'brave', 'websearch'],
18
+ scrape: ['firecrawl', 'jina'],
19
+ };
20
+ function authorityOf(provider) {
21
+ switch (provider) {
22
+ case 'context7':
23
+ case 'ref':
24
+ return 'official';
25
+ case 'jina':
26
+ case 'firecrawl':
27
+ return 'scrape';
28
+ case 'exa':
29
+ case 'tavily':
30
+ case 'perplexity':
31
+ case 'brave':
32
+ case 'websearch':
33
+ return 'web';
34
+ default:
35
+ return 'none';
36
+ }
37
+ }
38
+ function normalizeLegitimacyVerdict(raw) {
39
+ if (typeof raw !== 'string')
40
+ return null;
41
+ const upper = raw.toUpperCase();
42
+ if (upper === 'OK' || upper === 'SUS' || upper === 'SLOP')
43
+ return upper;
44
+ return null;
45
+ }
46
+ function classifyConfidence(input) {
47
+ try {
48
+ const { provider, verifiedAgainstOfficial, legitimacyVerdict } = input;
49
+ const authority = authorityOf(provider);
50
+ const verdict = normalizeLegitimacyVerdict(legitimacyVerdict);
51
+ const groundTruth = verdict === 'OK';
52
+ // SLOP caps everything — checked first
53
+ if (verdict === 'SLOP')
54
+ return 'LOW';
55
+ // Ground-truth corroboration + known authority → HIGH
56
+ if (groundTruth && authority !== 'none')
57
+ return 'HIGH';
58
+ // Official or scrape provider (authority alone) → MEDIUM
59
+ if (authority === 'official' || authority === 'scrape')
60
+ return 'MEDIUM';
61
+ // Ground-truth but unknown provider → MEDIUM
62
+ if (groundTruth)
63
+ return 'MEDIUM';
64
+ // Web provider with self-reported verification → MEDIUM
65
+ if (authority === 'web' && verifiedAgainstOfficial === true)
66
+ return 'MEDIUM';
67
+ return 'LOW';
68
+ }
69
+ catch {
70
+ return 'LOW';
71
+ }
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // Cycle 5: providerAvailability
75
+ // ---------------------------------------------------------------------------
76
+ function providerAvailability(config) {
77
+ const cfg = config ?? {};
78
+ return {
79
+ context7: true,
80
+ jina: cfg.jina !== undefined ? Boolean(cfg.jina) : true,
81
+ websearch: true,
82
+ exa: Boolean(cfg.exa_search),
83
+ tavily: Boolean(cfg.tavily_search),
84
+ brave: Boolean(cfg.brave_search),
85
+ firecrawl: Boolean(cfg.firecrawl),
86
+ ref: Boolean(cfg.ref_search),
87
+ perplexity: Boolean(cfg.perplexity),
88
+ };
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // Lazy-load default store (avoids circular require at module eval time)
92
+ // ---------------------------------------------------------------------------
93
+ let _defaultStore;
94
+ function getDefaultStore() {
95
+ if (!_defaultStore) {
96
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- lazy default store; tests inject their own
97
+ _defaultStore = require('./research-store.cjs');
98
+ }
99
+ return _defaultStore;
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Cycle 1–3, 5, 7: planResearch
103
+ // ---------------------------------------------------------------------------
104
+ function planResearch(options) {
105
+ const { questions, ecosystem = '', cwd, config, clock = Date, homeDir, store = getDefaultStore(), } = options;
106
+ const availability = providerAvailability(config);
107
+ const items = questions.flatMap((q) => {
108
+ const { text, kind, library, version } = q;
109
+ // Skip questions without a non-empty string text — emitting an item with
110
+ // question:undefined / fetch.query:undefined would produce corrupt output.
111
+ if (typeof text !== 'string' || text.length === 0) {
112
+ return [];
113
+ }
114
+ const key = store.researchKey({ ecosystem, library, version, query: text, kind });
115
+ const res = store.getResearch(cwd, key, { clock, homeDir, kind });
116
+ // Fresh cache hit — no fetch needed
117
+ if (res.hit && !res.stale) {
118
+ return { question: text, key, cache: { hit: true, stale: false } };
119
+ }
120
+ // Determine which waterfall to use
121
+ const waterfall = PROVIDER_WATERFALL[kind] ?? PROVIDER_WATERFALL.web;
122
+ // Pick first available provider
123
+ const provider = waterfall.find((p) => availability[p] === true) ?? 'websearch';
124
+ const item = {
125
+ question: text,
126
+ key,
127
+ fetch: { provider, query: text },
128
+ };
129
+ // Stale hit: include cache info
130
+ if (res.hit) {
131
+ item.cache = { hit: true, stale: true };
132
+ }
133
+ return item;
134
+ });
135
+ return { items };
136
+ }
137
+ module.exports = { PROVIDER_WATERFALL, classifyConfidence, providerAvailability, planResearch };
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ /**
3
+ * Research Store Module
4
+ *
5
+ * Provides deterministic cache key generation, TTL policy, path resolution,
6
+ * and JSON-backed put/get operations for research entries.
7
+ *
8
+ * ADR-457 build-at-publish: authored as TypeScript .cts → emits .cjs via tsc.
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ const node_fs_1 = __importDefault(require("node:fs"));
14
+ const node_os_1 = __importDefault(require("node:os"));
15
+ const node_path_1 = __importDefault(require("node:path"));
16
+ const node_crypto_1 = __importDefault(require("node:crypto"));
17
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
18
+ // ---------------------------------------------------------------------------
19
+ // Constants
20
+ // ---------------------------------------------------------------------------
21
+ const DAY_MS = 86_400_000;
22
+ // ---------------------------------------------------------------------------
23
+ // researchKey
24
+ // ---------------------------------------------------------------------------
25
+ function normalize(x) {
26
+ if (x === null || x === undefined)
27
+ return '';
28
+ if (typeof x === 'object')
29
+ return JSON.stringify(x).trim().toLowerCase();
30
+ // After excluding null, undefined, and object, x can only be a primitive —
31
+ // cast through number | string | boolean to avoid no-base-to-string on unknown.
32
+ return `${x}`.trim().toLowerCase();
33
+ }
34
+ function researchKey(input) {
35
+ const parts = {
36
+ ecosystem: normalize(input.ecosystem),
37
+ library: normalize(input.library),
38
+ version: normalize(input.version),
39
+ query: normalize(input.query),
40
+ kind: normalize(input.kind),
41
+ };
42
+ const serialized = JSON.stringify(parts);
43
+ return node_crypto_1.default.createHash('sha256').update(serialized).digest('hex');
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // ttlForSource
47
+ // ---------------------------------------------------------------------------
48
+ function ttlForSource(source, confidence) {
49
+ if (source === 'curated' && confidence === 'HIGH')
50
+ return 30 * DAY_MS;
51
+ if (source === 'curated' && confidence === 'MEDIUM')
52
+ return 7 * DAY_MS;
53
+ return DAY_MS;
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // tierForSource / resolveStorePath
57
+ // ---------------------------------------------------------------------------
58
+ const CURATED_SOURCES = new Set(['curated']);
59
+ function tierForSource(source) {
60
+ return CURATED_SOURCES.has(source) ? 'user' : 'project';
61
+ }
62
+ function resolveStorePath(cwd, source, { homeDir = node_os_1.default.homedir() } = {}) {
63
+ if (tierForSource(source) === 'user') {
64
+ return node_path_1.default.join(homeDir, '.gsd', 'research-cache');
65
+ }
66
+ return node_path_1.default.join(cwd, '.planning', 'research', '.cache');
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // isValidResearchKey
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * Returns true iff key is a valid 64-character lowercase hexadecimal SHA-256
73
+ * string (the exact shape produced by researchKey). Any other shape —
74
+ * including path-traversal sequences — is rejected.
75
+ */
76
+ function isValidResearchKey(key) {
77
+ return typeof key === 'string' && /^[0-9a-f]{64}$/.test(key);
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // putResearch
81
+ // ---------------------------------------------------------------------------
82
+ function putResearch(cwd, key, payload, { clock = Date, homeDir = node_os_1.default.homedir() } = {}) {
83
+ // Defense-in-depth: reject any key that is not a 64-char sha256 hex string.
84
+ if (!isValidResearchKey(key)) {
85
+ throw new Error('invalid research key');
86
+ }
87
+ const { content, source, provider, confidence, kind, version } = payload;
88
+ let ttl = ttlForSource(source, confidence);
89
+ // Cap TTL when version is blank/missing — a versionless curated entry must not
90
+ // get the long 30-day window since we can't know if it's still current.
91
+ if (!version) {
92
+ ttl = Math.min(ttl, DAY_MS);
93
+ }
94
+ const fetched_at = new Date(clock.now()).toISOString();
95
+ const entry = { content, source, provider, confidence, fetched_at, ttl, kind };
96
+ const dir = resolveStorePath(cwd, source, { homeDir });
97
+ // Belt-and-suspenders: ensure the resolved file path stays inside the store dir.
98
+ const resolvedDir = node_path_1.default.resolve(dir);
99
+ const filePath = node_path_1.default.join(dir, `${key}.json`);
100
+ const resolvedFile = node_path_1.default.resolve(filePath);
101
+ if (!resolvedFile.startsWith(resolvedDir + node_path_1.default.sep)) {
102
+ throw new Error('invalid research key');
103
+ }
104
+ node_fs_1.default.mkdirSync(dir, { recursive: true });
105
+ (0, shell_command_projection_cjs_1.platformWriteSync)(filePath, JSON.stringify(entry));
106
+ return entry;
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // getResearch
110
+ // ---------------------------------------------------------------------------
111
+ function getResearch(cwd, key, { clock = Date, homeDir = node_os_1.default.homedir() } = {}) {
112
+ // Defense-in-depth: reject any key that is not a 64-char sha256 hex string.
113
+ if (!isValidResearchKey(key)) {
114
+ return { hit: false, stale: false, entry: null };
115
+ }
116
+ try {
117
+ // Search both physical tiers: user (curated) and project (web/etc.)
118
+ const userDir = node_path_1.default.join(homeDir, '.gsd', 'research-cache');
119
+ const projectDir = node_path_1.default.join(cwd, '.planning', 'research', '.cache');
120
+ const tierDirs = [userDir, projectDir];
121
+ const candidates = [];
122
+ for (const dir of tierDirs) {
123
+ const resolvedDir = node_path_1.default.resolve(dir);
124
+ const filePath = node_path_1.default.join(dir, `${key}.json`);
125
+ // Belt-and-suspenders: ensure path stays inside tier dir
126
+ if (!node_path_1.default.resolve(filePath).startsWith(resolvedDir + node_path_1.default.sep))
127
+ continue;
128
+ if (!node_fs_1.default.existsSync(filePath))
129
+ continue;
130
+ let entry;
131
+ try {
132
+ entry = JSON.parse(node_fs_1.default.readFileSync(filePath, 'utf8'));
133
+ }
134
+ catch {
135
+ // Corrupt file in this tier — skip it
136
+ continue;
137
+ }
138
+ // Finding 3: validate entry metadata shape before accepting as a candidate.
139
+ // An entry with missing/invalid fetched_at or ttl must be treated as a miss.
140
+ const parsedFetchedAt = Date.parse(entry.fetched_at);
141
+ if (!Number.isFinite(parsedFetchedAt))
142
+ continue;
143
+ if (typeof entry.ttl !== 'number' ||
144
+ !Number.isFinite(entry.ttl) ||
145
+ entry.ttl <= 0)
146
+ continue;
147
+ const age = clock.now() - parsedFetchedAt;
148
+ const stale = age > entry.ttl;
149
+ candidates.push({ entry, stale, age });
150
+ }
151
+ if (candidates.length === 0) {
152
+ return { hit: false, stale: false, entry: null };
153
+ }
154
+ // Prefer: non-stale over stale; among same-staleness, lowest age (most recent)
155
+ candidates.sort((a, b) => {
156
+ if (a.stale !== b.stale)
157
+ return a.stale ? 1 : -1; // non-stale first
158
+ return a.age - b.age; // lower age (more recent) first
159
+ });
160
+ const best = candidates[0];
161
+ return { hit: true, stale: best.stale, entry: best.entry };
162
+ }
163
+ catch {
164
+ return { hit: false, stale: false, entry: null };
165
+ }
166
+ }
167
+ module.exports = { isValidResearchKey, researchKey, ttlForSource, tierForSource, resolveStorePath, putResearch, getResearch };