chatroom-cli 1.103.0 → 1.103.1

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
@@ -81229,6 +81229,14 @@ var init_cursor_sdk_config = __esm(() => {
81229
81229
  outputActivity: true,
81230
81230
  processExited: true
81231
81231
  },
81232
+ crashRecovery: {
81233
+ onSessionFailure: {
81234
+ maxAttempts: 6,
81235
+ intervalMs: 1e4,
81236
+ resumeFirstAttempts: 3,
81237
+ recoveryReason: "platform.cursor_sdk_session_reopen"
81238
+ }
81239
+ },
81232
81240
  wireEvents: ["sdk.cursor.message", "sdk.cursor.run.completed", "wire.log.agent_end"]
81233
81241
  };
81234
81242
  });
@@ -103006,6 +103014,25 @@ function resolveResumableHarnessSessionId(snapshot) {
103006
103014
  return snapshot.resumableHarnessSessionId ?? snapshot.harnessSessionId;
103007
103015
  }
103008
103016
 
103017
+ // src/daemon/domain/entities/session-recovery-policy.ts
103018
+ function resolveSessionRecoveryPolicy(harness, classification2) {
103019
+ const caps = getHarnessCapabilities(harness);
103020
+ if (classification2.hadSessionFailure && caps.crashRecovery?.onSessionFailure) {
103021
+ return caps.crashRecovery.onSessionFailure;
103022
+ }
103023
+ return DEFAULT_CRASH_RECOVERY_POLICY;
103024
+ }
103025
+ var DEFAULT_CRASH_RECOVERY_POLICY;
103026
+ var init_session_recovery_policy = __esm(() => {
103027
+ init_types();
103028
+ DEFAULT_CRASH_RECOVERY_POLICY = {
103029
+ maxAttempts: 1,
103030
+ intervalMs: 0,
103031
+ resumeFirstAttempts: 0,
103032
+ recoveryReason: "platform.crash_recovery"
103033
+ };
103034
+ });
103035
+
103009
103036
  // src/daemon/domain/usecase/classify-resume-storm-reason.ts
