deepline 0.3.451 → 0.3.453

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 (117) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +65 -0
  2. package/dist/bundling-sources/sdk/src/http.ts +2 -1
  3. package/dist/bundling-sources/sdk/src/index.ts +2 -0
  4. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  5. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +63 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +5 -1
  7. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +49 -11
  8. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +6 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +3 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +17 -2
  12. package/dist/cli/{auth-YLBWEMRW.mjs → auth-6CXS55CN.mjs} +4 -4
  13. package/dist/cli/auth-AICIA232.js +40 -0
  14. package/dist/cli/{billing-GWG5D3P6.js → billing-QC52XTAD.js} +87 -74
  15. package/dist/cli/{billing-DUFOEOPT.mjs → billing-SWLTV6PV.mjs} +18 -5
  16. package/dist/cli/{chunk-37CPEQBE.mjs → chunk-2LDU5BMG.mjs} +3 -3
  17. package/dist/cli/{chunk-JUCEEIEC.mjs → chunk-43HOSM2F.mjs} +1 -1
  18. package/dist/cli/{chunk-E7V5CRA2.mjs → chunk-6CTVXF6X.mjs} +8 -8
  19. package/dist/cli/{chunk-BJOVX7EB.mjs → chunk-7557D4FM.mjs} +2 -2
  20. package/dist/cli/chunk-BX343KU7.mjs +155 -0
  21. package/dist/cli/{chunk-7VRWERTM.js → chunk-DMTAFWMS.js} +84 -50
  22. package/dist/cli/{chunk-XLOXUW5Y.mjs → chunk-FS2RMEJ7.mjs} +1 -1
  23. package/dist/cli/{chunk-EJ6YI46S.js → chunk-HUDUN4AR.js} +2 -2
  24. package/dist/cli/{chunk-OKTCLFKM.mjs → chunk-IFBLLSGH.mjs} +5 -5
  25. package/dist/cli/{chunk-33EM4SMH.mjs → chunk-IWFI6FTJ.mjs} +4 -153
  26. package/dist/cli/{chunk-ZPV7DMAA.mjs → chunk-IXVABCNA.mjs} +1 -1
  27. package/dist/cli/{chunk-O3KVUHCG.js → chunk-JOF3B22H.js} +20 -20
  28. package/dist/cli/{chunk-6TFACCXN.js → chunk-KFKM5J2N.js} +2 -2
  29. package/dist/cli/{chunk-WLVGRU5A.mjs → chunk-KQD6EFPD.mjs} +2 -2
  30. package/dist/cli/{chunk-HSKLAPMD.js → chunk-MP35NE55.js} +26 -26
  31. package/dist/cli/chunk-NOHA3SZJ.js +155 -0
  32. package/dist/cli/{chunk-Z3DBS4IB.js → chunk-NSQZUUYB.js} +81 -81
  33. package/dist/cli/{chunk-BQQLTSGC.mjs → chunk-P4UQCYKH.mjs} +4 -4
  34. package/dist/cli/{chunk-CH2WDSBC.js → chunk-PJWXEUUH.js} +8 -8
  35. package/dist/cli/{chunk-L2IUGWV5.js → chunk-RG644LJU.js} +1 -1
  36. package/dist/cli/{chunk-5DUMNKQG.js → chunk-RNCIPLU5.js} +50 -50
  37. package/dist/cli/{chunk-WDOWAOYB.js → chunk-RTR2KUU6.js} +10 -10
  38. package/dist/cli/{chunk-4C7HPD57.mjs → chunk-SQUJHT7O.mjs} +1 -1
  39. package/dist/cli/{chunk-ZNDE2BTH.js → chunk-V6AZQ4JH.js} +16 -16
  40. package/dist/cli/{chunk-F2DW7DFE.js → chunk-V7S2RUVE.js} +8 -8
  41. package/dist/cli/{chunk-C4NPWUZY.js → chunk-VG6WESY7.js} +73 -222
  42. package/dist/cli/{chunk-6G6KX7I7.js → chunk-WTTHH2K3.js} +6 -6
  43. package/dist/cli/{chunk-JRPNCMMN.js → chunk-WWZ4YJ6J.js} +35 -35
  44. package/dist/cli/{chunk-PJYTV24I.mjs → chunk-X2LUT22I.mjs} +2 -2
  45. package/dist/cli/{chunk-YXXIFMXI.mjs → chunk-XH4QC5ZX.mjs} +2 -2
  46. package/dist/cli/{chunk-3HT47QPJ.mjs → chunk-XNN3OTGT.mjs} +2 -2
  47. package/dist/cli/{chunk-LPPAJJJN.mjs → chunk-XV4463XW.mjs} +35 -1
  48. package/dist/cli/{chunk-TFCLUWDQ.js → chunk-YU6IE234.js} +6 -6
  49. package/dist/cli/{chunk-RFPP4Q66.mjs → chunk-ZVBLECZX.mjs} +3 -3
  50. package/dist/cli/{csv-RL7WQD6Y.mjs → csv-FON4ZQKC.mjs} +3 -3
  51. package/dist/cli/{csv-4CHXZQXO.js → csv-WIQB5XWZ.js} +12 -12
  52. package/dist/cli/{db-ZDBAWV7B.mjs → db-3KA62DOQ.mjs} +4 -4
  53. package/dist/cli/{db-MRI5IM2A.js → db-VMDDODCN.js} +25 -25
  54. package/dist/cli/{describe-RRQUUJQ3.mjs → describe-LGDK77QI.mjs} +13 -12
  55. package/dist/cli/{describe-2FYKXM5B.js → describe-NTAAHCCX.js} +17 -16
  56. package/dist/cli/describe-core.d.mts +1 -1
  57. package/dist/cli/describe-core.d.ts +1 -1
  58. package/dist/cli/{executions-KDBD47A5.js → executions-OT2KNJDO.js} +6 -6
  59. package/dist/cli/{executions-RJL76TJS.mjs → executions-TM6AMTQ7.mjs} +4 -4
  60. package/dist/cli/{feedback-2CE24NHD.js → feedback-4HQGY3TO.js} +7 -7
  61. package/dist/cli/{feedback-KOYLXHYE.mjs → feedback-HWLUVFE2.mjs} +3 -3
  62. package/dist/cli/git-QIZWO5BA.js +24 -0
  63. package/dist/cli/{git-RDUHU6L6.mjs → git-TDJVSPE6.mjs} +4 -4
  64. package/dist/cli/index.js +133 -131
  65. package/dist/cli/index.mjs +39 -37
  66. package/dist/cli/{legacy-noops-7FOMGBMN.js → legacy-noops-XH3FDLWT.js} +7 -7
  67. package/dist/cli/{legacy-noops-4HS2LYP6.mjs → legacy-noops-YB2PES43.mjs} +4 -4
  68. package/dist/cli/{monitors-IJXNK5BL.js → monitors-E3QFEJKF.js} +276 -124
  69. package/dist/cli/{monitors-JLBTNBVU.mjs → monitors-KQDDMSDR.mjs} +156 -4
  70. package/dist/cli/{org-OWP6K4AA.mjs → org-7X2C7YKA.mjs} +4 -4
  71. package/dist/cli/{org-JL7SW6VY.js → org-PMTLR7VP.js} +66 -66
  72. package/dist/cli/{play-FNOVKU74.mjs → play-7FNEPSVR.mjs} +11 -10
  73. package/dist/cli/{play-LLNZWHT6.js → play-RH22Z3D6.js} +284 -283
  74. package/dist/cli/{providers-WBOEOKE7.mjs → providers-HOEDJNUK.mjs} +4 -4
  75. package/dist/cli/{providers-E4XIEUC7.js → providers-X5NY5IQH.js} +7 -7
  76. package/dist/cli/{quickstart-3FUHKGEY.js → quickstart-FI4A6VTV.js} +5 -5
  77. package/dist/cli/{quickstart-6G5G3BVA.mjs → quickstart-NCL7P2US.mjs} +3 -3
  78. package/dist/cli/search-6FUMJBIY.js +30 -0
  79. package/dist/cli/{search-CNMB4Z6M.mjs → search-UHT7ZNPO.mjs} +5 -5
  80. package/dist/cli/{secrets-5FY5APVK.mjs → secrets-D4ZB5RKB.mjs} +4 -4
  81. package/dist/cli/{secrets-BDSWOYAT.js → secrets-TT6J3SZJ.js} +13 -13
  82. package/dist/cli/{sessions-PMIKVPQN.mjs → sessions-HRLJ6SLL.mjs} +4 -4
  83. package/dist/cli/{sessions-B7T2CHYK.js → sessions-SRQQZMM7.js} +5 -5
  84. package/dist/cli/{settings-RXQJRRLR.js → settings-EJIKXLC7.js} +76 -75
  85. package/dist/cli/{settings-4TAYLTPR.mjs → settings-PJJYPWU3.mjs} +9 -8
  86. package/dist/cli/{setup-ZTMETGSO.js → setup-3FL77Z33.js} +43 -42
  87. package/dist/cli/{setup-LVUISLVO.mjs → setup-DNI6ENFD.mjs} +8 -7
  88. package/dist/cli/skills-DEKOSL7F.js +30 -0
  89. package/dist/cli/{skills-NSJ43Z5Q.mjs → skills-FO7MY2OE.mjs} +6 -5
  90. package/dist/cli/tools-E6XRW6PW.js +45 -0
  91. package/dist/cli/{tools-CFCKIGDY.mjs → tools-F72WONN3.mjs} +13 -12
  92. package/dist/cli/update-6M3CAS4T.js +32 -0
  93. package/dist/cli/{update-HYOCBXJO.mjs → update-JZU33TC5.mjs} +8 -7
  94. package/dist/cli/{workflow-U6S4SWTF.js → workflow-BGKC73V2.js} +15 -15
  95. package/dist/cli/{workflow-RKX45RJ4.mjs → workflow-PQYQXQPH.mjs} +5 -5
  96. package/dist/{client-CPRaigLC.d.ts → client-D6XhrO0f.d.ts} +26 -1
  97. package/dist/{client-DstDI5TV.d.mts → client-mRA_esYI.d.mts} +26 -1
  98. package/dist/index.d.mts +2 -2
  99. package/dist/index.d.ts +2 -2
  100. package/dist/index.js +6 -6
  101. package/dist/index.mjs +3 -3
  102. package/dist/install-integrity.json +82 -80
  103. package/dist/plays/play-description.d.mts +1 -1
  104. package/dist/plays/play-description.d.ts +1 -1
  105. package/dist/plays/run-request.d.mts +1 -1
  106. package/dist/plays/run-request.d.ts +1 -1
  107. package/dist/release.d.mts +1 -1
  108. package/dist/release.d.ts +1 -1
  109. package/dist/release.js +2 -2
  110. package/dist/release.mjs +1 -1
  111. package/package.json +1 -1
  112. package/dist/cli/auth-WPQBEOES.js +0 -40
  113. package/dist/cli/git-DZ5GROPH.js +0 -24
  114. package/dist/cli/search-4ECC773X.js +0 -30
  115. package/dist/cli/skills-MIENPTOD.js +0 -29
  116. package/dist/cli/tools-CXJO5XSH.js +0 -44
  117. package/dist/cli/update-B2LQGEXF.js +0 -31
