@claude-flow/cli 3.32.1 → 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 (657) hide show
  1. package/.claude/helpers/.helpers-version +1 -1
  2. package/.claude/helpers/helpers.manifest.json +3 -3
  3. package/.claude/helpers/statusline.cjs +24 -17
  4. package/.claude/helpers/statusline.js +19 -31
  5. package/catalog-manifest.json +2 -2
  6. package/package.json +1 -1
  7. package/plugins/ruflo-metaharness/.claude-plugin/plugin.json +1 -1
  8. package/plugins/ruflo-metaharness/scripts/smoke.sh +8 -5
  9. package/plugins/ruflo-metaharness/skills/harness-similarity/SKILL.md +1 -1
  10. package/dist/src/agenticow/speculative-exploration.d.ts +0 -148
  11. package/dist/src/agenticow/speculative-exploration.js +0 -218
  12. package/dist/src/appliance/gguf-engine.d.ts +0 -91
  13. package/dist/src/appliance/gguf-engine.js +0 -425
  14. package/dist/src/appliance/ruvllm-bridge.d.ts +0 -102
  15. package/dist/src/appliance/ruvllm-bridge.js +0 -292
  16. package/dist/src/appliance/rvfa-builder.d.ts +0 -44
  17. package/dist/src/appliance/rvfa-builder.js +0 -329
  18. package/dist/src/appliance/rvfa-distribution.d.ts +0 -97
  19. package/dist/src/appliance/rvfa-distribution.js +0 -370
  20. package/dist/src/appliance/rvfa-format.d.ts +0 -111
  21. package/dist/src/appliance/rvfa-format.js +0 -393
  22. package/dist/src/appliance/rvfa-runner.d.ts +0 -69
  23. package/dist/src/appliance/rvfa-runner.js +0 -237
  24. package/dist/src/appliance/rvfa-signing.d.ts +0 -123
  25. package/dist/src/appliance/rvfa-signing.js +0 -347
  26. package/dist/src/autopilot-state.d.ts +0 -77
  27. package/dist/src/autopilot-state.js +0 -271
  28. package/dist/src/benchmarks/gaia-agent-planning.smoke.d.ts +0 -18
  29. package/dist/src/benchmarks/gaia-agent-planning.smoke.js +0 -253
  30. package/dist/src/benchmarks/gaia-agent.d.ts +0 -198
  31. package/dist/src/benchmarks/gaia-agent.js +0 -651
  32. package/dist/src/benchmarks/gaia-causal-memory.d.ts +0 -133
  33. package/dist/src/benchmarks/gaia-causal-memory.js +0 -281
  34. package/dist/src/benchmarks/gaia-causal-memory.smoke.d.ts +0 -22
  35. package/dist/src/benchmarks/gaia-causal-memory.smoke.js +0 -300
  36. package/dist/src/benchmarks/gaia-convergence.d.ts +0 -138
  37. package/dist/src/benchmarks/gaia-convergence.js +0 -260
  38. package/dist/src/benchmarks/gaia-convergence.smoke.d.ts +0 -19
  39. package/dist/src/benchmarks/gaia-convergence.smoke.js +0 -246
  40. package/dist/src/benchmarks/gaia-critic.d.ts +0 -123
  41. package/dist/src/benchmarks/gaia-critic.js +0 -312
  42. package/dist/src/benchmarks/gaia-critic.smoke.d.ts +0 -21
  43. package/dist/src/benchmarks/gaia-critic.smoke.js +0 -327
  44. package/dist/src/benchmarks/gaia-decomposer.d.ts +0 -125
  45. package/dist/src/benchmarks/gaia-decomposer.js +0 -350
  46. package/dist/src/benchmarks/gaia-decomposer.smoke.d.ts +0 -21
  47. package/dist/src/benchmarks/gaia-decomposer.smoke.js +0 -228
  48. package/dist/src/benchmarks/gaia-e2e-smoke.d.ts +0 -27
  49. package/dist/src/benchmarks/gaia-e2e-smoke.js +0 -136
  50. package/dist/src/benchmarks/gaia-extract.smoke.d.ts +0 -45
  51. package/dist/src/benchmarks/gaia-extract.smoke.js +0 -242
  52. package/dist/src/benchmarks/gaia-hardness/features.d.ts +0 -46
  53. package/dist/src/benchmarks/gaia-hardness/features.js +0 -170
  54. package/dist/src/benchmarks/gaia-hardness/predictor.d.ts +0 -105
  55. package/dist/src/benchmarks/gaia-hardness/predictor.js +0 -260
  56. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.d.ts +0 -20
  57. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.js +0 -235
  58. package/dist/src/benchmarks/gaia-hardness/train-data-loader.d.ts +0 -51
  59. package/dist/src/benchmarks/gaia-hardness/train-data-loader.js +0 -179
  60. package/dist/src/benchmarks/gaia-judge.d.ts +0 -88
  61. package/dist/src/benchmarks/gaia-judge.js +0 -437
  62. package/dist/src/benchmarks/gaia-loader.d.ts +0 -87
  63. package/dist/src/benchmarks/gaia-loader.js +0 -326
  64. package/dist/src/benchmarks/gaia-tools/file_read.d.ts +0 -35
  65. package/dist/src/benchmarks/gaia-tools/file_read.js +0 -403
  66. package/dist/src/benchmarks/gaia-tools/grounded_query.d.ts +0 -126
  67. package/dist/src/benchmarks/gaia-tools/grounded_query.js +0 -225
  68. package/dist/src/benchmarks/gaia-tools/index.d.ts +0 -32
  69. package/dist/src/benchmarks/gaia-tools/index.js +0 -36
  70. package/dist/src/benchmarks/gaia-tools/types.d.ts +0 -62
  71. package/dist/src/benchmarks/gaia-tools/types.js +0 -12
  72. package/dist/src/benchmarks/gaia-tools/web_search.d.ts +0 -30
  73. package/dist/src/benchmarks/gaia-tools/web_search.js +0 -210
  74. package/dist/src/benchmarks/gaia-voting.d.ts +0 -88
  75. package/dist/src/benchmarks/gaia-voting.js +0 -297
  76. package/dist/src/benchmarks/gaia-voting.smoke.d.ts +0 -20
  77. package/dist/src/benchmarks/gaia-voting.smoke.js +0 -332
  78. package/dist/src/benchmarks/pretrain/index.d.ts +0 -58
  79. package/dist/src/benchmarks/pretrain/index.js +0 -404
  80. package/dist/src/business-pods/bbs-budget-tracker.d.ts +0 -139
  81. package/dist/src/business-pods/bbs-budget-tracker.js +0 -358
  82. package/dist/src/business-pods/domain-affinity-policy.d.ts +0 -47
  83. package/dist/src/business-pods/domain-affinity-policy.js +0 -65
  84. package/dist/src/business-pods/pod-schema.d.ts +0 -96
  85. package/dist/src/business-pods/pod-schema.js +0 -225
  86. package/dist/src/commands/advisor.d.ts +0 -15
  87. package/dist/src/commands/advisor.js +0 -94
  88. package/dist/src/commands/agent-wasm.d.ts +0 -14
  89. package/dist/src/commands/agent-wasm.js +0 -333
  90. package/dist/src/commands/agent.d.ts +0 -8
  91. package/dist/src/commands/agent.js +0 -927
  92. package/dist/src/commands/analyze.d.ts +0 -19
  93. package/dist/src/commands/analyze.js +0 -2047
  94. package/dist/src/commands/announcements.d.ts +0 -17
  95. package/dist/src/commands/announcements.js +0 -0
  96. package/dist/src/commands/appliance-advanced.d.ts +0 -9
  97. package/dist/src/commands/appliance-advanced.js +0 -215
  98. package/dist/src/commands/appliance.d.ts +0 -8
  99. package/dist/src/commands/appliance.js +0 -404
  100. package/dist/src/commands/autopilot.d.ts +0 -15
  101. package/dist/src/commands/autopilot.js +0 -407
  102. package/dist/src/commands/benchmark.d.ts +0 -10
  103. package/dist/src/commands/benchmark.js +0 -460
  104. package/dist/src/commands/claims.d.ts +0 -10
  105. package/dist/src/commands/claims.js +0 -620
  106. package/dist/src/commands/cleanup.d.ts +0 -13
  107. package/dist/src/commands/cleanup.js +0 -250
  108. package/dist/src/commands/completions.d.ts +0 -10
  109. package/dist/src/commands/completions.js +0 -539
  110. package/dist/src/commands/config.d.ts +0 -8
  111. package/dist/src/commands/config.js +0 -428
  112. package/dist/src/commands/daemon.d.ts +0 -59
  113. package/dist/src/commands/daemon.js +0 -1733
  114. package/dist/src/commands/deployment.d.ts +0 -10
  115. package/dist/src/commands/deployment.js +0 -672
  116. package/dist/src/commands/doctor.d.ts +0 -10
  117. package/dist/src/commands/doctor.js +0 -1695
  118. package/dist/src/commands/eject.d.ts +0 -33
  119. package/dist/src/commands/eject.js +0 -195
  120. package/dist/src/commands/embeddings.d.ts +0 -18
  121. package/dist/src/commands/embeddings.js +0 -1623
  122. package/dist/src/commands/funnel.d.ts +0 -18
  123. package/dist/src/commands/funnel.js +0 -302
  124. package/dist/src/commands/gaia-bench.d.ts +0 -40
  125. package/dist/src/commands/gaia-bench.js +0 -597
  126. package/dist/src/commands/guidance.d.ts +0 -8
  127. package/dist/src/commands/guidance.js +0 -556
  128. package/dist/src/commands/hive-mind.d.ts +0 -11
  129. package/dist/src/commands/hive-mind.js +0 -1319
  130. package/dist/src/commands/hooks.d.ts +0 -8
  131. package/dist/src/commands/hooks.js +0 -4595
  132. package/dist/src/commands/index.d.ts +0 -118
  133. package/dist/src/commands/index.js +0 -364
  134. package/dist/src/commands/init.d.ts +0 -13
  135. package/dist/src/commands/init.js +0 -1297
  136. package/dist/src/commands/issues.d.ts +0 -21
  137. package/dist/src/commands/issues.js +0 -567
  138. package/dist/src/commands/mcp.d.ts +0 -11
  139. package/dist/src/commands/mcp.js +0 -732
  140. package/dist/src/commands/memory-backup.d.ts +0 -11
  141. package/dist/src/commands/memory-backup.js +0 -46
  142. package/dist/src/commands/memory-distill.d.ts +0 -27
  143. package/dist/src/commands/memory-distill.js +0 -374
  144. package/dist/src/commands/memory.d.ts +0 -8
  145. package/dist/src/commands/memory.js +0 -1596
  146. package/dist/src/commands/metaharness.d.ts +0 -39
  147. package/dist/src/commands/metaharness.js +0 -215
  148. package/dist/src/commands/migrate.d.ts +0 -8
  149. package/dist/src/commands/migrate.js +0 -742
  150. package/dist/src/commands/neural.d.ts +0 -10
  151. package/dist/src/commands/neural.js +0 -4331
  152. package/dist/src/commands/performance.d.ts +0 -10
  153. package/dist/src/commands/performance.js +0 -583
  154. package/dist/src/commands/plugins.d.ts +0 -11
  155. package/dist/src/commands/plugins.js +0 -826
  156. package/dist/src/commands/process.d.ts +0 -10
  157. package/dist/src/commands/process.js +0 -694
  158. package/dist/src/commands/progress.d.ts +0 -11
  159. package/dist/src/commands/progress.js +0 -259
  160. package/dist/src/commands/providers.d.ts +0 -10
  161. package/dist/src/commands/providers.js +0 -502
  162. package/dist/src/commands/proxy.d.ts +0 -21
  163. package/dist/src/commands/proxy.js +0 -310
  164. package/dist/src/commands/route.d.ts +0 -16
  165. package/dist/src/commands/route.js +0 -822
  166. package/dist/src/commands/ruvector/backup.d.ts +0 -11
  167. package/dist/src/commands/ruvector/backup.js +0 -747
  168. package/dist/src/commands/ruvector/benchmark.d.ts +0 -11
  169. package/dist/src/commands/ruvector/benchmark.js +0 -490
  170. package/dist/src/commands/ruvector/import.d.ts +0 -18
  171. package/dist/src/commands/ruvector/import.js +0 -373
  172. package/dist/src/commands/ruvector/index.d.ts +0 -29
  173. package/dist/src/commands/ruvector/index.js +0 -129
  174. package/dist/src/commands/ruvector/init.d.ts +0 -11
  175. package/dist/src/commands/ruvector/init.js +0 -467
  176. package/dist/src/commands/ruvector/migrate.d.ts +0 -11
  177. package/dist/src/commands/ruvector/migrate.js +0 -498
  178. package/dist/src/commands/ruvector/optimize.d.ts +0 -11
  179. package/dist/src/commands/ruvector/optimize.js +0 -505
  180. package/dist/src/commands/ruvector/pg-utils.d.ts +0 -14
  181. package/dist/src/commands/ruvector/pg-utils.js +0 -41
  182. package/dist/src/commands/ruvector/setup.d.ts +0 -18
  183. package/dist/src/commands/ruvector/setup.js +0 -765
  184. package/dist/src/commands/ruvector/status.d.ts +0 -11
  185. package/dist/src/commands/ruvector/status.js +0 -479
  186. package/dist/src/commands/security.d.ts +0 -10
  187. package/dist/src/commands/security.js +0 -1007
  188. package/dist/src/commands/session.d.ts +0 -8
  189. package/dist/src/commands/session.js +0 -757
  190. package/dist/src/commands/settings.d.ts +0 -19
  191. package/dist/src/commands/settings.js +0 -180
  192. package/dist/src/commands/spinner.d.ts +0 -16
  193. package/dist/src/commands/spinner.js +0 -329
  194. package/dist/src/commands/start.d.ts +0 -8
  195. package/dist/src/commands/start.js +0 -418
  196. package/dist/src/commands/status.d.ts +0 -8
  197. package/dist/src/commands/status.js +0 -608
  198. package/dist/src/commands/swarm.d.ts +0 -8
  199. package/dist/src/commands/swarm.js +0 -891
  200. package/dist/src/commands/task.d.ts +0 -8
  201. package/dist/src/commands/task.js +0 -675
  202. package/dist/src/commands/transfer-store.d.ts +0 -13
  203. package/dist/src/commands/transfer-store.js +0 -428
  204. package/dist/src/commands/update.d.ts +0 -8
  205. package/dist/src/commands/update.js +0 -276
  206. package/dist/src/commands/verify.d.ts +0 -19
  207. package/dist/src/commands/verify.js +0 -261
  208. package/dist/src/commands/version.d.ts +0 -42
  209. package/dist/src/commands/version.js +0 -106
  210. package/dist/src/commands/workflow.d.ts +0 -8
  211. package/dist/src/commands/workflow.js +0 -617
  212. package/dist/src/config/harness-feedback-applier.d.ts +0 -50
  213. package/dist/src/config/harness-feedback-applier.js +0 -122
  214. package/dist/src/config/proven-config-refresh.d.ts +0 -39
  215. package/dist/src/config/proven-config-refresh.js +0 -154
  216. package/dist/src/config/proven-config-rvfa.d.ts +0 -23
  217. package/dist/src/config/proven-config-rvfa.js +0 -73
  218. package/dist/src/config/proven-config.d.ts +0 -86
  219. package/dist/src/config/proven-config.js +0 -176
  220. package/dist/src/config-adapter.d.ts +0 -15
  221. package/dist/src/config-adapter.js +0 -186
  222. package/dist/src/encryption/vault.d.ts +0 -94
  223. package/dist/src/encryption/vault.js +0 -172
  224. package/dist/src/fs-secure.d.ts +0 -86
  225. package/dist/src/fs-secure.js +0 -133
  226. package/dist/src/funnel/advisor-tip.d.ts +0 -58
  227. package/dist/src/funnel/advisor-tip.js +0 -92
  228. package/dist/src/funnel/attribution.d.ts +0 -37
  229. package/dist/src/funnel/attribution.js +0 -101
  230. package/dist/src/funnel/consent.d.ts +0 -22
  231. package/dist/src/funnel/consent.js +0 -58
  232. package/dist/src/funnel/credit-errors.d.ts +0 -31
  233. package/dist/src/funnel/credit-errors.js +0 -88
  234. package/dist/src/funnel/credit-notifier.d.ts +0 -44
  235. package/dist/src/funnel/credit-notifier.js +0 -74
  236. package/dist/src/funnel/disclosure.d.ts +0 -47
  237. package/dist/src/funnel/disclosure.js +0 -109
  238. package/dist/src/funnel/enrollment.d.ts +0 -36
  239. package/dist/src/funnel/enrollment.js +0 -64
  240. package/dist/src/funnel/environment.d.ts +0 -17
  241. package/dist/src/funnel/environment.js +0 -39
  242. package/dist/src/funnel/event-transport.d.ts +0 -51
  243. package/dist/src/funnel/event-transport.js +0 -199
  244. package/dist/src/funnel/events.d.ts +0 -42
  245. package/dist/src/funnel/events.js +0 -150
  246. package/dist/src/funnel/index.d.ts +0 -21
  247. package/dist/src/funnel/index.js +0 -21
  248. package/dist/src/funnel/insights.d.ts +0 -49
  249. package/dist/src/funnel/insights.js +0 -120
  250. package/dist/src/funnel/local-signals.d.ts +0 -15
  251. package/dist/src/funnel/local-signals.js +0 -68
  252. package/dist/src/funnel/message-transport.d.ts +0 -51
  253. package/dist/src/funnel/message-transport.js +0 -149
  254. package/dist/src/funnel/messages.d.ts +0 -55
  255. package/dist/src/funnel/messages.js +0 -160
  256. package/dist/src/funnel/payout.d.ts +0 -40
  257. package/dist/src/funnel/payout.js +0 -60
  258. package/dist/src/funnel/power-saver-notifier.d.ts +0 -44
  259. package/dist/src/funnel/power-saver-notifier.js +0 -92
  260. package/dist/src/funnel/precedence.d.ts +0 -16
  261. package/dist/src/funnel/precedence.js +0 -85
  262. package/dist/src/funnel/promo.d.ts +0 -41
  263. package/dist/src/funnel/promo.js +0 -144
  264. package/dist/src/funnel/rate-limit-notifier.d.ts +0 -55
  265. package/dist/src/funnel/rate-limit-notifier.js +0 -102
  266. package/dist/src/funnel/rotation.d.ts +0 -19
  267. package/dist/src/funnel/rotation.js +0 -70
  268. package/dist/src/funnel/state.d.ts +0 -13
  269. package/dist/src/funnel/state.js +0 -52
  270. package/dist/src/funnel/toggle-cooldown.d.ts +0 -17
  271. package/dist/src/funnel/toggle-cooldown.js +0 -32
  272. package/dist/src/funnel/types.d.ts +0 -98
  273. package/dist/src/funnel/types.js +0 -26
  274. package/dist/src/index.d.ts +0 -81
  275. package/dist/src/index.js +0 -609
  276. package/dist/src/infrastructure/in-memory-repositories.d.ts +0 -68
  277. package/dist/src/infrastructure/in-memory-repositories.js +0 -264
  278. package/dist/src/init/claudemd-generator.d.ts +0 -16
  279. package/dist/src/init/claudemd-generator.js +0 -368
  280. package/dist/src/init/executor.d.ts +0 -41
  281. package/dist/src/init/executor.js +0 -2142
  282. package/dist/src/init/helper-refresh.d.ts +0 -79
  283. package/dist/src/init/helper-refresh.js +0 -347
  284. package/dist/src/init/helper-signing.d.ts +0 -37
  285. package/dist/src/init/helper-signing.js +0 -67
  286. package/dist/src/init/helpers-generator.d.ts +0 -87
  287. package/dist/src/init/helpers-generator.js +0 -1456
  288. package/dist/src/init/index.d.ts +0 -13
  289. package/dist/src/init/index.js +0 -15
  290. package/dist/src/init/mcp-generator.d.ts +0 -26
  291. package/dist/src/init/mcp-generator.js +0 -126
  292. package/dist/src/init/memory-package-resolver.d.ts +0 -53
  293. package/dist/src/init/memory-package-resolver.js +0 -118
  294. package/dist/src/init/settings-generator.d.ts +0 -14
  295. package/dist/src/init/settings-generator.js +0 -462
  296. package/dist/src/init/statusline-generator.d.ts +0 -28
  297. package/dist/src/init/statusline-generator.js +0 -177
  298. package/dist/src/init/types.d.ts +0 -331
  299. package/dist/src/init/types.js +0 -276
  300. package/dist/src/log-filters.d.ts +0 -46
  301. package/dist/src/log-filters.js +0 -107
  302. package/dist/src/mcp-client.d.ts +0 -92
  303. package/dist/src/mcp-client.js +0 -397
  304. package/dist/src/mcp-server.d.ts +0 -163
  305. package/dist/src/mcp-server.js +0 -751
  306. package/dist/src/mcp-tools/agent-execute-core.d.ts +0 -115
  307. package/dist/src/mcp-tools/agent-execute-core.js +0 -587
  308. package/dist/src/mcp-tools/agent-tools.d.ts +0 -9
  309. package/dist/src/mcp-tools/agent-tools.js +0 -837
  310. package/dist/src/mcp-tools/agentbbs-tools.d.ts +0 -28
  311. package/dist/src/mcp-tools/agentbbs-tools.js +0 -394
  312. package/dist/src/mcp-tools/agentdb-tools.d.ts +0 -35
  313. package/dist/src/mcp-tools/agentdb-tools.js +0 -1473
  314. package/dist/src/mcp-tools/agenticow-loader.d.ts +0 -59
  315. package/dist/src/mcp-tools/agenticow-loader.js +0 -105
  316. package/dist/src/mcp-tools/agenticow-speculate-tools.d.ts +0 -24
  317. package/dist/src/mcp-tools/agenticow-speculate-tools.js +0 -209
  318. package/dist/src/mcp-tools/agenticow-tools.d.ts +0 -36
  319. package/dist/src/mcp-tools/agenticow-tools.js +0 -360
  320. package/dist/src/mcp-tools/analyze-tools.d.ts +0 -38
  321. package/dist/src/mcp-tools/analyze-tools.js +0 -346
  322. package/dist/src/mcp-tools/auto-install.d.ts +0 -83
  323. package/dist/src/mcp-tools/auto-install.js +0 -131
  324. package/dist/src/mcp-tools/autopilot-tools.d.ts +0 -12
  325. package/dist/src/mcp-tools/autopilot-tools.js +0 -231
  326. package/dist/src/mcp-tools/browser-intent-tools.d.ts +0 -162
  327. package/dist/src/mcp-tools/browser-intent-tools.js +0 -548
  328. package/dist/src/mcp-tools/browser-session-tools.d.ts +0 -27
  329. package/dist/src/mcp-tools/browser-session-tools.js +0 -398
  330. package/dist/src/mcp-tools/browser-tools.d.ts +0 -21
  331. package/dist/src/mcp-tools/browser-tools.js +0 -760
  332. package/dist/src/mcp-tools/business-pod-tools.d.ts +0 -20
  333. package/dist/src/mcp-tools/business-pod-tools.js +0 -169
  334. package/dist/src/mcp-tools/claims-tools.d.ts +0 -12
  335. package/dist/src/mcp-tools/claims-tools.js +0 -863
  336. package/dist/src/mcp-tools/config-tools.d.ts +0 -8
  337. package/dist/src/mcp-tools/config-tools.js +0 -411
  338. package/dist/src/mcp-tools/coordination-tools.d.ts +0 -13
  339. package/dist/src/mcp-tools/coordination-tools.js +0 -729
  340. package/dist/src/mcp-tools/daa-tools.d.ts +0 -13
  341. package/dist/src/mcp-tools/daa-tools.js +0 -534
  342. package/dist/src/mcp-tools/embeddings-tools.d.ts +0 -9
  343. package/dist/src/mcp-tools/embeddings-tools.js +0 -904
  344. package/dist/src/mcp-tools/github-tools.d.ts +0 -9
  345. package/dist/src/mcp-tools/github-tools.js +0 -659
  346. package/dist/src/mcp-tools/guidance-tools.d.ts +0 -15
  347. package/dist/src/mcp-tools/guidance-tools.js +0 -639
  348. package/dist/src/mcp-tools/hive-mind-tools.d.ts +0 -8
  349. package/dist/src/mcp-tools/hive-mind-tools.js +0 -953
  350. package/dist/src/mcp-tools/hooks-tools.d.ts +0 -65
  351. package/dist/src/mcp-tools/hooks-tools.js +0 -4824
  352. package/dist/src/mcp-tools/http-fetch-tools.d.ts +0 -55
  353. package/dist/src/mcp-tools/http-fetch-tools.js +0 -329
  354. package/dist/src/mcp-tools/index.d.ts +0 -34
  355. package/dist/src/mcp-tools/index.js +0 -40
  356. package/dist/src/mcp-tools/managed-agent-tools.d.ts +0 -22
  357. package/dist/src/mcp-tools/managed-agent-tools.js +0 -357
  358. package/dist/src/mcp-tools/memory-tools.d.ts +0 -14
  359. package/dist/src/mcp-tools/memory-tools.js +0 -1330
  360. package/dist/src/mcp-tools/metaharness-tools.d.ts +0 -51
  361. package/dist/src/mcp-tools/metaharness-tools.js +0 -684
  362. package/dist/src/mcp-tools/neural-tools.d.ts +0 -54
  363. package/dist/src/mcp-tools/neural-tools.js +0 -1168
  364. package/dist/src/mcp-tools/performance-tools.d.ts +0 -16
  365. package/dist/src/mcp-tools/performance-tools.js +0 -675
  366. package/dist/src/mcp-tools/progress-tools.d.ts +0 -14
  367. package/dist/src/mcp-tools/progress-tools.js +0 -348
  368. package/dist/src/mcp-tools/request-tracker.d.ts +0 -17
  369. package/dist/src/mcp-tools/request-tracker.js +0 -27
  370. package/dist/src/mcp-tools/ruvllm-tools.d.ts +0 -9
  371. package/dist/src/mcp-tools/ruvllm-tools.js +0 -355
  372. package/dist/src/mcp-tools/security-tools.d.ts +0 -18
  373. package/dist/src/mcp-tools/security-tools.js +0 -556
  374. package/dist/src/mcp-tools/session-tools.d.ts +0 -8
  375. package/dist/src/mcp-tools/session-tools.js +0 -517
  376. package/dist/src/mcp-tools/swarm-tools.d.ts +0 -37
  377. package/dist/src/mcp-tools/swarm-tools.js +0 -390
  378. package/dist/src/mcp-tools/system-tools.d.ts +0 -13
  379. package/dist/src/mcp-tools/system-tools.js +0 -688
  380. package/dist/src/mcp-tools/task-tools.d.ts +0 -8
  381. package/dist/src/mcp-tools/task-tools.js +0 -487
  382. package/dist/src/mcp-tools/terminal-tools.d.ts +0 -8
  383. package/dist/src/mcp-tools/terminal-tools.js +0 -306
  384. package/dist/src/mcp-tools/testgen-tools.d.ts +0 -26
  385. package/dist/src/mcp-tools/testgen-tools.js +0 -168
  386. package/dist/src/mcp-tools/tool-loop-guardrail.d.ts +0 -31
  387. package/dist/src/mcp-tools/tool-loop-guardrail.js +0 -71
  388. package/dist/src/mcp-tools/transfer-tools.d.ts +0 -14
  389. package/dist/src/mcp-tools/transfer-tools.js +0 -447
  390. package/dist/src/mcp-tools/types.d.ts +0 -8
  391. package/dist/src/mcp-tools/types.js +0 -8
  392. package/dist/src/mcp-tools/validate-input.d.ts +0 -9
  393. package/dist/src/mcp-tools/validate-input.js +0 -9
  394. package/dist/src/mcp-tools/wasm-agent-tools.d.ts +0 -13
  395. package/dist/src/mcp-tools/wasm-agent-tools.js +0 -840
  396. package/dist/src/mcp-tools/workflow-tools.d.ts +0 -8
  397. package/dist/src/mcp-tools/workflow-tools.js +0 -884
  398. package/dist/src/memory/bge-embedder.d.ts +0 -25
  399. package/dist/src/memory/bge-embedder.js +0 -121
  400. package/dist/src/memory/cross-encoder-rerank.d.ts +0 -33
  401. package/dist/src/memory/cross-encoder-rerank.js +0 -123
  402. package/dist/src/memory/embedding-policy.d.ts +0 -21
  403. package/dist/src/memory/embedding-policy.js +0 -30
  404. package/dist/src/memory/embedding-quantization.d.ts +0 -62
  405. package/dist/src/memory/embedding-quantization.js +0 -156
  406. package/dist/src/memory/ewc-consolidation.d.ts +0 -305
  407. package/dist/src/memory/ewc-consolidation.js +0 -611
  408. package/dist/src/memory/graph-edge-writer.d.ts +0 -95
  409. package/dist/src/memory/graph-edge-writer.js +0 -217
  410. package/dist/src/memory/hybrid-retrieval.d.ts +0 -77
  411. package/dist/src/memory/hybrid-retrieval.js +0 -192
  412. package/dist/src/memory/intelligence.d.ts +0 -405
  413. package/dist/src/memory/intelligence.js +0 -1316
  414. package/dist/src/memory/lucene-bm25.d.ts +0 -19
  415. package/dist/src/memory/lucene-bm25.js +0 -308
  416. package/dist/src/memory/memory-bridge.d.ts +0 -537
  417. package/dist/src/memory/memory-bridge.js +0 -2460
  418. package/dist/src/memory/memory-initializer.d.ts +0 -556
  419. package/dist/src/memory/memory-initializer.js +0 -3021
  420. package/dist/src/memory/neural-package-bridge.d.ts +0 -48
  421. package/dist/src/memory/neural-package-bridge.js +0 -87
  422. package/dist/src/memory/rabitq-index.d.ts +0 -60
  423. package/dist/src/memory/rabitq-index.js +0 -242
  424. package/dist/src/memory/sona-optimizer.d.ts +0 -267
  425. package/dist/src/memory/sona-optimizer.js +0 -779
  426. package/dist/src/memory/structured-distill.d.ts +0 -48
  427. package/dist/src/memory/structured-distill.js +0 -125
  428. package/dist/src/output.d.ts +0 -9
  429. package/dist/src/output.js +0 -9
  430. package/dist/src/parser.d.ts +0 -89
  431. package/dist/src/parser.js +0 -516
  432. package/dist/src/plugins/manager.d.ts +0 -133
  433. package/dist/src/plugins/manager.js +0 -415
  434. package/dist/src/plugins/store/discovery.d.ts +0 -99
  435. package/dist/src/plugins/store/discovery.js +0 -1224
  436. package/dist/src/plugins/store/index.d.ts +0 -76
  437. package/dist/src/plugins/store/index.js +0 -141
  438. package/dist/src/plugins/store/search.d.ts +0 -46
  439. package/dist/src/plugins/store/search.js +0 -230
  440. package/dist/src/plugins/store/types.d.ts +0 -279
  441. package/dist/src/plugins/store/types.js +0 -7
  442. package/dist/src/plugins/tests/demo-plugin-store.d.ts +0 -7
  443. package/dist/src/plugins/tests/demo-plugin-store.js +0 -126
  444. package/dist/src/plugins/tests/standalone-test.d.ts +0 -12
  445. package/dist/src/plugins/tests/standalone-test.js +0 -188
  446. package/dist/src/plugins/tests/test-plugin-store.d.ts +0 -7
  447. package/dist/src/plugins/tests/test-plugin-store.js +0 -206
  448. package/dist/src/production/circuit-breaker.d.ts +0 -101
  449. package/dist/src/production/circuit-breaker.js +0 -241
  450. package/dist/src/production/error-handler.d.ts +0 -92
  451. package/dist/src/production/error-handler.js +0 -299
  452. package/dist/src/production/index.d.ts +0 -23
  453. package/dist/src/production/index.js +0 -18
  454. package/dist/src/production/monitoring.d.ts +0 -161
  455. package/dist/src/production/monitoring.js +0 -356
  456. package/dist/src/production/rate-limiter.d.ts +0 -80
  457. package/dist/src/production/rate-limiter.js +0 -201
  458. package/dist/src/production/retry.d.ts +0 -48
  459. package/dist/src/production/retry.js +0 -179
  460. package/dist/src/prompt.d.ts +0 -44
  461. package/dist/src/prompt.js +0 -501
  462. package/dist/src/runtime/headless.d.ts +0 -60
  463. package/dist/src/runtime/headless.js +0 -284
  464. package/dist/src/runtime/parent-death-watchdog.d.ts +0 -42
  465. package/dist/src/runtime/parent-death-watchdog.js +0 -70
  466. package/dist/src/ruvector/agent-wasm.d.ts +0 -228
  467. package/dist/src/ruvector/agent-wasm.js +0 -463
  468. package/dist/src/ruvector/ast-analyzer.d.ts +0 -67
  469. package/dist/src/ruvector/ast-analyzer.js +0 -277
  470. package/dist/src/ruvector/codemods/engine.d.ts +0 -45
  471. package/dist/src/ruvector/codemods/engine.js +0 -291
  472. package/dist/src/ruvector/codemods/scope-analysis.d.ts +0 -29
  473. package/dist/src/ruvector/codemods/scope-analysis.js +0 -162
  474. package/dist/src/ruvector/coverage-router.d.ts +0 -160
  475. package/dist/src/ruvector/coverage-router.js +0 -531
  476. package/dist/src/ruvector/coverage-tools.d.ts +0 -33
  477. package/dist/src/ruvector/coverage-tools.js +0 -157
  478. package/dist/src/ruvector/diff-classifier.d.ts +0 -175
  479. package/dist/src/ruvector/diff-classifier.js +0 -699
  480. package/dist/src/ruvector/diskann-backend.d.ts +0 -78
  481. package/dist/src/ruvector/diskann-backend.js +0 -310
  482. package/dist/src/ruvector/enhanced-model-router.d.ts +0 -172
  483. package/dist/src/ruvector/enhanced-model-router.js +0 -577
  484. package/dist/src/ruvector/graph-analyzer.d.ts +0 -187
  485. package/dist/src/ruvector/graph-analyzer.js +0 -929
  486. package/dist/src/ruvector/graph-backend.d.ts +0 -79
  487. package/dist/src/ruvector/graph-backend.js +0 -220
  488. package/dist/src/ruvector/index.d.ts +0 -38
  489. package/dist/src/ruvector/index.js +0 -86
  490. package/dist/src/ruvector/lora-adapter.d.ts +0 -292
  491. package/dist/src/ruvector/lora-adapter.js +0 -710
  492. package/dist/src/ruvector/model-prices.d.ts +0 -50
  493. package/dist/src/ruvector/model-prices.js +0 -72
  494. package/dist/src/ruvector/model-router.d.ts +0 -408
  495. package/dist/src/ruvector/model-router.js +0 -1162
  496. package/dist/src/ruvector/neural-router.d.ts +0 -182
  497. package/dist/src/ruvector/neural-router.js +0 -825
  498. package/dist/src/ruvector/output-verifier.d.ts +0 -83
  499. package/dist/src/ruvector/output-verifier.js +0 -277
  500. package/dist/src/ruvector/q-learning-router.d.ts +0 -227
  501. package/dist/src/ruvector/q-learning-router.js +0 -721
  502. package/dist/src/ruvector/router-calibrator.d.ts +0 -65
  503. package/dist/src/ruvector/router-calibrator.js +0 -120
  504. package/dist/src/ruvector/router-parallel-recorder.d.ts +0 -127
  505. package/dist/src/ruvector/router-parallel-recorder.js +0 -183
  506. package/dist/src/ruvector/router-trajectory.d.ts +0 -194
  507. package/dist/src/ruvector/router-trajectory.js +0 -281
  508. package/dist/src/ruvector/run-transcript-recorder.d.ts +0 -154
  509. package/dist/src/ruvector/run-transcript-recorder.js +0 -209
  510. package/dist/src/ruvector/ruvllm-wasm.d.ts +0 -179
  511. package/dist/src/ruvector/ruvllm-wasm.js +0 -379
  512. package/dist/src/ruvector/semantic-router.d.ts +0 -77
  513. package/dist/src/ruvector/semantic-router.js +0 -178
  514. package/dist/src/ruvector/task-embedder.d.ts +0 -56
  515. package/dist/src/ruvector/task-embedder.js +0 -237
  516. package/dist/src/ruvector/trajectory-tree.d.ts +0 -113
  517. package/dist/src/ruvector/trajectory-tree.js +0 -237
  518. package/dist/src/ruvector/vector-db.d.ts +0 -73
  519. package/dist/src/ruvector/vector-db.js +0 -301
  520. package/dist/src/ruvector/wasm-embedder.d.ts +0 -13
  521. package/dist/src/ruvector/wasm-embedder.js +0 -143
  522. package/dist/src/services/agentic-flow-bridge.d.ts +0 -50
  523. package/dist/src/services/agentic-flow-bridge.js +0 -95
  524. package/dist/src/services/ai-job-dedup.d.ts +0 -61
  525. package/dist/src/services/ai-job-dedup.js +0 -136
  526. package/dist/src/services/checkpoint-gate.d.ts +0 -140
  527. package/dist/src/services/checkpoint-gate.js +0 -223
  528. package/dist/src/services/claim-service.d.ts +0 -204
  529. package/dist/src/services/claim-service.js +0 -818
  530. package/dist/src/services/config-file-manager.d.ts +0 -37
  531. package/dist/src/services/config-file-manager.js +0 -224
  532. package/dist/src/services/container-worker-pool.d.ts +0 -204
  533. package/dist/src/services/container-worker-pool.js +0 -589
  534. package/dist/src/services/daemon-autostart.d.ts +0 -17
  535. package/dist/src/services/daemon-autostart.js +0 -102
  536. package/dist/src/services/distill-oracle.d.ts +0 -190
  537. package/dist/src/services/distill-oracle.js +0 -349
  538. package/dist/src/services/distill-tuning.d.ts +0 -111
  539. package/dist/src/services/distill-tuning.js +0 -510
  540. package/dist/src/services/evolve-proof.d.ts +0 -253
  541. package/dist/src/services/evolve-proof.js +0 -343
  542. package/dist/src/services/fable-harness.d.ts +0 -207
  543. package/dist/src/services/fable-harness.js +0 -388
  544. package/dist/src/services/git-workspace-identity.d.ts +0 -42
  545. package/dist/src/services/git-workspace-identity.js +0 -99
  546. package/dist/src/services/global-ai-budget.d.ts +0 -135
  547. package/dist/src/services/global-ai-budget.js +0 -415
  548. package/dist/src/services/harness-benchmark.d.ts +0 -68
  549. package/dist/src/services/harness-benchmark.js +0 -94
  550. package/dist/src/services/harness-canary.d.ts +0 -60
  551. package/dist/src/services/harness-canary.js +0 -69
  552. package/dist/src/services/harness-corpus-harvester.d.ts +0 -51
  553. package/dist/src/services/harness-corpus-harvester.js +0 -74
  554. package/dist/src/services/harness-flywheel-generations.d.ts +0 -115
  555. package/dist/src/services/harness-flywheel-generations.js +0 -360
  556. package/dist/src/services/harness-flywheel-runtime.d.ts +0 -25
  557. package/dist/src/services/harness-flywheel-runtime.js +0 -92
  558. package/dist/src/services/harness-flywheel.d.ts +0 -48
  559. package/dist/src/services/harness-flywheel.js +0 -207
  560. package/dist/src/services/harness-frozen-eval.d.ts +0 -22
  561. package/dist/src/services/harness-frozen-eval.js +0 -66
  562. package/dist/src/services/harness-hosts.d.ts +0 -40
  563. package/dist/src/services/harness-hosts.js +0 -88
  564. package/dist/src/services/harness-improvement-ledger.d.ts +0 -63
  565. package/dist/src/services/harness-improvement-ledger.js +0 -101
  566. package/dist/src/services/harness-loop.d.ts +0 -53
  567. package/dist/src/services/harness-loop.js +0 -85
  568. package/dist/src/services/harness-qualification.d.ts +0 -66
  569. package/dist/src/services/harness-qualification.js +0 -143
  570. package/dist/src/services/harness-replay.d.ts +0 -37
  571. package/dist/src/services/harness-replay.js +0 -92
  572. package/dist/src/services/harness-verify.d.ts +0 -33
  573. package/dist/src/services/harness-verify.js +0 -26
  574. package/dist/src/services/harness-worker.d.ts +0 -23
  575. package/dist/src/services/harness-worker.js +0 -66
  576. package/dist/src/services/headless-worker-executor.d.ts +0 -358
  577. package/dist/src/services/headless-worker-executor.js +0 -1269
  578. package/dist/src/services/index.d.ts +0 -13
  579. package/dist/src/services/index.js +0 -11
  580. package/dist/src/services/memory-backup.d.ts +0 -53
  581. package/dist/src/services/memory-backup.js +0 -198
  582. package/dist/src/services/memory-distillation.d.ts +0 -41
  583. package/dist/src/services/memory-distillation.js +0 -277
  584. package/dist/src/services/native-training.d.ts +0 -68
  585. package/dist/src/services/native-training.js +0 -141
  586. package/dist/src/services/registry-api.d.ts +0 -58
  587. package/dist/src/services/registry-api.js +0 -146
  588. package/dist/src/services/repo-supervisor.d.ts +0 -70
  589. package/dist/src/services/repo-supervisor.js +0 -228
  590. package/dist/src/services/ruvector-training.d.ts +0 -222
  591. package/dist/src/services/ruvector-training.js +0 -693
  592. package/dist/src/services/swarm-memory-branches.d.ts +0 -135
  593. package/dist/src/services/swarm-memory-branches.js +0 -213
  594. package/dist/src/services/weight-eft.d.ts +0 -305
  595. package/dist/src/services/weight-eft.js +0 -296
  596. package/dist/src/services/worker-daemon.d.ts +0 -439
  597. package/dist/src/services/worker-daemon.js +0 -1865
  598. package/dist/src/services/worker-queue.d.ts +0 -194
  599. package/dist/src/services/worker-queue.js +0 -513
  600. package/dist/src/services/workspace-lease.d.ts +0 -55
  601. package/dist/src/services/workspace-lease.js +0 -191
  602. package/dist/src/suggest.d.ts +0 -53
  603. package/dist/src/suggest.js +0 -200
  604. package/dist/src/transfer/anonymization/index.d.ts +0 -25
  605. package/dist/src/transfer/anonymization/index.js +0 -175
  606. package/dist/src/transfer/deploy-seraphine.d.ts +0 -13
  607. package/dist/src/transfer/deploy-seraphine.js +0 -205
  608. package/dist/src/transfer/export.d.ts +0 -25
  609. package/dist/src/transfer/export.js +0 -113
  610. package/dist/src/transfer/index.d.ts +0 -12
  611. package/dist/src/transfer/index.js +0 -31
  612. package/dist/src/transfer/ipfs/client.d.ts +0 -109
  613. package/dist/src/transfer/ipfs/client.js +0 -307
  614. package/dist/src/transfer/ipfs/upload.d.ts +0 -95
  615. package/dist/src/transfer/ipfs/upload.js +0 -413
  616. package/dist/src/transfer/models/seraphine.d.ts +0 -72
  617. package/dist/src/transfer/models/seraphine.js +0 -373
  618. package/dist/src/transfer/serialization/cfp.d.ts +0 -49
  619. package/dist/src/transfer/serialization/cfp.js +0 -183
  620. package/dist/src/transfer/storage/gcs.d.ts +0 -82
  621. package/dist/src/transfer/storage/gcs.js +0 -272
  622. package/dist/src/transfer/storage/index.d.ts +0 -6
  623. package/dist/src/transfer/storage/index.js +0 -6
  624. package/dist/src/transfer/store/discovery.d.ts +0 -84
  625. package/dist/src/transfer/store/discovery.js +0 -382
  626. package/dist/src/transfer/store/download.d.ts +0 -70
  627. package/dist/src/transfer/store/download.js +0 -334
  628. package/dist/src/transfer/store/index.d.ts +0 -84
  629. package/dist/src/transfer/store/index.js +0 -153
  630. package/dist/src/transfer/store/publish.d.ts +0 -76
  631. package/dist/src/transfer/store/publish.js +0 -294
  632. package/dist/src/transfer/store/registry.d.ts +0 -58
  633. package/dist/src/transfer/store/registry.js +0 -285
  634. package/dist/src/transfer/store/search.d.ts +0 -54
  635. package/dist/src/transfer/store/search.js +0 -232
  636. package/dist/src/transfer/store/tests/standalone-test.d.ts +0 -12
  637. package/dist/src/transfer/store/tests/standalone-test.js +0 -190
  638. package/dist/src/transfer/store/types.d.ts +0 -193
  639. package/dist/src/transfer/store/types.js +0 -6
  640. package/dist/src/transfer/test-seraphine.d.ts +0 -6
  641. package/dist/src/transfer/test-seraphine.js +0 -105
  642. package/dist/src/transfer/tests/test-store.d.ts +0 -7
  643. package/dist/src/transfer/tests/test-store.js +0 -214
  644. package/dist/src/transfer/types.d.ts +0 -245
  645. package/dist/src/transfer/types.js +0 -6
  646. package/dist/src/types.d.ts +0 -13
  647. package/dist/src/types.js +0 -13
  648. package/dist/src/update/checker.d.ts +0 -34
  649. package/dist/src/update/checker.js +0 -191
  650. package/dist/src/update/executor.d.ts +0 -33
  651. package/dist/src/update/executor.js +0 -217
  652. package/dist/src/update/index.d.ts +0 -33
  653. package/dist/src/update/index.js +0 -64
  654. package/dist/src/update/rate-limiter.d.ts +0 -20
  655. package/dist/src/update/rate-limiter.js +0 -96
  656. package/dist/src/update/validator.d.ts +0 -17
  657. package/dist/src/update/validator.js +0 -123
