cli-link 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -14
- package/dist/client/assets/History-D2xDopni.js +4 -0
- package/dist/client/assets/ImageViewer-DuegU_fC.js +1 -0
- package/dist/client/assets/MarkdownRenderer-CsyizEL3.js +1 -0
- package/dist/client/assets/{PageTopBar-C8j-5s_3.js → PageTopBar-CQwjO6Af.js} +1 -1
- package/dist/client/assets/Session-B0s5zBGg.js +7 -0
- package/dist/client/assets/Settings-CfHFmJdV.js +1 -0
- package/dist/client/assets/Workspace-Cfl0mbNE.js +4 -0
- package/dist/client/assets/WorkspaceLinkedText-DCVYd9x-.js +2 -0
- package/dist/client/assets/c-BIGW1oBm.js +1 -0
- package/dist/client/assets/cpp-DIPi6g--.js +1 -0
- package/dist/client/assets/csharp-DSvCPggb.js +1 -0
- package/dist/client/assets/dart-bE4Kk8sk.js +1 -0
- package/dist/client/assets/dotenv-Da5cRb03.js +1 -0
- package/dist/client/assets/go-C27-OAKa.js +1 -0
- package/dist/client/assets/graphql-pNE0_Gx8.js +1 -0
- package/dist/client/assets/groovy-gcz8RCvz.js +1 -0
- package/dist/client/assets/index-BCg3ymV3.css +1 -0
- package/dist/client/assets/index-CrJqHlc8.js +2 -0
- package/dist/client/assets/java-VnEXKtx_.js +148 -0
- package/dist/client/assets/jsx-g9-lgVsj.js +1 -0
- package/dist/client/assets/kotlin-BdnUsdx6.js +1 -0
- package/dist/client/assets/less-B1dDrJ26.js +1 -0
- package/dist/client/assets/lua-BaeVxFsk.js +1 -0
- package/dist/client/assets/makefile-CHLpvVh8.js +1 -0
- package/dist/client/assets/php-BcCyJq-p.js +1 -0
- package/dist/client/assets/properties-DTPjHERo.js +1 -0
- package/dist/client/assets/ruby-BwImf3Ka.js +1 -0
- package/dist/client/assets/rust-B1yitclQ.js +1 -0
- package/dist/client/assets/scss-lMagJa-5.js +1 -0
- package/dist/client/assets/sql-CRqJ_cUM.js +1 -0
- package/dist/client/assets/svelte-B4a9v_or.js +1 -0
- package/dist/client/assets/swift-D82vCrfD.js +1 -0
- package/dist/client/assets/toml-vGWfd6FD.js +1 -0
- package/dist/client/assets/{vendor-icons-CNN4EKVi.js → vendor-icons-CMXJHDEv.js} +125 -65
- package/dist/client/assets/vendor-markdown--d-T3AbU.js +37 -0
- package/dist/client/assets/{vendor-motion-n6Lx6G4a.js → vendor-motion-D0ZmPdi9.js} +1 -1
- package/dist/client/assets/{vendor-react-DSV5aFEg.js → vendor-react-CcDXZHn_.js} +1 -1
- package/dist/client/assets/{vendor-virtual-CcftJrIC.js → vendor-virtual-DJI7OicV.js} +1 -1
- package/dist/client/assets/vue-DBXACu8K.js +1 -0
- package/dist/client/assets/workspace-return-FrQUv7g3.js +1 -0
- package/dist/client/index.html +4 -4
- package/dist/server/cli-manager.js +151 -26
- package/dist/server/codex-history.js +119 -17
- package/dist/server/index.js +906 -57
- package/dist/server/store.js +369 -27
- package/package.json +3 -3
- package/dist/client/assets/History-BxJVDFpN.js +0 -3
- package/dist/client/assets/MarkdownRenderer-BO-KS_L1.js +0 -1
- package/dist/client/assets/Session-CQFXA2Sr.js +0 -11
- package/dist/client/assets/Settings-DYmjRmoN.js +0 -1
- package/dist/client/assets/Workspace-D8kv9euM.js +0 -8
- package/dist/client/assets/WorkspaceLinkedText-DQyPLk-X.js +0 -2
- package/dist/client/assets/code-highlight-CEcsuMpw.js +0 -1
- package/dist/client/assets/index-BXT2BylN.css +0 -1
- package/dist/client/assets/index-DOgH1Kf3.js +0 -2
- package/dist/client/assets/vendor-markdown-BDwu-Ux6.js +0 -35
|
@@ -55,7 +55,7 @@ function localTime(timestamp, fallbackMs) {
|
|
|
55
55
|
? new Date(timestamp).getTime()
|
|
56
56
|
: Number(timestamp);
|
|
57
57
|
const date = Number.isFinite(ms) && ms > 0 ? new Date(ms) : new Date(fallbackMs || Date.now());
|
|
58
|
-
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
58
|
+
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' });
|
|
59
59
|
}
|
|
60
60
|
function cleanTitle(value) {
|
|
61
61
|
const normalized = safeString(value)
|
|
@@ -70,6 +70,21 @@ function cleanTitle(value) {
|
|
|
70
70
|
return 'Codex 会话记录';
|
|
71
71
|
return normalized.length > 60 ? `${normalized.slice(0, 60).trimEnd()}...` : normalized;
|
|
72
72
|
}
|
|
73
|
+
function selectColumn(columns, name, fallbackSql) {
|
|
74
|
+
return columns.has(name) ? name : `${fallbackSql} AS ${name}`;
|
|
75
|
+
}
|
|
76
|
+
function timestampOrderExpression(columns) {
|
|
77
|
+
const candidates = [];
|
|
78
|
+
if (columns.has('updated_at_ms'))
|
|
79
|
+
candidates.push('updated_at_ms');
|
|
80
|
+
if (columns.has('updated_at'))
|
|
81
|
+
candidates.push('updated_at * 1000');
|
|
82
|
+
if (columns.has('created_at_ms'))
|
|
83
|
+
candidates.push('created_at_ms');
|
|
84
|
+
if (columns.has('created_at'))
|
|
85
|
+
candidates.push('created_at * 1000');
|
|
86
|
+
return candidates.length > 0 ? `COALESCE(${candidates.join(', ')})` : '0';
|
|
87
|
+
}
|
|
73
88
|
function extractContentText(content) {
|
|
74
89
|
if (typeof content === 'string')
|
|
75
90
|
return content;
|
|
@@ -87,15 +102,56 @@ function extractContentText(content) {
|
|
|
87
102
|
.filter(Boolean)
|
|
88
103
|
.join('\n');
|
|
89
104
|
}
|
|
105
|
+
function objectDetails(details) {
|
|
106
|
+
return details && typeof details === 'object' && !Array.isArray(details)
|
|
107
|
+
? { ...details }
|
|
108
|
+
: {};
|
|
109
|
+
}
|
|
110
|
+
function setAssistantPhase(message, phase) {
|
|
111
|
+
const details = objectDetails(message.details);
|
|
112
|
+
if (typeof details.assistantPhase === 'string')
|
|
113
|
+
return;
|
|
114
|
+
message.details = { ...details, assistantPhase: phase };
|
|
115
|
+
}
|
|
116
|
+
function annotateAssistantPhases(messages) {
|
|
117
|
+
let turnStart = 0;
|
|
118
|
+
const finalizeTurn = (turnEnd) => {
|
|
119
|
+
const assistantIndexes = [];
|
|
120
|
+
for (let i = turnStart; i < turnEnd; i += 1) {
|
|
121
|
+
const message = messages[i];
|
|
122
|
+
if (message.type === 'ai_message' || message.type === 'ai') {
|
|
123
|
+
assistantIndexes.push(i);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
assistantIndexes.forEach((messageIndex, index) => {
|
|
127
|
+
setAssistantPhase(messages[messageIndex], index === assistantIndexes.length - 1 ? 'final' : 'progress');
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
for (let i = 0; i < messages.length; i += 1) {
|
|
131
|
+
const message = messages[i];
|
|
132
|
+
if (message.type === 'user_message' || message.type === 'user') {
|
|
133
|
+
finalizeTurn(i);
|
|
134
|
+
turnStart = i + 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
finalizeTurn(messages.length);
|
|
138
|
+
}
|
|
90
139
|
function parseRolloutMessages(thread) {
|
|
91
140
|
const rolloutPath = thread.rollout_path;
|
|
92
141
|
if (!rolloutPath || !existsSync(rolloutPath))
|
|
93
142
|
return [];
|
|
94
|
-
|
|
143
|
+
let lines;
|
|
144
|
+
try {
|
|
145
|
+
if (statSync(rolloutPath).size > MAX_ROLLOUT_BYTES) {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
lines = readFileSync(rolloutPath, 'utf8').split(/\r?\n/).filter(Boolean);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.warn(`[CodexHistory] Failed to read rollout ${rolloutPath}: ${err?.message || err}`);
|
|
95
152
|
return [];
|
|
96
153
|
}
|
|
97
154
|
const startedAt = thread.created_at_ms || (thread.created_at || 0) * 1000 || Date.now();
|
|
98
|
-
const lines = readFileSync(rolloutPath, 'utf8').split(/\r?\n/).filter(Boolean);
|
|
99
155
|
const messages = [];
|
|
100
156
|
const toolByCallId = new Map();
|
|
101
157
|
const push = (message) => {
|
|
@@ -116,6 +172,7 @@ function parseRolloutMessages(thread) {
|
|
|
116
172
|
return next;
|
|
117
173
|
};
|
|
118
174
|
push({
|
|
175
|
+
id: `codex-${thread.id}-system-init`,
|
|
119
176
|
type: 'system',
|
|
120
177
|
content: `Codex session synced (${thread.id.slice(0, 8)}...)`,
|
|
121
178
|
time: localTime(thread.created_at_ms || startedAt, startedAt),
|
|
@@ -129,7 +186,9 @@ function parseRolloutMessages(thread) {
|
|
|
129
186
|
importedFrom: 'codex-client',
|
|
130
187
|
},
|
|
131
188
|
});
|
|
132
|
-
for (
|
|
189
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
190
|
+
const line = lines[index];
|
|
191
|
+
const lineNo = index + 1;
|
|
133
192
|
let entry;
|
|
134
193
|
try {
|
|
135
194
|
entry = JSON.parse(line);
|
|
@@ -145,19 +204,19 @@ function parseRolloutMessages(thread) {
|
|
|
145
204
|
if (payload.type === 'user_message') {
|
|
146
205
|
const content = truncate(payload.message, MAX_MESSAGE_CHARS).trim();
|
|
147
206
|
if (content)
|
|
148
|
-
push({ type: 'user_message', content, time });
|
|
207
|
+
push({ id: `codex-${thread.id}-event-${lineNo}-user`, type: 'user_message', content, time });
|
|
149
208
|
}
|
|
150
209
|
else if (payload.type === 'agent_message') {
|
|
151
210
|
const content = truncate(payload.message, MAX_MESSAGE_CHARS).trim();
|
|
152
211
|
if (content)
|
|
153
|
-
push({ type: 'ai_message', content, time });
|
|
212
|
+
push({ id: `codex-${thread.id}-event-${lineNo}-agent`, type: 'ai_message', content, time });
|
|
154
213
|
}
|
|
155
214
|
continue;
|
|
156
215
|
}
|
|
157
216
|
if (entry.type !== 'response_item')
|
|
158
217
|
continue;
|
|
159
218
|
if (payload.type === 'function_call') {
|
|
160
|
-
const callId = safeString(payload.call_id || payload.id || `
|
|
219
|
+
const callId = safeString(payload.call_id || payload.id || `line-${lineNo}`);
|
|
161
220
|
const toolName = safeString(payload.name || 'tool');
|
|
162
221
|
const tool = push({
|
|
163
222
|
id: `codex-${thread.id}-tool-${callId}`,
|
|
@@ -182,7 +241,7 @@ function parseRolloutMessages(thread) {
|
|
|
182
241
|
}
|
|
183
242
|
else {
|
|
184
243
|
push({
|
|
185
|
-
id: `codex-${thread.id}-tool-output-${
|
|
244
|
+
id: `codex-${thread.id}-tool-output-${lineNo}`,
|
|
186
245
|
type: 'tool_call',
|
|
187
246
|
content: 'tool',
|
|
188
247
|
time,
|
|
@@ -198,12 +257,13 @@ function parseRolloutMessages(thread) {
|
|
|
198
257
|
const content = truncate(extractContentText(payload.content), MAX_MESSAGE_CHARS).trim();
|
|
199
258
|
const last = messages[messages.length - 1];
|
|
200
259
|
if (content && !(last?.type === 'ai_message' && last.content === content)) {
|
|
201
|
-
push({ type: 'ai_message', content, time });
|
|
260
|
+
push({ id: `codex-${thread.id}-event-${lineNo}-assistant`, type: 'ai_message', content, time });
|
|
202
261
|
}
|
|
203
262
|
}
|
|
204
263
|
}
|
|
205
264
|
if (thread.tokens_used && thread.tokens_used > 0) {
|
|
206
265
|
push({
|
|
266
|
+
id: `codex-${thread.id}-system-result`,
|
|
207
267
|
type: 'system',
|
|
208
268
|
content: 'Codex usage summary',
|
|
209
269
|
time: localTime(thread.updated_at_ms || Date.now(), Date.now()),
|
|
@@ -216,6 +276,10 @@ function parseRolloutMessages(thread) {
|
|
|
216
276
|
},
|
|
217
277
|
});
|
|
218
278
|
}
|
|
279
|
+
if (!messages.some(message => message.type === 'user_message' || message.type === 'user')) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
annotateAssistantPhases(messages);
|
|
219
283
|
return messages;
|
|
220
284
|
}
|
|
221
285
|
export function readCodexHistorySessions(options = {}) {
|
|
@@ -225,17 +289,51 @@ export function readCodexHistorySessions(options = {}) {
|
|
|
225
289
|
return [];
|
|
226
290
|
const limit = normalizeLimit(options.limit);
|
|
227
291
|
const workDir = normalizeWorkDir(options.workDir);
|
|
228
|
-
|
|
292
|
+
let db;
|
|
293
|
+
try {
|
|
294
|
+
db = new Database(stateDbPath, { readonly: true, fileMustExist: true });
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
console.warn(`[CodexHistory] Failed to open ${stateDbPath}: ${err?.message || err}`);
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
229
300
|
try {
|
|
301
|
+
const columns = new Set(db.prepare(`PRAGMA table_info(threads)`).all()
|
|
302
|
+
.map(column => column.name));
|
|
303
|
+
if (!columns.has('id') || !columns.has('rollout_path')) {
|
|
304
|
+
console.warn('[CodexHistory] Codex threads table is missing required columns');
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
if (workDir && !columns.has('cwd')) {
|
|
308
|
+
console.warn('[CodexHistory] Codex threads table has no cwd column; scoped sync skipped');
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
const selectedColumns = [
|
|
312
|
+
selectColumn(columns, 'id', "''"),
|
|
313
|
+
selectColumn(columns, 'rollout_path', "''"),
|
|
314
|
+
selectColumn(columns, 'created_at', '0'),
|
|
315
|
+
selectColumn(columns, 'updated_at', '0'),
|
|
316
|
+
selectColumn(columns, 'created_at_ms', '0'),
|
|
317
|
+
selectColumn(columns, 'updated_at_ms', '0'),
|
|
318
|
+
selectColumn(columns, 'title', "''"),
|
|
319
|
+
selectColumn(columns, 'cwd', 'NULL'),
|
|
320
|
+
selectColumn(columns, 'source', "''"),
|
|
321
|
+
selectColumn(columns, 'model', 'NULL'),
|
|
322
|
+
selectColumn(columns, 'reasoning_effort', 'NULL'),
|
|
323
|
+
selectColumn(columns, 'tokens_used', '0'),
|
|
324
|
+
selectColumn(columns, 'first_user_message', "''"),
|
|
325
|
+
].join(', ');
|
|
326
|
+
const where = [
|
|
327
|
+
'rollout_path IS NOT NULL',
|
|
328
|
+
"rollout_path != ''",
|
|
329
|
+
];
|
|
330
|
+
if (workDir)
|
|
331
|
+
where.push('cwd = ?');
|
|
230
332
|
const query = `
|
|
231
|
-
SELECT
|
|
232
|
-
title, cwd, source, model, reasoning_effort, tokens_used, first_user_message
|
|
333
|
+
SELECT ${selectedColumns}
|
|
233
334
|
FROM threads
|
|
234
|
-
WHERE
|
|
235
|
-
|
|
236
|
-
AND has_user_event = 1
|
|
237
|
-
${workDir ? 'AND cwd = ?' : ''}
|
|
238
|
-
ORDER BY COALESCE(updated_at_ms, updated_at * 1000, created_at_ms, created_at * 1000) DESC
|
|
335
|
+
WHERE ${where.join(' AND ')}
|
|
336
|
+
ORDER BY ${timestampOrderExpression(columns)} DESC
|
|
239
337
|
LIMIT ?
|
|
240
338
|
`;
|
|
241
339
|
const params = workDir ? [workDir, limit] : [limit];
|
|
@@ -270,6 +368,10 @@ export function readCodexHistorySessions(options = {}) {
|
|
|
270
368
|
};
|
|
271
369
|
});
|
|
272
370
|
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
console.warn(`[CodexHistory] Failed to read Codex history: ${err?.message || err}`);
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
273
375
|
finally {
|
|
274
376
|
db.close();
|
|
275
377
|
}
|