@winspan/claude-forge 8.39.0 → 8.50.6

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 (804) hide show
  1. package/.claude/CLAUDE.md +17 -0
  2. package/.eslintrc.js +23 -0
  3. package/.prettierrc +8 -0
  4. package/ARCHITECTURE_ISSUES.md +249 -0
  5. package/CLAUDE.md +265 -0
  6. package/CLAUDE.md.backup +488 -0
  7. package/DEVELOPMENT.md +310 -0
  8. package/dist/claudemd/claudemd-generator.d.ts +38 -3
  9. package/dist/claudemd/claudemd-generator.d.ts.map +1 -1
  10. package/dist/claudemd/claudemd-generator.js +629 -11
  11. package/dist/claudemd/claudemd-generator.js.map +1 -1
  12. package/dist/claudemd/index.d.ts +2 -2
  13. package/dist/claudemd/index.d.ts.map +1 -1
  14. package/dist/claudemd/index.js.map +1 -1
  15. package/dist/claudemd/resume-manager.d.ts.map +1 -1
  16. package/dist/claudemd/resume-manager.js +5 -2
  17. package/dist/claudemd/resume-manager.js.map +1 -1
  18. package/dist/claudemd/tech-detector.d.ts +1 -0
  19. package/dist/claudemd/tech-detector.d.ts.map +1 -1
  20. package/dist/claudemd/tech-detector.js +53 -0
  21. package/dist/claudemd/tech-detector.js.map +1 -1
  22. package/dist/cli/commands/claudemd.js +2 -2
  23. package/dist/cli/commands/claudemd.js.map +1 -1
  24. package/dist/cli/commands/daemon.d.ts +28 -0
  25. package/dist/cli/commands/daemon.d.ts.map +1 -1
  26. package/dist/cli/commands/daemon.js +200 -8
  27. package/dist/cli/commands/daemon.js.map +1 -1
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +3 -35
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/menu.js +10 -10
  32. package/dist/cli/commands/menu.js.map +1 -1
  33. package/dist/cli/commands/skills.d.ts.map +1 -1
  34. package/dist/cli/commands/skills.js +8 -2
  35. package/dist/cli/commands/skills.js.map +1 -1
  36. package/dist/cli/commands/stats.d.ts.map +1 -1
  37. package/dist/cli/commands/stats.js +0 -17
  38. package/dist/cli/commands/stats.js.map +1 -1
  39. package/dist/cli/commands/trace.d.ts +9 -0
  40. package/dist/cli/commands/trace.d.ts.map +1 -0
  41. package/dist/cli/commands/trace.js +137 -0
  42. package/dist/cli/commands/trace.js.map +1 -0
  43. package/dist/cli/index.js +2 -4
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/core/ai/provider.d.ts +10 -2
  46. package/dist/core/ai/provider.d.ts.map +1 -1
  47. package/dist/core/ai/provider.js.map +1 -1
  48. package/dist/core/ai/types.d.ts +1 -19
  49. package/dist/core/ai/types.d.ts.map +1 -1
  50. package/dist/core/ai/types.js +1 -1
  51. package/dist/core/config.d.ts +2 -1
  52. package/dist/core/config.d.ts.map +1 -1
  53. package/dist/core/config.js +30 -6
  54. package/dist/core/config.js.map +1 -1
  55. package/dist/core/constants.d.ts +2 -2
  56. package/dist/core/constants.js +2 -2
  57. package/dist/core/constants.js.map +1 -1
  58. package/dist/core/queue/index.d.ts +52 -0
  59. package/dist/core/queue/index.d.ts.map +1 -0
  60. package/dist/core/queue/index.js +176 -0
  61. package/dist/core/queue/index.js.map +1 -0
  62. package/dist/core/storage/base.d.ts +33 -0
  63. package/dist/core/storage/base.d.ts.map +1 -0
  64. package/dist/core/storage/base.js +211 -0
  65. package/dist/core/storage/base.js.map +1 -0
  66. package/dist/core/storage/events.d.ts +52 -0
  67. package/dist/core/storage/events.d.ts.map +1 -0
  68. package/dist/core/storage/events.js +201 -0
  69. package/dist/core/storage/events.js.map +1 -0
  70. package/dist/core/storage/injections.d.ts +27 -0
  71. package/dist/core/storage/injections.d.ts.map +1 -0
  72. package/dist/core/storage/injections.js +51 -0
  73. package/dist/core/storage/injections.js.map +1 -0
  74. package/dist/core/storage/maintenance.d.ts +21 -0
  75. package/dist/core/storage/maintenance.d.ts.map +1 -0
  76. package/dist/core/storage/maintenance.js +52 -0
  77. package/dist/core/storage/maintenance.js.map +1 -0
  78. package/dist/core/storage/routing.d.ts +71 -0
  79. package/dist/core/storage/routing.d.ts.map +1 -0
  80. package/dist/core/storage/routing.js +141 -0
  81. package/dist/core/storage/routing.js.map +1 -0
  82. package/dist/core/storage/rows.d.ts +0 -47
  83. package/dist/core/storage/rows.d.ts.map +1 -1
  84. package/dist/core/storage/schema.sql +74 -136
  85. package/dist/core/storage/sessions.d.ts +34 -0
  86. package/dist/core/storage/sessions.d.ts.map +1 -0
  87. package/dist/core/storage/sessions.js +78 -0
  88. package/dist/core/storage/sessions.js.map +1 -0
  89. package/dist/core/storage/skills.d.ts +40 -0
  90. package/dist/core/storage/skills.d.ts.map +1 -0
  91. package/dist/core/storage/skills.js +107 -0
  92. package/dist/core/storage/skills.js.map +1 -0
  93. package/dist/core/storage/sqlite.d.ts +63 -265
  94. package/dist/core/storage/sqlite.d.ts.map +1 -1
  95. package/dist/core/storage/sqlite.js +102 -759
  96. package/dist/core/storage/sqlite.js.map +1 -1
  97. package/dist/core/storage/tasks.d.ts +64 -0
  98. package/dist/core/storage/tasks.d.ts.map +1 -0
  99. package/dist/core/storage/tasks.js +134 -0
  100. package/dist/core/storage/tasks.js.map +1 -0
  101. package/dist/core/storage/token-usage.d.ts +36 -0
  102. package/dist/core/storage/token-usage.d.ts.map +1 -0
  103. package/dist/core/storage/token-usage.js +59 -0
  104. package/dist/core/storage/token-usage.js.map +1 -0
  105. package/dist/core/types.d.ts +70 -4
  106. package/dist/core/types.d.ts.map +1 -1
  107. package/dist/core/types.js +24 -1
  108. package/dist/core/types.js.map +1 -1
  109. package/dist/core/utils/format.d.ts +28 -0
  110. package/dist/core/utils/format.d.ts.map +1 -0
  111. package/dist/core/utils/format.js +68 -0
  112. package/dist/core/utils/format.js.map +1 -0
  113. package/dist/core/utils/logger.d.ts +6 -1
  114. package/dist/core/utils/logger.d.ts.map +1 -1
  115. package/dist/core/utils/logger.js +72 -2
  116. package/dist/core/utils/logger.js.map +1 -1
  117. package/dist/core/utils/session.d.ts +16 -0
  118. package/dist/core/utils/session.d.ts.map +1 -0
  119. package/dist/core/utils/session.js +25 -0
  120. package/dist/core/utils/session.js.map +1 -0
  121. package/dist/core/utils/time.d.ts +22 -0
  122. package/dist/core/utils/time.d.ts.map +1 -0
  123. package/dist/core/utils/time.js +38 -0
  124. package/dist/core/utils/time.js.map +1 -0
  125. package/dist/daemon/handlers/history-exporter.d.ts.map +1 -1
  126. package/dist/daemon/handlers/history-exporter.js +6 -4
  127. package/dist/daemon/handlers/history-exporter.js.map +1 -1
  128. package/dist/daemon/handlers/post-tool-use.d.ts +5 -12
  129. package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
  130. package/dist/daemon/handlers/post-tool-use.js +21 -79
  131. package/dist/daemon/handlers/post-tool-use.js.map +1 -1
  132. package/dist/daemon/handlers/stop.d.ts +24 -12
  133. package/dist/daemon/handlers/stop.d.ts.map +1 -1
  134. package/dist/daemon/handlers/stop.js +141 -42
  135. package/dist/daemon/handlers/stop.js.map +1 -1
  136. package/dist/daemon/handlers/user-prompt.d.ts +18 -19
  137. package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
  138. package/dist/daemon/handlers/user-prompt.js +103 -227
  139. package/dist/daemon/handlers/user-prompt.js.map +1 -1
  140. package/dist/daemon/index.d.ts +6 -2
  141. package/dist/daemon/index.d.ts.map +1 -1
  142. package/dist/daemon/index.js +76 -120
  143. package/dist/daemon/index.js.map +1 -1
  144. package/dist/daemon/launchd/com.claude-forge.daemon.plist.template +47 -0
  145. package/dist/daemon/launchd-installer.d.ts +61 -0
  146. package/dist/daemon/launchd-installer.d.ts.map +1 -0
  147. package/dist/daemon/launchd-installer.js +182 -0
  148. package/dist/daemon/launchd-installer.js.map +1 -0
  149. package/dist/daemon/lifecycle.d.ts +11 -0
  150. package/dist/daemon/lifecycle.d.ts.map +1 -1
  151. package/dist/daemon/lifecycle.js +44 -0
  152. package/dist/daemon/lifecycle.js.map +1 -1
  153. package/dist/daemon/router.d.ts +9 -2
  154. package/dist/daemon/router.d.ts.map +1 -1
  155. package/dist/daemon/router.js +27 -3
  156. package/dist/daemon/router.js.map +1 -1
  157. package/dist/daemon/server.d.ts.map +1 -1
  158. package/dist/daemon/server.js +6 -5
  159. package/dist/daemon/server.js.map +1 -1
  160. package/dist/daemon/services/anti-pattern-detector.d.ts +50 -0
  161. package/dist/daemon/services/anti-pattern-detector.d.ts.map +1 -0
  162. package/dist/daemon/services/anti-pattern-detector.js +357 -0
  163. package/dist/daemon/services/anti-pattern-detector.js.map +1 -0
  164. package/dist/daemon/services/drift-detector.d.ts +64 -0
  165. package/dist/daemon/services/drift-detector.d.ts.map +1 -0
  166. package/dist/daemon/services/drift-detector.js +201 -0
  167. package/dist/daemon/services/drift-detector.js.map +1 -0
  168. package/dist/{intelligence → daemon/services}/task-segmenter.d.ts +7 -1
  169. package/dist/daemon/services/task-segmenter.d.ts.map +1 -0
  170. package/dist/{intelligence → daemon/services}/task-segmenter.js +29 -6
  171. package/dist/daemon/services/task-segmenter.js.map +1 -0
  172. package/dist/daemon/services/weekly-report.d.ts +91 -0
  173. package/dist/daemon/services/weekly-report.d.ts.map +1 -0
  174. package/dist/daemon/services/weekly-report.js +327 -0
  175. package/dist/daemon/services/weekly-report.js.map +1 -0
  176. package/dist/hooks/hook-lib.sh +81 -0
  177. package/dist/hooks/notification.sh +7 -3
  178. package/dist/hooks/post-tool-use.sh +8 -4
  179. package/dist/hooks/pre-tool-use.sh +7 -4
  180. package/dist/hooks/stop.sh +1 -1
  181. package/dist/hooks/user-prompt-submit.sh +8 -9
  182. package/dist/mcp/server.d.ts +2 -2
  183. package/dist/mcp/server.d.ts.map +1 -1
  184. package/dist/mcp/server.js +71 -11
  185. package/dist/mcp/server.js.map +1 -1
  186. package/dist/skills/invocation-guard.d.ts +20 -0
  187. package/dist/skills/invocation-guard.d.ts.map +1 -1
  188. package/dist/skills/invocation-guard.js +63 -0
  189. package/dist/skills/invocation-guard.js.map +1 -1
  190. package/dist/skills/matcher.d.ts.map +1 -1
  191. package/dist/skills/matcher.js +12 -3
  192. package/dist/skills/matcher.js.map +1 -1
  193. package/dist/skills/official/code-simplifier.md +16 -0
  194. package/dist/skills/official/find-skills.md +23 -0
  195. package/dist/skills/official/official-api-design.md +17 -0
  196. package/dist/skills/official/official-architecture-decision.md +20 -0
  197. package/dist/skills/official/official-bmad.md +118 -0
  198. package/dist/skills/official/official-db-schema-design.md +16 -0
  199. package/dist/skills/official/official-debug.md +17 -0
  200. package/dist/skills/official/official-doc-driven.md +31 -0
  201. package/dist/skills/official/official-harness-engineering.md +108 -0
  202. package/dist/skills/official/official-performance-optimization.md +30 -0
  203. package/dist/skills/official/official-pr-review.md +35 -0
  204. package/dist/skills/official/official-release-checklist.md +30 -0
  205. package/dist/skills/official/official-security-hardening.md +26 -0
  206. package/dist/skills/official/official-spec-driven-design.md +31 -0
  207. package/dist/skills/official/planning-with-files.md +37 -0
  208. package/dist/skills/official/ui-ux-pro-max.md +18 -0
  209. package/dist/skills/official/webapp-testing.md +12 -0
  210. package/dist/skills/official-skills.d.ts +8 -4
  211. package/dist/skills/official-skills.d.ts.map +1 -1
  212. package/dist/skills/official-skills.js +48 -704
  213. package/dist/skills/official-skills.js.map +1 -1
  214. package/dist/skills/registry.d.ts +5 -0
  215. package/dist/skills/registry.d.ts.map +1 -1
  216. package/dist/skills/registry.js +48 -15
  217. package/dist/skills/registry.js.map +1 -1
  218. package/dist/skills/tools/pipeline-suggest.d.ts +30 -0
  219. package/dist/skills/tools/pipeline-suggest.d.ts.map +1 -0
  220. package/dist/skills/tools/pipeline-suggest.js +178 -0
  221. package/dist/skills/tools/pipeline-suggest.js.map +1 -0
  222. package/dist/skills/tools/skill-invoke.d.ts +2 -0
  223. package/dist/skills/tools/skill-invoke.d.ts.map +1 -1
  224. package/dist/skills/tools/skill-invoke.js +5 -2
  225. package/dist/skills/tools/skill-invoke.js.map +1 -1
  226. package/dist/web/routes/ai.d.ts.map +1 -1
  227. package/dist/web/routes/ai.js +16 -22
  228. package/dist/web/routes/ai.js.map +1 -1
  229. package/dist/web/routes/drift.d.ts +10 -0
  230. package/dist/web/routes/drift.d.ts.map +1 -0
  231. package/dist/web/routes/drift.js +21 -0
  232. package/dist/web/routes/drift.js.map +1 -0
  233. package/dist/web/routes/error-handler.d.ts +43 -0
  234. package/dist/web/routes/error-handler.d.ts.map +1 -0
  235. package/dist/web/routes/error-handler.js +99 -0
  236. package/dist/web/routes/error-handler.js.map +1 -0
  237. package/dist/web/routes/insights.d.ts +9 -0
  238. package/dist/web/routes/insights.d.ts.map +1 -0
  239. package/dist/web/routes/insights.js +34 -0
  240. package/dist/web/routes/insights.js.map +1 -0
  241. package/dist/web/routes/patch.js +2 -2
  242. package/dist/web/routes/patch.js.map +1 -1
  243. package/dist/web/routes/reports.d.ts +10 -0
  244. package/dist/web/routes/reports.d.ts.map +1 -0
  245. package/dist/web/routes/reports.js +27 -0
  246. package/dist/web/routes/reports.js.map +1 -0
  247. package/dist/web/routes/rules.d.ts +10 -3
  248. package/dist/web/routes/rules.d.ts.map +1 -1
  249. package/dist/web/routes/rules.js +80 -95
  250. package/dist/web/routes/rules.js.map +1 -1
  251. package/dist/web/routes/sessions.d.ts +1 -2
  252. package/dist/web/routes/sessions.d.ts.map +1 -1
  253. package/dist/web/routes/sessions.js +27 -39
  254. package/dist/web/routes/sessions.js.map +1 -1
  255. package/dist/web/routes/skill-stats.d.ts.map +1 -1
  256. package/dist/web/routes/skill-stats.js +38 -0
  257. package/dist/web/routes/skill-stats.js.map +1 -1
  258. package/dist/web/routes/skills.d.ts.map +1 -1
  259. package/dist/web/routes/skills.js +34 -0
  260. package/dist/web/routes/skills.js.map +1 -1
  261. package/dist/web/routes/stats.d.ts +7 -0
  262. package/dist/web/routes/stats.d.ts.map +1 -0
  263. package/dist/web/routes/stats.js +44 -0
  264. package/dist/web/routes/stats.js.map +1 -0
  265. package/dist/web/routes/status.js +1 -1
  266. package/dist/web/routes/status.js.map +1 -1
  267. package/dist/web/routes/tasks.d.ts +4 -0
  268. package/dist/web/routes/tasks.d.ts.map +1 -0
  269. package/dist/web/routes/tasks.js +181 -0
  270. package/dist/web/routes/tasks.js.map +1 -0
  271. package/dist/web/routes/trace.d.ts +10 -0
  272. package/dist/web/routes/trace.d.ts.map +1 -0
  273. package/dist/web/routes/trace.js +123 -0
  274. package/dist/web/routes/trace.js.map +1 -0
  275. package/dist/web/routes/types.d.ts +1 -14
  276. package/dist/web/routes/types.d.ts.map +1 -1
  277. package/dist/web/routes/types.js +8 -17
  278. package/dist/web/routes/types.js.map +1 -1
  279. package/dist/web/server.d.ts +1 -9
  280. package/dist/web/server.d.ts.map +1 -1
  281. package/dist/web/server.js +28 -28
  282. package/dist/web/server.js.map +1 -1
  283. package/dist/web/static/assets/AIConfig-BQCAQE9D.js +2 -0
  284. package/dist/web/static/assets/AIConfig-BQCAQE9D.js.map +1 -0
  285. package/dist/web/static/assets/Dashboard-D7Bo6Kan.js +2 -0
  286. package/dist/web/static/assets/Dashboard-D7Bo6Kan.js.map +1 -0
  287. package/dist/web/static/assets/{Drawer-DcU3ln98.js → Drawer-BeHRQxUS.js} +2 -2
  288. package/dist/web/static/assets/{Drawer-DcU3ln98.js.map → Drawer-BeHRQxUS.js.map} +1 -1
  289. package/dist/web/static/assets/Events-K_tCY2ti.js +2 -0
  290. package/dist/web/static/assets/Events-K_tCY2ti.js.map +1 -0
  291. package/dist/web/static/assets/Reports-BJCmBnc_.js +2 -0
  292. package/dist/web/static/assets/Reports-BJCmBnc_.js.map +1 -0
  293. package/dist/web/static/assets/SearchInput-BX2KhMkw.js +2 -0
  294. package/dist/web/static/assets/SearchInput-BX2KhMkw.js.map +1 -0
  295. package/dist/web/static/assets/SessionDetail-Bkr-kC7V.js +2 -0
  296. package/dist/web/static/assets/SessionDetail-Bkr-kC7V.js.map +1 -0
  297. package/dist/web/static/assets/Sessions-Chx9OCLH.js +2 -0
  298. package/dist/web/static/assets/Sessions-Chx9OCLH.js.map +1 -0
  299. package/dist/web/static/assets/Skills-O0GT1i7m.js +2 -0
  300. package/dist/web/static/assets/Skills-O0GT1i7m.js.map +1 -0
  301. package/dist/web/static/assets/TaskDetail-5SR8zGzv.js +2 -0
  302. package/dist/web/static/assets/TaskDetail-5SR8zGzv.js.map +1 -0
  303. package/dist/web/static/assets/Tasks-DCgDqvOZ.js +2 -0
  304. package/dist/web/static/assets/Tasks-DCgDqvOZ.js.map +1 -0
  305. package/dist/web/static/assets/export-L_VBD2p1.js +4 -0
  306. package/dist/web/static/assets/export-L_VBD2p1.js.map +1 -0
  307. package/dist/web/static/assets/index-D8AKj26b.css +1 -0
  308. package/dist/web/static/assets/index-DxIbmNmr.js +3 -0
  309. package/dist/web/static/assets/index-DxIbmNmr.js.map +1 -0
  310. package/dist/web/static/assets/{lucide-53bR2rki.js → lucide-fJlPI3H7.js} +68 -38
  311. package/dist/web/static/assets/lucide-fJlPI3H7.js.map +1 -0
  312. package/dist/web/static/assets/time-Bxuk0M-C.js +2 -0
  313. package/dist/web/static/assets/time-Bxuk0M-C.js.map +1 -0
  314. package/dist/web/static/index.html +3 -3
  315. package/docs/concurrent-agents.md +129 -0
  316. package/docs/design/architecture-review-20260516.md +232 -0
  317. package/docs/design/fix-skills-data-and-set-leak-spec-20260516-1300.md +219 -0
  318. package/docs/design/hook-failure-queue-spec-20260516-1530.md +204 -0
  319. package/docs/design/refactor-phase1-spec-20260515-1600.md +543 -0
  320. package/docs/design/refactor-phase2-spec-20260515-1700.md +424 -0
  321. package/docs/design/tasks-list-filter-pagination-spec-20260518-0930.md +208 -0
  322. package/docs/implementation/fix-skills-data-and-set-leak-changelog-20260516-1300.md +104 -0
  323. package/docs/implementation/hook-failure-queue-changelog-20260516-1530.md +196 -0
  324. package/docs/implementation/hotfix-daemon-event-reject-20260516-1430.md +56 -0
  325. package/docs/implementation/refactor-phase1-changelog-20260515-1630.md +354 -0
  326. package/docs/implementation/refactor-phase2-changelog-20260515-1705.md +421 -0
  327. package/docs/implementation/tasks-list-filter-pagination-changelog-20260518-0930.md +72 -0
  328. package/docs/reviews/claudemd-template-sync.md +54 -0
  329. package/docs/reviews/tasks-filter-pagination.md +80 -0
  330. package/docs/ruflo-learning-strategy.md +322 -0
  331. package/docs/skills-deduplication-analysis.md +83 -0
  332. package/docs/skills-multiformat-support.md +177 -0
  333. package/docs/skills-third-party.md +183 -0
  334. package/docs/testing/tasks-filter-pagination-test-report.md +86 -0
  335. package/forge +321 -0
  336. package/package.json +28 -62
  337. package/playwright.config.ts +40 -0
  338. package/scripts/demo-v2.ts +91 -0
  339. package/scripts/dev-daemon.sh +232 -0
  340. package/scripts/dev-web.ts +109 -0
  341. package/scripts/e2e-mcp-link.ts +423 -0
  342. package/scripts/e2e-methodology-quality.ts +253 -0
  343. package/scripts/e2e-routing.ts +456 -0
  344. package/scripts/e2e-user-methodology.ts +326 -0
  345. package/scripts/e2e-web-workflows.ts +299 -0
  346. package/scripts/migrate-legacy-to-dynamic.sql +108 -0
  347. package/scripts/regenerate-execution-docs.ts +116 -0
  348. package/scripts/sync-agent-skills.ts +193 -0
  349. package/scripts/test-hook.sh +71 -0
  350. package/scripts/verify-skill-loading.ts +62 -0
  351. package/src/claudemd/claudemd-generator.ts +777 -0
  352. package/src/claudemd/convention-extractor.ts +69 -0
  353. package/src/claudemd/index.ts +35 -0
  354. package/src/claudemd/persona-manager.ts +88 -0
  355. package/src/claudemd/resume-manager.ts +236 -0
  356. package/src/claudemd/tech-detector.ts +220 -0
  357. package/src/cli/commands/claudemd.ts +84 -0
  358. package/src/cli/commands/config.ts +46 -0
  359. package/src/cli/commands/daemon.ts +310 -0
  360. package/src/cli/commands/executions.ts +114 -0
  361. package/src/cli/commands/init.ts +204 -0
  362. package/src/cli/commands/logs.ts +181 -0
  363. package/src/cli/commands/mcp.ts +244 -0
  364. package/src/cli/commands/menu.ts +356 -0
  365. package/src/cli/commands/skills.ts +185 -0
  366. package/src/cli/commands/stats.ts +74 -0
  367. package/src/cli/commands/status.ts +69 -0
  368. package/src/cli/commands/template.ts +77 -0
  369. package/src/cli/commands/trace.ts +164 -0
  370. package/src/cli/index.ts +42 -0
  371. package/src/cli/init/hook-manager.ts +132 -0
  372. package/src/core/ai/provider.ts +308 -0
  373. package/src/core/ai/types.ts +51 -0
  374. package/src/core/config.ts +124 -0
  375. package/src/core/constants.ts +45 -0
  376. package/src/core/queue/index.ts +193 -0
  377. package/src/core/storage/base.ts +226 -0
  378. package/src/core/storage/events.ts +255 -0
  379. package/src/core/storage/injections.ts +78 -0
  380. package/src/core/storage/maintenance.ts +59 -0
  381. package/src/core/storage/migrations/002_add_skill_tracking.sql +6 -0
  382. package/src/core/storage/migrations/003_add_skill_invocations.sql +23 -0
  383. package/src/core/storage/performance-indexes.sql +23 -0
  384. package/src/core/storage/routing.ts +194 -0
  385. package/src/core/storage/rows.ts +112 -0
  386. package/src/core/storage/schema.sql +214 -0
  387. package/src/core/storage/sessions.ts +104 -0
  388. package/src/core/storage/skills.ts +164 -0
  389. package/src/core/storage/sqlite.ts +194 -0
  390. package/src/core/storage/tasks.ts +170 -0
  391. package/src/core/storage/token-usage.ts +93 -0
  392. package/src/core/types.ts +154 -0
  393. package/src/core/utils/error-handler.ts +256 -0
  394. package/src/core/utils/forge-resume-block.ts +74 -0
  395. package/src/core/utils/format.ts +69 -0
  396. package/src/core/utils/logger.ts +119 -0
  397. package/src/core/utils/lru-cache.ts +50 -0
  398. package/src/core/utils/path.ts +19 -0
  399. package/src/core/utils/session.ts +26 -0
  400. package/src/core/utils/time.ts +37 -0
  401. package/src/core/utils/token-tracker.ts +97 -0
  402. package/src/daemon/event-parser.ts +35 -0
  403. package/src/daemon/handlers/history-exporter.ts +117 -0
  404. package/src/daemon/handlers/post-tool-use.ts +50 -0
  405. package/src/daemon/handlers/stop.ts +215 -0
  406. package/src/daemon/handlers/user-prompt.ts +188 -0
  407. package/src/daemon/index.ts +278 -0
  408. package/src/daemon/launchd/com.claude-forge.daemon.plist.template +47 -0
  409. package/src/daemon/launchd-installer.ts +260 -0
  410. package/src/daemon/lifecycle.ts +128 -0
  411. package/src/daemon/router.ts +40 -0
  412. package/src/daemon/server.ts +209 -0
  413. package/src/daemon/services/anti-pattern-detector.ts +412 -0
  414. package/src/daemon/services/drift-detector.ts +232 -0
  415. package/src/daemon/services/task-segmenter.ts +112 -0
  416. package/src/daemon/services/weekly-report.ts +454 -0
  417. package/src/hooks/hook-lib.sh +81 -0
  418. package/src/hooks/notification.sh +35 -0
  419. package/src/hooks/post-tool-use.sh +61 -0
  420. package/src/hooks/pre-tool-use.sh +63 -0
  421. package/src/hooks/stop.sh +40 -0
  422. package/src/hooks/user-prompt-submit.sh +69 -0
  423. package/src/mcp/server.ts +322 -0
  424. package/src/skills/index.ts +2 -0
  425. package/src/skills/invocation-guard.ts +177 -0
  426. package/src/skills/matcher.ts +148 -0
  427. package/src/skills/official/code-simplifier.md +16 -0
  428. package/src/skills/official/find-skills.md +23 -0
  429. package/src/skills/official/official-api-design.md +17 -0
  430. package/src/skills/official/official-architecture-decision.md +20 -0
  431. package/src/skills/official/official-bmad.md +118 -0
  432. package/src/skills/official/official-db-schema-design.md +16 -0
  433. package/src/skills/official/official-debug.md +17 -0
  434. package/src/skills/official/official-doc-driven.md +31 -0
  435. package/src/skills/official/official-harness-engineering.md +108 -0
  436. package/src/skills/official/official-performance-optimization.md +30 -0
  437. package/src/skills/official/official-pr-review.md +35 -0
  438. package/src/skills/official/official-release-checklist.md +30 -0
  439. package/src/skills/official/official-security-hardening.md +26 -0
  440. package/src/skills/official/official-spec-driven-design.md +31 -0
  441. package/src/skills/official/planning-with-files.md +37 -0
  442. package/src/skills/official/ui-ux-pro-max.md +18 -0
  443. package/src/skills/official/webapp-testing.md +12 -0
  444. package/src/skills/official-skills.ts +89 -0
  445. package/src/skills/registry.ts +355 -0
  446. package/src/skills/semantic-matcher.ts +231 -0
  447. package/src/skills/tools/pipeline-suggest.ts +226 -0
  448. package/src/skills/tools/skill-invoke.ts +168 -0
  449. package/src/skills/tools/skill-list.ts +59 -0
  450. package/src/templates/go.yaml +53 -0
  451. package/src/templates/python.yaml +59 -0
  452. package/src/templates/react.yaml +55 -0
  453. package/src/templates/template-manager.ts +170 -0
  454. package/src/web/auth-middleware.ts +55 -0
  455. package/src/web/routes/ai.ts +204 -0
  456. package/src/web/routes/auth.ts +22 -0
  457. package/src/web/routes/drift.ts +25 -0
  458. package/src/web/routes/error-handler.ts +120 -0
  459. package/src/web/routes/events.ts +47 -0
  460. package/src/web/routes/insights.ts +43 -0
  461. package/src/web/routes/patch.ts +117 -0
  462. package/src/web/routes/reports.ts +34 -0
  463. package/src/web/routes/rules.ts +101 -0
  464. package/src/web/routes/sessions.ts +262 -0
  465. package/src/web/routes/skill-stats.ts +132 -0
  466. package/src/web/routes/skills.ts +349 -0
  467. package/src/web/routes/static.ts +67 -0
  468. package/src/web/routes/stats.ts +60 -0
  469. package/src/web/routes/status.ts +30 -0
  470. package/src/web/routes/tasks.ts +218 -0
  471. package/src/web/routes/token-usage.ts +20 -0
  472. package/src/web/routes/trace.ts +138 -0
  473. package/src/web/routes/types.ts +56 -0
  474. package/src/web/server.ts +134 -0
  475. package/src/web/ssrf-guard.ts +112 -0
  476. package/src/web/static/index.html +3251 -0
  477. package/src/web/static/vendor/chart.umd.min.js +20 -0
  478. package/tests/e2e/dashboard.spec.ts +205 -0
  479. package/tests/e2e/routing-skill-e2e.test.ts +39 -0
  480. package/tests/helpers/mock-ai.ts +92 -0
  481. package/tests/helpers/mock-storage.ts +159 -0
  482. package/tests/integration/queue-replay.integration.test.ts +193 -0
  483. package/tests/integration/tasks-filter.integration.test.ts +154 -0
  484. package/tests/performance/database.benchmark.ts +161 -0
  485. package/tests/semantic-matcher.test.ts +99 -0
  486. package/tests/skill-matcher.test.ts +110 -0
  487. package/tests/unit/ai-provider-retry.test.ts +194 -0
  488. package/tests/unit/ai-provider-vision.test.ts +224 -0
  489. package/tests/unit/claudemd-generator.test.ts +68 -0
  490. package/tests/unit/cli-mcp.test.ts +141 -0
  491. package/tests/unit/handlers.test.ts +171 -0
  492. package/tests/unit/invocation-guard.test.ts +125 -0
  493. package/tests/unit/queue.test.ts +272 -0
  494. package/tests/unit/router.test.ts +138 -0
  495. package/tests/unit/security.test.ts +128 -0
  496. package/tests/unit/skill-invocations-workflow.test.ts +495 -0
  497. package/tests/unit/skill-registry.test.ts +94 -0
  498. package/tests/unit/skills/invocation-guard-ttl.test.ts +211 -0
  499. package/tests/unit/skills/official-skills-loader.test.ts +126 -0
  500. package/tests/unit/skills/registry-multiformat.test.ts +92 -0
  501. package/tests/unit/storage/sessions-aggregate.test.ts +435 -0
  502. package/tests/unit/storage/sqlite-refactor-harness.test.ts +314 -0
  503. package/tests/unit/storage.test.ts +172 -0
  504. package/tests/unit/token-usage.test.ts +144 -0
  505. package/tests/unit/type-guards.test.ts +201 -0
  506. package/tests/unit/utils/format.test.ts +189 -0
  507. package/tests/unit/utils/session.test.ts +89 -0
  508. package/tests/unit/utils/time.test.ts +112 -0
  509. package/tests/unit/web/routes-auth.test.ts +93 -0
  510. package/tests/unit/web/routes-events.test.ts +101 -0
  511. package/tests/unit/web/routes-sessions.test.ts +181 -0
  512. package/tests/unit/web/routes-skill-stats.test.ts +179 -0
  513. package/tests/unit/web/routes-stats.test.ts +92 -0
  514. package/tests/unit/web/routes-tasks.test.ts +351 -0
  515. package/tsconfig.json +22 -0
  516. package/vitest.config.ts +21 -0
  517. package/vitest.integration.config.ts +16 -0
  518. package/web/CLAUDE.md +20 -0
  519. package/web/index.html +13 -0
  520. package/web/package-lock.json +4854 -0
  521. package/web/package.json +35 -0
  522. package/web/postcss.config.js +6 -0
  523. package/web/src/App.tsx +110 -0
  524. package/web/src/components/CodeBlock.tsx +31 -0
  525. package/web/src/components/Confirm.tsx +96 -0
  526. package/web/src/components/Drawer.tsx +60 -0
  527. package/web/src/components/Layout.tsx +145 -0
  528. package/web/src/components/MarkdownRenderer.tsx +77 -0
  529. package/web/src/components/SearchInput.tsx +31 -0
  530. package/web/src/components/SessionDetailContent.tsx +157 -0
  531. package/web/src/components/Toast.tsx +92 -0
  532. package/web/src/index.css +19 -0
  533. package/web/src/main.tsx +31 -0
  534. package/web/src/pages/AIConfig.tsx +233 -0
  535. package/web/src/pages/Dashboard.tsx +572 -0
  536. package/web/src/pages/Events.tsx +271 -0
  537. package/web/src/pages/Reports.tsx +428 -0
  538. package/web/src/pages/SessionDetail.tsx +162 -0
  539. package/web/src/pages/Sessions.tsx +205 -0
  540. package/web/src/pages/Skills.tsx +180 -0
  541. package/web/src/pages/TaskDetail.tsx +511 -0
  542. package/web/src/pages/Tasks.tsx +150 -0
  543. package/web/src/utils/auth.ts +59 -0
  544. package/web/src/utils/export.ts +54 -0
  545. package/web/src/utils/time.ts +13 -0
  546. package/web/tailwind.config.js +11 -0
  547. package/web/tsconfig.json +21 -0
  548. package/web/tsconfig.node.json +10 -0
  549. package/web/vite.config.ts +76 -0
  550. package/winspan-claude-forge-8.43.0.tgz +0 -0
  551. package/dist/agents/definition.d.ts +0 -62
  552. package/dist/agents/definition.d.ts.map +0 -1
  553. package/dist/agents/definition.js +0 -27
  554. package/dist/agents/definition.js.map +0 -1
  555. package/dist/agents/distributor.d.ts +0 -23
  556. package/dist/agents/distributor.d.ts.map +0 -1
  557. package/dist/agents/distributor.js +0 -85
  558. package/dist/agents/distributor.js.map +0 -1
  559. package/dist/agents/index.d.ts +0 -5
  560. package/dist/agents/index.d.ts.map +0 -1
  561. package/dist/agents/index.js +0 -5
  562. package/dist/agents/index.js.map +0 -1
  563. package/dist/agents/methodologies/agent-builder.d.ts +0 -21
  564. package/dist/agents/methodologies/agent-builder.d.ts.map +0 -1
  565. package/dist/agents/methodologies/agent-builder.js +0 -124
  566. package/dist/agents/methodologies/agent-builder.js.map +0 -1
  567. package/dist/agents/methodologies/phases/bmad/analyze.d.ts +0 -3
  568. package/dist/agents/methodologies/phases/bmad/analyze.d.ts.map +0 -1
  569. package/dist/agents/methodologies/phases/bmad/analyze.js +0 -18
  570. package/dist/agents/methodologies/phases/bmad/analyze.js.map +0 -1
  571. package/dist/agents/methodologies/phases/bmad/design.d.ts +0 -3
  572. package/dist/agents/methodologies/phases/bmad/design.d.ts.map +0 -1
  573. package/dist/agents/methodologies/phases/bmad/design.js +0 -17
  574. package/dist/agents/methodologies/phases/bmad/design.js.map +0 -1
  575. package/dist/agents/methodologies/phases/bmad/implement.d.ts +0 -3
  576. package/dist/agents/methodologies/phases/bmad/implement.d.ts.map +0 -1
  577. package/dist/agents/methodologies/phases/bmad/implement.js +0 -16
  578. package/dist/agents/methodologies/phases/bmad/implement.js.map +0 -1
  579. package/dist/agents/methodologies/phases/bmad/index.d.ts +0 -6
  580. package/dist/agents/methodologies/phases/bmad/index.d.ts.map +0 -1
  581. package/dist/agents/methodologies/phases/bmad/index.js +0 -6
  582. package/dist/agents/methodologies/phases/bmad/index.js.map +0 -1
  583. package/dist/agents/methodologies/phases/bmad/review.d.ts +0 -3
  584. package/dist/agents/methodologies/phases/bmad/review.d.ts.map +0 -1
  585. package/dist/agents/methodologies/phases/bmad/review.js +0 -16
  586. package/dist/agents/methodologies/phases/bmad/review.js.map +0 -1
  587. package/dist/agents/methodologies/phases/bmad/test.d.ts +0 -3
  588. package/dist/agents/methodologies/phases/bmad/test.d.ts.map +0 -1
  589. package/dist/agents/methodologies/phases/bmad/test.js +0 -20
  590. package/dist/agents/methodologies/phases/bmad/test.js.map +0 -1
  591. package/dist/agents/methodologies/phases/harness/fix.d.ts +0 -3
  592. package/dist/agents/methodologies/phases/harness/fix.d.ts.map +0 -1
  593. package/dist/agents/methodologies/phases/harness/fix.js +0 -16
  594. package/dist/agents/methodologies/phases/harness/fix.js.map +0 -1
  595. package/dist/agents/methodologies/phases/harness/index.d.ts +0 -6
  596. package/dist/agents/methodologies/phases/harness/index.d.ts.map +0 -1
  597. package/dist/agents/methodologies/phases/harness/index.js +0 -6
  598. package/dist/agents/methodologies/phases/harness/index.js.map +0 -1
  599. package/dist/agents/methodologies/phases/harness/reproduce.d.ts +0 -3
  600. package/dist/agents/methodologies/phases/harness/reproduce.d.ts.map +0 -1
  601. package/dist/agents/methodologies/phases/harness/reproduce.js +0 -19
  602. package/dist/agents/methodologies/phases/harness/reproduce.js.map +0 -1
  603. package/dist/agents/methodologies/phases/harness/root-cause.d.ts +0 -3
  604. package/dist/agents/methodologies/phases/harness/root-cause.d.ts.map +0 -1
  605. package/dist/agents/methodologies/phases/harness/root-cause.js +0 -20
  606. package/dist/agents/methodologies/phases/harness/root-cause.js.map +0 -1
  607. package/dist/agents/methodologies/phases/harness/safety-net.d.ts +0 -3
  608. package/dist/agents/methodologies/phases/harness/safety-net.d.ts.map +0 -1
  609. package/dist/agents/methodologies/phases/harness/safety-net.js +0 -16
  610. package/dist/agents/methodologies/phases/harness/safety-net.js.map +0 -1
  611. package/dist/agents/methodologies/phases/harness/verify.d.ts +0 -3
  612. package/dist/agents/methodologies/phases/harness/verify.d.ts.map +0 -1
  613. package/dist/agents/methodologies/phases/harness/verify.js +0 -21
  614. package/dist/agents/methodologies/phases/harness/verify.js.map +0 -1
  615. package/dist/agents/methodologies/presets.d.ts +0 -10
  616. package/dist/agents/methodologies/presets.d.ts.map +0 -1
  617. package/dist/agents/methodologies/presets.js +0 -79
  618. package/dist/agents/methodologies/presets.js.map +0 -1
  619. package/dist/agents/methodologies/types.d.ts +0 -43
  620. package/dist/agents/methodologies/types.d.ts.map +0 -1
  621. package/dist/agents/methodologies/types.js +0 -10
  622. package/dist/agents/methodologies/types.js.map +0 -1
  623. package/dist/agents/methodologies/user-config-loader.d.ts +0 -30
  624. package/dist/agents/methodologies/user-config-loader.d.ts.map +0 -1
  625. package/dist/agents/methodologies/user-config-loader.js +0 -159
  626. package/dist/agents/methodologies/user-config-loader.js.map +0 -1
  627. package/dist/agents/official-agents.d.ts +0 -4
  628. package/dist/agents/official-agents.d.ts.map +0 -1
  629. package/dist/agents/official-agents.js +0 -559
  630. package/dist/agents/official-agents.js.map +0 -1
  631. package/dist/agents/registry.d.ts +0 -57
  632. package/dist/agents/registry.d.ts.map +0 -1
  633. package/dist/agents/registry.js +0 -271
  634. package/dist/agents/registry.js.map +0 -1
  635. package/dist/capability/index.d.ts +0 -10
  636. package/dist/capability/index.d.ts.map +0 -1
  637. package/dist/capability/index.js +0 -10
  638. package/dist/capability/index.js.map +0 -1
  639. package/dist/capability/types.d.ts +0 -10
  640. package/dist/capability/types.d.ts.map +0 -1
  641. package/dist/capability/types.js +0 -10
  642. package/dist/capability/types.js.map +0 -1
  643. package/dist/cli/commands/agents.d.ts +0 -3
  644. package/dist/cli/commands/agents.d.ts.map +0 -1
  645. package/dist/cli/commands/agents.js +0 -62
  646. package/dist/cli/commands/agents.js.map +0 -1
  647. package/dist/cli/commands/rules.d.ts +0 -8
  648. package/dist/cli/commands/rules.d.ts.map +0 -1
  649. package/dist/cli/commands/rules.js +0 -89
  650. package/dist/cli/commands/rules.js.map +0 -1
  651. package/dist/daemon/auto-disable-scheduler.d.ts +0 -53
  652. package/dist/daemon/auto-disable-scheduler.d.ts.map +0 -1
  653. package/dist/daemon/auto-disable-scheduler.js +0 -114
  654. package/dist/daemon/auto-disable-scheduler.js.map +0 -1
  655. package/dist/daemon/handlers/pre-tool-use.d.ts +0 -30
  656. package/dist/daemon/handlers/pre-tool-use.d.ts.map +0 -1
  657. package/dist/daemon/handlers/pre-tool-use.js +0 -173
  658. package/dist/daemon/handlers/pre-tool-use.js.map +0 -1
  659. package/dist/daemon/routing-observer.d.ts +0 -42
  660. package/dist/daemon/routing-observer.d.ts.map +0 -1
  661. package/dist/daemon/routing-observer.js +0 -264
  662. package/dist/daemon/routing-observer.js.map +0 -1
  663. package/dist/daemon/routing-state.d.ts +0 -63
  664. package/dist/daemon/routing-state.d.ts.map +0 -1
  665. package/dist/daemon/routing-state.js +0 -223
  666. package/dist/daemon/routing-state.js.map +0 -1
  667. package/dist/engine/agent-router.d.ts +0 -142
  668. package/dist/engine/agent-router.d.ts.map +0 -1
  669. package/dist/engine/agent-router.js +0 -276
  670. package/dist/engine/agent-router.js.map +0 -1
  671. package/dist/engine/context-builder.d.ts +0 -23
  672. package/dist/engine/context-builder.d.ts.map +0 -1
  673. package/dist/engine/context-builder.js +0 -63
  674. package/dist/engine/context-builder.js.map +0 -1
  675. package/dist/engine/conventions/basic-security.yaml +0 -109
  676. package/dist/engine/conventions/code-quality.yaml +0 -123
  677. package/dist/engine/conventions/database-safety.yaml +0 -74
  678. package/dist/engine/conventions/dependency-safety.yaml +0 -132
  679. package/dist/engine/conventions/docker-safety.yaml +0 -69
  680. package/dist/engine/conventions/git-safety.yaml +0 -118
  681. package/dist/engine/conventions/go-best-practices.yaml +0 -84
  682. package/dist/engine/conventions/python-best-practices.yaml +0 -96
  683. package/dist/engine/conventions/react-best-practices.yaml +0 -96
  684. package/dist/engine/conventions/routing.yaml +0 -378
  685. package/dist/engine/conventions/strict-security.yaml +0 -30
  686. package/dist/engine/conventions/ts-quality.yaml +0 -49
  687. package/dist/engine/dsl/compiler.d.ts +0 -34
  688. package/dist/engine/dsl/compiler.d.ts.map +0 -1
  689. package/dist/engine/dsl/compiler.js +0 -702
  690. package/dist/engine/dsl/compiler.js.map +0 -1
  691. package/dist/engine/dsl/parser.d.ts +0 -25
  692. package/dist/engine/dsl/parser.d.ts.map +0 -1
  693. package/dist/engine/dsl/parser.js +0 -208
  694. package/dist/engine/dsl/parser.js.map +0 -1
  695. package/dist/engine/dsl/runtime.d.ts +0 -46
  696. package/dist/engine/dsl/runtime.d.ts.map +0 -1
  697. package/dist/engine/dsl/runtime.js +0 -173
  698. package/dist/engine/dsl/runtime.js.map +0 -1
  699. package/dist/engine/dsl/types.d.ts +0 -139
  700. package/dist/engine/dsl/types.d.ts.map +0 -1
  701. package/dist/engine/dsl/types.js +0 -11
  702. package/dist/engine/dsl/types.js.map +0 -1
  703. package/dist/engine/evidence-store.d.ts +0 -44
  704. package/dist/engine/evidence-store.d.ts.map +0 -1
  705. package/dist/engine/evidence-store.js +0 -109
  706. package/dist/engine/evidence-store.js.map +0 -1
  707. package/dist/engine/experiment-router.d.ts +0 -102
  708. package/dist/engine/experiment-router.d.ts.map +0 -1
  709. package/dist/engine/experiment-router.js +0 -289
  710. package/dist/engine/experiment-router.js.map +0 -1
  711. package/dist/engine/recommender.d.ts +0 -52
  712. package/dist/engine/recommender.d.ts.map +0 -1
  713. package/dist/engine/recommender.js +0 -162
  714. package/dist/engine/recommender.js.map +0 -1
  715. package/dist/engine/rule-engine.d.ts +0 -33
  716. package/dist/engine/rule-engine.d.ts.map +0 -1
  717. package/dist/engine/rule-engine.js +0 -250
  718. package/dist/engine/rule-engine.js.map +0 -1
  719. package/dist/intelligence/classifier.d.ts +0 -75
  720. package/dist/intelligence/classifier.d.ts.map +0 -1
  721. package/dist/intelligence/classifier.js +0 -352
  722. package/dist/intelligence/classifier.js.map +0 -1
  723. package/dist/intelligence/context-gatherer.d.ts +0 -101
  724. package/dist/intelligence/context-gatherer.d.ts.map +0 -1
  725. package/dist/intelligence/context-gatherer.js +0 -417
  726. package/dist/intelligence/context-gatherer.js.map +0 -1
  727. package/dist/intelligence/cot-classifier.d.ts +0 -95
  728. package/dist/intelligence/cot-classifier.d.ts.map +0 -1
  729. package/dist/intelligence/cot-classifier.js +0 -391
  730. package/dist/intelligence/cot-classifier.js.map +0 -1
  731. package/dist/intelligence/distiller.d.ts +0 -22
  732. package/dist/intelligence/distiller.d.ts.map +0 -1
  733. package/dist/intelligence/distiller.js +0 -108
  734. package/dist/intelligence/distiller.js.map +0 -1
  735. package/dist/intelligence/execution-doc-builder.d.ts +0 -151
  736. package/dist/intelligence/execution-doc-builder.d.ts.map +0 -1
  737. package/dist/intelligence/execution-doc-builder.js +0 -1018
  738. package/dist/intelligence/execution-doc-builder.js.map +0 -1
  739. package/dist/intelligence/intent-types.d.ts +0 -13
  740. package/dist/intelligence/intent-types.d.ts.map +0 -1
  741. package/dist/intelligence/intent-types.js +0 -19
  742. package/dist/intelligence/intent-types.js.map +0 -1
  743. package/dist/intelligence/multimodal-parser.d.ts +0 -105
  744. package/dist/intelligence/multimodal-parser.d.ts.map +0 -1
  745. package/dist/intelligence/multimodal-parser.js +0 -425
  746. package/dist/intelligence/multimodal-parser.js.map +0 -1
  747. package/dist/intelligence/quality-gate.d.ts +0 -45
  748. package/dist/intelligence/quality-gate.d.ts.map +0 -1
  749. package/dist/intelligence/quality-gate.js +0 -193
  750. package/dist/intelligence/quality-gate.js.map +0 -1
  751. package/dist/intelligence/task-segmenter.d.ts.map +0 -1
  752. package/dist/intelligence/task-segmenter.js.map +0 -1
  753. package/dist/web/routes/agents.d.ts +0 -7
  754. package/dist/web/routes/agents.d.ts.map +0 -1
  755. package/dist/web/routes/agents.js +0 -209
  756. package/dist/web/routes/agents.js.map +0 -1
  757. package/dist/web/routes/execution-trace.d.ts +0 -21
  758. package/dist/web/routes/execution-trace.d.ts.map +0 -1
  759. package/dist/web/routes/execution-trace.js +0 -353
  760. package/dist/web/routes/execution-trace.js.map +0 -1
  761. package/dist/web/routes/experiments.d.ts +0 -15
  762. package/dist/web/routes/experiments.d.ts.map +0 -1
  763. package/dist/web/routes/experiments.js +0 -187
  764. package/dist/web/routes/experiments.js.map +0 -1
  765. package/dist/web/routes/routing.d.ts +0 -17
  766. package/dist/web/routes/routing.d.ts.map +0 -1
  767. package/dist/web/routes/routing.js +0 -592
  768. package/dist/web/routes/routing.js.map +0 -1
  769. package/dist/web/routes/workflows.d.ts +0 -19
  770. package/dist/web/routes/workflows.d.ts.map +0 -1
  771. package/dist/web/routes/workflows.js +0 -86
  772. package/dist/web/routes/workflows.js.map +0 -1
  773. package/dist/web/static/assets/AIConfig-R5wZ3ZKT.js +0 -2
  774. package/dist/web/static/assets/AIConfig-R5wZ3ZKT.js.map +0 -1
  775. package/dist/web/static/assets/Agents-Beg34V1g.js +0 -2
  776. package/dist/web/static/assets/Agents-Beg34V1g.js.map +0 -1
  777. package/dist/web/static/assets/CodeBlock--H53gk46.js +0 -2
  778. package/dist/web/static/assets/CodeBlock--H53gk46.js.map +0 -1
  779. package/dist/web/static/assets/Dashboard-Cy1xsj1J.js +0 -2
  780. package/dist/web/static/assets/Dashboard-Cy1xsj1J.js.map +0 -1
  781. package/dist/web/static/assets/Events-mFhXl4zI.js +0 -2
  782. package/dist/web/static/assets/Events-mFhXl4zI.js.map +0 -1
  783. package/dist/web/static/assets/ExecutionTrace-DG901hLR.js +0 -3
  784. package/dist/web/static/assets/ExecutionTrace-DG901hLR.js.map +0 -1
  785. package/dist/web/static/assets/MarkdownRenderer-CCIz1MOz.js +0 -2
  786. package/dist/web/static/assets/MarkdownRenderer-CCIz1MOz.js.map +0 -1
  787. package/dist/web/static/assets/Routing-B7BFLfjh.js +0 -2
  788. package/dist/web/static/assets/Routing-B7BFLfjh.js.map +0 -1
  789. package/dist/web/static/assets/SessionDetail-BT0l4RrK.js +0 -2
  790. package/dist/web/static/assets/SessionDetail-BT0l4RrK.js.map +0 -1
  791. package/dist/web/static/assets/Sessions-C6J_HQ_u.js +0 -2
  792. package/dist/web/static/assets/Sessions-C6J_HQ_u.js.map +0 -1
  793. package/dist/web/static/assets/Skills-4DQWLaTv.js +0 -2
  794. package/dist/web/static/assets/Skills-4DQWLaTv.js.map +0 -1
  795. package/dist/web/static/assets/WorkflowDetail-zhNqUkBE.js +0 -2
  796. package/dist/web/static/assets/WorkflowDetail-zhNqUkBE.js.map +0 -1
  797. package/dist/web/static/assets/Workflows-Btvi-lGw.js +0 -2
  798. package/dist/web/static/assets/Workflows-Btvi-lGw.js.map +0 -1
  799. package/dist/web/static/assets/export-BQQZLaHV.js +0 -4
  800. package/dist/web/static/assets/export-BQQZLaHV.js.map +0 -1
  801. package/dist/web/static/assets/index-Cgr9qMtq.js +0 -3
  802. package/dist/web/static/assets/index-Cgr9qMtq.js.map +0 -1
  803. package/dist/web/static/assets/index-CngWb5gC.css +0 -1
  804. package/dist/web/static/assets/lucide-53bR2rki.js.map +0 -1
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Tests for ClaudeProvider retry + timeout logic.
3
+ *
4
+ * The SDK client is replaced with a mock object exposing only
5
+ * `messages.create`; the provider never hits the network.
6
+ */
7
+
8
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
9
+ import { ClaudeProvider, timing } from '../../src/core/ai/provider.js';
10
+
11
+ /** Shape of what `messages.create` must return for the provider to succeed. */
12
+ function makeOkResponse(text = 'ok') {
13
+ return {
14
+ content: [{ type: 'text', text }],
15
+ usage: { input_tokens: 3, output_tokens: 5 },
16
+ model: 'claude-sonnet-4-20250514',
17
+ };
18
+ }
19
+
20
+ /** Build an error object that mimics an Anthropic APIError. */
21
+ function apiError(status: number, message = `HTTP ${status}`): Error & { status: number } {
22
+ const err = new Error(message) as Error & { status: number };
23
+ err.status = status;
24
+ return err;
25
+ }
26
+
27
+ function abortError(message = 'Request aborted'): Error {
28
+ const err = new Error(message);
29
+ err.name = 'AbortError';
30
+ return err;
31
+ }
32
+
33
+ function installMockClient(provider: ClaudeProvider, create: ReturnType<typeof vi.fn>) {
34
+ // @ts-expect-error — overriding internal client for test isolation
35
+ provider.client = { messages: { create } };
36
+ }
37
+
38
+ describe('ClaudeProvider retry + timeout', () => {
39
+ let provider: ClaudeProvider;
40
+ let delaySpy: ReturnType<typeof vi.spyOn>;
41
+
42
+ beforeEach(() => {
43
+ provider = new ClaudeProvider('test-key', 'claude-sonnet-4-20250514');
44
+ vi.useRealTimers();
45
+ // Skip the actual backoff wait so tests finish quickly while still being
46
+ // able to assert the backoff durations via spy call args.
47
+ delaySpy = vi.spyOn(timing, 'delay').mockResolvedValue();
48
+ });
49
+
50
+ afterEach(() => {
51
+ vi.restoreAllMocks();
52
+ vi.useRealTimers();
53
+ });
54
+
55
+ it('retries on 429 rate limit then succeeds', async () => {
56
+ const create = vi
57
+ .fn()
58
+ .mockRejectedValueOnce(apiError(429, 'rate limited'))
59
+ .mockRejectedValueOnce(apiError(429, 'rate limited'))
60
+ .mockResolvedValueOnce(makeOkResponse('done'));
61
+ installMockClient(provider, create);
62
+
63
+ const res = await provider.complete('hi', { maxRetries: 2, timeoutMs: 1000 });
64
+
65
+ expect(res).toBe('done');
66
+ expect(create).toHaveBeenCalledTimes(3);
67
+ });
68
+
69
+ it('retries on 5xx errors then succeeds', async () => {
70
+ const create = vi
71
+ .fn()
72
+ .mockRejectedValueOnce(apiError(503, 'unavailable'))
73
+ .mockRejectedValueOnce(apiError(500, 'boom'))
74
+ .mockResolvedValueOnce(makeOkResponse('recovered'));
75
+ installMockClient(provider, create);
76
+
77
+ const res = await provider.complete('hi', { maxRetries: 2, timeoutMs: 1000 });
78
+
79
+ expect(res).toBe('recovered');
80
+ expect(create).toHaveBeenCalledTimes(3);
81
+ });
82
+
83
+ it('gives up after maxRetries when errors keep coming', async () => {
84
+ const create = vi.fn().mockRejectedValue(apiError(500, 'persistent'));
85
+ installMockClient(provider, create);
86
+
87
+ await expect(
88
+ provider.complete('hi', { maxRetries: 2, timeoutMs: 1000 }),
89
+ ).rejects.toThrow('persistent');
90
+
91
+ // attempt 0 + 2 retries = 3 calls
92
+ expect(create).toHaveBeenCalledTimes(3);
93
+ });
94
+
95
+ it('does not retry on 4xx other than 429', async () => {
96
+ const create = vi.fn().mockRejectedValue(apiError(400, 'bad request'));
97
+ installMockClient(provider, create);
98
+
99
+ await expect(
100
+ provider.complete('hi', { maxRetries: 3, timeoutMs: 1000 }),
101
+ ).rejects.toThrow('bad request');
102
+
103
+ expect(create).toHaveBeenCalledTimes(1);
104
+ });
105
+
106
+ it('does not retry on 401 auth errors', async () => {
107
+ const create = vi.fn().mockRejectedValue(apiError(401, 'unauthorized'));
108
+ installMockClient(provider, create);
109
+
110
+ await expect(
111
+ provider.complete('hi', { maxRetries: 3, timeoutMs: 1000 }),
112
+ ).rejects.toThrow('unauthorized');
113
+
114
+ expect(create).toHaveBeenCalledTimes(1);
115
+ });
116
+
117
+ it('timeout triggers retry and eventually surfaces', async () => {
118
+ // Each call hangs longer than timeoutMs; we reject with AbortError to mirror
119
+ // what the SDK throws when its signal fires, so we don't have to wire a
120
+ // real long-running pending promise into the test.
121
+ const create = vi.fn().mockImplementation(
122
+ () => new Promise((_resolve, reject) => {
123
+ setTimeout(() => reject(abortError()), 20);
124
+ }),
125
+ );
126
+ installMockClient(provider, create);
127
+
128
+ await expect(
129
+ provider.complete('hi', { maxRetries: 2, timeoutMs: 10 }),
130
+ ).rejects.toMatchObject({ name: 'AbortError' });
131
+
132
+ expect(create).toHaveBeenCalledTimes(3);
133
+ });
134
+
135
+ it('uses exponential backoff between retries (1000ms, 2000ms, ...)', async () => {
136
+ const create = vi
137
+ .fn()
138
+ .mockRejectedValueOnce(apiError(500))
139
+ .mockRejectedValueOnce(apiError(500))
140
+ .mockResolvedValueOnce(makeOkResponse());
141
+ installMockClient(provider, create);
142
+
143
+ const res = await provider.complete('hi', { maxRetries: 2, timeoutMs: 5000 });
144
+
145
+ expect(res).toBe('ok');
146
+ expect(create).toHaveBeenCalledTimes(3);
147
+ // delay() is called once per retry with exponential durations.
148
+ const delayCalls = delaySpy.mock.calls.map((args) => args[0]);
149
+ expect(delayCalls).toEqual([1000, 2000]);
150
+ });
151
+
152
+ it('propagates external signal aborts without retry', async () => {
153
+ const create = vi.fn().mockImplementation(() => {
154
+ return new Promise((_resolve, reject) => {
155
+ // Simulate SDK surfacing AbortError once external signal fires.
156
+ setTimeout(() => reject(abortError('user abort')), 5);
157
+ });
158
+ });
159
+ installMockClient(provider, create);
160
+
161
+ const controller = new AbortController();
162
+ setTimeout(() => controller.abort(), 1);
163
+
164
+ await expect(
165
+ provider.complete('hi', { maxRetries: 3, timeoutMs: 1000, signal: controller.signal }),
166
+ ).rejects.toThrow('user abort');
167
+
168
+ // Only one attempt: external aborts short-circuit retry.
169
+ expect(create).toHaveBeenCalledTimes(1);
170
+ });
171
+
172
+ it('completeWithUsage returns usage and model on success', async () => {
173
+ const create = vi.fn().mockResolvedValue(makeOkResponse('hello'));
174
+ installMockClient(provider, create);
175
+
176
+ const res = await provider.completeWithUsage('prompt', { timeoutMs: 500 });
177
+ expect(res.text).toBe('hello');
178
+ expect(res.usage).toEqual({ input_tokens: 3, output_tokens: 5 });
179
+ expect(res.model).toBe('claude-sonnet-4-20250514');
180
+ });
181
+
182
+ it('passes signal and maxRetries:0 to the SDK', async () => {
183
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
184
+ installMockClient(provider, create);
185
+
186
+ await provider.complete('hi', { timeoutMs: 1234, maxRetries: 1 });
187
+
188
+ expect(create).toHaveBeenCalledTimes(1);
189
+ const [, requestOptions] = create.mock.calls[0];
190
+ expect(requestOptions.maxRetries).toBe(0);
191
+ expect(requestOptions.timeout).toBe(1234);
192
+ expect(requestOptions.signal).toBeDefined();
193
+ });
194
+ });
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Tests for ClaudeProvider.completeWithImage (Vision support).
3
+ *
4
+ * The SDK client is replaced with a mock that captures the request body so we
5
+ * can assert content-block shape, base64 encoding, and that the existing
6
+ * retry/timeout pipeline is reused. The provider never hits the network.
7
+ */
8
+
9
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
+ import { promises as fs } from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import { ClaudeProvider, timing } from '../../src/core/ai/provider.js';
14
+ import type { ImageInput } from '../../src/core/ai/types.js';
15
+
16
+ /** Minimal valid response shape the SDK returns. */
17
+ function makeOkResponse(text = 'image described'): unknown {
18
+ return {
19
+ content: [{ type: 'text', text }],
20
+ usage: { input_tokens: 100, output_tokens: 20 },
21
+ model: 'claude-sonnet-4-20250514',
22
+ };
23
+ }
24
+
25
+ /** Build an Anthropic-style API error. */
26
+ function apiError(status: number, message = `HTTP ${status}`): Error & { status: number } {
27
+ const err = new Error(message) as Error & { status: number };
28
+ err.status = status;
29
+ return err;
30
+ }
31
+
32
+ function installMockClient(provider: ClaudeProvider, create: ReturnType<typeof vi.fn>): void {
33
+ // @ts-expect-error — overriding internal client for test isolation
34
+ provider.client = { messages: { create } };
35
+ }
36
+
37
+ /** Create a tmp file containing the given bytes; returns the absolute path. */
38
+ async function writeTmpImage(bytes: Buffer, suffix = '.png'): Promise<string> {
39
+ const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'forge-vision-'));
40
+ const file = path.join(dir, `img${suffix}`);
41
+ await fs.writeFile(file, bytes);
42
+ return file;
43
+ }
44
+
45
+ describe('ClaudeProvider.completeWithImage', () => {
46
+ let provider: ClaudeProvider;
47
+ // The retry path uses timing.delay; stub it to keep retry tests fast.
48
+ let delaySpy: ReturnType<typeof vi.spyOn>;
49
+
50
+ beforeEach(() => {
51
+ provider = new ClaudeProvider('test-key', 'claude-sonnet-4-20250514');
52
+ delaySpy = vi.spyOn(timing, 'delay').mockResolvedValue();
53
+ });
54
+
55
+ afterEach(() => {
56
+ vi.restoreAllMocks();
57
+ });
58
+
59
+ it('encodes image as base64 and packs an image+text user message', async () => {
60
+ const bytes = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); // PNG magic
61
+ const imgPath = await writeTmpImage(bytes, '.png');
62
+
63
+ const create = vi.fn().mockResolvedValue(makeOkResponse('a tiny png'));
64
+ installMockClient(provider, create);
65
+
66
+ const text = await provider.completeWithImage('What is this?', {
67
+ images: [{ path: imgPath, mediaType: 'image/png' }],
68
+ timeoutMs: 1000,
69
+ });
70
+
71
+ expect(text).toBe('a tiny png');
72
+ expect(create).toHaveBeenCalledTimes(1);
73
+
74
+ const [requestBody] = create.mock.calls[0];
75
+ expect(requestBody.messages).toHaveLength(1);
76
+
77
+ const msg = requestBody.messages[0];
78
+ expect(msg.role).toBe('user');
79
+ expect(Array.isArray(msg.content)).toBe(true);
80
+ expect(msg.content).toHaveLength(2);
81
+
82
+ // Image block first, text block second.
83
+ expect(msg.content[0]).toEqual({
84
+ type: 'image',
85
+ source: {
86
+ type: 'base64',
87
+ media_type: 'image/png',
88
+ data: bytes.toString('base64'),
89
+ },
90
+ });
91
+ expect(msg.content[1]).toEqual({ type: 'text', text: 'What is this?' });
92
+ });
93
+
94
+ it('supports multiple images in stable order before the prompt', async () => {
95
+ const a = await writeTmpImage(Buffer.from('aaaa'), '.jpg');
96
+ const b = await writeTmpImage(Buffer.from('bbbb'), '.webp');
97
+
98
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
99
+ installMockClient(provider, create);
100
+
101
+ const images: ImageInput[] = [
102
+ { path: a, mediaType: 'image/jpeg' },
103
+ { path: b, mediaType: 'image/webp' },
104
+ ];
105
+
106
+ await provider.completeWithImage('compare these', { images, timeoutMs: 1000 });
107
+
108
+ const [requestBody] = create.mock.calls[0];
109
+ const content = requestBody.messages[0].content as Array<{ type: string }>;
110
+ expect(content.map((c) => c.type)).toEqual(['image', 'image', 'text']);
111
+
112
+ const block0 = content[0] as { source: { media_type: string; data: string } };
113
+ const block1 = content[1] as { source: { media_type: string; data: string } };
114
+ expect(block0.source.media_type).toBe('image/jpeg');
115
+ expect(block0.source.data).toBe(Buffer.from('aaaa').toString('base64'));
116
+ expect(block1.source.media_type).toBe('image/webp');
117
+ expect(block1.source.data).toBe(Buffer.from('bbbb').toString('base64'));
118
+ });
119
+
120
+ it('forwards system / model / maxTokens through to messages.create', async () => {
121
+ const imgPath = await writeTmpImage(Buffer.from('xy'), '.gif');
122
+
123
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
124
+ installMockClient(provider, create);
125
+
126
+ await provider.completeWithImage('describe', {
127
+ images: [{ path: imgPath, mediaType: 'image/gif' }],
128
+ system: 'you are a vision expert',
129
+ model: 'claude-opus-4-20250514',
130
+ maxTokens: 2048,
131
+ timeoutMs: 1234,
132
+ });
133
+
134
+ const [requestBody, requestOptions] = create.mock.calls[0];
135
+ expect(requestBody.system).toBe('you are a vision expert');
136
+ expect(requestBody.model).toBe('claude-opus-4-20250514');
137
+ expect(requestBody.max_tokens).toBe(2048);
138
+ // Confirm we still strip retries (own retry pipeline) and pass timeout.
139
+ expect(requestOptions.maxRetries).toBe(0);
140
+ expect(requestOptions.timeout).toBe(1234);
141
+ });
142
+
143
+ it('throws a clear error when the file does not exist', async () => {
144
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
145
+ installMockClient(provider, create);
146
+
147
+ const missing = path.join(os.tmpdir(), 'forge-vision-missing-' + Date.now() + '.png');
148
+
149
+ await expect(
150
+ provider.completeWithImage('hi', {
151
+ images: [{ path: missing, mediaType: 'image/png' }],
152
+ timeoutMs: 1000,
153
+ }),
154
+ ).rejects.toThrow(/failed to read image/i);
155
+
156
+ // Validation must run before any API request.
157
+ expect(create).not.toHaveBeenCalled();
158
+ });
159
+
160
+ it('rejects unsupported media types up front', async () => {
161
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
162
+ installMockClient(provider, create);
163
+
164
+ const imgPath = await writeTmpImage(Buffer.from('xx'), '.bmp');
165
+
166
+ await expect(
167
+ provider.completeWithImage('hi', {
168
+ // @ts-expect-error — intentionally invalid to test runtime guard
169
+ images: [{ path: imgPath, mediaType: 'image/bmp' }],
170
+ timeoutMs: 1000,
171
+ }),
172
+ ).rejects.toThrow(/unsupported media type/i);
173
+
174
+ expect(create).not.toHaveBeenCalled();
175
+ });
176
+
177
+ it('throws when images array is empty', async () => {
178
+ const create = vi.fn().mockResolvedValue(makeOkResponse());
179
+ installMockClient(provider, create);
180
+
181
+ await expect(
182
+ provider.completeWithImage('hi', { images: [], timeoutMs: 1000 }),
183
+ ).rejects.toThrow(/at least one image/i);
184
+
185
+ expect(create).not.toHaveBeenCalled();
186
+ });
187
+
188
+ it('reuses retry pipeline: retries on 429 then succeeds', async () => {
189
+ const imgPath = await writeTmpImage(Buffer.from('z'), '.png');
190
+
191
+ const create = vi
192
+ .fn()
193
+ .mockRejectedValueOnce(apiError(429, 'rate limited'))
194
+ .mockResolvedValueOnce(makeOkResponse('done'));
195
+ installMockClient(provider, create);
196
+
197
+ const text = await provider.completeWithImage('hi', {
198
+ images: [{ path: imgPath, mediaType: 'image/png' }],
199
+ maxRetries: 2,
200
+ timeoutMs: 1000,
201
+ });
202
+
203
+ expect(text).toBe('done');
204
+ expect(create).toHaveBeenCalledTimes(2);
205
+ expect(delaySpy).toHaveBeenCalledTimes(1);
206
+ });
207
+
208
+ it('reuses retry pipeline: surfaces non-retriable 400 immediately', async () => {
209
+ const imgPath = await writeTmpImage(Buffer.from('z'), '.png');
210
+
211
+ const create = vi.fn().mockRejectedValue(apiError(400, 'bad image'));
212
+ installMockClient(provider, create);
213
+
214
+ await expect(
215
+ provider.completeWithImage('hi', {
216
+ images: [{ path: imgPath, mediaType: 'image/png' }],
217
+ maxRetries: 3,
218
+ timeoutMs: 1000,
219
+ }),
220
+ ).rejects.toThrow('bad image');
221
+
222
+ expect(create).toHaveBeenCalledTimes(1);
223
+ });
224
+ });
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Characterization tests for ClaudeMdGenerator — safety-net phase.
3
+ *
4
+ * These tests lock down the observable behavior of the SWARM_PROTOCOL
5
+ * template embedded in claudemd-generator.ts BEFORE the template sync fix.
6
+ *
7
+ * NOTE: assertions marked "OLD BEHAVIOR" will be updated in the fix phase
8
+ * to reflect the new template.
9
+ */
10
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
11
+ import { ClaudeMdGenerator } from '../../src/claudemd/claudemd-generator.js';
12
+ import type { ClaudeProvider } from '../../src/core/ai/provider.js';
13
+
14
+ function makeMockAi(response?: string): ClaudeProvider {
15
+ return {
16
+ complete: vi.fn().mockRejectedValue(new Error('ai disabled for tests')),
17
+ } as unknown as ClaudeProvider;
18
+ }
19
+
20
+ describe('ClaudeMdGenerator — SWARM_PROTOCOL template characterization', () => {
21
+ let generator: ClaudeMdGenerator;
22
+
23
+ beforeEach(() => {
24
+ generator = new ClaudeMdGenerator(makeMockAi());
25
+ });
26
+
27
+ it('generates output that contains the core behavior rules section', async () => {
28
+ const result = await generator.generate('/tmp');
29
+ expect(result).toContain('## 核心行为规则');
30
+ });
31
+
32
+ it('generated output contains the Two-Phase Workflow section with NEW title (BMAD 默认路径)', async () => {
33
+ const result = await generator.generate('/tmp');
34
+ // NEW behavior after template sync fix
35
+ expect(result).toContain('Two-Phase Workflow (BMAD 默认路径)');
36
+ });
37
+
38
+ it('generated output contains the 工作流升级判定 section', async () => {
39
+ const result = await generator.generate('/tmp');
40
+ expect(result).toContain('工作流升级判定');
41
+ });
42
+
43
+ it('generated output contains harness-hotfix workflow entry', async () => {
44
+ const result = await generator.generate('/tmp');
45
+ expect(result).toContain('harness-hotfix');
46
+ });
47
+
48
+ it('generated output contains refactor-safe workflow entry', async () => {
49
+ const result = await generator.generate('/tmp');
50
+ expect(result).toContain('refactor-safe');
51
+ });
52
+
53
+ it('generated output contains 测试覆盖率 < 50% condition', async () => {
54
+ const result = await generator.generate('/tmp');
55
+ expect(result).toContain('测试覆盖率 < 50%');
56
+ });
57
+
58
+ it('generated output contains Agent 委托规则 section', async () => {
59
+ const result = await generator.generate('/tmp');
60
+ expect(result).toContain('## Agent 委托规则');
61
+ });
62
+
63
+ it('generated output does NOT contain OLD Two-Phase title (Design-First)', async () => {
64
+ const result = await generator.generate('/tmp');
65
+ // After fix, old title must be gone
66
+ expect(result).not.toContain('Two-Phase Workflow (Design-First)');
67
+ });
68
+ });
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+
3
+ // Mock 必须在 import 被测模块之前
4
+ vi.mock('node:child_process', () => ({
5
+ execSync: vi.fn(),
6
+ }));
7
+ vi.mock('node:fs', async (importOriginal) => {
8
+ const actual = await importOriginal<typeof import('node:fs')>();
9
+ return {
10
+ ...actual,
11
+ existsSync: vi.fn(),
12
+ readFileSync: vi.fn(),
13
+ };
14
+ });
15
+
16
+ import { execSync } from 'node:child_process';
17
+ import { existsSync, readFileSync } from 'node:fs';
18
+ import {
19
+ isClaudeCodeInstalled,
20
+ isMcpRegistered,
21
+ getMcpServerUrl,
22
+ } from '../../src/cli/commands/mcp.js';
23
+
24
+ const mockExecSync = vi.mocked(execSync);
25
+ const mockExistsSync = vi.mocked(existsSync);
26
+ const mockReadFileSync = vi.mocked(readFileSync);
27
+
28
+ describe('cf mcp command', () => {
29
+ beforeEach(() => {
30
+ vi.clearAllMocks();
31
+ });
32
+
33
+ afterEach(() => {
34
+ vi.restoreAllMocks();
35
+ });
36
+
37
+ describe('isClaudeCodeInstalled', () => {
38
+ it('returns true when `command -v claude` succeeds', () => {
39
+ mockExecSync.mockReturnValue(Buffer.from(''));
40
+ expect(isClaudeCodeInstalled()).toBe(true);
41
+ // 用 command -v 而不是 which(POSIX 标准)
42
+ expect(mockExecSync).toHaveBeenCalledWith('command -v claude', { stdio: 'ignore' });
43
+ });
44
+
45
+ it('returns false when execSync throws', () => {
46
+ mockExecSync.mockImplementation(() => {
47
+ throw new Error('not found');
48
+ });
49
+ expect(isClaudeCodeInstalled()).toBe(false);
50
+ });
51
+ });
52
+
53
+ describe('isMcpRegistered', () => {
54
+ it('returns false when `claude mcp get` throws (not registered)', () => {
55
+ mockExecSync.mockImplementation(() => {
56
+ throw new Error('No MCP server found');
57
+ });
58
+ expect(isMcpRegistered()).toEqual({ registered: false });
59
+ });
60
+
61
+ it('returns true with extracted URL when registered', () => {
62
+ mockExecSync.mockReturnValue(
63
+ 'claude-forge:\n Scope: User config\n Status: ✓ Connected\n Type: http\n URL: http://127.0.0.1:3456/mcp\n',
64
+ );
65
+ const result = isMcpRegistered();
66
+ expect(result.registered).toBe(true);
67
+ expect(result.url).toBe('http://127.0.0.1:3456/mcp');
68
+ });
69
+
70
+ it('returns registered=true with undefined url when output lacks URL line', () => {
71
+ mockExecSync.mockReturnValue('claude-forge:\n Scope: User config\n');
72
+ const result = isMcpRegistered();
73
+ expect(result.registered).toBe(true);
74
+ expect(result.url).toBeUndefined();
75
+ });
76
+
77
+ it('uses `claude mcp get claude-forge` command', () => {
78
+ mockExecSync.mockReturnValue('claude-forge:\n URL: http://x\n');
79
+ isMcpRegistered();
80
+ expect(mockExecSync).toHaveBeenCalledWith(
81
+ 'claude mcp get claude-forge',
82
+ expect.objectContaining({ encoding: 'utf-8' }),
83
+ );
84
+ });
85
+ });
86
+
87
+ describe('getMcpServerUrl', () => {
88
+ it('builds URL from default port', () => {
89
+ const url = getMcpServerUrl();
90
+ // 默认端口是 3456(来自 DEFAULTS.WEB_PORT)
91
+ expect(url).toMatch(/^http:\/\/127\.0\.0\.1:\d+\/mcp$/);
92
+ });
93
+ });
94
+
95
+ describe('command syntax sanity', () => {
96
+ // 这组测试是"防回归"——锁定 cf mcp register 实际执行的命令格式,
97
+ // 避免再次出现 `--url` 这种不存在的选项
98
+ it('register command syntax must use --transport http and -H header', () => {
99
+ // 单纯检查源文件里的 execSync 字符串模板(black-box sanity check)
100
+ // 不在这里执行 registerCommand,因为它会 process.exit
101
+ const mcpSource = readFileSync('src/cli/commands/mcp.ts', 'utf-8');
102
+ // 注意:这里调用的是真实 readFileSync(mock 不影响 import 之外的调用),
103
+ // 但因为我们 mock 了 readFileSync,这条测试需要 setup 真实读
104
+ // —— 为了简化,我们做静态字符串断言
105
+ // (skip if mock returned a fake value)
106
+ });
107
+ });
108
+ });
109
+
110
+ // 单独 describe:通过读取真实源代码验证命令格式
111
+ describe('cf mcp register: command format static check', () => {
112
+ it('source code uses `claude mcp add --transport http`', async () => {
113
+ // 用 dynamic import 拿到 node:fs 的真实模块(绕过文件级 mock)
114
+ const fs = await vi.importActual<typeof import('node:fs')>('node:fs');
115
+ const src = fs.readFileSync('src/cli/commands/mcp.ts', 'utf-8');
116
+
117
+ expect(src, 'must NOT contain deprecated --url flag').not.toMatch(/--url\s/);
118
+ expect(src, 'must use --transport http').toMatch(/--transport http/);
119
+ expect(src, 'must use -s user (user scope)').toMatch(/-s\s+\$\{SCOPE\}|-s user/);
120
+ expect(src, 'must pass Authorization header').toMatch(/Authorization: Bearer/);
121
+ });
122
+
123
+ it('source code uses correct `claude mcp remove` syntax', async () => {
124
+ const fs = await vi.importActual<typeof import('node:fs')>('node:fs');
125
+ const src = fs.readFileSync('src/cli/commands/mcp.ts', 'utf-8');
126
+
127
+ expect(src).toMatch(/claude mcp remove -s \$\{SCOPE\}|claude mcp remove -s user/);
128
+ });
129
+
130
+ it('source code uses `claude mcp get` for status check (not settings.json)', async () => {
131
+ const fs = await vi.importActual<typeof import('node:fs')>('node:fs');
132
+ const src = fs.readFileSync('src/cli/commands/mcp.ts', 'utf-8');
133
+
134
+ expect(src).toMatch(/claude mcp get/);
135
+ // 不应该再用 ~/.claude/settings.json 路径来检查注册状态
136
+ // (只允许在注释里出现作为历史对比,但 join() 调用不能拼这个路径)
137
+ expect(src, 'must not join settings.json in code').not.toMatch(
138
+ /join\([^)]*['"]settings\.json['"]\)/,
139
+ );
140
+ });
141
+ });