@@ -1,1695 +0,0 @@
1
- /**
2
- * V3 CLI Doctor Command
3
- * System diagnostics, dependency checks, config validation
4
- *
5
- * Created with ruv.io
6
- */
7
- import { output } from '../output.js';
8
- import { existsSync, readFileSync, statSync } from 'fs';
9
- import { join, dirname } from 'path';
10
- import { fileURLToPath } from 'url';
11
- import { createHash } from 'crypto';
12
- import { execSync, exec } from 'child_process';
13
- import { promisify } from 'util';
14
- import { decodeKey, isEncryptionEnabled } from '../encryption/vault.js';
15
- import { isEncryptedBlob } from '../encryption/vault.js';
16
- import { resolveMemoryPackageFromProject, readMemoryPackageVersion, recordMemoryPackagePath, } from '../init/memory-package-resolver.js';
17
- // Promisified exec with proper shell and env inheritance for cross-platform support
18
- const execAsync = promisify(exec);
19
- /**
20
- * Execute command asynchronously with proper environment inheritance
21
- * Critical for Windows where PATH may not be inherited properly
22
- */
23
- async function runCommand(command, timeoutMs = 5000) {
24
- const { stdout } = await execAsync(command, {
25
- encoding: 'utf8',
26
- timeout: timeoutMs,
27
- shell: process.platform === 'win32' ? 'cmd.exe' : '/bin/sh', // Use proper shell per platform
28
- env: { ...process.env }, // Explicitly inherit full environment
29
- windowsHide: true, // Hide window on Windows
30
- });
31
- return stdout.trim();
32
- }
33
- // Check Node.js version
34
- async function checkNodeVersion() {
35
- const requiredMajor = 20;
36
- const version = process.version;
37
- const major = parseInt(version.slice(1).split('.')[0], 10);
38
- if (major >= requiredMajor) {
39
- return { name: 'Node.js Version', status: 'pass', message: `${version} (>= ${requiredMajor} required)` };
40
- }
41
- else if (major >= 18) {
42
- return { name: 'Node.js Version', status: 'warn', message: `${version} (>= ${requiredMajor} recommended)`, fix: 'nvm install 20 && nvm use 20' };
43
- }
44
- else {
45
- return { name: 'Node.js Version', status: 'fail', message: `${version} (>= ${requiredMajor} required)`, fix: 'nvm install 20 && nvm use 20' };
46
- }
47
- }
48
- // Check npm version (async with proper env inheritance)
49
- async function checkNpmVersion() {
50
- try {
51
- const version = await runCommand('npm --version');
52
- const major = parseInt(version.split('.')[0], 10);
53
- if (major >= 9) {
54
- return { name: 'npm Version', status: 'pass', message: `v${version}` };
55
- }
56
- else {
57
- return { name: 'npm Version', status: 'warn', message: `v${version} (>= 9 recommended)`, fix: 'npm install -g npm@latest' };
58
- }
59
- }
60
- catch {
61
- return { name: 'npm Version', status: 'fail', message: 'npm not found', fix: 'Install Node.js from https://nodejs.org' };
62
- }
63
- }
64
- // Check config file
65
- async function checkConfigFile() {
66
- // JSON configs (parse-validated). The first three are LEGACY shapes from
67
- // pre-v3 init flows; v3 init writes only `.claude-flow/config.yaml`.
68
- const jsonPaths = [
69
- '.claude-flow/config.json',
70
- 'claude-flow.config.json',
71
- '.claude-flow.json'
72
- ];
73
- // YAML configs (existence-checked only — no heavy yaml parser dependency).
74
- const yamlPaths = [
75
- '.claude-flow/config.yaml',
76
- '.claude-flow/config.yml',
77
- 'claude-flow.config.yaml'
78
- ];
79
- // #1798 — collect ALL configs that exist instead of returning at the first
80
- // hit. The previous early-return masked silent collisions: if both a v2
81
- // JSON and a v3 YAML existed, doctor reported only the JSON while the
82
- // daemon was actually reading from the YAML. Surfacing both lets the user
83
- // see and resolve the disagreement.
84
- const foundJson = [];
85
- const invalidJson = [];
86
- for (const configPath of jsonPaths) {
87
- if (!existsSync(configPath))
88
- continue;
89
- try {
90
- JSON.parse(readFileSync(configPath, 'utf8'));
91
- foundJson.push(configPath);
92
- }
93
- catch {
94
- invalidJson.push(configPath);
95
- }
96
- }
97
- const foundYaml = yamlPaths.filter(p => existsSync(p));
98
- // Hard failures first: malformed JSON wins.
99
- if (invalidJson.length > 0) {
100
- return { name: 'Config File', status: 'fail', message: `Invalid JSON: ${invalidJson.join(', ')}`, fix: 'Fix JSON syntax in config file' };
101
- }
102
- // #1798 — collision: legacy JSON + new YAML both present. Subsystems can
103
- // disagree on which to read; surface this as a warn with the recommended
104
- // resolution (keep the YAML, archive the JSON).
105
- if (foundJson.length > 0 && foundYaml.length > 0) {
106
- return {
107
- name: 'Config File',
108
- status: 'warn',
109
- message: `Config collision: legacy ${foundJson.join(', ')} + ${foundYaml.join(', ')} — subsystems may disagree silently`,
110
- fix: `Archive the legacy JSON (mv ${foundJson[0]} ${foundJson[0]}.bak) and keep ${foundYaml[0]} as the canonical config`,
111
- };
112
- }
113
- if (foundYaml.length > 0) {
114
- return { name: 'Config File', status: 'pass', message: `Found: ${foundYaml[0]}` };
115
- }
116
- if (foundJson.length > 0) {
117
- return { name: 'Config File', status: 'pass', message: `Found: ${foundJson[0]}` };
118
- }
119
- return { name: 'Config File', status: 'warn', message: 'No config file (using defaults)', fix: 'claude-flow config init' };
120
- }
121
- // Check daemon status
122
- /**
123
- * #2448 — Detect the runaway `npx @claude-flow/cli@latest` statusLine / hook
124
- * commands left over in `.claude/settings.json` from pre-#2337 installs.
125
- *
126
- * These fire on every Claude Code event (statusLine refires every few hundred
127
- * ms, hooks fire per tool-use), each spawning a cold Node process + npm
128
- * registry round-trip. On the reporter's 48 GB macOS box this produced
129
- * load average 49, jetsam, and a kernel watchdog panic two minutes after
130
- * boot. Severity is CRITICAL when present; users who installed before #2337
131
- * and never re-ran `ruflo init` still have it.
132
- *
133
- * Detection only — does not modify settings. Fix path is `ruflo init` (the
134
- * executor's migration logic, also patched in #2448, will now regenerate
135
- * the broken commands).
136
- */
137
- async function checkStaleSettingsNpx() {
138
- // Same regex pattern the executor migration uses — kept in sync. Flag-list
139
- // repetition bounded at 10 (CodeQL js/redos — unbounded `*` here is
140
- // exponential-backtracking-prone on a crafted settings.json).
141
- const BROKEN_RE = /npx\s+(?:--?\S+\s+){0,10}@?claude-flow\/cli@latest\s+hooks\s+(?:statusline|\S+)/;
142
- // Look in both project-local and home-dir settings.
143
- const candidates = [
144
- join(process.cwd(), '.claude', 'settings.json'),
145
- join(process.env.HOME ?? '', '.claude', 'settings.json'),
146
- ].filter((p, i, a) => p && a.indexOf(p) === i);
147
- const offenders = [];
148
- for (const settingsPath of candidates) {
149
- if (!existsSync(settingsPath))
150
- continue;
151
- let settings;
152
- try {
153
- settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
154
- }
155
- catch {
156
- continue; // checkConfigFile reports JSON errors separately
157
- }
158
- // statusLine.command
159
- const sl = settings.statusLine;
160
- if (sl?.command && BROKEN_RE.test(sl.command)) {
161
- offenders.push({ path: settingsPath, where: 'statusLine' });
162
- }
163
- // hooks.<event>[].hooks[].command
164
- const hooks = settings.hooks;
165
- if (hooks) {
166
- for (const [eventName, groups] of Object.entries(hooks)) {
167
- if (!Array.isArray(groups))
168
- continue;
169
- for (const group of groups) {
170
- if (!Array.isArray(group.hooks))
171
- continue;
172
- for (const h of group.hooks) {
173
- if (typeof h?.command === 'string' && BROKEN_RE.test(h.command)) {
174
- offenders.push({ path: settingsPath, where: `hooks.${eventName}` });
175
- }
176
- }
177
- }
178
- }
179
- }
180
- }
181
- if (offenders.length === 0) {
182
- return { name: 'Stale npx@latest in settings (#2448)', status: 'pass', message: 'no runaway commands detected' };
183
- }
184
- // Group by file for readable output
185
- const byFile = offenders.reduce((acc, o) => {
186
- (acc[o.path] ??= []).push(o.where);
187
- return acc;
188
- }, {});
189
- const summary = Object.entries(byFile)
190
- .map(([p, wheres]) => `${p} [${[...new Set(wheres)].join(', ')}]`)
191
- .join('; ');
192
- return {
193
- name: 'Stale npx@latest in settings (#2448)',
194
- status: 'fail',
195
- message: `CRITICAL — runaway \`npx @claude-flow/cli@latest\` commands detected: ${summary}`,
196
- fix: 'Re-run `npx ruflo init` to migrate (the v3.13.3+ init migrator regenerates these to local-helper form). On macOS this prevents the process-storm / kernel-panic class reported in #2448.',
197
- };
198
- }
199
- async function checkDaemonStatus() {
200
- try {
201
- const pidFile = '.claude-flow/daemon.pid';
202
- if (existsSync(pidFile)) {
203
- const pid = readFileSync(pidFile, 'utf8').trim();
204
- try {
205
- process.kill(parseInt(pid, 10), 0); // Check if process exists
206
- return { name: 'Daemon Status', status: 'pass', message: `Running (PID: ${pid})` };
207
- }
208
- catch {
209
- return { name: 'Daemon Status', status: 'warn', message: 'Stale PID file', fix: 'rm .claude-flow/daemon.pid && claude-flow daemon start' };
210
- }
211
- }
212
- return { name: 'Daemon Status', status: 'warn', message: 'Not running', fix: 'claude-flow daemon start' };
213
- }
214
- catch {
215
- return { name: 'Daemon Status', status: 'warn', message: 'Unable to check', fix: 'claude-flow daemon status' };
216
- }
217
- }
218
- // Check memory database
219
- async function checkMemoryDatabase() {
220
- // Authoritative path comes from `getMemoryRoot()` (honors
221
- // `CLAUDE_FLOW_MEMORY_PATH`, claude-flow.config.json's `memory.persistPath`,
222
- // then defaults to `.swarm/`). #1946: the previous hard-coded list missed
223
- // `data/memory/memory.db` (a common config) and ignored the env var
224
- // entirely, so doctor reported "Not initialized" on perfectly-init'd DBs.
225
- // Try the configured path first, then fall back to the historic candidates.
226
- const candidates = [];
227
- try {
228
- const { getMemoryRoot } = await import('../memory/memory-initializer.js');
229
- candidates.push(join(getMemoryRoot(), 'memory.db'));
230
- }
231
- catch {
232
- /* memory-initializer not available — fall through to legacy candidates */
233
- }
234
- candidates.push('.swarm/memory.db', '.claude-flow/memory.db', 'data/memory/memory.db', // matches `CLAUDE_FLOW_MEMORY_PATH=data/memory`
235
- 'data/memory.db');
236
- for (const dbPath of candidates) {
237
- if (existsSync(dbPath)) {
238
- try {
239
- const stats = statSync(dbPath);
240
- const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
241
- return { name: 'Memory Database', status: 'pass', message: `${dbPath} (${sizeMB} MB)` };
242
- }
243
- catch {
244
- return { name: 'Memory Database', status: 'warn', message: `${dbPath} (unable to stat)` };
245
- }
246
- }
247
- }
248
- return { name: 'Memory Database', status: 'warn', message: 'Not initialized', fix: 'claude-flow memory configure --backend hybrid' };
249
- }
250
- // ═══════════════════════════════════════════════════════════════════════════
251
- // #2677 — memory doctor: functional checks (stuinfla)
252
- //
253
- // The existing `checkMemoryDatabase` above asserts existence + statability
254
- // only, so it CANNOT distinguish a healthy DB from a 99.97%-empty or
255
- // SQLite-malformed one. Stuinfla reported both cases live (81-store fleet).
256
- // The three checks below layer functional assertions on top, ordered so
257
- // the earliest chain-break is always the first red the user sees:
258
- // 1. Integrity — can sql.js open it AND does PRAGMA integrity_check pass?
259
- // 2. Content — do most memory_entries rows carry non-empty content?
260
- // 3. Embedding coverage — do most rows have a vector? (unembedded rows are
261
- // both unrecallable AND undistillable per ADR-174)
262
- // Ordering matters: content ratio is meaningless on a DB that can't open;
263
- // embedding coverage is meaningless on rows with no content. First red wins.
264
- //
265
- // Recall probe (stuinfla check 4) requires actual write+search+delete round
266
- // trips through the CLI's own memory pipeline — deferred to a follow-up PR
267
- // to keep this one purely additive and safe.
268
- //
269
- // Design rules (also from stuinfla's report):
270
- // - "A check that cannot fail protects nothing" — every check has a
271
- // demonstrable red state.
272
- // - "UNKNOWN is never PASS" — if the check can't RUN, report warn/fail,
273
- // never a reassuring pass. Encrypted-DB case gets warn with the caveat
274
- // spelled out; corruption gets fail.
275
- // - "Print the measurement, not a checkmark" — messages include the
276
- // ratios so operators see the shape of the problem.
277
- /** Resolve the same DB path checkMemoryDatabase above uses. Returns null
278
- * if no candidate exists (in which case none of these checks should
279
- * fire — checkMemoryDatabase will already have surfaced the missing DB). */
280
- async function resolveMemoryDbPath() {
281
- const candidates = [];
282
- try {
283
- const { getMemoryRoot } = await import('../memory/memory-initializer.js');
284
- candidates.push(join(getMemoryRoot(), 'memory.db'));
285
- }
286
- catch { /* fall through to legacy candidates */ }
287
- candidates.push('.swarm/memory.db', '.claude-flow/memory.db', 'data/memory/memory.db', 'data/memory.db');
288
- for (const p of candidates)
289
- if (existsSync(p))
290
- return p;
291
- return null;
292
- }
293
- /** Open a sql.js Database over an on-disk file, returning null when the
294
- * file can't be opened as a SQLite database (encrypted / corrupted / not
295
- * a database). Callers decide whether that's warn or fail. */
296
- async function tryOpenSqlJs(dbPath) {
297
- try {
298
- const initSqlJs = (await import('sql.js')).default ?? (await import('sql.js'));
299
- const SQL = await (typeof initSqlJs === 'function' ? initSqlJs() : initSqlJs.default());
300
- const { readFileSync } = await import('fs');
301
- const buf = readFileSync(dbPath);
302
- return new SQL.Database(new Uint8Array(buf));
303
- }
304
- catch {
305
- return null;
306
- }
307
- }
308
- // Check 1 — sql.js can open it AND PRAGMA integrity_check returns 'ok'.
309
- // Two fail modes handled distinctly per "UNKNOWN is never PASS":
310
- // - Open fails: warn ("cannot open; encrypted DB or corrupt — doctor
311
- // can't distinguish from this side")
312
- // - Open succeeds but pragma != 'ok': fail (definite corruption)
313
- async function checkMemoryIntegrity() {
314
- const dbPath = await resolveMemoryDbPath();
315
- if (!dbPath)
316
- return { name: 'Memory Integrity', status: 'warn', message: 'no memory.db found (see Memory Database check above)' };
317
- const db = await tryOpenSqlJs(dbPath);
318
- if (!db) {
319
- return {
320
- name: 'Memory Integrity',
321
- status: 'warn',
322
- message: `${dbPath} — sql.js can't open (encrypted DB or corrupt; doctor can't tell which from outside)`,
323
- fix: 'if encrypted: expected. if not: back up + `claude-flow memory init --force` to rebuild',
324
- };
325
- }
326
- try {
327
- const res = db.exec('PRAGMA integrity_check');
328
- const rows = res[0]?.values?.map((v) => String(v[0])) ?? [];
329
- if (rows.length === 1 && rows[0] === 'ok') {
330
- return { name: 'Memory Integrity', status: 'pass', message: `${dbPath} — PRAGMA integrity_check: ok` };
331
- }
332
- return {
333
- name: 'Memory Integrity',
334
- status: 'fail',
335
- message: `${dbPath} — PRAGMA integrity_check: ${rows.slice(0, 3).join('; ')}${rows.length > 3 ? ` (+${rows.length - 3} more)` : ''}`,
336
- fix: 'back up .swarm/memory.db then `claude-flow memory init --force`',
337
- };
338
- }
339
- catch (e) {
340
- const msg = e.message || String(e);
341
- const encryptedOrCorrupt = msg.includes('file is not a database') || msg.includes('malformed');
342
- return {
343
- name: 'Memory Integrity',
344
- status: 'warn',
345
- message: encryptedOrCorrupt
346
- ? `${dbPath} — DB refused query: ${msg} (encrypted DB or corruption; see Memory Integrity above)`
347
- : `${dbPath} — probe threw: ${msg}`,
348
- };
349
- }
350
- finally {
351
- try {
352
- db.close();
353
- }
354
- catch { /* best-effort */ }
355
- }
356
- }
357
- // Check 2 — memory_entries rows should mostly carry non-empty content.
358
- // Stuinfla's live case: 11,133 rows, 3 with content (0.03%). Threshold 95%
359
- // is the number he proposed. Values below → fail with the exact ratio in
360
- // the message ("Print the measurement, not a checkmark").
361
- async function checkMemoryContent() {
362
- const dbPath = await resolveMemoryDbPath();
363
- if (!dbPath)
364
- return { name: 'Memory Content', status: 'warn', message: 'no memory.db found' };
365
- const db = await tryOpenSqlJs(dbPath);
366
- if (!db)
367
- return { name: 'Memory Content', status: 'warn', message: 'DB unreadable (see Memory Integrity)' };
368
- try {
369
- const tables = db.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='memory_entries'")[0]?.values?.map((v) => String(v[0])) ?? [];
370
- if (tables.length === 0)
371
- return { name: 'Memory Content', status: 'warn', message: 'no memory_entries table in DB — schema mismatch or empty init' };
372
- const r = db.exec("SELECT count(*), sum(CASE WHEN length(trim(coalesce(content,'')))>0 THEN 1 ELSE 0 END) FROM memory_entries");
373
- const total = Number(r[0]?.values?.[0]?.[0] ?? 0);
374
- const populated = Number(r[0]?.values?.[0]?.[1] ?? 0);
375
- if (total === 0)
376
- return { name: 'Memory Content', status: 'pass', message: `${dbPath} — 0 rows (fresh DB, expected)` };
377
- const ratio = populated / total;
378
- const pct = (ratio * 100).toFixed(2);
379
- const detail = `content ${populated}/${total} (${pct}%)`;
380
- if (ratio < 0.95) {
381
- return {
382
- name: 'Memory Content',
383
- status: 'fail',
384
- message: `${dbPath} — ${detail} below 95% floor`,
385
- fix: 'schema drift likely (rename of value→content or similar). check migration state via `claude-flow migrate status`',
386
- };
387
- }
388
- return { name: 'Memory Content', status: 'pass', message: `${dbPath} — ${detail}` };
389
- }
390
- catch (e) {
391
- const msg = e.message || String(e);
392
- const encryptedOrCorrupt = msg.includes('file is not a database') || msg.includes('malformed');
393
- return {
394
- name: 'Memory Content',
395
- status: 'warn',
396
- message: encryptedOrCorrupt
397
- ? `${dbPath} — DB refused query: ${msg} (encrypted DB or corruption; see Memory Integrity above)`
398
- : `${dbPath} — probe threw: ${msg}`,
399
- };
400
- }
401
- finally {
402
- try {
403
- db.close();
404
- }
405
- catch { /* best-effort */ }
406
- }
407
- }
408
- // Check 3 — most memory_entries with content should also carry an embedding
409
- // vector. Rows without a vector are BOTH unrecallable (no similarity search
410
- // can find them) AND undistillable (ADR-174's distill skips rows with no
411
- // parseable vector). Same 95% threshold + fail-with-ratio pattern as check 2.
412
- //
413
- // Embedding storage varies across ruflo installs (agentdb migrations, HNSW
414
- // index vs inline vector column). Discovers the shape via schema probes,
415
- // falls back to warn if the schema is unrecognized (better than a false
416
- // pass, per "UNKNOWN is never PASS").
417
- async function checkMemoryEmbeddingCoverage() {
418
- const dbPath = await resolveMemoryDbPath();
419
- if (!dbPath)
420
- return { name: 'Memory Embedding Coverage', status: 'warn', message: 'no memory.db found' };
421
- const db = await tryOpenSqlJs(dbPath);
422
- if (!db)
423
- return { name: 'Memory Embedding Coverage', status: 'warn', message: 'DB unreadable (see Memory Integrity)' };
424
- try {
425
- // Schema-shape discovery. Three candidate columns / tables we've seen
426
- // across the agentdb / ruvector history — first match wins.
427
- const cols = db.exec("PRAGMA table_info(memory_entries)");
428
- const colNames = new Set((cols[0]?.values ?? []).map((v) => String(v[1])));
429
- let vectorPredicate = null;
430
- if (colNames.has('embedding'))
431
- vectorPredicate = "embedding IS NOT NULL AND length(embedding) > 0";
432
- else if (colNames.has('vector'))
433
- vectorPredicate = "vector IS NOT NULL AND length(vector) > 0";
434
- if (!vectorPredicate) {
435
- const otherTables = db.exec("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('vector_indexes','embeddings','memory_embeddings')")[0]?.values?.map((v) => String(v[0])) ?? [];
436
- if (otherTables.length === 0) {
437
- return {
438
- name: 'Memory Embedding Coverage',
439
- status: 'warn',
440
- message: 'no embedding column/table recognized (agentdb schema mismatch or older format) — doctor cannot measure',
441
- };
442
- }
443
- const tbl = otherTables[0];
444
- const r = db.exec(`SELECT count(*) FROM memory_entries m WHERE EXISTS (SELECT 1 FROM ${tbl} e WHERE e.memory_id = m.id OR e.entry_id = m.id OR e.id = m.id)`);
445
- const withEmbedding = Number(r[0]?.values?.[0]?.[0] ?? 0);
446
- const total = Number(db.exec("SELECT count(*) FROM memory_entries WHERE length(trim(coalesce(content,'')))>0")[0]?.values?.[0]?.[0] ?? 0);
447
- if (total === 0)
448
- return { name: 'Memory Embedding Coverage', status: 'pass', message: `${dbPath} — 0 content rows (nothing to embed)` };
449
- const ratio = withEmbedding / total;
450
- const pct = (ratio * 100).toFixed(2);
451
- const detail = `embedded ${withEmbedding}/${total} (${pct}%) via ${tbl}`;
452
- if (ratio < 0.95)
453
- return { name: 'Memory Embedding Coverage', status: 'fail', message: `${dbPath} — ${detail} below 95% floor`, fix: 'unembedded rows are unrecallable + undistillable — re-run `claude-flow memory embed --namespace <name>` for populated namespaces' };
454
- return { name: 'Memory Embedding Coverage', status: 'pass', message: `${dbPath} — ${detail}` };
455
- }
456
- // Inline embedding column
457
- const r = db.exec(`SELECT count(*), sum(CASE WHEN ${vectorPredicate} THEN 1 ELSE 0 END) FROM memory_entries WHERE length(trim(coalesce(content,'')))>0`);
458
- const total = Number(r[0]?.values?.[0]?.[0] ?? 0);
459
- const withEmb = Number(r[0]?.values?.[0]?.[1] ?? 0);
460
- if (total === 0)
461
- return { name: 'Memory Embedding Coverage', status: 'pass', message: `${dbPath} — 0 content rows (nothing to embed)` };
462
- const ratio = withEmb / total;
463
- const pct = (ratio * 100).toFixed(2);
464
- const detail = `embedded ${withEmb}/${total} (${pct}%)`;
465
- if (ratio < 0.95) {
466
- return { name: 'Memory Embedding Coverage', status: 'fail', message: `${dbPath} — ${detail} below 95% floor`, fix: 'unembedded rows are unrecallable + undistillable — re-run `claude-flow memory embed --namespace <name>` for populated namespaces' };
467
- }
468
- return { name: 'Memory Embedding Coverage', status: 'pass', message: `${dbPath} — ${detail}` };
469
- }
470
- catch (e) {
471
- const msg = e.message || String(e);
472
- const encryptedOrCorrupt = msg.includes('file is not a database') || msg.includes('malformed');
473
- return {
474
- name: 'Memory Embedding Coverage',
475
- status: 'warn',
476
- message: encryptedOrCorrupt
477
- ? `${dbPath} — DB refused query: ${msg} (encrypted DB or corruption; see Memory Integrity above)`
478
- : `${dbPath} — probe threw: ${msg}`,
479
- };
480
- }
481
- finally {
482
- try {
483
- db.close();
484
- }
485
- catch { /* best-effort */ }
486
- }
487
- }
488
- // #2545: Check that the self-learning bridge can actually load @claude-flow/memory
489
- // the SAME way the SessionStart auto-memory hook does. On the documented `npx ruflo`
490
- // path the package lands in the npx cache — unreachable from the project — so the
491
- // hook silently no-op'd with no signal anywhere. This surfaces it.
492
- async function checkLearningBridge() {
493
- const cwd = process.cwd();
494
- const hookPath = join(cwd, '.claude', 'helpers', 'auto-memory-hook.mjs');
495
- // Only relevant once init has deployed the hook; otherwise stay quiet.
496
- if (!existsSync(hookPath)) {
497
- return {
498
- name: 'Learning Bridge',
499
- status: 'pass',
500
- message: 'auto-memory hook not installed (run: npx ruflo@latest init)',
501
- };
502
- }
503
- const distPath = resolveMemoryPackageFromProject(cwd);
504
- if (distPath) {
505
- const version = readMemoryPackageVersion(distPath);
506
- return {
507
- name: 'Learning Bridge',
508
- status: 'pass',
509
- message: `@claude-flow/memory resolvable${version ? ` (v${version})` : ''}`,
510
- };
511
- }
512
- // #2599: Self-heal on plain `doctor` (not just --fix). The project-side resolver
513
- // fails when the sidecar is stale or missing (e.g. npx cache generation rotated),
514
- // but the CLI process itself can resolve @claude-flow/memory from its own module
515
- // context. Write the sidecar automatically instead of hard-failing the check.
516
- const record = recordMemoryPackagePath(cwd, 'doctor-auto');
517
- if (record) {
518
- const version = readMemoryPackageVersion(record.distPath);
519
- return {
520
- name: 'Learning Bridge',
521
- status: 'pass',
522
- message: `@claude-flow/memory resolvable via auto-recorded sidecar${version ? ` (v${version})` : ''}`,
523
- };
524
- }
525
- return {
526
- name: 'Learning Bridge',
527
- status: 'fail',
528
- message: '@claude-flow/memory NOT resolvable — SessionStart self-learning imports are a silent no-op',
529
- fix: 'npm i -D @claude-flow/memory (optional dep appears absent — likely --omit=optional install)',
530
- };
531
- }
532
- // Check API keys
533
- async function checkApiKeys() {
534
- const keys = ['ANTHROPIC_API_KEY', 'CLAUDE_API_KEY', 'OPENAI_API_KEY'];
535
- const found = [];
536
- for (const key of keys) {
537
- if (process.env[key]) {
538
- found.push(key);
539
- }
540
- }
541
- // Detect Claude Code environment — API keys are managed internally
542
- const inClaudeCode = !!(process.env.CLAUDE_CODE || process.env.CLAUDE_PROJECT_DIR || process.env.MCP_SESSION_ID);
543
- if (found.includes('ANTHROPIC_API_KEY') || found.includes('CLAUDE_API_KEY')) {
544
- return { name: 'API Keys', status: 'pass', message: `Found: ${found.join(', ')}` };
545
- }
546
- else if (inClaudeCode) {
547
- return { name: 'API Keys', status: 'pass', message: 'Claude Code (managed internally)' };
548
- }
549
- else if (found.length > 0) {
550
- return { name: 'API Keys', status: 'warn', message: `Found: ${found.join(', ')} (no Claude key)`, fix: 'export ANTHROPIC_API_KEY=your_key' };
551
- }
552
- else {
553
- return { name: 'API Keys', status: 'warn', message: 'No API keys found', fix: 'export ANTHROPIC_API_KEY=your_key' };
554
- }
555
- }
556
- // Check git (async with proper env inheritance)
557
- async function checkGit() {
558
- try {
559
- const version = await runCommand('git --version');
560
- return { name: 'Git', status: 'pass', message: version.replace('git version ', 'v') };
561
- }
562
- catch {
563
- return { name: 'Git', status: 'warn', message: 'Not installed', fix: 'Install git from https://git-scm.com' };
564
- }
565
- }
566
- // Check if in git repo (async with proper env inheritance)
567
- //
568
- // #1791.7 — `git rev-parse` was reported as failing on hosts where `.git`
569
- // clearly exists in cwd (linux-arm64 daemon contexts). Treat the git binary
570
- // as authoritative when it succeeds, but fall back to a `.git` walk-up so a
571
- // present repository is recognized even when the git invocation fails for
572
- // environment reasons (PATH, broken global config, EBADCWD, etc.).
573
- async function checkGitRepo() {
574
- try {
575
- await runCommand('git rev-parse --is-inside-work-tree');
576
- return { name: 'Git Repository', status: 'pass', message: 'In a git repository' };
577
- }
578
- catch {
579
- // Walk parents of cwd for a .git directory before reporting "not a repo"
580
- let dir = process.cwd();
581
- while (true) {
582
- if (existsSync(join(dir, '.git'))) {
583
- return {
584
- name: 'Git Repository',
585
- status: 'warn',
586
- message: `Repo detected on disk (${join(dir, '.git')}) but \`git rev-parse\` failed — check git installation and PATH`,
587
- fix: 'Verify git is on PATH (try `git --version`) and that the working tree is not corrupted',
588
- };
589
- }
590
- const parent = dirname(dir);
591
- if (parent === dir)
592
- break;
593
- dir = parent;
594
- }
595
- return { name: 'Git Repository', status: 'warn', message: 'Not a git repository', fix: 'git init' };
596
- }
597
- }
598
- // Check AIDefence package availability (#1807)
599
- //
600
- // `aidefence_*` MCP tools (scan, analyze, has_pii, stats, learn) require
601
- // `@claude-flow/aidefence` to be installed and loadable. The package is an
602
- // optional dependency — present in some installs (project-local) but
603
- // missing in others (npm-global of `claude-flow`). Without it, every
604
- // aidefence MCP call fails at runtime with "Cannot find module".
605
- //
606
- // Surface that state in `doctor` so operators know BEFORE they rely on
607
- // AI-defence scanning. The probe is the same dynamic `import()` the MCP
608
- // tool's handler uses, so a `pass` here means the actual tools will work.
609
- async function checkAIDefence() {
610
- try {
611
- // eslint-disable-next-line @typescript-eslint/no-var-requires
612
- await import('@claude-flow/aidefence');
613
- return {
614
- name: 'AIDefence',
615
- status: 'pass',
616
- message: '@claude-flow/aidefence loadable — aidefence_* MCP tools functional',
617
- };
618
- }
619
- catch {
620
- return {
621
- name: 'AIDefence',
622
- status: 'warn',
623
- message: '@claude-flow/aidefence not loadable — aidefence_* MCP tools will fail (optional package)',
624
- fix: 'npm install --save @claude-flow/aidefence (in your project), or run `claude-flow mcp start` from a directory that has it installed',
625
- };
626
- }
627
- }
628
- /**
629
- * ADR-097 Phase 4: federation peer-state surface for doctor.
630
- *
631
- * Probes the federation plugin loadability + asserts the breaker entity
632
- * layer is present in the installed version. Without the plugin
633
- * installed this is a "not configured" pass — federation is opt-in.
634
- *
635
- * Live coordinator state (per-peer counts) requires a running MCP server
636
- * with `federation_init` called; operators inspect that via the
637
- * `federation_breaker_status` MCP tool, not the doctor (which is a
638
- * one-shot CLI process with no coordinator session).
639
- */
640
- async function checkFederationBreaker() {
641
- try {
642
- // Optional plugin — not a hard dep of @claude-flow/cli. Build the
643
- // module specifier dynamically so TypeScript cannot statically
644
- // resolve it (which would emit TS2307); at runtime the import
645
- // either resolves (plugin installed) or throws (handled below).
646
- const specifier = ['@claude-flow', 'plugin-agent-federation'].join('/');
647
- const mod = await import(specifier);
648
- if (!mod.FederationNodeState) {
649
- return {
650
- name: 'Federation Breaker',
651
- status: 'warn',
652
- message: '@claude-flow/plugin-agent-federation loaded but FederationNodeState export missing — version older than ADR-097 Phase 2',
653
- fix: 'Upgrade: npm install @claude-flow/plugin-agent-federation@alpha',
654
- };
655
- }
656
- return {
657
- name: 'Federation Breaker',
658
- status: 'pass',
659
- message: 'ADR-097 breaker loadable — federation_breaker_status / federation_evict / federation_reactivate MCP tools available',
660
- };
661
- }
662
- catch {
663
- return {
664
- name: 'Federation Breaker',
665
- status: 'pass',
666
- message: 'Federation plugin not installed (optional) — install only if you need cross-installation peering',
667
- fix: 'npm install --save @claude-flow/plugin-agent-federation@alpha',
668
- };
669
- }
670
- }
671
- // Check MCP servers
672
- async function checkMcpServers() {
673
- const home = process.env.HOME || process.env.USERPROFILE || '';
674
- // #1842: ~/.claude.json holds project-scoped registrations under
675
- // parsed.projects[<projectPath>].mcpServers.ruflo, in addition to any
676
- // top-level mcpServers. Check both shapes plus the legacy desktop and
677
- // local .mcp.json paths.
678
- const mcpConfigPaths = [
679
- join(home, '.claude.json'),
680
- join(home, '.claude/claude_desktop_config.json'),
681
- join(home, '.config/claude/mcp.json'),
682
- '.mcp.json',
683
- ];
684
- const isRufloKey = (k) => k === 'ruflo' || k === 'ruflo_alpha' || k === 'claude-flow' || k === 'claude-flow_alpha';
685
- // Canonical MCP-server key is `claude-flow` — matches the `mcp__claude-flow__*`
686
- // prefix that ~166 plugin tool references depend on (#2206). A `ruflo`-keyed
687
- // entry pointing at the same binary is the legacy duplicate created by
688
- // pre-rename setup docs that #2612 tracks; doctor treats it as removable.
689
- const isCurrentRufloKey = (k) => k === 'claude-flow' || k === 'claude-flow_alpha';
690
- const isLegacyRufloKey = (k) => k === 'ruflo' || k === 'ruflo_alpha';
691
- const isRufloServer = (server) => {
692
- if (!server || typeof server !== 'object')
693
- return false;
694
- const entry = server;
695
- const command = typeof entry.command === 'string' ? entry.command : '';
696
- const args = Array.isArray(entry.args)
697
- ? entry.args.filter((arg) => typeof arg === 'string')
698
- : [];
699
- const haystack = [command, ...args].join(' ');
700
- return /\b(?:ruflo|claude-flow|@claude-flow\/cli)(?:@[\w.-]+)?\b/.test(haystack);
701
- };
702
- let totalServersSeen = 0;
703
- const rufloLocations = [];
704
- const duplicateLocations = [];
705
- const legacyLocations = [];
706
- const currentLocations = [];
707
- const inspectServers = (servers, location) => {
708
- if (!servers || typeof servers !== 'object')
709
- return { total: 0, hasRuflo: false };
710
- const entries = Object.entries(servers);
711
- const activeRufloEntries = entries.filter(([key, server]) => isRufloKey(key) && isRufloServer(server));
712
- const hasLegacy = activeRufloEntries.some(([key]) => isLegacyRufloKey(key));
713
- const hasCurrent = activeRufloEntries.some(([key]) => isCurrentRufloKey(key));
714
- if (activeRufloEntries.length > 0) {
715
- rufloLocations.push(`${location}: ${activeRufloEntries.map(([key]) => key).join(', ')}`);
716
- }
717
- if (hasLegacy && hasCurrent) {
718
- duplicateLocations.push(`${location}: ${activeRufloEntries.map(([key]) => key).join(' + ')}`);
719
- }
720
- for (const [key] of activeRufloEntries) {
721
- if (isLegacyRufloKey(key))
722
- legacyLocations.push(`${location}: ${key}`);
723
- if (isCurrentRufloKey(key))
724
- currentLocations.push(`${location}: ${key}`);
725
- }
726
- return { total: entries.length, hasRuflo: activeRufloEntries.length > 0 };
727
- };
728
- for (const configPath of mcpConfigPaths) {
729
- if (!existsSync(configPath))
730
- continue;
731
- try {
732
- const content = JSON.parse(readFileSync(configPath, 'utf8'));
733
- // Top-level mcpServers (legacy / desktop form)
734
- const topResult = inspectServers(content.mcpServers || content.servers || {}, `${configPath} top-level`);
735
- totalServersSeen += topResult.total;
736
- // Project-scoped (Claude Code shape): projects[*].mcpServers.ruflo
737
- if (content.projects && typeof content.projects === 'object') {
738
- for (const [projectKey, projectVal] of Object.entries(content.projects)) {
739
- const pm = projectVal?.mcpServers;
740
- if (pm && typeof pm === 'object') {
741
- const projectResult = inspectServers(pm, `${configPath} projects[${projectKey}]`);
742
- totalServersSeen += projectResult.total;
743
- }
744
- }
745
- }
746
- }
747
- catch {
748
- // continue to next path
749
- }
750
- }
751
- if (duplicateLocations.length > 0 || (legacyLocations.length > 0 && currentLocations.length > 0)) {
752
- const locations = duplicateLocations.length > 0
753
- ? duplicateLocations.join('; ')
754
- : `legacy ${legacyLocations.join('; ')} + current ${currentLocations.join('; ')}`;
755
- return {
756
- name: 'MCP Servers',
757
- status: 'warn',
758
- message: `Duplicate Ruflo MCP registrations found (${locations}) — Claude Code will start both tool schemas`,
759
- fix: 'Remove the legacy `ruflo`-keyed MCP registration (pre-rename duplicate) and keep the canonical `claude-flow` entry: `claude mcp add claude-flow -- npx -y ruflo@latest mcp start`. The canonical key stays `claude-flow` so the ~166 `mcp__claude-flow__*` plugin tool references keep resolving (#2206).',
760
- };
761
- }
762
- if (rufloLocations.length > 0) {
763
- return {
764
- name: 'MCP Servers',
765
- status: 'pass',
766
- message: `${totalServersSeen} servers (ruflo configured: ${rufloLocations.join('; ')})`,
767
- };
768
- }
769
- if (totalServersSeen > 0) {
770
- return {
771
- name: 'MCP Servers',
772
- status: 'warn',
773
- message: `${totalServersSeen} servers (ruflo not found)`,
774
- fix: 'claude mcp add claude-flow -- npx -y ruflo@latest mcp start',
775
- };
776
- }
777
- return {
778
- name: 'MCP Servers',
779
- status: 'warn',
780
- message: 'No MCP config found',
781
- fix: 'claude mcp add ruflo -- npx -y ruflo@latest mcp start',
782
- };
783
- }
784
- // Check disk space (async with proper env inheritance)
785
- async function checkDiskSpace() {
786
- try {
787
- if (process.platform === 'win32') {
788
- return { name: 'Disk Space', status: 'pass', message: 'Check skipped on Windows' };
789
- }
790
- // Use df -Ph for POSIX mode (guarantees single-line output even with long device names)
791
- const output_str = await runCommand('df -Ph . | tail -1');
792
- const parts = output_str.split(/\s+/);
793
- // POSIX format: Filesystem Size Used Avail Capacity Mounted
794
- const available = parts[3];
795
- const usePercent = parseInt(parts[4]?.replace('%', '') || '0', 10);
796
- if (isNaN(usePercent)) {
797
- return { name: 'Disk Space', status: 'warn', message: `${available || 'unknown'} available (unable to parse usage)` };
798
- }
799
- if (usePercent > 90) {
800
- return { name: 'Disk Space', status: 'fail', message: `${available} available (${usePercent}% used)`, fix: 'Free up disk space' };
801
- }
802
- else if (usePercent > 80) {
803
- return { name: 'Disk Space', status: 'warn', message: `${available} available (${usePercent}% used)` };
804
- }
805
- return { name: 'Disk Space', status: 'pass', message: `${available} available` };
806
- }
807
- catch {
808
- return { name: 'Disk Space', status: 'warn', message: 'Unable to check' };
809
- }
810
- }
811
- // Check TypeScript/build (async with proper env inheritance)
812
- async function checkBuildTools() {
813
- try {
814
- const tscVersion = await runCommand('npx tsc --version', 10000); // tsc can be slow
815
- if (!tscVersion || tscVersion.includes('not found')) {
816
- return { name: 'TypeScript', status: 'warn', message: 'Not installed locally', fix: 'npm install -D typescript' };
817
- }
818
- return { name: 'TypeScript', status: 'pass', message: tscVersion.replace('Version ', 'v') };
819
- }
820
- catch {
821
- return { name: 'TypeScript', status: 'warn', message: 'Not installed locally', fix: 'npm install -D typescript' };
822
- }
823
- }
824
- // Check for stale npx cache (version freshness)
825
- async function checkVersionFreshness() {
826
- try {
827
- // Get current CLI version from package.json
828
- // Use import.meta.url to reliably locate our own package.json,
829
- // regardless of how deep the compiled file sits (e.g. dist/src/commands/).
830
- let currentVersion = '0.0.0';
831
- try {
832
- const thisFile = fileURLToPath(import.meta.url);
833
- let dir = dirname(thisFile);
834
- // Walk up from the current file's directory until we find the
835
- // package.json that belongs to @claude-flow/cli (or claude-flow/cli).
836
- // Walk until dirname(dir) === dir (filesystem root on any platform).
837
- for (;;) {
838
- const candidate = join(dir, 'package.json');
839
- try {
840
- if (existsSync(candidate)) {
841
- const pkg = JSON.parse(readFileSync(candidate, 'utf8'));
842
- if (pkg.version &&
843
- typeof pkg.name === 'string' &&
844
- (pkg.name === '@claude-flow/cli' || pkg.name === 'claude-flow' || pkg.name === 'ruflo')) {
845
- currentVersion = pkg.version;
846
- break;
847
- }
848
- }
849
- }
850
- catch {
851
- // Unreadable/invalid JSON -- skip and keep walking up
852
- }
853
- const parent = dirname(dir);
854
- if (parent === dir)
855
- break; // reached root
856
- dir = parent;
857
- }
858
- }
859
- catch {
860
- // Fall back to a default
861
- currentVersion = '0.0.0';
862
- }
863
- // Check if running via npx (look for _npx in process path or argv)
864
- const isNpx = process.argv[1]?.includes('_npx') ||
865
- process.env.npm_execpath?.includes('npx') ||
866
- process.cwd().includes('_npx');
867
- // Query npm for latest version (using alpha tag since that's what we publish to)
868
- let latestVersion = currentVersion;
869
- try {
870
- const npmInfo = await runCommand('npm view @claude-flow/cli@alpha version', 5000);
871
- latestVersion = npmInfo.trim();
872
- }
873
- catch {
874
- // Can't reach npm registry - skip check
875
- return {
876
- name: 'Version Freshness',
877
- status: 'warn',
878
- message: `v${currentVersion} (cannot check registry)`
879
- };
880
- }
881
- // Parse version numbers for comparison (handle prerelease like 3.0.0-alpha.84)
882
- const parseVersion = (v) => {
883
- const match = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-[a-zA-Z]+\.(\d+))?/);
884
- if (!match)
885
- return { major: 0, minor: 0, patch: 0, prerelease: 0 };
886
- return {
887
- major: parseInt(match[1], 10) || 0,
888
- minor: parseInt(match[2], 10) || 0,
889
- patch: parseInt(match[3], 10) || 0,
890
- prerelease: parseInt(match[4], 10) || 0
891
- };
892
- };
893
- const current = parseVersion(currentVersion);
894
- const latest = parseVersion(latestVersion);
895
- // Compare versions (including prerelease number)
896
- const isOutdated = (latest.major > current.major ||
897
- (latest.major === current.major && latest.minor > current.minor) ||
898
- (latest.major === current.major && latest.minor === current.minor && latest.patch > current.patch) ||
899
- (latest.major === current.major && latest.minor === current.minor && latest.patch === current.patch && latest.prerelease > current.prerelease));
900
- if (isOutdated) {
901
- const fix = isNpx
902
- ? 'rm -rf ~/.npm/_npx/* && npx -y @claude-flow/cli@latest'
903
- : 'npm update @claude-flow/cli';
904
- return {
905
- name: 'Version Freshness',
906
- status: 'warn',
907
- message: `v${currentVersion} (latest: v${latestVersion})${isNpx ? ' [npx cache stale]' : ''}`,
908
- fix
909
- };
910
- }
911
- return {
912
- name: 'Version Freshness',
913
- status: 'pass',
914
- message: `v${currentVersion} (up to date)`
915
- };
916
- }
917
- catch (error) {
918
- return {
919
- name: 'Version Freshness',
920
- status: 'warn',
921
- message: 'Unable to check version freshness'
922
- };
923
- }
924
- }
925
- // Check Claude Code CLI (async with proper env inheritance)
926
- // ADR-150 — surface MetaHarness availability + harnessFit score in
927
- // the standard ruflo doctor flow. Graceful degradation: when metaharness
928
- // is not installed (no network, optionalDep skipped), the check returns
929
- // `warn` with a hint instead of `fail` — ruflo continues to function.
930
- /**
931
- * iter 45 — verify the ruflo-side MetaHarness integration is intact.
932
- *
933
- * The existing `checkMetaharness` verifies the UPSTREAM `metaharness`
934
- * package is reachable (warn if missing — it's optional per ADR-150).
935
- * This check verifies the INTEGRATION LAYER (plugin scripts, production
936
- * module, subprocess bridge) is intact. Unlike upstream, the integration
937
- * layer is shipped with ruflo — missing files mean ruflo's install is
938
- * corrupted, not that an optional dep is absent.
939
- *
940
- * Status mapping:
941
- * pass — all required files present + module loads + similarity() smoke OK
942
- * fail — any required file missing OR module fails to import
943
- * warn — files present but module import errored at runtime
944
- *
945
- * Verified files (iter 36-53 surfaces — full ADR-150 deep-integration set):
946
- * - plugins/ruflo-metaharness/scripts/_harness.mjs (subprocess bridge)
947
- * - plugins/ruflo-metaharness/scripts/_similarity.mjs (ADR-152 §3.1 module, iter 36)
948
- * - plugins/ruflo-metaharness/scripts/similarity.mjs (CLI skill, iter 36)
949
- * - plugins/ruflo-metaharness/scripts/_spike-similarity.mjs (regression anchor, iter 35)
950
- * - plugins/ruflo-metaharness/scripts/drift-from-history.mjs (1-command primitive, iter 53)
951
- * - plugins/ruflo-metaharness/skills/harness-similarity/SKILL.md
952
- * - plugins/ruflo-metaharness/skills/harness-drift-from-history/SKILL.md (iter 53)
953
- */
954
- /**
955
- * ADR-305 — funnel state audit. Reports the effective enabled/disabled
956
- * state and, critically for enterprise audit verification, WHICH
957
- * precedence source decided it (env > enterprise > user > default).
958
- * Informational: both states are `pass`; only a resolver failure warns.
959
- */
960
- async function checkFunnel() {
961
- try {
962
- const { resolveFunnelEnabled, getDisclosure } = await import('../funnel/index.js');
963
- const decision = resolveFunnelEnabled();
964
- const disclosure = getDisclosure();
965
- return {
966
- name: 'Funnel (ADR-305)',
967
- status: 'pass',
968
- message: `${decision.enabled ? 'enabled' : 'disabled'} (decided by: ${decision.decidedBy}; disclosure: ${disclosure.state})`,
969
- };
970
- }
971
- catch (err) {
972
- return {
973
- name: 'Funnel (ADR-305)',
974
- status: 'warn',
975
- message: `state unreadable: ${err instanceof Error ? err.message : String(err)}`,
976
- fix: 'ruflo funnel status',
977
- };
978
- }
979
- }
980
- /** Meta LLM Proxy — sponsored-downtime health (ADR-313). */
981
- async function checkProxy() {
982
- try {
983
- const { funnelStateDir, hasConsent, readRateLimitStatus, lastRecordedEvent } = await import('../funnel/index.js');
984
- const dir = funnelStateDir();
985
- const installed = existsSync(join(dir, 'proxy-token'));
986
- const consented = hasConsent('sponsored-downtime');
987
- const rateLimited = readRateLimitStatus();
988
- const lastExhausted = lastRecordedEvent('sponsor_capacity_exhausted');
989
- if (!installed) {
990
- return {
991
- name: 'Meta LLM Proxy (ADR-313)',
992
- status: 'warn',
993
- message: 'not installed — no proxy-token found; sponsored-downtime capacity is unavailable',
994
- fix: 'See cognitum-one/meta-proxy (private) for install instructions',
995
- };
996
- }
997
- const parts = [
998
- `sponsored consent: ${consented ? 'granted' : 'not granted'}`,
999
- `rate-limit flag: ${rateLimited.limited ? `set (since ${rateLimited.since})` : 'not set'}`,
1000
- ];
1001
- if (lastExhausted)
1002
- parts.push(`last capacity-exhausted: ${lastExhausted}`);
1003
- if (rateLimited.limited && !consented) {
1004
- return {
1005
- name: 'Meta LLM Proxy (ADR-313)',
1006
- status: 'warn',
1007
- message: `${parts.join('; ')} — flagged rate-limited but sponsored capacity isn't enabled`,
1008
- fix: 'ruflo proxy sponsor-enable --yes',
1009
- };
1010
- }
1011
- return { name: 'Meta LLM Proxy (ADR-313)', status: 'pass', message: parts.join('; ') };
1012
- }
1013
- catch (err) {
1014
- return {
1015
- name: 'Meta LLM Proxy (ADR-313)',
1016
- status: 'warn',
1017
- message: `state unreadable: ${err instanceof Error ? err.message : String(err)}`,
1018
- fix: 'ruflo proxy sponsor-status',
1019
- };
1020
- }
1021
- }
1022
- async function checkMetaharnessIntegration() {
1023
- // Locate plugins dir.
1024
- //
1025
- // Pre-#2437 fix this only walked up from `process.cwd()` + checked one
1026
- // hard-coded `<cwd>/node_modules/@claude-flow/cli/...` candidate. That
1027
- // missed the two cases users actually run from:
1028
- // (a) `npx @claude-flow/cli@<tag>` → resolves to a per-version cache
1029
- // under `~/.npm/_npx/<hash>/node_modules/@claude-flow/cli/...`
1030
- // (b) `npm install -g @claude-flow/cli` → lives at
1031
- // `$(npm prefix -g)/lib/node_modules/@claude-flow/cli/...`
1032
- //
1033
- // The bulletproof fix: resolve relative to THIS file's own location via
1034
- // `import.meta.url`. The plugins dir is always a sibling of the package
1035
- // root regardless of where the package was installed. Walk up from
1036
- // `dist/src/commands/doctor.js` (built) or `src/commands/doctor.ts`
1037
- // (dev) until we find a directory containing `plugins/ruflo-metaharness/`.
1038
- const candidates = [];
1039
- // Strategy 1: walk up from this module's own URL — covers npx + global install.
1040
- try {
1041
- const selfDir = dirname(fileURLToPath(import.meta.url));
1042
- let q = selfDir;
1043
- for (let i = 0; i < 8; i++) {
1044
- candidates.push(join(q, 'plugins', 'ruflo-metaharness'));
1045
- q = dirname(q);
1046
- }
1047
- }
1048
- catch {
1049
- // import.meta.url unavailable under some bundlers — fall through to cwd walk.
1050
- }
1051
- // Strategy 2: walk up from cwd — covers monorepo dev (running from a sub-package).
1052
- let p = process.cwd();
1053
- for (let i = 0; i < 8; i++) {
1054
- candidates.push(join(p, 'plugins', 'ruflo-metaharness'));
1055
- p = dirname(p);
1056
- }
1057
- // Strategy 3: explicit node_modules path relative to cwd — covers project-local install.
1058
- candidates.push(join(process.cwd(), 'node_modules', '@claude-flow', 'cli', 'plugins', 'ruflo-metaharness'));
1059
- let pluginDir = null;
1060
- for (const c of candidates) {
1061
- if (existsSync(join(c, 'scripts', '_harness.mjs'))) {
1062
- pluginDir = c;
1063
- break;
1064
- }
1065
- }
1066
- if (!pluginDir) {
1067
- // #2437: MetaHarness is documented as an optional dependency in
1068
- // optionalDependencies (per ADR-150 architectural constraint #2 —
1069
- // "Optional in package.json"). A genuinely-absent plugin therefore
1070
- // warrants WARN, not FAIL — same posture as the runtime path which
1071
- // returns {degraded: true, exit 0}. FAIL is reserved for misconfigured
1072
- // installs where the plugin SHOULD be present but is broken.
1073
- return {
1074
- name: 'MetaHarness integration (ADR-150)',
1075
- status: 'warn',
1076
- message: 'plugins/ruflo-metaharness/ not found — MetaHarness skills will degrade gracefully',
1077
- fix: 'Optional: install via `npm i -D @metaharness/darwin metaharness` or run `ruflo plugins install ruflo-metaharness`',
1078
- };
1079
- }
1080
- // Required files (iter 36+44 surfaces, +ADR-153 darwin surfaces in v3.13.0)
1081
- const required = [
1082
- 'scripts/_harness.mjs',
1083
- 'scripts/_similarity.mjs',
1084
- 'scripts/similarity.mjs',
1085
- 'scripts/_spike-similarity.mjs',
1086
- // iter 53 surfaces — gated against silent deletion
1087
- 'scripts/drift-from-history.mjs',
1088
- 'skills/harness-similarity/SKILL.md',
1089
- 'skills/harness-drift-from-history/SKILL.md',
1090
- // ADR-153 Darwin Mode surfaces (v3.13.0) — added to gate against silent deletion
1091
- 'scripts/_darwin.mjs',
1092
- 'scripts/evolve.mjs',
1093
- 'scripts/security-bench.mjs',
1094
- 'scripts/bench.mjs',
1095
- 'skills/harness-evolve/SKILL.md',
1096
- 'skills/harness-security-bench/SKILL.md',
1097
- 'skills/harness-bench/SKILL.md',
1098
- ];
1099
- const missing = required.filter((f) => !existsSync(join(pluginDir, f)));
1100
- if (missing.length > 0) {
1101
- return {
1102
- name: 'MetaHarness integration (ADR-150)',
1103
- status: 'fail',
1104
- message: `Missing files: ${missing.join(', ')}`,
1105
- fix: 'Reinstall ruflo or restore from git: `git checkout HEAD -- plugins/ruflo-metaharness/`',
1106
- };
1107
- }
1108
- // Runtime smoke: import the similarity module and exercise it
1109
- try {
1110
- const modPath = join(pluginDir, 'scripts', '_similarity.mjs');
1111
- const mod = await import(modPath);
1112
- if (typeof mod.similarity !== 'function') {
1113
- return {
1114
- name: 'MetaHarness integration (ADR-150)',
1115
- status: 'fail',
1116
- message: '_similarity.mjs does not export similarity()',
1117
- fix: 'Reinstall ruflo or restore the file from git',
1118
- };
1119
- }
1120
- const result = mod.similarity({}, {});
1121
- if (typeof result?.overall !== 'number') {
1122
- return {
1123
- name: 'MetaHarness integration (ADR-150)',
1124
- status: 'warn',
1125
- message: 'similarity() returned unexpected shape; module may be stale',
1126
- };
1127
- }
1128
- // iter 52 — also verify the iter-50 mcp-scan text parser exports
1129
- // correctly. parseMcpScanText is the shared util both mcp-scan.mjs
1130
- // and oia-audit.mjs depend on; if it's missing the audit-trend
1131
- // introduced/cleared diff silently degrades to dead code.
1132
- //
1133
- // iter 61 — additionally verify iter-56's async exports
1134
- // (runHarnessAsync / runMetaharnessAsync). These are the
1135
- // parallelization primitives oia-audit depends on; if they're
1136
- // missing, oia-audit's import fails and the whole pipeline breaks.
1137
- const harnessPath = join(pluginDir, 'scripts', '_harness.mjs');
1138
- const harnessMod = await import(harnessPath);
1139
- if (typeof harnessMod.parseMcpScanText !== 'function') {
1140
- return {
1141
- name: 'MetaHarness integration (ADR-150)',
1142
- status: 'fail',
1143
- message: '_harness.mjs does not export parseMcpScanText (iter 50 — needed by mcp-scan + oia-audit)',
1144
- fix: 'Reinstall ruflo or restore _harness.mjs from git',
1145
- };
1146
- }
1147
- if (typeof harnessMod.runHarnessAsync !== 'function' || typeof harnessMod.runMetaharnessAsync !== 'function') {
1148
- return {
1149
- name: 'MetaHarness integration (ADR-150)',
1150
- status: 'fail',
1151
- message: '_harness.mjs missing iter-56 async exports (runHarnessAsync / runMetaharnessAsync) — oia-audit parallelization will fail',
1152
- fix: 'Reinstall ruflo or restore _harness.mjs from git',
1153
- };
1154
- }
1155
- // Smoke: parser handles empty input gracefully
1156
- const parsed = harnessMod.parseMcpScanText('');
1157
- if (!Array.isArray(parsed?.findings)) {
1158
- return {
1159
- name: 'MetaHarness integration (ADR-150)',
1160
- status: 'warn',
1161
- message: 'parseMcpScanText returned unexpected shape on empty input',
1162
- };
1163
- }
1164
- return {
1165
- name: 'MetaHarness integration (ADR-150)',
1166
- status: 'pass',
1167
- message: 'plugin scripts intact, _similarity.mjs + parseMcpScanText load, smoke OK',
1168
- };
1169
- }
1170
- catch (e) {
1171
- return {
1172
- name: 'MetaHarness integration (ADR-150)',
1173
- status: 'warn',
1174
- message: `Module import errored: ${e.message.slice(0, 60)}`,
1175
- };
1176
- }
1177
- }
1178
- async function checkMetaharness() {
1179
- try {
1180
- const version = await runCommand('npx -y metaharness@latest --version 2>&1', 15000);
1181
- // metaharness emits multi-line stdout; parse a version-shaped line.
1182
- const versionMatch = version.match(/(\d+\.\d+\.\d+)/);
1183
- if (!versionMatch) {
1184
- return {
1185
- name: 'MetaHarness (ADR-150)',
1186
- status: 'warn',
1187
- message: 'Installed but version-string not parseable; integration may still work',
1188
- };
1189
- }
1190
- return {
1191
- name: 'MetaHarness (ADR-150)',
1192
- status: 'pass',
1193
- message: `v${versionMatch[1]} — run \`npx ruflo metaharness score\` for the full scorecard`,
1194
- };
1195
- }
1196
- catch {
1197
- return {
1198
- name: 'MetaHarness (ADR-150)',
1199
- status: 'warn',
1200
- message: 'Not installed — `npx ruflo metaharness *` commands will degrade gracefully',
1201
- fix: 'npm install --include=optional # to enable the metaharness optional dep',
1202
- };
1203
- }
1204
- }
1205
- async function checkClaudeCode() {
1206
- try {
1207
- const version = await runCommand('claude --version');
1208
- // Parse version from output like "claude 1.0.0" or "Claude Code v1.0.0"
1209
- const versionMatch = version.match(/v?(\d+\.\d+\.\d+)/);
1210
- const versionStr = versionMatch ? `v${versionMatch[1]}` : version;
1211
- return { name: 'Claude Code CLI', status: 'pass', message: versionStr };
1212
- }
1213
- catch {
1214
- return {
1215
- name: 'Claude Code CLI',
1216
- status: 'warn',
1217
- message: 'Not installed',
1218
- fix: 'npm install -g @anthropic-ai/claude-code'
1219
- };
1220
- }
1221
- }
1222
- // Install Claude Code CLI
1223
- async function installClaudeCode() {
1224
- try {
1225
- output.writeln();
1226
- output.writeln(output.bold('Installing Claude Code CLI...'));
1227
- execSync('npm install -g @anthropic-ai/claude-code', {
1228
- encoding: 'utf8',
1229
- stdio: 'inherit'
1230
- });
1231
- output.writeln(output.success('Claude Code CLI installed successfully!'));
1232
- return true;
1233
- }
1234
- catch (error) {
1235
- output.writeln(output.error('Failed to install Claude Code CLI'));
1236
- if (error instanceof Error) {
1237
- output.writeln(output.dim(error.message));
1238
- }
1239
- return false;
1240
- }
1241
- }
1242
- // Check agentic-flow v3 integration (filesystem-based to avoid slow WASM/DB init)
1243
- async function checkAgenticFlow() {
1244
- try {
1245
- // Walk common node_modules paths to find agentic-flow/package.json
1246
- const candidates = [
1247
- join(process.cwd(), 'node_modules', 'agentic-flow', 'package.json'),
1248
- join(process.cwd(), '..', 'node_modules', 'agentic-flow', 'package.json'),
1249
- ];
1250
- let pkgJsonPath = null;
1251
- for (const p of candidates) {
1252
- if (existsSync(p)) {
1253
- pkgJsonPath = p;
1254
- break;
1255
- }
1256
- }
1257
- if (!pkgJsonPath) {
1258
- return {
1259
- name: 'agentic-flow',
1260
- status: 'warn',
1261
- message: 'Not installed (optional — embeddings/routing will use fallbacks)',
1262
- fix: 'npm install agentic-flow@latest'
1263
- };
1264
- }
1265
- const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
1266
- const version = pkg.version || 'unknown';
1267
- const exports = pkg.exports || {};
1268
- const features = [
1269
- exports['./reasoningbank'] ? 'ReasoningBank' : null,
1270
- exports['./router'] ? 'Router' : null,
1271
- exports['./transport/quic'] ? 'QUIC' : null,
1272
- ].filter(Boolean);
1273
- return {
1274
- name: 'agentic-flow',
1275
- status: 'pass',
1276
- message: `v${version} (${features.join(', ')})`
1277
- };
1278
- }
1279
- catch {
1280
- return { name: 'agentic-flow', status: 'warn', message: 'Check failed' };
1281
- }
1282
- }
1283
- // Check encryption-at-rest status (ADR-096 Phase 5)
1284
- //
1285
- // Reports four facets without disclosing the key itself:
1286
- // 1. Gate status — is CLAUDE_FLOW_ENCRYPT_AT_REST set?
1287
- // 2. Key resolution — does CLAUDE_FLOW_ENCRYPTION_KEY resolve to a valid
1288
- // 32-byte key (env-var path only; keychain/passphrase are deferred)?
1289
- // 3. Key fingerprint — first 16 hex chars of sha256(key) so users can
1290
- // sanity-check across machines without ever logging the key bytes.
1291
- // 4. High-tier store presence — for sessions/, terminals/, .swarm/memory.db
1292
- // report whether on-disk bytes carry the RFE1 magic (encrypted) or not.
1293
- async function checkEncryptionAtRest() {
1294
- if (!isEncryptionEnabled()) {
1295
- return {
1296
- name: 'Encryption at Rest',
1297
- status: 'warn',
1298
- message: 'Off — session/terminal/memory stores are plaintext (mode 0600 only)',
1299
- fix: 'export CLAUDE_FLOW_ENCRYPT_AT_REST=1 && export CLAUDE_FLOW_ENCRYPTION_KEY=<64-char-hex>',
1300
- };
1301
- }
1302
- // Gate is on — try to resolve the key. Fail-closed if missing or malformed.
1303
- const rawKey = process.env.CLAUDE_FLOW_ENCRYPTION_KEY;
1304
- if (!rawKey) {
1305
- return {
1306
- name: 'Encryption at Rest',
1307
- status: 'fail',
1308
- message: 'Gate is on but CLAUDE_FLOW_ENCRYPTION_KEY is unset (fail-closed)',
1309
- fix: 'Generate a key: openssl rand -hex 32 → export CLAUDE_FLOW_ENCRYPTION_KEY=<value>',
1310
- };
1311
- }
1312
- let keyFingerprint;
1313
- try {
1314
- const key = decodeKey(rawKey);
1315
- keyFingerprint = createHash('sha256').update(key).digest('hex').slice(0, 16);
1316
- }
1317
- catch (err) {
1318
- return {
1319
- name: 'Encryption at Rest',
1320
- status: 'fail',
1321
- message: `CLAUDE_FLOW_ENCRYPTION_KEY invalid: ${err instanceof Error ? err.message : String(err)}`,
1322
- fix: 'Provide a 64-char hex or 44-char base64 key (32 bytes)',
1323
- };
1324
- }
1325
- // Check the three high-tier store paths for RFE1 magic
1326
- const cwd = process.cwd();
1327
- const stores = [
1328
- { label: 'sessions/', path: join(cwd, '.claude-flow', 'sessions') },
1329
- { label: 'terminals', path: join(cwd, '.claude-flow', 'terminals', 'store.json') },
1330
- { label: 'memory.db', path: join(cwd, '.swarm', 'memory.db') },
1331
- ];
1332
- const status = [];
1333
- for (const s of stores) {
1334
- if (!existsSync(s.path)) {
1335
- status.push(`${s.label}=∅`);
1336
- continue;
1337
- }
1338
- try {
1339
- const stat = statSync(s.path);
1340
- if (stat.isDirectory()) {
1341
- // Sessions: probe the first .json file
1342
- const { readdirSync } = await import('fs');
1343
- const files = readdirSync(s.path).filter(f => f.endsWith('.json'));
1344
- if (files.length === 0) {
1345
- status.push(`${s.label}=∅`);
1346
- continue;
1347
- }
1348
- const first = readFileSync(join(s.path, files[0]));
1349
- status.push(`${s.label}=${isEncryptedBlob(first) ? 'enc' : 'plain'}`);
1350
- }
1351
- else {
1352
- const buf = readFileSync(s.path);
1353
- status.push(`${s.label}=${isEncryptedBlob(buf) ? 'enc' : 'plain'}`);
1354
- }
1355
- }
1356
- catch {
1357
- status.push(`${s.label}=err`);
1358
- }
1359
- }
1360
- return {
1361
- name: 'Encryption at Rest',
1362
- status: 'pass',
1363
- message: `On — key fp:${keyFingerprint}… (${status.join(' ')})`,
1364
- };
1365
- }
1366
- // Format health check result
1367
- function formatCheck(check) {
1368
- const icon = check.status === 'pass' ? output.success('✓') :
1369
- check.status === 'warn' ? output.warning('⚠') :
1370
- output.error('✗');
1371
- return `${icon} ${check.name}: ${check.message}`;
1372
- }
1373
- // Main doctor command
1374
- export const doctorCommand = {
1375
- name: 'doctor',
1376
- description: 'System diagnostics and health checks',
1377
- options: [
1378
- {
1379
- name: 'fix',
1380
- short: 'f',
1381
- // #1791.5 — flag name was misleading: it does NOT auto-apply fixes,
1382
- // it only prints the suggested commands so the user can run them
1383
- // themselves. Make that explicit in the help output.
1384
- description: 'Print suggested fix commands (does not auto-apply — copy/paste them yourself)',
1385
- type: 'boolean',
1386
- default: false
1387
- },
1388
- {
1389
- name: 'install',
1390
- short: 'i',
1391
- description: 'Auto-install missing dependencies (Claude Code CLI)',
1392
- type: 'boolean',
1393
- default: false
1394
- },
1395
- {
1396
- name: 'component',
1397
- short: 'c',
1398
- description: 'Check specific component (version, node, npm, config, daemon, memory, api, git, mcp, claude, disk, typescript, agentic-flow, encryption, federation, funnel, proxy, metaharness)',
1399
- type: 'string'
1400
- },
1401
- {
1402
- name: 'verbose',
1403
- short: 'v',
1404
- description: 'Verbose output',
1405
- type: 'boolean',
1406
- default: false
1407
- },
1408
- {
1409
- name: 'fix-handles',
1410
- // Windows-only mitigation for anthropics/claude-code#67888 — Claude Code's
1411
- // Bash tool spawns cmd.exe/bash.exe without cleaning up child conhost.exe
1412
- // handles, so a long session accumulates dozens (observed live: 26+
1413
- // orphaned conhost.exe after a ~4h session). Each holds a kernel object
1414
- // + ~1MB, and combined with memory pressure this measurably slows the
1415
- // machine. This flag kills orphan conhost.exe (safe — Windows respawns
1416
- // on demand). Deliberately does NOT touch cmd.exe/bash.exe — those can
1417
- // be the invoking shell, and killing them 255's the caller.
1418
- description: 'Windows only: kill orphaned conhost.exe processes leaked by Claude Code (mitigation for anthropics/claude-code#67888)',
1419
- type: 'boolean',
1420
- default: false
1421
- }
1422
- ],
1423
- examples: [
1424
- { command: 'claude-flow doctor', description: 'Run full health check' },
1425
- { command: 'claude-flow doctor --fix', description: 'Print suggested fix commands (does not auto-apply)' },
1426
- { command: 'claude-flow doctor --install', description: 'Auto-install missing dependencies' },
1427
- { command: 'claude-flow doctor -c version', description: 'Check for stale npx cache' },
1428
- { command: 'claude-flow doctor -c claude', description: 'Check Claude Code CLI only' },
1429
- { command: 'claude-flow doctor --fix-handles', description: 'Windows: kill leaked conhost.exe from Claude Code sessions' }
1430
- ],
1431
- action: async (ctx) => {
1432
- const showFix = ctx.flags.fix;
1433
- const autoInstall = ctx.flags.install;
1434
- const component = ctx.flags.component;
1435
- const verbose = ctx.flags.verbose;
1436
- // Parser camelCases kebab-case flag names — read via `fixHandles`, not `['fix-handles']`.
1437
- const fixHandles = ctx.flags.fixHandles;
1438
- // Early-return short-circuit: `--fix-handles` is a targeted mitigation, not
1439
- // part of the health-check flow. Runs, reports, exits.
1440
- if (fixHandles) {
1441
- output.writeln();
1442
- output.writeln(output.bold('RuFlo Doctor — fix-handles'));
1443
- output.writeln(output.dim('─'.repeat(50)));
1444
- output.writeln();
1445
- if (process.platform !== 'win32') {
1446
- output.printInfo('--fix-handles is a Windows-only mitigation. On this platform (' + process.platform + '), no action taken.');
1447
- return { success: true };
1448
- }
1449
- const { spawnSync } = await import('child_process');
1450
- // PowerShell one-liner: read before-count, kill conhost, read after-count, report delta.
1451
- const psScript = [
1452
- "$before = (Get-Process conhost -EA SilentlyContinue).Count",
1453
- "$mem_before = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)",
1454
- "$killed = 0",
1455
- "Get-Process conhost -EA SilentlyContinue | ForEach-Object {",
1456
- " try { Stop-Process -Id $_.Id -Force -EA Stop; $killed++ } catch {}",
1457
- "}",
1458
- "Start-Sleep -Seconds 1",
1459
- "$after = (Get-Process conhost -EA SilentlyContinue).Count",
1460
- "$mem_after = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)",
1461
- "Write-Output ('BEFORE_COUNT=' + $before)",
1462
- "Write-Output ('KILLED=' + $killed)",
1463
- "Write-Output ('AFTER_COUNT=' + $after)",
1464
- "Write-Output ('MEM_BEFORE_GB=' + $mem_before)",
1465
- "Write-Output ('MEM_AFTER_GB=' + $mem_after)",
1466
- ].join('; ');
1467
- const res = spawnSync('powershell', ['-NoProfile', '-Command', psScript], {
1468
- encoding: 'utf-8', timeout: 30000, windowsHide: true,
1469
- });
1470
- if (res.status !== 0) {
1471
- output.printError('PowerShell exited with code ' + res.status);
1472
- if (res.stderr)
1473
- output.writeln(output.dim(res.stderr));
1474
- return { success: false, exitCode: 1 };
1475
- }
1476
- const parse = (key) => {
1477
- const line = (res.stdout || '').split('\n').find((l) => l.startsWith(key + '='));
1478
- return line ? line.slice(key.length + 1).trim() : '?';
1479
- };
1480
- const before = parse('BEFORE_COUNT');
1481
- const killed = parse('KILLED');
1482
- const after = parse('AFTER_COUNT');
1483
- const memBefore = parse('MEM_BEFORE_GB');
1484
- const memAfter = parse('MEM_AFTER_GB');
1485
- output.writeln('conhost.exe processes:');
1486
- output.writeln(' before: ' + before);
1487
- output.writeln(' killed: ' + output.success(killed));
1488
- output.writeln(' after: ' + after);
1489
- output.writeln('');
1490
- output.writeln('Free RAM:');
1491
- output.writeln(' before: ' + memBefore + ' GB');
1492
- output.writeln(' after: ' + memAfter + ' GB');
1493
- output.writeln('');
1494
- output.writeln(output.dim('Note: does NOT touch cmd.exe/bash.exe/node.exe — those may be the invoking shell'));
1495
- output.writeln(output.dim(' or an active MCP server. Kill them manually if you need to.'));
1496
- output.writeln('');
1497
- output.writeln(output.dim('Upstream tracking: https://github.com/anthropics/claude-code/issues/67888'));
1498
- return { success: true };
1499
- }
1500
- output.writeln();
1501
- output.writeln(output.bold('RuFlo Doctor'));
1502
- output.writeln(output.dim('System diagnostics and health check'));
1503
- output.writeln(output.dim('─'.repeat(50)));
1504
- output.writeln();
1505
- const allChecks = [
1506
- checkVersionFreshness,
1507
- checkNodeVersion,
1508
- checkNpmVersion,
1509
- checkClaudeCode,
1510
- checkGit,
1511
- checkGitRepo,
1512
- checkConfigFile,
1513
- checkStaleSettingsNpx, // #2448 — runaway `npx @latest` in statusLine/hooks
1514
- checkDaemonStatus,
1515
- checkMemoryDatabase,
1516
- checkLearningBridge, // #2545 — can the auto-memory hook actually load @claude-flow/memory?
1517
- checkApiKeys,
1518
- checkMcpServers,
1519
- checkAIDefence, // #1807
1520
- checkDiskSpace,
1521
- checkBuildTools,
1522
- checkAgenticFlow,
1523
- checkEncryptionAtRest, // ADR-096 Phase 5
1524
- checkFederationBreaker, // ADR-097 Phase 4
1525
- checkMetaharness, // ADR-150 — MetaHarness upstream package
1526
- checkMetaharnessIntegration, // iter 45 — ruflo-side integration layer
1527
- checkFunnel, // ADR-305 — effective funnel state + deciding precedence source
1528
- checkProxy, // ADR-313 — Meta LLM Proxy sponsored-downtime health
1529
- ];
1530
- // #2677: `--component memory` now runs the whole memory-health suite,
1531
- // not just the existence check. Values can be a single check or an
1532
- // array — expanded at execution time. Stuinfla's report showed the
1533
- // existence-only check reporting PASS on a 99.97%-empty and even a
1534
- // SQLite-malformed DB; the array here layers integrity → content →
1535
- // embedding coverage over the existing existence probe, ordered so
1536
- // the earliest chain-break is always the first red the user sees.
1537
- const componentMap = {
1538
- 'version': checkVersionFreshness,
1539
- 'freshness': checkVersionFreshness,
1540
- 'node': checkNodeVersion,
1541
- 'npm': checkNpmVersion,
1542
- 'claude': checkClaudeCode,
1543
- 'config': checkConfigFile,
1544
- 'stale-settings': checkStaleSettingsNpx, // #2448
1545
- 'daemon': checkDaemonStatus,
1546
- 'memory': [
1547
- checkMemoryDatabase, // existing: exists + statable (unchanged)
1548
- checkMemoryIntegrity, // #2677 check 1: sql.js open + PRAGMA integrity_check
1549
- checkMemoryContent, // #2677 check 2: memory_entries content coverage
1550
- checkMemoryEmbeddingCoverage, // #2677 check 3: vector coverage on populated rows
1551
- ],
1552
- 'learning': checkLearningBridge, // #2545
1553
- 'learning-bridge': checkLearningBridge, // #2545
1554
- 'api': checkApiKeys,
1555
- 'git': checkGit,
1556
- 'mcp': checkMcpServers,
1557
- 'aidefence': checkAIDefence, // #1807
1558
- 'disk': checkDiskSpace,
1559
- 'typescript': checkBuildTools,
1560
- 'agentic-flow': checkAgenticFlow,
1561
- 'encryption': checkEncryptionAtRest, // ADR-096 Phase 5
1562
- 'federation': checkFederationBreaker, // ADR-097 Phase 4
1563
- 'metaharness': checkMetaharness, // ADR-150 — upstream package
1564
- 'metaharness-integration': checkMetaharnessIntegration, // iter 45 — ruflo-side
1565
- 'funnel': checkFunnel, // ADR-305
1566
- 'proxy': checkProxy, // ADR-313
1567
- };
1568
- let checksToRun = allChecks;
1569
- if (component && componentMap[component]) {
1570
- const entry = componentMap[component];
1571
- checksToRun = Array.isArray(entry) ? entry : [entry];
1572
- }
1573
- const results = [];
1574
- const fixes = [];
1575
- // OPTIMIZATION: Run all checks in parallel for 3-5x faster execution
1576
- const spinner = output.createSpinner({ text: 'Running health checks in parallel...', spinner: 'dots' });
1577
- spinner.start();
1578
- try {
1579
- // Execute all checks concurrently
1580
- const checkResults = await Promise.allSettled(checksToRun.map(check => check()));
1581
- spinner.stop();
1582
- // Process results in order
1583
- for (const settledResult of checkResults) {
1584
- if (settledResult.status === 'fulfilled') {
1585
- const result = settledResult.value;
1586
- results.push(result);
1587
- output.writeln(formatCheck(result));
1588
- if (result.fix && (result.status === 'fail' || result.status === 'warn')) {
1589
- fixes.push(`${result.name}: ${result.fix}`);
1590
- }
1591
- }
1592
- else {
1593
- const errorResult = {
1594
- name: 'Check',
1595
- status: 'fail',
1596
- message: settledResult.reason?.message || 'Unknown error'
1597
- };
1598
- results.push(errorResult);
1599
- output.writeln(formatCheck(errorResult));
1600
- }
1601
- }
1602
- }
1603
- catch (error) {
1604
- spinner.stop();
1605
- output.writeln(output.error('Failed to run health checks'));
1606
- }
1607
- // #2545: --fix / --install can actually repair the Learning Bridge by
1608
- // recording the resolver sidecar. When doctor runs via `npx ruflo`, the CLI
1609
- // CAN resolve its optional @claude-flow/memory dep (it is in the same npx
1610
- // cache), so writing the sidecar makes the SessionStart hook find it.
1611
- if ((showFix || autoInstall)) {
1612
- const lbResult = results.find(r => r.name === 'Learning Bridge');
1613
- if (lbResult && lbResult.status === 'fail') {
1614
- const record = recordMemoryPackagePath(process.cwd(), 'doctor');
1615
- if (record) {
1616
- const newCheck = await checkLearningBridge();
1617
- const idx = results.findIndex(r => r.name === 'Learning Bridge');
1618
- if (idx !== -1)
1619
- results[idx] = newCheck;
1620
- const fixIdx = fixes.findIndex(f => f.startsWith('Learning Bridge:'));
1621
- if (fixIdx !== -1 && newCheck.status === 'pass')
1622
- fixes.splice(fixIdx, 1);
1623
- output.writeln(output.success(`Repaired Learning Bridge — wrote .claude-flow/memory-package.json → ${record.distPath}`));
1624
- output.writeln(formatCheck(newCheck));
1625
- }
1626
- }
1627
- }
1628
- // Auto-install missing dependencies if requested
1629
- if (autoInstall) {
1630
- const claudeCodeResult = results.find(r => r.name === 'Claude Code CLI');
1631
- if (claudeCodeResult && claudeCodeResult.status !== 'pass') {
1632
- const installed = await installClaudeCode();
1633
- if (installed) {
1634
- // Re-check Claude Code after installation
1635
- const newCheck = await checkClaudeCode();
1636
- const idx = results.findIndex(r => r.name === 'Claude Code CLI');
1637
- if (idx !== -1) {
1638
- results[idx] = newCheck;
1639
- // Update fixes list
1640
- const fixIdx = fixes.findIndex(f => f.startsWith('Claude Code CLI:'));
1641
- if (fixIdx !== -1 && newCheck.status === 'pass') {
1642
- fixes.splice(fixIdx, 1);
1643
- }
1644
- }
1645
- output.writeln(formatCheck(newCheck));
1646
- }
1647
- }
1648
- }
1649
- // Summary
1650
- const passed = results.filter(r => r.status === 'pass').length;
1651
- const warnings = results.filter(r => r.status === 'warn').length;
1652
- const failed = results.filter(r => r.status === 'fail').length;
1653
- output.writeln();
1654
- output.writeln(output.dim('─'.repeat(50)));
1655
- output.writeln();
1656
- const summaryParts = [
1657
- output.success(`${passed} passed`),
1658
- warnings > 0 ? output.warning(`${warnings} warnings`) : null,
1659
- failed > 0 ? output.error(`${failed} failed`) : null
1660
- ].filter(Boolean);
1661
- output.writeln(`Summary: ${summaryParts.join(', ')}`);
1662
- // Show fixes — #1791.5: header makes it explicit these are commands you
1663
- // run yourself, not actions doctor took.
1664
- if (showFix && fixes.length > 0) {
1665
- output.writeln();
1666
- output.writeln(output.bold('Suggested commands (run them yourself):'));
1667
- output.writeln();
1668
- for (const fix of fixes) {
1669
- output.writeln(output.dim(` ${fix}`));
1670
- }
1671
- }
1672
- else if (fixes.length > 0 && !showFix) {
1673
- output.writeln();
1674
- output.writeln(output.dim(`Run with --fix to see ${fixes.length} suggested command${fixes.length > 1 ? 's' : ''} (does not auto-apply)`));
1675
- }
1676
- // Overall result
1677
- if (failed > 0) {
1678
- output.writeln();
1679
- output.writeln(output.error('Some checks failed. Please address the issues above.'));
1680
- return { success: false, exitCode: 1, data: { passed, warnings, failed, results } };
1681
- }
1682
- else if (warnings > 0) {
1683
- output.writeln();
1684
- output.writeln(output.warning('All checks passed with some warnings.'));
1685
- return { success: true, data: { passed, warnings, failed, results } };
1686
- }
1687
- else {
1688
- output.writeln();
1689
- output.writeln(output.success('All checks passed! System is healthy.'));
1690
- return { success: true, data: { passed, warnings, failed, results } };
1691
- }
1692
- }
1693
- };
1694
- export default doctorCommand;
1695
- //# sourceMappingURL=doctor.js.map