@adhdev/daemon-core 0.8.97 → 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.
@@ -103,4 +103,5 @@ export declare function listSavedHistorySessions(agentType: string, options?: {
103
103
  hasMore: boolean;
104
104
  };
105
105
  export declare function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId: string): boolean;
106
+ export declare function rebuildClaudeSavedHistoryFromNativeProject(historySessionId: string, workspace?: string): boolean;
106
107
  export {};
package/dist/index.js CHANGED
@@ -1789,8 +1789,8 @@ function resolveCliSpawnPlan(options) {
1789
1789
  isWin,
1790
1790
  useShell,
1791
1791
  ptyOptions: {
1792
- cols: 80,
1793
- rows: 24,
1792
+ cols: import_session_host_core2.DEFAULT_SESSION_HOST_COLS,
1793
+ rows: import_session_host_core2.DEFAULT_SESSION_HOST_ROWS,
1794
1794
  cwd: workingDir,
1795
1795
  env: buildCliSpawnEnv(process.env, spawnConfig.env)
1796
1796
  }
@@ -1841,12 +1841,13 @@ function respondToCliTerminalQueries(options) {
1841
1841
  }
1842
1842
  return "";
1843
1843
  }
1844
- var os9, path10;
1844
+ var os9, path10, import_session_host_core2;
1845
1845
  var init_provider_cli_runtime = __esm({
1846
1846
  "src/cli-adapters/provider-cli-runtime.ts"() {
1847
1847
  "use strict";
1848
1848
  os9 = __toESM(require("os"));
1849
1849
  path10 = __toESM(require("path"));
1850
+ import_session_host_core2 = require("@adhdev/session-host-core");
1850
1851
  init_provider_cli_shared();
1851
1852
  }
1852
1853
  });
@@ -4581,6 +4582,7 @@ init_config();
4581
4582
 
4582
4583
  // src/providers/provider-session-id.ts
4583
4584
  var HERMES_SESSION_ID_RE = /^\d{8}_\d{6}_[a-z0-9]+$/i;
