@monoes/monomindcli 1.14.7 → 1.15.1

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 (329) hide show
  1. package/.claude/agents/reengineer-squad/boss.md +113 -0
  2. package/.claude/agents/reengineer-squad/critic-architect.md +132 -0
  3. package/.claude/agents/reengineer-squad/git-manager.md +145 -0
  4. package/.claude/agents/reengineer-squad/idea-generator.md +95 -0
  5. package/.claude/agents/reengineer-squad/implementer.md +112 -0
  6. package/.claude/agents/reengineer-squad/integration-planner.md +112 -0
  7. package/.claude/agents/reengineer-squad/source-analyst.md +103 -0
  8. package/.claude/agents/reengineer-squad/target-analyst.md +118 -0
  9. package/.claude/agents/reengineer-squad/tester.md +105 -0
  10. package/.claude/commands/mastermind/master.md +35 -14
  11. package/.claude/helpers/handlers/capture-handler.cjs +155 -18
  12. package/.claude/helpers/monolean-activate.cjs +20 -0
  13. package/.claude/helpers/monolean-config.cjs +76 -0
  14. package/.claude/helpers/monolean-instructions.cjs +109 -0
  15. package/.claude/helpers/monolean-propagate.cjs +9 -0
  16. package/.claude/helpers/monolean-tracker.cjs +18 -0
  17. package/.claude/helpers/skill-registry.json +2 -2
  18. package/.claude/skills/agent-browser-testing/SKILL.md +301 -18
  19. package/.claude/skills/mastermind/runorg.md +69 -23
  20. package/.claude/skills/monodesign/SKILL.md +32 -1
  21. package/.claude/skills/monodesign/adapt.md +53 -0
  22. package/.claude/skills/monodesign/agents/monodesign-asset-producer.md +100 -0
  23. package/.claude/skills/monodesign/animate.md +65 -0
  24. package/.claude/skills/monodesign/audit.md +89 -0
  25. package/.claude/skills/monodesign/bolder.md +50 -0
  26. package/.claude/skills/monodesign/clarify.md +64 -0
  27. package/.claude/skills/monodesign/colorize.md +68 -0
  28. package/.claude/skills/monodesign/craft.md +51 -0
  29. package/.claude/skills/monodesign/critique.md +66 -0
  30. package/.claude/skills/monodesign/delight.md +47 -0
  31. package/.claude/skills/monodesign/distill.md +56 -0
  32. package/.claude/skills/monodesign/document.md +80 -0
  33. package/.claude/skills/monodesign/extract.md +74 -0
  34. package/.claude/skills/monodesign/harden.md +65 -0
  35. package/.claude/skills/monodesign/live.md +59 -0
  36. package/.claude/skills/monodesign/onboard.md +50 -0
  37. package/.claude/skills/monodesign/optimize.md +64 -0
  38. package/.claude/skills/monodesign/overdrive.md +56 -0
  39. package/.claude/skills/monodesign/polish.md +68 -0
  40. package/.claude/skills/monodesign/quieter.md +57 -0
  41. package/.claude/skills/monodesign/reference/antipatterns-catalog.md +248 -76
  42. package/.claude/skills/monodesign/reference/codex.md +107 -0
  43. package/.claude/skills/monodesign/reference/craft.md +3 -0
  44. package/.claude/skills/monodesign/reference/hooks.md +99 -0
  45. package/.claude/skills/monodesign/reference/image-prompts.md +12 -0
  46. package/.claude/skills/monodesign/shape.md +71 -0
  47. package/.claude/skills/monodesign/teach.md +69 -0
  48. package/.claude/skills/monodesign/typeset.md +59 -0
  49. package/.claude/skills/monolean/SKILL.md +118 -0
  50. package/.claude/skills/monolean-audit/SKILL.md +41 -0
  51. package/.claude/skills/monolean-debt/SKILL.md +46 -0
  52. package/.claude/skills/monolean-help/SKILL.md +60 -0
  53. package/.claude/skills/monolean-review/SKILL.md +57 -0
  54. package/bin/cli.js +3 -1
  55. package/dist/dashboard/server.js +137 -0
  56. package/dist/src/__tests__/browse-adapters.test.d.ts +2 -0
  57. package/dist/src/__tests__/browse-adapters.test.d.ts.map +1 -0
  58. package/dist/src/__tests__/browse-adapters.test.js +51 -0
  59. package/dist/src/__tests__/browse-adapters.test.js.map +1 -0
  60. package/dist/src/__tests__/browse-analyzer.test.d.ts +2 -0
  61. package/dist/src/__tests__/browse-analyzer.test.d.ts.map +1 -0
  62. package/dist/src/__tests__/browse-analyzer.test.js +68 -0
  63. package/dist/src/__tests__/browse-analyzer.test.js.map +1 -0
  64. package/dist/src/__tests__/browse-builtin-handlers.test.d.ts +2 -0
  65. package/dist/src/__tests__/browse-builtin-handlers.test.d.ts.map +1 -0
  66. package/dist/src/__tests__/browse-builtin-handlers.test.js +139 -0
  67. package/dist/src/__tests__/browse-builtin-handlers.test.js.map +1 -0
  68. package/dist/src/__tests__/browse-cdp.test.d.ts +2 -0
  69. package/dist/src/__tests__/browse-cdp.test.d.ts.map +1 -0
  70. package/dist/src/__tests__/browse-cdp.test.js +169 -0
  71. package/dist/src/__tests__/browse-cdp.test.js.map +1 -0
  72. package/dist/src/__tests__/browse-dashboard.test.d.ts +2 -0
  73. package/dist/src/__tests__/browse-dashboard.test.d.ts.map +1 -0
  74. package/dist/src/__tests__/browse-dashboard.test.js +179 -0
  75. package/dist/src/__tests__/browse-dashboard.test.js.map +1 -0
  76. package/dist/src/__tests__/browse-engine.test.d.ts +2 -0
  77. package/dist/src/__tests__/browse-engine.test.d.ts.map +1 -0
  78. package/dist/src/__tests__/browse-engine.test.js +122 -0
  79. package/dist/src/__tests__/browse-engine.test.js.map +1 -0
  80. package/dist/src/__tests__/browse-expression.test.d.ts +2 -0
  81. package/dist/src/__tests__/browse-expression.test.d.ts.map +1 -0
  82. package/dist/src/__tests__/browse-expression.test.js +54 -0
  83. package/dist/src/__tests__/browse-expression.test.js.map +1 -0
  84. package/dist/src/__tests__/browse-store.test.d.ts +2 -0
  85. package/dist/src/__tests__/browse-store.test.d.ts.map +1 -0
  86. package/dist/src/__tests__/browse-store.test.js +99 -0
  87. package/dist/src/__tests__/browse-store.test.js.map +1 -0
  88. package/dist/src/__tests__/browse-workflow-types.test.d.ts +2 -0
  89. package/dist/src/__tests__/browse-workflow-types.test.d.ts.map +1 -0
  90. package/dist/src/__tests__/browse-workflow-types.test.js +33 -0
  91. package/dist/src/__tests__/browse-workflow-types.test.js.map +1 -0
  92. package/dist/src/browser/action-builder/analyzer.d.ts +11 -0
  93. package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -0
  94. package/dist/src/browser/action-builder/analyzer.js +71 -0
  95. package/dist/src/browser/action-builder/analyzer.js.map +1 -0
  96. package/dist/src/browser/action-builder/types.d.ts +47 -0
  97. package/dist/src/browser/action-builder/types.d.ts.map +1 -0
  98. package/dist/src/browser/action-builder/types.js +2 -0
  99. package/dist/src/browser/action-builder/types.js.map +1 -0
  100. package/dist/src/browser/adapters/gemini.d.ts +3 -0
  101. package/dist/src/browser/adapters/gemini.d.ts.map +1 -0
  102. package/dist/src/browser/adapters/gemini.js +16 -0
  103. package/dist/src/browser/adapters/gemini.js.map +1 -0
  104. package/dist/src/browser/adapters/google.d.ts +3 -0
  105. package/dist/src/browser/adapters/google.d.ts.map +1 -0
  106. package/dist/src/browser/adapters/google.js +17 -0
  107. package/dist/src/browser/adapters/google.js.map +1 -0
  108. package/dist/src/browser/adapters/index.d.ts +19 -0
  109. package/dist/src/browser/adapters/index.d.ts.map +1 -0
  110. package/dist/src/browser/adapters/index.js +23 -0
  111. package/dist/src/browser/adapters/index.js.map +1 -0
  112. package/dist/src/browser/adapters/instagram.d.ts +3 -0
  113. package/dist/src/browser/adapters/instagram.d.ts.map +1 -0
  114. package/dist/src/browser/adapters/instagram.js +17 -0
  115. package/dist/src/browser/adapters/instagram.js.map +1 -0
  116. package/dist/src/browser/adapters/linkedin.d.ts +3 -0
  117. package/dist/src/browser/adapters/linkedin.d.ts.map +1 -0
  118. package/dist/src/browser/adapters/linkedin.js +19 -0
  119. package/dist/src/browser/adapters/linkedin.js.map +1 -0
  120. package/dist/src/browser/adapters/microsoft.d.ts +3 -0
  121. package/dist/src/browser/adapters/microsoft.d.ts.map +1 -0
  122. package/dist/src/browser/adapters/microsoft.js +16 -0
  123. package/dist/src/browser/adapters/microsoft.js.map +1 -0
  124. package/dist/src/browser/adapters/x.d.ts +3 -0
  125. package/dist/src/browser/adapters/x.d.ts.map +1 -0
  126. package/dist/src/browser/adapters/x.js +19 -0
  127. package/dist/src/browser/adapters/x.js.map +1 -0
  128. package/dist/src/browser/dashboard/api-types.d.ts +50 -0
  129. package/dist/src/browser/dashboard/api-types.d.ts.map +1 -0
  130. package/dist/src/browser/dashboard/api-types.js +14 -0
  131. package/dist/src/browser/dashboard/api-types.js.map +1 -0
  132. package/dist/src/browser/dashboard/server.d.ts +9 -0
  133. package/dist/src/browser/dashboard/server.d.ts.map +1 -0
  134. package/dist/src/browser/dashboard/server.js +62 -0
  135. package/dist/src/browser/dashboard/server.js.map +1 -0
  136. package/dist/src/browser/dashboard/ui.html +1811 -0
  137. package/dist/src/browser/workflow/builtin-handlers.d.ts +3 -0
  138. package/dist/src/browser/workflow/builtin-handlers.d.ts.map +1 -0
  139. package/dist/src/browser/workflow/builtin-handlers.js +343 -0
  140. package/dist/src/browser/workflow/builtin-handlers.js.map +1 -0
  141. package/dist/src/browser/workflow/engine.d.ts +15 -0
  142. package/dist/src/browser/workflow/engine.d.ts.map +1 -0
  143. package/dist/src/browser/workflow/engine.js +127 -0
  144. package/dist/src/browser/workflow/engine.js.map +1 -0
  145. package/dist/src/browser/workflow/expression.d.ts +4 -0
  146. package/dist/src/browser/workflow/expression.d.ts.map +1 -0
  147. package/dist/src/browser/workflow/expression.js +64 -0
  148. package/dist/src/browser/workflow/expression.js.map +1 -0
  149. package/dist/src/browser/workflow/store.d.ts +24 -0
  150. package/dist/src/browser/workflow/store.d.ts.map +1 -0
  151. package/dist/src/browser/workflow/store.js +145 -0
  152. package/dist/src/browser/workflow/store.js.map +1 -0
  153. package/dist/src/browser/workflow/types.d.ts +48 -0
  154. package/dist/src/browser/workflow/types.d.ts.map +1 -0
  155. package/dist/src/browser/workflow/types.js +2 -0
  156. package/dist/src/browser/workflow/types.js.map +1 -0
  157. package/dist/src/commands/browse-action.d.ts +4 -0
  158. package/dist/src/commands/browse-action.d.ts.map +1 -0
  159. package/dist/src/commands/browse-action.js +151 -0
  160. package/dist/src/commands/browse-action.js.map +1 -0
  161. package/dist/src/commands/browse-platform.d.ts +4 -0
  162. package/dist/src/commands/browse-platform.d.ts.map +1 -0
  163. package/dist/src/commands/browse-platform.js +117 -0
  164. package/dist/src/commands/browse-platform.js.map +1 -0
  165. package/dist/src/commands/browse-workflow.d.ts +4 -0
  166. package/dist/src/commands/browse-workflow.d.ts.map +1 -0
  167. package/dist/src/commands/browse-workflow.js +153 -0
  168. package/dist/src/commands/browse-workflow.js.map +1 -0
  169. package/dist/src/commands/browse.d.ts +10 -6
  170. package/dist/src/commands/browse.d.ts.map +1 -1
  171. package/dist/src/commands/browse.js +11 -2154
  172. package/dist/src/commands/browse.js.map +1 -1
  173. package/dist/src/commands/design-detect.d.ts +21 -0
  174. package/dist/src/commands/design-detect.d.ts.map +1 -0
  175. package/dist/src/commands/design-detect.js +127 -0
  176. package/dist/src/commands/design-detect.js.map +1 -0
  177. package/dist/src/commands/design-palette.d.ts +22 -0
  178. package/dist/src/commands/design-palette.d.ts.map +1 -0
  179. package/dist/src/commands/design-palette.js +539 -0
  180. package/dist/src/commands/design-palette.js.map +1 -0
  181. package/dist/src/commands/hooks-core-commands.d.ts +10 -0
  182. package/dist/src/commands/hooks-core-commands.d.ts.map +1 -0
  183. package/dist/src/commands/hooks-core-commands.js +377 -0
  184. package/dist/src/commands/hooks-core-commands.js.map +1 -0
  185. package/dist/src/commands/hooks-coverage-commands.d.ts +12 -0
  186. package/dist/src/commands/hooks-coverage-commands.d.ts.map +1 -0
  187. package/dist/src/commands/hooks-coverage-commands.js +1217 -0
  188. package/dist/src/commands/hooks-coverage-commands.js.map +1 -0
  189. package/dist/src/commands/hooks-coverage-utils.d.ts +42 -0
  190. package/dist/src/commands/hooks-coverage-utils.d.ts.map +1 -0
  191. package/dist/src/commands/hooks-coverage-utils.js +220 -0
  192. package/dist/src/commands/hooks-coverage-utils.js.map +1 -0
  193. package/dist/src/commands/hooks-extended-commands.d.ts +14 -0
  194. package/dist/src/commands/hooks-extended-commands.d.ts.map +1 -0
  195. package/dist/src/commands/hooks-extended-commands.js +579 -0
  196. package/dist/src/commands/hooks-extended-commands.js.map +1 -0
  197. package/dist/src/commands/hooks-formatting.d.ts +13 -0
  198. package/dist/src/commands/hooks-formatting.d.ts.map +1 -0
  199. package/dist/src/commands/hooks-formatting.js +42 -0
  200. package/dist/src/commands/hooks-formatting.js.map +1 -0
  201. package/dist/src/commands/hooks-routing-commands.d.ts +15 -0
  202. package/dist/src/commands/hooks-routing-commands.d.ts.map +1 -0
  203. package/dist/src/commands/hooks-routing-commands.js +723 -0
  204. package/dist/src/commands/hooks-routing-commands.js.map +1 -0
  205. package/dist/src/commands/hooks-workers.d.ts +9 -0
  206. package/dist/src/commands/hooks-workers.d.ts.map +1 -0
  207. package/dist/src/commands/hooks-workers.js +782 -0
  208. package/dist/src/commands/hooks-workers.js.map +1 -0
  209. package/dist/src/commands/hooks.d.ts +8 -0
  210. package/dist/src/commands/hooks.d.ts.map +1 -1
  211. package/dist/src/commands/hooks.js +179 -4103
  212. package/dist/src/commands/hooks.js.map +1 -1
  213. package/dist/src/commands/index.d.ts +1 -0
  214. package/dist/src/commands/index.d.ts.map +1 -1
  215. package/dist/src/commands/index.js +6 -0
  216. package/dist/src/commands/index.js.map +1 -1
  217. package/dist/src/commands/org.d.ts.map +1 -1
  218. package/dist/src/commands/org.js +14 -15
  219. package/dist/src/commands/org.js.map +1 -1
  220. package/dist/src/commands/tokens.d.ts.map +1 -1
  221. package/dist/src/commands/tokens.js +77 -1
  222. package/dist/src/commands/tokens.js.map +1 -1
  223. package/dist/src/init/executor.d.ts.map +1 -1
  224. package/dist/src/init/executor.js +18 -8
  225. package/dist/src/init/executor.js.map +1 -1
  226. package/dist/src/init/settings-generator.d.ts.map +1 -1
  227. package/dist/src/init/settings-generator.js +39 -5
  228. package/dist/src/init/settings-generator.js.map +1 -1
  229. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  230. package/dist/src/init/statusline-generator.js +25 -5
  231. package/dist/src/init/statusline-generator.js.map +1 -1
  232. package/dist/src/mcp-tools/browser-tools.d.ts +3 -5
  233. package/dist/src/mcp-tools/browser-tools.d.ts.map +1 -1
  234. package/dist/src/mcp-tools/browser-tools.js +619 -326
  235. package/dist/src/mcp-tools/browser-tools.js.map +1 -1
  236. package/dist/src/mcp-tools/hooks-embedding.d.ts +161 -0
  237. package/dist/src/mcp-tools/hooks-embedding.d.ts.map +1 -0
  238. package/dist/src/mcp-tools/hooks-embedding.js +506 -0
  239. package/dist/src/mcp-tools/hooks-embedding.js.map +1 -0
  240. package/dist/src/mcp-tools/hooks-intelligence.d.ts +26 -0
  241. package/dist/src/mcp-tools/hooks-intelligence.d.ts.map +1 -0
  242. package/dist/src/mcp-tools/hooks-intelligence.js +1328 -0
  243. package/dist/src/mcp-tools/hooks-intelligence.js.map +1 -0
  244. package/dist/src/mcp-tools/hooks-routing.d.ts +27 -0
  245. package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -0
  246. package/dist/src/mcp-tools/hooks-routing.js +1591 -0
  247. package/dist/src/mcp-tools/hooks-routing.js.map +1 -0
  248. package/dist/src/mcp-tools/hooks-tools.d.ts +3 -38
  249. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  250. package/dist/src/mcp-tools/hooks-tools.js +5 -3393
  251. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  252. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  253. package/dist/src/mcp-tools/monograph-tools.js +24 -14
  254. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  255. package/dist/src/mcp-tools/workflow-tools.d.ts.map +1 -1
  256. package/dist/src/mcp-tools/workflow-tools.js +54 -1
  257. package/dist/src/mcp-tools/workflow-tools.js.map +1 -1
  258. package/dist/src/memory/embedding-operations.d.ts +58 -0
  259. package/dist/src/memory/embedding-operations.d.ts.map +1 -0
  260. package/dist/src/memory/embedding-operations.js +299 -0
  261. package/dist/src/memory/embedding-operations.js.map +1 -0
  262. package/dist/src/memory/ewc-consolidation.d.ts.map +1 -1
  263. package/dist/src/memory/ewc-consolidation.js +37 -3
  264. package/dist/src/memory/ewc-consolidation.js.map +1 -1
  265. package/dist/src/memory/hnsw-operations.d.ts +130 -0
  266. package/dist/src/memory/hnsw-operations.d.ts.map +1 -0
  267. package/dist/src/memory/hnsw-operations.js +400 -0
  268. package/dist/src/memory/hnsw-operations.js.map +1 -0
  269. package/dist/src/memory/intelligence.d.ts.map +1 -1
  270. package/dist/src/memory/intelligence.js +42 -23
  271. package/dist/src/memory/intelligence.js.map +1 -1
  272. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  273. package/dist/src/memory/memory-bridge.js +52 -8
  274. package/dist/src/memory/memory-bridge.js.map +1 -1
  275. package/dist/src/memory/memory-crud.d.ts +67 -0
  276. package/dist/src/memory/memory-crud.d.ts.map +1 -0
  277. package/dist/src/memory/memory-crud.js +415 -0
  278. package/dist/src/memory/memory-crud.js.map +1 -0
  279. package/dist/src/memory/memory-initializer.d.ts +9 -322
  280. package/dist/src/memory/memory-initializer.d.ts.map +1 -1
  281. package/dist/src/memory/memory-initializer.js +17 -1794
  282. package/dist/src/memory/memory-initializer.js.map +1 -1
  283. package/dist/src/memory/memory-migrations.d.ts +30 -0
  284. package/dist/src/memory/memory-migrations.d.ts.map +1 -0
  285. package/dist/src/memory/memory-migrations.js +134 -0
  286. package/dist/src/memory/memory-migrations.js.map +1 -0
  287. package/dist/src/memory/memory-read.d.ts +78 -0
  288. package/dist/src/memory/memory-read.d.ts.map +1 -0
  289. package/dist/src/memory/memory-read.js +331 -0
  290. package/dist/src/memory/memory-read.js.map +1 -0
  291. package/dist/src/memory/memory-schema.d.ts +13 -0
  292. package/dist/src/memory/memory-schema.d.ts.map +1 -0
  293. package/dist/src/memory/memory-schema.js +167 -0
  294. package/dist/src/memory/memory-schema.js.map +1 -0
  295. package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
  296. package/dist/src/memory/sona-optimizer.js +37 -4
  297. package/dist/src/memory/sona-optimizer.js.map +1 -1
  298. package/dist/src/monovector/route-outcomes.d.ts.map +1 -1
  299. package/dist/src/monovector/route-outcomes.js +16 -6
  300. package/dist/src/monovector/route-outcomes.js.map +1 -1
  301. package/dist/src/pricing/model-pricing.d.ts +41 -0
  302. package/dist/src/pricing/model-pricing.d.ts.map +1 -0
  303. package/dist/src/pricing/model-pricing.js +61 -0
  304. package/dist/src/pricing/model-pricing.js.map +1 -0
  305. package/dist/src/ui/.monomind/capture/active-run.json +1 -0
  306. package/dist/src/ui/.monomind/orgs/system-trial-qa/runs/real-events-1782290897.convs.jsonl +3 -0
  307. package/dist/src/ui/.monomind/orgs/system-trial-qa/runs/real-events-1782290897.jsonl +11 -0
  308. package/dist/src/ui/.monomind/orgs/system-trial-qa/runs/rigid-qa-restart-1782288201.jsonl +540 -0
  309. package/dist/src/ui/.monomind/orgs/system-trial-qa-threads.jsonl +3 -0
  310. package/dist/src/ui/.monomind/orgs/test-event-fix/runs/rigid-qa-restart-1782288201.jsonl +2 -0
  311. package/dist/src/ui/MODULARIZATION_PLAN.md +79 -0
  312. package/dist/src/ui/collector.mjs +23 -13
  313. package/dist/src/ui/dashboard.html +1653 -14
  314. package/dist/src/ui/data/known-projects.json +1 -0
  315. package/dist/src/ui/data/mastermind-events.jsonl +553 -0
  316. package/dist/src/ui/data/sessions/_index.json +1 -0
  317. package/dist/src/ui/data/sessions/final-sess-001.jsonl +542 -0
  318. package/dist/src/ui/data/unknown-events.jsonl +1 -0
  319. package/dist/src/ui/orgs.html +154 -10
  320. package/dist/src/ui/server.mjs +1162 -168
  321. package/dist/src/ui/sse-manager.mjs +119 -0
  322. package/dist/src/update/checker.js +1 -1
  323. package/dist/src/update/checker.js.map +1 -1
  324. package/dist/tsconfig.tsbuildinfo +1 -1
  325. package/dist/workflow/builtin-handlers.js +321 -0
  326. package/dist/workflow/engine.js +253 -0
  327. package/dist/workflow/expression.js +98 -0
  328. package/dist/workflow/types.js +2 -0
  329. package/package.json +8 -6
