@mohanscodex/spectra-code 0.4.6 → 0.4.7

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 (284) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/agents/definitions.d.ts +2 -2
  3. package/dist/src/agents/definitions.d.ts.map +1 -1
  4. package/dist/src/agents/definitions.js +18 -18
  5. package/dist/src/agents/definitions.js.map +1 -1
  6. package/dist/src/agents/registry.d.ts +1 -1
  7. package/dist/src/agents/registry.d.ts.map +1 -1
  8. package/dist/src/agents/registry.js.map +1 -1
  9. package/dist/src/cli.js +117 -115
  10. package/dist/src/cli.js.map +1 -1
  11. package/dist/src/commands/agent.d.ts +1 -1
  12. package/dist/src/commands/agent.d.ts.map +1 -1
  13. package/dist/src/commands/agent.js +14 -14
  14. package/dist/src/commands/agent.js.map +1 -1
  15. package/dist/src/commands/db.d.ts +1 -1
  16. package/dist/src/commands/db.d.ts.map +1 -1
  17. package/dist/src/commands/db.js +11 -11
  18. package/dist/src/commands/db.js.map +1 -1
  19. package/dist/src/commands/doctor.d.ts.map +1 -1
  20. package/dist/src/commands/doctor.js +33 -30
  21. package/dist/src/commands/doctor.js.map +1 -1
  22. package/dist/src/commands/mcp.d.ts +1 -1
  23. package/dist/src/commands/mcp.d.ts.map +1 -1
  24. package/dist/src/commands/mcp.js +39 -39
  25. package/dist/src/commands/mcp.js.map +1 -1
  26. package/dist/src/commands/plugin.d.ts +1 -1
  27. package/dist/src/commands/plugin.d.ts.map +1 -1
  28. package/dist/src/commands/plugin.js +13 -13
  29. package/dist/src/commands/plugin.js.map +1 -1
  30. package/dist/src/commands/session.d.ts +1 -1
  31. package/dist/src/commands/session.d.ts.map +1 -1
  32. package/dist/src/commands/session.js +12 -12
  33. package/dist/src/commands/session.js.map +1 -1
  34. package/dist/src/index.d.ts +18 -18
  35. package/dist/src/index.d.ts.map +1 -1
  36. package/dist/src/index.js +16 -16
  37. package/dist/src/index.js.map +1 -1
  38. package/dist/src/integrations/acp/index.d.ts +1 -1
  39. package/dist/src/integrations/acp/index.js +1 -1
  40. package/dist/src/integrations/acp/server.d.ts.map +1 -1
  41. package/dist/src/integrations/acp/server.js +89 -79
  42. package/dist/src/integrations/acp/server.js.map +1 -1
  43. package/dist/src/integrations/custom-tools/index.d.ts +2 -2
  44. package/dist/src/integrations/custom-tools/index.js +1 -1
  45. package/dist/src/integrations/custom-tools/loader.d.ts +2 -2
  46. package/dist/src/integrations/custom-tools/loader.d.ts.map +1 -1
  47. package/dist/src/integrations/custom-tools/loader.js +19 -18
  48. package/dist/src/integrations/custom-tools/loader.js.map +1 -1
  49. package/dist/src/integrations/mcp/client.d.ts +5 -5
  50. package/dist/src/integrations/mcp/client.d.ts.map +1 -1
  51. package/dist/src/integrations/mcp/client.js +7 -7
  52. package/dist/src/integrations/mcp/client.js.map +1 -1
  53. package/dist/src/integrations/mcp/index.d.ts +2 -2
  54. package/dist/src/integrations/mcp/index.d.ts.map +1 -1
  55. package/dist/src/integrations/mcp/index.js +1 -1
  56. package/dist/src/integrations/mcp/index.js.map +1 -1
  57. package/dist/src/security/doom-loop.d.ts +1 -1
  58. package/dist/src/security/doom-loop.d.ts.map +1 -1
  59. package/dist/src/security/doom-loop.js +4 -4
  60. package/dist/src/security/doom-loop.js.map +1 -1
  61. package/dist/src/security/index.d.ts +10 -10
  62. package/dist/src/security/index.d.ts.map +1 -1
  63. package/dist/src/security/index.js +116 -69
  64. package/dist/src/security/index.js.map +1 -1
  65. package/dist/src/security/path-safety.d.ts +1 -1
  66. package/dist/src/security/path-safety.d.ts.map +1 -1
  67. package/dist/src/security/path-safety.js +19 -19
  68. package/dist/src/security/path-safety.js.map +1 -1
  69. package/dist/src/security/permissions.d.ts +1 -1
  70. package/dist/src/security/permissions.d.ts.map +1 -1
  71. package/dist/src/security/permissions.js +12 -10
  72. package/dist/src/security/permissions.js.map +1 -1
  73. package/dist/src/security/read-tracker.d.ts +2 -2
  74. package/dist/src/security/read-tracker.d.ts.map +1 -1
  75. package/dist/src/security/read-tracker.js +15 -13
  76. package/dist/src/security/read-tracker.js.map +1 -1
  77. package/dist/src/security/ssrf-guard.d.ts +1 -1
  78. package/dist/src/security/ssrf-guard.d.ts.map +1 -1
  79. package/dist/src/security/ssrf-guard.js +11 -11
  80. package/dist/src/security/ssrf-guard.js.map +1 -1
  81. package/dist/src/security/types.d.ts +4 -4
  82. package/dist/src/security/types.d.ts.map +1 -1
  83. package/dist/src/security/wildcard.d.ts.map +1 -1
  84. package/dist/src/security/wildcard.js +14 -16
  85. package/dist/src/security/wildcard.js.map +1 -1
  86. package/dist/src/services/auth-store.d.ts +3 -3
  87. package/dist/src/services/auth-store.d.ts.map +1 -1
  88. package/dist/src/services/auth-store.js +7 -7
  89. package/dist/src/services/auth-store.js.map +1 -1
  90. package/dist/src/services/config.d.ts +3 -3
  91. package/dist/src/services/config.d.ts.map +1 -1
  92. package/dist/src/services/config.js +17 -21
  93. package/dist/src/services/config.js.map +1 -1
  94. package/dist/src/services/context.d.ts.map +1 -1
  95. package/dist/src/services/context.js +5 -8
  96. package/dist/src/services/context.js.map +1 -1
  97. package/dist/src/services/custom-providers.d.ts +2 -2
  98. package/dist/src/services/custom-providers.d.ts.map +1 -1
  99. package/dist/src/services/custom-providers.js +108 -49
  100. package/dist/src/services/custom-providers.js.map +1 -1
  101. package/dist/src/services/session-store.d.ts +1 -1
  102. package/dist/src/services/session-store.d.ts.map +1 -1
  103. package/dist/src/services/session-store.js +32 -24
  104. package/dist/src/services/session-store.js.map +1 -1
  105. package/dist/src/services/snapshot-manager.d.ts.map +1 -1
  106. package/dist/src/services/snapshot-manager.js +14 -15
  107. package/dist/src/services/snapshot-manager.js.map +1 -1
  108. package/dist/src/tools/edit.d.ts +1 -1
  109. package/dist/src/tools/edit.js +18 -16
  110. package/dist/src/tools/edit.js.map +1 -1
  111. package/dist/src/tools/glob.d.ts +1 -1
  112. package/dist/src/tools/glob.d.ts.map +1 -1
  113. package/dist/src/tools/glob.js +20 -16
  114. package/dist/src/tools/glob.js.map +1 -1
  115. package/dist/src/tools/grep.d.ts +1 -1
  116. package/dist/src/tools/grep.d.ts.map +1 -1
  117. package/dist/src/tools/grep.js +18 -18
  118. package/dist/src/tools/grep.js.map +1 -1
  119. package/dist/src/tools/index.d.ts +4 -4
  120. package/dist/src/tools/index.d.ts.map +1 -1
  121. package/dist/src/tools/index.js +40 -32
  122. package/dist/src/tools/index.js.map +1 -1
  123. package/dist/src/tools/mcp-tool.d.ts +2 -2
  124. package/dist/src/tools/mcp-tool.d.ts.map +1 -1
  125. package/dist/src/tools/mcp-tool.js +28 -25
  126. package/dist/src/tools/mcp-tool.js.map +1 -1
  127. package/dist/src/tools/read.d.ts +1 -1
  128. package/dist/src/tools/read.d.ts.map +1 -1
  129. package/dist/src/tools/read.js +15 -13
  130. package/dist/src/tools/read.js.map +1 -1
  131. package/dist/src/tools/shell.d.ts +1 -1
  132. package/dist/src/tools/shell.d.ts.map +1 -1
  133. package/dist/src/tools/shell.js +71 -62
  134. package/dist/src/tools/shell.js.map +1 -1
  135. package/dist/src/tools/task.d.ts +1 -1
  136. package/dist/src/tools/task.js +22 -22
  137. package/dist/src/tools/task.js.map +1 -1
  138. package/dist/src/tools/types.d.ts +3 -3
  139. package/dist/src/tools/types.d.ts.map +1 -1
  140. package/dist/src/tools/utils.d.ts +1 -1
  141. package/dist/src/tools/utils.js +2 -2
  142. package/dist/src/tools/utils.js.map +1 -1
  143. package/dist/src/tools/web-fetch.d.ts +1 -1
  144. package/dist/src/tools/web-fetch.js +31 -31
  145. package/dist/src/tools/web-fetch.js.map +1 -1
  146. package/dist/src/tools/write.d.ts +1 -1
  147. package/dist/src/tools/write.js +9 -9
  148. package/dist/src/tools/write.js.map +1 -1
  149. package/dist/src/tui/app-constants.d.ts.map +1 -1
  150. package/dist/src/tui/app-constants.js +11 -2
  151. package/dist/src/tui/app-constants.js.map +1 -1
  152. package/dist/src/tui/app.d.ts +1 -1
  153. package/dist/src/tui/app.d.ts.map +1 -1
  154. package/dist/src/tui/app.js +293 -121
  155. package/dist/src/tui/app.js.map +1 -1
  156. package/dist/src/tui/commands.d.ts +14 -14
  157. package/dist/src/tui/commands.d.ts.map +1 -1
  158. package/dist/src/tui/commands.js +242 -49
  159. package/dist/src/tui/commands.js.map +1 -1
  160. package/dist/src/tui/components/chat-area.d.ts +2 -2
  161. package/dist/src/tui/components/chat-area.d.ts.map +1 -1
  162. package/dist/src/tui/components/chat-area.js +5 -5
  163. package/dist/src/tui/components/chat-area.js.map +1 -1
  164. package/dist/src/tui/components/command-palette.d.ts.map +1 -1
  165. package/dist/src/tui/components/command-palette.js +7 -5
  166. package/dist/src/tui/components/command-palette.js.map +1 -1
  167. package/dist/src/tui/components/message.d.ts +2 -2
  168. package/dist/src/tui/components/message.d.ts.map +1 -1
  169. package/dist/src/tui/components/message.js +63 -50
  170. package/dist/src/tui/components/message.js.map +1 -1
  171. package/dist/src/tui/components/slash-autocomplete.d.ts +2 -2
  172. package/dist/src/tui/components/slash-autocomplete.d.ts.map +1 -1
  173. package/dist/src/tui/components/slash-autocomplete.js +6 -8
  174. package/dist/src/tui/components/slash-autocomplete.js.map +1 -1
  175. package/dist/src/tui/components/toast.d.ts +2 -2
  176. package/dist/src/tui/components/toast.d.ts.map +1 -1
  177. package/dist/src/tui/components/toast.js +10 -5
  178. package/dist/src/tui/components/toast.js.map +1 -1
  179. package/dist/src/tui/hooks/use-agent.d.ts +3 -3
  180. package/dist/src/tui/hooks/use-agent.d.ts.map +1 -1
  181. package/dist/src/tui/hooks/use-agent.js +22 -29
  182. package/dist/src/tui/hooks/use-agent.js.map +1 -1
  183. package/dist/src/tui/hooks/use-app-keyboard.d.ts +3 -3
  184. package/dist/src/tui/hooks/use-app-keyboard.d.ts.map +1 -1
  185. package/dist/src/tui/hooks/use-app-keyboard.js +28 -29
  186. package/dist/src/tui/hooks/use-app-keyboard.js.map +1 -1
  187. package/dist/src/tui/hooks/use-chat-submit.d.ts +6 -6
  188. package/dist/src/tui/hooks/use-chat-submit.d.ts.map +1 -1
  189. package/dist/src/tui/hooks/use-chat-submit.js +115 -54
  190. package/dist/src/tui/hooks/use-chat-submit.js.map +1 -1
  191. package/dist/src/tui/hooks/use-permission-queue.d.ts +2 -2
  192. package/dist/src/tui/hooks/use-permission-queue.d.ts.map +1 -1
  193. package/dist/src/tui/hooks/use-permission-queue.js +1 -1
  194. package/dist/src/tui/hooks/use-permission-queue.js.map +1 -1
  195. package/dist/src/tui/hooks/use-revert.d.ts +4 -4
  196. package/dist/src/tui/hooks/use-revert.d.ts.map +1 -1
  197. package/dist/src/tui/hooks/use-revert.js +22 -13
  198. package/dist/src/tui/hooks/use-revert.js.map +1 -1
  199. package/dist/src/tui/index.d.ts.map +1 -1
  200. package/dist/src/tui/index.js +11 -11
  201. package/dist/src/tui/index.js.map +1 -1
  202. package/dist/src/tui/prompt-bar.d.ts +1 -1
  203. package/dist/src/tui/prompt-bar.d.ts.map +1 -1
  204. package/dist/src/tui/prompt-bar.js +14 -11
  205. package/dist/src/tui/prompt-bar.js.map +1 -1
  206. package/dist/src/tui/slash-commands.d.ts +2 -2
  207. package/dist/src/tui/slash-commands.d.ts.map +1 -1
  208. package/dist/src/tui/slash-commands.js +9 -9
  209. package/dist/src/tui/slash-commands.js.map +1 -1
  210. package/dist/src/tui/theme.d.ts +1 -1
  211. package/dist/src/tui/theme.d.ts.map +1 -1
  212. package/dist/src/tui/theme.js +46 -38
  213. package/dist/src/tui/theme.js.map +1 -1
  214. package/dist/src/tui/tips.d.ts.map +1 -1
  215. package/dist/src/tui/tips.js +14 -14
  216. package/dist/src/tui/tips.js.map +1 -1
  217. package/dist/src/tui/types.d.ts +5 -5
  218. package/dist/src/tui/types.d.ts.map +1 -1
  219. package/dist/src/tui/ui/about-dialog.d.ts.map +1 -1
  220. package/dist/src/tui/ui/about-dialog.js +5 -5
  221. package/dist/src/tui/ui/about-dialog.js.map +1 -1
  222. package/dist/src/tui/ui/agent-switcher.d.ts.map +1 -1
  223. package/dist/src/tui/ui/agent-switcher.js +16 -14
  224. package/dist/src/tui/ui/agent-switcher.js.map +1 -1
  225. package/dist/src/tui/ui/debug-dialog.d.ts +1 -1
  226. package/dist/src/tui/ui/debug-dialog.d.ts.map +1 -1
  227. package/dist/src/tui/ui/debug-dialog.js +26 -26
  228. package/dist/src/tui/ui/debug-dialog.js.map +1 -1
  229. package/dist/src/tui/ui/doctor-dialog.d.ts +2 -2
  230. package/dist/src/tui/ui/doctor-dialog.d.ts.map +1 -1
  231. package/dist/src/tui/ui/doctor-dialog.js +10 -8
  232. package/dist/src/tui/ui/doctor-dialog.js.map +1 -1
  233. package/dist/src/tui/ui/manage-providers-dialog.d.ts +1 -1
  234. package/dist/src/tui/ui/manage-providers-dialog.d.ts.map +1 -1
  235. package/dist/src/tui/ui/manage-providers-dialog.js +102 -86
  236. package/dist/src/tui/ui/manage-providers-dialog.js.map +1 -1
  237. package/dist/src/tui/ui/mcp-toggle-dialog.d.ts.map +1 -1
  238. package/dist/src/tui/ui/mcp-toggle-dialog.js +17 -14
  239. package/dist/src/tui/ui/mcp-toggle-dialog.js.map +1 -1
  240. package/dist/src/tui/ui/message-controls.d.ts +1 -1
  241. package/dist/src/tui/ui/message-controls.d.ts.map +1 -1
  242. package/dist/src/tui/ui/message-controls.js +40 -28
  243. package/dist/src/tui/ui/message-controls.js.map +1 -1
  244. package/dist/src/tui/ui/model-switcher.d.ts.map +1 -1
  245. package/dist/src/tui/ui/model-switcher.js +40 -25
  246. package/dist/src/tui/ui/model-switcher.js.map +1 -1
  247. package/dist/src/tui/ui/permission-dialog.d.ts +1 -1
  248. package/dist/src/tui/ui/permission-dialog.d.ts.map +1 -1
  249. package/dist/src/tui/ui/permission-dialog.js +11 -11
  250. package/dist/src/tui/ui/permission-dialog.js.map +1 -1
  251. package/dist/src/tui/ui/provider-dialog.d.ts.map +1 -1
  252. package/dist/src/tui/ui/provider-dialog.js +75 -64
  253. package/dist/src/tui/ui/provider-dialog.js.map +1 -1
  254. package/dist/src/tui/ui/session-list.d.ts +3 -3
  255. package/dist/src/tui/ui/session-list.d.ts.map +1 -1
  256. package/dist/src/tui/ui/session-list.js +44 -32
  257. package/dist/src/tui/ui/session-list.js.map +1 -1
  258. package/dist/src/tui/ui/thinking-effort-dialog.d.ts.map +1 -1
  259. package/dist/src/tui/ui/thinking-effort-dialog.js +19 -19
  260. package/dist/src/tui/ui/thinking-effort-dialog.js.map +1 -1
  261. package/dist/src/tui/utils/model-config.d.ts.map +1 -1
  262. package/dist/src/tui/utils/model-config.js +13 -13
  263. package/dist/src/tui/utils/model-config.js.map +1 -1
  264. package/dist/src/tui/utils/session-messages.d.ts +2 -2
  265. package/dist/src/tui/utils/session-messages.d.ts.map +1 -1
  266. package/dist/src/tui/utils/session-messages.js +35 -22
  267. package/dist/src/tui/utils/session-messages.js.map +1 -1
  268. package/dist/src/tui/utils/version.d.ts.map +1 -1
  269. package/dist/src/tui/utils/version.js +7 -7
  270. package/dist/src/tui/utils/version.js.map +1 -1
  271. package/dist/src/tui/utils.d.ts +2 -2
  272. package/dist/src/tui/utils.d.ts.map +1 -1
  273. package/dist/src/tui/utils.js +7 -7
  274. package/dist/src/tui/utils.js.map +1 -1
  275. package/dist/src/tui/variant-cycle.d.ts.map +1 -1
  276. package/dist/src/tui/variant-cycle.js +23 -23
  277. package/dist/src/tui/variant-cycle.js.map +1 -1
  278. package/dist/src/utils/paths.d.ts.map +1 -1
  279. package/dist/src/utils/paths.js +25 -25
  280. package/dist/src/utils/paths.js.map +1 -1
  281. package/dist/src/utils/platform.d.ts.map +1 -1
  282. package/dist/src/utils/platform.js +15 -17
  283. package/dist/src/utils/platform.js.map +1 -1
  284. package/package.json +3 -3
