deepline 0.1.221 → 0.1.222

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.
@@ -108,10 +108,10 @@ export const SDK_RELEASE = {
108
108
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
109
109
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
110
110
  // automatically without blocking their current command.
111
- version: '0.1.221',
111
+ version: '0.1.222',
112
112
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
113
113
  supportPolicy: {
114
- latest: '0.1.221',
114
+ latest: '0.1.222',
115
115
  minimumSupported: '0.1.53',
116
116
  deprecatedBelow: '0.1.219',
117
117
  commandMinimumSupported: [
@@ -288,6 +288,9 @@ const MAP_INCREMENTAL_PERSIST_CHUNK_ROWS = 100;
288
288
  const MAP_INCREMENTAL_PERSIST_CHUNK_BYTES = 1 * 1024 * 1024;
289
289
  const MAP_INCREMENTAL_PERSIST_INTERVAL_MS = 100;
290
290
  const MAP_FRAME_FLUSH_INTERVAL_MS = 250;
291
+ // Batchable calls wait at most this long for same-key row continuations. The
292
+ // window is fixed from the first item and never resets on later arrivals.
293
+ const TOOL_BATCH_COALESCE_WINDOW_MS = 5;
291
294
  const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
292
295
  const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
293
296
  const DEEPLINEAGENT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000;
@@ -1196,6 +1199,14 @@ function createPacingResolver(
1196
1199
  export class PlayContextImpl {
1197
1200
  private rowStates = new Map<number, RowState>();
1198
1201
  private toolCallQueue: ToolCallRequest[] = [];
1202
+ /**
1203
+ * Fixed, non-resetting coalescing deadlines for batchable ready work. A
1204
+ * deadline starts when the first request enters an empty batch bucket. New
1205
+ * arrivals never push it back, so sustained traffic cannot starve dispatch.
1206
+ */
1207
+ private readonly toolBatchQueuedAtByKey = new Map<string, number>();
1208
+ private readonly toolDispatcherWakeWaiters = new Set<() => void>();
1209
+ private toolDispatcherFailure: unknown | null = null;
1199
1210
  private toolCallResolvers = new Map<
1200
1211
  string,
1201
1212
  { resolve: (value: unknown) => void; reject: (reason: unknown) => void }
@@ -6064,33 +6075,172 @@ export class PlayContextImpl {
6064
6075
  }
6065
6076
  }
6066
6077
 
6078
+ private toolBatchCoalesceKey(request: ToolCallRequest): string | null {
6079
+ const strategy =
6080
+ this.#options.getBatchOperationStrategy?.(request.toolId) ?? null;
6081
+ if (!strategy) return null;
6082
+ return [
6083
+ request.toolId,
6084
+ request.executionAuthScopeDigest ?? '',
6085
+ String(strategy.toBucketKey(request.input)),
6086
+ ].join('\u0000');
6087
+ }
6088
+
6089
+ private wakeToolDispatcher(): void {
6090
+ const waiters = [...this.toolDispatcherWakeWaiters];
6091
+ this.toolDispatcherWakeWaiters.clear();
6092
+ for (const wake of waiters) wake();
6093
+ }
6094
+
6095
+ private enqueueToolCall(request: ToolCallRequest): void {
6096
+ if (this.toolDispatcherFailure != null) {
6097
+ const resolver = this.toolCallResolvers.get(request.callId);
6098
+ if (resolver) {
6099
+ resolver.reject(this.toolDispatcherFailure);
6100
+ this.toolCallResolvers.delete(request.callId);
6101
+ }
6102
+ return;
6103
+ }
6104
+ this.toolCallQueue.push(request);
6105
+ const batchKey = this.toolBatchCoalesceKey(request);
6106
+ if (batchKey && !this.toolBatchQueuedAtByKey.has(batchKey)) {
6107
+ this.toolBatchQueuedAtByKey.set(batchKey, Date.now());
6108
+ }
6109
+ this.wakeToolDispatcher();
6110
+ }
6111
+
6112
+ private rejectQueuedToolCalls(error: unknown): void {
6113
+ const queued = this.toolCallQueue;
6114
+ this.toolCallQueue = [];
6115
+ this.toolBatchQueuedAtByKey.clear();
6116
+ for (const request of queued) {
6117
+ const resolver = this.toolCallResolvers.get(request.callId);
6118
+ if (!resolver) continue;
6119
+ resolver.reject(error);
6120
+ this.toolCallResolvers.delete(request.callId);
6121
+ }
6122
+ }
6123
+
6124
+ private takeDispatchableToolCalls(nowMs: number): {
6125
+ requests: ToolCallRequest[];
6126
+ nextDeadlineMs: number | null;
6127
+ } {
6128
+ if (this.toolCallQueue.length === 0) {
6129
+ return { requests: [], nextDeadlineMs: null };
6130
+ }
6131
+
6132
+ const batchCounts = new Map<string, number>();
6133
+ const batchMaxSizes = new Map<string, number>();
6134
+ for (const request of this.toolCallQueue) {
6135
+ const batchKey = this.toolBatchCoalesceKey(request);
6136
+ if (!batchKey) continue;
6137
+ batchCounts.set(batchKey, (batchCounts.get(batchKey) ?? 0) + 1);
6138
+ const strategy =
6139
+ this.#options.getBatchOperationStrategy?.(request.toolId) ?? null;
6140
+ if (strategy) batchMaxSizes.set(batchKey, strategy.maxBatchSize);
6141
+ }
6142
+
6143
+ const readyBatchKeys = new Set<string>();
6144
+ let nextDeadlineMs: number | null = null;
6145
+ for (const [batchKey, count] of batchCounts) {
6146
+ const queuedAt = this.toolBatchQueuedAtByKey.get(batchKey) ?? nowMs;
6147
+ if (!this.toolBatchQueuedAtByKey.has(batchKey)) {
6148
+ this.toolBatchQueuedAtByKey.set(batchKey, queuedAt);
6149
+ }
6150
+ const deadline = queuedAt + TOOL_BATCH_COALESCE_WINDOW_MS;
6151
+ const maxBatchSize = batchMaxSizes.get(batchKey) ?? 1;
6152
+ if (count >= maxBatchSize || deadline <= nowMs) {
6153
+ readyBatchKeys.add(batchKey);
6154
+ } else {
6155
+ nextDeadlineMs =
6156
+ nextDeadlineMs == null
6157
+ ? deadline
6158
+ : Math.min(nextDeadlineMs, deadline);
6159
+ }
6160
+ }
6161
+
6162
+ const requests: ToolCallRequest[] = [];
6163
+ const remaining: ToolCallRequest[] = [];
6164
+ for (const request of this.toolCallQueue) {
6165
+ const batchKey = this.toolBatchCoalesceKey(request);
6166
+ if (!batchKey || readyBatchKeys.has(batchKey)) {
6167
+ requests.push(request);
6168
+ } else {
6169
+ remaining.push(request);
6170
+ }
6171
+ }
6172
+ this.toolCallQueue = remaining;
6173
+ for (const batchKey of readyBatchKeys) {
6174
+ this.toolBatchQueuedAtByKey.delete(batchKey);
6175
+ }
6176
+ return { requests, nextDeadlineMs };
6177
+ }
6178
+
6179
+ private waitForToolDispatcherWake(deadlineMs: number | null): Promise<void> {
6180
+ return new Promise((resolve) => {
6181
+ let timer: ReturnType<typeof setTimeout> | null = null;
6182
+ const wake = () => {
6183
+ if (timer) clearTimeout(timer);
6184
+ this.toolDispatcherWakeWaiters.delete(wake);
6185
+ resolve();
6186
+ };
6187
+ this.toolDispatcherWakeWaiters.add(wake);
6188
+ if (deadlineMs != null) {
6189
+ timer = setTimeout(wake, Math.max(0, deadlineMs - Date.now()));
6190
+ }
6191
+ });
6192
+ }
6193
+
6067
6194
  private async drainQueuedWork<T>(promises: Promise<T>[]): Promise<void> {
6068
- // Drain loop: each pass resolves queued tool calls.
6069
- // When a batch resolves, rows resume and may queue MORE calls
6070
- // (e.g. row does tools.execute('a') then tools.execute('b') sequentially).
6071
- // We keep looping until nothing new is queued and all rows finish.
6072
- //
6073
- // Important: an unresolved Promise by itself does not keep Node alive. The
6074
- // play runner is a short-lived child process, so parking on
6075
- // Promise.allSettled(promises) while there is no timer/socket/file handle can
6076
- // let Node exit 0 before main() emits the result envelope. That presents as
6077
- // "Local play runner produced no result" even though the real bug was a
6078
- // map row waiting for queued tool work. Always race row settlement
6079
- // against a small timer and re-check the queues instead of blocking forever
6080
- // on promises that may be waiting for this drain loop to do the next batch.
6081
- const raceSettled = () =>
6082
- Promise.race([
6083
- Promise.allSettled(promises).then(() => 'done' as const),
6084
- new Promise<'pending'>((r) => setTimeout(() => r('pending'), 50)),
6085
- ]);
6086
-
6087
- let pass = 0;
6088
- while (true) {
6089
- const hasPendingWork = this.toolCallQueue.length > 0;
6090
-
6091
- if (!hasPendingWork) {
6092
- const status = await raceSettled();
6093
- if (status === 'done' && this.toolCallQueue.length === 0) {
6195
+ // One dispatcher owns ready work, fixed batch coalescing deadlines, and
6196
+ // the in-flight registry. A row resumes after its own receipt persists; it
6197
+ // never waits for unrelated sibling calls from the previous column.
6198
+ const inFlightToolExecutions = new Set<Promise<void>>();
6199
+ let rowsSettled = false;
6200
+ void Promise.allSettled(promises).then(() => {
6201
+ rowsSettled = true;
6202
+ this.wakeToolDispatcher();
6203
+ });
6204
+ // A pending Promise does not keep a short-lived Node runner alive. Keep one
6205
+ // handle open without polling scheduler state; actual work wakes the
6206
+ // dispatcher through queue/in-flight/row-settlement signals.
6207
+ const keepAlive = setInterval(() => undefined, 1_000);
6208
+ try {
6209
+ let pass = 0;
6210
+ while (true) {
6211
+ if (this.toolDispatcherFailure != null) {
6212
+ this.rejectQueuedToolCalls(this.toolDispatcherFailure);
6213
+ await Promise.allSettled([...inFlightToolExecutions]);
6214
+ throw this.toolDispatcherFailure;
6215
+ }
6216
+
6217
+ const dispatchable = this.takeDispatchableToolCalls(Date.now());
6218
+ if (dispatchable.requests.length > 0) {
6219
+ pass += 1;
6220
+ this.log(` Batch pass ${pass}`);
6221
+ this.log(
6222
+ ` Dispatcher launch: ready=${dispatchable.requests.length} ` +
6223
+ `queued=${this.toolCallQueue.length} ` +
6224
+ `in_flight_groups=${inFlightToolExecutions.size}`,
6225
+ );
6226
+ const tracked = this.executeBatchedToolCalls(dispatchable.requests)
6227
+ .catch((error) => {
6228
+ this.toolDispatcherFailure ??= error;
6229
+ this.rejectQueuedToolCalls(error);
6230
+ })
6231
+ .finally(() => {
6232
+ inFlightToolExecutions.delete(tracked);
6233
+ this.wakeToolDispatcher();
6234
+ });
6235
+ inFlightToolExecutions.add(tracked);
6236
+ continue;
6237
+ }
6238
+
6239
+ if (
6240
+ rowsSettled &&
6241
+ this.toolCallQueue.length === 0 &&
6242
+ inFlightToolExecutions.size === 0
6243
+ ) {
6094
6244
  if (!this.activeDatasetStep) {
6095
6245
  const childPlaySuspension =
6096
6246
  this.consumePendingChildPlaySuspension();
@@ -6101,23 +6251,10 @@ export class PlayContextImpl {
6101
6251
  break;
6102
6252
  }
6103
6253
 
6104
- // Promises are still running, or they settled while scheduling one last
6105
- // batch. Give resolver microtasks a turn, then loop back and drain any
6106
- // newly queued work. This timer is deliberately tiny; it is here for
6107
- // correctness/liveness, not throughput throttling.
6108
- await new Promise((r) => setTimeout(r, 10));
6109
- continue;
6110
- }
6111
-
6112
- pass++;
6113
- this.log(` Batch pass ${pass}`);
6114
- this.log(
6115
- ` Queue depth before drain: tool_calls=${this.toolCallQueue.length}`,
6116
- );
6117
-
6118
- if (this.toolCallQueue.length > 0) {
6119
- await this.executeBatchedToolCalls();
6254
+ await this.waitForToolDispatcherWake(dispatchable.nextDeadlineMs);
6120
6255
  }
6256
+ } finally {
6257
+ clearInterval(keepAlive);
6121
6258
  }
6122
6259
  }
6123
6260
 
@@ -6392,7 +6529,7 @@ export class PlayContextImpl {
6392
6529
  toolId,
6393
6530
  options?.timeoutMs,
6394
6531
  );
6395
- this.toolCallQueue.push({
6532
+ this.enqueueToolCall({
6396
6533
  callId,
6397
6534
  cacheKey: toolResultCacheKey,
6398
6535
  cacheable: cacheableToolResult,
@@ -7407,10 +7544,9 @@ export class PlayContextImpl {
7407
7544
 
7408
7545
  // ——— Batched tool call execution ———
7409
7546
 
7410
- private async executeBatchedToolCalls(): Promise<void> {
7411
- const queuedToolCalls = this.toolCallQueue;
7412
- this.toolCallQueue = [];
7413
-
7547
+ private async executeBatchedToolCalls(
7548
+ queuedToolCalls: ToolCallRequest[],
7549
+ ): Promise<void> {
7414
7550
  // Group by toolId
7415
7551
  const byTool = new Map<string, ToolCallRequest[]>();
7416
7552
  for (const req of queuedToolCalls) {
@@ -7418,7 +7554,7 @@ export class PlayContextImpl {
7418
7554
  byTool.get(req.toolId)!.push(req);
7419
7555
  }
7420
7556
 
7421
- await Promise.all(
7557
+ const toolSettlements = await Promise.allSettled(
7422
7558
  [...byTool.entries()].map(async ([toolId, requests]) => {
7423
7559
  this.log(`Executing tool batch ${toolId}: ${requests.length} calls`);
7424
7560
  const liveStepResults = new Map<string, unknown>();
@@ -8341,6 +8477,11 @@ export class PlayContextImpl {
8341
8477
  }
8342
8478
  }),
8343
8479
  );
8480
+ const rejected = toolSettlements.find(
8481
+ (settlement): settlement is PromiseRejectedResult =>
8482
+ settlement.status === 'rejected',
8483
+ );
8484
+ if (rejected) throw rejected.reason;
8344
8485
  }
8345
8486
 
8346
8487
  private async executeResolvedPlay(
@@ -7,17 +7,15 @@ import { isIsolatedRuntimeSchedulerSchema } from '@shared_libs/play-runtime/runt
7
7
 
8
8
  const DAYTONA_CREATE_TIMEOUT_SECONDS = 10;
9
9
  const DAYTONA_CREATE_RETRY_DELAYS_MS = [0, 500, 1_500] as const;
10
- const DAYTONA_AUTO_STOP_INTERVAL_MINUTES = 5;
10
+ // A detached runner is bounded by both the play runtime ceiling and Daytona's
11
+ // own inactivity stop. No background activity refresh keeps a wedged sandbox
12
+ // alive past those limits.
13
+ const DAYTONA_AUTO_STOP_INTERVAL_MINUTES = 30;
11
14
  const DAYTONA_AUTO_ARCHIVE_INTERVAL_MINUTES = 15;
12
15
  const DAYTONA_SANDBOX_LABEL_SOURCE = 'deepline-play-runner';
13
- // The hosted Daytona API pins sandbox resources to the creating snapshot: it
14
- // rejects create-time resource overrides for snapshot sandboxes (400 "Cannot
15
- // specify Sandbox resources when using a snapshot") and does not serve
16
- // POST /sandbox/:id/resize (404 "Cannot POST"). The resource boundary is
17
- // therefore the default snapshot's grant, verified against these pins after
18
- // create. If Daytona changes the default snapshot's resources, sandbox
19
- // acquisition fails loudly instead of silently running plays on a different
20
- // compute boundary; bump these pins deliberately when that happens.
16
+ // The sandbox must be created at its final resource boundary. Do not add a
17
+ // resize call here: sandbox acquisition is launch-critical, and every extra
18
+ // control-plane round trip raises cold-start latency.
21
19
  export const DAYTONA_SANDBOX_CPU = 1;
22
20
  export const DAYTONA_SANDBOX_MEMORY_GIB = 1;
23
21
  export const DAYTONA_SANDBOX_DISK_GIB = 3;
@@ -132,10 +132,7 @@ function redactDaytonaErrorDetail(value: string): string {
132
132
  '$1[redacted]',
133
133
  )
134
134
  .replace(/(bearer\s+)[^\s,;]+/gi, '$1[redacted]')
135
- .replace(
136
- /((?:api[_-]?key|token)\s*[=:]\s*)[^\s,;]+/gi,
137
- '$1[redacted]',
138
- )
135
+ .replace(/((?:api[_-]?key|token)\s*[=:]\s*)[^\s,;]+/gi, '$1[redacted]')
139
136
  .replace(/\s+/g, ' ')
140
137
  .trim()
141
138
  .slice(0, 1_000);
@@ -1,12 +1,12 @@
1
1
  /** Maximum active user-code runtime for a standard play, in seconds. */
2
- export const STANDARD_PLAY_RUNTIME_LIMIT_SECONDS = 20 * 60;
3
- export const STANDARD_PLAY_RUNTIME_LIMIT_LABEL = '20 minutes';
2
+ export const STANDARD_PLAY_RUNTIME_LIMIT_SECONDS = 30 * 60;
3
+ export const STANDARD_PLAY_RUNTIME_LIMIT_LABEL = '30 minutes';
4
4
 
5
5
  /**
6
6
  * Runner timeout includes setup, cleanup, and billing headroom after the
7
7
  * user-code runtime cap.
8
8
  */
9
- export const PLAY_RUNNER_TIMEOUT_SECONDS = 30 * 60;
9
+ export const PLAY_RUNNER_TIMEOUT_SECONDS = 40 * 60;
10
10
 
11
11
  /** TTL for workflow executor tokens, in seconds. */
12
12
  export const WORKFLOW_EXECUTOR_TOKEN_TTL_SECONDS = PLAY_RUNNER_TIMEOUT_SECONDS;
@@ -173,6 +173,7 @@ export type PlaySchedulerSubmitInput = {
173
173
  * case the worker falls back to the dev-collapse id (today's queue).
174
174
  */
175
175
  absurdReleaseId?: string | null;
176
+ absurdReleaseEnvironment?: 'preview' | 'production';
176
177
  /** Request-scoped Vercel Deployment Protection bypass for preview runtime callbacks. */
177
178
  vercelProtectionBypassToken?: string | null;
178
179
  /** Request-scoped, dev-only runtime fault injection header for black-box durability tests. */
package/dist/cli/index.js CHANGED
@@ -625,10 +625,10 @@ var SDK_RELEASE = {
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
626
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
627
627
  // automatically without blocking their current command.
628
- version: "0.1.221",
628
+ version: "0.1.222",
629
629
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
630
630
  supportPolicy: {
631
- latest: "0.1.221",
631
+ latest: "0.1.222",
632
632
  minimumSupported: "0.1.53",
633
633
  deprecatedBelow: "0.1.219",
634
634
  commandMinimumSupported: [
@@ -5350,6 +5350,12 @@ function printCommandEnvelope(envelope, options = {}) {
5350
5350
  }
5351
5351
 
5352
5352
  // src/cli/commands/admin.ts
5353
+ function laneStatusLine(input2) {
5354
+ if (input2.lane) {
5355
+ return `status: ${input2.lane.status}${input2.lane.active ? " (active)" : ""}`;
5356
+ }
5357
+ return input2.registration ? `status: ${input2.registration.status}` : "status: (not in registry)";
5358
+ }
5353
5359
  function normalizeEnvironment(value) {
5354
5360
  const trimmed = value?.trim().toLowerCase();
5355
5361
  if (!trimmed || trimmed === "production" || trimmed === "prod") {
@@ -5402,7 +5408,7 @@ async function handleLanesShow(releaseId, options) {
5402
5408
  title: `Lane ${releaseId} (${environment}):`,
5403
5409
  lines: [
5404
5410
  `registered: ${payload.registered}`,
5405
- payload.lane ? `status: ${payload.lane.status}${payload.lane.active ? " (active)" : ""}` : "status: (not in registry)",
5411
+ laneStatusLine(payload),
5406
5412
  `queue: ${payload.retireCheck.queue}`,
5407
5413
  `queued tasks: ${payload.retireCheck.queuedTasks}`,
5408
5414
  `non-terminal runs: ${payload.retireCheck.nonTerminalRuns}`,
@@ -5444,7 +5450,7 @@ async function handleReleasesActivate(releaseId, options) {
5444
5450
  {
5445
5451
  releaseId,
5446
5452
  environment,
5447
- ...options.schedulerBackend ? { schedulerBackend: options.schedulerBackend } : {}
5453
+ schedulerBackend: options.schedulerBackend ?? "absurd"
5448
5454
  }
5449
5455
  );
5450
5456
  printCommandEnvelope(
@@ -5469,7 +5475,10 @@ function registerAdminCommands(program) {
5469
5475
  lanes.command("show <releaseId>").description("Show one lane and its retire-gate depth.").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesShow);
5470
5476
  lanes.command("retire-check <releaseId>").description("Check whether a lane is safe to retire (queue empty).").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesRetireCheck);
5471
5477
  const releases = admin.command("releases").description("Manage the active runtime release pointer.");
5472
- releases.command("activate <releaseId>").description("Flip the active runtime release to a prior registered lane.").option("--environment <env>", "production (default) or preview").option("--scheduler-backend <backend>", "absurd or workers_edge").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5478
+ releases.command("activate <releaseId>").description("Activate a prior registered Absurd release lane.").option("--environment <env>", "production (default) or preview").option(
5479
+ "--scheduler-backend <backend>",
5480
+ "compatibility flag: absurd only; workers_edge is disabled"
5481
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5473
5482
  }
5474
5483
 
5475
5484
  // src/cli/commands/auth.ts
@@ -610,10 +610,10 @@ var SDK_RELEASE = {
610
610
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
611
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
612
612
  // automatically without blocking their current command.
613
- version: "0.1.221",
613
+ version: "0.1.222",
614
614
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
615
615
  supportPolicy: {
616
- latest: "0.1.221",
616
+ latest: "0.1.222",
617
617
  minimumSupported: "0.1.53",
618
618
  deprecatedBelow: "0.1.219",
619
619
  commandMinimumSupported: [
@@ -5341,6 +5341,12 @@ function printCommandEnvelope(envelope, options = {}) {
5341
5341
  }
5342
5342
 
5343
5343
  // src/cli/commands/admin.ts
5344
+ function laneStatusLine(input2) {
5345
+ if (input2.lane) {
5346
+ return `status: ${input2.lane.status}${input2.lane.active ? " (active)" : ""}`;
5347
+ }
5348
+ return input2.registration ? `status: ${input2.registration.status}` : "status: (not in registry)";
5349
+ }
5344
5350
  function normalizeEnvironment(value) {
5345
5351
  const trimmed = value?.trim().toLowerCase();
5346
5352
  if (!trimmed || trimmed === "production" || trimmed === "prod") {
@@ -5393,7 +5399,7 @@ async function handleLanesShow(releaseId, options) {
5393
5399
  title: `Lane ${releaseId} (${environment}):`,
5394
5400
  lines: [
5395
5401
  `registered: ${payload.registered}`,
5396
- payload.lane ? `status: ${payload.lane.status}${payload.lane.active ? " (active)" : ""}` : "status: (not in registry)",
5402
+ laneStatusLine(payload),
5397
5403
  `queue: ${payload.retireCheck.queue}`,
5398
5404
  `queued tasks: ${payload.retireCheck.queuedTasks}`,
5399
5405
  `non-terminal runs: ${payload.retireCheck.nonTerminalRuns}`,
@@ -5435,7 +5441,7 @@ async function handleReleasesActivate(releaseId, options) {
5435
5441
  {
5436
5442
  releaseId,
5437
5443
  environment,
5438
- ...options.schedulerBackend ? { schedulerBackend: options.schedulerBackend } : {}
5444
+ schedulerBackend: options.schedulerBackend ?? "absurd"
5439
5445
  }
5440
5446
  );
5441
5447
  printCommandEnvelope(
@@ -5460,7 +5466,10 @@ function registerAdminCommands(program) {
5460
5466
  lanes.command("show <releaseId>").description("Show one lane and its retire-gate depth.").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesShow);
5461
5467
  lanes.command("retire-check <releaseId>").description("Check whether a lane is safe to retire (queue empty).").option("--environment <env>", "production (default) or preview").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLanesRetireCheck);
5462
5468
  const releases = admin.command("releases").description("Manage the active runtime release pointer.");
5463
- releases.command("activate <releaseId>").description("Flip the active runtime release to a prior registered lane.").option("--environment <env>", "production (default) or preview").option("--scheduler-backend <backend>", "absurd or workers_edge").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5469
+ releases.command("activate <releaseId>").description("Activate a prior registered Absurd release lane.").option("--environment <env>", "production (default) or preview").option(
5470
+ "--scheduler-backend <backend>",
5471
+ "compatibility flag: absurd only; workers_edge is disabled"
5472
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReleasesActivate);
5464
5473
  }
5465
5474
 
5466
5475
  // src/cli/commands/auth.ts
package/dist/index.js CHANGED
@@ -424,10 +424,10 @@ var SDK_RELEASE = {
424
424
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
425
425
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
426
426
  // automatically without blocking their current command.
427
- version: "0.1.221",
427
+ version: "0.1.222",
428
428
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
429
429
  supportPolicy: {
430
- latest: "0.1.221",
430
+ latest: "0.1.222",
431
431
  minimumSupported: "0.1.53",
432
432
  deprecatedBelow: "0.1.219",
433
433
  commandMinimumSupported: [
package/dist/index.mjs CHANGED
@@ -354,10 +354,10 @@ var SDK_RELEASE = {
354
354
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
355
355
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
356
356
  // automatically without blocking their current command.
357
- version: "0.1.221",
357
+ version: "0.1.222",
358
358
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
359
359
  supportPolicy: {
360
- latest: "0.1.221",
360
+ latest: "0.1.222",
361
361
  minimumSupported: "0.1.53",
362
362
  deprecatedBelow: "0.1.219",
363
363
  commandMinimumSupported: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.221",
3
+ "version": "0.1.222",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {