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,346 @@
1
+ /**
2
+ * FalkorDB implementation of GraphStore.
3
+ * FalkorDB speaks Redis protocol + GRAPH commands.
4
+ * Connects to localhost:6380 (remapped from container port 6379 per ADR-7).
5
+ *
6
+ * FalkorDB GRAPH.QUERY --compact response format:
7
+ * [
8
+ * ["header", [...column_names]],
9
+ * ["data", [[row], [row], ...]],
10
+ * ["stats", ["Query internal execution time: X ms"]]
11
+ * ]
12
+ *
13
+ * Without --compact:
14
+ * [header_array, data_array, stats_array]
15
+ * where header_array = [column_names]
16
+ * and data_array = [[cell, cell, ...], ...]
17
+ */
18
+ import { createClient } from 'redis';
19
+ import { logger } from '../util/logger.js';
20
+ import { CircuitBreaker } from '../util/circuit-breaker.js';
21
+ const DEFAULT_QUERY_TIMEOUT_MS = 5000;
22
+ const RECONNECT_DELAY_MS = 1000;
23
+ const MAX_RECONNECT_ATTEMPTS = 3;
24
+ export class FalkorDBGraphStore {
25
+ client = null;
26
+ url;
27
+ graphName;
28
+ queryTimeoutMs;
29
+ connected = false;
30
+ reconnectAttempts = 0;
31
+ breaker;
32
+ constructor(url = 'redis://localhost:6380', graphName = 'forge_knowledge', queryTimeoutMs = DEFAULT_QUERY_TIMEOUT_MS) {
33
+ this.url = url;
34
+ this.graphName = graphName;
35
+ this.queryTimeoutMs = queryTimeoutMs;
36
+ this.breaker = new CircuitBreaker({
37
+ name: 'falkordb',
38
+ failureThreshold: 5,
39
+ resetTimeoutMs: 30_000,
40
+ });
41
+ }
42
+ async connect() {
43
+ if (this.connected)
44
+ return;
45
+ this.client = createClient({
46
+ url: this.url,
47
+ socket: {
48
+ connectTimeout: this.queryTimeoutMs,
49
+ reconnectStrategy: (retries) => {
50
+ if (retries >= MAX_RECONNECT_ATTEMPTS) {
51
+ logger.error('FalkorDB max reconnect attempts reached');
52
+ return new Error('Max reconnect attempts reached');
53
+ }
54
+ const delay = RECONNECT_DELAY_MS * Math.pow(2, retries);
55
+ logger.warn('FalkorDB reconnecting', { attempt: retries + 1, delayMs: delay });
56
+ return delay;
57
+ },
58
+ },
59
+ });
60
+ this.client.on('error', (err) => {
61
+ logger.error('FalkorDB connection error', { error: err.message });
62
+ this.connected = false;
63
+ });
64
+ this.client.on('ready', () => {
65
+ this.connected = true;
66
+ this.reconnectAttempts = 0;
67
+ logger.info('FalkorDB ready', { url: this.url, graph: this.graphName });
68
+ });
69
+ this.client.on('reconnecting', () => {
70
+ this.reconnectAttempts++;
71
+ logger.warn('FalkorDB reconnecting', { attempt: this.reconnectAttempts });
72
+ });
73
+ await this.client.connect();
74
+ this.connected = true;
75
+ logger.info('FalkorDB connected', { url: this.url, graph: this.graphName });
76
+ }
77
+ async disconnect() {
78
+ if (this.client && this.connected) {
79
+ await this.client.disconnect();
80
+ this.client = null;
81
+ this.connected = false;
82
+ logger.info('FalkorDB disconnected');
83
+ }
84
+ }
85
+ async isHealthy() {
86
+ // Circuit breaker short-circuits when OPEN — no ping needed
87
+ if (!this.breaker.isHealthy())
88
+ return false;
89
+ if (!this.client || !this.connected)
90
+ return false;
91
+ try {
92
+ const result = await this.withTimeout(this.client.ping(), this.queryTimeoutMs);
93
+ return result === 'PONG';
94
+ }
95
+ catch {
96
+ return false;
97
+ }
98
+ }
99
+ /**
100
+ * Execute a raw Cypher query and return typed results.
101
+ * Parses FalkorDB's non-compact response format.
102
+ */
103
+ async query(cypher, params) {
104
+ try {
105
+ const raw = await this.graphQuery(cypher, params);
106
+ return this.parseGraphQueryResult(raw);
107
+ }
108
+ catch (err) {
109
+ logger.error('Graph query error', { error: String(err), cypher: cypher.slice(0, 100) });
110
+ return { nodes: [], edges: [], raw: [] };
111
+ }
112
+ }
113
+ async upsertNode(label, matchProps, setProps) {
114
+ const matchClause = this.propsToMatch(matchProps);
115
+ const setClause = this.propsToSet(setProps, 'n');
116
+ const cypher = `MERGE (n:${label} {${matchClause}}) SET ${setClause}`;
117
+ try {
118
+ await this.graphQuery(cypher);
119
+ }
120
+ catch (err) {
121
+ logger.warn('upsertNode failed', { label, error: String(err) });
122
+ }
123
+ }
124
+ async upsertEdge(fromLabel, fromProps, edgeType, edgeProps, toLabel, toProps) {
125
+ const fromMatch = this.propsToMatch(fromProps);
126
+ const toMatch = this.propsToMatch(toProps);
127
+ const edgeSet = Object.keys(edgeProps).length > 0
128
+ ? ` {${this.propsToMatch(edgeProps)}}`
129
+ : '';
130
+ const cypher = `
131
+ MATCH (a:${fromLabel} {${fromMatch}})
132
+ MATCH (b:${toLabel} {${toMatch}})
133
+ MERGE (a)-[r:${edgeType}${edgeSet}]->(b)
134
+ `;
135
+ try {
136
+ await this.graphQuery(cypher);
137
+ }
138
+ catch (err) {
139
+ logger.warn('upsertEdge failed', { edgeType, error: String(err) });
140
+ }
141
+ }
142
+ async deleteFile(filePath, repoId) {
143
+ // Delete child nodes (symbols contained in the file)
144
+ const deleteChildren = `
145
+ MATCH (f:File {path: "${this.escape(filePath)}", repo_id: "${this.escape(repoId)}"})-[:CONTAINS]->(s)
146
+ DETACH DELETE s
147
+ `;
148
+ // Delete the file node itself
149
+ const deleteFile = `
150
+ MATCH (f:File {path: "${this.escape(filePath)}", repo_id: "${this.escape(repoId)}"})
151
+ DETACH DELETE f
152
+ `;
153
+ try {
154
+ await this.graphQuery(deleteChildren);
155
+ await this.graphQuery(deleteFile);
156
+ }
157
+ catch (err) {
158
+ logger.warn('deleteFile failed', { filePath, error: String(err) });
159
+ }
160
+ }
161
+ async deleteRepo(repoId) {
162
+ const cypher = `
163
+ MATCH (n {repo_id: "${this.escape(repoId)}"})
164
+ DETACH DELETE n
165
+ `;
166
+ try {
167
+ await this.graphQuery(cypher);
168
+ }
169
+ catch (err) {
170
+ logger.warn('deleteRepo failed', { repoId, error: String(err) });
171
+ }
172
+ }
173
+ async getCounts() {
174
+ try {
175
+ // FalkorDB GRAPH.QUERY returns [headers, data, stats]
176
+ // MATCH (n) RETURN count(n) returns [[count_value]]
177
+ const nodeResult = await this.graphQuery('MATCH (n) RETURN count(n) AS cnt');
178
+ const edgeResult = await this.graphQuery('MATCH ()-[r]->() RETURN count(r) AS cnt');
179
+ const totalNodes = this.extractScalarNumber(nodeResult);
180
+ const totalEdges = this.extractScalarNumber(edgeResult);
181
+ // Get per-label counts for known node labels
182
+ const labels = ['File', 'Function', 'Class', 'Interface', 'Module', 'TypeAlias', 'Variable', 'Observation'];
183
+ const byLabel = {};
184
+ await Promise.all(labels.map(async (label) => {
185
+ try {
186
+ const result = await this.graphQuery(`MATCH (n:${label}) RETURN count(n) AS cnt`);
187
+ const count = this.extractScalarNumber(result);
188
+ if (count > 0)
189
+ byLabel[label] = count;
190
+ }
191
+ catch {
192
+ // Label might not exist in graph yet - skip
193
+ }
194
+ }));
195
+ return { totalNodes, totalEdges, byLabel };
196
+ }
197
+ catch (err) {
198
+ logger.warn('getCounts failed', { error: String(err) });
199
+ return { totalNodes: 0, totalEdges: 0, byLabel: {} };
200
+ }
201
+ }
202
+ async ensureIndexes() {
203
+ const indexes = [
204
+ 'CREATE INDEX ON :File(path, repo_id)',
205
+ 'CREATE INDEX ON :Function(name, repo_id)',
206
+ 'CREATE INDEX ON :Class(name, repo_id)',
207
+ 'CREATE INDEX ON :Interface(name, repo_id)',
208
+ 'CREATE INDEX ON :Module(name, repo_id)',
209
+ 'CREATE INDEX ON :Observation(id)',
210
+ 'CREATE INDEX ON :Observation(session_id)',
211
+ ];
212
+ for (const idx of indexes) {
213
+ try {
214
+ await this.graphQuery(idx);
215
+ }
216
+ catch {
217
+ // Index may already exist - FalkorDB throws on duplicate index creation.
218
+ // This is expected and safe to ignore.
219
+ }
220
+ }
221
+ logger.info('FalkorDB indexes ensured');
222
+ }
223
+ // ============================================================
224
+ // Private helpers
225
+ // ============================================================
226
+ /**
227
+ * Execute a GRAPH.QUERY command with timeout, wrapped in the circuit breaker.
228
+ * Returns the raw FalkorDB response array.
229
+ */
230
+ async graphQuery(cypher, _params) {
231
+ if (!this.client)
232
+ throw new Error('FalkorDB not connected. Call connect() first.');
233
+ return this.breaker.execute(async () => {
234
+ const queryPromise = this.client.sendCommand([
235
+ 'GRAPH.QUERY',
236
+ this.graphName,
237
+ cypher,
238
+ ]);
239
+ return this.withTimeout(queryPromise, this.queryTimeoutMs);
240
+ });
241
+ }
242
+ /**
243
+ * Wrap a promise with a timeout that rejects after timeoutMs.
244
+ */
245
+ withTimeout(promise, timeoutMs) {
246
+ return new Promise((resolve, reject) => {
247
+ const timer = setTimeout(() => {
248
+ reject(new Error(`FalkorDB query timed out after ${timeoutMs}ms`));
249
+ }, timeoutMs);
250
+ promise.then((value) => { clearTimeout(timer); resolve(value); }, (err) => { clearTimeout(timer); reject(err); });
251
+ });
252
+ }
253
+ /**
254
+ * Parse FalkorDB GRAPH.QUERY response into GraphQueryResult.
255
+ * FalkorDB non-compact format: [header_row, data_rows, stats_row]
256
+ * header_row: ["column1", "column2", ...]
257
+ * data_rows: [[val1, val2, ...], [val1, val2, ...], ...]
258
+ */
259
+ parseGraphQueryResult(raw) {
260
+ if (!Array.isArray(raw) || raw.length < 2) {
261
+ return { nodes: [], edges: [], raw };
262
+ }
263
+ const headers = raw[0];
264
+ const dataRows = raw[1];
265
+ if (!Array.isArray(headers) || !Array.isArray(dataRows)) {
266
+ return { nodes: [], edges: [], raw };
267
+ }
268
+ const nodes = [];
269
+ const edges = [];
270
+ for (const row of dataRows) {
271
+ if (!Array.isArray(row))
272
+ continue;
273
+ for (let i = 0; i < headers.length; i++) {
274
+ const cell = row[i];
275
+ if (cell && typeof cell === 'object' && !Array.isArray(cell)) {
276
+ const obj = cell;
277
+ // FalkorDB node: { id, labels, properties }
278
+ if (Array.isArray(obj.labels)) {
279
+ nodes.push({
280
+ id: String(obj.id ?? ''),
281
+ label: obj.labels[0] ?? '',
282
+ properties: obj.properties ?? {},
283
+ });
284
+ }
285
+ // FalkorDB edge: { id, type, src_node, dest_node, properties }
286
+ if (typeof obj.type === 'string' && obj.src_node !== undefined) {
287
+ edges.push({
288
+ type: obj.type,
289
+ from: String(obj.src_node),
290
+ to: String(obj.dest_node ?? ''),
291
+ properties: obj.properties ?? {},
292
+ });
293
+ }
294
+ }
295
+ }
296
+ }
297
+ return { nodes, edges, raw };
298
+ }
299
+ /**
300
+ * Extract a single scalar number from a GRAPH.QUERY count result.
301
+ * Response: [["cnt"], [[42]], [...stats]]
302
+ */
303
+ extractScalarNumber(raw) {
304
+ if (!Array.isArray(raw) || raw.length < 2)
305
+ return 0;
306
+ const dataRows = raw[1];
307
+ if (!Array.isArray(dataRows) || dataRows.length === 0)
308
+ return 0;
309
+ const firstRow = dataRows[0];
310
+ if (!Array.isArray(firstRow) || firstRow.length === 0)
311
+ return 0;
312
+ const val = firstRow[0];
313
+ if (typeof val === 'number')
314
+ return val;
315
+ if (typeof val === 'string')
316
+ return parseInt(val, 10) || 0;
317
+ return 0;
318
+ }
319
+ propsToMatch(props) {
320
+ return Object.entries(props)
321
+ .map(([k, v]) => `${k}: ${this.valueToLiteral(v)}`)
322
+ .join(', ');
323
+ }
324
+ propsToSet(props, alias) {
325
+ return Object.entries(props)
326
+ .map(([k, v]) => `${alias}.${k} = ${this.valueToLiteral(v)}`)
327
+ .join(', ');
328
+ }
329
+ valueToLiteral(v) {
330
+ if (typeof v === 'string')
331
+ return `"${this.escape(v)}"`;
332
+ if (typeof v === 'number')
333
+ return String(v);
334
+ if (typeof v === 'boolean')
335
+ return v ? 'true' : 'false';
336
+ if (v === null || v === undefined)
337
+ return 'null';
338
+ if (Array.isArray(v))
339
+ return `[${v.map(x => this.valueToLiteral(x)).join(', ')}]`;
340
+ return `"${this.escape(JSON.stringify(v))}"`;
341
+ }
342
+ escape(s) {
343
+ return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
344
+ }
345
+ }
346
+ //# sourceMappingURL=falkordb-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"falkordb-store.js","sourceRoot":"","sources":["../../src/storage/falkordb-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * In-memory LRU file content cache.
3
+ * Provides the cross-agent shared context (ADR-8, section 4.6).
4
+ * Size-aware eviction with content-hash keying for invalidation.
5
+ */
6
+ import type { FileContentCache } from './interfaces.js';
7
+ import type { CacheEntry, CacheStats } from '../util/types.js';
8
+ export interface FileCacheOptions {
9
+ maxSizeBytes?: number;
10
+ maxEntries?: number;
11
+ ttlMs?: number;
12
+ }
13
+ export declare class LRUFileContentCache implements FileContentCache {
14
+ private cache;
15
+ private hits;
16
+ private misses;
17
+ private evictionCount;
18
+ private startedAt;
19
+ constructor(options?: FileCacheOptions);
20
+ private cacheKey;
21
+ get(repoId: string, filePath: string): CacheEntry | null;
22
+ set(repoId: string, filePath: string, content: string, contentHash: string): void;
23
+ invalidate(repoId: string, filePath: string): void;
24
+ invalidateRepo(repoId: string): void;
25
+ clear(): void;
26
+ getStats(): CacheStats;
27
+ }
28
+ /**
29
+ * Utility: compute SHA-256 hash of content string.
30
+ */
31
+ export declare function hashContent(content: string): string;
32
+ //# sourceMappingURL=file-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-cache.d.ts","sourceRoot":"","sources":["../../src/storage/file-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAO/D,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,mBAAoB,YAAW,gBAAgB;IAC1D,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAAc;gBAEnB,OAAO,GAAE,gBAAqB;IAqB1C,OAAO,CAAC,QAAQ;IAIhB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAexD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAgBjF,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlD,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAYpC,KAAK,IAAI,IAAI;IAOb,QAAQ,IAAI,UAAU;CAuBvB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * In-memory LRU file content cache.
3
+ * Provides the cross-agent shared context (ADR-8, section 4.6).
4
+ * Size-aware eviction with content-hash keying for invalidation.
5
+ */
6
+ import { LRUCache } from 'lru-cache';
7
+ import { createHash } from 'crypto';
8
+ import { logger } from '../util/logger.js';
9
+ const DEFAULT_MAX_SIZE_BYTES = 100 * 1024 * 1024; // 100 MB
10
+ const DEFAULT_MAX_ENTRIES = 2000;
11
+ const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 min
12
+ export class LRUFileContentCache {
13
+ cache;
14
+ hits = 0;
15
+ misses = 0;
16
+ evictionCount = 0;
17
+ startedAt = Date.now();
18
+ constructor(options = {}) {
19
+ const maxSizeBytes = options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
20
+ const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
21
+ this.cache = new LRUCache({
22
+ maxSize: maxSizeBytes,
23
+ // LRU cache requires sizeCalculation to return a positive integer.
24
+ // Use minimum of 1 so zero-byte content (empty string) is still accepted.
25
+ sizeCalculation: (entry) => Math.max(1, entry.sizeBytes),
26
+ ttl: ttlMs,
27
+ max: options.maxEntries ?? DEFAULT_MAX_ENTRIES,
28
+ // Use Date.now() for TTL tracking. This makes the cache compatible with
29
+ // vi.useFakeTimers() in tests (which replaces Date.now but not performance.now).
30
+ // lru-cache v11 defaults to performance.now which isn't affected by fake timers.
31
+ perf: { now: () => Date.now() },
32
+ dispose: () => {
33
+ this.evictionCount++;
34
+ },
35
+ });
36
+ }
37
+ cacheKey(repoId, filePath) {
38
+ return `${repoId}:${filePath}`;
39
+ }
40
+ get(repoId, filePath) {
41
+ const key = this.cacheKey(repoId, filePath);
42
+ const entry = this.cache.get(key);
43
+ if (entry) {
44
+ this.hits++;
45
+ // Update access count in-place
46
+ entry.accessCount++;
47
+ return entry;
48
+ }
49
+ this.misses++;
50
+ return null;
51
+ }
52
+ set(repoId, filePath, content, contentHash) {
53
+ const key = this.cacheKey(repoId, filePath);
54
+ const sizeBytes = Buffer.byteLength(content, 'utf8');
55
+ const entry = {
56
+ content,
57
+ contentHash,
58
+ cachedAt: Date.now(),
59
+ accessCount: 0,
60
+ sizeBytes, // Report the actual byte size (may be 0 for empty string)
61
+ };
62
+ this.cache.set(key, entry);
63
+ logger.debug('File cached', { filePath, sizeBytes, repoId });
64
+ }
65
+ invalidate(repoId, filePath) {
66
+ const key = this.cacheKey(repoId, filePath);
67
+ this.cache.delete(key);
68
+ logger.debug('Cache invalidated', { filePath, repoId });
69
+ }
70
+ invalidateRepo(repoId) {
71
+ const prefix = `${repoId}:`;
72
+ let count = 0;
73
+ for (const key of this.cache.keys()) {
74
+ if (key.startsWith(prefix)) {
75
+ this.cache.delete(key);
76
+ count++;
77
+ }
78
+ }
79
+ logger.info('Repo cache invalidated', { repoId, count });
80
+ }
81
+ clear() {
82
+ this.cache.clear();
83
+ this.hits = 0;
84
+ this.misses = 0;
85
+ logger.info('File content cache cleared');
86
+ }
87
+ getStats() {
88
+ const total = this.hits + this.misses;
89
+ const hitRate = total > 0 ? this.hits / total : 0;
90
+ // Calculate current memory usage
91
+ let totalBytes = 0;
92
+ let oldestAge = 0;
93
+ const now = Date.now();
94
+ for (const entry of this.cache.values()) {
95
+ totalBytes += entry.sizeBytes;
96
+ const age = (now - entry.cachedAt) / 1000;
97
+ if (age > oldestAge)
98
+ oldestAge = age;
99
+ }
100
+ return {
101
+ entries: this.cache.size,
102
+ memoryUsageMb: totalBytes / (1024 * 1024),
103
+ hitRate,
104
+ evictionCount: this.evictionCount,
105
+ oldestEntryAgeSeconds: oldestAge,
106
+ };
107
+ }
108
+ }
109
+ /**
110
+ * Utility: compute SHA-256 hash of content string.
111
+ */
112
+ export function hashContent(content) {
113
+ return createHash('sha256').update(content, 'utf8').digest('hex');
114
+ }
115
+ //# sourceMappingURL=file-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-cache.js","sourceRoot":"","sources":["../../src/storage/file-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,sBAAsB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,CAAE,SAAS;AAC5D,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAe,SAAS;AAQ9D,MAAM,OAAO,mBAAmB;IACtB,KAAK,CAA+B;IACpC,IAAI,GAAG,CAAC,CAAC;IACT,MAAM,GAAG,CAAC,CAAC;IACX,aAAa,GAAG,CAAC,CAAC;IAClB,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE/B,YAAY,UAA4B,EAAE;QACxC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,sBAAsB,CAAC;QACpE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC;QAE9C,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAqB;YAC5C,OAAO,EAAE,YAAY;YACrB,mEAAmE;YACnE,0EAA0E;YAC1E,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;YACxD,GAAG,EAAE,KAAK;YACV,GAAG,EAAE,OAAO,CAAC,UAAU,IAAI,mBAAmB;YAC9C,wEAAwE;YACxE,iFAAiF;YACjF,iFAAiF;YACjF,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE;YAC/B,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,MAAc,EAAE,QAAgB;QAC/C,OAAO,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,QAAgB;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,+BAA+B;YAC/B,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAE,OAAe,EAAE,WAAmB;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAErD,MAAM,KAAK,GAAe;YACxB,OAAO;YACP,WAAW;YACX,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;YACpB,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,0DAA0D;SACtE,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,UAAU,CAAC,MAAc,EAAE,QAAgB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC5C,CAAC;IAED,QAAQ;QACN,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACtC,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,iCAAiC;QACjC,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,UAAU,IAAI,KAAK,CAAC,SAAS,CAAC;YAC9B,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;YAC1C,IAAI,GAAG,GAAG,SAAS;gBAAE,SAAS,GAAG,GAAG,CAAC;QACvC,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACxB,aAAa,EAAE,UAAU,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YACzC,OAAO;YACP,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,qBAAqB,EAAE,SAAS;SACjC,CAAC;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Storage abstraction interfaces (ADR-8).
3
+ * All tool handlers interact with these interfaces, never with FalkorDB/Qdrant clients directly.
4
+ * This enables swapping implementations without rewriting the query engine.
5
+ */
6
+ import type { GraphQueryResult, VectorSearchResult, CodeChunkPayload, ObservationPayload, CacheEntry, CacheStats } from '../util/types.js';
7
+ export interface GraphStore {
8
+ /**
9
+ * Connect to the graph database.
10
+ */
11
+ connect(): Promise<void>;
12
+ /**
13
+ * Disconnect and clean up.
14
+ */
15
+ disconnect(): Promise<void>;
16
+ /**
17
+ * Check if the connection is healthy.
18
+ */
19
+ isHealthy(): Promise<boolean>;
20
+ /**
21
+ * Execute a raw Cypher query.
22
+ */
23
+ query(cypher: string, params?: Record<string, unknown>): Promise<GraphQueryResult>;
24
+ /**
25
+ * Create or update a node. Uses MERGE to avoid duplicates.
26
+ * Returns the node's internal ID.
27
+ */
28
+ upsertNode(label: string, matchProps: Record<string, unknown>, setProps: Record<string, unknown>): Promise<void>;
29
+ /**
30
+ * Create or update an edge between two nodes.
31
+ */
32
+ upsertEdge(fromLabel: string, fromProps: Record<string, unknown>, edgeType: string, edgeProps: Record<string, unknown>, toLabel: string, toProps: Record<string, unknown>): Promise<void>;
33
+ /**
34
+ * Delete all nodes and edges for a given file path + repo.
35
+ * Used during re-indexing.
36
+ */
37
+ deleteFile(filePath: string, repoId: string): Promise<void>;
38
+ /**
39
+ * Delete all nodes and edges for a given repo.
40
+ */
41
+ deleteRepo(repoId: string): Promise<void>;
42
+ /**
43
+ * Get total node and edge counts.
44
+ */
45
+ getCounts(): Promise<{
46
+ totalNodes: number;
47
+ totalEdges: number;
48
+ byLabel: Record<string, number>;
49
+ }>;
50
+ /**
51
+ * Ensure all required indexes exist.
52
+ */
53
+ ensureIndexes(): Promise<void>;
54
+ }
55
+ export interface VectorSearchOptions {
56
+ limit?: number;
57
+ filter?: Record<string, unknown>;
58
+ scoreThreshold?: number;
59
+ }
60
+ export interface VectorStore {
61
+ /**
62
+ * Connect / verify connection.
63
+ */
64
+ connect(): Promise<void>;
65
+ /**
66
+ * Disconnect.
67
+ */
68
+ disconnect(): Promise<void>;
69
+ /**
70
+ * Check if the connection is healthy.
71
+ */
72
+ isHealthy(): Promise<boolean>;
73
+ /**
74
+ * Ensure collections exist with the correct schema.
75
+ */
76
+ ensureCollections(dimension: number): Promise<void>;
77
+ /**
78
+ * Upsert code chunk vectors.
79
+ */
80
+ upsertCodeChunks(chunks: Array<{
81
+ id: string;
82
+ vector: number[];
83
+ payload: CodeChunkPayload;
84
+ }>): Promise<void>;
85
+ /**
86
+ * Upsert observation vectors.
87
+ */
88
+ upsertObservation(id: string, vector: number[], payload: ObservationPayload): Promise<void>;
89
+ /**
90
+ * Semantic search over code_chunks collection.
91
+ */
92
+ searchCodeChunks(queryVector: number[], options: VectorSearchOptions): Promise<VectorSearchResult[]>;
93
+ /**
94
+ * Semantic search over observations collection.
95
+ */
96
+ searchObservations(queryVector: number[], options: VectorSearchOptions): Promise<VectorSearchResult[]>;
97
+ /**
98
+ * Delete all code chunk vectors for a file.
99
+ */
100
+ deleteFileChunks(filePath: string, repoId: string): Promise<void>;
101
+ /**
102
+ * Delete all vectors for a repo.
103
+ */
104
+ deleteRepoChunks(repoId: string): Promise<void>;
105
+ /**
106
+ * Get count of points in each collection.
107
+ */
108
+ getCounts(): Promise<{
109
+ codeChunks: number;
110
+ observations: number;
111
+ }>;
112
+ /**
113
+ * Retrieve a specific observation by ID.
114
+ */
115
+ getObservation(id: string): Promise<ObservationPayload | null>;
116
+ /**
117
+ * Update an observation's payload fields.
118
+ */
119
+ updateObservation(id: string, payload: Partial<ObservationPayload>): Promise<void>;
120
+ /**
121
+ * Filter observations by payload conditions (e.g. by key + namespace).
122
+ */
123
+ filterObservations(filter: Record<string, unknown>, limit?: number): Promise<VectorSearchResult[]>;
124
+ }
125
+ export interface FileContentCache {
126
+ /**
127
+ * Get cached file content. Returns null on miss.
128
+ */
129
+ get(repoId: string, filePath: string): CacheEntry | null;
130
+ /**
131
+ * Store file content in cache.
132
+ */
133
+ set(repoId: string, filePath: string, content: string, contentHash: string): void;
134
+ /**
135
+ * Invalidate a specific file's cache entry.
136
+ */
137
+ invalidate(repoId: string, filePath: string): void;
138
+ /**
139
+ * Invalidate all cache entries for a repo.
140
+ */
141
+ invalidateRepo(repoId: string): void;
142
+ /**
143
+ * Clear all cache entries.
144
+ */
145
+ clear(): void;
146
+ /**
147
+ * Get cache statistics.
148
+ */
149
+ getStats(): CacheStats;
150
+ }
151
+ //# sourceMappingURL=interfaces.d.ts.map