chatroom-cli 1.103.0 → 1.103.2

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 (3) hide show
  1. package/dist/index.js +341 -167
  2. package/dist/index.js.map +218 -213
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -30445,8 +30445,8 @@ var init_claude_sdk_agent_service = __esm(() => {
30445
30445
  maxTurns: DEFAULT_MAX_TURNS2,
30446
30446
  pathToClaudeCodeExecutable: executablePath,
30447
30447
  includePartialMessages: true,
30448
- systemPrompt: isFirstQuery && !sdkSession.resumeOnFirstQuery ? sdkSession.storedSystemPrompt : undefined,
30449
- resume: useResume ? sdkSession.sessionId : undefined,
30448
+ ...isFirstQuery && !sdkSession.resumeOnFirstQuery && sdkSession.storedSystemPrompt !== undefined ? { systemPrompt: sdkSession.storedSystemPrompt } : {},
30449
+ ...useResume && sdkSession.sessionId !== undefined ? { resume: sdkSession.sessionId } : {},
30450
30450
  settingSources: [],
30451
30451
  permissionMode: "bypassPermissions",
30452
30452
  allowDangerouslySkipPermissions: true,
@@ -79539,7 +79539,7 @@ To reconnect, run:`);
79539
79539
  chatroomId: this.chatroomId,
79540
79540
  role: this.role,
79541
79541
  taskId: task._id,
79542
- messageId: message?._id,
79542
+ ...message?._id !== undefined ? { messageId: message._id } : {},
79543
79543
  convexUrl: getConvexUrl()
79544
79544
  });
79545
79545
  const taskReceivedTime = new Date().toISOString().replace("T", " ").substring(0, 19);
@@ -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
  });
@@ -110224,8 +110359,9 @@ var init_on_request_stop_agent = __esm(() => {
110224
110359
  // src/daemon/entry/events/agent/on-stop-scope-agent.ts
110225
110360
  var onStopScopeAgentEffect = (event) => exports_Effect.gen(function* () {
110226
110361
  const agentMgr = yield* DaemonAgentProcessManagerService;
110227
- if (agentMgr.runInboxScopedStop)
110228
- yield* agentMgr.runInboxScopedStop(event);
110362
+ const stop4 = agentMgr.runInboxScopedStop;
110363
+ if (stop4)
110364
+ yield* stop4(event);
110229
110365
  });
110230
110366
  var init_on_stop_scope_agent = __esm(() => {
110231
110367
  init_esm();
@@ -111779,13 +111915,6 @@ var init_file_content_subscription = __esm(() => {
111779
111915
  init_daemon_services();
111780
111916
  });
111781
111917
 
111782
- // src/infrastructure/services/workspace/file-tree-data-hash.ts
111783
- import { createHash as createHash6 } from "node:crypto";
111784
- function computeFileTreeDataHash(tree) {
111785
- return createHash6("md5").update(JSON.stringify(tree)).digest("hex");
111786
- }
111787
- var init_file_tree_data_hash = () => {};
111788
-
111789
111918
  // src/infrastructure/services/workspace/file-tree-sync-ranker.ts
111790
111919
  function fileExtension(p) {
111791
111920
  const b = (p.split("/").pop() ?? p).toLowerCase();
@@ -112606,6 +112735,13 @@ var init_file_tree_scanner = __esm(() => {
112606
112735
  init_workspace_visibility_policy();
112607
112736
  });
112608
112737
 
112738
+ // src/infrastructure/services/workspace/file-tree-data-hash.ts
112739
+ import { createHash as createHash6 } from "node:crypto";
112740
+ function computeFileTreeDataHash(tree) {
112741
+ return createHash6("md5").update(JSON.stringify(tree)).digest("hex");
112742
+ }
112743
+ var init_file_tree_data_hash = () => {};
112744
+
112609
112745
  // src/infrastructure/services/workspace/git-workspace-porcelain.ts
112610
112746
  import { existsSync as existsSync9 } from "node:fs";
112611
112747
  import path4 from "node:path";
@@ -115939,6 +116075,17 @@ var init_workspace_file_tree_delta_send = __esm(() => {
115939
116075
  function logSubscriptionWarn(label, err) {
115940
116076
  console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage(err)}`);
115941
116077
  }
