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,25 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Check, Loader2 } from '@/lib/icons'
|
|
4
|
+
|
|
5
|
+
// idle → saving → done label+icon for action buttons (create / rename / delete…).
|
|
6
|
+
export function ActionStatus({
|
|
7
|
+
state,
|
|
8
|
+
idle,
|
|
9
|
+
busy,
|
|
10
|
+
done,
|
|
11
|
+
idleIcon = null
|
|
12
|
+
}: {
|
|
13
|
+
state: 'done' | 'idle' | 'saving'
|
|
14
|
+
idle: string
|
|
15
|
+
busy: string
|
|
16
|
+
done: string
|
|
17
|
+
idleIcon?: ReactNode
|
|
18
|
+
}) {
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
{state === 'saving' ? <Loader2 className="animate-spin" /> : state === 'done' ? <Check /> : idleIcon}
|
|
22
|
+
{state === 'saving' ? busy : state === 'done' ? done : idle}
|
|
23
|
+
</>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
'relative grid w-full grid-cols-[auto_minmax(0,1fr)] items-start gap-x-3 gap-y-1 rounded-lg border bg-card px-4 py-3 text-sm text-card-foreground shadow-xs [&>svg]:mt-0.5 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'border-border',
|
|
12
|
+
destructive:
|
|
13
|
+
'border-destructive/35 bg-[color-mix(in_srgb,var(--dt-card)_96%,var(--dt-destructive)_4%)] [&>svg]:text-destructive',
|
|
14
|
+
warning:
|
|
15
|
+
'border-primary/30 bg-[color-mix(in_srgb,var(--dt-card)_96%,var(--dt-primary)_4%)] [&>svg]:text-primary',
|
|
16
|
+
success:
|
|
17
|
+
'border-primary/25 bg-[color-mix(in_srgb,var(--dt-card)_97%,var(--dt-primary)_3%)] [&>svg]:text-primary'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
function Alert({ className, variant, ...props }: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
|
|
27
|
+
return <div className={cn(alertVariants({ variant }), className)} data-slot="alert" role="alert" {...props} />
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className={cn('col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight text-foreground', className)}
|
|
34
|
+
data-slot="alert-title"
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className={cn(
|
|
44
|
+
'col-start-2 grid justify-items-start gap-1 text-muted-foreground [&_p]:leading-relaxed',
|
|
45
|
+
className
|
|
46
|
+
)}
|
|
47
|
+
data-slot="alert-description"
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { Alert, AlertDescription, AlertTitle }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { Slot } from 'radix-ui'
|
|
3
|
+
import type * as React from 'react'
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
// Small status/metadata tag. App radius (not a full pill); tones map to the
|
|
8
|
+
// shared accent/muted/destructive surfaces so badges read consistently.
|
|
9
|
+
const badgeVariants = cva(
|
|
10
|
+
'inline-flex w-fit shrink-0 items-center gap-1 rounded-[3px] px-1.5 py-0.5 text-[0.65rem] font-medium leading-none whitespace-nowrap [&_svg]:size-3 [&_svg]:pointer-events-none',
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: 'bg-primary/10 text-primary',
|
|
15
|
+
muted: 'bg-muted text-muted-foreground',
|
|
16
|
+
warn: 'bg-amber-500/10 text-amber-600 dark:text-amber-300',
|
|
17
|
+
destructive: 'bg-destructive/10 text-destructive',
|
|
18
|
+
outline: 'border border-(--ui-stroke-secondary) text-muted-foreground'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: { variant: 'default' }
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export interface BadgeProps extends React.ComponentProps<'span'>, VariantProps<typeof badgeVariants> {
|
|
26
|
+
asChild?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Badge({ asChild = false, className, variant, ...props }: BadgeProps) {
|
|
30
|
+
const Comp = asChild ? Slot.Root : 'span'
|
|
31
|
+
|
|
32
|
+
return <Comp className={cn(badgeVariants({ variant }), className)} data-slot="badge" {...props} />
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { badgeVariants }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import spinners, { type BrailleSpinnerName } from 'unicode-animations'
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
interface NormalisedSpinner {
|
|
7
|
+
frames: readonly string[]
|
|
8
|
+
interval: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Some spinners ship multi-character frames. Pull the first cell so each
|
|
12
|
+
// frame fits in one monospace box — matches how the TUI uses them.
|
|
13
|
+
const FRAMES_BY_NAME: Record<BrailleSpinnerName, NormalisedSpinner> = (() => {
|
|
14
|
+
const out = {} as Record<BrailleSpinnerName, NormalisedSpinner>
|
|
15
|
+
|
|
16
|
+
for (const name of Object.keys(spinners) as BrailleSpinnerName[]) {
|
|
17
|
+
const raw = spinners[name]
|
|
18
|
+
|
|
19
|
+
out[name] = {
|
|
20
|
+
frames: raw.frames.map(frame => [...frame][0] ?? '⠀'),
|
|
21
|
+
interval: raw.interval
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return out
|
|
26
|
+
})()
|
|
27
|
+
|
|
28
|
+
interface BrailleSpinnerProps {
|
|
29
|
+
ariaLabel?: string
|
|
30
|
+
className?: string
|
|
31
|
+
spinner?: BrailleSpinnerName
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* One-char braille spinner driven by `unicode-animations`. Mirrors the
|
|
36
|
+
* spinner used by the Ink TUI so the desktop and terminal experiences
|
|
37
|
+
* read the same visually. Renders inside an `inline-flex` cell with
|
|
38
|
+
* `leading-none` and `items-center` so it sits vertically centred inside
|
|
39
|
+
* its parent's line-box (e.g. the 1.1rem disclosure row).
|
|
40
|
+
*/
|
|
41
|
+
export function BrailleSpinner({ ariaLabel = 'Loading', className, spinner = 'breathe' }: BrailleSpinnerProps) {
|
|
42
|
+
const spin = FRAMES_BY_NAME[spinner] ?? FRAMES_BY_NAME.breathe!
|
|
43
|
+
const [frame, setFrame] = useState(0)
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
setFrame(0)
|
|
47
|
+
const id = window.setInterval(() => setFrame(f => (f + 1) % spin.frames.length), spin.interval)
|
|
48
|
+
|
|
49
|
+
return () => window.clearInterval(id)
|
|
50
|
+
}, [spin])
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<span
|
|
54
|
+
aria-label={ariaLabel}
|
|
55
|
+
className={cn('inline-flex items-center justify-center font-mono leading-none tabular-nums', className)}
|
|
56
|
+
role="status"
|
|
57
|
+
>
|
|
58
|
+
{spin.frames[frame]}
|
|
59
|
+
</span>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
2
|
+
import { Slot } from 'radix-ui'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
// Text buttons are square (no radius) and sized by padding + line-height — no
|
|
8
|
+
// fixed heights — so they stay snug and scale with content. Only icon buttons
|
|
9
|
+
// (inherently square) carry the shared 4px radius.
|
|
10
|
+
const buttonVariants = cva(
|
|
11
|
+
"inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 rounded-[2.5px] text-xs leading-4 font-medium whitespace-nowrap shadow-none transition-all duration-100 outline-none focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-default disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
16
|
+
destructive:
|
|
17
|
+
'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',
|
|
18
|
+
// Quiet action — transparent fill with a 1.5px inset ring (no layout-shifting border).
|
|
19
|
+
outline:
|
|
20
|
+
'bg-transparent text-(--ui-text-primary) shadow-[inset_0_0_0_1px_color-mix(in_srgb,var(--ui-stroke-secondary)_50%,transparent)] hover:bg-(--chrome-action-hover) hover:text-(--ui-text-primary)',
|
|
21
|
+
// Soft-fill action (the default "non-primary button" look).
|
|
22
|
+
secondary:
|
|
23
|
+
'bg-(--ui-bg-quaternary) text-(--ui-text-primary) hover:bg-(--chrome-action-hover) hover:text-(--ui-text-primary)',
|
|
24
|
+
ghost: 'text-(--ui-text-secondary) hover:bg-(--chrome-action-hover) hover:text-(--ui-text-primary)',
|
|
25
|
+
link: 'text-primary underline-offset-4 decoration-current/20 hover:underline',
|
|
26
|
+
// Boxless inline-text action (no bg/border). Quiet by default — reads as
|
|
27
|
+
// muted label text, underlines on hover (e.g. "Cancel", "Clear").
|
|
28
|
+
text: 'text-muted-foreground underline-offset-4 hover:text-foreground hover:underline',
|
|
29
|
+
// Emphasized inline-text action: bold + always-underlined link. Use for
|
|
30
|
+
// the actionable affordance in a row ("Change", "Set", "Open logs", …).
|
|
31
|
+
textStrong: 'font-semibold text-muted-foreground underline underline-offset-4 hover:text-foreground'
|
|
32
|
+
},
|
|
33
|
+
size: {
|
|
34
|
+
default: 'px-3 py-1.5 has-[>svg]:px-2.5',
|
|
35
|
+
xs: "gap-1 px-2 py-0.5 text-[0.6875rem] leading-4 has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
36
|
+
sm: 'px-2.5 py-1 has-[>svg]:px-2',
|
|
37
|
+
lg: 'px-5 py-2 text-sm leading-5 has-[>svg]:px-4',
|
|
38
|
+
// Flush inline text action — no box padding/height. Pair with text/link
|
|
39
|
+
// variants when the button must sit inline in a heading or sentence
|
|
40
|
+
// (replaces ad-hoc `h-auto px-0 py-0` overrides).
|
|
41
|
+
inline: 'h-auto gap-1 p-0 has-[>svg]:px-0',
|
|
42
|
+
icon: 'size-9 rounded-[4px]',
|
|
43
|
+
micro: "gap-0.5 px-1.5 py-0 text-[0.625rem] leading-4 has-[>svg]:px-1 [&_svg:not([class*='size-'])]:size-2.5",
|
|
44
|
+
'icon-xs': "size-6 rounded-[4px] [&_svg:not([class*='size-'])]:size-3",
|
|
45
|
+
'icon-sm': 'size-8 rounded-[4px]',
|
|
46
|
+
'icon-lg': 'size-10 rounded-[4px]',
|
|
47
|
+
'icon-titlebar':
|
|
48
|
+
'h-(--titlebar-control-height) w-(--titlebar-control-size) rounded-[4px] [&_.codicon]:text-[0.875rem]'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
defaultVariants: {
|
|
52
|
+
variant: 'default',
|
|
53
|
+
size: 'default'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
function Button({
|
|
59
|
+
className,
|
|
60
|
+
variant = 'default',
|
|
61
|
+
size = 'default',
|
|
62
|
+
asChild = false,
|
|
63
|
+
...props
|
|
64
|
+
}: React.ComponentProps<'button'> &
|
|
65
|
+
VariantProps<typeof buttonVariants> & {
|
|
66
|
+
asChild?: boolean
|
|
67
|
+
}) {
|
|
68
|
+
const Comp = asChild ? Slot.Root : 'button'
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Comp
|
|
72
|
+
className={cn(buttonVariants({ variant, size }), className)}
|
|
73
|
+
data-size={size}
|
|
74
|
+
data-slot="button"
|
|
75
|
+
data-variant={variant}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Checkbox as CheckboxPrimitive } 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
|
+
function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
8
|
+
return (
|
|
9
|
+
<CheckboxPrimitive.Root
|
|
10
|
+
className={cn(
|
|
11
|
+
'peer size-4 shrink-0 rounded-sm border border-input shadow-xs outline-none transition-shadow focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40',
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
data-slot="checkbox"
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<CheckboxPrimitive.Indicator
|
|
18
|
+
className="flex items-center justify-center text-current"
|
|
19
|
+
data-slot="checkbox-indicator"
|
|
20
|
+
>
|
|
21
|
+
<Codicon name="check" size="0.875rem" />
|
|
22
|
+
</CheckboxPrimitive.Indicator>
|
|
23
|
+
</CheckboxPrimitive.Root>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Checkbox }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@/lib/utils'
|
|
4
|
+
|
|
5
|
+
export interface CodiconProps extends React.HTMLAttributes<HTMLElement> {
|
|
6
|
+
name: string
|
|
7
|
+
size?: number | string
|
|
8
|
+
spinning?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function Codicon({ className, name, size, spinning, style, ...props }: CodiconProps) {
|
|
12
|
+
return (
|
|
13
|
+
<i
|
|
14
|
+
aria-hidden="true"
|
|
15
|
+
className={cn('codicon', `codicon-${name}`, spinning && 'codicon-modifier-spin', className)}
|
|
16
|
+
style={{ fontSize: size, ...style }}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Command as CommandPrimitive } from 'cmdk'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
|
|
4
|
+
import { SearchIcon } from '@/lib/icons'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
|
|
8
|
+
return (
|
|
9
|
+
<CommandPrimitive
|
|
10
|
+
className={cn(
|
|
11
|
+
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
data-slot="command"
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function CommandInput({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
21
|
+
return (
|
|
22
|
+
<div className="flex h-11 items-center gap-2 border-b border-border px-3" data-slot="command-input-wrapper">
|
|
23
|
+
<SearchIcon className="size-4 shrink-0 text-muted-foreground" />
|
|
24
|
+
<CommandPrimitive.Input
|
|
25
|
+
className={cn(
|
|
26
|
+
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
|
27
|
+
className
|
|
28
|
+
)}
|
|
29
|
+
data-slot="command-input"
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
37
|
+
return (
|
|
38
|
+
<CommandPrimitive.List
|
|
39
|
+
className={cn('max-h-100 overflow-y-auto overflow-x-hidden', className)}
|
|
40
|
+
data-slot="command-list"
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
47
|
+
return (
|
|
48
|
+
<CommandPrimitive.Empty
|
|
49
|
+
className="py-6 text-center text-sm text-muted-foreground"
|
|
50
|
+
data-slot="command-empty"
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
57
|
+
return (
|
|
58
|
+
<CommandPrimitive.Group
|
|
59
|
+
className={cn(
|
|
60
|
+
'overflow-hidden p-1 text-foreground **:[[cmdk-group-heading]]:sticky **:[[cmdk-group-heading]]:top-0 **:[[cmdk-group-heading]]:z-10 **:[[cmdk-group-heading]]:bg-popover **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-muted-foreground',
|
|
61
|
+
className
|
|
62
|
+
)}
|
|
63
|
+
data-slot="command-group"
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function CommandSeparator({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
70
|
+
return (
|
|
71
|
+
<CommandPrimitive.Separator
|
|
72
|
+
className={cn('-mx-1 h-px bg-border', className)}
|
|
73
|
+
data-slot="command-separator"
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
80
|
+
return (
|
|
81
|
+
<CommandPrimitive.Item
|
|
82
|
+
className={cn(
|
|
83
|
+
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50',
|
|
84
|
+
className
|
|
85
|
+
)}
|
|
86
|
+
data-slot="command-item"
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function CommandShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
93
|
+
return (
|
|
94
|
+
<span
|
|
95
|
+
className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
|
|
96
|
+
data-slot="command-shortcut"
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
Command,
|
|
104
|
+
CommandEmpty,
|
|
105
|
+
CommandGroup,
|
|
106
|
+
CommandInput,
|
|
107
|
+
CommandItem,
|
|
108
|
+
CommandList,
|
|
109
|
+
CommandSeparator,
|
|
110
|
+
CommandShortcut
|
|
111
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import { ActionStatus } from '@/components/ui/action-status'
|
|
5
|
+
import { Button } from '@/components/ui/button'
|
|
6
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
|
7
|
+
import { useI18n } from '@/i18n'
|
|
8
|
+
import { AlertTriangle } from '@/lib/icons'
|
|
9
|
+
|
|
10
|
+
interface ConfirmDialogProps {
|
|
11
|
+
open: boolean
|
|
12
|
+
onClose: () => void
|
|
13
|
+
// Does the work. Throw to surface an inline error and keep the dialog open.
|
|
14
|
+
onConfirm: () => Promise<void> | void
|
|
15
|
+
title: ReactNode
|
|
16
|
+
description?: ReactNode
|
|
17
|
+
confirmLabel?: string
|
|
18
|
+
busyLabel?: string
|
|
19
|
+
doneLabel?: string
|
|
20
|
+
cancelLabel?: string
|
|
21
|
+
destructive?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Shared confirmation dialog: Enter confirms (from anywhere in the dialog),
|
|
25
|
+
// Esc/Cancel/backdrop dismiss. Owns the pending → done → close beat and inline
|
|
26
|
+
// error, so callers pass only an async onConfirm that does the work.
|
|
27
|
+
export function ConfirmDialog({
|
|
28
|
+
open,
|
|
29
|
+
onClose,
|
|
30
|
+
onConfirm,
|
|
31
|
+
title,
|
|
32
|
+
description,
|
|
33
|
+
confirmLabel,
|
|
34
|
+
busyLabel,
|
|
35
|
+
doneLabel,
|
|
36
|
+
cancelLabel,
|
|
37
|
+
destructive = false
|
|
38
|
+
}: ConfirmDialogProps) {
|
|
39
|
+
const { t } = useI18n()
|
|
40
|
+
const [status, setStatus] = useState<'done' | 'idle' | 'saving'>('idle')
|
|
41
|
+
const [error, setError] = useState<null | string>(null)
|
|
42
|
+
const busy = status === 'saving' || status === 'done'
|
|
43
|
+
const resolvedConfirmLabel = confirmLabel ?? t.common.confirm
|
|
44
|
+
const resolvedBusyLabel = busyLabel ?? t.common.loading
|
|
45
|
+
const resolvedDoneLabel = doneLabel ?? t.common.done
|
|
46
|
+
const resolvedCancelLabel = cancelLabel ?? t.common.cancel
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (open) {
|
|
50
|
+
setStatus('idle')
|
|
51
|
+
setError(null)
|
|
52
|
+
}
|
|
53
|
+
}, [open])
|
|
54
|
+
|
|
55
|
+
async function run() {
|
|
56
|
+
if (busy) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setStatus('saving')
|
|
61
|
+
setError(null)
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await onConfirm()
|
|
65
|
+
setStatus('done')
|
|
66
|
+
window.setTimeout(onClose, 600)
|
|
67
|
+
} catch (err) {
|
|
68
|
+
setStatus('idle')
|
|
69
|
+
setError(err instanceof Error ? err.message : t.errors.genericFailure)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Dialog onOpenChange={value => !value && !busy && onClose()} open={open}>
|
|
75
|
+
<DialogContent
|
|
76
|
+
className="max-w-md"
|
|
77
|
+
onKeyDown={event => {
|
|
78
|
+
// Enter/Space confirm regardless of which button holds focus
|
|
79
|
+
// (preventDefault stops a focused Cancel from swallowing it).
|
|
80
|
+
if ((event.key === 'Enter' || event.key === ' ') && !busy) {
|
|
81
|
+
event.preventDefault()
|
|
82
|
+
void run()
|
|
83
|
+
}
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
86
|
+
<DialogHeader>
|
|
87
|
+
<DialogTitle>{title}</DialogTitle>
|
|
88
|
+
{description ? <DialogDescription>{description}</DialogDescription> : null}
|
|
89
|
+
</DialogHeader>
|
|
90
|
+
|
|
91
|
+
{error && (
|
|
92
|
+
<div className="flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
|
93
|
+
<AlertTriangle className="mt-0.5 size-3.5 shrink-0" />
|
|
94
|
+
<span>{error}</span>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
|
|
98
|
+
<DialogFooter>
|
|
99
|
+
<Button disabled={busy} onClick={onClose} type="button" variant="ghost">
|
|
100
|
+
{resolvedCancelLabel}
|
|
101
|
+
</Button>
|
|
102
|
+
<Button disabled={busy} onClick={() => void run()} variant={destructive ? 'destructive' : 'default'}>
|
|
103
|
+
<ActionStatus busy={resolvedBusyLabel} done={resolvedDoneLabel} idle={resolvedConfirmLabel} state={status} />
|
|
104
|
+
</Button>
|
|
105
|
+
</DialogFooter>
|
|
106
|
+
</DialogContent>
|
|
107
|
+
</Dialog>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ContextMenu as ContextMenuPrimitive } 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
|
+
function ContextMenu({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
|
|
8
|
+
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ContextMenuPortal({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
|
|
12
|
+
return <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function ContextMenuTrigger({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
|
|
16
|
+
return <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ContextMenuGroup({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
|
|
20
|
+
return <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ContextMenuContent({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
|
|
24
|
+
return (
|
|
25
|
+
<ContextMenuPrimitive.Portal>
|
|
26
|
+
<ContextMenuPrimitive.Content
|
|
27
|
+
className={cn(
|
|
28
|
+
'z-50 max-h-(--radix-context-menu-content-available-height) min-w-36 origin-(--radix-context-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',
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
data-slot="context-menu-content"
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
</ContextMenuPrimitive.Portal>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function ContextMenuItem({
|
|
39
|
+
className,
|
|
40
|
+
inset,
|
|
41
|
+
variant = 'default',
|
|
42
|
+
...props
|
|
43
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
|
|
44
|
+
inset?: boolean
|
|
45
|
+
variant?: 'default' | 'destructive'
|
|
46
|
+
}) {
|
|
47
|
+
return (
|
|
48
|
+
<ContextMenuPrimitive.Item
|
|
49
|
+
className={cn(
|
|
50
|
+
"relative flex cursor-default 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!",
|
|
51
|
+
className
|
|
52
|
+
)}
|
|
53
|
+
data-inset={inset}
|
|
54
|
+
data-slot="context-menu-item"
|
|
55
|
+
data-variant={variant}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function ContextMenuLabel({
|
|
62
|
+
className,
|
|
63
|
+
inset,
|
|
64
|
+
...props
|
|
65
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
|
|
66
|
+
inset?: boolean
|
|
67
|
+
}) {
|
|
68
|
+
return (
|
|
69
|
+
<ContextMenuPrimitive.Label
|
|
70
|
+
className={cn('px-2 py-1 text-xs font-medium text-(--ui-text-tertiary) data-[inset]:pl-7', className)}
|
|
71
|
+
data-inset={inset}
|
|
72
|
+
data-slot="context-menu-label"
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function ContextMenuSeparator({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
|
|
79
|
+
return (
|
|
80
|
+
<ContextMenuPrimitive.Separator
|
|
81
|
+
className={cn('-mx-1 my-1 h-px bg-(--ui-stroke-tertiary)', className)}
|
|
82
|
+
data-slot="context-menu-separator"
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function ContextMenuSub({ ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
|
|
89
|
+
return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function ContextMenuSubTrigger({
|
|
93
|
+
className,
|
|
94
|
+
inset,
|
|
95
|
+
children,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
|
|
98
|
+
inset?: boolean
|
|
99
|
+
}) {
|
|
100
|
+
return (
|
|
101
|
+
<ContextMenuPrimitive.SubTrigger
|
|
102
|
+
className={cn(
|
|
103
|
+
"flex cursor-default 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)",
|
|
104
|
+
className
|
|
105
|
+
)}
|
|
106
|
+
data-inset={inset}
|
|
107
|
+
data-slot="context-menu-sub-trigger"
|
|
108
|
+
{...props}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
<Codicon className="ml-auto text-(--ui-text-tertiary)" name="chevron-right" size="1rem" />
|
|
112
|
+
</ContextMenuPrimitive.SubTrigger>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function ContextMenuSubContent({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
|
|
117
|
+
return (
|
|
118
|
+
<ContextMenuPrimitive.SubContent
|
|
119
|
+
className={cn(
|
|
120
|
+
'z-50 min-w-36 origin-(--radix-context-menu-content-transform-origin) overflow-hidden 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',
|
|
121
|
+
className
|
|
122
|
+
)}
|
|
123
|
+
data-slot="context-menu-sub-content"
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
ContextMenu,
|
|
131
|
+
ContextMenuContent,
|
|
132
|
+
ContextMenuGroup,
|
|
133
|
+
ContextMenuItem,
|
|
134
|
+
ContextMenuLabel,
|
|
135
|
+
ContextMenuPortal,
|
|
136
|
+
ContextMenuSeparator,
|
|
137
|
+
ContextMenuSub,
|
|
138
|
+
ContextMenuSubContent,
|
|
139
|
+
ContextMenuSubTrigger,
|
|
140
|
+
ContextMenuTrigger
|
|
141
|
+
}
|