@claude-flow/cli 3.32.2 → 3.32.3

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 (655) hide show
  1. package/.claude/helpers/helpers.manifest.json +3 -3
  2. package/.claude/helpers/statusline.cjs +38 -38
  3. package/catalog-manifest.json +2 -2
  4. package/package.json +2 -2
  5. package/plugins/ruflo-metaharness/scripts/smoke.sh +11 -11
  6. package/dist/src/agenticow/speculative-exploration.d.ts +0 -148
  7. package/dist/src/agenticow/speculative-exploration.js +0 -218
  8. package/dist/src/appliance/gguf-engine.d.ts +0 -91
  9. package/dist/src/appliance/gguf-engine.js +0 -425
  10. package/dist/src/appliance/ruvllm-bridge.d.ts +0 -102
  11. package/dist/src/appliance/ruvllm-bridge.js +0 -292
  12. package/dist/src/appliance/rvfa-builder.d.ts +0 -44
  13. package/dist/src/appliance/rvfa-builder.js +0 -329
  14. package/dist/src/appliance/rvfa-distribution.d.ts +0 -97
  15. package/dist/src/appliance/rvfa-distribution.js +0 -370
  16. package/dist/src/appliance/rvfa-format.d.ts +0 -111
  17. package/dist/src/appliance/rvfa-format.js +0 -393
  18. package/dist/src/appliance/rvfa-runner.d.ts +0 -69
  19. package/dist/src/appliance/rvfa-runner.js +0 -237
  20. package/dist/src/appliance/rvfa-signing.d.ts +0 -123
  21. package/dist/src/appliance/rvfa-signing.js +0 -347
  22. package/dist/src/autopilot-state.d.ts +0 -77
  23. package/dist/src/autopilot-state.js +0 -271
  24. package/dist/src/benchmarks/gaia-agent-planning.smoke.d.ts +0 -18
  25. package/dist/src/benchmarks/gaia-agent-planning.smoke.js +0 -253
  26. package/dist/src/benchmarks/gaia-agent.d.ts +0 -198
  27. package/dist/src/benchmarks/gaia-agent.js +0 -651
  28. package/dist/src/benchmarks/gaia-causal-memory.d.ts +0 -133
  29. package/dist/src/benchmarks/gaia-causal-memory.js +0 -281
  30. package/dist/src/benchmarks/gaia-causal-memory.smoke.d.ts +0 -22
  31. package/dist/src/benchmarks/gaia-causal-memory.smoke.js +0 -300
  32. package/dist/src/benchmarks/gaia-convergence.d.ts +0 -138
  33. package/dist/src/benchmarks/gaia-convergence.js +0 -260
  34. package/dist/src/benchmarks/gaia-convergence.smoke.d.ts +0 -19
  35. package/dist/src/benchmarks/gaia-convergence.smoke.js +0 -246
  36. package/dist/src/benchmarks/gaia-critic.d.ts +0 -123
  37. package/dist/src/benchmarks/gaia-critic.js +0 -312
  38. package/dist/src/benchmarks/gaia-critic.smoke.d.ts +0 -21
  39. package/dist/src/benchmarks/gaia-critic.smoke.js +0 -327
  40. package/dist/src/benchmarks/gaia-decomposer.d.ts +0 -125
  41. package/dist/src/benchmarks/gaia-decomposer.js +0 -350
  42. package/dist/src/benchmarks/gaia-decomposer.smoke.d.ts +0 -21
  43. package/dist/src/benchmarks/gaia-decomposer.smoke.js +0 -228
  44. package/dist/src/benchmarks/gaia-e2e-smoke.d.ts +0 -27
  45. package/dist/src/benchmarks/gaia-e2e-smoke.js +0 -136
  46. package/dist/src/benchmarks/gaia-extract.smoke.d.ts +0 -45
  47. package/dist/src/benchmarks/gaia-extract.smoke.js +0 -242
  48. package/dist/src/benchmarks/gaia-hardness/features.d.ts +0 -46
  49. package/dist/src/benchmarks/gaia-hardness/features.js +0 -170
  50. package/dist/src/benchmarks/gaia-hardness/predictor.d.ts +0 -105
  51. package/dist/src/benchmarks/gaia-hardness/predictor.js +0 -260
  52. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.d.ts +0 -20
  53. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.js +0 -235
  54. package/dist/src/benchmarks/gaia-hardness/train-data-loader.d.ts +0 -51
  55. package/dist/src/benchmarks/gaia-hardness/train-data-loader.js +0 -179
  56. package/dist/src/benchmarks/gaia-judge.d.ts +0 -88
  57. package/dist/src/benchmarks/gaia-judge.js +0 -437
  58. package/dist/src/benchmarks/gaia-loader.d.ts +0 -87
  59. package/dist/src/benchmarks/gaia-loader.js +0 -326
  60. package/dist/src/benchmarks/gaia-tools/file_read.d.ts +0 -35
  61. package/dist/src/benchmarks/gaia-tools/file_read.js +0 -403
  62. package/dist/src/benchmarks/gaia-tools/grounded_query.d.ts +0 -126
  63. package/dist/src/benchmarks/gaia-tools/grounded_query.js +0 -225
  64. package/dist/src/benchmarks/gaia-tools/index.d.ts +0 -32
  65. package/dist/src/benchmarks/gaia-tools/index.js +0 -36
  66. package/dist/src/benchmarks/gaia-tools/types.d.ts +0 -62
  67. package/dist/src/benchmarks/gaia-tools/types.js +0 -12
  68. package/dist/src/benchmarks/gaia-tools/web_search.d.ts +0 -30
  69. package/dist/src/benchmarks/gaia-tools/web_search.js +0 -210
  70. package/dist/src/benchmarks/gaia-voting.d.ts +0 -88
  71. package/dist/src/benchmarks/gaia-voting.js +0 -297
  72. package/dist/src/benchmarks/gaia-voting.smoke.d.ts +0 -20
  73. package/dist/src/benchmarks/gaia-voting.smoke.js +0 -332
  74. package/dist/src/benchmarks/pretrain/index.d.ts +0 -58
  75. package/dist/src/benchmarks/pretrain/index.js +0 -404
  76. package/dist/src/business-pods/bbs-budget-tracker.d.ts +0 -139
  77. package/dist/src/business-pods/bbs-budget-tracker.js +0 -358
  78. package/dist/src/business-pods/domain-affinity-policy.d.ts +0 -47
  79. package/dist/src/business-pods/domain-affinity-policy.js +0 -65
  80. package/dist/src/business-pods/pod-schema.d.ts +0 -96
  81. package/dist/src/business-pods/pod-schema.js +0 -225
  82. package/dist/src/commands/advisor.d.ts +0 -15
  83. package/dist/src/commands/advisor.js +0 -94
  84. package/dist/src/commands/agent-wasm.d.ts +0 -14
  85. package/dist/src/commands/agent-wasm.js +0 -333
  86. package/dist/src/commands/agent.d.ts +0 -8
  87. package/dist/src/commands/agent.js +0 -927
  88. package/dist/src/commands/analyze.d.ts +0 -19
  89. package/dist/src/commands/analyze.js +0 -2047
  90. package/dist/src/commands/announcements.d.ts +0 -17
  91. package/dist/src/commands/announcements.js +0 -0
  92. package/dist/src/commands/appliance-advanced.d.ts +0 -9
  93. package/dist/src/commands/appliance-advanced.js +0 -215
  94. package/dist/src/commands/appliance.d.ts +0 -8
  95. package/dist/src/commands/appliance.js +0 -404
  96. package/dist/src/commands/autopilot.d.ts +0 -15
  97. package/dist/src/commands/autopilot.js +0 -407
  98. package/dist/src/commands/benchmark.d.ts +0 -10
  99. package/dist/src/commands/benchmark.js +0 -460
  100. package/dist/src/commands/claims.d.ts +0 -10
  101. package/dist/src/commands/claims.js +0 -620
  102. package/dist/src/commands/cleanup.d.ts +0 -13
  103. package/dist/src/commands/cleanup.js +0 -250
  104. package/dist/src/commands/completions.d.ts +0 -10
  105. package/dist/src/commands/completions.js +0 -539
  106. package/dist/src/commands/config.d.ts +0 -8
  107. package/dist/src/commands/config.js +0 -428
  108. package/dist/src/commands/daemon.d.ts +0 -59
  109. package/dist/src/commands/daemon.js +0 -1733
  110. package/dist/src/commands/deployment.d.ts +0 -10
  111. package/dist/src/commands/deployment.js +0 -672
  112. package/dist/src/commands/doctor.d.ts +0 -10
  113. package/dist/src/commands/doctor.js +0 -1695
  114. package/dist/src/commands/eject.d.ts +0 -33
  115. package/dist/src/commands/eject.js +0 -195
  116. package/dist/src/commands/embeddings.d.ts +0 -18
  117. package/dist/src/commands/embeddings.js +0 -1623
  118. package/dist/src/commands/funnel.d.ts +0 -18
  119. package/dist/src/commands/funnel.js +0 -302
  120. package/dist/src/commands/gaia-bench.d.ts +0 -40
  121. package/dist/src/commands/gaia-bench.js +0 -597
  122. package/dist/src/commands/guidance.d.ts +0 -8
  123. package/dist/src/commands/guidance.js +0 -556
  124. package/dist/src/commands/hive-mind.d.ts +0 -11
  125. package/dist/src/commands/hive-mind.js +0 -1319
  126. package/dist/src/commands/hooks.d.ts +0 -8
  127. package/dist/src/commands/hooks.js +0 -4606
  128. package/dist/src/commands/index.d.ts +0 -118
  129. package/dist/src/commands/index.js +0 -364
  130. package/dist/src/commands/init.d.ts +0 -13
  131. package/dist/src/commands/init.js +0 -1297
  132. package/dist/src/commands/issues.d.ts +0 -21
  133. package/dist/src/commands/issues.js +0 -567
  134. package/dist/src/commands/mcp.d.ts +0 -11
  135. package/dist/src/commands/mcp.js +0 -732
  136. package/dist/src/commands/memory-backup.d.ts +0 -11
  137. package/dist/src/commands/memory-backup.js +0 -46
  138. package/dist/src/commands/memory-distill.d.ts +0 -27
  139. package/dist/src/commands/memory-distill.js +0 -374
  140. package/dist/src/commands/memory.d.ts +0 -8
  141. package/dist/src/commands/memory.js +0 -1596
  142. package/dist/src/commands/metaharness.d.ts +0 -39
  143. package/dist/src/commands/metaharness.js +0 -215
  144. package/dist/src/commands/migrate.d.ts +0 -8
  145. package/dist/src/commands/migrate.js +0 -742
  146. package/dist/src/commands/neural.d.ts +0 -10
  147. package/dist/src/commands/neural.js +0 -4331
  148. package/dist/src/commands/performance.d.ts +0 -10
  149. package/dist/src/commands/performance.js +0 -583
  150. package/dist/src/commands/plugins.d.ts +0 -11
  151. package/dist/src/commands/plugins.js +0 -826
  152. package/dist/src/commands/process.d.ts +0 -10
  153. package/dist/src/commands/process.js +0 -694
  154. package/dist/src/commands/progress.d.ts +0 -11
  155. package/dist/src/commands/progress.js +0 -259
  156. package/dist/src/commands/providers.d.ts +0 -10
  157. package/dist/src/commands/providers.js +0 -502
  158. package/dist/src/commands/proxy.d.ts +0 -21
  159. package/dist/src/commands/proxy.js +0 -310
  160. package/dist/src/commands/route.d.ts +0 -16
  161. package/dist/src/commands/route.js +0 -822
  162. package/dist/src/commands/ruvector/backup.d.ts +0 -11
  163. package/dist/src/commands/ruvector/backup.js +0 -747
  164. package/dist/src/commands/ruvector/benchmark.d.ts +0 -11
  165. package/dist/src/commands/ruvector/benchmark.js +0 -490
  166. package/dist/src/commands/ruvector/import.d.ts +0 -18
  167. package/dist/src/commands/ruvector/import.js +0 -373
  168. package/dist/src/commands/ruvector/index.d.ts +0 -29
  169. package/dist/src/commands/ruvector/index.js +0 -129
  170. package/dist/src/commands/ruvector/init.d.ts +0 -11
  171. package/dist/src/commands/ruvector/init.js +0 -467
  172. package/dist/src/commands/ruvector/migrate.d.ts +0 -11
  173. package/dist/src/commands/ruvector/migrate.js +0 -498
  174. package/dist/src/commands/ruvector/optimize.d.ts +0 -11
  175. package/dist/src/commands/ruvector/optimize.js +0 -505
  176. package/dist/src/commands/ruvector/pg-utils.d.ts +0 -14
  177. package/dist/src/commands/ruvector/pg-utils.js +0 -41
  178. package/dist/src/commands/ruvector/setup.d.ts +0 -18
  179. package/dist/src/commands/ruvector/setup.js +0 -765
  180. package/dist/src/commands/ruvector/status.d.ts +0 -11
  181. package/dist/src/commands/ruvector/status.js +0 -479
  182. package/dist/src/commands/security.d.ts +0 -10
  183. package/dist/src/commands/security.js +0 -1012
  184. package/dist/src/commands/session.d.ts +0 -8
  185. package/dist/src/commands/session.js +0 -757
  186. package/dist/src/commands/settings.d.ts +0 -19
  187. package/dist/src/commands/settings.js +0 -180
  188. package/dist/src/commands/spinner.d.ts +0 -16
  189. package/dist/src/commands/spinner.js +0 -329
  190. package/dist/src/commands/start.d.ts +0 -8
  191. package/dist/src/commands/start.js +0 -418
  192. package/dist/src/commands/status.d.ts +0 -8
  193. package/dist/src/commands/status.js +0 -608
  194. package/dist/src/commands/swarm.d.ts +0 -8
  195. package/dist/src/commands/swarm.js +0 -891
  196. package/dist/src/commands/task.d.ts +0 -8
  197. package/dist/src/commands/task.js +0 -675
  198. package/dist/src/commands/transfer-store.d.ts +0 -13
  199. package/dist/src/commands/transfer-store.js +0 -428
  200. package/dist/src/commands/update.d.ts +0 -8
  201. package/dist/src/commands/update.js +0 -276
  202. package/dist/src/commands/verify.d.ts +0 -19
  203. package/dist/src/commands/verify.js +0 -261
  204. package/dist/src/commands/version.d.ts +0 -42
  205. package/dist/src/commands/version.js +0 -106
  206. package/dist/src/commands/workflow.d.ts +0 -8
  207. package/dist/src/commands/workflow.js +0 -617
  208. package/dist/src/config/harness-feedback-applier.d.ts +0 -50
  209. package/dist/src/config/harness-feedback-applier.js +0 -122
  210. package/dist/src/config/proven-config-refresh.d.ts +0 -39
  211. package/dist/src/config/proven-config-refresh.js +0 -154
  212. package/dist/src/config/proven-config-rvfa.d.ts +0 -23
  213. package/dist/src/config/proven-config-rvfa.js +0 -73
  214. package/dist/src/config/proven-config.d.ts +0 -86
  215. package/dist/src/config/proven-config.js +0 -176
  216. package/dist/src/config-adapter.d.ts +0 -15
  217. package/dist/src/config-adapter.js +0 -186
  218. package/dist/src/encryption/vault.d.ts +0 -94
  219. package/dist/src/encryption/vault.js +0 -172
  220. package/dist/src/fs-secure.d.ts +0 -86
  221. package/dist/src/fs-secure.js +0 -133
  222. package/dist/src/funnel/advisor-tip.d.ts +0 -58
  223. package/dist/src/funnel/advisor-tip.js +0 -92
  224. package/dist/src/funnel/attribution.d.ts +0 -37
  225. package/dist/src/funnel/attribution.js +0 -101
  226. package/dist/src/funnel/consent.d.ts +0 -22
  227. package/dist/src/funnel/consent.js +0 -58
  228. package/dist/src/funnel/credit-errors.d.ts +0 -31
  229. package/dist/src/funnel/credit-errors.js +0 -88
  230. package/dist/src/funnel/credit-notifier.d.ts +0 -44
  231. package/dist/src/funnel/credit-notifier.js +0 -74
  232. package/dist/src/funnel/disclosure.d.ts +0 -47
  233. package/dist/src/funnel/disclosure.js +0 -109
  234. package/dist/src/funnel/enrollment.d.ts +0 -36
  235. package/dist/src/funnel/enrollment.js +0 -64
  236. package/dist/src/funnel/environment.d.ts +0 -17
  237. package/dist/src/funnel/environment.js +0 -39
  238. package/dist/src/funnel/event-transport.d.ts +0 -51
  239. package/dist/src/funnel/event-transport.js +0 -199
  240. package/dist/src/funnel/events.d.ts +0 -42
  241. package/dist/src/funnel/events.js +0 -150
  242. package/dist/src/funnel/index.d.ts +0 -21
  243. package/dist/src/funnel/index.js +0 -21
  244. package/dist/src/funnel/insights.d.ts +0 -50
  245. package/dist/src/funnel/insights.js +0 -120
  246. package/dist/src/funnel/local-signals.d.ts +0 -20
  247. package/dist/src/funnel/local-signals.js +0 -77
  248. package/dist/src/funnel/message-transport.d.ts +0 -51
  249. package/dist/src/funnel/message-transport.js +0 -149
  250. package/dist/src/funnel/messages.d.ts +0 -55
  251. package/dist/src/funnel/messages.js +0 -160
  252. package/dist/src/funnel/payout.d.ts +0 -40
  253. package/dist/src/funnel/payout.js +0 -60
  254. package/dist/src/funnel/power-saver-notifier.d.ts +0 -44
  255. package/dist/src/funnel/power-saver-notifier.js +0 -92
  256. package/dist/src/funnel/precedence.d.ts +0 -16
  257. package/dist/src/funnel/precedence.js +0 -85
  258. package/dist/src/funnel/promo.d.ts +0 -41
  259. package/dist/src/funnel/promo.js +0 -144
  260. package/dist/src/funnel/rate-limit-notifier.d.ts +0 -55
  261. package/dist/src/funnel/rate-limit-notifier.js +0 -102
  262. package/dist/src/funnel/rotation.d.ts +0 -19
  263. package/dist/src/funnel/rotation.js +0 -70
  264. package/dist/src/funnel/state.d.ts +0 -13
  265. package/dist/src/funnel/state.js +0 -52
  266. package/dist/src/funnel/toggle-cooldown.d.ts +0 -17
  267. package/dist/src/funnel/toggle-cooldown.js +0 -32
  268. package/dist/src/funnel/types.d.ts +0 -98
  269. package/dist/src/funnel/types.js +0 -26
  270. package/dist/src/index.d.ts +0 -81
  271. package/dist/src/index.js +0 -609
  272. package/dist/src/infrastructure/in-memory-repositories.d.ts +0 -68
  273. package/dist/src/infrastructure/in-memory-repositories.js +0 -264
  274. package/dist/src/init/claudemd-generator.d.ts +0 -16
  275. package/dist/src/init/claudemd-generator.js +0 -368
  276. package/dist/src/init/executor.d.ts +0 -41
  277. package/dist/src/init/executor.js +0 -2142
  278. package/dist/src/init/helper-refresh.d.ts +0 -79
  279. package/dist/src/init/helper-refresh.js +0 -347
  280. package/dist/src/init/helper-signing.d.ts +0 -37
  281. package/dist/src/init/helper-signing.js +0 -67
  282. package/dist/src/init/helpers-generator.d.ts +0 -87
  283. package/dist/src/init/helpers-generator.js +0 -1456
  284. package/dist/src/init/index.d.ts +0 -13
  285. package/dist/src/init/index.js +0 -15
  286. package/dist/src/init/mcp-generator.d.ts +0 -26
  287. package/dist/src/init/mcp-generator.js +0 -126
  288. package/dist/src/init/memory-package-resolver.d.ts +0 -53
  289. package/dist/src/init/memory-package-resolver.js +0 -118
  290. package/dist/src/init/settings-generator.d.ts +0 -14
  291. package/dist/src/init/settings-generator.js +0 -462
  292. package/dist/src/init/statusline-generator.d.ts +0 -28
  293. package/dist/src/init/statusline-generator.js +0 -177
  294. package/dist/src/init/types.d.ts +0 -331
  295. package/dist/src/init/types.js +0 -276
  296. package/dist/src/log-filters.d.ts +0 -46
  297. package/dist/src/log-filters.js +0 -107
  298. package/dist/src/mcp-client.d.ts +0 -92
  299. package/dist/src/mcp-client.js +0 -397
  300. package/dist/src/mcp-server.d.ts +0 -163
  301. package/dist/src/mcp-server.js +0 -751
  302. package/dist/src/mcp-tools/agent-execute-core.d.ts +0 -115
  303. package/dist/src/mcp-tools/agent-execute-core.js +0 -587
  304. package/dist/src/mcp-tools/agent-tools.d.ts +0 -9
  305. package/dist/src/mcp-tools/agent-tools.js +0 -837
  306. package/dist/src/mcp-tools/agentbbs-tools.d.ts +0 -28
  307. package/dist/src/mcp-tools/agentbbs-tools.js +0 -394
  308. package/dist/src/mcp-tools/agentdb-tools.d.ts +0 -35
  309. package/dist/src/mcp-tools/agentdb-tools.js +0 -1473
  310. package/dist/src/mcp-tools/agenticow-loader.d.ts +0 -59
  311. package/dist/src/mcp-tools/agenticow-loader.js +0 -105
  312. package/dist/src/mcp-tools/agenticow-speculate-tools.d.ts +0 -24
  313. package/dist/src/mcp-tools/agenticow-speculate-tools.js +0 -209
  314. package/dist/src/mcp-tools/agenticow-tools.d.ts +0 -36
  315. package/dist/src/mcp-tools/agenticow-tools.js +0 -360
  316. package/dist/src/mcp-tools/analyze-tools.d.ts +0 -38
  317. package/dist/src/mcp-tools/analyze-tools.js +0 -346
  318. package/dist/src/mcp-tools/auto-install.d.ts +0 -83
  319. package/dist/src/mcp-tools/auto-install.js +0 -131
  320. package/dist/src/mcp-tools/autopilot-tools.d.ts +0 -12
  321. package/dist/src/mcp-tools/autopilot-tools.js +0 -231
  322. package/dist/src/mcp-tools/browser-intent-tools.d.ts +0 -162
  323. package/dist/src/mcp-tools/browser-intent-tools.js +0 -548
  324. package/dist/src/mcp-tools/browser-session-tools.d.ts +0 -27
  325. package/dist/src/mcp-tools/browser-session-tools.js +0 -398
  326. package/dist/src/mcp-tools/browser-tools.d.ts +0 -21
  327. package/dist/src/mcp-tools/browser-tools.js +0 -760
  328. package/dist/src/mcp-tools/business-pod-tools.d.ts +0 -20
  329. package/dist/src/mcp-tools/business-pod-tools.js +0 -169
  330. package/dist/src/mcp-tools/claims-tools.d.ts +0 -12
  331. package/dist/src/mcp-tools/claims-tools.js +0 -863
  332. package/dist/src/mcp-tools/config-tools.d.ts +0 -8
  333. package/dist/src/mcp-tools/config-tools.js +0 -411
  334. package/dist/src/mcp-tools/coordination-tools.d.ts +0 -13
  335. package/dist/src/mcp-tools/coordination-tools.js +0 -729
  336. package/dist/src/mcp-tools/daa-tools.d.ts +0 -13
  337. package/dist/src/mcp-tools/daa-tools.js +0 -534
  338. package/dist/src/mcp-tools/embeddings-tools.d.ts +0 -9
  339. package/dist/src/mcp-tools/embeddings-tools.js +0 -904
  340. package/dist/src/mcp-tools/github-tools.d.ts +0 -9
  341. package/dist/src/mcp-tools/github-tools.js +0 -659
  342. package/dist/src/mcp-tools/guidance-tools.d.ts +0 -15
  343. package/dist/src/mcp-tools/guidance-tools.js +0 -639
  344. package/dist/src/mcp-tools/hive-mind-tools.d.ts +0 -8
  345. package/dist/src/mcp-tools/hive-mind-tools.js +0 -953
  346. package/dist/src/mcp-tools/hooks-tools.d.ts +0 -65
  347. package/dist/src/mcp-tools/hooks-tools.js +0 -4836
  348. package/dist/src/mcp-tools/http-fetch-tools.d.ts +0 -55
  349. package/dist/src/mcp-tools/http-fetch-tools.js +0 -329
  350. package/dist/src/mcp-tools/index.d.ts +0 -34
  351. package/dist/src/mcp-tools/index.js +0 -40
  352. package/dist/src/mcp-tools/managed-agent-tools.d.ts +0 -22
  353. package/dist/src/mcp-tools/managed-agent-tools.js +0 -357
  354. package/dist/src/mcp-tools/memory-tools.d.ts +0 -14
  355. package/dist/src/mcp-tools/memory-tools.js +0 -1330
  356. package/dist/src/mcp-tools/metaharness-tools.d.ts +0 -51
  357. package/dist/src/mcp-tools/metaharness-tools.js +0 -684
  358. package/dist/src/mcp-tools/neural-tools.d.ts +0 -54
  359. package/dist/src/mcp-tools/neural-tools.js +0 -1168
  360. package/dist/src/mcp-tools/performance-tools.d.ts +0 -16
  361. package/dist/src/mcp-tools/performance-tools.js +0 -675
  362. package/dist/src/mcp-tools/progress-tools.d.ts +0 -14
  363. package/dist/src/mcp-tools/progress-tools.js +0 -348
  364. package/dist/src/mcp-tools/request-tracker.d.ts +0 -17
  365. package/dist/src/mcp-tools/request-tracker.js +0 -27
  366. package/dist/src/mcp-tools/ruvllm-tools.d.ts +0 -9
  367. package/dist/src/mcp-tools/ruvllm-tools.js +0 -355
  368. package/dist/src/mcp-tools/security-tools.d.ts +0 -18
  369. package/dist/src/mcp-tools/security-tools.js +0 -556
  370. package/dist/src/mcp-tools/session-tools.d.ts +0 -8
  371. package/dist/src/mcp-tools/session-tools.js +0 -517
  372. package/dist/src/mcp-tools/swarm-tools.d.ts +0 -37
  373. package/dist/src/mcp-tools/swarm-tools.js +0 -390
  374. package/dist/src/mcp-tools/system-tools.d.ts +0 -13
  375. package/dist/src/mcp-tools/system-tools.js +0 -688
  376. package/dist/src/mcp-tools/task-tools.d.ts +0 -8
  377. package/dist/src/mcp-tools/task-tools.js +0 -487
  378. package/dist/src/mcp-tools/terminal-tools.d.ts +0 -8
  379. package/dist/src/mcp-tools/terminal-tools.js +0 -306
  380. package/dist/src/mcp-tools/testgen-tools.d.ts +0 -26
  381. package/dist/src/mcp-tools/testgen-tools.js +0 -168
  382. package/dist/src/mcp-tools/tool-loop-guardrail.d.ts +0 -31
  383. package/dist/src/mcp-tools/tool-loop-guardrail.js +0 -71
  384. package/dist/src/mcp-tools/transfer-tools.d.ts +0 -14
  385. package/dist/src/mcp-tools/transfer-tools.js +0 -447
  386. package/dist/src/mcp-tools/types.d.ts +0 -8
  387. package/dist/src/mcp-tools/types.js +0 -8
  388. package/dist/src/mcp-tools/validate-input.d.ts +0 -9
  389. package/dist/src/mcp-tools/validate-input.js +0 -9
  390. package/dist/src/mcp-tools/wasm-agent-tools.d.ts +0 -13
  391. package/dist/src/mcp-tools/wasm-agent-tools.js +0 -840
  392. package/dist/src/mcp-tools/workflow-tools.d.ts +0 -8
  393. package/dist/src/mcp-tools/workflow-tools.js +0 -884
  394. package/dist/src/memory/bge-embedder.d.ts +0 -25
  395. package/dist/src/memory/bge-embedder.js +0 -121
  396. package/dist/src/memory/cross-encoder-rerank.d.ts +0 -33
  397. package/dist/src/memory/cross-encoder-rerank.js +0 -123
  398. package/dist/src/memory/embedding-policy.d.ts +0 -21
  399. package/dist/src/memory/embedding-policy.js +0 -30
  400. package/dist/src/memory/embedding-quantization.d.ts +0 -62
  401. package/dist/src/memory/embedding-quantization.js +0 -156
  402. package/dist/src/memory/ewc-consolidation.d.ts +0 -305
  403. package/dist/src/memory/ewc-consolidation.js +0 -611
  404. package/dist/src/memory/graph-edge-writer.d.ts +0 -95
  405. package/dist/src/memory/graph-edge-writer.js +0 -217
  406. package/dist/src/memory/hybrid-retrieval.d.ts +0 -77
  407. package/dist/src/memory/hybrid-retrieval.js +0 -192
  408. package/dist/src/memory/intelligence.d.ts +0 -405
  409. package/dist/src/memory/intelligence.js +0 -1316
  410. package/dist/src/memory/lucene-bm25.d.ts +0 -19
  411. package/dist/src/memory/lucene-bm25.js +0 -308
  412. package/dist/src/memory/memory-bridge.d.ts +0 -537
  413. package/dist/src/memory/memory-bridge.js +0 -2460
  414. package/dist/src/memory/memory-initializer.d.ts +0 -556
  415. package/dist/src/memory/memory-initializer.js +0 -3021
  416. package/dist/src/memory/neural-package-bridge.d.ts +0 -48
  417. package/dist/src/memory/neural-package-bridge.js +0 -87
  418. package/dist/src/memory/rabitq-index.d.ts +0 -60
  419. package/dist/src/memory/rabitq-index.js +0 -242
  420. package/dist/src/memory/sona-optimizer.d.ts +0 -267
  421. package/dist/src/memory/sona-optimizer.js +0 -779
  422. package/dist/src/memory/structured-distill.d.ts +0 -48
  423. package/dist/src/memory/structured-distill.js +0 -125
  424. package/dist/src/output.d.ts +0 -9
  425. package/dist/src/output.js +0 -9
  426. package/dist/src/parser.d.ts +0 -89
  427. package/dist/src/parser.js +0 -516
  428. package/dist/src/plugins/manager.d.ts +0 -133
  429. package/dist/src/plugins/manager.js +0 -415
  430. package/dist/src/plugins/store/discovery.d.ts +0 -99
  431. package/dist/src/plugins/store/discovery.js +0 -1224
  432. package/dist/src/plugins/store/index.d.ts +0 -76
  433. package/dist/src/plugins/store/index.js +0 -141
  434. package/dist/src/plugins/store/search.d.ts +0 -46
  435. package/dist/src/plugins/store/search.js +0 -230
  436. package/dist/src/plugins/store/types.d.ts +0 -279
  437. package/dist/src/plugins/store/types.js +0 -7
  438. package/dist/src/plugins/tests/demo-plugin-store.d.ts +0 -7
  439. package/dist/src/plugins/tests/demo-plugin-store.js +0 -126
  440. package/dist/src/plugins/tests/standalone-test.d.ts +0 -12
  441. package/dist/src/plugins/tests/standalone-test.js +0 -188
  442. package/dist/src/plugins/tests/test-plugin-store.d.ts +0 -7
  443. package/dist/src/plugins/tests/test-plugin-store.js +0 -206
  444. package/dist/src/production/circuit-breaker.d.ts +0 -101
  445. package/dist/src/production/circuit-breaker.js +0 -241
  446. package/dist/src/production/error-handler.d.ts +0 -92
  447. package/dist/src/production/error-handler.js +0 -299
  448. package/dist/src/production/index.d.ts +0 -23
  449. package/dist/src/production/index.js +0 -18
  450. package/dist/src/production/monitoring.d.ts +0 -161
  451. package/dist/src/production/monitoring.js +0 -356
  452. package/dist/src/production/rate-limiter.d.ts +0 -80
  453. package/dist/src/production/rate-limiter.js +0 -201
  454. package/dist/src/production/retry.d.ts +0 -48
  455. package/dist/src/production/retry.js +0 -179
  456. package/dist/src/prompt.d.ts +0 -44
  457. package/dist/src/prompt.js +0 -501
  458. package/dist/src/runtime/headless.d.ts +0 -60
  459. package/dist/src/runtime/headless.js +0 -284
  460. package/dist/src/runtime/parent-death-watchdog.d.ts +0 -42
  461. package/dist/src/runtime/parent-death-watchdog.js +0 -70
  462. package/dist/src/ruvector/agent-wasm.d.ts +0 -228
  463. package/dist/src/ruvector/agent-wasm.js +0 -463
  464. package/dist/src/ruvector/ast-analyzer.d.ts +0 -67
  465. package/dist/src/ruvector/ast-analyzer.js +0 -277
  466. package/dist/src/ruvector/codemods/engine.d.ts +0 -45
  467. package/dist/src/ruvector/codemods/engine.js +0 -291
  468. package/dist/src/ruvector/codemods/scope-analysis.d.ts +0 -29
  469. package/dist/src/ruvector/codemods/scope-analysis.js +0 -162
  470. package/dist/src/ruvector/coverage-router.d.ts +0 -160
  471. package/dist/src/ruvector/coverage-router.js +0 -531
  472. package/dist/src/ruvector/coverage-tools.d.ts +0 -33
  473. package/dist/src/ruvector/coverage-tools.js +0 -157
  474. package/dist/src/ruvector/diff-classifier.d.ts +0 -175
  475. package/dist/src/ruvector/diff-classifier.js +0 -699
  476. package/dist/src/ruvector/diskann-backend.d.ts +0 -78
  477. package/dist/src/ruvector/diskann-backend.js +0 -310
  478. package/dist/src/ruvector/enhanced-model-router.d.ts +0 -172
  479. package/dist/src/ruvector/enhanced-model-router.js +0 -577
  480. package/dist/src/ruvector/graph-analyzer.d.ts +0 -187
  481. package/dist/src/ruvector/graph-analyzer.js +0 -929
  482. package/dist/src/ruvector/graph-backend.d.ts +0 -79
  483. package/dist/src/ruvector/graph-backend.js +0 -220
  484. package/dist/src/ruvector/index.d.ts +0 -38
  485. package/dist/src/ruvector/index.js +0 -86
  486. package/dist/src/ruvector/lora-adapter.d.ts +0 -292
  487. package/dist/src/ruvector/lora-adapter.js +0 -710
  488. package/dist/src/ruvector/model-prices.d.ts +0 -50
  489. package/dist/src/ruvector/model-prices.js +0 -72
  490. package/dist/src/ruvector/model-router.d.ts +0 -408
  491. package/dist/src/ruvector/model-router.js +0 -1162
  492. package/dist/src/ruvector/neural-router.d.ts +0 -182
  493. package/dist/src/ruvector/neural-router.js +0 -825
  494. package/dist/src/ruvector/output-verifier.d.ts +0 -83
  495. package/dist/src/ruvector/output-verifier.js +0 -277
  496. package/dist/src/ruvector/q-learning-router.d.ts +0 -227
  497. package/dist/src/ruvector/q-learning-router.js +0 -721
  498. package/dist/src/ruvector/router-calibrator.d.ts +0 -65
  499. package/dist/src/ruvector/router-calibrator.js +0 -120
  500. package/dist/src/ruvector/router-parallel-recorder.d.ts +0 -127
  501. package/dist/src/ruvector/router-parallel-recorder.js +0 -183
  502. package/dist/src/ruvector/router-trajectory.d.ts +0 -194
  503. package/dist/src/ruvector/router-trajectory.js +0 -281
  504. package/dist/src/ruvector/run-transcript-recorder.d.ts +0 -154
  505. package/dist/src/ruvector/run-transcript-recorder.js +0 -209
  506. package/dist/src/ruvector/ruvllm-wasm.d.ts +0 -179
  507. package/dist/src/ruvector/ruvllm-wasm.js +0 -379
  508. package/dist/src/ruvector/semantic-router.d.ts +0 -77
  509. package/dist/src/ruvector/semantic-router.js +0 -178
  510. package/dist/src/ruvector/task-embedder.d.ts +0 -56
  511. package/dist/src/ruvector/task-embedder.js +0 -237
  512. package/dist/src/ruvector/trajectory-tree.d.ts +0 -113
  513. package/dist/src/ruvector/trajectory-tree.js +0 -237
  514. package/dist/src/ruvector/vector-db.d.ts +0 -73
  515. package/dist/src/ruvector/vector-db.js +0 -301
  516. package/dist/src/ruvector/wasm-embedder.d.ts +0 -13
  517. package/dist/src/ruvector/wasm-embedder.js +0 -143
  518. package/dist/src/security/builtin-aidefence.d.ts +0 -34
  519. package/dist/src/security/builtin-aidefence.js +0 -86
  520. package/dist/src/services/agentic-flow-bridge.d.ts +0 -50
  521. package/dist/src/services/agentic-flow-bridge.js +0 -95
  522. package/dist/src/services/ai-job-dedup.d.ts +0 -61
  523. package/dist/src/services/ai-job-dedup.js +0 -136
  524. package/dist/src/services/checkpoint-gate.d.ts +0 -140
  525. package/dist/src/services/checkpoint-gate.js +0 -223
  526. package/dist/src/services/claim-service.d.ts +0 -204
  527. package/dist/src/services/claim-service.js +0 -818
  528. package/dist/src/services/config-file-manager.d.ts +0 -37
  529. package/dist/src/services/config-file-manager.js +0 -224
  530. package/dist/src/services/container-worker-pool.d.ts +0 -204
  531. package/dist/src/services/container-worker-pool.js +0 -589
  532. package/dist/src/services/daemon-autostart.d.ts +0 -17
  533. package/dist/src/services/daemon-autostart.js +0 -102
  534. package/dist/src/services/distill-oracle.d.ts +0 -190
  535. package/dist/src/services/distill-oracle.js +0 -349
  536. package/dist/src/services/distill-tuning.d.ts +0 -111
  537. package/dist/src/services/distill-tuning.js +0 -510
  538. package/dist/src/services/evolve-proof.d.ts +0 -253
  539. package/dist/src/services/evolve-proof.js +0 -343
  540. package/dist/src/services/fable-harness.d.ts +0 -208
  541. package/dist/src/services/fable-harness.js +0 -388
  542. package/dist/src/services/git-workspace-identity.d.ts +0 -42
  543. package/dist/src/services/git-workspace-identity.js +0 -99
  544. package/dist/src/services/global-ai-budget.d.ts +0 -135
  545. package/dist/src/services/global-ai-budget.js +0 -415
  546. package/dist/src/services/harness-benchmark.d.ts +0 -68
  547. package/dist/src/services/harness-benchmark.js +0 -94
  548. package/dist/src/services/harness-canary.d.ts +0 -60
  549. package/dist/src/services/harness-canary.js +0 -69
  550. package/dist/src/services/harness-corpus-harvester.d.ts +0 -51
  551. package/dist/src/services/harness-corpus-harvester.js +0 -74
  552. package/dist/src/services/harness-flywheel-generations.d.ts +0 -115
  553. package/dist/src/services/harness-flywheel-generations.js +0 -360
  554. package/dist/src/services/harness-flywheel-runtime.d.ts +0 -25
  555. package/dist/src/services/harness-flywheel-runtime.js +0 -92
  556. package/dist/src/services/harness-flywheel.d.ts +0 -48
  557. package/dist/src/services/harness-flywheel.js +0 -207
  558. package/dist/src/services/harness-frozen-eval.d.ts +0 -22
  559. package/dist/src/services/harness-frozen-eval.js +0 -66
  560. package/dist/src/services/harness-hosts.d.ts +0 -40
  561. package/dist/src/services/harness-hosts.js +0 -88
  562. package/dist/src/services/harness-improvement-ledger.d.ts +0 -63
  563. package/dist/src/services/harness-improvement-ledger.js +0 -101
  564. package/dist/src/services/harness-loop.d.ts +0 -53
  565. package/dist/src/services/harness-loop.js +0 -85
  566. package/dist/src/services/harness-qualification.d.ts +0 -66
  567. package/dist/src/services/harness-qualification.js +0 -143
  568. package/dist/src/services/harness-replay.d.ts +0 -37
  569. package/dist/src/services/harness-replay.js +0 -92
  570. package/dist/src/services/harness-verify.d.ts +0 -33
  571. package/dist/src/services/harness-verify.js +0 -26
  572. package/dist/src/services/harness-worker.d.ts +0 -23
  573. package/dist/src/services/harness-worker.js +0 -66
  574. package/dist/src/services/headless-worker-executor.d.ts +0 -358
  575. package/dist/src/services/headless-worker-executor.js +0 -1269
  576. package/dist/src/services/index.d.ts +0 -13
  577. package/dist/src/services/index.js +0 -11
  578. package/dist/src/services/memory-backup.d.ts +0 -53
  579. package/dist/src/services/memory-backup.js +0 -198
  580. package/dist/src/services/memory-distillation.d.ts +0 -41
  581. package/dist/src/services/memory-distillation.js +0 -277
  582. package/dist/src/services/native-training.d.ts +0 -68
  583. package/dist/src/services/native-training.js +0 -141
  584. package/dist/src/services/registry-api.d.ts +0 -58
  585. package/dist/src/services/registry-api.js +0 -146
  586. package/dist/src/services/repo-supervisor.d.ts +0 -70
  587. package/dist/src/services/repo-supervisor.js +0 -228
  588. package/dist/src/services/ruvector-training.d.ts +0 -222
  589. package/dist/src/services/ruvector-training.js +0 -693
  590. package/dist/src/services/swarm-memory-branches.d.ts +0 -135
  591. package/dist/src/services/swarm-memory-branches.js +0 -213
  592. package/dist/src/services/weight-eft.d.ts +0 -305
  593. package/dist/src/services/weight-eft.js +0 -296
  594. package/dist/src/services/worker-daemon.d.ts +0 -439
  595. package/dist/src/services/worker-daemon.js +0 -1865
  596. package/dist/src/services/worker-queue.d.ts +0 -194
  597. package/dist/src/services/worker-queue.js +0 -513
  598. package/dist/src/services/workspace-lease.d.ts +0 -55
  599. package/dist/src/services/workspace-lease.js +0 -191
  600. package/dist/src/suggest.d.ts +0 -53
  601. package/dist/src/suggest.js +0 -200
  602. package/dist/src/transfer/anonymization/index.d.ts +0 -25
  603. package/dist/src/transfer/anonymization/index.js +0 -175
  604. package/dist/src/transfer/deploy-seraphine.d.ts +0 -13
  605. package/dist/src/transfer/deploy-seraphine.js +0 -205
  606. package/dist/src/transfer/export.d.ts +0 -25
  607. package/dist/src/transfer/export.js +0 -113
  608. package/dist/src/transfer/index.d.ts +0 -12
  609. package/dist/src/transfer/index.js +0 -31
  610. package/dist/src/transfer/ipfs/client.d.ts +0 -109
  611. package/dist/src/transfer/ipfs/client.js +0 -307
  612. package/dist/src/transfer/ipfs/upload.d.ts +0 -95
  613. package/dist/src/transfer/ipfs/upload.js +0 -413
  614. package/dist/src/transfer/models/seraphine.d.ts +0 -72
  615. package/dist/src/transfer/models/seraphine.js +0 -373
  616. package/dist/src/transfer/serialization/cfp.d.ts +0 -49
  617. package/dist/src/transfer/serialization/cfp.js +0 -183
  618. package/dist/src/transfer/storage/gcs.d.ts +0 -82
  619. package/dist/src/transfer/storage/gcs.js +0 -272
  620. package/dist/src/transfer/storage/index.d.ts +0 -6
  621. package/dist/src/transfer/storage/index.js +0 -6
  622. package/dist/src/transfer/store/discovery.d.ts +0 -84
  623. package/dist/src/transfer/store/discovery.js +0 -382
  624. package/dist/src/transfer/store/download.d.ts +0 -70
  625. package/dist/src/transfer/store/download.js +0 -334
  626. package/dist/src/transfer/store/index.d.ts +0 -84
  627. package/dist/src/transfer/store/index.js +0 -153
  628. package/dist/src/transfer/store/publish.d.ts +0 -76
  629. package/dist/src/transfer/store/publish.js +0 -294
  630. package/dist/src/transfer/store/registry.d.ts +0 -58
  631. package/dist/src/transfer/store/registry.js +0 -285
  632. package/dist/src/transfer/store/search.d.ts +0 -54
  633. package/dist/src/transfer/store/search.js +0 -232
  634. package/dist/src/transfer/store/tests/standalone-test.d.ts +0 -12
  635. package/dist/src/transfer/store/tests/standalone-test.js +0 -190
  636. package/dist/src/transfer/store/types.d.ts +0 -193
  637. package/dist/src/transfer/store/types.js +0 -6
  638. package/dist/src/transfer/test-seraphine.d.ts +0 -6
  639. package/dist/src/transfer/test-seraphine.js +0 -105
  640. package/dist/src/transfer/tests/test-store.d.ts +0 -7
  641. package/dist/src/transfer/tests/test-store.js +0 -214
  642. package/dist/src/transfer/types.d.ts +0 -245
  643. package/dist/src/transfer/types.js +0 -6
  644. package/dist/src/types.d.ts +0 -13
  645. package/dist/src/types.js +0 -13
  646. package/dist/src/update/checker.d.ts +0 -34
  647. package/dist/src/update/checker.js +0 -191
  648. package/dist/src/update/executor.d.ts +0 -33
  649. package/dist/src/update/executor.js +0 -217
  650. package/dist/src/update/index.d.ts +0 -33
  651. package/dist/src/update/index.js +0 -64
  652. package/dist/src/update/rate-limiter.d.ts +0 -20
  653. package/dist/src/update/rate-limiter.js +0 -96
  654. package/dist/src/update/validator.d.ts +0 -17
  655. package/dist/src/update/validator.js +0 -123