@@ -1,43 +1,43 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- import { useRef, useCallback, useEffect, useMemo, useState } from "react";
3
- import { useTerminalDimensions } from "@opentui/react";
4
- import { execSync } from "child_process";
5
- import { c, SPINNER } from "./theme.js";
6
- import { ChatArea } from "./components/chat-area.js";
7
- import { CommandPalette } from "./components/command-palette.js";
8
- import { PromptBar } from "./prompt-bar.js";
9
- import { Tips } from "./tips.js";
10
- import { titlecase } from "./utils.js";
11
- import { SessionStore } from "../services/session-store.js";
12
- import { SnapshotManager } from "../services/snapshot-manager.js";
13
- import { ProviderDialog } from "./ui/provider-dialog.js";
14
- import { SessionList } from "./ui/session-list.js";
15
- import { ModelSwitcher } from "./ui/model-switcher.js";
16
- import { ManageProvidersDialog } from "./ui/manage-providers-dialog.js";
17
- import { DoctorDialog } from "./ui/doctor-dialog.js";
18
- import { AboutDialog } from "./ui/about-dialog.js";
19
- import { AgentSwitcher } from "./ui/agent-switcher.js";
20
- import { ThinkingEffortDialog } from "./ui/thinking-effort-dialog.js";
21
- import { McpToggleDialog } from "./ui/mcp-toggle-dialog.js";
22
- import { DebugDialog } from "./ui/debug-dialog.js";
23
- import { MessageControls } from "./ui/message-controls.js";
24
- import { ToastContainer, showToast } from "./components/toast.js";
25
- import clipboard from "clipboardy";
26
- import { buildCmdItems, collectSlashNames } from "./commands.js";
27
- import { slashHead } from "./slash-commands.js";
28
- import { SlashAutocomplete } from "./components/slash-autocomplete.js";
29
- import { loadConfig } from "../services/config.js";
30
- import { registerAllCustomProviders } from "../services/custom-providers.js";
31
- import { PermissionDialog } from "./ui/permission-dialog.js";
32
- import { PLACEHOLDERS } from "./app-constants.js";
33
- import { loadSavedConfig, saveModelConfig, fmtCtx, lookupContextWindow } from "./utils/model-config.js";
34
- import { sdkMessagesToChatMessages } from "./utils/session-messages.js";
35
- import { usePermissionQueue } from "./hooks/use-permission-queue.js";
36
- import { useRevert } from "./hooks/use-revert.js";
37
- import { useAgent } from "./hooks/use-agent.js";
38
- import { useChatSubmit } from "./hooks/use-chat-submit.js";
39
- import { useAppKeyboard } from "./hooks/use-app-keyboard.js";
40
- import { cycleEffort } from "./variant-cycle.js";
2
+ import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
3
+ import { useTerminalDimensions } from '@opentui/react';
4
+ import { execSync } from 'child_process';
5
+ import { c, SPINNER } from './theme.js';
6
+ import { ChatArea } from './components/chat-area.js';
7
+ import { CommandPalette } from './components/command-palette.js';
8
+ import { PromptBar } from './prompt-bar.js';
9
+ import { Tips } from './tips.js';
10
+ import { titlecase } from './utils.js';
11
+ import { SessionStore } from '../services/session-store.js';
12
+ import { SnapshotManager } from '../services/snapshot-manager.js';
13
+ import { ProviderDialog } from './ui/provider-dialog.js';
14
+ import { SessionList } from './ui/session-list.js';
15
+ import { ModelSwitcher } from './ui/model-switcher.js';
16
+ import { ManageProvidersDialog } from './ui/manage-providers-dialog.js';
17
+ import { DoctorDialog } from './ui/doctor-dialog.js';
18
+ import { AboutDialog } from './ui/about-dialog.js';
19
+ import { AgentSwitcher } from './ui/agent-switcher.js';
20
+ import { ThinkingEffortDialog } from './ui/thinking-effort-dialog.js';
21
+ import { McpToggleDialog } from './ui/mcp-toggle-dialog.js';
22
+ import { DebugDialog } from './ui/debug-dialog.js';
23
+ import { MessageControls } from './ui/message-controls.js';
24
+ import { ToastContainer, showToast } from './components/toast.js';
25
+ import clipboard from 'clipboardy';
26
+ import { buildCmdItems, collectSlashNames } from './commands.js';
27
+ import { slashHead } from './slash-commands.js';
28
+ import { SlashAutocomplete } from './components/slash-autocomplete.js';
29
+ import { loadConfig } from '../services/config.js';
30
+ import { registerAllCustomProviders } from '../services/custom-providers.js';
31
+ import { PermissionDialog } from './ui/permission-dialog.js';
32
+ import { PLACEHOLDERS } from './app-constants.js';
33
+ import { loadSavedConfig, saveModelConfig, fmtCtx, lookupContextWindow } from './utils/model-config.js';
34
+ import { sdkMessagesToChatMessages } from './utils/session-messages.js';
35
+ import { usePermissionQueue } from './hooks/use-permission-queue.js';
36
+ import { useRevert } from './hooks/use-revert.js';
37
+ import { useAgent } from './hooks/use-agent.js';
38
+ import { useChatSubmit } from './hooks/use-chat-submit.js';
39
+ import { useAppKeyboard } from './hooks/use-app-keyboard.js';
40
+ import { cycleEffort } from './variant-cycle.js';
41
41
  export function App({ renderer }) {
42
42
  const { width: termWidth, height: termHeight } = useTerminalDimensions();
43
43
  // --- State ---
@@ -51,13 +51,13 @@ export function App({ renderer }) {
51
51
  const [selectedModel, setSelectedModel] = useState(savedConfig.model);
52
52
  const [selectedProvider, setSelectedProvider] = useState(savedConfig.provider);
53
53
  const [thinkingEffort, setThinkingEffort] = useState(undefined);
54
- const [route, setRoute] = useState("home");
54
+ const [route, setRoute] = useState('home');
55
55
  const [messages, setMessages] = useState([]);
56
56
  const [isLoading, setIsLoading] = useState(false);
57
- const [status, setStatus] = useState("Ready");
57
+ const [status, setStatus] = useState('Ready');
58
58
  const [spinnerFrame, setSpinnerFrame] = useState(0);
59
59
  const [showCmd, setShowCmd] = useState(false);
60
- const [cmdFilter, setCmdFilter] = useState("");
60
+ const [cmdFilter, setCmdFilter] = useState('');
61
61
  const [cmdSelected, setCmdSelected] = useState(0);
62
62
  const [elapsedMs, setElapsedMs] = useState(null);
63
63
  const [tokPerSec, setTokPerSec] = useState(null);
@@ -65,7 +65,7 @@ export function App({ renderer }) {
65
65
  const [showThinking, setShowThinking] = useState(true);
66
66
  const [showToolCalls, setShowToolCalls] = useState(true);
67
67
  const [copiedMsg, setCopiedMsg] = useState(false);
68
- const [selectedAgent, setSelectedAgent] = useState("build");
68
+ const [selectedAgent, setSelectedAgent] = useState('build');
69
69
  const [submitKey, setSubmitKey] = useState(0);
70
70
  const [dialogStep, setDialogStep] = useState(null);
71
71
  const [placeholderIdx, setPlaceholderIdx] = useState(0);
@@ -76,7 +76,7 @@ export function App({ renderer }) {
76
76
  const [interruptKey, setInterruptKey] = useState(0);
77
77
  const [msgControls, setMsgControls] = useState(null);
78
78
  const [revertPoint, setRevertPoint] = useState(null);
79
- const [draftText, setDraftText] = useState("");
79
+ const [draftText, setDraftText] = useState('');
80
80
  const [slashSelected, setSlashSelected] = useState(0);
81
81
  const [promptPosition, setPromptPosition] = useState({ top: 0, left: 0, width: 0 });
82
82
  // --- Refs ---
@@ -98,10 +98,12 @@ export function App({ renderer }) {
98
98
  const mcpCount = 0;
99
99
  const customProviderCount = Object.keys(customProviders).length;
100
100
  const cwdLabel = useMemo(() => {
101
- const home = process.env.HOME || process.env.USERPROFILE || "";
102
- const dir = process.cwd().replace(home, "~");
101
+ const home = process.env.HOME || process.env.USERPROFILE || '';
102
+ const dir = process.cwd().replace(home, '~');
103
103
  try {
104
- const branch = execSync("git rev-parse --abbrev-ref HEAD 2>/dev/null", { encoding: "utf-8", timeout: 2000 }).toString().trim();
104
+ const branch = execSync('git rev-parse --abbrev-ref HEAD 2>/dev/null', { encoding: 'utf-8', timeout: 2000 })
105
+ .toString()
106
+ .trim();
105
107
  if (branch)
106
108
  return `${dir}:${branch}`;
107
109
  }
@@ -118,7 +120,10 @@ export function App({ renderer }) {
118
120
  return;
119
121
  const id = setInterval(() => setSpinnerFrame((f) => (f + 1) % SPINNER.length), 80);
120
122
  renderer.requestLive();
121
- return () => { clearInterval(id); renderer.dropLive(); };
123
+ return () => {
124
+ clearInterval(id);
125
+ renderer.dropLive();
126
+ };
122
127
  }, [isLoading, renderer]);
123
128
  useEffect(() => {
124
129
  const handler = (selection) => {
@@ -134,8 +139,10 @@ export function App({ renderer }) {
134
139
  catch { }
135
140
  }, 2000);
136
141
  };
137
- renderer.on("selection", handler);
138
- return () => { renderer.off?.("selection", handler); };
142
+ renderer.on('selection', handler);
143
+ return () => {
144
+ renderer.off?.('selection', handler);
145
+ };
139
146
  }, [renderer]);
140
147
  // --- Stable callbacks ---
141
148
  const addMessage = useCallback((msg) => setMessages((p) => [...p, msg]), []);
@@ -143,30 +150,59 @@ export function App({ renderer }) {
143
150
  // --- Hooks (order matters for ref lifecycle) ---
144
151
  const securityRef = useRef(null);
145
152
  const { permissionRequest, enqueuePermission, resolvePermission } = usePermissionQueue(securityRef);
146
- const { agentRef, loadedSessionMessages, getOrCreateAgent, resetAgentForModelSwitch, } = useAgent({ securityRef, securityConfig, enqueuePermission });
147
- const { revertedMessagesRef, revertDraftRef, runRevert, runRedo, runRollbackFiles, discardRevert, } = useRevert({
148
- sessionStore, sessionId, agentRef, loadedSessionMessages,
149
- setMessages, setRevertPoint, setHistoryIdx, setNavKey, snapshotManager,
153
+ const { agentRef, loadedSessionMessages, getOrCreateAgent, resetAgentForModelSwitch } = useAgent({
154
+ securityRef,
155
+ securityConfig,
156
+ enqueuePermission,
157
+ });
158
+ const { revertedMessagesRef, revertDraftRef, runRevert, runRedo, runRollbackFiles, discardRevert } = useRevert({
159
+ sessionStore,
160
+ sessionId,
161
+ agentRef,
162
+ loadedSessionMessages,
163
+ setMessages,
164
+ setRevertPoint,
165
+ setHistoryIdx,
166
+ setNavKey,
167
+ snapshotManager,
150
168
  });
151
169
  const handleCycleVariant = useCallback(() => {
152
170
  if (!provider) {
153
- showToast("No provider configured", "warn");
171
+ showToast('No provider configured', 'warn');
154
172
  return;
155
173
  }
156
174
  const nextEffort = cycleEffort(provider, thinkingEffort);
157
175
  if (!nextEffort) {
158
- showToast("No variants available", "info");
176
+ showToast('No variants available', 'info');
159
177
  return;
160
178
  }
161
179
  setThinkingEffort(nextEffort);
162
180
  agentRef.current = null;
163
- showToast(nextEffort === "none" ? "Thinking: off" : `Thinking: ${nextEffort}`, "info");
181
+ showToast(nextEffort === 'none' ? 'Thinking: off' : `Thinking: ${nextEffort}`, 'info');
164
182
  }, [provider, thinkingEffort, agentRef]);
165
183
  const cmdItems = useMemo(() => buildCmdItems({
166
- renderer, sessionStore: sessionStore.current, sessionIdRef: sessionId,
167
- hasModel, selectedModel, provider, mcpCount, customProviderCount, messagesLength: messages.length,
168
- showThinking, showToolCalls,
169
- setRoute, setMessages, setStatus, setElapsedMs, setTokPerSec, setTokenUsage, setShowThinking, setShowToolCalls, setHomeKey, setNavKey, setDialogStep,
184
+ renderer,
185
+ sessionStore: sessionStore.current,
186
+ sessionIdRef: sessionId,
187
+ hasModel,
188
+ selectedModel,
189
+ provider,
190
+ mcpCount,
191
+ customProviderCount,
192
+ messagesLength: messages.length,
193
+ showThinking,
194
+ showToolCalls,
195
+ setRoute,
196
+ setMessages,
197
+ setStatus,
198
+ setElapsedMs,
199
+ setTokPerSec,
200
+ setTokenUsage,
201
+ setShowThinking,
202
+ setShowToolCalls,
203
+ setHomeKey,
204
+ setNavKey,
205
+ setDialogStep,
170
206
  onCycleVariant: handleCycleVariant,
171
207
  currentEffort: thinkingEffort,
172
208
  selectedAgent,
@@ -174,23 +210,81 @@ export function App({ renderer }) {
174
210
  securityRef.current?.getReadTracker().reset();
175
211
  securityRef.current?.getDoomLoop().reset();
176
212
  },
177
- }), [renderer, hasModel, selectedModel, provider, mcpCount, customProviderCount, messages.length, showThinking, showToolCalls, handleCycleVariant, thinkingEffort, selectedAgent, sessionStore, sessionId, setRoute, setMessages, setStatus, setElapsedMs, setTokPerSec, setTokenUsage, setShowThinking, setShowToolCalls, setHomeKey, setNavKey, setDialogStep, securityRef]);
213
+ }), [
214
+ renderer,
215
+ hasModel,
216
+ selectedModel,
217
+ provider,
218
+ mcpCount,
219
+ customProviderCount,
220
+ messages.length,
221
+ showThinking,
222
+ showToolCalls,
223
+ handleCycleVariant,
224
+ thinkingEffort,
225
+ selectedAgent,
226
+ sessionStore,
227
+ sessionId,
228
+ setRoute,
229
+ setMessages,
230
+ setStatus,
231
+ setElapsedMs,
232
+ setTokPerSec,
233
+ setTokenUsage,
234
+ setShowThinking,
235
+ setShowToolCalls,
236
+ setHomeKey,
237
+ setNavKey,
238
+ setDialogStep,
239
+ securityRef,
240
+ ]);
178
241
  const slashNames = useMemo(() => collectSlashNames(cmdItems), [cmdItems]);
179
- const { handleSubmit, updateLastAssistantMeta, } = useChatSubmit({
180
- sessionStore, sessionId, agentRef, securityRef, loadedSessionMessages,
181
- snapshotManager, lastAgentRef: useRef(null), isStreamingRef, currentTurnStartRef,
182
- currentTurnMsgIdRef, revertPoint, getOrCreateAgent,
183
- selectedModel, provider, selectedAgent, customProviders, thinkingEffort,
184
- cmdItems, slashNames, addMessage, updateMessage, setMessages,
185
- setIsLoading, setStatus, setRoute, setElapsedMs, setTokPerSec,
186
- setTokenUsage, setDraftText, setSlashSelected, setSubmitKey,
187
- setPromptHistory, setHistoryIdx, setInterruptKey, setRevertPoint,
242
+ const { handleSubmit, updateLastAssistantMeta } = useChatSubmit({
243
+ sessionStore,
244
+ sessionId,
245
+ agentRef,
246
+ securityRef,
247
+ loadedSessionMessages,
248
+ snapshotManager,
249
+ lastAgentRef: useRef(null),
250
+ isStreamingRef,
251
+ currentTurnStartRef,
252
+ currentTurnMsgIdRef,
253
+ revertPoint,
254
+ getOrCreateAgent,
255
+ selectedModel,
256
+ provider,
257
+ selectedAgent,
258
+ customProviders,
259
+ thinkingEffort,
260
+ cmdItems,
261
+ slashNames,
262
+ addMessage,
263
+ updateMessage,
264
+ setMessages,
265
+ setIsLoading,
266
+ setStatus,
267
+ setRoute,
268
+ setElapsedMs,
269
+ setTokPerSec,
270
+ setTokenUsage,
271
+ setDraftText,
272
+ setSlashSelected,
273
+ setSubmitKey,
274
+ setPromptHistory,
275
+ setHistoryIdx,
276
+ setInterruptKey,
277
+ setRevertPoint,
188
278
  discardRevert,
189
279
  });
190
280
  // --- cmdFiltered + slash ---
191
281
  const cmdFiltered = useMemo(() => {
192
282
  const q = cmdFilter.toLowerCase();
193
- return !q ? cmdItems : cmdItems.filter((i) => i.label.toLowerCase().includes(q) || i.desc.toLowerCase().includes(q) || (i.cat && i.cat.toLowerCase().includes(q)));
283
+ return !q
284
+ ? cmdItems
285
+ : cmdItems.filter((i) => i.label.toLowerCase().includes(q) ||
286
+ i.desc.toLowerCase().includes(q) ||
287
+ (i.cat && i.cat.toLowerCase().includes(q)));
194
288
  }, [cmdItems, cmdFilter]);
195
289
  const slashFiltered = useMemo(() => {
196
290
  const head = slashHead(draftText);
@@ -208,54 +302,98 @@ export function App({ renderer }) {
208
302
  });
209
303
  }, [cmdItems, draftText]);
210
304
  const slashActive = useMemo(() => slashHead(draftText) !== undefined, [draftText]);
211
- useEffect(() => { setSlashSelected(0); }, [draftText]);
212
- useEffect(() => { if (cmdSelected >= cmdFiltered.length && cmdFiltered.length > 0)
213
- setCmdSelected(cmdFiltered.length - 1); }, [cmdSelected, cmdFiltered.length]);
214
- const execCmd = useCallback((item) => { item.action(); setShowCmd(false); }, [setShowCmd]);
305
+ useEffect(() => {
306
+ setSlashSelected(0);
307
+ }, [draftText]);
308
+ useEffect(() => {
309
+ if (cmdSelected >= cmdFiltered.length && cmdFiltered.length > 0)
310
+ setCmdSelected(cmdFiltered.length - 1);
311
+ }, [cmdSelected, cmdFiltered.length]);
312
+ const execCmd = useCallback((item) => {
313
+ item.action();
314
+ setShowCmd(false);
315
+ }, [setShowCmd]);
215
316
  // --- Keyboard ---
216
317
  useAppKeyboard({
217
- renderer, isStreamingRef, currentTurnStartRef, currentTurnMsgIdRef,
218
- revertPoint, revertedMessagesRef, runRedo, runRollbackFiles,
219
- dialogStep, msgControls, permissionRequest, dialogKeyHandler,
220
- showCmd, cmdFilter, cmdSelected, cmdFiltered,
221
- draftText, slashActive, slashFiltered, slashSelected,
222
- promptHistory, historyIdx, interruptKey,
223
- selectedAgent, thinkingEffort, provider,
224
- agentRef, securityRef, promptTextareaRef,
225
- setShowCmd, setCmdFilter, setCmdSelected,
226
- setDraftText, setSlashSelected, setHistoryIdx, setNavKey,
227
- setInterruptKey, setSelectedAgent, setMessages, setStatus,
228
- setThinkingEffort, updateMessage, updateLastAssistantMeta,
229
- execCmd, handleCycleVariant,
318
+ renderer,
319
+ isStreamingRef,
320
+ currentTurnStartRef,
321
+ currentTurnMsgIdRef,
322
+ revertPoint,
323
+ revertedMessagesRef,
324
+ runRedo,
325
+ runRollbackFiles,
326
+ dialogStep,
327
+ msgControls,
328
+ permissionRequest,
329
+ dialogKeyHandler,
330
+ showCmd,
331
+ cmdFilter,
332
+ cmdSelected,
333
+ cmdFiltered,
334
+ draftText,
335
+ slashActive,
336
+ slashFiltered,
337
+ slashSelected,
338
+ promptHistory,
339
+ historyIdx,
340
+ interruptKey,
341
+ selectedAgent,
342
+ thinkingEffort,
343
+ provider,
344
+ agentRef,
345
+ securityRef,
346
+ promptTextareaRef,
347
+ setShowCmd,
348
+ setCmdFilter,
349
+ setCmdSelected,
350
+ setDraftText,
351
+ setSlashSelected,
352
+ setHistoryIdx,
353
+ setNavKey,
354
+ setInterruptKey,
355
+ setSelectedAgent,
356
+ setMessages,
357
+ setStatus,
358
+ setThinkingEffort,
359
+ updateMessage,
360
+ updateLastAssistantMeta,
361
+ execCmd,
362
+ handleCycleVariant,
230
363
  });
231
364
  // --- JSX ---
232
- return (_jsxs("box", { flexDirection: "column", height: termHeight, backgroundColor: c.bg, children: [route === "home" ? (_jsxs("box", { flexDirection: "column", flexGrow: 1, children: [_jsx("box", { flexGrow: 1 }), _jsxs("box", { flexDirection: "column", alignItems: "center", flexShrink: 0, children: [_jsx("ascii-font", { text: "SPECTRA", font: "block", color: c.accent }), _jsx("box", { height: 1 }), _jsx(PromptBar, { isLoading: isLoading, spinnerFrame: spinnerFrame, inputKey: `h-${submitKey}-${navKey}`, placeholder: `Ask anything... "${PLACEHOLDERS[placeholderIdx]}"`, onSubmit: handleSubmit, hasModel: hasModel, agent: selectedAgent, model: selectedModel || "", provider: provider || "", thinkingEffort: thinkingEffort, initialValue: revertDraftRef.current || (historyIdx >= 0 ? promptHistory[historyIdx] : ""), width: Math.min(68, termWidth - 8), focused: !dialogStep && !showCmd && !msgControls && !permissionRequest, onTextChange: (t) => setDraftText(t), onGetTextarea: (r) => { promptTextareaRef.current = r; }, onPositionChange: setPromptPosition }), _jsx("box", { height: 1 }), _jsx("box", { flexDirection: "row", justifyContent: "flex-end", width: Math.min(68, termWidth - 8), children: _jsxs("box", { flexDirection: "row", gap: 2, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "tab" }), _jsx("text", { fg: c.dim, children: " agent" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+t" }), _jsx("text", { fg: c.dim, children: " effort" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+p" }), _jsx("text", { fg: c.dim, children: " commands" })] })] }) }), _jsx("box", { height: 1 }), _jsx("box", { flexDirection: "row", gap: 4, alignItems: "center", children: [
233
- { icon: "◈", label: `${sessionStore.current.list().length} sessions` },
234
- { icon: "", label: "3 agents" },
235
- { icon: "◆", label: "7 tools" },
236
- { icon: "⬢", label: `${mcpCount} MCP` },
237
- ].map((s) => (_jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", children: [_jsx("text", { fg: c.accent, children: s.icon }), _jsx("text", { fg: c.dim, children: s.label })] }, s.label))) }), _jsx(Tips, {})] }), _jsx("box", { flexGrow: 1 }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, height: 1, marginBottom: 1, children: [_jsx("box", { flexDirection: "row", gap: 4, children: _jsx("text", { fg: c.dim, overflow: "hidden", wrapMode: "none", children: cwdLabel }) }), _jsx("text", { fg: c.dim, flexShrink: 0, children: "Spectra Code" })] })] }, `home-${homeKey}`)) : (_jsxs("box", { flexDirection: "column", height: termHeight, paddingLeft: 2, paddingRight: 2, children: [revertPoint && (_jsxs("box", { flexDirection: "column", alignItems: "center", paddingY: 1, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.warn, children: "Messages reverted. " }), _jsx("text", { fg: c.accent, children: "Ctrl+Y" }), _jsx("text", { fg: c.dim, children: " to restore" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.dim, children: "Files unchanged. " }), _jsx("text", { fg: c.accent, children: "Ctrl+Shift+Y" }), _jsx("text", { fg: c.dim, children: " to rollback files" })] })] })), _jsx("box", { flexDirection: "column", flexGrow: 1, paddingBottom: 1, children: _jsx(ChatArea, { messages: messages, showThinking: showThinking, showToolCalls: showToolCalls, revertPoint: revertPoint, onMessageClick: (msg) => setMsgControls(msg) }) }), _jsxs("box", { flexShrink: 0, children: [_jsx(PromptBar, { isLoading: isLoading, spinnerFrame: spinnerFrame, inputKey: `c-${submitKey}-${navKey}`, placeholder: "Reply...", onSubmit: handleSubmit, hasModel: hasModel, agent: selectedAgent, model: selectedModel || "", provider: provider || "", thinkingEffort: thinkingEffort, initialValue: revertDraftRef.current || (historyIdx >= 0 ? promptHistory[historyIdx] : ""), elapsedMs: elapsedMs, tokenUsage: tokenUsage, width: termWidth - 4, focused: !dialogStep && !showCmd && !msgControls && !permissionRequest, onTextChange: (t) => setDraftText(t), onGetTextarea: (r) => { promptTextareaRef.current = r; }, onPositionChange: setPromptPosition }), _jsx("box", { height: 1 }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", alignItems: "center", height: 1, paddingLeft: 3, paddingRight: 1, children: [_jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", overflow: "hidden", children: [isLoading ? (_jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", children: [_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.warn, children: SPINNER[spinnerFrame] }), _jsx("text", { fg: c.dim, children: "Streaming..." })] }), _jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.accent, children: "esc" }), _jsx("text", { fg: c.dim, children: "interrupt" })] })] })) : (_jsx("text", { fg: c.dim, children: "Ready" })), (tokenUsage.input + tokenUsage.output) > 0 && (() => {
238
- const used = tokenUsage.input + tokenUsage.output;
239
- const cw = lookupContextWindow(selectedModel || "", provider);
240
- const pct = cw ? Math.round((used / cw) * 100) : null;
241
- return (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.subtext, children: fmtCtx(used) }), pct !== null && _jsxs("text", { fg: pct > 80 ? c.warn : c.dim, children: ["(", pct, "%)"] })] }));
242
- })()] }), _jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "tab" }), _jsx("text", { fg: c.dim, children: " agent" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+t" }), _jsx("text", { fg: c.dim, children: " effort" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+p" }), _jsx("text", { fg: c.dim, children: " commands" })] })] })] })] })] })), showCmd && _jsx(CommandPalette, { filter: cmdFilter, selected: cmdSelected, items: cmdFiltered, termWidth: termWidth, termHeight: termHeight }), slashActive && slashFiltered.length > 0 && (_jsx(SlashAutocomplete, { query: slashHead(draftText)?.name || "", selected: slashSelected, items: slashFiltered, termWidth: termWidth, termHeight: termHeight, route: route, promptTop: promptPosition.top, promptLeft: promptPosition.left, promptWidth: promptPosition.width })), dialogStep?.type === "provider" && (_jsx(ProviderDialog, { termWidth: termWidth, termHeight: termHeight, keyHandlerRef: dialogKeyHandler, onModelSelected: (modelId, providerId) => {
365
+ return (_jsxs("box", { flexDirection: "column", height: termHeight, backgroundColor: c.bg, children: [route === 'home' ? (_jsxs("box", { flexDirection: "column", flexGrow: 1, children: [_jsx("box", { flexGrow: 1 }), _jsxs("box", { flexDirection: "column", alignItems: "center", flexShrink: 0, children: [_jsx("ascii-font", { text: "SPECTRA", font: "block", color: c.accent }), _jsx("box", { height: 1 }), _jsx(PromptBar, { isLoading: isLoading, spinnerFrame: spinnerFrame, inputKey: `h-${submitKey}-${navKey}`, placeholder: `Ask anything... "${PLACEHOLDERS[placeholderIdx]}"`, onSubmit: handleSubmit, hasModel: hasModel, agent: selectedAgent, model: selectedModel || '', provider: provider || '', thinkingEffort: thinkingEffort, initialValue: revertDraftRef.current || (historyIdx >= 0 ? promptHistory[historyIdx] : ''), width: Math.min(68, termWidth - 8), focused: !dialogStep && !showCmd && !msgControls && !permissionRequest, onTextChange: (t) => setDraftText(t), onGetTextarea: (r) => {
366
+ promptTextareaRef.current = r;
367
+ }, onPositionChange: setPromptPosition }), _jsx("box", { height: 1 }), _jsx("box", { flexDirection: "row", justifyContent: "flex-end", width: Math.min(68, termWidth - 8), children: _jsxs("box", { flexDirection: "row", gap: 2, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "tab" }), _jsx("text", { fg: c.dim, children: " agent" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+t" }), _jsx("text", { fg: c.dim, children: " effort" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+p" }), _jsx("text", { fg: c.dim, children: " commands" })] })] }) }), _jsx("box", { height: 1 }), _jsx("box", { flexDirection: "row", gap: 4, alignItems: "center", children: [
368
+ { icon: '◈', label: `${sessionStore.current.list().length} sessions` },
369
+ { icon: '◉', label: '3 agents' },
370
+ { icon: '◆', label: '7 tools' },
371
+ { icon: '⬢', label: `${mcpCount} MCP` },
372
+ ].map((s) => (_jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", children: [_jsx("text", { fg: c.accent, children: s.icon }), _jsx("text", { fg: c.dim, children: s.label })] }, s.label))) }), _jsx(Tips, {})] }), _jsx("box", { flexGrow: 1 }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, height: 1, marginBottom: 1, children: [_jsx("box", { flexDirection: "row", gap: 4, children: _jsx("text", { fg: c.dim, overflow: "hidden", wrapMode: "none", children: cwdLabel }) }), _jsx("text", { fg: c.dim, flexShrink: 0, children: "Spectra Code" })] })] }, `home-${homeKey}`)) : (_jsxs("box", { flexDirection: "column", height: termHeight, paddingLeft: 2, paddingRight: 2, children: [revertPoint && (_jsxs("box", { flexDirection: "column", alignItems: "center", paddingY: 1, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.warn, children: "Messages reverted. " }), _jsx("text", { fg: c.accent, children: "Ctrl+Y" }), _jsx("text", { fg: c.dim, children: " to restore" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.dim, children: "Files unchanged. " }), _jsx("text", { fg: c.accent, children: "Ctrl+Shift+Y" }), _jsx("text", { fg: c.dim, children: " to rollback files" })] })] })), _jsx("box", { flexDirection: "column", flexGrow: 1, paddingBottom: 1, children: _jsx(ChatArea, { messages: messages, showThinking: showThinking, showToolCalls: showToolCalls, revertPoint: revertPoint, onMessageClick: (msg) => setMsgControls(msg) }) }), _jsxs("box", { flexShrink: 0, children: [_jsx(PromptBar, { isLoading: isLoading, spinnerFrame: spinnerFrame, inputKey: `c-${submitKey}-${navKey}`, placeholder: "Reply...", onSubmit: handleSubmit, hasModel: hasModel, agent: selectedAgent, model: selectedModel || '', provider: provider || '', thinkingEffort: thinkingEffort, initialValue: revertDraftRef.current || (historyIdx >= 0 ? promptHistory[historyIdx] : ''), elapsedMs: elapsedMs, tokenUsage: tokenUsage, width: termWidth - 4, focused: !dialogStep && !showCmd && !msgControls && !permissionRequest, onTextChange: (t) => setDraftText(t), onGetTextarea: (r) => {
373
+ promptTextareaRef.current = r;
374
+ }, onPositionChange: setPromptPosition }), _jsx("box", { height: 1 }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", alignItems: "center", height: 1, paddingLeft: 3, paddingRight: 1, children: [_jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", overflow: "hidden", children: [isLoading ? (_jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", children: [_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.warn, children: SPINNER[spinnerFrame] }), _jsx("text", { fg: c.dim, children: "Streaming..." })] }), _jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.accent, children: "esc" }), _jsx("text", { fg: c.dim, children: "interrupt" })] })] })) : (_jsx("text", { fg: c.dim, children: "Ready" })), tokenUsage.input + tokenUsage.output > 0 &&
375
+ (() => {
376
+ const used = tokenUsage.input + tokenUsage.output;
377
+ const cw = lookupContextWindow(selectedModel || '', provider);
378
+ const pct = cw ? Math.round((used / cw) * 100) : null;
379
+ return (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: c.subtext, children: fmtCtx(used) }), pct !== null && _jsxs("text", { fg: pct > 80 ? c.warn : c.dim, children: ["(", pct, "%)"] })] }));
380
+ })()] }), _jsxs("box", { flexDirection: "row", gap: 2, alignItems: "center", children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "tab" }), _jsx("text", { fg: c.dim, children: " agent" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+t" }), _jsx("text", { fg: c.dim, children: " effort" })] }), _jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: c.text, children: "ctrl+p" }), _jsx("text", { fg: c.dim, children: " commands" })] })] })] })] })] })), showCmd && (_jsx(CommandPalette, { filter: cmdFilter, selected: cmdSelected, items: cmdFiltered, termWidth: termWidth, termHeight: termHeight })), slashActive && slashFiltered.length > 0 && (_jsx(SlashAutocomplete, { query: slashHead(draftText)?.name || '', selected: slashSelected, items: slashFiltered, termWidth: termWidth, termHeight: termHeight, route: route, promptTop: promptPosition.top, promptLeft: promptPosition.left, promptWidth: promptPosition.width })), dialogStep?.type === 'provider' && (_jsx(ProviderDialog, { termWidth: termWidth, termHeight: termHeight, keyHandlerRef: dialogKeyHandler, onModelSelected: (modelId, providerId) => {
243
381
  resetAgentForModelSwitch();
244
382
  setSelectedModel(modelId);
245
383
  setSelectedProvider(providerId);
246
384
  setDialogStep(null);
247
385
  saveModelConfig(modelId, providerId);
248
- showToast(`Model set`, "success");
249
- }, onClose: () => setDialogStep(null) })), dialogStep?.type === "session-list" && (_jsx(SessionList, { store: sessionStore.current, termWidth: termWidth, termHeight: termHeight, mode: dialogStep.mode || "load", onLoad: (data) => {
386
+ showToast(`Model set`, 'success');
387
+ }, onClose: () => setDialogStep(null) })), dialogStep?.type === 'session-list' && (_jsx(SessionList, { store: sessionStore.current, termWidth: termWidth, termHeight: termHeight, mode: dialogStep.mode || 'load', onLoad: (data) => {
250
388
  const { messages: loadedMsgs, tokenUsage: tu } = sdkMessagesToChatMessages(data);
251
389
  setTokenUsage(tu);
252
390
  setMessages(() => loadedMsgs);
253
391
  sessionId.current = data.id;
254
392
  setSelectedModel(data.model);
255
- setSelectedProvider(data.provider || data.model.split("/")[0]);
393
+ setSelectedProvider(data.provider || data.model.split('/')[0]);
256
394
  setSelectedAgent(data.agent);
257
395
  setThinkingEffort(data.thinkingEffort || undefined);
258
- setRoute("chat");
396
+ setRoute('chat');
259
397
  setDialogStep(null);
260
398
  loadedSessionMessages.current = data.messages;
261
399
  if (agentRef.current) {
@@ -264,47 +402,71 @@ export function App({ renderer }) {
264
402
  }
265
403
  securityRef.current?.getReadTracker().reset();
266
404
  securityRef.current?.getDoomLoop().reset();
267
- showToast(`Loaded: ${data.title.slice(0, 40)}`, "info");
405
+ showToast(`Loaded: ${data.title.slice(0, 40)}`, 'info');
268
406
  }, onDelete: (id) => {
269
407
  sessionStore.current.delete(id);
270
408
  if (sessionId.current === id) {
271
409
  sessionId.current = null;
272
410
  setMessages([]);
273
- setRoute("home");
411
+ setRoute('home');
274
412
  setHomeKey((k) => k + 1);
275
413
  }
276
- showToast("Session deleted", "success");
414
+ showToast('Session deleted', 'success');
277
415
  }, onRename: (id, title) => {
278
416
  sessionStore.current.rename(id, title);
279
- showToast("Session renamed", "success");
280
- }, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "switch-model" && (_jsx(ModelSwitcher, { providerId: provider || "", termWidth: termWidth, termHeight: termHeight, onModelSelected: (modelId, providerId) => {
417
+ showToast('Session renamed', 'success');
418
+ }, onClose: () => setDialogStep(null), registerHandler: (fn) => {
419
+ dialogKeyHandler.current = fn;
420
+ } })), dialogStep?.type === 'switch-model' && (_jsx(ModelSwitcher, { providerId: provider || '', termWidth: termWidth, termHeight: termHeight, onModelSelected: (modelId, providerId) => {
281
421
  resetAgentForModelSwitch();
282
422
  setSelectedModel(modelId);
283
423
  setSelectedProvider(providerId);
284
424
  setDialogStep(null);
285
425
  saveModelConfig(modelId, providerId);
286
- showToast(`Switched model`, "info");
287
- }, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "manage-providers" && (_jsx(ManageProvidersDialog, { termWidth: termWidth, termHeight: termHeight, providers: customProviders, onProvidersChange: (updated) => {
426
+ showToast(`Switched model`, 'info');
427
+ }, onClose: () => setDialogStep(null), registerHandler: (fn) => {
428
+ dialogKeyHandler.current = fn;
429
+ } })), dialogStep?.type === 'manage-providers' && (_jsx(ManageProvidersDialog, { termWidth: termWidth, termHeight: termHeight, providers: customProviders, onProvidersChange: (updated) => {
288
430
  setCustomProviders(updated);
289
431
  resetAgentForModelSwitch();
290
- showToast("Providers updated", "success");
291
- }, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "doctor" && dialogStep.result && (_jsx(DoctorDialog, { result: dialogStep.result, termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "about" && (_jsx(AboutDialog, { termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "switch-agent" && (_jsx(AgentSwitcher, { currentAgent: selectedAgent, termWidth: termWidth, termHeight: termHeight, onAgentSelected: (agent) => {
432
+ showToast('Providers updated', 'success');
433
+ }, onClose: () => setDialogStep(null), registerHandler: (fn) => {
434
+ dialogKeyHandler.current = fn;
435
+ } })), dialogStep?.type === 'doctor' && dialogStep.result && (_jsx(DoctorDialog, { result: dialogStep.result, termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => {
436
+ dialogKeyHandler.current = fn;
437
+ } })), dialogStep?.type === 'about' && (_jsx(AboutDialog, { termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => {
438
+ dialogKeyHandler.current = fn;
439
+ } })), dialogStep?.type === 'switch-agent' && (_jsx(AgentSwitcher, { currentAgent: selectedAgent, termWidth: termWidth, termHeight: termHeight, onAgentSelected: (agent) => {
292
440
  setSelectedAgent(agent);
293
441
  resetAgentForModelSwitch();
294
442
  setDialogStep(null);
295
- showToast(`Switched to ${titlecase(agent)} agent`, "info");
296
- }, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "thinking-effort" && (_jsx(ThinkingEffortDialog, { provider: provider, currentEffort: thinkingEffort, termWidth: termWidth, termHeight: termHeight, onEffortSelected: (effort) => {
443
+ showToast(`Switched to ${titlecase(agent)} agent`, 'info');
444
+ }, onClose: () => setDialogStep(null), registerHandler: (fn) => {
445
+ dialogKeyHandler.current = fn;
446
+ } })), dialogStep?.type === 'thinking-effort' && (_jsx(ThinkingEffortDialog, { provider: provider, currentEffort: thinkingEffort, termWidth: termWidth, termHeight: termHeight, onEffortSelected: (effort) => {
297
447
  setThinkingEffort(effort);
298
448
  resetAgentForModelSwitch();
299
449
  setDialogStep(null);
300
- showToast(effort === "none" ? "Thinking: off" : `Thinking: ${effort}`, "info");
301
- }, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "toggle-mcp" && (_jsx(McpToggleDialog, { termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), dialogStep?.type === "debug" && (_jsx(DebugDialog, { termWidth: termWidth, termHeight: termHeight, selectedModel: selectedModel, provider: provider, selectedAgent: selectedAgent, thinkingEffort: thinkingEffort, sessionStore: sessionStore.current, mcpCount: mcpCount, onClose: () => setDialogStep(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), msgControls && sessionId.current && (_jsx(MessageControls, { message: msgControls, sessionId: sessionId.current, messages: messages, termWidth: termWidth, termHeight: termHeight, revertPoint: revertPoint, onRevert: (msgId) => { runRevert(messages, msgId); setMsgControls(null); }, onRedo: () => { runRedo(); setMsgControls(null); }, onFork: (msgId) => {
450
+ showToast(effort === 'none' ? 'Thinking: off' : `Thinking: ${effort}`, 'info');
451
+ }, onClose: () => setDialogStep(null), registerHandler: (fn) => {
452
+ dialogKeyHandler.current = fn;
453
+ } })), dialogStep?.type === 'toggle-mcp' && (_jsx(McpToggleDialog, { termWidth: termWidth, termHeight: termHeight, onClose: () => setDialogStep(null), registerHandler: (fn) => {
454
+ dialogKeyHandler.current = fn;
455
+ } })), dialogStep?.type === 'debug' && (_jsx(DebugDialog, { termWidth: termWidth, termHeight: termHeight, selectedModel: selectedModel, provider: provider, selectedAgent: selectedAgent, thinkingEffort: thinkingEffort, sessionStore: sessionStore.current, mcpCount: mcpCount, onClose: () => setDialogStep(null), registerHandler: (fn) => {
456
+ dialogKeyHandler.current = fn;
457
+ } })), msgControls && sessionId.current && (_jsx(MessageControls, { message: msgControls, sessionId: sessionId.current, messages: messages, termWidth: termWidth, termHeight: termHeight, revertPoint: revertPoint, onRevert: (msgId) => {
458
+ runRevert(messages, msgId);
459
+ setMsgControls(null);
460
+ }, onRedo: () => {
461
+ runRedo();
462
+ setMsgControls(null);
463
+ }, onFork: (msgId) => {
302
464
  const forked = sessionStore.current.fork(sessionId.current);
303
465
  if (forked) {
304
- const msgIdx = messages.findIndex(m => m.id === msgId);
466
+ const msgIdx = messages.findIndex((m) => m.id === msgId);
305
467
  if (msgIdx >= 0) {
306
468
  forked.messages = forked.messages.slice(0, msgIdx + 1);
307
- forked.title = `${forked.title.split(" (fork)")[0]} (fork)`;
469
+ forked.title = `${forked.title.split(' (fork)')[0]} (fork)`;
308
470
  sessionStore.current.save(forked);
309
471
  }
310
472
  const data = sessionStore.current.get(forked.id);
@@ -313,10 +475,20 @@ export function App({ renderer }) {
313
475
  setMessages(loadedMsgs);
314
476
  sessionId.current = forked.id;
315
477
  loadedSessionMessages.current = data.messages;
316
- showToast("Session forked", "success");
478
+ showToast('Session forked', 'success');
317
479
  }
318
480
  }
319
481
  setMsgControls(null);
320
- }, onClose: () => setMsgControls(null), registerHandler: (fn) => { dialogKeyHandler.current = fn; } })), permissionRequest && (_jsx(PermissionDialog, { request: permissionRequest, termWidth: termWidth, termHeight: termHeight, onAllow: (id) => { resolvePermission(id, { action: "once" }); }, onAllowAlways: (id) => { resolvePermission(id, { action: "always" }); }, onDeny: (id) => { resolvePermission(id, { action: "deny" }); }, onClose: () => { resolvePermission(permissionRequest.id, { action: "deny" }); } })), _jsx(ToastContainer, {})] }));
482
+ }, onClose: () => setMsgControls(null), registerHandler: (fn) => {
483
+ dialogKeyHandler.current = fn;
484
+ } })), permissionRequest && (_jsx(PermissionDialog, { request: permissionRequest, termWidth: termWidth, termHeight: termHeight, onAllow: (id) => {
485
+ resolvePermission(id, { action: 'once' });
486
+ }, onAllowAlways: (id) => {
487
+ resolvePermission(id, { action: 'always' });
488
+ }, onDeny: (id) => {
489
+ resolvePermission(id, { action: 'deny' });
490
+ }, onClose: () => {
491
+ resolvePermission(permissionRequest.id, { action: 'deny' });
492
+ } })), _jsx(ToastContainer, {})] }));
321
493
  }
322
494
  //# sourceMappingURL=app.js.map