coding-tool-x 3.7.6 → 3.7.8
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/dist/web/assets/{Analytics-wCRLv26m.js → Analytics-BE5H9JGG.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-aa1blEHh.js → ConfigTemplates-z118k1BE.js} +1 -1
- package/dist/web/assets/{Home-eIxO50-k.js → Home-CBhtmOIN.js} +1 -1
- package/dist/web/assets/{PluginManager-BAwGFNjN.js → PluginManager-CGhfZ3t8.js} +1 -1
- package/dist/web/assets/ProjectList-BMPLJtgQ.js +1 -0
- package/dist/web/assets/ProjectList-VeMNXfgO.css +1 -0
- package/dist/web/assets/SessionList-C4chCPxK.css +1 -0
- package/dist/web/assets/SessionList-D9e7wGF1.js +1 -0
- package/dist/web/assets/{SkillManager-Bhzs1O5S.js → SkillManager-DJpdUmnk.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CLdX-pTT.js → WorkspaceManager-C0Ud_V7v.js} +1 -1
- package/dist/web/assets/index-CeTaG4IX.js +2 -0
- package/dist/web/assets/index-S8wrU2Nf.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/commands/daemon.js +3 -1
- package/src/commands/port-config.js +0 -2
- package/src/commands/switch.js +1 -5
- package/src/commands/ui.js +4 -3
- package/src/commands/workspace.js +35 -3
- package/src/config/loader.js +76 -5
- package/src/index.js +11 -0
- package/src/server/api/config.js +0 -3
- package/src/server/api/omp-channels.js +29 -9
- package/src/server/api/omp-config.js +6 -8
- package/src/server/api/settings.js +0 -2
- package/src/server/api/workspaces.js +39 -1
- package/src/server/services/dashboard-snapshot-worker.js +1 -0
- package/src/server/services/https-cert.js +3 -2
- package/src/server/services/model-detector.js +106 -26
- package/src/server/services/omp-auth-providers.js +1 -0
- package/src/server/services/omp-config.js +22 -0
- package/src/server/services/omp-settings-manager.js +31 -16
- package/src/server/services/session-snapshots.js +1 -0
- package/src/server/services/sessions.js +35 -19
- package/src/server/services/web-build.js +2 -1
- package/src/server/services/workspace-service.js +204 -98
- package/src/utils/cli-flags.js +7 -0
- package/src/utils/session.js +10 -4
- package/dist/web/assets/ProjectList-CRiAEixW.js +0 -1
- package/dist/web/assets/ProjectList-Dw2omgOH.css +0 -1
- package/dist/web/assets/SessionList-BQ0FW6Gd.js +0 -1
- package/dist/web/assets/SessionList-kYJ6-Ies.css +0 -1
- package/dist/web/assets/index-B_nFqixU.css +0 -1
- package/dist/web/assets/index-ClMNA9Hf.js +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// 多项目工作区服务
|
|
2
2
|
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const { execFileSync } = require('child_process');
|
|
5
6
|
const { PATHS } = require('../../config/paths');
|
|
@@ -46,6 +47,190 @@ function resolveCurrentBranch(repoPath) {
|
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
function getGitErrorMessage(error) {
|
|
51
|
+
const stderr = error && error.stderr ? error.stderr.toString().trim() : '';
|
|
52
|
+
return stderr || (error && error.message) || String(error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function normalizeString(value) {
|
|
56
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function normalizeBranchMode(projectConfig = {}) {
|
|
60
|
+
const branchMode = normalizeString(projectConfig.branchMode);
|
|
61
|
+
if (branchMode === 'new' || branchMode === 'existing') {
|
|
62
|
+
return branchMode;
|
|
63
|
+
}
|
|
64
|
+
return normalizeString(projectConfig.baseBranch) ? 'new' : 'existing';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeGitBranchRef(branchName) {
|
|
68
|
+
return normalizeString(branchName).replace(/^refs\/heads\//, '');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function parseGitWorktrees(output) {
|
|
72
|
+
const worktrees = [];
|
|
73
|
+
const lines = output.split('\n');
|
|
74
|
+
let current = {};
|
|
75
|
+
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
if (line.startsWith('worktree ')) {
|
|
78
|
+
if (current.path) {
|
|
79
|
+
worktrees.push(current);
|
|
80
|
+
}
|
|
81
|
+
current = { path: line.substring(9) };
|
|
82
|
+
} else if (line.startsWith('branch ')) {
|
|
83
|
+
current.branch = line.substring(7);
|
|
84
|
+
} else if (line.startsWith('HEAD ')) {
|
|
85
|
+
current.head = line.substring(5);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (current.path) {
|
|
90
|
+
worktrees.push(current);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return worktrees;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function listGitWorktrees(repoPath) {
|
|
97
|
+
const output = runGitCommand(['worktree', 'list', '--porcelain'], {
|
|
98
|
+
cwd: repoPath
|
|
99
|
+
});
|
|
100
|
+
return parseGitWorktrees(output);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function hasGitRef(repoPath, ref) {
|
|
104
|
+
try {
|
|
105
|
+
runGitCommand(['show-ref', '--verify', '--quiet', ref], {
|
|
106
|
+
cwd: repoPath,
|
|
107
|
+
stdio: 'ignore'
|
|
108
|
+
});
|
|
109
|
+
return true;
|
|
110
|
+
} catch (_) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function findWorktreeForBranch(repoPath, branchName) {
|
|
116
|
+
const normalizedBranch = normalizeGitBranchRef(branchName);
|
|
117
|
+
const refName = `refs/heads/${normalizedBranch}`;
|
|
118
|
+
return listGitWorktrees(repoPath).find(wt => wt.branch === refName);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function pullBaseBranch(worktreePath, baseBranch) {
|
|
122
|
+
try {
|
|
123
|
+
runGitCommand(['pull', '--ff-only'], { cwd: worktreePath });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
try {
|
|
126
|
+
runGitCommand(['remote', 'get-url', 'origin'], { cwd: worktreePath });
|
|
127
|
+
} catch (_) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const normalizedBaseBranch = normalizeGitBranchRef(baseBranch);
|
|
131
|
+
runGitCommand(['pull', '--ff-only', 'origin', normalizedBaseBranch], {
|
|
132
|
+
cwd: worktreePath
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function removeTemporaryWorktree(repoPath, tempWorktreePath) {
|
|
138
|
+
try {
|
|
139
|
+
runGitCommand(['worktree', 'remove', tempWorktreePath, '--force'], {
|
|
140
|
+
cwd: repoPath
|
|
141
|
+
});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn(`移除临时 worktree 失败: ${tempWorktreePath}`, error.message);
|
|
144
|
+
} finally {
|
|
145
|
+
if (fs.existsSync(tempWorktreePath)) {
|
|
146
|
+
fs.rmSync(tempWorktreePath, { recursive: true, force: true });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function updateBaseBranch(repoPath, baseBranch) {
|
|
152
|
+
const normalizedBaseBranch = normalizeGitBranchRef(baseBranch);
|
|
153
|
+
if (!normalizedBaseBranch) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
runGitCommand(['fetch', '--all', '--prune'], { cwd: repoPath });
|
|
158
|
+
|
|
159
|
+
const localRef = `refs/heads/${normalizedBaseBranch}`;
|
|
160
|
+
const remoteRef = `refs/remotes/origin/${normalizedBaseBranch}`;
|
|
161
|
+
const hasLocalBranch = hasGitRef(repoPath, localRef);
|
|
162
|
+
const hasRemoteBranch = hasGitRef(repoPath, remoteRef);
|
|
163
|
+
if (!hasLocalBranch && !hasRemoteBranch) {
|
|
164
|
+
throw new Error(`基础分支不存在: ${normalizedBaseBranch}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const existingWorktree = hasLocalBranch ? findWorktreeForBranch(repoPath, normalizedBaseBranch) : null;
|
|
168
|
+
if (existingWorktree) {
|
|
169
|
+
pullBaseBranch(existingWorktree.path, normalizedBaseBranch);
|
|
170
|
+
return normalizedBaseBranch;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const tempParent = fs.mkdtempSync(path.join(os.tmpdir(), 'ctx-base-'));
|
|
174
|
+
const tempWorktreePath = path.join(tempParent, 'worktree');
|
|
175
|
+
try {
|
|
176
|
+
if (hasLocalBranch) {
|
|
177
|
+
runGitCommand(['worktree', 'add', tempWorktreePath, normalizedBaseBranch], {
|
|
178
|
+
cwd: repoPath
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
runGitCommand(['worktree', 'add', tempWorktreePath, '-b', normalizedBaseBranch, `origin/${normalizedBaseBranch}`], {
|
|
182
|
+
cwd: repoPath
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
pullBaseBranch(tempWorktreePath, normalizedBaseBranch);
|
|
186
|
+
return normalizedBaseBranch;
|
|
187
|
+
} finally {
|
|
188
|
+
removeTemporaryWorktree(repoPath, tempWorktreePath);
|
|
189
|
+
if (fs.existsSync(tempParent)) {
|
|
190
|
+
fs.rmSync(tempParent, { recursive: true, force: true });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function createGitWorktree({ sourcePath, worktreePath, branch, baseBranch, branchMode, actionLabel }) {
|
|
196
|
+
let targetBranch = normalizeString(branch);
|
|
197
|
+
if (!targetBranch) {
|
|
198
|
+
try {
|
|
199
|
+
targetBranch = resolveCurrentBranch(sourcePath);
|
|
200
|
+
} catch (e) {
|
|
201
|
+
targetBranch = 'main';
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const resolvedBranchMode = branchMode === 'new' ? 'new' : 'existing';
|
|
206
|
+
|
|
207
|
+
if (resolvedBranchMode === 'new') {
|
|
208
|
+
const worktreeArgs = ['worktree', 'add', worktreePath, '-b', targetBranch];
|
|
209
|
+
const updatedBaseBranch = updateBaseBranch(sourcePath, baseBranch);
|
|
210
|
+
if (updatedBaseBranch) {
|
|
211
|
+
worktreeArgs.push(updatedBaseBranch);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
runGitCommand(worktreeArgs, { cwd: sourcePath });
|
|
216
|
+
return { branch: targetBranch, path: worktreePath };
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw new Error(`创建 worktree 失败: ${getGitErrorMessage(error)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
// Existing branches may already be checked out in another worktree.
|
|
224
|
+
// `-f` makes that explicit instead of relying on a version-dependent retry.
|
|
225
|
+
runGitCommand(['worktree', 'add', '-f', worktreePath, targetBranch], {
|
|
226
|
+
cwd: sourcePath
|
|
227
|
+
});
|
|
228
|
+
return { branch: targetBranch, path: worktreePath };
|
|
229
|
+
} catch (error) {
|
|
230
|
+
throw new Error(`创建 worktree 失败: ${getGitErrorMessage(error)}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
49
234
|
/**
|
|
50
235
|
* 生成唯一工作区 ID
|
|
51
236
|
*/
|
|
@@ -147,31 +332,7 @@ function getGitWorktrees(repoPath) {
|
|
|
147
332
|
if (!isGitRepo(repoPath)) {
|
|
148
333
|
return [];
|
|
149
334
|
}
|
|
150
|
-
const
|
|
151
|
-
cwd: repoPath
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const worktrees = [];
|
|
155
|
-
const lines = output.split('\n');
|
|
156
|
-
let current = {};
|
|
157
|
-
|
|
158
|
-
for (const line of lines) {
|
|
159
|
-
if (line.startsWith('worktree ')) {
|
|
160
|
-
if (current.path) {
|
|
161
|
-
worktrees.push(current);
|
|
162
|
-
}
|
|
163
|
-
current = { path: line.substring(9) };
|
|
164
|
-
} else if (line.startsWith('branch ')) {
|
|
165
|
-
current.branch = line.substring(7);
|
|
166
|
-
} else if (line.startsWith('HEAD ')) {
|
|
167
|
-
current.head = line.substring(5);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (current.path) {
|
|
172
|
-
worktrees.push(current);
|
|
173
|
-
}
|
|
174
|
-
|
|
335
|
+
const worktrees = listGitWorktrees(repoPath);
|
|
175
336
|
return worktrees.filter(wt => wt.path !== repoPath); // 排除主仓库
|
|
176
337
|
} catch (error) {
|
|
177
338
|
console.error('获取 worktree 列表失败:', error.message);
|
|
@@ -308,48 +469,19 @@ function createWorkspace(options) {
|
|
|
308
469
|
|
|
309
470
|
// Git 仓库且需要创建 worktree:直接在工作区目录内创建,无需额外 symlink
|
|
310
471
|
if (isGit && useWorktree) {
|
|
311
|
-
// 获取当前分支作为默认分支
|
|
312
|
-
let targetBranch = branch;
|
|
313
|
-
if (!targetBranch) {
|
|
314
|
-
try {
|
|
315
|
-
targetBranch = resolveCurrentBranch(sourcePath);
|
|
316
|
-
} catch (e) {
|
|
317
|
-
targetBranch = 'main';
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
472
|
// worktree 直接创建到工作区目录内的项目路径
|
|
322
473
|
const worktreePath = symlinkPath;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
try {
|
|
332
|
-
const worktreeArgs = ['worktree', 'add', worktreePath, '-b', targetBranch];
|
|
333
|
-
if (baseBranch && baseBranch.trim()) {
|
|
334
|
-
worktreeArgs.push(baseBranch.trim());
|
|
335
|
-
}
|
|
336
|
-
runGitCommand(worktreeArgs, {
|
|
337
|
-
cwd: sourcePath
|
|
338
|
-
});
|
|
339
|
-
} catch (err) {
|
|
340
|
-
if (err.message.includes('already checked out')) {
|
|
341
|
-
throw new Error(
|
|
342
|
-
`无法创建 worktree:分支 '${targetBranch}' 已在其他工作树中检出。\n` +
|
|
343
|
-
`错误详情: ${err.message}\n\n` +
|
|
344
|
-
`提示:请为此项目指定不同的分支名,或禁用 worktree 模式。`
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
throw new Error(`创建 worktree 失败: ${err.message}`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
474
|
+
const createdWorktree = createGitWorktree({
|
|
475
|
+
sourcePath,
|
|
476
|
+
worktreePath,
|
|
477
|
+
branch,
|
|
478
|
+
baseBranch,
|
|
479
|
+
branchMode: normalizeBranchMode(proj),
|
|
480
|
+
actionLabel: '创建 worktree'
|
|
481
|
+
});
|
|
350
482
|
|
|
351
483
|
targetPath = worktreePath;
|
|
352
|
-
worktrees.push(
|
|
484
|
+
worktrees.push(createdWorktree);
|
|
353
485
|
} else if (isGit) {
|
|
354
486
|
// Git 仓库但不创建 worktree:symlink 指向源路径,记录已有 worktrees
|
|
355
487
|
worktrees = getGitWorktrees(sourcePath);
|
|
@@ -509,44 +641,18 @@ function addProjectToWorkspace(workspaceId, projectConfig) {
|
|
|
509
641
|
|
|
510
642
|
// Git 仓库且需要创建 worktree:直接在工作区目录内创建,无需额外 symlink
|
|
511
643
|
if (isGit && useWorktree) {
|
|
512
|
-
let targetBranch = branch;
|
|
513
|
-
if (!targetBranch) {
|
|
514
|
-
try {
|
|
515
|
-
targetBranch = resolveCurrentBranch(sourcePath);
|
|
516
|
-
} catch (e) {
|
|
517
|
-
targetBranch = 'main';
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
644
|
const worktreePath = symlinkPath;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (baseBranch && baseBranch.trim()) {
|
|
531
|
-
worktreeArgs.push(baseBranch.trim());
|
|
532
|
-
}
|
|
533
|
-
runGitCommand(worktreeArgs, { cwd: sourcePath });
|
|
534
|
-
} catch (err) {
|
|
535
|
-
if (err.message && err.message.includes('already checked out')) {
|
|
536
|
-
throw new Error(
|
|
537
|
-
`无法添加项目:分支 '${targetBranch}' 已在其他工作树中检出。\n` +
|
|
538
|
-
`仓库路径: ${sourcePath}\n\n` +
|
|
539
|
-
`解决方案:\n` +
|
|
540
|
-
`1. 指定不同的分支名\n` +
|
|
541
|
-
`2. 或者禁用 worktree 模式(设置 createWorktree: false)`
|
|
542
|
-
);
|
|
543
|
-
}
|
|
544
|
-
throw new Error(`创建 worktree 失败: ${err.message}`);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
645
|
+
const createdWorktree = createGitWorktree({
|
|
646
|
+
sourcePath,
|
|
647
|
+
worktreePath,
|
|
648
|
+
branch,
|
|
649
|
+
baseBranch,
|
|
650
|
+
branchMode: normalizeBranchMode(projectConfig),
|
|
651
|
+
actionLabel: '添加项目'
|
|
652
|
+
});
|
|
547
653
|
|
|
548
654
|
targetPath = worktreePath;
|
|
549
|
-
worktrees.push(
|
|
655
|
+
worktrees.push(createdWorktree);
|
|
550
656
|
} else if (isGit) {
|
|
551
657
|
// Git 仓库但不创建 worktree:symlink 指向源路径
|
|
552
658
|
worktrees = getGitWorktrees(sourcePath);
|
package/src/utils/session.js
CHANGED
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
|
+
const { NATIVE_PATHS } = require('../config/paths');
|
|
6
|
+
|
|
7
|
+
function resolveProjectsDir(config = {}) {
|
|
8
|
+
return config.projectsDir || NATIVE_PATHS.claude.projects;
|
|
9
|
+
}
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* 获取会话目录
|
|
8
13
|
*/
|
|
9
14
|
function getSessionsDir(config) {
|
|
10
|
-
return path.join(config
|
|
15
|
+
return path.join(resolveProjectsDir(config), config.currentProject);
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -196,7 +201,7 @@ function parseLinesWithTail(headLines, tailLines) {
|
|
|
196
201
|
* 获取所有可用的项目
|
|
197
202
|
*/
|
|
198
203
|
async function getAvailableProjects(config) {
|
|
199
|
-
const projectsDir = config
|
|
204
|
+
const projectsDir = resolveProjectsDir(config);
|
|
200
205
|
if (!fs.existsSync(projectsDir)) {
|
|
201
206
|
console.log(chalk.red(`项目目录不存在: ${projectsDir}`));
|
|
202
207
|
return [];
|
|
@@ -204,8 +209,9 @@ async function getAvailableProjects(config) {
|
|
|
204
209
|
|
|
205
210
|
// 获取项目列表和统计信息(包含解析后的名称)
|
|
206
211
|
const { getProjectsWithStats, getProjectOrder } = require('../server/services/sessions');
|
|
207
|
-
const
|
|
208
|
-
const
|
|
212
|
+
const resolvedConfig = { ...config, projectsDir };
|
|
213
|
+
const projects = await getProjectsWithStats(resolvedConfig);
|
|
214
|
+
const savedOrder = getProjectOrder(resolvedConfig);
|
|
209
215
|
const projectList = Array.isArray(projects) ? projects : [];
|
|
210
216
|
|
|
211
217
|
// 按保存的顺序排列
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e,f as a,c as t,o as l,a as s,X as n,s as o,Y as r,N as i,_ as c,G as u,Z as d,p,a0 as v,W as m,a8 as f,a5 as h,w as y,h as g,K as k,F as j,$ as _,a6 as x,R as w,v as b}from"./vue-vendor-B5RqjEjQ.js";import{d as C}from"./vendors-DQA4Hw9v.js";import{_ as z,k as $,l as P,m as L,o as M,p as N,q as T}from"./index-ClMNA9Hf.js";import{a9 as D,T as I,d as R,ad as U,h as E}from"./icons-nGdSKQn2.js";import{N as K,B as q,c as V,a as F,_ as H,q as O,m as S,g as A,x as B,h as G,p as W}from"./naive-ui-CVyvdmg1.js";import"./markdown-BNJfEgCA.js";const X={class:"card-content"},Y={class:"header-row"},Z={class:"project-name"},J={class:"stats-row"},Q=z({__name:"ProjectCard",props:{project:{type:Object,required:!0}},emits:["click","delete"],setup(f,{emit:h}){const y=f,g=h,k=e(!1);function j(){g("click")}function _(){g("delete",y.project)}const x=a(()=>{var e,a;return(null==(e=y.project)?void 0:e.displayName)||(null==(a=y.project)?void 0:a.name)||""}),w=a(()=>{var e,a,t;return(null==(e=y.project)?void 0:e.path)||(null==(a=y.project)?void 0:a.fullPath)||(null==(t=y.project)?void 0:t.name)||""}),b=a(()=>{var e;return(null==(e=y.project)?void 0:e.sessionCount)||0}),C=a(()=>{var e;return null==(e=y.project)?void 0:e.lastUsed}),z=a(()=>{var e;const a=["#18a058","#2080f0","#f0a020","#d03050","#9333ea","#06b6d4"];return a[((null==(e=y.project)?void 0:e.name)||"").split("").reduce((e,a)=>e+a.charCodeAt(0),0)%a.length]});function $(e){if(!e)return"";const a=new Date(e),t=new Date-a;return t<6e4?"刚刚":t<36e5?`${Math.floor(t/6e4)}分钟前`:t<864e5?`${Math.floor(t/36e5)}小时前`:t<6048e5?`${Math.floor(t/864e5)}天前`:a.toLocaleDateString("zh-CN")}return(e,a)=>(l(),t("div",{class:"project-card",onClick:j,onMouseenter:a[0]||(a[0]=e=>k.value=!0),onMouseleave:a[1]||(a[1]=e=>k.value=!1)},[s("div",X,[s("div",Y,[n(i(K),{size:"18",color:z.value},{default:r(()=>[n(i(D))]),_:1},8,["color"]),s("span",Z,c(x.value),1),o(n(i(q),{text:"",type:"error",size:"tiny",class:"delete-btn",onClick:d(_,["stop"])},{icon:r(()=>[n(i(K),{size:"14"},{default:r(()=>[n(i(I))]),_:1})]),_:1},512),[[u,k.value]])]),n(i(V),{depth:"3",class:"project-path"},{default:r(()=>[p(c(w.value),1)]),_:1}),s("div",J,[n(i(F),{size:"tiny",bordered:!1,type:"success"},{default:r(()=>[p(c(b.value)+" 会话 ",1)]),_:1}),C.value?(l(),v(i(V),{key:0,depth:"3",class:"last-used"},{default:r(()=>[p(c($(C.value)),1)]),_:1})):m("",!0)])])],32))}},[["__scopeId","data-v-3a18e66d"]]),ee={class:"project-list-container"},ae={class:"header"},te={class:"header-text"},le={key:0,class:"status-tags",role:"status","aria-live":"polite"},se={key:0,class:"loading-container"},ne={key:1,class:"loading-container compact"},oe={key:4,class:"projects-grid"},re={class:"search-hint"},ie={style:{"margin-bottom":"16px"}},ce={key:0,style:{"max-height":"60vh","overflow-y":"auto"}},ue={class:"search-result-header"},de={class:"search-result-title"},pe=z({__name:"ProjectList",setup(o){const u=f(),d=h(),z=$(),I=a(()=>d.meta.channel||"claude"),X=e(""),Y=e([]),Z=e(null),J=e(!1),pe=e(""),ve=e(null),me=e(!1),fe=e(null),he=a(()=>{const e=X.value.toLowerCase();return Y.value.filter(a=>{const t=(a.displayName||"").toLowerCase(),l=(a.fullPath||"").toLowerCase();return t.includes(e)||l.includes(e)})}),ye=a(()=>{const e=[];return z.projectsRefreshing&&e.push({key:"refreshing",type:"info",text:z.projects.length>0?"后台刷新中":"首次生成中"}),z.projectsUsingFallback&&z.projects.length>0&&e.push({key:"fallback",type:"warning",text:"正在显示缓存数据"}),z.error&&e.push({key:"error",type:"error",text:`刷新失败:${z.error}`}),e});function ge(e){const a=d.meta.channel||"claude";u.push({name:`${a}-sessions`,params:{projectName:e}})}async function ke(){const e=Y.value.map(e=>e.name);await z.saveProjectOrder(e)}function je(e){const a=e.fullPath||e.name,t=e.sessionCount||0;M.warning({title:"删除项目",content:`确定要删除项目 "${a}" 吗?\n\n当前项目包含 ${t} 个会话,删除后所有会话数据将无法恢复!`,positiveText:"确定删除",negativeText:"取消",onPositiveClick:async()=>{try{await z.deleteProject(e.name),L.success("项目已删除")}catch(a){L.error("删除失败: "+a.message)}}})}async function _e(){try{const a="codex"===(e=I.value||"claude")?"codex":"gemini"===e?"gemini":"opencode"===e?"opencode":"omp"===e?"omp":"claude",t=await P(a);if("manual"===(null==t?void 0:t.method))return void L.warning("自动复制失败,已弹出手动复制框");L.success("基础启动命令已复制到剪贴板")}catch(a){L.error("复制失败: "+a.message)}var e}async function xe(){var e;const a=(null==(e=Z.value)?void 0:e.scrollTop)||0;await z.retryProjects(),await b(),Z.value&&(Z.value.scrollTop=a)}async function we(){if(pe.value){me.value=!0;try{const e=await N(pe.value,35,I.value);ve.value=e}catch(e){L.error("搜索失败: "+e.message)}finally{me.value=!1}}}function be(e,a){if(!a||!e)return e;const t=new RegExp(`(${a})`,"gi");return e.replace(t,'<mark style="background-color: #ffd700; padding: 2px 4px; border-radius: 2px; font-weight: 600;">$1</mark>')}function Ce(e){(e.metaKey||e.ctrlKey)&&"k"===e.key&&(e.preventDefault(),J.value=!0,b(()=>{var e;null==(e=fe.value)||e.focus()}))}return y(()=>z.projects,e=>{Y.value=[...e]},{immediate:!0}),y(J,e=>{e||(pe.value="",ve.value=null)}),y(I,e=>{z.setChannel(e),z.fetchProjects()},{immediate:!0}),g(()=>{document.addEventListener("keydown",Ce)}),k(()=>{document.removeEventListener("keydown",Ce)}),(e,a)=>{var o;return l(),t("div",ee,[s("div",ae,[s("div",te,[n(i(H),{style:{margin:"0"}},{default:r(()=>[...a[4]||(a[4]=[p("我的项目",-1)])]),_:1}),n(i(V),{depth:"3"},{default:r(()=>[...a[5]||(a[5]=[p("选择一个项目查看会话,拖拽可调整顺序",-1)])]),_:1}),ye.value.length?(l(),t("div",le,[(l(!0),t(j,null,_(ye.value,e=>(l(),v(i(F),{key:e.key,size:"small",type:e.type,bordered:!1},{default:r(()=>[p(c(e.text),1)]),_:2},1032,["type"]))),128)),i(z).projectsRefreshing||(null==(o=i(z).projectsMeta)?void 0:o.error)||i(z).error?(l(),v(i(q),{key:0,text:"",size:"tiny",loading:i(z).loading,onClick:xe},{default:r(()=>[...a[6]||(a[6]=[p(" 立即刷新 ",-1)])]),_:1},8,["loading"])):m("",!0)])):m("",!0)]),n(i(S),null,{default:r(()=>[n(i(q),{type:"primary",size:"medium",onClick:_e},{icon:r(()=>[n(i(K),null,{default:r(()=>[n(i(R))]),_:1})]),default:r(()=>[a[7]||(a[7]=p(" 新建项目 ",-1))]),_:1}),n(i(O),{value:X.value,"onUpdate:value":a[0]||(a[0]=e=>X.value=e),placeholder:"搜索项目...",clearable:"",class:"search-input"},{prefix:r(()=>[n(i(K),null,{default:r(()=>[n(i(U))]),_:1})]),_:1},8,["value"])]),_:1})]),s("div",{class:"content",ref_key:"contentEl",ref:Z},[i(z).loading&&0===i(z).projects.length&&!i(z).projectsPending?(l(),t("div",se,[n(i(A),{size:"large"},{description:r(()=>[...a[8]||(a[8]=[p(" 加载项目列表... ",-1)])]),_:1})])):i(z).projectsPending?(l(),t("div",ne,[n(i(A),{size:"small"},{description:r(()=>[...a[9]||(a[9]=[p(" 正在生成项目列表... ",-1)])]),_:1})])):i(z).error&&0===i(z).projects.length?(l(),v(i(B),{key:2,type:"error",title:"加载失败",style:{"margin-top":"20px"}},{default:r(()=>[p(c(i(z).error),1)]),_:1})):!X.value&&Y.value.length>0?(l(),v(i(C),{key:3,modelValue:Y.value,"onUpdate:modelValue":a[1]||(a[1]=e=>Y.value=e),"item-key":"name",class:"projects-grid","ghost-class":"ghost","chosen-class":"chosen","drag-class":"drag",animation:"200",onEnd:ke},{item:r(({element:e})=>[n(Q,{project:e,onClick:a=>ge(e.name),onDelete:je},null,8,["project","onClick"])]),_:1},8,["modelValue"])):X.value&&he.value.length>0?(l(),t("div",oe,[(l(!0),t(j,null,_(he.value,e=>(l(),v(Q,{key:e.name,project:e,onClick:a=>ge(e.name),onDelete:je},null,8,["project","onClick"]))),128))])):m("",!0),i(z).loading||i(z).error||i(z).projectsPending||!(!X.value&&0===i(z).projects.length||X.value&&0===he.value.length)?m("",!0):(l(),v(i(G),{key:5,description:X.value?"没有匹配的项目":"没有找到项目",style:{"margin-top":"60px"}},{icon:r(()=>[n(i(K),null,{default:r(()=>[n(i(D))]),_:1})]),_:1},8,["description"]))],512),s("div",re,[n(i(V),{depth:"3",style:{"font-size":"12px"}},{default:r(()=>[...a[10]||(a[10]=[s("kbd",null,"Cmd",-1),p(" / ",-1),s("kbd",null,"Ctrl",-1),p(" + ",-1),s("kbd",null,"K",-1),p(" 全局搜索 ",-1)])]),_:1})]),n(i(W),{show:J.value,"onUpdate:show":a[3]||(a[3]=e=>J.value=e),preset:"card",title:"全局搜索",style:w([{width:"800px","max-width":"90vw"},{marginTop:"80px"}])},{default:r(()=>[s("div",ie,[n(i(O),{ref_key:"globalSearchInputRef",ref:fe,value:pe.value,"onUpdate:value":a[2]||(a[2]=e=>pe.value=e),placeholder:"搜索所有项目的对话内容...",clearable:"",onKeyup:x(we,["enter"]),disabled:me.value},{prefix:r(()=>[n(i(K),null,{default:r(()=>[n(i(U))]),_:1})]),suffix:r(()=>[n(i(q),{text:"",onClick:we,disabled:!pe.value||me.value,loading:me.value},{default:r(()=>[...a[11]||(a[11]=[p(" 搜索 ",-1)])]),_:1},8,["disabled","loading"])]),_:1},8,["value","disabled"])]),ve.value?(l(),t("div",ce,[n(i(B),{type:"info",style:{"margin-bottom":"16px"}},{default:r(()=>[p(' 关键词 "'+c(ve.value.keyword)+'" 共找到 '+c(ve.value.totalMatches)+" 处匹配 ",1)]),_:1}),(l(!0),t(j,null,_(ve.value.sessions,e=>(l(),t("div",{key:`${e.projectName}-${e.sessionId}`,class:"search-result-item"},[s("div",ue,[s("div",de,[n(i(V),{strong:"",style:{"font-size":"15px","font-weight":"700"}},{default:r(()=>[p(c(e.projectDisplayName),1)]),_:2},1024),n(i(V),{depth:"2",style:{margin:"0 8px"}},{default:r(()=>[...a[12]||(a[12]=[p("·",-1)])]),_:1}),n(i(V),{strong:""},{default:r(()=>[p(c(e.alias?`${e.alias} (${e.sessionId.substring(0,8)})`:e.sessionId.substring(0,8)),1)]),_:2},1024),n(i(F),{size:"small",bordered:!1},{default:r(()=>[p(c(e.matchCount)+" 个匹配",1)]),_:2},1024)]),n(i(q),{size:"small",type:"primary",onClick:a=>async function(e,a){try{const{copyResult:t}=await T(e,a,I.value);"manual"===(null==t?void 0:t.method)?L.warning("自动复制失败,已弹出手动复制框"):L.success("启动命令已复制到剪贴板"),J.value=!1}catch(t){L.error("复制失败: "+t.message)}}(e.projectName,e.sessionId)},{icon:r(()=>[n(i(K),null,{default:r(()=>[n(i(E))]),_:1})]),default:r(()=>[a[13]||(a[13]=p(" 使用对话 ",-1))]),_:1},8,["onClick"])]),(l(!0),t(j,null,_(e.matches,(e,a)=>(l(),t("div",{key:a,class:"search-match"},[n(i(F),{size:"tiny",type:"user"===e.role?"info":"success",bordered:!1},{default:r(()=>[p(c("user"===e.role?"用户":"助手"),1)]),_:2},1032,["type"]),n(i(V),{depth:"3",class:"search-match-text",innerHTML:be(e.context,ve.value.keyword)},null,8,["innerHTML"])]))),128))]))),128)),0===ve.value.sessions.length?(l(),v(i(G),{key:0,description:"没有找到匹配的内容"})):m("",!0)])):m("",!0)]),_:1},8,["show"])])}}},[["__scopeId","data-v-31b9e395"]]);export{pe as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.project-card[data-v-3a18e66d]{padding:12px 14px;cursor:pointer;transition:all .25s cubic-bezier(.4,0,.2,1);border-radius:8px;border:1px solid var(--border-primary);box-shadow:0 1px 3px #0000000a;background:var(--bg-primary);position:relative;overflow:hidden}.project-card[data-v-3a18e66d]:before{content:"";position:absolute;top:0;left:0;width:3px;height:100%;background:linear-gradient(180deg,#18a058,#18a05866);opacity:0;transition:opacity .25s ease}.project-card[data-v-3a18e66d]:hover{transform:translateY(-3px);box-shadow:0 8px 20px #18a0581f,0 2px 6px #0000000f;border-color:#18a05866}.project-card[data-v-3a18e66d]:hover:before{opacity:1}.card-content[data-v-3a18e66d]{display:flex;flex-direction:column;gap:6px}.header-row[data-v-3a18e66d]{display:flex;align-items:center;gap:8px}.project-name[data-v-3a18e66d]{font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;color:var(--text-primary);letter-spacing:-.2px}.delete-btn[data-v-3a18e66d]{opacity:.7;transition:opacity .2s;padding:2px!important}.delete-btn[data-v-3a18e66d]:hover{opacity:1}.project-path[data-v-3a18e66d]{font-size:11px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.3}.stats-row[data-v-3a18e66d]{display:flex;align-items:center;justify-content:space-between;margin-top:4px;padding-top:8px;border-top:1px dashed var(--border-primary)}.stats-row[data-v-3a18e66d] .n-tag{font-size:11px;font-weight:600;padding:0 6px;height:18px;border-radius:4px}.last-used[data-v-3a18e66d]{font-size:11px;font-weight:500}.project-list-container[data-v-31b9e395]{width:100%;height:100%;display:flex;flex-direction:column;box-sizing:border-box}.header[data-v-31b9e395]{flex-shrink:0;padding:24px 24px 20px;background:var(--gradient-bg);border-bottom:1px solid var(--border-primary);display:flex;justify-content:space-between;align-items:flex-start;gap:24px;position:relative}.header[data-v-31b9e395]:after{content:"";position:absolute;bottom:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,rgba(24,160,88,.1),transparent)}.header-text[data-v-31b9e395]{flex:1}.status-tags[data-v-31b9e395]{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:8px}.header-text[data-v-31b9e395] .n-h2{font-size:26px;font-weight:700;background:linear-gradient(135deg,#1f2937,#374151);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;letter-spacing:-.5px}[data-theme=dark] .header-text[data-v-31b9e395] .n-h2{background:linear-gradient(135deg,#f9fafb,#d1d5db);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.search-input[data-v-31b9e395]{width:320px;flex-shrink:0}.search-input[data-v-31b9e395] .n-input{border-radius:10px;background:var(--bg-primary);border:1px solid var(--border-primary);transition:all .2s ease}.search-input[data-v-31b9e395] .n-input:hover{border-color:var(--border-secondary);box-shadow:var(--shadow-sm)}.search-input[data-v-31b9e395] .n-input:focus-within{border-color:#18a058;box-shadow:0 0 0 3px #18a0581a}.content[data-v-31b9e395]{flex:1;overflow-y:auto;padding:20px 24px 24px;background:var(--gradient-bg)}.loading-container[data-v-31b9e395]{display:flex;justify-content:center;align-items:center;min-height:400px}.loading-container.compact[data-v-31b9e395]{min-height:180px}.projects-grid[data-v-31b9e395]{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.ghost[data-v-31b9e395]{opacity:.4}.chosen[data-v-31b9e395]{transform:scale(1.05);box-shadow:0 8px 24px #0003!important;cursor:move!important}.drag[data-v-31b9e395]{opacity:.8;transform:rotate(2deg);box-shadow:0 12px 32px #00000040!important}.search-hint[data-v-31b9e395]{position:fixed;bottom:24px;left:24px;padding:10px 14px;background:#ffffffe6;border:1px solid var(--border-primary);border-radius:8px;box-shadow:0 4px 12px #00000014;z-index:10;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:.8;transition:all .2s ease}[data-theme=dark] .search-hint[data-v-31b9e395]{background:#1e293bf2;border:1px solid rgba(71,85,105,.6);box-shadow:0 4px 16px #0006}.search-hint[data-v-31b9e395]:hover{opacity:1;transform:translateY(-2px);box-shadow:0 6px 16px #0000001f}[data-theme=dark] .search-hint[data-v-31b9e395]:hover{box-shadow:0 6px 20px #00000080}.search-hint kbd[data-v-31b9e395]{display:inline-block;padding:4px 8px;font-family:SF Mono,Monaco,monospace;font-size:12px;line-height:1.4;font-weight:600;color:var(--text-secondary);background:var(--bg-primary);border:1px solid var(--border-secondary);border-radius:4px;box-shadow:0 2px 0 var(--border-primary),0 1px 3px #0000001a}[data-theme=dark] .search-hint kbd[data-v-31b9e395]{background:#33415599;border:1px solid rgba(71,85,105,.8);box-shadow:0 2px #1e293bcc,0 1px 4px #0006;color:#e2e8f0}.search-result-item[data-v-31b9e395]{margin-bottom:16px;padding:12px;border:1px solid var(--border-primary);border-radius:6px;background:var(--bg-elevated)}.search-result-header[data-v-31b9e395]{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.search-result-title[data-v-31b9e395]{display:flex;align-items:center;gap:8px}.search-match[data-v-31b9e395]{display:flex;align-items:flex-start;gap:8px;margin-top:6px;padding:6px;background:var(--bg-secondary);border-radius:4px}.search-match-text[data-v-31b9e395]{flex:1;line-height:1.6}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a8 as e,a5 as s,f as a,r as l,w as n,h as t,K as i,c as o,o as u,a as r,X as d,a0 as c,W as v,Y as f,N as p,p as m,_ as h,F as y,$ as g,a6 as k,L as _,Z as w,s as b,G as I,y as C,v as z}from"./vue-vendor-B5RqjEjQ.js";import{d as j}from"./vendors-DQA4Hw9v.js";import{_ as x,k as F,r as N,C as S,t as $,m as M,o as B,v as U,q as L}from"./index-ClMNA9Hf.js";import{Z as P,T,ad as A,ay as R,k as q,G as E,a3 as K,az as G,q as H,h as O,Y as V}from"./icons-nGdSKQn2.js";import{N as D,B as W,_ as Y,c as Z,a as X,G as J,q as Q,g as ee,x as se,s as ae,m as le,h as ne,p as te,k as ie}from"./naive-ui-CVyvdmg1.js";import"./markdown-BNJfEgCA.js";const oe={class:"session-list-container"},ue={class:"header"},re={class:"title-bar"},de={class:"title-section"},ce={class:"title-with-count"},ve={class:"header-actions"},fe={key:0,class:"status-tags",role:"status","aria-live":"polite"},pe={key:0,class:"loading-container"},me={key:1,class:"loading-container compact"},he=["onMouseenter","onClick"],ye={key:0,class:"drag-handle"},ge={class:"session-left"},ke={class:"session-icon"},_e={class:"session-info"},we={class:"session-header"},be={class:"session-title-row"},Ie={class:"session-title"},Ce={class:"session-meta"},ze={class:"session-right"},je={class:"session-tags-area"},xe={key:0,class:"session-actions"},Fe={key:0,style:{"max-height":"70vh","overflow-y":"auto"}},Ne={class:"search-result-header"},Se={class:"search-result-title"},$e="__full__",Me=x({__name:"SessionList",props:{projectName:{type:String,required:!0}},setup(x){const Me=x,Be=e(),Ue=s(),Le=F(),{addFavorite:Pe,removeFavorite:Te,isFavorite:Ae}=N(),Re=a(()=>Ue.meta.channel||"claude"),qe=l(Me.projectName),Ee=a(()=>qe.value||Me.projectName),Ke=l(""),Ge=l(!1),He=l(null),Oe=l(""),Ve=l(null),De=l([]),We=l(null),Ye=l(!1),Ze=l(null),Xe=l(!1),Je=l(!1),Qe=l([]),es=l(!1),ss=l(!1),as=l(null),ls=l(""),ns=l($e),ts=l(!1),is=l(!1),os=l([]),us=l(!1),rs=l(""),ds=l(""),cs=l(null),vs={group:{name:`${Re.value}-sessions`,pull:!1,put:!1},forceFallback:!0,fallbackOnBody:!1,fallbackTolerance:4,scroll:!0},fs=a(()=>{var e;return(null==(e=Le.currentProjectInfo)?void 0:e.displayName)||Me.projectName}),ps=a(()=>{var e;return(null==(e=Le.currentProjectInfo)?void 0:e.fullPath)||Ee.value}),ms=a(()=>new Set(Qe.value)),hs=a(()=>Qe.value.length),ys=a(()=>De.value.length>0&&De.value.every(e=>ms.value.has(e.sessionId))),gs=a(()=>hs.value>0&&!ys.value);async function ks(){Le.projects.length||await Le.fetchProjects();const e=Le.projects.find(e=>e.name===Me.projectName);if(e)return qe.value=e.name,e.name;const s=Le.projects.find(e=>e.displayName===Me.projectName||e.fullPath===Me.projectName);return s?(qe.value=s.name,s.name!==Me.projectName&&await Be.replace({name:`${Re.value}-sessions`,params:{projectName:s.name}}),s.name):(qe.value=Me.projectName,Me.projectName)}n(()=>Le.sessionsWithAlias,e=>{De.value=[...e];const s=new Set(e.map(e=>e.sessionId));Qe.value=Qe.value.filter(e=>s.has(e)),Je.value&&0===e.length&&js()},{immediate:!0});const _s=a(()=>{if(!Ke.value)return De.value;const e=Ke.value.toLowerCase();return De.value.filter(s=>s.sessionId.toLowerCase().includes(e)||s.alias&&s.alias.toLowerCase().includes(e)||s.firstMessage&&s.firstMessage.toLowerCase().includes(e)||s.gitBranch&&s.gitBranch.toLowerCase().includes(e))}),ws=a(()=>{const e=[];return Le.sessionsRefreshing&&e.push({key:"refreshing",type:"info",text:Le.sessions.length>0?"后台刷新中":"首次生成中"}),Le.sessionsUsingFallback&&Le.sessions.length>0&&e.push({key:"fallback",type:"warning",text:"正在显示缓存数据"}),Le.error&&e.push({key:"error",type:"error",text:`刷新失败:${Le.error}`}),e});function bs(){const e=Ue.meta.channel||"claude";Be.push({name:`${e}-projects`})}async function Is(){if(Ke.value){Xe.value=!0;try{const e=await $(Ee.value,Ke.value,35,Re.value);We.value=e,Ye.value=!0}catch(e){M.error("搜索失败: "+e.message)}finally{Xe.value=!1}}}async function Cs(){const e=De.value.map(e=>e.sessionId);await Le.saveSessionOrder(e)}function zs(){Je.value=!0,Ve.value=null}function js(){Je.value=!1,Qe.value=[],Ve.value=null}function xs(e){return ms.value.has(e)}function Fs(e,s=!xs(e)){const a=new Set(Qe.value);s?a.add(e):a.delete(e),Qe.value=Array.from(a)}function Ns(e){Qe.value=e?De.value.map(e=>e.sessionId):[]}function Ss(e){Je.value?Fs(e.sessionId):function(e){rs.value=e.sessionId,ds.value=e.alias||"",us.value=!0,z(()=>{var e;null==(e=cs.value)||e.open()})}(e)}async function $s(){if(He.value)try{const e=He.value.sessionId;Oe.value?(await Le.setAlias(e,Oe.value),M.success("别名设置成功")):(await Le.deleteAlias(e),M.success("别名已删除")),Ge.value=!1,He.value=null,Oe.value=""}catch(e){M.error("操作失败: "+e.message)}}function Ms(){ss.value=!1,as.value=null,ls.value="",ns.value=$e,os.value=[],ts.value=!1,is.value=!1}async function Bs(){var e;if(as.value)try{is.value=!0,await Le.forkSession(as.value.sessionId,{afterUserMessageNumber:ns.value===$e?null:ns.value,alias:(null==(e=ls.value)?void 0:e.trim())||void 0}),M.success("Fork 成功!"),Ms()}catch(s){M.error("Fork 失败: "+s.message)}finally{is.value=!1}}function Us(e){M.error(e)}function Ls(e){const s=new Set((e||[]).filter(Boolean));0!==s.size&&(Qe.value=Qe.value.filter(e=>!s.has(e)),rs.value&&s.has(rs.value)&&(us.value=!1,rs.value="",ds.value=""))}async function Ps(e){try{const{copyResult:s}=await L(Ee.value,e,Re.value);if("manual"===(null==s?void 0:s.method))return void M.warning("自动复制失败,已弹出手动复制框");M.success("启动命令已复制到剪贴板")}catch(s){M.error("复制失败: "+s.message)}}function Ts(){if(0===hs.value)return void M.warning("请先选择要删除的会话");const e=[...Qe.value];B.warning({title:"批量删除会话",content:`确定要删除选中的 ${e.length} 个会话吗?此操作不可恢复!`,positiveText:"确定删除",negativeText:"取消",onPositiveClick:async()=>{es.value=!0;try{const s=await Le.deleteSessions(e);if(Ls(s.deletedSessionIds),0===s.failed.length)return M.success(`已删除 ${s.deletedSessionIds.length} 个会话`),void js();Qe.value=s.failed.map(e=>e.sessionId),s.deletedSessionIds.length>0?M.warning(`已删除 ${s.deletedSessionIds.length} 个会话,${s.failed.length} 个删除失败`):M.error(`删除失败: ${s.failed[0].error.message}`)}finally{es.value=!1}}})}function As(e){if(!e)return"";return new Date(e).toLocaleString("zh-CN")}function Rs(e){if(!e)return"0 B";const s=1024;return e<s?e+" B":e<s*s?(e/s).toFixed(1)+" KB":(e/s/s).toFixed(1)+" MB"}function qs(e,s){if(!s||!e)return e;const a=new RegExp(`(${s})`,"gi");return e.replace(a,'<mark style="background-color: #ffd700; padding: 2px 4px; border-radius: 2px; font-weight: 600;">$1</mark>')}function Es(e,s=80){return e?e.length>s?e.substring(0,s)+"...":e:""}async function Ks(){var e;const s=(null==(e=Ze.value)?void 0:e.scrollTop)||0,a=await ks();await Le.retrySessions(a),await z(),Ze.value&&(Ze.value.scrollTop=s)}return n([Re,()=>Me.projectName],([e])=>{js(),Le.setChannel(e),async function(e={}){const s=await ks();await Le.fetchSessions(s,e)}()},{immediate:!0}),t(()=>{}),i(()=>{}),(e,s)=>{var a;return u(),o("div",oe,[r("div",ue,[r("div",re,[d(p(W),{size:"small",onClick:bs,class:"back-button"},{icon:f(()=>[d(p(D),{size:"18"},{default:f(()=>[d(p(P))]),_:1})]),_:1}),r("div",de,[r("div",ce,[d(p(Y),null,{default:f(()=>[m(h(fs.value),1)]),_:1}),d(p(Z),{depth:"3",class:"session-count"},{default:f(()=>[m("("+h(p(Le).sessions.length)+" 个对话)",1)]),_:1}),d(p(X),{size:"small",bordered:!1,type:"info",class:"total-size-tag"},{default:f(()=>[m(h(Rs(p(Le).totalSize)),1)]),_:1}),r("div",ve,[Je.value?(u(),o(y,{key:0},[d(p(J),{checked:ys.value,indeterminate:gs.value,disabled:0===De.value.length||es.value,"onUpdate:checked":Ns},{default:f(()=>[...s[12]||(s[12]=[m(" 全选 ",-1)])]),_:1},8,["checked","indeterminate","disabled"]),d(p(Z),{depth:"3"},{default:f(()=>[m("已选 "+h(hs.value)+" 个",1)]),_:1}),d(p(W),{size:"small",type:"error",disabled:0===hs.value,loading:es.value,onClick:Ts},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(T))]),_:1})]),default:f(()=>[s[13]||(s[13]=m(" 删除 ",-1))]),_:1},8,["disabled","loading"]),d(p(W),{size:"small",disabled:es.value,onClick:js},{default:f(()=>[...s[14]||(s[14]=[m(" 完成 ",-1)])]),_:1},8,["disabled"])],64)):(u(),c(p(W),{key:1,size:"small",type:"error",secondary:"",onClick:zs},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(T))]),_:1})]),default:f(()=>[s[15]||(s[15]=m(" 管理 ",-1))]),_:1}))])]),d(p(Z),{depth:"3",class:"project-path"},{default:f(()=>[m(h(ps.value),1)]),_:1}),ws.value.length?(u(),o("div",fe,[(u(!0),o(y,null,g(ws.value,e=>(u(),c(p(X),{key:e.key,size:"small",type:e.type,bordered:!1},{default:f(()=>[m(h(e.text),1)]),_:2},1032,["type"]))),128)),p(Le).sessionsRefreshing||(null==(a=p(Le).sessionsMeta)?void 0:a.error)||p(Le).error?(u(),c(p(W),{key:0,text:"",size:"tiny",loading:p(Le).loading,onClick:Ks},{default:f(()=>[...s[16]||(s[16]=[m(" 立即刷新 ",-1)])]),_:1},8,["loading"])):v("",!0)])):v("",!0)]),d(p(Q),{value:Ke.value,"onUpdate:value":s[0]||(s[0]=e=>Ke.value=e),placeholder:"搜索会话...",clearable:"",class:"search-input",onKeyup:k(Is,["enter"]),disabled:Xe.value},{prefix:f(()=>[d(p(D),null,{default:f(()=>[d(p(A))]),_:1})]),suffix:f(()=>[d(p(W),{text:"",onClick:Is,disabled:!Ke.value||Xe.value,loading:Xe.value},{default:f(()=>[...s[17]||(s[17]=[m(" 搜索 ",-1)])]),_:1},8,["disabled","loading"])]),_:1},8,["value","disabled"])])]),r("div",{class:"content",ref_key:"contentEl",ref:Ze},[p(Le).loading&&0===p(Le).sessions.length&&!p(Le).sessionsPending?(u(),o("div",pe,[d(p(ee),{size:"large"},{description:f(()=>[...s[18]||(s[18]=[m(" 加载会话列表... ",-1)])]),_:1})])):p(Le).sessionsPending?(u(),o("div",me,[d(p(ee),{size:"small"},{description:f(()=>[...s[19]||(s[19]=[m(" 正在生成会话列表... ",-1)])]),_:1})])):p(Le).error&&0===p(Le).sessions.length?(u(),c(p(se),{key:2,type:"error",title:"加载失败",style:{"margin-bottom":"16px"}},{default:f(()=>[m(h(p(Le).error),1)]),_:1})):_s.value.length>0?(u(),c(p(j),C({key:3,modelValue:De.value,"onUpdate:modelValue":s[3]||(s[3]=e=>De.value=e),"item-key":"sessionId",class:"sessions-list",handle:".drag-handle",disabled:Je.value||es.value},vs,{"ghost-class":"ghost","chosen-class":"chosen",animation:"200",onEnd:Cs}),{item:f(({element:e})=>[r("div",{class:_(["session-item",{"session-item-selected":xs(e.sessionId),"session-item-selection-mode":Je.value}]),onMouseenter:s=>Ve.value=e.sessionId,onMouseleave:s[2]||(s[2]=e=>Ve.value=null),onClick:s=>Ss(e)},[Je.value?(u(),o("div",{key:1,class:"selection-checkbox",onClick:s[1]||(s[1]=w(()=>{},["stop"]))},[d(p(J),{checked:xs(e.sessionId),"onUpdate:checked":s=>Fs(e.sessionId,s)},null,8,["checked","onUpdate:checked"])])):(u(),o("div",ye,[d(p(D),{size:"16",color:"#999"},{default:f(()=>[d(p(R))]),_:1})])),r("div",ge,[r("div",ke,[d(p(D),{size:"24",color:"#18a058"},{default:f(()=>[d(p(q))]),_:1})]),r("div",_e,[r("div",we,[r("div",be,[r("span",Ie,h(e.alias?`${e.alias} (${e.sessionId.substring(0,8)})`:e.sessionId),1),e.forkedFrom?(u(),c(p(ae),{key:0,placement:"top"},{trigger:f(()=>[d(p(X),{size:"small",type:"warning",bordered:!1,style:{"margin-left":"8px",cursor:"help"}},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(E))]),_:1})]),default:f(()=>[s[20]||(s[20]=m(" Fork ",-1))]),_:1})]),default:f(()=>[m(" Fork 自: "+h(e.forkedFrom),1)]),_:2},1024)):v("",!0)])]),r("div",Ce,[d(p(Z),{depth:"3"},{default:f(()=>[m(h(As(e.mtime)),1)]),_:2},1024),d(p(Z),{depth:"3"},{default:f(()=>[...s[21]||(s[21]=[m("•",-1)])]),_:1}),d(p(X),{size:"small",bordered:!1},{default:f(()=>[m(h(Rs(e.size)),1)]),_:2},1024)]),e.firstMessage?(u(),c(p(Z),{key:0,depth:"3",class:"session-message"},{default:f(()=>[m(h(Es(e.firstMessage,80)),1)]),_:2},1024)):e.gitBranch||e.summary?v("",!0):(u(),c(p(Z),{key:1,depth:"3",class:"session-message session-message-empty"},{default:f(()=>[...s[22]||(s[22]=[m(" 暂未读取到对话内容 ",-1)])]),_:1}))])]),r("div",ze,[r("div",je,[e.gitBranch?(u(),c(p(X),{key:0,size:"small",type:"info",bordered:!1},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(E))]),_:1})]),default:f(()=>[m(" "+h(e.gitBranch),1)]),_:2},1024)):v("",!0)]),Je.value?v("",!0):(u(),o("div",xe,[d(p(le),null,{default:f(()=>[b(d(p(W),{size:"small",type:"error",onClick:w(s=>{return a=e.sessionId,void B.warning({title:"删除会话",content:"确定要删除这个会话吗?此操作不可恢复!",positiveText:"确定删除",negativeText:"取消",onPositiveClick:async()=>{try{await Le.deleteSession(a),Ls([a]),M.success("会话已删除")}catch(e){M.error("删除失败: "+e.message)}}});var a},["stop"])},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(T))]),_:1})]),default:f(()=>[s[23]||(s[23]=m(" 删除 ",-1))]),_:1},8,["onClick"]),[[I,Ve.value===e.sessionId]]),d(p(W),{size:"small",onClick:w(s=>function(e){He.value=e,Oe.value=e.alias||"",Ge.value=!0}(e),["stop"])},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(K))]),_:1})]),default:f(()=>[s[24]||(s[24]=m(" 别名 ",-1))]),_:1},8,["onClick"]),d(p(W),{size:"small",type:p(Ae)(Re.value,Ee.value,e.sessionId)?"warning":"default",onClick:w(s=>async function(e){const s=Re.value,a=Ae(s,Ee.value,e.sessionId);try{if(a)await Te(s,Ee.value,e.sessionId),M.success("已取消收藏");else{const a={sessionId:e.sessionId,projectName:Ee.value,projectDisplayName:fs.value,projectFullPath:ps.value,alias:e.alias||"",firstMessage:e.firstMessage||"",mtime:e.mtime,size:e.size,gitBranch:e.gitBranch||"",forkedFrom:e.forkedFrom||""};await Pe(s,a),M.success("已添加到收藏")}}catch(l){M.error("操作失败: "+l.message)}}(e),["stop"])},{icon:f(()=>[d(p(D),null,{default:f(()=>[p(Ae)(Re.value,Ee.value,e.sessionId)?(u(),c(p(G),{key:0})):(u(),c(p(H),{key:1}))]),_:2},1024)]),default:f(()=>[m(" "+h(p(Ae)(Re.value,Ee.value,e.sessionId)?"已收藏":"收藏"),1)]),_:2},1032,["type","onClick"]),"opencode"!==Re.value?(u(),c(p(W),{key:0,size:"small",onClick:w(s=>async function(e){if("opencode"!==Re.value)try{const s=De.value.find(s=>s.sessionId===e);as.value=s||{sessionId:e},ls.value="",ns.value=$e,os.value=[{label:"完整会话末尾(保留全部消息)",value:$e}],ss.value=!0,ts.value=!0;const a=await U(Ee.value,e,Re.value),l=Array.isArray(null==a?void 0:a.items)?a.items:[];os.value=[{label:"完整会话末尾(保留全部消息)",value:$e},...l.map(e=>({label:`保留到第 ${e.userMessageNumber} 条用户消息这一轮 · ${e.preview}`,value:e.userMessageNumber}))]}catch(s){M.error("加载 Fork 位置失败: "+s.message),Ms()}finally{ts.value=!1}else M.warning("OpenCode 当前不支持该 Fork 操作")}(e.sessionId),["stop"])},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(E))]),_:1})]),default:f(()=>[s[25]||(s[25]=m(" Fork ",-1))]),_:1},8,["onClick"])):v("",!0),d(p(W),{size:"small",type:"primary",onClick:w(s=>Ps(e.sessionId),["stop"])},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(O))]),_:1})]),default:f(()=>[s[26]||(s[26]=m(" 使用对话 ",-1))]),_:1},8,["onClick"])]),_:2},1024)]))])],42,he)]),_:1},16,["modelValue","disabled"])):(u(),c(p(ne),{key:4,description:"没有找到会话",style:{"margin-top":"60px"}},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(V))]),_:1})]),_:1}))],512),d(p(te),{show:Ge.value,"onUpdate:show":s[6]||(s[6]=e=>Ge.value=e),preset:"dialog",title:"设置别名"},{action:f(()=>[d(p(le),null,{default:f(()=>[d(p(W),{onClick:s[5]||(s[5]=e=>Ge.value=!1)},{default:f(()=>[...s[27]||(s[27]=[m("取消",-1)])]),_:1}),d(p(W),{type:"primary",onClick:$s},{default:f(()=>[...s[28]||(s[28]=[m("确定",-1)])]),_:1})]),_:1})]),default:f(()=>[d(p(Q),{value:Oe.value,"onUpdate:value":s[4]||(s[4]=e=>Oe.value=e),placeholder:"输入别名(留空删除)",onKeyup:k($s,["enter"])},null,8,["value"])]),_:1},8,["show"]),d(p(te),{show:ss.value,"onUpdate:show":s[9]||(s[9]=e=>ss.value=e),preset:"dialog",title:"Fork 对话"},{action:f(()=>[d(p(le),null,{default:f(()=>[d(p(W),{disabled:is.value,onClick:Ms},{default:f(()=>[...s[30]||(s[30]=[m("取消",-1)])]),_:1},8,["disabled"]),d(p(W),{type:"primary",loading:is.value,onClick:Bs},{default:f(()=>[...s[31]||(s[31]=[m(" 确认 Fork ",-1)])]),_:1},8,["loading"])]),_:1})]),default:f(()=>[d(p(le),{vertical:"",size:14},{default:f(()=>[d(p(Z),{depth:"3"},{default:f(()=>[...s[29]||(s[29]=[m(" 可选择保留到第几条用户消息所在轮次;会包含这条消息后 AI 的完整输出。 ",-1)])]),_:1}),d(p(ie),{value:ns.value,"onUpdate:value":s[7]||(s[7]=e=>ns.value=e),options:os.value,loading:ts.value,clearable:"",placeholder:"选择保留到哪一轮(默认完整会话)"},null,8,["value","options","loading"]),d(p(Q),{value:ls.value,"onUpdate:value":s[8]||(s[8]=e=>ls.value=e),placeholder:"输入新会话别名(可选)",maxlength:"120"},null,8,["value"])]),_:1})]),_:1},8,["show"]),d(p(te),{show:Ye.value,"onUpdate:show":s[10]||(s[10]=e=>Ye.value=e),preset:"card",title:"搜索结果",style:{width:"1200px"}},{default:f(()=>[We.value?(u(),o("div",Fe,[d(p(se),{type:"info",style:{"margin-bottom":"16px"}},{default:f(()=>[m(' 关键词 "'+h(We.value.keyword)+'" 共找到 '+h(We.value.totalMatches)+" 处匹配 ",1)]),_:1}),(u(!0),o(y,null,g(We.value.sessions,e=>(u(),o("div",{key:e.sessionId,class:"search-result-item"},[r("div",Ne,[r("div",Se,[d(p(Z),{strong:""},{default:f(()=>[m(h(e.alias?`${e.alias} (${e.sessionId.substring(0,8)})`:e.sessionId.substring(0,8)),1)]),_:2},1024),d(p(X),{size:"small",bordered:!1},{default:f(()=>[m(h(e.matchCount)+" 个匹配",1)]),_:2},1024)]),d(p(W),{size:"small",type:"primary",onClick:s=>Ps(e.sessionId)},{icon:f(()=>[d(p(D),null,{default:f(()=>[d(p(O))]),_:1})]),default:f(()=>[s[32]||(s[32]=m(" 使用对话 ",-1))]),_:1},8,["onClick"])]),(u(!0),o(y,null,g(e.matches,(e,s)=>(u(),o("div",{key:s,class:"search-match"},[d(p(X),{size:"tiny",type:"user"===e.role?"info":"success",bordered:!1},{default:f(()=>[m(h("user"===e.role?"用户":"助手"),1)]),_:2},1032,["type"]),d(p(Z),{depth:"3",class:"search-match-text",innerHTML:qs(e.context,We.value.keyword)},null,8,["innerHTML"])]))),128))]))),128)),0===We.value.sessions.length?(u(),c(p(ne),{key:0,description:"没有找到匹配的内容"})):v("",!0)])):v("",!0)]),_:1},8,["show"]),rs.value?(u(),c(S,{key:0,ref_key:"chatHistoryRef",ref:cs,show:us.value,"onUpdate:show":s[11]||(s[11]=e=>us.value=e),"project-name":Ee.value,"session-id":rs.value,"session-alias":ds.value,channel:Re.value,onError:Us},null,8,["show","project-name","session-id","session-alias","channel"])):v("",!0)])}}},[["__scopeId","data-v-1660d94f"]]);export{Me as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.session-list-container[data-v-1660d94f]{width:100%;height:100%;display:flex;flex-direction:column;box-sizing:border-box}.header[data-v-1660d94f]{flex-shrink:0;padding:24px 24px 16px;background:var(--bg-primary);border-bottom:1px solid var(--border-primary)}.content[data-v-1660d94f]{flex:1;overflow-y:auto;overflow-x:hidden;padding:16px 24px 24px}.sessions-list[data-v-1660d94f]{position:relative;overflow:hidden}.back-button[data-v-1660d94f]{flex-shrink:0;margin-right:12px}.title-bar[data-v-1660d94f]{display:flex;align-items:center;gap:16px}.title-section[data-v-1660d94f]{flex:1;min-width:0}.title-with-count[data-v-1660d94f]{display:flex;align-items:center;gap:8px;margin-bottom:2px;flex-wrap:wrap}.title-section h2[data-v-1660d94f]{margin:0;font-size:20px}.session-count[data-v-1660d94f]{font-size:14px;color:#666}.total-size-tag[data-v-1660d94f]{margin-left:8px}.project-path[data-v-1660d94f]{font-size:13px;display:block;color:#666;margin-bottom:2px}.status-tags[data-v-1660d94f]{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:6px}.header-actions[data-v-1660d94f]{display:flex;align-items:center;gap:12px;margin-left:4px}.search-input[data-v-1660d94f]{width:320px;flex-shrink:0}.loading-container[data-v-1660d94f]{display:flex;justify-content:center;align-items:center;min-height:400px}.loading-container.compact[data-v-1660d94f]{min-height:180px}.session-item[data-v-1660d94f]{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-primary);border:1px solid var(--border-primary);border-radius:8px;margin-bottom:8px;transition:all .2s;cursor:pointer}.session-item[data-v-1660d94f]:hover{border-color:#18a058;box-shadow:0 2px 8px #18a0581a}.session-item-selection-mode[data-v-1660d94f]{cursor:default}.session-item-selected[data-v-1660d94f]{border-color:#18a058;box-shadow:0 0 0 2px #18a0581f;background:#18a0580a}.drag-handle[data-v-1660d94f]{cursor:move;width:24px;height:24px;padding:4px;opacity:.4;transition:all .2s;flex-shrink:0;display:flex;align-items:center;justify-content:center}.session-item:hover .drag-handle[data-v-1660d94f]{opacity:1;background-color:#18a0581a;border-radius:4px}.selection-checkbox[data-v-1660d94f]{width:24px;min-width:24px;display:flex;align-items:center;justify-content:center}.session-left[data-v-1660d94f]{flex:1;display:flex;align-items:center;gap:16px;min-width:0}.session-icon[data-v-1660d94f]{flex-shrink:0}.session-info[data-v-1660d94f]{flex:1;min-width:0}.session-header[data-v-1660d94f]{display:flex;align-items:center;margin-bottom:6px}.session-title-row[data-v-1660d94f]{display:flex;align-items:center;gap:8px}.session-title[data-v-1660d94f]{font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.session-meta[data-v-1660d94f]{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:13px}.session-message[data-v-1660d94f]{display:block;max-width:600px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.session-message-empty[data-v-1660d94f]{font-style:italic;opacity:.5}.session-right[data-v-1660d94f]{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-end;min-width:280px;flex-shrink:0;gap:12px}.session-tags-area[data-v-1660d94f]{min-height:24px;display:flex;align-items:flex-start;justify-content:flex-end}.session-actions[data-v-1660d94f]{display:flex;align-items:center;margin-top:auto}.ghost[data-v-1660d94f]{opacity:.4}.chosen[data-v-1660d94f]{box-shadow:0 4px 16px #00000026}.search-result-item[data-v-1660d94f]{margin-bottom:16px;padding:12px;border:1px solid var(--border-primary);border-radius:6px;background:var(--bg-elevated)}.search-result-header[data-v-1660d94f]{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.search-result-title[data-v-1660d94f]{display:flex;align-items:center;gap:8px}.search-match[data-v-1660d94f]{display:flex;align-items:flex-start;gap:8px;margin-top:6px;padding:6px;background:var(--bg-secondary);border-radius:4px}.search-match-text[data-v-1660d94f]{flex:1;line-height:1.6}
|