@adhdev/daemon-core 0.8.81 → 0.8.83

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.
Files changed (36) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
  2. package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
  3. package/dist/config/recent-activity.d.ts +14 -0
  4. package/dist/config/state-store.d.ts +4 -0
  5. package/dist/index.js +363 -117
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +363 -117
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/providers/acp-provider-instance.d.ts +0 -2
  10. package/dist/providers/cli-provider-instance.d.ts +2 -0
  11. package/dist/providers/provider-instance.d.ts +1 -1
  12. package/dist/shared-types.d.ts +3 -1
  13. package/dist/status/chat-tail-hot-sessions.d.ts +2 -0
  14. package/dist/status/snapshot.d.ts +1 -0
  15. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  16. package/package.json +1 -1
  17. package/src/cli-adapter-types.d.ts +2 -0
  18. package/src/cli-adapters/provider-cli-adapter.ts +107 -30
  19. package/src/cli-adapters/provider-cli-shared.d.ts +3 -4
  20. package/src/cli-adapters/provider-cli-shared.ts +2 -0
  21. package/src/cli-adapters/terminal-screen.ts +6 -4
  22. package/src/commands/chat-commands.ts +8 -3
  23. package/src/commands/router.ts +59 -1
  24. package/src/config/recent-activity.ts +122 -0
  25. package/src/config/state-store.ts +16 -0
  26. package/src/logging/command-log.ts +2 -0
  27. package/src/providers/acp-provider-instance.ts +2 -17
  28. package/src/providers/cli-provider-instance.ts +33 -10
  29. package/src/providers/extension-provider-instance.ts +0 -2
  30. package/src/providers/ide-provider-instance.ts +0 -2
  31. package/src/providers/provider-instance.d.ts +1 -1
  32. package/src/providers/provider-instance.ts +1 -0
  33. package/src/shared-types.d.ts +3 -0
  34. package/src/shared-types.ts +5 -1
  35. package/src/status/chat-tail-hot-sessions.ts +15 -1
  36. package/src/status/snapshot.ts +20 -3
package/dist/index.mjs CHANGED
@@ -951,6 +951,58 @@ var init_read_chat_contract = __esm({
951
951
  }
952
952
  });
953
953
 
954
+ // src/logging/debug-config.ts
955
+ function normalizeCategories(categories) {
956
+ if (!Array.isArray(categories)) return [];
957
+ return categories.map((category) => String(category || "").trim()).filter(Boolean);
958
+ }
959
+ function resolveDebugRuntimeConfig(options = {}) {
960
+ const dev = options.dev === true;
961
+ return {
962
+ logLevel: options.logLevel || (dev ? "debug" : DEFAULT_CONFIG2.logLevel),
963
+ collectDebugTrace: typeof options.trace === "boolean" ? options.trace : dev,
964
+ traceContent: options.traceContent === true,
965
+ traceBufferSize: Number.isFinite(options.traceBufferSize) ? Math.max(10, Math.floor(options.traceBufferSize)) : dev ? DEV_TRACE_BUFFER_SIZE : DEFAULT_CONFIG2.traceBufferSize,
966
+ traceCategories: normalizeCategories(options.traceCategories)
967
+ };
968
+ }
969
+ function setDebugRuntimeConfig(config) {
970
+ currentConfig = {
971
+ ...config,
972
+ traceCategories: normalizeCategories(config.traceCategories),
973
+ traceBufferSize: Math.max(10, Math.floor(config.traceBufferSize || DEFAULT_CONFIG2.traceBufferSize))
974
+ };
975
+ }
976
+ function getDebugRuntimeConfig() {
977
+ return { ...currentConfig, traceCategories: [...currentConfig.traceCategories] };
978
+ }
979
+ function resetDebugRuntimeConfig() {
980
+ currentConfig = { ...DEFAULT_CONFIG2 };
981
+ }
982
+ function shouldCollectTraceCategory(category) {
983
+ const config = currentConfig;
984
+ if (!config.collectDebugTrace) return false;
985
+ if (!category) return true;
986
+ if (config.traceCategories.length === 0) return true;
987
+ return config.traceCategories.includes(category);
988
+ }
989
+ var NORMAL_TRACE_BUFFER_SIZE, DEV_TRACE_BUFFER_SIZE, DEFAULT_CONFIG2, currentConfig;
990
+ var init_debug_config = __esm({
991
+ "src/logging/debug-config.ts"() {
992
+ "use strict";
993
+ NORMAL_TRACE_BUFFER_SIZE = 200;
994
+ DEV_TRACE_BUFFER_SIZE = 1e3;
995
+ DEFAULT_CONFIG2 = {
996
+ logLevel: "info",
997
+ collectDebugTrace: false,
998
+ traceContent: false,
999
+ traceBufferSize: NORMAL_TRACE_BUFFER_SIZE,
1000
+ traceCategories: []
1001
+ };
1002
+ currentConfig = { ...DEFAULT_CONFIG2 };
1003
+ }
1004
+ });
1005
+
954
1006
  // src/cli-adapters/terminal-backends/ghostty-vt-backend.ts
