forge-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. package/.claude/hooks/worktree-create.sh +64 -0
  2. package/.claude/hooks/worktree-remove.sh +57 -0
  3. package/.claude/settings.local.json +29 -0
  4. package/.forge/knowledge/conventions.yaml +1 -0
  5. package/.forge/knowledge/decisions.yaml +1 -0
  6. package/.forge/knowledge/gotchas.yaml +1 -0
  7. package/.forge/knowledge/patterns.yaml +1 -0
  8. package/.forge/manifest.yaml +6 -0
  9. package/CLAUDE.md +144 -0
  10. package/bin/setup-forge.sh +132 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +553 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/context/codebase.d.ts +57 -0
  16. package/dist/context/codebase.d.ts.map +1 -0
  17. package/dist/context/codebase.js +301 -0
  18. package/dist/context/codebase.js.map +1 -0
  19. package/dist/context/injector.d.ts +147 -0
  20. package/dist/context/injector.d.ts.map +1 -0
  21. package/dist/context/injector.js +533 -0
  22. package/dist/context/injector.js.map +1 -0
  23. package/dist/context/memory.d.ts +32 -0
  24. package/dist/context/memory.d.ts.map +1 -0
  25. package/dist/context/memory.js +140 -0
  26. package/dist/context/memory.js.map +1 -0
  27. package/dist/context/session-index.d.ts +54 -0
  28. package/dist/context/session-index.d.ts.map +1 -0
  29. package/dist/context/session-index.js +265 -0
  30. package/dist/context/session-index.js.map +1 -0
  31. package/dist/context/session.d.ts +42 -0
  32. package/dist/context/session.d.ts.map +1 -0
  33. package/dist/context/session.js +121 -0
  34. package/dist/context/session.js.map +1 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +37 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/ingestion/chunker.d.ts +19 -0
  40. package/dist/ingestion/chunker.d.ts.map +1 -0
  41. package/dist/ingestion/chunker.js +189 -0
  42. package/dist/ingestion/chunker.js.map +1 -0
  43. package/dist/ingestion/embedder.d.ts +45 -0
  44. package/dist/ingestion/embedder.d.ts.map +1 -0
  45. package/dist/ingestion/embedder.js +152 -0
  46. package/dist/ingestion/embedder.js.map +1 -0
  47. package/dist/ingestion/git-analyzer.d.ts +77 -0
  48. package/dist/ingestion/git-analyzer.d.ts.map +1 -0
  49. package/dist/ingestion/git-analyzer.js +437 -0
  50. package/dist/ingestion/git-analyzer.js.map +1 -0
  51. package/dist/ingestion/indexer.d.ts +79 -0
  52. package/dist/ingestion/indexer.d.ts.map +1 -0
  53. package/dist/ingestion/indexer.js +766 -0
  54. package/dist/ingestion/indexer.js.map +1 -0
  55. package/dist/ingestion/markdown-chunker.d.ts +19 -0
  56. package/dist/ingestion/markdown-chunker.d.ts.map +1 -0
  57. package/dist/ingestion/markdown-chunker.js +243 -0
  58. package/dist/ingestion/markdown-chunker.js.map +1 -0
  59. package/dist/ingestion/markdown-knowledge.d.ts +21 -0
  60. package/dist/ingestion/markdown-knowledge.d.ts.map +1 -0
  61. package/dist/ingestion/markdown-knowledge.js +129 -0
  62. package/dist/ingestion/markdown-knowledge.js.map +1 -0
  63. package/dist/ingestion/parser.d.ts +20 -0
  64. package/dist/ingestion/parser.d.ts.map +1 -0
  65. package/dist/ingestion/parser.js +429 -0
  66. package/dist/ingestion/parser.js.map +1 -0
  67. package/dist/ingestion/watcher.d.ts +28 -0
  68. package/dist/ingestion/watcher.d.ts.map +1 -0
  69. package/dist/ingestion/watcher.js +147 -0
  70. package/dist/ingestion/watcher.js.map +1 -0
  71. package/dist/knowledge/hydrator.d.ts +37 -0
  72. package/dist/knowledge/hydrator.d.ts.map +1 -0
  73. package/dist/knowledge/hydrator.js +220 -0
  74. package/dist/knowledge/hydrator.js.map +1 -0
  75. package/dist/knowledge/registry.d.ts +129 -0
  76. package/dist/knowledge/registry.d.ts.map +1 -0
  77. package/dist/knowledge/registry.js +361 -0
  78. package/dist/knowledge/registry.js.map +1 -0
  79. package/dist/knowledge/search.d.ts +114 -0
  80. package/dist/knowledge/search.d.ts.map +1 -0
  81. package/dist/knowledge/search.js +428 -0
  82. package/dist/knowledge/search.js.map +1 -0
  83. package/dist/knowledge/store.d.ts +76 -0
  84. package/dist/knowledge/store.d.ts.map +1 -0
  85. package/dist/knowledge/store.js +230 -0
  86. package/dist/knowledge/store.js.map +1 -0
  87. package/dist/learning/confidence.d.ts +30 -0
  88. package/dist/learning/confidence.d.ts.map +1 -0
  89. package/dist/learning/confidence.js +165 -0
  90. package/dist/learning/confidence.js.map +1 -0
  91. package/dist/learning/patterns.d.ts +52 -0
  92. package/dist/learning/patterns.d.ts.map +1 -0
  93. package/dist/learning/patterns.js +290 -0
  94. package/dist/learning/patterns.js.map +1 -0
  95. package/dist/learning/trajectory.d.ts +55 -0
  96. package/dist/learning/trajectory.d.ts.map +1 -0
  97. package/dist/learning/trajectory.js +200 -0
  98. package/dist/learning/trajectory.js.map +1 -0
  99. package/dist/memory/memory-compat.d.ts +100 -0
  100. package/dist/memory/memory-compat.d.ts.map +1 -0
  101. package/dist/memory/memory-compat.js +146 -0
  102. package/dist/memory/memory-compat.js.map +1 -0
  103. package/dist/memory/observation-store.d.ts +57 -0
  104. package/dist/memory/observation-store.d.ts.map +1 -0
  105. package/dist/memory/observation-store.js +154 -0
  106. package/dist/memory/observation-store.js.map +1 -0
  107. package/dist/memory/session-tracker.d.ts +81 -0
  108. package/dist/memory/session-tracker.d.ts.map +1 -0
  109. package/dist/memory/session-tracker.js +262 -0
  110. package/dist/memory/session-tracker.js.map +1 -0
  111. package/dist/pipeline/engine.d.ts +179 -0
  112. package/dist/pipeline/engine.d.ts.map +1 -0
  113. package/dist/pipeline/engine.js +691 -0
  114. package/dist/pipeline/engine.js.map +1 -0
  115. package/dist/pipeline/events.d.ts +54 -0
  116. package/dist/pipeline/events.d.ts.map +1 -0
  117. package/dist/pipeline/events.js +157 -0
  118. package/dist/pipeline/events.js.map +1 -0
  119. package/dist/pipeline/parallel.d.ts +83 -0
  120. package/dist/pipeline/parallel.d.ts.map +1 -0
  121. package/dist/pipeline/parallel.js +277 -0
  122. package/dist/pipeline/parallel.js.map +1 -0
  123. package/dist/pipeline/state-machine.d.ts +65 -0
  124. package/dist/pipeline/state-machine.d.ts.map +1 -0
  125. package/dist/pipeline/state-machine.js +176 -0
  126. package/dist/pipeline/state-machine.js.map +1 -0
  127. package/dist/query/graph-queries.d.ts +84 -0
  128. package/dist/query/graph-queries.d.ts.map +1 -0
  129. package/dist/query/graph-queries.js +216 -0
  130. package/dist/query/graph-queries.js.map +1 -0
  131. package/dist/query/hybrid-search.d.ts +34 -0
  132. package/dist/query/hybrid-search.d.ts.map +1 -0
  133. package/dist/query/hybrid-search.js +263 -0
  134. package/dist/query/hybrid-search.js.map +1 -0
  135. package/dist/query/intent-detector.d.ts +35 -0
  136. package/dist/query/intent-detector.d.ts.map +1 -0
  137. package/dist/query/intent-detector.js +115 -0
  138. package/dist/query/intent-detector.js.map +1 -0
  139. package/dist/query/ranking.d.ts +57 -0
  140. package/dist/query/ranking.d.ts.map +1 -0
  141. package/dist/query/ranking.js +109 -0
  142. package/dist/query/ranking.js.map +1 -0
  143. package/dist/server.d.ts +3 -0
  144. package/dist/server.d.ts.map +1 -0
  145. package/dist/server.js +291 -0
  146. package/dist/server.js.map +1 -0
  147. package/dist/storage/falkordb-store.d.ts +73 -0
  148. package/dist/storage/falkordb-store.d.ts.map +1 -0
  149. package/dist/storage/falkordb-store.js +346 -0
  150. package/dist/storage/falkordb-store.js.map +1 -0
  151. package/dist/storage/file-cache.d.ts +32 -0
  152. package/dist/storage/file-cache.d.ts.map +1 -0
  153. package/dist/storage/file-cache.js +115 -0
  154. package/dist/storage/file-cache.js.map +1 -0
  155. package/dist/storage/interfaces.d.ts +151 -0
  156. package/dist/storage/interfaces.d.ts.map +1 -0
  157. package/dist/storage/interfaces.js +7 -0
  158. package/dist/storage/interfaces.js.map +1 -0
  159. package/dist/storage/qdrant-store.d.ts +110 -0
  160. package/dist/storage/qdrant-store.d.ts.map +1 -0
  161. package/dist/storage/qdrant-store.js +467 -0
  162. package/dist/storage/qdrant-store.js.map +1 -0
  163. package/dist/storage/schema.d.ts +4 -0
  164. package/dist/storage/schema.d.ts.map +1 -0
  165. package/dist/storage/schema.js +136 -0
  166. package/dist/storage/schema.js.map +1 -0
  167. package/dist/storage/sqlite.d.ts +35 -0
  168. package/dist/storage/sqlite.d.ts.map +1 -0
  169. package/dist/storage/sqlite.js +132 -0
  170. package/dist/storage/sqlite.js.map +1 -0
  171. package/dist/tools/collaboration-tools.d.ts +111 -0
  172. package/dist/tools/collaboration-tools.d.ts.map +1 -0
  173. package/dist/tools/collaboration-tools.js +174 -0
  174. package/dist/tools/collaboration-tools.js.map +1 -0
  175. package/dist/tools/context-tools.d.ts +293 -0
  176. package/dist/tools/context-tools.d.ts.map +1 -0
  177. package/dist/tools/context-tools.js +437 -0
  178. package/dist/tools/context-tools.js.map +1 -0
  179. package/dist/tools/graph-tools.d.ts +129 -0
  180. package/dist/tools/graph-tools.d.ts.map +1 -0
  181. package/dist/tools/graph-tools.js +237 -0
  182. package/dist/tools/graph-tools.js.map +1 -0
  183. package/dist/tools/ingestion-tools.d.ts +96 -0
  184. package/dist/tools/ingestion-tools.d.ts.map +1 -0
  185. package/dist/tools/ingestion-tools.js +90 -0
  186. package/dist/tools/ingestion-tools.js.map +1 -0
  187. package/dist/tools/learning-tools.d.ts +168 -0
  188. package/dist/tools/learning-tools.d.ts.map +1 -0
  189. package/dist/tools/learning-tools.js +158 -0
  190. package/dist/tools/learning-tools.js.map +1 -0
  191. package/dist/tools/memory-tools.d.ts +183 -0
  192. package/dist/tools/memory-tools.d.ts.map +1 -0
  193. package/dist/tools/memory-tools.js +197 -0
  194. package/dist/tools/memory-tools.js.map +1 -0
  195. package/dist/tools/phase-tools.d.ts +954 -0
  196. package/dist/tools/phase-tools.d.ts.map +1 -0
  197. package/dist/tools/phase-tools.js +1215 -0
  198. package/dist/tools/phase-tools.js.map +1 -0
  199. package/dist/tools/pipeline-tools.d.ts +140 -0
  200. package/dist/tools/pipeline-tools.d.ts.map +1 -0
  201. package/dist/tools/pipeline-tools.js +162 -0
  202. package/dist/tools/pipeline-tools.js.map +1 -0
  203. package/dist/tools/registration-tools.d.ts +220 -0
  204. package/dist/tools/registration-tools.d.ts.map +1 -0
  205. package/dist/tools/registration-tools.js +391 -0
  206. package/dist/tools/registration-tools.js.map +1 -0
  207. package/dist/util/circuit-breaker.d.ts +75 -0
  208. package/dist/util/circuit-breaker.d.ts.map +1 -0
  209. package/dist/util/circuit-breaker.js +159 -0
  210. package/dist/util/circuit-breaker.js.map +1 -0
  211. package/dist/util/config.d.ts +23 -0
  212. package/dist/util/config.d.ts.map +1 -0
  213. package/dist/util/config.js +164 -0
  214. package/dist/util/config.js.map +1 -0
  215. package/dist/util/logger.d.ts +13 -0
  216. package/dist/util/logger.d.ts.map +1 -0
  217. package/dist/util/logger.js +45 -0
  218. package/dist/util/logger.js.map +1 -0
  219. package/dist/util/token-counter.d.ts +24 -0
  220. package/dist/util/token-counter.d.ts.map +1 -0
  221. package/dist/util/token-counter.js +48 -0
  222. package/dist/util/token-counter.js.map +1 -0
  223. package/dist/util/types.d.ts +525 -0
  224. package/dist/util/types.d.ts.map +1 -0
  225. package/dist/util/types.js +5 -0
  226. package/dist/util/types.js.map +1 -0
  227. package/docker-compose.yml +20 -0
  228. package/docs/plans/2026-02-27-swarm-coordination/architecture.md +203 -0
  229. package/docs/plans/2026-02-27-swarm-coordination/vision.md +57 -0
  230. package/docs/plans/completed/2026-02-26-forge-plugin-bundling/architecture.md +1 -0
  231. package/docs/plans/completed/2026-02-26-forge-plugin-bundling/vision.md +300 -0
  232. package/docs/plans/completed/2026-02-27-forge-swarm-learning/architecture.md +480 -0
  233. package/docs/plans/completed/2026-02-27-forge-swarm-learning/verification-checklist.md +462 -0
  234. package/docs/plans/completed/2026-02-27-git-history-atlassian/git-jira-plan.md +181 -0
  235. package/package.json +39 -0
  236. package/plugin/.claude-plugin/plugin.json +8 -0
  237. package/plugin/.mcp.json +15 -0
  238. package/plugin/README.md +134 -0
  239. package/plugin/agents/architect.md +367 -0
  240. package/plugin/agents/backend-specialist.md +263 -0
  241. package/plugin/agents/brainstormer.md +122 -0
  242. package/plugin/agents/data-specialist.md +266 -0
  243. package/plugin/agents/designer.md +408 -0
  244. package/plugin/agents/frontend-specialist.md +241 -0
  245. package/plugin/agents/inspector.md +406 -0
  246. package/plugin/agents/knowledge-keeper.md +443 -0
  247. package/plugin/agents/platform-engineer.md +326 -0
  248. package/plugin/agents/product-manager.md +268 -0
  249. package/plugin/agents/product-owner.md +438 -0
  250. package/plugin/agents/pulse-checker.md +73 -0
  251. package/plugin/agents/qa-strategist.md +500 -0
  252. package/plugin/agents/self-improver.md +310 -0
  253. package/plugin/agents/strategist.md +360 -0
  254. package/plugin/agents/supervisor.md +380 -0
  255. package/plugin/commands/brainstorm.md +25 -0
  256. package/plugin/commands/forge.md +88 -0
  257. package/plugin/docs/atlassian-integration.md +110 -0
  258. package/plugin/docs/workflow.md +126 -0
  259. package/plugin/skills/agent-development/.skillfish.json +10 -0
  260. package/plugin/skills/agent-development/SKILL.md +415 -0
  261. package/plugin/skills/agent-development/examples/agent-creation-prompt.md +238 -0
  262. package/plugin/skills/agent-development/examples/complete-agent-examples.md +427 -0
  263. package/plugin/skills/agent-development/references/agent-creation-system-prompt.md +207 -0
  264. package/plugin/skills/agent-development/references/system-prompt-design.md +411 -0
  265. package/plugin/skills/agent-development/references/triggering-examples.md +491 -0
  266. package/plugin/skills/agent-development/scripts/validate-agent.sh +217 -0
  267. package/plugin/skills/agent-handoff/SKILL.md +335 -0
  268. package/plugin/skills/anti-stub/SKILL.md +317 -0
  269. package/plugin/skills/brainstorm/SKILL.md +31 -0
  270. package/plugin/skills/debugging/SKILL.md +276 -0
  271. package/plugin/skills/fix/SKILL.md +62 -0
  272. package/plugin/skills/frontend-design/.skillfish.json +10 -0
  273. package/plugin/skills/frontend-design/SKILL.md +42 -0
  274. package/plugin/skills/gotchas/SKILL.md +61 -0
  275. package/plugin/skills/graph-orchestrator/SKILL.md +38 -0
  276. package/plugin/skills/history/SKILL.md +58 -0
  277. package/plugin/skills/impact/SKILL.md +59 -0
  278. package/plugin/skills/implementation-execution/SKILL.md +291 -0
  279. package/plugin/skills/index-repo/SKILL.md +55 -0
  280. package/plugin/skills/interviewing/SKILL.md +225 -0
  281. package/plugin/skills/knowledge-curation/SKILL.md +393 -0
  282. package/plugin/skills/learn/SKILL.md +69 -0
  283. package/plugin/skills/mcp-integration/.skillfish.json +10 -0
  284. package/plugin/skills/mcp-integration/SKILL.md +554 -0
  285. package/plugin/skills/mcp-integration/examples/http-server.json +20 -0
  286. package/plugin/skills/mcp-integration/examples/sse-server.json +19 -0
  287. package/plugin/skills/mcp-integration/examples/stdio-server.json +26 -0
  288. package/plugin/skills/mcp-integration/references/authentication.md +549 -0
  289. package/plugin/skills/mcp-integration/references/server-types.md +536 -0
  290. package/plugin/skills/mcp-integration/references/tool-usage.md +538 -0
  291. package/plugin/skills/nestjs/.skillfish.json +10 -0
  292. package/plugin/skills/nestjs/SKILL.md +669 -0
  293. package/plugin/skills/nestjs/drizzle-reference.md +1894 -0
  294. package/plugin/skills/nestjs/reference.md +1447 -0
  295. package/plugin/skills/nestjs/workflow-optimization.md +229 -0
  296. package/plugin/skills/parallel-dispatch/SKILL.md +308 -0
  297. package/plugin/skills/project-discovery/SKILL.md +304 -0
  298. package/plugin/skills/search/SKILL.md +56 -0
  299. package/plugin/skills/security-audit/SKILL.md +362 -0
  300. package/plugin/skills/skill-development/.skillfish.json +10 -0
  301. package/plugin/skills/skill-development/SKILL.md +637 -0
  302. package/plugin/skills/skill-development/references/skill-creator-original.md +209 -0
  303. package/plugin/skills/tdd/SKILL.md +273 -0
  304. package/plugin/skills/terminal-presentation/SKILL.md +395 -0
  305. package/plugin/skills/test-strategy/SKILL.md +365 -0
  306. package/plugin/skills/verification-protocol/SKILL.md +256 -0
  307. package/plugin/skills/visual-explainer/CHANGELOG.md +97 -0
  308. package/plugin/skills/visual-explainer/LICENSE +21 -0
  309. package/plugin/skills/visual-explainer/README.md +137 -0
  310. package/plugin/skills/visual-explainer/SKILL.md +352 -0
  311. package/plugin/skills/visual-explainer/banner.png +0 -0
  312. package/plugin/skills/visual-explainer/package.json +11 -0
  313. package/plugin/skills/visual-explainer/prompts/diff-review.md +68 -0
  314. package/plugin/skills/visual-explainer/prompts/fact-check.md +63 -0
  315. package/plugin/skills/visual-explainer/prompts/generate-slides.md +18 -0
  316. package/plugin/skills/visual-explainer/prompts/generate-web-diagram.md +10 -0
  317. package/plugin/skills/visual-explainer/prompts/plan-review.md +86 -0
  318. package/plugin/skills/visual-explainer/prompts/project-recap.md +61 -0
  319. package/plugin/skills/visual-explainer/references/css-patterns.md +1188 -0
  320. package/plugin/skills/visual-explainer/references/libraries.md +470 -0
  321. package/plugin/skills/visual-explainer/references/responsive-nav.md +212 -0
  322. package/plugin/skills/visual-explainer/references/slide-patterns.md +1403 -0
  323. package/plugin/skills/visual-explainer/templates/architecture.html +596 -0
  324. package/plugin/skills/visual-explainer/templates/data-table.html +540 -0
  325. package/plugin/skills/visual-explainer/templates/mermaid-flowchart.html +435 -0
  326. package/plugin/skills/visual-explainer/templates/slide-deck.html +913 -0
  327. package/src/cli.ts +655 -0
  328. package/src/context/.gitkeep +0 -0
  329. package/src/context/codebase.ts +393 -0
  330. package/src/context/injector.ts +797 -0
  331. package/src/context/memory.ts +187 -0
  332. package/src/context/session-index.ts +327 -0
  333. package/src/context/session.ts +152 -0
  334. package/src/index.ts +47 -0
  335. package/src/ingestion/.gitkeep +0 -0
  336. package/src/ingestion/chunker.ts +277 -0
  337. package/src/ingestion/embedder.ts +167 -0
  338. package/src/ingestion/git-analyzer.ts +545 -0
  339. package/src/ingestion/indexer.ts +984 -0
  340. package/src/ingestion/markdown-chunker.ts +337 -0
  341. package/src/ingestion/markdown-knowledge.ts +175 -0
  342. package/src/ingestion/parser.ts +475 -0
  343. package/src/ingestion/watcher.ts +182 -0
  344. package/src/knowledge/.gitkeep +0 -0
  345. package/src/knowledge/hydrator.ts +246 -0
  346. package/src/knowledge/registry.ts +463 -0
  347. package/src/knowledge/search.ts +565 -0
  348. package/src/knowledge/store.ts +262 -0
  349. package/src/learning/.gitkeep +0 -0
  350. package/src/learning/confidence.ts +193 -0
  351. package/src/learning/patterns.ts +360 -0
  352. package/src/learning/trajectory.ts +268 -0
  353. package/src/memory/.gitkeep +0 -0
  354. package/src/memory/memory-compat.ts +233 -0
  355. package/src/memory/observation-store.ts +224 -0
  356. package/src/memory/session-tracker.ts +332 -0
  357. package/src/pipeline/.gitkeep +0 -0
  358. package/src/pipeline/engine.ts +1139 -0
  359. package/src/pipeline/events.ts +253 -0
  360. package/src/pipeline/parallel.ts +394 -0
  361. package/src/pipeline/state-machine.ts +199 -0
  362. package/src/query/.gitkeep +0 -0
  363. package/src/query/graph-queries.ts +262 -0
  364. package/src/query/hybrid-search.ts +337 -0
  365. package/src/query/intent-detector.ts +131 -0
  366. package/src/query/ranking.ts +161 -0
  367. package/src/server.ts +352 -0
  368. package/src/storage/.gitkeep +0 -0
  369. package/src/storage/falkordb-store.ts +388 -0
  370. package/src/storage/file-cache.ts +141 -0
  371. package/src/storage/interfaces.ts +201 -0
  372. package/src/storage/qdrant-store.ts +557 -0
  373. package/src/storage/schema.ts +139 -0
  374. package/src/storage/sqlite.ts +168 -0
  375. package/src/tools/.gitkeep +0 -0
  376. package/src/tools/collaboration-tools.ts +208 -0
  377. package/src/tools/context-tools.ts +493 -0
  378. package/src/tools/graph-tools.ts +295 -0
  379. package/src/tools/ingestion-tools.ts +122 -0
  380. package/src/tools/learning-tools.ts +181 -0
  381. package/src/tools/memory-tools.ts +234 -0
  382. package/src/tools/phase-tools.ts +1452 -0
  383. package/src/tools/pipeline-tools.ts +188 -0
  384. package/src/tools/registration-tools.ts +450 -0
  385. package/src/util/.gitkeep +0 -0
  386. package/src/util/circuit-breaker.ts +193 -0
  387. package/src/util/config.ts +177 -0
  388. package/src/util/logger.ts +53 -0
  389. package/src/util/token-counter.ts +52 -0
  390. package/src/util/types.ts +710 -0
  391. package/tests/context/.gitkeep +0 -0
  392. package/tests/integration/.gitkeep +0 -0
  393. package/tests/knowledge/.gitkeep +0 -0
  394. package/tests/learning/.gitkeep +0 -0
  395. package/tests/pipeline/.gitkeep +0 -0
  396. package/tests/tools/.gitkeep +0 -0
  397. package/tsconfig.json +21 -0
  398. package/vitest.config.ts +10 -0
  399. package/vscode-extension/.vscodeignore +7 -0
  400. package/vscode-extension/README.md +43 -0
  401. package/vscode-extension/out/edge-collector.js +274 -0
  402. package/vscode-extension/out/edge-collector.js.map +1 -0
  403. package/vscode-extension/out/extension.js +264 -0
  404. package/vscode-extension/out/extension.js.map +1 -0
  405. package/vscode-extension/out/forge-client.js +318 -0
  406. package/vscode-extension/out/forge-client.js.map +1 -0
  407. package/vscode-extension/package-lock.json +59 -0
  408. package/vscode-extension/package.json +71 -0
  409. package/vscode-extension/src/edge-collector.ts +320 -0
  410. package/vscode-extension/src/extension.ts +269 -0
  411. package/vscode-extension/src/forge-client.ts +364 -0
  412. package/vscode-extension/tsconfig.json +19 -0
@@ -0,0 +1,295 @@
1
+ // graph-tools.ts — Swarm Learning Phase 1
2
+ // MCP tool handlers for graph-based code analysis.
3
+ // Tools: get_impact_graph, search_logic_flow
4
+
5
+ import { z } from 'zod';
6
+ import type { GraphStore } from '../storage/interfaces.js';
7
+ import {
8
+ QUERY_INBOUND_IMPACT,
9
+ QUERY_OUTBOUND_IMPACT,
10
+ QUERY_SHORTEST_PATH,
11
+ } from '../query/graph-queries.js';
12
+ import { logger } from '../util/logger.js';
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Input schemas
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export const getImpactGraphSchema = z.object({
19
+ symbol: z.string().min(1, 'symbol name is required'),
20
+ repo_id: z.string().min(1, 'repo_id is required'),
21
+ direction: z.enum(['inbound', 'outbound', 'both']).default('both'),
22
+ depth: z.number().int().min(1).max(5).default(3),
23
+ });
24
+
25
+ export const searchLogicFlowSchema = z.object({
26
+ from_symbol: z.string().min(1, 'from_symbol is required'),
27
+ to_symbol: z.string().min(1, 'to_symbol is required'),
28
+ repo_id: z.string().min(1, 'repo_id is required'),
29
+ max_depth: z.number().int().min(1).max(10).default(5),
30
+ });
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Tool factory
34
+ // ---------------------------------------------------------------------------
35
+
36
+ export function createGraphTools(graphStore: GraphStore | null) {
37
+ return {
38
+ 'get_impact_graph': {
39
+ schema: getImpactGraphSchema,
40
+ description: 'Get the impact graph (callers/dependents) for a code symbol. PREFER THIS over manual Grep for "who uses X" questions — it traverses the actual call/import graph with depth control, not just text matches. Requires FalkorDB graph store.',
41
+ handler: async (input: z.infer<typeof getImpactGraphSchema>) => {
42
+ if (!graphStore) {
43
+ return {
44
+ error: 'GRAPH_UNAVAILABLE',
45
+ message: 'FalkorDB graph store is not available. Impact graph requires a running FalkorDB instance.',
46
+ };
47
+ }
48
+
49
+ const healthy = await graphStore.isHealthy();
50
+ if (!healthy) {
51
+ return {
52
+ error: 'GRAPH_UNAVAILABLE',
53
+ message: 'FalkorDB is not healthy. Impact graph unavailable.',
54
+ };
55
+ }
56
+
57
+ try {
58
+ const nodes: Array<{ name: string; label: string; file_path?: string }> = [];
59
+ const edges: Array<{ from: string; to: string; type: string; depth: number }> = [];
60
+
61
+ // Inbound: who calls/imports/uses this symbol?
62
+ if (input.direction === 'inbound' || input.direction === 'both') {
63
+ try {
64
+ const result = await graphStore.query(
65
+ QUERY_INBOUND_IMPACT(input.symbol, input.repo_id, input.depth)
66
+ );
67
+ parseImpactResult(result, nodes, edges, 'inbound');
68
+ } catch (err) {
69
+ logger.warn('get_impact_graph: inbound query failed', { error: String(err) });
70
+ }
71
+ }
72
+
73
+ // Outbound: what does this symbol depend on?
74
+ if (input.direction === 'outbound' || input.direction === 'both') {
75
+ try {
76
+ const result = await graphStore.query(
77
+ QUERY_OUTBOUND_IMPACT(input.symbol, input.repo_id, input.depth)
78
+ );
79
+ parseImpactResult(result, nodes, edges, 'outbound');
80
+ } catch (err) {
81
+ logger.warn('get_impact_graph: outbound query failed', { error: String(err) });
82
+ }
83
+ }
84
+
85
+ // Deduplicate nodes by name
86
+ const uniqueNodes = deduplicateNodes(nodes);
87
+
88
+ logger.debug('graph-tools.get_impact_graph: completed', {
89
+ symbol: input.symbol,
90
+ direction: input.direction,
91
+ nodes: uniqueNodes.length,
92
+ edges: edges.length,
93
+ });
94
+
95
+ return {
96
+ symbol: input.symbol,
97
+ direction: input.direction,
98
+ nodes: uniqueNodes,
99
+ edges,
100
+ total_nodes: uniqueNodes.length,
101
+ total_edges: edges.length,
102
+ };
103
+ } catch (err) {
104
+ logger.error('graph-tools.get_impact_graph: error', { error: String(err) });
105
+ return {
106
+ error: 'GET_IMPACT_GRAPH_FAILED',
107
+ message: String(err),
108
+ };
109
+ }
110
+ },
111
+ },
112
+
113
+ 'search_logic_flow': {
114
+ schema: searchLogicFlowSchema,
115
+ description: 'Find the shortest path between two code symbols in the call/dependency graph. Use this to understand how data or control flows from A to B through the codebase — much faster than manually tracing imports. Requires FalkorDB graph store.',
116
+ handler: async (input: z.infer<typeof searchLogicFlowSchema>) => {
117
+ if (!graphStore) {
118
+ return {
119
+ error: 'GRAPH_UNAVAILABLE',
120
+ message: 'FalkorDB graph store is not available. Logic flow search requires a running FalkorDB instance.',
121
+ };
122
+ }
123
+
124
+ const healthy = await graphStore.isHealthy();
125
+ if (!healthy) {
126
+ return {
127
+ error: 'GRAPH_UNAVAILABLE',
128
+ message: 'FalkorDB is not healthy. Logic flow search unavailable.',
129
+ };
130
+ }
131
+
132
+ try {
133
+ const result = await graphStore.query(
134
+ QUERY_SHORTEST_PATH(input.from_symbol, input.to_symbol, input.repo_id, input.max_depth)
135
+ );
136
+
137
+ const paths = parsePathResult(result);
138
+
139
+ logger.debug('graph-tools.search_logic_flow: completed', {
140
+ from: input.from_symbol,
141
+ to: input.to_symbol,
142
+ pathCount: paths.length,
143
+ });
144
+
145
+ return {
146
+ from_symbol: input.from_symbol,
147
+ to_symbol: input.to_symbol,
148
+ paths,
149
+ connected: paths.length > 0,
150
+ };
151
+ } catch (err) {
152
+ logger.error('graph-tools.search_logic_flow: error', { error: String(err) });
153
+ return {
154
+ error: 'SEARCH_LOGIC_FLOW_FAILED',
155
+ message: String(err),
156
+ from_symbol: input.from_symbol,
157
+ to_symbol: input.to_symbol,
158
+ paths: [],
159
+ connected: false,
160
+ };
161
+ }
162
+ },
163
+ },
164
+ };
165
+ }
166
+
167
+ // ---------------------------------------------------------------------------
168
+ // Result parsers for FalkorDB raw responses
169
+ // ---------------------------------------------------------------------------
170
+
171
+ interface GraphQueryResult {
172
+ nodes: Array<{ label: string; properties: Record<string, unknown> }>;
173
+ edges: Array<{ type: string; from: string; to: string; properties?: Record<string, unknown> }>;
174
+ raw?: unknown[];
175
+ }
176
+
177
+ function parseImpactResult(
178
+ result: GraphQueryResult,
179
+ nodes: Array<{ name: string; label: string; file_path?: string }>,
180
+ edges: Array<{ from: string; to: string; type: string; depth: number }>,
181
+ _direction: 'inbound' | 'outbound',
182
+ ): void {
183
+ // Parse nodes from the result
184
+ for (const node of result.nodes ?? []) {
185
+ const name = String(node.properties?.['name'] ?? '');
186
+ const filePath = node.properties?.['file_path'] as string | undefined;
187
+ if (name) {
188
+ nodes.push({ name, label: node.label, file_path: filePath });
189
+ }
190
+ }
191
+
192
+ // Parse edges from the result
193
+ for (const edge of result.edges ?? []) {
194
+ edges.push({
195
+ from: edge.from,
196
+ to: edge.to,
197
+ type: edge.type,
198
+ depth: 1,
199
+ });
200
+ }
201
+
202
+ // Also try to parse from raw results (FalkorDB returns varying formats)
203
+ for (const row of result.raw ?? []) {
204
+ if (!row || !Array.isArray(row)) continue;
205
+
206
+ // Expected columns: [caller/dep, relationship_array, depth]
207
+ const entity = row[0];
208
+ const depth = typeof row[2] === 'number' ? row[2] : 1;
209
+
210
+ if (entity && typeof entity === 'object') {
211
+ const props = (entity as Record<string, unknown>).properties as Record<string, unknown> | undefined;
212
+ if (props) {
213
+ const name = String(props['name'] ?? '');
214
+ const filePath = props['file_path'] as string | undefined;
215
+ if (name) {
216
+ nodes.push({ name, label: 'unknown', file_path: filePath });
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ function parsePathResult(
224
+ result: GraphQueryResult,
225
+ ): Array<{ nodes: string[]; edges: string[]; length: number }> {
226
+ const paths: Array<{ nodes: string[]; edges: string[]; length: number }> = [];
227
+
228
+ // Try to parse from raw results
229
+ for (const row of result.raw ?? []) {
230
+ if (!row) continue;
231
+
232
+ // The QUERY_SHORTEST_PATH returns path objects
233
+ // Different FalkorDB parsers represent these differently
234
+ if (Array.isArray(row)) {
235
+ const pathObj = row[0];
236
+ if (pathObj && typeof pathObj === 'object') {
237
+ const pathNodes: string[] = [];
238
+ const pathEdges: string[] = [];
239
+
240
+ // Extract from FalkorDB path representation
241
+ const pNodes = (pathObj as Record<string, unknown>).nodes as Array<Record<string, unknown>> | undefined;
242
+ const pEdges = (pathObj as Record<string, unknown>).edges as Array<Record<string, unknown>> | undefined;
243
+
244
+ if (pNodes) {
245
+ for (const n of pNodes) {
246
+ const props = n.properties as Record<string, unknown> | undefined;
247
+ pathNodes.push(String(props?.['name'] ?? 'unknown'));
248
+ }
249
+ }
250
+
251
+ if (pEdges) {
252
+ for (const e of pEdges) {
253
+ pathEdges.push(String(e.type ?? e.relation ?? 'unknown'));
254
+ }
255
+ }
256
+
257
+ if (pathNodes.length > 0) {
258
+ paths.push({
259
+ nodes: pathNodes,
260
+ edges: pathEdges,
261
+ length: pathNodes.length - 1,
262
+ });
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ // Fallback: build from the standard node/edge arrays
269
+ if (paths.length === 0 && (result.nodes.length > 0 || result.edges.length > 0)) {
270
+ const nodeNames = result.nodes.map(n => String(n.properties?.['name'] ?? 'unknown'));
271
+ const edgeTypes = result.edges.map(e => e.type);
272
+
273
+ if (nodeNames.length > 0) {
274
+ paths.push({
275
+ nodes: nodeNames,
276
+ edges: edgeTypes,
277
+ length: Math.max(0, nodeNames.length - 1),
278
+ });
279
+ }
280
+ }
281
+
282
+ return paths;
283
+ }
284
+
285
+ function deduplicateNodes(
286
+ nodes: Array<{ name: string; label: string; file_path?: string }>,
287
+ ): Array<{ name: string; label: string; file_path?: string }> {
288
+ const seen = new Map<string, { name: string; label: string; file_path?: string }>();
289
+ for (const node of nodes) {
290
+ if (!seen.has(node.name)) {
291
+ seen.set(node.name, node);
292
+ }
293
+ }
294
+ return Array.from(seen.values());
295
+ }
@@ -0,0 +1,122 @@
1
+ // ingestion-tools.ts — Swarm Learning Phase 4
2
+ // MCP tool handlers for ingesting external data into the graph store.
3
+ // Tools: submit_lsp_edges
4
+ // Designed for VS Code extension and CI pipelines to push type-resolved
5
+ // call edges that supplement the static AST parsing.
6
+
7
+ import { z } from 'zod';
8
+ import type { GraphStore } from '../storage/interfaces.js';
9
+ import { logger } from '../util/logger.js';
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Input schemas
13
+ // ---------------------------------------------------------------------------
14
+
15
+ const lspEdgeSchema = z.object({
16
+ from_file: z.string().min(1),
17
+ from_symbol: z.string().min(1),
18
+ to_file: z.string().min(1),
19
+ to_symbol: z.string().min(1),
20
+ edge_type: z.string().min(1),
21
+ });
22
+
23
+ export const submitLspEdgesSchema = z.object({
24
+ repo_id: z.string().min(1, 'repo_id is required'),
25
+ edges: z.array(lspEdgeSchema).min(1, 'at least one edge is required'),
26
+ });
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Tool factory
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export function createIngestionTools(graphStore: GraphStore | null) {
33
+ return {
34
+ 'submit_lsp_edges': {
35
+ schema: submitLspEdgesSchema,
36
+ description:
37
+ 'Submit LSP-resolved call/reference edges to enrich the code graph. ' +
38
+ 'Designed for the VS Code extension and CI pipelines. Each edge describes ' +
39
+ 'a typed relationship between two symbols (e.g. calls, imports, implements).',
40
+ handler: async (input: z.infer<typeof submitLspEdgesSchema>) => {
41
+ if (!graphStore) {
42
+ return {
43
+ error: 'GRAPH_UNAVAILABLE',
44
+ message:
45
+ 'FalkorDB graph store is not available. LSP edges require a running FalkorDB instance.',
46
+ };
47
+ }
48
+
49
+ const healthy = await graphStore.isHealthy();
50
+ if (!healthy) {
51
+ return {
52
+ error: 'GRAPH_UNAVAILABLE',
53
+ message: 'FalkorDB is not healthy. Cannot ingest LSP edges.',
54
+ };
55
+ }
56
+
57
+ let accepted = 0;
58
+ let failed = 0;
59
+ const errors: string[] = [];
60
+
61
+ for (const edge of input.edges) {
62
+ try {
63
+ // Upsert the source node (Symbol)
64
+ await graphStore.upsertNode(
65
+ 'Symbol',
66
+ { name: edge.from_symbol, repo_id: input.repo_id },
67
+ { file_path: edge.from_file, source: 'lsp' },
68
+ );
69
+
70
+ // Upsert the target node (Symbol)
71
+ await graphStore.upsertNode(
72
+ 'Symbol',
73
+ { name: edge.to_symbol, repo_id: input.repo_id },
74
+ { file_path: edge.to_file, source: 'lsp' },
75
+ );
76
+
77
+ // Upsert the edge between the two symbols
78
+ await graphStore.upsertEdge(
79
+ 'Symbol',
80
+ { name: edge.from_symbol, repo_id: input.repo_id },
81
+ edge.edge_type,
82
+ { source: 'lsp', repo_id: input.repo_id },
83
+ 'Symbol',
84
+ { name: edge.to_symbol, repo_id: input.repo_id },
85
+ );
86
+
87
+ accepted++;
88
+ } catch (err) {
89
+ failed++;
90
+ const msg = `${edge.from_symbol} -[${edge.edge_type}]-> ${edge.to_symbol}: ${String(err)}`;
91
+ errors.push(msg);
92
+ logger.warn('ingestion-tools.submit_lsp_edges: edge failed', {
93
+ from: edge.from_symbol,
94
+ to: edge.to_symbol,
95
+ edgeType: edge.edge_type,
96
+ error: String(err),
97
+ });
98
+ }
99
+ }
100
+
101
+ logger.debug('ingestion-tools.submit_lsp_edges: completed', {
102
+ repoId: input.repo_id,
103
+ total: input.edges.length,
104
+ accepted,
105
+ failed,
106
+ });
107
+
108
+ const result: { accepted: number; failed: number; errors?: string[] } = {
109
+ accepted,
110
+ failed,
111
+ };
112
+
113
+ if (errors.length > 0) {
114
+ // Cap error messages to avoid oversized responses
115
+ result.errors = errors.slice(0, 20);
116
+ }
117
+
118
+ return result;
119
+ },
120
+ },
121
+ };
122
+ }
@@ -0,0 +1,181 @@
1
+ // learning-tools.ts — B17
2
+ // MCP tool handlers for knowledge retrieval and confidence management.
3
+ // Tools: get_patterns, get_gotchas, boost_knowledge, decay_knowledge
4
+
5
+ import { z } from 'zod';
6
+ import type { KnowledgeSearch } from '../knowledge/search.js';
7
+ import type { ConfidenceManager } from '../learning/confidence.js';
8
+ import type { QdrantVectorStore } from '../storage/qdrant-store.js';
9
+ import { logger } from '../util/logger.js';
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Input schemas
13
+ // ---------------------------------------------------------------------------
14
+
15
+ export const getPatternsSchema = z.object({
16
+ domain: z.string().optional(),
17
+ min_confidence: z.number().min(0).max(1).default(0.5),
18
+ limit: z.number().int().min(1).max(50).default(20),
19
+ });
20
+
21
+ export const getGotchasSchema = z.object({
22
+ stack: z.array(z.string()).optional(),
23
+ min_confidence: z.number().min(0).max(1).default(0.3),
24
+ limit: z.number().int().min(1).max(50).default(20),
25
+ });
26
+
27
+ export const boostKnowledgeSchema = z.object({
28
+ knowledge_id: z.string().min(1, 'knowledge_id is required'),
29
+ amount: z.number().min(0).max(1).default(0.05),
30
+ reason: z.string().optional(),
31
+ });
32
+
33
+ export const decayKnowledgeSchema = z.object({
34
+ decay_rate: z.number().min(0).max(1).default(0.01),
35
+ });
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Tool factory
39
+ // ---------------------------------------------------------------------------
40
+
41
+ export function createLearningTools(
42
+ knowledgeSearch: KnowledgeSearch,
43
+ confidenceManager?: ConfidenceManager,
44
+ vectorStore?: QdrantVectorStore | null,
45
+ ) {
46
+ return {
47
+ 'get_patterns': {
48
+ schema: getPatternsSchema,
49
+ description: 'Retrieve established code patterns from the knowledge base. PREFER THIS over ad-hoc code exploration when looking for "how do we do X in this codebase" — it returns curated, high-confidence patterns from past pipeline runs. Optionally filtered by domain/stack.',
50
+ handler: async (input: z.infer<typeof getPatternsSchema>) => {
51
+ try {
52
+ const patterns = await knowledgeSearch.getPatterns(input.domain, input.limit, input.min_confidence);
53
+
54
+ logger.debug('learning-tools.get_patterns: completed', {
55
+ domain: input.domain,
56
+ count: patterns.length,
57
+ });
58
+
59
+ return {
60
+ patterns: patterns.map(p => ({
61
+ title: p.title,
62
+ content: p.content,
63
+ confidence: p.confidence,
64
+ stack_tags: Array.isArray(p.stack_tags) ? p.stack_tags : [],
65
+ source_repo: (p as { source_repo?: string }).source_repo ?? p.source_agent ?? 'unknown',
66
+ times_confirmed: 1, // Qdrant payload doesn't track this yet
67
+ })),
68
+ };
69
+ } catch (err) {
70
+ logger.error('learning-tools.get_patterns: error', { error: String(err) });
71
+ return {
72
+ error: 'GET_PATTERNS_FAILED',
73
+ message: String(err),
74
+ patterns: [],
75
+ };
76
+ }
77
+ },
78
+ },
79
+
80
+ 'get_gotchas': {
81
+ schema: getGotchasSchema,
82
+ description: 'Retrieve known gotchas and pitfalls from the knowledge base. ALWAYS CHECK THIS before starting implementation in an indexed repo — avoids repeating past mistakes. Optionally filtered by stack tags.',
83
+ handler: async (input: z.infer<typeof getGotchasSchema>) => {
84
+ try {
85
+ const gotchas = await knowledgeSearch.getGotchas(input.stack, input.limit, input.min_confidence);
86
+
87
+ logger.debug('learning-tools.get_gotchas: completed', {
88
+ stack: input.stack,
89
+ count: gotchas.length,
90
+ });
91
+
92
+ return {
93
+ gotchas: gotchas.map(g => ({
94
+ title: g.title,
95
+ content: g.content,
96
+ confidence: g.confidence,
97
+ stack_tags: Array.isArray(g.stack_tags) ? g.stack_tags : [],
98
+ source_repo: (g as { source_repo?: string }).source_repo ?? g.source_agent ?? 'unknown',
99
+ })),
100
+ };
101
+ } catch (err) {
102
+ logger.error('learning-tools.get_gotchas: error', { error: String(err) });
103
+ return {
104
+ error: 'GET_GOTCHAS_FAILED',
105
+ message: String(err),
106
+ gotchas: [],
107
+ };
108
+ }
109
+ },
110
+ },
111
+
112
+ 'boost_knowledge': {
113
+ schema: boostKnowledgeSchema,
114
+ description: 'Boost the confidence score of a specific knowledge item. Used by Knowledge Keeper when a knowledge item proves valuable.',
115
+ handler: async (input: z.infer<typeof boostKnowledgeSchema>) => {
116
+ if (!confidenceManager || !vectorStore) {
117
+ return {
118
+ error: 'CONFIDENCE_UNAVAILABLE',
119
+ message: 'ConfidenceManager or vector store not available. Qdrant may be down.',
120
+ };
121
+ }
122
+
123
+ try {
124
+ await confidenceManager.boost(vectorStore, input.knowledge_id, input.amount);
125
+
126
+ logger.debug('learning-tools.boost_knowledge: completed', {
127
+ knowledge_id: input.knowledge_id,
128
+ amount: input.amount,
129
+ reason: input.reason,
130
+ });
131
+
132
+ return {
133
+ knowledge_id: input.knowledge_id,
134
+ boosted: true,
135
+ amount: input.amount,
136
+ reason: input.reason,
137
+ };
138
+ } catch (err) {
139
+ logger.error('learning-tools.boost_knowledge: error', { error: String(err) });
140
+ return {
141
+ error: 'BOOST_KNOWLEDGE_FAILED',
142
+ message: String(err),
143
+ };
144
+ }
145
+ },
146
+ },
147
+
148
+ 'decay_knowledge': {
149
+ schema: decayKnowledgeSchema,
150
+ description: 'Apply time-based confidence decay to all knowledge items. Items not accessed within 30 days lose confidence. Used by Knowledge Keeper for maintenance.',
151
+ handler: async (input: z.infer<typeof decayKnowledgeSchema>) => {
152
+ if (!confidenceManager || !vectorStore) {
153
+ return {
154
+ error: 'CONFIDENCE_UNAVAILABLE',
155
+ message: 'ConfidenceManager or vector store not available. Qdrant may be down.',
156
+ };
157
+ }
158
+
159
+ try {
160
+ const decayedCount = await confidenceManager.decayAll(vectorStore, input.decay_rate);
161
+
162
+ logger.debug('learning-tools.decay_knowledge: completed', {
163
+ decay_rate: input.decay_rate,
164
+ decayed_count: decayedCount,
165
+ });
166
+
167
+ return {
168
+ decayed_count: decayedCount,
169
+ decay_rate: input.decay_rate,
170
+ };
171
+ } catch (err) {
172
+ logger.error('learning-tools.decay_knowledge: error', { error: String(err) });
173
+ return {
174
+ error: 'DECAY_KNOWLEDGE_FAILED',
175
+ message: String(err),
176
+ };
177
+ }
178
+ },
179
+ },
180
+ };
181
+ }