@edwardlee5423/magi 0.1.0-alpha.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 (531) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/dist/agent/headless-agent.d.ts +15 -0
  4. package/dist/agent/headless-agent.js +105 -0
  5. package/dist/agent/headless-agent.js.map +1 -0
  6. package/dist/agent/local-plan.d.ts +20 -0
  7. package/dist/agent/local-plan.js +30 -0
  8. package/dist/agent/local-plan.js.map +1 -0
  9. package/dist/agent/query-engine.d.ts +71 -0
  10. package/dist/agent/query-engine.js +938 -0
  11. package/dist/agent/query-engine.js.map +1 -0
  12. package/dist/agent/query.d.ts +128 -0
  13. package/dist/agent/query.js +674 -0
  14. package/dist/agent/query.js.map +1 -0
  15. package/dist/agent/system-prompt.d.ts +12 -0
  16. package/dist/agent/system-prompt.js +104 -0
  17. package/dist/agent/system-prompt.js.map +1 -0
  18. package/dist/agent/tools.d.ts +71 -0
  19. package/dist/agent/tools.js +37 -0
  20. package/dist/agent/tools.js.map +1 -0
  21. package/dist/agents/roles.d.ts +9 -0
  22. package/dist/agents/roles.js +18 -0
  23. package/dist/agents/roles.js.map +1 -0
  24. package/dist/agents/task-queue.d.ts +13 -0
  25. package/dist/agents/task-queue.js +50 -0
  26. package/dist/agents/task-queue.js.map +1 -0
  27. package/dist/cli.d.ts +7 -0
  28. package/dist/cli.js +1540 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/colors.d.ts +20 -0
  31. package/dist/colors.js +92 -0
  32. package/dist/colors.js.map +1 -0
  33. package/dist/commands/agents.d.ts +9 -0
  34. package/dist/commands/agents.js +37 -0
  35. package/dist/commands/agents.js.map +1 -0
  36. package/dist/commands/clear.d.ts +9 -0
  37. package/dist/commands/clear.js +20 -0
  38. package/dist/commands/clear.js.map +1 -0
  39. package/dist/commands/commit.d.ts +8 -0
  40. package/dist/commands/commit.js +35 -0
  41. package/dist/commands/commit.js.map +1 -0
  42. package/dist/commands/compact.d.ts +8 -0
  43. package/dist/commands/compact.js +29 -0
  44. package/dist/commands/compact.js.map +1 -0
  45. package/dist/commands/copy.d.ts +8 -0
  46. package/dist/commands/copy.js +49 -0
  47. package/dist/commands/copy.js.map +1 -0
  48. package/dist/commands/cost.d.ts +8 -0
  49. package/dist/commands/cost.js +94 -0
  50. package/dist/commands/cost.js.map +1 -0
  51. package/dist/commands/diff.d.ts +8 -0
  52. package/dist/commands/diff.js +38 -0
  53. package/dist/commands/diff.js.map +1 -0
  54. package/dist/commands/doctor.d.ts +8 -0
  55. package/dist/commands/doctor.js +23 -0
  56. package/dist/commands/doctor.js.map +1 -0
  57. package/dist/commands/export.d.ts +8 -0
  58. package/dist/commands/export.js +42 -0
  59. package/dist/commands/export.js.map +1 -0
  60. package/dist/commands/fork.d.ts +8 -0
  61. package/dist/commands/fork.js +20 -0
  62. package/dist/commands/fork.js.map +1 -0
  63. package/dist/commands/goal.d.ts +9 -0
  64. package/dist/commands/goal.js +54 -0
  65. package/dist/commands/goal.js.map +1 -0
  66. package/dist/commands/help.d.ts +8 -0
  67. package/dist/commands/help.js +65 -0
  68. package/dist/commands/help.js.map +1 -0
  69. package/dist/commands/hooks.d.ts +8 -0
  70. package/dist/commands/hooks.js +56 -0
  71. package/dist/commands/hooks.js.map +1 -0
  72. package/dist/commands/image.d.ts +17 -0
  73. package/dist/commands/image.js +74 -0
  74. package/dist/commands/image.js.map +1 -0
  75. package/dist/commands/init.d.ts +26 -0
  76. package/dist/commands/init.js +214 -0
  77. package/dist/commands/init.js.map +1 -0
  78. package/dist/commands/mcp.d.ts +8 -0
  79. package/dist/commands/mcp.js +217 -0
  80. package/dist/commands/mcp.js.map +1 -0
  81. package/dist/commands/memory.d.ts +8 -0
  82. package/dist/commands/memory.js +79 -0
  83. package/dist/commands/memory.js.map +1 -0
  84. package/dist/commands/model.d.ts +8 -0
  85. package/dist/commands/model.js +21 -0
  86. package/dist/commands/model.js.map +1 -0
  87. package/dist/commands/permissions.d.ts +9 -0
  88. package/dist/commands/permissions.js +30 -0
  89. package/dist/commands/permissions.js.map +1 -0
  90. package/dist/commands/proactive.d.ts +9 -0
  91. package/dist/commands/proactive.js +24 -0
  92. package/dist/commands/proactive.js.map +1 -0
  93. package/dist/commands/register-all.d.ts +1 -0
  94. package/dist/commands/register-all.js +68 -0
  95. package/dist/commands/register-all.js.map +1 -0
  96. package/dist/commands/registry.d.ts +64 -0
  97. package/dist/commands/registry.js +235 -0
  98. package/dist/commands/registry.js.map +1 -0
  99. package/dist/commands/rename.d.ts +8 -0
  100. package/dist/commands/rename.js +16 -0
  101. package/dist/commands/rename.js.map +1 -0
  102. package/dist/commands/review.d.ts +8 -0
  103. package/dist/commands/review.js +13 -0
  104. package/dist/commands/review.js.map +1 -0
  105. package/dist/commands/rewind.d.ts +8 -0
  106. package/dist/commands/rewind.js +45 -0
  107. package/dist/commands/rewind.js.map +1 -0
  108. package/dist/commands/route.d.ts +9 -0
  109. package/dist/commands/route.js +83 -0
  110. package/dist/commands/route.js.map +1 -0
  111. package/dist/commands/sessions.d.ts +9 -0
  112. package/dist/commands/sessions.js +25 -0
  113. package/dist/commands/sessions.js.map +1 -0
  114. package/dist/commands/skill.d.ts +9 -0
  115. package/dist/commands/skill.js +46 -0
  116. package/dist/commands/skill.js.map +1 -0
  117. package/dist/commands/status.d.ts +8 -0
  118. package/dist/commands/status.js +41 -0
  119. package/dist/commands/status.js.map +1 -0
  120. package/dist/commands/summary.d.ts +8 -0
  121. package/dist/commands/summary.js +39 -0
  122. package/dist/commands/summary.js.map +1 -0
  123. package/dist/commands/tasks.d.ts +9 -0
  124. package/dist/commands/tasks.js +70 -0
  125. package/dist/commands/tasks.js.map +1 -0
  126. package/dist/commands/todos.d.ts +9 -0
  127. package/dist/commands/todos.js +27 -0
  128. package/dist/commands/todos.js.map +1 -0
  129. package/dist/commands/tutorial.d.ts +8 -0
  130. package/dist/commands/tutorial.js +159 -0
  131. package/dist/commands/tutorial.js.map +1 -0
  132. package/dist/commands/upgrade.d.ts +9 -0
  133. package/dist/commands/upgrade.js +73 -0
  134. package/dist/commands/upgrade.js.map +1 -0
  135. package/dist/commands/usage.d.ts +8 -0
  136. package/dist/commands/usage.js +54 -0
  137. package/dist/commands/usage.js.map +1 -0
  138. package/dist/commands/vim.d.ts +10 -0
  139. package/dist/commands/vim.js +34 -0
  140. package/dist/commands/vim.js.map +1 -0
  141. package/dist/config.d.ts +104 -0
  142. package/dist/config.js +533 -0
  143. package/dist/config.js.map +1 -0
  144. package/dist/context/compaction.d.ts +66 -0
  145. package/dist/context/compaction.js +353 -0
  146. package/dist/context/compaction.js.map +1 -0
  147. package/dist/context/layers.d.ts +32 -0
  148. package/dist/context/layers.js +114 -0
  149. package/dist/context/layers.js.map +1 -0
  150. package/dist/context/token-budget.d.ts +21 -0
  151. package/dist/context/token-budget.js +70 -0
  152. package/dist/context/token-budget.js.map +1 -0
  153. package/dist/control/auth.d.ts +17 -0
  154. package/dist/control/auth.js +31 -0
  155. package/dist/control/auth.js.map +1 -0
  156. package/dist/control/daemon.d.ts +38 -0
  157. package/dist/control/daemon.js +135 -0
  158. package/dist/control/daemon.js.map +1 -0
  159. package/dist/control/mdns.d.ts +51 -0
  160. package/dist/control/mdns.js +344 -0
  161. package/dist/control/mdns.js.map +1 -0
  162. package/dist/control/peer-client.d.ts +49 -0
  163. package/dist/control/peer-client.js +170 -0
  164. package/dist/control/peer-client.js.map +1 -0
  165. package/dist/control/server.d.ts +30 -0
  166. package/dist/control/server.js +887 -0
  167. package/dist/control/server.js.map +1 -0
  168. package/dist/cost.d.ts +23 -0
  169. package/dist/cost.js +80 -0
  170. package/dist/cost.js.map +1 -0
  171. package/dist/doctor.d.ts +8 -0
  172. package/dist/doctor.js +22 -0
  173. package/dist/doctor.js.map +1 -0
  174. package/dist/env.d.ts +7 -0
  175. package/dist/env.js +70 -0
  176. package/dist/env.js.map +1 -0
  177. package/dist/errors.d.ts +6 -0
  178. package/dist/errors.js +13 -0
  179. package/dist/errors.js.map +1 -0
  180. package/dist/events.d.ts +19 -0
  181. package/dist/events.js +236 -0
  182. package/dist/events.js.map +1 -0
  183. package/dist/fs-utils.d.ts +21 -0
  184. package/dist/fs-utils.js +48 -0
  185. package/dist/fs-utils.js.map +1 -0
  186. package/dist/goal.d.ts +32 -0
  187. package/dist/goal.js +172 -0
  188. package/dist/goal.js.map +1 -0
  189. package/dist/headless.d.ts +38 -0
  190. package/dist/headless.js +547 -0
  191. package/dist/headless.js.map +1 -0
  192. package/dist/history.d.ts +8 -0
  193. package/dist/history.js +77 -0
  194. package/dist/history.js.map +1 -0
  195. package/dist/hooks/events.d.ts +14 -0
  196. package/dist/hooks/events.js +37 -0
  197. package/dist/hooks/events.js.map +1 -0
  198. package/dist/hooks/runner.d.ts +73 -0
  199. package/dist/hooks/runner.js +256 -0
  200. package/dist/hooks/runner.js.map +1 -0
  201. package/dist/hooks/trigger.d.ts +9 -0
  202. package/dist/hooks/trigger.js +18 -0
  203. package/dist/hooks/trigger.js.map +1 -0
  204. package/dist/index.d.ts +61 -0
  205. package/dist/index.js +62 -0
  206. package/dist/index.js.map +1 -0
  207. package/dist/interactions.d.ts +102 -0
  208. package/dist/interactions.js +250 -0
  209. package/dist/interactions.js.map +1 -0
  210. package/dist/logger.d.ts +32 -0
  211. package/dist/logger.js +115 -0
  212. package/dist/logger.js.map +1 -0
  213. package/dist/markdown.d.ts +18 -0
  214. package/dist/markdown.js +293 -0
  215. package/dist/markdown.js.map +1 -0
  216. package/dist/mcp/approval.d.ts +9 -0
  217. package/dist/mcp/approval.js +27 -0
  218. package/dist/mcp/approval.js.map +1 -0
  219. package/dist/mcp/client.d.ts +61 -0
  220. package/dist/mcp/client.js +276 -0
  221. package/dist/mcp/client.js.map +1 -0
  222. package/dist/mcp/connection-manager.d.ts +30 -0
  223. package/dist/mcp/connection-manager.js +126 -0
  224. package/dist/mcp/connection-manager.js.map +1 -0
  225. package/dist/mcp/oauth-callback.d.ts +23 -0
  226. package/dist/mcp/oauth-callback.js +108 -0
  227. package/dist/mcp/oauth-callback.js.map +1 -0
  228. package/dist/mcp/oauth-flow.d.ts +45 -0
  229. package/dist/mcp/oauth-flow.js +145 -0
  230. package/dist/mcp/oauth-flow.js.map +1 -0
  231. package/dist/mcp/oauth.d.ts +82 -0
  232. package/dist/mcp/oauth.js +169 -0
  233. package/dist/mcp/oauth.js.map +1 -0
  234. package/dist/mcp/tool-registry.d.ts +29 -0
  235. package/dist/mcp/tool-registry.js +207 -0
  236. package/dist/mcp/tool-registry.js.map +1 -0
  237. package/dist/mcp/transport.d.ts +33 -0
  238. package/dist/mcp/transport.js +493 -0
  239. package/dist/mcp/transport.js.map +1 -0
  240. package/dist/mcp/types.d.ts +57 -0
  241. package/dist/mcp/types.js +2 -0
  242. package/dist/mcp/types.js.map +1 -0
  243. package/dist/memdir.d.ts +58 -0
  244. package/dist/memdir.js +219 -0
  245. package/dist/memdir.js.map +1 -0
  246. package/dist/memory-selection.d.ts +30 -0
  247. package/dist/memory-selection.js +102 -0
  248. package/dist/memory-selection.js.map +1 -0
  249. package/dist/memory.d.ts +85 -0
  250. package/dist/memory.js +259 -0
  251. package/dist/memory.js.map +1 -0
  252. package/dist/paths.d.ts +25 -0
  253. package/dist/paths.js +99 -0
  254. package/dist/paths.js.map +1 -0
  255. package/dist/permissions.d.ts +17 -0
  256. package/dist/permissions.js +72 -0
  257. package/dist/permissions.js.map +1 -0
  258. package/dist/plugins/manifest.d.ts +17 -0
  259. package/dist/plugins/manifest.js +98 -0
  260. package/dist/plugins/manifest.js.map +1 -0
  261. package/dist/plugins/marketplace.d.ts +22 -0
  262. package/dist/plugins/marketplace.js +98 -0
  263. package/dist/plugins/marketplace.js.map +1 -0
  264. package/dist/proactive.d.ts +15 -0
  265. package/dist/proactive.js +49 -0
  266. package/dist/proactive.js.map +1 -0
  267. package/dist/providers/errors.d.ts +14 -0
  268. package/dist/providers/errors.js +66 -0
  269. package/dist/providers/errors.js.map +1 -0
  270. package/dist/providers/format-proxy.d.ts +100 -0
  271. package/dist/providers/format-proxy.js +235 -0
  272. package/dist/providers/format-proxy.js.map +1 -0
  273. package/dist/providers/http.d.ts +4 -0
  274. package/dist/providers/http.js +21 -0
  275. package/dist/providers/http.js.map +1 -0
  276. package/dist/providers/ir.d.ts +84 -0
  277. package/dist/providers/ir.js +76 -0
  278. package/dist/providers/ir.js.map +1 -0
  279. package/dist/providers/messages-compatible.d.ts +19 -0
  280. package/dist/providers/messages-compatible.js +592 -0
  281. package/dist/providers/messages-compatible.js.map +1 -0
  282. package/dist/providers/openai.d.ts +18 -0
  283. package/dist/providers/openai.js +430 -0
  284. package/dist/providers/openai.js.map +1 -0
  285. package/dist/providers/registry.d.ts +10 -0
  286. package/dist/providers/registry.js +16 -0
  287. package/dist/providers/registry.js.map +1 -0
  288. package/dist/providers/sse.d.ts +6 -0
  289. package/dist/providers/sse.js +104 -0
  290. package/dist/providers/sse.js.map +1 -0
  291. package/dist/routing/model-alias.d.ts +8 -0
  292. package/dist/routing/model-alias.js +23 -0
  293. package/dist/routing/model-alias.js.map +1 -0
  294. package/dist/routing/model-router.d.ts +55 -0
  295. package/dist/routing/model-router.js +233 -0
  296. package/dist/routing/model-router.js.map +1 -0
  297. package/dist/routing/router.d.ts +26 -0
  298. package/dist/routing/router.js +63 -0
  299. package/dist/routing/router.js.map +1 -0
  300. package/dist/rules/agents-loader.d.ts +12 -0
  301. package/dist/rules/agents-loader.js +61 -0
  302. package/dist/rules/agents-loader.js.map +1 -0
  303. package/dist/runner/client.d.ts +67 -0
  304. package/dist/runner/client.js +175 -0
  305. package/dist/runner/client.js.map +1 -0
  306. package/dist/session-store.d.ts +250 -0
  307. package/dist/session-store.js +629 -0
  308. package/dist/session-store.js.map +1 -0
  309. package/dist/skills/bundled.d.ts +14 -0
  310. package/dist/skills/bundled.js +148 -0
  311. package/dist/skills/bundled.js.map +1 -0
  312. package/dist/skills/loader.d.ts +11 -0
  313. package/dist/skills/loader.js +73 -0
  314. package/dist/skills/loader.js.map +1 -0
  315. package/dist/slash-menu.d.ts +14 -0
  316. package/dist/slash-menu.js +166 -0
  317. package/dist/slash-menu.js.map +1 -0
  318. package/dist/slash.d.ts +75 -0
  319. package/dist/slash.js +126 -0
  320. package/dist/slash.js.map +1 -0
  321. package/dist/spinner.d.ts +27 -0
  322. package/dist/spinner.js +68 -0
  323. package/dist/spinner.js.map +1 -0
  324. package/dist/ssh/exec.d.ts +20 -0
  325. package/dist/ssh/exec.js +39 -0
  326. package/dist/ssh/exec.js.map +1 -0
  327. package/dist/ssh/file.d.ts +32 -0
  328. package/dist/ssh/file.js +60 -0
  329. package/dist/ssh/file.js.map +1 -0
  330. package/dist/syntax-highlight.d.ts +19 -0
  331. package/dist/syntax-highlight.js +181 -0
  332. package/dist/syntax-highlight.js.map +1 -0
  333. package/dist/tools/agent-tool.d.ts +53 -0
  334. package/dist/tools/agent-tool.js +62 -0
  335. package/dist/tools/agent-tool.js.map +1 -0
  336. package/dist/tools/archive-create.d.ts +35 -0
  337. package/dist/tools/archive-create.js +37 -0
  338. package/dist/tools/archive-create.js.map +1 -0
  339. package/dist/tools/archive-extract.d.ts +28 -0
  340. package/dist/tools/archive-extract.js +36 -0
  341. package/dist/tools/archive-extract.js.map +1 -0
  342. package/dist/tools/base64.d.ts +27 -0
  343. package/dist/tools/base64.js +19 -0
  344. package/dist/tools/base64.js.map +1 -0
  345. package/dist/tools/browser.d.ts +125 -0
  346. package/dist/tools/browser.js +241 -0
  347. package/dist/tools/browser.js.map +1 -0
  348. package/dist/tools/config-tool.d.ts +31 -0
  349. package/dist/tools/config-tool.js +167 -0
  350. package/dist/tools/config-tool.js.map +1 -0
  351. package/dist/tools/cron.d.ts +110 -0
  352. package/dist/tools/cron.js +299 -0
  353. package/dist/tools/cron.js.map +1 -0
  354. package/dist/tools/date.d.ts +24 -0
  355. package/dist/tools/date.js +26 -0
  356. package/dist/tools/date.js.map +1 -0
  357. package/dist/tools/dir-create.d.ts +21 -0
  358. package/dist/tools/dir-create.js +19 -0
  359. package/dist/tools/dir-create.js.map +1 -0
  360. package/dist/tools/dir-list.d.ts +36 -0
  361. package/dist/tools/dir-list.js +47 -0
  362. package/dist/tools/dir-list.js.map +1 -0
  363. package/dist/tools/disk-usage.d.ts +30 -0
  364. package/dist/tools/disk-usage.js +22 -0
  365. package/dist/tools/disk-usage.js.map +1 -0
  366. package/dist/tools/download-file.d.ts +28 -0
  367. package/dist/tools/download-file.js +42 -0
  368. package/dist/tools/download-file.js.map +1 -0
  369. package/dist/tools/environment.d.ts +31 -0
  370. package/dist/tools/environment.js +33 -0
  371. package/dist/tools/environment.js.map +1 -0
  372. package/dist/tools/errors.d.ts +5 -0
  373. package/dist/tools/errors.js +9 -0
  374. package/dist/tools/errors.js.map +1 -0
  375. package/dist/tools/file-copy.d.ts +34 -0
  376. package/dist/tools/file-copy.js +45 -0
  377. package/dist/tools/file-copy.js.map +1 -0
  378. package/dist/tools/file-delete.d.ts +34 -0
  379. package/dist/tools/file-delete.js +42 -0
  380. package/dist/tools/file-delete.js.map +1 -0
  381. package/dist/tools/file-find.d.ts +46 -0
  382. package/dist/tools/file-find.js +33 -0
  383. package/dist/tools/file-find.js.map +1 -0
  384. package/dist/tools/file-move.d.ts +33 -0
  385. package/dist/tools/file-move.js +32 -0
  386. package/dist/tools/file-move.js.map +1 -0
  387. package/dist/tools/files.d.ts +38 -0
  388. package/dist/tools/files.js +123 -0
  389. package/dist/tools/files.js.map +1 -0
  390. package/dist/tools/git-branch-delete.d.ts +27 -0
  391. package/dist/tools/git-branch-delete.js +25 -0
  392. package/dist/tools/git-branch-delete.js.map +1 -0
  393. package/dist/tools/git-reset.d.ts +30 -0
  394. package/dist/tools/git-reset.js +28 -0
  395. package/dist/tools/git-reset.js.map +1 -0
  396. package/dist/tools/git-stash.d.ts +28 -0
  397. package/dist/tools/git-stash.js +24 -0
  398. package/dist/tools/git-stash.js.map +1 -0
  399. package/dist/tools/git.d.ts +77 -0
  400. package/dist/tools/git.js +300 -0
  401. package/dist/tools/git.js.map +1 -0
  402. package/dist/tools/github.d.ts +68 -0
  403. package/dist/tools/github.js +77 -0
  404. package/dist/tools/github.js.map +1 -0
  405. package/dist/tools/head-tail.d.ts +34 -0
  406. package/dist/tools/head-tail.js +23 -0
  407. package/dist/tools/head-tail.js.map +1 -0
  408. package/dist/tools/http-request.d.ts +44 -0
  409. package/dist/tools/http-request.js +57 -0
  410. package/dist/tools/http-request.js.map +1 -0
  411. package/dist/tools/json-query.d.ts +27 -0
  412. package/dist/tools/json-query.js +90 -0
  413. package/dist/tools/json-query.js.map +1 -0
  414. package/dist/tools/kill-process.d.ts +32 -0
  415. package/dist/tools/kill-process.js +51 -0
  416. package/dist/tools/kill-process.js.map +1 -0
  417. package/dist/tools/lsp.d.ts +98 -0
  418. package/dist/tools/lsp.js +398 -0
  419. package/dist/tools/lsp.js.map +1 -0
  420. package/dist/tools/monitor.d.ts +29 -0
  421. package/dist/tools/monitor.js +78 -0
  422. package/dist/tools/monitor.js.map +1 -0
  423. package/dist/tools/network-check.d.ts +34 -0
  424. package/dist/tools/network-check.js +57 -0
  425. package/dist/tools/network-check.js.map +1 -0
  426. package/dist/tools/notebook.d.ts +63 -0
  427. package/dist/tools/notebook.js +158 -0
  428. package/dist/tools/notebook.js.map +1 -0
  429. package/dist/tools/plan-mode.d.ts +48 -0
  430. package/dist/tools/plan-mode.js +57 -0
  431. package/dist/tools/plan-mode.js.map +1 -0
  432. package/dist/tools/process-list.d.ts +35 -0
  433. package/dist/tools/process-list.js +42 -0
  434. package/dist/tools/process-list.js.map +1 -0
  435. package/dist/tools/registry.d.ts +132 -0
  436. package/dist/tools/registry.js +2262 -0
  437. package/dist/tools/registry.js.map +1 -0
  438. package/dist/tools/search.d.ts +38 -0
  439. package/dist/tools/search.js +327 -0
  440. package/dist/tools/search.js.map +1 -0
  441. package/dist/tools/shell.d.ts +18 -0
  442. package/dist/tools/shell.js +249 -0
  443. package/dist/tools/shell.js.map +1 -0
  444. package/dist/tools/skill-tool.d.ts +22 -0
  445. package/dist/tools/skill-tool.js +66 -0
  446. package/dist/tools/skill-tool.js.map +1 -0
  447. package/dist/tools/sleep.d.ts +16 -0
  448. package/dist/tools/sleep.js +24 -0
  449. package/dist/tools/sleep.js.map +1 -0
  450. package/dist/tools/snip.d.ts +26 -0
  451. package/dist/tools/snip.js +95 -0
  452. package/dist/tools/snip.js.map +1 -0
  453. package/dist/tools/system-info.d.ts +17 -0
  454. package/dist/tools/system-info.js +33 -0
  455. package/dist/tools/system-info.js.map +1 -0
  456. package/dist/tools/tasks.d.ts +191 -0
  457. package/dist/tools/tasks.js +348 -0
  458. package/dist/tools/tasks.js.map +1 -0
  459. package/dist/tools/text-stats.d.ts +25 -0
  460. package/dist/tools/text-stats.js +25 -0
  461. package/dist/tools/text-stats.js.map +1 -0
  462. package/dist/tools/todo.d.ts +69 -0
  463. package/dist/tools/todo.js +197 -0
  464. package/dist/tools/todo.js.map +1 -0
  465. package/dist/tools/tool-search.d.ts +29 -0
  466. package/dist/tools/tool-search.js +114 -0
  467. package/dist/tools/tool-search.js.map +1 -0
  468. package/dist/tools/tree-view.d.ts +34 -0
  469. package/dist/tools/tree-view.js +39 -0
  470. package/dist/tools/tree-view.js.map +1 -0
  471. package/dist/tools/user-message.d.ts +39 -0
  472. package/dist/tools/user-message.js +70 -0
  473. package/dist/tools/user-message.js.map +1 -0
  474. package/dist/tools/user-question.d.ts +88 -0
  475. package/dist/tools/user-question.js +236 -0
  476. package/dist/tools/user-question.js.map +1 -0
  477. package/dist/tools/web-browser.d.ts +53 -0
  478. package/dist/tools/web-browser.js +373 -0
  479. package/dist/tools/web-browser.js.map +1 -0
  480. package/dist/tools/web-fetch.d.ts +22 -0
  481. package/dist/tools/web-fetch.js +146 -0
  482. package/dist/tools/web-fetch.js.map +1 -0
  483. package/dist/tools/web-search.d.ts +51 -0
  484. package/dist/tools/web-search.js +198 -0
  485. package/dist/tools/web-search.js.map +1 -0
  486. package/dist/tools/which.d.ts +22 -0
  487. package/dist/tools/which.js +21 -0
  488. package/dist/tools/which.js.map +1 -0
  489. package/dist/tools/whoami.d.ts +17 -0
  490. package/dist/tools/whoami.js +24 -0
  491. package/dist/tools/whoami.js.map +1 -0
  492. package/dist/tools/workspace-diagnostics.d.ts +62 -0
  493. package/dist/tools/workspace-diagnostics.js +421 -0
  494. package/dist/tools/workspace-diagnostics.js.map +1 -0
  495. package/dist/tools/workspace.d.ts +14 -0
  496. package/dist/tools/workspace.js +65 -0
  497. package/dist/tools/workspace.js.map +1 -0
  498. package/dist/tools/worktree.d.ts +70 -0
  499. package/dist/tools/worktree.js +150 -0
  500. package/dist/tools/worktree.js.map +1 -0
  501. package/dist/tui/interactions.d.ts +25 -0
  502. package/dist/tui/interactions.js +232 -0
  503. package/dist/tui/interactions.js.map +1 -0
  504. package/dist/tui/multiline-input.d.ts +14 -0
  505. package/dist/tui/multiline-input.js +550 -0
  506. package/dist/tui/multiline-input.js.map +1 -0
  507. package/dist/tui/paste.d.ts +40 -0
  508. package/dist/tui/paste.js +113 -0
  509. package/dist/tui/paste.js.map +1 -0
  510. package/dist/tui/prompt-reader.d.ts +26 -0
  511. package/dist/tui/prompt-reader.js +553 -0
  512. package/dist/tui/prompt-reader.js.map +1 -0
  513. package/dist/tui/transcript.d.ts +34 -0
  514. package/dist/tui/transcript.js +275 -0
  515. package/dist/tui/transcript.js.map +1 -0
  516. package/dist/tui.d.ts +53 -0
  517. package/dist/tui.js +669 -0
  518. package/dist/tui.js.map +1 -0
  519. package/dist/version.d.ts +1 -0
  520. package/dist/version.js +2 -0
  521. package/dist/version.js.map +1 -0
  522. package/dist/vim/lineEditor.d.ts +18 -0
  523. package/dist/vim/lineEditor.js +420 -0
  524. package/dist/vim/lineEditor.js.map +1 -0
  525. package/dist/web/panel-html.d.ts +1 -0
  526. package/dist/web/panel-html.js +532 -0
  527. package/dist/web/panel-html.js.map +1 -0
  528. package/dist/web/panel.d.ts +4 -0
  529. package/dist/web/panel.js +121 -0
  530. package/dist/web/panel.js.map +1 -0
  531. package/package.json +42 -0