955
1007
  function isModuleNotFoundError(error, ref) {
956
1008
  if (!(error instanceof Error)) return false;
@@ -1149,10 +1201,12 @@ function logTerminalBackendSelection(preference, ghosttyAvailable, backendKind)
1149
1201
  if (loggedTerminalBackends.has(key)) return;
1150
1202
  loggedTerminalBackends.add(key);
1151
1203
  if (backendKind === "xterm" && preference !== "xterm" && !ghosttyAvailable) {
1152
- LOG.warn(
1153
- "Terminal",
1154
- `[terminal-screen] ghostty-vt unavailable; using xterm fallback (preference=${preference})`
1155
- );
1204
+ const message = `[terminal-screen] ghostty-vt unavailable; using xterm fallback (preference=${preference})`;
1205
+ if (preference === "auto") {
1206
+ LOG.info("Terminal", message);
1207
+ } else {
1208
+ LOG.warn("Terminal", message);
1209
+ }
1156
1210
  return;
1157
1211
  }
1158
1212
  LOG.info(
@@ -1806,6 +1860,7 @@ var init_provider_cli_adapter = __esm({
1806
1860
  "src/cli-adapters/provider-cli-adapter.ts"() {
1807
1861
  "use strict";
1808
1862
  init_logger();
1863
+ init_debug_config();
1809
1864
  init_terminal_screen();
1810
1865
  init_pty_transport();
1811
1866
  init_provider_cli_shared();
@@ -1839,7 +1894,15 @@ var init_provider_cli_adapter = __esm({
1839
1894
  `[${this.cliType}] Provider resolution: providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"} source=${this.providerResolutionMeta.scriptsSource || "-"} version=${this.providerResolutionMeta.resolvedVersion || "-"}`
1840
1895
  );
1841
1896
  } else {
1842
- LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
1897
+ const resolutionSummary = `providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"} source=${this.providerResolutionMeta.scriptsSource || "-"} version=${this.providerResolutionMeta.resolvedVersion || "-"}`;
1898
+ const hasResolvedProviderScripts = Boolean(
1899
+ this.providerResolutionMeta.providerDir || this.providerResolutionMeta.scriptDir || this.providerResolutionMeta.scriptsPath || this.providerResolutionMeta.scriptsSource || this.providerResolutionMeta.resolvedVersion
1900
+ );
1901
+ if (hasResolvedProviderScripts) {
1902
+ LOG.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js (${resolutionSummary})`);
1903
+ } else {
1904
+ LOG.info("CLI", `[${this.cliType}] CLI scripts not yet resolved (${resolutionSummary})`);
1905
+ }
1843
1906
  }
1844
1907
  }
1845
1908
  cliType;
@@ -1857,6 +1920,7 @@ var init_provider_cli_adapter = __esm({
1857
1920
  recentOutputBuffer = "";
1858
1921
  isWaitingForResponse = false;
1859
1922
  activeModal = null;
1923
+ parseErrorMessage = null;
1860
1924
  responseTimeout = null;
1861
1925
  idleTimeout = null;
1862
1926
  ready = false;
@@ -1917,7 +1981,8 @@ var init_provider_cli_adapter = __esm({
1917
1981
  currentTurnScope = null;
1918
1982
  traceEntries = [];
1919
1983
  traceSeq = 0;
1920
- traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1984
+ traceSessionId = "";
1985
+ parsedStatusCache = null;
1921
1986
  static MAX_TRACE_ENTRIES = 250;
1922
1987
  providerResolutionMeta;
1923
1988
  static FINISH_RETRY_DELAY_MS = 300;
@@ -2158,7 +2223,8 @@ var init_provider_cli_adapter = __esm({
2158
2223
  this.terminalScreen.write(rawData);
2159
2224
  const cleanData = sanitizeTerminalText(rawData);
2160
2225
  const now = Date.now();
2161
- const normalizedScreenSnapshot = normalizeScreenSnapshot(this.terminalScreen.getText());
2226
+ const screenText = this.terminalScreen.getText();
2227
+ const normalizedScreenSnapshot = normalizeScreenSnapshot(screenText);
2162
2228
  this.lastOutputAt = now;
2163
2229
  if (cleanData.trim()) this.lastNonEmptyOutputAt = now;
2164
2230
  if (normalizedScreenSnapshot !== this.lastScreenSnapshot) {
@@ -2171,13 +2237,14 @@ var init_provider_cli_adapter = __esm({
2171
2237
  if (this.idleFinishCandidate && (rawData.length > 0 || cleanData.length > 0)) {
2172
2238
  this.clearIdleFinishCandidate("new_output");
2173
2239
  }
2174
- this.recordTrace("output", {
2175
- rawLength: rawData.length,
2176
- cleanLength: cleanData.length,
2177
- rawPreview: summarizeCliTraceText(rawData, 300),
2178
- cleanPreview: summarizeCliTraceText(cleanData, 300),
2179
- screenText: summarizeCliTraceText(this.terminalScreen.getText(), 1200)
2180
- });
2240
+ if (getDebugRuntimeConfig().collectDebugTrace) {
2241
+ this.recordTrace("output", {
2242
+ rawLength: rawData.length,
2243
+ cleanLength: cleanData.length,
2244
+ rawPreview: summarizeCliTraceText(rawData, 300),
2245
+ cleanPreview: summarizeCliTraceText(cleanData, 300)
2246
+ });
2247
+ }
2181
2248
  if (this.startupParseGate) {
2182
2249
  this.scheduleStartupSettleCheck();
2183
2250
  }
@@ -2851,10 +2918,12 @@ var init_provider_cli_adapter = __esm({
2851
2918
  // ─── Public API (CliAdapter) ───────────────────
2852
2919
  getStatus() {
2853
2920
  return {
2854
- status: this.currentStatus,
2921
+ status: this.parseErrorMessage ? "error" : this.currentStatus,
2855
2922
  messages: [...this.committedMessages],
2856
2923
  workingDir: this.workingDir,
2857
- activeModal: this.activeModal
2924
+ activeModal: this.activeModal,
2925
+ errorMessage: this.parseErrorMessage || void 0,
2926
+ errorReason: this.parseErrorMessage ? "parse_error" : void 0
2858
2927
  };
2859
2928
  }
2860
2929
  seedCommittedMessages(messages) {
@@ -2877,12 +2946,19 @@ var init_provider_cli_adapter = __esm({
2877
2946
  * Called by command handler / dashboard for rich content rendering.
2878
2947
  */
2879
2948
  getScriptParsedStatus() {
2949
+ const screenText = this.terminalScreen.getText();
2950
+ const cached = this.parsedStatusCache;
2951
+ if (cached && cached.committedMessagesRef === this.committedMessages && cached.responseBuffer === this.responseBuffer && cached.currentTurnScope === this.currentTurnScope && cached.recentOutputBuffer === this.recentOutputBuffer && cached.accumulatedBuffer === this.accumulatedBuffer && cached.accumulatedRawBuffer === this.accumulatedRawBuffer && cached.screenText === screenText && cached.currentStatus === this.currentStatus && cached.activeModal === this.activeModal && cached.cliName === this.cliName && cached.lastOutputAt === this.lastOutputAt) {
2952
+ return cached.result;
2953
+ }
2880
2954
  const parsed = this.parseCurrentTranscript(
2881
2955
  this.committedMessages,
2882
2956
  this.responseBuffer,
2883
- this.currentTurnScope
2957
+ this.currentTurnScope,
2958
+ screenText
2884
2959
  );
2885
2960
  const shouldPreferCommittedMessages = !this.currentTurnScope && this.currentStatus === "idle" && !this.activeModal;
2961
+ let result;
2886
2962
  if (parsed && Array.isArray(parsed.messages)) {
2887
2963
  const hydratedMessages = shouldPreferCommittedMessages ? this.committedMessages.map((message, index) => buildChatMessage({
2888
2964
  ...message,
@@ -2894,7 +2970,7 @@ var init_provider_cli_adapter = __esm({
2894
2970
  scope: this.currentTurnScope,
2895
2971
  lastOutputAt: this.lastOutputAt
2896
2972
  });
2897
- return {
2973
+ result = {
2898
2974
  id: parsed.id || "cli_session",
2899
2975
  status: parsed.status || this.currentStatus,
2900
2976
  title: parsed.title || this.cliName,
@@ -2902,20 +2978,36 @@ var init_provider_cli_adapter = __esm({
2902
2978
  activeModal: parsed.activeModal ?? this.activeModal,
2903
2979
  providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0
2904
2980
  };
2981
+ } else {
2982
+ const messages = [...this.committedMessages];
2983
+ result = {
2984
+ id: "cli_session",
2985
+ status: this.currentStatus,
2986
+ title: this.cliName,
2987
+ messages: messages.map((message, index) => buildChatMessage({
2988
+ ...message,
2989
+ id: message.id || `msg_${index}`,
2990
+ index: typeof message.index === "number" ? message.index : index,
2991
+ receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2992
+ })),
2993
+ activeModal: this.activeModal
2994
+ };
2905
2995
  }
2906
- const messages = [...this.committedMessages];
2907
- return {
2908
- id: "cli_session",
2909
- status: this.currentStatus,
2910
- title: this.cliName,
2911
- messages: messages.slice(-50).map((message, index) => buildChatMessage({
2912
- ...message,
2913
- id: message.id || `msg_${index}`,
2914
- index: typeof message.index === "number" ? message.index : index,
2915
- receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
2916
- })),
2917
- activeModal: this.activeModal
2996
+ this.parsedStatusCache = {
2997
+ committedMessagesRef: this.committedMessages,
2998
+ responseBuffer: this.responseBuffer,
2999
+ currentTurnScope: this.currentTurnScope,
3000
+ recentOutputBuffer: this.recentOutputBuffer,
3001
+ accumulatedBuffer: this.accumulatedBuffer,
3002
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
3003
+ screenText,
3004
+ currentStatus: this.currentStatus,
3005
+ activeModal: this.activeModal,
3006
+ cliName: this.cliName,
3007
+ lastOutputAt: this.lastOutputAt,
3008
+ result
2918
3009
  };
3010
+ return result;
2919
3011
  }
2920
3012
  async invokeScript(scriptName, args) {
2921
3013
  const fn = this.cliScripts?.[scriptName];
@@ -2938,14 +3030,18 @@ var init_provider_cli_adapter = __esm({
2938
3030
  args: args && typeof args === "object" ? { ...args } : {}
2939
3031
  }));
2940
3032
  }
2941
- parseCurrentTranscript(baseMessages, partialResponse, scope) {
2942
- if (!this.cliScripts?.parseOutput) return null;
3033
+ parseCurrentTranscript(baseMessages, partialResponse, scope, screenTextOverride) {
3034
+ if (!this.cliScripts?.parseOutput) {
3035
+ this.parseErrorMessage = null;
3036
+ return null;
3037
+ }
2943
3038
  try {
3039
+ const screenText = typeof screenTextOverride === "string" ? screenTextOverride : this.terminalScreen.getText();
2944
3040
  const input = buildCliParseInput({
2945
3041
  accumulatedBuffer: this.accumulatedBuffer,
2946
3042
  accumulatedRawBuffer: this.accumulatedRawBuffer,
2947
3043
  recentOutputBuffer: this.recentOutputBuffer,
2948
- terminalScreenText: this.terminalScreen.getText(),
3044
+ terminalScreenText: screenText,
2949
3045
  baseMessages,
2950
3046
  partialResponse,
2951
3047
  isWaitingForResponse: this.isWaitingForResponse,
@@ -2967,10 +3063,13 @@ var init_provider_cli_adapter = __esm({
2967
3063
  lastAssistant.content = trimPromptEchoPrefix(lastAssistant.content, promptForTrim);
2968
3064
  }
2969
3065
  }
3066
+ this.parseErrorMessage = null;
2970
3067
  return parsed;
2971
3068
  } catch (e) {
2972
- LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
2973
- return null;
3069
+ const message = e?.message || String(e);
3070
+ this.parseErrorMessage = message;
3071
+ LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${message}`);
3072
+ throw e;
2974
3073
  }
2975
3074
  }
2976
3075
  /** Whether this adapter has CLI scripts loaded */
@@ -3834,6 +3933,96 @@ function getSessionSeenMarker(state, sessionId, providerSessionId) {
3834
3933
  const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
3835
3934
  return state.sessionReadMarkers?.[providerKey] || state.sessionReadMarkers?.[sessionId] || "";
3836
3935
  }
3936
+ function getSessionNotificationDismissal(state, sessionId, providerSessionId) {
3937
+ const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
3938
+ return state.sessionNotificationDismissals?.[providerKey] || state.sessionNotificationDismissals?.[sessionId] || "";
3939
+ }
3940
+ function getSessionNotificationUnreadOverride(state, sessionId, providerSessionId) {
3941
+ const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
3942
+ return state.sessionNotificationUnreadOverrides?.[providerKey] || state.sessionNotificationUnreadOverrides?.[sessionId] || "";
3943
+ }
3944
+ function dismissSessionNotification(state, sessionId, notificationId, providerSessionId) {
3945
+ const dismissalId = String(notificationId || "").trim();
3946
+ if (!dismissalId) return state;
3947
+ const dismissalKeys = Array.from(new Set([
3948
+ sessionId,
3949
+ buildSessionReadStateKey(sessionId, providerSessionId)
3950
+ ].filter(Boolean)));
3951
+ const nextSessionNotificationDismissals = { ...state.sessionNotificationDismissals || {} };
3952
+ const nextSessionNotificationUnreadOverrides = { ...state.sessionNotificationUnreadOverrides || {} };
3953
+ for (const key of dismissalKeys) {
3954
+ nextSessionNotificationDismissals[key] = dismissalId;
3955
+ delete nextSessionNotificationUnreadOverrides[key];
3956
+ }
3957
+ return {
3958
+ ...state,
3959
+ sessionNotificationDismissals: nextSessionNotificationDismissals,
3960
+ sessionNotificationUnreadOverrides: nextSessionNotificationUnreadOverrides
3961
+ };
3962
+ }
3963
+ function markSessionNotificationUnread(state, sessionId, notificationId, providerSessionId) {
3964
+ const unreadId = String(notificationId || "").trim();
3965
+ if (!unreadId) return state;
3966
+ const unreadKeys = Array.from(new Set([
3967
+ sessionId,
3968
+ buildSessionReadStateKey(sessionId, providerSessionId)
3969
+ ].filter(Boolean)));
3970
+ const nextSessionNotificationDismissals = { ...state.sessionNotificationDismissals || {} };
3971
+ const nextSessionNotificationUnreadOverrides = { ...state.sessionNotificationUnreadOverrides || {} };
3972
+ for (const key of unreadKeys) {
3973
+ nextSessionNotificationUnreadOverrides[key] = unreadId;
3974
+ delete nextSessionNotificationDismissals[key];
3975
+ }
3976
+ return {
3977
+ ...state,
3978
+ sessionNotificationDismissals: nextSessionNotificationDismissals,
3979
+ sessionNotificationUnreadOverrides: nextSessionNotificationUnreadOverrides
3980
+ };
3981
+ }
3982
+ function getSessionNotificationTargetValue(session) {
3983
+ const providerSessionId = typeof session.providerSessionId === "string" ? session.providerSessionId.trim() : "";
3984
+ return providerSessionId || session.id;
3985
+ }
3986
+ function getSessionCurrentNotificationId(session) {
3987
+ const inboxBucket = session.inboxBucket || "idle";
3988
+ const isNeedsAttention = inboxBucket === "needs_attention" || session.status === "waiting_approval";
3989
+ const isTaskComplete = inboxBucket === "task_complete" && !!session.unread;
3990
+ const type = isNeedsAttention ? "needs_attention" : isTaskComplete ? "task_complete" : "";
3991
+ if (!type) return "";
3992
+ const target = getSessionNotificationTargetValue(session);
3993
+ const lastMessageHash = typeof session.lastMessageHash === "string" ? session.lastMessageHash : "";
3994
+ const timestamp = Number(session.lastMessageAt || session.lastUpdated || 0);
3995
+ return [type, target, lastMessageHash, String(timestamp)].join("|");
3996
+ }
3997
+ function applySessionNotificationOverlay(session, overlay) {
3998
+ const currentNotificationId = getSessionCurrentNotificationId(session);
3999
+ const taskCompleteNotificationId = (() => {
4000
+ const target = getSessionNotificationTargetValue(session);
4001
+ const lastMessageHash = typeof session.lastMessageHash === "string" ? session.lastMessageHash : "";
4002
+ const timestamp = Number(session.lastMessageAt || session.lastUpdated || 0);
4003
+ if (!target || !lastMessageHash || !timestamp) return "";
4004
+ return ["task_complete", target, lastMessageHash, String(timestamp)].join("|");
4005
+ })();
4006
+ const dismissedNotificationId = typeof overlay.dismissedNotificationId === "string" ? overlay.dismissedNotificationId.trim() : "";
4007
+ const unreadNotificationId = typeof overlay.unreadNotificationId === "string" ? overlay.unreadNotificationId.trim() : "";
4008
+ if (unreadNotificationId && (currentNotificationId === unreadNotificationId || taskCompleteNotificationId === unreadNotificationId)) {
4009
+ const forcedInboxBucket = session.inboxBucket === "needs_attention" || session.status === "waiting_approval" ? "needs_attention" : "task_complete";
4010
+ return {
4011
+ unread: true,
4012
+ inboxBucket: forcedInboxBucket
4013
+ };
4014
+ }
4015
+ if (!currentNotificationId || !dismissedNotificationId || currentNotificationId !== dismissedNotificationId) {
4016
+ return {
4017
+ unread: !!session.unread,
4018
+ inboxBucket: session.inboxBucket || "idle"
4019
+ };
4020
+ }
4021
+ return {
4022
+ unread: false,
4023
+ inboxBucket: "idle"
4024
+ };
4025
+ }
3837
4026
  function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker, providerSessionId) {
3838
4027
  const prev = state.sessionReads || {};
3839
4028
  const prevMarkers = state.sessionReadMarkers || {};
@@ -3844,14 +4033,20 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
3844
4033
  ].filter(Boolean)));
3845
4034
  const nextSessionReads = { ...prev };
3846
4035
  const nextSessionReadMarkers = { ...prevMarkers };
4036
+ const nextSessionNotificationDismissals = { ...state.sessionNotificationDismissals || {} };
4037
+ const nextSessionNotificationUnreadOverrides = { ...state.sessionNotificationUnreadOverrides || {} };
3847
4038
  for (const key of readKeys) {
3848
4039
  nextSessionReads[key] = Math.max(prev[key] || 0, seenAt);
3849
4040
  if (nextMarker) nextSessionReadMarkers[key] = nextMarker;
4041
+ delete nextSessionNotificationDismissals[key];
4042
+ delete nextSessionNotificationUnreadOverrides[key];
3850
4043
  }
3851
4044
  return {
3852
4045
  ...state,
3853
4046
  sessionReads: nextSessionReads,
3854
- sessionReadMarkers: nextMarker ? nextSessionReadMarkers : prevMarkers
4047
+ sessionReadMarkers: nextMarker ? nextSessionReadMarkers : prevMarkers,
4048
+ sessionNotificationDismissals: nextSessionNotificationDismissals,
4049
+ sessionNotificationUnreadOverrides: nextSessionNotificationUnreadOverrides
3855
4050
  };
3856
4051
  }