103010
103037
  function classifyResumeStormReason(logLines) {
103011
103038
  const blob = logLines.join(`
@@ -103114,18 +103141,6 @@ function appendRecentLogLine(slot, line) {
103114
103141
  }
103115
103142
  var RECENT_LOG_LINE_CAP2 = 100;
103116
103143
 
103117
- // src/daemon/domain/usecase/cursor-sdk-session-reopen-retry.ts
103118
- var CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS = 20, CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS = 5000, CURSOR_SDK_SESSION_REOPEN_REASON = "platform.cursor_sdk_session_reopen", CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS = 3;
103119
-
103120
- // src/daemon/domain/usecase/detect-cursor-sdk-run-error.ts
103121
- function isCursorSdkRunErrorInLogs(logLines) {
103122
- return logLines.some((line) => line.includes(" run-error]"));
103123
- }
103124
- function formatCursorSdkRunErrorMessage(logLines) {
103125
- const line = [...logLines].reverse().find((l) => l.includes(" run-error]"));
103126
- return line?.trim() ?? "Cursor SDK run failed";
103127
- }
103128
-
103129
103144
  // src/daemon/domain/usecase/handle-turn-completed.ts
103130
103145
  async function handleTurnCompleted(deps, input, slot) {
103131
103146
  if (await tryAbortResumeStorm(deps, input, slot)) {
@@ -103262,6 +103277,19 @@ var init_native_spawn_presence = __esm(() => {
103262
103277
  init_execution_kind();
103263
103278
  });
103264
103279
 
103280
+ // src/daemon/infrastructure/local/harness/session-monitors/no-op-session-monitor.ts
103281
+ var NO_FAILURE, noOpSessionMonitor;
103282
+ var init_no_op_session_monitor = __esm(() => {
103283
+ NO_FAILURE = {
103284
+ hadSessionFailure: false,
103285
+ failureKind: "none",
103286
+ recoverable: true
103287
+ };
103288
+ noOpSessionMonitor = {
103289
+ classifyExitFailure: () => NO_FAILURE
103290
+ };
103291
+ });
103292
+
103265
103293
  // src/daemon/infrastructure/agent-process-manager/agent-process-manager.ts
103266
103294
  function agentKey3(chatroomId, role) {
103267
103295
  return `${chatroomId}:${role.toLowerCase()}`;
@@ -103271,7 +103299,7 @@ class AgentProcessManager {
103271
103299
  deps;
103272
103300
  slots = new Map;
103273
103301
  lastHarnessSessions = new Map;
103274
- sessionReopenRetryInFlight = new Set;
103302
+ sessionRecoveryRetryInFlight = new Set;
103275
103303
  exitRetryQueue = [];
103276
103304
  exitRetryTimer = null;
103277
103305
  turnEndQueue = new TurnEndQueue;
@@ -103689,12 +103717,12 @@ class AgentProcessManager {
103689
103717
  });
103690
103718
  }));
103691
103719
  this.resetSlotAfterExit(slot);
103692
- await this.emitExitEvent(slot, opts, ctx);
103720
+ const exitLifecyclePromise = this.emitExitEvent(slot, opts, ctx);
103693
103721
  try {
103694
103722
  await this.deps.persistence.clearAgentPid(this.deps.machineId, opts.chatroomId, opts.role);
103695
103723
  } catch {}
103696
103724
  this.untrackAllServices(opts.pid);
103697
- lifecyclePromise.then(() => this.dispatchRestartAfterExit(opts, ctx, key)).catch(() => {});
103725
+ lifecyclePromise.then(() => this.dispatchRestartAfterExit(opts, ctx, key, exitLifecyclePromise)).catch(() => {});
103698
103726
  }
103699
103727
  captureExitContext(slot, opts, stopReason) {
103700
103728
  return {
@@ -103742,7 +103770,7 @@ class AgentProcessManager {
103742
103770
  slot.pendingOperation = undefined;
103743
103771
  slot.nativeTurnPhase = undefined;
103744
103772
  }
103745
- async emitExitEvent(slot, opts, ctx) {
103773
+ emitExitEvent(slot, opts, ctx) {
103746
103774
  const stopReason = ctx.stopReason;
103747
103775
  const exitArgs = {
103748
103776
  sessionId: this.deps.sessionId,
@@ -103756,14 +103784,14 @@ class AgentProcessManager {
103756
103784
  signal: opts.signal ?? undefined,
103757
103785
  agentHarness: ctx.harness
103758
103786
  };
103759
- this.recordAgentExit(opts.role, exitArgs, "Failed to record agent exit event");
103787
+ return this.recordAgentExit(opts.role, exitArgs, "Failed to record agent exit event");
103760
103788
  }
103761
103789
  untrackAllServices(pid) {
103762
103790
  for (const service3 of this.deps.agentServices.values()) {
103763
103791
  service3.untrack(pid);
103764
103792
  }
103765
103793
  }
103766
- dispatchRestartAfterExit(opts, ctx, _key) {
103794
+ dispatchRestartAfterExit(opts, ctx, _key, exitLifecyclePromise) {
103767
103795
  if (this.isStopRequested(opts.chatroomId, opts.role)) {
103768
103796
  return;
103769
103797
  }
@@ -103774,14 +103802,123 @@ class AgentProcessManager {
103774
103802
  }
103775
103803
  return;
103776
103804
  }
103777
- this.maybeRestartAgent(opts, ctx);
103805
+ this.maybeRestartAgent(opts, ctx, exitLifecyclePromise);
103778
103806
  }
103779
- hasCursorSdkRunErrorInContext(recentLogLines) {
103780
- if (!isCursorSdkRunErrorInLogs(recentLogLines)) {
103781
- return false;
103807
+ maybeRestartAgent(opts, ctx, exitLifecyclePromise) {
103808
+ const { harness, recentLogLines } = ctx;
103809
+ const logs = recentLogLines ?? [];
103810
+ if (!harness || !ctx.workingDir) {
103811
+ console.log(`[AgentProcessManager] ⚠️ Cannot restart — missing harness or workingDir ` + `(role: ${opts.role}, harness: ${harness ?? "none"}, workingDir: ${ctx.workingDir ?? "none"})`);
103812
+ return;
103782
103813
  }
103783
- console.log(`[AgentProcessManager] cursor-sdk run-error detected: ${formatCursorSdkRunErrorMessage(recentLogLines)}`);
103784
- return true;
103814
+ const monitor = this.deps.sessionMonitors.get(harness) ?? noOpSessionMonitor;
103815
+ const monitorCtx = {
103816
+ recentLogLines: logs,
103817
+ harness,
103818
+ wantResume: ctx.wantResume
103819
+ };
103820
+ const classification2 = monitor.classifyExitFailure(monitorCtx);
103821
+ this.retrySessionRecovery(opts, ctx, classification2, monitor, monitorCtx, exitLifecyclePromise);
103822
+ }
103823
+ async retrySessionRecovery(opts, ctx, classification2, monitor, monitorCtx, exitLifecyclePromise) {
103824
+ const harness = ctx.harness;
103825
+ const policy = resolveSessionRecoveryPolicy(harness, classification2);
103826
+ const key = agentKey3(opts.chatroomId, opts.role);
103827
+ const multiAttempt = policy.maxAttempts > 1;
103828
+ if (multiAttempt && this.sessionRecoveryRetryInFlight.has(key)) {
103829
+ return;
103830
+ }
103831
+ if (multiAttempt) {
103832
+ this.sessionRecoveryRetryInFlight.add(key);
103833
+ }
103834
+ try {
103835
+ await this.prepareSessionRecoveryBeforeRetry(opts, classification2, exitLifecyclePromise);
103836
+ const lastError = await this.runSessionRecoveryAttempts(opts, ctx, classification2, monitor, monitorCtx, policy, key, multiAttempt);
103837
+ if (lastError === null)
103838
+ return;
103839
+ if (multiAttempt) {
103840
+ const failureMessage = `${harness} session recovery failed after ${policy.maxAttempts} attempts: ${lastError}`;
103841
+ console.log(`[AgentProcessManager] ⛔ ${failureMessage}`);
103842
+ this.emitStartFailedEvent(opts.role, opts.chatroomId, failureMessage);
103843
+ } else {
103844
+ console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${opts.role}: ${lastError}`);
103845
+ }
103846
+ } catch (err) {
103847
+ const message = err instanceof Error ? err.message : String(err);
103848
+ console.log(` ⚠️ Session recovery retry loop failed: ${message}`);
103849
+ this.emitStartFailedEvent(opts.role, opts.chatroomId, message);
103850
+ } finally {
103851
+ if (multiAttempt) {
103852
+ this.sessionRecoveryRetryInFlight.delete(key);
103853
+ }
103854
+ }
103855
+ }
103856
+ async prepareSessionRecoveryBeforeRetry(opts, classification2, exitLifecyclePromise) {
103857
+ if (!classification2.requiresTaskReleaseBeforeRecovery)
103858
+ return;
103859
+ this.clearLastInFlightTask(opts.chatroomId, opts.role);
103860
+ if (exitLifecyclePromise) {
103861
+ await exitLifecyclePromise;
103862
+ }
103863
+ }
103864
+ async runSessionRecoveryAttempts(opts, ctx, classification2, monitor, monitorCtx, policy, key, multiAttempt) {
103865
+ const generation = this.slots.get(key)?.stopGeneration;
103866
+ let lastError = "unknown";
103867
+ for (let attempt = 1;attempt <= policy.maxAttempts; attempt++) {
103868
+ if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103869
+ return null;
103870
+ if (classification2.hadSessionFailure && policy.resumeFirstAttempts > 0 && attempt === policy.resumeFirstAttempts + 1) {
103871
+ this.clearHarnessSessionAfterResumePhaseFailure(key, opts);
103872
+ }
103873
+ const wantResume = monitor.resolveWantResume?.(attempt, classification2, monitorCtx) ?? (classification2.hadSessionFailure ? false : ctx.wantResume ?? true);
103874
+ if (multiAttempt) {
103875
+ const stored = this.lastHarnessSessions.get(key);
103876
+ const storedSessionId = stored ? resolveResumableHarnessSessionId(stored) : undefined;
103877
+ await this.emitSessionReopenRetry(opts.chatroomId, opts.role, attempt, policy.maxAttempts, attempt > 1 ? lastError : undefined, storedSessionId);
103878
+ if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103879
+ return null;
103880
+ }
103881
+ const attemptResult = await this.executeSessionRecoveryAttempt(opts, ctx, policy, wantResume, multiAttempt, generation);
103882
+ if (attemptResult.kind === "success" || attemptResult.kind === "stopped")
103883
+ return null;
103884
+ if (attemptResult.kind === "crash_loop")
103885
+ return null;
103886
+ lastError = attemptResult.lastError;
103887
+ if (attempt < policy.maxAttempts && policy.intervalMs > 0) {
103888
+ await this.deps.clock.delay(policy.intervalMs);
103889
+ if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103890
+ return null;
103891
+ }
103892
+ }
103893
+ return lastError;
103894
+ }
103895
+ async executeSessionRecoveryAttempt(opts, ctx, policy, wantResume, multiAttempt, generation) {
103896
+ const harness = ctx.harness;
103897
+ const ensureOpts = {
103898
+ chatroomId: opts.chatroomId,
103899
+ role: opts.role,
103900
+ agentHarness: harness,
103901
+ model: ctx.model,
103902
+ workingDir: ctx.workingDir,
103903
+ reason: policy.recoveryReason,
103904
+ wantResume
103905
+ };
103906
+ const result = await this.ensureRunning(ensureOpts);
103907
+ if (result.success)
103908
+ return { kind: "success" };
103909
+ if (this.isStopRequested(opts.chatroomId, opts.role, generation)) {
103910
+ return { kind: "stopped" };
103911
+ }
103912
+ const error51 = result.error ?? "unknown";
103913
+ if (!multiAttempt && result.error === "backoff") {
103914
+ await this.retryCrashRecoveryAfterBackoff(opts, ctx, ensureOpts, result.retryAfterMs);
103915
+ return { kind: "success" };
103916
+ }
103917
+ if (result.error === "crash_loop") {
103918
+ this.handleCrashLoopLimitReached(opts, ctx.recentLogLines);
103919
+ return { kind: "crash_loop" };
103920
+ }
103921
+ return { kind: "failed", lastError: error51 };
103785
103922
  }
