@skrr-ai/cli 0.1.29 → 0.1.31

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.
@@ -63,3 +63,5 @@ export declare abstract class DedicatedLeaseCommand extends BaseCommand {
63
63
  workspace?: string;
64
64
  }, goal: DedicatedWaitGoal | null, verb: string): Promise<void>;
65
65
  }
66
+ /** The same transient verdict BaseCommand gives an ordinary API call. */
67
+ export declare function dedicatedRuntimeApiErrorRetryable(err: unknown): boolean;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DedicatedLeaseCommand = exports.DEDICATED_LEASE_ARG_DESCRIPTION = exports.DEDICATED_SELF_LEASE = exports.dedicatedWaitFlags = void 0;
4
+ exports.dedicatedRuntimeApiErrorRetryable = dedicatedRuntimeApiErrorRetryable;
4
5
  const core_1 = require("@oclif/core");
5
6
  const base_command_1 = require("../base-command");
7
+ const api_fetch_1 = require("./api-fetch");
6
8
  const dedicated_machines_1 = require("./dedicated-machines");
7
9
  const dedicated_terminal_1 = require("./dedicated-terminal");
8
10
  const daemonBroker_1 = require("./daemonBroker");
@@ -176,8 +178,23 @@ class DedicatedLeaseCommand extends base_command_1.BaseCommand {
176
178
  this.error(err.message, { exit: 1 });
177
179
  }
178
180
  const message = (0, dedicated_machines_1.formatDedicatedRuntimeApiError)(err);
179
- if (message)
180
- this.error(message, { exit: 1, code: (0, dedicated_machines_1.dedicatedRuntimeApiErrorCode)(err) });
181
+ if (message) {
182
+ const retryable = dedicatedRuntimeApiErrorRetryable(err);
183
+ this.failWithCliError({
184
+ message: retryable
185
+ ? `Stopped waiting for ${id}; nothing was cancelled and the operation continues server-side. Check it with \`${this.config.bin} machines dedicated show ${id}\`. The status poll failed: ${message}`
186
+ : message,
187
+ code: (0, dedicated_machines_1.dedicatedRuntimeApiErrorCode)(err) ?? 'CLI_ERROR',
188
+ status: err instanceof api_fetch_1.ApiFetchError ? err.status : undefined,
189
+ exit: 1,
190
+ retryable,
191
+ details: {
192
+ ...(0, dedicated_machines_1.dedicatedRuntimeApiErrorDetails)(err),
193
+ leaseId: id,
194
+ operationContinues: true,
195
+ },
196
+ });
197
+ }
181
198
  this.handleApiError(err);
182
199
  }
183
200
  }
@@ -192,3 +209,19 @@ class DedicatedLeaseCommand extends base_command_1.BaseCommand {
192
209
  }
193
210
  }
194
211
  exports.DedicatedLeaseCommand = DedicatedLeaseCommand;
212
+ /** The same transient verdict BaseCommand gives an ordinary API call. */
213
+ function dedicatedRuntimeApiErrorRetryable(err) {
214
+ if (!(err instanceof api_fetch_1.ApiFetchError))
215
+ return false;
216
+ let body = null;
217
+ try {
218
+ const parsed = JSON.parse(err.body || '');
219
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
220
+ body = parsed;
221
+ }
222
+ }
223
+ catch {
224
+ // The HTTP status remains authoritative for an unparseable edge response.
225
+ }
226
+ return (0, base_command_1.isRetryableFailure)(err.status, body);
227
+ }
@@ -71,6 +71,7 @@ export declare const DEDICATED_WAIT_TIMEOUT_EXIT = 124;
71
71
  export declare const DEDICATED_WAIT_DEFAULT_TIMEOUT_MS: number;
72
72
  export declare const DEDICATED_WAIT_DEFAULT_INTERVAL_MS: number;
73
73
  export declare const DEDICATED_WAIT_MAX_READ_FAILURES = 3;