@@ -1285,6 +1285,18 @@ export type MonitorsListOptions = {
1285
1285
  * plans, dependents) and it must not require an SDK bump to evolve.
1286
1286
  */
1287
1287
  export type MonitorCheckResult = Record<string, unknown>;
1288
+
1289
+ export type MonitorPreviewOptions = {
1290
+ /** Sample size, 1-3. The server default is 3. */
1291
+ limit?: number;
1292
+ /** Reuse to recover one preview's result; a new key is a new, paid preview. */
1293
+ idempotencyKey?: string;
1294
+ };
1295
+
1296
+ /** A preview's sample and charge, plus the key that identifies it. */
1297
+ export type MonitorPreviewResult = Record<string, unknown> & {
1298
+ idempotency_key: string;
1299
+ };
1288
1300
  export type MonitorDeployResult = Record<string, unknown>;
1289
1301
  /** Field-level monitor capability spec returned by `client.monitors.get(...)`. */
1290
1302
  export type MonitorSpec = {
@@ -1868,6 +1880,15 @@ export type MonitorsNamespace = {
1868
1880
  ) => Promise<MonitorsAvailableResult>;
1869
1881
  /** Validate a monitor definition without deploying it (no spend). */
1870
1882
  check: (definition: MonitorDefinition) => Promise<MonitorCheckResult>;
1883
+ /**
1884
+ * Sample a few recent matches for a definition before deploying it. Spends
1885
+ * Deepline credits per returned update. Reuse `idempotencyKey` to recover a
1886
+ * lost result without paying again; omit it for a new preview.
1887
+ */
1888
+ preview: (
1889
+ definition: MonitorDefinition,
1890
+ options?: MonitorPreviewOptions,
1891
+ ) => Promise<MonitorPreviewResult>;
1871
1892
  /** Deploy a monitor from a definition. May spend Deepline credits. */
1872
1893
  deploy: (
1873
1894
  definition: MonitorDefinition,
@@ -2850,6 +2871,8 @@ export class DeeplineClient {
2850
2871
  available: (toolIdOrOptions, options) =>
2851
2872
  this.getMonitorsAvailable(toolIdOrOptions, options),
2852
2873
  check: (definition) => this.checkMonitor(definition),
2874
+ preview: (definition, options) =>
2875
+ this.previewMonitor(definition, options),
2853
2876
  deploy: (definition, options) => this.deployMonitor(definition, options),
2854
2877
  sync: (definition, options) =>
2855
2878
  options?.dryRun
@@ -6686,6 +6709,48 @@ export class DeeplineClient {
6686
6709
  });
6687
6710
  }
6688
6711
 
6712
+ /**
6713
+ * Run one paid preview. Prefer `client.monitors.preview(...)`.
6714
+ *
6715
+ * The key is fixed before the request is sent and returned on the result
6716
+ * and on any error (`error.idempotencyKey`), so a caller that loses the
6717
+ * response can repeat the call with it and get the original result without
6718
+ * a second charge. The submission is never replayed automatically.
6719
+ */
6720
+ async previewMonitor(
6721
+ definition: MonitorDefinition,
6722
+ options?: MonitorPreviewOptions,
6723
+ ): Promise<MonitorPreviewResult> {
6724
+ const idempotencyKey =
6725
+ options?.idempotencyKey ??
6726
+ `monitor-preview-${
6727
+ globalThis.crypto?.randomUUID?.() ??
6728
+ `${Date.now()}-${Math.random().toString(36).slice(2)}`
6729
+ }`;
6730
+ try {
6731
+ const result = await this.http.request<Record<string, unknown>>(
6732
+ '/api/v2/monitors/preview',
6733
+ {
6734
+ method: 'POST',
6735
+ body: {
6736
+ ...definition,
6737
+ ...(options?.limit === undefined ? {} : { limit: options.limit }),
6738
+ },
6739
+ headers: { 'Idempotency-Key': idempotencyKey },
6740
+ maxRetries: 0,
6741
+ exactUrlOnly: true,
6742
+ preserveRateLimitResponse: true,
6743
+ },
6744
+ );
6745
+ return { ...result, idempotency_key: idempotencyKey };
6746
+ } catch (error) {
6747
+ if (error && typeof error === 'object') {
6748
+ Object.assign(error, { idempotencyKey });
6749
+ }
6750
+ throw error;
6751
+ }
6752
+ }
6753
+
6689
6754
  /**
6690
6755
  * Deploy a monitor from a definition. `dryRun` validates via the check
6691
6756
  * endpoint and returns the plan without deploying. Prefer
@@ -1036,7 +1036,8 @@ function isMonitorRateLimitEnvelope(parsed: unknown): boolean {
1036
1036
  const response = asRecord(parsed);
1037
1037
  const error = asRecord(response?.error);
1038
1038
  return (
1039
- error?.code === 'monitor_upstream_rate_limited' &&
1039
+ (error?.code === 'monitor_upstream_rate_limited' ||
1040
+ error?.code === 'monitor_preview_rate_limited') &&
1040
1041
  typeof error.message === 'string'
1041
1042
  );
1042
1043
  }
@@ -140,6 +140,8 @@ export type {
140
140
  LegacyMonitorStatusFilter,
141
141
  MonitorListEntry,
142
142
  MonitorCheckResult,
143
+ MonitorPreviewOptions,
144
+ MonitorPreviewResult,
143
145
  MonitorDeployResult,
144
146
  MonitorDetail,
145
147
  MonitorSpec,
@@ -205,7 +205,7 @@ export const SDK_RELEASE = {
205
205
  // getters keep their established compatibility behavior.
206
206
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
207
207
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
208
- version: '0.3.451',
208
+ version: '0.3.453',
209
209
  updateSummary: {
210
210
  introducedIn: '0.3.90',
211
211
  summary:
@@ -286,6 +286,15 @@ export type ProviderMonitorCapabilityDefinition = {
286
286
  maxIds: number;
287
287
  rateLimitId: string;
288
288
  };
289
+ /**
290
+ * Optional paid sample: a few recent matches for the definition being
291
+ * considered, with nothing created. Only payloads whose `payloadField`
292
+ * value is listed can be previewed; every other payload of this capability,
293
+ * and every capability without this field, has no preview. `action` must
294
+ * also appear in `supportActions`, which is what registers it for
295
+ * execution.
296
+ */
297
+ preview?: ProviderMonitorPreviewDescriptor;
289
298
  // Declares that this monitor delivers data to Deepline via an inbound
290
299
  // webhook callback (handled by the provider-callbacks route). Webhook
291
300
  // subscription monitors are inherently inbound; native monitors must set
@@ -349,6 +358,43 @@ const UNLOCKED_ENTITLEMENT_STATUS: ProviderMonitorCapabilityEntitlementStatus =
349
358
  locked: false,
350
359
  };
