@opengsd/gsd-core 1.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja-JP.md +870 -0
  3. package/README.ko-KR.md +861 -0
  4. package/README.md +301 -0
  5. package/README.pt-BR.md +492 -0
  6. package/README.zh-CN.md +842 -0
  7. package/agents/gsd-advisor-researcher.md +127 -0
  8. package/agents/gsd-ai-researcher.md +133 -0
  9. package/agents/gsd-assumptions-analyzer.md +105 -0
  10. package/agents/gsd-code-fixer.md +668 -0
  11. package/agents/gsd-code-reviewer.md +387 -0
  12. package/agents/gsd-codebase-mapper.md +853 -0
  13. package/agents/gsd-debug-session-manager.md +314 -0
  14. package/agents/gsd-debugger.md +1452 -0
  15. package/agents/gsd-doc-classifier.md +168 -0
  16. package/agents/gsd-doc-synthesizer.md +204 -0
  17. package/agents/gsd-doc-verifier.md +217 -0
  18. package/agents/gsd-doc-writer.md +615 -0
  19. package/agents/gsd-domain-researcher.md +153 -0
  20. package/agents/gsd-eval-auditor.md +191 -0
  21. package/agents/gsd-eval-planner.md +154 -0
  22. package/agents/gsd-executor.md +772 -0
  23. package/agents/gsd-framework-selector.md +160 -0
  24. package/agents/gsd-integration-checker.md +470 -0
  25. package/agents/gsd-intel-updater.md +342 -0
  26. package/agents/gsd-nyquist-auditor.md +203 -0
  27. package/agents/gsd-pattern-mapper.md +335 -0
  28. package/agents/gsd-phase-researcher.md +928 -0
  29. package/agents/gsd-plan-checker.md +978 -0
  30. package/agents/gsd-planner.md +1218 -0
  31. package/agents/gsd-project-researcher.md +677 -0
  32. package/agents/gsd-research-synthesizer.md +255 -0
  33. package/agents/gsd-roadmapper.md +688 -0
  34. package/agents/gsd-security-auditor.md +155 -0
  35. package/agents/gsd-ui-auditor.md +495 -0
  36. package/agents/gsd-ui-checker.md +309 -0
  37. package/agents/gsd-ui-researcher.md +380 -0
  38. package/agents/gsd-user-profiler.md +171 -0
  39. package/agents/gsd-verifier.md +917 -0
  40. package/bin/install.js +10936 -0
  41. package/bin/lib/ui-safety-gate.cjs +107 -0
  42. package/commands/gsd/add-tests.md +42 -0
  43. package/commands/gsd/ai-integration-phase.md +37 -0
  44. package/commands/gsd/audit-fix.md +34 -0
  45. package/commands/gsd/audit-milestone.md +37 -0
  46. package/commands/gsd/audit-uat.md +24 -0
  47. package/commands/gsd/autonomous.md +46 -0
  48. package/commands/gsd/capture.md +62 -0
  49. package/commands/gsd/cleanup.md +24 -0
  50. package/commands/gsd/code-review.md +59 -0
  51. package/commands/gsd/complete-milestone.md +143 -0
  52. package/commands/gsd/config.md +56 -0
  53. package/commands/gsd/debug.md +52 -0
  54. package/commands/gsd/discuss-phase.md +76 -0
  55. package/commands/gsd/docs-update.md +49 -0
  56. package/commands/gsd/eval-review.md +33 -0
  57. package/commands/gsd/execute-phase.md +64 -0
  58. package/commands/gsd/explore.md +27 -0
  59. package/commands/gsd/extract-learnings.md +23 -0
  60. package/commands/gsd/fast.md +31 -0
  61. package/commands/gsd/forensics.md +57 -0
  62. package/commands/gsd/graphify.md +199 -0
  63. package/commands/gsd/health.md +31 -0
  64. package/commands/gsd/help.md +28 -0
  65. package/commands/gsd/import.md +41 -0
  66. package/commands/gsd/inbox.md +39 -0
  67. package/commands/gsd/ingest-docs.md +42 -0
  68. package/commands/gsd/manager.md +45 -0
  69. package/commands/gsd/map-codebase.md +83 -0
  70. package/commands/gsd/milestone-summary.md +51 -0
  71. package/commands/gsd/mvp-phase.md +45 -0
  72. package/commands/gsd/new-milestone.md +45 -0
  73. package/commands/gsd/new-project.md +47 -0
  74. package/commands/gsd/ns-context.md +23 -0
  75. package/commands/gsd/ns-ideate.md +24 -0
  76. package/commands/gsd/ns-manage.md +29 -0
  77. package/commands/gsd/ns-project.md +22 -0
  78. package/commands/gsd/ns-review.md +26 -0
  79. package/commands/gsd/ns-workflow.md +28 -0
  80. package/commands/gsd/pause-work.md +43 -0
  81. package/commands/gsd/phase.md +56 -0
  82. package/commands/gsd/plan-phase.md +62 -0
  83. package/commands/gsd/plan-review-convergence.md +59 -0
  84. package/commands/gsd/pr-branch.md +26 -0
  85. package/commands/gsd/profile-user.md +46 -0
  86. package/commands/gsd/progress.md +47 -0
  87. package/commands/gsd/quick.md +174 -0
  88. package/commands/gsd/resume-work.md +30 -0
  89. package/commands/gsd/review-backlog.md +63 -0
  90. package/commands/gsd/review.md +41 -0
  91. package/commands/gsd/secure-phase.md +36 -0
  92. package/commands/gsd/settings.md +29 -0
  93. package/commands/gsd/ship.md +24 -0
  94. package/commands/gsd/sketch.md +60 -0
  95. package/commands/gsd/spec-phase.md +63 -0
  96. package/commands/gsd/spike.md +57 -0
  97. package/commands/gsd/stats.md +19 -0
  98. package/commands/gsd/surface.md +155 -0
  99. package/commands/gsd/thread.md +24 -0
  100. package/commands/gsd/ui-phase.md +35 -0
  101. package/commands/gsd/ui-review.md +33 -0
  102. package/commands/gsd/ultraplan-phase.md +34 -0
  103. package/commands/gsd/undo.md +35 -0
  104. package/commands/gsd/update.md +48 -0
  105. package/commands/gsd/validate-phase.md +36 -0
  106. package/commands/gsd/verify-work.md +39 -0
  107. package/commands/gsd/workspace.md +52 -0
  108. package/commands/gsd/workstreams.md +70 -0
  109. package/get-shit-done/bin/check-latest-version.cjs +106 -0
  110. package/get-shit-done/bin/gsd-tools.cjs +1676 -0
  111. package/get-shit-done/bin/lib/active-workstream-store.cjs +302 -0
  112. package/get-shit-done/bin/lib/adr-parser.cjs +394 -0
  113. package/get-shit-done/bin/lib/agent-command-router.cjs +65 -0
  114. package/get-shit-done/bin/lib/artifacts.cjs +53 -0
  115. package/get-shit-done/bin/lib/audit.cjs +755 -0
  116. package/get-shit-done/bin/lib/check-command-router.cjs +333 -0
  117. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +118 -0
  118. package/get-shit-done/bin/lib/clock.cjs +96 -0
  119. package/get-shit-done/bin/lib/clusters.cjs +135 -0
  120. package/get-shit-done/bin/lib/code-review-flags.cjs +74 -0
  121. package/get-shit-done/bin/lib/command-aliases.cjs +815 -0
  122. package/get-shit-done/bin/lib/command-arg-projection.cjs +62 -0
  123. package/get-shit-done/bin/lib/command-routing-hub.cjs +388 -0
  124. package/get-shit-done/bin/lib/commands.cjs +1188 -0
  125. package/get-shit-done/bin/lib/config-schema.cjs +31 -0
  126. package/get-shit-done/bin/lib/config.cjs +728 -0
  127. package/get-shit-done/bin/lib/configuration.cjs +248 -0
  128. package/get-shit-done/bin/lib/context-utilization.cjs +47 -0
  129. package/get-shit-done/bin/lib/core.cjs +2121 -0
  130. package/get-shit-done/bin/lib/decisions.cjs +116 -0
  131. package/get-shit-done/bin/lib/docs.cjs +270 -0
  132. package/get-shit-done/bin/lib/drift.cjs +388 -0
  133. package/get-shit-done/bin/lib/fallow-runner.cjs +109 -0
  134. package/get-shit-done/bin/lib/frontmatter.cjs +389 -0
  135. package/get-shit-done/bin/lib/gap-checker.cjs +205 -0
  136. package/get-shit-done/bin/lib/graphify.cjs +592 -0
  137. package/get-shit-done/bin/lib/gsd2-import.cjs +514 -0
  138. package/get-shit-done/bin/lib/init-command-router.cjs +58 -0
  139. package/get-shit-done/bin/lib/init.cjs +2112 -0
  140. package/get-shit-done/bin/lib/install-profiles.cjs +603 -0
  141. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +117 -0
  142. package/get-shit-done/bin/lib/installer-migration-report.cjs +354 -0
  143. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
  144. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
  145. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
  146. package/get-shit-done/bin/lib/installer-migrations.cjs +778 -0
  147. package/get-shit-done/bin/lib/intel.cjs +708 -0
  148. package/get-shit-done/bin/lib/learnings.cjs +421 -0
  149. package/get-shit-done/bin/lib/milestone.cjs +314 -0
  150. package/get-shit-done/bin/lib/model-catalog.cjs +212 -0
  151. package/get-shit-done/bin/lib/model-profiles.cjs +31 -0
  152. package/get-shit-done/bin/lib/observability/event.cjs +82 -0
  153. package/get-shit-done/bin/lib/observability/logger.cjs +174 -0
  154. package/get-shit-done/bin/lib/observability/redaction.cjs +50 -0
  155. package/get-shit-done/bin/lib/package-identity.cjs +31 -0
  156. package/get-shit-done/bin/lib/phase-command-router.cjs +191 -0
  157. package/get-shit-done/bin/lib/phase-lifecycle.cjs +80 -0
  158. package/get-shit-done/bin/lib/phase.cjs +1607 -0
  159. package/get-shit-done/bin/lib/phases-command-router.cjs +39 -0
  160. package/get-shit-done/bin/lib/plan-scan.cjs +97 -0
  161. package/get-shit-done/bin/lib/planning-workspace.cjs +238 -0
  162. package/get-shit-done/bin/lib/profile-output.cjs +1141 -0
  163. package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
  164. package/get-shit-done/bin/lib/project-root.cjs +112 -0
  165. package/get-shit-done/bin/lib/prompt-budget.cjs +399 -0
  166. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +125 -0
  167. package/get-shit-done/bin/lib/roadmap-command-router.cjs +28 -0
  168. package/get-shit-done/bin/lib/roadmap.cjs +650 -0
  169. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +301 -0
  170. package/get-shit-done/bin/lib/runtime-homes.cjs +222 -0
  171. package/get-shit-done/bin/lib/runtime-name-policy.cjs +83 -0
  172. package/get-shit-done/bin/lib/runtime-slash.cjs +112 -0
  173. package/get-shit-done/bin/lib/schema-detect.cjs +165 -0
  174. package/get-shit-done/bin/lib/secrets.cjs +32 -0
  175. package/get-shit-done/bin/lib/security.cjs +600 -0
  176. package/get-shit-done/bin/lib/semver-compare.cjs +35 -0
  177. package/get-shit-done/bin/lib/shell-command-projection.cjs +500 -0
  178. package/get-shit-done/bin/lib/state-command-router.cjs +252 -0
  179. package/get-shit-done/bin/lib/state-document.cjs +263 -0
  180. package/get-shit-done/bin/lib/state.cjs +2038 -0
  181. package/get-shit-done/bin/lib/surface.cjs +470 -0
  182. package/get-shit-done/bin/lib/task-command-router.cjs +81 -0
  183. package/get-shit-done/bin/lib/template.cjs +228 -0
  184. package/get-shit-done/bin/lib/uat.cjs +289 -0
  185. package/get-shit-done/bin/lib/update-context.cjs +209 -0
  186. package/get-shit-done/bin/lib/validate-command-router.cjs +83 -0
  187. package/get-shit-done/bin/lib/validate.cjs +92 -0
  188. package/get-shit-done/bin/lib/verify-command-router.cjs +40 -0
  189. package/get-shit-done/bin/lib/verify.cjs +1511 -0
  190. package/get-shit-done/bin/lib/workstream-inventory-builder.cjs +74 -0
  191. package/get-shit-done/bin/lib/workstream-inventory.cjs +146 -0
  192. package/get-shit-done/bin/lib/workstream-name-policy.cjs +94 -0
  193. package/get-shit-done/bin/lib/workstream.cjs +389 -0
  194. package/get-shit-done/bin/lib/worktree-safety.cjs +985 -0
  195. package/get-shit-done/bin/shared/config-defaults.manifest.json +97 -0
  196. package/get-shit-done/bin/shared/config-schema.manifest.json +175 -0
  197. package/get-shit-done/bin/shared/model-catalog.json +122 -0
  198. package/get-shit-done/bin/shared/runtime-aliases.manifest.json +75 -0
  199. package/get-shit-done/bin/verify-reapply-patches.cjs +352 -0
  200. package/get-shit-done/contexts/dev.md +21 -0
  201. package/get-shit-done/contexts/research.md +22 -0
  202. package/get-shit-done/contexts/review.md +23 -0
  203. package/get-shit-done/references/agent-contracts.md +79 -0
  204. package/get-shit-done/references/ai-evals.md +156 -0
  205. package/get-shit-done/references/ai-frameworks.md +186 -0
  206. package/get-shit-done/references/artifact-types.md +131 -0
  207. package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
  208. package/get-shit-done/references/checkpoints.md +814 -0
  209. package/get-shit-done/references/common-bug-patterns.md +114 -0
  210. package/get-shit-done/references/context-budget.md +85 -0
  211. package/get-shit-done/references/continuation-format.md +253 -0
  212. package/get-shit-done/references/debugger-philosophy.md +76 -0
  213. package/get-shit-done/references/decimal-phase-calculation.md +64 -0
  214. package/get-shit-done/references/doc-conflict-engine.md +91 -0
  215. package/get-shit-done/references/domain-probes.md +125 -0
  216. package/get-shit-done/references/execute-mvp-tdd.md +81 -0
  217. package/get-shit-done/references/executor-examples.md +110 -0
  218. package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
  219. package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
  220. package/get-shit-done/references/gate-prompts.md +100 -0
  221. package/get-shit-done/references/gates.md +70 -0
  222. package/get-shit-done/references/git-integration.md +298 -0
  223. package/get-shit-done/references/git-planning-commit.md +40 -0
  224. package/get-shit-done/references/ios-scaffold.md +123 -0
  225. package/get-shit-done/references/mandatory-initial-read.md +2 -0
  226. package/get-shit-done/references/model-profile-resolution.md +38 -0
  227. package/get-shit-done/references/model-profiles.md +245 -0
  228. package/get-shit-done/references/mvp-concepts.md +49 -0
  229. package/get-shit-done/references/phase-argument-parsing.md +61 -0
  230. package/get-shit-done/references/planner-antipatterns.md +89 -0
  231. package/get-shit-done/references/planner-chunked.md +49 -0
  232. package/get-shit-done/references/planner-gap-closure.md +62 -0
  233. package/get-shit-done/references/planner-graphify-auto-update.md +67 -0
  234. package/get-shit-done/references/planner-human-verify-mode.md +57 -0
  235. package/get-shit-done/references/planner-interface-context.md +62 -0
  236. package/get-shit-done/references/planner-mvp-mode.md +53 -0
  237. package/get-shit-done/references/planner-reviews.md +39 -0
  238. package/get-shit-done/references/planner-revision.md +87 -0
  239. package/get-shit-done/references/planner-source-audit.md +73 -0
  240. package/get-shit-done/references/planning-config.md +471 -0
  241. package/get-shit-done/references/project-skills-discovery.md +19 -0
  242. package/get-shit-done/references/questioning.md +162 -0
  243. package/get-shit-done/references/revision-loop.md +97 -0
  244. package/get-shit-done/references/scout-codebase.md +51 -0
  245. package/get-shit-done/references/skeleton-template.md +48 -0
  246. package/get-shit-done/references/sketch-interactivity.md +41 -0
  247. package/get-shit-done/references/sketch-theme-system.md +94 -0
  248. package/get-shit-done/references/sketch-tooling.md +45 -0
  249. package/get-shit-done/references/sketch-variant-patterns.md +81 -0
  250. package/get-shit-done/references/spidr-splitting.md +69 -0
  251. package/get-shit-done/references/tdd.md +330 -0
  252. package/get-shit-done/references/thinking-models-debug.md +44 -0
  253. package/get-shit-done/references/thinking-models-execution.md +50 -0
  254. package/get-shit-done/references/thinking-models-planning.md +62 -0
  255. package/get-shit-done/references/thinking-models-research.md +50 -0
  256. package/get-shit-done/references/thinking-models-verification.md +55 -0
  257. package/get-shit-done/references/thinking-partner.md +96 -0
  258. package/get-shit-done/references/ui-brand.md +160 -0
  259. package/get-shit-done/references/universal-anti-patterns.md +63 -0
  260. package/get-shit-done/references/user-profiling.md +681 -0
  261. package/get-shit-done/references/user-story-template.md +58 -0
  262. package/get-shit-done/references/verification-overrides.md +227 -0
  263. package/get-shit-done/references/verification-patterns.md +612 -0
  264. package/get-shit-done/references/verify-mvp-mode.md +85 -0
  265. package/get-shit-done/references/workstream-flag.md +111 -0
  266. package/get-shit-done/references/worktree-path-safety.md +89 -0
  267. package/get-shit-done/templates/AI-SPEC.md +246 -0
  268. package/get-shit-done/templates/DEBUG.md +169 -0
  269. package/get-shit-done/templates/README.md +77 -0
  270. package/get-shit-done/templates/SECURITY.md +61 -0
  271. package/get-shit-done/templates/UAT.md +265 -0
  272. package/get-shit-done/templates/UI-SPEC.md +100 -0
  273. package/get-shit-done/templates/VALIDATION.md +76 -0
  274. package/get-shit-done/templates/claude-md.md +145 -0
  275. package/get-shit-done/templates/codebase/architecture.md +255 -0
  276. package/get-shit-done/templates/codebase/concerns.md +310 -0
  277. package/get-shit-done/templates/codebase/conventions.md +307 -0
  278. package/get-shit-done/templates/codebase/integrations.md +280 -0
  279. package/get-shit-done/templates/codebase/stack.md +186 -0
  280. package/get-shit-done/templates/codebase/structure.md +285 -0
  281. package/get-shit-done/templates/codebase/testing.md +480 -0
  282. package/get-shit-done/templates/config.json +62 -0
  283. package/get-shit-done/templates/context.md +352 -0
  284. package/get-shit-done/templates/continue-here.md +78 -0
  285. package/get-shit-done/templates/copilot-instructions.md +7 -0
  286. package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
  287. package/get-shit-done/templates/dev-preferences.md +21 -0
  288. package/get-shit-done/templates/discovery.md +146 -0
  289. package/get-shit-done/templates/discussion-log.md +63 -0
  290. package/get-shit-done/templates/milestone-archive.md +123 -0
  291. package/get-shit-done/templates/milestone.md +115 -0
  292. package/get-shit-done/templates/phase-prompt.md +610 -0
  293. package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
  294. package/get-shit-done/templates/project.md +186 -0
  295. package/get-shit-done/templates/requirements.md +231 -0
  296. package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
  297. package/get-shit-done/templates/research-project/FEATURES.md +147 -0
  298. package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
  299. package/get-shit-done/templates/research-project/STACK.md +120 -0
  300. package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
  301. package/get-shit-done/templates/research.md +592 -0
  302. package/get-shit-done/templates/retrospective.md +54 -0
  303. package/get-shit-done/templates/roadmap.md +202 -0
  304. package/get-shit-done/templates/spec.md +307 -0
  305. package/get-shit-done/templates/state.md +195 -0
  306. package/get-shit-done/templates/summary-complex.md +59 -0
  307. package/get-shit-done/templates/summary-minimal.md +41 -0
  308. package/get-shit-done/templates/summary-standard.md +48 -0
  309. package/get-shit-done/templates/summary.md +248 -0
  310. package/get-shit-done/templates/user-profile.md +146 -0
  311. package/get-shit-done/templates/user-setup.md +311 -0
  312. package/get-shit-done/templates/verification-report.md +322 -0
  313. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +1 -0
  314. package/get-shit-done/workflows/add-backlog.md +91 -0
  315. package/get-shit-done/workflows/add-phase.md +113 -0
  316. package/get-shit-done/workflows/add-tests.md +355 -0
  317. package/get-shit-done/workflows/add-todo.md +161 -0
  318. package/get-shit-done/workflows/ai-integration-phase.md +295 -0
  319. package/get-shit-done/workflows/analyze-dependencies.md +96 -0
  320. package/get-shit-done/workflows/audit-fix.md +178 -0
  321. package/get-shit-done/workflows/audit-milestone.md +358 -0
  322. package/get-shit-done/workflows/audit-uat.md +110 -0
  323. package/get-shit-done/workflows/autonomous.md +795 -0
  324. package/get-shit-done/workflows/check-todos.md +180 -0
  325. package/get-shit-done/workflows/cleanup.md +155 -0
  326. package/get-shit-done/workflows/code-review-fix.md +502 -0
  327. package/get-shit-done/workflows/code-review.md +656 -0
  328. package/get-shit-done/workflows/complete-milestone.md +855 -0
  329. package/get-shit-done/workflows/debug.md +232 -0
  330. package/get-shit-done/workflows/diagnose-issues.md +241 -0
  331. package/get-shit-done/workflows/discovery-phase.md +291 -0
  332. package/get-shit-done/workflows/discuss-phase/modes/advisor.md +176 -0
  333. package/get-shit-done/workflows/discuss-phase/modes/all.md +28 -0
  334. package/get-shit-done/workflows/discuss-phase/modes/analyze.md +44 -0
  335. package/get-shit-done/workflows/discuss-phase/modes/auto.md +57 -0
  336. package/get-shit-done/workflows/discuss-phase/modes/batch.md +52 -0
  337. package/get-shit-done/workflows/discuss-phase/modes/chain.md +98 -0
  338. package/get-shit-done/workflows/discuss-phase/modes/default.md +141 -0
  339. package/get-shit-done/workflows/discuss-phase/modes/power.md +44 -0
  340. package/get-shit-done/workflows/discuss-phase/modes/text.md +55 -0
  341. package/get-shit-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
  342. package/get-shit-done/workflows/discuss-phase/templates/context.md +136 -0
  343. package/get-shit-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
  344. package/get-shit-done/workflows/discuss-phase-assumptions.md +675 -0
  345. package/get-shit-done/workflows/discuss-phase-power.md +291 -0
  346. package/get-shit-done/workflows/discuss-phase.md +499 -0
  347. package/get-shit-done/workflows/do.md +111 -0
  348. package/get-shit-done/workflows/docs-update.md +1162 -0
  349. package/get-shit-done/workflows/edit-phase.md +295 -0
  350. package/get-shit-done/workflows/eval-review.md +156 -0
  351. package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +82 -0
  352. package/get-shit-done/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  353. package/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  354. package/get-shit-done/workflows/execute-phase.md +1709 -0
  355. package/get-shit-done/workflows/execute-plan.md +526 -0
  356. package/get-shit-done/workflows/explore.md +144 -0
  357. package/get-shit-done/workflows/extract-learnings.md +243 -0
  358. package/get-shit-done/workflows/fast.md +124 -0
  359. package/get-shit-done/workflows/forensics.md +279 -0
  360. package/get-shit-done/workflows/graduation.md +196 -0
  361. package/get-shit-done/workflows/health.md +224 -0
  362. package/get-shit-done/workflows/help/modes/brief.md +22 -0
  363. package/get-shit-done/workflows/help/modes/default.md +50 -0
  364. package/get-shit-done/workflows/help/modes/full.md +784 -0
  365. package/get-shit-done/workflows/help/modes/topic.md +74 -0
  366. package/get-shit-done/workflows/help.md +24 -0
  367. package/get-shit-done/workflows/import.md +254 -0
  368. package/get-shit-done/workflows/inbox.md +387 -0
  369. package/get-shit-done/workflows/ingest-docs.md +339 -0
  370. package/get-shit-done/workflows/insert-phase.md +152 -0
  371. package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
  372. package/get-shit-done/workflows/list-workspaces.md +57 -0
  373. package/get-shit-done/workflows/manager.md +393 -0
  374. package/get-shit-done/workflows/map-codebase.md +444 -0
  375. package/get-shit-done/workflows/milestone-summary.md +224 -0
  376. package/get-shit-done/workflows/mvp-phase.md +222 -0
  377. package/get-shit-done/workflows/new-milestone.md +635 -0
  378. package/get-shit-done/workflows/new-project.md +1555 -0
  379. package/get-shit-done/workflows/new-workspace.md +240 -0
  380. package/get-shit-done/workflows/next.md +299 -0
  381. package/get-shit-done/workflows/node-repair.md +92 -0
  382. package/get-shit-done/workflows/note.md +158 -0
  383. package/get-shit-done/workflows/pause-work.md +244 -0
  384. package/get-shit-done/workflows/plan-milestone-gaps.md +281 -0
  385. package/get-shit-done/workflows/plan-phase.md +1809 -0
  386. package/get-shit-done/workflows/plan-review-convergence.md +346 -0
  387. package/get-shit-done/workflows/plant-seed.md +230 -0
  388. package/get-shit-done/workflows/pr-branch.md +157 -0
  389. package/get-shit-done/workflows/profile-user.md +453 -0
  390. package/get-shit-done/workflows/progress.md +699 -0
  391. package/get-shit-done/workflows/quick.md +1039 -0
  392. package/get-shit-done/workflows/reapply-patches.md +426 -0
  393. package/get-shit-done/workflows/remove-phase.md +156 -0
  394. package/get-shit-done/workflows/remove-workspace.md +108 -0
  395. package/get-shit-done/workflows/resume-project.md +332 -0
  396. package/get-shit-done/workflows/review.md +623 -0
  397. package/get-shit-done/workflows/scan.md +105 -0
  398. package/get-shit-done/workflows/secure-phase.md +180 -0
  399. package/get-shit-done/workflows/session-report.md +146 -0
  400. package/get-shit-done/workflows/settings-advanced.md +620 -0
  401. package/get-shit-done/workflows/settings-integrations.md +312 -0
  402. package/get-shit-done/workflows/settings.md +552 -0
  403. package/get-shit-done/workflows/ship.md +356 -0
  404. package/get-shit-done/workflows/sketch-wrap-up.md +286 -0
  405. package/get-shit-done/workflows/sketch.md +361 -0
  406. package/get-shit-done/workflows/spec-phase.md +262 -0
  407. package/get-shit-done/workflows/spike-wrap-up.md +307 -0
  408. package/get-shit-done/workflows/spike.md +453 -0
  409. package/get-shit-done/workflows/stats.md +80 -0
  410. package/get-shit-done/workflows/sync-skills.md +182 -0
  411. package/get-shit-done/workflows/thread.md +222 -0
  412. package/get-shit-done/workflows/transition.md +694 -0
  413. package/get-shit-done/workflows/ui-phase.md +328 -0
  414. package/get-shit-done/workflows/ui-review.md +193 -0
  415. package/get-shit-done/workflows/ultraplan-phase.md +199 -0
  416. package/get-shit-done/workflows/undo.md +314 -0
  417. package/get-shit-done/workflows/update.md +443 -0
  418. package/get-shit-done/workflows/validate-phase.md +179 -0
  419. package/get-shit-done/workflows/verify-phase.md +544 -0
  420. package/get-shit-done/workflows/verify-work.md +781 -0
  421. package/hooks/dist/gsd-check-update-worker.js +95 -0
  422. package/hooks/dist/gsd-check-update.js +64 -0
  423. package/hooks/dist/gsd-context-monitor.js +195 -0
  424. package/hooks/dist/gsd-graphify-update.sh +158 -0
  425. package/hooks/dist/gsd-phase-boundary.sh +47 -0
  426. package/hooks/dist/gsd-prompt-guard.js +97 -0
  427. package/hooks/dist/gsd-read-guard.js +101 -0
  428. package/hooks/dist/gsd-read-injection-scanner.js +203 -0
  429. package/hooks/dist/gsd-session-state.sh +59 -0
  430. package/hooks/dist/gsd-statusline.js +548 -0
  431. package/hooks/dist/gsd-update-banner.js +134 -0
  432. package/hooks/dist/gsd-validate-commit.sh +57 -0
  433. package/hooks/dist/gsd-workflow-guard.js +166 -0
  434. package/hooks/dist/lib/git-cmd.js +150 -0
  435. package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
  436. package/hooks/gsd-check-update-worker.js +95 -0
  437. package/hooks/gsd-check-update.js +64 -0
  438. package/hooks/gsd-context-monitor.js +195 -0
  439. package/hooks/gsd-graphify-update.sh +158 -0
  440. package/hooks/gsd-phase-boundary.sh +47 -0
  441. package/hooks/gsd-prompt-guard.js +97 -0
  442. package/hooks/gsd-read-guard.js +101 -0
  443. package/hooks/gsd-read-injection-scanner.js +203 -0
  444. package/hooks/gsd-session-state.sh +59 -0
  445. package/hooks/gsd-statusline.js +548 -0
  446. package/hooks/gsd-update-banner.js +134 -0
  447. package/hooks/gsd-validate-commit.sh +57 -0
  448. package/hooks/gsd-workflow-guard.js +166 -0
  449. package/hooks/lib/git-cmd.js +150 -0
  450. package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
  451. package/hooks/managed-hooks-registry.cjs +34 -0
  452. package/package.json +102 -0
  453. package/scripts/affected-tests-lib.cjs +541 -0
  454. package/scripts/audit-workflow-script-paths.cjs +73 -0
  455. package/scripts/base64-scan.sh +339 -0
  456. package/scripts/build-hooks.js +236 -0
  457. package/scripts/changeset/README.md +129 -0
  458. package/scripts/changeset/cli.cjs +392 -0
  459. package/scripts/changeset/github-release-notes.cjs +199 -0
  460. package/scripts/changeset/lint.cjs +110 -0
  461. package/scripts/changeset/new.cjs +137 -0
  462. package/scripts/changeset/parse.cjs +114 -0
  463. package/scripts/changeset/render.cjs +34 -0
  464. package/scripts/changeset/serialize.cjs +130 -0
  465. package/scripts/check-alias-drift.cjs +108 -0
  466. package/scripts/check-env.cjs +302 -0
  467. package/scripts/check-npm-integrity.cjs +209 -0
  468. package/scripts/ci-guard-runner.cjs +16 -0
  469. package/scripts/ci-prepare-test-scope.cjs +46 -0
  470. package/scripts/ci-rebase-check.cjs +85 -0
  471. package/scripts/ci-test-scope.cjs +302 -0
  472. package/scripts/command-contract-helpers.cjs +64 -0
  473. package/scripts/diff-touches-shipped-paths.cjs +147 -0
  474. package/scripts/fix-slash-commands.cjs +147 -0
  475. package/scripts/gen-inventory-manifest.cjs +109 -0
  476. package/scripts/generate-package-identity.cjs +104 -0
  477. package/scripts/lint-command-contract.cjs +108 -0
  478. package/scripts/lint-descriptions.cjs +83 -0
  479. package/scripts/lint-docs-required.cjs +222 -0
  480. package/scripts/lint-no-source-grep-extras.cjs +81 -0
  481. package/scripts/lint-no-source-grep.cjs +174 -0
  482. package/scripts/lint-package-identity-drift.cjs +141 -0
  483. package/scripts/lint-pr-check-project-dir.cjs +98 -0
  484. package/scripts/lint-shared-module-handsync.cjs +388 -0
  485. package/scripts/lint-shell-command-projection-drift.cjs +57 -0
  486. package/scripts/lint-skill-deps.cjs +180 -0
  487. package/scripts/lint-test-file-count.allowlist.json +36 -0
  488. package/scripts/lint-test-file-count.cjs +190 -0
  489. package/scripts/pr-template-policy.cjs +268 -0
  490. package/scripts/prompt-injection-scan.sh +203 -0
  491. package/scripts/release-tarball-smoke.cjs +627 -0
  492. package/scripts/run-affected-tests.cjs +6 -0
  493. package/scripts/run-cross-platform-tests.cjs +63 -0
  494. package/scripts/run-tests.cjs +282 -0
  495. package/scripts/secret-scan-lint.sh +231 -0
  496. package/scripts/secret-scan.sh +358 -0
  497. package/scripts/setup-branch-protection.sh +236 -0
  498. package/scripts/shared-module-handsync-allowlist.json +183 -0
  499. package/scripts/strip-prose-atrefs.cjs +106 -0
  500. package/scripts/sync-rulesets.sh +34 -0
  501. package/scripts/sync-runtime-launcher.cjs +402 -0
  502. package/scripts/test-failure-reasons.cjs +34 -0
  503. package/scripts/workflow-policy.cjs +450 -0
