@hoangsonw/forge 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 (598) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +919 -0
  3. package/bin/forge.js +30 -0
  4. package/dist/agents/architect.d.ts +20 -0
  5. package/dist/agents/architect.d.ts.map +1 -0
  6. package/dist/agents/architect.js +75 -0
  7. package/dist/agents/architect.js.map +1 -0
  8. package/dist/agents/base.d.ts +20 -0
  9. package/dist/agents/base.d.ts.map +1 -0
  10. package/dist/agents/base.js +3 -0
  11. package/dist/agents/base.js.map +1 -0
  12. package/dist/agents/debugger.d.ts +16 -0
  13. package/dist/agents/debugger.d.ts.map +1 -0
  14. package/dist/agents/debugger.js +93 -0
  15. package/dist/agents/debugger.js.map +1 -0
  16. package/dist/agents/executor.d.ts +48 -0
  17. package/dist/agents/executor.d.ts.map +1 -0
  18. package/dist/agents/executor.js +402 -0
  19. package/dist/agents/executor.js.map +1 -0
  20. package/dist/agents/memory.d.ts +8 -0
  21. package/dist/agents/memory.d.ts.map +1 -0
  22. package/dist/agents/memory.js +84 -0
  23. package/dist/agents/memory.js.map +1 -0
  24. package/dist/agents/planner.d.ts +5 -0
  25. package/dist/agents/planner.d.ts.map +1 -0
  26. package/dist/agents/planner.js +185 -0
  27. package/dist/agents/planner.js.map +1 -0
  28. package/dist/agents/registry.d.ts +6 -0
  29. package/dist/agents/registry.d.ts.map +1 -0
  30. package/dist/agents/registry.js +32 -0
  31. package/dist/agents/registry.js.map +1 -0
  32. package/dist/agents/reviewer.d.ts +18 -0
  33. package/dist/agents/reviewer.d.ts.map +1 -0
  34. package/dist/agents/reviewer.js +87 -0
  35. package/dist/agents/reviewer.js.map +1 -0
  36. package/dist/classifier/classifier.d.ts +9 -0
  37. package/dist/classifier/classifier.d.ts.map +1 -0
  38. package/dist/classifier/classifier.js +83 -0
  39. package/dist/classifier/classifier.js.map +1 -0
  40. package/dist/classifier/heuristics.d.ts +11 -0
  41. package/dist/classifier/heuristics.d.ts.map +1 -0
  42. package/dist/classifier/heuristics.js +112 -0
  43. package/dist/classifier/heuristics.js.map +1 -0
  44. package/dist/cli/animations.d.ts +27 -0
  45. package/dist/cli/animations.d.ts.map +1 -0
  46. package/dist/cli/animations.js +186 -0
  47. package/dist/cli/animations.js.map +1 -0
  48. package/dist/cli/banners.d.ts +47 -0
  49. package/dist/cli/banners.d.ts.map +1 -0
  50. package/dist/cli/banners.js +211 -0
  51. package/dist/cli/banners.js.map +1 -0
  52. package/dist/cli/bootstrap.d.ts +2 -0
  53. package/dist/cli/bootstrap.d.ts.map +1 -0
  54. package/dist/cli/bootstrap.js +21 -0
  55. package/dist/cli/bootstrap.js.map +1 -0
  56. package/dist/cli/commands/bundle.d.ts +3 -0
  57. package/dist/cli/commands/bundle.d.ts.map +1 -0
  58. package/dist/cli/commands/bundle.js +80 -0
  59. package/dist/cli/commands/bundle.js.map +1 -0
  60. package/dist/cli/commands/changelog.d.ts +3 -0
  61. package/dist/cli/commands/changelog.d.ts.map +1 -0
  62. package/dist/cli/commands/changelog.js +60 -0
  63. package/dist/cli/commands/changelog.js.map +1 -0
  64. package/dist/cli/commands/config.d.ts +3 -0
  65. package/dist/cli/commands/config.d.ts.map +1 -0
  66. package/dist/cli/commands/config.js +91 -0
  67. package/dist/cli/commands/config.js.map +1 -0
  68. package/dist/cli/commands/container.d.ts +3 -0
  69. package/dist/cli/commands/container.d.ts.map +1 -0
  70. package/dist/cli/commands/container.js +149 -0
  71. package/dist/cli/commands/container.js.map +1 -0
  72. package/dist/cli/commands/cost.d.ts +3 -0
  73. package/dist/cli/commands/cost.d.ts.map +1 -0
  74. package/dist/cli/commands/cost.js +38 -0
  75. package/dist/cli/commands/cost.js.map +1 -0
  76. package/dist/cli/commands/daemon.d.ts +3 -0
  77. package/dist/cli/commands/daemon.d.ts.map +1 -0
  78. package/dist/cli/commands/daemon.js +39 -0
  79. package/dist/cli/commands/daemon.js.map +1 -0
  80. package/dist/cli/commands/dev.d.ts +3 -0
  81. package/dist/cli/commands/dev.d.ts.map +1 -0
  82. package/dist/cli/commands/dev.js +73 -0
  83. package/dist/cli/commands/dev.js.map +1 -0
  84. package/dist/cli/commands/doctor.d.ts +3 -0
  85. package/dist/cli/commands/doctor.d.ts.map +1 -0
  86. package/dist/cli/commands/doctor.js +214 -0
  87. package/dist/cli/commands/doctor.js.map +1 -0
  88. package/dist/cli/commands/init.d.ts +3 -0
  89. package/dist/cli/commands/init.d.ts.map +1 -0
  90. package/dist/cli/commands/init.js +148 -0
  91. package/dist/cli/commands/init.js.map +1 -0
  92. package/dist/cli/commands/mcp.d.ts +3 -0
  93. package/dist/cli/commands/mcp.d.ts.map +1 -0
  94. package/dist/cli/commands/mcp.js +227 -0
  95. package/dist/cli/commands/mcp.js.map +1 -0
  96. package/dist/cli/commands/memory.d.ts +3 -0
  97. package/dist/cli/commands/memory.d.ts.map +1 -0
  98. package/dist/cli/commands/memory.js +101 -0
  99. package/dist/cli/commands/memory.js.map +1 -0
  100. package/dist/cli/commands/migrate.d.ts +3 -0
  101. package/dist/cli/commands/migrate.d.ts.map +1 -0
  102. package/dist/cli/commands/migrate.js +18 -0
  103. package/dist/cli/commands/migrate.js.map +1 -0
  104. package/dist/cli/commands/model.d.ts +3 -0
  105. package/dist/cli/commands/model.d.ts.map +1 -0
  106. package/dist/cli/commands/model.js +37 -0
  107. package/dist/cli/commands/model.js.map +1 -0
  108. package/dist/cli/commands/permissions.d.ts +3 -0
  109. package/dist/cli/commands/permissions.d.ts.map +1 -0
  110. package/dist/cli/commands/permissions.js +32 -0
  111. package/dist/cli/commands/permissions.js.map +1 -0
  112. package/dist/cli/commands/resume.d.ts +3 -0
  113. package/dist/cli/commands/resume.d.ts.map +1 -0
  114. package/dist/cli/commands/resume.js +90 -0
  115. package/dist/cli/commands/resume.js.map +1 -0
  116. package/dist/cli/commands/run.d.ts +5 -0
  117. package/dist/cli/commands/run.d.ts.map +1 -0
  118. package/dist/cli/commands/run.js +164 -0
  119. package/dist/cli/commands/run.js.map +1 -0
  120. package/dist/cli/commands/session.d.ts +3 -0
  121. package/dist/cli/commands/session.d.ts.map +1 -0
  122. package/dist/cli/commands/session.js +94 -0
  123. package/dist/cli/commands/session.js.map +1 -0
  124. package/dist/cli/commands/skills.d.ts +4 -0
  125. package/dist/cli/commands/skills.d.ts.map +1 -0
  126. package/dist/cli/commands/skills.js +176 -0
  127. package/dist/cli/commands/skills.js.map +1 -0
  128. package/dist/cli/commands/spec.d.ts +3 -0
  129. package/dist/cli/commands/spec.d.ts.map +1 -0
  130. package/dist/cli/commands/spec.js +58 -0
  131. package/dist/cli/commands/spec.js.map +1 -0
  132. package/dist/cli/commands/status.d.ts +3 -0
  133. package/dist/cli/commands/status.d.ts.map +1 -0
  134. package/dist/cli/commands/status.js +65 -0
  135. package/dist/cli/commands/status.js.map +1 -0
  136. package/dist/cli/commands/task.d.ts +3 -0
  137. package/dist/cli/commands/task.d.ts.map +1 -0
  138. package/dist/cli/commands/task.js +42 -0
  139. package/dist/cli/commands/task.js.map +1 -0
  140. package/dist/cli/commands/ui.d.ts +3 -0
  141. package/dist/cli/commands/ui.d.ts.map +1 -0
  142. package/dist/cli/commands/ui.js +28 -0
  143. package/dist/cli/commands/ui.js.map +1 -0
  144. package/dist/cli/commands/update.d.ts +3 -0
  145. package/dist/cli/commands/update.d.ts.map +1 -0
  146. package/dist/cli/commands/update.js +53 -0
  147. package/dist/cli/commands/update.js.map +1 -0
  148. package/dist/cli/commands/web.d.ts +3 -0
  149. package/dist/cli/commands/web.d.ts.map +1 -0
  150. package/dist/cli/commands/web.js +42 -0
  151. package/dist/cli/commands/web.js.map +1 -0
  152. package/dist/cli/help.d.ts +21 -0
  153. package/dist/cli/help.d.ts.map +1 -0
  154. package/dist/cli/help.js +216 -0
  155. package/dist/cli/help.js.map +1 -0
  156. package/dist/cli/index.d.ts +3 -0
  157. package/dist/cli/index.d.ts.map +1 -0
  158. package/dist/cli/index.js +154 -0
  159. package/dist/cli/index.js.map +1 -0
  160. package/dist/cli/repl-commands.d.ts +47 -0
  161. package/dist/cli/repl-commands.d.ts.map +1 -0
  162. package/dist/cli/repl-commands.js +508 -0
  163. package/dist/cli/repl-commands.js.map +1 -0
  164. package/dist/cli/repl-input.d.ts +87 -0
  165. package/dist/cli/repl-input.d.ts.map +1 -0
  166. package/dist/cli/repl-input.js +764 -0
  167. package/dist/cli/repl-input.js.map +1 -0
  168. package/dist/cli/repl.d.ts +5 -0
  169. package/dist/cli/repl.d.ts.map +1 -0
  170. package/dist/cli/repl.js +1046 -0
  171. package/dist/cli/repl.js.map +1 -0
  172. package/dist/cli/ui.d.ts +19 -0
  173. package/dist/cli/ui.d.ts.map +1 -0
  174. package/dist/cli/ui.js +106 -0
  175. package/dist/cli/ui.js.map +1 -0
  176. package/dist/config/loader.d.ts +11 -0
  177. package/dist/config/loader.d.ts.map +1 -0
  178. package/dist/config/loader.js +132 -0
  179. package/dist/config/loader.js.map +1 -0
  180. package/dist/config/paths.d.ts +35 -0
  181. package/dist/config/paths.d.ts.map +1 -0
  182. package/dist/config/paths.js +114 -0
  183. package/dist/config/paths.js.map +1 -0
  184. package/dist/config/schema.d.ts +372 -0
  185. package/dist/config/schema.d.ts.map +1 -0
  186. package/dist/config/schema.js +161 -0
  187. package/dist/config/schema.js.map +1 -0
  188. package/dist/config/xdg.d.ts +2 -0
  189. package/dist/config/xdg.d.ts.map +1 -0
  190. package/dist/config/xdg.js +55 -0
  191. package/dist/config/xdg.js.map +1 -0
  192. package/dist/core/continuity.d.ts +8 -0
  193. package/dist/core/continuity.d.ts.map +1 -0
  194. package/dist/core/continuity.js +36 -0
  195. package/dist/core/continuity.js.map +1 -0
  196. package/dist/core/conversation.d.ts +152 -0
  197. package/dist/core/conversation.d.ts.map +1 -0
  198. package/dist/core/conversation.js +435 -0
  199. package/dist/core/conversation.js.map +1 -0
  200. package/dist/core/estimation.d.ts +19 -0
  201. package/dist/core/estimation.d.ts.map +1 -0
  202. package/dist/core/estimation.js +53 -0
  203. package/dist/core/estimation.js.map +1 -0
  204. package/dist/core/fork.d.ts +7 -0
  205. package/dist/core/fork.d.ts.map +1 -0
  206. package/dist/core/fork.js +93 -0
  207. package/dist/core/fork.js.map +1 -0
  208. package/dist/core/interactive-host.d.ts +28 -0
  209. package/dist/core/interactive-host.d.ts.map +1 -0
  210. package/dist/core/interactive-host.js +19 -0
  211. package/dist/core/interactive-host.js.map +1 -0
  212. package/dist/core/loop-detection.d.ts +25 -0
  213. package/dist/core/loop-detection.d.ts.map +1 -0
  214. package/dist/core/loop-detection.js +37 -0
  215. package/dist/core/loop-detection.js.map +1 -0
  216. package/dist/core/loop.d.ts +15 -0
  217. package/dist/core/loop.d.ts.map +1 -0
  218. package/dist/core/loop.js +417 -0
  219. package/dist/core/loop.js.map +1 -0
  220. package/dist/core/mode-policy.d.ts +33 -0
  221. package/dist/core/mode-policy.d.ts.map +1 -0
  222. package/dist/core/mode-policy.js +62 -0
  223. package/dist/core/mode-policy.js.map +1 -0
  224. package/dist/core/orchestrator.d.ts +14 -0
  225. package/dist/core/orchestrator.d.ts.map +1 -0
  226. package/dist/core/orchestrator.js +69 -0
  227. package/dist/core/orchestrator.js.map +1 -0
  228. package/dist/core/plan-fixer.d.ts +16 -0
  229. package/dist/core/plan-fixer.d.ts.map +1 -0
  230. package/dist/core/plan-fixer.js +55 -0
  231. package/dist/core/plan-fixer.js.map +1 -0
  232. package/dist/core/signals.d.ts +5 -0
  233. package/dist/core/signals.d.ts.map +1 -0
  234. package/dist/core/signals.js +44 -0
  235. package/dist/core/signals.js.map +1 -0
  236. package/dist/core/spec.d.ts +8 -0
  237. package/dist/core/spec.d.ts.map +1 -0
  238. package/dist/core/spec.js +75 -0
  239. package/dist/core/spec.js.map +1 -0
  240. package/dist/core/validation.d.ts +21 -0
  241. package/dist/core/validation.d.ts.map +1 -0
  242. package/dist/core/validation.js +126 -0
  243. package/dist/core/validation.js.map +1 -0
  244. package/dist/daemon/control.d.ts +9 -0
  245. package/dist/daemon/control.d.ts.map +1 -0
  246. package/dist/daemon/control.js +88 -0
  247. package/dist/daemon/control.js.map +1 -0
  248. package/dist/daemon/server.d.ts +8 -0
  249. package/dist/daemon/server.d.ts.map +1 -0
  250. package/dist/daemon/server.js +129 -0
  251. package/dist/daemon/server.js.map +1 -0
  252. package/dist/daemon/updater.d.ts +21 -0
  253. package/dist/daemon/updater.d.ts.map +1 -0
  254. package/dist/daemon/updater.js +159 -0
  255. package/dist/daemon/updater.js.map +1 -0
  256. package/dist/keychain/index.d.ts +8 -0
  257. package/dist/keychain/index.d.ts.map +1 -0
  258. package/dist/keychain/index.js +243 -0
  259. package/dist/keychain/index.js.map +1 -0
  260. package/dist/keychain/windows.d.ts +5 -0
  261. package/dist/keychain/windows.d.ts.map +1 -0
  262. package/dist/keychain/windows.js +65 -0
  263. package/dist/keychain/windows.js.map +1 -0
  264. package/dist/logging/logger.d.ts +12 -0
  265. package/dist/logging/logger.d.ts.map +1 -0
  266. package/dist/logging/logger.js +127 -0
  267. package/dist/logging/logger.js.map +1 -0
  268. package/dist/logging/rotation.d.ts +9 -0
  269. package/dist/logging/rotation.d.ts.map +1 -0
  270. package/dist/logging/rotation.js +85 -0
  271. package/dist/logging/rotation.js.map +1 -0
  272. package/dist/logging/trace.d.ts +7 -0
  273. package/dist/logging/trace.d.ts.map +1 -0
  274. package/dist/logging/trace.js +50 -0
  275. package/dist/logging/trace.js.map +1 -0
  276. package/dist/mcp/client.d.ts +37 -0
  277. package/dist/mcp/client.d.ts.map +1 -0
  278. package/dist/mcp/client.js +111 -0
  279. package/dist/mcp/client.js.map +1 -0
  280. package/dist/mcp/http-transport.d.ts +30 -0
  281. package/dist/mcp/http-transport.d.ts.map +1 -0
  282. package/dist/mcp/http-transport.js +109 -0
  283. package/dist/mcp/http-transport.js.map +1 -0
  284. package/dist/mcp/oauth.d.ts +23 -0
  285. package/dist/mcp/oauth.d.ts.map +1 -0
  286. package/dist/mcp/oauth.js +235 -0
  287. package/dist/mcp/oauth.js.map +1 -0
  288. package/dist/mcp/registry.d.ts +5 -0
  289. package/dist/mcp/registry.d.ts.map +1 -0
  290. package/dist/mcp/registry.js +35 -0
  291. package/dist/mcp/registry.js.map +1 -0
  292. package/dist/memory/cold.d.ts +16 -0
  293. package/dist/memory/cold.d.ts.map +1 -0
  294. package/dist/memory/cold.js +244 -0
  295. package/dist/memory/cold.js.map +1 -0
  296. package/dist/memory/graph.d.ts +19 -0
  297. package/dist/memory/graph.d.ts.map +1 -0
  298. package/dist/memory/graph.js +102 -0
  299. package/dist/memory/graph.js.map +1 -0
  300. package/dist/memory/hot.d.ts +26 -0
  301. package/dist/memory/hot.d.ts.map +1 -0
  302. package/dist/memory/hot.js +58 -0
  303. package/dist/memory/hot.js.map +1 -0
  304. package/dist/memory/index.d.ts +7 -0
  305. package/dist/memory/index.d.ts.map +1 -0
  306. package/dist/memory/index.js +26 -0
  307. package/dist/memory/index.js.map +1 -0
  308. package/dist/memory/learning.d.ts +18 -0
  309. package/dist/memory/learning.d.ts.map +1 -0
  310. package/dist/memory/learning.js +83 -0
  311. package/dist/memory/learning.js.map +1 -0
  312. package/dist/memory/retrieval.d.ts +21 -0
  313. package/dist/memory/retrieval.d.ts.map +1 -0
  314. package/dist/memory/retrieval.js +114 -0
  315. package/dist/memory/retrieval.js.map +1 -0
  316. package/dist/memory/warm.d.ts +9 -0
  317. package/dist/memory/warm.d.ts.map +1 -0
  318. package/dist/memory/warm.js +150 -0
  319. package/dist/memory/warm.js.map +1 -0
  320. package/dist/migrations/runner.d.ts +18 -0
  321. package/dist/migrations/runner.d.ts.map +1 -0
  322. package/dist/migrations/runner.js +62 -0
  323. package/dist/migrations/runner.js.map +1 -0
  324. package/dist/models/adapter.d.ts +46 -0
  325. package/dist/models/adapter.d.ts.map +1 -0
  326. package/dist/models/adapter.js +85 -0
  327. package/dist/models/adapter.js.map +1 -0
  328. package/dist/models/anthropic.d.ts +17 -0
  329. package/dist/models/anthropic.d.ts.map +1 -0
  330. package/dist/models/anthropic.js +128 -0
  331. package/dist/models/anthropic.js.map +1 -0
  332. package/dist/models/cache.d.ts +5 -0
  333. package/dist/models/cache.d.ts.map +1 -0
  334. package/dist/models/cache.js +135 -0
  335. package/dist/models/cache.js.map +1 -0
  336. package/dist/models/circuit-breaker.d.ts +18 -0
  337. package/dist/models/circuit-breaker.d.ts.map +1 -0
  338. package/dist/models/circuit-breaker.js +63 -0
  339. package/dist/models/circuit-breaker.js.map +1 -0
  340. package/dist/models/cost.d.ts +13 -0
  341. package/dist/models/cost.d.ts.map +1 -0
  342. package/dist/models/cost.js +92 -0
  343. package/dist/models/cost.js.map +1 -0
  344. package/dist/models/llamacpp.d.ts +9 -0
  345. package/dist/models/llamacpp.d.ts.map +1 -0
  346. package/dist/models/llamacpp.js +15 -0
  347. package/dist/models/llamacpp.js.map +1 -0
  348. package/dist/models/lmstudio.d.ts +11 -0
  349. package/dist/models/lmstudio.d.ts.map +1 -0
  350. package/dist/models/lmstudio.js +18 -0
  351. package/dist/models/lmstudio.js.map +1 -0
  352. package/dist/models/local-catalog.d.ts +45 -0
  353. package/dist/models/local-catalog.d.ts.map +1 -0
  354. package/dist/models/local-catalog.js +314 -0
  355. package/dist/models/local-catalog.js.map +1 -0
  356. package/dist/models/ollama.d.ts +10 -0
  357. package/dist/models/ollama.d.ts.map +1 -0
  358. package/dist/models/ollama.js +98 -0
  359. package/dist/models/ollama.js.map +1 -0
  360. package/dist/models/openai.d.ts +16 -0
  361. package/dist/models/openai.d.ts.map +1 -0
  362. package/dist/models/openai.js +139 -0
  363. package/dist/models/openai.js.map +1 -0
  364. package/dist/models/provider.d.ts +7 -0
  365. package/dist/models/provider.d.ts.map +1 -0
  366. package/dist/models/provider.js +39 -0
  367. package/dist/models/provider.js.map +1 -0
  368. package/dist/models/rate-limit.d.ts +13 -0
  369. package/dist/models/rate-limit.d.ts.map +1 -0
  370. package/dist/models/rate-limit.js +37 -0
  371. package/dist/models/rate-limit.js.map +1 -0
  372. package/dist/models/registry.d.ts +2 -0
  373. package/dist/models/registry.d.ts.map +1 -0
  374. package/dist/models/registry.js +69 -0
  375. package/dist/models/registry.js.map +1 -0
  376. package/dist/models/router.d.ts +26 -0
  377. package/dist/models/router.d.ts.map +1 -0
  378. package/dist/models/router.js +185 -0
  379. package/dist/models/router.js.map +1 -0
  380. package/dist/models/vllm.d.ts +13 -0
  381. package/dist/models/vllm.d.ts.map +1 -0
  382. package/dist/models/vllm.js +19 -0
  383. package/dist/models/vllm.js.map +1 -0
  384. package/dist/notifications/manager.d.ts +5 -0
  385. package/dist/notifications/manager.d.ts.map +1 -0
  386. package/dist/notifications/manager.js +65 -0
  387. package/dist/notifications/manager.js.map +1 -0
  388. package/dist/permissions/manager.d.ts +15 -0
  389. package/dist/permissions/manager.d.ts.map +1 -0
  390. package/dist/permissions/manager.js +159 -0
  391. package/dist/permissions/manager.js.map +1 -0
  392. package/dist/permissions/risk.d.ts +13 -0
  393. package/dist/permissions/risk.d.ts.map +1 -0
  394. package/dist/permissions/risk.js +43 -0
  395. package/dist/permissions/risk.js.map +1 -0
  396. package/dist/persistence/compression.d.ts +9 -0
  397. package/dist/persistence/compression.d.ts.map +1 -0
  398. package/dist/persistence/compression.js +126 -0
  399. package/dist/persistence/compression.js.map +1 -0
  400. package/dist/persistence/conversation-store.d.ts +67 -0
  401. package/dist/persistence/conversation-store.d.ts.map +1 -0
  402. package/dist/persistence/conversation-store.js +370 -0
  403. package/dist/persistence/conversation-store.js.map +1 -0
  404. package/dist/persistence/events.d.ts +4 -0
  405. package/dist/persistence/events.d.ts.map +1 -0
  406. package/dist/persistence/events.js +50 -0
  407. package/dist/persistence/events.js.map +1 -0
  408. package/dist/persistence/index-db.d.ts +65 -0
  409. package/dist/persistence/index-db.d.ts.map +1 -0
  410. package/dist/persistence/index-db.js +280 -0
  411. package/dist/persistence/index-db.js.map +1 -0
  412. package/dist/persistence/jsonl.d.ts +8 -0
  413. package/dist/persistence/jsonl.d.ts.map +1 -0
  414. package/dist/persistence/jsonl.js +90 -0
  415. package/dist/persistence/jsonl.js.map +1 -0
  416. package/dist/persistence/sessions.d.ts +5 -0
  417. package/dist/persistence/sessions.d.ts.map +1 -0
  418. package/dist/persistence/sessions.js +54 -0
  419. package/dist/persistence/sessions.js.map +1 -0
  420. package/dist/persistence/tasks.d.ts +7 -0
  421. package/dist/persistence/tasks.d.ts.map +1 -0
  422. package/dist/persistence/tasks.js +162 -0
  423. package/dist/persistence/tasks.js.map +1 -0
  424. package/dist/prompts/assembler.d.ts +29 -0
  425. package/dist/prompts/assembler.d.ts.map +1 -0
  426. package/dist/prompts/assembler.js +136 -0
  427. package/dist/prompts/assembler.js.map +1 -0
  428. package/dist/prompts/layers.d.ts +6 -0
  429. package/dist/prompts/layers.d.ts.map +1 -0
  430. package/dist/prompts/layers.js +60 -0
  431. package/dist/prompts/layers.js.map +1 -0
  432. package/dist/release/download.d.ts +19 -0
  433. package/dist/release/download.d.ts.map +1 -0
  434. package/dist/release/download.js +187 -0
  435. package/dist/release/download.js.map +1 -0
  436. package/dist/release/verify.d.ts +34 -0
  437. package/dist/release/verify.d.ts.map +1 -0
  438. package/dist/release/verify.js +127 -0
  439. package/dist/release/verify.js.map +1 -0
  440. package/dist/sandbox/fs.d.ts +10 -0
  441. package/dist/sandbox/fs.d.ts.map +1 -0
  442. package/dist/sandbox/fs.js +114 -0
  443. package/dist/sandbox/fs.js.map +1 -0
  444. package/dist/sandbox/shell.d.ts +20 -0
  445. package/dist/sandbox/shell.d.ts.map +1 -0
  446. package/dist/sandbox/shell.js +131 -0
  447. package/dist/sandbox/shell.js.map +1 -0
  448. package/dist/scheduler/dag.d.ts +7 -0
  449. package/dist/scheduler/dag.d.ts.map +1 -0
  450. package/dist/scheduler/dag.js +72 -0
  451. package/dist/scheduler/dag.js.map +1 -0
  452. package/dist/scheduler/resource-manager.d.ts +25 -0
  453. package/dist/scheduler/resource-manager.d.ts.map +1 -0
  454. package/dist/scheduler/resource-manager.js +101 -0
  455. package/dist/scheduler/resource-manager.js.map +1 -0
  456. package/dist/security/injection.d.ts +14 -0
  457. package/dist/security/injection.d.ts.map +1 -0
  458. package/dist/security/injection.js +46 -0
  459. package/dist/security/injection.js.map +1 -0
  460. package/dist/security/redact.d.ts +10 -0
  461. package/dist/security/redact.d.ts.map +1 -0
  462. package/dist/security/redact.js +89 -0
  463. package/dist/security/redact.js.map +1 -0
  464. package/dist/skills/loader.d.ts +4 -0
  465. package/dist/skills/loader.d.ts.map +1 -0
  466. package/dist/skills/loader.js +142 -0
  467. package/dist/skills/loader.js.map +1 -0
  468. package/dist/skills/marketplace.d.ts +15 -0
  469. package/dist/skills/marketplace.d.ts.map +1 -0
  470. package/dist/skills/marketplace.js +132 -0
  471. package/dist/skills/marketplace.js.map +1 -0
  472. package/dist/tools/apply-patch.d.ts +20 -0
  473. package/dist/tools/apply-patch.d.ts.map +1 -0
  474. package/dist/tools/apply-patch.js +195 -0
  475. package/dist/tools/apply-patch.js.map +1 -0
  476. package/dist/tools/ask-user.d.ts +12 -0
  477. package/dist/tools/ask-user.d.ts.map +1 -0
  478. package/dist/tools/ask-user.js +86 -0
  479. package/dist/tools/ask-user.js.map +1 -0
  480. package/dist/tools/delete-file.d.ts +10 -0
  481. package/dist/tools/delete-file.d.ts.map +1 -0
  482. package/dist/tools/delete-file.js +94 -0
  483. package/dist/tools/delete-file.js.map +1 -0
  484. package/dist/tools/edit-file.d.ts +20 -0
  485. package/dist/tools/edit-file.d.ts.map +1 -0
  486. package/dist/tools/edit-file.js +128 -0
  487. package/dist/tools/edit-file.js.map +1 -0
  488. package/dist/tools/format.d.ts +5 -0
  489. package/dist/tools/format.d.ts.map +1 -0
  490. package/dist/tools/format.js +131 -0
  491. package/dist/tools/format.js.map +1 -0
  492. package/dist/tools/git.d.ts +24 -0
  493. package/dist/tools/git.d.ts.map +1 -0
  494. package/dist/tools/git.js +122 -0
  495. package/dist/tools/git.js.map +1 -0
  496. package/dist/tools/glob.d.ts +12 -0
  497. package/dist/tools/glob.d.ts.map +1 -0
  498. package/dist/tools/glob.js +55 -0
  499. package/dist/tools/glob.js.map +1 -0
  500. package/dist/tools/grep.d.ts +19 -0
  501. package/dist/tools/grep.d.ts.map +1 -0
  502. package/dist/tools/grep.js +97 -0
  503. package/dist/tools/grep.js.map +1 -0
  504. package/dist/tools/init.d.ts +3 -0
  505. package/dist/tools/init.d.ts.map +1 -0
  506. package/dist/tools/init.js +66 -0
  507. package/dist/tools/init.js.map +1 -0
  508. package/dist/tools/list-dir.d.ts +16 -0
  509. package/dist/tools/list-dir.d.ts.map +1 -0
  510. package/dist/tools/list-dir.js +107 -0
  511. package/dist/tools/list-dir.js.map +1 -0
  512. package/dist/tools/move-file.d.ts +13 -0
  513. package/dist/tools/move-file.d.ts.map +1 -0
  514. package/dist/tools/move-file.js +100 -0
  515. package/dist/tools/move-file.js.map +1 -0
  516. package/dist/tools/read-file.d.ts +14 -0
  517. package/dist/tools/read-file.d.ts.map +1 -0
  518. package/dist/tools/read-file.js +99 -0
  519. package/dist/tools/read-file.js.map +1 -0
  520. package/dist/tools/registry.d.ts +10 -0
  521. package/dist/tools/registry.d.ts.map +1 -0
  522. package/dist/tools/registry.js +30 -0
  523. package/dist/tools/registry.js.map +1 -0
  524. package/dist/tools/run-command.d.ts +17 -0
  525. package/dist/tools/run-command.d.ts.map +1 -0
  526. package/dist/tools/run-command.js +73 -0
  527. package/dist/tools/run-command.js.map +1 -0
  528. package/dist/tools/run-tests.d.ts +16 -0
  529. package/dist/tools/run-tests.d.ts.map +1 -0
  530. package/dist/tools/run-tests.js +140 -0
  531. package/dist/tools/run-tests.js.map +1 -0
  532. package/dist/tools/web-browse.d.ts +10 -0
  533. package/dist/tools/web-browse.d.ts.map +1 -0
  534. package/dist/tools/web-browse.js +45 -0
  535. package/dist/tools/web-browse.js.map +1 -0
  536. package/dist/tools/web-fetch.d.ts +11 -0
  537. package/dist/tools/web-fetch.d.ts.map +1 -0
  538. package/dist/tools/web-fetch.js +43 -0
  539. package/dist/tools/web-fetch.js.map +1 -0
  540. package/dist/tools/web-search.d.ts +12 -0
  541. package/dist/tools/web-search.d.ts.map +1 -0
  542. package/dist/tools/web-search.js +52 -0
  543. package/dist/tools/web-search.js.map +1 -0
  544. package/dist/tools/write-file.d.ts +13 -0
  545. package/dist/tools/write-file.d.ts.map +1 -0
  546. package/dist/tools/write-file.js +100 -0
  547. package/dist/tools/write-file.js.map +1 -0
  548. package/dist/types/errors.d.ts +14 -0
  549. package/dist/types/errors.d.ts.map +1 -0
  550. package/dist/types/errors.js +55 -0
  551. package/dist/types/errors.js.map +1 -0
  552. package/dist/types/index.d.ts +267 -0
  553. package/dist/types/index.d.ts.map +1 -0
  554. package/dist/types/index.js +38 -0
  555. package/dist/types/index.js.map +1 -0
  556. package/dist/ui/chat.d.ts +89 -0
  557. package/dist/ui/chat.d.ts.map +1 -0
  558. package/dist/ui/chat.js +311 -0
  559. package/dist/ui/chat.js.map +1 -0
  560. package/dist/ui/public/app.js +2113 -0
  561. package/dist/ui/public/index.html +78 -0
  562. package/dist/ui/public/styles.css +1703 -0
  563. package/dist/ui/server-errors.d.ts +24 -0
  564. package/dist/ui/server-errors.d.ts.map +1 -0
  565. package/dist/ui/server-errors.js +31 -0
  566. package/dist/ui/server-errors.js.map +1 -0
  567. package/dist/ui/server.d.ts +10 -0
  568. package/dist/ui/server.d.ts.map +1 -0
  569. package/dist/ui/server.js +815 -0
  570. package/dist/ui/server.js.map +1 -0
  571. package/dist/ui/task-runner.d.ts +71 -0
  572. package/dist/ui/task-runner.d.ts.map +1 -0
  573. package/dist/ui/task-runner.js +334 -0
  574. package/dist/ui/task-runner.js.map +1 -0
  575. package/dist/web/browse.d.ts +35 -0
  576. package/dist/web/browse.d.ts.map +1 -0
  577. package/dist/web/browse.js +166 -0
  578. package/dist/web/browse.js.map +1 -0
  579. package/dist/web/fetch.d.ts +18 -0
  580. package/dist/web/fetch.d.ts.map +1 -0
  581. package/dist/web/fetch.js +107 -0
  582. package/dist/web/fetch.js.map +1 -0
  583. package/dist/web/sanitize.d.ts +8 -0
  584. package/dist/web/sanitize.d.ts.map +1 -0
  585. package/dist/web/sanitize.js +58 -0
  586. package/dist/web/sanitize.js.map +1 -0
  587. package/dist/web/search.d.ts +12 -0
  588. package/dist/web/search.d.ts.map +1 -0
  589. package/dist/web/search.js +124 -0
  590. package/dist/web/search.js.map +1 -0
  591. package/install/install.ps1 +46 -0
  592. package/install/install.sh +72 -0
  593. package/package.json +89 -0
  594. package/scripts/bundle.js +26 -0
  595. package/scripts/copy-assets.js +33 -0
  596. package/scripts/link.sh +79 -0
  597. package/scripts/metrics.sh +33 -0
  598. package/scripts/postinstall.js +36 -0