351
360
 
361
+ export type ProviderMonitorPreviewDescriptor = {
362
+ action: string;
363
+ payloadField: string;
364
+ supportedValues: readonly string[];
365
+ defaultLimit: number;
366
+ maxLimit: number;
367
+ };
368
+
369
+ export type ProviderMonitorPreviewResolution =
370
+ | { available: true; descriptor: ProviderMonitorPreviewDescriptor }
371
+ | { available: false; reason: string };
372
+
373
+ /**
374
+ * Whether this payload of this capability can be previewed. `null` means the
375
+ * capability declares no preview at all, so callers omit preview entirely
376
+ * rather than saying "unavailable" for every monitor.
377
+ */
378
+ export function resolveProviderMonitorPreview(input: {
379
+ capability: Pick<
380
+ ProviderMonitorCapabilityDefinition,
381
+ 'providerCapability' | 'runtime'
382
+ >;
383
+ payload: Record<string, unknown>;
384
+ }): ProviderMonitorPreviewResolution | null {
385
+ const descriptor = input.capability.runtime.preview;
386
+ if (!descriptor) return null;
387
+ const value = input.payload[descriptor.payloadField];
388
+ if (typeof value === 'string' && descriptor.supportedValues.includes(value)) {
389
+ return { available: true, descriptor };
390
+ }
391
+ const label = typeof value === 'string' && value ? value : 'this payload';
392
+ return {
393
+ available: false,
394
+ reason: `Preview isn't available for ${label} yet. Run monitors check, then deploy.`,
395
+ };
396
+ }
397
+
352
398
  export type ProviderMonitorCapabilitySerializable = {
353
399
  provider: string;
354
400
  tool: string;
@@ -381,6 +427,11 @@ export type ProviderMonitorCapabilitySerializable = {
381
427
  included_active_monitors?: number | null;
382
428
  reason?: string;
383
429
  };
430
+ /** Present only when the capability declares a paid preview. */
431
+ preview?: {
432
+ available_for: Record<string, string[]>;
433
+ max_limit: number;
434
+ };
384
435
  next_commands: string[];
385
436
  };
