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.
Files changed (57) hide show
  1. package/README.md +56 -14
  2. package/dist/client/assets/History-D2xDopni.js +4 -0
  3. package/dist/client/assets/ImageViewer-DuegU_fC.js +1 -0
  4. package/dist/client/assets/MarkdownRenderer-CsyizEL3.js +1 -0
  5. package/dist/client/assets/{PageTopBar-C8j-5s_3.js → PageTopBar-CQwjO6Af.js} +1 -1
  6. package/dist/client/assets/Session-B0s5zBGg.js +7 -0
  7. package/dist/client/assets/Settings-CfHFmJdV.js +1 -0
  8. package/dist/client/assets/Workspace-Cfl0mbNE.js +4 -0
  9. package/dist/client/assets/WorkspaceLinkedText-DCVYd9x-.js +2 -0
  10. package/dist/client/assets/c-BIGW1oBm.js +1 -0
  11. package/dist/client/assets/cpp-DIPi6g--.js +1 -0
  12. package/dist/client/assets/csharp-DSvCPggb.js +1 -0
  13. package/dist/client/assets/dart-bE4Kk8sk.js +1 -0
  14. package/dist/client/assets/dotenv-Da5cRb03.js +1 -0
  15. package/dist/client/assets/go-C27-OAKa.js +1 -0
  16. package/dist/client/assets/graphql-pNE0_Gx8.js +1 -0
  17. package/dist/client/assets/groovy-gcz8RCvz.js +1 -0
  18. package/dist/client/assets/index-BCg3ymV3.css +1 -0
  19. package/dist/client/assets/index-CrJqHlc8.js +2 -0
  20. package/dist/client/assets/java-VnEXKtx_.js +148 -0
  21. package/dist/client/assets/jsx-g9-lgVsj.js +1 -0
  22. package/dist/client/assets/kotlin-BdnUsdx6.js +1 -0
  23. package/dist/client/assets/less-B1dDrJ26.js +1 -0
  24. package/dist/client/assets/lua-BaeVxFsk.js +1 -0
  25. package/dist/client/assets/makefile-CHLpvVh8.js +1 -0
  26. package/dist/client/assets/php-BcCyJq-p.js +1 -0
  27. package/dist/client/assets/properties-DTPjHERo.js +1 -0
  28. package/dist/client/assets/ruby-BwImf3Ka.js +1 -0
  29. package/dist/client/assets/rust-B1yitclQ.js +1 -0
  30. package/dist/client/assets/scss-lMagJa-5.js +1 -0
  31. package/dist/client/assets/sql-CRqJ_cUM.js +1 -0
  32. package/dist/client/assets/svelte-B4a9v_or.js +1 -0
  33. package/dist/client/assets/swift-D82vCrfD.js +1 -0
  34. package/dist/client/assets/toml-vGWfd6FD.js +1 -0
  35. package/dist/client/assets/{vendor-icons-CNN4EKVi.js → vendor-icons-CMXJHDEv.js} +125 -65
  36. package/dist/client/assets/vendor-markdown--d-T3AbU.js +37 -0
  37. package/dist/client/assets/{vendor-motion-n6Lx6G4a.js → vendor-motion-D0ZmPdi9.js} +1 -1
  38. package/dist/client/assets/{vendor-react-DSV5aFEg.js → vendor-react-CcDXZHn_.js} +1 -1
  39. package/dist/client/assets/{vendor-virtual-CcftJrIC.js → vendor-virtual-DJI7OicV.js} +1 -1
  40. package/dist/client/assets/vue-DBXACu8K.js +1 -0
  41. package/dist/client/assets/workspace-return-FrQUv7g3.js +1 -0
  42. package/dist/client/index.html +4 -4
  43. package/dist/server/cli-manager.js +151 -26
  44. package/dist/server/codex-history.js +119 -17
  45. package/dist/server/index.js +906 -57
  46. package/dist/server/store.js +369 -27
  47. package/package.json +3 -3
  48. package/dist/client/assets/History-BxJVDFpN.js +0 -3
  49. package/dist/client/assets/MarkdownRenderer-BO-KS_L1.js +0 -1
  50. package/dist/client/assets/Session-CQFXA2Sr.js +0 -11
  51. package/dist/client/assets/Settings-DYmjRmoN.js +0 -1
  52. package/dist/client/assets/Workspace-D8kv9euM.js +0 -8
  53. package/dist/client/assets/WorkspaceLinkedText-DQyPLk-X.js +0 -2
  54. package/dist/client/assets/code-highlight-CEcsuMpw.js +0 -1
  55. package/dist/client/assets/index-BXT2BylN.css +0 -1
  56. package/dist/client/assets/index-DOgH1Kf3.js +0 -2
  57. 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
- if (statSync(rolloutPath).size > MAX_ROLLOUT_BYTES) {
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 (const line of lines) {
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 || `call-${messages.length + 1}`);
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-${messages.length + 1}`,
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
- const db = new Database(stateDbPath, { readonly: true, fileMustExist: true });
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 id, rollout_path, created_at, updated_at, created_at_ms, updated_at_ms,
232
- title, cwd, source, model, reasoning_effort, tokens_used, first_user_message
333
+ SELECT ${selectedColumns}
233
334
  FROM threads
234
- WHERE rollout_path IS NOT NULL
235
- AND rollout_path != ''
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
  }