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.
- package/.prettierrc +11 -0
- package/DESIGN.md +167 -0
- package/README.md +141 -0
- package/assets/icon.icns +0 -0
- package/assets/icon.ico +0 -0
- package/assets/icon.png +0 -0
- package/components.json +21 -0
- package/electron/backend-env.cjs +112 -0
- package/electron/backend-env.test.cjs +111 -0
- package/electron/backend-probes.cjs +106 -0
- package/electron/backend-probes.test.cjs +82 -0
- package/electron/backend-ready.cjs +66 -0
- package/electron/bootstrap-platform.cjs +91 -0
- package/electron/bootstrap-platform.test.cjs +111 -0
- package/electron/bootstrap-runner.cjs +720 -0
- package/electron/bootstrap-runner.test.cjs +138 -0
- package/electron/connection-config.cjs +254 -0
- package/electron/connection-config.test.cjs +329 -0
- package/electron/dashboard-token.cjs +99 -0
- package/electron/dashboard-token.test.cjs +142 -0
- package/electron/desktop-uninstall.cjs +232 -0
- package/electron/desktop-uninstall.test.cjs +246 -0
- package/electron/entitlements.mac.inherit.plist +14 -0
- package/electron/entitlements.mac.plist +14 -0
- package/electron/fs-read-dir.cjs +109 -0
- package/electron/fs-read-dir.test.cjs +364 -0
- package/electron/gateway-ws-probe.cjs +188 -0
- package/electron/gateway-ws-probe.test.cjs +122 -0
- package/electron/git-root.cjs +54 -0
- package/electron/git-root.test.cjs +40 -0
- package/electron/git-worktrees.cjs +174 -0
- package/electron/hardening.cjs +184 -0
- package/electron/hardening.test.cjs +116 -0
- package/electron/main.cjs +5762 -0
- package/electron/oauth-net-request.cjs +20 -0
- package/electron/oauth-net-request.test.cjs +34 -0
- package/electron/preload.cjs +135 -0
- package/electron/session-windows.cjs +99 -0
- package/electron/session-windows.test.cjs +177 -0
- package/electron/update-remote.cjs +56 -0
- package/electron/update-remote.test.cjs +78 -0
- package/electron/vscode-marketplace.cjs +331 -0
- package/electron/vscode-marketplace.test.cjs +113 -0
- package/electron/windows-child-process.test.cjs +57 -0
- package/electron/windows-user-env.cjs +76 -0
- package/electron/windows-user-env.test.cjs +90 -0
- package/electron/workspace-cwd.cjs +38 -0
- package/electron/workspace-cwd.test.cjs +45 -0
- package/eslint.config.mjs +122 -0
- package/index.html +17 -0
- package/package.json +254 -0
- package/pr-assets/session-source-folders.png +0 -0
- package/preview-demo.html +65 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/ds-assets/filler-bg0.jpg +0 -0
- package/public/nastech-frames/nastech-frame-0.png +0 -0
- package/public/nastech-frames/nastech-frame-1.png +0 -0
- package/public/nastech-frames/nastech-frame-2.png +0 -0
- package/public/nastech-frames/nastech-frame-3.png +0 -0
- package/public/nastech-frames/nastech-frame-4.png +0 -0
- package/public/nastech-frames/nastech-frame-5.png +0 -0
- package/public/nastech-frames/nastech-frame-6.png +0 -0
- package/public/nastech-frames/nastech-frame-7.png +0 -0
- package/public/nastech-girl.jpg +0 -0
- package/public/nastech-sprite.png +0 -0
- package/public/nastech.png +0 -0
- package/scripts/after-pack.cjs +41 -0
- package/scripts/assert-dist-built.cjs +70 -0
- package/scripts/assert-dist-built.test.cjs +84 -0
- package/scripts/assert-root-install.cjs +13 -0
- package/scripts/before-build.cjs +11 -0
- package/scripts/before-pack.cjs +78 -0
- package/scripts/before-pack.test.cjs +53 -0
- package/scripts/click-session.mjs +51 -0
- package/scripts/dev-no-hmr.mjs +22 -0
- package/scripts/diag-jump.mjs +115 -0
- package/scripts/diag-scroll-reset.mjs +229 -0
- package/scripts/eval.mjs +21 -0
- package/scripts/leak-typing.mjs +222 -0
- package/scripts/measure-jump.mjs +108 -0
- package/scripts/measure-latency.mjs +184 -0
- package/scripts/measure-real-stream.mjs +252 -0
- package/scripts/measure-submit.mjs +179 -0
- package/scripts/measure-synthetic-stream.mjs +322 -0
- package/scripts/notarize-artifact.cjs +77 -0
- package/scripts/notarize.cjs +100 -0
- package/scripts/patch-electron-builder-mac-binary.cjs +59 -0
- package/scripts/probe-renderer.mjs +38 -0
- package/scripts/probe-thread.mjs +40 -0
- package/scripts/profile-long-stream.mjs +191 -0
- package/scripts/profile-real-stream.mjs +137 -0
- package/scripts/profile-synth-stream.mjs +103 -0
- package/scripts/profile-typing-lag.md +381 -0
- package/scripts/profile-typing.mjs +260 -0
- package/scripts/reload-renderer.mjs +25 -0
- package/scripts/reload.mjs +36 -0
- package/scripts/set-exe-identity.cjs +94 -0
- package/scripts/stage-native-deps.cjs +159 -0
- package/scripts/test-desktop.mjs +425 -0
- package/scripts/write-build-stamp.cjs +126 -0
- package/src/app/agents/index.tsx +398 -0
- package/src/app/artifacts/index.test.ts +62 -0
- package/src/app/artifacts/index.tsx +906 -0
- package/src/app/chat/chat-drop-overlay.tsx +48 -0
- package/src/app/chat/chat-swap-overlay.tsx +47 -0
- package/src/app/chat/composer/attachments.tsx +114 -0
- package/src/app/chat/composer/completion-drawer.tsx +63 -0
- package/src/app/chat/composer/context-menu.tsx +172 -0
- package/src/app/chat/composer/controls.tsx +289 -0
- package/src/app/chat/composer/drop-affordance.ts +2 -0
- package/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
- package/src/app/chat/composer/focus.ts +134 -0
- package/src/app/chat/composer/help-hint.tsx +59 -0
- package/src/app/chat/composer/hooks/use-at-completions.ts +141 -0
- package/src/app/chat/composer/hooks/use-live-completion-adapter.ts +119 -0
- package/src/app/chat/composer/hooks/use-mic-recorder.ts +291 -0
- package/src/app/chat/composer/hooks/use-slash-completions.ts +114 -0
- package/src/app/chat/composer/hooks/use-voice-conversation.ts +390 -0
- package/src/app/chat/composer/hooks/use-voice-recorder.ts +116 -0
- package/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
- package/src/app/chat/composer/index.tsx +1611 -0
- package/src/app/chat/composer/inline-refs.ts +138 -0
- package/src/app/chat/composer/model-pill.tsx +86 -0
- package/src/app/chat/composer/queue-panel.tsx +130 -0
- package/src/app/chat/composer/rich-editor.test.ts +18 -0
- package/src/app/chat/composer/rich-editor.ts +165 -0
- package/src/app/chat/composer/skin-slash-popover.tsx +61 -0
- package/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
- package/src/app/chat/composer/status-stack/index.tsx +202 -0
- package/src/app/chat/composer/status-stack/status-row.tsx +155 -0
- package/src/app/chat/composer/text-utils.test.ts +77 -0
- package/src/app/chat/composer/text-utils.ts +107 -0
- package/src/app/chat/composer/trigger-popover.test.tsx +42 -0
- package/src/app/chat/composer/trigger-popover.tsx +116 -0
- package/src/app/chat/composer/types.ts +64 -0
- package/src/app/chat/composer/url-dialog.tsx +82 -0
- package/src/app/chat/composer/voice-activity.tsx +252 -0
- package/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
- package/src/app/chat/hooks/use-composer-actions.ts +525 -0
- package/src/app/chat/hooks/use-file-drop-zone.ts +118 -0
- package/src/app/chat/index.tsx +390 -0
- package/src/app/chat/perf-probe.tsx +269 -0
- package/src/app/chat/right-rail/index.ts +1 -0
- package/src/app/chat/right-rail/preview-console-state.ts +82 -0
- package/src/app/chat/right-rail/preview-console.tsx +290 -0
- package/src/app/chat/right-rail/preview-file.tsx +559 -0
- package/src/app/chat/right-rail/preview-pane.test.tsx +43 -0
- package/src/app/chat/right-rail/preview-pane.tsx +657 -0
- package/src/app/chat/right-rail/preview.tsx +171 -0
- package/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
- package/src/app/chat/scroll-to-bottom-button.tsx +74 -0
- package/src/app/chat/sidebar/cron-jobs-section.tsx +325 -0
- package/src/app/chat/sidebar/index.tsx +1219 -0
- package/src/app/chat/sidebar/load-more-row.tsx +30 -0
- package/src/app/chat/sidebar/order.test.ts +21 -0
- package/src/app/chat/sidebar/order.ts +17 -0
- package/src/app/chat/sidebar/profile-switcher.tsx +516 -0
- package/src/app/chat/sidebar/session-actions-menu.tsx +264 -0
- package/src/app/chat/sidebar/session-row.tsx +257 -0
- package/src/app/chat/sidebar/virtual-session-list.tsx +154 -0
- package/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
- package/src/app/chat/sidebar/workspace-groups.ts +326 -0
- package/src/app/chat/thread-loading.test.ts +34 -0
- package/src/app/chat/thread-loading.ts +26 -0
- package/src/app/command-center/index.tsx +654 -0
- package/src/app/command-palette/index.tsx +513 -0
- package/src/app/command-palette/marketplace-theme-page.tsx +157 -0
- package/src/app/cron/index.tsx +942 -0
- package/src/app/cron/job-state.ts +29 -0
- package/src/app/desktop-controller.tsx +938 -0
- package/src/app/floating-hud.ts +22 -0
- package/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
- package/src/app/gateway/hooks/use-gateway-boot.ts +387 -0
- package/src/app/gateway/hooks/use-gateway-request.ts +138 -0
- package/src/app/hooks/use-keybinds.ts +186 -0
- package/src/app/hooks/use-refresh-hotkey.ts +45 -0
- package/src/app/hooks/use-route-enum-param.ts +38 -0
- package/src/app/index.tsx +1 -0
- package/src/app/layout-constants.ts +13 -0
- package/src/app/messaging/index.tsx +648 -0
- package/src/app/messaging/platform-icon.tsx +93 -0
- package/src/app/model-picker-overlay.tsx +42 -0
- package/src/app/model-visibility-overlay.tsx +31 -0
- package/src/app/overlays/overlay-chrome.tsx +66 -0
- package/src/app/overlays/overlay-search-input.tsx +33 -0
- package/src/app/overlays/overlay-split-layout.tsx +130 -0
- package/src/app/overlays/overlay-view.tsx +91 -0
- package/src/app/page-search-shell.tsx +75 -0
- package/src/app/profiles/create-profile-dialog.tsx +154 -0
- package/src/app/profiles/delete-profile-dialog.tsx +65 -0
- package/src/app/profiles/index.tsx +671 -0
- package/src/app/profiles/rename-profile-dialog.tsx +125 -0
- package/src/app/right-sidebar/files/dnd-manager.ts +27 -0
- package/src/app/right-sidebar/files/ipc.test.ts +100 -0
- package/src/app/right-sidebar/files/ipc.ts +161 -0
- package/src/app/right-sidebar/files/remote-picker.tsx +177 -0
- package/src/app/right-sidebar/files/tree.tsx +224 -0
- package/src/app/right-sidebar/files/use-project-tree.test.ts +190 -0
- package/src/app/right-sidebar/files/use-project-tree.ts +268 -0
- package/src/app/right-sidebar/index.test.tsx +75 -0
- package/src/app/right-sidebar/index.tsx +395 -0
- package/src/app/right-sidebar/store.ts +15 -0
- package/src/app/right-sidebar/terminal/buffer.ts +65 -0
- package/src/app/right-sidebar/terminal/index.tsx +98 -0
- package/src/app/right-sidebar/terminal/persistent.tsx +122 -0
- package/src/app/right-sidebar/terminal/selection.ts +75 -0
- package/src/app/right-sidebar/terminal/use-terminal-session.ts +504 -0
- package/src/app/routes.ts +88 -0
- package/src/app/session/hooks/use-context-suggestions.ts +58 -0
- package/src/app/session/hooks/use-cwd-actions.ts +109 -0
- package/src/app/session/hooks/use-message-stream.ts +957 -0
- package/src/app/session/hooks/use-model-controls.test.tsx +198 -0
- package/src/app/session/hooks/use-model-controls.ts +106 -0
- package/src/app/session/hooks/use-nastech-config.ts +74 -0
- package/src/app/session/hooks/use-preview-routing.test.tsx +168 -0
- package/src/app/session/hooks/use-preview-routing.ts +223 -0
- package/src/app/session/hooks/use-prompt-actions.test.tsx +316 -0
- package/src/app/session/hooks/use-prompt-actions.ts +1030 -0
- package/src/app/session/hooks/use-route-resume.test.tsx +136 -0
- package/src/app/session/hooks/use-route-resume.ts +115 -0
- package/src/app/session/hooks/use-session-actions.test.tsx +119 -0
- package/src/app/session/hooks/use-session-actions.ts +885 -0
- package/src/app/session/hooks/use-session-state-cache.test.tsx +118 -0
- package/src/app/session/hooks/use-session-state-cache.ts +191 -0
- package/src/app/session-picker-overlay.tsx +32 -0
- package/src/app/session-switcher.tsx +107 -0
- package/src/app/settings/about-settings.tsx +173 -0
- package/src/app/settings/appearance-settings.tsx +162 -0
- package/src/app/settings/config-settings.tsx +384 -0
- package/src/app/settings/constants.ts +545 -0
- package/src/app/settings/credential-key-ui.tsx +373 -0
- package/src/app/settings/env-credentials.tsx +198 -0
- package/src/app/settings/env-var-actions-menu.tsx +136 -0
- package/src/app/settings/field-copy.ts +56 -0
- package/src/app/settings/gateway-settings.tsx +620 -0
- package/src/app/settings/helpers.test.ts +138 -0
- package/src/app/settings/helpers.ts +151 -0
- package/src/app/settings/index.tsx +237 -0
- package/src/app/settings/keys-settings.tsx +96 -0
- package/src/app/settings/mcp-settings.tsx +271 -0
- package/src/app/settings/model-settings.test.tsx +157 -0
- package/src/app/settings/model-settings.tsx +559 -0
- package/src/app/settings/notifications-settings.tsx +150 -0
- package/src/app/settings/primitives.tsx +115 -0
- package/src/app/settings/providers-settings.test.tsx +100 -0
- package/src/app/settings/providers-settings.tsx +258 -0
- package/src/app/settings/sessions-settings.tsx +276 -0
- package/src/app/settings/toolset-config-panel.test.tsx +289 -0
- package/src/app/settings/toolset-config-panel.tsx +449 -0
- package/src/app/settings/types.ts +42 -0
- package/src/app/settings/uninstall-section.tsx +185 -0
- package/src/app/settings/use-deep-link-highlight.ts +60 -0
- package/src/app/shell/app-shell.tsx +167 -0
- package/src/app/shell/gateway-menu-panel.tsx +150 -0
- package/src/app/shell/hooks/use-overlay-routing.ts +71 -0
- package/src/app/shell/hooks/use-status-snapshot.ts +57 -0
- package/src/app/shell/hooks/use-statusbar-items.tsx +403 -0
- package/src/app/shell/keybind-panel.tsx +220 -0
- package/src/app/shell/model-edit-submenu.test.tsx +84 -0
- package/src/app/shell/model-edit-submenu.tsx +245 -0
- package/src/app/shell/model-menu-panel.tsx +295 -0
- package/src/app/shell/sidebar-label.tsx +22 -0
- package/src/app/shell/statusbar-controls.tsx +185 -0
- package/src/app/shell/titlebar-controls.tsx +244 -0
- package/src/app/shell/titlebar.test.ts +26 -0
- package/src/app/shell/titlebar.ts +45 -0
- package/src/app/shell/use-group-registry.ts +39 -0
- package/src/app/skills/index.test.tsx +103 -0
- package/src/app/skills/index.tsx +371 -0
- package/src/app/types.ts +99 -0
- package/src/app/updates-overlay.tsx +369 -0
- package/src/components/Backdrop.tsx +114 -0
- package/src/components/assistant-ui/ansi-text.tsx +34 -0
- package/src/components/assistant-ui/clarify-tool.tsx +281 -0
- package/src/components/assistant-ui/directive-text.test.ts +39 -0
- package/src/components/assistant-ui/directive-text.tsx +389 -0
- package/src/components/assistant-ui/markdown-text.test.ts +204 -0
- package/src/components/assistant-ui/markdown-text.tsx +497 -0
- package/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
- package/src/components/assistant-ui/message-render-boundary.tsx +48 -0
- package/src/components/assistant-ui/streaming.test.tsx +739 -0
- package/src/components/assistant-ui/thread-list.tsx +307 -0
- package/src/components/assistant-ui/thread-virtualizer.tsx +512 -0
- package/src/components/assistant-ui/thread.tsx +1474 -0
- package/src/components/assistant-ui/todo-tool.tsx +109 -0
- package/src/components/assistant-ui/tool-approval-group.test.tsx +158 -0
- package/src/components/assistant-ui/tool-approval.test.tsx +81 -0
- package/src/components/assistant-ui/tool-approval.tsx +209 -0
- package/src/components/assistant-ui/tool-fallback-model.test.ts +66 -0
- package/src/components/assistant-ui/tool-fallback-model.ts +1368 -0
- package/src/components/assistant-ui/tool-fallback.tsx +466 -0
- package/src/components/assistant-ui/tooltip-icon-button.tsx +33 -0
- package/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
- package/src/components/assistant-ui/user-message-text.tsx +150 -0
- package/src/components/boot-failure-overlay.tsx +246 -0
- package/src/components/boot-failure-reauth.test.ts +100 -0
- package/src/components/boot-failure-reauth.ts +81 -0
- package/src/components/brand-mark.tsx +19 -0
- package/src/components/chat/activity-timer-text.tsx +24 -0
- package/src/components/chat/activity-timer.test.tsx +43 -0
- package/src/components/chat/activity-timer.ts +64 -0
- package/src/components/chat/code-card.tsx +78 -0
- package/src/components/chat/compact-markdown.tsx +113 -0
- package/src/components/chat/composer-dock.ts +31 -0
- package/src/components/chat/diff-lines.tsx +54 -0
- package/src/components/chat/disclosure-row.tsx +63 -0
- package/src/components/chat/generated-image-context.tsx +19 -0
- package/src/components/chat/generated-image-result.tsx +174 -0
- package/src/components/chat/image-generation-placeholder.tsx +279 -0
- package/src/components/chat/intro-copy.jsonl +75 -0
- package/src/components/chat/intro.tsx +182 -0
- package/src/components/chat/preview-attachment.tsx +125 -0
- package/src/components/chat/shiki-highlighter.tsx +107 -0
- package/src/components/chat/status-row.tsx +70 -0
- package/src/components/chat/status-section.tsx +42 -0
- package/src/components/chat/terminal-output.tsx +50 -0
- package/src/components/chat/zoomable-image.tsx +177 -0
- package/src/components/desktop-install-overlay.tsx +595 -0
- package/src/components/desktop-onboarding-overlay.test.tsx +100 -0
- package/src/components/desktop-onboarding-overlay.tsx +1286 -0
- package/src/components/error-boundary.tsx +77 -0
- package/src/components/gateway-connecting-overlay.test.tsx +143 -0
- package/src/components/gateway-connecting-overlay.tsx +183 -0
- package/src/components/haptics-provider.tsx +19 -0
- package/src/components/language-switcher.test.tsx +53 -0
- package/src/components/language-switcher.tsx +175 -0
- package/src/components/model-picker.tsx +340 -0
- package/src/components/model-visibility-dialog.tsx +155 -0
- package/src/components/notifications.tsx +196 -0
- package/src/components/page-loader.tsx +34 -0
- package/src/components/pane-shell/context.ts +14 -0
- package/src/components/pane-shell/index.ts +4 -0
- package/src/components/pane-shell/pane-shell.test.tsx +333 -0
- package/src/components/pane-shell/pane-shell.tsx +330 -0
- package/src/components/prompt-overlays.tsx +234 -0
- package/src/components/session-picker.tsx +108 -0
- package/src/components/status-dot.tsx +26 -0
- package/src/components/ui/action-status.tsx +25 -0
- package/src/components/ui/alert.tsx +53 -0
- package/src/components/ui/badge.tsx +35 -0
- package/src/components/ui/braille-spinner.tsx +61 -0
- package/src/components/ui/button.tsx +81 -0
- package/src/components/ui/checkbox.tsx +27 -0
- package/src/components/ui/codicon.tsx +20 -0
- package/src/components/ui/command.tsx +111 -0
- package/src/components/ui/confirm-dialog.tsx +109 -0
- package/src/components/ui/context-menu.tsx +141 -0
- package/src/components/ui/control.ts +25 -0
- package/src/components/ui/copy-button.test.tsx +36 -0
- package/src/components/ui/copy-button.tsx +229 -0
- package/src/components/ui/dialog.tsx +152 -0
- package/src/components/ui/disclosure-caret.tsx +20 -0
- package/src/components/ui/dropdown-menu.tsx +291 -0
- package/src/components/ui/error-state.tsx +50 -0
- package/src/components/ui/fade-text.tsx +110 -0
- package/src/components/ui/glyph-spinner.tsx +63 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/kbd.tsx +37 -0
- package/src/components/ui/loader.tsx +558 -0
- package/src/components/ui/log-view.tsx +17 -0
- package/src/components/ui/pagination.tsx +114 -0
- package/src/components/ui/popover.tsx +44 -0
- package/src/components/ui/scroll-area.tsx +43 -0
- package/src/components/ui/search-field.tsx +80 -0
- package/src/components/ui/segmented-control.tsx +51 -0
- package/src/components/ui/select.tsx +92 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/sheet.tsx +116 -0
- package/src/components/ui/sidebar.tsx +674 -0
- package/src/components/ui/skeleton.tsx +7 -0
- package/src/components/ui/switch.tsx +49 -0
- package/src/components/ui/tabs.tsx +36 -0
- package/src/components/ui/text-tab.tsx +43 -0
- package/src/components/ui/textarea.tsx +11 -0
- package/src/components/ui/tool-icon.tsx +65 -0
- package/src/components/ui/tooltip.tsx +69 -0
- package/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
- package/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
- package/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
- package/src/global.d.ts +457 -0
- package/src/hooks/use-image-download.ts +85 -0
- package/src/hooks/use-media-query.ts +24 -0
- package/src/hooks/use-mobile.ts +3 -0
- package/src/hooks/use-resize-observer.ts +38 -0
- package/src/hooks/use-worktree-info.ts +68 -0
- package/src/i18n/catalog.ts +12 -0
- package/src/i18n/context.test.tsx +232 -0
- package/src/i18n/context.tsx +183 -0
- package/src/i18n/define-locale.ts +41 -0
- package/src/i18n/en.ts +1779 -0
- package/src/i18n/index.ts +20 -0
- package/src/i18n/ja.ts +1890 -0
- package/src/i18n/languages.test.ts +43 -0
- package/src/i18n/languages.ts +86 -0
- package/src/i18n/runtime.test.ts +75 -0
- package/src/i18n/runtime.ts +53 -0
- package/src/i18n/types.ts +1452 -0
- package/src/i18n/zh-hant.ts +1849 -0
- package/src/i18n/zh.ts +1923 -0
- package/src/lib/ansi.test.ts +123 -0
- package/src/lib/ansi.ts +175 -0
- package/src/lib/chat-messages.test.ts +708 -0
- package/src/lib/chat-messages.ts +885 -0
- package/src/lib/chat-runtime.test.ts +18 -0
- package/src/lib/chat-runtime.ts +335 -0
- package/src/lib/clipboard.ts +28 -0
- package/src/lib/commit-changelog.test.ts +114 -0
- package/src/lib/commit-changelog.ts +177 -0
- package/src/lib/completion-sound.ts +519 -0
- package/src/lib/desktop-fs.test.ts +116 -0
- package/src/lib/desktop-fs.ts +113 -0
- package/src/lib/desktop-slash-commands.test.ts +126 -0
- package/src/lib/desktop-slash-commands.ts +286 -0
- package/src/lib/embedded-images.test.ts +35 -0
- package/src/lib/embedded-images.ts +60 -0
- package/src/lib/external-link.test.tsx +168 -0
- package/src/lib/external-link.tsx +303 -0
- package/src/lib/gateway-events.test.ts +27 -0
- package/src/lib/gateway-events.ts +49 -0
- package/src/lib/gateway-ws-url.test.ts +78 -0
- package/src/lib/gateway-ws-url.ts +91 -0
- package/src/lib/generated-images.test.ts +97 -0
- package/src/lib/generated-images.ts +116 -0
- package/src/lib/haptics.ts +129 -0
- package/src/lib/icons.ts +203 -0
- package/src/lib/incremental-external-store-runtime.ts +188 -0
- package/src/lib/katex-memo.ts +260 -0
- package/src/lib/keybinds/actions.ts +125 -0
- package/src/lib/keybinds/combo.test.ts +86 -0
- package/src/lib/keybinds/combo.ts +169 -0
- package/src/lib/local-preview.ts +126 -0
- package/src/lib/markdown-code.test.ts +23 -0
- package/src/lib/markdown-code.ts +195 -0
- package/src/lib/markdown-preprocess.ts +386 -0
- package/src/lib/media.remote.test.ts +58 -0
- package/src/lib/media.ts +111 -0
- package/src/lib/model-status-label.test.ts +31 -0
- package/src/lib/model-status-label.ts +103 -0
- package/src/lib/mutable-ref.ts +6 -0
- package/src/lib/preview-targets.test.ts +27 -0
- package/src/lib/preview-targets.ts +63 -0
- package/src/lib/profile-color.ts +58 -0
- package/src/lib/provider-setup-errors.test.ts +26 -0
- package/src/lib/provider-setup-errors.ts +12 -0
- package/src/lib/query-client.ts +13 -0
- package/src/lib/remend-tail.test.ts +105 -0
- package/src/lib/remend-tail.ts +108 -0
- package/src/lib/runtime-readiness.test.ts +65 -0
- package/src/lib/runtime-readiness.ts +147 -0
- package/src/lib/session-export.ts +57 -0
- package/src/lib/session-search.test.ts +58 -0
- package/src/lib/session-search.ts +19 -0
- package/src/lib/session-source.ts +62 -0
- package/src/lib/speech-text.ts +35 -0
- package/src/lib/statusbar.ts +91 -0
- package/src/lib/storage.test.ts +25 -0
- package/src/lib/storage.ts +107 -0
- package/src/lib/todos.test.ts +35 -0
- package/src/lib/todos.ts +51 -0
- package/src/lib/tool-result-summary.test.ts +106 -0
- package/src/lib/tool-result-summary.ts +467 -0
- package/src/lib/update-copy.test.ts +38 -0
- package/src/lib/update-copy.ts +44 -0
- package/src/lib/use-enter-animation.ts +100 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/voice-playback.ts +128 -0
- package/src/lib/yolo-session.ts +26 -0
- package/src/main.tsx +43 -0
- package/src/nastech.test.ts +49 -0
- package/src/nastech.ts +718 -0
- package/src/store/activity.ts +100 -0
- package/src/store/boot.ts +91 -0
- package/src/store/clarify.test.ts +81 -0
- package/src/store/clarify.ts +69 -0
- package/src/store/command-palette.ts +20 -0
- package/src/store/compaction.test.ts +53 -0
- package/src/store/compaction.ts +38 -0
- package/src/store/completion-sound.ts +32 -0
- package/src/store/composer-input-history.test.ts +147 -0
- package/src/store/composer-input-history.ts +158 -0
- package/src/store/composer-queue.test.ts +148 -0
- package/src/store/composer-queue.ts +239 -0
- package/src/store/composer-status.test.ts +99 -0
- package/src/store/composer-status.ts +277 -0
- package/src/store/composer.test.ts +106 -0
- package/src/store/composer.ts +184 -0
- package/src/store/cron.ts +19 -0
- package/src/store/gateway.ts +290 -0
- package/src/store/haptics.ts +17 -0
- package/src/store/keybinds.ts +139 -0
- package/src/store/layout.ts +176 -0
- package/src/store/model-presets.test.ts +51 -0
- package/src/store/model-presets.ts +86 -0
- package/src/store/model-visibility.test.ts +37 -0
- package/src/store/model-visibility.ts +108 -0
- package/src/store/native-notifications.test.ts +192 -0
- package/src/store/native-notifications.ts +203 -0
- package/src/store/notifications.ts +165 -0
- package/src/store/onboarding.test.ts +372 -0
- package/src/store/onboarding.ts +866 -0
- package/src/store/panes.test.ts +146 -0
- package/src/store/panes.ts +145 -0
- package/src/store/preview.test.ts +135 -0
- package/src/store/preview.ts +466 -0
- package/src/store/profile.test.ts +89 -0
- package/src/store/profile.ts +365 -0
- package/src/store/prompts.test.ts +121 -0
- package/src/store/prompts.ts +115 -0
- package/src/store/session-switcher.test.ts +115 -0
- package/src/store/session-switcher.ts +128 -0
- package/src/store/session-sync.ts +25 -0
- package/src/store/session.test.ts +131 -0
- package/src/store/session.ts +255 -0
- package/src/store/subagents.test.ts +111 -0
- package/src/store/subagents.ts +260 -0
- package/src/store/thread-scroll.ts +46 -0
- package/src/store/todos.test.ts +47 -0
- package/src/store/todos.ts +64 -0
- package/src/store/tool-diffs.ts +23 -0
- package/src/store/tool-dismiss.ts +45 -0
- package/src/store/tool-view.ts +91 -0
- package/src/store/translucency.ts +38 -0
- package/src/store/updates.test.ts +77 -0
- package/src/store/updates.ts +315 -0
- package/src/store/voice-playback.ts +24 -0
- package/src/store/windows.test.ts +143 -0
- package/src/store/windows.ts +77 -0
- package/src/styles.css +1235 -0
- package/src/themes/color.ts +142 -0
- package/src/themes/context.tsx +339 -0
- package/src/themes/index.ts +3 -0
- package/src/themes/install.test.ts +119 -0
- package/src/themes/install.ts +95 -0
- package/src/themes/presets.test.ts +33 -0
- package/src/themes/presets.ts +293 -0
- package/src/themes/profile-theme.test.ts +41 -0
- package/src/themes/types.ts +66 -0
- package/src/themes/use-skin-command.ts +60 -0
- package/src/themes/user-themes.test.ts +63 -0
- package/src/themes/user-themes.ts +122 -0
- package/src/themes/vscode.test.ts +171 -0
- package/src/themes/vscode.ts +343 -0
- package/src/types/nastech.ts +646 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +56 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
|
|
4
|
+
import { Codicon } from '@/components/ui/codicon'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
// Shared class tokens for edge-to-edge menus (use with `p-0` content): rows go
|
|
8
|
+
// full-width, square, and compact so the highlight spans the whole surface.
|
|
9
|
+
// Reuse these instead of re-deriving per menu so every searchable/compact menu
|
|
10
|
+
// reads identically.
|
|
11
|
+
export const dropdownMenuRow = 'gap-2 rounded-none px-2.5 py-1 text-xs'
|
|
12
|
+
export const dropdownMenuSectionLabel = 'px-2.5 pt-1 pb-0.5 text-[0.625rem] font-medium uppercase tracking-wide'
|
|
13
|
+
|
|
14
|
+
// Keys that must reach Radix's menu handler (navigation/close). Everything else
|
|
15
|
+
// is a filter keystroke and is stopped so the menu's typeahead doesn't hijack it.
|
|
16
|
+
const DROPDOWN_NAV_KEYS = new Set(['ArrowDown', 'ArrowUp', 'Enter', 'Escape', 'Tab'])
|
|
17
|
+
|
|
18
|
+
function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
19
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
23
|
+
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
27
|
+
return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Borderless filter input for a searchable dropdown. Autofocuses, keeps the
|
|
32
|
+
* menu's typeahead from eating keystrokes, and still lets arrow/enter/escape
|
|
33
|
+
* drive the list. Drop it in as the first child of a `DropdownMenuContent`.
|
|
34
|
+
*/
|
|
35
|
+
function DropdownMenuSearch({
|
|
36
|
+
className,
|
|
37
|
+
onChange,
|
|
38
|
+
onKeyDown,
|
|
39
|
+
onValueChange,
|
|
40
|
+
...props
|
|
41
|
+
}: Omit<React.ComponentProps<'input'>, 'type'> & {
|
|
42
|
+
onValueChange?: (value: string) => void
|
|
43
|
+
}) {
|
|
44
|
+
return (
|
|
45
|
+
<div className="px-2.5 py-1.5" data-slot="dropdown-menu-search">
|
|
46
|
+
<input
|
|
47
|
+
autoFocus
|
|
48
|
+
className={cn(
|
|
49
|
+
'h-4 w-full bg-transparent text-xs leading-none text-foreground placeholder:text-(--ui-text-tertiary) focus:outline-none',
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
onChange={event => {
|
|
53
|
+
onChange?.(event)
|
|
54
|
+
onValueChange?.(event.target.value)
|
|
55
|
+
}}
|
|
56
|
+
onKeyDown={event => {
|
|
57
|
+
if (!DROPDOWN_NAV_KEYS.has(event.key)) {
|
|
58
|
+
event.stopPropagation()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onKeyDown?.(event)
|
|
62
|
+
}}
|
|
63
|
+
type="text"
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function DropdownMenuContent({
|
|
71
|
+
className,
|
|
72
|
+
collisionPadding = 8,
|
|
73
|
+
sideOffset = 4,
|
|
74
|
+
...props
|
|
75
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
76
|
+
return (
|
|
77
|
+
<DropdownMenuPrimitive.Portal>
|
|
78
|
+
<DropdownMenuPrimitive.Content
|
|
79
|
+
// `dt-portal-scrollbar` reproduces the thin themed scrollbar from
|
|
80
|
+
// `.scrollbar-dt` for portaled overlays (Radix renders this under
|
|
81
|
+
// document.body, outside #root's scope). See styles.css.
|
|
82
|
+
className={cn(
|
|
83
|
+
'dt-portal-scrollbar z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-36 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg border border-(--ui-stroke-secondary) bg-[color-mix(in_srgb,var(--ui-bg-elevated)_96%,transparent)] p-1 text-[length:var(--conversation-text-font-size)] text-popover-foreground shadow-md backdrop-blur-md data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
84
|
+
className
|
|
85
|
+
)}
|
|
86
|
+
// Keep the menu inside the viewport: Radix flips/shifts away from edges
|
|
87
|
+
// (avoidCollisions defaults on); the padding stops it kissing the edge.
|
|
88
|
+
collisionPadding={collisionPadding}
|
|
89
|
+
data-slot="dropdown-menu-content"
|
|
90
|
+
sideOffset={sideOffset}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
</DropdownMenuPrimitive.Portal>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
98
|
+
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function DropdownMenuItem({
|
|
102
|
+
className,
|
|
103
|
+
inset,
|
|
104
|
+
variant = 'default',
|
|
105
|
+
...props
|
|
106
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
107
|
+
inset?: boolean
|
|
108
|
+
variant?: 'default' | 'destructive'
|
|
109
|
+
}) {
|
|
110
|
+
return (
|
|
111
|
+
<DropdownMenuPrimitive.Item
|
|
112
|
+
className={cn(
|
|
113
|
+
"relative flex items-center gap-2 rounded-md px-2 py-1 text-xs outline-hidden select-none focus:bg-(--ui-control-active-background) focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-(--ui-text-tertiary) data-[variant=destructive]:*:[svg]:text-destructive!",
|
|
114
|
+
className
|
|
115
|
+
)}
|
|
116
|
+
data-inset={inset}
|
|
117
|
+
data-slot="dropdown-menu-item"
|
|
118
|
+
data-variant={variant}
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function DropdownMenuCheckboxItem({
|
|
125
|
+
className,
|
|
126
|
+
children,
|
|
127
|
+
checked,
|
|
128
|
+
...props
|
|
129
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
130
|
+
return (
|
|
131
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
132
|
+
checked={checked}
|
|
133
|
+
className={cn(
|
|
134
|
+
"relative flex items-center gap-2 rounded-md px-2 py-1 text-xs outline-hidden select-none focus:bg-(--ui-control-active-background) focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
135
|
+
className
|
|
136
|
+
)}
|
|
137
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
138
|
+
{...props}
|
|
139
|
+
>
|
|
140
|
+
{children}
|
|
141
|
+
<DropdownMenuPrimitive.ItemIndicator className="ml-auto flex items-center pl-2 text-foreground">
|
|
142
|
+
<Codicon name="check" size="0.75rem" />
|
|
143
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
144
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
149
|
+
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function DropdownMenuRadioItem({
|
|
153
|
+
className,
|
|
154
|
+
children,
|
|
155
|
+
...props
|
|
156
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
157
|
+
return (
|
|
158
|
+
<DropdownMenuPrimitive.RadioItem
|
|
159
|
+
className={cn(
|
|
160
|
+
"relative flex items-center gap-2 rounded-md px-2 py-1 text-xs outline-hidden select-none focus:bg-(--ui-control-active-background) focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
161
|
+
className
|
|
162
|
+
)}
|
|
163
|
+
data-slot="dropdown-menu-radio-item"
|
|
164
|
+
{...props}
|
|
165
|
+
>
|
|
166
|
+
{children}
|
|
167
|
+
<DropdownMenuPrimitive.ItemIndicator className="ml-auto flex items-center pl-2 text-foreground">
|
|
168
|
+
<Codicon name="check" size="0.75rem" />
|
|
169
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
170
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function DropdownMenuLabel({
|
|
175
|
+
className,
|
|
176
|
+
inset,
|
|
177
|
+
...props
|
|
178
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
179
|
+
inset?: boolean
|
|
180
|
+
}) {
|
|
181
|
+
return (
|
|
182
|
+
<DropdownMenuPrimitive.Label
|
|
183
|
+
className={cn('px-2 py-1 text-xs font-medium text-(--ui-text-tertiary) data-[inset]:pl-7', className)}
|
|
184
|
+
data-inset={inset}
|
|
185
|
+
data-slot="dropdown-menu-label"
|
|
186
|
+
{...props}
|
|
187
|
+
/>
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
192
|
+
return (
|
|
193
|
+
<DropdownMenuPrimitive.Separator
|
|
194
|
+
className={cn('-mx-1 my-1 h-px bg-(--ui-stroke-tertiary)', className)}
|
|
195
|
+
data-slot="dropdown-menu-separator"
|
|
196
|
+
{...props}
|
|
197
|
+
/>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
202
|
+
return (
|
|
203
|
+
<span
|
|
204
|
+
className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
|
|
205
|
+
data-slot="dropdown-menu-shortcut"
|
|
206
|
+
{...props}
|
|
207
|
+
/>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
212
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function DropdownMenuSubTrigger({
|
|
216
|
+
className,
|
|
217
|
+
inset,
|
|
218
|
+
hideChevron = false,
|
|
219
|
+
children,
|
|
220
|
+
...props
|
|
221
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
222
|
+
inset?: boolean
|
|
223
|
+
/** Suppress the trailing caret — for triggers that own their right-side affordance. */
|
|
224
|
+
hideChevron?: boolean
|
|
225
|
+
}) {
|
|
226
|
+
return (
|
|
227
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
228
|
+
className={cn(
|
|
229
|
+
"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1 text-xs outline-hidden select-none focus:bg-(--ui-control-active-background) focus:text-foreground data-[inset]:pl-7 data-[state=open]:bg-(--ui-control-active-background) data-[state=open]:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 [&_svg:not([class*='text-'])]:text-(--ui-text-tertiary)",
|
|
230
|
+
className
|
|
231
|
+
)}
|
|
232
|
+
data-inset={inset}
|
|
233
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
234
|
+
{...props}
|
|
235
|
+
>
|
|
236
|
+
{children}
|
|
237
|
+
{!hideChevron && <Codicon className="ml-auto text-(--ui-text-tertiary)" name="chevron-right" size="1rem" />}
|
|
238
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function DropdownMenuSubContent({
|
|
243
|
+
className,
|
|
244
|
+
collisionPadding = 8,
|
|
245
|
+
...props
|
|
246
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
247
|
+
return (
|
|
248
|
+
// Portal the submenu out of the parent Content so it escapes that Content's
|
|
249
|
+
// `overflow` clip. Without this, a submenu opening from a scrollable menu
|
|
250
|
+
// gets visually cut off at the parent's edges. Radix Popper still anchors
|
|
251
|
+
// it to the SubTrigger and handles collision/flip, so portaling is safe.
|
|
252
|
+
<DropdownMenuPrimitive.Portal>
|
|
253
|
+
<DropdownMenuPrimitive.SubContent
|
|
254
|
+
// `dt-portal-scrollbar` reproduces the themed scrollbar for portaled
|
|
255
|
+
// overlays (rendered under document.body). Use a fixed `max-h-80`
|
|
256
|
+
// rather than the Radix available-height variable: that variable is
|
|
257
|
+
// only published on Content, NOT SubContent — using it here collapses
|
|
258
|
+
// the submenu to 0px height.
|
|
259
|
+
className={cn(
|
|
260
|
+
'dt-portal-scrollbar z-50 max-h-80 min-w-36 origin-(--radix-dropdown-menu-content-transform-origin) overflow-y-auto rounded-lg border border-(--ui-stroke-secondary) bg-[color-mix(in_srgb,var(--ui-bg-elevated)_96%,transparent)] p-1 text-[length:var(--conversation-text-font-size)] text-popover-foreground shadow-md backdrop-blur-md data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
261
|
+
className
|
|
262
|
+
)}
|
|
263
|
+
// Flip to the other side / shift vertically when near a viewport edge
|
|
264
|
+
// (e.g. the status bar menu opening from the bottom-right corner) so
|
|
265
|
+
// the submenu never gets clipped.
|
|
266
|
+
collisionPadding={collisionPadding}
|
|
267
|
+
data-slot="dropdown-menu-sub-content"
|
|
268
|
+
{...props}
|
|
269
|
+
/>
|
|
270
|
+
</DropdownMenuPrimitive.Portal>
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export {
|
|
275
|
+
DropdownMenu,
|
|
276
|
+
DropdownMenuCheckboxItem,
|
|
277
|
+
DropdownMenuContent,
|
|
278
|
+
DropdownMenuGroup,
|
|
279
|
+
DropdownMenuItem,
|
|
280
|
+
DropdownMenuLabel,
|
|
281
|
+
DropdownMenuPortal,
|
|
282
|
+
DropdownMenuRadioGroup,
|
|
283
|
+
DropdownMenuRadioItem,
|
|
284
|
+
DropdownMenuSearch,
|
|
285
|
+
DropdownMenuSeparator,
|
|
286
|
+
DropdownMenuShortcut,
|
|
287
|
+
DropdownMenuSub,
|
|
288
|
+
DropdownMenuSubContent,
|
|
289
|
+
DropdownMenuSubTrigger,
|
|
290
|
+
DropdownMenuTrigger
|
|
291
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Codicon } from '@/components/ui/codicon'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
// The single canonical error glyph (codicon's filled error mark). Use this
|
|
7
|
+
// everywhere an error is surfaced (boundaries, dialogs, banners) so failures
|
|
8
|
+
// read identically — one icon, one color, no background chip.
|
|
9
|
+
export function ErrorIcon({ className, size = '1.75rem' }: { className?: string; size?: string }) {
|
|
10
|
+
return <Codicon className={cn('text-destructive', className)} name="error" size={size} />
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ErrorStateProps {
|
|
14
|
+
/** Optional actions row/stack rendered below the copy. */
|
|
15
|
+
children?: ReactNode
|
|
16
|
+
className?: string
|
|
17
|
+
description?: ReactNode
|
|
18
|
+
/** Defaults to a destructive AlertCircle. */
|
|
19
|
+
icon?: ReactNode
|
|
20
|
+
title: ReactNode
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Shared, presentation-only error layout: the canonical ErrorIcon (no bg chip)
|
|
24
|
+
// over a centered title + body, with an optional actions stack. Used by the
|
|
25
|
+
// React error boundary, the in-dialog update error, and the boot-failure banner
|
|
26
|
+
// so every failure reads the same. Title/description accept nodes so Radix
|
|
27
|
+
// Dialog callers can pass DialogTitle/DialogDescription for accessibility.
|
|
28
|
+
export function ErrorState({ children, className, description, icon, title }: ErrorStateProps) {
|
|
29
|
+
return (
|
|
30
|
+
<div className={cn('grid gap-5', className)}>
|
|
31
|
+
<div className="flex flex-col items-center gap-3 text-center">
|
|
32
|
+
{icon ?? <ErrorIcon />}
|
|
33
|
+
|
|
34
|
+
{typeof title === 'string' ? (
|
|
35
|
+
<h2 className="text-center text-xl font-semibold tracking-tight">{title}</h2>
|
|
36
|
+
) : (
|
|
37
|
+
title
|
|
38
|
+
)}
|
|
39
|
+
|
|
40
|
+
{typeof description === 'string' ? (
|
|
41
|
+
<p className="max-w-prose text-center text-sm leading-5 text-muted-foreground">{description}</p>
|
|
42
|
+
) : (
|
|
43
|
+
description
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
{children && <div className="grid gap-2">{children}</div>}
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { ComponentProps, CSSProperties } from 'react'
|
|
2
|
+
import { memo, useCallback, useRef, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import { useResizeObserver } from '@/hooks/use-resize-observer'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
interface FadeTextProps extends Omit<ComponentProps<'span'>, 'children'> {
|
|
8
|
+
children: React.ReactNode
|
|
9
|
+
/**
|
|
10
|
+
* Width of the fade region on the trailing edge. Accepts any CSS length.
|
|
11
|
+
* Defaults to 3rem so long strings clearly trail off — short enough to
|
|
12
|
+
* preserve readable content, long enough to feel like a deliberate fade
|
|
13
|
+
* rather than a clipped ellipsis.
|
|
14
|
+
*/
|
|
15
|
+
fadeWidth?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Single-line text that fades out instead of truncating with an ellipsis.
|
|
20
|
+
*
|
|
21
|
+
* Uses an inline mask-image so the fade resolves against whatever the parent
|
|
22
|
+
* background is — no need to know the surface color, no after-pseudo overlap.
|
|
23
|
+
* The mask is only applied when the text is actually overflowing, so short
|
|
24
|
+
* strings render as plain text without an unnecessary gradient on their tail.
|
|
25
|
+
*
|
|
26
|
+
* Layout reads (`el.scrollWidth`) are forced reflows. To avoid measuring
|
|
27
|
+
* once per parent re-render — which during streaming happens on every token —
|
|
28
|
+
* we only re-measure when the ResizeObserver fires (real size changes), not
|
|
29
|
+
* on every `children` reference change. Wrapped in `memo` with a custom
|
|
30
|
+
* comparator so scalar-string children skip re-render entirely when the text
|
|
31
|
+
* is unchanged but the parent re-rendered.
|
|
32
|
+
*/
|
|
33
|
+
function FadeTextImpl({ children, className, fadeWidth = '3rem', style, ...rest }: FadeTextProps) {
|
|
34
|
+
const ref = useRef<HTMLSpanElement>(null)
|
|
35
|
+
const [overflowing, setOverflowing] = useState(false)
|
|
36
|
+
|
|
37
|
+
const measureOverflow = useCallback(() => {
|
|
38
|
+
const el = ref.current
|
|
39
|
+
|
|
40
|
+
if (!el) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setOverflowing(el.scrollWidth - el.clientWidth > 1)
|
|
45
|
+
}, [])
|
|
46
|
+
|
|
47
|
+
useResizeObserver(measureOverflow, ref)
|
|
48
|
+
|
|
49
|
+
const maskStyle: CSSProperties = overflowing
|
|
50
|
+
? {
|
|
51
|
+
maskImage: `linear-gradient(to right, black calc(100% - ${fadeWidth}), transparent)`,
|
|
52
|
+
WebkitMaskImage: `linear-gradient(to right, black calc(100% - ${fadeWidth}), transparent)`,
|
|
53
|
+
...style
|
|
54
|
+
}
|
|
55
|
+
: (style ?? {})
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<span
|
|
59
|
+
{...rest}
|
|
60
|
+
className={cn('block min-w-0 max-w-full overflow-hidden whitespace-nowrap', className)}
|
|
61
|
+
ref={ref}
|
|
62
|
+
style={maskStyle}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</span>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function styleEqual(a: CSSProperties | undefined, b: CSSProperties | undefined) {
|
|
70
|
+
if (a === b) {
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!a || !b) {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const aKeys = Object.keys(a)
|
|
79
|
+
|
|
80
|
+
if (aKeys.length !== Object.keys(b).length) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (const k of aKeys) {
|
|
85
|
+
if ((a as Record<string, unknown>)[k] !== (b as Record<string, unknown>)[k]) {
|
|
86
|
+
return false
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const FadeText = memo(FadeTextImpl, (prev, next) => {
|
|
94
|
+
if (prev.className !== next.className) {
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (prev.fadeWidth !== next.fadeWidth) {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!styleEqual(prev.style, next.style)) {
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Cheap path: the common case is a scalar string/number child. Identity
|
|
107
|
+
// comparison is correct for any other element type (a new JSX node should
|
|
108
|
+
// force a re-render).
|
|
109
|
+
return prev.children === next.children
|
|
110
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import spinners, { type BrailleSpinnerName as SpinnerName } from 'unicode-animations'
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
export type { SpinnerName }
|
|
7
|
+
|
|
8
|
+
interface NormalisedSpinner {
|
|
9
|
+
frames: readonly string[]
|
|
10
|
+
interval: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Some spinners ship multi-character frames. Pull the first cell so each
|
|
14
|
+
// frame fits in one monospace box — matches how the TUI uses them.
|
|
15
|
+
const FRAMES_BY_NAME: Record<SpinnerName, NormalisedSpinner> = (() => {
|
|
16
|
+
const out = {} as Record<SpinnerName, NormalisedSpinner>
|
|
17
|
+
|
|
18
|
+
for (const name of Object.keys(spinners) as SpinnerName[]) {
|
|
19
|
+
const raw = spinners[name]
|
|
20
|
+
|
|
21
|
+
out[name] = {
|
|
22
|
+
frames: raw.frames.map(frame => [...frame][0] ?? '⠀'),
|
|
23
|
+
interval: raw.interval
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return out
|
|
28
|
+
})()
|
|
29
|
+
|
|
30
|
+
interface GlyphSpinnerProps {
|
|
31
|
+
ariaLabel?: string
|
|
32
|
+
className?: string
|
|
33
|
+
spinner?: SpinnerName
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* One-char glyph spinner driven by `unicode-animations` (braille, orbit, scan,
|
|
38
|
+
* etc. — pick any `spinner` name). Mirrors the spinner used by the Ink TUI so
|
|
39
|
+
* the desktop and terminal experiences read the same visually. Renders inside
|
|
40
|
+
* an `inline-flex` cell with `leading-none` and `items-center` so it sits
|
|
41
|
+
* vertically centred inside its parent's line-box.
|
|
42
|
+
*/
|
|
43
|
+
export function GlyphSpinner({ ariaLabel = 'Loading', className, spinner = 'braille' }: GlyphSpinnerProps) {
|
|
44
|
+
const spin = FRAMES_BY_NAME[spinner] ?? FRAMES_BY_NAME.braille!
|
|
45
|
+
const [frame, setFrame] = useState(0)
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
setFrame(0)
|
|
49
|
+
const id = window.setInterval(() => setFrame(f => (f + 1) % spin.frames.length), spin.interval)
|
|
50
|
+
|
|
51
|
+
return () => window.clearInterval(id)
|
|
52
|
+
}, [spin])
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<span
|
|
56
|
+
aria-label={ariaLabel}
|
|
57
|
+
className={cn('inline-flex items-center justify-center font-mono leading-none tabular-nums', className)}
|
|
58
|
+
role="status"
|
|
59
|
+
>
|
|
60
|
+
{spin.frames[frame]}
|
|
61
|
+
</span>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@/lib/utils'
|
|
4
|
+
|
|
5
|
+
import { type ControlVariantProps, controlVariants } from './control'
|
|
6
|
+
|
|
7
|
+
function Input({ className, type, size, ...props }: Omit<React.ComponentProps<'input'>, 'size'> & ControlVariantProps) {
|
|
8
|
+
return (
|
|
9
|
+
<input
|
|
10
|
+
className={cn(
|
|
11
|
+
controlVariants({ size }),
|
|
12
|
+
'selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-xs file:font-medium file:text-foreground',
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
data-slot="input"
|
|
16
|
+
type={type}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { Input }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@/lib/utils'
|
|
4
|
+
|
|
5
|
+
function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
|
|
6
|
+
return (
|
|
7
|
+
<kbd
|
|
8
|
+
className={cn(
|
|
9
|
+
'inline-grid h-4 min-w-4 place-items-center rounded-sm border border-border/70 bg-muted/45 px-1 font-mono text-[0.5625rem] font-medium leading-none text-muted-foreground shadow-xs',
|
|
10
|
+
className
|
|
11
|
+
)}
|
|
12
|
+
data-slot="kbd"
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface KbdGroupProps extends Omit<React.ComponentProps<'span'>, 'children'> {
|
|
19
|
+
keys: string[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function KbdGroup({ className, keys, ...props }: KbdGroupProps) {
|
|
23
|
+
return (
|
|
24
|
+
<span
|
|
25
|
+
aria-label={keys.join(' ')}
|
|
26
|
+
className={cn('inline-flex shrink-0 items-center gap-0.5 opacity-55', className)}
|
|
27
|
+
data-slot="kbd-group"
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
{keys.map(key => (
|
|
31
|
+
<Kbd key={key}>{key}</Kbd>
|
|
32
|
+
))}
|
|
33
|
+
</span>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { Kbd, KbdGroup }
|