engrm 0.4.44 → 0.4.46

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.
@@ -909,11 +909,20 @@ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, wr
909
909
  import { homedir, hostname, networkInterfaces } from "node:os";
910
910
  import { join as join2 } from "node:path";
911
911
  import { createHash } from "node:crypto";
912
- var CONFIG_DIR = join2(homedir(), ".engrm");
913
- var SETTINGS_PATH = join2(CONFIG_DIR, "settings.json");
914
- var DB_PATH = join2(CONFIG_DIR, "engrm.db");
912
+ function resolveConfigDir() {
913
+ return process.env["ENGRM_CONFIG_DIR"]?.trim() || join2(homedir(), ".engrm");
914
+ }
915
+ function resolveSettingsPath() {
916
+ return join2(resolveConfigDir(), "settings.json");
917
+ }
918
+ function resolveDbPath() {
919
+ return join2(resolveConfigDir(), "engrm.db");
920
+ }
921
+ function resolveAuthBackupPath() {
922
+ return join2(resolveConfigDir(), "auth-backup.json");
923
+ }
915
924
  function getDbPath() {
916
- return DB_PATH;
925
+ return resolveDbPath();
917
926
  }
918
927
  function generateDeviceId() {
919
928
  const host = hostname().toLowerCase().replace(/[^a-z0-9-]/g, "");
@@ -936,7 +945,7 @@ function generateDeviceId() {
936
945
  return `${host}-${suffix}`;
937
946
  }
938
947
  function createDefaultConfig() {
939
- return {
948
+ const merged = {
940
949
  candengo_url: "",
941
950
  candengo_api_key: "",
942
951
  site_id: "",
@@ -991,24 +1000,26 @@ function createDefaultConfig() {
991
1000
  },
992
1001
  tool_profile: "full"
993
1002
  };
1003
+ return merged;
994
1004
  }
995
1005
  function loadConfig() {
996
- if (!existsSync2(SETTINGS_PATH)) {
997
- throw new Error(`Config not found at ${SETTINGS_PATH}. Run 'engrm init --manual' to configure.`);
1006
+ const settingsPath = resolveSettingsPath();
1007
+ if (!existsSync2(settingsPath)) {
1008
+ throw new Error(`Config not found at ${settingsPath}. Run 'engrm init --manual' to configure.`);
998
1009
  }
999
- const raw = readFileSync2(SETTINGS_PATH, "utf-8");
1010
+ const raw = readFileSync2(settingsPath, "utf-8");
1000
1011
  let parsed;
1001
1012
  try {
1002
1013
  parsed = JSON.parse(raw);
1003
1014
  } catch {
1004
- throw new Error(`Invalid JSON in ${SETTINGS_PATH}`);
1015
+ throw new Error(`Invalid JSON in ${settingsPath}`);
1005
1016
  }
1006
1017
  if (typeof parsed !== "object" || parsed === null) {
1007
- throw new Error(`Config at ${SETTINGS_PATH} is not a JSON object`);
1018
+ throw new Error(`Config at ${settingsPath} is not a JSON object`);
1008
1019
  }
1009
1020
  const config = parsed;
1010
1021
  const defaults = createDefaultConfig();
1011
- return {
1022
+ const merged = {
1012
1023
  candengo_url: asString(config["candengo_url"], defaults.candengo_url),
1013
1024
  candengo_api_key: asString(config["candengo_api_key"], defaults.candengo_api_key),
1014
1025
  site_id: asString(config["site_id"], defaults.site_id),
@@ -1063,16 +1074,27 @@ function loadConfig() {
1063
1074
  },
1064
1075
  tool_profile: asToolProfile(config["tool_profile"], defaults.tool_profile)
1065
1076
  };
1077
+ if (looksLikePlaceholderAuth(merged)) {
1078
+ return restoreAuthBackup(merged) ?? merged;
1079
+ }
1080
+ return merged;
1066
1081
  }
1067
1082
  function saveConfig(config) {
1068
- if (!existsSync2(CONFIG_DIR)) {
1069
- mkdirSync(CONFIG_DIR, { recursive: true });
1083
+ const configDir = resolveConfigDir();
1084
+ const settingsPath = resolveSettingsPath();
1085
+ const authBackupPath = resolveAuthBackupPath();
1086
+ if (!existsSync2(configDir)) {
1087
+ mkdirSync(configDir, { recursive: true });
1070
1088
  }
1071
- writeFileSync(SETTINGS_PATH, JSON.stringify(config, null, 2) + `
1089
+ writeFileSync(settingsPath, JSON.stringify(config, null, 2) + `
1072
1090
  `, "utf-8");
1091
+ if (!looksLikePlaceholderAuth(config)) {
1092
+ writeFileSync(authBackupPath, JSON.stringify(extractAuthBackup(config), null, 2) + `
1093
+ `, "utf-8");
1094
+ }
1073
1095
  }
1074
1096
  function configExists() {
1075
- return existsSync2(SETTINGS_PATH);
1097
+ return existsSync2(resolveSettingsPath());
1076
1098
  }
1077
1099
  function asString(value, fallback) {
1078
1100
  return typeof value === "string" ? value : fallback;
@@ -1126,6 +1148,50 @@ function asTeams(value, fallback) {
1126
1148
  return fallback;
1127
1149
  return value.filter((t) => typeof t === "object" && t !== null && typeof t.id === "string" && typeof t.name === "string" && typeof t.namespace === "string");
1128
1150
  }
1151
+ function looksLikePlaceholderAuth(config) {
1152
+ const apiKey = config.candengo_api_key.trim();
1153
+ const siteId = config.site_id.trim();
1154
+ const namespace = config.namespace.trim();
1155
+ const email = config.user_email.trim().toLowerCase();
1156
+ if (apiKey === "cvk_org" && siteId === "site-1" && namespace === "org-ns")
1157
+ return true;
1158
+ if (siteId === "site-1" && namespace === "org-ns" && email.endsWith("@example.com"))
1159
+ return true;
1160
+ return false;
1161
+ }
1162
+ function extractAuthBackup(config) {
1163
+ return {
1164
+ candengo_url: config.candengo_url,
1165
+ candengo_api_key: config.candengo_api_key,
1166
+ site_id: config.site_id,
1167
+ namespace: config.namespace,
1168
+ user_id: config.user_id,
1169
+ user_email: config.user_email,
1170
+ teams: config.teams
1171
+ };
1172
+ }
1173
+ function restoreAuthBackup(config) {
1174
+ const authBackupPath = resolveAuthBackupPath();
1175
+ if (!existsSync2(authBackupPath))
1176
+ return null;
1177
+ try {
1178
+ const raw = readFileSync2(authBackupPath, "utf-8");
1179
+ const parsed = JSON.parse(raw);
1180
+ const restored = {
1181
+ ...config,
1182
+ candengo_url: asString(parsed["candengo_url"], config.candengo_url),
1183
+ candengo_api_key: asString(parsed["candengo_api_key"], config.candengo_api_key),
1184
+ site_id: asString(parsed["site_id"], config.site_id),
1185
+ namespace: asString(parsed["namespace"], config.namespace),
1186
+ user_id: asString(parsed["user_id"], config.user_id),
1187
+ user_email: asString(parsed["user_email"], config.user_email),
1188
+ teams: asTeams(parsed["teams"], config.teams)
1189
+ };
1190
+ return looksLikePlaceholderAuth(restored) ? null : restored;
1191
+ } catch {
1192
+ return null;
1193
+ }
1194
+ }
1129
1195
 
1130
1196
  // src/storage/migrations.ts
1131
1197
  var MIGRATIONS = [
@@ -213,11 +213,20 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
213
213
  import { homedir, hostname, networkInterfaces } from "node:os";
214
214
  import { join } from "node:path";
215
215
  import { createHash } from "node:crypto";
216
- var CONFIG_DIR = join(homedir(), ".engrm");
217
- var SETTINGS_PATH = join(CONFIG_DIR, "settings.json");
218
- var DB_PATH = join(CONFIG_DIR, "engrm.db");
216
+ function resolveConfigDir() {
217
+ return process.env["ENGRM_CONFIG_DIR"]?.trim() || join(homedir(), ".engrm");
218
+ }
219
+ function resolveSettingsPath() {
220
+ return join(resolveConfigDir(), "settings.json");
221
+ }
222
+ function resolveDbPath() {
223
+ return join(resolveConfigDir(), "engrm.db");
224
+ }
225
+ function resolveAuthBackupPath() {
226
+ return join(resolveConfigDir(), "auth-backup.json");
227
+ }
219
228
  function getDbPath() {
220
- return DB_PATH;
229
+ return resolveDbPath();
221
230
  }
222
231
  function generateDeviceId() {
223
232
  const host = hostname().toLowerCase().replace(/[^a-z0-9-]/g, "");
@@ -240,7 +249,7 @@ function generateDeviceId() {
240
249
  return `${host}-${suffix}`;
241
250
  }
242
251
  function createDefaultConfig() {
243
- return {
252
+ const merged = {
244
253
  candengo_url: "",
245
254
  candengo_api_key: "",
246
255
  site_id: "",
@@ -295,24 +304,26 @@ function createDefaultConfig() {
295
304
  },
296
305
  tool_profile: "full"
297
306
  };
307
+ return merged;
298
308
  }
299
309
  function loadConfig() {
300
- if (!existsSync(SETTINGS_PATH)) {
301
- throw new Error(`Config not found at ${SETTINGS_PATH}. Run 'engrm init --manual' to configure.`);
310
+ const settingsPath = resolveSettingsPath();
311
+ if (!existsSync(settingsPath)) {
312
+ throw new Error(`Config not found at ${settingsPath}. Run 'engrm init --manual' to configure.`);
302
313
  }
303
- const raw = readFileSync(SETTINGS_PATH, "utf-8");
314
+ const raw = readFileSync(settingsPath, "utf-8");
304
315
  let parsed;
305
316
  try {
306
317
  parsed = JSON.parse(raw);
307
318
  } catch {
308
- throw new Error(`Invalid JSON in ${SETTINGS_PATH}`);
319
+ throw new Error(`Invalid JSON in ${settingsPath}`);
309
320
  }
310
321
  if (typeof parsed !== "object" || parsed === null) {
311
- throw new Error(`Config at ${SETTINGS_PATH} is not a JSON object`);
322
+ throw new Error(`Config at ${settingsPath} is not a JSON object`);
312
323
  }
313
324
  const config = parsed;
314
325
  const defaults = createDefaultConfig();
315
- return {
326
+ const merged = {
316
327
  candengo_url: asString(config["candengo_url"], defaults.candengo_url),
317
328
  candengo_api_key: asString(config["candengo_api_key"], defaults.candengo_api_key),
318
329
  site_id: asString(config["site_id"], defaults.site_id),
@@ -367,16 +378,27 @@ function loadConfig() {
367
378
  },
368
379
  tool_profile: asToolProfile(config["tool_profile"], defaults.tool_profile)
369
380
  };
381
+ if (looksLikePlaceholderAuth(merged)) {
382
+ return restoreAuthBackup(merged) ?? merged;
383
+ }
384
+ return merged;
370
385
  }
371
386
  function saveConfig(config) {
372
- if (!existsSync(CONFIG_DIR)) {
373
- mkdirSync(CONFIG_DIR, { recursive: true });
387
+ const configDir = resolveConfigDir();
388
+ const settingsPath = resolveSettingsPath();
389
+ const authBackupPath = resolveAuthBackupPath();
390
+ if (!existsSync(configDir)) {
391
+ mkdirSync(configDir, { recursive: true });
374
392
  }
375
- writeFileSync(SETTINGS_PATH, JSON.stringify(config, null, 2) + `
393
+ writeFileSync(settingsPath, JSON.stringify(config, null, 2) + `
394
+ `, "utf-8");
395
+ if (!looksLikePlaceholderAuth(config)) {
396
+ writeFileSync(authBackupPath, JSON.stringify(extractAuthBackup(config), null, 2) + `
376
397
  `, "utf-8");
398
+ }
377
399
  }
378
400
  function configExists() {
379
- return existsSync(SETTINGS_PATH);
401
+ return existsSync(resolveSettingsPath());
380
402
  }
381
403
  function asString(value, fallback) {
382
404
  return typeof value === "string" ? value : fallback;
@@ -430,6 +452,50 @@ function asTeams(value, fallback) {
430
452
  return fallback;
431
453
  return value.filter((t) => typeof t === "object" && t !== null && typeof t.id === "string" && typeof t.name === "string" && typeof t.namespace === "string");
432
454
  }
455
+ function looksLikePlaceholderAuth(config) {
456
+ const apiKey = config.candengo_api_key.trim();
457
+ const siteId = config.site_id.trim();
458
+ const namespace = config.namespace.trim();
459
+ const email = config.user_email.trim().toLowerCase();
460
+ if (apiKey === "cvk_org" && siteId === "site-1" && namespace === "org-ns")
461
+ return true;
462
+ if (siteId === "site-1" && namespace === "org-ns" && email.endsWith("@example.com"))
463
+ return true;
464
+ return false;
465
+ }
466
+ function extractAuthBackup(config) {
467
+ return {
468
+ candengo_url: config.candengo_url,
469
+ candengo_api_key: config.candengo_api_key,
470
+ site_id: config.site_id,
471
+ namespace: config.namespace,
472
+ user_id: config.user_id,
473
+ user_email: config.user_email,
474
+ teams: config.teams
475
+ };
476
+ }
477
+ function restoreAuthBackup(config) {
478
+ const authBackupPath = resolveAuthBackupPath();
479
+ if (!existsSync(authBackupPath))
480
+ return null;
481
+ try {
482
+ const raw = readFileSync(authBackupPath, "utf-8");
483
+ const parsed = JSON.parse(raw);
484
+ const restored = {
485
+ ...config,
486
+ candengo_url: asString(parsed["candengo_url"], config.candengo_url),
487
+ candengo_api_key: asString(parsed["candengo_api_key"], config.candengo_api_key),
488
+ site_id: asString(parsed["site_id"], config.site_id),
489
+ namespace: asString(parsed["namespace"], config.namespace),
490
+ user_id: asString(parsed["user_id"], config.user_id),
491
+ user_email: asString(parsed["user_email"], config.user_email),
492
+ teams: asTeams(parsed["teams"], config.teams)
493
+ };
494
+ return looksLikePlaceholderAuth(restored) ? null : restored;
495
+ } catch {
496
+ return null;
497
+ }
498
+ }
433
499
 
434
500
  // src/storage/migrations.ts
435
501
  var MIGRATIONS = [
@@ -3826,14 +3892,18 @@ function parseJsonArray(value) {
3826
3892
 
3827
3893
  // src/capture/transcript.ts
3828
3894
  import { createHash as createHash3 } from "node:crypto";
3829
- import { readFileSync as readFileSync4, existsSync as existsSync4 } from "node:fs";
3895
+ import { readFileSync as readFileSync4, existsSync as existsSync4, statSync, readdirSync } from "node:fs";
3830
3896
  import { join as join4 } from "node:path";
3831
3897
  import { homedir as homedir3 } from "node:os";
3832
3898
  function resolveTranscriptPath(sessionId, cwd, transcriptPath) {
3833
3899
  if (transcriptPath)
3834
3900
  return transcriptPath;
3835
3901
  const encodedCwd = cwd.replace(/\//g, "-");
3836
- return join4(homedir3(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
3902
+ const directPath = join4(homedir3(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
3903
+ if (existsSync4(directPath))
3904
+ return directPath;
3905
+ const discovered = findTranscriptPathBySessionId(sessionId);
3906
+ return discovered ?? directPath;
3837
3907
  }
3838
3908
  function readTranscript(sessionId, cwd, transcriptPath) {
3839
3909
  const path = resolveTranscriptPath(sessionId, cwd, transcriptPath);
@@ -3856,10 +3926,10 @@ function readTranscript(sessionId, cwd, transcriptPath) {
3856
3926
  } catch {
3857
3927
  continue;
3858
3928
  }
3859
- const role = entry.role;
3929
+ const role = getTranscriptRole(entry);
3860
3930
  if (role !== "user" && role !== "assistant")
3861
3931
  continue;
3862
- const content = entry.content;
3932
+ const content = getTranscriptContent(entry);
3863
3933
  if (typeof content === "string") {
3864
3934
  messages.push({ role, text: content });
3865
3935
  continue;
@@ -3879,6 +3949,66 @@ function readTranscript(sessionId, cwd, transcriptPath) {
3879
3949
  }
3880
3950
  return messages;
3881
3951
  }
3952
+ function readTranscriptToolEvents(sessionId, cwd, transcriptPath) {
3953
+ const path = resolveTranscriptPath(sessionId, cwd, transcriptPath);
3954
+ if (!existsSync4(path))
3955
+ return [];
3956
+ let raw;
3957
+ try {
3958
+ raw = readFileSync4(path, "utf-8");
3959
+ } catch {
3960
+ return [];
3961
+ }
3962
+ const toolEvents = [];
3963
+ const toolEventIndexes = new Map;
3964
+ for (const line of raw.split(`
3965
+ `)) {
3966
+ if (!line.trim())
3967
+ continue;
3968
+ let entry;
3969
+ try {
3970
+ entry = JSON.parse(line);
3971
+ } catch {
3972
+ continue;
3973
+ }
3974
+ const createdAtEpoch = parseTranscriptTimestamp(entry);
3975
+ const content = getTranscriptContent(entry);
3976
+ if (!Array.isArray(content))
3977
+ continue;
3978
+ for (const block of content) {
3979
+ if (!block || typeof block !== "object")
3980
+ continue;
3981
+ if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
3982
+ const preview = extractToolResultPreview(block.content);
3983
+ const index = toolEventIndexes.get(block.tool_use_id);
3984
+ if (preview && index !== undefined) {
3985
+ toolEvents[index] = {
3986
+ ...toolEvents[index],
3987
+ tool_response_preview: preview
3988
+ };
3989
+ }
3990
+ continue;
3991
+ }
3992
+ if (block.type !== "tool_use")
3993
+ continue;
3994
+ const input = block.input && typeof block.input === "object" ? block.input : {};
3995
+ const toolUseId = typeof block.id === "string" ? block.id : null;
3996
+ const nextEvent = {
3997
+ tool_name: typeof block.name === "string" ? block.name : "Unknown",
3998
+ tool_input_json: JSON.stringify(input),
3999
+ tool_response_preview: null,
4000
+ file_path: extractToolFilePath(input),
4001
+ command: typeof input.command === "string" ? input.command : null,
4002
+ created_at_epoch: createdAtEpoch
4003
+ };
4004
+ toolEvents.push(nextEvent);
4005
+ if (toolUseId) {
4006
+ toolEventIndexes.set(toolUseId, toolEvents.length - 1);
4007
+ }
4008
+ }
4009
+ }
4010
+ return toolEvents;
4011
+ }
3882
4012
  function resolveHistoryPath(historyPath) {
3883
4013
  if (historyPath)
3884
4014
  return historyPath;
@@ -3944,9 +4074,22 @@ function readHistoryFallback(sessionId, cwd, opts) {
3944
4074
  createdAtEpoch: entry.timestamp
3945
4075
  })));
3946
4076
  }
3947
- async function syncTranscriptChat(db, config, sessionId, cwd, transcriptPath) {
4077
+ async function syncTranscriptChat(db, config, sessionId, cwd, transcriptPath, options = {}) {
4078
+ const embed = options.embed ?? true;
3948
4079
  const session = db.getSessionById(sessionId);
3949
- const transcriptMessages = readTranscript(sessionId, cwd, transcriptPath).map((message) => ({
4080
+ const resolvedTranscriptPath = resolveTranscriptPath(sessionId, cwd, transcriptPath);
4081
+ const syncCursorKey = `transcript_sync_cursor:${sessionId}`;
4082
+ if (existsSync4(resolvedTranscriptPath)) {
4083
+ try {
4084
+ const stat = statSync(resolvedTranscriptPath);
4085
+ const cursor = `${stat.size}:${Math.floor(stat.mtimeMs)}`;
4086
+ if (db.getSyncState(syncCursorKey) === cursor) {
4087
+ return { imported: 0, total: 0 };
4088
+ }
4089
+ db.setSyncState(syncCursorKey, cursor);
4090
+ } catch {}
4091
+ }
4092
+ const transcriptMessages = readTranscript(sessionId, cwd, resolvedTranscriptPath).map((message) => ({
3950
4093
  ...message,
3951
4094
  text: message.text.trim()
3952
4095
  })).filter((message) => message.text.length > 0);
@@ -4008,7 +4151,7 @@ async function syncTranscriptChat(db, config, sessionId, cwd, transcriptPath) {
4008
4151
  created_at_epoch: createdAtEpoch
4009
4152
  });
4010
4153
  }
4011
- if (db.vecAvailable) {
4154
+ if (embed && db.vecAvailable) {
4012
4155
  const embedding = await embedText(composeChatEmbeddingText(message.text));
4013
4156
  if (embedding) {
4014
4157
  db.vecChatInsert(row.id, embedding);
@@ -4018,6 +4161,35 @@ async function syncTranscriptChat(db, config, sessionId, cwd, transcriptPath) {
4018
4161
  }
4019
4162
  return { imported, total: messages.length };
4020
4163
  }
4164
+ function syncTranscriptToolEvents(db, config, sessionId, cwd, transcriptPath) {
4165
+ const session = db.getSessionById(sessionId);
4166
+ if (!session)
4167
+ return { imported: 0, total: 0 };
4168
+ if (db.getSessionToolEvents(sessionId, 1).length > 0) {
4169
+ return { imported: 0, total: 0 };
4170
+ }
4171
+ const toolEvents = readTranscriptToolEvents(sessionId, cwd, transcriptPath);
4172
+ if (toolEvents.length === 0)
4173
+ return { imported: 0, total: 0 };
4174
+ let imported = 0;
4175
+ for (const event of toolEvents) {
4176
+ db.insertToolEvent({
4177
+ session_id: sessionId,
4178
+ project_id: session.project_id,
4179
+ tool_name: event.tool_name,
4180
+ tool_input_json: event.tool_input_json,
4181
+ tool_response_preview: event.tool_response_preview,
4182
+ file_path: event.file_path,
4183
+ command: event.command,
4184
+ user_id: config.user_id,
4185
+ device_id: config.device_id,
4186
+ agent: "claude-code",
4187
+ created_at_epoch: event.created_at_epoch ?? undefined
4188
+ });
4189
+ imported++;
4190
+ }
4191
+ return { imported, total: toolEvents.length };
4192
+ }
4021
4193
  function dedupeHistoryMessages(messages) {
4022
4194
  const deduped = [];
4023
4195
  for (const message of messages) {
@@ -4035,6 +4207,59 @@ function buildHistorySourceId(sessionId, createdAtEpoch, text) {
4035
4207
  const digest = createHash3("sha1").update(text).digest("hex").slice(0, 12);
4036
4208
  return `history:${sessionId}:${createdAtEpoch}:${digest}`;
4037
4209
  }
4210
+ function getTranscriptRole(entry) {
4211
+ return entry.role ?? entry.message?.role ?? entry.type ?? entry.message?.type;
4212
+ }
4213
+ function getTranscriptContent(entry) {
4214
+ return entry.content ?? entry.message?.content;
4215
+ }
4216
+ function parseTranscriptTimestamp(entry) {
4217
+ const raw = entry.timestamp ?? entry.message?.timestamp;
4218
+ if (typeof raw !== "string")
4219
+ return null;
4220
+ const epoch = Date.parse(raw);
4221
+ return Number.isFinite(epoch) ? Math.floor(epoch / 1000) : null;
4222
+ }
4223
+ function extractToolResultPreview(content) {
4224
+ if (typeof content === "string")
4225
+ return content.slice(0, 4000);
4226
+ if (Array.isArray(content)) {
4227
+ const text = content.map((item) => {
4228
+ if (typeof item === "string")
4229
+ return item;
4230
+ if (item && typeof item === "object" && typeof item.text === "string")
4231
+ return item.text;
4232
+ return "";
4233
+ }).filter(Boolean).join(`
4234
+ `);
4235
+ return text ? text.slice(0, 4000) : null;
4236
+ }
4237
+ return null;
4238
+ }
4239
+ function extractToolFilePath(input) {
4240
+ for (const key of ["file_path", "path", "target_file"]) {
4241
+ if (typeof input[key] === "string")
4242
+ return input[key];
4243
+ }
4244
+ return null;
4245
+ }
4246
+ function findTranscriptPathBySessionId(sessionId) {
4247
+ const projectsDir = join4(homedir3(), ".claude", "projects");
4248
+ if (!existsSync4(projectsDir))
4249
+ return null;
4250
+ try {
4251
+ for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
4252
+ if (!entry.isDirectory())
4253
+ continue;
4254
+ const candidate = join4(projectsDir, entry.name, `${sessionId}.jsonl`);
4255
+ if (existsSync4(candidate))
4256
+ return candidate;
4257
+ }
4258
+ } catch {
4259
+ return null;
4260
+ }
4261
+ return null;
4262
+ }
4038
4263
  function truncateTranscript(messages, maxBytes = 50000) {
4039
4264
  const lines = [];
4040
4265
  for (const msg of messages) {
@@ -4588,7 +4813,9 @@ async function main() {
4588
4813
  try {
4589
4814
  if (event.session_id) {
4590
4815
  persistRawToolChronology(db, event, config.user_id, config.device_id);
4591
- await syncTranscriptChat(db, config, event.session_id, event.cwd);
4816
+ await syncTranscriptChat(db, config, event.session_id, event.cwd, undefined, {
4817
+ embed: false
4818
+ });
4592
4819
  }
4593
4820
  const textToScan = extractScanText(event);
4594
4821
  if (textToScan) {