386
437
 
@@ -604,6 +655,18 @@ export function serializeProviderMonitorCapability(
604
655
  : {}),
605
656
  ...(entitlement.reason ? { reason: entitlement.reason } : {}),
606
657
  },
658
+ ...(capability.runtime.preview
659
+ ? {
660
+ preview: {
661
+ available_for: {
662
+ [capability.runtime.preview.payloadField]: [
663
+ ...capability.runtime.preview.supportedValues,
664
+ ],
665
+ },
666
+ max_limit: capability.runtime.preview.maxLimit,
667
+ },
668
+ }
669
+ : {}),
607
670
  next_commands: [],
608
671
  };
609
672
  }
@@ -303,7 +303,11 @@ function createPlayRuntimeRequire(): ReturnType<typeof createRequire> {
303
303
  }
304
304
  const WAIT_CONFIG_POLL_MS = 25;
305
305
  const WAIT_CONFIG_TIMEOUT_MS = 120_000;
306
- export const RUNNER_EXECUTION_ACK_TIMEOUT_MS = 75_000;
306
+ // Outlasts the claim lease, because an unanswered heartbeat says nothing about
307
+ // the park. A stall shorter than the lease keeps this sandbox, and a longer one
308
+ // reaches the heartbeat loop's own guard and is reported as an outage.
309
+ export const RUNNER_EXECUTION_ACK_TIMEOUT_MS =
310
+ (RUNTIME_RELIABILITY_POLICY.worker.claimLeaseSeconds + 30) * 1_000;
307
311
  const RUNNER_RUNTIME_CONTROL_MAX_ATTEMPTS =
