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,193 @@
1
+ /**
2
+ * Circuit breaker pattern for external service calls.
3
+ *
4
+ * States:
5
+ * CLOSED — normal operation, failures are counted
6
+ * OPEN — failing, all calls rejected immediately after failureThreshold reached
7
+ * HALF_OPEN — testing recovery, one probe request allowed
8
+ *
9
+ * Transitions:
10
+ * CLOSED → OPEN after failureThreshold consecutive failures
11
+ * OPEN → HALF_OPEN after resetTimeoutMs has elapsed
12
+ * HALF_OPEN → CLOSED if the probe request succeeds
13
+ * HALF_OPEN → OPEN if the probe request fails
14
+ */
15
+
16
+ import { logger } from './logger.js';
17
+
18
+ export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
19
+
20
+ export interface CircuitBreakerOptions {
21
+ /** Number of consecutive failures before tripping to OPEN. Default: 5 */
22
+ failureThreshold?: number;
23
+ /** Milliseconds to wait in OPEN before transitioning to HALF_OPEN. Default: 30000 */
24
+ resetTimeoutMs?: number;
25
+ /** Name for log messages. */
26
+ name: string;
27
+ }
28
+
29
+ export class CircuitBreaker {
30
+ private state: CircuitState = 'CLOSED';
31
+ private consecutiveFailures = 0;
32
+ private lastFailureTime = 0;
33
+ private halfOpenProbeInFlight = false;
34
+
35
+ private readonly failureThreshold: number;
36
+ private readonly resetTimeoutMs: number;
37
+ private readonly name: string;
38
+
39
+ constructor(opts: CircuitBreakerOptions) {
40
+ this.name = opts.name;
41
+ this.failureThreshold = opts.failureThreshold ?? 5;
42
+ this.resetTimeoutMs = opts.resetTimeoutMs ?? 30_000;
43
+ }
44
+
45
+ /**
46
+ * Current state of the circuit breaker.
47
+ */
48
+ getState(): CircuitState {
49
+ this.maybeTransitionToHalfOpen();
50
+ return this.state;
51
+ }
52
+
53
+ /**
54
+ * Returns true when the breaker allows the call to proceed.
55
+ * Returns false when OPEN (or HALF_OPEN but a probe is already in flight).
56
+ */
57
+ isAllowed(): boolean {
58
+ this.maybeTransitionToHalfOpen();
59
+
60
+ if (this.state === 'CLOSED') return true;
61
+
62
+ if (this.state === 'HALF_OPEN') {
63
+ // Allow exactly one probe through
64
+ if (!this.halfOpenProbeInFlight) {
65
+ this.halfOpenProbeInFlight = true;
66
+ return true;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ // OPEN — reject
72
+ return false;
73
+ }
74
+
75
+ /**
76
+ * Call this when a protected operation succeeds.
77
+ */
78
+ recordSuccess(): void {
79
+ // Ensure state is up to date before evaluating
80
+ this.maybeTransitionToHalfOpen();
81
+
82
+ if (this.state === 'HALF_OPEN') {
83
+ logger.info(`Circuit breaker [${this.name}] recovered — closing`, {
84
+ previousFailures: this.consecutiveFailures,
85
+ });
86
+ this.transitionTo('CLOSED');
87
+ }
88
+ this.consecutiveFailures = 0;
89
+ this.halfOpenProbeInFlight = false;
90
+ }
91
+
92
+ /**
93
+ * Call this when a protected operation fails.
94
+ */
95
+ recordFailure(): void {
96
+ // Ensure state is up to date before evaluating
97
+ this.maybeTransitionToHalfOpen();
98
+
99
+ this.consecutiveFailures++;
100
+ this.lastFailureTime = Date.now();
101
+ this.halfOpenProbeInFlight = false;
102
+
103
+ if (this.state === 'HALF_OPEN') {
104
+ logger.warn(`Circuit breaker [${this.name}] probe failed — re-opening`, {
105
+ consecutiveFailures: this.consecutiveFailures,
106
+ });
107
+ this.transitionTo('OPEN');
108
+ return;
109
+ }
110
+
111
+ if (this.state === 'CLOSED' && this.consecutiveFailures >= this.failureThreshold) {
112
+ logger.warn(`Circuit breaker [${this.name}] tripped OPEN`, {
113
+ consecutiveFailures: this.consecutiveFailures,
114
+ failureThreshold: this.failureThreshold,
115
+ resetTimeoutMs: this.resetTimeoutMs,
116
+ });
117
+ this.transitionTo('OPEN');
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Execute a function with circuit breaker protection.
123
+ * Throws CircuitOpenError if the circuit is open.
124
+ * Automatically records success/failure.
125
+ */
126
+ async execute<T>(fn: () => Promise<T>): Promise<T> {
127
+ if (!this.isAllowed()) {
128
+ throw new CircuitOpenError(
129
+ `Circuit breaker [${this.name}] is OPEN — request rejected`
130
+ );
131
+ }
132
+
133
+ try {
134
+ const result = await fn();
135
+ this.recordSuccess();
136
+ return result;
137
+ } catch (err) {
138
+ this.recordFailure();
139
+ throw err;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Convenience: returns true when the circuit is healthy enough to allow requests.
145
+ * Equivalent to `isAllowed()` but does not reserve the HALF_OPEN probe slot.
146
+ */
147
+ isHealthy(): boolean {
148
+ this.maybeTransitionToHalfOpen();
149
+ return this.state === 'CLOSED' || this.state === 'HALF_OPEN';
150
+ }
151
+
152
+ /**
153
+ * Force-reset the breaker to CLOSED state. Useful for testing or manual recovery.
154
+ */
155
+ reset(): void {
156
+ logger.info(`Circuit breaker [${this.name}] manually reset`);
157
+ this.transitionTo('CLOSED');
158
+ this.consecutiveFailures = 0;
159
+ this.halfOpenProbeInFlight = false;
160
+ }
161
+
162
+ /** Internal: check if we should transition from OPEN to HALF_OPEN due to timeout. */
163
+ private maybeTransitionToHalfOpen(): void {
164
+ if (
165
+ this.state === 'OPEN' &&
166
+ Date.now() - this.lastFailureTime >= this.resetTimeoutMs
167
+ ) {
168
+ logger.info(`Circuit breaker [${this.name}] entering HALF_OPEN — probing`, {
169
+ elapsed: Date.now() - this.lastFailureTime,
170
+ resetTimeoutMs: this.resetTimeoutMs,
171
+ });
172
+ this.transitionTo('HALF_OPEN');
173
+ }
174
+ }
175
+
176
+ private transitionTo(next: CircuitState): void {
177
+ this.state = next;
178
+ if (next === 'CLOSED') {
179
+ this.lastFailureTime = 0;
180
+ this.halfOpenProbeInFlight = false;
181
+ }
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Thrown when a call is rejected because the circuit is open.
187
+ */
188
+ export class CircuitOpenError extends Error {
189
+ constructor(message: string) {
190
+ super(message);
191
+ this.name = 'CircuitOpenError';
192
+ }
193
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Configuration loading from env vars + YAML files.
3
+ * Priority: env vars > YAML config > hardcoded defaults.
4
+ */
5
+
6
+ import { readFileSync, existsSync } from 'fs';
7
+ import { resolve } from 'path';
8
+ import { parse as parseYaml } from 'yaml';
9
+ import type { AppConfig, RepoConfig } from './types.js';
10
+ import { logger } from './logger.js';
11
+
12
+ const DEFAULT_CONFIG: AppConfig = {
13
+ server: {
14
+ name: 'forge-knowledge',
15
+ version: '0.1.0',
16
+ transport: 'stdio',
17
+ },
18
+ embedding: {
19
+ model: 'Xenova/all-MiniLM-L6-v2',
20
+ dimension: 384,
21
+ batch_size: 32,
22
+ },
23
+ cache: {
24
+ max_size_mb: 100,
25
+ max_entries: 2000,
26
+ ttl_minutes: 30,
27
+ },
28
+ watcher: {
29
+ debounce_ms: 500,
30
+ ignored_patterns: [
31
+ '**/node_modules/**',
32
+ '**/.git/**',
33
+ '**/dist/**',
34
+ '**/build/**',
35
+ '**/*.map',
36
+ '**/package-lock.json',
37
+ ],
38
+ watched_extensions: [
39
+ '.ts', '.tsx', '.js', '.jsx', '.mts', '.cts',
40
+ '.json', '.yaml', '.yml', '.md', '.graphql', '.sql',
41
+ ],
42
+ },
43
+ indexing: {
44
+ max_file_size_kb: 500,
45
+ chunk_max_tokens: 1024,
46
+ chunk_overlap_tokens: 64,
47
+ git_history_depth: 500,
48
+ },
49
+ graph: {
50
+ name: 'forge_knowledge',
51
+ query_timeout_ms: 5000,
52
+ },
53
+ vector: {
54
+ code_chunks_collection: 'code_chunks',
55
+ observations_collection: 'observations',
56
+ hnsw_m: 16,
57
+ hnsw_ef_construct: 100,
58
+ on_disk_payload: true,
59
+ },
60
+ knowledge_routing: {
61
+ default_ownership: 'external',
62
+ },
63
+ repos: [],
64
+ };
65
+
66
+ let loadedConfig: AppConfig | null = null;
67
+
68
+ /**
69
+ * Load and merge configuration from YAML + env vars.
70
+ * Cached after first load.
71
+ */
72
+ export function loadConfig(): AppConfig {
73
+ if (loadedConfig) return loadedConfig;
74
+
75
+ let config = { ...DEFAULT_CONFIG };
76
+
77
+ // Load YAML config
78
+ const configPath = process.env.REPOS_CONFIG
79
+ ? resolve(process.env.REPOS_CONFIG)
80
+ : resolve('./config/default.yaml');
81
+
82
+ const reposPath = process.env.REPOS_CONFIG
83
+ ? process.env.REPOS_CONFIG
84
+ : resolve('./config/repos.yaml');
85
+
86
+ if (existsSync(configPath)) {
87
+ try {
88
+ const yamlContent = readFileSync(configPath, 'utf8');
89
+ const yamlConfig = parseYaml(yamlContent) as Partial<AppConfig>;
90
+ config = deepMerge(config, yamlConfig) as AppConfig;
91
+ } catch (err) {
92
+ logger.warn(`Failed to load config from ${configPath}`, { error: String(err) });
93
+ }
94
+ }
95
+
96
+ // Load repos config separately
97
+ if (existsSync(reposPath)) {
98
+ try {
99
+ const reposContent = readFileSync(reposPath, 'utf8');
100
+ const reposYaml = parseYaml(reposContent) as { repos?: RepoConfig[] };
101
+ if (reposYaml.repos) {
102
+ config.repos = reposYaml.repos;
103
+ }
104
+ } catch (err) {
105
+ logger.warn(`Failed to load repos config from ${reposPath}`, { error: String(err) });
106
+ }
107
+ }
108
+
109
+ // Override with env vars
110
+ config = applyEnvOverrides(config);
111
+
112
+ loadedConfig = config;
113
+ return config;
114
+ }
115
+
116
+ /**
117
+ * Get connection URLs from config/env.
118
+ */
119
+ export function getConnectionConfig(): {
120
+ falkordbUrl: string;
121
+ qdrantUrl: string;
122
+ graphName: string;
123
+ } {
124
+ return {
125
+ falkordbUrl: process.env.FALKORDB_URL ?? 'redis://localhost:6380',
126
+ qdrantUrl: process.env.QDRANT_URL ?? 'http://localhost:6333',
127
+ graphName: process.env.GRAPH_NAME ?? 'forge_knowledge',
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Get the default repo ID (first repo in config, or from env).
133
+ */
134
+ export function getDefaultRepoId(config: AppConfig): string | undefined {
135
+ const envRepo = process.env.DEFAULT_REPO_ID;
136
+ if (envRepo) return envRepo;
137
+ return config.repos[0]?.id;
138
+ }
139
+
140
+ function applyEnvOverrides(config: AppConfig): AppConfig {
141
+ if (process.env.LOG_LEVEL) {
142
+ // Log level handled by logger module
143
+ }
144
+ if (process.env.EMBEDDING_MODEL) {
145
+ config.embedding.model = process.env.EMBEDDING_MODEL;
146
+ }
147
+ if (process.env.EMBEDDING_DIMENSION) {
148
+ config.embedding.dimension = parseInt(process.env.EMBEDDING_DIMENSION, 10);
149
+ }
150
+ if (process.env.CACHE_MAX_SIZE_MB) {
151
+ config.cache.max_size_mb = parseInt(process.env.CACHE_MAX_SIZE_MB, 10);
152
+ }
153
+ if (process.env.CACHE_TTL_MINUTES) {
154
+ config.cache.ttl_minutes = parseInt(process.env.CACHE_TTL_MINUTES, 10);
155
+ }
156
+ if (process.env.GRAPH_NAME) {
157
+ config.graph.name = process.env.GRAPH_NAME;
158
+ }
159
+ if (process.env.WATCHER_DEBOUNCE_MS) {
160
+ config.watcher.debounce_ms = parseInt(process.env.WATCHER_DEBOUNCE_MS, 10);
161
+ }
162
+ return config;
163
+ }
164
+
165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
166
+ function deepMerge(target: any, source: any): any {
167
+ if (!source || typeof source !== 'object') return target;
168
+ const result = { ...target };
169
+ for (const key of Object.keys(source)) {
170
+ if (source[key] !== null && typeof source[key] === 'object' && !Array.isArray(source[key])) {
171
+ result[key] = deepMerge(target[key] ?? {}, source[key]);
172
+ } else if (source[key] !== undefined) {
173
+ result[key] = source[key];
174
+ }
175
+ }
176
+ return result;
177
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Structured logger for dk-forge-server
3
+ */
4
+
5
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
6
+
7
+ const LOG_LEVELS: Record<LogLevel, number> = {
8
+ debug: 0,
9
+ info: 1,
10
+ warn: 2,
11
+ error: 3,
12
+ };
13
+
14
+ let currentLevel: LogLevel = 'info';
15
+
16
+ export function setLogLevel(level: LogLevel): void {
17
+ currentLevel = level;
18
+ }
19
+
20
+ function shouldLog(level: LogLevel): boolean {
21
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
22
+ }
23
+
24
+ function formatMessage(level: LogLevel, message: string, meta?: unknown): string {
25
+ const ts = new Date().toISOString();
26
+ const metaStr = meta !== undefined ? ' ' + JSON.stringify(meta) : '';
27
+ return `[${ts}] [${level.toUpperCase()}] ${message}${metaStr}`;
28
+ }
29
+
30
+ export const logger = {
31
+ debug(message: string, meta?: unknown): void {
32
+ if (shouldLog('debug')) {
33
+ process.stderr.write(formatMessage('debug', message, meta) + '\n');
34
+ }
35
+ },
36
+ info(message: string, meta?: unknown): void {
37
+ if (shouldLog('info')) {
38
+ process.stderr.write(formatMessage('info', message, meta) + '\n');
39
+ }
40
+ },
41
+ warn(message: string, meta?: unknown): void {
42
+ if (shouldLog('warn')) {
43
+ process.stderr.write(formatMessage('warn', message, meta) + '\n');
44
+ }
45
+ },
46
+ error(message: string, meta?: unknown): void {
47
+ if (shouldLog('error')) {
48
+ process.stderr.write(formatMessage('error', message, meta) + '\n');
49
+ }
50
+ },
51
+ };
52
+
53
+ export default logger;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Approximate token counter.
3
+ * Uses char_count / 4 heuristic - good enough for budget control.
4
+ * No external dependencies.
5
+ */
6
+
7
+ /**
8
+ * Estimate token count for a string.
9
+ * Heuristic: ~4 characters per token (GPT-style tokenization average).
10
+ */
11
+ export function estimateTokens(text: string): number {
12
+ if (!text) return 0;
13
+ return Math.ceil(text.length / 4);
14
+ }
15
+
16
+ /**
17
+ * Estimate token count for an array of strings (summed).
18
+ */
19
+ export function estimateTokensForArray(texts: string[]): number {
20
+ return texts.reduce((sum, text) => sum + estimateTokens(text), 0);
21
+ }
22
+
23
+ /**
24
+ * Check if content fits within a token budget.
25
+ */
26
+ export function fitsInBudget(text: string, budgetTokens: number): boolean {
27
+ return estimateTokens(text) <= budgetTokens;
28
+ }
29
+
30
+ /**
31
+ * Truncate text to approximately fit within a token budget.
32
+ * Truncates at word boundary when possible.
33
+ */
34
+ export function truncateToTokenBudget(text: string, maxTokens: number): string {
35
+ const maxChars = maxTokens * 4;
36
+ if (text.length <= maxChars) return text;
37
+
38
+ // Try to truncate at a newline boundary
39
+ const truncated = text.slice(0, maxChars);
40
+ const lastNewline = truncated.lastIndexOf('\n');
41
+ if (lastNewline > maxChars * 0.8) {
42
+ return truncated.slice(0, lastNewline) + '\n... [truncated]';
43
+ }
44
+
45
+ // Fall back to word boundary
46
+ const lastSpace = truncated.lastIndexOf(' ');
47
+ if (lastSpace > maxChars * 0.8) {
48
+ return truncated.slice(0, lastSpace) + ' ... [truncated]';
49
+ }
50
+
51
+ return truncated + '... [truncated]';
52
+ }