@winspan/claude-forge 8.50.6 → 8.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/CLAUDE.md +7 -7
  2. package/dist/claudemd/claudemd-generator.d.ts.map +1 -1
  3. package/dist/claudemd/claudemd-generator.js +27 -237
  4. package/dist/claudemd/claudemd-generator.js.map +1 -1
  5. package/dist/claudemd/resume-manager.js +1 -1
  6. package/dist/claudemd/resume-manager.js.map +1 -1
  7. package/dist/claudemd/templates/swarm-protocol.md +222 -0
  8. package/dist/cli/commands/daemon.js +6 -6
  9. package/dist/cli/commands/daemon.js.map +1 -1
  10. package/dist/cli/commands/executions.d.ts.map +1 -1
  11. package/dist/cli/commands/executions.js +4 -3
  12. package/dist/cli/commands/executions.js.map +1 -1
  13. package/dist/cli/commands/init.js +2 -2
  14. package/dist/cli/commands/init.js.map +1 -1
  15. package/dist/cli/commands/logs.js.map +1 -1
  16. package/dist/cli/commands/mcp.d.ts.map +1 -1
  17. package/dist/cli/commands/mcp.js +3 -5
  18. package/dist/cli/commands/mcp.js.map +1 -1
  19. package/dist/cli/commands/menu.d.ts.map +1 -1
  20. package/dist/cli/commands/menu.js +4 -3
  21. package/dist/cli/commands/menu.js.map +1 -1
  22. package/dist/cli/commands/stats.d.ts.map +1 -1
  23. package/dist/cli/commands/stats.js +2 -3
  24. package/dist/cli/commands/stats.js.map +1 -1
  25. package/dist/cli/commands/status.js +2 -2
  26. package/dist/cli/commands/status.js.map +1 -1
  27. package/dist/cli/commands/trace.d.ts.map +1 -1
  28. package/dist/cli/commands/trace.js +11 -23
  29. package/dist/cli/commands/trace.js.map +1 -1
  30. package/dist/cli/init/hook-manager.d.ts.map +1 -1
  31. package/dist/cli/init/hook-manager.js +2 -2
  32. package/dist/cli/init/hook-manager.js.map +1 -1
  33. package/dist/core/ai/provider.js +2 -2
  34. package/dist/core/ai/provider.js.map +1 -1
  35. package/dist/core/constants.d.ts +12 -1
  36. package/dist/core/constants.d.ts.map +1 -1
  37. package/dist/core/constants.js +15 -1
  38. package/dist/core/constants.js.map +1 -1
  39. package/dist/core/event-fields.d.ts +16 -0
  40. package/dist/core/event-fields.d.ts.map +1 -0
  41. package/dist/core/event-fields.js +19 -0
  42. package/dist/core/event-fields.js.map +1 -0
  43. package/dist/core/queue/index.d.ts.map +1 -1
  44. package/dist/core/queue/index.js +3 -4
  45. package/dist/core/queue/index.js.map +1 -1
  46. package/dist/core/storage/base.d.ts +36 -3
  47. package/dist/core/storage/base.d.ts.map +1 -1
  48. package/dist/core/storage/base.js +101 -58
  49. package/dist/core/storage/base.js.map +1 -1
  50. package/dist/core/storage/events.d.ts +92 -3
  51. package/dist/core/storage/events.d.ts.map +1 -1
  52. package/dist/core/storage/events.js +147 -0
  53. package/dist/core/storage/events.js.map +1 -1
  54. package/dist/core/storage/routing.d.ts +54 -1
  55. package/dist/core/storage/routing.d.ts.map +1 -1
  56. package/dist/core/storage/routing.js +99 -1
  57. package/dist/core/storage/routing.js.map +1 -1
  58. package/dist/core/storage/schema.sql +12 -2
  59. package/dist/core/storage/sessions.d.ts +20 -0
  60. package/dist/core/storage/sessions.d.ts.map +1 -1
  61. package/dist/core/storage/sessions.js +59 -0
  62. package/dist/core/storage/sessions.js.map +1 -1
  63. package/dist/core/storage/skills.d.ts +23 -0
  64. package/dist/core/storage/skills.d.ts.map +1 -1
  65. package/dist/core/storage/skills.js +47 -0
  66. package/dist/core/storage/skills.js.map +1 -1
  67. package/dist/core/storage/sqlite.d.ts +35 -2
  68. package/dist/core/storage/sqlite.d.ts.map +1 -1
  69. package/dist/core/storage/sqlite.js +93 -4
  70. package/dist/core/storage/sqlite.js.map +1 -1
  71. package/dist/core/storage/tasks.d.ts +49 -0
  72. package/dist/core/storage/tasks.d.ts.map +1 -1
  73. package/dist/core/storage/tasks.js +143 -1
  74. package/dist/core/storage/tasks.js.map +1 -1
  75. package/dist/core/storage/token-usage.d.ts +1 -1
  76. package/dist/core/storage/token-usage.d.ts.map +1 -1
  77. package/dist/core/storage/token-usage.js +1 -1
  78. package/dist/core/storage/token-usage.js.map +1 -1
  79. package/dist/core/types.d.ts +24 -3
  80. package/dist/core/types.d.ts.map +1 -1
  81. package/dist/core/types.js.map +1 -1
  82. package/dist/core/utils/error-handler.d.ts.map +1 -1
  83. package/dist/core/utils/error-handler.js +3 -2
  84. package/dist/core/utils/error-handler.js.map +1 -1
  85. package/dist/core/utils/git.d.ts +10 -0
  86. package/dist/core/utils/git.d.ts.map +1 -0
  87. package/dist/core/utils/git.js +24 -0
  88. package/dist/core/utils/git.js.map +1 -0
  89. package/dist/core/utils/logger.d.ts.map +1 -1
  90. package/dist/core/utils/logger.js +15 -1
  91. package/dist/core/utils/logger.js.map +1 -1
  92. package/dist/core/utils/lru-cache.d.ts +1 -0
  93. package/dist/core/utils/lru-cache.d.ts.map +1 -1
  94. package/dist/core/utils/lru-cache.js +3 -0
  95. package/dist/core/utils/lru-cache.js.map +1 -1
  96. package/dist/core/utils/token-tracker.js +1 -1
  97. package/dist/core/utils/token-tracker.js.map +1 -1
  98. package/dist/daemon/event-parser.d.ts.map +1 -1
  99. package/dist/daemon/event-parser.js +2 -1
  100. package/dist/daemon/event-parser.js.map +1 -1
  101. package/dist/daemon/handlers/history-exporter.js.map +1 -1
  102. package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
  103. package/dist/daemon/handlers/post-tool-use.js +7 -3
  104. package/dist/daemon/handlers/post-tool-use.js.map +1 -1
  105. package/dist/daemon/handlers/stop.d.ts +4 -0
  106. package/dist/daemon/handlers/stop.d.ts.map +1 -1
  107. package/dist/daemon/handlers/stop.js +23 -35
  108. package/dist/daemon/handlers/stop.js.map +1 -1
  109. package/dist/daemon/handlers/user-prompt.d.ts +3 -3
  110. package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
  111. package/dist/daemon/handlers/user-prompt.js +12 -22
  112. package/dist/daemon/handlers/user-prompt.js.map +1 -1
  113. package/dist/daemon/index.d.ts.map +1 -1
  114. package/dist/daemon/index.js +23 -9
  115. package/dist/daemon/index.js.map +1 -1
  116. package/dist/daemon/lifecycle.js +3 -4
  117. package/dist/daemon/lifecycle.js.map +1 -1
  118. package/dist/daemon/server.d.ts +6 -4
  119. package/dist/daemon/server.d.ts.map +1 -1
  120. package/dist/daemon/server.js +76 -85
  121. package/dist/daemon/server.js.map +1 -1
  122. package/dist/daemon/services/task-segmenter.js +1 -1
  123. package/dist/daemon/services/task-segmenter.js.map +1 -1
  124. package/dist/hooks/hook-lib.sh +37 -0
  125. package/dist/hooks/notification.sh +2 -2
  126. package/dist/hooks/post-tool-use.sh +2 -2
  127. package/dist/hooks/pre-tool-use.sh +2 -2
  128. package/dist/hooks/stop.sh +9 -6
  129. package/dist/hooks/user-prompt-submit.sh +2 -2
  130. package/dist/{daemon/services → web/analytics}/anti-pattern-detector.d.ts +3 -4
  131. package/dist/web/analytics/anti-pattern-detector.d.ts.map +1 -0
  132. package/dist/{daemon/services → web/analytics}/anti-pattern-detector.js +7 -46
  133. package/dist/{daemon/services → web/analytics}/anti-pattern-detector.js.map +1 -1
  134. package/dist/web/analytics/drift-detector.d.ts.map +1 -0
  135. package/dist/{daemon/services → web/analytics}/drift-detector.js +10 -13
  136. package/dist/web/analytics/drift-detector.js.map +1 -0
  137. package/dist/web/analytics/weekly-report.d.ts.map +1 -0
  138. package/dist/{daemon/services → web/analytics}/weekly-report.js +51 -50
  139. package/dist/web/analytics/weekly-report.js.map +1 -0
  140. package/dist/web/auth-middleware.d.ts.map +1 -1
  141. package/dist/web/auth-middleware.js +1 -2
  142. package/dist/web/auth-middleware.js.map +1 -1
  143. package/dist/web/routes/_helpers.d.ts +16 -0
  144. package/dist/web/routes/_helpers.d.ts.map +1 -0
  145. package/dist/web/routes/_helpers.js +32 -0
  146. package/dist/web/routes/_helpers.js.map +1 -0
  147. package/dist/web/routes/drift.js +1 -1
  148. package/dist/web/routes/drift.js.map +1 -1
  149. package/dist/web/routes/insights.js +1 -1
  150. package/dist/web/routes/insights.js.map +1 -1
  151. package/dist/web/routes/reports.js +1 -1
  152. package/dist/web/routes/reports.js.map +1 -1
  153. package/dist/web/routes/rules.d.ts +3 -0
  154. package/dist/web/routes/rules.d.ts.map +1 -1
  155. package/dist/web/routes/rules.js +28 -52
  156. package/dist/web/routes/rules.js.map +1 -1
  157. package/dist/web/routes/sessions.d.ts.map +1 -1
  158. package/dist/web/routes/sessions.js +16 -30
  159. package/dist/web/routes/sessions.js.map +1 -1
  160. package/dist/web/routes/skill-stats.d.ts +2 -0
  161. package/dist/web/routes/skill-stats.d.ts.map +1 -1
  162. package/dist/web/routes/skill-stats.js +28 -64
  163. package/dist/web/routes/skill-stats.js.map +1 -1
  164. package/dist/web/routes/skills.d.ts.map +1 -1
  165. package/dist/web/routes/skills.js +5 -4
  166. package/dist/web/routes/skills.js.map +1 -1
  167. package/dist/web/routes/stats.d.ts +4 -0
  168. package/dist/web/routes/stats.d.ts.map +1 -1
  169. package/dist/web/routes/stats.js +19 -21
  170. package/dist/web/routes/stats.js.map +1 -1
  171. package/dist/web/routes/tasks.d.ts.map +1 -1
  172. package/dist/web/routes/tasks.js +17 -42
  173. package/dist/web/routes/tasks.js.map +1 -1
  174. package/dist/web/routes/trace.d.ts.map +1 -1
  175. package/dist/web/routes/trace.js +7 -17
  176. package/dist/web/routes/trace.js.map +1 -1
  177. package/dist/web/routes/types.d.ts.map +1 -1
  178. package/dist/web/routes/types.js +4 -3
  179. package/dist/web/routes/types.js.map +1 -1
  180. package/dist/web/static/assets/{AIConfig-BQCAQE9D.js → AIConfig-CdDWzJyO.js} +2 -2
  181. package/dist/web/static/assets/{AIConfig-BQCAQE9D.js.map → AIConfig-CdDWzJyO.js.map} +1 -1
  182. package/dist/web/static/assets/{Dashboard-D7Bo6Kan.js → Dashboard-CoEmmIDt.js} +2 -2
  183. package/dist/web/static/assets/{Dashboard-D7Bo6Kan.js.map → Dashboard-CoEmmIDt.js.map} +1 -1
  184. package/dist/web/static/assets/{Drawer-BeHRQxUS.js → Drawer-DdRTzlLB.js} +2 -2
  185. package/dist/web/static/assets/{Drawer-BeHRQxUS.js.map → Drawer-DdRTzlLB.js.map} +1 -1
  186. package/dist/web/static/assets/{Events-K_tCY2ti.js → Events-DrIq1SUS.js} +2 -2
  187. package/dist/web/static/assets/{Events-K_tCY2ti.js.map → Events-DrIq1SUS.js.map} +1 -1
  188. package/dist/web/static/assets/{Reports-BJCmBnc_.js → Reports-DFBM3MDK.js} +2 -2
  189. package/dist/web/static/assets/{Reports-BJCmBnc_.js.map → Reports-DFBM3MDK.js.map} +1 -1
  190. package/dist/web/static/assets/{SearchInput-BX2KhMkw.js → SearchInput-qCj_jAcf.js} +2 -2
  191. package/dist/web/static/assets/{SearchInput-BX2KhMkw.js.map → SearchInput-qCj_jAcf.js.map} +1 -1
  192. package/dist/web/static/assets/{SessionDetail-Bkr-kC7V.js → SessionDetail-CCzwdoT7.js} +2 -2
  193. package/dist/web/static/assets/{SessionDetail-Bkr-kC7V.js.map → SessionDetail-CCzwdoT7.js.map} +1 -1
  194. package/dist/web/static/assets/{Sessions-Chx9OCLH.js → Sessions-FfLYkAw9.js} +2 -2
  195. package/dist/web/static/assets/{Sessions-Chx9OCLH.js.map → Sessions-FfLYkAw9.js.map} +1 -1
  196. package/dist/web/static/assets/{Skills-O0GT1i7m.js → Skills-C8Gvs3Qa.js} +2 -2
  197. package/dist/web/static/assets/{Skills-O0GT1i7m.js.map → Skills-C8Gvs3Qa.js.map} +1 -1
  198. package/dist/web/static/assets/TaskDetail-BS8pYhaR.js +2 -0
  199. package/dist/web/static/assets/TaskDetail-BS8pYhaR.js.map +1 -0
  200. package/dist/web/static/assets/Tasks-CyuhizG8.js +2 -0
  201. package/dist/web/static/assets/Tasks-CyuhizG8.js.map +1 -0
  202. package/dist/web/static/assets/index-CBX47X8l.js +3 -0
  203. package/dist/web/static/assets/{index-DxIbmNmr.js.map → index-CBX47X8l.js.map} +1 -1
  204. package/dist/web/static/assets/index-DjIoMdoR.css +1 -0
  205. package/dist/web/static/assets/{lucide-fJlPI3H7.js → lucide-Bs_edTLa.js} +44 -39
  206. package/dist/web/static/assets/lucide-Bs_edTLa.js.map +1 -0
  207. package/dist/web/static/assets/react-router-r79dBVy4.js +20 -0
  208. package/dist/web/static/assets/{react-router-I-HqunH7.js.map → react-router-r79dBVy4.js.map} +1 -1
  209. package/dist/web/static/assets/task-title-BhOcemuR.js +2 -0
  210. package/dist/web/static/assets/task-title-BhOcemuR.js.map +1 -0
  211. package/dist/web/static/index.html +4 -4
  212. package/docs/design/h1-storage-aggregation-spec-20260518-1121.md +299 -0
  213. package/docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md +191 -0
  214. package/docs/design/h3-fallback-removal-spec-20260518-1245.md +76 -0
  215. package/docs/design/h4-index-dedup-spec-20260518-1230.md +109 -0
  216. package/docs/design/h6-services-migration-spec-20260518-1355.md +82 -0
  217. package/docs/design/l1-swarm-protocol-extract-spec-20260518-1605.md +106 -0
  218. package/docs/design/m10-forge-paths-spec-20260518-1320.md +121 -0
  219. package/docs/design/m2-m3-tool-input-spec-20260518-1425.md +131 -0
  220. package/docs/design/m7-routing-event-association-spec-20260518-1545.md +103 -0
  221. package/docs/design/project-path-gitroot-spec-20260518-1715.md +134 -0
  222. package/docs/design/task-active-gc-spec-20260518-1745.md +146 -0
  223. package/docs/implementation/h1-storage-aggregation-changelog-20260518-1121.md +82 -0
  224. package/docs/implementation/h2-final-changelog-20260518-1530.md +61 -0
  225. package/docs/implementation/h2-phase1-safety-net-changelog-20260518-1450.md +70 -0
  226. package/docs/implementation/h2-phase2-operations-changelog-20260518-1450.md +120 -0
  227. package/docs/implementation/h2-phase3-callsites-changelog-20260518-1450.md +71 -0
  228. package/docs/implementation/h3-fallback-removal-changelog-20260518-1245.md +71 -0
  229. package/docs/implementation/h4-index-dedup-changelog-20260518-1230.md +60 -0
  230. package/docs/implementation/h6-services-migration-changelog-20260518-1355.md +46 -0
  231. package/docs/implementation/h7-m9-defaults-changelog-20260518-1300.md +46 -0
  232. package/docs/implementation/l1-swarm-protocol-extract-changelog-20260518-1605.md +45 -0
  233. package/docs/implementation/l3-l4-daemon-perf-changelog-20260518-1410.md +63 -0
  234. package/docs/implementation/l6-l8-final-cleanup-changelog-20260518-1640.md +38 -0
  235. package/docs/implementation/m1-m4-m5-l7-cleanup-changelog-20260518-1310.md +58 -0
  236. package/docs/implementation/m10-forge-paths-changelog-20260518-1320.md +60 -0
  237. package/docs/implementation/m2-m3-tool-input-changelog-20260518-1425.md +43 -0
  238. package/docs/implementation/m6-m8-naming-shutdown-changelog-20260518-1340.md +56 -0
  239. package/docs/implementation/m7-routing-association-changelog-20260518-1545.md +69 -0
  240. package/docs/implementation/project-path-gitroot-changelog-20260518-1715.md +63 -0
  241. package/docs/implementation/task-active-gc-changelog-20260518-1745.md +35 -0
  242. package/docs/implementation/task-title-summary-changelog-20260518-1130.md +39 -0
  243. package/docs/implementation/tasks-detail-back-loses-filters-changelog-20260518-1100.md +22 -0
  244. package/docs/implementation/tasks-page-white-screen-hotfix-changelog-20260518-1015.md +56 -0
  245. package/docs/reviews/task-title-summary.md +92 -0
  246. package/docs/reviews/tasks-detail-back-loses-filters.md +58 -0
  247. package/docs/reviews/tasks-page-white-screen-hotfix.md +126 -0
  248. package/package.json +2 -2
  249. package/src/claudemd/claudemd-generator.ts +29 -238
  250. package/src/claudemd/resume-manager.ts +1 -1
  251. package/src/claudemd/templates/swarm-protocol.md +222 -0
  252. package/src/cli/commands/daemon.ts +6 -6
  253. package/src/cli/commands/executions.ts +4 -3
  254. package/src/cli/commands/init.ts +2 -2
  255. package/src/cli/commands/logs.ts +1 -1
  256. package/src/cli/commands/mcp.ts +3 -5
  257. package/src/cli/commands/menu.ts +4 -3
  258. package/src/cli/commands/stats.ts +2 -3
  259. package/src/cli/commands/status.ts +2 -2
  260. package/src/cli/commands/trace.ts +10 -26
  261. package/src/cli/init/hook-manager.ts +2 -2
  262. package/src/core/ai/provider.ts +2 -2
  263. package/src/core/constants.ts +18 -1
  264. package/src/core/event-fields.ts +32 -0
  265. package/src/core/queue/index.ts +3 -4
  266. package/src/core/storage/base.ts +132 -56
  267. package/src/core/storage/events.ts +183 -4
  268. package/src/core/storage/routing.ts +129 -1
  269. package/src/core/storage/schema.sql +12 -2
  270. package/src/core/storage/sessions.ts +64 -0
  271. package/src/core/storage/skills.ts +69 -0
  272. package/src/core/storage/sqlite.ts +103 -4
  273. package/src/core/storage/tasks.ts +149 -1
  274. package/src/core/storage/token-usage.ts +1 -1
  275. package/src/core/types.ts +30 -3
  276. package/src/core/utils/error-handler.ts +3 -2
  277. package/src/core/utils/git.ts +23 -0
  278. package/src/core/utils/logger.ts +16 -1
  279. package/src/core/utils/lru-cache.ts +4 -0
  280. package/src/core/utils/token-tracker.ts +1 -1
  281. package/src/daemon/event-parser.ts +4 -3
  282. package/src/daemon/handlers/history-exporter.ts +1 -1
  283. package/src/daemon/handlers/post-tool-use.ts +7 -3
  284. package/src/daemon/handlers/stop.ts +32 -39
  285. package/src/daemon/handlers/user-prompt.ts +12 -22
  286. package/src/daemon/index.ts +24 -10
  287. package/src/daemon/lifecycle.ts +3 -3
  288. package/src/daemon/server.ts +76 -89
  289. package/src/daemon/services/task-segmenter.ts +1 -1
  290. package/src/hooks/hook-lib.sh +37 -0
  291. package/src/hooks/notification.sh +2 -2
  292. package/src/hooks/post-tool-use.sh +2 -2
  293. package/src/hooks/pre-tool-use.sh +2 -2
  294. package/src/hooks/stop.sh +9 -6
  295. package/src/hooks/user-prompt-submit.sh +2 -2
  296. package/src/{daemon/services → web/analytics}/anti-pattern-detector.ts +9 -54
  297. package/src/{daemon/services → web/analytics}/drift-detector.ts +10 -23
  298. package/src/{daemon/services → web/analytics}/weekly-report.ts +52 -75
  299. package/src/web/auth-middleware.ts +1 -2
  300. package/src/web/routes/_helpers.ts +34 -0
  301. package/src/web/routes/drift.ts +1 -1
  302. package/src/web/routes/insights.ts +1 -1
  303. package/src/web/routes/reports.ts +1 -1
  304. package/src/web/routes/rules.ts +31 -56
  305. package/src/web/routes/sessions.ts +18 -30
  306. package/src/web/routes/skill-stats.ts +29 -69
  307. package/src/web/routes/skills.ts +5 -4
  308. package/src/web/routes/stats.ts +19 -29
  309. package/src/web/routes/tasks.ts +17 -42
  310. package/src/web/routes/trace.ts +7 -19
  311. package/src/web/routes/types.ts +4 -3
  312. package/tests/integration/claudemd-generator.test.ts +90 -0
  313. package/tests/integration/web-analytics.integration.test.ts +133 -0
  314. package/tests/integration/web-stats.integration.test.ts +135 -0
  315. package/tests/integration/web-trace.integration.test.ts +175 -0
  316. package/tests/unit/core/forge-paths.test.ts +99 -0
  317. package/tests/unit/daemon/post-tool-use.test.ts +121 -0
  318. package/tests/unit/daemon/stop-handler-behavior-summary.test.ts +202 -0
  319. package/tests/unit/daemon/task-segmenter-recover.test.ts +84 -0
  320. package/tests/unit/event-fields.test.ts +88 -0
  321. package/tests/unit/event-parser.test.ts +55 -0
  322. package/tests/unit/hooks/resolve-project-path.test.ts +122 -0
  323. package/tests/unit/socket-server.test.ts +183 -0
  324. package/tests/unit/storage/event-operations-aggregates.test.ts +342 -0
  325. package/tests/unit/storage/migration-idempotent.test.ts +304 -0
  326. package/tests/unit/storage/routing-aggregates.test.ts +276 -0
  327. package/tests/unit/storage/routing.test.ts +117 -0
  328. package/tests/unit/storage/schema-missing.test.ts +81 -0
  329. package/tests/unit/storage/session-operations-aggregates.test.ts +120 -0
  330. package/tests/unit/storage/skill-operations-counts.test.ts +106 -0
  331. package/tests/unit/storage/skills-aggregates.test.ts +104 -0
  332. package/tests/unit/storage/sqlite-refactor-harness.test.ts +3 -3
  333. package/tests/unit/storage/task-operations-counts.test.ts +46 -0
  334. package/tests/unit/storage/tasks-getById.test.ts +343 -0
  335. package/tests/unit/storage/tasks-stale-gc.test.ts +86 -0
  336. package/tests/unit/token-usage.test.ts +6 -6
  337. package/tests/unit/web/navigation-back-contract.test.ts +134 -0
  338. package/tests/unit/web/routes-rules.test.ts +182 -0
  339. package/tests/unit/web/routes-tasks.test.ts +34 -0
  340. package/tests/unit/web/task-title-contract.test.ts +210 -0
  341. package/tests/unit/web/tasks-component-contract.test.ts +179 -0
  342. package/vitest.config.ts +1 -1
  343. package/web/src/pages/TaskDetail.tsx +9 -5
  344. package/web/src/pages/Tasks.tsx +315 -50
  345. package/web/src/utils/navigation.ts +25 -0
  346. package/web/src/utils/task-title.ts +49 -0
  347. package/dist/daemon/services/anti-pattern-detector.d.ts.map +0 -1
  348. package/dist/daemon/services/drift-detector.d.ts.map +0 -1
  349. package/dist/daemon/services/drift-detector.js.map +0 -1
  350. package/dist/daemon/services/weekly-report.d.ts.map +0 -1
  351. package/dist/daemon/services/weekly-report.js.map +0 -1
  352. package/dist/web/static/assets/TaskDetail-5SR8zGzv.js +0 -2
  353. package/dist/web/static/assets/TaskDetail-5SR8zGzv.js.map +0 -1
  354. package/dist/web/static/assets/Tasks-DCgDqvOZ.js +0 -2
  355. package/dist/web/static/assets/Tasks-DCgDqvOZ.js.map +0 -1
  356. package/dist/web/static/assets/index-D8AKj26b.css +0 -1
  357. package/dist/web/static/assets/index-DxIbmNmr.js +0 -3
  358. package/dist/web/static/assets/lucide-fJlPI3H7.js.map +0 -1
  359. package/dist/web/static/assets/react-router-I-HqunH7.js +0 -20
  360. /package/dist/{daemon/services → web/analytics}/drift-detector.d.ts +0 -0
  361. /package/dist/{daemon/services → web/analytics}/weekly-report.d.ts +0 -0
