zen-gitsync 2.16.11 → 2.16.13

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 (30) hide show
  1. package/README.md +8 -16
  2. package/package.json +1 -1
  3. package/scripts/release.js +3 -3
  4. package/src/cli/customCommand.exec.test.js +52 -13
  5. package/src/ui/public/assets/{AgentView-d83DuyQq.js → AgentView-DpHVftKB.js} +1 -1
  6. package/src/ui/public/assets/{AppVersionBadge-UNabzjNF.js → AppVersionBadge-DoBF_YRQ.js} +2 -2
  7. package/src/ui/public/assets/{BranchSelector-DUbFSWiQ.js → BranchSelector-BG5-5Rji.js} +1 -1
  8. package/src/ui/public/assets/{CommitForm-HiRHE42z.js → CommitForm-CRvh9bMD.js} +1 -1
  9. package/src/ui/public/assets/EditorView-CvmonArf.css +1 -0
  10. package/src/ui/public/assets/EditorView-D8Rj7g4x.js +0 -0
  11. package/src/ui/public/assets/{FlowExecutionViewer-6mr8M454.js → FlowExecutionViewer-BblOVK2I.js} +1 -1
  12. package/src/ui/public/assets/{FlowOrchestrationWorkspace-Cw2ADY-p.js → FlowOrchestrationWorkspace-DYJtdPCz.js} +1 -1
  13. package/src/ui/public/assets/{LogList-DLg6RUCd.js → LogList-BJDC-tvx.js} +1 -1
  14. package/src/ui/public/assets/{MindmapView-BKIsdNvz.js → MindmapView-DVKkHt-H.js} +1 -1
  15. package/src/ui/public/assets/{MonitorView-BjjHr8a5.js → MonitorView-ZHUyTSjI.js} +1 -1
  16. package/src/ui/public/assets/{ProjectStartupButton-C-qI63k1.js → ProjectStartupButton-CRpmOPMY.js} +1 -1
  17. package/src/ui/public/assets/{RemoteRepoCard-B0q3WipX.js → RemoteRepoCard-oN1X-RTu.js} +1 -1
  18. package/src/ui/public/assets/{SourceMapView-BZgc-Ylv.js → SourceMapView-DWjOj5HG.js} +1 -1
  19. package/src/ui/public/assets/{UserInputNode-s3Dfg2Gm.js → UserInputNode-DUS9U0qM.js} +1 -1
  20. package/src/ui/public/assets/{WorkbenchView-DbF4hH5s.css → WorkbenchView-DFO8IfcU.css} +1 -1
  21. package/src/ui/public/assets/{WorkbenchView-BakrUWDH.js → WorkbenchView-qCRoJV-3.js} +1 -1
  22. package/src/ui/public/assets/index-DLfjXhwQ.js +82 -0
  23. package/src/ui/public/assets/index-Fbjp0DKn.css +1 -0
  24. package/src/ui/public/index.html +2 -2
  25. package/src/ui/server/routes/fs.js +53 -1
  26. package/src/ui/server/routes/workbench/taskRunner.js +27 -10
  27. package/src/ui/public/assets/EditorView-BVod-rjn.css +0 -1
  28. package/src/ui/public/assets/EditorView-BvLP-NL1.js +0 -0
  29. package/src/ui/public/assets/index-Bumd4MSq.css +0 -1
  30. package/src/ui/public/assets/index-Cr5-U-r6.js +0 -82
@@ -10,7 +10,7 @@
10
10
  <link rel="preconnect" href="https://fonts.googleapis.com" />
11
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
12
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
13
- <script type="module" crossorigin src="/assets/index-Cr5-U-r6.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-DLfjXhwQ.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-BM3Ffeng.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/monaco-DPQ3OaiL.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/element-plus-C0loJL0J.js">
@@ -21,7 +21,7 @@
21
21
  <link rel="stylesheet" crossorigin href="/assets/element-plus-CXfbWXaJ.css">
22
22
  <link rel="stylesheet" crossorigin href="/assets/vendor-C2ZpZPB4.css">
23
23
  <link rel="stylesheet" crossorigin href="/assets/vue-flow-CavUTEzp.css">
