@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,764 @@
1
+ "use strict";
2
+ /**
3
+ * Raw-mode line editor for the Forge REPL.
4
+ *
5
+ * Why a custom editor instead of readline? readline is one-line-at-a-time
6
+ * and gives no hooks for rendering below the input (live suggestions, ghost
7
+ * text, status line). We use Node's keypress parser (readline.emitKeypressEvents)
8
+ * plus raw-mode stdin to own the render loop end-to-end.
9
+ *
10
+ * Rendering model: we keep track of how many rows we drew below the input
11
+ * line on the last frame (`belowRows`). On each keystroke we:
12
+ * 1. Move cursor to column 0 of the input line.
13
+ * 2. Clear from here to end of screen (wipes old dropdown + status).
14
+ * 3. Write prompt + input + inline ghost-text suggestion.
15
+ * 4. Write the dropdown (if any), then the status line.
16
+ * 5. Move cursor back up to the input row and into position.
17
+ *
18
+ * The layout:
19
+ *
20
+ * [1] forge ❯ /stat| us ← cursor; "us" is dim ghost text
21
+ * ╭──────────────────────────────────────╮
22
+ * │ ▸ /status show runtime status │
23
+ * │ /spec specification flow │
24
+ * ╰──────────────────────────────────────╯
25
+ * ⚡ balanced · ollama:qwen2.5 · ~/proj · ctx 820/32k · turn 3 · $0.002
26
+ *
27
+ * The editor itself only deals with input + presentation. The REPL passes
28
+ * in callbacks for prompt/status/suggestions/history/onSubmit/etc.
29
+ */
30
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
34
+ desc = { enumerable: true, get: function() { return m[k]; } };
35
+ }
36
+ Object.defineProperty(o, k2, desc);
37
+ }) : (function(o, m, k, k2) {
38
+ if (k2 === undefined) k2 = k;
39
+ o[k2] = m[k];
40
+ }));
41
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
42
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
43
+ }) : function(o, v) {
44
+ o["default"] = v;
45
+ });
46
+ var __importStar = (this && this.__importStar) || (function () {
47
+ var ownKeys = function(o) {
48
+ ownKeys = Object.getOwnPropertyNames || function (o) {
49
+ var ar = [];
50
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
51
+ return ar;
52
+ };
53
+ return ownKeys(o);
54
+ };
55
+ return function (mod) {
56
+ if (mod && mod.__esModule) return mod;
57
+ var result = {};
58
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
59
+ __setModuleDefault(result, mod);
60
+ return result;
61
+ };
62
+ })();
63
+ var __importDefault = (this && this.__importDefault) || function (mod) {
64
+ return (mod && mod.__esModule) ? mod : { "default": mod };
65
+ };
66
+ Object.defineProperty(exports, "__esModule", { value: true });
67
+ exports.LineEditor = void 0;
68
+ const readline = __importStar(require("readline"));
69
+ const chalk_1 = __importDefault(require("chalk"));
70
+ // ---------- Utilities ----------
71
+ // eslint-disable-next-line no-control-regex -- ANSI CSI sequences need the ESC byte.
72
+ const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
73
+ const visibleWidth = (s) => stripAnsi(s).length;
74
+ const esc = {
75
+ clearScreenDown: '\x1b[0J',
76
+ clearLine: '\x1b[2K',
77
+ cursorUp: (n) => (n > 0 ? `\x1b[${n}A` : ''),
78
+ cursorDown: (n) => (n > 0 ? `\x1b[${n}B` : ''),
79
+ cursorRight: (n) => (n > 0 ? `\x1b[${n}C` : ''),
80
+ cursorCol0: '\r',
81
+ cursorTo: (col) => `\r${col > 0 ? `\x1b[${col}C` : ''}`,
82
+ hideCursor: '\x1b[?25l',
83
+ showCursor: '\x1b[?25h',
84
+ fullClear: '\x1b[2J\x1b[H',
85
+ };
86
+ // ---------- Core class ----------
87
+ class LineEditor {
88
+ buf = '';
89
+ cursor = 0;
90
+ historyIdx = -1; // -1 = live buffer, 0..n-1 = history entries (newest→oldest)
91
+ historyStash = ''; // what was being typed before user entered history
92
+ sel = 0; // selected suggestion index
93
+ lastSuggestions = [];
94
+ done = false;
95
+ blocked = false; // true while onSubmit handler is running
96
+ resolveDone;
97
+ hooks;
98
+ // Kill ring — last text removed by Ctrl+U / Ctrl+K / Ctrl+W / Alt+Backspace.
99
+ // Retrieved via Ctrl+Y (yank). Single-slot for simplicity; good enough.
100
+ killRing = '';
101
+ // Reverse-i-search state. When active, keystrokes feed `searchQuery` and we
102
+ // render a `(reverse-i-search)'q': match` prompt. Esc cancels (restore
103
+ // original buffer); Enter accepts (copy match into buffer); Ctrl+R steps
104
+ // older; any navigation key exits search mode with the match applied.
105
+ searchMode = false;
106
+ searchQuery = '';
107
+ searchCursor = -1; // index in `history` (0 = oldest) of current match; -1 = no match
108
+ searchStash = '';
109
+ searchStashCursor = 0;
110
+ // Double-Esc detection (clear buffer).
111
+ lastEsc = 0;
112
+ constructor(hooks) {
113
+ this.hooks = hooks;
114
+ }
115
+ async run() {
116
+ return new Promise((resolve) => {
117
+ this.resolveDone = resolve;
118
+ readline.emitKeypressEvents(process.stdin);
119
+ if (process.stdin.isTTY)
120
+ process.stdin.setRawMode(true);
121
+ process.stdin.resume();
122
+ this.render(true);
123
+ process.stdin.on('keypress', this.onKey);
124
+ });
125
+ }
126
+ /** Pause input without teardown (used during task execution). */
127
+ suspend() {
128
+ process.stdin.off('keypress', this.onKey);
129
+ if (process.stdin.isTTY)
130
+ process.stdin.setRawMode(false);
131
+ // clear our rendered region so command output lands cleanly
132
+ this.eraseBelowAndPromptRow();
133
+ }
134
+ /** Resume after task completion. */
135
+ resume() {
136
+ if (process.stdin.isTTY)
137
+ process.stdin.setRawMode(true);
138
+ process.stdin.resume();
139
+ process.stdin.on('keypress', this.onKey);
140
+ this.render(true);
141
+ }
142
+ close() {
143
+ if (this.done)
144
+ return;
145
+ this.done = true;
146
+ this.eraseBelowAndPromptRow();
147
+ process.stdin.off('keypress', this.onKey);
148
+ if (process.stdin.isTTY)
149
+ process.stdin.setRawMode(false);
150
+ process.stdin.pause();
151
+ process.stdout.write(esc.showCursor);
152
+ this.resolveDone?.();
153
+ }
154
+ // ---------- Key handling ----------
155
+ onKey = (str, key) => {
156
+ if (this.done)
157
+ return;
158
+ const name = key?.name ?? '';
159
+ const ctrl = Boolean(key?.ctrl);
160
+ const meta = Boolean(key?.meta);
161
+ const shift = Boolean(key?.shift);
162
+ // While submitting / task running: only Ctrl+C is honoured (→ task cancel)
163
+ if (this.blocked || this.hooks.isRunning?.()) {
164
+ if (ctrl && name === 'c')
165
+ this.hooks.onCancel();
166
+ return;
167
+ }
168
+ // Reverse-i-search mode owns its own key handling.
169
+ if (this.searchMode) {
170
+ this.handleSearchKey(str, key);
171
+ return;
172
+ }
173
+ // Idle Ctrl+C:
174
+ // - non-empty buffer → clear the line (like zsh/bash)
175
+ // - empty buffer → delegate to the hook, which tracks double-press exit
176
+ if (ctrl && name === 'c') {
177
+ if (this.buf.length > 0) {
178
+ this.buf = '';
179
+ this.cursor = 0;
180
+ this.historyIdx = -1;
181
+ this.sel = 0;
182
+ // echo ^C then redraw a fresh prompt on the next line
183
+ process.stdout.write(chalk_1.default.dim('^C\n'));
184
+ this.render(true);
185
+ return;
186
+ }
187
+ this.hooks.onCancel();
188
+ return;
189
+ }
190
+ // Ctrl+D: exit if buffer empty, else delete-at-cursor
191
+ if (ctrl && name === 'd') {
192
+ if (this.buf.length === 0) {
193
+ this.hooks.onExit();
194
+ return;
195
+ }
196
+ this.deleteAtCursor();
197
+ this.render();
198
+ return;
199
+ }
200
+ // Ctrl+L: clear screen and redraw
201
+ if (ctrl && name === 'l') {
202
+ process.stdout.write(esc.fullClear);
203
+ this.render(true);
204
+ return;
205
+ }
206
+ // Ctrl+A / Home: start of line
207
+ if ((ctrl && name === 'a') || name === 'home') {
208
+ this.cursor = 0;
209
+ this.render();
210
+ return;
211
+ }
212
+ // Ctrl+E / End: end of line
213
+ if ((ctrl && name === 'e') || name === 'end') {
214
+ this.cursor = this.buf.length;
215
+ this.render();
216
+ return;
217
+ }
218
+ // Ctrl+U: delete to start (→ kill ring)
219
+ if (ctrl && name === 'u') {
220
+ this.killRing = this.buf.slice(0, this.cursor);
221
+ this.buf = this.buf.slice(this.cursor);
222
+ this.cursor = 0;
223
+ this.render();
224
+ return;
225
+ }
226
+ // Ctrl+K: delete to end (→ kill ring)
227
+ if (ctrl && name === 'k') {
228
+ this.killRing = this.buf.slice(this.cursor);
229
+ this.buf = this.buf.slice(0, this.cursor);
230
+ this.render();
231
+ return;
232
+ }
233
+ // Ctrl+W / Alt+Backspace: delete word backward (→ kill ring)
234
+ if ((ctrl && name === 'w') || (meta && name === 'backspace')) {
235
+ const left = this.buf.slice(0, this.cursor);
236
+ const right = this.buf.slice(this.cursor);
237
+ const trimmed = left.replace(/\S+\s*$/, '');
238
+ this.killRing = left.slice(trimmed.length);
239
+ this.cursor = trimmed.length;
240
+ this.buf = trimmed + right;
241
+ this.render();
242
+ return;
243
+ }
244
+ // Ctrl+Y: yank from kill ring at cursor
245
+ if (ctrl && name === 'y') {
246
+ if (this.killRing) {
247
+ this.buf = this.buf.slice(0, this.cursor) + this.killRing + this.buf.slice(this.cursor);
248
+ this.cursor += this.killRing.length;
249
+ this.render();
250
+ }
251
+ return;
252
+ }
253
+ // Ctrl+T: transpose the two chars around cursor (emacs classic)
254
+ if (ctrl && name === 't') {
255
+ if (this.buf.length >= 2) {
256
+ const pos = this.cursor === this.buf.length ? this.cursor - 1 : this.cursor;
257
+ if (pos >= 1) {
258
+ const chars = this.buf.split('');
259
+ [chars[pos - 1], chars[pos]] = [chars[pos], chars[pos - 1]];
260
+ this.buf = chars.join('');
261
+ if (this.cursor < this.buf.length)
262
+ this.cursor++;
263
+ }
264
+ }
265
+ this.render();
266
+ return;
267
+ }
268
+ // Alt+B: move cursor one word back
269
+ if (meta && name === 'b') {
270
+ const left = this.buf.slice(0, this.cursor);
271
+ const m = left.match(/(?:\s*\S+)\s*$/);
272
+ if (m) {
273
+ const trimmed = left.replace(/(?:\s*\S+)\s*$/, (x) => {
274
+ // keep leading whitespace, move only past the last word
275
+ const trailing = x.match(/\s*$/)?.[0] ?? '';
276
+ return x.slice(0, x.length - (x.length - trailing.length));
277
+ });
278
+ this.cursor = Math.max(0, this.cursor - (m[0].length - (m[0].match(/\s*$/)?.[0].length ?? 0)));
279
+ // simpler: recompute
280
+ const idx = this.buf.slice(0, this.cursor).search(/\S(?!.*\S)/);
281
+ void trimmed;
282
+ void idx;
283
+ }
284
+ // Re-derive cleanly: find start of previous word
285
+ let p = this.cursor;
286
+ while (p > 0 && /\s/.test(this.buf[p - 1]))
287
+ p--;
288
+ while (p > 0 && !/\s/.test(this.buf[p - 1]))
289
+ p--;
290
+ this.cursor = p;
291
+ this.render();
292
+ return;
293
+ }
294
+ // Alt+F: move cursor one word forward
295
+ if (meta && name === 'f') {
296
+ let p = this.cursor;
297
+ while (p < this.buf.length && /\s/.test(this.buf[p]))
298
+ p++;
299
+ while (p < this.buf.length && !/\s/.test(this.buf[p]))
300
+ p++;
301
+ this.cursor = p;
302
+ this.render();
303
+ return;
304
+ }
305
+ // Ctrl+R: enter reverse-i-search
306
+ if (ctrl && name === 'r') {
307
+ this.enterSearchMode();
308
+ return;
309
+ }
310
+ // Alt+Enter or Ctrl+J: insert newline at cursor (multi-line compose)
311
+ if ((meta && (name === 'return' || name === 'enter')) || (ctrl && name === 'j')) {
312
+ this.buf = this.buf.slice(0, this.cursor) + '\n' + this.buf.slice(this.cursor);
313
+ this.cursor++;
314
+ this.render();
315
+ return;
316
+ }
317
+ // F1: /help · F2: /sessions · F3: /new
318
+ if (name === 'f1') {
319
+ void this.submitLiteral('/help');
320
+ return;
321
+ }
322
+ if (name === 'f2') {
323
+ void this.submitLiteral('/sessions');
324
+ return;
325
+ }
326
+ if (name === 'f3') {
327
+ void this.submitLiteral('/new');
328
+ return;
329
+ }
330
+ // Enter: submit
331
+ if (name === 'return' || name === 'enter') {
332
+ if (this.hooks.isRunning?.())
333
+ return; // ignore while a task runs
334
+ void this.submit();
335
+ return;
336
+ }
337
+ // Tab: accept suggestion (or cycle)
338
+ if (name === 'tab' && !shift) {
339
+ if (this.lastSuggestions.length) {
340
+ const pick = this.lastSuggestions[this.sel] ?? this.lastSuggestions[0];
341
+ this.buf = pick.value + ' ';
342
+ this.cursor = this.buf.length;
343
+ this.sel = 0;
344
+ this.render();
345
+ }
346
+ return;
347
+ }
348
+ if (name === 'tab' && shift) {
349
+ if (this.lastSuggestions.length) {
350
+ this.sel = (this.sel - 1 + this.lastSuggestions.length) % this.lastSuggestions.length;
351
+ this.render();
352
+ }
353
+ return;
354
+ }
355
+ // Arrow up/down: if dropdown visible, navigate; else history
356
+ if (name === 'up') {
357
+ if (this.lastSuggestions.length > 1) {
358
+ this.sel = (this.sel - 1 + this.lastSuggestions.length) % this.lastSuggestions.length;
359
+ this.render();
360
+ }
361
+ else {
362
+ this.historyPrev();
363
+ }
364
+ return;
365
+ }
366
+ if (name === 'down') {
367
+ if (this.lastSuggestions.length > 1) {
368
+ this.sel = (this.sel + 1) % this.lastSuggestions.length;
369
+ this.render();
370
+ }
371
+ else {
372
+ this.historyNext();
373
+ }
374
+ return;
375
+ }
376
+ // Arrow left/right: cursor nav
377
+ if (name === 'left') {
378
+ if (this.cursor > 0)
379
+ this.cursor--;
380
+ this.render();
381
+ return;
382
+ }
383
+ if (name === 'right') {
384
+ // if at end and we have a ghost suggestion, accept the ghost
385
+ if (this.cursor === this.buf.length && this.ghostSuffix()) {
386
+ const g = this.ghostSuffix();
387
+ if (g) {
388
+ this.buf += g;
389
+ this.cursor = this.buf.length;
390
+ }
391
+ }
392
+ else if (this.cursor < this.buf.length) {
393
+ this.cursor++;
394
+ }
395
+ this.render();
396
+ return;
397
+ }
398
+ // Backspace
399
+ if (name === 'backspace') {
400
+ if (this.cursor > 0) {
401
+ this.buf = this.buf.slice(0, this.cursor - 1) + this.buf.slice(this.cursor);
402
+ this.cursor--;
403
+ }
404
+ this.render();
405
+ return;
406
+ }
407
+ // Delete
408
+ if (name === 'delete') {
409
+ this.deleteAtCursor();
410
+ this.render();
411
+ return;
412
+ }
413
+ // Escape: once dismisses dropdown selection; pressing Esc again within
414
+ // 500ms clears the whole buffer (zsh-like).
415
+ if (name === 'escape') {
416
+ const now = Date.now();
417
+ if (now - this.lastEsc < 500 && this.buf.length > 0) {
418
+ this.buf = '';
419
+ this.cursor = 0;
420
+ this.historyIdx = -1;
421
+ this.sel = 0;
422
+ this.lastEsc = 0;
423
+ }
424
+ else {
425
+ this.sel = 0;
426
+ this.lastEsc = now;
427
+ }
428
+ this.render();
429
+ return;
430
+ }
431
+ // Printable char insertion
432
+ if (str && !meta && !ctrl && str.length === 1 && str.charCodeAt(0) >= 32) {
433
+ this.buf = this.buf.slice(0, this.cursor) + str + this.buf.slice(this.cursor);
434
+ this.cursor++;
435
+ this.historyIdx = -1;
436
+ this.sel = 0;
437
+ this.render();
438
+ return;
439
+ }
440
+ // Bracketed paste or multi-char input: insert verbatim, minus newlines
441
+ if (str && str.length > 1 && !ctrl && !meta) {
442
+ const clean = str.replace(/[\r\n]+/g, ' ');
443
+ this.buf = this.buf.slice(0, this.cursor) + clean + this.buf.slice(this.cursor);
444
+ this.cursor += clean.length;
445
+ this.render();
446
+ return;
447
+ }
448
+ };
449
+ deleteAtCursor() {
450
+ if (this.cursor < this.buf.length) {
451
+ this.buf = this.buf.slice(0, this.cursor) + this.buf.slice(this.cursor + 1);
452
+ }
453
+ }
454
+ historyPrev() {
455
+ const h = this.hooks.history;
456
+ if (!h.length)
457
+ return;
458
+ if (this.historyIdx === -1)
459
+ this.historyStash = this.buf;
460
+ this.historyIdx = Math.min(this.historyIdx + 1, h.length - 1);
461
+ this.buf = h[h.length - 1 - this.historyIdx] ?? '';
462
+ this.cursor = this.buf.length;
463
+ this.render();
464
+ }
465
+ historyNext() {
466
+ const h = this.hooks.history;
467
+ if (!h.length || this.historyIdx === -1)
468
+ return;
469
+ this.historyIdx--;
470
+ if (this.historyIdx === -1) {
471
+ this.buf = this.historyStash;
472
+ }
473
+ else {
474
+ this.buf = h[h.length - 1 - this.historyIdx] ?? '';
475
+ }
476
+ this.cursor = this.buf.length;
477
+ this.render();
478
+ }
479
+ // ---------- Submit ----------
480
+ async submit() {
481
+ const raw = this.buf;
482
+ let picked;
483
+ // If the input starts with a slash and there are suggestions, apply the
484
+ // highest-ranked match when the literal input doesn't exactly equal any
485
+ // command.
486
+ if (raw.startsWith('/') && this.lastSuggestions.length) {
487
+ const first = this.lastSuggestions[0];
488
+ const head = raw.slice(1).split(/\s+/, 1)[0] ?? '';
489
+ const exact = this.lastSuggestions.find((s) => s.value.slice(1) === head);
490
+ if (!exact) {
491
+ // rewrite buf so display + handler see the normalised command
492
+ picked = first;
493
+ }
494
+ }
495
+ this.eraseBelowAndPromptRow();
496
+ // Echo the line as entered (with picked hint if any)
497
+ const prompt = this.hooks.prompt();
498
+ const line = picked ? chalk_1.default.white(raw) + chalk_1.default.dim(` ↳ ${picked.label}`) : chalk_1.default.white(raw);
499
+ process.stdout.write(prompt + line + '\n');
500
+ this.buf = '';
501
+ this.cursor = 0;
502
+ this.historyIdx = -1;
503
+ this.sel = 0;
504
+ this.lastSuggestions = [];
505
+ const final = picked
506
+ ? picked.value + raw.slice(raw.indexOf(' ') >= 0 ? raw.indexOf(' ') : raw.length)
507
+ : raw;
508
+ this.blocked = true;
509
+ try {
510
+ await this.hooks.onSubmit(final.trim(), picked);
511
+ }
512
+ catch (e) {
513
+ process.stdout.write(chalk_1.default.red(`\nEditor submit error: ${e instanceof Error ? e.message : String(e)}\n`));
514
+ }
515
+ finally {
516
+ this.blocked = false;
517
+ }
518
+ if (!this.done)
519
+ this.render(true);
520
+ }
521
+ /** Fire a command without going through user editing — used by F-keys. */
522
+ async submitLiteral(text) {
523
+ this.buf = text;
524
+ this.cursor = text.length;
525
+ this.sel = 0;
526
+ this.lastSuggestions = this.hooks.suggestions(text);
527
+ await this.submit();
528
+ }
529
+ // ---------- Reverse-i-search ----------
530
+ enterSearchMode() {
531
+ this.searchMode = true;
532
+ this.searchQuery = '';
533
+ this.searchCursor = -1;
534
+ this.searchStash = this.buf;
535
+ this.searchStashCursor = this.cursor;
536
+ this.sel = 0;
537
+ this.lastSuggestions = [];
538
+ this.renderSearch();
539
+ }
540
+ exitSearchMode(apply) {
541
+ this.searchMode = false;
542
+ if (apply && this.searchCursor >= 0) {
543
+ const match = this.hooks.history[this.searchCursor];
544
+ if (match !== undefined) {
545
+ this.buf = match;
546
+ this.cursor = match.length;
547
+ }
548
+ }
549
+ else {
550
+ this.buf = this.searchStash;
551
+ this.cursor = this.searchStashCursor;
552
+ }
553
+ this.searchQuery = '';
554
+ this.searchCursor = -1;
555
+ this.render(true);
556
+ }
557
+ findMatch(startAt, backwards = true) {
558
+ const h = this.hooks.history;
559
+ const q = this.searchQuery.toLowerCase();
560
+ if (!q)
561
+ return -1;
562
+ // history is newest-last; "reverse" means newer → older.
563
+ for (let i = startAt; backwards ? i >= 0 : i < h.length; i += backwards ? -1 : 1) {
564
+ if ((h[i] ?? '').toLowerCase().includes(q))
565
+ return i;
566
+ }
567
+ return -1;
568
+ }
569
+ handleSearchKey(str, key) {
570
+ const name = key?.name ?? '';
571
+ const ctrl = Boolean(key?.ctrl);
572
+ const meta = Boolean(key?.meta);
573
+ // Cancel — restore pre-search buffer
574
+ if (ctrl && name === 'c') {
575
+ this.exitSearchMode(false);
576
+ return;
577
+ }
578
+ if (name === 'escape') {
579
+ this.exitSearchMode(false);
580
+ return;
581
+ }
582
+ // Accept match into buffer, exit search mode, but don't auto-submit.
583
+ if (name === 'return' || name === 'enter') {
584
+ this.exitSearchMode(true);
585
+ return;
586
+ }
587
+ // Ctrl+R: find next older match
588
+ if (ctrl && name === 'r') {
589
+ const h = this.hooks.history;
590
+ const from = this.searchCursor === -1 ? h.length - 1 : this.searchCursor - 1;
591
+ const idx = this.findMatch(from, true);
592
+ if (idx >= 0)
593
+ this.searchCursor = idx;
594
+ this.renderSearch();
595
+ return;
596
+ }
597
+ // Ctrl+S: find next newer match (if terminal doesn't swallow it)
598
+ if (ctrl && name === 's') {
599
+ const from = this.searchCursor === -1 ? 0 : this.searchCursor + 1;
600
+ const idx = this.findMatch(from, false);
601
+ if (idx >= 0)
602
+ this.searchCursor = idx;
603
+ this.renderSearch();
604
+ return;
605
+ }
606
+ // Backspace: shrink query
607
+ if (name === 'backspace') {
608
+ this.searchQuery = this.searchQuery.slice(0, -1);
609
+ this.searchCursor = this.findMatch(this.hooks.history.length - 1, true);
610
+ this.renderSearch();
611
+ return;
612
+ }
613
+ // Navigation or Tab — accept the match, exit search, keep the key's behaviour
614
+ if (name === 'left' ||
615
+ name === 'right' ||
616
+ name === 'home' ||
617
+ name === 'end' ||
618
+ name === 'tab') {
619
+ this.exitSearchMode(true);
620
+ return;
621
+ }
622
+ // Printable char: extend query
623
+ if (str && !meta && !ctrl && str.length === 1 && str.charCodeAt(0) >= 32) {
624
+ this.searchQuery += str;
625
+ // search from the current position (so successive chars narrow the same match)
626
+ const startFrom = this.searchCursor === -1 ? this.hooks.history.length - 1 : this.searchCursor;
627
+ this.searchCursor = this.findMatch(startFrom, true);
628
+ this.renderSearch();
629
+ return;
630
+ }
631
+ }
632
+ renderSearch() {
633
+ // Layout:
634
+ // (reverse-i-search)`query': matched text
635
+ // <status line>
636
+ this.eraseBelowAndPromptRow();
637
+ const h = this.hooks.history;
638
+ const match = this.searchCursor >= 0 ? (h[this.searchCursor] ?? '') : '';
639
+ const label = chalk_1.default.yellow('(reverse-i-search)');
640
+ const q = chalk_1.default.bold(`'${this.searchQuery}'`);
641
+ const result = this.searchCursor >= 0
642
+ ? chalk_1.default.white(match)
643
+ : this.searchQuery
644
+ ? chalk_1.default.red('(no match)')
645
+ : chalk_1.default.dim('(type to search · ↵ accept · esc cancel · C-r older · C-s newer)');
646
+ process.stdout.write(`${label}${q}: ${result}`);
647
+ // status line below
648
+ process.stdout.write('\n\n' + this.hooks.statusLine());
649
+ // position cursor at end of query (purely cosmetic — edits are query-only)
650
+ process.stdout.write(esc.cursorUp(2));
651
+ const cursorCol = stripAnsi(`(reverse-i-search)'${this.searchQuery}`).length;
652
+ process.stdout.write(esc.cursorTo(cursorCol));
653
+ }
654
+ // ---------- Rendering ----------
655
+ ghostSuffix() {
656
+ if (!this.buf.startsWith('/'))
657
+ return null;
658
+ if (!this.lastSuggestions.length)
659
+ return null;
660
+ const top = this.lastSuggestions[this.sel] ?? this.lastSuggestions[0];
661
+ if (!top)
662
+ return null;
663
+ if (!top.value.startsWith(this.buf))
664
+ return null;
665
+ return top.value.slice(this.buf.length);
666
+ }
667
+ render(initial = false) {
668
+ // Refresh suggestions for current buffer
669
+ this.lastSuggestions = this.hooks.suggestions(this.buf);
670
+ if (this.sel >= this.lastSuggestions.length)
671
+ this.sel = 0;
672
+ if (!initial)
673
+ this.eraseBelowAndPromptRow();
674
+ else {
675
+ // First render: just sit at current cursor position, don't erase above
676
+ process.stdout.write(esc.clearScreenDown);
677
+ }
678
+ const prompt = this.hooks.prompt();
679
+ const promptWidth = visibleWidth(prompt);
680
+ // Render newlines inside the input as a visible ↵ glyph so a multi-line
681
+ // compose (Alt+Enter) stays on the same visual row. The raw buffer keeps
682
+ // the \n for submission; only the display is munged.
683
+ const NL_GLYPH = chalk_1.default.dim('↵ ');
684
+ const renderBuf = this.buf.replace(/\n/g, NL_GLYPH);
685
+ const ghost = this.ghostSuffix();
686
+ const inputSegment = renderBuf + (ghost ? chalk_1.default.dim(ghost) : '');
687
+ process.stdout.write(prompt + inputSegment);
688
+ // Cursor column = promptWidth + visible chars before cursor. Each \n
689
+ // before the cursor becomes 2 visible chars (the ↵ glyph + space).
690
+ const newlinesBefore = (this.buf.slice(0, this.cursor).match(/\n/g) ?? []).length;
691
+ const cursorCol = promptWidth + this.cursor + newlinesBefore;
692
+ // Render dropdown + status line below
693
+ const belowLines = [];
694
+ const drop = this.renderDropdown();
695
+ if (drop.length)
696
+ belowLines.push(...drop, '');
697
+ else
698
+ belowLines.push('');
699
+ belowLines.push(this.hooks.statusLine());
700
+ let belowCount = 0;
701
+ for (const line of belowLines) {
702
+ process.stdout.write('\n' + line);
703
+ belowCount++;
704
+ }
705
+ // Move cursor up back to input row, then to correct column
706
+ if (belowCount > 0)
707
+ process.stdout.write(esc.cursorUp(belowCount));
708
+ process.stdout.write(esc.cursorTo(cursorCol));
709
+ }
710
+ renderDropdown() {
711
+ const s = this.lastSuggestions;
712
+ if (!s.length || !this.buf.startsWith('/'))
713
+ return [];
714
+ const maxShown = 6;
715
+ const visible = s.slice(0, maxShown);
716
+ // Layout budget. The inner row is built as:
717
+ // " ▸ <label:labelCol> <desc:descBudget>"
718
+ // where everything between the │ borders is exactly `innerW` visible chars.
719
+ const pad = ' '.repeat(12);
720
+ const termCols = process.stdout.columns && process.stdout.columns > 30 ? process.stdout.columns : 120;
721
+ const maxBox = Math.min(86, Math.max(44, termCols - pad.length - 2));
722
+ const innerW = maxBox - 2; // between │ and │
723
+ const labelCol = Math.min(20, Math.max(12, Math.floor(innerW * 0.28)));
724
+ // " " + arrow + " " + label + " " + desc → fixed chrome width = 4
725
+ const descBudget = Math.max(8, innerW - labelCol - 4);
726
+ // Truncate a plain string to fit `max` visible chars. Ellipsis on overflow.
727
+ const fit = (raw, max) => {
728
+ if (raw.length <= max)
729
+ return raw + ' '.repeat(max - raw.length);
730
+ if (max <= 1)
731
+ return '…'.slice(0, max);
732
+ return raw.slice(0, max - 1) + '…';
733
+ };
734
+ const lines = [];
735
+ lines.push(pad + chalk_1.default.dim('╭' + '─'.repeat(innerW) + '╮'));
736
+ visible.forEach((sg, i) => {
737
+ const isSel = i === this.sel;
738
+ const arrow = isSel ? chalk_1.default.bold.cyan('▸') : ' ';
739
+ const labelText = fit(sg.label, labelCol);
740
+ const descText = fit(sg.description ?? '', descBudget);
741
+ const labelColored = isSel ? chalk_1.default.bold.cyan(labelText) : chalk_1.default.cyan(labelText);
742
+ const descColored = chalk_1.default.dim(descText);
743
+ // Row body, by construction visible width == innerW.
744
+ const row = ` ${arrow} ${labelColored} ${descColored}`;
745
+ // Safety assertion in case label or desc contained stray wide chars
746
+ const surplus = visibleWidth(row) - innerW;
747
+ const safeRow = surplus > 0 ? row.slice(0, row.length - surplus) : row;
748
+ lines.push(pad + chalk_1.default.dim('│') + safeRow + chalk_1.default.dim('│'));
749
+ });
750
+ if (s.length > maxShown) {
751
+ const text = fit(` …+${s.length - maxShown} more`, innerW);
752
+ lines.push(pad + chalk_1.default.dim('│') + chalk_1.default.dim(text) + chalk_1.default.dim('│'));
753
+ }
754
+ lines.push(pad + chalk_1.default.dim('╰' + '─'.repeat(innerW) + '╯'));
755
+ return lines;
756
+ }
757
+ eraseBelowAndPromptRow() {
758
+ // Move to col 0 of input row, wipe it + everything below
759
+ process.stdout.write(esc.cursorCol0);
760
+ process.stdout.write(esc.clearScreenDown);
761
+ }
762
+ }
763
+ exports.LineEditor = LineEditor;
764
+ //# sourceMappingURL=repl-input.js.map