codexmate 0.1.28 → 0.1.29
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 +53 -44
- package/README.vi.md +45 -36
- package/README.zh.md +51 -42
- package/cli/session-usage.js +2 -2
- package/cli.js +369 -15
- package/package.json +1 -1
- package/web-ui/app.js +3 -0
- package/web-ui/index.html +3 -2
- package/web-ui/logic.sessions.mjs +6 -4
- package/web-ui/modules/app.computed.session.mjs +52 -33
- package/web-ui/modules/app.methods.agents.mjs +36 -0
- package/web-ui/modules/app.methods.codex-config.mjs +3 -1
- package/web-ui/modules/app.methods.providers.mjs +12 -4
- package/web-ui/modules/app.methods.session-actions.mjs +10 -8
- package/web-ui/modules/app.methods.session-browser.mjs +3 -1
- package/web-ui/modules/app.methods.session-trash.mjs +16 -16
- package/web-ui/modules/app.methods.theme.mjs +5 -4
- package/web-ui/modules/i18n/locales/en.mjs +74 -1
- package/web-ui/modules/i18n/locales/ja.mjs +74 -1
- package/web-ui/modules/i18n/locales/vi.mjs +74 -1
- package/web-ui/modules/i18n/locales/zh-tw.mjs +74 -1
- package/web-ui/modules/i18n/locales/zh.mjs +74 -1
- package/web-ui/modules/i18n.mjs +7 -0
- package/web-ui/partials/index/modal-config-template-agents.html +1 -1
- package/web-ui/partials/index/modal-health-check.html +1 -1
- package/web-ui/partials/index/modal-openclaw-config.html +50 -50
- package/web-ui/partials/index/panel-dashboard.html +1 -1
- package/web-ui/partials/index/panel-prompts.html +2 -2
- package/web-ui/partials/index/panel-sessions.html +45 -28
- package/web-ui/partials/index/panel-settings.html +6 -0
- package/web-ui/res/web-ui-render.precompiled.js +219 -156
- package/web-ui/session-helpers.mjs +3 -0
- package/web-ui/styles/base-theme.css +2 -2
- package/web-ui/styles/bridge-pool.css +1 -1
- package/web-ui/styles/layout-shell.css +0 -1
- package/web-ui/styles/sessions-preview.css +77 -0
- package/web-ui/styles/theme-dark-tokens.css +2 -2
- package/web-ui/styles/theme-dark.css +2 -2
- package/web-ui/styles/theme-ocean-tokens.css +88 -0
- package/web-ui/styles/theme-ocean.css +920 -0
- package/web-ui/styles.css +1 -0
package/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ const toml = require('@iarna/toml');
|
|
|
7
7
|
const JSON5 = require('json5');
|
|
8
8
|
const zipLib = require('zip-lib');
|
|
9
9
|
const yauzl = require('yauzl');
|
|
10
|
+
const zlib = require('node:zlib');
|
|
10
11
|
const { exec, execSync, execFileSync, spawn, spawnSync } = require('child_process');
|
|
11
12
|
const http = require('http');
|
|
12
13
|
const https = require('https');
|
|
@@ -264,6 +265,20 @@ const PI_SESSIONS_DIR = path.join(PI_DIR, 'agent', 'sessions');
|
|
|
264
265
|
const OPENCODE_DATA_DIR = path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'), 'opencode');
|
|
265
266
|
const OPENCODE_DB_VIRTUAL_ROOT = path.join(OPENCODE_DATA_DIR, 'sessions');
|
|
266
267
|
const OPENCODE_DB_READ_LIMIT = 2000;
|
|
268
|
+
function resolveZedDataDir() {
|
|
269
|
+
if (process.env.ZED_DATA_DIR) return process.env.ZED_DATA_DIR;
|
|
270
|
+
if (process.platform === 'win32') {
|
|
271
|
+
return process.env.LOCALAPPDATA
|
|
272
|
+
? path.join(process.env.LOCALAPPDATA, 'Zed')
|
|
273
|
+
: path.join(os.homedir(), 'AppData', 'Local', 'Zed');
|
|
274
|
+
}
|
|
275
|
+
if (process.platform === 'darwin') return path.join(os.homedir(), '.zed');
|
|
276
|
+
return path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share'), 'zed');
|
|
277
|
+
}
|
|
278
|
+
const ZED_DATA_DIR = resolveZedDataDir();
|
|
279
|
+
const ZED_THREADS_DB_FILE = path.join(ZED_DATA_DIR, 'threads', 'threads.db');
|
|
280
|
+
const ZED_DB_VIRTUAL_ROOT = path.join(ZED_DATA_DIR, 'threads', 'sessions');
|
|
281
|
+
const ZED_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
267
282
|
const RECENT_CONFIGS_FILE = path.join(CONFIG_DIR, 'recent-configs.json');
|
|
268
283
|
const WORKFLOW_DEFINITIONS_FILE = path.join(CONFIG_DIR, 'codexmate-workflows.json');
|
|
269
284
|
const WORKFLOW_RUNS_FILE = path.join(CONFIG_DIR, 'codexmate-workflow-runs.jsonl');
|
|
@@ -772,7 +787,8 @@ let g_sessionFileLookupCache = {
|
|
|
772
787
|
gemini: new Map(),
|
|
773
788
|
codebuddy: new Map(),
|
|
774
789
|
workbuddy: new Map(),
|
|
775
|
-
pi: new Map()
|
|
790
|
+
pi: new Map(),
|
|
791
|
+
zed: new Map()
|
|
776
792
|
};
|
|
777
793
|
let g_exactMessageCountCache = new Map();
|
|
778
794
|
let g_modelsCache = new Map();
|
|
@@ -1041,7 +1057,8 @@ function normalizeSidebarCollapsedPreference(value) {
|
|
|
1041
1057
|
}
|
|
1042
1058
|
|
|
1043
1059
|
function normalizeThemePreference(value) {
|
|
1044
|
-
|
|
1060
|
+
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
1061
|
+
return normalized === 'dark' || normalized === 'ocean' ? normalized : 'light';
|
|
1045
1062
|
}
|
|
1046
1063
|
|
|
1047
1064
|
function normalizeSessionFilterSourcePreference(value) {
|
|
@@ -2417,6 +2434,260 @@ function listOpencodeSessions(limit, options = {}) {
|
|
|
2417
2434
|
}, []);
|
|
2418
2435
|
}
|
|
2419
2436
|
|
|
2437
|
+
|
|
2438
|
+
function isZedThreadsDbAvailable() {
|
|
2439
|
+
const Database = getNodeSqliteDatabaseSync();
|
|
2440
|
+
return !!(Database && ZED_THREADS_DB_FILE && fs.existsSync(ZED_THREADS_DB_FILE));
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
function withZedThreadsDb(callback, fallback = null) {
|
|
2444
|
+
const Database = getNodeSqliteDatabaseSync();
|
|
2445
|
+
if (!Database || !ZED_THREADS_DB_FILE || !fs.existsSync(ZED_THREADS_DB_FILE)) {
|
|
2446
|
+
return fallback;
|
|
2447
|
+
}
|
|
2448
|
+
let db;
|
|
2449
|
+
try {
|
|
2450
|
+
db = new Database(ZED_THREADS_DB_FILE, { readOnly: true });
|
|
2451
|
+
return callback(db);
|
|
2452
|
+
} catch (_) {
|
|
2453
|
+
return fallback;
|
|
2454
|
+
} finally {
|
|
2455
|
+
if (db) {
|
|
2456
|
+
try { db.close(); } catch (_) { }
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
function buildZedVirtualSessionPath(sessionId) {
|
|
2462
|
+
const id = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
2463
|
+
if (!id) return '';
|
|
2464
|
+
return path.join(ZED_DB_VIRTUAL_ROOT, `${id}.zed.jsonl`);
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
function parseZedVirtualSessionId(filePath) {
|
|
2468
|
+
const raw = typeof filePath === 'string' ? filePath.trim() : '';
|
|
2469
|
+
if (!raw) return '';
|
|
2470
|
+
const base = path.basename(raw, path.extname(raw));
|
|
2471
|
+
return ZED_SESSION_ID_RE.test(base) ? base.toLowerCase() : '';
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
/* Zed 会话文档存于 threads.db 的 threads.data 列(zstd 压缩 JSON)。
|
|
2475
|
+
* 版本 0.3.0 结构:{ title, messages: [{User:{content:[{Text}]}} | {Agent:{content:[{Text}|{Thinking:{text}}], tool_results, reasoning_details}}],
|
|
2476
|
+
* model: {provider, model}, cumulative_token_usage, initial_project_snapshot } */
|
|
2477
|
+
function parseZedThreadDocument(row) {
|
|
2478
|
+
if (!row || typeof row !== 'object') return null;
|
|
2479
|
+
const dataType = typeof row.data_type === 'string' ? row.data_type.trim().toLowerCase() : '';
|
|
2480
|
+
let text = '';
|
|
2481
|
+
try {
|
|
2482
|
+
if (dataType === 'zstd') {
|
|
2483
|
+
text = zlib.zstdDecompressSync(Buffer.from(row.data)).toString('utf8');
|
|
2484
|
+
} else if (!dataType || dataType === 'json' || dataType === 'utf8' || dataType === 'text') {
|
|
2485
|
+
text = Buffer.from(row.data).toString('utf8');
|
|
2486
|
+
} else {
|
|
2487
|
+
return null;
|
|
2488
|
+
}
|
|
2489
|
+
const parsed = JSON.parse(text);
|
|
2490
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
2491
|
+
} catch (_) {
|
|
2492
|
+
return null;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
function extractZedTextFromContentBlocks(blocks) {
|
|
2497
|
+
if (!Array.isArray(blocks)) return '';
|
|
2498
|
+
const parts = [];
|
|
2499
|
+
for (const block of blocks) {
|
|
2500
|
+
if (!block || typeof block !== 'object') continue;
|
|
2501
|
+
if (typeof block.Text === 'string' && block.Text.trim()) {
|
|
2502
|
+
parts.push(block.Text.trim());
|
|
2503
|
+
} else if (block.Thinking && typeof block.Thinking === 'object'
|
|
2504
|
+
&& typeof block.Thinking.text === 'string' && block.Thinking.text.trim()) {
|
|
2505
|
+
parts.push(block.Thinking.text.trim());
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
return parts.join('\n').trim();
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
function readZedThreadModelInfo(doc) {
|
|
2512
|
+
const model = doc && doc.model && typeof doc.model === 'object' ? doc.model : null;
|
|
2513
|
+
return {
|
|
2514
|
+
model: model && typeof model.model === 'string' ? model.model.trim() : '',
|
|
2515
|
+
provider: model && typeof model.provider === 'string' && model.provider.trim() ? model.provider.trim() : 'zed'
|
|
2516
|
+
};
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
function normalizeZedThreadMessage(entry, modelInfo) {
|
|
2520
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
2521
|
+
if (entry.User && typeof entry.User === 'object') {
|
|
2522
|
+
const text = extractZedTextFromContentBlocks(entry.User.content);
|
|
2523
|
+
if (!text) return null;
|
|
2524
|
+
return { role: 'user', text, timestamp: '', model: modelInfo.model, provider: modelInfo.provider };
|
|
2525
|
+
}
|
|
2526
|
+
if (entry.Agent && typeof entry.Agent === 'object') {
|
|
2527
|
+
const text = extractZedTextFromContentBlocks(entry.Agent.content);
|
|
2528
|
+
if (!text) return null;
|
|
2529
|
+
return { role: 'assistant', text, timestamp: '', model: modelInfo.model, provider: modelInfo.provider };
|
|
2530
|
+
}
|
|
2531
|
+
return null;
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
function countZedThreadMessages(doc, modelInfo) {
|
|
2535
|
+
const rawMessages = doc && Array.isArray(doc.messages) ? doc.messages : [];
|
|
2536
|
+
return rawMessages.map(entry => normalizeZedThreadMessage(entry, modelInfo)).filter(Boolean).length;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
function readZedThreadUsage(doc) {
|
|
2540
|
+
const usage = doc && doc.cumulative_token_usage && typeof doc.cumulative_token_usage === 'object'
|
|
2541
|
+
? doc.cumulative_token_usage
|
|
2542
|
+
: {};
|
|
2543
|
+
const inputTokens = readNonNegativeInteger(usage.input_tokens) || 0;
|
|
2544
|
+
const cachedInputTokens = readNonNegativeInteger(usage.cache_read_input_tokens) || 0;
|
|
2545
|
+
const cacheCreationInputTokens = readNonNegativeInteger(usage.cache_creation_input_tokens) || 0;
|
|
2546
|
+
const outputTokens = readNonNegativeInteger(usage.output_tokens) || 0;
|
|
2547
|
+
const reasoningOutputTokens = readNonNegativeInteger(usage.reasoning_output_tokens) || 0;
|
|
2548
|
+
return {
|
|
2549
|
+
inputTokens,
|
|
2550
|
+
cachedInputTokens,
|
|
2551
|
+
cacheCreationInputTokens,
|
|
2552
|
+
outputTokens,
|
|
2553
|
+
reasoningOutputTokens,
|
|
2554
|
+
totalTokens: inputTokens + outputTokens + reasoningOutputTokens + cachedInputTokens + cacheCreationInputTokens
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
function readZedThreadCwd(row, doc) {
|
|
2559
|
+
const raw = typeof row.folder_paths === 'string' ? row.folder_paths.trim() : '';
|
|
2560
|
+
if (raw && !raw.startsWith('[')) {
|
|
2561
|
+
return raw;
|
|
2562
|
+
}
|
|
2563
|
+
if (raw.startsWith('[')) {
|
|
2564
|
+
try {
|
|
2565
|
+
const parsed = JSON.parse(raw);
|
|
2566
|
+
const first = Array.isArray(parsed) ? parsed.find(item => typeof item === 'string' && item.trim()) : null;
|
|
2567
|
+
if (first) return first;
|
|
2568
|
+
} catch (_) { }
|
|
2569
|
+
}
|
|
2570
|
+
const snapshot = doc && doc.initial_project_snapshot && Array.isArray(doc.initial_project_snapshot.worktree_snapshots)
|
|
2571
|
+
? doc.initial_project_snapshot.worktree_snapshots.find(item => item && typeof item.worktree_path === 'string' && item.worktree_path.trim())
|
|
2572
|
+
: null;
|
|
2573
|
+
return snapshot ? snapshot.worktree_path : '';
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
function queryZedSessionMessages(sessionId, options = {}) {
|
|
2577
|
+
const id = typeof sessionId === 'string' ? sessionId.trim().toLowerCase() : '';
|
|
2578
|
+
if (!id) return null;
|
|
2579
|
+
const maxMessages = resolveMaxMessagesValue(options.maxMessages, DEFAULT_SESSION_DETAIL_MESSAGES);
|
|
2580
|
+
return withZedThreadsDb((db) => {
|
|
2581
|
+
const row = db.prepare('select data, data_type, folder_paths, updated_at from threads where id = ?').get(id) || null;
|
|
2582
|
+
const doc = parseZedThreadDocument(row);
|
|
2583
|
+
const modelInfo = readZedThreadModelInfo(doc);
|
|
2584
|
+
const all = (doc && Array.isArray(doc.messages) ? doc.messages : [])
|
|
2585
|
+
.map(entry => normalizeZedThreadMessage(entry, modelInfo))
|
|
2586
|
+
.filter(Boolean);
|
|
2587
|
+
const totalMessages = all.length;
|
|
2588
|
+
const limit = maxMessages === Infinity
|
|
2589
|
+
? totalMessages
|
|
2590
|
+
: Math.min(totalMessages, Math.max(1, Math.floor(maxMessages)));
|
|
2591
|
+
const messages = limit < totalMessages ? all.slice(totalMessages - limit) : all;
|
|
2592
|
+
return {
|
|
2593
|
+
sessionId: id,
|
|
2594
|
+
cwd: doc ? readZedThreadCwd(row, doc) : '',
|
|
2595
|
+
updatedAt: row ? toIsoTime(row.updated_at, '') : '',
|
|
2596
|
+
messages,
|
|
2597
|
+
totalMessages,
|
|
2598
|
+
clipped: maxMessages !== Infinity && totalMessages > messages.length,
|
|
2599
|
+
truncated: maxMessages !== Infinity && totalMessages > messages.length
|
|
2600
|
+
};
|
|
2601
|
+
}, null);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
function countZedMessages(sessionId) {
|
|
2605
|
+
const id = typeof sessionId === 'string' ? sessionId.trim().toLowerCase() : '';
|
|
2606
|
+
if (!id) return null;
|
|
2607
|
+
return withZedThreadsDb((db) => {
|
|
2608
|
+
const row = db.prepare('select data, data_type from threads where id = ?').get(id) || null;
|
|
2609
|
+
const doc = parseZedThreadDocument(row);
|
|
2610
|
+
if (!doc) return null;
|
|
2611
|
+
return countZedThreadMessages(doc, readZedThreadModelInfo(doc));
|
|
2612
|
+
}, null);
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
function parseZedSessionSummaryRow(row) {
|
|
2616
|
+
if (!row || typeof row !== 'object') return null;
|
|
2617
|
+
const sessionId = typeof row.id === 'string' ? row.id.trim().toLowerCase() : '';
|
|
2618
|
+
if (!sessionId) return null;
|
|
2619
|
+
const doc = parseZedThreadDocument(row);
|
|
2620
|
+
if (!doc) return null;
|
|
2621
|
+
const modelInfo = readZedThreadModelInfo(doc);
|
|
2622
|
+
const usage = readZedThreadUsage(doc);
|
|
2623
|
+
let title = typeof row.summary === 'string' ? row.summary.trim() : '';
|
|
2624
|
+
if (!title && typeof doc.title === 'string') title = doc.title.trim();
|
|
2625
|
+
if (!title) {
|
|
2626
|
+
const firstUser = (Array.isArray(doc.messages) ? doc.messages : [])
|
|
2627
|
+
.map(entry => normalizeZedThreadMessage(entry, modelInfo))
|
|
2628
|
+
.find(item => item && item.role === 'user' && item.text);
|
|
2629
|
+
if (firstUser) title = truncateText(firstUser.text, 120);
|
|
2630
|
+
}
|
|
2631
|
+
if (!title) title = sessionId;
|
|
2632
|
+
return {
|
|
2633
|
+
source: 'zed',
|
|
2634
|
+
sourceLabel: 'Zed',
|
|
2635
|
+
provider: modelInfo.provider,
|
|
2636
|
+
model: modelInfo.model,
|
|
2637
|
+
models: modelInfo.model ? [modelInfo.model] : [],
|
|
2638
|
+
sessionId,
|
|
2639
|
+
title,
|
|
2640
|
+
cwd: readZedThreadCwd(row, doc),
|
|
2641
|
+
createdAt: toIsoTime(row.created_at, ''),
|
|
2642
|
+
updatedAt: toIsoTime(row.updated_at, ''),
|
|
2643
|
+
messageCount: countZedThreadMessages(doc, modelInfo),
|
|
2644
|
+
totalTokens: usage.totalTokens,
|
|
2645
|
+
contextWindow: 0,
|
|
2646
|
+
inputTokens: usage.inputTokens,
|
|
2647
|
+
cachedInputTokens: usage.cachedInputTokens,
|
|
2648
|
+
cacheCreationInputTokens: usage.cacheCreationInputTokens,
|
|
2649
|
+
outputTokens: usage.outputTokens,
|
|
2650
|
+
reasoningOutputTokens: usage.reasoningOutputTokens,
|
|
2651
|
+
__messageCountExact: true,
|
|
2652
|
+
filePath: buildZedVirtualSessionPath(sessionId),
|
|
2653
|
+
keywords: [],
|
|
2654
|
+
capabilities: { code: true }
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
function parseZedSessionSummary(sessionId) {
|
|
2659
|
+
const id = typeof sessionId === 'string' ? sessionId.trim().toLowerCase() : '';
|
|
2660
|
+
if (!id) return null;
|
|
2661
|
+
return withZedThreadsDb((db) => {
|
|
2662
|
+
const row = db.prepare(`
|
|
2663
|
+
select id, summary, folder_paths, created_at, updated_at, data, data_type
|
|
2664
|
+
from threads where id = ?
|
|
2665
|
+
`).get(id) || null;
|
|
2666
|
+
return parseZedSessionSummaryRow(row);
|
|
2667
|
+
}, null);
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
function listZedSessions(limit, options = {}) {
|
|
2671
|
+
if (!isZedThreadsDbAvailable()) return [];
|
|
2672
|
+
const scanFactor = Number.isFinite(Number(options.scanFactor)) ? Math.max(1, Number(options.scanFactor)) : SESSION_SCAN_FACTOR;
|
|
2673
|
+
const targetCount = Number.isFinite(Number(options.targetCount)) ? Math.max(1, Math.floor(Number(options.targetCount))) : Math.max(1, Math.floor(limit * scanFactor));
|
|
2674
|
+
const scanCount = Number.isFinite(Number(options.scanCount)) ? Math.max(targetCount, Math.floor(Number(options.scanCount))) : Math.max(targetCount, Math.min(SESSION_SCAN_MIN_FILES, MAX_SESSION_LIST_SIZE * SESSION_SCAN_FACTOR));
|
|
2675
|
+
return withZedThreadsDb((db) => {
|
|
2676
|
+
const rows = db.prepare(`
|
|
2677
|
+
select id, summary, folder_paths, created_at, updated_at, data, data_type
|
|
2678
|
+
from threads
|
|
2679
|
+
order by updated_at desc
|
|
2680
|
+
limit ?
|
|
2681
|
+
`).all(Math.min(OPENCODE_DB_READ_LIMIT, Math.max(scanCount, targetCount)));
|
|
2682
|
+
const sessions = [];
|
|
2683
|
+
for (const row of rows) {
|
|
2684
|
+
const summary = parseZedSessionSummaryRow(row);
|
|
2685
|
+
if (summary) sessions.push(summary);
|
|
2686
|
+
if (sessions.length >= targetCount) break;
|
|
2687
|
+
}
|
|
2688
|
+
return mergeAndLimitSessions(sessions, limit);
|
|
2689
|
+
}, []);
|
|
2690
|
+
}
|
|
2420
2691
|
function getCodexmateDerivedSessionsRoot(target) {
|
|
2421
2692
|
if (target === 'claude') {
|
|
2422
2693
|
return CODEXMATE_DERIVED_CLAUDE_DIR;
|
|
@@ -4689,7 +4960,7 @@ async function hydrateSessionItemsExactMessageCount(items) {
|
|
|
4689
4960
|
|
|
4690
4961
|
function normalizeSessionSourceName(value, fallback = '') {
|
|
4691
4962
|
const source = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
4692
|
-
if (source === 'codex' || source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode') {
|
|
4963
|
+
if (source === 'codex' || source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode' || source === 'zed') {
|
|
4693
4964
|
return source;
|
|
4694
4965
|
}
|
|
4695
4966
|
return fallback;
|
|
@@ -4707,6 +4978,7 @@ function getSessionSourceLabel(source) {
|
|
|
4707
4978
|
if (source === 'workbuddy') return 'WorkBuddy AI';
|
|
4708
4979
|
if (source === 'pi') return 'Pi';
|
|
4709
4980
|
if (source === 'opencode') return 'OpenCode';
|
|
4981
|
+
if (source === 'zed') return 'Zed';
|
|
4710
4982
|
return 'Codex';
|
|
4711
4983
|
}
|
|
4712
4984
|
|
|
@@ -4717,6 +4989,7 @@ function getSessionSourceProvider(source) {
|
|
|
4717
4989
|
if (source === 'workbuddy') return 'workbuddy';
|
|
4718
4990
|
if (source === 'pi') return 'pi';
|
|
4719
4991
|
if (source === 'opencode') return 'opencode';
|
|
4992
|
+
if (source === 'zed') return 'zed';
|
|
4720
4993
|
return 'codex';
|
|
4721
4994
|
}
|
|
4722
4995
|
|
|
@@ -4746,6 +5019,9 @@ async function readSessionMessageCounts(params = {}) {
|
|
|
4746
5019
|
if (source === 'opencode') {
|
|
4747
5020
|
const opencodeSessionId = item.sessionId || parseOpencodeVirtualSessionId(filePath);
|
|
4748
5021
|
exactMessageCount = countOpencodeMessages(opencodeSessionId);
|
|
5022
|
+
} else if (source === 'zed') {
|
|
5023
|
+
const zedSessionId = item.sessionId || parseZedVirtualSessionId(filePath);
|
|
5024
|
+
exactMessageCount = countZedMessages(zedSessionId);
|
|
4749
5025
|
} else {
|
|
4750
5026
|
if (!filePath || !fs.existsSync(filePath)) {
|
|
4751
5027
|
return { key };
|
|
@@ -4896,6 +5172,7 @@ function createSessionQueryScanState(tokens, options = {}) {
|
|
|
4896
5172
|
count: 0,
|
|
4897
5173
|
snippets: [],
|
|
4898
5174
|
positions: [],
|
|
5175
|
+
complete: true,
|
|
4899
5176
|
leadingSystem: roleFilter !== 'system'
|
|
4900
5177
|
};
|
|
4901
5178
|
}
|
|
@@ -4934,11 +5211,13 @@ function consumeSessionQueryMessage(state, message) {
|
|
|
4934
5211
|
timestamp: typeof message.timestamp === 'string' ? message.timestamp : ''
|
|
4935
5212
|
});
|
|
4936
5213
|
}
|
|
5214
|
+
if (state.count >= state.maxMatches) state.complete = false;
|
|
4937
5215
|
return state.count >= state.maxMatches;
|
|
4938
5216
|
}
|
|
4939
5217
|
|
|
4940
5218
|
function buildSessionQueryScanResult(state) {
|
|
4941
5219
|
return {
|
|
5220
|
+
complete: !!(state && state.complete),
|
|
4942
5221
|
hit: !!(state && state.count > 0),
|
|
4943
5222
|
count: state && Number.isFinite(state.count) ? state.count : 0,
|
|
4944
5223
|
snippets: state && Array.isArray(state.snippets) ? state.snippets : [],
|
|
@@ -4983,6 +5262,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4983
5262
|
const state = createSessionQueryScanState(tokens, options);
|
|
4984
5263
|
if (session.source === 'opencode') {
|
|
4985
5264
|
const extracted = queryOpencodeSessionMessages(session.sessionId || parseOpencodeVirtualSessionId(filePath), { maxMessages: Infinity });
|
|
5265
|
+
state.complete = !!extracted && !extracted.truncated;
|
|
4986
5266
|
const messages = extracted && Array.isArray(extracted.messages) ? extracted.messages : [];
|
|
4987
5267
|
for (let i = 0; i < messages.length; i += 1) {
|
|
4988
5268
|
const message = { ...messages[i], recordLineIndex: i };
|
|
@@ -4990,6 +5270,16 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4990
5270
|
}
|
|
4991
5271
|
return buildSessionQueryScanResult(state);
|
|
4992
5272
|
}
|
|
5273
|
+
if (session.source === 'zed') {
|
|
5274
|
+
const zedExtracted = queryZedSessionMessages(session.sessionId || parseZedVirtualSessionId(filePath), { maxMessages: Infinity });
|
|
5275
|
+
state.complete = !!zedExtracted && !zedExtracted.truncated;
|
|
5276
|
+
const zedMessages = zedExtracted && Array.isArray(zedExtracted.messages) ? zedExtracted.messages : [];
|
|
5277
|
+
for (let i = 0; i < zedMessages.length; i += 1) {
|
|
5278
|
+
const message = { ...zedMessages[i], recordLineIndex: i };
|
|
5279
|
+
if (consumeSessionQueryMessage(state, message)) break;
|
|
5280
|
+
}
|
|
5281
|
+
return buildSessionQueryScanResult(state);
|
|
5282
|
+
}
|
|
4993
5283
|
if (session.source === 'gemini') {
|
|
4994
5284
|
if (state.roleFilter !== 'all' || state.positionsLimit > 0) {
|
|
4995
5285
|
let json;
|
|
@@ -4998,6 +5288,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4998
5288
|
} catch (_) {
|
|
4999
5289
|
json = null;
|
|
5000
5290
|
}
|
|
5291
|
+
state.complete = !!json;
|
|
5001
5292
|
const rawMessages = json && Array.isArray(json.messages) ? json.messages : [];
|
|
5002
5293
|
for (const entry of rawMessages) {
|
|
5003
5294
|
if (!entry || typeof entry !== 'object') continue;
|
|
@@ -5025,12 +5316,14 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5025
5316
|
const buf = Buffer.alloc(targetBytes);
|
|
5026
5317
|
const bytes = fs.readSync(fd, buf, 0, targetBytes, 0);
|
|
5027
5318
|
fs.closeSync(fd);
|
|
5319
|
+
state.complete = bytes >= stat.size;
|
|
5028
5320
|
text = bytes > 0 ? buf.slice(0, bytes).toString('utf-8') : '';
|
|
5029
5321
|
} catch (_) {
|
|
5030
5322
|
try {
|
|
5031
5323
|
text = fs.readFileSync(filePath, 'utf-8');
|
|
5032
5324
|
} catch (_) {
|
|
5033
5325
|
text = '';
|
|
5326
|
+
state.complete = false;
|
|
5034
5327
|
}
|
|
5035
5328
|
}
|
|
5036
5329
|
|
|
@@ -5055,6 +5348,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5055
5348
|
const currentLineIndex = lineIndex;
|
|
5056
5349
|
lineIndex += 1;
|
|
5057
5350
|
if (maxBytes > 0 && bytesRead >= maxBytes) {
|
|
5351
|
+
state.complete = false;
|
|
5058
5352
|
break;
|
|
5059
5353
|
}
|
|
5060
5354
|
|
|
@@ -5084,6 +5378,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5084
5378
|
|
|
5085
5379
|
return buildSessionQueryScanResult(state);
|
|
5086
5380
|
} catch (e) {
|
|
5381
|
+
state.complete = false;
|
|
5087
5382
|
return scanSessionContentForQueryInRecords(readJsonlRecords(filePath), session.source, state);
|
|
5088
5383
|
} finally {
|
|
5089
5384
|
if (rl) {
|
|
@@ -5098,7 +5393,9 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5098
5393
|
async function applySessionQueryFilter(sessions, options = {}) {
|
|
5099
5394
|
const tokens = Array.isArray(options.tokens) ? options.tokens : [];
|
|
5100
5395
|
if (tokens.length === 0) {
|
|
5101
|
-
|
|
5396
|
+
const result = sessions.slice();
|
|
5397
|
+
Object.defineProperty(result, 'searchInfo', { value: null });
|
|
5398
|
+
return result;
|
|
5102
5399
|
}
|
|
5103
5400
|
|
|
5104
5401
|
const mode = normalizeQueryMode(options.queryMode);
|
|
@@ -5112,10 +5409,12 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5112
5409
|
: 0;
|
|
5113
5410
|
|
|
5114
5411
|
let scanned = 0;
|
|
5412
|
+
let complete = true;
|
|
5115
5413
|
const results = [];
|
|
5116
5414
|
|
|
5117
5415
|
for (const session of sessions) {
|
|
5118
5416
|
if (scope === 'content' && scanned >= contentScanLimit) {
|
|
5417
|
+
complete = false;
|
|
5119
5418
|
break;
|
|
5120
5419
|
}
|
|
5121
5420
|
|
|
@@ -5135,6 +5434,10 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5135
5434
|
snippetLimit: 2
|
|
5136
5435
|
});
|
|
5137
5436
|
contentHit = contentInfo.hit;
|
|
5437
|
+
// 命中已完成候选的存在性判定,无需穷尽匹配或消息。
|
|
5438
|
+
if (!contentHit && !contentInfo.complete) complete = false;
|
|
5439
|
+
} else if (shouldScanContent) {
|
|
5440
|
+
complete = false;
|
|
5138
5441
|
}
|
|
5139
5442
|
|
|
5140
5443
|
const hit = scope === 'summary'
|
|
@@ -5156,6 +5459,9 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5156
5459
|
results.push(session);
|
|
5157
5460
|
}
|
|
5158
5461
|
|
|
5462
|
+
Object.defineProperty(results, 'searchInfo', {
|
|
5463
|
+
value: { scanned, candidates: sessions.length, complete }
|
|
5464
|
+
});
|
|
5159
5465
|
return results;
|
|
5160
5466
|
}
|
|
5161
5467
|
function collectRecentJsonlFiles(rootDir, options = {}) {
|
|
@@ -5381,7 +5687,7 @@ function getSessionInventoryCache(cacheKey, forceRefresh = false) {
|
|
|
5381
5687
|
}
|
|
5382
5688
|
|
|
5383
5689
|
function registerSessionFileLookupEntries(source, sessions = []) {
|
|
5384
|
-
const normalizedSource = source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode'
|
|
5690
|
+
const normalizedSource = source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode' || source === 'zed'
|
|
5385
5691
|
? source
|
|
5386
5692
|
: 'codex';
|
|
5387
5693
|
const store = g_sessionFileLookupCache[normalizedSource];
|
|
@@ -5422,7 +5728,7 @@ function setSessionInventoryCache(cacheKey, source, value) {
|
|
|
5422
5728
|
}
|
|
5423
5729
|
|
|
5424
5730
|
function listSessionInventoryBySource(source, limit, scanOptions = {}, options = {}) {
|
|
5425
|
-
const normalizedSource = source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode'
|
|
5731
|
+
const normalizedSource = source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'pi' || source === 'opencode' || source === 'zed'
|
|
5426
5732
|
? source
|
|
5427
5733
|
: 'codex';
|
|
5428
5734
|
const forceRefresh = !!options.forceRefresh;
|
|
@@ -5444,7 +5750,9 @@ function listSessionInventoryBySource(source, limit, scanOptions = {}, options =
|
|
|
5444
5750
|
? listPiSessions(limit, scanOptions)
|
|
5445
5751
|
: (normalizedSource === 'opencode'
|
|
5446
5752
|
? listOpencodeSessions(limit, scanOptions)
|
|
5447
|
-
:
|
|
5753
|
+
: (normalizedSource === 'zed'
|
|
5754
|
+
? listZedSessions(limit, scanOptions)
|
|
5755
|
+
: listCodexSessions(limit, scanOptions)))))));
|
|
5448
5756
|
setSessionInventoryCache(cacheKey, normalizedSource, sessions);
|
|
5449
5757
|
return sessions;
|
|
5450
5758
|
}
|
|
@@ -5459,7 +5767,8 @@ function invalidateSessionListCache() {
|
|
|
5459
5767
|
codebuddy: new Map(),
|
|
5460
5768
|
workbuddy: new Map(),
|
|
5461
5769
|
pi: new Map(),
|
|
5462
|
-
opencode: new Map()
|
|
5770
|
+
opencode: new Map(),
|
|
5771
|
+
zed: new Map()
|
|
5463
5772
|
};
|
|
5464
5773
|
}
|
|
5465
5774
|
|
|
@@ -7325,6 +7634,9 @@ async function listAllSessions(params = {}) {
|
|
|
7325
7634
|
if (source === 'all' || source === 'opencode') {
|
|
7326
7635
|
sessions = sessions.concat(listSessionInventoryBySource('opencode', limit, scanOptions, { forceRefresh }));
|
|
7327
7636
|
}
|
|
7637
|
+
if (source === 'all' || source === 'zed') {
|
|
7638
|
+
sessions = sessions.concat(listSessionInventoryBySource('zed', limit, scanOptions, { forceRefresh }));
|
|
7639
|
+
}
|
|
7328
7640
|
|
|
7329
7641
|
if (hasPathFilter) {
|
|
7330
7642
|
sessions = sessions.filter(item => matchesSessionPathFilter(item, normalizedPathFilter));
|
|
@@ -7341,7 +7653,9 @@ async function listAllSessions(params = {}) {
|
|
|
7341
7653
|
contentScanBytes: params.contentScanBytes
|
|
7342
7654
|
});
|
|
7343
7655
|
}
|
|
7656
|
+
const searchInfo = hasQuery ? result.searchInfo : null;
|
|
7344
7657
|
result = mergeAndLimitSessions(result, limit);
|
|
7658
|
+
Object.defineProperty(result, 'searchInfo', { value: searchInfo });
|
|
7345
7659
|
setSessionListCache(cacheKey, result);
|
|
7346
7660
|
return result;
|
|
7347
7661
|
}
|
|
@@ -7374,6 +7688,7 @@ async function listAllSessionsData(params = {}) {
|
|
|
7374
7688
|
delete normalized.__messageCountExact;
|
|
7375
7689
|
return normalized;
|
|
7376
7690
|
});
|
|
7691
|
+
Object.defineProperty(result, 'searchInfo', { value: sessions.searchInfo || null });
|
|
7377
7692
|
if (!hasQuery) {
|
|
7378
7693
|
setSessionListCache(cacheKey, result);
|
|
7379
7694
|
}
|
|
@@ -7385,7 +7700,7 @@ async function listSessionBrowse(params = {}) {
|
|
|
7385
7700
|
...params,
|
|
7386
7701
|
browseLightweight: true
|
|
7387
7702
|
});
|
|
7388
|
-
|
|
7703
|
+
const result = Array.isArray(sessions)
|
|
7389
7704
|
? sessions.map((item) => {
|
|
7390
7705
|
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
7391
7706
|
return item;
|
|
@@ -7395,6 +7710,8 @@ async function listSessionBrowse(params = {}) {
|
|
|
7395
7710
|
return normalized;
|
|
7396
7711
|
})
|
|
7397
7712
|
: [];
|
|
7713
|
+
Object.defineProperty(result, 'searchInfo', { value: sessions.searchInfo || null });
|
|
7714
|
+
return result;
|
|
7398
7715
|
}
|
|
7399
7716
|
|
|
7400
7717
|
async function listSessionUsage(params = {}) {
|
|
@@ -7466,6 +7783,9 @@ function listSessionPaths(params = {}) {
|
|
|
7466
7783
|
if (validSource === 'all' || validSource === 'opencode') {
|
|
7467
7784
|
sessions = sessions.concat(listSessionInventoryBySource('opencode', gatherLimit, scanOptions, { forceRefresh }));
|
|
7468
7785
|
}
|
|
7786
|
+
if (validSource === 'all' || validSource === 'zed') {
|
|
7787
|
+
sessions = sessions.concat(listSessionInventoryBySource('zed', gatherLimit, scanOptions, { forceRefresh }));
|
|
7788
|
+
}
|
|
7469
7789
|
|
|
7470
7790
|
const dedupedPaths = [];
|
|
7471
7791
|
const seen = new Set();
|
|
@@ -7492,6 +7812,12 @@ function listSessionPaths(params = {}) {
|
|
|
7492
7812
|
|
|
7493
7813
|
function resolveSessionFilePath(source, filePath, sessionId) {
|
|
7494
7814
|
const normalizedSource = normalizeSessionSourceName(source, 'codex');
|
|
7815
|
+
if (normalizedSource === 'zed') {
|
|
7816
|
+
const zedId = typeof sessionId === 'string' && sessionId.trim()
|
|
7817
|
+
? sessionId.trim()
|
|
7818
|
+
: parseZedVirtualSessionId(filePath);
|
|
7819
|
+
return zedId && parseZedSessionSummary(zedId) ? buildZedVirtualSessionPath(zedId) : '';
|
|
7820
|
+
}
|
|
7495
7821
|
if (normalizedSource === 'opencode') {
|
|
7496
7822
|
const id = typeof sessionId === 'string' && sessionId.trim()
|
|
7497
7823
|
? sessionId.trim()
|
|
@@ -8072,7 +8398,7 @@ function buildSessionSummaryFallback(source, filePath, sessionId = '') {
|
|
|
8072
8398
|
contextWindow: 0,
|
|
8073
8399
|
filePath,
|
|
8074
8400
|
keywords: [],
|
|
8075
|
-
capabilities: source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'opencode' ? { code: true } : {}
|
|
8401
|
+
capabilities: source === 'claude' || source === 'gemini' || source === 'codebuddy' || source === 'workbuddy' || source === 'opencode' || source === 'zed' ? { code: true } : {}
|
|
8076
8402
|
};
|
|
8077
8403
|
}
|
|
8078
8404
|
|
|
@@ -8659,6 +8985,9 @@ async function trashSessionData(params = {}) {
|
|
|
8659
8985
|
if (source === 'opencode') {
|
|
8660
8986
|
return { error: 'OpenCode DB-backed sessions cannot be deleted from CodexMate' };
|
|
8661
8987
|
}
|
|
8988
|
+
if (source === 'zed') {
|
|
8989
|
+
return { error: 'Zed DB-backed sessions cannot be deleted from CodexMate' };
|
|
8990
|
+
}
|
|
8662
8991
|
|
|
8663
8992
|
const filePath = resolveSessionFilePath(source, getSessionFileArg(params), params.sessionId);
|
|
8664
8993
|
if (!filePath) {
|
|
@@ -8771,6 +9100,9 @@ async function deleteSessionData(params = {}) {
|
|
|
8771
9100
|
if (source === 'opencode') {
|
|
8772
9101
|
return { error: 'OpenCode DB-backed sessions cannot be deleted from CodexMate' };
|
|
8773
9102
|
}
|
|
9103
|
+
if (source === 'zed') {
|
|
9104
|
+
return { error: 'Zed DB-backed sessions cannot be deleted from CodexMate' };
|
|
9105
|
+
}
|
|
8774
9106
|
|
|
8775
9107
|
const filePath = resolveSessionFilePath(source, getSessionFileArg(params), params.sessionId);
|
|
8776
9108
|
if (!filePath) {
|
|
@@ -9470,6 +9802,13 @@ async function readSessionDetail(params = {}) {
|
|
|
9470
9802
|
if (!extracted) {
|
|
9471
9803
|
return { error: 'Failed to parse session file' };
|
|
9472
9804
|
}
|
|
9805
|
+
}
|
|
9806
|
+
if (source === 'zed') {
|
|
9807
|
+
const zedSessionId = params.sessionId || parseZedVirtualSessionId(filePath);
|
|
9808
|
+
extracted = queryZedSessionMessages(zedSessionId, { maxMessages: messageLimit });
|
|
9809
|
+
if (!extracted) {
|
|
9810
|
+
return { error: 'Failed to parse session file' };
|
|
9811
|
+
}
|
|
9473
9812
|
} else if (source === 'gemini') {
|
|
9474
9813
|
let json;
|
|
9475
9814
|
try {
|
|
@@ -9604,6 +9943,13 @@ async function readSessionPlain(params = {}) {
|
|
|
9604
9943
|
if (!extracted) {
|
|
9605
9944
|
return { error: 'Failed to parse session file' };
|
|
9606
9945
|
}
|
|
9946
|
+
}
|
|
9947
|
+
if (source === 'zed') {
|
|
9948
|
+
const zedSessionId = params.sessionId || parseZedVirtualSessionId(filePath);
|
|
9949
|
+
extracted = queryZedSessionMessages(zedSessionId, { maxMessages });
|
|
9950
|
+
if (!extracted) {
|
|
9951
|
+
return { error: 'Failed to parse session file' };
|
|
9952
|
+
}
|
|
9607
9953
|
} else if (source === 'gemini') {
|
|
9608
9954
|
let json;
|
|
9609
9955
|
try {
|
|
@@ -9688,6 +10034,12 @@ async function exportSessionData(params = {}) {
|
|
|
9688
10034
|
if (!extracted) {
|
|
9689
10035
|
return { error: 'Failed to parse session file' };
|
|
9690
10036
|
}
|
|
10037
|
+
} else if (source === 'zed') {
|
|
10038
|
+
const zedSessionId = params.sessionId || parseZedVirtualSessionId(filePath);
|
|
10039
|
+
extracted = queryZedSessionMessages(zedSessionId, { maxMessages });
|
|
10040
|
+
if (!extracted) {
|
|
10041
|
+
return { error: 'Failed to parse session file' };
|
|
10042
|
+
}
|
|
9691
10043
|
} else if (source === 'gemini') {
|
|
9692
10044
|
let json;
|
|
9693
10045
|
try {
|
|
@@ -12929,7 +13281,7 @@ function resolveExportOutputPath(outputPath, defaultFileName) {
|
|
|
12929
13281
|
}
|
|
12930
13282
|
|
|
12931
13283
|
function printExportSessionUsage() {
|
|
12932
|
-
console.log('\n用法: codexmate export-session --source <codex|claude|gemini|codebuddy|workbuddy|pi|opencode> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
13284
|
+
console.log('\n用法: codexmate export-session --source <codex|claude|gemini|codebuddy|workbuddy|pi|opencode|zed> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
12933
13285
|
console.log('\n示例:');
|
|
12934
13286
|
console.log(' codexmate export-session --source codex --session-id 123456');
|
|
12935
13287
|
console.log(' codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl"');
|
|
@@ -13002,7 +13354,7 @@ function parseExportSessionArgs(args = []) {
|
|
|
13002
13354
|
|
|
13003
13355
|
const normalizedSource = options.source.trim().toLowerCase();
|
|
13004
13356
|
if (normalizedSource && !isSessionSourceOrAll(normalizedSource)) {
|
|
13005
|
-
errors.push('参数 --source 仅支持 codex、claude、gemini、codebuddy、workbuddy、pi 或
|
|
13357
|
+
errors.push('参数 --source 仅支持 codex、claude、gemini、codebuddy、workbuddy、pi、opencode 或 zed');
|
|
13006
13358
|
}
|
|
13007
13359
|
options.source = normalizedSource;
|
|
13008
13360
|
|
|
@@ -14433,9 +14785,11 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
14433
14785
|
if (source && !isSessionSourceOrAll(source)) {
|
|
14434
14786
|
result = { error: 'Invalid source. Must be codex, claude, gemini, codebuddy, workbuddy, pi, opencode, or all' };
|
|
14435
14787
|
} else {
|
|
14788
|
+
const sessions = await listSessionBrowse(params);
|
|
14436
14789
|
result = {
|
|
14437
|
-
sessions
|
|
14438
|
-
source: source || 'all'
|
|
14790
|
+
sessions,
|
|
14791
|
+
source: source || 'all',
|
|
14792
|
+
searchInfo: sessions.searchInfo
|
|
14439
14793
|
};
|
|
14440
14794
|
}
|
|
14441
14795
|
}
|
|
@@ -17374,7 +17728,7 @@ function printMainHelp() {
|
|
|
17374
17728
|
console.log(' 注: follow-up 自动排队仅支持 linux/android/netbsd/openbsd/darwin/freebsd 且 stdin 必须是 TTY,其他平台会报错');
|
|
17375
17729
|
console.log(' codexmate qwen [参数...] 等同于 qwen --yolo');
|
|
17376
17730
|
console.log(' codexmate mcp [serve] [--transport stdio] [--allow-write|--read-only]');
|
|
17377
|
-
console.log(' codexmate export-session --source <codex|claude|gemini|codebuddy|workbuddy|pi|opencode> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
17731
|
+
console.log(' codexmate export-session --source <codex|claude|gemini|codebuddy|workbuddy|pi|opencode|zed> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
17378
17732
|
console.log(' codexmate convert-session --from <codex|claude> --to <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
17379
17733
|
console.log(' codexmate zip <路径> [--max:级别] 压缩(系统 zip 优先,其次 zip-lib)');
|
|
17380
17734
|
console.log(' codexmate unzip <zip文件> [输出目录] 解压(zip-lib)');
|