coding-tool-x 3.5.8 → 3.5.9
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-BzoNzfbi.js → Analytics-C5W3axXs.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-O4ikBt1o.js → ConfigTemplates-DzyVFDx9.js} +1 -1
- package/dist/web/assets/{Home-BQjsnblU.js → Home-C9TQNB6f.js} +1 -1
- package/dist/web/assets/{PluginManager-DS_DJnVc.js → PluginManager-9B_brLWT.js} +1 -1
- package/dist/web/assets/{ProjectList-CqYDtsHx.js → ProjectList-Bjt6mrsV.js} +1 -1
- package/dist/web/assets/SessionList-BsHPgmUR.css +1 -0
- package/dist/web/assets/{SessionList-DMlLtMCz.js → SessionList-DcBH13uA.js} +1 -1
- package/dist/web/assets/{SkillManager-DpNE02r0.js → SkillManager-vST8DRRg.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-DMY7_SHh.js → WorkspaceManager-ov1KgRXR.js} +1 -1
- package/dist/web/assets/index-Duc7QP4e.js +2 -0
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/src/server/api/codex-sessions.js +4 -2
- package/src/server/api/opencode-sessions.js +4 -2
- package/src/server/api/sessions.js +4 -2
- package/src/server/services/opencode-sessions.js +12 -2
- package/src/server/services/session-launch-command.js +1 -24
- package/src/server/services/sessions.js +89 -38
- package/dist/web/assets/SessionList-CfPtcq6Y.css +0 -1
- package/dist/web/assets/index-Clf0l3wc.js +0 -2
package/dist/web/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" href="/favicon.ico">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>coding-tool-x · AI 编程工作台</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Duc7QP4e.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/markdown-DyTJGI4N.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vue-vendor-BxIT0uQq.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendors-Bsp-dq2d.js">
|
package/package.json
CHANGED
|
@@ -468,6 +468,7 @@ module.exports = (config) => {
|
|
|
468
468
|
}
|
|
469
469
|
|
|
470
470
|
const { sessionId } = req.params;
|
|
471
|
+
const fork = Boolean(req.body?.fork);
|
|
471
472
|
const fs = require('fs');
|
|
472
473
|
|
|
473
474
|
// 获取会话详情
|
|
@@ -510,7 +511,7 @@ module.exports = (config) => {
|
|
|
510
511
|
broadcastLog({
|
|
511
512
|
type: 'action',
|
|
512
513
|
action: 'launch_codex_session',
|
|
513
|
-
message:
|
|
514
|
+
message: `${fork ? '复制 Codex 会话 Fork 命令' : '复制 Codex 会话启动命令'} ${alias || sessionId.substring(0, 8)}`,
|
|
514
515
|
sessionId: sessionId,
|
|
515
516
|
alias: alias || null,
|
|
516
517
|
timestamp: Date.now()
|
|
@@ -519,7 +520,7 @@ module.exports = (config) => {
|
|
|
519
520
|
const { command, copyCommand } = buildLaunchCommand({
|
|
520
521
|
cwd,
|
|
521
522
|
executable: 'codex',
|
|
522
|
-
args: ['resume', sessionId]
|
|
523
|
+
args: fork ? ['fork', sessionId] : ['resume', sessionId]
|
|
523
524
|
});
|
|
524
525
|
|
|
525
526
|
res.json({
|
|
@@ -528,6 +529,7 @@ module.exports = (config) => {
|
|
|
528
529
|
sessionFile: session.filePath,
|
|
529
530
|
sessionId,
|
|
530
531
|
tool: 'codex',
|
|
532
|
+
fork,
|
|
531
533
|
command,
|
|
532
534
|
copyCommand
|
|
533
535
|
});
|
|
@@ -342,6 +342,7 @@ module.exports = (config) => {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
const { projectName, sessionId } = req.params;
|
|
345
|
+
const fork = Boolean(req.body?.fork);
|
|
345
346
|
|
|
346
347
|
const session = getSessionById(sessionId);
|
|
347
348
|
if (!session) {
|
|
@@ -354,13 +355,13 @@ module.exports = (config) => {
|
|
|
354
355
|
const { command, copyCommand } = buildLaunchCommand({
|
|
355
356
|
cwd,
|
|
356
357
|
executable: 'opencode',
|
|
357
|
-
args: ['
|
|
358
|
+
args: fork ? ['--session', sessionId, '--fork'] : ['--session', sessionId]
|
|
358
359
|
});
|
|
359
360
|
|
|
360
361
|
broadcastLog({
|
|
361
362
|
type: 'action',
|
|
362
363
|
action: 'launch_opencode_session',
|
|
363
|
-
message:
|
|
364
|
+
message: `${fork ? '复制 OpenCode 会话 Fork 命令' : '复制 OpenCode 会话启动命令'} ${sessionId.substring(0, 8)}`,
|
|
364
365
|
sessionId,
|
|
365
366
|
tool: 'opencode',
|
|
366
367
|
timestamp: Date.now()
|
|
@@ -371,6 +372,7 @@ module.exports = (config) => {
|
|
|
371
372
|
cwd,
|
|
372
373
|
sessionId,
|
|
373
374
|
tool: 'opencode',
|
|
375
|
+
fork,
|
|
374
376
|
command,
|
|
375
377
|
copyCommand
|
|
376
378
|
});
|
|
@@ -472,6 +472,7 @@ module.exports = (config) => {
|
|
|
472
472
|
router.post('/:projectName/:sessionId/launch', async (req, res) => {
|
|
473
473
|
try {
|
|
474
474
|
const { projectName, sessionId } = req.params;
|
|
475
|
+
const fork = Boolean(req.body?.fork);
|
|
475
476
|
const path = require('path');
|
|
476
477
|
const fs = require('fs');
|
|
477
478
|
|
|
@@ -564,7 +565,7 @@ module.exports = (config) => {
|
|
|
564
565
|
broadcastLog({
|
|
565
566
|
type: 'action',
|
|
566
567
|
action: 'launch_session',
|
|
567
|
-
message:
|
|
568
|
+
message: `${fork ? '复制会话 Fork 命令' : '复制会话启动命令'} ${alias || sessionId.substring(0, 8)} (claude)`,
|
|
568
569
|
sessionId,
|
|
569
570
|
alias: alias || null,
|
|
570
571
|
tool: 'claude',
|
|
@@ -574,7 +575,7 @@ module.exports = (config) => {
|
|
|
574
575
|
const { command, copyCommand } = buildLaunchCommand({
|
|
575
576
|
cwd,
|
|
576
577
|
executable: 'claude',
|
|
577
|
-
args: ['-r', sessionId]
|
|
578
|
+
args: fork ? ['-r', sessionId, '--fork-session'] : ['-r', sessionId]
|
|
578
579
|
});
|
|
579
580
|
|
|
580
581
|
res.json({
|
|
@@ -583,6 +584,7 @@ module.exports = (config) => {
|
|
|
583
584
|
sessionFile,
|
|
584
585
|
sessionId,
|
|
585
586
|
tool: 'claude',
|
|
587
|
+
fork,
|
|
586
588
|
command,
|
|
587
589
|
copyCommand
|
|
588
590
|
});
|
|
@@ -513,7 +513,13 @@ function getProjects() {
|
|
|
513
513
|
|
|
514
514
|
// 根据项目ID获取会话列表
|
|
515
515
|
function getSessionsByProjectId(projectId) {
|
|
516
|
-
const
|
|
516
|
+
const { getForkRelations } = require('./sessions');
|
|
517
|
+
const forkRelations = getForkRelations();
|
|
518
|
+
const sessions = getSessionRowsByProjectId(projectId).map((session) => {
|
|
519
|
+
const normalized = normalizeSession(session, projectId);
|
|
520
|
+
normalized.forkedFrom = forkRelations[normalized.sessionId] || null;
|
|
521
|
+
return normalized;
|
|
522
|
+
});
|
|
517
523
|
const order = getSessionOrder(projectId);
|
|
518
524
|
|
|
519
525
|
const fallbackSorted = sessions.sort(
|
|
@@ -558,7 +564,11 @@ function getSessionById(sessionId) {
|
|
|
558
564
|
return null;
|
|
559
565
|
}
|
|
560
566
|
|
|
561
|
-
|
|
567
|
+
const { getForkRelations } = require('./sessions');
|
|
568
|
+
const forkRelations = getForkRelations();
|
|
569
|
+
const normalized = normalizeSession(location.sessionData, location.projectId);
|
|
570
|
+
normalized.forkedFrom = forkRelations[normalized.sessionId] || null;
|
|
571
|
+
return normalized;
|
|
562
572
|
}
|
|
563
573
|
|
|
564
574
|
function buildSessionMessages(sessionId) {
|
|
@@ -1,28 +1,11 @@
|
|
|
1
|
-
const { isWindowsLikePlatform } = require('../../utils/home-dir');
|
|
2
|
-
|
|
3
1
|
function escapeForDoubleQuotes(value) {
|
|
4
2
|
return String(value).replace(/"/g, '\\"');
|
|
5
3
|
}
|
|
6
4
|
|
|
7
|
-
function escapeForPowerShellSingleQuotes(value) {
|
|
8
|
-
return String(value).replace(/'/g, "''");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
5
|
function buildDisplayCommand(executable, args = []) {
|
|
12
6
|
return [String(executable || ''), ...args.map(arg => String(arg))].filter(Boolean).join(' ').trim();
|
|
13
7
|
}
|
|
14
8
|
|
|
15
|
-
function buildWindowsCopyCommand(cwd, executable, args = []) {
|
|
16
|
-
const quotedCwd = `'${escapeForPowerShellSingleQuotes(cwd)}'`;
|
|
17
|
-
const quotedExecutable = `'${escapeForPowerShellSingleQuotes(executable)}'`;
|
|
18
|
-
const quotedArgs = args.map(arg => `'${escapeForPowerShellSingleQuotes(arg)}'`).join(' ');
|
|
19
|
-
const invokeCommand = quotedArgs
|
|
20
|
-
? `& ${quotedExecutable} ${quotedArgs}`
|
|
21
|
-
: `& ${quotedExecutable}`;
|
|
22
|
-
|
|
23
|
-
return `powershell -NoProfile -ExecutionPolicy Bypass -Command "& { Set-Location -LiteralPath ${quotedCwd}; ${invokeCommand} }"`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
9
|
function buildPosixCopyCommand(cwd, command) {
|
|
27
10
|
const quotedCwd = `"${escapeForDoubleQuotes(cwd)}"`;
|
|
28
11
|
return `cd ${quotedCwd} && ${command}`;
|
|
@@ -41,10 +24,6 @@ function buildCopyCommand({
|
|
|
41
24
|
return resolvedCommand;
|
|
42
25
|
}
|
|
43
26
|
|
|
44
|
-
if (isWindowsLikePlatform(runtimePlatform, runtimeEnv)) {
|
|
45
|
-
return buildWindowsCopyCommand(cwd, executable, args);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
27
|
return buildPosixCopyCommand(cwd, resolvedCommand);
|
|
49
28
|
}
|
|
50
29
|
|
|
@@ -74,8 +53,6 @@ module.exports = {
|
|
|
74
53
|
_test: {
|
|
75
54
|
buildDisplayCommand,
|
|
76
55
|
buildCopyCommand,
|
|
77
|
-
|
|
78
|
-
buildPosixCopyCommand,
|
|
79
|
-
escapeForPowerShellSingleQuotes
|
|
56
|
+
buildPosixCopyCommand
|
|
80
57
|
}
|
|
81
58
|
};
|
|
@@ -20,6 +20,29 @@ const PROJECT_PATH_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
|
20
20
|
const MAX_PROJECT_PATH_CACHE_ENTRIES = 500;
|
|
21
21
|
let projectPathResolutionCache = new Map();
|
|
22
22
|
|
|
23
|
+
function getProjectsStatsCacheKey(config) {
|
|
24
|
+
return `${CacheKeys.PROJECTS}${config?.projectsDir || '__default__'}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getProjectSessionsCacheKey(projectName) {
|
|
28
|
+
return `${CacheKeys.SESSIONS}${projectName}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function invalidateProjectStatsCache(config) {
|
|
32
|
+
invalidateProjectsCache(config);
|
|
33
|
+
globalCache.delete(getProjectsStatsCacheKey(config));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function invalidateProjectSessionCache(projectName) {
|
|
37
|
+
if (!projectName) return;
|
|
38
|
+
globalCache.delete(getProjectSessionsCacheKey(projectName));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function invalidateProjectCaches(config, projectName) {
|
|
42
|
+
invalidateProjectStatsCache(config);
|
|
43
|
+
invalidateProjectSessionCache(projectName);
|
|
44
|
+
}
|
|
45
|
+
|
|
23
46
|
// Base directory for cc-tool data
|
|
24
47
|
function getCcToolDir() {
|
|
25
48
|
return PATHS.base;
|
|
@@ -313,6 +336,41 @@ function validateProjectPath(candidatePath) {
|
|
|
313
336
|
return null;
|
|
314
337
|
}
|
|
315
338
|
|
|
339
|
+
function scanSessionsDir(sessionsDir) {
|
|
340
|
+
if (!sessionsDir || !fs.existsSync(sessionsDir)) {
|
|
341
|
+
return [];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return fs.readdirSync(sessionsDir)
|
|
345
|
+
.filter(file => file.endsWith('.jsonl') && !file.startsWith('agent-'))
|
|
346
|
+
.map((file) => {
|
|
347
|
+
const filePath = path.join(sessionsDir, file);
|
|
348
|
+
const stats = fs.statSync(filePath);
|
|
349
|
+
return {
|
|
350
|
+
sessionId: file.replace('.jsonl', ''),
|
|
351
|
+
filePath,
|
|
352
|
+
size: stats.size,
|
|
353
|
+
mtime: stats.mtime
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function getProjectSessionsDir(config, projectName) {
|
|
359
|
+
return path.join(config.projectsDir, projectName);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function getProjectSessionFiles(config, projectName) {
|
|
363
|
+
return scanSessionsDir(getProjectSessionsDir(config, projectName)).sort((a, b) => b.mtime - a.mtime);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function resolveSessionFile(config, projectName, sessionId) {
|
|
367
|
+
const sessionFile = path.join(getProjectSessionsDir(config, projectName), `${sessionId}.jsonl`);
|
|
368
|
+
if (fs.existsSync(sessionFile)) {
|
|
369
|
+
return sessionFile;
|
|
370
|
+
}
|
|
371
|
+
return '';
|
|
372
|
+
}
|
|
373
|
+
|
|
316
374
|
function tryResolvePathFromSessions(encodedName) {
|
|
317
375
|
try {
|
|
318
376
|
const projectDir = path.join(CLAUDE_PROJECTS_DIR, encodedName);
|
|
@@ -365,7 +423,7 @@ function extractCwdFromSessionHeader(sessionFile) {
|
|
|
365
423
|
async function getProjectsWithStats(config, options = {}) {
|
|
366
424
|
if (!options.force) {
|
|
367
425
|
// Check enhanced cache first
|
|
368
|
-
const cacheKey =
|
|
426
|
+
const cacheKey = getProjectsStatsCacheKey(config);
|
|
369
427
|
const enhancedCached = globalCache.get(cacheKey);
|
|
370
428
|
if (enhancedCached) {
|
|
371
429
|
return enhancedCached;
|
|
@@ -386,7 +444,7 @@ async function getProjectsWithStats(config, options = {}) {
|
|
|
386
444
|
return [];
|
|
387
445
|
}
|
|
388
446
|
setCachedProjects(config, data);
|
|
389
|
-
globalCache.set(
|
|
447
|
+
globalCache.set(getProjectsStatsCacheKey(config), data, 300000);
|
|
390
448
|
return data;
|
|
391
449
|
} catch (err) {
|
|
392
450
|
console.error(`[getProjectsWithStats] Failed to build projects for ${config.projectsDir}:`, err);
|
|
@@ -418,14 +476,10 @@ async function buildProjectsWithStats(config) {
|
|
|
418
476
|
let lastUsed = null;
|
|
419
477
|
|
|
420
478
|
try {
|
|
421
|
-
const files = await fs.promises.readdir(projectPath);
|
|
422
|
-
const jsonlFiles = files.filter(f => f.endsWith('.jsonl') && !f.startsWith('agent-'));
|
|
423
|
-
|
|
424
479
|
const sessionChecks = await Promise.all(
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
const
|
|
428
|
-
const hasMessages = await hasActualMessages(filePath, stats);
|
|
480
|
+
getProjectSessionFiles(config, projectName).map(async (session) => {
|
|
481
|
+
const stats = await fs.promises.stat(session.filePath);
|
|
482
|
+
const hasMessages = await hasActualMessages(session.filePath, stats);
|
|
429
483
|
return hasMessages ? stats.mtime.getTime() : null;
|
|
430
484
|
})
|
|
431
485
|
);
|
|
@@ -469,10 +523,8 @@ function getProjectAndSessionCounts(config) {
|
|
|
469
523
|
return;
|
|
470
524
|
}
|
|
471
525
|
projectCount += 1;
|
|
472
|
-
const projectPath = path.join(projectsDir, entry.name);
|
|
473
526
|
try {
|
|
474
|
-
|
|
475
|
-
sessionCount += files.filter(file => file.endsWith('.jsonl') && !file.startsWith('agent-')).length;
|
|
527
|
+
sessionCount += getProjectSessionFiles(config, entry.name).length;
|
|
476
528
|
} catch (err) {
|
|
477
529
|
// 忽略单个项目的读取错误
|
|
478
530
|
}
|
|
@@ -575,14 +627,14 @@ function scanSessionFileForMessagesAsync(filePath) {
|
|
|
575
627
|
// Get sessions for a project - async version
|
|
576
628
|
async function getSessionsForProject(config, projectName) {
|
|
577
629
|
// Check cache first
|
|
578
|
-
const cacheKey =
|
|
630
|
+
const cacheKey = getProjectSessionsCacheKey(projectName);
|
|
579
631
|
const cached = globalCache.get(cacheKey);
|
|
580
632
|
if (cached) {
|
|
581
633
|
return cached;
|
|
582
634
|
}
|
|
583
635
|
|
|
584
636
|
const projectConfig = { ...config, currentProject: projectName };
|
|
585
|
-
const sessions =
|
|
637
|
+
const sessions = getProjectSessionFiles(projectConfig, projectName);
|
|
586
638
|
const forkRelations = getForkRelations();
|
|
587
639
|
const savedOrder = getSessionOrder(projectName);
|
|
588
640
|
|
|
@@ -627,8 +679,10 @@ async function getSessionsForProject(config, projectName) {
|
|
|
627
679
|
}
|
|
628
680
|
|
|
629
681
|
// Add remaining sessions (new ones not in saved order)
|
|
630
|
-
|
|
631
|
-
|
|
682
|
+
const newSessions = [...sessionMap.values()].sort((a, b) => {
|
|
683
|
+
return new Date(b.mtime).getTime() - new Date(a.mtime).getTime();
|
|
684
|
+
});
|
|
685
|
+
orderedSessions = [...newSessions, ...ordered];
|
|
632
686
|
}
|
|
633
687
|
|
|
634
688
|
const result = {
|
|
@@ -643,24 +697,22 @@ async function getSessionsForProject(config, projectName) {
|
|
|
643
697
|
|
|
644
698
|
// Delete a session
|
|
645
699
|
function deleteSession(config, projectName, sessionId) {
|
|
646
|
-
const
|
|
647
|
-
const sessionFile = path.join(projectDir, sessionId + '.jsonl');
|
|
700
|
+
const sessionFile = resolveSessionFile(config, projectName, sessionId);
|
|
648
701
|
|
|
649
|
-
if (!fs.existsSync(sessionFile)) {
|
|
702
|
+
if (!sessionFile || !fs.existsSync(sessionFile)) {
|
|
650
703
|
throw new Error('Session not found');
|
|
651
704
|
}
|
|
652
705
|
|
|
653
706
|
fs.unlinkSync(sessionFile);
|
|
654
|
-
|
|
707
|
+
invalidateProjectCaches(config, projectName);
|
|
655
708
|
return { success: true };
|
|
656
709
|
}
|
|
657
710
|
|
|
658
711
|
// Fork a session
|
|
659
712
|
function forkSession(config, projectName, sessionId) {
|
|
660
|
-
const
|
|
661
|
-
const sessionFile = path.join(projectDir, sessionId + '.jsonl');
|
|
713
|
+
const sessionFile = resolveSessionFile(config, projectName, sessionId);
|
|
662
714
|
|
|
663
|
-
if (!fs.existsSync(sessionFile)) {
|
|
715
|
+
if (!sessionFile || !fs.existsSync(sessionFile)) {
|
|
664
716
|
throw new Error('Session not found');
|
|
665
717
|
}
|
|
666
718
|
|
|
@@ -669,7 +721,7 @@ function forkSession(config, projectName, sessionId) {
|
|
|
669
721
|
|
|
670
722
|
// Generate new session ID (UUID v4)
|
|
671
723
|
const newSessionId = crypto.randomUUID();
|
|
672
|
-
const newSessionFile = path.join(
|
|
724
|
+
const newSessionFile = path.join(path.dirname(sessionFile), newSessionId + '.jsonl');
|
|
673
725
|
|
|
674
726
|
// Write to new file
|
|
675
727
|
fs.writeFileSync(newSessionFile, content, 'utf8');
|
|
@@ -678,7 +730,13 @@ function forkSession(config, projectName, sessionId) {
|
|
|
678
730
|
const forkRelations = getForkRelations();
|
|
679
731
|
forkRelations[newSessionId] = sessionId;
|
|
680
732
|
saveForkRelations(forkRelations);
|
|
681
|
-
|
|
733
|
+
|
|
734
|
+
const savedOrder = getSessionOrder(projectName);
|
|
735
|
+
if (savedOrder.length > 0) {
|
|
736
|
+
saveSessionOrder(projectName, [newSessionId, ...savedOrder.filter(id => id !== newSessionId)]);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
invalidateProjectCaches(config, projectName);
|
|
682
740
|
|
|
683
741
|
return { newSessionId, forkedFrom: sessionId };
|
|
684
742
|
}
|
|
@@ -720,6 +778,7 @@ function saveSessionOrder(projectName, order) {
|
|
|
720
778
|
// Update order for this project
|
|
721
779
|
allOrders[projectName] = order;
|
|
722
780
|
fs.writeFileSync(orderFile, JSON.stringify(allOrders, null, 2), 'utf8');
|
|
781
|
+
invalidateProjectSessionCache(projectName);
|
|
723
782
|
}
|
|
724
783
|
|
|
725
784
|
// Delete a project (remove the entire project directory)
|
|
@@ -739,7 +798,7 @@ function deleteProject(config, projectName) {
|
|
|
739
798
|
saveProjectOrder(config, newOrder);
|
|
740
799
|
}
|
|
741
800
|
|
|
742
|
-
|
|
801
|
+
invalidateProjectCaches(config, projectName);
|
|
743
802
|
clearProjectPathResolutionCache(projectName);
|
|
744
803
|
return {
|
|
745
804
|
success: true,
|
|
@@ -749,20 +808,12 @@ function deleteProject(config, projectName) {
|
|
|
749
808
|
|
|
750
809
|
// Search sessions for keyword
|
|
751
810
|
function searchSessions(config, projectName, keyword, contextLength = 15) {
|
|
752
|
-
const projectDir = path.join(config.projectsDir, projectName);
|
|
753
|
-
|
|
754
|
-
if (!fs.existsSync(projectDir)) {
|
|
755
|
-
return [];
|
|
756
|
-
}
|
|
757
|
-
|
|
758
811
|
const results = [];
|
|
759
|
-
const files = fs.readdirSync(projectDir);
|
|
760
|
-
const jsonlFiles = files.filter(f => f.endsWith('.jsonl') && !f.startsWith('agent-'));
|
|
761
812
|
const aliases = loadAliases();
|
|
762
813
|
|
|
763
|
-
for (const
|
|
764
|
-
const sessionId =
|
|
765
|
-
const filePath =
|
|
814
|
+
for (const session of getProjectSessionFiles(config, projectName)) {
|
|
815
|
+
const sessionId = session.sessionId;
|
|
816
|
+
const filePath = session.filePath;
|
|
766
817
|
|
|
767
818
|
// Skip sessions with no actual messages
|
|
768
819
|
if (!hasActualMessages(filePath)) {
|
|
@@ -836,7 +887,7 @@ async function getRecentSessions(config, limit = 5) {
|
|
|
836
887
|
// Collect all sessions from all projects
|
|
837
888
|
projects.forEach(projectName => {
|
|
838
889
|
const projectConfig = { ...config, currentProject: projectName };
|
|
839
|
-
const sessions =
|
|
890
|
+
const sessions = getProjectSessionFiles(projectConfig, projectName);
|
|
840
891
|
const { projectName: displayName, fullPath } = parseRealProjectPath(projectName);
|
|
841
892
|
|
|
842
893
|
sessions.forEach(session => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.session-list-container[data-v-e76934ff]{width:100%}.sessions-list[data-v-e76934ff]{position:relative;overflow:hidden}.session-header[data-v-e76934ff]{align-items:flex-start;gap:14px}.session-header-main[data-v-e76934ff]{display:flex;align-items:flex-start;gap:12px;min-width:0;flex:1}.back-button[data-v-e76934ff]{flex-shrink:0}.title-section[data-v-e76934ff]{flex:1;min-width:0}.title-with-count[data-v-e76934ff]{display:flex;align-items:center;gap:6px;margin-bottom:0;flex-wrap:wrap}.title-section h2[data-v-e76934ff]{margin:0}.session-page-title[data-v-e76934ff]{font-size:clamp(22px,1.75vw,27px);line-height:1.08;letter-spacing:-.03em}.session-count[data-v-e76934ff]{font-size:13px;color:var(--text-secondary)}.total-size-tag[data-v-e76934ff]{margin-left:0}.project-path[data-v-e76934ff]{margin-top:0}.header-actions[data-v-e76934ff]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.session-toolbar[data-v-e76934ff]{min-width:min(420px,100%)}.search-input[data-v-e76934ff]{width:300px;min-width:min(300px,100%)}.search-input[data-v-e76934ff] .n-input{border-radius:14px;background:var(--surface-panel-strong);border:1px solid var(--border-primary);transition:all .2s ease}.search-input[data-v-e76934ff] .n-input:hover{border-color:var(--border-secondary);box-shadow:var(--shadow-sm)}.search-input[data-v-e76934ff] .n-input:focus-within{border-color:var(--primary-color);box-shadow:var(--focus-ring)}.loading-container[data-v-e76934ff]{display:flex;justify-content:center;align-items:center;min-height:400px}.session-item[data-v-e76934ff]{display:flex;align-items:center;gap:12px;padding:18px;background:var(--surface-panel);border:1px solid var(--border-primary);border-radius:18px;margin-bottom:10px;transition:all .22s ease;cursor:pointer;box-shadow:var(--shadow-sm)}.session-item[data-v-e76934ff]:hover{border-color:#18a05842;box-shadow:var(--shadow-md);transform:translateY(-1px)}.session-item-selection-mode[data-v-e76934ff]{cursor:default}.session-item-selected[data-v-e76934ff]{border-color:#18a0585c;box-shadow:0 0 0 3px #18a0581f;background:#18a0580a}.drag-handle[data-v-e76934ff]{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-e76934ff]{opacity:1;background-color:#18a0581a;border-radius:10px}.selection-checkbox[data-v-e76934ff]{width:24px;min-width:24px;display:flex;align-items:center;justify-content:center}.session-left[data-v-e76934ff]{flex:1;display:flex;align-items:center;gap:16px;min-width:0}.session-icon[data-v-e76934ff]{flex-shrink:0}.session-info[data-v-e76934ff]{flex:1;min-width:0}.session-header[data-v-e76934ff]{display:flex;align-items:center;margin-bottom:6px}.session-title-row[data-v-e76934ff]{display:flex;align-items:center;gap:8px}.session-title[data-v-e76934ff]{font-size:15px;font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.session-meta[data-v-e76934ff]{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:13px}.session-message[data-v-e76934ff]{display:block;max-width:680px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}.session-message-empty[data-v-e76934ff]{font-style:italic;opacity:.5}.session-right[data-v-e76934ff]{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-end;min-width:248px;flex-shrink:0;gap:12px}.session-tags-area[data-v-e76934ff]{min-height:24px;display:flex;align-items:flex-start;justify-content:flex-end}.session-actions[data-v-e76934ff]{display:flex;align-items:center;margin-top:auto}.session-actions[data-v-e76934ff] .n-button{border-radius:12px}.ghost[data-v-e76934ff]{opacity:.4}.chosen[data-v-e76934ff]{box-shadow:0 4px 16px #00000026}.search-result-item[data-v-e76934ff]{margin-bottom:16px;padding:14px;border:1px solid var(--border-primary);border-radius:14px;background:var(--surface-panel);box-shadow:var(--shadow-sm)}.search-result-header[data-v-e76934ff]{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.search-result-title[data-v-e76934ff]{display:flex;align-items:center;gap:8px}.search-match[data-v-e76934ff]{display:flex;align-items:flex-start;gap:8px;margin-top:8px;padding:10px 12px;background:var(--surface-panel-muted);border-radius:12px}.search-match-text[data-v-e76934ff]{flex:1;line-height:1.6}@media (max-width: 1024px){.session-header[data-v-e76934ff]{align-items:stretch}.session-toolbar[data-v-e76934ff]{width:100%;min-width:0}.search-input[data-v-e76934ff]{width:100%}}@media (max-width: 900px){.session-page-title[data-v-e76934ff]{font-size:20px}.session-item[data-v-e76934ff]{flex-direction:column;align-items:stretch}.session-right[data-v-e76934ff]{min-width:0;align-items:flex-start}.session-tags-area[data-v-e76934ff],.session-actions[data-v-e76934ff]{width:100%;justify-content:flex-start}}
|