profclaw 2.0.0 → 2.4.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 (519) hide show
  1. package/.env.example +14 -2
  2. package/CHANGELOG.md +52 -0
  3. package/CONTRIBUTING.md +20 -0
  4. package/Dockerfile +39 -23
  5. package/README.md +178 -41
  6. package/config/pricing.yml +26 -2
  7. package/dist/agents/agent-summary.d.ts +44 -0
  8. package/dist/agents/agent-summary.js +176 -0
  9. package/dist/agents/auto-memory.d.ts +59 -0
  10. package/dist/agents/auto-memory.js +310 -0
  11. package/dist/agents/checkpoint-manager.d.ts +76 -0
  12. package/dist/agents/checkpoint-manager.js +156 -0
  13. package/dist/agents/circuit-breaker.d.ts +54 -0
  14. package/dist/agents/circuit-breaker.js +153 -0
  15. package/dist/agents/command-sandbox.d.ts +93 -0
  16. package/dist/agents/command-sandbox.js +235 -0
  17. package/dist/agents/context-compactor.d.ts +70 -0
  18. package/dist/agents/context-compactor.js +361 -0
  19. package/dist/agents/conversation-branch.d.ts +55 -0
  20. package/dist/agents/conversation-branch.js +115 -0
  21. package/dist/agents/error-recovery.d.ts +44 -0
  22. package/dist/agents/error-recovery.js +197 -0
  23. package/dist/agents/events.d.ts +76 -0
  24. package/dist/agents/events.js +8 -0
  25. package/dist/agents/executor-runner.d.ts +135 -0
  26. package/dist/agents/executor-runner.js +303 -0
  27. package/dist/agents/executor.d.ts +37 -1
  28. package/dist/agents/executor.js +606 -124
  29. package/dist/agents/file-snapshots.d.ts +72 -0
  30. package/dist/agents/file-snapshots.js +182 -0
  31. package/dist/agents/index.d.ts +2 -0
  32. package/dist/agents/orchestrator.d.ts +183 -0
  33. package/dist/agents/orchestrator.js +495 -0
  34. package/dist/agents/output-truncator.d.ts +59 -0
  35. package/dist/agents/output-truncator.js +128 -0
  36. package/dist/agents/permissions.d.ts +63 -0
  37. package/dist/agents/permissions.js +138 -0
  38. package/dist/agents/plan-mode.d.ts +71 -0
  39. package/dist/agents/plan-mode.js +186 -0
  40. package/dist/agents/prompt-suggestions.d.ts +33 -0
  41. package/dist/agents/prompt-suggestions.js +208 -0
  42. package/dist/agents/rate-limit-monitor.d.ts +56 -0
  43. package/dist/agents/rate-limit-monitor.js +224 -0
  44. package/dist/agents/receipt/receipt-cli.d.ts +43 -0
  45. package/dist/agents/receipt/receipt-cli.js +82 -0
  46. package/dist/agents/receipt/receipt-types.d.ts +136 -0
  47. package/dist/agents/receipt/receipt-types.js +19 -0
  48. package/dist/agents/receipt/receipt-verify.d.ts +19 -0
  49. package/dist/agents/receipt/receipt-verify.js +176 -0
  50. package/dist/agents/receipt/receipt-view.d.ts +29 -0
  51. package/dist/agents/receipt/receipt-view.js +227 -0
  52. package/dist/agents/receipt/receipt-writer.d.ts +47 -0
  53. package/dist/agents/receipt/receipt-writer.js +186 -0
  54. package/dist/agents/result-store.d.ts +43 -0
  55. package/dist/agents/result-store.js +145 -0
  56. package/dist/agents/session-diff.d.ts +49 -0
  57. package/dist/agents/session-diff.js +249 -0
  58. package/dist/agents/tool-loader.d.ts +65 -0
  59. package/dist/agents/tool-loader.js +273 -0
  60. package/dist/agents/tool-selector.d.ts +123 -0
  61. package/dist/agents/tool-selector.js +321 -0
  62. package/dist/agents/transcript.d.ts +96 -0
  63. package/dist/agents/transcript.js +267 -0
  64. package/dist/agents/verified-run-git.d.ts +49 -0
  65. package/dist/agents/verified-run-git.js +82 -0
  66. package/dist/agents/verified-run.d.ts +149 -0
  67. package/dist/agents/verified-run.js +402 -0
  68. package/dist/agents/verifier.d.ts +64 -0
  69. package/dist/agents/verifier.js +186 -0
  70. package/dist/agents/worktree-manager.d.ts +80 -0
  71. package/dist/agents/worktree-manager.js +203 -0
  72. package/dist/agents/worktree-tools.d.ts +47 -0
  73. package/dist/agents/worktree-tools.js +246 -0
  74. package/dist/auth/middleware.js +14 -0
  75. package/dist/chat/agentic-executor.d.ts +7 -0
  76. package/dist/chat/agentic-executor.js +263 -32
  77. package/dist/chat/conversations.d.ts +2 -0
  78. package/dist/chat/conversations.js +8 -0
  79. package/dist/chat/execution/executor.d.ts +8 -0
  80. package/dist/chat/execution/executor.js +157 -103
  81. package/dist/chat/execution/index.js +5 -1
  82. package/dist/chat/execution/sandbox.d.ts +8 -0
  83. package/dist/chat/execution/sandbox.js +25 -1
  84. package/dist/chat/execution/tool-router.js +40 -14
  85. package/dist/chat/execution/tools/canvas.d.ts +2 -2
  86. package/dist/chat/execution/tools/code-tools.d.ts +66 -0
  87. package/dist/chat/execution/tools/code-tools.js +353 -0
  88. package/dist/chat/execution/tools/complete-task.d.ts +2 -2
  89. package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
  90. package/dist/chat/execution/tools/cron-tool.js +48 -3
  91. package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
  92. package/dist/chat/execution/tools/decompose-task.js +166 -0
  93. package/dist/chat/execution/tools/exec.d.ts +5 -2
  94. package/dist/chat/execution/tools/exec.js +294 -155
  95. package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
  96. package/dist/chat/execution/tools/feed-tools.js +142 -0
  97. package/dist/chat/execution/tools/file-ops.d.ts +1 -1
  98. package/dist/chat/execution/tools/github.d.ts +2 -2
  99. package/dist/chat/execution/tools/index.d.ts +14 -2
  100. package/dist/chat/execution/tools/index.js +86 -12
  101. package/dist/chat/execution/tools/integrations.d.ts +8 -8
  102. package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
  103. package/dist/chat/execution/tools/multi-patch.js +373 -0
  104. package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
  105. package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
  106. package/dist/chat/execution/tools/plan-tools.js +134 -0
  107. package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
  108. package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
  109. package/dist/chat/execution/tools/repl-tool.js +207 -0
  110. package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
  111. package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
  112. package/dist/chat/execution/tools/system.d.ts +4 -4
  113. package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
  114. package/dist/chat/execution/tools/todo-tool.js +152 -0
  115. package/dist/chat/execution/tools/tool-search.d.ts +50 -0
  116. package/dist/chat/execution/tools/tool-search.js +155 -0
  117. package/dist/chat/execution/tools/tts-speak.d.ts +2 -2
  118. package/dist/chat/execution/types.d.ts +21 -14
  119. package/dist/chat/execution/workflows/executor.d.ts +11 -0
  120. package/dist/chat/execution/workflows/executor.js +99 -1
  121. package/dist/chat/execution/workflows/types.d.ts +35 -2
  122. package/dist/chat/format/index.d.ts +1 -0
  123. package/dist/chat/format/index.js +1 -0
  124. package/dist/chat/format/markdown-convert.d.ts +23 -0
  125. package/dist/chat/format/markdown-convert.js +149 -0
  126. package/dist/chat/index.d.ts +1 -1
  127. package/dist/chat/index.js +1 -1
  128. package/dist/chat/message-handler.js +58 -6
  129. package/dist/chat/meta-tool-handlers.d.ts +18 -0
  130. package/dist/chat/meta-tool-handlers.js +51 -0
  131. package/dist/chat/proactive/index.d.ts +62 -0
  132. package/dist/chat/proactive/index.js +147 -0
  133. package/dist/chat/prompt-adapter.js +2 -0
  134. package/dist/chat/providers/irc/index.d.ts +2 -2
  135. package/dist/chat/providers/telegram/index.d.ts +2 -0
  136. package/dist/chat/providers/telegram/index.js +21 -2
  137. package/dist/chat/system-prompts.d.ts +3 -3
  138. package/dist/chat/system-prompts.js +121 -61
  139. package/dist/chat/tool-handler.d.ts +2 -0
  140. package/dist/chat/tool-handler.js +47 -3
  141. package/dist/chat/tools.d.ts +6 -6
  142. package/dist/cli/commands/auth.js +64 -1
  143. package/dist/cli/commands/chat.js +1327 -138
  144. package/dist/cli/commands/doctor.js +222 -16
  145. package/dist/cli/commands/history.d.ts +3 -0
  146. package/dist/cli/commands/history.js +138 -0
  147. package/dist/cli/commands/import.d.ts +44 -0
  148. package/dist/cli/commands/import.js +526 -0
  149. package/dist/cli/commands/init.d.ts +13 -0
  150. package/dist/cli/commands/init.js +381 -0
  151. package/dist/cli/commands/onboard.js +210 -30
  152. package/dist/cli/commands/plan.d.ts +13 -0
  153. package/dist/cli/commands/plan.js +184 -0
  154. package/dist/cli/commands/receipt.d.ts +7 -0
  155. package/dist/cli/commands/receipt.js +90 -0
  156. package/dist/cli/commands/run.d.ts +28 -0
  157. package/dist/cli/commands/run.js +204 -0
  158. package/dist/cli/commands/serve.d.ts +7 -0
  159. package/dist/cli/commands/serve.js +77 -18
  160. package/dist/cli/commands/setup.js +84 -3
  161. package/dist/cli/commands/status.js +54 -0
  162. package/dist/cli/commands/tools.js +13 -13
  163. package/dist/cli/commands/tui.js +26 -1
  164. package/dist/cli/index.js +23 -0
  165. package/dist/cli/ink/App.d.ts +13 -0
  166. package/dist/cli/ink/App.js +6 -0
  167. package/dist/cli/ink/ChatApp.d.ts +60 -0
  168. package/dist/cli/ink/ChatApp.js +325 -0
  169. package/dist/cli/ink/DashboardApp.d.ts +3 -0
  170. package/dist/cli/ink/DashboardApp.js +143 -0
  171. package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
  172. package/dist/cli/ink/components/AgentStatus.js +33 -0
  173. package/dist/cli/ink/components/ChannelList.d.ts +17 -0
  174. package/dist/cli/ink/components/ChannelList.js +33 -0
  175. package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
  176. package/dist/cli/ink/components/ConnectionStatus.js +50 -0
  177. package/dist/cli/ink/components/CostBar.d.ts +19 -0
  178. package/dist/cli/ink/components/CostBar.js +35 -0
  179. package/dist/cli/ink/components/HookStatus.d.ts +15 -0
  180. package/dist/cli/ink/components/HookStatus.js +7 -0
  181. package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
  182. package/dist/cli/ink/components/PermissionPrompt.js +51 -0
  183. package/dist/cli/ink/components/PlanView.d.ts +23 -0
  184. package/dist/cli/ink/components/PlanView.js +26 -0
  185. package/dist/cli/ink/components/ProviderList.d.ts +16 -0
  186. package/dist/cli/ink/components/ProviderList.js +16 -0
  187. package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
  188. package/dist/cli/ink/components/SessionHeader.js +15 -0
  189. package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
  190. package/dist/cli/ink/components/StreamingMessage.js +27 -0
  191. package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
  192. package/dist/cli/ink/components/SuggestionBar.js +28 -0
  193. package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
  194. package/dist/cli/ink/components/SystemHealth.js +39 -0
  195. package/dist/cli/ink/components/TaskList.d.ts +17 -0
  196. package/dist/cli/ink/components/TaskList.js +59 -0
  197. package/dist/cli/ink/components/ToolCall.d.ts +17 -0
  198. package/dist/cli/ink/components/ToolCall.js +43 -0
  199. package/dist/cli/ink/index.d.ts +23 -0
  200. package/dist/cli/ink/index.js +15 -0
  201. package/dist/cli/ink/keybindings.d.ts +35 -0
  202. package/dist/cli/ink/keybindings.js +105 -0
  203. package/dist/cli/ink/markdown-renderer.d.ts +47 -0
  204. package/dist/cli/ink/markdown-renderer.js +380 -0
  205. package/dist/cli/ink/output-styles.d.ts +39 -0
  206. package/dist/cli/ink/output-styles.js +119 -0
  207. package/dist/cli/interactive/auto-serve.d.ts +38 -0
  208. package/dist/cli/interactive/auto-serve.js +209 -0
  209. package/dist/cli/interactive/index.d.ts +25 -0
  210. package/dist/cli/interactive/index.js +23 -0
  211. package/dist/cli/interactive/picker.d.ts +28 -0
  212. package/dist/cli/interactive/picker.js +153 -0
  213. package/dist/cli/interactive/renderer.d.ts +26 -0
  214. package/dist/cli/interactive/renderer.js +555 -0
  215. package/dist/cli/interactive/repl.d.ts +14 -0
  216. package/dist/cli/interactive/repl.js +1516 -0
  217. package/dist/cli/interactive/stream-client.d.ts +59 -0
  218. package/dist/cli/interactive/stream-client.js +506 -0
  219. package/dist/cli/interactive/types.d.ts +121 -0
  220. package/dist/cli/interactive/types.js +10 -0
  221. package/dist/cli/utils/api.d.ts +9 -0
  222. package/dist/cli/utils/api.js +58 -2
  223. package/dist/costs/token-tracker.d.ts +10 -1
  224. package/dist/costs/token-tracker.js +37 -5
  225. package/dist/cron/natural-language.d.ts +54 -0
  226. package/dist/cron/natural-language.js +569 -0
  227. package/dist/cron/scheduler.d.ts +34 -4
  228. package/dist/cron/scheduler.js +141 -9
  229. package/dist/cron/templates.d.ts +1 -1
  230. package/dist/cron/templates.js +219 -0
  231. package/dist/feeds/feed-engine.d.ts +149 -0
  232. package/dist/feeds/feed-engine.js +600 -0
  233. package/dist/feeds/index.d.ts +9 -0
  234. package/dist/feeds/index.js +8 -0
  235. package/dist/gateway/router.js +6 -1
  236. package/dist/hooks/built-in/audit-log.d.ts +11 -0
  237. package/dist/hooks/built-in/audit-log.js +84 -0
  238. package/dist/hooks/built-in/cost-warning.d.ts +10 -0
  239. package/dist/hooks/built-in/cost-warning.js +59 -0
  240. package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
  241. package/dist/hooks/built-in/dangerous-tool.js +80 -0
  242. package/dist/hooks/built-in/index.d.ts +14 -0
  243. package/dist/hooks/built-in/index.js +20 -0
  244. package/dist/hooks/index.d.ts +3 -0
  245. package/dist/hooks/index.js +6 -0
  246. package/dist/hooks/loader.d.ts +17 -0
  247. package/dist/hooks/loader.js +142 -0
  248. package/dist/hooks/registry.d.ts +62 -0
  249. package/dist/hooks/registry.js +127 -0
  250. package/dist/integrations/web-search.js +6 -3
  251. package/dist/memory/index.d.ts +1 -0
  252. package/dist/memory/index.js +2 -0
  253. package/dist/memory/memory-service.js +14 -13
  254. package/dist/memory/observational.d.ts +62 -0
  255. package/dist/memory/observational.js +396 -0
  256. package/dist/middleware/content-filter.d.ts +22 -0
  257. package/dist/middleware/content-filter.js +69 -0
  258. package/dist/middleware/request-validator.d.ts +159 -0
  259. package/dist/middleware/request-validator.js +93 -0
  260. package/dist/plugins/sdk.d.ts +22 -0
  261. package/dist/plugins/sdk.js +17 -1
  262. package/dist/projects/types.d.ts +10 -10
  263. package/dist/providers/ai-sdk.d.ts +11 -0
  264. package/dist/providers/ai-sdk.js +111 -56
  265. package/dist/providers/core/models.js +114 -6
  266. package/dist/providers/core/types.d.ts +7 -0
  267. package/dist/providers/index.d.ts +1 -0
  268. package/dist/providers/index.js +1 -0
  269. package/dist/providers/prompt-cache.d.ts +68 -0
  270. package/dist/providers/prompt-cache.js +165 -0
  271. package/dist/providers/smart-router.d.ts +118 -0
  272. package/dist/providers/smart-router.js +693 -0
  273. package/dist/providers/types.d.ts +16 -16
  274. package/dist/routes/agents.js +50 -0
  275. package/dist/routes/auth.js +8 -1
  276. package/dist/routes/chat.js +280 -18
  277. package/dist/routes/costs.js +32 -0
  278. package/dist/routes/cron.js +80 -5
  279. package/dist/routes/feeds.d.ts +10 -0
  280. package/dist/routes/feeds.js +168 -0
  281. package/dist/routes/mcp.js +21 -0
  282. package/dist/routes/memory.js +130 -0
  283. package/dist/routes/skills.js +129 -0
  284. package/dist/routes/teams.d.ts +9 -0
  285. package/dist/routes/teams.js +210 -0
  286. package/dist/routes/tools.js +14 -0
  287. package/dist/routes/users.js +2 -0
  288. package/dist/server/route-loader.js +3 -1
  289. package/dist/server/stream-bridge.d.ts +19 -0
  290. package/dist/server/stream-bridge.js +38 -0
  291. package/dist/server.js +313 -36
  292. package/dist/skills/marketplace.d.ts +87 -0
  293. package/dist/skills/marketplace.js +268 -0
  294. package/dist/storage/index.d.ts +14 -0
  295. package/dist/storage/index.js +64 -3
  296. package/dist/storage/schema.d.ts +4 -4
  297. package/dist/storage/schema.js +1 -1
  298. package/dist/teams/index.d.ts +110 -0
  299. package/dist/teams/index.js +365 -0
  300. package/dist/tickets/types.d.ts +39 -39
  301. package/dist/types/summary.d.ts +5 -5
  302. package/dist/utils/auto-update.d.ts +23 -0
  303. package/dist/utils/auto-update.js +157 -0
  304. package/dist/utils/offline-detect.d.ts +55 -0
  305. package/dist/utils/offline-detect.js +121 -0
  306. package/dist/utils/pid-file.d.ts +36 -0
  307. package/dist/utils/pid-file.js +125 -0
  308. package/dist/utils/prevent-sleep.d.ts +27 -0
  309. package/dist/utils/prevent-sleep.js +95 -0
  310. package/dist/utils/sanitizer.d.ts +57 -0
  311. package/dist/utils/sanitizer.js +174 -0
  312. package/docker-compose.yml +13 -137
  313. package/package.json +31 -6
  314. package/skills/deploy-cloudflare/SKILL.md +62 -0
  315. package/skills/deploy-vercel/SKILL.md +67 -0
  316. package/skills/docker-deploy/SKILL.md +158 -0
  317. package/skills/full-stack-builder/SKILL.md +92 -0
  318. package/skills/humanizer/SKILL.md +488 -0
  319. package/skills/profclaw-assistant/SKILL.md +85 -56
  320. package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
  321. package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
  322. package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
  323. package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
  324. package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
  325. package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
  326. package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
  327. package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
  328. package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
  329. package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
  330. package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
  331. package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  332. package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  333. package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  334. package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  335. package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  336. package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  337. package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  338. package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  339. package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  340. package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  341. package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  342. package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  343. package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  344. package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  345. package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  346. package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  347. package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  348. package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  349. package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  350. package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  351. package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  352. package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  353. package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  354. package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  355. package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  356. package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  357. package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  358. package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  359. package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  360. package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  361. package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  362. package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  363. package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  364. package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  365. package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  366. package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  367. package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  368. package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  369. package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  370. package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  371. package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  372. package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  373. package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  374. package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  375. package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  376. package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  377. package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  378. package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  379. package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  380. package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  381. package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  382. package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  383. package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  384. package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  385. package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  386. package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  387. package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  388. package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  389. package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  390. package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
  391. package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
  392. package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
  393. package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
  394. package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
  395. package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
  396. package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
  397. package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
  398. package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
  399. package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
  400. package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
  401. package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
  402. package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
  403. package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
  404. package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
  405. package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
  406. package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
  407. package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
  408. package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
  409. package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
  410. package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
  411. package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
  412. package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
  413. package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
  414. package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
  415. package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
  416. package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
  417. package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
  418. package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
  419. package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
  420. package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
  421. package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
  422. package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
  423. package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
  424. package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
  425. package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
  426. package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
  427. package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
  428. package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
  429. package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
  430. package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
  431. package/ui/dist/assets/index-CR8gfCHv.js +1 -0
  432. package/ui/dist/assets/index-DVXMpWai.js +1 -0
  433. package/ui/dist/assets/index-DaDJMM2v.js +1 -0
  434. package/ui/dist/assets/index-Djdq_0xu.js +1 -0
  435. package/ui/dist/assets/index-M46Gcb8K.css +1 -0
  436. package/ui/dist/assets/index-sEBN7w8J.js +109 -0
  437. package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
  438. package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
  439. package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
  440. package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
  441. package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
  442. package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
  443. package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
  444. package/ui/dist/assets/package-CwT3IzFx.js +1 -0
  445. package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
  446. package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
  447. package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
  448. package/ui/dist/assets/progress-BboUHuLf.js +1 -0
  449. package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
  450. package/ui/dist/assets/select-n108rXny.js +1 -0
  451. package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
  452. package/ui/dist/assets/server-DmodxZp-.js +1 -0
  453. package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
  454. package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
  455. package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
  456. package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
  457. package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
  458. package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
  459. package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
  460. package/ui/dist/assets/star-DhdFVidS.js +1 -0
  461. package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
  462. package/ui/dist/assets/table-BC56FVMV.js +1 -0
  463. package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
  464. package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
  465. package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
  466. package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
  467. package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
  468. package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
  469. package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
  470. package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
  471. package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
  472. package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
  473. package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
  474. package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
  475. package/ui/dist/index.html +5 -2
  476. package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
  477. package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
  478. package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
  479. package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
  480. package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
  481. package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
  482. package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
  483. package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
  484. package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
  485. package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
  486. package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
  487. package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
  488. package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
  489. package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
  490. package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
  491. package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
  492. package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
  493. package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
  494. package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
  495. package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
  496. package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
  497. package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
  498. package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
  499. package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
  500. package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
  501. package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
  502. package/ui/dist/assets/index-BUmnwPQr.js +0 -1
  503. package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
  504. package/ui/dist/assets/index-C8N375c2.js +0 -1
  505. package/ui/dist/assets/index-CuxnqVVz.css +0 -1
  506. package/ui/dist/assets/index-CzMM3QOk.js +0 -1
  507. package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
  508. package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
  509. package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
  510. package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
  511. package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
  512. package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
  513. package/ui/dist/assets/server-CVHTZB72.js +0 -1
  514. package/ui/dist/assets/sheet-DuQExSho.js +0 -1
  515. package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
  516. package/ui/dist/assets/switch-CAePkd6k.js +0 -1
  517. package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
  518. package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
  519. package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
@@ -0,0 +1,325 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ChatApp — Full Interactive Chat TUI
4
+ *
5
+ * Layout:
6
+ * ┌ SessionHeader ──────────────────────────────────┐
7
+ * │ message history (StreamingMessage list) │
8
+ * │ AgentStatus (while streaming) │
9
+ * │ PermissionPrompt (overlay when needed) │
10
+ * ├─────────────────────────────────────────────────┤
11
+ * │ CostBar │
12
+ * │ > TextInput │
13
+ * └─────────────────────────────────────────────────┘
14
+ */
15
+ import { useState, useCallback, useEffect } from 'react';
16
+ import { Box, Text, useApp, useInput } from 'ink';
17
+ import TextInput from 'ink-text-input';
18
+ import { App } from './App.js';
19
+ import { SessionHeader } from './components/SessionHeader.js';
20
+ import { StreamingMessage } from './components/StreamingMessage.js';
21
+ import { AgentStatus } from './components/AgentStatus.js';
22
+ import { CostBar } from './components/CostBar.js';
23
+ import { PermissionPrompt, } from './components/PermissionPrompt.js';
24
+ import { SuggestionBar } from './components/SuggestionBar.js';
25
+ import { ConnectionStatus } from './components/ConnectionStatus.js';
26
+ const SLASH_COMMANDS = [
27
+ { name: '/model', description: 'Switch AI model', hasSubPicker: true, immediate: false },
28
+ { name: '/provider', description: 'Switch provider', hasSubPicker: true, immediate: false },
29
+ { name: '/agentic', description: 'Toggle agentic mode (tools + multi-step)', hasSubPicker: false, immediate: true },
30
+ { name: '/effort', description: 'Set effort: low | medium | high', hasSubPicker: false, immediate: false },
31
+ { name: '/thinking', description: 'Toggle thinking display', hasSubPicker: false, immediate: true },
32
+ { name: '/tools', description: 'Toggle tool call verbosity', hasSubPicker: false, immediate: true },
33
+ { name: '/new', description: 'Start a fresh conversation', hasSubPicker: false, immediate: true },
34
+ { name: '/sessions', description: 'List recent conversations', hasSubPicker: false, immediate: true },
35
+ { name: '/resume', description: 'Resume a session by id prefix', hasSubPicker: false, immediate: false },
36
+ { name: '/status', description: 'Server and provider health', hasSubPicker: false, immediate: true },
37
+ { name: '/insights', description: 'Session and server usage analytics', hasSubPicker: false, immediate: true },
38
+ { name: '/run', description: 'Execute a shell command', hasSubPicker: false, immediate: false },
39
+ { name: '/retry', description: 'Retry last message', hasSubPicker: false, immediate: true },
40
+ { name: '/diff', description: 'Show unified diff of all file changes this session', hasSubPicker: false, immediate: true },
41
+ { name: '/rewind', description: 'List or restore file snapshots (optional: <path> or --turn <n>)', hasSubPicker: false, immediate: false },
42
+ { name: '/compact', description: 'Compact context — summarize old turns (--llm for LLM summary)', hasSubPicker: false, immediate: true },
43
+ { name: '/branch', description: 'Fork conversation at current turn (or /branch <n> for turn N)', hasSubPicker: false, immediate: false },
44
+ { name: '/branches', description: 'List all branches for this conversation', hasSubPicker: false, immediate: true },
45
+ { name: '/clear', description: 'Clear display', hasSubPicker: false, immediate: true },
46
+ { name: '/help', description: 'Show all commands', hasSubPicker: false, immediate: true },
47
+ { name: '/exit', description: 'Quit', hasSubPicker: false, immediate: true },
48
+ ];
49
+ // Max number of history entries to retain
50
+ const MAX_HISTORY = 50;
51
+ export const ChatApp = ({ sessionInfo, tokensUsed, tokensMax, estimatedCost, agentStatus, agentAction, stepCount, elapsedMs, messages, streamingContent, pendingPermission, availableModels = [], availableProviders = [], suggestions = [], connectionStatus = 'connected', connectionLatencyMs, onSubmit, onPermissionDecision, onCancel, }) => {
52
+ const { exit } = useApp();
53
+ const [inputValue, setInputValue] = useState('');
54
+ const [pickerMode, setPickerMode] = useState('none');
55
+ const [selectedIdx, setSelectedIdx] = useState(0);
56
+ const [subPickerTitle, setSubPickerTitle] = useState('');
57
+ const [subPickerItems, setSubPickerItems] = useState([]);
58
+ const [subPickerCommand, setSubPickerCommand] = useState('');
59
+ // ── Multiline state ──────────────────────────────────────────────────────────
60
+ const [isMultiline, setIsMultiline] = useState(false);
61
+ const [multilineLines, setMultilineLines] = useState([]);
62
+ // ── Input history state ──────────────────────────────────────────────────────
63
+ const [inputHistory, setInputHistory] = useState([]);
64
+ const [historyIndex, setHistoryIndex] = useState(-1);
65
+ // Saved draft before navigating history (so Down arrow restores it)
66
+ const [historyDraft, setHistoryDraft] = useState('');
67
+ const isStreaming = agentStatus === 'thinking' || agentStatus === 'executing';
68
+ // Compute matching commands when in command picker mode
69
+ const inCommandPicker = inputValue.startsWith('/') && inputValue.indexOf(' ') === -1 && !isStreaming && !isMultiline;
70
+ const matchingCmds = inCommandPicker
71
+ ? SLASH_COMMANDS.filter(c => c.name.startsWith(inputValue.toLowerCase()))
72
+ : [];
73
+ // Auto-show/hide command picker
74
+ useEffect(() => {
75
+ if (inCommandPicker && matchingCmds.length > 0 && pickerMode === 'none') {
76
+ setPickerMode('commands');
77
+ setSelectedIdx(0);
78
+ }
79
+ else if (!inCommandPicker && pickerMode === 'commands') {
80
+ setPickerMode('none');
81
+ }
82
+ }, [inCommandPicker, matchingCmds.length, pickerMode]);
83
+ // Current picker items
84
+ const pickerItems = pickerMode === 'commands'
85
+ ? matchingCmds.map(c => ({ label: c.name, value: c.name, description: c.description }))
86
+ : pickerMode === 'sub'
87
+ ? subPickerItems
88
+ : [];
89
+ // Keep index in bounds
90
+ const maxIdx = Math.max(0, pickerItems.length - 1);
91
+ const safeIdx = Math.min(selectedIdx, maxIdx);
92
+ // Ghost text
93
+ const ghostText = pickerMode === 'commands' && matchingCmds.length > 0
94
+ ? (matchingCmds[safeIdx]?.name ?? '').slice(inputValue.length)
95
+ : '';
96
+ // Open sub-picker for a command
97
+ const openSubPicker = useCallback((cmd) => {
98
+ if (cmd.name === '/model') {
99
+ setSubPickerTitle(`Select Model (${availableModels.length} available)`);
100
+ setSubPickerItems(availableModels);
101
+ setSubPickerCommand('/model');
102
+ }
103
+ else if (cmd.name === '/provider') {
104
+ setSubPickerTitle(`Select Provider (${availableProviders.length} available)`);
105
+ setSubPickerItems(availableProviders);
106
+ setSubPickerCommand('/provider');
107
+ }
108
+ setPickerMode('sub');
109
+ setSelectedIdx(0);
110
+ setInputValue('');
111
+ }, [availableModels, availableProviders]);
112
+ // ── Ctrl+C handler — always active to intercept before Ink's default exit ────
113
+ useInput((input, key) => {
114
+ if (!key.ctrl || input !== 'c')
115
+ return;
116
+ if (isStreaming) {
117
+ // Cancel the in-flight stream; do not exit
118
+ onCancel?.();
119
+ return;
120
+ }
121
+ if (inputValue.length > 0 || isMultiline) {
122
+ // Clear pending input
123
+ setInputValue('');
124
+ setIsMultiline(false);
125
+ setMultilineLines([]);
126
+ setHistoryIndex(-1);
127
+ return;
128
+ }
129
+ // Nothing to cancel — exit normally
130
+ exit();
131
+ });
132
+ // ── Alt+Enter / history navigation ──────────────────────────────────────────
133
+ useInput((input, key) => {
134
+ // Alt+Enter: toggle multiline mode
135
+ if (key.meta && key.return) {
136
+ if (!isMultiline) {
137
+ setIsMultiline(true);
138
+ }
139
+ else {
140
+ // Cancel multiline; discard accumulated lines
141
+ setIsMultiline(false);
142
+ setMultilineLines([]);
143
+ }
144
+ return;
145
+ }
146
+ // Up arrow: navigate backward through history (picker closed, not in multiline)
147
+ if (key.upArrow && pickerMode === 'none' && !isMultiline) {
148
+ if (inputHistory.length === 0)
149
+ return;
150
+ if (historyIndex === -1) {
151
+ setHistoryDraft(inputValue);
152
+ }
153
+ const newIdx = historyIndex === -1
154
+ ? inputHistory.length - 1
155
+ : Math.max(0, historyIndex - 1);
156
+ setHistoryIndex(newIdx);
157
+ setInputValue(inputHistory[newIdx] ?? '');
158
+ return;
159
+ }
160
+ // Down arrow: navigate forward through history (picker closed, not in multiline)
161
+ if (key.downArrow && pickerMode === 'none' && !isMultiline) {
162
+ if (historyIndex === -1)
163
+ return;
164
+ const newIdx = historyIndex + 1;
165
+ if (newIdx >= inputHistory.length) {
166
+ setHistoryIndex(-1);
167
+ setInputValue(historyDraft);
168
+ }
169
+ else {
170
+ setHistoryIndex(newIdx);
171
+ setInputValue(inputHistory[newIdx] ?? '');
172
+ }
173
+ return;
174
+ }
175
+ // Ctrl+Enter in multiline mode: submit all accumulated lines + current line
176
+ if (isMultiline && key.ctrl && key.return) {
177
+ const allLines = [...multilineLines, inputValue].filter(l => l.length > 0);
178
+ if (allLines.length === 0)
179
+ return;
180
+ const combined = allLines.join('\n');
181
+ setIsMultiline(false);
182
+ setMultilineLines([]);
183
+ setInputValue('');
184
+ setHistoryIndex(-1);
185
+ setHistoryDraft('');
186
+ setInputHistory(prev => {
187
+ const next = [...prev, combined];
188
+ return next.length > MAX_HISTORY ? next.slice(next.length - MAX_HISTORY) : next;
189
+ });
190
+ onSubmit(combined);
191
+ return;
192
+ }
193
+ void input;
194
+ }, { isActive: !isStreaming && pendingPermission === undefined });
195
+ // ── Picker keyboard navigation ───────────────────────────────────────────────
196
+ useInput((_input, key) => {
197
+ if (pickerMode === 'none' || pickerItems.length === 0)
198
+ return;
199
+ if (key.upArrow) {
200
+ setSelectedIdx(prev => {
201
+ let next = prev <= 0 ? pickerItems.length - 1 : prev - 1;
202
+ // Skip disabled items
203
+ let attempts = 0;
204
+ while (pickerItems[next] && pickerItems[next]?.disabled && attempts < pickerItems.length) {
205
+ next = next <= 0 ? pickerItems.length - 1 : next - 1;
206
+ attempts++;
207
+ }
208
+ return next;
209
+ });
210
+ }
211
+ else if (key.downArrow) {
212
+ setSelectedIdx(prev => {
213
+ let next = prev >= pickerItems.length - 1 ? 0 : prev + 1;
214
+ let attempts = 0;
215
+ while (pickerItems[next] && pickerItems[next]?.disabled && attempts < pickerItems.length) {
216
+ next = next >= pickerItems.length - 1 ? 0 : next + 1;
217
+ attempts++;
218
+ }
219
+ return next;
220
+ });
221
+ }
222
+ else if (key.escape) {
223
+ setPickerMode('none');
224
+ setInputValue('');
225
+ setSelectedIdx(0);
226
+ }
227
+ }, { isActive: pickerMode !== 'none' && !isStreaming });
228
+ const handleSubmit = useCallback((value) => {
229
+ // In multiline mode, Enter appends the current line and moves to the next
230
+ if (isMultiline) {
231
+ setMultilineLines(prev => [...prev, value]);
232
+ setInputValue('');
233
+ return;
234
+ }
235
+ const trimmed = value.trim();
236
+ // Sub-picker: Enter selects the highlighted option (skip disabled)
237
+ if (pickerMode === 'sub' && subPickerItems.length > 0) {
238
+ const item = subPickerItems[safeIdx];
239
+ if (item && !(item.disabled)) {
240
+ setPickerMode('none');
241
+ setInputValue('');
242
+ setSelectedIdx(0);
243
+ onSubmit(`${subPickerCommand} ${item.value}`);
244
+ }
245
+ return;
246
+ }
247
+ // Command picker: Enter selects highlighted command
248
+ if (pickerMode === 'commands' && matchingCmds.length > 0) {
249
+ const cmd = matchingCmds[safeIdx];
250
+ if (cmd) {
251
+ if (cmd.hasSubPicker) {
252
+ openSubPicker(cmd);
253
+ }
254
+ else if (cmd.immediate) {
255
+ setPickerMode('none');
256
+ setInputValue('');
257
+ setSelectedIdx(0);
258
+ if (cmd.name === '/exit') {
259
+ exit();
260
+ return;
261
+ }
262
+ onSubmit(cmd.name);
263
+ }
264
+ }
265
+ return;
266
+ }
267
+ if (trimmed.length === 0)
268
+ return;
269
+ if (trimmed === '/exit' || trimmed === '/quit') {
270
+ exit();
271
+ return;
272
+ }
273
+ setInputValue('');
274
+ setSelectedIdx(0);
275
+ setPickerMode('none');
276
+ setHistoryIndex(-1);
277
+ setHistoryDraft('');
278
+ setInputHistory(prev => {
279
+ const next = [...prev, trimmed];
280
+ return next.length > MAX_HISTORY ? next.slice(next.length - MAX_HISTORY) : next;
281
+ });
282
+ onSubmit(trimmed);
283
+ }, [
284
+ onSubmit,
285
+ exit,
286
+ pickerMode,
287
+ safeIdx,
288
+ matchingCmds,
289
+ subPickerItems,
290
+ subPickerCommand,
291
+ openSubPicker,
292
+ isMultiline,
293
+ ]);
294
+ const handlePermission = useCallback((decision) => {
295
+ if (pendingPermission) {
296
+ pendingPermission.resolve(decision);
297
+ }
298
+ onPermissionDecision?.(decision);
299
+ }, [pendingPermission, onPermissionDecision]);
300
+ // ── Prompt prefix ────────────────────────────────────────────────────────────
301
+ const promptPrefix = isMultiline ? '... ' : '> ';
302
+ return (_jsxs(App, { children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", alignItems: "center", children: [_jsx(SessionHeader, { model: sessionInfo.model, provider: sessionInfo.provider, sessionId: sessionInfo.sessionId, mode: sessionInfo.mode }), connectionStatus !== 'connected' && (_jsx(Box, { paddingX: 1, children: _jsx(ConnectionStatus, { status: connectionStatus, latencyMs: connectionLatencyMs, provider: sessionInfo.provider }) }))] }), connectionStatus === 'disconnected' && (_jsxs(Box, { borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 0, marginX: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Server unreachable \u2014 waiting for connection..." }), _jsx(Text, { dimColor: true, children: " Messages will be sent once the server is back online." })] })), connectionStatus === 'reconnecting' && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellow", children: "Reconnecting to server..." }) })), _jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingY: 1, children: [messages.map((msg, idx) => (_jsx(StreamingMessage, { role: msg.role === 'system' ? 'assistant' : msg.role, content: msg.content, model: msg.model }, `msg-${msg.timestamp?.getTime?.() ?? idx}-${idx}`))), streamingContent !== undefined && streamingContent.length > 0 && (_jsx(StreamingMessage, { role: "assistant", content: streamingContent, isStreaming: true, model: sessionInfo.model }))] }), (isStreaming || agentStatus === 'complete') && (_jsx(AgentStatus, { status: agentStatus, currentAction: agentAction, stepCount: stepCount, tokensUsed: tokensUsed, elapsedMs: elapsedMs })), pendingPermission !== undefined && (_jsx(PermissionPrompt, { toolName: pendingPermission.toolName, args: pendingPermission.args, permissionLevel: pendingPermission.permissionLevel, reason: pendingPermission.reason, onDecision: handlePermission })), pickerMode !== 'none' && pickerItems.length > 0 && (() => {
303
+ const MAX_VISIBLE = 6;
304
+ const total = pickerItems.length;
305
+ const start = Math.max(0, Math.min(safeIdx - Math.floor(MAX_VISIBLE / 2), total - MAX_VISIBLE));
306
+ const visible = pickerItems.slice(start, start + MAX_VISIBLE);
307
+ const showScrollUp = start > 0;
308
+ const showScrollDown = start + MAX_VISIBLE < total;
309
+ const title = pickerMode === 'sub' ? subPickerTitle : 'Commands';
310
+ return (_jsx(Box, { flexDirection: "column", paddingX: 2, children: _jsxs(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { bold: true, color: "cyan", children: [' ', title] }), _jsx(Text, { dimColor: true, children: ' ─'.repeat(20) }), showScrollUp && _jsxs(Text, { dimColor: true, children: [" \u2191 more (", start, " above)"] }), visible.map((item) => {
311
+ const realIdx = pickerItems.indexOf(item);
312
+ const isSelected = realIdx === safeIdx;
313
+ const isDisabled = item.disabled;
314
+ return (_jsxs(Box, { gap: 1, children: [_jsxs(Text, { color: isDisabled ? 'gray' : isSelected ? 'cyan' : undefined, bold: isSelected && !isDisabled, inverse: isSelected && !isDisabled, dimColor: isDisabled, strikethrough: isDisabled, children: [' ', item.label.padEnd(20)] }), item.description && _jsx(Text, { dimColor: true, children: item.description }), item.active && !isDisabled && _jsx(Text, { color: "green", children: " \u25CF" }), isDisabled && _jsx(Text, { color: "gray", children: " \u2298" })] }, item.value + (isDisabled ? '-disabled' : '')));
315
+ }), showScrollDown && _jsxs(Text, { dimColor: true, children: [" \u2193 more (", total - start - MAX_VISIBLE, " below)"] }), _jsx(Text, { dimColor: true, children: " \u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc back" })] }) }));
316
+ })(), suggestions.length > 0 && !isStreaming && pickerMode === 'none' && (_jsx(SuggestionBar, { suggestions: suggestions, isActive: pendingPermission === undefined && !isStreaming && pickerMode === 'none', onSelect: (text) => {
317
+ onSubmit(text);
318
+ } })), isMultiline && multilineLines.length > 0 && (_jsx(Box, { flexDirection: "column", paddingX: 1, children: multilineLines.map((line, idx) => (_jsxs(Box, { flexDirection: "row", gap: 0, children: [_jsx(Text, { color: "yellow", bold: true, children: '... ' }), _jsx(Text, { children: line })] }, idx))) })), _jsxs(Box, { flexDirection: "row", gap: 0, paddingX: 1, children: [_jsx(Text, { color: isMultiline ? 'yellow' : 'cyan', bold: true, children: promptPrefix }), connectionStatus === 'disconnected' ? (_jsx(Text, { dimColor: true, color: "red", children: "Offline \u2014 waiting for server..." })) : pendingPermission === undefined && !isStreaming ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(TextInput, { value: inputValue, onChange: (val) => { setInputValue(val); if (!isMultiline)
319
+ setSelectedIdx(0); }, onSubmit: handleSubmit, placeholder: isMultiline
320
+ ? 'Add line... (Ctrl+Enter to send · Alt+Enter to cancel)'
321
+ : 'Message profClaw... (/ for commands)' }), ghostText.length > 0 && _jsx(Text, { dimColor: true, children: ghostText })] })) : (_jsx(Text, { dimColor: true, children: pendingPermission !== undefined
322
+ ? 'Waiting for permission...'
323
+ : 'Agent is working... (Ctrl+C to cancel)' }))] }), isMultiline && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: " multiline \u2014 Enter adds line \u00B7 Ctrl+Enter sends \u00B7 Alt+Enter cancels" }) })), _jsx(CostBar, { tokensUsed: tokensUsed, tokensMax: tokensMax, estimatedCost: estimatedCost })] }));
324
+ };
325
+ //# sourceMappingURL=ChatApp.js.map
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare function DashboardApp(): React.ReactElement;
3
+ //# sourceMappingURL=DashboardApp.d.ts.map
@@ -0,0 +1,143 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback } from 'react';
3
+ import { Box, Text, useInput, useApp } from 'ink';
4
+ import { ProviderList } from './components/ProviderList.js';
5
+ import { TaskList } from './components/TaskList.js';
6
+ import { SystemHealth } from './components/SystemHealth.js';
7
+ import { HookStatus } from './components/HookStatus.js';
8
+ import { ChannelList } from './components/ChannelList.js';
9
+ import { api } from '../utils/api.js';
10
+ const TABS = [
11
+ { id: 'overview', label: 'Overview' },
12
+ { id: 'tasks', label: 'Tasks' },
13
+ { id: 'channels', label: 'Channels' },
14
+ { id: 'hooks', label: 'Hooks' },
15
+ ];
16
+ // ---- Helpers ----
17
+ function toTaskStatus(raw) {
18
+ const allowed = ['pending', 'running', 'completed', 'failed', 'cancelled'];
19
+ return allowed.includes(raw)
20
+ ? raw
21
+ : 'pending';
22
+ }
23
+ function toChannelStatus(raw) {
24
+ const allowed = ['connected', 'disconnected', 'error', 'connecting'];
25
+ return allowed.includes(raw)
26
+ ? raw
27
+ : 'disconnected';
28
+ }
29
+ // ---- Tab bar ----
30
+ function TabBar({ current, onSelect }) {
31
+ void onSelect; // navigation handled via keyboard, kept for future mouse use
32
+ return (_jsxs(Box, { gap: 1, marginBottom: 1, children: [TABS.map((tab, i) => (_jsx(Box, { gap: 0, children: _jsxs(Text, { color: current === tab.id ? 'cyan' : 'white', bold: current === tab.id, dimColor: current !== tab.id, children: [i > 0 ? '│ ' : '', tab.label] }) }, tab.id))), _jsx(Text, { dimColor: true, children: " \u2190 \u2192 to switch q to quit" })] }));
33
+ }
34
+ // ---- Main app ----
35
+ export function DashboardApp() {
36
+ const { exit } = useApp();
37
+ const [tabIndex, setTabIndex] = useState(0);
38
+ const [lastRefresh, setLastRefresh] = useState(new Date());
39
+ const [data, setData] = useState({
40
+ system: {},
41
+ providers: [],
42
+ tasks: [],
43
+ hooks: [],
44
+ channels: [],
45
+ });
46
+ const [loadState, setLoadState] = useState({ loading: true });
47
+ const fetchData = useCallback(async () => {
48
+ setLoadState((prev) => ({ ...prev, loading: true }));
49
+ const [sysRes, provRes, taskRes, hookRes, chanRes] = await Promise.allSettled([
50
+ api.get('/health'),
51
+ api.get('/api/chat/providers'),
52
+ api.get('/api/tasks?limit=20&sort=createdAt'),
53
+ api.get('/api/hooks'),
54
+ api.get('/api/channels'),
55
+ ]);
56
+ const next = {
57
+ system: {},
58
+ providers: [],
59
+ tasks: [],
60
+ hooks: [],
61
+ channels: [],
62
+ };
63
+ const errors = { loading: false };
64
+ if (sysRes.status === 'fulfilled' && sysRes.value.ok && sysRes.value.data) {
65
+ const raw = sysRes.value.data;
66
+ next.system = {
67
+ ...raw,
68
+ healthy: raw.status === 'ok' || raw.healthy === true,
69
+ queueBackend: (raw.queue ?? raw.queueBackend),
70
+ };
71
+ }
72
+ else {
73
+ errors.systemError =
74
+ sysRes.status === 'fulfilled'
75
+ ? (sysRes.value.error ?? 'Failed to load system status')
76
+ : 'Failed to load system status';
77
+ }
78
+ if (provRes.status === 'fulfilled' && provRes.value.ok && provRes.value.data) {
79
+ next.providers = provRes.value.data.providers;
80
+ }
81
+ else {
82
+ errors.providersError = 'Failed to load providers';
83
+ }
84
+ if (taskRes.status === 'fulfilled' && taskRes.value.ok && taskRes.value.data) {
85
+ next.tasks = taskRes.value.data.tasks.map((t) => ({
86
+ ...t,
87
+ status: toTaskStatus(t.status),
88
+ }));
89
+ }
90
+ else {
91
+ errors.tasksError = 'Failed to load tasks';
92
+ }
93
+ if (hookRes.status === 'fulfilled' && hookRes.value.ok && hookRes.value.data) {
94
+ next.hooks = hookRes.value.data.hooks;
95
+ }
96
+ else {
97
+ // /api/hooks may not exist yet — show empty list instead of error
98
+ next.hooks = [];
99
+ }
100
+ if (chanRes.status === 'fulfilled' && chanRes.value.ok && chanRes.value.data) {
101
+ // API returns { provider, registered, enabled, configured } — map to our Channel shape
102
+ const raw = chanRes.value.data.channels;
103
+ next.channels = raw.map((c) => ({
104
+ name: (c.name ?? c.provider ?? 'unknown'),
105
+ type: (c.type ?? c.provider ?? ''),
106
+ status: toChannelStatus(c.status ??
107
+ (c.registered ? 'connected' : c.configured ? 'disconnected' : 'disconnected')),
108
+ messageCount: (c.messageCount ?? 0),
109
+ lastActivity: (c.lastActivity ?? c.lastActivityAt ?? ''),
110
+ }));
111
+ }
112
+ else {
113
+ errors.channelsError = 'Failed to load channels';
114
+ }
115
+ setData(next);
116
+ setLoadState(errors);
117
+ setLastRefresh(new Date());
118
+ }, []);
119
+ // Initial load + auto-refresh every 5 seconds
120
+ useEffect(() => {
121
+ void fetchData();
122
+ const timer = setInterval(() => { void fetchData(); }, 5000);
123
+ return () => clearInterval(timer);
124
+ }, [fetchData]);
125
+ useInput((input, key) => {
126
+ if (input === 'q' || (key.ctrl && input === 'c')) {
127
+ exit();
128
+ return;
129
+ }
130
+ if (key.rightArrow) {
131
+ setTabIndex((i) => (i + 1) % TABS.length);
132
+ }
133
+ if (key.leftArrow) {
134
+ setTabIndex((i) => (i - 1 + TABS.length) % TABS.length);
135
+ }
136
+ if (input === 'r') {
137
+ void fetchData();
138
+ }
139
+ });
140
+ const currentTab = TABS[tabIndex].id;
141
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsx(Text, { bold: true, color: "cyan", children: "profClaw Dashboard" }), _jsxs(Text, { dimColor: true, children: [lastRefresh.toLocaleTimeString(), " \u00B7 r to refresh"] })] }), _jsx(TabBar, { current: currentTab, onSelect: (id) => setTabIndex(TABS.findIndex((t) => t.id === id)) }), _jsx(Text, { dimColor: true, children: '─'.repeat(60) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [currentTab === 'overview' && (_jsxs(Box, { flexDirection: "column", gap: 2, children: [_jsx(SystemHealth, { metrics: data.system, loading: loadState.loading, error: loadState.systemError }), _jsx(ProviderList, { providers: data.providers, loading: loadState.loading, error: loadState.providersError })] })), currentTab === 'tasks' && (_jsx(TaskList, { tasks: data.tasks, loading: loadState.loading, error: loadState.tasksError })), currentTab === 'channels' && (_jsx(ChannelList, { channels: data.channels, loading: loadState.loading, error: loadState.channelsError })), currentTab === 'hooks' && (_jsx(HookStatus, { hooks: data.hooks, loading: loadState.loading, error: loadState.hooksError }))] })] }));
142
+ }
143
+ //# sourceMappingURL=DashboardApp.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * AgentStatus Component
3
+ *
4
+ * Real-time agent status display showing current action, step count,
5
+ * tokens used, and elapsed time. Uses a spinner when agent is active.
6
+ */
7
+ import React from 'react';
8
+ export type AgentStatusState = 'idle' | 'thinking' | 'executing' | 'complete' | 'error';
9
+ export interface AgentStatusProps {
10
+ status: AgentStatusState;
11
+ currentAction?: string;
12
+ stepCount: number;
13
+ tokensUsed: number;
14
+ elapsedMs: number;
15
+ }
16
+ export declare const AgentStatus: React.FC<AgentStatusProps>;
17
+ //# sourceMappingURL=AgentStatus.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import Spinner from 'ink-spinner';
4
+ function formatElapsed(ms) {
5
+ if (ms < 1000)
6
+ return `${ms}ms`;
7
+ if (ms < 60000)
8
+ return `${(ms / 1000).toFixed(1)}s`;
9
+ const mins = Math.floor(ms / 60000);
10
+ const secs = Math.floor((ms % 60000) / 1000);
11
+ return `${mins}m ${secs}s`;
12
+ }
13
+ function formatTokens(count) {
14
+ if (count >= 1000000)
15
+ return `${(count / 1000000).toFixed(1)}M`;
16
+ if (count >= 1000)
17
+ return `${(count / 1000).toFixed(1)}K`;
18
+ return count.toString();
19
+ }
20
+ const STATUS_COLORS = {
21
+ idle: 'gray',
22
+ thinking: 'yellow',
23
+ executing: 'cyan',
24
+ complete: 'green',
25
+ error: 'red',
26
+ };
27
+ const isActive = (status) => status === 'thinking' || status === 'executing';
28
+ export const AgentStatus = ({ status, currentAction, stepCount, tokensUsed, elapsedMs, }) => {
29
+ const statusColor = STATUS_COLORS[status];
30
+ const active = isActive(status);
31
+ return (_jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, children: [active ? (_jsx(Text, { color: statusColor, children: _jsx(Spinner, { type: "dots" }) })) : (_jsx(Text, { color: statusColor, children: status === 'complete' ? '✓' : status === 'error' ? '✗' : '·' })), _jsx(Text, { color: statusColor, bold: active, children: status }), currentAction !== undefined && currentAction.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "\u203A" }), _jsx(Text, { color: "white", children: currentAction })] })), _jsxs(Text, { dimColor: true, children: [' ', "step ", stepCount, " \u00B7 ", formatTokens(tokensUsed), " tok \u00B7 ", formatElapsed(elapsedMs)] })] }));
32
+ };
33
+ //# sourceMappingURL=AgentStatus.js.map
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ export type ChannelStatus = 'connected' | 'disconnected' | 'error' | 'connecting';
3
+ export interface Channel {
4
+ name: string;
5
+ type: string;
6
+ status: ChannelStatus;
7
+ messageCount?: number;
8
+ lastActivity?: string;
9
+ }
10
+ interface ChannelListProps {
11
+ channels: Channel[];
12
+ loading?: boolean;
13
+ error?: string;
14
+ }
15
+ export declare function ChannelList({ channels, loading, error }: ChannelListProps): React.ReactElement;
16
+ export {};
17
+ //# sourceMappingURL=ChannelList.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ function statusColor(status) {
4
+ const map = {
5
+ connected: 'green',
6
+ connecting: 'yellow',
7
+ disconnected: 'gray',
8
+ error: 'red',
9
+ };
10
+ return map[status];
11
+ }
12
+ function statusDot(status) {
13
+ return status === 'connected' ? '●' : status === 'connecting' ? '◐' : '○';
14
+ }
15
+ function formatRelative(iso) {
16
+ if (!iso)
17
+ return '-';
18
+ const diff = Date.now() - new Date(iso).getTime();
19
+ const s = Math.floor(diff / 1000);
20
+ if (s < 60)
21
+ return `${s}s ago`;
22
+ const m = Math.floor(s / 60);
23
+ if (m < 60)
24
+ return `${m}m ago`;
25
+ const h = Math.floor(m / 60);
26
+ if (h < 24)
27
+ return `${h}h ago`;
28
+ return `${Math.floor(h / 24)}d ago`;
29
+ }
30
+ export function ChannelList({ channels, loading, error }) {
31
+ return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { bold: true, color: "white", children: "Chat Channels" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [loading && _jsx(Text, { dimColor: true, children: " Loading channels..." }), error && _jsxs(Text, { color: "red", children: [" ", error] }), !loading && !error && channels.length === 0 && (_jsx(Text, { dimColor: true, children: " No channels configured" })), !loading && !error && channels.length > 0 && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { dimColor: true, bold: true, children: ' Channel'.padEnd(18) }), _jsx(Text, { dimColor: true, bold: true, children: 'Type'.padEnd(12) }), _jsx(Text, { dimColor: true, bold: true, children: 'Status'.padEnd(16) }), _jsx(Text, { dimColor: true, bold: true, children: 'Messages'.padEnd(10) }), _jsx(Text, { dimColor: true, bold: true, children: "Last active" })] }), channels.filter((c) => c.name).map((c) => (_jsxs(Box, { gap: 2, children: [_jsx(Text, { children: ' ' + (c.name ?? '').slice(0, 16).padEnd(16) }), _jsx(Text, { dimColor: true, children: (c.type ?? '').slice(0, 10).padEnd(10) }), _jsxs(Box, { width: 16, gap: 1, children: [_jsx(Text, { color: statusColor(c.status), children: statusDot(c.status) }), _jsx(Text, { color: statusColor(c.status), children: c.status })] }), _jsx(Text, { dimColor: true, children: String(c.messageCount ?? 0).padEnd(8) }), _jsx(Text, { dimColor: true, children: formatRelative(c.lastActivity) })] }, c.name)))] }))] })] }));
32
+ }
33
+ //# sourceMappingURL=ChannelList.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ConnectionStatus Component
3
+ *
4
+ * Small indicator shown in the session header area displaying the live
5
+ * server connection state, optional latency, and active provider.
6
+ *
7
+ * Visual states:
8
+ * ● Connected (green)
9
+ * ○ Reconnecting... (yellow, animated dot cycle)
10
+ * ✗ Disconnected (red)
11
+ */
12
+ import React from 'react';
13
+ export interface ConnectionStatusProps {
14
+ status: 'connected' | 'reconnecting' | 'disconnected';
15
+ latencyMs?: number;
16
+ provider?: string;
17
+ }
18
+ export declare const ConnectionStatus: React.FC<ConnectionStatusProps>;
19
+ //# sourceMappingURL=ConnectionStatus.d.ts.map
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ConnectionStatus Component
4
+ *
5
+ * Small indicator shown in the session header area displaying the live
6
+ * server connection state, optional latency, and active provider.
7
+ *
8
+ * Visual states:
9
+ * ● Connected (green)
10
+ * ○ Reconnecting... (yellow, animated dot cycle)
11
+ * ✗ Disconnected (red)
12
+ */
13
+ import { useState, useEffect } from 'react';
14
+ import { Box, Text } from 'ink';
15
+ // Spinner frames used while reconnecting
16
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
17
+ export const ConnectionStatus = ({ status, latencyMs, provider, }) => {
18
+ const [spinnerIdx, setSpinnerIdx] = useState(0);
19
+ // Animate the spinner only while reconnecting
20
+ useEffect(() => {
21
+ if (status !== 'reconnecting')
22
+ return;
23
+ const id = setInterval(() => {
24
+ setSpinnerIdx(prev => (prev + 1) % SPINNER_FRAMES.length);
25
+ }, 80);
26
+ return () => clearInterval(id);
27
+ }, [status]);
28
+ let indicator;
29
+ let color;
30
+ let label;
31
+ switch (status) {
32
+ case 'connected':
33
+ indicator = '●';
34
+ color = 'green';
35
+ label = 'Connected';
36
+ break;
37
+ case 'reconnecting':
38
+ indicator = SPINNER_FRAMES[spinnerIdx] ?? '○';
39
+ color = 'yellow';
40
+ label = 'Reconnecting...';
41
+ break;
42
+ case 'disconnected':
43
+ indicator = '✗';
44
+ color = 'red';
45
+ label = 'Disconnected';
46
+ break;
47
+ }
48
+ return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: color, children: indicator }), _jsx(Text, { color: color, children: label }), provider !== undefined && provider.length > 0 && (_jsxs(Text, { dimColor: true, children: ["via ", provider] })), latencyMs !== undefined && status === 'connected' && (_jsxs(Text, { dimColor: true, children: [latencyMs, "ms"] }))] }));
49
+ };
50
+ //# sourceMappingURL=ConnectionStatus.js.map