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.
- package/README.md +10 -4
- package/package.json +8 -1
- package/scripts/run-tests.cjs +5 -0
- package/src/cli/ai/agent.js +20 -0
- package/src/cli/ai/termui.js +73 -1
- package/src/cli/ai/termui.test.js +51 -0
- package/src/cli/ai/tools.js +114 -0
- package/src/cli/ai/tools.test.js +65 -1
- package/src/cli/ai/turn.js +3 -0
- package/src/config.js +34 -3
- package/src/memory/library.js +273 -0
- package/src/memory/library.test.js +187 -0
- package/src/memory/store.js +199 -0
- package/src/memory/store.test.js +137 -0
- package/src/memory/templates.js +113 -0
- package/src/paths.js +18 -0
- package/src/ui/public/assets/{AgentEngineSelector-DLJ8He83.js → AgentEngineSelector-BArUIELz.js} +1 -1
- package/src/ui/public/assets/{AgentView-DnN-vCMi.css → AgentView-B3LhhRsy.css} +1 -1
- package/src/ui/public/assets/{AgentView-CQ18nw02.js → AgentView-LpT8A9Fo.js} +1 -1
- package/src/ui/public/assets/{AppVersionBadge-1pyUzRer.js → AppVersionBadge-DNXQm_Si.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-DrsrZiWJ.js → BranchSelector-DZPTz5Ql.js} +1 -1
- package/src/ui/public/assets/{CommitForm-B5p-7P7m.js → CommitForm-6avyu1Kv.js} +1 -1
- package/src/ui/public/assets/{CommonDialog-BEm2cK1X.js → CommonDialog-CRXyMlp5.js} +1 -1
- package/src/ui/public/assets/EditorView-BIHL8I9g.js +1 -0
- package/src/ui/public/assets/{EditorView-C6HFYeEM.css → EditorView-DqxBkn6c.css} +1 -1
- package/src/ui/public/assets/{FileDiffViewer-CYxcLw10.js → FileDiffViewer-BEYcCYs5.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-DTmlBLXQ.js → FlowExecutionViewer-DKRHDqbG.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-Da_UmTRT.js → FlowOrchestrationWorkspace-BnCsF4z4.js} +1 -1
- package/src/ui/public/assets/{IconButton-BShiC2AP.js → IconButton-D4df4t9A.js} +1 -1
- package/src/ui/public/assets/{LogList-5M5JBhlB.js → LogList-DXqB4JJv.js} +1 -1
- package/src/ui/public/assets/{MindmapView-BUV_w14M.js → MindmapView-Ddc55wzp.js} +1 -1
- package/src/ui/public/assets/{MonitorView-D9N4QH5Y.js → MonitorView-DeERavq-.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DYYQ-O7P.js → ProjectStartupButton-DaLU4iS4.js} +1 -1
- package/src/ui/public/assets/{RecentDirectoriesChat-BtWa_HMY.js → RecentDirectoriesChat-DVtsf7lW.js} +1 -1
- package/src/ui/public/assets/RecentDirectoriesChat-o4xK1Koc.css +1 -0
- package/src/ui/public/assets/{RemoteManagerDialog-C4QIJK_F.js → RemoteManagerDialog-C3cfDsZi.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BmDh538v.js → RemoteRepoCard-D1Hso5Fq.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-Ceamya-N.js → SourceMapView-Dwn5wy1o.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-xtz4vvc9.js → SvgIcon-diKLLWK9.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-DhKTZ4EM.js → TemplateManager-D9gyZbHP.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-DfeCGlEO.js → UserInputNode-JNtVWcbE.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-CJCxYK-K.css +1 -0
- package/src/ui/public/assets/WorkbenchView-DxaAjZAA.js +6 -0
- package/src/ui/public/assets/_plugin-vue_export-helper-C7IvbEC3.js +19 -0
- package/src/ui/public/assets/agentConversations-nN-yDz8q.js +5 -0
- package/src/ui/public/assets/configStore-C-htWfWm.js +1 -0
- package/src/ui/public/assets/{gitStore-ByP9lpuT.js → gitStore-DYpd8vZK.js} +1 -1
- package/src/ui/public/assets/index-BZFKDSGv.css +1 -0
- package/src/ui/public/assets/index-eq1OUcdk.js +29 -0
- package/src/ui/public/assets/{previewSandbox-DSzZ_Rky.js → previewSandbox-Z707CZD9.js} +1 -1
- package/src/ui/public/assets/toolsStore-DFu4Alwg.js +1 -0
- package/src/ui/public/assets/vendor-BY5ZDlW1.css +1 -0
- package/src/ui/public/assets/{vendor-CyWsJd6S.js → vendor-BjomZKSS.js} +28 -120
- package/src/ui/public/index.html +14 -14
- package/src/ui/server/index.js +4 -0
- package/src/ui/server/routes/config.js +11 -2
- package/src/ui/server/routes/fileOpen.js +78 -13
- package/src/ui/server/routes/memory.js +125 -0
- package/src/ui/server/routes/workbench/agentChat.js +35 -3
- package/src/ui/server/routes/workbench/agentChatShared.test.js +49 -0
- package/src/ui/server/routes/workbench/executorModels.js +329 -0
- package/src/ui/server/routes/workbench/executorModels.test.js +326 -0
- package/src/ui/server/routes/workbench/index.js +45 -2
- package/src/ui/server/routes/workbench/jobActivity.js +6 -0
- package/src/ui/server/routes/workbench/memoryContext.js +125 -0
- package/src/ui/server/routes/workbench/memoryContext.test.js +79 -0
- package/src/ui/server/routes/workbench/orchestratorStore.js +4 -1
- package/src/ui/server/routes/workbench/runExternalTurn.js +6 -1
- package/src/ui/server/routes/workbench/taskRunner.js +48 -5
- package/src/ui/public/assets/EditorView-fuMrS9P7.js +0 -1
- package/src/ui/public/assets/RecentDirectoriesChat-vHT8jMxW.css +0 -1
- package/src/ui/public/assets/WorkbenchView-D9l3i4Qj.css +0 -1
- package/src/ui/public/assets/WorkbenchView-DX2epPD9.js +0 -6
- package/src/ui/public/assets/_plugin-vue_export-helper-C_bQVzeb.js +0 -19
- package/src/ui/public/assets/agentConversations-BUPj8vzH.js +0 -5
- package/src/ui/public/assets/configStore-DJH7OlB_.js +0 -1
- package/src/ui/public/assets/index-CFX8sK4w.js +0 -29
- package/src/ui/public/assets/index-DVJITdth.css +0 -1
- package/src/ui/public/assets/toolsStore-B49mCaQ_.js +0 -1
- package/src/ui/public/assets/vendor-BzMymUBi.css +0 -1
|
@@ -0,0 +1,199 @@
|
|
|
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
|
+
// 跨会话「记忆库」的读写层。
|
|
16
|
+
//
|
|
17
|
+
// ── 为什么是"索引 + 正文"两层 ─────────────────────────────────────────
|
|
18
|
+
// 用户原话点破的那件事:「总结要尽可能简洁,或者用索引的方式,不然上下文会太长」。
|
|
19
|
+
// 早期形态是单个 MEMORY.md 全文进上下文,越记越贵、越贵越没人看。所以:
|
|
20
|
+
//
|
|
21
|
+
// INDEX.md 每条 ≤100 字,只有它进 prompt(见 memoryContext.js)
|
|
22
|
+
// lessons/ 正文单条 ≤25 行,Agent 命中关键词才自己 read
|
|
23
|
+
// archive/ 冻结历史,永不读
|
|
24
|
+
//
|
|
25
|
+
// ── 谁在写 ───────────────────────────────────────────────────────────
|
|
26
|
+
// **Agent 自己**,不是服务端。服务端只在 prompt 里给一段指针,Agent 用它自己的
|
|
27
|
+
// 文件工具去读索引、按需读正文、收尾时追加 lesson。理由:
|
|
28
|
+
// · Agent 才知道"这次踩的坑"是什么,服务端只有一堆 IO 事件;
|
|
29
|
+
// · 少一次 LLM 调用(服务端代写就得再起一轮模型,还猜不准该记什么);
|
|
30
|
+
// · Agent 写完立刻能自己验证路径对不对。
|
|
31
|
+
// 服务端只保留两件事:目录不存在时铺种子、算 slug 告诉 Agent 写哪儿。
|
|
32
|
+
//
|
|
33
|
+
// ⚠️ 这个模块**只碰 MEMORY_DIR 下的路径**,一个字节都不写到用户工作区或
|
|
34
|
+
// 第三方工具的配置目录(~/.claude、~/.codex 等)。Agent 按 prompt 里的
|
|
35
|
+
// 指令去写那些文件时是它自己的选择,不是本产品替他改配置。
|
|
36
|
+
|
|
37
|
+
import fs from 'node:fs';
|
|
38
|
+
import fsp from 'node:fs/promises';
|
|
39
|
+
import path from 'node:path';
|
|
40
|
+
import { createHash } from 'node:crypto';
|
|
41
|
+
import { MEMORY_DIR, MEMORY_GLOBAL_FILE, MEMORY_INDEX_FILE, MEMORY_PROJECTS_DIR } from '../paths.js';
|
|
42
|
+
|
|
43
|
+
/** 种子模板:随包发布,首次运行时铺进 MEMORY_DIR(见 templates.js) */
|
|
44
|
+
import { MEMORY_SEED_FILES } from './templates.js';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 仓库绝对路径 → 记忆库里的项目 slug。
|
|
48
|
+
*
|
|
49
|
+
* 形状:`<可读部分>-<路径哈希 6 位>`
|
|
50
|
+
* `C:\workspace\github_workspace\xz333221\zen-gitsync`
|
|
51
|
+
* → `c-workspace-github_workspace-xz333221-zen-gitsync-3f2a1b`
|
|
52
|
+
*
|
|
53
|
+
* ⚠️ **哈希是必须的,不是装饰**(2026-09-29 实测踩到):
|
|
54
|
+
* 只做"小写 + 非 [a-z0-9_] 压成 -"的话,两个不同的中文路径会塌成同一个 slug ——
|
|
55
|
+
* `C:\中文\项目` 与 `C:\中文\别的` → 都是 `c-`
|
|
56
|
+
* 于是两个仓库共用一份 lessons,A 项目的教训会被当成 B 项目的写进 prompt。
|
|
57
|
+
* 这类污染**不报错、不可见**,是记忆系统最坏的一类失效。
|
|
58
|
+
*
|
|
59
|
+
* 哈希前先把 `\` 归一成 `/` 再算:`C:\a\b` 与 `C:/a/b` 是同一个仓库的两个写法,
|
|
60
|
+
* 归一后才能算出同一个 slug(否则同仓库会裂成两份记忆)。
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ 两条纪律(改这个函数前先读):
|
|
63
|
+
* 1. **纯函数,不碰文件系统** —— 单测要能直接钉住映射规则,不许夹带 stat。
|
|
64
|
+
* 2. **规则一改 = 全量历史记忆失联**(目录名变了)。所以要改必须同时带一份
|
|
65
|
+
* 重命名迁移;宁可永远不改规则也不要"顺手优化一下"。
|
|
66
|
+
*
|
|
67
|
+
* 保留 `_`(不下划线)是为了让 slug 读起来还认得出仓库名。
|
|
68
|
+
*/
|
|
69
|
+
export function projectSlug(repoPath) {
|
|
70
|
+
if (typeof repoPath !== 'string') return '';
|
|
71
|
+
const s = repoPath.trim();
|
|
72
|
+
if (!s) return '';
|
|
73
|
+
// 分隔符先归一,让同一个仓库的两种写法落到同一个 slug
|
|
74
|
+
const normalized = s.replace(/\\/g, '/').toLowerCase();
|
|
75
|
+
const readable = normalized
|
|
76
|
+
.replace(/[^a-z0-9_]+/g, '-')
|
|
77
|
+
.replace(/^-+|-+$/g, '');
|
|
78
|
+
// 哈希走归一后的路径:大小写与分隔符差异不该让同一个仓库裂成两份
|
|
79
|
+
const hash = createHash('sha1').update(normalized).digest('hex').slice(0, 6);
|
|
80
|
+
return `${readable || 'root'}-${hash}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** 某仓库的项目目录绝对路径(不保证存在 —— 存在性由 ensureProjectDir 负责) */
|
|
84
|
+
export function projectMemoryDir(repoPath) {
|
|
85
|
+
const slug = projectSlug(repoPath);
|
|
86
|
+
return slug ? path.join(MEMORY_PROJECTS_DIR, slug) : '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** 某仓库的项目索引绝对路径 */
|
|
90
|
+
export function projectIndexFile(repoPath) {
|
|
91
|
+
const dir = projectMemoryDir(repoPath);
|
|
92
|
+
return dir ? path.join(dir, 'INDEX.md') : '';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** 读一个文本文件;不存在返回 '',读失败也返回 ''(记忆读不到不该影响任何事) */
|
|
96
|
+
async function readTextOrEmpty(file) {
|
|
97
|
+
if (!file) return '';
|
|
98
|
+
try {
|
|
99
|
+
return await fsp.readFile(file, 'utf8');
|
|
100
|
+
} catch {
|
|
101
|
+
return '';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 幂等铺种子:目录不存在时把 MEMORY_SEED_FILES 写进去。
|
|
107
|
+
*
|
|
108
|
+
* **已存在的文件一律不覆盖** —— 用户(和 Agent)可能在里面写过东西,
|
|
109
|
+
* 每次启动都重铺等于把记忆洗回出厂设置。
|
|
110
|
+
*
|
|
111
|
+
* @returns {Promise<{created: string[], existed: number}>} created = 实际新建的文件名
|
|
112
|
+
*/
|
|
113
|
+
export async function ensureMemoryStore() {
|
|
114
|
+
await fsp.mkdir(MEMORY_DIR, { recursive: true });
|
|
115
|
+
await fsp.mkdir(path.join(MEMORY_DIR, 'archive'), { recursive: true });
|
|
116
|
+
|
|
117
|
+
let existed = 0;
|
|
118
|
+
const created = [];
|
|
119
|
+
for (const [rel, content] of Object.entries(MEMORY_SEED_FILES)) {
|
|
120
|
+
const target = path.join(MEMORY_DIR, ...rel.split('/'));
|
|
121
|
+
try {
|
|
122
|
+
await fsp.access(target);
|
|
123
|
+
existed += 1;
|
|
124
|
+
} catch {
|
|
125
|
+
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
126
|
+
await fsp.writeFile(target, content, 'utf8');
|
|
127
|
+
created.push(rel);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { created, existed };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 确保某仓库的项目目录存在,并返回它的索引路径。
|
|
135
|
+
* 索引不存在就铺一份**带 path 头**的骨架 —— 头里记着仓库绝对路径,
|
|
136
|
+
* 这样即便将来 slug 规则变了,人/Agent 还能从 INDEX.md 认回来。
|
|
137
|
+
*
|
|
138
|
+
* @returns {Promise<string>} 项目索引绝对路径;repoPath 非法时返回 ''
|
|
139
|
+
*/
|
|
140
|
+
export async function ensureProjectMemory(repoPath) {
|
|
141
|
+
const dir = projectMemoryDir(repoPath);
|
|
142
|
+
if (!dir) return '';
|
|
143
|
+
await fsp.mkdir(path.join(dir, 'lessons'), { recursive: true });
|
|
144
|
+
await fsp.mkdir(path.join(dir, 'archive'), { recursive: true });
|
|
145
|
+
|
|
146
|
+
const idx = path.join(dir, 'INDEX.md');
|
|
147
|
+
try {
|
|
148
|
+
await fsp.access(idx);
|
|
149
|
+
} catch {
|
|
150
|
+
await fsp.writeFile(idx, renderProjectIndexHeader(repoPath), 'utf8');
|
|
151
|
+
}
|
|
152
|
+
return idx;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** 新项目索引的头部。抽成函数是为了单测能直接断言首行格式。 */
|
|
156
|
+
export function renderProjectIndexHeader(repoPath) {
|
|
157
|
+
return [
|
|
158
|
+
'# 记忆索引 · 本项目',
|
|
159
|
+
'',
|
|
160
|
+
`> 仓库:\`${repoPath}\``,
|
|
161
|
+
'> 预算:≤40 条 / ≤6KB,**每条 ≤100 字**。**正文在 `lessons/`,只有命中本行才去 Read 对应文件。**',
|
|
162
|
+
'> 条目只写"先查什么 / 以后怎么做",不写"我做了什么"。单条 >25 行 → 那是文档,踢去项目 `docs/`。',
|
|
163
|
+
'',
|
|
164
|
+
'## 主题',
|
|
165
|
+
'',
|
|
166
|
+
].join('\n');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** 全局索引内容(可能为空串) */
|
|
170
|
+
export function readGlobalIndex() {
|
|
171
|
+
return readTextOrEmpty(MEMORY_INDEX_FILE);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** 跨项目经验正文(可能为空串) */
|
|
175
|
+
export function readGlobalMemory() {
|
|
176
|
+
return readTextOrEmpty(MEMORY_GLOBAL_FILE);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** 某仓库的项目索引内容(可能为空串) */
|
|
180
|
+
export function readProjectIndex(repoPath) {
|
|
181
|
+
return readTextOrEmpty(projectIndexFile(repoPath));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 记忆库是否"可用"。
|
|
186
|
+
*
|
|
187
|
+
* 判据刻意很弱:只要 MEMORY_DIR 存在就算可用。因为产品默认**不预填任何经验**,
|
|
188
|
+
* 一个只有种子文件、没有一条 lesson 的空库也该被指针照常指向 ——
|
|
189
|
+
* 否则第一次派发时 Agent 看不到"有个记忆库存在",永远写不出第一条。
|
|
190
|
+
* 首次写入的活由 ensureMemoryStore() 兜。
|
|
191
|
+
*/
|
|
192
|
+
export function memoryAvailable() {
|
|
193
|
+
try {
|
|
194
|
+
fs.accessSync(MEMORY_DIR);
|
|
195
|
+
return true;
|
|
196
|
+
} catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// store.js 的单测。
|
|
2
|
+
//
|
|
3
|
+
// ⚠️ paths.js 在**模块加载时**由 os.homedir() 求值,所以 USERPROFILE/HOME 必须
|
|
4
|
+
// 在 import 之前改掉(与 agentRoutes.test.js / agentMarketplace.test.js 同一套),
|
|
5
|
+
// 否则这个文件会往用户真实的 ~/.zen-gitsync/memory 里写。
|
|
6
|
+
// Windows 上 os.homedir() 还走 HOMEDRIVE/HOMEPATH 另一条路径,**必须一起删**。
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import fsp from 'node:fs/promises';
|
|
10
|
+
import { test, before, after } from 'node:test';
|
|
11
|
+
import assert from 'node:assert/strict';
|
|
12
|
+
|
|
13
|
+
const SANDBOX = await fsp.mkdtemp(path.join(os.tmpdir(), 'zen-memory-store-'));
|
|
14
|
+
for (const k of ['HOMEDRIVE', 'HOMEPATH']) delete process.env[k];
|
|
15
|
+
process.env.USERPROFILE = SANDBOX;
|
|
16
|
+
process.env.HOME = SANDBOX;
|
|
17
|
+
|
|
18
|
+
const { MEMORY_DIR, MEMORY_INDEX_FILE } = await import('../paths.js');
|
|
19
|
+
const {
|
|
20
|
+
projectSlug,
|
|
21
|
+
projectMemoryDir,
|
|
22
|
+
projectIndexFile,
|
|
23
|
+
ensureMemoryStore,
|
|
24
|
+
ensureProjectMemory,
|
|
25
|
+
renderProjectIndexHeader,
|
|
26
|
+
readGlobalIndex,
|
|
27
|
+
readProjectIndex,
|
|
28
|
+
memoryAvailable,
|
|
29
|
+
} = await import('./store.js');
|
|
30
|
+
const { MEMORY_SEED_FILES } = await import('./templates.js');
|
|
31
|
+
|
|
32
|
+
after(() => fsp.rm(SANDBOX, { recursive: true, force: true }));
|
|
33
|
+
|
|
34
|
+
test('projectSlug:Windows 与 POSIX 盘符都落进同一套形状', () => {
|
|
35
|
+
const a = projectSlug('C:\\workspace\\github_workspace\\xz333221\\zen-gitsync');
|
|
36
|
+
assert.match(a, /^c-workspace-github_workspace-xz333221-zen-gitsync-[0-9a-f]{6}$/, a);
|
|
37
|
+
assert.match(projectSlug('/home/u/proj'), /^home-u-proj-[0-9a-f]{6}$/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('projectSlug:同一仓库的两种写法(\\ 与 /)必须同一个 slug,否则同仓库裂成两份记忆', () => {
|
|
41
|
+
assert.equal(projectSlug('C:\\ws\\zen'), projectSlug('C:/ws/zen'));
|
|
42
|
+
assert.equal(projectSlug('C:\\WS\\Zen'), projectSlug('c:\\ws\\zen'));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('⚠️ projectSlug:全中文路径不能互相碰撞(否则记忆跨项目串味,且不报错)', () => {
|
|
46
|
+
const a = projectSlug('C:\\中文\\项目');
|
|
47
|
+
const b = projectSlug('C:\\中文\\别的');
|
|
48
|
+
const c = projectSlug('D:\\中文\\项目');
|
|
49
|
+
assert.notEqual(a, b, '不同目录不能撞');
|
|
50
|
+
assert.notEqual(a, c, '不同盘符不能撞');
|
|
51
|
+
// 退化也不能含路径分隔符 —— 那会顺着 join 逃出 projects/ 目录
|
|
52
|
+
for (const s of [a, b, c]) {
|
|
53
|
+
assert.ok(s.length > 0);
|
|
54
|
+
assert.ok(!s.includes('/') && !s.includes('\\'));
|
|
55
|
+
assert.ok(!s.includes('..'));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('projectSlug:非法入参返回空串而不是抛错(派发时不该因路径怪就炸)', () => {
|
|
60
|
+
assert.equal(projectSlug(''), '');
|
|
61
|
+
assert.equal(projectSlug(' '), '');
|
|
62
|
+
assert.equal(projectSlug(null), '');
|
|
63
|
+
assert.equal(projectSlug(undefined), '');
|
|
64
|
+
assert.equal(projectSlug(123), '');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('projectMemoryDir / projectIndexFile 必须落在 projects/ 之内', () => {
|
|
68
|
+
const dir = projectMemoryDir('C:\\a\\b');
|
|
69
|
+
assert.ok(dir.startsWith(path.join(MEMORY_DIR, 'projects')));
|
|
70
|
+
assert.ok(projectIndexFile('C:\\a\\b').startsWith(dir));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('ensureMemoryStore 铺出全部种子,且 created 报得出建了什么', async () => {
|
|
74
|
+
assert.equal(memoryAvailable(), false, '初始应不存在');
|
|
75
|
+
const { created } = await ensureMemoryStore();
|
|
76
|
+
assert.equal(memoryAvailable(), true);
|
|
77
|
+
for (const rel of Object.keys(MEMORY_SEED_FILES)) {
|
|
78
|
+
assert.ok(created.includes(rel), `${rel} 应报为新建`);
|
|
79
|
+
await fsp.access(path.join(MEMORY_DIR, ...rel.split('/')));
|
|
80
|
+
}
|
|
81
|
+
await fsp.access(path.join(MEMORY_DIR, 'archive'));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('⚠️ 二次调用不覆盖已存在的种子(否则每次启动都把用户写的记忆洗回出厂)', async () => {
|
|
85
|
+
const before = await fsp.readFile(MEMORY_INDEX_FILE, 'utf8');
|
|
86
|
+
await fsp.appendFile(MEMORY_INDEX_FILE, '\n- 用户自己写的一行\n', 'utf8');
|
|
87
|
+
const { created, existed } = await ensureMemoryStore();
|
|
88
|
+
assert.equal(created.length, 0, '不该有任何新建');
|
|
89
|
+
assert.equal(existed, Object.keys(MEMORY_SEED_FILES).length);
|
|
90
|
+
const after = await fsp.readFile(MEMORY_INDEX_FILE, 'utf8');
|
|
91
|
+
assert.ok(after.startsWith(before));
|
|
92
|
+
assert.ok(after.includes('用户自己写的一行'), '用户内容必须活下来');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('ensureProjectMemory 建目录 + 建带仓库路径头的索引', async () => {
|
|
96
|
+
const idx = await ensureProjectMemory('C:\\ws\\zen-gitsync');
|
|
97
|
+
assert.ok(idx);
|
|
98
|
+
await fsp.access(path.join(MEMORY_DIR, 'projects', projectSlug('C:\\ws\\zen-gitsync'), 'lessons'));
|
|
99
|
+
await fsp.access(path.join(MEMORY_DIR, 'projects', projectSlug('C:\\ws\\zen-gitsync'), 'archive'));
|
|
100
|
+
const text = await fsp.readFile(idx, 'utf8');
|
|
101
|
+
assert.ok(text.includes('C:\\ws\\zen-gitsync'), '头里必须记着仓库绝对路径(slug 规则变了还能认回来)');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('ensureProjectMemory 幂等:已存在的索引不被重写', async () => {
|
|
105
|
+
const idx = projectIndexFile('C:\\ws\\zen-gitsync');
|
|
106
|
+
await fsp.appendFile(idx, '\n- [手写条目](lessons/x.md) — 摘要\n', 'utf8');
|
|
107
|
+
await ensureProjectMemory('C:\\ws\\zen-gitsync');
|
|
108
|
+
const text = await fsp.readFile(idx, 'utf8');
|
|
109
|
+
assert.ok(text.includes('手写条目'), '重复调用不能吃掉已有条目');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('ensureProjectMemory 对非法路径返回空串而不是建出垃圾目录', async () => {
|
|
113
|
+
assert.equal(await ensureProjectMemory(''), '');
|
|
114
|
+
assert.equal(await ensureProjectMemory(null), '');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('renderProjectIndexHeader 把三条硬约束写进头里', () => {
|
|
118
|
+
const h = renderProjectIndexHeader('C:\\x');
|
|
119
|
+
assert.match(h, /≤40 条/);
|
|
120
|
+
assert.match(h, /只有命中本行才去 Read/);
|
|
121
|
+
assert.match(h, /不写"我做了什么"/);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('读取函数对不存在的文件返回空串,不抛错', async () => {
|
|
125
|
+
assert.equal(await readProjectIndex('C:\\never-existed-repo'), '');
|
|
126
|
+
assert.equal(typeof await readGlobalIndex(), 'string');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('种子文件本身要满足预算(它就是每台机器的初始索引)', () => {
|
|
130
|
+
for (const [rel, content] of Object.entries(MEMORY_SEED_FILES)) {
|
|
131
|
+
assert.ok(Buffer.byteLength(content, 'utf8') <= 6000, `${rel} 种子 ${Buffer.byteLength(content, 'utf8')}B 过大`);
|
|
132
|
+
}
|
|
133
|
+
// 规范里写死的三条预算,种子必须自洽
|
|
134
|
+
assert.match(MEMORY_SEED_FILES['INDEX.md'], /≤30 行/);
|
|
135
|
+
assert.match(MEMORY_SEED_FILES['GLOBAL.md'], /≤40 行/);
|
|
136
|
+
assert.match(MEMORY_SEED_FILES['RULES.md'], /≤25 行/);
|
|
137
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
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
|
+
// 记忆库种子文件。**键是相对 MEMORY_DIR 的路径**,值是首次运行时铺进去的内容。
|
|
16
|
+
//
|
|
17
|
+
// 为什么要"随包带种子"而不是"运行时拼字符串":
|
|
18
|
+
// · 种子本身要能被 review —— 它是每个用户都会看到的东西,写在代码里
|
|
19
|
+
// 散在几处 `if (!exists) write(...)` 里没人看得出全貌;
|
|
20
|
+
// · 文案改动走 i18n 之外的单测(内容断言)比散落拼接好维护;
|
|
21
|
+
// · 往后想加 RULES.md / 模板示例,只是多一个键。
|
|
22
|
+
//
|
|
23
|
+
// ⚠️ 铺种子的语义是 **only-if-missing**(见 store.js 的 ensureMemoryStore):
|
|
24
|
+
// 用户和 Agent 在这些文件里写的内容永远不会被重置。
|
|
25
|
+
//
|
|
26
|
+
// ⚠️ 这里**不预填任何一条经验**。空库是合法状态 —— 产品不能替用户编造
|
|
27
|
+
// "经验",只能把记账的目录和格式准备好。
|
|
28
|
+
|
|
29
|
+
/** @type {Record<string, string>} 相对 MEMORY_DIR 的路径 → 文件内容 */
|
|
30
|
+
export const MEMORY_SEED_FILES = {
|
|
31
|
+
'INDEX.md': [
|
|
32
|
+
'# 记忆索引 · 全局',
|
|
33
|
+
'',
|
|
34
|
+
'> **本文件是唯一默认进上下文的东西。** 正文一律懒加载。',
|
|
35
|
+
'> 预算:≤30 行。超了就把细节下沉到各项目 lessons/。',
|
|
36
|
+
'',
|
|
37
|
+
'## 项目',
|
|
38
|
+
'',
|
|
39
|
+
'_(还没有项目条目。派发第一个任务时会自动补上。)_',
|
|
40
|
+
'',
|
|
41
|
+
'## 全局',
|
|
42
|
+
'',
|
|
43
|
+
'- [跨项目经验](GLOBAL.md) — 本机环境事实 · 沙箱工具边界 · 通用坑',
|
|
44
|
+
'',
|
|
45
|
+
'## 约定',
|
|
46
|
+
'',
|
|
47
|
+
'- 条目只写"先查什么 / 以后怎么做",**不写"我做了什么"**(那是 commit message 的活)。',
|
|
48
|
+
'- 单条 lesson ≤25 行;超过说明它是文档不是记忆 → 写进项目 `docs/`。',
|
|
49
|
+
'- 项目索引 >40 条 或 30 天没整理 → 强制整理(同类合并 / 过时移 `archive/`)。',
|
|
50
|
+
'',
|
|
51
|
+
].join('\n'),
|
|
52
|
+
|
|
53
|
+
'GLOBAL.md': [
|
|
54
|
+
'# 跨项目经验(热档)',
|
|
55
|
+
'',
|
|
56
|
+
'> 预算:≤40 行 / ≤3KB。只收"跟具体仓库无关、换个项目照样成立"的结论。',
|
|
57
|
+
'> 项目特定的进 `projects/<slug>/INDEX.md`,别往这里塞。',
|
|
58
|
+
'',
|
|
59
|
+
'## 本机环境',
|
|
60
|
+
'',
|
|
61
|
+
'_(空。首次踩到"换台机器也成立"的坑时写这里。)_',
|
|
62
|
+
'',
|
|
63
|
+
'## 通用坑',
|
|
64
|
+
'',
|
|
65
|
+
'_(空。搜索命中被构建产物淹没、探针假绿、默认值测试假绿……这类先写这里。)_',
|
|
66
|
+
'',
|
|
67
|
+
].join('\n'),
|
|
68
|
+
|
|
69
|
+
'RULES.md': [
|
|
70
|
+
'# 记忆库规范(完整版)',
|
|
71
|
+
'',
|
|
72
|
+
'> 这是**权威版本**。派发任务时注入 Agent 的是精简版(见 routes/workbench/memoryContext.js),',
|
|
73
|
+
'> 两者口径一致;改规则先改这里。',
|
|
74
|
+
'',
|
|
75
|
+
'## 目录形状',
|
|
76
|
+
'',
|
|
77
|
+
'```',
|
|
78
|
+
'memory/',
|
|
79
|
+
'├── INDEX.md 全局索引 · 唯一默认进上下文的东西',
|
|
80
|
+
'├── GLOBAL.md 跨项目经验正文 · ≤40 行 · 按需读',
|
|
81
|
+
'├── RULES.md 本文件',
|
|
82
|
+
'└── projects/<slug>/',
|
|
83
|
+
' ├── INDEX.md 本项目索引 · ≤40 条 / 每条 ≤100 字',
|
|
84
|
+
' ├── lessons/<topic>.md 正文 · 单条 ≤25 行 · 命中才读',
|
|
85
|
+
' └── archive/ 冻结历史 · 永不读',
|
|
86
|
+
'```',
|
|
87
|
+
'',
|
|
88
|
+
'`<slug>` = 仓库绝对路径 → 小写 → 非 `[a-z0-9_]` 的连续串压成一个 `-`。',
|
|
89
|
+
'',
|
|
90
|
+
'## 召回(开工时)',
|
|
91
|
+
'',
|
|
92
|
+
'1. 读全局 `INDEX.md`',
|
|
93
|
+
'2. 当前仓库在「项目」段 → 读它的 `INDEX.md`,**到此为止**',
|
|
94
|
+
'3. 索引某条关键词与当前任务相关 → 才 Read 对应的 `lessons/<topic>.md`',
|
|
95
|
+
'4. 索引没命中但怀疑是通用坑 → 读 `GLOBAL.md`',
|
|
96
|
+
'',
|
|
97
|
+
'**不做**:不预加载全部 lessons、不读 `archive/`、不在没命中时硬读。',
|
|
98
|
+
'',
|
|
99
|
+
'## 捕获(收尾时)',
|
|
100
|
+
'',
|
|
101
|
+
'四问自检,**全为否就不写**:',
|
|
102
|
+
'',
|
|
103
|
+
'1. 本轮卡住 ≥3 分钟,或走了 A→取消→B→取消→C 的反复路径?',
|
|
104
|
+
'2. 用错工具 / 写错文件 / grep 命中被构建产物淹没 / 探针假绿?',
|
|
105
|
+
'3. 用户纠正过方向 / 用法 / 命名?',
|
|
106
|
+
'4. 发现"看似绕路但更快"或"反直觉但正确"且被验证的做法?',
|
|
107
|
+
'',
|
|
108
|
+
'- 写成"以后怎么做",不写"我做了什么"。',
|
|
109
|
+
'- 一个主题一个文件;同主题**追加/改写**,不新建近似重复的。',
|
|
110
|
+
'- 写完**必须**在对应 `INDEX.md` 补一行 —— 没索引的记忆等于不存在。',
|
|
111
|
+
'',
|
|
112
|
+
].join('\n'),
|
|
113
|
+
};
|
package/src/paths.js
CHANGED
|
@@ -88,6 +88,24 @@ export const AI_MCP_FILE = path.join(DATA_DIR, 'ai', 'mcp.json');
|
|
|
88
88
|
// 别人的 git 历史;同一台机器上多个 g ui 实例共用一份就够了。
|
|
89
89
|
export const AI_CONTEXT_DIR = path.join(DATA_DIR, 'ai-context');
|
|
90
90
|
|
|
91
|
+
// ── 跨会话「记忆库」(2026-09-29 新增) ─────────────────────────
|
|
92
|
+
// 每个项目的长期经验:索引进上下文、正文按需读。目录形状与 aiContext 同构
|
|
93
|
+
// (一份 INDEX + 若干分块),理由也一样 —— 让 Agent 只读它要的那一块。
|
|
94
|
+
//
|
|
95
|
+
// 为什么放 DATA_DIR 而不是项目里:同 aiContext,这是**本机派生数据**,
|
|
96
|
+
// 不该污染任何仓库、不该进别人的 git 历史。
|
|
97
|
+
//
|
|
98
|
+
// 写入方不是服务端而是**被派发的 Agent 自己**(它有文件工具):服务端只在
|
|
99
|
+
// prompt 里给一段指针(见 routes/workbench/memoryContext.js),Agent 读完索引
|
|
100
|
+
// 自己决定要不要读正文。服务端只负责"目录不存在时铺一份种子"。
|
|
101
|
+
export const MEMORY_DIR = path.join(DATA_DIR, 'memory');
|
|
102
|
+
// 全局索引:项目清单 + 跨项目主题词。**唯一默认进上下文的东西**
|
|
103
|
+
export const MEMORY_INDEX_FILE = path.join(MEMORY_DIR, 'INDEX.md');
|
|
104
|
+
// 跨项目经验正文(本机环境 / 通用坑)。≤40 行,按需读
|
|
105
|
+
export const MEMORY_GLOBAL_FILE = path.join(MEMORY_DIR, 'GLOBAL.md');
|
|
106
|
+
// 每仓库一个子目录,按 projects/<slug>/ 分,与 aiContext 的分块思路一致
|
|
107
|
+
export const MEMORY_PROJECTS_DIR = path.join(MEMORY_DIR, 'projects');
|
|
108
|
+
|
|
91
109
|
// ── 工作台 / 会话 / 缓存 ──────────────────────────────────────
|
|
92
110
|
export const WORKBENCH_IMAGES_DIR = path.join(DATA_DIR, 'workbench-images');
|
|
93
111
|
// 智能体对话的非图片附件:前端把字节传上来后落在这里,只把绝对路径给模型(见
|
package/src/ui/public/assets/{AgentEngineSelector-DLJ8He83.js → AgentEngineSelector-BArUIELz.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,C as t,Cn as n,Dn as r,En as i,Er as a,Jn as o,K as s,Kn as c,Mn as l,Pn as u,Pr as d,Qn as f,Qr as p,Rn as m,S as h,Tn as g,Un as _,Xn as v,br as y,cr as b,pr as x,q as S,qr as C,w,wn as T,yn as E}from"./element-plus-Bx3j6vzG.js";import{n as D,t as O}from"./_plugin-vue_export-helper-
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,C as t,Cn as n,Dn as r,En as i,Er as a,Jn as o,K as s,Kn as c,Mn as l,Pn as u,Pr as d,Qn as f,Qr as p,Rn as m,S as h,Tn as g,Un as _,Xn as v,br as y,cr as b,pr as x,q as S,qr as C,w,wn as T,yn as E}from"./element-plus-Bx3j6vzG.js";import{n as D,t as O}from"./_plugin-vue_export-helper-C7IvbEC3.js";import{t as k}from"./SvgIcon-diKLLWK9.js";import{t as A}from"./toolsStore-DFu4Alwg.js";import{a as j,m as M}from"./index-eq1OUcdk.js";import{c as N,d as P,l as F,u as I}from"./agentConversations-nN-yDz8q.js";m(),x();function L(e,t=680){let r=y(0),i=null;function a(){let t=e.value;return t?(r.value=t.clientWidth,typeof ResizeObserver>`u`||(i=new ResizeObserver(e=>{let t=e[0]?.contentRect?.width;typeof t==`number`&&(r.value=t)}),i.observe(t),!0)):!1}return o(()=>{a()||_(()=>a())}),c(()=>{i?.disconnect(),i=null}),{width:r,narrow:n(()=>r.value>0&&r.value<t)}}m(),x(),d();var R={class:`agent-engine`},z=[`disabled`,`title`,`aria-label`],B={class:`agent-engine__name`},V={class:`agent-engine__item`},H={class:`agent-engine__item-name`},U={key:3,class:`agent-engine__item-missing`},W=O(u({__name:`AgentEngineSelector`,props:{engine:{},locked:{type:Boolean}},emits:[`select`],setup(o,{emit:c}){let u=o,d=c,m=A(),_=n(()=>I(u.engine)),x=n(()=>({gai:!0,claude:m.claudeAvailable,opencode:m.opencodeAvailable,codex:m.codexAvailable})),O=y(!1),L=y(null);function W(e){if(!u.locked){if(!x.value[e]){if(!P(e))return;L.value=e,O.value=!0;return}d(`select`,e)}}return(n,c)=>(v(),r(`div`,R,[l(a(h),{trigger:`click`,onCommand:W},{dropdown:b(()=>[l(a(w),null,{default:b(()=>[(v(!0),r(E,null,f(a(N),n=>(v(),g(a(t),{key:n.id,command:n.id},{default:b(()=>[T(`span`,V,[a(P)(n.id)?(v(),g(j,{key:0,executor:n.id,class:`agent-engine__item-icon`},null,8,[`executor`])):(v(),g(k,{key:1,"icon-class":a(F),class:`agent-engine__item-icon`},null,8,[`icon-class`])),T(`span`,H,p(n.name),1),o.engine===n.id?(v(),g(a(s),{key:2,class:`agent-engine__item-check`},{default:b(()=>[l(a(e))]),_:1})):x.value[n.id]?i(``,!0):(v(),r(`span`,U,p(a(D)(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`]))),128))]),_:1})]),default:b(()=>[T(`button`,{type:`button`,class:C([`agent-engine__btn`,{"is-locked":o.locked}]),disabled:o.locked,title:o.locked?a(D)(`@AGENT:本会话的引擎已锁定;要换引擎请新建会话`):a(D)(`@AGENT:新建会话使用的引擎`),"aria-label":a(D)(`@AGENT:智能体引擎`)},[a(P)(o.engine)?(v(),g(j,{key:0,executor:o.engine,class:`agent-engine__icon`},null,8,[`executor`])):(v(),g(k,{key:1,"icon-class":a(F),class:`agent-engine__icon`},null,8,[`icon-class`])),T(`span`,B,p(_.value),1),l(a(s),{class:`agent-engine__caret`},{default:b(()=>[l(a(S))]),_:1})],10,z)]),_:1}),l(M,{modelValue:O.value,"onUpdate:modelValue":c[0]||=e=>O.value=e,tool:L.value},null,8,[`modelValue`,`tool`])]))}}),[[`__scopeId`,`data-v-81dfa007`]]);export{L as n,W as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.marketplace-panel[data-v-6788a7b1]{background:var(--bg-container);flex-direction:column;height:100%;min-height:0;display:flex}.mp-toolbar[data-v-6788a7b1]{flex-shrink:0;align-items:center;gap:12px;padding:12px 16px 8px;display:flex}.mp-search[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);max-width:420px;height:32px;transition:border-color var(--transition-fast) ease;flex:1;align-items:center;gap:6px;padding:0 10px;display:flex}.mp-search[data-v-6788a7b1]:focus-within{border-color:var(--color-primary)}.mp-search .mp-search-icon[data-v-6788a7b1]{color:var(--text-tertiary);flex-shrink:0}.mp-search .mp-search-input[data-v-6788a7b1]{color:var(--text-primary);font-size:var(--font-size-mid);background:0 0;border:none;outline:none;flex:1;font-family:inherit}.mp-search .mp-search-input[data-v-6788a7b1]::placeholder{color:var(--text-tertiary)}.mp-target[data-v-6788a7b1]{flex-shrink:0}.mp-refresh[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;transition:var(--transition-ui-fast);justify-content:center;align-items:center;display:flex}.mp-refresh[data-v-6788a7b1]:hover{color:var(--color-primary);border-color:var(--color-primary)}.mp-refresh.spinning svg[data-v-6788a7b1]{animation:.9s linear infinite mkt-spin-6788a7b1}@keyframes mkt-spin-6788a7b1{to{transform:rotate(360deg)}}.mp-toolbar-sub[data-v-6788a7b1]{flex-wrap:wrap;flex-shrink:0;align-items:center;gap:12px;padding:0 16px 10px;display:flex}.mp-target-hint[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-tertiary)}.mp-target-hint b[data-v-6788a7b1]{color:var(--color-primary);font-weight:600}.mp-source-filter[data-v-6788a7b1]{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.mp-chip[data-v-6788a7b1]{font-size:var(--font-size-sm);border:1px solid var(--border-color);border-radius:var(--radius-xl);color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;padding:2px 10px;font-family:inherit}.mp-chip[data-v-6788a7b1]:hover{color:var(--text-secondary);border-color:var(--text-tertiary)}.mp-chip.active[data-v-6788a7b1]{color:var(--color-primary);border-color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, transparent)}.mp-chip.clear[data-v-6788a7b1]{color:var(--text-tertiary);border-style:dashed}.mp-body[data-v-6788a7b1]{flex:1;min-height:0;padding:0 16px 20px;overflow-y:auto}.mp-group[data-v-6788a7b1]{margin-bottom:20px}.mp-group.installed[data-v-6788a7b1]{border-top:1px dashed var(--border-color);padding-top:14px}.mp-group-header[data-v-6788a7b1]{align-items:center;gap:8px;margin-bottom:10px;display:flex}.mp-group-title[data-v-6788a7b1]{font-size:var(--font-size-mid);color:var(--text-primary);margin:0;font-weight:600}.mp-group-count[data-v-6788a7b1]{min-width:20px;height:18px;font-size:var(--font-size-xs);border-radius:var(--radius-lg);background:var(--bg-hover);color:var(--text-tertiary);justify-content:center;align-items:center;padding:0 6px;display:inline-flex}.mp-group-error[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--color-warning);align-items:center;gap:4px;display:inline-flex}.mp-group-link[data-v-6788a7b1]{color:var(--text-tertiary);transition:color var(--transition-fast) ease;display:inline-flex}.mp-group-link[data-v-6788a7b1]:hover{color:var(--color-primary)}.mp-grid[data-v-6788a7b1]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;display:grid}.mp-card[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);transition:border-color var(--transition-fast) ease, box-shadow var(--transition-fast) ease;flex-direction:column;gap:6px;padding:12px;display:flex}.mp-card[data-v-6788a7b1]:hover{border-color:color-mix(in srgb, var(--color-primary) 40%, var(--border-color));box-shadow:var(--shadow-sm)}.mp-card-head[data-v-6788a7b1]{align-items:center;gap:8px;display:flex}.mp-card-name[data-v-6788a7b1]{min-width:0;font-size:var(--font-size-mid);color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;flex:1;font-weight:600;overflow:hidden}.mp-card-metric[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);flex-shrink:0;align-items:center;gap:3px;display:inline-flex}.mp-card-desc[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;margin:0;line-height:1.5;display:-webkit-box;overflow:hidden}.mp-card-meta[data-v-6788a7b1]{flex-wrap:wrap;align-items:center;gap:6px;min-height:18px;display:flex}.mp-meta-pkg[data-v-6788a7b1],.mp-meta-repo[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;max-width:220px;overflow:hidden}.mp-tag[data-v-6788a7b1]{font-size:var(--font-size-xs);border-radius:var(--radius-lg);background:var(--bg-hover);color:var(--text-tertiary);flex-shrink:0;padding:1px 6px}.mp-tag.remote[data-v-6788a7b1]{background:color-mix(in srgb, var(--color-info,var(--action-teal)) 14%, transparent);color:var(--color-info,var(--action-teal))}.mp-tag.warn[data-v-6788a7b1]{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning)}.mp-card-foot[data-v-6788a7b1]{align-items:center;gap:8px;margin-top:2px;display:flex}.mp-card-link[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);text-decoration:none}.mp-card-link[data-v-6788a7b1]:hover{color:var(--color-primary);text-decoration:underline}.mp-foot-spacer[data-v-6788a7b1]{flex:1}.mp-install-btn[data-v-6788a7b1]{font-size:var(--font-size-sm);border:1px solid var(--color-primary);border-radius:var(--radius-base);color:var(--color-primary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;padding:4px 14px;font-family:inherit}.mp-install-btn[data-v-6788a7b1]:hover:not(:disabled){background:var(--color-primary);color:#fff}.mp-install-btn[data-v-6788a7b1]:disabled{opacity:.5;cursor:not-allowed}.mp-installed-chip[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--color-success,var(--action-emerald));align-items:center;gap:3px;display:inline-flex}.mp-not-installable[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary)}.mp-empty[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-tertiary);padding:16px 0}.mp-empty.all[data-v-6788a7b1]{text-align:center;padding:48px 0}.mp-installed-block[data-v-6788a7b1]{margin-bottom:12px}.mp-installed-target[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px;font-weight:600}.mp-installed-list[data-v-6788a7b1]{flex-direction:column;gap:4px;display:flex}.mp-installed-row[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-base);background:var(--bg-panel);align-items:center;gap:10px;padding:6px 10px;display:flex}.mp-installed-name[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-weight:500;overflow:hidden}.mp-remove-btn[data-v-6788a7b1]{font-size:var(--font-size-xs);border:1px solid var(--border-color);border-radius:var(--radius-xs);color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;display:inline-flex}.mp-remove-btn[data-v-6788a7b1]:hover:not(:disabled){color:var(--color-danger);border-color:var(--color-danger)}.mp-remove-btn[data-v-6788a7b1]:disabled{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.mp-refresh.spinning svg[data-v-6788a7b1]{animation:none}}.mkt-form[data-v-6788a7b1]{flex-direction:column;gap:12px;display:flex}.mkt-form-name[data-v-6788a7b1]{font-size:var(--font-size-mid);color:var(--text-primary);margin:0;font-weight:600}.mkt-field[data-v-6788a7b1]{flex-direction:column;gap:4px;display:flex}.mkt-field label[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-secondary);font-weight:600}.mkt-field input[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-container);height:30px;color:var(--text-primary);font-size:var(--font-size-mid);transition:border-color var(--transition-fast) ease;padding:0 8px;font-family:inherit}.mkt-field input[data-v-6788a7b1]:focus{border-color:var(--color-primary);outline:none}.mkt-hint[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);margin:0}.mkt-cancel[data-v-6788a7b1],.mkt-confirm[data-v-6788a7b1]{font-size:var(--font-size-mid);border-radius:var(--radius-base);cursor:pointer;transition:var(--transition-ui-fast);padding:6px 16px;font-family:inherit}.mkt-cancel[data-v-6788a7b1]{border:1px solid var(--border-color);color:var(--text-secondary);background:0 0;margin-right:8px}.mkt-cancel[data-v-6788a7b1]:hover{color:var(--text-primary);border-color:var(--text-tertiary)}.mkt-confirm[data-v-6788a7b1]{border:1px solid var(--color-primary);background:var(--color-primary);color:#fff}.mkt-confirm[data-v-6788a7b1]:hover{opacity:.9}.agent-view[data-v-52f9739a]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-52f9739a]{background:var(--bg-panel);border-right:1px solid var(--border-color);flex-direction:column;flex-shrink:0;display:flex;overflow:hidden}.agent-conversations[data-v-52f9739a]{flex:1;min-height:0;padding:10px 6px 8px 12px}.sidebar-resizer[data-v-52f9739a]{cursor:col-resize;width:4px;transition:background var(--transition-fast) ease;background:0 0;flex-shrink:0}.sidebar-resizer[data-v-52f9739a]:hover,.sidebar-resizer.active[data-v-52f9739a]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-52f9739a]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.agent-engine[data-v-52f9739a]{margin-bottom:7px;margin-left:auto}.agent-tabs[data-v-52f9739a]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:4px;padding:8px 12px 0;display:flex}.agent-tab[data-v-52f9739a]{color:var(--text-tertiary);font-size:var(--font-size-mid);cursor:pointer;transition:color var(--transition-fast) ease, border-color var(--transition-fast) ease, background var(--transition-fast) ease;border-radius:var(--radius-base) var(--radius-base) 0 0;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;padding:7px 14px 9px;font-family:inherit;display:inline-flex}.agent-tab[data-v-52f9739a]:hover{color:var(--text-secondary);background:var(--bg-hover)}.agent-tab.active[data-v-52f9739a]{color:var(--color-primary);border-bottom-color:var(--color-primary);font-weight:600}.agent-tab-body[data-v-52f9739a]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-pane[data-v-52f9739a]{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.agent-tab-body[data-v-52f9739a]>.marketplace-panel{flex:1;min-height:0}.chat-loading[data-v-52f9739a]{color:var(--text-tertiary);font-size:var(--font-size-base);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}.agent-list-page[data-v-52f9739a]{background:var(--bg-panel);flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-list-page .agent-conversations[data-v-52f9739a]{padding:12px 12px 10px 14px}.agent-page-bar[data-v-52f9739a]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:6px;height:34px;padding:0 12px 0 6px;display:flex}.agent-page-back[data-v-52f9739a]{border-radius:var(--radius-xs);width:24px;height:24px;color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:flex}.agent-page-back[data-v-52f9739a]:hover{background:var(--bg-hover);color:var(--text-secondary)}.agent-page-title[data-v-52f9739a]{min-width:0;font-size:var(--font-size-mid);color:var(--text-secondary);white-space:nowrap;text-overflow:ellipsis;flex:1;overflow:hidden}.agent-chat-host[data-v-52f9739a]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-host[data-v-52f9739a] .acu-avatar--left{background:0 0}[data-v-52f9739a] .acu-welcome-grid>.acu-preset-q:last-child:nth-child(odd){grid-column:1/-1}[data-theme=dark]{background:var(--bg-panel)}
|
|
1
|
+
.marketplace-panel[data-v-6788a7b1]{background:var(--bg-container);flex-direction:column;height:100%;min-height:0;display:flex}.mp-toolbar[data-v-6788a7b1]{flex-shrink:0;align-items:center;gap:12px;padding:12px 16px 8px;display:flex}.mp-search[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);max-width:420px;height:32px;transition:border-color var(--transition-fast) ease;flex:1;align-items:center;gap:6px;padding:0 10px;display:flex}.mp-search[data-v-6788a7b1]:focus-within{border-color:var(--color-primary)}.mp-search .mp-search-icon[data-v-6788a7b1]{color:var(--text-tertiary);flex-shrink:0}.mp-search .mp-search-input[data-v-6788a7b1]{color:var(--text-primary);font-size:var(--font-size-mid);background:0 0;border:none;outline:none;flex:1;font-family:inherit}.mp-search .mp-search-input[data-v-6788a7b1]::placeholder{color:var(--text-tertiary)}.mp-target[data-v-6788a7b1]{flex-shrink:0}.mp-refresh[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);width:30px;height:30px;color:var(--text-secondary);cursor:pointer;transition:var(--transition-ui-fast);justify-content:center;align-items:center;display:flex}.mp-refresh[data-v-6788a7b1]:hover{color:var(--color-primary);border-color:var(--color-primary)}.mp-refresh.spinning svg[data-v-6788a7b1]{animation:.9s linear infinite mkt-spin-6788a7b1}@keyframes mkt-spin-6788a7b1{to{transform:rotate(360deg)}}.mp-toolbar-sub[data-v-6788a7b1]{flex-wrap:wrap;flex-shrink:0;align-items:center;gap:12px;padding:0 16px 10px;display:flex}.mp-target-hint[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-tertiary)}.mp-target-hint b[data-v-6788a7b1]{color:var(--color-primary);font-weight:600}.mp-source-filter[data-v-6788a7b1]{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.mp-chip[data-v-6788a7b1]{font-size:var(--font-size-sm);border:1px solid var(--border-color);border-radius:var(--radius-xl);color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;padding:2px 10px;font-family:inherit}.mp-chip[data-v-6788a7b1]:hover{color:var(--text-secondary);border-color:var(--text-tertiary)}.mp-chip.active[data-v-6788a7b1]{color:var(--color-primary);border-color:var(--color-primary);background:color-mix(in srgb, var(--color-primary) 8%, transparent)}.mp-chip.clear[data-v-6788a7b1]{color:var(--text-tertiary);border-style:dashed}.mp-body[data-v-6788a7b1]{flex:1;min-height:0;padding:0 16px 20px;overflow-y:auto}.mp-group[data-v-6788a7b1]{margin-bottom:20px}.mp-group.installed[data-v-6788a7b1]{border-top:1px dashed var(--border-color);padding-top:14px}.mp-group-header[data-v-6788a7b1]{align-items:center;gap:8px;margin-bottom:10px;display:flex}.mp-group-title[data-v-6788a7b1]{font-size:var(--font-size-mid);color:var(--text-primary);margin:0;font-weight:600}.mp-group-count[data-v-6788a7b1]{min-width:20px;height:18px;font-size:var(--font-size-xs);border-radius:var(--radius-lg);background:var(--bg-hover);color:var(--text-tertiary);justify-content:center;align-items:center;padding:0 6px;display:inline-flex}.mp-group-error[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--color-warning);align-items:center;gap:4px;display:inline-flex}.mp-group-link[data-v-6788a7b1]{color:var(--text-tertiary);transition:color var(--transition-fast) ease;display:inline-flex}.mp-group-link[data-v-6788a7b1]:hover{color:var(--color-primary)}.mp-grid[data-v-6788a7b1]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;display:grid}.mp-card[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-panel);transition:border-color var(--transition-fast) ease, box-shadow var(--transition-fast) ease;flex-direction:column;gap:6px;padding:12px;display:flex}.mp-card[data-v-6788a7b1]:hover{border-color:color-mix(in srgb, var(--color-primary) 40%, var(--border-color));box-shadow:var(--shadow-sm)}.mp-card-head[data-v-6788a7b1]{align-items:center;gap:8px;display:flex}.mp-card-name[data-v-6788a7b1]{min-width:0;font-size:var(--font-size-mid);color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;flex:1;font-weight:600;overflow:hidden}.mp-card-metric[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);flex-shrink:0;align-items:center;gap:3px;display:inline-flex}.mp-card-desc[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:36px;margin:0;line-height:1.5;display:-webkit-box;overflow:hidden}.mp-card-meta[data-v-6788a7b1]{flex-wrap:wrap;align-items:center;gap:6px;min-height:18px;display:flex}.mp-meta-pkg[data-v-6788a7b1],.mp-meta-repo[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);white-space:nowrap;text-overflow:ellipsis;max-width:220px;overflow:hidden}.mp-tag[data-v-6788a7b1]{font-size:var(--font-size-xs);border-radius:var(--radius-lg);background:var(--bg-hover);color:var(--text-tertiary);flex-shrink:0;padding:1px 6px}.mp-tag.remote[data-v-6788a7b1]{background:color-mix(in srgb, var(--color-info,var(--action-teal)) 14%, transparent);color:var(--color-info,var(--action-teal))}.mp-tag.warn[data-v-6788a7b1]{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning)}.mp-card-foot[data-v-6788a7b1]{align-items:center;gap:8px;margin-top:2px;display:flex}.mp-card-link[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);text-decoration:none}.mp-card-link[data-v-6788a7b1]:hover{color:var(--color-primary);text-decoration:underline}.mp-foot-spacer[data-v-6788a7b1]{flex:1}.mp-install-btn[data-v-6788a7b1]{font-size:var(--font-size-sm);border:1px solid var(--color-primary);border-radius:var(--radius-base);color:var(--color-primary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;padding:4px 14px;font-family:inherit}.mp-install-btn[data-v-6788a7b1]:hover:not(:disabled){background:var(--color-primary);color:#fff}.mp-install-btn[data-v-6788a7b1]:disabled{opacity:.5;cursor:not-allowed}.mp-installed-chip[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--color-success,var(--action-emerald));align-items:center;gap:3px;display:inline-flex}.mp-not-installable[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary)}.mp-empty[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-tertiary);padding:16px 0}.mp-empty.all[data-v-6788a7b1]{text-align:center;padding:48px 0}.mp-installed-block[data-v-6788a7b1]{margin-bottom:12px}.mp-installed-target[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.4px;margin-bottom:6px;font-weight:600}.mp-installed-list[data-v-6788a7b1]{flex-direction:column;gap:4px;display:flex}.mp-installed-row[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-base);background:var(--bg-panel);align-items:center;gap:10px;padding:6px 10px;display:flex}.mp-installed-name[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-primary);white-space:nowrap;text-overflow:ellipsis;font-weight:500;overflow:hidden}.mp-remove-btn[data-v-6788a7b1]{font-size:var(--font-size-xs);border:1px solid var(--border-color);border-radius:var(--radius-xs);color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;align-items:center;gap:4px;padding:3px 10px;font-family:inherit;display:inline-flex}.mp-remove-btn[data-v-6788a7b1]:hover:not(:disabled){color:var(--color-danger);border-color:var(--color-danger)}.mp-remove-btn[data-v-6788a7b1]:disabled{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.mp-refresh.spinning svg[data-v-6788a7b1]{animation:none}}.mkt-form[data-v-6788a7b1]{flex-direction:column;gap:12px;display:flex}.mkt-form-name[data-v-6788a7b1]{font-size:var(--font-size-mid);color:var(--text-primary);margin:0;font-weight:600}.mkt-field[data-v-6788a7b1]{flex-direction:column;gap:4px;display:flex}.mkt-field label[data-v-6788a7b1]{font-size:var(--font-size-sm);color:var(--text-secondary);font-weight:600}.mkt-field input[data-v-6788a7b1]{border:1px solid var(--border-color);border-radius:var(--radius-md);background:var(--bg-container);height:30px;color:var(--text-primary);font-size:var(--font-size-mid);transition:border-color var(--transition-fast) ease;padding:0 8px;font-family:inherit}.mkt-field input[data-v-6788a7b1]:focus{border-color:var(--color-primary);outline:none}.mkt-hint[data-v-6788a7b1]{font-size:var(--font-size-xs);color:var(--text-tertiary);margin:0}.mkt-cancel[data-v-6788a7b1],.mkt-confirm[data-v-6788a7b1]{font-size:var(--font-size-mid);border-radius:var(--radius-base);cursor:pointer;transition:var(--transition-ui-fast);padding:6px 16px;font-family:inherit}.mkt-cancel[data-v-6788a7b1]{border:1px solid var(--border-color);color:var(--text-secondary);background:0 0;margin-right:8px}.mkt-cancel[data-v-6788a7b1]:hover{color:var(--text-primary);border-color:var(--text-tertiary)}.mkt-confirm[data-v-6788a7b1]{border:1px solid var(--color-primary);background:var(--color-primary);color:#fff}.mkt-confirm[data-v-6788a7b1]:hover{opacity:.9}.agent-view[data-v-05972cec]{background:var(--bg-container);height:100%;min-height:0;display:flex}.agent-sidebar[data-v-05972cec]{background:var(--bg-panel);border-right:1px solid var(--border-color);flex-direction:column;flex-shrink:0;display:flex;overflow:hidden}.agent-conversations[data-v-05972cec]{flex:1;min-height:0;padding:10px 6px 8px 12px}.sidebar-resizer[data-v-05972cec]{cursor:col-resize;width:4px;transition:background var(--transition-fast) ease;background:0 0;flex-shrink:0}.sidebar-resizer[data-v-05972cec]:hover,.sidebar-resizer.active[data-v-05972cec]{background:var(--color-primary);opacity:.3}.agent-chat-area[data-v-05972cec]{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.agent-engine[data-v-05972cec]{margin-bottom:7px;margin-left:auto}.agent-tabs[data-v-05972cec]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:4px;padding:8px 12px 0;display:flex}.agent-tab[data-v-05972cec]{color:var(--text-tertiary);font-size:var(--font-size-mid);cursor:pointer;transition:color var(--transition-fast) ease, border-color var(--transition-fast) ease, background var(--transition-fast) ease;border-radius:var(--radius-base) var(--radius-base) 0 0;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;padding:7px 14px 9px;font-family:inherit;display:inline-flex}.agent-tab[data-v-05972cec]:hover{color:var(--text-secondary);background:var(--bg-hover)}.agent-tab.active[data-v-05972cec]{color:var(--color-primary);border-bottom-color:var(--color-primary);font-weight:600}.agent-tab-body[data-v-05972cec]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-pane[data-v-05972cec]{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.agent-tab-body[data-v-05972cec]>.marketplace-panel{flex:1;min-height:0}.chat-loading[data-v-05972cec]{color:var(--text-tertiary);font-size:var(--font-size-base);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}.agent-list-page[data-v-05972cec]{background:var(--bg-panel);flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-list-page .agent-conversations[data-v-05972cec]{padding:12px 12px 10px 14px}.agent-page-bar[data-v-05972cec]{border-bottom:1px solid var(--border-color);background:var(--bg-panel);flex-shrink:0;align-items:center;gap:6px;height:34px;padding:0 12px 0 6px;display:flex}.agent-page-back[data-v-05972cec]{border-radius:var(--radius-xs);width:24px;height:24px;color:var(--text-tertiary);cursor:pointer;transition:var(--transition-ui-fast);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:flex}.agent-page-back[data-v-05972cec]:hover{background:var(--bg-hover);color:var(--text-secondary)}.agent-page-title[data-v-05972cec]{min-width:0;font-size:var(--font-size-mid);color:var(--text-secondary);white-space:nowrap;text-overflow:ellipsis;flex:1;overflow:hidden}.agent-chat-host[data-v-05972cec]{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.agent-chat-host[data-v-05972cec] .acu-avatar--left{background:0 0}.agent-chat-host[data-v-05972cec] .acu-welcome-logo{background:var(--welcome-avatar) center/46px 46px no-repeat;width:56px;height:56px;box-shadow:none}.agent-chat-host[data-v-05972cec] .acu-welcome-logo>svg{display:none}.agent-chat-host[data-v-05972cec] .acu-welcome-grid{flex-wrap:wrap;display:flex}.agent-chat-host[data-v-05972cec] .acu-welcome-grid>.acu-preset-q{flex:260px;min-width:0}[data-theme=dark]{background:var(--bg-panel)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,A as t,Bt as n,Cn as r,Ct as i,Dn as a,Dt as o,En as s,Er as c,H as l,K as u,Mn as d,Ot as f,Pn as p,Pr as m,Q as h,Qn as g,Qr as _,Rn as v,Tn as y,Un as b,Ut as x,Xn as S,Yr as C,a as w,at as T,br as E,cr as D,ft as O,hn as k,i as A,j as ee,jn as j,ln as M,lr as N,o as P,or as F,pr as I,qr as L,qt as te,rn as ne,st as re,tr as R,vr as ie,wn as z,yn as B}from"./element-plus-Bx3j6vzG.js";import{r as V,t as H}from"./vendor-CyWsJd6S.js";import{n as U,t as W}from"./_plugin-vue_export-helper-C_bQVzeb.js";import{t as ae}from"./configStore-DJH7OlB_.js";import{t as oe}from"./CommonDialog-BEm2cK1X.js";import{a as se,i as G,n as K,o as q,r as ce,s as le,t as J}from"./agentConversations-BUPj8vzH.js";import{n as ue,t as de}from"./AgentEngineSelector-DLJ8He83.js";v(),I(),M(),m();var fe={class:`marketplace-panel`},Y={class:`mp-toolbar`},pe={class:`mp-search`},me=[`placeholder`],he={class:`mp-toolbar-sub`},ge={class:`mp-target-hint`},_e={class:`mp-source-filter`},X=[`onClick`],ve={class:`mp-body`},ye={class:`mp-group-header`},be={class:`mp-group-title`},xe={key:0,class:`mp-group-count`},Se={key:1,class:`mp-group-error`},Ce=[`href`,`title`],we={key:0,class:`mp-grid`},Z={class:`mp-card-head`},Te=[`title`],Ee={key:0,class:`mp-card-metric`},Q=[`title`],$={class:`mp-card-meta`},De=[`title`],Oe=[`title`],ke={key:2,class:`mp-tag remote`},Ae={class:`mp-card-foot`},je=[`href`],Me={key:1,class:`mp-installed-chip`},Ne=[`disabled`,`onClick`],Pe={key:3,class:`mp-not-installable`},Fe={key:1,class:`mp-empty`},Ie={key:0,class:`mp-group installed`},Le={class:`mp-group-header`},Re={class:`mp-group-title`},ze={class:`mp-group-count`},Be={key:0,class:`mp-installed-block`},Ve={class:`mp-installed-target`},He={class:`mp-installed-list`},Ue={class:`mp-installed-name`},We={key:0,class:`mp-meta-pkg`},Ge={key:1,class:`mp-tag warn`},Ke=[`disabled`,`onClick`],qe={key:1,class:`mp-empty all`},Je={key:0,class:`mkt-form`},Ye={class:`mkt-form-name`},Xe=[`onUpdate:modelValue`,`placeholder`],Ze={key:0,class:`mkt-field`},Qe={class:`mkt-hint`},$e=W(p({__name:`MarketplacePanel`,props:{type:{}},setup(i){let f=i,p=ae(),m=E([]),h=E([]),v=E(!1),b=E(``),C=E(``),T=E([]),M=E(`project`),I=E(new Set),R=E(new Set),V=r(()=>p.currentDirectory||``),H=null;async function W(){if(!v.value){v.value=!0;try{let e=new URLSearchParams({type:f.type,cwd:V.value});C.value&&e.set(`q`,C.value),T.value.length&&e.set(`sources`,T.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(m.value=t.groups||[],h.value=t.installed||[]):w.error(t?.error||U(`@MKT:加载失败`))}catch{w.error(U(`@MKT:加载失败`))}finally{v.value=!1}}}F(b,e=>{H&&clearTimeout(H),H=setTimeout(()=>{C.value=e.trim(),W()},400)}),F(T,()=>W()),F(()=>f.type,()=>{T.value=[],C.value=``,b.value=``,W()}),F(V,()=>W()),W();let se=r(()=>{let e=V.value?V.value.split(/[\\/]/).filter(Boolean).pop():``;return M.value===`project`?e||U(`@MKT:当前项目`):U(`@MKT:g ai 智能体`)});function G(e){return e.stars?`${K(e.stars)} ★`:e.downloads?`${K(e.downloads)} ${U(`@MKT:周下载`)}`:e.uses?`${K(e.uses)} ${U(`@MKT:次使用`)}`:``}function K(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function q(e){return`${e.id}`}function ce(e){return I.value.has(q(e))}let le=r(()=>{let e={project:[],global:[]};for(let t of h.value)(e[t.target]||=[]).push(t);return e}),J=ie({visible:!1,item:null,env:{},args:``});function ue(e){return f.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function de(e){J.item=e,J.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),J.args=(e.args||[]).join(` `),J.visible=!0}function $e(){let e=J.item;if(J.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(J.env).filter(([,e])=>e.trim()!==``)),n=J.args.trim()?J.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;tt(e,{env:t,...n?{args:n}:{}})}async function et(e){if(!e.installed||await nt(e)){if(ue(e)){de(e);return}await tt(e,{})}}async function tt(e,t){let n=q(e);I.value.add(n);try{let n=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:f.type,target:M.value,cwd:V.value,item:{...e,...t}})}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){w.error(r?.error||U(`@MKT:安装失败`));return}r.item?.warning&&w.warning(r.item.warning),r.item?.envKeys?.length?w.warning(`${U(`@MKT:还缺环境变量`)}: ${r.item.envKeys.join(`, `)}`):w.success(U(`@MKT:安装成功`)),await W()}catch{w.error(U(`@MKT:安装失败`))}finally{I.value.delete(n)}}async function nt(e){try{return await A.confirm(`${e.name} ${U(`@MKT:已安装,要重新安装吗?`)}`,U(`@MKT:重新安装`),{confirmButtonText:U(`@MKT:重装`),cancelButtonText:U(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function rt(e){try{await A.confirm(`${U(`@MKT:确定卸载`)} ${e.name}?`,U(`@MKT:卸载`),{confirmButtonText:U(`@MKT:卸载`),cancelButtonText:U(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;R.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:V.value}),n=await fetch(`/api/agent/marketplace/item/${f.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){w.error(r?.error||U(`@MKT:卸载失败`));return}w.success(U(`@MKT:已卸载`)),await W()}catch{w.error(U(`@MKT:卸载失败`))}finally{R.value.delete(t)}}return(r,f)=>{let p=u,C=t,w=ee,E=l,A=P;return S(),a(`div`,fe,[z(`div`,Y,[z(`div`,pe,[d(p,{class:`mp-search-icon`},{default:D(()=>[d(c(x))]),_:1}),N(z(`input`,{"onUpdate:modelValue":f[0]||=e=>b.value=e,class:`mp-search-input`,type:`text`,placeholder:i.type===`skill`?c(U)(`@MKT:搜索 Skill...`):c(U)(`@MKT:搜索 MCP 服务...`)},null,8,me),[[k,b.value]])]),d(w,{modelValue:M.value,"onUpdate:modelValue":f[1]||=e=>M.value=e,size:`small`,class:`mp-target`},{default:D(()=>[d(C,{value:`project`},{default:D(()=>[j(_(c(U)(`@MKT:当前项目`)),1)]),_:1}),d(C,{value:`global`},{default:D(()=>[j(_(c(U)(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),d(E,{content:c(U)(`@MKT:刷新`),placement:`top`,"show-after":300},{default:D(()=>[z(`button`,{class:L([`mp-refresh`,{spinning:v.value}]),onClick:W},[d(p,null,{default:D(()=>[d(c(n))]),_:1})],2)]),_:1},8,[`content`])]),z(`div`,he,[z(`span`,ge,[j(_(c(U)(`@MKT:安装到`))+` `,1),z(`b`,null,_(se.value),1)]),z(`div`,_e,[(S(!0),a(B,null,g(m.value,e=>(S(),a(`button`,{key:e.id,class:L([`mp-chip`,{active:T.value.includes(e.id)}]),onClick:()=>{let t=T.value.indexOf(e.id);t>=0?T.value.splice(t,1):T.value.push(e.id)}},_(e.label),11,X))),128)),T.value.length?(S(),a(`button`,{key:0,class:`mp-chip clear`,onClick:f[2]||=e=>T.value=[]},_(c(U)(`@MKT:全部来源`)),1)):s(``,!0)])]),N((S(),a(`div`,ve,[(S(!0),a(B,null,g(m.value,t=>(S(),a(`section`,{key:t.id,class:`mp-group`},[z(`header`,ye,[z(`h3`,be,_(t.label),1),t.status===`ok`?(S(),a(`span`,xe,_(t.items.length),1)):(S(),a(`span`,Se,[d(p,null,{default:D(()=>[d(c(ne))]),_:1}),j(` `+_(t.error||c(U)(`@MKT:来源不可用`)),1)])),t.homepage?(S(),a(`a`,{key:2,class:`mp-group-link`,href:t.homepage,target:`_blank`,rel:`noopener noreferrer`,title:t.homepage},[d(p,null,{default:D(()=>[d(c(o))]),_:1})],8,Ce)):s(``,!0)]),t.status===`ok`&&t.items.length?(S(),a(`div`,we,[(S(!0),a(B,null,g(t.items,t=>(S(),a(`article`,{key:q(t),class:`mp-card`},[z(`div`,Z,[z(`span`,{class:`mp-card-name`,title:t.name},_(t.name),9,Te),G(t)?(S(),a(`span`,Ee,[d(p,null,{default:D(()=>[t.stars?(S(),y(c(te),{key:0})):(S(),y(c(O),{key:1}))]),_:2},1024),j(` `+_(G(t)),1)])):s(``,!0)]),z(`p`,{class:`mp-card-desc`,title:t.description},_(t.description||c(U)(`@MKT:暂无描述`)),9,Q),z(`div`,$,[t.package?(S(),a(`code`,{key:0,class:`mp-meta-pkg`,title:t.package},_(t.package),9,De)):t.repository?(S(),a(`span`,{key:1,class:`mp-meta-repo`,title:t.repository+(t.subpath?` · `+t.subpath:``)},[j(_(t.repository),1),t.subpath?(S(),a(B,{key:0},[j(` · `+_(t.subpath),1)],64)):s(``,!0)],8,Oe)):s(``,!0),t.transport===`remote`?(S(),a(`span`,ke,_(c(U)(`@MKT:远程服务`)),1)):s(``,!0),(S(!0),a(B,null,g((t.tags||[]).slice(0,2),e=>(S(),a(`span`,{key:e,class:`mp-tag`},_(e),1))),128))]),z(`div`,Ae,[t.upstream?(S(),a(`a`,{key:0,class:`mp-card-link`,href:t.upstream,target:`_blank`,rel:`noopener noreferrer`},_(c(U)(`@MKT:查看来源`)),9,je)):s(``,!0),f[6]||=z(`span`,{class:`mp-foot-spacer`},null,-1),t.installed?(S(),a(`span`,Me,[d(p,null,{default:D(()=>[d(c(e))]),_:1}),j(_(c(U)(`@MKT:已安装`)),1)])):t.installable===!1?(S(),a(`span`,Pe,_(c(U)(`@MKT:暂不支持一键安装`)),1)):(S(),a(`button`,{key:2,class:`mp-install-btn`,disabled:ce(t),onClick:e=>et(t)},_(ce(t)?c(U)(`@MKT:安装中...`):c(U)(`@MKT:安装`)),9,Ne))])]))),128))])):t.status===`ok`?(S(),a(`div`,Fe,_(c(U)(`@MKT:该来源暂无结果`)),1)):s(``,!0)]))),128)),h.value.length?(S(),a(`section`,Ie,[z(`header`,Le,[z(`h3`,Re,_(c(U)(`@MKT:已安装`)),1),z(`span`,ze,_(h.value.length),1)]),(S(),a(B,null,g([`project`,`global`],e=>z(`div`,{key:e},[le.value[e]?.length?(S(),a(`div`,Be,[z(`div`,Ve,_(e===`project`?c(U)(`@MKT:当前项目`):c(U)(`@MKT:g ai 智能体`)),1),z(`div`,He,[(S(!0),a(B,null,g(le.value[e],t=>(S(),a(`div`,{key:e+t.id,class:`mp-installed-row`},[z(`span`,Ue,_(t.name),1),t.package?(S(),a(`code`,We,_(t.package),1)):s(``,!0),t.requiredEnv?.length?(S(),a(`span`,Ge,_(c(U)(`@MKT:待配置`))+`: `+_(t.requiredEnv.join(`, `)),1)):s(``,!0),f[7]||=z(`span`,{class:`mp-foot-spacer`},null,-1),z(`button`,{class:`mp-remove-btn`,disabled:R.value.has(e+t.id),onClick:e=>rt(t)},[d(p,null,{default:D(()=>[d(c(re))]),_:1}),j(` `+_(R.value.has(e+t.id)?c(U)(`@MKT:卸载中...`):c(U)(`@MKT:卸载`)),1)],8,Ke)]))),128))])])):s(``,!0)])),64))])):s(``,!0),!v.value&&!m.value.length?(S(),a(`div`,qe,_(c(U)(`@MKT:加载失败`)),1)):s(``,!0)])),[[A,v.value]]),d(oe,{modelValue:J.visible,"onUpdate:modelValue":f[5]||=e=>J.visible=e,title:c(U)(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:D(()=>[z(`button`,{class:`mkt-cancel`,onClick:f[4]||=e=>J.visible=!1},_(c(U)(`@MKT:取消`)),1),z(`button`,{class:`mkt-confirm`,onClick:$e},_(c(U)(`@MKT:安装`)),1)]),default:D(()=>[J.item?(S(),a(`div`,Je,[z(`p`,Ye,_(J.item.name),1),(S(!0),a(B,null,g(Object.keys(J.env),e=>(S(),a(`div`,{key:e,class:`mkt-field`},[z(`label`,null,_(e),1),N(z(`input`,{"onUpdate:modelValue":t=>J.env[e]=t,type:`text`,autocomplete:`off`,placeholder:c(U)(`@MKT:环境变量值`),spellcheck:`false`},null,8,Xe),[[k,J.env[e]]])]))),128)),J.item.args?.length?(S(),a(`div`,Ze,[z(`label`,null,_(c(U)(`@MKT:启动参数`)),1),N(z(`input`,{"onUpdate:modelValue":f[3]||=e=>J.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[k,J.args]]),z(`p`,Qe,_(c(U)(`@MKT:参数提示`)),1)])):s(``,!0)])):s(``,!0)]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-6788a7b1`]]);v(),I(),m();var et={class:`agent-chat-area`},tt={class:`agent-tabs`,role:`tablist`},nt=[`aria-selected`,`onClick`],rt={class:`agent-tab-body`},it={key:0,class:`agent-chat-pane`},at={key:0,class:`agent-list-page`},ot={key:0,class:`agent-page-bar`},st=[`title`,`aria-label`],ct={class:`agent-page-title`},lt={class:`agent-chat-host`},ut={key:0,class:`chat-loading`},dt=W(p({__name:`AgentView`,setup(e){let t=ae(),n=E(null),{narrow:o}=ue(n),l=E(`chat`),p=E(`chat`),m=r(()=>p.value===`mcp`?`mcp`:`skill`),v=r(()=>[{id:`chat`,label:U(`@AGENT:对话`),icon:h},{id:`skill`,label:U(`@AGENT:Skill 广场`),icon:i},{id:`mcp`,label:U(`@AGENT:MCP 广场`),icon:T}]),{sessions:x,sessionsLoading:w,currentSessionId:O,messages:k,isStreaming:A,sessionLoading:ee,loadSessions:j,loadSession:M,deleteSession:N,renameSession:P,newSession:I,sendMessage:te,pendingQuestion:ne,answeringQuestion:re,answerQuestion:ie,isSessionGenerating:W,currentEngine:oe,pendingEngine:fe,isEngineLocked:Y,pickEngine:pe,stop:me}=le(),he=r(()=>Y.value?oe.value:fe.value);function ge(e){Y.value||pe(e)}let _e=r(()=>{let e=t.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),X=r(()=>se(x.value,W)),ve=ce(),ye=r(()=>X.value.find(e=>e.id===O.value)?.title||U(`@AGENT:对话`)),be=r(()=>[{id:`p1`,label:U(`@AGENT:查看项目结构`),prompt:U(`@AGENT:prompt_p1`)},{id:`p2`,label:U(`@AGENT:分析代码质量`),prompt:U(`@AGENT:prompt_p2`)},{id:`p3`,label:U(`@AGENT:帮我写测试`),prompt:U(`@AGENT:prompt_p3`)},{id:`p4`,label:U(`@AGENT:Git 状态检查`),prompt:U(`@AGENT:prompt_p4`)},{id:`p5`,label:U(`@AGENT:帮我启动项目`),prompt:U(`@AGENT:prompt_p5`)}]);async function xe(e){await te(e.text,e.files),await b(),Z()}async function Se(e){await te(e.prompt),await b(),Z()}let Ce=G(),we=E(null);function Z(e=!0){we.value?.scrollToBottom(e)}F(()=>k.value.length,()=>{b(()=>Z(!1))});function Te(e){M(e),l.value=`chat`}function Ee(){I(),l.value=`chat`}let Q=E(280),$=E(!1);function De(e){$.value=!0;let t=e.clientX,n=Q.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Q.value=i},i=()=>{$.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return F(o,e=>{e||(l.value=`chat`)}),F(()=>[t.currentDirectory,A.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await j(),O.value&&!A.value&&!x.value.some(e=>e.sessionId===O.value)&&I()},{immediate:!0}),(e,t)=>(S(),a(`div`,{ref_key:`rootRef`,ref:n,class:`agent-view`},[p.value===`chat`&&!c(o)?(S(),a(B,{key:0},[z(`aside`,{class:`agent-sidebar`,style:C({width:Q.value+`px`})},[d(c(V),{class:`agent-conversations`,items:X.value,"active-id":c(O),loading:c(w),labels:c(ve),onSelect:Te,onNew:Ee,onRename:c(P),onDelete:c(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],4),z(`div`,{class:L([`sidebar-resizer`,{active:$.value}]),onMousedown:De},null,34)],64)):s(``,!0),z(`main`,et,[z(`nav`,tt,[(S(!0),a(B,null,g(v.value,e=>(S(),a(`button`,{key:e.id,type:`button`,class:L([`agent-tab`,{active:p.value===e.id}]),role:`tab`,"aria-selected":p.value===e.id,onClick:t=>p.value=e.id},[d(c(u),null,{default:D(()=>[(S(),y(R(e.icon)))]),_:2},1024),z(`span`,null,_(e.label),1)],10,nt))),128)),p.value===`chat`?(S(),y(de,{key:0,class:`agent-engine`,engine:he.value,locked:c(Y),onSelect:ge},null,8,[`engine`,`locked`])):s(``,!0)]),z(`div`,rt,[p.value===`chat`?(S(),a(`div`,it,[c(o)&&l.value===`list`?(S(),a(`div`,at,[d(c(V),{class:`agent-conversations`,items:X.value,"active-id":c(O),loading:c(w),labels:c(ve),onSelect:Te,onNew:Ee,onRename:c(P),onDelete:c(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(S(),a(B,{key:1},[c(o)?(S(),a(`div`,ot,[z(`button`,{type:`button`,class:`agent-page-back`,title:c(U)(`@AGENT:返回会话列表`),"aria-label":c(U)(`@AGENT:返回会话列表`),onClick:t[0]||=e=>l.value=`list`},[...t[1]||=[z(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[z(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),z(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,st),z(`span`,ct,_(ye.value),1)])):s(``,!0),z(`div`,lt,[c(ee)?(S(),a(`div`,ut,[d(c(u),{class:`is-loading`,size:32},{default:D(()=>[d(c(f))]),_:1}),z(`span`,null,_(c(U)(`@AGENT:加载会话中...`)),1)])):(S(),y(c(H),{key:1,ref_key:`chatContainerRef`,ref:we,messages:c(k),"preset-questions":be.value,"welcome-title":c(U)(`@AGENT:智能体助手`),"welcome-description":c(U)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":c(K),"assistant-avatar":c(J),theme:_e.value,disabled:c(A),generating:c(A),"upload-config":{accept:c(q)},placeholder:c(A)?c(U)(`@AGENT:正在生成中...`):c(U)(`@AGENT:输入消息,Enter 发送`),question:c(ne),"question-submitting":c(re),"question-labels":c(Ce),onSend:xe,onSelect:Se,onStop:c(me),onAnswer:c(ie)},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`assistant-avatar`,`theme`,`disabled`,`generating`,`upload-config`,`placeholder`,`question`,`question-submitting`,`question-labels`,`onStop`,`onAnswer`]))])],64))])):(S(),y($e,{key:1,type:m.value},null,8,[`type`]))])])],512))}}),[[`__scopeId`,`data-v-52f9739a`]]);export{dt as default};
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$ as e,A as t,Bt as n,Cn as r,Ct as i,Dn as a,Dt as o,En as s,Er as c,H as l,K as u,Mn as d,Ot as f,Pn as p,Pr as m,Q as h,Qn as g,Qr as _,Rn as v,Tn as y,Un as b,Ut as x,Xn as S,Yr as C,a as w,at as T,br as E,cr as D,ft as O,hn as k,i as A,j as ee,jn as j,ln as M,lr as N,o as P,or as F,pr as I,qr as L,qt as te,rn as ne,st as re,tr as R,vr as ie,wn as z,yn as B}from"./element-plus-Bx3j6vzG.js";import{c as V,t as H}from"./vendor-BjomZKSS.js";import{n as U,t as W}from"./_plugin-vue_export-helper-C7IvbEC3.js";import{t as ae}from"./configStore-C-htWfWm.js";import{t as oe}from"./CommonDialog-CRXyMlp5.js";import{a as se,i as G,n as K,o as q,r as ce,s as le,t as J}from"./agentConversations-nN-yDz8q.js";import{n as ue,t as de}from"./AgentEngineSelector-BArUIELz.js";v(),I(),M(),m();var fe={class:`marketplace-panel`},Y={class:`mp-toolbar`},pe={class:`mp-search`},me=[`placeholder`],he={class:`mp-toolbar-sub`},ge={class:`mp-target-hint`},_e={class:`mp-source-filter`},X=[`onClick`],ve={class:`mp-body`},ye={class:`mp-group-header`},be={class:`mp-group-title`},xe={key:0,class:`mp-group-count`},Se={key:1,class:`mp-group-error`},Ce=[`href`,`title`],we={key:0,class:`mp-grid`},Te={class:`mp-card-head`},Z=[`title`],Ee={key:0,class:`mp-card-metric`},De=[`title`],Q={class:`mp-card-meta`},$=[`title`],Oe=[`title`],ke={key:2,class:`mp-tag remote`},Ae={class:`mp-card-foot`},je=[`href`],Me={key:1,class:`mp-installed-chip`},Ne=[`disabled`,`onClick`],Pe={key:3,class:`mp-not-installable`},Fe={key:1,class:`mp-empty`},Ie={key:0,class:`mp-group installed`},Le={class:`mp-group-header`},Re={class:`mp-group-title`},ze={class:`mp-group-count`},Be={key:0,class:`mp-installed-block`},Ve={class:`mp-installed-target`},He={class:`mp-installed-list`},Ue={class:`mp-installed-name`},We={key:0,class:`mp-meta-pkg`},Ge={key:1,class:`mp-tag warn`},Ke=[`disabled`,`onClick`],qe={key:1,class:`mp-empty all`},Je={key:0,class:`mkt-form`},Ye={class:`mkt-form-name`},Xe=[`onUpdate:modelValue`,`placeholder`],Ze={key:0,class:`mkt-field`},Qe={class:`mkt-hint`},$e=W(p({__name:`MarketplacePanel`,props:{type:{}},setup(i){let f=i,p=ae(),m=E([]),h=E([]),v=E(!1),b=E(``),C=E(``),T=E([]),M=E(`project`),I=E(new Set),R=E(new Set),V=r(()=>p.currentDirectory||``),H=null;async function W(){if(!v.value){v.value=!0;try{let e=new URLSearchParams({type:f.type,cwd:V.value});C.value&&e.set(`q`,C.value),T.value.length&&e.set(`sources`,T.value.join(`,`));let t=await(await fetch(`/api/agent/marketplace/catalog?${e}`)).json();t?.success?(m.value=t.groups||[],h.value=t.installed||[]):w.error(t?.error||U(`@MKT:加载失败`))}catch{w.error(U(`@MKT:加载失败`))}finally{v.value=!1}}}F(b,e=>{H&&clearTimeout(H),H=setTimeout(()=>{C.value=e.trim(),W()},400)}),F(T,()=>W()),F(()=>f.type,()=>{T.value=[],C.value=``,b.value=``,W()}),F(V,()=>W()),W();let se=r(()=>{let e=V.value?V.value.split(/[\\/]/).filter(Boolean).pop():``;return M.value===`project`?e||U(`@MKT:当前项目`):U(`@MKT:g ai 智能体`)});function G(e){return e.stars?`${K(e.stars)} ★`:e.downloads?`${K(e.downloads)} ${U(`@MKT:周下载`)}`:e.uses?`${K(e.uses)} ${U(`@MKT:次使用`)}`:``}function K(e){return e>=1e3?`${(e/1e3).toFixed(e>=1e4?0:1)}k`:String(e)}function q(e){return`${e.id}`}function ce(e){return I.value.has(q(e))}let le=r(()=>{let e={project:[],global:[]};for(let t of h.value)(e[t.target]||=[]).push(t);return e}),J=ie({visible:!1,item:null,env:{},args:``});function ue(e){return f.type===`mcp`&&(!!e.envKeys?.length||!!e.args?.length)}function de(e){J.item=e,J.env=Object.fromEntries((e.envKeys||[]).map(e=>[e,``])),J.args=(e.args||[]).join(` `),J.visible=!0}function $e(){let e=J.item;if(J.visible=!1,!e)return;let t=Object.fromEntries(Object.entries(J.env).filter(([,e])=>e.trim()!==``)),n=J.args.trim()?J.args.trim().match(/(?:[^\s"]+|"[^"]*")+/g)?.map(e=>e.replace(/^"|"$/g,``))??void 0:void 0;tt(e,{env:t,...n?{args:n}:{}})}async function et(e){if(!e.installed||await nt(e)){if(ue(e)){de(e);return}await tt(e,{})}}async function tt(e,t){let n=q(e);I.value.add(n);try{let n=await fetch(`/api/agent/marketplace/install`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:f.type,target:M.value,cwd:V.value,item:{...e,...t}})}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){w.error(r?.error||U(`@MKT:安装失败`));return}r.item?.warning&&w.warning(r.item.warning),r.item?.envKeys?.length?w.warning(`${U(`@MKT:还缺环境变量`)}: ${r.item.envKeys.join(`, `)}`):w.success(U(`@MKT:安装成功`)),await W()}catch{w.error(U(`@MKT:安装失败`))}finally{I.value.delete(n)}}async function nt(e){try{return await A.confirm(`${e.name} ${U(`@MKT:已安装,要重新安装吗?`)}`,U(`@MKT:重新安装`),{confirmButtonText:U(`@MKT:重装`),cancelButtonText:U(`@MKT:取消`),type:`warning`}),!0}catch{return!1}}async function rt(e){try{await A.confirm(`${U(`@MKT:确定卸载`)} ${e.name}?`,U(`@MKT:卸载`),{confirmButtonText:U(`@MKT:卸载`),cancelButtonText:U(`@MKT:取消`),type:`warning`})}catch{return}let t=`${e.target}:${e.id}`;R.value.add(t);try{let t=new URLSearchParams({target:e.target,cwd:V.value}),n=await fetch(`/api/agent/marketplace/item/${f.type}/${encodeURIComponent(e.id)}?${t}`,{method:`DELETE`}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success){w.error(r?.error||U(`@MKT:卸载失败`));return}w.success(U(`@MKT:已卸载`)),await W()}catch{w.error(U(`@MKT:卸载失败`))}finally{R.value.delete(t)}}return(r,f)=>{let p=u,C=t,w=ee,E=l,A=P;return S(),a(`div`,fe,[z(`div`,Y,[z(`div`,pe,[d(p,{class:`mp-search-icon`},{default:D(()=>[d(c(x))]),_:1}),N(z(`input`,{"onUpdate:modelValue":f[0]||=e=>b.value=e,class:`mp-search-input`,type:`text`,placeholder:i.type===`skill`?c(U)(`@MKT:搜索 Skill...`):c(U)(`@MKT:搜索 MCP 服务...`)},null,8,me),[[k,b.value]])]),d(w,{modelValue:M.value,"onUpdate:modelValue":f[1]||=e=>M.value=e,size:`small`,class:`mp-target`},{default:D(()=>[d(C,{value:`project`},{default:D(()=>[j(_(c(U)(`@MKT:当前项目`)),1)]),_:1}),d(C,{value:`global`},{default:D(()=>[j(_(c(U)(`@MKT:g ai 智能体`)),1)]),_:1})]),_:1},8,[`modelValue`]),d(E,{content:c(U)(`@MKT:刷新`),placement:`top`,"show-after":300},{default:D(()=>[z(`button`,{class:L([`mp-refresh`,{spinning:v.value}]),onClick:W},[d(p,null,{default:D(()=>[d(c(n))]),_:1})],2)]),_:1},8,[`content`])]),z(`div`,he,[z(`span`,ge,[j(_(c(U)(`@MKT:安装到`))+` `,1),z(`b`,null,_(se.value),1)]),z(`div`,_e,[(S(!0),a(B,null,g(m.value,e=>(S(),a(`button`,{key:e.id,class:L([`mp-chip`,{active:T.value.includes(e.id)}]),onClick:()=>{let t=T.value.indexOf(e.id);t>=0?T.value.splice(t,1):T.value.push(e.id)}},_(e.label),11,X))),128)),T.value.length?(S(),a(`button`,{key:0,class:`mp-chip clear`,onClick:f[2]||=e=>T.value=[]},_(c(U)(`@MKT:全部来源`)),1)):s(``,!0)])]),N((S(),a(`div`,ve,[(S(!0),a(B,null,g(m.value,t=>(S(),a(`section`,{key:t.id,class:`mp-group`},[z(`header`,ye,[z(`h3`,be,_(t.label),1),t.status===`ok`?(S(),a(`span`,xe,_(t.items.length),1)):(S(),a(`span`,Se,[d(p,null,{default:D(()=>[d(c(ne))]),_:1}),j(` `+_(t.error||c(U)(`@MKT:来源不可用`)),1)])),t.homepage?(S(),a(`a`,{key:2,class:`mp-group-link`,href:t.homepage,target:`_blank`,rel:`noopener noreferrer`,title:t.homepage},[d(p,null,{default:D(()=>[d(c(o))]),_:1})],8,Ce)):s(``,!0)]),t.status===`ok`&&t.items.length?(S(),a(`div`,we,[(S(!0),a(B,null,g(t.items,t=>(S(),a(`article`,{key:q(t),class:`mp-card`},[z(`div`,Te,[z(`span`,{class:`mp-card-name`,title:t.name},_(t.name),9,Z),G(t)?(S(),a(`span`,Ee,[d(p,null,{default:D(()=>[t.stars?(S(),y(c(te),{key:0})):(S(),y(c(O),{key:1}))]),_:2},1024),j(` `+_(G(t)),1)])):s(``,!0)]),z(`p`,{class:`mp-card-desc`,title:t.description},_(t.description||c(U)(`@MKT:暂无描述`)),9,De),z(`div`,Q,[t.package?(S(),a(`code`,{key:0,class:`mp-meta-pkg`,title:t.package},_(t.package),9,$)):t.repository?(S(),a(`span`,{key:1,class:`mp-meta-repo`,title:t.repository+(t.subpath?` · `+t.subpath:``)},[j(_(t.repository),1),t.subpath?(S(),a(B,{key:0},[j(` · `+_(t.subpath),1)],64)):s(``,!0)],8,Oe)):s(``,!0),t.transport===`remote`?(S(),a(`span`,ke,_(c(U)(`@MKT:远程服务`)),1)):s(``,!0),(S(!0),a(B,null,g((t.tags||[]).slice(0,2),e=>(S(),a(`span`,{key:e,class:`mp-tag`},_(e),1))),128))]),z(`div`,Ae,[t.upstream?(S(),a(`a`,{key:0,class:`mp-card-link`,href:t.upstream,target:`_blank`,rel:`noopener noreferrer`},_(c(U)(`@MKT:查看来源`)),9,je)):s(``,!0),f[6]||=z(`span`,{class:`mp-foot-spacer`},null,-1),t.installed?(S(),a(`span`,Me,[d(p,null,{default:D(()=>[d(c(e))]),_:1}),j(_(c(U)(`@MKT:已安装`)),1)])):t.installable===!1?(S(),a(`span`,Pe,_(c(U)(`@MKT:暂不支持一键安装`)),1)):(S(),a(`button`,{key:2,class:`mp-install-btn`,disabled:ce(t),onClick:e=>et(t)},_(ce(t)?c(U)(`@MKT:安装中...`):c(U)(`@MKT:安装`)),9,Ne))])]))),128))])):t.status===`ok`?(S(),a(`div`,Fe,_(c(U)(`@MKT:该来源暂无结果`)),1)):s(``,!0)]))),128)),h.value.length?(S(),a(`section`,Ie,[z(`header`,Le,[z(`h3`,Re,_(c(U)(`@MKT:已安装`)),1),z(`span`,ze,_(h.value.length),1)]),(S(),a(B,null,g([`project`,`global`],e=>z(`div`,{key:e},[le.value[e]?.length?(S(),a(`div`,Be,[z(`div`,Ve,_(e===`project`?c(U)(`@MKT:当前项目`):c(U)(`@MKT:g ai 智能体`)),1),z(`div`,He,[(S(!0),a(B,null,g(le.value[e],t=>(S(),a(`div`,{key:e+t.id,class:`mp-installed-row`},[z(`span`,Ue,_(t.name),1),t.package?(S(),a(`code`,We,_(t.package),1)):s(``,!0),t.requiredEnv?.length?(S(),a(`span`,Ge,_(c(U)(`@MKT:待配置`))+`: `+_(t.requiredEnv.join(`, `)),1)):s(``,!0),f[7]||=z(`span`,{class:`mp-foot-spacer`},null,-1),z(`button`,{class:`mp-remove-btn`,disabled:R.value.has(e+t.id),onClick:e=>rt(t)},[d(p,null,{default:D(()=>[d(c(re))]),_:1}),j(` `+_(R.value.has(e+t.id)?c(U)(`@MKT:卸载中...`):c(U)(`@MKT:卸载`)),1)],8,Ke)]))),128))])])):s(``,!0)])),64))])):s(``,!0),!v.value&&!m.value.length?(S(),a(`div`,qe,_(c(U)(`@MKT:加载失败`)),1)):s(``,!0)])),[[A,v.value]]),d(oe,{modelValue:J.visible,"onUpdate:modelValue":f[5]||=e=>J.visible=e,title:c(U)(`@MKT:配置 MCP`),width:`460px`,type:`flex`,"close-on-click-modal":!1,"append-to-body":``},{footer:D(()=>[z(`button`,{class:`mkt-cancel`,onClick:f[4]||=e=>J.visible=!1},_(c(U)(`@MKT:取消`)),1),z(`button`,{class:`mkt-confirm`,onClick:$e},_(c(U)(`@MKT:安装`)),1)]),default:D(()=>[J.item?(S(),a(`div`,Je,[z(`p`,Ye,_(J.item.name),1),(S(!0),a(B,null,g(Object.keys(J.env),e=>(S(),a(`div`,{key:e,class:`mkt-field`},[z(`label`,null,_(e),1),N(z(`input`,{"onUpdate:modelValue":t=>J.env[e]=t,type:`text`,autocomplete:`off`,placeholder:c(U)(`@MKT:环境变量值`),spellcheck:`false`},null,8,Xe),[[k,J.env[e]]])]))),128)),J.item.args?.length?(S(),a(`div`,Ze,[z(`label`,null,_(c(U)(`@MKT:启动参数`)),1),N(z(`input`,{"onUpdate:modelValue":f[3]||=e=>J.args=e,type:`text`,autocomplete:`off`,spellcheck:`false`},null,512),[[k,J.args]]),z(`p`,Qe,_(c(U)(`@MKT:参数提示`)),1)])):s(``,!0)])):s(``,!0)]),_:1},8,[`modelValue`,`title`])])}}}),[[`__scopeId`,`data-v-6788a7b1`]]);v(),I(),m();var et={class:`agent-chat-area`},tt={class:`agent-tabs`,role:`tablist`},nt=[`aria-selected`,`onClick`],rt={class:`agent-tab-body`},it={key:0,class:`agent-chat-pane`},at={key:0,class:`agent-list-page`},ot={key:0,class:`agent-page-bar`},st=[`title`,`aria-label`],ct={class:`agent-page-title`},lt={key:0,class:`chat-loading`},ut=W(p({__name:`AgentView`,setup(e){let t=ae(),n=E(null),{narrow:o}=ue(n),l=E(`chat`),p=E(`chat`),m=r(()=>p.value===`mcp`?`mcp`:`skill`),v=r(()=>[{id:`chat`,label:U(`@AGENT:对话`),icon:h},{id:`skill`,label:U(`@AGENT:Skill 广场`),icon:i},{id:`mcp`,label:U(`@AGENT:MCP 广场`),icon:T}]),{sessions:x,sessionsLoading:w,currentSessionId:O,messages:k,isStreaming:A,sessionLoading:ee,loadSessions:j,loadSession:M,deleteSession:N,renameSession:P,newSession:I,sendMessage:te,pendingQuestion:ne,answeringQuestion:re,answerQuestion:ie,isSessionGenerating:W,currentEngine:oe,pendingEngine:fe,isEngineLocked:Y,pickEngine:pe,stop:me}=le(),he=r(()=>Y.value?oe.value:fe.value);function ge(e){Y.value||pe(e)}let _e=r(()=>{let e=t.theme;return e===`dark`||e===`auto`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}),X=r(()=>se(x.value,W)),ve=ce(),ye=r(()=>X.value.find(e=>e.id===O.value)?.title||U(`@AGENT:对话`)),be={"--welcome-avatar":`url("${J}")`},xe=r(()=>[{id:`p1`,label:U(`@AGENT:查看项目结构`),prompt:U(`@AGENT:prompt_p1`)},{id:`p2`,label:U(`@AGENT:分析代码质量`),prompt:U(`@AGENT:prompt_p2`)},{id:`p3`,label:U(`@AGENT:帮我写测试`),prompt:U(`@AGENT:prompt_p3`)},{id:`p4`,label:U(`@AGENT:Git 状态检查`),prompt:U(`@AGENT:prompt_p4`)},{id:`p5`,label:U(`@AGENT:帮我启动项目`),prompt:U(`@AGENT:prompt_p5`)}]);async function Se(e){await te(e.text,e.files),await b(),Z()}async function Ce(e){await te(e.prompt),await b(),Z()}let we=G(),Te=E(null);function Z(e=!0){Te.value?.scrollToBottom(e)}F(()=>k.value.length,()=>{b(()=>Z(!1))});function Ee(e){M(e),l.value=`chat`}function De(){I(),l.value=`chat`}let Q=E(280),$=E(!1);function Oe(e){$.value=!0;let t=e.clientX,n=Q.value,r=e=>{let r=e.clientX-t,i=Math.max(200,Math.min(500,n+r));Q.value=i},i=()=>{$.value=!1,document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)}return F(o,e=>{e||(l.value=`chat`)}),F(()=>[t.currentDirectory,A.value],async([e,t],n)=>{let r=!n||e!==n[0],i=!!n&&n[1]===!0&&!t;(r||i)&&await j(),O.value&&!A.value&&!x.value.some(e=>e.sessionId===O.value)&&I()},{immediate:!0}),(e,t)=>(S(),a(`div`,{ref_key:`rootRef`,ref:n,class:`agent-view`},[p.value===`chat`&&!c(o)?(S(),a(B,{key:0},[z(`aside`,{class:`agent-sidebar`,style:C({width:Q.value+`px`})},[d(c(H),{class:`agent-conversations`,items:X.value,"active-id":c(O),loading:c(w),labels:c(ve),onSelect:Ee,onNew:De,onRename:c(P),onDelete:c(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],4),z(`div`,{class:L([`sidebar-resizer`,{active:$.value}]),onMousedown:Oe},null,34)],64)):s(``,!0),z(`main`,et,[z(`nav`,tt,[(S(!0),a(B,null,g(v.value,e=>(S(),a(`button`,{key:e.id,type:`button`,class:L([`agent-tab`,{active:p.value===e.id}]),role:`tab`,"aria-selected":p.value===e.id,onClick:t=>p.value=e.id},[d(c(u),null,{default:D(()=>[(S(),y(R(e.icon)))]),_:2},1024),z(`span`,null,_(e.label),1)],10,nt))),128)),p.value===`chat`?(S(),y(de,{key:0,class:`agent-engine`,engine:he.value,locked:c(Y),onSelect:ge},null,8,[`engine`,`locked`])):s(``,!0)]),z(`div`,rt,[p.value===`chat`?(S(),a(`div`,it,[c(o)&&l.value===`list`?(S(),a(`div`,at,[d(c(H),{class:`agent-conversations`,items:X.value,"active-id":c(O),loading:c(w),labels:c(ve),onSelect:Ee,onNew:De,onRename:c(P),onDelete:c(N)},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])])):(S(),a(B,{key:1},[c(o)?(S(),a(`div`,ot,[z(`button`,{type:`button`,class:`agent-page-back`,title:c(U)(`@AGENT:返回会话列表`),"aria-label":c(U)(`@AGENT:返回会话列表`),onClick:t[0]||=e=>l.value=`list`},[...t[1]||=[z(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[z(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),z(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,st),z(`span`,ct,_(ye.value),1)])):s(``,!0),z(`div`,{class:`agent-chat-host`,style:be},[c(ee)?(S(),a(`div`,lt,[d(c(u),{class:`is-loading`,size:32},{default:D(()=>[d(c(f))]),_:1}),z(`span`,null,_(c(U)(`@AGENT:加载会话中...`)),1)])):(S(),y(c(V),{key:1,ref_key:`chatContainerRef`,ref:Te,messages:c(k),"preset-questions":xe.value,"welcome-title":c(U)(`@AGENT:智能体助手`),"welcome-description":c(U)(`@AGENT:我可以帮你阅读代码、执行命令、修改文件。选择下方话题或直接输入你的问题。`),"assistant-name":c(K),"assistant-avatar":c(J),theme:_e.value,disabled:c(A),generating:c(A),"upload-config":{accept:c(q)},placeholder:c(A)?c(U)(`@AGENT:正在生成中...`):c(U)(`@AGENT:输入消息,Enter 发送`),question:c(ne),"question-submitting":c(re),"question-labels":c(we),"plan-config":{labels:{title:c(U)(`@AGENT:计划`),raw:c(U)(`@AGENT:原始参数`)}},onSend:Se,onSelect:Ce,onStop:c(me),onAnswer:c(ie)},null,8,[`messages`,`preset-questions`,`welcome-title`,`welcome-description`,`assistant-name`,`assistant-avatar`,`theme`,`disabled`,`generating`,`upload-config`,`placeholder`,`question`,`question-submitting`,`question-labels`,`plan-config`,`onStop`,`onAnswer`]))])],64))])):(S(),y($e,{key:1,type:m.value},null,8,[`type`]))])])],512))}}),[[`__scopeId`,`data-v-05972cec`]]);export{ut as default};
|