claude-flow 3.42.1 → 3.42.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 (461) hide show
  1. package/.claude/agents/MIGRATION_SUMMARY.md +221 -221
  2. package/.claude/agents/analysis/analyze-code-quality.md +57 -57
  3. package/.claude/agents/analysis/code-analyzer.md +188 -188
  4. package/.claude/agents/analysis/code-review/analyze-code-quality.md +57 -57
  5. package/.claude/agents/architecture/system-design/arch-system-design.md +35 -35
  6. package/.claude/agents/base-template-generator.md +41 -41
  7. package/.claude/agents/consensus/byzantine-coordinator.md +42 -42
  8. package/.claude/agents/consensus/crdt-synchronizer.md +976 -976
  9. package/.claude/agents/consensus/gossip-coordinator.md +42 -42
  10. package/.claude/agents/consensus/performance-benchmarker.md +830 -830
  11. package/.claude/agents/consensus/quorum-manager.md +802 -802
  12. package/.claude/agents/consensus/raft-manager.md +42 -42
  13. package/.claude/agents/consensus/security-manager.md +601 -601
  14. package/.claude/agents/core/coder.md +254 -254
  15. package/.claude/agents/core/planner.md +151 -151
  16. package/.claude/agents/core/researcher.md +173 -173
  17. package/.claude/agents/core/reviewer.md +308 -308
  18. package/.claude/agents/core/tester.md +299 -299
  19. package/.claude/agents/custom/test-long-runner.md +43 -43
  20. package/.claude/agents/data/ml/data-ml-model.md +75 -75
  21. package/.claude/agents/database-specialist.md +9 -9
  22. package/.claude/agents/development/backend/dev-backend-api.md +28 -28
  23. package/.claude/agents/development/dev-backend-api.md +177 -177
  24. package/.claude/agents/devops/ci-cd/ops-cicd-github.md +51 -51
  25. package/.claude/agents/documentation/api-docs/docs-api-openapi.md +62 -62
  26. package/.claude/agents/dual-mode/codex-coordinator.md +206 -206
  27. package/.claude/agents/dual-mode/codex-worker.md +190 -190
  28. package/.claude/agents/dual-mode/dual-orchestrator.md +253 -253
  29. package/.claude/agents/flow-nexus/app-store.md +87 -87
  30. package/.claude/agents/flow-nexus/authentication.md +68 -68
  31. package/.claude/agents/flow-nexus/challenges.md +80 -80
  32. package/.claude/agents/flow-nexus/neural-network.md +87 -87
  33. package/.claude/agents/flow-nexus/payments.md +82 -82
  34. package/.claude/agents/flow-nexus/sandbox.md +75 -75
  35. package/.claude/agents/flow-nexus/swarm.md +75 -75
  36. package/.claude/agents/flow-nexus/user-tools.md +95 -95
  37. package/.claude/agents/flow-nexus/workflow.md +83 -83
  38. package/.claude/agents/github/code-review-swarm.md +520 -520
  39. package/.claude/agents/github/github-modes.md +153 -153
  40. package/.claude/agents/github/issue-tracker.md +298 -298
  41. package/.claude/agents/github/multi-repo-swarm.md +524 -524
  42. package/.claude/agents/github/pr-manager.md +162 -162
  43. package/.claude/agents/github/project-board-sync.md +477 -477
  44. package/.claude/agents/github/release-manager.md +337 -337
  45. package/.claude/agents/github/release-swarm.md +550 -550
  46. package/.claude/agents/github/repo-architect.md +364 -364
  47. package/.claude/agents/github/swarm-issue.md +550 -550
  48. package/.claude/agents/github/swarm-pr.md +401 -401
  49. package/.claude/agents/github/sync-coordinator.md +424 -424
  50. package/.claude/agents/github/workflow-automation.md +604 -604
  51. package/.claude/agents/goal/agent.md +816 -816
  52. package/.claude/agents/goal/code-goal-planner.md +444 -444
  53. package/.claude/agents/goal/goal-planner.md +167 -167
  54. package/.claude/agents/hive-mind/collective-intelligence-coordinator.md +128 -128
  55. package/.claude/agents/hive-mind/queen-coordinator.md +201 -201
  56. package/.claude/agents/hive-mind/scout-explorer.md +240 -240
  57. package/.claude/agents/hive-mind/swarm-memory-manager.md +191 -191
  58. package/.claude/agents/hive-mind/worker-specialist.md +215 -215
  59. package/.claude/agents/neural/safla-neural.md +73 -73
  60. package/.claude/agents/optimization/benchmark-suite.md +662 -662
  61. package/.claude/agents/optimization/load-balancer.md +428 -428
  62. package/.claude/agents/optimization/performance-monitor.md +669 -669
  63. package/.claude/agents/optimization/resource-allocator.md +671 -671
  64. package/.claude/agents/optimization/topology-optimizer.md +805 -805
  65. package/.claude/agents/payments/agentic-payments.md +126 -126
  66. package/.claude/agents/project-coordinator.md +8 -8
  67. package/.claude/agents/python-specialist.md +9 -9
  68. package/.claude/agents/reasoning/agent.md +816 -816
  69. package/.claude/agents/reasoning/goal-planner.md +72 -72
  70. package/.claude/agents/security-auditor.md +9 -9
  71. package/.claude/agents/sona/sona-learning-optimizer.md +65 -65
  72. package/.claude/agents/sparc/architecture.md +452 -452
  73. package/.claude/agents/sparc/pseudocode.md +298 -298
  74. package/.claude/agents/sparc/refinement.md +503 -503
  75. package/.claude/agents/sparc/specification.md +257 -257
  76. package/.claude/agents/specialized/mobile/spec-mobile-react-native.md +87 -87
  77. package/.claude/agents/sublinear/consensus-coordinator.md +337 -337
  78. package/.claude/agents/sublinear/matrix-optimizer.md +184 -184
  79. package/.claude/agents/sublinear/pagerank-analyzer.md +298 -298
  80. package/.claude/agents/sublinear/performance-optimizer.md +367 -367
  81. package/.claude/agents/sublinear/trading-predictor.md +245 -245
  82. package/.claude/agents/swarm/adaptive-coordinator.md +363 -363
  83. package/.claude/agents/swarm/hierarchical-coordinator.md +299 -299
  84. package/.claude/agents/swarm/mesh-coordinator.md +362 -362
  85. package/.claude/agents/templates/automation-smart-agent.md +184 -184
  86. package/.claude/agents/templates/coordinator-swarm-init.md +82 -82
  87. package/.claude/agents/templates/github-pr-manager.md +154 -154
  88. package/.claude/agents/templates/implementer-sparc-coder.md +242 -242
  89. package/.claude/agents/templates/memory-coordinator.md +162 -162
  90. package/.claude/agents/templates/migration-plan.md +723 -723
  91. package/.claude/agents/templates/orchestrator-task.md +119 -119
  92. package/.claude/agents/templates/performance-analyzer.md +178 -178
  93. package/.claude/agents/templates/sparc-coordinator.md +162 -162
  94. package/.claude/agents/testing/production-validator.md +372 -372
  95. package/.claude/agents/testing/tdd-london-swarm.md +221 -221
  96. package/.claude/agents/testing/unit/tdd-london-swarm.md +221 -221
  97. package/.claude/agents/testing/validation/production-validator.md +372 -372
  98. package/.claude/agents/typescript-specialist.md +9 -9
  99. package/.claude/agents/v3/database-specialist.md +9 -9
  100. package/.claude/agents/v3/project-coordinator.md +8 -8
  101. package/.claude/agents/v3/python-specialist.md +9 -9
  102. package/.claude/agents/v3/test-architect.md +9 -9
  103. package/.claude/agents/v3/typescript-specialist.md +9 -9
  104. package/.claude/agents/v3/v3-integration-architect.md +311 -311
  105. package/.claude/agents/v3/v3-memory-specialist.md +280 -280
  106. package/.claude/agents/v3/v3-performance-engineer.md +362 -362
  107. package/.claude/agents/v3/v3-queen-coordinator.md +62 -62
  108. package/.claude/agents/v3/v3-security-architect.md +139 -139
  109. package/.claude/checkpoints/1767754460.json +8 -8
  110. package/.claude/commands/agents/README.md +10 -10
  111. package/.claude/commands/agents/agent-capabilities.md +21 -21
  112. package/.claude/commands/agents/agent-coordination.md +28 -28
  113. package/.claude/commands/agents/agent-spawning.md +28 -28
  114. package/.claude/commands/agents/agent-types.md +26 -26
  115. package/.claude/commands/analysis/COMMAND_COMPLIANCE_REPORT.md +53 -53
  116. package/.claude/commands/analysis/README.md +9 -9
  117. package/.claude/commands/analysis/bottleneck-detect.md +162 -162
  118. package/.claude/commands/analysis/performance-bottlenecks.md +58 -58
  119. package/.claude/commands/analysis/performance-report.md +25 -25
  120. package/.claude/commands/analysis/token-efficiency.md +44 -44
  121. package/.claude/commands/analysis/token-usage.md +25 -25
  122. package/.claude/commands/automation/README.md +9 -9
  123. package/.claude/commands/automation/auto-agent.md +122 -122
  124. package/.claude/commands/automation/self-healing.md +105 -105
  125. package/.claude/commands/automation/session-memory.md +89 -89
  126. package/.claude/commands/automation/smart-agents.md +72 -72
  127. package/.claude/commands/automation/smart-spawn.md +25 -25
  128. package/.claude/commands/automation/workflow-select.md +25 -25
  129. package/.claude/commands/claude-flow-help.md +103 -103
  130. package/.claude/commands/claude-flow-memory.md +107 -107
  131. package/.claude/commands/claude-flow-swarm.md +205 -205
  132. package/.claude/commands/coordination/README.md +9 -9
  133. package/.claude/commands/coordination/agent-spawn.md +25 -25
  134. package/.claude/commands/coordination/init.md +44 -44
  135. package/.claude/commands/coordination/orchestrate.md +43 -43
  136. package/.claude/commands/coordination/spawn.md +45 -45
  137. package/.claude/commands/coordination/swarm-init.md +85 -85
  138. package/.claude/commands/coordination/task-orchestrate.md +25 -25
  139. package/.claude/commands/flow-nexus/app-store.md +123 -123
  140. package/.claude/commands/flow-nexus/challenges.md +119 -119
  141. package/.claude/commands/flow-nexus/login-registration.md +64 -64
  142. package/.claude/commands/flow-nexus/neural-network.md +133 -133
  143. package/.claude/commands/flow-nexus/payments.md +115 -115
  144. package/.claude/commands/flow-nexus/sandbox.md +82 -82
  145. package/.claude/commands/flow-nexus/swarm.md +86 -86
  146. package/.claude/commands/flow-nexus/user-tools.md +151 -151
  147. package/.claude/commands/flow-nexus/workflow.md +114 -114
  148. package/.claude/commands/github/README.md +11 -11
  149. package/.claude/commands/github/code-review-swarm.md +513 -513
  150. package/.claude/commands/github/code-review.md +25 -25
  151. package/.claude/commands/github/github-modes.md +146 -146
  152. package/.claude/commands/github/github-swarm.md +121 -121
  153. package/.claude/commands/github/issue-tracker.md +291 -291
  154. package/.claude/commands/github/issue-triage.md +25 -25
  155. package/.claude/commands/github/multi-repo-swarm.md +518 -518
  156. package/.claude/commands/github/pr-enhance.md +26 -26
  157. package/.claude/commands/github/pr-manager.md +169 -169
  158. package/.claude/commands/github/project-board-sync.md +470 -470
  159. package/.claude/commands/github/release-manager.md +337 -337
  160. package/.claude/commands/github/release-swarm.md +543 -543
  161. package/.claude/commands/github/repo-analyze.md +25 -25
  162. package/.claude/commands/github/repo-architect.md +366 -366
  163. package/.claude/commands/github/swarm-issue.md +481 -481
  164. package/.claude/commands/github/swarm-pr.md +284 -284
  165. package/.claude/commands/github/sync-coordinator.md +300 -300
  166. package/.claude/commands/github/workflow-automation.md +441 -441
  167. package/.claude/commands/hive-mind/README.md +17 -17
  168. package/.claude/commands/hive-mind/hive-mind-consensus.md +8 -8
  169. package/.claude/commands/hive-mind/hive-mind-init.md +18 -18
  170. package/.claude/commands/hive-mind/hive-mind-memory.md +8 -8
  171. package/.claude/commands/hive-mind/hive-mind-metrics.md +8 -8
  172. package/.claude/commands/hive-mind/hive-mind-resume.md +8 -8
  173. package/.claude/commands/hive-mind/hive-mind-sessions.md +8 -8
  174. package/.claude/commands/hive-mind/hive-mind-spawn.md +21 -21
  175. package/.claude/commands/hive-mind/hive-mind-status.md +8 -8
  176. package/.claude/commands/hive-mind/hive-mind-stop.md +8 -8
  177. package/.claude/commands/hive-mind/hive-mind-wizard.md +8 -8
  178. package/.claude/commands/hive-mind/hive-mind.md +27 -27
  179. package/.claude/commands/hooks/README.md +11 -11
  180. package/.claude/commands/hooks/overview.md +57 -57
  181. package/.claude/commands/hooks/post-edit.md +117 -117
  182. package/.claude/commands/hooks/post-task.md +112 -112
  183. package/.claude/commands/hooks/pre-edit.md +113 -113
  184. package/.claude/commands/hooks/pre-task.md +111 -111
  185. package/.claude/commands/hooks/session-end.md +118 -118
  186. package/.claude/commands/hooks/setup.md +102 -102
  187. package/.claude/commands/memory/README.md +9 -9
  188. package/.claude/commands/memory/memory-persist.md +25 -25
  189. package/.claude/commands/memory/memory-search.md +25 -25
  190. package/.claude/commands/memory/memory-usage.md +25 -25
  191. package/.claude/commands/memory/neural.md +47 -47
  192. package/.claude/commands/monitoring/README.md +9 -9
  193. package/.claude/commands/monitoring/agent-metrics.md +25 -25
  194. package/.claude/commands/monitoring/agents.md +44 -44
  195. package/.claude/commands/monitoring/real-time-view.md +25 -25
  196. package/.claude/commands/monitoring/status.md +46 -46
  197. package/.claude/commands/monitoring/swarm-monitor.md +25 -25
  198. package/.claude/commands/optimization/README.md +9 -9
  199. package/.claude/commands/optimization/auto-topology.md +61 -61
  200. package/.claude/commands/optimization/cache-manage.md +25 -25
  201. package/.claude/commands/optimization/parallel-execute.md +25 -25
  202. package/.claude/commands/optimization/parallel-execution.md +49 -49
  203. package/.claude/commands/optimization/topology-optimize.md +25 -25
  204. package/.claude/commands/pair/README.md +260 -260
  205. package/.claude/commands/pair/commands.md +545 -545
  206. package/.claude/commands/pair/config.md +509 -509
  207. package/.claude/commands/pair/examples.md +511 -511
  208. package/.claude/commands/pair/modes.md +347 -347
  209. package/.claude/commands/pair/session.md +406 -406
  210. package/.claude/commands/pair/start.md +208 -208
  211. package/.claude/commands/sparc/analyzer.md +51 -51
  212. package/.claude/commands/sparc/architect.md +53 -53
  213. package/.claude/commands/sparc/ask.md +97 -97
  214. package/.claude/commands/sparc/batch-executor.md +54 -54
  215. package/.claude/commands/sparc/code.md +89 -89
  216. package/.claude/commands/sparc/coder.md +54 -54
  217. package/.claude/commands/sparc/debug.md +83 -83
  218. package/.claude/commands/sparc/debugger.md +54 -54
  219. package/.claude/commands/sparc/designer.md +53 -53
  220. package/.claude/commands/sparc/devops.md +109 -109
  221. package/.claude/commands/sparc/docs-writer.md +80 -80
  222. package/.claude/commands/sparc/documenter.md +54 -54
  223. package/.claude/commands/sparc/innovator.md +54 -54
  224. package/.claude/commands/sparc/integration.md +83 -83
  225. package/.claude/commands/sparc/mcp.md +117 -117
  226. package/.claude/commands/sparc/memory-manager.md +54 -54
  227. package/.claude/commands/sparc/optimizer.md +54 -54
  228. package/.claude/commands/sparc/orchestrator.md +131 -131
  229. package/.claude/commands/sparc/post-deployment-monitoring-mode.md +83 -83
  230. package/.claude/commands/sparc/refinement-optimization-mode.md +83 -83
  231. package/.claude/commands/sparc/researcher.md +54 -54
  232. package/.claude/commands/sparc/reviewer.md +54 -54
  233. package/.claude/commands/sparc/security-review.md +80 -80
  234. package/.claude/commands/sparc/sparc-modes.md +174 -174
  235. package/.claude/commands/sparc/sparc.md +111 -111
  236. package/.claude/commands/sparc/spec-pseudocode.md +80 -80
  237. package/.claude/commands/sparc/supabase-admin.md +348 -348
  238. package/.claude/commands/sparc/swarm-coordinator.md +54 -54
  239. package/.claude/commands/sparc/tdd.md +54 -54
  240. package/.claude/commands/sparc/tester.md +54 -54
  241. package/.claude/commands/sparc/tutorial.md +79 -79
  242. package/.claude/commands/sparc/workflow-manager.md +54 -54
  243. package/.claude/commands/sparc.md +166 -166
  244. package/.claude/commands/stream-chain/pipeline.md +120 -120
  245. package/.claude/commands/stream-chain/run.md +69 -69
  246. package/.claude/commands/swarm/README.md +15 -15
  247. package/.claude/commands/swarm/analysis.md +95 -95
  248. package/.claude/commands/swarm/development.md +96 -96
  249. package/.claude/commands/swarm/examples.md +168 -168
  250. package/.claude/commands/swarm/maintenance.md +102 -102
  251. package/.claude/commands/swarm/optimization.md +117 -117
  252. package/.claude/commands/swarm/research.md +136 -136
  253. package/.claude/commands/swarm/swarm-analysis.md +8 -8
  254. package/.claude/commands/swarm/swarm-background.md +8 -8
  255. package/.claude/commands/swarm/swarm-init.md +19 -19
  256. package/.claude/commands/swarm/swarm-modes.md +8 -8
  257. package/.claude/commands/swarm/swarm-monitor.md +8 -8
  258. package/.claude/commands/swarm/swarm-spawn.md +19 -19
  259. package/.claude/commands/swarm/swarm-status.md +8 -8
  260. package/.claude/commands/swarm/swarm-strategies.md +8 -8
  261. package/.claude/commands/swarm/swarm.md +27 -27
  262. package/.claude/commands/swarm/testing.md +131 -131
  263. package/.claude/commands/training/README.md +9 -9
  264. package/.claude/commands/training/model-update.md +25 -25
  265. package/.claude/commands/training/neural-patterns.md +73 -73
  266. package/.claude/commands/training/neural-train.md +25 -25
  267. package/.claude/commands/training/pattern-learn.md +25 -25
  268. package/.claude/commands/training/specialization.md +62 -62
  269. package/.claude/commands/truth/start.md +142 -142
  270. package/.claude/commands/verify/check.md +49 -49
  271. package/.claude/commands/verify/start.md +127 -127
  272. package/.claude/commands/workflows/README.md +9 -9
  273. package/.claude/commands/workflows/development.md +77 -77
  274. package/.claude/commands/workflows/research.md +62 -62
  275. package/.claude/commands/workflows/workflow-create.md +25 -25
  276. package/.claude/commands/workflows/workflow-execute.md +25 -25
  277. package/.claude/commands/workflows/workflow-export.md +25 -25
  278. package/.claude/config/v3-dependency-optimization.json +265 -265
  279. package/.claude/config/v3-performance-targets.json +250 -250
  280. package/.claude/helpers/.LOCKED +2 -2
  281. package/.claude/helpers/README.md +96 -96
  282. package/.claude/helpers/adr-compliance.sh +186 -186
  283. package/.claude/helpers/aggressive-microcompact.mjs +36 -36
  284. package/.claude/helpers/auto-commit.sh +178 -178
  285. package/.claude/helpers/auto-memory-hook.mjs +430 -430
  286. package/.claude/helpers/checkpoint-manager.sh +251 -251
  287. package/.claude/helpers/context-persistence-hook.mjs +2001 -2001
  288. package/.claude/helpers/daemon-manager.sh +252 -252
  289. package/.claude/helpers/ddd-tracker.sh +144 -144
  290. package/.claude/helpers/github-safe.js +156 -156
  291. package/.claude/helpers/github-setup.sh +45 -45
  292. package/.claude/helpers/guidance-hook.sh +13 -13
  293. package/.claude/helpers/guidance-hooks.sh +102 -102
  294. package/.claude/helpers/health-monitor.sh +108 -108
  295. package/.claude/helpers/hook-handler.cjs +606 -606
  296. package/.claude/helpers/intelligence.cjs +1169 -1169
  297. package/.claude/helpers/learning-hooks.sh +329 -329
  298. package/.claude/helpers/learning-optimizer.sh +127 -127
  299. package/.claude/helpers/learning-service.mjs +1144 -1144
  300. package/.claude/helpers/memory.cjs +84 -84
  301. package/.claude/helpers/metrics-db.mjs +503 -503
  302. package/.claude/helpers/patch-aggressive-prune.mjs +184 -184
  303. package/.claude/helpers/pattern-consolidator.sh +86 -86
  304. package/.claude/helpers/perf-worker.sh +160 -160
  305. package/.claude/helpers/quick-start.sh +19 -19
  306. package/.claude/helpers/router.cjs +62 -62
  307. package/.claude/helpers/security-scanner.sh +127 -127
  308. package/.claude/helpers/session.cjs +125 -125
  309. package/.claude/helpers/setup-mcp.sh +18 -18
  310. package/.claude/helpers/standard-checkpoint-hooks.sh +189 -189
  311. package/.claude/helpers/statusline.cjs +0 -0
  312. package/.claude/helpers/swarm-comms.sh +353 -353
  313. package/.claude/helpers/swarm-hooks.sh +761 -761
  314. package/.claude/helpers/swarm-monitor.sh +210 -210
  315. package/.claude/helpers/sync-v3-metrics.sh +245 -245
  316. package/.claude/helpers/update-v3-progress.sh +165 -165
  317. package/.claude/helpers/v3-quick-status.sh +57 -57
  318. package/.claude/helpers/v3.sh +110 -110
  319. package/.claude/helpers/validate-v3-config.sh +215 -215
  320. package/.claude/helpers/worker-manager.sh +170 -170
  321. package/.claude/mcp.json +12 -12
  322. package/.claude/proven-config.json +1 -1
  323. package/.claude/settings.json +284 -284
  324. package/.claude/settings.json.bak +526 -526
  325. package/.claude/skills/agentdb-advanced/SKILL.md +550 -550
  326. package/.claude/skills/agentdb-learning/SKILL.md +545 -545
  327. package/.claude/skills/agentdb-memory-patterns/SKILL.md +339 -339
  328. package/.claude/skills/agentdb-optimization/SKILL.md +509 -509
  329. package/.claude/skills/agentdb-vector-search/SKILL.md +339 -339
  330. package/.claude/skills/agentic-jujutsu/SKILL.md +645 -645
  331. package/.claude/skills/browser/SKILL.md +204 -204
  332. package/.claude/skills/dual-mode/README.md +71 -71
  333. package/.claude/skills/dual-mode/dual-collect.md +103 -103
  334. package/.claude/skills/dual-mode/dual-coordinate.md +85 -85
  335. package/.claude/skills/dual-mode/dual-spawn.md +81 -81
  336. package/.claude/skills/flow-nexus-neural/SKILL.md +727 -727
  337. package/.claude/skills/flow-nexus-platform/SKILL.md +1154 -1154
  338. package/.claude/skills/flow-nexus-swarm/SKILL.md +604 -604
  339. package/.claude/skills/github-code-review/SKILL.md +1125 -1125
  340. package/.claude/skills/github-multi-repo/SKILL.md +862 -862
  341. package/.claude/skills/github-project-management/SKILL.md +1262 -1262
  342. package/.claude/skills/github-release-management/SKILL.md +1064 -1064
  343. package/.claude/skills/github-workflow-automation/SKILL.md +1047 -1047
  344. package/.claude/skills/hive-mind-advanced/SKILL.md +709 -709
  345. package/.claude/skills/hooks-automation/SKILL.md +1201 -1201
  346. package/.claude/skills/pair-programming/SKILL.md +1202 -1202
  347. package/.claude/skills/performance-analysis/SKILL.md +560 -560
  348. package/.claude/skills/reasoningbank-agentdb/SKILL.md +446 -446
  349. package/.claude/skills/reasoningbank-intelligence/SKILL.md +201 -201
  350. package/.claude/skills/skill-builder/SKILL.md +910 -910
  351. package/.claude/skills/sparc-methodology/SKILL.md +1106 -1106
  352. package/.claude/skills/stream-chain/SKILL.md +560 -560
  353. package/.claude/skills/swarm-advanced/SKILL.md +970 -970
  354. package/.claude/skills/swarm-orchestration/SKILL.md +179 -179
  355. package/.claude/skills/v3-cli-modernization/SKILL.md +871 -871
  356. package/.claude/skills/v3-core-implementation/SKILL.md +796 -796
  357. package/.claude/skills/v3-ddd-architecture/SKILL.md +441 -441
  358. package/.claude/skills/v3-integration-deep/SKILL.md +240 -240
  359. package/.claude/skills/v3-mcp-optimization/SKILL.md +776 -776
  360. package/.claude/skills/v3-memory-unification/SKILL.md +173 -173
  361. package/.claude/skills/v3-performance-optimization/SKILL.md +389 -389
  362. package/.claude/skills/v3-security-overhaul/SKILL.md +81 -81
  363. package/.claude/skills/v3-swarm-coordination/SKILL.md +339 -339
  364. package/.claude/skills/verification-quality/SKILL.md +691 -691
  365. package/.claude/skills/worker-benchmarks/SKILL.md +129 -129
  366. package/.claude/skills/worker-integration/SKILL.md +147 -147
  367. package/.claude/statusline-command.sh +176 -176
  368. package/.claude/statusline.mjs +109 -109
  369. package/.claude/statusline.sh +431 -431
  370. package/.claude/workflows/full-system-test.js +65 -65
  371. package/.claude/workflows/intelligence-system-hardening.js +120 -120
  372. package/.claude/workflows/plugin-contract-audit.js +91 -91
  373. package/.claude-plugin/README.md +720 -720
  374. package/.claude-plugin/docs/INSTALLATION.md +261 -261
  375. package/.claude-plugin/docs/PLUGIN_SUMMARY.md +361 -361
  376. package/.claude-plugin/docs/QUICKSTART.md +361 -361
  377. package/.claude-plugin/docs/STRUCTURE.md +128 -128
  378. package/.claude-plugin/hooks/hooks.json +77 -77
  379. package/.claude-plugin/marketplace.json +204 -204
  380. package/.claude-plugin/plugin.json +71 -71
  381. package/.claude-plugin/scripts/install.sh +234 -234
  382. package/.claude-plugin/scripts/ruflo-hook.cjs +304 -166
  383. package/.claude-plugin/scripts/ruflo-hook.sh +52 -52
  384. package/.claude-plugin/scripts/uninstall.sh +36 -36
  385. package/.claude-plugin/scripts/verify.sh +108 -108
  386. package/LICENSE +21 -21
  387. package/README.md +422 -422
  388. package/bin/cli.js +11 -11
  389. package/bin/npx-repair.js +7 -7
  390. package/bin/npx-safe-launch.js +9 -9
  391. package/node_modules/@claude-flow/codex/.agents/skills/github-automation/SKILL.md +32 -32
  392. package/node_modules/@claude-flow/codex/.agents/skills/memory-management/SKILL.md +45 -45
  393. package/node_modules/@claude-flow/codex/.agents/skills/performance-analysis/SKILL.md +32 -32
  394. package/node_modules/@claude-flow/codex/.agents/skills/security-audit/SKILL.md +46 -46
  395. package/node_modules/@claude-flow/codex/.agents/skills/sparc-methodology/SKILL.md +46 -46
  396. package/node_modules/@claude-flow/codex/.agents/skills/swarm-orchestration/SKILL.md +53 -53
  397. package/node_modules/@claude-flow/codex/README.md +1044 -1044
  398. package/node_modules/@claude-flow/codex/dist/dual-mode/orchestrator.js +13 -13
  399. package/node_modules/@claude-flow/codex/dist/generators/agents-md.js +664 -664
  400. package/node_modules/@claude-flow/codex/dist/generators/config-toml.js +455 -455
  401. package/node_modules/@claude-flow/codex/dist/generators/skill-md.js +45 -45
  402. package/node_modules/@claude-flow/codex/dist/initializer.js +167 -167
  403. package/node_modules/@claude-flow/codex/dist/templates/index.js +15 -15
  404. package/node_modules/@claude-flow/mcp/README.md +429 -429
  405. package/node_modules/@claude-flow/plugin-agent-federation/README.md +49 -49
  406. package/node_modules/@claude-flow/security/README.md +292 -292
  407. package/node_modules/@claude-flow/security/dist/credential-generator.js +9 -9
  408. package/node_modules/@claude-flow/security/dist/input-validator.d.ts +6 -6
  409. package/node_modules/@claude-flow/security/dist/oauth/callback-server.js +9 -9
  410. package/package.json +222 -222
  411. package/v3/@claude-flow/cli/README.md +422 -422
  412. package/v3/@claude-flow/cli/bin/cli.js +338 -338
  413. package/v3/@claude-flow/cli/bin/mcp-server.js +224 -224
  414. package/v3/@claude-flow/cli/bin/preinstall.cjs +2 -2
  415. package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
  416. package/v3/@claude-flow/cli/dist/src/benchmarks/gaia-critic.js +24 -24
  417. package/v3/@claude-flow/cli/dist/src/business-pods/bbs-budget-tracker.js +53 -53
  418. package/v3/@claude-flow/cli/dist/src/commands/completions.js +409 -409
  419. package/v3/@claude-flow/cli/dist/src/commands/daemon.js +44 -44
  420. package/v3/@claude-flow/cli/dist/src/commands/doctor.js +4 -4
  421. package/v3/@claude-flow/cli/dist/src/commands/embeddings.js +26 -26
  422. package/v3/@claude-flow/cli/dist/src/commands/hive-mind.js +97 -97
  423. package/v3/@claude-flow/cli/dist/src/commands/hooks.js +9 -9
  424. package/v3/@claude-flow/cli/dist/src/commands/init.js +75 -75
  425. package/v3/@claude-flow/cli/dist/src/commands/ruvector/backup.js +23 -23
  426. package/v3/@claude-flow/cli/dist/src/commands/ruvector/benchmark.js +31 -31
  427. package/v3/@claude-flow/cli/dist/src/commands/ruvector/import.js +14 -14
  428. package/v3/@claude-flow/cli/dist/src/commands/ruvector/init.js +115 -115
  429. package/v3/@claude-flow/cli/dist/src/commands/ruvector/migrate.js +99 -99
  430. package/v3/@claude-flow/cli/dist/src/commands/ruvector/optimize.js +51 -51
  431. package/v3/@claude-flow/cli/dist/src/commands/ruvector/setup.js +624 -624
  432. package/v3/@claude-flow/cli/dist/src/commands/ruvector/status.js +38 -38
  433. package/v3/@claude-flow/cli/dist/src/config/proven-config.js +2 -2
  434. package/v3/@claude-flow/cli/dist/src/init/claudemd-generator.js +273 -273
  435. package/v3/@claude-flow/cli/dist/src/init/executor.js +453 -453
  436. package/v3/@claude-flow/cli/dist/src/init/helper-signing.js +2 -2
  437. package/v3/@claude-flow/cli/dist/src/init/helpers-generator.js +917 -751
  438. package/v3/@claude-flow/cli/dist/src/init/statusline-generator.js +24 -24
  439. package/v3/@claude-flow/cli/dist/src/mcp-tools/agentdb-tools.js +15 -15
  440. package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-intent-tools.js +19 -19
  441. package/v3/@claude-flow/cli/dist/src/mcp-tools/seraphina-tools.js +4 -4
  442. package/v3/@claude-flow/cli/dist/src/memory/graph-edge-writer.js +22 -22
  443. package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +114 -114
  444. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +416 -416
  445. package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.js +5 -5
  446. package/v3/@claude-flow/cli/dist/src/proxy/verify.js +2 -2
  447. package/v3/@claude-flow/cli/dist/src/runtime/headless.js +28 -28
  448. package/v3/@claude-flow/cli/dist/src/ruvector/diskann-backend.d.ts +78 -0
  449. package/v3/@claude-flow/cli/dist/src/ruvector/diskann-backend.js +310 -0
  450. package/v3/@claude-flow/cli/dist/src/services/distill-tuning.js +7 -7
  451. package/v3/@claude-flow/cli/dist/src/services/headless-worker-executor.js +84 -84
  452. package/v3/@claude-flow/cli/dist/src/services/memory-distillation.js +18 -18
  453. package/v3/@claude-flow/cli/dist/src/transfer/deploy-seraphine.js +23 -23
  454. package/v3/@claude-flow/cli/package.json +181 -181
  455. package/v3/@claude-flow/guidance/README.md +1195 -1195
  456. package/v3/@claude-flow/guidance/package.json +198 -198
  457. package/v3/@claude-flow/shared/README.md +323 -323
  458. package/v3/@claude-flow/shared/dist/events/event-store.js +31 -31
  459. package/v3/@claude-flow/shared/dist/hooks/safety/git-commit.js +3 -3
  460. package/v3/@claude-flow/shared/package.json +43 -43
  461. package/v3/README.md +493 -493