4585
+ 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;
4584
4586
  function normalizeProviderSessionId(providerType, providerSessionId) {
4585
4587
  const normalizedProviderType = typeof providerType === "string" ? providerType.trim() : "";
4586
4588
  const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
@@ -4590,6 +4592,9 @@ function normalizeProviderSessionId(providerType, providerSessionId) {
4590
4592
  if (normalizedProviderType === "hermes-cli" && !HERMES_SESSION_ID_RE.test(normalizedId)) {
4591
4593
  return "";
4592
4594
  }
4595
+ if (normalizedProviderType === "claude-cli" && !CLAUDE_SESSION_ID_RE.test(normalizedId)) {
4596
+ return "";
4597
+ }
4593
4598
  return normalizedId;
4594
4599
  }
4595
4600
  function isLegacyVolatileSessionReadKey(key) {
@@ -7711,9 +7716,16 @@ function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
7711
7716
  if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
7712
7717
  return fallbackTs;
7713
7718
  }
7714
- function readExistingHermesSessionStartRecord(historySessionId) {
7719
+ function extractTimestampValue(value) {
7720
+ const numericTimestamp = Number(value || 0);
7721
+ if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
7722
+ const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
7723
+ if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
7724
+ return 0;
7725
+ }
7726
+ function readExistingSessionStartRecord(agentType, historySessionId) {
7715
7727
  try {
7716
- const dir = path7.join(HISTORY_DIR, "hermes-cli");
7728
+ const dir = path7.join(HISTORY_DIR, agentType);
7717
7729
  if (!fs3.existsSync(dir)) return null;
7718
7730
  const files = listHistoryFiles(dir, historySessionId).sort();
7719
7731
  for (const file of files) {
@@ -7734,6 +7746,28 @@ function readExistingHermesSessionStartRecord(historySessionId) {
7734
7746
  return null;
7735
7747
  }
7736
7748
  }
7749
+ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
7750
+ if (records.length === 0) return false;
7751
+ try {
7752
+ const dir = path7.join(HISTORY_DIR, agentType);
7753
+ fs3.mkdirSync(dir, { recursive: true });
7754
+ const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
7755
+ for (const file of fs3.readdirSync(dir)) {
7756
+ if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
7757
+ fs3.unlinkSync(path7.join(dir, file));
7758
+ }
7759
+ }
7760
+ const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
7761
+ const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
7762
+ fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
7763
+ `, "utf-8");
7764
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
7765
+ savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
7766
+ return true;
7767
+ } catch {
7768
+ return false;
7769
+ }
7770
+ }
7737
7771
  function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7738
7772
  const normalizedSessionId = normalizeSavedHistorySessionId("hermes-cli", historySessionId);
7739
7773
  if (!normalizedSessionId) return false;
@@ -7744,7 +7778,7 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7744
7778
  const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
7745
7779
  const dir = path7.join(HISTORY_DIR, "hermes-cli");
7746
7780
  fs3.mkdirSync(dir, { recursive: true });
7747
- const existingSessionStart = readExistingHermesSessionStartRecord(normalizedSessionId);
7781
+ const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
7748
7782
  const records = [];
7749
7783
  if (existingSessionStart) {
7750
7784
  records.push({
@@ -7796,20 +7830,167 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7796
7830
  });
7797
7831
  }
7798
7832
  }
7799
- if (records.length === 0) return false;
7800
- const prefix = `${normalizedSessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
7801
- for (const file of fs3.readdirSync(dir)) {
7802
- if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
7803
- fs3.unlinkSync(path7.join(dir, file));
7833
+ return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
7834
+ } catch {
7835
+ return false;
7836
+ }
7837
+ }
7838
+ function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
7839
+ const claudeProjectsDir = path7.join(os5.homedir(), ".claude", "projects");
7840
+ if (!fs3.existsSync(claudeProjectsDir)) return null;
7841
+ const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
7842
+ if (normalizedWorkspace) {
7843
+ const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
7844
+ if (fs3.existsSync(directPath)) return directPath;
7845
+ }
7846
+ const stack = [claudeProjectsDir];
7847
+ while (stack.length > 0) {
7848
+ const current = stack.pop();
7849
+ if (!current) continue;
7850
+ for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
7851
+ const entryPath = path7.join(current, entry.name);
7852
+ if (entry.isDirectory()) {
7853
+ stack.push(entryPath);
7854
+ continue;
7855
+ }
7856
+ if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
7857
+ return entryPath;
7804
7858
  }
7805
7859
  }
7806
- const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
7807
- const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
7808
- fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
7809
- `, "utf-8");
7810
- invalidatePersistedSavedHistoryIndex("hermes-cli", dir);
7811
- savedHistorySessionCache.delete("hermes-cli");
7812
- return true;
7860
+ }
7861
+ return null;
7862
+ }
7863
+ function extractClaudeAssistantContentParts(content) {
7864
+ if (typeof content === "string") {
7865
+ const trimmed = content.trim();
7866
+ return trimmed ? [{ content: trimmed, kind: "standard", role: "assistant" }] : [];
7867
+ }
7868
+ if (!Array.isArray(content)) return [];
7869
+ const parts = [];
7870
+ for (const block of content) {
7871
+ if (!block || typeof block !== "object") continue;
7872
+ const record = block;
7873
+ const type = String(record.type || "").trim();
7874
+ if (type === "text") {
7875
+ const text = String(record.text || "").trim();
7876
+ if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
7877
+ continue;
7878
+ }
7879
+ if (type === "tool_use") {
7880
+ const name = String(record.name || "").trim() || "Tool";
7881
+ const input = record.input && typeof record.input === "object" ? record.input : null;
7882
+ const command = input ? String(input.command || "").trim() : "";
7883
+ const summary = command ? `${name}: ${command}` : name;
7884
+ if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
7885
+ }
7886
+ }
7887
+ return parts;
7888
+ }
7889
+ function extractClaudeUserContentParts(content) {
7890
+ if (typeof content === "string") {
7891
+ const trimmed = content.trim();
7892
+ return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
7893
+ }
7894
+ if (!Array.isArray(content)) return [];
7895
+ const parts = [];
7896
+ for (const block of content) {
7897
+ if (!block || typeof block !== "object") continue;
7898
+ const record = block;
7899
+ const type = String(record.type || "").trim();
7900
+ if (type === "text") {
7901
+ const text = String(record.text || "").trim();
7902
+ if (text) parts.push({ role: "user", content: text, kind: "standard" });
7903
+ continue;
7904
+ }
7905
+ if (type === "tool_result") {
7906
+ const rawContent = record.content;
7907
+ const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
7908
+ if (typeof entry === "string") return entry.trim();
7909
+ if (!entry || typeof entry !== "object") return "";
7910
+ const nested = entry;
7911
+ if (typeof nested.text === "string") return nested.text.trim();
7912
+ if (typeof nested.content === "string") return nested.content.trim();
7913
+ return "";
7914
+ }).filter(Boolean).join("\n") : "";
7915
+ if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
7916
+ }
7917
+ }
7918
+ return parts;
7919
+ }
7920
+ function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
7921
+ const normalizedSessionId = normalizeSavedHistorySessionId("claude-cli", historySessionId);
7922
+ if (!normalizedSessionId) return false;
7923
+ try {
7924
+ const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
7925
+ if (!transcriptPath) return false;
7926
+ const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
7927
+ const records = [];
7928
+ const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
7929
+ if (existingSessionStart) {
7930
+ records.push({
7931
+ ...existingSessionStart,
7932
+ historySessionId: normalizedSessionId
7933
+ });
7934
+ }
7935
+ let fallbackTs = Date.now();
7936
+ for (const line of lines) {
7937
+ let parsed = null;
7938
+ try {
7939
+ parsed = JSON.parse(line);
7940
+ } catch {
7941
+ parsed = null;
7942
+ }
7943
+ if (!parsed) continue;
7944
+ const parsedSessionId = String(parsed.sessionId || "").trim();
7945
+ if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
7946
+ const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
7947
+ fallbackTs = receivedAt + 1;
7948
+ const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
7949
+ if (records.length === 0 && parsedWorkspace) {
7950
+ records.push({
7951
+ ts: new Date(receivedAt).toISOString(),
7952
+ receivedAt,
7953
+ role: "system",
7954
+ kind: "session_start",
7955
+ content: parsedWorkspace,
7956
+ agent: "claude-cli",
7957
+ historySessionId: normalizedSessionId,
7958
+ workspace: parsedWorkspace
7959
+ });
7960
+ }
7961
+ const type = String(parsed.type || "").trim();
7962
+ const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
7963
+ if (type === "user" && message) {
7964
+ for (const part of extractClaudeUserContentParts(message.content)) {
7965
+ records.push({
7966
+ ts: new Date(receivedAt).toISOString(),
7967
+ receivedAt,
7968
+ role: part.role,
7969
+ content: part.content,
7970
+ kind: part.kind,
7971
+ senderName: part.senderName,
7972
+ agent: "claude-cli",
7973
+ historySessionId: normalizedSessionId
7974
+ });
7975
+ }
7976
+ continue;
7977
+ }
7978
+ if (type === "assistant" && message) {
7979
+ for (const part of extractClaudeAssistantContentParts(message.content)) {
7980
+ records.push({
7981
+ ts: new Date(receivedAt).toISOString(),
7982
+ receivedAt,
7983
+ role: "assistant",
7984
+ content: part.content,
7985
+ kind: part.kind,
7986
+ senderName: part.senderName,
7987
+ agent: "claude-cli",
7988
+ historySessionId: normalizedSessionId
7989
+ });
7990
+ }
7991
+ }
7992
+ }
7993
+ return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
7813
7994
  } catch {
7814
7995
  return false;
7815
7996
  }
@@ -12868,7 +13049,7 @@ var CliProviderInstance = class {
12868
13049
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
12869
13050
  }
12870
13051
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
12871
- const canonicalHermesBackedHistory = this.syncCanonicalHermesSavedHistoryIfNeeded();
13052
+ const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
12872
13053
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
12873
13054
  if (parsedMessages.length > 0) {
12874
13055
  const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
@@ -12886,7 +13067,7 @@ var CliProviderInstance = class {
12886
13067
  senderName: typeof message.senderName === "string" ? message.senderName : void 0,
12887
13068
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
12888
13069
  }));
12889
- if (!canonicalHermesBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
13070
+ if (!canonicalBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
12890
13071
  const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
12891
13072
  this.historyWriter.appendNewMessages(
12892
13073
  this.type,
@@ -12896,7 +13077,7 @@ var CliProviderInstance = class {
12896
13077
  this.providerSessionId
12897
13078
  );
12898
13079
  }
12899
- if (!canonicalHermesBackedHistory) {
13080
+ if (!canonicalBackedHistory) {
12900
13081
  this.lastPersistedHistoryMessages = normalizedMessagesToSave;
12901
13082
  }
12902
13083
  }
@@ -13373,32 +13554,52 @@ ${effect.notification.body || ""}`.trim();
13373
13554
  });
13374
13555
  LOG.info("CLI", `[${this.type}] discovered provider session id: ${nextSessionId}`);
13375
13556
  }
