lody 0.44.2-next.1 → 0.44.3-next.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.
Files changed (2) hide show
  1. package/dist/index.js +53 -39
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -36820,7 +36820,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
36820
36820
  return client;
36821
36821
  }
36822
36822
  const name = "lody";
36823
- const version$4 = "0.44.2-next.1";
36823
+ const version$4 = "0.44.3-next.1";
36824
36824
  const description = "Lody Agent CLI tool for managing remote command execution";
36825
36825
  const type = "module";
36826
36826
  const main$3 = "dist/index.js";
@@ -112230,6 +112230,9 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
112230
112230
  isTransportConnected() {
112231
112231
  return this.transportStatus === "connected";
112232
112232
  }
112233
+ isRecovering() {
112234
+ return !this.isCleanedUp && !this.isStreamsHealthy();
112235
+ }
112233
112236
  setTransportStatus(status) {
112234
112237
  this.transportStatus = status;
112235
112238
  if (status === "disconnected") {
@@ -113429,6 +113432,9 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
113429
113432
  isTransportConnected() {
113430
113433
  return this.connectionRecovery.isTransportConnected();
113431
113434
  }
113435
+ isTransportRecovering() {
113436
+ return this.connectionRecovery.isRecovering();
113437
+ }
113432
113438
  getConnectedRoomCount() {
113433
113439
  return this.sessions.size + this.codeSessions.size;
113434
113440
  }
@@ -122333,23 +122339,20 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122333
122339
  }
122334
122340
  return Boolean(meta.latestUserMsgId && meta.latestUserMsgId !== meta.lastHandledUserMsgId);
122335
122341
  }
122336
- async setHistorySyncWaitStatus(sessionId, sessionDoc, detail) {
122337
- try {
122338
- await sessionDoc.setStatus(SessionStatusFactory.initializing(void 0, detail));
122339
- } catch (error2) {
122340
- this.deps.logger.debug(`[${sessionId}] Failed to set history sync wait status (${detail}): ${formatErrorMessage(error2)}`);
122341
- }
122342
- }
122343
122342
  async waitForPendingUserTurnHistorySync(sessionId, sessionDoc, meta) {
122344
122343
  this.deps.logger.debug(`[${sessionId}] Pending user turn metadata is visible but history is missing it; waiting up to ${SessionDispatchWatcher.HISTORY_SYNC_WAIT_TIMEOUT_MS / 1e3}s for history CRDT sync`);
122345
- let currentWaitDetail = "joining-history";
122346
- await this.setHistorySyncWaitStatus(sessionId, sessionDoc, currentWaitDetail);
122347
122344
  try {
122348
122345
  await sessionDoc.ensureDocRoomJoined();
122349
122346
  } catch (error2) {
122350
122347
  this.deps.logger.debug(`[${sessionId}] Failed to ensure session history room is joined before waiting: ${formatErrorMessage(error2)}`);
122351
122348
  }
122352
- const turnAfterJoin = await this.checkHistoryAndQueue(sessionDoc, meta);
122349
+ await sessionDoc.waitUntilSynced();
122350
+ const freshMeta = await sessionDoc.getMetaState() ?? meta;
122351
+ if (!this.hasPendingUserTurnSignal(freshMeta)) {
122352
+ this.deps.logger.debug(`[${sessionId}] Pending user turn pointer cleared during pre-wait sync; exiting wait`);
122353
+ return null;
122354
+ }
122355
+ const turnAfterJoin = await this.checkHistoryAndQueue(sessionDoc, freshMeta);
122353
122356
  if (turnAfterJoin) {
122354
122357
  return turnAfterJoin;
122355
122358
  }
@@ -122367,18 +122370,11 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122367
122370
  unsubscribeMirror?.();
122368
122371
  unsubscribeStatus?.();
122369
122372
  };
