@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.
package/dist/index.mjs CHANGED
@@ -1756,6 +1756,7 @@ var init_provider_cli_config = __esm({
1756
1756
  // src/cli-adapters/provider-cli-runtime.ts
1757
1757
  import * as os9 from "os";
1758
1758
  import * as path10 from "path";
1759
+ import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
1759
1760
  function resolveCliSpawnPlan(options) {
1760
1761
  const { provider, runtimeSettings, workingDir, extraArgs } = options;
1761
1762
  const { spawn: spawnConfig } = provider;
@@ -1789,8 +1790,8 @@ function resolveCliSpawnPlan(options) {
1789
1790
  isWin,
1790
1791
  useShell,
1791
1792
  ptyOptions: {
1792
- cols: 80,
1793
- rows: 24,
1793
+ cols: DEFAULT_SESSION_HOST_COLS,
1794
+ rows: DEFAULT_SESSION_HOST_ROWS,
1794
1795
  cwd: workingDir,
1795
1796
  env: buildCliSpawnEnv(process.env, spawnConfig.env)
1796
1797
  }
@@ -4430,6 +4431,7 @@ import { join as join3 } from "path";
4430
4431
 
4431
4432
  // src/providers/provider-session-id.ts
4432
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;
4433
4435
  function normalizeProviderSessionId(providerType, providerSessionId) {
4434
4436
  const normalizedProviderType = typeof providerType === "string" ? providerType.trim() : "";
4435
4437
  const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
@@ -4439,6 +4441,9 @@ function normalizeProviderSessionId(providerType, providerSessionId) {
4439
4441
  if (normalizedProviderType === "hermes-cli" && !HERMES_SESSION_ID_RE.test(normalizedId)) {
4440
4442
  return "";
4441
4443
  }
4444
+ if (normalizedProviderType === "claude-cli" && !CLAUDE_SESSION_ID_RE.test(normalizedId)) {
4445
+ return "";
4446
+ }
4442
4447
  return normalizedId;
4443
4448
  }
4444
4449
  function isLegacyVolatileSessionReadKey(key) {
@@ -7560,9 +7565,16 @@ function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
7560
7565
  if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
7561
7566
  return fallbackTs;
7562
7567
  }
7563
- 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) {
7564
7576
  try {
7565
- const dir = path7.join(HISTORY_DIR, "hermes-cli");
7577
+ const dir = path7.join(HISTORY_DIR, agentType);
7566
7578
  if (!fs3.existsSync(dir)) return null;
7567
7579
  const files = listHistoryFiles(dir, historySessionId).sort();
7568
7580
  for (const file of files) {
@@ -7583,6 +7595,28 @@ function readExistingHermesSessionStartRecord(historySessionId) {
7583
7595
  return null;
7584
7596
  }
7585
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
+ }
7586
7620
  function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7587
7621
  const normalizedSessionId = normalizeSavedHistorySessionId("hermes-cli", historySessionId);
7588
7622
  if (!normalizedSessionId) return false;
@@ -7593,7 +7627,7 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7593
7627
  const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
7594
7628
  const dir = path7.join(HISTORY_DIR, "hermes-cli");
7595
7629
  fs3.mkdirSync(dir, { recursive: true });
7596
- const existingSessionStart = readExistingHermesSessionStartRecord(normalizedSessionId);
7630
+ const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
7597
7631
  const records = [];
7598
7632
  if (existingSessionStart) {
7599
7633
  records.push({
@@ -7645,20 +7679,167 @@ function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7645
7679
  });
7646
7680
  }
7647
7681
  }
7648
- if (records.length === 0) return false;
7649
- const prefix = `${normalizedSessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
7650
- for (const file of fs3.readdirSync(dir)) {
7651
- if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
7652
- 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;
7653
7707
  }
7654
7708
  }
7655
- const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
7656
- const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
7657
- fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
7658
- `, "utf-8");
7659
- invalidatePersistedSavedHistoryIndex("hermes-cli", dir);
7660
- savedHistorySessionCache.delete("hermes-cli");
7661
- 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);
7662
7843
  } catch {
7663
7844
  return false;
7664
7845
  }
@@ -12717,7 +12898,7 @@ var CliProviderInstance = class {
12717
12898
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
12718
12899
  }
12719
12900
  const mergedMessages = this.mergeConversationMessages(parsedMessages);
12720
- const canonicalHermesBackedHistory = this.syncCanonicalHermesSavedHistoryIfNeeded();
12901
+ const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
12721
12902
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
12722
12903
  if (parsedMessages.length > 0) {
12723
12904
  const shouldSkipReplayPersist = this.suppressIdleHistoryReplay && adapterStatus.status === "idle" && parsedStatus?.status === "idle";
@@ -12735,7 +12916,7 @@ var CliProviderInstance = class {
12735
12916
  senderName: typeof message.senderName === "string" ? message.senderName : void 0,
12736
12917
  receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
12737
12918
  }));
12738
- if (!canonicalHermesBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
12919
+ if (!canonicalBackedHistory && !shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
12739
12920
  const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
12740
12921
  this.historyWriter.appendNewMessages(
12741
12922
  this.type,
@@ -12745,7 +12926,7 @@ var CliProviderInstance = class {
12745
12926
  this.providerSessionId
12746
12927
  );
12747
12928
  }
12748
- if (!canonicalHermesBackedHistory) {
12929
+ if (!canonicalBackedHistory) {
12749
12930
  this.lastPersistedHistoryMessages = normalizedMessagesToSave;
12750
12931
  }
12751
12932
  }
@@ -13222,32 +13403,52 @@ ${effect.notification.body || ""}`.trim();
13222
13403
  });
13223
13404
  LOG.info("CLI", `[${this.type}] discovered provider session id: ${nextSessionId}`);
13224
13405
  }
13225
- syncCanonicalHermesSavedHistoryIfNeeded() {
13226
- if (this.type !== "hermes-cli" || !this.providerSessionId) return false;
13227
- try {
13228
- const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13229
- if (!fs5.existsSync(canonicalPath)) return false;
13230
- const stat = fs5.statSync(canonicalPath);
13231
- if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13232
- const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13233
- if (!rebuilt) return false;
13234
- this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13235
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13236
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13237
- role: message.role,
13238
- content: message.content,
13239
- kind: message.kind,
13240
- senderName: message.senderName,
13241
- receivedAt: message.receivedAt
13242
- }));
13243
- return true;
13244
- } catch {
13245
- 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
+ }
13246
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;
13247
13448
  }
13248
13449
  restorePersistedHistoryFromCurrentSession() {
13249
13450
  if (!this.providerSessionId) return;
13250
- this.syncCanonicalHermesSavedHistoryIfNeeded();
13451
+ this.syncCanonicalSavedHistoryIfNeeded();
13251
13452
  this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
13252
13453
  const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13253
13454
  this.historyWriter.seedSessionHistory(