zen-gitsync 2.17.23 → 2.17.25

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 (80) hide show
  1. package/README.md +10 -4
  2. package/package.json +8 -1
  3. package/scripts/run-tests.cjs +5 -0
  4. package/src/cli/ai/agent.js +20 -0
  5. package/src/cli/ai/termui.js +73 -1
  6. package/src/cli/ai/termui.test.js +51 -0
  7. package/src/cli/ai/tools.js +114 -0
  8. package/src/cli/ai/tools.test.js +65 -1
  9. package/src/cli/ai/turn.js +3 -0
  10. package/src/config.js +34 -3
  11. package/src/memory/library.js +273 -0
  12. package/src/memory/library.test.js +187 -0
  13. package/src/memory/store.js +199 -0
  14. package/src/memory/store.test.js +137 -0
  15. package/src/memory/templates.js +113 -0
  16. package/src/paths.js +18 -0
  17. package/src/ui/public/assets/{AgentEngineSelector-DLJ8He83.js → AgentEngineSelector-BArUIELz.js} +1 -1
  18. package/src/ui/public/assets/{AgentView-DnN-vCMi.css → AgentView-B3LhhRsy.css} +1 -1
  19. package/src/ui/public/assets/{AgentView-CQ18nw02.js → AgentView-LpT8A9Fo.js} +1 -1
  20. package/src/ui/public/assets/{AppVersionBadge-1pyUzRer.js → AppVersionBadge-DNXQm_Si.js} +2 -2
  21. package/src/ui/public/assets/{BranchSelector-DrsrZiWJ.js → BranchSelector-DZPTz5Ql.js} +1 -1
  22. package/src/ui/public/assets/{CommitForm-B5p-7P7m.js → CommitForm-6avyu1Kv.js} +1 -1
  23. package/src/ui/public/assets/{CommonDialog-BEm2cK1X.js → CommonDialog-CRXyMlp5.js} +1 -1
  24. package/src/ui/public/assets/EditorView-BIHL8I9g.js +1 -0
  25. package/src/ui/public/assets/{EditorView-C6HFYeEM.css → EditorView-DqxBkn6c.css} +1 -1
  26. package/src/ui/public/assets/{FileDiffViewer-CYxcLw10.js → FileDiffViewer-BEYcCYs5.js} +1 -1
  27. package/src/ui/public/assets/{FlowExecutionViewer-DTmlBLXQ.js → FlowExecutionViewer-DKRHDqbG.js} +1 -1
  28. package/src/ui/public/assets/{FlowOrchestrationWorkspace-Da_UmTRT.js → FlowOrchestrationWorkspace-BnCsF4z4.js} +1 -1
  29. package/src/ui/public/assets/{IconButton-BShiC2AP.js → IconButton-D4df4t9A.js} +1 -1
  30. package/src/ui/public/assets/{LogList-5M5JBhlB.js → LogList-DXqB4JJv.js} +1 -1
  31. package/src/ui/public/assets/{MindmapView-BUV_w14M.js → MindmapView-Ddc55wzp.js} +1 -1
  32. package/src/ui/public/assets/{MonitorView-D9N4QH5Y.js → MonitorView-DeERavq-.js} +1 -1
  33. package/src/ui/public/assets/{ProjectStartupButton-DYYQ-O7P.js → ProjectStartupButton-DaLU4iS4.js} +1 -1
  34. package/src/ui/public/assets/{RecentDirectoriesChat-BtWa_HMY.js → RecentDirectoriesChat-DVtsf7lW.js} +1 -1
  35. package/src/ui/public/assets/RecentDirectoriesChat-o4xK1Koc.css +1 -0
  36. package/src/ui/public/assets/{RemoteManagerDialog-C4QIJK_F.js → RemoteManagerDialog-C3cfDsZi.js} +1 -1
  37. package/src/ui/public/assets/{RemoteRepoCard-BmDh538v.js → RemoteRepoCard-D1Hso5Fq.js} +1 -1
  38. package/src/ui/public/assets/{SourceMapView-Ceamya-N.js → SourceMapView-Dwn5wy1o.js} +1 -1
  39. package/src/ui/public/assets/{SvgIcon-xtz4vvc9.js → SvgIcon-diKLLWK9.js} +1 -1
  40. package/src/ui/public/assets/{TemplateManager-DhKTZ4EM.js → TemplateManager-D9gyZbHP.js} +1 -1
  41. package/src/ui/public/assets/{UserInputNode-DfeCGlEO.js → UserInputNode-JNtVWcbE.js} +1 -1
  42. package/src/ui/public/assets/WorkbenchView-CJCxYK-K.css +1 -0
  43. package/src/ui/public/assets/WorkbenchView-DxaAjZAA.js +6 -0
  44. package/src/ui/public/assets/_plugin-vue_export-helper-C7IvbEC3.js +19 -0
  45. package/src/ui/public/assets/agentConversations-nN-yDz8q.js +5 -0
  46. package/src/ui/public/assets/configStore-C-htWfWm.js +1 -0
  47. package/src/ui/public/assets/{gitStore-ByP9lpuT.js → gitStore-DYpd8vZK.js} +1 -1
  48. package/src/ui/public/assets/index-BZFKDSGv.css +1 -0
  49. package/src/ui/public/assets/index-eq1OUcdk.js +29 -0
  50. package/src/ui/public/assets/{previewSandbox-DSzZ_Rky.js → previewSandbox-Z707CZD9.js} +1 -1
  51. package/src/ui/public/assets/toolsStore-DFu4Alwg.js +1 -0
  52. package/src/ui/public/assets/vendor-BY5ZDlW1.css +1 -0
  53. package/src/ui/public/assets/{vendor-CyWsJd6S.js → vendor-BjomZKSS.js} +28 -120
  54. package/src/ui/public/index.html +14 -14
  55. package/src/ui/server/index.js +4 -0
  56. package/src/ui/server/routes/config.js +11 -2
  57. package/src/ui/server/routes/fileOpen.js +78 -13
  58. package/src/ui/server/routes/memory.js +125 -0
  59. package/src/ui/server/routes/workbench/agentChat.js +35 -3
  60. package/src/ui/server/routes/workbench/agentChatShared.test.js +49 -0
  61. package/src/ui/server/routes/workbench/executorModels.js +329 -0
  62. package/src/ui/server/routes/workbench/executorModels.test.js +326 -0
  63. package/src/ui/server/routes/workbench/index.js +45 -2
  64. package/src/ui/server/routes/workbench/jobActivity.js +6 -0
  65. package/src/ui/server/routes/workbench/memoryContext.js +125 -0
  66. package/src/ui/server/routes/workbench/memoryContext.test.js +79 -0
  67. package/src/ui/server/routes/workbench/orchestratorStore.js +4 -1
  68. package/src/ui/server/routes/workbench/runExternalTurn.js +6 -1
  69. package/src/ui/server/routes/workbench/taskRunner.js +48 -5
  70. package/src/ui/public/assets/EditorView-fuMrS9P7.js +0 -1
  71. package/src/ui/public/assets/RecentDirectoriesChat-vHT8jMxW.css +0 -1
  72. package/src/ui/public/assets/WorkbenchView-D9l3i4Qj.css +0 -1
  73. package/src/ui/public/assets/WorkbenchView-DX2epPD9.js +0 -6
  74. package/src/ui/public/assets/_plugin-vue_export-helper-C_bQVzeb.js +0 -19
  75. package/src/ui/public/assets/agentConversations-BUPj8vzH.js +0 -5
  76. package/src/ui/public/assets/configStore-DJH7OlB_.js +0 -1
  77. package/src/ui/public/assets/index-CFX8sK4w.js +0 -29
  78. package/src/ui/public/assets/index-DVJITdth.css +0 -1
  79. package/src/ui/public/assets/toolsStore-B49mCaQ_.js +0 -1
  80. package/src/ui/public/assets/vendor-BzMymUBi.css +0 -1
@@ -108,6 +108,7 @@ import {
108
108
  canonicalProjectPath,
109
109
  } from './projectRegistry.js';
110
110
  import { buildEnvContextBlock } from './envContext.js';
111
+ import { ensureMemoryStore } from '../../../../memory/store.js';
111
112
  import { createJobSettledRefresher } from '../aiContext/jobRefresh.js';
