cli-link 0.0.5 → 0.0.7
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/bin/agentpilot.js +1 -0
- 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 +18 -4
- package/dist/server/cli-manager.js +151 -26
- package/dist/server/codex-history.js +119 -17
- package/dist/server/index.js +1051 -65
- package/dist/server/store.js +369 -27
- package/dist/server/terminal-qr.js +17 -314
- package/package.json +5 -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
package/dist/server/store.js
CHANGED
|
@@ -33,6 +33,17 @@ function buildHistoryTitle(messages) {
|
|
|
33
33
|
const userMessage = messages.find(m => m.type === 'user_message' || m.type === 'user');
|
|
34
34
|
return userMessage ? cleanHistoryTitle(userMessage.content) : '会话记录';
|
|
35
35
|
}
|
|
36
|
+
function normalizePromptHistoryText(content) {
|
|
37
|
+
if (typeof content !== 'string')
|
|
38
|
+
return null;
|
|
39
|
+
const text = content.trim();
|
|
40
|
+
if (!text)
|
|
41
|
+
return null;
|
|
42
|
+
const key = text.replace(/\s+/g, ' ').toLowerCase();
|
|
43
|
+
if (!key)
|
|
44
|
+
return null;
|
|
45
|
+
return { text, key };
|
|
46
|
+
}
|
|
36
47
|
function normalizeWorkDir(workDir) {
|
|
37
48
|
if (typeof workDir !== 'string')
|
|
38
49
|
return null;
|
|
@@ -124,7 +135,20 @@ export function initDb(dbPath) {
|
|
|
124
135
|
created_at INTEGER NOT NULL
|
|
125
136
|
);
|
|
126
137
|
|
|
138
|
+
CREATE TABLE IF NOT EXISTS prompt_history (
|
|
139
|
+
id TEXT PRIMARY KEY,
|
|
140
|
+
work_dir TEXT,
|
|
141
|
+
text TEXT NOT NULL,
|
|
142
|
+
normalized_text TEXT NOT NULL,
|
|
143
|
+
session_id TEXT,
|
|
144
|
+
message_id TEXT,
|
|
145
|
+
use_count INTEGER NOT NULL DEFAULT 1,
|
|
146
|
+
last_used_at INTEGER NOT NULL,
|
|
147
|
+
created_at INTEGER NOT NULL
|
|
148
|
+
);
|
|
149
|
+
|
|
127
150
|
CREATE INDEX IF NOT EXISTS idx_messages_session_seq ON messages(session_id, seq);
|
|
151
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session_id ON messages(session_id, id);
|
|
128
152
|
`);
|
|
129
153
|
// Migrate: add 'details' column if it doesn't exist (for existing databases)
|
|
130
154
|
const columns = db.prepare(`PRAGMA table_info(messages)`).all();
|
|
@@ -147,7 +171,11 @@ export function initDb(dbPath) {
|
|
|
147
171
|
}
|
|
148
172
|
db.exec(`CREATE INDEX IF NOT EXISTS idx_history_tasks_work_dir_created ON history_tasks(work_dir, created_at DESC)`);
|
|
149
173
|
db.exec(`CREATE INDEX IF NOT EXISTS idx_workdir_history_last_used ON workdir_history(last_used_at DESC)`);
|
|
174
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_prompt_history_work_dir_last_used ON prompt_history(work_dir, last_used_at DESC)`);
|
|
175
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_prompt_history_last_used ON prompt_history(last_used_at DESC)`);
|
|
176
|
+
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_prompt_history_work_dir_norm ON prompt_history(work_dir, normalized_text)`);
|
|
150
177
|
backfillHistoryTaskSummaries();
|
|
178
|
+
backfillPromptHistoryFromMessages();
|
|
151
179
|
console.log(`[Store] Database initialized at ${path}`);
|
|
152
180
|
}
|
|
153
181
|
function backfillHistoryTaskSummaries() {
|
|
@@ -475,6 +503,105 @@ export function getRecentWorkDirs(limit = 12) {
|
|
|
475
503
|
}
|
|
476
504
|
return existing;
|
|
477
505
|
}
|
|
506
|
+
// --- Prompt History ---
|
|
507
|
+
export function recordPromptHistory(input) {
|
|
508
|
+
const normalizedText = normalizePromptHistoryText(input.text);
|
|
509
|
+
if (!normalizedText)
|
|
510
|
+
return null;
|
|
511
|
+
const workDir = normalizeWorkDir(input.workDir);
|
|
512
|
+
const now = Date.now();
|
|
513
|
+
const existing = workDir
|
|
514
|
+
? db.prepare(`SELECT * FROM prompt_history WHERE work_dir = ? AND normalized_text = ?`)
|
|
515
|
+
.get(workDir, normalizedText.key)
|
|
516
|
+
: db.prepare(`SELECT * FROM prompt_history WHERE work_dir IS NULL AND normalized_text = ?`)
|
|
517
|
+
.get(normalizedText.key);
|
|
518
|
+
if (existing) {
|
|
519
|
+
db.prepare(`UPDATE prompt_history
|
|
520
|
+
SET text = ?, session_id = ?, message_id = ?, use_count = use_count + 1, last_used_at = ?
|
|
521
|
+
WHERE id = ?`).run(normalizedText.text, input.sessionId || null, input.messageId || null, now, existing.id);
|
|
522
|
+
return {
|
|
523
|
+
...existing,
|
|
524
|
+
text: normalizedText.text,
|
|
525
|
+
session_id: input.sessionId || null,
|
|
526
|
+
message_id: input.messageId || null,
|
|
527
|
+
use_count: existing.use_count + 1,
|
|
528
|
+
last_used_at: now,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const item = {
|
|
532
|
+
id: randomUUID(),
|
|
533
|
+
work_dir: workDir,
|
|
534
|
+
text: normalizedText.text,
|
|
535
|
+
normalized_text: normalizedText.key,
|
|
536
|
+
session_id: input.sessionId || null,
|
|
537
|
+
message_id: input.messageId || null,
|
|
538
|
+
use_count: 1,
|
|
539
|
+
last_used_at: now,
|
|
540
|
+
created_at: now,
|
|
541
|
+
};
|
|
542
|
+
db.prepare(`INSERT INTO prompt_history (id, work_dir, text, normalized_text, session_id, message_id, use_count, last_used_at, created_at)
|
|
543
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(item.id, item.work_dir || null, item.text, item.normalized_text, item.session_id || null, item.message_id || null, item.use_count, item.last_used_at, item.created_at);
|
|
544
|
+
return item;
|
|
545
|
+
}
|
|
546
|
+
export function getPromptHistory(options = {}) {
|
|
547
|
+
const limit = Math.max(1, Math.min(100, Math.floor(options.limit || 50)));
|
|
548
|
+
const workDir = normalizeWorkDir(options.workDir);
|
|
549
|
+
const query = normalizePromptHistoryText(options.query || '')?.key || '';
|
|
550
|
+
const like = `%${query}%`;
|
|
551
|
+
if (workDir && query) {
|
|
552
|
+
return db.prepare(`SELECT * FROM prompt_history
|
|
553
|
+
WHERE work_dir = ? AND normalized_text LIKE ?
|
|
554
|
+
ORDER BY last_used_at DESC
|
|
555
|
+
LIMIT ?`).all(workDir, like, limit);
|
|
556
|
+
}
|
|
557
|
+
if (workDir) {
|
|
558
|
+
return db.prepare(`SELECT * FROM prompt_history
|
|
559
|
+
WHERE work_dir = ?
|
|
560
|
+
ORDER BY last_used_at DESC
|
|
561
|
+
LIMIT ?`).all(workDir, limit);
|
|
562
|
+
}
|
|
563
|
+
if (query) {
|
|
564
|
+
return db.prepare(`SELECT * FROM prompt_history
|
|
565
|
+
WHERE normalized_text LIKE ?
|
|
566
|
+
ORDER BY last_used_at DESC
|
|
567
|
+
LIMIT ?`).all(like, limit);
|
|
568
|
+
}
|
|
569
|
+
return db.prepare(`SELECT * FROM prompt_history
|
|
570
|
+
ORDER BY last_used_at DESC
|
|
571
|
+
LIMIT ?`).all(limit);
|
|
572
|
+
}
|
|
573
|
+
export function deletePromptHistory(id, workDir) {
|
|
574
|
+
const normalizedWorkDir = normalizeWorkDir(workDir);
|
|
575
|
+
const result = normalizedWorkDir
|
|
576
|
+
? db.prepare(`DELETE FROM prompt_history WHERE id = ? AND work_dir = ?`).run(id, normalizedWorkDir)
|
|
577
|
+
: db.prepare(`DELETE FROM prompt_history WHERE id = ?`).run(id);
|
|
578
|
+
return result.changes > 0;
|
|
579
|
+
}
|
|
580
|
+
function backfillPromptHistoryFromMessages() {
|
|
581
|
+
const existing = db.prepare(`SELECT COUNT(*) AS count FROM prompt_history`).get();
|
|
582
|
+
if (existing.count > 0)
|
|
583
|
+
return;
|
|
584
|
+
const rows = db.prepare(`SELECT m.id AS message_id, m.session_id, m.content, s.cli_config
|
|
585
|
+
FROM messages m
|
|
586
|
+
LEFT JOIN sessions s ON s.id = m.session_id
|
|
587
|
+
WHERE m.type IN ('user_message', 'user') AND TRIM(m.content) != ''
|
|
588
|
+
ORDER BY m.seq ASC
|
|
589
|
+
LIMIT 10000`).all();
|
|
590
|
+
if (rows.length === 0)
|
|
591
|
+
return;
|
|
592
|
+
const backfill = db.transaction((items) => {
|
|
593
|
+
for (const item of items) {
|
|
594
|
+
recordPromptHistory({
|
|
595
|
+
text: item.content,
|
|
596
|
+
workDir: getWorkDirFromSessionConfig(item.cli_config),
|
|
597
|
+
sessionId: item.session_id,
|
|
598
|
+
messageId: item.message_id,
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
backfill(rows);
|
|
603
|
+
console.log(`[Store] Backfilled ${rows.length} user messages into prompt history`);
|
|
604
|
+
}
|
|
478
605
|
// --- Migration (from client localStorage) ---
|
|
479
606
|
export function importLocalData(messages, historyTasks, workDir) {
|
|
480
607
|
const current = getCurrentSession();
|
|
@@ -496,7 +623,18 @@ export function importLocalData(messages, historyTasks, workDir) {
|
|
|
496
623
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
497
624
|
const insertMany = db.transaction((msgs) => {
|
|
498
625
|
for (const msg of msgs) {
|
|
499
|
-
|
|
626
|
+
const id = String(msg.id || randomUUID());
|
|
627
|
+
const type = String(msg.type || 'system');
|
|
628
|
+
const content = String(msg.content || '');
|
|
629
|
+
insertStmt.run(id, type, content, String(msg.time || new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' })), msg.status || null, msg.toolName || null, msg.toolDetails || null, msg.permission ? JSON.stringify(msg.permission) : null, sessionId);
|
|
630
|
+
if (type === 'user_message' || type === 'user') {
|
|
631
|
+
recordPromptHistory({
|
|
632
|
+
text: content,
|
|
633
|
+
workDir: importWorkDir,
|
|
634
|
+
sessionId,
|
|
635
|
+
messageId: id,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
500
638
|
}
|
|
501
639
|
});
|
|
502
640
|
insertMany(messages);
|
|
@@ -517,10 +655,76 @@ export function importLocalData(messages, historyTasks, workDir) {
|
|
|
517
655
|
}
|
|
518
656
|
console.log(`[Store] Imported ${messages.length} messages and ${historyTasks.length} history tasks`);
|
|
519
657
|
}
|
|
658
|
+
function jsonOrNull(value) {
|
|
659
|
+
if (value == null)
|
|
660
|
+
return null;
|
|
661
|
+
try {
|
|
662
|
+
return JSON.stringify(value);
|
|
663
|
+
}
|
|
664
|
+
catch {
|
|
665
|
+
return String(value);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function textOrNull(value) {
|
|
669
|
+
if (value == null)
|
|
670
|
+
return null;
|
|
671
|
+
const text = String(value);
|
|
672
|
+
return text.length > 0 ? text : null;
|
|
673
|
+
}
|
|
674
|
+
function getImportedSessionTiming(session) {
|
|
675
|
+
const startedAt = Number.isFinite(session.startedAt) && session.startedAt > 0 ? session.startedAt : Date.now();
|
|
676
|
+
const endedAt = Number.isFinite(session.endedAt) && session.endedAt > 0 ? session.endedAt : startedAt;
|
|
677
|
+
const createdAt = Number.isFinite(session.createdAt) && session.createdAt > 0 ? session.createdAt : endedAt;
|
|
678
|
+
const diffSec = Math.max(0, Math.round((endedAt - startedAt) / 1000));
|
|
679
|
+
const duration = diffSec > 0
|
|
680
|
+
? diffSec >= 60
|
|
681
|
+
? `${Math.floor(diffSec / 60)}m ${String(diffSec % 60).padStart(2, '0')}s`
|
|
682
|
+
: `${diffSec}s`
|
|
683
|
+
: null;
|
|
684
|
+
return { startedAt, endedAt, createdAt, duration };
|
|
685
|
+
}
|
|
686
|
+
function importedMessageSignature(message) {
|
|
687
|
+
return [
|
|
688
|
+
message.type || '',
|
|
689
|
+
message.time || '',
|
|
690
|
+
message.toolUseId || '',
|
|
691
|
+
message.toolName || '',
|
|
692
|
+
message.content || '',
|
|
693
|
+
].join('\u001f');
|
|
694
|
+
}
|
|
695
|
+
function storedMessageSignature(message) {
|
|
696
|
+
return importedMessageSignature({
|
|
697
|
+
type: message.type,
|
|
698
|
+
content: message.content,
|
|
699
|
+
time: message.time,
|
|
700
|
+
toolName: message.toolName || undefined,
|
|
701
|
+
toolUseId: message.toolUseId || undefined,
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
function codexSpecialKeyFromDetails(details, type) {
|
|
705
|
+
if (type !== 'system')
|
|
706
|
+
return null;
|
|
707
|
+
const parsed = typeof details === 'string' ? parseConfig(details) : details;
|
|
708
|
+
if (!parsed || typeof parsed !== 'object')
|
|
709
|
+
return null;
|
|
710
|
+
const record = parsed;
|
|
711
|
+
const subtype = record.subtype;
|
|
712
|
+
const sessionId = record.session_id;
|
|
713
|
+
if ((subtype === 'init' || subtype === 'result') && typeof sessionId === 'string' && sessionId) {
|
|
714
|
+
return `${subtype}:${sessionId}`;
|
|
715
|
+
}
|
|
716
|
+
return null;
|
|
717
|
+
}
|
|
718
|
+
function putFirst(map, key, value) {
|
|
719
|
+
if (key == null || map.has(key))
|
|
720
|
+
return;
|
|
721
|
+
map.set(key, value);
|
|
722
|
+
}
|
|
520
723
|
export function importCodexSessions(sessions) {
|
|
521
724
|
const result = {
|
|
522
725
|
scanned: sessions.length,
|
|
523
726
|
imported: 0,
|
|
727
|
+
updated: 0,
|
|
524
728
|
skipped: 0,
|
|
525
729
|
failed: 0,
|
|
526
730
|
messagesImported: 0,
|
|
@@ -529,60 +733,198 @@ export function importCodexSessions(sessions) {
|
|
|
529
733
|
if (sessions.length === 0) {
|
|
530
734
|
return result;
|
|
531
735
|
}
|
|
532
|
-
const
|
|
533
|
-
const
|
|
736
|
+
const getSession = db.prepare(`SELECT * FROM sessions WHERE id = ?`);
|
|
737
|
+
const getTaskById = db.prepare(`SELECT * FROM history_tasks WHERE id = ?`);
|
|
738
|
+
const getTaskBySession = db.prepare(`SELECT * FROM history_tasks WHERE session_id = ? ORDER BY created_at DESC LIMIT 1`);
|
|
739
|
+
const getMessagesBySession = db.prepare(`SELECT * FROM messages WHERE session_id = ? ORDER BY seq ASC`);
|
|
534
740
|
const insertSession = db.prepare(`INSERT INTO sessions (id, status, cli_config, started_at, last_seq) VALUES (?, ?, ?, ?, 0)`);
|
|
741
|
+
const updateSession = db.prepare(`UPDATE sessions SET cli_config = ?, started_at = ? WHERE id = ?`);
|
|
535
742
|
const insertMessage = db.prepare(`INSERT INTO messages (id, type, content, time, status, toolName, toolDetails, toolUseId, toolResult, permission, details, session_id)
|
|
536
743
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
744
|
+
const updateMessage = db.prepare(`UPDATE messages
|
|
745
|
+
SET id = ?, type = ?, content = ?, time = ?, status = ?, toolName = ?, toolDetails = ?, toolUseId = ?, toolResult = ?, permission = ?, details = ?
|
|
746
|
+
WHERE seq = ?`);
|
|
747
|
+
const getMaxSeq = db.prepare(`SELECT MAX(seq) AS seq FROM messages WHERE session_id = ?`);
|
|
537
748
|
const updateLastSeq = db.prepare(`UPDATE sessions SET last_seq = ? WHERE id = ?`);
|
|
538
749
|
const insertTask = db.prepare(`INSERT INTO history_tasks (id, session_id, work_dir, status, title, confirm_count, tool_count, duration, start_time, end_time, created_at)
|
|
539
750
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
751
|
+
const updateTask = db.prepare(`UPDATE history_tasks
|
|
752
|
+
SET session_id = ?, work_dir = ?, status = ?, title = ?, confirm_count = ?, tool_count = ?, duration = ?, start_time = ?, end_time = ?, created_at = ?
|
|
753
|
+
WHERE id = ?`);
|
|
540
754
|
const importOne = db.transaction((session) => {
|
|
541
755
|
const workDir = normalizeWorkDir(session.workDir);
|
|
542
756
|
const messages = session.messages || [];
|
|
543
757
|
const confirmCount = messages.filter(m => m.type === 'confirm_request' || m.type === 'confirm').length;
|
|
544
758
|
const toolCount = messages.filter(m => m.type === 'tool_call' || m.type === 'tool').length;
|
|
545
|
-
const
|
|
546
|
-
const
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
759
|
+
const { startedAt, endedAt, createdAt, duration } = getImportedSessionTiming(session);
|
|
760
|
+
const existingSession = getSession.get(session.sessionId);
|
|
761
|
+
const createdSession = !existingSession;
|
|
762
|
+
let changed = false;
|
|
763
|
+
if (existingSession) {
|
|
764
|
+
const mergedConfig = { ...parseConfig(existingSession.cli_config), ...(session.cliConfig || {}) };
|
|
765
|
+
const nextConfig = JSON.stringify(mergedConfig);
|
|
766
|
+
const nextStartedAt = existingSession.started_at > 0 ? Math.min(existingSession.started_at, startedAt) : startedAt;
|
|
767
|
+
if ((existingSession.cli_config || null) !== nextConfig || existingSession.started_at !== nextStartedAt) {
|
|
768
|
+
updateSession.run(nextConfig, nextStartedAt, session.sessionId);
|
|
769
|
+
changed = true;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
insertSession.run(session.sessionId, 'archived', JSON.stringify(session.cliConfig || {}), startedAt);
|
|
774
|
+
changed = true;
|
|
775
|
+
}
|
|
776
|
+
const existingMessages = getMessagesBySession.all(session.sessionId);
|
|
777
|
+
const byId = new Map();
|
|
778
|
+
const bySpecial = new Map();
|
|
779
|
+
const byToolUseId = new Map();
|
|
780
|
+
const bySignature = new Map();
|
|
781
|
+
const rememberMessage = (message) => {
|
|
782
|
+
putFirst(byId, message.id, message);
|
|
783
|
+
putFirst(bySpecial, codexSpecialKeyFromDetails(message.details, message.type), message);
|
|
784
|
+
if (message.type === 'tool_call' || message.type === 'tool') {
|
|
785
|
+
putFirst(byToolUseId, message.toolUseId, message);
|
|
786
|
+
}
|
|
787
|
+
putFirst(bySignature, storedMessageSignature(message), message);
|
|
788
|
+
};
|
|
789
|
+
for (const message of existingMessages)
|
|
790
|
+
rememberMessage(message);
|
|
791
|
+
let insertedMessages = 0;
|
|
792
|
+
let updatedMessages = 0;
|
|
556
793
|
for (const message of messages) {
|
|
557
|
-
|
|
558
|
-
|
|
794
|
+
if (!message.id || !message.type)
|
|
795
|
+
continue;
|
|
796
|
+
const next = {
|
|
797
|
+
id: message.id,
|
|
798
|
+
type: message.type,
|
|
799
|
+
content: message.content || '',
|
|
800
|
+
time: message.time || '',
|
|
801
|
+
status: textOrNull(message.status),
|
|
802
|
+
toolName: textOrNull(message.toolName),
|
|
803
|
+
toolDetails: textOrNull(message.toolDetails),
|
|
804
|
+
toolUseId: textOrNull(message.toolUseId),
|
|
805
|
+
toolResult: textOrNull(message.toolResult),
|
|
806
|
+
permission: jsonOrNull(message.permission),
|
|
807
|
+
details: jsonOrNull(message.details),
|
|
808
|
+
};
|
|
809
|
+
const specialKey = codexSpecialKeyFromDetails(message.details, message.type);
|
|
810
|
+
const signature = importedMessageSignature(message);
|
|
811
|
+
const existing = byId.get(next.id)
|
|
812
|
+
|| (next.toolUseId && (next.type === 'tool_call' || next.type === 'tool') ? byToolUseId.get(next.toolUseId) : undefined)
|
|
813
|
+
|| (specialKey ? bySpecial.get(specialKey) : undefined)
|
|
814
|
+
|| bySignature.get(signature);
|
|
815
|
+
if (existing) {
|
|
816
|
+
const differs = existing.id !== next.id
|
|
817
|
+
|| existing.type !== next.type
|
|
818
|
+
|| existing.content !== next.content
|
|
819
|
+
|| existing.time !== next.time
|
|
820
|
+
|| (existing.status || null) !== next.status
|
|
821
|
+
|| (existing.toolName || null) !== next.toolName
|
|
822
|
+
|| (existing.toolDetails || null) !== next.toolDetails
|
|
823
|
+
|| (existing.toolUseId || null) !== next.toolUseId
|
|
824
|
+
|| (existing.toolResult || null) !== next.toolResult
|
|
825
|
+
|| (existing.permission || null) !== next.permission
|
|
826
|
+
|| (existing.details || null) !== next.details;
|
|
827
|
+
if (differs) {
|
|
828
|
+
updateMessage.run(next.id, next.type, next.content, next.time, next.status, next.toolName, next.toolDetails, next.toolUseId, next.toolResult, next.permission, next.details, existing.seq);
|
|
829
|
+
updatedMessages += 1;
|
|
830
|
+
changed = true;
|
|
831
|
+
rememberMessage({
|
|
832
|
+
...existing,
|
|
833
|
+
...next,
|
|
834
|
+
status: next.status || undefined,
|
|
835
|
+
toolName: next.toolName || undefined,
|
|
836
|
+
toolDetails: next.toolDetails || undefined,
|
|
837
|
+
toolUseId: next.toolUseId || undefined,
|
|
838
|
+
toolResult: next.toolResult || undefined,
|
|
839
|
+
permission: next.permission || undefined,
|
|
840
|
+
details: next.details || undefined,
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
const inserted = insertMessage.run(next.id, next.type, next.content, next.time, next.status, next.toolName, next.toolDetails, next.toolUseId, next.toolResult, next.permission, next.details, session.sessionId);
|
|
846
|
+
insertedMessages += 1;
|
|
847
|
+
changed = true;
|
|
848
|
+
if (next.type === 'user_message' || next.type === 'user') {
|
|
849
|
+
recordPromptHistory({
|
|
850
|
+
text: next.content,
|
|
851
|
+
workDir,
|
|
852
|
+
sessionId: session.sessionId,
|
|
853
|
+
messageId: next.id,
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
rememberMessage({
|
|
857
|
+
seq: Number(inserted.lastInsertRowid),
|
|
858
|
+
id: next.id,
|
|
859
|
+
type: next.type,
|
|
860
|
+
content: next.content,
|
|
861
|
+
time: next.time,
|
|
862
|
+
status: next.status || undefined,
|
|
863
|
+
toolName: next.toolName || undefined,
|
|
864
|
+
toolDetails: next.toolDetails || undefined,
|
|
865
|
+
toolUseId: next.toolUseId || undefined,
|
|
866
|
+
toolResult: next.toolResult || undefined,
|
|
867
|
+
permission: next.permission || undefined,
|
|
868
|
+
details: next.details || undefined,
|
|
869
|
+
session_id: session.sessionId,
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
if (insertedMessages > 0 || updatedMessages > 0) {
|
|
873
|
+
const row = getMaxSeq.get(session.sessionId);
|
|
874
|
+
if (row?.seq)
|
|
875
|
+
updateLastSeq.run(row.seq, session.sessionId);
|
|
876
|
+
}
|
|
877
|
+
const refreshedSession = (existingSession ? getSession.get(session.sessionId) : null);
|
|
878
|
+
const isActiveSession = (refreshedSession || existingSession)?.status !== 'archived' && !!(refreshedSession || existingSession);
|
|
879
|
+
const existingTask = (getTaskById.get(session.taskId) || getTaskBySession.get(session.sessionId));
|
|
880
|
+
const taskStatus = session.status || 'completed';
|
|
881
|
+
const taskTitle = session.title || 'Codex 会话记录';
|
|
882
|
+
if (existingTask) {
|
|
883
|
+
const taskDiffers = existingTask.session_id !== session.sessionId
|
|
884
|
+
|| (existingTask.work_dir || null) !== (workDir || null)
|
|
885
|
+
|| existingTask.status !== taskStatus
|
|
886
|
+
|| existingTask.title !== taskTitle
|
|
887
|
+
|| existingTask.confirm_count !== confirmCount
|
|
888
|
+
|| existingTask.tool_count !== toolCount
|
|
889
|
+
|| (existingTask.duration || null) !== duration
|
|
890
|
+
|| existingTask.start_time !== startedAt
|
|
891
|
+
|| existingTask.end_time !== endedAt
|
|
892
|
+
|| existingTask.created_at !== createdAt;
|
|
893
|
+
if (taskDiffers) {
|
|
894
|
+
updateTask.run(session.sessionId, workDir, taskStatus, taskTitle, confirmCount, toolCount, duration, startedAt, endedAt, createdAt, existingTask.id);
|
|
895
|
+
changed = true;
|
|
896
|
+
}
|
|
559
897
|
}
|
|
560
|
-
if (
|
|
561
|
-
|
|
898
|
+
else if (!isActiveSession) {
|
|
899
|
+
insertTask.run(session.taskId, session.sessionId, workDir, taskStatus, taskTitle, confirmCount, toolCount, duration, startedAt, endedAt, createdAt);
|
|
900
|
+
changed = true;
|
|
562
901
|
}
|
|
563
|
-
|
|
564
|
-
return messages.length;
|
|
902
|
+
return { createdSession, changed, insertedMessages };
|
|
565
903
|
});
|
|
566
904
|
for (const session of sessions) {
|
|
567
905
|
try {
|
|
568
|
-
if (!session.sessionId || !session.taskId || session.messages.length === 0) {
|
|
906
|
+
if (!session.sessionId || !session.taskId || !session.messages || session.messages.length === 0) {
|
|
569
907
|
result.skipped += 1;
|
|
570
908
|
continue;
|
|
571
909
|
}
|
|
572
|
-
|
|
910
|
+
const imported = importOne(session);
|
|
911
|
+
if (imported.createdSession) {
|
|
912
|
+
result.imported += 1;
|
|
913
|
+
}
|
|
914
|
+
else if (imported.changed) {
|
|
915
|
+
result.updated += 1;
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
573
918
|
result.skipped += 1;
|
|
574
|
-
continue;
|
|
575
919
|
}
|
|
576
|
-
|
|
577
|
-
result.imported += 1;
|
|
578
|
-
result.messagesImported += importedMessages;
|
|
920
|
+
result.messagesImported += imported.insertedMessages;
|
|
579
921
|
}
|
|
580
922
|
catch (err) {
|
|
581
923
|
result.failed += 1;
|
|
582
924
|
result.errors.push(`${session.sessionId || 'unknown'}: ${err?.message || 'import failed'}`);
|
|
583
925
|
}
|
|
584
926
|
}
|
|
585
|
-
console.log(`[Store] Synced Codex history: imported=${result.imported}, skipped=${result.skipped}, failed=${result.failed}`);
|
|
927
|
+
console.log(`[Store] Synced Codex history: imported=${result.imported}, updated=${result.updated}, skipped=${result.skipped}, failed=${result.failed}`);
|
|
586
928
|
return result;
|
|
587
929
|
}
|
|
588
930
|
// --- Cleanup ---
|