24
- <link rel="stylesheet" crossorigin href="/assets/index-Bumd4MSq.css">
24
+ <link rel="stylesheet" crossorigin href="/assets/index-Fbjp0DKn.css">
25
25
  </head>
26
26
  <body>
27
27
  <div id="app"></div>
@@ -19,7 +19,7 @@ import fs from 'fs/promises';
19
19
  import path from 'path';
20
20
  import open from 'open';
21
21
  import os from 'os';
22
- import { spawn, exec } from 'child_process';
22
+ import { spawn, exec, execSync } from 'child_process';
23
23
  import { ensureWithinCwd } from '../utils/pathGuard.js';
24
24
  import { asyncRoute, HttpError } from '../utils/asyncRoute.js';
25
25
  import { invalidateCurrentProjectKey, invalidateRawConfigCache } from '../../../config.js';
@@ -796,5 +796,57 @@ export function registerFsRoutes({
796
796
  res.status(500).json({ success: false, error: error.message });
797
797
  }
798
798
  });
799
+
800
+ // ── 编辑器:用 VSCode 打开文件/目录 ─────────────────────────
801
+ // 行为:spawn `code` / `code.cmd` (argv 数组,无 shell 解释)
802
+ // - Windows: VSCode 安装时会把 bin 目录加到 PATH,bin/code.cmd 直接 spawn 即可
803
+ // - macOS / Linux: 直接 spawn `code`(CLI command)
804
+ // 找不到 code 时返回 503 + 明确提示,而不是静默成功
805
+ app.post('/api/editor/open-in-vscode', express.json(), async (req, res) => {
806
+ try {
807
+ const targetPath = req.body?.path;
808
+ if (!targetPath) throw new HttpError(400, '缺少 path 参数');
809
+
810
+ const safe = await safePathInProject(targetPath);
811
+ if (!safe) throw new HttpError(403, '禁止访问工作目录以外的内容');
812
+ const resolved = safe.safePath;
813
+
814
+ try {
815
+ await fs.access(resolved);
816
+ } catch {
817
+ throw new HttpError(404, '目标不存在');
818
+ }
819
+
820
+ const isWin = process.platform === 'win32';
821
+ const candidates = isWin ? ['code.cmd', 'code'] : ['code'];
822
+ let cli = null;
823
+ for (const cmd of candidates) {
824
+ try {
825
+ const probe = isWin ? `where ${cmd}` : `which ${cmd}`;
826
+ execSync(probe, { stdio: ['ignore', 'pipe', 'ignore'] });
827
+ cli = cmd;
828
+ break;
829
+ } catch {
830
+ // 找不到,试下一个候选
831
+ }
832
+ }
833
+ if (!cli) {
834
+ throw new HttpError(503, '未检测到 VSCode CLI (PATH 中找不到 code),请确认已安装 VSCode 并启用 "将 code 添加到 PATH"');
835
+ }
836
+
837
+ // Windows 上 spawn .cmd / .bat 必须 shell: true(Node 18+ 限制),否则 EINVAL
838
+ // 路径已通过 safePathInProject 校验,argv 数组不会被再次 shell 展开
839
+ const spawnOpts = { detached: true, stdio: 'ignore' };
840
+ if (isWin) spawnOpts.shell = true;
841
+ const child = spawn(cli, [resolved], spawnOpts);
842
+ child.on('error', () => { /* 静默:已通过 PATH 探测,理论不会出错 */ });
843
+ child.unref();
844
+
845
+ res.json({ success: true });
846
+ } catch (error) {
847
+ const status = error?.status || 500;
848
+ res.status(status).json({ success: false, error: error.message });
849
+ }
850
+ });
799
851
  }
800
852
 