103786
103923
  maybeEmitProviderUnavailable(chatroomId, role, slot) {
103787
103924
  if (!slot || slot.harness !== "codex-sdk" || slot.providerUnavailableEmitted)
@@ -103813,48 +103950,6 @@ class AgentProcessManager {
103813
103950
  recoverable: providerUnavailableRecoverable(classification2.reason)
103814
103951
  }).catch(() => {});
103815
103952
  }
103816
- maybeRestartAgent(opts, ctx) {
103817
- const { harness, model, workingDir, recentLogLines } = ctx;
103818
- const logs = recentLogLines ?? [];
103819
- if (!harness || !workingDir) {
103820
- console.log(`[AgentProcessManager] ⚠️ Cannot restart — missing harness or workingDir ` + `(role: ${opts.role}, harness: ${harness ?? "none"}, workingDir: ${workingDir ?? "none"})`);
103821
- return;
103822
- }
103823
- const hadRunError = this.hasCursorSdkRunErrorInContext(logs);
103824
- if (harness === "cursor-sdk") {
103825
- this.retryCursorSdkSessionReopen(opts, ctx, hadRunError);
103826
- return;
103827
- }
103828
- this.attemptCrashRecoveryRestart(opts, ctx, {
103829
- chatroomId: opts.chatroomId,
103830
- role: opts.role,
103831
- agentHarness: harness,
103832
- model,
103833
- workingDir,
103834
- reason: "platform.crash_recovery",
103835
- wantResume: hadRunError ? false : ctx.wantResume ?? true
103836
- });
103837
- }
103838
- async attemptCrashRecoveryRestart(exitOpts, ctx, ensureOpts) {
103839
- try {
103840
- const result = await this.ensureRunning(ensureOpts);
103841
- if (result.success)
103842
- return;
103843
- if (result.error === "backoff") {
103844
- await this.retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, result.retryAfterMs);
103845
- return;
103846
- }
103847
- if (result.error === "crash_loop") {
103848
- this.handleCrashLoopLimitReached(exitOpts, ctx.recentLogLines);
103849
- return;
103850
- }
103851
- console.log(`[AgentProcessManager] ⚠️ Agent restart did not complete for ${exitOpts.role}: ${result.error ?? "unknown"}`);
103852
- } catch (err) {
103853
- const message = err instanceof Error ? err.message : String(err);
103854
- console.log(` ⚠️ Failed to restart agent: ${message}`);
103855
- this.emitStartFailedEvent(exitOpts.role, exitOpts.chatroomId, message);
103856
- }
103857
- }
103858
103953
  async retryCrashRecoveryAfterBackoff(exitOpts, ctx, ensureOpts, retryAfterMs) {
103859
103954
  if (retryAfterMs === undefined || retryAfterMs <= 0) {
103860
103955
  return;
@@ -103892,71 +103987,6 @@ class AgentProcessManager {
103892
103987
  });
103893
103988
  }