112
113
  import {
113
114
  createDispatcher,
@@ -129,6 +130,7 @@ import {
129
130
  buildRunningFacts,
130
131
  generateProgressReport,
131
132
  } from './progressReport.js';
133
+ import { detectExecutorModels, formatExecutorModel } from './executorModels.js';
132
134
 
133
135
  /**
134
136
  * 「任务结束 → 刷快照」的监听器。存成模块级的,是为了在重复装配路由时
@@ -1156,6 +1158,23 @@ ${subSummaries.map((s, i) => `\n### [${i + 1}] ${s.name} (${s.root})\n${s.summar
1156
1158
  });
1157
1159
  });
1158
1160
 
1161
+ /**
1162
+ * 铺一次记忆库种子(幂等,only-if-missing)。
1163
+ *
1164
+ * **为什么在这里而不是 taskRunner 每次派发时**:目录不存在时若每次派发都尝试
1165
+ * 铺,等于把"有没有记忆"绑在"这次有没有干活"上;而且首次铺种子的 IO 抖动会
1166
+ * 落在派发的关键路径上。注册路由时铺一次,语义是"工作台起来了,记忆库就位"。
1167
+ *
1168
+ * 失败只记日志不抛:记忆库铺不出来不该让整个工作台起不来
1169
+ * (与上面 resolveEnvContext 同一原则)。真正注入时 taskRunner 拿不到项目索引
1170
+ * 会自动降级成"只有全局那层",Agent 照样能用。
1171
+ */
1172
+ ensureMemoryStore()
1173
+ .then(({ created }) => {
1174
+ if (created.length) logger.info(`[workbench] 已铺记忆库种子: ${created.join(', ')}`);
1175
+ })
1176
+ .catch((err) => logger.warn('[workbench] 铺记忆库种子失败,记忆功能降级:', err?.message || err));
1177
+
1159
1178
  /**
1160
1179
  * 「工作台任务执行结束」→ 定向刷新快照。
1161
1180
  *
@@ -1164,8 +1183,7 @@ ${subSummaries.map((s, i) => `\n### [${i + 1}] ${s.name} (${s.root})\n${s.summar
1164
1183
  *
1165
1184
  * `bus.on` 前先 `off` 掉上一个:bus 是模块级单例,重复注册(例如同一进程里
1166
1185
  * 再次装配路由)会让同一次 job 结束被刷好几遍。
1167
- */
1168
- if (jobSettledHandler) bus.off('event', jobSettledHandler);
1186
+ */ if (jobSettledHandler) bus.off('event', jobSettledHandler);
1169
1187
  jobSettledHandler = createJobSettledRefresher({
1170
1188
  getSnapshotter: getAiContextSnapshotter,
1171
1189
  onError: (err) => logger.warn('[workbench] 任务结束后刷新工作区快照失败:', err?.message || err),
@@ -1497,6 +1515,31 @@ ${subSummaries.map((s, i) => `\n### [${i + 1}] ${s.name} (${s.root})\n${s.summar
1497
1515
  }
1498
1516
  }));
1499
1517
 
1518
+ // ════════════════════════════════════════════════════════════════════════
1519
+ // §20. 执行器模型探测(只读)
1520
+ // ════════════════════════════════════════════════════════════════════════
1521
+ /**
1522
+ * 「这三个执行器现在实际在用什么模型」。
1523
+ *
1524
+ * 为什么需要这个端点:工作台派任务**一律不传 --model**(见 executorModels.js 的
1525
+ * 长注释),模型完全跟随各自 CLI 的配置文件。副作用是界面上一个执行器的模型都
1526
+ * 看不到 —— 用户想确认"这活到底是哪个模型跑的"只能去翻三个不同格式的配置文件。
1527
+ * 这个端点把那件事收口到一次请求里。
1528
+ *
1529
+ * 无参数、服务端不算缓存:三个文件都很小,每次实读比让前端踩脏缓存划算;
1530
+ * 前端那边(stores/toolsStore)自己按分钟级 TTL + 并发去重压请求频率。
1531
+ * 返回值里某项为 null = 那个 CLI 没在配置里写模型,前端照实显示「未在配置中指定」。
1532
+ * key 恒为 claude / codex / opencode 三个,与 TASK_EXECUTOR_OPTIONS 对齐。
1533
+ */
1534
+ app.get('/api/workbench/executor-models', asyncRoute(async (_req, res) => {
1535
+ const detected = await detectExecutorModels();
1536
+ const models = {};
1537
+ for (const [executor, info] of Object.entries(detected)) {
1538
+ models[executor] = formatExecutorModel(info);
1539
+ }
1540
+ res.json({ success: true, checkedAt: nowIso(), models });
1541
+ }));
1542
+
1500
1543
  // 暂存区兜底清理:粘了图却没派发就关页面的痕迹,不该永久占着磁盘。
1501
1544
  // 不上定时器 —— 暂存区的生命周期本来就是"几分钟内被派发掉",启动清一次足够。
1502
1545
  cleanupDispatchStaging().catch(err => {
@@ -220,6 +220,12 @@ export function buildLiveActivity(job, now = Date.now()) {
220
220
  /** 本轮执行器(claude | opencode | codex)。老记录没有这个字段 → 空串 */
221
221
  agent: jobAgent(job),
222
222
  startedAt: job.startedAt || null,
223
+ /**
224
+ * 子进程 PID。原来只有左栏那个「执行监控」面板会显示它,面板去掉之后
225
+ * 卡片就是唯一的落点 —— 真要手动 kill 或排查僵尸 claude 进程时,
226
+ * 这是卡片上唯一能指认"到底是哪个进程"的字段。
227
+ */
228
+ pid: job.pid || null,
223
229
  elapsedMs: Number.isFinite(started) ? Math.max(0, now - started) : 0,
224
230
  /** 见 taskRunner 的 MAX_TOOL_CALLS:超上限的调用不再入数组,所以这是"至少这么多次" */
225
231
  toolCallCount: Array.isArray(job.toolCalls) ? job.toolCalls.length : 0,
@@ -0,0 +1,125 @@
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // 派发任务时注入给 Agent 的「记忆指针块」—— 让被派出去的 agent 知道
16
+ // 本机有一份跨会话经验库、以及**怎么按预算的方式去读它**。
17
+ //
18
+ // ── 与 envContext 的关系(同一个位置,两件事)────────────────────────
19
+ // envContext.js 讲的是"这台机器此刻的现场"(项目清单 / 看板 / 真相源路径),
20
+ // 快照语义、每次都变;这里讲的是"这个仓库踩过的坑",长期累积、很少变。
21
+ // 两者都在 taskRunner.js 拼 prompt 时前置,注入失败都不该挡住任务执行。
22
+ //
23
+ // ── 为什么用"指针"而不是把索引内容塞进 prompt ───────────────────────
24
+ // 把 INDEX.md 全文塞进 prompt 是最省事也最糟的做法:索引会随记忆增长线性膨胀,
25
+ // 而**每次派发都要为每一条不相关的历史经验付 token**。塞路径 + 塞纪律(各 5~8 行),
26
+ // 剩下的交给 Agent 自己的 read 工具按需取 —— 这正是"索引式摘要"这个需求的核心。
27
+ //
28
+ // ⚠️ 文案可以硬编码中文(与 envContext.js 同一口径):这里是喂给模型的 prompt
29
+ // 内容,不经过前端 $t()、不显示在界面上,也不该跟着界面语言变。
30
+ //
31
+ // 纯函数:只吃入参、不读文件、不做 IO。这样单测不用碰真实用户数据 ——
32
+ // 与 envContext.js / promptParts.js 同一个理由。取数在 store.js。
33
+
34
+ /** 指针块自身的体积上限(字节)。超了就是文案写飘了,Agent 读它比查索引还贵。 */
35
+ export const MEMORY_BLOCK_MAX_BYTES = 2048;
36
+
37
+ /** 状态标签:给 UI / 日志判断"这次注入了几层信息",不参与 prompt 语义 */
38
+ export const MEMORY_BLOCK_LEVEL = {
39
+ /** 记忆库不可用(目录不存在且铺种子失败)—— 完全不注入 */
40
+ NONE: 'none',
41
+ /** 库在,但没有本项目目录 —— 只给全局路径 */
42
+ GLOBAL_ONLY: 'global-only',
43
+ /** 库在且本项目目录在 —— 给全局 + 本项目两个路径 */
44
+ PROJECT: 'project',
45
+ };
46
+
47
+ /**
48
+ * 拼记忆指针块。
49
+ *
50
+ * @param {object} input
51
+ * @param {string} input.memoryDir 记忆库根目录(~/<pkg>/memory 的绝对路径)
52
+ * @param {string} [input.projectIndexFile] 本项目索引绝对路径;空/不存在 → 只给全局那层
53
+ * @param {boolean} [input.capture=true] 是否附上"收尾时怎么记"那一段。
54
+ * 续聊轮可以关掉(同一场对话里第二、三轮再讲一遍捕获纪律是噪音)。
55
+ * @param {string} [input.locale] 暂未使用;预留让文案随界面语言走(中文硬编码是
56
+ * 当前口径,见文件头注释)
57
+ * @returns {{ block: string, level: string }} block 为 '' 表示不注入
58
+ */
59
+ export function buildMemoryPointerBlock(input = {}) {
60
+ const {
61
+ memoryDir = '',
62
+ projectIndexFile = '',
63
+ capture = true,
64
+ } = input;
65
+
66
+ if (!memoryDir) return { block: '', level: MEMORY_BLOCK_LEVEL.NONE };
67
+
68
+ const lines = [
69
+ '## 跨会话记忆库(本机)',
70
+ '',
71
+ `本机有一份长期经验库,是**之前在这个仓库干活的 agent 留下的坑**。开工前先查,别重复踩:`,
72
+ '',
73
+ `- 全局索引:\`${memoryDir}/INDEX.md\`(项目清单 + 通用坑主题词)`,
74
+ ];
75
+
76
+ let level = MEMORY_BLOCK_LEVEL.GLOBAL_ONLY;
77
+ if (projectIndexFile) {
78
+ lines.push(`- **本项目索引:\`${projectIndexFile}\`** ← 先读这个`);
79
+ level = MEMORY_BLOCK_LEVEL.PROJECT;
80
+ } else {
81
+ lines.push('- 本项目还没有记忆库条目(首次在本仓库干活时会被自动建好)');
82
+ }
83
+
84
+ lines.push(
85
+ '',
86
+ '**怎么读(别烧 token)**:',
87
+ '',
88
+ '1. 用 read 工具读上面那个索引;',
89
+ '2. 索引里某条的关键词和当前任务**真正相关**时,才去读它指向的 `lessons/<topic>.md`;',
90
+ '3. 没命中就别读。**不要预加载全部 lessons,也不要读 `archive/`** —— ',
91
+ ' 索引是给你做取舍的,不是让你通读的。',
92
+ );
93
+
94
+ if (capture) {
95
+ lines.push(
96
+ '',
97
+ '**收尾时(做完了、准备回复之前)自检一次**,四条里任意一条为"是"就记一条:',
98
+ '',
99
+ '1. 本轮卡住 ≥3 分钟,或走了 A→放弃→B→放弃→C 的反复路径;',
100
+ '2. 用错了工具 / 写错了文件 / grep 命中被构建产物淹没 / 探针假绿;',
101
+ '3. 用户纠正了你的方向、用法或命名;',
102
+ '4. 发现"看似绕路但更快"或"反直觉但正确"、且被验证有效的做法。',
103
+ '',
104
+ '记的时候:',
105
+ '',
106
+ '- 写"**以后怎么做**",不写"我做了什么"(后者是 commit message 的活);',
107
+ '- 单条 ≤25 行,形状 ` lessons/<topic>.md`:`# 一句话讲清坑是什么` / 现象根因 / `**How to apply:**`;',
108
+ '- 同主题**追加/改写已有文件**,不要新建近似重复的(先 read 一眼);',
109
+ '- 跨仓库都成立 → 写 `${memoryDir}/GLOBAL.md`;只跟本仓库有关 → 写本项目 `lessons/`;',
110
+ `- 写完**必须在对应 INDEX.md 补一行** \`- [标题](lessons/<file>.md) — ≤100 字摘要\`。**没索引的记忆等于不存在。**`,
111
+ '- 四条全否 → 一条都别写。不要为沉淀而沉淀。',
112
+ );
113
+ }
114
+
115
+ let block = lines.join('\n');
116
+
117
+ // 文案哪天写飘了也不许把 prompt 撑大:超预算就砍掉捕获段(最长的可省部分),
118
+ // 召回指针本身必须留着 —— 那是这个块存在的全部理由。
119
+ if (Buffer.byteLength(block, 'utf8') > MEMORY_BLOCK_MAX_BYTES && capture) {
120
+ lines.length = lines.findIndex((l) => l.includes('收尾时'));
121
+ block = lines.join('\n').trimEnd();
122
+ }
123
+
124
+ return { block, level };
125
+ }
@@ -0,0 +1,79 @@
1
+ // memoryContext.js 的单测。
2
+ //
3
+ // 纯函数、不碰文件系统(见该文件头注释),所以直接喂入参断输出即可 ——
4
+ // 与 envContext.test.js 同一个理由,也正是它要保持纯的原因。
5
+ import { test } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import {
8
+ buildMemoryPointerBlock,
9
+ MEMORY_BLOCK_MAX_BYTES,
10
+ MEMORY_BLOCK_LEVEL,
11
+ } from './memoryContext.js';
12
+
13
+ const DIR = '/home/u/.zen-gitsync/memory';
14
+ const PIDX = `${DIR}/projects/my-repo/INDEX.md`;
15
+
16
+ test('没有 memoryDir → 完全不注入', () => {
17
+ const { block, level } = buildMemoryPointerBlock({});
18
+ assert.equal(block, '');
19
+ assert.equal(level, MEMORY_BLOCK_LEVEL.NONE);
20
+ });
21
+
22
+ test('只有全局层:给全局索引路径,明说本项目还没有条目', () => {
23
+ const { block, level } = buildMemoryPointerBlock({ memoryDir: DIR });
24
+ assert.equal(level, MEMORY_BLOCK_LEVEL.GLOBAL_ONLY);
25
+ assert.ok(block.includes(`${DIR}/INDEX.md`));
26
+ assert.ok(block.includes('本项目还没有记忆库条目'));
27
+ // 捕获段里仍会出现 lessons/ —— Agent 收尾时要知道往哪儿写;
28
+ // 这里断言的是**不出现项目索引路径**(没有的路径给了就是骗 Agent)。
29
+ assert.ok(!block.includes(`${DIR}/projects/`));
30
+ assert.ok(!block.includes('本项目索引'));
31
+ });
32
+
33
+ test('有项目层:标为 PROJECT 并点名本项目索引', () => {
34
+ const { block, level } = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX });
35
+ assert.equal(level, MEMORY_BLOCK_LEVEL.PROJECT);
36
+ assert.ok(block.includes(PIDX));
37
+ assert.ok(!block.includes('本项目还没有记忆库条目'));
38
+ });
39
+
40
+ test('capture=false → 保留召回纪律、砍掉捕获纪律', () => {
41
+ const withCap = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX, capture: true });
42
+ const noCap = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX, capture: false });
43
+ assert.ok(withCap.block.includes('收尾时'));
44
+ assert.ok(!noCap.block.includes('收尾时'));
45
+ // 砍的只是长的那段,召回指针必须还在 —— 那才是这个块存在的理由
46
+ assert.ok(noCap.block.includes(PIDX));
47
+ assert.ok(noCap.block.length > 0);
48
+ assert.ok(Buffer.byteLength(noCap.block, 'utf8') < Buffer.byteLength(withCap.block, 'utf8'));
49
+ });
50
+
51
+ test('块本身不能超预算(这是它替代"索引全文进 prompt"的前提)', () => {
52
+ const { block } = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX });
53
+ assert.ok(
54
+ Buffer.byteLength(block, 'utf8') <= MEMORY_BLOCK_MAX_BYTES,
55
+ `块 ${Buffer.byteLength(block, 'utf8')}B 超过 ${MEMORY_BLOCK_MAX_BYTES}B 预算`
56
+ );
57
+ });
58
+
59
+ test('超预算时降级:砍捕获段、保住召回指针(不静默产出超大 prompt)', () => {
60
+ const { block } = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX, capture: true });
61
+ const recallAt = block.indexOf('不要预加载全部 lessons');
62
+ const captureAt = block.indexOf('收尾时');
63
+ assert.ok(recallAt > 0, '召回纪律必须在');
64
+ assert.ok(captureAt > recallAt, '捕获纪律必须排在召回纪律之后');
65
+ });
66
+
67
+ test('纪律里必须写死两条硬约束:懒加载 + 索引缺一不可', () => {
68
+ const { block } = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX });
69
+ assert.match(block, /不要预加载全部 lessons/);
70
+ assert.match(block, /archive/);
71
+ assert.match(block, /没索引的记忆等于不存在/);
72
+ assert.match(block, /以后怎么做/);
73
+ });
74
+
75
+ test('续接场景(capture 由调用方关掉)不产生空块', () => {
76
+ const { block } = buildMemoryPointerBlock({ memoryDir: DIR, projectIndexFile: PIDX, capture: false });
77
+ assert.ok(block.trim().length > 0);
78
+ assert.ok(block.includes(PIDX), '关掉捕获纪律不能把召回指针一起关掉');
79
+ });
@@ -421,12 +421,15 @@ export async function appendReport(entry) {
421
421
  }