@@ -69,24 +69,41 @@ export function launchClaudeInNewWindow(cwd, promptText, resumeSessionId) {
69
69
  let child;
70
70
  let spawnedExe = 'claude';
71
71
  if (process.platform === 'win32') {
72
- // 直接 spawn claude.exe(npm 全局 @anthropic-ai/claude-code 里的真实二进制),
73
- // 避开两件事:
74
- // 1. Node 23 Windows 上拒绝 spawn .cmd/.bat(EINVAL)
75
- // 2. shell:true 会把 argv 拼成命令行交给 cmd 解释,prompt 里的 \n 被切成多段
76
- // `where claude` 找到 claude.cmd,再从 cmd 内容推断对应 .exe 路径。
72
+ // 避开两件事:
73
+ // 1. Node 23 在 Windows 上拒绝 spawn .cmd/.bat(EINVAL)
74
+ // 2. shell:true 会把 argv 拼成命令行交给 cmd 解释,prompt 里的 \n 被切成多段
75
+ // `where claude` 找到 claude.cmd,优先按 npm 全局 shim 实际行为走:
76
+ // 直接 spawn(process.execPath, [cliJs, ...])。原代码读 shim 内容推断
77
+ // bin\claude.exe 路径,但当前 claude-code 已经改成走 `node cli.js`,
78
+ // shim 内容正则匹配不上 → 落回 'claude.exe' → spawn ENOENT。
77
79
  let claudeExe = 'claude.exe';
80
+ let spawnExe = null;
81
+ let spawnArgs = args;
78
82
  try {
79
83
  const cmdShim = execFileSync('where', ['claude'], { encoding: 'utf8', windowsHide: true })
80
84
  .split(/\r?\n/).map(s => s.trim()).find(s => /\.cmd$/i.test(s));
81
85
  if (cmdShim) {
82
- const txt = fs.readFileSync(cmdShim, 'utf8');
83
- if (/%dp0%\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude\.exe/i.test(txt)) {
84
- claudeExe = path.join(path.dirname(cmdShim), 'node_modules', '@anthropic-ai', 'claude-code', 'bin', 'claude.exe');
86
+ const prefix = path.dirname(cmdShim);
87
+ const cliJs = path.join(prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'cli.js');
88
+ if (fs.existsSync(cliJs)) {
89
+ // npm 全局安装:shim 实质是 `node <prefix>/node_modules/.../cli.js`
90
+ spawnExe = process.execPath;
91
+ spawnArgs = [cliJs, ...args];
92
+ } else {
93
+ // 老式安装:shim 内容真的指向 bin\claude.exe
94
+ try {
95
+ const txt = fs.readFileSync(cmdShim, 'utf8');
96
+ if (/%~?dp0%\\node_modules\\@anthropic-ai\\claude-code\\bin\\claude\.exe/i.test(txt)) {
97
+ claudeExe = path.join(prefix, 'node_modules', '@anthropic-ai', 'claude-code', 'bin', 'claude.exe');
98
+ }
99
+ } catch { /* fallback */ }
100
+ spawnExe = claudeExe;
85
101
  }
86
102
  }
87
103
  } catch { /* fallback */ }
88
- spawnedExe = claudeExe;
89
- child = spawn(claudeExe, args, {
104
+ if (!spawnExe) spawnExe = claudeExe;
105
+ spawnedExe = spawnExe;
106
+ child = spawn(spawnExe, spawnArgs, {
90
107
  cwd,
91
108
  stdio: ['pipe', 'pipe', 'pipe'],
92
109
  windowsHide: false,
@@ -1 +0,0 @@
1
- .md-preview[data-v-c5fe3d4b]{color:inherit;word-break:break-word;padding:20px 24px;font-size:14px;line-height:1.6}.md-preview[data-v-c5fe3d4b] h1,.md-preview[data-v-c5fe3d4b] h2,.md-preview[data-v-c5fe3d4b] h3,.md-preview[data-v-c5fe3d4b] h4,.md-preview[data-v-c5fe3d4b] h5,.md-preview[data-v-c5fe3d4b] h6{border-bottom:1px solid var(--border-color,#d0d7de);margin-top:24px;margin-bottom:16px;padding-bottom:.3em;font-weight:600}.md-preview[data-v-c5fe3d4b] h1{font-size:1.8em}.md-preview[data-v-c5fe3d4b] h2{font-size:1.4em}.md-preview[data-v-c5fe3d4b] h3{font-size:1.2em}.md-preview[data-v-c5fe3d4b] p{margin:0 0 14px}.md-preview[data-v-c5fe3d4b] a{color:var(--link-color,#0969da);text-decoration:none}.md-preview[data-v-c5fe3d4b] a:hover{text-decoration:underline}.md-preview[data-v-c5fe3d4b] code{background:var(--code-bg,#f6f8fa);border-radius:4px;padding:2px 5px;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:87%}.md-preview[data-v-c5fe3d4b] pre{background:var(--code-bg,#f6f8fa);border-radius:6px;margin:0 0 16px;padding:14px 16px;overflow:auto}.md-preview[data-v-c5fe3d4b] pre code{background:0 0;padding:0;font-size:100%}.md-preview[data-v-c5fe3d4b] blockquote{border-left:3px solid var(--border-color,#d0d7de);color:var(--text-secondary,#656d76);margin:0 0 16px;padding:0 16px}.md-preview[data-v-c5fe3d4b] img{border-radius:4px;max-width:100%}.md-preview[data-v-c5fe3d4b] hr{border:none;border-top:1px solid var(--border-color,#d0d7de);margin:24px 0}.md-preview[data-v-c5fe3d4b] table{border-collapse:collapse;width:100%;margin-bottom:16px}.md-preview[data-v-c5fe3d4b] th,.md-preview[data-v-c5fe3d4b] td{border:1px solid var(--border-color,#d0d7de);padding:6px 13px}.md-preview[data-v-c5fe3d4b] thead tr{background:var(--code-bg,#f6f8fa)}.md-preview[data-v-c5fe3d4b] ul,.md-preview[data-v-c5fe3d4b] ol{margin-bottom:16px;padding-left:2em}.md-preview[data-v-c5fe3d4b] li{margin:4px 0}.md-segment[data-v-c5fe3d4b]{display:block}.md-mindmap[data-v-c5fe3d4b]{border:1px solid var(--border-color,#d0d7de);background:var(--bg-panel,#fff);border-radius:8px;margin:18px 0 28px;overflow:hidden}.md-mindmap-title[data-v-c5fe3d4b]{color:var(--text-secondary,#656d76);background:var(--code-bg,#f6f8fa);letter-spacing:.5px;padding:8px 12px;font-size:12px;font-weight:600}.md-mindmap-canvas[data-v-c5fe3d4b]{width:100%;height:480px;display:block}.mindmap-preview[data-v-3969a8bf]{background:var(--bg-container,#fff);flex-direction:column;width:100%;height:100%;display:flex}.mindmap-preview-header[data-v-3969a8bf]{background:var(--bg-panel,#f6f8fa);align-items:center;gap:12px;padding:8px 14px;font-size:12px;display:flex}.mindmap-preview-title[data-v-3969a8bf]{color:var(--text-primary,#1f2328);letter-spacing:.5px;font-weight:600}.mindmap-preview-hint[data-v-3969a8bf]{color:var(--text-secondary,#656d76);font-size:11px}.mindmap-preview-canvas[data-v-3969a8bf]{flex:1;width:100%;min-height:0}.mindmap-preview-canvas[data-v-3969a8bf] .zm-mindmap,.mindmap-preview-canvas[data-v-3969a8bf]>*{width:100%;height:100%}.editor-view[data-v-fc2ebf13]{background:var(--bg-container);width:100%;height:100%;box-shadow:var(--shadow-sm);border-radius:0;display:flex;overflow:hidden}.editor-sidebar[data-v-fc2ebf13]{background:var(--bg-panel);flex-direction:column;flex-shrink:0;display:flex;overflow:hidden}.sidebar-header[data-v-fc2ebf13]{flex-shrink:0;justify-content:space-between;align-items:center;padding:8px 10px 6px;display:flex}.sidebar-title[data-v-fc2ebf13]{letter-spacing:.08em;text-transform:uppercase;color:var(--text-secondary);-webkit-user-select:none;user-select:none;font-size:11px;font-weight:700}.sidebar-action-btn[data-v-fc2ebf13]{cursor:pointer;color:var(--text-tertiary);border-radius:var(--radius-base);background:0 0;border:none;align-items:center;padding:3px;display:flex}.sidebar-action-btn[data-v-fc2ebf13]:hover{color:var(--text-primary);background:var(--bg-hover)}.sidebar-search[data-v-fc2ebf13]{flex-shrink:0;align-items:center;padding:6px 10px;display:flex;position:relative}.sidebar-search-icon[data-v-fc2ebf13]{color:var(--text-tertiary);pointer-events:none;position:absolute;left:18px}.sidebar-search-input[data-v-fc2ebf13]{min-width:0;height:26px;color:var(--text-primary);background:var(--bg-input,#ffffff0a);border:1px solid var(--border-color);border-radius:var(--radius-base);outline:none;flex:1;padding:0 24px 0 26px;font-size:12px;transition:border-color .12s,background .12s}.sidebar-search-input[data-v-fc2ebf13]::placeholder{color:var(--text-tertiary)}.sidebar-search-input[data-v-fc2ebf13]:hover{border-color:var(--text-tertiary)}.sidebar-search-input[data-v-fc2ebf13]:focus{border-color:var(--accent-color,#3b82f6);background:var(--bg-panel)}.sidebar-search-clear[data-v-fc2ebf13]{cursor:pointer;width:18px;height:18px;color:var(--text-tertiary);background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;padding:0;transition:background .12s,color .12s;display:flex;position:absolute;right:14px}.sidebar-search-clear[data-v-fc2ebf13]:hover{background:var(--bg-hover);color:var(--text-primary)}.tree-name-hit[data-v-fc2ebf13]{color:var(--accent-color,#f59e0b);background:#f59e0b26;border-radius:2px;padding:0 1px}.sidebar-tree[data-v-fc2ebf13]{flex:1;padding:4px 0;overflow:hidden auto}.tree-node[data-v-fc2ebf13]{cursor:pointer;-webkit-user-select:none;user-select:none;height:24px;color:var(--text-primary);white-space:nowrap;border-radius:4px;align-items:center;gap:4px;padding-right:8px;font-size:13px;transition:background .1s;display:flex;overflow:hidden}.tree-node[data-v-fc2ebf13]:hover{background:var(--bg-hover)}.tree-node--active[data-v-fc2ebf13]{color:var(--color-primary);background:#3b82f61f}.tree-node--selected[data-v-fc2ebf13]{outline-offset:-1px;background:#63b3ed26;outline:1px solid #63b3ed59}.tree-arrow[data-v-fc2ebf13]{color:var(--text-tertiary);flex-shrink:0;align-items:center;width:12px;transition:transform .15s;display:flex}.tree-arrow.expanded[data-v-fc2ebf13]{transform:rotate(90deg)}.tree-arrow-spacer[data-v-fc2ebf13]{flex-shrink:0;width:12px}.tree-icon[data-v-fc2ebf13]{flex-shrink:0;align-items:center;font-size:14px;line-height:1;display:flex}.tree-icon.mit-icon[data-v-fc2ebf13]{fill:currentColor;vertical-align:middle;width:14px;height:14px;display:inline-block}.tree-icon--dir[data-v-fc2ebf13]{color:#e8b84b}.tree-name[data-v-fc2ebf13]{text-overflow:ellipsis;flex:1;min-width:0;font-size:13px;overflow:hidden}.tree-loading[data-v-fc2ebf13]{border:1.5px solid var(--color-primary);border-top-color:#0000;border-radius:50%;flex-shrink:0;width:10px;height:10px;animation:.8s linear infinite spin-fc2ebf13;display:inline-block}.tree-empty[data-v-fc2ebf13]{color:var(--text-tertiary);text-align:center;padding:24px 12px;font-size:12px}.sidebar-loading[data-v-fc2ebf13]{flex:1;justify-content:center;align-items:center;display:flex}.spin-icon[data-v-fc2ebf13]{border:2px solid var(--color-primary);border-top-color:#0000;border-radius:50%;width:20px;height:20px;animation:.8s linear infinite spin-fc2ebf13;display:inline-block}@keyframes spin-fc2ebf13{to{transform:rotate(360deg)}}.editor-resizer[data-v-fc2ebf13]{cursor:col-resize;z-index:2;background:0 0;flex-shrink:0;width:6px;transition:background .15s;position:relative}.editor-resizer[data-v-fc2ebf13]:after{content:"";background:var(--color-gray-300);border-radius:2px;width:2px;height:32px;transition:background .15s,height .15s;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.editor-resizer[data-v-fc2ebf13]:hover{background:#3b82f60f}.editor-resizer[data-v-fc2ebf13]:hover:after{background:var(--color-primary);height:48px;box-shadow:0 0 8px #3b82f666}.editor-main[data-v-fc2ebf13]{flex-direction:column;flex:1;display:flex;overflow:hidden}.editor-tabs[data-v-fc2ebf13]{background:var(--bg-panel);scrollbar-width:none;flex-shrink:0;display:flex;overflow:auto hidden}.editor-tabs[data-v-fc2ebf13]::-webkit-scrollbar{display:none}.editor-tab[data-v-fc2ebf13]{cursor:pointer;height:34px;color:var(--text-secondary);-webkit-user-select:none;user-select:none;flex-shrink:0;align-items:center;gap:6px;min-width:80px;max-width:200px;padding:0 12px;font-size:12.5px;transition:background .1s,color .1s;display:flex}.editor-tab[data-v-fc2ebf13]:hover{background:var(--bg-hover);color:var(--text-primary)}.editor-tab.active[data-v-fc2ebf13]{background:var(--bg-container);color:var(--text-primary);border-bottom:2px solid var(--color-primary)}.tab-name[data-v-fc2ebf13]{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.tab-dirty-dot[data-v-fc2ebf13]{background:var(--color-warning);border-radius:50%;flex-shrink:0;width:6px;height:6px}.tab-close[data-v-fc2ebf13]{cursor:pointer;color:var(--text-tertiary);opacity:0;background:0 0;border:none;border-radius:3px;flex-shrink:0;align-items:center;padding:2px;transition:opacity .1s,background .1s;display:flex}.editor-tab:hover .tab-close[data-v-fc2ebf13],.editor-tab.active .tab-close[data-v-fc2ebf13]{opacity:1}.tab-close[data-v-fc2ebf13]:hover{background:var(--bg-hover);color:var(--color-danger)}.editor-empty[data-v-fc2ebf13]{color:var(--text-tertiary);-webkit-user-select:none;user-select:none;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:10px;font-size:13px;display:flex}.editor-empty p[data-v-fc2ebf13]{margin:0}.editor-empty-hint[data-v-fc2ebf13]{opacity:.6;font-size:11px}.monaco-container[data-v-fc2ebf13]{flex:1;min-width:0;overflow:hidden}.monaco-container.hidden[data-v-fc2ebf13]{display:none}.image-tab-placeholder[data-v-fc2ebf13]{justify-content:center;align-items:center;gap:var(--spacing-sm);color:var(--text-secondary);background:var(--bg-container);text-align:center;padding:var(--spacing-lg);flex-direction:column;flex:1;display:flex}.image-tab-placeholder-title[data-v-fc2ebf13]{font-size:var(--font-size-md);font-weight:var(--font-weight-medium);color:var(--text-primary);word-break:break-all;margin:0}.image-tab-placeholder-hint[data-v-fc2ebf13]{font-size:var(--font-size-sm);color:var(--text-tertiary);margin:0}.editor-body[data-v-fc2ebf13]{flex:1;min-height:0;display:flex;overflow:hidden}.preview-resizer[data-v-fc2ebf13]{cursor:col-resize;z-index:2;background:0 0;flex-shrink:0;order:99;width:6px;margin-left:auto;transition:background .15s;position:relative}.preview-resizer[data-v-fc2ebf13]:after{content:"";background:var(--color-gray-300);border-radius:2px;width:2px;height:32px;transition:background .15s,height .15s;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.preview-resizer[data-v-fc2ebf13]:hover{background:#3b82f60f}.preview-resizer[data-v-fc2ebf13]:hover:after{background:var(--color-primary);height:48px;box-shadow:0 0 8px #3b82f666}.preview-panel[data-v-fc2ebf13]{background:var(--bg-panel);flex-direction:column;flex:1 1 0;min-width:200px;display:flex;overflow:hidden}.preview-header[data-v-fc2ebf13]{background:var(--bg-panel);flex-shrink:0;align-items:center;gap:6px;height:34px;padding:0 10px;display:flex}.preview-title[data-v-fc2ebf13]{letter-spacing:.08em;text-transform:uppercase;color:var(--text-secondary);-webkit-user-select:none;user-select:none;font-size:11px;font-weight:700}.preview-ext-badge[data-v-fc2ebf13]{color:var(--color-primary);letter-spacing:.04em;background:#3b82f626;border-radius:3px;padding:1px 5px;font-size:10px;font-weight:600}.preview-header-spacer[data-v-fc2ebf13]{flex:1}.preview-close-btn[data-v-fc2ebf13]{cursor:pointer;color:var(--text-tertiary);border-radius:var(--radius-base);background:0 0;border:none;align-items:center;padding:3px;transition:color .1s,background .1s;display:flex}.preview-close-btn[data-v-fc2ebf13]:hover{color:var(--color-danger);background:var(--bg-hover)}.preview-body[data-v-fc2ebf13]{flex-direction:column;flex:1;display:flex;overflow:hidden}.preview-iframe[data-v-fc2ebf13]{background:0 0;border:none;flex:1;width:100%;height:100%}.preview-markdown[data-v-fc2ebf13]{background:var(--bg-container,#fff);width:100%;height:100%;color:var(--text-primary,#1f2328);flex:1;overflow:auto}.preview-mindmap[data-v-fc2ebf13]{background:var(--bg-container,#fff);flex-direction:column;flex:1;width:100%;height:100%;display:flex;overflow:hidden}.mindmap-toggle-btn.disabled[data-v-fc2ebf13]{opacity:.45;cursor:not-allowed}.mindmap-toggle-btn.active[data-v-fc2ebf13]{color:#fff;background:linear-gradient(#6366f1 0%,#4f46e5 100%);border-color:#4f46e5}.preview-image-wrap[data-v-fc2ebf13]{background:var(--bg-container);flex:1;justify-content:center;align-items:center;padding:16px;display:flex;overflow:auto}.preview-image-wrap img[data-v-fc2ebf13]{object-fit:contain;border-radius:4px;max-width:100%;max-height:100%;box-shadow:0 2px 12px #0003}.editor-tabs-spacer[data-v-fc2ebf13]{flex:1}.preview-toggle-btn[data-v-fc2ebf13]{cursor:pointer;height:34px;color:var(--text-secondary);white-space:nowrap;background:0 0;border:none;flex-shrink:0;align-items:center;gap:5px;padding:0 10px;font-size:12px;transition:background .1s,color .1s;display:flex}.preview-toggle-btn[data-v-fc2ebf13]:hover{background:var(--bg-hover);color:var(--text-primary)}.preview-toggle-btn.active[data-v-fc2ebf13]{color:var(--color-primary);background:#3b82f614}.sidebar-actions[data-v-fc2ebf13]{align-items:center;gap:2px;display:flex}.tree-inline-input-row[data-v-fc2ebf13]{cursor:default;background:var(--bg-hover)}.tree-inline-input[data-v-fc2ebf13]{background:var(--bg-container);border:1px solid var(--color-primary);min-width:0;height:20px;color:var(--text-primary);border-radius:3px;outline:none;flex:1;padding:0 5px;font-family:inherit;font-size:12.5px}.ctx-menu[data-v-fc2ebf13]{z-index:9999;background:var(--bg-panel);border:1px solid var(--border-color);-webkit-user-select:none;user-select:none;border-radius:6px;min-width:160px;padding:4px;position:fixed;box-shadow:0 8px 24px #00000040}.ctx-menu-item[data-v-fc2ebf13]{cursor:pointer;width:100%;color:var(--text-primary);text-align:left;background:0 0;border:none;border-radius:4px;align-items:center;gap:8px;padding:6px 10px;font-size:12.5px;transition:background .1s;display:flex}.ctx-menu-item[data-v-fc2ebf13]:hover{background:var(--bg-hover)}.ctx-menu-item--danger[data-v-fc2ebf13]{color:var(--color-danger)}.ctx-menu-item--danger[data-v-fc2ebf13]:hover{background:#ef44441a}.ctx-menu-sep[data-v-fc2ebf13]{background:var(--border-color);height:1px;margin:4px 2px}