@winspan/claude-forge 8.54.4 → 9.12.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 (1053) hide show
  1. package/DEVELOPMENT.md +723 -46
  2. package/README.md +166 -21
  3. package/dist/catalogs/agents.json +67 -0
  4. package/dist/catalogs/skills.json +306 -0
  5. package/dist/claudemd/claudemd-generator.d.ts +45 -45
  6. package/dist/claudemd/claudemd-generator.d.ts.map +1 -1
  7. package/dist/claudemd/claudemd-generator.js +128 -449
  8. package/dist/claudemd/claudemd-generator.js.map +1 -1
  9. package/dist/claudemd/index.d.ts +14 -4
  10. package/dist/claudemd/index.d.ts.map +1 -1
  11. package/dist/claudemd/index.js +15 -4
  12. package/dist/claudemd/index.js.map +1 -1
  13. package/dist/claudemd/resume-manager.d.ts.map +1 -1
  14. package/dist/claudemd/resume-manager.js +37 -9
  15. package/dist/claudemd/resume-manager.js.map +1 -1
  16. package/dist/claudemd/templates/swarm-protocol.md +35 -186
  17. package/dist/claudemd/violations-manager.d.ts +40 -0
  18. package/dist/claudemd/violations-manager.d.ts.map +1 -0
  19. package/dist/claudemd/violations-manager.js +106 -0
  20. package/dist/claudemd/violations-manager.js.map +1 -0
  21. package/dist/cli/commands/admin.d.ts +15 -0
  22. package/dist/cli/commands/admin.d.ts.map +1 -0
  23. package/dist/cli/commands/admin.js +177 -0
  24. package/dist/cli/commands/admin.js.map +1 -0
  25. package/dist/cli/commands/agent.d.ts +169 -0
  26. package/dist/cli/commands/agent.d.ts.map +1 -0
  27. package/dist/cli/commands/agent.js +690 -0
  28. package/dist/cli/commands/agent.js.map +1 -0
  29. package/dist/cli/commands/agents.d.ts +18 -0
  30. package/dist/cli/commands/agents.d.ts.map +1 -0
  31. package/dist/cli/commands/agents.js +160 -0
  32. package/dist/cli/commands/agents.js.map +1 -0
  33. package/dist/cli/commands/bypass.d.ts +18 -0
  34. package/dist/cli/commands/bypass.d.ts.map +1 -0
  35. package/dist/cli/commands/bypass.js +87 -0
  36. package/dist/cli/commands/bypass.js.map +1 -0
  37. package/dist/cli/commands/claudemd.d.ts +60 -0
  38. package/dist/cli/commands/claudemd.d.ts.map +1 -1
  39. package/dist/cli/commands/claudemd.js +174 -37
  40. package/dist/cli/commands/claudemd.js.map +1 -1
  41. package/dist/cli/commands/codegraph.d.ts +17 -0
  42. package/dist/cli/commands/codegraph.d.ts.map +1 -0
  43. package/dist/cli/commands/codegraph.js +263 -0
  44. package/dist/cli/commands/codegraph.js.map +1 -0
  45. package/dist/cli/commands/config.d.ts.map +1 -1
  46. package/dist/cli/commands/config.js +94 -1
  47. package/dist/cli/commands/config.js.map +1 -1
  48. package/dist/cli/commands/daemon.d.ts +39 -0
  49. package/dist/cli/commands/daemon.d.ts.map +1 -1
  50. package/dist/cli/commands/daemon.js +167 -20
  51. package/dist/cli/commands/daemon.js.map +1 -1
  52. package/dist/cli/commands/decisions.d.ts +129 -0
  53. package/dist/cli/commands/decisions.d.ts.map +1 -0
  54. package/dist/cli/commands/decisions.js +706 -0
  55. package/dist/cli/commands/decisions.js.map +1 -0
  56. package/dist/cli/commands/doctor.d.ts +29 -0
  57. package/dist/cli/commands/doctor.d.ts.map +1 -0
  58. package/dist/cli/commands/doctor.js +124 -0
  59. package/dist/cli/commands/doctor.js.map +1 -0
  60. package/dist/cli/commands/entropy.d.ts +35 -0
  61. package/dist/cli/commands/entropy.d.ts.map +1 -0
  62. package/dist/cli/commands/entropy.js +121 -0
  63. package/dist/cli/commands/entropy.js.map +1 -0
  64. package/dist/cli/commands/executions.d.ts +1 -0
  65. package/dist/cli/commands/executions.d.ts.map +1 -1
  66. package/dist/cli/commands/executions.js +12 -2
  67. package/dist/cli/commands/executions.js.map +1 -1
  68. package/dist/cli/commands/fix.d.ts +31 -0
  69. package/dist/cli/commands/fix.d.ts.map +1 -0
  70. package/dist/cli/commands/fix.js +108 -0
  71. package/dist/cli/commands/fix.js.map +1 -0
  72. package/dist/cli/commands/governance.d.ts +21 -0
  73. package/dist/cli/commands/governance.d.ts.map +1 -0
  74. package/dist/cli/commands/governance.js +60 -0
  75. package/dist/cli/commands/governance.js.map +1 -0
  76. package/dist/cli/commands/init.d.ts +27 -0
  77. package/dist/cli/commands/init.d.ts.map +1 -1
  78. package/dist/cli/commands/init.js +158 -146
  79. package/dist/cli/commands/init.js.map +1 -1
  80. package/dist/cli/commands/insights-goal-check.d.ts +54 -0
  81. package/dist/cli/commands/insights-goal-check.d.ts.map +1 -0
  82. package/dist/cli/commands/insights-goal-check.js +318 -0
  83. package/dist/cli/commands/insights-goal-check.js.map +1 -0
  84. package/dist/cli/commands/insights.d.ts +15 -0
  85. package/dist/cli/commands/insights.d.ts.map +1 -0
  86. package/dist/cli/commands/insights.js +127 -0
  87. package/dist/cli/commands/insights.js.map +1 -0
  88. package/dist/cli/commands/knowledge.d.ts +117 -0
  89. package/dist/cli/commands/knowledge.d.ts.map +1 -0
  90. package/dist/cli/commands/knowledge.js +1070 -0
  91. package/dist/cli/commands/knowledge.js.map +1 -0
  92. package/dist/cli/commands/loop.d.ts +95 -0
  93. package/dist/cli/commands/loop.d.ts.map +1 -0
  94. package/dist/cli/commands/loop.js +408 -0
  95. package/dist/cli/commands/loop.js.map +1 -0
  96. package/dist/cli/commands/maintenance.d.ts +33 -0
  97. package/dist/cli/commands/maintenance.d.ts.map +1 -0
  98. package/dist/cli/commands/maintenance.js +75 -0
  99. package/dist/cli/commands/maintenance.js.map +1 -0
  100. package/dist/cli/commands/mcp.d.ts +22 -11
  101. package/dist/cli/commands/mcp.d.ts.map +1 -1
  102. package/dist/cli/commands/mcp.js +93 -5
  103. package/dist/cli/commands/mcp.js.map +1 -1
  104. package/dist/cli/commands/menu.d.ts.map +1 -1
  105. package/dist/cli/commands/menu.js +10 -184
  106. package/dist/cli/commands/menu.js.map +1 -1
  107. package/dist/cli/commands/project.d.ts +98 -0
  108. package/dist/cli/commands/project.d.ts.map +1 -0
  109. package/dist/cli/commands/project.js +382 -0
  110. package/dist/cli/commands/project.js.map +1 -0
  111. package/dist/cli/commands/skills.d.ts +131 -0
  112. package/dist/cli/commands/skills.d.ts.map +1 -1
  113. package/dist/cli/commands/skills.js +404 -118
  114. package/dist/cli/commands/skills.js.map +1 -1
  115. package/dist/cli/commands/spec.d.ts +40 -0
  116. package/dist/cli/commands/spec.d.ts.map +1 -0
  117. package/dist/cli/commands/spec.js +49 -0
  118. package/dist/cli/commands/spec.js.map +1 -0
  119. package/dist/cli/commands/stats.d.ts.map +1 -1
  120. package/dist/cli/commands/stats.js +11 -3
  121. package/dist/cli/commands/stats.js.map +1 -1
  122. package/dist/cli/commands/status.d.ts.map +1 -1
  123. package/dist/cli/commands/status.js +17 -2
  124. package/dist/cli/commands/status.js.map +1 -1
  125. package/dist/cli/commands/trace.d.ts.map +1 -1
  126. package/dist/cli/commands/trace.js +4 -9
  127. package/dist/cli/commands/trace.js.map +1 -1
  128. package/dist/cli/commands/violations.d.ts +14 -0
  129. package/dist/cli/commands/violations.d.ts.map +1 -0
  130. package/dist/cli/commands/violations.js +43 -0
  131. package/dist/cli/commands/violations.js.map +1 -0
  132. package/dist/cli/index.js +34 -0
  133. package/dist/cli/index.js.map +1 -1
  134. package/dist/cli/init/hook-manager.d.ts +1 -1
  135. package/dist/cli/init/hook-manager.d.ts.map +1 -1
  136. package/dist/cli/init/hook-manager.js +6 -0
  137. package/dist/cli/init/hook-manager.js.map +1 -1
  138. package/dist/cli/utils/resolve-session.d.ts +32 -0
  139. package/dist/cli/utils/resolve-session.d.ts.map +1 -0
  140. package/dist/cli/utils/resolve-session.js +39 -0
  141. package/dist/cli/utils/resolve-session.js.map +1 -0
  142. package/dist/core/config.d.ts +4 -1
  143. package/dist/core/config.d.ts.map +1 -1
  144. package/dist/core/config.js +11 -23
  145. package/dist/core/config.js.map +1 -1
  146. package/dist/core/constants.d.ts +51 -13
  147. package/dist/core/constants.d.ts.map +1 -1
  148. package/dist/core/constants.js +63 -13
  149. package/dist/core/constants.js.map +1 -1
  150. package/dist/core/diagnostics/checks.d.ts +151 -0
  151. package/dist/core/diagnostics/checks.d.ts.map +1 -0
  152. package/dist/core/diagnostics/checks.js +766 -0
  153. package/dist/core/diagnostics/checks.js.map +1 -0
  154. package/dist/core/diagnostics/daemon-status.d.ts +77 -0
  155. package/dist/core/diagnostics/daemon-status.d.ts.map +1 -0
  156. package/dist/core/diagnostics/daemon-status.js +113 -0
  157. package/dist/core/diagnostics/daemon-status.js.map +1 -0
  158. package/dist/core/diagnostics/entropy-checks.d.ts +83 -0
  159. package/dist/core/diagnostics/entropy-checks.d.ts.map +1 -0
  160. package/dist/core/diagnostics/entropy-checks.js +400 -0
  161. package/dist/core/diagnostics/entropy-checks.js.map +1 -0
  162. package/dist/core/diagnostics/fix-runner.d.ts +54 -0
  163. package/dist/core/diagnostics/fix-runner.d.ts.map +1 -0
  164. package/dist/core/diagnostics/fix-runner.js +90 -0
  165. package/dist/core/diagnostics/fix-runner.js.map +1 -0
  166. package/dist/core/diagnostics/heartbeat-reader.d.ts +28 -0
  167. package/dist/core/diagnostics/heartbeat-reader.d.ts.map +1 -0
  168. package/dist/core/diagnostics/heartbeat-reader.js +50 -0
  169. package/dist/core/diagnostics/heartbeat-reader.js.map +1 -0
  170. package/dist/core/diagnostics/knip-runner.d.ts +49 -0
  171. package/dist/core/diagnostics/knip-runner.d.ts.map +1 -0
  172. package/dist/core/diagnostics/knip-runner.js +100 -0
  173. package/dist/core/diagnostics/knip-runner.js.map +1 -0
  174. package/dist/core/diagnostics/markers.d.ts +96 -0
  175. package/dist/core/diagnostics/markers.d.ts.map +1 -0
  176. package/dist/core/diagnostics/markers.js +153 -0
  177. package/dist/core/diagnostics/markers.js.map +1 -0
  178. package/dist/core/event-fields.d.ts +27 -0
  179. package/dist/core/event-fields.d.ts.map +1 -1
  180. package/dist/core/event-fields.js +43 -0
  181. package/dist/core/event-fields.js.map +1 -1
  182. package/dist/core/governance/global-inject.d.ts +90 -0
  183. package/dist/core/governance/global-inject.d.ts.map +1 -0
  184. package/dist/core/governance/global-inject.js +184 -0
  185. package/dist/core/governance/global-inject.js.map +1 -0
  186. package/dist/core/insights/agent-anchor-guard.d.ts +77 -0
  187. package/dist/core/insights/agent-anchor-guard.d.ts.map +1 -0
  188. package/dist/core/insights/agent-anchor-guard.js +119 -0
  189. package/dist/core/insights/agent-anchor-guard.js.map +1 -0
  190. package/dist/core/insights/agent-distill-context.d.ts +55 -0
  191. package/dist/core/insights/agent-distill-context.d.ts.map +1 -0
  192. package/dist/core/insights/agent-distill-context.js +146 -0
  193. package/dist/core/insights/agent-distill-context.js.map +1 -0
  194. package/dist/core/insights/agent-distill-spawn.d.ts +56 -0
  195. package/dist/core/insights/agent-distill-spawn.d.ts.map +1 -0
  196. package/dist/core/insights/agent-distill-spawn.js +179 -0
  197. package/dist/core/insights/agent-distill-spawn.js.map +1 -0
  198. package/dist/core/insights/agent-drift.d.ts +66 -0
  199. package/dist/core/insights/agent-drift.d.ts.map +1 -0
  200. package/dist/core/insights/agent-drift.js +109 -0
  201. package/dist/core/insights/agent-drift.js.map +1 -0
  202. package/dist/core/insights/agent-evolution-sources.d.ts +21 -0
  203. package/dist/core/insights/agent-evolution-sources.d.ts.map +1 -0
  204. package/dist/core/insights/agent-evolution-sources.js +36 -0
  205. package/dist/core/insights/agent-evolution-sources.js.map +1 -0
  206. package/dist/core/insights/agent-health.d.ts +142 -0
  207. package/dist/core/insights/agent-health.d.ts.map +1 -0
  208. package/dist/core/insights/agent-health.js +296 -0
  209. package/dist/core/insights/agent-health.js.map +1 -0
  210. package/dist/core/insights/agent-patch-apply.d.ts +45 -0
  211. package/dist/core/insights/agent-patch-apply.d.ts.map +1 -0
  212. package/dist/core/insights/agent-patch-apply.js +165 -0
  213. package/dist/core/insights/agent-patch-apply.js.map +1 -0
  214. package/dist/core/insights/agent-suggest.d.ts +128 -0
  215. package/dist/core/insights/agent-suggest.d.ts.map +1 -0
  216. package/dist/core/insights/agent-suggest.js +284 -0
  217. package/dist/core/insights/agent-suggest.js.map +1 -0
  218. package/dist/core/insights/coverage-tiers.d.ts +46 -0
  219. package/dist/core/insights/coverage-tiers.d.ts.map +1 -0
  220. package/dist/core/insights/coverage-tiers.js +95 -0
  221. package/dist/core/insights/coverage-tiers.js.map +1 -0
  222. package/dist/core/insights/experience-extractor.d.ts +60 -0
  223. package/dist/core/insights/experience-extractor.d.ts.map +1 -0
  224. package/dist/core/insights/experience-extractor.js +319 -0
  225. package/dist/core/insights/experience-extractor.js.map +1 -0
  226. package/dist/core/insights/violation-reporter.d.ts +149 -0
  227. package/dist/core/insights/violation-reporter.d.ts.map +1 -0
  228. package/dist/core/insights/violation-reporter.js +391 -0
  229. package/dist/core/insights/violation-reporter.js.map +1 -0
  230. package/dist/core/loop/loop-engine.d.ts +140 -0
  231. package/dist/core/loop/loop-engine.d.ts.map +1 -0
  232. package/dist/core/loop/loop-engine.js +266 -0
  233. package/dist/core/loop/loop-engine.js.map +1 -0
  234. package/dist/core/queue/index.d.ts +16 -3
  235. package/dist/core/queue/index.d.ts.map +1 -1
  236. package/dist/core/queue/index.js +16 -4
  237. package/dist/core/queue/index.js.map +1 -1
  238. package/dist/core/storage/base.d.ts +317 -0
  239. package/dist/core/storage/base.d.ts.map +1 -1
  240. package/dist/core/storage/base.js +1093 -0
  241. package/dist/core/storage/base.js.map +1 -1
  242. package/dist/core/storage/codec/tool-input-codec.d.ts +93 -0
  243. package/dist/core/storage/codec/tool-input-codec.d.ts.map +1 -0
  244. package/dist/core/storage/codec/tool-input-codec.js +159 -0
  245. package/dist/core/storage/codec/tool-input-codec.js.map +1 -0
  246. package/dist/core/storage/codegraph-types.d.ts +79 -0
  247. package/dist/core/storage/codegraph-types.d.ts.map +1 -0
  248. package/dist/core/storage/codegraph-types.js +14 -0
  249. package/dist/core/storage/codegraph-types.js.map +1 -0
  250. package/dist/core/storage/codegraph.d.ts +186 -0
  251. package/dist/core/storage/codegraph.d.ts.map +1 -0
  252. package/dist/core/storage/codegraph.js +452 -0
  253. package/dist/core/storage/codegraph.js.map +1 -0
  254. package/dist/core/storage/decisions.d.ts +387 -0
  255. package/dist/core/storage/decisions.d.ts.map +1 -0
  256. package/dist/core/storage/decisions.js +534 -0
  257. package/dist/core/storage/decisions.js.map +1 -0
  258. package/dist/core/storage/events.d.ts +239 -8
  259. package/dist/core/storage/events.d.ts.map +1 -1
  260. package/dist/core/storage/events.js +705 -39
  261. package/dist/core/storage/events.js.map +1 -1
  262. package/dist/core/storage/feedback.d.ts +111 -0
  263. package/dist/core/storage/feedback.d.ts.map +1 -0
  264. package/dist/core/storage/feedback.js +186 -0
  265. package/dist/core/storage/feedback.js.map +1 -0
  266. package/dist/core/storage/forge-config.d.ts +40 -0
  267. package/dist/core/storage/forge-config.d.ts.map +1 -0
  268. package/dist/core/storage/forge-config.js +65 -0
  269. package/dist/core/storage/forge-config.js.map +1 -0
  270. package/dist/core/storage/injections.d.ts +68 -0
  271. package/dist/core/storage/injections.d.ts.map +1 -1
  272. package/dist/core/storage/injections.js +131 -5
  273. package/dist/core/storage/injections.js.map +1 -1
  274. package/dist/core/storage/knowledge.d.ts +332 -0
  275. package/dist/core/storage/knowledge.d.ts.map +1 -0
  276. package/dist/core/storage/knowledge.js +589 -0
  277. package/dist/core/storage/knowledge.js.map +1 -0
  278. package/dist/core/storage/maintenance.d.ts +36 -9
  279. package/dist/core/storage/maintenance.d.ts.map +1 -1
  280. package/dist/core/storage/maintenance.js +56 -24
  281. package/dist/core/storage/maintenance.js.map +1 -1
  282. package/dist/core/storage/pipeline-rollup.d.ts +111 -0
  283. package/dist/core/storage/pipeline-rollup.d.ts.map +1 -0
  284. package/dist/core/storage/pipeline-rollup.js +432 -0
  285. package/dist/core/storage/pipeline-rollup.js.map +1 -0
  286. package/dist/core/storage/routing.d.ts +50 -3
  287. package/dist/core/storage/routing.d.ts.map +1 -1
  288. package/dist/core/storage/routing.js +131 -10
  289. package/dist/core/storage/routing.js.map +1 -1
  290. package/dist/core/storage/rows.d.ts +31 -8
  291. package/dist/core/storage/rows.d.ts.map +1 -1
  292. package/dist/core/storage/schema.sql +367 -23
  293. package/dist/core/storage/sessions.d.ts +136 -0
  294. package/dist/core/storage/sessions.d.ts.map +1 -1
  295. package/dist/core/storage/sessions.js +352 -15
  296. package/dist/core/storage/sessions.js.map +1 -1
  297. package/dist/core/storage/skills.d.ts +160 -0
  298. package/dist/core/storage/skills.d.ts.map +1 -1
  299. package/dist/core/storage/skills.js +368 -7
  300. package/dist/core/storage/skills.js.map +1 -1
  301. package/dist/core/storage/sqlite.d.ts +309 -20
  302. package/dist/core/storage/sqlite.d.ts.map +1 -1
  303. package/dist/core/storage/sqlite.js +523 -16
  304. package/dist/core/storage/sqlite.js.map +1 -1
  305. package/dist/core/storage/tasks.d.ts +744 -2
  306. package/dist/core/storage/tasks.d.ts.map +1 -1
  307. package/dist/core/storage/tasks.js +1691 -17
  308. package/dist/core/storage/tasks.js.map +1 -1
  309. package/dist/core/storage/tool-intercepts.d.ts +69 -0
  310. package/dist/core/storage/tool-intercepts.d.ts.map +1 -0
  311. package/dist/core/storage/tool-intercepts.js +116 -0
  312. package/dist/core/storage/tool-intercepts.js.map +1 -0
  313. package/dist/core/types.d.ts +136 -18
  314. package/dist/core/types.d.ts.map +1 -1
  315. package/dist/core/types.js +10 -0
  316. package/dist/core/types.js.map +1 -1
  317. package/dist/core/utils/backup.d.ts +81 -0
  318. package/dist/core/utils/backup.d.ts.map +1 -0
  319. package/dist/core/utils/backup.js +98 -0
  320. package/dist/core/utils/backup.js.map +1 -0
  321. package/dist/core/utils/binary-paths.d.ts +124 -0
  322. package/dist/core/utils/binary-paths.d.ts.map +1 -0
  323. package/dist/core/utils/binary-paths.js +218 -0
  324. package/dist/core/utils/binary-paths.js.map +1 -0
  325. package/dist/core/utils/bypass-token.d.ts +75 -0
  326. package/dist/core/utils/bypass-token.d.ts.map +1 -0
  327. package/dist/core/utils/bypass-token.js +133 -0
  328. package/dist/core/utils/bypass-token.js.map +1 -0
  329. package/dist/core/utils/cc-builtin-agents.d.ts +3 -0
  330. package/dist/core/utils/cc-builtin-agents.d.ts.map +1 -0
  331. package/dist/core/utils/cc-builtin-agents.js +29 -0
  332. package/dist/core/utils/cc-builtin-agents.js.map +1 -0
  333. package/dist/core/utils/claude-cli-resolver.d.ts +26 -0
  334. package/dist/core/utils/claude-cli-resolver.d.ts.map +1 -0
  335. package/dist/core/utils/claude-cli-resolver.js +115 -0
  336. package/dist/core/utils/claude-cli-resolver.js.map +1 -0
  337. package/dist/core/utils/claude-cli-spawn.d.ts +106 -0
  338. package/dist/core/utils/claude-cli-spawn.d.ts.map +1 -0
  339. package/dist/core/utils/claude-cli-spawn.js +219 -0
  340. package/dist/core/utils/claude-cli-spawn.js.map +1 -0
  341. package/dist/core/utils/forge-resume-block.d.ts.map +1 -1
  342. package/dist/core/utils/forge-resume-block.js +3 -2
  343. package/dist/core/utils/forge-resume-block.js.map +1 -1
  344. package/dist/core/utils/logger.d.ts +15 -3
  345. package/dist/core/utils/logger.d.ts.map +1 -1
  346. package/dist/core/utils/logger.js +20 -2
  347. package/dist/core/utils/logger.js.map +1 -1
  348. package/dist/core/utils/noise-prompt.d.ts +97 -0
  349. package/dist/core/utils/noise-prompt.d.ts.map +1 -0
  350. package/dist/core/utils/noise-prompt.js +127 -0
  351. package/dist/core/utils/noise-prompt.js.map +1 -0
  352. package/dist/core/utils/path.d.ts +0 -4
  353. package/dist/core/utils/path.d.ts.map +1 -1
  354. package/dist/core/utils/path.js +0 -7
  355. package/dist/core/utils/path.js.map +1 -1
  356. package/dist/core/utils/time.d.ts +67 -0
  357. package/dist/core/utils/time.d.ts.map +1 -1
  358. package/dist/core/utils/time.js +147 -0
  359. package/dist/core/utils/time.js.map +1 -1
  360. package/dist/daemon/agent-sync.d.ts +24 -0
  361. package/dist/daemon/agent-sync.d.ts.map +1 -0
  362. package/dist/daemon/agent-sync.js +114 -0
  363. package/dist/daemon/agent-sync.js.map +1 -0
  364. package/dist/daemon/config-store.d.ts +55 -0
  365. package/dist/daemon/config-store.d.ts.map +1 -0
  366. package/dist/daemon/config-store.js +146 -0
  367. package/dist/daemon/config-store.js.map +1 -0
  368. package/dist/daemon/event-parser.d.ts +22 -0
  369. package/dist/daemon/event-parser.d.ts.map +1 -1
  370. package/dist/daemon/event-parser.js +54 -3
  371. package/dist/daemon/event-parser.js.map +1 -1
  372. package/dist/daemon/handlers/history-exporter.d.ts.map +1 -1
  373. package/dist/daemon/handlers/history-exporter.js +9 -8
  374. package/dist/daemon/handlers/history-exporter.js.map +1 -1
  375. package/dist/daemon/handlers/post-tool-use.d.ts +66 -4
  376. package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
  377. package/dist/daemon/handlers/post-tool-use.js +221 -8
  378. package/dist/daemon/handlers/post-tool-use.js.map +1 -1
  379. package/dist/daemon/handlers/pre-tool-use.d.ts +181 -0
  380. package/dist/daemon/handlers/pre-tool-use.d.ts.map +1 -0
  381. package/dist/daemon/handlers/pre-tool-use.js +618 -0
  382. package/dist/daemon/handlers/pre-tool-use.js.map +1 -0
  383. package/dist/daemon/handlers/stop.d.ts +55 -7
  384. package/dist/daemon/handlers/stop.d.ts.map +1 -1
  385. package/dist/daemon/handlers/stop.js +245 -8
  386. package/dist/daemon/handlers/stop.js.map +1 -1
  387. package/dist/daemon/handlers/user-prompt.d.ts +51 -14
  388. package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
  389. package/dist/daemon/handlers/user-prompt.js +223 -95
  390. package/dist/daemon/handlers/user-prompt.js.map +1 -1
  391. package/dist/daemon/handlers/violation-content-backfill.d.ts +76 -0
  392. package/dist/daemon/handlers/violation-content-backfill.d.ts.map +1 -0
  393. package/dist/daemon/handlers/violation-content-backfill.js +167 -0
  394. package/dist/daemon/handlers/violation-content-backfill.js.map +1 -0
  395. package/dist/daemon/hook-sync.d.ts.map +1 -1
  396. package/dist/daemon/hook-sync.js +2 -1
  397. package/dist/daemon/hook-sync.js.map +1 -1
  398. package/dist/daemon/index.d.ts +19 -0
  399. package/dist/daemon/index.d.ts.map +1 -1
  400. package/dist/daemon/index.js +439 -86
  401. package/dist/daemon/index.js.map +1 -1
  402. package/dist/daemon/lifecycle.d.ts +48 -1
  403. package/dist/daemon/lifecycle.d.ts.map +1 -1
  404. package/dist/daemon/lifecycle.js +98 -2
  405. package/dist/daemon/lifecycle.js.map +1 -1
  406. package/dist/daemon/router.d.ts +4 -1
  407. package/dist/daemon/router.d.ts.map +1 -1
  408. package/dist/daemon/router.js +4 -2
  409. package/dist/daemon/router.js.map +1 -1
  410. package/dist/daemon/rules/defaults.d.ts +20 -0
  411. package/dist/daemon/rules/defaults.d.ts.map +1 -0
  412. package/dist/daemon/rules/defaults.js +779 -0
  413. package/dist/daemon/rules/defaults.js.map +1 -0
  414. package/dist/daemon/rules/registry.d.ts +47 -0
  415. package/dist/daemon/rules/registry.d.ts.map +1 -0
  416. package/dist/daemon/rules/registry.js +84 -0
  417. package/dist/daemon/rules/registry.js.map +1 -0
  418. package/dist/daemon/rules/types.d.ts +176 -0
  419. package/dist/daemon/rules/types.d.ts.map +1 -0
  420. package/dist/daemon/rules/types.js +15 -0
  421. package/dist/daemon/rules/types.js.map +1 -0
  422. package/dist/daemon/rules/whitelist.d.ts +101 -0
  423. package/dist/daemon/rules/whitelist.d.ts.map +1 -0
  424. package/dist/daemon/rules/whitelist.js +210 -0
  425. package/dist/daemon/rules/whitelist.js.map +1 -0
  426. package/dist/daemon/rules/workflow-defaults.d.ts +52 -0
  427. package/dist/daemon/rules/workflow-defaults.d.ts.map +1 -0
  428. package/dist/daemon/rules/workflow-defaults.js +521 -0
  429. package/dist/daemon/rules/workflow-defaults.js.map +1 -0
  430. package/dist/daemon/server.d.ts +11 -1
  431. package/dist/daemon/server.d.ts.map +1 -1
  432. package/dist/daemon/server.js +7 -1
  433. package/dist/daemon/server.js.map +1 -1
  434. package/dist/daemon/services/codegraph-sync.d.ts +94 -0
  435. package/dist/daemon/services/codegraph-sync.d.ts.map +1 -0
  436. package/dist/daemon/services/codegraph-sync.js +159 -0
  437. package/dist/daemon/services/codegraph-sync.js.map +1 -0
  438. package/dist/daemon/services/context-injector.d.ts +34 -0
  439. package/dist/daemon/services/context-injector.d.ts.map +1 -0
  440. package/dist/daemon/services/context-injector.js +61 -0
  441. package/dist/daemon/services/context-injector.js.map +1 -0
  442. package/dist/daemon/services/decision-hint.d.ts +240 -0
  443. package/dist/daemon/services/decision-hint.d.ts.map +1 -0
  444. package/dist/daemon/services/decision-hint.js +562 -0
  445. package/dist/daemon/services/decision-hint.js.map +1 -0
  446. package/dist/daemon/services/event-ttl-sweep.d.ts +86 -0
  447. package/dist/daemon/services/event-ttl-sweep.d.ts.map +1 -0
  448. package/dist/daemon/services/event-ttl-sweep.js +124 -0
  449. package/dist/daemon/services/event-ttl-sweep.js.map +1 -0
  450. package/dist/daemon/services/feedback-aggregator.d.ts +167 -0
  451. package/dist/daemon/services/feedback-aggregator.d.ts.map +1 -0
  452. package/dist/daemon/services/feedback-aggregator.js +415 -0
  453. package/dist/daemon/services/feedback-aggregator.js.map +1 -0
  454. package/dist/daemon/services/heartbeat-writer.d.ts +46 -0
  455. package/dist/daemon/services/heartbeat-writer.d.ts.map +1 -0
  456. package/dist/daemon/services/heartbeat-writer.js +82 -0
  457. package/dist/daemon/services/heartbeat-writer.js.map +1 -0
  458. package/dist/daemon/services/idle-session-sweeper.d.ts +61 -0
  459. package/dist/daemon/services/idle-session-sweeper.d.ts.map +1 -0
  460. package/dist/daemon/services/idle-session-sweeper.js +94 -0
  461. package/dist/daemon/services/idle-session-sweeper.js.map +1 -0
  462. package/dist/daemon/services/idle-task-budget.d.ts +50 -0
  463. package/dist/daemon/services/idle-task-budget.d.ts.map +1 -0
  464. package/dist/daemon/services/idle-task-budget.js +72 -0
  465. package/dist/daemon/services/idle-task-budget.js.map +1 -0
  466. package/dist/daemon/services/intercept-revive.d.ts +60 -0
  467. package/dist/daemon/services/intercept-revive.d.ts.map +1 -0
  468. package/dist/daemon/services/intercept-revive.js +86 -0
  469. package/dist/daemon/services/intercept-revive.js.map +1 -0
  470. package/dist/daemon/services/intercept-rollback-guard.d.ts +105 -0
  471. package/dist/daemon/services/intercept-rollback-guard.d.ts.map +1 -0
  472. package/dist/daemon/services/intercept-rollback-guard.js +152 -0
  473. package/dist/daemon/services/intercept-rollback-guard.js.map +1 -0
  474. package/dist/daemon/services/intercept-timeout-sweeper.d.ts +58 -0
  475. package/dist/daemon/services/intercept-timeout-sweeper.d.ts.map +1 -0
  476. package/dist/daemon/services/intercept-timeout-sweeper.js +83 -0
  477. package/dist/daemon/services/intercept-timeout-sweeper.js.map +1 -0
  478. package/dist/daemon/services/kb-injector.d.ts +57 -0
  479. package/dist/daemon/services/kb-injector.d.ts.map +1 -0
  480. package/dist/daemon/services/kb-injector.js +148 -0
  481. package/dist/daemon/services/kb-injector.js.map +1 -0
  482. package/dist/daemon/services/kb-rebuild-scheduler.d.ts +95 -0
  483. package/dist/daemon/services/kb-rebuild-scheduler.d.ts.map +1 -0
  484. package/dist/daemon/services/kb-rebuild-scheduler.js +149 -0
  485. package/dist/daemon/services/kb-rebuild-scheduler.js.map +1 -0
  486. package/dist/daemon/services/loop-hint.d.ts +139 -0
  487. package/dist/daemon/services/loop-hint.d.ts.map +1 -0
  488. package/dist/daemon/services/loop-hint.js +272 -0
  489. package/dist/daemon/services/loop-hint.js.map +1 -0
  490. package/dist/daemon/services/outcome-classification-service.d.ts +49 -0
  491. package/dist/daemon/services/outcome-classification-service.d.ts.map +1 -0
  492. package/dist/daemon/services/outcome-classification-service.js +214 -0
  493. package/dist/daemon/services/outcome-classification-service.js.map +1 -0
  494. package/dist/daemon/services/outcome-classifier.d.ts +136 -0
  495. package/dist/daemon/services/outcome-classifier.d.ts.map +1 -0
  496. package/dist/daemon/services/outcome-classifier.js +178 -0
  497. package/dist/daemon/services/outcome-classifier.js.map +1 -0
  498. package/dist/daemon/services/outcome-nudge.d.ts +107 -0
  499. package/dist/daemon/services/outcome-nudge.d.ts.map +1 -0
  500. package/dist/daemon/services/outcome-nudge.js +242 -0
  501. package/dist/daemon/services/outcome-nudge.js.map +1 -0
  502. package/dist/daemon/services/spec-approval.d.ts +127 -0
  503. package/dist/daemon/services/spec-approval.d.ts.map +1 -0
  504. package/dist/daemon/services/spec-approval.js +216 -0
  505. package/dist/daemon/services/spec-approval.js.map +1 -0
  506. package/dist/daemon/services/spec-gate.d.ts +54 -0
  507. package/dist/daemon/services/spec-gate.d.ts.map +1 -0
  508. package/dist/daemon/services/spec-gate.js +113 -0
  509. package/dist/daemon/services/spec-gate.js.map +1 -0
  510. package/dist/daemon/services/task-boundary-classifier.d.ts +78 -0
  511. package/dist/daemon/services/task-boundary-classifier.d.ts.map +1 -0
  512. package/dist/daemon/services/task-boundary-classifier.js +202 -0
  513. package/dist/daemon/services/task-boundary-classifier.js.map +1 -0
  514. package/dist/daemon/services/task-segmenter.d.ts +230 -1
  515. package/dist/daemon/services/task-segmenter.d.ts.map +1 -1
  516. package/dist/daemon/services/task-segmenter.js +527 -17
  517. package/dist/daemon/services/task-segmenter.js.map +1 -1
  518. package/dist/daemon/skill-sync.d.ts +7 -2
  519. package/dist/daemon/skill-sync.d.ts.map +1 -1
  520. package/dist/daemon/skill-sync.js +114 -9
  521. package/dist/daemon/skill-sync.js.map +1 -1
  522. package/dist/daemon/startup/maintenance-schedulers.d.ts +68 -0
  523. package/dist/daemon/startup/maintenance-schedulers.d.ts.map +1 -0
  524. package/dist/daemon/startup/maintenance-schedulers.js +294 -0
  525. package/dist/daemon/startup/maintenance-schedulers.js.map +1 -0
  526. package/dist/daemon/templates/agents/agent-retro-distiller.md +106 -0
  527. package/dist/daemon/templates/agents/claudemd-writer.md +102 -0
  528. package/dist/daemon/templates/agents/coder.md +262 -0
  529. package/dist/daemon/templates/agents/decision-maker.md +546 -0
  530. package/dist/daemon/templates/agents/doc-reviewer.md +118 -0
  531. package/dist/daemon/templates/agents/harness-debug-full.md +196 -0
  532. package/dist/daemon/templates/agents/knowledge-builder.md +120 -0
  533. package/dist/daemon/templates/agents/patch-applier.md +145 -0
  534. package/dist/daemon/templates/agents/planner.md +217 -0
  535. package/dist/daemon/templates/agents/safety-net-implementer.md +278 -0
  536. package/dist/daemon/templates/agents/skill-distiller.md +114 -0
  537. package/dist/daemon/templates/agents/task-boundary-classifier.md +65 -0
  538. package/dist/daemon/templates/agents/verify-agent.md +259 -0
  539. package/dist/daemon/utils/inject-block.d.ts +39 -0
  540. package/dist/daemon/utils/inject-block.d.ts.map +1 -0
  541. package/dist/daemon/utils/inject-block.js +25 -0
  542. package/dist/daemon/utils/inject-block.js.map +1 -0
  543. package/dist/hooks/hook-lib.sh +8 -0
  544. package/dist/hooks/notification.sh +19 -8
  545. package/dist/hooks/post-tool-use.sh +41 -23
  546. package/dist/hooks/pre-tool-use.sh +54 -23
  547. package/dist/hooks/session-start.sh +68 -0
  548. package/dist/hooks/stop.sh +31 -11
  549. package/dist/hooks/user-prompt-submit.sh +37 -21
  550. package/dist/knowledge/adapters/go-adapter.d.ts +65 -0
  551. package/dist/knowledge/adapters/go-adapter.d.ts.map +1 -0
  552. package/dist/knowledge/adapters/go-adapter.js +294 -0
  553. package/dist/knowledge/adapters/go-adapter.js.map +1 -0
  554. package/dist/knowledge/adapters/index.d.ts +41 -0
  555. package/dist/knowledge/adapters/index.d.ts.map +1 -0
  556. package/dist/knowledge/adapters/index.js +71 -0
  557. package/dist/knowledge/adapters/index.js.map +1 -0
  558. package/dist/knowledge/adapters/java-adapter.d.ts +66 -0
  559. package/dist/knowledge/adapters/java-adapter.d.ts.map +1 -0
  560. package/dist/knowledge/adapters/java-adapter.js +260 -0
  561. package/dist/knowledge/adapters/java-adapter.js.map +1 -0
  562. package/dist/knowledge/adapters/js-vue-adapter.d.ts +56 -0
  563. package/dist/knowledge/adapters/js-vue-adapter.d.ts.map +1 -0
  564. package/dist/knowledge/adapters/js-vue-adapter.js +203 -0
  565. package/dist/knowledge/adapters/js-vue-adapter.js.map +1 -0
  566. package/dist/knowledge/adapters/kotlin-adapter.d.ts +55 -0
  567. package/dist/knowledge/adapters/kotlin-adapter.d.ts.map +1 -0
  568. package/dist/knowledge/adapters/kotlin-adapter.js +209 -0
  569. package/dist/knowledge/adapters/kotlin-adapter.js.map +1 -0
  570. package/dist/knowledge/adapters/monorepo-adapter.d.ts +77 -0
  571. package/dist/knowledge/adapters/monorepo-adapter.d.ts.map +1 -0
  572. package/dist/knowledge/adapters/monorepo-adapter.js +170 -0
  573. package/dist/knowledge/adapters/monorepo-adapter.js.map +1 -0
  574. package/dist/knowledge/adapters/python-adapter.d.ts +89 -0
  575. package/dist/knowledge/adapters/python-adapter.d.ts.map +1 -0
  576. package/dist/knowledge/adapters/python-adapter.js +358 -0
  577. package/dist/knowledge/adapters/python-adapter.js.map +1 -0
  578. package/dist/knowledge/adapters/rust-adapter.d.ts +73 -0
  579. package/dist/knowledge/adapters/rust-adapter.d.ts.map +1 -0
  580. package/dist/knowledge/adapters/rust-adapter.js +329 -0
  581. package/dist/knowledge/adapters/rust-adapter.js.map +1 -0
  582. package/dist/knowledge/adapters/types.d.ts +99 -0
  583. package/dist/knowledge/adapters/types.d.ts.map +1 -0
  584. package/dist/knowledge/adapters/types.js +17 -0
  585. package/dist/knowledge/adapters/types.js.map +1 -0
  586. package/dist/knowledge/adapters/typescript-adapter.d.ts +57 -0
  587. package/dist/knowledge/adapters/typescript-adapter.d.ts.map +1 -0
  588. package/dist/knowledge/adapters/typescript-adapter.js +171 -0
  589. package/dist/knowledge/adapters/typescript-adapter.js.map +1 -0
  590. package/dist/knowledge/audit-applier.d.ts +70 -0
  591. package/dist/knowledge/audit-applier.d.ts.map +1 -0
  592. package/dist/knowledge/audit-applier.js +251 -0
  593. package/dist/knowledge/audit-applier.js.map +1 -0
  594. package/dist/knowledge/builder.d.ts +261 -0
  595. package/dist/knowledge/builder.d.ts.map +1 -0
  596. package/dist/knowledge/builder.js +966 -0
  597. package/dist/knowledge/builder.js.map +1 -0
  598. package/dist/knowledge/cli-provider.d.ts +151 -0
  599. package/dist/knowledge/cli-provider.d.ts.map +1 -0
  600. package/dist/knowledge/cli-provider.js +313 -0
  601. package/dist/knowledge/cli-provider.js.map +1 -0
  602. package/dist/knowledge/constants.d.ts +78 -0
  603. package/dist/knowledge/constants.d.ts.map +1 -0
  604. package/dist/knowledge/constants.js +98 -0
  605. package/dist/knowledge/constants.js.map +1 -0
  606. package/dist/knowledge/cross-module.d.ts +139 -0
  607. package/dist/knowledge/cross-module.d.ts.map +1 -0
  608. package/dist/knowledge/cross-module.js +370 -0
  609. package/dist/knowledge/cross-module.js.map +1 -0
  610. package/dist/knowledge/git-hooks.d.ts +67 -0
  611. package/dist/knowledge/git-hooks.d.ts.map +1 -0
  612. package/dist/knowledge/git-hooks.js +258 -0
  613. package/dist/knowledge/git-hooks.js.map +1 -0
  614. package/dist/knowledge/graph/edge-extractor.d.ts +45 -0
  615. package/dist/knowledge/graph/edge-extractor.d.ts.map +1 -0
  616. package/dist/knowledge/graph/edge-extractor.js +242 -0
  617. package/dist/knowledge/graph/edge-extractor.js.map +1 -0
  618. package/dist/knowledge/graph/impact.d.ts +73 -0
  619. package/dist/knowledge/graph/impact.d.ts.map +1 -0
  620. package/dist/knowledge/graph/impact.js +94 -0
  621. package/dist/knowledge/graph/impact.js.map +1 -0
  622. package/dist/knowledge/graph/types.d.ts +22 -0
  623. package/dist/knowledge/graph/types.d.ts.map +1 -0
  624. package/dist/knowledge/graph/types.js +13 -0
  625. package/dist/knowledge/graph/types.js.map +1 -0
  626. package/dist/knowledge/module-hash.d.ts +88 -0
  627. package/dist/knowledge/module-hash.d.ts.map +1 -0
  628. package/dist/knowledge/module-hash.js +162 -0
  629. package/dist/knowledge/module-hash.js.map +1 -0
  630. package/dist/knowledge/project-detector.d.ts +101 -0
  631. package/dist/knowledge/project-detector.d.ts.map +1 -0
  632. package/dist/knowledge/project-detector.js +223 -0
  633. package/dist/knowledge/project-detector.js.map +1 -0
  634. package/dist/knowledge/prompt.d.ts +237 -0
  635. package/dist/knowledge/prompt.d.ts.map +1 -0
  636. package/dist/knowledge/prompt.js +416 -0
  637. package/dist/knowledge/prompt.js.map +1 -0
  638. package/dist/knowledge/query.d.ts +118 -0
  639. package/dist/knowledge/query.d.ts.map +1 -0
  640. package/dist/knowledge/query.js +438 -0
  641. package/dist/knowledge/query.js.map +1 -0
  642. package/dist/knowledge/repo-map.d.ts +97 -0
  643. package/dist/knowledge/repo-map.d.ts.map +1 -0
  644. package/dist/knowledge/repo-map.js +447 -0
  645. package/dist/knowledge/repo-map.js.map +1 -0
  646. package/dist/knowledge/tools/index.d.ts +14 -0
  647. package/dist/knowledge/tools/index.d.ts.map +1 -0
  648. package/dist/knowledge/tools/index.js +11 -0
  649. package/dist/knowledge/tools/index.js.map +1 -0
  650. package/dist/knowledge/tools/knowledge-get-page.d.ts +46 -0
  651. package/dist/knowledge/tools/knowledge-get-page.d.ts.map +1 -0
  652. package/dist/knowledge/tools/knowledge-get-page.js +101 -0
  653. package/dist/knowledge/tools/knowledge-get-page.js.map +1 -0
  654. package/dist/knowledge/tools/knowledge-query.d.ts +77 -0
  655. package/dist/knowledge/tools/knowledge-query.d.ts.map +1 -0
  656. package/dist/knowledge/tools/knowledge-query.js +104 -0
  657. package/dist/knowledge/tools/knowledge-query.js.map +1 -0
  658. package/dist/knowledge/tools/repo-map-lookup.d.ts +45 -0
  659. package/dist/knowledge/tools/repo-map-lookup.d.ts.map +1 -0
  660. package/dist/knowledge/tools/repo-map-lookup.js +82 -0
  661. package/dist/knowledge/tools/repo-map-lookup.js.map +1 -0
  662. package/dist/knowledge/types.d.ts +269 -0
  663. package/dist/knowledge/types.d.ts.map +1 -0
  664. package/dist/knowledge/types.js +10 -0
  665. package/dist/knowledge/types.js.map +1 -0
  666. package/dist/knowledge/validator.d.ts +90 -0
  667. package/dist/knowledge/validator.d.ts.map +1 -0
  668. package/dist/knowledge/validator.js +355 -0
  669. package/dist/knowledge/validator.js.map +1 -0
  670. package/dist/mcp/server.d.ts +64 -8
  671. package/dist/mcp/server.d.ts.map +1 -1
  672. package/dist/mcp/server.js +448 -12
  673. package/dist/mcp/server.js.map +1 -1
  674. package/dist/skills/builtin-skills.d.ts +35 -0
  675. package/dist/skills/builtin-skills.d.ts.map +1 -0
  676. package/dist/skills/builtin-skills.js +68 -0
  677. package/dist/skills/builtin-skills.js.map +1 -0
  678. package/dist/skills/distill/attribution.d.ts +59 -0
  679. package/dist/skills/distill/attribution.d.ts.map +1 -0
  680. package/dist/skills/distill/attribution.js +101 -0
  681. package/dist/skills/distill/attribution.js.map +1 -0
  682. package/dist/skills/distill/distiller.d.ts +161 -0
  683. package/dist/skills/distill/distiller.d.ts.map +1 -0
  684. package/dist/skills/distill/distiller.js +461 -0
  685. package/dist/skills/distill/distiller.js.map +1 -0
  686. package/dist/skills/distill/index.d.ts +223 -0
  687. package/dist/skills/distill/index.d.ts.map +1 -0
  688. package/dist/skills/distill/index.js +466 -0
  689. package/dist/skills/distill/index.js.map +1 -0
  690. package/dist/skills/distill/project-anchor-guard.d.ts +116 -0
  691. package/dist/skills/distill/project-anchor-guard.d.ts.map +1 -0
  692. package/dist/skills/distill/project-anchor-guard.js +334 -0
  693. package/dist/skills/distill/project-anchor-guard.js.map +1 -0
  694. package/dist/skills/distill/topic-deduper.d.ts +77 -0
  695. package/dist/skills/distill/topic-deduper.d.ts.map +1 -0
  696. package/dist/skills/distill/topic-deduper.js +119 -0
  697. package/dist/skills/distill/topic-deduper.js.map +1 -0
  698. package/dist/skills/distill/upstream-fetcher.d.ts +71 -0
  699. package/dist/skills/distill/upstream-fetcher.d.ts.map +1 -0
  700. package/dist/skills/distill/upstream-fetcher.js +202 -0
  701. package/dist/skills/distill/upstream-fetcher.js.map +1 -0
  702. package/dist/skills/distilled/distilled-api-design.md +495 -0
  703. package/dist/skills/distilled/distilled-architecture-decision.md +173 -0
  704. package/dist/skills/distilled/distilled-brainstorming.md +79 -0
  705. package/dist/skills/distilled/distilled-brand-guidelines.md +86 -0
  706. package/dist/skills/distilled/distilled-canvas-design.md +128 -0
  707. package/dist/skills/distilled/distilled-claude-api.md +185 -0
  708. package/dist/skills/distilled/distilled-creator.md +181 -0
  709. package/dist/skills/distilled/distilled-db-schema-design.md +245 -0
  710. package/dist/skills/distilled/distilled-dispatching-parallel-agents.md +136 -0
  711. package/dist/skills/distilled/distilled-doc-coauthoring.md +144 -0
  712. package/dist/skills/distilled/distilled-docx.md +231 -0
  713. package/dist/skills/distilled/distilled-executing-plans.md +148 -0
  714. package/dist/skills/distilled/distilled-finishing-a-development-branch.md +213 -0
  715. package/dist/skills/distilled/distilled-frontend-design.md +118 -0
  716. package/dist/skills/distilled/distilled-harness-engineering.md +242 -0
  717. package/dist/skills/distilled/distilled-karpathy-guidelines.md +104 -0
  718. package/dist/skills/distilled/distilled-performance-optimization.md +175 -0
  719. package/dist/skills/distilled/distilled-receiving-code-review.md +185 -0
  720. package/dist/skills/distilled/distilled-spec-driven-design.md +193 -0
  721. package/dist/skills/distilled/distilled-subagent-driven-development.md +124 -0
  722. package/dist/skills/distilled/distilled-systematic-debugging.md +154 -0
  723. package/dist/skills/distilled/distilled-test-driven-development.md +432 -0
  724. package/dist/skills/distilled/distilled-using-superpowers.md +134 -0
  725. package/dist/skills/distilled/distilled-verification-before-completion.md +213 -0
  726. package/dist/skills/distilled/distilled-writing-skills.md +175 -0
  727. package/dist/skills/registry.d.ts +55 -51
  728. package/dist/skills/registry.d.ts.map +1 -1
  729. package/dist/skills/registry.js +82 -196
  730. package/dist/skills/registry.js.map +1 -1
  731. package/dist/skills/tools/pipeline-suggest.js +14 -14
  732. package/dist/skills/tools/pipeline-suggest.js.map +1 -1
  733. package/dist/skills/tools/skill-invoke.d.ts +3 -2
  734. package/dist/skills/tools/skill-invoke.d.ts.map +1 -1
  735. package/dist/skills/tools/skill-invoke.js +4 -2
  736. package/dist/skills/tools/skill-invoke.js.map +1 -1
  737. package/dist/web/analytics/anti-pattern-detector.d.ts.map +1 -1
  738. package/dist/web/analytics/anti-pattern-detector.js +6 -1
  739. package/dist/web/analytics/anti-pattern-detector.js.map +1 -1
  740. package/dist/web/analytics/drift-detector.d.ts +6 -0
  741. package/dist/web/analytics/drift-detector.d.ts.map +1 -1
  742. package/dist/web/analytics/drift-detector.js +15 -8
  743. package/dist/web/analytics/drift-detector.js.map +1 -1
  744. package/dist/web/analytics/weekly-report.d.ts +13 -0
  745. package/dist/web/analytics/weekly-report.d.ts.map +1 -1
  746. package/dist/web/analytics/weekly-report.js +17 -3
  747. package/dist/web/analytics/weekly-report.js.map +1 -1
  748. package/dist/web/routes/_helpers.d.ts +31 -0
  749. package/dist/web/routes/_helpers.d.ts.map +1 -1
  750. package/dist/web/routes/_helpers.js +33 -0
  751. package/dist/web/routes/_helpers.js.map +1 -1
  752. package/dist/web/routes/agent-content.d.ts +30 -0
  753. package/dist/web/routes/agent-content.d.ts.map +1 -0
  754. package/dist/web/routes/agent-content.js +139 -0
  755. package/dist/web/routes/agent-content.js.map +1 -0
  756. package/dist/web/routes/agent-distill.d.ts +49 -0
  757. package/dist/web/routes/agent-distill.d.ts.map +1 -0
  758. package/dist/web/routes/agent-distill.js +526 -0
  759. package/dist/web/routes/agent-distill.js.map +1 -0
  760. package/dist/web/routes/config.d.ts +56 -0
  761. package/dist/web/routes/config.d.ts.map +1 -0
  762. package/dist/web/routes/config.js +243 -0
  763. package/dist/web/routes/config.js.map +1 -0
  764. package/dist/web/routes/decisions.d.ts +15 -0
  765. package/dist/web/routes/decisions.d.ts.map +1 -0
  766. package/dist/web/routes/decisions.js +181 -0
  767. package/dist/web/routes/decisions.js.map +1 -0
  768. package/dist/web/routes/diagnostics.d.ts +61 -0
  769. package/dist/web/routes/diagnostics.d.ts.map +1 -0
  770. package/dist/web/routes/diagnostics.js +203 -0
  771. package/dist/web/routes/diagnostics.js.map +1 -0
  772. package/dist/web/routes/error-handler.d.ts +0 -4
  773. package/dist/web/routes/error-handler.d.ts.map +1 -1
  774. package/dist/web/routes/error-handler.js +0 -8
  775. package/dist/web/routes/error-handler.js.map +1 -1
  776. package/dist/web/routes/events.d.ts.map +1 -1
  777. package/dist/web/routes/events.js +26 -1
  778. package/dist/web/routes/events.js.map +1 -1
  779. package/dist/web/routes/health.d.ts +33 -0
  780. package/dist/web/routes/health.d.ts.map +1 -0
  781. package/dist/web/routes/health.js +37 -0
  782. package/dist/web/routes/health.js.map +1 -0
  783. package/dist/web/routes/insights.d.ts +0 -5
  784. package/dist/web/routes/insights.d.ts.map +1 -1
  785. package/dist/web/routes/insights.js +0 -0
  786. package/dist/web/routes/insights.js.map +1 -1
  787. package/dist/web/routes/knowledge.d.ts +57 -0
  788. package/dist/web/routes/knowledge.d.ts.map +1 -0
  789. package/dist/web/routes/knowledge.js +772 -0
  790. package/dist/web/routes/knowledge.js.map +1 -0
  791. package/dist/web/routes/patch.d.ts +60 -1
  792. package/dist/web/routes/patch.d.ts.map +1 -1
  793. package/dist/web/routes/patch.js +170 -64
  794. package/dist/web/routes/patch.js.map +1 -1
  795. package/dist/web/routes/pipeline.d.ts +28 -0
  796. package/dist/web/routes/pipeline.d.ts.map +1 -0
  797. package/dist/web/routes/pipeline.js +145 -0
  798. package/dist/web/routes/pipeline.js.map +1 -0
  799. package/dist/web/routes/rules.d.ts.map +1 -1
  800. package/dist/web/routes/rules.js +26 -7
  801. package/dist/web/routes/rules.js.map +1 -1
  802. package/dist/web/routes/sessions.d.ts.map +1 -1
  803. package/dist/web/routes/sessions.js +17 -8
  804. package/dist/web/routes/sessions.js.map +1 -1
  805. package/dist/web/routes/skill-content.d.ts +30 -0
  806. package/dist/web/routes/skill-content.d.ts.map +1 -0
  807. package/dist/web/routes/skill-content.js +117 -0
  808. package/dist/web/routes/skill-content.js.map +1 -0
  809. package/dist/web/routes/skill-stats.d.ts.map +1 -1
  810. package/dist/web/routes/skill-stats.js +153 -16
  811. package/dist/web/routes/skill-stats.js.map +1 -1
  812. package/dist/web/routes/skills-distill.d.ts +29 -0
  813. package/dist/web/routes/skills-distill.d.ts.map +1 -0
  814. package/dist/web/routes/skills-distill.js +552 -0
  815. package/dist/web/routes/skills-distill.js.map +1 -0
  816. package/dist/web/routes/skills.js +7 -7
  817. package/dist/web/routes/skills.js.map +1 -1
  818. package/dist/web/routes/stats.d.ts.map +1 -1
  819. package/dist/web/routes/stats.js +2 -1
  820. package/dist/web/routes/stats.js.map +1 -1
  821. package/dist/web/routes/task-timeline.d.ts +178 -0
  822. package/dist/web/routes/task-timeline.d.ts.map +1 -0
  823. package/dist/web/routes/task-timeline.js +530 -0
  824. package/dist/web/routes/task-timeline.js.map +1 -0
  825. package/dist/web/routes/tasks.d.ts.map +1 -1
  826. package/dist/web/routes/tasks.js +377 -8
  827. package/dist/web/routes/tasks.js.map +1 -1
  828. package/dist/web/routes/trace.d.ts.map +1 -1
  829. package/dist/web/routes/trace.js +3 -2
  830. package/dist/web/routes/trace.js.map +1 -1
  831. package/dist/web/routes/types.d.ts +0 -4
  832. package/dist/web/routes/types.d.ts.map +1 -1
  833. package/dist/web/routes/types.js +1 -1
  834. package/dist/web/routes/types.js.map +1 -1
  835. package/dist/web/routes/violations.d.ts +14 -0
  836. package/dist/web/routes/violations.d.ts.map +1 -0
  837. package/dist/web/routes/violations.js +112 -0
  838. package/dist/web/routes/violations.js.map +1 -0
  839. package/dist/web/server.d.ts.map +1 -1
  840. package/dist/web/server.js +99 -19
  841. package/dist/web/server.js.map +1 -1
  842. package/dist/web/services/agent-distill-manager.d.ts +122 -0
  843. package/dist/web/services/agent-distill-manager.d.ts.map +1 -0
  844. package/dist/web/services/agent-distill-manager.js +397 -0
  845. package/dist/web/services/agent-distill-manager.js.map +1 -0
  846. package/dist/web/services/build-manager.d.ts +72 -0
  847. package/dist/web/services/build-manager.d.ts.map +1 -0
  848. package/dist/web/services/build-manager.js +189 -0
  849. package/dist/web/services/build-manager.js.map +1 -0
  850. package/dist/web/services/distill-manager.d.ts +172 -0
  851. package/dist/web/services/distill-manager.d.ts.map +1 -0
  852. package/dist/web/services/distill-manager.js +411 -0
  853. package/dist/web/services/distill-manager.js.map +1 -0
  854. package/dist/web/static/assets/AgentDetailPage-DlUeA1sX.js +2 -0
  855. package/dist/web/static/assets/AgentDetailPage-DlUeA1sX.js.map +1 -0
  856. package/dist/web/static/assets/AgentDistillRunPage-Cybo4bii.js +3 -0
  857. package/dist/web/static/assets/AgentDistillRunPage-Cybo4bii.js.map +1 -0
  858. package/dist/web/static/assets/AgentsPage-Qd9FExLG.js +2 -0
  859. package/dist/web/static/assets/AgentsPage-Qd9FExLG.js.map +1 -0
  860. package/dist/web/static/assets/DaemonHealthPage-DTSVqtrI.js +2 -0
  861. package/dist/web/static/assets/DaemonHealthPage-DTSVqtrI.js.map +1 -0
  862. package/dist/web/static/assets/DecisionDetailPage-b4BA8dhc.js +2 -0
  863. package/dist/web/static/assets/DecisionDetailPage-b4BA8dhc.js.map +1 -0
  864. package/dist/web/static/assets/DecisionsPage-a3NRo_T7.js +2 -0
  865. package/dist/web/static/assets/DecisionsPage-a3NRo_T7.js.map +1 -0
  866. package/dist/web/static/assets/DiagnosticsPage-DIVdiIQG.js +2 -0
  867. package/dist/web/static/assets/DiagnosticsPage-DIVdiIQG.js.map +1 -0
  868. package/dist/web/static/assets/DistillDetailPage-U6a3l2iP.js +4 -0
  869. package/dist/web/static/assets/DistillDetailPage-U6a3l2iP.js.map +1 -0
  870. package/dist/web/static/assets/DistillPage-O7BHtRN8.js +2 -0
  871. package/dist/web/static/assets/DistillPage-O7BHtRN8.js.map +1 -0
  872. package/dist/web/static/assets/DistillRunPage-D1JuRWWr.js +2 -0
  873. package/dist/web/static/assets/DistillRunPage-D1JuRWWr.js.map +1 -0
  874. package/dist/web/static/assets/GlobalScopeHint-Q3wTJx3F.js +2 -0
  875. package/dist/web/static/assets/GlobalScopeHint-Q3wTJx3F.js.map +1 -0
  876. package/dist/web/static/assets/IssueDetailPage-BDfrtk2C.js +2 -0
  877. package/dist/web/static/assets/IssueDetailPage-BDfrtk2C.js.map +1 -0
  878. package/dist/web/static/assets/IssuesPage-SKmhlCrw.js +2 -0
  879. package/dist/web/static/assets/IssuesPage-SKmhlCrw.js.map +1 -0
  880. package/dist/web/static/assets/KbDetailPage-Yna86Na8.js +2 -0
  881. package/dist/web/static/assets/KbDetailPage-Yna86Na8.js.map +1 -0
  882. package/dist/web/static/assets/KbHitsPage-Cljl7H9p.js +2 -0
  883. package/dist/web/static/assets/KbHitsPage-Cljl7H9p.js.map +1 -0
  884. package/dist/web/static/assets/MarkdownRenderer-DlDQNihj.js +3 -0
  885. package/dist/web/static/assets/MarkdownRenderer-DlDQNihj.js.map +1 -0
  886. package/dist/web/static/assets/NotFound-LMzbP51V.js +2 -0
  887. package/dist/web/static/assets/NotFound-LMzbP51V.js.map +1 -0
  888. package/dist/web/static/assets/SettingsPage-DzoK4PKg.js +2 -0
  889. package/dist/web/static/assets/SettingsPage-DzoK4PKg.js.map +1 -0
  890. package/dist/web/static/assets/SkillDetailPage-BuBJJ_NX.js +2 -0
  891. package/dist/web/static/assets/SkillDetailPage-BuBJJ_NX.js.map +1 -0
  892. package/dist/web/static/assets/SkillsPage-aojkJpBc.js +2 -0
  893. package/dist/web/static/assets/SkillsPage-aojkJpBc.js.map +1 -0
  894. package/dist/web/static/assets/TaskDetailPage-1ckxnGhw.js +4 -0
  895. package/dist/web/static/assets/TaskDetailPage-1ckxnGhw.js.map +1 -0
  896. package/dist/web/static/assets/TasksHubPage-C2PLh3eg.js +6 -0
  897. package/dist/web/static/assets/TasksHubPage-C2PLh3eg.js.map +1 -0
  898. package/dist/web/static/assets/WorkplacePage-DHrp5VxS.js +2 -0
  899. package/dist/web/static/assets/WorkplacePage-DHrp5VxS.js.map +1 -0
  900. package/dist/web/static/assets/arco-DFQA6dO_.css +1 -0
  901. package/dist/web/static/assets/arco-DV6xCLhr.js +14 -0
  902. package/dist/web/static/assets/arco-DV6xCLhr.js.map +1 -0
  903. package/dist/web/static/assets/charts-BSV4cyC4.js +37 -0
  904. package/dist/web/static/assets/charts-BSV4cyC4.js.map +1 -0
  905. package/dist/web/static/assets/date-fns-sbWH3_uq.js +2 -0
  906. package/dist/web/static/assets/date-fns-sbWH3_uq.js.map +1 -0
  907. package/dist/web/static/assets/index-B_v_MKlb.css +1 -0
  908. package/dist/web/static/assets/index-DileOOE4.js +4 -0
  909. package/dist/web/static/assets/index-DileOOE4.js.map +1 -0
  910. package/dist/web/static/assets/lucide-CnlPQoG8.js +72 -0
  911. package/dist/web/static/assets/lucide-CnlPQoG8.js.map +1 -0
  912. package/dist/web/static/assets/markdown-CA7ePUts.js +30 -0
  913. package/dist/web/static/assets/markdown-CA7ePUts.js.map +1 -0
  914. package/dist/web/static/assets/outcome-BKGy9azt.js +2 -0
  915. package/dist/web/static/assets/outcome-BKGy9azt.js.map +1 -0
  916. package/dist/web/static/assets/query-CgCOpYWf.js +2 -0
  917. package/dist/web/static/assets/{query-C99w429o.js.map → query-CgCOpYWf.js.map} +1 -1
  918. package/dist/web/static/assets/{react-router-r79dBVy4.js → react-router-Cxmg8RuL.js} +3 -3
  919. package/dist/web/static/assets/{react-router-r79dBVy4.js.map → react-router-Cxmg8RuL.js.map} +1 -1
  920. package/dist/web/static/assets/react-vendor-tkvCrao7.js +57 -0
  921. package/dist/web/static/assets/react-vendor-tkvCrao7.js.map +1 -0
  922. package/dist/web/static/assets/syntax-highlighter-BDYycNja.js +6 -0
  923. package/dist/web/static/assets/syntax-highlighter-BDYycNja.js.map +1 -0
  924. package/dist/web/static/assets/useAgentStats-B-uTgqBd.js +2 -0
  925. package/dist/web/static/assets/useAgentStats-B-uTgqBd.js.map +1 -0
  926. package/dist/web/static/assets/useDecisions-D-G2Ft5T.js +2 -0
  927. package/dist/web/static/assets/useDecisions-D-G2Ft5T.js.map +1 -0
  928. package/dist/web/static/assets/useDistill-21dZkXlT.js +3 -0
  929. package/dist/web/static/assets/useDistill-21dZkXlT.js.map +1 -0
  930. package/dist/web/static/assets/useEffectiveProject-DQiyX54y.js +2 -0
  931. package/dist/web/static/assets/useEffectiveProject-DQiyX54y.js.map +1 -0
  932. package/dist/web/static/assets/useIssuesFeed-CFiyQkAL.js +2 -0
  933. package/dist/web/static/assets/useIssuesFeed-CFiyQkAL.js.map +1 -0
  934. package/dist/web/static/assets/useKbHits-xKXWgqh9.js +2 -0
  935. package/dist/web/static/assets/useKbHits-xKXWgqh9.js.map +1 -0
  936. package/dist/web/static/assets/useSkillStats-B5hbIwdf.js +2 -0
  937. package/dist/web/static/assets/useSkillStats-B5hbIwdf.js.map +1 -0
  938. package/dist/web/static/assets/vendor-DS-q4Eyc.js +36 -0
  939. package/dist/web/static/assets/vendor-DS-q4Eyc.js.map +1 -0
  940. package/dist/web/static/index.html +12 -8
  941. package/package.json +18 -5
  942. package/dist/core/ai/provider.d.ts +0 -63
  943. package/dist/core/ai/provider.d.ts.map +0 -1
  944. package/dist/core/ai/provider.js +0 -241
  945. package/dist/core/ai/provider.js.map +0 -1
  946. package/dist/core/ai/types.d.ts +0 -43
  947. package/dist/core/ai/types.d.ts.map +0 -1
  948. package/dist/core/ai/types.js +0 -5
  949. package/dist/core/ai/types.js.map +0 -1
  950. package/dist/core/storage/token-usage.d.ts +0 -36
  951. package/dist/core/storage/token-usage.d.ts.map +0 -1
  952. package/dist/core/storage/token-usage.js +0 -59
  953. package/dist/core/storage/token-usage.js.map +0 -1
  954. package/dist/core/utils/token-tracker.d.ts +0 -39
  955. package/dist/core/utils/token-tracker.d.ts.map +0 -1
  956. package/dist/core/utils/token-tracker.js +0 -69
  957. package/dist/core/utils/token-tracker.js.map +0 -1
  958. package/dist/skills/index.d.ts +0 -3
  959. package/dist/skills/index.d.ts.map +0 -1
  960. package/dist/skills/index.js +0 -3
  961. package/dist/skills/index.js.map +0 -1
  962. package/dist/skills/matcher.d.ts +0 -26
  963. package/dist/skills/matcher.d.ts.map +0 -1
  964. package/dist/skills/matcher.js +0 -113
  965. package/dist/skills/matcher.js.map +0 -1
  966. package/dist/skills/official/code-simplifier.md +0 -52
  967. package/dist/skills/official/find-skills.md +0 -142
  968. package/dist/skills/official/official-api-design.md +0 -30
  969. package/dist/skills/official/official-architecture-decision.md +0 -41
  970. package/dist/skills/official/official-bmad.md +0 -118
  971. package/dist/skills/official/official-db-schema-design.md +0 -34
  972. package/dist/skills/official/official-debug.md +0 -25
  973. package/dist/skills/official/official-doc-driven.md +0 -31
  974. package/dist/skills/official/official-harness-engineering.md +0 -108
  975. package/dist/skills/official/official-openspec.md +0 -89
  976. package/dist/skills/official/official-performance-optimization.md +0 -30
  977. package/dist/skills/official/official-pr-review.md +0 -35
  978. package/dist/skills/official/official-release-checklist.md +0 -30
  979. package/dist/skills/official/official-security-hardening.md +0 -32
  980. package/dist/skills/official/official-spec-driven-design.md +0 -31
  981. package/dist/skills/official/planning-with-files.md +0 -241
  982. package/dist/skills/official/ui-ux-pro-max.md +0 -105
  983. package/dist/skills/official/webapp-testing.md +0 -96
  984. package/dist/skills/official-skills.d.ts +0 -26
  985. package/dist/skills/official-skills.d.ts.map +0 -1
  986. package/dist/skills/official-skills.js +0 -74
  987. package/dist/skills/official-skills.js.map +0 -1
  988. package/dist/skills/semantic-matcher.d.ts +0 -60
  989. package/dist/skills/semantic-matcher.d.ts.map +0 -1
  990. package/dist/skills/semantic-matcher.js +0 -192
  991. package/dist/skills/semantic-matcher.js.map +0 -1
  992. package/dist/skills/upgrade-engine.d.ts +0 -93
  993. package/dist/skills/upgrade-engine.d.ts.map +0 -1
  994. package/dist/skills/upgrade-engine.js +0 -447
  995. package/dist/skills/upgrade-engine.js.map +0 -1
  996. package/dist/skills/upgrade-prompt.d.ts +0 -20
  997. package/dist/skills/upgrade-prompt.d.ts.map +0 -1
  998. package/dist/skills/upgrade-prompt.js +0 -75
  999. package/dist/skills/upgrade-prompt.js.map +0 -1
  1000. package/dist/web/routes/ai.d.ts +0 -10
  1001. package/dist/web/routes/ai.d.ts.map +0 -1
  1002. package/dist/web/routes/ai.js +0 -186
  1003. package/dist/web/routes/ai.js.map +0 -1
  1004. package/dist/web/routes/token-usage.d.ts +0 -7
  1005. package/dist/web/routes/token-usage.d.ts.map +0 -1
  1006. package/dist/web/routes/token-usage.js +0 -18
  1007. package/dist/web/routes/token-usage.js.map +0 -1
  1008. package/dist/web/ssrf-guard.d.ts +0 -35
  1009. package/dist/web/ssrf-guard.d.ts.map +0 -1
  1010. package/dist/web/ssrf-guard.js +0 -93
  1011. package/dist/web/ssrf-guard.js.map +0 -1
  1012. package/dist/web/static/assets/AIConfig-CdDWzJyO.js +0 -2
  1013. package/dist/web/static/assets/AIConfig-CdDWzJyO.js.map +0 -1
  1014. package/dist/web/static/assets/Dashboard-CoEmmIDt.js +0 -2
  1015. package/dist/web/static/assets/Dashboard-CoEmmIDt.js.map +0 -1
  1016. package/dist/web/static/assets/Drawer-DdRTzlLB.js +0 -2
  1017. package/dist/web/static/assets/Drawer-DdRTzlLB.js.map +0 -1
  1018. package/dist/web/static/assets/Events-DrIq1SUS.js +0 -2
  1019. package/dist/web/static/assets/Events-DrIq1SUS.js.map +0 -1
  1020. package/dist/web/static/assets/Reports-DFBM3MDK.js +0 -2
  1021. package/dist/web/static/assets/Reports-DFBM3MDK.js.map +0 -1
  1022. package/dist/web/static/assets/SearchInput-qCj_jAcf.js +0 -2
  1023. package/dist/web/static/assets/SearchInput-qCj_jAcf.js.map +0 -1
  1024. package/dist/web/static/assets/SessionDetail-CCzwdoT7.js +0 -2
  1025. package/dist/web/static/assets/SessionDetail-CCzwdoT7.js.map +0 -1
  1026. package/dist/web/static/assets/Sessions-FfLYkAw9.js +0 -2
  1027. package/dist/web/static/assets/Sessions-FfLYkAw9.js.map +0 -1
  1028. package/dist/web/static/assets/Skills-C8Gvs3Qa.js +0 -2
  1029. package/dist/web/static/assets/Skills-C8Gvs3Qa.js.map +0 -1
  1030. package/dist/web/static/assets/TaskDetail-BS8pYhaR.js +0 -2
  1031. package/dist/web/static/assets/TaskDetail-BS8pYhaR.js.map +0 -1
  1032. package/dist/web/static/assets/Tasks-CyuhizG8.js +0 -2
  1033. package/dist/web/static/assets/Tasks-CyuhizG8.js.map +0 -1
  1034. package/dist/web/static/assets/charts-CLrM0_uM.js +0 -37
  1035. package/dist/web/static/assets/charts-CLrM0_uM.js.map +0 -1
  1036. package/dist/web/static/assets/date-fns-CZ_bHujz.js +0 -2
  1037. package/dist/web/static/assets/date-fns-CZ_bHujz.js.map +0 -1
  1038. package/dist/web/static/assets/export-L_VBD2p1.js +0 -4
  1039. package/dist/web/static/assets/export-L_VBD2p1.js.map +0 -1
  1040. package/dist/web/static/assets/index-CBX47X8l.js +0 -3
  1041. package/dist/web/static/assets/index-CBX47X8l.js.map +0 -1
  1042. package/dist/web/static/assets/index-DjIoMdoR.css +0 -1
  1043. package/dist/web/static/assets/lucide-Bs_edTLa.js +0 -232
  1044. package/dist/web/static/assets/lucide-Bs_edTLa.js.map +0 -1
  1045. package/dist/web/static/assets/query-C99w429o.js +0 -2
  1046. package/dist/web/static/assets/react-vendor-CSp-GLFF.js +0 -49
  1047. package/dist/web/static/assets/react-vendor-CSp-GLFF.js.map +0 -1
  1048. package/dist/web/static/assets/syntax-highlighter-44FakypI.js +0 -9
  1049. package/dist/web/static/assets/syntax-highlighter-44FakypI.js.map +0 -1
  1050. package/dist/web/static/assets/time-Bxuk0M-C.js +0 -2
  1051. package/dist/web/static/assets/time-Bxuk0M-C.js.map +0 -1
  1052. package/dist/web/static/assets/vendor-CMMjVdZs.js +0 -64
  1053. package/dist/web/static/assets/vendor-CMMjVdZs.js.map +0 -1