74
+ export declare const DEDICATED_WAIT_MAX_RATE_LIMIT_FAILURES = 6;
74
75
  export declare function waitForDedicatedLease(leaseId: string, goal: DedicatedWaitGoal, options?: DedicatedRuntimeScope & {
75
76
  initial?: DedicatedLease;
76
77
  intervalMs?: number;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEDICATED_WAIT_MAX_READ_FAILURES = exports.DEDICATED_WAIT_DEFAULT_INTERVAL_MS = exports.DEDICATED_WAIT_DEFAULT_TIMEOUT_MS = exports.DEDICATED_WAIT_TIMEOUT_EXIT = exports.DedicatedWaitFailedError = exports.DedicatedWaitTimeoutError = void 0;
3
+ exports.DEDICATED_WAIT_MAX_RATE_LIMIT_FAILURES = exports.DEDICATED_WAIT_MAX_READ_FAILURES = exports.DEDICATED_WAIT_DEFAULT_INTERVAL_MS = exports.DEDICATED_WAIT_DEFAULT_TIMEOUT_MS = exports.DEDICATED_WAIT_TIMEOUT_EXIT = exports.DedicatedWaitFailedError = exports.DedicatedWaitTimeoutError = void 0;
4
4
  exports.evaluateDedicatedWait = evaluateDedicatedWait;
5
5
  exports.waitForDedicatedLease = waitForDedicatedLease;
6
6
  const dedicated_machines_1 = require("./dedicated-machines");
7
+ const api_fetch_1 = require("./api-fetch");
7
8
  const RUNNING_STATES = new Set(['ready', 'active', 'idle']);
8
9
  /** Terminal for the lease itself, so no goal but `destroyed` can still be reached. */
9
10
  const DEAD_STATES = new Set(['failed', 'lost', 'terminated']);
@@ -194,6 +195,15 @@ exports.DEDICATED_WAIT_TIMEOUT_EXIT = 124;
194
195
  exports.DEDICATED_WAIT_DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
195
196
  exports.DEDICATED_WAIT_DEFAULT_INTERVAL_MS = 5 * 1000;
196
197
  exports.DEDICATED_WAIT_MAX_READ_FAILURES = 3;
198
+ exports.DEDICATED_WAIT_MAX_RATE_LIMIT_FAILURES = 6;
199
+ function readRetryDelayMs(err, consecutiveFailures, intervalMs) {
200
+ if (!(err instanceof api_fetch_1.ApiFetchError) || err.status !== 429)
201
+ return intervalMs;
202
+ // A normal five-second poll repeated three times stays inside the same
203
+ // minute bucket and turns a healthy server-side operation into a CLI error.
204
+ // Back off across the bucket boundary while keeping the overall wait bounded.
205
+ return Math.min(intervalMs * 2 ** consecutiveFailures, 60_000);
206
+ }
197
207
  async function waitForDedicatedLease(leaseId, goal, options = {}) {
198
208
  const intervalMs = options.intervalMs ?? exports.DEDICATED_WAIT_DEFAULT_INTERVAL_MS;
199
209
  const timeoutMs = options.timeoutMs ?? exports.DEDICATED_WAIT_DEFAULT_TIMEOUT_MS;
@@ -217,9 +227,12 @@ async function waitForDedicatedLease(leaseId, goal, options = {}) {
217
227
  }
218
228
  catch (err) {
219
229
  consecutiveReadFailures += 1;
220
- if (consecutiveReadFailures >= exports.DEDICATED_WAIT_MAX_READ_FAILURES)
230
+ const maxFailures = err instanceof api_fetch_1.ApiFetchError && err.status === 429
231
+ ? exports.DEDICATED_WAIT_MAX_RATE_LIMIT_FAILURES
232
+ : exports.DEDICATED_WAIT_MAX_READ_FAILURES;
233
+ if (consecutiveReadFailures >= maxFailures)
221
234
  throw err;
222
- await sleep(intervalMs);
235
+ await sleep(readRetryDelayMs(err, consecutiveReadFailures, intervalMs));
223
236
  }
224
237
  }
225
238
  };