@adhdev/daemon-core 0.9.4 → 0.9.6

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.js CHANGED
@@ -4604,31 +4604,6 @@ function getSavedProviderSessions(state, filters) {
4604
4604
  var import_fs2 = require("fs");
4605
4605
  var import_path2 = require("path");
4606
4606
  init_config();
4607
-
4608
- // src/providers/provider-session-id.ts
4609
- var HERMES_SESSION_ID_RE = /^\d{8}_\d{6}_[a-z0-9]+$/i;
4610
- 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;
4611
- function normalizeProviderSessionId(providerType, providerSessionId) {
4612
- const normalizedProviderType = typeof providerType === "string" ? providerType.trim() : "";
4613
- const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
4614
- if (!normalizedId) return "";
4615
- const lowered = normalizedId.toLowerCase();
4616
- if (lowered === "undefined" || lowered === "null") return "";
4617
- if (normalizedProviderType === "hermes-cli" && !HERMES_SESSION_ID_RE.test(normalizedId)) {
4618
- return "";
4619
- }
4620
- if (normalizedProviderType === "claude-cli" && !CLAUDE_SESSION_ID_RE.test(normalizedId)) {
4621
- return "";
4622
- }
4623
- return normalizedId;
4624
- }
4625
- function isLegacyVolatileSessionReadKey(key) {
4626
- const normalizedKey = typeof key === "string" ? key.trim() : "";
4627
- if (!normalizedKey) return false;
4628
- return normalizedKey.startsWith("provider:codex:vscode-webview://");
4629
- }
4630
-
4631
- // src/config/state-store.ts
4632
4607
  var DEFAULT_STATE = {
4633
4608
  recentActivity: [],
4634
4609
  savedProviderSessions: [],
@@ -4647,31 +4622,24 @@ function normalizeState(raw) {
4647
4622
  const parsed = isPlainObject2(raw) ? raw : {};
4648
4623
  const recentActivity = (Array.isArray(parsed.recentActivity) ? parsed.recentActivity : []).filter((entry) => {
4649
4624
  if (!isPlainObject2(entry)) return false;
4650
- const normalizedId = normalizeProviderSessionId(
4651
- typeof entry.providerType === "string" ? entry.providerType : "",
4652
- typeof entry.providerSessionId === "string" ? entry.providerSessionId : ""
4653
- );
4654
- if (typeof entry.providerSessionId === "string" && !normalizedId) return false;
4625
+ if (typeof entry.providerSessionId === "string" && !entry.providerSessionId.trim()) return false;
4655
4626
  return true;
4656
4627
  });
4657
4628
  const savedProviderSessions = (Array.isArray(parsed.savedProviderSessions) ? parsed.savedProviderSessions : []).filter((entry) => {
4658
4629
  if (!isPlainObject2(entry)) return false;
4659
- return !!normalizeProviderSessionId(
4660
- typeof entry.providerType === "string" ? entry.providerType : "",
4661
- typeof entry.providerSessionId === "string" ? entry.providerSessionId : ""
4662
- );
4630
+ return typeof entry.providerSessionId === "string" && !!entry.providerSessionId.trim();
4663
4631
  });
4664
4632
  const sessionReads = Object.fromEntries(
4665
- Object.entries(isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "number" && Number.isFinite(value))
4633
+ Object.entries(isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {}).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
4666
4634
  );
4667
4635
  const sessionReadMarkers = Object.fromEntries(
4668
- Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string")
4636
+ Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
4669
4637
  );
4670
4638
  const sessionNotificationDismissals = Object.fromEntries(
4671
- Object.entries(isPlainObject2(parsed.sessionNotificationDismissals) ? parsed.sessionNotificationDismissals : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
4639
+ Object.entries(isPlainObject2(parsed.sessionNotificationDismissals) ? parsed.sessionNotificationDismissals : {}).filter(([, value]) => typeof value === "string" && value.length > 0)
4672
4640
  );
4673
4641
  const sessionNotificationUnreadOverrides = Object.fromEntries(
4674
- Object.entries(isPlainObject2(parsed.sessionNotificationUnreadOverrides) ? parsed.sessionNotificationUnreadOverrides : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
4642
+ Object.entries(isPlainObject2(parsed.sessionNotificationUnreadOverrides) ? parsed.sessionNotificationUnreadOverrides : {}).filter(([, value]) => typeof value === "string" && value.length > 0)
4675
4643
  );
4676
4644
  return {
4677
4645
  recentActivity,
@@ -6763,16 +6731,24 @@ var savedHistorySessionCache = /* @__PURE__ */ new Map();
6763
6731
  var savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
6764
6732
  var savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
6765
6733
  var savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
6766
- var CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
6767
6734
  function normalizeHistoryComparable(text) {
6768
6735
  return String(text || "").replace(/\s+/g, " ").trim();
6769
6736
  }
6770
- function cleanupHistoryContent(agentType, role, content) {
6737
+ function cleanupHistoryContent(agentType, role, content, historyBehavior) {
6771
6738
  let value = String(content || "").replace(/\r\n/g, "\n").trim();
6772
6739
  if (!value) return "";
6773
- if (agentType === "codex-cli" && role === "assistant") {
6774
- const filtered = value.split("\n").filter((line) => !CODEX_STARTER_PROMPT_RE.test(line.trim())).join("\n").replace(/\n{3,}/g, "\n\n").trim();
6775
- value = filtered;
6740
+ if (role === "assistant" && historyBehavior?.filterAssistantPatterns?.length) {
6741
+ const filters = historyBehavior.filterAssistantPatterns.map((p) => {
6742
+ try {
6743
+ return new RegExp(p, "i");
6744
+ } catch {
6745
+ return null;
6746
+ }
6747
+ }).filter(Boolean);
6748
+ if (filters.length > 0) {
6749
+ const filtered = value.split("\n").filter((line) => !filters.some((re) => re.test(line.trim()))).join("\n").replace(/\n{3,}/g, "\n\n").trim();
6750
+ value = filtered;
6751
+ }
6776
6752
  }
6777
6753
  return value;
6778
6754
  }
@@ -6789,8 +6765,8 @@ function isAdjacentHistoryDuplicate(agentType, previous, next) {
6789
6765
  if (!previous || !next) return false;
6790
6766
  return buildHistoryMessageSignature(agentType, previous) === buildHistoryMessageSignature(agentType, next);
6791
6767
  }
6792
- function collapseReplayAssistantTurns(agentType, messages) {
6793
- if (agentType !== "codex-cli") return messages;
6768
+ function collapseReplayAssistantTurns(messages, historyBehavior) {
6769
+ if (!historyBehavior?.collapseConsecutiveAssistantTurns) return messages;
6794
6770
  const collapsed = [];
6795
6771
  let sawAssistantSinceLastUser = false;
6796
6772
  for (const message of messages) {
@@ -6895,16 +6871,12 @@ function listHistoryFiles(dir, historySessionId) {
6895
6871
  return true;
6896
6872
  }).sort().reverse();
6897
6873
  }
6898
- function normalizeSavedHistorySessionId(agentType, historySessionId) {
6899
- const normalizedId = String(historySessionId || "").trim();
6900
- if (!normalizedId) return "";
6901
- const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
6902
- if (strictProviderId) return strictProviderId;
6903
- return agentType === "hermes-cli" ? "" : normalizedId;
6874
+ function normalizeSavedHistorySessionId(historySessionId) {
6875
+ return String(historySessionId || "").trim();
6904
6876
  }
6905
- function extractSavedHistorySessionIdFromFile(agentType, file) {
6877
+ function extractSavedHistorySessionIdFromFile(file) {
6906
6878
  const match = file.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
6907
- return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
6879
+ return normalizeSavedHistorySessionId(match?.[1] || "");
6908
6880
  }
6909
6881
  function buildSavedHistoryFileSignatureMap(dir, files) {
6910
6882
  return new Map(files.map((file) => {
@@ -7083,7 +7055,7 @@ function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
7083
7055
  }
7084
7056
  }
7085
7057
  function updateSavedHistoryIndexForSessionStart(agentType, dir, file, historySessionId, workspace) {
7086
- const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
7058
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
7087
7059
  const normalizedWorkspace = String(workspace || "").trim();
7088
7060
  if (!normalizedSessionId || !normalizedWorkspace) return;
7089
7061
  persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => ({
@@ -7098,7 +7070,7 @@ function updateSavedHistoryIndexForSessionStart(agentType, dir, file, historySes
7098
7070
  }));
7099
7071
  }
7100
7072
  function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, historySessionId, messages) {
7101
- const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
7073
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
7102
7074
  if (!normalizedSessionId || messages.length === 0) return;
7103
7075
  persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => {
7104
7076
  const nextSummary = {
@@ -7135,8 +7107,8 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
7135
7107
  return nextSummary;
7136
7108
  });
7137
7109
  }
7138
- function computeSavedHistoryFileSummary(agentType, dir, file) {
7139
- const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file);
7110
+ function computeSavedHistoryFileSummary(dir, file) {
7111
+ const historySessionId = extractSavedHistorySessionIdFromFile(file);
7140
7112
  if (!historySessionId) return null;
7141
7113
  const filePath = path7.join(dir, file);
7142
7114
  const content = fs3.readFileSync(filePath, "utf-8");
@@ -7230,7 +7202,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
7230
7202
  const cached = savedHistoryFileSummaryCache.get(filePath);
7231
7203
  const persisted = persistedEntries.get(file);
7232
7204
  const reusableEntry = cached?.signature === signature ? cached : persisted?.signature === signature ? persisted : null;
7233
- const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file);
7205
+ const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(dir, file);
7234
7206
  const nextEntry = reusableEntry || {
7235
7207
  signature,
7236
7208
  summary: fileSummary
@@ -7528,7 +7500,7 @@ var ChatHistoryWriter = class {
7528
7500
  } catch {
7529
7501
  }
7530
7502
  }
7531
- compactHistorySession(agentType, historySessionId) {
7503
+ compactHistorySession(agentType, historySessionId, historyBehavior) {
7532
7504
  const sessionId = String(historySessionId || "").trim();
7533
7505
  if (!sessionId) return;
7534
7506
  try {
@@ -7566,7 +7538,7 @@ var ChatHistoryWriter = class {
7566
7538
  dedupedAdjacent.push(entry);
7567
7539
  if (entry.role !== "system") lastTurn = entry;
7568
7540
  }
7569
- const collapsed = collapseReplayAssistantTurns(agentType, dedupedAdjacent);
7541
+ const collapsed = collapseReplayAssistantTurns(dedupedAdjacent, historyBehavior);
7570
7542
  if (collapsed.length === 0) {
7571
7543
  fs3.unlinkSync(filePath);
7572
7544
  continue;
@@ -7615,7 +7587,7 @@ var ChatHistoryWriter = class {
7615
7587
  return name.replace(/[^a-zA-Z0-9_-]/g, "_");
7616
7588
  }
7617
7589
  };
7618
- function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0) {
7590
+ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
7619
7591
  try {
7620
7592
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
7621
7593
  const dir = path7.join(HISTORY_DIR, sanitized);
@@ -7650,7 +7622,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
7650
7622
  chronological.push(message);
7651
7623
  if (message.role !== "system") lastTurn = message;
7652
7624
  }
7653
- const collapsed = collapseReplayAssistantTurns(agentType, chronological);
7625
+ const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
7654
7626
  const boundedLimit = Math.max(1, limit);
7655
7627
  const boundedOffset = Math.max(0, offset);
7656
7628
  const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
@@ -7663,7 +7635,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
7663
7635
  return { messages: [], hasMore: false };
7664
7636
  }
7665
7637
  }
7666
- function listSavedHistorySessions(agentType, options = {}) {
7638
+ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
7667
7639
  try {
7668
7640
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
7669
7641
  const dir = path7.join(HISTORY_DIR, sanitized);
@@ -7794,7 +7766,7 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
7794
7766
  }
7795
7767
  }
7796
7768
  function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
7797
- const normalizedSessionId = normalizeSavedHistorySessionId("hermes-cli", historySessionId);
7769
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
7798
7770
  if (!normalizedSessionId) return false;
7799
7771
  try {
7800
7772
  const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
@@ -7943,7 +7915,7 @@ function extractClaudeUserContentParts(content) {
7943
7915
  return parts;
7944
7916
  }
7945
7917
  function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
7946
- const normalizedSessionId = normalizeSavedHistorySessionId("claude-cli", historySessionId);
7918
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
7947
7919
  if (!normalizedSessionId) return false;
7948
7920
  try {
7949
7921
  const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
@@ -12109,7 +12081,8 @@ async function executeProviderScript(h, args, scriptName) {
12109
12081
  }
12110
12082
  const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
12111
12083
  const targetSessionId = managed?.cdpSessionId || null;
12112
- const IDE_LEVEL_SCRIPTS = provider.type === "claude-code-vscode" ? ["listModes", "setMode", "listModels", "setModel", "setModelGui"] : ["listModes", "setMode", "listModels", "setModel"];
12084
+ const DEFAULT_IDE_LEVEL_SCRIPTS = ["listModes", "setMode", "listModels", "setModel"];
12085
+ const IDE_LEVEL_SCRIPTS = provider.ideLevelScripts ?? DEFAULT_IDE_LEVEL_SCRIPTS;
12113
12086
  if (IDE_LEVEL_SCRIPTS.includes(scriptName)) {
12114
12087
  if (targetSessionId) {
12115
12088
  try {
@@ -12834,6 +12807,25 @@ var import_node_module = require("module");
12834
12807
  init_contracts();
12835
12808
  init_provider_cli_adapter();
12836
12809
  init_logger();
12810
+
12811
+ // src/providers/provider-session-id.ts
12812
+ function normalizeProviderSessionId(provider, providerSessionId) {
12813
+ const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
12814
+ if (!normalizedId) return "";
12815
+ const lowered = normalizedId.toLowerCase();
12816
+ if (lowered === "undefined" || lowered === "null") return "";
12817
+ const sessionIdPattern = provider?.sessionIdPattern;
12818
+ if (sessionIdPattern) {
12819
+ try {
12820
+ const re = new RegExp(sessionIdPattern, "i");
12821
+ if (!re.test(normalizedId)) return "";
12822
+ } catch {
12823
+ }
12824
+ }
12825
+ return normalizedId;
12826
+ }
12827
+
12828
+ // src/providers/cli-provider-instance.ts
12837
12829
  init_chat_message_normalization();
12838
12830
  function normalizePersistableCliHistoryContent(content) {
12839
12831
  return flattenContent(content).replace(/\s+/g, " ").trim();
@@ -12940,6 +12932,13 @@ var CliProviderInstance = class {
12940
12932
  runtimeMessages = [];
12941
12933
  lastPersistedHistoryMessages = [];
12942
12934
  lastCanonicalHermesSyncMtimeMs = 0;
12935
+ lastCanonicalHermesExistCheckAt = 0;
12936
+ lastCanonicalHermesWatchPath = void 0;
12937
+ lastCanonicalClaudeRebuildMtimeMs = 0;
12938
+ lastCanonicalClaudeCheckAt = 0;
12939
+ cachedSqliteDb = null;
12940
+ cachedSqliteDbPath = null;
12941
+ cachedSqliteDbMissingUntil = 0;
12943
12942
  instanceId;
12944
12943
  suppressIdleHistoryReplay = false;
12945
12944
  errorMessage = void 0;
@@ -12990,32 +12989,10 @@ var CliProviderInstance = class {
12990
12989
  }
12991
12990
  async onTick() {
12992
12991
  if (this.providerSessionId) return;
12993
- if (this.type === "hermes-cli" && this.launchMode === "new") return;
12994
- let probedSessionId = null;
12992
+ if (this.provider.resume?.skipProbeOnNewSession && this.launchMode === "new") return;
12995
12993
  const probeConfig = this.provider.sessionProbe;
12996
- if (probeConfig) {
12997
- probedSessionId = this.probeSessionIdFromConfig(probeConfig);
12998
- } else {
12999
- if (this.type === "opencode-cli") {
13000
- probedSessionId = this.probeSessionIdFromConfig({
13001
- dbPath: "~/.local/share/opencode/opencode.db",
13002
- query: "select id from session where directory in ({dirs}) and time_created >= ? and time_archived is null order by time_updated desc limit 1",
13003
- timestampFormat: "unix_ms"
13004
- });
13005
- } else if (this.type === "codex-cli") {
13006
- probedSessionId = this.probeSessionIdFromConfig({
13007
- dbPath: "~/.codex/state_5.sqlite",
13008
- query: "select id from threads where cwd in ({dirs}) and updated_at >= ? and archived = 0 order by updated_at desc limit 1",
13009
- timestampFormat: "unix_s"
13010
- });
13011
- } else if (this.type === "goose-cli") {
13012
- probedSessionId = this.probeSessionIdFromConfig({
13013
- dbPath: "~/.local/share/goose/sessions/sessions.db",
13014
- query: "select id from sessions where working_dir in ({dirs}) and created_at >= ? order by updated_at desc limit 1",
13015
- timestampFormat: "iso"
13016
- });
13017
- }
13018
- }
12994
+ if (!probeConfig) return;
12995
+ const probedSessionId = this.probeSessionIdFromConfig(probeConfig);
13019
12996
  if (probedSessionId) {
13020
12997
  this.promoteProviderSessionId(probedSessionId);
13021
12998
  }
@@ -13026,7 +13003,12 @@ var CliProviderInstance = class {
13026
13003
  */
13027
13004
  probeSessionIdFromConfig(probe) {
13028
13005
  const resolvedDbPath = probe.dbPath.replace(/^~/, os11.homedir());
13029
- if (!fs5.existsSync(resolvedDbPath)) return null;
13006
+ const now = Date.now();
13007
+ if (this.cachedSqliteDbMissingUntil > now) return null;
13008
+ if (!fs5.existsSync(resolvedDbPath)) {
13009
+ this.cachedSqliteDbMissingUntil = now + 1e4;
13010
+ return null;
13011
+ }
13030
13012
  const directories = this.getProbeDirectories();
13031
13013
  const minCreatedAt = Math.max(0, this.startedAt - 6e4);
13032
13014
  const tsFormat = probe.timestampFormat || "unix_ms";
@@ -13067,7 +13049,7 @@ var CliProviderInstance = class {
13067
13049
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13068
13050
  const visibleStatus = parseErrorMessage ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
13069
13051
  const parsedProviderSessionId = normalizeProviderSessionId(
13070
- this.type,
13052
+ this.provider,
13071
13053
  typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId : ""
13072
13054
  );
13073
13055
  if (parsedProviderSessionId) {
@@ -13197,6 +13179,12 @@ var CliProviderInstance = class {
13197
13179
  this.adapter.shutdown();
13198
13180
  this.monitor.reset();
13199
13181
  this.appliedEffectKeys.clear();
13182
+ try {
13183
+ this.cachedSqliteDb?.close();
13184
+ } catch {
13185
+ }
13186
+ this.cachedSqliteDb = null;
13187
+ this.cachedSqliteDbPath = null;
13200
13188
  }
13201
13189
  completedDebounceTimer = null;
13202
13190
  completedDebouncePending = null;
@@ -13357,7 +13345,7 @@ var CliProviderInstance = class {
13357
13345
  applyProviderResponse(data, options) {
13358
13346
  if (!data || typeof data !== "object") return;
13359
13347
  const patchedProviderSessionId = normalizeProviderSessionId(
13360
- this.type,
13348
+ this.provider,
13361
13349
  typeof data.providerSessionId === "string" ? data.providerSessionId : ""
13362
13350
  );
13363
13351
  if (patchedProviderSessionId) {
@@ -13595,52 +13583,61 @@ ${effect.notification.body || ""}`.trim();
13595
13583
  }
13596
13584
  syncCanonicalSavedHistoryIfNeeded() {
13597
13585
  if (!this.providerSessionId) return false;
13598
- if (this.type === "hermes-cli") {
13599
- try {
13600
- const canonicalPath = path11.join(os11.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
13601
- if (!fs5.existsSync(canonicalPath)) return false;
13602
- const stat = fs5.statSync(canonicalPath);
13586
+ const canonicalHistory = this.provider.canonicalHistory;
13587
+ if (!canonicalHistory) return false;
13588
+ try {
13589
+ let rebuilt = false;
13590
+ if (canonicalHistory.format === "hermes-json") {
13591
+ const watchPath = canonicalHistory.watchPath.replace(/^~/, os11.homedir()).replace("{{sessionId}}", this.providerSessionId);
13592
+ const now = Date.now();
13593
+ if (watchPath !== this.lastCanonicalHermesWatchPath || now - this.lastCanonicalHermesExistCheckAt >= 2e3) {
13594
+ this.lastCanonicalHermesWatchPath = watchPath;
13595
+ this.lastCanonicalHermesExistCheckAt = now;
13596
+ if (!fs5.existsSync(watchPath)) return false;
13597
+ } else if (this.lastCanonicalHermesSyncMtimeMs === 0) {
13598
+ if (!fs5.existsSync(watchPath)) return false;
13599
+ }
13600
+ const stat = fs5.statSync(watchPath);
13603
13601
  if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
13604
- const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13605
- if (!rebuilt) return false;
13606
- this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13607
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13608
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13609
- role: message.role,
13610
- content: message.content,
13611
- kind: message.kind,
13612
- senderName: message.senderName,
13613
- receivedAt: message.receivedAt
13614
- }));
13615
- return true;
13616
- } catch {
13617
- return false;
13618
- }
13619
- }
13620
- if (this.type === "claude-cli") {
13621
- try {
13622
- const rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
13623
- if (!rebuilt) return false;
13624
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13625
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13626
- role: message.role,
13627
- content: message.content,
13628
- kind: message.kind,
13629
- senderName: message.senderName,
13630
- receivedAt: message.receivedAt
13631
- }));
13632
- return true;
13633
- } catch {
13634
- return false;
13602
+ rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13603
+ if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13604
+ } else if (canonicalHistory.format === "claude-jsonl") {
13605
+ const now = Date.now();
13606
+ if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
13607
+ return true;
13608
+ }
13609
+ this.lastCanonicalClaudeCheckAt = now;
13610
+ const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
13611
+ const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
13612
+ const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
13613
+ let transcriptMtime = 0;
13614
+ try {
13615
+ transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
13616
+ } catch {
13617
+ }
13618
+ if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
13619
+ rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
13620
+ if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
13635
13621
  }
13622
+ if (!rebuilt) return false;
13623
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
13624
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13625
+ role: message.role,
13626
+ content: message.content,
13627
+ kind: message.kind,
13628
+ senderName: message.senderName,
13629
+ receivedAt: message.receivedAt
13630
+ }));
13631
+ return true;
13632
+ } catch {
13633
+ return false;
13636
13634
  }
13637
- return false;
13638
13635
  }
13639
13636
  restorePersistedHistoryFromCurrentSession() {
13640
13637
  if (!this.providerSessionId) return;
13641
13638
  this.syncCanonicalSavedHistoryIfNeeded();
13642
- this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
13643
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13639
+ this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
13640
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
13644
13641
  this.historyWriter.seedSessionHistory(
13645
13642
  this.type,
13646
13643
  restoredHistory.messages,
@@ -13685,20 +13682,29 @@ ${effect.notification.body || ""}`.trim();
13685
13682
  return Array.from({ length: count }, () => "?").join(", ");
13686
13683
  }
13687
13684
  querySqliteText(dbPath, query, params) {
13688
- let db = null;
13689
13685
  try {
13690
- const DatabaseSync = getDatabaseSync();
13691
- db = new DatabaseSync(dbPath, { readOnly: true });
13692
- const row = db.prepare(query).get(...params);
13686
+ if (this.cachedSqliteDb === null || this.cachedSqliteDbPath !== dbPath) {
13687
+ try {
13688
+ this.cachedSqliteDb?.close();
13689
+ } catch {
13690
+ }
13691
+ this.cachedSqliteDb = null;
13692
+ this.cachedSqliteDbPath = null;
13693
+ const DatabaseSync = getDatabaseSync();
13694
+ this.cachedSqliteDb = new DatabaseSync(dbPath, { readOnly: true });
13695
+ this.cachedSqliteDbPath = dbPath;
13696
+ }
13697
+ const row = this.cachedSqliteDb.prepare(query).get(...params);
13693
13698
  const sessionId = typeof row?.id === "string" ? row.id.trim() : "";
13694
13699
  return sessionId || null;
13695
13700
  } catch {
13696
- return null;
13697
- } finally {
13698
13701
  try {
13699
- db?.close();
13702
+ this.cachedSqliteDb?.close();
13700
13703
  } catch {
13701
13704
  }
13705
+ this.cachedSqliteDb = null;
13706
+ this.cachedSqliteDbPath = null;
13707
+ return null;
13702
13708
  }
13703
13709
  }
13704
13710
  };
@@ -14881,14 +14887,15 @@ function expandResumeArgs(template, sessionId) {
14881
14887
  if (!Array.isArray(template) || template.length === 0) return void 0;
14882
14888
  return template.map((part) => part === "{{id}}" ? sessionId : part);
14883
14889
  }
14884
- function readCodexResumeSessionId(args) {
14885
- const resumeIndex = args.findIndex((arg) => arg === "resume" || arg === "fork");
14890
+ function readSubcommandSessionId(args, subcommands) {
14891
+ const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
14886
14892
  if (resumeIndex < 0) return void 0;
14887
14893
  const candidate = args[resumeIndex + 1];
14888
14894
  if (!candidate || candidate.startsWith("-")) return void 0;
14889
14895
  return candidate;
14890
14896
  }
14891
- function detectExplicitProviderSessionId(normalizedType, args) {
14897
+ function detectExplicitProviderSessionId(provider, args) {
14898
+ const resume = provider?.resume;
14892
14899
  const explicitResumeId = readArgValue(args, ["--resume", "-r"]);
14893
14900
  if (explicitResumeId) {
14894
14901
  return { providerSessionId: explicitResumeId, launchMode: "resume" };
@@ -14902,19 +14909,20 @@ function detectExplicitProviderSessionId(normalizedType, args) {
14902
14909
  }
14903
14910
  const explicitSessionId = readArgValue(args, ["--session-id"]);
14904
14911
  if (explicitSessionId) {
14905
- if (normalizedType === "goose-cli" && !hasArg(args, ["--resume", "-r"])) {
14912
+ if (resume?.sessionIdIsNewByDefault && !hasArg(args, ["--resume", "-r"])) {
14906
14913
  return { launchMode: "manual" };
14907
14914
  }
14908
- const isResume = normalizedType === "goose-cli" ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
14915
+ const isResume = resume?.sessionIdIsNewByDefault ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
14909
14916
  return {
14910
14917
  providerSessionId: explicitSessionId,
14911
14918
  launchMode: isResume ? "resume" : "new"
14912
14919
  };
14913
14920
  }
14914
- if (normalizedType === "codex-cli") {
14915
- const codexSessionId = readCodexResumeSessionId(args);
14916
- if (codexSessionId) {
14917
- return { providerSessionId: codexSessionId, launchMode: "resume" };
14921
+ const subcommands = resume?.sessionIdFromSubcommand;
14922
+ if (Array.isArray(subcommands) && subcommands.length > 0) {
14923
+ const subcommandSessionId = readSubcommandSessionId(args, subcommands);
14924
+ if (subcommandSessionId) {
14925
+ return { providerSessionId: subcommandSessionId, launchMode: "resume" };
14918
14926
  }
14919
14927
  }
14920
14928
  return { launchMode: "manual" };
@@ -14931,7 +14939,7 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
14931
14939
  if (!resume?.supported) {
14932
14940
  return { cliArgs: baseArgs, launchMode: "manual" };
14933
14941
  }
14934
- const explicit = detectExplicitProviderSessionId(normalizedType, baseArgs || []);
14942
+ const explicit = detectExplicitProviderSessionId(provider, baseArgs || []);
14935
14943
  if (explicit.providerSessionId) {
14936
14944
  return {
14937
14945
  cliArgs: baseArgs,
@@ -14939,6 +14947,12 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
14939
14947
  launchMode: explicit.launchMode
14940
14948
  };
14941
14949
  }
14950
+ if (explicit.launchMode === "manual" && hasArg(baseArgs || [], ["--session-id"])) {
14951
+ return {
14952
+ cliArgs: baseArgs,
14953
+ launchMode: "manual"
14954
+ };
14955
+ }
14942
14956
  if (requestedResumeSessionId) {
14943
14957
  if (resume.sessionIdFormat === "uuid" && !isUuid(requestedResumeSessionId)) {
14944
14958
  throw new Error(`Invalid ${provider?.displayName || provider?.name || normalizedType} session ID: ${requestedResumeSessionId}`);
@@ -15643,6 +15657,12 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
15643
15657
  "resume",
15644
15658
  "sessionProbe",
15645
15659
  "approvalPositiveHints",
15660
+ "sessionIdPattern",
15661
+ "historyBehavior",
15662
+ "canonicalHistory",
15663
+ "autoFixProfile",
15664
+ "ideLevelScripts",
15665
+ "allowInputDuringGeneration",
15646
15666
  "scripts",
15647
15667
  "vscodeCommands",
15648
15668
  "inputMethod",
@@ -22972,20 +22992,13 @@ function tryKillAutoImplProcess(processRef, signal) {
22972
22992
  } catch {
22973
22993
  }
22974
22994
  }
22995
+ function shouldScheduleAutoStopOnQuiet(options) {
22996
+ return !!options.verification && options.autoImpl?.autoStopOnQuiet === true;
22997
+ }
22975
22998
  function getDefaultAutoImplReference(ctx, category, type) {
22976
- if (category === "cli") {
22977
- return type === "codex-cli" ? "claude-cli" : "codex-cli";
22978
- }
22979
- if (category === "extension") {
22980
- const preferred = ["claude-code-vscode", "codex", "cline", "roo-code"];
22981
- for (const ref of preferred) {
22982
- if (ref === type) continue;
22983
- if (ctx.providerLoader.resolve(ref) || ctx.providerLoader.getMeta(ref)) return ref;
22984
- }
22985
- const all = ctx.providerLoader.getAll();
22986
- const fb = all.find((p) => p.category === "extension" && p.type !== type);
22987
- if (fb?.type) return fb.type;
22988
- }
22999
+ const all = ctx.providerLoader.getAll();
23000
+ const sameCategoryOther = all.find((p) => p.category === category && p.type !== type);
23001
+ if (sameCategoryOther?.type) return sameCategoryOther.type;
22989
23002
  return "antigravity";
22990
23003
  }
22991
23004
  function resolveAutoImplReference(ctx, category, requestedReference, targetType) {
@@ -23303,37 +23316,33 @@ async function handleAutoImplement(ctx, type, req, res) {
23303
23316
  return;
23304
23317
  }
23305
23318
  const command = spawn4.command;
23319
+ const autoImpl = spawn4.autoImpl;
23306
23320
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
23307
23321
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
23308
23322
  let shellCmd;
23309
23323
  const isWin = os19.platform() === "win32";
23310
23324
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
23311
- if (command === "claude") {
23312
- const args = [...baseArgs, "--dangerously-skip-permissions"];
23325
+ const promptMode = autoImpl?.promptMode ?? "stdin";
23326
+ const extraArgs = autoImpl?.extraArgs ?? [];
23327
+ const rawMetaPrompt = autoImpl?.metaPrompt ? autoImpl.metaPrompt.replace("{{promptFile}}", promptFile) : `Read the file at ${promptFile} and follow ALL the instructions in it exactly. Do not ask questions, just execute.`;
23328
+ if (promptMode === "flag") {
23329
+ const flag = autoImpl?.promptFlag ?? "-p";
23330
+ const args = [...baseArgs, ...extraArgs];
23313
23331
  if (model) args.push("--model", model);
23314
23332
  const escapedArgs = args.map(escapeArg).join(" ");
23315
- const metaPrompt = `Read the file at ${promptFile} and follow ALL the instructions. Implement the specific function requested, then test it via CDP curl targeting 127.0.0.1:19280, wait for confirmation of success, and then close. DO NOT start working on other features not listed in the prompt constraint.`;
23316
- shellCmd = `${command} ${escapedArgs} -p ${escapeArg(metaPrompt)}`;
23317
- } else if (command === "gemini") {
23318
- const args = [...baseArgs, "-y", "-s", "false"];
23319
- if (model) args.push("-m", model);
23320
- const escapedArgs = args.map(escapeArg).join(" ");
23321
- const metaPrompt = `Read the file at ${promptFile} and follow ALL the instructions in it exactly. Do not ask questions, just execute.`;
23322
- shellCmd = `${command} ${escapedArgs} -p ${escapeArg(metaPrompt)}`;
23323
- } else if (command === "codex") {
23324
- const args = ["exec", ...baseArgs];
23325
- if (!args.includes("--dangerously-bypass-approvals-and-sandbox")) {
23326
- args.push("--dangerously-bypass-approvals-and-sandbox");
23327
- }
23328
- if (!args.includes("--skip-git-repo-check")) {
23329
- args.push("--skip-git-repo-check");
23333
+ shellCmd = `${command} ${escapedArgs} ${flag} ${escapeArg(rawMetaPrompt)}`;
23334
+ } else if (promptMode === "subcommand") {
23335
+ const subcommand = autoImpl?.subcommand ?? "";
23336
+ const args = subcommand ? [subcommand, ...baseArgs] : [...baseArgs];
23337
+ for (const extra of extraArgs) {
23338
+ if (!args.includes(extra)) args.push(extra);
23330
23339
  }
23331
23340
  if (model) args.push("--model", model);
23332
23341
  const escapedArgs = args.map(escapeArg).join(" ");
23333
- const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions strictly. DO NOT spend time exploring the filesystem or other providers. You have full authority to implement ALL required script files and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "_PIPELINE_COMPLETE_SIGNAL_" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
23334
- shellCmd = `${command} ${escapedArgs} ${escapeArg(metaPrompt)}`;
23342
+ shellCmd = `${command} ${escapedArgs} ${escapeArg(rawMetaPrompt)}`;
23335
23343
  } else {
23336
- const escapedArgs = baseArgs.map(escapeArg).join(" ");
23344
+ const args = [...baseArgs, ...extraArgs];
23345
+ const escapedArgs = args.map(escapeArg).join(" ");
23337
23346
  if (isWin) {
23338
23347
  shellCmd = `type "${promptFile}" | ${command} ${escapedArgs}`;
23339
23348
  } else {
@@ -23368,8 +23377,7 @@ async function handleAutoImplement(ctx, type, req, res) {
23368
23377
  stdio: ["pipe", "pipe", "pipe"],
23369
23378
  env: {
23370
23379
  ...process.env,
23371
- ...spawn4.env || {},
23372
- ...command === "gemini" ? { SANDBOX: "1", GEMINI_CLI_NO_RELAUNCH: "1" } : {}
23380
+ ...spawn4.env || {}
23373
23381
  }
23374
23382
  });
23375
23383
  child.on("error", (err2) => {
@@ -23431,7 +23439,7 @@ async function handleAutoImplement(ctx, type, req, res) {
23431
23439
  }
23432
23440
  };
23433
23441
  const scheduleAutoStopForVerification = () => {
23434
- if (!verification || command !== "codex" || completionSignalSeen || autoStopIssued) return;
23442
+ if (!shouldScheduleAutoStopOnQuiet({ verification, autoImpl }) || completionSignalSeen || autoStopIssued) return;
23435
23443
  const elapsed = Date.now() - spawnedAt;
23436
23444
  if (elapsed < 3e4) return;
23437
23445
  clearAutoStopTimer();