@specforge/cli 0.1.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 (380) hide show
  1. package/README.md +781 -0
  2. package/bin/specforge +21 -0
  3. package/dist/channel.d.ts +27 -0
  4. package/dist/channel.d.ts.map +1 -0
  5. package/dist/channel.js +22 -0
  6. package/dist/channel.js.map +1 -0
  7. package/dist/cli/commands/configure.d.ts +16 -0
  8. package/dist/cli/commands/configure.d.ts.map +1 -0
  9. package/dist/cli/commands/configure.js +186 -0
  10. package/dist/cli/commands/configure.js.map +1 -0
  11. package/dist/cli/commands/configure.types.d.ts +110 -0
  12. package/dist/cli/commands/configure.types.d.ts.map +1 -0
  13. package/dist/cli/commands/configure.types.js +82 -0
  14. package/dist/cli/commands/configure.types.js.map +1 -0
  15. package/dist/cli/commands/debug/call.d.ts +14 -0
  16. package/dist/cli/commands/debug/call.d.ts.map +1 -0
  17. package/dist/cli/commands/debug/call.js +96 -0
  18. package/dist/cli/commands/debug/call.js.map +1 -0
  19. package/dist/cli/commands/debug/index.d.ts +12 -0
  20. package/dist/cli/commands/debug/index.d.ts.map +1 -0
  21. package/dist/cli/commands/debug/index.js +14 -0
  22. package/dist/cli/commands/debug/index.js.map +1 -0
  23. package/dist/cli/commands/debug/register.d.ts +11 -0
  24. package/dist/cli/commands/debug/register.d.ts.map +1 -0
  25. package/dist/cli/commands/debug/register.js +78 -0
  26. package/dist/cli/commands/debug/register.js.map +1 -0
  27. package/dist/cli/commands/debug/test.d.ts +13 -0
  28. package/dist/cli/commands/debug/test.d.ts.map +1 -0
  29. package/dist/cli/commands/debug/test.js +91 -0
  30. package/dist/cli/commands/debug/test.js.map +1 -0
  31. package/dist/cli/commands/debug/tools.d.ts +13 -0
  32. package/dist/cli/commands/debug/tools.d.ts.map +1 -0
  33. package/dist/cli/commands/debug/tools.js +86 -0
  34. package/dist/cli/commands/debug/tools.js.map +1 -0
  35. package/dist/cli/commands/debug/types.d.ts +119 -0
  36. package/dist/cli/commands/debug/types.d.ts.map +1 -0
  37. package/dist/cli/commands/debug/types.js +36 -0
  38. package/dist/cli/commands/debug/types.js.map +1 -0
  39. package/dist/cli/commands/debug/whoami.d.ts +13 -0
  40. package/dist/cli/commands/debug/whoami.d.ts.map +1 -0
  41. package/dist/cli/commands/debug/whoami.js +131 -0
  42. package/dist/cli/commands/debug/whoami.js.map +1 -0
  43. package/dist/cli/commands/doctor.d.ts +16 -0
  44. package/dist/cli/commands/doctor.d.ts.map +1 -0
  45. package/dist/cli/commands/doctor.js +413 -0
  46. package/dist/cli/commands/doctor.js.map +1 -0
  47. package/dist/cli/commands/doctor.types.d.ts +180 -0
  48. package/dist/cli/commands/doctor.types.d.ts.map +1 -0
  49. package/dist/cli/commands/doctor.types.js +140 -0
  50. package/dist/cli/commands/doctor.types.js.map +1 -0
  51. package/dist/cli/commands/feedback.d.ts +27 -0
  52. package/dist/cli/commands/feedback.d.ts.map +1 -0
  53. package/dist/cli/commands/feedback.js +262 -0
  54. package/dist/cli/commands/feedback.js.map +1 -0
  55. package/dist/cli/commands/feedback.types.d.ts +116 -0
  56. package/dist/cli/commands/feedback.types.d.ts.map +1 -0
  57. package/dist/cli/commands/feedback.types.js +65 -0
  58. package/dist/cli/commands/feedback.types.js.map +1 -0
  59. package/dist/cli/commands/index.d.ts +15 -0
  60. package/dist/cli/commands/index.d.ts.map +1 -0
  61. package/dist/cli/commands/index.js +21 -0
  62. package/dist/cli/commands/index.js.map +1 -0
  63. package/dist/cli/commands/init.d.ts +17 -0
  64. package/dist/cli/commands/init.d.ts.map +1 -0
  65. package/dist/cli/commands/init.js +773 -0
  66. package/dist/cli/commands/init.js.map +1 -0
  67. package/dist/cli/commands/init.types.d.ts +193 -0
  68. package/dist/cli/commands/init.types.d.ts.map +1 -0
  69. package/dist/cli/commands/init.types.js +29 -0
  70. package/dist/cli/commands/init.types.js.map +1 -0
  71. package/dist/cli/commands/invitations.d.ts +31 -0
  72. package/dist/cli/commands/invitations.d.ts.map +1 -0
  73. package/dist/cli/commands/invitations.js +250 -0
  74. package/dist/cli/commands/invitations.js.map +1 -0
  75. package/dist/cli/commands/login.d.ts +40 -0
  76. package/dist/cli/commands/login.d.ts.map +1 -0
  77. package/dist/cli/commands/login.js +139 -0
  78. package/dist/cli/commands/login.js.map +1 -0
  79. package/dist/cli/commands/members.d.ts +55 -0
  80. package/dist/cli/commands/members.d.ts.map +1 -0
  81. package/dist/cli/commands/members.js +296 -0
  82. package/dist/cli/commands/members.js.map +1 -0
  83. package/dist/cli/commands/scaffold/agent-types.d.ts +54 -0
  84. package/dist/cli/commands/scaffold/agent-types.d.ts.map +1 -0
  85. package/dist/cli/commands/scaffold/agent-types.js +22 -0
  86. package/dist/cli/commands/scaffold/agent-types.js.map +1 -0
  87. package/dist/cli/commands/scaffold/display.d.ts +56 -0
  88. package/dist/cli/commands/scaffold/display.d.ts.map +1 -0
  89. package/dist/cli/commands/scaffold/display.js +217 -0
  90. package/dist/cli/commands/scaffold/display.js.map +1 -0
  91. package/dist/cli/commands/scaffold/files.d.ts +99 -0
  92. package/dist/cli/commands/scaffold/files.d.ts.map +1 -0
  93. package/dist/cli/commands/scaffold/files.js +122 -0
  94. package/dist/cli/commands/scaffold/files.js.map +1 -0
  95. package/dist/cli/commands/scaffold/index.d.ts +13 -0
  96. package/dist/cli/commands/scaffold/index.d.ts.map +1 -0
  97. package/dist/cli/commands/scaffold/index.js +12 -0
  98. package/dist/cli/commands/scaffold/index.js.map +1 -0
  99. package/dist/cli/commands/scaffold/register.d.ts +11 -0
  100. package/dist/cli/commands/scaffold/register.d.ts.map +1 -0
  101. package/dist/cli/commands/scaffold/register.js +11 -0
  102. package/dist/cli/commands/scaffold/register.js.map +1 -0
  103. package/dist/cli/commands/scaffold/scaffold.d.ts +11 -0
  104. package/dist/cli/commands/scaffold/scaffold.d.ts.map +1 -0
  105. package/dist/cli/commands/scaffold/scaffold.js +728 -0
  106. package/dist/cli/commands/scaffold/scaffold.js.map +1 -0
  107. package/dist/cli/commands/scaffold/targets.d.ts +60 -0
  108. package/dist/cli/commands/scaffold/targets.d.ts.map +1 -0
  109. package/dist/cli/commands/scaffold/targets.js +251 -0
  110. package/dist/cli/commands/scaffold/targets.js.map +1 -0
  111. package/dist/cli/commands/scaffold/types.d.ts +170 -0
  112. package/dist/cli/commands/scaffold/types.d.ts.map +1 -0
  113. package/dist/cli/commands/scaffold/types.js +12 -0
  114. package/dist/cli/commands/scaffold/types.js.map +1 -0
  115. package/dist/cli/commands/scaffold/utils.d.ts +89 -0
  116. package/dist/cli/commands/scaffold/utils.d.ts.map +1 -0
  117. package/dist/cli/commands/scaffold/utils.js +401 -0
  118. package/dist/cli/commands/scaffold/utils.js.map +1 -0
  119. package/dist/cli/commands/status.d.ts +19 -0
  120. package/dist/cli/commands/status.d.ts.map +1 -0
  121. package/dist/cli/commands/status.js +124 -0
  122. package/dist/cli/commands/status.js.map +1 -0
  123. package/dist/cli/commands/status.types.d.ts +37 -0
  124. package/dist/cli/commands/status.types.d.ts.map +1 -0
  125. package/dist/cli/commands/status.types.js +7 -0
  126. package/dist/cli/commands/status.types.js.map +1 -0
  127. package/dist/cli/commands/switch.d.ts +18 -0
  128. package/dist/cli/commands/switch.d.ts.map +1 -0
  129. package/dist/cli/commands/switch.js +134 -0
  130. package/dist/cli/commands/switch.js.map +1 -0
  131. package/dist/cli/commands/switch.types.d.ts +123 -0
  132. package/dist/cli/commands/switch.types.d.ts.map +1 -0
  133. package/dist/cli/commands/switch.types.js +46 -0
  134. package/dist/cli/commands/switch.types.js.map +1 -0
  135. package/dist/cli/config/agent-teams.types.d.ts +120 -0
  136. package/dist/cli/config/agent-teams.types.d.ts.map +1 -0
  137. package/dist/cli/config/agent-teams.types.js +23 -0
  138. package/dist/cli/config/agent-teams.types.js.map +1 -0
  139. package/dist/cli/config/index.d.ts +13 -0
  140. package/dist/cli/config/index.d.ts.map +1 -0
  141. package/dist/cli/config/index.js +7 -0
  142. package/dist/cli/config/index.js.map +1 -0
  143. package/dist/cli/config/loader.d.ts +114 -0
  144. package/dist/cli/config/loader.d.ts.map +1 -0
  145. package/dist/cli/config/loader.js +198 -0
  146. package/dist/cli/config/loader.js.map +1 -0
  147. package/dist/cli/config/paths.d.ts +107 -0
  148. package/dist/cli/config/paths.d.ts.map +1 -0
  149. package/dist/cli/config/paths.js +79 -0
  150. package/dist/cli/config/paths.js.map +1 -0
  151. package/dist/cli/config/planning-sessions-registry.d.ts +52 -0
  152. package/dist/cli/config/planning-sessions-registry.d.ts.map +1 -0
  153. package/dist/cli/config/planning-sessions-registry.js +46 -0
  154. package/dist/cli/config/planning-sessions-registry.js.map +1 -0
  155. package/dist/cli/config/types.d.ts +186 -0
  156. package/dist/cli/config/types.d.ts.map +1 -0
  157. package/dist/cli/config/types.js +27 -0
  158. package/dist/cli/config/types.js.map +1 -0
  159. package/dist/cli/config/validation.d.ts +62 -0
  160. package/dist/cli/config/validation.d.ts.map +1 -0
  161. package/dist/cli/config/validation.js +133 -0
  162. package/dist/cli/config/validation.js.map +1 -0
  163. package/dist/cli/config/writer.d.ts +153 -0
  164. package/dist/cli/config/writer.d.ts.map +1 -0
  165. package/dist/cli/config/writer.js +168 -0
  166. package/dist/cli/config/writer.js.map +1 -0
  167. package/dist/cli/index.d.ts +30 -0
  168. package/dist/cli/index.d.ts.map +1 -0
  169. package/dist/cli/index.js +142 -0
  170. package/dist/cli/index.js.map +1 -0
  171. package/dist/cli/middleware/auth-guard.d.ts +107 -0
  172. package/dist/cli/middleware/auth-guard.d.ts.map +1 -0
  173. package/dist/cli/middleware/auth-guard.js +97 -0
  174. package/dist/cli/middleware/auth-guard.js.map +1 -0
  175. package/dist/cli/middleware/error-handler.d.ts +133 -0
  176. package/dist/cli/middleware/error-handler.d.ts.map +1 -0
  177. package/dist/cli/middleware/error-handler.js +139 -0
  178. package/dist/cli/middleware/error-handler.js.map +1 -0
  179. package/dist/cli/middleware/index.d.ts +6 -0
  180. package/dist/cli/middleware/index.d.ts.map +1 -0
  181. package/dist/cli/middleware/index.js +3 -0
  182. package/dist/cli/middleware/index.js.map +1 -0
  183. package/dist/cli/templates/agents/content/core/sfag-orchestrator.d.ts +9 -0
  184. package/dist/cli/templates/agents/content/core/sfag-orchestrator.d.ts.map +1 -0
  185. package/dist/cli/templates/agents/content/core/sfag-orchestrator.js +160 -0
  186. package/dist/cli/templates/agents/content/core/sfag-orchestrator.js.map +1 -0
  187. package/dist/cli/templates/agents/content/core/sfag-spec-creator.d.ts +9 -0
  188. package/dist/cli/templates/agents/content/core/sfag-spec-creator.d.ts.map +1 -0
  189. package/dist/cli/templates/agents/content/core/sfag-spec-creator.js +343 -0
  190. package/dist/cli/templates/agents/content/core/sfag-spec-creator.js.map +1 -0
  191. package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.d.ts +9 -0
  192. package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.d.ts.map +1 -0
  193. package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js +254 -0
  194. package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js.map +1 -0
  195. package/dist/cli/templates/agents/content/research/sfag-package-researcher.d.ts +8 -0
  196. package/dist/cli/templates/agents/content/research/sfag-package-researcher.d.ts.map +1 -0
  197. package/dist/cli/templates/agents/content/research/sfag-package-researcher.js +128 -0
  198. package/dist/cli/templates/agents/content/research/sfag-package-researcher.js.map +1 -0
  199. package/dist/cli/templates/agents/index.d.ts +23 -0
  200. package/dist/cli/templates/agents/index.d.ts.map +1 -0
  201. package/dist/cli/templates/agents/index.js +29 -0
  202. package/dist/cli/templates/agents/index.js.map +1 -0
  203. package/dist/cli/templates/commands.d.ts +17 -0
  204. package/dist/cli/templates/commands.d.ts.map +1 -0
  205. package/dist/cli/templates/commands.js +78 -0
  206. package/dist/cli/templates/commands.js.map +1 -0
  207. package/dist/cli/templates/content/sf-blockers.d.ts +7 -0
  208. package/dist/cli/templates/content/sf-blockers.d.ts.map +1 -0
  209. package/dist/cli/templates/content/sf-blockers.js +69 -0
  210. package/dist/cli/templates/content/sf-blockers.js.map +1 -0
  211. package/dist/cli/templates/content/sf-commit.d.ts +7 -0
  212. package/dist/cli/templates/content/sf-commit.d.ts.map +1 -0
  213. package/dist/cli/templates/content/sf-commit.js +79 -0
  214. package/dist/cli/templates/content/sf-commit.js.map +1 -0
  215. package/dist/cli/templates/content/sf-context.d.ts +7 -0
  216. package/dist/cli/templates/content/sf-context.d.ts.map +1 -0
  217. package/dist/cli/templates/content/sf-context.js +63 -0
  218. package/dist/cli/templates/content/sf-context.js.map +1 -0
  219. package/dist/cli/templates/content/sf-help.d.ts +7 -0
  220. package/dist/cli/templates/content/sf-help.d.ts.map +1 -0
  221. package/dist/cli/templates/content/sf-help.js +42 -0
  222. package/dist/cli/templates/content/sf-help.js.map +1 -0
  223. package/dist/cli/templates/content/sf-init.d.ts +7 -0
  224. package/dist/cli/templates/content/sf-init.d.ts.map +1 -0
  225. package/dist/cli/templates/content/sf-init.js +62 -0
  226. package/dist/cli/templates/content/sf-init.js.map +1 -0
  227. package/dist/cli/templates/content/sf-reset.d.ts +7 -0
  228. package/dist/cli/templates/content/sf-reset.d.ts.map +1 -0
  229. package/dist/cli/templates/content/sf-reset.js +67 -0
  230. package/dist/cli/templates/content/sf-reset.js.map +1 -0
  231. package/dist/cli/templates/content/sf-search.d.ts +7 -0
  232. package/dist/cli/templates/content/sf-search.d.ts.map +1 -0
  233. package/dist/cli/templates/content/sf-search.js +63 -0
  234. package/dist/cli/templates/content/sf-search.js.map +1 -0
  235. package/dist/cli/templates/content/sf-status.d.ts +7 -0
  236. package/dist/cli/templates/content/sf-status.d.ts.map +1 -0
  237. package/dist/cli/templates/content/sf-status.js +62 -0
  238. package/dist/cli/templates/content/sf-status.js.map +1 -0
  239. package/dist/cli/templates/index.d.ts +8 -0
  240. package/dist/cli/templates/index.d.ts.map +1 -0
  241. package/dist/cli/templates/index.js +17 -0
  242. package/dist/cli/templates/index.js.map +1 -0
  243. package/dist/cli/ui/banner.d.ts +38 -0
  244. package/dist/cli/ui/banner.d.ts.map +1 -0
  245. package/dist/cli/ui/banner.js +89 -0
  246. package/dist/cli/ui/banner.js.map +1 -0
  247. package/dist/cli/ui/colors.d.ts +76 -0
  248. package/dist/cli/ui/colors.d.ts.map +1 -0
  249. package/dist/cli/ui/colors.js +67 -0
  250. package/dist/cli/ui/colors.js.map +1 -0
  251. package/dist/cli/ui/index.d.ts +7 -0
  252. package/dist/cli/ui/index.d.ts.map +1 -0
  253. package/dist/cli/ui/index.js +4 -0
  254. package/dist/cli/ui/index.js.map +1 -0
  255. package/dist/cli/ui/output.d.ts +117 -0
  256. package/dist/cli/ui/output.d.ts.map +1 -0
  257. package/dist/cli/ui/output.js +83 -0
  258. package/dist/cli/ui/output.js.map +1 -0
  259. package/dist/cli/ui/spinner.d.ts +120 -0
  260. package/dist/cli/ui/spinner.d.ts.map +1 -0
  261. package/dist/cli/ui/spinner.js +158 -0
  262. package/dist/cli/ui/spinner.js.map +1 -0
  263. package/dist/cli/ui/time.d.ts +54 -0
  264. package/dist/cli/ui/time.d.ts.map +1 -0
  265. package/dist/cli/ui/time.js +119 -0
  266. package/dist/cli/ui/time.js.map +1 -0
  267. package/dist/client/api-client.d.ts +123 -0
  268. package/dist/client/api-client.d.ts.map +1 -0
  269. package/dist/client/api-client.js +105 -0
  270. package/dist/client/api-client.js.map +1 -0
  271. package/dist/client/cli-client.d.ts +26 -0
  272. package/dist/client/cli-client.d.ts.map +1 -0
  273. package/dist/client/cli-client.js +20 -0
  274. package/dist/client/cli-client.js.map +1 -0
  275. package/dist/config/index.d.ts +78 -0
  276. package/dist/config/index.d.ts.map +1 -0
  277. package/dist/config/index.js +79 -0
  278. package/dist/config/index.js.map +1 -0
  279. package/dist/index.d.ts +16 -0
  280. package/dist/index.d.ts.map +1 -0
  281. package/dist/index.js +73 -0
  282. package/dist/index.js.map +1 -0
  283. package/dist/lib/format.d.ts +126 -0
  284. package/dist/lib/format.d.ts.map +1 -0
  285. package/dist/lib/format.js +71 -0
  286. package/dist/lib/format.js.map +1 -0
  287. package/dist/lib/index.d.ts +11 -0
  288. package/dist/lib/index.d.ts.map +1 -0
  289. package/dist/lib/index.js +45 -0
  290. package/dist/lib/index.js.map +1 -0
  291. package/dist/lib/monorepo-detector.d.ts +31 -0
  292. package/dist/lib/monorepo-detector.d.ts.map +1 -0
  293. package/dist/lib/monorepo-detector.js +188 -0
  294. package/dist/lib/monorepo-detector.js.map +1 -0
  295. package/dist/lib/prompt-generator.d.ts +65 -0
  296. package/dist/lib/prompt-generator.d.ts.map +1 -0
  297. package/dist/lib/prompt-generator.js +162 -0
  298. package/dist/lib/prompt-generator.js.map +1 -0
  299. package/dist/lib/strategy-analyzer.d.ts +59 -0
  300. package/dist/lib/strategy-analyzer.d.ts.map +1 -0
  301. package/dist/lib/strategy-analyzer.js +91 -0
  302. package/dist/lib/strategy-analyzer.js.map +1 -0
  303. package/dist/lib/workflow-definitions.d.ts +41 -0
  304. package/dist/lib/workflow-definitions.d.ts.map +1 -0
  305. package/dist/lib/workflow-definitions.js +497 -0
  306. package/dist/lib/workflow-definitions.js.map +1 -0
  307. package/dist/patterns/index.d.ts +9 -0
  308. package/dist/patterns/index.d.ts.map +1 -0
  309. package/dist/patterns/index.js +21 -0
  310. package/dist/patterns/index.js.map +1 -0
  311. package/dist/patterns/inheritance.d.ts +193 -0
  312. package/dist/patterns/inheritance.d.ts.map +1 -0
  313. package/dist/patterns/inheritance.js +125 -0
  314. package/dist/patterns/inheritance.js.map +1 -0
  315. package/dist/server.d.ts +44 -0
  316. package/dist/server.d.ts.map +1 -0
  317. package/dist/server.js +91 -0
  318. package/dist/server.js.map +1 -0
  319. package/dist/tools/core/context-helper.d.ts +50 -0
  320. package/dist/tools/core/context-helper.d.ts.map +1 -0
  321. package/dist/tools/core/context-helper.js +49 -0
  322. package/dist/tools/core/context-helper.js.map +1 -0
  323. package/dist/tools/core/index.d.ts +2 -0
  324. package/dist/tools/core/index.d.ts.map +1 -0
  325. package/dist/tools/core/index.js +2 -0
  326. package/dist/tools/core/index.js.map +1 -0
  327. package/dist/tools/index.d.ts +58 -0
  328. package/dist/tools/index.d.ts.map +1 -0
  329. package/dist/tools/index.js +1499 -0
  330. package/dist/tools/index.js.map +1 -0
  331. package/dist/transport/__tests__/resolve-endpoint.test.d.ts +6 -0
  332. package/dist/transport/__tests__/resolve-endpoint.test.d.ts.map +1 -0
  333. package/dist/transport/index.d.ts +6 -0
  334. package/dist/transport/index.d.ts.map +1 -0
  335. package/dist/transport/index.js +5 -0
  336. package/dist/transport/index.js.map +1 -0
  337. package/dist/transport/interface.d.ts +25 -0
  338. package/dist/transport/interface.d.ts.map +1 -0
  339. package/dist/transport/interface.js +1 -0
  340. package/dist/transport/interface.js.map +1 -0
  341. package/dist/transport/remote.d.ts +38 -0
  342. package/dist/transport/remote.d.ts.map +1 -0
  343. package/dist/transport/remote.js +107 -0
  344. package/dist/transport/remote.js.map +1 -0
  345. package/dist/transport/resolve-endpoint.d.ts +58 -0
  346. package/dist/transport/resolve-endpoint.d.ts.map +1 -0
  347. package/dist/transport/resolve-endpoint.js +146 -0
  348. package/dist/transport/resolve-endpoint.js.map +1 -0
  349. package/dist/types/index.d.ts +212 -0
  350. package/dist/types/index.d.ts.map +1 -0
  351. package/dist/types/index.js +16 -0
  352. package/dist/types/index.js.map +1 -0
  353. package/dist/validation/index.d.ts +86 -0
  354. package/dist/validation/index.d.ts.map +1 -0
  355. package/dist/validation/index.js +392 -0
  356. package/dist/validation/index.js.map +1 -0
  357. package/dist/validation/ticket-validation.d.ts +162 -0
  358. package/dist/validation/ticket-validation.d.ts.map +1 -0
  359. package/dist/validation/ticket-validation.js +188 -0
  360. package/dist/validation/ticket-validation.js.map +1 -0
  361. package/package.json +69 -0
  362. package/src/cli/templates/agents/content/core/sfag-orchestrator.ts +165 -0
  363. package/src/cli/templates/agents/content/core/sfag-spec-creator.ts +348 -0
  364. package/src/cli/templates/agents/content/core/sfag-ticket-implementer.ts +259 -0
  365. package/src/cli/templates/agents/content/research/sfag-package-researcher.ts +132 -0
  366. package/src/cli/templates/agents/index.ts +47 -0
  367. package/src/cli/templates/commands.ts +90 -0
  368. package/src/cli/templates/content/sf-blockers.ts +71 -0
  369. package/src/cli/templates/content/sf-commit.ts +81 -0
  370. package/src/cli/templates/content/sf-context.ts +65 -0
  371. package/src/cli/templates/content/sf-help.ts +44 -0
  372. package/src/cli/templates/content/sf-init.ts +64 -0
  373. package/src/cli/templates/content/sf-reset.ts +69 -0
  374. package/src/cli/templates/content/sf-search.ts +65 -0
  375. package/src/cli/templates/content/sf-status.ts +64 -0
  376. package/src/cli/templates/index.ts +16 -0
  377. package/src/cli/templates/skills/specforge-conventions.md +114 -0
  378. package/src/cli/templates/skills/specforge-orchestrator.md +409 -0
  379. package/src/cli/templates/skills/specforge-validator.md +128 -0
  380. package/src/cli/templates/skills/specforge-worker.md +412 -0