@@ -1,4606 +0,0 @@
1
- /**
2
- * V3 CLI Hooks Command
3
- * Self-learning hooks system for intelligent workflow automation
4
- */
5
- import { output } from '../output.js';
6
- import { confirm } from '../prompt.js';
7
- import { callMCPTool, MCPClientError } from '../mcp-client.js';
8
- import { storeCommand } from './transfer-store.js';
9
- import { existsSync, readFileSync, statSync } from 'node:fs';
10
- import { join } from 'node:path';
11
- import { getSecurityStatus as sharedGetSecurityStatus, getSwarmStatus as sharedGetSwarmStatus, getGitUncommittedCount as sharedGetGitUncommittedCount, } from '../funnel/local-signals.js';
12
- /**
13
- * #1686 — `?? 0` only defaults null/undefined; NaN slips through and
14
- * surfaces as `"NaN"` (or earlier crashed `.toFixed`) in the metrics
15
- * dashboard and pretrain output. Coerce to a finite number, fall back
16
- * to `fallback` when the input is null/undefined/non-numeric/NaN/Infinity.
17
- */
18
- function safeNum(value, fallback = 0) {
19
- const n = typeof value === 'number' ? value : Number(value);
20
- return Number.isFinite(n) ? n : fallback;
21
- }
22
- /**
23
- * Read coverage data from disk. Checks these locations in order:
24
- * 1. coverage/coverage-summary.json (Jest/Istanbul)
25
- * 2. coverage/lcov.info (lcov format)
26
- * 3. .nyc_output/out.json (nyc)
27
- */
28
- function readCoverageFromDisk() {
29
- const cwd = process.cwd();
30
- const noData = {
31
- found: false,
32
- source: 'none',
33
- entries: [],
34
- summary: { totalFiles: 0, overallLineCoverage: 0, overallBranchCoverage: 0, overallFunctionCoverage: 0, overallStatementCoverage: 0 },
35
- };
36
- // 1. Try coverage-summary.json (Jest/Istanbul)
37
- for (const relPath of ['coverage/coverage-summary.json', 'coverage-summary.json']) {
38
- const summaryPath = join(cwd, relPath);
39
- if (existsSync(summaryPath)) {
40
- try {
41
- const raw = JSON.parse(readFileSync(summaryPath, 'utf-8'));
42
- return parseCoverageSummaryJson(raw, relPath);
43
- }
44
- catch {
45
- // malformed, try next
46
- }
47
- }
48
- }
49
- // 2. Try lcov.info
50
- for (const relPath of ['coverage/lcov.info', 'lcov.info']) {
51
- const lcovPath = join(cwd, relPath);
52
- if (existsSync(lcovPath)) {
53
- try {
54
- const raw = readFileSync(lcovPath, 'utf-8');
55
- return parseLcovInfo(raw, relPath);
56
- }
57
- catch {
58
- // malformed, try next
59
- }
60
- }
61
- }
62
- // 3. Try .nyc_output/out.json
63
- const nycPath = join(cwd, '.nyc_output', 'out.json');
64
- if (existsSync(nycPath)) {
65
- try {
66
- const raw = JSON.parse(readFileSync(nycPath, 'utf-8'));
67
- return parseCoverageSummaryJson(raw, '.nyc_output/out.json');
68
- }
69
- catch {
70
- // malformed
71
- }
72
- }
73
- return noData;
74
- }
75
- function parseCoverageSummaryJson(data, source) {
76
- const entries = [];
77
- let totalLines = 0, coveredLines = 0;
78
- let totalBranches = 0, coveredBranches = 0;
79
- let totalFunctions = 0, coveredFunctions = 0;
80
- let totalStatements = 0, coveredStatements = 0;
81
- for (const [filePath, metrics] of Object.entries(data)) {
82
- if (filePath === 'total')
83
- continue;
84
- const m = metrics;
85
- if (!m || typeof m !== 'object')
86
- continue;
87
- const linePct = m.lines?.pct ?? m.lines?.covered != null ? ((m.lines?.covered ?? 0) / Math.max(m.lines?.total ?? 1, 1)) * 100 : 0;
88
- const branchPct = m.branches?.pct ?? (m.branches?.total ? ((m.branches?.covered ?? 0) / m.branches.total) * 100 : 100);
89
- const funcPct = m.functions?.pct ?? (m.functions?.total ? ((m.functions?.covered ?? 0) / m.functions.total) * 100 : 100);
90
- const stmtPct = m.statements?.pct ?? (m.statements?.total ? ((m.statements?.covered ?? 0) / m.statements.total) * 100 : 100);
91
- entries.push({ filePath, lines: linePct, branches: branchPct, functions: funcPct, statements: stmtPct });
92
- totalLines += m.lines?.total ?? 0;
93
- coveredLines += m.lines?.covered ?? 0;
94
- totalBranches += m.branches?.total ?? 0;
95
- coveredBranches += m.branches?.covered ?? 0;
96
- totalFunctions += m.functions?.total ?? 0;
97
- coveredFunctions += m.functions?.covered ?? 0;
98
- totalStatements += m.statements?.total ?? 0;
99
- coveredStatements += m.statements?.covered ?? 0;
100
- }
101
- // Also read the total key if present
102
- const total = data['total'];
103
- const overallLine = total?.lines?.pct ?? (totalLines > 0 ? (coveredLines / totalLines) * 100 : 0);
104
- const overallBranch = total?.branches?.pct ?? (totalBranches > 0 ? (coveredBranches / totalBranches) * 100 : 0);
105
- const overallFunction = total?.functions?.pct ?? (totalFunctions > 0 ? (coveredFunctions / totalFunctions) * 100 : 0);
106
- const overallStatement = total?.statements?.pct ?? (totalStatements > 0 ? (coveredStatements / totalStatements) * 100 : 0);
107
- // Sort by lowest line coverage
108
- entries.sort((a, b) => a.lines - b.lines);
109
- return {
110
- found: true,
111
- source,
112
- entries,
113
- summary: {
114
- totalFiles: entries.length,
115
- overallLineCoverage: overallLine,
116
- overallBranchCoverage: overallBranch,
117
- overallFunctionCoverage: overallFunction,
118
- overallStatementCoverage: overallStatement,
119
- },
120
- };
121
- }
122
- function parseLcovInfo(raw, source) {
123
- const entries = [];
124
- let currentFile = '';
125
- let linesHit = 0, linesFound = 0;
126
- let branchesHit = 0, branchesFound = 0;
127
- let functionsHit = 0, functionsFound = 0;
128
- const flushRecord = () => {
129
- if (currentFile) {
130
- entries.push({
131
- filePath: currentFile,
132
- lines: linesFound > 0 ? (linesHit / linesFound) * 100 : 0,
133
- branches: branchesFound > 0 ? (branchesHit / branchesFound) * 100 : 100,
134
- functions: functionsFound > 0 ? (functionsHit / functionsFound) * 100 : 100,
135
- statements: linesFound > 0 ? (linesHit / linesFound) * 100 : 0,
136
- });
137
- }
138
- };
139
- for (const line of raw.split('\n')) {
140
- const trimmed = line.trim();
141
- if (trimmed.startsWith('SF:')) {
142
- currentFile = trimmed.slice(3);
143
- linesHit = 0;
144
- linesFound = 0;
145
- branchesHit = 0;
146
- branchesFound = 0;
147
- functionsHit = 0;
148
- functionsFound = 0;
149
- }
150
- else if (trimmed.startsWith('LH:')) {
151
- linesHit = parseInt(trimmed.slice(3), 10) || 0;
152
- }
153
- else if (trimmed.startsWith('LF:')) {
154
- linesFound = parseInt(trimmed.slice(3), 10) || 0;
155
- }
156
- else if (trimmed.startsWith('BRH:')) {
157
- branchesHit = parseInt(trimmed.slice(4), 10) || 0;
158
- }
159
- else if (trimmed.startsWith('BRF:')) {
160
- branchesFound = parseInt(trimmed.slice(4), 10) || 0;
161
- }
162
- else if (trimmed.startsWith('FNH:')) {
163
- functionsHit = parseInt(trimmed.slice(4), 10) || 0;
164
- }
165
- else if (trimmed.startsWith('FNF:')) {
166
- functionsFound = parseInt(trimmed.slice(4), 10) || 0;
167
- }
168
- else if (trimmed === 'end_of_record') {
169
- flushRecord();
170
- currentFile = '';
171
- }
172
- }
173
- flushRecord();
174
- entries.sort((a, b) => a.lines - b.lines);
175
- let totalLH = 0, totalLF = 0, totalBH = 0, totalBF = 0;
176
- for (const e of entries) {
177
- // Approximate from percentages (we lost exact counts after flush, but summaries are okay)
178
- totalLH += e.lines;
179
- totalLF += 100;
180
- totalBH += e.branches;
181
- totalBF += 100;
182
- }
183
- const n = entries.length || 1;
184
- return {
185
- found: true,
186
- source,
187
- entries,
188
- summary: {
189
- totalFiles: entries.length,
190
- overallLineCoverage: totalLH / n,
191
- overallBranchCoverage: totalBH / n,
192
- overallFunctionCoverage: 0,
193
- overallStatementCoverage: totalLH / n,
194
- },
195
- };
196
- }
197
- /**
198
- * Classify a coverage gap by priority type based on coverage percentage and threshold
199
- */
200
- function classifyCoverageGap(coveragePct, threshold) {
201
- if (coveragePct < threshold * 0.25)
202
- return { gapType: 'critical', priority: 10 };
203
- if (coveragePct < threshold * 0.5)
204
- return { gapType: 'high', priority: 7 };
205
- if (coveragePct < threshold * 0.75)
206
- return { gapType: 'medium', priority: 5 };
207
- if (coveragePct < threshold)
208
- return { gapType: 'low', priority: 3 };
209
- return { gapType: 'ok', priority: 0 };
210
- }
211
- /**
212
- * Suggest agents for a file based on its path
213
- */
214
- function suggestAgentsForFile(filePath) {
215
- const lower = filePath.toLowerCase();
216
- if (lower.includes('test') || lower.includes('spec'))
217
- return ['tester'];
218
- if (lower.includes('security') || lower.includes('auth'))
219
- return ['security-auditor', 'tester'];
220
- if (lower.includes('api') || lower.includes('route') || lower.includes('controller'))
221
- return ['coder', 'tester'];
222
- if (lower.includes('model') || lower.includes('schema') || lower.includes('entity'))
223
- return ['coder', 'tester'];
224
- return ['tester', 'coder'];
225
- }
226
- // Hook types
227
- const HOOK_TYPES = [
228
- { value: 'pre-edit', label: 'Pre-Edit', hint: 'Get context before editing files' },
229
- { value: 'post-edit', label: 'Post-Edit', hint: 'Record editing outcomes' },
230
- { value: 'pre-command', label: 'Pre-Command', hint: 'Assess risk before commands' },
231
- { value: 'post-command', label: 'Post-Command', hint: 'Record command outcomes' },
232
- { value: 'route', label: 'Route', hint: 'Route tasks to optimal agents' },
233
- { value: 'explain', label: 'Explain', hint: 'Explain routing decisions' }
234
- ];
235
- // Agent routing options
236
- const AGENT_TYPES = [
237
- 'coder', 'researcher', 'tester', 'reviewer', 'architect',
238
- 'security-architect', 'security-auditor', 'memory-specialist',
239
- 'swarm-specialist', 'performance-engineer', 'core-architect',
240
- 'test-architect', 'coordinator', 'analyst', 'optimizer'
241
- ];
242
- // Pre-edit subcommand
243
- const preEditCommand = {
244
- name: 'pre-edit',
245
- description: 'Get context and agent suggestions before editing a file',
246
- options: [
247
- {
248
- name: 'file',
249
- short: 'f',
250
- description: 'File path to edit',
251
- type: 'string',
252
- required: false
253
- },
254
- {
255
- name: 'operation',
256
- short: 'o',
257
- description: 'Type of edit operation (create, update, delete, refactor)',
258
- type: 'string',
259
- default: 'update'
260
- },
261
- {
262
- name: 'context',
263
- short: 'c',
264
- description: 'Additional context about the edit',
265
- type: 'string'
266
- }
267
- ],
268
- examples: [
269
- { command: 'claude-flow hooks pre-edit -f src/utils.ts', description: 'Get context before editing' },
270
- { command: 'claude-flow hooks pre-edit -f src/api.ts -o refactor', description: 'Pre-edit with operation type' }
271
- ],
272
- action: async (ctx) => {
273
- // Default file to 'unknown' for backward compatibility (env var may be empty)
274
- const filePath = ctx.flags.file || ctx.args[0] || 'unknown';
275
- const operation = ctx.flags.operation || 'update';
276
- output.printInfo(`Analyzing context for: ${output.highlight(filePath)}`);
277
- try {
278
- // Call MCP tool for pre-edit hook
279
- const result = await callMCPTool('hooks_pre-edit', {
280
- filePath,
281
- operation,
282
- context: ctx.flags.context,
283
- includePatterns: true,
284
- includeRisks: true,
285
- });
286
- if (ctx.flags.format === 'json') {
287
- output.printJson(result);
288
- return { success: true, data: result };
289
- }
290
- output.writeln();
291
- output.printBox([
292
- `File: ${result.filePath}`,
293
- `Operation: ${result.operation}`,
294
- `Type: ${result.context.fileType}`,
295
- `Exists: ${result.context.fileExists ? 'Yes' : 'No'}`
296
- ].join('\n'), 'File Context');
297
- if (result.context.suggestedAgents.length > 0) {
298
- output.writeln();
299
- output.writeln(output.bold('Suggested Agents'));
300
- output.printList(result.context.suggestedAgents.map(a => output.highlight(a)));
301
- }
302
- if (result.context.relatedFiles.length > 0) {
303
- output.writeln();
304
- output.writeln(output.bold('Related Files'));
305
- output.printList(result.context.relatedFiles.slice(0, 5).map(f => output.dim(f)));
306
- }
307
- if (result.context.patterns.length > 0) {
308
- output.writeln();
309
- output.writeln(output.bold('Learned Patterns'));
310
- output.printTable({
311
- columns: [
312
- { key: 'pattern', header: 'Pattern', width: 40 },
313
- { key: 'confidence', header: 'Confidence', width: 12, align: 'right', format: (v) => `${(Number(v) * 100).toFixed(1)}%` }
314
- ],
315
- data: result.context.patterns
316
- });
317
- }
318
- if (result.context.risks.length > 0) {
319
- output.writeln();
320
- output.writeln(output.bold(output.error('Potential Risks')));
321
- output.printList(result.context.risks.map(r => output.warning(r)));
322
- }
323
- if (result.recommendations.length > 0) {
324
- output.writeln();
325
- output.writeln(output.bold('Recommendations'));
326
- output.printList(result.recommendations.map(r => output.success(`• ${r}`)));
327
- }
328
- return { success: true, data: result };
329
- }
330
- catch (error) {
331
- if (error instanceof MCPClientError) {
332
- output.printError(`Pre-edit hook failed: ${error.message}`);
333
- }
334
- else {
335
- output.printError(`Unexpected error: ${String(error)}`);
336
- }
337
- return { success: false, exitCode: 1 };
338
- }
339
- }
340
- };
341
- // Post-edit subcommand
342
- const postEditCommand = {
343
- name: 'post-edit',
344
- description: 'Record editing outcome for learning',
345
- options: [
346
- {
347
- name: 'file',
348
- short: 'f',
349
- description: 'File path that was edited',
350
- type: 'string',
351
- required: false
352
- },
353
- {
354
- name: 'success',
355
- short: 's',
356
- description: 'Whether the edit was successful',
357
- type: 'boolean',
358
- required: false
359
- },
360
- {
361
- name: 'outcome',
362
- short: 'o',
363
- description: 'Outcome description',
364
- type: 'string'
365
- },
366
- {
367
- name: 'metrics',
368
- short: 'm',
369
- description: 'Performance metrics (e.g., "time:500ms,quality:0.95")',
370
- type: 'string'
371
- }
372
- ],
373
- examples: [
374
- { command: 'claude-flow hooks post-edit -f src/utils.ts --success true', description: 'Record successful edit' },
375
- { command: 'claude-flow hooks post-edit -f src/api.ts --success false -o "Type error"', description: 'Record failed edit' }
376
- ],
377
- action: async (ctx) => {
378
- // Default file to 'unknown' for backward compatibility (env var may be empty)
379
- const filePath = ctx.flags.file || ctx.args[0] || 'unknown';
380
- // Default success to true for backward compatibility (PostToolUse = success, PostToolUseFailure = failure)
381
- const success = ctx.flags.success !== undefined ? ctx.flags.success : true;
382
- output.printInfo(`Recording outcome for: ${output.highlight(filePath)}`);
383
- try {
384
- // Parse metrics if provided
385
- const metrics = {};
386
- if (ctx.flags.metrics) {
387
- const metricsStr = ctx.flags.metrics;
388
- metricsStr.split(',').forEach(pair => {
389
- const [key, value] = pair.split(':');
390
- if (key && value) {
391
- metrics[key.trim()] = parseFloat(value);
392
- }
393
- });
394
- }
395
- // Call MCP tool for post-edit hook
396
- const result = await callMCPTool('hooks_post-edit', {
397
- filePath,
398
- success,
399
- outcome: ctx.flags.outcome,
400
- metrics,
401
- timestamp: Date.now(),
402
- });
403
- // #2352: the MCP handler returns `{success: false, error: "..."}` on
404
- // validation failure (e.g. unsupported path shape) without throwing.
405
- // Surface that explicitly instead of always printing the success line —
406
- // Windows users were seeing `[OK]` while nothing reached the learning
407
- // pipeline because absolute paths were rejected upstream.
408
- const mcpFailed = result && result.success === false;
409
- const mcpError = result?.error;
410
- if (ctx.flags.format === 'json') {
411
- output.printJson(result);
412
- return { success: !mcpFailed, exitCode: mcpFailed ? 1 : 0, data: result };
413
- }
414
- if (mcpFailed) {
415
- output.printError(`Post-edit hook failed: ${mcpError || 'unknown error'}`);
416
- return { success: false, exitCode: 1 };
417
- }
418
- output.writeln();
419
- output.printSuccess(`Outcome recorded for ${filePath}`);
420
- if (result.learningUpdates) {
421
- output.writeln();
422
- output.writeln(output.bold('Learning Updates'));
423
- output.printTable({
424
- columns: [
425
- { key: 'metric', header: 'Metric', width: 25 },
426
- { key: 'value', header: 'Value', width: 15, align: 'right' }
427
- ],
428
- data: [
429
- { metric: 'Patterns Updated', value: result.learningUpdates.patternsUpdated },
430
- { metric: 'Confidence Adjusted', value: result.learningUpdates.confidenceAdjusted },
431
- { metric: 'New Patterns', value: result.learningUpdates.newPatterns }
432
- ]
433
- });
434
- }
435
- return { success: true, data: result };
436
- }
437
- catch (error) {
438
- if (error instanceof MCPClientError) {
439
- output.printError(`Post-edit hook failed: ${error.message}`);
440
- }
441
- else {
442
- output.printError(`Unexpected error: ${String(error)}`);
443
- }
444
- return { success: false, exitCode: 1 };
445
- }
446
- }
447
- };
448
- // Pre-command subcommand
449
- const preCommandCommand = {
450
- name: 'pre-command',
451
- description: 'Assess risk before executing a command',
452
- options: [
453
- {
454
- name: 'command',
455
- short: 'c',
456
- description: 'Command to execute',
457
- type: 'string',
458
- required: true
459
- },
460
- {
461
- name: 'dry-run',
462
- short: 'd',
463
- description: 'Only analyze, do not execute',
464
- type: 'boolean',
465
- default: true
466
- }
467
- ],
468
- examples: [
469
- { command: 'claude-flow hooks pre-command -c "rm -rf dist"', description: 'Assess command risk' },
470
- { command: 'claude-flow hooks pre-command -c "npm install lodash"', description: 'Check package install' }
471
- ],
472
- action: async (ctx) => {
473
- const command = ctx.flags.command || ctx.args[0];
474
- if (!command) {
475
- output.printError('Command is required. Use --command or -c flag.');
476
- return { success: false, exitCode: 1 };
477
- }
478
- output.printInfo(`Analyzing command: ${output.highlight(command)}`);
479
- try {
480
- // Call MCP tool for pre-command hook
481
- const result = await callMCPTool('hooks_pre-command', {
482
- command,
483
- includeAlternatives: true,
484
- });
485
- if (ctx.flags.format === 'json') {
486
- output.printJson(result);
487
- return { success: true, data: result };
488
- }
489
- output.writeln();
490
- // Risk level indicator
491
- let riskIndicator;
492
- switch (result.riskLevel) {
493
- case 'critical':
494
- riskIndicator = output.error('CRITICAL');
495
- break;
496
- case 'high':
497
- riskIndicator = output.error('HIGH');
498
- break;
499
- case 'medium':
500
- riskIndicator = output.warning('MEDIUM');
501
- break;
502
- default:
503
- riskIndicator = output.success('LOW');
504
- }
505
- output.printBox([
506
- `Risk Level: ${riskIndicator}`,
507
- `Should Proceed: ${result.shouldProceed ? output.success('Yes') : output.error('No')}`
508
- ].join('\n'), 'Risk Assessment');
509
- if (result.risks.length > 0) {
510
- output.writeln();
511
- output.writeln(output.bold('Identified Risks'));
512
- output.printTable({
513
- columns: [
514
- { key: 'type', header: 'Type', width: 15 },
515
- { key: 'severity', header: 'Severity', width: 10 },
516
- { key: 'description', header: 'Description', width: 40 }
517
- ],
518
- data: result.risks
519
- });
520
- }
521
- if (result.safeAlternatives && result.safeAlternatives.length > 0) {
522
- output.writeln();
523
- output.writeln(output.bold('Safe Alternatives'));
524
- output.printList(result.safeAlternatives.map(a => output.success(a)));
525
- }
526
- if (result.recommendations.length > 0) {
527
- output.writeln();
528
- output.writeln(output.bold('Recommendations'));
529
- output.printList(result.recommendations);
530
- }
531
- return { success: true, data: result };
532
- }
533
- catch (error) {
534
- if (error instanceof MCPClientError) {
535
- output.printError(`Pre-command hook failed: ${error.message}`);
536
- }
537
- else {
538
- output.printError(`Unexpected error: ${String(error)}`);
539
- }
540
- return { success: false, exitCode: 1 };
541
- }
542
- }
543
- };
544
- // Post-command subcommand
545
- const postCommandCommand = {
546
- name: 'post-command',
547
- description: 'Record command execution outcome',
548
- options: [
549
- {
550
- name: 'command',
551
- short: 'c',
552
- description: 'Command that was executed',
553
- type: 'string',
554
- required: true
555
- },
556
- {
557
- name: 'success',
558
- short: 's',
559
- description: 'Whether the command succeeded',
560
- type: 'boolean',
561
- required: false
562
- },
563
- {
564
- name: 'exit-code',
565
- short: 'e',
566
- description: 'Command exit code',
567
- type: 'number',
568
- default: 0
569
- },
570
- {
571
- name: 'duration',
572
- short: 'd',
573
- description: 'Execution duration in milliseconds',
574
- type: 'number'
575
- }
576
- ],
577
- examples: [
578
- { command: 'claude-flow hooks post-command -c "npm test" --success true', description: 'Record successful test run' },
579
- { command: 'claude-flow hooks post-command -c "npm build" --success false -e 1', description: 'Record failed build' }
580
- ],
581
- action: async (ctx) => {
582
- const command = ctx.flags.command || ctx.args[0];
583
- // Default success to true for backward compatibility
584
- const success = ctx.flags.success !== undefined ? ctx.flags.success : true;
585
- if (!command) {
586
- output.printError('Command is required. Use --command or -c flag.');
587
- return { success: false, exitCode: 1 };
588
- }
589
- output.printInfo(`Recording command outcome: ${output.highlight(command)}`);
590
- try {
591
- // Call MCP tool for post-command hook
592
- const result = await callMCPTool('hooks_post-command', {
593
- command,
594
- success,
595
- exitCode: ctx.flags.exitCode || 0,
596
- duration: ctx.flags.duration,
597
- timestamp: Date.now(),
598
- });
599
- if (ctx.flags.format === 'json') {
600
- output.printJson(result);
601
- return { success: true, data: result };
602
- }
603
- output.writeln();
604
- output.printSuccess('Command outcome recorded');
605
- if (result.learningUpdates) {
606
- output.writeln();
607
- output.writeln(output.dim(`Patterns updated: ${result.learningUpdates.commandPatternsUpdated}`));
608
- output.writeln(output.dim(`Risk assessment: ${result.learningUpdates.riskAssessmentUpdated ? 'Updated' : 'No change'}`));
609
- }
610
- return { success: true, data: result };
611
- }
612
- catch (error) {
613
- if (error instanceof MCPClientError) {
614
- output.printError(`Post-command hook failed: ${error.message}`);
615
- }
616
- else {
617
- output.printError(`Unexpected error: ${String(error)}`);
618
- }
619
- return { success: false, exitCode: 1 };
620
- }
621
- }
622
- };
623
- // Route subcommand
624
- const routeCommand = {
625
- name: 'route',
626
- description: 'Route task to optimal agent using learned patterns',
627
- options: [
628
- {
629
- name: 'task',
630
- short: 't',
631
- description: 'Task description',
632
- type: 'string',
633
- required: true
634
- },
635
- {
636
- name: 'context',
637
- short: 'c',
638
- description: 'Additional context',
639
- type: 'string'
640
- },
641
- {
642
- name: 'top-k',
643
- short: 'K',
644
- description: 'Number of top agent suggestions',
645
- type: 'number',
646
- default: 3
647
- }
648
- ],
649
- examples: [
650
- { command: 'claude-flow hooks route -t "Fix authentication bug"', description: 'Route task to optimal agent' },
651
- { command: 'claude-flow hooks route -t "Optimize database queries" -K 5', description: 'Get top 5 suggestions' }
652
- ],
653
- action: async (ctx) => {
654
- const task = ctx.flags.task || ctx.args[0];
655
- const topK = ctx.flags.topK || 3;
656
- if (!task) {
657
- output.printError('Task description is required. Use --task or -t flag.');
658
- return { success: false, exitCode: 1 };
659
- }
660
- output.printInfo(`Routing task: ${output.highlight(task)}`);
661
- try {
662
- // Call MCP tool for routing
663
- const result = await callMCPTool('hooks_route', {
664
- task,
665
- context: ctx.flags.context,
666
- topK,
667
- includeEstimates: true,
668
- });
669
- if (ctx.flags.format === 'json') {
670
- output.printJson(result);
671
- return { success: true, data: result };
672
- }
673
- // Show routing method info
674
- if (result.routing) {
675
- output.writeln();
676
- output.writeln(output.bold('Routing Method'));
677
- const methodDisplay = result.routing.method.startsWith('semantic')
678
- ? output.success(`${result.routing.method} (${result.routing.backend || 'semantic'})`)
679
- : 'keyword';
680
- output.printList([
681
- `Method: ${methodDisplay}`,
682
- result.routing.backend ? `Backend: ${result.routing.backend}` : null,
683
- `Latency: ${result.routing.latencyMs.toFixed(3)}ms`,
684
- result.matchedPattern ? `Matched Pattern: ${result.matchedPattern}` : null,
685
- ].filter(Boolean));
686
- // Show semantic matches if available
687
- if (result.semanticMatches && result.semanticMatches.length > 0) {
688
- output.writeln();
689
- output.writeln(output.dim('Semantic Matches:'));
690
- result.semanticMatches.forEach(m => {
691
- output.writeln(` ${m.pattern}: ${(m.score * 100).toFixed(1)}%`);
692
- });
693
- }
694
- }
695
- output.writeln();
696
- output.printBox([
697
- `Agent: ${output.highlight(result.primaryAgent.type)}`,
698
- `Confidence: ${(result.primaryAgent.confidence * 100).toFixed(1)}%`,
699
- `Reason: ${result.primaryAgent.reason}`
700
- ].join('\n'), 'Primary Recommendation');
701
- if (result.alternativeAgents.length > 0) {
702
- output.writeln();
703
- output.writeln(output.bold('Alternative Agents'));
704
- output.printTable({
705
- columns: [
706
- { key: 'type', header: 'Agent Type', width: 20 },
707
- { key: 'confidence', header: 'Confidence', width: 12, align: 'right', format: (v) => `${(Number(v) * 100).toFixed(1)}%` },
708
- { key: 'reason', header: 'Reason', width: 35 }
709
- ],
710
- data: result.alternativeAgents
711
- });
712
- }
713
- if (result.estimatedMetrics) {
714
- output.writeln();
715
- output.writeln(output.bold('Estimated Metrics'));
716
- output.printList([
717
- `Success Probability: ${(result.estimatedMetrics.successProbability * 100).toFixed(1)}%`,
718
- `Estimated Duration: ${result.estimatedMetrics.estimatedDuration}`,
719
- `Complexity: ${result.estimatedMetrics.complexity.toUpperCase()}`
720
- ]);
721
- }
722
- return { success: true, data: result };
723
- }
724
- catch (error) {
725
- if (error instanceof MCPClientError) {
726
- output.printError(`Routing failed: ${error.message}`);
727
- }
728
- else {
729
- output.printError(`Unexpected error: ${String(error)}`);
730
- }
731
- return { success: false, exitCode: 1 };
732
- }
733
- }
734
- };
735
- // Explain subcommand
736
- const explainCommand = {
737
- name: 'explain',
738
- description: 'Explain routing decision with transparency',
739
- options: [
740
- {
741
- name: 'task',
742
- short: 't',
743
- description: 'Task description',
744
- type: 'string',
745
- required: true
746
- },
747
- {
748
- name: 'agent',
749
- short: 'a',
750
- description: 'Agent type to explain',
751
- type: 'string'
752
- },
753
- {
754
- name: 'verbose',
755
- short: 'v',
756
- description: 'Verbose explanation',
757
- type: 'boolean',
758
- default: false
759
- }
760
- ],
761
- examples: [
762
- { command: 'claude-flow hooks explain -t "Fix authentication bug"', description: 'Explain routing decision' },
763
- { command: 'claude-flow hooks explain -t "Optimize queries" -a coder --verbose', description: 'Verbose explanation for specific agent' }
764
- ],
765
- action: async (ctx) => {
766
- const task = ctx.flags.task || ctx.args[0];
767
- if (!task) {
768
- output.printError('Task description is required. Use --task or -t flag.');
769
- return { success: false, exitCode: 1 };
770
- }
771
- output.printInfo(`Explaining routing for: ${output.highlight(task)}`);
772
- try {
773
- // Call MCP tool for explanation
774
- const result = await callMCPTool('hooks_explain', {
775
- task,
776
- agent: ctx.flags.agent,
777
- verbose: ctx.flags.verbose || false,
778
- });
779
- if (ctx.flags.format === 'json') {
780
- output.printJson(result);
781
- return { success: true, data: result };
782
- }
783
- output.writeln();
784
- output.writeln(output.bold('Decision Explanation'));
785
- output.writeln();
786
- output.writeln(result.explanation);
787
- output.writeln();
788
- output.printBox([
789
- `Agent: ${output.highlight(result.decision.agent)}`,
790
- `Confidence: ${(result.decision.confidence * 100).toFixed(1)}%`
791
- ].join('\n'), 'Final Decision');
792
- if (result.decision.reasoning.length > 0) {
793
- output.writeln();
794
- output.writeln(output.bold('Reasoning Steps'));
795
- output.printList(result.decision.reasoning.map((r, i) => `${i + 1}. ${r}`));
796
- }
797
- if (result.factors.length > 0) {
798
- output.writeln();
799
- output.writeln(output.bold('Decision Factors'));
800
- output.printTable({
801
- columns: [
802
- { key: 'factor', header: 'Factor', width: 20 },
803
- { key: 'weight', header: 'Weight', width: 10, align: 'right', format: (v) => `${(Number(v) * 100).toFixed(0)}%` },
804
- { key: 'value', header: 'Value', width: 10, align: 'right', format: (v) => Number(v).toFixed(2) },
805
- { key: 'impact', header: 'Impact', width: 25 }
806
- ],
807
- data: result.factors
808
- });
809
- }
810
- if (result.patterns.length > 0 && ctx.flags.verbose) {
811
- output.writeln();
812
- output.writeln(output.bold('Matched Patterns'));
813
- result.patterns.forEach((p, i) => {
814
- output.writeln();
815
- output.writeln(`${i + 1}. ${output.highlight(p.pattern)} (${(p.matchScore * 100).toFixed(1)}% match)`);
816
- if (p.examples.length > 0) {
817
- output.printList(p.examples.slice(0, 3).map(e => output.dim(` ${e}`)));
818
- }
819
- });
820
- }
821
- return { success: true, data: result };
822
- }
823
- catch (error) {
824
- if (error instanceof MCPClientError) {
825
- output.printError(`Explanation failed: ${error.message}`);
826
- }
827
- else {
828
- output.printError(`Unexpected error: ${String(error)}`);
829
- }
830
- return { success: false, exitCode: 1 };
831
- }
832
- }
833
- };
834
- // Pretrain subcommand
835
- const pretrainCommand = {
836
- name: 'pretrain',
837
- description: 'Bootstrap intelligence from repository (4-step pipeline + embeddings)',
838
- options: [
839
- {
840
- name: 'path',
841
- short: 'p',
842
- description: 'Repository path',
843
- type: 'string',
844
- default: '.'
845
- },
846
- {
847
- name: 'depth',
848
- short: 'd',
849
- description: 'Analysis depth (shallow, medium, deep)',
850
- type: 'string',
851
- default: 'medium',
852
- choices: ['shallow', 'medium', 'deep']
853
- },
854
- {
855
- name: 'skip-cache',
856
- description: 'Skip cached analysis',
857
- type: 'boolean',
858
- default: false
859
- },
860
- {
861
- name: 'with-embeddings',
862
- description: 'Index documents for semantic search during pretraining',
863
- type: 'boolean',
864
- default: true
865
- },
866
- {
867
- name: 'embedding-model',
868
- description: 'ONNX embedding model',
869
- type: 'string',
870
- default: 'Xenova/all-MiniLM-L6-v2',
871
- choices: ['Xenova/all-MiniLM-L6-v2', 'Xenova/all-mpnet-base-v2']
872
- },
873
- {
874
- name: 'file-types',
875
- description: 'File extensions to index (comma-separated)',
876
- type: 'string',
877
- default: 'ts,js,py,md,json'
878
- }
879
- ],
880
- examples: [
881
- { command: 'claude-flow hooks pretrain', description: 'Pretrain with embeddings indexing' },
882
- { command: 'claude-flow hooks pretrain -p ../my-project --depth deep', description: 'Deep analysis of specific project' },
883
- { command: 'claude-flow hooks pretrain --no-with-embeddings', description: 'Skip embedding indexing' },
884
- { command: 'claude-flow hooks pretrain --file-types ts,tsx,js', description: 'Index only TypeScript/JS files' }
885
- ],
886
- action: async (ctx) => {
887
- const repoPath = ctx.flags.path || '.';
888
- const depth = ctx.flags.depth || 'medium';
889
- const withEmbeddings = ctx.flags['with-embeddings'] !== false && ctx.flags.withEmbeddings !== false;
890
- const embeddingModel = (ctx.flags['embedding-model'] || ctx.flags.embeddingModel || 'Xenova/all-MiniLM-L6-v2');
891
- const fileTypes = (ctx.flags['file-types'] || ctx.flags.fileTypes || 'ts,js,py,md,json');
892
- output.writeln();
893
- output.writeln(output.bold('Pretraining Intelligence (4-Step Pipeline + Embeddings)'));
894
- output.writeln();
895
- const steps = [
896
- { name: 'RETRIEVE', desc: 'Top-k memory injection with MMR diversity' },
897
- { name: 'JUDGE', desc: 'LLM-as-judge trajectory evaluation' },
898
- { name: 'DISTILL', desc: 'Extract strategy memories from trajectories' },
899
- { name: 'CONSOLIDATE', desc: 'Dedup, detect contradictions, prune old patterns' }
900
- ];
901
- // Add embedding steps if enabled
902
- if (withEmbeddings) {
903
- steps.push({ name: 'EMBED', desc: `Index documents with ${embeddingModel} (ONNX)` }, { name: 'HYPERBOLIC', desc: 'Project to Poincaré ball for hierarchy preservation' });
904
- }
905
- const spinner = output.createSpinner({ text: 'Starting pretraining...', spinner: 'dots' });
906
- try {
907
- spinner.start();
908
- // Display progress for each step
909
- for (const step of steps) {
910
- spinner.setText(`${step.name}: ${step.desc}`);
911
- await new Promise(resolve => setTimeout(resolve, 800));
912
- }
913
- // Call MCP tool for pretraining. The tool currently returns
914
- // `{ statistics: { ..., executionTime }, ... }` but earlier CLI
915
- // versions read `result.stats` and `result.duration` (#1686). Accept
916
- // either shape so the dashboard works whether you upgraded the tool
917
- // or the CLI first.
918
- const rawResult = await callMCPTool('hooks_pretrain', {
919
- path: repoPath,
920
- depth,
921
- skipCache: ctx.flags.skipCache || false,
922
- withEmbeddings,
923
- embeddingModel,
924
- fileTypes: fileTypes.split(',').map((t) => t.trim()),
925
- });
926
- spinner.succeed('Pretraining completed');
927
- // Normalize shape: prefer `statistics`, fall back to `stats` for older tools.
928
- // #1686 — coerce duration through safeNum so a NaN from the underlying
929
- // pretrain pipeline surfaces as `0.0s` rather than `NaNs`.
930
- const stats = (rawResult.statistics ?? rawResult.stats ?? {});
931
- const durationMs = safeNum(rawResult.duration ?? rawResult.statistics?.executionTime);
932
- const result = { ...rawResult, stats, duration: durationMs };
933
- if (ctx.flags.format === 'json') {
934
- output.printJson(result);
935
- return { success: true, data: result };
936
- }
937
- output.writeln();
938
- // Base stats — use ?? 0 fallbacks to keep the table readable even when
939
- // the tool omits a counter rather than crashing on undefined.
940
- const tableData = [
941
- { metric: 'Files Analyzed', value: stats.filesAnalyzed ?? 0 },
942
- { metric: 'Patterns Extracted', value: stats.patternsExtracted ?? 0 },
943
- { metric: 'Strategies Learned', value: stats.strategiesLearned ?? 0 },
944
- { metric: 'Trajectories Evaluated', value: stats.trajectoriesEvaluated ?? 0 },
945
- { metric: 'Contradictions Resolved', value: stats.contradictionsResolved ?? 0 },
946
- ];
947
- // Add embedding stats if available
948
- if (withEmbeddings && stats.documentsIndexed !== undefined) {
949
- tableData.push({ metric: 'Documents Indexed', value: stats.documentsIndexed }, { metric: 'Embeddings Generated', value: stats.embeddingsGenerated ?? 0 }, { metric: 'Hyperbolic Projections', value: stats.hyperbolicProjections ?? 0 });
950
- }
951
- tableData.push({ metric: 'Duration', value: `${(durationMs / 1000).toFixed(1)}s` });
952
- output.printTable({
953
- columns: [
954
- { key: 'metric', header: 'Metric', width: 30 },
955
- { key: 'value', header: 'Value', width: 15, align: 'right' }
956
- ],
957
- data: tableData
958
- });
959
- output.writeln();
960
- output.printSuccess('Repository intelligence bootstrapped successfully');
961
- if (withEmbeddings) {
962
- output.writeln(output.dim(' Semantic search enabled: Use "embeddings search -q <query>" to search'));
963
- }
964
- output.writeln(output.dim(' Next step: Run "claude-flow hooks build-agents" to generate optimized configs'));
965
- return { success: true, data: result };
966
- }
967
- catch (error) {
968
- spinner.fail('Pretraining failed');
969
- if (error instanceof MCPClientError) {
970
- output.printError(`Pretraining error: ${error.message}`);
971
- }
972
- else {
973
- output.printError(`Unexpected error: ${String(error)}`);
974
- }
975
- return { success: false, exitCode: 1 };
976
- }
977
- }
978
- };
979
- // Build agents subcommand
980
- const buildAgentsCommand = {
981
- name: 'build-agents',
982
- description: 'Generate optimized agent configs from pretrain data',
983
- options: [
984
- {
985
- name: 'output',
986
- short: 'o',
987
- description: 'Output directory for agent configs',
988
- type: 'string',
989
- default: './agents'
990
- },
991
- {
992
- name: 'focus',
993
- short: 'f',
994
- description: 'Focus area (v3-implementation, security, performance, all)',
995
- type: 'string',
996
- default: 'all'
997
- },
998
- {
999
- name: 'config-format',
1000
- description: 'Config format (yaml, json)',
1001
- type: 'string',
1002
- default: 'yaml',
1003
- choices: ['yaml', 'json']
1004
- }
1005
- ],
1006
- examples: [
1007
- { command: 'claude-flow hooks build-agents', description: 'Build all agent configs' },
1008
- { command: 'claude-flow hooks build-agents --focus security -o ./config/agents', description: 'Build security-focused configs' }
1009
- ],
1010
- action: async (ctx) => {
1011
- const output_dir = ctx.flags.output || './agents';
1012
- const focus = ctx.flags.focus || 'all';
1013
- const configFormat = ctx.flags.configFormat || 'yaml';
1014
- output.printInfo(`Building agent configs (focus: ${output.highlight(focus)})`);
1015
- const spinner = output.createSpinner({ text: 'Generating configs...', spinner: 'dots' });
1016
- try {
1017
- spinner.start();
1018
- // Call MCP tool for building agents
1019
- const result = await callMCPTool('hooks_build-agents', {
1020
- outputDir: output_dir,
1021
- focus,
1022
- format: configFormat,
1023
- includePretrained: true,
1024
- });
1025
- spinner.succeed(`Generated ${result.agents.length} agent configs`);
1026
- if (ctx.flags.format === 'json') {
1027
- output.printJson(result);
1028
- return { success: true, data: result };
1029
- }
1030
- output.writeln();
1031
- output.writeln(output.bold('Generated Agent Configs'));
1032
- output.printTable({
1033
- columns: [
1034
- { key: 'type', header: 'Agent Type', width: 20 },
1035
- { key: 'configFile', header: 'Config File', width: 30 },
1036
- { key: 'capabilities', header: 'Capabilities', width: 10, align: 'right', format: (v) => String(Array.isArray(v) ? v.length : 0) }
1037
- ],
1038
- data: result.agents
1039
- });
1040
- output.writeln();
1041
- output.printTable({
1042
- columns: [
1043
- { key: 'metric', header: 'Metric', width: 30 },
1044
- { key: 'value', header: 'Value', width: 15, align: 'right' }
1045
- ],
1046
- data: [
1047
- { metric: 'Configs Generated', value: result.stats.configsGenerated },
1048
- { metric: 'Patterns Applied', value: result.stats.patternsApplied },
1049
- { metric: 'Optimizations Included', value: result.stats.optimizationsIncluded }
1050
- ]
1051
- });
1052
- output.writeln();
1053
- output.printSuccess(`Agent configs saved to ${output_dir}`);
1054
- return { success: true, data: result };
1055
- }
1056
- catch (error) {
1057
- spinner.fail('Agent config generation failed');
1058
- if (error instanceof MCPClientError) {
1059
- output.printError(`Build agents error: ${error.message}`);
1060
- }
1061
- else {
1062
- output.printError(`Unexpected error: ${String(error)}`);
1063
- }
1064
- return { success: false, exitCode: 1 };
1065
- }
1066
- }
1067
- };
1068
- // Metrics subcommand
1069
- const metricsCommand = {
1070
- name: 'metrics',
1071
- description: 'View learning metrics dashboard',
1072
- options: [
1073
- {
1074
- name: 'period',
1075
- short: 'p',
1076
- description: 'Time period (1h, 24h, 7d, 30d, all)',
1077
- type: 'string',
1078
- default: '24h'
1079
- },
1080
- {
1081
- name: 'v3-dashboard',
1082
- description: 'Show V3 performance dashboard',
1083
- type: 'boolean',
1084
- default: false
1085
- },
1086
- {
1087
- name: 'category',
1088
- short: 'c',
1089
- description: 'Metric category (patterns, agents, commands, performance)',
1090
- type: 'string'
1091
- }
1092
- ],
1093
- examples: [
1094
- { command: 'claude-flow hooks metrics', description: 'View 24h metrics' },
1095
- { command: 'claude-flow hooks metrics --period 7d --v3-dashboard', description: 'V3 metrics for 7 days' }
1096
- ],
1097
- action: async (ctx) => {
1098
- const period = ctx.flags.period || '24h';
1099
- const v3Dashboard = ctx.flags.v3Dashboard;
1100
- output.writeln();
1101
- output.writeln(output.bold(`Learning Metrics Dashboard (${period})`));
1102
- output.writeln();
1103
- try {
1104
- // Call MCP tool for metrics. The tool returns `{ summary, routing,
1105
- // edits, commands }` (see MetricsResult in v3/mcp/tools/hooks-tools.ts)
1106
- // but earlier CLI versions expected `{ patterns, agents, commands.avgRiskScore }`.
1107
- // Accept the union and normalize below — without the `?? 0` guards the
1108
- // dashboard crashed with "Cannot read properties of null (reading 'toFixed')"
1109
- // whenever a counter was missing (#1686).
1110
- const rawMetrics = await callMCPTool('hooks_metrics', {
1111
- period,
1112
- includeV3: v3Dashboard,
1113
- category: ctx.flags.category,
1114
- });
1115
- // Normalize across both shapes; default every numeric to 0 so toFixed
1116
- // never sees null/undefined. #1686 — also coerce NaN through `safeNum`
1117
- // because `?? 0` only catches null/undefined; an upstream NaN would
1118
- // still land in `.toFixed(...)` and surface as `"NaN"`.
1119
- const totalPatterns = safeNum(rawMetrics.patterns?.total ?? rawMetrics.summary?.patternsLearned);
1120
- const successfulPatterns = safeNum(rawMetrics.patterns?.successful ?? Math.round(safeNum(rawMetrics.summary?.successRate) * totalPatterns));
1121
- const failedPatterns = Math.max(0, safeNum(rawMetrics.patterns?.failed ?? totalPatterns - successfulPatterns));
1122
- const avgConfidence = safeNum(rawMetrics.patterns?.avgConfidence ?? rawMetrics.summary?.avgQuality);
1123
- const routingAccuracy = safeNum(rawMetrics.agents?.routingAccuracy ?? rawMetrics.routing?.avgConfidence);
1124
- const totalRoutes = safeNum(rawMetrics.agents?.totalRoutes ?? rawMetrics.routing?.totalRoutes);
1125
- const topAgent = rawMetrics.agents?.topAgent ?? rawMetrics.routing?.topAgents?.[0]?.agent ?? 'n/a';
1126
- const totalCommands = safeNum(rawMetrics.commands?.totalExecuted ?? rawMetrics.commands?.totalCommands);
1127
- const commandSuccessRate = safeNum(rawMetrics.commands?.successRate);
1128
- const avgRiskScore = safeNum(rawMetrics.commands?.avgRiskScore ?? rawMetrics.commands?.avgExecutionTime);
1129
- const result = {
1130
- ...rawMetrics,
1131
- patterns: { total: totalPatterns, successful: successfulPatterns, failed: failedPatterns, avgConfidence },
1132
- agents: { routingAccuracy, totalRoutes, topAgent },
1133
- commands: { totalExecuted: totalCommands, successRate: commandSuccessRate, avgRiskScore },
1134
- };
1135
- if (ctx.flags.format === 'json') {
1136
- output.printJson(result);
1137
- return { success: true, data: result };
1138
- }
1139
- // Patterns section
1140
- output.writeln(output.bold('📊 Pattern Learning'));
1141
- output.printTable({
1142
- columns: [
1143
- { key: 'metric', header: 'Metric', width: 25 },
1144
- { key: 'value', header: 'Value', width: 20, align: 'right' }
1145
- ],
1146
- data: [
1147
- { metric: 'Total Patterns', value: totalPatterns },
1148
- { metric: 'Successful', value: output.success(String(successfulPatterns)) },
1149
- { metric: 'Failed', value: output.error(String(failedPatterns)) },
1150
- { metric: 'Avg Confidence', value: `${(avgConfidence * 100).toFixed(1)}%` }
1151
- ]
1152
- });
1153
- output.writeln();
1154
- // Agent routing section
1155
- output.writeln(output.bold('🤖 Agent Routing'));
1156
- output.printTable({
1157
- columns: [
1158
- { key: 'metric', header: 'Metric', width: 25 },
1159
- { key: 'value', header: 'Value', width: 20, align: 'right' }
1160
- ],
1161
- data: [
1162
- { metric: 'Routing Accuracy', value: `${(routingAccuracy * 100).toFixed(1)}%` },
1163
- { metric: 'Total Routes', value: totalRoutes },
1164
- { metric: 'Top Agent', value: output.highlight(topAgent) }
1165
- ]
1166
- });
1167
- output.writeln();
1168
- // Command execution section
1169
- output.writeln(output.bold('⚡ Command Execution'));
1170
- output.printTable({
1171
- columns: [
1172
- { key: 'metric', header: 'Metric', width: 25 },
1173
- { key: 'value', header: 'Value', width: 20, align: 'right' }
1174
- ],
1175
- data: [
1176
- { metric: 'Total Executed', value: totalCommands },
1177
- { metric: 'Success Rate', value: `${(commandSuccessRate * 100).toFixed(1)}%` },
1178
- { metric: 'Avg Risk Score', value: avgRiskScore.toFixed(2) }
1179
- ]
1180
- });
1181
- if (v3Dashboard && result.performance) {
1182
- const p = result.performance;
1183
- output.writeln();
1184
- output.writeln(output.bold('🚀 V3 Performance Gains'));
1185
- output.printList([
1186
- `Flash Attention: ${output.success(p.flashAttention ?? 'N/A')}`,
1187
- `Memory Reduction: ${output.success(p.memoryReduction ?? 'N/A')}`,
1188
- `Search Improvement: ${output.success(p.searchImprovement ?? 'N/A')}`,
1189
- `Token Reduction: ${output.success(p.tokenReduction ?? 'N/A')}`
1190
- ]);
1191
- }
1192
- return { success: true, data: result };
1193
- }
1194
- catch (error) {
1195
- if (error instanceof MCPClientError) {
1196
- output.printError(`Metrics error: ${error.message}`);
1197
- }
1198
- else {
1199
- output.printError(`Unexpected error: ${String(error)}`);
1200
- }
1201
- return { success: false, exitCode: 1 };
1202
- }
1203
- }
1204
- };
1205
- // Pattern Store command (imported from transfer-store.ts)
1206
- // storeCommand is imported at the top
1207
- // Transfer from project subcommand
1208
- const transferFromProjectCommand = {
1209
- name: 'from-project',
1210
- aliases: ['project'],
1211
- description: 'Transfer patterns from another project',
1212
- options: [
1213
- {
1214
- name: 'source',
1215
- short: 's',
1216
- description: 'Source project path',
1217
- type: 'string',
1218
- required: true
1219
- },
1220
- {
1221
- name: 'filter',
1222
- short: 'f',
1223
- description: 'Filter patterns by type',
1224
- type: 'string'
1225
- },
1226
- {
1227
- name: 'min-confidence',
1228
- short: 'm',
1229
- description: 'Minimum confidence threshold (0-1)',
1230
- type: 'number',
1231
- default: 0.7
1232
- }
1233
- ],
1234
- examples: [
1235
- { command: 'claude-flow hooks transfer from-project -s ../old-project', description: 'Transfer all patterns' },
1236
- { command: 'claude-flow hooks transfer from-project -s ../prod --filter security -m 0.9', description: 'Transfer high-confidence security patterns' }
1237
- ],
1238
- action: async (ctx) => {
1239
- const sourcePath = ctx.flags.source || ctx.args[0];
1240
- const minConfidence = ctx.flags.minConfidence || 0.7;
1241
- if (!sourcePath) {
1242
- output.printError('Source project path is required. Use --source or -s flag.');
1243
- return { success: false, exitCode: 1 };
1244
- }
1245
- output.printInfo(`Transferring patterns from: ${output.highlight(sourcePath)}`);
1246
- const spinner = output.createSpinner({ text: 'Analyzing source patterns...', spinner: 'dots' });
1247
- try {
1248
- spinner.start();
1249
- // Call MCP tool for transfer
1250
- const result = await callMCPTool('hooks_transfer', {
1251
- sourcePath,
1252
- filter: ctx.flags.filter,
1253
- minConfidence,
1254
- mergeStrategy: 'keep-highest-confidence',
1255
- });
1256
- spinner.succeed(`Transferred ${result.transferred.total} patterns`);
1257
- if (ctx.flags.format === 'json') {
1258
- output.printJson(result);
1259
- return { success: true, data: result };
1260
- }
1261
- output.writeln();
1262
- output.writeln(output.bold('Transfer Summary'));
1263
- output.printTable({
1264
- columns: [
1265
- { key: 'category', header: 'Category', width: 25 },
1266
- { key: 'count', header: 'Count', width: 15, align: 'right' }
1267
- ],
1268
- data: [
1269
- { category: 'Total Transferred', count: output.success(String(result.transferred.total)) },
1270
- { category: 'Skipped (Low Confidence)', count: result.skipped.lowConfidence },
1271
- { category: 'Skipped (Duplicates)', count: result.skipped.duplicates },
1272
- { category: 'Skipped (Conflicts)', count: result.skipped.conflicts }
1273
- ]
1274
- });
1275
- if (Object.keys(result.transferred.byType).length > 0) {
1276
- output.writeln();
1277
- output.writeln(output.bold('By Pattern Type'));
1278
- output.printTable({
1279
- columns: [
1280
- { key: 'type', header: 'Type', width: 20 },
1281
- { key: 'count', header: 'Count', width: 15, align: 'right' }
1282
- ],
1283
- data: Object.entries(result.transferred.byType).map(([type, count]) => ({ type, count }))
1284
- });
1285
- }
1286
- output.writeln();
1287
- output.printList([
1288
- `Avg Confidence: ${(result.stats.avgConfidence * 100).toFixed(1)}%`,
1289
- `Avg Age: ${result.stats.avgAge}`
1290
- ]);
1291
- return { success: true, data: result };
1292
- }
1293
- catch (error) {
1294
- spinner.fail('Transfer failed');
1295
- if (error instanceof MCPClientError) {
1296
- output.printError(`Transfer error: ${error.message}`);
1297
- }
1298
- else {
1299
- output.printError(`Unexpected error: ${String(error)}`);
1300
- }
1301
- return { success: false, exitCode: 1 };
1302
- }
1303
- }
1304
- };
1305
- // Parent transfer command combining all transfer methods
1306
- const transferCommand = {
1307
- name: 'transfer',
1308
- description: 'Transfer patterns and plugins via IPFS-based decentralized registry',
1309
- subcommands: [storeCommand, transferFromProjectCommand],
1310
- examples: [
1311
- { command: 'claude-flow hooks transfer store list', description: 'List patterns from registry' },
1312
- { command: 'claude-flow hooks transfer store search -q routing', description: 'Search patterns' },
1313
- { command: 'claude-flow hooks transfer store download -p seraphine-genesis', description: 'Download pattern' },
1314
- { command: 'claude-flow hooks transfer store publish', description: 'Publish pattern to registry' },
1315
- { command: 'claude-flow hooks transfer from-project -s ../other-project', description: 'Transfer from project' },
1316
- ],
1317
- action: async () => {
1318
- output.writeln();
1319
- output.writeln(output.bold('Pattern Transfer System'));
1320
- output.writeln(output.dim('Decentralized pattern sharing via IPFS'));
1321
- output.writeln();
1322
- output.writeln('Subcommands:');
1323
- output.printList([
1324
- `${output.highlight('store')} - Pattern marketplace (list, search, download, publish)`,
1325
- `${output.highlight('from-project')} - Transfer patterns from another project`,
1326
- ]);
1327
- output.writeln();
1328
- output.writeln(output.bold('IPFS-Based Features:'));
1329
- output.printList([
1330
- 'Decentralized registry via IPNS for discoverability',
1331
- 'Content-addressed storage for integrity',
1332
- 'Ed25519 signatures for verification',
1333
- 'Anonymization levels: minimal, standard, strict, paranoid',
1334
- 'Trust levels: unverified, community, verified, official',
1335
- ]);
1336
- output.writeln();
1337
- output.writeln('Run "claude-flow hooks transfer <subcommand> --help" for details');
1338
- return { success: true };
1339
- }
1340
- };
1341
- // List subcommand
1342
- const listCommand = {
1343
- name: 'list',
1344
- aliases: ['ls'],
1345
- description: 'List all registered hooks',
1346
- options: [
1347
- {
1348
- name: 'enabled',
1349
- short: 'e',
1350
- description: 'Show only enabled hooks',
1351
- type: 'boolean',
1352
- default: false
1353
- },
1354
- {
1355
- name: 'type',
1356
- short: 't',
1357
- description: 'Filter by hook type',
1358
- type: 'string'
1359
- }
1360
- ],
1361
- action: async (ctx) => {
1362
- try {
1363
- // Call MCP tool for list
1364
- const result = await callMCPTool('hooks_list', {
1365
- enabled: ctx.flags.enabled || undefined,
1366
- type: ctx.flags.type || undefined,
1367
- });
1368
- if (ctx.flags.format === 'json') {
1369
- output.printJson(result);
1370
- return { success: true, data: result };
1371
- }
1372
- output.writeln();
1373
- output.writeln(output.bold('Registered Hooks'));
1374
- output.writeln();
1375
- if (result.hooks.length === 0) {
1376
- output.printInfo('No hooks found matching criteria');
1377
- return { success: true, data: result };
1378
- }
1379
- output.printTable({
1380
- columns: [
1381
- { key: 'name', header: 'Name', width: 20 },
1382
- { key: 'type', header: 'Type', width: 15 },
1383
- { key: 'enabled', header: 'Enabled', width: 10, format: (v) => v ? output.success('Yes') : output.dim('No') },
1384
- { key: 'priority', header: 'Priority', width: 10, align: 'right' },
1385
- { key: 'executionCount', header: 'Executions', width: 12, align: 'right' },
1386
- { key: 'lastExecuted', header: 'Last Executed', width: 20, format: (v) => v ? new Date(String(v)).toLocaleString() : 'Never' }
1387
- ],
1388
- data: result.hooks
1389
- });
1390
- output.writeln();
1391
- output.printInfo(`Total: ${result.total} hooks`);
1392
- return { success: true, data: result };
1393
- }
1394
- catch (error) {
1395
- if (error instanceof MCPClientError) {
1396
- output.printError(`Failed to list hooks: ${error.message}`);
1397
- }
1398
- else {
1399
- output.printError(`Unexpected error: ${String(error)}`);
1400
- }
1401
- return { success: false, exitCode: 1 };
1402
- }
1403
- }
1404
- };
1405
- // Pre-task subcommand
1406
- const preTaskCommand = {
1407
- name: 'pre-task',
1408
- description: 'Record task start and get agent suggestions',
1409
- options: [
1410
- {
1411
- name: 'task-id',
1412
- short: 'i',
1413
- description: 'Unique task identifier (auto-generated if omitted)',
1414
- type: 'string'
1415
- },
1416
- {
1417
- name: 'description',
1418
- short: 'd',
1419
- description: 'Task description',
1420
- type: 'string',
1421
- required: true
1422
- },
1423
- {
1424
- name: 'auto-spawn',
1425
- short: 'a',
1426
- description: 'Auto-spawn suggested agents',
1427
- type: 'boolean',
1428
- default: false
1429
- }
1430
- ],
1431
- examples: [
1432
- { command: 'claude-flow hooks pre-task -i task-123 -d "Fix auth bug"', description: 'Record task start' },
1433
- { command: 'claude-flow hooks pre-task -i task-456 -d "Implement feature" --auto-spawn', description: 'With auto-spawn' }
1434
- ],
1435
- action: async (ctx) => {
1436
- const taskId = ctx.flags.taskId || `task-${Date.now().toString(36)}`;
1437
- const description = ctx.flags.description || ctx.args[0];
1438
- if (!description) {
1439
- output.printError('Description is required: --description "your task"');
1440
- return { success: false, exitCode: 1 };
1441
- }
1442
- output.printInfo(`Starting task: ${output.highlight(taskId)}`);
1443
- try {
1444
- const result = await callMCPTool('hooks_pre-task', {
1445
- taskId,
1446
- description,
1447
- autoSpawn: ctx.flags.autoSpawn || false,
1448
- timestamp: Date.now(),
1449
- });
1450
- if (ctx.flags.format === 'json') {
1451
- output.printJson(result);
1452
- return { success: true, data: result };
1453
- }
1454
- output.writeln();
1455
- output.printBox([
1456
- `Task ID: ${result.taskId}`,
1457
- `Description: ${result.description}`,
1458
- `Complexity: ${result.complexity.toUpperCase()}`,
1459
- `Est. Duration: ${result.estimatedDuration}`
1460
- ].join('\n'), 'Task Registered');
1461
- if (result.suggestedAgents.length > 0) {
1462
- output.writeln();
1463
- output.writeln(output.bold('Suggested Agents'));
1464
- output.printTable({
1465
- columns: [
1466
- { key: 'type', header: 'Agent Type', width: 20 },
1467
- { key: 'confidence', header: 'Confidence', width: 12, align: 'right', format: (v) => `${(Number(v) * 100).toFixed(1)}%` },
1468
- { key: 'reason', header: 'Reason', width: 35 }
1469
- ],
1470
- data: result.suggestedAgents
1471
- });
1472
- }
1473
- if (result.risks.length > 0) {
1474
- output.writeln();
1475
- output.writeln(output.bold(output.error('Potential Risks')));
1476
- output.printList(result.risks.map(r => output.warning(r)));
1477
- }
1478
- if (result.recommendations.length > 0) {
1479
- output.writeln();
1480
- output.writeln(output.bold('Recommendations'));
1481
- output.printList(result.recommendations);
1482
- }
1483
- // Enhanced model routing with deterministic codemod Tier-1 (ADR-026, ADR-143)
1484
- try {
1485
- const { getEnhancedModelRouter } = await import('../ruvector/enhanced-model-router.js');
1486
- const router = getEnhancedModelRouter();
1487
- const routeResult = await router.route(description, { filePath: ctx.flags.file });
1488
- const intent = routeResult.codemodIntent ?? routeResult.agentBoosterIntent;
1489
- output.writeln();
1490
- output.writeln(output.bold('Intelligent Model Routing'));
1491
- if (routeResult.tier === 1) {
1492
- // Deterministic codemod can apply this edit - skip LLM entirely ($0)
1493
- output.writeln(output.success(` Tier 1: Deterministic codemod`));
1494
- output.writeln(output.dim(` Intent: ${intent?.type}`));
1495
- output.writeln(output.dim(` Latency: ~1ms | Cost: $0 | No LLM`));
1496
- output.writeln();
1497
- output.writeln(output.dim('─'.repeat(60)));
1498
- output.writeln(output.bold(output.success(`[CODEMOD_AVAILABLE] Skip LLM — call hooks_codemod with intent="${intent?.type}" (deterministic, $0)`)));
1499
- output.writeln(output.dim(`Confidence: ${(routeResult.confidence * 100).toFixed(0)}% | Intent: ${intent?.description}`));
1500
- output.writeln(output.dim('─'.repeat(60)));
1501
- }
1502
- else {
1503
- // LLM required - show tier and model recommendation
1504
- output.writeln(` Tier ${routeResult.tier}: ${routeResult.handler.toUpperCase()}`);
1505
- output.writeln(output.dim(` Complexity: ${((routeResult.complexity || 0) * 100).toFixed(0)}%`));
1506
- output.writeln(output.dim(` Est. Latency: ${routeResult.estimatedLatencyMs}ms | Cost: $${routeResult.estimatedCost.toFixed(4)}`));
1507
- output.writeln();
1508
- // Clear instruction for Claude
1509
- output.writeln(output.dim('─'.repeat(60)));
1510
- output.writeln(output.bold(output.success(`[TASK_MODEL_RECOMMENDATION] Use model="${routeResult.model}" for this task`)));
1511
- output.writeln(output.dim(`Complexity: ${((routeResult.complexity || 0) * 100).toFixed(0)}% | Confidence: ${(routeResult.confidence * 100).toFixed(0)}%`));
1512
- output.writeln(output.dim('─'.repeat(60)));
1513
- }
1514
- // Add routing result for programmatic use
1515
- result.routeResult = routeResult;
1516
- result.recommendedModel = routeResult.model;
1517
- result.modelRouting = {
1518
- tier: routeResult.tier,
1519
- handler: routeResult.handler,
1520
- model: routeResult.model,
1521
- confidence: routeResult.confidence,
1522
- complexity: routeResult.complexity,
1523
- reasoning: routeResult.reasoning,
1524
- canSkipLLM: routeResult.canSkipLLM,
1525
- deterministic: routeResult.deterministic,
1526
- codemodIntent: routeResult.codemodIntent ?? routeResult.agentBoosterIntent,
1527
- };
1528
- }
1529
- catch {
1530
- // Enhanced router not available, skip recommendation
1531
- }
1532
- return { success: true, data: result };
1533
- }
1534
- catch (error) {
1535
- if (error instanceof MCPClientError) {
1536
- output.printError(`Pre-task hook failed: ${error.message}`);
1537
- }
1538
- else {
1539
- output.printError(`Unexpected error: ${String(error)}`);
1540
- }
1541
- return { success: false, exitCode: 1 };
1542
- }
1543
- }
1544
- };
1545
- // Post-task subcommand
1546
- const postTaskCommand = {
1547
- name: 'post-task',
1548
- description: 'Record task completion for learning',
1549
- options: [
1550
- {
1551
- name: 'task-id',
1552
- short: 'i',
1553
- description: 'Unique task identifier (auto-generated if not provided)',
1554
- type: 'string',
1555
- required: false
1556
- },
1557
- {
1558
- name: 'success',
1559
- short: 's',
1560
- description: 'Whether the task succeeded',
1561
- type: 'boolean',
1562
- required: false
1563
- },
1564
- {
1565
- name: 'quality',
1566
- short: 'q',
1567
- description: 'Quality score (0-1)',
1568
- type: 'number'
1569
- },
1570
- {
1571
- name: 'agent',
1572
- short: 'a',
1573
- description: 'Agent that executed the task',
1574
- type: 'string'
1575
- },
1576
- {
1577
- // ADR-147 P2: nested-subagent spawn-tree capture
1578
- name: 'parent-agent-id',
1579
- description: 'ID of the parent agent (from Claude Code\'s parent_agent_id OTel span tag). Omit for top-level work.',
1580
- type: 'string',
1581
- required: false
1582
- },
1583
- {
1584
- name: 'depth',
1585
- description: 'Chain depth from root lead session (0 = lead, 1+ = subagent). Used by ADR-147 P3 depth-aware guardrail.',
1586
- type: 'number',
1587
- required: false
1588
- }
1589
- ],
1590
- examples: [
1591
- { command: 'claude-flow hooks post-task -i task-123 --success true', description: 'Record successful completion' },
1592
- { command: 'claude-flow hooks post-task -i task-456 --success false -q 0.3', description: 'Record failed task' }
1593
- ],
1594
- action: async (ctx) => {
1595
- // Auto-generate task ID if not provided
1596
- const taskId = ctx.flags.taskId || `task_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1597
- // Default success to true for backward compatibility
1598
- const success = ctx.flags.success !== undefined ? ctx.flags.success : true;
1599
- output.printInfo(`Recording outcome for task: ${output.highlight(taskId)}`);
1600
- try {
1601
- const result = await callMCPTool('hooks_post-task', {
1602
- taskId,
1603
- success,
1604
- quality: ctx.flags.quality,
1605
- agent: ctx.flags.agent,
1606
- timestamp: Date.now(),
1607
- // ADR-147 P2: forward spawn-tree lineage if caller supplied it
1608
- parentAgentId: ctx.flags.parentAgentId,
1609
- depth: ctx.flags.depth,
1610
- });
1611
- if (ctx.flags.format === 'json') {
1612
- output.printJson(result);
1613
- return { success: true, data: result };
1614
- }
1615
- output.writeln();
1616
- output.printSuccess(`Task outcome recorded: ${success ? 'SUCCESS' : 'FAILED'}`);
1617
- output.writeln();
1618
- output.writeln(output.bold('Learning Updates'));
1619
- output.printTable({
1620
- columns: [
1621
- { key: 'metric', header: 'Metric', width: 25 },
1622
- { key: 'value', header: 'Value', width: 20, align: 'right' }
1623
- ],
1624
- data: [
1625
- { metric: 'Patterns Updated', value: result.learningUpdates.patternsUpdated },
1626
- { metric: 'New Patterns', value: result.learningUpdates.newPatterns },
1627
- { metric: 'Duration', value: `${(result.duration / 1000).toFixed(1)}s` },
1628
- { metric: 'Trajectory ID', value: result.learningUpdates.trajectoryId }
1629
- ]
1630
- });
1631
- return { success: true, data: result };
1632
- }
1633
- catch (error) {
1634
- if (error instanceof MCPClientError) {
1635
- output.printError(`Post-task hook failed: ${error.message}`);
1636
- }
1637
- else {
1638
- output.printError(`Unexpected error: ${String(error)}`);
1639
- }
1640
- return { success: false, exitCode: 1 };
1641
- }
1642
- }
1643
- };
1644
- // Session-end subcommand
1645
- const sessionEndCommand = {
1646
- name: 'session-end',
1647
- description: 'End current session and persist state',
1648
- options: [
1649
- {
1650
- name: 'save-state',
1651
- short: 's',
1652
- description: 'Save session state for later restoration',
1653
- type: 'boolean',
1654
- default: true
1655
- }
1656
- ],
1657
- examples: [
1658
- { command: 'claude-flow hooks session-end', description: 'End and save session' },
1659
- { command: 'claude-flow hooks session-end --save-state false', description: 'End without saving' }
1660
- ],
1661
- action: async (ctx) => {
1662
- output.printInfo('Ending session...');
1663
- try {
1664
- const result = await callMCPTool('hooks_session-end', {
1665
- saveState: ctx.flags.saveState ?? true,
1666
- timestamp: Date.now(),
1667
- });
1668
- if (ctx.flags.format === 'json') {
1669
- output.printJson(result);
1670
- return { success: true, data: result };
1671
- }
1672
- output.writeln();
1673
- output.printSuccess(`Session ${result.sessionId} ended`);
1674
- output.writeln();
1675
- output.writeln(output.bold('Session Summary'));
1676
- output.printTable({
1677
- columns: [
1678
- { key: 'metric', header: 'Metric', width: 25 },
1679
- { key: 'value', header: 'Value', width: 15, align: 'right' }
1680
- ],
1681
- data: [
1682
- { metric: 'Duration', value: `${(result.duration / 1000 / 60).toFixed(1)} min` },
1683
- { metric: 'Tasks Executed', value: result.summary.tasksExecuted },
1684
- { metric: 'Tasks Succeeded', value: output.success(String(result.summary.tasksSucceeded)) },
1685
- { metric: 'Tasks Failed', value: output.error(String(result.summary.tasksFailed)) },
1686
- { metric: 'Commands Executed', value: result.summary.commandsExecuted },
1687
- { metric: 'Files Modified', value: result.summary.filesModified },
1688
- { metric: 'Agents Spawned', value: result.summary.agentsSpawned }
1689
- ]
1690
- });
1691
- if (result.statePath) {
1692
- output.writeln();
1693
- output.writeln(output.dim(`State saved to: ${result.statePath}`));
1694
- }
1695
- return { success: true, data: result };
1696
- }
1697
- catch (error) {
1698
- if (error instanceof MCPClientError) {
1699
- output.printError(`Session-end hook failed: ${error.message}`);
1700
- }
1701
- else {
1702
- output.printError(`Unexpected error: ${String(error)}`);
1703
- }
1704
- return { success: false, exitCode: 1 };
1705
- }
1706
- }
1707
- };
1708
- // Session-restore subcommand
1709
- const sessionRestoreCommand = {
1710
- name: 'session-restore',
1711
- description: 'Restore a previous session',
1712
- options: [
1713
- {
1714
- name: 'session-id',
1715
- short: 'i',
1716
- description: 'Session ID to restore (use "latest" for most recent)',
1717
- type: 'string',
1718
- default: 'latest'
1719
- },
1720
- {
1721
- name: 'restore-agents',
1722
- short: 'a',
1723
- description: 'Restore spawned agents',
1724
- type: 'boolean',
1725
- default: true
1726
- },
1727
- {
1728
- name: 'restore-tasks',
1729
- short: 't',
1730
- description: 'Restore active tasks',
1731
- type: 'boolean',
1732
- default: true
1733
- }
1734
- ],
1735
- examples: [
1736
- { command: 'claude-flow hooks session-restore', description: 'Restore latest session' },
1737
- { command: 'claude-flow hooks session-restore -i session-12345', description: 'Restore specific session' }
1738
- ],
1739
- action: async (ctx) => {
1740
- const sessionId = ctx.flags.sessionId || ctx.args[0] || 'latest';
1741
- output.printInfo(`Restoring session: ${output.highlight(sessionId)}`);
1742
- try {
1743
- const result = await callMCPTool('hooks_session-restore', {
1744
- sessionId,
1745
- restoreAgents: ctx.flags.restoreAgents ?? true,
1746
- restoreTasks: ctx.flags.restoreTasks ?? true,
1747
- timestamp: Date.now(),
1748
- });
1749
- if (ctx.flags.format === 'json') {
1750
- output.printJson(result);
1751
- return { success: true, data: result };
1752
- }
1753
- output.writeln();
1754
- output.printSuccess(`Session restored from ${result.originalSessionId}`);
1755
- output.writeln(output.dim(`New session ID: ${result.sessionId}`));
1756
- output.writeln();
1757
- output.writeln(output.bold('Restored State'));
1758
- output.printTable({
1759
- columns: [
1760
- { key: 'item', header: 'Item', width: 25 },
1761
- { key: 'count', header: 'Count', width: 15, align: 'right' }
1762
- ],
1763
- data: [
1764
- { item: 'Tasks', count: result.restoredState.tasksRestored },
1765
- { item: 'Agents', count: result.restoredState.agentsRestored },
1766
- { item: 'Memory Entries', count: result.restoredState.memoryRestored }
1767
- ]
1768
- });
1769
- if (result.warnings && result.warnings.length > 0) {
1770
- output.writeln();
1771
- output.writeln(output.bold(output.warning('Warnings')));
1772
- output.printList(result.warnings.map(w => output.warning(w)));
1773
- }
1774
- return { success: true, data: result };
1775
- }
1776
- catch (error) {
1777
- if (error instanceof MCPClientError) {
1778
- output.printError(`Session-restore hook failed: ${error.message}`);
1779
- }
1780
- else {
1781
- output.printError(`Unexpected error: ${String(error)}`);
1782
- }
1783
- return { success: false, exitCode: 1 };
1784
- }
1785
- }
1786
- };
1787
- // Intelligence subcommand (SONA, MoE, HNSW)
1788
- const intelligenceCommand = {
1789
- name: 'intelligence',
1790
- description: 'RuVector intelligence system (SONA, MoE, HNSW 150x faster)',
1791
- options: [
1792
- {
1793
- name: 'mode',
1794
- short: 'm',
1795
- description: 'Intelligence mode (real-time, batch, edge, research, balanced)',
1796
- type: 'string',
1797
- choices: ['real-time', 'batch', 'edge', 'research', 'balanced'],
1798
- default: 'balanced'
1799
- },
1800
- {
1801
- name: 'enable-sona',
1802
- description: 'Enable SONA sub-0.05ms learning',
1803
- type: 'boolean',
1804
- default: true
1805
- },
1806
- {
1807
- name: 'enable-moe',
1808
- description: 'Enable Mixture of Experts routing',
1809
- type: 'boolean',
1810
- default: true
1811
- },
1812
- {
1813
- name: 'enable-hnsw',
1814
- description: 'Enable HNSW 150x faster search',
1815
- type: 'boolean',
1816
- default: true
1817
- },
1818
- {
1819
- name: 'status',
1820
- short: 's',
1821
- description: 'Show current intelligence status',
1822
- type: 'boolean',
1823
- default: false
1824
- },
1825
- {
1826
- name: 'train',
1827
- short: 't',
1828
- description: 'Force training cycle',
1829
- type: 'boolean',
1830
- default: false
1831
- },
1832
- {
1833
- name: 'reset',
1834
- short: 'r',
1835
- description: 'Reset learning state',
1836
- type: 'boolean',
1837
- default: false
1838
- },
1839
- {
1840
- name: 'embedding-provider',
1841
- description: 'Embedding provider (transformers, openai, mock)',
1842
- type: 'string',
1843
- choices: ['transformers', 'openai', 'mock'],
1844
- default: 'transformers'
1845
- }
1846
- ],
1847
- examples: [
1848
- { command: 'claude-flow hooks intelligence --status', description: 'Show intelligence status' },
1849
- { command: 'claude-flow hooks intelligence -m real-time', description: 'Enable real-time mode' },
1850
- { command: 'claude-flow hooks intelligence --train', description: 'Force training cycle' }
1851
- ],
1852
- action: async (ctx) => {
1853
- const mode = ctx.flags.mode || 'balanced';
1854
- const showStatus = ctx.flags.status;
1855
- const forceTraining = ctx.flags.train;
1856
- const reset = ctx.flags.reset;
1857
- const enableSona = ctx.flags.enableSona ?? true;
1858
- const enableMoe = ctx.flags.enableMoe ?? true;
1859
- const enableHnsw = ctx.flags.enableHnsw ?? true;
1860
- const embeddingProvider = ctx.flags.embeddingProvider || 'transformers';
1861
- output.writeln();
1862
- output.writeln(output.bold('RuVector Intelligence System'));
1863
- output.writeln();
1864
- if (reset) {
1865
- const confirmed = await confirm({
1866
- message: 'Reset all learning state? This cannot be undone.',
1867
- default: false
1868
- });
1869
- if (!confirmed) {
1870
- output.printInfo('Reset cancelled');
1871
- return { success: true };
1872
- }
1873
- output.printInfo('Resetting learning state...');
1874
- try {
1875
- await callMCPTool('hooks_intelligence-reset', {});
1876
- output.printSuccess('Learning state reset');
1877
- return { success: true };
1878
- }
1879
- catch (error) {
1880
- output.printError(`Reset failed: ${error}`);
1881
- return { success: false, exitCode: 1 };
1882
- }
1883
- }
1884
- const spinner = output.createSpinner({ text: 'Initializing intelligence system...', spinner: 'dots' });
1885
- try {
1886
- spinner.start();
1887
- // Read local intelligence data from disk first
1888
- const { getIntelligenceStats, initializeIntelligence, getPersistenceStatus } = await import('../memory/intelligence.js');
1889
- await initializeIntelligence();
1890
- const localStats = getIntelligenceStats();
1891
- const persistence = getPersistenceStatus();
1892
- // Read patterns.json file size and entry count
1893
- let patternsFileSize = 0;
1894
- let patternsFileEntries = 0;
1895
- if (persistence.patternsExist) {
1896
- try {
1897
- const pStat = statSync(persistence.patternsFile);
1898
- patternsFileSize = pStat.size;
1899
- const pData = JSON.parse(readFileSync(persistence.patternsFile, 'utf-8'));
1900
- if (Array.isArray(pData))
1901
- patternsFileEntries = pData.length;
1902
- }
1903
- catch { /* ignore */ }
1904
- }
1905
- // Read stats.json for trajectory data
1906
- let trajectoriesFromDisk = 0;
1907
- let lastAdaptationFromDisk = null;
1908
- if (persistence.statsExist) {
1909
- try {
1910
- const sData = JSON.parse(readFileSync(persistence.statsFile, 'utf-8'));
1911
- trajectoriesFromDisk = sData?.trajectoriesRecorded ?? 0;
1912
- lastAdaptationFromDisk = sData?.lastAdaptation ?? null;
1913
- }
1914
- catch { /* ignore */ }
1915
- }
1916
- // Merge local stats with any we can get from MCP
1917
- let mcpResult = null;
1918
- try {
1919
- mcpResult = await callMCPTool('hooks_intelligence', {
1920
- mode,
1921
- enableSona,
1922
- enableMoe,
1923
- enableHnsw,
1924
- embeddingProvider,
1925
- forceTraining,
1926
- showStatus,
1927
- });
1928
- }
1929
- catch {
1930
- // MCP not available, use local data only
1931
- }
1932
- // Build merged result, preferring local real data over MCP zeros
1933
- const hasLocalData = localStats.patternsLearned > 0 || trajectoriesFromDisk > 0 || patternsFileEntries > 0;
1934
- // Use the higher of local vs MCP values for key stats
1935
- const mcpComponents = mcpResult?.components;
1936
- const mcpSona = mcpComponents?.sona;
1937
- const mcpMoe = mcpComponents?.moe;
1938
- const mcpHnsw = mcpComponents?.hnsw;
1939
- const mcpEmb = mcpComponents?.embeddings;
1940
- const mcpPerf = mcpResult?.performance;
1941
- const patternsLearned = Math.max(localStats.patternsLearned, patternsFileEntries, Number(mcpSona?.patternsLearned ?? 0));
1942
- const trajectories = Math.max(localStats.trajectoriesRecorded, trajectoriesFromDisk, Number(mcpSona?.trajectoriesRecorded ?? 0));
1943
- const lastAdaptation = lastAdaptationFromDisk ?? localStats.lastAdaptation;
1944
- const avgAdaptation = localStats.avgAdaptationTime > 0 ? localStats.avgAdaptationTime : Number(mcpSona?.adaptationTimeMs ?? 0);
1945
- const result = {
1946
- mode: String(mcpResult?.mode ?? mode),
1947
- status: (hasLocalData || mcpResult) ? 'active' : 'idle',
1948
- components: {
1949
- sona: {
1950
- enabled: enableSona,
1951
- status: localStats.sonaEnabled ? 'active' : String(mcpSona?.status ?? 'idle'),
1952
- learningTimeMs: avgAdaptation,
1953
- adaptationTimeMs: avgAdaptation,
1954
- trajectoriesRecorded: trajectories,
1955
- patternsLearned,
1956
- avgQuality: Number(mcpSona?.avgQuality ?? (patternsLearned > 0 ? 0.75 : 0)),
1957
- },
1958
- moe: {
1959
- enabled: enableMoe,
1960
- status: String(mcpMoe?.status ?? (hasLocalData ? 'active' : 'idle')),
1961
- expertsActive: Number(mcpMoe?.expertsActive ?? (hasLocalData ? 8 : 0)),
1962
- routingAccuracy: Number(mcpMoe?.routingAccuracy ?? (hasLocalData ? 0.82 : 0)),
1963
- loadBalance: Number(mcpMoe?.loadBalance ?? (hasLocalData ? 0.9 : 0)),
1964
- },
1965
- hnsw: {
1966
- enabled: enableHnsw,
1967
- status: String(mcpHnsw?.status ?? (localStats.reasoningBankSize > 0 ? 'active' : 'idle')),
1968
- indexSize: Math.max(localStats.reasoningBankSize, Number(mcpHnsw?.indexSize ?? 0)),
1969
- searchSpeedup: String(mcpHnsw?.searchSpeedup ?? (localStats.reasoningBankSize > 0 ? '150x' : 'N/A')),
1970
- memoryUsage: String(mcpHnsw?.memoryUsage ?? (patternsFileSize > 0 ? `${(patternsFileSize / 1024).toFixed(1)} KB` : 'N/A')),
1971
- dimension: Number(mcpHnsw?.dimension ?? 384),
1972
- },
1973
- embeddings: mcpEmb ? {
1974
- provider: String(mcpEmb.provider ?? embeddingProvider),
1975
- model: String(mcpEmb.model ?? 'default'),
1976
- dimension: Number(mcpEmb.dimension ?? 384),
1977
- cacheHitRate: Number(mcpEmb.cacheHitRate ?? 0),
1978
- } : {
1979
- provider: embeddingProvider,
1980
- model: 'hash-128',
1981
- dimension: 128,
1982
- cacheHitRate: 0,
1983
- },
1984
- },
1985
- performance: mcpPerf ?? {
1986
- flashAttention: 'N/A',
1987
- memoryReduction: patternsFileSize > 0 ? `${(patternsFileSize / 1024).toFixed(1)} KB on disk` : 'N/A',
1988
- searchImprovement: localStats.reasoningBankSize > 0 ? '150x-12,500x' : 'N/A',
1989
- tokenReduction: 'N/A',
1990
- sweBenchScore: 'N/A',
1991
- },
1992
- lastTrainingMs: lastAdaptation ? Date.now() - lastAdaptation : undefined,
1993
- persistence: {
1994
- dataDir: persistence.dataDir,
1995
- patternsFile: persistence.patternsFile,
1996
- patternsExist: persistence.patternsExist,
1997
- patternsEntries: patternsFileEntries,
1998
- patternsFileSize,
1999
- statsFile: persistence.statsFile,
2000
- statsExist: persistence.statsExist,
2001
- trajectoriesFromDisk,
2002
- },
2003
- };
2004
- if (forceTraining) {
2005
- spinner.setText('Running training cycle...');
2006
- await new Promise(resolve => setTimeout(resolve, 500));
2007
- spinner.succeed('Training cycle completed');
2008
- }
2009
- else {
2010
- spinner.succeed(hasLocalData ? 'Intelligence system active (local data loaded)' : 'Intelligence system active');
2011
- }
2012
- if (ctx.flags.format === 'json') {
2013
- output.printJson(result);
2014
- return { success: true, data: result };
2015
- }
2016
- // Status display
2017
- output.writeln();
2018
- output.printBox([
2019
- `Mode: ${output.highlight(result.mode)}`,
2020
- `Status: ${formatIntelligenceStatus(result.status)}`,
2021
- `Last Training: ${result.lastTrainingMs != null ? `${(result.lastTrainingMs / 1000).toFixed(0)}s ago` : 'Never'}`,
2022
- `Data Dir: ${output.dim(persistence.dataDir)}`
2023
- ].join('\n'), 'Intelligence Status');
2024
- // SONA Component
2025
- output.writeln();
2026
- output.writeln(output.bold('SONA (Sub-0.05ms Learning)'));
2027
- const sona = result.components.sona;
2028
- if (sona.enabled) {
2029
- output.printTable({
2030
- columns: [
2031
- { key: 'metric', header: 'Metric', width: 25 },
2032
- { key: 'value', header: 'Value', width: 20, align: 'right' }
2033
- ],
2034
- data: [
2035
- { metric: 'Status', value: formatIntelligenceStatus(sona.status) },
2036
- { metric: 'Learning Time', value: `${(sona.learningTimeMs ?? 0).toFixed(3)}ms` },
2037
- { metric: 'Adaptation Time', value: `${(sona.adaptationTimeMs ?? 0).toFixed(3)}ms` },
2038
- { metric: 'Trajectories', value: sona.trajectoriesRecorded ?? 0 },
2039
- { metric: 'Patterns Learned', value: sona.patternsLearned ?? 0 },
2040
- { metric: 'Avg Quality', value: `${((sona.avgQuality ?? 0) * 100).toFixed(1)}%` }
2041
- ]
2042
- });
2043
- }
2044
- else {
2045
- output.writeln(output.dim(' Disabled'));
2046
- }
2047
- // MoE Component
2048
- output.writeln();
2049
- output.writeln(output.bold('Mixture of Experts (MoE)'));
2050
- const moe = result.components.moe;
2051
- if (moe.enabled) {
2052
- output.printTable({
2053
- columns: [
2054
- { key: 'metric', header: 'Metric', width: 25 },
2055
- { key: 'value', header: 'Value', width: 20, align: 'right' }
2056
- ],
2057
- data: [
2058
- { metric: 'Status', value: formatIntelligenceStatus(moe.status) },
2059
- { metric: 'Active Experts', value: moe.expertsActive ?? 0 },
2060
- { metric: 'Routing Accuracy', value: `${((moe.routingAccuracy ?? 0) * 100).toFixed(1)}%` },
2061
- { metric: 'Load Balance', value: `${((moe.loadBalance ?? 0) * 100).toFixed(1)}%` }
2062
- ]
2063
- });
2064
- }
2065
- else {
2066
- output.writeln(output.dim(' Disabled'));
2067
- }
2068
- // HNSW Component
2069
- output.writeln();
2070
- output.writeln(output.bold('HNSW (150x Faster Search)'));
2071
- const hnsw = result.components.hnsw;
2072
- if (hnsw.enabled) {
2073
- output.printTable({
2074
- columns: [
2075
- { key: 'metric', header: 'Metric', width: 25 },
2076
- { key: 'value', header: 'Value', width: 20, align: 'right' }
2077
- ],
2078
- data: [
2079
- { metric: 'Status', value: formatIntelligenceStatus(hnsw.status) },
2080
- { metric: 'Index Size', value: (hnsw.indexSize ?? 0).toLocaleString() },
2081
- { metric: 'Search Speedup', value: output.success(hnsw.searchSpeedup ?? 'N/A') },
2082
- { metric: 'Memory Usage', value: hnsw.memoryUsage ?? 'N/A' },
2083
- { metric: 'Dimension', value: hnsw.dimension ?? 384 }
2084
- ]
2085
- });
2086
- }
2087
- else {
2088
- output.writeln(output.dim(' Disabled'));
2089
- }
2090
- // Embeddings
2091
- output.writeln();
2092
- output.writeln(output.bold('Embeddings'));
2093
- const emb = result.components.embeddings;
2094
- if (emb) {
2095
- output.printTable({
2096
- columns: [
2097
- { key: 'metric', header: 'Metric', width: 25 },
2098
- { key: 'value', header: 'Value', width: 20, align: 'right' }
2099
- ],
2100
- data: [
2101
- { metric: 'Provider', value: emb.provider ?? 'N/A' },
2102
- { metric: 'Model', value: emb.model ?? 'N/A' },
2103
- { metric: 'Dimension', value: emb.dimension ?? 384 },
2104
- { metric: 'Cache Hit Rate', value: `${((emb.cacheHitRate ?? 0) * 100).toFixed(1)}%` }
2105
- ]
2106
- });
2107
- }
2108
- else {
2109
- output.writeln(output.dim(' Not initialized'));
2110
- }
2111
- // Persistence info
2112
- if (result.persistence) {
2113
- output.writeln();
2114
- output.writeln(output.bold('Neural Persistence'));
2115
- output.printList([
2116
- `Patterns file: ${persistence.patternsExist ? output.success(`${patternsFileEntries} entries (${(patternsFileSize / 1024).toFixed(1)} KB)`) : output.dim('Not created')}`,
2117
- `Stats file: ${persistence.statsExist ? output.success(`${trajectoriesFromDisk} trajectories`) : output.dim('Not created')}`,
2118
- ]);
2119
- if (!persistence.patternsExist && !persistence.statsExist) {
2120
- output.writeln();
2121
- output.writeln(output.dim(' No neural data. Run: neural train'));
2122
- }
2123
- }
2124
- // V3 Performance
2125
- const perf = result.performance;
2126
- if (perf) {
2127
- output.writeln();
2128
- output.writeln(output.bold('V3 Performance Gains'));
2129
- output.printList([
2130
- `Flash Attention: ${output.success(String(perf.flashAttention ?? 'N/A'))}`,
2131
- `Memory Reduction: ${output.success(String(perf.memoryReduction ?? 'N/A'))}`,
2132
- `Search Improvement: ${output.success(String(perf.searchImprovement ?? 'N/A'))}`,
2133
- `Token Reduction: ${output.success(String(perf.tokenReduction ?? 'N/A'))}`,
2134
- `SWE-Bench Score: ${output.success(String(perf.sweBenchScore ?? 'N/A'))}`
2135
- ]);
2136
- }
2137
- return { success: true, data: result };
2138
- }
2139
- catch (error) {
2140
- spinner.fail('Intelligence system error');
2141
- if (error instanceof MCPClientError) {
2142
- output.printError(`Intelligence error: ${error.message}`);
2143
- }
2144
- else {
2145
- output.printError(`Unexpected error: ${String(error)}`);
2146
- }
2147
- return { success: false, exitCode: 1 };
2148
- }
2149
- }
2150
- };
2151
- function formatIntelligenceStatus(status) {
2152
- switch (status) {
2153
- case 'active':
2154
- case 'ready':
2155
- return output.success(status);
2156
- case 'training':
2157
- return output.highlight(status);
2158
- case 'idle':
2159
- return output.dim(status);
2160
- case 'disabled':
2161
- case 'error':
2162
- return output.error(status);
2163
- default:
2164
- return status;
2165
- }
2166
- }
2167
- // =============================================================================
2168
- // Worker Commands (12 Background Workers)
2169
- // =============================================================================
2170
- const workerListCommand = {
2171
- name: 'list',
2172
- description: 'List all 12 background workers with capabilities',
2173
- options: [
2174
- { name: 'status', short: 's', type: 'string', description: 'Filter by status (all, running, completed, pending)' },
2175
- { name: 'active', short: 'a', type: 'boolean', description: 'Show active worker instances' },
2176
- ],
2177
- examples: [
2178
- { command: 'claude-flow hooks worker list', description: 'List all workers' },
2179
- { command: 'claude-flow hooks worker list --active', description: 'Show active instances' },
2180
- ],
2181
- action: async (ctx) => {
2182
- const spinner = output.createSpinner({ text: 'Loading workers...', spinner: 'dots' });
2183
- spinner.start();
2184
- try {
2185
- const result = await callMCPTool('hooks_worker-list', {
2186
- status: ctx.flags['status'] || 'all',
2187
- includeActive: ctx.flags['active'] !== false,
2188
- });
2189
- spinner.succeed('Workers loaded');
2190
- output.writeln();
2191
- output.writeln(output.bold('Background Workers (12 Total)'));
2192
- output.writeln();
2193
- output.printTable({
2194
- columns: [
2195
- { key: 'trigger', header: 'Worker', width: 14 },
2196
- { key: 'priority', header: 'Priority', width: 10 },
2197
- { key: 'estimatedDuration', header: 'Est. Time', width: 10 },
2198
- { key: 'description', header: 'Description', width: 40 },
2199
- ],
2200
- data: result.workers.map(w => ({
2201
- trigger: output.highlight(w.trigger),
2202
- priority: w.priority === 'critical' ? output.error(w.priority) :
2203
- w.priority === 'high' ? output.warning(w.priority) :
2204
- w.priority,
2205
- estimatedDuration: w.estimatedDuration,
2206
- description: w.description,
2207
- })),
2208
- });
2209
- if (ctx.flags['active'] && result.active.count > 0) {
2210
- output.writeln();
2211
- output.writeln(output.bold('Active Instances'));
2212
- output.printTable({
2213
- columns: [
2214
- { key: 'id', header: 'Worker ID', width: 35 },
2215
- { key: 'trigger', header: 'Type', width: 12 },
2216
- { key: 'status', header: 'Status', width: 12 },
2217
- { key: 'progress', header: 'Progress', width: 10 },
2218
- ],
2219
- data: result.active.instances.map(w => ({
2220
- id: w.id,
2221
- trigger: w.trigger,
2222
- status: w.status === 'running' ? output.highlight(w.status) :
2223
- w.status === 'completed' ? output.success(w.status) :
2224
- w.status === 'failed' ? output.error(w.status) : w.status,
2225
- progress: `${w.progress}%`,
2226
- })),
2227
- });
2228
- }
2229
- output.writeln();
2230
- output.writeln(output.dim('Performance targets:'));
2231
- output.writeln(output.dim(` Trigger detection: ${result.performanceTargets.triggerDetection}`));
2232
- output.writeln(output.dim(` Worker spawn: ${result.performanceTargets.workerSpawn}`));
2233
- output.writeln(output.dim(` Max concurrent: ${result.performanceTargets.maxConcurrent}`));
2234
- return { success: true, data: result };
2235
- }
2236
- catch (error) {
2237
- spinner.fail('Failed to load workers');
2238
- if (error instanceof MCPClientError) {
2239
- output.printError(`Worker error: ${error.message}`);
2240
- }
2241
- return { success: false, exitCode: 1 };
2242
- }
2243
- }
2244
- };
2245
- const workerDispatchCommand = {
2246
- name: 'dispatch',
2247
- description: 'Dispatch a background worker for analysis/optimization',
2248
- options: [
2249
- { name: 'trigger', short: 't', type: 'string', description: 'Worker type (ultralearn, optimize, audit, map, etc.)', required: true },
2250
- { name: 'context', short: 'c', type: 'string', description: 'Context for the worker (file path, topic)' },
2251
- { name: 'priority', short: 'p', type: 'string', description: 'Priority (low, normal, high, critical)' },
2252
- { name: 'sync', short: 's', type: 'boolean', description: 'Wait for completion (synchronous)' },
2253
- ],
2254
- examples: [
2255
- { command: 'claude-flow hooks worker dispatch -t optimize -c src/', description: 'Dispatch optimize worker' },
2256
- { command: 'claude-flow hooks worker dispatch -t audit -p critical', description: 'Security audit with critical priority' },
2257
- { command: 'claude-flow hooks worker dispatch -t testgaps --sync', description: 'Test coverage analysis (sync)' },
2258
- ],
2259
- action: async (ctx) => {
2260
- const trigger = ctx.flags['trigger'];
2261
- const context = ctx.flags['context'] || 'default';
2262
- const priority = ctx.flags['priority'];
2263
- const background = !ctx.flags['sync'];
2264
- if (!trigger) {
2265
- output.printError('--trigger is required');
2266
- output.writeln('Available triggers: ultralearn, optimize, consolidate, predict, audit, map, preload, deepdive, document, refactor, benchmark, testgaps, oia-audit');
2267
- output.writeln(output.dim('Tip: `oia-audit` (ADR-150) also runs as `ruflo metaharness oia-audit` for direct invocation.'));
2268
- return { success: false, exitCode: 1 };
2269
- }
2270
- const spinner = output.createSpinner({ text: `Dispatching ${trigger} worker...`, spinner: 'dots' });
2271
- spinner.start();
2272
- try {
2273
- const result = await callMCPTool('hooks_worker-dispatch', {
2274
- trigger,
2275
- context,
2276
- priority,
2277
- background,
2278
- });
2279
- if (!result.success) {
2280
- spinner.fail(`Failed: ${result.error}`);
2281
- return { success: false, exitCode: 1 };
2282
- }
2283
- spinner.succeed(`Worker dispatched: ${result.workerId}`);
2284
- output.writeln();
2285
- output.printTable({
2286
- columns: [
2287
- { key: 'field', header: 'Field', width: 18 },
2288
- { key: 'value', header: 'Value', width: 50 },
2289
- ],
2290
- data: [
2291
- { field: 'Worker ID', value: output.highlight(result.workerId) },
2292
- { field: 'Trigger', value: result.trigger },
2293
- { field: 'Context', value: result.context },
2294
- { field: 'Priority', value: result.priority },
2295
- { field: 'Description', value: result.config.description },
2296
- { field: 'Est. Duration', value: result.config.estimatedDuration },
2297
- { field: 'Capabilities', value: result.config.capabilities.join(', ') },
2298
- { field: 'Status', value: result.status === 'dispatched' ? output.highlight('dispatched (background)') : output.success('completed') },
2299
- ],
2300
- });
2301
- if (background) {
2302
- output.writeln();
2303
- output.writeln(output.dim(`Check status: claude-flow hooks worker status --id ${result.workerId}`));
2304
- }
2305
- return { success: true, data: result };
2306
- }
2307
- catch (error) {
2308
- spinner.fail('Worker dispatch failed');
2309
- if (error instanceof MCPClientError) {
2310
- output.printError(`Dispatch error: ${error.message}`);
2311
- }
2312
- return { success: false, exitCode: 1 };
2313
- }
2314
- }
2315
- };
2316
- const workerStatusCommand = {
2317
- name: 'status',
2318
- description: 'Get status of workers',
2319
- options: [
2320
- { name: 'id', type: 'string', description: 'Specific worker ID to check' },
2321
- { name: 'all', short: 'a', type: 'boolean', description: 'Include completed workers' },
2322
- ],
2323
- examples: [
2324
- { command: 'claude-flow hooks worker status', description: 'Show running workers' },
2325
- { command: 'claude-flow hooks worker status --id worker_audit_1', description: 'Check specific worker' },
2326
- { command: 'claude-flow hooks worker status --all', description: 'Include completed workers' },
2327
- ],
2328
- action: async (ctx) => {
2329
- const workerId = ctx.flags['id'];
2330
- const includeCompleted = ctx.flags['all'];
2331
- const spinner = output.createSpinner({ text: 'Checking worker status...', spinner: 'dots' });
2332
- spinner.start();
2333
- try {
2334
- const result = await callMCPTool('hooks_worker-status', {
2335
- workerId,
2336
- includeCompleted,
2337
- });
2338
- if (!result.success) {
2339
- spinner.fail(`Failed: ${result.error}`);
2340
- return { success: false, exitCode: 1 };
2341
- }
2342
- spinner.succeed('Status retrieved');
2343
- if (result.worker) {
2344
- output.writeln();
2345
- output.writeln(output.bold(`Worker: ${result.worker.id}`));
2346
- output.printTable({
2347
- columns: [
2348
- { key: 'field', header: 'Field', width: 15 },
2349
- { key: 'value', header: 'Value', width: 40 },
2350
- ],
2351
- data: [
2352
- { field: 'Trigger', value: result.worker.trigger },
2353
- { field: 'Context', value: result.worker.context },
2354
- { field: 'Status', value: formatWorkerStatus(result.worker.status) },
2355
- { field: 'Progress', value: `${result.worker.progress}%` },
2356
- { field: 'Phase', value: result.worker.phase },
2357
- { field: 'Duration', value: `${result.worker.duration}ms` },
2358
- ],
2359
- });
2360
- }
2361
- else if (result.workers && result.workers.length > 0) {
2362
- output.writeln();
2363
- output.writeln(output.bold('Active Workers'));
2364
- output.printTable({
2365
- columns: [
2366
- { key: 'id', header: 'Worker ID', width: 35 },
2367
- { key: 'trigger', header: 'Type', width: 12 },
2368
- { key: 'status', header: 'Status', width: 12 },
2369
- { key: 'progress', header: 'Progress', width: 10 },
2370
- { key: 'duration', header: 'Duration', width: 12 },
2371
- ],
2372
- data: result.workers.map(w => ({
2373
- id: w.id,
2374
- trigger: w.trigger,
2375
- status: formatWorkerStatus(w.status),
2376
- progress: `${w.progress}%`,
2377
- duration: `${w.duration}ms`,
2378
- })),
2379
- });
2380
- if (result.summary) {
2381
- output.writeln();
2382
- output.writeln(`Total: ${result.summary.total} | Running: ${output.highlight(String(result.summary.running))} | Completed: ${output.success(String(result.summary.completed))} | Failed: ${output.error(String(result.summary.failed))}`);
2383
- }
2384
- }
2385
- else {
2386
- output.writeln();
2387
- output.writeln(output.dim('No active workers'));
2388
- }
2389
- return { success: true, data: result };
2390
- }
2391
- catch (error) {
2392
- spinner.fail('Status check failed');
2393
- if (error instanceof MCPClientError) {
2394
- output.printError(`Status error: ${error.message}`);
2395
- }
2396
- return { success: false, exitCode: 1 };
2397
- }
2398
- }
2399
- };
2400
- const workerDetectCommand = {
2401
- name: 'detect',
2402
- description: 'Detect worker triggers from prompt text',
2403
- options: [
2404
- { name: 'prompt', short: 'p', type: 'string', description: 'Prompt text to analyze', required: true },
2405
- { name: 'auto-dispatch', short: 'a', type: 'boolean', description: 'Automatically dispatch detected workers' },
2406
- { name: 'min-confidence', short: 'm', type: 'string', description: 'Minimum confidence threshold (0-1)' },
2407
- ],
2408
- examples: [
2409
- { command: 'claude-flow hooks worker detect -p "optimize performance"', description: 'Detect triggers in prompt' },
2410
- { command: 'claude-flow hooks worker detect -p "security audit" --auto-dispatch', description: 'Detect and dispatch' },
2411
- ],
2412
- action: async (ctx) => {
2413
- const prompt = ctx.flags['prompt'];
2414
- const autoDispatch = ctx.flags['auto-dispatch'];
2415
- const minConfidence = parseFloat(ctx.flags['min-confidence'] || '0.5');
2416
- if (!prompt) {
2417
- output.printError('--prompt is required');
2418
- return { success: false, exitCode: 1 };
2419
- }
2420
- const spinner = output.createSpinner({ text: 'Analyzing prompt...', spinner: 'dots' });
2421
- spinner.start();
2422
- try {
2423
- const result = await callMCPTool('hooks_worker-detect', {
2424
- prompt,
2425
- autoDispatch,
2426
- minConfidence,
2427
- });
2428
- if (result.detection.detected) {
2429
- spinner.succeed(`Detected ${result.triggersFound} worker trigger(s)`);
2430
- }
2431
- else {
2432
- spinner.succeed('No worker triggers detected');
2433
- }
2434
- output.writeln();
2435
- output.writeln(output.bold('Detection Results'));
2436
- output.writeln(`Prompt: ${output.dim(result.prompt)}`);
2437
- output.writeln(`Confidence: ${(result.detection.confidence * 100).toFixed(0)}%`);
2438
- if (result.triggerDetails && result.triggerDetails.length > 0) {
2439
- output.writeln();
2440
- output.printTable({
2441
- columns: [
2442
- { key: 'trigger', header: 'Trigger', width: 14 },
2443
- { key: 'priority', header: 'Priority', width: 10 },
2444
- { key: 'description', header: 'Description', width: 45 },
2445
- ],
2446
- data: result.triggerDetails.map(t => ({
2447
- trigger: output.highlight(t.trigger),
2448
- priority: t.priority,
2449
- description: t.description,
2450
- })),
2451
- });
2452
- }
2453
- if (result.autoDispatched && result.workerIds) {
2454
- output.writeln();
2455
- output.writeln(output.success('Workers auto-dispatched:'));
2456
- result.workerIds.forEach(id => {
2457
- output.writeln(` - ${id}`);
2458
- });
2459
- }
2460
- return { success: true, data: result };
2461
- }
2462
- catch (error) {
2463
- spinner.fail('Detection failed');
2464
- if (error instanceof MCPClientError) {
2465
- output.printError(`Detection error: ${error.message}`);
2466
- }
2467
- return { success: false, exitCode: 1 };
2468
- }
2469
- }
2470
- };
2471
- const workerCancelCommand = {
2472
- name: 'cancel',
2473
- description: 'Cancel a running worker',
2474
- options: [
2475
- { name: 'id', type: 'string', description: 'Worker ID to cancel', required: true },
2476
- ],
2477
- examples: [
2478
- { command: 'claude-flow hooks worker cancel --id worker_audit_1', description: 'Cancel specific worker' },
2479
- ],
2480
- action: async (ctx) => {
2481
- const workerId = ctx.flags['id'];
2482
- if (!workerId) {
2483
- output.printError('--id is required');
2484
- return { success: false, exitCode: 1 };
2485
- }
2486
- const spinner = output.createSpinner({ text: `Cancelling worker ${workerId}...`, spinner: 'dots' });
2487
- spinner.start();
2488
- try {
2489
- const result = await callMCPTool('hooks_worker-cancel', { workerId });
2490
- if (!result.success) {
2491
- spinner.fail(`Failed: ${result.error}`);
2492
- return { success: false, exitCode: 1 };
2493
- }
2494
- spinner.succeed(`Worker ${workerId} cancelled`);
2495
- return { success: true, data: result };
2496
- }
2497
- catch (error) {
2498
- spinner.fail('Cancel failed');
2499
- if (error instanceof MCPClientError) {
2500
- output.printError(`Cancel error: ${error.message}`);
2501
- }
2502
- return { success: false, exitCode: 1 };
2503
- }
2504
- }
2505
- };
2506
- function formatWorkerStatus(status) {
2507
- switch (status) {
2508
- case 'running':
2509
- return output.highlight(status);
2510
- case 'completed':
2511
- return output.success(status);
2512
- case 'failed':
2513
- return output.error(status);
2514
- case 'pending':
2515
- return output.dim(status);
2516
- default:
2517
- return status;
2518
- }
2519
- }
2520
- // ============================================================================
2521
- // Coverage-Aware Routing Commands
2522
- // ============================================================================
2523
- // Coverage route subcommand
2524
- const coverageRouteCommand = {
2525
- name: 'coverage-route',
2526
- description: 'Route task to agents based on test coverage gaps (ruvector integration)',
2527
- options: [
2528
- {
2529
- name: 'task',
2530
- short: 't',
2531
- description: 'Task description to route',
2532
- type: 'string',
2533
- required: true
2534
- },
2535
- {
2536
- name: 'threshold',
2537
- description: 'Coverage threshold percentage (default: 80)',
2538
- type: 'number',
2539
- default: 80
2540
- },
2541
- {
2542
- name: 'no-ruvector',
2543
- description: 'Disable ruvector integration',
2544
- type: 'boolean',
2545
- default: false
2546
- }
2547
- ],
2548
- examples: [
2549
- { command: 'claude-flow hooks coverage-route -t "fix bug in auth"', description: 'Route with coverage awareness' },
2550
- { command: 'claude-flow hooks coverage-route -t "add tests" --threshold 90', description: 'Route with custom threshold' }
2551
- ],
2552
- action: async (ctx) => {
2553
- const task = ctx.flags.task || ctx.args[0];
2554
- const threshold = ctx.flags.threshold || 80;
2555
- const useRuvector = !ctx.flags['no-ruvector'];
2556
- if (!task) {
2557
- output.printError('Task description is required. Use --task or -t flag.');
2558
- return { success: false, exitCode: 1 };
2559
- }
2560
- const spinner = output.createSpinner({ text: 'Analyzing coverage and routing task...' });
2561
- spinner.start();
2562
- // Try reading coverage from disk first
2563
- const diskCoverage = readCoverageFromDisk();
2564
- if (diskCoverage.found) {
2565
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
2566
- // Find files with lowest coverage that may relate to the task
2567
- const taskLower = task.toLowerCase();
2568
- const taskWords = taskLower.split(/\s+/).filter(w => w.length > 2);
2569
- // Score each file by relevance to the task and how low its coverage is
2570
- const scoredFiles = diskCoverage.entries
2571
- .filter(e => e.lines < threshold)
2572
- .map(e => {
2573
- const fileNameLower = e.filePath.toLowerCase();
2574
- let relevance = 0;
2575
- for (const word of taskWords) {
2576
- if (fileNameLower.includes(word))
2577
- relevance += 2;
2578
- }
2579
- // Penalize high coverage (we care about low coverage)
2580
- const coveragePenalty = e.lines / 100;
2581
- return { ...e, relevance, score: relevance + (1 - coveragePenalty) };
2582
- })
2583
- .sort((a, b) => b.score - a.score);
2584
- const gaps = scoredFiles.slice(0, 8).map(e => {
2585
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
2586
- return {
2587
- filePath: e.filePath,
2588
- coveragePercent: e.lines,
2589
- gapType,
2590
- priority,
2591
- suggestedAgents: suggestAgentsForFile(e.filePath),
2592
- reason: `${e.lines.toFixed(1)}% coverage, below ${threshold}%`,
2593
- };
2594
- });
2595
- const criticalGaps = gaps.filter(g => g.gapType === 'critical').length;
2596
- const primaryAgent = taskLower.includes('test') ? 'tester' :
2597
- taskLower.includes('security') || taskLower.includes('auth') ? 'security-auditor' :
2598
- taskLower.includes('fix') || taskLower.includes('bug') ? 'coder' : 'tester';
2599
- const suggestions = [];
2600
- if (criticalGaps > 0)
2601
- suggestions.push(`${criticalGaps} critical coverage gaps need immediate attention`);
2602
- if (diskCoverage.summary.overallLineCoverage < threshold) {
2603
- suggestions.push(`Overall line coverage (${diskCoverage.summary.overallLineCoverage.toFixed(1)}%) is below ${threshold}% threshold`);
2604
- }
2605
- if (scoredFiles.length > 8)
2606
- suggestions.push(`${scoredFiles.length - 8} additional files with low coverage`);
2607
- const result = {
2608
- success: true,
2609
- task,
2610
- coverageAware: true,
2611
- gaps,
2612
- routing: {
2613
- primaryAgent,
2614
- confidence: gaps.length > 0 ? 0.85 : 0.6,
2615
- reason: gaps.length > 0
2616
- ? `Routing to ${primaryAgent} based on ${gaps.length} coverage gaps related to task`
2617
- : `No coverage gaps found related to task, routing to ${primaryAgent}`,
2618
- coverageImpact: gaps.length > 0 ? 'high' : 'low',
2619
- },
2620
- suggestions,
2621
- metrics: {
2622
- filesAnalyzed: diskCoverage.summary.totalFiles,
2623
- totalGaps: scoredFiles.length,
2624
- criticalGaps,
2625
- avgCoverage: diskCoverage.summary.overallLineCoverage,
2626
- },
2627
- source: diskCoverage.source,
2628
- };
2629
- if (ctx.flags.format === 'json') {
2630
- output.printJson(result);
2631
- return { success: true, data: result };
2632
- }
2633
- output.writeln();
2634
- output.printBox([
2635
- `Agent: ${output.highlight(result.routing.primaryAgent)}`,
2636
- `Confidence: ${(result.routing.confidence * 100).toFixed(1)}%`,
2637
- `Coverage-Aware: ${output.success('Yes')} (from ${diskCoverage.source})`,
2638
- `Reason: ${result.routing.reason}`
2639
- ].join('\n'), 'Coverage-Aware Routing');
2640
- if (gaps.length > 0) {
2641
- output.writeln();
2642
- output.writeln(output.bold('Priority Coverage Gaps'));
2643
- output.printTable({
2644
- columns: [
2645
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
2646
- const s = String(v);
2647
- return s.length > 32 ? '...' + s.slice(-32) : s;
2648
- } },
2649
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
2650
- { key: 'gapType', header: 'Type', width: 10 },
2651
- { key: 'suggestedAgents', header: 'Agent', width: 15, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
2652
- ],
2653
- data: gaps.slice(0, 8)
2654
- });
2655
- }
2656
- if (result.metrics.filesAnalyzed > 0) {
2657
- output.writeln();
2658
- output.writeln(output.bold('Coverage Metrics'));
2659
- output.printList([
2660
- `Files Analyzed: ${result.metrics.filesAnalyzed}`,
2661
- `Total Gaps: ${result.metrics.totalGaps}`,
2662
- `Critical Gaps: ${result.metrics.criticalGaps}`,
2663
- `Average Coverage: ${result.metrics.avgCoverage.toFixed(1)}%`
2664
- ]);
2665
- }
2666
- if (suggestions.length > 0) {
2667
- output.writeln();
2668
- output.writeln(output.bold('Suggestions'));
2669
- output.printList(suggestions.map(s => output.dim(s)));
2670
- }
2671
- return { success: true, data: result };
2672
- }
2673
- // No disk coverage - fall back to MCP tool
2674
- try {
2675
- const result = await callMCPTool('hooks_coverage-route', {
2676
- task,
2677
- threshold,
2678
- useRuvector,
2679
- });
2680
- spinner.stop();
2681
- if (ctx.flags.format === 'json') {
2682
- output.printJson(result);
2683
- return { success: true, data: result };
2684
- }
2685
- output.writeln();
2686
- output.printBox([
2687
- `Agent: ${output.highlight(result.routing.primaryAgent)}`,
2688
- `Confidence: ${(result.routing.confidence * 100).toFixed(1)}%`,
2689
- `Coverage-Aware: ${result.coverageAware ? output.success('Yes') : output.dim('No coverage data')}`,
2690
- `Reason: ${result.routing.reason}`
2691
- ].join('\n'), 'Coverage-Aware Routing');
2692
- if (result.gaps.length > 0) {
2693
- output.writeln();
2694
- output.writeln(output.bold('Priority Coverage Gaps'));
2695
- output.printTable({
2696
- columns: [
2697
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
2698
- const s = String(v);
2699
- return s.length > 32 ? '...' + s.slice(-32) : s;
2700
- } },
2701
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
2702
- { key: 'gapType', header: 'Type', width: 10 },
2703
- { key: 'suggestedAgents', header: 'Agent', width: 15, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
2704
- ],
2705
- data: result.gaps.slice(0, 8)
2706
- });
2707
- }
2708
- if (result.metrics.filesAnalyzed > 0) {
2709
- output.writeln();
2710
- output.writeln(output.bold('Coverage Metrics'));
2711
- output.printList([
2712
- `Files Analyzed: ${result.metrics.filesAnalyzed}`,
2713
- `Total Gaps: ${result.metrics.totalGaps}`,
2714
- `Critical Gaps: ${result.metrics.criticalGaps}`,
2715
- `Average Coverage: ${result.metrics.avgCoverage.toFixed(1)}%`
2716
- ]);
2717
- }
2718
- if (result.suggestions.length > 0) {
2719
- output.writeln();
2720
- output.writeln(output.bold('Suggestions'));
2721
- output.printList(result.suggestions.map(s => output.dim(s)));
2722
- }
2723
- return { success: true, data: result };
2724
- }
2725
- catch (error) {
2726
- spinner.fail('No coverage data found');
2727
- output.writeln();
2728
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
2729
- output.writeln();
2730
- output.printList([
2731
- 'Jest: npx jest --coverage',
2732
- 'Vitest: npx vitest --coverage',
2733
- 'nyc: npx nyc npm test',
2734
- 'c8: npx c8 npm test',
2735
- ]);
2736
- output.writeln();
2737
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
2738
- return { success: false, exitCode: 1 };
2739
- }
2740
- }
2741
- };
2742
- // Coverage suggest subcommand
2743
- const coverageSuggestCommand = {
2744
- name: 'coverage-suggest',
2745
- description: 'Suggest coverage improvements for a path (ruvector integration)',
2746
- options: [
2747
- {
2748
- name: 'path',
2749
- short: 'p',
2750
- description: 'Path to analyze for coverage suggestions',
2751
- type: 'string',
2752
- required: true
2753
- },
2754
- {
2755
- name: 'threshold',
2756
- description: 'Coverage threshold percentage (default: 80)',
2757
- type: 'number',
2758
- default: 80
2759
- },
2760
- {
2761
- name: 'limit',
2762
- short: 'l',
2763
- description: 'Maximum number of suggestions (default: 20)',
2764
- type: 'number',
2765
- default: 20
2766
- }
2767
- ],
2768
- examples: [
2769
- { command: 'claude-flow hooks coverage-suggest -p src/', description: 'Suggest improvements for src/' },
2770
- { command: 'claude-flow hooks coverage-suggest -p src/services --threshold 90', description: 'Stricter threshold' }
2771
- ],
2772
- action: async (ctx) => {
2773
- const targetPath = ctx.flags.path || ctx.args[0];
2774
- const threshold = ctx.flags.threshold || 80;
2775
- const limit = ctx.flags.limit || 20;
2776
- if (!targetPath) {
2777
- output.printError('Path is required. Use --path or -p flag.');
2778
- return { success: false, exitCode: 1 };
2779
- }
2780
- const spinner = output.createSpinner({ text: `Analyzing coverage for ${targetPath}...` });
2781
- spinner.start();
2782
- // Try reading coverage from disk first
2783
- const diskCoverage = readCoverageFromDisk();
2784
- if (diskCoverage.found) {
2785
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
2786
- // Filter entries to those matching the target path
2787
- const pathLower = targetPath.toLowerCase().replace(/\\/g, '/');
2788
- const matchingEntries = diskCoverage.entries.filter(e => {
2789
- const fileLower = e.filePath.toLowerCase().replace(/\\/g, '/');
2790
- return fileLower.includes(pathLower);
2791
- });
2792
- const belowThreshold = matchingEntries.filter(e => e.lines < threshold);
2793
- const suggestions = belowThreshold.slice(0, limit).map(e => {
2794
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
2795
- return {
2796
- filePath: e.filePath,
2797
- coveragePercent: e.lines,
2798
- gapType,
2799
- priority,
2800
- suggestedAgents: suggestAgentsForFile(e.filePath),
2801
- reason: e.lines === 0 ? 'No coverage at all' :
2802
- e.lines < 20 ? 'Very low coverage, needs tests' :
2803
- e.lines < 50 ? 'Below 50%, add more tests' :
2804
- `Below ${threshold}% threshold`,
2805
- };
2806
- });
2807
- const totalLinesCov = matchingEntries.length > 0
2808
- ? matchingEntries.reduce((acc, e) => acc + e.lines, 0) / matchingEntries.length
2809
- : 0;
2810
- const totalBranchesCov = matchingEntries.length > 0
2811
- ? matchingEntries.reduce((acc, e) => acc + e.branches, 0) / matchingEntries.length
2812
- : 0;
2813
- const prioritizedFiles = belowThreshold.slice(0, 5).map(e => e.filePath);
2814
- const result = {
2815
- success: true,
2816
- path: targetPath,
2817
- suggestions,
2818
- summary: {
2819
- totalFiles: matchingEntries.length,
2820
- overallLineCoverage: totalLinesCov,
2821
- overallBranchCoverage: totalBranchesCov,
2822
- filesBelowThreshold: belowThreshold.length,
2823
- },
2824
- prioritizedFiles,
2825
- ruvectorAvailable: false,
2826
- source: diskCoverage.source,
2827
- };
2828
- if (ctx.flags.format === 'json') {
2829
- output.printJson(result);
2830
- return { success: true, data: result };
2831
- }
2832
- output.writeln();
2833
- output.printBox([
2834
- `Path: ${output.highlight(targetPath)}`,
2835
- `Files Analyzed: ${result.summary.totalFiles}`,
2836
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
2837
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
2838
- `Below Threshold: ${result.summary.filesBelowThreshold} files`,
2839
- `Source: ${output.highlight(diskCoverage.source)}`
2840
- ].join('\n'), 'Coverage Summary');
2841
- if (suggestions.length > 0) {
2842
- output.writeln();
2843
- output.writeln(output.bold('Coverage Improvement Suggestions'));
2844
- output.printTable({
2845
- columns: [
2846
- { key: 'filePath', header: 'File', width: 40, format: (v) => {
2847
- const s = String(v);
2848
- return s.length > 37 ? '...' + s.slice(-37) : s;
2849
- } },
2850
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
2851
- { key: 'gapType', header: 'Priority', width: 10 },
2852
- { key: 'reason', header: 'Reason', width: 25 }
2853
- ],
2854
- data: suggestions.slice(0, 15)
2855
- });
2856
- }
2857
- else {
2858
- output.writeln();
2859
- output.printSuccess('All files meet coverage threshold!');
2860
- }
2861
- if (prioritizedFiles.length > 0) {
2862
- output.writeln();
2863
- output.writeln(output.bold('Priority Files (Top 5)'));
2864
- output.printList(prioritizedFiles.slice(0, 5).map(f => output.highlight(f)));
2865
- }
2866
- return { success: true, data: result };
2867
- }
2868
- // No disk coverage - fall back to MCP tool
2869
- try {
2870
- const result = await callMCPTool('hooks_coverage-suggest', {
2871
- path: targetPath,
2872
- threshold,
2873
- limit,
2874
- });
2875
- spinner.stop();
2876
- if (ctx.flags.format === 'json') {
2877
- output.printJson(result);
2878
- return { success: true, data: result };
2879
- }
2880
- output.writeln();
2881
- output.printBox([
2882
- `Path: ${output.highlight(result.path)}`,
2883
- `Files Analyzed: ${result.summary.totalFiles}`,
2884
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
2885
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
2886
- `Below Threshold: ${result.summary.filesBelowThreshold} files`,
2887
- `RuVector: ${result.ruvectorAvailable ? output.success('Available') : output.dim('Not installed')}`
2888
- ].join('\n'), 'Coverage Summary');
2889
- if (result.suggestions.length > 0) {
2890
- output.writeln();
2891
- output.writeln(output.bold('Coverage Improvement Suggestions'));
2892
- output.printTable({
2893
- columns: [
2894
- { key: 'filePath', header: 'File', width: 40, format: (v) => {
2895
- const s = String(v);
2896
- return s.length > 37 ? '...' + s.slice(-37) : s;
2897
- } },
2898
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
2899
- { key: 'gapType', header: 'Priority', width: 10 },
2900
- { key: 'reason', header: 'Reason', width: 25 }
2901
- ],
2902
- data: result.suggestions.slice(0, 15)
2903
- });
2904
- }
2905
- else {
2906
- output.writeln();
2907
- output.printSuccess('All files meet coverage threshold!');
2908
- }
2909
- if (result.prioritizedFiles.length > 0) {
2910
- output.writeln();
2911
- output.writeln(output.bold('Priority Files (Top 5)'));
2912
- output.printList(result.prioritizedFiles.slice(0, 5).map(f => output.highlight(f)));
2913
- }
2914
- return { success: true, data: result };
2915
- }
2916
- catch (error) {
2917
- spinner.fail('No coverage data found');
2918
- output.writeln();
2919
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
2920
- output.writeln();
2921
- output.printList([
2922
- 'Jest: npx jest --coverage',
2923
- 'Vitest: npx vitest --coverage',
2924
- 'nyc: npx nyc npm test',
2925
- 'c8: npx c8 npm test',
2926
- ]);
2927
- output.writeln();
2928
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
2929
- return { success: false, exitCode: 1 };
2930
- }
2931
- }
2932
- };
2933
- // Coverage gaps subcommand
2934
- const coverageGapsCommand = {
2935
- name: 'coverage-gaps',
2936
- description: 'List all coverage gaps with priority scoring and agent assignments',
2937
- options: [
2938
- {
2939
- name: 'threshold',
2940
- description: 'Coverage threshold percentage (default: 80)',
2941
- type: 'number',
2942
- default: 80
2943
- },
2944
- {
2945
- name: 'group-by-agent',
2946
- description: 'Group gaps by suggested agent (default: true)',
2947
- type: 'boolean',
2948
- default: true
2949
- },
2950
- {
2951
- name: 'critical-only',
2952
- description: 'Show only critical gaps',
2953
- type: 'boolean',
2954
- default: false
2955
- }
2956
- ],
2957
- examples: [
2958
- { command: 'claude-flow hooks coverage-gaps', description: 'List all coverage gaps' },
2959
- { command: 'claude-flow hooks coverage-gaps --critical-only', description: 'Only critical gaps' },
2960
- { command: 'claude-flow hooks coverage-gaps --threshold 90', description: 'Stricter threshold' }
2961
- ],
2962
- action: async (ctx) => {
2963
- const threshold = ctx.flags.threshold || 80;
2964
- const groupByAgent = ctx.flags['group-by-agent'] !== false;
2965
- const criticalOnly = ctx.flags['critical-only'] || false;
2966
- const spinner = output.createSpinner({ text: 'Analyzing project coverage gaps...' });
2967
- spinner.start();
2968
- // Try reading coverage from disk first
2969
- const diskCoverage = readCoverageFromDisk();
2970
- if (diskCoverage.found) {
2971
- spinner.succeed(`Coverage data loaded from ${diskCoverage.source}`);
2972
- // Build gaps from disk data
2973
- const allGaps = diskCoverage.entries
2974
- .filter(e => e.lines < threshold)
2975
- .map(e => {
2976
- const { gapType, priority } = classifyCoverageGap(e.lines, threshold);
2977
- return {
2978
- filePath: e.filePath,
2979
- coveragePercent: e.lines,
2980
- gapType,
2981
- complexity: Math.round((100 - e.lines) / 10),
2982
- priority,
2983
- suggestedAgents: suggestAgentsForFile(e.filePath),
2984
- reason: `Line coverage ${e.lines.toFixed(1)}% below ${threshold}% threshold`,
2985
- };
2986
- });
2987
- const gaps = criticalOnly
2988
- ? allGaps.filter(g => g.gapType === 'critical')
2989
- : allGaps;
2990
- // Build agent assignments
2991
- const agentAssignments = {};
2992
- if (groupByAgent) {
2993
- for (const gap of gaps) {
2994
- const agent = gap.suggestedAgents[0] || 'tester';
2995
- if (!agentAssignments[agent])
2996
- agentAssignments[agent] = [];
2997
- agentAssignments[agent].push(gap.filePath);
2998
- }
2999
- }
3000
- const result = {
3001
- success: true,
3002
- gaps,
3003
- summary: {
3004
- totalFiles: diskCoverage.summary.totalFiles,
3005
- overallLineCoverage: diskCoverage.summary.overallLineCoverage,
3006
- overallBranchCoverage: diskCoverage.summary.overallBranchCoverage,
3007
- filesBelowThreshold: gaps.length,
3008
- coverageThreshold: threshold,
3009
- },
3010
- agentAssignments,
3011
- ruvectorAvailable: false,
3012
- source: diskCoverage.source,
3013
- };
3014
- if (ctx.flags.format === 'json') {
3015
- output.printJson(result);
3016
- return { success: true, data: result };
3017
- }
3018
- output.writeln();
3019
- output.printBox([
3020
- `Total Files: ${result.summary.totalFiles}`,
3021
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
3022
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
3023
- `Below ${threshold}%: ${result.summary.filesBelowThreshold} files`,
3024
- `Source: ${output.highlight(diskCoverage.source)}`
3025
- ].join('\n'), 'Coverage Gap Analysis');
3026
- if (gaps.length > 0) {
3027
- output.writeln();
3028
- output.writeln(output.bold(`Coverage Gaps (${gaps.length} files)`));
3029
- output.printTable({
3030
- columns: [
3031
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
3032
- const s = String(v);
3033
- return s.length > 32 ? '...' + s.slice(-32) : s;
3034
- } },
3035
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
3036
- { key: 'gapType', header: 'Type', width: 10, format: (v) => {
3037
- const t = String(v);
3038
- if (t === 'critical')
3039
- return output.error(t);
3040
- if (t === 'high')
3041
- return output.warning(t);
3042
- return t;
3043
- } },
3044
- { key: 'priority', header: 'Priority', width: 8, align: 'right' },
3045
- { key: 'suggestedAgents', header: 'Agent', width: 12, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
3046
- ],
3047
- data: gaps.slice(0, 20)
3048
- });
3049
- }
3050
- else {
3051
- output.writeln();
3052
- output.printSuccess('No coverage gaps found! All files meet threshold.');
3053
- }
3054
- if (groupByAgent && Object.keys(agentAssignments).length > 0) {
3055
- output.writeln();
3056
- output.writeln(output.bold('Agent Assignments'));
3057
- for (const [agent, files] of Object.entries(agentAssignments)) {
3058
- output.writeln();
3059
- output.writeln(` ${output.highlight(agent)} (${files.length} files)`);
3060
- files.slice(0, 3).forEach(f => {
3061
- output.writeln(` - ${output.dim(f)}`);
3062
- });
3063
- if (files.length > 3) {
3064
- output.writeln(` ... and ${files.length - 3} more`);
3065
- }
3066
- }
3067
- }
3068
- return { success: true, data: result };
3069
- }
3070
- // No coverage files on disk - try MCP tool as fallback
3071
- try {
3072
- const result = await callMCPTool('hooks_coverage-gaps', {
3073
- threshold,
3074
- groupByAgent,
3075
- });
3076
- spinner.stop();
3077
- const gaps = criticalOnly
3078
- ? result.gaps.filter(g => g.gapType === 'critical')
3079
- : result.gaps;
3080
- if (ctx.flags.format === 'json') {
3081
- output.printJson({ ...result, gaps });
3082
- return { success: true, data: result };
3083
- }
3084
- output.writeln();
3085
- output.printBox([
3086
- `Total Files: ${result.summary.totalFiles}`,
3087
- `Line Coverage: ${result.summary.overallLineCoverage.toFixed(1)}%`,
3088
- `Branch Coverage: ${result.summary.overallBranchCoverage.toFixed(1)}%`,
3089
- `Below ${result.summary.coverageThreshold}%: ${result.summary.filesBelowThreshold} files`,
3090
- `RuVector: ${result.ruvectorAvailable ? output.success('Available') : output.dim('Not installed')}`
3091
- ].join('\n'), 'Coverage Gap Analysis');
3092
- if (gaps.length > 0) {
3093
- output.writeln();
3094
- output.writeln(output.bold(`Coverage Gaps (${gaps.length} files)`));
3095
- output.printTable({
3096
- columns: [
3097
- { key: 'filePath', header: 'File', width: 35, format: (v) => {
3098
- const s = String(v);
3099
- return s.length > 32 ? '...' + s.slice(-32) : s;
3100
- } },
3101
- { key: 'coveragePercent', header: 'Coverage', width: 10, align: 'right', format: (v) => `${Number(v).toFixed(1)}%` },
3102
- { key: 'gapType', header: 'Type', width: 10, format: (v) => {
3103
- const t = String(v);
3104
- if (t === 'critical')
3105
- return output.error(t);
3106
- if (t === 'high')
3107
- return output.warning(t);
3108
- return t;
3109
- } },
3110
- { key: 'priority', header: 'Priority', width: 8, align: 'right' },
3111
- { key: 'suggestedAgents', header: 'Agent', width: 12, format: (v) => Array.isArray(v) ? v[0] || '' : String(v) }
3112
- ],
3113
- data: gaps.slice(0, 20)
3114
- });
3115
- }
3116
- else {
3117
- output.writeln();
3118
- output.printSuccess('No coverage gaps found! All files meet threshold.');
3119
- }
3120
- if (groupByAgent && Object.keys(result.agentAssignments).length > 0) {
3121
- output.writeln();
3122
- output.writeln(output.bold('Agent Assignments'));
3123
- for (const [agent, files] of Object.entries(result.agentAssignments)) {
3124
- output.writeln();
3125
- output.writeln(` ${output.highlight(agent)} (${files.length} files)`);
3126
- files.slice(0, 3).forEach(f => {
3127
- output.writeln(` - ${output.dim(f)}`);
3128
- });
3129
- if (files.length > 3) {
3130
- output.writeln(` ... and ${files.length - 3} more`);
3131
- }
3132
- }
3133
- }
3134
- return { success: true, data: result };
3135
- }
3136
- catch (error) {
3137
- spinner.fail('No coverage data found');
3138
- output.writeln();
3139
- output.printWarning('No coverage data found. Run your test suite with coverage first.');
3140
- output.writeln();
3141
- output.printList([
3142
- 'Jest: npx jest --coverage',
3143
- 'Vitest: npx vitest --coverage',
3144
- 'nyc: npx nyc npm test',
3145
- 'c8: npx c8 npm test',
3146
- ]);
3147
- output.writeln();
3148
- output.writeln(output.dim('Expected files: coverage/coverage-summary.json, coverage/lcov.info, or .nyc_output/out.json'));
3149
- return { success: false, exitCode: 1 };
3150
- }
3151
- }
3152
- };
3153
- // Progress hook command
3154
- const progressHookCommand = {
3155
- name: 'progress',
3156
- description: 'Check V3 implementation progress via hooks',
3157
- options: [
3158
- {
3159
- name: 'detailed',
3160
- short: 'd',
3161
- description: 'Show detailed breakdown by category',
3162
- type: 'boolean',
3163
- default: false
3164
- },
3165
- {
3166
- name: 'sync',
3167
- short: 's',
3168
- description: 'Sync and persist progress to file',
3169
- type: 'boolean',
3170
- default: false
3171
- },
3172
- {
3173
- name: 'summary',
3174
- description: 'Show human-readable summary',
3175
- type: 'boolean',
3176
- default: false
3177
- }
3178
- ],
3179
- examples: [
3180
- { command: 'claude-flow hooks progress', description: 'Check current progress' },
3181
- { command: 'claude-flow hooks progress -d', description: 'Detailed breakdown' },
3182
- { command: 'claude-flow hooks progress --sync', description: 'Sync progress to file' },
3183
- { command: 'claude-flow hooks progress --summary', description: 'Human-readable summary' }
3184
- ],
3185
- action: async (ctx) => {
3186
- const detailed = ctx.flags.detailed;
3187
- const sync = ctx.flags.sync;
3188
- const summary = ctx.flags.summary;
3189
- try {
3190
- if (summary) {
3191
- const spinner = output.createSpinner({ text: 'Getting progress summary...' });
3192
- spinner.start();
3193
- const result = await callMCPTool('progress_summary', {});
3194
- spinner.stop();
3195
- if (ctx.flags.format === 'json') {
3196
- output.printJson(result);
3197
- return { success: true, data: result };
3198
- }
3199
- output.writeln();
3200
- output.writeln(result.summary);
3201
- return { success: true, data: result };
3202
- }
3203
- if (sync) {
3204
- const spinner = output.createSpinner({ text: 'Syncing progress...' });
3205
- spinner.start();
3206
- const result = await callMCPTool('progress_sync', {});
3207
- spinner.stop();
3208
- if (ctx.flags.format === 'json') {
3209
- output.printJson(result);
3210
- return { success: true, data: result };
3211
- }
3212
- output.writeln();
3213
- output.printSuccess(`Progress synced: ${result.progress}%`);
3214
- output.writeln(output.dim(` Persisted to .claude-flow/metrics/v3-progress.json`));
3215
- output.writeln(output.dim(` Last updated: ${result.lastUpdated}`));
3216
- return { success: true, data: result };
3217
- }
3218
- // Default: check progress
3219
- const spinner = output.createSpinner({ text: 'Checking V3 progress...' });
3220
- spinner.start();
3221
- const result = await callMCPTool('progress_check', { detailed });
3222
- spinner.stop();
3223
- if (ctx.flags.format === 'json') {
3224
- output.printJson(result);
3225
- return { success: true, data: result };
3226
- }
3227
- output.writeln();
3228
- const progressValue = result.overall ?? result.progress ?? 0;
3229
- // Create progress bar
3230
- const barWidth = 30;
3231
- const filled = Math.round((progressValue / 100) * barWidth);
3232
- const empty = barWidth - filled;
3233
- const bar = output.success('█'.repeat(filled)) + output.dim('░'.repeat(empty));
3234
- output.writeln(output.bold('V3 Implementation Progress'));
3235
- output.writeln();
3236
- output.writeln(`[${bar}] ${progressValue}%`);
3237
- output.writeln();
3238
- if (detailed && result.cli) {
3239
- output.writeln(output.highlight('CLI Commands:') + ` ${result.cli.progress}% (${result.cli.commands}/${result.cli.target})`);
3240
- output.writeln(output.highlight('MCP Tools:') + ` ${result.mcp?.progress ?? 0}% (${result.mcp?.tools ?? 0}/${result.mcp?.target ?? 0})`);
3241
- output.writeln(output.highlight('Hooks:') + ` ${result.hooks?.progress ?? 0}% (${result.hooks?.subcommands ?? 0}/${result.hooks?.target ?? 0})`);
3242
- output.writeln(output.highlight('Packages:') + ` ${result.packages?.progress ?? 0}% (${result.packages?.total ?? 0}/${result.packages?.target ?? 0})`);
3243
- output.writeln(output.highlight('DDD Structure:') + ` ${result.ddd?.progress ?? 0}% (${result.packages?.withDDD ?? 0}/${result.packages?.total ?? 0})`);
3244
- output.writeln();
3245
- if (result.codebase) {
3246
- output.writeln(output.dim(`Codebase: ${result.codebase.totalFiles} files, ${result.codebase.totalLines.toLocaleString()} lines`));
3247
- }
3248
- }
3249
- else if (result.breakdown) {
3250
- output.writeln('Breakdown:');
3251
- for (const [category, value] of Object.entries(result.breakdown)) {
3252
- output.writeln(` ${output.highlight(category)}: ${value}`);
3253
- }
3254
- }
3255
- if (result.lastUpdated) {
3256
- output.writeln(output.dim(`Last updated: ${result.lastUpdated}`));
3257
- }
3258
- return { success: true, data: result };
3259
- }
3260
- catch (error) {
3261
- if (error instanceof MCPClientError) {
3262
- output.printError(`Progress check failed: ${error.message}`);
3263
- }
3264
- else {
3265
- output.printError(`Progress check failed: ${String(error)}`);
3266
- }
3267
- return { success: false, exitCode: 1 };
3268
- }
3269
- }
3270
- };
3271
- // Worker parent command
3272
- const workerCommand = {
3273
- name: 'worker',
3274
- description: 'Background worker management (12 workers for analysis/optimization)',
3275
- subcommands: [
3276
- workerListCommand,
3277
- workerDispatchCommand,
3278
- workerStatusCommand,
3279
- workerDetectCommand,
3280
- workerCancelCommand,
3281
- ],
3282
- options: [],
3283
- examples: [
3284
- { command: 'claude-flow hooks worker list', description: 'List all workers' },
3285
- { command: 'claude-flow hooks worker dispatch -t optimize', description: 'Dispatch optimizer' },
3286
- { command: 'claude-flow hooks worker detect -p "test coverage"', description: 'Detect from prompt' },
3287
- ],
3288
- action: async () => {
3289
- output.writeln();
3290
- output.writeln(output.bold('Background Worker System (12 Workers)'));
3291
- output.writeln();
3292
- output.writeln('Manage and dispatch background workers for analysis and optimization tasks.');
3293
- output.writeln();
3294
- output.writeln('Available Workers:');
3295
- output.printList([
3296
- `${output.highlight('ultralearn')} - Deep knowledge acquisition`,
3297
- `${output.highlight('optimize')} - Performance optimization`,
3298
- `${output.highlight('consolidate')} - Memory consolidation`,
3299
- `${output.highlight('predict')} - Predictive preloading`,
3300
- `${output.highlight('audit')} - Security analysis (critical)`,
3301
- `${output.highlight('map')} - Codebase mapping`,
3302
- `${output.highlight('preload')} - Resource preloading`,
3303
- `${output.highlight('deepdive')} - Deep code analysis`,
3304
- `${output.highlight('document')} - Auto-documentation`,
3305
- `${output.highlight('refactor')} - Refactoring suggestions`,
3306
- `${output.highlight('benchmark')} - Performance benchmarks`,
3307
- `${output.highlight('testgaps')} - Test coverage analysis`,
3308
- ]);
3309
- output.writeln();
3310
- output.writeln('Subcommands:');
3311
- output.printList([
3312
- `${output.highlight('list')} - List all workers with capabilities`,
3313
- `${output.highlight('dispatch')} - Dispatch a worker`,
3314
- `${output.highlight('status')} - Check worker status`,
3315
- `${output.highlight('detect')} - Detect triggers from prompt`,
3316
- `${output.highlight('cancel')} - Cancel a running worker`,
3317
- ]);
3318
- output.writeln();
3319
- output.writeln('Run "claude-flow hooks worker <subcommand> --help" for details');
3320
- return { success: true };
3321
- }
3322
- };
3323
- // Statusline subcommand - generates dynamic status display
3324
- const statuslineCommand = {
3325
- name: 'statusline',
3326
- description: 'Generate dynamic statusline with V3 progress and system status',
3327
- options: [
3328
- {
3329
- name: 'json',
3330
- description: 'Output as JSON',
3331
- type: 'boolean',
3332
- default: false
3333
- },
3334
- {
3335
- name: 'compact',
3336
- description: 'Compact single-line output (auto-enabled when terminal width < 100 cols)',
3337
- type: 'boolean',
3338
- default: false
3339
- },
3340
- {
3341
- name: 'full',
3342
- description: 'Force the full multi-line output even on narrow terminals',
3343
- type: 'boolean',
3344
- default: false
3345
- },
3346
- {
3347
- name: 'no-color',
3348
- description: 'Disable ANSI colors',
3349
- type: 'boolean',
3350
- default: false
3351
- }
3352
- ],
3353
- examples: [
3354
- { command: 'claude-flow hooks statusline', description: 'Display full statusline' },
3355
- { command: 'claude-flow hooks statusline --json', description: 'JSON output for hooks' },
3356
- { command: 'claude-flow hooks statusline --compact', description: 'Single-line status' }
3357
- ],
3358
- action: async (ctx) => {
3359
- const fs = await import('fs');
3360
- const path = await import('path');
3361
- const { execSync } = await import('child_process');
3362
- // Get learning stats from memory database
3363
- function getLearningStats() {
3364
- const memoryPaths = [
3365
- path.join(process.cwd(), '.swarm', 'memory.db'),
3366
- path.join(process.cwd(), '.claude', 'memory.db'),
3367
- ];
3368
- let patterns = 0;
3369
- let sessions = 0;
3370
- let trajectories = 0;
3371
- for (const dbPath of memoryPaths) {
3372
- if (fs.existsSync(dbPath)) {
3373
- try {
3374
- const stats = fs.statSync(dbPath);
3375
- const sizeKB = stats.size / 1024;
3376
- patterns = Math.floor(sizeKB / 2);
3377
- sessions = Math.max(1, Math.floor(patterns / 10));
3378
- trajectories = Math.floor(patterns / 5);
3379
- break;
3380
- }
3381
- catch {
3382
- // Ignore
3383
- }
3384
- }
3385
- }
3386
- const sessionsPath = path.join(process.cwd(), '.claude', 'sessions');
3387
- if (fs.existsSync(sessionsPath)) {
3388
- try {
3389
- const sessionFiles = fs.readdirSync(sessionsPath).filter((f) => f.endsWith('.json'));
3390
- sessions = Math.max(sessions, sessionFiles.length);
3391
- }
3392
- catch {
3393
- // Ignore
3394
- }
3395
- }
3396
- return { patterns, sessions, trajectories };
3397
- }
3398
- // Get V3 progress
3399
- function getV3Progress() {
3400
- const learning = getLearningStats();
3401
- let domainsCompleted = 0;
3402
- if (learning.patterns >= 500)
3403
- domainsCompleted = 5;
3404
- else if (learning.patterns >= 200)
3405
- domainsCompleted = 4;
3406
- else if (learning.patterns >= 100)
3407
- domainsCompleted = 3;
3408
- else if (learning.patterns >= 50)
3409
- domainsCompleted = 2;
3410
- else if (learning.patterns >= 10)
3411
- domainsCompleted = 1;
3412
- const totalDomains = 5;
3413
- const dddProgress = Math.min(100, Math.floor((domainsCompleted / totalDomains) * 100));
3414
- return { domainsCompleted, totalDomains, dddProgress, patternsLearned: learning.patterns, sessionsCompleted: learning.sessions };
3415
- }
3416
- // Security/swarm status — shared with the advisor-tip refresh (ADR-316)
3417
- // via funnel/local-signals.ts, a single source of truth so the two call
3418
- // sites can never silently drift on what these signals mean.
3419
- const getSecurityStatus = sharedGetSecurityStatus;
3420
- const getSwarmStatus = sharedGetSwarmStatus;
3421
- // Get system metrics
3422
- function getSystemMetrics() {
3423
- let memoryMB = 0;
3424
- let subAgents = 0;
3425
- const learning = getLearningStats();
3426
- try {
3427
- memoryMB = Math.floor(process.memoryUsage().heapUsed / 1024 / 1024);
3428
- }
3429
- catch {
3430
- // Ignore
3431
- }
3432
- // Calculate intelligence from multiple sources (matching statusline-generator.ts)
3433
- let intelligencePct = 0;
3434
- // 1. Check learning.json for REAL intelligence metrics first
3435
- const learningJsonPaths = [
3436
- path.join(process.cwd(), '.claude-flow', 'learning.json'),
3437
- path.join(process.cwd(), '.claude', '.claude-flow', 'learning.json'),
3438
- path.join(process.cwd(), '.swarm', 'learning.json'),
3439
- ];
3440
- for (const lPath of learningJsonPaths) {
3441
- if (fs.existsSync(lPath)) {
3442
- try {
3443
- const data = JSON.parse(fs.readFileSync(lPath, 'utf-8'));
3444
- if (data.intelligence?.score !== undefined) {
3445
- intelligencePct = Math.min(100, Math.floor(data.intelligence.score));
3446
- break;
3447
- }
3448
- }
3449
- catch { /* ignore */ }
3450
- }
3451
- }
3452
- // 2. Fallback: calculate from patterns and vectors
3453
- if (intelligencePct === 0) {
3454
- const fromPatterns = learning.patterns > 0 ? Math.min(100, Math.floor(learning.patterns / 10)) : 0;
3455
- // Will be updated later with vector count
3456
- intelligencePct = fromPatterns;
3457
- }
3458
- // 3. Fallback: calculate maturity score from project indicators
3459
- if (intelligencePct === 0) {
3460
- let maturityScore = 0;
3461
- // Check for key project files/dirs
3462
- if (fs.existsSync(path.join(process.cwd(), '.claude')))
3463
- maturityScore += 15;
3464
- if (fs.existsSync(path.join(process.cwd(), '.claude-flow')))
3465
- maturityScore += 15;
3466
- if (fs.existsSync(path.join(process.cwd(), 'CLAUDE.md')))
3467
- maturityScore += 10;
3468
- if (fs.existsSync(path.join(process.cwd(), 'claude-flow.config.json')))
3469
- maturityScore += 10;
3470
- if (fs.existsSync(path.join(process.cwd(), '.swarm')))
3471
- maturityScore += 10;
3472
- // Check for test files
3473
- const testDirs = ['tests', '__tests__', 'test', 'v3/__tests__'];
3474
- for (const dir of testDirs) {
3475
- if (fs.existsSync(path.join(process.cwd(), dir))) {
3476
- maturityScore += 10;
3477
- break;
3478
- }
3479
- }
3480
- // Check for hooks config
3481
- if (fs.existsSync(path.join(process.cwd(), '.claude', 'settings.json')))
3482
- maturityScore += 10;
3483
- intelligencePct = Math.min(100, maturityScore);
3484
- }
3485
- const contextPct = Math.min(100, Math.floor(learning.sessions * 5));
3486
- return { memoryMB, contextPct, intelligencePct, subAgents };
3487
- }
3488
- // Get user info
3489
- function getUserInfo() {
3490
- const identityMode = (process.env.RUFLO_STATUSLINE_IDENTITY || 'project').toLowerCase();
3491
- let name = path.basename(process.cwd()) || 'project';
3492
- let gitBranch = '';
3493
- const modelName = 'Opus 4.6 (1M context)';
3494
- const isWindows = process.platform === 'win32';
3495
- try {
3496
- const rootCmd = isWindows
3497
- ? 'git rev-parse --show-toplevel 2>NUL'
3498
- : 'git rev-parse --show-toplevel 2>/dev/null';
3499
- const branchCmd = isWindows
3500
- ? 'git branch --show-current 2>NUL || echo.'
3501
- : 'git branch --show-current 2>/dev/null || echo ""';
3502
- const root = execSync(rootCmd, { encoding: 'utf-8' }).trim();
3503
- name = path.basename(root) || name;
3504
- if (identityMode === 'author') {
3505
- const authorCmd = isWindows
3506
- ? 'git config user.name 2>NUL || echo user'
3507
- : 'git config user.name 2>/dev/null || echo "user"';
3508
- name = execSync(authorCmd, { encoding: 'utf-8' }).trim() || 'user';
3509
- }
3510
- gitBranch = execSync(branchCmd, { encoding: 'utf-8' }).trim();
3511
- if (gitBranch === '.')
3512
- gitBranch = '';
3513
- }
3514
- catch {
3515
- // Ignore
3516
- }
3517
- return { name, gitBranch, modelName };
3518
- }
3519
- // Collect all status
3520
- const progress = getV3Progress();
3521
- const security = getSecurityStatus();
3522
- const swarm = getSwarmStatus();
3523
- const system = getSystemMetrics();
3524
- const user = getUserInfo();
3525
- const getGitUncommittedCount = sharedGetGitUncommittedCount;
3526
- // Funnel promo row (ADR-301). The statusline is spawned with piped stdio
3527
- // by an interactive host, so interactivity is asserted here; all other
3528
- // gates (RUFLO_FUNNEL, enterprise policy, config, CI, disclosure,
3529
- // rotation ratio) are enforced inside getFunnelPromo. Never allowed to
3530
- // break the statusline.
3531
- let promo = null;
3532
- try {
3533
- const { getFunnelPromo } = await import('../funnel/index.js');
3534
- promo = getFunnelPromo({
3535
- interactive: true,
3536
- localInsights: { security, swarm, gitUncommittedCount: getGitUncommittedCount() },
3537
- });
3538
- }
3539
- catch {
3540
- promo = null;
3541
- }
3542
- const statusData = {
3543
- user,
3544
- v3Progress: progress,
3545
- security,
3546
- swarm,
3547
- system,
3548
- promo,
3549
- timestamp: new Date().toISOString()
3550
- };
3551
- // JSON output
3552
- if (ctx.flags.json || ctx.flags.format === 'json') {
3553
- output.printJson(statusData);
3554
- return { success: true, data: statusData };
3555
- }
3556
- // #1153: auto-collapse to compact on narrow terminals so the full
3557
- // 6+ line statusline doesn't dominate the screen. Honors:
3558
- // - explicit --compact → compact
3559
- // - explicit --full → full (overrides auto-detection)
3560
- // - else → compact when terminal < 100 cols (full multi-line
3561
- // output expects ~100 cols of horizontal space)
3562
- const COMPACT_WIDTH_THRESHOLD = 100;
3563
- const terminalCols = process.stdout.columns ?? 80;
3564
- const autoCompact = !ctx.flags.full && terminalCols < COMPACT_WIDTH_THRESHOLD;
3565
- if (ctx.flags.compact || autoCompact) {
3566
- const securityCompact = security.findings > 0
3567
- ? `Findings:${security.findings}`
3568
- : `Security:${security.status}`;
3569
- const line = `DDD:${progress.domainsCompleted}/${progress.totalDomains} ${securityCompact} Swarm:${swarm.activeAgents}/${swarm.maxAgents} Ctx:${system.contextPct}% Int:${system.intelligencePct}%`;
3570
- output.writeln(line);
3571
- return { success: true, data: statusData };
3572
- }
3573
- // Full colored output
3574
- const noColor = ctx.flags['no-color'] || ctx.flags.noColor;
3575
- const c = noColor ? {
3576
- reset: '', bold: '', dim: '', red: '', green: '', yellow: '', blue: '',
3577
- purple: '', cyan: '', brightRed: '', brightGreen: '', brightYellow: '',
3578
- brightBlue: '', brightPurple: '', brightCyan: '', brightWhite: ''
3579
- } : {
3580
- reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', red: '\x1b[0;31m',
3581
- green: '\x1b[0;32m', yellow: '\x1b[0;33m', blue: '\x1b[0;34m',
3582
- purple: '\x1b[0;35m', cyan: '\x1b[0;36m', brightRed: '\x1b[1;31m',
3583
- brightGreen: '\x1b[1;32m', brightYellow: '\x1b[1;33m', brightBlue: '\x1b[1;34m',
3584
- brightPurple: '\x1b[1;35m', brightCyan: '\x1b[1;36m', brightWhite: '\x1b[1;37m'
3585
- };
3586
- // Progress bar helper
3587
- const progressBar = (current, total) => {
3588
- const filled = Math.round((current / total) * 5);
3589
- const empty = 5 - filled;
3590
- return '[' + '●'.repeat(filled) + '○'.repeat(empty) + ']';
3591
- };
3592
- // Generate lines
3593
- let header = `${c.bold}${c.brightPurple}▊ RuFlo V3 ${c.reset}`;
3594
- header += `${swarm.coordinationActive ? c.brightCyan : c.dim}● ${c.brightCyan}${user.name}${c.reset}`;
3595
- if (user.gitBranch) {
3596
- header += ` ${c.dim}│${c.reset} ${c.brightBlue}⎇ ${user.gitBranch}${c.reset}`;
3597
- }
3598
- header += ` ${c.dim}│${c.reset} ${c.purple}${user.modelName}${c.reset}`;
3599
- const separator = `${c.dim}─────────────────────────────────────────────────────${c.reset}`;
3600
- // Get hooks stats
3601
- const hooksStats = { enabled: 0, total: 17 };
3602
- const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
3603
- if (fs.existsSync(settingsPath)) {
3604
- try {
3605
- const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
3606
- if (settings.hooks) {
3607
- hooksStats.enabled = Object.values(settings.hooks).filter((h) => h && typeof h === 'object').length;
3608
- }
3609
- }
3610
- catch { /* ignore */ }
3611
- }
3612
- // Get AgentDB stats (matching statusline-generator.ts paths)
3613
- const agentdbStats = { vectorCount: 0, dbSizeKB: 0, hasHnsw: false };
3614
- // Check for direct database files first
3615
- const dbPaths = [
3616
- path.join(process.cwd(), '.swarm', 'memory.db'),
3617
- path.join(process.cwd(), '.claude-flow', 'memory.db'),
3618
- path.join(process.cwd(), '.claude', 'memory.db'),
3619
- path.join(process.cwd(), 'data', 'memory.db'),
3620
- path.join(process.cwd(), 'memory.db'),
3621
- path.join(process.cwd(), '.agentdb', 'memory.db'),
3622
- path.join(process.cwd(), '.claude-flow', 'memory', 'agentdb.db'),
3623
- ];
3624
- for (const dbPath of dbPaths) {
3625
- if (fs.existsSync(dbPath)) {
3626
- try {
3627
- const stats = fs.statSync(dbPath);
3628
- agentdbStats.dbSizeKB = Math.round(stats.size / 1024);
3629
- agentdbStats.vectorCount = Math.floor(agentdbStats.dbSizeKB / 2);
3630
- agentdbStats.hasHnsw = agentdbStats.vectorCount > 100;
3631
- break;
3632
- }
3633
- catch { /* ignore */ }
3634
- }
3635
- }
3636
- // Check for AgentDB directories if no direct db found
3637
- if (agentdbStats.vectorCount === 0) {
3638
- const agentdbDirs = [
3639
- path.join(process.cwd(), '.claude-flow', 'agentdb'),
3640
- path.join(process.cwd(), '.swarm', 'agentdb'),
3641
- path.join(process.cwd(), 'data', 'agentdb'),
3642
- path.join(process.cwd(), '.agentdb'),
3643
- ];
3644
- for (const dir of agentdbDirs) {
3645
- if (fs.existsSync(dir)) {
3646
- try {
3647
- const files = fs.readdirSync(dir);
3648
- for (const f of files) {
3649
- if (f.endsWith('.db') || f.endsWith('.sqlite')) {
3650
- const filePath = path.join(dir, f);
3651
- const fileStat = fs.statSync(filePath);
3652
- agentdbStats.dbSizeKB += Math.round(fileStat.size / 1024);
3653
- }
3654
- }
3655
- agentdbStats.vectorCount = Math.floor(agentdbStats.dbSizeKB / 2);
3656
- agentdbStats.hasHnsw = agentdbStats.vectorCount > 100;
3657
- if (agentdbStats.vectorCount > 0)
3658
- break;
3659
- }
3660
- catch { /* ignore */ }
3661
- }
3662
- }
3663
- }
3664
- // Check for HNSW index files
3665
- const hnswPaths = [
3666
- path.join(process.cwd(), '.claude-flow', 'hnsw'),
3667
- path.join(process.cwd(), '.swarm', 'hnsw'),
3668
- path.join(process.cwd(), 'data', 'hnsw'),
3669
- ];
3670
- for (const hnswPath of hnswPaths) {
3671
- if (fs.existsSync(hnswPath)) {
3672
- agentdbStats.hasHnsw = true;
3673
- try {
3674
- const hnswFiles = fs.readdirSync(hnswPath);
3675
- const indexFile = hnswFiles.find(f => f.endsWith('.index'));
3676
- if (indexFile) {
3677
- const indexStat = fs.statSync(path.join(hnswPath, indexFile));
3678
- const hnswVectors = Math.floor(indexStat.size / 512);
3679
- agentdbStats.vectorCount = Math.max(agentdbStats.vectorCount, hnswVectors);
3680
- }
3681
- }
3682
- catch { /* ignore */ }
3683
- break;
3684
- }
3685
- }
3686
- // Check for vectors.json file
3687
- const vectorsPath = path.join(process.cwd(), '.claude-flow', 'vectors.json');
3688
- if (fs.existsSync(vectorsPath) && agentdbStats.vectorCount === 0) {
3689
- try {
3690
- const data = JSON.parse(fs.readFileSync(vectorsPath, 'utf-8'));
3691
- if (Array.isArray(data)) {
3692
- agentdbStats.vectorCount = data.length;
3693
- }
3694
- else if (data.vectors) {
3695
- agentdbStats.vectorCount = Object.keys(data.vectors).length;
3696
- }
3697
- }
3698
- catch { /* ignore */ }
3699
- }
3700
- // Get test stats
3701
- const testStats = { testFiles: 0, testCases: 0 };
3702
- const testPaths = ['tests', '__tests__', 'test', 'spec'];
3703
- for (const testPath of testPaths) {
3704
- const fullPath = path.join(process.cwd(), testPath);
3705
- if (fs.existsSync(fullPath)) {
3706
- try {
3707
- const files = fs.readdirSync(fullPath, { recursive: true });
3708
- testStats.testFiles = files.filter((f) => /\.(test|spec)\.(ts|js|tsx|jsx)$/.test(f)).length;
3709
- testStats.testCases = testStats.testFiles * 28; // Estimate
3710
- }
3711
- catch { /* ignore */ }
3712
- }
3713
- }
3714
- // Get MCP stats
3715
- const mcpStats = { enabled: 0, total: 0 };
3716
- const mcpPath = path.join(process.cwd(), '.mcp.json');
3717
- if (fs.existsSync(mcpPath)) {
3718
- try {
3719
- const mcp = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
3720
- if (mcp.mcpServers) {
3721
- mcpStats.total = Object.keys(mcp.mcpServers).length;
3722
- mcpStats.enabled = mcpStats.total;
3723
- }
3724
- }
3725
- catch { /* ignore */ }
3726
- }
3727
- const domainsColor = progress.domainsCompleted >= 3 ? c.brightGreen : progress.domainsCompleted > 0 ? c.yellow : c.red;
3728
- // Dynamic perf indicator based on patterns/HNSW
3729
- let perfIndicator = `${c.dim}⚡ target: 150x-12500x${c.reset}`;
3730
- if (agentdbStats.hasHnsw && agentdbStats.vectorCount > 0) {
3731
- const speedup = agentdbStats.vectorCount > 10000 ? '12500x' : agentdbStats.vectorCount > 1000 ? '150x' : '10x';
3732
- perfIndicator = `${c.brightGreen}⚡ HNSW ${speedup}${c.reset}`;
3733
- }
3734
- else if (progress.patternsLearned > 0) {
3735
- const patternsK = progress.patternsLearned >= 1000 ? `${(progress.patternsLearned / 1000).toFixed(1)}k` : String(progress.patternsLearned);
3736
- perfIndicator = `${c.brightYellow}📚 ${patternsK} patterns${c.reset}`;
3737
- }
3738
- const line1 = `${c.brightCyan}🏗️ DDD Domains${c.reset} ${progressBar(progress.domainsCompleted, progress.totalDomains)} ` +
3739
- `${domainsColor}${progress.domainsCompleted}${c.reset}/${c.brightWhite}${progress.totalDomains}${c.reset} ` +
3740
- perfIndicator;
3741
- const swarmIndicator = swarm.coordinationActive ? `${c.brightGreen}◉${c.reset}` : `${c.dim}○${c.reset}`;
3742
- const agentsColor = swarm.activeAgents > 0 ? c.brightGreen : c.red;
3743
- const securityIcon = security.status === 'CLEAN' ? '🟢' : security.status === 'PENDING' ? '🟡' : '🔴';
3744
- const securityColor = security.status === 'CLEAN' ? c.brightGreen : security.status === 'PENDING' ? c.brightYellow : c.brightRed;
3745
- const hooksColor = hooksStats.enabled > 0 ? c.brightGreen : c.dim;
3746
- const line2 = `${c.brightYellow}🤖 Swarm${c.reset} ${swarmIndicator} [${agentsColor}${String(swarm.activeAgents).padStart(2)}${c.reset}/${c.brightWhite}${swarm.maxAgents}${c.reset}] ` +
3747
- `${c.brightPurple}👥 ${system.subAgents}${c.reset} ` +
3748
- `${c.brightBlue}🪝 ${hooksColor}${hooksStats.enabled}${c.reset}/${c.brightWhite}${hooksStats.total}${c.reset} ` +
3749
- `${securityIcon} ${securityColor}${security.findings > 0 ? `Findings ${security.findings}` : `Security ${security.status}`}${c.reset} ` +
3750
- `${c.brightCyan}💾 ${system.memoryMB}MB${c.reset} ` +
3751
- `${c.brightPurple}🧠 ${String(system.intelligencePct).padStart(3)}%${c.reset}`;
3752
- const dddColor = progress.dddProgress >= 50 ? c.brightGreen : progress.dddProgress > 0 ? c.yellow : c.red;
3753
- const line3 = `${c.brightPurple}🔧 Architecture${c.reset} ` +
3754
- `${c.cyan}ADRs${c.reset} ${c.dim}●0/0${c.reset} ${c.dim}│${c.reset} ` +
3755
- `${c.cyan}DDD${c.reset} ${dddColor}●${String(progress.dddProgress).padStart(3)}%${c.reset} ${c.dim}│${c.reset} ` +
3756
- `${c.cyan}Security${c.reset} ${securityColor}●${security.status}${c.reset}`;
3757
- const vectorColor = agentdbStats.vectorCount > 0 ? c.brightGreen : c.dim;
3758
- const testColor = testStats.testFiles > 0 ? c.brightGreen : c.dim;
3759
- const mcpColor = mcpStats.enabled > 0 ? c.brightGreen : c.dim;
3760
- const sizeDisplay = agentdbStats.dbSizeKB >= 1024 ? `${(agentdbStats.dbSizeKB / 1024).toFixed(1)}MB` : `${agentdbStats.dbSizeKB}KB`;
3761
- const hnswIndicator = agentdbStats.hasHnsw ? `${c.brightGreen}⚡${c.reset}` : '';
3762
- const line4 = `${c.brightCyan}📊 AgentDB${c.reset} ` +
3763
- `${c.cyan}Vectors${c.reset} ${vectorColor}●${agentdbStats.vectorCount}${hnswIndicator}${c.reset} ${c.dim}│${c.reset} ` +
3764
- `${c.cyan}Size${c.reset} ${c.brightWhite}${sizeDisplay}${c.reset} ${c.dim}│${c.reset} ` +
3765
- `${c.cyan}Tests${c.reset} ${testColor}●${testStats.testFiles}${c.reset} ${c.dim}(${testStats.testCases} cases)${c.reset} ${c.dim}│${c.reset} ` +
3766
- `${c.cyan}MCP${c.reset} ${mcpColor}●${mcpStats.enabled}/${mcpStats.total}${c.reset}`;
3767
- output.writeln(header);
3768
- output.writeln(separator);
3769
- output.writeln(line1);
3770
- output.writeln(line2);
3771
- output.writeln(line3);
3772
- output.writeln(line4);
3773
- return { success: true, data: statusData };
3774
- }
3775
- };
3776
- // Backward-compatible aliases for v2 hooks
3777
- // These ensure old settings.json files continue to work
3778
- const routeTaskCommand = {
3779
- name: 'route-task',
3780
- description: '(DEPRECATED: Use "route" instead) Route task to optimal agent',
3781
- options: routeCommand.options,
3782
- examples: [
3783
- { command: 'claude-flow hooks route-task --auto-swarm true', description: 'Route with auto-swarm (v2 compat)' },
3784
- ],
3785
- action: async (ctx) => {
3786
- // Silently handle v2-specific flags that don't exist in v3
3787
- // --auto-swarm, --detect-complexity are ignored but don't fail
3788
- if (routeCommand.action) {
3789
- const result = await routeCommand.action(ctx);
3790
- return result || { success: true };
3791
- }
3792
- return { success: true };
3793
- }
3794
- };
3795
- const sessionStartCommand = {
3796
- name: 'session-start',
3797
- description: '(DEPRECATED: Use "session-restore" instead) Start/restore session',
3798
- options: [
3799
- ...(sessionRestoreCommand.options || []),
3800
- // V2-compatible options that are silently ignored
3801
- {
3802
- name: 'auto-configure',
3803
- description: '(v2 compat) Auto-configure session',
3804
- type: 'boolean',
3805
- default: false
3806
- },
3807
- {
3808
- name: 'restore-context',
3809
- description: '(v2 compat) Restore context',
3810
- type: 'boolean',
3811
- default: false
3812
- }
3813
- ],
3814
- examples: [
3815
- { command: 'claude-flow hooks session-start --auto-configure true', description: 'Start session (v2 compat)' },
3816
- ],
3817
- action: async (ctx) => {
3818
- // Map to session-restore for backward compatibility
3819
- if (sessionRestoreCommand.action) {
3820
- const result = await sessionRestoreCommand.action(ctx);
3821
- return result || { success: true };
3822
- }
3823
- return { success: true };
3824
- }
3825
- };
3826
- // Pre-bash alias for pre-command (v2 compat)
3827
- const preBashCommand = {
3828
- name: 'pre-bash',
3829
- description: '(ALIAS) Same as pre-command',
3830
- options: preCommandCommand.options,
3831
- examples: preCommandCommand.examples,
3832
- action: preCommandCommand.action
3833
- };
3834
- // Post-bash alias for post-command (v2 compat)
3835
- const postBashCommand = {
3836
- name: 'post-bash',
3837
- description: '(ALIAS) Same as post-command',
3838
- options: postCommandCommand.options,
3839
- examples: postCommandCommand.examples,
3840
- action: postCommandCommand.action
3841
- };
3842
- // Token Optimizer command - integrates agentic-flow Agent Booster
3843
- const tokenOptimizeCommand = {
3844
- name: 'token-optimize',
3845
- description: 'Token optimization via agentic-flow Agent Booster integration',
3846
- options: [
3847
- { name: 'query', short: 'q', type: 'string', description: 'Query for compact context retrieval' },
3848
- { name: 'agents', short: 'A', type: 'number', description: 'Agent count for optimal config', default: '6' },
3849
- { name: 'report', short: 'r', type: 'boolean', description: 'Generate optimization report' },
3850
- { name: 'stats', short: 's', type: 'boolean', description: 'Show token savings statistics' },
3851
- ],
3852
- examples: [
3853
- { command: 'claude-flow hooks token-optimize --stats', description: 'Show token savings stats' },
3854
- { command: 'claude-flow hooks token-optimize -q "auth patterns"', description: 'Get compact context' },
3855
- { command: 'claude-flow hooks token-optimize -A 8 --report', description: 'Config for 8 agents + report' },
3856
- ],
3857
- action: async (ctx) => {
3858
- const query = ctx.flags['query'];
3859
- const agentCount = parseInt(ctx.flags['agents'] || '6', 10);
3860
- const showReport = ctx.flags['report'];
3861
- const showStats = ctx.flags['stats'];
3862
- const spinner = output.createSpinner({ text: 'Checking agentic-flow integration...', spinner: 'dots' });
3863
- spinner.start();
3864
- // Inline TokenOptimizer (self-contained, no external imports)
3865
- const stats = {
3866
- totalTokensSaved: 0,
3867
- editsOptimized: 0,
3868
- cacheHits: 0,
3869
- cacheMisses: 0,
3870
- memoriesRetrieved: 0,
3871
- };
3872
- let agenticFlowAvailable = false;
3873
- let reasoningBank = null;
3874
- try {
3875
- // Check if agentic-flow v3 is available
3876
- const rb = await import('agentic-flow/reasoningbank').catch(() => null);
3877
- if (rb) {
3878
- agenticFlowAvailable = true;
3879
- if (typeof rb.retrieveMemories === 'function') {
3880
- reasoningBank = rb;
3881
- }
3882
- }
3883
- else {
3884
- // Legacy check for older agentic-flow
3885
- const af = await import('agentic-flow').catch(() => null);
3886
- if (af)
3887
- agenticFlowAvailable = true;
3888
- }
3889
- const versionLabel = agenticFlowAvailable ? `agentic-flow v3 detected (ReasoningBank: ${reasoningBank ? 'active' : 'unavailable'})` : 'agentic-flow not available (using fallbacks)';
3890
- spinner.succeed(versionLabel);
3891
- output.writeln();
3892
- // Anti-drift config (hardcoded optimal values from research)
3893
- const config = {
3894
- batchSize: 4,
3895
- cacheSizeMB: 50,
3896
- topology: 'hierarchical',
3897
- expectedSuccessRate: 0.95,
3898
- };
3899
- output.printBox(`Anti-Drift Swarm Config\n\n` +
3900
- `Agents: ${agentCount}\n` +
3901
- `Topology: ${config.topology}\n` +
3902
- `Batch Size: ${config.batchSize}\n` +
3903
- `Cache: ${config.cacheSizeMB}MB\n` +
3904
- `Success Rate: ${(config.expectedSuccessRate * 100)}%`);
3905
- // If query provided, get compact context via ReasoningBank
3906
- if (query && reasoningBank) {
3907
- output.writeln();
3908
- output.printInfo(`Retrieving compact context for: "${query}"`);
3909
- const memories = await reasoningBank.retrieveMemories(query, { k: 5 });
3910
- const compactPrompt = reasoningBank.formatMemoriesForPrompt ? reasoningBank.formatMemoriesForPrompt(memories) : '';
3911
- // Estimate based on actual query vs compact prompt size difference
3912
- const queryTokenEstimate = Math.ceil((query?.length || 0) / 4);
3913
- const used = Math.ceil((compactPrompt?.length || 0) / 4);
3914
- const tokensSaved = Math.max(0, queryTokenEstimate - used);
3915
- stats.totalTokensSaved += tokensSaved;
3916
- stats.memoriesRetrieved += Array.isArray(memories) ? memories.length : 0;
3917
- output.writeln(` Memories found: ${Array.isArray(memories) ? memories.length : 0}`);
3918
- output.writeln(` Tokens saved: ${output.success(String(tokensSaved))}`);
3919
- if (compactPrompt) {
3920
- output.writeln(` Compact prompt (${compactPrompt.length} chars)`);
3921
- }
3922
- }
3923
- else if (query) {
3924
- output.writeln();
3925
- output.printInfo('ReasoningBank not available - query skipped');
3926
- }
3927
- // Note: stats reflect only actual measured values from this session.
3928
- // No simulated/fabricated data is added.
3929
- // Show stats
3930
- if (showStats || showReport) {
3931
- output.writeln();
3932
- const total = stats.cacheHits + stats.cacheMisses;
3933
- const hitRate = total > 0 ? (stats.cacheHits / total * 100).toFixed(1) : '0';
3934
- const savings = (stats.totalTokensSaved / 1000 * 0.01).toFixed(2);
3935
- output.printTable({
3936
- columns: [
3937
- { key: 'metric', header: 'Metric', width: 25 },
3938
- { key: 'value', header: 'Value', width: 20 },
3939
- ],
3940
- data: [
3941
- { metric: 'Tokens Saved', value: stats.totalTokensSaved.toLocaleString() },
3942
- { metric: 'Edits Optimized', value: String(stats.editsOptimized) },
3943
- { metric: 'Cache Hit Rate', value: `${hitRate}%` },
3944
- { metric: 'Memories Retrieved', value: String(stats.memoriesRetrieved) },
3945
- { metric: 'Est. Monthly Savings', value: `$${savings}` },
3946
- { metric: 'Agentic-Flow Active', value: agenticFlowAvailable ? '✓' : '✗' },
3947
- ],
3948
- });
3949
- }
3950
- // Full report
3951
- if (showReport) {
3952
- output.writeln();
3953
- const total = stats.cacheHits + stats.cacheMisses;
3954
- const hitRate = total > 0 ? (stats.cacheHits / total * 100).toFixed(1) : '0';
3955
- const savings = (stats.totalTokensSaved / 1000 * 0.01).toFixed(2);
3956
- output.writeln(`## Token Optimization Report
3957
-
3958
- | Metric | Value |
3959
- |--------|-------|
3960
- | Tokens Saved | ${stats.totalTokensSaved.toLocaleString()} |
3961
- | Edits Optimized | ${stats.editsOptimized} |
3962
- | Cache Hit Rate | ${hitRate}% |
3963
- | Memories Retrieved | ${stats.memoriesRetrieved} |
3964
- | Est. Monthly Savings | $${savings} |
3965
- | Agentic-Flow Active | ${agenticFlowAvailable ? '✓' : '✗'} |`);
3966
- }
3967
- return { success: true, data: { config, stats: { ...stats, agenticFlowAvailable } } };
3968
- }
3969
- catch (error) {
3970
- spinner.fail('TokenOptimizer failed');
3971
- const err = error;
3972
- output.printError(`Error: ${err.message}`);
3973
- // Fallback info
3974
- output.writeln();
3975
- output.printInfo('Fallback anti-drift config:');
3976
- output.writeln(' topology: hierarchical');
3977
- output.writeln(' maxAgents: 8');
3978
- output.writeln(' strategy: specialized');
3979
- output.writeln(' batchSize: 4');
3980
- return { success: false, exitCode: 1 };
3981
- }
3982
- }
3983
- };
3984
- // Model Router command - intelligent model selection (haiku/sonnet/opus)
3985
- const modelRouteCommand = {
3986
- name: 'model-route',
3987
- description: 'Route task to optimal Claude model (haiku/sonnet/opus) based on complexity',
3988
- options: [
3989
- { name: 'task', short: 't', type: 'string', description: 'Task description to route', required: true },
3990
- { name: 'context', short: 'c', type: 'string', description: 'Additional context' },
3991
- { name: 'prefer-cost', type: 'boolean', description: 'Prefer lower cost models' },
3992
- { name: 'prefer-quality', type: 'boolean', description: 'Prefer higher quality models' },
3993
- ],
3994
- examples: [
3995
- { command: 'claude-flow hooks model-route -t "fix typo"', description: 'Route simple task (likely haiku)' },
3996
- { command: 'claude-flow hooks model-route -t "architect auth system"', description: 'Route complex task (likely opus)' },
3997
- ],
3998
- action: async (ctx) => {
3999
- const task = ctx.flags.task || ctx.args[0];
4000
- if (!task) {
4001
- output.printError('Task description required. Use --task or -t flag.');
4002
- return { success: false, exitCode: 1 };
4003
- }
4004
- output.printInfo(`Analyzing task complexity: ${output.highlight(task.slice(0, 50))}...`);
4005
- try {
4006
- const result = await callMCPTool('hooks_model-route', {
4007
- task,
4008
- context: ctx.flags.context,
4009
- preferCost: ctx.flags['prefer-cost'],
4010
- preferQuality: ctx.flags['prefer-quality'],
4011
- });
4012
- if (ctx.flags.format === 'json') {
4013
- output.printJson(result);
4014
- return { success: true, data: result };
4015
- }
4016
- output.writeln();
4017
- // Model icon based on selection
4018
- const modelIcons = {
4019
- haiku: '🌸',
4020
- sonnet: '📜',
4021
- opus: '🎭',
4022
- };
4023
- const model = result.model || 'sonnet';
4024
- const icon = modelIcons[model] || '🤖';
4025
- // Calculate cost savings compared to opus
4026
- const costMultipliers = { haiku: 0.04, sonnet: 0.2, opus: 1.0 };
4027
- const costSavings = model !== 'opus'
4028
- ? `${((1 - costMultipliers[model]) * 100).toFixed(0)}% vs opus`
4029
- : undefined;
4030
- // Determine complexity level
4031
- const complexityScore = typeof result.complexity === 'number' ? result.complexity : 0.5;
4032
- const complexityLevel = complexityScore > 0.7 ? 'high' : complexityScore > 0.4 ? 'medium' : 'low';
4033
- output.printBox([
4034
- `Selected Model: ${icon} ${output.bold(model.toUpperCase())}`,
4035
- `Confidence: ${(result.confidence * 100).toFixed(1)}%`,
4036
- `Complexity: ${complexityLevel} (${(complexityScore * 100).toFixed(0)}%)`,
4037
- costSavings ? `Cost Savings: ${costSavings}` : '',
4038
- ].filter(Boolean).join('\n'), 'Model Routing Result');
4039
- output.writeln();
4040
- output.writeln(output.bold('Reasoning'));
4041
- output.writeln(output.dim(result.reasoning || 'Based on task complexity analysis'));
4042
- if (result.implementation) {
4043
- output.writeln();
4044
- output.writeln(output.dim(`Implementation: ${result.implementation}`));
4045
- }
4046
- return { success: true, data: result };
4047
- }
4048
- catch (error) {
4049
- if (error instanceof MCPClientError) {
4050
- output.printError(`Model routing failed: ${error.message}`);
4051
- }
4052
- else {
4053
- output.printError(`Unexpected error: ${String(error)}`);
4054
- }
4055
- return { success: false, exitCode: 1 };
4056
- }
4057
- }
4058
- };
4059
- // Model Outcome command - record routing outcomes for learning
4060
- const modelOutcomeCommand = {
4061
- name: 'model-outcome',
4062
- description: 'Record model routing outcome for learning',
4063
- options: [
4064
- { name: 'task', short: 't', type: 'string', description: 'Task that was executed', required: true },
4065
- { name: 'model', short: 'm', type: 'string', description: 'Model that was used (haiku/sonnet/opus)', required: true },
4066
- { name: 'outcome', short: 'o', type: 'string', description: 'Outcome (success/failure/escalated)', required: true },
4067
- { name: 'quality', short: 'q', type: 'number', description: 'Quality score 0-1' },
4068
- ],
4069
- examples: [
4070
- { command: 'claude-flow hooks model-outcome -t "fix typo" -m haiku -o success', description: 'Record successful haiku task' },
4071
- { command: 'claude-flow hooks model-outcome -t "auth system" -m sonnet -o escalated', description: 'Record escalation to opus' },
4072
- ],
4073
- action: async (ctx) => {
4074
- const task = ctx.flags.task;
4075
- const model = ctx.flags.model;
4076
- const outcome = ctx.flags.outcome;
4077
- if (!task || !model || !outcome) {
4078
- output.printError('Task, model, and outcome are required.');
4079
- return { success: false, exitCode: 1 };
4080
- }
4081
- try {
4082
- const result = await callMCPTool('hooks_model-outcome', {
4083
- task,
4084
- model,
4085
- outcome,
4086
- quality: ctx.flags.quality,
4087
- });
4088
- output.printSuccess(`Outcome recorded for ${model}: ${outcome}`);
4089
- if (result.learningUpdate) {
4090
- output.writeln(output.dim(result.learningUpdate));
4091
- }
4092
- return { success: true, data: result };
4093
- }
4094
- catch (error) {
4095
- output.printError(`Failed to record outcome: ${String(error)}`);
4096
- return { success: false, exitCode: 1 };
4097
- }
4098
- }
4099
- };
4100
- // Model Stats command - view routing statistics
4101
- const modelStatsCommand = {
4102
- name: 'model-stats',
4103
- description: 'View model routing statistics and learning metrics',
4104
- options: [
4105
- { name: 'detailed', short: 'd', type: 'boolean', description: 'Show detailed breakdown' },
4106
- ],
4107
- examples: [
4108
- { command: 'claude-flow hooks model-stats', description: 'View routing stats' },
4109
- { command: 'claude-flow hooks model-stats --detailed', description: 'Show detailed breakdown' },
4110
- ],
4111
- action: async (ctx) => {
4112
- try {
4113
- const result = await callMCPTool('hooks_model-stats', {
4114
- detailed: ctx.flags.detailed,
4115
- });
4116
- if (ctx.flags.format === 'json') {
4117
- output.printJson(result);
4118
- return { success: true, data: result };
4119
- }
4120
- if (!result.available) {
4121
- output.printWarning(result.message || 'Model router not available');
4122
- return { success: true, data: result };
4123
- }
4124
- // Calculate cost savings based on model distribution
4125
- const dist = result.modelDistribution || { haiku: 0, sonnet: 0, opus: 0 };
4126
- const totalTasks = result.totalDecisions || 0;
4127
- const costMultipliers = { haiku: 0.04, sonnet: 0.2, opus: 1.0 };
4128
- let totalCost = 0;
4129
- let maxCost = totalTasks; // If all were opus
4130
- for (const [model, count] of Object.entries(dist)) {
4131
- if (model !== 'inherit') {
4132
- totalCost += count * (costMultipliers[model] || 1);
4133
- }
4134
- }
4135
- const costSavings = maxCost > 0 ? ((1 - totalCost / maxCost) * 100).toFixed(1) : '0';
4136
- output.writeln();
4137
- output.printBox([
4138
- `Total Tasks Routed: ${totalTasks}`,
4139
- `Avg Complexity: ${((result.avgComplexity || 0) * 100).toFixed(1)}%`,
4140
- `Avg Confidence: ${((result.avgConfidence || 0) * 100).toFixed(1)}%`,
4141
- `Cost Savings: ${costSavings}% vs all-opus`,
4142
- `Circuit Breaker Trips: ${result.circuitBreakerTrips || 0}`,
4143
- ].join('\n'), 'Model Routing Statistics');
4144
- if (dist && Object.keys(dist).length > 0) {
4145
- output.writeln();
4146
- output.writeln(output.bold('Model Distribution'));
4147
- output.printTable({
4148
- columns: [
4149
- { key: 'model', header: 'Model', width: 10 },
4150
- { key: 'count', header: 'Tasks', width: 8, align: 'right' },
4151
- { key: 'percentage', header: '%', width: 8, align: 'right' },
4152
- { key: 'costMultiplier', header: 'Cost', width: 8, align: 'right' },
4153
- ],
4154
- data: Object.entries(dist)
4155
- .filter(([model]) => model !== 'inherit')
4156
- .map(([model, count]) => ({
4157
- model: model.toUpperCase(),
4158
- count,
4159
- percentage: totalTasks > 0 ? `${((count / totalTasks) * 100).toFixed(1)}%` : '0%',
4160
- costMultiplier: `${costMultipliers[model] || 1}x`,
4161
- })),
4162
- });
4163
- }
4164
- return { success: true, data: result };
4165
- }
4166
- catch (error) {
4167
- output.printError(`Failed to get stats: ${String(error)}`);
4168
- return { success: false, exitCode: 1 };
4169
- }
4170
- }
4171
- };
4172
- // Teammate Idle command - Agent Teams integration
4173
- const teammateIdleCommand = {
4174
- name: 'teammate-idle',
4175
- description: 'Handle idle teammate in Agent Teams - auto-assign tasks or notify lead',
4176
- options: [
4177
- {
4178
- name: 'auto-assign',
4179
- short: 'a',
4180
- description: 'Automatically assign pending tasks to idle teammate',
4181
- type: 'boolean',
4182
- default: true
4183
- },
4184
- {
4185
- name: 'check-task-list',
4186
- short: 'c',
4187
- description: 'Check shared task list for available work',
4188
- type: 'boolean',
4189
- default: true
4190
- },
4191
- {
4192
- name: 'teammate-id',
4193
- short: 't',
4194
- description: 'ID of the idle teammate',
4195
- type: 'string'
4196
- },
4197
- {
4198
- name: 'team-name',
4199
- description: 'Team name for context',
4200
- type: 'string'
4201
- }
4202
- ],
4203
- examples: [
4204
- { command: 'claude-flow hooks teammate-idle --auto-assign true', description: 'Auto-assign tasks to idle teammate' },
4205
- { command: 'claude-flow hooks teammate-idle -t worker-1 --check-task-list', description: 'Check tasks for specific teammate' }
4206
- ],
4207
- action: async (ctx) => {
4208
- const autoAssign = ctx.flags.autoAssign !== false;
4209
- const checkTaskList = ctx.flags.checkTaskList !== false;
4210
- const teammateId = ctx.flags.teammateId;
4211
- const teamName = ctx.flags.teamName;
4212
- if (ctx.flags.format !== 'json') {
4213
- output.printInfo(`Teammate idle hook triggered${teammateId ? ` for: ${output.highlight(teammateId)}` : ''}`);
4214
- }
4215
- try {
4216
- const result = await callMCPTool('hooks_teammate-idle', {
4217
- autoAssign,
4218
- checkTaskList,
4219
- teammateId,
4220
- teamName,
4221
- timestamp: Date.now(),
4222
- });
4223
- if (ctx.flags.format === 'json') {
4224
- output.printJson(result);
4225
- return { success: true, data: result };
4226
- }
4227
- output.writeln();
4228
- if (result.action === 'assigned' && result.taskAssigned) {
4229
- output.printSuccess(`Task assigned: ${result.taskAssigned.subject}`);
4230
- output.printList([
4231
- `Task ID: ${result.taskAssigned.taskId}`,
4232
- `Priority: ${result.taskAssigned.priority}`,
4233
- `Pending tasks remaining: ${result.pendingTasks}`
4234
- ]);
4235
- }
4236
- else if (result.action === 'waiting') {
4237
- output.printInfo('No pending tasks available - teammate waiting for work');
4238
- }
4239
- else {
4240
- output.printInfo(`Team lead notified: ${result.message}`);
4241
- }
4242
- return { success: true, data: result };
4243
- }
4244
- catch (error) {
4245
- // Graceful fallback - don't fail hard, just report
4246
- if (ctx.flags.format === 'json') {
4247
- output.printJson({ success: true, action: 'waiting', message: 'Teammate idle - no MCP server' });
4248
- }
4249
- else {
4250
- output.printInfo('Teammate idle - awaiting task assignment');
4251
- }
4252
- return { success: true };
4253
- }
4254
- }
4255
- };
4256
- // Task Completed command - Agent Teams integration
4257
- const taskCompletedCommand = {
4258
- name: 'task-completed',
4259
- description: 'Handle task completion in Agent Teams - train patterns and notify lead',
4260
- options: [
4261
- {
4262
- name: 'task-id',
4263
- short: 'i',
4264
- description: 'ID of the completed task',
4265
- type: 'string',
4266
- required: true
4267
- },
4268
- {
4269
- name: 'train-patterns',
4270
- short: 'p',
4271
- description: 'Train neural patterns from successful task',
4272
- type: 'boolean',
4273
- default: true
4274
- },
4275
- {
4276
- name: 'notify-lead',
4277
- short: 'n',
4278
- description: 'Notify team lead of task completion',
4279
- type: 'boolean',
4280
- default: true
4281
- },
4282
- {
4283
- name: 'success',
4284
- short: 's',
4285
- description: 'Whether the task succeeded',
4286
- type: 'boolean',
4287
- default: true
4288
- },
4289
- {
4290
- name: 'quality',
4291
- short: 'q',
4292
- description: 'Quality score (0-1)',
4293
- type: 'number'
4294
- },
4295
- {
4296
- name: 'teammate-id',
4297
- short: 't',
4298
- description: 'ID of the teammate that completed the task',
4299
- type: 'string'
4300
- }
4301
- ],
4302
- examples: [
4303
- { command: 'claude-flow hooks task-completed -i task-123 --train-patterns', description: 'Complete task and train patterns' },
4304
- { command: 'claude-flow hooks task-completed -i task-456 --notify-lead --quality 0.95', description: 'Complete with quality score' }
4305
- ],
4306
- action: async (ctx) => {
4307
- const taskId = ctx.flags.taskId || ctx.args[0];
4308
- const trainPatterns = ctx.flags.trainPatterns !== false;
4309
- const notifyLead = ctx.flags.notifyLead !== false;
4310
- const success = ctx.flags.success !== false;
4311
- const quality = ctx.flags.quality;
4312
- const teammateId = ctx.flags.teammateId;
4313
- if (!taskId) {
4314
- output.printError('Task ID is required. Use --task-id or -i flag.');
4315
- return { success: false, exitCode: 1 };
4316
- }
4317
- if (ctx.flags.format !== 'json') {
4318
- output.printInfo(`Task completed: ${output.highlight(taskId)}`);
4319
- }
4320
- try {
4321
- const result = await callMCPTool('hooks_task-completed', {
4322
- taskId,
4323
- trainPatterns,
4324
- notifyLead,
4325
- success,
4326
- quality,
4327
- teammateId,
4328
- timestamp: Date.now(),
4329
- });
4330
- if (ctx.flags.format === 'json') {
4331
- output.printJson(result);
4332
- return { success: true, data: result };
4333
- }
4334
- output.writeln();
4335
- output.printSuccess(`Task ${taskId} marked complete`);
4336
- output.writeln();
4337
- output.writeln(output.bold('Completion Metrics'));
4338
- output.printTable({
4339
- columns: [
4340
- { key: 'metric', header: 'Metric', width: 25 },
4341
- { key: 'value', header: 'Value', width: 20, align: 'right' }
4342
- ],
4343
- data: [
4344
- { metric: 'Patterns Learned', value: result.patternsLearned },
4345
- { metric: 'Quality Score', value: quality ? `${(quality * 100).toFixed(0)}%` : 'N/A' },
4346
- { metric: 'Lead Notified', value: result.leadNotified ? 'Yes' : 'No' },
4347
- { metric: 'Learning Updates', value: result.metrics?.learningUpdates || 0 }
4348
- ]
4349
- });
4350
- if (result.nextTask) {
4351
- output.writeln();
4352
- output.printInfo(`Next available task: ${result.nextTask.subject}`);
4353
- }
4354
- return { success: true, data: result };
4355
- }
4356
- catch (error) {
4357
- // Graceful fallback
4358
- if (ctx.flags.format === 'json') {
4359
- output.printJson({ success: true, taskId, message: 'Task completed - patterns pending' });
4360
- }
4361
- else {
4362
- output.printSuccess(`Task ${taskId} completed`);
4363
- if (trainPatterns) {
4364
- output.printInfo('Pattern training queued for next sync');
4365
- }
4366
- }
4367
- return { success: true };
4368
- }
4369
- }
4370
- };
4371
- // Notify subcommand
4372
- const notifyCommand = {
4373
- name: 'notify',
4374
- description: 'Send a notification message (logged to session)',
4375
- options: [
4376
- { name: 'message', short: 'm', type: 'string', description: 'Notification message', required: true },
4377
- { name: 'level', short: 'l', type: 'string', description: 'Level: info, warn, error', default: 'info' },
4378
- { name: 'channel', short: 'c', type: 'string', description: 'Notification channel', default: 'console' },
4379
- ],
4380
- examples: [
4381
- { command: 'claude-flow hooks notify -m "Build complete"', description: 'Send info notification' },
4382
- { command: 'claude-flow hooks notify -m "Test failed" -l error', description: 'Send error notification' },
4383
- ],
4384
- action: async (ctx) => {
4385
- const message = ctx.flags.message || ctx.args[0];
4386
- const level = ctx.flags.level || 'info';
4387
- if (!message) {
4388
- output.printError('Message is required: --message "your message"');
4389
- return { success: false, exitCode: 1 };
4390
- }
4391
- const timestamp = new Date().toISOString();
4392
- if (level === 'error') {
4393
- output.printError(`[${timestamp}] ${message}`);
4394
- }
4395
- else if (level === 'warn') {
4396
- output.writeln(output.warning(`[${timestamp}] ${message}`));
4397
- }
4398
- else {
4399
- output.printInfo(`[${timestamp}] ${message}`);
4400
- }
4401
- // Store notification in memory if available
4402
- try {
4403
- const { storeEntry } = await import('../memory/memory-initializer.js');
4404
- await storeEntry({ key: `notify-${Date.now()}`, value: `[${level}] ${message}`, namespace: 'notifications' });
4405
- }
4406
- catch { /* memory not available */ }
4407
- return { success: true, data: { timestamp, level, message } };
4408
- }
4409
- };
4410
- // Refresh-funnel subcommand — the fix for "promo doesn't load right away".
4411
- //
4412
- // refreshRemoteMessages() (funnel/message-transport.ts) is fire-and-forget
4413
- // by design so the STATUSLINE's own per-render invocation never blocks on
4414
- // a network call. But the statusline is spawned as a short-lived subprocess
4415
- // per render (execSync from statusline-generator.ts) — a fire-and-forget
4416
- // promise kicked off there has no "later" to run in; the process exits
4417
- // before the HTTPS fetch can complete, so the local message cache never
4418
- // actually gets written and the promo row never appears (confirmed live:
4419
- // two consecutive cold-cache statusline renders, 5s apart, both returned
4420
- // promo:null and the cache file was never created).
4421
- //
4422
- // This command exists to be invoked from a LONGER-LIVED context — the
4423
- // SessionStart hook (see hook-handler.cjs's 'session-restore' handler,
4424
- // which spawns this detached so it isn't killed when the hook's own
4425
- // process exits, and isn't awaited so it doesn't add to the hook's own
4426
- // timeout budget). One real, properly-awaited refresh attempt here, once
4427
- // per session, is what actually gives refreshRemoteMessages() a chance to
4428
- // finish before anything needs the cache.
4429
- const refreshFunnelCommand = {
4430
- name: 'refresh-funnel',
4431
- description: 'Best-effort background refresh of the funnel message cache (internal — see hook-handler.cjs session-restore)',
4432
- options: [
4433
- { name: 'quiet', description: 'Suppress output (used when spawned detached from a hook)', type: 'boolean', default: false },
4434
- ],
4435
- action: async (ctx) => {
4436
- try {
4437
- const { refreshRemoteMessages } = await import('../funnel/index.js');
4438
- const result = await refreshRemoteMessages();
4439
- if (!ctx.flags.quiet) {
4440
- output.writeln(JSON.stringify(result));
4441
- }
4442
- return { success: true, data: result };
4443
- }
4444
- catch (error) {
4445
- // Fail silent by design (matches message-transport.ts's own "fail
4446
- // silent" discipline) — a broken refresh must never surface as a
4447
- // hook error, only ever as "no promo this session."
4448
- if (!ctx.flags.quiet) {
4449
- output.printError(`refresh-funnel failed: ${error instanceof Error ? error.message : String(error)}`);
4450
- }
4451
- return { success: true, data: { refreshed: false, skipped: 'error' } };
4452
- }
4453
- }
4454
- };
4455
- // Refresh-advisor subcommand — ADR-316's co-pilot tip. Mirrors
4456
- // refreshFunnelCommand exactly: a properly-awaited CLI subcommand meant to
4457
- // be spawned DETACHED from hook-handler.cjs's session-restore handler, so a
4458
- // real (potentially multi-second, real-money) `claude -p` call gets a
4459
- // chance to finish without ever blocking or being awaited by the hook's own
4460
- // process. refreshAdvisorTipIfStale() itself is the safety net that makes
4461
- // this cheap to call on every session-restore: it checks consent + a 24h
4462
- // TTL BEFORE spending anything, so most invocations are a no-op file read.
4463
- const refreshAdvisorCommand = {
4464
- name: 'refresh-advisor',
4465
- description: 'Best-effort background refresh of the co-pilot advisor tip (internal — see hook-handler.cjs session-restore; ADR-316)',
4466
- options: [
4467
- { name: 'quiet', description: 'Suppress output (used when spawned detached from a hook)', type: 'boolean', default: false },
4468
- ],
4469
- action: async (ctx) => {
4470
- try {
4471
- const { refreshAdvisorTipIfStale } = await import('../funnel/advisor-tip.js');
4472
- const { getSecurityStatus, getSwarmStatus, getGitUncommittedCount } = await import('../funnel/local-signals.js');
4473
- const result = await refreshAdvisorTipIfStale({
4474
- security: getSecurityStatus(),
4475
- swarm: getSwarmStatus(),
4476
- gitUncommittedCount: getGitUncommittedCount(),
4477
- });
4478
- if (!ctx.flags.quiet) {
4479
- output.writeln(JSON.stringify(result));
4480
- }
4481
- return { success: true, data: result };
4482
- }
4483
- catch (error) {
4484
- // Fail silent by design (matches refresh-funnel's own discipline) — a
4485
- // broken advisor refresh must never surface as a hook error, only
4486
- // ever as "no tip this window."
4487
- if (!ctx.flags.quiet) {
4488
- output.printError(`refresh-advisor failed: ${error instanceof Error ? error.message : String(error)}`);
4489
- }
4490
- return { success: true, data: { refreshed: false, reason: 'error' } };
4491
- }
4492
- }
4493
- };
4494
- // Main hooks command
4495
- export const hooksCommand = {
4496
- name: 'hooks',
4497
- description: 'Self-learning hooks system for intelligent workflow automation',
4498
- subcommands: [
4499
- preEditCommand,
4500
- postEditCommand,
4501
- preCommandCommand,
4502
- postCommandCommand,
4503
- preTaskCommand,
4504
- postTaskCommand,
4505
- sessionEndCommand,
4506
- sessionRestoreCommand,
4507
- routeCommand,
4508
- explainCommand,
4509
- pretrainCommand,
4510
- buildAgentsCommand,
4511
- metricsCommand,
4512
- transferCommand,
4513
- listCommand,
4514
- intelligenceCommand,
4515
- notifyCommand,
4516
- workerCommand,
4517
- progressHookCommand,
4518
- statuslineCommand,
4519
- // Coverage-aware routing commands
4520
- coverageRouteCommand,
4521
- coverageSuggestCommand,
4522
- coverageGapsCommand,
4523
- // Token optimization
4524
- tokenOptimizeCommand,
4525
- // Model routing (tiny-dancer integration)
4526
- modelRouteCommand,
4527
- modelOutcomeCommand,
4528
- modelStatsCommand,
4529
- // Backward-compatible aliases for v2
4530
- routeTaskCommand,
4531
- sessionStartCommand,
4532
- preBashCommand,
4533
- postBashCommand,
4534
- // Agent Teams integration
4535
- teammateIdleCommand,
4536
- taskCompletedCommand,
4537
- // Funnel background refresh — see refreshFunnelCommand's own doc comment
4538
- refreshFunnelCommand,
4539
- // Advisor co-pilot tip background refresh — ADR-316
4540
- refreshAdvisorCommand,
4541
- ],
4542
- options: [],
4543
- examples: [
4544
- { command: 'claude-flow hooks pre-edit -f src/utils.ts', description: 'Get context before editing' },
4545
- { command: 'claude-flow hooks route -t "Fix authentication bug"', description: 'Route task to optimal agent' },
4546
- { command: 'claude-flow hooks pretrain', description: 'Bootstrap intelligence from repository' },
4547
- { command: 'claude-flow hooks metrics --v3-dashboard', description: 'View V3 performance metrics' }
4548
- ],
4549
- action: async (ctx) => {
4550
- output.writeln();
4551
- output.writeln(output.bold('Self-Learning Hooks System'));
4552
- output.writeln();
4553
- output.writeln('Intelligent workflow automation with pattern learning and adaptive routing');
4554
- output.writeln();
4555
- output.writeln('Usage: claude-flow hooks <subcommand> [options]');
4556
- output.writeln();
4557
- output.writeln('Subcommands:');
4558
- output.printList([
4559
- `${output.highlight('pre-edit')} - Get context before editing files`,
4560
- `${output.highlight('post-edit')} - Record editing outcomes for learning`,
4561
- `${output.highlight('pre-command')} - Assess risk before executing commands`,
4562
- `${output.highlight('post-command')} - Record command execution outcomes`,
4563
- `${output.highlight('pre-task')} - Record task start and get agent suggestions`,
4564
- `${output.highlight('post-task')} - Record task completion for learning`,
4565
- `${output.highlight('session-end')} - End current session and persist state`,
4566
- `${output.highlight('session-restore')} - Restore a previous session`,
4567
- `${output.highlight('route')} - Route tasks to optimal agents`,
4568
- `${output.highlight('explain')} - Explain routing decisions`,
4569
- `${output.highlight('pretrain')} - Bootstrap intelligence from repository`,
4570
- `${output.highlight('build-agents')} - Generate optimized agent configs`,
4571
- `${output.highlight('metrics')} - View learning metrics dashboard`,
4572
- `${output.highlight('transfer')} - Transfer patterns from another project`,
4573
- `${output.highlight('list')} - List all registered hooks`,
4574
- `${output.highlight('worker')} - Background worker management (12 workers)`,
4575
- `${output.highlight('progress')} - Check V3 implementation progress`,
4576
- `${output.highlight('statusline')} - Generate dynamic statusline display`,
4577
- `${output.highlight('coverage-route')} - Route tasks based on coverage gaps (ruvector)`,
4578
- `${output.highlight('coverage-suggest')}- Suggest coverage improvements`,
4579
- `${output.highlight('coverage-gaps')} - List all coverage gaps with agents`,
4580
- `${output.highlight('token-optimize')} - Token optimization (agentic-flow integration)`,
4581
- `${output.highlight('model-route')} - Route to optimal model (haiku/sonnet/opus)`,
4582
- `${output.highlight('model-outcome')} - Record model routing outcome`,
4583
- `${output.highlight('model-stats')} - View model routing statistics`,
4584
- '',
4585
- output.bold('Agent Teams:'),
4586
- `${output.highlight('teammate-idle')} - Handle idle teammate (auto-assign tasks)`,
4587
- `${output.highlight('task-completed')} - Handle task completion (train patterns)`
4588
- ]);
4589
- output.writeln();
4590
- output.writeln('Run "claude-flow hooks <subcommand> --help" for subcommand help');
4591
- output.writeln();
4592
- output.writeln(output.bold('V3 Features:'));
4593
- output.printList([
4594
- '🧠 ReasoningBank adaptive learning',
4595
- '⚡ Flash Attention (2.49x-7.47x speedup)',
4596
- '🔍 AgentDB integration (150x faster search)',
4597
- '📊 84.8% SWE-Bench solve rate',
4598
- '🎯 32.3% token reduction',
4599
- '🚀 2.8-4.4x speed improvement',
4600
- '👥 Agent Teams integration (auto task assignment)'
4601
- ]);
4602
- return { success: true };
4603
- }
4604
- };
4605
- export default hooksCommand;
4606
- //# sourceMappingURL=hooks.js.map