13376
- syncCanonicalHermesSavedHistoryIfNeeded() {
13377
- if (this.type !== "hermes-cli" || !this.providerSessionId) return false;
13378
- try {
13379
- const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13380
- if (!fs5.existsSync(canonicalPath)) return false;
13381
- const stat = fs5.statSync(canonicalPath);
13382
- if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13383
- const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13384
- if (!rebuilt) return false;
13385
- this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13386
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13387
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13388
- role: message.role,
13389
- content: message.content,
13390
- kind: message.kind,
13391
- senderName: message.senderName,
13392
- receivedAt: message.receivedAt
13393
- }));
13394
- return true;
13395
- } catch {
13396
- return false;
13557
+ syncCanonicalSavedHistoryIfNeeded() {
13558
+ if (!this.providerSessionId) return false;
13559
+ if (this.type === "hermes-cli") {
13560
+ try {
13561
+ const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13562
+ if (!fs5.existsSync(canonicalPath)) return false;
13563
+ const stat = fs5.statSync(canonicalPath);
13564
+ if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13565
+ const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13566
+ if (!rebuilt) return false;
13567
+ this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13568
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13569
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13570
+ role: message.role,
13571
+ content: message.content,
13572
+ kind: message.kind,
13573
+ senderName: message.senderName,
13574
+ receivedAt: message.receivedAt
13575
+ }));
13576
+ return true;
13577
+ } catch {
13578
+ return false;
13579
+ }
13397
13580
  }
