@hienlh/ppm 0.9.93 → 0.9.94

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 (218) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/web/assets/ai-settings-section-LMO_cfIW.js +1 -0
  3. package/dist/web/assets/api-client-o_6TmLGC.js +1 -0
  4. package/dist/web/assets/api-settings-CoKe_BdR.js +1 -0
  5. package/dist/web/assets/architecture-PBZL5I3N-CUZIB1Vq.js +1 -0
  6. package/dist/web/assets/arrow-up-Dtrfv490.js +1 -0
  7. package/dist/web/assets/chat-tab-DQNdrUvL.js +10 -0
  8. package/dist/web/assets/chevron-right-BzAdxJRG.js +1 -0
  9. package/dist/web/assets/code-CuravVys.js +1 -0
  10. package/dist/web/assets/code-editor-B4XNYHnl.js +8 -0
  11. package/dist/web/assets/columns-2-4fQcE4PF.js +1 -0
  12. package/dist/web/assets/conflict-editor-BcsRDSCw.js +19 -0
  13. package/dist/web/assets/createLucideIcon-BjHrJDVb.js +1 -0
  14. package/dist/web/assets/{csv-preview-BZRICDP0.js → csv-preview-BizIVMyb.js} +2 -2
  15. package/dist/web/assets/database-D4DIhgi-.js +1 -0
  16. package/dist/web/assets/database-viewer-CfzAAtm3.js +2 -0
  17. package/dist/web/assets/diff-viewer-DgA9z9Ux.js +4 -0
  18. package/dist/web/assets/dist-C5IgeqrV.js +1 -0
  19. package/dist/web/assets/dist-im4ynINo.js +11 -0
  20. package/dist/web/assets/esm-K1XIK4vc.js +2 -0
  21. package/dist/web/assets/extension-store-3yZYn07W.js +1 -0
  22. package/dist/web/assets/{extension-webview-C1d6fezE.js → extension-webview-gHGB2Nw2.js} +2 -2
  23. package/dist/web/assets/gitGraph-HDMCJU4V-CtOMUphQ.js +1 -0
  24. package/dist/web/assets/index-B4mGNywE.js +26 -0
  25. package/dist/web/assets/index-BZ4G-2BK.css +2 -0
  26. package/dist/web/assets/info-3K5VOQVL-BCrPCWGY.js +1 -0
  27. package/dist/web/assets/input-CHRMley8.js +1 -0
  28. package/dist/web/assets/keybindings-store-BAuymsWd.js +1 -0
  29. package/dist/web/assets/keybindings-store-BKyNIeFB.js +1 -0
  30. package/dist/web/assets/{lib-DSLzfeW0.js → lib-D_kRA9p6.js} +1 -1
  31. package/dist/web/assets/markdown-renderer-sIjU5LtB.js +3 -0
  32. package/dist/web/assets/packet-RMMSAZCW-D_OqB-zi.js +1 -0
  33. package/dist/web/assets/pie-UPGHQEXC-WUHpLNJz.js +1 -0
  34. package/dist/web/assets/plus-51UQ45rf.js +1 -0
  35. package/dist/web/assets/port-forwarding-tab-BMXnuRuI.js +1 -0
  36. package/dist/web/assets/postgres-viewer-B6Wj5xiN.js +3 -0
  37. package/dist/web/assets/project-store-Ciq-cK1O.js +1 -0
  38. package/dist/web/assets/radar-KQ55EAFF-HQIIecVM.js +1 -0
  39. package/dist/web/assets/react-GqWghJ-L.js +1 -0
  40. package/dist/web/assets/refresh-cw-CSFrDtiu.js +1 -0
  41. package/dist/web/assets/scroll-area-DwWF9FpN.js +1 -0
  42. package/dist/web/assets/settings-store-B470PCWf.js +2 -0
  43. package/dist/web/assets/settings-tab-BKQo79HU.js +1 -0
  44. package/dist/web/assets/{sql-query-editor-DaePHpQI.js → sql-query-editor-DZ9xskL8.js} +1 -1
  45. package/dist/web/assets/sqlite-viewer-CytNesG3.js +1 -0
  46. package/dist/web/assets/square-nsMa3iMk.js +1 -0
  47. package/dist/web/assets/tab-store-DZbiYk7y.js +1 -0
  48. package/dist/web/assets/table-Dq575bPF.js +1 -0
  49. package/dist/web/assets/terminal-tab-DjfxKMSB.js +1 -0
  50. package/dist/web/assets/text-wrap-Cn6BNQfq.js +1 -0
  51. package/dist/web/assets/trash-2-CJYoLw7Q.js +1 -0
  52. package/dist/web/assets/treemap-KZPCXAKY-0wLgUUTz.js +1 -0
  53. package/dist/web/assets/{use-monaco-theme-CM4IMROI.js → use-monaco-theme-OY18iXNi.js} +1 -1
  54. package/dist/web/assets/vendor-markdown-0Mxgxy0L.js +295 -0
  55. package/dist/web/assets/vendor-mermaid-B2SLgECS.js +2657 -0
  56. package/dist/web/assets/vendor-ui-B-T_damt.js +45 -0
  57. package/dist/web/assets/vendor-xterm-ejLe7-tK.js +36 -0
  58. package/dist/web/assets/x-DlFGzN8d.js +1 -0
  59. package/dist/web/index.html +26 -21
  60. package/dist/web/sw.js +1 -1
  61. package/docs/code-standards.md +56 -4
  62. package/docs/journals/260415-frontend-memory-optimization.md +73 -0
  63. package/docs/project-changelog.md +11 -1
  64. package/docs/system-architecture.md +36 -0
  65. package/package.json +1 -1
  66. package/src/web/components/chat/message-list.tsx +59 -22
  67. package/src/web/components/chat/tool-cards.tsx +11 -4
  68. package/src/web/components/database/data-grid.tsx +2 -1
  69. package/src/web/components/editor/code-editor.tsx +14 -8
  70. package/src/web/components/editor/conflict-editor.tsx +2 -1
  71. package/src/web/components/editor/diff-viewer.tsx +2 -1
  72. package/src/web/components/editor/editor-breadcrumb.tsx +2 -1
  73. package/src/web/components/explorer/file-tree.tsx +6 -5
  74. package/src/web/components/explorer/search-panel.tsx +2 -1
  75. package/src/web/components/git/git-status-panel.tsx +2 -1
  76. package/src/web/components/layout/add-project-form.tsx +2 -1
  77. package/src/web/components/layout/mobile-drawer.tsx +2 -1
  78. package/src/web/components/layout/mobile-nav.tsx +2 -1
  79. package/src/web/components/layout/panel-layout.tsx +3 -3
  80. package/src/web/components/layout/project-bar.tsx +7 -6
  81. package/src/web/components/layout/project-bottom-sheet.tsx +2 -1
  82. package/src/web/components/layout/sidebar.tsx +5 -4
  83. package/src/web/components/layout/status-bar.tsx +5 -4
  84. package/src/web/components/layout/tab-bar.tsx +3 -3
  85. package/src/web/components/layout/tab-content.tsx +2 -1
  86. package/src/web/components/postgres/postgres-viewer.tsx +7 -5
  87. package/src/web/components/settings/settings-tab.tsx +2 -1
  88. package/src/web/components/shared/markdown-code-block.tsx +10 -8
  89. package/src/web/components/terminal/terminal-tab.tsx +3 -3
  90. package/src/web/hooks/use-chat.ts +4 -1
  91. package/vite.config.ts +17 -0
  92. package/dist/web/assets/_basePickBy-Bj0dI1ei.js +0 -1
  93. package/dist/web/assets/_baseUniq-CyzdZeQH.js +0 -1
  94. package/dist/web/assets/ai-settings-section-Bo9lCaTd.js +0 -1
  95. package/dist/web/assets/api-client-BvxmRZUi.js +0 -1
  96. package/dist/web/assets/api-settings-CUxg9RE5.js +0 -1
  97. package/dist/web/assets/arc-CxgHJ7Z4.js +0 -1
  98. package/dist/web/assets/architecture-PBZL5I3N-DDFO_NKq.js +0 -1
  99. package/dist/web/assets/architectureDiagram-2XIMDMQ5-D16OotsC.js +0 -36
  100. package/dist/web/assets/array-BFDiaBgf.js +0 -1
  101. package/dist/web/assets/arrow-up-I9-21gkR.js +0 -1
  102. package/dist/web/assets/blockDiagram-WCTKOSBZ-Ct57Wtfk.js +0 -132
  103. package/dist/web/assets/c4Diagram-IC4MRINW-BIymcNsg.js +0 -10
  104. package/dist/web/assets/channel-wumTB1if.js +0 -1
  105. package/dist/web/assets/chat-tab-CC721_mQ.js +0 -10
  106. package/dist/web/assets/chevron-right-DY_wImxB.js +0 -1
  107. package/dist/web/assets/chunk-4BX2VUAB-CENmY7Kw.js +0 -1
  108. package/dist/web/assets/chunk-55IACEB6-DhZGI1l3.js +0 -1
  109. package/dist/web/assets/chunk-7E7YKBS2-DZcnC7Ow.js +0 -1
  110. package/dist/web/assets/chunk-7R4GIKGN-y8bfHEy-.js +0 -80
  111. package/dist/web/assets/chunk-C72U2L5F-BHPkfQj2.js +0 -1
  112. package/dist/web/assets/chunk-EGIJ26TM-nant2LXl.js +0 -1
  113. package/dist/web/assets/chunk-FMBD7UC4-Bog4cpN-.js +0 -15
  114. package/dist/web/assets/chunk-GEFDOKGD-86LFbsAC.js +0 -2
  115. package/dist/web/assets/chunk-GLR3WWYH-Re-5eSlQ.js +0 -2
  116. package/dist/web/assets/chunk-HHEYEP7N-C45i5G_3.js +0 -1
  117. package/dist/web/assets/chunk-JSJVCQXG-23eG9mgt.js +0 -1
  118. package/dist/web/assets/chunk-KX2RTZJC-CHj8TnTB.js +0 -1
  119. package/dist/web/assets/chunk-KYZI473N-gqRLpJ4w.js +0 -53
  120. package/dist/web/assets/chunk-L3YUKLVL-DnSMmNFC.js +0 -1
  121. package/dist/web/assets/chunk-MX3YWQON-B6g1ZH9X.js +0 -1
  122. package/dist/web/assets/chunk-NQ4KR5QH-DX32345Y.js +0 -220
  123. package/dist/web/assets/chunk-O4XLMI2P-Vp_V4P-b.js +0 -7
  124. package/dist/web/assets/chunk-OZEHJAEY-lKq2SWjA.js +0 -1
  125. package/dist/web/assets/chunk-PQ6SQG4A-Bik13fTV.js +0 -1
  126. package/dist/web/assets/chunk-PU5JKC2W-DD95Rx35.js +0 -70
  127. package/dist/web/assets/chunk-QZHKN3VN-N3VXx1VH.js +0 -1
  128. package/dist/web/assets/chunk-R5LLSJPH-dRhXRnrb.js +0 -1
  129. package/dist/web/assets/chunk-WL4C6EOR-B1iIvLOG.js +0 -189
  130. package/dist/web/assets/chunk-XIRO2GV7-DZBoNl1_.js +0 -1
  131. package/dist/web/assets/chunk-XPW4576I-CgLyyW03.js +0 -32
  132. package/dist/web/assets/chunk-XZSTWKYB-DjV8xl5A.js +0 -94
  133. package/dist/web/assets/chunk-YBOYWFTD-D_ILLe6_.js +0 -1
  134. package/dist/web/assets/classDiagram-VBA2DB6C-mr-Cb1me.js +0 -1
  135. package/dist/web/assets/classDiagram-v2-RAHNMMFH-BKe8_uda.js +0 -1
  136. package/dist/web/assets/clone--z5KLAuR.js +0 -1
  137. package/dist/web/assets/code-editor-BZ0xwZ4Z.js +0 -8
  138. package/dist/web/assets/columns-2-IeETSfON.js +0 -1
  139. package/dist/web/assets/conflict-editor-Bwls2-yk.js +0 -19
  140. package/dist/web/assets/cose-bilkent-S5V4N54A-BGNPFv3x.js +0 -1
  141. package/dist/web/assets/cytoscape.esm-C8i2jUzT.js +0 -321
  142. package/dist/web/assets/dagre-CkhlMHnx.js +0 -1
  143. package/dist/web/assets/dagre-KLK3FWXG-Cnp996VG.js +0 -4
  144. package/dist/web/assets/database-CgTomMxt.js +0 -1
  145. package/dist/web/assets/database-viewer-DiXWqOJH.js +0 -2
  146. package/dist/web/assets/defaultLocale-ZeknFqNe.js +0 -1
  147. package/dist/web/assets/diagram-E7M64L7V-BZF0tSOr.js +0 -24
  148. package/dist/web/assets/diagram-IFDJBPK2-nUcO8sN8.js +0 -43
  149. package/dist/web/assets/diagram-P4PSJMXO-CW0eCkwC.js +0 -24
  150. package/dist/web/assets/diff-viewer-CC-RmeV5.js +0 -4
  151. package/dist/web/assets/dist-CM0oD8tQ.js +0 -1
  152. package/dist/web/assets/dist-DZmJeHOA.js +0 -1
  153. package/dist/web/assets/erDiagram-INFDFZHY-DSkriYZ9.js +0 -70
  154. package/dist/web/assets/flowDiagram-PKNHOUZH-CFYAfZBx.js +0 -162
  155. package/dist/web/assets/ganttDiagram-A5KZAMGK-KSn4XAU4.js +0 -292
  156. package/dist/web/assets/gitGraph-HDMCJU4V-OkvBPi6H.js +0 -1
  157. package/dist/web/assets/gitGraphDiagram-K3NZZRJ6-BMgjjVys.js +0 -65
  158. package/dist/web/assets/graphlib-BWe1iK_s.js +0 -1
  159. package/dist/web/assets/index-BcIyrJiY.js +0 -26
  160. package/dist/web/assets/index-Chf0otez.css +0 -2
  161. package/dist/web/assets/info-3K5VOQVL-BDU2_bYD.js +0 -1
  162. package/dist/web/assets/infoDiagram-LFFYTUFH-Diq4Cyc3.js +0 -2
  163. package/dist/web/assets/init-0VJVrkRJ.js +0 -1
  164. package/dist/web/assets/input-BHj0veau.js +0 -45
  165. package/dist/web/assets/isArrayLikeObject-ClzWCpcm.js +0 -1
  166. package/dist/web/assets/isEmpty-BfLnxq-B.js +0 -1
  167. package/dist/web/assets/ishikawaDiagram-PHBUUO56-CiVEvp8o.js +0 -70
  168. package/dist/web/assets/journeyDiagram-4ABVD52K-CG_v5Aho.js +0 -139
  169. package/dist/web/assets/jsx-runtime-BRW_vwa9.js +0 -1
  170. package/dist/web/assets/kanban-definition-K7BYSVSG-miB0-_Zq.js +0 -89
  171. package/dist/web/assets/keybindings-store-BIufrOzJ.js +0 -1
  172. package/dist/web/assets/line-CSuSrJ9J.js +0 -1
  173. package/dist/web/assets/linear-DFN_MPsw.js +0 -1
  174. package/dist/web/assets/markdown-renderer-C5UPA1-7.js +0 -306
  175. package/dist/web/assets/math-CRc16Nj6.js +0 -1
  176. package/dist/web/assets/mermaid-parser.core-CFdP1Z5_.js +0 -4
  177. package/dist/web/assets/mindmap-definition-YRQLILUH-pYPWwASE.js +0 -68
  178. package/dist/web/assets/ordinal-DpFn432U.js +0 -1
  179. package/dist/web/assets/packet-RMMSAZCW-BwpIpYB3.js +0 -1
  180. package/dist/web/assets/path-INs8XTPH.js +0 -1
  181. package/dist/web/assets/pie-UPGHQEXC-BPgAfmes.js +0 -1
  182. package/dist/web/assets/pieDiagram-SKSYHLDU-Dovdlvhu.js +0 -30
  183. package/dist/web/assets/plus-DQGIb4mQ.js +0 -1
  184. package/dist/web/assets/port-forwarding-tab-DmifthYH.js +0 -1
  185. package/dist/web/assets/postgres-viewer-Bo7jEQfQ.js +0 -13
  186. package/dist/web/assets/preload-helper-mr3rCizq.js +0 -1
  187. package/dist/web/assets/quadrantDiagram-337W2JSQ-TXe6cU_F.js +0 -7
  188. package/dist/web/assets/radar-KQ55EAFF-TqxBkWx-.js +0 -1
  189. package/dist/web/assets/react-0tkk-ztn.js +0 -1
  190. package/dist/web/assets/react-dom-Bpkvzu3U.js +0 -1
  191. package/dist/web/assets/react-nm2Ru1Pt.js +0 -1
  192. package/dist/web/assets/refresh-cw-Clk8fdUD.js +0 -1
  193. package/dist/web/assets/requirementDiagram-Z7DCOOCP-CuiiuGS9.js +0 -73
  194. package/dist/web/assets/rough.esm-eLccZ4OJ.js +0 -1
  195. package/dist/web/assets/sankeyDiagram-WA2Y5GQK-BbRmhv0t.js +0 -10
  196. package/dist/web/assets/scroll-area-BpXCNme3.js +0 -1
  197. package/dist/web/assets/sequenceDiagram-2WXFIKYE-B2D8IQDb.js +0 -145
  198. package/dist/web/assets/settings-tab-D9GicyA9.js +0 -1
  199. package/dist/web/assets/sqlite-viewer-pacZlViY.js +0 -1
  200. package/dist/web/assets/square-vBdqj0bF.js +0 -1
  201. package/dist/web/assets/src-CqyWLlNZ.js +0 -1
  202. package/dist/web/assets/stateDiagram-RAJIS63D-ylr4HxPu.js +0 -1
  203. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D6zvxf3M.js +0 -1
  204. package/dist/web/assets/table-Bi27fEaN.js +0 -1
  205. package/dist/web/assets/terminal-tab-DpzE3yoD.js +0 -36
  206. package/dist/web/assets/text-wrap-D_OmSzhp.js +0 -1
  207. package/dist/web/assets/timeline-definition-YZTLITO2-pMv1grvM.js +0 -61
  208. package/dist/web/assets/trash-2-CNuB-htI.js +0 -1
  209. package/dist/web/assets/treemap-KZPCXAKY-Kck06FKU.js +0 -1
  210. package/dist/web/assets/vennDiagram-LZ73GAT5-C-rkIUbo.js +0 -34
  211. package/dist/web/assets/x-Dw3TjeY_.js +0 -1
  212. package/dist/web/assets/xychartDiagram-JWTSCODW-CtpjAakO.js +0 -7
  213. /package/dist/web/assets/{csv-parser-i7fjqP2H.js → csv-parser--2WJNgS7.js} +0 -0
  214. /package/dist/web/assets/{katex-DR0kdMDv.js → katex-CKoArbIw.js} +0 -0
  215. /package/dist/web/assets/{chunk-CFjPhJqf.js → rolldown-runtime-FhOqtrmT.js} +0 -0
  216. /package/dist/web/assets/{sql-completion-provider-B8uUWWej.js → sql-completion-provider-C3cq9j99.js} +0 -0
  217. /package/dist/web/assets/{utils-DX8jb5qv.js → utils-ChWX7pZv.js} +0 -0
  218. /package/dist/web/assets/{terminal-tab-BrP-ENHg.css → vendor-xterm-BrP-ENHg.css} +0 -0
