codesesh 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +16 -0
  2. package/dist/{chunk-L4G3LE7I.js → chunk-5YY675UR.js} +2 -2
  3. package/dist/{chunk-DHQPM5FF.js → chunk-CIMPLUT6.js} +5 -5
  4. package/dist/{chunk-YLXHGL4S.js → chunk-MOZLVHCC.js} +20 -2
  5. package/dist/{chunk-YLXHGL4S.js.map → chunk-MOZLVHCC.js.map} +1 -1
  6. package/dist/{chunk-V3HKVTIO.js → chunk-QFG33PKR.js} +2 -2
  7. package/dist/{chunk-KVTLNX7V.js → chunk-RDTQ2WPR.js} +2 -2
  8. package/dist/{chunk-RBCCNCDO.js → chunk-ZDH2BKQK.js} +696 -4
  9. package/dist/chunk-ZDH2BKQK.js.map +1 -0
  10. package/dist/{chunk-AGUAXTKC.js → chunk-ZLU7ODBV.js} +2 -2
  11. package/dist/{discovery-KEZQU6RL.js → discovery-MS2ZSMZ5.js} +5 -5
  12. package/dist/index.js +8 -8
  13. package/dist/project-identity-worker.js +4 -4
  14. package/dist/scan-refresh-worker.js +6 -6
  15. package/dist/search-index-worker.js +6 -6
  16. package/dist/session-detail-worker.js +6 -6
  17. package/dist/smart-tag-worker.js +3 -3
  18. package/dist/web/assets/CustomTimeWindowDialog-CGPvUFkc.js +1 -0
  19. package/dist/web/assets/DetailLanding-Dgb2Qg8H.js +1 -0
  20. package/dist/web/assets/{InteractiveReceipt-Bsj37HtN.js → InteractiveReceipt-SckXLiPB.js} +1 -1
  21. package/dist/web/assets/OverviewScreen-D44AMeDu.js +1 -0
  22. package/dist/web/assets/{PrismHighlighter-DWS6Nx_X.js → PrismHighlighter-D7JLjKja.js} +1 -1
  23. package/dist/web/assets/Projects-DVHOqH2Z.js +1 -0
  24. package/dist/web/assets/{SearchResultsPanel-BAManMmt.js → SearchResultsPanel-B1WEw9Q5.js} +1 -1
  25. package/dist/web/assets/SessionDetail-J00I4QfE.js +53 -0
  26. package/dist/web/assets/index-BIpTq_7T.js +1423 -0
  27. package/dist/web/assets/index-BXhaumu7.css +1 -0
  28. package/dist/web/assets/{panel-DcOuALYX.js → panel-B-5dVddJ.js} +1 -1
  29. package/dist/web/assets/session-indexes-3LjxBYNe.js +4 -0
  30. package/dist/web/assets/utils-BuYa9y6l.js +1 -0
  31. package/dist/web/icon/agent/cherrystudio.svg +7 -0
  32. package/dist/web/icon/agent/deepchat.LICENSE.txt +206 -0
  33. package/dist/web/icon/agent/deepchat.svg +6 -0
  34. package/dist/web/index.html +5 -192
  35. package/package.json +3 -3
  36. package/dist/chunk-RBCCNCDO.js.map +0 -1
  37. package/dist/web/assets/CustomTimeWindowDialog-z5xtqkBF.js +0 -1
  38. package/dist/web/assets/DetailLanding-CpV0jLmT.js +0 -1
  39. package/dist/web/assets/OverviewScreen-B9qZqEQA.js +0 -1
  40. package/dist/web/assets/Projects-oY3KCgS4.js +0 -1
  41. package/dist/web/assets/SessionDetail-KSgkmLV7.js +0 -53
  42. package/dist/web/assets/index-BSLHxV0w.css +0 -1
  43. package/dist/web/assets/index-DNw59Qsn.js +0 -1423
  44. package/dist/web/assets/session-indexes-DKukxoe1.js +0 -4
  45. package/dist/web/assets/utils-Dk_44zMo.js +0 -1
  46. /package/dist/{chunk-L4G3LE7I.js.map → chunk-5YY675UR.js.map} +0 -0
  47. /package/dist/{chunk-DHQPM5FF.js.map → chunk-CIMPLUT6.js.map} +0 -0
  48. /package/dist/{chunk-V3HKVTIO.js.map → chunk-QFG33PKR.js.map} +0 -0
  49. /package/dist/{chunk-KVTLNX7V.js.map → chunk-RDTQ2WPR.js.map} +0 -0
  50. /package/dist/{chunk-AGUAXTKC.js.map → chunk-ZLU7ODBV.js.map} +0 -0
  51. /package/dist/{discovery-KEZQU6RL.js.map → discovery-MS2ZSMZ5.js.map} +0 -0
@@ -32,14 +32,14 @@ import {
32
32
  reportFieldMismatch,
33
33
  resolveSessionTitle,
34
34
  safeParseJsonRecord
35
- } from "./chunk-YLXHGL4S.js";
35
+ } from "./chunk-MOZLVHCC.js";
36
36
 
37
- // ../core/dist/chunk-V6GZEKLJ.mjs
37
+ // ../core/dist/chunk-SJU7QB6Z.mjs
38
38
  import { statSync } from "fs";
39
39
  import { readdirSync, statSync as statSync2 } from "fs";
40
40
  import { join } from "path";
41
41
  import { existsSync as existsSync2, readFileSync, statSync as statSync3 } from "fs";
