deepline 0.3.450 → 0.3.452

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 (102) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +5 -1
  3. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +133 -2
  4. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +49 -11
  5. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +6 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +3 -1
  8. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +17 -2
  9. package/dist/cli/auth-36DQP46D.js +40 -0
  10. package/dist/cli/{auth-CHYW6BU3.mjs → auth-DKZLB6GN.mjs} +4 -4
  11. package/dist/cli/{billing-NCV2CBLH.js → billing-CN3XSVER.js} +73 -73
  12. package/dist/cli/{billing-YADYH5P7.mjs → billing-DOFXWAZR.mjs} +4 -4
  13. package/dist/cli/{chunk-EKVOSR3S.mjs → chunk-2GMAPSJU.mjs} +5 -5
  14. package/dist/cli/{chunk-B2V2F3KV.mjs → chunk-2SICEJBN.mjs} +1 -1
  15. package/dist/cli/{chunk-UMA7425N.js → chunk-2VERHTKO.js} +2 -2
  16. package/dist/cli/{chunk-IGMBTEF7.js → chunk-5DRGDSJL.js} +26 -26
  17. package/dist/cli/{chunk-IESQOIOE.js → chunk-74BPYDDG.js} +8 -8
  18. package/dist/cli/{chunk-IYBC6WON.js → chunk-7JSZOUNU.js} +1 -1
  19. package/dist/cli/{chunk-OZ5ME7BP.js → chunk-7OI33KE5.js} +2 -2
  20. package/dist/cli/{chunk-QROZFMGC.mjs → chunk-ELULDUX3.mjs} +1 -1
  21. package/dist/cli/{chunk-6TABNDCB.js → chunk-ETFVH7PO.js} +4 -4
  22. package/dist/cli/{chunk-ZYORWYLP.mjs → chunk-FIQ2F5LA.mjs} +2 -2
  23. package/dist/cli/{chunk-2VKDHJU3.js → chunk-G5BMPTZD.js} +81 -81
  24. package/dist/cli/{chunk-JWZIZH2C.js → chunk-J5O4AXSO.js} +10 -10
  25. package/dist/cli/{chunk-3JEMYGIR.mjs → chunk-JJOSUZMS.mjs} +1 -1
  26. package/dist/cli/{chunk-VYMLYV2K.js → chunk-JT4ZSWBK.js} +16 -16
  27. package/dist/cli/{chunk-N42KCXPD.mjs → chunk-KQUDU3ZE.mjs} +2 -2
  28. package/dist/cli/{chunk-LTQCEQOZ.js → chunk-L2GATUZK.js} +20 -20
  29. package/dist/cli/{chunk-XUD5AOQY.js → chunk-L6YCGSL4.js} +35 -35
  30. package/dist/cli/{chunk-7IUG4STX.js → chunk-M4FFNUF4.js} +50 -50
  31. package/dist/cli/{chunk-4Z356NPN.mjs → chunk-PBQSX6ES.mjs} +1 -1
  32. package/dist/cli/{chunk-UJHJXWM4.mjs → chunk-POSAVPQZ.mjs} +2 -2
  33. package/dist/cli/{chunk-HRRVDDFH.mjs → chunk-QK65KBWN.mjs} +8 -8
  34. package/dist/cli/{chunk-3SRJO6H4.mjs → chunk-R7YZKHN5.mjs} +3 -3
  35. package/dist/cli/{chunk-AJUNUE32.mjs → chunk-RFDIXLRX.mjs} +1 -1
  36. package/dist/cli/{chunk-CA3NM3W4.mjs → chunk-RNM4HG3W.mjs} +3 -3
  37. package/dist/cli/{chunk-5R7YPB5X.mjs → chunk-SM5RZ5JC.mjs} +1 -1
  38. package/dist/cli/{chunk-ZEVUPOF6.mjs → chunk-TXN27XQQ.mjs} +2 -2
  39. package/dist/cli/{chunk-2UNTSLTR.mjs → chunk-UGPGB4C6.mjs} +3 -3
  40. package/dist/cli/{chunk-2SASGLVN.js → chunk-WW63S4RC.js} +6 -6
  41. package/dist/cli/{chunk-B4T7EFBZ.mjs → chunk-X4IMX5AO.mjs} +4 -4
  42. package/dist/cli/{chunk-NSIOVSNZ.js → chunk-YWL4ULLT.js} +52 -52
  43. package/dist/cli/{chunk-CBM27PDJ.js → chunk-ZH6HFV7Y.js} +8 -8
  44. package/dist/cli/{chunk-47GRLLV2.js → chunk-ZKGK2JU3.js} +6 -6
  45. package/dist/cli/{csv-VQLS5D7H.js → csv-N25FMDZQ.js} +12 -12
  46. package/dist/cli/{csv-7PXCJKYS.mjs → csv-QUNUQZYC.mjs} +3 -3
  47. package/dist/cli/{db-XDUC3MFP.js → db-2SGG56WR.js} +25 -25
  48. package/dist/cli/{db-JYLMLQQO.mjs → db-WYWDUYXS.mjs} +4 -4
  49. package/dist/cli/{describe-LDHY5HTB.mjs → describe-4RBUIHR7.mjs} +12 -12
  50. package/dist/cli/{describe-G6SRQQHS.js → describe-QQ2XL6PV.js} +16 -16
  51. package/dist/cli/{executions-M7MDBFHA.mjs → executions-WOBIMQ7H.mjs} +4 -4
  52. package/dist/cli/{executions-HPI65XBL.js → executions-YLJHAHHX.js} +6 -6
  53. package/dist/cli/{feedback-Y66JKRPN.js → feedback-D653FAXY.js} +7 -7
  54. package/dist/cli/{feedback-6V4DDJVD.mjs → feedback-VCGVROTY.mjs} +3 -3
  55. package/dist/cli/{git-BTKGTTGF.mjs → git-SZ6RSLFN.mjs} +4 -4
  56. package/dist/cli/git-T6LBJEY6.js +24 -0
  57. package/dist/cli/index.js +131 -131
  58. package/dist/cli/index.mjs +36 -36
  59. package/dist/cli/{legacy-noops-DEVCEE64.js → legacy-noops-TXZ75CWS.js} +7 -7
  60. package/dist/cli/{legacy-noops-MUBHYOEG.mjs → legacy-noops-UGLTI2ZY.mjs} +4 -4
  61. package/dist/cli/{monitors-SOGDSYPL.mjs → monitors-HLIW4AIL.mjs} +7 -5
  62. package/dist/cli/{monitors-2DJFA7XX.js → monitors-VC6YSBYX.js} +87 -85
  63. package/dist/cli/{org-UWMWVV73.js → org-I3VQDIGZ.js} +66 -66
  64. package/dist/cli/{org-D6ZFFG4D.mjs → org-X4MVTSKM.mjs} +4 -4
  65. package/dist/cli/{play-P423OXCU.js → play-7TLGGN66.js} +283 -283
  66. package/dist/cli/{play-TIR2S6IA.mjs → play-EAYGEAMI.mjs} +10 -10
  67. package/dist/cli/{providers-6F5F6D4O.js → providers-IZ3YWZ4E.js} +7 -7
  68. package/dist/cli/{providers-HRDAG3UX.mjs → providers-MBTMUEGX.mjs} +4 -4
  69. package/dist/cli/{quickstart-SOWZOPAS.js → quickstart-MBDEV4RJ.js} +5 -5
  70. package/dist/cli/{quickstart-UMZS7HBY.mjs → quickstart-MDW2NMAS.mjs} +3 -3
  71. package/dist/cli/{search-5FGZVQSP.mjs → search-4PQZYRQO.mjs} +5 -5
  72. package/dist/cli/search-5B4ZM7VS.js +30 -0
  73. package/dist/cli/{secrets-7E2TOVYP.js → secrets-3S7KUS2H.js} +13 -13
  74. package/dist/cli/{secrets-SACNVEWL.mjs → secrets-S55UCYYR.mjs} +4 -4
  75. package/dist/cli/{sessions-5VCX7MYU.mjs → sessions-T6XVN737.mjs} +4 -4
  76. package/dist/cli/{sessions-FNON33JD.js → sessions-UEHVIB6W.js} +5 -5
  77. package/dist/cli/{settings-EJACNJR4.mjs → settings-CGP7XMJZ.mjs} +8 -8
  78. package/dist/cli/{settings-6MYQGDQX.js → settings-MYAUWNTF.js} +75 -75
  79. package/dist/cli/{setup-QVEIV4R4.js → setup-5Z5HAWEG.js} +42 -42
  80. package/dist/cli/{setup-KJ7IADVC.mjs → setup-U66NZQXB.mjs} +7 -7
  81. package/dist/cli/{skills-SUV3DJEU.mjs → skills-2JS3SNFA.mjs} +5 -5
  82. package/dist/cli/skills-JXPQFJAJ.js +29 -0
  83. package/dist/cli/{tools-H4ZL5QDZ.mjs → tools-G3VYZKTO.mjs} +12 -12
  84. package/dist/cli/tools-RHRJ4SLY.js +44 -0
  85. package/dist/cli/update-5YBPJ3EQ.js +31 -0
  86. package/dist/cli/{update-5UGF4334.mjs → update-C7CLWWIW.mjs} +7 -7
  87. package/dist/cli/{workflow-RABLQNGO.mjs → workflow-EUMRVXU7.mjs} +5 -5
  88. package/dist/cli/{workflow-THIBJ3VE.js → workflow-TBKVIN4S.js} +15 -15
  89. package/dist/index.js +6 -6
  90. package/dist/index.mjs +3 -3
  91. package/dist/install-integrity.json +78 -78
  92. package/dist/release.d.mts +1 -1
  93. package/dist/release.d.ts +1 -1
  94. package/dist/release.js +2 -2
  95. package/dist/release.mjs +1 -1
  96. package/package.json +1 -1
  97. package/dist/cli/auth-3LOZKBPO.js +0 -40
  98. package/dist/cli/git-VVC5BRCG.js +0 -24
  99. package/dist/cli/search-BDIO4BBH.js +0 -30
  100. package/dist/cli/skills-YPH2KNH6.js +0 -29
  101. package/dist/cli/tools-X23MQMNE.js +0 -44
  102. package/dist/cli/update-GZOPNTGJ.js +0 -31
