@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,124 @@
1
+ import ora from "ora";
2
+ import { resolveConfig } from "../config/index.js";
3
+ import { withErrorHandler, CliError, NetworkError } from "../middleware/error-handler.js";
4
+ import { printBlank } from "../ui/output.js";
5
+ import { colors } from "../ui/colors.js";
6
+ import { ApiClient } from "../../client/api-client.js";
7
+ import {
8
+ formatTicketNumber
9
+ } from "./status.types.js";
10
+ function renderStatus(report, next, specificationId) {
11
+ printBlank();
12
+ console.log(colors.bold("Context"));
13
+ console.log(colors.muted("\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
14
+ console.log(`Project: ${report.project?.name ?? colors.muted("(unknown)")}`);
15
+ const specEntry = specificationId ? report.specifications.find((s) => s.specification.id === specificationId) : report.specifications[0];
16
+ if (specEntry) {
17
+ const spec = specEntry.specification;
18
+ const specStatus = spec.status;
19
+ console.log(`Spec: ${spec.title}${specStatus ? colors.muted(` (${specStatus})`) : ""}`);
20
+ printBlank();
21
+ console.log(colors.bold("Progress"));
22
+ console.log(colors.muted("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
23
+ const pct = specEntry.totalTickets > 0 ? Math.round(specEntry.completedTickets / specEntry.totalTickets * 100) : 0;
24
+ console.log(`Tickets: ${specEntry.completedTickets}/${specEntry.totalTickets} (${pct}%)`);
25
+ console.log(`Epics: ${specEntry.completedEpics}/${specEntry.totalEpics}`);
26
+ } else {
27
+ console.log(colors.muted("Spec: (none active \u2014 run `specforge switch <id>`)"));
28
+ }
29
+ if (report.recentActivity && report.recentActivity.length > 0) {
30
+ printBlank();
31
+ console.log(colors.bold("Recent activity"));
32
+ console.log(colors.muted("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
33
+ for (const a of report.recentActivity.slice(0, 3)) {
34
+ console.log(` ${a.action} \u2014 ${a.ticketTitle}`);
35
+ }
36
+ }
37
+ if (next && next.items.length > 0) {
38
+ printBlank();
39
+ console.log(colors.bold("Next actionable"));
40
+ console.log(colors.muted("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
41
+ for (const t of next.items.slice(0, 5)) {
42
+ const priority = t.priority ? colors.muted(` [${t.priority}]`) : "";
43
+ console.log(` ${formatTicketNumber(t.ticketNumber)} ${t.title}${priority}`);
44
+ }
45
+ }
46
+ printBlank();
47
+ }
48
+ async function statusAction(options) {
49
+ const config = resolveConfig();
50
+ if (!config.apiKey) {
51
+ throw new CliError(
52
+ "Not authenticated",
53
+ 1,
54
+ "Run `specforge login` to authenticate first"
55
+ );
56
+ }
57
+ const scope = config.specificationId ? "specification" : "project";
58
+ const scopeId = config.specificationId ?? config.projectId;
59
+ if (!scopeId) {
60
+ throw new CliError(
61
+ "No active project or specification",
62
+ 1,
63
+ "Run `specforge init` or `specforge switch <id>` first"
64
+ );
65
+ }
66
+ const spinner = ora({ text: "Fetching status...", color: "cyan" }).start();
67
+ try {
68
+ const client = new ApiClient({
69
+ apiKey: config.apiKey,
70
+ apiUrl: config.apiUrl,
71
+ debug: config.debug
72
+ });
73
+ const report = await client.call("get_report", {
74
+ type: "implementation",
75
+ scope,
76
+ scopeId
77
+ });
78
+ let next;
79
+ if (config.specificationId) {
80
+ try {
81
+ next = await client.call("get_next_actionable_tickets", {
82
+ specificationId: config.specificationId
83
+ });
84
+ } catch {
85
+ }
86
+ }
87
+ spinner.stop();
88
+ if (options.json) {
89
+ console.log(JSON.stringify({ report, nextActionable: next ?? null }, null, 2));
90
+ } else {
91
+ renderStatus(report, next, config.specificationId);
92
+ }
93
+ } catch (error) {
94
+ spinner.fail("Failed to fetch status");
95
+ const message = error instanceof Error ? error.message : "Unknown error";
96
+ if (message.includes("401") || message.includes("Unauthorized")) {
97
+ throw new CliError(
98
+ "Authentication failed",
99
+ 1,
100
+ "Your API key may be invalid. Run `specforge login` to re-authenticate"
101
+ );
102
+ }
103
+ throw new NetworkError(`Failed to fetch status: ${message}`);
104
+ }
105
+ }
106
+ function registerStatusCommand(program) {
107
+ program.command("status").description("Show active project/spec, implementation progress, and next actionable tickets").option("--json", "Output as JSON").addHelpText("after", `
108
+ Examples:
109
+ $ specforge status # Active project/spec + progress + next tickets
110
+ $ specforge status --json # Machine-readable output
111
+
112
+ Shows:
113
+ - Context: active project and specification (from .specforge/config.json)
114
+ - Progress: epic/ticket completion for the active spec
115
+ - Next actionable: ready-to-work tickets
116
+
117
+ Use 'specforge switch <id>' to change the active project or specification.
118
+ `).action(withErrorHandler(statusAction));
119
+ }
120
+ export {
121
+ registerStatusCommand,
122
+ statusAction
123
+ };
124
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/status.ts"],"sourcesContent":["/**\n * Status Command\n *\n * Shows what this terminal is pointed at (project / spec from\n * `.specforge/config.json`) plus a live implementation report for the active\n * spec and the next actionable tickets. Uses only canonical tools —\n * `get_report` (type='implementation') + `get_next_actionable_tickets`.\n */\n\nimport { Command } from 'commander';\nimport ora from 'ora';\nimport { resolveConfig } from '../config/index.js';\nimport { withErrorHandler, CliError, NetworkError } from '../middleware/error-handler.js';\nimport { printBlank } from '../ui/output.js';\nimport { colors } from '../ui/colors.js';\nimport { ApiClient } from '../../client/api-client.js';\nimport type { ImplementationSummary } from '../../types/index.js';\nimport {\n StatusOptions,\n NextActionableResponse,\n formatTicketNumber,\n} from './status.types.js';\n\n/**\n * Render the human-facing status view.\n */\nfunction renderStatus(\n report: ImplementationSummary,\n next: NextActionableResponse | undefined,\n specificationId: string | null\n): void {\n printBlank();\n console.log(colors.bold('Context'));\n console.log(colors.muted('───────'));\n console.log(`Project: ${report.project?.name ?? colors.muted('(unknown)')}`);\n\n const specEntry = specificationId\n ? report.specifications.find((s) => s.specification.id === specificationId)\n : report.specifications[0];\n\n if (specEntry) {\n const spec = specEntry.specification;\n const specStatus = (spec as { status?: string }).status;\n console.log(`Spec: ${spec.title}${specStatus ? colors.muted(` (${specStatus})`) : ''}`);\n\n printBlank();\n console.log(colors.bold('Progress'));\n console.log(colors.muted('────────'));\n const pct = specEntry.totalTickets > 0\n ? Math.round((specEntry.completedTickets / specEntry.totalTickets) * 100)\n : 0;\n console.log(`Tickets: ${specEntry.completedTickets}/${specEntry.totalTickets} (${pct}%)`);\n console.log(`Epics: ${specEntry.completedEpics}/${specEntry.totalEpics}`);\n } else {\n console.log(colors.muted('Spec: (none active — run `specforge switch <id>`)'));\n }\n\n if (report.recentActivity && report.recentActivity.length > 0) {\n printBlank();\n console.log(colors.bold('Recent activity'));\n console.log(colors.muted('───────────────'));\n for (const a of report.recentActivity.slice(0, 3)) {\n console.log(` ${a.action} — ${a.ticketTitle}`);\n }\n }\n\n if (next && next.items.length > 0) {\n printBlank();\n console.log(colors.bold('Next actionable'));\n console.log(colors.muted('───────────────'));\n for (const t of next.items.slice(0, 5)) {\n const priority = t.priority ? colors.muted(` [${t.priority}]`) : '';\n console.log(` ${formatTicketNumber(t.ticketNumber)} ${t.title}${priority}`);\n }\n }\n\n printBlank();\n}\n\n/**\n * Status command action handler\n */\nexport async function statusAction(options: StatusOptions): Promise<void> {\n const config = resolveConfig();\n\n if (!config.apiKey) {\n throw new CliError(\n 'Not authenticated',\n 1,\n 'Run `specforge login` to authenticate first'\n );\n }\n\n const scope = config.specificationId ? 'specification' : 'project';\n const scopeId = config.specificationId ?? config.projectId;\n if (!scopeId) {\n throw new CliError(\n 'No active project or specification',\n 1,\n 'Run `specforge init` or `specforge switch <id>` first'\n );\n }\n\n const spinner = ora({ text: 'Fetching status...', color: 'cyan' }).start();\n\n try {\n const client = new ApiClient({\n apiKey: config.apiKey,\n apiUrl: config.apiUrl,\n debug: config.debug,\n });\n\n const report = await client.call<ImplementationSummary>('get_report', {\n type: 'implementation',\n scope,\n scopeId,\n });\n\n let next: NextActionableResponse | undefined;\n if (config.specificationId) {\n try {\n next = await client.call<NextActionableResponse>('get_next_actionable_tickets', {\n specificationId: config.specificationId,\n });\n } catch {\n // Next-actionable is a best-effort enrichment — ignore failures.\n }\n }\n\n spinner.stop();\n\n if (options.json) {\n console.log(JSON.stringify({ report, nextActionable: next ?? null }, null, 2));\n } else {\n renderStatus(report, next, config.specificationId);\n }\n } catch (error) {\n spinner.fail('Failed to fetch status');\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n if (message.includes('401') || message.includes('Unauthorized')) {\n throw new CliError(\n 'Authentication failed',\n 1,\n 'Your API key may be invalid. Run `specforge login` to re-authenticate'\n );\n }\n\n throw new NetworkError(`Failed to fetch status: ${message}`);\n }\n}\n\n/**\n * Register status command with Commander\n */\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status')\n .description('Show active project/spec, implementation progress, and next actionable tickets')\n .option('--json', 'Output as JSON')\n .addHelpText('after', `\nExamples:\n $ specforge status # Active project/spec + progress + next tickets\n $ specforge status --json # Machine-readable output\n\nShows:\n - Context: active project and specification (from .specforge/config.json)\n - Progress: epic/ticket completion for the active spec\n - Next actionable: ready-to-work tickets\n\nUse 'specforge switch <id>' to change the active project or specification.\n`)\n .action(withErrorHandler(statusAction));\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Status Command Types
3
+ *
4
+ * Post-M9: status shows the active project/spec (from config) plus a live
5
+ * implementation report and the next actionable tickets. The pre-M9
6
+ * working-context / session / dashboard / teams model was removed with its
7
+ * backing ops (M9.4).
8
+ */
9
+ /**
10
+ * Status command options from Commander
11
+ */
12
+ export interface StatusOptions {
13
+ /** Output as JSON */
14
+ json?: boolean;
15
+ }
16
+ /**
17
+ * A single next-actionable ticket (subset of get_next_actionable_tickets items).
18
+ */
19
+ export interface NextActionableItem {
20
+ id: string;
21
+ ticketNumber: number;
22
+ title: string;
23
+ priority?: string;
24
+ epicTitle?: string;
25
+ }
26
+ /**
27
+ * Response shape of get_next_actionable_tickets.
28
+ */
29
+ export interface NextActionableResponse {
30
+ items: NextActionableItem[];
31
+ total: number;
32
+ }
33
+ /**
34
+ * Format a ticket number with padding (e.g. 7 → "TKT-007").
35
+ */
36
+ export declare function formatTicketNumber(ticketNumber: number, prefix?: string, padding?: number): string;
37
+ //# sourceMappingURL=status.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.types.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,SAAQ,EACd,OAAO,SAAI,GACV,MAAM,CAER"}
@@ -0,0 +1,7 @@
1
+ function formatTicketNumber(ticketNumber, prefix = "TKT", padding = 3) {
2
+ return `${prefix}-${ticketNumber.toString().padStart(padding, "0")}`;
3
+ }
4
+ export {
5
+ formatTicketNumber
6
+ };
7
+ //# sourceMappingURL=status.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/status.types.ts"],"sourcesContent":["/**\n * Status Command Types\n *\n * Post-M9: status shows the active project/spec (from config) plus a live\n * implementation report and the next actionable tickets. The pre-M9\n * working-context / session / dashboard / teams model was removed with its\n * backing ops (M9.4).\n */\n\n/**\n * Status command options from Commander\n */\nexport interface StatusOptions {\n /** Output as JSON */\n json?: boolean;\n}\n\n/**\n * A single next-actionable ticket (subset of get_next_actionable_tickets items).\n */\nexport interface NextActionableItem {\n id: string;\n ticketNumber: number;\n title: string;\n priority?: string;\n epicTitle?: string;\n}\n\n/**\n * Response shape of get_next_actionable_tickets.\n */\nexport interface NextActionableResponse {\n items: NextActionableItem[];\n total: number;\n}\n\n/**\n * Format a ticket number with padding (e.g. 7 → \"TKT-007\").\n */\nexport function formatTicketNumber(\n ticketNumber: number,\n prefix = 'TKT',\n padding = 3\n): string {\n return `${prefix}-${ticketNumber.toString().padStart(padding, '0')}`;\n}\n"],"mappings":"AAuCO,SAAS,mBACd,cACA,SAAS,OACT,UAAU,GACF;AACR,SAAO,GAAG,MAAM,IAAI,aAAa,SAAS,EAAE,SAAS,SAAS,GAAG,CAAC;AACpE;","names":[]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Switch Command
3
+ *
4
+ * Changes working context to a different project or specification.
5
+ * Auto-detects whether the ID is a project or specification.
6
+ */
7
+ import { Command } from 'commander';
8
+ /**
9
+ * Switch command action handler
10
+ *
11
+ * @param id Project or Specification ID to switch to
12
+ */
13
+ export declare function switchAction(id: string): Promise<void>;
14
+ /**
15
+ * Register switch command with Commander
16
+ */
17
+ export declare function registerSwitchCommand(program: Command): void;
18
+ //# sourceMappingURL=switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/switch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyEpC;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiG5D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqB5D"}
@@ -0,0 +1,134 @@
1
+ import ora from "ora";
2
+ import { resolveConfig, tryLoadProjectConfig, saveProjectConfig } from "../config/index.js";
3
+ import { withErrorHandler, CliError, NetworkError, ValidationError } from "../middleware/error-handler.js";
4
+ import { printBlank } from "../ui/output.js";
5
+ import { colors } from "../ui/colors.js";
6
+ import { createCliClient } from "../../client/cli-client.js";
7
+ import {
8
+ isProjectResult,
9
+ getDisplayName
10
+ } from "./switch.types.js";
11
+ async function detectIdType(client, id) {
12
+ try {
13
+ const project = await client.call("get_project", {
14
+ projectId: id
15
+ });
16
+ return { type: "project", data: project };
17
+ } catch {
18
+ }
19
+ try {
20
+ const specification = await client.call("get_specification", {
21
+ specificationId: id
22
+ });
23
+ return { type: "specification", data: specification };
24
+ } catch {
25
+ }
26
+ return null;
27
+ }
28
+ function updateLocalConfig(projectId, specificationId) {
29
+ const projectConfig = tryLoadProjectConfig() || {};
30
+ projectConfig.projectId = projectId;
31
+ if (specificationId) {
32
+ projectConfig.specificationId = specificationId;
33
+ } else {
34
+ delete projectConfig.specificationId;
35
+ }
36
+ saveProjectConfig(projectConfig);
37
+ }
38
+ async function switchAction(id) {
39
+ if (!id || id.trim() === "") {
40
+ throw new ValidationError(
41
+ "ID is required",
42
+ "Usage: specforge switch <project-or-spec-id>"
43
+ );
44
+ }
45
+ const config = resolveConfig();
46
+ if (!config.apiKey) {
47
+ throw new CliError(
48
+ "Not authenticated",
49
+ 1,
50
+ "Run `specforge login` to authenticate first"
51
+ );
52
+ }
53
+ const spinner = ora({
54
+ text: "Detecting resource type...",
55
+ color: "cyan"
56
+ }).start();
57
+ try {
58
+ const client = createCliClient({
59
+ apiKey: config.apiKey,
60
+ apiUrl: config.apiUrl,
61
+ debug: config.debug
62
+ });
63
+ spinner.text = "Looking up ID...";
64
+ const detected = await detectIdType(client, id);
65
+ if (!detected) {
66
+ spinner.fail("Resource not found");
67
+ throw new CliError(
68
+ `"${id}" is not a valid project or specification ID`,
69
+ 1,
70
+ "Make sure you have access to this resource. Use `specforge projects` or `specforge specs` to list available resources."
71
+ );
72
+ }
73
+ const { type, data } = detected;
74
+ const displayName = getDisplayName(detected);
75
+ spinner.text = `Switching to ${type}...`;
76
+ if (isProjectResult(detected)) {
77
+ const projectData = data;
78
+ updateLocalConfig(projectData.id);
79
+ spinner.succeed(`Switched to project: ${colors.primary(displayName)}`);
80
+ } else {
81
+ const specData = data;
82
+ updateLocalConfig(specData.projectId, specData.id);
83
+ spinner.succeed(`Switched to specification: ${colors.primary(displayName)}`);
84
+ }
85
+ printBlank();
86
+ console.log(colors.muted("Run `specforge status` to see the current context."));
87
+ printBlank();
88
+ } catch (error) {
89
+ if (error instanceof CliError || error instanceof ValidationError) {
90
+ spinner.stop();
91
+ throw error;
92
+ }
93
+ spinner.fail("Failed to switch context");
94
+ const message = error instanceof Error ? error.message : "Unknown error";
95
+ if (message.includes("401") || message.includes("Unauthorized")) {
96
+ throw new CliError(
97
+ "Authentication failed",
98
+ 1,
99
+ "Your API key may be invalid. Run `specforge login` to re-authenticate"
100
+ );
101
+ }
102
+ if (message.includes("403") || message.includes("Forbidden")) {
103
+ throw new CliError(
104
+ `Access denied to "${id}"`,
105
+ 1,
106
+ "You may not have permission to access this resource"
107
+ );
108
+ }
109
+ throw new NetworkError(`Failed to switch context: ${message}`);
110
+ }
111
+ }
112
+ function registerSwitchCommand(program) {
113
+ program.command("switch <id>").description("Switch working context to a project or specification").addHelpText("after", `
114
+ Arguments:
115
+ id Project ID (proj_xxx) or Specification ID (spec_xxx)
116
+
117
+ Examples:
118
+ $ specforge switch proj_abc123 # Switch to a project
119
+ $ specforge switch spec_def456 # Switch to a specification
120
+
121
+ The command auto-detects whether the ID is a project or specification.
122
+ When switching to a project, the specification context is cleared.
123
+ When switching to a specification, the project is set automatically.
124
+
125
+ Use 'specforge status' to see the current context.
126
+ Use 'specforge projects' to list available projects.
127
+ Use 'specforge specs' to list specifications in a project.
128
+ `).action(withErrorHandler(switchAction));
129
+ }
130
+ export {
131
+ registerSwitchCommand,
132
+ switchAction
133
+ };
134
+ //# sourceMappingURL=switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/switch.ts"],"sourcesContent":["/**\n * Switch Command\n *\n * Changes working context to a different project or specification.\n * Auto-detects whether the ID is a project or specification.\n */\n\nimport { Command } from 'commander';\nimport ora from 'ora';\nimport { resolveConfig, tryLoadProjectConfig, saveProjectConfig } from '../config/index.js';\nimport { withErrorHandler, CliError, NetworkError, ValidationError } from '../middleware/error-handler.js';\nimport { printBlank } from '../ui/output.js';\nimport { colors } from '../ui/colors.js';\nimport { ApiClient } from '../../client/api-client.js';\nimport { createCliClient } from '../../client/cli-client.js';\nimport {\n DetectionResult,\n ProjectData,\n SpecificationData,\n isProjectResult,\n getDisplayName,\n} from './switch.types.js';\n\n/**\n * Detect if an ID refers to a project or specification\n *\n * Tries to fetch the ID as a project first, then as a specification.\n *\n * @param client API client instance\n * @param id ID to detect\n * @returns Detection result or null if not found\n */\nasync function detectIdType(\n client: ApiClient,\n id: string\n): Promise<DetectionResult | null> {\n // Try as project first\n try {\n const project = await client.call<ProjectData>('get_project', {\n projectId: id,\n });\n return { type: 'project', data: project };\n } catch {\n // Not a project, continue to try specification\n }\n\n // Try as specification\n try {\n const specification = await client.call<SpecificationData>('get_specification', {\n specificationId: id,\n });\n return { type: 'specification', data: specification };\n } catch {\n // Not a specification either\n }\n\n return null;\n}\n\n/**\n * Update local project configuration\n *\n * @param projectId Project ID to set\n * @param specificationId Specification ID to set (undefined to clear)\n */\nfunction updateLocalConfig(projectId: string, specificationId?: string): void {\n const projectConfig = tryLoadProjectConfig() || {};\n\n projectConfig.projectId = projectId;\n\n if (specificationId) {\n projectConfig.specificationId = specificationId;\n } else {\n // Clear specification when switching to a project\n delete projectConfig.specificationId;\n }\n\n saveProjectConfig(projectConfig);\n}\n\n/**\n * Switch command action handler\n *\n * @param id Project or Specification ID to switch to\n */\nexport async function switchAction(id: string): Promise<void> {\n // Validate ID is provided\n if (!id || id.trim() === '') {\n throw new ValidationError(\n 'ID is required',\n 'Usage: specforge switch <project-or-spec-id>'\n );\n }\n\n const config = resolveConfig();\n\n if (!config.apiKey) {\n throw new CliError(\n 'Not authenticated',\n 1,\n 'Run `specforge login` to authenticate first'\n );\n }\n\n const spinner = ora({\n text: 'Detecting resource type...',\n color: 'cyan',\n }).start();\n\n try {\n const client = createCliClient({\n apiKey: config.apiKey,\n apiUrl: config.apiUrl,\n debug: config.debug,\n });\n\n // Detect what type of ID this is\n spinner.text = 'Looking up ID...';\n const detected = await detectIdType(client, id);\n\n if (!detected) {\n spinner.fail('Resource not found');\n throw new CliError(\n `\"${id}\" is not a valid project or specification ID`,\n 1,\n 'Make sure you have access to this resource. Use `specforge projects` or `specforge specs` to list available resources.'\n );\n }\n\n const { type, data } = detected;\n const displayName = getDisplayName(detected);\n\n // Update working context based on type\n spinner.text = `Switching to ${type}...`;\n\n // The local `.specforge/config.json` IS the working context now (M9 — the\n // backend `set_working_context` op was removed); persist the selection.\n if (isProjectResult(detected)) {\n const projectData = data as ProjectData;\n updateLocalConfig(projectData.id);\n spinner.succeed(`Switched to project: ${colors.primary(displayName)}`);\n } else {\n const specData = data as SpecificationData;\n updateLocalConfig(specData.projectId, specData.id);\n spinner.succeed(`Switched to specification: ${colors.primary(displayName)}`);\n }\n\n printBlank();\n\n // Show helpful next steps\n console.log(colors.muted('Run `specforge status` to see the current context.'));\n printBlank();\n\n } catch (error) {\n // Re-throw CLI errors as-is\n if (error instanceof CliError || error instanceof ValidationError) {\n spinner.stop();\n throw error;\n }\n\n spinner.fail('Failed to switch context');\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n if (message.includes('401') || message.includes('Unauthorized')) {\n throw new CliError(\n 'Authentication failed',\n 1,\n 'Your API key may be invalid. Run `specforge login` to re-authenticate'\n );\n }\n\n if (message.includes('403') || message.includes('Forbidden')) {\n throw new CliError(\n `Access denied to \"${id}\"`,\n 1,\n 'You may not have permission to access this resource'\n );\n }\n\n throw new NetworkError(`Failed to switch context: ${message}`);\n }\n}\n\n/**\n * Register switch command with Commander\n */\nexport function registerSwitchCommand(program: Command): void {\n program\n .command('switch <id>')\n .description('Switch working context to a project or specification')\n .addHelpText('after', `\nArguments:\n id Project ID (proj_xxx) or Specification ID (spec_xxx)\n\nExamples:\n $ specforge switch proj_abc123 # Switch to a project\n $ specforge switch spec_def456 # Switch to a specification\n\nThe command auto-detects whether the ID is a project or specification.\nWhen switching to a project, the specification context is cleared.\nWhen switching to a specification, the project is set automatically.\n\nUse 'specforge status' to see the current context.\nUse 'specforge projects' to list available projects.\nUse 'specforge specs' to list specifications in a project.\n`)\n .action(withErrorHandler(switchAction));\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Switch Command Types
3
+ *
4
+ * Type definitions for the switch command that changes
5
+ * working context between projects and specifications.
6
+ */
7
+ /**
8
+ * Types of resources that can be switched to
9
+ */
10
+ export type SwitchTargetType = 'project' | 'specification';
11
+ /**
12
+ * Result of detecting what type an ID refers to
13
+ */
14
+ export interface DetectionResult {
15
+ /** The type of resource detected */
16
+ type: SwitchTargetType;
17
+ /** The resource data from the API */
18
+ data: ProjectData | SpecificationData;
19
+ }
20
+ /**
21
+ * Project data from get_project API
22
+ */
23
+ export interface ProjectData {
24
+ /** Project ID */
25
+ id: string;
26
+ /** Project name */
27
+ name: string;
28
+ /** Project description (optional) */
29
+ description?: string;
30
+ }
31
+ /**
32
+ * Specification data from get_specification API
33
+ */
34
+ export interface SpecificationData {
35
+ /** Specification ID */
36
+ id: string;
37
+ /** Specification title */
38
+ title: string;
39
+ /** Parent project ID */
40
+ projectId: string;
41
+ /** Specification description (optional) */
42
+ description?: string;
43
+ /** Specification status (optional) */
44
+ status?: string;
45
+ }
46
+ /**
47
+ * API request for set_working_context
48
+ */
49
+ export interface SetWorkingContextRequest extends Record<string, unknown> {
50
+ /** Project ID to set */
51
+ projectId: string;
52
+ /** Specification ID to set (null to clear) */
53
+ specificationId: string | null;
54
+ /** Epic ID to set (null to clear) */
55
+ epicId: string | null;
56
+ /** Ticket ID to set (null to clear) */
57
+ ticketId: string | null;
58
+ }
59
+ /**
60
+ * API response for set_working_context
61
+ */
62
+ export interface SetWorkingContextResponse {
63
+ /** Success indicator */
64
+ success?: boolean;
65
+ /** Updated context */
66
+ context?: {
67
+ projectId: string;
68
+ specificationId: string | null;
69
+ epicId: string | null;
70
+ ticketId: string | null;
71
+ };
72
+ }
73
+ /**
74
+ * Switch command result for display
75
+ */
76
+ export interface SwitchResult {
77
+ /** Whether switch was successful */
78
+ success: boolean;
79
+ /** Type of resource switched to */
80
+ type: SwitchTargetType;
81
+ /** Display name of the resource */
82
+ displayName: string;
83
+ /** Project ID (always set) */
84
+ projectId: string;
85
+ /** Specification ID (if switching to spec) */
86
+ specificationId?: string;
87
+ }
88
+ /**
89
+ * Error codes for switch command
90
+ */
91
+ export declare enum SwitchErrorCode {
92
+ /** ID not provided */
93
+ MISSING_ID = "MISSING_ID",
94
+ /** ID not found as project or specification */
95
+ NOT_FOUND = "NOT_FOUND",
96
+ /** User does not have access to resource */
97
+ ACCESS_DENIED = "ACCESS_DENIED",
98
+ /** Failed to update working context */
99
+ UPDATE_FAILED = "UPDATE_FAILED",
100
+ /** Failed to save local config */
101
+ CONFIG_SAVE_FAILED = "CONFIG_SAVE_FAILED"
102
+ }
103
+ /**
104
+ * Check if detection result is a project
105
+ */
106
+ export declare function isProjectResult(result: DetectionResult): result is DetectionResult & {
107
+ data: ProjectData;
108
+ };
109
+ /**
110
+ * Check if detection result is a specification
111
+ */
112
+ export declare function isSpecificationResult(result: DetectionResult): result is DetectionResult & {
113
+ data: SpecificationData;
114
+ };
115
+ /**
116
+ * Get display name from detection result
117
+ */
118
+ export declare function getDisplayName(result: DetectionResult): string;
119
+ /**
120
+ * Create switch result from detection result
121
+ */
122
+ export declare function createSwitchResult(result: DetectionResult): SwitchResult;
123
+ //# sourceMappingURL=switch.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.types.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/switch.types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,eAAe,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,qCAAqC;IACrC,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,iBAAiB;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qCAAqC;IACrC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,wBAAwB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sBAAsB;IACtB,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,sBAAsB;IACtB,UAAU,eAAe;IACzB,+CAA+C;IAC/C,SAAS,cAAc;IACvB,4CAA4C;IAC5C,aAAa,kBAAkB;IAC/B,uCAAuC;IACvC,aAAa,kBAAkB;IAC/B,kCAAkC;IAClC,kBAAkB,uBAAuB;CAC1C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,IAAI,eAAe,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAE1G;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,IAAI,eAAe,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAEtH;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAK9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,YAAY,CAkBxE"}
@@ -0,0 +1,46 @@
1
+ var SwitchErrorCode = /* @__PURE__ */ ((SwitchErrorCode2) => {
2
+ SwitchErrorCode2["MISSING_ID"] = "MISSING_ID";
3
+ SwitchErrorCode2["NOT_FOUND"] = "NOT_FOUND";
4
+ SwitchErrorCode2["ACCESS_DENIED"] = "ACCESS_DENIED";
5
+ SwitchErrorCode2["UPDATE_FAILED"] = "UPDATE_FAILED";
6
+ SwitchErrorCode2["CONFIG_SAVE_FAILED"] = "CONFIG_SAVE_FAILED";
7
+ return SwitchErrorCode2;
8
+ })(SwitchErrorCode || {});
9
+ function isProjectResult(result) {
10
+ return result.type === "project";
11
+ }
12
+ function isSpecificationResult(result) {
13
+ return result.type === "specification";
14
+ }
15
+ function getDisplayName(result) {
16
+ if (isProjectResult(result)) {
17
+ return result.data.name;
18
+ }
19
+ return result.data.title;
20
+ }
21
+ function createSwitchResult(result) {
22
+ if (isProjectResult(result)) {
23
+ return {
24
+ success: true,
25
+ type: "project",
26
+ displayName: result.data.name,
27
+ projectId: result.data.id
28
+ };
29
+ }
30
+ const specData = result.data;
31
+ return {
32
+ success: true,
33
+ type: "specification",
34
+ displayName: specData.title,
35
+ projectId: specData.projectId,
36
+ specificationId: specData.id
37
+ };
38
+ }
39
+ export {
40
+ SwitchErrorCode,
41
+ createSwitchResult,
42
+ getDisplayName,
43
+ isProjectResult,
44
+ isSpecificationResult
45
+ };
46
+ //# sourceMappingURL=switch.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/switch.types.ts"],"sourcesContent":["/**\n * Switch Command Types\n *\n * Type definitions for the switch command that changes\n * working context between projects and specifications.\n */\n\n/**\n * Types of resources that can be switched to\n */\nexport type SwitchTargetType = 'project' | 'specification';\n\n/**\n * Result of detecting what type an ID refers to\n */\nexport interface DetectionResult {\n /** The type of resource detected */\n type: SwitchTargetType;\n /** The resource data from the API */\n data: ProjectData | SpecificationData;\n}\n\n/**\n * Project data from get_project API\n */\nexport interface ProjectData {\n /** Project ID */\n id: string;\n /** Project name */\n name: string;\n /** Project description (optional) */\n description?: string;\n}\n\n/**\n * Specification data from get_specification API\n */\nexport interface SpecificationData {\n /** Specification ID */\n id: string;\n /** Specification title */\n title: string;\n /** Parent project ID */\n projectId: string;\n /** Specification description (optional) */\n description?: string;\n /** Specification status (optional) */\n status?: string;\n}\n\n/**\n * API request for set_working_context\n */\nexport interface SetWorkingContextRequest extends Record<string, unknown> {\n /** Project ID to set */\n projectId: string;\n /** Specification ID to set (null to clear) */\n specificationId: string | null;\n /** Epic ID to set (null to clear) */\n epicId: string | null;\n /** Ticket ID to set (null to clear) */\n ticketId: string | null;\n}\n\n/**\n * API response for set_working_context\n */\nexport interface SetWorkingContextResponse {\n /** Success indicator */\n success?: boolean;\n /** Updated context */\n context?: {\n projectId: string;\n specificationId: string | null;\n epicId: string | null;\n ticketId: string | null;\n };\n}\n\n/**\n * Switch command result for display\n */\nexport interface SwitchResult {\n /** Whether switch was successful */\n success: boolean;\n /** Type of resource switched to */\n type: SwitchTargetType;\n /** Display name of the resource */\n displayName: string;\n /** Project ID (always set) */\n projectId: string;\n /** Specification ID (if switching to spec) */\n specificationId?: string;\n}\n\n/**\n * Error codes for switch command\n */\nexport enum SwitchErrorCode {\n /** ID not provided */\n MISSING_ID = 'MISSING_ID',\n /** ID not found as project or specification */\n NOT_FOUND = 'NOT_FOUND',\n /** User does not have access to resource */\n ACCESS_DENIED = 'ACCESS_DENIED',\n /** Failed to update working context */\n UPDATE_FAILED = 'UPDATE_FAILED',\n /** Failed to save local config */\n CONFIG_SAVE_FAILED = 'CONFIG_SAVE_FAILED',\n}\n\n/**\n * Check if detection result is a project\n */\nexport function isProjectResult(result: DetectionResult): result is DetectionResult & { data: ProjectData } {\n return result.type === 'project';\n}\n\n/**\n * Check if detection result is a specification\n */\nexport function isSpecificationResult(result: DetectionResult): result is DetectionResult & { data: SpecificationData } {\n return result.type === 'specification';\n}\n\n/**\n * Get display name from detection result\n */\nexport function getDisplayName(result: DetectionResult): string {\n if (isProjectResult(result)) {\n return result.data.name;\n }\n return (result.data as SpecificationData).title;\n}\n\n/**\n * Create switch result from detection result\n */\nexport function createSwitchResult(result: DetectionResult): SwitchResult {\n if (isProjectResult(result)) {\n return {\n success: true,\n type: 'project',\n displayName: result.data.name,\n projectId: result.data.id,\n };\n }\n\n const specData = result.data as SpecificationData;\n return {\n success: true,\n type: 'specification',\n displayName: specData.title,\n projectId: specData.projectId,\n specificationId: specData.id,\n };\n}\n"],"mappings":"AAkGO,IAAK,kBAAL,kBAAKA,qBAAL;AAEL,EAAAA,iBAAA,gBAAa;AAEb,EAAAA,iBAAA,eAAY;AAEZ,EAAAA,iBAAA,mBAAgB;AAEhB,EAAAA,iBAAA,mBAAgB;AAEhB,EAAAA,iBAAA,wBAAqB;AAVX,SAAAA;AAAA,GAAA;AAgBL,SAAS,gBAAgB,QAA4E;AAC1G,SAAO,OAAO,SAAS;AACzB;AAKO,SAAS,sBAAsB,QAAkF;AACtH,SAAO,OAAO,SAAS;AACzB;AAKO,SAAS,eAAe,QAAiC;AAC9D,MAAI,gBAAgB,MAAM,GAAG;AAC3B,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAQ,OAAO,KAA2B;AAC5C;AAKO,SAAS,mBAAmB,QAAuC;AACxE,MAAI,gBAAgB,MAAM,GAAG;AAC3B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,MACN,aAAa,OAAO,KAAK;AAAA,MACzB,WAAW,OAAO,KAAK;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,WAAW,OAAO;AACxB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,aAAa,SAAS;AAAA,IACtB,WAAW,SAAS;AAAA,IACpB,iBAAiB,SAAS;AAAA,EAC5B;AACF;","names":["SwitchErrorCode"]}