42
- import { join as join3, basename, dirname } from "path";
42
+ import { join as join3, basename, dirname, isAbsolute as isAbsolute2, relative, sep } from "path";
43
43
  import { existsSync } from "fs";
44
44
  import { homedir, platform } from "os";
45
45
  import { isAbsolute, join as join2, resolve } from "path";
@@ -68,6 +68,12 @@ import * as zlib from "zlib";
68
68
  import { createHash as createHash2 } from "crypto";
69
69
  import { readFileSync as readFileSync8 } from "fs";
70
70
  import { join as join13 } from "path";
71
+ import { createHash as createHash3 } from "crypto";
72
+ import { homedir as homedir4, platform as platform4 } from "os";
73
+ import { join as join15 } from "path";
74
+ import { createHash as createHash4 } from "crypto";
75
+ import { homedir as homedir5, platform as platform5 } from "os";
76
+ import { join as join16 } from "path";
71
77
  function fingerprintMatches(ref, cached) {
72
78
  return typeof cached?.sourceFingerprint === "string" && cached.sourceFingerprint === ref.fingerprint;
73
79
  }
@@ -1423,6 +1429,16 @@ var ClaudeCodeAgent = class extends SingleFileSessionSource {
1423
1429
  }
1424
1430
  return false;
1425
1431
  }