13581
+ if (this.type === "claude-cli") {
13582
+ try {
13583
+ const rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
13584
+ if (!rebuilt) return false;
13585
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13586
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13587
+ role: message.role,
13588
+ content: message.content,
13589
+ kind: message.kind,
13590
+ senderName: message.senderName,
13591
+ receivedAt: message.receivedAt
13592
+ }));
13593
+ return true;
13594
+ } catch {
13595
+ return false;
13596
+ }
13597
+ }
13598
+ return false;
13398
13599
  }
13399
13600
  restorePersistedHistoryFromCurrentSession() {
13400
13601
  if (!this.providerSessionId) return;
13401
- this.syncCanonicalHermesSavedHistoryIfNeeded();
13602
+ this.syncCanonicalSavedHistoryIfNeeded();
13402
13603
  this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
13403
13604
  const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13404
13605
  this.historyWriter.seedSessionHistory(
@@ -25494,7 +25695,7 @@ init_provider_cli_adapter();
25494
25695
  init_pty_transport();
25495
25696
 
25496
25697
  // src/cli-adapters/session-host-transport.ts
25497
- var import_session_host_core2 = require("@adhdev/session-host-core");
25698
+ var import_session_host_core3 = require("@adhdev/session-host-core");
25498
25699
  init_logger();
25499
25700
  function shouldResumeAttachedSession(record) {
25500
25701
  if (!record) return false;
@@ -25506,7 +25707,7 @@ function shouldResumeAttachedSession(record) {
25506
25707
  var SessionHostRuntimeTransport = class {
25507
25708
  constructor(options) {
25508
25709
  this.options = options;
25509
- this.client = new import_session_host_core2.SessionHostClient({
25710
+ this.client = new import_session_host_core3.SessionHostClient({
25510
25711
  endpoint: options.endpoint,
25511
25712
  appName: options.appName
25512
25713
  });
@@ -25912,11 +26113,11 @@ function resolveSessionHostAppName(options = {}) {
25912
26113
  }
25913
26114
 
25914
26115
  // src/session-host/runtime-support.ts
25915
- var import_session_host_core3 = require("@adhdev/session-host-core");
26116
+ var import_session_host_core4 = require("@adhdev/session-host-core");
25916
26117
  var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
25917
26118
  var STARTUP_POLL_MS = 200;
25918
26119
  async function canConnect(endpoint) {
25919
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
26120
+ const client = new import_session_host_core4.SessionHostClient({ endpoint });
25920
26121
  try {
25921
26122
  await client.connect();
25922
26123
  await client.close();
@@ -25934,14 +26135,14 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
25934
26135
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
25935
26136
  }
25936
26137
  async function ensureSessionHostReady(options) {
25937
- const endpoint = (0, import_session_host_core3.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
26138
+ const endpoint = (0, import_session_host_core4.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
25938
26139
  if (await canConnect(endpoint)) return endpoint;
25939
26140
  options.spawnHost();
25940
26141
  await waitForReady(endpoint, options.timeoutMs);
25941
26142
  return endpoint;
25942
26143
  }
25943
26144
  async function listHostedCliRuntimes(endpoint) {
25944
- const client = new import_session_host_core3.SessionHostClient({ endpoint });
26145
+ const client = new import_session_host_core4.SessionHostClient({ endpoint });
25945
26146
  try {
25946
26147
  const response = await client.request({
25947
26148
  type: "list_sessions",