@@ -0,0 +1,708 @@
1
+ /**
2
+ * lib/intel.cjs -- Intel storage and query operations for GSD.
3
+ *
4
+ * Provides a persistent, queryable intelligence system for project metadata.
5
+ * Intel files live in .planning/intel/ and store structured data about
6
+ * the project's files, APIs, dependencies, architecture, and tech stack.
7
+ *
8
+ * All public functions gate on intel.enabled config (no-op when false).
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const crypto = require('crypto');
16
+ const { platformWriteSync, platformReadSync, platformEnsureDir } = require('./shell-command-projection.cjs');
17
+
18
+ // ─── Constants ───────────────────────────────────────────────────────────────
19
+
20
+ const INTEL_DIR = '.planning/intel';
21
+
22
+ const INTEL_FILES = {
23
+ files: 'file-roles.json',
24
+ apis: 'api-map.json',
25
+ deps: 'dependency-graph.json',
26
+ arch: 'arch-decisions.json',
27
+ stack: 'stack.json'
28
+ };
29
+
30
+ // ─── Internal helpers ────────────────────────────────────────────────────────
31
+
32
+ /**
33
+ * Ensure the intel directory exists under the given planning dir.
34
+ *
35
+ * @param {string} planningDir - Path to .planning directory
36
+ * @returns {string} Full path to .planning/intel/
37
+ */
38
+ function ensureIntelDir(planningDir) {
39
+ const intelPath = path.join(planningDir, 'intel');
40
+ platformEnsureDir(intelPath);
41
+ return intelPath;
42
+ }
43
+
44
+ /**
45
+ * Check whether intel is enabled in the project config.
46
+ * Reads config.json directly via fs. Returns false by default
47
+ * (when no config, no intel key, or on error).
48
+ *
49
+ * @param {string} planningDir - Path to .planning directory
50
+ * @returns {boolean}
51
+ */
52
+ function isIntelEnabled(planningDir) {
53
+ try {
54
+ const configPath = path.join(planningDir, 'config.json');
55
+ const raw = platformReadSync(configPath);
56
+ if (raw === null) return false;
57
+ const config = JSON.parse(raw);
58
+ if (config && config.intel && config.intel.enabled === true) return true;
59
+ return false;
60
+ } catch (_e) {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Return the standard disabled response object.
67
+ * @returns {{ disabled: true, message: string }}
68
+ */
69
+ function disabledResponse() {
70
+ return { disabled: true, message: 'Intel system disabled. Set intel.enabled=true in config.json to activate.' };
71
+ }
72
+
73
+ /**
74
+ * Resolve full path to an intel file.
75
+ * @param {string} planningDir
76
+ * @param {string} filename
77
+ * @returns {string}
78
+ */
79
+ function intelFilePath(planningDir, filename) {
80
+ return path.join(planningDir, 'intel', filename);
81
+ }
82
+
83
+ /**
84
+ * Safely read and parse a JSON intel file.
85
+ * Returns null if file doesn't exist or can't be parsed.
86
+ *
87
+ * @param {string} filePath
88
+ * @returns {object|null}
89
+ */
90
+ function safeReadJson(filePath) {
91
+ try {
92
+ const raw = platformReadSync(filePath);
93
+ if (raw === null) return null;
94
+ return JSON.parse(raw);
95
+ } catch (_e) {
96
+ return null;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Compute SHA-256 hash of a file's contents.
102
+ * Returns null if the file doesn't exist.
103
+ *
104
+ * @param {string} filePath
105
+ * @returns {string|null}
106
+ */
107
+ function hashFile(filePath) {
108
+ try {
109
+ const content = platformReadSync(filePath);
110
+ if (content === null) return null;
111
+ return crypto.createHash('sha256').update(content).digest('hex');
112
+ } catch (_e) {
113
+ return null;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Search for a term (case-insensitive) in a JSON object's keys and string values.
119
+ * Returns an array of matching entries.
120
+ *
121
+ * @param {object} data - The JSON data (expects { _meta, entries } or flat object)
122
+ * @param {string} term - Search term
123
+ * @returns {Array<{ key: string, value: * }>}
124
+ */
125
+ function searchJsonEntries(data, term) {
126
+ if (!data || typeof data !== 'object') return [];
127
+
128
+ const entries = data.entries || data;
129
+ if (!entries || typeof entries !== 'object') return [];
130
+
131
+ const lowerTerm = term.toLowerCase();
132
+ const matches = [];
133
+
134
+ for (const [key, value] of Object.entries(entries)) {
135
+ if (key === '_meta') continue;
136
+
137
+ // Check key match
138
+ if (key.toLowerCase().includes(lowerTerm)) {
139
+ matches.push({ key, value });
140
+ continue;
141
+ }
142
+
143
+ // Check string value match (recursive for objects)
144
+ if (matchesInValue(value, lowerTerm)) {
145
+ matches.push({ key, value });
146
+ }
147
+ }
148
+
149
+ return matches;
150
+ }
151
+
152
+ /**
153
+ * Recursively check if a term appears in any string value.
154
+ *
155
+ * @param {*} value
156
+ * @param {string} lowerTerm
157
+ * @returns {boolean}
158
+ */
159
+ function matchesInValue(value, lowerTerm) {
160
+ if (typeof value === 'string') {
161
+ return value.toLowerCase().includes(lowerTerm);
162
+ }
163
+ if (Array.isArray(value)) {
164
+ return value.some(v => matchesInValue(v, lowerTerm));
165
+ }
166
+ if (value && typeof value === 'object') {
167
+ return Object.values(value).some(v => matchesInValue(v, lowerTerm));
168
+ }
169
+ return false;
170
+ }
171
+
172
+ /**
173
+ * Search for a term in arch.md text content.
174
+ * Returns matching lines.
175
+ *
176
+ * @param {string} filePath - Path to arch.md
177
+ * @param {string} term - Search term
178
+ * @returns {string[]}
179
+ */
180
+ function searchArchMd(filePath, term) {
181
+ try {
182
+ const content = platformReadSync(filePath);
183
+ if (content === null) return [];
184
+ const lowerTerm = term.toLowerCase();
185
+ const lines = content.split(/\r?\n/);
186
+ return lines.filter(line => line.toLowerCase().includes(lowerTerm));
187
+ } catch (_e) {
188
+ return [];
189
+ }
190
+ }
191
+
192
+ // ─── Public API ──────────────────────────────────────────────────────────────
193
+
194
+ /**
195
+ * Query intel files for a search term.
196
+ * Searches across all JSON intel files (keys and values) and arch.md (text lines).
197
+ *
198
+ * @param {string} term - Search term (case-insensitive)
199
+ * @param {string} planningDir - Path to .planning directory
200
+ * @returns {{ matches: Array<{ source: string, entries: Array }>, term: string, total: number } | { disabled: true, message: string }}
201
+ */
202
+ function intelQuery(term, planningDir) {
203
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
204
+
205
+ const matches = [];
206
+ let total = 0;
207
+
208
+ // Search all JSON intel files
209
+ for (const [_key, filename] of Object.entries(INTEL_FILES)) {
210
+ const filePath = intelFilePath(planningDir, filename);
211
+ const data = safeReadJson(filePath);
212
+ if (!data) continue;
213
+
214
+ const found = searchJsonEntries(data, term);
215
+ if (found.length > 0) {
216
+ matches.push({ source: filename, entries: found });
217
+ total += found.length;
218
+ }
219
+ }
220
+
221
+ return { matches, term, total };
222
+ }
223
+
224
+ /**
225
+ * Report status and staleness of each intel file.
226
+ * A file is considered stale if its updated_at is older than 24 hours.
227
+ *
228
+ * @param {string} planningDir - Path to .planning directory
229
+ * @returns {{ files: object, overall_stale: boolean } | { disabled: true, message: string }}
230
+ */
231
+ function intelStatus(planningDir) {
232
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
233
+
234
+ const STALE_MS = 24 * 60 * 60 * 1000; // 24 hours
235
+ const now = Date.now();
236
+ const files = {};
237
+ let overallStale = false;
238
+
239
+ for (const [_key, filename] of Object.entries(INTEL_FILES)) {
240
+ const filePath = intelFilePath(planningDir, filename);
241
+ const exists = fs.existsSync(filePath);
242
+
243
+ if (!exists) {
244
+ files[filename] = { exists: false, updated_at: null, stale: true };
245
+ overallStale = true;
246
+ continue;
247
+ }
248
+
249
+ let updatedAt = null;
250
+
251
+ // All intel files are JSON — read _meta.updated_at
252
+ const data = safeReadJson(filePath);
253
+ if (data && data._meta && data._meta.updated_at) {
254
+ updatedAt = data._meta.updated_at;
255
+ }
256
+
257
+ let stale = true;
258
+ if (updatedAt) {
259
+ const age = now - new Date(updatedAt).getTime();
260
+ stale = age > STALE_MS;
261
+ }
262
+
263
+ if (stale) overallStale = true;
264
+ files[filename] = { exists: true, updated_at: updatedAt, stale };
265
+ }
266
+
267
+ return { files, overall_stale: overallStale };
268
+ }
269
+
270
+ /**
271
+ * Show changes since the last full refresh by comparing file hashes.
272
+ *
273
+ * @param {string} planningDir - Path to .planning directory
274
+ * @returns {{ changed: string[], added: string[], removed: string[] } | { no_baseline: true } | { disabled: true, message: string }}
275
+ */
276
+ function intelDiff(planningDir) {
277
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
278
+
279
+ const snapshotPath = intelFilePath(planningDir, '.last-refresh.json');
280
+ const snapshot = safeReadJson(snapshotPath);
281
+
282
+ if (!snapshot) {
283
+ return { no_baseline: true };
284
+ }
285
+
286
+ const prevHashes = snapshot.hashes || {};
287
+ const changed = [];
288
+ const added = [];
289
+ const removed = [];
290
+
291
+ // Check current files against snapshot
292
+ for (const [_key, filename] of Object.entries(INTEL_FILES)) {
293
+ const filePath = intelFilePath(planningDir, filename);
294
+ const currentHash = hashFile(filePath);
295
+
296
+ if (currentHash && !prevHashes[filename]) {
297
+ added.push(filename);
298
+ } else if (currentHash && prevHashes[filename] && currentHash !== prevHashes[filename]) {
299
+ changed.push(filename);
300
+ } else if (!currentHash && prevHashes[filename]) {
301
+ removed.push(filename);
302
+ }
303
+ }
304
+
305
+ return { changed, added, removed };
306
+ }
307
+
308
+ /**
309
+ * Stub for triggering an intel update.
310
+ * The actual update is performed by the intel-updater agent (PLAN-02).
311
+ *
312
+ * @param {string} planningDir - Path to .planning directory
313
+ * @returns {{ action: string, message: string } | { disabled: true, message: string }}
314
+ */
315
+ function intelUpdate(planningDir) {
316
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
317
+
318
+ return {
319
+ action: 'spawn_agent',
320
+ message: 'Run gsd-tools intel update or spawn gsd-intel-updater agent for full refresh'
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Save a refresh snapshot with hashes of all current intel files.
326
+ * Called by the intel-updater agent after completing a refresh.
327
+ *
328
+ * @param {string} planningDir - Path to .planning directory
329
+ * @returns {{ saved: boolean, timestamp: string, files: number }}
330
+ */
331
+ function saveRefreshSnapshot(planningDir) {
332
+ const intelPath = ensureIntelDir(planningDir);
333
+ const hashes = {};
334
+ let fileCount = 0;
335
+
336
+ for (const [_key, filename] of Object.entries(INTEL_FILES)) {
337
+ const filePath = path.join(intelPath, filename);
338
+ const hash = hashFile(filePath);
339
+ if (hash) {
340
+ hashes[filename] = hash;
341
+ fileCount++;
342
+ }
343
+ }
344
+
345
+ const timestamp = new Date().toISOString();
346
+ const snapshotPath = path.join(intelPath, '.last-refresh.json');
347
+ platformWriteSync(snapshotPath, JSON.stringify({
348
+ hashes,
349
+ timestamp,
350
+ version: 1
351
+ }, null, 2));
352
+
353
+ return { saved: true, timestamp, files: fileCount };
354
+ }
355
+
356
+ // ─── CLI Subcommands ─────────────────────────────────────────────────────────
357
+
358
+ /**
359
+ * Thin wrapper around saveRefreshSnapshot for CLI dispatch.
360
+ * Writes .last-refresh.json with accurate timestamps and hashes.
361
+ *
362
+ * @param {string} planningDir - Path to .planning directory
363
+ * @returns {{ saved: boolean, timestamp: string, files: number } | { disabled: true, message: string }}
364
+ */
365
+ function intelSnapshot(planningDir) {
366
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
367
+ return saveRefreshSnapshot(planningDir);
368
+ }
369
+
370
+ /**
371
+ * Validate all intel files for correctness and freshness.
372
+ *
373
+ * @param {string} planningDir - Path to .planning directory
374
+ * @returns {{ valid: boolean, errors: string[], warnings: string[] } | { disabled: true, message: string }}
375
+ */
376
+ function intelValidate(planningDir) {
377
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
378
+
379
+ const errors = [];
380
+ const warnings = [];
381
+ const STALE_MS = 24 * 60 * 60 * 1000;
382
+ const now = Date.now();
383
+
384
+ for (const [key, filename] of Object.entries(INTEL_FILES)) {
385
+ const filePath = intelFilePath(planningDir, filename);
386
+
387
+ // Check existence
388
+ if (!fs.existsSync(filePath)) {
389
+ errors.push(`${filename}: file does not exist`);
390
+ continue;
391
+ }
392
+
393
+ // All intel files are JSON — validate _meta and entries structure
394
+
395
+ // Parse JSON
396
+ const raw = platformReadSync(filePath);
397
+ if (raw === null) {
398
+ errors.push(`${filename}: file missing`);
399
+ continue;
400
+ }
401
+ let data;
402
+ try {
403
+ data = JSON.parse(raw);
404
+ } catch (e) {
405
+ errors.push(`${filename}: invalid JSON — ${e.message}`);
406
+ continue;
407
+ }
408
+
409
+ // Check _meta.updated_at recency
410
+ if (data._meta && data._meta.updated_at) {
411
+ const age = now - new Date(data._meta.updated_at).getTime();
412
+ if (age > STALE_MS) {
413
+ warnings.push(`${filename}: _meta.updated_at is ${Math.round(age / 3600000)} hours old (>24 hr)`);
414
+ }
415
+ } else {
416
+ warnings.push(`${filename}: missing _meta.updated_at`);
417
+ }
418
+
419
+ // Validate entries are objects with expected fields
420
+ if (data.entries && typeof data.entries === 'object') {
421
+ // files.json: check exports are actual symbol names (no spaces)
422
+ if (key === 'files') {
423
+ for (const [entryPath, entry] of Object.entries(data.entries)) {
424
+ if (entry.exports && Array.isArray(entry.exports)) {
425
+ for (const exp of entry.exports) {
426
+ if (typeof exp === 'string' && exp.includes(' ')) {
427
+ warnings.push(`${filename}: "${entryPath}" export "${exp}" looks like a description (contains space)`);
428
+ }
429
+ }
430
+ }
431
+ }
432
+ // Spot-check first 5 file paths exist on disk
433
+ const entryPaths = Object.keys(data.entries).slice(0, 5);
434
+ for (const ep of entryPaths) {
435
+ if (!fs.existsSync(ep)) {
436
+ warnings.push(`${filename}: entry path "${ep}" does not exist on disk`);
437
+ }
438
+ }
439
+ }
440
+
441
+ // deps.json: check entries have version, type, used_by
442
+ if (key === 'deps') {
443
+ for (const [depName, entry] of Object.entries(data.entries)) {
444
+ const missing = [];
445
+ if (!entry.version) missing.push('version');
446
+ if (!entry.type) missing.push('type');
447
+ if (!entry.used_by) missing.push('used_by');
448
+ if (missing.length > 0) {
449
+ warnings.push(`${filename}: "${depName}" missing fields: ${missing.join(', ')}`);
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ return { valid: errors.length === 0, errors, warnings };
457
+ }
458
+
459
+ /**
460
+ * Render .planning/intel/api-map.json into a human-readable API-SURFACE.md.
461
+ * Always writes the file — even when api-map.json is absent or empty, the
462
+ * surface will contain an explicit "incomplete" banner so consumers never
463
+ * mistake silence for "nothing exists".
464
+ *
465
+ * @param {string} planningDir - Path to .planning directory
466
+ * @returns {{ written: string, symbolCount: number, stale: boolean } | { disabled: true, message: string }}
467
+ */
468
+ function intelApiSurface(planningDir) {
469
+ if (!isIntelEnabled(planningDir)) return disabledResponse();
470
+
471
+ const intelPath = ensureIntelDir(planningDir);
472
+ const apiMapPath = path.join(intelPath, INTEL_FILES.apis);
473
+ const outputPath = path.join(intelPath, 'API-SURFACE.md');
474
+
475
+ const data = safeReadJson(apiMapPath);
476
+ const entries = (data && data.entries && typeof data.entries === 'object')
477
+ ? Object.entries(data.entries)
478
+ : [];
479
+ const symbolCount = entries.length;
480
+
481
+ // Staleness: reuse the _meta.updated_at field if present
482
+ const STALE_MS = 24 * 60 * 60 * 1000;
483
+ let stale = true;
484
+ if (data && data._meta && data._meta.updated_at) {
485
+ const age = Date.now() - new Date(data._meta.updated_at).getTime();
486
+ stale = age > STALE_MS;
487
+ }
488
+
489
+ const lines = [];
490
+ lines.push('# API Surface');
491
+ lines.push('');
492
+ lines.push('> Generated from `.planning/intel/api-map.json`. Do not edit by hand.');
493
+ lines.push('');
494
+
495
+ if (symbolCount === 0) {
496
+ lines.push('> **Incomplete:** api-map.json has no entries (intel extraction is regex/JS-only or not yet populated).');
497
+ lines.push('> Treat absence here as "unknown", not "does not exist".');
498
+ lines.push('');
499
+ } else {
500
+ if (stale) {
501
+ lines.push('> **Warning:** api-map.json is stale (>24 hours old). Data below may be out of date.');
502
+ lines.push('');
503
+ }
504
+
505
+ for (const [symbol, info] of entries) {
506
+ lines.push(`## \`${symbol}\``);
507
+ lines.push('');
508
+ if (info && typeof info === 'object') {
509
+ for (const [field, val] of Object.entries(info)) {
510
+ const display = Array.isArray(val) ? val.join(', ') : String(val);
511
+ lines.push(`- **${field}:** ${display}`);
512
+ }
513
+ }
514
+ lines.push('');
515
+ }
516
+ }
517
+
518
+ platformWriteSync(outputPath, lines.join('\n'));
519
+
520
+ return { written: outputPath, symbolCount, stale };
521
+ }
522
+
523
+ /**
524
+ * Patch _meta.updated_at in a JSON intel file to the current timestamp.
525
+ * Reads the file, updates _meta.updated_at, increments version, writes back.
526
+ *
527
+ * NOTE: Does not gate on isIntelEnabled — operates on arbitrary file paths
528
+ * for use by agents patching individual files outside the intel store.
529
+ *
530
+ * @param {string} filePath - Absolute or relative path to the JSON intel file
531
+ * @returns {{ patched: boolean, file: string, timestamp: string } | { patched: false, error: string }}
532
+ */
533
+ function intelPatchMeta(filePath) {
534
+ try {
535
+ const content = platformReadSync(filePath);
536
+ if (content === null) {
537
+ return { patched: false, error: `File not found: ${filePath}` };
538
+ }
539
+ let data;
540
+ try {
541
+ data = JSON.parse(content);
542
+ } catch (e) {
543
+ return { patched: false, error: `Invalid JSON: ${e.message}` };
544
+ }
545
+
546
+ if (!data._meta) {
547
+ data._meta = {};
548
+ }
549
+
550
+ const timestamp = new Date().toISOString();
551
+ data._meta.updated_at = timestamp;
552
+ data._meta.version = (data._meta.version || 0) + 1;
553
+
554
+ platformWriteSync(filePath, JSON.stringify(data, null, 2) + '\n');
555
+
556
+ return { patched: true, file: filePath, timestamp };
557
+ } catch (e) {
558
+ return { patched: false, error: e.message };
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Extract exports from a JS/CJS file by parsing module.exports or exports.X patterns.
564
+ *
565
+ * NOTE: Does not gate on isIntelEnabled — operates on arbitrary source files
566
+ * for use by agents building intel data from project files.
567
+ *
568
+ * @param {string} filePath - Path to the JS/CJS file
569
+ * @returns {{ file: string, exports: string[], method: string }}
570
+ */
571
+ function intelExtractExports(filePath) {
572
+ const content = platformReadSync(filePath);
573
+ if (content === null) {
574
+ return { file: filePath, exports: [], method: 'none' };
575
+ }
576
+ const exports = new Set();
577
+ let method = 'none';
578
+
579
+ // Try module.exports = { ... } pattern (handle multi-line)
580
+ // Find the LAST module.exports assignment (the actual one, not references in code)
581
+ const allMatches = [...content.matchAll(/module\.exports\s*=\s*\{/g)];
582
+ if (allMatches.length > 0) {
583
+ const lastMatch = allMatches[allMatches.length - 1];
584
+ const startIdx = lastMatch.index + lastMatch[0].length;
585
+ // Find matching closing brace by counting braces
586
+ let depth = 1;
587
+ let endIdx = startIdx;
588
+ while (endIdx < content.length && depth > 0) {
589
+ if (content[endIdx] === '{') depth++;
590
+ else if (content[endIdx] === '}') depth--;
591
+ if (depth > 0) endIdx++;
592
+ }
593
+ const block = content.substring(startIdx, endIdx);
594
+ method = 'module.exports';
595
+ // Extract key names from lines like " keyName," or " keyName: value,"
596
+ const lines = block.split('\n');
597
+ for (const line of lines) {
598
+ const trimmed = line.trim();
599
+ // Skip comments and empty lines
600
+ if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('*')) continue;
601
+ // Match identifier at start of line (before comma, colon, end of line)
602
+ const keyMatch = trimmed.match(/^(\w+)\s*[,}:]/) || trimmed.match(/^(\w+)$/);
603
+ if (keyMatch) {
604
+ exports.add(keyMatch[1]);
605
+ }
606
+ }
607
+ }
608
+
609
+ // Also try individual exports.X = patterns (only at start of line, not inside strings/regex)
610
+ const individualPattern = /^exports\.(\w+)\s*=/gm;
611
+ let im;
612
+ while ((im = individualPattern.exec(content)) !== null) {
613
+ if (!exports.has(im[1])) {
614
+ exports.add(im[1]);
615
+ if (method === 'none') method = 'exports.X';
616
+ }
617
+ }
618
+
619
+ const hadCjs = exports.size > 0;
620
+
621
+ // ESM patterns
622
+ const esmExports = new Set();
623
+
624
+ // export default function X / export default class X
625
+ const defaultNamedPattern = /^export\s+default\s+(?:function|class)\s+(\w+)/gm;
626
+ let em;
627
+ while ((em = defaultNamedPattern.exec(content)) !== null) {
628
+ esmExports.add(em[1]);
629
+ }
630
+
631
+ // export default (without named function/class)
632
+ const defaultAnonPattern = /^export\s+default\s+(?!function\s|class\s)/gm;
633
+ if (defaultAnonPattern.test(content) && esmExports.size === 0) {
634
+ esmExports.add('default');
635
+ }
636
+
637
+ // export function X( / export async function X(
638
+ const exportFnPattern = /^export\s+(?:async\s+)?function\s+(\w+)\s*\(/gm;
639
+ while ((em = exportFnPattern.exec(content)) !== null) {
640
+ esmExports.add(em[1]);
641
+ }
642
+
643
+ // export const X = / export let X = / export var X =
644
+ const exportVarPattern = /^export\s+(?:const|let|var)\s+(\w+)\s*=/gm;
645
+ while ((em = exportVarPattern.exec(content)) !== null) {
646
+ esmExports.add(em[1]);
647
+ }
648
+
649
+ // export class X
650
+ const exportClassPattern = /^export\s+class\s+(\w+)/gm;
651
+ while ((em = exportClassPattern.exec(content)) !== null) {
652
+ esmExports.add(em[1]);
653
+ }
654
+
655
+ // export { X, Y, Z } — strip "as alias" parts
656
+ const exportBlockPattern = /^export\s*\{([^}]+)\}/gm;
657
+ while ((em = exportBlockPattern.exec(content)) !== null) {
658
+ const items = em[1].split(',');
659
+ for (const item of items) {
660
+ const trimmed = item.trim();
661
+ if (!trimmed) continue;
662
+ // "foo as bar" -> extract "foo"
663
+ const name = trimmed.split(/\s+as\s+/)[0].trim();
664
+ if (name) esmExports.add(name);
665
+ }
666
+ }
667
+
668
+ // Merge ESM exports into the result
669
+ for (const e of esmExports) {
670
+ exports.add(e);
671
+ }
672
+
673
+ // Determine method
674
+ const hadEsm = esmExports.size > 0;
675
+ if (hadCjs && hadEsm) {
676
+ method = 'mixed';
677
+ } else if (hadEsm && !hadCjs) {
678
+ method = 'esm';
679
+ }
680
+
681
+ return { file: filePath, exports: [...exports], method };
682
+ }
683
+
684
+ // ─── Exports ─────────────────────────────────────────────────────────────────
685
+
686
+ module.exports = {
687
+ // Public API
688
+ intelQuery,
689
+ intelUpdate,
690
+ intelStatus,
691
+ intelDiff,
692
+ saveRefreshSnapshot,
693
+
694
+ // CLI subcommands
695
+ intelSnapshot,
696
+ intelValidate,
697
+ intelExtractExports,
698
+ intelPatchMeta,
699
+ intelApiSurface,
700
+
701
+ // Utilities
702
+ ensureIntelDir,
703
+ isIntelEnabled,
704
+
705
+ // Constants
706
+ INTEL_FILES,
707
+ INTEL_DIR
708
+ };