package/dist/tui.js ADDED
@@ -0,0 +1,669 @@
1
+ import readline from "node:readline/promises";
2
+ import { stdin as input, stdout as output } from "node:process";
3
+ import { formatEventList, toEventView } from "./events.js";
4
+ import { buildTuiTranscriptState, formatTuiLiveEvent, formatTuiTranscriptStatus } from "./tui/transcript.js";
5
+ import { readTuiPrompt, TuiPromptAbortError } from "./tui/prompt-reader.js";
6
+ import { handleTuiPendingInteraction, parseTuiInteractionTimeoutMs } from "./tui/interactions.js";
7
+ import { runHeadlessPrompt } from "./headless.js";
8
+ import { ActiveInteractionRegistry } from "./interactions.js";
9
+ import { resolveModelPickerSelection, resolveSessionPickerSelection } from "./slash.js";
10
+ import { parseCommandLine, registry } from "./commands/registry.js";
11
+ import { isVimModeEnabled } from "./commands/vim.js";
12
+ import { readLineWithVim } from "./vim/lineEditor.js";
13
+ import { startSpinner } from "./spinner.js";
14
+ import { createStreamingMarkdown } from "./markdown.js";
15
+ import { loadHistory, appendHistory, decodeHistoryEntry } from "./history.js";
16
+ import { showSlashMenu } from "./slash-menu.js";
17
+ import { takePendingImages } from "./commands/image.js";
18
+ import { encodePromptWithImages } from "./providers/ir.js";
19
+ import { findSkill, listSkills } from "./skills/loader.js";
20
+ import { getProactiveSuggestions } from "./proactive.js";
21
+ import { getBuiltinToolDefinitions } from "./tools/registry.js";
22
+ import { createGoal, formatGoalBadge, getGoal, isGoalCreationArgs } from "./goal.js";
23
+ export const MAGI_TEXT_HAT = [
24
+ " △",
25
+ " /✦\\",
26
+ "▔▔▔"
27
+ ].join("\n");
28
+ export { buildTuiTranscriptState, formatTuiLiveEvent, formatTuiTranscriptEntry, formatTuiTranscriptStatus } from "./tui/transcript.js";
29
+ export { colorizeDiffLine, createTerminalUserQuestionResolver } from "./tui/interactions.js";
30
+ function installRunningInterruptKeys(controller) {
31
+ const wasRaw = input.isRaw;
32
+ let interrupted = false;
33
+ const interrupt = () => {
34
+ if (interrupted || controller.signal.aborted)
35
+ return;
36
+ interrupted = true;
37
+ output.write("\n\x1b[33mInterrupting...\x1b[39m\n");
38
+ controller.abort();
39
+ };
40
+ const onData = (chunk) => {
41
+ const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk;
42
+ if (text === "\x1b" || text === "\x03")
43
+ interrupt();
44
+ };
45
+ input.setRawMode(true);
46
+ input.resume();
47
+ input.on("data", onData);
48
+ return () => {
49
+ input.off("data", onData);
50
+ input.setRawMode(Boolean(wasRaw));
51
+ };
52
+ }
53
+ export async function runInteractiveTerminal(inputConfig) {
54
+ if (!input.isTTY || !output.isTTY) {
55
+ output.write("Interactive terminal requires a TTY. Use magi -p <prompt> for headless mode.\n");
56
+ return 2;
57
+ }
58
+ const rl = readline.createInterface({
59
+ input,
60
+ output,
61
+ completer: (line) => {
62
+ const match = line.match(/^\/(\w*)$/);
63
+ if (!match) {
64
+ return [[], line];
65
+ }
66
+ const partial = match[1].toLowerCase();
67
+ const all = registry.getAll();
68
+ const matches = partial
69
+ ? all.filter(cmd => cmd.name.startsWith(partial) || (cmd.aliases ?? []).some(a => a.startsWith(partial)))
70
+ : all;
71
+ if (matches.length === 0) {
72
+ return [[], line];
73
+ }
74
+ // If single match, complete it directly
75
+ if (matches.length === 1) {
76
+ return [[`/${matches[0].name} `], line];
77
+ }
78
+ // Show all matches with descriptions
79
+ const maxName = Math.max(...matches.map(c => c.name.length));
80
+ const display = matches.map(cmd => `/${cmd.name.padEnd(maxName)} ${cmd.description}`);
81
+ // Print the menu above the prompt
82
+ output.write("\n" + display.join("\n") + "\n");
83
+ return [[`/${partial}`], line];
84
+ }
85
+ });
86
+ let currentModel = inputConfig.modelAlias ?? "main";
87
+ let currentSessionId = inputConfig.sessionId;
88
+ let running = false;
89
+ let abortController = null;
90
+ const modelDisplay = inputConfig.config.models.aliases[currentModel] ?? currentModel;
91
+ const toolCount = getBuiltinToolDefinitions().length;
92
+ output.write([
93
+ "",
94
+ `\x1b[36m △\x1b[39m \x1b[1mMagi\x1b[22m \x1b[90m· ${toolCount} tools\x1b[39m`,
95
+ `\x1b[36m /✦\\\x1b[39m \x1b[90mcwd:\x1b[39m ${inputConfig.cwd}`,
96
+ `\x1b[36m▔▔▔\x1b[39m \x1b[90mmodel:\x1b[39m ${modelDisplay}`,
97
+ "",
98
+ " \x1b[90m/help for commands · Esc/Ctrl+C to interrupt · /exit to quit\x1b[39m",
99
+ ""
100
+ ].join("\n"));
101
+ writeGoalBadge(output, inputConfig.paths, currentSessionId);
102
+ // Show a setup hint if no provider is configured
103
+ const aliasCount = Object.keys(inputConfig.config.models?.aliases ?? {}).length;
104
+ const providerCount = Object.keys(inputConfig.config.providers ?? {}).length;
105
+ if (providerCount === 0 || aliasCount === 0) {
106
+ output.write([
107
+ "\x1b[33m ⚠ No provider is configured.\x1b[39m",
108
+ " \x1b[90mRun 'magi init' (in another shell) to set up a provider, then restart.\x1b[39m",
109
+ ""
110
+ ].join("\n"));
111
+ }
112
+ // Handle Ctrl+C: interrupt running query or exit on double-Ctrl+C.
113
+ // readline emits 'SIGINT' on the rl instance (not on stdin); attaching here
114
+ // also suppresses readline's default behavior of killing the process.
115
+ let lastSigintAt = 0;
116
+ const onSigint = () => {
117
+ if (!running) {
118
+ // Double Ctrl+C within 1 second exits the program
119
+ const now = Date.now();
120
+ if (now - lastSigintAt < 1000) {
121
+ output.write("\n");
122
+ rl.close();
123
+ process.exit(0);
124
+ }
125
+ lastSigintAt = now;
126
+ output.write("\n\x1b[90mPress Ctrl+C again to exit\x1b[39m\n");
127
+ rl.prompt(true);
128
+ return;
129
+ }
130
+ // Running: abort the request. The catch block handles the error and
131
+ // returns to the prompt.
132
+ if (!abortController?.signal.aborted) {
133
+ output.write("\n\x1b[33mInterrupting...\x1b[39m\n");
134
+ }
135
+ abortController?.abort();
136
+ };
137
+ rl.on("SIGINT", onSigint);
138
+ const inputHistory = loadHistory().map(decodeHistoryEntry);
139
+ try {
140
+ while (true) {
141
+ let line;
142
+ if (isVimModeEnabled()) {
143
+ // Vim mode: use raw-mode line editor
144
+ rl.pause();
145
+ try {
146
+ line = await readLineWithVim({
147
+ input,
148
+ output,
149
+ prompt: "> ",
150
+ history: inputHistory
151
+ });
152
+ }
153
+ catch (err) {
154
+ if (err.message === "SIGINT" || err.message === "EOF") {
155
+ return 0;
156
+ }
157
+ throw err;
158
+ }
159
+ rl.resume();
160
+ }
161
+ else {
162
+ try {
163
+ line = await readTuiPrompt({
164
+ input,
165
+ output,
166
+ prompt: "> ",
167
+ history: inputHistory
168
+ });
169
+ }
170
+ catch (err) {
171
+ if (err instanceof TuiPromptAbortError) {
172
+ return 0;
173
+ }
174
+ throw err;
175
+ }
176
+ }
177
+ let trimmed = line.trim();
178
+ if (!trimmed) {
179
+ continue;
180
+ }
181
+ // Multi-line input: backslash continuation or unclosed code fences
182
+ if (trimmed.endsWith("\\") || hasUnclosedFence(trimmed)) {
183
+ const multiLines = [trimmed.endsWith("\\") ? trimmed.slice(0, -1) : trimmed];
184
+ while (true) {
185
+ const cont = await rl.question("\x1b[90m... \x1b[39m");
186
+ if (cont.trim() === "" && !hasUnclosedFence(multiLines.join("\n"))) {
187
+ break; // Empty line ends multi-line (unless inside code fence)
188
+ }
189
+ if (cont.trim().endsWith("\\")) {
190
+ multiLines.push(cont.trim().slice(0, -1));
191
+ }
192
+ else {
193
+ multiLines.push(cont);
194
+ if (!hasUnclosedFence(multiLines.join("\n"))) {
195
+ break;
196
+ }
197
+ }
198
+ }
199
+ trimmed = multiLines.join("\n").trim();
200
+ }
201
+ if (!trimmed) {
202
+ continue;
203
+ }
204
+ // Paste detection: show summary for any multi-line or long input
205
+ const lineCount = trimmed.split("\n").length;
206
+ const charCount = trimmed.length;
207
+ if (lineCount >= 2 || charCount > 500) {
208
+ output.write(`\x1b[90m[pasted ${charCount} chars, ${lineCount} lines]\x1b[39m\n`);
209
+ }
210
+ if (trimmed) {
211
+ inputHistory.push(trimmed);
212
+ appendHistory(trimmed);
213
+ }
214
+ if (trimmed === "/exit" || trimmed === "/quit") {
215
+ return 0;
216
+ }
217
+ const parsed = parseCommandLine(trimmed);
218
+ if (parsed) {
219
+ // Bare "/" — show interactive slash menu
220
+ if (parsed.name === "") {
221
+ rl.pause();
222
+ // Detach readline's data listener so it doesn't consume menu keystrokes
223
+ const rlDataListeners = input.rawListeners("data").slice();
224
+ input.removeAllListeners("data");
225
+ input.resume();
226
+ const skillItems = inputConfig.paths
227
+ ? listSkills(inputConfig.paths).map(s => ({ name: s.name, description: `[skill] ${s.summary}` }))
228
+ : [];
229
+ const picked = await showSlashMenu({
230
+ stdin: input,
231
+ stdout: output,
232
+ items: [
233
+ ...registry.getAll().map(cmd => ({ name: cmd.name, description: cmd.description })),
234
+ ...skillItems,
235
+ { name: "exit", description: "Quit Magi" },
236
+ { name: "continue", description: "Continue last response" }
237
+ ]
238
+ });
239
+ output.write("\x1b[?25h"); // show cursor
240
+ // Restore readline's data listeners
241
+ for (const listener of rlDataListeners) {
242
+ input.on("data", listener);
243
+ }
244
+ if (picked) {
245
+ trimmed = picked.trim();
246
+ // Re-parse the picked command
247
+ const reparsed = parseCommandLine(trimmed);
248
+ if (reparsed) {
249
+ if (trimmed === "/exit" || trimmed === "/quit") {
250
+ return 0;
251
+ }
252
+ // Fall through to dispatch below with reparsed
253
+ Object.assign(parsed, reparsed);
254
+ }
255
+ }
256
+ else {
257
+ rl.resume();
258
+ continue;
259
+ }
260
+ rl.resume();
261
+ }
262
+ if (parsed.name === "help") {
263
+ const result = await registry.dispatch("help", parsed.args, {
264
+ cwd: inputConfig.cwd,
265
+ config: inputConfig.config,
266
+ store: inputConfig.store,
267
+ paths: inputConfig.paths,
268
+ sessionId: currentSessionId,
269
+ currentModel
270
+ });
271
+ if (result) {
272
+ output.write(result + "\n");
273
+ output.write(" /exit or /quit Quit Magi Next\n");
274
+ output.write(" /continue Ask the model to continue its last response\n");
275
+ }
276
+ continue;
277
+ }
278
+ // State-updating commands
279
+ if (parsed.name === "model" && parsed.args[0]) {
280
+ const selected = resolveModelPickerSelection(inputConfig.config, parsed.args[0]);
281
+ if (selected)
282
+ currentModel = selected;
283
+ }
284
+ if (parsed.name === "resume" && parsed.args[0]) {
285
+ const selected = resolveSessionPickerSelection(inputConfig.store, parsed.args[0]);
286
+ if (selected) {
287
+ currentSessionId = selected.id;
288
+ output.write(formatSessionResume(inputConfig.store, selected.id) + "\n");
289
+ writeGoalBadge(output, inputConfig.paths, currentSessionId);
290
+ }
291
+ }
292
+ const isGoalStartCommand = parsed.name === "goal" && isGoalCreationArgs(parsed.args);
293
+ if (isGoalStartCommand && !currentSessionId) {
294
+ currentSessionId = inputConfig.store.createSession({
295
+ title: parsed.args.join(" ").slice(0, 80) || "goal",
296
+ cwd: inputConfig.cwd,
297
+ metadata: { mode: "interactive", command: "goal" }
298
+ });
299
+ }
300
+ if (parsed.name === "clear") {
301
+ currentSessionId = inputConfig.store.createSession({
302
+ title: "",
303
+ cwd: inputConfig.cwd,
304
+ metadata: { mode: "interactive", clearedFrom: currentSessionId }
305
+ });
306
+ }
307
+ const result = isGoalStartCommand
308
+ ? startInteractiveGoal(inputConfig.paths, currentSessionId, parsed.args)
309
+ : await registry.dispatch(parsed.name, parsed.args, {
310
+ cwd: inputConfig.cwd,
311
+ config: inputConfig.config,
312
+ store: inputConfig.store,
313
+ paths: inputConfig.paths,
314
+ sessionId: currentSessionId,
315
+ currentModel
316
+ });
317
+ if (result !== undefined) {
318
+ output.write(`${result}\n`);
319
+ if (parsed.name === "goal") {
320
+ writeGoalBadge(output, inputConfig.paths, currentSessionId);
321
+ }
322
+ if (isGoalStartCommand) {
323
+ trimmed = parsed.args.join(" ");
324
+ // Continue into the normal prompt flow so /goal <objective>
325
+ // both starts the goal and immediately asks the agent to work it.
326
+ }
327
+ else {
328
+ continue;
329
+ }
330
+ }
331
+ // Check if this is a user-installed skill (e.g., /commit, /review-pr)
332
+ if (isGoalStartCommand) {
333
+ // Already converted to a normal prompt above.
334
+ }
335
+ else if (inputConfig.paths) {
336
+ const skill = findSkill(inputConfig.paths, parsed.name);
337
+ if (skill) {
338
+ // Inject skill body as the prompt; let the model handle it
339
+ const skillArgs = parsed.args.length > 0 ? `\n\nArguments: ${parsed.args.join(" ")}` : "";
340
+ trimmed = `Execute the "${skill.name}" skill:\n\n${skill.body ?? ""}${skillArgs}`;
341
+ // Fall through to normal prompt flow
342
+ }
343
+ else {
344
+ // /continue: fall through to normal prompt flow with "continue"
345
+ if (parsed.name !== "continue") {
346
+ output.write(formatUnknownCommand(parsed.name));
347
+ continue;
348
+ }
349
+ if (!currentSessionId) {
350
+ output.write("No active session to continue. Start a conversation first.\n");
351
+ continue;
352
+ }
353
+ trimmed = "continue";
354
+ }
355
+ }
356
+ else {
357
+ // /continue: fall through to normal prompt flow with "continue"
358
+ if (parsed.name !== "continue") {
359
+ output.write(formatUnknownCommand(parsed.name));
360
+ continue;
361
+ }
362
+ if (!currentSessionId) {
363
+ output.write("No active session to continue. Start a conversation first.\n");
364
+ continue;
365
+ }
366
+ trimmed = "continue";
367
+ }
368
+ }
369
+ currentSessionId ??= inputConfig.store.createSession({
370
+ title: trimmed.slice(0, 80),
371
+ cwd: inputConfig.cwd,
372
+ metadata: { mode: "interactive" }
373
+ });
374
+ const activeInteractions = new ActiveInteractionRegistry({
375
+ timeoutMs: parseTuiInteractionTimeoutMs(inputConfig.env?.MAGI_INTERACTION_TIMEOUT_MS)
376
+ });
377
+ const modelDisplayInline = inputConfig.config.models?.aliases?.[currentModel] ?? currentModel;
378
+ const spinner = startSpinner(output, { model: modelDisplayInline });
379
+ const controller = new AbortController();
380
+ abortController = controller;
381
+ const liveEvents = startTuiLiveEventWriter({
382
+ store: inputConfig.store,
383
+ output,
384
+ sessionId: currentSessionId,
385
+ interactions: activeInteractions,
386
+ rl,
387
+ spinner,
388
+ signal: controller.signal
389
+ });
390
+ running = true;
391
+ const startedAt = Date.now();
392
+ let streamedAny = false;
393
+ const usedTools = new Set();
394
+ let hadErrors = false;
395
+ const lastEventTextParts = [];
396
+ let totalInputTokens = 0;
397
+ let totalOutputTokens = 0;
398
+ const md = createStreamingMarkdown();
399
+ // Attach any images queued by /image. encodePromptWithImages adds a
400
+ // sentinel-prefixed block that the agent loop parses back into multi-part
401
+ // user messages.
402
+ const pendingImages = takePendingImages();
403
+ const promptWithImages = pendingImages.length > 0
404
+ ? encodePromptWithImages(trimmed, pendingImages)
405
+ : trimmed;
406
+ if (pendingImages.length > 0) {
407
+ output.write(`\x1b[90m[attaching ${pendingImages.length} image${pendingImages.length === 1 ? "" : "s"}]\x1b[39m\n`);
408
+ }
409
+ let result;
410
+ let stopInterruptKeys;
411
+ try {
412
+ stopInterruptKeys = installRunningInterruptKeys(controller);
413
+ result = await runHeadlessPrompt({
414
+ prompt: promptWithImages,
415
+ cwd: inputConfig.cwd,
416
+ store: inputConfig.store,
417
+ config: inputConfig.config,
418
+ env: inputConfig.env,
419
+ paths: inputConfig.paths,
420
+ stateRoot: inputConfig.paths?.stateRoot,
421
+ modelAlias: currentModel,
422
+ sessionId: currentSessionId,
423
+ activeInteractions,
424
+ permissionMode: "default",
425
+ signal: controller.signal,
426
+ onStreamEvent: (event) => {
427
+ if (event.type === "text_delta") {
428
+ if (!streamedAny)
429
+ spinner.stop();
430
+ streamedAny = true;
431
+ const rendered = md.push(event.text);
432
+ if (rendered)
433
+ output.write(rendered);
434
+ lastEventTextParts.push(event.text);
435
+ }
436
+ if (event.type === "tool_use") {
437
+ // Update spinner to show which tool is running, then keep spinning
438
+ spinner.update({ text: `Tool: ${event.toolUse.name}` });
439
+ usedTools.add(event.toolUse.name);
440
+ }
441
+ if (event.type === "tool_result") {
442
+ // Restore "Thinking" once tool finishes
443
+ spinner.update({ text: "Thinking" });
444
+ if (event.isError)
445
+ hadErrors = true;
446
+ }
447
+ if (event.type === "error") {
448
+ hadErrors = true;
449
+ }
450
+ if (event.type === "usage") {
451
+ totalInputTokens += event.usage.inputTokens;
452
+ totalOutputTokens += event.usage.outputTokens;
453
+ spinner.update({ inputTokens: totalInputTokens, outputTokens: totalOutputTokens });
454
+ }
455
+ if (event.type === "compact_boundary") {
456
+ if (!streamedAny)
457
+ spinner.stop();
458
+ output.write(`\x1b[90m[context compacted: ${event.sourceMessageCount} messages, ~${event.estimatedTokensBefore} tokens]\x1b[39m\n`);
459
+ }
460
+ }
461
+ });
462
+ }
463
+ catch (err) {
464
+ // Provider/agent failure must not kill the TUI session.
465
+ // Stop transient UI, show the error, and return to the prompt.
466
+ spinner.stop();
467
+ const remaining = md.flush();
468
+ if (remaining)
469
+ output.write(remaining);
470
+ const msg = err instanceof Error ? err.message : String(err);
471
+ output.write(`\n\x1b[31m✗ ${msg}\x1b[39m\n`);
472
+ running = false;
473
+ hadErrors = true;
474
+ continue;
475
+ }
476
+ finally {
477
+ stopInterruptKeys?.();
478
+ abortController = null;
479
+ spinner.stop();
480
+ const remaining = md.flush();
481
+ if (remaining)
482
+ output.write(remaining);
483
+ liveEvents.stop();
484
+ activeInteractions.close();
485
+ }
486
+ running = false;
487
+ currentSessionId = result.sessionId;
488
+ writeGoalBadge(output, inputConfig.paths, currentSessionId);
489
+ if (!streamedAny && result.message) {
490
+ output.write(`${result.message}\n`);
491
+ }
492
+ else if (streamedAny) {
493
+ output.write("\n");
494
+ }
495
+ const elapsed = Date.now() - startedAt;
496
+ const secs = (elapsed / 1000).toFixed(1);
497
+ const tokenInfo = totalInputTokens > 0
498
+ ? ` · ${formatTokens(totalInputTokens)}↑ ${formatTokens(totalOutputTokens)}↓`
499
+ : "";
500
+ output.write(`\n\x1b[90m${result.model ?? currentModel} · ${secs}s${tokenInfo}\x1b[39m\n`);
501
+ // Proactive suggestions
502
+ const suggestions = getProactiveSuggestions({
503
+ toolNames: [...usedTools],
504
+ lastMessage: lastEventTextParts.join("") || result.message,
505
+ hadErrors
506
+ });
507
+ if (suggestions.length > 0) {
508
+ output.write(`\x1b[90m${suggestions.map(s => `→ ${s}`).join(" ")}\x1b[39m\n`);
509
+ }
510
+ }
511
+ }
512
+ finally {
513
+ rl.removeListener("SIGINT", onSigint);
514
+ rl.close();
515
+ }
516
+ }
517
+ export function startTuiLiveEventWriter(input) {
518
+ const terminalOutput = input.output ?? output;
519
+ let liveSessionId = input.sessionId;
520
+ const afterEventId = input.afterEventId ?? 0;
521
+ const handledInteractions = new Set();
522
+ const unsubscribe = input.store.subscribeAuditEvents((event) => {
523
+ if (event.id <= afterEventId) {
524
+ return;
525
+ }
526
+ if (liveSessionId) {
527
+ if (event.sessionId !== liveSessionId) {
528
+ return;
529
+ }
530
+ }
531
+ else {
532
+ liveSessionId = event.sessionId;
533
+ }
534
+ const line = formatTuiLiveEvent(toEventView(event));
535
+ if (line) {
536
+ terminalOutput.write(`${line}\n`);
537
+ }
538
+ if (input.interactions && input.rl) {
539
+ // Pause the spinner so the approval prompt isn't clobbered by the
540
+ // animation. Resume after the user resolves it.
541
+ input.spinner?.pause();
542
+ void handleTuiPendingInteraction({
543
+ event: toEventView(event),
544
+ interactions: input.interactions,
545
+ rl: input.rl,
546
+ output: terminalOutput,
547
+ handled: handledInteractions,
548
+ signal: input.signal
549
+ }).finally(() => {
550
+ input.spinner?.resume();
551
+ });
552
+ }
553
+ });
554
+ return {
555
+ stop: unsubscribe,
556
+ getSessionId: () => liveSessionId
557
+ };
558
+ }
559
+ export function formatSessionList(store) {
560
+ const sessions = store.listSessions(50);
561
+ if (sessions.length === 0) {
562
+ return "No sessions\n";
563
+ }
564
+ return [
565
+ "Recent sessions:",
566
+ ...sessions.map((session, index) => {
567
+ const marker = index === 0 ? ">" : " ";
568
+ return `${marker} ${session.id} ${session.updatedAt} ${session.messageCount} msg ${session.title ?? "(untitled)"} ${session.cwd}`;
569
+ }),
570
+ "Use magi -r <session-id> -p <prompt> or magi resume <session-id>."
571
+ ].join("\n") + "\n";
572
+ }
573
+ export function formatSessionResume(store, sessionId) {
574
+ const session = store.getSession(sessionId);
575
+ if (!session) {
576
+ return `Session not found: ${sessionId}\n`;
577
+ }
578
+ const pending = store.listSessionAuditEvents(sessionId, 50)
579
+ .map(toEventView)
580
+ .filter((event) => event.status === "pending" && (event.category === "approval" || event.category === "question"));
581
+ const events = store.listSessionAuditEvents(sessionId, 8).map(toEventView);
582
+ const transcript = buildTuiTranscriptState(store.listSessionAuditEvents(sessionId, 50).map(toEventView), {
583
+ sessionId,
584
+ limit: 8
585
+ });
586
+ return [
587
+ `sessionId: ${session.id}`,
588
+ `title: ${session.title ?? "(untitled)"}`,
589
+ `cwd: ${session.cwd}`,
590
+ `messages: ${session.messages.length}`,
591
+ ...session.messages.map((message) => `${message.role}: ${message.content}`),
592
+ formatPendingResumeInteractions(pending),
593
+ formatTuiTranscriptStatus(transcript),
594
+ formatEventList(events),
595
+ ""
596
+ ].join("\n");
597
+ }
598
+ function formatPendingResumeInteractions(events) {
599
+ if (events.length === 0) {
600
+ return "Pending interactions: none";
601
+ }
602
+ return [
603
+ "Pending interactions:",
604
+ ...events.map((event) => {
605
+ const toolUseId = typeof event.metadata.toolUseId === "string" ? event.metadata.toolUseId : event.target ?? "unknown";
606
+ return `- ${event.category} ${toolUseId} job=${event.jobId ?? "unknown"} ${event.message}`;
607
+ })
608
+ ].join("\n");
609
+ }
610
+ export async function collectPastedContinuations(rl, firstLine, windowMs = 100) {
611
+ const lines = [firstLine];
612
+ while (true) {
613
+ let timer;
614
+ const next = await new Promise((resolve) => {
615
+ const onLine = (next) => {
616
+ if (timer)
617
+ clearTimeout(timer);
618
+ rl.off("line", onLine);
619
+ resolve(next);
620
+ };
621
+ rl.on("line", onLine);
622
+ timer = setTimeout(() => {
623
+ rl.off("line", onLine);
624
+ resolve(undefined);
625
+ }, windowMs);
626
+ });
627
+ if (next === undefined)
628
+ break;
629
+ lines.push(next);
630
+ }
631
+ return lines.join("\n");
632
+ }
633
+ function formatUnknownCommand(name) {
634
+ const suggestion = registry.suggestCommand(name);
635
+ if (suggestion && suggestion !== name) {
636
+ return `\x1b[33mUnknown slash command:\x1b[39m /${name}\n Did you mean \x1b[36m/${suggestion}\x1b[39m?\n`;
637
+ }
638
+ return `\x1b[33mUnknown slash command:\x1b[39m /${name}\n Run \x1b[36m/help\x1b[39m to see available commands.\n`;
639
+ }
640
+ function hasUnclosedFence(text) {
641
+ const fences = text.split("\n").filter((l) => l.trimStart().startsWith("```"));
642
+ return fences.length % 2 !== 0;
643
+ }
644
+ function formatTokens(n) {
645
+ if (n >= 1_000_000)
646
+ return `${(n / 1_000_000).toFixed(1)}M`;
647
+ if (n >= 1_000)
648
+ return `${(n / 1_000).toFixed(1)}k`;
649
+ return String(n);
650
+ }
651
+ function writeGoalBadge(terminalOutput, paths, sessionId) {
652
+ if (!paths || !sessionId) {
653
+ return;
654
+ }
655
+ const badge = formatGoalBadge(getGoal(paths, sessionId));
656
+ if (badge) {
657
+ terminalOutput.write(`\x1b[90m${badge}\x1b[39m\n`);
658
+ }
659
+ }
660
+ function startInteractiveGoal(paths, sessionId, args) {
661
+ if (!paths)
662
+ return "Goal requires a configured paths root.";
663
+ if (!sessionId)
664
+ return "No active session. Send a message first or resume a session, then use /goal.";
665
+ const objective = args.join(" ").trim();
666
+ const goal = createGoal(paths, { sessionId, objective });
667
+ return `Goal started: ${goal.objective}`;
668
+ }
669
+ //# sourceMappingURL=tui.js.map