dsh-reference-anything 0.4.4 → 0.5.1
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/NOTICE.md +58 -0
- package/README.md +151 -64
- package/cordis.patch.yml +19 -15
- package/images/agents/LICENSE +22 -0
- package/images/agents/README.md +3 -0
- package/images/agents/antigravity.svg +1 -0
- package/images/agents/chatgpt.svg +1 -0
- package/images/agents/claude.svg +1 -0
- package/images/agents/cline.svg +1 -0
- package/images/agents/codex.svg +1 -0
- package/images/agents/continue.svg +1 -0
- package/images/agents/crush.svg +1 -0
- package/images/agents/cursor.svg +1 -0
- package/images/agents/dsh.svg +1 -0
- package/images/agents/gemini.svg +1 -0
- package/images/agents/goose.svg +1 -0
- package/images/agents/grokbuild.svg +1 -0
- package/images/agents/hermes.svg +1 -0
- package/images/agents/kilocode.svg +1 -0
- package/images/agents/kimi.svg +1 -0
- package/images/agents/mimocode.svg +1 -0
- package/images/agents/openclaw.svg +1 -0
- package/images/agents/opencode.svg +1 -0
- package/images/agents/pi.svg +1 -0
- package/images/agents/qoder.svg +1 -0
- package/images/agents/qwen.svg +1 -0
- package/images/agents/reasonix.svg +6 -0
- package/images/agents/teleagent.svg +1 -0
- package/images/agents/trae.svg +1 -0
- package/images/agents/vibe.svg +1 -0
- package/images/agents/workbuddy.svg +37 -0
- package/images/agents/zcode.svg +1 -0
- package/images/agents/zed.svg +1 -0
- package/lib/agent-scan-cache.d.ts +13 -0
- package/lib/agent-scan-cache.js +43 -0
- package/lib/chat-import-compatibility.d.ts +18 -0
- package/lib/chat-import-compatibility.js +87 -0
- package/lib/chat-import-discovery.d.ts +32 -0
- package/lib/chat-import-discovery.js +17 -0
- package/lib/chat-import-reader.d.ts +27 -0
- package/lib/chat-import-reader.js +111 -0
- package/lib/chat-import-runtime.d.ts +4 -0
- package/lib/chat-import-runtime.js +4 -0
- package/lib/client/index.d.ts +5 -0
- package/lib/client.js +4 -34024
- package/lib/contract.d.ts +50 -3
- package/lib/contract.js +14 -4
- package/lib/conversation-availability.d.ts +13 -0
- package/lib/conversation-availability.js +76 -0
- package/lib/errors.d.ts +2 -2
- package/lib/host.d.ts +55 -11
- package/lib/host.js +200 -14
- package/lib/index.d.ts +3 -1
- package/lib/index.js +31 -3
- package/lib/local-conversation-reader.d.ts +3 -0
- package/lib/local-conversation-reader.js +81 -0
- package/lib/local-conversation-scanner.d.ts +18 -0
- package/lib/local-conversation-scanner.js +55 -0
- package/lib/local-locator.d.ts +14 -0
- package/lib/local-locator.js +34 -0
- package/lib/local-reference-tools.d.ts +4 -0
- package/lib/local-reference-tools.js +195 -0
- package/lib/local-reference.d.ts +118 -0
- package/lib/local-reference.js +289 -0
- package/lib/opencli.d.ts +5 -2
- package/lib/opencli.js +88 -64
- package/lib/reference.d.ts +5 -3
- package/lib/reference.js +167 -72
- package/lib/render.d.ts +1 -1
- package/lib/render.js +4 -4
- package/lib/retain.d.ts +14 -0
- package/lib/retain.js +1 -1
- package/lib/serialize.d.ts +1 -1
- package/lib/serialize.js +2 -2
- package/lib/sources/local-agent/index.d.ts +23 -16
- package/lib/sources/local-agent/index.js +101 -15
- package/lib/store/spec.d.ts +40 -7
- package/lib/sync/index.js +4 -0
- package/lib/tool.d.ts +2 -0
- package/lib/tool.js +36 -41
- package/lib/typert.js +2 -0
- package/lib/types.d.ts +2 -0
- package/lib/update.d.ts +2 -0
- package/lib/update.js +12 -0
- package/lib/uri-codec.d.ts +1 -0
- package/lib/uri-codec.js +64 -3
- package/lib/uri.d.ts +1 -10
- package/lib/uri.js +16 -5
- package/lib/wire.d.ts +59 -0
- package/lib/wire.js +13 -4
- package/opencli-plugin/common.js +5 -3
- package/opencli-plugin/opencli-plugin.json +1 -1
- package/opencli-plugin/package.json +1 -1
- package/package.json +28 -4
- package/release-notes/0.4.4/commands.png +0 -0
- package/release-notes/0.4.4/demos/agent-import.gif +0 -0
- package/release-notes/0.4.4/demos/chat-import-upgrade.gif +0 -0
- package/release-notes/0.4.4/demos/folders.gif +0 -0
- package/release-notes/0.4.4/demos/local-plugins.gif +0 -0
- package/release-notes/0.4.4/demos/shortcuts.gif +0 -0
- package/release-notes/0.4.4/features.json +36 -0
- package/release-notes/0.4.4/files.png +0 -0
- package/release-notes/0.5.0/demos/agent-import.gif +0 -0
- package/release-notes/0.5.0/demos/chat-import-upgrade.gif +0 -0
- package/release-notes/0.5.0/demos/folders.gif +0 -0
- package/release-notes/0.5.0/demos/local-plugins.gif +0 -0
- package/release-notes/0.5.0/demos/local-references.gif +0 -0
- package/release-notes/0.5.0/demos/shortcuts.gif +0 -0
- package/release-notes/0.5.0/features.json +65 -0
- package/release-notes/README.md +38 -0
- package/vendor/chat-import-reader/LICENSE +22 -0
- package/vendor/chat-import-reader/LICENSE.fzstd +21 -0
- package/vendor/chat-import-reader/README.md +48 -0
- package/vendor/chat-import-reader/availability-worker.mjs +114 -0
- package/vendor/chat-import-reader/parsers.d.mts +6 -0
- package/vendor/chat-import-reader/parsers.mjs +11168 -0
- package/vendor/chat-import-reader/scan-worker.mjs +7 -0
- package/vendor/chat-import-reader/scanners.mjs +4286 -0
- package/vendor/chat-import-reader/upstream-sha256.json +101 -0
|
@@ -0,0 +1,4286 @@
|
|
|
1
|
+
// Generated by scripts/vendor-chat-import-reader.mjs; see adjacent licenses.
|
|
2
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/registry.mjs
|
|
3
|
+
import { homedir as homedir3 } from "node:os";
|
|
4
|
+
|
|
5
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/claude.mjs
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
|
|
9
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/inject.mjs
|
|
10
|
+
var INJECT_MARKERS = [
|
|
11
|
+
"<environment_context>",
|
|
12
|
+
"<system-reminder>",
|
|
13
|
+
"<user_instructions>",
|
|
14
|
+
"<local-command-caveat>",
|
|
15
|
+
"<local-command-stdout>",
|
|
16
|
+
"<command-name>",
|
|
17
|
+
"<permissions>",
|
|
18
|
+
"# AGENTS.md",
|
|
19
|
+
"# Files mentioned",
|
|
20
|
+
"The user is asking about",
|
|
21
|
+
"# Context from my IDE setup:",
|
|
22
|
+
"<user_info>"
|
|
23
|
+
];
|
|
24
|
+
function isInjectedTopic(text) {
|
|
25
|
+
const t = String(text ?? "").trim();
|
|
26
|
+
if (!t) return true;
|
|
27
|
+
const lower = t.toLowerCase();
|
|
28
|
+
return INJECT_MARKERS.some((m) => lower.startsWith(m.toLowerCase()));
|
|
29
|
+
}
|
|
30
|
+
function stripPastedWrapper(text) {
|
|
31
|
+
const t = String(text ?? "").trim();
|
|
32
|
+
if (!t.includes("<pasted_content")) return t;
|
|
33
|
+
const cleaned = t.replace(/<\/?pasted_content(?:\s[^>]*)?>/g, " ").replace(/\s+/g, " ").trim();
|
|
34
|
+
return cleaned || t;
|
|
35
|
+
}
|
|
36
|
+
var CODEX_PAGE_CONTEXT_OPEN = "<external_codex_apps_open_page>";
|
|
37
|
+
var CODEX_PAGE_CONTEXT_CLOSE = "</external_codex_apps_open_page>";
|
|
38
|
+
var CODEX_PAGE_CONTEXT_RE = new RegExp(
|
|
39
|
+
CODEX_PAGE_CONTEXT_OPEN + "[\\s\\S]*?" + CODEX_PAGE_CONTEXT_CLOSE,
|
|
40
|
+
"g"
|
|
41
|
+
);
|
|
42
|
+
function stripCodexPageContext(text) {
|
|
43
|
+
const t = String(text ?? "");
|
|
44
|
+
if (!t.includes(CODEX_PAGE_CONTEXT_OPEN)) return t;
|
|
45
|
+
return t.replace(CODEX_PAGE_CONTEXT_RE, "");
|
|
46
|
+
}
|
|
47
|
+
function stripSystemReminders(text) {
|
|
48
|
+
return String(text ?? "").replace(/<system-reminder[\s\S]*?<\/system-reminder>/gi, "");
|
|
49
|
+
}
|
|
50
|
+
function stripUserQueryWrapper(text) {
|
|
51
|
+
const t = String(text ?? "").trim();
|
|
52
|
+
if (!t.includes("<user_query>")) return t;
|
|
53
|
+
const parts = [];
|
|
54
|
+
const re = /<user_query>([\s\S]*?)(?:<\/user_query>|$)/g;
|
|
55
|
+
let m;
|
|
56
|
+
while ((m = re.exec(t)) !== null) {
|
|
57
|
+
const inner = m[1].trim();
|
|
58
|
+
if (inner) parts.push(inner);
|
|
59
|
+
}
|
|
60
|
+
return parts.join("\n");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/image.mjs
|
|
64
|
+
var MAX_IMAGE_BASE64_CHARS = 24 * 1024 * 1024;
|
|
65
|
+
|
|
66
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/validate.mjs
|
|
67
|
+
var SESSION_EVENT_TYPES = [
|
|
68
|
+
// 本插件自产 / 客户端流事件(宿主词汇表外,见上)
|
|
69
|
+
"session/imported",
|
|
70
|
+
"assistant/chunk",
|
|
71
|
+
// 以下对齐宿主 @deepseek-ai/dsh-session 的 KNOWN_SESSION_EVENT_TYPES(0.1.5 时代,
|
|
72
|
+
// 含 system/message、developer/message、assistant/attempt、model/selection、
|
|
73
|
+
// subagent/catalog、deliverables/presented、image/offload、workspace/changes、
|
|
74
|
+
// tool/ptc-dispatch* 等新事件)。白名单滞后会把宿主合法事件误报成 unknown-type——
|
|
75
|
+
// 2026-09-22 实测:一个 V4 会话里有 4 种新事件被误报,把真正的问题挤出上报上限。
|
|
76
|
+
"agent-preset/selected",
|
|
77
|
+
"agent/inbox/spliced",
|
|
78
|
+
"approval/asked",
|
|
79
|
+
"approval/decided",
|
|
80
|
+
"approval/policy",
|
|
81
|
+
"assistant/attempt",
|
|
82
|
+
"assistant/message",
|
|
83
|
+
"command/done",
|
|
84
|
+
"command/run",
|
|
85
|
+
"compaction/end",
|
|
86
|
+
"compaction/prune",
|
|
87
|
+
"compaction/start",
|
|
88
|
+
"compaction/summary",
|
|
89
|
+
"deliverables/presented",
|
|
90
|
+
"developer/message",
|
|
91
|
+
"feedback/message-delete",
|
|
92
|
+
"feedback/message-put",
|
|
93
|
+
"feedback/record",
|
|
94
|
+
"goal/change",
|
|
95
|
+
"hook/invoked",
|
|
96
|
+
"hook/result",
|
|
97
|
+
"image/offload",
|
|
98
|
+
"llm/retry",
|
|
99
|
+
"llm/retry-started",
|
|
100
|
+
"model/selection",
|
|
101
|
+
"permission/preset",
|
|
102
|
+
"plan/mode",
|
|
103
|
+
"request/header",
|
|
104
|
+
"request/context",
|
|
105
|
+
"sandbox/mode",
|
|
106
|
+
"schedule/change",
|
|
107
|
+
"session-log-deepseek/delivery-accepted",
|
|
108
|
+
"session/end-seed",
|
|
109
|
+
"session/title",
|
|
110
|
+
"session/title-llm-request",
|
|
111
|
+
"step/start",
|
|
112
|
+
"step/end",
|
|
113
|
+
"subagent/catalog",
|
|
114
|
+
"subagent/descriptor",
|
|
115
|
+
"subagent/model-selection-policy",
|
|
116
|
+
"system/message",
|
|
117
|
+
"team/member",
|
|
118
|
+
"team/message/delivered",
|
|
119
|
+
"team/message/queued",
|
|
120
|
+
"team/task",
|
|
121
|
+
"todo/write",
|
|
122
|
+
"tool-workflow/agent-end",
|
|
123
|
+
"tool-workflow/agent-start",
|
|
124
|
+
"tool-workflow/run-end",
|
|
125
|
+
"tool-workflow/run-start",
|
|
126
|
+
"tool/call",
|
|
127
|
+
"tool/result",
|
|
128
|
+
"tool/code-dispatch",
|
|
129
|
+
"tool/code-dispatch-start",
|
|
130
|
+
"tool/ptc-dispatch",
|
|
131
|
+
"tool/ptc-dispatch-start",
|
|
132
|
+
"turn/start",
|
|
133
|
+
"turn/end",
|
|
134
|
+
"user/message",
|
|
135
|
+
"web/deepseek-search-llm-request",
|
|
136
|
+
"workspace/changes"
|
|
137
|
+
];
|
|
138
|
+
var SESSION_EVENT_TYPES_SET = new Set(SESSION_EVENT_TYPES);
|
|
139
|
+
|
|
140
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/core.mjs
|
|
141
|
+
function parseTimeMs(value, { truncSeconds = false } = {}) {
|
|
142
|
+
if (typeof value === "number") {
|
|
143
|
+
if (!Number.isFinite(value)) return null;
|
|
144
|
+
const ms = Math.round(value < 1e11 ? (truncSeconds ? Math.trunc(value) : value) * 1e3 : value);
|
|
145
|
+
return Number.isSafeInteger(ms) ? ms : null;
|
|
146
|
+
}
|
|
147
|
+
if (typeof value === "string") {
|
|
148
|
+
const n = Date.parse(value);
|
|
149
|
+
if (Number.isFinite(n)) return n;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function parseTime(value) {
|
|
154
|
+
return parseTimeMs(value) ?? Date.now();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/util.mjs
|
|
158
|
+
import { posix, win32 } from "node:path";
|
|
159
|
+
function joinForPlatform(platform, ...parts) {
|
|
160
|
+
return platform === "win32" ? win32.join(...parts) : posix.join(...parts);
|
|
161
|
+
}
|
|
162
|
+
function isAbsoluteLike(p) {
|
|
163
|
+
return /^([a-zA-Z]:[\\/]|[\\/])/.test(String(p));
|
|
164
|
+
}
|
|
165
|
+
var TITLE_MAX_LEN = 80;
|
|
166
|
+
var TITLE_ELLIPSIS = "\u2026";
|
|
167
|
+
function normalizeTitle(text) {
|
|
168
|
+
const t = String(text ?? "").trim().replace(/\s+/g, " ");
|
|
169
|
+
if (!t) return "";
|
|
170
|
+
return t.length <= TITLE_MAX_LEN ? t : t.slice(0, TITLE_MAX_LEN - TITLE_ELLIPSIS.length) + TITLE_ELLIPSIS;
|
|
171
|
+
}
|
|
172
|
+
var TEXT_BLOCK_TYPES = ["text"];
|
|
173
|
+
function contentText(content, { types = TEXT_BLOCK_TYPES, sep = "\n", skipEmpty = false, trim = false } = {}) {
|
|
174
|
+
let text = "";
|
|
175
|
+
if (typeof content === "string") {
|
|
176
|
+
text = content;
|
|
177
|
+
} else if (Array.isArray(content)) {
|
|
178
|
+
const parts = [];
|
|
179
|
+
for (const b of content) {
|
|
180
|
+
if (!b || typeof b !== "object" || typeof b.text !== "string") continue;
|
|
181
|
+
if (types !== null && !types.includes(b.type)) continue;
|
|
182
|
+
if (skipEmpty && !b.text) continue;
|
|
183
|
+
parts.push(b.text);
|
|
184
|
+
}
|
|
185
|
+
text = parts.join(sep);
|
|
186
|
+
}
|
|
187
|
+
return trim ? text.trim() : text;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/qwen.mjs
|
|
191
|
+
function realWorkspaceDir(directories) {
|
|
192
|
+
if (!Array.isArray(directories)) return null;
|
|
193
|
+
for (const d of directories) {
|
|
194
|
+
if (typeof d === "string" && d && !/[\\/]\.qwenworkcn([\\/]|$)/i.test(d)) return d;
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/workbuddy.mjs
|
|
200
|
+
function extractWorkbuddyUserQuery(content) {
|
|
201
|
+
const joined = Array.isArray(content) ? contentText(content, { types: null }) : "";
|
|
202
|
+
const m = /<user_query>([\s\S]*?)<\/user_query>/.exec(joined);
|
|
203
|
+
if (m && m[1] && m[1].trim()) return m[1].trim();
|
|
204
|
+
return stripSystemReminders(joined).replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/common.mjs
|
|
208
|
+
var HEAD_MAX_BYTES = 256 * 1024;
|
|
209
|
+
var TAIL_MAX_BYTES = 64 * 1024;
|
|
210
|
+
function pathSegments(p) {
|
|
211
|
+
return String(p ?? "").split(/[\\/]/).filter((s) => s.length > 0);
|
|
212
|
+
}
|
|
213
|
+
function slashPath(p) {
|
|
214
|
+
return String(p ?? "").replace(/\\/g, "/");
|
|
215
|
+
}
|
|
216
|
+
function basenameOf(p) {
|
|
217
|
+
const s = pathSegments(p);
|
|
218
|
+
return s[s.length - 1] ?? "";
|
|
219
|
+
}
|
|
220
|
+
function dirnameOf(p) {
|
|
221
|
+
const s = pathSegments(p);
|
|
222
|
+
s.pop();
|
|
223
|
+
return s.join("/");
|
|
224
|
+
}
|
|
225
|
+
function siblingPath(filePath, suffixName) {
|
|
226
|
+
const m = String(filePath).match(/[\\/][^\\/]+$/);
|
|
227
|
+
return m ? filePath.slice(0, m.index + 1) + suffixName : filePath;
|
|
228
|
+
}
|
|
229
|
+
function parseJsonlHead(head) {
|
|
230
|
+
const recs = [];
|
|
231
|
+
for (const line of String(head ?? "").split(/\r?\n/)) {
|
|
232
|
+
const t = line.trim();
|
|
233
|
+
if (!t) continue;
|
|
234
|
+
try {
|
|
235
|
+
recs.push(JSON.parse(t));
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return recs;
|
|
240
|
+
}
|
|
241
|
+
function isInjectedTitle(text) {
|
|
242
|
+
return isInjectedTopic(text);
|
|
243
|
+
}
|
|
244
|
+
function contentText2(content) {
|
|
245
|
+
if (typeof content === "string") return content;
|
|
246
|
+
if (Array.isArray(content)) {
|
|
247
|
+
const parts = [];
|
|
248
|
+
for (const block of content) {
|
|
249
|
+
if (!block || typeof block !== "object") continue;
|
|
250
|
+
if (block.type === "tool_result") continue;
|
|
251
|
+
if (typeof block.text === "string" && block.text.trim()) parts.push(block.text);
|
|
252
|
+
}
|
|
253
|
+
return parts.join("\n");
|
|
254
|
+
}
|
|
255
|
+
if (content && typeof content === "object" && typeof content.text === "string") return content.text;
|
|
256
|
+
return "";
|
|
257
|
+
}
|
|
258
|
+
function firstUserRawText(recs, extract) {
|
|
259
|
+
for (const rec of recs) {
|
|
260
|
+
const text = extract(rec);
|
|
261
|
+
const t = String(text ?? "").trim();
|
|
262
|
+
if (!t || isInjectedTitle(t)) continue;
|
|
263
|
+
return t;
|
|
264
|
+
}
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
function firstUserTitle(recs, extract) {
|
|
268
|
+
const raw = firstUserRawText(recs, extract);
|
|
269
|
+
return raw ? normalizeTitle(raw) : null;
|
|
270
|
+
}
|
|
271
|
+
function parseTimeValue(v) {
|
|
272
|
+
if (typeof v === "number" && Number.isFinite(v)) return v > 1e12 ? v : Math.trunc(v) * 1e3;
|
|
273
|
+
if (typeof v === "string" && v) {
|
|
274
|
+
const n = Date.parse(v);
|
|
275
|
+
if (Number.isFinite(n)) return n;
|
|
276
|
+
}
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
function firstString(recs, pick) {
|
|
280
|
+
for (const r of recs) {
|
|
281
|
+
const v = pick(r);
|
|
282
|
+
if (typeof v === "string" && v) return v;
|
|
283
|
+
}
|
|
284
|
+
return void 0;
|
|
285
|
+
}
|
|
286
|
+
function lastString(recs, pick) {
|
|
287
|
+
for (let i = recs.length - 1; i >= 0; i--) {
|
|
288
|
+
const v = pick(recs[i]);
|
|
289
|
+
if (typeof v === "string" && v) return v;
|
|
290
|
+
}
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
function firstNumber(recs, pick) {
|
|
294
|
+
for (const r of recs) {
|
|
295
|
+
const v = pick(r);
|
|
296
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
297
|
+
}
|
|
298
|
+
return void 0;
|
|
299
|
+
}
|
|
300
|
+
function projectFromRecord(cwd, layoutFallback) {
|
|
301
|
+
const base = cwd ? basenameOf(cwd) : "";
|
|
302
|
+
return base || layoutFallback() || null;
|
|
303
|
+
}
|
|
304
|
+
function makeEntry({ format, sessionId, title, project, createdAt, lastActiveAt, contextTokens, sourcePath, cwd }) {
|
|
305
|
+
const intOrNull = (v) => typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : null;
|
|
306
|
+
return {
|
|
307
|
+
format,
|
|
308
|
+
sessionId,
|
|
309
|
+
title: title || null,
|
|
310
|
+
project: project || null,
|
|
311
|
+
createdAt: intOrNull(createdAt),
|
|
312
|
+
lastActiveAt: intOrNull(lastActiveAt),
|
|
313
|
+
contextTokens: intOrNull(contextTokens),
|
|
314
|
+
sourcePath,
|
|
315
|
+
cwd: cwd || null,
|
|
316
|
+
importStatus: null
|
|
317
|
+
// discoverSessions 统一填充(本模块不做 registry I/O)
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function fileFingerprint(st) {
|
|
321
|
+
return { mtimeMs: st.mtimeMs, sizeBytes: st.size };
|
|
322
|
+
}
|
|
323
|
+
function compositeFingerprint(primary, ...companions) {
|
|
324
|
+
return {
|
|
325
|
+
mtimeMs: primary.mtimeMs + companions.map((c) => "|" + (c ? c.mtimeMs : "")).join(""),
|
|
326
|
+
sizeBytes: companions.reduce((sum, c) => sum + (c ? c.size : 0), primary.size)
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
async function emitEach(emit, entries) {
|
|
330
|
+
if (!emit || !entries || entries.length === 0) return;
|
|
331
|
+
for (const e of entries) await emit(e);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/walk.mjs
|
|
335
|
+
var WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
336
|
+
"node_modules",
|
|
337
|
+
".git",
|
|
338
|
+
".hg",
|
|
339
|
+
".svn",
|
|
340
|
+
".venv",
|
|
341
|
+
"venv",
|
|
342
|
+
"dist",
|
|
343
|
+
"build",
|
|
344
|
+
".next",
|
|
345
|
+
".turbo",
|
|
346
|
+
".cache",
|
|
347
|
+
"target",
|
|
348
|
+
"out",
|
|
349
|
+
".idea",
|
|
350
|
+
".vscode",
|
|
351
|
+
"__pycache__",
|
|
352
|
+
".pytest_cache",
|
|
353
|
+
".mypy_cache",
|
|
354
|
+
".DS_Store"
|
|
355
|
+
]);
|
|
356
|
+
var WALK_MAX_DEPTH = 12;
|
|
357
|
+
async function walkFiles(host2, target, out, match, depth = 0) {
|
|
358
|
+
if (depth > WALK_MAX_DEPTH) return;
|
|
359
|
+
const entries = await host2.readDir(target);
|
|
360
|
+
if (!entries || entries.length === 0) {
|
|
361
|
+
const st = await host2.stat(target);
|
|
362
|
+
const name = basenameOf(target);
|
|
363
|
+
if (st && st.type === "file" && match(name)) out.push({ name, type: "file", path: target });
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
for (const e of entries) {
|
|
367
|
+
if (e.type === "directory") {
|
|
368
|
+
if (WALK_SKIP_DIRS.has(e.name)) continue;
|
|
369
|
+
await walkFiles(host2, e.path, out, match, depth + 1);
|
|
370
|
+
} else if (e.type === "file" && match(e.name)) {
|
|
371
|
+
out.push(e);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/scan-cache.mjs
|
|
377
|
+
var SCAN_TTL_MS = 3e4;
|
|
378
|
+
function createScanCache({ ttlMs = SCAN_TTL_MS, now = () => Date.now() } = {}) {
|
|
379
|
+
const map = /* @__PURE__ */ new Map();
|
|
380
|
+
return {
|
|
381
|
+
get(key) {
|
|
382
|
+
const hit = map.get(key);
|
|
383
|
+
if (!hit) return void 0;
|
|
384
|
+
if (now() - hit.ts < ttlMs) return hit.data;
|
|
385
|
+
map.delete(key);
|
|
386
|
+
return void 0;
|
|
387
|
+
},
|
|
388
|
+
set(key, data) {
|
|
389
|
+
map.set(key, { ts: now(), data });
|
|
390
|
+
},
|
|
391
|
+
clear() {
|
|
392
|
+
map.clear();
|
|
393
|
+
},
|
|
394
|
+
get size() {
|
|
395
|
+
return map.size;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
var scanCache = createScanCache();
|
|
400
|
+
var cacheWriteChain = Promise.resolve();
|
|
401
|
+
async function probeSource(bm, format, sourcePath, fp, probe, patchHit) {
|
|
402
|
+
if (!bm) return probe();
|
|
403
|
+
const hit = await bm.get(format, sourcePath, fp);
|
|
404
|
+
if (hit !== void 0) {
|
|
405
|
+
if (hit !== null && typeof patchHit === "function") {
|
|
406
|
+
const patched = await patchHit(hit);
|
|
407
|
+
if (patched.changed) await bm.remember(format, sourcePath, fp, patched.entries);
|
|
408
|
+
return patched.entries;
|
|
409
|
+
}
|
|
410
|
+
return hit;
|
|
411
|
+
}
|
|
412
|
+
const entries = await probe();
|
|
413
|
+
await bm.remember(format, sourcePath, fp, entries);
|
|
414
|
+
return entries;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/claude.mjs
|
|
418
|
+
function claudeContextTokens(tailText) {
|
|
419
|
+
let last = null;
|
|
420
|
+
for (const line of String(tailText ?? "").split(/\r?\n/)) {
|
|
421
|
+
const t = line.trim();
|
|
422
|
+
if (!t) continue;
|
|
423
|
+
let r;
|
|
424
|
+
try {
|
|
425
|
+
r = JSON.parse(t);
|
|
426
|
+
} catch {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
const u = r && r.message && r.message.usage;
|
|
430
|
+
if (u && typeof u.input_tokens === "number" && Number.isFinite(u.input_tokens)) last = u.input_tokens;
|
|
431
|
+
}
|
|
432
|
+
return last;
|
|
433
|
+
}
|
|
434
|
+
function claudeTitle(headRecs, tailRecs) {
|
|
435
|
+
const lastCustom = (list) => {
|
|
436
|
+
let v = null;
|
|
437
|
+
for (const r of list) {
|
|
438
|
+
if (r && r.type === "custom-title" && typeof r.customTitle === "string" && r.customTitle.trim()) v = r.customTitle;
|
|
439
|
+
}
|
|
440
|
+
return v;
|
|
441
|
+
};
|
|
442
|
+
const custom = lastCustom(tailRecs) || lastCustom(headRecs);
|
|
443
|
+
if (custom) return normalizeTitle(custom);
|
|
444
|
+
const ai = firstString(
|
|
445
|
+
[...headRecs, ...tailRecs],
|
|
446
|
+
(r) => r && r.type === "ai-title" && typeof r.aiTitle === "string" && r.aiTitle.trim() ? r.aiTitle : void 0
|
|
447
|
+
);
|
|
448
|
+
if (ai) return normalizeTitle(ai);
|
|
449
|
+
const raw = firstUserRawText(
|
|
450
|
+
headRecs,
|
|
451
|
+
(r) => r && r.type === "user" && r.message && r.message.role === "user" ? contentText2(r.message.content) : ""
|
|
452
|
+
);
|
|
453
|
+
return raw ? normalizeTitle(stripPastedWrapper(raw)) : null;
|
|
454
|
+
}
|
|
455
|
+
async function scanClaude(host2, target, { bm, emit }) {
|
|
456
|
+
if (/claude-code-sessions/i.test(String(target))) return scanClaude3p(host2, target, { bm, emit });
|
|
457
|
+
const files = [];
|
|
458
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
459
|
+
const out = [];
|
|
460
|
+
for (const file of files) {
|
|
461
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
462
|
+
if (stem.startsWith("agent-")) continue;
|
|
463
|
+
const st = await host2.stat(file.path);
|
|
464
|
+
if (!st) continue;
|
|
465
|
+
const fp = fileFingerprint(st);
|
|
466
|
+
const entries = await probeSource(bm, "claude", file.path, fp, async () => {
|
|
467
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
468
|
+
if (head === null || head === "") return [];
|
|
469
|
+
const headRecs = parseJsonlHead(head);
|
|
470
|
+
const whole = st.size <= HEAD_MAX_BYTES;
|
|
471
|
+
const tail = whole ? head : await host2.readTail(file.path, TAIL_MAX_BYTES);
|
|
472
|
+
const tailRecs = whole ? headRecs : parseJsonlHead(tail);
|
|
473
|
+
const isMain = firstString(headRecs, (r) => r && r.sessionId) === stem || lastString(tailRecs, (r) => r && r.sessionId) === stem;
|
|
474
|
+
if (!isMain) return [];
|
|
475
|
+
const sessionId = stem;
|
|
476
|
+
const cwd = firstString(headRecs, (r) => r && r.cwd);
|
|
477
|
+
const createdAt = firstNumber(headRecs, (r) => r && r.timestamp !== void 0 ? parseTimeValue(r.timestamp) : void 0);
|
|
478
|
+
const title = claudeTitle(headRecs, tailRecs);
|
|
479
|
+
const contextTokens = claudeContextTokens(tail);
|
|
480
|
+
return [makeEntry({
|
|
481
|
+
format: "claude",
|
|
482
|
+
sessionId,
|
|
483
|
+
title,
|
|
484
|
+
project: projectFromRecord(cwd, () => claudeLayoutProject(file.path)),
|
|
485
|
+
createdAt,
|
|
486
|
+
lastActiveAt: st.mtimeMs,
|
|
487
|
+
contextTokens,
|
|
488
|
+
sourcePath: file.path,
|
|
489
|
+
cwd
|
|
490
|
+
})];
|
|
491
|
+
});
|
|
492
|
+
out.push(...entries);
|
|
493
|
+
await emitEach(emit, entries);
|
|
494
|
+
}
|
|
495
|
+
return out;
|
|
496
|
+
}
|
|
497
|
+
async function scanClaude3p(host2, target, { bm, emit }) {
|
|
498
|
+
const files = [];
|
|
499
|
+
await walkFiles(host2, target, files, (name) => /\.json$/i.test(name));
|
|
500
|
+
const out = [];
|
|
501
|
+
for (const file of files) {
|
|
502
|
+
const st = await host2.stat(file.path);
|
|
503
|
+
if (!st) continue;
|
|
504
|
+
const fp = fileFingerprint(st);
|
|
505
|
+
const entries = await probeSource(bm, "claude", file.path, fp, async () => {
|
|
506
|
+
const raw = await host2.readText(file.path);
|
|
507
|
+
if (raw === null || raw === "") return [];
|
|
508
|
+
let meta;
|
|
509
|
+
try {
|
|
510
|
+
meta = JSON.parse(raw);
|
|
511
|
+
} catch {
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
if (!meta || typeof meta !== "object") return [];
|
|
515
|
+
const sessionId = typeof meta.sessionId === "string" && meta.sessionId ? meta.sessionId : basenameOf(file.name).replace(/\.json$/i, "");
|
|
516
|
+
const cliId = typeof meta.cliSessionId === "string" && meta.cliSessionId ? meta.cliSessionId : null;
|
|
517
|
+
const cwd = typeof meta.cwd === "string" && meta.cwd ? meta.cwd : null;
|
|
518
|
+
const title = typeof meta.title === "string" && meta.title.trim() ? normalizeTitle(meta.title) : null;
|
|
519
|
+
const lastActiveAt = parseTimeValue(meta.lastActivityAt);
|
|
520
|
+
const createdAt = parseTimeValue(meta.createdAt);
|
|
521
|
+
if (cliId) {
|
|
522
|
+
const jsonlPath = await findJsonlBySessionId(host2, cliId, join(homedir(), ".claude", "projects"));
|
|
523
|
+
if (jsonlPath) {
|
|
524
|
+
return [makeEntry({
|
|
525
|
+
format: "claude",
|
|
526
|
+
sessionId: cliId,
|
|
527
|
+
title,
|
|
528
|
+
project: cwd ? basenameOf(cwd) : claudeLayoutProject(jsonlPath),
|
|
529
|
+
createdAt,
|
|
530
|
+
lastActiveAt,
|
|
531
|
+
sourcePath: jsonlPath,
|
|
532
|
+
cwd
|
|
533
|
+
})];
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return [makeEntry({
|
|
537
|
+
format: "claude",
|
|
538
|
+
sessionId,
|
|
539
|
+
title,
|
|
540
|
+
project: cwd ? basenameOf(cwd) : null,
|
|
541
|
+
createdAt,
|
|
542
|
+
lastActiveAt,
|
|
543
|
+
sourcePath: file.path,
|
|
544
|
+
cwd
|
|
545
|
+
})];
|
|
546
|
+
});
|
|
547
|
+
out.push(...entries);
|
|
548
|
+
await emitEach(emit, entries);
|
|
549
|
+
}
|
|
550
|
+
return out;
|
|
551
|
+
}
|
|
552
|
+
async function findJsonlBySessionId(host2, cliSessionId, projectsRoot) {
|
|
553
|
+
const files = [];
|
|
554
|
+
await walkFiles(host2, projectsRoot, files, (name) => name === cliSessionId + ".jsonl");
|
|
555
|
+
for (const file of files) {
|
|
556
|
+
const head = await host2.readHead(file.path, 4096);
|
|
557
|
+
if (parseJsonlHead(head).some((r) => r && r.sessionId === cliSessionId)) return file.path;
|
|
558
|
+
}
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
async function scanQoder(host2, target, { bm, emit }) {
|
|
562
|
+
if (!/\.qoder[\\/]projects([\\/]|$)/i.test(String(target))) return [];
|
|
563
|
+
const files = [];
|
|
564
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
565
|
+
const out = [];
|
|
566
|
+
for (const file of files) {
|
|
567
|
+
if (/\bsubagents[\\/]/.test(file.path)) continue;
|
|
568
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
569
|
+
const st = await host2.stat(file.path);
|
|
570
|
+
if (!st) continue;
|
|
571
|
+
const fp = fileFingerprint(st);
|
|
572
|
+
const entries = await probeSource(bm, "qoder", file.path, fp, async () => {
|
|
573
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
574
|
+
if (head === null || head === "") return [];
|
|
575
|
+
const recs = parseJsonlHead(head);
|
|
576
|
+
const sessionId = firstString(recs, (r) => r && r.sessionId);
|
|
577
|
+
if (!sessionId || sessionId !== stem) return [];
|
|
578
|
+
const cwd = firstString(recs, (r) => r && r.cwd);
|
|
579
|
+
const createdAt = firstNumber(recs, (r) => r && r.timestamp !== void 0 ? parseTimeValue(r.timestamp) : void 0);
|
|
580
|
+
const aiTitle = firstString(recs, (r) => r && r.type === "ai-title" ? r.aiTitle : void 0);
|
|
581
|
+
const lastPrompt = firstString(recs, (r) => r && r.type === "last-prompt" ? r.lastPrompt : void 0);
|
|
582
|
+
const title = normalizeTitle(aiTitle || lastPrompt) || firstUserTitle(recs, (r) => r && r.type === "user" && r.message && r.message.role === "user" ? contentText2(r.message.content) : "");
|
|
583
|
+
return [makeEntry({
|
|
584
|
+
format: "qoder",
|
|
585
|
+
sessionId,
|
|
586
|
+
title,
|
|
587
|
+
project: projectFromRecord(cwd, () => qoderLayoutProject(file.path)),
|
|
588
|
+
createdAt,
|
|
589
|
+
lastActiveAt: st.mtimeMs,
|
|
590
|
+
sourcePath: file.path,
|
|
591
|
+
cwd
|
|
592
|
+
})];
|
|
593
|
+
});
|
|
594
|
+
out.push(...entries);
|
|
595
|
+
await emitEach(emit, entries);
|
|
596
|
+
}
|
|
597
|
+
return out;
|
|
598
|
+
}
|
|
599
|
+
function workbuddyUserQuery(recs) {
|
|
600
|
+
for (const r of recs) {
|
|
601
|
+
if (!r || typeof r !== "object") continue;
|
|
602
|
+
if (r.type === "message" && r.role === "user" && Array.isArray(r.content)) {
|
|
603
|
+
const text = extractWorkbuddyUserQuery(r.content);
|
|
604
|
+
if (text) return text;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return "";
|
|
608
|
+
}
|
|
609
|
+
async function scanWorkbuddy(host2, target, { bm, emit }) {
|
|
610
|
+
if (!/\.workbuddy[\\/]projects([\\/]|$)/i.test(String(target))) return [];
|
|
611
|
+
const files = [];
|
|
612
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
613
|
+
const out = [];
|
|
614
|
+
for (const file of files) {
|
|
615
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
616
|
+
const st = await host2.stat(file.path);
|
|
617
|
+
if (!st) continue;
|
|
618
|
+
const fp = fileFingerprint(st);
|
|
619
|
+
const entries = await probeSource(bm, "workbuddy", file.path, fp, async () => {
|
|
620
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
621
|
+
if (head === null || head === "") return [];
|
|
622
|
+
const recs = parseJsonlHead(head);
|
|
623
|
+
const sessionId = firstString(recs, (r) => r && r.sessionId) || stem;
|
|
624
|
+
if (!sessionId) return [];
|
|
625
|
+
const cwd = firstString(recs, (r) => r && r.cwd);
|
|
626
|
+
const createdAt = firstNumber(recs, (r) => r && r.timestamp !== void 0 ? parseTimeValue(r.timestamp) : void 0);
|
|
627
|
+
const title = normalizeTitle(workbuddyUserQuery(recs));
|
|
628
|
+
return [makeEntry({
|
|
629
|
+
format: "workbuddy",
|
|
630
|
+
sessionId,
|
|
631
|
+
title,
|
|
632
|
+
project: projectFromRecord(cwd, () => workbuddyLayoutProject(file.path)),
|
|
633
|
+
createdAt,
|
|
634
|
+
lastActiveAt: st.mtimeMs,
|
|
635
|
+
sourcePath: file.path,
|
|
636
|
+
cwd
|
|
637
|
+
})];
|
|
638
|
+
});
|
|
639
|
+
out.push(...entries);
|
|
640
|
+
await emitEach(emit, entries);
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
function qwenUserQuery(recs) {
|
|
645
|
+
for (const r of recs) {
|
|
646
|
+
if (!r || typeof r !== "object" || r.type !== "user" || !r.message) continue;
|
|
647
|
+
const hi = r.humanInput;
|
|
648
|
+
if (hi && typeof hi === "object" && typeof hi.text === "string" && hi.text.trim()) return hi.text;
|
|
649
|
+
const blocks = Array.isArray(r.message.content) ? r.message.content : null;
|
|
650
|
+
if (blocks !== null) {
|
|
651
|
+
const texts = blocks.filter((b) => b && b.type === "text" && typeof b.text === "string" && b.text.trim() && !/^<system/.test(b.text.trim())).map((b) => b.text);
|
|
652
|
+
if (texts.length > 0) return texts.join("\n");
|
|
653
|
+
} else if (typeof r.message.content === "string" && r.message.content.trim() && !/^<system/.test(r.message.content.trim())) {
|
|
654
|
+
return r.message.content;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return "";
|
|
658
|
+
}
|
|
659
|
+
async function scanQwen(host2, target, { bm, emit }) {
|
|
660
|
+
if (!/\.qwenworkcn[\\/]projects([\\/]|$)/i.test(String(target))) return [];
|
|
661
|
+
const files = [];
|
|
662
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
663
|
+
const bySession = /* @__PURE__ */ new Map();
|
|
664
|
+
for (const file of files) {
|
|
665
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
666
|
+
const st = await host2.stat(file.path);
|
|
667
|
+
if (!st) continue;
|
|
668
|
+
const fp = fileFingerprint(st);
|
|
669
|
+
const entries = await probeSource(bm, "qwen", file.path, fp, async () => {
|
|
670
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
671
|
+
if (head === null || head === "") return [];
|
|
672
|
+
const recs = parseJsonlHead(head);
|
|
673
|
+
const sessionId = firstString(recs, (r) => r && r.sessionId) || stem;
|
|
674
|
+
if (!sessionId || sessionId !== stem) return [];
|
|
675
|
+
const wsDir = firstString(recs, (r) => r && r.type === "workspace-directories" ? realWorkspaceDir(r.directories) : void 0);
|
|
676
|
+
const createdAt = firstNumber(recs, (r) => r && r.timestamp !== void 0 ? parseTimeValue(r.timestamp) : void 0);
|
|
677
|
+
const title = normalizeTitle(qwenUserQuery(recs));
|
|
678
|
+
return [makeEntry({
|
|
679
|
+
format: "qwen",
|
|
680
|
+
sessionId,
|
|
681
|
+
title,
|
|
682
|
+
project: wsDir ? basenameOf(wsDir) : null,
|
|
683
|
+
createdAt,
|
|
684
|
+
lastActiveAt: st.mtimeMs,
|
|
685
|
+
sourcePath: file.path,
|
|
686
|
+
cwd: wsDir
|
|
687
|
+
})];
|
|
688
|
+
});
|
|
689
|
+
for (const e of entries) {
|
|
690
|
+
const prev = bySession.get(e.sessionId);
|
|
691
|
+
if (!prev || (e.lastActiveAt ?? 0) > (prev.lastActiveAt ?? 0)) bySession.set(e.sessionId, e);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
const out = [...bySession.values()];
|
|
695
|
+
for (const e of out) await emitEach(emit, [e]);
|
|
696
|
+
return out;
|
|
697
|
+
}
|
|
698
|
+
function claudeLayoutProject(sourcePath) {
|
|
699
|
+
const m = slashPath(sourcePath).match(/\/projects\/([^/]+)\/[^/]+\.jsonl$/i);
|
|
700
|
+
return m ? m[1] : null;
|
|
701
|
+
}
|
|
702
|
+
function qoderLayoutProject(sourcePath) {
|
|
703
|
+
const m = slashPath(sourcePath).match(/\/projects\/([^/]+)\/[^/]+\.jsonl$/i);
|
|
704
|
+
if (!m) return null;
|
|
705
|
+
const decoded = m[1].replace(/-/g, "/");
|
|
706
|
+
return decoded.split("/").filter(Boolean).pop() || m[1];
|
|
707
|
+
}
|
|
708
|
+
function workbuddyLayoutProject(sourcePath) {
|
|
709
|
+
const m = slashPath(sourcePath).match(/\/\.workbuddy\/projects\/([^/]+)\/[^/]+\.jsonl$/i);
|
|
710
|
+
return m ? m[1] : null;
|
|
711
|
+
}
|
|
712
|
+
var isJsonl = (lower) => lower.endsWith(".jsonl");
|
|
713
|
+
var claudeSource = {
|
|
714
|
+
format: "claude",
|
|
715
|
+
// Claude-3p 新端(Windows LOCALAPPDATA)元数据根与 ~/.claude/projects 并列
|
|
716
|
+
roots: (home, env) => {
|
|
717
|
+
const projects = join(home, ".claude", "projects");
|
|
718
|
+
return env.LOCALAPPDATA ? [projects, join(env.LOCALAPPDATA, "Claude-3p", "claude-code-sessions")] : projects;
|
|
719
|
+
},
|
|
720
|
+
scan: scanClaude,
|
|
721
|
+
layoutProject: claudeLayoutProject,
|
|
722
|
+
matchFile: (lower) => isJsonl(lower) && /\.claude[\\/]/.test(lower),
|
|
723
|
+
fileFallback: ["jsonl"]
|
|
724
|
+
};
|
|
725
|
+
var qoderSource = {
|
|
726
|
+
format: "qoder",
|
|
727
|
+
roots: (home) => join(home, ".qoder", "projects"),
|
|
728
|
+
scan: scanQoder,
|
|
729
|
+
layoutProject: qoderLayoutProject,
|
|
730
|
+
matchFile: (lower) => isJsonl(lower) && /\.qoder[\\/]projects[\\/]/.test(lower)
|
|
731
|
+
};
|
|
732
|
+
var workbuddySource = {
|
|
733
|
+
format: "workbuddy",
|
|
734
|
+
roots: (home) => join(home, ".workbuddy", "projects"),
|
|
735
|
+
scan: scanWorkbuddy,
|
|
736
|
+
layoutProject: workbuddyLayoutProject,
|
|
737
|
+
matchFile: (lower) => isJsonl(lower) && /\.workbuddy[\\/]projects[\\/]/.test(lower)
|
|
738
|
+
};
|
|
739
|
+
var qwenSource = {
|
|
740
|
+
format: "qwen",
|
|
741
|
+
roots: (home) => join(home, ".qwenworkcn", "projects"),
|
|
742
|
+
scan: scanQwen,
|
|
743
|
+
matchFile: (lower) => isJsonl(lower) && /\.qwenworkcn[\\/]projects[\\/]/.test(lower)
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/jsonl.mjs
|
|
747
|
+
import { join as join3 } from "node:path";
|
|
748
|
+
|
|
749
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/reasonix.mjs
|
|
750
|
+
function reasonixStemTime(stem) {
|
|
751
|
+
const m = String(stem || "").match(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/);
|
|
752
|
+
if (!m) return null;
|
|
753
|
+
const month = +m[2];
|
|
754
|
+
const day = +m[3];
|
|
755
|
+
const hour = +m[4];
|
|
756
|
+
const minute = +m[5];
|
|
757
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59) return null;
|
|
758
|
+
const t = new Date(+m[1], month - 1, day, hour, minute);
|
|
759
|
+
return Number.isNaN(t.getTime()) ? null : t.getTime();
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/codex.mjs
|
|
763
|
+
function codexSubagentMarker(payload) {
|
|
764
|
+
if (!payload || typeof payload !== "object") return null;
|
|
765
|
+
if (payload.thread_source === "subagent") return "thread_source=subagent";
|
|
766
|
+
const src = payload.source;
|
|
767
|
+
if (src && typeof src === "object" && src.subagent) return "source.subagent";
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
function codexUserPrompt(content) {
|
|
771
|
+
const parts = [];
|
|
772
|
+
if (Array.isArray(content)) {
|
|
773
|
+
for (const block of content) {
|
|
774
|
+
if (!block || block.type !== "input_text" || typeof block.text !== "string") continue;
|
|
775
|
+
const stripped = stripCodexPageContext(block.text).trim();
|
|
776
|
+
const text = stripped.startsWith("# Files mentioned by the user:") && stripped.includes("## My request:") ? stripped.slice(stripped.indexOf("## My request:") + "## My request:".length).trim() : stripped;
|
|
777
|
+
if (!text.startsWith("<") && !isInjectedTopic(text)) parts.push(text);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return parts.join("\n").trim();
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/openclaw.mjs
|
|
784
|
+
function openclawDisplayNames(indexJson) {
|
|
785
|
+
const map = /* @__PURE__ */ new Map();
|
|
786
|
+
let index;
|
|
787
|
+
try {
|
|
788
|
+
index = JSON.parse(indexJson);
|
|
789
|
+
} catch {
|
|
790
|
+
return map;
|
|
791
|
+
}
|
|
792
|
+
if (!index || typeof index !== "object") return map;
|
|
793
|
+
for (const entry of Object.values(index)) {
|
|
794
|
+
if (!entry || typeof entry !== "object") continue;
|
|
795
|
+
if (typeof entry.sessionId === "string" && typeof entry.displayName === "string" && entry.displayName.trim()) {
|
|
796
|
+
map.set(entry.sessionId, entry.displayName.trim());
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return map;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// .codex-tmp/vendor-pagination-upstream/lib/cwd-map.mjs
|
|
803
|
+
import { homedir as homedir2 } from "node:os";
|
|
804
|
+
import { join as join2 } from "node:path";
|
|
805
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
806
|
+
|
|
807
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/cursor.mjs
|
|
808
|
+
function parseCursorEmbeddedTimestamp(text) {
|
|
809
|
+
const m = String(text ?? "").match(/<timestamp>\s*([^<]+?)\s*<\/timestamp>/i);
|
|
810
|
+
if (!m) return void 0;
|
|
811
|
+
const cleaned = m[1].replace(/\s*\(UTC[^)]*\)\s*/gi, " ").trim();
|
|
812
|
+
const n = Date.parse(cleaned);
|
|
813
|
+
return Number.isFinite(n) ? n : void 0;
|
|
814
|
+
}
|
|
815
|
+
function stripCursorTitleDecorations(text) {
|
|
816
|
+
return String(text ?? "").replace(/<timestamp>[\s\S]*?<\/timestamp>\s*/gi, "").replace(/<\/?user_query>/gi, "").trim();
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// .codex-tmp/vendor-pagination-upstream/lib/cwd-map.mjs
|
|
820
|
+
var CURSOR_NON_REPO_SLUGS = /* @__PURE__ */ new Set(["empty-window"]);
|
|
821
|
+
function isCursorNonRepoSlug(slug) {
|
|
822
|
+
const s = String(slug ?? "");
|
|
823
|
+
if (!s || CURSOR_NON_REPO_SLUGS.has(s)) return true;
|
|
824
|
+
return /^\d+$/.test(s);
|
|
825
|
+
}
|
|
826
|
+
function encodeCursorSlug(absPath) {
|
|
827
|
+
const p = String(absPath ?? "").replace(/\\/g, "/").replace(/\/+$/, "");
|
|
828
|
+
const m = p.match(/^([A-Za-z]):\/?(.*)$/);
|
|
829
|
+
if (!m) return null;
|
|
830
|
+
const drive = m[1].toLowerCase();
|
|
831
|
+
const tail = m[2].split("/").filter(Boolean).map((seg) => seg.replace(/\./g, "-")).join("-");
|
|
832
|
+
return tail ? drive + "-" + tail : drive;
|
|
833
|
+
}
|
|
834
|
+
var workspacePathCache = null;
|
|
835
|
+
var workspacePathCacheAt = 0;
|
|
836
|
+
var WORKSPACE_PATH_CACHE_MS = 3e4;
|
|
837
|
+
function collectPathsFromWorkspaceJson(node, paths) {
|
|
838
|
+
if (!node || typeof node !== "object") return;
|
|
839
|
+
if (typeof node.path === "string" && node.path) paths.add(node.path);
|
|
840
|
+
if (typeof node.cwd === "string" && node.cwd) paths.add(node.cwd);
|
|
841
|
+
for (const key of ["workspaces", "items", "list"]) {
|
|
842
|
+
const arr = node[key];
|
|
843
|
+
if (!Array.isArray(arr)) continue;
|
|
844
|
+
for (const item of arr) {
|
|
845
|
+
if (typeof item === "string" && item) paths.add(item);
|
|
846
|
+
else collectPathsFromWorkspaceJson(item, paths);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async function loadDshWorkspaceJsonPaths() {
|
|
851
|
+
const paths = /* @__PURE__ */ new Set();
|
|
852
|
+
const base = process.env.DSH_HOME || join2(homedir2(), ".dsh");
|
|
853
|
+
try {
|
|
854
|
+
const profilesDir = join2(base, "profiles");
|
|
855
|
+
const profiles = await readdir(profilesDir, { withFileTypes: true });
|
|
856
|
+
for (const prof of profiles) {
|
|
857
|
+
if (!prof.isDirectory()) continue;
|
|
858
|
+
const file = join2(profilesDir, prof.name, "storages", "workspace.json");
|
|
859
|
+
try {
|
|
860
|
+
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
861
|
+
collectPathsFromWorkspaceJson(parsed, paths);
|
|
862
|
+
} catch {
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
} catch {
|
|
866
|
+
}
|
|
867
|
+
return paths;
|
|
868
|
+
}
|
|
869
|
+
async function knownWorkspacePaths(ctx) {
|
|
870
|
+
const now = Date.now();
|
|
871
|
+
if (workspacePathCache && now - workspacePathCacheAt < WORKSPACE_PATH_CACHE_MS) {
|
|
872
|
+
return workspacePathCache;
|
|
873
|
+
}
|
|
874
|
+
const paths = await loadDshWorkspaceJsonPaths();
|
|
875
|
+
try {
|
|
876
|
+
const wr = ctx && typeof ctx.get === "function" ? ctx.get("workspaceRegistry") : null;
|
|
877
|
+
if (wr && typeof wr.list === "function") {
|
|
878
|
+
for (const ws of wr.list()) {
|
|
879
|
+
const p = ws && (ws.path || ws.cwd);
|
|
880
|
+
if (typeof p === "string" && p) paths.add(p);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
} catch {
|
|
884
|
+
}
|
|
885
|
+
workspacePathCache = paths;
|
|
886
|
+
workspacePathCacheAt = now;
|
|
887
|
+
return paths;
|
|
888
|
+
}
|
|
889
|
+
async function greedyDecodeCursorSlugPath(ctx, slug) {
|
|
890
|
+
const s = String(slug ?? "");
|
|
891
|
+
const m = s.match(/^([a-z])-(.*)$/i);
|
|
892
|
+
if (!m) return null;
|
|
893
|
+
const drive = m[1].toUpperCase() + ":\\";
|
|
894
|
+
const segments = m[2].split("-").filter(Boolean);
|
|
895
|
+
if (segments.length === 0) return null;
|
|
896
|
+
const exists = async (p) => {
|
|
897
|
+
try {
|
|
898
|
+
const info = await ctx.fs.stat(await ctx.fs.resolve(p));
|
|
899
|
+
return !!(info && info.type === "directory");
|
|
900
|
+
} catch {
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
const nameVariants = (parts) => {
|
|
905
|
+
const out = /* @__PURE__ */ new Set([parts.join("-")]);
|
|
906
|
+
if (parts.length === 2) out.add(parts[0] + "." + parts[1]);
|
|
907
|
+
if (parts.length === 3) {
|
|
908
|
+
out.add(parts[0] + "." + parts[1] + "-" + parts[2]);
|
|
909
|
+
out.add(parts[0] + "." + parts[1] + "." + parts[2]);
|
|
910
|
+
}
|
|
911
|
+
return [...out];
|
|
912
|
+
};
|
|
913
|
+
async function walk(i, prefix) {
|
|
914
|
+
if (i >= segments.length) return await exists(prefix) ? prefix : null;
|
|
915
|
+
for (let n = segments.length - i; n >= 1; n--) {
|
|
916
|
+
const chunk = segments.slice(i, i + n);
|
|
917
|
+
for (const name of nameVariants(chunk)) {
|
|
918
|
+
const next = prefix + name;
|
|
919
|
+
if (!await exists(next)) continue;
|
|
920
|
+
if (i + n >= segments.length) return next;
|
|
921
|
+
const rest = await walk(i + n, next + "\\");
|
|
922
|
+
if (rest) return rest;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
return walk(0, drive);
|
|
928
|
+
}
|
|
929
|
+
async function resolveCursorSlugPath(ctx, slug) {
|
|
930
|
+
if (!slug || isCursorNonRepoSlug(slug)) return null;
|
|
931
|
+
const paths = await knownWorkspacePaths(ctx);
|
|
932
|
+
for (const p of paths) {
|
|
933
|
+
if (encodeCursorSlug(p) === slug) return p;
|
|
934
|
+
}
|
|
935
|
+
return greedyDecodeCursorSlugPath(ctx, slug);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/antigravity.mjs
|
|
939
|
+
function unquote(value) {
|
|
940
|
+
if (typeof value !== "string") return value;
|
|
941
|
+
const s = value.trim();
|
|
942
|
+
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
943
|
+
try {
|
|
944
|
+
return JSON.parse(s);
|
|
945
|
+
} catch {
|
|
946
|
+
return s.slice(1, -1);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return value;
|
|
950
|
+
}
|
|
951
|
+
function unwrapUserRequest(text) {
|
|
952
|
+
let s = String(text ?? "");
|
|
953
|
+
const m = s.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/i);
|
|
954
|
+
if (m) s = m[1];
|
|
955
|
+
s = s.replace(/<ADDITIONAL_METADATA>[\s\S]*?<\/ADDITIONAL_METADATA>/gi, "");
|
|
956
|
+
s = s.replace(/<\/?USER_REQUEST>/gi, "");
|
|
957
|
+
return s.trim();
|
|
958
|
+
}
|
|
959
|
+
function parseAnnotationTitle(raw) {
|
|
960
|
+
const m = String(raw ?? "").match(/title\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
961
|
+
if (!m) return "";
|
|
962
|
+
try {
|
|
963
|
+
return String(JSON.parse(`"${m[1]}"`)).trim();
|
|
964
|
+
} catch {
|
|
965
|
+
return m[1].trim();
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/opencode.mjs
|
|
970
|
+
var OPENCODE_TOOL_ALIASES = {
|
|
971
|
+
websearch: "web_search",
|
|
972
|
+
webfetch: "web_fetch",
|
|
973
|
+
question: "ask_user_question",
|
|
974
|
+
todowrite: "todo_write",
|
|
975
|
+
task: "subagent"
|
|
976
|
+
};
|
|
977
|
+
var DSH_TO_OPENCODE = Object.fromEntries(
|
|
978
|
+
Object.entries(OPENCODE_TOOL_ALIASES).map(([local, dsh]) => [dsh, local])
|
|
979
|
+
);
|
|
980
|
+
|
|
981
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/trae.mjs
|
|
982
|
+
var MESSAGE_TEXT_KEYS = ["content", "text", "message", "body", "prompt", "response", "output", "result"];
|
|
983
|
+
var SESSION_MESSAGE_KEYS = ["messages", "chatMessages", "history", "messageList", "entries"];
|
|
984
|
+
var SESSION_ID_KEYS = ["sessionId", "id", "uuid", "session_id"];
|
|
985
|
+
var SESSION_TITLE_KEYS = ["title", "name", "topic", "summary"];
|
|
986
|
+
var SESSION_DIRECTORY_KEYS = ["cwd", "directory", "workspacePath", "workspace", "projectPath"];
|
|
987
|
+
var SESSION_TIME_KEYS = ["createdAt", "created_at", "createTime", "created", "startTime", "timestamp"];
|
|
988
|
+
function stringValue(value) {
|
|
989
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
990
|
+
}
|
|
991
|
+
function firstString2(object, keys) {
|
|
992
|
+
if (!object || typeof object !== "object") return "";
|
|
993
|
+
for (const key of keys) {
|
|
994
|
+
const value = stringValue(object[key]);
|
|
995
|
+
if (value) return value;
|
|
996
|
+
}
|
|
997
|
+
return "";
|
|
998
|
+
}
|
|
999
|
+
function firstPresent(object, keys) {
|
|
1000
|
+
if (!object || typeof object !== "object") return void 0;
|
|
1001
|
+
for (const key of keys) {
|
|
1002
|
+
const value = object[key];
|
|
1003
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1004
|
+
const text = stringValue(value);
|
|
1005
|
+
if (text) return text;
|
|
1006
|
+
}
|
|
1007
|
+
return void 0;
|
|
1008
|
+
}
|
|
1009
|
+
function valuesOf(value) {
|
|
1010
|
+
if (Array.isArray(value)) return value;
|
|
1011
|
+
if (value && typeof value === "object") return Object.values(value);
|
|
1012
|
+
return [];
|
|
1013
|
+
}
|
|
1014
|
+
function textFromValue(value, depth = 0) {
|
|
1015
|
+
if (depth > 4 || value === null || value === void 0) return "";
|
|
1016
|
+
const scalar = stringValue(value);
|
|
1017
|
+
if (scalar) return scalar;
|
|
1018
|
+
if (Array.isArray(value)) {
|
|
1019
|
+
return value.map((item) => textFromValue(item, depth + 1)).filter(Boolean).join("\n").trim();
|
|
1020
|
+
}
|
|
1021
|
+
if (typeof value !== "object") return "";
|
|
1022
|
+
if (value.type === "text" || value.type === "output" || value.type === "message") {
|
|
1023
|
+
const typed = textFromValue(value.text ?? value.content ?? value.value, depth + 1);
|
|
1024
|
+
if (typed) return typed;
|
|
1025
|
+
}
|
|
1026
|
+
for (const key of MESSAGE_TEXT_KEYS) {
|
|
1027
|
+
const text = textFromValue(value[key], depth + 1);
|
|
1028
|
+
if (text) return text;
|
|
1029
|
+
}
|
|
1030
|
+
return textFromValue(value.parts, depth + 1);
|
|
1031
|
+
}
|
|
1032
|
+
function formatPlanValue(value) {
|
|
1033
|
+
const text = textFromValue(value);
|
|
1034
|
+
if (text) return text;
|
|
1035
|
+
if (value && typeof value === "object") {
|
|
1036
|
+
try {
|
|
1037
|
+
return JSON.stringify(value);
|
|
1038
|
+
} catch {
|
|
1039
|
+
return "";
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return value === void 0 || value === null ? "" : String(value);
|
|
1043
|
+
}
|
|
1044
|
+
function planItemText(item) {
|
|
1045
|
+
if (!item || typeof item !== "object") return "";
|
|
1046
|
+
const lines = [];
|
|
1047
|
+
const thought = formatPlanValue(item.thought);
|
|
1048
|
+
const toolName = stringValue(item.toolName || item.tool || item.name);
|
|
1049
|
+
const params = formatPlanValue(item.params ?? item.arguments ?? item.input);
|
|
1050
|
+
const result = formatPlanValue(item.result ?? item.finish);
|
|
1051
|
+
const content = formatPlanValue(item.content ?? item.text);
|
|
1052
|
+
if (thought) lines.push("[thought] " + thought);
|
|
1053
|
+
if (toolName) lines.push("[tool] " + toolName);
|
|
1054
|
+
if (params) lines.push("[arguments] " + params);
|
|
1055
|
+
if (result) lines.push("[result] " + result);
|
|
1056
|
+
if (!thought && !toolName && !params && !result && content) lines.push(content);
|
|
1057
|
+
return lines.join("\n").trim();
|
|
1058
|
+
}
|
|
1059
|
+
function agentPlanText(message) {
|
|
1060
|
+
const sources = [message && message.agentTaskContent, message && message.content];
|
|
1061
|
+
for (const source of sources) {
|
|
1062
|
+
const items = source && source.guideline && valuesOf(source.guideline.planItems);
|
|
1063
|
+
const text = items ? items.map(planItemText).filter(Boolean).join("\n\n").trim() : "";
|
|
1064
|
+
if (text) return text;
|
|
1065
|
+
}
|
|
1066
|
+
return "";
|
|
1067
|
+
}
|
|
1068
|
+
function normalizeRole(message) {
|
|
1069
|
+
const raw = firstString2(message, ["role", "type", "sender"]) || firstString2(message && message.author, ["role", "type"]);
|
|
1070
|
+
const role = raw.toLowerCase();
|
|
1071
|
+
if (role === "user" || role === "human" || role === "human_message") return "user";
|
|
1072
|
+
if (role === "assistant" || role === "ai" || role === "bot" || role === "agent" || role === "model") return "assistant";
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
function messageText(message) {
|
|
1076
|
+
const direct = textFromValue(message && message.content) || textFromValue(message && message.text) || textFromValue(message && message.message) || textFromValue(message && message.parts) || textFromValue(message && message.body) || textFromValue(message && message.prompt) || textFromValue(message && message.response) || textFromValue(message && message.output);
|
|
1077
|
+
return direct || agentPlanText(message);
|
|
1078
|
+
}
|
|
1079
|
+
function extractTraeSessions(value) {
|
|
1080
|
+
if (Array.isArray(value)) return value;
|
|
1081
|
+
if (!value || typeof value !== "object") return [];
|
|
1082
|
+
for (const key of ["list", "sessions", "conversations", "entries", "items", "data"]) {
|
|
1083
|
+
const entries = valuesOf(value[key]);
|
|
1084
|
+
if (entries.length > 0) return entries;
|
|
1085
|
+
}
|
|
1086
|
+
return Object.values(value).filter((item) => item && typeof item === "object");
|
|
1087
|
+
}
|
|
1088
|
+
function normalizeTraeSession(session, index = 0) {
|
|
1089
|
+
if (!session || typeof session !== "object") return null;
|
|
1090
|
+
const id = firstString2(session, SESSION_ID_KEYS);
|
|
1091
|
+
if (!id) return null;
|
|
1092
|
+
const messagesValue = SESSION_MESSAGE_KEYS.map((key) => session[key]).find((value) => valuesOf(value).length > 0);
|
|
1093
|
+
const messages = valuesOf(messagesValue).map((message, messageIndex) => {
|
|
1094
|
+
if (!message || typeof message !== "object") return null;
|
|
1095
|
+
const role = normalizeRole(message);
|
|
1096
|
+
if (!role) return null;
|
|
1097
|
+
const text = messageText(message);
|
|
1098
|
+
if (!text) return null;
|
|
1099
|
+
const messageId = firstString2(message, ["id", "messageId", "uuid"]) || id + "-message-" + messageIndex;
|
|
1100
|
+
const createdAt = firstPresent(message, ["createdAt", "created_at", "timestamp", "time"]);
|
|
1101
|
+
const model = firstString2(message, ["model", "modelId", "modelID", "modelName"]) || void 0;
|
|
1102
|
+
return { id: messageId, role, createdAt, model, parts: [{ type: "text", text }] };
|
|
1103
|
+
}).filter(Boolean);
|
|
1104
|
+
const normalized = {
|
|
1105
|
+
id,
|
|
1106
|
+
title: firstString2(session, SESSION_TITLE_KEYS) || void 0,
|
|
1107
|
+
directory: firstString2(session, SESSION_DIRECTORY_KEYS) || void 0,
|
|
1108
|
+
createdAt: firstPresent(session, SESSION_TIME_KEYS),
|
|
1109
|
+
model: typeof session.model === "object" ? session.model : firstString2(session, ["model", "modelId", "modelID"]) || void 0,
|
|
1110
|
+
messages
|
|
1111
|
+
};
|
|
1112
|
+
if (!normalized.id) normalized.id = "trae-session-" + index;
|
|
1113
|
+
return normalized;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/hermes.mjs
|
|
1117
|
+
function parseHermesTime(value) {
|
|
1118
|
+
return parseTimeMs(value, { truncSeconds: true }) ?? void 0;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/continue.mjs
|
|
1122
|
+
function indexTime(v) {
|
|
1123
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1124
|
+
if (typeof v === "string") {
|
|
1125
|
+
const t = v.trim();
|
|
1126
|
+
if (/^\d+$/.test(t)) {
|
|
1127
|
+
const n = Number(t);
|
|
1128
|
+
if (Number.isFinite(n)) return n;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return parseTime(v);
|
|
1132
|
+
}
|
|
1133
|
+
function readContinueIndex(raw) {
|
|
1134
|
+
let list;
|
|
1135
|
+
try {
|
|
1136
|
+
list = JSON.parse(raw);
|
|
1137
|
+
} catch {
|
|
1138
|
+
return /* @__PURE__ */ new Map();
|
|
1139
|
+
}
|
|
1140
|
+
const out = /* @__PURE__ */ new Map();
|
|
1141
|
+
if (!Array.isArray(list)) return out;
|
|
1142
|
+
for (const rec of list) {
|
|
1143
|
+
if (!rec || typeof rec !== "object") continue;
|
|
1144
|
+
const id = typeof rec.sessionId === "string" && rec.sessionId ? rec.sessionId : null;
|
|
1145
|
+
if (!id) continue;
|
|
1146
|
+
out.set(id, {
|
|
1147
|
+
title: typeof rec.title === "string" ? rec.title : "",
|
|
1148
|
+
createdAt: indexTime(rec.dateCreated),
|
|
1149
|
+
cwd: typeof rec.workspaceDirectory === "string" && rec.workspaceDirectory ? rec.workspaceDirectory : null
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
return out;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/cline.mjs
|
|
1156
|
+
function clineLegacyTaskHistoryPath(globalStorageDir) {
|
|
1157
|
+
const sep = String(globalStorageDir).includes("\\") ? "\\" : "/";
|
|
1158
|
+
return String(globalStorageDir).replace(/[\\/]+$/, "") + sep + "state" + sep + "taskHistory.json";
|
|
1159
|
+
}
|
|
1160
|
+
function clineLegacyUiMessagesPath(globalStorageDir, id) {
|
|
1161
|
+
const sep = String(globalStorageDir).includes("\\") ? "\\" : "/";
|
|
1162
|
+
const base = String(globalStorageDir).replace(/[\\/]+$/, "");
|
|
1163
|
+
return base + sep + "tasks" + sep + id + sep + "ui_messages.json";
|
|
1164
|
+
}
|
|
1165
|
+
function clineLegacyTaskIdFromPath(path) {
|
|
1166
|
+
const value = String(path).replace(/[\\/]+$/, "");
|
|
1167
|
+
const parts = value.split(/[\\/]/);
|
|
1168
|
+
if (parts.length < 2 || parts[parts.length - 1].toLowerCase() !== "api_conversation_history.json") return null;
|
|
1169
|
+
const taskId = parts[parts.length - 2];
|
|
1170
|
+
const tasksIndex = parts.length - 3;
|
|
1171
|
+
return parts[tasksIndex] && parts[tasksIndex].toLowerCase() === "tasks" && taskId ? taskId : null;
|
|
1172
|
+
}
|
|
1173
|
+
function clineLegacyRootFromApiPath(path) {
|
|
1174
|
+
const value = String(path);
|
|
1175
|
+
const marker = value.match(/[\\/]tasks[\\/][^\\/]+[\\/]api_conversation_history\.json$/i);
|
|
1176
|
+
if (!marker) return null;
|
|
1177
|
+
return value.slice(0, marker.index);
|
|
1178
|
+
}
|
|
1179
|
+
function parseClineLegacyTaskHistory(raw) {
|
|
1180
|
+
if (typeof raw !== "string" || !raw.trim()) return [];
|
|
1181
|
+
try {
|
|
1182
|
+
const value = JSON.parse(raw);
|
|
1183
|
+
return Array.isArray(value) ? value.filter((item) => item && typeof item === "object" && typeof item.id === "string" && item.id) : [];
|
|
1184
|
+
} catch {
|
|
1185
|
+
return [];
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
function clineMessagesPath(sessionsDir, id) {
|
|
1189
|
+
const sep = String(sessionsDir).includes("\\") ? "\\" : "/";
|
|
1190
|
+
const base = String(sessionsDir).replace(/[\\/]+$/, "");
|
|
1191
|
+
return base + sep + id + sep + id + ".messages.json";
|
|
1192
|
+
}
|
|
1193
|
+
function readClineManifest(raw) {
|
|
1194
|
+
if (typeof raw !== "string" || !raw) return null;
|
|
1195
|
+
let doc;
|
|
1196
|
+
try {
|
|
1197
|
+
doc = JSON.parse(raw);
|
|
1198
|
+
} catch {
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
if (!doc || typeof doc !== "object") return null;
|
|
1202
|
+
const meta = doc.metadata && typeof doc.metadata === "object" ? doc.metadata : null;
|
|
1203
|
+
const title = meta && typeof meta.title === "string" ? meta.title : "";
|
|
1204
|
+
const cwd = typeof doc.cwd === "string" && doc.cwd ? doc.cwd : typeof doc.workspace_root === "string" && doc.workspace_root ? doc.workspace_root : null;
|
|
1205
|
+
const startedAt = typeof doc.started_at === "string" && doc.started_at ? doc.started_at : null;
|
|
1206
|
+
return { title, cwd, startedAt };
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/goose.mjs
|
|
1210
|
+
function gooseDataDir(home, env = process.env, platform = process.platform) {
|
|
1211
|
+
const root = env.GOOSE_PATH_ROOT;
|
|
1212
|
+
if (root && isAbsoluteLike(root)) return joinForPlatform(platform, String(root), "data");
|
|
1213
|
+
if (platform === "win32" && env.APPDATA) return joinForPlatform(platform, String(env.APPDATA), "Block", "goose", "data");
|
|
1214
|
+
if (platform === "darwin") return joinForPlatform(platform, String(home), "Library", "Application Support", "Block", "goose");
|
|
1215
|
+
return joinForPlatform(platform, String(home), ".local", "share", "goose");
|
|
1216
|
+
}
|
|
1217
|
+
function gooseSessionsDir(home, env = process.env, platform = process.platform) {
|
|
1218
|
+
return joinForPlatform(platform, gooseDataDir(home, env, platform), "sessions");
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/zed.mjs
|
|
1222
|
+
function zedDataDir(home, env = process.env, platform = process.platform) {
|
|
1223
|
+
if (platform === "win32" && env.LOCALAPPDATA) return joinForPlatform(platform, String(env.LOCALAPPDATA), "Zed");
|
|
1224
|
+
if (platform === "darwin") return joinForPlatform(platform, String(home), "Library", "Application Support", "Zed");
|
|
1225
|
+
const xdg = env.XDG_DATA_HOME;
|
|
1226
|
+
if (xdg && /^([a-zA-Z]:[\\/]|[\\/])/.test(String(xdg))) return joinForPlatform(platform, String(xdg), "zed");
|
|
1227
|
+
return joinForPlatform(platform, String(home), ".local", "share", "zed");
|
|
1228
|
+
}
|
|
1229
|
+
function zedThreadsDir(home, env = process.env, platform = process.platform) {
|
|
1230
|
+
return joinForPlatform(platform, zedDataDir(home, env, platform), "threads");
|
|
1231
|
+
}
|
|
1232
|
+
function zedFolderPaths(folderPaths, folderPathsOrder) {
|
|
1233
|
+
const paths = typeof folderPaths === "string" && folderPaths ? folderPaths.split("\n").filter((p) => p) : [];
|
|
1234
|
+
if (paths.length <= 1) return paths;
|
|
1235
|
+
const order = typeof folderPathsOrder === "string" && folderPathsOrder ? folderPathsOrder.split(",").map((n) => Number.parseInt(n, 10)) : [];
|
|
1236
|
+
if (order.length !== paths.length || order.some((i) => !Number.isInteger(i) || i < 0 || i >= paths.length)) {
|
|
1237
|
+
return paths;
|
|
1238
|
+
}
|
|
1239
|
+
return order.map((i) => paths[i]);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/crush.mjs
|
|
1243
|
+
function crushUserDataDir(home, env = process.env, platform = process.platform) {
|
|
1244
|
+
const override = env.CRUSH_GLOBAL_DATA;
|
|
1245
|
+
if (override && isAbsoluteLike(override)) return String(override);
|
|
1246
|
+
const xdg = env.XDG_DATA_HOME;
|
|
1247
|
+
if (platform === "win32" && env.LOCALAPPDATA) return joinForPlatform(platform, String(env.LOCALAPPDATA), "crush");
|
|
1248
|
+
if (xdg && isAbsoluteLike(xdg)) return joinForPlatform(platform, String(xdg), "crush");
|
|
1249
|
+
return joinForPlatform(platform, String(home), ".local", "share", "crush");
|
|
1250
|
+
}
|
|
1251
|
+
function crushProjectDbPath(projectDir, platform = process.platform) {
|
|
1252
|
+
return joinForPlatform(platform, String(projectDir), ".crush", "crush.db");
|
|
1253
|
+
}
|
|
1254
|
+
function parseCrushProjects(raw) {
|
|
1255
|
+
if (typeof raw !== "string" || !raw.trim()) return [];
|
|
1256
|
+
let doc;
|
|
1257
|
+
try {
|
|
1258
|
+
doc = JSON.parse(raw);
|
|
1259
|
+
} catch {
|
|
1260
|
+
return [];
|
|
1261
|
+
}
|
|
1262
|
+
const list = doc && typeof doc === "object" && Array.isArray(doc.projects) ? doc.projects : [];
|
|
1263
|
+
const out = [];
|
|
1264
|
+
for (const entry of list) {
|
|
1265
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1266
|
+
const path = typeof entry.path === "string" && entry.path ? entry.path : null;
|
|
1267
|
+
if (!path) continue;
|
|
1268
|
+
out.push({
|
|
1269
|
+
path,
|
|
1270
|
+
dataDir: typeof entry.data_dir === "string" && entry.data_dir ? entry.data_dir : null,
|
|
1271
|
+
lastAccessed: typeof entry.last_accessed === "string" ? entry.last_accessed : null
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
return out;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// .codex-tmp/vendor-pagination-upstream/lib/convert/vibe.mjs
|
|
1278
|
+
function parseVibeTime(value) {
|
|
1279
|
+
return parseTimeMs(value, { truncSeconds: true }) ?? void 0;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// .codex-tmp/vendor-pagination-upstream/lib/ignore.mjs
|
|
1283
|
+
var IGNORE_VERSION = 1;
|
|
1284
|
+
var IGNORE_REASONS = Object.freeze(["archived", "retracted", "workspace-deleted"]);
|
|
1285
|
+
function emptyIgnores() {
|
|
1286
|
+
return { version: IGNORE_VERSION, sources: {}, workspaces: {} };
|
|
1287
|
+
}
|
|
1288
|
+
var lastIgnoreSnapshot = emptyIgnores();
|
|
1289
|
+
var writeChain = Promise.resolve();
|
|
1290
|
+
|
|
1291
|
+
// .codex-tmp/vendor-pagination-upstream/lib/host-session.mjs
|
|
1292
|
+
var SYSTEM_PROMPT_PLUGIN = "@deepseek-ai/dsh-system-prompt";
|
|
1293
|
+
var RENAMED_PRODUCERS = {
|
|
1294
|
+
compact: "compact-checkpoint",
|
|
1295
|
+
"tools-code-mode": "ptc-mode",
|
|
1296
|
+
"tools-ptc": "ptc-mode",
|
|
1297
|
+
"dsh-compaction-basic": "compact-basic",
|
|
1298
|
+
[SYSTEM_PROMPT_PLUGIN]: "runtime-context"
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
// .codex-tmp/vendor-pagination-upstream/lib/imports.mjs
|
|
1302
|
+
var writeChain2 = Promise.resolve();
|
|
1303
|
+
|
|
1304
|
+
// vendor/chat-import-reader/conversation-content.mjs
|
|
1305
|
+
var READ_CONTENT = Symbol("readConversation");
|
|
1306
|
+
|
|
1307
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/codex.mjs
|
|
1308
|
+
function codexThreadIdFromName(name) {
|
|
1309
|
+
const m = String(name).match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/);
|
|
1310
|
+
return m ? m[0] : void 0;
|
|
1311
|
+
}
|
|
1312
|
+
function codexNameTimestamp(name) {
|
|
1313
|
+
const m = String(name).match(/rollout-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})-/);
|
|
1314
|
+
return m ? m[1] : null;
|
|
1315
|
+
}
|
|
1316
|
+
function pageCmp(a, b, mtimeOf) {
|
|
1317
|
+
const ta = a.nameTs || "";
|
|
1318
|
+
const tb = b.nameTs || "";
|
|
1319
|
+
if (ta !== tb) return ta < tb ? -1 : 1;
|
|
1320
|
+
const ma = mtimeOf(a) ?? 0;
|
|
1321
|
+
const mb = mtimeOf(b) ?? 0;
|
|
1322
|
+
if (ma !== mb) return ma - mb;
|
|
1323
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
1324
|
+
}
|
|
1325
|
+
function sortCodexPages(pages, mtimeOf = () => null) {
|
|
1326
|
+
return [...pages].sort((a, b) => pageCmp(a, b, mtimeOf));
|
|
1327
|
+
}
|
|
1328
|
+
function groupCodexThreads(files) {
|
|
1329
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1330
|
+
for (const file of files) {
|
|
1331
|
+
const name = String(file.name ?? "");
|
|
1332
|
+
const threadId = codexThreadIdFromName(name) ?? "file:" + String(file.path).replace(/\\/g, "/");
|
|
1333
|
+
if (!groups.has(threadId)) groups.set(threadId, []);
|
|
1334
|
+
groups.get(threadId).push({ path: String(file.path), name, nameTs: codexNameTimestamp(name) });
|
|
1335
|
+
}
|
|
1336
|
+
for (const pages of groups.values()) {
|
|
1337
|
+
pages.sort((a, b) => pageCmp(a, b, () => null));
|
|
1338
|
+
}
|
|
1339
|
+
return groups;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/jsonl.mjs
|
|
1343
|
+
async function scanCodex(host2, target, { bm, emit }) {
|
|
1344
|
+
const files = [];
|
|
1345
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
1346
|
+
const pageOf = /* @__PURE__ */ new Map();
|
|
1347
|
+
const accepted = [];
|
|
1348
|
+
for (const file of files) {
|
|
1349
|
+
const st = await host2.stat(file.path);
|
|
1350
|
+
if (!st) continue;
|
|
1351
|
+
const summaries = await probeSource(bm, "codex", file.path, fileFingerprint(st), async () => {
|
|
1352
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
1353
|
+
if (head === null || head === "") return [];
|
|
1354
|
+
const recs = parseJsonlHead(head);
|
|
1355
|
+
const meta = recs.find((r) => r && r.type === "session_meta" && r.payload && typeof r.payload === "object");
|
|
1356
|
+
if (!meta) return [];
|
|
1357
|
+
const payload = meta.payload;
|
|
1358
|
+
if (codexSubagentMarker(payload)) return [];
|
|
1359
|
+
const tail = typeof host2.readTail === "function" ? await host2.readTail(file.path, TAIL_MAX_BYTES) : null;
|
|
1360
|
+
const times = [...recs, ...parseJsonlHead(tail)].map((r) => parseTimeValue(r?.timestamp)).filter(Number.isFinite);
|
|
1361
|
+
const createdAt = parseTimeValue(meta.timestamp) ?? parseTimeValue(payload.timestamp) ?? null;
|
|
1362
|
+
return [{
|
|
1363
|
+
id: typeof payload.id === "string" && payload.id ? payload.id : null,
|
|
1364
|
+
cwd: typeof payload.cwd === "string" && payload.cwd ? payload.cwd : null,
|
|
1365
|
+
createdAt,
|
|
1366
|
+
lastActiveAt: times.length ? Math.max(...times) : createdAt,
|
|
1367
|
+
title: firstUserTitle(recs, codexUserText)
|
|
1368
|
+
}];
|
|
1369
|
+
});
|
|
1370
|
+
if (summaries.length === 0) continue;
|
|
1371
|
+
pageOf.set(file.path, { st, summary: summaries[0] });
|
|
1372
|
+
accepted.push(file);
|
|
1373
|
+
}
|
|
1374
|
+
const out = [];
|
|
1375
|
+
const titleIndexes = /* @__PURE__ */ new Map();
|
|
1376
|
+
for (const [threadKey, grouped] of groupCodexThreads(accepted)) {
|
|
1377
|
+
const pages = sortCodexPages(grouped, (p) => pageOf.get(p.path).st.mtimeMs ?? null);
|
|
1378
|
+
const summaries = pages.map((p) => pageOf.get(p.path).summary);
|
|
1379
|
+
const root = summaries[0];
|
|
1380
|
+
const sessionId = threadKey.startsWith("file:") ? root.id : threadKey;
|
|
1381
|
+
if (!sessionId) continue;
|
|
1382
|
+
const mtimeMax = Math.max(0, ...pages.map((p) => pageOf.get(p.path).st.mtimeMs ?? 0));
|
|
1383
|
+
const activityTimes = summaries.map((s) => s.lastActiveAt).filter(Number.isFinite);
|
|
1384
|
+
const home = pages[0].path.match(/^(.*[\/\\])(?:sessions|archived_sessions)[\/\\]/);
|
|
1385
|
+
const indexPath = home ? home[1] + "session_index.jsonl" : siblingPath(target, "session_index.jsonl");
|
|
1386
|
+
if (!titleIndexes.has(indexPath)) titleIndexes.set(indexPath, await readCodexTitleIndex(host2, indexPath));
|
|
1387
|
+
const titles = titleIndexes.get(indexPath);
|
|
1388
|
+
const indexedTitle = titles.get(sessionId);
|
|
1389
|
+
const entries = [makeEntry({
|
|
1390
|
+
format: "codex",
|
|
1391
|
+
sessionId,
|
|
1392
|
+
title: indexedTitle || root.title || summaries[summaries.length - 1].title,
|
|
1393
|
+
project: projectFromRecord(root.cwd, () => codexLayoutProject(pages[0].path)),
|
|
1394
|
+
createdAt: summaries.map((x) => x.createdAt).find((v) => v !== null && v !== void 0),
|
|
1395
|
+
lastActiveAt: activityTimes.length ? Math.max(...activityTimes) : mtimeMax || void 0,
|
|
1396
|
+
sourcePath: pages[0].path,
|
|
1397
|
+
cwd: root.cwd
|
|
1398
|
+
})];
|
|
1399
|
+
out.push(...entries);
|
|
1400
|
+
await emitEach(emit, entries);
|
|
1401
|
+
}
|
|
1402
|
+
return out;
|
|
1403
|
+
}
|
|
1404
|
+
async function readCodexTitleIndex(host2, path) {
|
|
1405
|
+
const titles = /* @__PURE__ */ new Map();
|
|
1406
|
+
const stat2 = await host2.stat(path);
|
|
1407
|
+
if (!stat2 || stat2.type !== "file") return titles;
|
|
1408
|
+
const lines = typeof host2.readLines === "function" ? host2.readLines(path) : (await host2.readText(path) || "").split(/\r?\n/);
|
|
1409
|
+
for await (const line of lines) {
|
|
1410
|
+
const row = parseJsonlHead(line)[0];
|
|
1411
|
+
if (typeof row?.id !== "string" || typeof row?.thread_name !== "string") continue;
|
|
1412
|
+
const title = row.thread_name.trim();
|
|
1413
|
+
if (title) titles.set(row.id, title);
|
|
1414
|
+
}
|
|
1415
|
+
return titles;
|
|
1416
|
+
}
|
|
1417
|
+
function codexUserText(r) {
|
|
1418
|
+
if (!r || r.type !== "response_item" || !r.payload || r.payload.type !== "message" || r.payload.role !== "user") return "";
|
|
1419
|
+
const content = r.payload.content;
|
|
1420
|
+
return codexUserPrompt(Array.isArray(content) ? content : [{ type: "input_text", text: contentText2(content) }]);
|
|
1421
|
+
}
|
|
1422
|
+
async function scanCursor(host2, target, { bm, emit }) {
|
|
1423
|
+
const files = [];
|
|
1424
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
1425
|
+
const out = [];
|
|
1426
|
+
for (const file of files) {
|
|
1427
|
+
if (!/agent-transcripts/i.test(file.path)) continue;
|
|
1428
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
1429
|
+
if (stem !== basenameOf(dirnameOf(file.path))) continue;
|
|
1430
|
+
const st = await host2.stat(file.path);
|
|
1431
|
+
if (!st) continue;
|
|
1432
|
+
const fp = fileFingerprint(st);
|
|
1433
|
+
const entries = await probeSource(bm, "cursor", file.path, fp, async () => {
|
|
1434
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
1435
|
+
if (head === null || head === "") return [];
|
|
1436
|
+
const recs = parseJsonlHead(head);
|
|
1437
|
+
const extractUser = (r) => r && r.role === "user" ? String(contentText2(r.message && r.message.content)).replace(/<\/?user_query>/g, "") : "";
|
|
1438
|
+
const rawFirst = firstUserRawText(recs, extractUser);
|
|
1439
|
+
const tsFromTitle = rawFirst ? parseCursorEmbeddedTimestamp(rawFirst) : void 0;
|
|
1440
|
+
const title = rawFirst ? normalizeTitle(stripCursorTitleDecorations(rawFirst)) : null;
|
|
1441
|
+
const slug = cursorLayoutProject(file.path);
|
|
1442
|
+
const cwd = host2.resolveCursorSlug && slug ? await host2.resolveCursorSlug(slug) : null;
|
|
1443
|
+
const createdAt = tsFromTitle ?? null;
|
|
1444
|
+
const lastActiveAt = typeof st.mtimeMs === "number" ? st.mtimeMs : tsFromTitle ?? null;
|
|
1445
|
+
return [makeEntry({
|
|
1446
|
+
format: "cursor",
|
|
1447
|
+
sessionId: stem,
|
|
1448
|
+
title,
|
|
1449
|
+
project: projectFromRecord(cwd, () => null),
|
|
1450
|
+
createdAt,
|
|
1451
|
+
lastActiveAt,
|
|
1452
|
+
sourcePath: file.path,
|
|
1453
|
+
cwd
|
|
1454
|
+
})];
|
|
1455
|
+
}, (hit) => patchCursorCacheEntries(host2, hit, file.path, fp));
|
|
1456
|
+
out.push(...entries);
|
|
1457
|
+
await emitEach(emit, entries);
|
|
1458
|
+
}
|
|
1459
|
+
return out;
|
|
1460
|
+
}
|
|
1461
|
+
async function patchCursorCacheEntries(host2, entries, sourcePath, fp) {
|
|
1462
|
+
if (!Array.isArray(entries) || entries.length === 0) return { entries, changed: false };
|
|
1463
|
+
const slug = cursorLayoutProject(sourcePath);
|
|
1464
|
+
let changed = false;
|
|
1465
|
+
const out = [];
|
|
1466
|
+
for (const entry of entries) {
|
|
1467
|
+
if (!entry || entry.format !== "cursor") {
|
|
1468
|
+
out.push(entry);
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
const next = { ...entry };
|
|
1472
|
+
const rawTitle = typeof entry.title === "string" ? entry.title : "";
|
|
1473
|
+
if (isCursorNonRepoSlug(slug)) {
|
|
1474
|
+
if (next.cwd !== null) {
|
|
1475
|
+
next.cwd = null;
|
|
1476
|
+
changed = true;
|
|
1477
|
+
}
|
|
1478
|
+
if (next.project !== null) {
|
|
1479
|
+
next.project = null;
|
|
1480
|
+
changed = true;
|
|
1481
|
+
}
|
|
1482
|
+
} else if (host2.resolveCursorSlug) {
|
|
1483
|
+
const cwd = await host2.resolveCursorSlug(slug);
|
|
1484
|
+
const project = projectFromRecord(cwd, () => null);
|
|
1485
|
+
if (next.cwd !== cwd) {
|
|
1486
|
+
next.cwd = cwd;
|
|
1487
|
+
changed = true;
|
|
1488
|
+
}
|
|
1489
|
+
if (next.project !== project) {
|
|
1490
|
+
next.project = project;
|
|
1491
|
+
changed = true;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
if (rawTitle.includes("<timestamp>") || rawTitle.includes("<user_query>")) {
|
|
1495
|
+
const cleaned = normalizeTitle(stripCursorTitleDecorations(rawTitle));
|
|
1496
|
+
const title = cleaned || null;
|
|
1497
|
+
if (next.title !== title) {
|
|
1498
|
+
next.title = title;
|
|
1499
|
+
changed = true;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (next.createdAt === null) {
|
|
1503
|
+
const ts = parseCursorEmbeddedTimestamp(rawTitle);
|
|
1504
|
+
if (typeof ts === "number" && Number.isFinite(ts)) {
|
|
1505
|
+
next.createdAt = ts;
|
|
1506
|
+
changed = true;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
if (next.lastActiveAt === null) {
|
|
1510
|
+
const la = typeof fp.mtimeMs === "number" ? fp.mtimeMs : next.createdAt ?? null;
|
|
1511
|
+
if (la !== null) {
|
|
1512
|
+
next.lastActiveAt = la;
|
|
1513
|
+
changed = true;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
out.push(next);
|
|
1517
|
+
}
|
|
1518
|
+
return { entries: out, changed };
|
|
1519
|
+
}
|
|
1520
|
+
function isReasonixSidecar(name) {
|
|
1521
|
+
return /\.(events|conflicts|guardian)\.jsonl$/i.test(name);
|
|
1522
|
+
}
|
|
1523
|
+
async function scanReasonix(host2, target, { bm, emit }) {
|
|
1524
|
+
const files = [];
|
|
1525
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name) && !isReasonixSidecar(name));
|
|
1526
|
+
const out = [];
|
|
1527
|
+
const titleCache = /* @__PURE__ */ new Map();
|
|
1528
|
+
for (const file of files) {
|
|
1529
|
+
const stem = basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
1530
|
+
const desktop = /projects[\\/][^\\/]+[\\/]sessions/i.test(String(file.path));
|
|
1531
|
+
if (!desktop && !/^desktop-/.test(stem)) continue;
|
|
1532
|
+
const st = await host2.stat(file.path);
|
|
1533
|
+
if (!st) continue;
|
|
1534
|
+
const fp = fileFingerprint(st);
|
|
1535
|
+
const entries = await probeSource(bm, "reasonix", file.path, fp, async () => {
|
|
1536
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
1537
|
+
if (head === null || head === "") return [];
|
|
1538
|
+
const recs = parseJsonlHead(head);
|
|
1539
|
+
if (!recs.some((r) => r && typeof r === "object" && r.role === "user")) return [];
|
|
1540
|
+
let explicit = "";
|
|
1541
|
+
if (desktop) {
|
|
1542
|
+
const titlesPath = siblingPath(file.path, ".titles.json");
|
|
1543
|
+
let titles = titleCache.get(titlesPath);
|
|
1544
|
+
if (titles === void 0) {
|
|
1545
|
+
try {
|
|
1546
|
+
titles = JSON.parse(await host2.readText(titlesPath) || "{}");
|
|
1547
|
+
} catch {
|
|
1548
|
+
titles = {};
|
|
1549
|
+
}
|
|
1550
|
+
titleCache.set(titlesPath, titles);
|
|
1551
|
+
}
|
|
1552
|
+
if (titles && typeof titles[stem] === "string" && titles[stem].trim()) explicit = titles[stem].trim();
|
|
1553
|
+
}
|
|
1554
|
+
const title = normalizeTitle(explicit) || firstUserTitle(recs, (r) => r && r.role === "user" && typeof r.content === "string" ? r.content : "");
|
|
1555
|
+
const createdAt = firstNumber(recs, (r) => r && typeof r.createdAt === "number" ? r.createdAt : void 0);
|
|
1556
|
+
return [makeEntry({
|
|
1557
|
+
format: "reasonix",
|
|
1558
|
+
sessionId: stem,
|
|
1559
|
+
title,
|
|
1560
|
+
project: reasonixLayoutProject(file.path),
|
|
1561
|
+
createdAt: createdAt ?? reasonixStemTime(stem),
|
|
1562
|
+
lastActiveAt: st.mtimeMs,
|
|
1563
|
+
sourcePath: file.path
|
|
1564
|
+
})];
|
|
1565
|
+
});
|
|
1566
|
+
out.push(...entries);
|
|
1567
|
+
await emitEach(emit, entries);
|
|
1568
|
+
}
|
|
1569
|
+
return out;
|
|
1570
|
+
}
|
|
1571
|
+
async function scanOpenclaw(host2, target, { bm, emit }) {
|
|
1572
|
+
const files = [];
|
|
1573
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
1574
|
+
const out = [];
|
|
1575
|
+
const nameCache = /* @__PURE__ */ new Map();
|
|
1576
|
+
for (const file of files) {
|
|
1577
|
+
if (!/\bagents\b.*\bsessions\b/i.test(file.path)) continue;
|
|
1578
|
+
const indexPath = siblingPath(file.path, "sessions.json");
|
|
1579
|
+
const st = await host2.stat(file.path);
|
|
1580
|
+
if (!st) continue;
|
|
1581
|
+
const ist = await host2.stat(indexPath);
|
|
1582
|
+
const fp = compositeFingerprint(st, ist);
|
|
1583
|
+
const entries = await probeSource(bm, "openclaw", file.path, fp, async () => {
|
|
1584
|
+
let names = nameCache.get(indexPath);
|
|
1585
|
+
if (names === void 0) {
|
|
1586
|
+
names = openclawDisplayNames(await host2.readText(indexPath));
|
|
1587
|
+
nameCache.set(indexPath, names);
|
|
1588
|
+
}
|
|
1589
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
1590
|
+
if (head === null || head === "") return [];
|
|
1591
|
+
const recs = parseJsonlHead(head);
|
|
1592
|
+
if (!recs.some((r) => r && typeof r === "object" && (r.type === "session" || r.type === "message"))) return [];
|
|
1593
|
+
const sessRec = recs.find((r) => r && r.type === "session");
|
|
1594
|
+
const sessionId = sessRec && typeof sessRec.id === "string" && sessRec.id ? sessRec.id : basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
1595
|
+
const title = names.get(sessionId) || firstUserTitle(recs, (r) => r && r.type === "message" && r.message && r.message.role === "user" ? contentText2(r.message.content) : "");
|
|
1596
|
+
const cwd = sessRec && typeof sessRec.cwd === "string" ? sessRec.cwd : void 0;
|
|
1597
|
+
const createdAt = sessRec ? parseTimeValue(sessRec.timestamp) : void 0;
|
|
1598
|
+
return [makeEntry({
|
|
1599
|
+
format: "openclaw",
|
|
1600
|
+
sessionId,
|
|
1601
|
+
title,
|
|
1602
|
+
project: projectFromRecord(cwd, () => openclawLayoutProject(file.path)),
|
|
1603
|
+
createdAt,
|
|
1604
|
+
lastActiveAt: st.mtimeMs,
|
|
1605
|
+
sourcePath: file.path,
|
|
1606
|
+
cwd
|
|
1607
|
+
})];
|
|
1608
|
+
});
|
|
1609
|
+
out.push(...entries);
|
|
1610
|
+
await emitEach(emit, entries);
|
|
1611
|
+
}
|
|
1612
|
+
return out;
|
|
1613
|
+
}
|
|
1614
|
+
async function scanPi(host2, target, { bm, emit }) {
|
|
1615
|
+
const files = [];
|
|
1616
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
1617
|
+
const out = [];
|
|
1618
|
+
for (const file of files) {
|
|
1619
|
+
const st = await host2.stat(file.path);
|
|
1620
|
+
if (!st) continue;
|
|
1621
|
+
const entries = await probeSource(bm, "pi", file.path, fileFingerprint(st), async () => {
|
|
1622
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
1623
|
+
if (head === null || head === "") return [];
|
|
1624
|
+
const recs = parseJsonlHead(head);
|
|
1625
|
+
const header = recs.find((r) => r && r.type === "session" && typeof r.version === "number");
|
|
1626
|
+
if (!header) return [];
|
|
1627
|
+
const sessionId = typeof header.id === "string" && header.id ? header.id : basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
1628
|
+
let name = "";
|
|
1629
|
+
for (let i = recs.length - 1; i >= 0; i--) {
|
|
1630
|
+
const r = recs[i];
|
|
1631
|
+
if (r && r.type === "session_info" && typeof r.name === "string" && r.name.trim()) {
|
|
1632
|
+
name = r.name.trim();
|
|
1633
|
+
break;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
const title = normalizeTitle(name) || firstUserTitle(recs, (r) => r && r.type === "message" && r.message && r.message.role === "user" ? contentText2(r.message.content) : "");
|
|
1637
|
+
const cwd = typeof header.cwd === "string" ? header.cwd : void 0;
|
|
1638
|
+
return [makeEntry({
|
|
1639
|
+
format: "pi",
|
|
1640
|
+
sessionId,
|
|
1641
|
+
title,
|
|
1642
|
+
project: projectFromRecord(cwd, () => null),
|
|
1643
|
+
createdAt: parseTimeValue(header.timestamp),
|
|
1644
|
+
lastActiveAt: st.mtimeMs,
|
|
1645
|
+
sourcePath: file.path,
|
|
1646
|
+
cwd
|
|
1647
|
+
})];
|
|
1648
|
+
});
|
|
1649
|
+
out.push(...entries);
|
|
1650
|
+
await emitEach(emit, entries);
|
|
1651
|
+
}
|
|
1652
|
+
return out;
|
|
1653
|
+
}
|
|
1654
|
+
function codexLayoutProject(sourcePath) {
|
|
1655
|
+
const m = slashPath(sourcePath).match(/\/sessions\/(\d{4})\/(\d{2})\//);
|
|
1656
|
+
return m ? m[1] + "/" + m[2] : null;
|
|
1657
|
+
}
|
|
1658
|
+
function cursorLayoutProject(sourcePath) {
|
|
1659
|
+
const m = slashPath(sourcePath).match(/\/projects\/([^/]+)\/agent-transcripts\//i);
|
|
1660
|
+
return m ? m[1] : null;
|
|
1661
|
+
}
|
|
1662
|
+
function reasonixLayoutProject(sourcePath) {
|
|
1663
|
+
const m = slashPath(sourcePath).match(/\/projects\/([^/]+)\//i);
|
|
1664
|
+
return m ? m[1] : null;
|
|
1665
|
+
}
|
|
1666
|
+
function openclawLayoutProject(sourcePath) {
|
|
1667
|
+
const m = slashPath(sourcePath).match(/\/agents\/([^/]+)\/sessions\//);
|
|
1668
|
+
return m ? m[1] : null;
|
|
1669
|
+
}
|
|
1670
|
+
var isJsonl2 = (lower) => lower.endsWith(".jsonl");
|
|
1671
|
+
var codexSource = {
|
|
1672
|
+
format: "codex",
|
|
1673
|
+
// sessions/YYYY/MM/DD/ 与扁平的 archived_sessions/ 双根
|
|
1674
|
+
roots: (home) => [join3(home, ".codex", "sessions"), join3(home, ".codex", "archived_sessions")],
|
|
1675
|
+
scan: scanCodex,
|
|
1676
|
+
layoutProject: codexLayoutProject,
|
|
1677
|
+
matchFile: (lower) => isJsonl2(lower) && /(^|[\\/])rollout-/.test(lower),
|
|
1678
|
+
fileFallback: ["jsonl"]
|
|
1679
|
+
};
|
|
1680
|
+
var cursorSource = {
|
|
1681
|
+
format: "cursor",
|
|
1682
|
+
roots: (home) => join3(home, ".cursor", "projects"),
|
|
1683
|
+
scan: scanCursor,
|
|
1684
|
+
layoutProject: cursorLayoutProject,
|
|
1685
|
+
matchFile: (lower) => isJsonl2(lower) && /\bagent-transcripts\b/.test(lower),
|
|
1686
|
+
fileFallback: ["jsonl"]
|
|
1687
|
+
};
|
|
1688
|
+
var reasonixSource = {
|
|
1689
|
+
format: "reasonix",
|
|
1690
|
+
// CLI 会话目录 + 桌面版状态根(Windows APPDATA;无此变量的平台只扫 CLI 根)
|
|
1691
|
+
roots: (home, env) => {
|
|
1692
|
+
const cli = join3(home, ".reasonix", "sessions");
|
|
1693
|
+
return env.APPDATA ? [cli, join3(env.APPDATA, "reasonix")] : cli;
|
|
1694
|
+
},
|
|
1695
|
+
scan: scanReasonix,
|
|
1696
|
+
layoutProject: reasonixLayoutProject,
|
|
1697
|
+
matchFile: (lower) => isJsonl2(lower) && /(^|[\\/])(desktop|subagent)-/.test(lower),
|
|
1698
|
+
fileFallback: ["jsonl"]
|
|
1699
|
+
};
|
|
1700
|
+
var openclawSource = {
|
|
1701
|
+
format: "openclaw",
|
|
1702
|
+
roots: (home) => join3(home, ".openclaw", "agents"),
|
|
1703
|
+
scan: scanOpenclaw,
|
|
1704
|
+
layoutProject: openclawLayoutProject,
|
|
1705
|
+
matchFile: (lower) => isJsonl2(lower) && /\bagents\b.*\bsessions\b/.test(lower),
|
|
1706
|
+
fileFallback: ["jsonl"]
|
|
1707
|
+
};
|
|
1708
|
+
var piSource = {
|
|
1709
|
+
format: "pi",
|
|
1710
|
+
roots: (home) => join3(home, ".pi", "agent", "sessions"),
|
|
1711
|
+
scan: scanPi,
|
|
1712
|
+
// 无路径特征时不进通用 JSONL 回退(会话头签名与 hermes/openclaw 的 session 头相近)
|
|
1713
|
+
matchFile: (lower) => isJsonl2(lower) && /\.pi[\\/]agent[\\/]sessions[\\/]/.test(lower)
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/gemini.mjs
|
|
1717
|
+
import { join as join4 } from "node:path";
|
|
1718
|
+
async function scanGemini(host2, target, { bm, emit }) {
|
|
1719
|
+
const files = [];
|
|
1720
|
+
await walkFiles(host2, target, files, (name) => /^session-.+\.json$/i.test(name));
|
|
1721
|
+
const out = [];
|
|
1722
|
+
for (const file of files) {
|
|
1723
|
+
const st = await host2.stat(file.path);
|
|
1724
|
+
if (!st) continue;
|
|
1725
|
+
const fp = fileFingerprint(st);
|
|
1726
|
+
const entries = await probeSource(bm, "gemini", file.path, fp, async () => {
|
|
1727
|
+
const raw = await host2.readText(file.path);
|
|
1728
|
+
if (raw === null || raw === "") return [];
|
|
1729
|
+
let chat;
|
|
1730
|
+
try {
|
|
1731
|
+
chat = JSON.parse(raw);
|
|
1732
|
+
} catch {
|
|
1733
|
+
return [];
|
|
1734
|
+
}
|
|
1735
|
+
if (!chat || typeof chat !== "object" || !Array.isArray(chat.messages)) return [];
|
|
1736
|
+
const stem = basenameOf(file.name).replace(/\.json$/i, "");
|
|
1737
|
+
const sessionId = typeof chat.sessionId === "string" && chat.sessionId ? chat.sessionId : stem;
|
|
1738
|
+
const title = firstUserTitle(chat.messages, (m) => m && m.type === "user" ? geminiPartsText(m.content) : "");
|
|
1739
|
+
const dir = Array.isArray(chat.directories) && chat.directories.length > 0 ? chat.directories[0] : void 0;
|
|
1740
|
+
return [makeEntry({
|
|
1741
|
+
format: "gemini",
|
|
1742
|
+
sessionId,
|
|
1743
|
+
title,
|
|
1744
|
+
project: projectFromRecord(dir, () => geminiLayoutProject(file.path)),
|
|
1745
|
+
createdAt: parseTimeValue(chat.startTime),
|
|
1746
|
+
lastActiveAt: st.mtimeMs,
|
|
1747
|
+
sourcePath: file.path,
|
|
1748
|
+
cwd: dir
|
|
1749
|
+
})];
|
|
1750
|
+
});
|
|
1751
|
+
out.push(...entries);
|
|
1752
|
+
await emitEach(emit, entries);
|
|
1753
|
+
}
|
|
1754
|
+
return out;
|
|
1755
|
+
}
|
|
1756
|
+
function geminiPartsText(content) {
|
|
1757
|
+
if (!Array.isArray(content)) return "";
|
|
1758
|
+
return content.map((p) => p && typeof p === "object" && typeof p.text === "string" ? p.text : "").join("\n");
|
|
1759
|
+
}
|
|
1760
|
+
async function scanAntigravity(host2, target, { bm, emit }) {
|
|
1761
|
+
const convDir = join4(target, "conversations");
|
|
1762
|
+
const brainDir = join4(target, "brain");
|
|
1763
|
+
const annoDir = join4(target, "annotations");
|
|
1764
|
+
const files = [];
|
|
1765
|
+
await walkFiles(host2, convDir, files, (name) => /\.(db|pb)$/i.test(name));
|
|
1766
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1767
|
+
const out = [];
|
|
1768
|
+
for (const file of files) {
|
|
1769
|
+
const id = basenameOf(file.name).replace(/\.(db|pb)$/i, "");
|
|
1770
|
+
if (!id || seen.has(id)) continue;
|
|
1771
|
+
seen.add(id);
|
|
1772
|
+
const transcriptPath = join4(brainDir, id, ".system_generated", "logs", "transcript.jsonl");
|
|
1773
|
+
const st = await host2.stat(transcriptPath);
|
|
1774
|
+
if (!st) continue;
|
|
1775
|
+
const fp = fileFingerprint(st);
|
|
1776
|
+
const entries = await probeSource(bm, "antigravity", transcriptPath, fp, async () => {
|
|
1777
|
+
const head = await host2.readHead(transcriptPath, HEAD_MAX_BYTES);
|
|
1778
|
+
if (head === null || head === "") return [];
|
|
1779
|
+
const recs = parseJsonlHead(head);
|
|
1780
|
+
if (recs.length === 0) return [];
|
|
1781
|
+
let title = "";
|
|
1782
|
+
const cwdCounts = /* @__PURE__ */ new Map();
|
|
1783
|
+
for (const rec of recs) {
|
|
1784
|
+
if (!rec || typeof rec !== "object") continue;
|
|
1785
|
+
if (!title && rec.type === "USER_INPUT") {
|
|
1786
|
+
title = antigravityPromptTitle(rec.content);
|
|
1787
|
+
}
|
|
1788
|
+
if (Array.isArray(rec.tool_calls)) {
|
|
1789
|
+
for (const tc of rec.tool_calls) {
|
|
1790
|
+
const v = unquote(tc && tc.args && tc.args.Cwd);
|
|
1791
|
+
if (typeof v === "string" && v.startsWith("/")) cwdCounts.set(v, (cwdCounts.get(v) || 0) + 1);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
let cwd = null;
|
|
1796
|
+
let best = 0;
|
|
1797
|
+
for (const [v, n] of cwdCounts) if (n > best) {
|
|
1798
|
+
cwd = v;
|
|
1799
|
+
best = n;
|
|
1800
|
+
}
|
|
1801
|
+
const annoRaw = await host2.readText(join4(annoDir, id + ".pbtxt"));
|
|
1802
|
+
const annoTitle = normalizeTitle(parseAnnotationTitle(annoRaw));
|
|
1803
|
+
if (annoTitle) title = annoTitle;
|
|
1804
|
+
return [makeEntry({
|
|
1805
|
+
format: "antigravity",
|
|
1806
|
+
sessionId: id,
|
|
1807
|
+
title,
|
|
1808
|
+
project: antigravityLayoutProject(transcriptPath),
|
|
1809
|
+
createdAt: parseTimeValue(recs[0] && recs[0].created_at),
|
|
1810
|
+
lastActiveAt: st.mtimeMs,
|
|
1811
|
+
sourcePath: transcriptPath,
|
|
1812
|
+
cwd
|
|
1813
|
+
})];
|
|
1814
|
+
});
|
|
1815
|
+
out.push(...entries);
|
|
1816
|
+
await emitEach(emit, entries);
|
|
1817
|
+
}
|
|
1818
|
+
return out;
|
|
1819
|
+
}
|
|
1820
|
+
function antigravityPromptTitle(content) {
|
|
1821
|
+
return normalizeTitle(unwrapUserRequest(content));
|
|
1822
|
+
}
|
|
1823
|
+
function geminiLayoutProject(sourcePath) {
|
|
1824
|
+
const m = slashPath(sourcePath).match(/\/history\/([^/]+)\/chats\//);
|
|
1825
|
+
return m ? m[1] : null;
|
|
1826
|
+
}
|
|
1827
|
+
function antigravityLayoutProject(sourcePath) {
|
|
1828
|
+
return /\/brain\/[^/]+\//.test(slashPath(sourcePath)) ? "antigravity" : null;
|
|
1829
|
+
}
|
|
1830
|
+
var geminiSource = {
|
|
1831
|
+
format: "gemini",
|
|
1832
|
+
roots: (home) => join4(home, ".gemini", "history"),
|
|
1833
|
+
scan: scanGemini,
|
|
1834
|
+
layoutProject: geminiLayoutProject,
|
|
1835
|
+
fileFallback: ["json"]
|
|
1836
|
+
};
|
|
1837
|
+
var antigravitySource = {
|
|
1838
|
+
format: "antigravity",
|
|
1839
|
+
// 根随产品版本分化(2.0 / 部分 IDE 用 antigravity、旧 CLI 用 antigravity-cli、另一些 IDE
|
|
1840
|
+
// 发行用 antigravity-ide),内层布局相同,三根并列扫——缺失的根由 walkFiles 静默落空。
|
|
1841
|
+
roots: (home) => [
|
|
1842
|
+
join4(home, ".gemini", "antigravity"),
|
|
1843
|
+
join4(home, ".gemini", "antigravity-cli"),
|
|
1844
|
+
join4(home, ".gemini", "antigravity-ide")
|
|
1845
|
+
],
|
|
1846
|
+
scan: scanAntigravity,
|
|
1847
|
+
layoutProject: antigravityLayoutProject
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/trae.mjs
|
|
1851
|
+
import { join as join5 } from "node:path";
|
|
1852
|
+
import { TextDecoder } from "node:util";
|
|
1853
|
+
|
|
1854
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/sqlite.mjs
|
|
1855
|
+
var DatabaseSync = null;
|
|
1856
|
+
function loadDatabaseSync() {
|
|
1857
|
+
if (DatabaseSync) return DatabaseSync;
|
|
1858
|
+
const mod = process.getBuiltinModule("node:sqlite");
|
|
1859
|
+
if (!mod || typeof mod.DatabaseSync !== "function") {
|
|
1860
|
+
const err2 = new Error("node:sqlite \u4E0D\u53EF\u7528\uFF08\u9700\u8981 Node >= 22.13 \u7684\u5B8C\u6574\u6784\u5EFA\uFF09\uFF0CSQLite \u6765\u6E90\u65E0\u6CD5\u8BFB\u53D6");
|
|
1861
|
+
err2.code = "DSH_SQLITE_UNAVAILABLE";
|
|
1862
|
+
throw err2;
|
|
1863
|
+
}
|
|
1864
|
+
DatabaseSync = mod.DatabaseSync;
|
|
1865
|
+
return DatabaseSync;
|
|
1866
|
+
}
|
|
1867
|
+
function openReadOnly(dbPath) {
|
|
1868
|
+
return new (loadDatabaseSync())(dbPath, { readOnly: true });
|
|
1869
|
+
}
|
|
1870
|
+
function closeQuietly(db) {
|
|
1871
|
+
if (!db) return;
|
|
1872
|
+
try {
|
|
1873
|
+
db.close();
|
|
1874
|
+
} catch {
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
function withReadOnlyDb(dbPath, fn) {
|
|
1878
|
+
const db = openReadOnly(dbPath);
|
|
1879
|
+
try {
|
|
1880
|
+
return fn(db);
|
|
1881
|
+
} finally {
|
|
1882
|
+
closeQuietly(db);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
function readOptionalDb(dbPath, probe, read = (_db, sig) => sig) {
|
|
1886
|
+
let db;
|
|
1887
|
+
try {
|
|
1888
|
+
db = openReadOnly(dbPath);
|
|
1889
|
+
} catch (err2) {
|
|
1890
|
+
if (err2 && err2.code === "DSH_SQLITE_UNAVAILABLE") throw err2;
|
|
1891
|
+
return null;
|
|
1892
|
+
}
|
|
1893
|
+
try {
|
|
1894
|
+
let sig;
|
|
1895
|
+
try {
|
|
1896
|
+
sig = probe(db);
|
|
1897
|
+
} catch {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
return sig ? read(db, sig) : null;
|
|
1901
|
+
} finally {
|
|
1902
|
+
closeQuietly(db);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
function columnsOf(db, table) {
|
|
1906
|
+
return new Set(db.prepare("PRAGMA table_info(" + table + ")").all().map((c) => c.name));
|
|
1907
|
+
}
|
|
1908
|
+
function tableNames(db) {
|
|
1909
|
+
return new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((r) => r.name));
|
|
1910
|
+
}
|
|
1911
|
+
function hasTable(db, name) {
|
|
1912
|
+
return db.prepare("SELECT COUNT(*) AS n FROM sqlite_master WHERE type = 'table' AND name = ?").get(name).n > 0;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/opencode.mjs
|
|
1916
|
+
function opencodeSchemaGeneration(db) {
|
|
1917
|
+
const names = tableNames(db);
|
|
1918
|
+
if (names.has("session_v2")) return "v2";
|
|
1919
|
+
if (names.has("session")) return "v1";
|
|
1920
|
+
return null;
|
|
1921
|
+
}
|
|
1922
|
+
function readOpencodeV2Summaries(db, options = {}) {
|
|
1923
|
+
const where = typeof options.where === "string" && options.where.trim() ? " WHERE " + options.where : "";
|
|
1924
|
+
const hasMessage = hasTable(db, "session_message");
|
|
1925
|
+
const rows = db.prepare(
|
|
1926
|
+
"SELECT s.id, s.title, s.directory, s.time_created AS createdAt" + (hasMessage ? ", (SELECT MAX(m.time_created) FROM session_message m WHERE m.session_id = s.id) AS lastActiveAt" : "") + " FROM session_v2 s" + where + " ORDER BY s.time_created, s.id"
|
|
1927
|
+
).all();
|
|
1928
|
+
return rows.map((row) => ({
|
|
1929
|
+
id: row.id,
|
|
1930
|
+
title: row.title,
|
|
1931
|
+
directory: row.directory,
|
|
1932
|
+
createdAt: row.createdAt,
|
|
1933
|
+
lastActiveAt: row.lastActiveAt ?? row.createdAt
|
|
1934
|
+
}));
|
|
1935
|
+
}
|
|
1936
|
+
function readOpencodeDbSummaries(dbPath, options = {}) {
|
|
1937
|
+
const where = typeof options.where === "string" && options.where.trim() ? " WHERE " + options.where : "";
|
|
1938
|
+
return withReadOnlyDb(dbPath, (db) => {
|
|
1939
|
+
if (opencodeSchemaGeneration(db) === "v2") return readOpencodeV2Summaries(db, options);
|
|
1940
|
+
const hasMessage = hasTable(db, "message");
|
|
1941
|
+
const rows = db.prepare(
|
|
1942
|
+
"SELECT s.id, s.title, s.directory, s.time_created AS createdAt" + (hasMessage ? ", (SELECT MAX(m.time_created) FROM message m WHERE m.session_id = s.id) AS lastActiveAt" : "") + " FROM session s" + where + " ORDER BY s.time_created, s.id"
|
|
1943
|
+
).all();
|
|
1944
|
+
return rows.map((row) => ({
|
|
1945
|
+
id: row.id,
|
|
1946
|
+
title: row.title,
|
|
1947
|
+
directory: row.directory,
|
|
1948
|
+
createdAt: row.createdAt,
|
|
1949
|
+
lastActiveAt: row.lastActiveAt ?? row.createdAt
|
|
1950
|
+
}));
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/trae.mjs
|
|
1955
|
+
var TRAE_DB_NAME = "state.vscdb";
|
|
1956
|
+
var TRAE_STORAGE_KEY = "memento/icube-ai-agent-storage";
|
|
1957
|
+
var TRAE_FALLBACK_KEYS = [
|
|
1958
|
+
"chat.ChatSessionStore.index",
|
|
1959
|
+
"ChatStore",
|
|
1960
|
+
"memento/icube-ai-chat-storage-7467774676505887760",
|
|
1961
|
+
"memento/icube-ai-ng-chat-storage-7467774676505887760"
|
|
1962
|
+
];
|
|
1963
|
+
function decodeSqlValue(value) {
|
|
1964
|
+
if (typeof value === "string") return value;
|
|
1965
|
+
if (value instanceof Uint8Array) return new TextDecoder().decode(value);
|
|
1966
|
+
return value === void 0 || value === null ? "" : String(value);
|
|
1967
|
+
}
|
|
1968
|
+
function readJsonValue(db, statement, key) {
|
|
1969
|
+
const row = statement.get(key);
|
|
1970
|
+
if (!row) return null;
|
|
1971
|
+
const text = decodeSqlValue(row.value);
|
|
1972
|
+
if (!text.trim()) return null;
|
|
1973
|
+
try {
|
|
1974
|
+
return JSON.parse(text);
|
|
1975
|
+
} catch {
|
|
1976
|
+
return null;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
var TRAE_NO_SESSIONS = "TRAE_NO_SESSIONS";
|
|
1980
|
+
function sessionRows(db) {
|
|
1981
|
+
const columns = columnsOf(db, "ItemTable");
|
|
1982
|
+
if (!columns.has("key") || !columns.has("value")) {
|
|
1983
|
+
throw new Error("Trae Work \u6570\u636E\u5E93\u7F3A\u5C11 ItemTable(key,value)");
|
|
1984
|
+
}
|
|
1985
|
+
const statement = db.prepare("SELECT value FROM ItemTable WHERE key = ?");
|
|
1986
|
+
const keys = [TRAE_STORAGE_KEY, ...TRAE_FALLBACK_KEYS];
|
|
1987
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1988
|
+
const sessions = [];
|
|
1989
|
+
let entries = 0;
|
|
1990
|
+
for (const key of keys) {
|
|
1991
|
+
const value = readJsonValue(db, statement, key);
|
|
1992
|
+
if (value === null) continue;
|
|
1993
|
+
const items = extractTraeSessions(value);
|
|
1994
|
+
entries += items.length;
|
|
1995
|
+
for (const item of items) {
|
|
1996
|
+
const session = normalizeTraeSession(item, sessions.length);
|
|
1997
|
+
if (!session || session.messages.length === 0 || seen.has(session.id)) continue;
|
|
1998
|
+
seen.add(session.id);
|
|
1999
|
+
sessions.push(session);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
if (sessions.length === 0 && entries === 0) {
|
|
2003
|
+
throw Object.assign(new Error("Trae Work \u6570\u636E\u5E93\u6CA1\u6709\u4F1A\u8BDD"), { code: TRAE_NO_SESSIONS });
|
|
2004
|
+
}
|
|
2005
|
+
if (sessions.length === 0) throw new Error("Trae Work \u6570\u636E\u5E93\u6CA1\u6709\u53EF\u8BC6\u522B\u4F1A\u8BDD");
|
|
2006
|
+
return sessions;
|
|
2007
|
+
}
|
|
2008
|
+
function readTraeDb(dbPath) {
|
|
2009
|
+
return withReadOnlyDb(dbPath, sessionRows);
|
|
2010
|
+
}
|
|
2011
|
+
function timeValue(value) {
|
|
2012
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2013
|
+
return value < 1e11 ? Math.trunc(value * 1e3) : Math.trunc(value);
|
|
2014
|
+
}
|
|
2015
|
+
if (typeof value === "string" && value.trim()) {
|
|
2016
|
+
const numeric = Number(value);
|
|
2017
|
+
if (Number.isFinite(numeric)) return timeValue(numeric);
|
|
2018
|
+
const parsed = Date.parse(value);
|
|
2019
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
2020
|
+
}
|
|
2021
|
+
return void 0;
|
|
2022
|
+
}
|
|
2023
|
+
function readTraeDbSummaries(dbPath) {
|
|
2024
|
+
return readTraeDb(dbPath).map((session) => {
|
|
2025
|
+
const times = [session.createdAt, ...(session.messages || []).map((message) => message.createdAt)].map(timeValue).filter((value) => value !== void 0);
|
|
2026
|
+
const createdAt = timeValue(session.createdAt);
|
|
2027
|
+
return {
|
|
2028
|
+
id: session.id,
|
|
2029
|
+
title: session.title,
|
|
2030
|
+
directory: session.directory,
|
|
2031
|
+
createdAt,
|
|
2032
|
+
lastActiveAt: times.length ? Math.max(...times) : createdAt
|
|
2033
|
+
};
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
2036
|
+
function entryPath(entry, parent, name) {
|
|
2037
|
+
return entry && entry.path ? entry.path : join5(parent, name);
|
|
2038
|
+
}
|
|
2039
|
+
async function listTraeDatabases(host2, target) {
|
|
2040
|
+
const found = [];
|
|
2041
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2042
|
+
const add = async (path) => {
|
|
2043
|
+
if (seen.has(path)) return;
|
|
2044
|
+
const stat2 = await host2.stat(path);
|
|
2045
|
+
if (stat2 && stat2.type === "file" && /(^|[\\/])state\.vscdb$/i.test(path)) {
|
|
2046
|
+
seen.add(path);
|
|
2047
|
+
found.push(path);
|
|
2048
|
+
}
|
|
2049
|
+
};
|
|
2050
|
+
const addContainer = async (path, kind) => {
|
|
2051
|
+
const stat2 = await host2.stat(path);
|
|
2052
|
+
if (!stat2 || stat2.type !== "directory") return;
|
|
2053
|
+
await add(join5(path, TRAE_DB_NAME));
|
|
2054
|
+
if (kind.toLowerCase() !== "workspacestorage") return;
|
|
2055
|
+
const entries = await host2.readDir(path);
|
|
2056
|
+
if (!entries) return;
|
|
2057
|
+
for (const entry of entries) {
|
|
2058
|
+
if (entry.type === "directory") await add(join5(entryPath(entry, path, entry.name), TRAE_DB_NAME));
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
const targetStat = await host2.stat(target);
|
|
2062
|
+
if (!targetStat) return found;
|
|
2063
|
+
if (targetStat.type === "file") {
|
|
2064
|
+
await add(target);
|
|
2065
|
+
return found;
|
|
2066
|
+
}
|
|
2067
|
+
await add(join5(target, TRAE_DB_NAME));
|
|
2068
|
+
const base = String(target).split(/[\\/]/).pop().toLowerCase();
|
|
2069
|
+
if (base === "workspacestorage" || base === "globalstorage") {
|
|
2070
|
+
await addContainer(target, base);
|
|
2071
|
+
} else {
|
|
2072
|
+
await addContainer(join5(target, "workspaceStorage"), "workspaceStorage");
|
|
2073
|
+
await addContainer(join5(target, "globalStorage"), "globalStorage");
|
|
2074
|
+
}
|
|
2075
|
+
return found;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/sqlite.mjs
|
|
2079
|
+
import { join as join6 } from "node:path";
|
|
2080
|
+
function traeUserDataDirs(home, env = process.env) {
|
|
2081
|
+
const names = ["Trae", "Trae CN", "TRAE SOLO CN", "TRAE SOLO"];
|
|
2082
|
+
if (process.platform === "win32") {
|
|
2083
|
+
if (!env.APPDATA) return [];
|
|
2084
|
+
return names.map((name) => join6(env.APPDATA, name, "User"));
|
|
2085
|
+
}
|
|
2086
|
+
if (process.platform === "darwin") {
|
|
2087
|
+
return names.map((name) => join6(home, "Library", "Application Support", name, "User"));
|
|
2088
|
+
}
|
|
2089
|
+
const configHome = env.XDG_CONFIG_HOME || join6(home, ".config");
|
|
2090
|
+
return names.map((name) => join6(configHome, name, "User"));
|
|
2091
|
+
}
|
|
2092
|
+
async function sqliteFingerprint(host2, dbStat, dbPath) {
|
|
2093
|
+
const side = [];
|
|
2094
|
+
for (const sfx of ["-wal", "-shm"]) {
|
|
2095
|
+
const st = await host2.stat(dbPath + sfx);
|
|
2096
|
+
side.push(st && st.type === "file" ? String(st.size ?? "") + ":" + String(st.mtimeMs ?? st.version ?? "") : "-");
|
|
2097
|
+
}
|
|
2098
|
+
return { mtimeMs: dbStat.mtimeMs, sizeBytes: dbStat.size, walSig: side.join("|") };
|
|
2099
|
+
}
|
|
2100
|
+
async function scanSqlite(host2, format, target, dbName, { bm, emit }) {
|
|
2101
|
+
const st = await host2.stat(target);
|
|
2102
|
+
if (!st) return [];
|
|
2103
|
+
let dbPath = target;
|
|
2104
|
+
if (st.type === "directory") {
|
|
2105
|
+
const candidate = join6(target, dbName);
|
|
2106
|
+
const cst = await host2.stat(candidate);
|
|
2107
|
+
if (!cst || cst.type !== "file") return [];
|
|
2108
|
+
dbPath = candidate;
|
|
2109
|
+
} else if (!new RegExp(dbName.replace(/\./g, "\\.") + "$", "i").test(target)) {
|
|
2110
|
+
return [];
|
|
2111
|
+
}
|
|
2112
|
+
const dbStat = await host2.stat(dbPath);
|
|
2113
|
+
if (!dbStat) return [];
|
|
2114
|
+
const fp = await sqliteFingerprint(host2, dbStat, dbPath);
|
|
2115
|
+
const entries = await probeSource(bm, format, dbPath, fp, async () => {
|
|
2116
|
+
const sessions = await host2.readSessions(format, dbPath);
|
|
2117
|
+
if (!sessions) return [];
|
|
2118
|
+
return sessions.map((s) => makeEntry({
|
|
2119
|
+
format,
|
|
2120
|
+
sessionId: s.id,
|
|
2121
|
+
title: normalizeTitle(s.title),
|
|
2122
|
+
project: s.directory ? basenameOf(s.directory) : null,
|
|
2123
|
+
createdAt: s.createdAt,
|
|
2124
|
+
lastActiveAt: s.lastActiveAt,
|
|
2125
|
+
sourcePath: dbPath,
|
|
2126
|
+
cwd: s.directory || null
|
|
2127
|
+
}));
|
|
2128
|
+
});
|
|
2129
|
+
await emitEach(emit, entries);
|
|
2130
|
+
return entries;
|
|
2131
|
+
}
|
|
2132
|
+
var fixedDbScanner = (format, dbName) => (host2, target, ctx) => scanSqlite(host2, format, target, dbName, ctx);
|
|
2133
|
+
async function scanTeleagent(host2, target, ctx) {
|
|
2134
|
+
const st = await host2.stat(target);
|
|
2135
|
+
if (!st) return [];
|
|
2136
|
+
if (st.type !== "directory") return scanSqlite(host2, "teleagent", target, "teleagent.db", ctx);
|
|
2137
|
+
const dbDirect = await host2.stat(join6(target, "teleagent.db"));
|
|
2138
|
+
if (dbDirect && dbDirect.type === "file") return scanSqlite(host2, "teleagent", target, "teleagent.db", ctx);
|
|
2139
|
+
const usersDir = basenameOf(target).toLowerCase() === "users" ? target : join6(target, "users");
|
|
2140
|
+
const accounts = await host2.readDir(usersDir);
|
|
2141
|
+
if (!accounts) return [];
|
|
2142
|
+
const out = [];
|
|
2143
|
+
for (const e of accounts) {
|
|
2144
|
+
if (e.type !== "directory") continue;
|
|
2145
|
+
out.push(...await scanSqlite(host2, "teleagent", e.path, "teleagent.db", ctx));
|
|
2146
|
+
}
|
|
2147
|
+
return out;
|
|
2148
|
+
}
|
|
2149
|
+
async function scanTrae(host2, target, { bm, emit }) {
|
|
2150
|
+
const dbPaths = await listTraeDatabases(host2, target);
|
|
2151
|
+
const out = [];
|
|
2152
|
+
for (const dbPath of dbPaths) {
|
|
2153
|
+
const dbStat = await host2.stat(dbPath);
|
|
2154
|
+
if (!dbStat) continue;
|
|
2155
|
+
const fp = await sqliteFingerprint(host2, dbStat, dbPath);
|
|
2156
|
+
const entries = await probeSource(bm, "trae", dbPath, fp, async () => {
|
|
2157
|
+
const sessions = await host2.readSessions("trae", dbPath);
|
|
2158
|
+
if (!sessions) return [];
|
|
2159
|
+
return sessions.map((session) => makeEntry({
|
|
2160
|
+
format: "trae",
|
|
2161
|
+
sessionId: session.id,
|
|
2162
|
+
title: normalizeTitle(session.title),
|
|
2163
|
+
project: projectFromRecord(session.directory, () => null),
|
|
2164
|
+
createdAt: session.createdAt,
|
|
2165
|
+
lastActiveAt: session.lastActiveAt,
|
|
2166
|
+
sourcePath: dbPath,
|
|
2167
|
+
cwd: session.directory || null
|
|
2168
|
+
}));
|
|
2169
|
+
});
|
|
2170
|
+
out.push(...entries);
|
|
2171
|
+
await emitEach(emit, entries);
|
|
2172
|
+
}
|
|
2173
|
+
return out;
|
|
2174
|
+
}
|
|
2175
|
+
var scanGoose = fixedDbScanner("goose", "sessions.db");
|
|
2176
|
+
var scanZed = fixedDbScanner("zed", "threads.db");
|
|
2177
|
+
async function scanCrush(host2, target, { bm, emit }) {
|
|
2178
|
+
const st = await host2.stat(target);
|
|
2179
|
+
if (!st) return [];
|
|
2180
|
+
const dbPaths = [];
|
|
2181
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2182
|
+
const pushDb = async (p) => {
|
|
2183
|
+
const s = await host2.stat(p);
|
|
2184
|
+
if (s && s.type === "file" && !seen.has(p)) {
|
|
2185
|
+
seen.add(p);
|
|
2186
|
+
dbPaths.push(p);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
const projects = /* @__PURE__ */ new Map();
|
|
2190
|
+
const norm = (p) => String(p ?? "").replace(/[\\/]+$/, "").replace(/\\/g, "/").toLowerCase();
|
|
2191
|
+
if (st.type === "file") {
|
|
2192
|
+
if (!/crush\.db$/i.test(String(target))) return [];
|
|
2193
|
+
await pushDb(target);
|
|
2194
|
+
} else {
|
|
2195
|
+
await pushDb(join6(target, ".crush", "crush.db"));
|
|
2196
|
+
await pushDb(join6(target, "crush.db"));
|
|
2197
|
+
const registryRaw = await host2.readText(join6(target, "projects.json"));
|
|
2198
|
+
for (const entry of parseCrushProjects(registryRaw)) {
|
|
2199
|
+
const dbPath = entry.dataDir ? join6(entry.dataDir, "crush.db") : crushProjectDbPath(entry.path);
|
|
2200
|
+
await pushDb(dbPath);
|
|
2201
|
+
projects.set(norm(entry.dataDir || join6(entry.path, ".crush")), entry.path);
|
|
2202
|
+
}
|
|
2203
|
+
const isUserDataDir = /[\\/]crush$/i.test(String(target)) || await host2.stat(join6(target, "projects.json")) !== null;
|
|
2204
|
+
if (isUserDataDir && typeof host2.listWorkspaces === "function") {
|
|
2205
|
+
for (const ws of await host2.listWorkspaces()) await pushDb(crushProjectDbPath(ws));
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
const out = [];
|
|
2209
|
+
for (const dbPath of dbPaths) {
|
|
2210
|
+
const dbStat = await host2.stat(dbPath);
|
|
2211
|
+
if (!dbStat) continue;
|
|
2212
|
+
const fp = await sqliteFingerprint(host2, dbStat, dbPath);
|
|
2213
|
+
const dir = dbPath.replace(/[\\/][^\\/]*$/, "");
|
|
2214
|
+
const projectPath = projects.get(norm(dir)) || (/[\\/]\.crush$/i.test(dir) ? dir.replace(/[\\/]\.crush$/i, "") : null);
|
|
2215
|
+
const entries = await probeSource(bm, "crush", dbPath, fp, async () => {
|
|
2216
|
+
const sessions = await host2.readSessions("crush", dbPath);
|
|
2217
|
+
if (!sessions) return [];
|
|
2218
|
+
return sessions.map((s) => makeEntry({
|
|
2219
|
+
format: "crush",
|
|
2220
|
+
sessionId: s.id,
|
|
2221
|
+
title: normalizeTitle(s.title),
|
|
2222
|
+
project: projectFromRecord(projectPath, () => null),
|
|
2223
|
+
createdAt: s.createdAt ?? void 0,
|
|
2224
|
+
lastActiveAt: s.updatedAt ?? dbStat.mtimeMs,
|
|
2225
|
+
sourcePath: dbPath,
|
|
2226
|
+
cwd: projectPath
|
|
2227
|
+
}));
|
|
2228
|
+
});
|
|
2229
|
+
out.push(...entries);
|
|
2230
|
+
await emitEach(emit, entries);
|
|
2231
|
+
}
|
|
2232
|
+
return out;
|
|
2233
|
+
}
|
|
2234
|
+
function hermesUserText(r) {
|
|
2235
|
+
if (!r || typeof r !== "object") return "";
|
|
2236
|
+
if (r.type === "message" && r.message && typeof r.message === "object" && r.message.role === "user") return contentText2(r.message.content);
|
|
2237
|
+
if (r.role === "user") return contentText2(r.content);
|
|
2238
|
+
return "";
|
|
2239
|
+
}
|
|
2240
|
+
async function scanHermes(host2, target, { bm, emit, warn }) {
|
|
2241
|
+
const st = await host2.stat(target);
|
|
2242
|
+
if (!st) return [];
|
|
2243
|
+
let dbPath = null;
|
|
2244
|
+
if (st.type === "file") {
|
|
2245
|
+
if (!/state\.db$/i.test(target)) return [];
|
|
2246
|
+
dbPath = target;
|
|
2247
|
+
} else {
|
|
2248
|
+
const candidate = join6(target, "state.db");
|
|
2249
|
+
const cst = await host2.stat(candidate);
|
|
2250
|
+
if (cst && cst.type === "file") dbPath = candidate;
|
|
2251
|
+
}
|
|
2252
|
+
if (dbPath) {
|
|
2253
|
+
const dbStat = await host2.stat(dbPath);
|
|
2254
|
+
if (!dbStat) return [];
|
|
2255
|
+
const fp = await sqliteFingerprint(host2, dbStat, dbPath);
|
|
2256
|
+
let dbEntries = null;
|
|
2257
|
+
try {
|
|
2258
|
+
dbEntries = await probeSource(bm, "hermes", dbPath, fp, async () => {
|
|
2259
|
+
const sessions = await host2.readSessions("hermes", dbPath);
|
|
2260
|
+
if (sessions === null) return null;
|
|
2261
|
+
return sessions.map((s) => makeEntry({
|
|
2262
|
+
format: "hermes",
|
|
2263
|
+
sessionId: s.id,
|
|
2264
|
+
title: normalizeTitle(s.title),
|
|
2265
|
+
project: s.directory ? basenameOf(s.directory) : null,
|
|
2266
|
+
createdAt: s.createdAt,
|
|
2267
|
+
lastActiveAt: s.lastActiveAt,
|
|
2268
|
+
sourcePath: dbPath
|
|
2269
|
+
}));
|
|
2270
|
+
});
|
|
2271
|
+
} catch (err2) {
|
|
2272
|
+
if (typeof warn === "function") warn(err2);
|
|
2273
|
+
}
|
|
2274
|
+
if (dbEntries !== null) {
|
|
2275
|
+
await emitEach(emit, dbEntries);
|
|
2276
|
+
return dbEntries;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
const files = [];
|
|
2280
|
+
await walkFiles(host2, target, files, (name) => /\.jsonl$/i.test(name));
|
|
2281
|
+
const out = [];
|
|
2282
|
+
for (const file of files) {
|
|
2283
|
+
const fst = await host2.stat(file.path);
|
|
2284
|
+
if (!fst) continue;
|
|
2285
|
+
const fp = fileFingerprint(fst);
|
|
2286
|
+
const entries = await probeSource(bm, "hermes", file.path, fp, async () => {
|
|
2287
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
2288
|
+
if (head === null || head === "") return [];
|
|
2289
|
+
const recs = parseJsonlHead(head);
|
|
2290
|
+
if (!recs.some((r) => r && typeof r === "object" && (r.role === "user" || r.type === "session" || r.type === "message"))) return [];
|
|
2291
|
+
const sessRec = recs.find((r) => r && r.type === "session");
|
|
2292
|
+
const sessionId = sessRec && typeof sessRec.id === "string" && sessRec.id ? sessRec.id : basenameOf(file.name).replace(/\.jsonl$/i, "");
|
|
2293
|
+
const explicitTitle = sessRec && typeof sessRec.title === "string" && sessRec.title.trim() ? sessRec.title : "";
|
|
2294
|
+
const title = explicitTitle || firstUserTitle(recs, hermesUserText);
|
|
2295
|
+
const cwd = sessRec && typeof sessRec.cwd === "string" ? sessRec.cwd : void 0;
|
|
2296
|
+
const createdAt = firstNumber(recs, (r) => {
|
|
2297
|
+
if (!r || typeof r !== "object") return void 0;
|
|
2298
|
+
const v = r.timestamp ?? r.ts ?? (r.message && typeof r.message === "object" ? r.message.ts : void 0);
|
|
2299
|
+
return v !== void 0 ? parseTimeValue(v) : void 0;
|
|
2300
|
+
});
|
|
2301
|
+
return [makeEntry({
|
|
2302
|
+
format: "hermes",
|
|
2303
|
+
sessionId,
|
|
2304
|
+
title: normalizeTitle(title),
|
|
2305
|
+
project: projectFromRecord(cwd, () => null),
|
|
2306
|
+
createdAt,
|
|
2307
|
+
lastActiveAt: fst.mtimeMs,
|
|
2308
|
+
sourcePath: file.path
|
|
2309
|
+
})];
|
|
2310
|
+
});
|
|
2311
|
+
out.push(...entries);
|
|
2312
|
+
await emitEach(emit, entries);
|
|
2313
|
+
}
|
|
2314
|
+
return out;
|
|
2315
|
+
}
|
|
2316
|
+
var isDb = (lower) => lower.endsWith(".db");
|
|
2317
|
+
var opencodeSource = {
|
|
2318
|
+
format: "opencode",
|
|
2319
|
+
sessionsFromHost: true,
|
|
2320
|
+
roots: (home) => join6(home, ".local", "share", "opencode", "opencode.db"),
|
|
2321
|
+
scan: fixedDbScanner("opencode", "opencode.db"),
|
|
2322
|
+
matchFile: (lower) => /opencode\.db$/.test(lower),
|
|
2323
|
+
fileFallback: ["db"]
|
|
2324
|
+
};
|
|
2325
|
+
var mimocodeSource = {
|
|
2326
|
+
format: "mimocode",
|
|
2327
|
+
sessionsFromHost: true,
|
|
2328
|
+
roots: (home) => join6(home, ".local", "share", "mimocode", "mimocode.db"),
|
|
2329
|
+
scan: fixedDbScanner("mimocode", "mimocode.db"),
|
|
2330
|
+
matchFile: (lower) => /mimocode\.db$/.test(lower)
|
|
2331
|
+
};
|
|
2332
|
+
var kilocodeSource = {
|
|
2333
|
+
format: "kilocode",
|
|
2334
|
+
sessionsFromHost: true,
|
|
2335
|
+
roots: (home) => join6(home, ".local", "share", "kilo", "kilo.db"),
|
|
2336
|
+
scan: fixedDbScanner("kilocode", "kilo.db"),
|
|
2337
|
+
matchFile: (lower) => /kilo\.db$/.test(lower)
|
|
2338
|
+
};
|
|
2339
|
+
var zcodeSource = {
|
|
2340
|
+
format: "zcode",
|
|
2341
|
+
sessionsFromHost: true,
|
|
2342
|
+
roots: (home) => join6(home, ".zcode", "cli", "db", "db.sqlite"),
|
|
2343
|
+
scan: fixedDbScanner("zcode", "db.sqlite"),
|
|
2344
|
+
matchFile: (lower) => /db\.sqlite$/.test(lower),
|
|
2345
|
+
fileFallback: ["db"]
|
|
2346
|
+
};
|
|
2347
|
+
var teleagentSource = {
|
|
2348
|
+
format: "teleagent",
|
|
2349
|
+
sessionsFromHost: true,
|
|
2350
|
+
// XDG 风格多账户目录(Windows 上同样在 ~/.local/share):根给到 users/ 层,扫描器枚举
|
|
2351
|
+
// 账户目录取各库(<账户>/teleagent.db)
|
|
2352
|
+
roots: (home) => join6(home, ".local", "share", "TeleAgent", "users"),
|
|
2353
|
+
scan: scanTeleagent,
|
|
2354
|
+
matchFile: (lower) => /teleagent\.db$/.test(lower)
|
|
2355
|
+
};
|
|
2356
|
+
var gooseSource = {
|
|
2357
|
+
format: "goose",
|
|
2358
|
+
sessionsFromHost: true,
|
|
2359
|
+
// <dataDir>/sessions/sessions.db(路径规则与导入层共用 lib/convert/goose.mjs)
|
|
2360
|
+
roots: (home) => gooseSessionsDir(home),
|
|
2361
|
+
scan: scanGoose,
|
|
2362
|
+
// sessions.db 是 Cline 与 Goose 共用的库文件名 → 两个候选都试,扫描器按表结构自拒
|
|
2363
|
+
matchFile: (lower) => /sessions\.db$/.test(lower)
|
|
2364
|
+
};
|
|
2365
|
+
var zedSource = {
|
|
2366
|
+
format: "zed",
|
|
2367
|
+
sessionsFromHost: true,
|
|
2368
|
+
// <data_dir>/threads/threads.db(路径规则见 lib/convert/zed.mjs;--user-data-dir 会整体
|
|
2369
|
+
// 改写 data_dir,那种安装需显式传 path)
|
|
2370
|
+
roots: (home) => zedThreadsDir(home),
|
|
2371
|
+
scan: scanZed,
|
|
2372
|
+
matchFile: (lower) => /threads\.db$/.test(lower)
|
|
2373
|
+
};
|
|
2374
|
+
var crushSource = {
|
|
2375
|
+
format: "crush",
|
|
2376
|
+
sessionsFromHost: true,
|
|
2377
|
+
// 库在项目里(<项目>/.crush/crush.db),用户级目录只有 JSON 状态 → 默认根取用户级目录,
|
|
2378
|
+
// 扫描器再用其 projects.json 与宿主工作区列表逐个探测项目库
|
|
2379
|
+
roots: (home) => crushUserDataDir(home),
|
|
2380
|
+
scan: scanCrush,
|
|
2381
|
+
matchFile: (lower) => /crush\.db$/.test(lower)
|
|
2382
|
+
};
|
|
2383
|
+
var traeSource = {
|
|
2384
|
+
format: "trae",
|
|
2385
|
+
sessionsFromHost: true,
|
|
2386
|
+
roots: (home, env) => traeUserDataDirs(home, env),
|
|
2387
|
+
scan: scanTrae,
|
|
2388
|
+
matchFile: (lower) => /state\.vscdb$/.test(lower) && /[\\/]((workspace|global)storage)[\\/]/.test(lower) && /[\\/]trae(?: cn| solo(?: cn)?)?[\\/]/.test(lower) ? "only" : false
|
|
2389
|
+
};
|
|
2390
|
+
var hermesSource = {
|
|
2391
|
+
format: "hermes",
|
|
2392
|
+
sessionsFromHost: true,
|
|
2393
|
+
roots: (home, env = process.env) => process.platform === "win32" ? [join6(env.LOCALAPPDATA || join6(home, "AppData", "Local"), "hermes"), join6(home, ".hermes")] : join6(home, ".hermes"),
|
|
2394
|
+
scan: scanHermes,
|
|
2395
|
+
matchFile: (lower) => lower.endsWith(".jsonl") && /\.hermes[\\/]/.test(lower) || isDb(lower) && /state\.db$/.test(lower),
|
|
2396
|
+
fileFallback: ["jsonl", "db"]
|
|
2397
|
+
};
|
|
2398
|
+
|
|
2399
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/cline.mjs
|
|
2400
|
+
import { join as join7 } from "node:path";
|
|
2401
|
+
function clineDataDir(home, env) {
|
|
2402
|
+
if (env.CLINE_DATA_DIR) return env.CLINE_DATA_DIR;
|
|
2403
|
+
const clineDir = env.CLINE_DIR || join7(home, ".cline");
|
|
2404
|
+
return join7(clineDir, "data");
|
|
2405
|
+
}
|
|
2406
|
+
function clineSessionsDir(home, env) {
|
|
2407
|
+
return env.CLINE_SESSION_DATA_DIR || join7(clineDataDir(home, env), "sessions");
|
|
2408
|
+
}
|
|
2409
|
+
function clineLegacyStorageDirs(home, env = process.env) {
|
|
2410
|
+
const override = env.CLINE_LEGACY_GLOBAL_STORAGE_DIR || env.CLINE_VSCODE_GLOBAL_STORAGE_DIR;
|
|
2411
|
+
if (override) return [override];
|
|
2412
|
+
const names = ["Code", "Code - Insiders", "VSCodium"];
|
|
2413
|
+
if (process.platform === "win32") {
|
|
2414
|
+
if (!env.APPDATA) return [];
|
|
2415
|
+
return names.map((name) => join7(env.APPDATA, name, "User", "globalStorage", "saoudrizwan.claude-dev"));
|
|
2416
|
+
}
|
|
2417
|
+
if (process.platform === "darwin") {
|
|
2418
|
+
return names.map((name) => join7(home, "Library", "Application Support", name, "User", "globalStorage", "saoudrizwan.claude-dev"));
|
|
2419
|
+
}
|
|
2420
|
+
const configHome = env.XDG_CONFIG_HOME || join7(home, ".config");
|
|
2421
|
+
return names.map((name) => join7(configHome, name, "User", "globalStorage", "saoudrizwan.claude-dev"));
|
|
2422
|
+
}
|
|
2423
|
+
function legacyRootForPath(path) {
|
|
2424
|
+
const value = String(path);
|
|
2425
|
+
const root = clineLegacyRootFromApiPath(value) ?? clineLegacyRootFromApiPath(value + "/api_conversation_history.json");
|
|
2426
|
+
if (root !== null) return root;
|
|
2427
|
+
if (basenameOf(value).toLowerCase() === "tasks") return dirnameOf(value);
|
|
2428
|
+
return value;
|
|
2429
|
+
}
|
|
2430
|
+
async function clineLegacyTitle(host2, root, id, item, apiPath) {
|
|
2431
|
+
if (item && typeof item.task === "string" && item.task.trim()) return normalizeTitle(item.task);
|
|
2432
|
+
const uiPath = clineLegacyUiMessagesPath(root, id);
|
|
2433
|
+
const uiHead = await host2.readHead(uiPath, HEAD_MAX_BYTES);
|
|
2434
|
+
if (uiHead) {
|
|
2435
|
+
try {
|
|
2436
|
+
const ui = JSON.parse(uiHead);
|
|
2437
|
+
const title = firstUserTitle(Array.isArray(ui) ? ui : [], (entry) => {
|
|
2438
|
+
if (!entry || typeof entry !== "object") return "";
|
|
2439
|
+
const isUserPrompt = entry.type === "ask" || entry.say === "task";
|
|
2440
|
+
return isUserPrompt && typeof entry.text === "string" ? entry.text : "";
|
|
2441
|
+
});
|
|
2442
|
+
if (title) return title;
|
|
2443
|
+
} catch {
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
const apiHead = await host2.readHead(apiPath, HEAD_MAX_BYTES);
|
|
2447
|
+
if (apiHead) {
|
|
2448
|
+
try {
|
|
2449
|
+
const api = JSON.parse(apiHead);
|
|
2450
|
+
const title = firstUserTitle(Array.isArray(api) ? api : [], (entry) => {
|
|
2451
|
+
if (!entry || typeof entry !== "object" || entry.role !== "user") return "";
|
|
2452
|
+
return contentText2(entry.content);
|
|
2453
|
+
});
|
|
2454
|
+
if (title) return title;
|
|
2455
|
+
} catch {
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
return null;
|
|
2459
|
+
}
|
|
2460
|
+
async function scanClineLegacy(host2, target, { bm, emit }) {
|
|
2461
|
+
const st = await host2.stat(target);
|
|
2462
|
+
if (!st) return [];
|
|
2463
|
+
const targetPath = String(target);
|
|
2464
|
+
const isApiFile = st.type === "file" && /^api_conversation_history\.json$/i.test(basenameOf(targetPath));
|
|
2465
|
+
const root = legacyRootForPath(targetPath);
|
|
2466
|
+
const historyPath = clineLegacyTaskHistoryPath(root);
|
|
2467
|
+
const historyStat = await host2.stat(historyPath);
|
|
2468
|
+
const indexed = historyStat && historyStat.type === "file" ? parseClineLegacyTaskHistory(await host2.readText(historyPath)) : [];
|
|
2469
|
+
const files = [];
|
|
2470
|
+
if (isApiFile) files.push({ name: basenameOf(targetPath), type: "file", path: targetPath });
|
|
2471
|
+
else {
|
|
2472
|
+
const tasksPath = join7(root, "tasks");
|
|
2473
|
+
await walkFiles(host2, tasksPath, files, (name) => /^api_conversation_history\.json$/i.test(name));
|
|
2474
|
+
}
|
|
2475
|
+
if (files.length === 0) return [];
|
|
2476
|
+
const byId = new Map(indexed.map((item) => [item.id, item]));
|
|
2477
|
+
const out = [];
|
|
2478
|
+
for (const file of files) {
|
|
2479
|
+
const id = clineLegacyTaskIdFromPath(file.path);
|
|
2480
|
+
if (!id) continue;
|
|
2481
|
+
const item = byId.get(id) || null;
|
|
2482
|
+
if (indexed.length > 0 && !item && !isApiFile) continue;
|
|
2483
|
+
const apiStat = await host2.stat(file.path);
|
|
2484
|
+
if (!apiStat || apiStat.type !== "file") continue;
|
|
2485
|
+
const uiStat = await host2.stat(clineLegacyUiMessagesPath(root, id));
|
|
2486
|
+
const fp = compositeFingerprint(apiStat, historyStat, uiStat);
|
|
2487
|
+
const entries = await probeSource(bm, "cline", file.path, fp, async () => [makeEntry({
|
|
2488
|
+
format: "cline",
|
|
2489
|
+
sessionId: id,
|
|
2490
|
+
title: await clineLegacyTitle(host2, root, id, item, file.path),
|
|
2491
|
+
project: projectFromRecord(item && item.cwdOnTaskInitialization, () => null),
|
|
2492
|
+
createdAt: item ? parseTimeValue(item.ts) : void 0,
|
|
2493
|
+
lastActiveAt: apiStat.mtimeMs,
|
|
2494
|
+
sourcePath: file.path,
|
|
2495
|
+
cwd: item && typeof item.cwdOnTaskInitialization === "string" ? item.cwdOnTaskInitialization : null
|
|
2496
|
+
})]);
|
|
2497
|
+
out.push(...entries);
|
|
2498
|
+
}
|
|
2499
|
+
await emitEach(emit, out);
|
|
2500
|
+
return out;
|
|
2501
|
+
}
|
|
2502
|
+
async function scanCline(host2, target, { bm, emit }) {
|
|
2503
|
+
const legacy = await scanClineLegacy(host2, target, { bm, emit });
|
|
2504
|
+
if (legacy.length > 0) return legacy;
|
|
2505
|
+
const st = await host2.stat(target);
|
|
2506
|
+
if (!st) return [];
|
|
2507
|
+
const candidates = [];
|
|
2508
|
+
if (st.type === "file") {
|
|
2509
|
+
if (!/sessions\.db$/i.test(String(target))) return [];
|
|
2510
|
+
candidates.push(String(target));
|
|
2511
|
+
} else {
|
|
2512
|
+
candidates.push(join7(target, "db", "sessions.db"));
|
|
2513
|
+
candidates.push(join7(target, "..", "db", "sessions.db"));
|
|
2514
|
+
}
|
|
2515
|
+
for (const dbPath of candidates) {
|
|
2516
|
+
const dbStat = await host2.stat(dbPath);
|
|
2517
|
+
if (!dbStat || dbStat.type !== "file") continue;
|
|
2518
|
+
const fp = await sqliteFingerprint(host2, dbStat, dbPath);
|
|
2519
|
+
const entries = await probeSource(bm, "cline", dbPath, fp, async () => {
|
|
2520
|
+
const sessions = await host2.readSessions("cline", dbPath);
|
|
2521
|
+
if (!sessions || sessions.length === 0) return [];
|
|
2522
|
+
const sessionsDir = join7(dbPath, "..", "..", "sessions");
|
|
2523
|
+
const out2 = [];
|
|
2524
|
+
for (const s of sessions) {
|
|
2525
|
+
const path = s.messagesPath && /[\\/]/.test(s.messagesPath) ? s.messagesPath : clineMessagesPath(sessionsDir, s.id);
|
|
2526
|
+
const mst = await host2.stat(path);
|
|
2527
|
+
if (!mst || mst.type !== "file") continue;
|
|
2528
|
+
const title = await clineEntryTitle(host2, sessionsDir, s);
|
|
2529
|
+
out2.push(makeEntry({
|
|
2530
|
+
format: "cline",
|
|
2531
|
+
sessionId: s.id,
|
|
2532
|
+
title,
|
|
2533
|
+
project: projectFromRecord(s.cwd, () => null),
|
|
2534
|
+
createdAt: s.createdAt ?? void 0,
|
|
2535
|
+
lastActiveAt: s.lastActiveAt ?? mst.mtimeMs,
|
|
2536
|
+
sourcePath: path,
|
|
2537
|
+
cwd: s.cwd
|
|
2538
|
+
}));
|
|
2539
|
+
}
|
|
2540
|
+
return out2;
|
|
2541
|
+
});
|
|
2542
|
+
await emitEach(emit, entries);
|
|
2543
|
+
return entries;
|
|
2544
|
+
}
|
|
2545
|
+
const files = [];
|
|
2546
|
+
await walkFiles(host2, target, files, (name) => /\.messages\.json$/i.test(name));
|
|
2547
|
+
const out = [];
|
|
2548
|
+
for (const file of files) {
|
|
2549
|
+
const base = basenameOf(file.name);
|
|
2550
|
+
const sessionId = base.replace(/\.messages\.json$/i, "");
|
|
2551
|
+
const dirName = String(file.path).replace(/\\/g, "/").split("/").slice(-2, -1)[0];
|
|
2552
|
+
if (dirName && sessionId !== dirName) continue;
|
|
2553
|
+
const st2 = await host2.stat(file.path);
|
|
2554
|
+
if (!st2) continue;
|
|
2555
|
+
const fp = fileFingerprint(st2);
|
|
2556
|
+
const entries = await probeSource(bm, "cline", file.path, fp, async () => {
|
|
2557
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
2558
|
+
if (head === null || head === "") return [];
|
|
2559
|
+
if (!/"version"\s*:\s*\d+/.test(head) || !/"sessionId"\s*:/.test(head) || !/"messages"\s*:\s*\[/.test(head)) {
|
|
2560
|
+
return [];
|
|
2561
|
+
}
|
|
2562
|
+
const agent = /"agent"\s*:\s*"([^"]+)"/.exec(head);
|
|
2563
|
+
if (agent && agent[1] !== "lead") return [];
|
|
2564
|
+
const updatedAt = /"updated_at"\s*:\s*"([^"]+)"/.exec(head);
|
|
2565
|
+
const manifestPath = join7(file.path, "..", sessionId + ".json");
|
|
2566
|
+
const man = readClineManifest(await host2.readHead(manifestPath, HEAD_MAX_BYTES));
|
|
2567
|
+
return [makeEntry({
|
|
2568
|
+
format: "cline",
|
|
2569
|
+
sessionId,
|
|
2570
|
+
title: normalizeTitle(man && man.title ? man.title : ""),
|
|
2571
|
+
project: projectFromRecord(man && man.cwd, () => null),
|
|
2572
|
+
createdAt: parseTimeValue(man && man.startedAt),
|
|
2573
|
+
lastActiveAt: parseTimeValue(updatedAt && updatedAt[1]) ?? st2.mtimeMs,
|
|
2574
|
+
sourcePath: file.path,
|
|
2575
|
+
cwd: man && man.cwd || null
|
|
2576
|
+
})];
|
|
2577
|
+
});
|
|
2578
|
+
out.push(...entries);
|
|
2579
|
+
await emitEach(emit, entries);
|
|
2580
|
+
}
|
|
2581
|
+
return out;
|
|
2582
|
+
}
|
|
2583
|
+
async function clineEntryTitle(host2, sessionsDir, s) {
|
|
2584
|
+
if (typeof s.title === "string" && s.title.trim()) return normalizeTitle(s.title);
|
|
2585
|
+
const manifestPath = join7(sessionsDir, s.id, s.id + ".json");
|
|
2586
|
+
const man = readClineManifest(await host2.readHead(manifestPath, HEAD_MAX_BYTES));
|
|
2587
|
+
if (man && man.title.trim()) return normalizeTitle(man.title);
|
|
2588
|
+
return normalizeTitle(typeof s.prompt === "string" ? s.prompt : "");
|
|
2589
|
+
}
|
|
2590
|
+
var clineSource = {
|
|
2591
|
+
format: "cline",
|
|
2592
|
+
sessionsFromHost: true,
|
|
2593
|
+
// SDK 会话目录与 SDK 迁移前的 VS Code globalStorage 根并列:两者文件布局不相交
|
|
2594
|
+
roots: (home, env) => [clineSessionsDir(home, env), ...clineLegacyStorageDirs(home, env)],
|
|
2595
|
+
scan: scanCline,
|
|
2596
|
+
// 转写 <sessionId>.messages.json / 旧版 tasks/<id>/api_conversation_history.json 独占;
|
|
2597
|
+
// 索引库 sessions.db 与 goose 同名,只作候选
|
|
2598
|
+
matchFile: (lower) => {
|
|
2599
|
+
if (/\.messages\.json$/.test(lower) || /[\\/]tasks[\\/][^\\/]+[\\/]api_conversation_history\.json$/.test(lower)) return "only";
|
|
2600
|
+
return /sessions\.db$/.test(lower);
|
|
2601
|
+
}
|
|
2602
|
+
};
|
|
2603
|
+
|
|
2604
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/session-dirs.mjs
|
|
2605
|
+
import { join as join9 } from "node:path";
|
|
2606
|
+
import { createHash } from "node:crypto";
|
|
2607
|
+
|
|
2608
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/vibe.mjs
|
|
2609
|
+
import { join as join8 } from "node:path";
|
|
2610
|
+
var VIBE_SESSION_FILE = "messages.jsonl";
|
|
2611
|
+
var VIBE_META_FILE = "meta.json";
|
|
2612
|
+
function vibeUserDataDirs(home) {
|
|
2613
|
+
const dirs = [];
|
|
2614
|
+
if (process.env.VIBE_HOME) {
|
|
2615
|
+
dirs.push(join8(process.env.VIBE_HOME, "logs", "session"));
|
|
2616
|
+
}
|
|
2617
|
+
if (home) {
|
|
2618
|
+
dirs.push(join8(home, ".vibe", "logs", "session"));
|
|
2619
|
+
}
|
|
2620
|
+
return dirs;
|
|
2621
|
+
}
|
|
2622
|
+
async function vibeIsSessionDir(hostOrCtx, dir) {
|
|
2623
|
+
const dirPath = typeof dir === "string" ? dir : dir.displayPath || hostOrCtx.fs?.processPath(dir);
|
|
2624
|
+
const msgPath = join8(dirPath, VIBE_SESSION_FILE);
|
|
2625
|
+
const st = hostOrCtx.stat ? await hostOrCtx.stat(msgPath) : await hostOrCtx.fs.stat(await hostOrCtx.fs.resolve(msgPath));
|
|
2626
|
+
return Boolean(st && st.type === "file");
|
|
2627
|
+
}
|
|
2628
|
+
async function listVibeSessions(host2, dir) {
|
|
2629
|
+
const out = [];
|
|
2630
|
+
if (await vibeIsSessionDir(host2, dir)) {
|
|
2631
|
+
out.push(String(dir));
|
|
2632
|
+
return out;
|
|
2633
|
+
}
|
|
2634
|
+
const entries = await host2.readDir(dir);
|
|
2635
|
+
for (const entry of entries || []) {
|
|
2636
|
+
if (entry.type !== "directory") continue;
|
|
2637
|
+
const sub = join8(dir, entry.name);
|
|
2638
|
+
if (await vibeIsSessionDir(host2, sub)) {
|
|
2639
|
+
out.push(sub);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
return out;
|
|
2643
|
+
}
|
|
2644
|
+
async function readVibeMeta(readText) {
|
|
2645
|
+
try {
|
|
2646
|
+
return JSON.parse(await readText());
|
|
2647
|
+
} catch {
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
async function firstUserPromptTitle(host2, messagesPath) {
|
|
2652
|
+
let head;
|
|
2653
|
+
try {
|
|
2654
|
+
head = await host2.readHead(messagesPath, 4096);
|
|
2655
|
+
} catch {
|
|
2656
|
+
return "";
|
|
2657
|
+
}
|
|
2658
|
+
for (const line of String(head || "").split("\n")) {
|
|
2659
|
+
if (!line.trim()) continue;
|
|
2660
|
+
let m;
|
|
2661
|
+
try {
|
|
2662
|
+
m = JSON.parse(line);
|
|
2663
|
+
} catch {
|
|
2664
|
+
continue;
|
|
2665
|
+
}
|
|
2666
|
+
if (m && m.role === "user") {
|
|
2667
|
+
const text = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p && p.text || "").join(" ") : "";
|
|
2668
|
+
if (text.trim()) return text.trim();
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
return "";
|
|
2672
|
+
}
|
|
2673
|
+
async function readVibeSessionSummary(host2, sessionDir) {
|
|
2674
|
+
const meta = await readVibeMeta(() => host2.readText(join8(sessionDir, VIBE_META_FILE)));
|
|
2675
|
+
let title = meta && typeof meta.title === "string" ? meta.title : "";
|
|
2676
|
+
if (!title) title = await firstUserPromptTitle(host2, join8(sessionDir, VIBE_SESSION_FILE));
|
|
2677
|
+
return {
|
|
2678
|
+
id: meta && typeof meta.session_id === "string" ? meta.session_id : sessionDir.split(/[\\/]/).pop() || "unknown",
|
|
2679
|
+
title,
|
|
2680
|
+
directory: meta?.environment?.working_directory || meta?.origin_directory || null,
|
|
2681
|
+
createdAt: meta ? parseVibeTime(meta.start_time) : null,
|
|
2682
|
+
model: meta?.config?.active_model || null
|
|
2683
|
+
};
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/session-dirs.mjs
|
|
2687
|
+
function kimiContextTokens(tailText) {
|
|
2688
|
+
let last = null;
|
|
2689
|
+
for (const line of String(tailText ?? "").split(/\r?\n/)) {
|
|
2690
|
+
const t = line.trim();
|
|
2691
|
+
if (!t) continue;
|
|
2692
|
+
let r;
|
|
2693
|
+
try {
|
|
2694
|
+
r = JSON.parse(t);
|
|
2695
|
+
} catch {
|
|
2696
|
+
continue;
|
|
2697
|
+
}
|
|
2698
|
+
const u = r && r.usage && typeof r.usage === "object" ? r.usage : null;
|
|
2699
|
+
if (u && (typeof u.inputOther === "number" || typeof u.inputCacheRead === "number")) {
|
|
2700
|
+
last = (typeof u.inputOther === "number" ? u.inputOther : 0) + (typeof u.inputCacheRead === "number" ? u.inputCacheRead : 0);
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
return last;
|
|
2704
|
+
}
|
|
2705
|
+
async function walkKimiSessions(host2, dir, out, depth = 0) {
|
|
2706
|
+
if (depth > WALK_MAX_DEPTH) return;
|
|
2707
|
+
const entries = await host2.readDir(dir);
|
|
2708
|
+
if (!entries) return;
|
|
2709
|
+
for (const e of entries) {
|
|
2710
|
+
if (e.type !== "directory") continue;
|
|
2711
|
+
if (WALK_SKIP_DIRS.has(e.name)) continue;
|
|
2712
|
+
const rootWire = join9(e.path, "wire.jsonl");
|
|
2713
|
+
const agentWire = join9(e.path, "agents", "main", "wire.jsonl");
|
|
2714
|
+
const st = await host2.stat(rootWire);
|
|
2715
|
+
const finalSt = st && st.type === "file" ? st : await host2.stat(agentWire);
|
|
2716
|
+
if (finalSt && finalSt.type === "file") out.push(e.path);
|
|
2717
|
+
else await walkKimiSessions(host2, e.path, out, depth + 1);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
async function kimiWorkDir(host2, sessionDir, hashDirName) {
|
|
2721
|
+
if (!hashDirName) return null;
|
|
2722
|
+
let dir = dirnameOf(sessionDir);
|
|
2723
|
+
for (let i = 0; i < 6; i++) {
|
|
2724
|
+
const metaPath = join9(dir, "kimi.json");
|
|
2725
|
+
if (await host2.stat(metaPath)) {
|
|
2726
|
+
try {
|
|
2727
|
+
const meta = JSON.parse(await host2.readText(metaPath));
|
|
2728
|
+
for (const wd of meta && Array.isArray(meta.work_dirs) ? meta.work_dirs : []) {
|
|
2729
|
+
if (!wd || typeof wd.path !== "string" || !wd.path) continue;
|
|
2730
|
+
const hex = createHash("md5").update(wd.path, "utf8").digest("hex");
|
|
2731
|
+
const kaos = typeof wd.kaos === "string" && wd.kaos ? wd.kaos : "local";
|
|
2732
|
+
if (hex === hashDirName || kaos + "_" + hex === hashDirName) return wd.path;
|
|
2733
|
+
}
|
|
2734
|
+
} catch {
|
|
2735
|
+
}
|
|
2736
|
+
return null;
|
|
2737
|
+
}
|
|
2738
|
+
const next = dirnameOf(dir);
|
|
2739
|
+
if (next === dir) return null;
|
|
2740
|
+
dir = next;
|
|
2741
|
+
}
|
|
2742
|
+
return null;
|
|
2743
|
+
}
|
|
2744
|
+
async function kimiCodeWorkDir(host2, sessionDir, workspaceId) {
|
|
2745
|
+
if (!workspaceId) return null;
|
|
2746
|
+
const rawPath = String(sessionDir);
|
|
2747
|
+
const marker = rawPath.toLowerCase().indexOf(".kimi-code");
|
|
2748
|
+
const beforeMarker = rawPath[marker - 1];
|
|
2749
|
+
const afterMarker = rawPath[marker + ".kimi-code".length];
|
|
2750
|
+
if (marker < 0 || beforeMarker && !/[\\/]/.test(beforeMarker) || afterMarker && !/[\\/]/.test(afterMarker)) return null;
|
|
2751
|
+
const home = rawPath.slice(0, marker + ".kimi-code".length);
|
|
2752
|
+
const metaPath = join9(home, "workspaces.json");
|
|
2753
|
+
const st = await host2.stat(metaPath);
|
|
2754
|
+
if (!st || st.type !== "file") return null;
|
|
2755
|
+
try {
|
|
2756
|
+
const meta = JSON.parse(await host2.readText(metaPath));
|
|
2757
|
+
const entry = meta && meta.workspaces && typeof meta.workspaces === "object" ? meta.workspaces[workspaceId] : null;
|
|
2758
|
+
const root = typeof entry === "string" ? entry : entry && entry.root;
|
|
2759
|
+
return typeof root === "string" && root.trim() ? root : null;
|
|
2760
|
+
} catch {
|
|
2761
|
+
return null;
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
function kimiUserText(rec) {
|
|
2765
|
+
if (!rec || typeof rec !== "object") return "";
|
|
2766
|
+
const m = rec.message;
|
|
2767
|
+
if (m && typeof m === "object" && (m.type === "TurnBegin" || m.type === "SteerInput")) {
|
|
2768
|
+
return contentText2(m.payload && typeof m.payload === "object" ? m.payload.user_input : "");
|
|
2769
|
+
}
|
|
2770
|
+
if (rec.type === "turn.prompt") return contentText2(rec.input);
|
|
2771
|
+
if (rec.type === "context.append_message") {
|
|
2772
|
+
const message = rec.message && typeof rec.message === "object" ? rec.message : {};
|
|
2773
|
+
return message.role === "user" ? contentText2(message.content) : "";
|
|
2774
|
+
}
|
|
2775
|
+
return "";
|
|
2776
|
+
}
|
|
2777
|
+
function kimiRecordTime(rec) {
|
|
2778
|
+
if (!rec || typeof rec !== "object") return void 0;
|
|
2779
|
+
if (rec.timestamp !== void 0) return parseTimeValue(rec.timestamp);
|
|
2780
|
+
if (rec.time !== void 0) return parseTimeValue(rec.time);
|
|
2781
|
+
if (rec.created_at !== void 0) return parseTimeValue(rec.created_at);
|
|
2782
|
+
return void 0;
|
|
2783
|
+
}
|
|
2784
|
+
async function scanKimi(host2, target, { bm, emit }) {
|
|
2785
|
+
const dirs = [];
|
|
2786
|
+
const selfWire = join9(target, "wire.jsonl");
|
|
2787
|
+
const selfStat = await host2.stat(selfWire);
|
|
2788
|
+
const selfAgentWire = join9(target, "agents", "main", "wire.jsonl");
|
|
2789
|
+
const selfAgentStat = await host2.stat(selfAgentWire);
|
|
2790
|
+
if (selfStat && selfStat.type === "file" || selfAgentStat && selfAgentStat.type === "file") {
|
|
2791
|
+
dirs.push(String(target));
|
|
2792
|
+
} else {
|
|
2793
|
+
await walkKimiSessions(host2, target, dirs);
|
|
2794
|
+
}
|
|
2795
|
+
const out = [];
|
|
2796
|
+
for (const dir of dirs) {
|
|
2797
|
+
let wirePath = join9(dir, "wire.jsonl");
|
|
2798
|
+
let wst = await host2.stat(wirePath);
|
|
2799
|
+
if (!wst || wst.type !== "file") {
|
|
2800
|
+
wirePath = join9(dir, "agents", "main", "wire.jsonl");
|
|
2801
|
+
wst = await host2.stat(wirePath);
|
|
2802
|
+
}
|
|
2803
|
+
if (!wst || wst.type !== "file") continue;
|
|
2804
|
+
const statePath = join9(dir, "state.json");
|
|
2805
|
+
const sst = await host2.stat(statePath);
|
|
2806
|
+
const fp = compositeFingerprint(wst, sst);
|
|
2807
|
+
const entries = await probeSource(bm, "kimi", dir, fp, async () => {
|
|
2808
|
+
let customTitle = "";
|
|
2809
|
+
let stateCwd = "";
|
|
2810
|
+
if (sst) {
|
|
2811
|
+
try {
|
|
2812
|
+
const state = JSON.parse(await host2.readText(statePath));
|
|
2813
|
+
if (state) {
|
|
2814
|
+
if (typeof state.custom_title === "string" && state.custom_title.trim()) {
|
|
2815
|
+
customTitle = state.custom_title.trim();
|
|
2816
|
+
} else if (state.isCustomTitle === true && typeof state.title === "string" && state.title.trim()) {
|
|
2817
|
+
customTitle = state.title.trim();
|
|
2818
|
+
}
|
|
2819
|
+
const rawCwd = [state.cwd, state.workDir].find((v) => typeof v === "string" && v.trim());
|
|
2820
|
+
if (rawCwd) stateCwd = rawCwd;
|
|
2821
|
+
}
|
|
2822
|
+
} catch {
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
const head = await host2.readHead(wirePath, HEAD_MAX_BYTES);
|
|
2826
|
+
if (head === null || head === "") return [];
|
|
2827
|
+
const recs = parseJsonlHead(head);
|
|
2828
|
+
if (!recs.some((r) => kimiUserText(r))) return [];
|
|
2829
|
+
const title = customTitle || firstUserTitle(recs, kimiUserText);
|
|
2830
|
+
const createdAt = firstNumber(recs, kimiRecordTime);
|
|
2831
|
+
const hashDirName = basenameOf(dirnameOf(dir));
|
|
2832
|
+
const cwd = stateCwd || await kimiWorkDir(host2, dir, hashDirName) || await kimiCodeWorkDir(host2, dir, hashDirName);
|
|
2833
|
+
const contextTokens = wst.size <= HEAD_MAX_BYTES ? kimiContextTokens(head) : kimiContextTokens(await host2.readTail(wirePath, TAIL_MAX_BYTES));
|
|
2834
|
+
return [makeEntry({
|
|
2835
|
+
format: "kimi",
|
|
2836
|
+
sessionId: basenameOf(dir),
|
|
2837
|
+
title,
|
|
2838
|
+
project: projectFromRecord(cwd, () => hashDirName),
|
|
2839
|
+
createdAt,
|
|
2840
|
+
lastActiveAt: wst.mtimeMs,
|
|
2841
|
+
contextTokens,
|
|
2842
|
+
sourcePath: dir,
|
|
2843
|
+
cwd
|
|
2844
|
+
})];
|
|
2845
|
+
});
|
|
2846
|
+
out.push(...entries);
|
|
2847
|
+
await emitEach(emit, entries);
|
|
2848
|
+
}
|
|
2849
|
+
return out;
|
|
2850
|
+
}
|
|
2851
|
+
async function grokbuildIsSessionDir(statOf, dir) {
|
|
2852
|
+
const st = await statOf(join9(String(dir), "summary.json"));
|
|
2853
|
+
return !!(st && st.type === "file");
|
|
2854
|
+
}
|
|
2855
|
+
async function walkGrokbuildSessions(host2, dir, out, depth = 0) {
|
|
2856
|
+
if (depth > WALK_MAX_DEPTH) return;
|
|
2857
|
+
const entries = await host2.readDir(dir);
|
|
2858
|
+
if (!entries) return;
|
|
2859
|
+
for (const e of entries) {
|
|
2860
|
+
if (e.type !== "directory") continue;
|
|
2861
|
+
if (WALK_SKIP_DIRS.has(e.name)) continue;
|
|
2862
|
+
if (await grokbuildIsSessionDir((p) => host2.stat(p), e.path)) out.push(e.path);
|
|
2863
|
+
else await walkGrokbuildSessions(host2, e.path, out, depth + 1);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
async function scanGrokbuild(host2, target, { bm, emit }) {
|
|
2867
|
+
const dirs = [];
|
|
2868
|
+
await walkGrokbuildSessions(host2, target, dirs);
|
|
2869
|
+
const out = [];
|
|
2870
|
+
for (const dir of dirs) {
|
|
2871
|
+
const sst = await host2.stat(join9(dir, "summary.json"));
|
|
2872
|
+
if (!sst) continue;
|
|
2873
|
+
const cst = await host2.stat(join9(dir, "chat_history.jsonl"));
|
|
2874
|
+
const fp = compositeFingerprint(sst, cst);
|
|
2875
|
+
const entries = await probeSource(bm, "grokbuild", dir, fp, async () => {
|
|
2876
|
+
const sumRaw = await host2.readText(join9(dir, "summary.json"));
|
|
2877
|
+
if (sumRaw === null) return [];
|
|
2878
|
+
let summary;
|
|
2879
|
+
try {
|
|
2880
|
+
summary = JSON.parse(sumRaw);
|
|
2881
|
+
} catch {
|
|
2882
|
+
return [];
|
|
2883
|
+
}
|
|
2884
|
+
if (!summary || typeof summary !== "object") return [];
|
|
2885
|
+
const info = summary.info && typeof summary.info === "object" ? summary.info : {};
|
|
2886
|
+
const sessionId = typeof info.id === "string" && info.id ? info.id : basenameOf(dir);
|
|
2887
|
+
const explicit = typeof summary.generated_title === "string" && summary.generated_title.trim() ? summary.generated_title : typeof summary.session_summary === "string" && summary.session_summary.trim() ? summary.session_summary : "";
|
|
2888
|
+
const chatRaw = await host2.readHead(join9(dir, "chat_history.jsonl"), HEAD_MAX_BYTES);
|
|
2889
|
+
const recs = chatRaw ? parseJsonlHead(chatRaw) : [];
|
|
2890
|
+
const title = normalizeTitle(explicit) || firstUserTitle(recs, (r) => {
|
|
2891
|
+
if (!r || (r.type ?? r.role) !== "user") return "";
|
|
2892
|
+
const reason = typeof r.synthetic_reason === "string" && r.synthetic_reason ? r.synthetic_reason : null;
|
|
2893
|
+
if (reason && reason !== "human") return "";
|
|
2894
|
+
return stripUserQueryWrapper(contentText2(r.content));
|
|
2895
|
+
});
|
|
2896
|
+
const createdAt = parseTimeValue(summary.created_at) ?? parseTimeValue(summary.updated_at) ?? parseTimeValue(summary.last_active_at);
|
|
2897
|
+
const mtimes = [cst && cst.mtimeMs, sst && sst.mtimeMs].filter((v) => typeof v === "number");
|
|
2898
|
+
const cwd = typeof info.cwd === "string" && info.cwd ? info.cwd : null;
|
|
2899
|
+
return [makeEntry({
|
|
2900
|
+
format: "grokbuild",
|
|
2901
|
+
sessionId,
|
|
2902
|
+
title,
|
|
2903
|
+
// 项目名优先取记录内 cwd 的 basename(真实路径),缺失时按目录布局解码回退
|
|
2904
|
+
project: projectFromRecord(cwd, () => grokbuildLayoutProject(dir)),
|
|
2905
|
+
cwd,
|
|
2906
|
+
createdAt,
|
|
2907
|
+
lastActiveAt: mtimes.length ? Math.max(...mtimes) : null,
|
|
2908
|
+
sourcePath: dir
|
|
2909
|
+
})];
|
|
2910
|
+
});
|
|
2911
|
+
out.push(...entries);
|
|
2912
|
+
await emitEach(emit, entries);
|
|
2913
|
+
}
|
|
2914
|
+
return out;
|
|
2915
|
+
}
|
|
2916
|
+
async function scanVibe(host2, target, { bm, emit }) {
|
|
2917
|
+
const sessionDirs = await listVibeSessions(host2, target);
|
|
2918
|
+
const out = [];
|
|
2919
|
+
for (const dir of sessionDirs) {
|
|
2920
|
+
const msgPath = join9(dir, "messages.jsonl");
|
|
2921
|
+
const mst = await host2.stat(msgPath);
|
|
2922
|
+
if (!mst || mst.type !== "file") continue;
|
|
2923
|
+
const metaPath = join9(dir, "meta.json");
|
|
2924
|
+
const metast = await host2.stat(metaPath);
|
|
2925
|
+
const fp = compositeFingerprint(mst, metast);
|
|
2926
|
+
const entries = await probeSource(bm, "vibe", dir, fp, async () => {
|
|
2927
|
+
const summary = await readVibeSessionSummary(host2, dir);
|
|
2928
|
+
return [makeEntry({
|
|
2929
|
+
format: "vibe",
|
|
2930
|
+
sessionId: summary.id,
|
|
2931
|
+
title: normalizeTitle(summary.title),
|
|
2932
|
+
project: projectFromRecord(summary.directory, () => null),
|
|
2933
|
+
createdAt: summary.createdAt,
|
|
2934
|
+
sourcePath: dir,
|
|
2935
|
+
cwd: summary.directory || null
|
|
2936
|
+
})];
|
|
2937
|
+
});
|
|
2938
|
+
out.push(...entries);
|
|
2939
|
+
await emitEach(emit, entries);
|
|
2940
|
+
}
|
|
2941
|
+
return out;
|
|
2942
|
+
}
|
|
2943
|
+
function grokbuildLayoutProject(sourcePath) {
|
|
2944
|
+
const m = slashPath(sourcePath).match(/\/(?:sessions|archived_sessions)\/([^/]+)\/[^/]+$/);
|
|
2945
|
+
if (!m) return null;
|
|
2946
|
+
try {
|
|
2947
|
+
return basenameOf(decodeURIComponent(m[1])) || m[1];
|
|
2948
|
+
} catch {
|
|
2949
|
+
return m[1];
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
var kimiSource = {
|
|
2953
|
+
format: "kimi",
|
|
2954
|
+
roots: (home) => [join9(home, ".kimi", "sessions"), join9(home, ".kimi-code", "sessions")],
|
|
2955
|
+
scan: scanKimi,
|
|
2956
|
+
matchFile: (lower) => lower.endsWith(".jsonl") && /(\.kimi|\.kimi-code)[\\/]sessions[\\/]/.test(lower)
|
|
2957
|
+
};
|
|
2958
|
+
var grokbuildSource = {
|
|
2959
|
+
format: "grokbuild",
|
|
2960
|
+
// sessions + archived_sessions 双根;GROK_HOME 非空时替代 ~/.grok
|
|
2961
|
+
roots: (home, env) => {
|
|
2962
|
+
const grokHome = env.GROK_HOME || join9(home, ".grok");
|
|
2963
|
+
return [join9(grokHome, "sessions"), join9(grokHome, "archived_sessions")];
|
|
2964
|
+
},
|
|
2965
|
+
scan: scanGrokbuild,
|
|
2966
|
+
layoutProject: grokbuildLayoutProject
|
|
2967
|
+
};
|
|
2968
|
+
var vibeSource = {
|
|
2969
|
+
format: "vibe",
|
|
2970
|
+
roots: (home) => vibeUserDataDirs(home),
|
|
2971
|
+
scan: scanVibe,
|
|
2972
|
+
matchFile: (lower) => lower.endsWith(".jsonl") && /(\.vibe[\\/]logs[\\/]session|messages\.jsonl$)/.test(lower)
|
|
2973
|
+
};
|
|
2974
|
+
|
|
2975
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/documents.mjs
|
|
2976
|
+
import { join as join10 } from "node:path";
|
|
2977
|
+
async function scanChatgpt(host2, target, { bm, emit }) {
|
|
2978
|
+
const st = await host2.stat(target);
|
|
2979
|
+
if (!st) return [];
|
|
2980
|
+
let file = target;
|
|
2981
|
+
if (st.type === "directory") {
|
|
2982
|
+
const candidate = join10(target, "conversations.json");
|
|
2983
|
+
const cst = await host2.stat(candidate);
|
|
2984
|
+
if (!cst || cst.type !== "file") return [];
|
|
2985
|
+
file = candidate;
|
|
2986
|
+
} else if (!/\.json$/i.test(target)) {
|
|
2987
|
+
return [];
|
|
2988
|
+
}
|
|
2989
|
+
const fst = await host2.stat(file);
|
|
2990
|
+
if (!fst) return [];
|
|
2991
|
+
const fp = fileFingerprint(fst);
|
|
2992
|
+
const entries = await probeSource(bm, "chatgpt", file, fp, async () => {
|
|
2993
|
+
const raw = await host2.readText(file);
|
|
2994
|
+
if (raw === null || raw === "") return [];
|
|
2995
|
+
let list;
|
|
2996
|
+
try {
|
|
2997
|
+
list = JSON.parse(raw);
|
|
2998
|
+
} catch {
|
|
2999
|
+
return [];
|
|
3000
|
+
}
|
|
3001
|
+
if (!Array.isArray(list)) return [];
|
|
3002
|
+
const out = [];
|
|
3003
|
+
for (const conv of list) {
|
|
3004
|
+
if (!conv || typeof conv !== "object" || typeof conv.id !== "string") continue;
|
|
3005
|
+
const mapping = conv.mapping && typeof conv.mapping === "object" ? conv.mapping : {};
|
|
3006
|
+
let lastTs;
|
|
3007
|
+
for (const node of Object.values(mapping)) {
|
|
3008
|
+
if (!node || typeof node !== "object" || !node.message || typeof node.message !== "object") continue;
|
|
3009
|
+
const t = parseTimeValue(node.message.create_time);
|
|
3010
|
+
if (t !== void 0 && (lastTs === void 0 || t > lastTs)) lastTs = t;
|
|
3011
|
+
}
|
|
3012
|
+
out.push(makeEntry({
|
|
3013
|
+
format: "chatgpt",
|
|
3014
|
+
sessionId: conv.id,
|
|
3015
|
+
title: typeof conv.title === "string" && conv.title.trim() ? normalizeTitle(conv.title) : null,
|
|
3016
|
+
project: null,
|
|
3017
|
+
createdAt: parseTimeValue(conv.create_time),
|
|
3018
|
+
lastActiveAt: lastTs,
|
|
3019
|
+
sourcePath: file
|
|
3020
|
+
}));
|
|
3021
|
+
}
|
|
3022
|
+
return out;
|
|
3023
|
+
});
|
|
3024
|
+
await emitEach(emit, entries);
|
|
3025
|
+
return entries;
|
|
3026
|
+
}
|
|
3027
|
+
async function scanContinue(host2, target, { bm, emit }) {
|
|
3028
|
+
const files = [];
|
|
3029
|
+
await walkFiles(host2, target, files, (name) => /\.json$/i.test(name));
|
|
3030
|
+
let index = /* @__PURE__ */ new Map();
|
|
3031
|
+
for (const file of files) {
|
|
3032
|
+
if (basenameOf(file.name).toLowerCase() !== "sessions.json") continue;
|
|
3033
|
+
const raw = await host2.readText(file.path);
|
|
3034
|
+
if (raw === null || raw === "") continue;
|
|
3035
|
+
index = readContinueIndex(raw);
|
|
3036
|
+
break;
|
|
3037
|
+
}
|
|
3038
|
+
const out = [];
|
|
3039
|
+
for (const file of files) {
|
|
3040
|
+
if (basenameOf(file.name).toLowerCase() === "sessions.json") continue;
|
|
3041
|
+
const stem = basenameOf(file.name).replace(/\.json$/i, "");
|
|
3042
|
+
const st = await host2.stat(file.path);
|
|
3043
|
+
if (!st) continue;
|
|
3044
|
+
const fp = fileFingerprint(st);
|
|
3045
|
+
const known = index.get(stem) || null;
|
|
3046
|
+
const entries = await probeSource(bm, "continue", file.path, fp, async () => {
|
|
3047
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
3048
|
+
if (head === null || head === "" || !/"sessionId"\s*:/.test(head) || !/"history"\s*:/.test(head)) return [];
|
|
3049
|
+
let createdAt = known ? known.createdAt : void 0;
|
|
3050
|
+
let cwd = known ? known.cwd : null;
|
|
3051
|
+
let title = known ? known.title : "";
|
|
3052
|
+
let sessionId = stem;
|
|
3053
|
+
if (!known) {
|
|
3054
|
+
const raw = await host2.readText(file.path);
|
|
3055
|
+
if (raw === null || raw === "") return [];
|
|
3056
|
+
let session;
|
|
3057
|
+
try {
|
|
3058
|
+
session = JSON.parse(raw);
|
|
3059
|
+
} catch {
|
|
3060
|
+
return [];
|
|
3061
|
+
}
|
|
3062
|
+
if (!session || typeof session !== "object" || !Array.isArray(session.history)) return [];
|
|
3063
|
+
sessionId = typeof session.sessionId === "string" && session.sessionId ? session.sessionId : stem;
|
|
3064
|
+
title = typeof session.title === "string" ? session.title : "";
|
|
3065
|
+
cwd = typeof session.workspaceDirectory === "string" && session.workspaceDirectory ? session.workspaceDirectory : null;
|
|
3066
|
+
}
|
|
3067
|
+
return [makeEntry({
|
|
3068
|
+
format: "continue",
|
|
3069
|
+
sessionId,
|
|
3070
|
+
// 默认标题('New Session')不是用户起的名字 → 交给首问兜底
|
|
3071
|
+
title: normalizeTitle(title === "New Session" ? "" : title),
|
|
3072
|
+
project: projectFromRecord(cwd, () => null),
|
|
3073
|
+
createdAt: createdAt ?? void 0,
|
|
3074
|
+
lastActiveAt: st.mtimeMs,
|
|
3075
|
+
sourcePath: file.path,
|
|
3076
|
+
cwd
|
|
3077
|
+
})];
|
|
3078
|
+
});
|
|
3079
|
+
out.push(...entries);
|
|
3080
|
+
await emitEach(emit, entries);
|
|
3081
|
+
}
|
|
3082
|
+
return out;
|
|
3083
|
+
}
|
|
3084
|
+
var continueSource = {
|
|
3085
|
+
format: "continue",
|
|
3086
|
+
// 全局单一会话目录(VS Code / JetBrains / CLI 三端共用);与 Continue core 同序:
|
|
3087
|
+
// $CONTINUE_GLOBAL_DIR 优先、否则 ~/.continue
|
|
3088
|
+
roots: (home, env) => env.CONTINUE_GLOBAL_DIR ? join10(env.CONTINUE_GLOBAL_DIR, "sessions") : join10(home, ".continue", "sessions"),
|
|
3089
|
+
scan: scanContinue,
|
|
3090
|
+
// 会话文件是单个 JSON 对象且路径特征唯一 → 独占,不落到 gemini/chatgpt 探测
|
|
3091
|
+
matchFile: (lower) => lower.endsWith(".json") && /(^|[\\/])\.continue[\\/]sessions[\\/]/.test(lower) ? "only" : false
|
|
3092
|
+
};
|
|
3093
|
+
var chatgptSource = {
|
|
3094
|
+
format: "chatgpt",
|
|
3095
|
+
// 官方导出无固定落点:只在显式 path 时发现
|
|
3096
|
+
roots: () => null,
|
|
3097
|
+
scan: scanChatgpt,
|
|
3098
|
+
fileFallback: ["json"]
|
|
3099
|
+
};
|
|
3100
|
+
|
|
3101
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/dsh.mjs
|
|
3102
|
+
import { join as join11 } from "node:path";
|
|
3103
|
+
|
|
3104
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/dsh.mjs
|
|
3105
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
3106
|
+
|
|
3107
|
+
// .codex-tmp/vendor-pagination-upstream/node_modules/fzstd/esm/index.mjs
|
|
3108
|
+
var ab = ArrayBuffer;
|
|
3109
|
+
var u8 = Uint8Array;
|
|
3110
|
+
var u16 = Uint16Array;
|
|
3111
|
+
var i16 = Int16Array;
|
|
3112
|
+
var i32 = Int32Array;
|
|
3113
|
+
var slc = function(v, s, e) {
|
|
3114
|
+
if (u8.prototype.slice)
|
|
3115
|
+
return u8.prototype.slice.call(v, s, e);
|
|
3116
|
+
if (s == null || s < 0)
|
|
3117
|
+
s = 0;
|
|
3118
|
+
if (e == null || e > v.length)
|
|
3119
|
+
e = v.length;
|
|
3120
|
+
var n = new u8(e - s);
|
|
3121
|
+
n.set(v.subarray(s, e));
|
|
3122
|
+
return n;
|
|
3123
|
+
};
|
|
3124
|
+
var fill = function(v, n, s, e) {
|
|
3125
|
+
if (u8.prototype.fill)
|
|
3126
|
+
return u8.prototype.fill.call(v, n, s, e);
|
|
3127
|
+
if (s == null || s < 0)
|
|
3128
|
+
s = 0;
|
|
3129
|
+
if (e == null || e > v.length)
|
|
3130
|
+
e = v.length;
|
|
3131
|
+
for (; s < e; ++s)
|
|
3132
|
+
v[s] = n;
|
|
3133
|
+
return v;
|
|
3134
|
+
};
|
|
3135
|
+
var cpw = function(v, t, s, e) {
|
|
3136
|
+
if (u8.prototype.copyWithin)
|
|
3137
|
+
return u8.prototype.copyWithin.call(v, t, s, e);
|
|
3138
|
+
if (s == null || s < 0)
|
|
3139
|
+
s = 0;
|
|
3140
|
+
if (e == null || e > v.length)
|
|
3141
|
+
e = v.length;
|
|
3142
|
+
while (s < e) {
|
|
3143
|
+
v[t++] = v[s++];
|
|
3144
|
+
}
|
|
3145
|
+
};
|
|
3146
|
+
var ec = [
|
|
3147
|
+
"invalid zstd data",
|
|
3148
|
+
"window size too large (>2046MB)",
|
|
3149
|
+
"invalid block type",
|
|
3150
|
+
"FSE accuracy too high",
|
|
3151
|
+
"match distance too far back",
|
|
3152
|
+
"unexpected EOF"
|
|
3153
|
+
];
|
|
3154
|
+
var err = function(ind, msg, nt) {
|
|
3155
|
+
var e = new Error(msg || ec[ind]);
|
|
3156
|
+
e.code = ind;
|
|
3157
|
+
if (Error.captureStackTrace)
|
|
3158
|
+
Error.captureStackTrace(e, err);
|
|
3159
|
+
if (!nt)
|
|
3160
|
+
throw e;
|
|
3161
|
+
return e;
|
|
3162
|
+
};
|
|
3163
|
+
var rb = function(d, b, n) {
|
|
3164
|
+
var i = 0, o = 0;
|
|
3165
|
+
for (; i < n; ++i)
|
|
3166
|
+
o |= d[b++] << (i << 3);
|
|
3167
|
+
return o;
|
|
3168
|
+
};
|
|
3169
|
+
var b4 = function(d, b) {
|
|
3170
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
3171
|
+
};
|
|
3172
|
+
var rzfh = function(dat, w) {
|
|
3173
|
+
var n3 = dat[0] | dat[1] << 8 | dat[2] << 16;
|
|
3174
|
+
if (n3 == 3126568 && dat[3] == 253) {
|
|
3175
|
+
var flg = dat[4];
|
|
3176
|
+
var ss = flg >> 5 & 1, cc = flg >> 2 & 1, df = flg & 3, fcf = flg >> 6;
|
|
3177
|
+
if (flg & 8)
|
|
3178
|
+
err(0);
|
|
3179
|
+
var bt = 6 - ss;
|
|
3180
|
+
var db = df == 3 ? 4 : df;
|
|
3181
|
+
var di = rb(dat, bt, db);
|
|
3182
|
+
bt += db;
|
|
3183
|
+
var fsb = fcf ? 1 << fcf : ss;
|
|
3184
|
+
var fss = rb(dat, bt, fsb) + (fcf == 1 && 256);
|
|
3185
|
+
var ws = fss;
|
|
3186
|
+
if (!ss) {
|
|
3187
|
+
var wb = 1 << 10 + (dat[5] >> 3);
|
|
3188
|
+
ws = wb + (wb >> 3) * (dat[5] & 7);
|
|
3189
|
+
}
|
|
3190
|
+
if (ws > 2145386496)
|
|
3191
|
+
err(1);
|
|
3192
|
+
var buf = new u8((w == 1 ? fss || ws : w ? 0 : ws) + 12);
|
|
3193
|
+
buf[0] = 1, buf[4] = 4, buf[8] = 8;
|
|
3194
|
+
return {
|
|
3195
|
+
b: bt + fsb,
|
|
3196
|
+
y: 0,
|
|
3197
|
+
l: 0,
|
|
3198
|
+
d: di,
|
|
3199
|
+
w: w && w != 1 ? w : buf.subarray(12),
|
|
3200
|
+
e: ws,
|
|
3201
|
+
o: new i32(buf.buffer, 0, 3),
|
|
3202
|
+
u: fss,
|
|
3203
|
+
c: cc,
|
|
3204
|
+
m: Math.min(131072, ws)
|
|
3205
|
+
};
|
|
3206
|
+
} else if ((n3 >> 4 | dat[3] << 20) == 25481893) {
|
|
3207
|
+
return b4(dat, 4) + 8;
|
|
3208
|
+
}
|
|
3209
|
+
err(0);
|
|
3210
|
+
};
|
|
3211
|
+
var msb = function(val) {
|
|
3212
|
+
var bits = 0;
|
|
3213
|
+
for (; 1 << bits <= val; ++bits)
|
|
3214
|
+
;
|
|
3215
|
+
return bits - 1;
|
|
3216
|
+
};
|
|
3217
|
+
var rfse = function(dat, bt, mal) {
|
|
3218
|
+
var tpos = (bt << 3) + 4;
|
|
3219
|
+
var al = (dat[bt] & 15) + 5;
|
|
3220
|
+
if (al > mal)
|
|
3221
|
+
err(3);
|
|
3222
|
+
var sz = 1 << al;
|
|
3223
|
+
var probs = sz, sym = -1, re = -1, i = -1, ht = sz;
|
|
3224
|
+
var buf = new ab(512 + (sz << 2));
|
|
3225
|
+
var freq = new i16(buf, 0, 256);
|
|
3226
|
+
var dstate = new u16(buf, 0, 256);
|
|
3227
|
+
var nstate = new u16(buf, 512, sz);
|
|
3228
|
+
var bb1 = 512 + (sz << 1);
|
|
3229
|
+
var syms = new u8(buf, bb1, sz);
|
|
3230
|
+
var nbits = new u8(buf, bb1 + sz);
|
|
3231
|
+
while (sym < 255 && probs > 0) {
|
|
3232
|
+
var bits = msb(probs + 1);
|
|
3233
|
+
var cbt = tpos >> 3;
|
|
3234
|
+
var msk = (1 << bits + 1) - 1;
|
|
3235
|
+
var val = (dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (tpos & 7) & msk;
|
|
3236
|
+
var msk1fb = (1 << bits) - 1;
|
|
3237
|
+
var msv = msk - probs - 1;
|
|
3238
|
+
var sval = val & msk1fb;
|
|
3239
|
+
if (sval < msv)
|
|
3240
|
+
tpos += bits, val = sval;
|
|
3241
|
+
else {
|
|
3242
|
+
tpos += bits + 1;
|
|
3243
|
+
if (val > msk1fb)
|
|
3244
|
+
val -= msv;
|
|
3245
|
+
}
|
|
3246
|
+
freq[++sym] = --val;
|
|
3247
|
+
if (val == -1) {
|
|
3248
|
+
probs += val;
|
|
3249
|
+
syms[--ht] = sym;
|
|
3250
|
+
} else
|
|
3251
|
+
probs -= val;
|
|
3252
|
+
if (!val) {
|
|
3253
|
+
do {
|
|
3254
|
+
var rbt = tpos >> 3;
|
|
3255
|
+
re = (dat[rbt] | dat[rbt + 1] << 8) >> (tpos & 7) & 3;
|
|
3256
|
+
tpos += 2;
|
|
3257
|
+
sym += re;
|
|
3258
|
+
} while (re == 3);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
if (sym > 255 || probs)
|
|
3262
|
+
err(0);
|
|
3263
|
+
var sympos = 0;
|
|
3264
|
+
var sstep = (sz >> 1) + (sz >> 3) + 3;
|
|
3265
|
+
var smask = sz - 1;
|
|
3266
|
+
for (var s = 0; s <= sym; ++s) {
|
|
3267
|
+
var sf = freq[s];
|
|
3268
|
+
if (sf < 1) {
|
|
3269
|
+
dstate[s] = -sf;
|
|
3270
|
+
continue;
|
|
3271
|
+
}
|
|
3272
|
+
for (i = 0; i < sf; ++i) {
|
|
3273
|
+
syms[sympos] = s;
|
|
3274
|
+
do {
|
|
3275
|
+
sympos = sympos + sstep & smask;
|
|
3276
|
+
} while (sympos >= ht);
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
if (sympos)
|
|
3280
|
+
err(0);
|
|
3281
|
+
for (i = 0; i < sz; ++i) {
|
|
3282
|
+
var ns = dstate[syms[i]]++;
|
|
3283
|
+
var nb = nbits[i] = al - msb(ns);
|
|
3284
|
+
nstate[i] = (ns << nb) - sz;
|
|
3285
|
+
}
|
|
3286
|
+
return [tpos + 7 >> 3, {
|
|
3287
|
+
b: al,
|
|
3288
|
+
s: syms,
|
|
3289
|
+
n: nbits,
|
|
3290
|
+
t: nstate
|
|
3291
|
+
}];
|
|
3292
|
+
};
|
|
3293
|
+
var rhu = function(dat, bt) {
|
|
3294
|
+
var i = 0, wc = -1;
|
|
3295
|
+
var buf = new u8(292), hb = dat[bt];
|
|
3296
|
+
var hw = buf.subarray(0, 256);
|
|
3297
|
+
var rc = buf.subarray(256, 268);
|
|
3298
|
+
var ri = new u16(buf.buffer, 268);
|
|
3299
|
+
if (hb < 128) {
|
|
3300
|
+
var _a = rfse(dat, bt + 1, 6), ebt = _a[0], fdt = _a[1];
|
|
3301
|
+
bt += hb;
|
|
3302
|
+
var epos = ebt << 3;
|
|
3303
|
+
var lb = dat[bt];
|
|
3304
|
+
if (!lb)
|
|
3305
|
+
err(0);
|
|
3306
|
+
var st1 = 0, st2 = 0, btr1 = fdt.b, btr2 = btr1;
|
|
3307
|
+
var fpos = (++bt << 3) - 8 + msb(lb);
|
|
3308
|
+
for (; ; ) {
|
|
3309
|
+
fpos -= btr1;
|
|
3310
|
+
if (fpos < epos)
|
|
3311
|
+
break;
|
|
3312
|
+
var cbt = fpos >> 3;
|
|
3313
|
+
st1 += (dat[cbt] | dat[cbt + 1] << 8) >> (fpos & 7) & (1 << btr1) - 1;
|
|
3314
|
+
hw[++wc] = fdt.s[st1];
|
|
3315
|
+
fpos -= btr2;
|
|
3316
|
+
if (fpos < epos)
|
|
3317
|
+
break;
|
|
3318
|
+
cbt = fpos >> 3;
|
|
3319
|
+
st2 += (dat[cbt] | dat[cbt + 1] << 8) >> (fpos & 7) & (1 << btr2) - 1;
|
|
3320
|
+
hw[++wc] = fdt.s[st2];
|
|
3321
|
+
btr1 = fdt.n[st1];
|
|
3322
|
+
st1 = fdt.t[st1];
|
|
3323
|
+
btr2 = fdt.n[st2];
|
|
3324
|
+
st2 = fdt.t[st2];
|
|
3325
|
+
}
|
|
3326
|
+
if (++wc > 255)
|
|
3327
|
+
err(0);
|
|
3328
|
+
} else {
|
|
3329
|
+
wc = hb - 127;
|
|
3330
|
+
for (; i < wc; i += 2) {
|
|
3331
|
+
var byte = dat[++bt];
|
|
3332
|
+
hw[i] = byte >> 4;
|
|
3333
|
+
hw[i + 1] = byte & 15;
|
|
3334
|
+
}
|
|
3335
|
+
++bt;
|
|
3336
|
+
}
|
|
3337
|
+
var wes = 0;
|
|
3338
|
+
for (i = 0; i < wc; ++i) {
|
|
3339
|
+
var wt = hw[i];
|
|
3340
|
+
if (wt > 11)
|
|
3341
|
+
err(0);
|
|
3342
|
+
wes += wt && 1 << wt - 1;
|
|
3343
|
+
}
|
|
3344
|
+
var mb = msb(wes) + 1;
|
|
3345
|
+
var ts = 1 << mb;
|
|
3346
|
+
var rem = ts - wes;
|
|
3347
|
+
if (rem & rem - 1)
|
|
3348
|
+
err(0);
|
|
3349
|
+
hw[wc++] = msb(rem) + 1;
|
|
3350
|
+
for (i = 0; i < wc; ++i) {
|
|
3351
|
+
var wt = hw[i];
|
|
3352
|
+
++rc[hw[i] = wt && mb + 1 - wt];
|
|
3353
|
+
}
|
|
3354
|
+
var hbuf = new u8(ts << 1);
|
|
3355
|
+
var syms = hbuf.subarray(0, ts), nb = hbuf.subarray(ts);
|
|
3356
|
+
ri[mb] = 0;
|
|
3357
|
+
for (i = mb; i > 0; --i) {
|
|
3358
|
+
var pv = ri[i];
|
|
3359
|
+
fill(nb, i, pv, ri[i - 1] = pv + rc[i] * (1 << mb - i));
|
|
3360
|
+
}
|
|
3361
|
+
if (ri[0] != ts)
|
|
3362
|
+
err(0);
|
|
3363
|
+
for (i = 0; i < wc; ++i) {
|
|
3364
|
+
var bits = hw[i];
|
|
3365
|
+
if (bits) {
|
|
3366
|
+
var code = ri[bits];
|
|
3367
|
+
fill(syms, i, code, ri[bits] = code + (1 << mb - bits));
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
return [bt, {
|
|
3371
|
+
n: nb,
|
|
3372
|
+
b: mb,
|
|
3373
|
+
s: syms
|
|
3374
|
+
}];
|
|
3375
|
+
};
|
|
3376
|
+
var dllt = rfse(/* @__PURE__ */ new u8([
|
|
3377
|
+
81,
|
|
3378
|
+
16,
|
|
3379
|
+
99,
|
|
3380
|
+
140,
|
|
3381
|
+
49,
|
|
3382
|
+
198,
|
|
3383
|
+
24,
|
|
3384
|
+
99,
|
|
3385
|
+
12,
|
|
3386
|
+
33,
|
|
3387
|
+
196,
|
|
3388
|
+
24,
|
|
3389
|
+
99,
|
|
3390
|
+
102,
|
|
3391
|
+
102,
|
|
3392
|
+
134,
|
|
3393
|
+
70,
|
|
3394
|
+
146,
|
|
3395
|
+
4
|
|
3396
|
+
]), 0, 6)[1];
|
|
3397
|
+
var dmlt = rfse(/* @__PURE__ */ new u8([
|
|
3398
|
+
33,
|
|
3399
|
+
20,
|
|
3400
|
+
196,
|
|
3401
|
+
24,
|
|
3402
|
+
99,
|
|
3403
|
+
140,
|
|
3404
|
+
33,
|
|
3405
|
+
132,
|
|
3406
|
+
16,
|
|
3407
|
+
66,
|
|
3408
|
+
8,
|
|
3409
|
+
33,
|
|
3410
|
+
132,
|
|
3411
|
+
16,
|
|
3412
|
+
66,
|
|
3413
|
+
8,
|
|
3414
|
+
33,
|
|
3415
|
+
68,
|
|
3416
|
+
68,
|
|
3417
|
+
68,
|
|
3418
|
+
68,
|
|
3419
|
+
68,
|
|
3420
|
+
68,
|
|
3421
|
+
68,
|
|
3422
|
+
68,
|
|
3423
|
+
36,
|
|
3424
|
+
9
|
|
3425
|
+
]), 0, 6)[1];
|
|
3426
|
+
var doct = rfse(/* @__PURE__ */ new u8([
|
|
3427
|
+
32,
|
|
3428
|
+
132,
|
|
3429
|
+
16,
|
|
3430
|
+
66,
|
|
3431
|
+
102,
|
|
3432
|
+
70,
|
|
3433
|
+
68,
|
|
3434
|
+
68,
|
|
3435
|
+
68,
|
|
3436
|
+
68,
|
|
3437
|
+
36,
|
|
3438
|
+
73,
|
|
3439
|
+
2
|
|
3440
|
+
]), 0, 5)[1];
|
|
3441
|
+
var b2bl = function(b, s) {
|
|
3442
|
+
var len = b.length, bl = new i32(len);
|
|
3443
|
+
for (var i = 0; i < len; ++i) {
|
|
3444
|
+
bl[i] = s;
|
|
3445
|
+
s += 1 << b[i];
|
|
3446
|
+
}
|
|
3447
|
+
return bl;
|
|
3448
|
+
};
|
|
3449
|
+
var llb = /* @__PURE__ */ new u8((/* @__PURE__ */ new i32([
|
|
3450
|
+
0,
|
|
3451
|
+
0,
|
|
3452
|
+
0,
|
|
3453
|
+
0,
|
|
3454
|
+
16843009,
|
|
3455
|
+
50528770,
|
|
3456
|
+
134678020,
|
|
3457
|
+
202050057,
|
|
3458
|
+
269422093
|
|
3459
|
+
])).buffer, 0, 36);
|
|
3460
|
+
var llbl = /* @__PURE__ */ b2bl(llb, 0);
|
|
3461
|
+
var mlb = /* @__PURE__ */ new u8((/* @__PURE__ */ new i32([
|
|
3462
|
+
0,
|
|
3463
|
+
0,
|
|
3464
|
+
0,
|
|
3465
|
+
0,
|
|
3466
|
+
0,
|
|
3467
|
+
0,
|
|
3468
|
+
0,
|
|
3469
|
+
0,
|
|
3470
|
+
16843009,
|
|
3471
|
+
50528770,
|
|
3472
|
+
117769220,
|
|
3473
|
+
185207048,
|
|
3474
|
+
252579084,
|
|
3475
|
+
16
|
|
3476
|
+
])).buffer, 0, 53);
|
|
3477
|
+
var mlbl = /* @__PURE__ */ b2bl(mlb, 3);
|
|
3478
|
+
var dhu = function(dat, out, hu) {
|
|
3479
|
+
var len = dat.length, ss = out.length, lb = dat[len - 1], msk = (1 << hu.b) - 1, eb = -hu.b;
|
|
3480
|
+
if (!lb)
|
|
3481
|
+
err(0);
|
|
3482
|
+
var st = 0, btr = hu.b, pos = (len << 3) - 8 + msb(lb) - btr, i = -1;
|
|
3483
|
+
for (; pos > eb && i < ss; ) {
|
|
3484
|
+
var cbt = pos >> 3;
|
|
3485
|
+
var val = (dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (pos & 7);
|
|
3486
|
+
st = (st << btr | val) & msk;
|
|
3487
|
+
out[++i] = hu.s[st];
|
|
3488
|
+
pos -= btr = hu.n[st];
|
|
3489
|
+
}
|
|
3490
|
+
if (pos != eb || i + 1 != ss)
|
|
3491
|
+
err(0);
|
|
3492
|
+
};
|
|
3493
|
+
var dhu4 = function(dat, out, hu) {
|
|
3494
|
+
var bt = 6;
|
|
3495
|
+
var ss = out.length, sz1 = ss + 3 >> 2, sz2 = sz1 << 1, sz3 = sz1 + sz2;
|
|
3496
|
+
dhu(dat.subarray(bt, bt += dat[0] | dat[1] << 8), out.subarray(0, sz1), hu);
|
|
3497
|
+
dhu(dat.subarray(bt, bt += dat[2] | dat[3] << 8), out.subarray(sz1, sz2), hu);
|
|
3498
|
+
dhu(dat.subarray(bt, bt += dat[4] | dat[5] << 8), out.subarray(sz2, sz3), hu);
|
|
3499
|
+
dhu(dat.subarray(bt), out.subarray(sz3), hu);
|
|
3500
|
+
};
|
|
3501
|
+
var rzb = function(dat, st, out) {
|
|
3502
|
+
var _a;
|
|
3503
|
+
var bt = st.b;
|
|
3504
|
+
var b0 = dat[bt], btype = b0 >> 1 & 3;
|
|
3505
|
+
st.l = b0 & 1;
|
|
3506
|
+
var sz = b0 >> 3 | dat[bt + 1] << 5 | dat[bt + 2] << 13;
|
|
3507
|
+
var ebt = (bt += 3) + sz;
|
|
3508
|
+
if (btype == 1) {
|
|
3509
|
+
if (bt >= dat.length)
|
|
3510
|
+
return;
|
|
3511
|
+
st.b = bt + 1;
|
|
3512
|
+
if (out) {
|
|
3513
|
+
fill(out, dat[bt], st.y, st.y += sz);
|
|
3514
|
+
return out;
|
|
3515
|
+
}
|
|
3516
|
+
return fill(new u8(sz), dat[bt]);
|
|
3517
|
+
}
|
|
3518
|
+
if (ebt > dat.length)
|
|
3519
|
+
return;
|
|
3520
|
+
if (btype == 0) {
|
|
3521
|
+
st.b = ebt;
|
|
3522
|
+
if (out) {
|
|
3523
|
+
out.set(dat.subarray(bt, ebt), st.y);
|
|
3524
|
+
st.y += sz;
|
|
3525
|
+
return out;
|
|
3526
|
+
}
|
|
3527
|
+
return slc(dat, bt, ebt);
|
|
3528
|
+
}
|
|
3529
|
+
if (btype == 2) {
|
|
3530
|
+
var b3 = dat[bt], lbt = b3 & 3, sf = b3 >> 2 & 3;
|
|
3531
|
+
var lss = b3 >> 4, lcs = 0, s4 = 0;
|
|
3532
|
+
if (lbt < 2) {
|
|
3533
|
+
if (sf & 1)
|
|
3534
|
+
lss |= dat[++bt] << 4 | (sf & 2 && dat[++bt] << 12);
|
|
3535
|
+
else
|
|
3536
|
+
lss = b3 >> 3;
|
|
3537
|
+
} else {
|
|
3538
|
+
s4 = sf;
|
|
3539
|
+
if (sf < 2)
|
|
3540
|
+
lss |= (dat[++bt] & 63) << 4, lcs = dat[bt] >> 6 | dat[++bt] << 2;
|
|
3541
|
+
else if (sf == 2)
|
|
3542
|
+
lss |= dat[++bt] << 4 | (dat[++bt] & 3) << 12, lcs = dat[bt] >> 2 | dat[++bt] << 6;
|
|
3543
|
+
else
|
|
3544
|
+
lss |= dat[++bt] << 4 | (dat[++bt] & 63) << 12, lcs = dat[bt] >> 6 | dat[++bt] << 2 | dat[++bt] << 10;
|
|
3545
|
+
}
|
|
3546
|
+
++bt;
|
|
3547
|
+
var buf = out ? out.subarray(st.y, st.y + st.m) : new u8(st.m);
|
|
3548
|
+
var spl = buf.length - lss;
|
|
3549
|
+
if (lbt == 0)
|
|
3550
|
+
buf.set(dat.subarray(bt, bt += lss), spl);
|
|
3551
|
+
else if (lbt == 1)
|
|
3552
|
+
fill(buf, dat[bt++], spl);
|
|
3553
|
+
else {
|
|
3554
|
+
var hu = st.h;
|
|
3555
|
+
if (lbt == 2) {
|
|
3556
|
+
var hud = rhu(dat, bt);
|
|
3557
|
+
lcs += bt - (bt = hud[0]);
|
|
3558
|
+
st.h = hu = hud[1];
|
|
3559
|
+
} else if (!hu)
|
|
3560
|
+
err(0);
|
|
3561
|
+
(s4 ? dhu4 : dhu)(dat.subarray(bt, bt += lcs), buf.subarray(spl), hu);
|
|
3562
|
+
}
|
|
3563
|
+
var ns = dat[bt++];
|
|
3564
|
+
if (ns) {
|
|
3565
|
+
if (ns == 255)
|
|
3566
|
+
ns = (dat[bt++] | dat[bt++] << 8) + 32512;
|
|
3567
|
+
else if (ns > 127)
|
|
3568
|
+
ns = ns - 128 << 8 | dat[bt++];
|
|
3569
|
+
var scm = dat[bt++];
|
|
3570
|
+
if (scm & 3)
|
|
3571
|
+
err(0);
|
|
3572
|
+
var dts = [dmlt, doct, dllt];
|
|
3573
|
+
for (var i = 2; i > -1; --i) {
|
|
3574
|
+
var md = scm >> (i << 1) + 2 & 3;
|
|
3575
|
+
if (md == 1) {
|
|
3576
|
+
var rbuf = new u8([0, 0, dat[bt++]]);
|
|
3577
|
+
dts[i] = {
|
|
3578
|
+
s: rbuf.subarray(2, 3),
|
|
3579
|
+
n: rbuf.subarray(0, 1),
|
|
3580
|
+
t: new u16(rbuf.buffer, 0, 1),
|
|
3581
|
+
b: 0
|
|
3582
|
+
};
|
|
3583
|
+
} else if (md == 2) {
|
|
3584
|
+
_a = rfse(dat, bt, 9 - (i & 1)), bt = _a[0], dts[i] = _a[1];
|
|
3585
|
+
} else if (md == 3) {
|
|
3586
|
+
if (!st.t)
|
|
3587
|
+
err(0);
|
|
3588
|
+
dts[i] = st.t[i];
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
var _b = st.t = dts, mlt = _b[0], oct = _b[1], llt = _b[2];
|
|
3592
|
+
var lb = dat[ebt - 1];
|
|
3593
|
+
if (!lb)
|
|
3594
|
+
err(0);
|
|
3595
|
+
var spos = (ebt << 3) - 8 + msb(lb) - llt.b, cbt = spos >> 3, oubt = 0;
|
|
3596
|
+
var lst = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << llt.b) - 1;
|
|
3597
|
+
cbt = (spos -= oct.b) >> 3;
|
|
3598
|
+
var ost = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << oct.b) - 1;
|
|
3599
|
+
cbt = (spos -= mlt.b) >> 3;
|
|
3600
|
+
var mst = (dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << mlt.b) - 1;
|
|
3601
|
+
for (++ns; --ns; ) {
|
|
3602
|
+
var llc = llt.s[lst];
|
|
3603
|
+
var lbtr = llt.n[lst];
|
|
3604
|
+
var mlc = mlt.s[mst];
|
|
3605
|
+
var mbtr = mlt.n[mst];
|
|
3606
|
+
var ofc = oct.s[ost];
|
|
3607
|
+
var obtr = oct.n[ost];
|
|
3608
|
+
cbt = (spos -= ofc) >> 3;
|
|
3609
|
+
var ofp = 1 << ofc;
|
|
3610
|
+
var off = ofp + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16 | dat[cbt + 3] << 24) >>> (spos & 7) & ofp - 1);
|
|
3611
|
+
cbt = (spos -= mlb[mlc]) >> 3;
|
|
3612
|
+
var ml = mlbl[mlc] + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (spos & 7) & (1 << mlb[mlc]) - 1);
|
|
3613
|
+
cbt = (spos -= llb[llc]) >> 3;
|
|
3614
|
+
var ll = llbl[llc] + ((dat[cbt] | dat[cbt + 1] << 8 | dat[cbt + 2] << 16) >> (spos & 7) & (1 << llb[llc]) - 1);
|
|
3615
|
+
cbt = (spos -= lbtr) >> 3;
|
|
3616
|
+
lst = llt.t[lst] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << lbtr) - 1);
|
|
3617
|
+
cbt = (spos -= mbtr) >> 3;
|
|
3618
|
+
mst = mlt.t[mst] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << mbtr) - 1);
|
|
3619
|
+
cbt = (spos -= obtr) >> 3;
|
|
3620
|
+
ost = oct.t[ost] + ((dat[cbt] | dat[cbt + 1] << 8) >> (spos & 7) & (1 << obtr) - 1);
|
|
3621
|
+
if (off > 3) {
|
|
3622
|
+
st.o[2] = st.o[1];
|
|
3623
|
+
st.o[1] = st.o[0];
|
|
3624
|
+
st.o[0] = off -= 3;
|
|
3625
|
+
} else {
|
|
3626
|
+
var idx = off - (ll != 0);
|
|
3627
|
+
if (idx) {
|
|
3628
|
+
off = idx == 3 ? st.o[0] - 1 : st.o[idx];
|
|
3629
|
+
if (idx > 1)
|
|
3630
|
+
st.o[2] = st.o[1];
|
|
3631
|
+
st.o[1] = st.o[0];
|
|
3632
|
+
st.o[0] = off;
|
|
3633
|
+
} else
|
|
3634
|
+
off = st.o[0];
|
|
3635
|
+
}
|
|
3636
|
+
for (var i = 0; i < ll; ++i) {
|
|
3637
|
+
buf[oubt + i] = buf[spl + i];
|
|
3638
|
+
}
|
|
3639
|
+
oubt += ll, spl += ll;
|
|
3640
|
+
var stin = oubt - off;
|
|
3641
|
+
if (stin < 0) {
|
|
3642
|
+
var len = -stin;
|
|
3643
|
+
var bs = st.e + stin;
|
|
3644
|
+
if (len > ml)
|
|
3645
|
+
len = ml;
|
|
3646
|
+
for (var i = 0; i < len; ++i) {
|
|
3647
|
+
buf[oubt + i] = st.w[bs + i];
|
|
3648
|
+
}
|
|
3649
|
+
oubt += len, ml -= len, stin = 0;
|
|
3650
|
+
}
|
|
3651
|
+
for (var i = 0; i < ml; ++i) {
|
|
3652
|
+
buf[oubt + i] = buf[stin + i];
|
|
3653
|
+
}
|
|
3654
|
+
oubt += ml;
|
|
3655
|
+
}
|
|
3656
|
+
if (oubt != spl) {
|
|
3657
|
+
while (spl < buf.length) {
|
|
3658
|
+
buf[oubt++] = buf[spl++];
|
|
3659
|
+
}
|
|
3660
|
+
} else
|
|
3661
|
+
oubt = buf.length;
|
|
3662
|
+
if (out)
|
|
3663
|
+
st.y += oubt;
|
|
3664
|
+
else
|
|
3665
|
+
buf = slc(buf, 0, oubt);
|
|
3666
|
+
} else if (out) {
|
|
3667
|
+
st.y += lss;
|
|
3668
|
+
if (spl) {
|
|
3669
|
+
for (var i = 0; i < lss; ++i) {
|
|
3670
|
+
buf[i] = buf[spl + i];
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
} else if (spl)
|
|
3674
|
+
buf = slc(buf, spl);
|
|
3675
|
+
st.b = ebt;
|
|
3676
|
+
return buf;
|
|
3677
|
+
}
|
|
3678
|
+
err(2);
|
|
3679
|
+
};
|
|
3680
|
+
var cct = function(bufs, ol) {
|
|
3681
|
+
if (bufs.length == 1)
|
|
3682
|
+
return bufs[0];
|
|
3683
|
+
var buf = new u8(ol);
|
|
3684
|
+
for (var i = 0, b = 0; i < bufs.length; ++i) {
|
|
3685
|
+
var chk = bufs[i];
|
|
3686
|
+
buf.set(chk, b);
|
|
3687
|
+
b += chk.length;
|
|
3688
|
+
}
|
|
3689
|
+
return buf;
|
|
3690
|
+
};
|
|
3691
|
+
function decompress(dat, buf) {
|
|
3692
|
+
var bufs = [], nb = +!buf;
|
|
3693
|
+
var bt = 0, ol = 0;
|
|
3694
|
+
for (; dat.length; ) {
|
|
3695
|
+
var st = rzfh(dat, nb || buf);
|
|
3696
|
+
if (typeof st == "object") {
|
|
3697
|
+
if (nb) {
|
|
3698
|
+
buf = null;
|
|
3699
|
+
if (st.w.length == st.u) {
|
|
3700
|
+
bufs.push(buf = st.w);
|
|
3701
|
+
ol += st.u;
|
|
3702
|
+
}
|
|
3703
|
+
} else {
|
|
3704
|
+
bufs.push(buf);
|
|
3705
|
+
st.e = 0;
|
|
3706
|
+
}
|
|
3707
|
+
for (; !st.l; ) {
|
|
3708
|
+
var blk = rzb(dat, st, buf);
|
|
3709
|
+
if (!blk)
|
|
3710
|
+
err(5);
|
|
3711
|
+
if (buf)
|
|
3712
|
+
st.e = st.y;
|
|
3713
|
+
else {
|
|
3714
|
+
bufs.push(blk);
|
|
3715
|
+
ol += blk.length;
|
|
3716
|
+
cpw(st.w, 0, blk.length);
|
|
3717
|
+
st.w.set(blk, st.w.length - blk.length);
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
bt = st.b + st.c * 4;
|
|
3721
|
+
} else
|
|
3722
|
+
bt = st;
|
|
3723
|
+
dat = dat.subarray(bt);
|
|
3724
|
+
}
|
|
3725
|
+
return cct(bufs, ol);
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/dsh.mjs
|
|
3729
|
+
var DSH_SESSION_LOG = /^session(?:\.v([1-9][0-9]*))?\.jsonl(?:\.zstd)?$/i;
|
|
3730
|
+
function dshSessionLogVersion(name) {
|
|
3731
|
+
const m = DSH_SESSION_LOG.exec(String(name || ""));
|
|
3732
|
+
return m ? Number(m[1] ?? 0) : void 0;
|
|
3733
|
+
}
|
|
3734
|
+
function isDshSessionFile(name) {
|
|
3735
|
+
return dshSessionLogVersion(name) !== void 0;
|
|
3736
|
+
}
|
|
3737
|
+
async function decodeZstdText(buf) {
|
|
3738
|
+
return Buffer2.from(decompress(buf)).toString("utf8");
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/dsh.mjs
|
|
3742
|
+
function decodeDshProjectKey(encoded) {
|
|
3743
|
+
return String(encoded).replace(/~([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
3744
|
+
}
|
|
3745
|
+
var DSH_ZSTD_SCAN_MAX_BYTES = 256 * 1024;
|
|
3746
|
+
async function scanDsh(host2, target, { bm, emit, format: onlyFormat }) {
|
|
3747
|
+
const files = [];
|
|
3748
|
+
await walkFiles(host2, target, files, (name) => isDshSessionFile(name));
|
|
3749
|
+
const out = [];
|
|
3750
|
+
for (const file of files) {
|
|
3751
|
+
const fmt = dshFormatOf(file.name);
|
|
3752
|
+
if (onlyFormat !== void 0 && fmt !== onlyFormat) continue;
|
|
3753
|
+
const st = await host2.stat(file.path);
|
|
3754
|
+
if (!st) continue;
|
|
3755
|
+
const zstd = /\.zstd$/i.test(file.path);
|
|
3756
|
+
const byDirName = () => [dirNameEntry(fmt, file.path, st)];
|
|
3757
|
+
let entries;
|
|
3758
|
+
if (zstd && (st.size > DSH_ZSTD_SCAN_MAX_BYTES || typeof host2.readBytes !== "function")) {
|
|
3759
|
+
entries = byDirName();
|
|
3760
|
+
} else {
|
|
3761
|
+
entries = await probeSource(bm, fmt, file.path, fileFingerprint(st), async () => {
|
|
3762
|
+
if (zstd) {
|
|
3763
|
+
const bytes = await host2.readBytes(file.path, DSH_ZSTD_SCAN_MAX_BYTES);
|
|
3764
|
+
if (!bytes) return byDirName();
|
|
3765
|
+
let text;
|
|
3766
|
+
try {
|
|
3767
|
+
text = await decodeZstdText(bytes);
|
|
3768
|
+
} catch {
|
|
3769
|
+
return [];
|
|
3770
|
+
}
|
|
3771
|
+
return dshEntry(fmt, file.path, st, parseJsonlHead(text), []);
|
|
3772
|
+
}
|
|
3773
|
+
const head = await host2.readHead(file.path, HEAD_MAX_BYTES);
|
|
3774
|
+
if (head === null || head === "") return [];
|
|
3775
|
+
const tail = st.size > HEAD_MAX_BYTES && typeof host2.readTail === "function" ? await host2.readTail(file.path, TAIL_MAX_BYTES) : null;
|
|
3776
|
+
return dshEntry(fmt, file.path, st, parseJsonlHead(head), tail ? parseJsonlHead(tail) : []);
|
|
3777
|
+
});
|
|
3778
|
+
}
|
|
3779
|
+
out.push(...entries);
|
|
3780
|
+
await emitEach(emit, entries);
|
|
3781
|
+
}
|
|
3782
|
+
return out;
|
|
3783
|
+
}
|
|
3784
|
+
function dshEntry(format, sourcePath, st, headRecs, tailRecs) {
|
|
3785
|
+
const sessionRec = headRecs.find((r) => r && r.type === "session" && typeof r.id === "string" && r.id);
|
|
3786
|
+
if (!sessionRec) return [];
|
|
3787
|
+
const lastTitle = (recs) => [...recs].reverse().find((r) => r && r.type === "session/title" && r.data && typeof r.data.title === "string");
|
|
3788
|
+
const titleRec = lastTitle(tailRecs) || lastTitle(headRecs);
|
|
3789
|
+
const title = titleRec ? normalizeTitle(titleRec.data.title) : firstUserTitle(headRecs, (r) => r && r.type === "user/message" && r.data && Array.isArray(r.data.content) ? contentText2(r.data.content) : "");
|
|
3790
|
+
return [makeEntry({
|
|
3791
|
+
format,
|
|
3792
|
+
sessionId: sessionRec.id,
|
|
3793
|
+
title,
|
|
3794
|
+
project: projectFromRecord(sessionRec.cwd, () => dshLayoutProject(sourcePath)),
|
|
3795
|
+
createdAt: Number.isFinite(sessionRec.createdAt) ? sessionRec.createdAt : parseTimeValue(sessionRec.createdAt),
|
|
3796
|
+
lastActiveAt: st.mtimeMs,
|
|
3797
|
+
sourcePath,
|
|
3798
|
+
cwd: sessionRec.cwd
|
|
3799
|
+
})];
|
|
3800
|
+
}
|
|
3801
|
+
function dirNameEntry(format, sourcePath, st) {
|
|
3802
|
+
const parts = String(sourcePath).split(/[\\/]/);
|
|
3803
|
+
return makeEntry({
|
|
3804
|
+
format,
|
|
3805
|
+
sessionId: parts[parts.length - 2],
|
|
3806
|
+
title: "",
|
|
3807
|
+
project: dshLayoutProject(sourcePath),
|
|
3808
|
+
createdAt: st.mtimeMs,
|
|
3809
|
+
lastActiveAt: st.mtimeMs,
|
|
3810
|
+
sourcePath
|
|
3811
|
+
});
|
|
3812
|
+
}
|
|
3813
|
+
function dshLayoutProject(sourcePath) {
|
|
3814
|
+
const m = slashPath(sourcePath).match(/\/sessions\/([^/]+)\/[^/]+\/([^/]+)$/i);
|
|
3815
|
+
if (!m || !isDshSessionFile(m[2])) return null;
|
|
3816
|
+
return decodeDshProjectKey(m[1]);
|
|
3817
|
+
}
|
|
3818
|
+
function dshFormatOf(fileName) {
|
|
3819
|
+
return (dshSessionLogVersion(fileName) ?? 0) >= 4 ? "dsh4" : "dsh";
|
|
3820
|
+
}
|
|
3821
|
+
var dshRoots = (home, env) => join11(env.DSH_HOME || join11(home, ".dsh"), "sessions");
|
|
3822
|
+
var dshMatchFile = (format) => (lower, base) => /(^|[\\/])sessions[\\/]/.test(lower) && isDshSessionFile(base) && dshFormatOf(base) === format ? "only" : false;
|
|
3823
|
+
var dshSource = {
|
|
3824
|
+
format: "dsh",
|
|
3825
|
+
roots: dshRoots,
|
|
3826
|
+
scan: scanDsh,
|
|
3827
|
+
layoutProject: dshLayoutProject,
|
|
3828
|
+
matchFile: dshMatchFile("dsh")
|
|
3829
|
+
};
|
|
3830
|
+
var dsh4Source = {
|
|
3831
|
+
format: "dsh4",
|
|
3832
|
+
roots: dshRoots,
|
|
3833
|
+
scan: scanDsh,
|
|
3834
|
+
layoutProject: dshLayoutProject,
|
|
3835
|
+
matchFile: dshMatchFile("dsh4")
|
|
3836
|
+
};
|
|
3837
|
+
|
|
3838
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/registry.mjs
|
|
3839
|
+
var SOURCES = Object.freeze([
|
|
3840
|
+
claudeSource,
|
|
3841
|
+
codexSource,
|
|
3842
|
+
cursorSource,
|
|
3843
|
+
geminiSource,
|
|
3844
|
+
antigravitySource,
|
|
3845
|
+
reasonixSource,
|
|
3846
|
+
opencodeSource,
|
|
3847
|
+
mimocodeSource,
|
|
3848
|
+
zcodeSource,
|
|
3849
|
+
grokbuildSource,
|
|
3850
|
+
openclawSource,
|
|
3851
|
+
piSource,
|
|
3852
|
+
hermesSource,
|
|
3853
|
+
kimiSource,
|
|
3854
|
+
kilocodeSource,
|
|
3855
|
+
qoderSource,
|
|
3856
|
+
chatgptSource,
|
|
3857
|
+
workbuddySource,
|
|
3858
|
+
qwenSource,
|
|
3859
|
+
continueSource,
|
|
3860
|
+
clineSource,
|
|
3861
|
+
gooseSource,
|
|
3862
|
+
dsh4Source,
|
|
3863
|
+
zedSource,
|
|
3864
|
+
crushSource,
|
|
3865
|
+
teleagentSource,
|
|
3866
|
+
traeSource,
|
|
3867
|
+
vibeSource,
|
|
3868
|
+
dshSource
|
|
3869
|
+
]);
|
|
3870
|
+
var FORMATS = SOURCES.map((s) => s.format);
|
|
3871
|
+
var BY_FORMAT = new Map(SOURCES.map((s) => [s.format, s]));
|
|
3872
|
+
function sourceOf(format) {
|
|
3873
|
+
return BY_FORMAT.get(format);
|
|
3874
|
+
}
|
|
3875
|
+
function defaultRoots({ home = homedir3(), env = process.env } = {}) {
|
|
3876
|
+
return Object.fromEntries(SOURCES.map((s) => [s.format, s.roots(home, env) ?? null]));
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/run-host.mjs
|
|
3880
|
+
function memoize(fn) {
|
|
3881
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3882
|
+
return (key) => {
|
|
3883
|
+
if (!cache.has(key)) cache.set(key, fn(key));
|
|
3884
|
+
return cache.get(key);
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3887
|
+
function createRunHost(host2) {
|
|
3888
|
+
const run = Object.create(host2);
|
|
3889
|
+
run.readDir = memoize((path) => host2.readDir(path));
|
|
3890
|
+
run.stat = memoize((path) => host2.stat(path));
|
|
3891
|
+
if (typeof host2.resolveCursorSlug === "function") {
|
|
3892
|
+
run.resolveCursorSlug = memoize((slug) => host2.resolveCursorSlug(slug));
|
|
3893
|
+
}
|
|
3894
|
+
return run;
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3897
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery/discover.mjs
|
|
3898
|
+
async function scanFormat(host2, format, target, bm, emit, warnings) {
|
|
3899
|
+
const source = sourceOf(format);
|
|
3900
|
+
if (!source) return [];
|
|
3901
|
+
const warn = (err2) => {
|
|
3902
|
+
if (Array.isArray(warnings)) warnings.push({ format, target: String(target), error: errorMessage(err2) });
|
|
3903
|
+
};
|
|
3904
|
+
try {
|
|
3905
|
+
return await source.scan(host2, target, { bm, emit, format, warn });
|
|
3906
|
+
} catch (err2) {
|
|
3907
|
+
warn(err2);
|
|
3908
|
+
return [];
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
function errorMessage(err2) {
|
|
3912
|
+
if (err2 && typeof err2 === "object" && typeof err2.message === "string") {
|
|
3913
|
+
return (typeof err2.code === "string" && !err2.message.includes(err2.code) ? err2.code + ": " : "") + err2.message;
|
|
3914
|
+
}
|
|
3915
|
+
return String(err2);
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/mimocode.mjs
|
|
3919
|
+
var MIMOCODE_BG_TITLE_WHERE = [
|
|
3920
|
+
"title LIKE 'checkpoint-writer:%'",
|
|
3921
|
+
"title LIKE 'checkpoint writer:%'",
|
|
3922
|
+
"title LIKE 'checkpoint_writer:%'",
|
|
3923
|
+
"title LIKE 'auto dream%'",
|
|
3924
|
+
"title LIKE 'auto-dream%'",
|
|
3925
|
+
"title LIKE 'auto_dream%'",
|
|
3926
|
+
"title LIKE 'auto distill%'",
|
|
3927
|
+
"title LIKE 'auto-distill%'",
|
|
3928
|
+
"title LIKE 'auto_distill%'"
|
|
3929
|
+
].join(" OR ");
|
|
3930
|
+
function readMimocodeDbSummaries(dbPath) {
|
|
3931
|
+
return readOpencodeDbSummaries(dbPath, { where: "NOT (" + MIMOCODE_BG_TITLE_WHERE + ")" });
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/kilocode.mjs
|
|
3935
|
+
function readKilocodeDbSummaries(dbPath) {
|
|
3936
|
+
const where = readOptionalDb(dbPath, (db) => {
|
|
3937
|
+
const sessionCols = columnsOf(db, "session");
|
|
3938
|
+
const keep = [];
|
|
3939
|
+
if (sessionCols.has("parent_id")) keep.push("(parent_id IS NULL OR parent_id = '')");
|
|
3940
|
+
if (sessionCols.has("time_archived")) keep.push("time_archived IS NULL");
|
|
3941
|
+
return keep.join(" AND ");
|
|
3942
|
+
}) || void 0;
|
|
3943
|
+
return readOpencodeDbSummaries(dbPath, { where });
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3946
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/zcode.mjs
|
|
3947
|
+
function readZcodeDbSummaries(dbPath) {
|
|
3948
|
+
return withReadOnlyDb(dbPath, (db) => {
|
|
3949
|
+
const hasMessage = hasTable(db, "message");
|
|
3950
|
+
const rows = db.prepare(
|
|
3951
|
+
"SELECT s.id, s.title, s.directory, s.time_updated AS updatedAt" + (hasMessage ? ", (SELECT MAX(m.time_created) FROM message m WHERE m.session_id = s.id) AS lastMsg" : "") + " FROM session s WHERE s.parent_id IS NULL OR s.parent_id = '' ORDER BY s.time_updated, s.id"
|
|
3952
|
+
).all();
|
|
3953
|
+
return rows.map((row) => ({
|
|
3954
|
+
id: row.id,
|
|
3955
|
+
title: row.title,
|
|
3956
|
+
directory: row.directory,
|
|
3957
|
+
createdAt: row.updatedAt,
|
|
3958
|
+
lastActiveAt: row.lastMsg ?? row.updatedAt
|
|
3959
|
+
}));
|
|
3960
|
+
});
|
|
3961
|
+
}
|
|
3962
|
+
|
|
3963
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/hermes.mjs
|
|
3964
|
+
function readHermesDbSummaries(dbPath) {
|
|
3965
|
+
return readOptionalDb(dbPath, (db) => {
|
|
3966
|
+
if (!hasTable(db, "sessions")) return null;
|
|
3967
|
+
const sCols = columnsOf(db, "sessions");
|
|
3968
|
+
const cwdCol = pickCol(sCols, "cwd", "directory");
|
|
3969
|
+
const startCol = pickCol(sCols, "started_at", "created_at");
|
|
3970
|
+
const endCol = pickCol(sCols, "ended_at", "updated_at");
|
|
3971
|
+
const mCols = columnsOf(db, "messages");
|
|
3972
|
+
const timeCol = pickCol(mCols, "created_at", "timestamp");
|
|
3973
|
+
const lastMsg = timeCol && mCols.has("session_id") ? ', (SELECT MAX(m."' + timeCol + '") FROM messages m WHERE m.session_id = s.id) AS lastMsg' : "";
|
|
3974
|
+
const rows = db.prepare("SELECT s.*" + lastMsg + " FROM sessions s ORDER BY s.rowid DESC").all();
|
|
3975
|
+
const out = [];
|
|
3976
|
+
for (const row of rows) {
|
|
3977
|
+
const id = typeof row.id === "string" && row.id ? row.id : void 0;
|
|
3978
|
+
if (!id) continue;
|
|
3979
|
+
const startedAt = startCol ? parseHermesTime(row[startCol]) : void 0;
|
|
3980
|
+
const endedAt = endCol ? parseHermesTime(row[endCol]) : void 0;
|
|
3981
|
+
out.push({
|
|
3982
|
+
id,
|
|
3983
|
+
title: typeof row.title === "string" && row.title ? row.title : void 0,
|
|
3984
|
+
cwd: cwdCol && typeof row[cwdCol] === "string" && row[cwdCol] ? row[cwdCol] : void 0,
|
|
3985
|
+
createdAt: startedAt ?? endedAt,
|
|
3986
|
+
lastActiveAt: lastMsg && row.lastMsg !== null && row.lastMsg !== void 0 ? parseHermesTime(row.lastMsg) : endedAt ?? void 0
|
|
3987
|
+
});
|
|
3988
|
+
}
|
|
3989
|
+
return out;
|
|
3990
|
+
});
|
|
3991
|
+
}
|
|
3992
|
+
function pickCol(cols, ...names) {
|
|
3993
|
+
for (const n of names) if (cols.has(n)) return n;
|
|
3994
|
+
return void 0;
|
|
3995
|
+
}
|
|
3996
|
+
|
|
3997
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/cline.mjs
|
|
3998
|
+
import { dirname, join as join12 } from "node:path";
|
|
3999
|
+
var timeOf = (v) => parseTimeMs(v, { truncSeconds: true });
|
|
4000
|
+
function metadataTitle(raw) {
|
|
4001
|
+
if (typeof raw !== "string" || !raw) return "";
|
|
4002
|
+
try {
|
|
4003
|
+
const obj = JSON.parse(raw);
|
|
4004
|
+
return obj && typeof obj === "object" && typeof obj.title === "string" ? obj.title : "";
|
|
4005
|
+
} catch {
|
|
4006
|
+
return "";
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
function readClineDb(dbPath) {
|
|
4010
|
+
return readOptionalDb(dbPath, (db) => {
|
|
4011
|
+
const cols = columnsOf(db, "sessions");
|
|
4012
|
+
if (!cols.has("session_id")) return null;
|
|
4013
|
+
const pick = (row, name) => cols.has(name) ? row[name] : void 0;
|
|
4014
|
+
const sessionsDir = join12(dirname(dirname(dbPath)), "sessions");
|
|
4015
|
+
const out = [];
|
|
4016
|
+
for (const row of db.prepare("SELECT * FROM sessions ORDER BY rowid DESC").all()) {
|
|
4017
|
+
const id = typeof row.session_id === "string" && row.session_id ? row.session_id : null;
|
|
4018
|
+
if (!id) continue;
|
|
4019
|
+
const isSubagent = pick(row, "is_subagent") === 1 || Boolean(pick(row, "agent_id")) || Boolean(pick(row, "parent_session_id"));
|
|
4020
|
+
if (isSubagent) continue;
|
|
4021
|
+
const rawPath = pick(row, "messages_path");
|
|
4022
|
+
out.push({
|
|
4023
|
+
id,
|
|
4024
|
+
title: metadataTitle(pick(row, "metadata_json")),
|
|
4025
|
+
prompt: typeof pick(row, "prompt") === "string" ? pick(row, "prompt") : "",
|
|
4026
|
+
cwd: typeof pick(row, "cwd") === "string" && pick(row, "cwd") || (typeof pick(row, "workspace_root") === "string" && pick(row, "workspace_root") ? pick(row, "workspace_root") : null),
|
|
4027
|
+
createdAt: timeOf(pick(row, "started_at")),
|
|
4028
|
+
lastActiveAt: timeOf(pick(row, "updated_at")) ?? timeOf(pick(row, "ended_at")),
|
|
4029
|
+
model: typeof pick(row, "model") === "string" ? pick(row, "model") : null,
|
|
4030
|
+
// messages_path 仅在**绝对路径**时直接用(跨平台判定,不依赖 node:path.isAbsolute 的
|
|
4031
|
+
// 运行平台语义);相对路径的基准不在契约里(可能相对 dataDir)→ 按
|
|
4032
|
+
// <sessionsDir>/<id>/<id>.messages.json 规范路径解析(发现层会 stat 校验)
|
|
4033
|
+
messagesPath: typeof rawPath === "string" && rawPath && isAbsoluteLike(rawPath) ? rawPath : clineMessagesPath(sessionsDir, id)
|
|
4034
|
+
});
|
|
4035
|
+
}
|
|
4036
|
+
return out;
|
|
4037
|
+
});
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/goose.mjs
|
|
4041
|
+
function gooseTextTime(v) {
|
|
4042
|
+
if (typeof v !== "string" || !v) return null;
|
|
4043
|
+
const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(v) ? v.replace(" ", "T") + "Z" : v;
|
|
4044
|
+
const n = Date.parse(iso);
|
|
4045
|
+
return Number.isFinite(n) ? n : null;
|
|
4046
|
+
}
|
|
4047
|
+
function summaryOf(row, cols, messageCount = null) {
|
|
4048
|
+
const pick = (name2) => cols.has(name2) ? row[name2] : void 0;
|
|
4049
|
+
const name = typeof pick("name") === "string" ? pick("name").trim() : "";
|
|
4050
|
+
const description = typeof pick("description") === "string" ? pick("description").trim() : "";
|
|
4051
|
+
const workingDir = typeof pick("working_dir") === "string" ? pick("working_dir") : "";
|
|
4052
|
+
return {
|
|
4053
|
+
id: typeof row.id === "string" && row.id ? row.id : null,
|
|
4054
|
+
title: name || description,
|
|
4055
|
+
cwd: workingDir || null,
|
|
4056
|
+
sessionType: typeof pick("session_type") === "string" ? pick("session_type") : "",
|
|
4057
|
+
parentSessionId: typeof pick("parent_session_id") === "string" ? pick("parent_session_id") : "",
|
|
4058
|
+
providerName: typeof pick("provider_name") === "string" ? pick("provider_name") : "",
|
|
4059
|
+
createdAt: gooseTextTime(pick("created_at")),
|
|
4060
|
+
updatedAt: gooseTextTime(pick("updated_at")),
|
|
4061
|
+
messageCount
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
function gooseRows(db) {
|
|
4065
|
+
const scols = columnsOf(db, "sessions");
|
|
4066
|
+
const mcols = columnsOf(db, "messages");
|
|
4067
|
+
const ok = scols.has("id") && scols.has("session_type") && scols.has("working_dir") && mcols.has("session_id") && mcols.has("content_json");
|
|
4068
|
+
if (!ok) return null;
|
|
4069
|
+
const rows = db.prepare("SELECT * FROM sessions ORDER BY updated_at DESC").all().filter((row) => {
|
|
4070
|
+
const type = row.session_type;
|
|
4071
|
+
const parent = scols.has("parent_session_id") ? row.parent_session_id : null;
|
|
4072
|
+
return type !== "sub_agent" && type !== "hidden" && !parent && typeof row.id === "string" && row.id;
|
|
4073
|
+
});
|
|
4074
|
+
return { scols, mcols, rows };
|
|
4075
|
+
}
|
|
4076
|
+
function readGooseSessions(dbPath) {
|
|
4077
|
+
return readOptionalDb(dbPath, gooseRows, (_db, read) => read.rows.map((row) => summaryOf(row, read.scols)));
|
|
4078
|
+
}
|
|
4079
|
+
|
|
4080
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/zed.mjs
|
|
4081
|
+
function zedRows(db) {
|
|
4082
|
+
const tables = tableNames(db);
|
|
4083
|
+
if (tables.size !== 1 || !tables.has("threads")) return null;
|
|
4084
|
+
const cols = columnsOf(db, "threads");
|
|
4085
|
+
if (!cols.has("id") || !cols.has("summary") || !cols.has("data_type") || !cols.has("data")) return null;
|
|
4086
|
+
const rows = db.prepare("SELECT * FROM threads").all().filter((row) => typeof row.id === "string" && row.id && !(cols.has("parent_id") && row.parent_id));
|
|
4087
|
+
return { cols, rows };
|
|
4088
|
+
}
|
|
4089
|
+
function readZedThreads(dbPath) {
|
|
4090
|
+
return readOptionalDb(dbPath, zedRows, (_db, read) => {
|
|
4091
|
+
const out = [];
|
|
4092
|
+
for (const row of read.rows) {
|
|
4093
|
+
const folderPaths = read.cols.has("folder_paths") ? row.folder_paths : null;
|
|
4094
|
+
const folderOrder = read.cols.has("folder_paths_order") ? row.folder_paths_order : null;
|
|
4095
|
+
const paths = zedFolderPaths(folderPaths, folderOrder);
|
|
4096
|
+
out.push({
|
|
4097
|
+
id: row.id,
|
|
4098
|
+
title: typeof row.summary === "string" ? row.summary : "",
|
|
4099
|
+
cwd: paths.length > 0 ? paths[0] : null,
|
|
4100
|
+
folderPaths: paths,
|
|
4101
|
+
createdAt: read.cols.has("created_at") ? row.created_at : null,
|
|
4102
|
+
updatedAt: typeof row.updated_at === "string" ? row.updated_at : null
|
|
4103
|
+
});
|
|
4104
|
+
}
|
|
4105
|
+
return out;
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
// .codex-tmp/vendor-pagination-upstream/lib/sources/crush.mjs
|
|
4110
|
+
function crushRows(db) {
|
|
4111
|
+
const tables = tableNames(db);
|
|
4112
|
+
if (!tables.has("sessions") || !tables.has("messages") || !tables.has("read_files")) return null;
|
|
4113
|
+
const scols = columnsOf(db, "sessions");
|
|
4114
|
+
const mcols = columnsOf(db, "messages");
|
|
4115
|
+
const ok = scols.has("parent_session_id") && scols.has("summary_message_id") && scols.has("prompt_tokens") && mcols.has("parts") && mcols.has("is_summary_message") && mcols.has("finished_at");
|
|
4116
|
+
if (!ok) return null;
|
|
4117
|
+
const rows = db.prepare("SELECT * FROM sessions WHERE parent_session_id IS NULL ORDER BY updated_at DESC").all().filter((row) => typeof row.id === "string" && row.id && !row.id.startsWith("title-"));
|
|
4118
|
+
return { scols, mcols, rows };
|
|
4119
|
+
}
|
|
4120
|
+
function crushMs(v) {
|
|
4121
|
+
return typeof v === "number" ? parseTimeMs(v, { truncSeconds: true }) : null;
|
|
4122
|
+
}
|
|
4123
|
+
function readCrushSessions(dbPath) {
|
|
4124
|
+
return readOptionalDb(dbPath, crushRows, (_db, read) => read.rows.map((row) => ({
|
|
4125
|
+
id: row.id,
|
|
4126
|
+
title: typeof row.title === "string" ? row.title : "",
|
|
4127
|
+
parentSessionId: typeof row.parent_session_id === "string" ? row.parent_session_id : null,
|
|
4128
|
+
createdAt: crushMs(row.created_at),
|
|
4129
|
+
updatedAt: crushMs(row.updated_at)
|
|
4130
|
+
})));
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4133
|
+
// .codex-tmp/vendor-pagination-upstream/lib/discovery-host.mjs
|
|
4134
|
+
var DB_SUMMARY_READERS = {
|
|
4135
|
+
// opencode 与 teleagent 无发现期过滤(teleagent 是 opencode 派生、schema 同构)
|
|
4136
|
+
opencode: (dbPath) => readOpencodeDbSummaries(dbPath).map(pickSummary),
|
|
4137
|
+
teleagent: (dbPath) => readOpencodeDbSummaries(dbPath).map(pickSummary),
|
|
4138
|
+
// mimocode:摘要路径按标题前缀剔除后台任务会话(agent 双信号需读消息,摘要不读,
|
|
4139
|
+
// 见 mimocode.mjs;导入路径仍走 isMimocodeBackgroundSession 全量精确剔除)
|
|
4140
|
+
mimocode: (dbPath) => readMimocodeDbSummaries(dbPath).map(pickSummary),
|
|
4141
|
+
// kilocode:摘要路径按 parent_id / time_archived 列剔除子/归档会话(同全量口径,
|
|
4142
|
+
// SQL 层直接完成,见 kilocode.mjs)
|
|
4143
|
+
kilocode: (dbPath) => readKilocodeDbSummaries(dbPath).map(pickSummary),
|
|
4144
|
+
zcode: (dbPath) => readZcodeDbSummaries(dbPath).map(pickSummary),
|
|
4145
|
+
hermes: (dbPath) => mapRows(readHermesDbSummaries(dbPath), (s) => ({
|
|
4146
|
+
id: s.id,
|
|
4147
|
+
title: s.title,
|
|
4148
|
+
directory: s.cwd,
|
|
4149
|
+
createdAt: s.createdAt,
|
|
4150
|
+
lastActiveAt: s.lastActiveAt
|
|
4151
|
+
})),
|
|
4152
|
+
// cline:sessions.db 只有元数据(无 title/message_count 列)→ 直接透传摘要,
|
|
4153
|
+
// 发现层再按需补 manifest 标题并 stat 校验转写是否存在
|
|
4154
|
+
cline: (dbPath) => mapRows(readClineDb(dbPath), (s) => ({
|
|
4155
|
+
id: s.id,
|
|
4156
|
+
title: s.title,
|
|
4157
|
+
prompt: s.prompt,
|
|
4158
|
+
directory: s.cwd,
|
|
4159
|
+
cwd: s.cwd,
|
|
4160
|
+
createdAt: s.createdAt,
|
|
4161
|
+
lastActiveAt: s.lastActiveAt,
|
|
4162
|
+
messagesPath: s.messagesPath
|
|
4163
|
+
})),
|
|
4164
|
+
// goose:sessions.db 也是元数据 + 消息同库;发现只需摘要(sessionIds 过滤与
|
|
4165
|
+
// 逐会话导入在 lib/sources/goose.mjs,用 readGooseDb 读全量)
|
|
4166
|
+
goose: (dbPath) => mapRows(readGooseSessions(dbPath), (s) => ({
|
|
4167
|
+
id: s.id,
|
|
4168
|
+
title: s.title,
|
|
4169
|
+
directory: s.cwd,
|
|
4170
|
+
createdAt: s.createdAt ?? void 0,
|
|
4171
|
+
lastActiveAt: s.updatedAt ?? void 0
|
|
4172
|
+
})),
|
|
4173
|
+
// zed:threads 单表(标题在 summary 列);时间只有行级 created_at/updated_at(RFC3339),
|
|
4174
|
+
// 消息数需要解压每个 zstd blob 才有 → 发现层留空(保持廉价路径)
|
|
4175
|
+
zed: (dbPath) => mapRows(readZedThreads(dbPath), (s) => ({
|
|
4176
|
+
id: s.id,
|
|
4177
|
+
title: s.title,
|
|
4178
|
+
directory: s.cwd,
|
|
4179
|
+
createdAt: s.createdAt ? Date.parse(s.createdAt) || void 0 : void 0,
|
|
4180
|
+
lastActiveAt: s.updatedAt ? Date.parse(s.updatedAt) || void 0 : void 0
|
|
4181
|
+
})),
|
|
4182
|
+
// crush:sessions 表有秒级时间戳;**没有 cwd 列** → directory 留空,
|
|
4183
|
+
// 项目路径由扫描器按注册表/库位置补(见 lib/discovery/sqlite.mjs 的 crush 扫描器)
|
|
4184
|
+
crush: (dbPath) => mapRows(readCrushSessions(dbPath), (s) => ({
|
|
4185
|
+
id: s.id,
|
|
4186
|
+
title: s.title,
|
|
4187
|
+
directory: null,
|
|
4188
|
+
createdAt: s.createdAt ?? void 0,
|
|
4189
|
+
lastActiveAt: s.updatedAt ?? void 0
|
|
4190
|
+
})),
|
|
4191
|
+
trae: (dbPath) => readTraeDbSummaries(dbPath).map((s) => ({
|
|
4192
|
+
id: s.id,
|
|
4193
|
+
title: s.title,
|
|
4194
|
+
directory: s.directory,
|
|
4195
|
+
createdAt: s.createdAt,
|
|
4196
|
+
lastActiveAt: s.lastActiveAt
|
|
4197
|
+
}))
|
|
4198
|
+
};
|
|
4199
|
+
var DB_SUMMARY_FORMATS = Object.freeze(Object.keys(DB_SUMMARY_READERS));
|
|
4200
|
+
function mapRows(rows, fn) {
|
|
4201
|
+
return rows === null ? null : rows.map(fn);
|
|
4202
|
+
}
|
|
4203
|
+
function pickSummary(s) {
|
|
4204
|
+
return {
|
|
4205
|
+
id: s.id,
|
|
4206
|
+
title: s.title,
|
|
4207
|
+
directory: s.directory ?? s.cwd,
|
|
4208
|
+
createdAt: s.createdAt,
|
|
4209
|
+
lastActiveAt: s.lastActiveAt
|
|
4210
|
+
};
|
|
4211
|
+
}
|
|
4212
|
+
|
|
4213
|
+
// vendor/chat-import-reader/scan-entry.mjs
|
|
4214
|
+
import { stat, readdir as readdir2, readFile as readFile2, open } from "node:fs/promises";
|
|
4215
|
+
import { createReadStream } from "node:fs";
|
|
4216
|
+
import { createInterface } from "node:readline";
|
|
4217
|
+
import { join as join13, resolve } from "node:path";
|
|
4218
|
+
import { homedir as homedir4 } from "node:os";
|
|
4219
|
+
var expand = (path) => resolve(path.startsWith("~/") || path.startsWith("~\\") ? join13(homedir4(), path.slice(2)) : path);
|
|
4220
|
+
async function missingAsNull(read) {
|
|
4221
|
+
try {
|
|
4222
|
+
return await read();
|
|
4223
|
+
} catch (error) {
|
|
4224
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") return null;
|
|
4225
|
+
throw error;
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
async function windowBytes(path, cap, tail = false) {
|
|
4229
|
+
return missingAsNull(async () => {
|
|
4230
|
+
const file = await open(expand(path), "r");
|
|
4231
|
+
try {
|
|
4232
|
+
const size = (await file.stat()).size;
|
|
4233
|
+
const offset = tail ? Math.max(0, size - cap) : 0;
|
|
4234
|
+
const buffer = Buffer.alloc(Math.min(size, cap));
|
|
4235
|
+
const { bytesRead } = await file.read(buffer, 0, buffer.length, offset);
|
|
4236
|
+
return buffer.subarray(0, bytesRead);
|
|
4237
|
+
} finally {
|
|
4238
|
+
await file.close();
|
|
4239
|
+
}
|
|
4240
|
+
});
|
|
4241
|
+
}
|
|
4242
|
+
var host = {
|
|
4243
|
+
stat: (path) => missingAsNull(async () => {
|
|
4244
|
+
const s = await stat(expand(path));
|
|
4245
|
+
return { type: s.isDirectory() ? "directory" : "file", size: s.size, mtimeMs: s.mtimeMs };
|
|
4246
|
+
}),
|
|
4247
|
+
readDir: (path) => missingAsNull(async () => (await readdir2(expand(path), { withFileTypes: true })).map((e) => ({
|
|
4248
|
+
name: e.name,
|
|
4249
|
+
type: e.isDirectory() ? "directory" : "file",
|
|
4250
|
+
path: join13(expand(path), e.name)
|
|
4251
|
+
}))),
|
|
4252
|
+
readText: (path) => missingAsNull(() => readFile2(expand(path), "utf8")),
|
|
4253
|
+
readHead: async (path, cap = 256 * 1024) => (await windowBytes(path, cap))?.toString("utf8") ?? null,
|
|
4254
|
+
readTail: async (path, cap = 64 * 1024) => (await windowBytes(path, cap, true))?.toString("utf8") ?? null,
|
|
4255
|
+
async readBytes(path, cap = 256 * 1024) {
|
|
4256
|
+
const s = await host.stat(path);
|
|
4257
|
+
return s?.type === "file" && s.size <= cap ? windowBytes(path, cap) : null;
|
|
4258
|
+
},
|
|
4259
|
+
async *readLines(path) {
|
|
4260
|
+
const input = createReadStream(expand(path), { encoding: "utf8" });
|
|
4261
|
+
const lines = createInterface({ input, crlfDelay: Infinity });
|
|
4262
|
+
try {
|
|
4263
|
+
yield* lines;
|
|
4264
|
+
} finally {
|
|
4265
|
+
lines.close();
|
|
4266
|
+
input.destroy();
|
|
4267
|
+
}
|
|
4268
|
+
},
|
|
4269
|
+
readSessions: (format, path) => DB_SUMMARY_READERS[format]?.(expand(path)) ?? null,
|
|
4270
|
+
resolveCursorSlug: (slug) => resolveCursorSlugPath(context, slug),
|
|
4271
|
+
listWorkspaces: async () => [...await knownWorkspacePaths(context)]
|
|
4272
|
+
};
|
|
4273
|
+
var context = { fs: { resolve: async (path) => expand(path), stat: host.stat } };
|
|
4274
|
+
async function scanConversations(input) {
|
|
4275
|
+
if (!sourceOf(input.format)) throw new Error("Unsupported conversation format: " + input.format);
|
|
4276
|
+
const root = input.path || defaultRoots()[input.format];
|
|
4277
|
+
const targets = Array.isArray(root) ? root : root ? [root] : [];
|
|
4278
|
+
const sessions = [], warnings = [];
|
|
4279
|
+
const run = createRunHost(host);
|
|
4280
|
+
for (const target of targets) sessions.push(...await scanFormat(run, input.format, expand(target), null, null, warnings));
|
|
4281
|
+
return { sessions: sessions.map(({ importStatus, ...entry }) => entry), warnings };
|
|
4282
|
+
}
|
|
4283
|
+
export {
|
|
4284
|
+
FORMATS,
|
|
4285
|
+
scanConversations
|
|
4286
|
+
};
|