116078
+ async function runOneShotFileTreeSync(session2, workingDir) {
116079
+ const normalized = normalizeWorkingDirForLookup(workingDir);
116080
+ const tree = await scanFileTree(normalized);
116081
+ const send = createWorkspaceFileTreeCheckpointSend(session2, normalized);
116082
+ await send({ tree, revision: 0 });
116083
+ await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
116084
+ sessionId: session2.sessionId,
116085
+ machineId: session2.machineId,
116086
+ workingDir: normalized
116087
+ });
116088
+ }
115942
116089
  async function stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized) {
115943
116090
  const coordinatorPromise = coordinators.get(normalized);
115944
116091
  if (!coordinatorPromise)
@@ -115947,8 +116094,8 @@ async function stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegist
115947
116094
  await coordinatorPromise.then((coordinator2) => coordinator2.stop()).catch(() => {
115948
116095
  return;
115949
116096
  });
115950
- await checkpointOutboxRegistry.stop(normalized);
115951
- await deltaOutboxRegistry.stop(normalized);
116097
+ await checkpointOutboxRegistry?.stop(normalized);
116098
+ await deltaOutboxRegistry?.stop(normalized);
115952
116099
  }
115953
116100
  async function drainPendingFileTreeReleaseRequests(session2, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry) {
115954
116101
  const releases = await session2.backend.query(api.workspaceFiles.getPendingFileTreeReleaseRequests, {
@@ -115973,7 +116120,36 @@ async function drainPendingFileTreeReleaseRequests(session2, coordinators, check
115973
116120
  });
115974
116121
  }
115975
116122
  }