@@ -0,0 +1,815 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.startUiServer = void 0;
37
+ /**
38
+ * Forge UI server. Serves the dashboard, streams live events per project,
39
+ * and exposes the CLI's capabilities over HTTP + WebSocket. The runtime
40
+ * runs in-process so every CLI capability is reachable without shelling
41
+ * out; this keeps UI-driven tasks under the same permission and sandbox
42
+ * rules as CLI-driven tasks.
43
+ */
44
+ const http = __importStar(require("http"));
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const url_1 = require("url");
48
+ const ws_1 = require("ws");
49
+ const index_db_1 = require("../persistence/index-db");
50
+ const tasks_1 = require("../persistence/tasks");
51
+ const sessions_1 = require("../persistence/sessions");
52
+ const loader_1 = require("../config/loader");
53
+ const paths_1 = require("../config/paths");
54
+ const control_1 = require("../daemon/control");
55
+ const provider_1 = require("../models/provider");
56
+ const logger_1 = require("../logging/logger");
57
+ const redact_1 = require("../security/redact");
58
+ const cost_1 = require("../models/cost");
59
+ const loader_2 = require("../skills/loader");
60
+ const marketplace_1 = require("../skills/marketplace");
61
+ const registry_1 = require("../mcp/registry");
62
+ const search_1 = require("../web/search");
63
+ const fetch_1 = require("../web/fetch");
64
+ const cold_1 = require("../memory/cold");
65
+ const task_runner_1 = require("./task-runner");
66
+ const chat_1 = require("./chat");
67
+ // ---------- helpers ----------
68
+ const sendJson = (res, status, body) => {
69
+ const payload = JSON.stringify((0, redact_1.redact)(body));
70
+ res.writeHead(status, {
71
+ 'content-type': 'application/json; charset=utf-8',
72
+ 'content-length': Buffer.byteLength(payload),
73
+ 'access-control-allow-origin': '*',
74
+ 'access-control-allow-headers': 'content-type',
75
+ 'access-control-allow-methods': 'GET, POST, DELETE, OPTIONS',
76
+ });
77
+ res.end(payload);
78
+ };
79
+ // `errorBody()` lives in ./server-errors so unit tests can import it
80
+ // without requiring the entire server (sqlite, ws, etc).
81
+ const server_errors_1 = require("./server-errors");
82
+ const sendStatic = (res, filePath) => {
83
+ try {
84
+ const body = fs.readFileSync(filePath);
85
+ const ext = path.extname(filePath).toLowerCase();
86
+ const contentType = ext === '.html'
87
+ ? 'text/html; charset=utf-8'
88
+ : ext === '.js'
89
+ ? 'application/javascript; charset=utf-8'
90
+ : ext === '.css'
91
+ ? 'text/css; charset=utf-8'
92
+ : ext === '.svg'
93
+ ? 'image/svg+xml'
94
+ : ext === '.json'
95
+ ? 'application/json'
96
+ : 'application/octet-stream';
97
+ res.writeHead(200, { 'content-type': contentType, 'cache-control': 'no-cache' });
98
+ res.end(body);
99
+ }
100
+ catch {
101
+ res.writeHead(404);
102
+ res.end('not found');
103
+ }
104
+ };
105
+ const readBody = (req, limit = 256 * 1024) => new Promise((resolve, reject) => {
106
+ let total = 0;
107
+ const chunks = [];
108
+ req.on('data', (chunk) => {
109
+ total += chunk.length;
110
+ if (total > limit) {
111
+ reject(new Error('body too large'));
112
+ return;
113
+ }
114
+ chunks.push(chunk);
115
+ });
116
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
117
+ req.on('error', reject);
118
+ });
119
+ const parseJson = async (req) => {
120
+ const raw = await readBody(req);
121
+ if (!raw.trim())
122
+ return {};
123
+ return JSON.parse(raw);
124
+ };
125
+ // ---------- routes ----------
126
+ const router = async (req, res, publicDir) => {
127
+ if (req.method === 'OPTIONS') {
128
+ res.writeHead(204, {
129
+ 'access-control-allow-origin': '*',
130
+ 'access-control-allow-methods': 'GET, POST, DELETE, OPTIONS',
131
+ 'access-control-allow-headers': 'content-type',
132
+ });
133
+ res.end();
134
+ return;
135
+ }
136
+ const u = new url_1.URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
137
+ const p = u.pathname;
138
+ // ---- Health ----
139
+ if (p === '/healthz') {
140
+ return sendJson(res, 200, { status: 'ok', uptime: process.uptime() });
141
+ }
142
+ // ---- Status / projects / config ----
143
+ if (p === '/api/status') {
144
+ const cfg = (0, loader_1.loadGlobalConfig)();
145
+ const d = (0, control_1.daemonStatus)();
146
+ const providers = await Promise.all((0, provider_1.listProviders)().map(async (prov) => ({
147
+ name: prov.name,
148
+ available: await prov.isAvailable().catch(() => false),
149
+ })));
150
+ return sendJson(res, 200, {
151
+ provider: cfg.provider,
152
+ defaultMode: cfg.defaultMode,
153
+ channel: cfg.update.channel,
154
+ daemon: d,
155
+ providers,
156
+ cwd: process.cwd(),
157
+ version: (() => {
158
+ try {
159
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf8'));
160
+ return pkg.version ?? null;
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ })(),
166
+ });
167
+ }
168
+ if (p === '/api/projects') {
169
+ return sendJson(res, 200, (0, index_db_1.listProjects)());
170
+ }
171
+ if (p === '/api/config' && req.method === 'GET') {
172
+ return sendJson(res, 200, (0, loader_1.loadGlobalConfig)());
173
+ }
174
+ if (p === '/api/config' && req.method === 'POST') {
175
+ try {
176
+ const body = await parseJson(req);
177
+ if (!body.key)
178
+ return sendJson(res, 400, { error: 'key required' });
179
+ const updated = (0, loader_1.updateGlobalConfig)((cfg) => {
180
+ const clone = JSON.parse(JSON.stringify(cfg));
181
+ setNested(clone, body.key, body.value);
182
+ return clone;
183
+ });
184
+ return sendJson(res, 200, updated);
185
+ }
186
+ catch (e) {
187
+ {
188
+ const { status, body } = (0, server_errors_1.errorBody)(e);
189
+ return sendJson(res, status, body);
190
+ }
191
+ }
192
+ }
193
+ // ---- Tasks (index) ----
194
+ if (p === '/api/tasks' && req.method === 'GET') {
195
+ const projectId = u.searchParams.get('project') ?? undefined;
196
+ const query = u.searchParams.get('q');
197
+ const limit = Number(u.searchParams.get('limit') ?? 50);
198
+ const rows = query ? (0, index_db_1.searchTasks)(query, limit) : (0, index_db_1.listTasks)(projectId, limit);
199
+ return sendJson(res, 200, rows);
200
+ }
201
+ // ---- Running UI tasks (must come BEFORE the generic /api/tasks/:id regex) ----
202
+ if (p === '/api/tasks/run' && req.method === 'POST') {
203
+ try {
204
+ const body = await parseJson(req);
205
+ if (!body.prompt?.trim())
206
+ return sendJson(res, 400, { error: 'prompt required' });
207
+ const reply = (0, task_runner_1.startUiTask)({
208
+ prompt: body.prompt,
209
+ mode: body.mode,
210
+ cwd: body.cwd,
211
+ autoApprove: body.autoApprove,
212
+ flags: body.flags,
213
+ title: body.title,
214
+ });
215
+ return sendJson(res, 202, reply);
216
+ }
217
+ catch (e) {
218
+ {
219
+ const { status, body } = (0, server_errors_1.errorBody)(e);
220
+ return sendJson(res, status, body);
221
+ }
222
+ }
223
+ }
224
+ if (p === '/api/tasks/active' && req.method === 'GET') {
225
+ return sendJson(res, 200, { active: (0, task_runner_1.listActive)(), pending: (0, task_runner_1.listPendingPrompts)() });
226
+ }
227
+ const cancelMatch = /^\/api\/tasks\/([a-f0-9]+)\/cancel$/.exec(p);
228
+ if (cancelMatch && req.method === 'POST') {
229
+ const ok = (0, task_runner_1.cancelTask)(cancelMatch[1]);
230
+ return sendJson(res, ok ? 200 : 404, { cancelled: ok });
231
+ }
232
+ if (p === '/api/prompts/respond' && req.method === 'POST') {
233
+ try {
234
+ const body = await parseJson(req);
235
+ const ok = (0, task_runner_1.respond)(body.promptId, body.value);
236
+ return sendJson(res, ok ? 200 : 404, { resolved: ok });
237
+ }
238
+ catch (e) {
239
+ {
240
+ const { status, body } = (0, server_errors_1.errorBody)(e);
241
+ return sendJson(res, status, body);
242
+ }
243
+ }
244
+ }
245
+ // Historical task detail — last to avoid catching /active, /run, /<id>/cancel.
246
+ const taskMatch = /^\/api\/tasks\/([a-z0-9_]+)$/.exec(p);
247
+ if (taskMatch && req.method === 'GET') {
248
+ const projectPath = u.searchParams.get('projectPath') ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
249
+ const task = (0, tasks_1.loadTask)(projectPath, taskMatch[1]);
250
+ if (!task)
251
+ return sendJson(res, 404, { error: 'task not found' });
252
+ return sendJson(res, 200, task);
253
+ }
254
+ // ---- Sessions ----
255
+ const sessionMatch = /^\/api\/sessions\/([a-z0-9_]+)$/.exec(p);
256
+ if (sessionMatch) {
257
+ const projectPath = u.searchParams.get('projectPath');
258
+ if (!projectPath)
259
+ return sendJson(res, 400, { error: 'projectPath required' });
260
+ const entries = await (0, sessions_1.loadSession)(projectPath, sessionMatch[1]);
261
+ return sendJson(res, 200, entries);
262
+ }
263
+ // ---- Chat / Conversations (unified; REPL and Web share the same store) ----
264
+ if (p === '/api/chat/sessions' && req.method === 'GET') {
265
+ const projectPath = u.searchParams.get('projectPath') ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
266
+ return sendJson(res, 200, (0, chat_1.listChatSessions)(projectPath));
267
+ }
268
+ if (p === '/api/chat/sessions' && req.method === 'POST') {
269
+ try {
270
+ const body = await parseJson(req);
271
+ const projectPath = body.projectPath ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
272
+ const session = await (0, chat_1.createChatSession)({
273
+ projectPath,
274
+ title: body.title,
275
+ mode: body.mode,
276
+ source: body.source ?? 'chat',
277
+ });
278
+ return sendJson(res, 201, session);
279
+ }
280
+ catch (e) {
281
+ {
282
+ const { status, body } = (0, server_errors_1.errorBody)(e);
283
+ return sendJson(res, status, body);
284
+ }
285
+ }
286
+ }
287
+ // Accept both chat-*, repl-*, and conv-* ids so the UI can display + edit
288
+ // any conversation irrespective of which surface created it.
289
+ const chatSessionMatch = /^\/api\/chat\/sessions\/((?:chat|repl|conv)-[a-z0-9_]+)$/.exec(p);
290
+ if (chatSessionMatch && req.method === 'GET') {
291
+ const projectPath = u.searchParams.get('projectPath') ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
292
+ const session = (0, chat_1.getChatSession)(projectPath, chatSessionMatch[1]);
293
+ if (!session)
294
+ return sendJson(res, 404, { error: 'conversation not found' });
295
+ return sendJson(res, 200, session);
296
+ }
297
+ if (chatSessionMatch && req.method === 'DELETE') {
298
+ const projectPath = u.searchParams.get('projectPath') ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
299
+ const ok = (0, chat_1.deleteChatSession)(projectPath, chatSessionMatch[1]);
300
+ return sendJson(res, ok ? 200 : 404, { deleted: ok });
301
+ }
302
+ if (chatSessionMatch && req.method === 'PATCH') {
303
+ try {
304
+ const body = await parseJson(req);
305
+ if (!body.title)
306
+ return sendJson(res, 400, { error: 'title required' });
307
+ const projectPath = body.projectPath ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
308
+ const s = await (0, chat_1.renameChatSession)(projectPath, chatSessionMatch[1], body.title);
309
+ if (!s)
310
+ return sendJson(res, 404, { error: 'conversation not found' });
311
+ return sendJson(res, 200, s);
312
+ }
313
+ catch (e) {
314
+ {
315
+ const { status, body } = (0, server_errors_1.errorBody)(e);
316
+ return sendJson(res, status, body);
317
+ }
318
+ }
319
+ }
320
+ const chatTurnMatch = /^\/api\/chat\/sessions\/((?:chat|repl|conv)-[a-z0-9_]+)\/turns$/.exec(p);
321
+ if (chatTurnMatch && req.method === 'POST') {
322
+ try {
323
+ const body = await parseJson(req);
324
+ if (!body.input?.trim())
325
+ return sendJson(res, 400, { error: 'input required' });
326
+ const projectPath = body.projectPath ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
327
+ const reply = await (0, chat_1.addTurn)({
328
+ projectPath,
329
+ conversationId: chatTurnMatch[1],
330
+ input: body.input,
331
+ mode: body.mode,
332
+ autoApprove: body.autoApprove,
333
+ flags: body.flags,
334
+ });
335
+ return sendJson(res, 202, reply);
336
+ }
337
+ catch (e) {
338
+ {
339
+ const { status, body } = (0, server_errors_1.errorBody)(e);
340
+ return sendJson(res, status, body);
341
+ }
342
+ }
343
+ }
344
+ // ---- Models ----
345
+ if (p === '/api/models') {
346
+ const out = [];
347
+ for (const prov of (0, provider_1.listProviders)()) {
348
+ try {
349
+ const available = await prov.isAvailable();
350
+ const models = available ? await prov.listModels() : [];
351
+ out.push({ provider: prov.name, available, models });
352
+ }
353
+ catch (err) {
354
+ out.push({ provider: prov.name, available: false, models: [], error: String(err) });
355
+ }
356
+ }
357
+ return sendJson(res, 200, out);
358
+ }
359
+ // ---- Events ----
360
+ if (p === '/api/events') {
361
+ const project = u.searchParams.get('projectPath');
362
+ if (!project)
363
+ return sendJson(res, 400, { error: 'projectPath required' });
364
+ const resolved = resolveEventFile(project);
365
+ if (!resolved || !fs.existsSync(resolved))
366
+ return sendJson(res, 200, []);
367
+ const limit = Number(u.searchParams.get('limit') ?? 200);
368
+ try {
369
+ const lines = fs.readFileSync(resolved, 'utf8').split('\n').filter(Boolean).slice(-limit);
370
+ return sendJson(res, 200, lines
371
+ .map((l) => {
372
+ try {
373
+ return JSON.parse(l);
374
+ }
375
+ catch {
376
+ return null;
377
+ }
378
+ })
379
+ .filter(Boolean));
380
+ }
381
+ catch (err) {
382
+ logger_1.log.warn('events read failed', { err: String(err) });
383
+ return sendJson(res, 200, []);
384
+ }
385
+ }
386
+ // ---- Cost ----
387
+ if (p === '/api/cost') {
388
+ const projectId = u.searchParams.get('projectId') ?? undefined;
389
+ return sendJson(res, 200, { totals: (0, cost_1.totals)(projectId), recent: (0, cost_1.recent)(50) });
390
+ }
391
+ // ---- Learning ----
392
+ if (p === '/api/learning') {
393
+ const rows = (0, index_db_1.getDb)()
394
+ .prepare('SELECT pattern, context, fix, confidence, success_count, failure_count, updated_at FROM learning_patterns ORDER BY confidence DESC LIMIT 50')
395
+ .all();
396
+ return sendJson(res, 200, rows);
397
+ }
398
+ // ---- Memory ----
399
+ if (p === '/api/memory/index' && req.method === 'POST') {
400
+ try {
401
+ const body = await parseJson(req);
402
+ const projectPath = body.projectPath ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
403
+ const stats = (0, cold_1.indexProject)(projectPath);
404
+ return sendJson(res, 200, { projectPath, ...stats });
405
+ }
406
+ catch (e) {
407
+ {
408
+ const { status, body } = (0, server_errors_1.errorBody)(e);
409
+ return sendJson(res, status, body);
410
+ }
411
+ }
412
+ }
413
+ if (p === '/api/memory/search') {
414
+ const query = u.searchParams.get('q');
415
+ const projectPath = u.searchParams.get('projectPath') ?? (0, loader_1.findProjectRoot)() ?? process.cwd();
416
+ if (!query)
417
+ return sendJson(res, 400, { error: 'q required' });
418
+ const results = (0, cold_1.search)(projectPath, query, 20);
419
+ return sendJson(res, 200, results);
420
+ }
421
+ // ---- Skills ----
422
+ if (p === '/api/skills' && req.method === 'GET') {
423
+ const root = (0, loader_1.findProjectRoot)() ?? undefined;
424
+ return sendJson(res, 200, (0, loader_2.loadSkills)(root));
425
+ }
426
+ if (p === '/api/skills/search') {
427
+ const q = u.searchParams.get('q') ?? '';
428
+ try {
429
+ return sendJson(res, 200, await (0, marketplace_1.searchRegistry)(q));
430
+ }
431
+ catch (e) {
432
+ return sendJson(res, 500, { error: String(e) });
433
+ }
434
+ }
435
+ if (p === '/api/skills/install' && req.method === 'POST') {
436
+ try {
437
+ const body = await parseJson(req);
438
+ const out = await (0, marketplace_1.installFromUrl)(body.name, body.url, { overwrite: true });
439
+ return sendJson(res, 200, out);
440
+ }
441
+ catch (e) {
442
+ {
443
+ const { status, body } = (0, server_errors_1.errorBody)(e);
444
+ return sendJson(res, status, body);
445
+ }
446
+ }
447
+ }
448
+ // ---- MCP ----
449
+ if (p === '/api/mcp' && req.method === 'GET') {
450
+ return sendJson(res, 200, (0, registry_1.listConnections)());
451
+ }
452
+ if (p === '/api/mcp' && req.method === 'POST') {
453
+ try {
454
+ const body = await parseJson(req);
455
+ (0, registry_1.addConnection)(body);
456
+ return sendJson(res, 201, { ok: true });
457
+ }
458
+ catch (e) {
459
+ {
460
+ const { status, body } = (0, server_errors_1.errorBody)(e);
461
+ return sendJson(res, status, body);
462
+ }
463
+ }
464
+ }
465
+ const mcpIdMatch = /^\/api\/mcp\/([^/]+)$/.exec(p);
466
+ if (mcpIdMatch && req.method === 'DELETE') {
467
+ (0, registry_1.removeConnection)(mcpIdMatch[1]);
468
+ return sendJson(res, 204, {});
469
+ }
470
+ // ---- Web ----
471
+ if (p === '/api/web/search') {
472
+ const query = u.searchParams.get('q');
473
+ if (!query)
474
+ return sendJson(res, 400, { error: 'q required' });
475
+ try {
476
+ const results = await (0, search_1.webSearch)({ query, limit: 10 });
477
+ return sendJson(res, 200, results);
478
+ }
479
+ catch (e) {
480
+ return sendJson(res, 500, { error: String(e) });
481
+ }
482
+ }
483
+ if (p === '/api/web/fetch' && req.method === 'POST') {
484
+ try {
485
+ const body = await parseJson(req);
486
+ if (!body.url)
487
+ return sendJson(res, 400, { error: 'url required' });
488
+ const result = await (0, fetch_1.webFetch)({ url: body.url, maxChars: 6_000 });
489
+ return sendJson(res, 200, result);
490
+ }
491
+ catch (e) {
492
+ {
493
+ const { status, body } = (0, server_errors_1.errorBody)(e);
494
+ return sendJson(res, status, body);
495
+ }
496
+ }
497
+ }
498
+ // ---- Doctor ----
499
+ if (p === '/api/doctor') {
500
+ const results = [];
501
+ const addCheck = (name, ok, detail) => results.push({ name, ok, detail });
502
+ addCheck('forge home', fs.existsSync(paths_1.paths.home), paths_1.paths.home);
503
+ try {
504
+ (0, index_db_1.getDb)().prepare('SELECT 1').get();
505
+ addCheck('sqlite index', true, paths_1.paths.globalIndex);
506
+ }
507
+ catch (e) {
508
+ addCheck('sqlite index', false, String(e));
509
+ }
510
+ try {
511
+ const cfg = (0, loader_1.loadGlobalConfig)();
512
+ addCheck('config valid', true, `provider=${cfg.provider} mode=${cfg.defaultMode}`);
513
+ }
514
+ catch (e) {
515
+ addCheck('config valid', false, String(e));
516
+ }
517
+ const prov = [];
518
+ for (const provObj of (0, provider_1.listProviders)()) {
519
+ prov.push(`${provObj.name}:${(await provObj.isAvailable().catch(() => false)) ? 'up' : 'down'}`);
520
+ }
521
+ addCheck('providers', prov.some((r) => r.endsWith(':up')), prov.join(' '));
522
+ return sendJson(res, 200, results);
523
+ }
524
+ // ---- Static ----
525
+ const staticPath = p === '/' ? '/index.html' : p;
526
+ const full = path.join(publicDir, staticPath);
527
+ const normalized = path.resolve(full);
528
+ if (!normalized.startsWith(path.resolve(publicDir))) {
529
+ res.writeHead(403);
530
+ res.end('forbidden');
531
+ return;
532
+ }
533
+ if (fs.existsSync(normalized) && fs.statSync(normalized).isFile()) {
534
+ sendStatic(res, normalized);
535
+ return;
536
+ }
537
+ sendStatic(res, path.join(publicDir, 'index.html'));
538
+ };
539
+ // ---------- helpers ----------
540
+ const setNested = (obj, keyPath, value) => {
541
+ const parts = keyPath.split('.');
542
+ let cur = obj;
543
+ for (let i = 0; i < parts.length - 1; i++) {
544
+ if (typeof cur[parts[i]] !== 'object' || cur[parts[i]] === null)
545
+ cur[parts[i]] = {};
546
+ cur = cur[parts[i]];
547
+ }
548
+ cur[parts[parts.length - 1]] = value;
549
+ };
550
+ // ---------- Event-file resolution ----------
551
+ //
552
+ // Events are written under ~/.forge/projects/<projectHash>/logs/events.jsonl
553
+ // (see src/persistence/events.ts). The UI caller usually sends the absolute
554
+ // project path, so we translate that to the stored location. We also support
555
+ // the legacy `<projectPath>/.forge/logs/events.jsonl` layout, and the shared
556
+ // per-project dir under `<projectPath>/logs/events.jsonl` only if it actually
557
+ // exists — never assuming.
558
+ const resolveEventFile = (projectPath) => {
559
+ const candidates = [
560
+ path.join((0, paths_1.projectSubdirs)(projectPath).logs, 'events.jsonl'),
561
+ path.join(projectPath, '.forge', 'logs', 'events.jsonl'),
562
+ path.join(projectPath, 'logs', 'events.jsonl'),
563
+ ];
564
+ for (const c of candidates) {
565
+ if (fs.existsSync(c))
566
+ return c;
567
+ }
568
+ return null;
569
+ };
570
+ // Resolve AND create the per-project events.jsonl so `fs.watch` never throws
571
+ // ENOENT. Touching a zero-byte file is cheap and idempotent.
572
+ const ensureEventFile = (projectPath) => {
573
+ const existing = resolveEventFile(projectPath);
574
+ if (existing)
575
+ return existing;
576
+ const sub = (0, paths_1.ensureProjectDir)(projectPath);
577
+ const target = path.join(sub.logs, 'events.jsonl');
578
+ if (!fs.existsSync(target))
579
+ fs.writeFileSync(target, '', 'utf8');
580
+ return target;
581
+ };
582
+ // ---------- Process-wide crash guards ----------
583
+ //
584
+ // The UI server is meant to stay up under imperfect conditions (files that
585
+ // appear and vanish, peers that disconnect mid-send, provider network
586
+ // hiccups). Without these, an unhandled rejection anywhere in the loop would
587
+ // crash the whole dashboard.
588
+ let guardsInstalled = false;
589
+ let bridgeInstalled = false;
590
+ const installProcessGuards = () => {
591
+ if (guardsInstalled)
592
+ return;
593
+ guardsInstalled = true;
594
+ process.on('uncaughtException', (err) => {
595
+ logger_1.log.error('uncaughtException (server kept alive)', {
596
+ err: String(err),
597
+ stack: err?.stack,
598
+ });
599
+ });
600
+ process.on('unhandledRejection', (reason) => {
601
+ logger_1.log.error('unhandledRejection (server kept alive)', { reason: String(reason) });
602
+ });
603
+ };
604
+ const startUiServer = (opts = {}) => {
605
+ const port = opts.port ?? Number(process.env.FORGE_UI_PORT ?? 7823);
606
+ const bind = opts.bind ?? '127.0.0.1';
607
+ const publicDir = opts.publicDir ?? path.join(__dirname, 'public');
608
+ installProcessGuards();
609
+ // Bridge task results back to chat sessions so turns get their summaries.
610
+ // Registered once per process — if `startUiServer` is called again (e.g.
611
+ // restart), subsequent calls skip this hook so we don't get duplicate
612
+ // writes per resolved task.
613
+ if (!bridgeInstalled) {
614
+ bridgeInstalled = true;
615
+ (0, task_runner_1.onTaskResolved)((r) => {
616
+ // chat.attachResultForTask is a no-op for tasks not associated with a
617
+ // chat turn — safe to call unconditionally.
618
+ (0, chat_1.attachResultForTask)(r.taskId, {
619
+ success: r.success,
620
+ summary: r.summary,
621
+ filesChanged: r.filesChanged,
622
+ durationMs: r.durationMs,
623
+ costUsd: r.costUsd,
624
+ }, r.status);
625
+ });
626
+ }
627
+ return new Promise((resolve, reject) => {
628
+ const server = http.createServer((req, res) => {
629
+ router(req, res, publicDir).catch((err) => {
630
+ logger_1.log.error('ui route failed', { err: String(err) });
631
+ try {
632
+ sendJson(res, 500, { error: String(err) });
633
+ }
634
+ catch {
635
+ /* socket may be dead */
636
+ }
637
+ });
638
+ });
639
+ server.on('clientError', (err, socket) => {
640
+ logger_1.log.debug('http clientError', { err: String(err) });
641
+ try {
642
+ socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
643
+ }
644
+ catch {
645
+ /* ignore */
646
+ }
647
+ });
648
+ // WebSocket channels: project event stream AND task streams.
649
+ const wss = new ws_1.WebSocketServer({ server });
650
+ wss.on('error', (err) => logger_1.log.warn('ws server error', { err: String(err) }));
651
+ const watchers = new Map();
652
+ wss.on('connection', (socket, req) => {
653
+ const u = new url_1.URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
654
+ const taskMatch = /^\/ws\/tasks\/([a-f0-9]+)$/.exec(u.pathname);
655
+ if (taskMatch) {
656
+ const ok = (0, task_runner_1.subscribe)(taskMatch[1], socket);
657
+ if (!ok) {
658
+ socket.close(1008, 'unknown task');
659
+ return;
660
+ }
661
+ return;
662
+ }
663
+ // Conversation live-sync channel. Browser tabs subscribe to hear about
664
+ // newly appended turns (from any writer — this tab, another tab, a CLI
665
+ // REPL on the same host, a task runner's result broadcast, etc.).
666
+ const convMatch = /^\/ws\/conversations\/((?:chat|repl|conv)-[a-z0-9_]+)$/.exec(u.pathname);
667
+ if (convMatch) {
668
+ const projectPath = u.searchParams.get('projectPath');
669
+ if (!projectPath) {
670
+ socket.close(1008, 'projectPath required');
671
+ return;
672
+ }
673
+ socket.on('error', (err) => logger_1.log.debug('ws conv socket error', { err: String(err) }));
674
+ const unsubscribe = (0, chat_1.subscribeConversation)(projectPath, convMatch[1], (update) => {
675
+ if (socket.readyState !== socket.OPEN)
676
+ return;
677
+ try {
678
+ socket.send(JSON.stringify({ kind: 'conversation.update', update }));
679
+ }
680
+ catch (err) {
681
+ logger_1.log.debug('ws conv send failed', { err: String(err) });
682
+ }
683
+ });
684
+ socket.on('close', () => unsubscribe());
685
+ return;
686
+ }
687
+ if (u.pathname !== '/ws') {
688
+ socket.close(1008, 'unknown channel');
689
+ return;
690
+ }
691
+ const projectPath = u.searchParams.get('projectPath');
692
+ if (!projectPath) {
693
+ socket.close(1008, 'projectPath required');
694
+ return;
695
+ }
696
+ // Always attach the socket-error handler first so a peer disconnect
697
+ // during send() can't bubble into an uncaught exception.
698
+ socket.on('error', (err) => logger_1.log.debug('ws socket error', { err: String(err) }));
699
+ let resolved;
700
+ try {
701
+ resolved = ensureEventFile(projectPath);
702
+ }
703
+ catch (err) {
704
+ logger_1.log.warn('ws: could not resolve events file', { projectPath, err: String(err) });
705
+ try {
706
+ socket.close(1011, 'event-file-unavailable');
707
+ }
708
+ catch {
709
+ /* ignore close error */
710
+ }
711
+ return;
712
+ }
713
+ let lastSize = 0;
714
+ try {
715
+ lastSize = fs.statSync(resolved).size;
716
+ }
717
+ catch {
718
+ /* created empty above; size is 0 */
719
+ }
720
+ let watcher = null;
721
+ try {
722
+ watcher = fs.watch(resolved, () => {
723
+ try {
724
+ const stat = fs.statSync(resolved);
725
+ if (stat.size <= lastSize)
726
+ return;
727
+ const fd = fs.openSync(resolved, 'r');
728
+ const buf = Buffer.alloc(stat.size - lastSize);
729
+ fs.readSync(fd, buf, 0, buf.length, lastSize);
730
+ fs.closeSync(fd);
731
+ lastSize = stat.size;
732
+ if (socket.readyState !== socket.OPEN)
733
+ return;
734
+ for (const line of buf.toString('utf8').split('\n').filter(Boolean)) {
735
+ try {
736
+ socket.send(line);
737
+ }
738
+ catch (err) {
739
+ logger_1.log.debug('ws send failed', { err: String(err) });
740
+ }
741
+ }
742
+ }
743
+ catch (err) {
744
+ logger_1.log.debug('ws watcher tick error', { err: String(err) });
745
+ }
746
+ });
747
+ watcher.on('error', (err) => {
748
+ logger_1.log.debug('ws watcher error event', { err: String(err) });
749
+ try {
750
+ watcher?.close();
751
+ }
752
+ catch {
753
+ /* ignore close error */
754
+ }
755
+ watchers.delete(String(socket));
756
+ });
757
+ }
758
+ catch (err) {
759
+ // fs.watch itself can throw on some platforms (e.g. rapid file churn).
760
+ logger_1.log.warn('fs.watch failed', { resolved, err: String(err) });
761
+ try {
762
+ socket.close(1011, 'watch-failed');
763
+ }
764
+ catch {
765
+ /* ignore close error */
766
+ }
767
+ return;
768
+ }
769
+ watchers.set(String(socket), watcher);
770
+ socket.on('close', () => {
771
+ const w = watchers.get(String(socket));
772
+ if (w) {
773
+ try {
774
+ w.close();
775
+ }
776
+ catch {
777
+ /* ignore */
778
+ }
779
+ watchers.delete(String(socket));
780
+ }
781
+ });
782
+ });
783
+ server.listen(port, bind, () => {
784
+ logger_1.log.info('ui server listening', { url: `http://${bind}:${port}` });
785
+ resolve({
786
+ port,
787
+ async stop() {
788
+ // Close task-event fs watchers (project event stream).
789
+ for (const w of watchers.values()) {
790
+ try {
791
+ w.close();
792
+ }
793
+ catch {
794
+ /* ignore */
795
+ }
796
+ }
797
+ // Close every conversation watcher + drop broadcasters so the
798
+ // process can exit without lingering handles.
799
+ (0, chat_1.closeAllConversationWatchers)();
800
+ wss.close();
801
+ await new Promise((r) => server.close(() => r()));
802
+ },
803
+ });
804
+ });
805
+ server.on('error', reject);
806
+ });
807
+ };
808
+ exports.startUiServer = startUiServer;
809
+ if (require.main === module) {
810
+ (0, exports.startUiServer)().catch((err) => {
811
+ logger_1.log.error('failed to start ui server', { err: String(err) });
812
+ process.exit(1);
813
+ });
814
+ }
815
+ //# sourceMappingURL=server.js.map