@adhdev/daemon-core 0.9.3 → 0.9.5

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.
@@ -8,6 +8,7 @@
8
8
  * - Auto-rotation (delete files older than 30 days)
9
9
  * - Async/non-blocking (no impact on chat collection)
10
10
  */
11
+ import type { ProviderHistoryBehavior } from '../providers/contracts.js';
11
12
  export declare const SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES: number;
12
13
  interface HistoryMessage {
13
14
  ts: string;
@@ -75,7 +76,7 @@ export declare class ChatHistoryWriter {
75
76
  }): void;
76
77
  writeSessionStart(agentType: string, historySessionId: string, workspace: string, instanceId?: string): void;
77
78
  promoteHistorySession(agentType: string, previousHistorySessionId: string, nextHistorySessionId: string): void;
78
- compactHistorySession(agentType: string, historySessionId: string): void;
79
+ compactHistorySession(agentType: string, historySessionId: string, historyBehavior?: ProviderHistoryBehavior): void;
79
80
  /** Called when agent session is explicitly changed */
80
81
  onSessionChange(agentType: string): void;
81
82
  /** Delete history files older than 30 days */
@@ -91,14 +92,14 @@ export declare class ChatHistoryWriter {
91
92
  * the newest N messages are skipped so older-history pagination can avoid
92
93
  * duplicating the live transcript tail already shown in the UI.
93
94
  */
94
- export declare function readChatHistory(agentType: string, offset?: number, limit?: number, historySessionId?: string, excludeRecentCount?: number): {
95
+ export declare function readChatHistory(agentType: string, offset?: number, limit?: number, historySessionId?: string, excludeRecentCount?: number, historyBehavior?: ProviderHistoryBehavior): {
95
96
  messages: HistoryMessage[];
96
97
  hasMore: boolean;
97
98
  };
98
99
  export declare function listSavedHistorySessions(agentType: string, options?: {
99
100
  offset?: number;
100
101
  limit?: number;
101
- }): {
102
+ }, historyBehavior?: ProviderHistoryBehavior): {
102
103
  sessions: SavedHistorySessionSummary[];
103
104
  hasMore: boolean;
104
105
  };
@@ -23,6 +23,12 @@ type CliExerciseVerification = {
23
23
  fixtureName?: string;
24
24
  fixtureNames?: string[];
25
25
  };
26
+ export declare function shouldScheduleAutoStopOnQuiet(options: {
27
+ verification?: unknown;
28
+ autoImpl?: {
29
+ autoStopOnQuiet?: boolean;
30
+ } | null;
31
+ }): boolean;
26
32
  export declare function getDefaultAutoImplReference(ctx: DevServerContext, category: string, type: string): string;
27
33
  export declare function resolveAutoImplReference(ctx: DevServerContext, category: string, requestedReference: string | undefined, targetType: string): string | null;
28
34
  export declare function getLatestScriptVersionDir(scriptsDir: string): string | null;
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();
@@ -12990,32 +12982,10 @@ var CliProviderInstance = class {
12990
12982
  }
12991
12983
  async onTick() {
12992
12984
  if (this.providerSessionId) return;
12993
- if (this.type === "hermes-cli" && this.launchMode === "new") return;
12994
- let probedSessionId = null;
12985
+ if (this.provider.resume?.skipProbeOnNewSession && this.launchMode === "new") return;
12995
12986
  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
- }
12987
+ if (!probeConfig) return;
12988
+ const probedSessionId = this.probeSessionIdFromConfig(probeConfig);
13019
12989
  if (probedSessionId) {
13020
12990
  this.promoteProviderSessionId(probedSessionId);
13021
12991
  }
@@ -13067,7 +13037,7 @@ var CliProviderInstance = class {
13067
13037
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
13068
13038
  const visibleStatus = parseErrorMessage ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
13069
13039
  const parsedProviderSessionId = normalizeProviderSessionId(
13070
- this.type,
13040
+ this.provider,
13071
13041
  typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId : ""
13072
13042
  );
13073
13043
  if (parsedProviderSessionId) {
@@ -13357,7 +13327,7 @@ var CliProviderInstance = class {
13357
13327
  applyProviderResponse(data, options) {
13358
13328
  if (!data || typeof data !== "object") return;
13359
13329
  const patchedProviderSessionId = normalizeProviderSessionId(
13360
- this.type,
13330
+ this.provider,
13361
13331
  typeof data.providerSessionId === "string" ? data.providerSessionId : ""
13362
13332
  );
13363
13333
  if (patchedProviderSessionId) {
@@ -13595,52 +13565,39 @@ ${effect.notification.body || ""}`.trim();
13595
13565
  }
13596
13566
  syncCanonicalSavedHistoryIfNeeded() {
13597
13567
  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);
13568
+ const canonicalHistory = this.provider.canonicalHistory;
13569
+ if (!canonicalHistory) return false;
13570
+ try {
13571
+ let rebuilt = false;
13572
+ if (canonicalHistory.format === "hermes-json") {
13573
+ const watchPath = canonicalHistory.watchPath.replace(/^~/, os11.homedir()).replace("{{sessionId}}", this.providerSessionId);
13574
+ if (!fs5.existsSync(watchPath)) return false;
13575
+ const stat = fs5.statSync(watchPath);
13603
13576
  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;
13635
- }
13577
+ rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
13578
+ if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
13579
+ } else if (canonicalHistory.format === "claude-jsonl") {
13580
+ rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
13581
+ }
13582
+ if (!rebuilt) return false;
13583
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
13584
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
13585
+ role: message.role,
13586
+ content: message.content,
13587
+ kind: message.kind,
13588
+ senderName: message.senderName,
13589
+ receivedAt: message.receivedAt
13590
+ }));
13591
+ return true;
13592
+ } catch {
13593
+ return false;
13636
13594
  }
13637
- return false;
13638
13595
  }
13639
13596
  restorePersistedHistoryFromCurrentSession() {
13640
13597
  if (!this.providerSessionId) return;
13641
13598
  this.syncCanonicalSavedHistoryIfNeeded();
13642
- this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
13643
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
13599
+ this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
13600
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
13644
13601
  this.historyWriter.seedSessionHistory(
13645
13602
  this.type,
13646
13603
  restoredHistory.messages,
@@ -14881,14 +14838,15 @@ function expandResumeArgs(template, sessionId) {
14881
14838
  if (!Array.isArray(template) || template.length === 0) return void 0;
14882
14839
  return template.map((part) => part === "{{id}}" ? sessionId : part);
14883
14840
  }
14884
- function readCodexResumeSessionId(args) {
14885
- const resumeIndex = args.findIndex((arg) => arg === "resume" || arg === "fork");
14841
+ function readSubcommandSessionId(args, subcommands) {
14842
+ const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
14886
14843
  if (resumeIndex < 0) return void 0;
14887
14844
  const candidate = args[resumeIndex + 1];
14888
14845
  if (!candidate || candidate.startsWith("-")) return void 0;
14889
14846
  return candidate;
14890
14847
  }
14891
- function detectExplicitProviderSessionId(normalizedType, args) {
14848
+ function detectExplicitProviderSessionId(provider, args) {
14849
+ const resume = provider?.resume;
14892
14850
  const explicitResumeId = readArgValue(args, ["--resume", "-r"]);
14893
14851
  if (explicitResumeId) {
14894
14852
  return { providerSessionId: explicitResumeId, launchMode: "resume" };
@@ -14902,19 +14860,20 @@ function detectExplicitProviderSessionId(normalizedType, args) {
14902
14860
  }
14903
14861
  const explicitSessionId = readArgValue(args, ["--session-id"]);
14904
14862
  if (explicitSessionId) {
14905
- if (normalizedType === "goose-cli" && !hasArg(args, ["--resume", "-r"])) {
14863
+ if (resume?.sessionIdIsNewByDefault && !hasArg(args, ["--resume", "-r"])) {
14906
14864
  return { launchMode: "manual" };
14907
14865
  }
14908
- const isResume = normalizedType === "goose-cli" ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
14866
+ const isResume = resume?.sessionIdIsNewByDefault ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
14909
14867
  return {
14910
14868
  providerSessionId: explicitSessionId,
14911
14869
  launchMode: isResume ? "resume" : "new"
14912
14870
  };
14913
14871
  }
14914
- if (normalizedType === "codex-cli") {
14915
- const codexSessionId = readCodexResumeSessionId(args);
14916
- if (codexSessionId) {
14917
- return { providerSessionId: codexSessionId, launchMode: "resume" };
14872
+ const subcommands = resume?.sessionIdFromSubcommand;
14873
+ if (Array.isArray(subcommands) && subcommands.length > 0) {
14874
+ const subcommandSessionId = readSubcommandSessionId(args, subcommands);
14875
+ if (subcommandSessionId) {
14876
+ return { providerSessionId: subcommandSessionId, launchMode: "resume" };
14918
14877
  }
14919
14878
  }
14920
14879
  return { launchMode: "manual" };
@@ -14931,7 +14890,7 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
14931
14890
  if (!resume?.supported) {
14932
14891
  return { cliArgs: baseArgs, launchMode: "manual" };
14933
14892
  }
14934
- const explicit = detectExplicitProviderSessionId(normalizedType, baseArgs || []);
14893
+ const explicit = detectExplicitProviderSessionId(provider, baseArgs || []);
14935
14894
  if (explicit.providerSessionId) {
14936
14895
  return {
14937
14896
  cliArgs: baseArgs,
@@ -14939,6 +14898,12 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
14939
14898
  launchMode: explicit.launchMode
14940
14899
  };
14941
14900
  }
14901
+ if (explicit.launchMode === "manual" && hasArg(baseArgs || [], ["--session-id"])) {
14902
+ return {
14903
+ cliArgs: baseArgs,
14904
+ launchMode: "manual"
14905
+ };
14906
+ }
14942
14907
  if (requestedResumeSessionId) {
14943
14908
  if (resume.sessionIdFormat === "uuid" && !isUuid(requestedResumeSessionId)) {
14944
14909
  throw new Error(`Invalid ${provider?.displayName || provider?.name || normalizedType} session ID: ${requestedResumeSessionId}`);
@@ -15643,6 +15608,11 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
15643
15608
  "resume",
15644
15609
  "sessionProbe",
15645
15610
  "approvalPositiveHints",
15611
+ "sessionIdPattern",
15612
+ "historyBehavior",
15613
+ "canonicalHistory",
15614
+ "autoFixProfile",
15615
+ "ideLevelScripts",
15646
15616
  "scripts",
15647
15617
  "vscodeCommands",
15648
15618
  "inputMethod",
@@ -22972,20 +22942,13 @@ function tryKillAutoImplProcess(processRef, signal) {
22972
22942
  } catch {
22973
22943
  }
22974
22944
  }
22945
+ function shouldScheduleAutoStopOnQuiet(options) {
22946
+ return !!options.verification && options.autoImpl?.autoStopOnQuiet === true;
22947
+ }
22975
22948
  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
- }
22949
+ const all = ctx.providerLoader.getAll();
22950
+ const sameCategoryOther = all.find((p) => p.category === category && p.type !== type);
22951
+ if (sameCategoryOther?.type) return sameCategoryOther.type;
22989
22952
  return "antigravity";
22990
22953
  }
22991
22954
  function resolveAutoImplReference(ctx, category, requestedReference, targetType) {
@@ -23303,37 +23266,33 @@ async function handleAutoImplement(ctx, type, req, res) {
23303
23266
  return;
23304
23267
  }
23305
23268
  const command = spawn4.command;
23269
+ const autoImpl = spawn4.autoImpl;
23306
23270
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
23307
23271
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
23308
23272
  let shellCmd;
23309
23273
  const isWin = os19.platform() === "win32";
23310
23274
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
23311
- if (command === "claude") {
23312
- const args = [...baseArgs, "--dangerously-skip-permissions"];
23275
+ const promptMode = autoImpl?.promptMode ?? "stdin";
23276
+ const extraArgs = autoImpl?.extraArgs ?? [];
23277
+ 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.`;
23278
+ if (promptMode === "flag") {
23279
+ const flag = autoImpl?.promptFlag ?? "-p";
23280
+ const args = [...baseArgs, ...extraArgs];
23313
23281
  if (model) args.push("--model", model);
23314
23282
  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");
23283
+ shellCmd = `${command} ${escapedArgs} ${flag} ${escapeArg(rawMetaPrompt)}`;
23284
+ } else if (promptMode === "subcommand") {
23285
+ const subcommand = autoImpl?.subcommand ?? "";
23286
+ const args = subcommand ? [subcommand, ...baseArgs] : [...baseArgs];
23287
+ for (const extra of extraArgs) {
23288
+ if (!args.includes(extra)) args.push(extra);
23330
23289
  }
23331
23290
  if (model) args.push("--model", model);
23332
23291
  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)}`;
23292
+ shellCmd = `${command} ${escapedArgs} ${escapeArg(rawMetaPrompt)}`;
23335
23293
  } else {
23336
- const escapedArgs = baseArgs.map(escapeArg).join(" ");
23294
+ const args = [...baseArgs, ...extraArgs];
23295
+ const escapedArgs = args.map(escapeArg).join(" ");
23337
23296
  if (isWin) {
23338
23297
  shellCmd = `type "${promptFile}" | ${command} ${escapedArgs}`;
23339
23298
  } else {
@@ -23368,8 +23327,7 @@ async function handleAutoImplement(ctx, type, req, res) {
23368
23327
  stdio: ["pipe", "pipe", "pipe"],
23369
23328
  env: {
23370
23329
  ...process.env,
23371
- ...spawn4.env || {},
23372
- ...command === "gemini" ? { SANDBOX: "1", GEMINI_CLI_NO_RELAUNCH: "1" } : {}
23330
+ ...spawn4.env || {}
23373
23331
  }
23374
23332
  });
23375
23333
  child.on("error", (err2) => {
@@ -23431,7 +23389,7 @@ async function handleAutoImplement(ctx, type, req, res) {
23431
23389
  }
23432
23390
  };
23433
23391
  const scheduleAutoStopForVerification = () => {
23434
- if (!verification || command !== "codex" || completionSignalSeen || autoStopIssued) return;
23392
+ if (!shouldScheduleAutoStopOnQuiet({ verification, autoImpl }) || completionSignalSeen || autoStopIssued) return;
23435
23393
  const elapsed = Date.now() - spawnedAt;
23436
23394
  if (elapsed < 3e4) return;
23437
23395
  clearAutoStopTimer();