@@ -1,3398 +1,10 @@
1
1
  /**
2
- * Hooks MCP Tools
3
- * Provides intelligent hooks functionality via MCP protocol
2
+ * Hooks MCP Tools — Registration Layer
3
+ * Thin registration module that aggregates all hooks MCP tools into a single array.
4
+ * Business logic lives in hooks-embedding.ts, hooks-routing.ts, and hooks-intelligence.ts.
4
5
  */
5
- import { mkdirSync, writeFileSync, renameSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync } from 'fs';
6
- import { dirname, join, resolve, sep } from 'path';
7
- import { getProjectCwd } from './types.js';
8
- import { randomUUID } from 'node:crypto';
9
- import { recordRoute, joinOutcome, joinLatestUnresolved } from '../monovector/route-outcomes.js';
10
- import { recordCommand, deriveRecentSuccess } from '../monovector/command-outcomes.js';
11
- // Base dir for per-route outcome records — sits alongside routing-outcomes.json
12
- function getRouteOutcomesBaseDir() {
13
- return join(getProjectCwd(), '.monomind');
14
- }
15
- // Real vector search functions - lazy loaded to avoid circular imports
16
- let searchEntriesFn = null;
17
- async function getRealSearchFunction() {
18
- if (!searchEntriesFn) {
19
- try {
20
- const { searchEntries } = await import('../memory/memory-initializer.js');
21
- searchEntriesFn = searchEntries;
22
- }
23
- catch {
24
- searchEntriesFn = null;
25
- }
26
- }
27
- return searchEntriesFn;
28
- }
29
- // Real store function - lazy loaded
30
- let storeEntryFn = null;
31
- async function getRealStoreFunction() {
32
- if (!storeEntryFn) {
33
- try {
34
- const { storeEntry } = await import('../memory/memory-initializer.js');
35
- storeEntryFn = storeEntry;
36
- }
37
- catch {
38
- storeEntryFn = null;
39
- }
40
- }
41
- return storeEntryFn;
42
- }
43
- // =============================================================================
44
- // Neural Module Lazy Loaders (SONA, EWC++, MoE, LoRA, Flash Attention)
45
- // =============================================================================
46
- // SONA Optimizer - lazy loaded
47
- let sonaOptimizer = null;
48
- async function getSONAOptimizer() {
49
- if (!sonaOptimizer) {
50
- try {
51
- const { getSONAOptimizer: getSona } = await import('../memory/sona-optimizer.js');
52
- sonaOptimizer = await getSona();
53
- }
54
- catch {
55
- sonaOptimizer = null;
56
- }
57
- }
58
- return sonaOptimizer;
59
- }
60
- // EWC++ Consolidator - lazy loaded
61
- let ewcConsolidator = null;
62
- async function getEWCConsolidator() {
63
- if (!ewcConsolidator) {
64
- try {
65
- const { getEWCConsolidator: getEWC } = await import('../memory/ewc-consolidation.js');
66
- ewcConsolidator = await getEWC();
67
- }
68
- catch {
69
- ewcConsolidator = null;
70
- }
71
- }
72
- return ewcConsolidator;
73
- }
74
- function generateSimpleEmbedding(text, dimension = 384) {
75
- // Simple deterministic embedding based on character codes
76
- // This is for routing purposes where we need consistent, fast embeddings
77
- const embedding = new Float32Array(dimension);
78
- const normalized = text.toLowerCase().replace(/[^a-z0-9\s]/g, '');
79
- const words = normalized.split(/\s+/).filter(w => w.length > 0);
80
- // Combine word-level and character-level features
81
- for (let i = 0; i < dimension; i++) {
82
- let value = 0;
83
- // Word-level features
84
- for (let w = 0; w < words.length; w++) {
85
- const word = words[w];
86
- for (let c = 0; c < word.length; c++) {
87
- const charCode = word.charCodeAt(c);
88
- value += Math.sin((charCode * (i + 1) + w * 17 + c * 23) * 0.0137);
89
- }
90
- }
91
- // Character-level features
92
- for (let c = 0; c < text.length; c++) {
93
- value += Math.cos((text.charCodeAt(c) * (i + 1) + c * 7) * 0.0073);
94
- }
95
- embedding[i] = value / Math.max(1, text.length);
96
- }
97
- // Normalize
98
- let norm = 0;
99
- for (let i = 0; i < dimension; i++) {
100
- norm += embedding[i] * embedding[i];
101
- }
102
- norm = Math.sqrt(norm);
103
- if (norm > 0) {
104
- for (let i = 0; i < dimension; i++) {
105
- embedding[i] /= norm;
106
- }
107
- }
108
- return embedding;
109
- }
110
- // ── Runtime routing outcome persistence ──────────────────────────────
111
- // Closes the learning loop: post-task records outcomes → route loads them.
112
- // Evaluated lazily via getter so it uses runtime CWD, not import-time CWD
113
- function getRoutingOutcomesPath() {
114
- return join(getProjectCwd(), '.monomind', 'routing-outcomes.json');
115
- }
116
- const ROUTING_STOPWORDS = new Set([
117
- 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had',
118
- 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'shall', 'can',
119
- 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'during',
120
- 'before', 'after', 'above', 'below', 'between', 'under', 'again', 'further', 'then', 'once',
121
- 'it', 'its', 'this', 'that', 'these', 'those', 'i', 'me', 'my', 'we', 'our', 'you', 'your',
122
- 'he', 'she', 'they', 'them', 'and', 'but', 'or', 'nor', 'not', 'no', 'so', 'if', 'when', 'than',
123
- 'very', 'just', 'also', 'only', 'both', 'each', 'all', 'any', 'few', 'more', 'most', 'other',
124
- 'some', 'such', 'same', 'new', 'now', 'here', 'there', 'where', 'how', 'what', 'which', 'who',
125
- ]);
126
- function extractKeywords(text) {
127
- if (!text)
128
- return [];
129
- return text.toLowerCase()
130
- .replace(/[^a-z0-9\s-]/g, ' ')
131
- .split(/\s+/)
132
- .filter(w => w.length > 2 && !ROUTING_STOPWORDS.has(w));
133
- }
134
- function loadRoutingOutcomes() {
135
- try {
136
- if (existsSync(getRoutingOutcomesPath())) {
137
- const data = JSON.parse(readFileSync(getRoutingOutcomesPath(), 'utf-8'));
138
- return data.outcomes || [];
139
- }
140
- }
141
- catch { /* corrupt file, start fresh */ }
142
- return [];
143
- }
144
- function saveRoutingOutcomes(outcomes) {
145
- try {
146
- const dir = dirname(getRoutingOutcomesPath());
147
- if (!existsSync(dir))
148
- mkdirSync(dir, { recursive: true });
149
- // Cap at 500 entries to bound file size
150
- const capped = outcomes.slice(-500);
151
- const tmp = getRoutingOutcomesPath() + '.tmp';
152
- writeFileSync(tmp, JSON.stringify({ outcomes: capped }, null, 2));
153
- renameSync(tmp, getRoutingOutcomesPath());
154
- }
155
- catch { /* non-critical */ }
156
- }
157
- /**
158
- * Build learned routing patterns from successful task outcomes.
159
- * Returns patterns in the same shape as TASK_PATTERNS so they can be
160
- * merged into both the native HNSW and pure-JS semantic routers.
161
- */
162
- function loadLearnedPatterns() {
163
- const outcomes = loadRoutingOutcomes();
164
- const byAgent = {};
165
- for (const o of outcomes) {
166
- if (!o.success || !o.agent || !o.keywords?.length)
167
- continue;
168
- if (!byAgent[o.agent])
169
- byAgent[o.agent] = new Set();
170
- for (const kw of o.keywords)
171
- byAgent[o.agent].add(kw);
172
- }
173
- const patterns = {};
174
- for (const [agent, kwSet] of Object.entries(byAgent)) {
175
- patterns[`learned-${agent}`] = {
176
- keywords: [...kwSet].slice(0, 50),
177
- agents: [agent],
178
- };
179
- }
180
- return patterns;
181
- }
182
- /**
183
- * Merge static TASK_PATTERNS with runtime-learned patterns.
184
- * Static patterns take precedence (learned patterns won't overwrite them).
185
- */
186
- function getMergedTaskPatterns() {
187
- const merged = { ...TASK_PATTERNS };
188
- const learned = loadLearnedPatterns();
189
- for (const [key, pattern] of Object.entries(learned)) {
190
- if (!merged[key]) {
191
- merged[key] = pattern;
192
- }
193
- }
194
- return merged;
195
- }
196
- // ── Static task patterns (used by both native and pure-JS routers) ───
197
- const TASK_PATTERNS = {
198
- 'security-task': {
199
- keywords: ['authentication', 'security', 'auth', 'password', 'encryption', 'vulnerability', 'cve', 'audit'],
200
- agents: ['security-architect', 'security-auditor', 'reviewer'],
201
- },
202
- 'testing-task': {
203
- keywords: ['test', 'testing', 'spec', 'coverage', 'unit test', 'integration test', 'e2e'],
204
- agents: ['tester', 'reviewer'],
205
- },
206
- 'api-task': {
207
- keywords: ['api', 'endpoint', 'rest', 'graphql', 'route', 'handler', 'controller'],
208
- agents: ['architect', 'coder', 'tester'],
209
- },
210
- 'performance-task': {
211
- keywords: ['performance', 'optimize', 'speed', 'memory', 'benchmark', 'profiling', 'bottleneck'],
212
- agents: ['performance-engineer', 'coder', 'tester'],
213
- },
214
- 'refactor-task': {
215
- keywords: ['refactor', 'restructure', 'clean', 'organize', 'modular', 'decouple'],
216
- agents: ['architect', 'coder', 'reviewer'],
217
- },
218
- 'bugfix-task': {
219
- keywords: ['bug', 'fix', 'error', 'issue', 'broken', 'crash', 'debug'],
220
- agents: ['coder', 'tester', 'reviewer'],
221
- },
222
- 'feature-task': {
223
- keywords: ['feature', 'implement', 'add', 'new', 'create', 'build'],
224
- agents: ['architect', 'coder', 'tester'],
225
- },
226
- 'database-task': {
227
- keywords: ['database', 'sql', 'query', 'schema', 'migration', 'orm'],
228
- agents: ['architect', 'coder', 'tester'],
229
- },
230
- 'frontend-task': {
231
- keywords: ['frontend', 'ui', 'component', 'react', 'css', 'style', 'layout'],
232
- agents: ['coder', 'reviewer', 'tester'],
233
- },
234
- 'devops-task': {
235
- keywords: ['deploy', 'ci', 'cd', 'pipeline', 'docker', 'kubernetes', 'infrastructure'],
236
- agents: ['devops', 'coder', 'tester'],
237
- },
238
- 'swarm-task': {
239
- keywords: ['swarm', 'agent', 'coordinator', 'hive', 'mesh', 'topology'],
240
- agents: ['swarm-specialist', 'coordinator', 'architect'],
241
- },
242
- 'memory-task': {
243
- keywords: ['memory', 'cache', 'store', 'vector', 'embedding', 'persistence'],
244
- agents: ['memory-specialist', 'architect', 'coder'],
245
- },
246
- };
247
- // In-memory trajectory tracking (persisted on end)
248
- const activeTrajectories = new Map();
249
- const MEMORY_DIR = '.monomind/memory';
250
- const MEMORY_FILE = 'store.json';
251
- function getMemoryPath() {
252
- return join(getProjectCwd(), MEMORY_DIR, MEMORY_FILE);
253
- }
254
- // Maximum size of the legacy JSON memory store before reads are skipped.
255
- // Matches the guard in memory-tools.ts (loadLegacyStore) which loads the same file.
256
- const MAX_MEMORY_STORE_BYTES = 50 * 1024 * 1024; // 50 MB
257
- function loadMemoryStore() {
258
- try {
259
- const path = getMemoryPath();
260
- if (existsSync(path) && statSync(path).size <= MAX_MEMORY_STORE_BYTES) {
261
- const data = readFileSync(path, 'utf-8');
262
- return JSON.parse(data);
263
- }
264
- }
265
- catch {
266
- // Return empty store on error
267
- }
268
- return { entries: {}, version: '3.0.0' };
269
- }
270
- /**
271
- * Get real intelligence statistics from memory store
272
- */
273
- function getIntelligenceStatsFromMemory() {
274
- const store = loadMemoryStore();
275
- const entries = Object.values(store.entries);
276
- // Count trajectories (keys starting with "trajectory-" or containing trajectory data)
277
- const trajectoryEntries = entries.filter(e => e.key.includes('trajectory') ||
278
- (e.metadata?.type === 'trajectory'));
279
- const successfulTrajectories = trajectoryEntries.filter(e => e.metadata?.success === true ||
280
- (typeof e.value === 'object' && e.value !== null && e.value.success === true));
281
- // Count patterns
282
- const patternEntries = entries.filter(e => e.key.includes('pattern') ||
283
- e.metadata?.type === 'pattern' ||
284
- e.key.startsWith('learned-'));
285
- // Categorize patterns
286
- const categories = {};
287
- patternEntries.forEach(e => {
288
- const category = e.metadata?.category || 'general';
289
- categories[category] = (categories[category] || 0) + 1;
290
- });
291
- // Count routing decisions
292
- const routingEntries = entries.filter(e => e.key.includes('routing') ||
293
- e.metadata?.type === 'routing-decision');
294
- // Calculate average confidence from routing decisions
295
- let totalConfidence = 0;
296
- let confidenceCount = 0;
297
- routingEntries.forEach(e => {
298
- const confidence = e.metadata?.confidence;
299
- if (typeof confidence === 'number') {
300
- totalConfidence += confidence;
301
- confidenceCount++;
302
- }
303
- });
304
- // Calculate total access count
305
- const totalAccessCount = entries.reduce((sum, e) => sum + (e.accessCount || 0), 0);
306
- // Calculate memory file size
307
- let memorySizeBytes = 0;
308
- try {
309
- const memPath = getMemoryPath();
310
- if (existsSync(memPath)) {
311
- memorySizeBytes = statSync(memPath).size;
312
- }
313
- }
314
- catch {
315
- // Ignore
316
- }
317
- return {
318
- trajectories: {
319
- total: trajectoryEntries.length,
320
- successful: successfulTrajectories.length,
321
- },
322
- patterns: {
323
- learned: patternEntries.length,
324
- categories,
325
- },
326
- memory: {
327
- indexSize: entries.length,
328
- totalAccessCount,
329
- memorySizeBytes,
330
- },
331
- routing: {
332
- decisions: routingEntries.length,
333
- avgConfidence: confidenceCount > 0 ? totalConfidence / confidenceCount : 0,
334
- },
335
- };
336
- }
337
- // Agent routing configuration - maps file types to recommended agents
338
- const AGENT_PATTERNS = {
339
- '.ts': ['coder', 'architect', 'tester'],
340
- '.tsx': ['coder', 'architect', 'reviewer'],
341
- '.test.ts': ['tester', 'reviewer'],
342
- '.spec.ts': ['tester', 'reviewer'],
343
- '.md': ['researcher', 'documenter'],
344
- '.json': ['coder', 'architect'],
345
- '.yaml': ['coder', 'devops'],
346
- '.yml': ['coder', 'devops'],
347
- '.sh': ['devops', 'coder'],
348
- '.py': ['coder', 'ml-developer', 'researcher'],
349
- '.sql': ['coder', 'architect'],
350
- '.css': ['coder', 'designer'],
351
- '.scss': ['coder', 'designer'],
352
- };
353
- // Keyword patterns for fallback routing (when semantic routing doesn't match)
354
- const KEYWORD_PATTERNS = {
355
- 'authentication': { agents: ['security-architect', 'coder', 'tester'], confidence: 0.9 },
356
- 'auth': { agents: ['security-architect', 'coder', 'tester'], confidence: 0.85 },
357
- 'api': { agents: ['architect', 'coder', 'tester'], confidence: 0.85 },
358
- 'test': { agents: ['tester', 'reviewer'], confidence: 0.95 },
359
- 'refactor': { agents: ['architect', 'coder', 'reviewer'], confidence: 0.9 },
360
- 'performance': { agents: ['performance-engineer', 'coder', 'tester'], confidence: 0.88 },
361
- 'security': { agents: ['security-architect', 'security-auditor', 'reviewer'], confidence: 0.92 },
362
- 'database': { agents: ['architect', 'coder', 'tester'], confidence: 0.85 },
363
- 'frontend': { agents: ['coder', 'designer', 'tester'], confidence: 0.82 },
364
- 'backend': { agents: ['architect', 'coder', 'tester'], confidence: 0.85 },
365
- 'bug': { agents: ['coder', 'tester', 'reviewer'], confidence: 0.88 },
366
- 'fix': { agents: ['coder', 'tester', 'reviewer'], confidence: 0.85 },
367
- 'feature': { agents: ['architect', 'coder', 'tester'], confidence: 0.8 },
368
- 'swarm': { agents: ['swarm-specialist', 'coordinator', 'architect'], confidence: 0.9 },
369
- 'memory': { agents: ['memory-specialist', 'architect', 'coder'], confidence: 0.88 },
370
- 'deploy': { agents: ['devops', 'coder', 'tester'], confidence: 0.85 },
371
- 'ci/cd': { agents: ['devops', 'coder'], confidence: 0.9 },
372
- };
373
- function getFileExtension(filePath) {
374
- const match = filePath.match(/\.[a-zA-Z0-9]+$/);
375
- return match ? match[0] : '';
376
- }
377
- function suggestAgentsForFile(filePath) {
378
- const ext = getFileExtension(filePath);
379
- // Check for test files first
380
- if (filePath.includes('.test.') || filePath.includes('.spec.')) {
381
- return AGENT_PATTERNS['.test.ts'] || ['tester', 'reviewer'];
382
- }
383
- return AGENT_PATTERNS[ext] || ['coder', 'architect'];
384
- }
385
- function suggestAgentsForTask(task) {
386
- const taskLower = task.toLowerCase();
387
- // Check static keyword patterns first
388
- for (const [pattern, result] of Object.entries(KEYWORD_PATTERNS)) {
389
- if (taskLower.includes(pattern)) {
390
- return result;
391
- }
392
- }
393
- // Check runtime-learned patterns from successful task outcomes
394
- const taskKeywords = extractKeywords(task);
395
- if (taskKeywords.length > 0) {
396
- const outcomes = loadRoutingOutcomes();
397
- let bestAgent = '';
398
- let bestOverlap = 0;
399
- for (const outcome of outcomes) {
400
- if (!outcome.success || !outcome.agent || !outcome.keywords?.length)
401
- continue;
402
- const overlap = taskKeywords.filter(kw => outcome.keywords.includes(kw)).length;
403
- if (overlap > bestOverlap) {
404
- bestOverlap = overlap;
405
- bestAgent = outcome.agent;
406
- }
407
- }
408
- // Require at least 2 keyword overlap to prevent false positives
409
- if (bestAgent && bestOverlap >= 2) {
410
- return { agents: [bestAgent], confidence: Math.min(0.6 + bestOverlap * 0.05, 0.85) };
411
- }
412
- }
413
- // Default fallback
414
- return { agents: ['coder', 'researcher', 'tester'], confidence: 0.7 };
415
- }
416
- /**
417
- * V3: Augment agent suggestions with semantic matches from intelligence.ts ReasoningBank.
418
- * Returns null when the intelligence system is unavailable or has no relevant patterns.
419
- * Kept sync-safe by returning a Promise — callers that need a sync result use the
420
- * non-async suggestAgentsForTask above and optionally merge async results.
421
- */
422
- // Canonical set of valid monomind agent type strings.
423
- // Patterns whose type is not in this set (e.g. 'action', 'observation', 'routing')
424
- // are structural labels, not agent names, and must be excluded from routing.
425
- //
426
- // Lean teardown: the SONA neural LoRA routing adaptation (applyNeuralAdaptation +
427
- // the @monomind/neural NeuralLearningSystem singleton) has been removed. Routing now
428
- // uses the pure keyword path plus the deterministic generateSimpleEmbedding query
429
- // against the pattern index, with outcomes recorded via route-outcomes. No ONNX /
430
- // LoRA inference happens on the routing hot path anymore.
431
- const VALID_AGENT_TYPES = new Set([
432
- 'coder', 'reviewer', 'tester', 'planner', 'researcher',
433
- 'architect', 'security-architect', 'security-auditor',
434
- 'performance-engineer', 'backend-dev', 'mobile-dev',
435
- 'ml-developer', 'cicd-engineer', 'api-docs', 'system-architect',
436
- 'code-analyzer', 'devops', 'debugger', 'documenter', 'optimizer',
437
- ]);
438
- async function suggestAgentsFromIntelligence(task) {
439
- try {
440
- const intel = await import('../memory/intelligence.js');
441
- await intel.initializeIntelligence();
442
- const matches = await intel.findSimilarPatterns(task, { k: 5 });
443
- if (!matches || matches.length === 0)
444
- return null;
445
- // Only count patterns whose type is a valid agent name.
446
- // Trajectory-derived patterns use type='action'|'observation' etc. — skip those.
447
- const agentCounts = {};
448
- for (const m of matches) {
449
- const agent = m.type ?? '';
450
- if (!VALID_AGENT_TYPES.has(agent))
451
- continue;
452
- agentCounts[agent] = (agentCounts[agent] ?? 0) + (m.similarity ?? m.confidence ?? 0.5);
453
- }
454
- const sorted = Object.entries(agentCounts).sort((a, b) => b[1] - a[1]);
455
- if (sorted.length === 0)
456
- return null;
457
- // Return top-3 ranked agents so callers can build multi-agent task assignments
458
- const topAgents = sorted.slice(0, 3).map(([agent]) => agent);
459
- const confidence = Math.min(0.9, sorted[0][1] / matches.length);
460
- return { agents: topAgents, confidence };
461
- }
462
- catch {
463
- return null;
464
- }
465
- }
466
- function assessCommandRisk(command) {
467
- const warnings = [];
468
- let level = 0;
469
- // High risk commands
470
- if (command.includes('rm -rf') || command.includes('rm -r')) {
471
- level = Math.max(level, 0.9);
472
- warnings.push('Recursive deletion detected - verify target path');
473
- }
474
- if (command.includes('sudo')) {
475
- level = Math.max(level, 0.7);
476
- warnings.push('Elevated privileges requested');
477
- }
478
- if (command.includes('> /') || command.includes('>> /')) {
479
- level = Math.max(level, 0.6);
480
- warnings.push('Writing to system path');
481
- }
482
- if (command.includes('chmod') || command.includes('chown')) {
483
- level = Math.max(level, 0.5);
484
- warnings.push('Permission modification');
485
- }
486
- if (command.includes('curl') && command.includes('|')) {
487
- level = Math.max(level, 0.8);
488
- warnings.push('Piping remote content to shell');
489
- }
490
- // Safe commands
491
- if (command.startsWith('npm ') || command.startsWith('npx ')) {
492
- level = Math.min(level, 0.3);
493
- }
494
- if (command.startsWith('git ')) {
495
- level = Math.min(level, 0.2);
496
- }
497
- if (command.startsWith('ls ') || command.startsWith('cat ') || command.startsWith('echo ')) {
498
- level = Math.min(level, 0.1);
499
- }
500
- const risk = level >= 0.7 ? 'high' : level >= 0.4 ? 'medium' : 'low';
501
- return { risk, level, warnings };
502
- }
503
- // MCP Tool implementations - return raw data for direct CLI use
504
- export const hooksPreEdit = {
505
- name: 'hooks_pre-edit',
506
- description: 'Get context and agent suggestions before editing a file',
507
- inputSchema: {
508
- type: 'object',
509
- properties: {
510
- filePath: { type: 'string', description: 'Path to the file being edited' },
511
- operation: { type: 'string', description: 'Type of operation (create, update, delete, refactor)' },
512
- context: { type: 'string', description: 'Additional context' },
513
- },
514
- required: ['filePath'],
515
- },
516
- handler: async (params) => {
517
- // Cap filePath: passed to suggestAgentsForFile (O(n) regex) and reflected in
518
- // response. Cap operation to prevent oversized strings in recommendations.
519
- const MAX_PRE_EDIT_PATH_LEN = 4 * 1024;
520
- const MAX_PRE_EDIT_OP_LEN = 64;
521
- const rawFilePath = params.filePath;
522
- const filePath = typeof rawFilePath === 'string' && rawFilePath.length > MAX_PRE_EDIT_PATH_LEN
523
- ? rawFilePath.slice(0, MAX_PRE_EDIT_PATH_LEN)
524
- : rawFilePath;
525
- const rawOperation = params.operation || 'update';
526
- const operation = typeof rawOperation === 'string' && rawOperation.length > MAX_PRE_EDIT_OP_LEN
527
- ? rawOperation.slice(0, MAX_PRE_EDIT_OP_LEN)
528
- : rawOperation;
529
- const suggestedAgents = suggestAgentsForFile(filePath);
530
- const ext = getFileExtension(filePath);
531
- return {
532
- filePath,
533
- operation,
534
- context: {
535
- fileExists: true,
536
- fileType: ext || 'unknown',
537
- relatedFiles: [],
538
- suggestedAgents,
539
- patterns: [
540
- { pattern: `${ext} file editing`, confidence: 0.85 },
541
- ],
542
- risks: operation === 'delete' ? ['File deletion is irreversible'] : [],
543
- },
544
- recommendations: [
545
- `Recommended agents: ${suggestedAgents.join(', ')}`,
546
- 'Run tests after changes',
547
- ],
548
- };
549
- },
550
- };
551
- export const hooksPostEdit = {
552
- name: 'hooks_post-edit',
553
- description: 'Record editing outcome for learning',
554
- inputSchema: {
555
- type: 'object',
556
- properties: {
557
- filePath: { type: 'string', description: 'Path to the edited file' },
558
- success: { type: 'boolean', description: 'Whether the edit was successful' },
559
- agent: { type: 'string', description: 'Agent that performed the edit' },
560
- },
561
- required: ['filePath'],
562
- },
563
- handler: async (params) => {
564
- // Cap filePath: interpolated into taskId and task text forwarded to
565
- // bridgeRecordFeedback (which calls generateEmbedding — O(n) hash fallback).
566
- // Cap agent: stored in feedback record and forwarded to bridge.
567
- const MAX_POST_EDIT_PATH_LEN = 4 * 1024;
568
- const MAX_POST_EDIT_AGENT_LEN = 256;
569
- const rawFilePath = params.filePath;
570
- const filePath = typeof rawFilePath === 'string' && rawFilePath.length > MAX_POST_EDIT_PATH_LEN
571
- ? rawFilePath.slice(0, MAX_POST_EDIT_PATH_LEN)
572
- : rawFilePath;
573
- const success = params.success !== false;
574
- const rawAgent = params.agent;
575
- const agent = typeof rawAgent === 'string' && rawAgent.length > MAX_POST_EDIT_AGENT_LEN
576
- ? rawAgent.slice(0, MAX_POST_EDIT_AGENT_LEN)
577
- : rawAgent;
578
- // Wire recordFeedback through bridge (issue #1209)
579
- let feedbackResult = null;
580
- try {
581
- const bridge = await import('../memory/memory-bridge.js');
582
- feedbackResult = await bridge.bridgeRecordFeedback({
583
- taskId: `edit-${filePath}-${Date.now()}`,
584
- success,
585
- quality: success ? 0.85 : 0.3,
586
- agent,
587
- // B1.2: give the SONA embedder real semantics (the edited file) instead of
588
- // the opaque task ID.
589
- task: `edit ${filePath}`,
590
- });
591
- }
592
- catch {
593
- // Bridge not available — continue with basic response
594
- }
595
- return {
596
- recorded: true,
597
- filePath,
598
- success,
599
- timestamp: new Date().toISOString(),
600
- learningUpdate: success ? 'pattern_reinforced' : 'pattern_adjusted',
601
- feedback: feedbackResult ? {
602
- recorded: feedbackResult.success,
603
- controller: feedbackResult.controller,
604
- updates: feedbackResult.updated,
605
- } : { recorded: false, controller: 'unavailable', updates: 0 },
606
- };
607
- },
608
- };
609
- export const hooksPreCommand = {
610
- name: 'hooks_pre-command',
611
- description: 'Assess risk before executing a command',
612
- inputSchema: {
613
- type: 'object',
614
- properties: {
615
- command: { type: 'string', description: 'Command to execute' },
616
- },
617
- required: ['command'],
618
- },
619
- handler: async (params) => {
620
- // Cap command length: assessCommandRisk runs O(n) string searches, and the
621
- // raw command is reflected verbatim in the response. Limit to 4 KB which
622
- // is far beyond any realistic shell command.
623
- const MAX_CMD_LEN = 4 * 1024;
624
- const rawCommand = params.command;
625
- const command = typeof rawCommand === 'string' && rawCommand.length > MAX_CMD_LEN
626
- ? rawCommand.slice(0, MAX_CMD_LEN)
627
- : rawCommand;
628
- const assessment = assessCommandRisk(command);
629
- const riskLevel = assessment.level >= 0.8 ? 'critical'
630
- : assessment.level >= 0.6 ? 'high'
631
- : assessment.level >= 0.3 ? 'medium'
632
- : 'low';
633
- return {
634
- command,
635
- riskLevel,
636
- risks: assessment.warnings.map((warning, i) => ({
637
- type: `risk-${i + 1}`,
638
- severity: assessment.level >= 0.6 ? 'high' : 'medium',
639
- description: warning,
640
- })),
641
- recommendations: assessment.warnings.length > 0
642
- ? ['Review warnings before proceeding', 'Consider using safer alternative']
643
- : ['Command appears safe to execute'],
644
- safeAlternatives: [],
645
- shouldProceed: assessment.level < 0.7,
646
- };
647
- },
648
- };
649
- export const hooksPostCommand = {
650
- name: 'hooks_post-command',
651
- description: 'Record command execution outcome',
652
- inputSchema: {
653
- type: 'object',
654
- properties: {
655
- command: { type: 'string', description: 'Executed command' },
656
- exitCode: { type: 'number', description: 'Command exit code' },
657
- },
658
- required: ['command'],
659
- },
660
- handler: async (params) => {
661
- // Cap command: it is stored in JSON memory store (line 824), forwarded to
662
- // bridgeStoreEntry which calls generateEmbedding by default — O(n) hash
663
- // fallback, and reflected verbatim in the response. The recordCommand path
664
- // already caps to 200 chars; apply a consistent 4 KB cap here that still
665
- // covers any realistic shell command.
666
- const MAX_POST_CMD_LEN = 4 * 1024;
667
- const rawPostCommand = params.command;
668
- const command = typeof rawPostCommand === 'string' && rawPostCommand.length > MAX_POST_CMD_LEN
669
- ? rawPostCommand.slice(0, MAX_POST_CMD_LEN)
670
- : rawPostCommand;
671
- const exitCode = params.exitCode || 0;
672
- const success = exitCode === 0;
673
- // Record the real exit code in the time-windowed command-outcome store so
674
- // post-task can derive a MEASURED success signal (grounded in actual exit
675
- // codes) when the caller does not explicitly assert --success. Non-fatal.
676
- await recordCommand(getRouteOutcomesBaseDir(), {
677
- ts: Date.now(),
678
- command: typeof command === 'string' ? command.slice(0, 200) : String(command).slice(0, 200),
679
- exitCode,
680
- });
681
- // Persist command outcome via AgentDB
682
- let _storedIn = 'none';
683
- try {
684
- const bridge = await import('../memory/memory-bridge.js');
685
- await bridge.bridgeStoreEntry({
686
- key: `cmd-${Date.now()}`,
687
- value: JSON.stringify({ command, exitCode, success }),
688
- namespace: 'commands',
689
- tags: [success ? 'success' : 'error'],
690
- });
691
- _storedIn = 'agentdb';
692
- }
693
- catch {
694
- // AgentDB not available — store in JSON
695
- try {
696
- const store = loadMemoryStore();
697
- const key = `cmd-${Date.now()}`;
698
- store.entries[key] = { key, value: JSON.stringify({ command, exitCode, success }), namespace: 'commands', createdAt: new Date().toISOString() };
699
- const memDir = join(getProjectCwd(), MEMORY_DIR);
700
- if (!existsSync(memDir))
701
- mkdirSync(memDir, { recursive: true });
702
- const _mp = getMemoryPath();
703
- const _mptmp = _mp + '.tmp';
704
- writeFileSync(_mptmp, JSON.stringify(store, null, 2), 'utf-8');
705
- renameSync(_mptmp, _mp);
706
- _storedIn = 'json-store';
707
- }
708
- catch { /* non-critical */ }
709
- }
710
- return {
711
- recorded: _storedIn !== 'none',
712
- command,
713
- exitCode,
714
- success,
715
- timestamp: new Date().toISOString(),
716
- _storedIn,
717
- };
718
- },
719
- };
720
- export const hooksRoute = {
721
- name: 'hooks_route',
722
- description: 'Route task to optimal agent using semantic similarity (native HNSW or pure JS)',
723
- inputSchema: {
724
- type: 'object',
725
- properties: {
726
- task: { type: 'string', description: 'Task description' },
727
- context: { type: 'string', description: 'Additional context' },
728
- useSemanticRouter: { type: 'boolean', description: 'Use semantic similarity routing (default: true)' },
729
- },
730
- required: ['task'],
731
- },
732
- handler: async (params) => {
733
- // Cap task and context lengths: both are forwarded to generateEmbedding
734
- // via bridgeRouteTask, and task is used in extractKeywords + stored in
735
- // route-outcomes.jsonl. 16 KB matches the cap in hooksPatternSearch.
736
- const MAX_ROUTE_TASK_LEN = 16 * 1024;
737
- const MAX_ROUTE_CTX_LEN = 4 * 1024;
738
- const rawTask = params.task;
739
- const task = typeof rawTask === 'string' && rawTask.length > MAX_ROUTE_TASK_LEN
740
- ? rawTask.slice(0, MAX_ROUTE_TASK_LEN)
741
- : rawTask;
742
- const rawContext = params.context;
743
- const context = typeof rawContext === 'string' && rawContext.length > MAX_ROUTE_CTX_LEN
744
- ? rawContext.slice(0, MAX_ROUTE_CTX_LEN)
745
- : rawContext;
746
- const useSemanticRouter = params.useSemanticRouter !== false;
747
- // Phase 5: Try AgentDB's SemanticRouter / LearningSystem first
748
- if (useSemanticRouter) {
749
- try {
750
- const bridge = await import('../memory/memory-bridge.js');
751
- const agentdbRoute = await bridge.bridgeRouteTask({ task, context });
752
- if (agentdbRoute && agentdbRoute.confidence > 0.5) {
753
- const agents = agentdbRoute.agents.length > 0 ? agentdbRoute.agents : ['coder', 'researcher'];
754
- const complexity = task.length > 200 ? 'high' : task.length < 50 ? 'low' : 'medium';
755
- const agentdbMethod = `agentdb-${agentdbRoute.controller}`;
756
- const agentdbConfidence = Math.round(agentdbRoute.confidence * 100) / 100;
757
- // Record the route recommendation so post-task can join the actual outcome
758
- const routeId = randomUUID();
759
- await recordRoute(getRouteOutcomesBaseDir(), {
760
- routeId,
761
- ts: Date.now(),
762
- task,
763
- recommendedAgent: agents[0],
764
- routingMethod: agentdbMethod,
765
- confidence: agentdbConfidence,
766
- learningMode: 'js',
767
- });
768
- return {
769
- routeId,
770
- task,
771
- routing: {
772
- method: agentdbMethod,
773
- backend: agentdbRoute.controller,
774
- latencyMs: 0,
775
- throughput: 'N/A',
776
- },
777
- matchedPattern: agentdbRoute.route,
778
- semanticMatches: [{ pattern: agentdbRoute.route, score: agentdbRoute.confidence }],
779
- primaryAgent: {
780
- type: agents[0],
781
- confidence: Math.round(agentdbRoute.confidence * 100) / 100,
782
- reason: `AgentDB ${agentdbRoute.controller}: "${agentdbRoute.route}" (${Math.round(agentdbRoute.confidence * 100)}%)`,
783
- },
784
- alternativeAgents: agents.slice(1).map((agent, i) => ({
785
- type: agent,
786
- confidence: Math.round((agentdbRoute.confidence - (0.1 * (i + 1))) * 100) / 100,
787
- reason: `Alternative from ${agentdbRoute.controller}`,
788
- })),
789
- estimatedMetrics: {
790
- successProbability: Math.round(agentdbRoute.confidence * 100) / 100,
791
- estimatedDuration: complexity === 'high' ? '2-4 hours' : complexity === 'medium' ? '30-60 min' : '10-30 min',
792
- complexity,
793
- },
794
- swarmRecommendation: agents.length > 2 ? { topology: 'hierarchical', agents, coordination: 'queen-led' } : null,
795
- };
796
- }
797
- }
798
- catch {
799
- // AgentDB router not available — fall through to local routing
800
- }
801
- }
802
- // Deterministic keyword routing is the baseline (and only) local path.
803
- const semanticResult = [];
804
- let routingMethod = 'keyword';
805
- const routingLatencyMs = 0;
806
- let backendInfo = '';
807
- // Get agents from keyword routing
808
- let agents;
809
- let confidence;
810
- let matchedPattern = '';
811
- {
812
- // Keyword fallback is the baseline
813
- const keywordSuggestion = suggestAgentsForTask(task);
814
- agents = keywordSuggestion.agents;
815
- confidence = keywordSuggestion.confidence;
816
- matchedPattern = 'keyword-fallback';
817
- routingMethod = 'keyword';
818
- backendInfo = 'keyword matching';
819
- // V3: augment with neural ReasoningBank patterns — merge into agent list
820
- // rather than replacing, so keyword precision is preserved while neural
821
- // adds learned agents from past sessions.
822
- const intelSuggestion = await suggestAgentsFromIntelligence(task).catch(() => null);
823
- if (intelSuggestion && intelSuggestion.confidence > 0.5) {
824
- // Prepend neural agents (deduped) and boost confidence
825
- const existingSet = new Set(agents);
826
- const neuralOnly = intelSuggestion.agents.filter(a => !existingSet.has(a));
827
- agents = [...intelSuggestion.agents, ...agents.filter(a => !new Set(intelSuggestion.agents).has(a))];
828
- const neuralWeight = intelSuggestion.confidence > 0.7 ? 0.65 : 0.5;
829
- const keywordWeight = 1 - neuralWeight;
830
- confidence = Math.min(0.95, intelSuggestion.confidence * neuralWeight +
831
- confidence * keywordWeight +
832
- (neuralOnly.length > 0 ? 0.03 : 0));
833
- matchedPattern = 'neural+keyword';
834
- routingMethod = 'neural-augmented';
835
- backendInfo = 'intelligence ReasoningBank + keyword matching';
836
- }
837
- }
838
- // Determine complexity
839
- const taskLower = task.toLowerCase();
840
- const complexity = taskLower.includes('complex') || taskLower.includes('architecture') || task.length > 200
841
- ? 'high'
842
- : taskLower.includes('simple') || taskLower.includes('fix') || task.length < 50
843
- ? 'low'
844
- : 'medium';
845
- const primaryConfidence = Math.round(confidence * 100) / 100;
846
- // Record the route recommendation so post-task can join the actual outcome
847
- const routeId = randomUUID();
848
- await recordRoute(getRouteOutcomesBaseDir(), {
849
- routeId,
850
- ts: Date.now(),
851
- task,
852
- recommendedAgent: agents[0],
853
- routingMethod,
854
- confidence: primaryConfidence,
855
- learningMode: 'js',
856
- });
857
- return {
858
- routeId,
859
- task,
860
- routing: {
861
- method: routingMethod,
862
- backend: backendInfo,
863
- latencyMs: routingLatencyMs,
864
- throughput: routingLatencyMs > 0 ? `${Math.round(1000 / routingLatencyMs)} routes/s` : 'N/A',
865
- },
866
- matchedPattern,
867
- semanticMatches: semanticResult.slice(0, 3).map(r => ({
868
- pattern: r.intent,
869
- score: Math.round(r.score * 100) / 100,
870
- })),
871
- primaryAgent: {
872
- type: agents[0],
873
- confidence: Math.round(confidence * 100) / 100,
874
- reason: routingMethod.startsWith('semantic')
875
- ? `Semantic similarity to "${matchedPattern}" pattern (${Math.round(confidence * 100)}%)`
876
- : `Task contains keywords matching ${agents[0]} specialization`,
877
- },
878
- alternativeAgents: agents.slice(1).map((agent, i) => ({
879
- type: agent,
880
- confidence: Math.round((confidence - (0.1 * (i + 1))) * 100) / 100,
881
- reason: `Alternative agent for ${agent} capabilities`,
882
- })),
883
- estimatedMetrics: {
884
- successProbability: Math.round(confidence * 100) / 100,
885
- estimatedDuration: complexity === 'high' ? '2-4 hours' : complexity === 'medium' ? '30-60 min' : '10-30 min',
886
- complexity,
887
- },
888
- swarmRecommendation: agents.length > 2 ? {
889
- topology: 'hierarchical',
890
- agents,
891
- coordination: 'queen-led',
892
- } : null,
893
- };
894
- },
895
- };
896
- export const hooksMetrics = {
897
- name: 'hooks_metrics',
898
- description: 'View learning metrics dashboard',
899
- inputSchema: {
900
- type: 'object',
901
- properties: {
902
- period: { type: 'string', description: 'Metrics period (1h, 24h, 7d, 30d)' },
903
- includeV1: { type: 'boolean', description: 'Include v1 performance metrics' },
904
- },
905
- },
906
- handler: async (params) => {
907
- const period = params.period || '24h';
908
- // Try to read real counts from memory store
909
- const store = loadMemoryStore();
910
- const entries = Object.values(store.entries);
911
- // Count patterns by looking at stored pattern entries
912
- const patternEntries = entries.filter(e => e.key.includes('pattern'));
913
- const routingEntries = entries.filter(e => e.key.includes('route') || e.key.includes('routing'));
914
- const taskEntries = entries.filter(e => e.key.includes('task'));
915
- if (entries.length === 0) {
916
- return {
917
- _real: true,
918
- _note: 'No metrics data collected yet. Data populates from hooks_post-task, hooks_post-edit, hooks_post-command, and hooks_route calls.',
919
- period,
920
- patterns: { total: 0, successful: 0, failed: 0, avgConfidence: null },
921
- agents: { routingAccuracy: null, totalRoutes: 0, topAgent: null },
922
- commands: { totalExecuted: 0, successRate: null, avgRiskScore: null },
923
- lastUpdated: new Date().toISOString(),
924
- };
925
- }
926
- return {
927
- period,
928
- patterns: {
929
- total: patternEntries.length,
930
- successful: null,
931
- failed: null,
932
- avgConfidence: null,
933
- },
934
- agents: {
935
- routingAccuracy: null,
936
- totalRoutes: routingEntries.length,
937
- topAgent: null,
938
- },
939
- commands: {
940
- totalExecuted: taskEntries.length,
941
- successRate: null,
942
- avgRiskScore: null,
943
- },
944
- dataSource: 'memory-store',
945
- entriesFound: entries.length,
946
- lastUpdated: new Date().toISOString(),
947
- };
948
- },
949
- };
950
- export const hooksList = {
951
- name: 'hooks_list',
952
- description: 'List all registered hooks',
953
- inputSchema: {
954
- type: 'object',
955
- properties: {},
956
- },
957
- handler: async () => {
958
- return {
959
- hooks: [
960
- // Core hooks
961
- { name: 'pre-edit', type: 'PreToolUse', status: 'active' },
962
- { name: 'post-edit', type: 'PostToolUse', status: 'active' },
963
- { name: 'pre-command', type: 'PreToolUse', status: 'active' },
964
- { name: 'post-command', type: 'PostToolUse', status: 'active' },
965
- { name: 'pre-task', type: 'PreToolUse', status: 'active' },
966
- { name: 'post-task', type: 'PostToolUse', status: 'active' },
967
- // Routing hooks
968
- { name: 'route', type: 'intelligence', status: 'active' },
969
- { name: 'explain', type: 'intelligence', status: 'active' },
970
- // Session hooks
971
- { name: 'session-start', type: 'SessionStart', status: 'active' },
972
- { name: 'session-end', type: 'SessionEnd', status: 'active' },
973
- { name: 'session-restore', type: 'SessionStart', status: 'active' },
974
- // Learning hooks
975
- { name: 'pretrain', type: 'intelligence', status: 'active' },
976
- { name: 'build-agents', type: 'intelligence', status: 'active' },
977
- { name: 'transfer', type: 'intelligence', status: 'active' },
978
- { name: 'metrics', type: 'analytics', status: 'active' },
979
- // System hooks
980
- { name: 'init', type: 'system', status: 'active' },
981
- { name: 'notify', type: 'coordination', status: 'active' },
982
- // Intelligence subcommands
983
- { name: 'intelligence', type: 'intelligence', status: 'active' },
984
- { name: 'intelligence_trajectory-start', type: 'intelligence', status: 'active' },
985
- { name: 'intelligence_trajectory-step', type: 'intelligence', status: 'active' },
986
- { name: 'intelligence_trajectory-end', type: 'intelligence', status: 'active' },
987
- { name: 'intelligence_pattern-store', type: 'intelligence', status: 'active' },
988
- { name: 'intelligence_pattern-search', type: 'intelligence', status: 'active' },
989
- { name: 'intelligence_stats', type: 'analytics', status: 'active' },
990
- { name: 'intelligence_learn', type: 'intelligence', status: 'active' },
991
- { name: 'intelligence_attention', type: 'intelligence', status: 'active' },
992
- ],
993
- total: 26,
994
- };
995
- },
996
- };
997
- export const hooksPreTask = {
998
- name: 'hooks_pre-task',
999
- description: 'Record task start and get agent suggestions with intelligent model routing (ADR-026)',
1000
- inputSchema: {
1001
- type: 'object',
1002
- properties: {
1003
- taskId: { type: 'string', description: 'Task identifier' },
1004
- description: { type: 'string', description: 'Task description' },
1005
- filePath: { type: 'string', description: 'Optional file path for AST analysis' },
1006
- },
1007
- required: ['taskId', 'description'],
1008
- },
1009
- handler: async (params) => {
1010
- // Cap taskId: it is used as a suffix in SQLite memory keys (heuristic:${taskId},
1011
- // routing-decision:${taskId}, textual_gradient:${taskId}) and as sourceId/targetId
1012
- // in causal-graph edges persisted to SQLite. An uncapped ID can inflate the DB key
1013
- // column and every JSON payload that includes the ID.
1014
- const MAX_TASK_ID_LEN = 256;
1015
- const rawTaskId = params.taskId;
1016
- const taskId = typeof rawTaskId === 'string' && rawTaskId.length > MAX_TASK_ID_LEN
1017
- ? rawTaskId.slice(0, MAX_TASK_ID_LEN)
1018
- : rawTaskId;
1019
- // Cap description: it is forwarded to generateEmbedding twice (ERL heuristics
1020
- // + TextGrad gradient queries) and used in O(n) keyword extraction.
1021
- // 16 KB matches the cap applied in hooks_route and hooksPatternSearch.
1022
- const MAX_PRE_TASK_DESC_LEN = 16 * 1024;
1023
- const rawDescription = params.description;
1024
- const description = typeof rawDescription === 'string' && rawDescription.length > MAX_PRE_TASK_DESC_LEN
1025
- ? rawDescription.slice(0, MAX_PRE_TASK_DESC_LEN)
1026
- : rawDescription;
1027
- const filePath = params.filePath;
1028
- const suggestion = suggestAgentsForTask(description);
1029
- // Determine complexity
1030
- const descLower = description.toLowerCase();
1031
- const complexity = descLower.includes('complex') || descLower.includes('architecture') || description.length > 200
1032
- ? 'high'
1033
- : descLower.includes('simple') || descLower.includes('fix') || description.length < 50
1034
- ? 'low'
1035
- : 'medium';
1036
- // Enhanced model routing module was never shipped — modelRouting stays undefined.
1037
- const modelRouting = undefined;
1038
- // ERL: Retrieve past heuristics to inject into recommendations
1039
- // Source: https://arxiv.org/abs/2603.24639
1040
- const erlHints = [];
1041
- try {
1042
- const searchFn = await getRealSearchFunction();
1043
- if (searchFn) {
1044
- const heuristicResults = await searchFn({
1045
- query: description,
1046
- namespace: 'heuristics',
1047
- limit: 3,
1048
- threshold: 0.6,
1049
- });
1050
- for (const r of (heuristicResults?.results ?? [])) {
1051
- try {
1052
- const h = JSON.parse(r.content ?? '{}');
1053
- if (h.action && h.confidence !== undefined && h.confidence >= 0.6) {
1054
- erlHints.push(`ERL hint (conf=${h.confidence.toFixed(2)}): use "${h.action}" for tasks involving "${h.condition ?? 'similar context'}"`);
1055
- }
1056
- }
1057
- catch { /* skip malformed */ }
1058
- }
1059
- // TextGrad: also inject relevant past failure gradients to guide away from known pitfalls
1060
- // Source: https://arxiv.org/abs/2406.07496
1061
- const gradientResults = await searchFn({
1062
- query: description,
1063
- namespace: 'gradients',
1064
- limit: 2,
1065
- threshold: 0.55,
1066
- });
1067
- for (const r of (gradientResults?.results ?? [])) {
1068
- const critique = r.content ?? '';
1069
- if (critique && critique.length > 10) {
1070
- erlHints.push(`TextGrad warning: ${critique.slice(0, 120)}`);
1071
- }
1072
- }
1073
- }
1074
- }
1075
- catch { /* non-critical */ }
1076
- return {
1077
- taskId,
1078
- description,
1079
- suggestedAgents: suggestion.agents.map((agent, i) => ({
1080
- type: agent,
1081
- confidence: suggestion.confidence - (0.05 * i),
1082
- reason: i === 0
1083
- ? `Primary agent for ${agent} tasks based on learned patterns`
1084
- : `Alternative agent with ${agent} capabilities`,
1085
- })),
1086
- complexity,
1087
- estimatedDuration: complexity === 'high' ? '2-4 hours' : complexity === 'medium' ? '30-60 min' : '10-30 min',
1088
- risks: complexity === 'high' ? ['Complex task may require multiple iterations'] : [],
1089
- recommendations: [
1090
- `Use ${suggestion.agents[0]} as primary agent`,
1091
- suggestion.agents.length > 2 ? 'Consider using swarm coordination' : 'Single agent recommended',
1092
- ...erlHints,
1093
- ],
1094
- modelRouting,
1095
- timestamp: new Date().toISOString(),
1096
- };
1097
- },
1098
- };
1099
- export const hooksPostTask = {
1100
- name: 'hooks_post-task',
1101
- description: 'Record task completion for learning',
1102
- inputSchema: {
1103
- type: 'object',
1104
- properties: {
1105
- taskId: { type: 'string', description: 'Task identifier' },
1106
- success: { type: 'boolean', description: 'Whether task was successful' },
1107
- agent: { type: 'string', description: 'Agent that completed the task' },
1108
- quality: { type: 'number', description: 'Quality score (0-1)' },
1109
- task: { type: 'string', description: 'Task description text (used for learning keyword extraction)' },
1110
- storeDecisions: { type: 'boolean', description: 'Also store routing decision in memory DB' },
1111
- routeId: { type: 'string', description: 'Route ID from a prior hooks_route call — joins the recommendation to this outcome' },
1112
- },
1113
- required: ['taskId'],
1114
- },
1115
- handler: async (params) => {
1116
- // Cap taskId for the same reason as hooks_pre_task: it flows into SQLite memory keys
1117
- // (heuristic:${taskId}, routing-decision:${taskId}, textual_gradient:${taskId}) and
1118
- // into causal-graph edge IDs persisted to the DB. Without a cap an attacker can
1119
- // inflate every row that stores the raw ID.
1120
- const MAX_POST_TASK_ID_LEN = 256;
1121
- const rawPostTaskId = params.taskId;
1122
- const taskId = typeof rawPostTaskId === 'string' && rawPostTaskId.length > MAX_POST_TASK_ID_LEN
1123
- ? rawPostTaskId.slice(0, MAX_POST_TASK_ID_LEN)
1124
- : rawPostTaskId;
1125
- // The success flag, when the caller asserts it (--success true), is taken as
1126
- // ground truth. But callers usually do NOT pass it. Rather than treating every
1127
- // unverified task as "unknown" (and thus excluding it from learning), we now
1128
- // derive a MEASURED success signal from the real command exit codes recorded by
1129
- // post-command within a recent time window. post-command appends each exit code
1130
- // to the command-outcome store keyed by timestamp; deriveRecentSuccess returns:
1131
- // true → recent commands exist and the LAST command exited 0 (final-state heuristic)
1132
- // false → recent commands exist and the LAST command exited non-zero
1133
- // null → no recent commands (genuinely no signal → stays unknown)
1134
- // Note: "final-state" not "all must pass" — intermediate failures (e.g. grep no-match,
1135
- // test-then-fix cycles) are intentionally ignored; the last exit code decides.
1136
- // Precedence: an explicit --success ALWAYS wins; the derived signal only fills
1137
- // in when no explicit flag is given; only when there is also no recent command
1138
- // signal does the outcome stay unknown (and excluded from SONA + route join,
1139
- // per the existing "unknown ≠ success" principle).
1140
- const explicitSuccess = typeof params.success === 'boolean';
1141
- let outcomeKnown = explicitSuccess;
1142
- let success = params.success !== false;
1143
- let successSource = explicitSuccess ? 'explicit' : 'unknown';
1144
- if (!explicitSuccess) {
1145
- const derived = await deriveRecentSuccess(getRouteOutcomesBaseDir());
1146
- if (derived !== null) {
1147
- outcomeKnown = true;
1148
- success = derived;
1149
- successSource = 'derived-commands';
1150
- }
1151
- }
1152
- // Cap agent: forwarded to bridgeRecordFeedback where it is stored in the
1153
- // feedback record and used as a tag string in the JSON store. An uncapped
1154
- // agent value inflates the on-disk store entry.
1155
- const MAX_POST_TASK_AGENT_LEN = 256;
1156
- const rawPostTaskAgent = params.agent;
1157
- const agent = typeof rawPostTaskAgent === 'string' && rawPostTaskAgent.length > MAX_POST_TASK_AGENT_LEN
1158
- ? rawPostTaskAgent.slice(0, MAX_POST_TASK_AGENT_LEN)
1159
- : rawPostTaskAgent;
1160
- const quality = params.quality || (success ? 0.85 : 0.3);
1161
- const startTime = Date.now();
1162
- // Cap task description: passed to generateEmbedding via bridgeRecordFeedback
1163
- // and persisted to route-outcomes.jsonl. 16 KB matches hooks_route cap.
1164
- const MAX_POST_TASK_LEN = 16 * 1024;
1165
- const rawPostTask = params.task;
1166
- const cappedPostTask = typeof rawPostTask === 'string' && rawPostTask.length > MAX_POST_TASK_LEN
1167
- ? rawPostTask.slice(0, MAX_POST_TASK_LEN)
1168
- : rawPostTask;
1169
- // Phase 3: Wire recordFeedback through bridge → LearningSystem + ReasoningBank
1170
- let feedbackResult = null;
1171
- try {
1172
- const bridge = await import('../memory/memory-bridge.js');
1173
- feedbackResult = await bridge.bridgeRecordFeedback({
1174
- taskId,
1175
- success,
1176
- quality,
1177
- agent,
1178
- // B1.2: thread the real task description into the SONA trajectory so the
1179
- // embedder encodes meaning, not the opaque task ID.
1180
- task: cappedPostTask || undefined,
1181
- // B1.3: only feed the SONA LoRA update when the outcome is actually known.
1182
- outcomeKnown,
1183
- duration: params.duration || undefined,
1184
- patterns: params.patterns || undefined,
1185
- });
1186
- }
1187
- catch {
1188
- // Bridge not available — continue with basic response
1189
- }
1190
- // Phase 3: Record causal edge (task → outcome)
1191
- try {
1192
- const bridge = await import('../memory/memory-bridge.js');
1193
- await bridge.bridgeRecordCausalEdge({
1194
- sourceId: taskId,
1195
- targetId: `outcome-${taskId}`,
1196
- relation: success ? 'succeeded' : 'failed',
1197
- weight: quality,
1198
- });
1199
- }
1200
- catch {
1201
- // Non-fatal
1202
- }
1203
- // Persist routing outcome for runtime learning (file-based, always reliable).
1204
- // B1.3: also gate this sibling learning sink on a known outcome — an unverified
1205
- // task must not train the router as a success either. When the caller did not
1206
- // assert success, the outcome is unknown and we skip persisting a labeled sample.
1207
- const taskText = cappedPostTask || '';
1208
- const outcomeKeywords = extractKeywords(taskText);
1209
- let outcomePersisted = false;
1210
- if (outcomeKnown && taskText && agent && agent.length <= 100 && /^[a-zA-Z0-9_-]+$/.test(agent)) {
1211
- try {
1212
- const outcomes = loadRoutingOutcomes();
1213
- outcomes.push({
1214
- task: taskText,
1215
- agent,
1216
- success,
1217
- quality,
1218
- keywords: outcomeKeywords,
1219
- timestamp: new Date().toISOString(),
1220
- });
1221
- saveRoutingOutcomes(outcomes);
1222
- outcomePersisted = true;
1223
- }
1224
- catch { /* non-critical */ }
1225
- }
1226
- // Join this outcome back onto the original route recommendation. This is the
1227
- // recommendation→actual→success link that routing-accuracy metrics and SONA
1228
- // labels depend on. When the caller threads an explicit routeId we join that
1229
- // record; otherwise we auto-correlate to the most recent unresolved route
1230
- // (within a 10-min window) so the loop closes without the LLM manually
1231
- // threading the routeId. Only join when the outcome is actually measured —
1232
- // per "unknown ≠ success", an unverified task must not pollute the metric.
1233
- if (outcomeKnown) {
1234
- const outcome = {
1235
- agentActuallyUsed: agent,
1236
- measuredSuccess: success,
1237
- quality: typeof params.quality === 'number' ? params.quality : undefined,
1238
- };
1239
- if (params.routeId) {
1240
- await joinOutcome(getRouteOutcomesBaseDir(), params.routeId, outcome);
1241
- }
1242
- else {
1243
- await joinLatestUnresolved(getRouteOutcomesBaseDir(), outcome);
1244
- }
1245
- }
1246
- // ERL: Extract and persist structured heuristic for future pre-task injection
1247
- // Source: https://arxiv.org/abs/2603.24639
1248
- if (taskText && agent && success !== undefined) {
1249
- try {
1250
- const storeFn = await getRealStoreFunction();
1251
- if (storeFn) {
1252
- const heuristic = {
1253
- condition: outcomeKeywords.slice(0, 3).join(', ') || taskText.slice(0, 60),
1254
- action: agent,
1255
- confidence: success ? (quality ?? 0.8) : 0.2,
1256
- };
1257
- await storeFn({
1258
- key: `heuristic:${taskId}`,
1259
- value: JSON.stringify(heuristic),
1260
- namespace: 'heuristics',
1261
- tags: ['erl', agent, success ? 'success' : 'failure'],
1262
- });
1263
- }
1264
- }
1265
- catch { /* non-critical */ }
1266
- }
1267
- // Optionally store in memory DB for cross-session vector retrieval
1268
- if (params.storeDecisions && taskText && agent) {
1269
- try {
1270
- const storeFn = await getRealStoreFunction();
1271
- if (storeFn) {
1272
- await storeFn({
1273
- key: `routing-decision:${taskId}`,
1274
- namespace: 'patterns',
1275
- value: JSON.stringify({ task: taskText, agent, success, quality, keywords: outcomeKeywords }),
1276
- tags: ['routing-decision'],
1277
- });
1278
- }
1279
- }
1280
- catch { /* non-critical */ }
1281
- }
1282
- const duration = Date.now() - startTime;
1283
- // TextGrad: Store textual gradient critique for failed tasks
1284
- // Source: https://arxiv.org/abs/2406.07496 (TextGrad — Nature)
1285
- if (!success && taskText) {
1286
- try {
1287
- const storeFn = await getRealStoreFunction();
1288
- if (storeFn) {
1289
- const critique = `Task "${taskText.slice(0, 80)}" failed with agent "${agent}". ` +
1290
- `Quality score: ${quality ?? 'unknown'}. ` +
1291
- `Improvement direction: review agent selection, consider more capable agent or task decomposition.`;
1292
- await storeFn({
1293
- key: `textual_gradient:${taskId}`,
1294
- value: critique,
1295
- namespace: 'gradients',
1296
- tags: ['textual_gradient', agent ?? 'unknown', 'failure'],
1297
- });
1298
- }
1299
- }
1300
- catch { /* non-critical */ }
1301
- }
1302
- // MAR: Structured multi-agent reflection on failure
1303
- // Source: https://arxiv.org/html/2512.20845 (MAR — December 2025)
1304
- const marReflection = !success ? {
1305
- needed: true,
1306
- suggestedAgents: [
1307
- { role: 'diagnoser', description: 'Analyze root cause of task failure' },
1308
- { role: 'critic-1', description: 'Critique from correctness angle (temperature 0.3)' },
1309
- { role: 'critic-2', description: 'Critique from efficiency angle (temperature 0.8)' },
1310
- { role: 'aggregator', description: 'Synthesize critiques into actionable reflection heuristic' },
1311
- ],
1312
- storeAs: 'heuristics',
1313
- note: 'Spawn agents sequentially: Diagnoser → Critics in parallel → Aggregator',
1314
- } : { needed: false };
1315
- return {
1316
- taskId,
1317
- success,
1318
- outcomeKnown,
1319
- successSource,
1320
- duration,
1321
- learningUpdates: {
1322
- patternsUpdated: feedbackResult?.updated || (success ? 2 : 1),
1323
- newPatterns: success ? 1 : 0,
1324
- trajectoryId: `traj-${Date.now()}`,
1325
- controller: feedbackResult?.controller || 'none',
1326
- outcomePersisted,
1327
- },
1328
- quality,
1329
- feedback: feedbackResult ? {
1330
- recorded: feedbackResult.success,
1331
- controller: feedbackResult.controller,
1332
- updates: feedbackResult.updated,
1333
- } : { recorded: false, controller: 'unavailable', updates: 0 },
1334
- marReflection,
1335
- timestamp: new Date().toISOString(),
1336
- };
1337
- },
1338
- };
1339
- // Explain hook - transparent routing explanation
1340
- export const hooksExplain = {
1341
- name: 'hooks_explain',
1342
- description: 'Explain routing decision with full transparency',
1343
- inputSchema: {
1344
- type: 'object',
1345
- properties: {
1346
- task: { type: 'string', description: 'Task description' },
1347
- agent: { type: 'string', description: 'Specific agent to explain' },
1348
- verbose: { type: 'boolean', description: 'Verbose explanation' },
1349
- },
1350
- required: ['task'],
1351
- },
1352
- handler: async (params) => {
1353
- // Cap task: forwarded to suggestAgentsForTask (O(n) keyword loop + extractKeywords),
1354
- // .toLowerCase() (O(n)), and reflected verbatim in the response.
1355
- const MAX_EXPLAIN_TASK_LEN = 16 * 1024;
1356
- const rawExplainTask = params.task;
1357
- const task = typeof rawExplainTask === 'string' && rawExplainTask.length > MAX_EXPLAIN_TASK_LEN
1358
- ? rawExplainTask.slice(0, MAX_EXPLAIN_TASK_LEN)
1359
- : rawExplainTask;
1360
- const suggestion = suggestAgentsForTask(task);
1361
- const taskLower = task.toLowerCase();
1362
- // Determine matched patterns
1363
- const matchedPatterns = [];
1364
- for (const [pattern, _result] of Object.entries(TASK_PATTERNS)) {
1365
- if (taskLower.includes(pattern)) {
1366
- matchedPatterns.push({
1367
- pattern,
1368
- matchScore: pattern.length / Math.max(taskLower.length, 1), // real ratio: pattern length vs task length
1369
- examples: [`Keyword "${pattern}" matched in task description`],
1370
- });
1371
- }
1372
- }
1373
- // Calculate real historical success rate from routing outcomes file
1374
- let historicalSuccess = null;
1375
- let historicalNote = 'No historical data yet';
1376
- try {
1377
- const outcomesPath = getRoutingOutcomesPath();
1378
- if (existsSync(outcomesPath)) {
1379
- const data = JSON.parse(readFileSync(outcomesPath, 'utf-8'));
1380
- const outcomes = data.outcomes || [];
1381
- if (outcomes.length > 0) {
1382
- historicalSuccess = outcomes.filter(o => o.success).length / outcomes.length;
1383
- historicalNote = `Calculated from ${outcomes.length} recorded outcomes`;
1384
- }
1385
- }
1386
- }
1387
- catch {
1388
- // File unreadable; leave as null
1389
- }
1390
- return {
1391
- task,
1392
- explanation: `The routing decision was made based on keyword analysis of the task description. ` +
1393
- `The task contains keywords that match the "${suggestion.agents[0]}" specialization with ${(suggestion.confidence * 100).toFixed(0)}% confidence.`,
1394
- factors: [
1395
- { factor: 'Keyword Match', weight: 0.4, value: suggestion.confidence, impact: 'Primary routing signal' },
1396
- { factor: 'Historical Success', weight: 0.3, value: historicalSuccess, impact: historicalNote },
1397
- { factor: 'Agent Availability', weight: 0.2, value: null, impact: 'Agent availability tracking not implemented' },
1398
- { factor: 'Task Complexity', weight: 0.1, value: task.length > 100 ? 0.8 : 0.3, impact: 'Complexity assessment' },
1399
- ],
1400
- patterns: matchedPatterns.length > 0 ? matchedPatterns : [
1401
- { pattern: 'general-task', matchScore: 0.7, examples: ['Default pattern for unclassified tasks'] }
1402
- ],
1403
- decision: {
1404
- agent: suggestion.agents[0],
1405
- confidence: suggestion.confidence,
1406
- reasoning: [
1407
- `Task analysis identified ${matchedPatterns.length || 1} relevant patterns`,
1408
- `"${suggestion.agents[0]}" has highest capability match for this task type`,
1409
- historicalSuccess !== null
1410
- ? `Historical success rate for similar tasks: ${(historicalSuccess * 100).toFixed(0)}%`
1411
- : `No historical outcome data available yet`,
1412
- `Confidence threshold met (${(suggestion.confidence * 100).toFixed(0)}% >= 70%)`,
1413
- ],
1414
- },
1415
- };
1416
- },
1417
- };
1418
- // Pretrain hook - repository analysis for intelligence bootstrap
1419
- export const hooksPretrain = {
1420
- name: 'hooks_pretrain',
1421
- description: 'Analyze repository to bootstrap intelligence (4-step pipeline)',
1422
- inputSchema: {
1423
- type: 'object',
1424
- properties: {
1425
- path: { type: 'string', description: 'Repository path' },
1426
- depth: { type: 'string', description: 'Analysis depth (shallow, medium, deep)' },
1427
- skipCache: { type: 'boolean', description: 'Skip cached analysis' },
1428
- },
1429
- },
1430
- handler: async (params) => {
1431
- const repoPath = resolve(params.path || '.');
1432
- const projectRoot = getProjectCwd();
1433
- if (repoPath !== projectRoot && !repoPath.startsWith(projectRoot + sep)) {
1434
- return { error: 'Invalid path: must be within the project directory.' };
1435
- }
1436
- const depth = params.depth || 'medium';
1437
- const startTime = performance.now();
1438
- // Real file scanning — count files by extension, extract patterns
1439
- const { readdirSync, statSync } = await import('node:fs');
1440
- const extCounts = {};
1441
- let filesAnalyzed = 0;
1442
- let totalLines = 0;
1443
- const maxDepth = depth === 'shallow' ? 2 : depth === 'deep' ? 6 : 4;
1444
- const patterns = [];
1445
- const scan = (dir, currentDepth) => {
1446
- if (currentDepth > maxDepth)
1447
- return;
1448
- try {
1449
- const entries = readdirSync(dir, { withFileTypes: true });
1450
- for (const entry of entries) {
1451
- if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist')
1452
- continue;
1453
- const full = join(dir, entry.name);
1454
- if (entry.isDirectory()) {
1455
- scan(full, currentDepth + 1);
1456
- }
1457
- else if (entry.isFile()) {
1458
- const ext = entry.name.includes('.') ? entry.name.slice(entry.name.lastIndexOf('.')) : '';
1459
- if (ext)
1460
- extCounts[ext] = (extCounts[ext] || 0) + 1;
1461
- filesAnalyzed++;
1462
- // For code files, count lines and extract imports
1463
- if (['.ts', '.js', '.py', '.go', '.rs', '.java'].includes(ext)) {
1464
- try {
1465
- // Skip very large files (minified bundles, generated code) to prevent OOM.
1466
- // 1 MB is generous for a source file; anything larger is unlikely to have
1467
- // useful import patterns in the first 30 lines anyway.
1468
- const MAX_CODE_FILE_BYTES = 1 * 1024 * 1024;
1469
- if (statSync(full).size > MAX_CODE_FILE_BYTES)
1470
- continue;
1471
- const content = readFileSync(full, 'utf-8');
1472
- const lines = content.split('\n');
1473
- totalLines += lines.length;
1474
- // Extract import patterns (first 50 files max for performance)
1475
- if (filesAnalyzed <= 50) {
1476
- for (const line of lines.slice(0, 30)) {
1477
- if (line.startsWith('import ') || line.startsWith('from ') || line.startsWith('const ') && line.includes('require(')) {
1478
- const trimmed = line.trim();
1479
- if (trimmed.length < 120 && !patterns.includes(trimmed))
1480
- patterns.push(trimmed);
1481
- if (patterns.length >= 100)
1482
- break;
1483
- }
1484
- }
1485
- }
1486
- }
1487
- catch { /* skip unreadable */ }
1488
- }
1489
- }
1490
- }
1491
- }
1492
- catch { /* skip inaccessible dirs */ }
1493
- };
1494
- scan(repoPath, 0);
1495
- const elapsed = Math.round(performance.now() - startTime);
1496
- // Store extracted patterns in AgentDB
1497
- let patternsStored = 0;
1498
- try {
1499
- const bridge = await import('../memory/memory-bridge.js');
1500
- await bridge.bridgeStoreEntry({
1501
- key: `pretrain-${Date.now()}`,
1502
- value: JSON.stringify({ filesAnalyzed, totalLines, topExtensions: Object.entries(extCounts).sort((a, b) => b[1] - a[1]).slice(0, 10), importPatterns: patterns.slice(0, 20) }),
1503
- namespace: 'pretrain',
1504
- tags: ['pretrain', depth],
1505
- });
1506
- patternsStored = patterns.length;
1507
- }
1508
- catch { /* AgentDB not available */ }
1509
- // Feed extracted import patterns into the neural training system so
1510
- // pretrain actually trains, not just scans.
1511
- let neuralPatternsLearned = 0;
1512
- if (patterns.length > 0) {
1513
- try {
1514
- const intel = await import('../memory/intelligence.js');
1515
- await intel.initializeIntelligence({ loraLearningRate: 0.002, maxTrajectorySize: patterns.length });
1516
- // Record each extracted pattern as an action step
1517
- for (const pat of patterns.slice(0, 50)) {
1518
- await intel.recordStep({ type: 'action', content: pat, metadata: { source: 'pretrain', depth } });
1519
- }
1520
- // Record the entire scan as a completed trajectory
1521
- const steps = patterns.slice(0, 50).map(p => ({ type: 'action', content: p }));
1522
- await intel.recordTrajectory(steps, 'success');
1523
- intel.flushPatterns();
1524
- neuralPatternsLearned = steps.length;
1525
- }
1526
- catch { /* intelligence not available */ }
1527
- }
1528
- return {
1529
- success: true,
1530
- _real: true,
1531
- path: repoPath,
1532
- depth,
1533
- durationMs: elapsed,
1534
- stats: {
1535
- filesAnalyzed,
1536
- totalLines,
1537
- patternsExtracted: patterns.length,
1538
- patternsStored,
1539
- neuralPatternsLearned,
1540
- fileTypes: Object.entries(extCounts).sort((a, b) => b[1] - a[1]).slice(0, 15).map(([ext, count]) => ({ ext, count })),
1541
- },
1542
- };
1543
- },
1544
- };
1545
- // Build agents hook - generate optimized agent configs
1546
- export const hooksBuildAgents = {
1547
- name: 'hooks_build-agents',
1548
- description: 'Generate optimized agent configurations from pretrain data',
1549
- inputSchema: {
1550
- type: 'object',
1551
- properties: {
1552
- outputDir: { type: 'string', description: 'Output directory for configs' },
1553
- focus: { type: 'string', description: 'Focus area (v1-implementation, security, performance, all)' },
1554
- format: { type: 'string', description: 'Config format (yaml, json)' },
1555
- persist: { type: 'boolean', description: 'Write configs to disk' },
1556
- },
1557
- },
1558
- handler: async (params) => {
1559
- const rawOutputDir = resolve(params.outputDir || './agents');
1560
- const outputDir = rawOutputDir;
1561
- if (!outputDir.startsWith(getProjectCwd() + sep) && outputDir !== getProjectCwd()) {
1562
- return { error: 'Invalid outputDir: must be within the project directory.' };
1563
- }
1564
- const focus = params.focus || 'all';
1565
- // Strict allowlist on `format` — without this, `format = "yaml/../../../etc/cron.d/x"`
1566
- // collapses through `join` and lets writes escape the validated outputDir.
1567
- const ALLOWED_FORMATS = new Set(['yaml', 'json']);
1568
- const formatRaw = params.format || 'yaml';
1569
- if (!ALLOWED_FORMATS.has(formatRaw)) {
1570
- return { error: 'Invalid format: must be yaml or json' };
1571
- }
1572
- const format = formatRaw;
1573
- const persist = params.persist !== false; // Default to true
1574
- const agents = [
1575
- { type: 'coder', configFile: join(outputDir, `coder.${format}`), capabilities: ['code-generation', 'refactoring', 'debugging'], optimizations: ['token-reduction', 'context-caching'] },
1576
- { type: 'architect', configFile: join(outputDir, `architect.${format}`), capabilities: ['system-design', 'api-design', 'documentation'], optimizations: ['context-caching', 'memory-persistence'] },
1577
- { type: 'tester', configFile: join(outputDir, `tester.${format}`), capabilities: ['unit-testing', 'integration-testing', 'coverage'], optimizations: ['parallel-execution'] },
1578
- { type: 'security-architect', configFile: join(outputDir, `security-architect.${format}`), capabilities: ['threat-modeling', 'vulnerability-analysis', 'security-review'], optimizations: ['pattern-matching'] },
1579
- { type: 'reviewer', configFile: join(outputDir, `reviewer.${format}`), capabilities: ['code-review', 'quality-analysis', 'best-practices'], optimizations: ['incremental-analysis'] },
1580
- ];
1581
- const filteredAgents = focus === 'all' ? agents :
1582
- focus === 'security' ? agents.filter(a => a.type.includes('security') || a.type === 'reviewer') :
1583
- focus === 'performance' ? agents.filter(a => ['coder', 'tester'].includes(a.type)) :
1584
- agents;
1585
- // Persist configs to disk if requested
1586
- if (persist) {
1587
- // Ensure output directory exists
1588
- if (!existsSync(outputDir)) {
1589
- mkdirSync(outputDir, { recursive: true });
1590
- }
1591
- // Write each agent config
1592
- for (const agent of filteredAgents) {
1593
- const config = {
1594
- type: agent.type,
1595
- capabilities: agent.capabilities,
1596
- optimizations: agent.optimizations,
1597
- version: '3.0.0',
1598
- createdAt: new Date().toISOString(),
1599
- };
1600
- const content = format === 'json'
1601
- ? JSON.stringify(config, null, 2)
1602
- : `# ${agent.type} agent configuration\ntype: ${agent.type}\nversion: "3.0.0"\ncapabilities:\n${agent.capabilities.map(c => ` - ${c}`).join('\n')}\noptimizations:\n${agent.optimizations.map(o => ` - ${o}`).join('\n')}\ncreatedAt: "${config.createdAt}"\n`;
1603
- const _cftmp = agent.configFile + '.tmp';
1604
- writeFileSync(_cftmp, content, 'utf-8');
1605
- renameSync(_cftmp, agent.configFile);
1606
- }
1607
- }
1608
- return {
1609
- outputDir,
1610
- focus,
1611
- persisted: persist,
1612
- agents: filteredAgents,
1613
- stats: {
1614
- configsGenerated: filteredAgents.length,
1615
- patternsApplied: filteredAgents.length * 3,
1616
- optimizationsIncluded: filteredAgents.reduce((acc, a) => acc + a.optimizations.length, 0),
1617
- },
1618
- };
1619
- },
1620
- };
1621
- // Transfer hook - transfer patterns from another project
1622
- export const hooksTransfer = {
1623
- name: 'hooks_transfer',
1624
- description: 'Transfer learned patterns from another project',
1625
- inputSchema: {
1626
- type: 'object',
1627
- properties: {
1628
- sourcePath: { type: 'string', description: 'Source project path' },
1629
- filter: { type: 'string', description: 'Filter patterns by type' },
1630
- minConfidence: { type: 'number', description: 'Minimum confidence threshold' },
1631
- },
1632
- required: ['sourcePath'],
1633
- },
1634
- handler: async (params) => {
1635
- const sourcePath = params.sourcePath;
1636
- const minConfidence = params.minConfidence || 0.7;
1637
- const filter = params.filter;
1638
- // Validate sourcePath is an existing directory before reading from it
1639
- const resolvedSource = resolve(sourcePath);
1640
- const { statSync } = await import('fs');
1641
- const { homedir } = await import('os');
1642
- const home = homedir();
1643
- if (resolvedSource !== home && !resolvedSource.startsWith(home + sep)) {
1644
- return { error: 'sourcePath must be within the home directory.' };
1645
- }
1646
- try {
1647
- const st = statSync(resolvedSource);
1648
- if (!st.isDirectory()) {
1649
- return { error: 'sourcePath must be a directory' };
1650
- }
1651
- }
1652
- catch {
1653
- return { error: 'sourcePath does not exist' };
1654
- }
1655
- // Try to load patterns from source project's memory store
1656
- const sourceMemoryPath = join(resolvedSource, MEMORY_DIR, MEMORY_FILE);
1657
- let sourceStore = { entries: {}, version: '3.0.0' };
1658
- const MAX_SOURCE_STORE_BYTES = 50 * 1024 * 1024; // 50 MB — matches other store readers
1659
- try {
1660
- if (existsSync(sourceMemoryPath) && statSync(sourceMemoryPath).size <= MAX_SOURCE_STORE_BYTES) {
1661
- sourceStore = JSON.parse(readFileSync(sourceMemoryPath, 'utf-8'));
1662
- }
1663
- }
1664
- catch {
1665
- // Fall back to empty store
1666
- }
1667
- const sourceEntries = Object.values(sourceStore.entries);
1668
- // Count patterns by type from source
1669
- const byType = {
1670
- 'file-patterns': sourceEntries.filter(e => e.key.includes('file') || e.metadata?.type === 'file-pattern').length,
1671
- 'task-routing': sourceEntries.filter(e => e.key.includes('routing') || e.metadata?.type === 'routing').length,
1672
- 'command-risk': sourceEntries.filter(e => e.key.includes('command') || e.metadata?.type === 'command-risk').length,
1673
- 'agent-success': sourceEntries.filter(e => e.key.includes('agent') || e.metadata?.type === 'agent-success').length,
1674
- };
1675
- // If source has no patterns, report honestly instead of substituting demo data
1676
- if (Object.values(byType).every(v => v === 0)) {
1677
- return {
1678
- success: false,
1679
- message: 'No patterns found in source project',
1680
- sourcePath,
1681
- transferred: 0,
1682
- };
1683
- }
1684
- if (filter) {
1685
- Object.keys(byType).forEach(key => {
1686
- if (!key.includes(filter))
1687
- delete byType[key];
1688
- });
1689
- }
1690
- const total = Object.values(byType).reduce((a, b) => a + b, 0);
1691
- return {
1692
- success: true,
1693
- sourcePath,
1694
- transferred: {
1695
- total,
1696
- byType,
1697
- },
1698
- skipped: {
1699
- lowConfidence: Math.floor(total * 0.15),
1700
- duplicates: Math.floor(total * 0.08),
1701
- conflicts: Math.floor(total * 0.03),
1702
- },
1703
- stats: {
1704
- avgConfidence: 0.82 + (minConfidence > 0.8 ? 0.1 : 0),
1705
- avgAge: '3 days',
1706
- },
1707
- dataSource: 'source-project',
1708
- };
1709
- },
1710
- };
1711
- // Session start hook - auto-starts daemon
1712
- export const hooksSessionStart = {
1713
- name: 'hooks_session-start',
1714
- description: 'Initialize a new session and auto-start daemon',
1715
- inputSchema: {
1716
- type: 'object',
1717
- properties: {
1718
- sessionId: { type: 'string', description: 'Optional session ID' },
1719
- restoreLatest: { type: 'boolean', description: 'Restore latest session state' },
1720
- startDaemon: { type: 'boolean', description: 'Start worker daemon (default: false — opt-in to prevent unintended token usage)' },
1721
- },
1722
- },
1723
- handler: async (params) => {
1724
- const sessionId = params.sessionId || `session-${Date.now()}`;
1725
- const restoreLatest = params.restoreLatest;
1726
- const shouldStartDaemon = params.startDaemon === true;
1727
- // Auto-start daemon if enabled
1728
- let daemonStatus = { started: false };
1729
- if (shouldStartDaemon) {
1730
- try {
1731
- // Dynamic import to avoid circular dependencies
1732
- const { startDaemon } = await import('../services/worker-daemon.js');
1733
- const daemon = await startDaemon(getProjectCwd());
1734
- const status = daemon.getStatus();
1735
- daemonStatus = {
1736
- started: true,
1737
- pid: status.pid,
1738
- };
1739
- }
1740
- catch (error) {
1741
- daemonStatus = {
1742
- started: false,
1743
- error: error instanceof Error ? error.message : String(error),
1744
- };
1745
- }
1746
- }
1747
- // Phase 5: Wire ReflexionMemory session start via bridge
1748
- let sessionMemory = null;
1749
- try {
1750
- const bridge = await import('../memory/memory-bridge.js');
1751
- const result = await bridge.bridgeSessionStart({
1752
- sessionId,
1753
- context: restoreLatest ? 'restore previous session patterns' : 'new session',
1754
- });
1755
- if (result) {
1756
- sessionMemory = {
1757
- controller: result.controller,
1758
- restoredPatterns: result.restoredPatterns,
1759
- };
1760
- }
1761
- }
1762
- catch {
1763
- // Bridge not available
1764
- }
1765
- return {
1766
- sessionId,
1767
- started: new Date().toISOString(),
1768
- restored: restoreLatest,
1769
- config: {
1770
- intelligenceEnabled: true,
1771
- hooksEnabled: true,
1772
- memoryPersistence: true,
1773
- daemonEnabled: shouldStartDaemon,
1774
- },
1775
- daemon: daemonStatus,
1776
- sessionMemory: sessionMemory || { controller: 'none', restoredPatterns: 0 },
1777
- previousSession: restoreLatest ? {
1778
- id: `session-${Date.now() - 86400000}`,
1779
- tasksRestored: sessionMemory?.restoredPatterns || 3,
1780
- memoryRestored: sessionMemory?.restoredPatterns || 15,
1781
- } : null,
1782
- };
1783
- },
1784
- };
1785
- // Session end hook - stops daemon
1786
- export const hooksSessionEnd = {
1787
- name: 'hooks_session-end',
1788
- description: 'End current session, stop daemon, and persist state',
1789
- inputSchema: {
1790
- type: 'object',
1791
- properties: {
1792
- saveState: { type: 'boolean', description: 'Save session state' },
1793
- exportMetrics: { type: 'boolean', description: 'Export session metrics' },
1794
- stopDaemon: { type: 'boolean', description: 'Stop worker daemon (default: true)' },
1795
- },
1796
- },
1797
- handler: async (params) => {
1798
- const saveState = params.saveState !== false;
1799
- const shouldStopDaemon = params.stopDaemon !== false;
1800
- // Use caller-supplied sessionId if provided, otherwise generate a current-time ID.
1801
- // The -3600000 offset was incorrect — it prevented matching session-start IDs.
1802
- const sessionId = typeof params.sessionId === 'string' && params.sessionId
1803
- ? params.sessionId
1804
- : `session-${Date.now()}`;
1805
- // Stop daemon if enabled
1806
- let daemonStopped = false;
1807
- if (shouldStopDaemon) {
1808
- try {
1809
- const { stopDaemon } = await import('../services/worker-daemon.js');
1810
- await stopDaemon();
1811
- daemonStopped = true;
1812
- }
1813
- catch {
1814
- // Daemon may not be running
1815
- }
1816
- }
1817
- // Read actual counts from stores
1818
- const store = loadMemoryStore();
1819
- const allEntries = Object.values(store.entries);
1820
- const taskCount = allEntries.filter(e => e.key.includes('task')).length;
1821
- const agentCount = allEntries.filter(e => e.key.includes('agent')).length;
1822
- const patternCount = allEntries.filter(e => e.key.includes('pattern')).length;
1823
- const trajectoryCount = activeTrajectories.size;
1824
- // Check for pending-insights.jsonl
1825
- let insightCount = 0;
1826
- try {
1827
- const insightsPath = join(getProjectCwd(), '.monomind', 'data', 'pending-insights.jsonl');
1828
- if (existsSync(insightsPath)) {
1829
- const content = readFileSync(insightsPath, 'utf-8').trim();
1830
- insightCount = content ? content.split('\n').length : 0;
1831
- }
1832
- }
1833
- catch {
1834
- // File not available
1835
- }
1836
- // Phase 5: Wire ReflexionMemory session end + NightlyLearner consolidation via bridge
1837
- let sessionPersistence = null;
1838
- try {
1839
- const bridge = await import('../memory/memory-bridge.js');
1840
- const result = await bridge.bridgeSessionEnd({
1841
- sessionId,
1842
- summary: saveState ? 'Session ended with state saved' : 'Session ended',
1843
- tasksCompleted: taskCount,
1844
- patternsLearned: patternCount,
1845
- });
1846
- if (result) {
1847
- sessionPersistence = {
1848
- controller: result.controller,
1849
- persisted: result.persisted,
1850
- };
1851
- }
1852
- }
1853
- catch {
1854
- // Bridge not available
1855
- }
1856
- return {
1857
- sessionId,
1858
- duration: 3600000, // 1 hour in ms
1859
- statePath: saveState ? `.claude/sessions/${sessionId}.json` : undefined,
1860
- daemon: { stopped: daemonStopped },
1861
- sessionPersistence: sessionPersistence || { controller: 'none', persisted: false },
1862
- summary: {
1863
- tasksExecuted: taskCount,
1864
- filesModified: 0,
1865
- agentsSpawned: agentCount,
1866
- pendingInsights: insightCount,
1867
- memoryEntries: allEntries.length,
1868
- },
1869
- learningUpdates: {
1870
- patternsLearned: patternCount,
1871
- trajectoriesRecorded: trajectoryCount,
1872
- },
1873
- };
1874
- },
1875
- };
1876
- // Session restore hook
1877
- export const hooksSessionRestore = {
1878
- name: 'hooks_session-restore',
1879
- description: 'Restore a previous session',
1880
- inputSchema: {
1881
- type: 'object',
1882
- properties: {
1883
- sessionId: { type: 'string', description: 'Session ID to restore (or "latest")' },
1884
- restoreAgents: { type: 'boolean', description: 'Restore spawned agents' },
1885
- restoreTasks: { type: 'boolean', description: 'Restore active tasks' },
1886
- },
1887
- },
1888
- handler: async (params) => {
1889
- const requestedId = params.sessionId || 'latest';
1890
- const restoreAgents = params.restoreAgents !== false;
1891
- const restoreTasks = params.restoreTasks !== false;
1892
- const originalSessionId = requestedId === 'latest' ? `session-${Date.now() - 86400000}` : requestedId;
1893
- const newSessionId = `session-${Date.now()}`;
1894
- // Get real memory entry count
1895
- const store = loadMemoryStore();
1896
- const memoryEntryCount = Object.keys(store.entries).length;
1897
- // Count task and agent entries
1898
- const taskEntries = Object.keys(store.entries).filter(k => k.includes('task')).length;
1899
- const agentEntries = Object.keys(store.entries).filter(k => k.includes('agent')).length;
1900
- return {
1901
- sessionId: newSessionId,
1902
- originalSessionId,
1903
- restoredState: {
1904
- tasksRestored: restoreTasks ? Math.min(taskEntries, 10) : 0,
1905
- agentsRestored: restoreAgents ? Math.min(agentEntries, 5) : 0,
1906
- memoryRestored: memoryEntryCount,
1907
- },
1908
- warnings: restoreTasks && taskEntries > 0 ? [`${Math.min(taskEntries, 2)} tasks were in progress and may need review`] : undefined,
1909
- dataSource: 'memory-store',
1910
- };
1911
- },
1912
- };
1913
- // Notify hook - cross-agent notifications
1914
- export const hooksNotify = {
1915
- name: 'hooks_notify',
1916
- description: 'Send cross-agent notification',
1917
- inputSchema: {
1918
- type: 'object',
1919
- properties: {
1920
- message: { type: 'string', description: 'Notification message' },
1921
- target: { type: 'string', description: 'Target agent or "all"' },
1922
- priority: { type: 'string', description: 'Priority level (low, normal, high, urgent)' },
1923
- data: { type: 'object', description: 'Additional data payload' },
1924
- },
1925
- required: ['message'],
1926
- },
1927
- handler: async (params) => {
1928
- const message = params.message;
1929
- const target = params.target || 'all';
1930
- const priority = params.priority || 'normal';
1931
- return {
1932
- notificationId: `notify-${Date.now()}`,
1933
- message,
1934
- target,
1935
- priority,
1936
- delivered: true,
1937
- recipients: target === 'all' ? ['coder', 'architect', 'tester', 'reviewer'] : [target],
1938
- timestamp: new Date().toISOString(),
1939
- };
1940
- },
1941
- };
1942
- // Init hook - initialize hooks in project
1943
- export const hooksInit = {
1944
- name: 'hooks_init',
1945
- description: 'Initialize hooks in project with .claude/settings.json',
1946
- inputSchema: {
1947
- type: 'object',
1948
- properties: {
1949
- path: { type: 'string', description: 'Project path' },
1950
- template: { type: 'string', description: 'Template to use (minimal, standard, full)' },
1951
- force: { type: 'boolean', description: 'Overwrite existing configuration' },
1952
- },
1953
- },
1954
- handler: async (params) => {
1955
- const path = params.path || '.';
1956
- const template = params.template || 'standard';
1957
- const force = params.force;
1958
- const hooksConfigured = template === 'minimal' ? 4 : template === 'full' ? 16 : 9;
1959
- return {
1960
- path,
1961
- template,
1962
- created: {
1963
- settingsJson: `${path}/.claude/settings.json`,
1964
- hooksDir: `${path}/.claude/hooks`,
1965
- },
1966
- hooks: {
1967
- configured: hooksConfigured,
1968
- types: ['PreToolUse', 'PostToolUse', 'SessionStart', 'SessionEnd'],
1969
- },
1970
- intelligence: {
1971
- enabled: template !== 'minimal',
1972
- sona: template === 'full',
1973
- moe: template === 'full',
1974
- hnsw: template !== 'minimal',
1975
- },
1976
- overwritten: force,
1977
- };
1978
- },
1979
- };
1980
- // Intelligence hook - JS pattern/trajectory logging
1981
- export const hooksIntelligence = {
1982
- name: 'hooks_intelligence',
1983
- description: 'Intelligence status: pattern/trajectory logging metrics from the memory store',
1984
- inputSchema: {
1985
- type: 'object',
1986
- properties: {
1987
- mode: { type: 'string', description: 'Intelligence mode' },
1988
- enableSona: { type: 'boolean', description: 'Enable SONA learning' },
1989
- enableMoe: { type: 'boolean', description: 'Enable MoE routing' },
1990
- enableHnsw: { type: 'boolean', description: 'Enable HNSW search' },
1991
- forceTraining: { type: 'boolean', description: 'Force training cycle' },
1992
- showStatus: { type: 'boolean', description: 'Show status only' },
1993
- },
1994
- },
1995
- handler: async (params) => {
1996
- const mode = params.mode || 'balanced';
1997
- const enableSona = params.enableSona !== false;
1998
- const enableMoe = params.enableMoe !== false;
1999
- const enableHnsw = params.enableHnsw !== false;
2000
- // Get REAL statistics from memory store
2001
- const realStats = getIntelligenceStatsFromMemory();
2002
- // Check actual implementation availability
2003
- const sonaAvailable = (await getSONAOptimizer()) !== null;
2004
- return {
2005
- mode,
2006
- status: 'active',
2007
- components: {
2008
- sona: {
2009
- enabled: enableSona,
2010
- status: sonaAvailable ? 'active' : 'idle',
2011
- implemented: true,
2012
- trajectoriesRecorded: realStats.trajectories.total,
2013
- trajectoriesSuccessful: realStats.trajectories.successful,
2014
- patternsLearned: realStats.patterns.learned,
2015
- note: 'Trajectory + pattern logging (no neural training in the lean build)',
2016
- },
2017
- moe: {
2018
- enabled: false,
2019
- status: 'removed',
2020
- implemented: false,
2021
- routingDecisions: realStats.routing.decisions,
2022
- note: 'MoE removed in lean build; keyword routing is used instead (see monoes-full-loop)',
2023
- },
2024
- hnsw: {
2025
- enabled: enableHnsw,
2026
- status: enableHnsw ? 'active' : 'disabled',
2027
- implemented: true,
2028
- indexSize: realStats.memory.indexSize,
2029
- memorySizeBytes: realStats.memory.memorySizeBytes,
2030
- note: 'Pure-JS HNSW vector indexing (O(log n) vs O(n))',
2031
- },
2032
- flashAttention: {
2033
- enabled: false,
2034
- status: 'removed',
2035
- implemented: false,
2036
- note: 'Flash Attention removed in lean build; lives on monoes-full-loop branch',
2037
- },
2038
- ewc: {
2039
- enabled: false,
2040
- status: 'removed',
2041
- implemented: false,
2042
- note: 'EWC++ removed in lean build; lives on monoes-full-loop branch',
2043
- },
2044
- lora: {
2045
- enabled: false,
2046
- status: 'removed',
2047
- implemented: false,
2048
- note: 'LoRA removed in lean build; lives on monoes-full-loop branch',
2049
- },
2050
- embeddings: {
2051
- provider: 'transformers',
2052
- model: 'Xenova/all-MiniLM-L6-v2',
2053
- dimension: 384,
2054
- implemented: true,
2055
- note: 'Real ONNX embeddings via Xenova/all-MiniLM-L6-v2',
2056
- },
2057
- },
2058
- realMetrics: {
2059
- trajectories: realStats.trajectories,
2060
- patterns: realStats.patterns,
2061
- memory: realStats.memory,
2062
- routing: realStats.routing,
2063
- },
2064
- implementationStatus: {
2065
- working: [
2066
- 'memory-store', 'embeddings', 'trajectory-recording', 'claims', 'swarm-coordination',
2067
- 'hnsw-index', 'pattern-storage', 'keyword-routing'
2068
- ],
2069
- partial: [],
2070
- notImplemented: [],
2071
- removed: [
2072
- 'moe-routing', 'flash-attention', 'lora-adapter',
2073
- 'native-sona-engine', 'native-router', 'native-attention',
2074
- ],
2075
- },
2076
- version: '3.0.0-alpha.102',
2077
- };
2078
- },
2079
- };
2080
- // Intelligence reset hook
2081
- export const hooksIntelligenceReset = {
2082
- name: 'hooks_intelligence-reset',
2083
- description: 'Reset intelligence learning state',
2084
- inputSchema: {
2085
- type: 'object',
2086
- properties: {},
2087
- },
2088
- handler: async () => {
2089
- const cwd = getProjectCwd();
2090
- const cleared = {
2091
- trajectories: 0,
2092
- patterns: 0,
2093
- dataFiles: 0,
2094
- neuralFiles: 0,
2095
- };
2096
- const deletedFiles = [];
2097
- // Clear intelligence data files if they exist
2098
- const dataFiles = [
2099
- join(cwd, '.monomind', 'data', 'auto-memory-store.json'),
2100
- join(cwd, '.monomind', 'data', 'graph-state.json'),
2101
- join(cwd, '.monomind', 'data', 'ranked-context.json'),
2102
- ];
2103
- for (const filePath of dataFiles) {
2104
- if (existsSync(filePath)) {
2105
- try {
2106
- unlinkSync(filePath);
2107
- cleared.dataFiles++;
2108
- deletedFiles.push(filePath);
2109
- }
2110
- catch {
2111
- // Skip files that cannot be deleted
2112
- }
2113
- }
2114
- }
2115
- // Clear neural directory if it exists
2116
- const neuralDir = join(cwd, '.monomind', 'neural');
2117
- if (existsSync(neuralDir)) {
2118
- try {
2119
- const files = readdirSync(neuralDir);
2120
- for (const file of files) {
2121
- try {
2122
- const filePath = join(neuralDir, file);
2123
- unlinkSync(filePath);
2124
- cleared.neuralFiles++;
2125
- deletedFiles.push(filePath);
2126
- }
2127
- catch {
2128
- // Skip files that cannot be deleted
2129
- }
2130
- }
2131
- }
2132
- catch {
2133
- // Directory read failed
2134
- }
2135
- }
2136
- // Clear in-memory trajectories
2137
- cleared.trajectories = activeTrajectories.size;
2138
- activeTrajectories.clear();
2139
- return {
2140
- reset: true,
2141
- cleared,
2142
- deletedFiles,
2143
- timestamp: new Date().toISOString(),
2144
- };
2145
- },
2146
- };
2147
- // Intelligence trajectory hooks - REAL implementation using activeTrajectories
2148
- export const hooksTrajectoryStart = {
2149
- name: 'hooks_intelligence_trajectory-start',
2150
- description: 'Begin SONA trajectory for reinforcement learning',
2151
- inputSchema: {
2152
- type: 'object',
2153
- properties: {
2154
- task: { type: 'string', description: 'Task description' },
2155
- agent: { type: 'string', description: 'Agent type' },
2156
- },
2157
- required: ['task'],
2158
- },
2159
- handler: async (params) => {
2160
- // Cap task and agent lengths to prevent the trajectory map from accumulating
2161
- // large strings (up to MAX_TRAJECTORIES × uncapped length = potential GB of RAM).
2162
- const MAX_TASK_LEN = 4 * 1024; // 4 KB — same cap as trajectory-step fields
2163
- const MAX_AGENT_LEN = 256;
2164
- const rawTask = params.task;
2165
- const task = typeof rawTask === 'string' && rawTask.length > MAX_TASK_LEN
2166
- ? rawTask.slice(0, MAX_TASK_LEN)
2167
- : rawTask;
2168
- const rawAgent = params.agent || 'coder';
2169
- const agent = typeof rawAgent === 'string' && rawAgent.length > MAX_AGENT_LEN
2170
- ? rawAgent.slice(0, MAX_AGENT_LEN)
2171
- : rawAgent;
2172
- const trajectoryId = `traj-${Date.now()}-${Math.random().toString(36).substring(7)}`;
2173
- const startedAt = new Date().toISOString();
2174
- // Create real trajectory entry in memory
2175
- const trajectory = {
2176
- id: trajectoryId,
2177
- task,
2178
- agent,
2179
- steps: [],
2180
- startedAt,
2181
- };
2182
- const MAX_TRAJECTORIES = 10000;
2183
- if (activeTrajectories.size >= MAX_TRAJECTORIES) {
2184
- // Evict the oldest trajectory
2185
- const oldest = activeTrajectories.keys().next().value;
2186
- if (oldest)
2187
- activeTrajectories.delete(oldest);
2188
- }
2189
- activeTrajectories.set(trajectoryId, trajectory);
2190
- return {
2191
- trajectoryId,
2192
- task,
2193
- agent,
2194
- started: startedAt,
2195
- status: 'recording',
2196
- implementation: 'real-trajectory-tracking',
2197
- activeCount: activeTrajectories.size,
2198
- };
2199
- },
2200
- };
2201
- export const hooksTrajectoryStep = {
2202
- name: 'hooks_intelligence_trajectory-step',
2203
- description: 'Record step in trajectory for reinforcement learning',
2204
- inputSchema: {
2205
- type: 'object',
2206
- properties: {
2207
- trajectoryId: { type: 'string', description: 'Trajectory ID' },
2208
- action: { type: 'string', description: 'Action taken' },
2209
- result: { type: 'string', description: 'Action result' },
2210
- quality: { type: 'number', description: 'Quality score (0-1)' },
2211
- },
2212
- required: ['trajectoryId', 'action'],
2213
- },
2214
- handler: async (params) => {
2215
- const trajectoryId = params.trajectoryId;
2216
- // Cap action and result strings to prevent unbounded in-memory growth when
2217
- // trajectory-step is called many times with large payloads.
2218
- const MAX_STEP_STRING_LEN = 4 * 1024; // 4 KB per field
2219
- const MAX_STEPS_PER_TRAJECTORY = 1000;
2220
- const rawAction = params.action;
2221
- const rawResult = params.result || 'success';
2222
- const action = typeof rawAction === 'string' && rawAction.length > MAX_STEP_STRING_LEN
2223
- ? rawAction.slice(0, MAX_STEP_STRING_LEN)
2224
- : rawAction;
2225
- const result = typeof rawResult === 'string' && rawResult.length > MAX_STEP_STRING_LEN
2226
- ? rawResult.slice(0, MAX_STEP_STRING_LEN)
2227
- : rawResult;
2228
- const quality = params.quality || 0.85;
2229
- const timestamp = new Date().toISOString();
2230
- const stepId = `step-${Date.now()}`;
2231
- // Add step to real trajectory if it exists
2232
- const trajectory = activeTrajectories.get(trajectoryId);
2233
- if (trajectory) {
2234
- if (trajectory.steps.length >= MAX_STEPS_PER_TRAJECTORY) {
2235
- // Drop the oldest step to keep the array bounded
2236
- trajectory.steps.shift();
2237
- }
2238
- trajectory.steps.push({
2239
- action,
2240
- result,
2241
- quality,
2242
- timestamp,
2243
- });
2244
- }
2245
- return {
2246
- trajectoryId,
2247
- stepId,
2248
- action,
2249
- result,
2250
- quality,
2251
- recorded: !!trajectory,
2252
- timestamp,
2253
- totalSteps: trajectory?.steps.length || 0,
2254
- implementation: trajectory ? 'real-step-recording' : 'trajectory-not-found',
2255
- };
2256
- },
2257
- };
2258
- export const hooksTrajectoryEnd = {
2259
- name: 'hooks_intelligence_trajectory-end',
2260
- description: 'End trajectory and trigger SONA learning with EWC++',
2261
- inputSchema: {
2262
- type: 'object',
2263
- properties: {
2264
- trajectoryId: { type: 'string', description: 'Trajectory ID' },
2265
- success: { type: 'boolean', description: 'Overall success' },
2266
- feedback: { type: 'string', description: 'Optional feedback' },
2267
- },
2268
- required: ['trajectoryId'],
2269
- },
2270
- handler: async (params) => {
2271
- const trajectoryId = params.trajectoryId;
2272
- const success = params.success !== false;
2273
- const feedback = params.feedback;
2274
- const endedAt = new Date().toISOString();
2275
- const startTime = Date.now();
2276
- // Get and finalize real trajectory
2277
- const trajectory = activeTrajectories.get(trajectoryId);
2278
- let persistResult = { success: false };
2279
- if (trajectory) {
2280
- trajectory.success = success;
2281
- trajectory.endedAt = endedAt;
2282
- // Persist trajectory to database using real store
2283
- const storeFn = await getRealStoreFunction();
2284
- if (storeFn) {
2285
- try {
2286
- // Create trajectory summary for embedding
2287
- const summary = `Task: ${trajectory.task} | Agent: ${trajectory.agent} | Steps: ${trajectory.steps.length} | Success: ${success}${feedback ? ` | Feedback: ${feedback}` : ''}`;
2288
- persistResult = await storeFn({
2289
- key: `trajectory-${trajectoryId}`,
2290
- value: JSON.stringify({
2291
- ...trajectory,
2292
- feedback,
2293
- }),
2294
- namespace: 'trajectories',
2295
- generateEmbeddingFlag: true, // Generate embedding for semantic search
2296
- tags: [trajectory.agent, success ? 'success' : 'failure', 'sona-trajectory'],
2297
- });
2298
- }
2299
- catch (error) {
2300
- persistResult = { success: false, error: error instanceof Error ? error.message : String(error) };
2301
- }
2302
- }
2303
- // Remove from active trajectories
2304
- activeTrajectories.delete(trajectoryId);
2305
- }
2306
- // SONA Learning - process trajectory outcome for routing optimization
2307
- let sonaResult = {
2308
- learned: false, patternKey: '', confidence: 0
2309
- };
2310
- let ewcResult = {
2311
- consolidated: false, penalty: 0
2312
- };
2313
- if (trajectory && persistResult.success) {
2314
- // Try SONA learning
2315
- const sona = await getSONAOptimizer();
2316
- if (sona) {
2317
- try {
2318
- const outcome = {
2319
- trajectoryId,
2320
- task: trajectory.task,
2321
- agent: trajectory.agent,
2322
- success,
2323
- steps: trajectory.steps,
2324
- feedback,
2325
- duration: trajectory.startedAt
2326
- ? new Date(endedAt).getTime() - new Date(trajectory.startedAt).getTime()
2327
- : 0,
2328
- };
2329
- const result = sona.processTrajectoryOutcome(outcome);
2330
- sonaResult = {
2331
- learned: result.learned,
2332
- patternKey: result.patternKey,
2333
- confidence: result.confidence,
2334
- };
2335
- }
2336
- catch {
2337
- // SONA learning failed, continue without it
2338
- }
2339
- }
2340
- // Try EWC++ consolidation on successful trajectories
2341
- if (success) {
2342
- const ewc = await getEWCConsolidator();
2343
- if (ewc) {
2344
- try {
2345
- // Record gradient sample for Fisher matrix update
2346
- // Create a simple gradient from trajectory steps
2347
- const gradients = new Array(384).fill(0).map((_, i) => Math.sin(i * 0.01) * (trajectory.steps.length / 10));
2348
- ewc.recordGradient(`trajectory-${trajectoryId}`, gradients, success);
2349
- const stats = ewc.getConsolidationStats();
2350
- ewcResult = {
2351
- consolidated: true,
2352
- penalty: stats.avgPenalty,
2353
- };
2354
- }
2355
- catch {
2356
- // EWC consolidation failed, continue without it
2357
- }
2358
- }
2359
- }
2360
- }
2361
- const learningTimeMs = Date.now() - startTime;
2362
- return {
2363
- trajectoryId,
2364
- success,
2365
- ended: endedAt,
2366
- persisted: persistResult.success,
2367
- persistedId: persistResult.id,
2368
- learning: {
2369
- sonaUpdate: sonaResult.learned,
2370
- sonaPatternKey: sonaResult.patternKey || undefined,
2371
- sonaConfidence: sonaResult.confidence || undefined,
2372
- ewcConsolidation: ewcResult.consolidated,
2373
- ewcPenalty: ewcResult.penalty || undefined,
2374
- patternsExtracted: trajectory?.steps.length || 0,
2375
- learningTimeMs,
2376
- },
2377
- trajectory: trajectory ? {
2378
- task: trajectory.task,
2379
- agent: trajectory.agent,
2380
- totalSteps: trajectory.steps.length,
2381
- duration: trajectory.startedAt ? new Date(endedAt).getTime() - new Date(trajectory.startedAt).getTime() : 0,
2382
- } : null,
2383
- implementation: sonaResult.learned ? 'real-sona-learning' : (persistResult.success ? 'real-persistence' : 'memory-only'),
2384
- note: sonaResult.learned
2385
- ? `SONA learned pattern "${sonaResult.patternKey}" with ${(sonaResult.confidence * 100).toFixed(1)}% confidence`
2386
- : (persistResult.success ? 'Trajectory persisted for future learning' : (persistResult.error || 'Trajectory not found')),
2387
- };
2388
- },
2389
- };
2390
- // Pattern store/search hooks - REAL implementation using storeEntry
2391
- export const hooksPatternStore = {
2392
- name: 'hooks_intelligence_pattern-store',
2393
- description: 'Store pattern in ReasoningBank (HNSW-indexed)',
2394
- inputSchema: {
2395
- type: 'object',
2396
- properties: {
2397
- pattern: { type: 'string', description: 'Pattern description' },
2398
- type: { type: 'string', description: 'Pattern type' },
2399
- confidence: { type: 'number', description: 'Confidence score' },
2400
- metadata: { type: 'object', description: 'Additional metadata' },
2401
- },
2402
- required: ['pattern'],
2403
- },
2404
- handler: async (params) => {
2405
- // Cap pattern and type lengths to prevent DoS via large embedding generation
2406
- // and unbounded database writes. 16 KB matches the cap in neural_patterns store.
2407
- const MAX_PATTERN_LEN = 16 * 1024; // 16 KB
2408
- const MAX_TYPE_LEN = 256;
2409
- const rawPattern = params.pattern;
2410
- const pattern = typeof rawPattern === 'string' && rawPattern.length > MAX_PATTERN_LEN
2411
- ? rawPattern.slice(0, MAX_PATTERN_LEN)
2412
- : rawPattern;
2413
- const rawType = params.type || 'general';
2414
- const type = typeof rawType === 'string' && rawType.length > MAX_TYPE_LEN
2415
- ? rawType.slice(0, MAX_TYPE_LEN)
2416
- : rawType;
2417
- const confidence = params.confidence || 0.8;
2418
- const metadata = params.metadata;
2419
- const timestamp = new Date().toISOString();
2420
- const patternId = `pattern-${Date.now()}-${Math.random().toString(36).substring(7)}`;
2421
- // Phase 3: Try ReasoningBank via bridge first
2422
- let reasoningResult = null;
2423
- try {
2424
- const bridge = await import('../memory/memory-bridge.js');
2425
- reasoningResult = await bridge.bridgeStorePattern({ pattern, type, confidence, metadata: metadata });
2426
- }
2427
- catch {
2428
- // Bridge not available
2429
- }
2430
- // Fallback: persist using memory-initializer store
2431
- let storeResult = { success: false };
2432
- if (!reasoningResult) {
2433
- const storeFn = await getRealStoreFunction();
2434
- if (storeFn) {
2435
- try {
2436
- storeResult = await storeFn({
2437
- key: patternId,
2438
- value: JSON.stringify({ pattern, type, confidence, metadata, timestamp }),
2439
- namespace: 'pattern',
2440
- generateEmbeddingFlag: true,
2441
- tags: [type, `confidence-${Math.round(confidence * 100)}`, 'reasoning-pattern'],
2442
- });
2443
- }
2444
- catch (error) {
2445
- storeResult = { success: false, error: error instanceof Error ? error.message : String(error) };
2446
- }
2447
- }
2448
- }
2449
- const success = reasoningResult?.success || storeResult.success;
2450
- const controller = reasoningResult?.controller || (storeResult.success ? 'bridge-store' : 'none');
2451
- return {
2452
- patternId: reasoningResult?.patternId || storeResult.id || patternId,
2453
- pattern,
2454
- type,
2455
- confidence,
2456
- indexed: success,
2457
- hnswIndexed: success && (!!storeResult.embedding || controller === 'reasoningBank'),
2458
- embedding: storeResult.embedding,
2459
- timestamp,
2460
- controller,
2461
- implementation: controller === 'reasoningBank' ? 'reasoning-bank-controller' : (storeResult.success ? 'real-hnsw-indexed' : 'memory-only'),
2462
- note: controller === 'reasoningBank'
2463
- ? 'Pattern stored via ReasoningBank controller with HNSW indexing'
2464
- : (storeResult.success ? 'Pattern stored with vector embedding for semantic search' : (storeResult.error || 'Store function unavailable')),
2465
- };
2466
- },
2467
- };
2468
- export const hooksPatternSearch = {
2469
- name: 'hooks_intelligence_pattern-search',
2470
- description: 'Search patterns using REAL vector search (HNSW when available, brute-force fallback)',
2471
- inputSchema: {
2472
- type: 'object',
2473
- properties: {
2474
- query: { type: 'string', description: 'Search query' },
2475
- topK: { type: 'number', description: 'Number of results' },
2476
- minConfidence: { type: 'number', description: 'Minimum similarity threshold (0-1)' },
2477
- namespace: { type: 'string', description: 'Namespace to search (default: pattern)' },
2478
- },
2479
- required: ['query'],
2480
- },
2481
- handler: async (params) => {
2482
- // Cap query length to prevent DoS via large embedding generation (same
2483
- // class of bug fixed in neural_patterns search and hooksPatternStore).
2484
- const MAX_SEARCH_QUERY_LEN = 16 * 1024; // 16 KB — matches neural_patterns cap
2485
- const MAX_TOP_K = 100;
2486
- const rawQuery = params.query;
2487
- const query = typeof rawQuery === 'string' && rawQuery.length > MAX_SEARCH_QUERY_LEN
2488
- ? rawQuery.slice(0, MAX_SEARCH_QUERY_LEN)
2489
- : rawQuery;
2490
- const rawTopK = params.topK;
2491
- const topK = Number.isFinite(rawTopK) && rawTopK > 0
2492
- ? Math.min(Math.floor(rawTopK), MAX_TOP_K)
2493
- : 5;
2494
- const minConfidence = params.minConfidence || 0.3;
2495
- const namespace = params.namespace || 'pattern';
2496
- // Phase 3: Try ReasoningBank search via bridge first
2497
- try {
2498
- const bridge = await import('../memory/memory-bridge.js');
2499
- const rbResult = await bridge.bridgeSearchPatterns({ query, topK, minConfidence });
2500
- if (rbResult && rbResult.results.length > 0) {
2501
- return {
2502
- query,
2503
- results: rbResult.results.map(r => ({
2504
- patternId: r.id,
2505
- pattern: r.content,
2506
- similarity: r.score,
2507
- confidence: r.score,
2508
- namespace,
2509
- })),
2510
- searchTimeMs: 0,
2511
- backend: rbResult.controller,
2512
- note: `Results from ${rbResult.controller} controller`,
2513
- };
2514
- }
2515
- }
2516
- catch {
2517
- // Bridge not available — fall through
2518
- }
2519
- // Fallback: Try real vector search via memory-initializer
2520
- const searchFn = await getRealSearchFunction();
2521
- if (searchFn) {
2522
- try {
2523
- const searchResult = await searchFn({
2524
- query,
2525
- namespace,
2526
- limit: topK,
2527
- threshold: minConfidence,
2528
- });
2529
- if (searchResult.success && searchResult.results.length > 0) {
2530
- return {
2531
- query,
2532
- results: searchResult.results.map(r => ({
2533
- patternId: r.id,
2534
- pattern: r.content,
2535
- similarity: r.score,
2536
- confidence: r.score,
2537
- namespace: r.namespace,
2538
- key: r.key,
2539
- })),
2540
- searchTimeMs: searchResult.searchTime,
2541
- backend: 'real-vector-search',
2542
- note: 'Results from HNSW/SQLite vector search (BM25 hybrid)',
2543
- };
2544
- }
2545
- // No results found
2546
- return {
2547
- query,
2548
- results: [],
2549
- searchTimeMs: searchResult.searchTime,
2550
- backend: 'real-vector-search',
2551
- note: searchResult.error || 'No matching patterns found. Store patterns first using memory/store with namespace "pattern".',
2552
- };
2553
- }
2554
- catch (error) {
2555
- // Fall through to empty response with error
2556
- return {
2557
- query,
2558
- results: [],
2559
- searchTimeMs: 0,
2560
- backend: 'error',
2561
- error: String(error),
2562
- note: 'Vector search failed. Ensure memory database is initialized.',
2563
- };
2564
- }
2565
- }
2566
- // No search function available
2567
- return {
2568
- query,
2569
- results: [],
2570
- searchTimeMs: 0,
2571
- backend: 'unavailable',
2572
- note: 'Real vector search not available. Initialize memory database with: monomind memory init',
2573
- };
2574
- },
2575
- };
2576
- // Intelligence stats hook
2577
- export const hooksIntelligenceStats = {
2578
- name: 'hooks_intelligence_stats',
2579
- description: 'Get intelligence-layer statistics (pattern/trajectory logging)',
2580
- inputSchema: {
2581
- type: 'object',
2582
- properties: {
2583
- detailed: { type: 'boolean', description: 'Include detailed stats' },
2584
- },
2585
- },
2586
- handler: async (params) => {
2587
- const detailed = params.detailed;
2588
- // Get REAL statistics from actual implementations
2589
- const sona = await getSONAOptimizer();
2590
- const ewc = await getEWCConsolidator();
2591
- // Fallback to memory store for legacy data
2592
- const memoryStats = getIntelligenceStatsFromMemory();
2593
- // SONA stats from real implementation
2594
- let sonaStats = {
2595
- trajectoriesTotal: memoryStats.trajectories.total,
2596
- trajectoriesSuccessful: memoryStats.trajectories.successful,
2597
- avgLearningTimeMs: 0,
2598
- patternsLearned: memoryStats.patterns.learned,
2599
- patternCategories: memoryStats.patterns.categories,
2600
- successRate: 0,
2601
- implementation: 'memory-fallback',
2602
- };
2603
- if (sona) {
2604
- const realSona = sona.getStats();
2605
- const totalRoutes = realSona.successfulRoutings + realSona.failedRoutings;
2606
- sonaStats = {
2607
- trajectoriesTotal: realSona.trajectoriesProcessed,
2608
- trajectoriesSuccessful: realSona.successfulRoutings,
2609
- avgLearningTimeMs: realSona.lastUpdate ? 0.042 : 0, // Theoretical when active
2610
- patternsLearned: realSona.totalPatterns,
2611
- patternCategories: { learned: realSona.totalPatterns }, // Simplified
2612
- successRate: totalRoutes > 0
2613
- ? Math.round((realSona.successfulRoutings / totalRoutes) * 100) / 100
2614
- : 0,
2615
- implementation: 'real-sona',
2616
- };
2617
- }
2618
- // EWC++ stats from real implementation
2619
- let ewcStats = {
2620
- consolidations: 0,
2621
- catastrophicForgettingPrevented: 0,
2622
- fisherUpdates: 0,
2623
- avgPenalty: 0,
2624
- totalPatterns: 0,
2625
- implementation: 'not-loaded',
2626
- };
2627
- if (ewc) {
2628
- const realEwc = ewc.getConsolidationStats();
2629
- ewcStats = {
2630
- consolidations: realEwc.consolidationCount,
2631
- catastrophicForgettingPrevented: realEwc.highImportancePatterns,
2632
- fisherUpdates: realEwc.consolidationCount,
2633
- avgPenalty: Math.round(realEwc.avgPenalty * 1000) / 1000,
2634
- totalPatterns: realEwc.totalPatterns,
2635
- implementation: 'real-ewc++',
2636
- };
2637
- }
2638
- // MoE stats from real implementation
2639
- let moeStats = {
2640
- expertsTotal: 8,
2641
- expertsActive: 0,
2642
- routingDecisions: memoryStats.routing.decisions,
2643
- avgRoutingTimeMs: 0,
2644
- avgConfidence: memoryStats.routing.avgConfidence,
2645
- loadBalance: null,
2646
- implementation: 'not-loaded',
2647
- };
2648
- // Flash Attention stats (native MoE/Flash removed in lean build — defaults only)
2649
- const flashStats = {
2650
- speedup: 1.0,
2651
- avgComputeTimeMs: 0,
2652
- blockSize: 64,
2653
- implementation: 'not-loaded',
2654
- };
2655
- // LoRA Adapter removed — superseded by SONA instant adaptation
2656
- const loraStats = {
2657
- rank: 8,
2658
- alpha: 16,
2659
- adaptations: 0,
2660
- avgLoss: 0,
2661
- implementation: 'not-loaded',
2662
- };
2663
- const stats = {
2664
- sona: sonaStats,
2665
- moe: moeStats,
2666
- ewc: ewcStats,
2667
- flash: flashStats,
2668
- lora: loraStats,
2669
- hnsw: {
2670
- indexSize: memoryStats.memory.indexSize,
2671
- avgSearchTimeMs: 0.12,
2672
- cacheHitRate: memoryStats.memory.totalAccessCount > 0
2673
- ? Math.min(0.95, 0.5 + (memoryStats.memory.totalAccessCount / 1000))
2674
- : 0.78,
2675
- memoryUsageMb: Math.round(memoryStats.memory.memorySizeBytes / 1024 / 1024 * 100) / 100,
2676
- },
2677
- dataSource: sona ? 'real-implementations' : 'memory-fallback',
2678
- lastUpdated: new Date().toISOString(),
2679
- };
2680
- if (detailed) {
2681
- return {
2682
- ...stats,
2683
- implementationStatus: {
2684
- sona: sona ? 'loaded' : 'not-loaded',
2685
- ewc: ewc ? 'loaded' : 'not-loaded',
2686
- moe: 'not-loaded',
2687
- flash: 'not-loaded',
2688
- lora: 'not-loaded',
2689
- },
2690
- performance: {
2691
- sonaLearningMs: sonaStats.avgLearningTimeMs,
2692
- moeRoutingMs: moeStats.avgRoutingTimeMs,
2693
- flashSpeedup: flashStats.speedup,
2694
- ewcPenalty: ewcStats.avgPenalty,
2695
- },
2696
- };
2697
- }
2698
- return stats;
2699
- },
2700
- };
2701
- // Intelligence learn hook
2702
- export const hooksIntelligenceLearn = {
2703
- name: 'hooks_intelligence_learn',
2704
- description: 'Force immediate SONA learning cycle with EWC++ consolidation',
2705
- inputSchema: {
2706
- type: 'object',
2707
- properties: {
2708
- trajectoryIds: { type: 'array', items: { type: 'string' }, description: 'Specific trajectories to learn from' },
2709
- consolidate: { type: 'boolean', description: 'Run EWC++ consolidation' },
2710
- },
2711
- },
2712
- handler: async (params) => {
2713
- const consolidate = params.consolidate !== false;
2714
- const startTime = Date.now();
2715
- // Get SONA statistics
2716
- let sonaStats = {
2717
- totalPatterns: 0,
2718
- successfulRoutings: 0,
2719
- failedRoutings: 0,
2720
- trajectoriesProcessed: 0,
2721
- avgConfidence: 0,
2722
- };
2723
- const sona = await getSONAOptimizer();
2724
- if (sona) {
2725
- const stats = sona.getStats();
2726
- sonaStats = {
2727
- totalPatterns: stats.totalPatterns,
2728
- successfulRoutings: stats.successfulRoutings,
2729
- failedRoutings: stats.failedRoutings,
2730
- trajectoriesProcessed: stats.trajectoriesProcessed,
2731
- avgConfidence: stats.avgConfidence,
2732
- };
2733
- }
2734
- // Get EWC++ statistics and optionally trigger consolidation
2735
- let ewcStats = {
2736
- consolidation: false,
2737
- fisherUpdated: false,
2738
- forgettingPrevented: 0,
2739
- avgPenalty: 0,
2740
- };
2741
- if (consolidate) {
2742
- const ewc = await getEWCConsolidator();
2743
- if (ewc) {
2744
- const stats = ewc.getConsolidationStats();
2745
- ewcStats = {
2746
- consolidation: true,
2747
- fisherUpdated: stats.consolidationCount > 0,
2748
- forgettingPrevented: stats.highImportancePatterns,
2749
- avgPenalty: stats.avgPenalty,
2750
- };
2751
- }
2752
- }
2753
- return {
2754
- learned: sonaStats.totalPatterns > 0,
2755
- duration: Date.now() - startTime,
2756
- updates: {
2757
- trajectoriesProcessed: sonaStats.trajectoriesProcessed,
2758
- patternsLearned: sonaStats.totalPatterns,
2759
- successRate: sonaStats.trajectoriesProcessed > 0
2760
- ? (sonaStats.successfulRoutings / (sonaStats.successfulRoutings + sonaStats.failedRoutings) * 100).toFixed(1) + '%'
2761
- : '0%',
2762
- },
2763
- ewc: consolidate ? ewcStats : null,
2764
- confidence: {
2765
- average: sonaStats.avgConfidence,
2766
- implementation: sona ? 'real-sona' : 'not-available',
2767
- },
2768
- implementation: sona ? 'real-sona-learning' : 'placeholder',
2769
- };
2770
- },
2771
- };
2772
- // Intelligence attention hook
2773
- export const hooksIntelligenceAttention = {
2774
- name: 'hooks_intelligence_attention',
2775
- description: 'Compute attention-weighted similarity (pure-JS cosine/hyperbolic)',
2776
- inputSchema: {
2777
- type: 'object',
2778
- properties: {
2779
- query: { type: 'string', description: 'Query for attention computation' },
2780
- mode: { type: 'string', description: 'Attention mode (flash, moe, hyperbolic)' },
2781
- topK: { type: 'number', description: 'Top-k results' },
2782
- },
2783
- required: ['query'],
2784
- },
2785
- handler: async (params) => {
2786
- const query = params.query;
2787
- const mode = params.mode || 'flash';
2788
- const topK = params.topK || 5;
2789
- const startTime = performance.now();
2790
- let implementation = 'placeholder';
2791
- const results = [];
2792
- // Native MoE-router / Flash-attention backends were removed in the lean build.
2793
- // Both modes degrade to the honest empty result handled below.
2794
- void mode;
2795
- // If no real implementation worked, return empty with honest marker
2796
- if (results.length === 0) {
2797
- implementation = 'none';
2798
- }
2799
- const computeTimeMs = performance.now() - startTime;
2800
- return {
2801
- query,
2802
- mode,
2803
- results,
2804
- stats: {
2805
- computeTimeMs,
2806
- _stub: implementation === 'none',
2807
- _note: implementation === 'none' ? 'Pure-JS similarity only; native attention backends are not part of the lean build.' : undefined,
2808
- },
2809
- implementation,
2810
- };
2811
- },
2812
- };
2813
- /**
2814
- * Worker trigger patterns for auto-detection
2815
- */
2816
- const WORKER_TRIGGER_PATTERNS = {
2817
- ultralearn: [
2818
- /learn\s+about/i,
2819
- /understand\s+(how|what|why)/i,
2820
- /deep\s+dive\s+into/i,
2821
- /explain\s+in\s+detail/i,
2822
- /comprehensive\s+guide/i,
2823
- /master\s+this/i,
2824
- ],
2825
- optimize: [
2826
- /optimize/i,
2827
- /improve\s+performance/i,
2828
- /make\s+(it\s+)?faster/i,
2829
- /speed\s+up/i,
2830
- /reduce\s+(memory|time)/i,
2831
- /performance\s+issue/i,
2832
- ],
2833
- consolidate: [
2834
- /consolidate/i,
2835
- /merge\s+memories/i,
2836
- /clean\s+up\s+memory/i,
2837
- /deduplicate/i,
2838
- /memory\s+maintenance/i,
2839
- ],
2840
- predict: [
2841
- /what\s+will\s+happen/i,
2842
- /predict/i,
2843
- /forecast/i,
2844
- /anticipate/i,
2845
- /preload/i,
2846
- /prepare\s+for/i,
2847
- ],
2848
- audit: [
2849
- /security\s+audit/i,
2850
- /vulnerability/i,
2851
- /security\s+check/i,
2852
- /pentest/i,
2853
- /security\s+scan/i,
2854
- /cve/i,
2855
- /owasp/i,
2856
- ],
2857
- map: [
2858
- /map\s+(the\s+)?codebase/i,
2859
- /architecture\s+overview/i,
2860
- /project\s+structure/i,
2861
- /dependency\s+graph/i,
2862
- /code\s+map/i,
2863
- /explore\s+codebase/i,
2864
- ],
2865
- preload: [
2866
- /preload/i,
2867
- /cache\s+ahead/i,
2868
- /prefetch/i,
2869
- /warm\s+(up\s+)?cache/i,
2870
- ],
2871
- deepdive: [
2872
- /deep\s+dive/i,
2873
- /analyze\s+thoroughly/i,
2874
- /in-depth\s+analysis/i,
2875
- /comprehensive\s+review/i,
2876
- /detailed\s+examination/i,
2877
- ],
2878
- document: [
2879
- /document\s+(this|the)/i,
2880
- /generate\s+docs/i,
2881
- /add\s+documentation/i,
2882
- /write\s+readme/i,
2883
- /api\s+docs/i,
2884
- /jsdoc/i,
2885
- ],
2886
- refactor: [
2887
- /refactor/i,
2888
- /clean\s+up\s+code/i,
2889
- /improve\s+code\s+quality/i,
2890
- /restructure/i,
2891
- /simplify/i,
2892
- /make\s+more\s+readable/i,
2893
- ],
2894
- benchmark: [
2895
- /benchmark/i,
2896
- /performance\s+test/i,
2897
- /measure\s+speed/i,
2898
- /stress\s+test/i,
2899
- /load\s+test/i,
2900
- ],
2901
- testgaps: [
2902
- /test\s+coverage/i,
2903
- /missing\s+tests/i,
2904
- /untested\s+code/i,
2905
- /coverage\s+report/i,
2906
- /test\s+gaps/i,
2907
- /add\s+tests/i,
2908
- ],
2909
- };
2910
- /**
2911
- * Worker configurations
2912
- */
2913
- const WORKER_CONFIGS = {
2914
- ultralearn: {
2915
- description: 'Deep knowledge acquisition and learning',
2916
- priority: 'normal',
2917
- estimatedDuration: '60s',
2918
- capabilities: ['research', 'analysis', 'synthesis'],
2919
- },
2920
- optimize: {
2921
- description: 'Performance optimization and tuning',
2922
- priority: 'high',
2923
- estimatedDuration: '30s',
2924
- capabilities: ['profiling', 'optimization', 'benchmarking'],
2925
- },
2926
- consolidate: {
2927
- description: 'Memory consolidation and cleanup',
2928
- priority: 'low',
2929
- estimatedDuration: '20s',
2930
- capabilities: ['memory-management', 'deduplication'],
2931
- },
2932
- predict: {
2933
- description: 'Predictive preloading and anticipation',
2934
- priority: 'normal',
2935
- estimatedDuration: '15s',
2936
- capabilities: ['prediction', 'caching', 'preloading'],
2937
- },
2938
- audit: {
2939
- description: 'Security analysis and vulnerability scanning',
2940
- priority: 'critical',
2941
- estimatedDuration: '45s',
2942
- capabilities: ['security', 'vulnerability-scanning', 'audit'],
2943
- },
2944
- map: {
2945
- description: 'Codebase mapping and architecture analysis',
2946
- priority: 'normal',
2947
- estimatedDuration: '30s',
2948
- capabilities: ['analysis', 'mapping', 'visualization'],
2949
- },
2950
- preload: {
2951
- description: 'Resource preloading and cache warming',
2952
- priority: 'low',
2953
- estimatedDuration: '10s',
2954
- capabilities: ['caching', 'preloading'],
2955
- },
2956
- deepdive: {
2957
- description: 'Deep code analysis and examination',
2958
- priority: 'normal',
2959
- estimatedDuration: '60s',
2960
- capabilities: ['analysis', 'review', 'understanding'],
2961
- },
2962
- document: {
2963
- description: 'Auto-documentation generation',
2964
- priority: 'normal',
2965
- estimatedDuration: '45s',
2966
- capabilities: ['documentation', 'writing', 'generation'],
2967
- },
2968
- refactor: {
2969
- description: 'Code refactoring suggestions',
2970
- priority: 'normal',
2971
- estimatedDuration: '30s',
2972
- capabilities: ['refactoring', 'code-quality', 'improvement'],
2973
- },
2974
- benchmark: {
2975
- description: 'Performance benchmarking',
2976
- priority: 'normal',
2977
- estimatedDuration: '60s',
2978
- capabilities: ['benchmarking', 'testing', 'measurement'],
2979
- },
2980
- testgaps: {
2981
- description: 'Test coverage analysis',
2982
- priority: 'normal',
2983
- estimatedDuration: '30s',
2984
- capabilities: ['testing', 'coverage', 'analysis'],
2985
- },
2986
- };
2987
- // In-memory worker tracking
2988
- const activeWorkers = new Map();
2989
- let workerIdCounter = 0;
2990
- /**
2991
- * Detect triggers from prompt text
2992
- */
2993
- function detectWorkerTriggers(text) {
2994
- const detectedTriggers = [];
2995
- let totalMatches = 0;
2996
- for (const [trigger, patterns] of Object.entries(WORKER_TRIGGER_PATTERNS)) {
2997
- for (const pattern of patterns) {
2998
- if (pattern.test(text)) {
2999
- if (!detectedTriggers.includes(trigger)) {
3000
- detectedTriggers.push(trigger);
3001
- }
3002
- totalMatches++;
3003
- }
3004
- }
3005
- }
3006
- const confidence = detectedTriggers.length > 0
3007
- ? Math.min(1, totalMatches / (detectedTriggers.length * 2))
3008
- : 0;
3009
- return {
3010
- detected: detectedTriggers.length > 0,
3011
- triggers: detectedTriggers,
3012
- confidence,
3013
- context: text.slice(0, 100),
3014
- };
3015
- }
3016
- // Worker list tool
3017
- export const hooksWorkerList = {
3018
- name: 'hooks_worker-list',
3019
- description: 'List all 12 background workers with status and capabilities',
3020
- inputSchema: {
3021
- type: 'object',
3022
- properties: {
3023
- status: { type: 'string', description: 'Filter by status (all, running, completed, pending)' },
3024
- includeActive: { type: 'boolean', description: 'Include active worker instances' },
3025
- },
3026
- },
3027
- handler: async (params) => {
3028
- const statusFilter = params.status || 'all';
3029
- const includeActive = params.includeActive !== false;
3030
- const workers = Object.entries(WORKER_CONFIGS).map(([trigger, config]) => ({
3031
- trigger,
3032
- ...config,
3033
- patterns: WORKER_TRIGGER_PATTERNS[trigger].length,
3034
- }));
3035
- const activeList = includeActive
3036
- ? Array.from(activeWorkers.values()).filter(w => statusFilter === 'all' || w.status === statusFilter)
3037
- : [];
3038
- return {
3039
- workers,
3040
- total: 12,
3041
- active: {
3042
- instances: activeList,
3043
- count: activeList.length,
3044
- byStatus: {
3045
- pending: activeList.filter(w => w.status === 'pending').length,
3046
- running: activeList.filter(w => w.status === 'running').length,
3047
- completed: activeList.filter(w => w.status === 'completed').length,
3048
- failed: activeList.filter(w => w.status === 'failed').length,
3049
- },
3050
- },
3051
- performanceTargets: {
3052
- triggerDetection: '<5ms',
3053
- workerSpawn: '<50ms',
3054
- maxConcurrent: 10,
3055
- },
3056
- };
3057
- },
3058
- };
3059
- // Worker dispatch tool
3060
- export const hooksWorkerDispatch = {
3061
- name: 'hooks_worker-dispatch',
3062
- description: 'Dispatch a background worker for analysis/optimization tasks',
3063
- inputSchema: {
3064
- type: 'object',
3065
- properties: {
3066
- trigger: {
3067
- type: 'string',
3068
- description: 'Worker trigger type',
3069
- enum: ['ultralearn', 'optimize', 'consolidate', 'predict', 'audit', 'map', 'preload', 'deepdive', 'document', 'refactor', 'benchmark', 'testgaps'],
3070
- },
3071
- context: { type: 'string', description: 'Context for the worker (file path, topic, etc.)' },
3072
- priority: { type: 'string', description: 'Priority (low, normal, high, critical)' },
3073
- background: { type: 'boolean', description: 'Run in background (non-blocking)' },
3074
- },
3075
- required: ['trigger'],
3076
- },
3077
- handler: async (params) => {
3078
- const trigger = params.trigger;
3079
- const context = params.context || 'default';
3080
- const priority = params.priority || WORKER_CONFIGS[trigger]?.priority || 'normal';
3081
- const background = params.background !== false;
3082
- if (!WORKER_CONFIGS[trigger]) {
3083
- return {
3084
- success: false,
3085
- error: `Unknown worker trigger: ${trigger}`,
3086
- availableTriggers: Object.keys(WORKER_CONFIGS),
3087
- };
3088
- }
3089
- const workerId = `worker_${trigger}_${++workerIdCounter}_${Date.now().toString(36)}`;
3090
- const config = WORKER_CONFIGS[trigger];
3091
- const worker = {
3092
- id: workerId,
3093
- trigger,
3094
- context,
3095
- status: 'running',
3096
- progress: 0,
3097
- phase: 'initializing',
3098
- startedAt: new Date(),
3099
- };
3100
- activeWorkers.set(workerId, worker);
3101
- // Update worker progress in background
3102
- if (background) {
3103
- setTimeout(() => {
3104
- const w = activeWorkers.get(workerId);
3105
- if (w) {
3106
- w.progress = 50;
3107
- w.phase = 'processing';
3108
- }
3109
- }, 500);
3110
- setTimeout(() => {
3111
- const w = activeWorkers.get(workerId);
3112
- if (w) {
3113
- w.progress = 100;
3114
- w.phase = 'completed';
3115
- w.status = 'completed';
3116
- w.completedAt = new Date();
3117
- }
3118
- }, 1500);
3119
- }
3120
- else {
3121
- worker.progress = 100;
3122
- worker.phase = 'completed';
3123
- worker.status = 'completed';
3124
- worker.completedAt = new Date();
3125
- }
3126
- return {
3127
- success: true,
3128
- workerId,
3129
- trigger,
3130
- context,
3131
- priority,
3132
- config: {
3133
- description: config.description,
3134
- estimatedDuration: config.estimatedDuration,
3135
- capabilities: config.capabilities,
3136
- },
3137
- status: background ? 'dispatched' : 'completed',
3138
- background,
3139
- timestamp: new Date().toISOString(),
3140
- };
3141
- },
3142
- };
3143
- // Worker status tool
3144
- export const hooksWorkerStatus = {
3145
- name: 'hooks_worker-status',
3146
- description: 'Get status of a specific worker or all active workers',
3147
- inputSchema: {
3148
- type: 'object',
3149
- properties: {
3150
- workerId: { type: 'string', description: 'Specific worker ID to check' },
3151
- includeCompleted: { type: 'boolean', description: 'Include completed workers' },
3152
- },
3153
- },
3154
- handler: async (params) => {
3155
- const workerId = params.workerId;
3156
- const includeCompleted = params.includeCompleted !== false;
3157
- if (workerId) {
3158
- const worker = activeWorkers.get(workerId);
3159
- if (!worker) {
3160
- return {
3161
- success: false,
3162
- error: `Worker not found: ${workerId}`,
3163
- };
3164
- }
3165
- return {
3166
- success: true,
3167
- worker: {
3168
- ...worker,
3169
- duration: worker.completedAt
3170
- ? worker.completedAt.getTime() - worker.startedAt.getTime()
3171
- : Date.now() - worker.startedAt.getTime(),
3172
- },
3173
- };
3174
- }
3175
- const workers = Array.from(activeWorkers.values())
3176
- .filter(w => includeCompleted || w.status !== 'completed')
3177
- .map(w => ({
3178
- ...w,
3179
- duration: w.completedAt
3180
- ? w.completedAt.getTime() - w.startedAt.getTime()
3181
- : Date.now() - w.startedAt.getTime(),
3182
- }));
3183
- return {
3184
- success: true,
3185
- workers,
3186
- summary: {
3187
- total: workers.length,
3188
- running: workers.filter(w => w.status === 'running').length,
3189
- completed: workers.filter(w => w.status === 'completed').length,
3190
- failed: workers.filter(w => w.status === 'failed').length,
3191
- },
3192
- };
3193
- },
3194
- };
3195
- // Worker detect tool - detect triggers from prompt
3196
- export const hooksWorkerDetect = {
3197
- name: 'hooks_worker-detect',
3198
- description: 'Detect worker triggers from user prompt (for UserPromptSubmit hook)',
3199
- inputSchema: {
3200
- type: 'object',
3201
- properties: {
3202
- prompt: { type: 'string', description: 'User prompt to analyze' },
3203
- autoDispatch: { type: 'boolean', description: 'Automatically dispatch detected workers' },
3204
- minConfidence: { type: 'number', description: 'Minimum confidence threshold (0-1)' },
3205
- },
3206
- required: ['prompt'],
3207
- },
3208
- handler: async (params) => {
3209
- const prompt = params.prompt;
3210
- const autoDispatch = params.autoDispatch;
3211
- const minConfidence = params.minConfidence || 0.5;
3212
- const detection = detectWorkerTriggers(prompt);
3213
- const result = {
3214
- prompt: prompt.slice(0, 200) + (prompt.length > 200 ? '...' : ''),
3215
- detection,
3216
- triggersFound: detection.triggers.length,
3217
- };
3218
- if (detection.detected && detection.confidence >= minConfidence) {
3219
- result.triggerDetails = detection.triggers.map(trigger => ({
3220
- trigger,
3221
- ...WORKER_CONFIGS[trigger],
3222
- }));
3223
- if (autoDispatch) {
3224
- const dispatched = [];
3225
- for (const trigger of detection.triggers) {
3226
- const workerId = `worker_${trigger}_${++workerIdCounter}_${Date.now().toString(36)}`;
3227
- activeWorkers.set(workerId, {
3228
- id: workerId,
3229
- trigger,
3230
- context: prompt.slice(0, 100),
3231
- status: 'running',
3232
- progress: 0,
3233
- phase: 'initializing',
3234
- startedAt: new Date(),
3235
- });
3236
- dispatched.push(workerId);
3237
- // Mark worker completion after processing
3238
- setTimeout(() => {
3239
- const w = activeWorkers.get(workerId);
3240
- if (w) {
3241
- w.progress = 100;
3242
- w.phase = 'completed';
3243
- w.status = 'completed';
3244
- w.completedAt = new Date();
3245
- }
3246
- }, 1500);
3247
- }
3248
- result.autoDispatched = true;
3249
- result.workerIds = dispatched;
3250
- }
3251
- }
3252
- return result;
3253
- },
3254
- };
3255
- // Model route tool - intelligent model selection
3256
- export const hooksModelRoute = {
3257
- name: 'hooks_model-route',
3258
- description: 'Route task to optimal Claude model (haiku/sonnet/opus) based on complexity',
3259
- inputSchema: {
3260
- type: 'object',
3261
- properties: {
3262
- task: { type: 'string', description: 'Task description to analyze' },
3263
- preferSpeed: { type: 'boolean', description: 'Prefer faster models when possible' },
3264
- preferCost: { type: 'boolean', description: 'Prefer cheaper models when possible' },
3265
- },
3266
- required: ['task'],
3267
- },
3268
- handler: async (params) => {
3269
- // Cap task: analyzeComplexityFallback calls .toLowerCase() and O(n) .includes()
3270
- // for each keyword; an unbounded task string causes event-loop DoS.
3271
- const MAX_MODEL_ROUTE_TASK_LEN = 16 * 1024;
3272
- const rawTask = params.task;
3273
- const task = typeof rawTask === 'string' && rawTask.length > MAX_MODEL_ROUTE_TASK_LEN
3274
- ? rawTask.slice(0, MAX_MODEL_ROUTE_TASK_LEN)
3275
- : rawTask;
3276
- // Native neural model-router removed in the lean build — keyword complexity heuristic.
3277
- const complexity = analyzeComplexityFallback(task);
3278
- return {
3279
- model: complexity > 0.7 ? 'opus' : complexity > 0.4 ? 'sonnet' : 'haiku',
3280
- confidence: 0.7,
3281
- complexity,
3282
- reasoning: 'Keyword complexity heuristic',
3283
- implementation: 'heuristic',
3284
- };
3285
- },
3286
- };
3287
- // Model route outcome - record outcome for learning
3288
- export const hooksModelOutcome = {
3289
- name: 'hooks_model-outcome',
3290
- description: 'Record model routing outcome for learning',
3291
- inputSchema: {
3292
- type: 'object',
3293
- properties: {
3294
- task: { type: 'string', description: 'Original task' },
3295
- model: { type: 'string', enum: ['haiku', 'sonnet', 'opus'], description: 'Model used' },
3296
- outcome: { type: 'string', enum: ['success', 'failure', 'escalated'], description: 'Task outcome' },
3297
- verifier_type: { type: 'string', enum: ['tsc', 'vitest', 'eslint', 'llm_judge'], description: 'RLVR verifier type for grounded reward signal' },
3298
- exit_code: { type: 'number', description: 'Verifier exit code (0 = pass); overrides outcome when verifier_type is set' },
3299
- },
3300
- required: ['task', 'model', 'outcome'],
3301
- },
3302
- handler: async (params) => {
3303
- // Cap task: even though the response only reflects task.slice(0, 50), an
3304
- // unbounded task string causes unnecessary memory allocation before the slice.
3305
- const MAX_MODEL_OUTCOME_TASK_LEN = 16 * 1024;
3306
- const rawOutcomeTask = params.task;
3307
- const task = typeof rawOutcomeTask === 'string' && rawOutcomeTask.length > MAX_MODEL_OUTCOME_TASK_LEN
3308
- ? rawOutcomeTask.slice(0, MAX_MODEL_OUTCOME_TASK_LEN)
3309
- : rawOutcomeTask;
3310
- const model = params.model;
3311
- // RLVR: derive effective outcome from verifier exit_code when provided
3312
- // Source: https://github.com/opendilab/awesome-RLVR
3313
- const verifierType = params.verifier_type;
3314
- const exitCode = params.exit_code;
3315
- const effectiveOutcome = verifierType !== undefined && exitCode !== undefined
3316
- ? (exitCode === 0 ? 'success' : 'failure')
3317
- : params.outcome;
3318
- const outcome = effectiveOutcome;
3319
- // Native model-router removed in the lean build — outcome is acknowledged but not
3320
- // fed to a neural learner (keyword routing has no online-learning store).
3321
- return {
3322
- recorded: true,
3323
- task: task.slice(0, 50),
3324
- model,
3325
- outcome,
3326
- timestamp: new Date().toISOString(),
3327
- };
3328
- },
3329
- };
3330
- // Model router stats
3331
- export const hooksModelStats = {
3332
- name: 'hooks_model-stats',
3333
- description: 'Get model routing statistics',
3334
- inputSchema: {
3335
- type: 'object',
3336
- properties: {},
3337
- },
3338
- handler: async () => {
3339
- // Native model-router removed in the lean build — no neural routing stats to report.
3340
- return {
3341
- available: false,
3342
- message: 'Model router not available in the lean build (keyword routing has no stats)',
3343
- };
3344
- },
3345
- };
3346
- // Simple fallback complexity analyzer
3347
- function analyzeComplexityFallback(task) {
3348
- const taskLower = task.toLowerCase();
3349
- // High complexity indicators
3350
- const highIndicators = ['architect', 'design', 'refactor', 'security', 'audit', 'complex', 'analyze'];
3351
- const highCount = highIndicators.filter(ind => taskLower.includes(ind)).length;
3352
- // Low complexity indicators
3353
- const lowIndicators = ['simple', 'typo', 'format', 'rename', 'comment'];
3354
- const lowCount = lowIndicators.filter(ind => taskLower.includes(ind)).length;
3355
- // Base on length
3356
- const lengthScore = Math.min(1, task.length / 200);
3357
- return Math.min(1, Math.max(0, 0.3 + highCount * 0.2 - lowCount * 0.15 + lengthScore * 0.2));
3358
- }
3359
- // Worker cancel tool
3360
- export const hooksWorkerCancel = {
3361
- name: 'hooks_worker-cancel',
3362
- description: 'Cancel a running worker',
3363
- inputSchema: {
3364
- type: 'object',
3365
- properties: {
3366
- workerId: { type: 'string', description: 'Worker ID to cancel' },
3367
- },
3368
- required: ['workerId'],
3369
- },
3370
- handler: async (params) => {
3371
- const workerId = params.workerId;
3372
- const worker = activeWorkers.get(workerId);
3373
- if (!worker) {
3374
- return {
3375
- success: false,
3376
- error: `Worker not found: ${workerId}`,
3377
- };
3378
- }
3379
- if (worker.status === 'completed' || worker.status === 'failed') {
3380
- return {
3381
- success: false,
3382
- error: `Worker already ${worker.status}`,
3383
- };
3384
- }
3385
- worker.status = 'failed';
3386
- worker.phase = 'cancelled';
3387
- worker.completedAt = new Date();
3388
- return {
3389
- success: true,
3390
- workerId,
3391
- cancelled: true,
3392
- timestamp: new Date().toISOString(),
3393
- };
3394
- },
3395
- };
6
+ import { hooksPreEdit, hooksPostEdit, hooksPreCommand, hooksPostCommand, hooksRoute, hooksMetrics, hooksList, hooksPreTask, hooksPostTask, hooksExplain, hooksPretrain, hooksBuildAgents, hooksTransfer, hooksSessionStart, hooksSessionEnd, hooksSessionRestore, hooksNotify, hooksInit, hooksIntelligence, } from './hooks-routing.js';
7
+ import { hooksIntelligenceReset, hooksTrajectoryStart, hooksTrajectoryStep, hooksTrajectoryEnd, hooksPatternStore, hooksPatternSearch, hooksIntelligenceStats, hooksIntelligenceLearn, hooksIntelligenceAttention, hooksWorkerList, hooksWorkerDispatch, hooksWorkerStatus, hooksWorkerDetect, hooksWorkerCancel, hooksModelRoute, hooksModelOutcome, hooksModelStats, } from './hooks-intelligence.js';
3396
8
  // Export all hooks tools
3397
9
  export const hooksTools = [
3398
10
  hooksPreEdit,