deepline 0.1.202 → 0.1.204

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.
@@ -106,10 +106,10 @@ export const SDK_RELEASE = {
106
106
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
107
107
  // fields shipped in 0.1.153.
108
108
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
109
- version: '0.1.202',
109
+ version: '0.1.204',
110
110
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
111
111
  supportPolicy: {
112
- latest: '0.1.202',
112
+ latest: '0.1.204',
113
113
  minimumSupported: '0.1.53',
114
114
  deprecatedBelow: '0.1.53',
115
115
  commandMinimumSupported: [
@@ -325,6 +325,9 @@ export type WorkerRuntimeApiContext = {
325
325
  };
326
326
 
327
327
  const APP_RUNTIME_API_RETRY_DELAYS_MS = [100, 250, 500, 1_000] as const;
328
+ const APP_RUNTIME_API_RECEIPT_RETRY_DELAYS_MS = [
329
+ 250, 500, 1_000, 2_000, 4_000, 8_000, 12_000,
330
+ ] as const;
328
331
  const APP_RUNTIME_API_APPEND_RETRY_DELAYS_MS = [
329
332
  100, 250, 500, 1_000, 2_000, 4_000, 8_000,
330
333
  ] as const;
@@ -485,9 +488,33 @@ function isRetryableAppRuntimeAction(
485
488
  );
486
489
  }
487
490
 
491
+ function isRuntimeStepReceiptAction(
492
+ action: RuntimeApiRequest['action'],
493
+ ): boolean {
494
+ return (
495
+ action === 'get_runtime_step_receipt' ||
496
+ action === 'get_runtime_step_receipts' ||
497
+ action === 'heartbeat_runtime_step_receipts' ||
498
+ action === 'claim_runtime_step_receipt' ||
499
+ action === 'claim_runtime_step_receipts' ||
500
+ action === 'mark_runtime_step_receipt_running' ||
501
+ action === 'mark_runtime_step_receipts_running' ||
502
+ action === 'mark_runtime_step_receipts_queued' ||
503
+ action === 'complete_runtime_step_receipt' ||
504
+ action === 'complete_runtime_step_receipts' ||
505
+ action === 'fail_runtime_step_receipt' ||
506
+ action === 'fail_runtime_step_receipts' ||
507
+ action === 'release_runtime_step_receipt' ||
508
+ action === 'skip_runtime_step_receipt'
509
+ );
510
+ }
511
+
488
512
  function appRuntimeRetryDelaysForAction(
489
513
  action: RuntimeApiRequest['action'],
490
514
  ): readonly number[] {
515
+ if (isRuntimeStepReceiptAction(action)) {
516
+ return APP_RUNTIME_API_RECEIPT_RETRY_DELAYS_MS;
517
+ }
491
518
  return action === 'append_run_events'
492
519
  ? APP_RUNTIME_API_APPEND_RETRY_DELAYS_MS
493
520
  : APP_RUNTIME_API_RETRY_DELAYS_MS;
@@ -586,7 +613,11 @@ async function postAppRuntimeApi<TResponse>(
586
613
  await sleep(appRuntimeRetryDelayMs(body.action, attempt));
587
614
  continue;
588
615
  }
589
- throw error;
616
+ const message = error instanceof Error ? error.message : String(error);
617
+ throw new Error(
618
+ `App runtime API ${body.action} failed before receiving a response from ${resolveAppRuntimeApiUrl(context)} after ${attempt}/${maxAttempts} attempts: ${message}`,
619
+ { cause: error },
620
+ );
590
621
  }
591
622
  if (response.ok) {
592
623
  return (await response.json()) as TResponse;
@@ -4006,6 +4006,7 @@ export class PlayContextImpl {
4006
4006
  {
4007
4007
  baseUrl: this.#options.baseUrl!,
4008
4008
  executorToken: this.#options.executorToken!,
4009
+ dbSessionStrategy: this.#options.dbSessionStrategy,
4009
4010
  playName: this.#options.playName!,
4010
4011
  userEmail: this.#options.userEmail,
4011
4012
  runId: this.#options.runId!,
@@ -4529,6 +4530,7 @@ export class PlayContextImpl {
4529
4530
  {
4530
4531
  baseUrl: this.#options.baseUrl!,
4531
4532
  executorToken: this.#options.executorToken!,
4533
+ dbSessionStrategy: this.#options.dbSessionStrategy,
4532
4534
  playName: this.#options.playName!,
4533
4535
  userEmail: this.#options.userEmail,
4534
4536
  runId: this.#options.runId!,
@@ -473,6 +473,11 @@ export interface ContextOptions {
473
473
  /** Short-lived HMAC-signed internal token for tool callbacks. Required for cloud execution. */
474
474
  executorToken?: string;
475
475
  baseUrl?: string;
476
+ /**
477
+ * Runtime-sheet transport selected by the runner. Daytona sandboxes use the
478
+ * execution gateway and must never fall back to minting direct DB sessions.
479
+ */
480
+ dbSessionStrategy?: 'preloaded' | 'sandbox_public_key' | 'gateway_only';
476
481
  vercelProtectionBypassToken?: string | null;
477
482
  /** Optional per-run integration execution mode for provider calls. */
478
483
  integrationMode?: 'live' | 'eval_stub' | 'fixture';
@@ -42,7 +42,7 @@ const DAYTONA_OUTPUT_TAIL_CHARS = 2_000;
42
42
  const DAYTONA_COMMAND_RECOVERY_TIMEOUT_MS = 60_000;
43
43
  const DAYTONA_COMMAND_RECOVERY_POLL_MS = 2_000;
44
44
  const DAYTONA_PROGRESS_SIDECAR_POLL_MS = 1_000;
45
- const DAYTONA_RUNTIME_DB_CONNECT_MAX_ATTEMPTS = 2;
45
+ const DAYTONA_RUNTIME_INITIALIZATION_MAX_ATTEMPTS = 2;
46
46
  const DAYTONA_INFRASTRUCTURE_MAX_ATTEMPTS = 2;
47
47
  const DAYTONA_UPLOAD_MAX_ATTEMPTS = 2;
48
48
  const DAYTONA_UPLOAD_ATTEMPT_DEADLINE_MS = 90_000;
@@ -113,6 +113,8 @@ export async function withDaytonaOperationDeadline<T>(input: {
113
113
  }
114
114
  const RUNTIME_POSTGRES_CONNECT_RETRY_PATTERN =
115
115
  /\bRuntime Postgres\b.*\b(connection timed out|connect timeout|ETIMEDOUT|ECONNRESET|ECONNREFUSED|Connection terminated|Connection ended unexpectedly)\b/i;
116
+ const RUNTIME_API_TRANSPORT_RETRY_PATTERN =
117
+ /\bRuntime API request to .+ failed before receiving a response:\s*(?:fetch failed|connection (?:terminated|timed out|closed|reset)|ECONNRESET|ETIMEDOUT|ECONNREFUSED)\b/i;
116
118
  const DAYTONA_INFRASTRUCTURE_RETRY_PATTERN =
117
119
  /\b(?:Request failed with status code (?:408|429|500|502|503|504)|ECONNRESET|ECONNREFUSED|ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT|fetch failed|socket hang up|Daytona sandbox create failed across|Daytona sandbox create did not complete)\b/i;
118
120
 
@@ -494,13 +496,22 @@ function createDaytonaFailedResult(input: {
494
496
  };
495
497
  }
496
498
 
497
- function isRetryableRuntimePostgresConnectFailure(
499
+ function retryableRuntimeInitializationFailureReason(
498
500
  result: PlayRunnerResult,
499
- ): result is Extract<PlayRunnerResult, { status: 'failed' }> {
500
- return (
501
- result.status === 'failed' &&
502
- RUNTIME_POSTGRES_CONNECT_RETRY_PATTERN.test(result.error)
503
- );
501
+ ): 'runtime_postgres_connect' | 'runtime_api_transport' | null {
502
+ if (result.status !== 'failed') return null;
503
+ if (RUNTIME_POSTGRES_CONNECT_RETRY_PATTERN.test(result.error)) {
504
+ return 'runtime_postgres_connect';
505
+ }
506
+ const rowsProcessed = Number(result.stats?.rowsProcessed ?? 0);
507
+ if (
508
+ rowsProcessed === 0 &&
509
+ result.steps.length === 0 &&
510
+ RUNTIME_API_TRANSPORT_RETRY_PATTERN.test(result.error)
511
+ ) {
512
+ return 'runtime_api_transport';
513
+ }
514
+ return null;
504
515
  }
505
516
 
506
517
  function isRetryableDaytonaInfrastructureFailure(error: unknown): boolean {
@@ -640,7 +651,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
640
651
  let executionAttempt = 1;
641
652
  executionAttempt <=
642
653
  Math.max(
643
- DAYTONA_RUNTIME_DB_CONNECT_MAX_ATTEMPTS,
654
+ DAYTONA_RUNTIME_INITIALIZATION_MAX_ATTEMPTS,
644
655
  DAYTONA_INFRASTRUCTURE_MAX_ATTEMPTS,
645
656
  );
646
657
  executionAttempt += 1
@@ -868,14 +879,17 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
868
879
 
869
880
  const result = findPlayRunnerResult(events);
870
881
  if (result) {
882
+ const initializationRetryReason =
883
+ retryableRuntimeInitializationFailureReason(result);
871
884
  if (
872
- executionAttempt < DAYTONA_RUNTIME_DB_CONNECT_MAX_ATTEMPTS &&
873
- isRetryableRuntimePostgresConnectFailure(result)
885
+ result.status === 'failed' &&
886
+ executionAttempt < DAYTONA_RUNTIME_INITIALIZATION_MAX_ATTEMPTS &&
887
+ initializationRetryReason
874
888
  ) {
875
889
  emitDaytonaStage(callbacks, config.context, 'execute:retry', {
876
890
  sandboxId: sandbox.id,
877
891
  attempt: executionAttempt + 1,
878
- reason: 'runtime_postgres_connect',
892
+ reason: initializationRetryReason,
879
893
  error: result.error,
880
894
  elapsedMs: Date.now() - startedAt,
881
895
  });
@@ -1,5 +1,7 @@
1
1
  export const PLAY_RUNTIME_API_COMPAT_PATH = '/api/v2/plays/internal/runtime';
2
2
  export const PLAY_RUNTIME_API_CURRENT_PATH = '/api/v2/internal/play-runtime';
3
+ export const PLAY_RUNTIME_ATTEMPT_EXECUTOR_TOKEN_PATH =
4
+ '/api/v2/internal/play-runtime/executor-token';
3
5
  export const PLAY_RUNTIME_CHILD_EXECUTOR_TOKEN_COMPAT_PATH =
4
6
  '/api/v2/plays/internal/child-executor-token';
5
7
  export const PLAY_RUNTIME_CHILD_EXECUTOR_TOKEN_CURRENT_PATH =
@@ -2884,10 +2884,10 @@ async function prepareRuntimeSheetDatasetRows(
2884
2884
  AND (
2885
2885
  ${targetAttemptFenceSql}
2886
2886
  OR ${targetOlderForeignAttemptOwnerSql}
2887
- OR (
2888
- $11::boolean
2889
- AND target._status = 'failed'
2890
- )
2887
+ -- Failed rows are repairable projection state, never terminal
2888
+ -- ownership. This matches decideRuntimeSheetPrepare(): any
2889
+ -- attempt may reclaim them, even after a newer failed attempt.
2890
+ OR target._status = 'failed'
2891
2891
  )
2892
2892
  AND (
2893
2893
  target._run_id IS DISTINCT FROM $4::text
@@ -2919,14 +2919,13 @@ async function prepareRuntimeSheetDatasetRows(
2919
2919
  AND NOT (${existingNewerTerminalRowSql})
2920
2920
  AND (
2921
2921
  ${existingAttemptFenceSql}
2922
+ -- See claimed_existing_rows: failed rows remain repairable
2923
+ -- across attempt ordering, while enriched rows stay fenced.
2924
+ OR existing._status = 'failed'
2922
2925
  OR (
2923
2926
  ${existingForeignAttemptOwnerSql}
2924
2927
  AND COALESCE(existing._attempt_seq, 0) < $10::integer
2925
2928
  )
2926
- OR (
2927
- $11::boolean
2928
- AND existing._status = 'failed'
2929
- )
2930
2929
  )
2931
2930
  )
2932
2931
  OR (
package/dist/cli/index.js CHANGED
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.202",
626
+ version: "0.1.204",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.202",
629
+ latest: "0.1.204",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -14113,7 +14113,7 @@ function writeStartedPlayRun(input2) {
14113
14113
  );
14114
14114
  }
14115
14115
  function parsePlayRunOptions(args) {
14116
- const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n --profile defaults to workers_edge, unless your local dev server exports a dev default such as absurd.\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotent call caching and ctx.dataset guidance.";
14116
+ const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Production defaults to workers_edge. Use --profile absurd only for an explicit Absurd run.\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotent call caching and ctx.dataset guidance.";
14117
14117
  let filePath = null;
14118
14118
  let playName = null;
14119
14119
  let input2 = null;
@@ -16116,6 +16116,7 @@ Examples:
16116
16116
  deepline plays run prebuilt/person-linkedin-to-email --input '{"linkedin_url":"..."}'
16117
16117
  deepline plays run long-background-play --no-wait
16118
16118
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
16119
+ deepline plays run my.play.ts --profile absurd
16119
16120
  deepline plays run my.play.ts --input @input.json --json
16120
16121
  deepline plays run cto-search.play.ts --limit 5
16121
16122
  deepline runs export <run-id> --out output.csv
@@ -18315,6 +18316,8 @@ var ENRICH_CELL_META_PATCH_FIELD = "__deeplineCellMetaPatch";
18315
18316
  var EXIT_SERVER2 = 5;
18316
18317
  var ENRICH_DEBUG_T0 = Date.now();
18317
18318
  var GENERATED_ENRICH_ROWS_TABLE_NAMESPACE = "deepline_enrich_rows";
18319
+ var SDK_ENRICH_TELEMETRY_TIMEOUT_MS = 1e4;
18320
+ var SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH = 2e4;
18318
18321
  var HEAVY_ENRICH_AUTO_BATCH_PLAYS = /* @__PURE__ */ new Set([
18319
18322
  "company-to-contact",
18320
18323
  "company-to-contact-by-role-waterfall",
@@ -18592,6 +18595,100 @@ function currentEnrichArgs() {
18592
18595
  const index = process.argv.findIndex((arg) => arg === "enrich");
18593
18596
  return index >= 0 ? process.argv.slice(index + 1) : [];
18594
18597
  }
18598
+ function shouldSuppressSdkEnrichTelemetry() {
18599
+ return ["1", "true", "yes", "on"].includes(
18600
+ String(process.env.DEEPLINE_SUPPRESS_ACTIVITY_EVENTS ?? "").trim().toLowerCase()
18601
+ );
18602
+ }
18603
+ function shellQuoteArg(value) {
18604
+ if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
18605
+ return value;
18606
+ }
18607
+ return `'${value.replace(/'/g, "'\\''")}'`;
18608
+ }
18609
+ function sdkEnrichCommandText(args) {
18610
+ const command = ["deepline", "enrich", ...args].map(shellQuoteArg).join(" ");
18611
+ if (command.length <= SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH) {
18612
+ return command;
18613
+ }
18614
+ return `${command.slice(0, SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH - 3)}...`;
18615
+ }
18616
+ function countConfiguredEnrichColumns(config) {
18617
+ const count = (commands) => commands.reduce((total, command) => {
18618
+ if ("with_waterfall" in command) {
18619
+ return total + count(command.commands);
18620
+ }
18621
+ return total + (command.disabled ? 0 : 1);
18622
+ }, 0);
18623
+ return count(config.commands ?? []);
18624
+ }
18625
+ function createSdkEnrichTelemetryContext(input2) {
18626
+ if (shouldSuppressSdkEnrichTelemetry()) {
18627
+ return null;
18628
+ }
18629
+ const baseUrl = input2.client.baseUrl.replace(/\/$/, "");
18630
+ let apiKey = null;
18631
+ try {
18632
+ apiKey = resolveApiKeyForBaseUrl(baseUrl);
18633
+ } catch {
18634
+ apiKey = null;
18635
+ }
18636
+ return {
18637
+ baseUrl,
18638
+ apiKey,
18639
+ runId: `sdk-enrich-${process.pid}-${Date.now()}`,
18640
+ command: sdkEnrichCommandText(input2.args),
18641
+ rowsRange: input2.rowsRange,
18642
+ inputPath: (0, import_node_path12.basename)(input2.inputCsv),
18643
+ startedAtMs: Date.now(),
18644
+ rowsTargeted: input2.selectedRange.count,
18645
+ columnsTargeted: countConfiguredEnrichColumns(input2.config)
18646
+ };
18647
+ }
18648
+ async function emitSdkEnrichTelemetry(context, event, summary) {
18649
+ if (!context?.apiKey) {
18650
+ return;
18651
+ }
18652
+ const controller = new AbortController();
18653
+ const timeout = setTimeout(
18654
+ () => controller.abort(),
18655
+ SDK_ENRICH_TELEMETRY_TIMEOUT_MS
18656
+ );
18657
+ try {
18658
+ const body = {
18659
+ event,
18660
+ source: "cli_enrich",
18661
+ run_id: context.runId,
18662
+ command: context.command,
18663
+ input_path: context.inputPath,
18664
+ ...context.rowsRange ? { rows_range: context.rowsRange } : {},
18665
+ ...summary ? { summary } : {}
18666
+ };
18667
+ await fetch(new URL("/api/v2/telemetry/activity", context.baseUrl), {
18668
+ method: "POST",
18669
+ headers: {
18670
+ Authorization: `Bearer ${context.apiKey}`,
18671
+ "Content-Type": "application/json"
18672
+ },
18673
+ body: JSON.stringify(body),
18674
+ signal: controller.signal
18675
+ });
18676
+ } catch {
18677
+ } finally {
18678
+ clearTimeout(timeout);
18679
+ }
18680
+ }
18681
+ async function completeSdkEnrichTelemetry(context, input2) {
18682
+ await emitSdkEnrichTelemetry(context, "enrich_completed", {
18683
+ status: input2.status,
18684
+ rows_targeted: context?.rowsTargeted ?? 0,
18685
+ columns_targeted: context?.columnsTargeted ?? 0,
18686
+ failed_jobs: Math.max(0, Math.trunc(input2.failedJobs ?? 0)),
18687
+ skipped_cells: Math.max(0, Math.trunc(input2.skippedCells ?? 0)),
18688
+ duration_ms: Math.max(0, Date.now() - (context?.startedAtMs ?? Date.now())),
18689
+ rate_limits: null
18690
+ });
18691
+ }
18595
18692
  async function buildPlanArgs(args) {
18596
18693
  const passthrough = /* @__PURE__ */ new Set([
18597
18694
  "--with",
@@ -21754,7 +21851,25 @@ function registerEnrichCommand(program) {
21754
21851
  inlineRunJavascript: true,
21755
21852
  failFast: options.failFast
21756
21853
  });
21854
+ const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
21855
+ const sdkEnrichTelemetry = createSdkEnrichTelemetryContext({
21856
+ client: client2,
21857
+ args,
21858
+ inputCsv,
21859
+ rowsRange: options.rows ?? (options.all ? "all" : null),
21860
+ selectedRange,
21861
+ config
21862
+ });
21863
+ let sdkEnrichTelemetryCompleted = false;
21864
+ const completeTelemetry = async (input2) => {
21865
+ if (sdkEnrichTelemetryCompleted) {
21866
+ return;
21867
+ }
21868
+ sdkEnrichTelemetryCompleted = true;
21869
+ await completeSdkEnrichTelemetry(sdkEnrichTelemetry, input2);
21870
+ };
21757
21871
  const tempDir = await (0, import_promises3.mkdtemp)((0, import_node_path12.join)((0, import_node_os8.tmpdir)(), "deepline-enrich-play-"));
21872
+ await emitSdkEnrichTelemetry(sdkEnrichTelemetry, "enrich_started");
21758
21873
  const tempPlay = (0, import_node_path12.join)(tempDir, "deepline-enrich.play.ts");
21759
21874
  let inPlaceTempDir = null;
21760
21875
  let inPlaceTempOutputPath = null;
@@ -21853,7 +21968,6 @@ function registerEnrichCommand(program) {
21853
21968
  });
21854
21969
  return { captured: captured2, status: status2, exportResult: exportResult2 };
21855
21970
  };
21856
- const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
21857
21971
  const autoBatchRows = enrichAutoBatchRowsForConfig(config);
21858
21972
  if (outputPath && selectedRange.count > autoBatchRows) {
21859
21973
  const chunkCount = Math.ceil(selectedRange.count / autoBatchRows);
@@ -22034,6 +22148,10 @@ function registerEnrichCommand(program) {
22034
22148
  });
22035
22149
  }
22036
22150
  process.exitCode = failureReport3 ? EXIT_SERVER2 : chunk.captured.result;
22151
+ await completeTelemetry({
22152
+ status: "failed",
22153
+ failedJobs: failureReport3?.jobs.length ?? 1
22154
+ });
22037
22155
  return;
22038
22156
  }
22039
22157
  if (chunk.exportResult) {
@@ -22112,6 +22230,10 @@ function registerEnrichCommand(program) {
22112
22230
  if (failureReport2) {
22113
22231
  process.exitCode = EXIT_SERVER2;
22114
22232
  }
22233
+ await completeTelemetry({
22234
+ status: failureReport2 ? "completed_with_failures" : "completed",
22235
+ failedJobs: failureReport2?.jobs.length ?? 0
22236
+ });
22115
22237
  return;
22116
22238
  }
22117
22239
  const { captured, status, exportResult } = await runOne({
@@ -22154,6 +22276,10 @@ function registerEnrichCommand(program) {
22154
22276
  });
22155
22277
  }
22156
22278
  process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
22279
+ await completeTelemetry({
22280
+ status: "failed",
22281
+ failedJobs: failureReport2?.jobs.length ?? 1
22282
+ });
22157
22283
  return;
22158
22284
  }
22159
22285
  if (options.json) {
@@ -22190,6 +22316,10 @@ function registerEnrichCommand(program) {
22190
22316
  if (failureReport2) {
22191
22317
  process.exitCode = EXIT_SERVER2;
22192
22318
  }
22319
+ await completeTelemetry({
22320
+ status: failureReport2 ? "completed_with_failures" : "completed",
22321
+ failedJobs: failureReport2?.jobs.length ?? 0
22322
+ });
22193
22323
  return;
22194
22324
  }
22195
22325
  const failureReport = await maybeEmitEnrichFailureReport({
@@ -22220,6 +22350,13 @@ function registerEnrichCommand(program) {
22220
22350
  if (failureReport) {
22221
22351
  process.exitCode = EXIT_SERVER2;
22222
22352
  }
22353
+ await completeTelemetry({
22354
+ status: failureReport ? "completed_with_failures" : "completed",
22355
+ failedJobs: failureReport?.jobs.length ?? 0
22356
+ });
22357
+ } catch (error) {
22358
+ await completeTelemetry({ status: "failed", failedJobs: 1 });
22359
+ throw error;
22223
22360
  } finally {
22224
22361
  if (inPlaceTempDir) {
22225
22362
  await (0, import_promises3.rm)(inPlaceTempDir, { recursive: true, force: true });
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
608
608
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
609
609
  // fields shipped in 0.1.153.
610
610
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
- version: "0.1.202",
611
+ version: "0.1.204",
612
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
613
613
  supportPolicy: {
614
- latest: "0.1.202",
614
+ latest: "0.1.204",
615
615
  minimumSupported: "0.1.53",
616
616
  deprecatedBelow: "0.1.53",
617
617
  commandMinimumSupported: [
@@ -14142,7 +14142,7 @@ function writeStartedPlayRun(input2) {
14142
14142
  );
14143
14143
  }
14144
14144
  function parsePlayRunOptions(args) {
14145
- const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n --profile defaults to workers_edge, unless your local dev server exports a dev default such as absurd.\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotent call caching and ctx.dataset guidance.";
14145
+ const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--profile <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--profile <id>] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Production defaults to workers_edge. Use --profile absurd only for an explicit Absurd run.\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotent call caching and ctx.dataset guidance.";
14146
14146
  let filePath = null;
14147
14147
  let playName = null;
14148
14148
  let input2 = null;
@@ -16145,6 +16145,7 @@ Examples:
16145
16145
  deepline plays run prebuilt/person-linkedin-to-email --input '{"linkedin_url":"..."}'
16146
16146
  deepline plays run long-background-play --no-wait
16147
16147
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
16148
+ deepline plays run my.play.ts --profile absurd
16148
16149
  deepline plays run my.play.ts --input @input.json --json
16149
16150
  deepline plays run cto-search.play.ts --limit 5
16150
16151
  deepline runs export <run-id> --out output.csv
@@ -18344,6 +18345,8 @@ var ENRICH_CELL_META_PATCH_FIELD = "__deeplineCellMetaPatch";
18344
18345
  var EXIT_SERVER2 = 5;
18345
18346
  var ENRICH_DEBUG_T0 = Date.now();
18346
18347
  var GENERATED_ENRICH_ROWS_TABLE_NAMESPACE = "deepline_enrich_rows";
18348
+ var SDK_ENRICH_TELEMETRY_TIMEOUT_MS = 1e4;
18349
+ var SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH = 2e4;
18347
18350
  var HEAVY_ENRICH_AUTO_BATCH_PLAYS = /* @__PURE__ */ new Set([
18348
18351
  "company-to-contact",
18349
18352
  "company-to-contact-by-role-waterfall",
@@ -18621,6 +18624,100 @@ function currentEnrichArgs() {
18621
18624
  const index = process.argv.findIndex((arg) => arg === "enrich");
18622
18625
  return index >= 0 ? process.argv.slice(index + 1) : [];
18623
18626
  }
18627
+ function shouldSuppressSdkEnrichTelemetry() {
18628
+ return ["1", "true", "yes", "on"].includes(
18629
+ String(process.env.DEEPLINE_SUPPRESS_ACTIVITY_EVENTS ?? "").trim().toLowerCase()
18630
+ );
18631
+ }
18632
+ function shellQuoteArg(value) {
18633
+ if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
18634
+ return value;
18635
+ }
18636
+ return `'${value.replace(/'/g, "'\\''")}'`;
18637
+ }
18638
+ function sdkEnrichCommandText(args) {
18639
+ const command = ["deepline", "enrich", ...args].map(shellQuoteArg).join(" ");
18640
+ if (command.length <= SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH) {
18641
+ return command;
18642
+ }
18643
+ return `${command.slice(0, SDK_ENRICH_TELEMETRY_COMMAND_MAX_LENGTH - 3)}...`;
18644
+ }
18645
+ function countConfiguredEnrichColumns(config) {
18646
+ const count = (commands) => commands.reduce((total, command) => {
18647
+ if ("with_waterfall" in command) {
18648
+ return total + count(command.commands);
18649
+ }
18650
+ return total + (command.disabled ? 0 : 1);
18651
+ }, 0);
18652
+ return count(config.commands ?? []);
18653
+ }
18654
+ function createSdkEnrichTelemetryContext(input2) {
18655
+ if (shouldSuppressSdkEnrichTelemetry()) {
18656
+ return null;
18657
+ }
18658
+ const baseUrl = input2.client.baseUrl.replace(/\/$/, "");
18659
+ let apiKey = null;
18660
+ try {
18661
+ apiKey = resolveApiKeyForBaseUrl(baseUrl);
18662
+ } catch {
18663
+ apiKey = null;
18664
+ }
18665
+ return {
18666
+ baseUrl,
18667
+ apiKey,
18668
+ runId: `sdk-enrich-${process.pid}-${Date.now()}`,
18669
+ command: sdkEnrichCommandText(input2.args),
18670
+ rowsRange: input2.rowsRange,
18671
+ inputPath: basename2(input2.inputCsv),
18672
+ startedAtMs: Date.now(),
18673
+ rowsTargeted: input2.selectedRange.count,
18674
+ columnsTargeted: countConfiguredEnrichColumns(input2.config)
18675
+ };
18676
+ }
18677
+ async function emitSdkEnrichTelemetry(context, event, summary) {
18678
+ if (!context?.apiKey) {
18679
+ return;
18680
+ }
18681
+ const controller = new AbortController();
18682
+ const timeout = setTimeout(
18683
+ () => controller.abort(),
18684
+ SDK_ENRICH_TELEMETRY_TIMEOUT_MS
18685
+ );
18686
+ try {
18687
+ const body = {
18688
+ event,
18689
+ source: "cli_enrich",
18690
+ run_id: context.runId,
18691
+ command: context.command,
18692
+ input_path: context.inputPath,
18693
+ ...context.rowsRange ? { rows_range: context.rowsRange } : {},
18694
+ ...summary ? { summary } : {}
18695
+ };
18696
+ await fetch(new URL("/api/v2/telemetry/activity", context.baseUrl), {
18697
+ method: "POST",
18698
+ headers: {
18699
+ Authorization: `Bearer ${context.apiKey}`,
18700
+ "Content-Type": "application/json"
18701
+ },
18702
+ body: JSON.stringify(body),
18703
+ signal: controller.signal
18704
+ });
18705
+ } catch {
18706
+ } finally {
18707
+ clearTimeout(timeout);
18708
+ }
18709
+ }
18710
+ async function completeSdkEnrichTelemetry(context, input2) {
18711
+ await emitSdkEnrichTelemetry(context, "enrich_completed", {
18712
+ status: input2.status,
18713
+ rows_targeted: context?.rowsTargeted ?? 0,
18714
+ columns_targeted: context?.columnsTargeted ?? 0,
18715
+ failed_jobs: Math.max(0, Math.trunc(input2.failedJobs ?? 0)),
18716
+ skipped_cells: Math.max(0, Math.trunc(input2.skippedCells ?? 0)),
18717
+ duration_ms: Math.max(0, Date.now() - (context?.startedAtMs ?? Date.now())),
18718
+ rate_limits: null
18719
+ });
18720
+ }
18624
18721
  async function buildPlanArgs(args) {
18625
18722
  const passthrough = /* @__PURE__ */ new Set([
18626
18723
  "--with",
@@ -21783,7 +21880,25 @@ function registerEnrichCommand(program) {
21783
21880
  inlineRunJavascript: true,
21784
21881
  failFast: options.failFast
21785
21882
  });
21883
+ const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
21884
+ const sdkEnrichTelemetry = createSdkEnrichTelemetryContext({
21885
+ client: client2,
21886
+ args,
21887
+ inputCsv,
21888
+ rowsRange: options.rows ?? (options.all ? "all" : null),
21889
+ selectedRange,
21890
+ config
21891
+ });
21892
+ let sdkEnrichTelemetryCompleted = false;
21893
+ const completeTelemetry = async (input2) => {
21894
+ if (sdkEnrichTelemetryCompleted) {
21895
+ return;
21896
+ }
21897
+ sdkEnrichTelemetryCompleted = true;
21898
+ await completeSdkEnrichTelemetry(sdkEnrichTelemetry, input2);
21899
+ };
21786
21900
  const tempDir = await mkdtemp(join7(tmpdir2(), "deepline-enrich-play-"));
21901
+ await emitSdkEnrichTelemetry(sdkEnrichTelemetry, "enrich_started");
21787
21902
  const tempPlay = join7(tempDir, "deepline-enrich.play.ts");
21788
21903
  let inPlaceTempDir = null;
21789
21904
  let inPlaceTempOutputPath = null;
@@ -21882,7 +21997,6 @@ function registerEnrichCommand(program) {
21882
21997
  });
21883
21998
  return { captured: captured2, status: status2, exportResult: exportResult2 };
21884
21999
  };
21885
- const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
21886
22000
  const autoBatchRows = enrichAutoBatchRowsForConfig(config);
21887
22001
  if (outputPath && selectedRange.count > autoBatchRows) {
21888
22002
  const chunkCount = Math.ceil(selectedRange.count / autoBatchRows);
@@ -22063,6 +22177,10 @@ function registerEnrichCommand(program) {
22063
22177
  });
22064
22178
  }
22065
22179
  process.exitCode = failureReport3 ? EXIT_SERVER2 : chunk.captured.result;
22180
+ await completeTelemetry({
22181
+ status: "failed",
22182
+ failedJobs: failureReport3?.jobs.length ?? 1
22183
+ });
22066
22184
  return;
22067
22185
  }
22068
22186
  if (chunk.exportResult) {
@@ -22141,6 +22259,10 @@ function registerEnrichCommand(program) {
22141
22259
  if (failureReport2) {
22142
22260
  process.exitCode = EXIT_SERVER2;
22143
22261
  }
22262
+ await completeTelemetry({
22263
+ status: failureReport2 ? "completed_with_failures" : "completed",
22264
+ failedJobs: failureReport2?.jobs.length ?? 0
22265
+ });
22144
22266
  return;
22145
22267
  }
22146
22268
  const { captured, status, exportResult } = await runOne({
@@ -22183,6 +22305,10 @@ function registerEnrichCommand(program) {
22183
22305
  });
22184
22306
  }
22185
22307
  process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
22308
+ await completeTelemetry({
22309
+ status: "failed",
22310
+ failedJobs: failureReport2?.jobs.length ?? 1
22311
+ });
22186
22312
  return;
22187
22313
  }
22188
22314
  if (options.json) {
@@ -22219,6 +22345,10 @@ function registerEnrichCommand(program) {
22219
22345
  if (failureReport2) {
22220
22346
  process.exitCode = EXIT_SERVER2;
22221
22347
  }
22348
+ await completeTelemetry({
22349
+ status: failureReport2 ? "completed_with_failures" : "completed",
22350
+ failedJobs: failureReport2?.jobs.length ?? 0
22351
+ });
22222
22352
  return;
22223
22353
  }
22224
22354
  const failureReport = await maybeEmitEnrichFailureReport({
@@ -22249,6 +22379,13 @@ function registerEnrichCommand(program) {
22249
22379
  if (failureReport) {
22250
22380
  process.exitCode = EXIT_SERVER2;
22251
22381
  }
22382
+ await completeTelemetry({
22383
+ status: failureReport ? "completed_with_failures" : "completed",
22384
+ failedJobs: failureReport?.jobs.length ?? 0
22385
+ });
22386
+ } catch (error) {
22387
+ await completeTelemetry({ status: "failed", failedJobs: 1 });
22388
+ throw error;
22252
22389
  } finally {
22253
22390
  if (inPlaceTempDir) {
22254
22391
  await rm(inPlaceTempDir, { recursive: true, force: true });
package/dist/index.js CHANGED
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
422
422
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
423
423
  // fields shipped in 0.1.153.
424
424
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
425
- version: "0.1.202",
425
+ version: "0.1.204",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.202",
428
+ latest: "0.1.204",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
package/dist/index.mjs CHANGED
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
352
352
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
353
353
  // fields shipped in 0.1.153.
354
354
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
355
- version: "0.1.202",
355
+ version: "0.1.204",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.202",
358
+ latest: "0.1.204",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.202",
3
+ "version": "0.1.204",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {