@adhdev/daemon-core 0.8.98 → 0.8.99

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/dist/index.mjs CHANGED
@@ -4431,6 +4431,7 @@ import { join as join3 } from "path";
4431
4431
 
4432
4432
  // src/providers/provider-session-id.ts
4433
4433
  var HERMES_SESSION_ID_RE = /^\d{8}_\d{6}_[a-z0-9]+$/i;
4434
+ var CLAUDE_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
4434
4435
  function normalizeProviderSessionId(providerType, providerSessionId) {
4435
4436
  const normalizedProviderType = typeof providerType === "string" ? providerType.trim() : "";
4436
4437
  const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
@@ -4440,6 +4441,9 @@ function normalizeProviderSessionId(providerType, providerSessionId) {
4440
4441
  if (normalizedProviderType === "hermes-cli" && !HERMES_SESSION_ID_RE.test(normalizedId)) {
4441
4442
  return "";
4442
4443
  }
4444
+ if (normalizedProviderType === "claude-cli" && !CLAUDE_SESSION_ID_RE.test(normalizedId)) {
4445
+ return "";
4446
+ }
4443
4447
  return normalizedId;
4444
4448
  }
4445
4449
  function isLegacyVolatileSessionReadKey(key) {
@@ -7561,9 +7565,16 @@ function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
7561
7565
  if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
7562
7566
  return fallbackTs;
7563
7567
  }
7564
- function readExistingHermesSessionStartRecord(historySessionId) {
7568
+ function extractTimestampValue(value) {
7569
+ const numericTimestamp = Number(value || 0);
7570
+ if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
7571
+ const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
7572
+ if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
7573
+ return 0;
7574
+ }
7575
+ function readExistingSessionStartRecord(agentType, historySessionId) {
7565
7576
  try {
7566
- const dir = path7.join(HISTORY_DIR, "hermes-cli");
7577
+ const dir = path7.join(HISTORY_DIR, agentType);
7567
7578
  if (!fs3.existsSync(dir)) return null;
7568
7579
  const files = listHistoryFiles(dir, historySessionId).sort();
7569
7580
  for (const file of files) {
@@ -7584,6 +7595,28 @@ function readExistingHermesSessionStartRecord(historySessionId) {
7584
7595
  return null;
7585
7596
  }
7586
7597
  }
7598
+ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
7599
+ if (records.length === 0) return false;
7600
+ try {
7601
+ const dir = path7.join(HISTORY_DIR, agentType);
7602
+ fs3.mkdirSync(dir, { recursive: true });
7603
+ const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
7604
+ for (const file of fs3.readdirSync(dir)) {
7605
+ if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
7606
+ fs3.unlinkSync(path7.join(dir, file));
7607
+ }
7608
+ }
7609
+ const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
7610
+ const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
7611
+ fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
7612
+ `, "utf-8");
7613
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
7614
+ savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
7615
+ return true;
7616
+ } catch {
7617
+ return false;
7618
+ }
7619
+ }
7587
7620
  function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7588
7621
  const normalizedSessionId = normalizeSavedHistorySessionId("hermes-cli", historySessionId);
7589
7622
  if (!normalizedSessionId) return false;
@@ -7594,7 +7627,7 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7594
7627
  const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
7595
7628
  const dir = path7.join(HISTORY_DIR, "hermes-cli");
7596
7629
  fs3.mkdirSync(dir, { recursive: true });
7597
- const existingSessionStart = readExistingHermesSessionStartRecord(normalizedSessionId);
7630
+ const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
7598
7631
  const records = [];
7599
7632
  if (existingSessionStart) {
7600
7633
  records.push({
@@ -7646,20 +7679,167 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7646
7679
  });
7647
7680
  }
7648
7681
  }
7649
- if (records.length === 0) return false;
7650
- const prefix = `${normalizedSessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
7651
- for (const file of fs3.readdirSync(dir)) {
7652
- if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
7653
- fs3.unlinkSync(path7.join(dir, file));
7682
+ return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
7683
+ } catch {
7684
+ return false;
7685
+ }
7686
+ }
7687
+ function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
7688
+ const claudeProjectsDir = path7.join(os5.homedir(), ".claude", "projects");
7689
+ if (!fs3.existsSync(claudeProjectsDir)) return null;
7690
+ const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
7691
+ if (normalizedWorkspace) {
7692
+ const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
7693
+ if (fs3.existsSync(directPath)) return directPath;
7694
+ }
7695
+ const stack = [claudeProjectsDir];
7696
+ while (stack.length > 0) {
7697
+ const current = stack.pop();
7698
+ if (!current) continue;
7699
+ for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
7700
+ const entryPath = path7.join(current, entry.name);
7701
+ if (entry.isDirectory()) {
7702
+ stack.push(entryPath);
7703
+ continue;
7704
+ }
7705
+ if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
7706
+ return entryPath;
7654
7707
  }
7655
7708
  }
7656
- const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
7657
- const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
7658
- fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
7659
- `, "utf-8");
7660
- invalidatePersistedSavedHistoryIndex("hermes-cli", dir);
7661
- savedHistorySessionCache.delete("hermes-cli");
7662
- return true;
7709
+ }
7710
+ return null;
7711
+ }
7712
+ function extractClaudeAssistantContentParts(content) {
7713
+ if (typeof content === "string") {
7714
+ const trimmed = content.trim();
7715
+ return trimmed ? [{ content: trimmed, kind: "standard", role: "assistant" }] : [];
7716
+ }
7717
+ if (!Array.isArray(content)) return [];
7718
+ const parts = [];
7719
+ for (const block of content) {
7720
+ if (!block || typeof block !== "object") continue;
7721
+ const record = block;
7722
+ const type = String(record.type || "").trim();
7723
+ if (type === "text") {
7724
+ const text = String(record.text || "").trim();
7725
+ if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
7726
+ continue;
7727
+ }
7728
+ if (type === "tool_use") {
7729
+ const name = String(record.name || "").trim() || "Tool";
7730
+ const input = record.input && typeof record.input === "object" ? record.input : null;
7731
+ const command = input ? String(input.command || "").trim() : "";
7732
+ const summary = command ? `${name}: ${command}` : name;
7733
+ if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
7734
+ }
7735
+ }
7736
+ return parts;
7737
+ }
7738
+ function extractClaudeUserContentParts(content) {
7739
+ if (typeof content === "string") {
7740
+ const trimmed = content.trim();
7741
+ return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
7742
+ }
7743
+ if (!Array.isArray(content)) return [];
7744
+ const parts = [];
7745
+ for (const block of content) {
7746
+ if (!block || typeof block !== "object") continue;
7747
+ const record = block;
7748
+ const type = String(record.type || "").trim();
7749
+ if (type === "text") {
7750
+ const text = String(record.text || "").trim();
7751
+ if (text) parts.push({ role: "user", content: text, kind: "standard" });
7752
+ continue;
7753
+ }
7754
+ if (type === "tool_result") {
7755
+ const rawContent = record.content;
7756
+ const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
7757
+ if (typeof entry === "string") return entry.trim();
7758
+ if (!entry || typeof entry !== "object") return "";
7759
+ const nested = entry;
7760
+ if (typeof nested.text === "string") return nested.text.trim();
7761
+ if (typeof nested.content === "string") return nested.content.trim();
7762
+ return "";
7763
+ }).filter(Boolean).join("\n") : "";
7764
+ if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
7765
+ }
7766
+ }
7767
+ return parts;
7768
+ }
7769
+ function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
7770
+ const normalizedSessionId = normalizeSavedHistorySessionId("claude-cli", historySessionId);
7771
+ if (!normalizedSessionId) return false;
7772
+ try {
7773
+ const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
7774
+ if (!transcriptPath) return false;
7775
+ const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
7776
+ const records = [];
7777
+ const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
7778
+ if (existingSessionStart) {
7779
+ records.push({
7780
+ ...existingSessionStart,
7781
+ historySessionId: normalizedSessionId
7782
+ });
7783
+ }
7784
+ let fallbackTs = Date.now();
7785
+ for (const line of lines) {
7786
+ let parsed = null;
7787
+ try {
7788
+ parsed = JSON.parse(line);
7789
+ } catch {
7790
+ parsed = null;
7791
+ }
7792
+ if (!parsed) continue;
7793
+ const parsedSessionId = String(parsed.sessionId || "").trim();
7794
+ if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
7795
+ const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
7796
+ fallbackTs = receivedAt + 1;
7797
+ const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
7798
+ if (records.length === 0 && parsedWorkspace) {
7799
+ records.push({
7800
+ ts: new Date(receivedAt).toISOString(),
7801
+ receivedAt,
7802
+ role: "system",
7803
+ kind: "session_start",
7804
+ content: parsedWorkspace,
7805
+ agent: "claude-cli",
7806
+ historySessionId: normalizedSessionId,
7807
+ workspace: parsedWorkspace
7808
+ });
7809
+ }
7810
+ const type = String(parsed.type || "").trim();
7811
+ const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
7812
+ if (type === "user" && message) {
7813
+ for (const part of extractClaudeUserContentParts(message.content)) {
7814
+ records.push({
7815
+ ts: new Date(receivedAt).toISOString(),
7816
+ receivedAt,
7817
+ role: part.role,
7818
+ content: part.content,
7819
+ kind: part.kind,
7820
+ senderName: part.senderName,
7821
+ agent: "claude-cli",
7822
+ historySessionId: normalizedSessionId
7823
+ });
7824
+ }
7825
+ continue;
7826
+ }
7827
+ if (type === "assistant" && message) {
7828
+ for (const part of extractClaudeAssistantContentParts(message.content)) {
7829
+ records.push({
7830
+ ts: new Date(receivedAt).toISOString(),
7831
+ receivedAt,
7832
+ role: "assistant",
7833
+ content: part.content,
7834
+ kind: part.kind,
7835
+ senderName: part.senderName,
7836
+ agent: "claude-cli",
7837
+ historySessionId: normalizedSessionId
7838
+ });
7839
+ }
7840
+ }
7841
+ }
7842
+ return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
7663
7843
  } catch {
7664
7844
  return false;
7665
7845
  }
@@ -12718,7 +12898,7 @@ var CliProviderInstance = class {
12718
12898
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
12719
12899
  }
12720
12900
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
12721
- const canonicalHermesBackedHistory = this.syncCanonicalHermesSavedHistoryIfNeeded();
12901
+ const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
12722
12902
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
12723
12903
  if (parsedMessages.length > 0) {
12724
12904
  const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
@@ -12736,7 +12916,7 @@ var CliProviderInstance = class {
12736
12916
  senderName: typeof message.senderName === "string" ? message.senderName : void 0,
12737
12917
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
12738
12918
  }));
12739
- if (!canonicalHermesBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
12919
+ if (!canonicalBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
12740
12920
  const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
12741
12921
  this.historyWriter.appendNewMessages(
12742
12922
  this.type,
@@ -12746,7 +12926,7 @@ var CliProviderInstance = class {
12746
12926
  this.providerSessionId
12747
12927
  );
12748
12928
  }
12749
- if (!canonicalHermesBackedHistory) {
12929
+ if (!canonicalBackedHistory) {
12750
12930
  this.lastPersistedHistoryMessages = normalizedMessagesToSave;
12751
12931
  }
12752
12932
  }
@@ -13223,32 +13403,52 @@ ${effect.notification.body || ""}`.trim();
13223
13403
  });
13224
13404
  LOG.info("CLI", `[${this.type}] discovered provider session id: ${nextSessionId}`);
13225
13405
  }