@@ -65,371 +65,371 @@ const TOOL_FAILURE_EXPR = '(function(hi){' +
65
65
  * Generate pre-commit hook script
66
66
  */
67
67
  export function generatePreCommitHook() {
68
- return `#!/bin/bash
69
- # Ruflo Pre-Commit Hook
70
- # Validates code quality before commit
71
-
72
- set -e
73
-
74
- echo "🔍 Running Ruflo pre-commit checks..."
75
-
76
- # Get staged files
77
- STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
78
-
79
- # Run validation for each staged file
80
- for FILE in $STAGED_FILES; do
81
- if [[ "$FILE" =~ \\.(ts|js|tsx|jsx)$ ]]; then
82
- echo " Validating: $FILE"
83
- npx @claude-flow/cli hooks pre-edit --file "$FILE" --validate-syntax 2>/dev/null || true
84
- fi
85
- done
86
-
87
- # Run tests if available
88
- if [ -f "package.json" ] && grep -q '"test"' package.json; then
89
- echo "🧪 Running tests..."
90
- npm test --if-present 2>/dev/null || echo " Tests skipped or failed"
91
- fi
92
-
93
- echo "✅ Pre-commit checks complete"
68
+ return `#!/bin/bash
69
+ # Ruflo Pre-Commit Hook
70
+ # Validates code quality before commit
71
+
72
+ set -e
73
+
74
+ echo "🔍 Running Ruflo pre-commit checks..."
75
+
76
+ # Get staged files
77
+ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
78
+
79
+ # Run validation for each staged file
80
+ for FILE in $STAGED_FILES; do
81
+ if [[ "$FILE" =~ \\.(ts|js|tsx|jsx)$ ]]; then
82
+ echo " Validating: $FILE"
83
+ npx @claude-flow/cli hooks pre-edit --file "$FILE" --validate-syntax 2>/dev/null || true
84
+ fi
85
+ done
86
+
87
+ # Run tests if available
88
+ if [ -f "package.json" ] && grep -q '"test"' package.json; then
89
+ echo "🧪 Running tests..."
90
+ npm test --if-present 2>/dev/null || echo " Tests skipped or failed"
91
+ fi
92
+
93
+ echo "✅ Pre-commit checks complete"
94
94
  `;
95
95
  }
96
96
  /**
97
97
  * Generate post-commit hook script
98
98
  */
99
99
  export function generatePostCommitHook() {
100
- return `#!/bin/bash
101
- # Ruflo Post-Commit Hook
102
- # Records commit metrics and trains patterns
103
-
104
- COMMIT_HASH=$(git rev-parse HEAD)
105
- COMMIT_MSG=$(git log -1 --pretty=%B)
106
-
107
- echo "📊 Recording commit metrics..."
108
-
109
- # Notify ruflo of commit
110
- npx ruflo@latest hooks notify \\
111
- --message "Commit: $COMMIT_MSG" \\
112
- --level info \\
113
- --metadata '{"hash": "'$COMMIT_HASH'"}' 2>/dev/null || true
114
-
115
- echo "✅ Commit recorded"
100
+ return `#!/bin/bash
101
+ # Ruflo Post-Commit Hook
102
+ # Records commit metrics and trains patterns
103
+
104
+ COMMIT_HASH=$(git rev-parse HEAD)
105
+ COMMIT_MSG=$(git log -1 --pretty=%B)
106
+
107
+ echo "📊 Recording commit metrics..."
108
+
109
+ # Notify ruflo of commit
110
+ npx ruflo@latest hooks notify \\
111
+ --message "Commit: $COMMIT_MSG" \\
112
+ --level info \\
113
+ --metadata '{"hash": "'$COMMIT_HASH'"}' 2>/dev/null || true
114
+
115
+ echo "✅ Commit recorded"
116
116
  `;
117
117
  }