@@ -8,6 +8,12 @@
8
8
  * - 一次性 sessions 回填
9
9
  *
10
10
  * 不涉及业务读写。所有业务读写由 *Operations 类组合 db 实例实现。
11
+ *
12
+ * 迁移机制(无编号 .sql runner):schema.sql 是当前 schema 的唯一真相
13
+ * (全 idempotent CREATE ... IF NOT EXISTS,每次启动 db.exec 重放)+
14
+ * 本文件 runColumnMigrations()/runIndexMigrations()/runPostMigrations()
15
+ * 对旧库就地补列/补索引/补 CHECK。migrations/ 目录下不存在被读取的编号 .sql。
16
+ * 详见 migrations/README.md。
11
17
  */
12
18
  import Database from 'better-sqlite3';
13
19
  import { readFileSync, existsSync, mkdirSync, statSync } from 'node:fs';
@@ -15,6 +21,48 @@ import { dirname, join } from 'node:path';
15
21
  import { fileURLToPath } from 'node:url';
16
22
  import { DATABASE } from '../constants.js';
17
23
  import { logger } from '../utils/logger.js';
24
+ import { extractSpawnFields } from '../event-fields.js';
25
+ import { decodeToolInput } from './codec/tool-input-codec.js';
26
+ /**
27
+ * Backfill window for events.decision_id / subagent_type (decision c425f26f,
28
+ * spec 1544 § 1.3, user ruling #4). The spec aligns the window to existing
29
+ * retention; the only retention constant that bounds recoverability is the
30
+ * event-ttl-sweep WARM TTL (default 7 days), past which `tool_input` is NULLed
31
+ * (gzip blob gone — nothing left to decode). We use 10 days (spec default) as a
32
+ * conservative-but-safe ceiling: rows older than the warm TTL simply have NULL
33
+ * tool_input and are skipped by the WHERE (`tool_input IS NOT NULL` implied by a
34
+ * successful decode). base.ts is in the leaf-most `core` layer and MUST NOT
35
+ * depend on the daemon ConfigStore (decision ed98c8e8), so this is a static
36
+ * constant, not a config read.
37
+ */
38
+ export const SPAWN_FIELD_BACKFILL_WINDOW = "-10 days";
39
+ /**
40
+ * Backfill window for the one-shot tasks.parent_task_id historical linkage
41
+ * (decision f47c2c90, spec 1711 § Phase 1.1, user ruling Q2 = -10 days). Aligned
42
+ * with SPAWN_FIELD_BACKFILL_WINDOW so the two boot-time backfills cover the same
43
+ * recent slice. Historical rows cannot read the in-memory agentJustReturned flag,
44
+ * so the backfill uses a WEAKER pure-SQL heuristic (ack-title + same session +
45
+ * ≤30min prior non-ack user task); anything ambiguous stays NULL (宁缺毋滥).
46
+ */
47
+ export const TASK_PARENT_BACKFILL_WINDOW = "-10 days";
48
+ /**
49
+ * Resume window in minutes (mirrors TASK_RESUME_WINDOW_MS=30min in the daemon
50
+ * TaskSegmenter). The parent backfill only links a follow-up ack task to a prior
51
+ * user task started within this window. Kept as a static constant here because
52
+ * base.ts is leaf-most core and MUST NOT depend on the daemon config (ed98c8e8).
53
+ */
54
+ const TASK_PARENT_BACKFILL_WINDOW_MIN = 30;
55
+ /**
56
+ * Conservative ack-title set for the parent backfill (decision f47c2c90). A
57
+ * follow-up task whose title is one of these short acknowledgements is treated
58
+ * as an approval/continue turn that should chain back to the prior user task.
59
+ * Mirrors the segmenter's ACK_CONTINUE_KEYWORDS spirit but is a SQL-side
60
+ * lowercase exact-match list (titles are short ack tokens, not free text).
61
+ */
62
+ const TASK_PARENT_ACK_TITLES = [
63
+ '批准', '同意', 'approve', '好', '好的', '嗯', 'ok', 'okay',
64
+ '可以', '是', '是的', '继续', 'yes', '对', '行', '没问题',
65
+ ];
18
66
  export class SQLiteBase {
19
67
  db;
20
68
  dbPath;
@@ -25,6 +73,20 @@ export class SQLiteBase {
25
73
  mkdirSync(dir, { recursive: true });
26
74
  }
27
75
  this.db = new Database(dbPath);
76
+ // ── Bootstrap PRAGMAs ─────────────────────────────────────────────────
77
+ //
78
+ // auto_vacuum MUST be set BEFORE any table is created on a new DB
79
+ // (SQLite requirement: see https://sqlite.org/pragma.html#pragma_auto_vacuum).
80
+ // On a fresh DB this sets the persistent header bit; on an existing DB it
81
+ // is a no-op and the conversion has to happen via VACUUM (handled below
82
+ // in `migrateAutoVacuumIfNeeded`).
83
+ //
84
+ // INCREMENTAL (=2) means free pages are kept on a freelist instead of
85
+ // being released at the OS level, and the daemon's TTL sweep can call
86
+ // `PRAGMA incremental_vacuum(N)` to reclaim N pages at a time without
87
+ // a full-table VACUUM. NONE (=0, the prior default) caused freelist
88
+ // growth on every TTL sweep with no way to shrink the on-disk file.
89
+ this.db.pragma('auto_vacuum = INCREMENTAL');
28
90
  // WAL mode optimization for better concurrency
29
91
  this.db.pragma('journal_mode = WAL');
30
92
  this.db.pragma('synchronous = NORMAL');
@@ -48,6 +110,73 @@ export class SQLiteBase {
48
110
  this.initSchema();
49
111
  this.runIndexMigrations();
50
112
  this.runPostMigrations();
113
+ this.migrateAutoVacuumIfNeeded();
114
+ }
115
+ /**
116
+ * One-shot migration: convert auto_vacuum from NONE (0) to INCREMENTAL (2)
117
+ * on existing DBs.
118
+ *
119
+ * Why this exists
120
+ * ---------------
121
+ * Setting `PRAGMA auto_vacuum = INCREMENTAL` in the constructor only takes
122
+ * effect on a *new* DB (before any table is created). On an existing DB it
123
+ * silently no-ops, so we must detect mode=0 and run a one-time `VACUUM`
124
+ * (which rewrites the whole file and flips the persistent header bit).
125
+ *
126
+ * Cost: O(DB size). For a 269 MB DB this is a few seconds of writer-lock.
127
+ * We log around it so an operator notices.
128
+ *
129
+ * Idempotent: after the first successful run, `auto_vacuum` reads as 2 and
130
+ * the migration short-circuits.
131
+ *
132
+ * Errors are warn-logged and swallowed — daemon startup must not fail.
133
+ * Worst case the DB stays on auto_vacuum=0 and the incremental_vacuum calls
134
+ * elsewhere become no-ops; freelist still grows but nothing breaks.
135
+ */
136
+ migrateAutoVacuumIfNeeded() {
137
+ try {
138
+ const current = this.db.pragma('auto_vacuum', { simple: true });
139
+ if (Number(current) === 2)
140
+ return; // already INCREMENTAL — done
141
+ logger.info(`[SQLiteStorage] migration: converting auto_vacuum ${current} → INCREMENTAL (2) via VACUUM (one-shot; may take seconds on large DBs)`);
142
+ const startMs = Date.now();
143
+ // Setting + VACUUM is the documented way to migrate. Both must execute
144
+ // outside any transaction; the constructor's caller has no open tx so
145
+ // we're safe.
146
+ this.db.pragma('auto_vacuum = INCREMENTAL');
147
+ this.db.exec('VACUUM');
148
+ const elapsedMs = Date.now() - startMs;
149
+ const after = this.db.pragma('auto_vacuum', { simple: true });
150
+ logger.info(`[SQLiteStorage] migration: auto_vacuum is now ${after} (took ${elapsedMs}ms)`);
151
+ }
152
+ catch (err) {
153
+ logger.warn(`[SQLiteStorage] migrateAutoVacuumIfNeeded failed: ${err}`);
154
+ }
155
+ }
156
+ /**
157
+ * Reclaim up to `maxPages` free pages from the auto_vacuum=INCREMENTAL
158
+ * freelist back to the OS. Returns the number of pages reclaimed.
159
+ *
160
+ * Called by the event-ttl-sweep service after TTL deletes accumulate free
161
+ * pages. Safe to call when auto_vacuum != INCREMENTAL — SQLite just returns
162
+ * 0 pages reclaimed.
163
+ *
164
+ * NOTE: not on the public SQLiteStorage facade by default — the daemon
165
+ * calls through `MaintenanceOperations.incrementalVacuum`. Kept here as a
166
+ * protected helper so any *Operations subclass can invoke it.
167
+ */
168
+ incrementalVacuumPages(maxPages) {
169
+ const before = this.db.pragma('freelist_count', { simple: true });
170
+ try {
171
+ this.db.exec(`PRAGMA incremental_vacuum(${Math.max(0, Math.floor(maxPages))})`);
172
+ }
173
+ catch (err) {
174
+ logger.warn(`[SQLiteStorage] incremental_vacuum(${maxPages}) failed: ${err}`);
175
+ return 0;
176
+ }
177
+ const after = this.db.pragma('freelist_count', { simple: true });
178
+ const reclaimed = Math.max(0, Number(before) - Number(after));
179
+ return reclaimed;
51
180
  }
52
181
  initSchema() {
53
182
  const thisDir = dirname(fileURLToPath(import.meta.url));
@@ -131,10 +260,189 @@ export class SQLiteBase {
131
260
  this.addColumnIfMissing('sessions', 'first_prompt', 'TEXT');
132
261
  this.addColumnIfMissing('routing_events', 'skill_confidence', 'REAL');
133
262
  this.addColumnIfMissing('routing_events', 'skill_source', 'TEXT');
263
+ // R9 (decision 1544, 2026-06-10): routing row provenance. NULL for normal
264
+ // hook-driven events; 'programmatic' for rows minted by code paths. Nullable,
265
+ // DEFAULT NULL keeps every legacy row untouched.
266
+ this.addColumnIfMissing('routing_events', 'source', 'TEXT');
134
267
  this.addColumnIfMissing('skill_invocations', 'workflow', 'TEXT');
135
268
  this.addColumnIfMissing('skill_invocations', 'phase', 'TEXT');
136
269
  this.addColumnIfMissing('skill_invocations', 'feature_slug', 'TEXT');
137
270
  this.addColumnIfMissing('skill_invocations', 'artifact_path', 'TEXT');
271
+ // audit #2 (decision f61b8a0c, 2026-06-09): distinguish "injected" rows from
272
+ // "really invoked" rows. The UserPromptSubmit auto-match path writes a row
273
+ // with success=1 the moment a skill is INJECTED — it never observes whether
274
+ // the skill was actually followed. That made every web "skill hit /
275
+ // effectiveness" metric (weekly-report / drift-detector / skill-stats) read
276
+ // injection counts as if they were real-call counts.
277
+ //
278
+ // Fix without breaking the old `success` semantics (5+ readers depend on the
279
+ // old column): add a NULLABLE marker `recorded_at_inject`. Auto-match
280
+ // injection rows stamp it 1; real-call rows (MCP skill_invoke /
281
+ // events.tool_name='Skill') leave it NULL. Readers filter on it to separate
282
+ // "injected" from "really invoked". DEFAULT NULL keeps legacy rows untouched.
283
+ this.addColumnIfMissing('skill_invocations', 'recorded_at_inject', 'INTEGER');
284
+ // Skill usefulness feedback (decision d24cd3a2 P0, spec
285
+ // docs/design/2026-06-11/1524-skill-usefulness-feedback-spec.md). Agent
286
+ // POST-USE self-assessment of whether a pulled skill's CONTENT was actionable
287
+ // on THIS project's task. DISTINCT from `success` (which only means the
288
+ // invoke call didn't throw) — usefulness measures content transfer.
289
+ // usefulness = 'helped' | 'partial' | 'not-actionable' (advisory enum,
290
+ // stored as free TEXT, nullable, DEFAULT NULL).
291
+ // usefulness_note = one-line "what was/wasn't applicable", nullable.
292
+ // Nullable + no backfill → every legacy row reads usefulness=NULL untouched,
293
+ // verbatim mirror of the reason/workflow/recorded_at_inject additive columns.
294
+ this.addColumnIfMissing('skill_invocations', 'usefulness', 'TEXT');
295
+ this.addColumnIfMissing('skill_invocations', 'usefulness_note', 'TEXT');
296
+ // Project scope (decision 39839e30 Part 2, 2026-06-13): the project a skill
297
+ // pull belongs to, so the workplace "Skill 调用" KPI can filter by project
298
+ // like the other 3 KPIs already do. Mirror of kb_query_log.project_path.
299
+ // Nullable, DEFAULT NULL → every legacy row reads project_path=NULL untouched;
300
+ // aggregations only add `AND project_path = ?` when a project is passed
301
+ // (additive, back-compat with Phase 2c / Skill 详情页 / cf skill usefulness).
302
+ // Historical rows are one-shot back-filled from sessions.project_path in
303
+ // runPostMigrations → backfillSkillInvocationsProjectPathIfNeeded (join miss
304
+ // → stays NULL).
305
+ this.addColumnIfMissing('skill_invocations', 'project_path', 'TEXT');
306
+ // Outcome instrumentation (v9.x). NOTE: SQLite ALTER TABLE ADD COLUMN can
307
+ // only add CHECK constraints that don't reference other rows — the
308
+ // outcome CHECK is therefore embedded in the column type clause below.
309
+ // spec 1100 Option C (2026-06-02): when ADDED on a fresh-ish legacy DB the
310
+ // column gets the RELAXED non-empty CHECK (matches schema.sql). DBs that
311
+ // already have the column with the OLD enum CHECK are widened in-place by
312
+ // rebuildOutcomeCheckIfNeeded (runPostMigrations).
313
+ this.addColumnIfMissing('sessions', 'outcome', `TEXT CHECK(outcome IS NULL OR length(outcome) > 0)`);
314
+ this.addColumnIfMissing('sessions', 'outcome_reason', 'TEXT');
315
+ this.addColumnIfMissing('sessions', 'commit_count', 'INTEGER DEFAULT 0');
316
+ this.addColumnIfMissing('sessions', 'reverted_commits', 'INTEGER DEFAULT 0');
317
+ this.addColumnIfMissing('sessions', 'user_violation_count', 'INTEGER DEFAULT 0');
318
+ this.addColumnIfMissing('sessions', 'classified_at', 'TEXT');
319
+ // Phase 2 metrics rollup (master roadmap §2): per-session counters.
320
+ // Default 0 keeps existing analytics queries (SUM/AVG) honest on legacy
321
+ // rows; back-fill happens at Stop time by classifyAndPersistOutcome.
322
+ this.addColumnIfMissing('sessions', 'intercept_count', 'INTEGER DEFAULT 0');
323
+ this.addColumnIfMissing('sessions', 'kb_inject_count', 'INTEGER DEFAULT 0');
324
+ this.addColumnIfMissing('sessions', 'skill_match_count', 'INTEGER DEFAULT 0');
325
+ // spec 1100 Option C (2026-06-02): relaxed CHECK (see sessions.outcome).
326
+ this.addColumnIfMissing('tasks', 'outcome', `TEXT CHECK(outcome IS NULL OR length(outcome) > 0)`);
327
+ this.addColumnIfMissing('tasks', 'outcome_reason', 'TEXT');
328
+ this.addColumnIfMissing('tasks', 'commit_count', 'INTEGER DEFAULT 0');
329
+ this.addColumnIfMissing('tasks', 'reverted_commits', 'INTEGER DEFAULT 0');
330
+ this.addColumnIfMissing('tasks', 'user_violation_count', 'INTEGER DEFAULT 0');
331
+ this.addColumnIfMissing('tasks', 'classified_at', 'TEXT');
332
+ // decision 265f59d5 (2026-06-08): LLM task-boundary classifier idempotency
333
+ // marker. Stamped on a task row when the async classifier (Option A) has
334
+ // already run for the prompt that minted it, so a re-delivered / replayed
335
+ // event never re-spawns claude or re-attributes the same prompt twice.
336
+ // Nullable TEXT (ISO timestamp); NULL = not yet classified.
337
+ this.addColumnIfMissing('tasks', 'llm_classified_at', 'TEXT');
338
+ // Task-tracking overhaul (2026-05-27): write-time noise classification.
339
+ // ALTER ADD COLUMN cannot enforce NOT NULL without a DEFAULT on legacy
340
+ // rows — DEFAULT 0 keeps existing data intact. The post-migration
341
+ // backfill (backfillTasksIsNoiseIfNeeded) flips matching rows to 1.
342
+ this.addColumnIfMissing('tasks', 'is_noise', 'INTEGER NOT NULL DEFAULT 0');
343
+ // spec b1480935 (2026-06-01): task_kind successor column. SQLite ALTER
344
+ // TABLE ADD COLUMN with NOT NULL DEFAULT 'user' back-fills every legacy
345
+ // row to 'user' atomically; the post-migration backfill
346
+ // (backfillTasksTaskKindIfNeeded) then promotes envelope/system rows
347
+ // to their granular kind via title-prefix sniff. The CHECK constraint
348
+ // here is the same one schema.sql declares for fresh DBs.
349
+ this.addColumnIfMissing('tasks', 'task_kind', `TEXT NOT NULL DEFAULT 'user' CHECK(task_kind IN ('user','agent-callback','image','system'))`);
350
+ // decision f47c2c90 (二期B, spec 1711): parent_task_id self-referencing FK
351
+ // for cross-turn workflow linkage on tasks that carry NO decision_id. The
352
+ // TaskSegmenter fills it (conservatively, triple-gate) for approval/continue
353
+ // follow-up turns; timeline aggregates the parent chain only when the task
354
+ // has no decision_id (else-branch fallback, strictly mutually exclusive with
355
+ // the decision_id path). Nullable, DEFAULT NULL → every legacy row untouched.
356
+ // SQLite ALTER ADD COLUMN cannot carry inline REFERENCES, so legacy DBs get
357
+ // a plain TEXT column with no FK enforcement — the app layer never relies on
358
+ // SQLite FK enforce (logical FK only). The one-shot backfill runs in
359
+ // runPostMigrations (backfillTasksParentIfNeeded).
360
+ this.addColumnIfMissing('tasks', 'parent_task_id', 'TEXT');
361
+ // C1 (spec 0854, 2026-06-02): the pending_specs table was retired and is
362
+ // DROPped by schema.sql. Its former `source` column migration + spec_path
363
+ // index migration were removed here — schema.sql runs AFTER these column
364
+ // migrations, so any addColumn/createIndex targeting pending_specs would
365
+ // hit a non-existent table on fresh DBs.
366
+ // v9.x MVP1: KB injection metadata column. Stores JSON array of KB hits
367
+ // (page name + score + refs) for the 'UserPromptSubmitHandler:kb' source.
368
+ this.addColumnIfMissing('injections', 'metadata_json', 'TEXT');
369
+ // KB 采纳 telemetry(decision 148f7a0a, 2026-06-10 审计):注入后同会话
370
+ // 出现主动 KB MCP 调用(mcp__claude-forge__knowledge*)时,PostToolUse
371
+ // handler 给该会话所有 source_handler LIKE '%:kb' 且 adopted_at IS NULL
372
+ // 的注入行盖 epoch-ms 时间戳。4 周后用一条 SQL 即可回答「注入的 KB 被
373
+ // 用了没」(adopted/total)。Nullable INTEGER;NULL = 从未被采纳。
374
+ this.addColumnIfMissing('injections', 'adopted_at', 'INTEGER');
375
+ // F3 (audit-20260522 migration 009): writer-side tool_output 50KB truncation
376
+ // marker. Legacy rows default to 0 (full content preserved).
377
+ this.addColumnIfMissing('events', 'tool_output_truncated', 'INTEGER DEFAULT 0');
378
+ // decision c425f26f (spec 1544): cross-task execution-chain aggregation.
379
+ // decision_id + subagent_type are extracted to PLAINTEXT columns so a SQL
380
+ // GROUP BY decision_id can stitch a workflow fragmented across per-prompt
381
+ // tasks. Both nullable, DEFAULT NULL → every legacy row untouched.
382
+ // CRITICAL: these are plaintext TEXT — they NEVER flow through the gzip
383
+ // codec (gzip one-way-door); the go-forward writer (events.ts) extracts them
384
+ // pre-codec, the one-shot backfill (runPostMigrations) decodes gzip once to
385
+ // fill historical rows. ALTER ADD COLUMN nullable is an O(1) metadata op
386
+ // (no row rewrite) so this is cheap even on the 295 MB events table.
387
+ this.addColumnIfMissing('events', 'decision_id', 'TEXT');
388
+ this.addColumnIfMissing('events', 'subagent_type', 'TEXT');
389
+ // decision-flow-overhaul (2026-05-28): link routing rows back to the decision
390
+ // that triggered the spawn. Both columns default NULL (additive).
391
+ this.addColumnIfMissing('routing_events', 'decision_id', 'TEXT');
392
+ this.addColumnIfMissing('routing_events', 'spawn_id', 'TEXT');
393
+ // decision d24cd3a2 Task B (2026-06-11): make agent KB pulls attributable.
394
+ // kb_query_log gains the same attribution fields as skill_invocations so a
395
+ // deliberate `cf knowledge query --reason` pull (source='cli') is
396
+ // distinguishable from the daemon's automatic per-prompt probe
397
+ // (source='daemon-probe'). All nullable — legacy rows stay NULL, no backfill.
398
+ this.addColumnIfMissing('kb_query_log', 'reason', 'TEXT');
399
+ this.addColumnIfMissing('kb_query_log', 'source', 'TEXT');
400
+ this.addColumnIfMissing('kb_query_log', 'agent_id', 'TEXT');
401
+ this.addColumnIfMissing('kb_query_log', 'workflow', 'TEXT');
402
+ this.addColumnIfMissing('kb_query_log', 'phase', 'TEXT');
403
+ // decision 096309e4 batch 1 item ① (2026-06-13): KB post-use usefulness
404
+ // self-assessment, mirroring skill_invocations.usefulness. An agent that
405
+ // pulled KB via `cf knowledge query/fetch --reason` rates whether the CONTENT
406
+ // helped on THIS task. Nullable + no backfill → legacy / daemon-probe rows
407
+ // read usefulness=NULL untouched. This is the real "KB was used AND helped"
408
+ // signal that the dead injections.adopted_at path (MCP-only, subagents have
409
+ // zero MCP) could never capture.
410
+ this.addColumnIfMissing('kb_query_log', 'usefulness', 'TEXT');
411
+ this.addColumnIfMissing('kb_query_log', 'usefulness_note', 'TEXT');
412
+ // decision-flow-overhaul (2026-05-28): update pending_specs.source CHECK to
413
+ // include 'decision'. SQLite does NOT support altering CHECK constraints on
414
+ // existing columns via ALTER TABLE, so for existing DBs the guard lives in
415
+ // application code (DecisionStore) rather than the schema. New DBs get the
416
+ // full CHECK via schema.sql CREATE TABLE.
417
+ // (no ALTER needed — addColumnIfMissing does nothing for existing columns)
418
+ // spec 1200 (2026-05-28): decision-maker recommended_agents/skills columns.
419
+ // Additive — existing rows get NULL by default.
420
+ this.addColumnIfMissing('decisions', 'recommended_agents', 'TEXT');
421
+ this.addColumnIfMissing('decisions', 'recommended_skills', 'TEXT');
422
+ // Option B (decision b95e0956, 2026-05-29) bypass-governance fields.
423
+ // bypass_flag=1 marks decisions resolved without a decision-maker spawn
424
+ // trace; bypass_reason holds the operator-supplied justification.
425
+ // Existing rows default to 0 / NULL — preserves legacy contract.
426
+ this.addColumnIfMissing('decisions', 'bypass_flag', 'INTEGER NOT NULL DEFAULT 0');
427
+ this.addColumnIfMissing('decisions', 'bypass_reason', 'TEXT');
428
+ // C1 (2026-06-02): unified approval subsystem. decisions absorbs the
429
+ // retired pending_specs table — kind distinguishes daemon-minted decision
430
+ // rows ('decision') from externally-registered spec rows ('spec'). The
431
+ // CHECK constraint lives in schema.sql for new DBs; legacy DBs get the
432
+ // column without the CHECK (enforced in app code), mirroring the existing
433
+ // status-CHECK migration note above. Existing rows default to 'decision'.
434
+ this.addColumnIfMissing('decisions', 'kind', "TEXT NOT NULL DEFAULT 'decision'");
435
+ this.addColumnIfMissing('decisions', 'spec_source', 'TEXT');
436
+ this.addColumnIfMissing('decisions', 'spec_intent_json', 'TEXT');
437
+ // decision-maker optimization Batch 1.1 (decision a5d5a85b, 2026-06-02):
438
+ // implementation-outcome column. NOTE: outcome (success|failed|partial) is
439
+ // the *implementation result* and is INDEPENDENT of status (the approval
440
+ // lifecycle pending/resolved/bypassed/expired). Mirrors the sessions/tasks
441
+ // outcome column convention (base.ts above). The enum is enforced in app
442
+ // code (writeDecisionOutcome); the column-level CHECK only guards non-empty
443
+ // — matching the relaxed sessions/tasks outcome CHECK so a future enum
444
+ // extension needs no in-place rebuild. Existing rows default to NULL.
445
+ this.addColumnIfMissing('decisions', 'outcome', `TEXT CHECK(outcome IS NULL OR length(outcome) > 0)`);
138
446
  }
139
447
  /**
140
448
  * Index migrations run AFTER initSchema(). Each call is guarded by hasIndex
@@ -148,22 +456,69 @@ export class SQLiteBase {
148
456
  runIndexMigrations() {
149
457
  this.createIndexIfMissing('idx_skill_invocations_workflow', `CREATE INDEX IF NOT EXISTS idx_skill_invocations_workflow ON skill_invocations(workflow, phase)`);
150
458
  this.createIndexIfMissing('idx_skill_invocations_feature', `CREATE INDEX IF NOT EXISTS idx_skill_invocations_feature ON skill_invocations(feature_slug)`);
459
+ // decision 39839e30 Part 2: project-scoped skill KPI filtering.
460
+ this.createIndexIfMissing('idx_skill_invocations_project', `CREATE INDEX IF NOT EXISTS idx_skill_invocations_project ON skill_invocations(project_path)`);
151
461
  this.createIndexIfMissing('idx_sessions_start_time', `CREATE INDEX IF NOT EXISTS idx_sessions_start_time ON sessions(start_time DESC)`);
152
462
  // Composite indexes for high-frequency session-scoped queries
153
463
  this.createIndexIfMissing('idx_events_session_ts', `CREATE INDEX IF NOT EXISTS idx_events_session_ts ON events(session_id, timestamp DESC)`);
154
464
  this.createIndexIfMissing('idx_routing_events_session_ts', `CREATE INDEX IF NOT EXISTS idx_routing_events_session_ts ON routing_events(session_id, ts DESC)`);
155
465
  this.createIndexIfMissing('idx_skill_invocations_session_ts', `CREATE INDEX IF NOT EXISTS idx_skill_invocations_session_ts ON skill_invocations(session_id, timestamp DESC)`);
466
+ // spec b1480935 (2026-06-01): task_kind index for hot WHERE filters.
467
+ this.createIndexIfMissing('idx_tasks_kind', `CREATE INDEX IF NOT EXISTS idx_tasks_kind ON tasks(task_kind)`);
468
+ // decision f47c2c90 (二期B): index on the parent FK column so the timeline
469
+ // chain query's `WHERE parent_task_id = ?` (向下收子 task) hits an index.
470
+ this.createIndexIfMissing('idx_tasks_parent', `CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task_id)`);
156
471
  // Phase 1 Refactor: Additional performance indexes
157
472
  this.createIndexIfMissing('idx_routing_events_obeyed_ts', `CREATE INDEX IF NOT EXISTS idx_routing_events_obeyed_ts ON routing_events(obeyed, ts DESC)`);
158
473
  this.createIndexIfMissing('idx_events_session_hook', `CREATE INDEX IF NOT EXISTS idx_events_session_hook ON events(session_id, hook_type, timestamp DESC)`);
474
+ // decision 7a3d07b5: covering index for the agent-board top_tools join.
475
+ // (event_id, hook_type, tool_name) lets the per-row events lookup satisfy the
476
+ // PostToolUse + tool_name filter and project tool_name without a table hit;
477
+ // paired with `INDEXED BY idx_task_events_task` in tasks.queryAgentBoardTasks
478
+ // it flips the join driver off the full PostToolUse scan (485ms → ~10ms).
479
+ this.createIndexIfMissing('idx_events_eid_hook_tool', `CREATE INDEX IF NOT EXISTS idx_events_eid_hook_tool ON events(event_id, hook_type, tool_name)`);
480
+ // decision c425f26f (spec 1544): cross-task decision_id aggregation indexes.
481
+ this.createIndexIfMissing('idx_events_decision_id', `CREATE INDEX IF NOT EXISTS idx_events_decision_id ON events(decision_id)`);
482
+ this.createIndexIfMissing('idx_events_decision_spawn', `CREATE INDEX IF NOT EXISTS idx_events_decision_spawn ON events(decision_id, hook_type, tool_name, timestamp)`);
159
483
  this.createIndexIfMissing('idx_injections_session_handler', `CREATE INDEX IF NOT EXISTS idx_injections_session_handler ON injections(session_id, source_handler)`);
160
484
  this.createIndexIfMissing('idx_routing_events_type_ts', `CREATE INDEX IF NOT EXISTS idx_routing_events_type_ts ON routing_events(routed_to_type, ts DESC)`);
485
+ // Outcome instrumentation indexes (v9.x)
486
+ this.createIndexIfMissing('idx_sessions_outcome', `CREATE INDEX IF NOT EXISTS idx_sessions_outcome ON sessions(outcome)`);
487
+ this.createIndexIfMissing('idx_sessions_project_outcome', `CREATE INDEX IF NOT EXISTS idx_sessions_project_outcome ON sessions(project_path, outcome)`);
488
+ this.createIndexIfMissing('idx_tasks_session_outcome', `CREATE INDEX IF NOT EXISTS idx_tasks_session_outcome ON tasks(session_id, outcome)`);
489
+ // C1 (spec 0854, 2026-06-02): pending_specs.spec_path UNIQUE index removed
490
+ // — the table is retired/DROPped by schema.sql. Its dedup role now lives on
491
+ // decisions (idx_decisions_approval_token + app-level findSpecByPath probe).
492
+ // decision-flow-overhaul (2026-05-28): index for decision → spawn JOIN.
493
+ this.createIndexIfMissing('idx_routing_decision', `CREATE INDEX IF NOT EXISTS idx_routing_decision ON routing_events(decision_id)`);
494
+ // decision-flow-overhaul (2026-05-28): indexes for decisions table (new DBs
495
+ // get these via schema.sql; legacy DBs need the migration guard here).
496
+ this.createIndexIfMissing('idx_decisions_session', `CREATE INDEX IF NOT EXISTS idx_decisions_session ON decisions(session_id, created_at DESC)`);
497
+ this.createIndexIfMissing('idx_decisions_status', `CREATE INDEX IF NOT EXISTS idx_decisions_status ON decisions(status, expires_at)`);
498
+ this.createIndexIfMissing('idx_decisions_trigger', `CREATE INDEX IF NOT EXISTS idx_decisions_trigger ON decisions(trigger_event_id)`);
499
+ // C1 (2026-06-02): spec-kind row lookups + partial-unique approval_token.
500
+ // New DBs get these via schema.sql; legacy DBs need the migration guard.
501
+ this.createIndexIfMissing('idx_decisions_kind_session', `CREATE INDEX IF NOT EXISTS idx_decisions_kind_session ON decisions(kind, session_id, status)`);
502
+ this.createIndexIfMissing('idx_decisions_approval_token', `CREATE UNIQUE INDEX IF NOT EXISTS idx_decisions_approval_token ON decisions(approval_token) WHERE approval_token IS NOT NULL`);
161
503
  }
162
504
  /**
163
505
  * One-shot data migrations + deprecated table cleanup.
164
506
  */
165
507
  runPostMigrations() {
166
508
  this.backfillSessionsIfNeeded();
509
+ this.rebuildWorkflowRecommendationsCheckIfNeeded();
510
+ this.rebuildOutcomeCheckIfNeeded();
511
+ this.widenDecisionsStatusCheckIfNeeded();
512
+ this.dropDecisionsWorkflowTypeIfNeeded();
513
+ this.dropDeadKbQueryLogColumnsIfNeeded();
514
+ this.dropTokenUsageIfNeeded();
515
+ this.dropRoutingIsForcedIfNeeded();
516
+ this.backfillRoutingRoutedToTypePending();
517
+ this.backfillTasksIsNoiseIfNeeded();
518
+ this.backfillTasksTaskKindIfNeeded();
519
+ this.backfillSkillInvocationsProjectPathIfNeeded();
520
+ this.backfillEventsDecisionIdIfNeeded();
521
+ this.backfillTasksParentIfNeeded();
167
522
  const deprecatedTables = [
168
523
  'quality_issues', 'distill_results', 'v2_decisions',
169
524
  'v2_tool_events', 'experiment_assignments', 'routing_rule_states',
@@ -175,6 +530,744 @@ export class SQLiteBase {
175
530
  catch { /* ignore */ }
176
531
  }
177
532
  }
533
+ /**
534
+ * Task-tracking overhaul (2026-05-27): one-shot back-fill of `tasks.is_noise`
535
+ * from existing title heuristics. Idempotent — runs every startup but the
536
+ * WHERE clause restricts to rows that don't yet match the new state. We do
537
+ * NOT include the semantic blocklist ('批准', 'approve', '好', 'ok', '可以'
538
+ * …) intentionally; those are real human acknowledgements and the Bug 1
539
+ * spec-approval path now absorbs them — see spec § 3.2.
540
+ *
541
+ * Backfill only sets is_noise=1; rows already marked stay marked. We never
542
+ * flip 1→0 here (a future writer change could reclassify a legacy noise
543
+ * row; that case is best handled by a one-shot script, not boot-time).
544
+ *
545
+ * Errors are warn-logged and swallowed — daemon startup must not fail on
546
+ * data backfill. Worst case the column stays 0 and the Web filter shows
547
+ * extra rows (which the user can spot and report).
548
+ */
549
+ backfillTasksIsNoiseIfNeeded() {
550
+ if (!this.hasTable('tasks'))
551
+ return;
552
+ if (!this.hasColumn('tasks', 'is_noise'))
553
+ return;
554
+ try {
555
+ // Spec § 3.2 + § R1: backfill is intentionally CONSERVATIVE — we flip
556
+ // envelope / single-word slash / sub-3-char titles, but EXEMPT the
557
+ // semantic blocklist ('批准', 'approve', '好', 'ok', '可以', '同意', …).
558
+ // Those titles are real human acknowledgements that historically got
559
+ // mis-classified as user task starts; the Web should now SHOW them
560
+ // (so the user sees how many "approve" replies were silently dropped
561
+ // pre-Bug-1 fix). Going forward, SpecGate.handleApproval intercepts
562
+ // them BEFORE TaskSegmenter runs so they never reach createTask.
563
+ const res = this.db
564
+ .prepare(`UPDATE tasks SET is_noise = 1
565
+ WHERE is_noise = 0
566
+ AND LOWER(trim(title)) NOT IN
567
+ ('批准', '同意', 'approve', '好', '好的', '嗯', 'ok', 'okay',
568
+ '可以', '是', '是的', '继续', '停', 'stop', 'yes', 'no')
569
+ AND (
570
+ length(trim(title)) < 3
571
+ OR title LIKE '<task-notification>%'
572
+ OR title LIKE '<system-reminder>%'
573
+ OR title LIKE '<local-command-stdout>%'
574
+ OR title LIKE '<command-message>%'
575
+ OR title LIKE '<command-name>%'
576
+ OR title LIKE '[Image #%'
577
+ OR (substr(title, 1, 1) = '/' AND instr(title, ' ') = 0)
578
+ )`)
579
+ .run();
580
+ if (res.changes > 0) {
581
+ logger.info(`[SQLiteStorage] migration: backfilled tasks.is_noise=1 on ${res.changes} rows`);
582
+ }
583
+ }
584
+ catch (err) {
585
+ logger.warn(`[SQLiteStorage] migration: backfillTasksIsNoiseIfNeeded failed: ${err}`);
586
+ }
587
+ }
588
+ /**
589
+ * spec b1480935 (2026-06-01 Option A § OQ Q3): one-shot back-fill of
590
+ * `tasks.task_kind` from existing title prefixes. The is_noise column
591
+ * is deprecated but we keep its backfill running first so legacy rows
592
+ * still have a usable filter signal during the transition window.
593
+ *
594
+ * Mapping (mirrors NOISE_PREFIX_TO_KIND in core/utils/noise-prompt.ts):
595
+ * - title LIKE '<task-notification>%' → 'agent-callback'
596
+ * - title LIKE '[Image #%' → 'image'
597
+ * - title LIKE '<system-reminder>%' / '<local-command-stdout>%' /
598
+ * '<command-message>%' / '<command-name>%' → 'system'
599
+ * - everything else → stays 'user' (default)
600
+ *
601
+ * Idempotent: WHERE task_kind = 'user' AND title LIKE ... so a second
602
+ * boot only touches rows that haven't been promoted yet. We never demote
603
+ * (1→0 for is_noise had the same invariant) — a row already classified as
604
+ * 'agent-callback' stays put even if a future writer would have called it
605
+ * 'system'.
606
+ *
607
+ * Errors are warn-logged and swallowed — daemon startup must not fail on
608
+ * a backfill. Worst case the column stays 'user' on a few legacy envelopes
609
+ * and they surface in the default Web view (cosmetic only).
610
+ */
611
+ backfillTasksTaskKindIfNeeded() {
612
+ if (!this.hasTable('tasks'))
613
+ return;
614
+ if (!this.hasColumn('tasks', 'task_kind'))
615
+ return;
616
+ try {
617
+ // Each kind gets its own UPDATE so we can log per-bucket counts (helpful
618
+ // diagnostic when a user reports "why did 50 rows just turn grey?").
619
+ // Using a single CASE WHEN would collapse the count to one line.
620
+ const updates = [
621
+ { kind: 'agent-callback', like: '<task-notification>%' },
622
+ { kind: 'image', like: '[Image #%' },
623
+ { kind: 'system', like: '<system-reminder>%' },
624
+ { kind: 'system', like: '<local-command-stdout>%' },
625
+ { kind: 'system', like: '<command-message>%' },
626
+ { kind: 'system', like: '<command-name>%' },
627
+ ];
628
+ let total = 0;
629
+ for (const { kind, like } of updates) {
630
+ const res = this.db
631
+ .prepare(`UPDATE tasks SET task_kind = ?
632
+ WHERE task_kind = 'user' AND title LIKE ?`)
633
+ .run(kind, like);
634
+ total += res.changes;
635
+ }
636
+ if (total > 0) {
637
+ logger.info(`[SQLiteStorage] migration: backfilled tasks.task_kind on ${total} rows`);
638
+ }
639
+ }
640
+ catch (err) {
641
+ logger.warn(`[SQLiteStorage] migration: backfillTasksTaskKindIfNeeded failed: ${err}`);
642
+ }
643
+ }
644
+ /**
645
+ * Migration (Spec 2 § B1): drop the rerank-related columns from
646
+ * `kb_query_log` (strategy / rerank_cache_hit / rerank_failed) and the
647
+ * compound index that referenced `strategy`. Idempotent — new DBs created
648
+ * from the current schema.sql skip this entirely; legacy DBs lose the dead
649
+ * columns on next boot.
650
+ *
651
+ * SQLite ≥ 3.35 supports ALTER TABLE DROP COLUMN; better-sqlite3 12.x ships
652
+ * 3.46 so we use that directly. Errors are warn-logged but never thrown —
653
+ * worst case the columns linger and the writer just stops populating them.
654
+ */
655
+ dropDeadKbQueryLogColumnsIfNeeded() {
656
+ if (!this.hasTable('kb_query_log'))
657
+ return;
658
+ try {
659
+ // Drop the index first (still references `strategy`).
660
+ this.db.exec(`DROP INDEX IF EXISTS idx_kb_query_log_project_strategy`);
661
+ }
662
+ catch (err) {
663
+ logger.warn(`[SQLiteStorage] migration: drop idx_kb_query_log_project_strategy failed: ${err}`);
664
+ }
665
+ for (const col of ['strategy', 'rerank_cache_hit', 'rerank_failed']) {
666
+ if (!this.hasColumn('kb_query_log', col))
667
+ continue;
668
+ try {
669
+ this.db.exec(`ALTER TABLE kb_query_log DROP COLUMN ${col}`);
670
+ logger.info(`[SQLiteStorage] migration: dropped kb_query_log.${col}`);
671
+ }
672
+ catch (err) {
673
+ logger.warn(`[SQLiteStorage] migration: drop kb_query_log.${col} failed: ${err}`);
674
+ }
675
+ }
676
+ }
677
+ /**
678
+ * Migration (Spec 2 § B2): drop the unused `token_usage` table + indexes.
679
+ * 7d evidence showed 0 rows; the only "live" writer path was never wired
680
+ * through TokenTracker, so deleting is safe. Idempotent — DROP TABLE IF
681
+ * EXISTS noops on new DBs (schema.sql no longer declares the table).
682
+ */
683
+ dropTokenUsageIfNeeded() {
684
+ try {
685
+ this.db.exec(`DROP INDEX IF EXISTS idx_token_usage_session`);
686
+ this.db.exec(`DROP INDEX IF EXISTS idx_token_usage_timestamp`);
687
+ this.db.exec(`DROP TABLE IF EXISTS token_usage`);
688
+ }
689
+ catch (err) {
690
+ logger.warn(`[SQLiteStorage] migration: drop token_usage failed: ${err}`);
691
+ }
692
+ }
693
+ /**
694
+ * Migration (Spec 2 § B3): drop `routing_events.is_forced`. 7d evidence
695
+ * showed 0 rows with is_forced=1 — the field was reserved for a feature
696
+ * (forced/fallback routing) that was never wired. ALTER TABLE DROP COLUMN
697
+ * lands the column removal in-place; SQLite ≥ 3.35 required.
698
+ */
699
+ dropRoutingIsForcedIfNeeded() {
700
+ if (!this.hasTable('routing_events'))
701
+ return;
702
+ if (!this.hasColumn('routing_events', 'is_forced'))
703
+ return;
704
+ try {
705
+ this.db.exec(`ALTER TABLE routing_events DROP COLUMN is_forced`);
706
+ logger.info(`[SQLiteStorage] migration: dropped routing_events.is_forced`);
707
+ }
708
+ catch (err) {
709
+ logger.warn(`[SQLiteStorage] migration: drop routing_events.is_forced failed: ${err}`);
710
+ }
711
+ }
712
+ /**
713
+ * Migration (Spec 2 § B4): backfill `routing_events.routed_to_type='pending'`
714
+ * for the historical rows that user-prompt.ts wrote with NULL placeholder.
715
+ * 7d evidence showed 297/555 (54%) rows had NULL; with the new write-side
716
+ * default already minting 'pending', this one-shot UPDATE realigns history.
717
+ */
718
+ backfillRoutingRoutedToTypePending() {
719
+ if (!this.hasTable('routing_events'))
720
+ return;
721
+ try {
722
+ const res = this.db
723
+ .prepare(`UPDATE routing_events SET routed_to_type='pending' WHERE routed_to_type IS NULL`)
724
+ .run();
725
+ if (res.changes > 0) {
726
+ logger.info(`[SQLiteStorage] migration: backfilled routed_to_type='pending' on ${res.changes} rows`);
727
+ }
728
+ }
729
+ catch (err) {
730
+ logger.warn(`[SQLiteStorage] migration: backfill routed_to_type='pending' failed: ${err}`);
731
+ }
732
+ }
733
+ /**
734
+ * One-shot back-fill of skill_invocations.project_path from
735
+ * sessions.project_path (decision 39839e30 Part 2). A skill pull's session_id
736
+ * JOINs sessions to recover the project it belonged to. Idempotent: the WHERE
737
+ * clause restricts to `project_path IS NULL AND session_id IS NOT NULL`, so a
738
+ * second startup touches 0 rows. Rows whose session can't be joined (sentinel
739
+ * session 'cli-no-session', or a session not in the sessions table) stay NULL
740
+ * — we deliberately do NOT invent a project for them.
741
+ *
742
+ * Errors are warn-logged and swallowed — daemon startup must not fail on a
743
+ * data back-fill; worst case some legacy rows stay project_path=NULL and only
744
+ * the all-projects view counts them.
745
+ */
746
+ backfillSkillInvocationsProjectPathIfNeeded() {
747
+ if (!this.hasTable('skill_invocations'))
748
+ return;
749
+ if (!this.hasColumn('skill_invocations', 'project_path'))
750
+ return;
751
+ try {
752
+ const res = this.db.prepare(`
753
+ UPDATE skill_invocations
754
+ SET project_path = (
755
+ SELECT s.project_path FROM sessions s
756
+ WHERE s.session_id = skill_invocations.session_id
757
+ )
758
+ WHERE project_path IS NULL
759
+ AND session_id IS NOT NULL
760
+ AND EXISTS (
761
+ SELECT 1 FROM sessions s2
762
+ WHERE s2.session_id = skill_invocations.session_id
763
+ AND s2.project_path IS NOT NULL
764
+ )
765
+ `).run();
766
+ if (res.changes > 0) {
767
+ logger.info(`[SQLiteStorage] migration: back-filled skill_invocations.project_path on ${res.changes} rows from sessions`);
768
+ }
769
+ }
770
+ catch (err) {
771
+ logger.warn(`[SQLiteStorage] migration: backfill skill_invocations.project_path failed: ${err}`);
772
+ }
773
+ }
774
+ /**
775
+ * decision f47c2c90 (二期B, spec 1711 § Phase 1.1): one-shot, idempotent,
776
+ * gzip-free backfill of `tasks.parent_task_id` for recent ack/continue-class
777
+ * follow-up tasks that have no parent linked yet.
778
+ *
779
+ * Why gzip-free + weaker than go-forward: this runs over HISTORY, which has no
780
+ * in-memory `agentJustReturned` flag to read (R2). It uses a pure-SQL heuristic
781
+ * over the plaintext tasks columns ONLY (title / start_time / session_id —
782
+ * never the gzip events.tool_input, R7). Conservatism over recall:
783
+ * - child candidate: task_kind='user', parent_task_id IS NULL, title is a
784
+ * short ack token (TASK_PARENT_ACK_TITLES), start_time within the window.
785
+ * - parent: the MOST RECENT same-session task_kind='user' task whose
786
+ * start_time is STRICTLY earlier than the child AND within 30min AND whose
787
+ * title is NOT itself an ack token (avoid ack→ack chains, prefer a
788
+ * substantive originating task). No qualifying parent → stays NULL.
789
+ * - never self-links (parent.id != child.id is implied by strict earlier
790
+ * start_time + the explicit guard below).
791
+ *
792
+ * Idempotent gate: only runs when at least one un-linked recent ack child
793
+ * exists; the UPDATE itself only touches `parent_task_id IS NULL` rows, so a
794
+ * second boot updates 0 rows (success criterion: `backfilled 0 rows`).
795
+ *
796
+ * Wrapped in a transaction. Errors are warn-logged and swallowed — daemon
797
+ * startup must not fail on a data backfill. Time math uses
798
+ * `datetime('now', ?)` + ISO lexical comparison (tasks.start_time is ISO TEXT;
799
+ * NO numeric probe — DB column type landmine, MEMORY).
800
+ */
801
+ backfillTasksParentIfNeeded() {
802
+ if (!this.hasTable('tasks'))
803
+ return;
804
+ if (!this.hasColumn('tasks', 'parent_task_id'))
805
+ return;
806
+ try {
807
+ const ackPh = TASK_PARENT_ACK_TITLES.map(() => '?').join(',');
808
+ // Idempotent gate: any un-linked recent ack child left to consider?
809
+ const pending = this.db.prepare(`SELECT 1 FROM tasks
810
+ WHERE task_kind = 'user'
811
+ AND parent_task_id IS NULL
812
+ AND LOWER(trim(title)) IN (${ackPh})
813
+ AND start_time >= datetime('now', ?)
814
+ LIMIT 1`).get(...TASK_PARENT_ACK_TITLES, TASK_PARENT_BACKFILL_WINDOW);
815
+ if (!pending)
816
+ return;
817
+ // Correlated UPDATE: for each eligible ack child, pick the most recent
818
+ // same-session non-ack user task strictly earlier and within 30min.
819
+ const upd = this.db.prepare(`UPDATE tasks AS child
820
+ SET parent_task_id = (
821
+ SELECT p.id FROM tasks p
822
+ WHERE p.session_id = child.session_id
823
+ AND p.task_kind = 'user'
824
+ AND p.id != child.id
825
+ AND p.start_time < child.start_time
826
+ AND p.start_time >= datetime(child.start_time, '-${TASK_PARENT_BACKFILL_WINDOW_MIN} minutes')
827
+ AND LOWER(trim(p.title)) NOT IN (${ackPh})
828
+ ORDER BY p.start_time DESC
829
+ LIMIT 1
830
+ )
831
+ WHERE child.task_kind = 'user'
832
+ AND child.parent_task_id IS NULL
833
+ AND LOWER(trim(child.title)) IN (${ackPh})
834
+ AND child.start_time >= datetime('now', ?)
835
+ AND EXISTS (
836
+ SELECT 1 FROM tasks p2
837
+ WHERE p2.session_id = child.session_id
838
+ AND p2.task_kind = 'user'
839
+ AND p2.id != child.id
840
+ AND p2.start_time < child.start_time
841
+ AND p2.start_time >= datetime(child.start_time, '-${TASK_PARENT_BACKFILL_WINDOW_MIN} minutes')
842
+ AND LOWER(trim(p2.title)) NOT IN (${ackPh})
843
+ )`);
844
+ let changes = 0;
845
+ const tx = this.db.transaction(() => {
846
+ const res = upd.run(...TASK_PARENT_ACK_TITLES, // parent NOT IN (subquery)
847
+ ...TASK_PARENT_ACK_TITLES, // child IN (WHERE)
848
+ TASK_PARENT_BACKFILL_WINDOW, ...TASK_PARENT_ACK_TITLES);
849
+ changes = res.changes;
850
+ });
851
+ tx();
852
+ if (changes > 0) {
853
+ logger.info(`[SQLiteStorage] migration: backfilled tasks.parent_task_id on ${changes} rows`);
854
+ }
855
+ }
856
+ catch (err) {
857
+ logger.warn(`[SQLiteStorage] migration: backfillTasksParentIfNeeded failed: ${err}`);
858
+ }
859
+ }
860
+ /**
861
+ * decision c425f26f (spec 1544 § 1.3): one-shot, idempotent backfill of the
862
+ * PLAINTEXT `events.decision_id` / `events.subagent_type` columns for recent
863
+ * Task/Agent spawn rows whose values still live only inside the gzip
864
+ * `tool_input` blob.
865
+ *
866
+ * Idempotent gate: only spawn rows in the backfill window where BOTH new
867
+ * columns are still NULL are touched, so a second daemon boot updates 0 rows
868
+ * (success criterion: `backfilled 0 rows`).
869
+ *
870
+ * gzip one-way-door: we DECODE `tool_input` via the codec (sniffs gzip magic),
871
+ * run `extractSpawnFields` on the decoded object, then write the extracted
872
+ * strings to the plaintext columns. The columns themselves never see gzip.
873
+ * Rows whose `tool_input` was already NULLed by the warm-TTL sweep have
874
+ * nothing to decode and are skipped (decode → undefined → both NULL, but the
875
+ * WHERE already excludes most via `tool_input IS NOT NULL`).
876
+ *
877
+ * Per-row try/catch: one malformed gzip blob never aborts the batch. Wrapped
878
+ * in a single transaction. Errors are warn-logged and swallowed — daemon
879
+ * startup must not fail on a data backfill.
880
+ *
881
+ * This is the boot-time wrapper (gated). The re-runnable engine lives in
882
+ * {@link backfillEventsDecisionId} so `cf maintenance backfill-spawn-fields`
883
+ * can force a full re-scan of the window.
884
+ */
885
+ backfillEventsDecisionIdIfNeeded() {
886
+ if (!this.hasTable('events'))
887
+ return;
888
+ if (!this.hasColumn('events', 'decision_id') || !this.hasColumn('events', 'subagent_type'))
889
+ return;
890
+ try {
891
+ // Idempotent gate: any un-backfilled recent spawn row left?
892
+ const pending = this.db.prepare(`SELECT 1 FROM events
893
+ WHERE hook_type = 'PreToolUse'
894
+ AND tool_name IN ('Task','Agent')
895
+ AND tool_input IS NOT NULL
896
+ AND decision_id IS NULL AND subagent_type IS NULL
897
+ AND timestamp >= datetime('now', ?)
898
+ LIMIT 1`).get(SPAWN_FIELD_BACKFILL_WINDOW);
899
+ if (!pending)
900
+ return;
901
+ const n = this.backfillEventsDecisionId();
902
+ if (n > 0) {
903
+ logger.info(`[SQLiteStorage] migration: backfilled events.decision_id/subagent_type on ${n} rows`);
904
+ }
905
+ }
906
+ catch (err) {
907
+ logger.warn(`[SQLiteStorage] migration: backfillEventsDecisionIdIfNeeded failed: ${err}`);
908
+ }
909
+ }
910
+ /**
911
+ * Re-runnable engine for the decision_id / subagent_type backfill (decision
912
+ * c425f26f, user ruling #3 manual fallback). Scans the backfill window for
913
+ * Pre/Post Task/Agent spawn rows that still have NULL plaintext columns,
914
+ * decodes their gzip `tool_input`, and writes the extracted fields. Returns
915
+ * the number of rows updated. Safe to call repeatedly (idempotent: only NULL
916
+ * rows are touched). Exposed via the SQLiteStorage facade for the
917
+ * `cf maintenance backfill-spawn-fields` command.
918
+ */
919
+ backfillEventsDecisionId() {
920
+ if (!this.hasTable('events'))
921
+ return 0;
922
+ if (!this.hasColumn('events', 'decision_id') || !this.hasColumn('events', 'subagent_type'))
923
+ return 0;
924
+ const rows = this.db.prepare(`SELECT event_id, tool_name, tool_input FROM events
925
+ WHERE hook_type IN ('PreToolUse','PostToolUse')
926
+ AND tool_name IN ('Task','Agent')
927
+ AND tool_input IS NOT NULL
928
+ AND decision_id IS NULL AND subagent_type IS NULL
929
+ AND timestamp >= datetime('now', ?)`).all(SPAWN_FIELD_BACKFILL_WINDOW);
930
+ if (rows.length === 0)
931
+ return 0;
932
+ const upd = this.db.prepare(`UPDATE events SET decision_id = ?, subagent_type = ? WHERE event_id = ?`);
933
+ let updated = 0;
934
+ const tx = this.db.transaction(() => {
935
+ for (const row of rows) {
936
+ try {
937
+ const decoded = decodeToolInput(row.tool_input);
938
+ const { decisionId, subagentType } = extractSpawnFields(row.tool_name, decoded);
939
+ // Only write when we actually extracted something — leaving both NULL
940
+ // for unparseable / field-less rows keeps the idempotent gate honest
941
+ // (they'd otherwise be re-scanned but never spuriously marked done).
942
+ if (decisionId === null && subagentType === null)
943
+ continue;
944
+ upd.run(decisionId, subagentType, row.event_id);
945
+ updated++;
946
+ }
947
+ catch (err) {
948
+ logger.warn(`[SQLiteStorage] backfillEventsDecisionId: skip row ${row.event_id}: ${err}`);
949
+ }
950
+ }
951
+ });
952
+ tx();
953
+ return updated;
954
+ }
955
+ /**
956
+ * Migration 010: widen workflow_recommendations.outcome CHECK to include
957
+ * 'partial_accepted'. SQLite cannot ALTER a CHECK constraint in place — we
958
+ * detect legacy tables (CHECK string does NOT contain 'partial_accepted')
959
+ * and rebuild via temp-table copy/drop/rename. Idempotent — new DBs
960
+ * already created by schema.sql carry the new CHECK and skip.
961
+ *
962
+ * Errors are warn-logged but never thrown — daemon startup must not fail
963
+ * on a migration; worst case the new outcome value just gets rejected at
964
+ * write time and the calling code's try/catch swallows it (writes here are
965
+ * fire-and-forget observability).
966
+ */
967
+ rebuildWorkflowRecommendationsCheckIfNeeded() {
968
+ if (!this.hasTable('workflow_recommendations'))
969
+ return;
970
+ try {
971
+ const sqlRow = this.db
972
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='workflow_recommendations'`)
973
+ .get();
974
+ if (!sqlRow || !sqlRow.sql)
975
+ return;
976
+ if (sqlRow.sql.includes('partial_accepted'))
977
+ return; // already widened
978
+ logger.info('[SQLiteStorage] migration 010: widening workflow_recommendations.outcome CHECK to include partial_accepted');
979
+ const rebuild = this.db.transaction(() => {
980
+ // 1) create the new table with widened CHECK
981
+ this.db.exec(`
982
+ CREATE TABLE workflow_recommendations_new (
983
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
984
+ session_id TEXT NOT NULL,
985
+ timestamp TEXT NOT NULL,
986
+ rule_id TEXT NOT NULL,
987
+ matched_keywords TEXT,
988
+ recommended_workflow TEXT NOT NULL,
989
+ recommended_agent_type TEXT NOT NULL,
990
+ reason TEXT,
991
+ outcome TEXT CHECK(outcome IS NULL OR outcome IN ('pending','accepted','partial_accepted','rejected','ignored','bypassed')),
992
+ outcome_at TEXT,
993
+ source TEXT DEFAULT 'workflow_classifier',
994
+ created_at TEXT DEFAULT (datetime('now'))
995
+ );
996
+ `);
997
+ // 2) copy rows preserving id
998
+ this.db.exec(`
999
+ INSERT INTO workflow_recommendations_new (
1000
+ id, session_id, timestamp, rule_id, matched_keywords,
1001
+ recommended_workflow, recommended_agent_type, reason,
1002
+ outcome, outcome_at, source, created_at
1003
+ )
1004
+ SELECT id, session_id, timestamp, rule_id, matched_keywords,
1005
+ recommended_workflow, recommended_agent_type, reason,
1006
+ outcome, outcome_at, source, created_at
1007
+ FROM workflow_recommendations;
1008
+ `);
1009
+ // 3) drop old + rename new (indexes auto-dropped with table; recreated below)
1010
+ this.db.exec(`DROP TABLE workflow_recommendations;`);
1011
+ this.db.exec(`ALTER TABLE workflow_recommendations_new RENAME TO workflow_recommendations;`);
1012
+ // 4) recreate indexes (mirrors schema.sql lines 378-379)
1013
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_workflow_rec_session ON workflow_recommendations(session_id, outcome);`);
1014
+ this.db.exec(`CREATE INDEX IF NOT EXISTS idx_workflow_rec_ts ON workflow_recommendations(timestamp DESC);`);
1015
+ });
1016
+ rebuild();
1017
+ logger.info('[SQLiteStorage] migration 010: workflow_recommendations rebuild complete');
1018
+ }
1019
+ catch (err) {
1020
+ logger.warn(`[SQLiteStorage] migration 010: rebuild failed: ${err}`);
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Migration 011 (spec 1100 Option C, 2026-06-02): widen the `outcome` CHECK
1025
+ * on `sessions` + `tasks` from the fixed value enum
1026
+ * `IN ('success','partial','failed','abandoned')` to a non-empty-string
1027
+ * guard `length(outcome) > 0`. This lets the classifier emit the new
1028
+ * `answered` outcome (and any future value) WITHOUT a table rebuild per
1029
+ * value. The rebuild here is the ONE-TIME widening for existing live DBs.
1030
+ *
1031
+ * Why a rebuild: SQLite cannot ALTER a CHECK constraint in place. We mirror
1032
+ * the migration-010 pattern: CREATE *_new → INSERT SELECT → DROP old →
1033
+ * RENAME → recreate indexes.
1034
+ *
1035
+ * Robustness choices:
1036
+ * - **Idempotent**: detected by sniffing the stored CREATE TABLE `sql`. If
1037
+ * it no longer contains the old enum fragment (`outcome IN (`) we skip —
1038
+ * a second boot is a no-op. New DBs created from current schema.sql carry
1039
+ * the relaxed CHECK already and skip.
1040
+ * - **Data-preserving**: we don't hand-write the new column list. We take
1041
+ * the table's existing CREATE statement and string-replace ONLY the
1042
+ * outcome CHECK fragment, so every column (incl. migration-added ones
1043
+ * like task_kind / intercept_count) is preserved verbatim, then copy all
1044
+ * rows with `INSERT INTO new SELECT * FROM old`.
1045
+ * - **Index-preserving**: we snapshot every non-autoindex on the table
1046
+ * from sqlite_master BEFORE the drop and replay each `sql` after rename.
1047
+ * - **FK-safe**: tasks is referenced by task_events(task_id) FK. We run the
1048
+ * whole rebuild inside a transaction with foreign_keys temporarily OFF so
1049
+ * the DROP/RENAME doesn't cascade-delete task_events rows. (PRAGMA
1050
+ * foreign_keys is a no-op inside a transaction in SQLite, so we toggle it
1051
+ * around the transaction.)
1052
+ *
1053
+ * Errors are warn-logged, never thrown — daemon startup must not fail. Worst
1054
+ * case the old enum CHECK lingers and writing `answered` is rejected at write
1055
+ * time (callers swallow the throw); the operator can re-run after the next
1056
+ * build.
1057
+ */
1058
+ rebuildOutcomeCheckIfNeeded() {
1059
+ for (const table of ['sessions', 'tasks']) {
1060
+ try {
1061
+ if (!this.hasTable(table))
1062
+ continue;
1063
+ const sqlRow = this.db
1064
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name=?`)
1065
+ .get(table);
1066
+ if (!sqlRow || !sqlRow.sql)
1067
+ continue;
1068
+ // Detect the OLD enum CHECK. The relaxed form uses `length(outcome)`,
1069
+ // so the presence of `outcome IN (` is the legacy marker.
1070
+ if (!/outcome\s+IN\s*\(/i.test(sqlRow.sql))
1071
+ continue; // already widened
1072
+ logger.info(`[SQLiteStorage] migration 011: widening ${table}.outcome CHECK (enum → non-empty) via table rebuild`);
1073
+ // Build the new CREATE statement by replacing the legacy outcome CHECK
1074
+ // fragment in-place. Two known shapes (sessions vs tasks columns differ
1075
+ // but the outcome CHECK fragment is identical):
1076
+ // outcome TEXT CHECK(outcome IS NULL OR outcome IN ('success', 'partial', 'failed', 'abandoned'))
1077
+ const newTableName = `${table}_oc_new`;
1078
+ const newCreate = sqlRow.sql
1079
+ .replace(/outcome\s+TEXT\s+CHECK\s*\(\s*outcome\s+IS\s+NULL\s+OR\s+outcome\s+IN\s*\([^)]*\)\s*\)/i, 'outcome TEXT CHECK(outcome IS NULL OR length(outcome) > 0)')
1080
+ // Point the CREATE at the temp table name. The original name appears
1081
+ // right after CREATE TABLE (optionally quoted) — replace the FIRST
1082
+ // occurrence only.
1083
+ .replace(new RegExp(`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?["'\`]?${table}["'\`]?`, 'i'), `CREATE TABLE ${newTableName}`);
1084
+ if (newCreate === sqlRow.sql || newCreate.includes(`outcome IN (`)) {
1085
+ logger.warn(`[SQLiteStorage] migration 011: could not rewrite ${table}.outcome CHECK (unexpected DDL shape) — skipping`);
1086
+ continue;
1087
+ }
1088
+ // Snapshot user indexes on the table (skip auto-indexes which have NULL sql).
1089
+ const indexRows = this.db
1090
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name=? AND sql IS NOT NULL`)
1091
+ .all(table);
1092
+ // task_events FK references tasks(id); toggle FK enforcement off around
1093
+ // the transaction so DROP TABLE tasks doesn't cascade.
1094
+ const fkOn = this.db.pragma('foreign_keys', { simple: true });
1095
+ if (Number(fkOn) === 1)
1096
+ this.db.pragma('foreign_keys = OFF');
1097
+ try {
1098
+ const rebuild = this.db.transaction(() => {
1099
+ this.db.exec(newCreate);
1100
+ this.db.exec(`INSERT INTO ${newTableName} SELECT * FROM ${table};`);
1101
+ this.db.exec(`DROP TABLE ${table};`);
1102
+ this.db.exec(`ALTER TABLE ${newTableName} RENAME TO ${table};`);
1103
+ for (const idx of indexRows) {
1104
+ // idx.sql is the original CREATE INDEX — replay verbatim. Make it
1105
+ // idempotent in case schema.sql already recreated it on this boot.
1106
+ const ddl = idx.sql.replace(/CREATE\s+(UNIQUE\s+)?INDEX\s+/i, (m) => /IF\s+NOT\s+EXISTS/i.test(idx.sql) ? m : `${m}IF NOT EXISTS `);
1107
+ this.db.exec(ddl);
1108
+ }
1109
+ });
1110
+ rebuild();
1111
+ }
1112
+ finally {
1113
+ if (Number(fkOn) === 1)
1114
+ this.db.pragma('foreign_keys = ON');
1115
+ }
1116
+ logger.info(`[SQLiteStorage] migration 011: ${table}.outcome CHECK widened`);
1117
+ }
1118
+ catch (err) {
1119
+ logger.warn(`[SQLiteStorage] migration 011: ${table} rebuild failed: ${err}`);
1120
+ }
1121
+ }
1122
+ }
1123
+ /**
1124
+ * Migration 012 (decision 0fc1883c, 2026-06-08): DROP the dead
1125
+ * `decisions.workflow_type` column. It was hard-coded to the literal
1126
+ * 'pending' by decision-hint.ts (daemon no longer pre-classifies) and had
1127
+ * ZERO consumers — no UPDATE path, no business logic branch. (The
1128
+ * `intent.workflow_type` read by rules/pipeline-rollup is a DIFFERENT field
1129
+ * sourced from injection metadata, NOT this column.)
1130
+ *
1131
+ * SQLite cannot reliably DROP COLUMN on older engines, so we mirror the
1132
+ * migration-010/011 table-rebuild pattern: read the table's stored CREATE
1133
+ * statement, strip the `workflow_type` line, CREATE the temp table, copy
1134
+ * every OTHER column by EXPLICIT name (never `SELECT *` — the live column
1135
+ * ORDER differs from schema.sql because migration-added columns are appended),
1136
+ * DROP old, RENAME, replay indexes.
1137
+ *
1138
+ * Robustness choices:
1139
+ * - **Idempotent**: guarded by hasColumn — if workflow_type is already gone
1140
+ * (fresh DB from current schema.sql, or a prior boot) this is a no-op.
1141
+ * - **Data-preserving**: copies all non-workflow_type columns by name, so
1142
+ * every decision row keeps its other fields verbatim.
1143
+ * - **Index-preserving**: snapshots user indexes before the drop and replays
1144
+ * each `sql` after rename (made IF NOT EXISTS so schema.sql's recreate on
1145
+ * the same boot doesn't clash).
1146
+ *
1147
+ * Errors are warn-logged, never thrown — daemon startup must not fail on a
1148
+ * migration. Worst case the dead column lingers (harmless — nothing reads it).
1149
+ */
1150
+ /**
1151
+ * Migration 013 (decision 93e8fff1, 2026-06-08): widen the
1152
+ * `decisions.status` CHECK to include 'advisory'. The advisory mint default
1153
+ * (writeDecision) writes status='advisory', which the legacy CHECK
1154
+ * (`status IN ('pending','resolved','bypassed','expired')`) would REJECT on
1155
+ * existing live DBs — SQLite cannot ALTER a CHECK in place, so we mirror the
1156
+ * migration-011/012 table-rebuild pattern: read the stored CREATE, string-
1157
+ * replace ONLY the status CHECK fragment, CREATE temp → INSERT SELECT * →
1158
+ * DROP → RENAME → replay indexes.
1159
+ *
1160
+ * Robustness:
1161
+ * - **Idempotent**: detected by sniffing the stored CREATE for the legacy
1162
+ * status enum WITHOUT 'advisory'. New DBs (schema.sql already carries
1163
+ * 'advisory') and a second boot are no-ops.
1164
+ * - **Data-preserving**: copies every column verbatim via `SELECT *`.
1165
+ * - **Index-preserving**: snapshots non-autoindexes before the drop, replays
1166
+ * each (made IF NOT EXISTS so schema.sql's recreate on the same boot is
1167
+ * harmless).
1168
+ *
1169
+ * Errors are warn-logged, never thrown — daemon startup must not fail on a
1170
+ * migration. Worst case the old CHECK lingers and a fresh advisory write is
1171
+ * rejected at write time (writeDecision callers fail-silent), and the operator
1172
+ * can re-run after the next build.
1173
+ */
1174
+ widenDecisionsStatusCheckIfNeeded() {
1175
+ try {
1176
+ if (!this.hasTable('decisions'))
1177
+ return;
1178
+ const sqlRow = this.db
1179
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='decisions'`)
1180
+ .get();
1181
+ if (!sqlRow || !sqlRow.sql)
1182
+ return;
1183
+ // Already widened? The new CHECK contains 'advisory'. Skip if present.
1184
+ if (/status\s+IN\s*\([^)]*'advisory'/i.test(sqlRow.sql))
1185
+ return;
1186
+ // Only act when the legacy status CHECK enum is present.
1187
+ if (!/status\s+IN\s*\(\s*'pending'/i.test(sqlRow.sql))
1188
+ return;
1189
+ logger.info('[SQLiteStorage] migration 013: widening decisions.status CHECK to include advisory via table rebuild');
1190
+ const newTableName = 'decisions_st_new';
1191
+ const newCreate = sqlRow.sql
1192
+ .replace(
1193
+ // Match the status CHECK fragment regardless of internal whitespace.
1194
+ /status\s+IN\s*\(\s*'pending'\s*,\s*'resolved'\s*,\s*'bypassed'\s*,\s*'expired'\s*\)/i, "status IN ('advisory','pending','resolved','bypassed','expired')")
1195
+ .replace(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["'`]?decisions["'`]?/i, `CREATE TABLE ${newTableName}`);
1196
+ if (newCreate === sqlRow.sql || !/'advisory'/i.test(newCreate)) {
1197
+ logger.warn('[SQLiteStorage] migration 013: could not rewrite decisions.status CHECK (unexpected DDL shape) — skipping');
1198
+ return;
1199
+ }
1200
+ const indexRows = this.db
1201
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name='decisions' AND sql IS NOT NULL`)
1202
+ .all();
1203
+ const rebuild = this.db.transaction(() => {
1204
+ this.db.exec(newCreate);
1205
+ this.db.exec(`INSERT INTO ${newTableName} SELECT * FROM decisions;`);
1206
+ this.db.exec(`DROP TABLE decisions;`);
1207
+ this.db.exec(`ALTER TABLE ${newTableName} RENAME TO decisions;`);
1208
+ for (const idx of indexRows) {
1209
+ const ddl = idx.sql.replace(/CREATE\s+(UNIQUE\s+)?INDEX\s+/i, (m) => /IF\s+NOT\s+EXISTS/i.test(idx.sql) ? m : `${m}IF NOT EXISTS `);
1210
+ this.db.exec(ddl);
1211
+ }
1212
+ });
1213
+ rebuild();
1214
+ logger.info('[SQLiteStorage] migration 013: decisions.status CHECK widened');
1215
+ }
1216
+ catch (err) {
1217
+ logger.warn(`[SQLiteStorage] migration 013: widen status CHECK failed: ${err}`);
1218
+ }
1219
+ }
1220
+ dropDecisionsWorkflowTypeIfNeeded() {
1221
+ try {
1222
+ if (!this.hasTable('decisions'))
1223
+ return;
1224
+ if (!this.hasColumn('decisions', 'workflow_type'))
1225
+ return; // already dropped
1226
+ const sqlRow = this.db
1227
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='decisions'`)
1228
+ .get();
1229
+ if (!sqlRow || !sqlRow.sql)
1230
+ return;
1231
+ logger.info('[SQLiteStorage] migration 012: dropping dead decisions.workflow_type column via table rebuild');
1232
+ const newTableName = 'decisions_wf_new';
1233
+ // Strip the entire `workflow_type ...` column line (up to and including
1234
+ // its trailing comma + newline). The column is declared NOT NULL with a
1235
+ // trailing comment, e.g.:
1236
+ // workflow_type TEXT NOT NULL, -- intent.workflow_type (...)
1237
+ let newCreate = sqlRow.sql.replace(/^[ \t]*workflow_type\b[^\n]*\n/im, '');
1238
+ // Point CREATE at the temp table (first occurrence of the table name).
1239
+ newCreate = newCreate.replace(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["'`]?decisions["'`]?/i, `CREATE TABLE ${newTableName}`);
1240
+ if (newCreate === sqlRow.sql || /\bworkflow_type\b/.test(newCreate)) {
1241
+ logger.warn('[SQLiteStorage] migration 012: could not strip decisions.workflow_type from DDL (unexpected shape) — skipping');
1242
+ return;
1243
+ }
1244
+ // Explicit column list (every column EXCEPT workflow_type), preserving the
1245
+ // live table's order. Never `SELECT *` — live order != schema.sql order.
1246
+ const liveCols = this.db.prepare(`PRAGMA table_info(decisions)`).all()
1247
+ .map((c) => c.name)
1248
+ .filter((name) => name !== 'workflow_type');
1249
+ const colList = liveCols.join(', ');
1250
+ // Snapshot user indexes (auto-indexes have NULL sql and are skipped).
1251
+ const indexRows = this.db
1252
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name='decisions' AND sql IS NOT NULL`)
1253
+ .all();
1254
+ const rebuild = this.db.transaction(() => {
1255
+ this.db.exec(newCreate);
1256
+ this.db.exec(`INSERT INTO ${newTableName} (${colList}) SELECT ${colList} FROM decisions;`);
1257
+ this.db.exec(`DROP TABLE decisions;`);
1258
+ this.db.exec(`ALTER TABLE ${newTableName} RENAME TO decisions;`);
1259
+ for (const idx of indexRows) {
1260
+ const ddl = idx.sql.replace(/CREATE\s+(UNIQUE\s+)?INDEX\s+/i, (m) => /IF\s+NOT\s+EXISTS/i.test(idx.sql) ? m : `${m}IF NOT EXISTS `);
1261
+ this.db.exec(ddl);
1262
+ }
1263
+ });
1264
+ rebuild();
1265
+ logger.info('[SQLiteStorage] migration 012: decisions.workflow_type dropped');
1266
+ }
1267
+ catch (err) {
1268
+ logger.warn(`[SQLiteStorage] migration 012: drop workflow_type failed: ${err}`);
1269
+ }
1270
+ }
178
1271
  /**
179
1272
  * 将 events 表按 session_id 聚合回填到 sessions 表,仅在 sessions 尚未对齐
180
1273
  * (没有任何一行带 first_prompt)时触发。