@specship/specship-win32-arm64 0.24.0 → 0.28.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 (341) hide show
  1. package/bin/specship.cmd +31 -1
  2. package/lib/dist/activation/cheatsheet.d.ts +17 -1
  3. package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
  4. package/lib/dist/activation/cheatsheet.js +47 -3
  5. package/lib/dist/activation/cheatsheet.js.map +1 -1
  6. package/lib/dist/activation/hook-output.d.ts +80 -0
  7. package/lib/dist/activation/hook-output.d.ts.map +1 -0
  8. package/lib/dist/activation/hook-output.js +103 -0
  9. package/lib/dist/activation/hook-output.js.map +1 -0
  10. package/lib/dist/activation/search-intercept.d.ts +60 -29
  11. package/lib/dist/activation/search-intercept.d.ts.map +1 -1
  12. package/lib/dist/activation/search-intercept.js +159 -55
  13. package/lib/dist/activation/search-intercept.js.map +1 -1
  14. package/lib/dist/activation/steering.d.ts +11 -13
  15. package/lib/dist/activation/steering.d.ts.map +1 -1
  16. package/lib/dist/activation/steering.js +25 -10
  17. package/lib/dist/activation/steering.js.map +1 -1
  18. package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
  19. package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
  20. package/lib/dist/behaviour/behaviour-surface.js +108 -2
  21. package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
  22. package/lib/dist/bin/node-version-check.d.ts +22 -7
  23. package/lib/dist/bin/node-version-check.d.ts.map +1 -1
  24. package/lib/dist/bin/node-version-check.js +39 -9
  25. package/lib/dist/bin/node-version-check.js.map +1 -1
  26. package/lib/dist/bin/specship.js +989 -116
  27. package/lib/dist/bin/specship.js.map +1 -1
  28. package/lib/dist/commands/specship/learn.md +27 -3
  29. package/lib/dist/commands/specship/spec.md +85 -15
  30. package/lib/dist/db/spec-queries.d.ts +73 -3
  31. package/lib/dist/db/spec-queries.d.ts.map +1 -1
  32. package/lib/dist/db/spec-queries.js +139 -5
  33. package/lib/dist/db/spec-queries.js.map +1 -1
  34. package/lib/dist/db/sqlite-adapter.d.ts +7 -5
  35. package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
  36. package/lib/dist/db/sqlite-adapter.js +11 -9
  37. package/lib/dist/db/sqlite-adapter.js.map +1 -1
  38. package/lib/dist/enforce/changed-files.d.ts +39 -0
  39. package/lib/dist/enforce/changed-files.d.ts.map +1 -0
  40. package/lib/dist/enforce/changed-files.js +114 -0
  41. package/lib/dist/enforce/changed-files.js.map +1 -0
  42. package/lib/dist/enforce/enforce.d.ts +53 -2
  43. package/lib/dist/enforce/enforce.d.ts.map +1 -1
  44. package/lib/dist/enforce/enforce.js +95 -8
  45. package/lib/dist/enforce/enforce.js.map +1 -1
  46. package/lib/dist/enforce/mutation.d.ts +46 -0
  47. package/lib/dist/enforce/mutation.d.ts.map +1 -0
  48. package/lib/dist/enforce/mutation.js +104 -0
  49. package/lib/dist/enforce/mutation.js.map +1 -0
  50. package/lib/dist/enforce/suppressions.d.ts +33 -0
  51. package/lib/dist/enforce/suppressions.d.ts.map +1 -0
  52. package/lib/dist/enforce/suppressions.js +159 -0
  53. package/lib/dist/enforce/suppressions.js.map +1 -0
  54. package/lib/dist/extraction/grammars.d.ts +10 -0
  55. package/lib/dist/extraction/grammars.d.ts.map +1 -1
  56. package/lib/dist/extraction/grammars.js +32 -3
  57. package/lib/dist/extraction/grammars.js.map +1 -1
  58. package/lib/dist/extraction/index.d.ts +7 -0
  59. package/lib/dist/extraction/index.d.ts.map +1 -1
  60. package/lib/dist/extraction/index.js.map +1 -1
  61. package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts +7 -0
  62. package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
  63. package/lib/dist/extraction/specs/markdown-spec-extractor.js +97 -10
  64. package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
  65. package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm.gz +0 -0
  66. package/lib/dist/extraction/wasm/tree-sitter-scala.wasm.gz +0 -0
  67. package/lib/dist/graph/spec-coverage.d.ts +142 -0
  68. package/lib/dist/graph/spec-coverage.d.ts.map +1 -0
  69. package/lib/dist/graph/spec-coverage.js +276 -0
  70. package/lib/dist/graph/spec-coverage.js.map +1 -0
  71. package/lib/dist/health/smoke-check.js +2 -2
  72. package/lib/dist/health/smoke-check.js.map +1 -1
  73. package/lib/dist/index.d.ts +75 -7
  74. package/lib/dist/index.d.ts.map +1 -1
  75. package/lib/dist/index.js +191 -23
  76. package/lib/dist/index.js.map +1 -1
  77. package/lib/dist/installer/gemini-commands.d.ts +107 -0
  78. package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
  79. package/lib/dist/installer/gemini-commands.js +264 -0
  80. package/lib/dist/installer/gemini-commands.js.map +1 -0
  81. package/lib/dist/installer/index.d.ts +55 -8
  82. package/lib/dist/installer/index.d.ts.map +1 -1
  83. package/lib/dist/installer/index.js +72 -53
  84. package/lib/dist/installer/index.js.map +1 -1
  85. package/lib/dist/installer/init-offer.d.ts +14 -9
  86. package/lib/dist/installer/init-offer.d.ts.map +1 -1
  87. package/lib/dist/installer/init-offer.js +13 -9
  88. package/lib/dist/installer/init-offer.js.map +1 -1
  89. package/lib/dist/installer/install-defaults.d.ts +81 -0
  90. package/lib/dist/installer/install-defaults.d.ts.map +1 -0
  91. package/lib/dist/installer/install-defaults.js +95 -0
  92. package/lib/dist/installer/install-defaults.js.map +1 -0
  93. package/lib/dist/installer/instructions-template.d.ts +22 -0
  94. package/lib/dist/installer/instructions-template.d.ts.map +1 -1
  95. package/lib/dist/installer/instructions-template.js +37 -1
  96. package/lib/dist/installer/instructions-template.js.map +1 -1
  97. package/lib/dist/installer/targets/claude.d.ts +18 -0
  98. package/lib/dist/installer/targets/claude.d.ts.map +1 -1
  99. package/lib/dist/installer/targets/claude.js +70 -23
  100. package/lib/dist/installer/targets/claude.js.map +1 -1
  101. package/lib/dist/installer/targets/gemini.d.ts +85 -12
  102. package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
  103. package/lib/dist/installer/targets/gemini.js +527 -30
  104. package/lib/dist/installer/targets/gemini.js.map +1 -1
  105. package/lib/dist/installer/targets/shared.d.ts +13 -0
  106. package/lib/dist/installer/targets/shared.d.ts.map +1 -1
  107. package/lib/dist/installer/targets/shared.js +22 -4
  108. package/lib/dist/installer/targets/shared.js.map +1 -1
  109. package/lib/dist/installer/targets/types.d.ts +12 -0
  110. package/lib/dist/installer/targets/types.d.ts.map +1 -1
  111. package/lib/dist/jira/auto-publish.d.ts +71 -4
  112. package/lib/dist/jira/auto-publish.d.ts.map +1 -1
  113. package/lib/dist/jira/auto-publish.js +186 -17
  114. package/lib/dist/jira/auto-publish.js.map +1 -1
  115. package/lib/dist/jira/reconcile.d.ts +24 -1
  116. package/lib/dist/jira/reconcile.d.ts.map +1 -1
  117. package/lib/dist/jira/reconcile.js +46 -2
  118. package/lib/dist/jira/reconcile.js.map +1 -1
  119. package/lib/dist/jira/repo-config.d.ts +9 -0
  120. package/lib/dist/jira/repo-config.d.ts.map +1 -1
  121. package/lib/dist/jira/repo-config.js +11 -0
  122. package/lib/dist/jira/repo-config.js.map +1 -1
  123. package/lib/dist/jira/types.d.ts +7 -0
  124. package/lib/dist/jira/types.d.ts.map +1 -1
  125. package/lib/dist/jira/types.js.map +1 -1
  126. package/lib/dist/knowledge/enforce.d.ts +75 -0
  127. package/lib/dist/knowledge/enforce.d.ts.map +1 -0
  128. package/lib/dist/knowledge/enforce.js +250 -0
  129. package/lib/dist/knowledge/enforce.js.map +1 -0
  130. package/lib/dist/knowledge/facts.d.ts +33 -0
  131. package/lib/dist/knowledge/facts.d.ts.map +1 -0
  132. package/lib/dist/knowledge/facts.js +117 -0
  133. package/lib/dist/knowledge/facts.js.map +1 -0
  134. package/lib/dist/knowledge/proposals.d.ts +88 -0
  135. package/lib/dist/knowledge/proposals.d.ts.map +1 -0
  136. package/lib/dist/knowledge/proposals.js +360 -0
  137. package/lib/dist/knowledge/proposals.js.map +1 -0
  138. package/lib/dist/knowledge/stale.d.ts +64 -0
  139. package/lib/dist/knowledge/stale.d.ts.map +1 -0
  140. package/lib/dist/knowledge/stale.js +174 -0
  141. package/lib/dist/knowledge/stale.js.map +1 -0
  142. package/lib/dist/mcp/fitness-tool.d.ts +5 -6
  143. package/lib/dist/mcp/fitness-tool.d.ts.map +1 -1
  144. package/lib/dist/mcp/fitness-tool.js +0 -16
  145. package/lib/dist/mcp/fitness-tool.js.map +1 -1
  146. package/lib/dist/mcp/gemini-session.d.ts +50 -0
  147. package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
  148. package/lib/dist/mcp/gemini-session.js +159 -0
  149. package/lib/dist/mcp/gemini-session.js.map +1 -0
  150. package/lib/dist/mcp/health-tool.d.ts +26 -0
  151. package/lib/dist/mcp/health-tool.d.ts.map +1 -0
  152. package/lib/dist/mcp/health-tool.js +50 -0
  153. package/lib/dist/mcp/health-tool.js.map +1 -0
  154. package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
  155. package/lib/dist/mcp/jira-tools.js +25 -0
  156. package/lib/dist/mcp/jira-tools.js.map +1 -1
  157. package/lib/dist/mcp/maintainability-tool.d.ts +5 -7
  158. package/lib/dist/mcp/maintainability-tool.d.ts.map +1 -1
  159. package/lib/dist/mcp/maintainability-tool.js +0 -16
  160. package/lib/dist/mcp/maintainability-tool.js.map +1 -1
  161. package/lib/dist/mcp/model-context.d.ts +31 -7
  162. package/lib/dist/mcp/model-context.d.ts.map +1 -1
  163. package/lib/dist/mcp/model-context.js +70 -21
  164. package/lib/dist/mcp/model-context.js.map +1 -1
  165. package/lib/dist/mcp/proxy.d.ts.map +1 -1
  166. package/lib/dist/mcp/proxy.js +5 -2
  167. package/lib/dist/mcp/proxy.js.map +1 -1
  168. package/lib/dist/mcp/server-instructions.d.ts +16 -15
  169. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  170. package/lib/dist/mcp/server-instructions.js +72 -5
  171. package/lib/dist/mcp/server-instructions.js.map +1 -1
  172. package/lib/dist/mcp/session.js +1 -1
  173. package/lib/dist/mcp/session.js.map +1 -1
  174. package/lib/dist/mcp/spec-tools.d.ts +9 -1
  175. package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
  176. package/lib/dist/mcp/spec-tools.js +282 -49
  177. package/lib/dist/mcp/spec-tools.js.map +1 -1
  178. package/lib/dist/mcp/tools.d.ts +49 -9
  179. package/lib/dist/mcp/tools.d.ts.map +1 -1
  180. package/lib/dist/mcp/tools.js +210 -58
  181. package/lib/dist/mcp/tools.js.map +1 -1
  182. package/lib/dist/pulse/pulse.d.ts +93 -0
  183. package/lib/dist/pulse/pulse.d.ts.map +1 -0
  184. package/lib/dist/pulse/pulse.js +401 -0
  185. package/lib/dist/pulse/pulse.js.map +1 -0
  186. package/lib/dist/reflect/apply.d.ts.map +1 -1
  187. package/lib/dist/reflect/apply.js +38 -3
  188. package/lib/dist/reflect/apply.js.map +1 -1
  189. package/lib/dist/reflect/auto-sweep.d.ts +26 -0
  190. package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
  191. package/lib/dist/reflect/auto-sweep.js +90 -0
  192. package/lib/dist/reflect/auto-sweep.js.map +1 -0
  193. package/lib/dist/reflect/cli.d.ts +62 -0
  194. package/lib/dist/reflect/cli.d.ts.map +1 -0
  195. package/lib/dist/reflect/cli.js +163 -0
  196. package/lib/dist/reflect/cli.js.map +1 -0
  197. package/lib/dist/reflect/miner.d.ts.map +1 -1
  198. package/lib/dist/reflect/miner.js +119 -0
  199. package/lib/dist/reflect/miner.js.map +1 -1
  200. package/lib/dist/reflect/sweep.d.ts +1 -0
  201. package/lib/dist/reflect/sweep.d.ts.map +1 -1
  202. package/lib/dist/reflect/sweep.js +62 -13
  203. package/lib/dist/reflect/sweep.js.map +1 -1
  204. package/lib/dist/reflect/targets.d.ts +2 -0
  205. package/lib/dist/reflect/targets.d.ts.map +1 -1
  206. package/lib/dist/reflect/targets.js +33 -0
  207. package/lib/dist/reflect/targets.js.map +1 -1
  208. package/lib/dist/reflect/types.d.ts +19 -2
  209. package/lib/dist/reflect/types.d.ts.map +1 -1
  210. package/lib/dist/resolution/spec-link-resolver.d.ts +44 -2
  211. package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
  212. package/lib/dist/resolution/spec-link-resolver.js +132 -0
  213. package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
  214. package/lib/dist/resolution/test-title-links.d.ts +62 -0
  215. package/lib/dist/resolution/test-title-links.d.ts.map +1 -0
  216. package/lib/dist/resolution/test-title-links.js +97 -0
  217. package/lib/dist/resolution/test-title-links.js.map +1 -0
  218. package/lib/dist/search/query-parser.d.ts.map +1 -1
  219. package/lib/dist/search/query-parser.js +6 -1
  220. package/lib/dist/search/query-parser.js.map +1 -1
  221. package/lib/dist/server/project-registry.js +1 -1
  222. package/lib/dist/server/routes/claude.js +24 -43
  223. package/lib/dist/server/routes/graph.js +53 -7
  224. package/lib/dist/server/routes/knowledge.js +118 -0
  225. package/lib/dist/server/routes/mcp.js +4 -3
  226. package/lib/dist/server/routes/projects.js +4 -4
  227. package/lib/dist/server/routes/spec.js +49 -7
  228. package/lib/dist/server/server.js +31 -17
  229. package/lib/dist/skills/spec-author/SKILL.md +164 -0
  230. package/lib/dist/skills/spec-author/references/format.md +210 -0
  231. package/lib/dist/skills/spec-author/references/gap-questions.md +152 -0
  232. package/lib/dist/skills/spec-author/references/quality-rubric.md +125 -0
  233. package/lib/dist/skills/spec-author/references/review-checklist.md +175 -0
  234. package/lib/dist/spec-lint/lint.d.ts +82 -0
  235. package/lib/dist/spec-lint/lint.d.ts.map +1 -0
  236. package/lib/dist/spec-lint/lint.js +491 -0
  237. package/lib/dist/spec-lint/lint.js.map +1 -0
  238. package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
  239. package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
  240. package/lib/dist/spec-quality/criterion-ids.js +38 -0
  241. package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
  242. package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
  243. package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
  244. package/lib/dist/spec-quality/evidence-kind.js +183 -0
  245. package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
  246. package/lib/dist/spec-quality/link-persist.d.ts +65 -0
  247. package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
  248. package/lib/dist/spec-quality/link-persist.js +249 -0
  249. package/lib/dist/spec-quality/link-persist.js.map +1 -0
  250. package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
  251. package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
  252. package/lib/dist/spec-quality/plan-scope.js +129 -0
  253. package/lib/dist/spec-quality/plan-scope.js.map +1 -0
  254. package/lib/dist/spec-quality/postcheck.d.ts +85 -0
  255. package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
  256. package/lib/dist/spec-quality/postcheck.js +390 -0
  257. package/lib/dist/spec-quality/postcheck.js.map +1 -0
  258. package/lib/dist/spec-quality/readiness.d.ts +72 -0
  259. package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
  260. package/lib/dist/spec-quality/readiness.js +226 -0
  261. package/lib/dist/spec-quality/readiness.js.map +1 -0
  262. package/lib/dist/statusline/index.js.map +1 -1
  263. package/lib/dist/statusline/render.d.ts +1 -1
  264. package/lib/dist/statusline/render.d.ts.map +1 -1
  265. package/lib/dist/statusline/render.js +3 -1
  266. package/lib/dist/statusline/render.js.map +1 -1
  267. package/lib/dist/ui/assets/index-BzuUWUAE.js +50 -0
  268. package/lib/dist/ui/index.html +1 -1
  269. package/lib/dist/verify/report-ingest.d.ts +88 -0
  270. package/lib/dist/verify/report-ingest.d.ts.map +1 -0
  271. package/lib/dist/verify/report-ingest.js +269 -0
  272. package/lib/dist/verify/report-ingest.js.map +1 -0
  273. package/lib/dist/workflows/agents/claude.d.ts +16 -0
  274. package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
  275. package/lib/dist/workflows/agents/claude.js +82 -0
  276. package/lib/dist/workflows/agents/claude.js.map +1 -0
  277. package/lib/dist/workflows/agents/gemini.d.ts +21 -0
  278. package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
  279. package/lib/dist/workflows/agents/gemini.js +124 -0
  280. package/lib/dist/workflows/agents/gemini.js.map +1 -0
  281. package/lib/dist/workflows/agents/index.d.ts +28 -0
  282. package/lib/dist/workflows/agents/index.d.ts.map +1 -0
  283. package/lib/dist/workflows/agents/index.js +104 -0
  284. package/lib/dist/workflows/agents/index.js.map +1 -0
  285. package/lib/dist/workflows/agents/types.d.ts +55 -0
  286. package/lib/dist/workflows/agents/types.d.ts.map +1 -0
  287. package/lib/dist/workflows/agents/types.js +46 -0
  288. package/lib/dist/workflows/agents/types.js.map +1 -0
  289. package/lib/dist/workflows/batch.d.ts +63 -0
  290. package/lib/dist/workflows/batch.d.ts.map +1 -0
  291. package/lib/dist/workflows/batch.js +151 -0
  292. package/lib/dist/workflows/batch.js.map +1 -0
  293. package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -4
  294. package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
  295. package/lib/dist/workflows/defaults/spec-fix.yaml +103 -12
  296. package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -193
  297. package/lib/dist/workflows/defaults/spec-implement.yaml +701 -41
  298. package/lib/dist/workflows/defaults/spec-verify.yaml +60 -9
  299. package/lib/dist/workflows/discovery.d.ts +13 -0
  300. package/lib/dist/workflows/discovery.d.ts.map +1 -1
  301. package/lib/dist/workflows/discovery.js +79 -17
  302. package/lib/dist/workflows/discovery.js.map +1 -1
  303. package/lib/dist/workflows/executor.d.ts +18 -0
  304. package/lib/dist/workflows/executor.d.ts.map +1 -1
  305. package/lib/dist/workflows/executor.js +130 -33
  306. package/lib/dist/workflows/executor.js.map +1 -1
  307. package/lib/dist/workflows/gc.d.ts +50 -0
  308. package/lib/dist/workflows/gc.d.ts.map +1 -0
  309. package/lib/dist/workflows/gc.js +120 -0
  310. package/lib/dist/workflows/gc.js.map +1 -0
  311. package/lib/dist/workflows/merge-queue.d.ts +64 -0
  312. package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
  313. package/lib/dist/workflows/merge-queue.js +162 -0
  314. package/lib/dist/workflows/merge-queue.js.map +1 -0
  315. package/lib/dist/workflows/runners/approval.d.ts +1 -1
  316. package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
  317. package/lib/dist/workflows/runners/approval.js +11 -2
  318. package/lib/dist/workflows/runners/approval.js.map +1 -1
  319. package/lib/dist/workflows/runners/bash.d.ts +15 -0
  320. package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
  321. package/lib/dist/workflows/runners/bash.js +50 -1
  322. package/lib/dist/workflows/runners/bash.js.map +1 -1
  323. package/lib/dist/workflows/runners/prompt.d.ts +16 -41
  324. package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
  325. package/lib/dist/workflows/runners/prompt.js +55 -120
  326. package/lib/dist/workflows/runners/prompt.js.map +1 -1
  327. package/lib/dist/workflows/runners/types.d.ts +12 -0
  328. package/lib/dist/workflows/runners/types.d.ts.map +1 -1
  329. package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
  330. package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
  331. package/lib/dist/workflows/schemas/workflow.js +27 -0
  332. package/lib/dist/workflows/schemas/workflow.js.map +1 -1
  333. package/lib/node_modules/.package-lock.json +1 -1
  334. package/lib/package.json +8 -4
  335. package/package.json +5 -3
  336. package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  337. package/lib/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  338. package/lib/dist/server/ingest/impact-query.js +0 -343
  339. package/lib/dist/server/routes/events.js +0 -152
  340. package/lib/dist/ui/assets/index-CjjaftDw.js +0 -50
  341. package/node.exe +0 -4