@@ -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.450',
208
+ version: '0.3.452',
209
209
  updateSummary: {
210
210
  introducedIn: '0.3.90',
211
211
  summary:
@@ -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;
@@ -64,6 +64,14 @@ const TERMINAL_TRANSPORT_OUTPUT_WARNINGS_MAX_BYTES = 32 * 1024;
64
64
  const TERMINAL_TRANSPORT_RUNTIME_DIAGNOSTICS_MAX_BYTES = 16 * 1024;
65
65
  const TERMINAL_TRANSPORT_ERROR_MAX_BYTES = 64 * 1024;
66
66
  const TERMINAL_TRANSPORT_TABLE_NAMESPACE_MAX_BYTES = 8 * 1024;
67
+ /**
68
+ * Leaves room in the gateway body for the action, run ID and log offset around
69
+ * the result. `terminalRequestBody` drops progress events to fit on its own.
70
+ */
71
+ const TERMINAL_SUSPENDED_RESULT_MAX_BYTES =
72
+ RUNNER_TERMINAL_PUSH_MAX_BODY_BYTES - 4 * 1024;
73
+ const RUNTIME_SUSPENDED_CHECKPOINT_TOO_LARGE_CODE =
74
+ 'RUNTIME_SUSPENDED_CHECKPOINT_TOO_LARGE';
67
75
 
68
76
  type CompletedRunnerResult = Extract<PlayRunnerResult, { status: 'completed' }>;
69
77
  type SuspendedRunnerResult = Extract<PlayRunnerResult, { status: 'suspended' }>;
@@ -288,6 +296,7 @@ function appendTerminalDiagnosticsMarker(
288
296
  logContexts?: Array<PlayLogContext | null>,
289
297
  logIds?: string[],
290
298
  logMetadata?: Array<PlayLogMetadata | null>,
299
+ completeness = 'the authored play output is complete.',
291
300
  ): {
292
301
  logs: string[];
293
302
  logContexts?: Array<PlayLogContext | null>;
@@ -296,7 +305,7 @@ function appendTerminalDiagnosticsMarker(
296
305
  } {
297
306
  const marker =
298
307
  `[deepline] terminal diagnostic metadata was bounded (${truncatedFields.join(', ')}); ` +
299
- 'the authored play output is complete.';
308
+ completeness;
300
309
  const marked = [marker, ...logs];
301
310
  const markedContexts = logContexts ? [null, ...logContexts] : undefined;
302
311
  const markedMetadata = logMetadata ? [null, ...logMetadata] : undefined;
@@ -495,6 +504,126 @@ function boundSettledTerminalTransportDiagnostics(
495
504
  };
496
505
  }
497
506
 
507
+ /**
508
+ * The gateway rejects a body over its ceiling before reading the action, and
509
+ * that line is also too long for the crash pusher's output tail, so an oversized
510
+ * suspended result surfaces only as an unexplained "exited with code 0". Keep
511
+ * ordinary suspensions byte-identical. When one would not fit, drop runner
512
+ * diagnostics first. The checkpoint is never sliced: without it the run cannot
513
+ * resume, so a checkpoint that alone exceeds the ceiling is an explicit failure.
514
+ */
515
+ function suspendedResultWithinGatewayBody(
516
+ result: SuspendedRunnerResult & IncludedResumeCheckpoint,
517
+ ): PlayRunnerTerminalTransportResult {
518
+ if (fitsJsonByteLimit(result, TERMINAL_SUSPENDED_RESULT_MAX_BYTES)) {
519
+ return result;
520
+ }
521
+ const logProjection = retainTerminalLogTailWithRuntimeDiagnostics(
522
+ result.logs,
523
+ result.logContexts,
524
+ result.logMetadata,
525
+ result.logIds,
526
+ );
527
+ const stats =
528
+ result.stats.runtimeWorkCounterSegment === undefined
529
+ ? result.stats
530
+ : {
531
+ // The worker reads this to number the resumed segment, so it must
532
+ // be the first key retained rather than whichever one fits.
533
+ runtimeWorkCounterSegment: result.stats.runtimeWorkCounterSegment,
534
+ ...result.stats,
535
+ };
536
+ const statsProjection = retainRecordWithinJsonByteLimit(
537
+ stats,
538
+ TERMINAL_TRANSPORT_STATS_MAX_BYTES,
539
+ );
540
+ const stepsProjection = retainArrayWithinJsonByteLimit(
541
+ result.steps,
542
+ TERMINAL_TRANSPORT_STEPS_MAX_BYTES,
543
+ 'head',
544
+ );
545
+ const truncatedFields = [
546
+ ...(logProjection.truncated ? ['logs'] : []),
547
+ ...(statsProjection.truncated ? ['stats'] : []),
548
+ ...(stepsProjection.truncated ? ['steps'] : []),
549
+ ];
550
+ const projectAligned = <T>(values: readonly T[] | undefined) =>
551
+ values?.length
552
+ ? logProjection.indexes.map((index) => values[index]!)
553
+ : undefined;
554
+ const boundedLogs =
555
+ truncatedFields.length > 0
556
+ ? appendTerminalDiagnosticsMarker(
557
+ logProjection.values,
558
+ truncatedFields,
559
+ projectAligned(result.logContexts),
560
+ projectAligned(result.logIds),
561
+ projectAligned(result.logMetadata),
562
+ 'the resume checkpoint is complete.',
563
+ )
564
+ : {
565
+ logs: logProjection.values,
566
+ logContexts: projectAligned(result.logContexts),
567
+ logIds: projectAligned(result.logIds),
568
+ logMetadata: projectAligned(result.logMetadata),
569
+ };
570
+ const bounded = {
571
+ ...result,
572
+ logs: boundedLogs.logs,
573
+ logContexts: boundedLogs.logContexts,
574
+ logMetadata: boundedLogs.logMetadata,
575
+ logIds: boundedLogs.logIds,
576
+ stats: statsProjection.value,
577
+ steps: stepsProjection.values,
578
+ };
579
+ if (fitsJsonByteLimit(bounded, TERMINAL_SUSPENDED_RESULT_MAX_BYTES)) {
580
+ return bounded;
581
+ }
582
+ // A run that can still resume must not fail over diagnostics, so keep only
583
+ // what the worker needs before giving up on the checkpoint.
584
+ const segment = result.stats.runtimeWorkCounterSegment;
585
+ const withoutDiagnostics = {
586
+ ...result,
587
+ logs: [
588
+ '[deepline] terminal diagnostic metadata was dropped (logs, stats, steps); the resume checkpoint is complete.',
589
+ ],
590
+ logContexts: undefined,
591
+ logMetadata: undefined,
592
+ logIds: undefined,
593
+ stats: segment === undefined ? {} : { runtimeWorkCounterSegment: segment },
594
+ steps: [],
595
+ };
596
+ if (
597
+ fitsJsonByteLimit(withoutDiagnostics, TERMINAL_SUSPENDED_RESULT_MAX_BYTES)
598
+ ) {
599
+ return withoutDiagnostics;
600
+ }
601
+ const { checkpoint: _checkpoint, suspension, ...diagnostics } = bounded;
602
+ const checkpointMiB = (result.checkpointBytes / (1024 * 1024)).toFixed(2);
603
+ const limitMiB = RUNNER_TERMINAL_PUSH_MAX_BODY_BYTES / (1024 * 1024);
604
+ const message =
605
+ `The play paused (${suspension.kind}) with a ${checkpointMiB} MiB resume checkpoint, which does not fit the ${limitMiB} MiB limit, so it cannot resume. ` +
606
+ 'Split the work into smaller runs, or finish fewer tool calls before the pause.';
607
+ const error = `${RUNTIME_SUSPENDED_CHECKPOINT_TOO_LARGE_CODE}: ${message}`;
608
+ return {
609
+ ...diagnostics,
610
+ status: 'failed',
611
+ error,
612
+ errors: [
613
+ {
614
+ code: RUNTIME_SUSPENDED_CHECKPOINT_TOO_LARGE_CODE,
615
+ phase: 'runtime',
616
+ message,
617
+ retryable: false,
618
+ cause: error,
619
+ },
620
+ ],
621
+ checkpointDisposition:
622
+ RUNNER_TERMINAL_CHECKPOINT_DISPOSITION.OMITTED_TERMINAL_REPLAY,
623
+ checkpointBytes: result.checkpointBytes,
624
+ };
625
+ }
626
+
498
627
  export function runnerTerminalResultForTransport(
499
628
  result: PlayRunnerResult | PlayRunnerTerminalTransportResult,
500
629
  ): PlayRunnerTerminalTransportResult {
@@ -534,7 +663,9 @@ export function runnerTerminalResultForTransport(
534
663
  if (transportResult.status === 'suspended') {
535
664
  // A suspended result retains its exact checkpoint because it is needed to
536
665
  // resume. Its checkpoint follows the dedicated receipt transport contract.
537
- return transportResult;
666
+ return suspendedResultWithinGatewayBody(
667
+ transportResult as SuspendedRunnerResult & IncludedResumeCheckpoint,
668
+ );
538
669
  }
539
670
  const bounded = boundSettledTerminalTransportDiagnostics(transportResult);
540
671
  if (!fitsJsonByteLimit(bounded, TERMINAL_RUN_RESULT_MAX_BYTES)) {
@@ -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;
@@ -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 _chunkM4FFNUF4js = require('./chunk-M4FFNUF4.js');
17
+ require('./chunk-ZKGK2JU3.js');
18
+ require('./chunk-ETFVH7PO.js');
19
+ require('./chunk-ALJJRZNJ.js');
20
+ require('./chunk-XNYIZMNQ.js');
21
+ require('./chunk-DIAWYWT5.js');
22
+ require('./chunk-7JSZOUNU.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 = _chunkM4FFNUF4js.EXIT_WORKSPACE_MISMATCH; exports.authStatusLine = _chunkM4FFNUF4js.authStatusLine; exports.clearPendingClaim = _chunkM4FFNUF4js.clearPendingClaim; exports.clearSatisfiedPendingClaim = _chunkM4FFNUF4js.clearSatisfiedPendingClaim; exports.handleRegister = _chunkM4FFNUF4js.handleRegister; exports.handleStatus = _chunkM4FFNUF4js.handleStatus; exports.handleWait = _chunkM4FFNUF4js.handleWait; exports.httpJson = _chunkM4FFNUF4js.httpJson; exports.readPendingAuthClaim = _chunkM4FFNUF4js.readPendingAuthClaim; exports.readStatusBanner = _chunkM4FFNUF4js.readStatusBanner; exports.registerAuthCommands = _chunkM4FFNUF4js.registerAuthCommands; exports.reportSetupCompleted = _chunkM4FFNUF4js.reportSetupCompleted; exports.resolvePendingAuthClaimForResume = _chunkM4FFNUF4js.resolvePendingAuthClaimForResume; exports.statusBannerLine = _chunkM4FFNUF4js.statusBannerLine;
@@ -13,13 +13,13 @@ import {
13
13
  reportSetupCompleted,
14
14
  resolvePendingAuthClaimForResume,
15
15
  statusBannerLine
16
- } from "./chunk-N42KCXPD.mjs";
17
- import "./chunk-4Z356NPN.mjs";
18
- import "./chunk-5R7YPB5X.mjs";
16
+ } from "./chunk-KQUDU3ZE.mjs";
17
+ import "./chunk-PBQSX6ES.mjs";
18
+ import "./chunk-SM5RZ5JC.mjs";
19
19
  import "./chunk-4QF2K7TM.mjs";
20
20
  import "./chunk-DLIRSHV6.mjs";
21
21
  import "./chunk-HBL4PM5Q.mjs";
22
- import "./chunk-AJUNUE32.mjs";
22
+ import "./chunk-RFDIXLRX.mjs";
23
23
  import "./chunk-WZYKRD7T.mjs";
24
24
  import "./chunk-KRD6H754.mjs";
25
25
  export {