308
312
  RUNTIME_RELIABILITY_POLICY.gateway.runnerControlMaxAttempts;
309
313
  const RUNNER_RUNTIME_CONTROL_RETRY_DELAYS_MS = [100, 250] as const;
@@ -37,6 +37,12 @@ const DAYTONA_CREATE_RETRY_DELAYS_MS = [0, 500, 1_500] as const;
37
37
  const DAYTONA_TIMED_OUT_CREATE_RECONCILE_DELAYS_MS = [
38
38
  0, 1_000, 3_000, 6_000, 12_000, 24_000, 36_000,
39
39
  ] as const;
40
+ // A reservation can outlive a create that was refused, or one never sent because
41
+ // the scheduler stalled between committing the reservation and acknowledging it.
42
+ // This delay lets a healthy owner finish its create and reconcile ladder first.
43
+ // It is not a fence: a stalled owner can outlast it, so name uniqueness and the
44
+ // attempt fences on abandon and promotion keep custody safe.
45
+ const DAYTONA_ABSENT_OPERATION_RECREATE_AFTER_MS = 3 * 60_000;
40
46
  // Explicit runner deadline + scheduler GC own the normal lifecycle. Daytona's
41
47
  // inactivity stop is a wider crash backstop measured from sandbox creation, so
42
48
  // setup time cannot consume the terminal-flush grace.
