@cryptiklemur/lattice 4.0.1 → 5.0.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/bin/lattice +1 -9
- package/dist/client/assets/{angular-html-N8PCEquT.js → angular-html-DKTL-XDO.js} +1 -1
- package/dist/client/assets/{angular-ts-CJ8RJIPD.js → angular-ts-tvBzOwQR.js} +1 -1
- package/dist/client/assets/{apl-BD6tCLWN.js → apl-CCzl5qFl.js} +1 -1
- package/dist/client/assets/{astro-CpIIfBs6.js → astro-DNQTpO2Y.js} +1 -1
- package/dist/client/assets/{blade-D3qgnjiV.js → blade-CyJoIMeJ.js} +1 -1
- package/dist/client/assets/{c-Dr6ADN_t.js → c-OEwk5KN8.js} +1 -1
- package/dist/client/assets/{cobol-BIfDE0Hr.js → cobol-DpHyJzz2.js} +1 -1
- package/dist/client/assets/{coffee-DHQ57vfY.js → coffee-BX5dbDzZ.js} +1 -1
- package/dist/client/assets/{cpp-CEBY6JOp.js → cpp-BTBjNg2U.js} +1 -1
- package/dist/client/assets/{crystal-D125CSmP.js → crystal-CNzZd6DW.js} +1 -1
- package/dist/client/assets/{css-CBmrkYSr.js → css-BuKsNmms.js} +1 -1
- package/dist/client/assets/{dist-A_mCRD1f.js → dist-CKpDHMy6.js} +2 -2
- package/dist/client/assets/{edge-Ccsz7cJW.js → edge-DzhnGgJE.js} +1 -1
- package/dist/client/assets/{elixir-Do6gk14X.js → elixir-Dqs0waqF.js} +1 -1
- package/dist/client/assets/{elm-Db22zT4C.js → elm-BtWwjxWn.js} +1 -1
- package/dist/client/assets/{erb-MXVqAAJD.js → erb-iPD89b4v.js} +1 -1
- package/dist/client/assets/{git-rebase-B-LLWBOA.js → git-rebase-BxVNXJL4.js} +1 -1
- package/dist/client/assets/{glimmer-js-eWszRU73.js → glimmer-js-BlyCupwF.js} +1 -1
- package/dist/client/assets/{glimmer-ts-VQmwGqUp.js → glimmer-ts-DjIxWOS9.js} +1 -1
- package/dist/client/assets/{glsl-B8ilOfAl.js → glsl-CGIL-65r.js} +1 -1
- package/dist/client/assets/{graphql-DnTqxeOc.js → graphql-DeOn6mNV.js} +1 -1
- package/dist/client/assets/{hack-XJsHYSQb.js → hack-DVppeCmS.js} +1 -1
- package/dist/client/assets/{haml-CQ7Vqzwp.js → haml-WDhua0Mp.js} +1 -1
- package/dist/client/assets/{handlebars-C4szooBf.js → handlebars-i2Fu_9HI.js} +1 -1
- package/dist/client/assets/{html-B6EgAiSd.js → html-B1e6oxzK.js} +1 -1
- package/dist/client/assets/{html-derivative-DdinogQX.js → html-derivative-MofKXIVd.js} +1 -1
- package/dist/client/assets/{http-BSLxCgRq.js → http-Dk6S5pRD.js} +1 -1
- package/dist/client/assets/{hurl-pOsTwNfp.js → hurl-CroFYYJG.js} +1 -1
- package/dist/client/assets/{index-BHQ_8mvl.js → index-CVu-S6Yk.js} +2 -2
- package/dist/client/assets/{java-DRQLiiST.js → java-B89FYjqS.js} +1 -1
- package/dist/client/assets/{javascript-DvEK2-47.js → javascript-m6CO1Uiy.js} +1 -1
- package/dist/client/assets/{jinja-D2NYJ25y.js → jinja-DC9Wi41X.js} +1 -1
- package/dist/client/assets/{jison-DDZaLNAp.js → jison-6xiegwDk.js} +1 -1
- package/dist/client/assets/{json-TGR0NIWd.js → json-HA-96-qr.js} +1 -1
- package/dist/client/assets/{jsx-BjUoPYga.js → jsx-Wt1a8i8U.js} +1 -1
- package/dist/client/assets/{julia-C4gjSpFu.js → julia-7M93VBON.js} +1 -1
- package/dist/client/assets/{just-H351x5u_.js → just-CjfDLYLv.js} +1 -1
- package/dist/client/assets/{latex-BiTmf6gf.js → latex-CitsJ46x.js} +1 -1
- package/dist/client/assets/{liquid-86ufjRy-.js → liquid-C8VIFin8.js} +1 -1
- package/dist/client/assets/{lua-BNxR0F_8.js → lua-Ba2N7esc.js} +1 -1
- package/dist/client/assets/{marko-CvRxpRjM.js → marko-lTLvb2wu.js} +1 -1
- package/dist/client/assets/{mdc-CYbAIy2C.js → mdc-D6IV-8FD.js} +1 -1
- package/dist/client/assets/{nginx-egdgMq-F.js → nginx-Ch5AjE6S.js} +1 -1
- package/dist/client/assets/{nim-CXBJVz_w.js → nim-WmDDC6LW.js} +1 -1
- package/dist/client/assets/{perl-XRfMobzg.js → perl-CQv0gYuq.js} +1 -1
- package/dist/client/assets/{php-Br7a8uil.js → php-BJmH0qOB.js} +1 -1
- package/dist/client/assets/{pug-BVbbUVvy.js → pug-CsHPkzc9.js} +1 -1
- package/dist/client/assets/{qml-ByKvrL1j.js → qml-B36ecArG.js} +1 -1
- package/dist/client/assets/{r-mVoV0Ni6.js → r-D5Yi5Z4y.js} +1 -1
- package/dist/client/assets/{razor-T5O-9UJL.js → razor-CHAxVq4R.js} +1 -1
- package/dist/client/assets/{regexp-CioRuhuN.js → regexp-gfs--3M7.js} +1 -1
- package/dist/client/assets/{rst-V__uTudD.js → rst-ugdlp-hl.js} +1 -1
- package/dist/client/assets/{ruby-C_PuKPTI.js → ruby-CDRRW37j.js} +1 -1
- package/dist/client/assets/{sas-D_DqqQH4.js → sas-DZaNQaIP.js} +1 -1
- package/dist/client/assets/{scss-D-TjzZ4c.js → scss-CzWQEplj.js} +1 -1
- package/dist/client/assets/{shellscript-E5759VHu.js → shellscript-fgYvpu9N.js} +1 -1
- package/dist/client/assets/{shellsession-AESTM-Pv.js → shellsession-BoAohHh7.js} +1 -1
- package/dist/client/assets/{soy-QrbrrcDv.js → soy-DBzVgv9x.js} +1 -1
- package/dist/client/assets/{sql-0M8VcDHD.js → sql-BYXpAYTs.js} +1 -1
- package/dist/client/assets/{stata-CgeIpGtc.js → stata-I71MMY3p.js} +1 -1
- package/dist/client/assets/{surrealql-DBGwnZbw.js → surrealql-C9U8_1VO.js} +1 -1
- package/dist/client/assets/{svelte-Cv0PvUc_.js → svelte-VOFrPnWT.js} +1 -1
- package/dist/client/assets/{templ-B9t7xRE4.js → templ-BIaxAEtC.js} +1 -1
- package/dist/client/assets/{tex-DhZZ8dr2.js → tex-D1dwnBE5.js} +1 -1
- package/dist/client/assets/{ts-tags-BFv8sbnd.js → ts-tags-C0L2Q0r5.js} +1 -1
- package/dist/client/assets/{tsx-CXC9KSbY.js → tsx-BqcycEv1.js} +1 -1
- package/dist/client/assets/{twig-CM_OO66r.js → twig-vyWqOhpM.js} +1 -1
- package/dist/client/assets/{typescript-BdgOTaoD.js → typescript-B2YbovqG.js} +1 -1
- package/dist/client/assets/{vue-BnQhjnCm.js → vue-CbXxGdjo.js} +1 -1
- package/dist/client/assets/{vue-html-CNnGecRI.js → vue-html-DDX4KXW7.js} +1 -1
- package/dist/client/assets/{vue-vine-DCuMkRhK.js → vue-vine-DsyY1LR5.js} +1 -1
- package/dist/client/assets/{xml-CbTD7cB8.js → xml-Ddi0-r0D.js} +1 -1
- package/dist/client/assets/{xsl-uOqqo7cf.js → xsl-CsFcZHFS.js} +1 -1
- package/dist/client/assets/{yaml-BNrLoH59.js → yaml-tGJWoH6Y.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/client/sw.js +1 -1
- package/dist/server/analytics/engine.js +832 -0
- package/dist/server/assets.js +39 -0
- package/dist/server/auth/passphrase.js +70 -0
- package/dist/server/config.js +47 -0
- package/dist/server/daemon.js +535 -0
- package/dist/server/features/ralph-loop.js +138 -0
- package/dist/server/features/scheduler.js +260 -0
- package/dist/server/features/sticky-notes.js +99 -0
- package/dist/server/handlers/analytics.js +28 -0
- package/dist/server/handlers/attachment.js +158 -0
- package/dist/server/handlers/bookmarks.js +41 -0
- package/dist/server/handlers/chat.js +350 -0
- package/dist/server/handlers/editor.js +72 -0
- package/dist/server/handlers/fs.js +234 -0
- package/dist/server/handlers/loop.js +33 -0
- package/dist/server/handlers/memory.js +181 -0
- package/dist/server/handlers/mesh.js +322 -0
- package/dist/server/handlers/notes.js +36 -0
- package/dist/server/handlers/plugins.js +593 -0
- package/dist/server/handlers/project-settings.js +166 -0
- package/dist/server/handlers/scheduler.js +52 -0
- package/dist/server/handlers/session.js +194 -0
- package/dist/server/handlers/settings.js +148 -0
- package/dist/server/handlers/skills.js +360 -0
- package/dist/server/handlers/terminal.js +75 -0
- package/dist/server/handlers/themes.js +102 -0
- package/dist/server/handlers/update.js +124 -0
- package/dist/server/identity.js +45 -0
- package/dist/server/index.js +435 -0
- package/dist/server/logger.js +20 -0
- package/dist/server/mesh/connector.js +355 -0
- package/dist/server/mesh/crypto.js +88 -0
- package/dist/server/mesh/discovery.js +95 -0
- package/dist/server/mesh/pairing.js +104 -0
- package/dist/server/mesh/peers.js +54 -0
- package/dist/server/mesh/proxy.js +86 -0
- package/dist/server/mesh/session-sync.js +85 -0
- package/dist/server/project/bookmarks.js +77 -0
- package/dist/server/project/context-breakdown.js +279 -0
- package/dist/server/project/file-browser.js +97 -0
- package/dist/server/project/project-files.js +274 -0
- package/dist/server/project/registry.js +51 -0
- package/dist/server/project/sdk-bridge.js +960 -0
- package/dist/server/project/session.js +696 -0
- package/dist/server/project/terminal.js +87 -0
- package/dist/server/project/warmup.js +242 -0
- package/dist/server/push.js +87 -0
- package/dist/server/tls.js +50 -0
- package/dist/server/tui.js +83 -0
- package/dist/server/update-checker.js +119 -0
- package/dist/server/ws/broadcast.js +50 -0
- package/dist/server/ws/router.js +105 -0
- package/dist/server/ws/server.js +2 -0
- package/dist/shared/analytics.js +1 -0
- package/dist/shared/messages.js +1 -0
- package/dist/shared/models.js +1 -0
- package/dist/shared/project-settings.js +1 -0
- package/package.json +5 -8
- package/themes/alabaster.json +9 -0
- package/themes/amoled.json +20 -0
- package/themes/ayu-light.json +9 -0
- package/themes/catppuccin-latte.json +9 -0
- package/themes/catppuccin-mocha.json +9 -0
- package/themes/clay-light.json +10 -0
- package/themes/clay.json +10 -0
- package/themes/dracula.json +9 -0
- package/themes/everforest-light.json +9 -0
- package/themes/everforest.json +9 -0
- package/themes/github-light.json +9 -0
- package/themes/gruvbox-dark.json +9 -0
- package/themes/gruvbox-light.json +9 -0
- package/themes/horizon-light.json +9 -0
- package/themes/kanagawa-lotus.json +9 -0
- package/themes/kanagawa.json +9 -0
- package/themes/modus-operandi.json +9 -0
- package/themes/monokai.json +9 -0
- package/themes/nightfox.json +9 -0
- package/themes/nord-light.json +9 -0
- package/themes/nord.json +9 -0
- package/themes/one-dark.json +9 -0
- package/themes/one-light.json +9 -0
- package/themes/palenight.json +9 -0
- package/themes/paper.json +9 -0
- package/themes/penumbra-light.json +9 -0
- package/themes/poimandres.json +9 -0
- package/themes/quiet-light.json +9 -0
- package/themes/rose-pine-dawn.json +9 -0
- package/themes/rose-pine.json +9 -0
- package/themes/solarized-dark.json +9 -0
- package/themes/solarized-light.json +9 -0
- package/themes/synthwave84.json +9 -0
- package/themes/tokyo-night-light.json +9 -0
- package/themes/tokyo-night.json +9 -0
- package/themes/vesper.json +9 -0
- package/index.html +0 -20
- package/public/icons/icon-192.svg +0 -11
- package/public/icons/icon-512.svg +0 -11
- package/public/sw-push.js +0 -53
- package/src/client/App.tsx +0 -42
- package/src/client/commands.ts +0 -36
- package/src/client/components/analytics/AnalyticsView.tsx +0 -244
- package/src/client/components/analytics/ChartCard.tsx +0 -194
- package/src/client/components/analytics/PeriodSelector.tsx +0 -42
- package/src/client/components/analytics/QuickStats.tsx +0 -122
- package/src/client/components/analytics/chartTokens.ts +0 -188
- package/src/client/components/analytics/charts/ActivityCalendar.tsx +0 -204
- package/src/client/components/analytics/charts/CacheEfficiencyChart.tsx +0 -56
- package/src/client/components/analytics/charts/ContextUtilizationChart.tsx +0 -106
- package/src/client/components/analytics/charts/CostAreaChart.tsx +0 -79
- package/src/client/components/analytics/charts/CostDistributionChart.tsx +0 -59
- package/src/client/components/analytics/charts/CostDonutChart.tsx +0 -84
- package/src/client/components/analytics/charts/CumulativeCostChart.tsx +0 -59
- package/src/client/components/analytics/charts/DailySummaryCards.tsx +0 -86
- package/src/client/components/analytics/charts/HourlyHeatmap.tsx +0 -133
- package/src/client/components/analytics/charts/NodeFleetOverview.tsx +0 -89
- package/src/client/components/analytics/charts/PermissionBreakdown.tsx +0 -98
- package/src/client/components/analytics/charts/ProjectRadar.tsx +0 -126
- package/src/client/components/analytics/charts/ResponseTimeScatter.tsx +0 -96
- package/src/client/components/analytics/charts/SessionBubbleChart.tsx +0 -114
- package/src/client/components/analytics/charts/SessionComplexityList.tsx +0 -65
- package/src/client/components/analytics/charts/SessionTimeline.tsx +0 -107
- package/src/client/components/analytics/charts/TokenFlowChart.tsx +0 -78
- package/src/client/components/analytics/charts/TokenSankeyChart.tsx +0 -93
- package/src/client/components/analytics/charts/ToolSunburst.tsx +0 -123
- package/src/client/components/analytics/charts/ToolTreemap.tsx +0 -110
- package/src/client/components/auth/PassphrasePrompt.tsx +0 -70
- package/src/client/components/chat/AttachmentChips.tsx +0 -116
- package/src/client/components/chat/ChatInput.tsx +0 -533
- package/src/client/components/chat/ChatView.tsx +0 -1076
- package/src/client/components/chat/CommandPalette.tsx +0 -162
- package/src/client/components/chat/ElicitationCard.tsx +0 -238
- package/src/client/components/chat/Message.tsx +0 -825
- package/src/client/components/chat/ModelSelector.tsx +0 -108
- package/src/client/components/chat/PermissionModeSelector.tsx +0 -41
- package/src/client/components/chat/PromptQuestion.tsx +0 -271
- package/src/client/components/chat/StatusBar.tsx +0 -50
- package/src/client/components/chat/TodoCard.tsx +0 -57
- package/src/client/components/chat/ToolGroup.tsx +0 -129
- package/src/client/components/chat/ToolResultRenderer.tsx +0 -348
- package/src/client/components/chat/VoiceRecorder.tsx +0 -85
- package/src/client/components/chat/toolSummary.ts +0 -41
- package/src/client/components/dashboard/DashboardView.tsx +0 -200
- package/src/client/components/dashboard/ProjectDashboardView.tsx +0 -179
- package/src/client/components/mesh/NodeBadge.tsx +0 -24
- package/src/client/components/mesh/PairingDialog.tsx +0 -340
- package/src/client/components/project-settings/ProjectClaude.tsx +0 -318
- package/src/client/components/project-settings/ProjectEnvironment.tsx +0 -235
- package/src/client/components/project-settings/ProjectGeneral.tsx +0 -76
- package/src/client/components/project-settings/ProjectMcp.tsx +0 -232
- package/src/client/components/project-settings/ProjectMemory.tsx +0 -488
- package/src/client/components/project-settings/ProjectNotifications.tsx +0 -48
- package/src/client/components/project-settings/ProjectPermissions.tsx +0 -209
- package/src/client/components/project-settings/ProjectPlugins.tsx +0 -117
- package/src/client/components/project-settings/ProjectRules.tsx +0 -286
- package/src/client/components/project-settings/ProjectSettingsView.tsx +0 -117
- package/src/client/components/project-settings/ProjectSkills.tsx +0 -91
- package/src/client/components/settings/Appearance.tsx +0 -275
- package/src/client/components/settings/BudgetSettings.tsx +0 -165
- package/src/client/components/settings/ClaudeSettings.tsx +0 -175
- package/src/client/components/settings/Editor.tsx +0 -123
- package/src/client/components/settings/Environment.tsx +0 -185
- package/src/client/components/settings/GlobalMcp.tsx +0 -216
- package/src/client/components/settings/GlobalMemory.tsx +0 -19
- package/src/client/components/settings/GlobalPlugins.tsx +0 -806
- package/src/client/components/settings/GlobalRules.tsx +0 -149
- package/src/client/components/settings/GlobalSkills.tsx +0 -140
- package/src/client/components/settings/MeshStatus.tsx +0 -183
- package/src/client/components/settings/Notifications.tsx +0 -123
- package/src/client/components/settings/SettingsView.tsx +0 -75
- package/src/client/components/settings/SkillMarketplace.tsx +0 -175
- package/src/client/components/settings/ThemePreview.tsx +0 -140
- package/src/client/components/settings/ThemeWizard.tsx +0 -405
- package/src/client/components/settings/mcp-shared.tsx +0 -194
- package/src/client/components/settings/skill-shared.tsx +0 -186
- package/src/client/components/setup/SetupWizard.tsx +0 -755
- package/src/client/components/sidebar/AddProjectModal.tsx +0 -438
- package/src/client/components/sidebar/NodeSettingsModal.tsx +0 -206
- package/src/client/components/sidebar/ProjectDropdown.tsx +0 -211
- package/src/client/components/sidebar/ProjectRail.tsx +0 -353
- package/src/client/components/sidebar/SearchFilter.tsx +0 -52
- package/src/client/components/sidebar/SessionList.tsx +0 -599
- package/src/client/components/sidebar/SettingsSidebar.tsx +0 -139
- package/src/client/components/sidebar/Sidebar.tsx +0 -469
- package/src/client/components/sidebar/UserIsland.tsx +0 -282
- package/src/client/components/sidebar/UserMenu.tsx +0 -107
- package/src/client/components/ui/CommandPalette.tsx +0 -321
- package/src/client/components/ui/ContextMenu.tsx +0 -153
- package/src/client/components/ui/ErrorBoundary.tsx +0 -56
- package/src/client/components/ui/IconPicker.tsx +0 -184
- package/src/client/components/ui/KeyboardShortcuts.tsx +0 -129
- package/src/client/components/ui/LatticeLogomark.tsx +0 -19
- package/src/client/components/ui/NodeDisconnectedOverlay.tsx +0 -35
- package/src/client/components/ui/PopupMenu.tsx +0 -120
- package/src/client/components/ui/SaveFooter.tsx +0 -63
- package/src/client/components/ui/Toast.tsx +0 -132
- package/src/client/components/ui/UpdateBanner.tsx +0 -110
- package/src/client/components/ui/UpdatePrompt.tsx +0 -47
- package/src/client/components/workspace/BookmarksView.tsx +0 -156
- package/src/client/components/workspace/FileBrowser.tsx +0 -174
- package/src/client/components/workspace/FileTree.tsx +0 -129
- package/src/client/components/workspace/FileViewer.tsx +0 -211
- package/src/client/components/workspace/NoteCard.tsx +0 -120
- package/src/client/components/workspace/NotesView.tsx +0 -102
- package/src/client/components/workspace/ScheduledTasksView.tsx +0 -117
- package/src/client/components/workspace/SplitPane.tsx +0 -81
- package/src/client/components/workspace/TabBar.tsx +0 -170
- package/src/client/components/workspace/TaskCard.tsx +0 -159
- package/src/client/components/workspace/TaskEditModal.tsx +0 -129
- package/src/client/components/workspace/TerminalInstance.tsx +0 -171
- package/src/client/components/workspace/TerminalView.tsx +0 -110
- package/src/client/components/workspace/WorkspaceView.tsx +0 -141
- package/src/client/hooks/useAnalytics.ts +0 -84
- package/src/client/hooks/useAttachments.ts +0 -313
- package/src/client/hooks/useBookmarks.ts +0 -57
- package/src/client/hooks/useEditorConfig.ts +0 -28
- package/src/client/hooks/useFocusTrap.ts +0 -74
- package/src/client/hooks/useIdleDetection.ts +0 -50
- package/src/client/hooks/useInstallPrompt.ts +0 -53
- package/src/client/hooks/useMesh.ts +0 -89
- package/src/client/hooks/useNotifications.ts +0 -54
- package/src/client/hooks/useOnline.ts +0 -6
- package/src/client/hooks/useProjectSettings.ts +0 -56
- package/src/client/hooks/useProjects.ts +0 -98
- package/src/client/hooks/usePushNotifications.ts +0 -92
- package/src/client/hooks/useSaveState.ts +0 -65
- package/src/client/hooks/useSession.ts +0 -580
- package/src/client/hooks/useSidebar.ts +0 -90
- package/src/client/hooks/useSkills.ts +0 -30
- package/src/client/hooks/useSpinnerVerb.ts +0 -36
- package/src/client/hooks/useSwipeDrawer.ts +0 -299
- package/src/client/hooks/useTheme.ts +0 -114
- package/src/client/hooks/useTimeTick.ts +0 -35
- package/src/client/hooks/useVoiceRecorder.ts +0 -169
- package/src/client/hooks/useWebSocket.ts +0 -27
- package/src/client/hooks/useWorkspace.ts +0 -57
- package/src/client/lib/theme-derive.ts +0 -196
- package/src/client/lib/workspace-url.ts +0 -219
- package/src/client/main.tsx +0 -10
- package/src/client/providers/WebSocketProvider.tsx +0 -186
- package/src/client/router.tsx +0 -578
- package/src/client/stores/analytics.ts +0 -68
- package/src/client/stores/bookmarks.ts +0 -45
- package/src/client/stores/mesh.ts +0 -78
- package/src/client/stores/session.ts +0 -569
- package/src/client/stores/sidebar.ts +0 -530
- package/src/client/stores/theme.ts +0 -44
- package/src/client/stores/workspace.ts +0 -518
- package/src/client/styles/global.css +0 -391
- package/src/client/styles/theme-vars.css +0 -18
- package/src/client/themes/index.ts +0 -105
- package/src/client/utils/editorUrl.ts +0 -55
- package/src/client/utils/findDuplicateKeys.ts +0 -12
- package/src/client/utils/formatSessionTitle.ts +0 -17
- package/src/client/vite-env.d.ts +0 -6
- package/src/server/analytics/engine.ts +0 -920
- package/src/server/assets.ts +0 -45
- package/src/server/auth/passphrase.ts +0 -78
- package/src/server/config.ts +0 -55
- package/src/server/daemon.ts +0 -567
- package/src/server/features/ralph-loop.ts +0 -173
- package/src/server/features/scheduler.ts +0 -304
- package/src/server/features/sticky-notes.ts +0 -104
- package/src/server/handlers/analytics.ts +0 -39
- package/src/server/handlers/attachment.ts +0 -189
- package/src/server/handlers/bookmarks.ts +0 -50
- package/src/server/handlers/chat.ts +0 -381
- package/src/server/handlers/editor.ts +0 -76
- package/src/server/handlers/fs.ts +0 -251
- package/src/server/handlers/loop.ts +0 -37
- package/src/server/handlers/memory.ts +0 -182
- package/src/server/handlers/mesh.ts +0 -362
- package/src/server/handlers/notes.ts +0 -47
- package/src/server/handlers/plugins.ts +0 -655
- package/src/server/handlers/project-settings.ts +0 -180
- package/src/server/handlers/scheduler.ts +0 -64
- package/src/server/handlers/session.ts +0 -226
- package/src/server/handlers/settings.ts +0 -157
- package/src/server/handlers/skills.ts +0 -378
- package/src/server/handlers/terminal.ts +0 -88
- package/src/server/handlers/themes.ts +0 -121
- package/src/server/handlers/update.ts +0 -133
- package/src/server/identity.ts +0 -56
- package/src/server/index.ts +0 -454
- package/src/server/logger.ts +0 -21
- package/src/server/mesh/connector.ts +0 -419
- package/src/server/mesh/crypto.ts +0 -106
- package/src/server/mesh/discovery.ts +0 -126
- package/src/server/mesh/pairing.ts +0 -123
- package/src/server/mesh/peers.ts +0 -60
- package/src/server/mesh/proxy.ts +0 -106
- package/src/server/mesh/session-sync.ts +0 -107
- package/src/server/project/bookmarks.ts +0 -83
- package/src/server/project/context-breakdown.ts +0 -307
- package/src/server/project/file-browser.ts +0 -106
- package/src/server/project/project-files.ts +0 -267
- package/src/server/project/pty-worker.cjs +0 -83
- package/src/server/project/registry.ts +0 -57
- package/src/server/project/sdk-bridge.ts +0 -1100
- package/src/server/project/session.ts +0 -723
- package/src/server/project/terminal.ts +0 -111
- package/src/server/project/warmup.ts +0 -285
- package/src/server/push.ts +0 -121
- package/src/server/tls.ts +0 -65
- package/src/server/tui.ts +0 -103
- package/src/server/update-checker.ts +0 -147
- package/src/server/ws/broadcast.ts +0 -61
- package/src/server/ws/router.ts +0 -123
- package/src/server/ws/server.ts +0 -2
- package/src/shared/analytics.ts +0 -40
- package/src/shared/messages.ts +0 -1302
- package/src/shared/models.ts +0 -255
- package/src/shared/project-settings.ts +0 -45
- package/tsconfig.json +0 -25
- package/vite.config.ts +0 -71
- /package/{src/server/runtime.ts → dist/server/runtime.js} +0 -0
- /package/{src/shared/constants.ts → dist/shared/constants.js} +0 -0
- /package/{src/shared/index.ts → dist/shared/index.js} +0 -0
|
@@ -1,825 +0,0 @@
|
|
|
1
|
-
import { useState, useRef, useEffect, memo, useMemo } from "react";
|
|
2
|
-
import Markdown from "react-markdown";
|
|
3
|
-
import remarkGfm from "remark-gfm";
|
|
4
|
-
import { Wrench, TriangleAlert, ChevronDown, ChevronRight, Check, X, Shield, Zap, Link, Copy, SquarePlus, Bookmark, BookmarkCheck, RotateCcw, ClipboardCopy, FileText, MessageSquarePlus, History } from "lucide-react";
|
|
5
|
-
import type { HistoryMessage, ChatPermissionResponseMessage } from "#shared";
|
|
6
|
-
import { useStore } from "@tanstack/react-store";
|
|
7
|
-
import { useWebSocket } from "../../hooks/useWebSocket";
|
|
8
|
-
import { getSessionStore, setPendingPrefill } from "../../stores/session";
|
|
9
|
-
import { getBookmarkStore, findBookmarkByUuid } from "../../stores/bookmarks";
|
|
10
|
-
import { ToolResultRenderer } from "./ToolResultRenderer";
|
|
11
|
-
import { formatToolSummary } from "./toolSummary";
|
|
12
|
-
import { PromptQuestion } from "./PromptQuestion";
|
|
13
|
-
import { TodoCard } from "./TodoCard";
|
|
14
|
-
import { ElicitationCard } from "./ElicitationCard";
|
|
15
|
-
import { ContextMenu, useContextMenu } from "../ui/ContextMenu";
|
|
16
|
-
import type { ContextMenuEntry } from "../ui/ContextMenu";
|
|
17
|
-
|
|
18
|
-
function TableWrapper(props: React.HTMLAttributes<HTMLTableElement>) {
|
|
19
|
-
var wrapperRef = useRef<HTMLDivElement>(null);
|
|
20
|
-
|
|
21
|
-
useEffect(function () {
|
|
22
|
-
var el = wrapperRef.current;
|
|
23
|
-
if (!el) return;
|
|
24
|
-
function check() {
|
|
25
|
-
if (!el) return;
|
|
26
|
-
var hasOverflow = el.scrollWidth > el.clientWidth + 1;
|
|
27
|
-
var atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 2;
|
|
28
|
-
el.classList.toggle("has-overflow", hasOverflow);
|
|
29
|
-
el.classList.toggle("scrolled-end", atEnd || !hasOverflow);
|
|
30
|
-
}
|
|
31
|
-
check();
|
|
32
|
-
el.addEventListener("scroll", check, { passive: true });
|
|
33
|
-
var ro = new ResizeObserver(check);
|
|
34
|
-
ro.observe(el);
|
|
35
|
-
return function () {
|
|
36
|
-
el!.removeEventListener("scroll", check);
|
|
37
|
-
ro.disconnect();
|
|
38
|
-
};
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div ref={wrapperRef} className="table-wrapper">
|
|
43
|
-
<table {...props} />
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
var mdComponents = {
|
|
49
|
-
table: TableWrapper,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
interface MessageProps {
|
|
53
|
-
message: HistoryMessage;
|
|
54
|
-
responseCost?: number | null;
|
|
55
|
-
responseDuration?: number | null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function formatTime(timestamp: number): string {
|
|
59
|
-
if (!timestamp) return "";
|
|
60
|
-
var d = new Date(timestamp);
|
|
61
|
-
var now = new Date();
|
|
62
|
-
var h = d.getHours().toString().padStart(2, "0");
|
|
63
|
-
var m = d.getMinutes().toString().padStart(2, "0");
|
|
64
|
-
var time = h + ":" + m;
|
|
65
|
-
|
|
66
|
-
var today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
67
|
-
var yesterday = new Date(today.getTime() - 86400000);
|
|
68
|
-
var msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
69
|
-
|
|
70
|
-
if (msgDay.getTime() === today.getTime()) {
|
|
71
|
-
return time;
|
|
72
|
-
}
|
|
73
|
-
if (msgDay.getTime() === yesterday.getTime()) {
|
|
74
|
-
return "Yesterday " + time;
|
|
75
|
-
}
|
|
76
|
-
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
77
|
-
return months[d.getMonth()] + " " + d.getDate() + ", " + time;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function MessageAnchor(props: { id: string | undefined }) {
|
|
81
|
-
if (!props.id) return null;
|
|
82
|
-
function handleClick() {
|
|
83
|
-
var url = window.location.pathname + "#msg-" + props.id;
|
|
84
|
-
window.history.replaceState(null, "", url);
|
|
85
|
-
navigator.clipboard.writeText(window.location.origin + url);
|
|
86
|
-
}
|
|
87
|
-
return (
|
|
88
|
-
<button
|
|
89
|
-
type="button"
|
|
90
|
-
onClick={handleClick}
|
|
91
|
-
className="icon-action opacity-0 group-hover/msg:opacity-100 transition-opacity duration-150 text-base-content/20 hover:text-base-content/50 cursor-pointer p-0.5 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none rounded"
|
|
92
|
-
title="Copy link to message"
|
|
93
|
-
aria-label="Copy link to message"
|
|
94
|
-
>
|
|
95
|
-
<Link size={11} />
|
|
96
|
-
</button>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function stripMarkdown(text: string): string {
|
|
101
|
-
return text
|
|
102
|
-
.replace(/```[\s\S]*?```/g, function (m) { return m.replace(/```\w*\n?/g, "").replace(/```$/g, ""); })
|
|
103
|
-
.replace(/`([^`]+)`/g, "$1")
|
|
104
|
-
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
|
105
|
-
.replace(/\*([^*]+)\*/g, "$1")
|
|
106
|
-
.replace(/^#{1,6}\s+/gm, "")
|
|
107
|
-
.replace(/^\s*[-*+]\s+/gm, "- ")
|
|
108
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
|
109
|
-
.replace(/^>\s+/gm, "")
|
|
110
|
-
.trim();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function MessageActions(props: { text: string; showNewSession?: boolean; messageUuid?: string; messageType?: "user" | "assistant" }) {
|
|
114
|
-
var [copied, setCopied] = useState(false);
|
|
115
|
-
var ws = useWebSocket();
|
|
116
|
-
var bookmarkState = useStore(getBookmarkStore(), function (s) { return s; });
|
|
117
|
-
var isBookmarked = useMemo(function () {
|
|
118
|
-
if (!props.messageUuid) return false;
|
|
119
|
-
for (var i = 0; i < bookmarkState.bookmarks.length; i++) {
|
|
120
|
-
if (bookmarkState.bookmarks[i].messageUuid === props.messageUuid) return true;
|
|
121
|
-
}
|
|
122
|
-
return false;
|
|
123
|
-
}, [props.messageUuid, bookmarkState.bookmarks]);
|
|
124
|
-
|
|
125
|
-
function handleCopy(e: React.MouseEvent) {
|
|
126
|
-
var content = e.shiftKey ? stripMarkdown(props.text) : props.text;
|
|
127
|
-
navigator.clipboard.writeText(content);
|
|
128
|
-
setCopied(true);
|
|
129
|
-
setTimeout(function () { setCopied(false); }, 1500);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function handleNewSession() {
|
|
133
|
-
var state = getSessionStore().state;
|
|
134
|
-
if (!state.activeProjectSlug) return;
|
|
135
|
-
setPendingPrefill(props.text);
|
|
136
|
-
ws.send({ type: "session:create", projectSlug: state.activeProjectSlug });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function handleBookmarkToggle() {
|
|
140
|
-
var state = getSessionStore().state;
|
|
141
|
-
if (!state.activeSessionId || !state.activeProjectSlug || !props.messageUuid || !props.messageType) return;
|
|
142
|
-
if (isBookmarked) {
|
|
143
|
-
var bm = findBookmarkByUuid(props.messageUuid);
|
|
144
|
-
if (bm) {
|
|
145
|
-
ws.send({ type: "bookmark:remove", id: bm.id });
|
|
146
|
-
}
|
|
147
|
-
} else {
|
|
148
|
-
ws.send({
|
|
149
|
-
type: "bookmark:add",
|
|
150
|
-
sessionId: state.activeSessionId,
|
|
151
|
-
projectSlug: state.activeProjectSlug,
|
|
152
|
-
messageUuid: props.messageUuid,
|
|
153
|
-
messageText: props.text.slice(0, 100),
|
|
154
|
-
messageType: props.messageType,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
var btnClass = "icon-action opacity-0 group-hover/msg:opacity-100 transition-opacity duration-150 text-base-content/20 hover:text-base-content/50 cursor-pointer p-0.5 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none rounded";
|
|
160
|
-
|
|
161
|
-
return (
|
|
162
|
-
<>
|
|
163
|
-
<button type="button" onClick={handleCopy} className={btnClass} title={copied ? "Copied!" : "Copy message (Shift+click for plain text)"} aria-label={copied ? "Copied" : "Copy message"}>
|
|
164
|
-
{copied ? <Check size={11} /> : <Copy size={11} />}
|
|
165
|
-
</button>
|
|
166
|
-
{props.showNewSession && (
|
|
167
|
-
<button type="button" onClick={handleNewSession} className={btnClass} title="Start new session with this message" aria-label="Start new session with this message">
|
|
168
|
-
<SquarePlus size={11} />
|
|
169
|
-
</button>
|
|
170
|
-
)}
|
|
171
|
-
{props.messageUuid && props.messageType && (
|
|
172
|
-
<button type="button" onClick={handleBookmarkToggle} className={btnClass + (isBookmarked ? " !opacity-100 !text-warning" : "")} title={isBookmarked ? "Remove bookmark" : "Bookmark message"} aria-label={isBookmarked ? "Remove bookmark" : "Bookmark message"}>
|
|
173
|
-
{isBookmarked ? <BookmarkCheck size={11} /> : <Bookmark size={11} />}
|
|
174
|
-
</button>
|
|
175
|
-
)}
|
|
176
|
-
</>
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function parseSkillInvocation(text: string): { skillName: string; content: string } | null {
|
|
181
|
-
var firstNewline = text.search(/\r?\n/);
|
|
182
|
-
if (firstNewline === -1) return null;
|
|
183
|
-
var firstLine = text.slice(0, firstNewline).trim();
|
|
184
|
-
if (firstLine.indexOf(":") === -1) return null;
|
|
185
|
-
if (!/\n---[\r\n]/.test(text)) return null;
|
|
186
|
-
return { skillName: firstLine, content: text.slice(firstNewline).replace(/^\r?\n+---[\r\n]+/, "").trim() };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function SkillMessage(props: { skillName: string; content: string; time: string | null; uuid?: string }) {
|
|
190
|
-
var [expanded, setExpanded] = useState(false);
|
|
191
|
-
return (
|
|
192
|
-
<div id={props.uuid ? "msg-" + props.uuid : undefined} className="chat chat-end px-5 py-1 group/msg">
|
|
193
|
-
<div className="chat-bubble chat-bubble-primary text-[13px] leading-relaxed break-words max-w-[95%] sm:max-w-[85%] shadow-sm">
|
|
194
|
-
<button
|
|
195
|
-
type="button"
|
|
196
|
-
aria-expanded={expanded}
|
|
197
|
-
onClick={function () { setExpanded(!expanded); }}
|
|
198
|
-
className="flex items-center gap-2 w-full text-left cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-content/30 rounded py-0.5"
|
|
199
|
-
>
|
|
200
|
-
<Zap size={13} className="text-primary-content/50 shrink-0" />
|
|
201
|
-
<span className="font-mono font-semibold text-primary-content text-[13px] tracking-tight">
|
|
202
|
-
/{props.skillName}
|
|
203
|
-
</span>
|
|
204
|
-
<ChevronRight
|
|
205
|
-
size={14}
|
|
206
|
-
className={"text-primary-content/30 ml-auto shrink-0 transition-transform duration-200 " + (expanded ? "rotate-90" : "")}
|
|
207
|
-
/>
|
|
208
|
-
</button>
|
|
209
|
-
{expanded && (
|
|
210
|
-
<div className="mt-2 pt-2 border-t border-primary-content/10 relative">
|
|
211
|
-
<div className="max-h-[400px] overflow-y-auto skill-content-scroll prose prose-sm max-w-none [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 prose-headings:text-primary-content prose-headings:text-[13px] prose-headings:mt-3 prose-headings:mb-1 prose-p:text-primary-content/80 prose-strong:text-primary-content prose-code:text-primary-content/70 prose-code:text-[11px] prose-pre:bg-primary/20 prose-a:text-primary-content/90 prose-a:underline text-[12px] leading-relaxed prose-li:text-primary-content/75 prose-li:text-[12px] prose-hr:border-primary-content/10">
|
|
212
|
-
<Markdown remarkPlugins={[remarkGfm]} components={mdComponents}>{props.content}</Markdown>
|
|
213
|
-
</div>
|
|
214
|
-
</div>
|
|
215
|
-
)}
|
|
216
|
-
</div>
|
|
217
|
-
{props.time && (
|
|
218
|
-
<div className="chat-footer text-[10px] text-base-content/30 mt-0.5 flex items-center gap-1">
|
|
219
|
-
{props.time}
|
|
220
|
-
<MessageAnchor id={props.uuid} />
|
|
221
|
-
<MessageActions text={"/" + props.skillName} showNewSession messageUuid={props.uuid} messageType="user" />
|
|
222
|
-
</div>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function RewindButton(props: { uuid: string }) {
|
|
229
|
-
var ws = useWebSocket();
|
|
230
|
-
var [pending, setPending] = useState(false);
|
|
231
|
-
var [preview, setPreview] = useState<{ canRewind: boolean; filesChanged?: number; error?: string } | null>(null);
|
|
232
|
-
|
|
233
|
-
useEffect(function () {
|
|
234
|
-
function handlePreview(msg: any) {
|
|
235
|
-
if (msg.type === "chat:rewind_preview_result" && msg.messageUuid === props.uuid) {
|
|
236
|
-
setPreview(msg);
|
|
237
|
-
setPending(false);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function handleExecResult(msg: any) {
|
|
241
|
-
if (msg.type === "chat:rewind_execute_result" && msg.messageUuid === props.uuid) {
|
|
242
|
-
setPreview(null);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
ws.subscribe("chat:rewind_preview_result", handlePreview);
|
|
246
|
-
ws.subscribe("chat:rewind_execute_result", handleExecResult);
|
|
247
|
-
return function () {
|
|
248
|
-
ws.unsubscribe("chat:rewind_preview_result", handlePreview);
|
|
249
|
-
ws.unsubscribe("chat:rewind_execute_result", handleExecResult);
|
|
250
|
-
};
|
|
251
|
-
}, [ws, props.uuid]);
|
|
252
|
-
|
|
253
|
-
function handleClick() {
|
|
254
|
-
if (preview) {
|
|
255
|
-
ws.send({ type: "chat:rewind_execute", messageUuid: props.uuid, mode: "files" } as any);
|
|
256
|
-
setPreview(null);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
setPending(true);
|
|
260
|
-
ws.send({ type: "chat:rewind_preview", messageUuid: props.uuid } as any);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (preview && !preview.canRewind) {
|
|
264
|
-
return (
|
|
265
|
-
<span className="text-error/60 text-[10px]" title={preview.error || "Cannot rewind"}>
|
|
266
|
-
{preview.error || "Cannot rewind"}
|
|
267
|
-
</span>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (preview && preview.canRewind) {
|
|
272
|
-
return (
|
|
273
|
-
<span className="flex items-center gap-1">
|
|
274
|
-
<button
|
|
275
|
-
onClick={handleClick}
|
|
276
|
-
className="btn btn-ghost btn-xs h-4 min-h-0 px-1 text-warning/70 hover:text-warning"
|
|
277
|
-
title={"Rewind files (" + (preview.filesChanged || 0) + " changed)"}
|
|
278
|
-
>
|
|
279
|
-
<RotateCcw className="!size-3" />
|
|
280
|
-
<span className="text-[10px]">Rewind {preview.filesChanged || 0} files</span>
|
|
281
|
-
</button>
|
|
282
|
-
<button
|
|
283
|
-
onClick={function () { setPreview(null); }}
|
|
284
|
-
className="btn btn-ghost btn-xs h-4 min-h-0 px-0.5 text-base-content/30 hover:text-base-content/60"
|
|
285
|
-
>
|
|
286
|
-
<X className="!size-3" />
|
|
287
|
-
</button>
|
|
288
|
-
</span>
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
return (
|
|
293
|
-
<button
|
|
294
|
-
onClick={handleClick}
|
|
295
|
-
disabled={pending}
|
|
296
|
-
className="btn btn-ghost btn-xs h-4 min-h-0 px-0.5 opacity-0 group-hover/msg:opacity-100 transition-opacity text-base-content/30 hover:text-base-content/60"
|
|
297
|
-
title="Rewind files to this point"
|
|
298
|
-
>
|
|
299
|
-
<RotateCcw className={"!size-3" + (pending ? " animate-spin" : "")} />
|
|
300
|
-
</button>
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function UserMessage(props: { message: HistoryMessage }) {
|
|
305
|
-
var msg = props.message;
|
|
306
|
-
var time = formatTime(msg.timestamp);
|
|
307
|
-
var text = msg.text || "";
|
|
308
|
-
var skill = parseSkillInvocation(text);
|
|
309
|
-
var ctxMenu = useContextMenu<HistoryMessage>();
|
|
310
|
-
var ws = useWebSocket();
|
|
311
|
-
var bookmarkState = useStore(getBookmarkStore(), function (s) { return s; });
|
|
312
|
-
var isBookmarked = useMemo(function () {
|
|
313
|
-
if (!msg.uuid) return false;
|
|
314
|
-
for (var i = 0; i < bookmarkState.bookmarks.length; i++) {
|
|
315
|
-
if (bookmarkState.bookmarks[i].messageUuid === msg.uuid) return true;
|
|
316
|
-
}
|
|
317
|
-
return false;
|
|
318
|
-
}, [msg.uuid, bookmarkState.bookmarks]);
|
|
319
|
-
|
|
320
|
-
function handleNewSession() {
|
|
321
|
-
var state = getSessionStore().state;
|
|
322
|
-
if (!state.activeProjectSlug) return;
|
|
323
|
-
setPendingPrefill(text);
|
|
324
|
-
ws.send({ type: "session:create", projectSlug: state.activeProjectSlug });
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function handleBookmarkToggle() {
|
|
328
|
-
var state = getSessionStore().state;
|
|
329
|
-
if (!state.activeSessionId || !state.activeProjectSlug || !msg.uuid) return;
|
|
330
|
-
if (isBookmarked) {
|
|
331
|
-
var bm = findBookmarkByUuid(msg.uuid);
|
|
332
|
-
if (bm) {
|
|
333
|
-
ws.send({ type: "bookmark:remove", id: bm.id });
|
|
334
|
-
}
|
|
335
|
-
} else {
|
|
336
|
-
ws.send({
|
|
337
|
-
type: "bookmark:add",
|
|
338
|
-
sessionId: state.activeSessionId,
|
|
339
|
-
projectSlug: state.activeProjectSlug,
|
|
340
|
-
messageUuid: msg.uuid,
|
|
341
|
-
messageText: text.slice(0, 100),
|
|
342
|
-
messageType: "user",
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function buildContextItems(): ContextMenuEntry[] {
|
|
348
|
-
return [
|
|
349
|
-
{ label: "Copy", icon: <Copy size={14} />, onClick: function () { navigator.clipboard.writeText(text); } },
|
|
350
|
-
{ label: "Copy as plain text", icon: <FileText size={14} />, onClick: function () { navigator.clipboard.writeText(stripMarkdown(text)); } },
|
|
351
|
-
{ type: "divider" as const },
|
|
352
|
-
{ label: "Start new session with this message", icon: <MessageSquarePlus size={14} />, onClick: handleNewSession },
|
|
353
|
-
{ type: "divider" as const },
|
|
354
|
-
{ label: isBookmarked ? "Unbookmark" : "Bookmark", icon: isBookmarked ? <BookmarkCheck size={14} /> : <Bookmark size={14} />, onClick: handleBookmarkToggle, hidden: !msg.uuid },
|
|
355
|
-
{ label: "Copy link to message", icon: <Link size={14} />, onClick: function () { navigator.clipboard.writeText(window.location.origin + window.location.pathname + "#msg-" + msg.uuid); }, hidden: !msg.uuid },
|
|
356
|
-
];
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (skill) {
|
|
360
|
-
return <SkillMessage skillName={skill.skillName} content={skill.content} time={time} uuid={msg.uuid} />;
|
|
361
|
-
}
|
|
362
|
-
return (
|
|
363
|
-
<div id={msg.uuid ? "msg-" + msg.uuid : undefined} data-allow-context-menu className="chat chat-end px-5 py-1 group/msg" onContextMenu={function (e) { ctxMenu.open(e, msg); }}>
|
|
364
|
-
<div className="chat-bubble chat-bubble-primary text-[13px] leading-relaxed break-words max-w-[95%] sm:max-w-[85%] shadow-sm">
|
|
365
|
-
<div className="prose prose-sm max-w-none [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 prose-headings:text-primary-content prose-p:text-primary-content prose-strong:text-primary-content prose-code:text-primary-content/80 prose-pre:bg-primary/20 prose-a:text-primary-content/90 prose-a:underline prose-li:text-primary-content [&_ul>li::marker]:text-primary-content [&_ol>li::marker]:text-primary-content">
|
|
366
|
-
<Markdown remarkPlugins={[remarkGfm]} components={mdComponents}>{text}</Markdown>
|
|
367
|
-
</div>
|
|
368
|
-
</div>
|
|
369
|
-
{time && (
|
|
370
|
-
<div className="chat-footer text-[10px] text-base-content/30 mt-0.5 flex items-center gap-1">
|
|
371
|
-
{time}
|
|
372
|
-
{msg.uuid && <RewindButton uuid={msg.uuid} />}
|
|
373
|
-
<MessageAnchor id={msg.uuid} />
|
|
374
|
-
<MessageActions text={text} showNewSession messageUuid={msg.uuid} messageType="user" />
|
|
375
|
-
</div>
|
|
376
|
-
)}
|
|
377
|
-
{ctxMenu.state && <ContextMenu x={ctxMenu.state.x} y={ctxMenu.state.y} items={buildContextItems()} onClose={ctxMenu.close} label="User message actions" />}
|
|
378
|
-
</div>
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function formatDuration(ms: number): string {
|
|
383
|
-
var seconds = Math.round(ms / 1000);
|
|
384
|
-
if (seconds < 60) return seconds + "s";
|
|
385
|
-
var minutes = Math.floor(seconds / 60);
|
|
386
|
-
var remainingSeconds = seconds % 60;
|
|
387
|
-
return minutes + "m " + remainingSeconds + "s";
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function formatTokenCount(n: number): string {
|
|
391
|
-
if (n >= 1000000) return (n / 1000000).toFixed(1).replace(/\.0$/, "") + "M";
|
|
392
|
-
if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, "") + "k";
|
|
393
|
-
return String(n);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
function AssistantMessage(props: { message: HistoryMessage; responseCost?: number | null; responseDuration?: number | null }) {
|
|
397
|
-
var msg = props.message;
|
|
398
|
-
var time = formatTime(msg.timestamp);
|
|
399
|
-
var text = msg.text || "";
|
|
400
|
-
var ctxMenu = useContextMenu<HistoryMessage>();
|
|
401
|
-
var ws = useWebSocket();
|
|
402
|
-
var bookmarkState = useStore(getBookmarkStore(), function (s) { return s; });
|
|
403
|
-
var isBookmarked = useMemo(function () {
|
|
404
|
-
if (!msg.uuid) return false;
|
|
405
|
-
for (var i = 0; i < bookmarkState.bookmarks.length; i++) {
|
|
406
|
-
if (bookmarkState.bookmarks[i].messageUuid === msg.uuid) return true;
|
|
407
|
-
}
|
|
408
|
-
return false;
|
|
409
|
-
}, [msg.uuid, bookmarkState.bookmarks]);
|
|
410
|
-
|
|
411
|
-
function handleNewSession() {
|
|
412
|
-
var state = getSessionStore().state;
|
|
413
|
-
if (!state.activeProjectSlug) return;
|
|
414
|
-
setPendingPrefill(text);
|
|
415
|
-
ws.send({ type: "session:create", projectSlug: state.activeProjectSlug });
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function handleBookmarkToggle() {
|
|
419
|
-
var state = getSessionStore().state;
|
|
420
|
-
if (!state.activeSessionId || !state.activeProjectSlug || !msg.uuid) return;
|
|
421
|
-
if (isBookmarked) {
|
|
422
|
-
var bm = findBookmarkByUuid(msg.uuid);
|
|
423
|
-
if (bm) {
|
|
424
|
-
ws.send({ type: "bookmark:remove", id: bm.id });
|
|
425
|
-
}
|
|
426
|
-
} else {
|
|
427
|
-
ws.send({
|
|
428
|
-
type: "bookmark:add",
|
|
429
|
-
sessionId: state.activeSessionId,
|
|
430
|
-
projectSlug: state.activeProjectSlug,
|
|
431
|
-
messageUuid: msg.uuid,
|
|
432
|
-
messageText: text.slice(0, 100),
|
|
433
|
-
messageType: "assistant",
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function buildContextItems(): ContextMenuEntry[] {
|
|
439
|
-
return [
|
|
440
|
-
{ label: "Copy", icon: <Copy size={14} />, onClick: function () { navigator.clipboard.writeText(text); } },
|
|
441
|
-
{ label: "Copy as plain text", icon: <FileText size={14} />, onClick: function () { navigator.clipboard.writeText(stripMarkdown(text)); } },
|
|
442
|
-
{ type: "divider" as const },
|
|
443
|
-
{ label: "Start new session with this message", icon: <MessageSquarePlus size={14} />, onClick: handleNewSession },
|
|
444
|
-
{ type: "divider" as const },
|
|
445
|
-
{ label: isBookmarked ? "Unbookmark" : "Bookmark", icon: isBookmarked ? <BookmarkCheck size={14} /> : <Bookmark size={14} />, onClick: handleBookmarkToggle, hidden: !msg.uuid },
|
|
446
|
-
{ label: "Copy link to message", icon: <Link size={14} />, onClick: function () { navigator.clipboard.writeText(window.location.origin + window.location.pathname + "#msg-" + msg.uuid); }, hidden: !msg.uuid },
|
|
447
|
-
];
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return (
|
|
451
|
-
<div id={msg.uuid ? "msg-" + msg.uuid : undefined} data-allow-context-menu className="chat chat-start px-5 py-1 group/msg" onContextMenu={function (e) { ctxMenu.open(e, msg); }}>
|
|
452
|
-
<div className="chat-image">
|
|
453
|
-
<div className="w-6 h-6 rounded-full bg-primary/15 border border-primary/20 flex items-center justify-center">
|
|
454
|
-
<div className="w-2.5 h-2.5 rounded-full bg-primary" />
|
|
455
|
-
</div>
|
|
456
|
-
</div>
|
|
457
|
-
<div className="chat-bubble bg-base-300/70 text-base-content text-[13px] leading-relaxed break-words max-w-[95%] sm:max-w-[85%] shadow-sm border border-base-content/5">
|
|
458
|
-
<div className="prose prose-sm max-w-none [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 prose-headings:text-base-content prose-p:text-base-content prose-strong:text-base-content prose-code:text-base-content/70 prose-code:bg-base-100/50 prose-pre:bg-base-100 prose-pre:text-base-content/70 prose-a:text-primary prose-a:underline prose-li:text-base-content">
|
|
459
|
-
<Markdown remarkPlugins={[remarkGfm]} components={mdComponents}>{text}</Markdown>
|
|
460
|
-
</div>
|
|
461
|
-
</div>
|
|
462
|
-
{time && (
|
|
463
|
-
<div className="chat-footer text-[10px] text-base-content/30 mt-0.5 flex items-center gap-2">
|
|
464
|
-
<span>{time}</span>
|
|
465
|
-
{props.responseDuration != null && props.responseDuration > 0 && (
|
|
466
|
-
<span className="text-base-content/20">{formatDuration(props.responseDuration)}</span>
|
|
467
|
-
)}
|
|
468
|
-
{(props.responseCost != null && props.responseCost > 0) ? (
|
|
469
|
-
<span className="text-base-content/20">{"$" + props.responseCost.toFixed(4)}</span>
|
|
470
|
-
) : (msg.costEstimate != null && msg.costEstimate > 0) ? (
|
|
471
|
-
<span className="text-base-content/20">{"~$" + msg.costEstimate.toFixed(4)}</span>
|
|
472
|
-
) : null}
|
|
473
|
-
{msg.outputTokens != null && msg.outputTokens > 0 && (
|
|
474
|
-
<span className="text-base-content/15">{formatTokenCount(msg.outputTokens)} out</span>
|
|
475
|
-
)}
|
|
476
|
-
<MessageAnchor id={msg.uuid} />
|
|
477
|
-
<MessageActions text={text} showNewSession messageUuid={msg.uuid} messageType="assistant" />
|
|
478
|
-
</div>
|
|
479
|
-
)}
|
|
480
|
-
{ctxMenu.state && <ContextMenu x={ctxMenu.state.x} y={ctxMenu.state.y} items={buildContextItems()} onClose={ctxMenu.close} label="Assistant message actions" />}
|
|
481
|
-
</div>
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function ToolMessage(props: { message: HistoryMessage }) {
|
|
486
|
-
var msg = props.message;
|
|
487
|
-
var [expanded, setExpanded] = useState<boolean>(false);
|
|
488
|
-
var hasResult = Boolean(msg.content);
|
|
489
|
-
var ctxMenu = useContextMenu<HistoryMessage>();
|
|
490
|
-
|
|
491
|
-
var parsedArgs: string = msg.args || "";
|
|
492
|
-
try {
|
|
493
|
-
if (msg.args) {
|
|
494
|
-
parsedArgs = JSON.stringify(JSON.parse(msg.args), null, 2);
|
|
495
|
-
}
|
|
496
|
-
} catch {
|
|
497
|
-
parsedArgs = msg.args || "";
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function buildContextItems(): ContextMenuEntry[] {
|
|
501
|
-
return [
|
|
502
|
-
{ label: "Copy output", icon: <ClipboardCopy size={14} />, onClick: function () { navigator.clipboard.writeText(msg.content || ""); }, disabled: !hasResult },
|
|
503
|
-
{ label: "Copy tool input", icon: <Copy size={14} />, onClick: function () { navigator.clipboard.writeText(parsedArgs); } },
|
|
504
|
-
];
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
return (
|
|
508
|
-
<div data-allow-context-menu className="ml-14 mr-5 py-0.5 max-w-[95%] sm:max-w-[75%] group/msg" onContextMenu={function (e) { ctxMenu.open(e, msg); }}>
|
|
509
|
-
<div
|
|
510
|
-
className={
|
|
511
|
-
"rounded-lg overflow-hidden text-[12px] border transition-colors duration-100 " +
|
|
512
|
-
(hasResult
|
|
513
|
-
? "bg-base-200/50 border-base-content/8"
|
|
514
|
-
: "bg-base-200/70 border-primary/20")
|
|
515
|
-
}
|
|
516
|
-
>
|
|
517
|
-
<button
|
|
518
|
-
type="button"
|
|
519
|
-
onClick={function () { setExpanded(function (v) { return !v; }); }}
|
|
520
|
-
className="flex items-center gap-2 w-full py-1.5 px-2.5 hover:bg-base-content/5 transition-colors duration-100 cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-inset rounded-lg"
|
|
521
|
-
>
|
|
522
|
-
<Wrench size={11} className={hasResult ? "text-base-content/30" : "text-primary/70"} />
|
|
523
|
-
<span className="font-mono font-medium text-[12px] text-base-content/70 flex-shrink-0">
|
|
524
|
-
{msg.name}
|
|
525
|
-
</span>
|
|
526
|
-
<span className="text-[10px] text-base-content/30 truncate min-w-0 flex-1 text-left">
|
|
527
|
-
{formatToolSummary(msg.name || "", msg.args || "")}
|
|
528
|
-
</span>
|
|
529
|
-
{hasResult ? (
|
|
530
|
-
<span className="text-[10px] text-base-content/30 flex-shrink-0">done</span>
|
|
531
|
-
) : (
|
|
532
|
-
<span className="text-[10px] text-primary/70 flex-shrink-0">running</span>
|
|
533
|
-
)}
|
|
534
|
-
<ChevronDown
|
|
535
|
-
size={11}
|
|
536
|
-
className={"text-base-content/30 transition-transform duration-150 " + (expanded ? "rotate-180" : "")}
|
|
537
|
-
/>
|
|
538
|
-
</button>
|
|
539
|
-
|
|
540
|
-
{expanded && (
|
|
541
|
-
<div className="border-t border-base-content/8">
|
|
542
|
-
<ToolResultRenderer toolName={msg.name || ""} args={msg.args || ""} result={msg.content || ""} />
|
|
543
|
-
{!(msg.name === "Edit" || msg.name === "MultiEdit") && parsedArgs && (
|
|
544
|
-
<div className="px-2.5 py-2 border-t border-base-content/8">
|
|
545
|
-
<div className="text-[9px] text-base-content/25 mb-0.5 uppercase tracking-wider font-semibold">Args</div>
|
|
546
|
-
<pre className="font-mono text-[11px] text-base-content/45 whitespace-pre-wrap break-words m-0 leading-relaxed bg-base-100/50 rounded-md p-2 max-h-[120px] overflow-y-auto">
|
|
547
|
-
{parsedArgs}
|
|
548
|
-
</pre>
|
|
549
|
-
</div>
|
|
550
|
-
)}
|
|
551
|
-
</div>
|
|
552
|
-
)}
|
|
553
|
-
</div>
|
|
554
|
-
{hasResult && (
|
|
555
|
-
<div className="flex items-center gap-1 mt-0.5 px-0.5">
|
|
556
|
-
<MessageActions text={msg.content || ""} />
|
|
557
|
-
</div>
|
|
558
|
-
)}
|
|
559
|
-
{ctxMenu.state && <ContextMenu x={ctxMenu.state.x} y={ctxMenu.state.y} items={buildContextItems()} onClose={ctxMenu.close} label="Tool message actions" />}
|
|
560
|
-
</div>
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
function PermissionMessage(props: { message: HistoryMessage }) {
|
|
565
|
-
var msg = props.message;
|
|
566
|
-
var { send } = useWebSocket();
|
|
567
|
-
var [showScopeMenu, setShowScopeMenu] = useState<boolean>(false);
|
|
568
|
-
var [expanded, setExpanded] = useState<boolean>(false);
|
|
569
|
-
var [dropUp, setDropUp] = useState<boolean>(false);
|
|
570
|
-
var scopeBtnRef = useRef<HTMLButtonElement>(null);
|
|
571
|
-
|
|
572
|
-
useEffect(function () {
|
|
573
|
-
if (showScopeMenu && scopeBtnRef.current) {
|
|
574
|
-
var rect = scopeBtnRef.current.getBoundingClientRect();
|
|
575
|
-
var spaceBelow = window.innerHeight - rect.bottom;
|
|
576
|
-
setDropUp(spaceBelow < 120);
|
|
577
|
-
}
|
|
578
|
-
}, [showScopeMenu]);
|
|
579
|
-
|
|
580
|
-
var isResolved = msg.permissionStatus && msg.permissionStatus !== "pending";
|
|
581
|
-
|
|
582
|
-
var parsedArgs: string = msg.args || "";
|
|
583
|
-
try {
|
|
584
|
-
if (msg.args) {
|
|
585
|
-
parsedArgs = JSON.stringify(JSON.parse(msg.args), null, 2);
|
|
586
|
-
}
|
|
587
|
-
} catch {
|
|
588
|
-
parsedArgs = msg.args || "";
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function respond(allow: boolean, alwaysAllow?: boolean, alwaysAllowScope?: "session" | "project") {
|
|
592
|
-
if (isResolved || !msg.toolId) {
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
send({
|
|
596
|
-
type: "chat:permission_response",
|
|
597
|
-
requestId: msg.toolId,
|
|
598
|
-
allow: allow,
|
|
599
|
-
alwaysAllow: alwaysAllow,
|
|
600
|
-
alwaysAllowScope: alwaysAllowScope,
|
|
601
|
-
} as ChatPermissionResponseMessage);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
function handleKeyDown(e: React.KeyboardEvent) {
|
|
605
|
-
if (isResolved) return;
|
|
606
|
-
if (e.key === "Enter") {
|
|
607
|
-
e.preventDefault();
|
|
608
|
-
respond(true);
|
|
609
|
-
} else if (e.key === "Escape") {
|
|
610
|
-
e.preventDefault();
|
|
611
|
-
respond(false);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (isResolved) {
|
|
616
|
-
var statusIcon = msg.permissionStatus === "denied"
|
|
617
|
-
? <X size={12} className="text-error" />
|
|
618
|
-
: <Check size={12} className="text-success" />;
|
|
619
|
-
var statusText = msg.permissionStatus === "denied"
|
|
620
|
-
? "Denied"
|
|
621
|
-
: msg.permissionStatus === "always_allowed"
|
|
622
|
-
? "Always allowed"
|
|
623
|
-
: "Allowed";
|
|
624
|
-
var borderClass = msg.permissionStatus === "denied"
|
|
625
|
-
? "border-error/15 bg-error/3"
|
|
626
|
-
: "border-success/15 bg-success/3";
|
|
627
|
-
|
|
628
|
-
return (
|
|
629
|
-
<div className="ml-14 mr-5 py-0.5 max-w-[95%] sm:max-w-[75%]">
|
|
630
|
-
<div className={"rounded-lg text-[12px] border px-2.5 py-1.5 flex items-center gap-2 " + borderClass}>
|
|
631
|
-
{statusIcon}
|
|
632
|
-
<span className="text-base-content/35">{statusText}</span>
|
|
633
|
-
<code className="font-mono text-[11px] bg-base-300/40 px-1.5 py-0.5 rounded text-base-content/30">
|
|
634
|
-
{msg.name}
|
|
635
|
-
</code>
|
|
636
|
-
<span className="text-[10px] text-base-content/15 ml-auto">{formatTime(msg.timestamp)}</span>
|
|
637
|
-
</div>
|
|
638
|
-
</div>
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
return (
|
|
643
|
-
<div className="ml-14 mr-5 py-1 max-w-[95%] sm:max-w-[75%]" onKeyDown={handleKeyDown} tabIndex={0} role="group" aria-label={"Permission request: " + (msg.name || "unknown tool")}>
|
|
644
|
-
<div className="border border-warning/30 bg-warning/5 rounded-lg p-3 flex flex-col gap-2 text-[13px]">
|
|
645
|
-
<div className="flex flex-col gap-1">
|
|
646
|
-
<div className="flex items-center gap-2">
|
|
647
|
-
<TriangleAlert size={14} className="text-warning flex-shrink-0" />
|
|
648
|
-
<code className="font-mono text-[11px] bg-base-300/60 px-1.5 py-0.5 rounded text-base-content/60">
|
|
649
|
-
{msg.name}
|
|
650
|
-
</code>
|
|
651
|
-
</div>
|
|
652
|
-
<div className="text-[13px] text-base-content/80">
|
|
653
|
-
{msg.title || "Permission required"}
|
|
654
|
-
</div>
|
|
655
|
-
</div>
|
|
656
|
-
|
|
657
|
-
{parsedArgs && (
|
|
658
|
-
<div>
|
|
659
|
-
<button
|
|
660
|
-
type="button"
|
|
661
|
-
onClick={function () { setExpanded(function (v) { return !v; }); }}
|
|
662
|
-
className="text-[10px] text-base-content/30 hover:text-base-content/50 transition-colors flex items-center gap-1 cursor-pointer"
|
|
663
|
-
>
|
|
664
|
-
<ChevronDown size={10} className={"transition-transform duration-150 " + (expanded ? "rotate-180" : "")} />
|
|
665
|
-
args
|
|
666
|
-
</button>
|
|
667
|
-
{expanded && (
|
|
668
|
-
<pre className="font-mono text-[11px] text-base-content/50 whitespace-pre-wrap break-words m-0 mt-1 leading-relaxed bg-base-100/50 px-2.5 py-2 rounded-md w-full max-h-[160px] overflow-y-auto">
|
|
669
|
-
{parsedArgs}
|
|
670
|
-
</pre>
|
|
671
|
-
)}
|
|
672
|
-
</div>
|
|
673
|
-
)}
|
|
674
|
-
|
|
675
|
-
<div className="flex gap-2 items-center relative">
|
|
676
|
-
<button
|
|
677
|
-
className="btn btn-warning btn-sm btn-outline"
|
|
678
|
-
onClick={function () { respond(true); }}
|
|
679
|
-
>
|
|
680
|
-
Allow
|
|
681
|
-
</button>
|
|
682
|
-
<div className="inline-flex">
|
|
683
|
-
<button
|
|
684
|
-
className="btn btn-ghost btn-sm text-warning/70 border border-warning/25 rounded-r-none border-r-0 text-[11px] px-2"
|
|
685
|
-
onClick={function () { respond(true, true, "session"); }}
|
|
686
|
-
>
|
|
687
|
-
Always Allow
|
|
688
|
-
</button>
|
|
689
|
-
<button
|
|
690
|
-
ref={scopeBtnRef}
|
|
691
|
-
className="btn btn-ghost btn-sm text-warning/70 border border-warning/25 rounded-l-none text-[11px] px-1"
|
|
692
|
-
onClick={function () { setShowScopeMenu(function (v) { return !v; }); }}
|
|
693
|
-
>
|
|
694
|
-
<ChevronDown size={10} />
|
|
695
|
-
</button>
|
|
696
|
-
</div>
|
|
697
|
-
<button
|
|
698
|
-
className="btn btn-ghost btn-sm text-base-content/40"
|
|
699
|
-
onClick={function () { respond(false); }}
|
|
700
|
-
>
|
|
701
|
-
Deny
|
|
702
|
-
</button>
|
|
703
|
-
<span className="text-[10px] text-base-content/20 italic ml-auto">waiting for approval...</span>
|
|
704
|
-
|
|
705
|
-
{showScopeMenu && (
|
|
706
|
-
<div className={"absolute left-0 sm:left-[88px] z-50 bg-base-300 border border-warning/20 rounded-lg shadow-xl p-1 text-[12px] font-mono w-[calc(100vw-48px)] sm:w-auto sm:min-w-[220px] max-w-[280px] " + (dropUp ? "bottom-full mb-1" : "top-full mt-1")}>
|
|
707
|
-
<button
|
|
708
|
-
className="flex flex-col w-full px-2.5 py-1.5 rounded hover:bg-warning/10 text-left text-base-content/70 transition-colors"
|
|
709
|
-
onClick={function () { setShowScopeMenu(false); respond(true, true, "session"); }}
|
|
710
|
-
>
|
|
711
|
-
<div className="flex items-center gap-2">
|
|
712
|
-
<Shield size={11} className="text-warning/60" />
|
|
713
|
-
This session only
|
|
714
|
-
</div>
|
|
715
|
-
</button>
|
|
716
|
-
<button
|
|
717
|
-
className="flex flex-col w-full px-2.5 py-1.5 rounded hover:bg-warning/10 text-left text-base-content/70 transition-colors"
|
|
718
|
-
onClick={function () { setShowScopeMenu(false); respond(true, true, "project"); }}
|
|
719
|
-
>
|
|
720
|
-
<div className="flex items-center gap-2">
|
|
721
|
-
<Shield size={11} className="text-warning/60" />
|
|
722
|
-
This project
|
|
723
|
-
</div>
|
|
724
|
-
{msg.permissionRule && (
|
|
725
|
-
<code className="text-[9px] text-base-content/25 mt-0.5 ml-[19px]">{msg.permissionRule}</code>
|
|
726
|
-
)}
|
|
727
|
-
</button>
|
|
728
|
-
</div>
|
|
729
|
-
)}
|
|
730
|
-
</div>
|
|
731
|
-
</div>
|
|
732
|
-
</div>
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
function CompactSummaryMessage(props: { message: HistoryMessage }) {
|
|
737
|
-
var [expanded, setExpanded] = useState(false);
|
|
738
|
-
var msg = props.message;
|
|
739
|
-
var text = msg.text || "";
|
|
740
|
-
var time = formatTime(msg.timestamp);
|
|
741
|
-
|
|
742
|
-
return (
|
|
743
|
-
<div id={msg.uuid ? "msg-" + msg.uuid : undefined} className="px-5 py-3">
|
|
744
|
-
<button
|
|
745
|
-
type="button"
|
|
746
|
-
onClick={function () { setExpanded(function (v) { return !v; }); }}
|
|
747
|
-
aria-expanded={expanded}
|
|
748
|
-
className="w-full flex items-center gap-3 group/compact focus-visible:outline-none"
|
|
749
|
-
>
|
|
750
|
-
<div className="h-px flex-1 bg-base-content/8 group-hover/compact:bg-base-content/15 transition-colors duration-150" />
|
|
751
|
-
<div className={"flex items-center gap-1.5 px-2.5 py-1 rounded-full border transition-all duration-150 " + (expanded ? "border-primary/30 bg-primary/8 text-primary/70" : "border-base-content/10 bg-base-200/60 text-base-content/35 hover:border-base-content/20 hover:text-base-content/55")}>
|
|
752
|
-
<History size={11} className="shrink-0" />
|
|
753
|
-
<span className="text-[10px] font-mono font-semibold tracking-wider uppercase">Context Compacted</span>
|
|
754
|
-
{time && <span className="text-[9px] opacity-60 ml-0.5">{time}</span>}
|
|
755
|
-
<ChevronDown size={10} className={"ml-0.5 transition-transform duration-200 " + (expanded ? "rotate-180" : "")} />
|
|
756
|
-
</div>
|
|
757
|
-
<div className="h-px flex-1 bg-base-content/8 group-hover/compact:bg-base-content/15 transition-colors duration-150" />
|
|
758
|
-
</button>
|
|
759
|
-
|
|
760
|
-
{expanded && (
|
|
761
|
-
<div className="mt-3 mx-auto max-w-[760px]">
|
|
762
|
-
<div className="rounded-xl border border-base-content/8 bg-base-200/40 overflow-hidden">
|
|
763
|
-
<div className="flex items-center gap-2 px-3 py-2 border-b border-base-content/6 bg-base-200/60">
|
|
764
|
-
<History size={12} className="text-base-content/30 shrink-0" />
|
|
765
|
-
<span className="text-[10px] font-mono font-semibold text-base-content/35 uppercase tracking-wider">Session Summary</span>
|
|
766
|
-
<span className="ml-auto text-[9px] text-base-content/20 font-mono">{time}</span>
|
|
767
|
-
</div>
|
|
768
|
-
<div className="max-h-[480px] overflow-y-auto p-4 prose prose-sm max-w-none [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 prose-headings:text-base-content/70 prose-headings:text-[12px] prose-headings:font-mono prose-headings:uppercase prose-headings:tracking-wide prose-headings:mt-4 prose-headings:mb-1.5 prose-p:text-base-content/50 prose-p:text-[12px] prose-p:leading-relaxed prose-strong:text-base-content/65 prose-code:text-base-content/50 prose-code:text-[11px] prose-code:bg-base-content/5 prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-li:text-base-content/50 prose-li:text-[12px] prose-hr:border-base-content/8">
|
|
769
|
-
<Markdown remarkPlugins={[remarkGfm]} components={mdComponents}>{text}</Markdown>
|
|
770
|
-
</div>
|
|
771
|
-
</div>
|
|
772
|
-
</div>
|
|
773
|
-
)}
|
|
774
|
-
</div>
|
|
775
|
-
);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
export var Message = memo(function Message(props: MessageProps) {
|
|
779
|
-
var msg = props.message;
|
|
780
|
-
|
|
781
|
-
if (msg.type === "user") {
|
|
782
|
-
return <UserMessage message={msg} />;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
if (msg.type === "assistant") {
|
|
786
|
-
return <AssistantMessage message={msg} responseCost={props.responseCost} responseDuration={props.responseDuration} />;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
if (msg.type === "tool_start") {
|
|
790
|
-
return <ToolMessage message={msg} />;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
if (msg.type === "compact_summary") {
|
|
794
|
-
return <CompactSummaryMessage message={msg} />;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
if (msg.type === "permission_request") {
|
|
798
|
-
return <PermissionMessage message={msg} />;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
if (msg.type === "prompt_question") {
|
|
802
|
-
return <PromptQuestion message={msg} />;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
if (msg.type === "todo_update") {
|
|
806
|
-
return <TodoCard message={msg} />;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
if (msg.type === "elicitation") {
|
|
810
|
-
return (
|
|
811
|
-
<ElicitationCard
|
|
812
|
-
requestId={msg.toolId || ""}
|
|
813
|
-
serverName={msg.elicitationServerName || "MCP Server"}
|
|
814
|
-
message={msg.elicitationMessage || ""}
|
|
815
|
-
mode={msg.elicitationMode || "form"}
|
|
816
|
-
url={msg.elicitationUrl}
|
|
817
|
-
requestedSchema={msg.elicitationSchema}
|
|
818
|
-
resolved={msg.elicitationStatus !== "pending"}
|
|
819
|
-
resolvedAction={msg.elicitationStatus === "accepted" ? "accept" : msg.elicitationStatus === "declined" ? "decline" : undefined}
|
|
820
|
-
/>
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
return null;
|
|
825
|
-
});
|