103894
103989
  }
103895
- resolveCursorSdkReopenWantResume(hadRunError, attempt, ctx) {
103896
- if (hadRunError && attempt <= CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS) {
103897
- return true;
103898
- }
103899
- if (hadRunError) {
103900
- return false;
103901
- }
103902
- return ctx.wantResume ?? true;
103903
- }
103904
- async retryCursorSdkSessionReopen(opts, ctx, hadRunError) {
103905
- const key = agentKey3(opts.chatroomId, opts.role);
103906
- if (this.sessionReopenRetryInFlight.has(key)) {
103907
- return;
103908
- }
103909
- this.sessionReopenRetryInFlight.add(key);
103910
- const generation = this.slots.get(key)?.stopGeneration;
103911
- const harness = ctx.harness;
103912
- const model = ctx.model;
103913
- const workingDir = ctx.workingDir;
103914
- let lastError = "unknown";
103915
- try {
103916
- for (let attempt = 1;attempt <= CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS; attempt++) {
103917
- if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103918
- return;
103919
- if (hadRunError && attempt === CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS + 1) {
103920
- this.clearHarnessSessionAfterResumePhaseFailure(key, opts);
103921
- }
103922
- const wantResume = this.resolveCursorSdkReopenWantResume(hadRunError, attempt, ctx);
103923
- const stored = this.lastHarnessSessions.get(key);
103924
- const storedSessionId = stored ? resolveResumableHarnessSessionId(stored) : undefined;
103925
- await this.emitSessionReopenRetry(opts.chatroomId, opts.role, attempt, attempt > 1 ? lastError : undefined, storedSessionId);
103926
- if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103927
- return;
103928
- const result = await this.ensureRunning({
103929
- chatroomId: opts.chatroomId,
103930
- role: opts.role,
103931
- agentHarness: harness,
103932
- model,
103933
- workingDir,
103934
- reason: CURSOR_SDK_SESSION_REOPEN_REASON,
103935
- wantResume
103936
- });
103937
- if (result.success) {
103938
- return;
103939
- }
103940
- if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103941
- return;
103942
- lastError = result.error ?? "unknown";
103943
- if (attempt < CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS) {
103944
- await this.deps.clock.delay(CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS);
103945
- if (this.isStopRequested(opts.chatroomId, opts.role, generation))
103946
- return;
103947
- }
103948
- }
103949
- const failureMessage = `cursor-sdk session reopen failed after ${CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS} attempts: ${lastError}`;
103950
- console.log(`[AgentProcessManager] ⛔ ${failureMessage}`);
103951
- this.emitStartFailedEvent(opts.role, opts.chatroomId, failureMessage);
103952
- } catch (err) {
103953
- const message = err instanceof Error ? err.message : String(err);
103954
- console.log(` ⚠️ cursor-sdk session reopen retry loop failed: ${message}`);
103955
- this.emitStartFailedEvent(opts.role, opts.chatroomId, message);
103956
- } finally {
103957
- this.sessionReopenRetryInFlight.delete(key);
103958
- }
103959
- }
103960
103990
  emitStartFailedEvent(role, chatroomId, error51) {
103961
103991
  logDaemonAuditEvent(this.deps.logEvent, {
103962
103992
  type: "agent.startFailed",
@@ -104166,7 +104196,11 @@ class AgentProcessManager {
104166
104196
  this.queueExitRetry({ role, args: exitArgs });
104167
104197
  });
104168
104198
  const emittedAt = this.deps.clock.now();
104169
- this.deps.lifecycleOutbox.enqueue(buildExitedLifecycleFact(exitArgs, emittedAt)).catch((err) => console.log(` ⚠️ Failed to enqueue agent exited lifecycle fact: ${err.message}`));
104199
+ return this.deps.lifecycleOutbox.enqueue(buildExitedLifecycleFact(exitArgs, emittedAt)).then(() => {
104200
+ return;
104201
+ }).catch((err) => {
104202
+ console.log(` ⚠️ Failed to enqueue agent exited lifecycle fact: ${err.message}`);
104203
+ });
104170
104204
  }
104171
104205
  async clearAgentPidQuietly(chatroomId, role) {
104172
104206
  try {
@@ -104344,7 +104378,7 @@ class AgentProcessManager {
104344
104378
  console.log(` ⚠️ Failed to emit sessionResumeFailed event: ${err.message}`);
104345
104379
  }
104346
104380
  }
104347
- async emitSessionReopenRetry(chatroomId, role, attempt, error51, harnessSessionId) {
104381
+ async emitSessionReopenRetry(chatroomId, role, attempt, maxAttempts, error51, harnessSessionId) {
104348
104382
  try {
104349
104383
  await logDaemonAuditEvent(this.deps.logEvent, {
104350
104384
  type: "agent.sessionReopenRetry",
@@ -104352,7 +104386,7 @@ class AgentProcessManager {
104352
104386
  role,
104353
104387
  machineId: this.deps.machineId,
104354
104388
  attempt,
104355
- maxAttempts: CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS,
104389
+ maxAttempts,
104356
104390
  ...error51 ? { error: error51 } : {},
104357
104391
  ...harnessSessionId ? { harnessSessionId } : {}
104358
104392
  });
@@ -104362,11 +104396,11 @@ class AgentProcessManager {
104362
104396
  chatroomId,
104363
104397
  role,
104364
104398
  attempt,
104365
- maxAttempts: CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS,
104399
+ maxAttempts,
104366
104400
  ...error51 ? { error: error51 } : {},
104367
104401
  ...harnessSessionId ? { harnessSessionId } : {}
104368
104402
  });
104369
- console.log(`[AgentProcessManager] ✅ Emitted agent.sessionReopenRetry for ${role} (attempt ${attempt}/${CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS})`);
104403
+ console.log(`[AgentProcessManager] ✅ Emitted agent.sessionReopenRetry for ${role} (attempt ${attempt}/${maxAttempts})`);
104370
104404
  } catch (err) {
104371
104405
  console.log(` ⚠️ Failed to emit sessionReopenRetry event: ${err.message}`);
104372
104406
  }
@@ -104945,6 +104979,7 @@ var init_agent_process_manager = __esm(() => {
104945
104979
  init_agent_lifecycle_runtime();
104946
104980
  init_agent_lifecycle_types();
104947
104981
  init_agent_stop();
104982
+ init_session_recovery_policy();
104948
104983
  init_spawn_policy();
104949
104984
  init_abort_resume_storm();
104950
104985
  init_classify_provider_error();
@@ -104956,6 +104991,99 @@ var init_agent_process_manager = __esm(() => {
104956
104991
  init_native_task_delivery_coordinator();
104957
104992
  init_native_turn_phase2();
104958
104993
  init_native_spawn_presence();
104994
+ init_no_op_session_monitor();
104995
+ });
104996
+
104997
+ // src/daemon/domain/usecase/cursor-sdk-session-reopen-retry.ts
104998
+ var CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS = 3;
104999
+
105000
+ // src/daemon/domain/usecase/detect-cursor-sdk-run-error.ts
105001
+ function isCursorSdkRunErrorInLogs(logLines) {
105002
+ return logLines.some((line) => line.includes(" run-error]"));
105003
+ }
105004
+ function formatCursorSdkRunErrorMessage(logLines) {
105005
+ const line = [...logLines].reverse().find((l) => l.includes(" run-error]"));
105006
+ return line?.trim() ?? "Cursor SDK run failed";
105007
+ }
105008
+ function isCursorSdkAuthErrorInLogs(logLines) {
105009
+ if (classifyResumeStormReason(logLines) !== "auth_error")
105010
+ return false;
105011
+ return logLines.some((line) => line.includes("[cursor-sdk:"));
105012
+ }
105013
+ function hasCursorSdkSessionReopenTrigger(logLines) {
105014
+ return isCursorSdkRunErrorInLogs(logLines) || isCursorSdkAuthErrorInLogs(logLines);
105015
+ }
105016
+ var init_detect_cursor_sdk_run_error = __esm(() => {
105017
+ init_classify_resume_storm_reason();
105018
+ });
105019
+
105020
+ // src/daemon/infrastructure/local/harness/session-monitors/cursor-sdk-session-monitor.ts
105021
+ var cursorSdkSessionMonitor;
105022
+ var init_cursor_sdk_session_monitor = __esm(() => {
105023
+ init_detect_cursor_sdk_run_error();
105024
+ cursorSdkSessionMonitor = {
105025
+ classifyExitFailure(ctx) {
105026
+ const logs = ctx.recentLogLines;
105027
+ if (!hasCursorSdkSessionReopenTrigger(logs)) {
105028
+ return { hadSessionFailure: false, failureKind: "none", recoverable: true };
105029
+ }
105030
+ const auth = isCursorSdkAuthErrorInLogs(logs);
105031
+ console.log(`[CursorSdkSessionMonitor] session failure detected: ${formatCursorSdkRunErrorMessage(logs)}`);
105032
+ return {
105033
+ hadSessionFailure: true,
105034
+ failureKind: auth ? "auth_error" : "run_error",
105035
+ recoverable: true,
105036
+ requiresTaskReleaseBeforeRecovery: auth
105037
+ };
105038
+ },
105039
+ resolveWantResume(attempt, classification2, ctx) {
105040
+ if (classification2.hadSessionFailure && attempt <= CURSOR_SDK_SESSION_RESUME_FIRST_ATTEMPTS) {
105041
+ return true;
105042
+ }
105043
+ if (classification2.hadSessionFailure) {
105044
+ return false;
105045
+ }
105046
+ return ctx.wantResume ?? true;
105047
+ }
105048
+ };
105049
+ });
105050
+
105051
+ // src/daemon/infrastructure/local/harness/session-monitors/session-monitor-registry.ts
105052
+ function registerSessionMonitor(harnessId, monitor) {
105053
+ registry3.set(harnessId, monitor);
105054
+ }
105055
+ function getSessionMonitor(harnessId) {
105056
+ return registry3.get(harnessId);
105057
+ }
105058
+ function getAllSessionMonitors() {
105059
+ return new Map(registry3);
105060
+ }
105061
+ var registry3;
105062
+ var init_session_monitor_registry = __esm(() => {
105063
+ registry3 = new Map;
105064
+ });
105065
+
105066
+ // src/daemon/infrastructure/local/harness/session-monitors/init-session-monitors.ts
105067
+ function initSessionMonitorRegistry() {
105068
+ if (initialized2)
105069
+ return;
105070
+ for (const harness of AGENT_HARNESSES) {
105071
+ registerSessionMonitor(harness, harness === "cursor-sdk" ? cursorSdkSessionMonitor : noOpSessionMonitor);
105072
+ }
105073
+ for (const service3 of getAllHarnesses()) {
105074
+ if (!getSessionMonitor(service3.id)) {
105075
+ registerSessionMonitor(service3.id, noOpSessionMonitor);
105076
+ }
105077
+ }
105078
+ initialized2 = true;
105079
+ }
105080
+ var initialized2 = false;
105081
+ var init_init_session_monitors = __esm(() => {
105082
+ init_agent2();
105083
+ init_cursor_sdk_session_monitor();
105084
+ init_no_op_session_monitor();
105085
+ init_session_monitor_registry();
105086
+ init_registry2();
104959
105087
  });
104960
105088
 
104961
105089
  // src/daemon/entry/init-daemon.ts
@@ -105019,6 +105147,7 @@ function assembleDaemonSessionInit(args2) {
105019
105147
  config: config4,
105020
105148
  convexUrl,
105021
105149
  agentServices,
105150
+ sessionMonitors,
105022
105151
  cachedModels,
105023
105152
  deps
105024
105153
  } = args2;
@@ -105035,6 +105164,7 @@ function assembleDaemonSessionInit(args2) {
105035
105164
  }),
105036
105165
  logSink: activeLogSink,
105037
105166
  agentServices,
105167
+ sessionMonitors,
105038
105168
  backend: deps.backend,
105039
105169
  sessionId: typedSessionId,
105040
105170
  machineId,
@@ -105216,11 +105346,13 @@ Run: ${formatAuthLoginCommand(convexUrl)}`);
105216
105346
  const config4 = yield* setupMachineEffect();
105217
105347
  const { machineId } = config4;
105218
105348
  initHarnessRegistry();
105349
+ initSessionMonitorRegistry();
105219
105350
  const agentServices = new Map(getAllHarnesses().map((s) => [s.id, s]));
105351
+ const sessionMonitors = getAllSessionMonitors();
105220
105352
  yield* registerMachineEffect(client4, typedSessionId, config4);
105221
105353
  const cachedModels = yield* fetchCachedMachineModelsEffect(client4, typedSessionId, machineId);
105222
105354
  yield* connectDaemonEffect(client4, typedSessionId, machineId);
105223
- return { typedSessionId, config: config4, machineId, agentServices, cachedModels };
105355
+ return { typedSessionId, config: config4, machineId, agentServices, sessionMonitors, cachedModels };
105224
105356
  }), activeLogSink, activeLogEvent, connectDaemonEffect = (client4, sessionId, machineId) => exports_Effect.tryPromise({
105225
105357
  try: () => client4.mutation(api.machines.updateDaemonStatus, {
105226
105358
  sessionId: asConvexSessionId(sessionId),
@@ -105308,6 +105440,8 @@ var init_init_daemon = __esm(() => {
105308
105440
  init_agent_process_manager();
105309
105441
  init_registry3();
105310
105442
  init_services2();
105443
+ init_init_session_monitors();
105444
+ init_session_monitor_registry();
105311
105445
  AUTH_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
105312
105446
  initDaemonEffect = exports_Effect.gen(function* () {
105313
105447
  const lockAcquired = yield* exports_Effect.tryPromise({
@@ -105337,7 +105471,7 @@ var init_init_daemon = __esm(() => {
105337
105471
  try: () => getConvexClient(),
105338
105472
  catch: (e) => e
105339
105473
  });
105340
- const { typedSessionId, config: config4, machineId, agentServices, cachedModels } = yield* connectWithRetryEffect(client4, sessionId, convexUrl);
105474
+ const { typedSessionId, config: config4, machineId, agentServices, sessionMonitors, cachedModels } = yield* connectWithRetryEffect(client4, sessionId, convexUrl);
105341
105475
  const init2 = assembleDaemonSessionInit({
105342
105476
  client: client4,
105343
105477
  typedSessionId,
@@ -105345,6 +105479,7 @@ var init_init_daemon = __esm(() => {
105345
105479
  config: config4,
105346
105480
  convexUrl,
105347
105481
  agentServices,
105482
+ sessionMonitors,
105348
105483
  cachedModels,
105349
105484
  deps: createDefaultDeps22()
105350
105485
  });
@@ -134957,4 +135092,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
134957
135092
  });
134958
135093
  program2.parse();
134959
135094
 
134960
- //# debugId=1C27BCC36565FE7A64756E2164756E21
135095
+ //# debugId=48E3BD8E7ACDCBFA64756E2164756E21