@@ -1,8 +1,8 @@
1
- import { useEffect, useState, useCallback, useRef, useMemo } from "react";
1
+ import { useEffect, useState, useCallback, useRef, useMemo, memo, lazy, Suspense } from "react";
2
2
  import Editor, { type OnMount } from "@monaco-editor/react";
3
3
  import type * as MonacoType from "monaco-editor";
4
- import { MarkdownRenderer } from "@/components/shared/markdown-renderer";
5
4
  import { api, projectUrl, getAuthToken } from "@/lib/api-client";
5
+ import { useShallow } from "zustand/react/shallow";
6
6
  import { useTabStore } from "@/stores/tab-store";
7
7
  import { usePanelStore } from "@/stores/panel-store";
8
8
  import { useSettingsStore } from "@/stores/settings-store";
@@ -12,10 +12,12 @@ import { Loader2, FileWarning, ExternalLink, Play, Database } from "lucide-react
12
12
  import { EditorBreadcrumb } from "./editor-breadcrumb";
13
13
  import { EditorToolbar } from "./editor-toolbar";
14
14
  import { SaveAsDialog } from "./save-as-dialog";
15
- import { lazy, Suspense } from "react";
16
15
  import { createSqlCompletionProvider, clearCompletionCache, type SchemaInfo } from "../database/sql-completion-provider";