118
118
  /**
119
119
  * Generate session manager script
120
120
  */
121
121
  export function generateSessionManager() {
122
- return `#!/usr/bin/env node
123
- /**
124
- * Ruflo Session Manager
125
- * Handles session lifecycle: start, restore, end
126
- */
127
-
128
- const fs = require('fs');
129
- const path = require('path');
130
-
131
- const SESSION_DIR = path.join(process.cwd(), '.claude-flow', 'sessions');
132
- const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
133
-
134
- const commands = {
135
- start: () => {
136
- const sessionId = \`session-\${Date.now()}\`;
137
- const session = {
138
- id: sessionId,
139
- startedAt: new Date().toISOString(),
140
- cwd: process.cwd(),
141
- context: {},
142
- metrics: {
143
- edits: 0,
144
- commands: 0,
145
- tasks: 0,
146
- errors: 0,
147
- },
148
- };
149
-
150
- fs.mkdirSync(SESSION_DIR, { recursive: true });
151
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
152
-
153
- console.log(\`Session started: \${sessionId}\`);
154
- return session;
155
- },
156
-
157
- restore: () => {
158
- if (!fs.existsSync(SESSION_FILE)) {
159
- console.log('No session to restore');
160
- return null;
161
- }
162
-
163
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
164
- session.restoredAt = new Date().toISOString();
165
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
166
-
167
- console.log(\`Session restored: \${session.id}\`);
168
- return session;
169
- },
170
-
171
- end: () => {
172
- if (!fs.existsSync(SESSION_FILE)) {
173
- console.log('No active session');
174
- return null;
175
- }
176
-
177
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
178
- session.endedAt = new Date().toISOString();
179
- session.duration = Date.now() - new Date(session.startedAt).getTime();
180
-
181
- // Archive session
182
- const archivePath = path.join(SESSION_DIR, \`\${session.id}.json\`);
183
- fs.writeFileSync(archivePath, JSON.stringify(session, null, 2));
184
- fs.unlinkSync(SESSION_FILE);
185
-
186
- console.log(\`Session ended: \${session.id}\`);
187
- console.log(\`Duration: \${Math.round(session.duration / 1000 / 60)} minutes\`);
188
- console.log(\`Metrics: \${JSON.stringify(session.metrics)}\`);
189
-
190
- return session;
191
- },
192
-
193
- status: () => {
194
- if (!fs.existsSync(SESSION_FILE)) {
195
- console.log('No active session');
196
- return null;
197
- }
198
-
199
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
200
- const duration = Date.now() - new Date(session.startedAt).getTime();
201
-
202
- console.log(\`Session: \${session.id}\`);
203
- console.log(\`Started: \${session.startedAt}\`);
204
- console.log(\`Duration: \${Math.round(duration / 1000 / 60)} minutes\`);
205
- console.log(\`Metrics: \${JSON.stringify(session.metrics)}\`);
206
-
207
- return session;
208
- },
209
-
210
- update: (key, value) => {
211
- if (!fs.existsSync(SESSION_FILE)) {
212
- console.log('No active session');
213
- return null;
214
- }
215
-
216
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
217
- session.context[key] = value;
218
- session.updatedAt = new Date().toISOString();
219
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
220
-
221
- return session;
222
- },
223
-
224
- metric: (name) => {
225
- if (!fs.existsSync(SESSION_FILE)) {
226
- return null;
227
- }
228
-
229
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
230
- if (session.metrics[name] !== undefined) {
231
- session.metrics[name]++;
232
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
233
- }
234
-
235
- return session;
236
- },
237
- };
238
-
239
- // CLI
240
- const [,, command, ...args] = process.argv;
241
-
242
- if (command && commands[command]) {
243
- commands[command](...args);
244
- } else {
245
- console.log('Usage: session.js <start|restore|end|status|update|metric> [args]');
246
- }
247
-
248
- module.exports = commands;
122
+ return `#!/usr/bin/env node
123
+ /**
124
+ * Ruflo Session Manager
125
+ * Handles session lifecycle: start, restore, end
126
+ */
127
+
128
+ const fs = require('fs');
129
+ const path = require('path');
130
+
131
+ const SESSION_DIR = path.join(process.cwd(), '.claude-flow', 'sessions');
132
+ const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
133
+
134
+ const commands = {
135
+ start: () => {
136
+ const sessionId = \`session-\${Date.now()}\`;
137
+ const session = {
138
+ id: sessionId,
139
+ startedAt: new Date().toISOString(),
140
+ cwd: process.cwd(),
141
+ context: {},
142
+ metrics: {
143
+ edits: 0,
144
+ commands: 0,
145
+ tasks: 0,
146
+ errors: 0,
147
+ },
148
+ };
149
+
150
+ fs.mkdirSync(SESSION_DIR, { recursive: true });
151
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
152
+
153
+ console.log(\`Session started: \${sessionId}\`);
154
+ return session;
155
+ },
156
+
157
+ restore: () => {
158
+ if (!fs.existsSync(SESSION_FILE)) {
159
+ console.log('No session to restore');
160
+ return null;
161
+ }
162
+
163
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
164
+ session.restoredAt = new Date().toISOString();
165
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
166
+
167
+ console.log(\`Session restored: \${session.id}\`);
168
+ return session;
169
+ },
170
+
171
+ end: () => {
172
+ if (!fs.existsSync(SESSION_FILE)) {
173
+ console.log('No active session');
174
+ return null;
175
+ }
176
+
177
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
178
+ session.endedAt = new Date().toISOString();
179
+ session.duration = Date.now() - new Date(session.startedAt).getTime();
180
+
181
+ // Archive session
182
+ const archivePath = path.join(SESSION_DIR, \`\${session.id}.json\`);
183
+ fs.writeFileSync(archivePath, JSON.stringify(session, null, 2));
184
+ fs.unlinkSync(SESSION_FILE);
185
+
186
+ console.log(\`Session ended: \${session.id}\`);
187
+ console.log(\`Duration: \${Math.round(session.duration / 1000 / 60)} minutes\`);
188
+ console.log(\`Metrics: \${JSON.stringify(session.metrics)}\`);
189
+
190
+ return session;
191
+ },
192
+
193
+ status: () => {
194
+ if (!fs.existsSync(SESSION_FILE)) {
195
+ console.log('No active session');
196
+ return null;
197
+ }
198
+
199
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
200
+ const duration = Date.now() - new Date(session.startedAt).getTime();
201
+
202
+ console.log(\`Session: \${session.id}\`);
203
+ console.log(\`Started: \${session.startedAt}\`);
204
+ console.log(\`Duration: \${Math.round(duration / 1000 / 60)} minutes\`);
205
+ console.log(\`Metrics: \${JSON.stringify(session.metrics)}\`);
206
+
207
+ return session;
208
+ },
209
+
210
+ update: (key, value) => {
211
+ if (!fs.existsSync(SESSION_FILE)) {
212
+ console.log('No active session');
213
+ return null;
214
+ }
215
+
216
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
217
+ session.context[key] = value;
218
+ session.updatedAt = new Date().toISOString();
219
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
220
+
221
+ return session;
222
+ },
223
+
224
+ metric: (name) => {
225
+ if (!fs.existsSync(SESSION_FILE)) {
226
+ return null;
227
+ }
228
+
229
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
230
+ if (session.metrics[name] !== undefined) {
231
+ session.metrics[name]++;
232
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
233
+ }
234
+
235
+ return session;
236
+ },
237
+ };
238
+
239
+ // CLI
240
+ const [,, command, ...args] = process.argv;
241
+
242
+ if (command && commands[command]) {
243
+ commands[command](...args);
244
+ } else {
245
+ console.log('Usage: session.js <start|restore|end|status|update|metric> [args]');
246
+ }
247
+
248
+ module.exports = commands;
249
249
  `;
250
250
  }
251
251
  /**
252
252
  * Generate agent router script
253
253
  */
254
254
  export function generateAgentRouter() {
255
- return `#!/usr/bin/env node
256
- /**
257
- * Ruflo Agent Router
258
- *
259
- * Static keyword router that suggests an agent for a task description.
260
- * NOTE: This is *not* a learned model. It is a heuristic table; "confidence"
261
- * is reported as a heuristic prior, not a calibrated probability.
262
- *
263
- * #2257 fix: patterns are now word-boundary-anchored so short tokens like
264
- * \`cd\`, \`ci\`, \`ui\`, \`add\`, \`structure\` no longer match inside unrelated
265
- * words (\`decision\`, \`infrastructure\`, \`address\`, \`addendum\`). Default
266
- * matched-confidence dropped from 0.8 to 0.6, and fall-through from 0.5 to
267
- * 0.3, to reflect that this is a static heuristic, not a learned classifier.
268
- */
269
-
270
- const AGENT_CAPABILITIES = {
271
- coder: ['code-generation', 'refactoring', 'debugging', 'implementation'],
272
- tester: ['unit-testing', 'integration-testing', 'coverage', 'test-generation'],
273
- reviewer: ['code-review', 'security-audit', 'quality-check', 'best-practices'],
274
- researcher: ['web-search', 'documentation', 'analysis', 'summarization'],
275
- architect: ['system-design', 'architecture', 'patterns', 'scalability'],
276
- 'backend-dev': ['api', 'database', 'server', 'authentication'],
277
- 'frontend-dev': ['ui', 'react', 'css', 'components'],
278
- devops: ['ci-cd', 'docker', 'deployment', 'infrastructure'],
279
- };
280
-
281
- // Each entry has a token list. Single tokens get \\b…\\b boundaries so 'cd'
282
- // won't match inside 'decide'. Phrases (whitespace or '/') match literally —
283
- // the whitespace acts as a natural boundary.
284
- const TASK_PATTERNS = [
285
- { tokens: ['implement', 'create', 'build', 'add', 'write code', 'refactor', 'debug'], agent: 'coder' },
286
- { tokens: ['test', 'tests', 'spec', 'coverage', 'unit test', 'integration test'], agent: 'tester' },
287
- { tokens: ['review', 'audit', 'check', 'validate', 'security'], agent: 'reviewer' },
288
- { tokens: ['research', 'find', 'search', 'documentation', 'explore'], agent: 'researcher' },
289
- { tokens: ['design', 'architect', 'architecture', 'structure', 'plan'], agent: 'architect' },
290
- { tokens: ['api', 'endpoint', 'server', 'backend', 'database'], agent: 'backend-dev' },
291
- { tokens: ['ui', 'frontend', 'component', 'react', 'css', 'style'], agent: 'frontend-dev' },
292
- { tokens: ['deploy', 'docker', 'ci', 'cd', 'ci/cd', 'pipeline', 'infrastructure', 'devops'], agent: 'devops' },
293
- ];
294
-
295
- function escapeRegex(s) {
296
- return s.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
297
- }
298
-
299
- function buildPattern(tokens) {
300
- const alternatives = tokens.map((tok) => {
301
- const escaped = escapeRegex(tok.toLowerCase());
302
- if (/\\s|\\//.test(tok)) return escaped;
303
- return \`\\\\b\${escaped}\\\\b\`;
304
- });
305
- return new RegExp(\`(?:\${alternatives.join('|')})\`, 'i');
306
- }
307
-
308
- const COMPILED_PATTERNS = TASK_PATTERNS.map((entry) => ({
309
- agent: entry.agent,
310
- tokens: entry.tokens,
311
- regex: buildPattern(entry.tokens),
312
- }));
313
-
314
- function routeTask(task) {
315
- const taskLower = String(task == null ? '' : task).toLowerCase();
316
- for (const entry of COMPILED_PATTERNS) {
317
- if (entry.regex.test(taskLower)) {
318
- return {
319
- agent: entry.agent,
320
- confidence: 0.6,
321
- reason: \`Matched keyword(s) from: \${entry.tokens.join('|')}\`,
322
- };
323
- }
324
- }
325
- return {
326
- agent: 'coder',
327
- confidence: 0.3,
328
- reason: 'Default routing - no specific keyword matched',
329
- };
330
- }
331
-
332
- // CLI
333
- const task = process.argv.slice(2).join(' ');
334
-
335
- if (task) {
336
- const result = routeTask(task);
337
- console.log(JSON.stringify(result, null, 2));
338
- } else {
339
- console.log('Usage: router.js <task description>');
340
- console.log('\\nAvailable agents:', Object.keys(AGENT_CAPABILITIES).join(', '));
341
- }
342
-
343
- module.exports = { routeTask, AGENT_CAPABILITIES, TASK_PATTERNS, buildPattern };
255
+ return `#!/usr/bin/env node
256
+ /**
257
+ * Ruflo Agent Router
258
+ *
259
+ * Static keyword router that suggests an agent for a task description.
260
+ * NOTE: This is *not* a learned model. It is a heuristic table; "confidence"
261
+ * is reported as a heuristic prior, not a calibrated probability.
262
+ *
263
+ * #2257 fix: patterns are now word-boundary-anchored so short tokens like
264
+ * \`cd\`, \`ci\`, \`ui\`, \`add\`, \`structure\` no longer match inside unrelated
265
+ * words (\`decision\`, \`infrastructure\`, \`address\`, \`addendum\`). Default
266
+ * matched-confidence dropped from 0.8 to 0.6, and fall-through from 0.5 to
267
+ * 0.3, to reflect that this is a static heuristic, not a learned classifier.
268
+ */
269
+
270
+ const AGENT_CAPABILITIES = {
271
+ coder: ['code-generation', 'refactoring', 'debugging', 'implementation'],
272
+ tester: ['unit-testing', 'integration-testing', 'coverage', 'test-generation'],
273
+ reviewer: ['code-review', 'security-audit', 'quality-check', 'best-practices'],
274
+ researcher: ['web-search', 'documentation', 'analysis', 'summarization'],
275
+ architect: ['system-design', 'architecture', 'patterns', 'scalability'],
276
+ 'backend-dev': ['api', 'database', 'server', 'authentication'],
277
+ 'frontend-dev': ['ui', 'react', 'css', 'components'],
278
+ devops: ['ci-cd', 'docker', 'deployment', 'infrastructure'],
279
+ };
280
+
281
+ // Each entry has a token list. Single tokens get \\b…\\b boundaries so 'cd'
282
+ // won't match inside 'decide'. Phrases (whitespace or '/') match literally —
283
+ // the whitespace acts as a natural boundary.
284
+ const TASK_PATTERNS = [
285
+ { tokens: ['implement', 'create', 'build', 'add', 'write code', 'refactor', 'debug'], agent: 'coder' },
286
+ { tokens: ['test', 'tests', 'spec', 'coverage', 'unit test', 'integration test'], agent: 'tester' },
287
+ { tokens: ['review', 'audit', 'check', 'validate', 'security'], agent: 'reviewer' },
288
+ { tokens: ['research', 'find', 'search', 'documentation', 'explore'], agent: 'researcher' },
289
+ { tokens: ['design', 'architect', 'architecture', 'structure', 'plan'], agent: 'architect' },
290
+ { tokens: ['api', 'endpoint', 'server', 'backend', 'database'], agent: 'backend-dev' },
291
+ { tokens: ['ui', 'frontend', 'component', 'react', 'css', 'style'], agent: 'frontend-dev' },
292
+ { tokens: ['deploy', 'docker', 'ci', 'cd', 'ci/cd', 'pipeline', 'infrastructure', 'devops'], agent: 'devops' },
293
+ ];
294
+
295
+ function escapeRegex(s) {
296
+ return s.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
297
+ }
298
+
299
+ function buildPattern(tokens) {
300
+ const alternatives = tokens.map((tok) => {
301
+ const escaped = escapeRegex(tok.toLowerCase());
302
+ if (/\\s|\\//.test(tok)) return escaped;
303
+ return \`\\\\b\${escaped}\\\\b\`;
304
+ });
305
+ return new RegExp(\`(?:\${alternatives.join('|')})\`, 'i');
306
+ }
307
+
308
+ const COMPILED_PATTERNS = TASK_PATTERNS.map((entry) => ({
309
+ agent: entry.agent,
310
+ tokens: entry.tokens,
311
+ regex: buildPattern(entry.tokens),
312
+ }));
313
+
314
+ function routeTask(task) {
315
+ const taskLower = String(task == null ? '' : task).toLowerCase();
316
+ for (const entry of COMPILED_PATTERNS) {
317
+ if (entry.regex.test(taskLower)) {
318
+ return {
319
+ agent: entry.agent,
320
+ confidence: 0.6,
321
+ reason: \`Matched keyword(s) from: \${entry.tokens.join('|')}\`,
322
+ };
323
+ }
324
+ }
325
+ return {
326
+ agent: 'coder',
327
+ confidence: 0.3,
328
+ reason: 'Default routing - no specific keyword matched',
329
+ };
330
+ }
331
+
332
+ // CLI
333
+ const task = process.argv.slice(2).join(' ');
334
+
335
+ if (task) {
336
+ const result = routeTask(task);
337
+ console.log(JSON.stringify(result, null, 2));
338
+ } else {
339
+ console.log('Usage: router.js <task description>');
340
+ console.log('\\nAvailable agents:', Object.keys(AGENT_CAPABILITIES).join(', '));
341
+ }
342
+
343
+ module.exports = { routeTask, AGENT_CAPABILITIES, TASK_PATTERNS, buildPattern };
344
344
  `;
345
345
  }
346
346
  /**
347
347
  * Generate memory helper script
348
348
  */
349
349
  export function generateMemoryHelper() {
350
- return `#!/usr/bin/env node
351
- /**
352
- * Ruflo Memory Helper
353
- * Simple key-value memory for cross-session context
354
- */
355
-
356
- const fs = require('fs');
357
- const path = require('path');
358
-
359
- const MEMORY_DIR = path.join(process.cwd(), '.claude-flow', 'data');
360
- const MEMORY_FILE = path.join(MEMORY_DIR, 'memory.json');
361
-
362
- function loadMemory() {
363
- try {
364
- if (fs.existsSync(MEMORY_FILE)) {
365
- return JSON.parse(fs.readFileSync(MEMORY_FILE, 'utf-8'));
366
- }
367
- } catch (e) {
368
- // Ignore
369
- }
370
- return {};
371
- }
372
-
373
- function saveMemory(memory) {
374
- fs.mkdirSync(MEMORY_DIR, { recursive: true });
375
- fs.writeFileSync(MEMORY_FILE, JSON.stringify(memory, null, 2));
376
- }
377
-
378
- const commands = {
379
- get: (key) => {
380
- const memory = loadMemory();
381
- const value = key ? memory[key] : memory;
382
- console.log(JSON.stringify(value, null, 2));
383
- return value;
384
- },
385
-
386
- set: (key, value) => {
387
- if (!key) {
388
- console.error('Key required');
389
- return;
390
- }
391
- const memory = loadMemory();
392
- memory[key] = value;
393
- memory._updated = new Date().toISOString();
394
- saveMemory(memory);
395
- console.log(\`Set: \${key}\`);
396
- },
397
-
398
- delete: (key) => {
399
- if (!key) {
400
- console.error('Key required');
401
- return;
402
- }
403
- const memory = loadMemory();
404
- delete memory[key];
405
- saveMemory(memory);
406
- console.log(\`Deleted: \${key}\`);
407
- },
408
-
409
- clear: () => {
410
- saveMemory({});
411
- console.log('Memory cleared');
412
- },
413
-
414
- keys: () => {
415
- const memory = loadMemory();
416
- const keys = Object.keys(memory).filter(k => !k.startsWith('_'));
417
- console.log(keys.join('\\n'));
418
- return keys;
419
- },
420
- };
421
-
422
- // CLI
423
- const [,, command, key, ...valueParts] = process.argv;
424
- const value = valueParts.join(' ');
425
-
426
- if (command && commands[command]) {
427
- commands[command](key, value);
428
- } else {
429
- console.log('Usage: memory.js <get|set|delete|clear|keys> [key] [value]');
430
- }
431
-
432
- module.exports = commands;
350
+ return `#!/usr/bin/env node
351
+ /**
352
+ * Ruflo Memory Helper
353
+ * Simple key-value memory for cross-session context
354
+ */
355
+
356
+ const fs = require('fs');
357
+ const path = require('path');
358
+
359
+ const MEMORY_DIR = path.join(process.cwd(), '.claude-flow', 'data');
360
+ const MEMORY_FILE = path.join(MEMORY_DIR, 'memory.json');
361
+
362
+ function loadMemory() {
363
+ try {
364
+ if (fs.existsSync(MEMORY_FILE)) {
365
+ return JSON.parse(fs.readFileSync(MEMORY_FILE, 'utf-8'));
366
+ }
367
+ } catch (e) {
368
+ // Ignore
369
+ }
370
+ return {};
371
+ }
372
+
373
+ function saveMemory(memory) {
374
+ fs.mkdirSync(MEMORY_DIR, { recursive: true });
375
+ fs.writeFileSync(MEMORY_FILE, JSON.stringify(memory, null, 2));
376
+ }
377
+
378
+ const commands = {
379
+ get: (key) => {
380
+ const memory = loadMemory();
381
+ const value = key ? memory[key] : memory;
382
+ console.log(JSON.stringify(value, null, 2));
383
+ return value;
384
+ },
385
+
386
+ set: (key, value) => {
387
+ if (!key) {
388
+ console.error('Key required');
389
+ return;
390
+ }
391
+ const memory = loadMemory();
392
+ memory[key] = value;
393
+ memory._updated = new Date().toISOString();
394
+ saveMemory(memory);
395
+ console.log(\`Set: \${key}\`);
396
+ },
397
+
398
+ delete: (key) => {
399
+ if (!key) {
400
+ console.error('Key required');
401
+ return;
402
+ }
403
+ const memory = loadMemory();
404
+ delete memory[key];
405
+ saveMemory(memory);
406
+ console.log(\`Deleted: \${key}\`);
407
+ },
408
+
409
+ clear: () => {
410
+ saveMemory({});
411
+ console.log('Memory cleared');
412
+ },
413
+
414
+ keys: () => {
415
+ const memory = loadMemory();
416
+ const keys = Object.keys(memory).filter(k => !k.startsWith('_'));
417
+ console.log(keys.join('\\n'));
418
+ return keys;
419
+ },
420
+ };
421
+
422
+ // CLI
423
+ const [,, command, key, ...valueParts] = process.argv;
424
+ const value = valueParts.join(' ');
425
+
426
+ if (command && commands[command]) {
427
+ commands[command](key, value);
428
+ } else {
429
+ console.log('Usage: memory.js <get|set|delete|clear|keys> [key] [value]');
430
+ }
431
+
432
+ module.exports = commands;
433
433
  `;
434
434
  }
435
435
  /**
@@ -992,375 +992,375 @@ export function generateIntelligenceStub() {
992
992
  * @claude-flow/memory is not installed. Gets overwritten when source copy succeeds.
993
993
  */
994
994
  export function generateAutoMemoryHook() {
995
- return `#!/usr/bin/env node
996
- /**
997
- * Auto Memory Bridge Hook (ADR-048/049) — Minimal Fallback
998
- * Full version is copied from package source when available.
999
- *
1000
- * Usage:
1001
- * node auto-memory-hook.mjs import # SessionStart
1002
- * node auto-memory-hook.mjs sync # SessionEnd / Stop
1003
- * node auto-memory-hook.mjs status # Show bridge status
1004
- */
1005
-
1006
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
1007
- import { join, dirname } from 'path';
1008
- import { fileURLToPath } from 'url';
1009
-
1010
- const __filename = fileURLToPath(import.meta.url);
1011
- const __dirname = dirname(__filename);
1012
- const PROJECT_ROOT = join(__dirname, '../..');
1013
- const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
1014
- const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
1015
-
1016
- const DIM = '\\x1b[2m';
1017
- const YELLOW = '\\x1b[0;33m';
1018
- const RESET = '\\x1b[0m';
1019
- const dim = (msg) => console.log(\` \${DIM}\${msg}\${RESET}\`);
1020
-
1021
- // #2545: fail LOUD instead of a silent dim skip when @claude-flow/memory is
1022
- // unresolvable — self-learning imports are a no-op and the user must be told.
1023
- function warnMemoryUnavailable() {
1024
- const l1 = \`[AutoMemory] @claude-flow/memory not resolvable from \${PROJECT_ROOT} — self-learning imports are DISABLED.\`;
1025
- const l2 = ' Fix: npm i -D @claude-flow/memory (or re-run: npx ruflo@latest init, then npx ruflo@latest doctor --fix)';
1026
- console.log(\`\${YELLOW}\${l1}\${RESET}\`);
1027
- console.log(\`\${YELLOW}\${l2}\${RESET}\`);
1028
- process.stderr.write(\`\${l1}\\n\${l2}\\n\`);
1029
- }
1030
-
1031
- // Ensure data dir
1032
- if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
1033
-
1034
- async function loadMemoryPackage() {
1035
- // Strategy 0 (#2545): sidecar recorded by \`init\` / \`doctor --fix\`. On the npx
1036
- // path @claude-flow/memory lands in the npx cache (unreachable by walk-up), so
1037
- // init records its absolute path here — the only strategy that works there.
1038
- try {
1039
- const sidecar = join(PROJECT_ROOT, '.claude-flow', 'memory-package.json');
1040
- if (existsSync(sidecar)) {
1041
- const rec = JSON.parse(readFileSync(sidecar, 'utf-8'));
1042
- if (rec && rec.distPath && existsSync(rec.distPath)) {
1043
- return await import(\`file://\${rec.distPath}\`);
1044
- }
1045
- }
1046
- } catch { /* fall through */ }
1047
-
1048
- // Strategy 1: Use createRequire for CJS-style resolution (handles nested node_modules
1049
- // when installed as a transitive dependency via npx ruflo / npx claude-flow)
1050
- try {
1051
- const { createRequire } = await import('module');
1052
- const require = createRequire(join(PROJECT_ROOT, 'package.json'));
1053
- return require('@claude-flow/memory');
1054
- } catch { /* fall through */ }
1055
-
1056
- // Strategy 2: ESM import (works when @claude-flow/memory is a direct dependency)
1057
- try { return await import('@claude-flow/memory'); } catch { /* fall through */ }
1058
-
1059
- // Strategy 3: Walk up from PROJECT_ROOT looking for the package in any node_modules
1060
- let searchDir = PROJECT_ROOT;
1061
- const { parse } = await import('path');
1062
- while (searchDir !== parse(searchDir).root) {
1063
- const candidate = join(searchDir, 'node_modules', '@claude-flow', 'memory', 'dist', 'index.js');
1064
- if (existsSync(candidate)) {
1065
- try { return await import(\`file://\${candidate}\`); } catch { /* fall through */ }
1066
- }
1067
- searchDir = dirname(searchDir);
1068
- }
1069
-
1070
- return null;
1071
- }
1072
-
1073
- async function doImport() {
1074
- const memPkg = await loadMemoryPackage();
1075
-
1076
- if (!memPkg || !memPkg.AutoMemoryBridge) {
1077
- warnMemoryUnavailable();
1078
- return;
1079
- }
1080
-
1081
- // Full implementation deferred to copied version
1082
- dim('Auto memory import available — run init --upgrade for full support');
1083
- }
1084
-
1085
- async function doSync() {
1086
- if (!existsSync(STORE_PATH)) {
1087
- dim('No entries to sync');
1088
- return;
1089
- }
1090
-
1091
- const memPkg = await loadMemoryPackage();
1092
-
1093
- if (!memPkg || !memPkg.AutoMemoryBridge) {
1094
- warnMemoryUnavailable();
1095
- return;
1096
- }
1097
-
1098
- dim('Auto memory sync available — run init --upgrade for full support');
1099
- }
1100
-
1101
- function doStatus() {
1102
- console.log('\\n=== Auto Memory Bridge Status ===\\n');
1103
- console.log(' Package: Fallback mode (run init --upgrade for full)');
1104
- console.log(\` Store: \${existsSync(STORE_PATH) ? 'Initialized' : 'Not initialized'}\`);
1105
- console.log('');
1106
- }
1107
-
1108
- // Suppress unhandled rejection warnings from dynamic import() failures
1109
- process.on('unhandledRejection', () => {});
1110
-
1111
- const command = process.argv[2] || 'status';
1112
-
1113
- try {
1114
- switch (command) {
1115
- case 'import': await doImport(); break;
1116
- case 'sync': await doSync(); break;
1117
- case 'status': doStatus(); break;
1118
- default:
1119
- console.log('Usage: auto-memory-hook.mjs <import|sync|status>');
1120
- process.exit(1);
1121
- }
1122
- } catch (err) {
1123
- // Hooks must never crash Claude Code - fail silently
1124
- dim(\`Error (non-critical): \${err.message}\`);
1125
- }
1126
- // Ensure clean exit for Claude Code hooks (exit 0 = success)
1127
- process.exit(0);
995
+ return `#!/usr/bin/env node
996
+ /**
997
+ * Auto Memory Bridge Hook (ADR-048/049) — Minimal Fallback
998
+ * Full version is copied from package source when available.
999
+ *
1000
+ * Usage:
1001
+ * node auto-memory-hook.mjs import # SessionStart
1002
+ * node auto-memory-hook.mjs sync # SessionEnd / Stop
1003
+ * node auto-memory-hook.mjs status # Show bridge status
1004
+ */
1005
+
1006
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
1007
+ import { join, dirname } from 'path';
1008
+ import { fileURLToPath } from 'url';
1009
+
1010
+ const __filename = fileURLToPath(import.meta.url);
1011
+ const __dirname = dirname(__filename);
1012
+ const PROJECT_ROOT = join(__dirname, '../..');
1013
+ const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
1014
+ const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
1015
+
1016
+ const DIM = '\\x1b[2m';
1017
+ const YELLOW = '\\x1b[0;33m';
1018
+ const RESET = '\\x1b[0m';
1019
+ const dim = (msg) => console.log(\` \${DIM}\${msg}\${RESET}\`);
1020
+
1021
+ // #2545: fail LOUD instead of a silent dim skip when @claude-flow/memory is
1022
+ // unresolvable — self-learning imports are a no-op and the user must be told.
1023
+ function warnMemoryUnavailable() {
1024
+ const l1 = \`[AutoMemory] @claude-flow/memory not resolvable from \${PROJECT_ROOT} — self-learning imports are DISABLED.\`;
1025
+ const l2 = ' Fix: npm i -D @claude-flow/memory (or re-run: npx ruflo@latest init, then npx ruflo@latest doctor --fix)';
1026
+ console.log(\`\${YELLOW}\${l1}\${RESET}\`);
1027
+ console.log(\`\${YELLOW}\${l2}\${RESET}\`);
1028
+ process.stderr.write(\`\${l1}\\n\${l2}\\n\`);
1029
+ }
1030
+
1031
+ // Ensure data dir
1032
+ if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
1033
+
1034
+ async function loadMemoryPackage() {
1035
+ // Strategy 0 (#2545): sidecar recorded by \`init\` / \`doctor --fix\`. On the npx
1036
+ // path @claude-flow/memory lands in the npx cache (unreachable by walk-up), so
1037
+ // init records its absolute path here — the only strategy that works there.
1038
+ try {
1039
+ const sidecar = join(PROJECT_ROOT, '.claude-flow', 'memory-package.json');
1040
+ if (existsSync(sidecar)) {
1041
+ const rec = JSON.parse(readFileSync(sidecar, 'utf-8'));
1042
+ if (rec && rec.distPath && existsSync(rec.distPath)) {
1043
+ return await import(\`file://\${rec.distPath}\`);
1044
+ }
1045
+ }
1046
+ } catch { /* fall through */ }
1047
+
1048
+ // Strategy 1: Use createRequire for CJS-style resolution (handles nested node_modules
1049
+ // when installed as a transitive dependency via npx ruflo / npx claude-flow)
1050
+ try {
1051
+ const { createRequire } = await import('module');
1052
+ const require = createRequire(join(PROJECT_ROOT, 'package.json'));
1053
+ return require('@claude-flow/memory');
1054
+ } catch { /* fall through */ }
1055
+
1056
+ // Strategy 2: ESM import (works when @claude-flow/memory is a direct dependency)
1057
+ try { return await import('@claude-flow/memory'); } catch { /* fall through */ }
1058
+
1059
+ // Strategy 3: Walk up from PROJECT_ROOT looking for the package in any node_modules
1060
+ let searchDir = PROJECT_ROOT;
1061
+ const { parse } = await import('path');
1062
+ while (searchDir !== parse(searchDir).root) {
1063
+ const candidate = join(searchDir, 'node_modules', '@claude-flow', 'memory', 'dist', 'index.js');
1064
+ if (existsSync(candidate)) {
1065
+ try { return await import(\`file://\${candidate}\`); } catch { /* fall through */ }
1066
+ }
1067
+ searchDir = dirname(searchDir);
1068
+ }
1069
+
1070
+ return null;
1071
+ }
1072
+
1073
+ async function doImport() {
1074
+ const memPkg = await loadMemoryPackage();
1075
+
1076
+ if (!memPkg || !memPkg.AutoMemoryBridge) {
1077
+ warnMemoryUnavailable();
1078
+ return;
1079
+ }
1080
+
1081
+ // Full implementation deferred to copied version
1082
+ dim('Auto memory import available — run init --upgrade for full support');
1083
+ }
1084
+
1085
+ async function doSync() {
1086
+ if (!existsSync(STORE_PATH)) {
1087
+ dim('No entries to sync');
1088
+ return;
1089
+ }
1090
+
1091
+ const memPkg = await loadMemoryPackage();
1092
+
1093
+ if (!memPkg || !memPkg.AutoMemoryBridge) {
1094
+ warnMemoryUnavailable();
1095
+ return;
1096
+ }
1097
+
1098
+ dim('Auto memory sync available — run init --upgrade for full support');
1099
+ }
1100
+
1101
+ function doStatus() {
1102
+ console.log('\\n=== Auto Memory Bridge Status ===\\n');
1103
+ console.log(' Package: Fallback mode (run init --upgrade for full)');
1104
+ console.log(\` Store: \${existsSync(STORE_PATH) ? 'Initialized' : 'Not initialized'}\`);
1105
+ console.log('');
1106
+ }
1107
+
1108
+ // Suppress unhandled rejection warnings from dynamic import() failures
1109
+ process.on('unhandledRejection', () => {});
1110
+
1111
+ const command = process.argv[2] || 'status';
1112
+
1113
+ try {
1114
+ switch (command) {
1115
+ case 'import': await doImport(); break;
1116
+ case 'sync': await doSync(); break;
1117
+ case 'status': doStatus(); break;
1118
+ default:
1119
+ console.log('Usage: auto-memory-hook.mjs <import|sync|status>');
1120
+ process.exit(1);
1121
+ }
1122
+ } catch (err) {
1123
+ // Hooks must never crash Claude Code - fail silently
1124
+ dim(\`Error (non-critical): \${err.message}\`);
1125
+ }
1126
+ // Ensure clean exit for Claude Code hooks (exit 0 = success)
1127
+ process.exit(0);
1128
1128
  `;
1129
1129
  }
1130
1130
  /**
1131
1131
  * Generate Windows PowerShell daemon manager
1132
1132
  */
1133
1133
  export function generateWindowsDaemonManager() {
1134
- return `# RuFlo V3 Daemon Manager for Windows
1135
- # PowerShell script for managing background processes
1136
-
1137
- param(
1138
- [Parameter(Position=0)]
1139
- [ValidateSet('start', 'stop', 'status', 'restart')]
1140
- [string]$Action = 'status'
1141
- )
1142
-
1143
- $ErrorActionPreference = 'SilentlyContinue'
1144
- $ClaudeFlowDir = Join-Path $PWD '.claude-flow'
1145
- $PidDir = Join-Path $ClaudeFlowDir 'pids'
1146
-
1147
- # Ensure directories exist
1148
- if (-not (Test-Path $PidDir)) {
1149
- New-Item -ItemType Directory -Path $PidDir -Force | Out-Null
1150
- }
1151
-
1152
- function Get-DaemonStatus {
1153
- param([string]$Name, [string]$PidFile)
1154
-
1155
- if (Test-Path $PidFile) {
1156
- $pid = Get-Content $PidFile
1157
- $process = Get-Process -Id $pid -ErrorAction SilentlyContinue
1158
- if ($process) {
1159
- return @{ Running = $true; Pid = $pid }
1160
- }
1161
- }
1162
- return @{ Running = $false; Pid = $null }
1163
- }
1164
-
1165
- function Start-SwarmMonitor {
1166
- $pidFile = Join-Path $PidDir 'swarm-monitor.pid'
1167
- $status = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $pidFile
1168
-
1169
- if ($status.Running) {
1170
- Write-Host "Swarm monitor already running (PID: $($status.Pid))" -ForegroundColor Yellow
1171
- return
1172
- }
1173
-
1174
- Write-Host "Starting swarm monitor..." -ForegroundColor Cyan
1175
- $process = Start-Process -FilePath 'node' -ArgumentList @(
1176
- '-e',
1177
- 'setInterval(() => { require("fs").writeFileSync(".claude-flow/metrics/swarm-activity.json", JSON.stringify({swarm:{active:true,agent_count:0},timestamp:Date.now()})) }, 5000)'
1178
- ) -PassThru -WindowStyle Hidden
1179
-
1180
- $process.Id | Out-File $pidFile
1181
- Write-Host "Swarm monitor started (PID: $($process.Id))" -ForegroundColor Green
1182
- }
1183
-
1184
- function Stop-SwarmMonitor {
1185
- $pidFile = Join-Path $PidDir 'swarm-monitor.pid'
1186
- $status = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $pidFile
1187
-
1188
- if (-not $status.Running) {
1189
- Write-Host "Swarm monitor not running" -ForegroundColor Yellow
1190
- return
1191
- }
1192
-
1193
- Stop-Process -Id $status.Pid -Force
1194
- Remove-Item $pidFile -Force
1195
- Write-Host "Swarm monitor stopped" -ForegroundColor Green
1196
- }
1197
-
1198
- function Show-Status {
1199
- Write-Host ""
1200
- Write-Host "RuFlo V3 Daemon Status" -ForegroundColor Cyan
1201
- Write-Host "=============================" -ForegroundColor Cyan
1202
-
1203
- $swarmPid = Join-Path $PidDir 'swarm-monitor.pid'
1204
- $swarmStatus = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $swarmPid
1205
-
1206
- if ($swarmStatus.Running) {
1207
- Write-Host " Swarm Monitor: RUNNING (PID: $($swarmStatus.Pid))" -ForegroundColor Green
1208
- } else {
1209
- Write-Host " Swarm Monitor: STOPPED" -ForegroundColor Red
1210
- }
1211
- Write-Host ""
1212
- }
1213
-
1214
- switch ($Action) {
1215
- 'start' {
1216
- Start-SwarmMonitor
1217
- Show-Status
1218
- }
1219
- 'stop' {
1220
- Stop-SwarmMonitor
1221
- Show-Status
1222
- }
1223
- 'restart' {
1224
- Stop-SwarmMonitor
1225
- Start-Sleep -Seconds 1
1226
- Start-SwarmMonitor
1227
- Show-Status
1228
- }
1229
- 'status' {
1230
- Show-Status
1231
- }
1232
- }
1134
+ return `# RuFlo V3 Daemon Manager for Windows
1135
+ # PowerShell script for managing background processes
1136
+
1137
+ param(
1138
+ [Parameter(Position=0)]
1139
+ [ValidateSet('start', 'stop', 'status', 'restart')]
1140
+ [string]$Action = 'status'
1141
+ )
1142
+
1143
+ $ErrorActionPreference = 'SilentlyContinue'
1144
+ $ClaudeFlowDir = Join-Path $PWD '.claude-flow'
1145
+ $PidDir = Join-Path $ClaudeFlowDir 'pids'
1146
+
1147
+ # Ensure directories exist
1148
+ if (-not (Test-Path $PidDir)) {
1149
+ New-Item -ItemType Directory -Path $PidDir -Force | Out-Null
1150
+ }
1151
+
1152
+ function Get-DaemonStatus {
1153
+ param([string]$Name, [string]$PidFile)
1154
+
1155
+ if (Test-Path $PidFile) {
1156
+ $pid = Get-Content $PidFile
1157
+ $process = Get-Process -Id $pid -ErrorAction SilentlyContinue
1158
+ if ($process) {
1159
+ return @{ Running = $true; Pid = $pid }
1160
+ }
1161
+ }
1162
+ return @{ Running = $false; Pid = $null }
1163
+ }
1164
+
1165
+ function Start-SwarmMonitor {
1166
+ $pidFile = Join-Path $PidDir 'swarm-monitor.pid'
1167
+ $status = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $pidFile
1168
+
1169
+ if ($status.Running) {
1170
+ Write-Host "Swarm monitor already running (PID: $($status.Pid))" -ForegroundColor Yellow
1171
+ return
1172
+ }
1173
+
1174
+ Write-Host "Starting swarm monitor..." -ForegroundColor Cyan
1175
+ $process = Start-Process -FilePath 'node' -ArgumentList @(
1176
+ '-e',
1177
+ 'setInterval(() => { require("fs").writeFileSync(".claude-flow/metrics/swarm-activity.json", JSON.stringify({swarm:{active:true,agent_count:0},timestamp:Date.now()})) }, 5000)'
1178
+ ) -PassThru -WindowStyle Hidden
1179
+
1180
+ $process.Id | Out-File $pidFile
1181
+ Write-Host "Swarm monitor started (PID: $($process.Id))" -ForegroundColor Green
1182
+ }
1183
+
1184
+ function Stop-SwarmMonitor {
1185
+ $pidFile = Join-Path $PidDir 'swarm-monitor.pid'
1186
+ $status = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $pidFile
1187
+
1188
+ if (-not $status.Running) {
1189
+ Write-Host "Swarm monitor not running" -ForegroundColor Yellow
1190
+ return
1191
+ }
1192
+
1193
+ Stop-Process -Id $status.Pid -Force
1194
+ Remove-Item $pidFile -Force
1195
+ Write-Host "Swarm monitor stopped" -ForegroundColor Green
1196
+ }
1197
+
1198
+ function Show-Status {
1199
+ Write-Host ""
1200
+ Write-Host "RuFlo V3 Daemon Status" -ForegroundColor Cyan
1201
+ Write-Host "=============================" -ForegroundColor Cyan
1202
+
1203
+ $swarmPid = Join-Path $PidDir 'swarm-monitor.pid'
1204
+ $swarmStatus = Get-DaemonStatus -Name 'swarm-monitor' -PidFile $swarmPid
1205
+
1206
+ if ($swarmStatus.Running) {
1207
+ Write-Host " Swarm Monitor: RUNNING (PID: $($swarmStatus.Pid))" -ForegroundColor Green
1208
+ } else {
1209
+ Write-Host " Swarm Monitor: STOPPED" -ForegroundColor Red
1210
+ }
1211
+ Write-Host ""
1212
+ }
1213
+
1214
+ switch ($Action) {
1215
+ 'start' {
1216
+ Start-SwarmMonitor
1217
+ Show-Status
1218
+ }
1219
+ 'stop' {
1220
+ Stop-SwarmMonitor
1221
+ Show-Status
1222
+ }
1223
+ 'restart' {
1224
+ Stop-SwarmMonitor
1225
+ Start-Sleep -Seconds 1
1226
+ Start-SwarmMonitor
1227
+ Show-Status
1228
+ }
1229
+ 'status' {
1230
+ Show-Status
1231
+ }
1232
+ }
1233
1233
  `;
1234
1234
  }
1235
1235
  /**
1236
1236
  * Generate Windows batch file wrapper
1237
1237
  */
1238
1238
  export function generateWindowsBatchWrapper() {
1239
- return `@echo off
1240
- REM RuFlo V3 - Windows Batch Wrapper
1241
- REM Routes to PowerShell daemon manager
1242
-
1243
- PowerShell -ExecutionPolicy Bypass -File "%~dp0daemon-manager.ps1" %*
1239
+ return `@echo off
1240
+ REM RuFlo V3 - Windows Batch Wrapper
1241
+ REM Routes to PowerShell daemon manager
1242
+
1243
+ PowerShell -ExecutionPolicy Bypass -File "%~dp0daemon-manager.ps1" %*
1244
1244
  `;
1245
1245
  }
1246
1246
  /**
1247
1247
  * Generate cross-platform session manager
1248
1248
  */
1249
1249
  export function generateCrossPlatformSessionManager() {
1250
- return `#!/usr/bin/env node
1251
- /**
1252
- * Ruflo Cross-Platform Session Manager
1253
- * Works on Windows, macOS, and Linux
1254
- */
1255
-
1256
- const fs = require('fs');
1257
- const path = require('path');
1258
- const os = require('os');
1259
-
1260
- // Platform-specific paths
1261
- const platform = os.platform();
1262
- const homeDir = os.homedir();
1263
-
1264
- // Get data directory based on platform
1265
- function getDataDir() {
1266
- const localDir = path.join(process.cwd(), '.claude-flow', 'sessions');
1267
- if (fs.existsSync(path.dirname(localDir))) {
1268
- return localDir;
1269
- }
1270
-
1271
- switch (platform) {
1272
- case 'win32':
1273
- return path.join(process.env.APPDATA || homeDir, 'claude-flow', 'sessions');
1274
- case 'darwin':
1275
- return path.join(homeDir, 'Library', 'Application Support', 'claude-flow', 'sessions');
1276
- default:
1277
- return path.join(homeDir, '.claude-flow', 'sessions');
1278
- }
1279
- }
1280
-
1281
- const SESSION_DIR = getDataDir();
1282
- const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
1283
-
1284
- // Ensure directory exists
1285
- function ensureDir(dir) {
1286
- if (!fs.existsSync(dir)) {
1287
- fs.mkdirSync(dir, { recursive: true });
1288
- }
1289
- }
1290
-
1291
- const commands = {
1292
- start: () => {
1293
- ensureDir(SESSION_DIR);
1294
- const sessionId = \`session-\${Date.now()}\`;
1295
- const session = {
1296
- id: sessionId,
1297
- startedAt: new Date().toISOString(),
1298
- platform: platform,
1299
- cwd: process.cwd(),
1300
- context: {},
1301
- metrics: { edits: 0, commands: 0, tasks: 0, errors: 0 }
1302
- };
1303
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
1304
- console.log(\`Session started: \${sessionId}\`);
1305
- return session;
1306
- },
1307
-
1308
- restore: () => {
1309
- if (!fs.existsSync(SESSION_FILE)) {
1310
- console.log('No session to restore');
1311
- return null;
1312
- }
1313
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1314
- session.restoredAt = new Date().toISOString();
1315
- fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
1316
- console.log(\`Session restored: \${session.id}\`);
1317
- return session;
1318
- },
1319
-
1320
- end: () => {
1321
- if (!fs.existsSync(SESSION_FILE)) {
1322
- console.log('No active session');
1323
- return null;
1324
- }
1325
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1326
- session.endedAt = new Date().toISOString();
1327
- session.duration = Date.now() - new Date(session.startedAt).getTime();
1328
-
1329
- const archivePath = path.join(SESSION_DIR, \`\${session.id}.json\`);
1330
- fs.writeFileSync(archivePath, JSON.stringify(session, null, 2));
1331
- fs.unlinkSync(SESSION_FILE);
1332
-
1333
- console.log(\`Session ended: \${session.id}\`);
1334
- console.log(\`Duration: \${Math.round(session.duration / 1000 / 60)} minutes\`);
1335
- return session;
1336
- },
1337
-
1338
- status: () => {
1339
- if (!fs.existsSync(SESSION_FILE)) {
1340
- console.log('No active session');
1341
- return null;
1342
- }
1343
- const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1344
- const duration = Date.now() - new Date(session.startedAt).getTime();
1345
- console.log(\`Session: \${session.id}\`);
1346
- console.log(\`Platform: \${session.platform}\`);
1347
- console.log(\`Started: \${session.startedAt}\`);
1348
- console.log(\`Duration: \${Math.round(duration / 1000 / 60)} minutes\`);
1349
- return session;
1350
- }
1351
- };
1352
-
1353
- // CLI
1354
- const [,, command, ...args] = process.argv;
1355
- if (command && commands[command]) {
1356
- commands[command](...args);
1357
- } else {
1358
- console.log('Usage: session.js <start|restore|end|status>');
1359
- console.log(\`Platform: \${platform}\`);
1360
- console.log(\`Data dir: \${SESSION_DIR}\`);
1361
- }
1362
-
1363
- module.exports = commands;
1250
+ return `#!/usr/bin/env node
1251
+ /**
1252
+ * Ruflo Cross-Platform Session Manager
1253
+ * Works on Windows, macOS, and Linux
1254
+ */
1255
+
1256
+ const fs = require('fs');
1257
+ const path = require('path');
1258
+ const os = require('os');
1259
+
1260
+ // Platform-specific paths
1261
+ const platform = os.platform();
1262
+ const homeDir = os.homedir();
1263
+
1264
+ // Get data directory based on platform
1265
+ function getDataDir() {
1266
+ const localDir = path.join(process.cwd(), '.claude-flow', 'sessions');
1267
+ if (fs.existsSync(path.dirname(localDir))) {
1268
+ return localDir;
1269
+ }
1270
+
1271
+ switch (platform) {
1272
+ case 'win32':
1273
+ return path.join(process.env.APPDATA || homeDir, 'claude-flow', 'sessions');
1274
+ case 'darwin':
1275
+ return path.join(homeDir, 'Library', 'Application Support', 'claude-flow', 'sessions');
1276
+ default:
1277
+ return path.join(homeDir, '.claude-flow', 'sessions');
1278
+ }
1279
+ }
1280
+
1281
+ const SESSION_DIR = getDataDir();
1282
+ const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
1283
+
1284
+ // Ensure directory exists
1285
+ function ensureDir(dir) {
1286
+ if (!fs.existsSync(dir)) {
1287
+ fs.mkdirSync(dir, { recursive: true });
1288
+ }
1289
+ }
1290
+
1291
+ const commands = {
1292
+ start: () => {
1293
+ ensureDir(SESSION_DIR);
1294
+ const sessionId = \`session-\${Date.now()}\`;
1295
+ const session = {
1296
+ id: sessionId,
1297
+ startedAt: new Date().toISOString(),
1298
+ platform: platform,
1299
+ cwd: process.cwd(),
1300
+ context: {},
1301
+ metrics: { edits: 0, commands: 0, tasks: 0, errors: 0 }
1302
+ };
1303
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
1304
+ console.log(\`Session started: \${sessionId}\`);
1305
+ return session;
1306
+ },
1307
+
1308
+ restore: () => {
1309
+ if (!fs.existsSync(SESSION_FILE)) {
1310
+ console.log('No session to restore');
1311
+ return null;
1312
+ }
1313
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1314
+ session.restoredAt = new Date().toISOString();
1315
+ fs.writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
1316
+ console.log(\`Session restored: \${session.id}\`);
1317
+ return session;
1318
+ },
1319
+
1320
+ end: () => {
1321
+ if (!fs.existsSync(SESSION_FILE)) {
1322
+ console.log('No active session');
1323
+ return null;
1324
+ }
1325
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1326
+ session.endedAt = new Date().toISOString();
1327
+ session.duration = Date.now() - new Date(session.startedAt).getTime();
1328
+
1329
+ const archivePath = path.join(SESSION_DIR, \`\${session.id}.json\`);
1330
+ fs.writeFileSync(archivePath, JSON.stringify(session, null, 2));
1331
+ fs.unlinkSync(SESSION_FILE);
1332
+
1333
+ console.log(\`Session ended: \${session.id}\`);
1334
+ console.log(\`Duration: \${Math.round(session.duration / 1000 / 60)} minutes\`);
1335
+ return session;
1336
+ },
1337
+
1338
+ status: () => {
1339
+ if (!fs.existsSync(SESSION_FILE)) {
1340
+ console.log('No active session');
1341
+ return null;
1342
+ }
1343
+ const session = JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
1344
+ const duration = Date.now() - new Date(session.startedAt).getTime();
1345
+ console.log(\`Session: \${session.id}\`);
1346
+ console.log(\`Platform: \${session.platform}\`);
1347
+ console.log(\`Started: \${session.startedAt}\`);
1348
+ console.log(\`Duration: \${Math.round(duration / 1000 / 60)} minutes\`);
1349
+ return session;
1350
+ }
1351
+ };
1352
+
1353
+ // CLI
1354
+ const [,, command, ...args] = process.argv;
1355
+ if (command && commands[command]) {
1356
+ commands[command](...args);
1357
+ } else {
1358
+ console.log('Usage: session.js <start|restore|end|status>');
1359
+ console.log(\`Platform: \${platform}\`);
1360
+ console.log(\`Data dir: \${SESSION_DIR}\`);
1361
+ }
1362
+
1363
+ module.exports = commands;
1364
1364
  `;
1365
1365
  }
1366
1366
  /**
@@ -1403,65 +1403,231 @@ export function generateHelpers(options) {
1403
1403
  * - Both: .claude/helpers/ruflo-hook.cjs available as a canonical cross-platform shim
1404
1404
  */
1405
1405
  export function generateRufloHookCjs() {
1406
- return `#!/usr/bin/env node
1407
- /**
1408
- * ruflo-hook.cjs — cross-platform Node.js port of ruflo-hook.sh (#2132)
1409
- *
1410
- * Deployed to .claude/helpers/ during ruflo init. On Windows, the
1411
- * generated .claude/settings.json hooks point here instead of the
1412
- * plugin's bash-only ruflo-hook.sh.
1413
- *
1414
- * Always exits 0 — hook subcommands are best-effort telemetry and must
1415
- * never block a Claude Code turn.
1416
- */
1417
-
1418
- 'use strict';
1419
-
1420
- const { spawnSync, execSync } = require('child_process');
1421
- const fs = require('fs');
1422
-
1423
- function done() { process.exit(0); }
1424
-
1425
- function commandExists(cmd) {
1426
- try {
1427
- const r = execSync(
1428
- process.platform === 'win32' ? 'where ' + cmd : 'command -v ' + cmd,
1429
- { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }
1430
- );
1431
- return r.trim().length > 0;
1432
- } catch { return false; }
1433
- }
1434
-
1435
- function invokeHook(bin, binArgs, hookArgs, stdinData) {
1436
- const args = [...binArgs, ...hookArgs];
1437
- const result = spawnSync(bin, args, {
1438
- shell: process.platform === 'win32',
1439
- input: stdinData || '',
1440
- encoding: 'utf8',
1441
- stdio: ['pipe', 'ignore', 'ignore'],
1442
- timeout: 30_000,
1443
- });
1444
- return result.status === 0;
1445
- }
1446
-
1447
- function main() {
1448
- const args = process.argv.slice(2);
1449
- if (args.length === 0) done();
1450
-
1451
- const [subcommand, ...rest] = args;
1452
-
1453
- let stdinData = '';
1454
- try { stdinData = fs.readFileSync(0, 'utf8'); } catch { stdinData = ''; }
1455
-
1456
- const hookArgs = ['hooks', subcommand, ...rest];
1457
-
1458
- if (commandExists('ruflo')) { invokeHook('ruflo', [], hookArgs, stdinData); done(); }
1459
- if (commandExists('claude-flow')) { invokeHook('claude-flow', [], hookArgs, stdinData); done(); }
1460
- invokeHook('npx', ['--prefer-offline', '--yes', 'ruflo@latest'], hookArgs, stdinData);
1461
- done();
1462
- }
1463
-
1464
- main();
1406
+ return `#!/usr/bin/env node
1407
+ /**
1408
+ * ruflo-hook.cjs — cross-platform Node.js port of ruflo-hook.sh (#2132)
1409
+ *
1410
+ * Deployed to .claude/helpers/ during ruflo init. On Windows, the
1411
+ * generated .claude/settings.json hooks point here instead of the
1412
+ * plugin's bash-only ruflo-hook.sh.
1413
+ *
1414
+ * Always exits 0 — hook subcommands are best-effort telemetry and must
1415
+ * never block a Claude Code turn.
1416
+ *
1417
+ * Windows argv integrity: hook-derived values (a Bash tool's \`command\`, a file path) must
1418
+ * reach the CLI as literal argv and never as shell syntax. Two layers, in
1419
+ * this order:
1420
+ *
1421
+ * 1. resolveInvocation() maps the command to a real executable — and on
1422
+ * Windows maps npm's .cmd shim to the package's own .js entrypoint —
1423
+ * so the spawn runs \`node <entry>\` with shell:false and NO cmd.exe in
1424
+ * the chain at all. Nothing to escape, nothing to re-tokenize, and no
1425
+ * %VAR% expansion. (The escaped fallback was measured on a real
1426
+ * windows-latest runner and does pass %VAR% through literally; layer 1
1427
+ * is still preferred because it removes the parser rather than
1428
+ * out-guessing it.)
1429
+ * 2. escapeCmdArg() guards the residual Windows path where step 1 cannot
1430
+ * identify an entrypoint. Escaping is strictly the weaker layer: it is
1431
+ * only reachable when resolution fails, and it is the one part of this
1432
+ * file that a non-Windows CI run cannot prove.
1433
+ */
1434
+
1435
+ 'use strict';
1436
+
1437
+ const { spawnSync } = require('child_process');
1438
+ const fs = require('fs');
1439
+ const path = require('path');
1440
+
1441
+ function done() { process.exit(0); }
1442
+
1443
+ /** Case-insensitive env lookup — Windows env keys are not case-stable. */
1444
+ function envValue(env, name) {
1445
+ const key = Object.keys(env).find((c) => c.toLowerCase() === name.toLowerCase());
1446
+ return key ? env[key] : undefined;
1447
+ }
1448
+
1449
+ /**
1450
+ * Locate a command on PATH using fs only.
1451
+ *
1452
+ * Deliberately NOT \`execSync('where ...')\` / \`command -v\`: that spawns a
1453
+ * shell on every hook invocation, which is both the thing this file is
1454
+ * trying to get away from and a per-turn cost. Taking \`env\` and \`platform\`
1455
+ * as arguments is what lets the Windows branch be exercised from a
1456
+ * Linux/macOS CI run — see the Windows argv tests.
1457
+ */
1458
+ function resolveCommandPath(command, env = process.env, platform = process.platform) {
1459
+ const hasSeparator = command.includes('/') || command.includes('\\\\');
1460
+ const dirs = hasSeparator
1461
+ ? ['']
1462
+ : (envValue(env, 'PATH') || '').split(platform === 'win32' ? ';' : path.delimiter);
1463
+ const hasExtension = path.extname(command) !== '';
1464
+ const extensions = platform === 'win32' && !(hasSeparator && hasExtension)
1465
+ ? (envValue(env, 'PATHEXT') || '.COM;.EXE;.BAT;.CMD').split(';')
1466
+ : [''];
1467
+ for (const dir of dirs) {
1468
+ for (const ext of extensions) {
1469
+ const base = path.resolve(dir || '.', command);
1470
+ const candidates = ext
1471
+ ? [base + ext.toLowerCase(), base + ext.toUpperCase()]
1472
+ : [base];
1473
+ for (const file of candidates) {
1474
+ try {
1475
+ fs.accessSync(file, platform === 'win32' ? fs.constants.F_OK : fs.constants.X_OK);
1476
+ if (fs.statSync(file).isFile()) return file;
1477
+ } catch { /* keep searching */ }
1478
+ }
1479
+ }
1480
+ }
1481
+ return null;
1482
+ }
1483
+
1484
+ /**
1485
+ * Map an npm-generated Windows shim (ruflo.cmd / npx.cmd / …) to the .js
1486
+ * entrypoint it would have run, so it can be executed as \`node <entry>\`
1487
+ * with no shell.
1488
+ *
1489
+ * Handles both npm layouts: a global prefix (\`<prefix>/ruflo.cmd\` beside
1490
+ * \`<prefix>/node_modules/ruflo\`) and a local one (\`node_modules/.bin/ruflo.cmd\`
1491
+ * beside \`node_modules/ruflo\`). \`npx\` lives in the \`npm\` package, hence the
1492
+ * command→package mapping rather than assuming they match.
1493
+ *
1494
+ * The entrypoint comes from the package's own \`bin\` field, never a guessed
1495
+ * filename, and is required to resolve inside the package directory — a
1496
+ * manifest pointing outside it is refused rather than followed.
1497
+ */
1498
+ function resolveNpmShim(shimPath) {
1499
+ const command = path.basename(shimPath, path.extname(shimPath)).toLowerCase();
1500
+ const packageName = command === 'npx' ? 'npm' : command;
1501
+ if (!['ruflo', 'claude-flow', 'npm'].includes(packageName)) return null;
1502
+ try {
1503
+ const shimDir = path.dirname(shimPath);
1504
+ const packageDir = path.basename(shimDir).toLowerCase() === '.bin'
1505
+ ? path.resolve(shimDir, '..', packageName)
1506
+ : path.resolve(shimDir, 'node_modules', packageName);
1507
+ const manifest = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8'));
1508
+ const declared = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin?.[command];
1509
+ if (typeof declared !== 'string') return null;
1510
+ const canonicalPackageDir = fs.realpathSync(packageDir);
1511
+ const canonicalEntry = fs.realpathSync(path.resolve(packageDir, declared));
1512
+ const relativeEntry = path.relative(canonicalPackageDir, canonicalEntry);
1513
+ if (relativeEntry.startsWith('..' + path.sep) || path.isAbsolute(relativeEntry)) return null;
1514
+ if (!fs.statSync(canonicalEntry).isFile()) return null;
1515
+ return { command: process.execPath, args: [canonicalEntry] };
1516
+ } catch { return null; }
1517
+ }
1518
+
1519
+ /**
1520
+ * Decide how to run \`bin\` without a shell. Returns {command, args}, or null
1521
+ * when no shell-free invocation could be identified (Windows shim that is
1522
+ * not an npm package entry) — the caller then falls back to the escaped
1523
+ * cmd.exe path rather than dropping the hook.
1524
+ */
1525
+ function resolveInvocation(bin, binArgs, options = {}) {
1526
+ const env = options.env || process.env;
1527
+ const platform = options.platform || process.platform;
1528
+ const commandPath = resolveCommandPath(bin, env, platform);
1529
+ if (!commandPath) return null;
1530
+ if (platform === 'win32' && /\\.(?:cmd|bat|ps1)$/i.test(commandPath)) {
1531
+ const npmBin = resolveNpmShim(commandPath);
1532
+ return npmBin ? { command: npmBin.command, args: [...npmBin.args, ...binArgs] } : null;
1533
+ }
1534
+ return { command: commandPath, args: binArgs };
1535
+ }
1536
+
1537
+ /**
1538
+ * Escape one argv element so it survives BOTH parsers a Windows shell:true
1539
+ * spawn puts it through before the target CLI ever sees it:
1540
+ * 1. cmd.exe's own line tokenizer, which still scans for & | < > ^ % ! " ( )
1541
+ * even inside a per-argument quoted segment — quoting alone does not
1542
+ * shield cmd.exe metacharacters, and this runs a SECOND time when the
1543
+ * resolved binary is itself a .cmd shim (npm's \`ruflo\`/\`claude-flow\`/
1544
+ * \`npx\` global installs on Windows), because launching a .cmd file is
1545
+ * cmd.exe re-invoking itself on the command line.
1546
+ * 2. The eventual CommandLineToArgvW argv parse in the target process,
1547
+ * which needs backslash-before-quote sequences doubled and the value
1548
+ * quoted so it lands as ONE argument.
1549
+ * Without this, a hook-derived value (e.g. a Bash tool's \`command\`, or a
1550
+ * file path) containing a shell metacharacter can be reinterpreted as a
1551
+ * separate command / redirection instead of reaching the CLI as literal
1552
+ * data — this is the class of bug in CVE-2024-27980 (Node's own .bat/.cmd
1553
+ * argument-injection advisory). Algorithm: https://qntm.org/cmd, the same
1554
+ * reference the \`cross-spawn\` package's Windows escaping is built from.
1555
+ *
1556
+ * Byte-identical to plugins/ruflo-core/scripts/ruflo-hook.cjs so the four
1557
+ * copies can be diffed against each other. This is the fallback, not the
1558
+ * primary defence: resolveInvocation() above is preferred because it removes
1559
+ * cmd.exe from the chain entirely rather than out-guessing its tokenizer.
1560
+ */
1561
+ function escapeCmdArg(arg) {
1562
+ let s = String(arg);
1563
+ s = s.replace(/(\\\\*)"/g, '$1$1\\\\"').replace(/(\\\\*)$/, '$1$1');
1564
+ s = \`"\${s}"\`;
1565
+ return s.replace(/[()%!^"<>&|;,]/g, '^$&');
1566
+ }
1567
+
1568
+ function invokeHook(bin, binArgs, hookArgs, stdinData, options = {}) {
1569
+ const env = options.env || process.env;
1570
+ const platform = options.platform || process.platform;
1571
+ const spawnOpts = {
1572
+ input: stdinData || '',
1573
+ encoding: 'utf8',
1574
+ stdio: ['pipe', 'ignore', 'ignore'],
1575
+ timeout: 30_000,
1576
+ env,
1577
+ };
1578
+
1579
+ // Layer 1: no shell. CreateProcess/execve receives the argv array
1580
+ // verbatim, so nothing in it can be reinterpreted as syntax.
1581
+ const invocation = resolveInvocation(bin, binArgs, { env, platform });
1582
+ if (invocation) {
1583
+ const result = spawnSync(invocation.command, [...invocation.args, ...hookArgs], {
1584
+ ...spawnOpts,
1585
+ shell: false,
1586
+ });
1587
+ return result.status === 0;
1588
+ }
1589
+
1590
+ // Layer 2: Windows shim we could not map to an entrypoint. cmd.exe is
1591
+ // unavoidable here (CreateProcess cannot launch a .cmd, and Node has
1592
+ // refused to since CVE-2024-27980), so every element is escaped. Losing
1593
+ // the hook entirely would be the wrong trade — telemetry is best-effort,
1594
+ // but silently doing nothing hides breakage.
1595
+ const useShell = platform === 'win32';
1596
+ const args = [...binArgs, ...hookArgs];
1597
+ const result = spawnSync(
1598
+ useShell ? escapeCmdArg(bin) : bin,
1599
+ useShell ? args.map(escapeCmdArg) : args,
1600
+ { ...spawnOpts, shell: useShell },
1601
+ );
1602
+ return result.status === 0;
1603
+ }
1604
+
1605
+ function main() {
1606
+ const args = process.argv.slice(2);
1607
+ if (args.length === 0) done();
1608
+
1609
+ const [subcommand, ...rest] = args;
1610
+
1611
+ let stdinData = '';
1612
+ try { stdinData = fs.readFileSync(0, 'utf8'); } catch { stdinData = ''; }
1613
+
1614
+ const hookArgs = ['hooks', subcommand, ...rest];
1615
+
1616
+ // Presence is checked separately from invocation strategy: a command that
1617
+ // exists but cannot be resolved to an entrypoint still runs, via layer 2.
1618
+ if (resolveCommandPath('ruflo')) { invokeHook('ruflo', [], hookArgs, stdinData); done(); }
1619
+ if (resolveCommandPath('claude-flow')) { invokeHook('claude-flow', [], hookArgs, stdinData); done(); }
1620
+ invokeHook('npx', ['--prefer-offline', '--yes', 'ruflo@latest'], hookArgs, stdinData);
1621
+ done();
1622
+ }
1623
+
1624
+ // Test seam: the Windows argv suite require()s this file to drive resolveInvocation()
1625
+ // and invokeHook() with a simulated { platform: 'win32', env } — which is how
1626
+ // the Windows branch is proved from a Linux/macOS CI run. hooks.json always
1627
+ // invokes this file directly, so main() runs unconditionally otherwise.
1628
+ if (!globalThis.__RUFLO_HOOK_IMPORT_ONLY__) main();
1629
+
1630
+ module.exports = { invokeHook, resolveCommandPath, resolveInvocation, resolveNpmShim, escapeCmdArg };
1465
1631
  `;
1466
1632
  }
1467
1633
  //# sourceMappingURL=helpers-generator.js.map