115976
- async function processPendingFileTreeRequests(session2, coordinators, ensureCoordinator, requests) {
116123
+ async function processOnePendingFileTreeRequest(session2, coordinators, ensureCoordinator, normalized, force, checkpointOutboxRegistry, deltaOutboxRegistry) {
116124
+ const start3 = Date.now();
116125
+ const lease = await session2.backend.query(api.workspaceFiles.getFileTreeWatchLease, {
116126
+ sessionId: session2.sessionId,
116127
+ machineId: session2.machineId,
116128
+ workingDir: normalized
116129
+ });
116130
+ if (!lease?.leaseActive) {
116131
+ await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116132
+ await runOneShotFileTreeSync(session2, normalized);
116133
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree ready: ${normalized} (${Date.now() - start3}ms, one-shot)`);
116134
+ return;
116135
+ }
116136
+ await ensureCoordinator(normalized, force);
116137
+ await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
116138
+ sessionId: session2.sessionId,
116139
+ machineId: session2.machineId,
116140
+ workingDir: normalized
116141
+ });
116142
+ const leaseAfterFulfill = await session2.backend.query(api.workspaceFiles.getFileTreeWatchLease, {
116143
+ sessionId: session2.sessionId,
116144
+ machineId: session2.machineId,
116145
+ workingDir: normalized
116146
+ });
116147
+ if (!leaseAfterFulfill?.leaseActive) {
116148
+ await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116149
+ }
116150
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree ready: ${normalized} (${Date.now() - start3}ms${force ? ", reconciled" : ", cached"})`);
116151
+ }
116152
+ async function processPendingFileTreeRequests(session2, coordinators, ensureCoordinator, requests, checkpointOutboxRegistry, deltaOutboxRegistry) {
115977
116153
  if (!requests?.length)
115978
116154
  return;
115979
116155
  const requestsByDir = new Map;
@@ -115983,25 +116159,20 @@ async function processPendingFileTreeRequests(session2, coordinators, ensureCoor
115983
116159
  }
115984
116160
  for (const [normalized, force] of requestsByDir) {
115985
116161
  await enqueueFileTreeSync(session2.machineId, normalized, async () => {
115986
- const start3 = Date.now();
115987
- await ensureCoordinator(normalized, force).then(() => session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
115988
- sessionId: session2.sessionId,
115989
- machineId: session2.machineId,
115990
- workingDir: normalized
115991
- })).then(() => {
115992
- console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree ready: ${normalized} (${Date.now() - start3}ms${force ? ", reconciled" : ", cached"})`);
115993
- }).catch((err) => {
116162
+ try {
116163
+ await processOnePendingFileTreeRequest(session2, coordinators, ensureCoordinator, normalized, force, checkpointOutboxRegistry, deltaOutboxRegistry);
116164
+ } catch (err) {
115994
116165
  logSubscriptionWarn(`File tree failed for ${normalized}`, err);
115995
- });
116166
+ }
115996
116167
  });
115997
116168
  }
115998
116169
  }
115999
- async function drainPendingFileTreeRequests(session2, coordinators, ensureCoordinator) {
116170
+ async function drainPendingFileTreeRequests(session2, coordinators, ensureCoordinator, checkpointOutboxRegistry, deltaOutboxRegistry) {
116000
116171
  const requests = await session2.backend.query(api.workspaceFiles.getPendingFileTreeRequests, {
116001
116172
  sessionId: session2.sessionId,
116002
116173
  machineId: session2.machineId
116003
116174
  });
116004
- await processPendingFileTreeRequests(session2, coordinators, ensureCoordinator, requests);
116175
+ await processPendingFileTreeRequests(session2, coordinators, ensureCoordinator, requests, checkpointOutboxRegistry, deltaOutboxRegistry);
116005
116176
  }
116006
116177
  var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
116007
116178
  const session2 = yield* DaemonSessionService;
@@ -116050,7 +116221,7 @@ var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
116050
116221
  });
116051
116222
  };
116052
116223
  return {
116053
- drainPendingFileTreeRequests: () => drainPendingFileTreeRequests(session2, coordinators, ensureCoordinator),
116224
+ drainPendingFileTreeRequests: () => drainPendingFileTreeRequests(session2, coordinators, ensureCoordinator, checkpointOutboxRegistry, deltaOutboxRegistry),
116054
116225
  drainPendingFileTreeReleaseRequests: () => drainPendingFileTreeReleaseRequests(session2, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry),
116055
116226
  stop: () => {
116056
116227
  (async () => {
@@ -116066,6 +116237,7 @@ var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
116066
116237
  var init_file_tree_subscription = __esm(() => {
116067
116238
  init_esm();
116068
116239
  init_api3();
116240
+ init_file_tree_scanner();
116069
116241
  init_workspace_file_tree_coordinator();
116070
116242
  init_workspace_sync_queue();
116071
116243
  init_convex_error();
@@ -134334,7 +134506,9 @@ var init_opencode_install = __esm(() => {
134334
134506
 
134335
134507
  // src/infrastructure/retry-queue.ts
134336
134508
  async function withRetry(fn2, opts) {
134337
- const { maxRetries, baseDelayMs, maxDelayMs } = { ...DEFAULTS, ...opts };
134509
+ const maxRetries = opts?.maxRetries ?? DEFAULTS.maxRetries;
134510
+ const baseDelayMs = opts?.baseDelayMs ?? DEFAULTS.baseDelayMs;
134511
+ const maxDelayMs = opts?.maxDelayMs ?? DEFAULTS.maxDelayMs;
134338
134512
  for (let attempt = 0;attempt <= maxRetries; attempt++) {
134339
134513
  try {
134340
134514
  return await fn2();
@@ -134957,4 +135131,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
134957
135131
  });
134958
135132
  program2.parse();
134959
135133
 
134960
- //# debugId=1C27BCC36565FE7A64756E2164756E21
135134
+ //# debugId=56DD8E367644E33A64756E2164756E21