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,320 @@
1
+ // edge-collector.ts — Forge LSP Bridge
2
+ // On file save, uses VS Code's built-in call hierarchy API to collect
3
+ // type-resolved CALLS edges from the TypeScript Language Server.
4
+ // Edges are batched and flushed to the forge server after a debounce period.
5
+
6
+ import * as vscode from 'vscode';
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Types
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export interface LspEdge {
13
+ from_file: string;
14
+ from_symbol: string;
15
+ to_file: string;
16
+ to_symbol: string;
17
+ edge_type: string;
18
+ }
19
+
20
+ export type FlushCallback = (edges: LspEdge[]) => Promise<void>;
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // EdgeCollector
24
+ // ---------------------------------------------------------------------------
25
+
26
+ export class EdgeCollector {
27
+ private pendingEdges: LspEdge[] = [];
28
+ private debounceTimer: ReturnType<typeof setTimeout> | undefined;
29
+ private debounceMs: number;
30
+ private readonly flushCallback: FlushCallback;
31
+ private flushing = false;
32
+
33
+ constructor(debounceMs: number, flushCallback: FlushCallback) {
34
+ this.debounceMs = debounceMs;
35
+ this.flushCallback = flushCallback;
36
+ }
37
+
38
+ /**
39
+ * Update the debounce interval (e.g. when the user changes settings).
40
+ */
41
+ setDebounceMs(ms: number): void {
42
+ this.debounceMs = ms;
43
+ }
44
+
45
+ /**
46
+ * Collect call-hierarchy edges for all functions/methods in a saved document.
47
+ */
48
+ async collectFromDocument(document: vscode.TextDocument): Promise<void> {
49
+ const uri = document.uri;
50
+
51
+ // Get all document symbols to find functions, methods, constructors
52
+ const symbols = await this.getCallableSymbols(uri);
53
+
54
+ if (symbols.length === 0) {
55
+ return;
56
+ }
57
+
58
+ // For each callable symbol, prepare a call hierarchy and collect outgoing calls
59
+ for (const sym of symbols) {
60
+ try {
61
+ const edges = await this.collectOutgoingCalls(uri, sym);
62
+ if (edges.length > 0) {
63
+ this.pendingEdges.push(...edges);
64
+ }
65
+ } catch {
66
+ // Individual symbol failures are non-fatal — skip and continue.
67
+ // This can happen if the TS language server hasn't finished loading
68
+ // or if the symbol is in an unsupported position.
69
+ }
70
+ }
71
+
72
+ // Reset the debounce timer
73
+ this.scheduleFlush();
74
+ }
75
+
76
+ /**
77
+ * Force an immediate flush of all pending edges, regardless of debounce.
78
+ */
79
+ async flushNow(): Promise<void> {
80
+ this.cancelDebounce();
81
+ await this.doFlush();
82
+ }
83
+
84
+ // -------------------------------------------------------------------------
85
+ // Symbol discovery
86
+ // -------------------------------------------------------------------------
87
+
88
+ /**
89
+ * Flatten the document symbol tree and return only callable symbols
90
+ * (functions, methods, constructors).
91
+ */
92
+ private async getCallableSymbols(
93
+ uri: vscode.Uri,
94
+ ): Promise<FlatSymbol[]> {
95
+ let rawSymbols: vscode.DocumentSymbol[] | undefined;
96
+ try {
97
+ rawSymbols = await vscode.commands.executeCommand<vscode.DocumentSymbol[]>(
98
+ 'vscode.executeDocumentSymbolProvider',
99
+ uri,
100
+ );
101
+ } catch {
102
+ return [];
103
+ }
104
+
105
+ if (!rawSymbols || rawSymbols.length === 0) {
106
+ return [];
107
+ }
108
+
109
+ const result: FlatSymbol[] = [];
110
+ this.flattenSymbols(rawSymbols, uri, result, undefined);
111
+ return result;
112
+ }
113
+
114
+ /**
115
+ * Recursively flatten nested DocumentSymbols into a flat list of callable
116
+ * symbols. Tracks parent name to build qualified symbol names like
117
+ * "ClassName.methodName".
118
+ */
119
+ private flattenSymbols(
120
+ symbols: vscode.DocumentSymbol[],
121
+ uri: vscode.Uri,
122
+ out: FlatSymbol[],
123
+ parentName: string | undefined,
124
+ ): void {
125
+ for (const sym of symbols) {
126
+ const qualifiedName = parentName
127
+ ? `${parentName}.${sym.name}`
128
+ : sym.name;
129
+
130
+ if (isCallable(sym.kind)) {
131
+ out.push({
132
+ name: qualifiedName,
133
+ kind: sym.kind,
134
+ range: sym.selectionRange,
135
+ uri,
136
+ });
137
+ }
138
+
139
+ // Recurse into children (e.g. methods inside a class)
140
+ if (sym.children && sym.children.length > 0) {
141
+ const nextParent =
142
+ sym.kind === vscode.SymbolKind.Class ||
143
+ sym.kind === vscode.SymbolKind.Interface ||
144
+ sym.kind === vscode.SymbolKind.Namespace ||
145
+ sym.kind === vscode.SymbolKind.Module
146
+ ? qualifiedName
147
+ : parentName;
148
+ this.flattenSymbols(sym.children, uri, out, nextParent);
149
+ }
150
+ }
151
+ }
152
+
153
+ // -------------------------------------------------------------------------
154
+ // Call hierarchy collection
155
+ // -------------------------------------------------------------------------
156
+
157
+ /**
158
+ * For a single callable symbol, prepare a call hierarchy item and collect
159
+ * its outgoing calls. Returns LspEdge[] for "CALLS" relationships.
160
+ */
161
+ private async collectOutgoingCalls(
162
+ uri: vscode.Uri,
163
+ sym: FlatSymbol,
164
+ ): Promise<LspEdge[]> {
165
+ // Prepare call hierarchy at the symbol's selection position
166
+ const position = sym.range.start;
167
+ let callItems: vscode.CallHierarchyItem[] | undefined;
168
+
169
+ try {
170
+ callItems = await vscode.commands.executeCommand<vscode.CallHierarchyItem[]>(
171
+ 'vscode.prepareCallHierarchy',
172
+ uri,
173
+ position,
174
+ );
175
+ } catch {
176
+ return [];
177
+ }
178
+
179
+ if (!callItems || callItems.length === 0) {
180
+ return [];
181
+ }
182
+
183
+ const edges: LspEdge[] = [];
184
+
185
+ for (const item of callItems) {
186
+ let outgoingCalls: vscode.CallHierarchyOutgoingCall[] | undefined;
187
+ try {
188
+ outgoingCalls = await vscode.commands.executeCommand<vscode.CallHierarchyOutgoingCall[]>(
189
+ 'vscode.provideOutgoingCalls',
190
+ item,
191
+ );
192
+ } catch {
193
+ continue;
194
+ }
195
+
196
+ if (!outgoingCalls || outgoingCalls.length === 0) {
197
+ continue;
198
+ }
199
+
200
+ const fromFile = normalizeFilePath(item.uri.fsPath);
201
+ const fromSymbol = item.name;
202
+
203
+ for (const call of outgoingCalls) {
204
+ const toFile = normalizeFilePath(call.to.uri.fsPath);
205
+ const toSymbol = call.to.name;
206
+
207
+ // Skip self-references and node_modules
208
+ if (fromSymbol === toSymbol && fromFile === toFile) {
209
+ continue;
210
+ }
211
+ if (toFile.includes('node_modules')) {
212
+ continue;
213
+ }
214
+
215
+ edges.push({
216
+ from_file: fromFile,
217
+ from_symbol: fromSymbol,
218
+ to_file: toFile,
219
+ to_symbol: toSymbol,
220
+ edge_type: 'CALLS',
221
+ });
222
+ }
223
+ }
224
+
225
+ return edges;
226
+ }
227
+
228
+ // -------------------------------------------------------------------------
229
+ // Debounced flush
230
+ // -------------------------------------------------------------------------
231
+
232
+ private scheduleFlush(): void {
233
+ this.cancelDebounce();
234
+ this.debounceTimer = setTimeout(() => {
235
+ void this.doFlush();
236
+ }, this.debounceMs);
237
+ }
238
+
239
+ private cancelDebounce(): void {
240
+ if (this.debounceTimer !== undefined) {
241
+ clearTimeout(this.debounceTimer);
242
+ this.debounceTimer = undefined;
243
+ }
244
+ }
245
+
246
+ private async doFlush(): Promise<void> {
247
+ if (this.flushing) {
248
+ // Re-schedule if a flush is already in progress
249
+ this.scheduleFlush();
250
+ return;
251
+ }
252
+
253
+ if (this.pendingEdges.length === 0) {
254
+ return;
255
+ }
256
+
257
+ // Take ownership of the pending edges
258
+ const batch = this.pendingEdges;
259
+ this.pendingEdges = [];
260
+ this.flushing = true;
261
+
262
+ try {
263
+ // Deduplicate edges within the batch
264
+ const deduplicated = deduplicateEdges(batch);
265
+ await this.flushCallback(deduplicated);
266
+ } catch {
267
+ // If flush fails, re-queue the edges for the next attempt
268
+ this.pendingEdges.unshift(...batch);
269
+ } finally {
270
+ this.flushing = false;
271
+ }
272
+ }
273
+ }
274
+
275
+ // ---------------------------------------------------------------------------
276
+ // Helpers
277
+ // ---------------------------------------------------------------------------
278
+
279
+ interface FlatSymbol {
280
+ name: string;
281
+ kind: vscode.SymbolKind;
282
+ range: vscode.Range;
283
+ uri: vscode.Uri;
284
+ }
285
+
286
+ /**
287
+ * Returns true if the symbol kind represents something that can make calls.
288
+ */
289
+ function isCallable(kind: vscode.SymbolKind): boolean {
290
+ return (
291
+ kind === vscode.SymbolKind.Function ||
292
+ kind === vscode.SymbolKind.Method ||
293
+ kind === vscode.SymbolKind.Constructor
294
+ );
295
+ }
296
+
297
+ /**
298
+ * Normalize file paths to use forward slashes for consistency.
299
+ */
300
+ function normalizeFilePath(filePath: string): string {
301
+ return filePath.replace(/\\/g, '/');
302
+ }
303
+
304
+ /**
305
+ * Remove duplicate edges within a batch (same from/to file+symbol+type).
306
+ */
307
+ function deduplicateEdges(edges: LspEdge[]): LspEdge[] {
308
+ const seen = new Set<string>();
309
+ const result: LspEdge[] = [];
310
+
311
+ for (const edge of edges) {
312
+ const key = `${edge.from_file}:${edge.from_symbol}->${edge.to_file}:${edge.to_symbol}:${edge.edge_type}`;
313
+ if (!seen.has(key)) {
314
+ seen.add(key);
315
+ result.push(edge);
316
+ }
317
+ }
318
+
319
+ return result;
320
+ }
@@ -0,0 +1,269 @@
1
+ // extension.ts — Forge LSP Bridge
2
+ // VS Code extension entry point. Hooks into file-save events for TS/JS files,
3
+ // collects LSP-resolved call edges via the edge collector, and flushes them
4
+ // to the dk-forge MCP server via the forge client.
5
+
6
+ import * as vscode from 'vscode';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs';
9
+ import { EdgeCollector } from './edge-collector';
10
+ import { ForgeClient } from './forge-client';
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // State
14
+ // ---------------------------------------------------------------------------
15
+
16
+ let edgeCollector: EdgeCollector | undefined;
17
+ let forgeClient: ForgeClient | undefined;
18
+ let statusBarItem: vscode.StatusBarItem | undefined;
19
+ let saveListener: vscode.Disposable | undefined;
20
+ let enabled = true;
21
+ let repoId = '';
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Activation
25
+ // ---------------------------------------------------------------------------
26
+
27
+ export async function activate(context: vscode.ExtensionContext): Promise<void> {
28
+ const config = vscode.workspace.getConfiguration('forge.lspBridge');
29
+ enabled = config.get<boolean>('enabled', true);
30
+
31
+ // Auto-detect repo ID from .forge/manifest.yaml if not configured
32
+ repoId = config.get<string>('repoId', '') || '';
33
+ if (!repoId) {
34
+ repoId = await detectRepoId();
35
+ }
36
+
37
+ const debounceMs = config.get<number>('debounceMs', 5000);
38
+ const mcpServerPath = config.get<string>('mcpServerPath', '') || '';
39
+
40
+ // Initialize forge MCP client
41
+ forgeClient = new ForgeClient(mcpServerPath);
42
+
43
+ // Initialize edge collector with flush callback
44
+ edgeCollector = new EdgeCollector(debounceMs, async (edges) => {
45
+ if (!forgeClient || !repoId) {
46
+ return;
47
+ }
48
+ try {
49
+ const result = await forgeClient.submitLspEdges(repoId, edges);
50
+ if (result && typeof result.accepted === 'number') {
51
+ log(`Flushed ${result.accepted} edges (${result.failed ?? 0} failed)`);
52
+ }
53
+ } catch (err) {
54
+ log(`Flush failed: ${String(err)}`);
55
+ }
56
+ });
57
+
58
+ // Status bar item
59
+ statusBarItem = vscode.window.createStatusBarItem(
60
+ vscode.StatusBarAlignment.Right,
61
+ 50,
62
+ );
63
+ statusBarItem.command = 'forge.lspBridge.toggle';
64
+ updateStatusBar();
65
+ statusBarItem.show();
66
+ context.subscriptions.push(statusBarItem);
67
+
68
+ // Register the save listener
69
+ if (enabled) {
70
+ registerSaveListener(context);
71
+ }
72
+
73
+ // Register commands
74
+ context.subscriptions.push(
75
+ vscode.commands.registerCommand('forge.lspBridge.toggle', () => {
76
+ enabled = !enabled;
77
+ if (enabled) {
78
+ registerSaveListener(context);
79
+ log('Enabled');
80
+ } else {
81
+ disposeSaveListener();
82
+ log('Disabled');
83
+ }
84
+ updateStatusBar();
85
+ }),
86
+ );
87
+
88
+ context.subscriptions.push(
89
+ vscode.commands.registerCommand('forge.lspBridge.flush', async () => {
90
+ if (!edgeCollector) {
91
+ return;
92
+ }
93
+ await edgeCollector.flushNow();
94
+ log('Manual flush complete');
95
+ }),
96
+ );
97
+
98
+ // Watch for configuration changes
99
+ context.subscriptions.push(
100
+ vscode.workspace.onDidChangeConfiguration((e) => {
101
+ if (e.affectsConfiguration('forge.lspBridge')) {
102
+ const newConfig = vscode.workspace.getConfiguration('forge.lspBridge');
103
+ const newEnabled = newConfig.get<boolean>('enabled', true);
104
+ const newRepoId = newConfig.get<string>('repoId', '') || '';
105
+ const newDebounce = newConfig.get<number>('debounceMs', 5000);
106
+
107
+ if (newRepoId) {
108
+ repoId = newRepoId;
109
+ }
110
+
111
+ if (edgeCollector) {
112
+ edgeCollector.setDebounceMs(newDebounce);
113
+ }
114
+
115
+ if (newEnabled !== enabled) {
116
+ enabled = newEnabled;
117
+ if (enabled) {
118
+ registerSaveListener(context);
119
+ } else {
120
+ disposeSaveListener();
121
+ }
122
+ updateStatusBar();
123
+ }
124
+ }
125
+ }),
126
+ );
127
+
128
+ log(`Activated (repoId: ${repoId || '<none>'}, debounce: ${debounceMs}ms)`);
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Deactivation
133
+ // ---------------------------------------------------------------------------
134
+
135
+ export async function deactivate(): Promise<void> {
136
+ disposeSaveListener();
137
+
138
+ // Flush any remaining edges
139
+ if (edgeCollector) {
140
+ try {
141
+ await edgeCollector.flushNow();
142
+ } catch {
143
+ // Ignore errors during deactivation
144
+ }
145
+ }
146
+
147
+ // Dispose the forge client (kills the child process)
148
+ if (forgeClient) {
149
+ forgeClient.dispose();
150
+ forgeClient = undefined;
151
+ }
152
+
153
+ if (statusBarItem) {
154
+ statusBarItem.dispose();
155
+ statusBarItem = undefined;
156
+ }
157
+
158
+ edgeCollector = undefined;
159
+ }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Internal helpers
163
+ // ---------------------------------------------------------------------------
164
+
165
+ const SUPPORTED_LANGUAGES = new Set([
166
+ 'typescript',
167
+ 'javascript',
168
+ 'typescriptreact',
169
+ 'javascriptreact',
170
+ ]);
171
+
172
+ function registerSaveListener(context: vscode.ExtensionContext): void {
173
+ disposeSaveListener();
174
+
175
+ saveListener = vscode.workspace.onDidSaveTextDocument(async (document) => {
176
+ if (!enabled || !edgeCollector) {
177
+ return;
178
+ }
179
+
180
+ if (!SUPPORTED_LANGUAGES.has(document.languageId)) {
181
+ return;
182
+ }
183
+
184
+ try {
185
+ await edgeCollector.collectFromDocument(document);
186
+ } catch (err) {
187
+ // Never let a collection error propagate to the save flow
188
+ log(`Collection error for ${document.fileName}: ${String(err)}`);
189
+ }
190
+ });
191
+
192
+ context.subscriptions.push(saveListener);
193
+ }
194
+
195
+ function disposeSaveListener(): void {
196
+ if (saveListener) {
197
+ saveListener.dispose();
198
+ saveListener = undefined;
199
+ }
200
+ }
201
+
202
+ function updateStatusBar(): void {
203
+ if (!statusBarItem) {
204
+ return;
205
+ }
206
+ if (enabled) {
207
+ statusBarItem.text = '$(symbol-method) Forge LSP';
208
+ statusBarItem.tooltip = 'Forge LSP Bridge: Active — click to toggle';
209
+ statusBarItem.backgroundColor = undefined;
210
+ } else {
211
+ statusBarItem.text = '$(circle-slash) Forge LSP';
212
+ statusBarItem.tooltip = 'Forge LSP Bridge: Disabled — click to toggle';
213
+ statusBarItem.backgroundColor = new vscode.ThemeColor(
214
+ 'statusBarItem.warningBackground',
215
+ );
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Detect the repo ID from .forge/manifest.yaml in the workspace root.
221
+ * Falls back to the workspace folder name, or empty string.
222
+ */
223
+ async function detectRepoId(): Promise<string> {
224
+ const folders = vscode.workspace.workspaceFolders;
225
+ if (!folders || folders.length === 0) {
226
+ return '';
227
+ }
228
+
229
+ for (const folder of folders) {
230
+ const manifestPath = path.join(folder.uri.fsPath, '.forge', 'manifest.yaml');
231
+ try {
232
+ if (fs.existsSync(manifestPath)) {
233
+ const content = fs.readFileSync(manifestPath, 'utf8');
234
+ // Simple YAML parsing — look for "name: <value>" line
235
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
236
+ if (nameMatch && nameMatch[1]) {
237
+ const name = nameMatch[1].trim();
238
+ if (name) {
239
+ return name;
240
+ }
241
+ }
242
+ // Check for repo_id_override
243
+ const overrideMatch = content.match(/^repo_id_override:\s*(.+)$/m);
244
+ if (overrideMatch && overrideMatch[1]) {
245
+ const override = overrideMatch[1].trim();
246
+ if (override && override !== 'null') {
247
+ return override;
248
+ }
249
+ }
250
+ }
251
+ } catch {
252
+ // Silently continue if the manifest can't be read
253
+ }
254
+ }
255
+
256
+ // Fallback: use the first workspace folder name
257
+ return folders[0]?.name ?? '';
258
+ }
259
+
260
+ // ---------------------------------------------------------------------------
261
+ // Logging
262
+ // ---------------------------------------------------------------------------
263
+
264
+ const outputChannel = vscode.window.createOutputChannel('Forge LSP Bridge');
265
+
266
+ function log(message: string): void {
267
+ const timestamp = new Date().toISOString();
268
+ outputChannel.appendLine(`[${timestamp}] ${message}`);
269
+ }