@cryptiklemur/lattice 4.0.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (394) hide show
  1. package/bin/lattice +1 -9
  2. package/dist/client/assets/{angular-html-N8PCEquT.js → angular-html-DKTL-XDO.js} +1 -1
  3. package/dist/client/assets/{angular-ts-CJ8RJIPD.js → angular-ts-tvBzOwQR.js} +1 -1
  4. package/dist/client/assets/{apl-BD6tCLWN.js → apl-CCzl5qFl.js} +1 -1
  5. package/dist/client/assets/{astro-CpIIfBs6.js → astro-DNQTpO2Y.js} +1 -1
  6. package/dist/client/assets/{blade-D3qgnjiV.js → blade-CyJoIMeJ.js} +1 -1
  7. package/dist/client/assets/{c-Dr6ADN_t.js → c-OEwk5KN8.js} +1 -1
  8. package/dist/client/assets/{cobol-BIfDE0Hr.js → cobol-DpHyJzz2.js} +1 -1
  9. package/dist/client/assets/{coffee-DHQ57vfY.js → coffee-BX5dbDzZ.js} +1 -1
  10. package/dist/client/assets/{cpp-CEBY6JOp.js → cpp-BTBjNg2U.js} +1 -1
  11. package/dist/client/assets/{crystal-D125CSmP.js → crystal-CNzZd6DW.js} +1 -1
  12. package/dist/client/assets/{css-CBmrkYSr.js → css-BuKsNmms.js} +1 -1
  13. package/dist/client/assets/{dist-A_mCRD1f.js → dist-CKpDHMy6.js} +2 -2
  14. package/dist/client/assets/{edge-Ccsz7cJW.js → edge-DzhnGgJE.js} +1 -1
  15. package/dist/client/assets/{elixir-Do6gk14X.js → elixir-Dqs0waqF.js} +1 -1
  16. package/dist/client/assets/{elm-Db22zT4C.js → elm-BtWwjxWn.js} +1 -1
  17. package/dist/client/assets/{erb-MXVqAAJD.js → erb-iPD89b4v.js} +1 -1
  18. package/dist/client/assets/{git-rebase-B-LLWBOA.js → git-rebase-BxVNXJL4.js} +1 -1
  19. package/dist/client/assets/{glimmer-js-eWszRU73.js → glimmer-js-BlyCupwF.js} +1 -1
  20. package/dist/client/assets/{glimmer-ts-VQmwGqUp.js → glimmer-ts-DjIxWOS9.js} +1 -1
  21. package/dist/client/assets/{glsl-B8ilOfAl.js → glsl-CGIL-65r.js} +1 -1
  22. package/dist/client/assets/{graphql-DnTqxeOc.js → graphql-DeOn6mNV.js} +1 -1
  23. package/dist/client/assets/{hack-XJsHYSQb.js → hack-DVppeCmS.js} +1 -1
  24. package/dist/client/assets/{haml-CQ7Vqzwp.js → haml-WDhua0Mp.js} +1 -1
  25. package/dist/client/assets/{handlebars-C4szooBf.js → handlebars-i2Fu_9HI.js} +1 -1
  26. package/dist/client/assets/{html-B6EgAiSd.js → html-B1e6oxzK.js} +1 -1
  27. package/dist/client/assets/{html-derivative-DdinogQX.js → html-derivative-MofKXIVd.js} +1 -1
  28. package/dist/client/assets/{http-BSLxCgRq.js → http-Dk6S5pRD.js} +1 -1
  29. package/dist/client/assets/{hurl-pOsTwNfp.js → hurl-CroFYYJG.js} +1 -1
  30. package/dist/client/assets/{index-BHQ_8mvl.js → index-CVu-S6Yk.js} +2 -2
  31. package/dist/client/assets/{java-DRQLiiST.js → java-B89FYjqS.js} +1 -1
  32. package/dist/client/assets/{javascript-DvEK2-47.js → javascript-m6CO1Uiy.js} +1 -1
  33. package/dist/client/assets/{jinja-D2NYJ25y.js → jinja-DC9Wi41X.js} +1 -1
  34. package/dist/client/assets/{jison-DDZaLNAp.js → jison-6xiegwDk.js} +1 -1
  35. package/dist/client/assets/{json-TGR0NIWd.js → json-HA-96-qr.js} +1 -1
  36. package/dist/client/assets/{jsx-BjUoPYga.js → jsx-Wt1a8i8U.js} +1 -1
  37. package/dist/client/assets/{julia-C4gjSpFu.js → julia-7M93VBON.js} +1 -1
  38. package/dist/client/assets/{just-H351x5u_.js → just-CjfDLYLv.js} +1 -1
  39. package/dist/client/assets/{latex-BiTmf6gf.js → latex-CitsJ46x.js} +1 -1
  40. package/dist/client/assets/{liquid-86ufjRy-.js → liquid-C8VIFin8.js} +1 -1
  41. package/dist/client/assets/{lua-BNxR0F_8.js → lua-Ba2N7esc.js} +1 -1
  42. package/dist/client/assets/{marko-CvRxpRjM.js → marko-lTLvb2wu.js} +1 -1
  43. package/dist/client/assets/{mdc-CYbAIy2C.js → mdc-D6IV-8FD.js} +1 -1
  44. package/dist/client/assets/{nginx-egdgMq-F.js → nginx-Ch5AjE6S.js} +1 -1
  45. package/dist/client/assets/{nim-CXBJVz_w.js → nim-WmDDC6LW.js} +1 -1
  46. package/dist/client/assets/{perl-XRfMobzg.js → perl-CQv0gYuq.js} +1 -1
  47. package/dist/client/assets/{php-Br7a8uil.js → php-BJmH0qOB.js} +1 -1
  48. package/dist/client/assets/{pug-BVbbUVvy.js → pug-CsHPkzc9.js} +1 -1
  49. package/dist/client/assets/{qml-ByKvrL1j.js → qml-B36ecArG.js} +1 -1
  50. package/dist/client/assets/{r-mVoV0Ni6.js → r-D5Yi5Z4y.js} +1 -1
  51. package/dist/client/assets/{razor-T5O-9UJL.js → razor-CHAxVq4R.js} +1 -1
  52. package/dist/client/assets/{regexp-CioRuhuN.js → regexp-gfs--3M7.js} +1 -1
  53. package/dist/client/assets/{rst-V__uTudD.js → rst-ugdlp-hl.js} +1 -1
  54. package/dist/client/assets/{ruby-C_PuKPTI.js → ruby-CDRRW37j.js} +1 -1
  55. package/dist/client/assets/{sas-D_DqqQH4.js → sas-DZaNQaIP.js} +1 -1
  56. package/dist/client/assets/{scss-D-TjzZ4c.js → scss-CzWQEplj.js} +1 -1
  57. package/dist/client/assets/{shellscript-E5759VHu.js → shellscript-fgYvpu9N.js} +1 -1
  58. package/dist/client/assets/{shellsession-AESTM-Pv.js → shellsession-BoAohHh7.js} +1 -1
  59. package/dist/client/assets/{soy-QrbrrcDv.js → soy-DBzVgv9x.js} +1 -1
  60. package/dist/client/assets/{sql-0M8VcDHD.js → sql-BYXpAYTs.js} +1 -1
  61. package/dist/client/assets/{stata-CgeIpGtc.js → stata-I71MMY3p.js} +1 -1
  62. package/dist/client/assets/{surrealql-DBGwnZbw.js → surrealql-C9U8_1VO.js} +1 -1
  63. package/dist/client/assets/{svelte-Cv0PvUc_.js → svelte-VOFrPnWT.js} +1 -1
  64. package/dist/client/assets/{templ-B9t7xRE4.js → templ-BIaxAEtC.js} +1 -1
  65. package/dist/client/assets/{tex-DhZZ8dr2.js → tex-D1dwnBE5.js} +1 -1
  66. package/dist/client/assets/{ts-tags-BFv8sbnd.js → ts-tags-C0L2Q0r5.js} +1 -1
  67. package/dist/client/assets/{tsx-CXC9KSbY.js → tsx-BqcycEv1.js} +1 -1
  68. package/dist/client/assets/{twig-CM_OO66r.js → twig-vyWqOhpM.js} +1 -1
  69. package/dist/client/assets/{typescript-BdgOTaoD.js → typescript-B2YbovqG.js} +1 -1
  70. package/dist/client/assets/{vue-BnQhjnCm.js → vue-CbXxGdjo.js} +1 -1
  71. package/dist/client/assets/{vue-html-CNnGecRI.js → vue-html-DDX4KXW7.js} +1 -1
  72. package/dist/client/assets/{vue-vine-DCuMkRhK.js → vue-vine-DsyY1LR5.js} +1 -1
  73. package/dist/client/assets/{xml-CbTD7cB8.js → xml-Ddi0-r0D.js} +1 -1
  74. package/dist/client/assets/{xsl-uOqqo7cf.js → xsl-CsFcZHFS.js} +1 -1
  75. package/dist/client/assets/{yaml-BNrLoH59.js → yaml-tGJWoH6Y.js} +1 -1
  76. package/dist/client/index.html +1 -1
  77. package/dist/client/sw.js +1 -1
  78. package/dist/server/analytics/engine.js +832 -0
  79. package/dist/server/assets.js +39 -0
  80. package/dist/server/auth/passphrase.js +70 -0
  81. package/dist/server/config.js +47 -0
  82. package/dist/server/daemon.js +533 -0
  83. package/dist/server/features/ralph-loop.js +138 -0
  84. package/dist/server/features/scheduler.js +260 -0
  85. package/dist/server/features/sticky-notes.js +99 -0
  86. package/dist/server/handlers/analytics.js +28 -0
  87. package/dist/server/handlers/attachment.js +158 -0
  88. package/dist/server/handlers/bookmarks.js +41 -0
  89. package/dist/server/handlers/chat.js +350 -0
  90. package/dist/server/handlers/editor.js +72 -0
  91. package/dist/server/handlers/fs.js +234 -0
  92. package/dist/server/handlers/loop.js +33 -0
  93. package/dist/server/handlers/memory.js +181 -0
  94. package/dist/server/handlers/mesh.js +322 -0
  95. package/dist/server/handlers/notes.js +36 -0
  96. package/dist/server/handlers/plugins.js +593 -0
  97. package/dist/server/handlers/project-settings.js +166 -0
  98. package/dist/server/handlers/scheduler.js +52 -0
  99. package/dist/server/handlers/session.js +194 -0
  100. package/dist/server/handlers/settings.js +148 -0
  101. package/dist/server/handlers/skills.js +360 -0
  102. package/dist/server/handlers/terminal.js +75 -0
  103. package/dist/server/handlers/themes.js +102 -0
  104. package/dist/server/handlers/update.js +124 -0
  105. package/dist/server/identity.js +45 -0
  106. package/dist/server/index.js +435 -0
  107. package/dist/server/logger.js +20 -0
  108. package/dist/server/mesh/connector.js +355 -0
  109. package/dist/server/mesh/crypto.js +88 -0
  110. package/dist/server/mesh/discovery.js +95 -0
  111. package/dist/server/mesh/pairing.js +104 -0
  112. package/dist/server/mesh/peers.js +54 -0
  113. package/dist/server/mesh/proxy.js +86 -0
  114. package/dist/server/mesh/session-sync.js +85 -0
  115. package/dist/server/project/bookmarks.js +77 -0
  116. package/dist/server/project/context-breakdown.js +279 -0
  117. package/dist/server/project/file-browser.js +97 -0
  118. package/dist/server/project/project-files.js +274 -0
  119. package/dist/server/project/registry.js +51 -0
  120. package/dist/server/project/sdk-bridge.js +960 -0
  121. package/dist/server/project/session.js +696 -0
  122. package/dist/server/project/terminal.js +87 -0
  123. package/dist/server/project/warmup.js +242 -0
  124. package/dist/server/push.js +87 -0
  125. package/dist/server/tls.js +50 -0
  126. package/dist/server/tui.js +83 -0
  127. package/dist/server/update-checker.js +119 -0
  128. package/dist/server/ws/broadcast.js +50 -0
  129. package/dist/server/ws/router.js +105 -0
  130. package/dist/server/ws/server.js +2 -0
  131. package/dist/shared/analytics.js +1 -0
  132. package/dist/shared/messages.js +1 -0
  133. package/dist/shared/models.js +1 -0
  134. package/dist/shared/project-settings.js +1 -0
  135. package/package.json +5 -8
  136. package/themes/alabaster.json +9 -0
  137. package/themes/amoled.json +20 -0
  138. package/themes/ayu-light.json +9 -0
  139. package/themes/catppuccin-latte.json +9 -0
  140. package/themes/catppuccin-mocha.json +9 -0
  141. package/themes/clay-light.json +10 -0
  142. package/themes/clay.json +10 -0
  143. package/themes/dracula.json +9 -0
  144. package/themes/everforest-light.json +9 -0
  145. package/themes/everforest.json +9 -0
  146. package/themes/github-light.json +9 -0
  147. package/themes/gruvbox-dark.json +9 -0
  148. package/themes/gruvbox-light.json +9 -0
  149. package/themes/horizon-light.json +9 -0
  150. package/themes/kanagawa-lotus.json +9 -0
  151. package/themes/kanagawa.json +9 -0
  152. package/themes/modus-operandi.json +9 -0
  153. package/themes/monokai.json +9 -0
  154. package/themes/nightfox.json +9 -0
  155. package/themes/nord-light.json +9 -0
  156. package/themes/nord.json +9 -0
  157. package/themes/one-dark.json +9 -0
  158. package/themes/one-light.json +9 -0
  159. package/themes/palenight.json +9 -0
  160. package/themes/paper.json +9 -0
  161. package/themes/penumbra-light.json +9 -0
  162. package/themes/poimandres.json +9 -0
  163. package/themes/quiet-light.json +9 -0
  164. package/themes/rose-pine-dawn.json +9 -0
  165. package/themes/rose-pine.json +9 -0
  166. package/themes/solarized-dark.json +9 -0
  167. package/themes/solarized-light.json +9 -0
  168. package/themes/synthwave84.json +9 -0
  169. package/themes/tokyo-night-light.json +9 -0
  170. package/themes/tokyo-night.json +9 -0
  171. package/themes/vesper.json +9 -0
  172. package/index.html +0 -20
  173. package/public/icons/icon-192.svg +0 -11
  174. package/public/icons/icon-512.svg +0 -11
  175. package/public/sw-push.js +0 -53
  176. package/src/client/App.tsx +0 -42
  177. package/src/client/commands.ts +0 -36
  178. package/src/client/components/analytics/AnalyticsView.tsx +0 -244
  179. package/src/client/components/analytics/ChartCard.tsx +0 -194
  180. package/src/client/components/analytics/PeriodSelector.tsx +0 -42
  181. package/src/client/components/analytics/QuickStats.tsx +0 -122
  182. package/src/client/components/analytics/chartTokens.ts +0 -188
  183. package/src/client/components/analytics/charts/ActivityCalendar.tsx +0 -204
  184. package/src/client/components/analytics/charts/CacheEfficiencyChart.tsx +0 -56
  185. package/src/client/components/analytics/charts/ContextUtilizationChart.tsx +0 -106
  186. package/src/client/components/analytics/charts/CostAreaChart.tsx +0 -79
  187. package/src/client/components/analytics/charts/CostDistributionChart.tsx +0 -59
  188. package/src/client/components/analytics/charts/CostDonutChart.tsx +0 -84
  189. package/src/client/components/analytics/charts/CumulativeCostChart.tsx +0 -59
  190. package/src/client/components/analytics/charts/DailySummaryCards.tsx +0 -86
  191. package/src/client/components/analytics/charts/HourlyHeatmap.tsx +0 -133
  192. package/src/client/components/analytics/charts/NodeFleetOverview.tsx +0 -89
  193. package/src/client/components/analytics/charts/PermissionBreakdown.tsx +0 -98
  194. package/src/client/components/analytics/charts/ProjectRadar.tsx +0 -126
  195. package/src/client/components/analytics/charts/ResponseTimeScatter.tsx +0 -96
  196. package/src/client/components/analytics/charts/SessionBubbleChart.tsx +0 -114
  197. package/src/client/components/analytics/charts/SessionComplexityList.tsx +0 -65
  198. package/src/client/components/analytics/charts/SessionTimeline.tsx +0 -107
  199. package/src/client/components/analytics/charts/TokenFlowChart.tsx +0 -78
  200. package/src/client/components/analytics/charts/TokenSankeyChart.tsx +0 -93
  201. package/src/client/components/analytics/charts/ToolSunburst.tsx +0 -123
  202. package/src/client/components/analytics/charts/ToolTreemap.tsx +0 -110
  203. package/src/client/components/auth/PassphrasePrompt.tsx +0 -70
  204. package/src/client/components/chat/AttachmentChips.tsx +0 -116
  205. package/src/client/components/chat/ChatInput.tsx +0 -533
  206. package/src/client/components/chat/ChatView.tsx +0 -1076
  207. package/src/client/components/chat/CommandPalette.tsx +0 -162
  208. package/src/client/components/chat/ElicitationCard.tsx +0 -238
  209. package/src/client/components/chat/Message.tsx +0 -825
  210. package/src/client/components/chat/ModelSelector.tsx +0 -108
  211. package/src/client/components/chat/PermissionModeSelector.tsx +0 -41
  212. package/src/client/components/chat/PromptQuestion.tsx +0 -271
  213. package/src/client/components/chat/StatusBar.tsx +0 -50
  214. package/src/client/components/chat/TodoCard.tsx +0 -57
  215. package/src/client/components/chat/ToolGroup.tsx +0 -129
  216. package/src/client/components/chat/ToolResultRenderer.tsx +0 -348
  217. package/src/client/components/chat/VoiceRecorder.tsx +0 -85
  218. package/src/client/components/chat/toolSummary.ts +0 -41
  219. package/src/client/components/dashboard/DashboardView.tsx +0 -200
  220. package/src/client/components/dashboard/ProjectDashboardView.tsx +0 -179
  221. package/src/client/components/mesh/NodeBadge.tsx +0 -24
  222. package/src/client/components/mesh/PairingDialog.tsx +0 -340
  223. package/src/client/components/project-settings/ProjectClaude.tsx +0 -318
  224. package/src/client/components/project-settings/ProjectEnvironment.tsx +0 -235
  225. package/src/client/components/project-settings/ProjectGeneral.tsx +0 -76
  226. package/src/client/components/project-settings/ProjectMcp.tsx +0 -232
  227. package/src/client/components/project-settings/ProjectMemory.tsx +0 -488
  228. package/src/client/components/project-settings/ProjectNotifications.tsx +0 -48
  229. package/src/client/components/project-settings/ProjectPermissions.tsx +0 -209
  230. package/src/client/components/project-settings/ProjectPlugins.tsx +0 -117
  231. package/src/client/components/project-settings/ProjectRules.tsx +0 -286
  232. package/src/client/components/project-settings/ProjectSettingsView.tsx +0 -117
  233. package/src/client/components/project-settings/ProjectSkills.tsx +0 -91
  234. package/src/client/components/settings/Appearance.tsx +0 -275
  235. package/src/client/components/settings/BudgetSettings.tsx +0 -165
  236. package/src/client/components/settings/ClaudeSettings.tsx +0 -175
  237. package/src/client/components/settings/Editor.tsx +0 -123
  238. package/src/client/components/settings/Environment.tsx +0 -185
  239. package/src/client/components/settings/GlobalMcp.tsx +0 -216
  240. package/src/client/components/settings/GlobalMemory.tsx +0 -19
  241. package/src/client/components/settings/GlobalPlugins.tsx +0 -806
  242. package/src/client/components/settings/GlobalRules.tsx +0 -149
  243. package/src/client/components/settings/GlobalSkills.tsx +0 -140
  244. package/src/client/components/settings/MeshStatus.tsx +0 -183
  245. package/src/client/components/settings/Notifications.tsx +0 -123
  246. package/src/client/components/settings/SettingsView.tsx +0 -75
  247. package/src/client/components/settings/SkillMarketplace.tsx +0 -175
  248. package/src/client/components/settings/ThemePreview.tsx +0 -140
  249. package/src/client/components/settings/ThemeWizard.tsx +0 -405
  250. package/src/client/components/settings/mcp-shared.tsx +0 -194
  251. package/src/client/components/settings/skill-shared.tsx +0 -186
  252. package/src/client/components/setup/SetupWizard.tsx +0 -755
  253. package/src/client/components/sidebar/AddProjectModal.tsx +0 -438
  254. package/src/client/components/sidebar/NodeSettingsModal.tsx +0 -206
  255. package/src/client/components/sidebar/ProjectDropdown.tsx +0 -211
  256. package/src/client/components/sidebar/ProjectRail.tsx +0 -353
  257. package/src/client/components/sidebar/SearchFilter.tsx +0 -52
  258. package/src/client/components/sidebar/SessionList.tsx +0 -599
  259. package/src/client/components/sidebar/SettingsSidebar.tsx +0 -139
  260. package/src/client/components/sidebar/Sidebar.tsx +0 -469
  261. package/src/client/components/sidebar/UserIsland.tsx +0 -282
  262. package/src/client/components/sidebar/UserMenu.tsx +0 -107
  263. package/src/client/components/ui/CommandPalette.tsx +0 -321
  264. package/src/client/components/ui/ContextMenu.tsx +0 -153
  265. package/src/client/components/ui/ErrorBoundary.tsx +0 -56
  266. package/src/client/components/ui/IconPicker.tsx +0 -184
  267. package/src/client/components/ui/KeyboardShortcuts.tsx +0 -129
  268. package/src/client/components/ui/LatticeLogomark.tsx +0 -19
  269. package/src/client/components/ui/NodeDisconnectedOverlay.tsx +0 -35
  270. package/src/client/components/ui/PopupMenu.tsx +0 -120
  271. package/src/client/components/ui/SaveFooter.tsx +0 -63
  272. package/src/client/components/ui/Toast.tsx +0 -132
  273. package/src/client/components/ui/UpdateBanner.tsx +0 -110
  274. package/src/client/components/ui/UpdatePrompt.tsx +0 -47
  275. package/src/client/components/workspace/BookmarksView.tsx +0 -156
  276. package/src/client/components/workspace/FileBrowser.tsx +0 -174
  277. package/src/client/components/workspace/FileTree.tsx +0 -129
  278. package/src/client/components/workspace/FileViewer.tsx +0 -211
  279. package/src/client/components/workspace/NoteCard.tsx +0 -120
  280. package/src/client/components/workspace/NotesView.tsx +0 -102
  281. package/src/client/components/workspace/ScheduledTasksView.tsx +0 -117
  282. package/src/client/components/workspace/SplitPane.tsx +0 -81
  283. package/src/client/components/workspace/TabBar.tsx +0 -170
  284. package/src/client/components/workspace/TaskCard.tsx +0 -159
  285. package/src/client/components/workspace/TaskEditModal.tsx +0 -129
  286. package/src/client/components/workspace/TerminalInstance.tsx +0 -171
  287. package/src/client/components/workspace/TerminalView.tsx +0 -110
  288. package/src/client/components/workspace/WorkspaceView.tsx +0 -141
  289. package/src/client/hooks/useAnalytics.ts +0 -84
  290. package/src/client/hooks/useAttachments.ts +0 -313
  291. package/src/client/hooks/useBookmarks.ts +0 -57
  292. package/src/client/hooks/useEditorConfig.ts +0 -28
  293. package/src/client/hooks/useFocusTrap.ts +0 -74
  294. package/src/client/hooks/useIdleDetection.ts +0 -50
  295. package/src/client/hooks/useInstallPrompt.ts +0 -53
  296. package/src/client/hooks/useMesh.ts +0 -89
  297. package/src/client/hooks/useNotifications.ts +0 -54
  298. package/src/client/hooks/useOnline.ts +0 -6
  299. package/src/client/hooks/useProjectSettings.ts +0 -56
  300. package/src/client/hooks/useProjects.ts +0 -98
  301. package/src/client/hooks/usePushNotifications.ts +0 -92
  302. package/src/client/hooks/useSaveState.ts +0 -65
  303. package/src/client/hooks/useSession.ts +0 -580
  304. package/src/client/hooks/useSidebar.ts +0 -90
  305. package/src/client/hooks/useSkills.ts +0 -30
  306. package/src/client/hooks/useSpinnerVerb.ts +0 -36
  307. package/src/client/hooks/useSwipeDrawer.ts +0 -299
  308. package/src/client/hooks/useTheme.ts +0 -114
  309. package/src/client/hooks/useTimeTick.ts +0 -35
  310. package/src/client/hooks/useVoiceRecorder.ts +0 -169
  311. package/src/client/hooks/useWebSocket.ts +0 -27
  312. package/src/client/hooks/useWorkspace.ts +0 -57
  313. package/src/client/lib/theme-derive.ts +0 -196
  314. package/src/client/lib/workspace-url.ts +0 -219
  315. package/src/client/main.tsx +0 -10
  316. package/src/client/providers/WebSocketProvider.tsx +0 -186
  317. package/src/client/router.tsx +0 -578
  318. package/src/client/stores/analytics.ts +0 -68
  319. package/src/client/stores/bookmarks.ts +0 -45
  320. package/src/client/stores/mesh.ts +0 -78
  321. package/src/client/stores/session.ts +0 -569
  322. package/src/client/stores/sidebar.ts +0 -530
  323. package/src/client/stores/theme.ts +0 -44
  324. package/src/client/stores/workspace.ts +0 -518
  325. package/src/client/styles/global.css +0 -391
  326. package/src/client/styles/theme-vars.css +0 -18
  327. package/src/client/themes/index.ts +0 -105
  328. package/src/client/utils/editorUrl.ts +0 -55
  329. package/src/client/utils/findDuplicateKeys.ts +0 -12
  330. package/src/client/utils/formatSessionTitle.ts +0 -17
  331. package/src/client/vite-env.d.ts +0 -6
  332. package/src/server/analytics/engine.ts +0 -920
  333. package/src/server/assets.ts +0 -45
  334. package/src/server/auth/passphrase.ts +0 -78
  335. package/src/server/config.ts +0 -55
  336. package/src/server/daemon.ts +0 -567
  337. package/src/server/features/ralph-loop.ts +0 -173
  338. package/src/server/features/scheduler.ts +0 -304
  339. package/src/server/features/sticky-notes.ts +0 -104
  340. package/src/server/handlers/analytics.ts +0 -39
  341. package/src/server/handlers/attachment.ts +0 -189
  342. package/src/server/handlers/bookmarks.ts +0 -50
  343. package/src/server/handlers/chat.ts +0 -381
  344. package/src/server/handlers/editor.ts +0 -76
  345. package/src/server/handlers/fs.ts +0 -251
  346. package/src/server/handlers/loop.ts +0 -37
  347. package/src/server/handlers/memory.ts +0 -182
  348. package/src/server/handlers/mesh.ts +0 -362
  349. package/src/server/handlers/notes.ts +0 -47
  350. package/src/server/handlers/plugins.ts +0 -655
  351. package/src/server/handlers/project-settings.ts +0 -180
  352. package/src/server/handlers/scheduler.ts +0 -64
  353. package/src/server/handlers/session.ts +0 -226
  354. package/src/server/handlers/settings.ts +0 -157
  355. package/src/server/handlers/skills.ts +0 -378
  356. package/src/server/handlers/terminal.ts +0 -88
  357. package/src/server/handlers/themes.ts +0 -121
  358. package/src/server/handlers/update.ts +0 -133
  359. package/src/server/identity.ts +0 -56
  360. package/src/server/index.ts +0 -457
  361. package/src/server/logger.ts +0 -21
  362. package/src/server/mesh/connector.ts +0 -419
  363. package/src/server/mesh/crypto.ts +0 -106
  364. package/src/server/mesh/discovery.ts +0 -126
  365. package/src/server/mesh/pairing.ts +0 -123
  366. package/src/server/mesh/peers.ts +0 -60
  367. package/src/server/mesh/proxy.ts +0 -106
  368. package/src/server/mesh/session-sync.ts +0 -107
  369. package/src/server/project/bookmarks.ts +0 -83
  370. package/src/server/project/context-breakdown.ts +0 -307
  371. package/src/server/project/file-browser.ts +0 -106
  372. package/src/server/project/project-files.ts +0 -267
  373. package/src/server/project/pty-worker.cjs +0 -83
  374. package/src/server/project/registry.ts +0 -57
  375. package/src/server/project/sdk-bridge.ts +0 -1100
  376. package/src/server/project/session.ts +0 -723
  377. package/src/server/project/terminal.ts +0 -111
  378. package/src/server/project/warmup.ts +0 -285
  379. package/src/server/push.ts +0 -121
  380. package/src/server/tls.ts +0 -65
  381. package/src/server/tui.ts +0 -103
  382. package/src/server/update-checker.ts +0 -147
  383. package/src/server/ws/broadcast.ts +0 -61
  384. package/src/server/ws/router.ts +0 -123
  385. package/src/server/ws/server.ts +0 -2
  386. package/src/shared/analytics.ts +0 -40
  387. package/src/shared/messages.ts +0 -1302
  388. package/src/shared/models.ts +0 -255
  389. package/src/shared/project-settings.ts +0 -45
  390. package/tsconfig.json +0 -25
  391. package/vite.config.ts +0 -71
  392. /package/{src/server/runtime.ts → dist/server/runtime.js} +0 -0
  393. /package/{src/shared/constants.ts → dist/shared/constants.js} +0 -0
  394. /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
- });