nastechai-desktop 18.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. package/.prettierrc +11 -0
  2. package/DESIGN.md +167 -0
  3. package/README.md +141 -0
  4. package/assets/icon.icns +0 -0
  5. package/assets/icon.ico +0 -0
  6. package/assets/icon.png +0 -0
  7. package/components.json +21 -0
  8. package/electron/backend-env.cjs +112 -0
  9. package/electron/backend-env.test.cjs +111 -0
  10. package/electron/backend-probes.cjs +106 -0
  11. package/electron/backend-probes.test.cjs +82 -0
  12. package/electron/backend-ready.cjs +66 -0
  13. package/electron/bootstrap-platform.cjs +91 -0
  14. package/electron/bootstrap-platform.test.cjs +111 -0
  15. package/electron/bootstrap-runner.cjs +720 -0
  16. package/electron/bootstrap-runner.test.cjs +138 -0
  17. package/electron/connection-config.cjs +254 -0
  18. package/electron/connection-config.test.cjs +329 -0
  19. package/electron/dashboard-token.cjs +99 -0
  20. package/electron/dashboard-token.test.cjs +142 -0
  21. package/electron/desktop-uninstall.cjs +232 -0
  22. package/electron/desktop-uninstall.test.cjs +246 -0
  23. package/electron/entitlements.mac.inherit.plist +14 -0
  24. package/electron/entitlements.mac.plist +14 -0
  25. package/electron/fs-read-dir.cjs +109 -0
  26. package/electron/fs-read-dir.test.cjs +364 -0
  27. package/electron/gateway-ws-probe.cjs +188 -0
  28. package/electron/gateway-ws-probe.test.cjs +122 -0
  29. package/electron/git-root.cjs +54 -0
  30. package/electron/git-root.test.cjs +40 -0
  31. package/electron/git-worktrees.cjs +174 -0
  32. package/electron/hardening.cjs +184 -0
  33. package/electron/hardening.test.cjs +116 -0
  34. package/electron/main.cjs +5762 -0
  35. package/electron/oauth-net-request.cjs +20 -0
  36. package/electron/oauth-net-request.test.cjs +34 -0
  37. package/electron/preload.cjs +135 -0
  38. package/electron/session-windows.cjs +99 -0
  39. package/electron/session-windows.test.cjs +177 -0
  40. package/electron/update-remote.cjs +56 -0
  41. package/electron/update-remote.test.cjs +78 -0
  42. package/electron/vscode-marketplace.cjs +331 -0
  43. package/electron/vscode-marketplace.test.cjs +113 -0
  44. package/electron/windows-child-process.test.cjs +57 -0
  45. package/electron/windows-user-env.cjs +76 -0
  46. package/electron/windows-user-env.test.cjs +90 -0
  47. package/electron/workspace-cwd.cjs +38 -0
  48. package/electron/workspace-cwd.test.cjs +45 -0
  49. package/eslint.config.mjs +122 -0
  50. package/index.html +17 -0
  51. package/package.json +254 -0
  52. package/pr-assets/session-source-folders.png +0 -0
  53. package/preview-demo.html +65 -0
  54. package/public/apple-touch-icon.png +0 -0
  55. package/public/ds-assets/filler-bg0.jpg +0 -0
  56. package/public/nastech-frames/nastech-frame-0.png +0 -0
  57. package/public/nastech-frames/nastech-frame-1.png +0 -0
  58. package/public/nastech-frames/nastech-frame-2.png +0 -0
  59. package/public/nastech-frames/nastech-frame-3.png +0 -0
  60. package/public/nastech-frames/nastech-frame-4.png +0 -0
  61. package/public/nastech-frames/nastech-frame-5.png +0 -0
  62. package/public/nastech-frames/nastech-frame-6.png +0 -0
  63. package/public/nastech-frames/nastech-frame-7.png +0 -0
  64. package/public/nastech-girl.jpg +0 -0
  65. package/public/nastech-sprite.png +0 -0
  66. package/public/nastech.png +0 -0
  67. package/scripts/after-pack.cjs +41 -0
  68. package/scripts/assert-dist-built.cjs +70 -0
  69. package/scripts/assert-dist-built.test.cjs +84 -0
  70. package/scripts/assert-root-install.cjs +13 -0
  71. package/scripts/before-build.cjs +11 -0
  72. package/scripts/before-pack.cjs +78 -0
  73. package/scripts/before-pack.test.cjs +53 -0
  74. package/scripts/click-session.mjs +51 -0
  75. package/scripts/dev-no-hmr.mjs +22 -0
  76. package/scripts/diag-jump.mjs +115 -0
  77. package/scripts/diag-scroll-reset.mjs +229 -0
  78. package/scripts/eval.mjs +21 -0
  79. package/scripts/leak-typing.mjs +222 -0
  80. package/scripts/measure-jump.mjs +108 -0
  81. package/scripts/measure-latency.mjs +184 -0
  82. package/scripts/measure-real-stream.mjs +252 -0
  83. package/scripts/measure-submit.mjs +179 -0
  84. package/scripts/measure-synthetic-stream.mjs +322 -0
  85. package/scripts/notarize-artifact.cjs +77 -0
  86. package/scripts/notarize.cjs +100 -0
  87. package/scripts/patch-electron-builder-mac-binary.cjs +59 -0
  88. package/scripts/probe-renderer.mjs +38 -0
  89. package/scripts/probe-thread.mjs +40 -0
  90. package/scripts/profile-long-stream.mjs +191 -0
  91. package/scripts/profile-real-stream.mjs +137 -0
  92. package/scripts/profile-synth-stream.mjs +103 -0
  93. package/scripts/profile-typing-lag.md +381 -0
  94. package/scripts/profile-typing.mjs +260 -0
  95. package/scripts/reload-renderer.mjs +25 -0
  96. package/scripts/reload.mjs +36 -0
  97. package/scripts/set-exe-identity.cjs +94 -0
  98. package/scripts/stage-native-deps.cjs +159 -0
  99. package/scripts/test-desktop.mjs +425 -0
  100. package/scripts/write-build-stamp.cjs +126 -0
  101. package/src/app/agents/index.tsx +398 -0
  102. package/src/app/artifacts/index.test.ts +62 -0
  103. package/src/app/artifacts/index.tsx +906 -0
  104. package/src/app/chat/chat-drop-overlay.tsx +48 -0
  105. package/src/app/chat/chat-swap-overlay.tsx +47 -0
  106. package/src/app/chat/composer/attachments.tsx +114 -0
  107. package/src/app/chat/composer/completion-drawer.tsx +63 -0
  108. package/src/app/chat/composer/context-menu.tsx +172 -0
  109. package/src/app/chat/composer/controls.tsx +289 -0
  110. package/src/app/chat/composer/drop-affordance.ts +2 -0
  111. package/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
  112. package/src/app/chat/composer/focus.ts +134 -0
  113. package/src/app/chat/composer/help-hint.tsx +59 -0
  114. package/src/app/chat/composer/hooks/use-at-completions.ts +141 -0
  115. package/src/app/chat/composer/hooks/use-live-completion-adapter.ts +119 -0
  116. package/src/app/chat/composer/hooks/use-mic-recorder.ts +291 -0
  117. package/src/app/chat/composer/hooks/use-slash-completions.ts +114 -0
  118. package/src/app/chat/composer/hooks/use-voice-conversation.ts +390 -0
  119. package/src/app/chat/composer/hooks/use-voice-recorder.ts +116 -0
  120. package/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
  121. package/src/app/chat/composer/index.tsx +1611 -0
  122. package/src/app/chat/composer/inline-refs.ts +138 -0
  123. package/src/app/chat/composer/model-pill.tsx +86 -0
  124. package/src/app/chat/composer/queue-panel.tsx +130 -0
  125. package/src/app/chat/composer/rich-editor.test.ts +18 -0
  126. package/src/app/chat/composer/rich-editor.ts +165 -0
  127. package/src/app/chat/composer/skin-slash-popover.tsx +61 -0
  128. package/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
  129. package/src/app/chat/composer/status-stack/index.tsx +202 -0
  130. package/src/app/chat/composer/status-stack/status-row.tsx +155 -0
  131. package/src/app/chat/composer/text-utils.test.ts +77 -0
  132. package/src/app/chat/composer/text-utils.ts +107 -0
  133. package/src/app/chat/composer/trigger-popover.test.tsx +42 -0
  134. package/src/app/chat/composer/trigger-popover.tsx +116 -0
  135. package/src/app/chat/composer/types.ts +64 -0
  136. package/src/app/chat/composer/url-dialog.tsx +82 -0
  137. package/src/app/chat/composer/voice-activity.tsx +252 -0
  138. package/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
  139. package/src/app/chat/hooks/use-composer-actions.ts +525 -0
  140. package/src/app/chat/hooks/use-file-drop-zone.ts +118 -0
  141. package/src/app/chat/index.tsx +390 -0
  142. package/src/app/chat/perf-probe.tsx +269 -0
  143. package/src/app/chat/right-rail/index.ts +1 -0
  144. package/src/app/chat/right-rail/preview-console-state.ts +82 -0
  145. package/src/app/chat/right-rail/preview-console.tsx +290 -0
  146. package/src/app/chat/right-rail/preview-file.tsx +559 -0
  147. package/src/app/chat/right-rail/preview-pane.test.tsx +43 -0
  148. package/src/app/chat/right-rail/preview-pane.tsx +657 -0
  149. package/src/app/chat/right-rail/preview.tsx +171 -0
  150. package/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
  151. package/src/app/chat/scroll-to-bottom-button.tsx +74 -0
  152. package/src/app/chat/sidebar/cron-jobs-section.tsx +325 -0
  153. package/src/app/chat/sidebar/index.tsx +1219 -0
  154. package/src/app/chat/sidebar/load-more-row.tsx +30 -0
  155. package/src/app/chat/sidebar/order.test.ts +21 -0
  156. package/src/app/chat/sidebar/order.ts +17 -0
  157. package/src/app/chat/sidebar/profile-switcher.tsx +516 -0
  158. package/src/app/chat/sidebar/session-actions-menu.tsx +264 -0
  159. package/src/app/chat/sidebar/session-row.tsx +257 -0
  160. package/src/app/chat/sidebar/virtual-session-list.tsx +154 -0
  161. package/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
  162. package/src/app/chat/sidebar/workspace-groups.ts +326 -0
  163. package/src/app/chat/thread-loading.test.ts +34 -0
  164. package/src/app/chat/thread-loading.ts +26 -0
  165. package/src/app/command-center/index.tsx +654 -0
  166. package/src/app/command-palette/index.tsx +513 -0
  167. package/src/app/command-palette/marketplace-theme-page.tsx +157 -0
  168. package/src/app/cron/index.tsx +942 -0
  169. package/src/app/cron/job-state.ts +29 -0
  170. package/src/app/desktop-controller.tsx +938 -0
  171. package/src/app/floating-hud.ts +22 -0
  172. package/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
  173. package/src/app/gateway/hooks/use-gateway-boot.ts +387 -0
  174. package/src/app/gateway/hooks/use-gateway-request.ts +138 -0
  175. package/src/app/hooks/use-keybinds.ts +186 -0
  176. package/src/app/hooks/use-refresh-hotkey.ts +45 -0
  177. package/src/app/hooks/use-route-enum-param.ts +38 -0
  178. package/src/app/index.tsx +1 -0
  179. package/src/app/layout-constants.ts +13 -0
  180. package/src/app/messaging/index.tsx +648 -0
  181. package/src/app/messaging/platform-icon.tsx +93 -0
  182. package/src/app/model-picker-overlay.tsx +42 -0
  183. package/src/app/model-visibility-overlay.tsx +31 -0
  184. package/src/app/overlays/overlay-chrome.tsx +66 -0
  185. package/src/app/overlays/overlay-search-input.tsx +33 -0
  186. package/src/app/overlays/overlay-split-layout.tsx +130 -0
  187. package/src/app/overlays/overlay-view.tsx +91 -0
  188. package/src/app/page-search-shell.tsx +75 -0
  189. package/src/app/profiles/create-profile-dialog.tsx +154 -0
  190. package/src/app/profiles/delete-profile-dialog.tsx +65 -0
  191. package/src/app/profiles/index.tsx +671 -0
  192. package/src/app/profiles/rename-profile-dialog.tsx +125 -0
  193. package/src/app/right-sidebar/files/dnd-manager.ts +27 -0
  194. package/src/app/right-sidebar/files/ipc.test.ts +100 -0
  195. package/src/app/right-sidebar/files/ipc.ts +161 -0
  196. package/src/app/right-sidebar/files/remote-picker.tsx +177 -0
  197. package/src/app/right-sidebar/files/tree.tsx +224 -0
  198. package/src/app/right-sidebar/files/use-project-tree.test.ts +190 -0
  199. package/src/app/right-sidebar/files/use-project-tree.ts +268 -0
  200. package/src/app/right-sidebar/index.test.tsx +75 -0
  201. package/src/app/right-sidebar/index.tsx +395 -0
  202. package/src/app/right-sidebar/store.ts +15 -0
  203. package/src/app/right-sidebar/terminal/buffer.ts +65 -0
  204. package/src/app/right-sidebar/terminal/index.tsx +98 -0
  205. package/src/app/right-sidebar/terminal/persistent.tsx +122 -0
  206. package/src/app/right-sidebar/terminal/selection.ts +75 -0
  207. package/src/app/right-sidebar/terminal/use-terminal-session.ts +504 -0
  208. package/src/app/routes.ts +88 -0
  209. package/src/app/session/hooks/use-context-suggestions.ts +58 -0
  210. package/src/app/session/hooks/use-cwd-actions.ts +109 -0
  211. package/src/app/session/hooks/use-message-stream.ts +957 -0
  212. package/src/app/session/hooks/use-model-controls.test.tsx +198 -0
  213. package/src/app/session/hooks/use-model-controls.ts +106 -0
  214. package/src/app/session/hooks/use-nastech-config.ts +74 -0
  215. package/src/app/session/hooks/use-preview-routing.test.tsx +168 -0
  216. package/src/app/session/hooks/use-preview-routing.ts +223 -0
  217. package/src/app/session/hooks/use-prompt-actions.test.tsx +316 -0
  218. package/src/app/session/hooks/use-prompt-actions.ts +1030 -0
  219. package/src/app/session/hooks/use-route-resume.test.tsx +136 -0
  220. package/src/app/session/hooks/use-route-resume.ts +115 -0
  221. package/src/app/session/hooks/use-session-actions.test.tsx +119 -0
  222. package/src/app/session/hooks/use-session-actions.ts +885 -0
  223. package/src/app/session/hooks/use-session-state-cache.test.tsx +118 -0
  224. package/src/app/session/hooks/use-session-state-cache.ts +191 -0
  225. package/src/app/session-picker-overlay.tsx +32 -0
  226. package/src/app/session-switcher.tsx +107 -0
  227. package/src/app/settings/about-settings.tsx +173 -0
  228. package/src/app/settings/appearance-settings.tsx +162 -0
  229. package/src/app/settings/config-settings.tsx +384 -0
  230. package/src/app/settings/constants.ts +545 -0
  231. package/src/app/settings/credential-key-ui.tsx +373 -0
  232. package/src/app/settings/env-credentials.tsx +198 -0
  233. package/src/app/settings/env-var-actions-menu.tsx +136 -0
  234. package/src/app/settings/field-copy.ts +56 -0
  235. package/src/app/settings/gateway-settings.tsx +620 -0
  236. package/src/app/settings/helpers.test.ts +138 -0
  237. package/src/app/settings/helpers.ts +151 -0
  238. package/src/app/settings/index.tsx +237 -0
  239. package/src/app/settings/keys-settings.tsx +96 -0
  240. package/src/app/settings/mcp-settings.tsx +271 -0
  241. package/src/app/settings/model-settings.test.tsx +157 -0
  242. package/src/app/settings/model-settings.tsx +559 -0
  243. package/src/app/settings/notifications-settings.tsx +150 -0
  244. package/src/app/settings/primitives.tsx +115 -0
  245. package/src/app/settings/providers-settings.test.tsx +100 -0
  246. package/src/app/settings/providers-settings.tsx +258 -0
  247. package/src/app/settings/sessions-settings.tsx +276 -0
  248. package/src/app/settings/toolset-config-panel.test.tsx +289 -0
  249. package/src/app/settings/toolset-config-panel.tsx +449 -0
  250. package/src/app/settings/types.ts +42 -0
  251. package/src/app/settings/uninstall-section.tsx +185 -0
  252. package/src/app/settings/use-deep-link-highlight.ts +60 -0
  253. package/src/app/shell/app-shell.tsx +167 -0
  254. package/src/app/shell/gateway-menu-panel.tsx +150 -0
  255. package/src/app/shell/hooks/use-overlay-routing.ts +71 -0
  256. package/src/app/shell/hooks/use-status-snapshot.ts +57 -0
  257. package/src/app/shell/hooks/use-statusbar-items.tsx +403 -0
  258. package/src/app/shell/keybind-panel.tsx +220 -0
  259. package/src/app/shell/model-edit-submenu.test.tsx +84 -0
  260. package/src/app/shell/model-edit-submenu.tsx +245 -0
  261. package/src/app/shell/model-menu-panel.tsx +295 -0
  262. package/src/app/shell/sidebar-label.tsx +22 -0
  263. package/src/app/shell/statusbar-controls.tsx +185 -0
  264. package/src/app/shell/titlebar-controls.tsx +244 -0
  265. package/src/app/shell/titlebar.test.ts +26 -0
  266. package/src/app/shell/titlebar.ts +45 -0
  267. package/src/app/shell/use-group-registry.ts +39 -0
  268. package/src/app/skills/index.test.tsx +103 -0
  269. package/src/app/skills/index.tsx +371 -0
  270. package/src/app/types.ts +99 -0
  271. package/src/app/updates-overlay.tsx +369 -0
  272. package/src/components/Backdrop.tsx +114 -0
  273. package/src/components/assistant-ui/ansi-text.tsx +34 -0
  274. package/src/components/assistant-ui/clarify-tool.tsx +281 -0
  275. package/src/components/assistant-ui/directive-text.test.ts +39 -0
  276. package/src/components/assistant-ui/directive-text.tsx +389 -0
  277. package/src/components/assistant-ui/markdown-text.test.ts +204 -0
  278. package/src/components/assistant-ui/markdown-text.tsx +497 -0
  279. package/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
  280. package/src/components/assistant-ui/message-render-boundary.tsx +48 -0
  281. package/src/components/assistant-ui/streaming.test.tsx +739 -0
  282. package/src/components/assistant-ui/thread-list.tsx +307 -0
  283. package/src/components/assistant-ui/thread-virtualizer.tsx +512 -0
  284. package/src/components/assistant-ui/thread.tsx +1474 -0
  285. package/src/components/assistant-ui/todo-tool.tsx +109 -0
  286. package/src/components/assistant-ui/tool-approval-group.test.tsx +158 -0
  287. package/src/components/assistant-ui/tool-approval.test.tsx +81 -0
  288. package/src/components/assistant-ui/tool-approval.tsx +209 -0
  289. package/src/components/assistant-ui/tool-fallback-model.test.ts +66 -0
  290. package/src/components/assistant-ui/tool-fallback-model.ts +1368 -0
  291. package/src/components/assistant-ui/tool-fallback.tsx +466 -0
  292. package/src/components/assistant-ui/tooltip-icon-button.tsx +33 -0
  293. package/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
  294. package/src/components/assistant-ui/user-message-text.tsx +150 -0
  295. package/src/components/boot-failure-overlay.tsx +246 -0
  296. package/src/components/boot-failure-reauth.test.ts +100 -0
  297. package/src/components/boot-failure-reauth.ts +81 -0
  298. package/src/components/brand-mark.tsx +19 -0
  299. package/src/components/chat/activity-timer-text.tsx +24 -0
  300. package/src/components/chat/activity-timer.test.tsx +43 -0
  301. package/src/components/chat/activity-timer.ts +64 -0
  302. package/src/components/chat/code-card.tsx +78 -0
  303. package/src/components/chat/compact-markdown.tsx +113 -0
  304. package/src/components/chat/composer-dock.ts +31 -0
  305. package/src/components/chat/diff-lines.tsx +54 -0
  306. package/src/components/chat/disclosure-row.tsx +63 -0
  307. package/src/components/chat/generated-image-context.tsx +19 -0
  308. package/src/components/chat/generated-image-result.tsx +174 -0
  309. package/src/components/chat/image-generation-placeholder.tsx +279 -0
  310. package/src/components/chat/intro-copy.jsonl +75 -0
  311. package/src/components/chat/intro.tsx +182 -0
  312. package/src/components/chat/preview-attachment.tsx +125 -0
  313. package/src/components/chat/shiki-highlighter.tsx +107 -0
  314. package/src/components/chat/status-row.tsx +70 -0
  315. package/src/components/chat/status-section.tsx +42 -0
  316. package/src/components/chat/terminal-output.tsx +50 -0
  317. package/src/components/chat/zoomable-image.tsx +177 -0
  318. package/src/components/desktop-install-overlay.tsx +595 -0
  319. package/src/components/desktop-onboarding-overlay.test.tsx +100 -0
  320. package/src/components/desktop-onboarding-overlay.tsx +1286 -0
  321. package/src/components/error-boundary.tsx +77 -0
  322. package/src/components/gateway-connecting-overlay.test.tsx +143 -0
  323. package/src/components/gateway-connecting-overlay.tsx +183 -0
  324. package/src/components/haptics-provider.tsx +19 -0
  325. package/src/components/language-switcher.test.tsx +53 -0
  326. package/src/components/language-switcher.tsx +175 -0
  327. package/src/components/model-picker.tsx +340 -0
  328. package/src/components/model-visibility-dialog.tsx +155 -0
  329. package/src/components/notifications.tsx +196 -0
  330. package/src/components/page-loader.tsx +34 -0
  331. package/src/components/pane-shell/context.ts +14 -0
  332. package/src/components/pane-shell/index.ts +4 -0
  333. package/src/components/pane-shell/pane-shell.test.tsx +333 -0
  334. package/src/components/pane-shell/pane-shell.tsx +330 -0
  335. package/src/components/prompt-overlays.tsx +234 -0
  336. package/src/components/session-picker.tsx +108 -0
  337. package/src/components/status-dot.tsx +26 -0
  338. package/src/components/ui/action-status.tsx +25 -0
  339. package/src/components/ui/alert.tsx +53 -0
  340. package/src/components/ui/badge.tsx +35 -0
  341. package/src/components/ui/braille-spinner.tsx +61 -0
  342. package/src/components/ui/button.tsx +81 -0
  343. package/src/components/ui/checkbox.tsx +27 -0
  344. package/src/components/ui/codicon.tsx +20 -0
  345. package/src/components/ui/command.tsx +111 -0
  346. package/src/components/ui/confirm-dialog.tsx +109 -0
  347. package/src/components/ui/context-menu.tsx +141 -0
  348. package/src/components/ui/control.ts +25 -0
  349. package/src/components/ui/copy-button.test.tsx +36 -0
  350. package/src/components/ui/copy-button.tsx +229 -0
  351. package/src/components/ui/dialog.tsx +152 -0
  352. package/src/components/ui/disclosure-caret.tsx +20 -0
  353. package/src/components/ui/dropdown-menu.tsx +291 -0
  354. package/src/components/ui/error-state.tsx +50 -0
  355. package/src/components/ui/fade-text.tsx +110 -0
  356. package/src/components/ui/glyph-spinner.tsx +63 -0
  357. package/src/components/ui/input.tsx +22 -0
  358. package/src/components/ui/kbd.tsx +37 -0
  359. package/src/components/ui/loader.tsx +558 -0
  360. package/src/components/ui/log-view.tsx +17 -0
  361. package/src/components/ui/pagination.tsx +114 -0
  362. package/src/components/ui/popover.tsx +44 -0
  363. package/src/components/ui/scroll-area.tsx +43 -0
  364. package/src/components/ui/search-field.tsx +80 -0
  365. package/src/components/ui/segmented-control.tsx +51 -0
  366. package/src/components/ui/select.tsx +92 -0
  367. package/src/components/ui/separator.tsx +26 -0
  368. package/src/components/ui/sheet.tsx +116 -0
  369. package/src/components/ui/sidebar.tsx +674 -0
  370. package/src/components/ui/skeleton.tsx +7 -0
  371. package/src/components/ui/switch.tsx +49 -0
  372. package/src/components/ui/tabs.tsx +36 -0
  373. package/src/components/ui/text-tab.tsx +43 -0
  374. package/src/components/ui/textarea.tsx +11 -0
  375. package/src/components/ui/tool-icon.tsx +65 -0
  376. package/src/components/ui/tooltip.tsx +69 -0
  377. package/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
  378. package/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
  379. package/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
  380. package/src/global.d.ts +457 -0
  381. package/src/hooks/use-image-download.ts +85 -0
  382. package/src/hooks/use-media-query.ts +24 -0
  383. package/src/hooks/use-mobile.ts +3 -0
  384. package/src/hooks/use-resize-observer.ts +38 -0
  385. package/src/hooks/use-worktree-info.ts +68 -0
  386. package/src/i18n/catalog.ts +12 -0
  387. package/src/i18n/context.test.tsx +232 -0
  388. package/src/i18n/context.tsx +183 -0
  389. package/src/i18n/define-locale.ts +41 -0
  390. package/src/i18n/en.ts +1779 -0
  391. package/src/i18n/index.ts +20 -0
  392. package/src/i18n/ja.ts +1890 -0
  393. package/src/i18n/languages.test.ts +43 -0
  394. package/src/i18n/languages.ts +86 -0
  395. package/src/i18n/runtime.test.ts +75 -0
  396. package/src/i18n/runtime.ts +53 -0
  397. package/src/i18n/types.ts +1452 -0
  398. package/src/i18n/zh-hant.ts +1849 -0
  399. package/src/i18n/zh.ts +1923 -0
  400. package/src/lib/ansi.test.ts +123 -0
  401. package/src/lib/ansi.ts +175 -0
  402. package/src/lib/chat-messages.test.ts +708 -0
  403. package/src/lib/chat-messages.ts +885 -0
  404. package/src/lib/chat-runtime.test.ts +18 -0
  405. package/src/lib/chat-runtime.ts +335 -0
  406. package/src/lib/clipboard.ts +28 -0
  407. package/src/lib/commit-changelog.test.ts +114 -0
  408. package/src/lib/commit-changelog.ts +177 -0
  409. package/src/lib/completion-sound.ts +519 -0
  410. package/src/lib/desktop-fs.test.ts +116 -0
  411. package/src/lib/desktop-fs.ts +113 -0
  412. package/src/lib/desktop-slash-commands.test.ts +126 -0
  413. package/src/lib/desktop-slash-commands.ts +286 -0
  414. package/src/lib/embedded-images.test.ts +35 -0
  415. package/src/lib/embedded-images.ts +60 -0
  416. package/src/lib/external-link.test.tsx +168 -0
  417. package/src/lib/external-link.tsx +303 -0
  418. package/src/lib/gateway-events.test.ts +27 -0
  419. package/src/lib/gateway-events.ts +49 -0
  420. package/src/lib/gateway-ws-url.test.ts +78 -0
  421. package/src/lib/gateway-ws-url.ts +91 -0
  422. package/src/lib/generated-images.test.ts +97 -0
  423. package/src/lib/generated-images.ts +116 -0
  424. package/src/lib/haptics.ts +129 -0
  425. package/src/lib/icons.ts +203 -0
  426. package/src/lib/incremental-external-store-runtime.ts +188 -0
  427. package/src/lib/katex-memo.ts +260 -0
  428. package/src/lib/keybinds/actions.ts +125 -0
  429. package/src/lib/keybinds/combo.test.ts +86 -0
  430. package/src/lib/keybinds/combo.ts +169 -0
  431. package/src/lib/local-preview.ts +126 -0
  432. package/src/lib/markdown-code.test.ts +23 -0
  433. package/src/lib/markdown-code.ts +195 -0
  434. package/src/lib/markdown-preprocess.ts +386 -0
  435. package/src/lib/media.remote.test.ts +58 -0
  436. package/src/lib/media.ts +111 -0
  437. package/src/lib/model-status-label.test.ts +31 -0
  438. package/src/lib/model-status-label.ts +103 -0
  439. package/src/lib/mutable-ref.ts +6 -0
  440. package/src/lib/preview-targets.test.ts +27 -0
  441. package/src/lib/preview-targets.ts +63 -0
  442. package/src/lib/profile-color.ts +58 -0
  443. package/src/lib/provider-setup-errors.test.ts +26 -0
  444. package/src/lib/provider-setup-errors.ts +12 -0
  445. package/src/lib/query-client.ts +13 -0
  446. package/src/lib/remend-tail.test.ts +105 -0
  447. package/src/lib/remend-tail.ts +108 -0
  448. package/src/lib/runtime-readiness.test.ts +65 -0
  449. package/src/lib/runtime-readiness.ts +147 -0
  450. package/src/lib/session-export.ts +57 -0
  451. package/src/lib/session-search.test.ts +58 -0
  452. package/src/lib/session-search.ts +19 -0
  453. package/src/lib/session-source.ts +62 -0
  454. package/src/lib/speech-text.ts +35 -0
  455. package/src/lib/statusbar.ts +91 -0
  456. package/src/lib/storage.test.ts +25 -0
  457. package/src/lib/storage.ts +107 -0
  458. package/src/lib/todos.test.ts +35 -0
  459. package/src/lib/todos.ts +51 -0
  460. package/src/lib/tool-result-summary.test.ts +106 -0
  461. package/src/lib/tool-result-summary.ts +467 -0
  462. package/src/lib/update-copy.test.ts +38 -0
  463. package/src/lib/update-copy.ts +44 -0
  464. package/src/lib/use-enter-animation.ts +100 -0
  465. package/src/lib/utils.ts +6 -0
  466. package/src/lib/voice-playback.ts +128 -0
  467. package/src/lib/yolo-session.ts +26 -0
  468. package/src/main.tsx +43 -0
  469. package/src/nastech.test.ts +49 -0
  470. package/src/nastech.ts +718 -0
  471. package/src/store/activity.ts +100 -0
  472. package/src/store/boot.ts +91 -0
  473. package/src/store/clarify.test.ts +81 -0
  474. package/src/store/clarify.ts +69 -0
  475. package/src/store/command-palette.ts +20 -0
  476. package/src/store/compaction.test.ts +53 -0
  477. package/src/store/compaction.ts +38 -0
  478. package/src/store/completion-sound.ts +32 -0
  479. package/src/store/composer-input-history.test.ts +147 -0
  480. package/src/store/composer-input-history.ts +158 -0
  481. package/src/store/composer-queue.test.ts +148 -0
  482. package/src/store/composer-queue.ts +239 -0
  483. package/src/store/composer-status.test.ts +99 -0
  484. package/src/store/composer-status.ts +277 -0
  485. package/src/store/composer.test.ts +106 -0
  486. package/src/store/composer.ts +184 -0
  487. package/src/store/cron.ts +19 -0
  488. package/src/store/gateway.ts +290 -0
  489. package/src/store/haptics.ts +17 -0
  490. package/src/store/keybinds.ts +139 -0
  491. package/src/store/layout.ts +176 -0
  492. package/src/store/model-presets.test.ts +51 -0
  493. package/src/store/model-presets.ts +86 -0
  494. package/src/store/model-visibility.test.ts +37 -0
  495. package/src/store/model-visibility.ts +108 -0
  496. package/src/store/native-notifications.test.ts +192 -0
  497. package/src/store/native-notifications.ts +203 -0
  498. package/src/store/notifications.ts +165 -0
  499. package/src/store/onboarding.test.ts +372 -0
  500. package/src/store/onboarding.ts +866 -0
  501. package/src/store/panes.test.ts +146 -0
  502. package/src/store/panes.ts +145 -0
  503. package/src/store/preview.test.ts +135 -0
  504. package/src/store/preview.ts +466 -0
  505. package/src/store/profile.test.ts +89 -0
  506. package/src/store/profile.ts +365 -0
  507. package/src/store/prompts.test.ts +121 -0
  508. package/src/store/prompts.ts +115 -0
  509. package/src/store/session-switcher.test.ts +115 -0
  510. package/src/store/session-switcher.ts +128 -0
  511. package/src/store/session-sync.ts +25 -0
  512. package/src/store/session.test.ts +131 -0
  513. package/src/store/session.ts +255 -0
  514. package/src/store/subagents.test.ts +111 -0
  515. package/src/store/subagents.ts +260 -0
  516. package/src/store/thread-scroll.ts +46 -0
  517. package/src/store/todos.test.ts +47 -0
  518. package/src/store/todos.ts +64 -0
  519. package/src/store/tool-diffs.ts +23 -0
  520. package/src/store/tool-dismiss.ts +45 -0
  521. package/src/store/tool-view.ts +91 -0
  522. package/src/store/translucency.ts +38 -0
  523. package/src/store/updates.test.ts +77 -0
  524. package/src/store/updates.ts +315 -0
  525. package/src/store/voice-playback.ts +24 -0
  526. package/src/store/windows.test.ts +143 -0
  527. package/src/store/windows.ts +77 -0
  528. package/src/styles.css +1235 -0
  529. package/src/themes/color.ts +142 -0
  530. package/src/themes/context.tsx +339 -0
  531. package/src/themes/index.ts +3 -0
  532. package/src/themes/install.test.ts +119 -0
  533. package/src/themes/install.ts +95 -0
  534. package/src/themes/presets.test.ts +33 -0
  535. package/src/themes/presets.ts +293 -0
  536. package/src/themes/profile-theme.test.ts +41 -0
  537. package/src/themes/types.ts +66 -0
  538. package/src/themes/use-skin-command.ts +60 -0
  539. package/src/themes/user-themes.test.ts +63 -0
  540. package/src/themes/user-themes.ts +122 -0
  541. package/src/themes/vscode.test.ts +171 -0
  542. package/src/themes/vscode.ts +343 -0
  543. package/src/types/nastech.ts +646 -0
  544. package/src/vite-env.d.ts +1 -0
  545. package/tsconfig.json +25 -0
  546. package/vite.config.ts +56 -0