1432
+ filterCachedSessions(sessions) {
1433
+ const basePath = this.basePath ?? this.findBasePath();
1434
+ if (!basePath) return sessions;
1435
+ return sessions.filter((session) => {
1436
+ const sourcePath = this.sessionMetaMap.get(session.reference.sessionId)?.sourcePath;
1437
+ if (!sourcePath) return true;
1438
+ const path = relative(basePath, sourcePath);
1439
+ return path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute2(path);
1440
+ });
1441
+ }
1426
1442
  listSessionSources(options) {
1427
1443
  if (!this.basePath) return [];
1428
1444
  const projectDirs = this.listProjectDirs();
@@ -8305,6 +8321,674 @@ function isMissingDirectory(error) {
8305
8321
  const code = error.code;
8306
8322
  return code === "ENOENT" || code === "ENOTDIR";
8307
8323
  }
8324
+ function parseDeepChatJson(value) {
8325
+ if (typeof value !== "string") return value;
8326
+ try {
8327
+ return JSON.parse(value);
8328
+ } catch {
8329
+ return value;
8330
+ }
8331
+ }
8332
+ function deepChatTokens(metadata) {
8333
+ const input = asNumber(metadata.inputTokens);
8334
+ const output = asNumber(metadata.outputTokens);
8335
+ if (input === void 0 && output === void 0) return void 0;
8336
+ const cacheRead = Math.max(0, asNumber(metadata.cachedInputTokens) ?? 0);
8337
+ const cacheCreate = Math.max(0, asNumber(metadata.cacheWriteInputTokens) ?? 0);
8338
+ return {
8339
+ input: Math.max(0, input ?? 0),
8340
+ output: Math.max(0, output ?? 0),
8341
+ cache_read: Math.min(cacheRead, Math.max(0, input ?? 0)),
8342
+ cache_create: Math.min(cacheCreate, Math.max(0, (input ?? 0) - cacheRead))
8343
+ };
8344
+ }
8345
+ function deepChatAssistantPart(block) {
8346
+ const time_created = asNumber(block.timestamp);
8347
+ const content = asString(block.content);
8348
+ if (block.type === "tool_call") {
8349
+ const tool = asRecord(block.tool_call);
8350
+ if (!tool) return null;
8351
+ const status = block.status === "pending" || block.status === "loading" ? "running" : block.status === "error" || block.status === "denied" ? "error" : "completed";
8352
+ const output = parseDeepChatJson(tool.response);
8353
+ return {
8354
+ type: "tool",
8355
+ tool: asString(tool.name) ?? "unknown",
8356
+ callID: asString(tool.id),
8357
+ time_created,
8358
+ state: {
8359
+ status,
8360
+ input: parseDeepChatJson(tool.params),
8361
+ output,
8362
+ error: status === "error" ? output ?? content : void 0,
8363
+ metadata: asRecord(block.extra)
8364
+ }
8365
+ };
8366
+ }
8367
+ if (block.type === "image") {
8368
+ const image = asRecord(block.image_data);
8369
+ const data = asString(image?.data);
8370
+ const mime = asString(image?.mimeType);
8371
+ if (data && mime) return { type: "image", data, mime_type: mime, time_created };
8372
+ }
8373
+ if (!content) return null;
8374
+ return {
8375
+ type: block.type === "reasoning_content" ? "reasoning" : "text",
8376
+ text: content,
8377
+ time_created
8378
+ };
8379
+ }
8380
+ function deepChatStoredBlockPart(row) {
8381
+ const extra = asRecord(parseDeepChatJson(row.extra_json));
8382
+ return deepChatAssistantPart({
8383
+ type: row.block_type,
8384
+ content: row.text_content,
8385
+ status: row.status,
8386
+ timestamp: extra?.timestamp ?? row.updated_at,
8387
+ extra: extra?.extra,
8388
+ tool_call: {
8389
+ id: row.tool_call_id,
8390
+ name: row.tool_name,
8391
+ params: row.tool_params,
8392
+ response: row.tool_response
8393
+ },
8394
+ image_data: { data: extra?.imageData, mimeType: row.image_mime_type }
8395
+ });
8396
+ }
8397
+ function deepChatUserParts(content) {
8398
+ const parts = [];
8399
+ const text = asString(content.text);
8400
+ if (text) parts.push({ type: "text", text });
8401
+ for (const file of asArray(content.files) ?? []) {
8402
+ const record = asRecord(file);
8403
+ const path = asString(record?.path);
8404
+ const name = asString(record?.name);
8405
+ if (path || name) parts.push({ type: "text", text: `Attachment: ${path ?? name}` });
8406
+ }
8407
+ for (const link of asArray(content.links) ?? []) {
8408
+ if (typeof link === "string") parts.push({ type: "text", text: link });
8409
+ }
8410
+ return parts;
8411
+ }
8412
+ function deepChatRawParts(role, content) {
8413
+ const parsed = parseDeepChatJson(content);
8414
+ if (role === "user") {
8415
+ const user = asRecord(parsed);
8416
+ if (user) return deepChatUserParts(user);
8417
+ }
8418
+ if (Array.isArray(parsed)) {
8419
+ const parts = [];
8420
+ for (const value of parsed) {
8421
+ const block = asRecord(value);
8422
+ const part = block ? deepChatAssistantPart(block) : null;
8423
+ if (part) parts.push(part);
8424
+ }
8425
+ return parts;
8426
+ }
8427
+ return typeof parsed === "string" && parsed ? [{ type: "text", text: parsed }] : [];
8428
+ }
8429
+ var AGENT_METADATA11 = getAgentCatalogEntry("deepchat");
8430
+ function resolveDeepChatDataRoot() {
8431
+ const configured = readEnvPath("DEEPCHAT_USER_DATA_DIR");
8432
+ if (configured) return configured;
8433
+ if (platform4() === "darwin") return join15(homedir4(), "Library", "Application Support", "DeepChat");
8434
+ if (platform4() === "win32") {
8435
+ return join15(readEnvPath("APPDATA") ?? join15(homedir4(), "AppData", "Roaming"), "DeepChat");
8436
+ }
8437
+ return join15(readEnvPath("XDG_CONFIG_HOME") ?? join15(homedir4(), ".config"), "DeepChat");
8438
+ }
8439
+ function accumulateUsage(session, row) {
8440
+ const model = asString(row.model) ?? session.model;
8441
+ const provider = asString(row.provider) ?? session.provider;
8442
+ const tokens = deepChatTokens(row);
8443
+ if (!tokens && asNumber(row.totalTokens) === void 0) return;
8444
+ const input = tokens?.input ?? 0;
8445
+ const output = tokens?.output ?? 0;
8446
+ const total = Math.max(0, asNumber(row.totalTokens) ?? input + output);
8447
+ const { result: estimate, unpricedModels } = capturePricingMisses(
8448
+ () => estimateTokenCost(model, tokens)
8449
+ );
8450
+ for (const missing of unpricedModels) session.unpricedModels.add(missing);
8451
+ const cost = estimate ?? 0;
8452
+ const stats = session.head.stats;
8453
+ stats.total_input_tokens += input;
8454
+ stats.total_output_tokens += output;
8455
+ stats.total_tokens = (stats.total_tokens ?? 0) + total;
8456
+ stats.total_cache_read_tokens = (stats.total_cache_read_tokens ?? 0) + (tokens?.cache_read ?? 0);
8457
+ stats.total_cache_create_tokens = (stats.total_cache_create_tokens ?? 0) + (tokens?.cache_create ?? 0);
8458
+ stats.total_cost += cost;
8459
+ if (cost > 0) stats.cost_source = "estimated";
8460
+ if (model && total > 0) {
8461
+ const usage = session.head.model_usage ??= /* @__PURE__ */ Object.create(null);
8462
+ usage[model] = (usage[model] ?? 0) + total;
8463
+ }
8464
+ const messageId = asString(row.message_id);
8465
+ if (!messageId) return;
8466
+ const previous = session.messageUsage.get(messageId);
8467
+ session.messageUsage.set(messageId, {
8468
+ model,
8469
+ provider,
8470
+ cost: (previous?.cost ?? 0) + cost,
8471
+ tokens: {
8472
+ input: (previous?.tokens.input ?? 0) + input,
8473
+ output: (previous?.tokens.output ?? 0) + output,
8474
+ cache_read: (previous?.tokens.cache_read ?? 0) + (tokens?.cache_read ?? 0),
8475
+ cache_create: (previous?.tokens.cache_create ?? 0) + (tokens?.cache_create ?? 0)
8476
+ }
8477
+ });
8478
+ }
8479
+ var DeepChatAgent = class extends DatabaseSessionSource {
8480
+ name = AGENT_METADATA11.name;
8481
+ displayName = AGENT_METADATA11.displayName;
8482
+ sourceRoot;
8483
+ constructor(options = {}) {
8484
+ super();
8485
+ this.sourceRoot = options.sourceRoot ?? resolveDeepChatDataRoot();
8486
+ }
8487
+ getDatabasePath() {
8488
+ return firstExisting(join15(this.sourceRoot, "app_db", "agent.db"));
8489
+ }
8490
+ isAvailable() {
8491
+ return isSqliteAvailable() && this.getDatabasePath() !== null;
8492
+ }
8493
+ getSessionWatchPlan() {
8494
+ return {
8495
+ status: "supported",
8496
+ targets: [{ root: this.sourceRoot, path: join15(this.sourceRoot, "app_db", "agent.db") }]
8497
+ };
8498
+ }
8499
+ readDatabase(read) {
8500
+ const path = this.getDatabasePath();
8501
+ if (!path) throw new Error("DeepChat agent.db is missing");
8502
+ return this.scanStep("reading unencrypted DeepChat agent.db", path, () => {
8503
+ const db = openDbReadOnly(path);
8504
+ if (!db)
8505
+ throw new Error("Cannot open DeepChat agent.db; only unencrypted databases are supported");
8506
+ try {
8507
+ return db.transaction(() => read(db))();
8508
+ } finally {
8509
+ db.close();
8510
+ }
8511
+ });
8512
+ }
8513
+ scan(options) {
8514
+ if (!this.getDatabasePath()) return [];
8515
+ return this.readDatabase((db) => {
8516
+ const projections = this.readProjections(db);
8517
+ const selected = /* @__PURE__ */ new Set();
8518
+ const children = /* @__PURE__ */ new Map();
8519
+ for (const [id, projection] of projections) {
8520
+ const parent = projection.head.parent_reference?.sessionId;
8521
+ if (parent && projections.has(parent)) {
8522
+ const siblings = children.get(parent) ?? [];
8523
+ siblings.push(id);
8524
+ children.set(parent, siblings);
8525
+ } else if (matchesScanWindow(projection.head.time_updated ?? projection.head.time_created, options)) {
8526
+ selected.add(id);
8527
+ }
8528
+ }
8529
+ if (options?.includeRelatedSessions !== false) {
8530
+ for (const id of selected) {
8531
+ for (const child of children.get(id) ?? []) selected.add(child);
8532
+ }
8533
+ }
8534
+ const sessions = [];
8535
+ for (const id of selected) {
8536
+ const projection = projections.get(id);
8537
+ if (projection.head.stats.message_count === 0) continue;
8538
+ this.rememberSession(id, {
8539
+ sourceFingerprint: projection.signature.digest("hex"),
8540
+ headParserVersion: "deepchat-v1",
8541
+ unpricedModels: [...projection.unpricedModels]
8542
+ });
8543
+ sessions.push(projection.head);
8544
+ }
8545
+ sessions.sort(
8546
+ (left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
8547
+ );
8548
+ options?.onProgress?.({
8549
+ total: selected.size,
8550
+ processed: selected.size,
8551
+ sessions: sessions.length
8552
+ });
8553
+ return sessions;
8554
+ });
8555
+ }
8556
+ readProjections(db, sessionId) {
8557
+ const filter = sessionId ? "AND s.id = ?" : "";
8558
+ const bindings = sessionId ? [sessionId] : [];
8559
+ const projections = /* @__PURE__ */ new Map();
8560
+ const sessions = db.prepare(`
8561
+ SELECT s.id, s.agent_id, s.title, s.project_dir, s.parent_session_id,
8562
+ s.created_at, s.updated_at, s.revision, d.model_id, d.provider_id
8563
+ FROM new_sessions s LEFT JOIN deepchat_sessions d ON d.id = s.id
8564
+ WHERE s.is_draft = 0 ${filter}
8565
+ ORDER BY s.id
8566
+ `).iterate(...bindings);
8567
+ for (const row of sessions) {
8568
+ const id = String(row.id);
8569
+ const parent = asString(row.parent_session_id);
8570
+ projections.set(id, {
8571
+ head: {
8572
+ ...this.sessionIdentity(id),
8573
+ title: resolveSessionTitle(asString(row.title), null, null),
8574
+ directory: asString(row.project_dir) ?? "",
8575
+ parent_reference: parent ? { agentName: this.name, sessionId: parent } : void 0,
8576
+ time_created: Number(row.created_at),
8577
+ time_updated: Number(row.updated_at),
8578
+ stats: { message_count: 0, total_input_tokens: 0, total_output_tokens: 0, total_cost: 0 }
8579
+ },
8580
+ agentId: String(row.agent_id),
8581
+ model: asString(row.model_id) ?? null,
8582
+ provider: asString(row.provider_id) ?? null,
8583
+ signature: createHash3("sha256").update(JSON.stringify(row)),
8584
+ unpricedModels: /* @__PURE__ */ new Set(),
8585
+ messageUsage: /* @__PURE__ */ new Map()
8586
+ });
8587
+ }
8588
+ const usageRows = db.prepare(`
8589
+ SELECT u.session_id, u.message_id, u.usage_id, u.created_at, u.updated_at,
8590
+ u.model_id AS model, u.provider_id AS provider,
8591
+ u.input_tokens AS inputTokens, u.output_tokens AS outputTokens,
8592
+ u.total_tokens AS totalTokens, u.cached_input_tokens AS cachedInputTokens,
8593
+ u.cache_write_input_tokens AS cacheWriteInputTokens
8594
+ FROM deepchat_usage_stats u JOIN new_sessions s ON s.id = u.session_id
8595
+ WHERE s.is_draft = 0 ${filter}
8596
+ ORDER BY u.session_id, u.usage_id
8597
+ `).iterate(...bindings);
8598
+ for (const row of usageRows) {
8599
+ const projection = projections.get(String(row.session_id));
8600
+ accumulateUsage(projection, row);
8601
+ projection.signature.update(JSON.stringify(row));
8602
+ projection.head.time_updated = Math.max(
8603
+ projection.head.time_updated ?? 0,
8604
+ Number(row.created_at)
8605
+ );
8606
+ }
8607
+ const messageRows = db.prepare(`
8608
+ SELECT m.id, m.session_id, m.order_seq, m.role, m.status, m.metadata, m.updated_at
8609
+ FROM deepchat_messages m JOIN new_sessions s ON s.id = m.session_id
8610
+ WHERE s.is_draft = 0 ${filter}
8611
+ ORDER BY m.session_id, m.order_seq, m.id
8612
+ `).iterate(...bindings);
8613
+ for (const row of messageRows) {
8614
+ const projection = projections.get(String(row.session_id));
8615
+ projection.signature.update(JSON.stringify(row));
8616
+ projection.head.stats.message_count += 1;
8617
+ projection.head.time_updated = Math.max(
8618
+ projection.head.time_updated ?? 0,
8619
+ Number(row.updated_at)
8620
+ );
8621
+ const metadata = asRecord(parseDeepChatJson(row.metadata));
8622
+ if (row.role === "assistant" && metadata && !projection.messageUsage.has(String(row.id))) {
8623
+ accumulateUsage(projection, { ...metadata, message_id: row.id });
8624
+ }
8625
+ }
8626
+ const blockActivity = db.prepare(`
8627
+ SELECT m.session_id, COUNT(*) AS block_count, MAX(b.updated_at) AS updated_at,
8628
+ SUM(b.updated_at) AS block_revision
8629
+ FROM deepchat_assistant_blocks b
8630
+ JOIN deepchat_messages m ON m.id = b.message_id
8631
+ JOIN new_sessions s ON s.id = m.session_id
8632
+ WHERE s.is_draft = 0 ${filter}
8633
+ GROUP BY m.session_id ORDER BY m.session_id
8634
+ `).iterate(...bindings);
8635
+ for (const row of blockActivity) {
8636
+ const projection = projections.get(String(row.session_id));
8637
+ projection.signature.update(JSON.stringify(row));
8638
+ projection.head.time_updated = Math.max(
8639
+ projection.head.time_updated ?? 0,
8640
+ Number(row.updated_at)
8641
+ );
8642
+ }
8643
+ return projections;
8644
+ }
8645
+ getSessionData(sessionId) {
8646
+ return this.readDatabase((db) => {
8647
+ const projection = this.readProjections(db, sessionId).get(sessionId);
8648
+ if (!projection) throw new Error(`DeepChat session not found: ${sessionId}`);
8649
+ const partsByMessage = this.readStructuredParts(db, sessionId);
8650
+ const rows = db.prepare(`
8651
+ SELECT id, role, content, metadata, status, created_at, updated_at
8652
+ FROM deepchat_messages WHERE session_id = ? ORDER BY order_seq, id
8653
+ `).iterate(sessionId);
8654
+ const messages = [];
8655
+ for (const row of rows) {
8656
+ if (row.role !== "user" && row.role !== "assistant") continue;
8657
+ const id = String(row.id);
8658
+ const metadata = asRecord(parseDeepChatJson(row.metadata));
8659
+ const usage = projection.messageUsage.get(id);
8660
+ messages.push({
8661
+ id,
8662
+ role: row.role,
8663
+ agent: row.role === "assistant" ? projection.agentId : void 0,
8664
+ time_created: Number(row.created_at),
8665
+ time_completed: row.status === "pending" ? void 0 : Number(row.updated_at),
8666
+ model: usage?.model ?? asString(metadata?.model) ?? projection.model,
8667
+ provider: usage?.provider ?? asString(metadata?.provider) ?? projection.provider,
8668
+ tokens: usage?.tokens,
8669
+ cost: usage?.cost,
8670
+ cost_source: usage && usage.cost > 0 ? "estimated" : void 0,
8671
+ parts: partsByMessage.get(id) ?? deepChatRawParts(row.role, String(row.content))
8672
+ });
8673
+ }
8674
+ return { ...projection.head, messages };
8675
+ });
8676
+ }
8677
+ readStructuredParts(db, sessionId) {
8678
+ const parts = /* @__PURE__ */ new Map();
8679
+ const blocks = db.prepare(`
8680
+ SELECT b.* FROM deepchat_assistant_blocks b
8681
+ JOIN deepchat_messages m ON m.id = b.message_id
8682
+ WHERE m.session_id = ? ORDER BY b.message_id, b.block_index
8683
+ `).iterate(sessionId);
8684
+ for (const block of blocks) {
8685
+ const id = String(block.message_id);
8686
+ const messageParts = parts.get(id) ?? [];
8687
+ const part = deepChatStoredBlockPart(block);
8688
+ if (part) messageParts.push(part);
8689
+ parts.set(id, messageParts);
8690
+ }
8691
+ const users = db.prepare(`
8692
+ SELECT u.message_id, u.text FROM deepchat_user_messages u
8693
+ JOIN deepchat_messages m ON m.id = u.message_id WHERE m.session_id = ?
8694
+ `).iterate(sessionId);
8695
+ for (const user of users) parts.set(String(user.message_id), deepChatUserParts(user));
8696
+ const attachments = db.prepare(`
8697
+ SELECT f.message_id, f.path, f.name FROM deepchat_user_message_files f
8698
+ JOIN deepchat_messages m ON m.id = f.message_id
8699
+ WHERE m.session_id = ? ORDER BY f.message_id, f.ordinal
8700
+ `).iterate(sessionId);
8701
+ for (const attachment of attachments) {
8702
+ parts.get(String(attachment.message_id))?.push(...deepChatUserParts({ files: [attachment] }));
8703
+ }
8704
+ const links = db.prepare(`
8705
+ SELECT l.message_id, l.url FROM deepchat_user_message_links l
8706
+ JOIN deepchat_messages m ON m.id = l.message_id
8707
+ WHERE m.session_id = ? ORDER BY l.message_id, l.ordinal
8708
+ `).iterate(sessionId);
8709
+ for (const link of links)
8710
+ parts.get(String(link.message_id))?.push(...deepChatUserParts({ links: [link.url] }));
8711
+ return parts;
8712
+ }
8713
+ };
8714
+ function jsonRecord(value) {
8715
+ return asRecord(typeof value === "string" ? JSON.parse(value) : value);
8716
+ }
8717
+ function nonnegative(value) {
8718
+ return Math.max(0, asNumber(value) ?? 0);
8719
+ }
8720
+ function tokensFromStats(stats) {
8721
+ if (!stats) return void 0;
8722
+ const input = asRecord(stats.inputTokenDetails);
8723
+ const output = asRecord(stats.outputTokenDetails);
8724
+ return {
8725
+ input: asNumber(stats.inputTokens) ?? nonnegative(input?.noCacheTokens) + nonnegative(input?.cacheReadTokens) + nonnegative(input?.cacheWriteTokens),
8726
+ output: asNumber(stats.outputTokens) ?? nonnegative(output?.textTokens) + nonnegative(output?.reasoningTokens),
8727
+ cache_read: nonnegative(input?.cacheReadTokens),
8728
+ cache_create: nonnegative(input?.cacheWriteTokens),
8729
+ reasoning: nonnegative(output?.reasoningTokens)
8730
+ };
8731
+ }
8732
+ function messageCost(stats, model, tokens) {
8733
+ const costs = (asArray(stats?.costs) ?? []).flatMap((value) => {
8734
+ const cost2 = asRecord(value);
8735
+ return cost2 ? [cost2] : [];
8736
+ });
8737
+ if (costs.length > 0 && costs.every((cost2) => cost2.currency === "USD")) {
8738
+ return {
8739
+ cost: costs.reduce((sum, cost2) => sum + nonnegative(cost2.amount), 0),
8740
+ costSource: costs.some((cost2) => nonnegative(cost2.computedRequestCount) > 0) ? "estimated" : "recorded"
8741
+ };
8742
+ }
8743
+ const cost = estimateTokenCost(model, tokens ? { ...tokens, reasoning: 0 } : void 0);
8744
+ return {
8745
+ cost: cost ?? void 0,
8746
+ costSource: cost === null ? void 0 : "estimated"
8747
+ };
8748
+ }
8749
+ function convertPart(part) {
8750
+ const type = asString(part.type);
8751
+ const text = asString(part.text);
8752
+ if ((type === "text" || type === "reasoning") && text) return { type, text };
8753
+ if (type === "dynamic-tool" || type?.startsWith("tool-")) {
8754
+ const state = asString(part.state);
8755
+ const failed = state === "output-error" || state === "output-denied";
8756
+ return {
8757
+ type: "tool",
8758
+ tool: asString(part.toolName) ?? (type === "dynamic-tool" ? "unknown" : type.slice(5)),
8759
+ callID: asString(part.toolCallId),
8760
+ title: asString(part.title),
8761
+ state: {
8762
+ status: failed ? "error" : state === "output-available" ? "completed" : "running",
8763
+ input: part.input,
8764
+ output: part.output,
8765
+ error: failed ? part.errorText ?? "Tool execution failed" : void 0,
8766
+ metadata: part.providerMetadata
8767
+ }
8768
+ };
8769
+ }
8770
+ if (type === "file") {
8771
+ const url = asString(part.url);
8772
+ const mime = asString(part.mediaType);
8773
+ if (url && mime?.startsWith("image/")) return { type: "image", url, mime_type: mime };
8774
+ const label = asString(part.filename) ?? url;
8775
+ return label ? { type: "text", text: `Attachment: ${label}` } : null;
8776
+ }
8777
+ const data = asRecord(part.data);
8778
+ if (type === "data-error") {
8779
+ const message = asString(data?.message);
8780
+ return message ? { type: "text", text: message } : null;
8781
+ }
8782
+ if (type === "data-compact" || type === "data-code" || type === "data-translation") {
8783
+ const content = asString(data?.content);
8784
+ return content ? { type: "text", text: content } : null;
8785
+ }
8786
+ return null;
8787
+ }
8788
+ function cherryStudioTranscript(rows) {
8789
+ const builder = new TranscriptBuilder();
8790
+ const modelUsage = /* @__PURE__ */ Object.create(null);
8791
+ let totalTokens = 0;
8792
+ for (const row of rows) {
8793
+ if (row.role !== "user" && row.role !== "assistant") continue;
8794
+ const data = jsonRecord(row.data);
8795
+ const snapshot = jsonRecord(row.message_snapshot);
8796
+ const modelSnapshot = asRecord(snapshot?.model);
8797
+ const uniqueModel = asString(row.model_id);
8798
+ const separator = uniqueModel?.indexOf("::") ?? -1;
8799
+ const model = asString(modelSnapshot?.id) ?? (separator >= 0 ? uniqueModel?.slice(separator + 2) : uniqueModel);
8800
+ const provider = asString(modelSnapshot?.provider) ?? (separator >= 0 ? uniqueModel?.slice(0, separator) : void 0);
8801
+ const stats = row.role === "assistant" ? jsonRecord(row.stats) : void 0;
8802
+ const tokens = tokensFromStats(stats);
8803
+ const total = nonnegative(stats?.totalTokens ?? (tokens?.input ?? 0) + (tokens?.output ?? 0));
8804
+ totalTokens += total;
8805
+ if (model && total > 0) modelUsage[model] = (modelUsage[model] ?? 0) + total;
8806
+ const message = builder.appendMessage({
8807
+ id: String(row.id),
8808
+ role: row.role,
8809
+ timestampMs: Number(row.created_at),
8810
+ agent: asString(snapshot?.name),
8811
+ model,
8812
+ provider,
8813
+ tokens,
8814
+ ...messageCost(stats, model, tokens),
8815
+ parts: (asArray(data?.parts) ?? []).flatMap((value) => {
8816
+ const part = asRecord(value);
8817
+ const converted = part ? convertPart(part) : null;
8818
+ return converted ? [converted] : [];
8819
+ })
8820
+ });
8821
+ if (row.status !== "pending") message.time_completed = Number(row.updated_at);
8822
+ }
8823
+ const transcript = builder.finish();
8824
+ return {
8825
+ ...transcript,
8826
+ stats: { ...transcript.stats, total_tokens: totalTokens },
8827
+ modelUsage
8828
+ };
8829
+ }
8830
+ var AGENT_METADATA12 = getAgentCatalogEntry("cherrystudio");
8831
+ function resolveCherryStudioDataRoot() {
8832
+ const configured = readEnvPath("CHERRYSTUDIO_USER_DATA_DIR");
8833
+ if (configured) return configured;
8834
+ if (platform5() === "darwin")
8835
+ return join16(homedir5(), "Library", "Application Support", "CherryStudio");
8836
+ if (platform5() === "win32") {
8837
+ return join16(readEnvPath("APPDATA") ?? join16(homedir5(), "AppData", "Roaming"), "CherryStudio");
8838
+ }
8839
+ return join16(readEnvPath("XDG_CONFIG_HOME") ?? join16(homedir5(), ".config"), "CherryStudio");
8840
+ }
8841
+ function liveRows(db, table, alias) {
8842
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
8843
+ return columns.some((column) => column.name === "deleted_at") ? `${alias}.deleted_at IS NULL` : "1 = 1";
8844
+ }
8845
+ function activeBranch(rows, activeId) {
8846
+ const byId = new Map(rows.map((row) => [String(row.id), row]));
8847
+ const selected = [];
8848
+ const visited = /* @__PURE__ */ new Set();
8849
+ let id = asString(activeId);
8850
+ while (id) {
8851
+ if (visited.has(id)) throw new Error("Cherry Studio message branch contains a cycle");
8852
+ visited.add(id);
8853
+ const row = byId.get(id);
8854
+ if (!row) break;
8855
+ selected.push(row);
8856
+ id = asString(row.parent_id);
8857
+ }
8858
+ return selected.reverse();
8859
+ }
8860
+ var CherryStudioAgent = class extends DatabaseSessionSource {
8861
+ name = AGENT_METADATA12.name;
8862
+ displayName = AGENT_METADATA12.displayName;
8863
+ sourceRoot;
8864
+ constructor(options = {}) {
8865
+ super();
8866
+ this.sourceRoot = options.sourceRoot ?? resolveCherryStudioDataRoot();
8867
+ }
8868
+ getDatabasePath() {
8869
+ return firstExisting(join16(this.sourceRoot, "Data", "cherrystudio.sqlite"));
8870
+ }
8871
+ isAvailable() {
8872
+ return isSqliteAvailable() && this.getDatabasePath() !== null;
8873
+ }
8874
+ getSessionWatchPlan() {
8875
+ return {
8876
+ status: "supported",
8877
+ targets: [
8878
+ { root: this.sourceRoot, path: join16(this.sourceRoot, "Data", "cherrystudio.sqlite") }
8879
+ ]
8880
+ };
8881
+ }
8882
+ readDatabase(read) {
8883
+ const path = this.getDatabasePath();
8884
+ if (!path) throw new Error("Cherry Studio 2.x cherrystudio.sqlite is missing");
8885
+ return this.scanStep("reading Cherry Studio 2.x cherrystudio.sqlite", path, () => {
8886
+ const db = openDbReadOnly(path);
8887
+ if (!db) throw new Error("Cannot open Cherry Studio database");
8888
+ try {
8889
+ return db.transaction(() => read(db))();
8890
+ } finally {
8891
+ db.close();
8892
+ }
8893
+ });
8894
+ }
8895
+ scan(options) {
8896
+ if (!this.getDatabasePath()) return [];
8897
+ return this.readDatabase((db) => {
8898
+ const sessions = [];
8899
+ for (const kind of ["agent", "topic"]) {
8900
+ for (const projection of this.readConversations(db, kind)) {
8901
+ const { messages: _messages, ...head } = projection.session;
8902
+ if (!head.stats.message_count || !matchesScanWindow(head.time_updated ?? head.time_created, options))
8903
+ continue;
8904
+ this.rememberSession(head.reference.sessionId, {
8905
+ sourceFingerprint: projection.fingerprint,
8906
+ headParserVersion: "cherrystudio-v1",
8907
+ unpricedModels: projection.unpricedModels
8908
+ });
8909
+ sessions.push(head);
8910
+ }
8911
+ }
8912
+ sessions.sort(
8913
+ (left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
8914
+ );
8915
+ options?.onProgress?.({
8916
+ total: sessions.length,
8917
+ processed: sessions.length,
8918
+ sessions: sessions.length
8919
+ });
8920
+ return sessions;
8921
+ });
8922
+ }
8923
+ getSessionData(sessionId) {
8924
+ const separator = sessionId.indexOf(":");
8925
+ const kind = sessionId.slice(0, separator);
8926
+ const id = sessionId.slice(separator + 1);
8927
+ if (kind !== "agent" && kind !== "topic" || !id)
8928
+ throw new Error(`Invalid Cherry Studio session: ${sessionId}`);
8929
+ return this.readDatabase((db) => {
8930
+ for (const projection of this.readConversations(db, kind, id)) return projection.session;
8931
+ throw new Error(`Cherry Studio session not found: ${sessionId}`);
8932
+ });
8933
+ }
8934
+ *readConversations(db, kind, id) {
8935
+ const table = kind === "agent" ? "agent_session" : "topic";
8936
+ const messageTable = kind === "agent" ? "agent_session_message" : "message";
8937
+ const foreignKey = kind === "agent" ? "session_id" : "topic_id";
8938
+ const filter = `${liveRows(db, table, "s")} ${id ? "AND s.id = ?" : ""}`;
8939
+ const bindings = id ? [id] : [];
8940
+ const headers = db.prepare(`
8941
+ SELECT s.id, s.name, s.created_at, s.updated_at, s.last_activity_at,
8942
+ ${kind === "agent" ? "w.path AS directory, NULL AS active_node_id" : "NULL AS directory, s.active_node_id"}
8943
+ FROM ${table} s ${kind === "agent" ? "LEFT JOIN agent_workspace w ON w.id = s.workspace_id" : ""}
8944
+ WHERE ${filter}
8945
+ `).all(...bindings);
8946
+ const byId = new Map(headers.map((row) => [String(row.id), row]));
8947
+ const messages = db.prepare(`
8948
+ SELECT m.id, m.${foreignKey} AS conversation_id, m.role, m.data, m.stats,
8949
+ m.model_id, m.message_snapshot, m.status, m.created_at, m.updated_at,
8950
+ ${kind === "topic" ? "m.parent_id" : "NULL AS parent_id"}
8951
+ FROM ${messageTable} m JOIN ${table} s ON s.id = m.${foreignKey}
8952
+ WHERE ${filter} AND ${liveRows(db, messageTable, "m")}
8953
+ ORDER BY m.${foreignKey}, m.created_at, m.id
8954
+ `).iterate(...bindings);
8955
+ let currentId;
8956
+ let rows = [];
8957
+ for (const row of messages) {
8958
+ const nextId = String(row.conversation_id);
8959
+ if (currentId !== void 0 && nextId !== currentId) {
8960
+ yield this.projectConversation(kind, byId.get(currentId), rows);
8961
+ rows = [];
8962
+ }
8963
+ currentId = nextId;
8964
+ rows.push(row);
8965
+ }
8966
+ if (currentId !== void 0) yield this.projectConversation(kind, byId.get(currentId), rows);
8967
+ }
8968
+ projectConversation(kind, row, rows) {
8969
+ const selected = kind === "topic" ? activeBranch(rows, row.active_node_id) : rows;
8970
+ const { result: transcript, unpricedModels } = capturePricingMisses(
8971
+ () => cherryStudioTranscript(selected)
8972
+ );
8973
+ const signature = createHash4("sha256").update(JSON.stringify(row));
8974
+ for (const message of selected) signature.update(JSON.stringify(message));
8975
+ const session = {
8976
+ ...this.sessionIdentity(`${kind}:${row.id}`),
8977
+ title: resolveSessionTitle(
8978
+ asString(row.name),
8979
+ firstUserMessageTitle(transcript.messages),
8980
+ "Cherry Studio"
8981
+ ),
8982
+ directory: asString(row.directory) || this.sourceRoot,
8983
+ time_created: Number(row.created_at),
8984
+ time_updated: Number(row.last_activity_at),
8985
+ stats: transcript.stats,
8986
+ model_usage: transcript.modelUsage,
8987
+ messages: transcript.messages
8988
+ };
8989
+ return { session, fingerprint: signature.digest("hex"), unpricedModels };
8990
+ }
8991
+ };
8308
8992
  var RUNTIME_REGISTRATIONS = {
8309
8993
  claudecode: {
8310
8994
  create: () => new ClaudeCodeAgent(),
@@ -8345,6 +9029,14 @@ var RUNTIME_REGISTRATIONS = {
8345
9029
  dsh: {
8346
9030
  create: () => new DshAgent(),
8347
9031
  resolveDataRoot: resolveDshDataRoot
9032
+ },
9033
+ deepchat: {
9034
+ create: () => new DeepChatAgent(),
9035
+ resolveDataRoot: resolveDeepChatDataRoot
9036
+ },
9037
+ cherrystudio: {
9038
+ create: () => new CherryStudioAgent(),
9039
+ resolveDataRoot: resolveCherryStudioDataRoot
8348
9040
  }
8349
9041
  };
8350
9042
  var AGENT_REGISTRATIONS = Object.freeze(
@@ -8387,4 +9079,4 @@ export {
8387
9079
  createRegisteredAgents,
8388
9080
  getAgentInfoMap
8389
9081
  };
8390
- //# sourceMappingURL=chunk-RBCCNCDO.js.map
9082
+ //# sourceMappingURL=chunk-ZDH2BKQK.js.map