@@ -0,0 +1,64 @@
1
+ /**
2
+ * External-fact staleness (KNOWLEDGE-DOC, REQ-KNOW-002 / REQ-KNOW-006.A1).
3
+ *
4
+ * An external domain fact (`type: external`) records the `version` of its
5
+ * `dependency` it was verified against. When the installed version differs,
6
+ * the fact is stale: what it says may no longer be true. A dependency that
7
+ * cannot be found is unverifiable — reported, never counted as fresh, but not
8
+ * by itself a failure.
9
+ *
10
+ * Version comparison is deliberately exact-string: a fact verified against
11
+ * 0.28.0 is not known to hold for 0.28.1, and semver ranges would hide that.
12
+ *
13
+ * Read-only: reads `specs/domain/` and `package.json` files, writes nothing.
14
+ */
15
+ export interface ResolveVersionOptions {
16
+ /**
17
+ * Returns the global npm root (what `npm root -g` prints), or null. Injected
18
+ * by tests; the default shells out to npm once per process and caches it.
19
+ */
20
+ globalRoot?: () => string | null;
21
+ }
22
+ export type StaleCheckOptions = ResolveVersionOptions;
23
+ export interface FreshFact {
24
+ id: string;
25
+ dependency: string;
26
+ version: string;
27
+ }
28
+ export interface StaleFact {
29
+ id: string;
30
+ dependency: string;
31
+ /** The version the fact was verified against. */
32
+ verified: string;
33
+ /** The version installed now. */
34
+ installed: string;
35
+ /** `path:Symbol` fixture tests to re-check (REQ-KNOW-006.A1). */
36
+ fixtures: string[];
37
+ }
38
+ export interface UnverifiableFact {
39
+ id: string;
40
+ dependency: string;
41
+ }
42
+ export interface StaleCheckResult {
43
+ fresh: FreshFact[];
44
+ stale: StaleFact[];
45
+ unverifiable: UnverifiableFact[];
46
+ }
47
+ /** `npm root -g`, run at most once per process. Null when npm is unavailable. */
48
+ export declare function defaultGlobalNpmRoot(): string | null;
49
+ /**
50
+ * The installed version of `dependency`: the project's `node_modules` first,
51
+ * then the global npm root; null when neither has it.
52
+ */
53
+ export declare function resolveInstalledVersion(dependency: string, projectRoot: string, opts?: ResolveVersionOptions): string | null;
54
+ /**
55
+ * Compare every external fact under `<projectRoot>/specs/domain/` with the
56
+ * installed version of its dependency. Facts missing `dependency` or `version`
57
+ * are skipped (the lint reports them as errors).
58
+ */
59
+ export declare function findStaleExternalFacts(projectRoot: string, opts?: StaleCheckOptions): StaleCheckResult;
60
+ /** Exit code for `knowledge stale`: non-zero when any fact is stale. Unverifiable alone passes. */
61
+ export declare function exitCodeForStale(result: StaleCheckResult): number;
62
+ /** Human-readable report for `knowledge stale`. */
63
+ export declare function formatStaleReport(result: StaleCheckResult): string;
64
+ //# sourceMappingURL=stale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale.d.ts","sourceRoot":"","sources":["../../src/knowledge/stale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEtD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,YAAY,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAID,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAcpD;AAaD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,qBAA0B,GAC/B,MAAM,GAAG,IAAI,CAQf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,iBAAsB,GAC3B,gBAAgB,CA+BlB;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAEjE;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAoBlE"}
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * External-fact staleness (KNOWLEDGE-DOC, REQ-KNOW-002 / REQ-KNOW-006.A1).
4
+ *
5
+ * An external domain fact (`type: external`) records the `version` of its
6
+ * `dependency` it was verified against. When the installed version differs,
7
+ * the fact is stale: what it says may no longer be true. A dependency that
8
+ * cannot be found is unverifiable — reported, never counted as fresh, but not
9
+ * by itself a failure.
10
+ *
11
+ * Version comparison is deliberately exact-string: a fact verified against
12
+ * 0.28.0 is not known to hold for 0.28.1, and semver ranges would hide that.
13
+ *
14
+ * Read-only: reads `specs/domain/` and `package.json` files, writes nothing.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.defaultGlobalNpmRoot = defaultGlobalNpmRoot;
51
+ exports.resolveInstalledVersion = resolveInstalledVersion;
52
+ exports.findStaleExternalFacts = findStaleExternalFacts;
53
+ exports.exitCodeForStale = exitCodeForStale;
54
+ exports.formatStaleReport = formatStaleReport;
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const child_process_1 = require("child_process");
58
+ const facts_1 = require("./facts");
59
+ let cachedGlobalRoot;
60
+ /** `npm root -g`, run at most once per process. Null when npm is unavailable. */
61
+ function defaultGlobalNpmRoot() {
62
+ if (cachedGlobalRoot !== undefined)
63
+ return cachedGlobalRoot;
64
+ try {
65
+ const out = (0, child_process_1.execFileSync)(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['root', '-g'], {
66
+ encoding: 'utf8',
67
+ stdio: ['ignore', 'pipe', 'ignore'],
68
+ timeout: 10_000,
69
+ shell: process.platform === 'win32',
70
+ }).trim();
71
+ cachedGlobalRoot = out.length > 0 ? out : null;
72
+ }
73
+ catch {
74
+ cachedGlobalRoot = null;
75
+ }
76
+ return cachedGlobalRoot;
77
+ }
78
+ function readPackageVersion(modulesDir, dependency) {
79
+ // `@scope/name` maps onto nested directories; path.join handles the slash.
80
+ const pkgPath = path.join(modulesDir, ...dependency.split('/'), 'package.json');
81
+ try {
82
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
83
+ return typeof pkg.version === 'string' && pkg.version.length > 0 ? pkg.version : null;
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ /**
90
+ * The installed version of `dependency`: the project's `node_modules` first,
91
+ * then the global npm root; null when neither has it.
92
+ */
93
+ function resolveInstalledVersion(dependency, projectRoot, opts = {}) {
94
+ const dep = dependency.trim();
95
+ if (dep.length === 0 || dep.includes('..'))
96
+ return null;
97
+ const local = readPackageVersion(path.join(projectRoot, 'node_modules'), dep);
98
+ if (local)
99
+ return local;
100
+ const globalRoot = (opts.globalRoot ?? defaultGlobalNpmRoot)();
101
+ if (!globalRoot)
102
+ return null;
103
+ return readPackageVersion(globalRoot, dep);
104
+ }
105
+ /**
106
+ * Compare every external fact under `<projectRoot>/specs/domain/` with the
107
+ * installed version of its dependency. Facts missing `dependency` or `version`
108
+ * are skipped (the lint reports them as errors).
109
+ */
110
+ function findStaleExternalFacts(projectRoot, opts = {}) {
111
+ const result = { fresh: [], stale: [], unverifiable: [] };
112
+ // Resolve the global root lazily and at most once for the whole run.
113
+ let globalRoot;
114
+ const memoGlobal = () => {
115
+ if (globalRoot === undefined)
116
+ globalRoot = (opts.globalRoot ?? defaultGlobalNpmRoot)();
117
+ return globalRoot;
118
+ };
119
+ for (const fact of (0, facts_1.loadDomainFacts)(projectRoot)) {
120
+ if (fact.type !== 'external')
121
+ continue;
122
+ const dependency = typeof fact.metadata.dependency === 'string' ? fact.metadata.dependency.trim() : '';
123
+ const rawVersion = fact.metadata.version;
124
+ const verified = typeof rawVersion === 'string' || typeof rawVersion === 'number' ? String(rawVersion).trim() : '';
125
+ if (!dependency || !verified)
126
+ continue;
127
+ const installed = resolveInstalledVersion(dependency, projectRoot, { globalRoot: memoGlobal });
128
+ if (installed === null) {
129
+ result.unverifiable.push({ id: fact.id, dependency });
130
+ }
131
+ else if (installed === verified) {
132
+ result.fresh.push({ id: fact.id, dependency, version: verified });
133
+ }
134
+ else {
135
+ result.stale.push({
136
+ id: fact.id,
137
+ dependency,
138
+ verified,
139
+ installed,
140
+ fixtures: (0, facts_1.parseFixtureList)(fact.metadata.fixture),
141
+ });
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ /** Exit code for `knowledge stale`: non-zero when any fact is stale. Unverifiable alone passes. */
147
+ function exitCodeForStale(result) {
148
+ return result.stale.length > 0 ? 1 : 0;
149
+ }
150
+ /** Human-readable report for `knowledge stale`. */
151
+ function formatStaleReport(result) {
152
+ const total = result.fresh.length + result.stale.length + result.unverifiable.length;
153
+ if (total === 0)
154
+ return 'Knowledge stale: no external facts in specs/domain/.';
155
+ const out = [
156
+ `Knowledge stale: ${result.stale.length} stale, ${result.unverifiable.length} unverifiable, ${result.fresh.length} fresh (of ${total} external fact${total === 1 ? '' : 's'}).`,
157
+ ];
158
+ if (result.stale.length > 0) {
159
+ out.push('', 'Stale:');
160
+ for (const s of result.stale) {
161
+ out.push(` ${s.id} ${s.dependency}: verified ${s.verified}, installed ${s.installed}`);
162
+ if (s.fixtures.length > 0) {
163
+ out.push(` re-check fixtures: ${s.fixtures.join(', ')}`);
164
+ }
165
+ }
166
+ }
167
+ if (result.unverifiable.length > 0) {
168
+ out.push('', 'Unverifiable (dependency not installed locally or globally):');
169
+ for (const u of result.unverifiable)
170
+ out.push(` ${u.id} ${u.dependency}`);
171
+ }
172
+ return out.join('\n');
173
+ }
174
+ //# sourceMappingURL=stale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale.js","sourceRoot":"","sources":["../../src/knowledge/stale.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,11 @@
1
1
  /**
2
- * MCP tool: specship_fitness (REQ-FITNESS-003.A3).
2
+ * Architecture-fitness report handler (REQ-FITNESS-003.A3).
3
3
  *
4
- * Returns the architecture-fitness evaluation to the agent — violations of the
5
- * declared rules plus any config errors — so it can check conformance before
6
- * committing. Type-only imports keep this free of a runtime cycle with tools.ts.
4
+ * The menu slot moved to the merged `specship_health` (REQ-SURF-007); this
5
+ * handler stays so `execute()` keeps answering clients holding a cached
6
+ * `specship_fitness` tool list.
7
7
  */
8
8
  import type { SpecShip } from '../index';
9
- import type { ToolDefinition, ToolResult } from './tools';
10
- export declare const fitnessToolDefinitions: ToolDefinition[];
9
+ import type { ToolResult } from './tools';
11
10
  export declare function handleSpecshipFitness(cg: SpecShip, _args: Record<string, unknown>): Promise<ToolResult>;
12
11
  //# sourceMappingURL=fitness-tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fitness-tool.d.ts","sourceRoot":"","sources":["../../src/mcp/fitness-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1D,eAAO,MAAM,sBAAsB,EAAE,cAAc,EAelD,CAAC;AAMF,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,UAAU,CAAC,CAqBrB"}
1
+ {"version":3,"file":"fitness-tool.d.ts","sourceRoot":"","sources":["../../src/mcp/fitness-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAM1C,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,UAAU,CAAC,CAqBrB"}
@@ -1,22 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fitnessToolDefinitions = void 0;
4
3
  exports.handleSpecshipFitness = handleSpecshipFitness;
5
- exports.fitnessToolDefinitions = [
6
- {
7
- name: 'specship_fitness',
8
- description: 'Evaluate the project\'s architecture-fitness rules (specship.config.json `fitness.rules`) against the code graph: forbidden dependencies, layering allow-lists, module isolation. Returns concrete violations (source → target, file:line) plus config errors (a rule whose selector matches nothing). Use to check architecture conformance before committing.',
9
- inputSchema: {
10
- type: 'object',
11
- properties: {
12
- projectPath: {
13
- type: 'string',
14
- description: 'Path to a different project with .specship/ initialized. Omit for the current project.',
15
- },
16
- },
17
- },
18
- },
19
- ];
20
4
  const text = (body) => ({ content: [{ type: 'text', text: body }] });
21
5
  const CAP = 30;
22
6
  async function handleSpecshipFitness(cg, _args) {
@@ -1 +1 @@
1
- {"version":3,"file":"fitness-tool.js","sourceRoot":"","sources":["../../src/mcp/fitness-tool.ts"],"names":[],"mappings":";;;AA+BA,sDAwBC;AA7CY,QAAA,sBAAsB,GAAqB;IACtD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,iWAAiW;QACnW,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wFAAwF;iBACtG;aACF;SACF;KACF;CACF,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAc,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzF,MAAM,GAAG,GAAG,EAAE,CAAC;AAER,KAAK,UAAU,qBAAqB,CACzC,EAAY,EACZ,KAA8B;IAE9B,MAAM,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,2IAA2I,CAAC,CAAC;IAC3J,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,mCAAmC,CAAC,CAAC,SAAS,gBAAgB,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,KAAK,GAAa,CAAC,wBAAwB,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"fitness-tool.js","sourceRoot":"","sources":["../../src/mcp/fitness-tool.ts"],"names":[],"mappings":";;AAcA,sDAwBC;AA5BD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAc,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzF,MAAM,GAAG,GAAG,EAAE,CAAC;AAER,KAAK,UAAU,qBAAqB,CACzC,EAAY,EACZ,KAA8B;IAE9B,MAAM,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;IAC1B,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC,2IAA2I,CAAC,CAAC;IAC3J,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,mCAAmC,CAAC,CAAC,SAAS,gBAAgB,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,KAAK,GAAa,CAAC,wBAAwB,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Gemini CLI session model detection (LOWEND-DOC, REQ-LOWEND-001).
3
+ *
4
+ * All three existing tier-detection channels — the status-line marker, the
5
+ * SessionStart hook seed, and the transcript tail — are Claude Code plumbing.
6
+ * The Gemini target is MCP-entry-only (no hooks, no status line), so a Gemini
7
+ * CLI session has to be read **in-server** from Gemini CLI's own configuration
8
+ * surface:
9
+ *
10
+ * GEMINI_MODEL (Gemini CLI's own env knob)
11
+ * <cwd>/.gemini/settings.json — project, wins over global
12
+ * <homedir>/.gemini/settings.json — global
13
+ *
14
+ * Gemini CLI has shipped both `"model": "gemini-3.5-flash"` and
15
+ * `"model": { "name": "gemini-3.5-flash" }`, so both shapes are accepted.
16
+ * Every read is best-effort: a missing file, malformed JSON, or a non-string
17
+ * model yields `null` and the caller falls back to `full` — detection must
18
+ * never error a tool call (REQ-LOWEND-001.A4).
19
+ *
20
+ * This module deliberately does NOT import the Gemini installer target: the
21
+ * MCP read path must not depend on installer code. The paths mirror what that
22
+ * target documents (Storage.getWorkspaceSettingsPath / getGlobalSettingsPath).
23
+ */
24
+ /**
25
+ * Gemini CLI's settings files for a workspace, project first (project settings
26
+ * override global ones, same as Gemini CLI's own precedence).
27
+ */
28
+ export declare function geminiSettingsPaths(cwd: string, homedir?: string): string[];
29
+ /** Test seam — drops the parse cache. */
30
+ export declare function __resetGeminiCache(): void;
31
+ /**
32
+ * Host gate: the Gemini leg may only run inside a server that Gemini CLI
33
+ * launched. The Gemini installer target stamps `SPECSHIP_HOST=gemini` into
34
+ * the `mcpServers.specship` entry (written AND printed snippet), so the env
35
+ * is present exactly in Gemini-launched server processes. Without this gate
36
+ * a **Claude Code** session in a repo that happens to contain
37
+ * `.gemini/settings.json` (or a shell exporting `GEMINI_MODEL`) would be
38
+ * silently compacted during the first-prompt window before the Claude marker
39
+ * exists — the exact crossover REQ-MODCTX-001.A6 closes on the Claude side.
40
+ */
41
+ export declare function isGeminiHost(env?: NodeJS.ProcessEnv): boolean;
42
+ /**
43
+ * Resolve the Gemini CLI session's model id, or null when nothing names one
44
+ * (REQ-LOWEND-001). Host-gated: returns null outright unless
45
+ * `SPECSHIP_HOST=gemini` (see `isGeminiHost`). Then env first, then project
46
+ * settings, then global settings — first hit wins. The returned id is
47
+ * verbatim; mapping it to a tier is `modelTier`'s job.
48
+ */
49
+ export declare function readGeminiSessionModel(cwd: string, env?: NodeJS.ProcessEnv, homedir?: string): string | null;
50
+ //# sourceMappingURL=gemini-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-session.d.ts","sourceRoot":"","sources":["../../src/mcp/gemini-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAKzF;AAiBD,yCAAyC;AACzC,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAmCD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,MAAqB,GAC7B,MAAM,GAAG,IAAI,CASf"}
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ /**
3
+ * Gemini CLI session model detection (LOWEND-DOC, REQ-LOWEND-001).
4
+ *
5
+ * All three existing tier-detection channels — the status-line marker, the
6
+ * SessionStart hook seed, and the transcript tail — are Claude Code plumbing.
7
+ * The Gemini target is MCP-entry-only (no hooks, no status line), so a Gemini
8
+ * CLI session has to be read **in-server** from Gemini CLI's own configuration
9
+ * surface:
10
+ *
11
+ * GEMINI_MODEL (Gemini CLI's own env knob)
12
+ * <cwd>/.gemini/settings.json — project, wins over global
13
+ * <homedir>/.gemini/settings.json — global
14
+ *
15
+ * Gemini CLI has shipped both `"model": "gemini-3.5-flash"` and
16
+ * `"model": { "name": "gemini-3.5-flash" }`, so both shapes are accepted.
17
+ * Every read is best-effort: a missing file, malformed JSON, or a non-string
18
+ * model yields `null` and the caller falls back to `full` — detection must
19
+ * never error a tool call (REQ-LOWEND-001.A4).
20
+ *
21
+ * This module deliberately does NOT import the Gemini installer target: the
22
+ * MCP read path must not depend on installer code. The paths mirror what that
23
+ * target documents (Storage.getWorkspaceSettingsPath / getGlobalSettingsPath).
24
+ */
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
37
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
38
+ }) : function(o, v) {
39
+ o["default"] = v;
40
+ });
41
+ var __importStar = (this && this.__importStar) || (function () {
42
+ var ownKeys = function(o) {
43
+ ownKeys = Object.getOwnPropertyNames || function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54
+ __setModuleDefault(result, mod);
55
+ return result;
56
+ };
57
+ })();
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.geminiSettingsPaths = geminiSettingsPaths;
60
+ exports.__resetGeminiCache = __resetGeminiCache;
61
+ exports.isGeminiHost = isGeminiHost;
62
+ exports.readGeminiSessionModel = readGeminiSessionModel;
63
+ const fs = __importStar(require("fs"));
64
+ const os = __importStar(require("os"));
65
+ const path = __importStar(require("path"));
66
+ /**
67
+ * Gemini CLI's settings files for a workspace, project first (project settings
68
+ * override global ones, same as Gemini CLI's own precedence).
69
+ */
70
+ function geminiSettingsPaths(cwd, homedir = os.homedir()) {
71
+ return [
72
+ path.join(cwd, '.gemini', 'settings.json'),
73
+ path.join(homedir, '.gemini', 'settings.json'),
74
+ ];
75
+ }
76
+ /**
77
+ * Per-file parse cache keyed on path, invalidated by (mtimeMs, size).
78
+ * Resolution runs per tool call; one `statSync` per settings file is the whole
79
+ * cost on the warm path — JSON is re-parsed only when the file actually
80
+ * changed (REQ-LOWEND-001: "cached with invalidation, never adding
81
+ * perceptible latency").
82
+ */
83
+ const cache = new Map();
84
+ /** Test seam — drops the parse cache. */
85
+ function __resetGeminiCache() {
86
+ cache.clear();
87
+ }
88
+ /** Pull a model id out of a parsed settings object, accepting both shapes. */
89
+ function modelFromSettings(parsed) {
90
+ if (!parsed || typeof parsed !== 'object')
91
+ return null;
92
+ const model = parsed.model;
93
+ if (typeof model === 'string' && model)
94
+ return model;
95
+ if (model && typeof model === 'object') {
96
+ const name = model.name;
97
+ if (typeof name === 'string' && name)
98
+ return name;
99
+ }
100
+ return null;
101
+ }
102
+ /** Read one settings file through the cache. Never throws. */
103
+ function readSettingsModel(filePath) {
104
+ try {
105
+ const stat = fs.statSync(filePath);
106
+ if (!stat.isFile())
107
+ return null;
108
+ const hit = cache.get(filePath);
109
+ if (hit && hit.mtimeMs === stat.mtimeMs && hit.size === stat.size)
110
+ return hit.model;
111
+ let model = null;
112
+ try {
113
+ model = modelFromSettings(JSON.parse(fs.readFileSync(filePath, 'utf-8')));
114
+ }
115
+ catch {
116
+ model = null; // malformed JSON — degrade silently
117
+ }
118
+ cache.set(filePath, { mtimeMs: stat.mtimeMs, size: stat.size, model });
119
+ return model;
120
+ }
121
+ catch {
122
+ cache.delete(filePath);
123
+ return null; // ENOENT, EACCES, a directory in the way — all just "unknown"
124
+ }
125
+ }
126
+ /**
127
+ * Host gate: the Gemini leg may only run inside a server that Gemini CLI
128
+ * launched. The Gemini installer target stamps `SPECSHIP_HOST=gemini` into
129
+ * the `mcpServers.specship` entry (written AND printed snippet), so the env
130
+ * is present exactly in Gemini-launched server processes. Without this gate
131
+ * a **Claude Code** session in a repo that happens to contain
132
+ * `.gemini/settings.json` (or a shell exporting `GEMINI_MODEL`) would be
133
+ * silently compacted during the first-prompt window before the Claude marker
134
+ * exists — the exact crossover REQ-MODCTX-001.A6 closes on the Claude side.
135
+ */
136
+ function isGeminiHost(env = process.env) {
137
+ return env.SPECSHIP_HOST === 'gemini';
138
+ }
139
+ /**
140
+ * Resolve the Gemini CLI session's model id, or null when nothing names one
141
+ * (REQ-LOWEND-001). Host-gated: returns null outright unless
142
+ * `SPECSHIP_HOST=gemini` (see `isGeminiHost`). Then env first, then project
143
+ * settings, then global settings — first hit wins. The returned id is
144
+ * verbatim; mapping it to a tier is `modelTier`'s job.
145
+ */
146
+ function readGeminiSessionModel(cwd, env = process.env, homedir = os.homedir()) {
147
+ if (!isGeminiHost(env))
148
+ return null;
149
+ const fromEnv = env.GEMINI_MODEL;
150
+ if (typeof fromEnv === 'string' && fromEnv.trim())
151
+ return fromEnv;
152
+ for (const p of geminiSettingsPaths(cwd, homedir)) {
153
+ const model = readSettingsModel(p);
154
+ if (model)
155
+ return model;
156
+ }
157
+ return null;
158
+ }
159
+ //# sourceMappingURL=gemini-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-session.js","sourceRoot":"","sources":["../../src/mcp/gemini-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * MCP tool: specship_health (REQ-SURF-007).
3
+ *
4
+ * One code-health door. Folds the former `specship_maintainability`
5
+ * (MAINT-DOC) and `specship_fitness` (FITNESS-DOC) tools into a single surface
6
+ * with a `checks` filter — two tools answering "is this codebase healthy?" made
7
+ * the agent pick between them, and it under-picked both. The two renderers stay
8
+ * where they are; this composes them.
9
+ *
10
+ * Config is untouched: both reports still read `specship.config.json`
11
+ * (`maintainability.thresholds`, `fitness.rules`), and the CLI enforce/check
12
+ * paths call the library directly, not this tool.
13
+ */
14
+ import type { SpecShip } from '../index';
15
+ import type { ToolDefinition, ToolResult } from './tools';
16
+ export declare const HEALTH_CHECKS: readonly ["maintainability", "fitness"];
17
+ export type HealthCheck = (typeof HEALTH_CHECKS)[number];
18
+ export declare const healthToolDefinitions: ToolDefinition[];
19
+ /**
20
+ * Normalize the `checks` filter. Anything unrecognized (or absent) falls back
21
+ * to both reports — a filter typo must not silently return an empty health
22
+ * report.
23
+ */
24
+ export declare function resolveHealthChecks(raw: unknown): HealthCheck[];
25
+ export declare function handleSpecshipHealth(cg: SpecShip, args: Record<string, unknown>): Promise<ToolResult>;
26
+ //# sourceMappingURL=health-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-tool.d.ts","sourceRoot":"","sources":["../../src/mcp/health-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1D,eAAO,MAAM,aAAa,yCAA0C,CAAC;AACrE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,qBAAqB,EAAE,cAAc,EAoBjD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,EAAE,CAM/D;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,CAWrB"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.healthToolDefinitions = exports.HEALTH_CHECKS = void 0;
4
+ exports.resolveHealthChecks = resolveHealthChecks;
5
+ exports.handleSpecshipHealth = handleSpecshipHealth;
6
+ const maintainability_tool_1 = require("./maintainability-tool");
7
+ const fitness_tool_1 = require("./fitness-tool");
8
+ exports.HEALTH_CHECKS = ['maintainability', 'fitness'];
9
+ exports.healthToolDefinitions = [
10
+ {
11
+ name: 'specship_health',
12
+ description: 'Report code health from the graph: maintainability signals (coupling hotspots by fan-in/out, oversized symbols + god-files, dependency cycles, dead-code candidates) and architecture-fitness violations (forbidden dependencies, layering allow-lists, module isolation) with file:line. Deterministic, no new parse. Returns both by default; pass `checks` to narrow. Thresholds and rules come from specship.config.json (maintainability.thresholds, fitness.rules).',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ checks: {
17
+ type: 'array',
18
+ description: 'Which reports to include: "maintainability", "fitness". Omit for both.',
19
+ items: { type: 'string' },
20
+ },
21
+ projectPath: {
22
+ type: 'string',
23
+ description: 'Path to a different project with .specship/ initialized. Omit for the current project.',
24
+ },
25
+ },
26
+ },
27
+ },
28
+ ];
29
+ /**
30
+ * Normalize the `checks` filter. Anything unrecognized (or absent) falls back
31
+ * to both reports — a filter typo must not silently return an empty health
32
+ * report.
33
+ */
34
+ function resolveHealthChecks(raw) {
35
+ const requested = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];
36
+ const picked = exports.HEALTH_CHECKS.filter((c) => requested.some((r) => typeof r === 'string' && r.trim().toLowerCase() === c));
37
+ return picked.length > 0 ? picked : [...exports.HEALTH_CHECKS];
38
+ }
39
+ async function handleSpecshipHealth(cg, args) {
40
+ const checks = resolveHealthChecks(args.checks);
41
+ const sections = [];
42
+ for (const check of checks) {
43
+ const r = check === 'maintainability'
44
+ ? await (0, maintainability_tool_1.handleSpecshipMaintainability)(cg, args)
45
+ : await (0, fitness_tool_1.handleSpecshipFitness)(cg, args);
46
+ sections.push(r.content.map((c) => c.text).join('\n'));
47
+ }
48
+ return { content: [{ type: 'text', text: sections.join('\n\n') }] };
49
+ }
50
+ //# sourceMappingURL=health-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-tool.js","sourceRoot":"","sources":["../../src/mcp/health-tool.ts"],"names":[],"mappings":";;;AAgDA,kDAMC;AAED,oDAcC;AAvDD,iEAAuE;AACvE,iDAAuD;AAE1C,QAAA,aAAa,GAAG,CAAC,iBAAiB,EAAE,SAAS,CAAU,CAAC;AAGxD,QAAA,qBAAqB,GAAqB;IACrD;QACE,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,2cAA2c;QAC7c,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,wEAAwE;oBACrF,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBAC1B;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,wFAAwF;iBACtG;aACF;SACF;KACF;CACF,CAAC;AAEF;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,MAAM,MAAM,GAAG,qBAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACxC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAC7E,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,qBAAa,CAAC,CAAC;AACzD,CAAC;AAEM,KAAK,UAAU,oBAAoB,CACxC,EAAY,EACZ,IAA6B;IAE7B,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GACL,KAAK,KAAK,iBAAiB;YACzB,CAAC,CAAC,MAAM,IAAA,oDAA6B,EAAC,EAAE,EAAE,IAAI,CAAC;YAC/C,CAAC,CAAC,MAAM,IAAA,oCAAqB,EAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;AACtE,CAAC"}