17
16
  import { useConnections, type Connection } from "../database/use-connections";
18
17
 
18
+ const MarkdownRenderer = lazy(() =>
19
+ import("@/components/shared/markdown-renderer").then((m) => ({ default: m.MarkdownRenderer }))
20
+ );
19
21
  const CsvPreview = lazy(() => import("./csv-preview").then((m) => ({ default: m.CsvPreview })));
20
22
 
21
23
  /** Image extensions renderable inline */
@@ -47,7 +49,7 @@ interface CodeEditorProps {
47
49
  tabId?: string;
48
50
  }
49
51
 
50
- export function CodeEditor({ metadata, tabId }: CodeEditorProps) {
52
+ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEditorProps) {
51
53
  const filePath = metadata?.filePath as string | undefined;
52
54
  const projectName = metadata?.projectName as string | undefined;
53
55
  // Inline content mode: read-only Monaco with pre-loaded content (e.g. cell viewer)
@@ -61,8 +63,8 @@ export function CodeEditor({ metadata, tabId }: CodeEditorProps) {
61
63
  const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
62
64
  const latestContentRef = useRef<string>("");
63
65
  const editorRef = useRef<MonacoType.editor.IStandaloneCodeEditor | null>(null);
64
- const { tabs, updateTab } = useTabStore();
65
- const { wordWrap, toggleWordWrap } = useSettingsStore();
66
+ const { tabs, updateTab } = useTabStore(useShallow((s) => ({ tabs: s.tabs, updateTab: s.updateTab })));
67
+ const { wordWrap, toggleWordWrap } = useSettingsStore(useShallow((s) => ({ wordWrap: s.wordWrap, toggleWordWrap: s.toggleWordWrap })));
66
68
  const monacoTheme = useMonacoTheme();
67
69
 
68
70
  const isUntitled = metadata?.isUntitled === true;
@@ -553,10 +555,14 @@ export function CodeEditor({ metadata, tabId }: CodeEditorProps) {
553
555
  )}
554
556
  </div>
555
557
  );
556
- }
558
+ });
557
559
 
558
560
  function MarkdownPreview({ content }: { content: string }) {
559
- return <MarkdownRenderer content={content} className="flex-1 overflow-auto p-4" />;
561
+ return (
562
+ <Suspense fallback={<div className="animate-pulse h-4 bg-muted rounded m-4" />}>
563
+ <MarkdownRenderer content={content} className="flex-1 overflow-auto p-4" />
564
+ </Suspense>
565
+ );
560
566
  }
561
567
 
