@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,205 @@
1
+ /**
2
+ * E2E 测试:管理后台 Dashboard
3
+ *
4
+ * 运行前提:
5
+ * 1. 安装 Playwright: npm install -D @playwright/test
6
+ * 2. 启动守护进程: claude-forge daemon start
7
+ * 3. 运行测试: npm run test:e2e
8
+ */
9
+
10
+ import { test, expect } from '@playwright/test';
11
+
12
+ const BASE_URL = 'http://localhost:3721';
13
+
14
+ test.describe('Dashboard 页面', () => {
15
+ test('应该正确加载并显示统计卡片', async ({ page }) => {
16
+ await page.goto(BASE_URL);
17
+
18
+ // 等待页面加载
19
+ await page.waitForSelector('#dash-stats');
20
+
21
+ // 检查统计卡片是否存在
22
+ await expect(page.locator('.stat-card')).toHaveCount(4);
23
+
24
+ // 检查守护进程状态
25
+ const status = await page.locator('#daemon-status').textContent();
26
+ expect(['运行中', '离线', '检查中']).toContain(status);
27
+ });
28
+
29
+ test('应该显示近 7 天活动图表', async ({ page }) => {
30
+ await page.goto(BASE_URL);
31
+
32
+ // 检查图表容器
33
+ await expect(page.locator('#chart-activity')).toBeVisible();
34
+ await expect(page.locator('#chart-tools')).toBeVisible();
35
+ });
36
+
37
+ test('应该显示最近会话列表', async ({ page }) => {
38
+ await page.goto(BASE_URL);
39
+
40
+ // 检查会话列表容器
41
+ await expect(page.locator('#dash-sessions')).toBeVisible();
42
+ });
43
+ });
44
+
45
+ test.describe('Sessions 页面', () => {
46
+ test('应该正确加载会话列表', async ({ page }) => {
47
+ await page.goto(BASE_URL);
48
+
49
+ // 点击 Sessions 导航
50
+ await page.click('#nav-sessions');
51
+
52
+ // 等待页面切换
53
+ await page.waitForSelector('#page-sessions.active');
54
+
55
+ // 检查搜索框
56
+ await expect(page.locator('#sessions-search')).toBeVisible();
57
+
58
+ // 检查列表容器
59
+ await expect(page.locator('#sessions-list')).toBeVisible();
60
+ });
61
+
62
+ test('搜索功能应该正常工作', async ({ page }) => {
63
+ await page.goto(BASE_URL);
64
+ await page.click('#nav-sessions');
65
+ await page.waitForSelector('#page-sessions.active');
66
+
67
+ // 输入搜索关键词
68
+ await page.fill('#sessions-search', 'test');
69
+
70
+ // 等待搜索结果更新(通过 oninput 触发)
71
+ await page.waitForTimeout(300);
72
+
73
+ // 验证搜索框有值
74
+ const searchValue = await page.inputValue('#sessions-search');
75
+ expect(searchValue).toBe('test');
76
+ });
77
+
78
+ test('点击会话应该打开详情抽屉', async ({ page }) => {
79
+ await page.goto(BASE_URL);
80
+ await page.click('#nav-sessions');
81
+ await page.waitForSelector('#page-sessions.active');
82
+
83
+ // 等待会话列表加载
84
+ await page.waitForTimeout(500);
85
+
86
+ // 如果有会话,点击第一个
87
+ const firstSession = page.locator('.list-item').first();
88
+ if (await firstSession.isVisible()) {
89
+ await firstSession.click();
90
+
91
+ // 检查抽屉是否打开
92
+ await expect(page.locator('#drawer.open')).toBeVisible();
93
+ await expect(page.locator('#drawer-title')).toContainText('会话');
94
+ }
95
+ });
96
+ });
97
+
98
+ test.describe('Events 页面', () => {
99
+ test('应该正确加载事件列表', async ({ page }) => {
100
+ await page.goto(BASE_URL);
101
+ await page.click('#nav-events');
102
+ await page.waitForSelector('#page-events.active');
103
+
104
+ // 检查搜索框和筛选器
105
+ await expect(page.locator('#events-search')).toBeVisible();
106
+ await expect(page.locator('#events-type')).toBeVisible();
107
+
108
+ // 检查表格
109
+ await expect(page.locator('#events-body')).toBeVisible();
110
+ });
111
+
112
+ test('类型筛选应该正常工作', async ({ page }) => {
113
+ await page.goto(BASE_URL);
114
+ await page.click('#nav-events');
115
+ await page.waitForSelector('#page-events.active');
116
+
117
+ // 选择筛选类型
118
+ await page.selectOption('#events-type', 'PreToolUse');
119
+
120
+ // 等待筛选结果更新
121
+ await page.waitForTimeout(300);
122
+
123
+ // 验证筛选器有值
124
+ const selectedValue = await page.inputValue('#events-type');
125
+ expect(selectedValue).toBe('PreToolUse');
126
+ });
127
+ });
128
+
129
+ test.describe('Injections 页面', () => {
130
+ test('应该正确加载注入列表', async ({ page }) => {
131
+ await page.goto(BASE_URL);
132
+ await page.click('#nav-injections');
133
+ await page.waitForSelector('#page-injections.active');
134
+
135
+ // 检查搜索框和筛选器
136
+ await expect(page.locator('#inj-search')).toBeVisible();
137
+ await expect(page.locator('#inj-handler')).toBeVisible();
138
+
139
+ // 检查列表容器
140
+ await expect(page.locator('#inj-list')).toBeVisible();
141
+ });
142
+ });
143
+
144
+ test.describe('Rules 页面', () => {
145
+ test('应该正确加载规则列表', async ({ page }) => {
146
+ await page.goto(BASE_URL);
147
+ await page.click('#nav-rules');
148
+ await page.waitForSelector('#page-rules.active');
149
+
150
+ // 检查搜索框
151
+ await expect(page.locator('#rules-search')).toBeVisible();
152
+
153
+ // 检查列表容器
154
+ await expect(page.locator('#rules-list')).toBeVisible();
155
+ });
156
+ });
157
+
158
+ test.describe('Live 页面', () => {
159
+ test('应该正确加载实时监控页面', async ({ page }) => {
160
+ await page.goto(BASE_URL);
161
+ await page.click('#nav-live');
162
+ await page.waitForSelector('#page-live.active');
163
+
164
+ // 检查状态和按钮
165
+ await expect(page.locator('#live-status')).toBeVisible();
166
+ await expect(page.locator('#live-btn')).toBeVisible();
167
+
168
+ // 检查日志容器
169
+ await expect(page.locator('#live-log')).toBeVisible();
170
+ });
171
+ });
172
+
173
+ test.describe('导航功能', () => {
174
+ test('所有导航链接应该正常工作', async ({ page }) => {
175
+ await page.goto(BASE_URL);
176
+
177
+ const navItems = [
178
+ { id: 'nav-dashboard', pageId: 'page-dashboard' },
179
+ { id: 'nav-sessions', pageId: 'page-sessions' },
180
+ { id: 'nav-events', pageId: 'page-events' },
181
+ { id: 'nav-injections', pageId: 'page-injections' },
182
+ { id: 'nav-live', pageId: 'page-live' },
183
+ { id: 'nav-rules', pageId: 'page-rules' }
184
+ ];
185
+
186
+ for (const item of navItems) {
187
+ await page.click(`#${item.id}`);
188
+ await page.waitForSelector(`#${item.pageId}.active`);
189
+ await expect(page.locator(`#${item.pageId}`)).toHaveClass(/active/);
190
+ }
191
+ });
192
+
193
+ test('刷新按钮应该正常工作', async ({ page }) => {
194
+ await page.goto(BASE_URL);
195
+
196
+ // 点击刷新按钮
197
+ await page.click('button:has-text("刷新")');
198
+
199
+ // 等待页面重新加载
200
+ await page.waitForTimeout(500);
201
+
202
+ // 验证页面仍然可见
203
+ await expect(page.locator('#dash-stats')).toBeVisible();
204
+ });
205
+ });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * E2E Test Suite: Routing & Skill Invocation Verification
3
+ *
4
+ * Tests the complete chain:
5
+ * 1. UserPrompt → Classifier → AgentRouter → routing_events
6
+ * 2. Agent execution → skill_invoke MCP call → skill_invocations
7
+ * 3. Data integrity: obeyed tracking, route_request_id linkage
8
+ *
9
+ * Prerequisites:
10
+ * - Daemon must be running (claude-forge daemon start)
11
+ * - Database at ~/.claude-forge/data.db
12
+ * - MCP server mounted at http://127.0.0.1:3721/mcp
13
+ */
14
+
15
+ import { describe, it, expect, beforeAll } from 'vitest';
16
+ import { readFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { FORGE_PATHS } from '../../src/core/constants.js';
19
+ import { SQLiteStorage } from '../../src/core/storage/sqlite.js';
20
+
21
+ const DAEMON_TOKEN_PATH = join(FORGE_PATHS.home(), 'daemon.token');
22
+ const DB_PATH = FORGE_PATHS.database();
23
+
24
+ describe('E2E: Routing & Skill Invocation', () => {
25
+ let storage: SQLiteStorage;
26
+ let daemonToken: string;
27
+
28
+ beforeAll(() => {
29
+ // Read daemon token for MCP auth
30
+ try {
31
+ daemonToken = readFileSync(DAEMON_TOKEN_PATH, 'utf-8').trim();
32
+ } catch (err) {
33
+ throw new Error(
34
+ `Cannot read daemon token at ${DAEMON_TOKEN_PATH}. ` +
35
+ `Is the daemon running? Run: claude-forge daemon start`
36
+ );
37
+ }
38
+
39
+ // Connect to live database
@@ -0,0 +1,92 @@
1
+ import type { AIProvider } from '../../src/core/ai/provider.js';
2
+
3
+ /**
4
+ * Mock AI Provider for testing
5
+ */
6
+ export class MockAIProvider implements AIProvider {
7
+ private responses: string[] = [];
8
+ private currentIndex = 0;
9
+ public callHistory: Array<{ prompt: string; options?: Record<string, unknown> }> = [];
10
+
11
+ constructor(responses: string[] = ['mock response']) {
12
+ this.responses = responses;
13
+ }
14
+
15
+ async complete(prompt: string, options?: { maxTokens?: number; temperature?: number }): Promise<string> {
16
+ this.callHistory.push({ prompt, options });
17
+
18
+ if (this.currentIndex >= this.responses.length) {
19
+ return this.responses[this.responses.length - 1] || 'default mock response';
20
+ }
21
+
22
+ const response = this.responses[this.currentIndex];
23
+ this.currentIndex++;
24
+ return response;
25
+ }
26
+
27
+ /**
28
+ * Add more responses to the queue
29
+ */
30
+ addResponse(response: string): void {
31
+ this.responses.push(response);
32
+ }
33
+
34
+ /**
35
+ * Reset the provider state
36
+ */
37
+ reset(): void {
38
+ this.currentIndex = 0;
39
+ this.callHistory = [];
40
+ }
41
+
42
+ /**
43
+ * Get the number of times complete() was called
44
+ */
45
+ getCallCount(): number {
46
+ return this.callHistory.length;
47
+ }
48
+
49
+ /**
50
+ * Get the last prompt sent to complete()
51
+ */
52
+ getLastPrompt(): string | undefined {
53
+ return this.callHistory[this.callHistory.length - 1]?.prompt;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Create a mock AI provider that always returns the same response
59
+ */
60
+ export function createMockAI(response: string = 'mock response'): MockAIProvider {
61
+ return new MockAIProvider([response]);
62
+ }
63
+
64
+ /**
65
+ * Create a mock AI provider with multiple responses (returns them in sequence)
66
+ */
67
+ export function createMockAIWithResponses(responses: string[]): MockAIProvider {
68
+ return new MockAIProvider(responses);
69
+ }
70
+
71
+ /**
72
+ * Create a mock AI provider that throws an error
73
+ */
74
+ export function createFailingMockAI(errorMessage: string = 'Mock AI error'): AIProvider {
75
+ return {
76
+ async complete(): Promise<string> {
77
+ throw new Error(errorMessage);
78
+ },
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Create a mock AI provider that simulates slow responses
84
+ */
85
+ export function createSlowMockAI(response: string = 'slow response', delayMs: number = 100): AIProvider {
86
+ return {
87
+ async complete(): Promise<string> {
88
+ await new Promise(resolve => setTimeout(resolve, delayMs));
89
+ return response;
90
+ },
91
+ };
92
+ }
@@ -0,0 +1,159 @@
1
+ import Database from 'better-sqlite3';
2
+ import type { ForgeEvent } from '../../src/core/types.js';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+
7
+ /**
8
+ * Create a temporary in-memory SQLite database for testing
9
+ */
10
+ export function createMockDatabase(): Database.Database {
11
+ const db = new Database(':memory:');
12
+
13
+ // Create minimal schema
14
+ db.exec(`
15
+ CREATE TABLE IF NOT EXISTS events (
16
+ event_id TEXT PRIMARY KEY,
17
+ session_id TEXT NOT NULL,
18
+ project_path TEXT NOT NULL,
19
+ timestamp TEXT NOT NULL,
20
+ hook_type TEXT NOT NULL,
21
+ tool_name TEXT,
22
+ tool_input TEXT,
23
+ tool_output TEXT,
24
+ user_prompt TEXT,
25
+ ai_response TEXT,
26
+ distilled INTEGER DEFAULT 0,
27
+ created_at TEXT DEFAULT (datetime('now'))
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS sessions (
31
+ session_id TEXT PRIMARY KEY,
32
+ project_path TEXT NOT NULL,
33
+ status TEXT NOT NULL DEFAULT 'active',
34
+ first_prompt TEXT,
35
+ start_time TEXT NOT NULL,
36
+ end_time TEXT,
37
+ last_event_time TEXT,
38
+ event_count INTEGER DEFAULT 0,
39
+ created_at TEXT DEFAULT (datetime('now')),
40
+ updated_at TEXT DEFAULT (datetime('now'))
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS routing_events (
44
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
45
+ session_id TEXT NOT NULL,
46
+ route_request_id TEXT,
47
+ project_path TEXT NOT NULL,
48
+ ts INTEGER NOT NULL,
49
+ prompt TEXT NOT NULL,
50
+ intent_json TEXT NOT NULL,
51
+ routed_to_type TEXT,
52
+ routed_to_name TEXT,
53
+ is_forced INTEGER DEFAULT 0,
54
+ obeyed INTEGER,
55
+ classification_ms INTEGER
56
+ );
57
+
58
+ CREATE TABLE IF NOT EXISTS injections (
59
+ id TEXT PRIMARY KEY,
60
+ event_id TEXT,
61
+ session_id TEXT NOT NULL,
62
+ timestamp TEXT NOT NULL,
63
+ source_handler TEXT NOT NULL,
64
+ injection_type TEXT NOT NULL,
65
+ content TEXT NOT NULL,
66
+ created_at TEXT DEFAULT (datetime('now'))
67
+ );
68
+
69
+ CREATE INDEX idx_events_session ON events(session_id);
70
+ CREATE INDEX idx_events_timestamp ON events(timestamp DESC);
71
+ CREATE INDEX idx_sessions_project ON sessions(project_path);
72
+ CREATE INDEX idx_routing_events_session ON routing_events(session_id);
73
+ CREATE INDEX idx_injections_session ON injections(session_id);
74
+ `);
75
+
76
+ return db;
77
+ }
78
+
79
+ /**
80
+ * Create a temporary file-based database for testing
81
+ */
82
+ export function createTempDatabase(): { db: Database.Database; path: string; cleanup: () => void } {
83
+ const dbPath = path.join(tmpdir(), `test-${Date.now()}-${Math.random().toString(36).slice(2)}.db`);
84
+ const db = createMockDatabase();
85
+
86
+ const cleanup = () => {
87
+ try {
88
+ db.close();
89
+ if (fs.existsSync(dbPath)) {
90
+ fs.unlinkSync(dbPath);
91
+ }
92
+ } catch (err) {
93
+ // Ignore cleanup errors
94
+ }
95
+ };
96
+
97
+ return { db, path: dbPath, cleanup };
98
+ }
99
+
100
+ /**
101
+ * Create mock ForgeEvent for testing
102
+ */
103
+ export function createMockEvent(overrides?: Partial<ForgeEvent>): ForgeEvent {
104
+ return {
105
+ event_id: `event-${Date.now()}-${Math.random().toString(36).slice(2)}`,
106
+ session_id: 'test-session',
107
+ project_path: '/test/project',
108
+ timestamp: new Date().toISOString(),
109
+ hook_type: 'UserPromptSubmit',
110
+ user_prompt: 'test prompt',
111
+ ...overrides,
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Insert mock events into database
117
+ */
118
+ export function insertMockEvents(db: Database.Database, events: ForgeEvent[]): void {
119
+ const stmt = db.prepare(`
120
+ INSERT INTO events (event_id, session_id, project_path, timestamp, hook_type,
121
+ tool_name, tool_input, tool_output, user_prompt, ai_response, distilled)
122
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)
123
+ `);
124
+
125
+ for (const event of events) {
126
+ stmt.run(
127
+ event.event_id || `event-${Date.now()}`,
128
+ event.session_id,
129
+ event.project_path,
130
+ event.timestamp,
131
+ event.hook_type,
132
+ event.tool_name ?? null,
133
+ event.tool_input ? JSON.stringify(event.tool_input) : null,
134
+ event.tool_output ? JSON.stringify(event.tool_output) : null,
135
+ event.user_prompt ?? null,
136
+ event.ai_response ?? null,
137
+ );
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Query all events from database
143
+ */
144
+ export function queryAllEvents(db: Database.Database): ForgeEvent[] {
145
+ const rows = db.prepare('SELECT * FROM events ORDER BY timestamp DESC').all() as Array<Record<string, unknown>>;
146
+
147
+ return rows.map(row => ({
148
+ event_id: row.event_id as string,
149
+ session_id: row.session_id as string,
150
+ project_path: row.project_path as string,
151
+ timestamp: row.timestamp as string,
152
+ hook_type: row.hook_type as ForgeEvent['hook_type'],
153
+ tool_name: (row.tool_name as string) || undefined,
154
+ tool_input: row.tool_input ? JSON.parse(row.tool_input as string) : undefined,
155
+ tool_output: row.tool_output ? JSON.parse(row.tool_output as string) : undefined,
156
+ user_prompt: (row.user_prompt as string) || undefined,
157
+ ai_response: (row.ai_response as string) || undefined,
158
+ }));
159
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Integration test: hook failure queue → daemon startup replay
3
+ *
4
+ * Uses real SQLiteStorage (no mocks for storage layer).
5
+ * Does NOT start an actual daemon process — instead tests the queue
6
+ * module functions directly with the same storage that daemon would use.
7
+ *
8
+ * Test scenarios:
9
+ * 1. Enqueue 3 events → replayQueue → all 3 in DB, queue empty
10
+ * 2. Second replayQueue → skipped=3 (dedup), DB still has 3 rows
11
+ * 3. TTL and bad JSON → dead-lettered correctly
12
+ */
13
+
14
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
15
+ import { mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync, utimesSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { tmpdir } from 'node:os';
18
+ import { randomUUID } from 'node:crypto';
19
+
20
+ describe('Queue → Daemon Replay Integration', () => {
21
+ let tempHome: string;
22
+ let queueDir: string;
23
+ let deadDir: string;
24
+ let dbPath: string;
25
+ let originalHome: string | undefined;
26
+
27
+ beforeEach(async () => {
28
+ originalHome = process.env['HOME'];
29
+ tempHome = mkdtempSync(join(tmpdir(), 'forge-integ-'));
30
+ process.env['HOME'] = tempHome;
31
+
32
+ queueDir = join(tempHome, '.claude-forge', 'queue');
33
+ deadDir = join(queueDir, 'dead');
34
+ dbPath = join(tempHome, 'data.db');
35
+
36
+ mkdirSync(queueDir, { recursive: true });
37
+ mkdirSync(deadDir, { recursive: true });
38
+
39
+ vi.resetModules();
40
+ });
41
+
42
+ afterEach(() => {
43
+ process.env['HOME'] = originalHome;
44
+ rmSync(tempHome, { recursive: true, force: true });
45
+ vi.resetModules();
46
+ });
47
+
48
+ it('enqueues 3 events then replays all into DB and empties queue', async () => {
49
+ const { enqueueEvent, replayQueue } = await import('../../src/core/queue/index.js');
50
+ const { SQLiteStorage } = await import('../../src/core/storage/sqlite.js');
51
+ const storage = new SQLiteStorage(dbPath);
52
+
53
+ const events = [
54
+ {
55
+ session_id: 'integ-session-1',
56
+ project_path: '/tmp/proj',
57
+ timestamp: new Date().toISOString(),
58
+ hook_type: 'UserPromptSubmit' as const,
59
+ user_prompt: 'prompt 1',
60
+ event_id: randomUUID(),
61
+ },
62
+ {
63
+ session_id: 'integ-session-1',
64
+ project_path: '/tmp/proj',
65
+ timestamp: new Date().toISOString(),
66
+ hook_type: 'PreToolUse' as const,
67
+ tool_name: 'Bash',
68
+ event_id: randomUUID(),
69
+ },
70
+ {
71
+ session_id: 'integ-session-1',
72
+ project_path: '/tmp/proj',
73
+ timestamp: new Date().toISOString(),
74
+ hook_type: 'PostToolUse' as const,
75
+ tool_name: 'Bash',
76
+ tool_input: { command: 'ls' },
77
+ tool_output: { output: 'file.txt' },
78
+ event_id: randomUUID(),
79
+ },
80
+ ];
81
+
82
+ // Simulate daemon downtime: enqueue all events
83
+ for (const event of events) {
84
+ enqueueEvent(event);
85
+ }
86
+
87
+ const queuedFiles = readdirSync(queueDir).filter((f) => f.endsWith('.json'));
88
+ expect(queuedFiles).toHaveLength(3);
89
+
90
+ // Simulate daemon startup: replay queue
91
+ const result = await replayQueue(storage);
92
+ expect(result.replayed).toBe(3);
93
+ expect(result.skipped).toBe(0);
94
+ expect(result.dead).toBe(0);
95
+
96
+ // Verify all events are in DB
97
+ const dbEvents = storage.queryEvents({ session_id: 'integ-session-1' });
98
+ expect(dbEvents).toHaveLength(3);
99
+
100
+ // Verify queue is empty
101
+ const remainingFiles = readdirSync(queueDir).filter((f) => f.endsWith('.json'));
102
+ expect(remainingFiles).toHaveLength(0);
103
+
104
+ storage.close();
105
+ });
106
+
107
+ it('second replayQueue skips all events (dedup), DB still has 3 rows', async () => {
108
+ const { enqueueEvent, replayQueue } = await import('../../src/core/queue/index.js');
109
+ const { SQLiteStorage } = await import('../../src/core/storage/sqlite.js');
110
+ const storage = new SQLiteStorage(dbPath);
111
+
112
+ const eventIds = [randomUUID(), randomUUID(), randomUUID()];
113
+ const events = eventIds.map((id, i) => ({
114
+ session_id: 'dedup-session',
115
+ project_path: '/tmp',
116
+ timestamp: new Date().toISOString(),
117
+ hook_type: 'Notification' as const,
118
+ event_id: id,
119
+ user_prompt: `prompt ${i}`,
120
+ }));
121
+
122
+ // First pass: enqueue + replay (all 3 enter DB)
123
+ for (const event of events) {
124
+ enqueueEvent(event);
125
+ }
126
+ const first = await replayQueue(storage);
127
+ expect(first.replayed).toBe(3);
128
+
129
+ // Queue is empty now. Re-enqueue the same events to simulate a second replay
130
+ for (const event of events) {
131
+ enqueueEvent(event);
132
+ }
133
+
134
+ // Second pass: all 3 should be skipped as duplicates
135
+ const second = await replayQueue(storage);
136
+ expect(second.skipped).toBe(3);
137
+ expect(second.replayed).toBe(0);
138
+
139
+ // DB still has exactly 3 events
140
+ const dbEvents = storage.queryEvents({ session_id: 'dedup-session' });
141
+ expect(dbEvents).toHaveLength(3);
142
+
143
+ storage.close();
144
+ });
145
+
146
+ it('dead-letters TTL-expired and corrupt files, replays valid ones', async () => {
147
+ const { enqueueEvent, replayQueue, TTL_DAYS } = await import('../../src/core/queue/index.js');
148
+ const { SQLiteStorage } = await import('../../src/core/storage/sqlite.js');
149
+ const storage = new SQLiteStorage(dbPath);
150
+
151
+ // Valid event
152
+ const validEvent = {
153
+ session_id: 'mixed-session',
154
+ project_path: '/tmp',
155
+ timestamp: new Date().toISOString(),
156
+ hook_type: 'UserPromptSubmit' as const,
157
+ user_prompt: 'valid',
158
+ event_id: randomUUID(),
159
+ };
160
+ enqueueEvent(validEvent);
161
+
162
+ // Corrupt JSON file
163
+ writeFileSync(join(queueDir, '2020-02-01T00-00-00-000Z-corrupt.json'), '{bad json]]');
164
+
165
+ // TTL-expired file (valid JSON but old mtime)
166
+ const oldEventPath = join(queueDir, '2000-01-01T00-00-00-000Z-expired.json');
167
+ writeFileSync(oldEventPath, JSON.stringify({
168
+ session_id: 'mixed-session',
169
+ project_path: '/tmp',
170
+ timestamp: '2000-01-01T00:00:00.000Z',
171
+ hook_type: 'Notification' as const,
172
+ event_id: randomUUID(),
173
+ }));
174
+ const pastTime = new Date(Date.now() - (TTL_DAYS + 2) * 24 * 60 * 60 * 1000);
175
+ utimesSync(oldEventPath, pastTime, pastTime);
176
+
177
+ const result = await replayQueue(storage);
178
+
179
+ expect(result.replayed).toBe(1);
180
+ expect(result.dead).toBe(2); // corrupt + expired
181
+ expect(result.skipped).toBe(0);
182
+
183
+ // dead-letter dir should have 2 files
184
+ const deadFiles = readdirSync(deadDir).filter((f) => f.endsWith('.json'));
185
+ expect(deadFiles).toHaveLength(2);
186
+
187
+ // queue is empty
188
+ const queueFiles = readdirSync(queueDir).filter((f) => f.endsWith('.json'));
189
+ expect(queueFiles).toHaveLength(0);
190
+
191
+ storage.close();
192
+ });
193
+ });