deepline 0.1.160 → 0.1.162

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.
@@ -64,11 +64,13 @@ import {
64
64
  import { RECEIPT_STATUS_CODE, receiptStatusFromCode } from './receipt-status';
65
65
  import type { MapRowOutcome } from './durability-store';
66
66
  import {
67
+ normalizeRuntimeMapInputIndex,
67
68
  prepareRuntimeSheetRowTransitions,
68
69
  type RuntimePreparedCompletedRow,
69
70
  type RuntimePreparedFailedRow,
70
71
  } from './runtime-sheet-row-transition';
71
72
  import {
73
+ MAP_ROW_OUTCOME_RUNTIME_FIELDS,
72
74
  mapRowOutcomeRuntimeFields,
73
75
  resolveMapRowOutcomeKey,
74
76
  } from './map-row-outcome';
@@ -2251,6 +2253,21 @@ async function prepareRuntimeSheetDatasetRows(
2251
2253
  AND (${targetMissingOutputSql})
2252
2254
  RETURNING target._key
2253
2255
  ),
2256
+ claimed_existing_rows AS (
2257
+ UPDATE ${sheetTable(session)} AS target
2258
+ SET _run_id = $4::text,
2259
+ _input_index = input_rows._input_index,
2260
+ _updated_at = now(),
2261
+ _version = ${nextRuntimeSheetVersionExpression(session)}
2262
+ FROM input_rows
2263
+ WHERE target._key = input_rows._key
2264
+ AND target._status IN ('pending', 'running', 'failed')
2265
+ AND (
2266
+ target._run_id IS DISTINCT FROM $4::text
2267
+ OR target._input_index IS DISTINCT FROM input_rows._input_index
2268
+ )
2269
+ RETURNING target._key
2270
+ ),
2254
2271
  pending_rows AS (
2255
2272
  SELECT _key
2256
2273
  FROM inserted_rows
@@ -2258,6 +2275,9 @@ async function prepareRuntimeSheetDatasetRows(
2258
2275
  SELECT _key
2259
2276
  FROM missing_output_rows
2260
2277
  UNION
2278
+ SELECT _key
2279
+ FROM claimed_existing_rows
2280
+ UNION
2261
2281
  SELECT existing._key
2262
2282
  FROM ${sheetTable(session)} AS existing
2263
2283
  JOIN input_rows ON input_rows._key = existing._key
@@ -3206,7 +3226,10 @@ export async function startRuntimeSheetDataset(
3206
3226
  rows: input.rows.length,
3207
3227
  });
3208
3228
  const normalizeStartedAt = Date.now();
3209
- const uniqueRows = new Map<string, Record<string, unknown>>();
3229
+ const uniqueRows = new Map<
3230
+ string,
3231
+ { row: Record<string, unknown>; inputIndex: number | null }
3232
+ >();
3210
3233
  for (const row of input.rows) {
3211
3234
  // Materializes projected CSV aliases as visible cells and drops internal
3212
3235
  // __deepline* keys — a plain spread would silently lose the
@@ -3216,15 +3239,20 @@ export async function startRuntimeSheetDataset(
3216
3239
  resolveMapRowOutcomeKey(row) ??
3217
3240
  derivePlayRowIdentity(cleanedRow, input.tableNamespace);
3218
3241
  if (key && !uniqueRows.has(key)) {
3219
- uniqueRows.set(key, cleanedRow);
3242
+ uniqueRows.set(key, {
3243
+ row: cleanedRow,
3244
+ inputIndex: normalizeRuntimeMapInputIndex(
3245
+ row[MAP_ROW_OUTCOME_RUNTIME_FIELDS.inputIndex],
3246
+ ),
3247
+ });
3220
3248
  }
3221
3249
  }
3222
3250
  const inputOffset = Math.max(0, Math.floor(input.inputOffset ?? 0));
3223
3251
  const rowEntries = [...uniqueRows.entries()].map(
3224
- ([key, row], inputIndex) => ({
3252
+ ([key, entry], inputIndex) => ({
3225
3253
  key,
3226
- row,
3227
- inputIndex: inputOffset + inputIndex,
3254
+ row: entry.row,
3255
+ inputIndex: entry.inputIndex ?? inputOffset + inputIndex,
3228
3256
  }),
3229
3257
  );
3230
3258
  timings.push({
@@ -3409,6 +3437,7 @@ async function completeRuntimeMapRowChunks(
3409
3437
  AND (target._run_id IS NULL OR target._run_id <= $5::text)
3410
3438
  AND (
3411
3439
  target._status <> 'enriched'
3440
+ OR target._run_id IS DISTINCT FROM $5::text
3412
3441
  OR (${targetChangedPatchedCellSql})
3413
3442
  OR EXISTS (
3414
3443
  SELECT 1
@@ -3608,6 +3637,7 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
3608
3637
  AND (target._run_id IS NULL OR target._run_id <= $5::text)
3609
3638
  AND (
3610
3639
  target._status <> 'enriched'
3640
+ OR target._run_id IS DISTINCT FROM $5::text
3611
3641
  OR (${targetChangedPatchedCellSql})
3612
3642
  OR EXISTS (
3613
3643
  SELECT 1
@@ -3722,6 +3752,148 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
3722
3752
  return { updated };
3723
3753
  }
3724
3754
 
3755
+ async function insertMissingCompletedMapRowChunks(
3756
+ client: RuntimeQueryClient,
3757
+ session: RuntimePostgresSession,
3758
+ input: CompleteRuntimeMapRowChunksInput,
3759
+ ): Promise<{ inserted: number }> {
3760
+ let inserted = 0;
3761
+ const physicalInsertColumnsSql =
3762
+ input.physicalColumnProjections.length > 0
3763
+ ? `, ${input.physicalColumnProjections
3764
+ .map((column) => quoteIdentifier(column.sqlName))
3765
+ .join(', ')}`
3766
+ : '';
3767
+ const physicalInsertValuesSql =
3768
+ input.physicalColumnProjections.length > 0
3769
+ ? `, ${input.physicalColumnProjections
3770
+ .map(
3771
+ (column) =>
3772
+ `missing_rows.data_patch -> ${quoteLiteral(column.fieldName)}`,
3773
+ )
3774
+ .join(', ')}`
3775
+ : '';
3776
+
3777
+ for (const chunk of input.chunks) {
3778
+ const chunkKeys = chunk.map((row) => row.key);
3779
+ const chunkInputIndexes = chunk.map((row) => row.input_index);
3780
+ const chunkDataPatches = chunk.map((row) =>
3781
+ stringifyPostgresJson(row.data_patch),
3782
+ );
3783
+ const chunkCellMetaPatches = chunk.map((row) =>
3784
+ stringifyPostgresJson(row.cell_meta_patch),
3785
+ );
3786
+ const { rows } = await client.query<{ inserted: number }>(
3787
+ `WITH input_rows AS (
3788
+ SELECT key_values._key,
3789
+ input_index_values.input_index,
3790
+ data_values.data_patch,
3791
+ cell_meta_values.cell_meta_patch
3792
+ FROM unnest($1::text[]) WITH ORDINALITY AS key_values(_key, ord)
3793
+ JOIN unnest($2::bigint[]) WITH ORDINALITY AS input_index_values(input_index, ord)
3794
+ ON input_index_values.ord = key_values.ord
3795
+ JOIN unnest($3::jsonb[]) WITH ORDINALITY AS data_values(data_patch, ord)
3796
+ ON data_values.ord = key_values.ord
3797
+ JOIN unnest($4::jsonb[]) WITH ORDINALITY AS cell_meta_values(cell_meta_patch, ord)
3798
+ ON cell_meta_values.ord = key_values.ord
3799
+ ),
3800
+ missing_rows AS (
3801
+ SELECT input_rows.*
3802
+ FROM input_rows
3803
+ WHERE NOT EXISTS (
3804
+ SELECT 1
3805
+ FROM ${sheetTable(session)} AS target
3806
+ WHERE target._key = input_rows._key
3807
+ OR (
3808
+ input_rows.input_index IS NOT NULL
3809
+ AND target._run_id = $5::text
3810
+ AND target._input_index = input_rows.input_index
3811
+ )
3812
+ )
3813
+ ),
3814
+ inserted_rows AS (
3815
+ INSERT INTO ${sheetTable(session)} (_key, _status, _run_id, _input_index, _cell_meta${physicalInsertColumnsSql})
3816
+ SELECT _key, 'enriched', $5::text, input_index, cell_meta_patch${physicalInsertValuesSql}
3817
+ FROM missing_rows
3818
+ ON CONFLICT (_key) DO NOTHING
3819
+ RETURNING _key
3820
+ ),
3821
+ inserted_count AS (
3822
+ SELECT count(*)::bigint AS c FROM inserted_rows
3823
+ ),
3824
+ summary_delta AS (
3825
+ INSERT INTO ${summaryTable(session)} AS target (
3826
+ play_name,
3827
+ table_namespace,
3828
+ total,
3829
+ queued,
3830
+ running,
3831
+ completed,
3832
+ failed
3833
+ )
3834
+ SELECT $6::text,
3835
+ $7::text,
3836
+ c::int,
3837
+ 0,
3838
+ 0,
3839
+ c::int,
3840
+ 0
3841
+ FROM inserted_count
3842
+ WHERE c > 0
3843
+ ON CONFLICT (play_name, table_namespace) DO UPDATE SET
3844
+ total = ${runtimeSummaryTotalSql({
3845
+ currentTotal: 'target.total',
3846
+ totalDelta: 'EXCLUDED.total',
3847
+ queued: 'target.queued',
3848
+ running: 'target.running',
3849
+ completed: 'target.completed + EXCLUDED.completed',
3850
+ failed: 'target.failed',
3851
+ })},
3852
+ completed = target.completed + EXCLUDED.completed,
3853
+ _updated_at = now()
3854
+ RETURNING 1
3855
+ ),
3856
+ completed_cell_delta AS (
3857
+ SELECT field_values.field, (SELECT c FROM inserted_count) AS c
3858
+ FROM unnest($8::text[]) AS field_values(field)
3859
+ WHERE (SELECT c FROM inserted_count) > 0
3860
+ ),
3861
+ column_delta AS (
3862
+ INSERT INTO ${columnSummaryTable(session)} AS target (
3863
+ play_name,
3864
+ table_namespace,
3865
+ field,
3866
+ completed,
3867
+ failed
3868
+ )
3869
+ SELECT $6::text,
3870
+ $7::text,
3871
+ field,
3872
+ c::int,
3873
+ 0
3874
+ FROM completed_cell_delta
3875
+ ON CONFLICT (play_name, table_namespace, field) DO UPDATE SET
3876
+ completed = target.completed + EXCLUDED.completed,
3877
+ _updated_at = now()
3878
+ RETURNING 1
3879
+ )
3880
+ SELECT c::int AS inserted FROM inserted_count`,
3881
+ [
3882
+ chunkKeys,
3883
+ chunkInputIndexes,
3884
+ chunkDataPatches,
3885
+ chunkCellMetaPatches,
3886
+ input.runId,
3887
+ input.normalizedPlayName,
3888
+ input.normalizedTableNamespace,
3889
+ [...new Set(input.outputFields)],
3890
+ ],
3891
+ );
3892
+ inserted += Number(rows[0]?.inserted ?? 0);
3893
+ }
3894
+ return { inserted };
3895
+ }
3896
+
3725
3897
  /**
3726
3898
  * Mark map rows FAILED in the per-run scoped Postgres sheet table by key.
3727
3899
  *
@@ -4003,17 +4175,30 @@ export async function completeRuntimeMapRows(
4003
4175
  async (client) => {
4004
4176
  const completed =
4005
4177
  completedRows.length > 0
4006
- ? await completeRuntimeMapRowChunks(client, session, {
4007
- chunks,
4008
- physicalUpdateSetSql,
4009
- physicalColumnProjections: projections,
4010
- runId: input.runId,
4011
- normalizedPlayName: normalizePlayNameForSheet(session.playName),
4012
- normalizedTableNamespace: normalizeTableNamespace(
4013
- input.tableNamespace,
4014
- ),
4015
- outputFields,
4016
- })
4178
+ ? await (async () => {
4179
+ const chunkInput = {
4180
+ chunks,
4181
+ physicalUpdateSetSql,
4182
+ physicalColumnProjections: projections,
4183
+ runId: input.runId,
4184
+ normalizedPlayName: normalizePlayNameForSheet(session.playName),
4185
+ normalizedTableNamespace: normalizeTableNamespace(
4186
+ input.tableNamespace,
4187
+ ),
4188
+ outputFields,
4189
+ };
4190
+ const updated = await completeRuntimeMapRowChunks(
4191
+ client,
4192
+ session,
4193
+ chunkInput,
4194
+ );
4195
+ const inserted = await insertMissingCompletedMapRowChunks(
4196
+ client,
4197
+ session,
4198
+ chunkInput,
4199
+ );
4200
+ return { updated: updated.updated + inserted.inserted };
4201
+ })()
4017
4202
  : { updated: 0 };
4018
4203
  const failed =
4019
4204
  failedRows.length > 0
@@ -4075,6 +4260,65 @@ export async function readRuntimeSheetDatasetRows(
4075
4260
  };
4076
4261
  }
4077
4262
 
4263
+ export async function readRuntimeSheetDatasetRowKeys(
4264
+ context: RuntimeApiContext & { playName: string },
4265
+ input: {
4266
+ tableNamespace: string;
4267
+ runId: string;
4268
+ keys: string[];
4269
+ rowMode?: 'output' | 'all';
4270
+ },
4271
+ ): Promise<{ keys: string[] }> {
4272
+ const keys = [
4273
+ ...new Set(
4274
+ input.keys
4275
+ .map((key) => key.trim())
4276
+ .filter((key) => key.length > 0),
4277
+ ),
4278
+ ];
4279
+ if (keys.length === 0) {
4280
+ return { keys: [] };
4281
+ }
4282
+ const session = requireRuntimePostgresSession(
4283
+ await getRuntimeDbSession(
4284
+ {
4285
+ ...context,
4286
+ playName: context.playName,
4287
+ runId: context.runId ?? input.runId,
4288
+ },
4289
+ {
4290
+ tableNamespace: input.tableNamespace,
4291
+ logicalTable: 'sheet_rows',
4292
+ operations: ['rows.read'],
4293
+ limits: { maxRows: runtimeDbSessionRowLimit(keys.length) },
4294
+ },
4295
+ ),
4296
+ );
4297
+ const rows = await withRuntimePostgres(session, async (client) => {
4298
+ if (input.rowMode === 'all') {
4299
+ const { rows: matchedRows } = await client.query<{ _key: string }>(
4300
+ `SELECT _key
4301
+ FROM ${sheetTable(session)}
4302
+ WHERE _run_id = $1::text
4303
+ AND _key = ANY($2::text[])
4304
+ AND _status IN ('enriched', 'failed')`,
4305
+ [input.runId, keys],
4306
+ );
4307
+ return matchedRows;
4308
+ }
4309
+ const { rows: matchedRows } = await client.query<{ _key: string }>(
4310
+ `SELECT _key
4311
+ FROM ${sheetTable(session)}
4312
+ WHERE _run_id = $1::text
4313
+ AND _key = ANY($2::text[])
4314
+ AND _status = 'enriched'`,
4315
+ [input.runId, keys],
4316
+ );
4317
+ return matchedRows;
4318
+ });
4319
+ return { keys: rows.map((row) => row._key) };
4320
+ }
4321
+
4078
4322
  export async function persistRuntimeCsvDataset(
4079
4323
  context: RuntimeApiContext & { playName: string },
4080
4324
  input: {
package/dist/cli/index.js CHANGED
@@ -237,8 +237,6 @@ var PROD_URL = "https://code.deepline.com";
237
237
  var DEFAULT_TIMEOUT = 6e4;
238
238
  var DEFAULT_MAX_RETRIES = 3;
239
239
  var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
240
- var WORKSPACE_RESTORE_ENV_DIR = ".deepline";
241
- var WORKSPACE_RESTORE_ENV_FILE = ".env";
242
240
  var COWORK_IGNORED_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
243
241
  ".auto-memory",
244
242
  ".claude",
@@ -553,18 +551,6 @@ function ensureProjectEnvIsIgnored(dir) {
553
551
  (0, import_node_fs.writeFileSync)(gitignorePath, `${existing}${prefix}${entry}
554
552
  `, "utf-8");
555
553
  }
556
- function ensureWorkspaceRestoreEnvIsIgnored(workspaceDir) {
557
- const gitignorePath = (0, import_node_path.join)(workspaceDir, ".gitignore");
558
- const entry = `${WORKSPACE_RESTORE_ENV_DIR}/`;
559
- const existing = (0, import_node_fs.existsSync)(gitignorePath) ? (0, import_node_fs.readFileSync)(gitignorePath, "utf-8") : "";
560
- const alreadyIgnored = existing.split(/\r?\n/).map((line) => line.trim()).some(
561
- (line) => line === entry || line === `/${entry}` || line === WORKSPACE_RESTORE_ENV_DIR || line === `/${WORKSPACE_RESTORE_ENV_DIR}`
562
- );
563
- if (alreadyIgnored) return;
564
- const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
565
- (0, import_node_fs.writeFileSync)(gitignorePath, `${existing}${prefix}${entry}
566
- `, "utf-8");
567
- }
568
554
  function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
569
555
  const target = resolveProjectPinTarget(startDir);
570
556
  if (!target.ok) {
@@ -578,27 +564,6 @@ function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
578
564
  mergeProjectEnvFile(filePath, values);
579
565
  return [filePath];
580
566
  }
581
- function saveCoworkWorkspaceRestoreEnvValues(values, startDir = process.cwd()) {
582
- if (!isCoworkLikeSandbox()) return [];
583
- const target = resolveProjectPinTarget(startDir);
584
- if (!target.ok || target.source === "cwd") return [];
585
- const workspaceDir = target.dir;
586
- const filePath = (0, import_node_path.join)(
587
- workspaceDir,
588
- WORKSPACE_RESTORE_ENV_DIR,
589
- WORKSPACE_RESTORE_ENV_FILE
590
- );
591
- const existing = parseEnvFile(filePath);
592
- const merged = { ...existing, ...values };
593
- const dir = (0, import_node_path.dirname)(filePath);
594
- if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
595
- ensureWorkspaceRestoreEnvIsIgnored(workspaceDir);
596
- const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
597
- const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
598
- (0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
599
- `, "utf-8");
600
- return [filePath];
601
- }
602
567
  function resolveProjectPinTarget(startDir = process.cwd()) {
603
568
  const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
604
569
  if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
@@ -657,10 +622,10 @@ var SDK_RELEASE = {
657
622
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
658
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
659
624
  // fields shipped in 0.1.153.
660
- version: "0.1.160",
625
+ version: "0.1.162",
661
626
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
662
627
  supportPolicy: {
663
- latest: "0.1.160",
628
+ latest: "0.1.162",
664
629
  minimumSupported: "0.1.53",
665
630
  deprecatedBelow: "0.1.53",
666
631
  commandMinimumSupported: [
@@ -4748,9 +4713,6 @@ function saveEnvValues(values, baseUrl) {
4748
4713
  ...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
4749
4714
  };
4750
4715
  saveHostEnvValues(baseUrl, filtered);
4751
- if (filtered[API_KEY_ENV]) {
4752
- saveCoworkWorkspaceRestoreEnvValues(filtered);
4753
- }
4754
4716
  }
4755
4717
  async function httpJson(method, url, apiKey, body) {
4756
4718
  const headers = {
@@ -17780,7 +17742,7 @@ function fallbackRowsInfoForGeneratedEnrichExport(status, options) {
17780
17742
  columns: [],
17781
17743
  columnsExplicit: false,
17782
17744
  complete: false,
17783
- source: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
17745
+ source: null,
17784
17746
  tableNamespace: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE
17785
17747
  };
17786
17748
  }
@@ -17801,10 +17763,45 @@ function hasLossyPreviewPlaceholder(value, depth = 0) {
17801
17763
  }
17802
17764
  return false;
17803
17765
  }
17766
+ function statusReferencesGeneratedEnrichRows(value, depth = 0) {
17767
+ if (depth > 12 || value === null || value === void 0) {
17768
+ return false;
17769
+ }
17770
+ if (typeof value === "string") {
17771
+ return value.trim() === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17772
+ }
17773
+ if (Array.isArray(value)) {
17774
+ return value.some(
17775
+ (item) => statusReferencesGeneratedEnrichRows(item, depth + 1)
17776
+ );
17777
+ }
17778
+ if (typeof value === "object") {
17779
+ return Object.values(value).some(
17780
+ (item) => statusReferencesGeneratedEnrichRows(item, depth + 1)
17781
+ );
17782
+ }
17783
+ return false;
17784
+ }
17785
+ function generatedEnrichRowsTableNamespaceForExport(rowsInfo, status) {
17786
+ const tableNamespace = rowsInfo.tableNamespace?.trim() || null;
17787
+ if (tableNamespace === "result.rows") {
17788
+ return GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17789
+ }
17790
+ if (!tableNamespace && statusReferencesGeneratedEnrichRows(status)) {
17791
+ return GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
17792
+ }
17793
+ return tableNamespace;
17794
+ }
17804
17795
  function shouldFetchBackingRowsForEnrichExport(rowsInfo, status, options = {}) {
17805
17796
  const terminalStatus = readEnrichRunStatus(status);
17806
- const tableNamespace = rowsInfo.tableNamespace?.trim();
17797
+ const tableNamespace = generatedEnrichRowsTableNamespaceForExport(
17798
+ rowsInfo,
17799
+ status
17800
+ );
17807
17801
  if (terminalStatus === "failed" || terminalStatus === "cancelled") {
17802
+ if (tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && rowsInfo.source !== null && typeof options.selectedSourceRows === "number" && rowsInfo.rows.length < options.selectedSourceRows) {
17803
+ return true;
17804
+ }
17808
17805
  return tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && (rowsInfo.recovered === true || hasPartialRunOutputWarning(status));
17809
17806
  }
17810
17807
  if (tableNamespace === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE && typeof options.selectedSourceRows === "number" && rowsInfo.rows.length < options.selectedSourceRows) {
@@ -17932,6 +17929,45 @@ function exportableSheetRow2(row, sourceRowStart = 0) {
17932
17929
  }
17933
17930
  return fallback;
17934
17931
  }
17932
+ function mergeExportedSheetRow(target, next) {
17933
+ const baseMetadata = target._metadata;
17934
+ const nextMetadata = next._metadata;
17935
+ for (const [key, value] of Object.entries(next)) {
17936
+ const existing = target[key];
17937
+ if (isNonEmptyCsvCell(existing) && !isNonEmptyCsvCell(value)) {
17938
+ continue;
17939
+ }
17940
+ target[key] = value;
17941
+ }
17942
+ const metadata = mergeLegacyMetadataCell(baseMetadata, nextMetadata);
17943
+ if (metadata !== void 0) {
17944
+ target._metadata = metadata;
17945
+ }
17946
+ }
17947
+ function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
17948
+ const mergedRows = [];
17949
+ const bySourceRowIndex = /* @__PURE__ */ new Map();
17950
+ for (const row of rows) {
17951
+ const rowIndex = sourceRowIndexFromEnrichRow(
17952
+ row,
17953
+ sourceRowStart,
17954
+ Number.MAX_SAFE_INTEGER
17955
+ );
17956
+ if (rowIndex === null) {
17957
+ mergedRows.push(row);
17958
+ continue;
17959
+ }
17960
+ const existing = bySourceRowIndex.get(rowIndex);
17961
+ if (existing) {
17962
+ mergeExportedSheetRow(existing, row);
17963
+ continue;
17964
+ }
17965
+ const next = { ...row };
17966
+ bySourceRowIndex.set(rowIndex, next);
17967
+ mergedRows.push(next);
17968
+ }
17969
+ return mergedRows;
17970
+ }
17935
17971
  function sourceRowIndexFromEnrichRow(row, start, end) {
17936
17972
  const value = row[ENRICH_SOURCE_ROW_INDEX_COLUMN];
17937
17973
  const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
@@ -18036,7 +18072,11 @@ function aliasFailureCellCandidates(row, alias) {
18036
18072
  if (key.startsWith(dottedPrefix)) {
18037
18073
  assignFlattenedFailurePath(nested, key.slice(dottedPrefix.length), value);
18038
18074
  } else if (key.startsWith(underscorePrefix)) {
18039
- assignFlattenedFailurePath(nested, key.slice(underscorePrefix.length), value);
18075
+ assignFlattenedFailurePath(
18076
+ nested,
18077
+ key.slice(underscorePrefix.length),
18078
+ value
18079
+ );
18040
18080
  }
18041
18081
  }
18042
18082
  if (Object.keys(nested).length > 0) {
@@ -18414,13 +18454,14 @@ function mergePreferredColumns(preferredColumns, rows) {
18414
18454
  async function fetchBackingRowsForCsvExport(input2) {
18415
18455
  const runId = extractRunId(input2.status);
18416
18456
  const playName = extractPlayName2(input2.status);
18417
- const tableNamespace = input2.rowsInfo.tableNamespace?.trim() || GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
18457
+ const tableNamespace = generatedEnrichRowsTableNamespaceForExport(input2.rowsInfo, input2.status) || GENERATED_ENRICH_ROWS_TABLE_NAMESPACE;
18418
18458
  if (!runId || !playName || !tableNamespace) {
18419
18459
  return null;
18420
18460
  }
18421
18461
  const deadline = Date.now() + enrichExportBackingRowsWaitMs();
18422
18462
  let lastRows = [];
18423
- const minimumExpectedRows = typeof input2.expectedRows === "number" && input2.expectedRows > 0 ? Math.trunc(input2.expectedRows) : input2.rowsInfo.totalRows;
18463
+ const hasExplicitExpectedRows = typeof input2.expectedRows === "number" && input2.expectedRows > 0;
18464
+ const minimumExpectedRows = hasExplicitExpectedRows ? Math.trunc(Number(input2.expectedRows)) : input2.rowsInfo.totalRows;
18424
18465
  let lastExpectedTotal = minimumExpectedRows;
18425
18466
  for (; ; ) {
18426
18467
  const sheetRows = [];
@@ -18445,10 +18486,15 @@ async function fetchBackingRowsForCsvExport(input2) {
18445
18486
  }
18446
18487
  offset += page.rows.length;
18447
18488
  }
18448
- const rows = sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row));
18489
+ const rawRows = sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row));
18490
+ const rows = coalesceExportableSheetRows(
18491
+ rawRows,
18492
+ input2.sourceRowStart ?? 0
18493
+ );
18449
18494
  lastRows = rows;
18450
18495
  lastExpectedTotal = expectedTotal;
18451
- if (expectedTotal > 0 && rows.length >= expectedTotal || expectedTotal === 0 && rows.length > 0) {
18496
+ const requiredExportRows = hasExplicitExpectedRows ? minimumExpectedRows : expectedTotal;
18497
+ if (requiredExportRows > 0 && rows.length >= requiredExportRows || requiredExportRows === 0 && rows.length > 0) {
18452
18498
  return {
18453
18499
  ...input2.rowsInfo,
18454
18500
  rows,
@@ -18456,7 +18502,7 @@ async function fetchBackingRowsForCsvExport(input2) {
18456
18502
  input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
18457
18503
  rows
18458
18504
  ),
18459
- totalRows: Math.max(rows.length, expectedTotal),
18505
+ totalRows: hasExplicitExpectedRows ? Math.max(rows.length, minimumExpectedRows) : Math.max(rows.length, expectedTotal),
18460
18506
  complete: true,
18461
18507
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
18462
18508
  };
@@ -18476,7 +18522,7 @@ async function fetchBackingRowsForCsvExport(input2) {
18476
18522
  input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
18477
18523
  lastRows
18478
18524
  ),
18479
- totalRows: Math.max(lastExpectedTotal, input2.rowsInfo.totalRows),
18525
+ totalRows: hasExplicitExpectedRows ? Math.max(lastRows.length, minimumExpectedRows) : Math.max(lastExpectedTotal, input2.rowsInfo.totalRows),
18480
18526
  complete: false,
18481
18527
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
18482
18528
  };
@@ -18664,8 +18710,13 @@ function materializeAliasSuccessCell(row, alias) {
18664
18710
  directCells.push({ field, value });
18665
18711
  }
18666
18712
  }
18667
- for (const preferredField of [alias, ...ENRICH_FLATTENED_SUCCESS_FIELD_PRIORITY]) {
18668
- const preferred = directCells.find(({ field }) => field === preferredField);
18713
+ for (const preferredField of [
18714
+ alias,
18715
+ ...ENRICH_FLATTENED_SUCCESS_FIELD_PRIORITY
18716
+ ]) {
18717
+ const preferred = directCells.find(
18718
+ ({ field }) => field === preferredField
18719
+ );
18669
18720
  if (preferred) {
18670
18721
  return materializeCsvCellValue(preferred.value);
18671
18722
  }
@@ -18867,7 +18918,7 @@ function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, options =
18867
18918
  return;
18868
18919
  }
18869
18920
  const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
18870
- const dataset = rowsInfo.source ?? "result.rows";
18921
+ const dataset = rowsInfo.source ?? rowsInfo.tableNamespace ?? "result.rows";
18871
18922
  const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
18872
18923
  throw new Error(
18873
18924
  `Refusing to write a partial CSV export: the run returned ${rowsInfo.rows.length} preview row(s) out of ${rowsInfo.totalRows}.${retry}`
@@ -20502,7 +20553,9 @@ async function handleOrgStatus(options) {
20502
20553
  const config = resolveConfig();
20503
20554
  const http = new HttpClient(config);
20504
20555
  const payload = await fetchOrganizations(http, config.apiKey);
20505
- const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find((org) => org.org_id === payload.current_org_id) ?? null;
20556
+ const current = payload.organizations.find((org) => org.is_current) ?? payload.organizations.find(
20557
+ (org) => org.org_id === payload.current_org_id
20558
+ ) ?? null;
20506
20559
  const projectCandidate = getActiveProjectAuthSource();
20507
20560
  const activeProject = getResolvedProjectAuthSource(
20508
20561
  config.baseUrl,
@@ -20634,15 +20687,14 @@ async function handleOrgSwitch(selection, options) {
20634
20687
  } else {
20635
20688
  saveHostEnvValues(config.baseUrl, authValues2);
20636
20689
  }
20637
- if (authTarget.kind === "folder") {
20638
- saveCoworkWorkspaceRestoreEnvValues(authValues2);
20639
- }
20640
20690
  const renderLines2 = [`Already on ${target.name}.`];
20641
20691
  for (const projectPath of project_env_paths2) {
20642
20692
  renderLines2.push(`Saved folder auth in ${projectPath}`);
20643
20693
  }
20644
20694
  if (authTarget.kind === "global") {
20645
- renderLines2.push(`Saved global auth in ${hostEnvFilePath(config.baseUrl)}`);
20695
+ renderLines2.push(
20696
+ `Saved global auth in ${hostEnvFilePath(config.baseUrl)}`
20697
+ );
20646
20698
  }
20647
20699
  renderLines2.push(
20648
20700
  `Scope: ${authTarget.requested_scope} -> ${authTarget.effective_scope} (${authTarget.reason})`
@@ -20697,9 +20749,6 @@ async function handleOrgSwitch(selection, options) {
20697
20749
  DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
20698
20750
  });
20699
20751
  }
20700
- if (authTarget.kind === "folder") {
20701
- saveCoworkWorkspaceRestoreEnvValues(authValues);
20702
- }
20703
20752
  const { api_key: _apiKey, ...publicSwitched } = switched;
20704
20753
  const renderLines = [`Switched to ${switched.org_name}.`];
20705
20754
  if (authTarget.kind === "folder") {
@@ -20764,7 +20813,6 @@ async function handleOrgCreate(name, options) {
20764
20813
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
20765
20814
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
20766
20815
  });
20767
- saveCoworkWorkspaceRestoreEnvValues(authValues);
20768
20816
  const { api_key: _apiKey, ...publicCreated } = created;
20769
20817
  printCommandEnvelope(
20770
20818
  {
@@ -20873,7 +20921,10 @@ Examples:
20873
20921
  "--auth-scope <scope>",
20874
20922
  "Where to save auth: auto, folder, or global",
20875
20923
  "auto"
20876
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped");
20924
+ ).option(
20925
+ "--json",
20926
+ "Emit JSON output. Also automatic when stdout is piped"
20927
+ );
20877
20928
  addOrgSetOptions(
20878
20929
  org.command("set [selection]").description("Set the organization for the selected auth scope.").addHelpText(
20879
20930
  "after",