@hienlh/ppm 0.13.49 → 0.13.51

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 (133) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/dist/web/assets/ai-settings-section-AuV6Lzz2.js +1 -2
  5. package/dist/web/assets/api-client-DIhJ5qVW.js +1 -2
  6. package/dist/web/assets/api-settings-C3T95dWg.js +1 -2
  7. package/dist/web/assets/arrow-up-Rcw6_KKu.js +1 -2
  8. package/dist/web/assets/{audio-preview-CQ-l5P8I.js → audio-preview-BQWWkcm0.js} +1 -2
  9. package/dist/web/assets/{chat-tab-DbuBr2ax.js → chat-tab-B-QMa-uT.js} +5 -6
  10. package/dist/web/assets/chevron-right-DnHIvvcy.js +1 -2
  11. package/dist/web/assets/code-DGBecc50.js +1 -2
  12. package/dist/web/assets/{code-editor-DEa0t62y.js → code-editor-DChspYxh.js} +3 -4
  13. package/dist/web/assets/{conflict-editor-D5H9urYy.js → conflict-editor-C1dZ8tsU.js} +2 -3
  14. package/dist/web/assets/createLucideIcon-BjHrJDVb.js +1 -2
  15. package/dist/web/assets/csv-parser-Dly5nqE1.js +1 -2
  16. package/dist/web/assets/csv-preview-B3Dyhgho.js +1 -2
  17. package/dist/web/assets/data-grid-overlay-editor-C1UUm7Ob.js +1 -2
  18. package/dist/web/assets/data-grid-types-D2cHE8hx.js +1 -2
  19. package/dist/web/assets/database-DOWH9-Vv.js +1 -2
  20. package/dist/web/assets/{database-viewer-CW60ytCl.js → database-viewer-2KW73oEG.js} +1 -2
  21. package/dist/web/assets/{diff-viewer-BfatMgWw.js → diff-viewer-BMla30lw.js} +2 -3
  22. package/dist/web/assets/dist-BoIkGNC8.js +1 -2
  23. package/dist/web/assets/dist-DVk8T0R5.js +1 -2
  24. package/dist/web/assets/esm-DCbn6xno.js +1 -2
  25. package/dist/web/assets/{extension-webview-DKSDoW_g.js → extension-webview-DpaCcCXq.js} +2 -3
  26. package/dist/web/assets/file-exclamation-point-BwzaQ50n.js +1 -2
  27. package/dist/web/assets/file-store-DOxcU_7s.js +1 -2
  28. package/dist/web/assets/{glide-data-grid-Bx48618B.js → glide-data-grid-D08bJMrD.js} +2 -3
  29. package/dist/web/assets/globe-B4Ilypbs.js +1 -2
  30. package/dist/web/assets/{image-preview-ClY2xl1B.js → image-preview-DVQkHkSo.js} +1 -2
  31. package/dist/web/assets/{index-DkQ6jVSH.js → index-U7GK_3ED.js} +4 -5
  32. package/dist/web/assets/input-_LFQwhzd.js +1 -2
  33. package/dist/web/assets/katex-C10ndCVt.js +1 -2
  34. package/dist/web/assets/keybindings-store-B9gpby19.js +1 -0
  35. package/dist/web/assets/lib-C2D8j3K3.js +1 -2
  36. package/dist/web/assets/{markdown-renderer-BmMmo0F-.js → markdown-renderer-B4_rx1aO.js} +2 -3
  37. package/dist/web/assets/notification-store-7WlicqzJ.js +1 -0
  38. package/dist/web/assets/number-overlay-editor-CyEqxXcg.js +1 -2
  39. package/dist/web/assets/{panel-store-Dy8-7E_g.js → panel-store-C8wwxBpn.js} +1 -2
  40. package/dist/web/assets/{pdf-preview-YylEP_Su.js → pdf-preview-D16LLBdq.js} +1 -2
  41. package/dist/web/assets/{port-forwarding-tab-COdo70kU.js → port-forwarding-tab-CoKoquJZ.js} +1 -2
  42. package/dist/web/assets/{postgres-viewer-3y9VshZZ.js → postgres-viewer-B45DfArf.js} +2 -3
  43. package/dist/web/assets/react-DMIOAtcX.js +1 -2
  44. package/dist/web/assets/refresh-cw-BjrAbUJe.js +1 -2
  45. package/dist/web/assets/scroll-area-BDi_FNzr.js +1 -2
  46. package/dist/web/assets/search-tM8K5zWU.js +1 -2
  47. package/dist/web/assets/settings-store-8FpQDjEA.js +1 -2
  48. package/dist/web/assets/{settings-tab-sYavdJk-.js → settings-tab-Dc8TBxJQ.js} +1 -1
  49. package/dist/web/assets/sparkles-CulWHe4c.js +1 -2
  50. package/dist/web/assets/{sql-query-editor-DlBYx1Ye.js → sql-query-editor-DMk0nmOO.js} +2 -3
  51. package/dist/web/assets/{sqlite-viewer-Bj8oPYho.js → sqlite-viewer-G81XimpL.js} +1 -2
  52. package/dist/web/assets/{tab-store-Dtg1_qL0.js → tab-store-CNas5Ny8.js} +1 -2
  53. package/dist/web/assets/table-BzjWcs87.js +1 -2
  54. package/dist/web/assets/{terminal-tab-B7ECmf95.js → terminal-tab-rslAfxoV.js} +2 -3
  55. package/dist/web/assets/text-wrap-DJz9Bgpa.js +1 -2
  56. package/dist/web/assets/use-blob-url-DB4nNruT.js +1 -2
  57. package/dist/web/assets/use-monaco-theme-DEI-tJAh.js +1 -2
  58. package/dist/web/assets/utils-CQux7CsO.js +1 -2
  59. package/dist/web/assets/vendor-markdown-0Mxgxy0L.js +1 -2
  60. package/dist/web/assets/vendor-mermaid-D2KKkqNs.js +1 -2
  61. package/dist/web/assets/vendor-ui-UXCWAcmi.js +1 -2
  62. package/dist/web/assets/vendor-xterm-D1P36hcr.js +1 -2
  63. package/dist/web/assets/{video-preview-CT78iZBo.js → video-preview-vjw8RpLK.js} +1 -2
  64. package/dist/web/assets/x-BPReZWnP.js +1 -2
  65. package/dist/web/index.html +3 -3
  66. package/dist/web/sw.js +1 -2
  67. package/package.json +1 -1
  68. package/src/web/components/chat/chat-tab.tsx +6 -4
  69. package/src/web/components/layout/tab-pool.tsx +1 -1
  70. package/src/web/hooks/use-chat.ts +7 -6
  71. package/src/web/stores/panel-store.ts +5 -0
  72. package/vite.config.ts +1 -1
  73. package/dist/web/assets/ai-settings-section-AuV6Lzz2.js.map +0 -1
  74. package/dist/web/assets/api-client-DIhJ5qVW.js.map +0 -1
  75. package/dist/web/assets/api-settings-C3T95dWg.js.map +0 -1
  76. package/dist/web/assets/arrow-up-Rcw6_KKu.js.map +0 -1
  77. package/dist/web/assets/audio-preview-CQ-l5P8I.js.map +0 -1
  78. package/dist/web/assets/chat-tab-DbuBr2ax.js.map +0 -1
  79. package/dist/web/assets/chevron-right-DnHIvvcy.js.map +0 -1
  80. package/dist/web/assets/code-DGBecc50.js.map +0 -1
  81. package/dist/web/assets/code-editor-DEa0t62y.js.map +0 -1
  82. package/dist/web/assets/conflict-editor-D5H9urYy.js.map +0 -1
  83. package/dist/web/assets/createLucideIcon-BjHrJDVb.js.map +0 -1
  84. package/dist/web/assets/csv-parser-Dly5nqE1.js.map +0 -1
  85. package/dist/web/assets/csv-preview-B3Dyhgho.js.map +0 -1
  86. package/dist/web/assets/data-grid-overlay-editor-C1UUm7Ob.js.map +0 -1
  87. package/dist/web/assets/data-grid-types-D2cHE8hx.js.map +0 -1
  88. package/dist/web/assets/database-DOWH9-Vv.js.map +0 -1
  89. package/dist/web/assets/database-viewer-CW60ytCl.js.map +0 -1
  90. package/dist/web/assets/diff-viewer-BfatMgWw.js.map +0 -1
  91. package/dist/web/assets/dist-BoIkGNC8.js.map +0 -1
  92. package/dist/web/assets/dist-DVk8T0R5.js.map +0 -1
  93. package/dist/web/assets/esm-DCbn6xno.js.map +0 -1
  94. package/dist/web/assets/extension-webview-DKSDoW_g.js.map +0 -1
  95. package/dist/web/assets/file-exclamation-point-BwzaQ50n.js.map +0 -1
  96. package/dist/web/assets/file-store-DOxcU_7s.js.map +0 -1
  97. package/dist/web/assets/glide-data-grid-Bx48618B.js.map +0 -1
  98. package/dist/web/assets/globe-B4Ilypbs.js.map +0 -1
  99. package/dist/web/assets/image-preview-ClY2xl1B.js.map +0 -1
  100. package/dist/web/assets/index-DkQ6jVSH.js.map +0 -1
  101. package/dist/web/assets/input-_LFQwhzd.js.map +0 -1
  102. package/dist/web/assets/katex-C10ndCVt.js.map +0 -1
  103. package/dist/web/assets/keybindings-store-DrAeg6Gw.js +0 -1
  104. package/dist/web/assets/lib-C2D8j3K3.js.map +0 -1
  105. package/dist/web/assets/markdown-renderer-BmMmo0F-.js.map +0 -1
  106. package/dist/web/assets/notification-store-Bukl8bKo.js +0 -1
  107. package/dist/web/assets/number-overlay-editor-CyEqxXcg.js.map +0 -1
  108. package/dist/web/assets/panel-store-Dy8-7E_g.js.map +0 -1
  109. package/dist/web/assets/pdf-preview-YylEP_Su.js.map +0 -1
  110. package/dist/web/assets/port-forwarding-tab-COdo70kU.js.map +0 -1
  111. package/dist/web/assets/postgres-viewer-3y9VshZZ.js.map +0 -1
  112. package/dist/web/assets/react-DMIOAtcX.js.map +0 -1
  113. package/dist/web/assets/refresh-cw-BjrAbUJe.js.map +0 -1
  114. package/dist/web/assets/scroll-area-BDi_FNzr.js.map +0 -1
  115. package/dist/web/assets/search-tM8K5zWU.js.map +0 -1
  116. package/dist/web/assets/settings-store-8FpQDjEA.js.map +0 -1
  117. package/dist/web/assets/sparkles-CulWHe4c.js.map +0 -1
  118. package/dist/web/assets/sql-query-editor-DlBYx1Ye.js.map +0 -1
  119. package/dist/web/assets/sqlite-viewer-Bj8oPYho.js.map +0 -1
  120. package/dist/web/assets/tab-store-Dtg1_qL0.js.map +0 -1
  121. package/dist/web/assets/table-BzjWcs87.js.map +0 -1
  122. package/dist/web/assets/terminal-tab-B7ECmf95.js.map +0 -1
  123. package/dist/web/assets/text-wrap-DJz9Bgpa.js.map +0 -1
  124. package/dist/web/assets/use-blob-url-DB4nNruT.js.map +0 -1
  125. package/dist/web/assets/use-monaco-theme-DEI-tJAh.js.map +0 -1
  126. package/dist/web/assets/utils-CQux7CsO.js.map +0 -1
  127. package/dist/web/assets/vendor-markdown-0Mxgxy0L.js.map +0 -1
  128. package/dist/web/assets/vendor-mermaid-D2KKkqNs.js.map +0 -1
  129. package/dist/web/assets/vendor-ui-UXCWAcmi.js.map +0 -1
  130. package/dist/web/assets/vendor-xterm-D1P36hcr.js.map +0 -1
  131. package/dist/web/assets/video-preview-CT78iZBo.js.map +0 -1
  132. package/dist/web/assets/x-BPReZWnP.js.map +0 -1
  133. package/dist/web/sw.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"extension-webview-DKSDoW_g.js","names":[],"sources":["../../../src/web/components/extensions/extension-webview.tsx"],"sourcesContent":["import { useRef, useEffect, useState, useCallback } from \"react\";\nimport { useExtensionStore } from \"@/stores/extension-store\";\nimport { getAuthToken } from \"@/lib/api-client\";\nimport { Loader2 } from \"lucide-react\";\n\n/** Inject acquireVsCodeApi() shim so extension webviews can postMessage to parent */\nconst VSCODE_API_SHIM = `<script>\nfunction acquireVsCodeApi(){return{postMessage:function(m){window.parent.postMessage(m,\"*\")},getState:function(){try{return JSON.parse(sessionStorage.getItem(\"vscode-state\")||\"null\")}catch{return null}},setState:function(s){sessionStorage.setItem(\"vscode-state\",JSON.stringify(s));return s}}}\n</script>`;\n\nfunction injectVscodeApiShim(html: string): string {\n if (!html) return html;\n // Insert shim right after <head> tag (or at start if no <head>)\n const headIdx = html.indexOf(\"<head>\");\n if (headIdx !== -1) {\n return html.slice(0, headIdx + 6) + VSCODE_API_SHIM + html.slice(headIdx + 6);\n }\n return VSCODE_API_SHIM + html;\n}\n\ninterface ExtensionWebviewProps {\n metadata?: Record<string, unknown>;\n}\n\n/**\n * iframe-based webview container for extension-contributed webview panels.\n * Matches panel by panelId (direct) or viewType (reload recovery).\n */\nexport function ExtensionWebview({ metadata }: ExtensionWebviewProps) {\n const panelId = metadata?.panelId as string | undefined;\n const viewType = metadata?.viewType as string | undefined;\n // Use the tab's own project name (frozen at creation time) — NOT the global\n // currentProject. Old project's ExtensionWebview must not react to project\n // switches, which would dispatch commands for the wrong project.\n const projectName = (metadata?.projectName as string | undefined) || undefined;\n const [timedOut, setTimedOut] = useState(false);\n // Track whether extensions are activated (contributions received from WS)\n const extensionsReady = useExtensionStore((s) => s.contributions !== null);\n\n // Match panel: prefer panelId (exact), fallback to viewType match (reload recovery)\n const panel = useExtensionStore((s) => {\n if (panelId && s.webviewPanels[panelId]) return s.webviewPanels[panelId];\n if (viewType) {\n // Find panel whose viewType matches (with or without .view suffix)\n const fullViewType = viewType.includes(\".\") ? viewType : `${viewType}.view`;\n return Object.values(s.webviewPanels).find(\n (p) => p.viewType === viewType || p.viewType === fullViewType,\n );\n }\n return undefined;\n });\n\n const resolvedPanelId = panel?.id ?? panelId;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // Inject acquireVsCodeApi shim + write HTML into iframe via srcdoc\n const rawHtml = panel?.html ?? \"\";\n const html = injectVscodeApiShim(rawHtml);\n\n // Track which project was last dispatched to prevent duplicate dispatches\n const prevProjectRef = useRef<string | null>(null);\n\n // On reload: resolve project path and dispatch command once.\n // Wait for extensions to be activated (contributions received) before dispatching.\n useEffect(() => {\n if (panel || !viewType || !extensionsReady) return;\n // Already dispatched for this project — panel is just temporarily missing\n if (projectName && projectName === prevProjectRef.current) return;\n if (projectName) prevProjectRef.current = projectName;\n const command = viewType.includes(\".\") ? viewType : `${viewType}.view`;\n let cancelled = false;\n\n async function dispatch() {\n let args: unknown[] = [];\n if (projectName) {\n try {\n const token = getAuthToken();\n const res = await fetch(\"/api/projects\", token ? { headers: { Authorization: `Bearer ${token}` } } : {});\n const json = await res.json() as { ok: boolean; data?: { name: string; path: string }[] };\n const match = json.data?.find((p) => p.name === projectName);\n if (match) args = [match.path];\n } catch {}\n }\n if (cancelled) return;\n window.dispatchEvent(new CustomEvent(\"ext:command:execute\", {\n detail: { command, args },\n }));\n }\n\n dispatch();\n return () => { cancelled = true; };\n }, [panel, viewType, projectName, extensionsReady]);\n\n // Check activation errors for this extension\n const extensionId = metadata?.extensionId as string | undefined;\n const activationError = useExtensionStore((s) => {\n // Direct match by extensionId (most reliable)\n if (extensionId && s.activationErrors[extensionId]) return s.activationErrors[extensionId];\n // Fallback: check by viewType prefix (e.g. \"ext-git-graph\" for viewType \"git-graph\")\n if (!viewType) return undefined;\n for (const [extId, error] of Object.entries(s.activationErrors)) {\n if (extId === `ext-${viewType}`) return error;\n }\n return undefined;\n });\n\n // Retry handler — re-dispatches the command\n const handleRetry = useCallback(() => {\n setTimedOut(false);\n if (!viewType) return;\n const command = viewType.includes(\".\") ? viewType : `${viewType}.view`;\n (async () => {\n try {\n const token = getAuthToken();\n const res = await fetch(\"/api/projects\", token ? { headers: { Authorization: `Bearer ${token}` } } : {});\n const json = await res.json() as { ok: boolean; data?: { name: string; path: string }[] };\n const match = json.data?.find((p) => p.name === projectName);\n const args = match ? [match.path] : [];\n window.dispatchEvent(new CustomEvent(\"ext:command:execute\", {\n detail: { command, args },\n }));\n } catch {}\n })();\n }, [viewType, projectName]);\n\n // On unmount: notify server to dispose the panel so extension clears activePanel state\n const panelIdForCleanup = useRef<string | null>(null);\n const viewTypeForCleanup = useRef<string | undefined>(viewType);\n useEffect(() => {\n panelIdForCleanup.current = resolvedPanelId ?? null;\n }, [resolvedPanelId]);\n useEffect(() => {\n viewTypeForCleanup.current = viewType;\n }, [viewType]);\n useEffect(() => {\n return () => {\n const id = panelIdForCleanup.current;\n if (id) {\n const vt = viewTypeForCleanup.current;\n useExtensionStore.getState().removeWebviewPanel(id);\n window.dispatchEvent(new CustomEvent(\"ext:webview:close\", { detail: { panelId: id, viewType: vt } }));\n }\n };\n }, []);\n\n // Auto-retry: if panel doesn't appear after extensions are ready,\n // re-dispatch the command every 2s (up to 3 times) before showing error.\n // This handles transient WS instability during initial page load where the\n // first command dispatch may be lost due to connection cycling.\n useEffect(() => {\n if (panel) { setTimedOut(false); return; }\n if (!extensionsReady || !viewType) return;\n let retries = 0;\n const id = setInterval(() => {\n retries++;\n if (retries > 3) {\n clearInterval(id);\n setTimedOut(true);\n return;\n }\n handleRetry();\n }, 2_000);\n return () => clearInterval(id);\n }, [panel, extensionsReady, viewType, handleRetry]);\n\n // Listen for postMessage from iframe → forward to extension via WS bridge\n useEffect(() => {\n if (!resolvedPanelId) return;\n const handler = (event: MessageEvent) => {\n if (iframeRef.current && event.source === iframeRef.current.contentWindow) {\n window.dispatchEvent(new CustomEvent(\"ext:webview:send\", {\n detail: { panelId: resolvedPanelId, message: event.data },\n }));\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }, [resolvedPanelId]);\n\n // Listen for server→webview messages (dispatched by useExtensionWs)\n useEffect(() => {\n if (!resolvedPanelId) return;\n const handler = (e: Event) => {\n const { panelId: targetId, message } = (e as CustomEvent).detail;\n if (targetId === resolvedPanelId) {\n iframeRef.current?.contentWindow?.postMessage(message, \"*\");\n }\n };\n window.addEventListener(\"ext:webview:message\", handler);\n return () => window.removeEventListener(\"ext:webview:message\", handler);\n }, [resolvedPanelId]);\n\n // Loading state — waiting for extension to create the panel AND deliver HTML.\n // We must wait for HTML before mounting the iframe because browsers don't\n // re-execute scripts when React updates the srcDoc attribute from \"\" to content.\n if (!panel || !rawHtml) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full gap-3 text-sm text-text-subtle\">\n {timedOut ? (\n <>\n <span className=\"text-destructive font-medium\">Extension failed to load</span>\n {activationError && (\n <span className=\"text-xs text-muted-foreground max-w-md text-center\">{activationError}</span>\n )}\n <button\n onClick={handleRetry}\n className=\"text-xs text-primary hover:underline\"\n >\n Retry\n </button>\n </>\n ) : (\n <>\n <Loader2 className=\"size-5 animate-spin\" />\n <span>Loading extension...</span>\n </>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"h-full w-full relative\">\n <iframe\n ref={iframeRef}\n key={resolvedPanelId}\n srcDoc={html}\n sandbox=\"allow-scripts\"\n className=\"w-full h-full border-0 bg-white dark:bg-zinc-900\"\n title={panel.title}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-exclamation-point-BwzaQ50n.js","names":[],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/icons/file-exclamation-point.js"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n];\nconst FileExclamationPoint = createLucideIcon(\"file-exclamation-point\", __iconNode);\n\nexport { __iconNode, FileExclamationPoint as default };\n//# sourceMappingURL=file-exclamation-point.js.map\n"],"x_google_ignoreList":[0],"mappings":"mDAoBA,IAAM,EAAuB,EAAiB,yBAX3B,CACjB,CACE,OACA,CACE,EAAG,iHACH,IAAK,SACN,CACF,CACD,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,SAAU,CAAC,CACzC,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,SAAU,CAAC,CAC7C,CACkF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-store-DOxcU_7s.js","names":[],"sources":["../../../src/web/stores/project-store.ts","../../../src/web/stores/file-tree-merge-helpers.ts","../../../src/web/stores/file-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { api } from \"@/lib/api-client\";\n\nexport interface Project {\n name: string;\n path: string;\n color?: string;\n}\n\nexport interface ProjectInfo extends Project {\n branch?: string;\n status?: \"clean\" | \"dirty\";\n}\n\n// ---------------------------------------------------------------------------\n// Recently-used tracking via localStorage\n// ---------------------------------------------------------------------------\nconst RECENT_KEY = \"ppm-recent-projects\";\nconst CUSTOM_ORDER_KEY = \"ppm-custom-order\";\n\nfunction loadRecentOrder(): string[] {\n try {\n const raw = localStorage.getItem(RECENT_KEY);\n return raw ? (JSON.parse(raw) as string[]) : [];\n } catch {\n return [];\n }\n}\n\nfunction saveRecentOrder(order: string[]) {\n try {\n localStorage.setItem(RECENT_KEY, JSON.stringify(order));\n } catch { /* ignore */ }\n}\n\n/** Move project name to front of recent list */\nfunction touchRecent(name: string) {\n const order = loadRecentOrder().filter((n) => n !== name);\n order.unshift(name);\n saveRecentOrder(order);\n}\n\n/** Sort projects by recent usage (most recent first) */\nexport function sortByRecent(projects: ProjectInfo[]): ProjectInfo[] {\n const order = loadRecentOrder();\n const orderMap = new Map(order.map((name, i) => [name, i]));\n return [...projects].sort((a, b) => {\n const ai = orderMap.get(a.name) ?? Infinity;\n const bi = orderMap.get(b.name) ?? Infinity;\n return ai - bi;\n });\n}\n\nfunction loadCustomOrder(): string[] | null {\n try {\n const raw = localStorage.getItem(CUSTOM_ORDER_KEY);\n return raw ? (JSON.parse(raw) as string[]) : null;\n } catch {\n return null;\n }\n}\n\nfunction saveCustomOrder(order: string[]) {\n try {\n localStorage.setItem(CUSTOM_ORDER_KEY, JSON.stringify(order));\n } catch { /* ignore */ }\n}\n\n/** Resolve display order: custom order if set, else preserve server order */\nexport function resolveOrder(projects: ProjectInfo[], customOrder: string[] | null): ProjectInfo[] {\n if (!customOrder) return [...projects];\n const orderMap = new Map(customOrder.map((name, i) => [name, i]));\n return [...projects].sort((a, b) => {\n const ai = orderMap.get(a.name) ?? Infinity;\n const bi = orderMap.get(b.name) ?? Infinity;\n return ai - bi;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\ninterface ProjectStore {\n projects: ProjectInfo[];\n activeProject: ProjectInfo | null;\n customOrder: string[] | null;\n loading: boolean;\n error: string | null;\n fetchProjects: () => Promise<void>;\n setActiveProject: (project: ProjectInfo) => void;\n addProject: (path: string, name?: string) => Promise<ProjectInfo>;\n setProjectColor: (name: string, color: string | null) => Promise<void>;\n moveProject: (name: string, direction: \"up\" | \"down\") => Promise<void>;\n reorderProjects: (newOrder: string[]) => Promise<void>;\n renameProject: (name: string, newName: string) => Promise<void>;\n deleteProject: (name: string) => Promise<void>;\n}\n\nexport const useProjectStore = create<ProjectStore>((set, get) => ({\n projects: [],\n activeProject: null,\n customOrder: loadCustomOrder(),\n loading: false,\n error: null,\n\n fetchProjects: async () => {\n set({ loading: true, error: null });\n try {\n const projects = await api.get<ProjectInfo[]>(\"/api/projects\");\n set({ projects, loading: false });\n } catch (err) {\n set({\n error: err instanceof Error ? err.message : \"Failed to fetch projects\",\n loading: false,\n });\n }\n },\n\n setActiveProject: (project) => {\n set({ activeProject: project });\n },\n\n addProject: async (path, name) => {\n const project = await api.post<ProjectInfo>(\"/api/projects\", { path, name });\n await get().fetchProjects();\n // Auto-select the newly added project\n const added = get().projects.find((p) => p.name === (name ?? project.name) || p.path === path);\n if (added) set({ activeProject: added });\n return project;\n },\n\n setProjectColor: async (name, color) => {\n await api.patch(`/api/projects/${encodeURIComponent(name)}/color`, { color });\n await get().fetchProjects();\n },\n\n moveProject: async (name, direction) => {\n const { projects, customOrder } = get();\n const ordered = resolveOrder(projects, customOrder);\n const idx = ordered.findIndex((p) => p.name === name);\n if (idx === -1) return;\n const newIdx = direction === \"up\" ? idx - 1 : idx + 1;\n if (newIdx < 0 || newIdx >= ordered.length) return;\n const newOrder = ordered.map((p) => p.name);\n [newOrder[idx], newOrder[newIdx]] = [newOrder[newIdx]!, newOrder[idx]!];\n saveCustomOrder(newOrder);\n await api.patch(\"/api/projects/reorder\", { order: newOrder });\n set({ customOrder: newOrder });\n },\n\n reorderProjects: async (newOrder) => {\n saveCustomOrder(newOrder);\n set({ customOrder: newOrder });\n await api.patch(\"/api/projects/reorder\", { order: newOrder }).catch(() => {});\n },\n\n renameProject: async (name, newName) => {\n await api.patch(`/api/projects/${encodeURIComponent(name)}`, { name: newName });\n // Refetch to get updated list\n await get().fetchProjects();\n },\n\n deleteProject: async (name) => {\n await api.del(`/api/projects/${encodeURIComponent(name)}`);\n set((s) => {\n const projects = s.projects.filter((p) => p.name !== name);\n const customOrder = s.customOrder ? s.customOrder.filter((n) => n !== name) : null;\n if (customOrder) saveCustomOrder(customOrder);\n return {\n projects,\n customOrder,\n activeProject: s.activeProject?.name === name\n ? (projects[0] ?? null)\n : s.activeProject,\n };\n });\n },\n}));\n","/**\n * Pure helper functions for immutable lazy-tree merging.\n * Kept separate to stay under the 200-line file size guideline.\n */\nimport type { FileDirEntry } from \"../../types/project\";\nimport type { FileNode } from \"./file-store\";\n\n/** Convert /files/list entries into sparse FileNode children (no grandchildren). */\nexport function entriesToNodes(entries: FileDirEntry[], parentPath: string): FileNode[] {\n return entries.map((e) => ({\n name: e.name,\n path: parentPath ? `${parentPath}/${e.name}` : e.name,\n type: e.type,\n ignored: e.isIgnored,\n // children intentionally undefined — loaded lazily on expand\n }));\n}\n\n/** Immutable deep-merge of newly loaded children into the sparse tree. */\nexport function mergeChildren(tree: FileNode[], folderPath: string, children: FileNode[]): FileNode[] {\n if (!folderPath) {\n // Root level: replace root entries, preserve already-loaded sub-children\n return children.map((newNode) => {\n const existing = tree.find((n) => n.path === newNode.path);\n return existing ? { ...newNode, children: existing.children } : newNode;\n });\n }\n return tree.map((node) => mergeNode(node, folderPath, children));\n}\n\nfunction mergeNode(node: FileNode, targetPath: string, children: FileNode[]): FileNode {\n if (node.path === targetPath) {\n // Merge: preserve already-loaded sub-children keyed by path\n const mergedChildren = children.map((newChild) => {\n const existing = node.children?.find((c) => c.path === newChild.path);\n return existing ? { ...newChild, children: existing.children } : newChild;\n });\n return { ...node, children: mergedChildren };\n }\n if (node.children && targetPath.startsWith(node.path + \"/\")) {\n return { ...node, children: node.children.map((child) => mergeNode(child, targetPath, children)) };\n }\n return node;\n}\n","import { create } from \"zustand\";\nimport { api, projectUrl } from \"@/lib/api-client\";\nimport type { FileEntry, FileDirEntry } from \"../../types/project\";\nimport { entriesToNodes, mergeChildren } from \"./file-tree-merge-helpers\";\n\nexport type { FileEntry };\n\nexport interface FileNode {\n name: string;\n path: string;\n type: \"file\" | \"directory\";\n children?: FileNode[];\n size?: number;\n modified?: string;\n /** True if path is matched by a .gitignore rule */\n ignored?: boolean;\n}\n\n/** State for inline create/rename in the file tree */\nexport interface InlineAction {\n type: \"new-file\" | \"new-folder\" | \"rename\";\n /** Parent directory path (for new-file/new-folder) or parent of the renamed file */\n parentPath: string;\n /** Existing node being renamed (only for type=rename) */\n existingNode?: FileNode;\n}\n\n/** Clipboard state for cut/copy/paste */\nexport interface ClipboardState {\n paths: string[];\n operation: \"cut\" | \"copy\";\n}\n\ninterface FileStore {\n tree: FileNode[];\n fileIndex: FileEntry[];\n loading: boolean;\n error: string | null;\n expandedPaths: Set<string>;\n loadedPaths: Set<string>;\n /** In-flight AbortControllers keyed by folder path */\n inflight: Map<string, AbortController>;\n indexStatus: \"idle\" | \"loading\" | \"ready\" | \"error\";\n selectedFiles: string[];\n inlineAction: InlineAction | null;\n clipboard: ClipboardState | null;\n focusedPath: string | null;\n\n setInlineAction(action: InlineAction | null): void;\n clearInlineAction(): void;\n setClipboard(clipboard: ClipboardState | null): void;\n setFocusedPath(path: string | null): void;\n loadRoot(projectName: string): Promise<void>;\n loadChildren(projectName: string, folderPath: string): Promise<void>;\n loadIndex(projectName: string): Promise<void>;\n invalidateIndex(): void;\n invalidateFolder(projectName: string, folderPath: string): Promise<void>;\n toggleExpand(projectName: string, path: string): void;\n setExpanded(path: string, expanded: boolean): void;\n collapseAll(): void;\n toggleFileSelect(path: string): void;\n setSelectedFiles(paths: string[]): void;\n clearSelection(): void;\n reset(): void;\n /** @deprecated Use loadRoot instead */\n fetchTree(projectName: string): Promise<void>;\n}\n\nexport const useFileStore = create<FileStore>((set, get) => ({\n tree: [],\n fileIndex: [],\n loading: false,\n error: null,\n expandedPaths: new Set<string>(),\n loadedPaths: new Set<string>(),\n inflight: new Map<string, AbortController>(),\n indexStatus: \"idle\",\n selectedFiles: [],\n inlineAction: null,\n clipboard: null,\n focusedPath: null,\n\n setInlineAction: (action) => set({ inlineAction: action }),\n clearInlineAction: () => set({ inlineAction: null }),\n setClipboard: (clipboard) => set({ clipboard }),\n setFocusedPath: (path) => set({ focusedPath: path }),\n\n loadRoot: async (projectName: string) => {\n set({ loading: true, error: null });\n try {\n const data = await api.get<FileDirEntry[]>(\n `${projectUrl(projectName)}/files/list?path=`,\n );\n const rootNodes = entriesToNodes(data, \"\");\n const loadedPaths = new Set(get().loadedPaths);\n loadedPaths.add(\"\"); // root is loaded\n set({ tree: rootNodes, loading: false, loadedPaths });\n } catch (err) {\n set({\n error: err instanceof Error ? err.message : \"Failed to load files\",\n loading: false,\n });\n }\n },\n\n loadChildren: async (projectName: string, folderPath: string) => {\n const state = get();\n\n // Idempotent guard — skip if already loaded\n if (state.loadedPaths.has(folderPath)) return;\n\n // Abort any existing in-flight request for this path\n const existing = state.inflight.get(folderPath);\n if (existing) existing.abort();\n\n const controller = new AbortController();\n const inflight = new Map(state.inflight);\n inflight.set(folderPath, controller);\n set({ inflight });\n\n try {\n const encodedPath = encodeURIComponent(folderPath);\n const data = await api.get<FileDirEntry[]>(\n `${projectUrl(projectName)}/files/list?path=${encodedPath}`,\n { signal: controller.signal },\n );\n\n // Check if aborted between request start and completion (defense in depth)\n if (controller.signal.aborted) return;\n\n const children = entriesToNodes(data, folderPath);\n const currentState = get();\n const newTree = mergeChildren(currentState.tree, folderPath, children);\n const newLoadedPaths = new Set(currentState.loadedPaths);\n newLoadedPaths.add(folderPath);\n const newInflight = new Map(currentState.inflight);\n newInflight.delete(folderPath);\n set({ tree: newTree, loadedPaths: newLoadedPaths, inflight: newInflight });\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") return;\n // Remove from inflight on error\n const newInflight = new Map(get().inflight);\n newInflight.delete(folderPath);\n set({ inflight: newInflight });\n }\n },\n\n loadIndex: async (projectName: string) => {\n set({ indexStatus: \"loading\" });\n try {\n const data = await api.get<FileEntry[]>(\n `${projectUrl(projectName)}/files/index`,\n );\n set({ fileIndex: data, indexStatus: \"ready\" });\n } catch {\n set({ indexStatus: \"error\" });\n }\n },\n\n invalidateIndex: () => {\n set({ indexStatus: \"idle\", fileIndex: [] });\n },\n\n invalidateFolder: async (projectName: string, folderPath: string) => {\n const state = get();\n\n // Only reload if this folder was previously loaded\n if (!state.loadedPaths.has(folderPath)) return;\n\n // Remove from loadedPaths to allow re-fetch\n const newLoadedPaths = new Set(state.loadedPaths);\n newLoadedPaths.delete(folderPath);\n set({ loadedPaths: newLoadedPaths });\n\n // Re-fetch if folder is currently expanded (or root)\n if (!folderPath || state.expandedPaths.has(folderPath)) {\n await get().loadChildren(projectName, folderPath);\n }\n },\n\n toggleExpand: (projectName: string, path: string) => {\n const state = get();\n const expanded = new Set(state.expandedPaths);\n if (expanded.has(path)) {\n expanded.delete(path);\n set({ expandedPaths: expanded });\n } else {\n expanded.add(path);\n set({ expandedPaths: expanded });\n // Lazy load children if not yet loaded\n if (!state.loadedPaths.has(path)) {\n get().loadChildren(projectName, path);\n }\n }\n },\n\n setExpanded: (path: string, expanded: boolean) => {\n const paths = new Set(get().expandedPaths);\n if (expanded) paths.add(path);\n else paths.delete(path);\n set({ expandedPaths: paths });\n },\n\n collapseAll: () => {\n set({ expandedPaths: new Set<string>() });\n },\n\n toggleFileSelect: (path: string) => {\n const current = get().selectedFiles;\n const idx = current.indexOf(path);\n if (idx >= 0) {\n set({ selectedFiles: current.filter((p) => p !== path) });\n } else {\n set({ selectedFiles: [...current, path] });\n }\n },\n\n setSelectedFiles: (paths) => set({ selectedFiles: paths }),\n\n clearSelection: () => set({ selectedFiles: [] }),\n\n reset: () => {\n // Abort all in-flight requests\n for (const ctrl of get().inflight.values()) ctrl.abort();\n set({\n tree: [],\n fileIndex: [],\n loading: false,\n error: null,\n expandedPaths: new Set(),\n loadedPaths: new Set(),\n inflight: new Map(),\n indexStatus: \"idle\",\n selectedFiles: [],\n inlineAction: null,\n clipboard: null,\n focusedPath: null,\n });\n },\n\n /** @deprecated Alias for loadRoot — kept for callers in tab-bar and mobile-nav */\n fetchTree: async (projectName: string) => {\n await get().loadRoot(projectName);\n get().loadIndex(projectName);\n },\n}));\n\n/** Compute flat visible path list from current tree state (for range selection) */\nexport function getVisiblePaths(): string[] {\n const { tree, expandedPaths } = useFileStore.getState();\n const result: string[] = [];\n function walk(nodes: FileNode[]) {\n const sorted = [...nodes].sort((a, b) => {\n if (a.type !== b.type) return a.type === \"directory\" ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n for (const n of sorted) {\n // Skip compacted intermediate dirs (matches compact folder rendering)\n let effective = n;\n if (n.type === \"directory\" && expandedPaths.has(n.path) && n.children) {\n while (\n effective.children &&\n effective.children.length === 1 &&\n effective.children[0]!.type === \"directory\" &&\n expandedPaths.has(effective.children[0]!.path)\n ) {\n effective = effective.children[0]!;\n }\n }\n result.push(effective.path);\n if (effective.type === \"directory\" && expandedPaths.has(effective.path) && effective.children) {\n walk(effective.children);\n }\n }\n }\n walk(tree);\n return result;\n}\n"],"mappings":"4FAkBA,IAAM,EAAmB,mBAmCzB,SAAS,GAAmC,CAC1C,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,EAAiB,CAClD,OAAO,EAAO,KAAK,MAAM,EAAI,CAAgB,UACvC,CACN,OAAO,MAIX,SAAS,EAAgB,EAAiB,CACxC,GAAI,CACF,aAAa,QAAQ,EAAkB,KAAK,UAAU,EAAM,CAAC,MACvD,GAIV,SAAgB,EAAa,EAAyB,EAA6C,CACjG,GAAI,CAAC,EAAa,MAAO,CAAC,GAAG,EAAS,CACtC,IAAM,EAAW,IAAI,IAAI,EAAY,KAAK,EAAM,IAAM,CAAC,EAAM,EAAE,CAAC,CAAC,CACjE,MAAO,CAAC,GAAG,EAAS,CAAC,MAAM,EAAG,KACjB,EAAS,IAAI,EAAE,KAAK,EAAI,MACxB,EAAS,IAAI,EAAE,KAAK,EAAI,KAEnC,CAsBJ,IAAa,EAAkB,GAAsB,EAAK,KAAS,CACjE,SAAU,EAAE,CACZ,cAAe,KACf,YAAa,GAAiB,CAC9B,QAAS,GACT,MAAO,KAEP,cAAe,SAAY,CACzB,EAAI,CAAE,QAAS,GAAM,MAAO,KAAM,CAAC,CACnC,GAAI,CAEF,EAAI,CAAE,SADW,MAAM,EAAI,IAAmB,gBAAgB,CAC9C,QAAS,GAAO,CAAC,OAC1B,EAAK,CACZ,EAAI,CACF,MAAO,aAAe,MAAQ,EAAI,QAAU,2BAC5C,QAAS,GACV,CAAC,GAIN,iBAAmB,GAAY,CAC7B,EAAI,CAAE,cAAe,EAAS,CAAC,EAGjC,WAAY,MAAO,EAAM,IAAS,CAChC,IAAM,EAAU,MAAM,EAAI,KAAkB,gBAAiB,CAAE,OAAM,OAAM,CAAC,CAC5E,MAAM,GAAK,CAAC,eAAe,CAE3B,IAAM,EAAQ,GAAK,CAAC,SAAS,KAAM,GAAM,EAAE,QAAU,GAAQ,EAAQ,OAAS,EAAE,OAAS,EAAK,CAE9F,OADI,GAAO,EAAI,CAAE,cAAe,EAAO,CAAC,CACjC,GAGT,gBAAiB,MAAO,EAAM,IAAU,CACtC,MAAM,EAAI,MAAM,iBAAiB,mBAAmB,EAAK,CAAC,QAAS,CAAE,QAAO,CAAC,CAC7E,MAAM,GAAK,CAAC,eAAe,EAG7B,YAAa,MAAO,EAAM,IAAc,CACtC,GAAM,CAAE,WAAU,eAAgB,GAAK,CACjC,EAAU,EAAa,EAAU,EAAY,CAC7C,EAAM,EAAQ,UAAW,GAAM,EAAE,OAAS,EAAK,CACrD,GAAI,IAAQ,GAAI,OAChB,IAAM,EAAS,IAAc,KAAO,EAAM,EAAI,EAAM,EACpD,GAAI,EAAS,GAAK,GAAU,EAAQ,OAAQ,OAC5C,IAAM,EAAW,EAAQ,IAAK,GAAM,EAAE,KAAK,CAC3C,CAAC,EAAS,GAAM,EAAS,IAAW,CAAC,EAAS,GAAU,EAAS,GAAM,CACvE,EAAgB,EAAS,CACzB,MAAM,EAAI,MAAM,wBAAyB,CAAE,MAAO,EAAU,CAAC,CAC7D,EAAI,CAAE,YAAa,EAAU,CAAC,EAGhC,gBAAiB,KAAO,IAAa,CACnC,EAAgB,EAAS,CACzB,EAAI,CAAE,YAAa,EAAU,CAAC,CAC9B,MAAM,EAAI,MAAM,wBAAyB,CAAE,MAAO,EAAU,CAAC,CAAC,UAAY,GAAG,EAG/E,cAAe,MAAO,EAAM,IAAY,CACtC,MAAM,EAAI,MAAM,iBAAiB,mBAAmB,EAAK,GAAI,CAAE,KAAM,EAAS,CAAC,CAE/E,MAAM,GAAK,CAAC,eAAe,EAG7B,cAAe,KAAO,IAAS,CAC7B,MAAM,EAAI,IAAI,iBAAiB,mBAAmB,EAAK,GAAG,CAC1D,EAAK,GAAM,CACT,IAAM,EAAW,EAAE,SAAS,OAAQ,GAAM,EAAE,OAAS,EAAK,CACpD,EAAc,EAAE,YAAc,EAAE,YAAY,OAAQ,GAAM,IAAM,EAAK,CAAG,KAE9E,OADI,GAAa,EAAgB,EAAY,CACtC,CACL,WACA,cACA,cAAe,EAAE,eAAe,OAAS,EACpC,EAAS,IAAM,KAChB,EAAE,cACP,EACD,EAEL,EAAE,CCzKH,SAAgB,EAAe,EAAyB,EAAgC,CACtF,OAAO,EAAQ,IAAK,IAAO,CACzB,KAAM,EAAE,KACR,KAAM,EAAa,GAAG,EAAW,GAAG,EAAE,OAAS,EAAE,KACjD,KAAM,EAAE,KACR,QAAS,EAAE,UAEZ,EAAE,CAIL,SAAgB,EAAc,EAAkB,EAAoB,EAAkC,CAQpG,OAPK,EAOE,EAAK,IAAK,GAAS,EAAU,EAAM,EAAY,EAAS,CAAC,CALvD,EAAS,IAAK,GAAY,CAC/B,IAAM,EAAW,EAAK,KAAM,GAAM,EAAE,OAAS,EAAQ,KAAK,CAC1D,OAAO,EAAW,CAAE,GAAG,EAAS,SAAU,EAAS,SAAU,CAAG,GAChE,CAKN,SAAS,EAAU,EAAgB,EAAoB,EAAgC,CACrF,GAAI,EAAK,OAAS,EAAY,CAE5B,IAAM,EAAiB,EAAS,IAAK,GAAa,CAChD,IAAM,EAAW,EAAK,UAAU,KAAM,GAAM,EAAE,OAAS,EAAS,KAAK,CACrE,OAAO,EAAW,CAAE,GAAG,EAAU,SAAU,EAAS,SAAU,CAAG,GACjE,CACF,MAAO,CAAE,GAAG,EAAM,SAAU,EAAgB,CAK9C,OAHI,EAAK,UAAY,EAAW,WAAW,EAAK,KAAO,IAAI,CAClD,CAAE,GAAG,EAAM,SAAU,EAAK,SAAS,IAAK,GAAU,EAAU,EAAO,EAAY,EAAS,CAAC,CAAE,CAE7F,EC0BT,IAAa,EAAe,GAAmB,EAAK,KAAS,CAC3D,KAAM,EAAE,CACR,UAAW,EAAE,CACb,QAAS,GACT,MAAO,KACP,cAAe,IAAI,IACnB,YAAa,IAAI,IACjB,SAAU,IAAI,IACd,YAAa,OACb,cAAe,EAAE,CACjB,aAAc,KACd,UAAW,KACX,YAAa,KAEb,gBAAkB,GAAW,EAAI,CAAE,aAAc,EAAQ,CAAC,CAC1D,sBAAyB,EAAI,CAAE,aAAc,KAAM,CAAC,CACpD,aAAe,GAAc,EAAI,CAAE,YAAW,CAAC,CAC/C,eAAiB,GAAS,EAAI,CAAE,YAAa,EAAM,CAAC,CAEpD,SAAU,KAAO,IAAwB,CACvC,EAAI,CAAE,QAAS,GAAM,MAAO,KAAM,CAAC,CACnC,GAAI,CAIF,IAAM,EAAY,EAHL,MAAM,EAAI,IACrB,GAAG,EAAW,EAAY,CAAC,mBAC5B,CACsC,GAAG,CACpC,EAAc,IAAI,IAAI,GAAK,CAAC,YAAY,CAC9C,EAAY,IAAI,GAAG,CACnB,EAAI,CAAE,KAAM,EAAW,QAAS,GAAO,cAAa,CAAC,OAC9C,EAAK,CACZ,EAAI,CACF,MAAO,aAAe,MAAQ,EAAI,QAAU,uBAC5C,QAAS,GACV,CAAC,GAIN,aAAc,MAAO,EAAqB,IAAuB,CAC/D,IAAM,EAAQ,GAAK,CAGnB,GAAI,EAAM,YAAY,IAAI,EAAW,CAAE,OAGvC,IAAM,EAAW,EAAM,SAAS,IAAI,EAAW,CAC3C,GAAU,EAAS,OAAO,CAE9B,IAAM,EAAa,IAAI,gBACjB,EAAW,IAAI,IAAI,EAAM,SAAS,CACxC,EAAS,IAAI,EAAY,EAAW,CACpC,EAAI,CAAE,WAAU,CAAC,CAEjB,GAAI,CACF,IAAM,EAAc,mBAAmB,EAAW,CAC5C,EAAO,MAAM,EAAI,IACrB,GAAG,EAAW,EAAY,CAAC,mBAAmB,IAC9C,CAAE,OAAQ,EAAW,OAAQ,CAC9B,CAGD,GAAI,EAAW,OAAO,QAAS,OAE/B,IAAM,EAAW,EAAe,EAAM,EAAW,CAC3C,EAAe,GAAK,CACpB,EAAU,EAAc,EAAa,KAAM,EAAY,EAAS,CAChE,EAAiB,IAAI,IAAI,EAAa,YAAY,CACxD,EAAe,IAAI,EAAW,CAC9B,IAAM,EAAc,IAAI,IAAI,EAAa,SAAS,CAClD,EAAY,OAAO,EAAW,CAC9B,EAAI,CAAE,KAAM,EAAS,YAAa,EAAgB,SAAU,EAAa,CAAC,OACnE,EAAK,CACZ,GAAI,aAAe,OAAS,EAAI,OAAS,aAAc,OAEvD,IAAM,EAAc,IAAI,IAAI,GAAK,CAAC,SAAS,CAC3C,EAAY,OAAO,EAAW,CAC9B,EAAI,CAAE,SAAU,EAAa,CAAC,GAIlC,UAAW,KAAO,IAAwB,CACxC,EAAI,CAAE,YAAa,UAAW,CAAC,CAC/B,GAAI,CAIF,EAAI,CAAE,UAHO,MAAM,EAAI,IACrB,GAAG,EAAW,EAAY,CAAC,cAC5B,CACsB,YAAa,QAAS,CAAC,MACxC,CACN,EAAI,CAAE,YAAa,QAAS,CAAC,GAIjC,oBAAuB,CACrB,EAAI,CAAE,YAAa,OAAQ,UAAW,EAAE,CAAE,CAAC,EAG7C,iBAAkB,MAAO,EAAqB,IAAuB,CACnE,IAAM,EAAQ,GAAK,CAGnB,GAAI,CAAC,EAAM,YAAY,IAAI,EAAW,CAAE,OAGxC,IAAM,EAAiB,IAAI,IAAI,EAAM,YAAY,CACjD,EAAe,OAAO,EAAW,CACjC,EAAI,CAAE,YAAa,EAAgB,CAAC,EAGhC,CAAC,GAAc,EAAM,cAAc,IAAI,EAAW,GACpD,MAAM,GAAK,CAAC,aAAa,EAAa,EAAW,EAIrD,cAAe,EAAqB,IAAiB,CACnD,IAAM,EAAQ,GAAK,CACb,EAAW,IAAI,IAAI,EAAM,cAAc,CACzC,EAAS,IAAI,EAAK,EACpB,EAAS,OAAO,EAAK,CACrB,EAAI,CAAE,cAAe,EAAU,CAAC,GAEhC,EAAS,IAAI,EAAK,CAClB,EAAI,CAAE,cAAe,EAAU,CAAC,CAE3B,EAAM,YAAY,IAAI,EAAK,EAC9B,GAAK,CAAC,aAAa,EAAa,EAAK,GAK3C,aAAc,EAAc,IAAsB,CAChD,IAAM,EAAQ,IAAI,IAAI,GAAK,CAAC,cAAc,CACtC,EAAU,EAAM,IAAI,EAAK,CACxB,EAAM,OAAO,EAAK,CACvB,EAAI,CAAE,cAAe,EAAO,CAAC,EAG/B,gBAAmB,CACjB,EAAI,CAAE,cAAe,IAAI,IAAe,CAAC,EAG3C,iBAAmB,GAAiB,CAClC,IAAM,EAAU,GAAK,CAAC,cACV,EAAQ,QAAQ,EAAK,EACtB,EACT,EAAI,CAAE,cAAe,EAAQ,OAAQ,GAAM,IAAM,EAAK,CAAE,CAAC,CAEzD,EAAI,CAAE,cAAe,CAAC,GAAG,EAAS,EAAK,CAAE,CAAC,EAI9C,iBAAmB,GAAU,EAAI,CAAE,cAAe,EAAO,CAAC,CAE1D,mBAAsB,EAAI,CAAE,cAAe,EAAE,CAAE,CAAC,CAEhD,UAAa,CAEX,IAAK,IAAM,KAAQ,GAAK,CAAC,SAAS,QAAQ,CAAE,EAAK,OAAO,CACxD,EAAI,CACF,KAAM,EAAE,CACR,UAAW,EAAE,CACb,QAAS,GACT,MAAO,KACP,cAAe,IAAI,IACnB,YAAa,IAAI,IACjB,SAAU,IAAI,IACd,YAAa,OACb,cAAe,EAAE,CACjB,aAAc,KACd,UAAW,KACX,YAAa,KACd,CAAC,EAIJ,UAAW,KAAO,IAAwB,CACxC,MAAM,GAAK,CAAC,SAAS,EAAY,CACjC,GAAK,CAAC,UAAU,EAAY,EAE/B,EAAE,CAGH,SAAgB,GAA4B,CAC1C,GAAM,CAAE,OAAM,iBAAkB,EAAa,UAAU,CACjD,EAAmB,EAAE,CAC3B,SAAS,EAAK,EAAmB,CAC/B,IAAM,EAAS,CAAC,GAAG,EAAM,CAAC,MAAM,EAAG,IAC7B,EAAE,OAAS,EAAE,KACV,EAAE,KAAK,cAAc,EAAE,KAAK,CADL,EAAE,OAAS,YAAc,GAAK,EAE5D,CACF,IAAK,IAAM,KAAK,EAAQ,CAEtB,IAAI,EAAY,EAChB,GAAI,EAAE,OAAS,aAAe,EAAc,IAAI,EAAE,KAAK,EAAI,EAAE,SAC3D,KACE,EAAU,UACV,EAAU,SAAS,SAAW,GAC9B,EAAU,SAAS,GAAI,OAAS,aAChC,EAAc,IAAI,EAAU,SAAS,GAAI,KAAK,EAE9C,EAAY,EAAU,SAAS,GAGnC,EAAO,KAAK,EAAU,KAAK,CACvB,EAAU,OAAS,aAAe,EAAc,IAAI,EAAU,KAAK,EAAI,EAAU,UACnF,EAAK,EAAU,SAAS,EAK9B,OADA,EAAK,EAAK,CACH"}