@@ -0,0 +1,131 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import { resolveConfig, getConfigPaths } from "../../config/index.js";
4
+ import { createCliClient } from "../../../client/cli-client.js";
5
+ import { CHANNEL } from "../../../channel.js";
6
+ function maskApiKey(apiKey) {
7
+ if (apiKey.length < 12) {
8
+ return "****";
9
+ }
10
+ return `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`;
11
+ }
12
+ function getConfigSource(config) {
13
+ if (process.env.SPECFORGE_API_KEY) {
14
+ return "environment";
15
+ }
16
+ if (config.projectId) {
17
+ return ".specforge.json (project)";
18
+ }
19
+ if (config.apiKey) {
20
+ return "~/.specforge/config.json (global)";
21
+ }
22
+ return "defaults";
23
+ }
24
+ function displayUserInfo(info) {
25
+ console.log(chalk.bold("\nUser"));
26
+ console.log("\u2500\u2500\u2500\u2500");
27
+ if (info.user.name) {
28
+ console.log(`Name: ${info.user.name}`);
29
+ }
30
+ console.log(`Email: ${info.user.email}`);
31
+ console.log(`API Key: ${info.user.apiKey}`);
32
+ }
33
+ function displayConfiguration(info) {
34
+ console.log(chalk.bold("\nConfiguration"));
35
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
36
+ console.log(`Source: ${info.configuration.source}`);
37
+ if (info.configuration.projectName) {
38
+ console.log(`Project: ${info.configuration.projectName} (${info.configuration.projectId})`);
39
+ } else if (info.configuration.projectId) {
40
+ console.log(`Project: ${info.configuration.projectId}`);
41
+ } else {
42
+ console.log(`Project: ${chalk.dim("(not set)")}`);
43
+ }
44
+ if (info.configuration.specificationTitle) {
45
+ console.log(`Spec: ${info.configuration.specificationTitle} (${info.configuration.specificationId})`);
46
+ } else if (info.configuration.specificationId) {
47
+ console.log(`Spec: ${info.configuration.specificationId}`);
48
+ } else {
49
+ console.log(`Spec: ${chalk.dim("(not set)")}`);
50
+ }
51
+ console.log(`MCP format: ${info.configuration.mcpOutputFormat}`);
52
+ }
53
+ function displayPaths(info) {
54
+ console.log(chalk.bold("\nPaths"));
55
+ console.log("\u2500\u2500\u2500\u2500\u2500");
56
+ console.log(`Project config: ${info.paths.projectConfig}`);
57
+ console.log(`MCP config: ${info.paths.mcpConfig}`);
58
+ console.log(`Global config: ${info.paths.globalConfig}`);
59
+ console.log();
60
+ }
61
+ async function whoamiCommand(options) {
62
+ const config = resolveConfig();
63
+ const paths = getConfigPaths();
64
+ const spinner = ora("Fetching user info...").start();
65
+ try {
66
+ const client = createCliClient({
67
+ apiKey: config.apiKey,
68
+ apiUrl: process.env.SPECFORGE_API_URL || CHANNEL.endpoint.primary,
69
+ debug: config.debug
70
+ });
71
+ const userResponse = await client.call("get_current_user", {});
72
+ const userEmail = userResponse.email || "Unknown";
73
+ const userName = userResponse.name;
74
+ let projectName;
75
+ if (config.projectId) {
76
+ try {
77
+ const proj = await client.call("get_project", { projectId: config.projectId });
78
+ projectName = proj.name;
79
+ } catch {
80
+ }
81
+ }
82
+ let specTitle;
83
+ if (config.specificationId) {
84
+ try {
85
+ const spec = await client.call("get_specification", {
86
+ specificationId: config.specificationId
87
+ });
88
+ specTitle = spec.title;
89
+ } catch {
90
+ }
91
+ }
92
+ spinner.stop();
93
+ const info = {
94
+ user: {
95
+ name: userName,
96
+ email: userEmail,
97
+ apiKey: maskApiKey(config.apiKey)
98
+ },
99
+ configuration: {
100
+ source: getConfigSource(config),
101
+ projectId: config.projectId || void 0,
102
+ projectName,
103
+ specificationId: config.specificationId || void 0,
104
+ specificationTitle: specTitle,
105
+ mcpOutputFormat: config.mcpOutputFormat || "json"
106
+ },
107
+ paths: {
108
+ projectConfig: paths.projectConfig,
109
+ mcpConfig: paths.mcpConfig,
110
+ globalConfig: paths.globalConfig
111
+ }
112
+ };
113
+ if (options.json) {
114
+ console.log(JSON.stringify(info, null, 2));
115
+ return;
116
+ }
117
+ displayUserInfo(info);
118
+ displayConfiguration(info);
119
+ displayPaths(info);
120
+ } catch (error) {
121
+ spinner.fail("Failed to fetch user info");
122
+ const message = error instanceof Error ? error.message : "Unknown error";
123
+ console.error(chalk.red(`
124
+ Error: ${message}`));
125
+ process.exit(1);
126
+ }
127
+ }
128
+ export {
129
+ whoamiCommand
130
+ };
131
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/cli/commands/debug/whoami.ts"],"sourcesContent":["/**\n * Whoami Command Implementation\n *\n * Displays current user information, configuration settings, and config file paths.\n */\n\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { resolveConfig, getConfigPaths } from '../../config/index.js';\nimport { createCliClient } from '../../../client/cli-client.js';\nimport { CHANNEL } from '../../../channel.js';\nimport type { WhoamiOptions, WhoamiInfo } from './types.js';\n\n/**\n * Mask API key for display\n */\nfunction maskApiKey(apiKey: string): string {\n if (apiKey.length < 12) {\n return '****';\n }\n return `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`;\n}\n\n/**\n * Determine configuration source\n */\nfunction getConfigSource(config: { apiKey?: string | null; projectId?: string | null }): string {\n if (process.env.SPECFORGE_API_KEY) {\n return 'environment';\n }\n if (config.projectId) {\n return '.specforge.json (project)';\n }\n if (config.apiKey) {\n return '~/.specforge/config.json (global)';\n }\n return 'defaults';\n}\n\n/**\n * Display user information\n */\nfunction displayUserInfo(info: WhoamiInfo): void {\n console.log(chalk.bold('\\nUser'));\n console.log('────');\n if (info.user.name) {\n console.log(`Name: ${info.user.name}`);\n }\n console.log(`Email: ${info.user.email}`);\n console.log(`API Key: ${info.user.apiKey}`);\n}\n\n/**\n * Display configuration information\n */\nfunction displayConfiguration(info: WhoamiInfo): void {\n console.log(chalk.bold('\\nConfiguration'));\n console.log('─────────────');\n console.log(`Source: ${info.configuration.source}`);\n\n if (info.configuration.projectName) {\n console.log(`Project: ${info.configuration.projectName} (${info.configuration.projectId})`);\n } else if (info.configuration.projectId) {\n console.log(`Project: ${info.configuration.projectId}`);\n } else {\n console.log(`Project: ${chalk.dim('(not set)')}`);\n }\n\n if (info.configuration.specificationTitle) {\n console.log(`Spec: ${info.configuration.specificationTitle} (${info.configuration.specificationId})`);\n } else if (info.configuration.specificationId) {\n console.log(`Spec: ${info.configuration.specificationId}`);\n } else {\n console.log(`Spec: ${chalk.dim('(not set)')}`);\n }\n\n console.log(`MCP format: ${info.configuration.mcpOutputFormat}`);\n}\n\n/**\n * Display configuration file paths\n */\nfunction displayPaths(info: WhoamiInfo): void {\n console.log(chalk.bold('\\nPaths'));\n console.log('─────');\n console.log(`Project config: ${info.paths.projectConfig}`);\n console.log(`MCP config: ${info.paths.mcpConfig}`);\n console.log(`Global config: ${info.paths.globalConfig}`);\n console.log();\n}\n\n/**\n * Whoami command implementation\n *\n * Displays current user and configuration information.\n */\nexport async function whoamiCommand(options: WhoamiOptions): Promise<void> {\n const config = resolveConfig();\n const paths = getConfigPaths();\n\n const spinner = ora('Fetching user info...').start();\n\n try {\n const client = createCliClient({\n apiKey: config.apiKey!,\n apiUrl: process.env.SPECFORGE_API_URL || CHANNEL.endpoint.primary,\n debug: config.debug,\n });\n\n // Get user info\n const userResponse = await client.call('get_current_user', {}) as { email?: string; name?: string };\n const userEmail = userResponse.email || 'Unknown';\n const userName = userResponse.name;\n\n // Get project name if configured\n let projectName: string | undefined;\n if (config.projectId) {\n try {\n const proj = await client.call('get_project', { projectId: config.projectId });\n projectName = (proj as { name?: string }).name;\n } catch {\n // Ignore - project might not exist\n }\n }\n\n // Get specification title if configured\n let specTitle: string | undefined;\n if (config.specificationId) {\n try {\n const spec = await client.call('get_specification', {\n specificationId: config.specificationId\n });\n specTitle = (spec as { title?: string }).title;\n } catch {\n // Ignore - spec might not exist\n }\n }\n\n spinner.stop();\n\n // Build whoami info\n const info: WhoamiInfo = {\n user: {\n name: userName,\n email: userEmail,\n apiKey: maskApiKey(config.apiKey!),\n },\n configuration: {\n source: getConfigSource(config),\n projectId: config.projectId || undefined,\n projectName,\n specificationId: config.specificationId || undefined,\n specificationTitle: specTitle,\n mcpOutputFormat: config.mcpOutputFormat || 'json',\n },\n paths: {\n projectConfig: paths.projectConfig,\n mcpConfig: paths.mcpConfig,\n globalConfig: paths.globalConfig,\n },\n };\n\n // JSON output\n if (options.json) {\n console.log(JSON.stringify(info, null, 2));\n return;\n }\n\n // Display formatted output\n displayUserInfo(info);\n displayConfiguration(info);\n displayPaths(info);\n\n } catch (error) {\n spinner.fail('Failed to fetch user info');\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(chalk.red(`\\nError: ${message}`));\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Doctor Command
3
+ *
4
+ * Diagnoses configuration and connection issues for SpecForge MCP.
5
+ */
6
+ import { Command } from 'commander';
7
+ import { DoctorOptions } from './doctor.types.js';
8
+ /**
9
+ * Doctor command action handler
10
+ */
11
+ export declare function doctorAction(options: DoctorOptions): Promise<void>;
12
+ /**
13
+ * Register doctor command with Commander
14
+ */
15
+ export declare function registerDoctorCommand(program: Command): void;
16
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,OAAO,EACL,aAAa,EAkBd,MAAM,mBAAmB,CAAC;AAoZ3B;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DxE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsB5D"}
@@ -0,0 +1,413 @@
1
+ import fs from "node:fs";
2
+ import {
3
+ resolveConfig,
4
+ loadGlobalConfig,
5
+ tryLoadProjectConfig,
6
+ getConfigPaths
7
+ } from "../config/index.js";
8
+ import { withErrorHandler } from "../middleware/error-handler.js";
9
+ import { printBlank, printHeader } from "../ui/output.js";
10
+ import { colors } from "../ui/colors.js";
11
+ import { forgeProgress } from "../ui/spinner.js";
12
+ import { createCliClient } from "../../client/cli-client.js";
13
+ import { CHANNEL } from "../../channel.js";
14
+ import {
15
+ createPassResult,
16
+ createFailResult,
17
+ createWarnResult,
18
+ calculateSummary,
19
+ hasFailures,
20
+ getStatusIcon,
21
+ CHECK_CATEGORIES,
22
+ CONFIG_CHECK_NAMES,
23
+ AUTH_CHECK_NAMES,
24
+ CONNECTION_CHECK_NAMES,
25
+ PROJECT_CHECK_NAMES,
26
+ PERFORMANCE_THRESHOLDS,
27
+ API_KEY_VALIDATION,
28
+ FIX_SUGGESTIONS
29
+ } from "./doctor.types.js";
30
+ function maskApiKey(apiKey, visibleChars = 8) {
31
+ if (apiKey.length <= visibleChars) {
32
+ return "***";
33
+ }
34
+ return `${API_KEY_VALIDATION.PREFIX}...${apiKey.slice(-visibleChars)}`;
35
+ }
36
+ function runConfigurationChecks() {
37
+ const results = [];
38
+ const paths = getConfigPaths();
39
+ const globalConfig = loadGlobalConfig();
40
+ const projectConfig = tryLoadProjectConfig();
41
+ results.push(createPassResult(
42
+ CONFIG_CHECK_NAMES.CHANNEL,
43
+ `${CHANNEL.name} \xB7 ${CHANNEL.packageName} \xB7 ${CHANNEL.endpoint.primary}`,
44
+ { name: CHANNEL.name, packageName: CHANNEL.packageName, endpoint: CHANNEL.endpoint.primary }
45
+ ));
46
+ if (fs.existsSync(paths.mcpConfig)) {
47
+ results.push(createPassResult(
48
+ CONFIG_CHECK_NAMES.MCP_CONFIG_FOUND,
49
+ paths.mcpConfig
50
+ ));
51
+ } else {
52
+ results.push(createFailResult(
53
+ CONFIG_CHECK_NAMES.MCP_CONFIG_FOUND,
54
+ "File not found",
55
+ FIX_SUGGESTIONS.MISSING_MCP_CONFIG
56
+ ));
57
+ }
58
+ if (projectConfig) {
59
+ results.push(createPassResult(
60
+ CONFIG_CHECK_NAMES.PROJECT_CONFIG_FOUND,
61
+ paths.projectConfig
62
+ ));
63
+ } else {
64
+ results.push(createWarnResult(
65
+ CONFIG_CHECK_NAMES.PROJECT_CONFIG_FOUND,
66
+ "File not found (optional)",
67
+ FIX_SUGGESTIONS.MISSING_PROJECT_CONFIG
68
+ ));
69
+ }
70
+ results.push(createPassResult(
71
+ CONFIG_CHECK_NAMES.GLOBAL_CONFIG_DIR,
72
+ paths.globalConfig
73
+ ));
74
+ if (projectConfig?.planningSessionId) {
75
+ results.push(createPassResult(
76
+ CONFIG_CHECK_NAMES.PLANNING_SESSION,
77
+ projectConfig.planningSessionId
78
+ ));
79
+ } else {
80
+ results.push(createWarnResult(
81
+ CONFIG_CHECK_NAMES.PLANNING_SESSION,
82
+ "None (no planning session persisted for this spec)"
83
+ ));
84
+ }
85
+ const apiKeySource = process.env.SPECFORGE_API_KEY ? "From environment variable" : globalConfig.apiKey ? "From ~/.specforge/config.json" : void 0;
86
+ if (apiKeySource) {
87
+ results.push(createPassResult(
88
+ CONFIG_CHECK_NAMES.API_KEY_CONFIGURED,
89
+ apiKeySource
90
+ ));
91
+ } else {
92
+ results.push(createFailResult(
93
+ CONFIG_CHECK_NAMES.API_KEY_CONFIGURED,
94
+ "No API key found",
95
+ FIX_SUGGESTIONS.MISSING_API_KEY
96
+ ));
97
+ }
98
+ return results;
99
+ }
100
+ async function runAuthenticationChecks(apiKey) {
101
+ const results = [];
102
+ if (!apiKey) {
103
+ results.push(createFailResult(
104
+ AUTH_CHECK_NAMES.API_KEY_FORMAT,
105
+ "No API key to validate"
106
+ ));
107
+ return results;
108
+ }
109
+ const hasValidPrefix = apiKey.startsWith(API_KEY_VALIDATION.PREFIX);
110
+ const hasValidLength = apiKey.length >= API_KEY_VALIDATION.MIN_LENGTH;
111
+ if (hasValidPrefix && hasValidLength) {
112
+ results.push(createPassResult(
113
+ AUTH_CHECK_NAMES.API_KEY_FORMAT,
114
+ maskApiKey(apiKey)
115
+ ));
116
+ } else {
117
+ const issues = [];
118
+ if (!hasValidPrefix) issues.push(`should start with ${API_KEY_VALIDATION.PREFIX}`);
119
+ if (!hasValidLength) issues.push(`minimum ${API_KEY_VALIDATION.MIN_LENGTH} characters`);
120
+ results.push(createFailResult(
121
+ AUTH_CHECK_NAMES.API_KEY_FORMAT,
122
+ `Invalid format (${issues.join(", ")})`,
123
+ FIX_SUGGESTIONS.INVALID_API_KEY_FORMAT
124
+ ));
125
+ return results;
126
+ }
127
+ const config = resolveConfig();
128
+ const client = createCliClient({
129
+ apiKey,
130
+ apiUrl: config.apiUrl,
131
+ debug: config.debug
132
+ });
133
+ try {
134
+ await client.call("list_projects", {});
135
+ results.push(createPassResult(
136
+ AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,
137
+ "Successfully authenticated"
138
+ ));
139
+ try {
140
+ const userResponse = await client.call(
141
+ "get_current_user",
142
+ {}
143
+ );
144
+ const userInfo = userResponse.name ? `${userResponse.name} (${userResponse.email})` : userResponse.email || "Unknown";
145
+ results.push(createPassResult(
146
+ AUTH_CHECK_NAMES.USER_INFO,
147
+ userInfo
148
+ ));
149
+ } catch {
150
+ results.push(createPassResult(
151
+ AUTH_CHECK_NAMES.USER_INFO,
152
+ "Authenticated (email not available)"
153
+ ));
154
+ }
155
+ } catch (error) {
156
+ const message = error instanceof Error ? error.message : "Unknown error";
157
+ if (message.includes("401") || message.includes("Unauthorized")) {
158
+ results.push(createFailResult(
159
+ AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,
160
+ "Invalid or expired API key",
161
+ FIX_SUGGESTIONS.EXPIRED_API_KEY
162
+ ));
163
+ } else {
164
+ results.push(createFailResult(
165
+ AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,
166
+ `Authentication failed: ${message}`
167
+ ));
168
+ }
169
+ }
170
+ return results;
171
+ }
172
+ async function runConnectionChecks(apiKey) {
173
+ const results = [];
174
+ const config = resolveConfig();
175
+ const apiUrl = config.apiUrl;
176
+ if (!apiKey) {
177
+ results.push(createFailResult(
178
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
179
+ "No API key to test connection",
180
+ FIX_SUGGESTIONS.MISSING_API_KEY
181
+ ));
182
+ return results;
183
+ }
184
+ const client = createCliClient({
185
+ apiKey,
186
+ apiUrl: config.apiUrl,
187
+ debug: config.debug
188
+ });
189
+ try {
190
+ const start = Date.now();
191
+ await client.call("list_projects", {});
192
+ const elapsed = Date.now() - start;
193
+ results.push(createPassResult(
194
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
195
+ apiUrl
196
+ ));
197
+ if (elapsed < PERFORMANCE_THRESHOLDS.RESPONSE_TIME_WARNING) {
198
+ results.push(createPassResult(
199
+ CONNECTION_CHECK_NAMES.RESPONSE_TIME,
200
+ `${elapsed}ms`,
201
+ { elapsed }
202
+ ));
203
+ } else if (elapsed < PERFORMANCE_THRESHOLDS.RESPONSE_TIME_ERROR) {
204
+ results.push(createWarnResult(
205
+ CONNECTION_CHECK_NAMES.RESPONSE_TIME,
206
+ `${elapsed}ms (slow)`,
207
+ void 0,
208
+ { elapsed }
209
+ ));
210
+ } else {
211
+ results.push(createFailResult(
212
+ CONNECTION_CHECK_NAMES.RESPONSE_TIME,
213
+ `${elapsed}ms (very slow)`,
214
+ FIX_SUGGESTIONS.CONNECTION_TIMEOUT,
215
+ { elapsed }
216
+ ));
217
+ }
218
+ } catch (error) {
219
+ const message = error instanceof Error ? error.message : "Unknown error";
220
+ if (message.includes("ENOTFOUND") || message.includes("ECONNREFUSED") || message.includes("getaddrinfo")) {
221
+ results.push(createFailResult(
222
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
223
+ "Could not connect to API",
224
+ FIX_SUGGESTIONS.CONNECTION_FAILED
225
+ ));
226
+ } else if (message.includes("timeout") || message.includes("TimeoutError")) {
227
+ results.push(createFailResult(
228
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
229
+ "Connection timed out",
230
+ FIX_SUGGESTIONS.CONNECTION_TIMEOUT
231
+ ));
232
+ } else if (message.includes("401") || message.includes("Unauthorized")) {
233
+ results.push(createPassResult(
234
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
235
+ `${apiUrl} (auth issue handled separately)`
236
+ ));
237
+ } else {
238
+ results.push(createFailResult(
239
+ CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,
240
+ message
241
+ ));
242
+ }
243
+ }
244
+ return results;
245
+ }
246
+ async function runProjectAccessChecks() {
247
+ const results = [];
248
+ const config = resolveConfig();
249
+ if (!config.apiKey) {
250
+ return results;
251
+ }
252
+ const client = createCliClient({
253
+ apiKey: config.apiKey,
254
+ apiUrl: config.apiUrl,
255
+ debug: config.debug
256
+ });
257
+ if (config.projectId) {
258
+ try {
259
+ await client.call("get_project", { projectId: config.projectId });
260
+ results.push(createPassResult(
261
+ PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,
262
+ config.projectId
263
+ ));
264
+ } catch (error) {
265
+ const message = error instanceof Error ? error.message : "Unknown error";
266
+ results.push(createFailResult(
267
+ PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,
268
+ `Cannot access: ${message}`,
269
+ FIX_SUGGESTIONS.PROJECT_NOT_ACCESSIBLE
270
+ ));
271
+ }
272
+ } else {
273
+ results.push(createWarnResult(
274
+ PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,
275
+ "No default project configured",
276
+ FIX_SUGGESTIONS.NO_PROJECT_CONFIGURED
277
+ ));
278
+ }
279
+ if (config.specificationId) {
280
+ try {
281
+ await client.call("get_specification", { specificationId: config.specificationId });
282
+ results.push(createPassResult(
283
+ PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,
284
+ config.specificationId
285
+ ));
286
+ } catch (error) {
287
+ const message = error instanceof Error ? error.message : "Unknown error";
288
+ results.push(createFailResult(
289
+ PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,
290
+ `Cannot access: ${message}`,
291
+ FIX_SUGGESTIONS.SPEC_NOT_ACCESSIBLE
292
+ ));
293
+ }
294
+ } else {
295
+ results.push(createWarnResult(
296
+ PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,
297
+ "No default specification configured"
298
+ ));
299
+ }
300
+ return results;
301
+ }
302
+ function displayReport(report) {
303
+ printBlank();
304
+ printHeader("SpecForge MCP Health Check");
305
+ printBlank();
306
+ for (const category of CHECK_CATEGORIES) {
307
+ const checks = report.checks[category.id];
308
+ if (checks.length === 0) continue;
309
+ console.log(colors.bold(category.name));
310
+ for (const check of checks) {
311
+ const icon = check.status === "pass" ? colors.success(getStatusIcon("pass")) : check.status === "warn" ? colors.warning(getStatusIcon("warn")) : colors.error(getStatusIcon("fail"));
312
+ console.log(` ${icon} ${check.name}: ${check.message}`);
313
+ if (check.fix && check.status !== "pass") {
314
+ console.log(colors.muted(` \u2192 ${check.fix}`));
315
+ }
316
+ }
317
+ printBlank();
318
+ }
319
+ const { passed, failed, warnings, total } = report.summary;
320
+ if (failed === 0 && warnings === 0) {
321
+ console.log(colors.success(`All ${total} checks passed!`));
322
+ } else if (failed === 0) {
323
+ console.log(
324
+ colors.success("All checks passed!") + colors.warning(` (${warnings} warning${warnings > 1 ? "s" : ""})`)
325
+ );
326
+ } else {
327
+ const failMsg = `${failed} check${failed > 1 ? "s" : ""} failed`;
328
+ const warnMsg = warnings > 0 ? `, ${warnings} warning${warnings > 1 ? "s" : ""}` : "";
329
+ console.log(colors.error(failMsg) + colors.warning(warnMsg));
330
+ }
331
+ printBlank();
332
+ }
333
+ async function doctorAction(options) {
334
+ const config = resolveConfig();
335
+ let configChecks = [];
336
+ let authChecks = [];
337
+ let connectionChecks = [];
338
+ let projectChecks = [];
339
+ if (options.json) {
340
+ configChecks = runConfigurationChecks();
341
+ authChecks = await runAuthenticationChecks(config.apiKey);
342
+ connectionChecks = await runConnectionChecks(config.apiKey);
343
+ projectChecks = await runProjectAccessChecks();
344
+ } else {
345
+ await forgeProgress("Running diagnostics", [
346
+ {
347
+ label: "config",
348
+ fn: async () => {
349
+ configChecks = runConfigurationChecks();
350
+ }
351
+ },
352
+ {
353
+ label: "auth",
354
+ fn: async () => {
355
+ authChecks = await runAuthenticationChecks(config.apiKey);
356
+ }
357
+ },
358
+ {
359
+ label: "connection",
360
+ fn: async () => {
361
+ connectionChecks = await runConnectionChecks(config.apiKey);
362
+ }
363
+ },
364
+ {
365
+ label: "project",
366
+ fn: async () => {
367
+ projectChecks = await runProjectAccessChecks();
368
+ }
369
+ }
370
+ ]);
371
+ }
372
+ const checks = {
373
+ configuration: configChecks,
374
+ authentication: authChecks,
375
+ connection: connectionChecks,
376
+ projectAccess: projectChecks
377
+ };
378
+ const report = {
379
+ checks,
380
+ summary: calculateSummary(checks),
381
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
382
+ };
383
+ if (options.json) {
384
+ console.log(JSON.stringify(report, null, 2));
385
+ } else {
386
+ displayReport(report);
387
+ }
388
+ if (hasFailures(report)) {
389
+ process.exit(1);
390
+ }
391
+ }
392
+ function registerDoctorCommand(program) {
393
+ program.command("doctor").description("Diagnose configuration and connection issues").option("--json", "Output as JSON for scripting").option("--fix", "Attempt to fix issues automatically (future)").addHelpText("after", `
394
+ Examples:
395
+ $ specforge doctor # Run health checks
396
+ $ specforge doctor --json # Output as JSON
397
+
398
+ Check Categories:
399
+ Configuration - Config files presence and validity
400
+ Authentication - API key format and authentication
401
+ Connection - API connectivity and response time
402
+ Project Access - Access to configured project/specification
403
+
404
+ Exit Codes:
405
+ 0 - All checks passed (warnings OK)
406
+ 1 - One or more checks failed
407
+ `).action(withErrorHandler(doctorAction));
408
+ }
409
+ export {
410
+ doctorAction,
411
+ registerDoctorCommand
412
+ };
413
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/doctor.ts"],"sourcesContent":["/**\n * Doctor Command\n *\n * Diagnoses configuration and connection issues for SpecForge MCP.\n */\n\nimport { Command } from 'commander';\nimport fs from 'node:fs';\nimport {\n resolveConfig,\n loadGlobalConfig,\n tryLoadProjectConfig,\n getConfigPaths,\n} from '../config/index.js';\nimport { withErrorHandler } from '../middleware/error-handler.js';\nimport { printBlank, printHeader } from '../ui/output.js';\nimport { colors } from '../ui/colors.js';\nimport { forgeProgress } from '../ui/spinner.js';\nimport { createCliClient } from '../../client/cli-client.js';\nimport { CHANNEL } from '../../channel.js';\nimport {\n DoctorOptions,\n DoctorReport,\n CheckResult,\n CheckCategory,\n createPassResult,\n createFailResult,\n createWarnResult,\n calculateSummary,\n hasFailures,\n getStatusIcon,\n CHECK_CATEGORIES,\n CONFIG_CHECK_NAMES,\n AUTH_CHECK_NAMES,\n CONNECTION_CHECK_NAMES,\n PROJECT_CHECK_NAMES,\n PERFORMANCE_THRESHOLDS,\n API_KEY_VALIDATION,\n FIX_SUGGESTIONS,\n} from './doctor.types.js';\n\n/**\n * Mask an API key for display (show only last N characters)\n */\nfunction maskApiKey(apiKey: string, visibleChars = 8): string {\n if (apiKey.length <= visibleChars) {\n return '***';\n }\n return `${API_KEY_VALIDATION.PREFIX}...${apiKey.slice(-visibleChars)}`;\n}\n\n/**\n * Run configuration checks\n */\nfunction runConfigurationChecks(): CheckResult[] {\n const results: CheckResult[] = [];\n const paths = getConfigPaths();\n const globalConfig = loadGlobalConfig();\n const projectConfig = tryLoadProjectConfig();\n\n // Channel + endpoint the binary is wired to (M9.6c).\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.CHANNEL,\n `${CHANNEL.name} · ${CHANNEL.packageName} · ${CHANNEL.endpoint.primary}`,\n { name: CHANNEL.name, packageName: CHANNEL.packageName, endpoint: CHANNEL.endpoint.primary },\n ));\n\n // Check .mcp.json\n if (fs.existsSync(paths.mcpConfig)) {\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.MCP_CONFIG_FOUND,\n paths.mcpConfig\n ));\n } else {\n results.push(createFailResult(\n CONFIG_CHECK_NAMES.MCP_CONFIG_FOUND,\n 'File not found',\n FIX_SUGGESTIONS.MISSING_MCP_CONFIG\n ));\n }\n\n // Check .specforge.json (optional)\n if (projectConfig) {\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.PROJECT_CONFIG_FOUND,\n paths.projectConfig\n ));\n } else {\n results.push(createWarnResult(\n CONFIG_CHECK_NAMES.PROJECT_CONFIG_FOUND,\n 'File not found (optional)',\n FIX_SUGGESTIONS.MISSING_PROJECT_CONFIG\n ));\n }\n\n // Global config directory (M9.6c — channel-aware path).\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.GLOBAL_CONFIG_DIR,\n paths.globalConfig\n ));\n\n // Active planning session for this spec (M9.6c) — read from local config; the\n // agent injects this id per-call. (The old `get_working_context` op is dead.)\n if (projectConfig?.planningSessionId) {\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.PLANNING_SESSION,\n projectConfig.planningSessionId\n ));\n } else {\n results.push(createWarnResult(\n CONFIG_CHECK_NAMES.PLANNING_SESSION,\n 'None (no planning session persisted for this spec)'\n ));\n }\n\n // Check API key configured\n const apiKeySource = process.env.SPECFORGE_API_KEY\n ? 'From environment variable'\n : globalConfig.apiKey\n ? 'From ~/.specforge/config.json'\n : undefined;\n\n if (apiKeySource) {\n results.push(createPassResult(\n CONFIG_CHECK_NAMES.API_KEY_CONFIGURED,\n apiKeySource\n ));\n } else {\n results.push(createFailResult(\n CONFIG_CHECK_NAMES.API_KEY_CONFIGURED,\n 'No API key found',\n FIX_SUGGESTIONS.MISSING_API_KEY\n ));\n }\n\n return results;\n}\n\n/**\n * Run authentication checks\n */\nasync function runAuthenticationChecks(apiKey: string | null | undefined): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n\n if (!apiKey) {\n results.push(createFailResult(\n AUTH_CHECK_NAMES.API_KEY_FORMAT,\n 'No API key to validate'\n ));\n return results;\n }\n\n // Check format\n const hasValidPrefix = apiKey.startsWith(API_KEY_VALIDATION.PREFIX);\n const hasValidLength = apiKey.length >= API_KEY_VALIDATION.MIN_LENGTH;\n\n if (hasValidPrefix && hasValidLength) {\n results.push(createPassResult(\n AUTH_CHECK_NAMES.API_KEY_FORMAT,\n maskApiKey(apiKey)\n ));\n } else {\n const issues: string[] = [];\n if (!hasValidPrefix) issues.push(`should start with ${API_KEY_VALIDATION.PREFIX}`);\n if (!hasValidLength) issues.push(`minimum ${API_KEY_VALIDATION.MIN_LENGTH} characters`);\n\n results.push(createFailResult(\n AUTH_CHECK_NAMES.API_KEY_FORMAT,\n `Invalid format (${issues.join(', ')})`,\n FIX_SUGGESTIONS.INVALID_API_KEY_FORMAT\n ));\n return results; // Don't test against backend if format is invalid\n }\n\n // Validate against backend\n const config = resolveConfig();\n const client = createCliClient({\n apiKey,\n apiUrl: config.apiUrl,\n debug: config.debug,\n });\n\n try {\n // First verify authentication works\n await client.call('list_projects', {});\n\n results.push(createPassResult(\n AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,\n 'Successfully authenticated'\n ));\n\n // Get user info\n try {\n const userResponse = await client.call<{ email?: string; name?: string }>(\n 'get_current_user',\n {}\n );\n const userInfo = userResponse.name\n ? `${userResponse.name} (${userResponse.email})`\n : userResponse.email || 'Unknown';\n results.push(createPassResult(\n AUTH_CHECK_NAMES.USER_INFO,\n userInfo\n ));\n } catch {\n results.push(createPassResult(\n AUTH_CHECK_NAMES.USER_INFO,\n 'Authenticated (email not available)'\n ));\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n if (message.includes('401') || message.includes('Unauthorized')) {\n results.push(createFailResult(\n AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,\n 'Invalid or expired API key',\n FIX_SUGGESTIONS.EXPIRED_API_KEY\n ));\n } else {\n results.push(createFailResult(\n AUTH_CHECK_NAMES.API_KEY_AUTHENTICATED,\n `Authentication failed: ${message}`\n ));\n }\n }\n\n return results;\n}\n\n/**\n * Run connection checks\n */\nasync function runConnectionChecks(apiKey: string | null | undefined): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n const config = resolveConfig();\n const apiUrl = config.apiUrl;\n\n // Skip connection check if no API key (auth checks will fail anyway)\n if (!apiKey) {\n results.push(createFailResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n 'No API key to test connection',\n FIX_SUGGESTIONS.MISSING_API_KEY\n ));\n return results;\n }\n\n const client = createCliClient({\n apiKey,\n apiUrl: config.apiUrl,\n debug: config.debug,\n });\n\n try {\n const start = Date.now();\n // Use an authenticated call to test connectivity\n await client.call('list_projects', {});\n const elapsed = Date.now() - start;\n\n results.push(createPassResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n apiUrl\n ));\n\n // Response time check\n if (elapsed < PERFORMANCE_THRESHOLDS.RESPONSE_TIME_WARNING) {\n results.push(createPassResult(\n CONNECTION_CHECK_NAMES.RESPONSE_TIME,\n `${elapsed}ms`,\n { elapsed }\n ));\n } else if (elapsed < PERFORMANCE_THRESHOLDS.RESPONSE_TIME_ERROR) {\n results.push(createWarnResult(\n CONNECTION_CHECK_NAMES.RESPONSE_TIME,\n `${elapsed}ms (slow)`,\n undefined,\n { elapsed }\n ));\n } else {\n results.push(createFailResult(\n CONNECTION_CHECK_NAMES.RESPONSE_TIME,\n `${elapsed}ms (very slow)`,\n FIX_SUGGESTIONS.CONNECTION_TIMEOUT,\n { elapsed }\n ));\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n if (message.includes('ENOTFOUND') || message.includes('ECONNREFUSED') || message.includes('getaddrinfo')) {\n results.push(createFailResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n 'Could not connect to API',\n FIX_SUGGESTIONS.CONNECTION_FAILED\n ));\n } else if (message.includes('timeout') || message.includes('TimeoutError')) {\n results.push(createFailResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n 'Connection timed out',\n FIX_SUGGESTIONS.CONNECTION_TIMEOUT\n ));\n } else if (message.includes('401') || message.includes('Unauthorized')) {\n // Auth issue, but connection works\n results.push(createPassResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n `${apiUrl} (auth issue handled separately)`\n ));\n } else {\n results.push(createFailResult(\n CONNECTION_CHECK_NAMES.API_ENDPOINT_REACHABLE,\n message\n ));\n }\n }\n\n return results;\n}\n\n/**\n * Run project access checks\n */\nasync function runProjectAccessChecks(): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n const config = resolveConfig();\n\n if (!config.apiKey) {\n // Skip if no API key (auth checks already failed)\n return results;\n }\n\n const client = createCliClient({\n apiKey: config.apiKey,\n apiUrl: config.apiUrl,\n debug: config.debug,\n });\n\n // Check project access\n if (config.projectId) {\n try {\n await client.call('get_project', { projectId: config.projectId });\n results.push(createPassResult(\n PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,\n config.projectId\n ));\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n results.push(createFailResult(\n PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,\n `Cannot access: ${message}`,\n FIX_SUGGESTIONS.PROJECT_NOT_ACCESSIBLE\n ));\n }\n } else {\n results.push(createWarnResult(\n PROJECT_CHECK_NAMES.PROJECT_ACCESSIBLE,\n 'No default project configured',\n FIX_SUGGESTIONS.NO_PROJECT_CONFIGURED\n ));\n }\n\n // Check specification access\n if (config.specificationId) {\n try {\n await client.call('get_specification', { specificationId: config.specificationId });\n results.push(createPassResult(\n PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,\n config.specificationId\n ));\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n results.push(createFailResult(\n PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,\n `Cannot access: ${message}`,\n FIX_SUGGESTIONS.SPEC_NOT_ACCESSIBLE\n ));\n }\n } else {\n results.push(createWarnResult(\n PROJECT_CHECK_NAMES.SPECIFICATION_ACCESSIBLE,\n 'No default specification configured'\n ));\n }\n\n // NOTE: the implementation-session probe (old `get_working_context`) was\n // removed in M8/M9 — that backend op no longer exists. The active planning\n // session is surfaced from local config in runConfigurationChecks (M9.6c).\n\n return results;\n}\n\n/**\n * Display the report in formatted console output\n */\nfunction displayReport(report: DoctorReport): void {\n printBlank();\n printHeader('SpecForge MCP Health Check');\n printBlank();\n\n for (const category of CHECK_CATEGORIES) {\n const checks = report.checks[category.id];\n if (checks.length === 0) continue;\n\n console.log(colors.bold(category.name));\n\n for (const check of checks) {\n const icon = check.status === 'pass'\n ? colors.success(getStatusIcon('pass'))\n : check.status === 'warn'\n ? colors.warning(getStatusIcon('warn'))\n : colors.error(getStatusIcon('fail'));\n\n console.log(` ${icon} ${check.name}: ${check.message}`);\n\n if (check.fix && check.status !== 'pass') {\n console.log(colors.muted(` → ${check.fix}`));\n }\n }\n\n printBlank();\n }\n\n // Summary\n const { passed, failed, warnings, total } = report.summary;\n\n if (failed === 0 && warnings === 0) {\n console.log(colors.success(`All ${total} checks passed!`));\n } else if (failed === 0) {\n console.log(\n colors.success('All checks passed!') +\n colors.warning(` (${warnings} warning${warnings > 1 ? 's' : ''})`)\n );\n } else {\n const failMsg = `${failed} check${failed > 1 ? 's' : ''} failed`;\n const warnMsg = warnings > 0\n ? `, ${warnings} warning${warnings > 1 ? 's' : ''}`\n : '';\n console.log(colors.error(failMsg) + colors.warning(warnMsg));\n }\n\n printBlank();\n}\n\n/**\n * Doctor command action handler\n */\nexport async function doctorAction(options: DoctorOptions): Promise<void> {\n const config = resolveConfig();\n\n let configChecks: CheckResult[] = [];\n let authChecks: CheckResult[] = [];\n let connectionChecks: CheckResult[] = [];\n let projectChecks: CheckResult[] = [];\n\n if (options.json) {\n configChecks = runConfigurationChecks();\n authChecks = await runAuthenticationChecks(config.apiKey);\n connectionChecks = await runConnectionChecks(config.apiKey);\n projectChecks = await runProjectAccessChecks();\n } else {\n await forgeProgress('Running diagnostics', [\n {\n label: 'config',\n fn: async () => { configChecks = runConfigurationChecks(); },\n },\n {\n label: 'auth',\n fn: async () => { authChecks = await runAuthenticationChecks(config.apiKey); },\n },\n {\n label: 'connection',\n fn: async () => { connectionChecks = await runConnectionChecks(config.apiKey); },\n },\n {\n label: 'project',\n fn: async () => { projectChecks = await runProjectAccessChecks(); },\n },\n ]);\n }\n\n // Compile report\n const checks: Record<CheckCategory, CheckResult[]> = {\n configuration: configChecks,\n authentication: authChecks,\n connection: connectionChecks,\n projectAccess: projectChecks,\n };\n\n const report: DoctorReport = {\n checks,\n summary: calculateSummary(checks),\n timestamp: new Date().toISOString(),\n };\n\n // Output\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n displayReport(report);\n }\n\n // Exit with error if any checks failed\n if (hasFailures(report)) {\n process.exit(1);\n }\n}\n\n/**\n * Register doctor command with Commander\n */\nexport function registerDoctorCommand(program: Command): void {\n program\n .command('doctor')\n .description('Diagnose configuration and connection issues')\n .option('--json', 'Output as JSON for scripting')\n .option('--fix', 'Attempt to fix issues automatically (future)')\n .addHelpText('after', `\nExamples:\n $ specforge doctor # Run health checks\n $ specforge doctor --json # Output as JSON\n\nCheck Categories:\n Configuration - Config files presence and validity\n Authentication - API key format and authentication\n Connection - API connectivity and response time\n Project Access - Access to configured project/specification\n\nExit Codes:\n 0 - All checks passed (warnings OK)\n 1 - One or more checks failed\n`)\n .action(withErrorHandler(doctorAction));\n}\n"],"mappings":"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","names":[]}