13226
- syncCanonicalHermesSavedHistoryIfNeeded() {
13227
- if (this.type !== "hermes-cli" || !this.providerSessionId) return false;
13228
- try {
13229
- const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13230
- if (!fs5.existsSync(canonicalPath)) return false;
13231
- const stat = fs5.statSync(canonicalPath);
13232
- if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13233
- const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13234
- if (!rebuilt) return false;
13235
- this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13236
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13237
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13238
- role: message.role,
13239
- content: message.content,
13240
- kind: message.kind,
13241
- senderName: message.senderName,
13242
- receivedAt: message.receivedAt
13243
- }));
13244
- return true;
13245
- } catch {
13246
- return false;
13406
+ syncCanonicalSavedHistoryIfNeeded() {
13407
+ if (!this.providerSessionId) return false;
13408
+ if (this.type === "hermes-cli") {
13409
+ try {
13410
+ const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13411
+ if (!fs5.existsSync(canonicalPath)) return false;
13412
+ const stat = fs5.statSync(canonicalPath);
13413
+ if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13414
+ const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13415
+ if (!rebuilt) return false;
13416
+ this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13417
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13418
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13419
+ role: message.role,
13420
+ content: message.content,
13421
+ kind: message.kind,
13422
+ senderName: message.senderName,
13423
+ receivedAt: message.receivedAt
13424
+ }));
13425
+ return true;
13426
+ } catch {
13427
+ return false;
13428
+ }
13247
13429
  }
13430
+ if (this.type === "claude-cli") {
13431
+ try {
13432
+ const rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
13433
+ if (!rebuilt) return false;
13434
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13435
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13436
+ role: message.role,
13437
+ content: message.content,
13438
+ kind: message.kind,
13439
+ senderName: message.senderName,
13440
+ receivedAt: message.receivedAt
13441
+ }));
13442
+ return true;
13443
+ } catch {
13444
+ return false;
13445
+ }
13446
+ }
13447
+ return false;
13248
13448
  }
13249
13449
  restorePersistedHistoryFromCurrentSession() {
13250
13450
  if (!this.providerSessionId) return;
13251
- this.syncCanonicalHermesSavedHistoryIfNeeded();
13451
+ this.syncCanonicalSavedHistoryIfNeeded();
13252
13452
  this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
13253
13453
  const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13254
13454
  this.historyWriter.seedSessionHistory(