deepline 0.1.238 → 0.1.240

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.
@@ -612,10 +612,10 @@ var SDK_RELEASE = {
612
612
  // silently materializing them as unmatched results.
613
613
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
614
614
  // automatically without blocking their current command.
615
- version: "0.1.238",
615
+ version: "0.1.240",
616
616
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
617
617
  supportPolicy: {
618
- latest: "0.1.238",
618
+ latest: "0.1.240",
619
619
  minimumSupported: "0.1.53",
620
620
  deprecatedBelow: "0.1.219",
621
621
  commandMinimumSupported: [
@@ -877,6 +877,7 @@ var HttpClient = class {
877
877
  "X-Deepline-CLI-Version": SDK_VERSION,
878
878
  "X-Deepline-SDK-Version": SDK_VERSION,
879
879
  "X-Deepline-API-Contract": SDK_API_CONTRACT,
880
+ "X-Deepline-Run-Result-Shape": "canonical",
880
881
  ...extra
881
882
  };
882
883
  const skillsVersion = this.readSkillsVersionHeader();
@@ -1355,7 +1356,7 @@ function normalizePlayRunLedgerTerminalSource(value) {
1355
1356
  var SECRET_REDACTION_PLACEHOLDER = "[REDACTED_SECRET]";
1356
1357
  var BEARER_TOKEN_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/g;
1357
1358
  var BASIC_CREDENTIAL_RE = /\bBasic\s+[A-Za-z0-9+/]{4,}={0,2}\b/g;
1358
- var JWT_RE = /\b[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{1,}\.[A-Za-z0-9_-]{8,}\b/g;
1359
+ var JWT_RE = /\b[A-Za-z0-9_-]{8,16384}\.[A-Za-z0-9_-]{1,16384}\.[A-Za-z0-9_-]{8,16384}\b/g;
1359
1360
  var PRIVATE_KEY_RE = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g;
1360
1361
  var SENSITIVE_FIELD_NAME = "authorization|cookie|password|(?:client[_-]?)?secret|(?:access|refresh)[_-]?token|(?:x[_-]?)?api[_-]?key|private[_-]?key|token|credentials";
1361
1362
  var COMMON_SECRET_RE = /\b(?:[prs]k_(?:live|test)_|(?:pat|ghp|github_pat)_|xox[baprs]-)[A-Za-z0-9_./+=:-]{12,}\b/gi;
@@ -2690,6 +2691,8 @@ var DeeplineClient = class {
2690
2691
  config;
2691
2692
  /** Canonical run lifecycle namespace backed by `/api/v2/runs`. */
2692
2693
  runs;
2694
+ /** Current mutable customer database namespace backed by `/api/v2/db/query`. */
2695
+ db;
2693
2696
  /** Billing namespace: subscription status/cancel and invoice history. */
2694
2697
  billing;
2695
2698
  /**
@@ -2713,6 +2716,9 @@ var DeeplineClient = class {
2713
2716
  stop: (runId, options2) => this.stopRun(runId, options2),
2714
2717
  stopAll: (options2) => this.stopAllRuns(options2)
2715
2718
  };
2719
+ this.db = {
2720
+ query: (input2) => this.queryDb(input2)
2721
+ };
2716
2722
  this.billing = {
2717
2723
  topUp: (options2) => this.topUpBillingBalance(options2),
2718
2724
  plans: () => this.getBillingPlans(),
@@ -2979,17 +2985,29 @@ var DeeplineClient = class {
2979
2985
  async executeToolRaw(toolId, input2, options) {
2980
2986
  return this.executeTool(toolId, input2, options);
2981
2987
  }
2988
+ async queryDb(input2) {
2989
+ const result = await this.http.post(
2990
+ "/api/v2/db/query",
2991
+ {
2992
+ sql: input2.sql,
2993
+ ...input2.maxRows ? { max_rows: input2.maxRows } : {}
2994
+ }
2995
+ );
2996
+ return {
2997
+ ...result,
2998
+ scope: { kind: "database", mutability: "current" }
2999
+ };
3000
+ }
2982
3001
  /**
2983
- * Run a bounded SQL query against the customer data plane.
3002
+ * Run a bounded SQL query against the current mutable customer database.
2984
3003
  *
2985
- * Use this from trusted backend or agent contexts only. The API enforces
2986
- * workspace scoping and row limits.
3004
+ * This query is not scoped to one play run. Use `client.runs` export actions
3005
+ * when the caller needs the rows produced by a specific run.
3006
+ *
3007
+ * @deprecated Use {@link DeeplineClient.db} `.query(...)`.
2987
3008
  */
2988
3009
  async queryCustomerDb(input2) {
2989
- return this.http.post("/api/v2/db/query", {
2990
- sql: input2.sql,
2991
- ...input2.maxRows ? { max_rows: input2.maxRows } : {}
2992
- });
3010
+ return this.db.query(input2);
2993
3011
  }
2994
3012
  /**
2995
3013
  * Re-establish this workspace's tenant storage contract: role/DB connect
@@ -4120,9 +4138,35 @@ var DeeplineClient = class {
4120
4138
  if (input2.rowMode === "all") {
4121
4139
  params.set("rowMode", "all");
4122
4140
  }
4123
- return await this.http.get(
4141
+ const result = await this.http.get(
4124
4142
  `/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
4125
4143
  );
4144
+ const requestedRunId = input2.runId?.trim() || "";
4145
+ if (requestedRunId) {
4146
+ const confirmedRunId = result.scope?.kind === "run" ? result.scope.runId.trim() : "";
4147
+ const foreignRowRunIds = [
4148
+ ...new Set(
4149
+ result.rows.map(
4150
+ (row) => typeof row.runId === "string" ? row.runId.trim() : ""
4151
+ ).filter((runId) => runId && runId !== requestedRunId)
4152
+ )
4153
+ ];
4154
+ if (result.scope?.kind !== "run" || confirmedRunId !== requestedRunId || foreignRowRunIds.length > 0) {
4155
+ throw new DeeplineError(
4156
+ `Run-scoped dataset export was not confirmed for ${requestedRunId}; no rows were returned to the caller. Update Deepline, then retry the same export command. Do not rerun the play.`,
4157
+ void 0,
4158
+ "RUN_EXPORT_SCOPE_MISMATCH",
4159
+ {
4160
+ requestedRunId,
4161
+ confirmedScope: result.scope ?? null,
4162
+ foreignRowRunIds,
4163
+ playName: input2.playName,
4164
+ tableNamespace: input2.tableNamespace
4165
+ }
4166
+ );
4167
+ }
4168
+ }
4169
+ return result;
4126
4170
  }
4127
4171
  /**
4128
4172
  * Stop a run by id using the public runs resource model.
@@ -7391,6 +7435,33 @@ function formatDatasetExecutionStats(raw, _persistedRowTotal) {
7391
7435
  }
7392
7436
 
7393
7437
  // src/cli/dataset-stats.ts
7438
+ function mergeCanonicalRowsInfo(left, right) {
7439
+ const preferred = right.rows.length > left.rows.length || right.complete && !left.complete && right.rows.length === left.rows.length ? right : left;
7440
+ const fallback = preferred === left ? right : left;
7441
+ const totalRows = Math.max(left.totalRows, right.totalRows);
7442
+ const exportUnavailableReason = left.exportUnavailableReason === "shared_table_namespace" || right.exportUnavailableReason === "shared_table_namespace" ? "shared_table_namespace" : left.exportUnavailableReason ?? right.exportUnavailableReason;
7443
+ const unavailableSource = left.exportUnavailableReason === exportUnavailableReason ? left : right.exportUnavailableReason === exportUnavailableReason ? right : null;
7444
+ const columns = preferred.columns.length > 0 ? preferred.columns : fallback.columns;
7445
+ return {
7446
+ ...fallback,
7447
+ ...preferred,
7448
+ rows: preferred.rows,
7449
+ totalRows,
7450
+ columns,
7451
+ columnsExplicit: columns === preferred.columns ? preferred.columnsExplicit : fallback.columnsExplicit,
7452
+ complete: preferred.rows.length === totalRows,
7453
+ source: preferred.source ?? fallback.source,
7454
+ datasetId: preferred.datasetId ?? fallback.datasetId,
7455
+ tableNamespace: preferred.tableNamespace ?? fallback.tableNamespace,
7456
+ ...left.recovered || right.recovered ? { recovered: true } : {},
7457
+ ...exportUnavailableReason ? {
7458
+ exportUnavailableReason,
7459
+ ...unavailableSource?.exportUnavailableMessage ? {
7460
+ exportUnavailableMessage: unavailableSource.exportUnavailableMessage
7461
+ } : {}
7462
+ } : {}
7463
+ };
7464
+ }
7394
7465
  var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
7395
7466
  function csvProjectedFields(row) {
7396
7467
  const serialized = row[CSV_PROJECTED_FIELDS_KEY];
@@ -7538,7 +7609,13 @@ function canonicalRowsInfoFromCandidate(input2) {
7538
7609
  source: candidate.source,
7539
7610
  datasetId: typeof candidate.value.datasetId === "string" ? candidate.value.datasetId : null,
7540
7611
  tableNamespace: typeof candidate.value.tableNamespace === "string" ? candidate.value.tableNamespace : null,
7541
- ...candidate.value.recovered === true ? { recovered: true } : {}
7612
+ ...candidate.value.recovered === true ? { recovered: true } : {},
7613
+ ...isRecord4(candidate.value.exportUnavailable) && (candidate.value.exportUnavailable.reason === "empty_dataset" || candidate.value.exportUnavailable.reason === "shared_table_namespace") ? {
7614
+ exportUnavailableReason: candidate.value.exportUnavailable.reason,
7615
+ ...typeof candidate.value.exportUnavailable.message === "string" ? {
7616
+ exportUnavailableMessage: candidate.value.exportUnavailable.message
7617
+ } : {}
7618
+ } : {}
7542
7619
  };
7543
7620
  }
7544
7621
  if (candidate.serializedOnly) {
@@ -7713,6 +7790,23 @@ function collectPackagedDatasetCandidates(statusOrResult) {
7713
7790
  }
7714
7791
  return candidates;
7715
7792
  }
7793
+ function collectPackagedStepDatasetCandidates(statusOrResult) {
7794
+ const root = isRecord4(statusOrResult) ? statusOrResult : null;
7795
+ if (!root) return [];
7796
+ const pkg = isRecord4(root.package) ? root.package : root;
7797
+ const steps = Array.isArray(pkg.steps) ? pkg.steps : [];
7798
+ return steps.flatMap((step) => {
7799
+ if (!isRecord4(step) || !isPackagedDatasetOutput(step.output)) return [];
7800
+ const source = typeof step.output.path === "string" && step.output.path.trim() ? step.output.path.trim() : null;
7801
+ return source ? [
7802
+ {
7803
+ source,
7804
+ value: step.output,
7805
+ total: step.output.rowCount ?? step.output.preview?.totalRows ?? void 0
7806
+ }
7807
+ ] : [];
7808
+ });
7809
+ }
7716
7810
  function collectSerializedDatasetRowsInfos(statusOrResult) {
7717
7811
  const root = isRecord4(statusOrResult) ? statusOrResult : null;
7718
7812
  const result = isRecord4(root?.result) ? root.result : root;
@@ -7731,8 +7825,9 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
7731
7825
  });
7732
7826
  }
7733
7827
  }
7828
+ candidates.push(...collectPackagedStepDatasetCandidates(statusOrResult));
7734
7829
  candidates.push(...collectPackagedDatasetCandidates(statusOrResult));
7735
- const seen = /* @__PURE__ */ new Set();
7830
+ const sourceIndexes = /* @__PURE__ */ new Map();
7736
7831
  const infos = [];
7737
7832
  for (const candidate of candidates) {
7738
7833
  const info = canonicalRowsInfoFromCandidate({
@@ -7741,10 +7836,15 @@ function collectSerializedDatasetRowsInfos(statusOrResult) {
7741
7836
  });
7742
7837
  if (info) {
7743
7838
  if (info.source) {
7744
- if (seen.has(info.source)) {
7839
+ const existingIndex = sourceIndexes.get(info.source);
7840
+ if (existingIndex !== void 0) {
7841
+ infos[existingIndex] = mergeCanonicalRowsInfo(
7842
+ infos[existingIndex],
7843
+ info
7844
+ );
7745
7845
  continue;
7746
7846
  }
7747
- seen.add(info.source);
7847
+ sourceIndexes.set(info.source, infos.length);
7748
7848
  }
7749
7849
  infos.push(info);
7750
7850
  }
@@ -8586,7 +8686,7 @@ async function handleDbQuery(args) {
8586
8686
  const client2 = new DeeplineClient();
8587
8687
  let result;
8588
8688
  try {
8589
- result = await client2.queryCustomerDb({ sql, maxRows });
8689
+ result = await client2.db.query({ sql, maxRows });
8590
8690
  } catch (error) {
8591
8691
  console.error(formatDbQueryError(sql, error));
8592
8692
  return 1;
@@ -8798,7 +8898,13 @@ Examples:
8798
8898
  deepline db repair
8799
8899
  deepline db repair --json
8800
8900
  `
8801
- ).option("--provider <provider>", "Limit materialized-table repair to one provider").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
8901
+ ).option(
8902
+ "--provider <provider>",
8903
+ "Limit materialized-table repair to one provider"
8904
+ ).option(
8905
+ "--json",
8906
+ "Emit raw JSON response. Also automatic when stdout is piped"
8907
+ ).action(async (options) => {
8802
8908
  process.exitCode = await handleDbRepair([
8803
8909
  ...options.provider ? ["--provider", options.provider] : [],
8804
8910
  ...options.json ? ["--json"] : []
@@ -13760,9 +13866,15 @@ function actionToCommand(action) {
13760
13866
  return null;
13761
13867
  }
13762
13868
  const record = action;
13869
+ if (typeof record.command === "string" && record.command.trim()) {
13870
+ return record.command.trim();
13871
+ }
13763
13872
  if (record.kind === "deepline_run_inspect" && typeof record.runId === "string") {
13764
13873
  return `deepline runs get ${record.runId} --json`;
13765
13874
  }
13875
+ if (record.kind === "deepline_run_full" && typeof record.runId === "string") {
13876
+ return `deepline runs get ${record.runId} --full --json`;
13877
+ }
13766
13878
  if (record.kind === "deepline_run_billing" && typeof record.runId === "string") {
13767
13879
  return `deepline runs get ${record.runId} --full --json | jq '.billing'`;
13768
13880
  }
@@ -13785,19 +13897,70 @@ function actionToCommand(action) {
13785
13897
  }
13786
13898
  return null;
13787
13899
  }
13788
- function readFirstDatasetActions(packaged) {
13789
- for (const dataset of readRecordArray(packaged.datasets)) {
13790
- const actions = readRecord(dataset.actions);
13791
- if (actions) return actions;
13900
+ function packageDatasetRecords(packaged) {
13901
+ const catalog = readRecordArray(packaged.datasets);
13902
+ if (catalog.length > 0) return catalog;
13903
+ return readRecordArray(packaged.steps).flatMap((step) => {
13904
+ const output2 = readRecord(step.output);
13905
+ return output2?.kind === "dataset" ? [output2] : [];
13906
+ });
13907
+ }
13908
+ function packageReturnedDatasetIdentity(packaged) {
13909
+ const datasetIds = /* @__PURE__ */ new Set();
13910
+ const paths = /* @__PURE__ */ new Set();
13911
+ const outputs = readRecord(packaged.outputs) ?? {};
13912
+ for (const outputValue of Object.values(outputs)) {
13913
+ const output2 = readRecord(outputValue);
13914
+ if (output2?.kind !== "dataset") continue;
13915
+ if (typeof output2.datasetId === "string" && output2.datasetId.trim()) {
13916
+ datasetIds.add(output2.datasetId.trim());
13917
+ }
13918
+ for (const candidate of [output2.dataset, output2.path]) {
13919
+ if (typeof candidate === "string" && candidate.trim()) {
13920
+ paths.add(candidate.trim());
13921
+ }
13922
+ }
13792
13923
  }
13793
- for (const step of readRecordArray(packaged.steps)) {
13794
- const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
13795
- const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
13796
- if (actions) {
13797
- return actions;
13924
+ return { datasetIds, paths };
13925
+ }
13926
+ function formatPackageDatasetActionLines(packaged) {
13927
+ const returned = packageReturnedDatasetIdentity(packaged);
13928
+ const lines = [];
13929
+ for (const dataset of packageDatasetRecords(packaged)) {
13930
+ const path = typeof dataset.path === "string" && dataset.path.trim() ? dataset.path.trim() : "dataset";
13931
+ const datasetId = typeof dataset.datasetId === "string" ? dataset.datasetId.trim() : "";
13932
+ const isReturned = datasetId && returned.datasetIds.has(datasetId) || returned.paths.has(path);
13933
+ const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
13934
+ const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
13935
+ const actions = readRecord(dataset.actions) ?? {};
13936
+ if (category === "recovered" && Object.keys(actions).length === 0) {
13937
+ lines.push(
13938
+ ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
13939
+ );
13940
+ } else {
13941
+ lines.push(
13942
+ ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
13943
+ );
13944
+ }
13945
+ const exportCommand = actionToCommand(actions.exportCsv);
13946
+ const currentQueryCommand = actionToCommand(actions.queryCurrentTable);
13947
+ const legacyQueryCommand = actionToCommand(actions.query);
13948
+ if (exportCommand) {
13949
+ lines.push(` export this run: ${exportCommand}`);
13950
+ }
13951
+ if (currentQueryCommand) {
13952
+ lines.push(` query current table: ${currentQueryCommand}`);
13953
+ } else if (legacyQueryCommand) {
13954
+ lines.push(` query run rows (legacy): ${legacyQueryCommand}`);
13955
+ }
13956
+ const unavailable = readRecord(dataset.exportUnavailable);
13957
+ if (typeof unavailable?.reason === "string" && typeof unavailable.message === "string") {
13958
+ lines.push(
13959
+ ` export unavailable (${unavailable.reason}): ${unavailable.message}`
13960
+ );
13798
13961
  }
13799
13962
  }
13800
- return {};
13963
+ return lines;
13801
13964
  }
13802
13965
  function formatInlinePackageValue(value) {
13803
13966
  const compacted = compactReturnValue(value);
@@ -13873,18 +14036,11 @@ function buildRunPackageTextLines(packaged) {
13873
14036
  failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
13874
14037
  );
13875
14038
  }
13876
- for (const output2 of readRecordArray(packaged.datasets)) {
13877
- if (output2.recovered !== true) continue;
13878
- const rowCount = typeof output2.rowCount === "number" ? formatInteger(output2.rowCount) : "persisted";
13879
- const datasetPath = typeof output2.path === "string" ? output2.path : "dataset";
13880
- lines.push(
13881
- ` dataset ${datasetPath}: available, ${rowCount} rows persisted; re-running reuses completed work`
13882
- );
13883
- }
13884
14039
  if (playName) {
13885
14040
  lines.push(` play: ${playName}`);
13886
14041
  }
13887
14042
  lines.push(...formatPackageValueOutputLines(packaged));
14043
+ lines.push(...formatPackageDatasetActionLines(packaged));
13888
14044
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
13889
14045
  const billingCommand = actionToCommand(next.billing);
13890
14046
  const logsCommand = actionToCommand(next.logs);
@@ -13908,16 +14064,20 @@ function buildRunPackageTextLines(packaged) {
13908
14064
  );
13909
14065
  }
13910
14066
  }
13911
- const datasetActions = readFirstDatasetActions(packaged);
13912
14067
  const inspectCommand = actionToCommand(next.inspect);
13913
- const queryCommand = actionToCommand(next.query) ?? actionToCommand(datasetActions.query);
13914
- const exportCommand = actionToCommand(next.export) ?? actionToCommand(datasetActions.exportCsv);
14068
+ const fullResultCommand = actionToCommand(next.full);
14069
+ const hasCatalogExportAction = packageDatasetRecords(packaged).some(
14070
+ (dataset) => Boolean(actionToCommand(readRecord(dataset.actions)?.exportCsv))
14071
+ );
14072
+ const legacyExportCommand = hasCatalogExportAction ? null : actionToCommand(next.export);
13915
14073
  const runAgainCommand = typeof next.run === "string" && next.run.trim() ? next.run.trim() : null;
13916
14074
  if (inspectCommand) lines.push(` inspect: ${inspectCommand}`);
14075
+ if (fullResultCommand) lines.push(` full result: ${fullResultCommand}`);
13917
14076
  if (logsCommand) lines.push(` logs: ${logsCommand}`);
13918
14077
  if (billingCommand) lines.push(` billing: ${billingCommand}`);
13919
- if (queryCommand) lines.push(` query: ${queryCommand}`);
13920
- if (exportCommand) lines.push(` export CSV: ${exportCommand}`);
14078
+ if (legacyExportCommand) {
14079
+ lines.push(` export CSV: ${legacyExportCommand}`);
14080
+ }
13921
14081
  if (runAgainCommand) {
13922
14082
  lines.push(" run again (completed work is reused):");
13923
14083
  lines.push(` ${runAgainCommand}`);
@@ -14217,6 +14377,102 @@ function resolveDatasetByName(available, datasetPath) {
14217
14377
  }
14218
14378
  return null;
14219
14379
  }
14380
+ function canonicalRowsIdentity(info) {
14381
+ return info.datasetId?.trim() ? `id:${info.datasetId.trim()}` : `path:${info.source ?? info.tableNamespace ?? "dataset"}`;
14382
+ }
14383
+ function distinctCanonicalRowsInfos(infos) {
14384
+ const byIdentity = /* @__PURE__ */ new Map();
14385
+ for (const info of infos) {
14386
+ const identity = canonicalRowsIdentity(info);
14387
+ const existing = byIdentity.get(identity);
14388
+ byIdentity.set(
14389
+ identity,
14390
+ existing ? mergeCanonicalRowsInfo(existing, info) : info
14391
+ );
14392
+ }
14393
+ return [...byIdentity.values()];
14394
+ }
14395
+ function packageForExportSelection(status) {
14396
+ const root = status;
14397
+ const nested = readRecord(root.package);
14398
+ if (nested?.kind === "play_run") return nested;
14399
+ return root.kind === "play_run" ? root : null;
14400
+ }
14401
+ function withReturnedDatasetAliases(status, available) {
14402
+ const packaged = packageForExportSelection(status);
14403
+ const outputs = readRecord(packaged?.outputs);
14404
+ if (!outputs) return available;
14405
+ const expanded = [...available];
14406
+ for (const outputValue of Object.values(outputs)) {
14407
+ const output2 = readRecord(outputValue);
14408
+ if (output2?.kind !== "dataset") continue;
14409
+ const alias = typeof output2.path === "string" && output2.path.trim() ? output2.path.trim() : null;
14410
+ if (!alias) continue;
14411
+ const datasetId = typeof output2.datasetId === "string" && output2.datasetId.trim() ? output2.datasetId.trim() : null;
14412
+ const canonicalPath2 = typeof output2.dataset === "string" && output2.dataset.trim() ? output2.dataset.trim() : null;
14413
+ const canonical = available.find(
14414
+ (info) => datasetId && info.datasetId === datasetId || canonicalPath2 && info.source === canonicalPath2
14415
+ );
14416
+ if (canonical) {
14417
+ const aliasIndex = expanded.findIndex((info) => info.source === alias);
14418
+ if (aliasIndex >= 0) {
14419
+ expanded[aliasIndex] = {
14420
+ ...mergeCanonicalRowsInfo(expanded[aliasIndex], canonical),
14421
+ source: alias
14422
+ };
14423
+ } else {
14424
+ expanded.push({ ...canonical, source: alias });
14425
+ }
14426
+ }
14427
+ }
14428
+ return expanded;
14429
+ }
14430
+ function returnedRowsInfos(status, available) {
14431
+ const packaged = packageForExportSelection(status);
14432
+ const outputs = readRecord(packaged?.outputs);
14433
+ if (outputs) {
14434
+ const selected = /* @__PURE__ */ new Map();
14435
+ for (const outputValue of Object.values(outputs)) {
14436
+ const output2 = readRecord(outputValue);
14437
+ if (output2?.kind !== "dataset") continue;
14438
+ const datasetId = typeof output2.datasetId === "string" && output2.datasetId.trim() ? output2.datasetId.trim() : null;
14439
+ const alias = typeof output2.path === "string" && output2.path.trim() ? output2.path.trim() : null;
14440
+ const canonicalPath2 = typeof output2.dataset === "string" && output2.dataset.trim() ? output2.dataset.trim() : null;
14441
+ const info = (alias ? available.find((candidate) => candidate.source === alias) : null) ?? (datasetId ? available.find((candidate) => candidate.datasetId === datasetId) : null) ?? (canonicalPath2 ? available.find((candidate) => candidate.source === canonicalPath2) : null);
14442
+ if (!info) continue;
14443
+ const identity = datasetId ? `id:${datasetId}` : `path:${canonicalPath2 ?? alias ?? info.source ?? "dataset"}`;
14444
+ const aliased = { ...info, source: alias ?? info.source };
14445
+ const existing = selected.get(identity);
14446
+ selected.set(
14447
+ identity,
14448
+ existing ? mergeCanonicalRowsInfo(existing, aliased) : aliased
14449
+ );
14450
+ }
14451
+ if (selected.size > 0) return [...selected.values()];
14452
+ }
14453
+ return distinctCanonicalRowsInfos(
14454
+ available.filter(
14455
+ (info) => Boolean(info.source?.startsWith("result.")) && !info.recovered
14456
+ )
14457
+ );
14458
+ }
14459
+ function exportDatasetCommand(input2) {
14460
+ return `deepline runs export ${input2.runId} --dataset ${shellSingleQuote(
14461
+ input2.datasetPath
14462
+ )} --out ${shellSingleQuote(resolve8(input2.outPath))}`;
14463
+ }
14464
+ function datasetChoiceLines(input2) {
14465
+ return input2.datasets.flatMap((dataset) => {
14466
+ const path = dataset.source ?? dataset.datasetId ?? dataset.tableNamespace;
14467
+ return path ? [
14468
+ exportDatasetCommand({
14469
+ runId: input2.runId,
14470
+ datasetPath: path,
14471
+ outPath: input2.outPath
14472
+ })
14473
+ ] : [];
14474
+ });
14475
+ }
14220
14476
  function assertDatasetHasExportableRows(input2) {
14221
14477
  if (input2.rowsInfo.rows.length > 0) {
14222
14478
  return input2.rowsInfo;
@@ -14237,28 +14493,93 @@ function assertDatasetHasExportableRows(input2) {
14237
14493
  }
14238
14494
  );
14239
14495
  }
14496
+ function assertDatasetExportAvailable(input2) {
14497
+ if (input2.rowsInfo.exportUnavailableReason !== "shared_table_namespace") {
14498
+ return;
14499
+ }
14500
+ throw new DeeplineError(
14501
+ input2.rowsInfo.exportUnavailableMessage ?? "Run CSV export is unavailable because multiple Dataset Handles share one physical table.",
14502
+ void 0,
14503
+ "RUN_EXPORT_UNAVAILABLE",
14504
+ {
14505
+ runId: input2.status.runId,
14506
+ dataset: input2.rowsInfo.source,
14507
+ datasetId: input2.rowsInfo.datasetId ?? null,
14508
+ tableNamespace: input2.rowsInfo.tableNamespace ?? null,
14509
+ reason: input2.rowsInfo.exportUnavailableReason
14510
+ }
14511
+ );
14512
+ }
14240
14513
  async function exportPlayStatusRows(client2, status, outPath, options = {}) {
14241
14514
  if (!outPath) {
14242
14515
  return null;
14243
14516
  }
14244
- const availableRows = collectSerializedDatasetRowsInfos(status);
14245
- const rowsInfo = options.datasetPath ? resolveDatasetByName(availableRows, options.datasetPath) ?? null : availableRows.length === 1 ? availableRows[0] : null;
14517
+ const availableRows = withReturnedDatasetAliases(
14518
+ status,
14519
+ distinctCanonicalRowsInfos(collectSerializedDatasetRowsInfos(status))
14520
+ );
14521
+ const returnedRows = returnedRowsInfos(status, availableRows);
14522
+ const recoveredRows = distinctCanonicalRowsInfos(
14523
+ availableRows.filter((info) => info.recovered)
14524
+ );
14525
+ const rowsInfo = options.datasetPath ? resolveDatasetByName(availableRows, options.datasetPath) ?? null : returnedRows.length === 1 ? returnedRows[0] : returnedRows.length === 0 && recoveredRows.length === 1 ? recoveredRows[0] : null;
14246
14526
  if (!rowsInfo && options.datasetPath) {
14247
14527
  const available = availableRows.map((info) => info.source).filter((source) => typeof source === "string");
14528
+ const commands = datasetChoiceLines({
14529
+ runId: status.runId,
14530
+ datasets: availableRows,
14531
+ outPath
14532
+ });
14248
14533
  throw new DeeplineError(
14249
- `Run ${status.runId} did not return a dataset at ${options.datasetPath}.` + (available.length > 0 ? ` Available datasets: ${available.join(", ")}.` : ""),
14534
+ `Run ${status.runId} did not return a dataset at ${options.datasetPath}.` + (available.length > 0 ? ` Available datasets: ${available.join(", ")}.
14535
+ ${commands.join("\n")}` : ""),
14250
14536
  void 0,
14251
14537
  "RUN_EXPORT_DATASET_NOT_FOUND",
14252
14538
  { runId: status.runId, dataset: options.datasetPath, available }
14253
14539
  );
14254
14540
  }
14255
- if (!options.datasetPath && availableRows.length > 1) {
14256
- const available = availableRows.map((info) => info.source).filter((source) => typeof source === "string");
14541
+ if (!options.datasetPath && returnedRows.length > 1) {
14542
+ const available = returnedRows.map((info) => info.source).filter((source) => typeof source === "string");
14543
+ const commands = datasetChoiceLines({
14544
+ runId: status.runId,
14545
+ datasets: returnedRows,
14546
+ outPath
14547
+ });
14257
14548
  throw new DeeplineError(
14258
- `Run ${status.runId} returned multiple datasets. Choose one with --dataset <path>: ${available.join(", ")}.`,
14549
+ `Run ${status.runId} returned multiple datasets. Choose one:
14550
+ ${commands.join("\n")}`,
14259
14551
  void 0,
14260
14552
  "RUN_EXPORT_DATASET_REQUIRED",
14261
- { runId: status.runId, available }
14553
+ {
14554
+ runId: status.runId,
14555
+ available,
14556
+ datasets: returnedRows.map((info, index) => ({
14557
+ path: info.source,
14558
+ rowCount: info.totalRows,
14559
+ command: commands[index]
14560
+ }))
14561
+ }
14562
+ );
14563
+ }
14564
+ if (!options.datasetPath && returnedRows.length === 0 && recoveredRows.length > 1) {
14565
+ const commands = datasetChoiceLines({
14566
+ runId: status.runId,
14567
+ datasets: recoveredRows,
14568
+ outPath
14569
+ });
14570
+ throw new DeeplineError(
14571
+ `Run ${status.runId} has multiple recovered datasets. Choose one:
14572
+ ${commands.join("\n")}`,
14573
+ void 0,
14574
+ "RUN_EXPORT_DATASET_REQUIRED",
14575
+ {
14576
+ runId: status.runId,
14577
+ datasets: recoveredRows.map((info, index) => ({
14578
+ path: info.source,
14579
+ rowCount: info.totalRows,
14580
+ command: commands[index]
14581
+ }))
14582
+ }
14262
14583
  );
14263
14584
  }
14264
14585
  if (!rowsInfo) {
@@ -14266,6 +14587,7 @@ async function exportPlayStatusRows(client2, status, outPath, options = {}) {
14266
14587
  `Run ${status.runId} did not expose a row-shaped final output to export.`
14267
14588
  );
14268
14589
  }
14590
+ assertDatasetExportAvailable({ rowsInfo, status });
14269
14591
  const attempts = Math.max(1, Math.trunc(options.attempts ?? 1));
14270
14592
  const retryDelayMs = Math.max(0, Math.trunc(options.retryDelayMs ?? 0));
14271
14593
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
@@ -14277,6 +14599,9 @@ async function exportPlayStatusRows(client2, status, outPath, options = {}) {
14277
14599
  rowsInfo
14278
14600
  });
14279
14601
  } catch (error) {
14602
+ if (error instanceof DeeplineError && error.code === "RUN_EXPORT_SCOPE_MISMATCH") {
14603
+ throw error;
14604
+ }
14280
14605
  if (!rowsInfo.complete) {
14281
14606
  throw error;
14282
14607
  }
@@ -20138,7 +20463,9 @@ function readFirstEnrichDatasetActions(value) {
20138
20463
  }
20139
20464
  const record = candidate;
20140
20465
  const actions = isRecord7(record.actions) ? record.actions : null;
20141
- const query = isRecord7(actions?.query) ? actions.query : null;
20466
+ const currentQuery = isRecord7(actions?.queryCurrentTable) ? actions.queryCurrentTable : null;
20467
+ const legacyQuery = isRecord7(actions?.query) ? actions.query : null;
20468
+ const query = currentQuery?.kind === "deepline_db_query" ? currentQuery : legacyQuery?.kind === "deepline_db_query" ? legacyQuery : null;
20142
20469
  if (query?.kind === "deepline_db_query") {
20143
20470
  return {
20144
20471
  dataset: record,
@@ -20364,7 +20691,7 @@ async function collectCustomerDbFailureJobs(input2) {
20364
20691
  for (let attempt = 0; attempt <= retryDelays.length; attempt += 1) {
20365
20692
  try {
20366
20693
  attempts = attempt + 1;
20367
- result = await input2.client.queryCustomerDb({
20694
+ result = await input2.client.db.query({
20368
20695
  sql,
20369
20696
  maxRows: 1e3
20370
20697
  });