codexmate 0.1.27 → 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/config-bootstrap.js +2 -9
- package/cli/session-usage.js +2 -2
- package/cli.js +407 -40
- package/package.json +1 -1
- package/web-ui/app.js +7 -0
- package/web-ui/index.html +12 -0
- 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.index.mjs +2 -0
- 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 +39 -0
- package/web-ui/modules/app.methods.web-ui-preferences.mjs +9 -0
- package/web-ui/modules/i18n/locales/en.mjs +80 -2
- package/web-ui/modules/i18n/locales/ja.mjs +80 -2
- package/web-ui/modules/i18n/locales/vi.mjs +80 -2
- package/web-ui/modules/i18n/locales/zh-tw.mjs +80 -2
- package/web-ui/modules/i18n/locales/zh.mjs +80 -2
- 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 +47 -30
- package/web-ui/partials/index/panel-settings.html +30 -0
- package/web-ui/res/web-ui-render.precompiled.js +244 -157
- package/web-ui/session-helpers.mjs +3 -0
- package/web-ui/styles/base-theme.css +3 -2
- package/web-ui/styles/bridge-pool.css +1 -1
- package/web-ui/styles/controls-forms.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/sessions-toolbar-trash.css +1 -1
- package/web-ui/styles/sessions-usage.css +1 -1
- package/web-ui/styles/settings-panel.css +2 -2
- package/web-ui/styles/theme-dark-tokens.css +83 -0
- package/web-ui/styles/theme-dark.css +1355 -0
- package/web-ui/styles/theme-ocean-tokens.css +88 -0
- package/web-ui/styles/theme-ocean.css +920 -0
- package/web-ui/styles.css +2 -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');
|
|
@@ -757,6 +772,7 @@ base_url = "http://127.0.0.1:3737/bridge/local/v1"
|
|
|
757
772
|
wire_api = "responses"
|
|
758
773
|
requires_openai_auth = true
|
|
759
774
|
preferred_auth_method = "codexmate"
|
|
775
|
+
experimental_bearer_token = "codexmate"
|
|
760
776
|
codexmate_bridge = "local"
|
|
761
777
|
request_max_retries = 4
|
|
762
778
|
stream_max_retries = 10
|
|
@@ -771,7 +787,8 @@ let g_sessionFileLookupCache = {
|
|
|
771
787
|
gemini: new Map(),
|
|
772
788
|
codebuddy: new Map(),
|
|
773
789
|
workbuddy: new Map(),
|
|
774
|
-
pi: new Map()
|
|
790
|
+
pi: new Map(),
|
|
791
|
+
zed: new Map()
|
|
775
792
|
};
|
|
776
793
|
let g_exactMessageCountCache = new Map();
|
|
777
794
|
let g_modelsCache = new Map();
|
|
@@ -893,17 +910,27 @@ function writeCurrentModels(data) {
|
|
|
893
910
|
fs.writeFileSync(CURRENT_MODELS_FILE, JSON.stringify(data, null, 2), 'utf-8');
|
|
894
911
|
}
|
|
895
912
|
|
|
896
|
-
function
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
913
|
+
function ensureActiveProviderBearerToken(content, providerName, providerSegments = null) {
|
|
914
|
+
// 单文件认证:auth.json 不再写入,激活 provider 块缺 experimental_bearer_token 时
|
|
915
|
+
// 从 preferred_auth_method(内部键仓)惰性补写,保证 codex 仅凭 config.toml 取到密钥。
|
|
916
|
+
const ranges = findProviderSectionRanges(content, providerName, providerSegments);
|
|
917
|
+
if (!ranges.length) return content;
|
|
918
|
+
let updated = content;
|
|
919
|
+
const sorted = [...ranges].sort((a, b) => b.start - a.start);
|
|
920
|
+
for (const range of sorted) {
|
|
921
|
+
const block = updated.slice(range.start, range.end);
|
|
922
|
+
if (/(^|\n)\s*experimental_bearer_token\s*=/.test(block)) continue;
|
|
923
|
+
const prefMatch = block.match(/^(\s*)preferred_auth_method\s*=\s*"((?:\\.|[^"\\\n])*)"\s*(?:#.*)?$/m);
|
|
924
|
+
if (!prefMatch || !prefMatch[2].trim()) continue;
|
|
925
|
+
const insertLine = `${prefMatch[1]}experimental_bearer_token = "${prefMatch[2]}"`;
|
|
926
|
+
const lineEndIndex = block.indexOf('\n', prefMatch.index + prefMatch[0].length);
|
|
927
|
+
const insertAt = lineEndIndex === -1
|
|
928
|
+
? range.start + block.length
|
|
929
|
+
: range.start + lineEndIndex + 1;
|
|
930
|
+
const prefix = lineEndIndex === -1 ? '\n' : '';
|
|
931
|
+
updated = updated.slice(0, insertAt) + prefix + insertLine + '\n' + updated.slice(insertAt);
|
|
904
932
|
}
|
|
905
|
-
|
|
906
|
-
fs.writeFileSync(AUTH_FILE, JSON.stringify(authData, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
933
|
+
return updated;
|
|
907
934
|
}
|
|
908
935
|
|
|
909
936
|
function isPlainObject(value) {
|
|
@@ -1029,6 +1056,11 @@ function normalizeSidebarCollapsedPreference(value) {
|
|
|
1029
1056
|
return normalizeBooleanPreference(value, false);
|
|
1030
1057
|
}
|
|
1031
1058
|
|
|
1059
|
+
function normalizeThemePreference(value) {
|
|
1060
|
+
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
1061
|
+
return normalized === 'dark' || normalized === 'ocean' ? normalized : 'light';
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1032
1064
|
function normalizeSessionFilterSourcePreference(value) {
|
|
1033
1065
|
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
1034
1066
|
if (normalized === 'all' || normalized === 'claude' || normalized === 'gemini' || normalized === 'codebuddy' || normalized === 'workbuddy' || normalized === 'pi') return normalized;
|
|
@@ -1100,6 +1132,7 @@ function normalizeWebUiPreferences(value = {}) {
|
|
|
1100
1132
|
sysPromptMode: normalizeSysPromptModePreference(source.sysPromptMode),
|
|
1101
1133
|
projectClaudeMdPath: typeof source.projectClaudeMdPath === 'string' ? source.projectClaudeMdPath : '',
|
|
1102
1134
|
sidebarCollapsed: normalizeSidebarCollapsedPreference(source.sidebarCollapsed),
|
|
1135
|
+
theme: normalizeThemePreference(source.theme),
|
|
1103
1136
|
starPrompted: normalizeBooleanPreference(source.starPrompted, false),
|
|
1104
1137
|
sessionLoadNativeDialog: normalizeBooleanPreference(source.sessionLoadNativeDialog, false),
|
|
1105
1138
|
language: typeof source.language === 'string' ? source.language : '',
|
|
@@ -1549,6 +1582,7 @@ const PROVIDER_CONFIG_KEYS = new Set([
|
|
|
1549
1582
|
'wire_api',
|
|
1550
1583
|
'requires_openai_auth',
|
|
1551
1584
|
'preferred_auth_method',
|
|
1585
|
+
'experimental_bearer_token',
|
|
1552
1586
|
'request_max_retries',
|
|
1553
1587
|
'stream_max_retries',
|
|
1554
1588
|
'stream_idle_timeout_ms'
|
|
@@ -2400,6 +2434,260 @@ function listOpencodeSessions(limit, options = {}) {
|
|
|
2400
2434
|
}, []);
|
|
2401
2435
|
}
|
|
2402
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
|
+
}
|
|
2403
2691
|
function getCodexmateDerivedSessionsRoot(target) {
|
|
2404
2692
|
if (target === 'claude') {
|
|
2405
2693
|
return CODEXMATE_DERIVED_CLAUDE_DIR;
|
|
@@ -2753,7 +3041,6 @@ const {
|
|
|
2753
3041
|
writeModels,
|
|
2754
3042
|
readCurrentModels,
|
|
2755
3043
|
writeCurrentModels,
|
|
2756
|
-
updateAuthJson,
|
|
2757
3044
|
CONFIG_DIR,
|
|
2758
3045
|
CONFIG_FILE,
|
|
2759
3046
|
AUTH_FILE,
|
|
@@ -3071,8 +3358,8 @@ function applyConfigTemplate(params = {}) {
|
|
|
3071
3358
|
return { error: `模板中找不到当前 provider: ${activeProvider}` };
|
|
3072
3359
|
}
|
|
3073
3360
|
|
|
3074
|
-
|
|
3075
|
-
|
|
3361
|
+
const ensuredTemplate = ensureActiveProviderBearerToken(template.trim(), activeProvider);
|
|
3362
|
+
writeConfig(ensuredTemplate + '\n');
|
|
3076
3363
|
|
|
3077
3364
|
const models = readModels();
|
|
3078
3365
|
if (!models.includes(parsed.model)) {
|
|
@@ -3310,6 +3597,7 @@ function addProviderToConfig(params = {}) {
|
|
|
3310
3597
|
`wire_api = "responses"`,
|
|
3311
3598
|
`requires_openai_auth = true`,
|
|
3312
3599
|
`preferred_auth_method = "${safeKey}"`,
|
|
3600
|
+
`experimental_bearer_token = "${safeKey}"`,
|
|
3313
3601
|
`models = [{ id = "${escapeTomlBasicString(model)}", name = "${escapeTomlBasicString(model)}" }]`,
|
|
3314
3602
|
...extraLines,
|
|
3315
3603
|
`request_max_retries = 4`,
|
|
@@ -4672,7 +4960,7 @@ async function hydrateSessionItemsExactMessageCount(items) {
|
|
|
4672
4960
|
|
|
4673
4961
|
function normalizeSessionSourceName(value, fallback = '') {
|
|
4674
4962
|
const source = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
4675
|
-
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') {
|
|
4676
4964
|
return source;
|
|
4677
4965
|
}
|
|
4678
4966
|
return fallback;
|
|
@@ -4690,6 +4978,7 @@ function getSessionSourceLabel(source) {
|
|
|
4690
4978
|
if (source === 'workbuddy') return 'WorkBuddy AI';
|
|
4691
4979
|
if (source === 'pi') return 'Pi';
|
|
4692
4980
|
if (source === 'opencode') return 'OpenCode';
|
|
4981
|
+
if (source === 'zed') return 'Zed';
|
|
4693
4982
|
return 'Codex';
|
|
4694
4983
|
}
|
|
4695
4984
|
|
|
@@ -4700,6 +4989,7 @@ function getSessionSourceProvider(source) {
|
|
|
4700
4989
|
if (source === 'workbuddy') return 'workbuddy';
|
|
4701
4990
|
if (source === 'pi') return 'pi';
|
|
4702
4991
|
if (source === 'opencode') return 'opencode';
|
|
4992
|
+
if (source === 'zed') return 'zed';
|
|
4703
4993
|
return 'codex';
|
|
4704
4994
|
}
|
|
4705
4995
|
|
|
@@ -4729,6 +5019,9 @@ async function readSessionMessageCounts(params = {}) {
|
|
|
4729
5019
|
if (source === 'opencode') {
|
|
4730
5020
|
const opencodeSessionId = item.sessionId || parseOpencodeVirtualSessionId(filePath);
|
|
4731
5021
|
exactMessageCount = countOpencodeMessages(opencodeSessionId);
|
|
5022
|
+
} else if (source === 'zed') {
|
|
5023
|
+
const zedSessionId = item.sessionId || parseZedVirtualSessionId(filePath);
|
|
5024
|
+
exactMessageCount = countZedMessages(zedSessionId);
|
|
4732
5025
|
} else {
|
|
4733
5026
|
if (!filePath || !fs.existsSync(filePath)) {
|
|
4734
5027
|
return { key };
|
|
@@ -4879,6 +5172,7 @@ function createSessionQueryScanState(tokens, options = {}) {
|
|
|
4879
5172
|
count: 0,
|
|
4880
5173
|
snippets: [],
|
|
4881
5174
|
positions: [],
|
|
5175
|
+
complete: true,
|
|
4882
5176
|
leadingSystem: roleFilter !== 'system'
|
|
4883
5177
|
};
|
|
4884
5178
|
}
|
|
@@ -4917,11 +5211,13 @@ function consumeSessionQueryMessage(state, message) {
|
|
|
4917
5211
|
timestamp: typeof message.timestamp === 'string' ? message.timestamp : ''
|
|
4918
5212
|
});
|
|
4919
5213
|
}
|
|
5214
|
+
if (state.count >= state.maxMatches) state.complete = false;
|
|
4920
5215
|
return state.count >= state.maxMatches;
|
|
4921
5216
|
}
|
|
4922
5217
|
|
|
4923
5218
|
function buildSessionQueryScanResult(state) {
|
|
4924
5219
|
return {
|
|
5220
|
+
complete: !!(state && state.complete),
|
|
4925
5221
|
hit: !!(state && state.count > 0),
|
|
4926
5222
|
count: state && Number.isFinite(state.count) ? state.count : 0,
|
|
4927
5223
|
snippets: state && Array.isArray(state.snippets) ? state.snippets : [],
|
|
@@ -4966,6 +5262,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4966
5262
|
const state = createSessionQueryScanState(tokens, options);
|
|
4967
5263
|
if (session.source === 'opencode') {
|
|
4968
5264
|
const extracted = queryOpencodeSessionMessages(session.sessionId || parseOpencodeVirtualSessionId(filePath), { maxMessages: Infinity });
|
|
5265
|
+
state.complete = !!extracted && !extracted.truncated;
|
|
4969
5266
|
const messages = extracted && Array.isArray(extracted.messages) ? extracted.messages : [];
|
|
4970
5267
|
for (let i = 0; i < messages.length; i += 1) {
|
|
4971
5268
|
const message = { ...messages[i], recordLineIndex: i };
|
|
@@ -4973,6 +5270,16 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4973
5270
|
}
|
|
4974
5271
|
return buildSessionQueryScanResult(state);
|
|
4975
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
|
+
}
|
|
4976
5283
|
if (session.source === 'gemini') {
|
|
4977
5284
|
if (state.roleFilter !== 'all' || state.positionsLimit > 0) {
|
|
4978
5285
|
let json;
|
|
@@ -4981,6 +5288,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
4981
5288
|
} catch (_) {
|
|
4982
5289
|
json = null;
|
|
4983
5290
|
}
|
|
5291
|
+
state.complete = !!json;
|
|
4984
5292
|
const rawMessages = json && Array.isArray(json.messages) ? json.messages : [];
|
|
4985
5293
|
for (const entry of rawMessages) {
|
|
4986
5294
|
if (!entry || typeof entry !== 'object') continue;
|
|
@@ -5008,12 +5316,14 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5008
5316
|
const buf = Buffer.alloc(targetBytes);
|
|
5009
5317
|
const bytes = fs.readSync(fd, buf, 0, targetBytes, 0);
|
|
5010
5318
|
fs.closeSync(fd);
|
|
5319
|
+
state.complete = bytes >= stat.size;
|
|
5011
5320
|
text = bytes > 0 ? buf.slice(0, bytes).toString('utf-8') : '';
|
|
5012
5321
|
} catch (_) {
|
|
5013
5322
|
try {
|
|
5014
5323
|
text = fs.readFileSync(filePath, 'utf-8');
|
|
5015
5324
|
} catch (_) {
|
|
5016
5325
|
text = '';
|
|
5326
|
+
state.complete = false;
|
|
5017
5327
|
}
|
|
5018
5328
|
}
|
|
5019
5329
|
|
|
@@ -5038,6 +5348,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5038
5348
|
const currentLineIndex = lineIndex;
|
|
5039
5349
|
lineIndex += 1;
|
|
5040
5350
|
if (maxBytes > 0 && bytesRead >= maxBytes) {
|
|
5351
|
+
state.complete = false;
|
|
5041
5352
|
break;
|
|
5042
5353
|
}
|
|
5043
5354
|
|
|
@@ -5067,6 +5378,7 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5067
5378
|
|
|
5068
5379
|
return buildSessionQueryScanResult(state);
|
|
5069
5380
|
} catch (e) {
|
|
5381
|
+
state.complete = false;
|
|
5070
5382
|
return scanSessionContentForQueryInRecords(readJsonlRecords(filePath), session.source, state);
|
|
5071
5383
|
} finally {
|
|
5072
5384
|
if (rl) {
|
|
@@ -5081,7 +5393,9 @@ async function scanSessionContentForQuery(session, tokens, options = {}) {
|
|
|
5081
5393
|
async function applySessionQueryFilter(sessions, options = {}) {
|
|
5082
5394
|
const tokens = Array.isArray(options.tokens) ? options.tokens : [];
|
|
5083
5395
|
if (tokens.length === 0) {
|
|
5084
|
-
|
|
5396
|
+
const result = sessions.slice();
|
|
5397
|
+
Object.defineProperty(result, 'searchInfo', { value: null });
|
|
5398
|
+
return result;
|
|
5085
5399
|
}
|
|
5086
5400
|
|
|
5087
5401
|
const mode = normalizeQueryMode(options.queryMode);
|
|
@@ -5095,10 +5409,12 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5095
5409
|
: 0;
|
|
5096
5410
|
|
|
5097
5411
|
let scanned = 0;
|
|
5412
|
+
let complete = true;
|
|
5098
5413
|
const results = [];
|
|
5099
5414
|
|
|
5100
5415
|
for (const session of sessions) {
|
|
5101
5416
|
if (scope === 'content' && scanned >= contentScanLimit) {
|
|
5417
|
+
complete = false;
|
|
5102
5418
|
break;
|
|
5103
5419
|
}
|
|
5104
5420
|
|
|
@@ -5118,6 +5434,10 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5118
5434
|
snippetLimit: 2
|
|
5119
5435
|
});
|
|
5120
5436
|
contentHit = contentInfo.hit;
|
|
5437
|
+
// 命中已完成候选的存在性判定,无需穷尽匹配或消息。
|
|
5438
|
+
if (!contentHit && !contentInfo.complete) complete = false;
|
|
5439
|
+
} else if (shouldScanContent) {
|
|
5440
|
+
complete = false;
|
|
5121
5441
|
}
|
|
5122
5442
|
|
|
5123
5443
|
const hit = scope === 'summary'
|
|
@@ -5139,6 +5459,9 @@ async function applySessionQueryFilter(sessions, options = {}) {
|
|
|
5139
5459
|
results.push(session);
|
|
5140
5460
|
}
|
|
5141
5461
|
|
|
5462
|
+
Object.defineProperty(results, 'searchInfo', {
|
|
5463
|
+
value: { scanned, candidates: sessions.length, complete }
|
|
5464
|
+
});
|
|
5142
5465
|
return results;
|
|
5143
5466
|
}
|
|
5144
5467
|
function collectRecentJsonlFiles(rootDir, options = {}) {
|
|
@@ -5364,7 +5687,7 @@ function getSessionInventoryCache(cacheKey, forceRefresh = false) {
|
|
|
5364
5687
|
}
|
|
5365
5688
|
|
|
5366
5689
|
function registerSessionFileLookupEntries(source, sessions = []) {
|
|
5367
|
-
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'
|
|
5368
5691
|
? source
|
|
5369
5692
|
: 'codex';
|
|
5370
5693
|
const store = g_sessionFileLookupCache[normalizedSource];
|
|
@@ -5405,7 +5728,7 @@ function setSessionInventoryCache(cacheKey, source, value) {
|
|
|
5405
5728
|
}
|
|
5406
5729
|
|
|
5407
5730
|
function listSessionInventoryBySource(source, limit, scanOptions = {}, options = {}) {
|
|
5408
|
-
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'
|
|
5409
5732
|
? source
|
|
5410
5733
|
: 'codex';
|
|
5411
5734
|
const forceRefresh = !!options.forceRefresh;
|
|
@@ -5427,7 +5750,9 @@ function listSessionInventoryBySource(source, limit, scanOptions = {}, options =
|
|
|
5427
5750
|
? listPiSessions(limit, scanOptions)
|
|
5428
5751
|
: (normalizedSource === 'opencode'
|
|
5429
5752
|
? listOpencodeSessions(limit, scanOptions)
|
|
5430
|
-
:
|
|
5753
|
+
: (normalizedSource === 'zed'
|
|
5754
|
+
? listZedSessions(limit, scanOptions)
|
|
5755
|
+
: listCodexSessions(limit, scanOptions)))))));
|
|
5431
5756
|
setSessionInventoryCache(cacheKey, normalizedSource, sessions);
|
|
5432
5757
|
return sessions;
|
|
5433
5758
|
}
|
|
@@ -5442,7 +5767,8 @@ function invalidateSessionListCache() {
|
|
|
5442
5767
|
codebuddy: new Map(),
|
|
5443
5768
|
workbuddy: new Map(),
|
|
5444
5769
|
pi: new Map(),
|
|
5445
|
-
opencode: new Map()
|
|
5770
|
+
opencode: new Map(),
|
|
5771
|
+
zed: new Map()
|
|
5446
5772
|
};
|
|
5447
5773
|
}
|
|
5448
5774
|
|
|
@@ -7308,6 +7634,9 @@ async function listAllSessions(params = {}) {
|
|
|
7308
7634
|
if (source === 'all' || source === 'opencode') {
|
|
7309
7635
|
sessions = sessions.concat(listSessionInventoryBySource('opencode', limit, scanOptions, { forceRefresh }));
|
|
7310
7636
|
}
|
|
7637
|
+
if (source === 'all' || source === 'zed') {
|
|
7638
|
+
sessions = sessions.concat(listSessionInventoryBySource('zed', limit, scanOptions, { forceRefresh }));
|
|
7639
|
+
}
|
|
7311
7640
|
|
|
7312
7641
|
if (hasPathFilter) {
|
|
7313
7642
|
sessions = sessions.filter(item => matchesSessionPathFilter(item, normalizedPathFilter));
|
|
@@ -7324,7 +7653,9 @@ async function listAllSessions(params = {}) {
|
|
|
7324
7653
|
contentScanBytes: params.contentScanBytes
|
|
7325
7654
|
});
|
|
7326
7655
|
}
|
|
7656
|
+
const searchInfo = hasQuery ? result.searchInfo : null;
|
|
7327
7657
|
result = mergeAndLimitSessions(result, limit);
|
|
7658
|
+
Object.defineProperty(result, 'searchInfo', { value: searchInfo });
|
|
7328
7659
|
setSessionListCache(cacheKey, result);
|
|
7329
7660
|
return result;
|
|
7330
7661
|
}
|
|
@@ -7357,6 +7688,7 @@ async function listAllSessionsData(params = {}) {
|
|
|
7357
7688
|
delete normalized.__messageCountExact;
|
|
7358
7689
|
return normalized;
|
|
7359
7690
|
});
|
|
7691
|
+
Object.defineProperty(result, 'searchInfo', { value: sessions.searchInfo || null });
|
|
7360
7692
|
if (!hasQuery) {
|
|
7361
7693
|
setSessionListCache(cacheKey, result);
|
|
7362
7694
|
}
|
|
@@ -7368,7 +7700,7 @@ async function listSessionBrowse(params = {}) {
|
|
|
7368
7700
|
...params,
|
|
7369
7701
|
browseLightweight: true
|
|
7370
7702
|
});
|
|
7371
|
-
|
|
7703
|
+
const result = Array.isArray(sessions)
|
|
7372
7704
|
? sessions.map((item) => {
|
|
7373
7705
|
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
7374
7706
|
return item;
|
|
@@ -7378,6 +7710,8 @@ async function listSessionBrowse(params = {}) {
|
|
|
7378
7710
|
return normalized;
|
|
7379
7711
|
})
|
|
7380
7712
|
: [];
|
|
7713
|
+
Object.defineProperty(result, 'searchInfo', { value: sessions.searchInfo || null });
|
|
7714
|
+
return result;
|
|
7381
7715
|
}
|
|
7382
7716
|
|
|
7383
7717
|
async function listSessionUsage(params = {}) {
|
|
@@ -7449,6 +7783,9 @@ function listSessionPaths(params = {}) {
|
|
|
7449
7783
|
if (validSource === 'all' || validSource === 'opencode') {
|
|
7450
7784
|
sessions = sessions.concat(listSessionInventoryBySource('opencode', gatherLimit, scanOptions, { forceRefresh }));
|
|
7451
7785
|
}
|
|
7786
|
+
if (validSource === 'all' || validSource === 'zed') {
|
|
7787
|
+
sessions = sessions.concat(listSessionInventoryBySource('zed', gatherLimit, scanOptions, { forceRefresh }));
|
|
7788
|
+
}
|
|
7452
7789
|
|
|
7453
7790
|
const dedupedPaths = [];
|
|
7454
7791
|
const seen = new Set();
|
|
@@ -7475,6 +7812,12 @@ function listSessionPaths(params = {}) {
|
|
|
7475
7812
|
|
|
7476
7813
|
function resolveSessionFilePath(source, filePath, sessionId) {
|
|
7477
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
|
+
}
|
|
7478
7821
|
if (normalizedSource === 'opencode') {
|
|
7479
7822
|
const id = typeof sessionId === 'string' && sessionId.trim()
|
|
7480
7823
|
? sessionId.trim()
|
|
@@ -8055,7 +8398,7 @@ function buildSessionSummaryFallback(source, filePath, sessionId = '') {
|
|
|
8055
8398
|
contextWindow: 0,
|
|
8056
8399
|
filePath,
|
|
8057
8400
|
keywords: [],
|
|
8058
|
-
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 } : {}
|
|
8059
8402
|
};
|
|
8060
8403
|
}
|
|
8061
8404
|
|
|
@@ -8642,6 +8985,9 @@ async function trashSessionData(params = {}) {
|
|
|
8642
8985
|
if (source === 'opencode') {
|
|
8643
8986
|
return { error: 'OpenCode DB-backed sessions cannot be deleted from CodexMate' };
|
|
8644
8987
|
}
|
|
8988
|
+
if (source === 'zed') {
|
|
8989
|
+
return { error: 'Zed DB-backed sessions cannot be deleted from CodexMate' };
|
|
8990
|
+
}
|
|
8645
8991
|
|
|
8646
8992
|
const filePath = resolveSessionFilePath(source, getSessionFileArg(params), params.sessionId);
|
|
8647
8993
|
if (!filePath) {
|
|
@@ -8754,6 +9100,9 @@ async function deleteSessionData(params = {}) {
|
|
|
8754
9100
|
if (source === 'opencode') {
|
|
8755
9101
|
return { error: 'OpenCode DB-backed sessions cannot be deleted from CodexMate' };
|
|
8756
9102
|
}
|
|
9103
|
+
if (source === 'zed') {
|
|
9104
|
+
return { error: 'Zed DB-backed sessions cannot be deleted from CodexMate' };
|
|
9105
|
+
}
|
|
8757
9106
|
|
|
8758
9107
|
const filePath = resolveSessionFilePath(source, getSessionFileArg(params), params.sessionId);
|
|
8759
9108
|
if (!filePath) {
|
|
@@ -9453,6 +9802,13 @@ async function readSessionDetail(params = {}) {
|
|
|
9453
9802
|
if (!extracted) {
|
|
9454
9803
|
return { error: 'Failed to parse session file' };
|
|
9455
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
|
+
}
|
|
9456
9812
|
} else if (source === 'gemini') {
|
|
9457
9813
|
let json;
|
|
9458
9814
|
try {
|
|
@@ -9587,6 +9943,13 @@ async function readSessionPlain(params = {}) {
|
|
|
9587
9943
|
if (!extracted) {
|
|
9588
9944
|
return { error: 'Failed to parse session file' };
|
|
9589
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
|
+
}
|
|
9590
9953
|
} else if (source === 'gemini') {
|
|
9591
9954
|
let json;
|
|
9592
9955
|
try {
|
|
@@ -9671,6 +10034,12 @@ async function exportSessionData(params = {}) {
|
|
|
9671
10034
|
if (!extracted) {
|
|
9672
10035
|
return { error: 'Failed to parse session file' };
|
|
9673
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
|
+
}
|
|
9674
10043
|
} else if (source === 'gemini') {
|
|
9675
10044
|
let json;
|
|
9676
10045
|
try {
|
|
@@ -10921,17 +11290,16 @@ function cmdSwitch(providerName, silent = false) {
|
|
|
10921
11290
|
throw new Error('提供商不存在');
|
|
10922
11291
|
}
|
|
10923
11292
|
|
|
10924
|
-
//
|
|
11293
|
+
// 切换提供商(单文件认证:同步确保目标块含 experimental_bearer_token)
|
|
10925
11294
|
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
10926
|
-
const
|
|
11295
|
+
const switchedContent = content.replace(
|
|
10927
11296
|
/^(model_provider\s*=\s*)(["']).*?(["'])/m,
|
|
10928
11297
|
`$1$2${providerName}$3`
|
|
10929
11298
|
);
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
updateAuthJson(apiKey);
|
|
11299
|
+
const providerSegments = providers[providerName] && Array.isArray(providers[providerName].__codexmate_legacy_segments)
|
|
11300
|
+
? providers[providerName].__codexmate_legacy_segments
|
|
11301
|
+
: null;
|
|
11302
|
+
writeConfig(ensureActiveProviderBearerToken(switchedContent, providerName, providerSegments));
|
|
10935
11303
|
|
|
10936
11304
|
// 切换到该提供商的模型
|
|
10937
11305
|
const currentModels = readCurrentModels();
|
|
@@ -11072,6 +11440,7 @@ base_url = "${safeBaseUrl}"
|
|
|
11072
11440
|
wire_api = "responses"
|
|
11073
11441
|
requires_openai_auth = true
|
|
11074
11442
|
preferred_auth_method = "${safeApiKey}"
|
|
11443
|
+
experimental_bearer_token = "${safeApiKey}"
|
|
11075
11444
|
request_max_retries = 4
|
|
11076
11445
|
stream_max_retries = 10
|
|
11077
11446
|
stream_idle_timeout_ms = 300000
|
|
@@ -11373,6 +11742,7 @@ function cmdUpdate(name, baseUrl, apiKey, silent = false, options = {}) {
|
|
|
11373
11742
|
updatedBlock = replaceTomlStringField(updatedBlock, 'base_url', computeLocalOpenaiBridgeBaseUrl());
|
|
11374
11743
|
updatedBlock = replaceTomlBooleanField(updatedBlock, 'requires_openai_auth', true);
|
|
11375
11744
|
updatedBlock = replaceTomlStringField(updatedBlock, 'preferred_auth_method', 'codexmate');
|
|
11745
|
+
updatedBlock = replaceTomlStringField(updatedBlock, 'experimental_bearer_token', 'codexmate');
|
|
11376
11746
|
updatedBlock = replaceTomlStringField(updatedBlock, 'codexmate_bridge', 'openai');
|
|
11377
11747
|
if (hasOpenaiBridgeMaxRetries) {
|
|
11378
11748
|
updatedBlock = replaceTomlNumberField(updatedBlock, 'codexmate_bridge_max_retries', openaiBridgeMaxRetries);
|
|
@@ -11383,6 +11753,7 @@ function cmdUpdate(name, baseUrl, apiKey, silent = false, options = {}) {
|
|
|
11383
11753
|
}
|
|
11384
11754
|
if (apiKey !== undefined) {
|
|
11385
11755
|
updatedBlock = replaceTomlStringField(updatedBlock, 'preferred_auth_method', apiKey);
|
|
11756
|
+
updatedBlock = replaceTomlStringField(updatedBlock, 'experimental_bearer_token', apiKey);
|
|
11386
11757
|
}
|
|
11387
11758
|
}
|
|
11388
11759
|
|
|
@@ -11397,12 +11768,6 @@ function cmdUpdate(name, baseUrl, apiKey, silent = false, options = {}) {
|
|
|
11397
11768
|
}
|
|
11398
11769
|
writeConfig(finalContent);
|
|
11399
11770
|
|
|
11400
|
-
// 如果更新了 API Key 且该提供商是当前激活的,同步更新 auth.json
|
|
11401
|
-
const currentProvider = config.model_provider;
|
|
11402
|
-
if (apiKey !== undefined && name === currentProvider) {
|
|
11403
|
-
updateAuthJson(apiKey);
|
|
11404
|
-
}
|
|
11405
|
-
|
|
11406
11771
|
if (!silent) {
|
|
11407
11772
|
console.log('✓ 已更新提供商:', name);
|
|
11408
11773
|
console.log();
|
|
@@ -12916,7 +13281,7 @@ function resolveExportOutputPath(outputPath, defaultFileName) {
|
|
|
12916
13281
|
}
|
|
12917
13282
|
|
|
12918
13283
|
function printExportSessionUsage() {
|
|
12919
|
-
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>]');
|
|
12920
13285
|
console.log('\n示例:');
|
|
12921
13286
|
console.log(' codexmate export-session --source codex --session-id 123456');
|
|
12922
13287
|
console.log(' codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl"');
|
|
@@ -12989,7 +13354,7 @@ function parseExportSessionArgs(args = []) {
|
|
|
12989
13354
|
|
|
12990
13355
|
const normalizedSource = options.source.trim().toLowerCase();
|
|
12991
13356
|
if (normalizedSource && !isSessionSourceOrAll(normalizedSource)) {
|
|
12992
|
-
errors.push('参数 --source 仅支持 codex、claude、gemini、codebuddy、workbuddy、pi 或
|
|
13357
|
+
errors.push('参数 --source 仅支持 codex、claude、gemini、codebuddy、workbuddy、pi、opencode 或 zed');
|
|
12993
13358
|
}
|
|
12994
13359
|
options.source = normalizedSource;
|
|
12995
13360
|
|
|
@@ -14420,9 +14785,11 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
14420
14785
|
if (source && !isSessionSourceOrAll(source)) {
|
|
14421
14786
|
result = { error: 'Invalid source. Must be codex, claude, gemini, codebuddy, workbuddy, pi, opencode, or all' };
|
|
14422
14787
|
} else {
|
|
14788
|
+
const sessions = await listSessionBrowse(params);
|
|
14423
14789
|
result = {
|
|
14424
|
-
sessions
|
|
14425
|
-
source: source || 'all'
|
|
14790
|
+
sessions,
|
|
14791
|
+
source: source || 'all',
|
|
14792
|
+
searchInfo: sessions.searchInfo
|
|
14426
14793
|
};
|
|
14427
14794
|
}
|
|
14428
14795
|
}
|
|
@@ -17361,7 +17728,7 @@ function printMainHelp() {
|
|
|
17361
17728
|
console.log(' 注: follow-up 自动排队仅支持 linux/android/netbsd/openbsd/darwin/freebsd 且 stdin 必须是 TTY,其他平台会报错');
|
|
17362
17729
|
console.log(' codexmate qwen [参数...] 等同于 qwen --yolo');
|
|
17363
17730
|
console.log(' codexmate mcp [serve] [--transport stdio] [--allow-write|--read-only]');
|
|
17364
|
-
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>]');
|
|
17365
17732
|
console.log(' codexmate convert-session --from <codex|claude> --to <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]');
|
|
17366
17733
|
console.log(' codexmate zip <路径> [--max:级别] 压缩(系统 zip 优先,其次 zip-lib)');
|
|
17367
17734
|
console.log(' codexmate unzip <zip文件> [输出目录] 解压(zip-lib)');
|