@@ -0,0 +1,93 @@
1
+ import {
2
+ SiApple,
3
+ SiBilibili,
4
+ SiDiscord,
5
+ SiGmail,
6
+ SiHomeassistant,
7
+ SiMatrix,
8
+ SiMattermost,
9
+ SiQq,
10
+ SiSignal,
11
+ SiTelegram,
12
+ SiWechat,
13
+ SiWhatsapp
14
+ } from '@icons-pack/react-simple-icons'
15
+ import type { ComponentType, SVGProps } from 'react'
16
+
17
+ import { Globe, Link as LinkIcon, MessageSquareText } from '@/lib/icons'
18
+ import { cn } from '@/lib/utils'
19
+
20
+ // We render simpleicons.org brand glyphs for platforms whose owners publish a
21
+ // usable mark (telegram, discord, matrix, ...). A few brands — Slack, Dingtalk,
22
+ // Feishu, WeCom — have been removed from Simple Icons at the brand owner's
23
+ // request, so we fall back to a colored letter monogram for those.
24
+ //
25
+ // `iconColor` is the brand's hex from simpleicons.org so we can paint each
26
+ // glyph in its native color on top of a soft tint. The fallback monogram uses
27
+ // the same hex to keep visual consistency.
28
+ type IconKind = 'brand' | 'generic'
29
+
30
+ interface PlatformIconSpec {
31
+ Icon: ComponentType<SVGProps<SVGSVGElement>>
32
+ color: string
33
+ kind: IconKind
34
+ }
35
+
36
+ const PLATFORM_ICONS: Record<string, PlatformIconSpec> = {
37
+ telegram: { Icon: SiTelegram, color: '#26A5E4', kind: 'brand' },
38
+ discord: { Icon: SiDiscord, color: '#5865F2', kind: 'brand' },
39
+ // Slack removed from Simple Icons by Salesforce request — letter monogram.
40
+ mattermost: { Icon: SiMattermost, color: '#0058CC', kind: 'brand' },
41
+ matrix: { Icon: SiMatrix, color: '#000000', kind: 'brand' },
42
+ signal: { Icon: SiSignal, color: '#3A76F0', kind: 'brand' },
43
+ whatsapp: { Icon: SiWhatsapp, color: '#25D366', kind: 'brand' },
44
+ bluebubbles: { Icon: SiApple, color: '#0BD318', kind: 'brand' },
45
+ homeassistant: { Icon: SiHomeassistant, color: '#18BCF2', kind: 'brand' },
46
+ email: { Icon: SiGmail, color: '#EA4335', kind: 'brand' },
47
+ sms: { Icon: MessageSquareText, color: '#F43F5E', kind: 'generic' },
48
+ webhook: { Icon: LinkIcon, color: '#71717A', kind: 'generic' },
49
+ api_server: { Icon: Globe, color: '#64748B', kind: 'generic' },
50
+ weixin: { Icon: SiWechat, color: '#07C160', kind: 'brand' },
51
+ qqbot: { Icon: SiQq, color: '#EB1923', kind: 'brand' },
52
+ yuanbao: { Icon: SiBilibili, color: '#FB7299', kind: 'brand' }
53
+ }
54
+
55
+ interface PlatformAvatarProps {
56
+ platformId: string
57
+ platformName: string
58
+ className?: string
59
+ }
60
+
61
+ export function PlatformAvatar({ className, platformId, platformName }: PlatformAvatarProps) {
62
+ const spec = PLATFORM_ICONS[platformId]
63
+
64
+ const baseClass = cn(
65
+ 'inline-grid size-6 shrink-0 place-items-center rounded-md text-[length:var(--conversation-caption-font-size)] font-medium',
66
+ className
67
+ )
68
+
69
+ if (!spec) {
70
+ return (
71
+ <span aria-hidden="true" className={cn(baseClass, 'bg-(--ui-bg-tertiary) text-(--ui-text-tertiary)')}>
72
+ {platformName.charAt(0).toUpperCase()}
73
+ </span>
74
+ )
75
+ }
76
+
77
+ const { Icon, color } = spec
78
+
79
+ return (
80
+ <span
81
+ aria-hidden="true"
82
+ className={baseClass}
83
+ style={{
84
+ // 16% tint of the brand color so the glyph reads against any surface
85
+ // without the avatar dominating the row.
86
+ backgroundColor: `color-mix(in srgb, ${color} 16%, transparent)`,
87
+ color
88
+ }}
89
+ >
90
+ <Icon className="size-3.5" />
91
+ </span>
92
+ )
93
+ }
@@ -0,0 +1,42 @@
1
+ import { useStore } from '@nanostores/react'
2
+ import type * as React from 'react'
3
+
4
+ import { ModelPickerDialog } from '@/components/model-picker'
5
+ import type { NasTechGateway } from '@/nastech'
6
+ import {
7
+ $activeSessionId,
8
+ $currentModel,
9
+ $currentProvider,
10
+ $gatewayState,
11
+ $modelPickerOpen,
12
+ setModelPickerOpen
13
+ } from '@/store/session'
14
+
15
+ interface ModelPickerOverlayProps {
16
+ gateway?: NasTechGateway
17
+ onSelect: React.ComponentProps<typeof ModelPickerDialog>['onSelect']
18
+ }
19
+
20
+ export function ModelPickerOverlay({ gateway, onSelect }: ModelPickerOverlayProps) {
21
+ const activeSessionId = useStore($activeSessionId)
22
+ const currentModel = useStore($currentModel)
23
+ const currentProvider = useStore($currentProvider)
24
+ const gatewayOpen = useStore($gatewayState) === 'open'
25
+ const open = useStore($modelPickerOpen)
26
+
27
+ if (!gatewayOpen) {
28
+ return null
29
+ }
30
+
31
+ return (
32
+ <ModelPickerDialog
33
+ currentModel={currentModel}
34
+ currentProvider={currentProvider}
35
+ gw={gateway}
36
+ onOpenChange={setModelPickerOpen}
37
+ onSelect={onSelect}
38
+ open={open}
39
+ sessionId={activeSessionId}
40
+ />
41
+ )
42
+ }
@@ -0,0 +1,31 @@
1
+ import { useStore } from '@nanostores/react'
2
+
3
+ import { ModelVisibilityDialog } from '@/components/model-visibility-dialog'
4
+ import type { NasTechGateway } from '@/nastech'
5
+ import { $modelVisibilityOpen, setModelVisibilityOpen } from '@/store/model-visibility'
6
+ import { $activeSessionId, $gatewayState } from '@/store/session'
7
+
8
+ interface ModelVisibilityOverlayProps {
9
+ gateway?: NasTechGateway
10
+ onOpenProviders: () => void
11
+ }
12
+
13
+ export function ModelVisibilityOverlay({ gateway, onOpenProviders }: ModelVisibilityOverlayProps) {
14
+ const activeSessionId = useStore($activeSessionId)
15
+ const gatewayOpen = useStore($gatewayState) === 'open'
16
+ const open = useStore($modelVisibilityOpen)
17
+
18
+ if (!gatewayOpen) {
19
+ return null
20
+ }
21
+
22
+ return (
23
+ <ModelVisibilityDialog
24
+ gw={gateway}
25
+ onOpenChange={setModelVisibilityOpen}
26
+ onOpenProviders={onOpenProviders}
27
+ open={open}
28
+ sessionId={activeSessionId}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,66 @@
1
+ import type { ButtonHTMLAttributes, ComponentProps, ReactNode } from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ export const overlayCardClass =
6
+ 'rounded-lg border border-[color-mix(in_srgb,var(--dt-border)_52%,transparent)] bg-[color-mix(in_srgb,var(--dt-card)_72%,transparent)] shadow-[inset_0_0.0625rem_0_color-mix(in_srgb,white_34%,transparent)]'
7
+
8
+ interface OverlayCardProps extends ComponentProps<'div'> {
9
+ children: ReactNode
10
+ }
11
+
12
+ interface OverlayActionButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
13
+ tone?: 'default' | 'danger' | 'subtle'
14
+ }
15
+
16
+ export function OverlayCard({ children, className, ...props }: OverlayCardProps) {
17
+ return (
18
+ <div className={cn(overlayCardClass, className)} {...props}>
19
+ {children}
20
+ </div>
21
+ )
22
+ }
23
+
24
+ export function OverlayActionButton({
25
+ children,
26
+ className,
27
+ tone = 'default',
28
+ type = 'button',
29
+ ...props
30
+ }: OverlayActionButtonProps) {
31
+ return (
32
+ <button
33
+ className={cn(
34
+ 'inline-flex h-8 items-center rounded-md border px-3 text-xs font-medium transition-colors disabled:cursor-default disabled:opacity-45',
35
+ tone === 'default' &&
36
+ 'border-[color-mix(in_srgb,var(--dt-border)_55%,transparent)] bg-[color-mix(in_srgb,var(--dt-card)_80%,transparent)] text-foreground hover:bg-[color-mix(in_srgb,var(--dt-muted)_46%,var(--dt-card))]',
37
+ tone === 'subtle' &&
38
+ 'h-7 border-transparent px-2 text-muted-foreground hover:border-[color-mix(in_srgb,var(--dt-border)_54%,transparent)] hover:bg-[color-mix(in_srgb,var(--dt-card)_72%,transparent)] hover:text-foreground',
39
+ tone === 'danger' &&
40
+ 'h-7 border-transparent px-2 text-destructive hover:border-[color-mix(in_srgb,var(--dt-destructive)_40%,transparent)] hover:bg-[color-mix(in_srgb,var(--dt-destructive)_10%,transparent)] hover:text-destructive',
41
+ className
42
+ )}
43
+ type={type}
44
+ {...props}
45
+ >
46
+ {children}
47
+ </button>
48
+ )
49
+ }
50
+
51
+ interface OverlayIconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
52
+ children: ReactNode
53
+ }
54
+
55
+ export function OverlayIconButton({ children, className, type = 'button', ...props }: OverlayIconButtonProps) {
56
+ return (
57
+ <OverlayActionButton
58
+ className={cn('h-7 w-7 justify-center px-0 [&_svg]:size-4', className)}
59
+ tone="subtle"
60
+ type={type}
61
+ {...props}
62
+ >
63
+ {children}
64
+ </OverlayActionButton>
65
+ )
66
+ }
@@ -0,0 +1,33 @@
1
+ import type { RefObject } from 'react'
2
+
3
+ import { SearchField } from '@/components/ui/search-field'
4
+
5
+ interface OverlaySearchInputProps {
6
+ containerClassName?: string
7
+ inputRef?: RefObject<HTMLInputElement | null>
8
+ loading?: boolean
9
+ onChange: (value: string) => void
10
+ placeholder: string
11
+ value: string
12
+ }
13
+
14
+ // Borderless underline search — matches the tools/skills page (PageSearchShell).
15
+ export function OverlaySearchInput({
16
+ containerClassName,
17
+ inputRef,
18
+ loading = false,
19
+ onChange,
20
+ placeholder,
21
+ value
22
+ }: OverlaySearchInputProps) {
23
+ return (
24
+ <SearchField
25
+ containerClassName={containerClassName}
26
+ inputRef={inputRef}
27
+ loading={loading}
28
+ onChange={onChange}
29
+ placeholder={placeholder}
30
+ value={value}
31
+ />
32
+ )
33
+ }
@@ -0,0 +1,130 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { Button } from '@/components/ui/button'
4
+ import { Codicon } from '@/components/ui/codicon'
5
+ import type { IconComponent } from '@/lib/icons'
6
+ import { cn } from '@/lib/utils'
7
+
8
+ import { PAGE_INSET_X } from '../layout-constants'
9
+
10
+ interface OverlaySplitLayoutProps {
11
+ children: ReactNode
12
+ className?: string
13
+ }
14
+
15
+ interface OverlaySidebarProps {
16
+ children: ReactNode
17
+ className?: string
18
+ }
19
+
20
+ interface OverlayMainProps {
21
+ children: ReactNode
22
+ className?: string
23
+ }
24
+
25
+ interface OverlayNavItemProps {
26
+ active: boolean
27
+ icon: IconComponent
28
+ label: string
29
+ // Renders as an indented child of another nav item: smaller icon and a
30
+ // lighter active state so it never competes with the boxed parent item.
31
+ nested?: boolean
32
+ onClick: () => void
33
+ trailing?: ReactNode
34
+ }
35
+
36
+ export function OverlaySplitLayout({ children, className }: OverlaySplitLayoutProps) {
37
+ return (
38
+ <div
39
+ className={cn(
40
+ 'grid h-full min-h-0 flex-1 grid-cols-[13rem_minmax(0,1fr)] overflow-hidden bg-transparent max-[47.5rem]:grid-cols-1',
41
+ className
42
+ )}
43
+ >
44
+ {children}
45
+ </div>
46
+ )
47
+ }
48
+
49
+ export function OverlaySidebar({ children, className }: OverlaySidebarProps) {
50
+ return (
51
+ <aside
52
+ className={cn(
53
+ // pt clears the floating titlebar/header; the bg itself fills from the
54
+ // card's top edge so there's no surface-colored gap above the sidebar.
55
+ 'flex min-h-0 flex-col gap-0.5 overflow-y-auto bg-(--ui-sidebar-surface-background) px-2.5 pb-3 pt-[calc(var(--titlebar-height)+1rem)]',
56
+ className
57
+ )}
58
+ >
59
+ {children}
60
+ </aside>
61
+ )
62
+ }
63
+
64
+ export function OverlayMain({ children, className }: OverlayMainProps) {
65
+ return (
66
+ <main
67
+ className={cn(
68
+ 'flex min-h-0 flex-1 flex-col overflow-hidden bg-transparent pb-3 pt-[calc(var(--titlebar-height)+1rem)]',
69
+ PAGE_INSET_X,
70
+ className
71
+ )}
72
+ >
73
+ {children}
74
+ </main>
75
+ )
76
+ }
77
+
78
+ // Boxless "+ New …" action that tops an OverlaySidebar list (profiles, cron, …).
79
+ // The text variant underlines on hover, which also strokes the icon glyph — so
80
+ // we keep the button itself underline-free and underline only the label span.
81
+ export function OverlayNewButton({
82
+ icon = 'add',
83
+ label,
84
+ onClick
85
+ }: {
86
+ icon?: string
87
+ label: string
88
+ onClick: () => void
89
+ }) {
90
+ return (
91
+ <Button
92
+ className="group mb-1 w-full justify-start gap-2 text-muted-foreground hover:bg-transparent hover:text-foreground"
93
+ onClick={onClick}
94
+ size="sm"
95
+ variant="ghost"
96
+ >
97
+ <Codicon name={icon} />
98
+ <span className="underline-offset-4 group-hover:underline">{label}</span>
99
+ </Button>
100
+ )
101
+ }
102
+
103
+ export function OverlayNavItem({ active, icon: Icon, label, nested, onClick, trailing }: OverlayNavItemProps) {
104
+ return (
105
+ <button
106
+ className={cn(
107
+ 'flex h-7 w-full items-center justify-start gap-2 rounded-md border px-2 text-left text-[length:var(--conversation-text-font-size)] font-normal transition-colors',
108
+ nested
109
+ ? active
110
+ ? 'border-transparent bg-(--chrome-action-hover) font-medium text-foreground'
111
+ : 'border-transparent bg-transparent text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground'
112
+ : active
113
+ ? 'border-(--ui-stroke-tertiary) bg-(--ui-bg-tertiary) text-foreground'
114
+ : 'border-transparent bg-transparent text-(--ui-text-secondary) hover:bg-(--chrome-action-hover) hover:text-foreground'
115
+ )}
116
+ onClick={onClick}
117
+ type="button"
118
+ >
119
+ <Icon
120
+ className={cn(
121
+ 'shrink-0',
122
+ nested ? 'size-3.5' : 'size-4',
123
+ active ? 'text-foreground/80' : 'text-muted-foreground/80'
124
+ )}
125
+ />
126
+ <span className="min-w-0 flex-1 truncate">{label}</span>
127
+ {trailing}
128
+ </button>
129
+ )
130
+ }
@@ -0,0 +1,91 @@
1
+ import { type ReactNode, useEffect } from 'react'
2
+
3
+ import { Button } from '@/components/ui/button'
4
+ import { Codicon } from '@/components/ui/codicon'
5
+ import { translateNow } from '@/i18n'
6
+ import { triggerHaptic } from '@/lib/haptics'
7
+ import { cn } from '@/lib/utils'
8
+
9
+ interface OverlayViewProps {
10
+ children: ReactNode
11
+ onClose: () => void
12
+ closeLabel?: string
13
+ contentClassName?: string
14
+ headerContent?: ReactNode
15
+ rootClassName?: string
16
+ }
17
+
18
+ export function OverlayView({
19
+ children,
20
+ onClose,
21
+ closeLabel = translateNow('common.close'),
22
+ contentClassName,
23
+ headerContent,
24
+ rootClassName
25
+ }: OverlayViewProps) {
26
+ const closeOverlay = () => {
27
+ triggerHaptic('close')
28
+ onClose()
29
+ }
30
+
31
+ // Esc dismisses every OverlayView-based overlay. Nested Radix dialogs
32
+ // stop propagation themselves, so opening (e.g.) the model picker inside
33
+ // Settings still closes the picker first instead of the underlying overlay.
34
+ useEffect(() => {
35
+ const onKeyDown = (event: KeyboardEvent) => {
36
+ if (event.key !== 'Escape' || event.defaultPrevented) {
37
+ return
38
+ }
39
+
40
+ event.preventDefault()
41
+ triggerHaptic('close')
42
+ onClose()
43
+ }
44
+
45
+ window.addEventListener('keydown', onKeyDown)
46
+
47
+ return () => window.removeEventListener('keydown', onKeyDown)
48
+ }, [onClose])
49
+
50
+ return (
51
+ <div
52
+ className="fixed inset-0 z-50 bg-black/22 p-3 backdrop-blur-[0.125rem] sm:p-6"
53
+ onClick={event => {
54
+ if (event.target === event.currentTarget) {
55
+ closeOverlay()
56
+ }
57
+ }}
58
+ role="presentation"
59
+ >
60
+ <div
61
+ className={cn(
62
+ 'relative flex h-full min-h-0 flex-col overflow-hidden rounded-xl border border-(--ui-stroke-secondary) bg-(--ui-chat-surface-background) shadow-md',
63
+ rootClassName
64
+ )}
65
+ >
66
+ <div className="pointer-events-none absolute inset-x-0 top-0 z-10 h-[calc(var(--titlebar-height)+0.1875rem)] [-webkit-app-region:drag]">
67
+ {headerContent && (
68
+ <div className="pointer-events-auto absolute left-1/2 top-[calc(0.5rem+var(--titlebar-height)/2)] -translate-x-1/2 -translate-y-1/2 [-webkit-app-region:no-drag]">
69
+ {headerContent}
70
+ </div>
71
+ )}
72
+
73
+ <Button
74
+ aria-label={closeLabel}
75
+ className="pointer-events-auto absolute right-3 top-[calc(0.1875rem+var(--titlebar-height)/2)] -translate-y-1/2 text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground [-webkit-app-region:no-drag]"
76
+ onClick={closeOverlay}
77
+ size="icon-titlebar"
78
+ variant="ghost"
79
+ >
80
+ <Codicon name="close" size="1rem" />
81
+ </Button>
82
+ </div>
83
+
84
+ {/* No top padding here: the split-layout columns own their own
85
+ titlebar clearance so their backgrounds run flush to the card top
86
+ (otherwise the card surface shows as a gap above the sidebar). */}
87
+ <div className={cn('min-h-0 flex flex-1 flex-col', contentClassName)}>{children}</div>
88
+ </div>
89
+ </div>
90
+ )
91
+ }
@@ -0,0 +1,75 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { SearchField } from '@/components/ui/search-field'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ interface PageSearchShellProps extends React.ComponentProps<'section'> {
7
+ children: ReactNode
8
+ /** Primary tabs shown on the top row, beside the search. */
9
+ tabs?: ReactNode
10
+ /** Secondary filters shown full-width on their own row below (expands). */
11
+ filters?: ReactNode
12
+ onSearchChange: (value: string) => void
13
+ searchPlaceholder: string
14
+ searchTrailingAction?: ReactNode
15
+ searchValue: string
16
+ /** Hide the search field when there's nothing to search (empty dataset). */
17
+ searchHidden?: boolean
18
+ }
19
+
20
+ export function PageSearchShell({
21
+ children,
22
+ className,
23
+ tabs,
24
+ filters,
25
+ onSearchChange,
26
+ searchPlaceholder,
27
+ searchTrailingAction,
28
+ searchValue,
29
+ searchHidden = false,
30
+ ...props
31
+ }: PageSearchShellProps) {
32
+ return (
33
+ <section
34
+ {...props}
35
+ className={cn('flex h-full min-w-0 flex-col overflow-hidden bg-(--ui-chat-surface-background)', className)}
36
+ >
37
+ {/*
38
+ Header lives in the page body, below the window chrome (the shell floats
39
+ traffic lights over the top titlebar-height strip, which the `pt` clears
40
+ and leaves draggable). Top row: primary tabs + search. Second row:
41
+ secondary filters, full-width so they expand. Interactive bits opt out
42
+ of the drag region.
43
+ */}
44
+ {/*
45
+ IMPORTANT: do NOT put `-webkit-app-region: drag` on this header. It spans
46
+ full width over the band where the floating titlebar icon clusters live,
47
+ and an overlapping OS drag region eats their clicks at the compositor
48
+ level (pointer-events / no-drag carve-outs across separate stacking
49
+ contexts don't reliably fix it on macOS). The shell already supplies a
50
+ draggable titlebar strip that is `calc()`'d around the icon clusters
51
+ (see app-shell.tsx), so window dragging still works here.
52
+ */}
53
+ <div className="shrink-0">
54
+ {(tabs || !searchHidden) && (
55
+ <div className="flex items-center gap-3 px-3 pb-2 pt-[calc(var(--titlebar-height)+0.5rem)]">
56
+ {tabs ? <div className="flex min-w-0 flex-1 flex-wrap items-center gap-x-2 gap-y-1">{tabs}</div> : null}
57
+ {!searchHidden && (
58
+ <div className={cn('flex shrink-0 items-center', !tabs && 'flex-1')}>
59
+ <SearchField
60
+ containerClassName="max-w-[45vw]"
61
+ onChange={onSearchChange}
62
+ placeholder={searchPlaceholder}
63
+ trailingAction={searchTrailingAction}
64
+ value={searchValue}
65
+ />
66
+ </div>
67
+ )}
68
+ </div>
69
+ )}
70
+ {filters ? <div className="flex flex-wrap items-center gap-x-2 gap-y-1 px-3 pb-2">{filters}</div> : null}
71
+ </div>
72
+ <div className="min-h-0 flex-1 overflow-hidden bg-(--ui-chat-surface-background)">{children}</div>
73
+ </section>
74
+ )
75
+ }