562
568
  function ImagePreview({ filePath, projectName }: { filePath: string; projectName: string }) {
@@ -2,6 +2,7 @@ import { useEffect, useState, useRef, useCallback } from "react";
2
2
  import Editor, { type OnMount } from "@monaco-editor/react";
3
3
  import type * as MonacoType from "monaco-editor";
4
4
  import { api, projectUrl } from "@/lib/api-client";
5
+ import { useShallow } from "zustand/react/shallow";
5
6
  import { useSettingsStore } from "@/stores/settings-store";
6
7
  import { useMonacoTheme } from "@/lib/use-monaco-theme";
7
8
  import { Loader2 } from "lucide-react";
@@ -100,7 +101,7 @@ export function ConflictEditor({ metadata }: ConflictEditorProps) {
100
101
  const widgetsRef = useRef<MonacoType.editor.IContentWidget[]>([]);
101
102
  const decorationsRef = useRef<MonacoType.editor.IEditorDecorationsCollection | null>(null);
102
103
 
103
- const { wordWrap } = useSettingsStore();
104
+ const { wordWrap } = useSettingsStore(useShallow((s) => ({ wordWrap: s.wordWrap })));
104
105
  const monacoTheme = useMonacoTheme();
105
106
 
106
107
  const containerRef = useRef<HTMLDivElement>(null);
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useState, useMemo, useRef } from "react";
2
2
  import { DiffEditor } from "@monaco-editor/react";
3
3
  import { api, projectUrl } from "@/lib/api-client";
4
+ import { useShallow } from "zustand/react/shallow";
4
5
  import { useSettingsStore } from "@/stores/settings-store";
5
6
  import { useMonacoTheme } from "@/lib/use-monaco-theme";
6
7
  import { Loader2, FileCode, PanelLeftOpen, PanelRightOpen, Columns2, WrapText } from "lucide-react";
@@ -40,7 +41,7 @@ export function DiffViewer({ metadata }: DiffViewerProps) {
40
41
  const [loading, setLoading] = useState(!isInline);
41
42
  const [error, setError] = useState<string | null>(null);
42
43
  const [expandMode, setExpandMode] = useState<"both" | "left" | "right">("both");
43
- const { wordWrap, toggleWordWrap } = useSettingsStore();
44
+ const { wordWrap, toggleWordWrap } = useSettingsStore(useShallow((s) => ({ wordWrap: s.wordWrap, toggleWordWrap: s.toggleWordWrap })));
44
45
  const monacoTheme = useMonacoTheme();
45
46
 
46
47
  // Measure container height — Monaco needs explicit pixel height on mobile
@@ -10,6 +10,7 @@ import {
10
10
  DropdownMenuSubContent,
11
11
  } from "@/components/ui/dropdown-menu";
12
12
  import { useFileStore, type FileNode } from "@/stores/file-store";
13
+ import { useShallow } from "zustand/react/shallow";
13
14
  import { useTabStore } from "@/stores/tab-store";
14
15
  import { basename } from "@/lib/utils";
15
16
 
@@ -83,7 +84,7 @@ interface EditorBreadcrumbProps {
83
84
 
84
85
  export function EditorBreadcrumb({ filePath, projectName, tabId, className }: EditorBreadcrumbProps) {
85
86
  const tree = useFileStore((s) => s.tree);
86
- const { updateTab, openTab } = useTabStore();
87
+ const { updateTab, openTab } = useTabStore(useShallow((s) => ({ updateTab: s.updateTab, openTab: s.openTab })));
87
88
  const scrollRef = useRef<HTMLDivElement>(null);
88
89
 
89
90
  const segments = useMemo(
@@ -1,4 +1,4 @@
1
- import { useEffect, useCallback, useState } from "react";
1
+ import { useEffect, useCallback, useState, memo } from "react";
2
2
  import {
3
3
  Folder,
4
4
  FolderOpen,
@@ -12,6 +12,7 @@ import {
12
12
  Download,
13
13
  Loader2,
14
14
  } from "lucide-react";
15
+ import { useShallow } from "zustand/react/shallow";
15
16
  import { useFileStore, type FileNode } from "@/stores/file-store";
16
17
  import { useProjectStore } from "@/stores/project-store";
17
18
  import { useTabStore } from "@/stores/tab-store";
@@ -58,8 +59,8 @@ interface TreeNodeProps {
58
59
  onFileOpen?: () => void;
59
60
  }
60
61
 
61
- function TreeNode({ node, depth, projectName, onAction, onFileOpen }: TreeNodeProps) {
62
- const { expandedPaths, toggleExpand, selectedFiles, toggleFileSelect } = useFileStore();
62
+ const TreeNode = memo(function TreeNode({ node, depth, projectName, onAction, onFileOpen }: TreeNodeProps) {
63
+ const { expandedPaths, toggleExpand, selectedFiles, toggleFileSelect } = useFileStore(useShallow((s) => ({ expandedPaths: s.expandedPaths, toggleExpand: s.toggleExpand, selectedFiles: s.selectedFiles, toggleFileSelect: s.toggleFileSelect })));
63
64
  const openTab = useTabStore((s) => s.openTab);
64
65
  const isExpanded = expandedPaths.has(node.path);
65
66
  const isDir = node.type === "directory";
@@ -187,14 +188,14 @@ function TreeNode({ node, depth, projectName, onAction, onFileOpen }: TreeNodePr
187
188
  ))}
188
189
  </div>
189
190
  );
190
- }
191
+ });
191
192
 
192
193
  interface FileTreeProps {
193
194
  onFileOpen?: () => void;
194
195
  }
195
196
 
196
197
  export function FileTree({ onFileOpen }: FileTreeProps = {}) {
197
- const { tree, loading, error, fetchTree, reset, selectedFiles, clearSelection } = useFileStore();
198
+ const { tree, loading, error, fetchTree, reset, selectedFiles, clearSelection } = useFileStore(useShallow((s) => ({ tree: s.tree, loading: s.loading, error: s.error, fetchTree: s.fetchTree, reset: s.reset, selectedFiles: s.selectedFiles, clearSelection: s.clearSelection })));
198
199
  const activeProject = useProjectStore((s) => s.activeProject);
199
200
  const openTab = useTabStore((s) => s.openTab);
200
201
  const [actionState, setActionState] = useState<{
@@ -1,5 +1,6 @@
1
1
  import { useState, useRef, useCallback, useEffect } from "react";
2
2
  import { Search, CaseSensitive, ChevronRight, ChevronDown, FileText, X, Loader2, WholeWord, Regex, ReplaceAll } from "lucide-react";
3
+ import { useShallow } from "zustand/react/shallow";
3
4
  import { useProjectStore } from "@/stores/project-store";
4
5
  import { useTabStore } from "@/stores/tab-store";
5
6
  import { projectUrl, api } from "@/lib/api-client";
@@ -62,7 +63,7 @@ function OptionButton({ active, onClick, title, children }: { active: boolean; o
62
63
  }
63
64
 
64
65
  export function SearchPanel() {
65
- const { activeProject } = useProjectStore();
66
+ const { activeProject } = useProjectStore(useShallow((s) => ({ activeProject: s.activeProject })));
66
67
  const openTab = useTabStore((s) => s.openTab);
67
68
 
68
69
  const [query, setQuery] = useState("");
@@ -15,6 +15,7 @@ import {
15
15
  } from "lucide-react";
16
16
  import { api, projectUrl } from "@/lib/api-client";
17
17
  import { basename } from "@/lib/utils";
18
+ import { useShallow } from "zustand/react/shallow";
18
19
  import { useTabStore } from "@/stores/tab-store";
19
20
  import { useSettingsStore } from "@/stores/settings-store";
20
21
  import { useProjectStore } from "@/stores/project-store";
@@ -117,7 +118,7 @@ export function GitStatusPanel({ metadata, tabId, onNavigate }: GitStatusPanelPr
117
118
  label: string;
118
119
  files: string[];
119
120
  } | null>(null);
120
- const { openTab } = useTabStore();
121
+ const { openTab } = useTabStore(useShallow((s) => ({ openTab: s.openTab })));
121
122
  const viewMode = useSettingsStore((s) => s.gitStatusViewMode);
122
123
  const setViewMode = useSettingsStore((s) => s.setGitStatusViewMode);
123
124
  const activeProjectPath = useProjectStore((s) =>
@@ -1,5 +1,6 @@
1
1
  import { useState, useEffect, useRef } from "react";
2
2
  import { Loader2, FolderOpen } from "lucide-react";
3
+ import { useShallow } from "zustand/react/shallow";
3
4
  import { useProjectStore } from "@/stores/project-store";
4
5
  import { api } from "@/lib/api-client";
5
6
  import { cn } from "@/lib/utils";
@@ -18,7 +19,7 @@ interface AddProjectFormProps {
18
19
  }
19
20
 
20
21
  export function AddProjectForm({ onSuccess, onCancel, footerClassName }: AddProjectFormProps) {
21
- const { addProject } = useProjectStore();
22
+ const { addProject } = useProjectStore(useShallow((s) => ({ addProject: s.addProject })));
22
23
  const [path, setPath] = useState("");
23
24
  const [name, setName] = useState("");
24
25
  const [suggestions, setSuggestions] = useState<SuggestedDir[]>([]);
@@ -2,6 +2,7 @@ import { useState, useCallback, useEffect } from "react";
2
2
  import {
3
3
  X, Bug, FolderOpen, GitBranch, Settings, Database,
4
4
  } from "lucide-react";
5
+ import { useShallow } from "zustand/react/shallow";
5
6
  import { useProjectStore } from "@/stores/project-store";
6
7
  import { useSettingsStore } from "@/stores/settings-store";
7
8
  import { FileTree } from "@/components/explorer/file-tree";
@@ -28,7 +29,7 @@ interface MobileDrawerProps {
28
29
  }
29
30
 
30
31
  export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps) {
31
- const { activeProject } = useProjectStore();
32
+ const { activeProject } = useProjectStore(useShallow((s) => ({ activeProject: s.activeProject })));
32
33
  const version = useSettingsStore((s) => s.version);
33
34
  const [activeTab, setActiveTab] = useState<DrawerTab>(initialTab ?? "explorer");
34
35
 
@@ -5,6 +5,7 @@ import {
5
5
  ChevronRight, Globe, Puzzle, Copy, Download, Pencil, Trash2,
6
6
  } from "lucide-react";
7
7
  import { usePanelStore } from "@/stores/panel-store";
8
+ import { useShallow } from "zustand/react/shallow";
8
9
  import { useProjectStore, resolveOrder } from "@/stores/project-store";
9
10
  import { useFileStore, type FileNode } from "@/stores/file-store";
10
11
  import { findPanelPosition, MAX_ROWS } from "@/stores/panel-utils";
@@ -152,7 +153,7 @@ export function MobileNav({ onMenuPress, onProjectsPress }: MobileNavProps) {
152
153
  }
153
154
 
154
155
  // Active project avatar for the Projects button
155
- const { activeProject, projects, customOrder } = useProjectStore();
156
+ const { activeProject, projects, customOrder } = useProjectStore(useShallow((s) => ({ activeProject: s.activeProject, projects: s.projects, customOrder: s.customOrder })));
156
157
  const ordered = resolveOrder(projects, customOrder ?? null);
157
158
  const allNames = ordered.map((p) => p.name);
158
159
  const activeIdx = ordered.findIndex((p) => p.name === activeProject?.name);
@@ -1,4 +1,4 @@
1
- import { useEffect } from "react";
1
+ import { useEffect, memo } from "react";
2
2
  import { Panel, Group, Separator } from "react-resizable-panels";
3
3
  import { GripVertical, GripHorizontal } from "lucide-react";
4
4
  import { usePanelStore } from "@/stores/panel-store";
@@ -10,7 +10,7 @@ interface PanelLayoutProps {
10
10
  projectName: string;
11
11
  }
12
12
 
13
- export function PanelLayout({ projectName }: PanelLayoutProps) {
13
+ export const PanelLayout = memo(function PanelLayout({ projectName }: PanelLayoutProps) {
14
14
  const isDesktop = useMediaQuery("(min-width: 768px)");
15
15
  const grid = usePanelStore((s) =>
16
16
  s.currentProject === projectName ? s.grid : (s.projectGrids[projectName] ?? [[]]),
@@ -51,7 +51,7 @@ export function PanelLayout({ projectName }: PanelLayoutProps) {
51
51
  ))}
52
52
  </Group>
53
53
  );
54
- }
54
+ });
55
55
 
56
56
  function RowGroup({ row, rowIdx, totalRows, projectName }: { row: string[]; rowIdx: number; totalRows: number; projectName: string }) {
57
57
  const defaultSize = `${Math.round(100 / totalRows)}%`;
@@ -1,8 +1,9 @@
1
- import { useState, useCallback, useMemo, useRef, useEffect } from "react";
1
+ import { useState, useCallback, useMemo, useRef, useEffect, memo } from "react";
2
2
  import { createPortal } from "react-dom";
3
3
  import { Plus, Settings, Pencil, Trash2, Palette, Bug, Cloud, X, Copy } from "lucide-react";
4
4
  import { CloudSharePopover } from "./cloud-share-popover";
5
5
  import { openBugReportPopup } from "@/lib/report-bug";
6
+ import { useShallow } from "zustand/react/shallow";
6
7
  import { useProjectStore, resolveOrder } from "@/stores/project-store";
7
8
  import { useTabStore } from "@/stores/tab-store";
8
9
  import { useSettingsStore } from "@/stores/settings-store";
@@ -29,7 +30,7 @@ import { cn } from "@/lib/utils";
29
30
  // ---------------------------------------------------------------------------
30
31
  // Avatar circle
31
32
  // ---------------------------------------------------------------------------
32
- function ProjectAvatar({ name, color, active, allNames }: {
33
+ const ProjectAvatar = memo(function ProjectAvatar({ name, color, active, allNames }: {
33
34
  name: string; color: string; active: boolean; allNames: string[];
34
35
  }) {
35
36
  const initials = getProjectInitials(name, allNames);
@@ -51,7 +52,7 @@ function ProjectAvatar({ name, color, active, allNames }: {
51
52
  )}
52
53
  </div>
53
54
  );
54
- }
55
+ });
55
56
 
56
57
  // ---------------------------------------------------------------------------
57
58
  // Color picker popover (inline in dialog)
@@ -78,8 +79,8 @@ function ColorPicker({ current, onChange }: { current: string; onChange: (c: str
78
79
  // ---------------------------------------------------------------------------
79
80
  // ProjectBar
80
81
  // ---------------------------------------------------------------------------
81
- export function ProjectBar() {
82
- const { projects, activeProject, setActiveProject, setProjectColor, reorderProjects, renameProject, deleteProject, customOrder } = useProjectStore();
82
+ export const ProjectBar = memo(function ProjectBar() {
83
+ const { projects, activeProject, setActiveProject, setProjectColor, reorderProjects, renameProject, deleteProject, customOrder } = useProjectStore(useShallow((s) => ({ projects: s.projects, activeProject: s.activeProject, setActiveProject: s.setActiveProject, setProjectColor: s.setProjectColor, reorderProjects: s.reorderProjects, renameProject: s.renameProject, deleteProject: s.deleteProject, customOrder: s.customOrder })));
83
84
  const openTab = useTabStore((s) => s.openTab);
84
85
  const version = useSettingsStore((s) => s.version);
85
86
  const handleReportBug = useCallback(() => openBugReportPopup(version), [version]);
@@ -435,4 +436,4 @@ export function ProjectBar() {
435
436
  </aside>
436
437
  </div>
437
438
  );
438
- }
439
+ });
@@ -1,5 +1,6 @@
1
1
  import { useState, useRef, useCallback } from "react";
2
2
  import { X, Check, Plus, Settings, ChevronUp, ChevronDown, Pencil, Trash2, Palette, ArrowLeft } from "lucide-react";
3
+ import { useShallow } from "zustand/react/shallow";
3
4
  import { useProjectStore, resolveOrder } from "@/stores/project-store";
4
5
  import { useTabStore } from "@/stores/tab-store";
5
6
  import { useSettingsStore } from "@/stores/settings-store";
@@ -34,7 +35,7 @@ function ProjectAvatar({ name, color, allNames }: { name: string; color: string;
34
35
  }
35
36
 
36
37
  export function ProjectBottomSheet({ isOpen, onClose }: ProjectBottomSheetProps) {
37
- const { projects, activeProject, setActiveProject, setProjectColor, reorderProjects, renameProject, deleteProject, customOrder } = useProjectStore();
38
+ const { projects, activeProject, setActiveProject, setProjectColor, reorderProjects, renameProject, deleteProject, customOrder } = useProjectStore(useShallow((s) => ({ projects: s.projects, activeProject: s.activeProject, setActiveProject: s.setActiveProject, setProjectColor: s.setProjectColor, reorderProjects: s.reorderProjects, renameProject: s.renameProject, deleteProject: s.deleteProject, customOrder: s.customOrder })));
38
39
 
39
40
  const openTab = useTabStore((s) => s.openTab);
40
41
  const version = useSettingsStore((s) => s.version);
@@ -1,5 +1,6 @@
1
- import { useCallback, useRef, useMemo } from "react";
1
+ import { useCallback, useRef, useMemo, memo } from "react";
2
2
  import { PanelLeftClose, PanelLeftOpen, FolderOpen, GitBranch, Settings, Database, Search, Puzzle } from "lucide-react";
3
+ import { useShallow } from "zustand/react/shallow";
3
4
  import { useProjectStore } from "@/stores/project-store";
4
5
  import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
5
6
  import { useExtensionStore } from "@/stores/extension-store";
@@ -58,8 +59,8 @@ function ResizeHandle({ onResize }: { onResize: (width: number) => void }) {
58
59
  );
59
60
  }
60
61
 
61
- export function Sidebar() {
62
- const { activeProject } = useProjectStore();
62
+ export const Sidebar = memo(function Sidebar() {
63
+ const { activeProject } = useProjectStore(useShallow((s) => ({ activeProject: s.activeProject })));
63
64
  const sidebarCollapsed = useSettingsStore((s) => s.sidebarCollapsed);
64
65
  const sidebarWidth = useSettingsStore((s) => s.sidebarWidth);
65
66
  const toggleSidebar = useSettingsStore((s) => s.toggleSidebar);
@@ -169,4 +170,4 @@ export function Sidebar() {
169
170
  <ResizeHandle onResize={setSidebarWidth} />
170
171
  </aside>
171
172
  );
172
- }
173
+ });
@@ -1,8 +1,9 @@
1
+ import { memo } from "react";
1
2
  import { useExtensionStore, type StatusBarItemUI } from "@/stores/extension-store";
2
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
3
4
 
4
5
  /** Fixed status bar at the bottom of the editor area (hidden on mobile) */
5
- export function StatusBar() {
6
+ export const StatusBar = memo(function StatusBar() {
6
7
  const items = useExtensionStore((s) => s.statusBarItems);
7
8
 
8
9
  const left = items
@@ -27,9 +28,9 @@ export function StatusBar() {
27
28
  </div>
28
29
  </div>
29
30
  );
30
- }
31
+ });
31
32
 
32
- function StatusBarEntry({ item }: { item: StatusBarItemUI }) {
33
+ const StatusBarEntry = memo(function StatusBarEntry({ item }: { item: StatusBarItemUI }) {
33
34
  const content = (
34
35
  <button
35
36
  className={`truncate px-1 rounded-sm transition-colors ${
@@ -61,4 +62,4 @@ function StatusBarEntry({ item }: { item: StatusBarItemUI }) {
61
62
  }
62
63
 
63
64
  return content;
64
- }
65
+ });
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, useCallback, useState } from "react";
1
+ import { useEffect, useRef, useCallback, useState, memo } from "react";
2
2
  import {
3
3
  Plus,
4
4
  Terminal,
@@ -47,7 +47,7 @@ interface TabBarProps {
47
47
  panelId?: string;
48
48
  }
49
49
 
50
- export function TabBar({ panelId }: TabBarProps) {
50
+ export const TabBar = memo(function TabBar({ panelId }: TabBarProps) {
51
51
  const activeProject = useProjectStore((s) => s.activeProject);
52
52
  const tabRefs = useRef<Map<string, HTMLButtonElement>>(new Map());
53
53
  const scrollRef = useRef<HTMLDivElement>(null);
@@ -267,5 +267,5 @@ export function TabBar({ panelId }: TabBarProps) {
267
267
  )}
268
268
  </>
269
269
  );
270
- }
270
+ });
271
271
 
@@ -1,4 +1,5 @@
1
1
  import { Suspense, lazy } from "react";
2
+ import { useShallow } from "zustand/react/shallow";
2
3
  import { useTabStore, type TabType } from "@/stores/tab-store";
3
4
  import { Loader2 } from "lucide-react";
4
5
 
@@ -74,7 +75,7 @@ function LoadingFallback() {
74
75
  }
75
76
 
76
77
  export function TabContent() {
77
- const { tabs, activeTabId } = useTabStore();
78
+ const { tabs, activeTabId } = useTabStore(useShallow((s) => ({ tabs: s.tabs, activeTabId: s.activeTabId })));
78
79
 
79
80
  if (tabs.length === 0) {
80
81
  return (
@@ -1,7 +1,7 @@
1
- import { useState, useCallback, useMemo, useEffect, useRef } from "react";
1
+ import { useState, useCallback, useMemo, useEffect, useRef, lazy, Suspense } from "react";
2
2
  import { Database, Loader2, AlertCircle, Play, ChevronLeft, ChevronRight, Table, RefreshCw } from "lucide-react";
3
3
  import { useReactTable, getCoreRowModel, flexRender, type ColumnDef } from "@tanstack/react-table";
4
- import CodeMirror from "@uiw/react-codemirror";
4
+ const CodeMirror = lazy(() => import("@uiw/react-codemirror"));
5
5
  import { sql, PostgreSQL } from "@codemirror/lang-sql";
6
6
  import { usePostgres, type PgColumnInfo, type PgQueryResult } from "./use-postgres";
7
7
 
@@ -244,9 +244,11 @@ function PgQueryEditor({ onExecute, result, error, loading }: {
244
244
  <div className="flex flex-col h-full overflow-hidden">
245
245
  <div className="flex items-start gap-1 border-b border-border bg-background" onKeyDown={handleKeyDown}>
246
246
  <div className="flex-1 max-h-[120px] overflow-auto">
247
- <CodeMirror value={query} onChange={setQuery} extensions={[sql({ dialect: PostgreSQL })]}
248
- basicSetup={{ lineNumbers: false, foldGutter: false, highlightActiveLine: false }}
249
- className="text-xs [&_.cm-editor]:!outline-none [&_.cm-scroller]:!overflow-auto" />
247
+ <Suspense fallback={<div className="p-2 text-xs text-text-secondary">Loading editor...</div>}>
248
+ <CodeMirror value={query} onChange={setQuery} extensions={[sql({ dialect: PostgreSQL })]}
249
+ basicSetup={{ lineNumbers: false, foldGutter: false, highlightActiveLine: false }}
250
+ className="text-xs [&_.cm-editor]:!outline-none [&_.cm-scroller]:!overflow-auto" />
251
+ </Suspense>
250
252
  </div>
251
253
  <button type="button" onClick={handleExecute} disabled={loading} title="Execute (Cmd+Enter)"
252
254
  className="shrink-0 m-1 p-1.5 rounded bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors">
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button";
7
7
  import { Input } from "@/components/ui/input";
8
8
  import { ScrollArea } from "@/components/ui/scroll-area";
9
9
  import { Separator } from "@/components/ui/separator";
10
+ import { useShallow } from "zustand/react/shallow";
10
11
  import { useSettingsStore, type Theme } from "@/stores/settings-store";
11
12
  import { cn } from "@/lib/utils";
12
13
  import { AISettingsSection } from "./ai-settings-section";
@@ -41,7 +42,7 @@ const CATEGORIES: { value: SettingsCategory; label: string; subtitle: string; ic
41
42
  ];
42
43
 
43
44
  export function SettingsTab() {
44
- const { theme, setTheme, deviceName, setDeviceName, version } = useSettingsStore();
45
+ const { theme, setTheme, deviceName, setDeviceName, version } = useSettingsStore(useShallow((s) => ({ theme: s.theme, setTheme: s.setTheme, deviceName: s.deviceName, setDeviceName: s.setDeviceName, version: s.version })));
45
46
  const { permission, isSubscribed, loading, error: pushError, subscribe, unsubscribe } = usePushNotification();
46
47
  const [activeCategory, setActiveCategory] = useState<SettingsCategory | null>(null);
47
48
  const [nameInput, setNameInput] = useState(deviceName ?? "");
@@ -1,15 +1,18 @@
1
1
  import { useState, useEffect, useRef, type ReactNode } from "react";
2
- import mermaid from "mermaid";
3
2
  import { useMdContext, FILE_EXT_RE, GLOB_CHARS_RE } from "./markdown-context";
4
3
  import { useTabStore } from "@/stores/tab-store";
5
4
 
6
5
  const MERMAID_KEYWORDS = /^(sequenceDiagram|flowchart|graph\s|classDiagram|stateDiagram|erDiagram|journey|gantt|pie|quadrantChart|requirementDiagram|gitGraph|mindmap|timeline|sankey|xychart|block-beta|packet-beta|architecture-beta|kanban)\b/;
7
6
 
8
- let mermaidInitialized = false;
9
- function ensureMermaidInit() {
10
- if (mermaidInitialized) return;
11
- mermaid.initialize({ startOnLoad: false, theme: "default", securityLevel: "loose", fontFamily: "ui-sans-serif, system-ui, sans-serif" });
12
- mermaidInitialized = true;
7
+ let mermaidPromise: Promise<typeof import("mermaid")["default"]> | null = null;
8
+ function getMermaid() {
9
+ if (!mermaidPromise) {
10
+ mermaidPromise = import("mermaid").then((mod) => {
11
+ mod.default.initialize({ startOnLoad: false, theme: "default", securityLevel: "loose", fontFamily: "ui-sans-serif, system-ui, sans-serif" });
12
+ return mod.default;
13
+ });
14
+ }
15
+ return mermaidPromise;
13
16
  }
14
17
 
15
18
  /** Extract plain text from a hast node tree */
@@ -89,9 +92,8 @@ function MermaidDiagram({ source }: { source: string }) {
89
92
  const [svg, setSvg] = useState<string | null>(null);
90
93
 
91
94
  useEffect(() => {
92
- ensureMermaidInit();
93
95
  const id = `mermaid-${Math.random().toString(36).slice(2, 9)}`;
94
- mermaid.render(id, source).then(({ svg }) => setSvg(svg)).catch(() => {});
96
+ getMermaid().then((m) => m.render(id, source)).then(({ svg }) => setSvg(svg)).catch(() => {});
95
97
  }, [source]);
96
98
 
97
99
  if (!svg) return <pre><code>{source}</code></pre>;
@@ -1,4 +1,4 @@
1
- import { useRef, useEffect, useState, useCallback } from "react";
1
+ import { useRef, useEffect, useState, useCallback, memo } from "react";
2
2
  import { useTerminal } from "@/hooks/use-terminal";
3
3
  import { cn } from "@/lib/utils";
4
4
  import { Copy, ClipboardPaste } from "lucide-react";
@@ -18,7 +18,7 @@ const MOBILE_KEYS = [
18
18
  { label: "\u2192", value: "\x1b[C" },
19
19
  ] as const;
20
20
 
21
- export function TerminalTab({ metadata }: TerminalTabProps) {
21
+ export const TerminalTab = memo(function TerminalTab({ metadata }: TerminalTabProps) {
22
22
  const sessionId = (metadata?.sessionId as string) ?? "new";
23
23
  const projectName = metadata?.projectName as string | undefined;
24
24
  const containerRef = useRef<HTMLDivElement>(null);
@@ -153,4 +153,4 @@ export function TerminalTab({ metadata }: TerminalTabProps) {
153
153
  )}
154
154
  </div>
155
155
  );
156
- }
156
+ });
@@ -310,6 +310,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
310
310
  );
311
311
  existing.push(...newMsgs);
312
312
  existing.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
313
+ if (existing.length > 500) existing.splice(0, existing.length - 500);
313
314
  }
314
315
  updateTeamActivity();
315
316
  }).catch(() => {});
@@ -321,7 +322,9 @@ export function useChat(sessionId: string | null, providerId = "claude", project
321
322
  case "team_inbox": {
322
323
  const msgs = (ev as any).messages as any[];
323
324
  if (Array.isArray(msgs)) {
324
- teamActivityRef.current.messages.push(...msgs);
325
+ const existing = teamActivityRef.current.messages;
326
+ existing.push(...msgs);
327
+ if (existing.length > 500) existing.splice(0, existing.length - 500);
325
328
  teamUnreadRef.current += msgs.length;
326
329
  updateTeamActivity();
327
330
  }
package/vite.config.ts CHANGED
@@ -110,6 +110,23 @@ export default defineConfig({
110
110
  build: {
111
111
  outDir: "../../dist/web",
112
112
  emptyOutDir: true,
113
+ rollupOptions: {
114
+ output: {
115
+ manualChunks(id: string) {
116
+ if (id.includes("node_modules/monaco-editor")) return "vendor-monaco";
117
+ if (id.includes("node_modules/mermaid")) return "vendor-mermaid";
118
+ if (id.includes("node_modules/@xterm")) return "vendor-xterm";
119
+ if (
120
+ id.includes("node_modules/react-markdown") ||
121
+ id.includes("node_modules/rehype-katex") ||
122
+ id.includes("node_modules/rehype-highlight") ||
123
+ id.includes("node_modules/remark-gfm") ||
124
+ id.includes("node_modules/remark-math")
125
+ ) return "vendor-markdown";
126
+ if (id.includes("node_modules/@radix-ui")) return "vendor-ui";
127
+ },
128
+ },
129
+ },
113
130
  },
114
131
  server: {
115
132
  host: true,
@@ -1 +0,0 @@
1
- import{A as e,B as t,C as n,E as r,H as i,M as a,U as o,V as s,k as c,p as l,w as u,z as d}from"./isArrayLikeObject-ClzWCpcm.js";import{A as f,C as p,D as m,M as h,N as g,S as _,T as v,f as y,h as b,u as x,w as S}from"./_baseUniq-CyzdZeQH.js";var C=/\s/;function w(e){for(var t=e.length;t--&&C.test(e.charAt(t)););return t}var ee=/^\s+/;function T(e){return e&&e.slice(0,w(e)+1).replace(ee,``)}var E=NaN,D=/^[-+]0x[0-9a-f]+$/i,O=/^0b[01]+$/i,k=/^0o[0-7]+$/i,A=parseInt;function j(e){if(typeof e==`number`)return e;if(g(e))return E;if(t(e)){var n=typeof e.valueOf==`function`?e.valueOf():e;e=t(n)?n+``:n}if(typeof e!=`string`)return e===0?e:+e;e=T(e);var r=O.test(e);return r||k.test(e)?A(e.slice(2),r?2:8):D.test(e)?E:+e}var M=1/0,N=17976931348623157e292;function P(e){return e?(e=j(e),e===M||e===-M?(e<0?-1:1)*N:e===e?e:0):e===0?e:0}function F(e){var t=P(e),n=t%1;return t===t?n?t-n:t:0}function I(e){return e!=null&&e.length?_(e,1):[]}var L=Object.prototype,R=L.hasOwnProperty,z=r(function(t,r){t=Object(t);var i=-1,a=r.length,o=a>2?r[2]:void 0;for(o&&n(r[0],r[1],o)&&(a=1);++i<a;)for(var s=r[i],c=l(s),u=-1,d=c.length;++u<d;){var f=c[u],p=t[f];(p===void 0||e(p,L[f])&&!R.call(t,f))&&(t[f]=s[f])}return t});function B(e){var t=e==null?0:e.length;return t?e[t-1]:void 0}function V(e){return function(t,n,r){var i=Object(t);if(!u(t)){var a=y(n,3);t=m(t),n=function(e){return a(i[e],e,i)}}var o=e(t,n,r);return o>-1?i[a?t[o]:o]:void 0}}var H=Math.max;function U(e,t,n){var r=e==null?0:e.length;if(!r)return-1;var i=n==null?0:F(n);return i<0&&(i=H(r+i,0)),f(e,y(t,3),i)}var W=V(U);function G(e,t){var n=-1,r=u(e)?Array(e.length):[];return x(e,function(e,i,a){r[++n]=t(e,i,a)}),r}function K(e,t){return(s(e)?h:G)(e,y(t,3))}var q=Object.prototype.hasOwnProperty;function J(e,t){return e!=null&&q.call(e,t)}function Y(e,t){return e!=null&&b(e,t,J)}var X=`[object String]`;function Z(e){return typeof e==`string`||!s(e)&&i(e)&&o(e)==X}function Q(e,t){return e<t}function $(e,t,n){for(var r=-1,i=e.length;++r<i;){var a=e[r],o=t(a);if(o!=null&&(s===void 0?o===o&&!g(o):n(o,s)))var s=o,c=a}return c}function te(e){return e&&e.length?$(e,d,Q):void 0}function ne(e,n,r,i){if(!t(e))return e;n=v(n,e);for(var o=-1,s=n.length,l=s-1,u=e;u!=null&&++o<s;){var d=S(n[o]),f=r;if(d===`__proto__`||d===`constructor`||d===`prototype`)return e;if(o!=l){var p=u[d];f=i?i(p,d,u):void 0,f===void 0&&(f=t(p)?p:a(n[o+1])?[]:{})}c(u,d,f),u=u[d]}return e}function re(e,t,n){for(var r=-1,i=t.length,a={};++r<i;){var o=t[r],s=p(e,o);n(s,o)&&ne(a,v(o,e),s)}return a}export{Z as a,G as c,z as d,I as f,Q as i,W as l,P as m,te as n,Y as o,F as p,$ as r,K as s,re as t,B as u};
@@ -1 +0,0 @@
1
- import{A as e,B as t,F as n,H as r,M as i,O as a,T as o,U as s,V as c,W as l,_ as u,a as d,b as f,c as p,d as m,g as h,h as g,i as _,k as v,l as y,n as ee,o as b,p as x,r as te,s as ne,u as re,v as ie,w as S,y as C,z as w}from"./isArrayLikeObject-ClzWCpcm.js";import{i as ae,n as T,r as E}from"./isEmpty-BfLnxq-B.js";var oe=`[object Symbol]`;function D(e){return typeof e==`symbol`||r(e)&&s(e)==oe}function O(e,t){for(var n=-1,r=e==null?0:e.length,i=Array(r);++n<r;)i[n]=t(e[n],n,e);return i}var se=1/0,ce=l?l.prototype:void 0,le=ce?ce.toString:void 0;function ue(e){if(typeof e==`string`)return e;if(c(e))return O(e,ue)+``;if(D(e))return le?le.call(e):``;var t=e+``;return t==`0`&&1/e==-se?`-0`:t}function de(){}function fe(e,t){for(var n=-1,r=e==null?0:e.length;++n<r&&t(e[n],n,e)!==!1;);return e}function pe(e,t,n,r){for(var i=e.length,a=n+(r?1:-1);r?a--:++a<i;)if(t(e[a],a,e))return a;return-1}function me(e){return e!==e}function he(e,t,n){for(var r=n-1,i=e.length;++r<i;)if(e[r]===t)return r;return-1}function ge(e,t,n){return t===t?he(e,t,n):pe(e,me,n)}function _e(e,t){return!!(e!=null&&e.length)&&ge(e,t,0)>-1}function k(e){return S(e)?g(e):ae(e)}var ve=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,ye=/^\w*$/;function A(e,t){if(c(e))return!1;var n=typeof e;return n==`number`||n==`symbol`||n==`boolean`||e==null||D(e)?!0:ye.test(e)||!ve.test(e)||t!=null&&e in Object(t)}var be=500;function xe(e){var t=re(e,function(e){return n.size===be&&n.clear(),e}),n=t.cache;return t}var Se=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Ce=/\\(\\)?/g,we=xe(function(e){var t=[];return e.charCodeAt(0)===46&&t.push(``),e.replace(Se,function(e,n,r,i){t.push(r?i.replace(Ce,`$1`):n||e)}),t});function j(e){return e==null?``:ue(e)}function M(e,t){return c(e)?e:A(e,t)?[e]:we(j(e))}var Te=1/0;function N(e){if(typeof e==`string`||D(e))return e;var t=e+``;return t==`0`&&1/e==-Te?`-0`:t}function P(e,t){t=M(t,e);for(var n=0,r=t.length;e!=null&&n<r;)e=e[N(t[n++])];return n&&n==r?e:void 0}function Ee(e,t,n){var r=e==null?void 0:P(e,t);return r===void 0?n:r}function F(e,t){for(var n=-1,r=t.length,i=e.length;++n<r;)e[i+n]=t[n];return e}var I=l?l.isConcatSpreadable:void 0;function De(e){return c(e)||f(e)||!!(I&&e&&e[I])}function L(e,t,n,r,i){var a=-1,o=e.length;for(n||=De,i||=[];++a<o;){var s=e[a];t>0&&n(s)?t>1?L(s,t-1,n,r,i):F(i,s):r||(i[i.length]=s)}return i}function Oe(e,t,n,r){var i=-1,a=e==null?0:e.length;for(r&&a&&(n=e[++i]);++i<a;)n=t(n,e[i],i,e);return n}function ke(e,t){return e&&a(t,k(t),e)}function Ae(e,t){return e&&a(t,x(t),e)}function R(e,t){for(var n=-1,r=e==null?0:e.length,i=0,a=[];++n<r;){var o=e[n];t(o,n,e)&&(a[i++]=o)}return a}function z(){return[]}var je=Object.prototype.propertyIsEnumerable,B=Object.getOwnPropertySymbols,V=B?function(e){return e==null?[]:(e=Object(e),R(B(e),function(t){return je.call(e,t)}))}:z;function Me(e,t){return a(e,V(e),t)}var Ne=Object.getOwnPropertySymbols?function(e){for(var t=[];e;)F(t,V(e)),e=y(e);return t}:z;function Pe(e,t){return a(e,Ne(e),t)}function Fe(e,t,n){var r=t(e);return c(e)?r:F(r,n(e))}function H(e){return Fe(e,k,V)}function Ie(e){return Fe(e,x,Ne)}var Le=Object.prototype.hasOwnProperty;function Re(e){var t=e.length,n=new e.constructor(t);return t&&typeof e[0]==`string`&&Le.call(e,`index`)&&(n.index=e.index,n.input=e.input),n}function ze(e,t){var n=t?d(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}var Be=/\w*$/;function Ve(e){var t=new e.constructor(e.source,Be.exec(e));return t.lastIndex=e.lastIndex,t}var He=l?l.prototype:void 0,Ue=He?He.valueOf:void 0;function We(e){return Ue?Object(Ue.call(e)):{}}var Ge=`[object Boolean]`,Ke=`[object Date]`,qe=`[object Map]`,Je=`[object Number]`,Ye=`[object RegExp]`,Xe=`[object Set]`,Ze=`[object String]`,Qe=`[object Symbol]`,$e=`[object ArrayBuffer]`,et=`[object DataView]`,tt=`[object Float32Array]`,nt=`[object Float64Array]`,rt=`[object Int8Array]`,it=`[object Int16Array]`,at=`[object Int32Array]`,ot=`[object Uint8Array]`,st=`[object Uint8ClampedArray]`,ct=`[object Uint16Array]`,lt=`[object Uint32Array]`;function ut(e,t,n){var r=e.constructor;switch(t){case $e:return d(e);case Ge:case Ke:return new r(+e);case et:return ze(e,n);case tt:case nt:case rt:case it:case at:case ot:case st:case ct:case lt:return _(e,n);case qe:return new r;case Je:case Ze:return new r(e);case Ye:return Ve(e);case Xe:return new r;case Qe:return We(e)}}var dt=`[object Map]`;function ft(e){return r(e)&&T(e)==dt}var pt=u&&u.isMap,mt=pt?ie(pt):ft,ht=`[object Set]`;function gt(e){return r(e)&&T(e)==ht}var _t=u&&u.isSet,vt=_t?ie(_t):gt,yt=1,bt=2,xt=4,St=`[object Arguments]`,Ct=`[object Array]`,wt=`[object Boolean]`,Tt=`[object Date]`,Et=`[object Error]`,Dt=`[object Function]`,Ot=`[object GeneratorFunction]`,kt=`[object Map]`,At=`[object Number]`,jt=`[object Object]`,Mt=`[object RegExp]`,Nt=`[object Set]`,Pt=`[object String]`,Ft=`[object Symbol]`,It=`[object WeakMap]`,Lt=`[object ArrayBuffer]`,Rt=`[object DataView]`,zt=`[object Float32Array]`,Bt=`[object Float64Array]`,Vt=`[object Int8Array]`,Ht=`[object Int16Array]`,Ut=`[object Int32Array]`,Wt=`[object Uint8Array]`,Gt=`[object Uint8ClampedArray]`,Kt=`[object Uint16Array]`,qt=`[object Uint32Array]`,U={};U[St]=U[Ct]=U[Lt]=U[Rt]=U[wt]=U[Tt]=U[zt]=U[Bt]=U[Vt]=U[Ht]=U[Ut]=U[kt]=U[At]=U[jt]=U[Mt]=U[Nt]=U[Pt]=U[Ft]=U[Wt]=U[Gt]=U[Kt]=U[qt]=!0,U[Et]=U[Dt]=U[It]=!1;function W(e,r,i,a,o,s){var l,u=r&yt,d=r&bt,f=r&xt;if(i&&(l=o?i(e,a,o,s):i(e)),l!==void 0)return l;if(!t(e))return e;var m=c(e);if(m){if(l=Re(e),!u)return n(e,l)}else{var h=T(e),g=h==Dt||h==Ot;if(C(e))return ne(e,u);if(h==jt||h==St||g&&!o){if(l=d||g?{}:te(e),!u)return d?Pe(e,Ae(l,e)):Me(e,ke(l,e))}else{if(!U[h])return o?e:{};l=ut(e,h,u)}}s||=new p;var _=s.get(e);if(_)return _;s.set(e,l),vt(e)?e.forEach(function(t){l.add(W(t,r,i,t,e,s))}):mt(e)&&e.forEach(function(t,n){l.set(n,W(t,r,i,n,e,s))});var y=m?void 0:(f?d?Ie:H:d?x:k)(e);return fe(y||e,function(t,n){y&&(n=t,t=e[n]),v(l,n,W(t,r,i,n,e,s))}),l}var Jt=`__lodash_hash_undefined__`;function Yt(e){return this.__data__.set(e,Jt),this}function Xt(e){return this.__data__.has(e)}function G(e){var t=-1,n=e==null?0:e.length;for(this.__data__=new m;++t<n;)this.add(e[t])}G.prototype.add=G.prototype.push=Yt,G.prototype.has=Xt;function Zt(e,t){for(var n=-1,r=e==null?0:e.length;++n<r;)if(t(e[n],n,e))return!0;return!1}function K(e,t){return e.has(t)}var Qt=1,$t=2;function en(e,t,n,r,i,a){var o=n&Qt,s=e.length,c=t.length;if(s!=c&&!(o&&c>s))return!1;var l=a.get(e),u=a.get(t);if(l&&u)return l==t&&u==e;var d=-1,f=!0,p=n&$t?new G:void 0;for(a.set(e,t),a.set(t,e);++d<s;){var m=e[d],h=t[d];if(r)var g=o?r(h,m,d,t,e,a):r(m,h,d,e,t,a);if(g!==void 0){if(g)continue;f=!1;break}if(p){if(!Zt(t,function(e,t){if(!K(p,t)&&(m===e||i(m,e,n,r,a)))return p.push(t)})){f=!1;break}}else if(!(m===h||i(m,h,n,r,a))){f=!1;break}}return a.delete(e),a.delete(t),f}function tn(e){var t=-1,n=Array(e.size);return e.forEach(function(e,r){n[++t]=[r,e]}),n}function q(e){var t=-1,n=Array(e.size);return e.forEach(function(e){n[++t]=e}),n}var nn=1,rn=2,an=`[object Boolean]`,on=`[object Date]`,sn=`[object Error]`,cn=`[object Map]`,ln=`[object Number]`,un=`[object RegExp]`,dn=`[object Set]`,fn=`[object String]`,pn=`[object Symbol]`,mn=`[object ArrayBuffer]`,hn=`[object DataView]`,gn=l?l.prototype:void 0,J=gn?gn.valueOf:void 0;function _n(t,n,r,i,a,o,s){switch(r){case hn:if(t.byteLength!=n.byteLength||t.byteOffset!=n.byteOffset)return!1;t=t.buffer,n=n.buffer;case mn:return!(t.byteLength!=n.byteLength||!o(new b(t),new b(n)));case an:case on:case ln:return e(+t,+n);case sn:return t.name==n.name&&t.message==n.message;case un:case fn:return t==n+``;case cn:var c=tn;case dn:var l=i&nn;if(c||=q,t.size!=n.size&&!l)return!1;var u=s.get(t);if(u)return u==n;i|=rn,s.set(t,n);var d=en(c(t),c(n),i,a,o,s);return s.delete(t),d;case pn:if(J)return J.call(t)==J.call(n)}return!1}var vn=1,yn=Object.prototype.hasOwnProperty;function bn(e,t,n,r,i,a){var o=n&vn,s=H(e),c=s.length;if(c!=H(t).length&&!o)return!1;for(var l=c;l--;){var u=s[l];if(!(o?u in t:yn.call(t,u)))return!1}var d=a.get(e),f=a.get(t);if(d&&f)return d==t&&f==e;var p=!0;a.set(e,t),a.set(t,e);for(var m=o;++l<c;){u=s[l];var h=e[u],g=t[u];if(r)var _=o?r(g,h,u,t,e,a):r(h,g,u,e,t,a);if(!(_===void 0?h===g||i(h,g,n,r,a):_)){p=!1;break}m||=u==`constructor`}if(p&&!m){var v=e.constructor,y=t.constructor;v!=y&&`constructor`in e&&`constructor`in t&&!(typeof v==`function`&&v instanceof v&&typeof y==`function`&&y instanceof y)&&(p=!1)}return a.delete(e),a.delete(t),p}var xn=1,Sn=`[object Arguments]`,Cn=`[object Array]`,Y=`[object Object]`,wn=Object.prototype.hasOwnProperty;function Tn(e,t,n,r,i,a){var o=c(e),s=c(t),l=o?Cn:T(e),u=s?Cn:T(t);l=l==Sn?Y:l,u=u==Sn?Y:u;var d=l==Y,f=u==Y,m=l==u;if(m&&C(e)){if(!C(t))return!1;o=!0,d=!1}if(m&&!d)return a||=new p,o||h(e)?en(e,t,n,r,i,a):_n(e,t,l,n,r,i,a);if(!(n&xn)){var g=d&&wn.call(e,`__wrapped__`),_=f&&wn.call(t,`__wrapped__`);if(g||_){var v=g?e.value():e,y=_?t.value():t;return a||=new p,i(v,y,n,r,a)}}return m?(a||=new p,bn(e,t,n,r,i,a)):!1}function X(e,t,n,i,a){return e===t?!0:e==null||t==null||!r(e)&&!r(t)?e!==e&&t!==t:Tn(e,t,n,i,X,a)}var En=1,Dn=2;function On(e,t,n,r){var i=n.length,a=i,o=!r;if(e==null)return!a;for(e=Object(e);i--;){var s=n[i];if(o&&s[2]?s[1]!==e[s[0]]:!(s[0]in e))return!1}for(;++i<a;){s=n[i];var c=s[0],l=e[c],u=s[1];if(o&&s[2]){if(l===void 0&&!(c in e))return!1}else{var d=new p;if(r)var f=r(l,u,c,e,t,d);if(!(f===void 0?X(u,l,En|Dn,r,d):f))return!1}}return!0}function kn(e){return e===e&&!t(e)}function An(e){for(var t=k(e),n=t.length;n--;){var r=t[n],i=e[r];t[n]=[r,i,kn(i)]}return t}function Z(e,t){return function(n){return n==null?!1:n[e]===t&&(t!==void 0||e in Object(n))}}function jn(e){var t=An(e);return t.length==1&&t[0][2]?Z(t[0][0],t[0][1]):function(n){return n===e||On(n,e,t)}}function Mn(e,t){return e!=null&&t in Object(e)}function Nn(e,t,n){t=M(t,e);for(var r=-1,a=t.length,s=!1;++r<a;){var l=N(t[r]);if(!(s=e!=null&&n(e,l)))break;e=e[l]}return s||++r!=a?s:(a=e==null?0:e.length,!!a&&o(a)&&i(l,a)&&(c(e)||f(e)))}function Pn(e,t){return e!=null&&Nn(e,t,Mn)}var Fn=1,In=2;function Ln(e,t){return A(e)&&kn(t)?Z(N(e),t):function(n){var r=Ee(n,e);return r===void 0&&r===t?Pn(n,e):X(t,r,Fn|In)}}function Rn(e){return function(t){return t?.[e]}}function zn(e){return function(t){return P(t,e)}}function Bn(e){return A(e)?Rn(N(e)):zn(e)}function Q(e){return typeof e==`function`?e:e==null?w:typeof e==`object`?c(e)?Ln(e[0],e[1]):jn(e):Bn(e)}function Vn(e,t){return e&&ee(e,t,k)}function Hn(e,t){return function(n,r){if(n==null)return n;if(!S(n))return e(n,r);for(var i=n.length,a=t?i:-1,o=Object(n);(t?a--:++a<i)&&r(o[a],a,o)!==!1;);return n}}var $=Hn(Vn);function Un(e,t,n){for(var r=-1,i=e==null?0:e.length;++r<i;)if(n(t,e[r]))return!0;return!1}function Wn(e){return typeof e==`function`?e:w}function Gn(e,t){return(c(e)?fe:$)(e,Wn(t))}function Kn(e,t){var n=[];return $(e,function(e,r,i){t(e,r,i)&&n.push(e)}),n}function qn(e,t){return(c(e)?R:Kn)(e,Q(t,3))}function Jn(e,t){return O(t,function(t){return e[t]})}function Yn(e){return e==null?[]:Jn(e,k(e))}function Xn(e){return e===void 0}function Zn(e,t,n,r,i){return i(e,function(e,i,a){n=r?(r=!1,e):t(n,e,i,a)}),n}function Qn(e,t,n){var r=c(e)?Oe:Zn,i=arguments.length<3;return r(e,Q(t,4),n,i,$)}var $n=E&&1/q(new E([,-0]))[1]==1/0?function(e){return new E(e)}:de,er=200;function tr(e,t,n){var r=-1,i=_e,a=e.length,o=!0,s=[],c=s;if(n)o=!1,i=Un;else if(a>=er){var l=t?null:$n(e);if(l)return q(l);o=!1,i=K,c=new G}else c=t?[]:s;outer:for(;++r<a;){var u=e[r],d=t?t(u):u;if(u=n||u!==0?u:0,o&&d===d){for(var f=c.length;f--;)if(c[f]===d)continue outer;t&&c.push(d),s.push(u)}else i(c,d,n)||(c!==s&&c.push(d),s.push(u))}return s}export{pe as A,P as C,k as D,j as E,O as M,D as N,_e as O,L as S,M as T,Zt as _,qn as a,Ie as b,Wn as c,Vn as d,Q as f,K as g,Nn as h,Yn as i,de as j,ge as k,Un as l,Pn as m,Qn as n,Kn as o,Rn as p,Xn as r,Gn as s,tr as t,$ as u,G as v,N as w,R as x,W as y};