3857
4052
 
@@ -3936,7 +4131,9 @@ var DEFAULT_STATE = {
3936
4131
  recentActivity: [],
3937
4132
  savedProviderSessions: [],
3938
4133
  sessionReads: {},
3939
- sessionReadMarkers: {}
4134
+ sessionReadMarkers: {},
4135
+ sessionNotificationDismissals: {},
4136
+ sessionNotificationUnreadOverrides: {}
3940
4137
  };
3941
4138
  function isPlainObject2(value) {
3942
4139
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -3968,11 +4165,19 @@ function normalizeState(raw) {
3968
4165
  const sessionReadMarkers = Object.fromEntries(
3969
4166
  Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string")
3970
4167
  );
4168
+ const sessionNotificationDismissals = Object.fromEntries(
4169
+ Object.entries(isPlainObject2(parsed.sessionNotificationDismissals) ? parsed.sessionNotificationDismissals : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
4170
+ );
4171
+ const sessionNotificationUnreadOverrides = Object.fromEntries(
4172
+ Object.entries(isPlainObject2(parsed.sessionNotificationUnreadOverrides) ? parsed.sessionNotificationUnreadOverrides : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
4173
+ );
3971
4174
  return {
3972
4175
  recentActivity,
3973
4176
  savedProviderSessions,
3974
4177
  sessionReads,
3975
- sessionReadMarkers
4178
+ sessionReadMarkers,
4179
+ sessionNotificationDismissals,
4180
+ sessionNotificationUnreadOverrides
3976
4181
  };
3977
4182
  }
3978
4183
  function loadState() {
@@ -4376,9 +4581,15 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
4376
4581
  continue;
4377
4582
  }
4378
4583
  const status = String(session?.status || "").toLowerCase();
4584
+ const unread = session?.unread === true;
4585
+ const inboxBucket = String(session?.inboxBucket || "").toLowerCase();
4586
+ const runtimeSurfaceKind = String(session?.runtimeSurfaceKind || "").toLowerCase();
4587
+ const runtimeLifecycle = String(session?.runtimeLifecycle || "").toLowerCase();
4588
+ const isLiveRuntime = runtimeSurfaceKind === "live_runtime" || LIVE_RUNTIME_LIFECYCLES.has(runtimeLifecycle);
4379
4589
  const lastMessageAt = parseMessageTimestamp(session?.lastMessageAt);
4380
4590
  const recentlyUpdated = lastMessageAt > 0 && now - lastMessageAt <= recentMessageGraceMs;
4381
- if (activeStatuses.has(status) || recentlyUpdated) {
4591
+ const shouldKeepRecentTailHot = recentlyUpdated && (unread || inboxBucket === "task_complete" || inboxBucket === "needs_attention" || isLiveRuntime || activeStatuses.has(status));
4592
+ if (activeStatuses.has(status) || shouldKeepRecentTailHot) {
4382
4593
  active.add(sessionId);
4383
4594
  }
4384
4595
  }
@@ -7295,7 +7506,6 @@ var ExtensionProviderInstance = class {
7295
7506
  }
7296
7507
  pushEvent(event) {
7297
7508
  this.events.push(event);
7298
- if (this.events.length > 50) this.events = this.events.slice(-50);
7299
7509
  }
7300
7510
  applyProviderResponse(data, options) {
7301
7511
  if (!data || typeof data !== "object") return;
@@ -7371,7 +7581,6 @@ var ExtensionProviderInstance = class {
7371
7581
  key: dedupKey,
7372
7582
  message: normalizedMessage
7373
7583
  });
7374
- if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
7375
7584
  if (normalizedContent) {
7376
7585
  this.historyWriter.appendNewMessages(
7377
7586
  this.type,
@@ -7906,7 +8115,6 @@ var IdeProviderInstance = class {
7906
8115
  }
7907
8116
  pushEvent(event) {
7908
8117
  this.events.push(event);
7909
- if (this.events.length > 50) this.events = this.events.slice(-50);
7910
8118
  }
7911
8119
  applyProviderResponse(data, options) {
7912
8120
  if (!data || typeof data !== "object") return;
@@ -7996,7 +8204,6 @@ var IdeProviderInstance = class {
7996
8204
  key: dedupKey,
7997
8205
  message: normalizedMessage
7998
8206
  });
7999
- if (this.runtimeMessages.length > 50) this.runtimeMessages = this.runtimeMessages.slice(-50);
8000
8207
  if (normalizedContent) {
8001
8208
  this.historyWriter.appendNewMessages(
8002
8209
  this.type,
@@ -9014,53 +9221,8 @@ function assertProviderSupportsDeclaredInput(provider, input) {
9014
9221
  init_read_chat_contract();
9015
9222
  init_logger();
9016
9223
 
9017
- // src/logging/debug-config.ts
9018
- var NORMAL_TRACE_BUFFER_SIZE = 200;
9019
- var DEV_TRACE_BUFFER_SIZE = 1e3;
9020
- var DEFAULT_CONFIG2 = {
9021
- logLevel: "info",
9022
- collectDebugTrace: false,
9023
- traceContent: false,
9024
- traceBufferSize: NORMAL_TRACE_BUFFER_SIZE,
9025
- traceCategories: []
9026
- };
9027
- var currentConfig = { ...DEFAULT_CONFIG2 };
9028
- function normalizeCategories(categories) {
9029
- if (!Array.isArray(categories)) return [];
9030
- return categories.map((category) => String(category || "").trim()).filter(Boolean);
9031
- }
9032
- function resolveDebugRuntimeConfig(options = {}) {
9033
- const dev = options.dev === true;
9034
- return {
9035
- logLevel: options.logLevel || (dev ? "debug" : DEFAULT_CONFIG2.logLevel),
9036
- collectDebugTrace: typeof options.trace === "boolean" ? options.trace : dev,
9037
- traceContent: options.traceContent === true,
9038
- traceBufferSize: Number.isFinite(options.traceBufferSize) ? Math.max(10, Math.floor(options.traceBufferSize)) : dev ? DEV_TRACE_BUFFER_SIZE : DEFAULT_CONFIG2.traceBufferSize,
9039
- traceCategories: normalizeCategories(options.traceCategories)
9040
- };
9041
- }
9042
- function setDebugRuntimeConfig(config) {
9043
- currentConfig = {
9044
- ...config,
9045
- traceCategories: normalizeCategories(config.traceCategories),
9046
- traceBufferSize: Math.max(10, Math.floor(config.traceBufferSize || DEFAULT_CONFIG2.traceBufferSize))
9047
- };
9048
- }
9049
- function getDebugRuntimeConfig() {
9050
- return { ...currentConfig, traceCategories: [...currentConfig.traceCategories] };
9051
- }
9052
- function resetDebugRuntimeConfig() {
9053
- currentConfig = { ...DEFAULT_CONFIG2 };
9054
- }
9055
- function shouldCollectTraceCategory(category) {
9056
- const config = currentConfig;
9057
- if (!config.collectDebugTrace) return false;
9058
- if (!category) return true;
9059
- if (config.traceCategories.length === 0) return true;
9060
- return config.traceCategories.includes(category);
9061
- }
9062
-
9063
9224
  // src/logging/debug-trace.ts
9225
+ init_debug_config();
9064
9226
  function summarizeString(value) {
9065
9227
  return `[${value.length} chars]`;
9066
9228
  }
@@ -9560,7 +9722,14 @@ async function handleReadChat(h, args) {
9560
9722
  const adapter = getTargetedCliAdapter(h, args, provider?.type);
9561
9723
  if (adapter) {
9562
9724
  _log(`${transport} adapter: ${adapter.cliType}`);
9563
- const parsedStatus = typeof adapter.getScriptParsedStatus === "function" ? parseMaybeJson(adapter.getScriptParsedStatus()) : null;
9725
+ let parsedStatus = null;
9726
+ if (typeof adapter.getScriptParsedStatus === "function") {
9727
+ try {
9728
+ parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
9729
+ } catch (error) {
9730
+ return { success: false, error: error?.message || String(error) };
9731
+ }
9732
+ }
9564
9733
  const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
9565
9734
  const status = parsedRecord || adapter.getStatus();
9566
9735
  const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
@@ -11894,6 +12063,8 @@ var CliProviderInstance = class {
11894
12063
  runtimeMessages = [];
11895
12064
  instanceId;
11896
12065
  suppressIdleHistoryReplay = false;
12066
+ errorMessage = void 0;
12067
+ errorReason = void 0;
11897
12068
  presentationMode;
11898
12069
  providerSessionId;
11899
12070
  launchMode;
@@ -11960,6 +12131,7 @@ var CliProviderInstance = class {
11960
12131
  }
11961
12132
  async onTick() {
11962
12133
  if (this.providerSessionId) return;
12134
+ if (this.type === "hermes-cli" && this.launchMode === "new") return;
11963
12135
  let probedSessionId = null;
11964
12136
  const probeConfig = this.provider.sessionProbe;
11965
12137
  if (probeConfig) {
@@ -12017,9 +12189,24 @@ var CliProviderInstance = class {
12017
12189
  }
12018
12190
  getState() {
12019
12191
  const adapterStatus = this.adapter.getStatus();
12020
- const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
12192
+ let parsedStatus = null;
12193
+ let parseErrorMessage;
12194
+ if (typeof this.adapter.getScriptParsedStatus === "function") {
12195
+ try {
12196
+ parsedStatus = this.adapter.getScriptParsedStatus() || null;
12197
+ this.errorMessage = void 0;
12198
+ this.errorReason = void 0;
12199
+ } catch (error) {
12200
+ parseErrorMessage = error?.message || String(error);
12201
+ this.errorMessage = parseErrorMessage;
12202
+ this.errorReason = "parse_error";
12203
+ }
12204
+ } else {
12205
+ this.errorMessage = void 0;
12206
+ this.errorReason = void 0;
12207
+ }
12021
12208
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
12022
- const visibleStatus = autoApproveActive ? "generating" : adapterStatus.status;
12209
+ const visibleStatus = parseErrorMessage ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
12023
12210
  const parsedProviderSessionId = normalizeProviderSessionId(
12024
12211
  this.type,
12025
12212
  typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId : ""
@@ -12029,7 +12216,7 @@ var CliProviderInstance = class {
12029
12216
  }
12030
12217
  const runtime = this.adapter.getRuntimeMetadata();
12031
12218
  this.maybeAppendRuntimeRecoveryMessage(runtime);
12032
- let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
12219
+ let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : parseErrorMessage ? normalizeChatMessages(Array.isArray(adapterStatus.messages) ? adapterStatus.messages : []) : [];
12033
12220
  const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount) ? Math.max(0, Number(parsedStatus.historyMessageCount)) : null;
12034
12221
  if (historyMessageCount !== null) {
12035
12222
  parsedMessages = historyMessageCount > 0 ? parsedMessages.slice(-historyMessageCount) : [];
@@ -12069,7 +12256,7 @@ var CliProviderInstance = class {
12069
12256
  activeChat: {
12070
12257
  id: `${this.type}_${this.workingDir}`,
12071
12258
  title: parsedStatus?.title || dirName,
12072
- status: autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
12259
+ status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
12073
12260
  messages: mergedMessages,
12074
12261
  activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
12075
12262
  inputContent: ""
@@ -12095,7 +12282,9 @@ var CliProviderInstance = class {
12095
12282
  resume: this.provider.resume,
12096
12283
  controlValues: surface.controlValues,
12097
12284
  providerControls: this.provider.controls,
12098
- summaryMetadata: surface.summaryMetadata
12285
+ summaryMetadata: surface.summaryMetadata,
12286
+ errorMessage: this.errorMessage,
12287
+ errorReason: this.errorReason
12099
12288
  };
12100
12289
  }
12101
12290
  setPresentationMode(mode) {
@@ -12282,7 +12471,6 @@ var CliProviderInstance = class {
12282
12471
  }
12283
12472
  pushEvent(event) {
12284
12473
  this.events.push(event);
12285
- if (this.events.length > 50) this.events = this.events.slice(-50);
12286
12474
  }
12287
12475
  flushEvents() {
12288
12476
  const events = [...this.events];
@@ -12464,9 +12652,6 @@ ${effect.notification.body || ""}`.trim();
12464
12652
  key: dedupKey,
12465
12653
  message: normalizedMessage
12466
12654
  });
12467
- if (this.runtimeMessages.length > 50) {
12468
- this.runtimeMessages = this.runtimeMessages.slice(-50);
12469
- }
12470
12655
  if (normalizedContent) {
12471
12656
  this.historyWriter.appendNewMessages(
12472
12657
  this.type,
@@ -12720,8 +12905,8 @@ var AcpProviderInstance = class {
12720
12905
  }
12721
12906
  getState() {
12722
12907
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
12723
- const recentMessages = normalizeChatMessages(this.messages.slice(-50).map((m) => {
12724
- const content = this.truncateContent(m.content);
12908
+ const recentMessages = normalizeChatMessages(this.messages.map((m) => {
12909
+ const content = m.content;
12725
12910
  return buildChatMessage({
12726
12911
  ...m,
12727
12912
  content
@@ -13514,18 +13699,6 @@ var AcpProviderInstance = class {
13514
13699
  }
13515
13700
  }
13516
13701
  // ─── Rich Content Helpers ────────────────────────────
13517
- /** Truncate content for transport (text: 2000 chars, images preserved) */
13518
- truncateContent(content) {
13519
- if (typeof content === "string") {
13520
- return content.length > 2e3 ? content.slice(0, 2e3) + "\n... (truncated)" : content;
13521
- }
13522
- return content.map((b) => {
13523
- if (b.type === "text" && b.text.length > 2e3) {
13524
- return { ...b, text: b.text.slice(0, 2e3) + "\n... (truncated)" };
13525
- }
13526
- return b;
13527
- });
13528
- }
13529
13702
  /** Build ContentBlock[] from current partial state */
13530
13703
  buildPartialBlocks() {
13531
13704
  const blocks = [];
@@ -13679,7 +13852,6 @@ ${rawInput}` : rawInput;
13679
13852
  }
13680
13853
  pushEvent(event) {
13681
13854
  this.events.push(event);
13682
- if (this.events.length > 50) this.events = this.events.slice(-50);
13683
13855
  }
13684
13856
  appendSystemMessage(content, timestamp = Date.now()) {
13685
13857
  const normalizedContent = String(content || "").trim();
@@ -16350,7 +16522,9 @@ var SKIP_COMMANDS = /* @__PURE__ */ new Set([
16350
16522
  "heartbeat",
16351
16523
  "status_report",
16352
16524
  "read_chat",
16353
- "mark_session_seen"
16525
+ "mark_session_seen",
16526
+ "delete_notification",
16527
+ "mark_notification_unread"
16354
16528
  ]);
16355
16529
  function shouldLogCommand(cmd) {
16356
16530
  return !SKIP_COMMANDS.has(cmd);
@@ -16627,9 +16801,24 @@ function buildStatusSnapshot(options) {
16627
16801
  completionMarker,
16628
16802
  seenCompletionMarker
16629
16803
  );
16804
+ const { unread: overlayUnread, inboxBucket: overlayInboxBucket } = applySessionNotificationOverlay({
16805
+ id: sourceSession.id,
16806
+ providerSessionId: sourceSession.providerSessionId,
16807
+ status: sourceSession.status,
16808
+ unread,
16809
+ inboxBucket,
16810
+ lastMessageHash: sourceSession.lastMessageHash,
16811
+ lastMessageAt: sourceSession.lastMessageAt,
16812
+ lastUpdated: sourceSession.lastUpdated
16813
+ }, {
16814
+ dismissedNotificationId: getSessionNotificationDismissal(state, sourceSession.id, sourceSession.providerSessionId),
16815
+ unreadNotificationId: getSessionNotificationUnreadOverride(state, sourceSession.id, sourceSession.providerSessionId)
16816
+ });
16630
16817
  session.lastSeenAt = lastSeenAt;
16631
- session.unread = unread;
16632
- session.inboxBucket = inboxBucket;
16818
+ session.unread = overlayUnread;
16819
+ session.inboxBucket = overlayInboxBucket;
16820
+ session.completionMarker = completionMarker;
16821
+ session.seenCompletionMarker = seenCompletionMarker;
16633
16822
  if (READ_DEBUG_ENABLED && (session.unread || session.inboxBucket !== "idle" || session.providerType.includes("codex"))) {
16634
16823
  const recentReadSnapshot = {
16635
16824
  sessionId: session.id,
@@ -17446,6 +17635,62 @@ var DaemonCommandRouter = class {
17446
17635
  completionMarker
17447
17636
  };
17448
17637
  }
17638
+ case "delete_notification": {
17639
+ const sessionId = args?.sessionId;
17640
+ const notificationId = typeof args?.notificationId === "string" ? args.notificationId.trim() : "";
17641
+ if (!sessionId || typeof sessionId !== "string") {
17642
+ return { success: false, error: "sessionId is required" };
17643
+ }
17644
+ if (!notificationId) {
17645
+ return { success: false, error: "notificationId is required" };
17646
+ }
17647
+ const sessionEntries = buildSessionEntries(
17648
+ this.deps.instanceManager.collectAllStates(),
17649
+ this.deps.cdpManagers
17650
+ );
17651
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
17652
+ const next = dismissSessionNotification(
17653
+ loadState(),
17654
+ sessionId,
17655
+ notificationId,
17656
+ targetSession?.providerSessionId
17657
+ );
17658
+ saveState(next);
17659
+ this.deps.onStatusChange?.();
17660
+ return {
17661
+ success: true,
17662
+ sessionId,
17663
+ notificationId
17664
+ };
17665
+ }
17666
+ case "mark_notification_unread": {
17667
+ const sessionId = args?.sessionId;
17668
+ const notificationId = typeof args?.notificationId === "string" ? args.notificationId.trim() : "";
17669
+ if (!sessionId || typeof sessionId !== "string") {
17670
+ return { success: false, error: "sessionId is required" };
17671
+ }
17672
+ if (!notificationId) {
17673
+ return { success: false, error: "notificationId is required" };
17674
+ }
17675
+ const sessionEntries = buildSessionEntries(
17676
+ this.deps.instanceManager.collectAllStates(),
17677
+ this.deps.cdpManagers
17678
+ );
17679
+ const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
17680
+ const next = markSessionNotificationUnread(
17681
+ loadState(),
17682
+ sessionId,
17683
+ notificationId,
17684
+ targetSession?.providerSessionId
17685
+ );
17686
+ saveState(next);
17687
+ this.deps.onStatusChange?.();
17688
+ return {
17689
+ success: true,
17690
+ sessionId,
17691
+ notificationId
17692
+ };
17693
+ }
17449
17694
  // ─── Daemon Self-Upgrade ───
17450
17695
  case "daemon_upgrade": {
17451
17696
  LOG.info("Upgrade", "Remote upgrade requested from dashboard");
@@ -17824,6 +18069,7 @@ var DaemonStatusReporter = class {
17824
18069
 
17825
18070
  // src/index.ts
17826
18071
  init_logger();
18072
+ init_debug_config();
17827
18073
 
17828
18074
  // src/ipc-protocol.ts
17829
18075
  var DEFAULT_DAEMON_PORT = 19222;