@@ -671,6 +677,7 @@ async function createRetriedOneShotDaytonaSandbox(input: {
671
677
  leaseId: string;
672
678
  providerOperationToken: string | null;
673
679
  resumeExistingProviderOperation?: boolean;
680
+ existingProviderOperationAgeMs?: number;
674
681
  }>;
675
682
  releaseSandboxCapacity?: (leaseId: string) => Promise<void>;
676
683
  nextProviderAttempt: () => number;
@@ -700,6 +707,7 @@ async function createRetriedOneShotDaytonaSandbox(input: {
700
707
  });
701
708
  const reservation = await input.reserveSandboxCapacity?.(attempt);
702
709
  const sandboxName = daytonaSandboxName(reservation?.providerOperationToken);
710
+ let recreatedAfter: TimedOutDaytonaSandboxReconcileObserved | null = null;
703
711
  if (reservation?.resumeExistingProviderOperation) {
704
712
  if (!reservation.providerOperationToken) {
705
713
  throw new DaytonaSandboxTransitionPendingError(sandboxName);
@@ -740,17 +748,32 @@ async function createRetriedOneShotDaytonaSandbox(input: {
740
748
  );
741
749
  }
742
750
  // Neither absence nor an ongoing transition proves that create cannot
743
- // commit. Retain the durable identity and its capacity reservation. The
744
- // detail only records which of the two Daytona reported, for the log.
745
- throw new DaytonaSandboxTransitionPendingError(
746
- sandboxName,
747
- daytonaTransitionPendingLogDetail({
748
- phase: 'resume',
749
- observed: reconciliation.observed,
750
- providerAttempt: attempt,
751
- launchOutcome: null,
752
- }),
753
- );
751
+ // commit, so inside the create window retain the durable identity and
752
+ // its capacity reservation. The detail only records which of the two
753
+ // Daytona reported, for the log.
754
+ const operationAgeMs = reservation.existingProviderOperationAgeMs ?? 0;
755
+ if (
756
+ reconciliation.observed.last.lookup !== 'not_found' ||
757
+ operationAgeMs < DAYTONA_ABSENT_OPERATION_RECREATE_AFTER_MS
758
+ ) {
759
+ throw new DaytonaSandboxTransitionPendingError(
760
+ sandboxName,
761
+ daytonaTransitionPendingLogDetail({
762
+ phase: 'resume',
763
+ observed: reconciliation.observed,
764
+ providerAttempt: attempt,
765
+ launchOutcome: null,
766
+ }),
767
+ );
768
+ }
769
+ // Daytona's own name uniqueness fences this: the same identity under the
770
+ // same reservation cannot become a second sandbox. A create that lands
771
+ // first surfaces as a conflict, which the reconcile below adopts by name.
772
+ input.emitStage('create:recreate_absent_operation', {
773
+ attempt,
774
+ operationAgeMs,
775
+ });
776
+ recreatedAfter = reconciliation.observed;
754
777
  }
755
778
  let sandbox: DaytonaSandbox;
756
779
  try {
@@ -895,6 +918,20 @@ async function createRetriedOneShotDaytonaSandbox(input: {
895
918
  { cause: error },
896
919
  );
897
920
  }
921
+ if (recreatedAfter) {
922
+ // Refusing this send says nothing about an earlier send of the identity,
923
+ // so keep its reservation and resume the same name.
924
+ await recordCreateFailure();
925
+ throw new DaytonaSandboxTransitionPendingError(
926
+ sandboxName,
927
+ daytonaTransitionPendingLogDetail({
928
+ phase: 'resume',
929
+ observed: recreatedAfter,
930
+ providerAttempt: attempt,
931
+ launchOutcome: null,
932
+ }),
933
+ );
934
+ }
898
935
  if (reservation) {
899
936
  await input.releaseSandboxCapacity?.(reservation.leaseId);
900
937
  }
@@ -1098,6 +1135,7 @@ export function createOneShotDaytonaSandboxLifecycle(input: {
1098
1135
  leaseId: string;
1099
1136
  providerOperationToken: string | null;
1100
1137
  resumeExistingProviderOperation?: boolean;
1138
+ existingProviderOperationAgeMs?: number;
1101
1139
  }>;
1102
1140
  releaseSandboxCapacity?: (leaseId: string) => Promise<void>;
1103
1141
  startAdmission?: DaytonaSandboxStartAdmission;
@@ -245,6 +245,8 @@ export type SandboxExecutionAdmission = {
245
245
  providerOperationToken?: string | null;
246
246
  /** Resume the existing durable provider operation before any new create. */
247
247
  resumeExistingProviderOperation?: boolean;
248
+ /** Scheduler-clock age of the operation being resumed. */
249
+ existingProviderOperationAgeMs?: number;
248
250
  }
249
251
  | { kind: 'pre_code_deferred'; reason: SandboxPreCodeDeferralReason }
250
252
  >;
@@ -310,6 +312,8 @@ export type SandboxExecutionLifecycle = {
310
312
  providerOperationToken?: string | null;
311
313
  /** Resume the existing durable provider operation before any new create. */
312
314
  resumeExistingProviderOperation?: boolean;
315
+ /** Scheduler-clock age of the operation being resumed. */
316
+ existingProviderOperationAgeMs?: number;
313
317
  }
314
318
  | { kind: 'pre_code_deferred'; reason: SandboxPreCodeDeferralReason }
315
319
  >;
@@ -188,6 +188,12 @@ function createRunnerCallbacks(input: {
188
188
  ...(outcome.resumeExistingProviderOperation === true
189
189
  ? { resumeExistingProviderOperation: true }
190
190
  : {}),
191
+ ...(outcome.existingProviderOperationAgeMs === undefined
192
+ ? {}
193
+ : {
194
+ existingProviderOperationAgeMs:
195
+ outcome.existingProviderOperationAgeMs,
196
+ }),
191
197
  };
192
198
  },
193
199
  releaseSandboxCapacity: async (leaseId) => {
@@ -4338,13 +4338,15 @@ async function executeAssignedAbsurdAttempt(input: {
4338
4338
  providerOperationToken: reserved.providerOperationToken,
4339
4339
  resumeExistingProviderOperation:
4340
4340
  reserved.resumeExistingProviderOperation,
4341
+ existingProviderOperationAgeMs:
4342
+ reserved.existingProviderOperationAgeMs,
4341
4343
  };
4342
4344
  },
4343
4345
  async releaseCapacity({ leaseId }) {
4344
4346
  await deps.runWithClient((client) =>
4345
4347
  abandonRuntimeSandboxOperationReservation(
4346
4348
  client,
4347
- { operationKey: leaseId },
4349
+ { operationKey: leaseId, attempt: generation },
4348
4350
  options,
4349
4351
  ),
4350
4352
  );
@@ -286,6 +286,11 @@ export async function reserveRuntimeSandboxCapacityLease(
286
286
  activeLeases: number;
287
287
  wouldDefer: boolean;
288
288
  resumeExistingProviderOperation: boolean;
289
+ /**
290
+ * Database-clock age of a resumed operation. Absent on a same-key race and
291
+ * once the lease expires, when a new sandbox could no longer be promoted.
292
+ */
293
+ existingProviderOperationAgeMs?: number;
289
294
  }
290
295
  | { granted: false; limit: number; activeLeases: number }
291
296
  > {
@@ -316,6 +321,7 @@ export async function reserveRuntimeSandboxCapacityLease(
316
321
  provider_operation_token: string | null;
317
322
  attempt: number;
318
323
  environment: 'preview' | 'production';
324
+ age_ms: number | null;
319
325
  }>;
320
326
  existing_operation: {
321
327
  org_id: string;
@@ -361,7 +367,10 @@ export async function reserveRuntimeSandboxCapacityLease(
361
367
  SELECT jsonb_agg(pending)
362
368
  FROM (
363
369
  SELECT lease.lease_id, operation.provider_operation_token,
364
- operation.attempt, operation.environment
370
+ operation.attempt, operation.environment,
371
+ CASE WHEN lease.expires_at > clock_timestamp() THEN
372
+ extract(epoch FROM clock_timestamp() - operation.created_at) * 1000
373
+ END AS age_ms
365
374
  FROM ${operations} AS operation
366
375
  JOIN ${leases} AS lease ON lease.lease_id = operation.operation_key
367
376
  WHERE $6::boolean
@@ -503,6 +512,9 @@ export async function reserveRuntimeSandboxCapacityLease(
503
512
  activeLeases,
504
513
  wouldDefer,
505
514
  resumeExistingProviderOperation: true,
515
+ ...(pendingOperation.age_ms === null
516
+ ? {}
517
+ : { existingProviderOperationAgeMs: Number(pendingOperation.age_ms) }),
506
518
  };
507
519
  }
508
520
  }
@@ -874,7 +886,8 @@ export async function releaseRuntimeSandboxCapacityLease(
874
886
  */
875
887
  export async function abandonRuntimeSandboxOperationReservation(
876
888
  client: PostgresSchedulerQueryClient,
877
- input: { operationKey: string },
889
+ /** With `attempt`, an operation a newer attempt has adopted is left alone. */
890
+ input: { operationKey: string; attempt?: number },
878
891
  options?: Pick<PostgresSchedulerOptions, 'schema'>,
879
892
  ): Promise<boolean> {
880
893
  const { leases, operations, runs } = schemaTables(options);
@@ -899,6 +912,7 @@ export async function abandonRuntimeSandboxOperationReservation(
899
912
  updated_at = clock_timestamp()
900
913
  WHERE operation.operation_key = $1
901
914
  AND operation.state = $3
915
+ AND ($4::integer IS NULL OR operation.attempt <= $4)
902
916
  AND EXISTS (SELECT 1 FROM eligible_lease)
903
917
  RETURNING operation.operation_key
904
918
  ), released AS (
@@ -915,6 +929,7 @@ export async function abandonRuntimeSandboxOperationReservation(
915
929
  assertId(input.operationKey, 'operationKey'),
916
930
  RuntimeSandboxOperationState.Abandoned,
917
931
  RuntimeSandboxOperationState.Reserved,
932
+ input.attempt ?? null,
918
933
  ],
919
934
  );
920
935
  return result.rows.length === 1;
@@ -13,13 +13,13 @@ import {
13
13
  reportSetupCompleted,
14
14
  resolvePendingAuthClaimForResume,
15
15
  statusBannerLine
16
- } from "./chunk-BJOVX7EB.mjs";
17
- import "./chunk-XLOXUW5Y.mjs";
18
- import "./chunk-PJYTV24I.mjs";
16
+ } from "./chunk-7557D4FM.mjs";
17
+ import "./chunk-FS2RMEJ7.mjs";
18
+ import "./chunk-X2LUT22I.mjs";
19
19
  import "./chunk-4QF2K7TM.mjs";
20
20
  import "./chunk-DLIRSHV6.mjs";
21
21
  import "./chunk-HBL4PM5Q.mjs";
22
- import "./chunk-ZPV7DMAA.mjs";
22
+ import "./chunk-IXVABCNA.mjs";
23
23
  import "./chunk-WZYKRD7T.mjs";
24
24
  import "./chunk-KRD6H754.mjs";
25
25
  export {
@@ -0,0 +1,40 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+ var _chunkRNCIPLU5js = require('./chunk-RNCIPLU5.js');
17
+ require('./chunk-WTTHH2K3.js');
18
+ require('./chunk-RTR2KUU6.js');
19
+ require('./chunk-ALJJRZNJ.js');
20
+ require('./chunk-XNYIZMNQ.js');
21
+ require('./chunk-DIAWYWT5.js');
22
+ require('./chunk-RG644LJU.js');
23
+ require('./chunk-OG64RBAC.js');
24
+ require('./chunk-COGTRVWW.js');
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ exports.EXIT_WORKSPACE_MISMATCH = _chunkRNCIPLU5js.EXIT_WORKSPACE_MISMATCH; exports.authStatusLine = _chunkRNCIPLU5js.authStatusLine; exports.clearPendingClaim = _chunkRNCIPLU5js.clearPendingClaim; exports.clearSatisfiedPendingClaim = _chunkRNCIPLU5js.clearSatisfiedPendingClaim; exports.handleRegister = _chunkRNCIPLU5js.handleRegister; exports.handleStatus = _chunkRNCIPLU5js.handleStatus; exports.handleWait = _chunkRNCIPLU5js.handleWait; exports.httpJson = _chunkRNCIPLU5js.httpJson; exports.readPendingAuthClaim = _chunkRNCIPLU5js.readPendingAuthClaim; exports.readStatusBanner = _chunkRNCIPLU5js.readStatusBanner; exports.registerAuthCommands = _chunkRNCIPLU5js.registerAuthCommands; exports.reportSetupCompleted = _chunkRNCIPLU5js.reportSetupCompleted; exports.resolvePendingAuthClaimForResume = _chunkRNCIPLU5js.resolvePendingAuthClaimForResume; exports.statusBannerLine = _chunkRNCIPLU5js.statusBannerLine;