codesesh 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/{chunk-GCOAE7KI.js → chunk-BV65IEWZ.js} +368 -179
- package/dist/chunk-BV65IEWZ.js.map +1 -0
- package/dist/{dist-TZTL6VP4.js → dist-VD54GDPO.js} +10 -2
- package/dist/index.js +949 -510
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +1 -1
- package/dist/search-index-worker.js +1 -1
- package/dist/smart-tag-worker.js +1 -1
- package/dist/web/assets/index-ZikfLnUo.js +113 -0
- package/dist/web/assets/index-y6Zx3LT1.css +2 -0
- package/dist/web/assets/markdown-dR4kAewZ.js +14 -0
- package/dist/web/assets/react-DBHwgW7V.js +1821 -0
- package/dist/web/assets/syntax-C_RLNYQn.js +6 -0
- package/dist/web/assets/vendor-bXsb4Kz4.js +40 -0
- package/dist/web/index.html +6 -6
- package/package.json +9 -8
- package/dist/chunk-GCOAE7KI.js.map +0 -1
- package/dist/web/assets/index-D05hsCzb.css +0 -2
- package/dist/web/assets/index-DOy8q3la.js +0 -113
- package/dist/web/assets/markdown-CGVJZBE7.js +0 -14
- package/dist/web/assets/react-DkEeEGji.js +0 -1821
- package/dist/web/assets/syntax-CFQ-7fm6.js +0 -6
- package/dist/web/assets/vendor-B2nLfkMs.js +0 -80
- /package/dist/{dist-TZTL6VP4.js.map → dist-VD54GDPO.js.map} +0 -0
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// ../core/dist/chunk-M5ISIPFR.mjs
|
|
4
|
+
function compareSessionActivityDesc(a, b) {
|
|
5
|
+
return (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created);
|
|
6
|
+
}
|
|
7
|
+
function sortSessionsByActivity(sessions) {
|
|
8
|
+
for (let index = 1; index < sessions.length; index += 1) {
|
|
9
|
+
if (compareSessionActivityDesc(sessions[index - 1], sessions[index]) > 0) {
|
|
10
|
+
return [...sessions].sort(compareSessionActivityDesc);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return [...sessions];
|
|
14
|
+
}
|
|
15
|
+
|
|
3
16
|
// ../core/dist/index.mjs
|
|
4
|
-
import { existsSync as existsSync4, readdirSync, readFileSync as
|
|
17
|
+
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
5
18
|
import { join as join3, basename as basename2, dirname } from "path";
|
|
6
19
|
import { existsSync, statSync } from "fs";
|
|
7
20
|
import { existsSync as existsSync2 } from "fs";
|
|
8
21
|
import { homedir, platform } from "os";
|
|
9
22
|
import { join } from "path";
|
|
10
|
-
import {
|
|
23
|
+
import { closeSync, openSync, readSync } from "fs";
|
|
24
|
+
import { StringDecoder } from "string_decoder";
|
|
11
25
|
import { basename } from "path";
|
|
12
|
-
import { existsSync as existsSync3, mkdirSync, readFileSync
|
|
26
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
13
27
|
import { homedir as homedir2 } from "os";
|
|
14
28
|
import { join as join2 } from "path";
|
|
15
29
|
import { join as join5 } from "path";
|
|
@@ -17,26 +31,26 @@ import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
|
17
31
|
import { basename as basename3, dirname as dirname2, join as join4 } from "path";
|
|
18
32
|
import { createRequire } from "module";
|
|
19
33
|
import { createHash } from "crypto";
|
|
20
|
-
import { existsSync as existsSync6, readFileSync as
|
|
34
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
21
35
|
import { join as join6, basename as basename4, dirname as dirname3 } from "path";
|
|
22
36
|
import {
|
|
23
|
-
closeSync,
|
|
37
|
+
closeSync as closeSync2,
|
|
24
38
|
existsSync as existsSync7,
|
|
25
|
-
openSync,
|
|
26
|
-
readFileSync as
|
|
27
|
-
readSync,
|
|
39
|
+
openSync as openSync2,
|
|
40
|
+
readFileSync as readFileSync4,
|
|
41
|
+
readSync as readSync2,
|
|
28
42
|
readdirSync as readdirSync3,
|
|
29
43
|
statSync as statSync4
|
|
30
44
|
} from "fs";
|
|
31
45
|
import { join as join7, basename as basename5 } from "path";
|
|
32
|
-
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as
|
|
46
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
|
|
33
47
|
import { join as join8, normalize } from "path";
|
|
34
|
-
import { existsSync as existsSync9, readFileSync as
|
|
48
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
|
|
35
49
|
import { basename as basename6, join as join9 } from "path";
|
|
36
50
|
import { join as join10 } from "path";
|
|
37
51
|
import { availableParallelism } from "os";
|
|
38
52
|
import { Worker } from "worker_threads";
|
|
39
|
-
import { existsSync as existsSync10, readFileSync as
|
|
53
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
40
54
|
import { spawnSync } from "child_process";
|
|
41
55
|
import * as os from "os";
|
|
42
56
|
import * as path from "path";
|
|
@@ -244,6 +258,7 @@ function getZCodeDataPath() {
|
|
|
244
258
|
}
|
|
245
259
|
return null;
|
|
246
260
|
}
|
|
261
|
+
var READ_CHUNK_BYTES = 1 << 20;
|
|
247
262
|
function* parseJsonlLines(content) {
|
|
248
263
|
for (const line of content.split("\n")) {
|
|
249
264
|
const trimmed = line.trim();
|
|
@@ -254,9 +269,35 @@ function* parseJsonlLines(content) {
|
|
|
254
269
|
}
|
|
255
270
|
}
|
|
256
271
|
}
|
|
257
|
-
function
|
|
258
|
-
const
|
|
259
|
-
|
|
272
|
+
function* readJsonlFileLines(filePath, chunkBytes = READ_CHUNK_BYTES) {
|
|
273
|
+
const fd = openSync(filePath, "r");
|
|
274
|
+
try {
|
|
275
|
+
const buffer = Buffer.alloc(chunkBytes);
|
|
276
|
+
const decoder = new StringDecoder("utf8");
|
|
277
|
+
let remainder = "";
|
|
278
|
+
let bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);
|
|
279
|
+
while (bytesRead > 0) {
|
|
280
|
+
const lines = (remainder + decoder.write(buffer.subarray(0, bytesRead))).split("\n");
|
|
281
|
+
remainder = lines.pop();
|
|
282
|
+
for (const line of lines) {
|
|
283
|
+
const trimmed = line.trim();
|
|
284
|
+
if (trimmed) yield trimmed;
|
|
285
|
+
}
|
|
286
|
+
bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);
|
|
287
|
+
}
|
|
288
|
+
const tail = (remainder + decoder.end()).trim();
|
|
289
|
+
if (tail) yield tail;
|
|
290
|
+
} finally {
|
|
291
|
+
closeSync(fd);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function* readJsonlFile(filePath) {
|
|
295
|
+
for (const line of readJsonlFileLines(filePath)) {
|
|
296
|
+
try {
|
|
297
|
+
yield JSON.parse(line);
|
|
298
|
+
} catch {
|
|
299
|
+
}
|
|
300
|
+
}
|
|
260
301
|
}
|
|
261
302
|
var INTERNAL_TAGS = [
|
|
262
303
|
"command-message",
|
|
@@ -638,7 +679,7 @@ function loadDiskCache() {
|
|
|
638
679
|
const path2 = getCachePath();
|
|
639
680
|
if (!existsSync3(path2)) return;
|
|
640
681
|
try {
|
|
641
|
-
const cached = JSON.parse(
|
|
682
|
+
const cached = JSON.parse(readFileSync(path2, "utf-8"));
|
|
642
683
|
if (Date.now() - cached.timestamp <= CACHE_TTL_MS) {
|
|
643
684
|
const next = loadSnapshot();
|
|
644
685
|
for (const [name, rawPricing] of Object.entries(cached.data)) {
|
|
@@ -661,7 +702,7 @@ async function refreshPricingCache() {
|
|
|
661
702
|
const path2 = getCachePath();
|
|
662
703
|
if (existsSync3(path2)) {
|
|
663
704
|
try {
|
|
664
|
-
const cached = JSON.parse(
|
|
705
|
+
const cached = JSON.parse(readFileSync(path2, "utf-8"));
|
|
665
706
|
if (typeof cached.timestamp === "number" && Date.now() - cached.timestamp <= CACHE_TTL_MS) {
|
|
666
707
|
return false;
|
|
667
708
|
}
|
|
@@ -945,7 +986,7 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
945
986
|
if (!existsSync4(meta.sourcePath)) {
|
|
946
987
|
throw new Error(`Session file missing: ${meta.sourcePath}`);
|
|
947
988
|
}
|
|
948
|
-
const content =
|
|
989
|
+
const content = readFileSync2(meta.sourcePath, "utf-8");
|
|
949
990
|
const messages = [];
|
|
950
991
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
951
992
|
const ignoredToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -1066,7 +1107,7 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1066
1107
|
const map = /* @__PURE__ */ new Map();
|
|
1067
1108
|
if (existsSync4(indexPath)) {
|
|
1068
1109
|
try {
|
|
1069
|
-
const data = JSON.parse(
|
|
1110
|
+
const data = JSON.parse(readFileSync2(indexPath, "utf-8"));
|
|
1070
1111
|
const entries = data?.entries ?? [];
|
|
1071
1112
|
for (const entry of entries) {
|
|
1072
1113
|
const sid = entry?.sessionId;
|
|
@@ -1085,7 +1126,7 @@ var ClaudeCodeAgent = class extends FileSystemSessionSource {
|
|
|
1085
1126
|
return getParsedSession(this.parseSessionHeadResult(filePath, projectDir));
|
|
1086
1127
|
}
|
|
1087
1128
|
parseSessionHeadResult(filePath, projectDir) {
|
|
1088
|
-
const content =
|
|
1129
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1089
1130
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
1090
1131
|
if (lines.length === 0) return skippedSession("empty file");
|
|
1091
1132
|
const sessionId = basename2(filePath, ".jsonl");
|
|
@@ -2142,7 +2183,7 @@ function kimiContentText(content) {
|
|
|
2142
2183
|
}
|
|
2143
2184
|
function extractFirstUserTitle(contextFile, wireFile) {
|
|
2144
2185
|
if (contextFile && existsSync6(contextFile)) {
|
|
2145
|
-
const content =
|
|
2186
|
+
const content = readFileSync3(contextFile, "utf-8");
|
|
2146
2187
|
for (const record of parseJsonlLines(content)) {
|
|
2147
2188
|
if (record.role !== "user") continue;
|
|
2148
2189
|
const title = normalizeTitleText(kimiContentText(record.content));
|
|
@@ -2150,7 +2191,7 @@ function extractFirstUserTitle(contextFile, wireFile) {
|
|
|
2150
2191
|
}
|
|
2151
2192
|
}
|
|
2152
2193
|
if (wireFile && existsSync6(wireFile)) {
|
|
2153
|
-
const content =
|
|
2194
|
+
const content = readFileSync3(wireFile, "utf-8");
|
|
2154
2195
|
for (const record of parseJsonlLines(content)) {
|
|
2155
2196
|
const message = record.message ?? {};
|
|
2156
2197
|
if (message.type !== "TurnBegin") continue;
|
|
@@ -2179,12 +2220,12 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2179
2220
|
const configPath = join6(roots.kimiRoot, "kimi.json");
|
|
2180
2221
|
const tomlPath = join6(roots.kimiRoot, "config.toml");
|
|
2181
2222
|
if (existsSync6(tomlPath)) {
|
|
2182
|
-
const configText =
|
|
2223
|
+
const configText = readFileSync3(tomlPath, "utf-8");
|
|
2183
2224
|
this.defaultModel = configText.match(/^default_model\s*=\s*"([^"]+)"/m)?.[1] ?? null;
|
|
2184
2225
|
}
|
|
2185
2226
|
if (!existsSync6(configPath)) return;
|
|
2186
2227
|
try {
|
|
2187
|
-
const raw = JSON.parse(
|
|
2228
|
+
const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
2188
2229
|
const workDirs = raw?.work_dirs;
|
|
2189
2230
|
if (!Array.isArray(workDirs)) return;
|
|
2190
2231
|
for (const wd of workDirs) {
|
|
@@ -2248,12 +2289,12 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2248
2289
|
let wireMtime = null;
|
|
2249
2290
|
let metaFile = "";
|
|
2250
2291
|
if (existsSync6(statePath)) {
|
|
2251
|
-
const state = JSON.parse(
|
|
2292
|
+
const state = JSON.parse(readFileSync3(statePath, "utf-8"));
|
|
2252
2293
|
title = String(state.custom_title ?? "");
|
|
2253
2294
|
wireMtime = typeof state.wire_mtime === "number" ? state.wire_mtime : null;
|
|
2254
2295
|
metaFile = statePath;
|
|
2255
2296
|
} else if (existsSync6(metaPath)) {
|
|
2256
|
-
const meta = JSON.parse(
|
|
2297
|
+
const meta = JSON.parse(readFileSync3(metaPath, "utf-8"));
|
|
2257
2298
|
title = String(meta.title ?? "");
|
|
2258
2299
|
wireMtime = typeof meta.wire_mtime === "number" ? meta.wire_mtime : null;
|
|
2259
2300
|
metaFile = metaPath;
|
|
@@ -2361,7 +2402,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2361
2402
|
}
|
|
2362
2403
|
getSessionDataFromContext(meta) {
|
|
2363
2404
|
if (!meta.contextFile) throw new Error("context.jsonl is missing");
|
|
2364
|
-
const content =
|
|
2405
|
+
const content = readFileSync3(meta.contextFile, "utf-8");
|
|
2365
2406
|
const messages = [];
|
|
2366
2407
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
2367
2408
|
const ignoredToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -2428,7 +2469,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2428
2469
|
getSessionDataFromWire(meta) {
|
|
2429
2470
|
const wirePath = meta.wireFile ?? join6(meta.sourcePath, "wire.jsonl");
|
|
2430
2471
|
if (!existsSync6(wirePath)) throw new Error("wire.jsonl is missing");
|
|
2431
|
-
const content =
|
|
2472
|
+
const content = readFileSync3(wirePath, "utf-8");
|
|
2432
2473
|
const messages = [];
|
|
2433
2474
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
2434
2475
|
const ignoredToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -2728,7 +2769,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2728
2769
|
const wirePath = join6(sessionDir, "wire.jsonl");
|
|
2729
2770
|
if (!existsSync6(wirePath)) return stats;
|
|
2730
2771
|
try {
|
|
2731
|
-
const content =
|
|
2772
|
+
const content = readFileSync3(wirePath, "utf-8");
|
|
2732
2773
|
for (const line of content.split("\n").filter((l) => l.trim())) {
|
|
2733
2774
|
try {
|
|
2734
2775
|
const data = JSON.parse(line);
|
|
@@ -2752,7 +2793,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2752
2793
|
const rawPath = existsSync6(contextPath) ? contextPath : wirePath;
|
|
2753
2794
|
if (!existsSync6(rawPath)) return stats;
|
|
2754
2795
|
try {
|
|
2755
|
-
const rawContent =
|
|
2796
|
+
const rawContent = readFileSync3(rawPath, "utf-8");
|
|
2756
2797
|
for (const line of rawContent.split("\n").filter((l) => l.trim())) {
|
|
2757
2798
|
try {
|
|
2758
2799
|
const data = JSON.parse(line);
|
|
@@ -3025,7 +3066,6 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3025
3066
|
const meta = this.sessionMetaMap.get(sessionId);
|
|
3026
3067
|
if (!meta) throw new Error(`Session not found: ${sessionId}`);
|
|
3027
3068
|
if (!existsSync7(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);
|
|
3028
|
-
const content = readFileSync5(meta.sourcePath, "utf-8");
|
|
3029
3069
|
const messages = [];
|
|
3030
3070
|
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
3031
3071
|
let totalInputTokens = 0;
|
|
@@ -3041,7 +3081,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3041
3081
|
let prevOutput = 0;
|
|
3042
3082
|
let prevReasoning = 0;
|
|
3043
3083
|
let prevCachedInput = 0;
|
|
3044
|
-
for (const record of
|
|
3084
|
+
for (const record of readJsonlFile(meta.sourcePath)) {
|
|
3045
3085
|
try {
|
|
3046
3086
|
const recordType = String(record["type"] ?? "");
|
|
3047
3087
|
if (recordType === "turn_context") {
|
|
@@ -3229,7 +3269,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3229
3269
|
this.sessionIndexMtime = mtime;
|
|
3230
3270
|
if (mtime === null) return;
|
|
3231
3271
|
try {
|
|
3232
|
-
const content =
|
|
3272
|
+
const content = readFileSync4(indexPath, "utf-8");
|
|
3233
3273
|
for (const record of parseJsonlLines(content)) {
|
|
3234
3274
|
const sid = String(record["id"] ?? "").trim();
|
|
3235
3275
|
const threadName = String(record["thread_name"] ?? "").trim();
|
|
@@ -3246,13 +3286,13 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3246
3286
|
}
|
|
3247
3287
|
// ---- Session head parsing ----
|
|
3248
3288
|
readFilePrefix(filePath, bytes = 64 * 1024) {
|
|
3249
|
-
const fd =
|
|
3289
|
+
const fd = openSync2(filePath, "r");
|
|
3250
3290
|
try {
|
|
3251
3291
|
const buffer = Buffer.alloc(bytes);
|
|
3252
|
-
const bytesRead =
|
|
3292
|
+
const bytesRead = readSync2(fd, buffer, 0, bytes, 0);
|
|
3253
3293
|
return buffer.subarray(0, bytesRead).toString("utf-8");
|
|
3254
3294
|
} finally {
|
|
3255
|
-
|
|
3295
|
+
closeSync2(fd);
|
|
3256
3296
|
}
|
|
3257
3297
|
}
|
|
3258
3298
|
parseSessionHead(filePath, options) {
|
|
@@ -3262,23 +3302,12 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3262
3302
|
if (options?.fast) {
|
|
3263
3303
|
return this.parseFastSessionHeadResult(filePath);
|
|
3264
3304
|
}
|
|
3265
|
-
const content = readFileSync5(filePath, "utf-8");
|
|
3266
|
-
const lines = content.split("\n").filter((l) => l.trim());
|
|
3267
|
-
if (lines.length === 0) return skippedSession("empty file");
|
|
3268
3305
|
const sessionId = extractSessionId(filePath);
|
|
3269
|
-
let
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
}
|
|
3275
|
-
const payload = firstRecord["payload"] ?? {};
|
|
3276
|
-
const createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(payload) || statSync4(filePath).mtimeMs;
|
|
3277
|
-
const indexTitle = this.getTitleForSession(sessionId);
|
|
3278
|
-
const messageTitle = this.extractTitleFromLines(lines);
|
|
3279
|
-
const directoryTitle = basenameTitle(payload["cwd"] ? String(payload["cwd"]) : null);
|
|
3280
|
-
const title = resolveSessionTitle(indexTitle, messageTitle, directoryTitle);
|
|
3281
|
-
let updatedAt = createdAt;
|
|
3306
|
+
let firstPayload = {};
|
|
3307
|
+
let createdAt = 0;
|
|
3308
|
+
let lineCount = 0;
|
|
3309
|
+
const titleLines = [];
|
|
3310
|
+
let updatedAt = 0;
|
|
3282
3311
|
let messageCount = 0;
|
|
3283
3312
|
let model = null;
|
|
3284
3313
|
let activeModel = null;
|
|
@@ -3294,18 +3323,31 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3294
3323
|
let scanPrevCachedInput = 0;
|
|
3295
3324
|
const COUNTED_TYPES = /* @__PURE__ */ new Set(["message", "function_call", "function_call_output"]);
|
|
3296
3325
|
let hasNonInternalRecord = false;
|
|
3297
|
-
for (const line of
|
|
3326
|
+
for (const line of readJsonlFileLines(filePath)) {
|
|
3327
|
+
lineCount += 1;
|
|
3328
|
+
if (lineCount === 1) {
|
|
3329
|
+
let firstRecord;
|
|
3330
|
+
try {
|
|
3331
|
+
firstRecord = JSON.parse(line);
|
|
3332
|
+
} catch {
|
|
3333
|
+
return skippedSession("malformed first record");
|
|
3334
|
+
}
|
|
3335
|
+
firstPayload = firstRecord["payload"] ?? {};
|
|
3336
|
+
createdAt = parseTimestampMs2(firstRecord) || parseTimestampMs2(firstPayload) || statSync4(filePath).mtimeMs;
|
|
3337
|
+
updatedAt = createdAt;
|
|
3338
|
+
}
|
|
3339
|
+
if (titleLines.length < 20) titleLines.push(line);
|
|
3298
3340
|
try {
|
|
3299
3341
|
const data = JSON.parse(line);
|
|
3300
3342
|
const recordType = String(data["type"] ?? "");
|
|
3301
|
-
const
|
|
3302
|
-
const payloadType = String(
|
|
3343
|
+
const payload = data["payload"] ?? {};
|
|
3344
|
+
const payloadType = String(payload["type"] ?? "");
|
|
3303
3345
|
if (isInternalEventType2(recordType) || isInternalEventType2(payloadType)) continue;
|
|
3304
3346
|
hasNonInternalRecord = true;
|
|
3305
3347
|
const recordTs = parseTimestampMs2(data) || parseTimestampMs2(data["payload"] ?? {});
|
|
3306
3348
|
if (recordTs > updatedAt) updatedAt = recordTs;
|
|
3307
3349
|
if (recordType === "session_meta" || recordType === "turn_context") {
|
|
3308
|
-
const nextModel = extractModelName(
|
|
3350
|
+
const nextModel = extractModelName(payload["model"]);
|
|
3309
3351
|
if (nextModel) {
|
|
3310
3352
|
activeModel = nextModel;
|
|
3311
3353
|
model ??= nextModel;
|
|
@@ -3313,7 +3355,7 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3313
3355
|
continue;
|
|
3314
3356
|
}
|
|
3315
3357
|
if (recordType === "response_item") {
|
|
3316
|
-
const p =
|
|
3358
|
+
const p = payload;
|
|
3317
3359
|
const pType = String(p["type"] ?? "");
|
|
3318
3360
|
if (COUNTED_TYPES.has(pType)) {
|
|
3319
3361
|
messageCount++;
|
|
@@ -3375,8 +3417,12 @@ var CodexAgent = class extends FileSystemSessionSource {
|
|
|
3375
3417
|
} catch {
|
|
3376
3418
|
}
|
|
3377
3419
|
}
|
|
3420
|
+
if (lineCount === 0) return skippedSession("empty file");
|
|
3378
3421
|
if (!hasNonInternalRecord) return filteredSession("internal events only");
|
|
3379
|
-
const
|
|
3422
|
+
const indexTitle = this.getTitleForSession(sessionId);
|
|
3423
|
+
const messageTitle = this.extractTitleFromLines(titleLines);
|
|
3424
|
+
const directory = firstPayload["cwd"] ? String(firstPayload["cwd"]) : "";
|
|
3425
|
+
const title = resolveSessionTitle(indexTitle, messageTitle, basenameTitle(directory || null));
|
|
3380
3426
|
return parsedSession({
|
|
3381
3427
|
id: sessionId,
|
|
3382
3428
|
slug: `codex/${sessionId}`,
|
|
@@ -4008,7 +4054,7 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
4008
4054
|
if (!existsSync8(wsJsonPath)) continue;
|
|
4009
4055
|
let workspacePath;
|
|
4010
4056
|
try {
|
|
4011
|
-
const data = JSON.parse(
|
|
4057
|
+
const data = JSON.parse(readFileSync5(wsJsonPath, "utf-8"));
|
|
4012
4058
|
const uri = data.folder ?? data.workspace ?? "";
|
|
4013
4059
|
if (!uri) continue;
|
|
4014
4060
|
workspacePath = normalize(decodeURIComponent(uri.replace(/^file:\/\//, "")));
|
|
@@ -4718,7 +4764,7 @@ var PiAgent = class extends FileSystemSessionSource {
|
|
|
4718
4764
|
});
|
|
4719
4765
|
}
|
|
4720
4766
|
parsePiFile(filePath) {
|
|
4721
|
-
const records = Array.from(parseJsonlLines(
|
|
4767
|
+
const records = Array.from(parseJsonlLines(readFileSync6(filePath, "utf-8")));
|
|
4722
4768
|
if (records.length === 0) throw new Error("empty file");
|
|
4723
4769
|
const header = records.find((record) => record["type"] === "session");
|
|
4724
4770
|
if (!header) throw new Error("missing session header");
|
|
@@ -5083,7 +5129,7 @@ var realFs = {
|
|
|
5083
5129
|
},
|
|
5084
5130
|
readText(path2) {
|
|
5085
5131
|
try {
|
|
5086
|
-
return
|
|
5132
|
+
return readFileSync7(path2, "utf8");
|
|
5087
5133
|
} catch {
|
|
5088
5134
|
return null;
|
|
5089
5135
|
}
|
|
@@ -5096,43 +5142,6 @@ var realFs = {
|
|
|
5096
5142
|
};
|
|
5097
5143
|
}
|
|
5098
5144
|
};
|
|
5099
|
-
function getAgentName(session) {
|
|
5100
|
-
return session.slug.split("/")[0]?.toLowerCase() || "unknown";
|
|
5101
|
-
}
|
|
5102
|
-
function buildProjectGroups(sessions) {
|
|
5103
|
-
const groups = /* @__PURE__ */ new Map();
|
|
5104
|
-
for (const session of sessions) {
|
|
5105
|
-
const identity = session.project_identity;
|
|
5106
|
-
if (!identity) continue;
|
|
5107
|
-
const activity = session.time_updated ?? session.time_created;
|
|
5108
|
-
const groupKey = `${identity.kind}:${identity.key}`;
|
|
5109
|
-
const current = groups.get(groupKey);
|
|
5110
|
-
if (current) {
|
|
5111
|
-
current.sources.add(getAgentName(session));
|
|
5112
|
-
current.sessionCount += 1;
|
|
5113
|
-
current.lastActivity = Math.max(current.lastActivity, activity);
|
|
5114
|
-
} else {
|
|
5115
|
-
groups.set(groupKey, {
|
|
5116
|
-
identity,
|
|
5117
|
-
sources: /* @__PURE__ */ new Set([getAgentName(session)]),
|
|
5118
|
-
sessionCount: 1,
|
|
5119
|
-
lastActivity: activity
|
|
5120
|
-
});
|
|
5121
|
-
}
|
|
5122
|
-
}
|
|
5123
|
-
return [...groups.values()].map((group) => ({
|
|
5124
|
-
identityKind: group.identity.kind,
|
|
5125
|
-
identityKey: group.identity.key,
|
|
5126
|
-
displayName: group.identity.displayName,
|
|
5127
|
-
sources: [...group.sources].sort(),
|
|
5128
|
-
sessionCount: group.sessionCount,
|
|
5129
|
-
lastActivity: group.lastActivity || null
|
|
5130
|
-
})).sort((a, b) => {
|
|
5131
|
-
if (a.identityKind === "loose" && b.identityKind !== "loose") return 1;
|
|
5132
|
-
if (b.identityKind === "loose" && a.identityKind !== "loose") return -1;
|
|
5133
|
-
return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);
|
|
5134
|
-
});
|
|
5135
|
-
}
|
|
5136
5145
|
var MANIFESTS = [
|
|
5137
5146
|
"package.json",
|
|
5138
5147
|
"Cargo.toml",
|
|
@@ -5145,6 +5154,23 @@ var MANIFESTS = [
|
|
|
5145
5154
|
var PARSEABLE_MANIFESTS = ["package.json", "Cargo.toml", "pyproject.toml"];
|
|
5146
5155
|
var LOOSE_DIRS = /* @__PURE__ */ new Set(["/tmp", "/private/tmp"]);
|
|
5147
5156
|
var LOOSE_HOME_DIRS = ["Desktop", "Downloads", "Documents"];
|
|
5157
|
+
var PROJECT_IDENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
5158
|
+
"git_remote",
|
|
5159
|
+
"git_common_dir",
|
|
5160
|
+
"manifest_path",
|
|
5161
|
+
"synthetic",
|
|
5162
|
+
"path",
|
|
5163
|
+
"loose"
|
|
5164
|
+
]);
|
|
5165
|
+
function isProjectIdentityKind(value) {
|
|
5166
|
+
return PROJECT_IDENTITY_KINDS.has(value);
|
|
5167
|
+
}
|
|
5168
|
+
function getProjectIdentityKey(identity) {
|
|
5169
|
+
return `${identity.kind}:${identity.key}`;
|
|
5170
|
+
}
|
|
5171
|
+
function matchesProjectIdentity(identity, expected) {
|
|
5172
|
+
return identity?.kind === expected.kind && identity.key === expected.key;
|
|
5173
|
+
}
|
|
5148
5174
|
function normalizeGitRemote(url) {
|
|
5149
5175
|
if (!url) return null;
|
|
5150
5176
|
let value = url.trim().replace(/\.git$/, "");
|
|
@@ -5275,15 +5301,53 @@ function parseManifestName(file, text) {
|
|
|
5275
5301
|
}
|
|
5276
5302
|
return null;
|
|
5277
5303
|
}
|
|
5304
|
+
function getAgentName(session) {
|
|
5305
|
+
return session.slug.split("/")[0]?.toLowerCase() || "unknown";
|
|
5306
|
+
}
|
|
5307
|
+
function buildProjectGroups(sessions) {
|
|
5308
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5309
|
+
for (const session of sessions) {
|
|
5310
|
+
const identity = session.project_identity;
|
|
5311
|
+
if (!identity) continue;
|
|
5312
|
+
const activity = session.time_updated ?? session.time_created;
|
|
5313
|
+
const groupKey = getProjectIdentityKey(identity);
|
|
5314
|
+
const current = groups.get(groupKey);
|
|
5315
|
+
if (current) {
|
|
5316
|
+
current.sources.add(getAgentName(session));
|
|
5317
|
+
current.sessionCount += 1;
|
|
5318
|
+
current.lastActivity = Math.max(current.lastActivity, activity);
|
|
5319
|
+
} else {
|
|
5320
|
+
groups.set(groupKey, {
|
|
5321
|
+
identity,
|
|
5322
|
+
sources: /* @__PURE__ */ new Set([getAgentName(session)]),
|
|
5323
|
+
sessionCount: 1,
|
|
5324
|
+
lastActivity: activity
|
|
5325
|
+
});
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
return [...groups.values()].map((group) => ({
|
|
5329
|
+
identityKind: group.identity.kind,
|
|
5330
|
+
identityKey: group.identity.key,
|
|
5331
|
+
displayName: group.identity.displayName,
|
|
5332
|
+
sources: [...group.sources].sort(),
|
|
5333
|
+
sessionCount: group.sessionCount,
|
|
5334
|
+
lastActivity: group.lastActivity || null
|
|
5335
|
+
})).sort((a, b) => {
|
|
5336
|
+
if (a.identityKind === "loose" && b.identityKind !== "loose") return 1;
|
|
5337
|
+
if (b.identityKind === "loose" && a.identityKind !== "loose") return -1;
|
|
5338
|
+
return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);
|
|
5339
|
+
});
|
|
5340
|
+
}
|
|
5278
5341
|
function createProjectScopeMatcher(queryPath, fs = realFs) {
|
|
5342
|
+
const identity = computeIdentity(queryPath, fs);
|
|
5279
5343
|
return {
|
|
5280
|
-
|
|
5344
|
+
identity: { kind: identity.kind, key: identity.key },
|
|
5281
5345
|
path: normalizeScopePath(queryPath)
|
|
5282
5346
|
};
|
|
5283
5347
|
}
|
|
5284
5348
|
function matchesProjectScope(session, scope) {
|
|
5285
5349
|
if (!session.directory) return false;
|
|
5286
|
-
if (session.project_identity
|
|
5350
|
+
if (matchesProjectIdentity(session.project_identity, scope.identity)) return true;
|
|
5287
5351
|
return isPathScopeMatch(scope.path, session.directory);
|
|
5288
5352
|
}
|
|
5289
5353
|
function filterSessionsByProjectScope(sessions, queryPath, fs) {
|
|
@@ -6892,30 +6956,6 @@ function ensureSchema(db, dbPath) {
|
|
|
6892
6956
|
setCacheSchemaVersion(db);
|
|
6893
6957
|
}
|
|
6894
6958
|
}
|
|
6895
|
-
function shouldBulkSyncSearchIndex(options, changedCount) {
|
|
6896
|
-
if (options.isBulk != null) {
|
|
6897
|
-
return options.isBulk;
|
|
6898
|
-
}
|
|
6899
|
-
const threshold = options.bulkThreshold ?? SEARCH_INDEX_BULK_SYNC_THRESHOLD;
|
|
6900
|
-
return threshold > 0 && changedCount >= threshold;
|
|
6901
|
-
}
|
|
6902
|
-
function sessionContentHash(session) {
|
|
6903
|
-
return JSON.stringify([
|
|
6904
|
-
session.slug,
|
|
6905
|
-
session.title,
|
|
6906
|
-
session.directory,
|
|
6907
|
-
session.time_created,
|
|
6908
|
-
session.time_updated ?? session.time_created,
|
|
6909
|
-
session.stats.message_count,
|
|
6910
|
-
session.stats.total_input_tokens,
|
|
6911
|
-
session.stats.total_output_tokens,
|
|
6912
|
-
session.stats.total_cache_read_tokens ?? 0,
|
|
6913
|
-
session.stats.total_cache_create_tokens ?? 0,
|
|
6914
|
-
session.stats.total_cost,
|
|
6915
|
-
session.stats.cost_source ?? "",
|
|
6916
|
-
session.stats.total_tokens ?? 0
|
|
6917
|
-
]);
|
|
6918
|
-
}
|
|
6919
6959
|
function escapeFtsTerm(value) {
|
|
6920
6960
|
return value.replaceAll('"', '""');
|
|
6921
6961
|
}
|
|
@@ -6938,9 +6978,7 @@ function splitSearchTokens(input) {
|
|
|
6938
6978
|
}
|
|
6939
6979
|
token += char;
|
|
6940
6980
|
}
|
|
6941
|
-
if (token)
|
|
6942
|
-
tokens.push(token);
|
|
6943
|
-
}
|
|
6981
|
+
if (token) tokens.push(token);
|
|
6944
6982
|
return tokens;
|
|
6945
6983
|
}
|
|
6946
6984
|
function unwrapSearchValue(value) {
|
|
@@ -7000,7 +7038,10 @@ function parseSearchQuery(input) {
|
|
|
7000
7038
|
if (key === "agent") filters.agent = value.toLowerCase();
|
|
7001
7039
|
else if (key === "project") filters.project = value;
|
|
7002
7040
|
else if (key === "projectkey" || key === "project-key") filters.projectKey = value;
|
|
7003
|
-
else if (key === "
|
|
7041
|
+
else if (key === "projectkind" || key === "project-kind") {
|
|
7042
|
+
if (isProjectIdentityKind(value)) filters.projectKind = value;
|
|
7043
|
+
else consumed = false;
|
|
7044
|
+
} else if (key === "cwd") filters.cwd = value;
|
|
7004
7045
|
else if (key === "tool") filters.tools = appendUnique(filters.tools, value.toLowerCase());
|
|
7005
7046
|
else if (key === "file" || key === "path") filters.file = value;
|
|
7006
7047
|
else if (key === "kind" || key === "filekind" || key === "file-kind") {
|
|
@@ -7011,21 +7052,15 @@ function parseSearchQuery(input) {
|
|
|
7011
7052
|
}
|
|
7012
7053
|
} else if (key === "tag" || key === "signal") {
|
|
7013
7054
|
const tag = value.toLowerCase();
|
|
7014
|
-
if (isSmartTag(tag))
|
|
7015
|
-
|
|
7016
|
-
} else {
|
|
7017
|
-
consumed = false;
|
|
7018
|
-
}
|
|
7055
|
+
if (isSmartTag(tag)) filters.tags = appendUnique(filters.tags, tag);
|
|
7056
|
+
else consumed = false;
|
|
7019
7057
|
} else if (key === "cost") {
|
|
7020
7058
|
parseCostQualifier(value, filters);
|
|
7021
7059
|
} else {
|
|
7022
7060
|
consumed = false;
|
|
7023
7061
|
}
|
|
7024
|
-
if (consumed)
|
|
7025
|
-
|
|
7026
|
-
} else {
|
|
7027
|
-
textTokens.push(token);
|
|
7028
|
-
}
|
|
7062
|
+
if (consumed) hasQualifiers = true;
|
|
7063
|
+
else textTokens.push(token);
|
|
7029
7064
|
}
|
|
7030
7065
|
return {
|
|
7031
7066
|
text: textTokens.join(" ").trim(),
|
|
@@ -7035,18 +7070,75 @@ function parseSearchQuery(input) {
|
|
|
7035
7070
|
}
|
|
7036
7071
|
function toFtsQuery(input) {
|
|
7037
7072
|
const tokens = splitSearchTokens(input);
|
|
7038
|
-
|
|
7039
|
-
if (/^OR$/i.test(token))
|
|
7040
|
-
return "OR";
|
|
7041
|
-
}
|
|
7073
|
+
return tokens.map((token) => {
|
|
7074
|
+
if (/^OR$/i.test(token)) return "OR";
|
|
7042
7075
|
if (token.startsWith('"') && token.endsWith('"')) {
|
|
7043
7076
|
return `"${escapeFtsTerm(token.slice(1, -1))}"`;
|
|
7044
7077
|
}
|
|
7045
7078
|
return `"${escapeFtsTerm(token)}"`;
|
|
7046
7079
|
}).filter(
|
|
7047
7080
|
(token, index, values) => token !== "OR" || index > 0 && index < values.length - 1 && values[index - 1] !== "OR" && values[index + 1] !== "OR"
|
|
7048
|
-
);
|
|
7049
|
-
|
|
7081
|
+
).join(" ");
|
|
7082
|
+
}
|
|
7083
|
+
var SEARCH_INDEX_STATE_BATCH_SIZE = 900;
|
|
7084
|
+
function shouldBulkSyncSearchIndex(options, changedCount) {
|
|
7085
|
+
if (options.isBulk != null) {
|
|
7086
|
+
return options.isBulk;
|
|
7087
|
+
}
|
|
7088
|
+
const threshold = options.bulkThreshold ?? SEARCH_INDEX_BULK_SYNC_THRESHOLD;
|
|
7089
|
+
return threshold > 0 && changedCount >= threshold;
|
|
7090
|
+
}
|
|
7091
|
+
function sessionContentHash(session) {
|
|
7092
|
+
return JSON.stringify([
|
|
7093
|
+
session.slug,
|
|
7094
|
+
session.title,
|
|
7095
|
+
session.directory,
|
|
7096
|
+
session.time_created,
|
|
7097
|
+
session.time_updated ?? session.time_created,
|
|
7098
|
+
session.stats.message_count,
|
|
7099
|
+
session.stats.total_input_tokens,
|
|
7100
|
+
session.stats.total_output_tokens,
|
|
7101
|
+
session.stats.total_cache_read_tokens ?? 0,
|
|
7102
|
+
session.stats.total_cache_create_tokens ?? 0,
|
|
7103
|
+
session.stats.total_cost,
|
|
7104
|
+
session.stats.cost_source ?? "",
|
|
7105
|
+
session.stats.total_tokens ?? 0
|
|
7106
|
+
]);
|
|
7107
|
+
}
|
|
7108
|
+
function searchIndexStateFromRows(indexedRows, messageCountRows) {
|
|
7109
|
+
return {
|
|
7110
|
+
contentHashBySessionId: new Map(
|
|
7111
|
+
indexedRows.map((row) => [String(row.session_id), String(row.content_hash ?? "")])
|
|
7112
|
+
),
|
|
7113
|
+
messageCountBySessionId: new Map(
|
|
7114
|
+
messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)])
|
|
7115
|
+
)
|
|
7116
|
+
};
|
|
7117
|
+
}
|
|
7118
|
+
function readSearchIndexState(db, agentName, sessionIds) {
|
|
7119
|
+
const rows = [];
|
|
7120
|
+
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
7121
|
+
for (let offset = 0; offset < uniqueSessionIds.length; offset += SEARCH_INDEX_STATE_BATCH_SIZE) {
|
|
7122
|
+
const batch = uniqueSessionIds.slice(offset, offset + SEARCH_INDEX_STATE_BATCH_SIZE);
|
|
7123
|
+
const requestedRows = batch.map(() => "(?)").join(", ");
|
|
7124
|
+
const batchRows = db.prepare(
|
|
7125
|
+
`
|
|
7126
|
+
WITH requested_session_ids(session_id) AS (VALUES ${requestedRows})
|
|
7127
|
+
SELECT
|
|
7128
|
+
requested.session_id,
|
|
7129
|
+
documents.content_hash,
|
|
7130
|
+
COUNT(messages.message_index) AS value
|
|
7131
|
+
FROM requested_session_ids AS requested
|
|
7132
|
+
LEFT JOIN session_documents AS documents
|
|
7133
|
+
ON documents.agent_name = ? AND documents.session_id = requested.session_id
|
|
7134
|
+
LEFT JOIN messages
|
|
7135
|
+
ON messages.agent_name = ? AND messages.session_id = requested.session_id
|
|
7136
|
+
GROUP BY requested.session_id, documents.content_hash
|
|
7137
|
+
`
|
|
7138
|
+
).all(...batch, agentName, agentName);
|
|
7139
|
+
rows.push(...batchRows);
|
|
7140
|
+
}
|
|
7141
|
+
return searchIndexStateFromRows(rows, rows);
|
|
7050
7142
|
}
|
|
7051
7143
|
function loadSearchIndexEntry(agentName, change, loadSessionData) {
|
|
7052
7144
|
try {
|
|
@@ -7222,20 +7314,15 @@ function syncSessionSearchIndex(agentName, sessions, loadSessionData, options =
|
|
|
7222
7314
|
const existingRows = db.prepare(
|
|
7223
7315
|
"SELECT session_id, content_hash FROM session_documents WHERE agent_name = ? ORDER BY id"
|
|
7224
7316
|
).all(agentName);
|
|
7225
|
-
const existingMap = new Map(
|
|
7226
|
-
existingRows.map((row) => [String(row.session_id), String(row.content_hash ?? "")])
|
|
7227
|
-
);
|
|
7228
7317
|
const sessionSortIndexMap = new Map(sessions.map((session, index) => [session.id, index]));
|
|
7229
7318
|
const messageCountRows = db.prepare(
|
|
7230
7319
|
"SELECT session_id, COUNT(*) AS value FROM messages WHERE agent_name = ? GROUP BY session_id"
|
|
7231
7320
|
).all(agentName);
|
|
7232
|
-
const
|
|
7233
|
-
messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)])
|
|
7234
|
-
);
|
|
7321
|
+
const searchIndexState = searchIndexStateFromRows(existingRows, messageCountRows);
|
|
7235
7322
|
const sessionMap = new Map(sessions.map((session) => [session.id, session]));
|
|
7236
7323
|
const toDelete = existingRows.map((row) => String(row.session_id)).filter((sessionId) => !sessionMap.has(sessionId));
|
|
7237
7324
|
const toUpsert = sessions.filter(
|
|
7238
|
-
(session) =>
|
|
7325
|
+
(session) => searchIndexState.contentHashBySessionId.get(session.id) !== sessionContentHash(session) || searchIndexState.messageCountBySessionId.get(session.id) !== session.stats.message_count
|
|
7239
7326
|
);
|
|
7240
7327
|
const changedCount = toDelete.length + toUpsert.length;
|
|
7241
7328
|
const isBulk = shouldBulkSyncSearchIndex(options, changedCount);
|
|
@@ -7293,17 +7380,14 @@ function syncSessionSearchIndexChanges(agentName, changes, removedSessionIds, lo
|
|
|
7293
7380
|
return withCacheDb((db) => {
|
|
7294
7381
|
ensureFtsConsistency(db);
|
|
7295
7382
|
const startedAt = performance.now();
|
|
7296
|
-
const
|
|
7297
|
-
|
|
7383
|
+
const searchIndexState = readSearchIndexState(
|
|
7384
|
+
db,
|
|
7385
|
+
agentName,
|
|
7386
|
+
changes.map(({ session }) => session.id)
|
|
7298
7387
|
);
|
|
7299
|
-
const
|
|
7300
|
-
|
|
7388
|
+
const toUpsert = changes.filter(
|
|
7389
|
+
({ session }) => (searchIndexState.contentHashBySessionId.get(session.id) ?? "") !== sessionContentHash(session) || (searchIndexState.messageCountBySessionId.get(session.id) ?? 0) !== session.stats.message_count
|
|
7301
7390
|
);
|
|
7302
|
-
const toUpsert = changes.filter(({ session }) => {
|
|
7303
|
-
const indexed = getIndexedRow.get(agentName, session.id);
|
|
7304
|
-
const messageCount = getMessageCount.get(agentName, session.id);
|
|
7305
|
-
return String(indexed?.content_hash ?? "") !== sessionContentHash(session) || Number(messageCount?.value ?? 0) !== session.stats.message_count;
|
|
7306
|
-
});
|
|
7307
7391
|
const uniqueRemovedSessionIds = Array.from(new Set(removedSessionIds));
|
|
7308
7392
|
const changedCount = uniqueRemovedSessionIds.length + toUpsert.length;
|
|
7309
7393
|
const isBulk = shouldBulkSyncSearchIndex(options, changedCount);
|
|
@@ -7354,6 +7438,7 @@ function mergeSearchQueryOptions(query, options) {
|
|
|
7354
7438
|
...options,
|
|
7355
7439
|
agent: options.agent ?? parsed2.filters.agent,
|
|
7356
7440
|
project: options.project ?? parsed2.filters.project,
|
|
7441
|
+
projectKind: options.projectKind ?? parsed2.filters.projectKind,
|
|
7357
7442
|
projectKey: options.projectKey ?? parsed2.filters.projectKey,
|
|
7358
7443
|
cwd: options.cwd ?? parsed2.filters.cwd,
|
|
7359
7444
|
tags: mergeSearchLists(options.tags, parsed2.filters.tags),
|
|
@@ -7389,13 +7474,20 @@ function buildSessionSearchFilters(options) {
|
|
|
7389
7474
|
clauses.push("s.agent_name = ?");
|
|
7390
7475
|
params.push(options.agent);
|
|
7391
7476
|
}
|
|
7392
|
-
if (options.projectKey) {
|
|
7393
|
-
|
|
7394
|
-
|
|
7477
|
+
if (options.projectKind || options.projectKey) {
|
|
7478
|
+
if (options.projectKind && options.projectKey) {
|
|
7479
|
+
clauses.push("s.project_identity_kind = ? AND s.project_identity_key = ?");
|
|
7480
|
+
params.push(options.projectKind, options.projectKey);
|
|
7481
|
+
} else {
|
|
7482
|
+
clauses.push("0");
|
|
7483
|
+
}
|
|
7395
7484
|
}
|
|
7396
7485
|
if (options.cwd) {
|
|
7397
|
-
|
|
7398
|
-
|
|
7486
|
+
const identity = computeIdentity(options.cwd, realFs);
|
|
7487
|
+
clauses.push(
|
|
7488
|
+
"((s.project_identity_kind = ? AND s.project_identity_key = ?) OR LOWER(s.directory) LIKE ? ESCAPE '\\')"
|
|
7489
|
+
);
|
|
7490
|
+
params.push(identity.kind, identity.key, likePattern(options.cwd));
|
|
7399
7491
|
}
|
|
7400
7492
|
if (options.project) {
|
|
7401
7493
|
clauses.push(
|
|
@@ -7640,10 +7732,13 @@ function searchSessions(query, options = {}) {
|
|
|
7640
7732
|
}
|
|
7641
7733
|
function fileActivityFilters(options) {
|
|
7642
7734
|
const path2 = options.path ? normalizeFilePathSearch(options.path) : "";
|
|
7735
|
+
const cwdIdentity = options.cwd ? computeIdentity(options.cwd, realFs) : null;
|
|
7643
7736
|
return {
|
|
7737
|
+
projectKind: options.projectKind ?? null,
|
|
7644
7738
|
projectKey: options.projectKey ?? null,
|
|
7645
7739
|
projectLike: options.project ? likePattern(options.project) : null,
|
|
7646
|
-
|
|
7740
|
+
cwdKind: cwdIdentity?.kind ?? null,
|
|
7741
|
+
cwdKey: cwdIdentity?.key ?? null,
|
|
7647
7742
|
cwdLike: options.cwd ? likePattern(options.cwd) : null,
|
|
7648
7743
|
path: path2,
|
|
7649
7744
|
pathLike: path2 ? likePattern(path2) : null
|
|
@@ -7672,9 +7767,13 @@ function buildFileActivityWhere(options) {
|
|
|
7672
7767
|
clauses.push("fa.session_id = ?");
|
|
7673
7768
|
params.push(options.sessionId);
|
|
7674
7769
|
}
|
|
7675
|
-
if (filters.projectKey != null) {
|
|
7676
|
-
|
|
7677
|
-
|
|
7770
|
+
if (filters.projectKind != null || filters.projectKey != null) {
|
|
7771
|
+
if (filters.projectKind != null && filters.projectKey != null) {
|
|
7772
|
+
clauses.push("s.project_identity_kind = ? AND fa.project_identity_key = ?");
|
|
7773
|
+
params.push(filters.projectKind, filters.projectKey);
|
|
7774
|
+
} else {
|
|
7775
|
+
clauses.push("0");
|
|
7776
|
+
}
|
|
7678
7777
|
}
|
|
7679
7778
|
if (filters.projectLike != null) {
|
|
7680
7779
|
clauses.push(
|
|
@@ -7683,8 +7782,10 @@ function buildFileActivityWhere(options) {
|
|
|
7683
7782
|
params.push(filters.projectLike, filters.projectLike, filters.projectLike);
|
|
7684
7783
|
}
|
|
7685
7784
|
if (filters.cwdKey != null) {
|
|
7686
|
-
clauses.push(
|
|
7687
|
-
|
|
7785
|
+
clauses.push(
|
|
7786
|
+
"((s.project_identity_kind = ? AND s.project_identity_key = ?) OR LOWER(s.directory) LIKE ? ESCAPE '\\')"
|
|
7787
|
+
);
|
|
7788
|
+
params.push(filters.cwdKind, filters.cwdKey, filters.cwdLike);
|
|
7688
7789
|
}
|
|
7689
7790
|
if (filters.pathLike != null) {
|
|
7690
7791
|
const pathQuery = filePathFtsQuery(filters.path);
|
|
@@ -7782,6 +7883,7 @@ function searchFileActivitySessions(query, options = {}) {
|
|
|
7782
7883
|
if (!path2) return [];
|
|
7783
7884
|
const rows = listFileActivity({
|
|
7784
7885
|
agent: search.options.agent,
|
|
7886
|
+
projectKind: search.options.projectKind,
|
|
7785
7887
|
projectKey: search.options.projectKey,
|
|
7786
7888
|
project: search.options.project,
|
|
7787
7889
|
cwd: search.options.cwd,
|
|
@@ -8258,9 +8360,7 @@ function sessionSignature(session) {
|
|
|
8258
8360
|
]);
|
|
8259
8361
|
}
|
|
8260
8362
|
function sortSessions(sessions) {
|
|
8261
|
-
return
|
|
8262
|
-
(a, b) => (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created)
|
|
8263
|
-
);
|
|
8363
|
+
return sortSessionsByActivity(sessions);
|
|
8264
8364
|
}
|
|
8265
8365
|
function computeSessionDiff(cachedSessions, updatedSessions, changedIds = [], signature = sessionSignature) {
|
|
8266
8366
|
const cachedMap = new Map(cachedSessions.map((session) => [session.id, session]));
|
|
@@ -8974,10 +9074,11 @@ function buildDashboard(sessions, options) {
|
|
|
8974
9074
|
for (const session of sessions) {
|
|
8975
9075
|
const agentName = getSessionAgentName(session);
|
|
8976
9076
|
if (scope.agent && agentName !== scope.agent) continue;
|
|
8977
|
-
if (scope.projectKey) {
|
|
9077
|
+
if (scope.projectKind || scope.projectKey) {
|
|
8978
9078
|
const identity = session.project_identity;
|
|
8979
|
-
if (!identity || identity.key !== scope.projectKey)
|
|
8980
|
-
|
|
9079
|
+
if (!identity || !scope.projectKind || !scope.projectKey || identity.kind !== scope.projectKind || identity.key !== scope.projectKey) {
|
|
9080
|
+
continue;
|
|
9081
|
+
}
|
|
8981
9082
|
}
|
|
8982
9083
|
const activity = getSessionActivityTime(session);
|
|
8983
9084
|
if (from != null && activity < from) continue;
|
|
@@ -9076,6 +9177,90 @@ function buildDashboard(sessions, options) {
|
|
|
9076
9177
|
recentSessions
|
|
9077
9178
|
};
|
|
9078
9179
|
}
|
|
9180
|
+
function executeSessionSearch(query, options, snapshot) {
|
|
9181
|
+
const merged = mergeSearchQueryOptions(query, options);
|
|
9182
|
+
if (!needsIndexedSearch(merged.text, merged.options)) {
|
|
9183
|
+
return searchRecentSessions(snapshot, merged.options);
|
|
9184
|
+
}
|
|
9185
|
+
return searchIndexedSessions(query, merged.text, merged.parsed, merged.options);
|
|
9186
|
+
}
|
|
9187
|
+
function needsIndexedSearch(textQuery, options) {
|
|
9188
|
+
return Boolean(textQuery || options.file || options.fileKind || options.tools?.length);
|
|
9189
|
+
}
|
|
9190
|
+
function filterSessionsByActivityWindow(sessions, from, to) {
|
|
9191
|
+
if (from == null && to == null) return sessions;
|
|
9192
|
+
return sessions.filter((session) => {
|
|
9193
|
+
const activity = getSessionActivityTime(session);
|
|
9194
|
+
if (from != null && activity < from) return false;
|
|
9195
|
+
if (to != null && activity > to) return false;
|
|
9196
|
+
return true;
|
|
9197
|
+
});
|
|
9198
|
+
}
|
|
9199
|
+
function matchesRecentSearchFilters(session, options, projectScope) {
|
|
9200
|
+
if (options.projectKind || options.projectKey) {
|
|
9201
|
+
if (!options.projectKind || !options.projectKey || !matchesProjectIdentity(session.project_identity, {
|
|
9202
|
+
kind: options.projectKind,
|
|
9203
|
+
key: options.projectKey
|
|
9204
|
+
})) {
|
|
9205
|
+
return false;
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9208
|
+
if (projectScope && !matchesProjectScope(session, projectScope)) return false;
|
|
9209
|
+
if (options.project) {
|
|
9210
|
+
const projectNeedle = options.project.toLowerCase();
|
|
9211
|
+
const projectText = [
|
|
9212
|
+
session.project_identity?.key,
|
|
9213
|
+
session.project_identity?.displayName,
|
|
9214
|
+
session.directory
|
|
9215
|
+
].filter(Boolean).join("\n").toLowerCase();
|
|
9216
|
+
if (!projectText.includes(projectNeedle)) return false;
|
|
9217
|
+
}
|
|
9218
|
+
if (options.tags?.length && !options.tags.every((tag) => session.smart_tags?.includes(tag))) {
|
|
9219
|
+
return false;
|
|
9220
|
+
}
|
|
9221
|
+
if (!sessionMatchesSearchCost(session, options)) return false;
|
|
9222
|
+
return true;
|
|
9223
|
+
}
|
|
9224
|
+
function searchRecentSessions(snapshot, options) {
|
|
9225
|
+
const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;
|
|
9226
|
+
const entries = options.agent ? [[options.agent, snapshot.byAgent[options.agent] ?? []]] : Object.entries(snapshot.byAgent);
|
|
9227
|
+
return entries.flatMap(
|
|
9228
|
+
([agentName, sessions]) => filterSessionsByActivityWindow(sessions, options.from, options.to).filter((session) => matchesRecentSearchFilters(session, options, projectScope)).map((session) => ({ agentName, session }))
|
|
9229
|
+
).sort(
|
|
9230
|
+
(a, b) => (b.session.time_updated ?? b.session.time_created) - (a.session.time_updated ?? a.session.time_created)
|
|
9231
|
+
).slice(0, options.limit ?? 50).map(({ agentName, session }) => ({
|
|
9232
|
+
agentName,
|
|
9233
|
+
session,
|
|
9234
|
+
snippet: `Recent session \xB7 ${session.directory}`,
|
|
9235
|
+
matchType: "recent"
|
|
9236
|
+
}));
|
|
9237
|
+
}
|
|
9238
|
+
function deriveFileQuery(query, parsed2, options) {
|
|
9239
|
+
return options.file ?? (!parsed2.text ? parsed2.filters.file : void 0) ?? (!parsed2.hasQualifiers && query ? parsed2.text || query : "");
|
|
9240
|
+
}
|
|
9241
|
+
function mergeSearchResultSources(results, limit) {
|
|
9242
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9243
|
+
const merged = [];
|
|
9244
|
+
for (const result of results) {
|
|
9245
|
+
const key = `${result.agentName}/${result.session.id}`;
|
|
9246
|
+
if (seen.has(key)) continue;
|
|
9247
|
+
seen.add(key);
|
|
9248
|
+
merged.push(result);
|
|
9249
|
+
if (merged.length >= limit) break;
|
|
9250
|
+
}
|
|
9251
|
+
return merged;
|
|
9252
|
+
}
|
|
9253
|
+
function canSkipSessionsSearch(fileQuery, textQuery, options) {
|
|
9254
|
+
return Boolean(
|
|
9255
|
+
fileQuery && !textQuery && !options.tools?.length && !options.tags?.length && options.from == null && options.to == null
|
|
9256
|
+
);
|
|
9257
|
+
}
|
|
9258
|
+
function searchIndexedSessions(query, textQuery, parsed2, options) {
|
|
9259
|
+
const fileQuery = deriveFileQuery(query, parsed2, options);
|
|
9260
|
+
const fileResults = fileQuery ? searchFileActivitySessions(fileQuery, options) : [];
|
|
9261
|
+
const sessionResults = canSkipSessionsSearch(fileQuery, textQuery, options) ? [] : searchSessions(query, options);
|
|
9262
|
+
return mergeSearchResultSources([...fileResults, ...sessionResults], options.limit ?? 50);
|
|
9263
|
+
}
|
|
9079
9264
|
|
|
9080
9265
|
export {
|
|
9081
9266
|
registerAgent,
|
|
@@ -9125,9 +9310,12 @@ export {
|
|
|
9125
9310
|
isSqliteAvailable,
|
|
9126
9311
|
fallbackDisplayName,
|
|
9127
9312
|
realFs,
|
|
9128
|
-
|
|
9313
|
+
isProjectIdentityKind,
|
|
9314
|
+
getProjectIdentityKey,
|
|
9315
|
+
matchesProjectIdentity,
|
|
9129
9316
|
normalizeGitRemote,
|
|
9130
9317
|
computeIdentity,
|
|
9318
|
+
buildProjectGroups,
|
|
9131
9319
|
createProjectScopeMatcher,
|
|
9132
9320
|
matchesProjectScope,
|
|
9133
9321
|
filterSessionsByProjectScope,
|
|
@@ -9176,6 +9364,7 @@ export {
|
|
|
9176
9364
|
getSessionActivityTime,
|
|
9177
9365
|
toLocalDateKey,
|
|
9178
9366
|
startOfLocalDay,
|
|
9179
|
-
buildDashboard
|
|
9367
|
+
buildDashboard,
|
|
9368
|
+
executeSessionSearch
|
|
9180
9369
|
};
|
|
9181
|
-
//# sourceMappingURL=chunk-
|
|
9370
|
+
//# sourceMappingURL=chunk-BV65IEWZ.js.map
|