122370
- const updateWaitStatus = (detail) => {
122371
- if (currentWaitDetail === detail) {
122372
- return;
122373
- }
122374
- currentWaitDetail = detail;
122375
- void this.setHistorySyncWaitStatus(sessionId, sessionDoc, detail);
122376
- };
122377
122373
  const checkForTurn = () => {
122378
122374
  if (settled) {
122379
122375
  return;
122380
122376
  }
122381
- void this.checkHistoryAndQueue(sessionDoc, meta).then((turn) => {
122377
+ void this.checkHistoryAndQueue(sessionDoc, freshMeta).then((turn) => {
122382
122378
  if (settled || !turn) {
122383
122379
  return;
122384
122380
  }
@@ -122398,7 +122394,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122398
122394
  }
122399
122395
  reconnectAttempted = true;
122400
122396
  void (async () => {
122401
- updateWaitStatus("reconnecting-history");
122402
122397
  const jitterMs = SessionDispatchWatcher.getReconnectJitterMs();
122403
122398
  this.deps.logger.debug(`[${sessionId}] Session history room ${reason}; attempting one rejoin in ${jitterMs}ms`);
122404
122399
  await SessionDispatchWatcher.sleep(jitterMs);
@@ -122417,14 +122412,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122417
122412
  if (settled || !status) {
122418
122413
  return;
122419
122414
  }
122420
- if (status === "connecting" || status === "joined") {
122421
- updateWaitStatus("joining-history");
122422
- return;
122423
- }
122424
- if (status === "reconnecting") {
122425
- updateWaitStatus("reconnecting-history");
122426
- return;
122427
- }
122428
122415
  if (status === "disconnected" || status === "error") {
122429
122416
  attemptReconnectOnce(status);
122430
122417
  }
@@ -122461,16 +122448,20 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
122461
122448
  if (meta.machineId !== this.deps.machineId || meta.isArchived || !this.hasPendingUserTurnSignal(meta)) {
122462
122449
  return;
122463
122450
  }
122464
- await this.deps.workspaceDocument.repo.upsertDocMeta?.(roomId, {
122451
+ const pendingUserMsgId = meta.processingUserMsgId ?? meta.latestUserMsgId ?? meta.lastHandledUserMsgId;
122452
+ const recoveryPatch = {
122465
122453
  status: SessionStatusFactory.idle(),
122466
- latestUserMsgId: void 0,
122467
- processingUserMsgId: void 0,
122468
122454
  dispatchError: {
122469
122455
  code: SessionDispatchWatcher.DISPATCH_HISTORY_SYNC_TIMEOUT_CODE,
122470
122456
  message: "Dispatch recovery could not reconnect to this session after 5 minutes. Send a new message to retry.",
122471
122457
  at: getServerNow()
122472
122458
  }
122473
- });
122459
+ };
122460
+ if (pendingUserMsgId) {
122461
+ recoveryPatch.lastHandledUserMsgId = pendingUserMsgId;
122462
+ recoveryPatch.latestUserMsgId = pendingUserMsgId;
122463
+ }
122464
+ await this.deps.workspaceDocument.repo.upsertDocMeta?.(roomId, recoveryPatch);
122474
122465
  const watched = this.watchedSessions.get(sessionId);
122475
122466
  watched?.unsubscribe();
122476
122467
  this.watchedSessions.delete(sessionId);
@@ -133184,6 +133175,9 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
133184
133175
  isControlPlaneReady() {
133185
133176
  return this.documentManager.isTransportConnected();
133186
133177
  }
133178
+ isControlPlaneRecovering() {
133179
+ return this.documentManager.isTransportRecovering();
133180
+ }
133187
133181
  getActiveSessionCount() {
133188
133182
  return this.runtime.getActiveSessionCount();
133189
133183
  }
@@ -135013,23 +135007,26 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
135013
135007
  refreshRuntimeState() {
135014
135008
  const desiredCount = this.desiredWorkspaces.size;
135015
135009
  let connectedCount = 0;
135010
+ let reconnectingCount = 0;
135016
135011
  let totalActiveSessions = 0;
135017
135012
  let totalConnectedRooms = 0;
135018
135013
  for (const runtime of this.runtimes.values()) {
135019
135014
  if (runtime.lody.isControlPlaneReady()) {
135020
135015
  connectedCount += 1;
135016
+ } else if (runtime.lody.isControlPlaneRecovering()) {
135017
+ reconnectingCount += 1;
135021
135018
  }
135022
135019
  totalActiveSessions += runtime.lody.getActiveSessionCount();
135023
135020
  totalConnectedRooms += runtime.lody.getConnectedRoomCount();
135024
135021
  }
135025
135022
  this.runtimeStateReporter.setActiveSessionCount(totalActiveSessions);
135026
135023
  this.runtimeStateReporter.setConnectedRoomCount(totalConnectedRooms);
135027
- const nextConnectivity = desiredCount === 0 ? "online" : connectedCount === 0 ? "offline" : connectedCount < desiredCount ? "reconnecting" : "online";
135024
+ const hasWorkspaceRetry = this.retryTimers.size > 0 || this.startInFlight.size > 0;
135025
+ const nextConnectivity = desiredCount === 0 ? "online" : connectedCount === desiredCount ? "online" : reconnectingCount > 0 || hasWorkspaceRetry ? "reconnecting" : "offline";
135028
135026
  if (this.lastConnectivity !== nextConnectivity) {
135029
135027
  this.lastConnectivity = nextConnectivity;
135030
135028
  this.runtimeStateReporter.setConnectivity(nextConnectivity);
135031
135029
  }
135032
- const hasWorkspaceRetry = this.retryTimers.size > 0 || this.startInFlight.size > 0;
135033
135030
  if (hasWorkspaceRetry && !this.hasWorkspaceRetryIssue) {
135034
135031
  this.hasWorkspaceRetryIssue = true;
135035
135032
  this.runtimeStateReporter.upsertIssue({
@@ -167312,10 +167309,18 @@ ${entry2.text}`).join("\n\n");
167312
167309
  }
167313
167310
  const DEFAULT_MIN_RETRY_MS$1 = 1e3;
167314
167311
  const DEFAULT_MAX_RETRY_MS$1 = 3e4;
167315
- function buildRetryDelay(attempt, minMs = DEFAULT_MIN_RETRY_MS$1, maxMs = DEFAULT_MAX_RETRY_MS$1) {
167312
+ const DEFAULT_JITTER_FRACTION = 0.2;
167313
+ function buildRetryDelay(attempt, minMs = DEFAULT_MIN_RETRY_MS$1, maxMs = DEFAULT_MAX_RETRY_MS$1, options = {}) {
167316
167314
  const exponent = Math.max(0, attempt);
167317
- const delay2 = minMs * 2 ** exponent;
167318
- return Math.min(delay2, maxMs);
167315
+ const baseDelay = Math.min(minMs * 2 ** exponent, maxMs);
167316
+ const jitterFraction = Math.max(0, options.jitterFraction ?? DEFAULT_JITTER_FRACTION);
167317
+ if (jitterFraction === 0) {
167318
+ return baseDelay;
167319
+ }
167320
+ const random2 = options.random ?? Math.random;
167321
+ const randomValue = Math.min(1, Math.max(0, random2()));
167322
+ const jitterMultiplier = 1 + (randomValue * 2 - 1) * jitterFraction;
167323
+ return Math.min(Math.max(0, Math.round(baseDelay * jitterMultiplier)), maxMs);
167319
167324
  }
167320
167325
  class FailureWindow {
167321
167326
  historyMs = [];
@@ -167376,6 +167381,7 @@ ${result.stderr}`;
167376
167381
  probeFailureThreshold;
167377
167382
  minRetryMs;
167378
167383
  maxRetryMs;
167384
+ retryRandom;
167379
167385
  failureWindow;
167380
167386
  triggered = false;
167381
167387
  inFlight = false;
@@ -167407,6 +167413,7 @@ ${result.stderr}`;
167407
167413
  this.probeFailureThreshold = options.probeFailureThreshold ?? DEFAULT_PROBE_FAILURE_THRESHOLD;
167408
167414
  this.minRetryMs = options.minRetryMs ?? DEFAULT_MIN_RETRY_MS;
167409
167415
  this.maxRetryMs = options.maxRetryMs ?? DEFAULT_MAX_RETRY_MS;
167416
+ this.retryRandom = options.retryRandom ?? Math.random;
167410
167417
  this.failureWindow = new FailureWindow(options.fatalFailureWindowMs ?? DEFAULT_FATAL_FAILURE_WINDOW_MS, options.fatalFailureThreshold ?? DEFAULT_FATAL_FAILURE_THRESHOLD);
167411
167418
  }
167412
167419
  getState() {
@@ -167486,6 +167493,9 @@ ${result.stderr}`;
167486
167493
  this.latestRuntimeState = runtimeState;
167487
167494
  this.probeFailureCount = 0;
167488
167495
  this.probeUnavailable = false;
167496
+ this.clearRetryTimer();
167497
+ this.attempt = 0;
167498
+ this.failureWindow.reset();
167489
167499
  this.lastStateMessage = void 0;
167490
167500
  } else {
167491
167501
  this.probeFailureCount += 1;
@@ -167506,7 +167516,9 @@ ${result.stderr}`;
167506
167516
  } else if (this.fatalReason) {
167507
167517
  phase = "fatal";
167508
167518
  } else if (runtime) {
167509
- phase = runtime.phase === "fatal" ? "fatal" : runtime.phase;
167519
+ phase = runtime.phase === "fatal" ? "fatal" : runtime.connectivity === "reconnecting" ? "reconnecting" : runtime.phase;
167520
+ } else if (this.retryTimer) {
167521
+ phase = "reconnecting";
167510
167522
  } else if (childRunning) {
167511
167523
  phase = this.probeUnavailable ? "offline" : "starting";
167512
167524
  } else if (this.probeUnavailable && !this.inFlight && !this.retryTimer) {
@@ -167563,7 +167575,9 @@ ${result.stderr}`;
167563
167575
  scheduleRetry(reason, recordFailure = true) {
167564
167576
  if (this.fatalReason) return;
167565
167577
  if (recordFailure && this.recordFailure(reason)) return;
167566
- const delay2 = buildRetryDelay(this.attempt, this.minRetryMs, this.maxRetryMs);
167578
+ const delay2 = buildRetryDelay(this.attempt, this.minRetryMs, this.maxRetryMs, {
167579
+ random: this.retryRandom
167580
+ });
167567
167581
  this.attempt += 1;
167568
167582
  this.clearRetryTimer();
167569
167583
  this.pendingRetryInMs = delay2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lody",
3
- "version": "0.44.2-next.1",
3
+ "version": "0.44.3-next.1",
4
4
  "description": "Lody Agent CLI tool for managing remote command execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",