422
422
 
423
423
  /**
424
- * 正在执行的执行体清单(看板左栏「执行监控」用)。
424
+ * 正在执行的执行体清单(右栏控制台顶部的「{n} 个执行中」计数用)。
425
425
  *
426
426
  * 一行 = 一个活跃 job(不是任务):job 只是执行进程,
427
427
  * 所以文案上叫「执行」而不是「Agent」—— 不要把正在跑的 claude 进程
428
428
  * 渲染成一个并不存在的"智能体集群"。
429
429
  *
430
+ * 它曾有第二个消费者:看板左栏那块「执行监控」面板(2026-09-29 已删,
431
+ * 字段与中间「进行中」卡片重合,只剩 PID 有增量 —— 那个已并到卡片上)。
432
+ *
430
433
  * @param {{ jobs?: object[], tasks?: object[] }} input
431
434
  */
432
435
  export function buildRunningAgents({ jobs = [], tasks = [] } = {}) {
@@ -40,6 +40,7 @@
40
40
  import { spawn, execFile } from 'child_process';
41
41
  import { logger } from './shared.js';
42
42
  import { engineLabel } from './agentEngines.js';
43
+ import { isPlanToolName } from '../../../../cli/ai/tools.js';
43
44
  import {
44
45
  createToolCallTracker,
45
46
  createClaudeEventHandler,
@@ -181,7 +182,11 @@ export async function runExternalTurn({
181
182
  const id = u.id || '';
182
183
  if (id && !announced.has(id)) {
183
184
  announced.add(id);
184
- send({ type: 'tool_call_start', toolCallId: id, name: u.name, argsPreview: u.argsPreview || '' });
185
+ // 计划类工具额外带完整参数:外部引擎里 claude 的 TodoWrite / opencode 的
186
+ // todowrite 就是计划,前端要靠原始 steps 渲染清单,而 argsPreview 是摘要。
187
+ // 只给计划类发全文,与内置 g ai 那条链路(agentChat.js)保持同一口径。
188
+ const planArgs = isPlanToolName(u.name) ? (u.arguments || '') : undefined;
189
+ send({ type: 'tool_call_start', toolCallId: id, name: u.name, argsPreview: u.argsPreview || '', arguments: planArgs });
185
190
  }
186
191
  if (u.status !== 'running') {
187
192
  send({
@@ -45,6 +45,7 @@ import {
45
45
  } from './shared.js';
46
46
  import { buildAttachmentBlock } from './pdfText.js';
47
47
  import { composePromptBody } from './promptParts.js';
48
+ import { buildMemoryPointerBlock } from './memoryContext.js';
48
49
  import {
49
50
  jobs,
50
51
  cancelledJobs,
@@ -52,6 +53,11 @@ import {
52
53
  flushJobsSaveNow,
53
54
  scheduleActiveJobsSave,
54
55
  } from './jobStore.js';
56
+ // MEMORY_DIR 在 paths.js(路径唯一真相源),projectIndexFile 在 memory/store.js ——
57
+ // 两个模块各取一处,别图省事都从 store.js 拿:store.js 没有 re-export MEMORY_DIR,
58
+ // 混着写会在**链接期**就炸(node --check 查不出来,得靠动态 import 或真跑单测)。
59
+ import { MEMORY_DIR } from '../../../../paths.js';
60
+ import { projectIndexFile } from '../../../../memory/store.js';
55
61
 
56
62
  // ── 运行环境上下文的提供者 ────────────────────────────────────────────────
57
63
  // 为什么用注入而不是在这里直接读:拼这份上下文要「最近目录」(在 configManager 上),
@@ -86,6 +92,23 @@ async function resolveEnvContext(repoPath) {
86
92
  }
87
93
  }
88
94
 
95
+ /**
96
+ * 取本仓库的记忆索引路径。
97
+ *
98
+ * **只读不建** —— 与 resolveEnvContext 同一原则:拼 prompt 是锦上添花,
99
+ * 记忆库不存在就只给全局那层,让 Agent 收尾时自己建(它有文件工具,也有那个动机)。
100
+ * 在这里建目录等于"读一次就产生一次副作用",派发任务不该有这种语义。
101
+ */
102
+ function resolveProjectMemoryIndex(repoPath) {
103
+ if (!repoPath) return '';
104
+ try {
105
+ return projectIndexFile(repoPath);
106
+ } catch (err) {
107
+ logger.warn(`[workbench] 记忆索引路径解析失败,本次不注入项目层: ${err.message}`);
108
+ return '';
109
+ }
110
+ }
111
+
89
112
  // 用 detached 进程跑 claude;进程退出时回填状态。
90
113
  // 返回 { pid, child }:调用方可以监听 child.stdout/stderr 实时收集输出。
91
114
  // 不再走 cmd /k 弹窗——claude -p 是非交互模式,输出通过 stdout pipe 实时回传
@@ -885,13 +908,33 @@ export async function runSingleSubtask(task, sub, repoPath, branch, options) {
885
908
  }
886
909
  }
887
910
 
888
- // ── 运行环境上下文:项目清单 + 看板概览 + 真相源文件路径 ──
889
- // 拼在**最前面**、任务正文压尾:
890
- // 越靠后离模型的注意力中心越近,用户真正要办的那句话必须在最后一屏。
891
- // task.envContext === false 可以单任务关掉(默认开 —— 老任务不迁移也一并受益)。
911
+ // ── 两块「背景」都拼在最前面,任务正文压尾 ──
912
+ // 顺序刻意是 [环境上下文 → 记忆指针 → 任务正文]:
913
+ // · 越靠后离模型的注意力中心越近,**用户真正要办的那句话必须在最后一屏**;
914
+ // · 记忆块夹在两块之间,不能放末尾 —— 放末尾等于把"背景"讲成了"当前任务",
915
+ // Agent 会以为这轮用户要求它去整理记忆库。
916
+ // 两块都可用 `task.<key> === false` 单任务关掉(默认开 —— 老任务不迁移也一并受益)。
917
+ const prefixBlocks = [];
918
+
892
919
  if (task.envContext !== false) {
893
920
  const envBlock = await resolveEnvContext(repoPath);
894
- if (envBlock) prompt = `${envBlock}\n\n---\n\n${prompt}`;
921
+ if (envBlock) prefixBlocks.push(envBlock);
922
+ }
923
+
924
+ if (task.memoryContext !== false) {
925
+ const memBlock = buildMemoryPointerBlock({
926
+ memoryDir: MEMORY_DIR,
927
+ // 首次在某仓库干活时目录还不存在 —— 这时不给项目路径,块里会明说
928
+ // "本项目还没有条目",Agent 收尾时自己建。
929
+ projectIndexFile: resolveProjectMemoryIndex(repoPath),
930
+ // 续聊轮不再重复讲捕获纪律:同一场对话里讲第二遍纯属噪音。
931
+ capture: !resumeSessionId,
932
+ }).block;
933
+ if (memBlock) prefixBlocks.push(memBlock);
934
+ }
935
+
936
+ if (prefixBlocks.length > 0) {
937
+ prompt = `${prefixBlocks.join('\n\n---\n\n')}\n\n---\n\n${prompt}`;
895
938
  }
896
939
 
897
940
  const jobId = genId();
@@ -1 +0,0 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Cn as t,Dn as n,En as r,Er as i,H as a,Jn as o,Kn as s,Mn as c,Pn as ee,Pr as l,Qn as te,Qr as u,Rn as d,Tn as f,Un as p,Xn as m,Yr as h,_n as ne,a as g,br as _,cr as re,gn as ie,hn as v,jn as y,ln as ae,lr as b,or as x,pr as S,qr as C,vn as oe,wn as w,xn as se,xr as ce,yn as T}from"./element-plus-Bx3j6vzG.js";import{o as le,r as E,t as ue}from"./vendor-CyWsJd6S.js";import{n as D,t as O}from"./_plugin-vue_export-helper-C_bQVzeb.js";import{t as de}from"./SvgIcon-xtz4vvc9.js";import{t as fe}from"./configStore-DJH7OlB_.js";import{n as pe,t as me}from"./fileIcon-B5p5pGN9.js";import{a as he,i as ge,n as _e,r as ve,s as k,t as ye}from"./previewSandbox-DSzZ_Rky.js";import{a as be,c as xe,l as Se,n as Ce,o as we,r as Te,s as Ee}from"./monaco-DkJuNcCr.js";import{t as De}from"./useThemeObserver-DYxFoHh1.js";import{r as Oe,t as A}from"./flow-mindmap-OPE_D4da.js";import{r as ke}from"./index-CFX8sK4w.js";import{a as Ae,i as je,n as Me,o as Ne,r as Pe,s as Fe,t as Ie}from"./agentConversations-BUPj8vzH.js";import{n as Le,t as j}from"./AgentEngineSelector-DLJ8He83.js";function Re(e){return{ts:`typescript`,tsx:`typescript`,js:`javascript`,mjs:`javascript`,cjs:`javascript`,jsx:`javascript`,vue:`html`,html:`html`,htm:`html`,css:`css`,scss:`scss`,less:`less`,json:`json`,jsonc:`json`,md:`markdown`,markdown:`markdown`,yaml:`yaml`,yml:`yaml`,toml:`ini`,xml:`xml`,svg:`xml`,sh:`shell`,bash:`shell`,zsh:`shell`,fish:`shell`,ps1:`powershell`,py:`python`,go:`go`,rs:`rust`,java:`java`,kt:`kotlin`,rb:`ruby`,php:`php`,c:`c`,cpp:`cpp`,h:`cpp`,cs:`csharp`,sql:`sql`,graphql:`graphql`,gql:`graphql`,txt:`plaintext`,log:`plaintext`,ini:`ini`,env:`ini`,gitignore:`ini`,dockerfile:`dockerfile`}[e.toLowerCase()]??`plaintext`}d(),S();var M={class:`mindmap-preview`},N={class:`mindmap-preview-canvas`},P=O(ee({__name:`MindmapPreview`,props:{content:{}},setup(e){let r=e,a=t(()=>A(r.content||``,`未命名文档`));return(e,t)=>(m(),n(`div`,M,[t[0]||=w(`div`,{class:`mindmap-preview-header`},[w(`span`,{class:`mindmap-preview-title`},`整篇导图`),w(`span`,{class:`mindmap-preview-hint`},`基于整篇 Markdown 自动生成 · 阅读模式`)],-1),w(`div`,N,[c(i(Oe),{data:a.value,"preview-mode":``},null,8,[`data`])])]))}}),[[`__scopeId`,`data-v-d2fe328b`]]);d(),S(),l(),ae();var ze={class:`agent-panel-header`},Be=[`title`,`aria-label`],Ve={class:`agent-panel-title`},He={key:1,class:`agent-panel-title`},Ue=[`title`,`aria-label`],We=[`title`],Ge={class:`agent-panel-convs`},Ke=[`data-theme`],F=[`title`],I={class:`agent-context-att-name`},L=[`title`,`aria-label`],qe=O(ee({__name:`EditorAgentPanel`,props:{activeFilePath:{},activeFileName:{},active:{type:Boolean}},emits:[`close`],setup(a,{emit:ee}){let l=a,te=ee,{theme:d}=De(),h=t(()=>d.value===`dark`?`dark`:`light`),{sessions:ne,sessionsLoading:g,currentSessionId:re,messages:v,isStreaming:y,pendingQuestion:ae,answeringQuestion:S,isSessionGenerating:oe,currentEngine:ce,pendingEngine:O,isEngineLocked:de,pickEngine:fe,loadSessions:pe,loadSession:me,deleteSession:he,renameSession:ge,newSession:_e,sendMessage:ve,answerQuestion:k,stop:ye}=Fe(),be=t(()=>de.value?ce.value:O.value);function xe(e){de.value||fe(e)}let Se=t(()=>Ae(ne.value,oe)),Ce=Pe(),we=je(),Te=_(null),Ee=_(null),Oe=_(null),A=_(null),ke=_(null),{width:Re,narrow:M}=Le(ke),N=_(`chat`),P=_(null),qe=_(!1),R=null,Je=t(()=>!!l.activeFileName&&!qe.value);function Ye(e){return Array.from(e.children).find(e=>e.classList?.contains(`acu-input-attachments`))??null}function Xe(){let e=Ee.value?.$el;if(!e)return;let t=e.querySelector(`.agent-context-slot`);if(!Je.value){if(!t)return;P.value=null,p(()=>t.remove());return}let n=P.value&&e.contains(P.value)?P.value:t;n||(n=document.createElement(`div`),n.className=`agent-context-slot`);let r=Ye(e),i=r??e;n.parentElement!==i&&i.insertBefore(n,r?r.firstChild:e.firstChild),P.value=n}function Ze(e=!0){Te.value?.scrollToBottom(e)}async function Qe(e){let t=qe.value?void 0:l.activeFilePath||void 0;await ve(e.text,e.files,{openFilePath:t}),await p(),Ze()}function $e(e){me(e),N.value=`chat`}function et(){_e(),N.value=`chat`}x(()=>v.value.length,()=>{p(()=>Ze(!1))});function tt(){let e=A.value;e&&typeof MutationObserver<`u`&&(R?.disconnect(),R=new MutationObserver(()=>Xe()),R.observe(e,{childList:!0,subtree:!0}))}return x(()=>l.active,e=>{e&&(N.value=`chat`,pe().catch(()=>{}),p(()=>{Xe(),Ze(!1)}))}),x(M,e=>{e||(N.value=`chat`)}),x(()=>l.activeFilePath,()=>{qe.value=!1}),x(Je,e=>{e&&p(Xe)}),o(()=>{pe().catch(()=>{}),p(()=>{Xe(),tt()})}),s(()=>{R?.disconnect(),R=null,P.value=null}),(t,o)=>(m(),n(`div`,{ref_key:`rootRef`,ref:ke,class:`editor-agent-panel`},[w(`div`,ze,[i(M)&&N.value===`list`?(m(),n(T,{key:0},[w(`button`,{class:`agent-panel-icon-btn agent-panel-back-btn`,title:i(D)(`@EDITOR:返回对话`),"aria-label":i(D)(`@EDITOR:返回对话`),onClick:o[0]||=e=>N.value=`chat`},[...o[4]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),w(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,Be),w(`span`,Ve,u(i(D)(`@EDITOR:会话列表`)),1)],64)):(m(),n(`span`,He,u(i(D)(`@EDITOR:g ai 对话`)),1)),o[7]||=w(`div`,{class:`agent-panel-spacer`},null,-1),!i(M)||N.value===`chat`?(m(),f(j,{key:2,class:`agent-panel-engine`,engine:be.value,locked:i(de),onSelect:xe},null,8,[`engine`,`locked`])):r(``,!0),i(M)&&N.value===`chat`?(m(),n(`button`,{key:3,class:`agent-panel-icon-btn agent-panel-list-btn`,title:i(D)(`@EDITOR:会话列表`),"aria-label":i(D)(`@EDITOR:会话列表`),onClick:o[1]||=e=>N.value=`list`},[...o[5]||=[e(`<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" data-v-d910c906><line x1="8" y1="6" x2="21" y2="6" data-v-d910c906></line><line x1="8" y1="12" x2="21" y2="12" data-v-d910c906></line><line x1="8" y1="18" x2="21" y2="18" data-v-d910c906></line><line x1="3" y1="6" x2="3.01" y2="6" data-v-d910c906></line><line x1="3" y1="12" x2="3.01" y2="12" data-v-d910c906></line><line x1="3" y1="18" x2="3.01" y2="18" data-v-d910c906></line></svg>`,1)]],8,Ue)):r(``,!0),w(`button`,{class:`agent-panel-icon-btn`,title:i(D)(`@EDITOR:关闭对话`),onClick:o[2]||=e=>te(`close`)},[...o[6]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[w(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),w(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,We)]),w(`div`,{class:C([`agent-panel-body`,{"is-wide":!i(M)}])},[b(w(`div`,Ge,[c(i(E),{"show-search":!0,items:Se.value,"active-id":i(re),loading:i(g),labels:i(Ce),onSelect:$e,onNew:et,onRename:i(ge),onDelete:i(he)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],512),[[ie,!i(M)||N.value===`list`]]),b(w(`div`,{ref_key:`chatHostRef`,ref:Oe,class:`agent-panel-chat`},[c(i(ue),{ref_key:`chatRef`,ref:Te,"show-input":!1,messages:i(v),"assistant-name":i(Me),"assistant-avatar":i(Ie),theme:h.value,question:i(ae),"question-submitting":i(S),"question-labels":i(we),onAnswer:i(k)},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`question`,`question-submitting`,`question-labels`,`onAnswer`])],512),[[ie,!i(M)||N.value===`chat`]]),i(Re)>0?(m(),n(`div`,{key:0,ref_key:`composerRef`,ref:A,class:`agent-panel-composer acu-root`,"data-theme":h.value},[c(i(le),{ref_key:`inputRef`,ref:Ee,disabled:i(y),generating:i(y),placeholder:i(y)?i(D)(`@AGENT:正在生成中...`):i(D)(`@AGENT:输入消息,Enter 发送`),"upload-config":{accept:i(Ne)},onSend:Qe,onStop:i(ye)},null,8,[`disabled`,`generating`,`placeholder`,`upload-config`,`onStop`]),P.value?(m(),f(se,{key:0,to:P.value},[Je.value?(m(),n(`div`,{key:0,class:`agent-context-att`,title:a.activeFilePath||``},[o[9]||=w(`svg`,{class:`agent-context-att-icon`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.7`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[w(`path`,{d:`M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z`}),w(`polyline`,{points:`14 3 14 8 19 8`})],-1),w(`span`,I,u(a.activeFileName),1),w(`button`,{type:`button`,class:`agent-context-att-remove`,title:i(D)(`@EDITOR:不引用当前文档`),"aria-label":i(D)(`@EDITOR:不引用当前文档`),onClick:o[3]||=e=>qe.value=!0},[...o[8]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`3`,"stroke-linecap":`round`,"aria-hidden":`true`},[w(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),w(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,L)],8,F)):r(``,!0)],8,[`to`])):r(``,!0)],8,Ke)):r(``,!0)],2)],512))}}),[[`__scopeId`,`data-v-d910c906`]]);d(),S(),l(),ae();var R={class:`sidebar-header`},Je={class:`sidebar-title`},Ye={class:`sidebar-actions`},Xe={class:`sidebar-search`},Ze=[`placeholder`,`title`],Qe=[`title`,`aria-label`],$e={key:0,class:`sidebar-tree`},et={key:1,class:`tree-arrow-spacer`},tt={class:`tree-icon mit-icon`,"aria-hidden":`true`},nt=[`xlink:href`],rt=[`onClick`,`onContextmenu`],it={key:1,class:`tree-arrow-spacer`},at={key:2,class:`tree-icon mit-icon`,"aria-hidden":`true`},ot=[`xlink:href`],st={key:3,class:`tree-icon mit-icon`,"aria-hidden":`true`},ct=[`xlink:href`],lt=[`title`],ut={key:0,class:`tree-name-hit`},dt={key:4,class:`tree-loading`},ft={key:0,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--color-warning)`}},pt={key:1,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--text-tertiary)`}},mt=[`placeholder`],ht={key:0,class:`tree-node tree-inline-input-row`,style:{paddingLeft:`12px`}},gt={key:0,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--color-warning)`}},_t={key:1,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{"flex-shrink":`0`,color:`var(--text-tertiary)`}},vt=[`placeholder`],yt={key:1,class:`tree-empty`},bt={key:1,class:`sidebar-loading`},xt={class:`editor-main`},St={key:0,class:`editor-tabs`},Ct=[`onClick`,`title`],wt={class:`tab-name`},Tt={key:0,class:`tab-dirty-dot`},Et=[`onClick`],Dt=[`title`],Ot=[`disabled`,`title`],kt=[`title`],At={key:1,class:`editor-empty`},jt={viewBox:`0 0 24 24`,width:`48`,height:`48`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{opacity:`.3`}},Mt={class:`editor-empty-hint`},Nt={class:`editor-body`},Pt={key:0,class:`image-tab-placeholder`},Ft={viewBox:`0 0 24 24`,width:`56`,height:`56`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,style:{opacity:`.35`}},It={class:`image-tab-placeholder-title`},Lt={class:`image-tab-placeholder-hint`},Rt={class:`preview-header`},zt={class:`preview-title`},Bt={class:`preview-ext-badge`},Vt=[`title`],Ht={class:`preview-body`},Ut=[`sandbox`,`srcdoc`],Wt=6e4,Gt=O(ee({__name:`EditorView`,props:{pendingFilePath:{}},setup(ee){self.MonacoEnvironment={getWorker(e,t){return t===`json`?new xe:t===`css`||t===`scss`||t===`less`?new Ee:t===`html`||t===`handlebars`||t===`razor`?new we:t===`typescript`||t===`javascript`?new be:new Se}};let l=ee,d=fe(),ae=ke(),S=_([]),le=_(!1),E=_(``),ue=_(``),O=null;function Oe(){E.value=``,ue.value=``,O&&=(clearTimeout(O),null)}x(E,e=>{O&&clearTimeout(O),O=setTimeout(()=>{ue.value=e,O=null},180)}),s(()=>{O&&clearTimeout(O),je()});let A=null;function Ae(){je(),d.ui.fileTreeAutoRefresh&&(A=setInterval(()=>{document.hidden||d.currentDirectory&&(E.value.trim()||j())},Wt))}function je(){A&&=(clearInterval(A),null)}x(()=>d.currentDirectory,async()=>{if(Xt=!1,Ae(),await Ne(),F.value.some(e=>e.isDirty)){Xt=!0;return}F.value=[],I.value=null,nn(),await $t()}),x(()=>d.ui.fileTreeAutoRefresh,()=>{Ae()});async function Me(e,t=0){let n=await(await fetch(`/api/browse_directory?path=${encodeURIComponent(e)}`)).json();return n.success?n.items.map(e=>({...e,depth:t,expanded:!1,loading:!1,children:(e.type,void 0)})):[]}async function Ne(){let e=d.currentDirectory;if(e){le.value=!0;try{S.value=await Me(e,0)}finally{le.value=!1}}}function Pe(e,t=new Set){for(let n of e)n.type===`directory`&&n.expanded&&(t.add(n.path),n.children&&Pe(n.children,t));return t}function Fe(e,t=0){return(e||[]).map(e=>{let n={name:e.name,path:e.path,type:e.type,depth:t,expanded:!1,loading:!1};return n.type===`directory`&&Array.isArray(e.children)&&(n.children=Fe(e.children,t+1),n.expanded=!0),n})}async function Ie(e){let t=d.currentDirectory;if(!t)return null;try{let n=await(await fetch(`/api/browse_directory_tree`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:t,expand:e})})).json().catch(()=>null);return!n?.success||!Array.isArray(n.items)?null:Fe(n.items,0)}catch{return null}}function Le(e,t){let n=new Map(e.map(e=>[e.path,e])),r=e.length!==t.length;if(!r){for(let n=0;n<t.length;n++)if(e[n].path!==t[n].path){r=!0;break}}for(let e=0;e<t.length;e++){let i=t[e],a=n.get(i.path);a&&(t[e]=a,a.name!==i.name&&(a.name=i.name,r=!0),a.type===`directory`&&a.expanded&&Array.isArray(i.children)&&(Array.isArray(a.children)?Le(a.children,i.children)&&(a.children=i.children,r=!0):(a.children=i.children,r=!0)))}return r}async function j(e={}){if(!d.currentDirectory)return;let t=await Ie([...Pe(S.value)]);if(!t){e.notifyOnError&&g.error(D(`@EDITOR:刷新失败`));return}if(S.value.length===0){S.value=t;return}Le(S.value,t)&&(S.value=t)}async function M(e){if(e.type===`directory`){if(e.expanded)e.expanded=!1;else{if(!e.children){e.loading=!0;try{e.children=await Me(e.path,e.depth+1)}finally{e.loading=!1}}e.expanded=!0}}}function N(e){let t=[];for(let n of e)t.push(n),n.type===`directory`&&n.expanded&&n.children&&t.push(...N(n.children));return t}let ze=t(()=>ue.value.trim().toLowerCase());function Be(e,t){if(!t)return e;let n=[];for(let r of e){let e=r.children?Be(r.children,t):[],i=r.name.toLowerCase().includes(t);r.type===`directory`?(i||e.length>0)&&(r.expanded=!0,r.children!==void 0&&(r.children=e),n.push(r)):i&&n.push(r)}return n}let Ve=t(()=>Be(S.value,ze.value)),He=t(()=>ze.value.length>0&&Ve.value.length===0);function Ue(e){let t=ue.value.trim();if(!t)return[{text:e,hit:!1}];let n=e.toLowerCase(),r=t.toLowerCase(),i=[],a=0,o=n.indexOf(r,a);for(;o!==-1;)o>a&&i.push({text:e.slice(a,o),hit:!1}),i.push({text:e.slice(o,o+r.length),hit:!0}),a=o+r.length,o=n.indexOf(r,a);return a<e.length&&i.push({text:e.slice(a),hit:!1}),i}let We=_(null);function Ge(){let e=We.value;e&&(e.focus(),e.select())}function Ke(){E.value?(Oe(),We.value?.focus()):(We.value?.blur(),z.value?.focus())}let F=_([]),I=_(null),L=_(null);async function Gt(e){if(L.value=e,e.type!==`file`){M(e);return}let t=F.value.find(t=>t.path===e.path);if(console.log(`[debug-open-in-editor] EditorView openFile existing tab check:`,{path:e.path,found:!!t,tabsCount:F.value.length}),t){I.value=e.path,p(()=>an());return}let n=e.name.split(`.`).pop()||``;if(Hn.has(n.toLowerCase())){let t={path:e.path,name:e.name,content:``,originalContent:``,isDirty:!1,language:`plaintext`};F.value.push(t),I.value=e.path,J.value=!0;return}if(k(e.name)){let t={path:e.path,name:e.name,content:``,originalContent:``,isDirty:!1,language:`office`};F.value.push(t),I.value=e.path,Y.value=!1,J.value=!0;return}try{let t=await fetch(`/api/editor/file?path=${encodeURIComponent(e.path)}`),r=await t.json();if(console.log(`[debug-open-in-editor] EditorView fetch /api/editor/file response:`,{path:e.path,status:t.status,data:r}),!r.success){g.error(`${D(`@EDITOR:打开文件失败: `)}${r.error}`);return}let i=Re(n),a={path:e.path,name:e.name,content:r.content,originalContent:r.content,isDirty:!1,language:i};console.log(`[debug-open-in-editor] EditorView pushing tab:`,{path:a.path,name:a.name,contentLen:a.content.length,lang:a.language}),F.value.push(a),I.value=e.path,console.log(`[debug-open-in-editor] EditorView tabs after push:`,F.value.length,`activeTabPath=`,I.value)}catch(e){console.log(`[debug-open-in-editor] EditorView fetch threw:`,e),g.error(`${D(`@EDITOR:打开文件失败: `)}${e.message}`)}}x(()=>l.pendingFilePath,async e=>{if(console.log(`[debug-open-in-editor] EditorView watcher fired, filePath=`,e),!e)return;await p();let t=e.split(/[\\/]/).pop()||e;console.log(`[debug-open-in-editor] EditorView calling openFile, name=`,t,`path=`,e),await Gt({name:t,path:e,type:`file`,depth:0}),console.log(`[debug-open-in-editor] EditorView openFile returned`)},{immediate:!0});function Kt(e,t){t.stopPropagation();let n=F.value.findIndex(t=>t.path===e);n!==-1&&(!F.value[n].isDirty||confirm(D(`@EDITOR:文件未保存,确认关闭?`)))&&(F.value.splice(n,1),I.value===e&&(I.value=F.value[Math.min(n,F.value.length-1)]?.path??null))}let qt=()=>F.value.find(e=>e.path===I.value)??null,Jt=t(()=>({expandedDirs:[...Pe(S.value)],tabs:F.value.map(e=>e.path),activeTab:I.value})),Yt=!1,Xt=!1;function Zt(){Xt&&!Yt&&d.isUiLoaded&&d.saveEditorWorkspace(Jt.value)}x(Jt,()=>Zt());async function Qt(e){if(F.value.some(t=>t.path===e))return;let t=e.split(/[\\/]/).pop()||e,n=(t.split(`.`).pop()||``).toLowerCase();if(Hn.has(n)){F.value.push({path:e,name:t,content:``,originalContent:``,isDirty:!1,language:`plaintext`});return}if(k(t)){F.value.push({path:e,name:t,content:``,originalContent:``,isDirty:!1,language:`office`});return}try{let r=await(await fetch(`/api/editor/file?path=${encodeURIComponent(e)}`)).json();if(!r.success)return;let i=B.get(e);i&&!i.isDisposed()&&z.value?.getModel()!==i&&(i.dispose(),B.delete(e)),F.value.push({path:e,name:t,content:r.content,originalContent:r.content,isDirty:!1,language:Re(n)})}catch{}}async function $t(){try{for(let e=0;e<100&&!d.isUiLoaded;e++)await new Promise(e=>setTimeout(e,50));if(!d.isUiLoaded)return;H.value=d.ui.editorSidebarWidth;let e=d.getEditorWorkspace();if(!e)return;Yt=!0;try{if(e.expandedDirs.length>0){let t=await Ie(e.expandedDirs);t&&(S.value=t)}for(let t of e.tabs)await Qt(t);if(!l.pendingFilePath&&e.activeTab&&F.value.some(t=>t.path===e.activeTab)){I.value=e.activeTab;let t=qt(),n=(t?.name.split(`.`).pop()||``).toLowerCase();t&&(Hn.has(n)||k(t.name))&&(J.value=!0)}}finally{Yt=!1}}finally{Xt=!0,Zt()}}let en=_(null),z=ce(null),B=new Map;function tn(e){let t=B.get(e.path);return(!t||t.isDisposed())&&(t=Te.createModel(e.content,e.language,Ce.file(e.path)),B.set(e.path,t)),t}function nn(){z.value?.setModel(null);for(let e of B.values())e.isDisposed()||e.dispose();B.clear()}function rn(){if(!en.value)return;let e=document.documentElement.getAttribute(`data-theme`)===`dark`;z.value=Te.create(en.value,{theme:e?`vs-dark`:`vs`,fontSize:13,lineHeight:20,fontFamily:`'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace`,minimap:{enabled:!0},scrollBeyondLastLine:!1,renderWhitespace:`selection`,automaticLayout:!0,tabSize:2,wordWrap:`off`,smoothScrolling:!0,cursorBlinking:`smooth`,padding:{top:8,bottom:8},editContext:!1}),z.value.onDidChangeModelContent(()=>{let e=qt();if(!e)return;let t=z.value.getValue();e.content=t,e.isDirty=t!==e.originalContent}),z.value.onDidBlurEditorText(()=>{d.ui.editorAutoSave&&qt()?.isDirty&&cn(!1),requestAnimationFrame(()=>{if(!V.value||V.value.offsetParent===null)return;let e=document.activeElement;e&&(e.tagName===`INPUT`||e.tagName===`TEXTAREA`||e.isContentEditable||e.classList?.contains(`native-edit-context`)||e.classList?.contains(`monaco-editor`))||an()})})}x(I,e=>{if(!z.value||!e)return;let t=F.value.find(t=>t.path===e);if(!t)return;let n=tn(t);z.value.setModel(n),p(()=>an())});function an(){if(!z.value)return;z.value.focus();let e=document.querySelector(`.monaco-editor .native-edit-context`);e&&document.activeElement!==e&&requestAnimationFrame(()=>e.focus?.())}x(()=>F.value.filter(e=>e.isDirty).length,e=>{ae.setDirtyCount(e)},{immediate:!0}),s(()=>ae.setDirtyCount(0)),De(()=>{let e=document.documentElement.getAttribute(`data-theme`)===`dark`;Te.setTheme(e?`vs-dark`:`vs`)});let on=null;function sn(){if(on||!V.value)return;let e=[V.value],t=V.value.parentElement;for(;t;){if(t.classList.contains(`view-pane`)||t.classList.contains(`editor-pane`)){e.push(t);break}t=t.parentElement}on=new MutationObserver(()=>{V.value&&V.value.offsetParent!==null&&I.value&&z.value&&requestAnimationFrame(()=>{let e=document.activeElement;e&&(e.tagName===`INPUT`||e.tagName===`TEXTAREA`||e.isContentEditable||e.classList?.contains(`native-edit-context`)||e.classList?.contains(`monaco-editor`))||an()})});let n=on;e.forEach(e=>n.observe(e,{attributes:!0,attributeFilter:[`style`,`class`,`hidden`]}))}o(async()=>{rn(),await Ne(),await $t(),sn(),Ae(),I.value&&p(()=>an())}),s(()=>{on?.disconnect(),on=null,z.value?.dispose(),B.forEach(e=>e.dispose()),B.clear()});async function cn(e=!1){let t=qt();if(t)try{let n=await(await fetch(`/api/editor/file`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:t.path,content:t.content})})).json();if(!n.success){g.error(`${D(`@EDITOR:保存失败: `)}${n.error}`);return}t.originalContent=t.content,t.isDirty=!1,e||g.success(D(`@EDITOR:已保存`))}catch(e){g.error(`${D(`@EDITOR:保存失败: `)}${e.message}`)}}function ln(e){let t=e.ctrlKey||e.metaKey;if(t&&e.key.toLowerCase()===`f`){e.preventDefault(),Ge();return}t&&e.key===`s`&&(e.preventDefault(),cn())}o(()=>window.addEventListener(`keydown`,ln)),s(()=>window.removeEventListener(`keydown`,ln));let V=_(null),H=_(d.ui.editorSidebarWidth),un=!1,dn=0,fn=0;function pn(e){un=!0,dn=e.clientX,fn=H.value,document.addEventListener(`mousemove`,mn),document.addEventListener(`mouseup`,hn),e.preventDefault()}function mn(e){if(!un)return;let t=e.clientX-dn;H.value=Math.max(140,Math.min(400,fn+t))}function hn(){un=!1,document.removeEventListener(`mousemove`,mn),document.removeEventListener(`mouseup`,hn),H.value!==d.ui.editorSidebarWidth&&d.setEditorSidebarWidth(H.value)}function gn(e){return e.type===`directory`?pe(e.name):me(e.name)}let U=_(null),W=_(null),G=_(null),_n=_(null);function vn(){let e=L.value;return e?e.type===`directory`?{parentPath:e.path,afterNode:e,depth:e.depth+1}:{parentPath:e.path.includes(`/`)||e.path.includes(`\\`)?e.path.replace(/[\\/][^\\/]+$/,``):d.currentDirectory??``,afterNode:e,depth:e.depth}:{parentPath:d.currentDirectory??``,afterNode:null,depth:0}}async function yn(){let e=vn();L.value?.type===`directory`&&!L.value.expanded&&await M(L.value),U.value={...e,kind:`file`,value:``},await p(),G.value?.focus()}async function bn(){let e=vn();L.value?.type===`directory`&&!L.value.expanded&&await M(L.value),U.value={...e,kind:`directory`,value:``},await p(),G.value?.focus()}function xn(){U.value=null}async function Sn(){let e=U.value;if(!e||!e.value.trim()){U.value=null;return}let t=e.value.trim(),n=e.parentPath.replace(/[/\\]$/,``)+`/`+t;if(e.kind===`file`){let e=await(await fetch(`/api/editor/file`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:n})})).json();if(!e.success){g.error(e.error);return}g.success(D(`@EDITOR:创建成功`))}else{let e=await(await fetch(`/api/editor/directory`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:n})})).json();if(!e.success){g.error(e.error);return}g.success(D(`@EDITOR:创建成功`))}U.value=null,await j()}function Cn(e){e.key===`Enter`&&(e.preventDefault(),Sn()),e.key===`Escape`&&(e.preventDefault(),xn())}let K=_(null),wn=_(null);function Tn(e,t){e.preventDefault(),K.value={x:e.clientX,y:e.clientY,node:t}}function q(){K.value=null}async function En(){let e=K.value?.node;q(),e&&(L.value=e),e?.type===`directory`&&!e.expanded&&await M(e);let t=vn();U.value={...t,kind:`file`,value:``},await p(),G.value?.focus()}async function Dn(){let e=K.value?.node;q(),e&&(L.value=e),e?.type===`directory`&&!e.expanded&&await M(e);let t=vn();U.value={...t,kind:`directory`,value:``},await p(),G.value?.focus()}async function On(){let e=K.value?.node;q(),e&&(W.value={node:e,value:e.name},await p(),_n.value?.focus(),_n.value?.select())}async function kn(){let e=W.value;if(!e||!e.value.trim()||e.value.trim()===e.node.name){W.value=null;return}let t=e.value.trim(),n=e.node.path.replace(/[\\/][^\\/]+$/,``).replace(/[/\\]$/,``)+`/`+t,r=await(await fetch(`/api/editor/rename`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({oldPath:e.node.path,newPath:n})})).json();if(!r.success){g.error(r.error);return}let i=F.value.find(t=>t.path===e.node.path);i&&(i.path=n,i.name=t,I.value===e.node.path&&(I.value=n)),W.value=null,await j()}function An(e){e.key===`Enter`&&(e.preventDefault(),kn()),e.key===`Escape`&&(e.preventDefault(),W.value=null)}async function jn(){let e=K.value?.node;if(q(),!e)return;let t=e.type===`directory`?D(`@EDITOR:文件夹`):D(`@EDITOR:文件`);if(!confirm(`${D(`@EDITOR:确认删除`)} ${t} "${e.name}"?`))return;let n=await(await fetch(`/api/editor/entry?path=${encodeURIComponent(e.path)}`,{method:`DELETE`})).json();if(!n.success){g.error(n.error);return}let r=F.value.findIndex(t=>t.path===e.path);r!==-1&&(F.value.splice(r,1),I.value===e.path&&(I.value=F.value[Math.max(0,r-1)]?.path??null)),g.success(D(`@EDITOR:已删除`)),await j()}async function Mn(){let e=K.value?.node;if(q(),e)try{let t=await(await fetch(`/api/editor/reveal`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e.path})})).json();t.success||g.error(t.error)}catch(e){g.error(e?.message||String(e))}}function Nn(e){let t=d.currentDirectory;if(!t)return e;let n=e=>e.replace(/\\/g,`/`).replace(/\/+$/,``),r=n(t),i=n(e);return i===r?`.`:i.startsWith(r+`/`)?i.slice(r.length+1):i}async function Pn(e){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}async function Fn(){let e=K.value?.node;q(),e&&(await Pn(e.path)?g.success(D(`@EDITOR:已复制到剪贴板`)):g.error(D(`@EDITOR:复制失败`)))}async function In(){let e=K.value?.node;q(),e&&(await Pn(Nn(e.path))?g.success(D(`@EDITOR:已复制到剪贴板`)):g.error(D(`@EDITOR:复制失败`)))}async function Ln(){let e=K.value?.node;if(q(),e)try{let t=await(await fetch(`/api/editor/open-in-vscode`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e.path})})).json();t.success||g.error(t.error||D(`@EDITOR:VSCode 未安装`))}catch(e){g.error(e?.message||String(e))}}let Rn=new Set([`html`,`htm`]),zn=t(()=>{let e=K.value?.node;if(!e||e.type!==`file`)return!1;let t=e.name.slice(e.name.lastIndexOf(`.`)+1).toLowerCase();return Rn.has(t)});async function Bn(){let e=K.value?.node;if(q(),e)try{let t=await(await fetch(`/api/editor/open-in-browser`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e.path})})).json();t.success||g.error(t.error||D(`@EDITOR:浏览器打开失败`))}catch(e){g.error(e?.message||String(e))}}o(()=>document.addEventListener(`click`,q)),s(()=>document.removeEventListener(`click`,q));let Vn=new Set([`md`,`html`,`htm`,`svg`]),Hn=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`ico`,`bmp`]),J=_(!1),Y=_(!1),X=_(!1),Un=_(!1),Wn=_(0),Z=t(()=>F.value.find(e=>e.path===I.value)??null),Gn=t(()=>Z.value?.language===`plaintext`&&Z.value?.content===``),Kn=t(()=>Z.value?.language===`office`),Q=t(()=>(Z.value?.name??``).split(`.`).pop()?.toLowerCase()??``),qn=t(()=>Vn.has(Q.value)||Hn.has(Q.value)||k(Q.value)),Jn=t(()=>((Z.value?.content??``).match(/^#{1,6}\s+/gm)||[]).length),$=t(()=>Q.value===`md`&&Jn.value>0);x(I,()=>{J.value&&!qn.value&&(J.value=!1),Y.value&&!$.value&&(Y.value=!1)});function Yn(){qn.value&&(J.value||(Y.value=!1,X.value=!1),J.value=!J.value)}function Xn(){$.value&&(Y.value||(J.value=!1,X.value=!1),Y.value=!Y.value)}function Zn(){X.value||(J.value=!1,Y.value=!1),X.value=!X.value,Un.value=!0}let Qn=t(()=>{let e=Z.value;if(!e)return``;let t=Q.value,n=document.documentElement.getAttribute(`data-theme`)===`light`?`#ffffff`:`#0d1117`;return t===`html`||t===`htm`?_e(e.content):t===`svg`?`<!DOCTYPE html><html><head><meta charset="utf-8"><style>html,body{margin:0;padding:0;background:${n};display:flex;align-items:center;justify-content:center;min-height:100vh;}svg{max-width:100%;max-height:90vh;}</style></head><body>${e.content}</body></html>`:``}),$n=!1,er=0,tr=0;function nr(e){$n=!0,er=e.clientX,tr=Wn.value,document.addEventListener(`mousemove`,rr),document.addEventListener(`mouseup`,ir),e.preventDefault()}function rr(e){if(!$n)return;let t=e.clientX-er;Wn.value=Math.max(200,Math.min(900,tr+t))}function ir(){$n=!1,document.removeEventListener(`mousemove`,rr),document.removeEventListener(`mouseup`,ir)}return(t,o)=>(m(),n(T,null,[w(`div`,{class:`editor-view`,ref_key:`containerRef`,ref:V},[w(`div`,{class:`editor-sidebar`,style:h({width:H.value+`px`})},[w(`div`,R,[w(`span`,Je,u(i(D)(`@EDITOR:资源管理器`)),1),w(`div`,Ye,[c(i(a),{content:i(D)(`@EDITOR:新建文件`),placement:`bottom`,"show-after":300},{default:re(()=>[w(`button`,{class:`sidebar-action-btn`,onClick:yn},[...o[11]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`}),w(`polyline`,{points:`14 2 14 8 20 8`}),w(`line`,{x1:`12`,y1:`13`,x2:`12`,y2:`19`}),w(`line`,{x1:`9`,y1:`16`,x2:`15`,y2:`16`})],-1)]])]),_:1},8,[`content`]),c(i(a),{content:i(D)(`@EDITOR:新建文件夹`),placement:`bottom`,"show-after":300},{default:re(()=>[w(`button`,{class:`sidebar-action-btn`,onClick:bn},[...o[12]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`}),w(`line`,{x1:`12`,y1:`11`,x2:`12`,y2:`17`}),w(`line`,{x1:`9`,y1:`14`,x2:`15`,y2:`14`})],-1)]])]),_:1},8,[`content`]),c(i(a),{content:i(D)(`@EDITOR:刷新`),placement:`bottom`,"show-after":300},{default:re(()=>[w(`button`,{class:`sidebar-action-btn`,onClick:o[0]||=e=>j({notifyOnError:!0})},[...o[13]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`polyline`,{points:`1 4 1 10 7 10`}),w(`polyline`,{points:`23 20 23 14 17 14`}),w(`path`,{d:`M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15`})],-1)]])]),_:1},8,[`content`])])]),w(`div`,Xe,[o[15]||=w(`svg`,{class:`sidebar-search-icon`,viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[w(`circle`,{cx:`11`,cy:`11`,r:`7`}),w(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})],-1),b(w(`input`,{ref_key:`searchInputRef`,ref:We,"onUpdate:modelValue":o[1]||=e=>E.value=e,type:`text`,class:`sidebar-search-input`,placeholder:i(D)(`@EDITOR:搜索文件...`),title:i(D)(`@EDITOR:搜索文件...`),spellcheck:`false`,autocomplete:`off`,onKeydown:ne(Ke,[`escape`])},null,40,Ze),[[v,E.value]]),E.value?(m(),n(`button`,{key:0,class:`sidebar-search-clear`,title:i(D)(`@EDITOR:清除搜索`),"aria-label":i(D)(`@EDITOR:清除搜索`),onClick:Oe},[...o[14]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`12`,height:`12`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[w(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),w(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,Qe)):r(``,!0)]),le.value?(m(),n(`div`,bt,[...o[24]||=[w(`span`,{class:`spin-icon`},null,-1)]])):(m(),n(`div`,$e,[(m(!0),n(T,null,te(N(Ve.value),e=>(m(),n(T,{key:e.path},[W.value&&W.value.node.path===e.path?(m(),n(`div`,{key:0,class:`tree-node tree-inline-input-row`,style:h({paddingLeft:12+e.depth*14+`px`})},[e.type===`directory`?(m(),n(`span`,{key:0,class:C([`tree-arrow`,{expanded:e.expanded}])},[...o[16]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`polyline`,{points:`9 18 15 12 9 6`})],-1)]],2)):(m(),n(`span`,et)),(m(),n(`svg`,tt,[w(`use`,{"xlink:href":`#${gn(e)}`},null,8,nt)])),b(w(`input`,{ref_for:!0,ref_key:`renameInputRef`,ref:_n,"onUpdate:modelValue":o[2]||=e=>W.value.value=e,onKeydown:An,onBlur:kn,onClick:o[3]||=oe(()=>{},[`stop`])},null,544),[[v,W.value.value]])],4)):(m(),n(`div`,{key:1,class:C([`tree-node`,{"tree-node--dir":e.type===`directory`,"tree-node--file":e.type===`file`,"tree-node--active":I.value===e.path,"tree-node--selected":L.value?.path===e.path&&I.value!==e.path}]),style:h({paddingLeft:12+e.depth*14+`px`}),onClick:t=>Gt(e),onContextmenu:t=>Tn(t,e)},[e.type===`directory`?(m(),n(`span`,{key:0,class:C([`tree-arrow`,{expanded:e.expanded}])},[...o[17]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`10`,height:`10`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`polyline`,{points:`9 18 15 12 9 6`})],-1)]],2)):(m(),n(`span`,it)),e.type===`directory`?(m(),n(`svg`,at,[w(`use`,{"xlink:href":`#${gn(e)}`},null,8,ot)])):(m(),n(`svg`,st,[w(`use`,{"xlink:href":`#${gn(e)}`},null,8,ct)])),w(`span`,{class:`tree-name`,title:e.path},[(m(!0),n(T,null,te(Ue(e.name),(e,t)=>(m(),n(T,{key:t},[e.hit?(m(),n(`span`,ut,u(e.text),1)):(m(),n(T,{key:1},[y(u(e.text),1)],64))],64))),128))],8,lt),e.loading?(m(),n(`span`,dt)):r(``,!0)],46,rt)),U.value&&U.value.afterNode?.path===e.path?(m(),n(`div`,{key:2,class:`tree-node tree-inline-input-row`,style:h({paddingLeft:12+U.value.depth*14+`px`})},[o[20]||=w(`span`,{class:`tree-arrow-spacer`},null,-1),U.value.kind===`directory`?(m(),n(`svg`,ft,[...o[18]||=[w(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`},null,-1)]])):(m(),n(`svg`,pt,[...o[19]||=[w(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),w(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),b(w(`input`,{ref_for:!0,ref_key:`inlineInputRef`,ref:G,class:`tree-inline-input`,"onUpdate:modelValue":o[4]||=e=>U.value.value=e,placeholder:U.value.kind===`file`?i(D)(`@EDITOR:输入文件名`):i(D)(`@EDITOR:输入文件夹名`),onKeydown:Cn,onBlur:xn,onClick:o[5]||=oe(()=>{},[`stop`])},null,40,mt),[[v,U.value.value]])],4)):r(``,!0)],64))),128)),U.value&&U.value.afterNode===null?(m(),n(`div`,ht,[o[23]||=w(`span`,{class:`tree-arrow-spacer`},null,-1),U.value.kind===`directory`?(m(),n(`svg`,gt,[...o[21]||=[w(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`},null,-1)]])):(m(),n(`svg`,_t,[...o[22]||=[w(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),w(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),b(w(`input`,{ref_key:`inlineInputRef`,ref:G,class:`tree-inline-input`,"onUpdate:modelValue":o[6]||=e=>U.value.value=e,placeholder:U.value.kind===`file`?i(D)(`@EDITOR:输入文件名`):i(D)(`@EDITOR:输入文件夹名`),onKeydown:Cn,onBlur:xn,onClick:o[7]||=oe(()=>{},[`stop`])},null,40,vt),[[v,U.value.value]])])):r(``,!0),!U.value&&(He.value||S.value.length===0)?(m(),n(`div`,yt,u(He.value?i(D)(`@EDITOR:未找到匹配文件`):i(D)(`@EDITOR:暂无文件`)),1)):r(``,!0)]))],4),w(`div`,{class:`editor-resizer`,onMousedown:pn},null,32),w(`div`,xt,[F.value.length>0?(m(),n(`div`,St,[(m(!0),n(T,null,te(F.value,e=>(m(),n(`div`,{key:e.path,class:C([`editor-tab`,{active:I.value===e.path,dirty:e.isDirty}]),onClick:t=>I.value=e.path,title:e.path},[w(`span`,wt,u(e.name),1),e.isDirty?(m(),n(`span`,Tt)):r(``,!0),w(`button`,{class:`tab-close`,onClick:t=>Kt(e.path,t)},[...o[25]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`12`,height:`12`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[w(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),w(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,Et)],10,Ct))),128)),o[29]||=w(`div`,{class:`editor-tabs-spacer`},null,-1),qn.value?(m(),n(`button`,{key:0,class:C([`preview-toggle-btn`,{active:J.value}]),title:J.value?i(D)(`@EDITOR:关闭预览`):i(D)(`@EDITOR:打开预览`),onClick:Yn},[o[26]||=w(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z`}),w(`circle`,{cx:`12`,cy:`12`,r:`3`})],-1),w(`span`,null,u(i(D)(`@EDITOR:预览`)),1)],10,Dt)):r(``,!0),$.value?(m(),n(`button`,{key:1,class:C([`preview-toggle-btn mindmap-toggle-btn`,{active:Y.value,disabled:!$.value}]),disabled:!$.value,title:$.value?Y.value?i(D)(`@EDITOR:关闭思维导图`):i(D)(`@EDITOR:打开思维导图`):i(D)(`@EDITOR:需要至少一个 # 标题`),onClick:Xn},[o[27]||=e(`<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-v-c9da401a><circle cx="12" cy="12" r="2" data-v-c9da401a></circle><circle cx="5" cy="6" r="1.6" data-v-c9da401a></circle><circle cx="19" cy="6" r="1.6" data-v-c9da401a></circle><circle cx="5" cy="18" r="1.6" data-v-c9da401a></circle><circle cx="19" cy="18" r="1.6" data-v-c9da401a></circle><line x1="11" y1="11" x2="6.4" y2="7" data-v-c9da401a></line><line x1="13" y1="11" x2="17.6" y2="7" data-v-c9da401a></line><line x1="11" y1="13" x2="6.4" y2="17" data-v-c9da401a></line><line x1="13" y1="13" x2="17.6" y2="17" data-v-c9da401a></line></svg>`,1),w(`span`,null,u(i(D)(`@EDITOR:思维导图`)),1)],10,Ot)):r(``,!0),w(`button`,{class:C([`preview-toggle-btn agent-toggle-btn`,{active:X.value}]),title:X.value?i(D)(`@EDITOR:关闭 g ai 对话`):i(D)(`@EDITOR:打开 g ai 对话`),onClick:Zn},[o[28]||=w(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9z`}),w(`path`,{d:`M18 16.5l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9z`})],-1),w(`span`,null,u(i(D)(`@EDITOR:g ai 对话`)),1)],10,kt)])):r(``,!0),F.value.length===0?(m(),n(`div`,At,[(m(),n(`svg`,jt,[...o[30]||=[w(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`},null,-1),w(`polyline`,{points:`14 2 14 8 20 8`},null,-1)]])),w(`p`,null,u(i(D)(`@EDITOR:从左侧选择文件打开`)),1),w(`p`,Mt,u(i(D)(`@EDITOR:Ctrl+S 保存`)),1)])):r(``,!0),w(`div`,Nt,[w(`div`,{class:C([`monaco-container`,{hidden:F.value.length===0||Gn.value||Kn.value}]),ref_key:`editorContainerRef`,ref:en},null,2),Gn.value&&F.value.length>0&&!J.value&&!Y.value?(m(),n(`div`,Pt,[(m(),n(`svg`,Ft,[...o[31]||=[w(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`},null,-1),w(`circle`,{cx:`9`,cy:`9`,r:`2`},null,-1),w(`path`,{d:`m21 15-5-5L5 21`},null,-1)]])),w(`p`,It,u(Z.value?.name),1),w(`p`,Lt,u(i(D)(`@EDITOR:这是图片文件,已在右侧预览面板中打开`)),1)])):r(``,!0),(J.value||Y.value||X.value)&&F.value.length>0?(m(),n(`div`,{key:1,class:`preview-resizer`,onMousedown:nr},null,32)):r(``,!0),Un.value?b((m(),f(qe,{key:2,active:X.value&&F.value.length>0,"active-file-path":I.value,"active-file-name":Z.value?.name??``,style:h({flexBasis:Wn.value+`px`}),onClose:o[8]||=e=>X.value=!1},null,8,[`active`,`active-file-path`,`active-file-name`,`style`])),[[ie,X.value&&F.value.length>0]]):r(``,!0),(J.value||Y.value)&&F.value.length>0?(m(),n(`div`,{key:3,class:`preview-panel`,style:h({flexBasis:Wn.value+`px`})},[w(`div`,Rt,[w(`span`,zt,u(Y.value?i(D)(`@EDITOR:思维导图`):i(D)(`@EDITOR:预览`)),1),w(`span`,Bt,u(Q.value.toUpperCase()),1),o[33]||=w(`div`,{class:`preview-header-spacer`},null,-1),w(`button`,{class:`preview-close-btn`,title:Y.value?i(D)(`@EDITOR:关闭思维导图`):i(D)(`@EDITOR:关闭预览`),onClick:o[9]||=e=>Y.value?Y.value=!1:J.value=!1},[...o[32]||=[w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"stroke-linecap":`round`},[w(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),w(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})],-1)]],8,Vt)]),w(`div`,Ht,[Y.value&&Q.value===`md`&&Z.value?(m(),f(P,{key:0,content:Z.value.content,class:`preview-mindmap`},null,8,[`content`])):J.value&&Q.value===`md`&&Z.value?(m(),f(ge,{key:Z.value.path,content:Z.value.content,class:`preview-markdown`},null,8,[`content`])):J.value&&[`html`,`htm`,`svg`].includes(Q.value)?(m(),n(`iframe`,{key:2,class:`preview-iframe`,sandbox:i(ye),srcdoc:Qn.value},null,8,Ut)):J.value&&i(Hn).has(Q.value)&&Z.value?(m(),f(he,{key:3,"file-path":Z.value.path,"file-name":Z.value.name},null,8,[`file-path`,`file-name`])):J.value&&Kn.value&&Z.value?(m(),f(ve,{key:4,"file-path":Z.value.path},null,8,[`file-path`])):r(``,!0)])],4)):r(``,!0)])])],512),(m(),f(se,{to:`body`},[K.value?(m(),n(`div`,{key:0,ref_key:`ctxMenuRef`,ref:wn,class:`ctx-menu`,style:h({left:K.value.x+`px`,top:K.value.y+`px`}),onClick:o[10]||=oe(()=>{},[`stop`])},[w(`button`,{class:`ctx-menu-item`,onClick:En},[o[34]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z`}),w(`polyline`,{points:`14 2 14 8 20 8`}),w(`line`,{x1:`12`,y1:`13`,x2:`12`,y2:`19`}),w(`line`,{x1:`9`,y1:`16`,x2:`15`,y2:`16`})],-1),y(` `+u(i(D)(`@EDITOR:新建文件`)),1)]),w(`button`,{class:`ctx-menu-item`,onClick:Dn},[o[35]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z`}),w(`line`,{x1:`12`,y1:`11`,x2:`12`,y2:`17`}),w(`line`,{x1:`9`,y1:`14`,x2:`15`,y2:`14`})],-1),y(` `+u(i(D)(`@EDITOR:新建文件夹`)),1)]),o[42]||=w(`div`,{class:`ctx-menu-sep`},null,-1),w(`button`,{class:`ctx-menu-item`,onClick:Fn},[o[36]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`rect`,{x:`9`,y:`9`,width:`13`,height:`13`,rx:`2`,ry:`2`}),w(`path`,{d:`M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1`})],-1),y(` `+u(i(D)(`@EDITOR:复制绝对路径`)),1)]),w(`button`,{class:`ctx-menu-item`,onClick:In},[o[37]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71`}),w(`path`,{d:`M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71`})],-1),y(` `+u(i(D)(`@EDITOR:复制相对路径`)),1)]),o[43]||=w(`div`,{class:`ctx-menu-sep`},null,-1),zn.value?(m(),n(`button`,{key:0,class:`ctx-menu-item`,onClick:Bn},[o[38]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`circle`,{cx:`12`,cy:`12`,r:`9`}),w(`line`,{x1:`3`,y1:`12`,x2:`21`,y2:`12`}),w(`path`,{d:`M12 3a13 13 0 0 1 3.5 9 13 13 0 0 1-3.5 9 13 13 0 0 1-3.5-9A13 13 0 0 1 12 3z`})],-1),y(` `+u(i(D)(`@EDITOR:在浏览器中打开`)),1)])):r(``,!0),w(`button`,{class:`ctx-menu-item`,onClick:Mn},[o[39]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`}),w(`path`,{d:`M3 7v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2`})],-1),y(` `+u(i(D)(`@EDITOR:在资源管理器中打开`)),1)]),w(`button`,{class:`ctx-menu-item`,onClick:Ln},[c(de,{"icon-class":`vscode`,"class-name":`ctx-menu-icon`}),y(` `+u(i(D)(`@EDITOR:在 VSCode 中打开`)),1)]),w(`button`,{class:`ctx-menu-item`,onClick:On},[o[40]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`path`,{d:`M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`}),w(`path`,{d:`M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z`})],-1),y(` `+u(i(D)(`@EDITOR:重命名`)),1)]),w(`button`,{class:`ctx-menu-item ctx-menu-item--danger`,onClick:jn},[o[41]||=w(`svg`,{viewBox:`0 0 24 24`,width:`13`,height:`13`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[w(`polyline`,{points:`3 6 5 6 21 6`}),w(`path`,{d:`M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6`}),w(`path`,{d:`M10 11v6`}),w(`path`,{d:`M14 11v6`}),w(`path`,{d:`M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2`})],-1),y(` `+u(i(D)(`@EDITOR:删除`)),1)])],4)):r(``,!0)]))],64))}}),[[`__scopeId`,`data-v-c9da401a`]]);export{Gt as default};
@@ -1 +0,0 @@
1
- .dir-chat[data-v-d962bb7c]{height:min(420px,42vh);min-height:200px;margin-top:var(--spacing-sm);border-top:1px solid var(--border-color-light);padding-top:var(--spacing-sm);flex-direction:column;display:flex}.dir-chat__bar[data-v-d962bb7c]{margin-bottom:var(--spacing-xs);flex-shrink:0;justify-content:flex-end;display:flex}.dir-chat__new[data-v-d962bb7c]{height:22px;padding:0 var(--spacing-base);border:1px solid var(--border-color);border-radius:var(--radius-base);color:var(--text-tertiary);font:inherit;font-size:var(--font-size-sm);cursor:pointer;transition:color var(--transition-fast), border-color var(--transition-fast);background:0 0;align-items:center;gap:4px;line-height:1;display:inline-flex}.dir-chat__new[data-v-d962bb7c]:hover{color:var(--color-primary);border-color:var(--color-primary)}.dir-chat__new[data-v-d962bb7c]:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.dir-chat[data-v-d962bb7c]>.acu-chat{flex:1;min-width:0;min-height:0}.dir-chat--fill[data-v-d962bb7c]{flex:auto;height:auto;min-height:0}.dir-chat[data-v-d962bb7c] .acu-welcome{padding:var(--spacing-base);align-items:flex-start;overflow-y:auto}.dir-chat[data-v-d962bb7c] .acu-welcome-inner{margin-block:auto}.dir-chat[data-v-d962bb7c] .acu-welcome-logo{display:none}.dir-chat[data-v-d962bb7c] .acu-welcome-title{font-size:var(--font-size-lg);margin-bottom:var(--spacing-xs)}.dir-chat[data-v-d962bb7c] .acu-welcome-desc{font-size:var(--font-size-sm);margin-bottom:var(--spacing-base)}.dir-chat[data-v-d962bb7c] .acu-welcome-grid{gap:var(--spacing-sm)}