@@ -0,0 +1,71 @@
1
+ # H2 Phase 3 替换调用方 Changelog
2
+
3
+ **Date**: 2026-05-18 14:50 (Phase 3)
4
+ **Spec**: docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md
5
+ **Status**: Phase 3 完成(Phase 4 待 getDatabase jsdoc)
6
+
7
+ ## 完成清单
8
+
9
+ - [x] `src/web/routes/stats.ts` — 5 段 SQL → `countAllEvents` / `countAllSessions` / `aggregateToolUsage` / `aggregateDailyEventCounts` / `aggregateDailySessionCounts` / `countAllSkillInvocations`
10
+ - [x] `src/web/routes/trace.ts` — 3 段 SQL → `aggregateHookTypeBySession` / `aggregateAgentTypeBySession` / `queryDistinctSkillIdsBySession`
11
+ - [x] `src/cli/commands/trace.ts` — 3 段 SQL(同 trace.ts 模式)+ 函数签名清理(移除 db 参数)
12
+ - [x] `src/daemon/handlers/stop.ts` — 3 段 SQL → `aggregateToolUsageBySession` / `aggregateAgentTypeBySession` / `countSkillInvocationsBySession`
13
+ - [x] `src/web/analytics/drift-detector.ts` — 4 段 SQL → `countDistinctSkillsSince` / `countActiveDays` / `countSessionsByRange` / `countTasksByRange`
14
+ - [x] `src/web/analytics/weekly-report.ts` — 6 段 SQL → `aggregateOverviewByRange` / `queryDistinctProjects` / `countTasksByRange` / `queryEventsByTimeRange` (内存聚合 tool) / `aggregateToolFailureRate` / `queryFileEditInputs`
15
+ - [x] `src/web/analytics/anti-pattern-detector.ts` — 2 段 SQL → `queryEventsByTimeRange` / `querySessionsByTimeRange`,附带删除无用 `safeParse` helper
16
+
17
+ ## 测试结果
18
+
19
+ | 测试套件 | 结果 |
20
+ |---|---|
21
+ | `tests/integration/web-stats.integration.test.ts` | 4/4 通过 |
22
+ | `tests/integration/web-trace.integration.test.ts` | 6/6 通过 |
23
+ | `tests/unit/daemon/stop-handler-behavior-summary.test.ts` | 5/5 通过 |
24
+ | `tests/integration/web-analytics.integration.test.ts` | 5/5 通过 |
25
+ | `npx tsc --noEmit` | 0 errors |
26
+ | `npm test`(全量) | 541 passed / 1 failed(pre-existing:`linkEventToTask`) |
27
+
28
+ ## 残留 db.prepare 检查
29
+
30
+ `grep -rn "db\.prepare\|getDatabase().prepare" src/web/routes/ src/web/analytics/ src/cli/commands/trace.ts src/daemon/handlers/ --include="*.ts" | grep -v ".test."` 输出:
31
+
32
+ ```
33
+ src/web/routes/stats.ts:7: * H2 Phase 3: 替换原 db.prepare 直写 SQL 为 SQLiteStorage facade 聚合方法。
34
+ src/web/routes/trace.ts:95: // H2 Phase 3: 改用 facade 聚合方法,消除 db.prepare 直写。
35
+ src/daemon/handlers/stop.ts:151: // H2 Phase 3: 改用 facade 聚合方法,消除 db.prepare 直写。
36
+ ```
37
+
38
+ 仅剩 3 处提到 `db.prepare` 的注释,**无实际 SQL 直写调用**。Phase 3 目标达成。
39
+
40
+ ## 超出 spec 改动
41
+
42
+ 1. **CLI trace 函数签名清理**:`printSessionTrace(storage, db, sessionId)` → `printSessionTrace(storage, sessionId)`,因 db 参数已无引用方。属于伴生改动,非业务逻辑变更。
43
+ 2. **anti-pattern-detector 删除 `safeParse`**:原函数仅在 `queryEventsSince` 旧实现中使用,迁移到 `queryEventsByTimeRange` 后已不再需要(events.ts 的 `rowToEvent` 内部完成 JSON 解析)。属于死代码清理。
44
+
45
+ ## Phase 2 vs 实际签名偏差(重要)
46
+
47
+ **`aggregateToolUsage` 缺 `until` 参数**:
48
+ - spec 设计:`aggregateToolUsage(opts: { since, until, hook_type, limit })`
49
+ - Phase 2 实现:`aggregateToolUsage(opts: { since?, hook_type?, limit? })`,**缺 `until`**
50
+
51
+ **影响**:`weekly-report.ts:aggregateTools` 需要 `[since, until)` 半开区间过滤(历史周不应混入下一周事件)。
52
+
53
+ **临时处理**:改用 `queryEventsByTimeRange({ since, until })` + JS 内存聚合 PreToolUse + tool_name。语义正确,但比专门聚合 SQL 多一次行映射。
54
+
55
+ **建议**:Phase 4 之后若有 H3,可考虑给 `aggregateToolUsage` 补 `until`,或新增 `aggregateToolUsageByRange`。当前不阻塞 Phase 3。
56
+
57
+ ## 关键设计决策
58
+
59
+ 1. **时间窗口 ISO 字符串化**:旧 SQL 用 `date('now', '-7 days')` SQLite 日期函数。新口径统一调用方计算 `new Date(Date.now() - N * 86400000).toISOString()` 后传 facade。在 `stats.ts` / `drift-detector.ts` 两处沿用此模式。
60
+ 2. **保留响应 shape**:所有路由响应字段名(toolUsage / dailyActivity / event_breakdown 等)完全不变,只把内部 `cnt` 字段名换成 facade 返回的 `count`,前端契约 0 改动。
61
+ 3. **failure 检测三条 LIKE 分支保留**:通过 `aggregateToolFailureRate` 内部封装 `'%"error"%' OR '%"is_error":true%' OR '%"isError":true%'`,行为与旧 SQL 完全一致。
62
+
63
+ ## 已知问题
64
+
65
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > Task Operations > linkEventToTask associates events with tasks` — **pre-existing 失败**(UUID 校验问题,与 Phase 3 无关)
66
+
67
+ ## Phase 4 待办
68
+
69
+ - `getDatabase()` 加 jsdoc `@internal` 警告(spec §「方案选择」与 Phase 4 计划)
70
+ - 跑全量 tsc + npm test 二次确认
71
+ - 可选:CLAUDE.md 「常见陷阱」补 1 条「越权 SQL 必须走 facade」
@@ -0,0 +1,71 @@
1
+ # H3 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 12:45
4
+ **Spec**: docs/design/h3-fallback-removal-spec-20260518-1245.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+
9
+ - [x] `src/core/storage/base.ts` `initSchema()` 删除 inline fallback + fail-fast
10
+ - [x] `src/core/storage/base.ts` 文件头注释清理("或 inline fallback" → "缺失则抛错")
11
+ - [x] `package.json` build script 末尾追加 `test -f dist/core/storage/schema.sql` 校验
12
+ - [x] `tests/unit/storage/schema-missing.test.ts` 新增 2 个 case
13
+
14
+ ## 关键代码定位
15
+
16
+ - `src/core/storage/base.ts:6` — 文件头注释:"加载 schema.sql(缺失则抛错)"
17
+ - `src/core/storage/base.ts:61-73` — `initSchema()` 重写:`existsSync` 缺失 → 抛 Error;不再有 else fallback 分支
18
+ - `package.json:13` — build script 末尾:`&& (test -f dist/core/storage/schema.sql || (echo '[build] FATAL: dist/core/storage/schema.sql missing' && exit 1))`
19
+ - `tests/unit/storage/schema-missing.test.ts:1-83` — 新测试文件
20
+
21
+ ## 设计要点
22
+
23
+ ### initSchema 行为变化
24
+
25
+ **旧**:
26
+ ```ts
27
+ if (existsSync(schemaPath)) {
28
+ // 读取并 exec schema.sql
29
+ } else {
30
+ // inline fallback:只建 events 表 + 4 个旧索引
31
+ }
32
+ ```
33
+
34
+ **新**:
35
+ ```ts
36
+ if (!existsSync(schemaPath)) {
37
+ throw new Error('[SQLiteStorage] schema.sql not found at ${schemaPath}. ...');
38
+ }
39
+ const schema = readFileSync(schemaPath, 'utf-8');
40
+ this.db.exec(schema);
41
+ ```
42
+
43
+ 错误信息含修复建议:`Run \`npm run build\` or reinstall the package.`
44
+
45
+ ### 测试 mock 策略
46
+
47
+ `tests/unit/storage/schema-missing.test.ts` case 2 使用 `vi.doMock('node:fs', ...)` + 动态 `import()`:
48
+
49
+ - 只让 `existsSync` 在路径以 `schema.sql` 结尾时返回 false
50
+ - 其他路径(如 mkdir 时的目录检查)保留真实行为,避免破坏构造函数的目录创建逻辑
51
+ - 每个 case 后 `vi.doUnmock` + `vi.resetModules` 防止跨 case 污染
52
+
53
+ ### Build 校验
54
+
55
+ `(test -f dist/core/storage/schema.sql || (echo '[build] FATAL:...' && exit 1))` 在所有 cp 步骤之后跑,捕获 schema.sql 漏拷贝场景。括号子 shell 形式确保 `||` 短路 + 显式 exit 1。
56
+
57
+ ## 测试结果
58
+
59
+ - 新增 `schema-missing.test.ts`:**2 / 2 passed**
60
+ - 现有 `tests/unit/storage/`:**60 / 61 passed**(仅 pre-existing `linkEventToTask` 失败)
61
+ - `npx tsc --noEmit`:**0 errors**
62
+ - `npm test`:**423 / 424 passed**(仅 pre-existing `linkEventToTask`)
63
+ - `npm run build`:**成功**(dist/core/storage/schema.sql 存在,校验通过)
64
+
65
+ ## 超出 spec 改动
66
+
67
+ 无。严格按 spec 改了 base.ts、package.json、新增 1 个测试文件。
68
+
69
+ ## 已知问题
70
+
71
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` — pre-existing failure(事件 UUID 校验失败),与本次 H3 改动无关,spec 明确豁免
@@ -0,0 +1,60 @@
1
+ # H4 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 12:30
4
+ **Spec**: docs/design/h4-index-dedup-spec-20260518-1230.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+
9
+ - [x] schema.sql 补 2 索引:`idx_skill_invocations_workflow` / `idx_skill_invocations_feature`
10
+ - [x] base.ts 加 `hasTable` / `hasIndex` 工具
11
+ - [x] base.ts 加 `createIndexIfMissing` 私有工具(hasIndex 守护 + debug 日志)
12
+ - [x] `runMigrations` 拆为 `runColumnMigrations` / `runIndexMigrations` / `runPostMigrations`
13
+ - [x] 列 migration 提前到 `initSchema()` 之前(修复 schema.sql 索引引用未存在列的回归)
14
+ - [x] 索引 migration(10 处)全部用 `createIndexIfMissing` 守护
15
+ - [x] 新增测试 `tests/unit/storage/migration-idempotent.test.ts`(4 case)
16
+
17
+ ## 关键代码定位
18
+
19
+ - `src/core/storage/schema.sql:220-222` — 新增 `idx_skill_invocations_workflow` / `idx_skill_invocations_feature`
20
+ - `src/core/storage/base.ts:46-60` — 构造函数调整为 `runColumnMigrations → initSchema → runIndexMigrations → runPostMigrations`
21
+ - `src/core/storage/base.ts:87-96` — 新增 `hasTable` 工具
22
+ - `src/core/storage/base.ts:107-121` — `addColumnIfMissing` 加 `hasTable` 短路(避免新库时 PRAGMA 噪音)
23
+ - `src/core/storage/base.ts:123-137` — `hasIndex` 工具(按 spec 第 4 节实现)
24
+ - `src/core/storage/base.ts:139-153` — `createIndexIfMissing` 私有工具(hasIndex 守护 + debug 日志)
25
+ - `src/core/storage/base.ts:155-171` — `runColumnMigrations`(7 处 addColumnIfMissing)
26
+ - `src/core/storage/base.ts:173-227` — `runIndexMigrations`(10 处 createIndexIfMissing)
27
+ - `src/core/storage/base.ts:232-244` — `runPostMigrations`(backfill + drop deprecated)
28
+ - `tests/unit/storage/migration-idempotent.test.ts` — 新增 4 个 case
29
+
30
+ ## 测试结果
31
+
32
+ - **新增测试**:`migration-idempotent.test.ts` 4/4 passed
33
+ - `baseline (缺索引)`:老库缺所有 migration 索引 → 启动后全部补齐
34
+ - `baseline (缺列)`:老库缺 `sessions.first_prompt` → ALTER 补齐
35
+ - `新库无害`:完整 schema.sql 初始化后再 new SQLiteStorage → 不重复 CREATE INDEX(debug 日志为 0 次"migration created",无 warn/error)
36
+ - `idempotent`:连续 3 次 new SQLiteStorage → 索引/列集合完全一致
37
+ - **storage 全模块**:`tests/unit/storage/` 58 passed / 1 pre-existing failed
38
+ - **tsc**:0 errors
39
+ - **npm test 全量**:421 passed / 1 failed
40
+ - 唯一失败:`tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask associates events with tasks` — pre-existing,与 H4 改动无关
41
+
42
+ ## 超出 spec 改动
43
+
44
+ 1. **构造函数顺序调整**:`runColumnMigrations` 提到 `initSchema` 之前。
45
+ - **原因**:spec 第 1 步要求把 `idx_skill_invocations_workflow ON skill_invocations(workflow, phase)` 放进 schema.sql。但 base.ts 原本顺序是 `initSchema → runMigrations`,对于"老库(无 workflow 列)"场景,`initSchema` 跑 schema.sql 时 `CREATE TABLE IF NOT EXISTS skill_invocations` 跳过老表(不会补列),随后 `CREATE INDEX ... ON skill_invocations(workflow, phase)` 即报 `no such column: workflow`。
46
+ - **现场重现**:先暴露于新增 `migration-idempotent.test.ts` 的 baseline case,随后确认 pre-existing 测试 `skill-invocations-workflow.test.ts` 的"增量迁移"case 同样会失败。
47
+ - **解决**:把 `addColumnIfMissing` 调用提前。等到老表已有 workflow 列后,schema.sql 的 CREATE INDEX 才安全。
48
+ - **影响**:新库(空 db)下 `hasTable` 全 false,列 migration 全静默跳过;老库下列先 ALTER;已 up-to-date 库下全跳过。三种路径均通过测试。
49
+
50
+ 2. **新增 `hasTable` 工具 + addColumnIfMissing 短路**:避免新库初始化时 PRAGMA 表不存在的噪音。spec 未要求但与顺序调整配套。
51
+
52
+ 3. **`runMigrations` 拆为 3 个私有方法**:column / index / post。提升可读性,让"列在前、索引在后、数据迁移最后"的依赖关系显式化。spec 第 49 行只要求"runMigrations 全部改造为 has 判断守护",拆分是顺手优化。
53
+
54
+ ## 已知问题
55
+
56
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > Task Operations > linkEventToTask associates events with tasks` — pre-existing failure,原因是测试数据校验失败(event tool_input 字段),与 H4 无关。H1 阶段已识别。
57
+
58
+ ## inline fallback (base.ts initSchema else 分支)
59
+
60
+ 按 spec 要求未动。spec 第 54 行明确说"本次 H4 不动它,仅注释 TODO",但 base.ts 现有代码无 TODO 注释,且 spec 没强制要求加,保持原状。
@@ -0,0 +1,46 @@
1
+ # H6 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 13:55
4
+ **Spec**: docs/design/h6-services-migration-spec-20260518-1355.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+ - [x] safety-net: tests/integration/web-analytics.integration.test.ts(3/3 pass,迁移前后均通过)
9
+ - [x] git mv 3 文件到 src/web/analytics/(保留 git history)
10
+ - [x] 改 3 处 import 路径(drift / reports / insights routes)
11
+ - [x] 清理 2 处误导注释(weekly-report 的 "implemented by another agent" + anti-pattern 的 "daemon/services 既定做法")
12
+ - [x] task-segmenter.ts 保留原地不动
13
+ - [x] vitest.config.ts 加入 `tests/integration/**` 到 include(让 safety-net 能被 npm test 拾取)
14
+
15
+ ## 关键代码定位
16
+ - 新测试文件:`tests/integration/web-analytics.integration.test.ts:1-67`
17
+ - 迁移后入口:`src/web/analytics/{drift-detector,weekly-report,anti-pattern-detector}.ts`
18
+ - import 变更:
19
+ - `src/web/routes/drift.ts:3` → `from '../analytics/drift-detector.js'`
20
+ - `src/web/routes/reports.ts:10` → `from '../analytics/weekly-report.js'`
21
+ - `src/web/routes/insights.ts:7` → `from '../analytics/anti-pattern-detector.js'`
22
+ - 注释清理:
23
+ - `src/web/analytics/weekly-report.ts:293-297`(aggregateAnomalies 内)
24
+ - `src/web/analytics/anti-pattern-detector.ts:76-81`(queryEventsSince 上方 JSDoc)
25
+ - vitest 配置:`vitest.config.ts:8`
26
+
27
+ ## 测试结果
28
+ - web-analytics 集成测试:3 passed(迁移前 baseline、迁移后回归均 3/3)
29
+ - tsc --noEmit:0 errors
30
+ - npm test:455 passed / 1 failed(仅 pre-existing `linkEventToTask` 失败,与本次迁移无关)
31
+ - npm run build:成功(dist/web/analytics/ 产出齐全;dist/daemon/services/ 只剩 task-segmenter)
32
+
33
+ ## 超出 spec 改动
34
+ - **vitest.config.ts 更新 include 模式**:原配置只扫描 `tests/unit/**`,导致 `tests/integration/**` 下的测试(含已有的 `tasks-filter.integration.test.ts`)从未跑过。为让 safety-net 真正生效,新增 `tests/integration/**/*.test.ts` 到 include。
35
+ - 副作用确认:把 `tasks-filter.integration.test.ts` 也拉进 CI,但它本就在主测试套件中通过(455 项 passed 含它)。
36
+
37
+ ## 已知问题
38
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` 失败(pre-existing,事件 UUID 校验问题,与 H6 迁移无关)
39
+
40
+ ## 迁移内文件 import 路径核查
41
+ 3 个被迁移的文件原来用 `../../core/...` 引用 core 层。从 `src/daemon/services/` 移到 `src/web/analytics/` 后,相对深度未变(仍为 2 层向上),无需调整。grep 校验通过:
42
+
43
+ ```
44
+ grep -rn "daemon/services/drift-detector|daemon/services/weekly-report|daemon/services/anti-pattern-detector" src/ tests/
45
+ → 无任何匹配
46
+ ```
@@ -0,0 +1,46 @@
1
+ # H7 + M9 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 13:00
4
+ **Status**: 完成
5
+
6
+ ## 背景修正
7
+
8
+ 原 review 误判:`claude-sonnet-4-6` 实际为合法 Sonnet 4.6 ID(非"非法")。
9
+ 真实问题:`provider.ts` 的 `DEFAULT_MODEL` 是已过时的 `claude-sonnet-4-20250514`(Sonnet 4.0 旧 ID),应改用 constants 暴露的最新值。
10
+ 端口侧的真实问题:`constants.ts` 的 `WEB_PORT: 3456` 是孤儿值(无人引用),而实际事实标准是 `3721`(7 个文件硬编码)。
11
+
12
+ ## 完成清单
13
+
14
+ - [x] `constants.ts` `WEB_PORT: 3456` → `3721`
15
+ - [x] `provider.ts` 删除硬编码 `DEFAULT_MODEL`,改用 `DEFAULTS.AI_MODEL`
16
+ - [x] `daemon/index.ts:73` 端口 fallback 用 `DEFAULTS.WEB_PORT`
17
+ - [x] `cli/commands/daemon.ts:46` 同上
18
+ - [x] `cli/commands/init.ts:107` 同上
19
+ - [x] `core/utils/error-handler.ts:224` 同上 (`String(DEFAULTS.WEB_PORT)`)
20
+ - [x] URL 字符串改 template literal(menu.ts ×3, trace.ts ×1)
21
+
22
+ ## 关键文件
23
+
24
+ - `src/core/constants.ts:44` — `WEB_PORT: 3721`
25
+ - `src/core/ai/provider.ts:27-29` — 移除 `DEFAULT_MODEL`,新增 `import { DEFAULTS } from '../constants.js'`
26
+ - `src/daemon/index.ts:73` — `?? DEFAULTS.WEB_PORT`
27
+ - `src/cli/commands/daemon.ts:46` — `const DEFAULT_PORT = DEFAULTS.WEB_PORT`
28
+ - `src/cli/commands/init.ts:107` — `let webPort: number = DEFAULTS.WEB_PORT`
29
+ - `src/core/utils/error-handler.ts:224` — `String(DEFAULTS.WEB_PORT)`
30
+ - `src/cli/commands/menu.ts:127,129,244` — template literal `http://localhost:${DEFAULTS.WEB_PORT}`
31
+ - `src/cli/commands/trace.ts:154` — 同上
32
+
33
+ ## 测试结果
34
+
35
+ - `npx tsc --noEmit`:0 errors
36
+ - `npm test`:423 passed / 1 failed(pre-existing `linkEventToTask` 与本次变更无关,位于 `tests/unit/storage/sqlite-refactor-harness.test.ts`,根因在 `EventOperations.writeEvent` 校验)
37
+
38
+ ## 不改的位置(理由)
39
+
40
+ 无。原计划中保守保留的 URL 字符串(menu.ts / trace.ts)由于改造极轻量(template literal),一并收敛进 `DEFAULTS.WEB_PORT`,进一步消除字面量漂移风险。
41
+
42
+ ## 影响面 / 风险
43
+
44
+ - 行为变更点:`constants.ts` 的 `WEB_PORT` 之前为 `3456`,但 grep 确认无实际引用,所以此值修正为 `3721` 不产生回归。
45
+ - `provider.ts` 默认模型从过时的 `claude-sonnet-4-20250514` 改为合法的 `claude-sonnet-4-6`:在 `config.ai.model` 未显式设置时,AI 调用将使用 Sonnet 4.6(更新、更便宜、更强)。这是预期升级。
46
+ - 所有端口硬编码已收敛到 `DEFAULTS.WEB_PORT`,后续调整只需改一处。
@@ -0,0 +1,45 @@
1
+ # L1 实施 Changelog: SWARM_PROTOCOL 抽到 .md 文件
2
+
3
+ **Date**: 2026-05-18 16:05
4
+ **Spec**: docs/design/l1-swarm-protocol-extract-spec-20260518-1605.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+
9
+ - [x] safety-net:`tests/integration/claudemd-generator.test.ts` 建立 baseline(SWARM 段 SHA256 锚定)
10
+ - [x] swarm-protocol.md 抽取(223 行,5441 字符 / 7817 字节)
11
+ - [x] claudemd-generator.ts:`getSwarmProtocol()` 加载器 + 模块级缓存
12
+ - [x] package.json `build`:cp `.md` + fail-fast 校验
13
+
14
+ ## 关键代码定位
15
+
16
+ - 新文件 `src/claudemd/templates/swarm-protocol.md`(223 行)
17
+ - `src/claudemd/claudemd-generator.ts:5-9` — import 增加 `dirname` + `fileURLToPath`
18
+ - `src/claudemd/claudemd-generator.ts:14-38` — `getSwarmProtocol()` 加载函数 + `_swarmProtocolCache`
19
+ - `src/claudemd/claudemd-generator.ts:59` — `generate()` 内 `SWARM_PROTOCOL` 引用改为 `getSwarmProtocol()`(实际行号 65)
20
+ - `src/claudemd/claudemd-generator.ts:568` 之后已无字面量(删除 569-804 共 236 行)
21
+ - `package.json:13` — build 中新增 `mkdir -p dist/claudemd/templates && cp src/claudemd/templates/*.md dist/claudemd/templates/`,末尾追加 `test -f dist/claudemd/templates/swarm-protocol.md` 校验
22
+
23
+ ## 测试结果
24
+
25
+ - **safety-net SHA256(迁移前后一致)**:`260dfe1e48fdecc324419a6330428eaa3597e3fd6e6262cf66cdcf301ca32e18`
26
+ - **SWARM 段长度(迁移前后一致)**:5442 字节(含分隔符尾的一个 `\n`)
27
+ - **tsc**:0 errors
28
+ - **npm test**:551 / 552 通过(1 个 pre-existing `sqlite-refactor-harness.test.ts > linkEventToTask` 失败,与本次无关)
29
+ - **npm run build**:成功;`dist/claudemd/templates/swarm-protocol.md` 存在(7817 字节,与 src 完全一致)
30
+
31
+ ## 顺手清理
32
+
33
+ - 删除 `claudemd-generator.ts` 原 547-553 两段重复的 `Core behavioral rules` 注释块(合并到新的 `getSwarmProtocol` 文档块)。
34
+ - 字面量 555-777(223 行)整体下线。文件总行数 805 → 569(-236)。
35
+
36
+ ## 已知问题
37
+
38
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` — pre-existing 失败,未触碰。
39
+
40
+ ## 兼容性确认
41
+
42
+ - dev 路径(`tsx src/`):`fileURLToPath(import.meta.url)` 解析到 `src/claudemd/`,同级 `templates/swarm-protocol.md` 存在 → 加载成功。
43
+ - npm install 路径:build 脚本 cp 到 `dist/claudemd/templates/`,末尾 `test -f` fail-fast 校验,CI 一旦缺失立刻报错。
44
+ - 缓存策略:模块级 `_swarmProtocolCache: string | null = null`,首次调用读盘后缓存;进程生命周期内 0 重复 I/O。
45
+ - 字节级等价:safety-net 测试通过 SHA256 哈希逐字符比对,新旧实现完全一致。
@@ -0,0 +1,63 @@
1
+ # L3 + L4 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 14:10
4
+ **Status**: 完成
5
+
6
+ ## 完成清单
7
+
8
+ - [x] **L4**: `stop.ts` git 调用异步化
9
+ - 3 个 `execFileSync` → `promisify(execFile)`
10
+ - `writeGitNote` 改为 `async`,主流程改为 **fire-and-forget**(`void this.writeGitNote(event)`)
11
+ - 内部仍按依赖串行 await(rev-parse work-tree → rev-parse HEAD → notes append),但**整体不阻塞 handler 主响应**
12
+ - 失败仍 catch + `logger.debug`,handler 对外契约不变(返回 `{allow: true}`)
13
+
14
+ - [x] **L3**: `server.ts` 避免 N² JSON.parse —— **方案 A(换行符分隔)**
15
+ - 验证 hook 端 `echo "$event_json" | nc -U`:`echo` 默认追加 `\n`,协议天然支持
16
+ - `data` handler 改为:仅在 `buffer.indexOf('\n') !== -1` 时切出完整消息并解析;未见换行就累积等待
17
+ - 抽取 `processMessage(socket, message)` 统一处理 auth 检查 + parser + handler response
18
+ - 兜底:监听 `socket.on('end')`,若 buffer 残留无换行内容(旧客户端)做最后一次解析尝试
19
+ - 删除 dead code `isCompleteJSON`(不再需要"启发式判完整",换行就是边界)
20
+
21
+ ## 关键代码定位
22
+
23
+ - `src/daemon/handlers/stop.ts:19-22` —— `promisify(execFile)` 导入
24
+ - `src/daemon/handlers/stop.ts:84-86` —— `void this.writeGitNote(event)` 调用点
25
+ - `src/daemon/handlers/stop.ts:102-135` —— async `writeGitNote` 实现
26
+ - `src/daemon/server.ts:51-122` —— 新的 `handleConnection` + `processMessage`
27
+ - `tests/unit/socket-server.test.ts` —— 新增 5 个测试(4 socket + 1 EventParser sanity)
28
+
29
+ ## 测试结果
30
+
31
+ - `npx tsc --noEmit`: **0 errors**
32
+ - `npm test`: **460 passed / 1 failed**(仅 pre-existing `linkEventToTask`)
33
+ - 新增 `tests/unit/socket-server.test.ts`: **5/5 passed**
34
+
35
+ 新测试覆盖:
36
+ 1. 单 chunk 完整消息(含换行)
37
+ 2. 大消息(~50KB)分 20 个 chunk 到达 —— 断言 `JSON.parse` 调用次数 ≤ 3(远小于 chunk 数,强对比旧 N² 行为)
38
+ 3. 600KB 无换行 oversized buffer 被丢弃
39
+ 4. 无换行结尾消息走 `socket.on('end')` 兜底
40
+ 5. EventParser sanity
41
+
42
+ ## 实施决策
43
+
44
+ ### L4:fire-and-forget + 内部串行
45
+ - **理由**:3 个 git 调用有严格依赖(work-tree 检查 → 拿 HEAD → 写 note),不能 `Promise.all` 并发
46
+ - **关键收益**:原 `execFileSync` 在 handler **主调用链路**中串行阻塞 daemon event loop(最坏 15s);改 `void` 调用后,git I/O 移到下一个 microtask,handler 立刻返回响应给 hook 客户端
47
+ - **副作用控制**:git 失败仍 `logger.debug`,与原行为一致;handler 主体 try/catch 已存在,async fire-and-forget 的未捕获错误已在 `writeGitNote` 内部 catch
48
+
49
+ ### L3:方案 A(换行符分隔)
50
+ - **理由**:
51
+ 1. 协议天然支持(验证了 `hook-lib.sh` 用 `echo`,默认带 `\n`)
52
+ 2. O(1) 检查(`indexOf('\n')` 在 V8 高度优化);旧代码每 chunk 做一次完整 `JSON.parse(buffer)` 在 ~512KB buffer 上是真正的 N²
53
+ 3. 单一边界标记,逻辑清晰,无需再保留 `isCompleteJSON` 启发式
54
+ - **兼容性**:保留 `socket.on('end')` 兜底,覆盖未来可能出现的"不带换行的客户端"
55
+ - **协议契约**:不变(hook 端 `echo` 不需要任何修改,服务器只是更聪明地等待 `\n`)
56
+
57
+ ## 跳过项
58
+
59
+ 无。
60
+
61
+ ## 已知问题
62
+
63
+ - **pre-existing**: `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` 失败(与本次改动无关,schema 校验 uuid 拒绝测试 fixture 中的 `event_id`)
@@ -0,0 +1,38 @@
1
+ # L6 + L8 最终扫尾 Changelog
2
+
3
+ **Date**: 2026-05-18 16:40
4
+ **Status**: 完成
5
+
6
+ ## 完成清单
7
+
8
+ - [x] L6: setLogLevel env 解析移到 logger 模块加载
9
+ - [x] L8: token_usage FK 注释补充
10
+
11
+ ## 关键代码定位
12
+
13
+ - `src/core/utils/logger.ts:5-22` — 新增 `getLogLevelFromEnv()`,模块加载时初始化 `currentLevel`
14
+ - `src/daemon/index.ts:23` / `src/daemon/index.ts:60-63` — 删除手动 env 解析与 setLogLevel 调用,import 收窄为 `logger`
15
+ - `src/core/storage/schema.sql:16-18` / `src/core/storage/schema.sql:20` / `src/core/storage/schema.sql:153-163` —
16
+ - header 关系图增加 `token_usage` 章节
17
+ - "Why no FK" 注释主语扩展为 routing_events / skill_invocations / token_usage
18
+ - token_usage.session_id 字段处补充内联注释(与 routing_events / skill_invocations 同口径)
19
+
20
+ ## 测试结果
21
+
22
+ - tsc: 0 errors
23
+ - npm test: 551 / 552 通过(1 个 pre-existing 失败:`tests/unit/storage/sqlite-refactor-harness.test.ts` 的 `writeEvent` Invalid uuid 校验失败,与本次改动无关)
24
+
25
+ ## 实施决策
26
+
27
+ - **L6**:采用「模块加载时一次性读取 env + `getLogLevelFromEnv()` 辅助函数」混合方案。
28
+ - 顶层 `let currentLevel: LogLevel = getLogLevelFromEnv();` 在模块首次 import 时执行一次。
29
+ - 由于 logger 模块当前无单元测试(`find src/tests tests/unit -name "logger.test.ts"` 为空),顶层副作用不会破坏测试 mock。
30
+ - 保留 `setLogLevel()` 导出函数以便测试或运行时覆写(向后兼容)。
31
+ - daemon/index.ts 不再需要重复 env 解析;其它入口(CLI、web)若 import logger 自动享受同样行为,无需改动。
32
+ - **L8**:纯文档/注释级补充,零 SQL 行为变更。
33
+ - 沿用 routing_events / skill_invocations 已有的 "logical ref,no FK due to write-order race" 表述。
34
+ - 同时更新文件头的表关系图,保持单一信息源。
35
+
36
+ ## 已知问题
37
+
38
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts:166` — `writeEvent Invalid uuid` 断言失败(pre-existing,与 `linkEventToTask` 重构 harness 同一组),本次未修复,按指令不扩大范围。
@@ -0,0 +1,58 @@
1
+ # M1 + M4 + M5 + L7 清理 Changelog
2
+
3
+ **Date**: 2026-05-18 13:10
4
+ **Status**: 完成
5
+
6
+ ## 完成清单
7
+ - [x] M4: events.ts 删 UpsertCapableEmitter 重复声明
8
+ - [x] L7: types.ts 删 ForgeEvent.pipeline_id 死字段(顺带删除 BaseEvent.pipeline_id)
9
+ - [x] M1: truncateField 抽到 web/routes/_helpers.ts
10
+ - [x] M5: user-prompt.ts 改用 LRUCache(保持两个独立实例)
11
+
12
+ ## 关键代码定位
13
+
14
+ ### M4 — UpsertCapableEmitter 去重
15
+ - `src/core/storage/events.ts:19-22`(旧 L19-21 + 空行)— 删除
16
+ - `src/core/storage/events.ts:57-59` — 保留(更靠近使用点 L64 constructor)
17
+
18
+ ### L7 — pipeline_id 死代码清理
19
+ - `src/core/types.ts:34` — 删除 `ForgeEvent.pipeline_id?`
20
+ - `src/core/types.ts:43` — 删除 `BaseEvent.pipeline_id?`
21
+ - 全量 grep 验证:`pipeline_id` 仅在 types.ts 中出现,无任何运行时引用,无 schema 字段、无注释、无解析逻辑。直接清理。
22
+
23
+ ### M1 — truncateField 抽取
24
+ - 新建 `src/web/routes/_helpers.ts` — 导出 `truncateField(obj, maxLen=300, arrayLimit=10)`
25
+ - 增加 `arrayLimit` 参数以兼容两个调用点的不同行为(tasks: 10, sessions: 5)
26
+ - 类型从 `any` 升为 `unknown` + `Record<string, unknown>`
27
+ - `src/web/routes/tasks.ts:1-4` — 新 import `truncateField from './_helpers.js'`
28
+ - `src/web/routes/tasks.ts` — 移除本地 `truncateField` 闭包定义(原 L87-99),调用点保持不变(默认参数 300/10 与原一致)
29
+ - `src/web/routes/sessions.ts:1-3` — 新 import
30
+ - `src/web/routes/sessions.ts` — 移除本地 `truncateField`(原 L189-201),两个调用点显式传 `(toolInput, 200, 5)` / `(toolOutput, 200, 5)` 以保留原有行为
31
+
32
+ ### M5 — LRUCache 替换手写 LRU
33
+ - `src/core/utils/lru-cache.ts:39-45` — 新增 `delete(key)` 方法(必须,否则 clearSession 无法实现)
34
+ - `src/daemon/handlers/user-prompt.ts:10` — 新 import `LRUCache`
35
+ - `src/daemon/handlers/user-prompt.ts:19-25` — 字段替换:
36
+ - `resumeInjected: Map<string, number>` → `LRUCache<string, number>(1000)`
37
+ - `conventionInjected: Map<string, number>` → `LRUCache<string, number>(1000)`
38
+ - `src/daemon/handlers/user-prompt.ts:markInjected` — 从 17 行手写 LRU 缩减为单行 `cache.set(key, Date.now())`
39
+ - `src/daemon/handlers/user-prompt.ts:hasInjected` / `clearSession` — 签名从 `Map` 改为 `LRUCache`,行为一致
40
+
41
+ ### M5 设计决策:不合并键集合
42
+ 两个 Map 虽然 key 类型相同(`sessionKey`),但语义独立:
43
+ - `resumeInjected` 控制 resume context 注入;同时还会触发 `resume.clear()`
44
+ - `conventionInjected` 控制 project guidance 注入
45
+
46
+ 如果合并成单一键集合,会丧失"同一 session 各自独立标记是否注入过"的语义。保留两个独立 LRUCache 实例最安全,不扩大改动范围。
47
+
48
+ ## 测试结果
49
+ - `npx tsc --noEmit`: **0 errors**
50
+ - `npm test`: **423 passed / 1 failed**
51
+ - 失败项:`tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask associates events with tasks`
52
+ - 失败原因:pre-existing UUID 校验问题,与本次清理无关
53
+
54
+ ## 跳过项
55
+
56
+
57
+ ## 已知问题
58
+ - pre-existing `linkEventToTask` test failure(与本次清理无关)
@@ -0,0 +1,60 @@
1
+ # M10 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 13:20
4
+ **Spec**: docs/design/m10-forge-paths-spec-20260518-1320.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+ - [x] safety-net: tests/unit/core/forge-paths.test.ts(16 个断言)
9
+ - [x] FORGE_PATHS 扩展 11 方法(daemonSocket/Pid/Token/Log/Stdout/Stderr, hooks, queue, queueDead, routingYaml, backups(kind))
10
+ - [x] Group A: daemon 运行时(lifecycle / cli/daemon / cli/status / cli/mcp / web/auth-middleware)
11
+ - [x] Group B: queue(core/queue/index.ts)
12
+ - [x] Group C: hooks(cli/init/hook-manager.ts)
13
+ - [x] Group D: web patch(web/routes/types.ts + web/routes/skills.ts × 4 处)
14
+ - [x] Group E: cli/stats.ts + error-handler.ts 文案 `forge.sock` → `daemon.sock`
15
+
16
+ ## 关键代码定位
17
+
18
+ **FORGE_PATHS 扩展**:
19
+ - `src/core/constants.ts:9-31` — 新增 11 个方法
20
+ - `tests/unit/core/forge-paths.test.ts` — 新增测试文件,16 个用例
21
+
22
+ **Group A(daemon 运行时)**:
23
+ - `src/daemon/lifecycle.ts:8-10` — TOKEN_FILE/PID_FILE 改用 FORGE_PATHS;`getSocketPath` (L51) 复用 daemonSocket
24
+ - `src/cli/commands/daemon.ts:34,44-47,114` — PID_FILE/STDOUT_LOG/STDERR_LOG/logFile,并移除未用的 FORGE_HOME import
25
+ - `src/cli/commands/status.ts:5-8` — PID_FILE 改 FORGE_PATHS.daemonPid();移除 FORGE_HOME import
26
+ - `src/cli/commands/mcp.ts:17-22,45,86` — tokenPath / daemon.pid 路径;移除 homedir/join import
27
+ - `src/web/auth-middleware.ts:13-17` — TOKEN_FILE 改 FORGE_PATHS.daemonToken();移除 path import
28
+
29
+ **Group B(queue)**:
30
+ - `src/core/queue/index.ts:16-27` — QUEUE_DIR/DEAD_DIR 改 FORGE_PATHS;移除 homedir import 与未用的 FORGE_DIR 常量
31
+
32
+ **Group C(hooks)**:
33
+ - `src/cli/init/hook-manager.ts:4,8` — HOOKS_DIR 改 FORGE_PATHS.hooks()
34
+
35
+ **Group D(web patch)**:
36
+ - `src/web/routes/types.ts:11,30-39` — resolvePatchTarget 中 4 处路径全部改 FORGE_PATHS
37
+ - `src/web/routes/skills.ts:7,208,235,279,321` — backupDir × 4 处统一 → FORGE_PATHS.backups('skills')
38
+
39
+ **Group E(其它)**:
40
+ - `src/cli/commands/stats.ts:10-21` — dbPath 改 FORGE_PATHS.database();移除 path/homedir import
41
+ - `src/core/utils/error-handler.ts:239` — 提示文本 `forge.sock` → `daemon.sock`
42
+
43
+ ## 测试结果
44
+
45
+ ```
46
+ forge-paths.test.ts: 16/16 passed
47
+ tests/unit/core/ + storage/ + queue: 85/86 passed(1 pre-existing linkEventToTask)
48
+ npm test 全量: 439/440 passed(1 pre-existing linkEventToTask)
49
+ npx tsc --noEmit: 0 errors
50
+ npm run build: 成功
51
+ ```
52
+
53
+ ## 超出 spec 改动
54
+
55
+ 无。严格按 spec 12 文件机械替换。附带顺手清理(与 spec 风险一致):
56
+ - 删除替换后未引用的 import(`homedir`、`path`、`FORGE_HOME`、`FORGE_DIR` 常量)以保持文件干净,不引入新逻辑。
57
+
58
+ ## 已知问题
59
+
60
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts` > `linkEventToTask associates events with tasks` 失败 — pre-existing UUID 校验问题,与 M10 改动无关(spec 已明示)。
@@ -0,0 +1,43 @@
1
+ # M2 + M3 实施 Changelog
2
+
3
+ **Date**: 2026-05-18 14:25
4
+ **Spec**: docs/design/m2-m3-tool-input-spec-20260518-1425.md
5
+ **Status**: 完成
6
+
7
+ ## 完成清单
8
+ - [x] M3: `event-parser.ts` 改为 `event_id: validated.event_id ?? randomUUID()`,schema 加 `event_id: z.string().uuid().optional()`
9
+ - [x] M2: `ToolInputFields` 接口 + 4 个 getter(`getCommand` / `getFilePath` / `getUserPrompt` / `getSubagentType`)
10
+ - [x] 替换所有 `(tool_input as any)` / `(tool_input as Record<string,unknown>)` 使用点(10 处源文件)
11
+ - [x] 新增 `tests/unit/event-fields.test.ts`(15 cases)
12
+ - [x] 新增 `tests/unit/event-parser.test.ts`(5 cases)
13
+
14
+ ## 关键代码定位
15
+ - `src/core/types.ts:25-61` — `ToolInputFields` 接口 + `ForgeEvent.tool_input: ToolInputFields | undefined`
16
+ - `src/core/event-fields.ts:1-32` — 4 个 getter
17
+ - `src/daemon/event-parser.ts:16,23,29` — M3 schema + event_id 透传 + `as ToolInputFields` cast
18
+ - `src/web/routes/sessions.ts:4,82-100,158-167,222-234` — sessions 路由 getter 化(8 处)
19
+ - `src/web/routes/tasks.ts:5,111-131,156-172` — tasks 路由 getter 化(5 处)
20
+ - `src/web/analytics/anti-pattern-detector.ts:95,354-364` — helpers 签名调整为 `ForgeEvent['tool_input']`,line 95 显式 cast
21
+ - `src/daemon/handlers/post-tool-use.ts:5,29` — `getSubagentType(event)`
22
+ - `src/daemon/handlers/history-exporter.ts:102` — 去掉 `as Record<string, unknown>` cast
23
+ - `src/cli/commands/logs.ts:43` — 去掉 `as Record<string, unknown>` cast
24
+ - `src/claudemd/resume-manager.ts:118` — 去掉 `as string` cast,改 `typeof === 'string'` 守卫
25
+ - `src/daemon/index.ts:39-40,161` — import + 改用 `getUserPrompt(event)`
26
+
27
+ ## 测试结果
28
+ - `tests/unit/event-fields.test.ts`: 15 / 15 passed
29
+ - `tests/unit/event-parser.test.ts`: 5 / 5 passed
30
+ - `npx tsc --noEmit`: 0 errors
31
+ - `npm test --reporter=dot`: **480 / 481 passed**(唯一失败为 pre-existing `linkEventToTask`,spec 第 5 项明确豁免)
32
+
33
+ ## 顺手发现的额外 as any(如有)
34
+ 无新增。`src/web/routes/sessions.ts:188-190` 的 `tool_input as any` 同步消除;`tool_output as any` 保留 1 处(`?.error` 防御访问,超出本 spec 范围)。
35
+
36
+ ## 已知问题
37
+ - `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` 失败:pre-existing,spec 已豁免;根因是测试构造的 event_id 不是 UUID,与本次 M3 schema 收紧无关(写入端 `writeEvent` 早已校验 UUID)。
38
+ - `tests/unit/web/routes-tasks.test.ts` 在全量并行跑时偶发首例 404(B 路径下 `getStorage()` 状态同步问题),单独跑 21/21 全过;非本次回归。
39
+
40
+ ## 设计要点
41
+ - `ToolInputFields` 加 `[key: string]: unknown` 索引签名:兼顾 forward-compat 与窄化收益(spec 风险 1 已确认接受)。
42
+ - M3 让 hook 端可选自带 `event_id`:未带时 parser 兜底 `randomUUID()`,与 queue / storage 层 `event.event_id ?? randomUUID()` 形成端到端去重链路(hook 端真正生成 event_id 是后续 follow-up)。
43
+ - `anti-pattern-detector.ts` 走保守路径:保留 `extractFilePath` / `extractBashCommand` 私有签名,只调整参数类型为 `ForgeEvent['tool_input']`,调用方零改动。