deepline 0.1.175 → 0.1.177

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.
@@ -607,17 +607,18 @@ var SDK_RELEASE = {
607
607
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
608
608
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
609
609
  // fields shipped in 0.1.153.
610
- version: "0.1.175",
610
+ // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
611
+ version: "0.1.177",
611
612
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
612
613
  supportPolicy: {
613
- latest: "0.1.175",
614
+ latest: "0.1.177",
614
615
  minimumSupported: "0.1.53",
615
616
  deprecatedBelow: "0.1.53",
616
617
  commandMinimumSupported: [
617
618
  {
618
619
  command: "enrich",
619
- minimumSupported: "0.1.154",
620
- reason: "Older SDK CLI enrich generated stale play source; SDK CLI enrich 0.1.153 generated removed StepOptions fields in play source."
620
+ minimumSupported: "0.1.175",
621
+ reason: "Older SDK CLI enrich generated stale play source; SDK CLI enrich 0.1.153 generated removed StepOptions fields in play source; SDK CLI enrich before 0.1.175 could silently succeed on the empty-waterfall bug when a requested waterfall returned no values for selected rows."
621
622
  },
622
623
  {
623
624
  command: "plays",
@@ -871,9 +872,10 @@ var HttpClient = class {
871
872
  headers["Content-Type"] = "application/json";
872
873
  }
873
874
  let lastError = null;
874
- const candidateUrls = buildCandidateUrls(url);
875
+ const candidateUrls = options?.exactUrlOnly ? [url] : buildCandidateUrls(url);
875
876
  let retryAfterDelayMs = null;
876
- for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
877
+ const maxRetries = options?.maxRetries ?? this.config.maxRetries;
878
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
877
879
  if (attempt > 0) {
878
880
  const backoffMs = Math.min(1e3 * Math.pow(2, attempt - 1), 3e4);
879
881
  const delayMs = retryAfterDelayMs === null ? backoffMs : Math.max(backoffMs, retryAfterDelayMs);
@@ -900,7 +902,7 @@ var HttpClient = class {
900
902
  if (response.status === 429) {
901
903
  const retryAfter = parseRetryAfter(response);
902
904
  lastError = new RateLimitError(retryAfter);
903
- if (attempt < this.config.maxRetries) {
905
+ if (attempt < maxRetries) {
904
906
  retryAfterDelayMs = retryAfter;
905
907
  break;
906
908
  }
@@ -930,7 +932,7 @@ var HttpClient = class {
930
932
  ...htmlError.workerThrewException ? { workerThrewException: true } : {}
931
933
  }
932
934
  );
933
- if (retryableApiError && attempt < this.config.maxRetries) {
935
+ if (retryableApiError && attempt < maxRetries) {
934
936
  retryAfterDelayMs = parseOptionalRetryAfter(response);
935
937
  break;
936
938
  }
@@ -942,7 +944,7 @@ var HttpClient = class {
942
944
  lastError = new DeeplineError(msg, response.status, apiErrorCode, {
943
945
  response: parsed
944
946
  });
945
- if (retryableApiError && attempt < this.config.maxRetries) {
947
+ if (retryableApiError && attempt < maxRetries) {
946
948
  retryAfterDelayMs = parseOptionalRetryAfter(response);
947
949
  break;
948
950
  }
@@ -961,7 +963,7 @@ var HttpClient = class {
961
963
  lastError = error instanceof Error ? error : new Error(String(error));
962
964
  }
963
965
  }
964
- if (attempt < this.config.maxRetries) continue;
966
+ if (attempt < maxRetries) continue;
965
967
  }
966
968
  if (lastError instanceof DeeplineError) {
967
969
  throw lastError;
@@ -2096,6 +2098,7 @@ var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
2096
2098
  var REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
2097
2099
  var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
2098
2100
  var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES = 25e5;
2101
+ var DEEPLINEAGENT_EXECUTE_TIMEOUT_MS = 15 * 60 * 1e3;
2099
2102
  function normalizePlayRunIntegrationMode(value) {
2100
2103
  if (value === "live" || value === "eval_stub" || value === "fixture") {
2101
2104
  return value;
@@ -2170,6 +2173,10 @@ function chunkRegisterPlayArtifacts(artifacts) {
2170
2173
  }
2171
2174
  return chunks;
2172
2175
  }
2176
+ function resolveToolExecuteTimeoutMs(toolId) {
2177
+ const normalized = toolId.trim().toLowerCase();
2178
+ return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
2179
+ }
2173
2180
  var RUN_LOGS_PAGE_LIMIT = 1e3;
2174
2181
  function isRecord3(value) {
2175
2182
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -2609,7 +2616,12 @@ var DeeplineClient = class {
2609
2616
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
2610
2617
  { payload: input2 },
2611
2618
  headers,
2612
- { forbiddenAsApiError: true }
2619
+ {
2620
+ forbiddenAsApiError: true,
2621
+ timeout: options?.timeout ?? resolveToolExecuteTimeoutMs(toolId),
2622
+ maxRetries: options?.maxRetries ?? 0,
2623
+ exactUrlOnly: true
2624
+ }
2613
2625
  );
2614
2626
  }
2615
2627
  /**
@@ -4569,10 +4581,21 @@ function failureMessageFromRecord(value) {
4569
4581
  }
4570
4582
  return directError || resultError || `Column status: ${status}`;
4571
4583
  }
4572
- function flattenObjectColumns(row) {
4584
+ function shouldPreserveJsonStringColumn(columns, key) {
4585
+ if (!columns) {
4586
+ return false;
4587
+ }
4588
+ if (columns.has(key)) {
4589
+ return true;
4590
+ }
4591
+ const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, "");
4592
+ return normalizedKey ? columns.has(normalizedKey) : false;
4593
+ }
4594
+ function flattenObjectColumns(row, options = {}) {
4573
4595
  const flattened = {};
4574
4596
  for (const [key, rawValue] of Object.entries(row)) {
4575
4597
  const value = parseMaybeJsonObject(rawValue);
4598
+ const parsedFromString = typeof rawValue === "string" && value !== rawValue;
4576
4599
  if (key === "_metadata") {
4577
4600
  flattened[key] = value && typeof value === "object" ? JSON.stringify(value) : value;
4578
4601
  continue;
@@ -4583,6 +4606,10 @@ function flattenObjectColumns(row) {
4583
4606
  if (hasMatchedEnvelope) {
4584
4607
  flattened[key] = JSON.stringify(record);
4585
4608
  continue;
4609
+ }
4610
+ if (parsedFromString && shouldPreserveJsonStringColumn(options.preserveJsonStringColumns, key)) {
4611
+ flattened[key] = rawValue;
4612
+ continue;
4586
4613
  } else {
4587
4614
  const failureMessage = failureMessageFromRecord(record);
4588
4615
  if (failureMessage) {
@@ -4607,8 +4634,8 @@ function recordRows(value) {
4607
4634
  (row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
4608
4635
  );
4609
4636
  }
4610
- function dataExportRows(rows) {
4611
- return rows.map((row) => flattenObjectColumns(row));
4637
+ function dataExportRows(rows, options = {}) {
4638
+ return rows.map((row) => flattenObjectColumns(row, options));
4612
4639
  }
4613
4640
  function dataExportColumns(rows, preferredColumns = []) {
4614
4641
  const discoveredColumns = [
@@ -7717,7 +7744,7 @@ import {
7717
7744
  writeFile as writeFile3
7718
7745
  } from "fs/promises";
7719
7746
  import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
7720
- import { dirname as dirname7, join as join7, resolve as resolve9 } from "path";
7747
+ import { basename as basename2, dirname as dirname7, extname, join as join7, resolve as resolve9 } from "path";
7721
7748
 
7722
7749
  // src/cli/commands/play.ts
7723
7750
  import { createHash as createHash2 } from "crypto";
@@ -16910,7 +16937,8 @@ function helperSource() {
16910
16937
  // src/cli/commands/enrich.ts
16911
16938
  var ENRICH_EXPORT_PAGE_SIZE = 5e3;
16912
16939
  var ENRICH_AUTO_BATCH_ROWS = 250;
16913
- var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 40;
16940
+ var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 25;
16941
+ var ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS = 50;
16914
16942
  var ENRICH_EXPORT_BACKING_ROWS_WAIT_MS = 6e4;
16915
16943
  var ENRICH_EXPORT_BACKING_ROWS_POLL_MS = 1e3;
16916
16944
  var ENRICH_SOURCE_ROW_INDEX_COLUMN = "__deeplineSourceRowIndex";
@@ -16925,6 +16953,12 @@ var HEAVY_ENRICH_AUTO_BATCH_PLAYS = /* @__PURE__ */ new Set([
16925
16953
  "company-to-contact-by-role-waterfall",
16926
16954
  "company_to_contact_by_role_waterfall"
16927
16955
  ]);
16956
+ var HEAVY_ENRICH_AUTO_BATCH_TOOLS = /* @__PURE__ */ new Set([
16957
+ "ai_inference",
16958
+ "aiinference",
16959
+ "deeplineagent"
16960
+ ]);
16961
+ var ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER = "__deeplineTestAiInference";
16928
16962
  var PLAN_SHAPING_OPTION_NAMES = [
16929
16963
  "with",
16930
16964
  "withWaterfall",
@@ -16942,6 +16976,15 @@ function normalizeAlias2(value) {
16942
16976
  function hasPlanShapingArgs(args) {
16943
16977
  return optionWasProvided(args, "--with") || optionWasProvided(args, "--with-waterfall") || optionWasProvided(args, "--min-results") || optionWasProvided(args, "--end-waterfall");
16944
16978
  }
16979
+ function isMarkedTestAiInferenceCommand(command) {
16980
+ if ("with_waterfall" in command) {
16981
+ return false;
16982
+ }
16983
+ if (normalizeEnrichPlayRef(command.tool) !== "run_javascript") {
16984
+ return false;
16985
+ }
16986
+ return isRecord7(command.payload) && command.payload[ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER] === true;
16987
+ }
16945
16988
  function enrichDebugEnabled(env = process.env) {
16946
16989
  const raw = String(env.DEEPLINE_DEBUG_ENRICH ?? "").trim().toLowerCase();
16947
16990
  if (["1", "true", "yes", "on"].includes(raw)) {
@@ -17709,8 +17752,6 @@ function normalizeEnrichPlayRef(value) {
17709
17752
  return normalized || null;
17710
17753
  }
17711
17754
  function configContainsHeavyEnrichPlay(config) {
17712
- let hasNestedPlayStep = false;
17713
- let hasSubrequestProviderStep = false;
17714
17755
  const visit = (commands) => {
17715
17756
  for (const command of commands) {
17716
17757
  if ("with_waterfall" in command) {
@@ -17734,18 +17775,67 @@ function configContainsHeavyEnrichPlay(config) {
17734
17775
  return true;
17735
17776
  }
17736
17777
  const normalizedTool = normalizeEnrichPlayRef(command.tool);
17778
+ const normalizedOperation = normalizeEnrichPlayRef(command.operation);
17779
+ if (isMarkedTestAiInferenceCommand(command) || normalizedTool && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedTool) || normalizedOperation && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedOperation)) {
17780
+ return true;
17781
+ }
17782
+ }
17783
+ return false;
17784
+ };
17785
+ return visit(config.commands);
17786
+ }
17787
+ function configContainsNestedProviderEnrichWorkload(config) {
17788
+ let hasNestedPlayStep = false;
17789
+ let hasSubrequestProviderStep = false;
17790
+ const visit = (commands) => {
17791
+ for (const command of commands) {
17792
+ if ("with_waterfall" in command) {
17793
+ visit(command.commands);
17794
+ continue;
17795
+ }
17796
+ if (command.disabled) {
17797
+ continue;
17798
+ }
17799
+ const normalizedTool = normalizeEnrichPlayRef(command.tool);
17737
17800
  if (command.play || normalizedTool === "test-play") {
17738
17801
  hasNestedPlayStep = true;
17739
17802
  } else if (normalizedTool !== null && normalizedTool !== "run_javascript") {
17740
17803
  hasSubrequestProviderStep = true;
17741
17804
  }
17742
17805
  }
17743
- return false;
17744
17806
  };
17745
- return visit(config.commands) || hasNestedPlayStep && hasSubrequestProviderStep;
17807
+ visit(config.commands);
17808
+ return hasNestedPlayStep && hasSubrequestProviderStep;
17746
17809
  }
17747
17810
  function enrichAutoBatchRowsForConfig(config) {
17748
- return configContainsHeavyEnrichPlay(config) ? ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS : ENRICH_AUTO_BATCH_ROWS;
17811
+ if (configContainsHeavyEnrichPlay(config)) {
17812
+ return ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS;
17813
+ }
17814
+ if (configContainsNestedProviderEnrichWorkload(config)) {
17815
+ return ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS;
17816
+ }
17817
+ return ENRICH_AUTO_BATCH_ROWS;
17818
+ }
17819
+ function enrichAiRuntimeCompactAliases(config) {
17820
+ const aliases = /* @__PURE__ */ new Set();
17821
+ const visit = (commands) => {
17822
+ for (const command of commands) {
17823
+ if ("with_waterfall" in command) {
17824
+ visit(command.commands);
17825
+ continue;
17826
+ }
17827
+ if (command.disabled) {
17828
+ continue;
17829
+ }
17830
+ const normalizedTool = normalizeEnrichPlayRef(command.tool);
17831
+ const normalizedOperation = normalizeEnrichPlayRef(command.operation);
17832
+ if (isMarkedTestAiInferenceCommand(command) || normalizedTool && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedTool) || normalizedOperation && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedOperation)) {
17833
+ aliases.add(normalizeAlias2(command.alias));
17834
+ }
17835
+ }
17836
+ };
17837
+ visit(config.commands);
17838
+ return aliases;
17749
17839
  }
17750
17840
  async function maybeWriteOutputCsv(input2) {
17751
17841
  if (!input2.outputPath) return null;
@@ -17777,14 +17867,39 @@ function enrichOutputJson(exportResult) {
17777
17867
  ...exportResult.partial ? { rows: exportResult.rows, partial: true } : {}
17778
17868
  };
17779
17869
  }
17870
+ function enrichReportJson(report) {
17871
+ if (!report) {
17872
+ return {};
17873
+ }
17874
+ return {
17875
+ ...report.jobs.length > 0 ? {
17876
+ failure_report: {
17877
+ path: report.path,
17878
+ jobs: report.jobs.length
17879
+ }
17880
+ } : {},
17881
+ ...report.issues.length > 0 ? {
17882
+ enrich_issues: {
17883
+ path: report.path,
17884
+ issues: report.issues.length,
17885
+ items: report.issues
17886
+ }
17887
+ } : {}
17888
+ };
17889
+ }
17780
17890
  async function buildEnrichFailureReport(input2) {
17891
+ const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
17781
17892
  return maybeEmitEnrichFailureReport({
17782
17893
  config: input2.config,
17783
17894
  rows: input2.rows,
17784
17895
  rowRange: input2.rowRange,
17785
17896
  client: input2.client,
17786
17897
  outputPath: input2.reportOutputPath ?? input2.exportResult?.path ?? input2.outputPath ?? null,
17787
- status: input2.status
17898
+ followUpOutputPath: input2.followUpOutputPath,
17899
+ status: input2.status,
17900
+ rowSetComplete: input2.exportResult ? !input2.exportResult.partial : Boolean(
17901
+ fallbackRowsInfo?.complete && input2.rows.length >= fallbackRowsInfo.totalRows
17902
+ )
17788
17903
  });
17789
17904
  }
17790
17905
  function recordField(value, key) {
@@ -17841,6 +17956,52 @@ function selectedSourceCsvRange(sourceCsvPath, rows) {
17841
17956
  sourceRows
17842
17957
  };
17843
17958
  }
17959
+ function compactRuntimeCsvCell(value) {
17960
+ const parsed = parseMaybeJsonObject(value);
17961
+ const compacted = compactAiInferenceCellForCsv(parsed);
17962
+ return materializeCsvCellValue(compacted);
17963
+ }
17964
+ async function writeSlimBatchedRuntimeCsv(input2) {
17965
+ const cleanRows = readCsvRows(input2.cleanSourceCsvPath).map(
17966
+ (row) => ({ ...row })
17967
+ );
17968
+ const mergeRows = readCsvRows(input2.mergeSourceCsvPath);
17969
+ const preserveJsonStringColumns = /* @__PURE__ */ new Set([
17970
+ ...cleanRows.flatMap((row) => Object.keys(row)),
17971
+ ...mergeRows.flatMap((row) => Object.keys(row))
17972
+ ]);
17973
+ const selectedRange = selectedSourceCsvRange(
17974
+ input2.mergeSourceCsvPath,
17975
+ input2.rows
17976
+ );
17977
+ for (let rowIndex = selectedRange.start; rowIndex <= selectedRange.end; rowIndex += 1) {
17978
+ const mergeRow = mergeRows[rowIndex];
17979
+ if (!mergeRow) {
17980
+ continue;
17981
+ }
17982
+ const baseRow = cleanRows[rowIndex] ?? {};
17983
+ const compactOverlayCell = ([key, value]) => {
17984
+ return [
17985
+ key,
17986
+ input2.compactAliases.has(normalizeAlias2(key)) ? compactRuntimeCsvCell(value) : value
17987
+ ];
17988
+ };
17989
+ cleanRows[rowIndex] = {
17990
+ ...baseRow,
17991
+ ...Object.fromEntries(
17992
+ Object.entries(mergeRow).map(compactOverlayCell)
17993
+ )
17994
+ };
17995
+ }
17996
+ const columns = dataExportColumns(
17997
+ dataExportRows(cleanRows, { preserveJsonStringColumns })
17998
+ );
17999
+ await writeFile3(
18000
+ input2.outputPath,
18001
+ csvStringFromRows(cleanRows, columns),
18002
+ "utf8"
18003
+ );
18004
+ }
17844
18005
  function selectedSourceCsvRowCount(options) {
17845
18006
  if (!options?.sourceCsvPath) {
17846
18007
  return null;
@@ -18015,7 +18176,7 @@ function emitPlainBatchRunFailure(input2) {
18015
18176
  `Batch ${input2.chunkIndex + 1}/${input2.chunkCount} failed for rows ${input2.rows.rowStart}:${input2.rows.rowEnd}.
18016
18177
  `
18017
18178
  );
18018
- const runId = extractRunId(input2.status);
18179
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
18019
18180
  const error = firstCollectedStringField(input2.status, "error") ?? firstCollectedStringField(input2.status, "message");
18020
18181
  if (runId) {
18021
18182
  process.stderr.write(`Run id: ${runId}
@@ -18147,6 +18308,22 @@ function mergeExportedSheetRow(target, next) {
18147
18308
  target._metadata = metadata;
18148
18309
  }
18149
18310
  }
18311
+ function countEnrichedRowsInSourceRange(exportResult, rows) {
18312
+ const start = Math.max(0, rows.rowStart ?? 0);
18313
+ const end = rows.rowEnd === null || rows.rowEnd === void 0 ? Number.MAX_SAFE_INTEGER : Math.max(start, rows.rowEnd);
18314
+ const rowIndexes = /* @__PURE__ */ new Set();
18315
+ for (const row of exportResult.enrichedDataRows) {
18316
+ const rowIndex = sourceRowIndexFromEnrichRow(row, start, end);
18317
+ if (rowIndex !== null) {
18318
+ rowIndexes.add(rowIndex);
18319
+ }
18320
+ }
18321
+ if (rowIndexes.size > 0) {
18322
+ return rowIndexes.size;
18323
+ }
18324
+ const selectedRows = end === Number.MAX_SAFE_INTEGER ? exportResult.enrichedRows : end - start + 1;
18325
+ return Math.min(exportResult.enrichedRows, Math.max(0, selectedRows));
18326
+ }
18150
18327
  function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
18151
18328
  const mergedRows = [];
18152
18329
  const bySourceRowIndex = /* @__PURE__ */ new Map();
@@ -18215,6 +18392,38 @@ function collectHardFailureAliasSpecs(config) {
18215
18392
  }
18216
18393
  return aliases;
18217
18394
  }
18395
+ function collectWaterfallAliasSpecs(config) {
18396
+ const aliases = [];
18397
+ const seen = /* @__PURE__ */ new Set();
18398
+ for (const command of config.commands) {
18399
+ if (!("with_waterfall" in command)) {
18400
+ continue;
18401
+ }
18402
+ const alias = command.with_waterfall.trim();
18403
+ if (!alias || seen.has(alias)) {
18404
+ continue;
18405
+ }
18406
+ const activeChildren = command.commands.filter(
18407
+ (child) => !("with_waterfall" in child) && !child.disabled
18408
+ );
18409
+ if (activeChildren.length === 0) {
18410
+ continue;
18411
+ }
18412
+ seen.add(alias);
18413
+ const childOperations = activeChildren.map((child) => child.operation?.trim() || child.tool.trim()).filter(Boolean);
18414
+ aliases.push({
18415
+ alias,
18416
+ childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
18417
+ childToolsByAlias: new Map(
18418
+ activeChildren.map(
18419
+ (child) => [child.alias, child.tool.trim()]
18420
+ )
18421
+ ),
18422
+ operation: childOperations.length > 0 ? childOperations.join(", ") : void 0
18423
+ });
18424
+ }
18425
+ return aliases;
18426
+ }
18218
18427
  function hardFailureOperationByAlias(config) {
18219
18428
  const operations = /* @__PURE__ */ new Map();
18220
18429
  if (!config) {
@@ -18227,6 +18436,60 @@ function hardFailureOperationByAlias(config) {
18227
18436
  }
18228
18437
  return operations;
18229
18438
  }
18439
+ function isWaterfallResultMeaningful(value) {
18440
+ if (Array.isArray(value)) {
18441
+ return value.some(isWaterfallResultMeaningful);
18442
+ }
18443
+ if (value && typeof value === "object") {
18444
+ const record = value;
18445
+ const status = typeof record.status === "string" ? record.status.trim().toLowerCase() : "";
18446
+ if (status === "error" || status === "failed") {
18447
+ return false;
18448
+ }
18449
+ if (typeof record.error === "string" && record.error.trim()) {
18450
+ return false;
18451
+ }
18452
+ if (Object.prototype.hasOwnProperty.call(record, "matched_result")) {
18453
+ return isWaterfallResultMeaningful(record.matched_result);
18454
+ }
18455
+ for (const key of [
18456
+ "value",
18457
+ "email",
18458
+ "phone",
18459
+ "phone_number",
18460
+ "mobile_phone",
18461
+ "mobile_phone_number",
18462
+ "url",
18463
+ "domain",
18464
+ "name",
18465
+ "result",
18466
+ "data"
18467
+ ]) {
18468
+ if (isWaterfallResultMeaningful(record[key])) {
18469
+ return true;
18470
+ }
18471
+ }
18472
+ return Object.entries(record).some(
18473
+ ([key, entry]) => !ENRICH_FLATTENED_CONTROL_FIELDS.has(key) && isWaterfallResultMeaningful(entry)
18474
+ );
18475
+ }
18476
+ return isNonEmptyCsvCell(value);
18477
+ }
18478
+ function aliasHasMeaningfulResult(row, alias) {
18479
+ return aliasFailureCellCandidates(row, alias).some(
18480
+ isWaterfallResultMeaningful
18481
+ );
18482
+ }
18483
+ function stableRowSnapshot(value) {
18484
+ if (Array.isArray(value)) {
18485
+ return `[${value.map(stableRowSnapshot).join(",")}]`;
18486
+ }
18487
+ if (value && typeof value === "object") {
18488
+ const record = value;
18489
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableRowSnapshot(record[key])}`).join(",")}}`;
18490
+ }
18491
+ return JSON.stringify(value);
18492
+ }
18230
18493
  function cellFailureError(value) {
18231
18494
  const parsed = parseMaybeJsonObject(value);
18232
18495
  if (!isRecord7(parsed)) {
@@ -18372,6 +18635,112 @@ function collectEnrichFailureJobs(input2) {
18372
18635
  });
18373
18636
  return jobs;
18374
18637
  }
18638
+ function collectEmptyWaterfallIssues(input2) {
18639
+ const aliases = collectWaterfallAliasSpecs(input2.config);
18640
+ if (aliases.length === 0 || input2.rows.length === 0 || !input2.rowSetComplete) {
18641
+ return [];
18642
+ }
18643
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
18644
+ const followUpCommands = collectEnrichFollowUpCommands({
18645
+ status: input2.status,
18646
+ runId,
18647
+ outputPath: input2.followUpOutputPath ?? input2.outputPath
18648
+ });
18649
+ const issues = [];
18650
+ aliases.forEach((spec) => {
18651
+ if (waterfallExecutionSignal(input2.status, spec) === "all_condition_skipped") {
18652
+ return;
18653
+ }
18654
+ const logicalRows = /* @__PURE__ */ new Map();
18655
+ input2.rows.forEach((row, rowIndex) => {
18656
+ const sourceRowId = sourceRowIndexFromEnrichRow(
18657
+ row,
18658
+ 0,
18659
+ Number.MAX_SAFE_INTEGER
18660
+ );
18661
+ const rowKey = sourceRowId !== null ? `source:${sourceRowId}` : `snapshot:${stableRowSnapshot(row)}`;
18662
+ const existing = logicalRows.get(rowKey);
18663
+ const hasMeaningfulResult = aliasHasMeaningfulResult(row, spec.alias);
18664
+ logicalRows.set(rowKey, {
18665
+ hasMeaningfulResult: (existing?.hasMeaningfulResult ?? false) || hasMeaningfulResult
18666
+ });
18667
+ });
18668
+ const emptyRows = Array.from(logicalRows.values()).filter(
18669
+ (row) => !row.hasMeaningfulResult
18670
+ );
18671
+ if (emptyRows.length !== logicalRows.size) {
18672
+ return;
18673
+ }
18674
+ const selectedRows = logicalRows.size;
18675
+ const message = `Waterfall ${spec.alias} produced 0 values for ${selectedRows} selected row(s).`;
18676
+ issues.push({
18677
+ issue_id: `${spec.alias}-empty-waterfall`,
18678
+ kind: "empty_waterfall",
18679
+ severity: "needs_attention",
18680
+ column: spec.alias,
18681
+ selected_rows: selectedRows,
18682
+ rows_with_value: 0,
18683
+ rows_without_value: selectedRows,
18684
+ message,
18685
+ next_steps: enrichIssueNextSteps({ runId }),
18686
+ follow_up_commands: followUpCommands,
18687
+ ...spec.operation ? { operation: spec.operation } : {},
18688
+ ...runId ? { run_id: runId } : {}
18689
+ });
18690
+ });
18691
+ return issues;
18692
+ }
18693
+ function waterfallExecutionSignal(status, spec) {
18694
+ const childAliases = spec.childAliases ?? [];
18695
+ if (childAliases.length === 0) {
18696
+ return "unknown";
18697
+ }
18698
+ const summaries = collectColumnStats(status);
18699
+ let sawChildStats = false;
18700
+ let everyChildStatOnlyConditionSkipped = true;
18701
+ const childAliasesWithStats = /* @__PURE__ */ new Set();
18702
+ for (const childAlias of childAliases) {
18703
+ for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord7)) {
18704
+ sawChildStats = true;
18705
+ childAliasesWithStats.add(childAlias);
18706
+ const execution = isRecord7(stat2.execution) ? stat2.execution : null;
18707
+ const executedSummary = parseExecutionSummary(
18708
+ execution?.["completed:executed"]
18709
+ );
18710
+ const skippedConditionSummary = parseExecutionSummary(
18711
+ execution?.["skipped:condition"]
18712
+ );
18713
+ const executedCount = executedSummary?.count ?? 0;
18714
+ const skippedConditionCount = skippedConditionSummary?.count ?? 0;
18715
+ const totalCount = executedSummary?.total ?? skippedConditionSummary?.total;
18716
+ const onlyConditionSkips = totalCount !== void 0 && skippedConditionCount >= totalCount && executedCount <= skippedConditionCount;
18717
+ if (executedCount > 0 && !onlyConditionSkips || numericFailedRowSignal(execution?.failed) > 0 || numericFailedRowSignal(stat2.failed) > 0 || numericFailedRowSignal(stat2.failedRows) > 0) {
18718
+ return "executed";
18719
+ }
18720
+ if (!onlyConditionSkips) {
18721
+ everyChildStatOnlyConditionSkipped = false;
18722
+ }
18723
+ }
18724
+ }
18725
+ if (sawChildStats && childAliasesWithStats.size === childAliases.length && everyChildStatOnlyConditionSkipped) {
18726
+ return "all_condition_skipped";
18727
+ }
18728
+ return "unknown";
18729
+ }
18730
+ function mergeEnrichFailureJobs(...jobGroups) {
18731
+ const merged = [];
18732
+ const seen = /* @__PURE__ */ new Set();
18733
+ for (const jobs of jobGroups) {
18734
+ for (const job of jobs) {
18735
+ if (seen.has(job.job_id)) {
18736
+ continue;
18737
+ }
18738
+ seen.add(job.job_id);
18739
+ merged.push(job);
18740
+ }
18741
+ }
18742
+ return merged;
18743
+ }
18375
18744
  function collectStatusFailureJobs(input2) {
18376
18745
  const aliases = collectHardFailureAliasSpecs(input2.config);
18377
18746
  if (aliases.length === 0) {
@@ -18465,14 +18834,23 @@ function collectCompleteStatusFailureMessages(input2) {
18465
18834
  return complete;
18466
18835
  }
18467
18836
  function parseExecutionCount(value) {
18837
+ return parseExecutionSummary(value)?.count ?? null;
18838
+ }
18839
+ function parseExecutionSummary(value) {
18468
18840
  if (typeof value === "number" && Number.isFinite(value)) {
18469
- return Math.max(0, Math.trunc(value));
18841
+ return { count: Math.max(0, Math.trunc(value)) };
18470
18842
  }
18471
18843
  if (typeof value !== "string") {
18472
18844
  return null;
18473
18845
  }
18474
- const match = value.trim().match(/^(\d+)\s*\//);
18475
- return match?.[1] ? Number.parseInt(match[1], 10) : null;
18846
+ const match = value.trim().match(/^(\d+)(?:\s*\/\s*(\d+))?/);
18847
+ if (!match?.[1]) {
18848
+ return null;
18849
+ }
18850
+ return {
18851
+ count: Number.parseInt(match[1], 10),
18852
+ ...match[2] ? { total: Number.parseInt(match[2], 10) } : {}
18853
+ };
18476
18854
  }
18477
18855
  function executionSummaryText(count, total) {
18478
18856
  const percent = total > 0 ? Math.round(count / total * 100) : 0;
@@ -18598,19 +18976,145 @@ function summarizeFailedJobError(value) {
18598
18976
  const text = String(value ?? "").trim();
18599
18977
  return text.length > 500 ? `${text.slice(0, 497)}...` : text;
18600
18978
  }
18979
+ function shellSingleQuote2(value) {
18980
+ return `'${value.replace(/'/g, `'\\''`)}'`;
18981
+ }
18982
+ function addEnrichFollowUpCommand(commands, seen, command) {
18983
+ const normalized = command.command.trim();
18984
+ if (!normalized || seen.has(normalized)) {
18985
+ return;
18986
+ }
18987
+ seen.add(normalized);
18988
+ commands.push({ ...command, command: normalized });
18989
+ }
18990
+ function datasetSelectorForEnrichCommand(record, fallbackPath) {
18991
+ const candidates = [record.path, record.tableNamespace, fallbackPath];
18992
+ for (const candidate of candidates) {
18993
+ if (typeof candidate === "string" && candidate.trim()) {
18994
+ return candidate.trim();
18995
+ }
18996
+ }
18997
+ return null;
18998
+ }
18999
+ function collectEnrichFollowUpCommands(input2) {
19000
+ const commands = [];
19001
+ const seen = /* @__PURE__ */ new Set();
19002
+ if (input2.runId) {
19003
+ addEnrichFollowUpCommand(commands, seen, {
19004
+ label: "inspect run",
19005
+ command: `deepline runs get ${input2.runId} --full --json`
19006
+ });
19007
+ }
19008
+ collectDatasetFollowUpCommands(input2.status, {
19009
+ runId: input2.runId,
19010
+ outputPath: input2.outputPath,
19011
+ commands,
19012
+ seen,
19013
+ path: "result",
19014
+ depth: 0
19015
+ });
19016
+ if (input2.runId && input2.outputPath && !commands.some((command) => command.label === "export enrich rows")) {
19017
+ addEnrichFollowUpCommand(commands, seen, {
19018
+ label: "export enrich rows",
19019
+ path: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
19020
+ command: `deepline runs export ${input2.runId} --dataset ${GENERATED_ENRICH_ROWS_TABLE_NAMESPACE} --out ${shellSingleQuote2(
19021
+ resolve9(input2.outputPath)
19022
+ )}`
19023
+ });
19024
+ }
19025
+ return commands.slice(0, 8);
19026
+ }
19027
+ function sidecarEnrichRowsExportPath(outputPath) {
19028
+ const resolved = resolve9(outputPath);
19029
+ const ext = extname(resolved) || ".csv";
19030
+ const stem = basename2(resolved, ext);
19031
+ return join7(dirname7(resolved), `${stem}.deepline-enrich-rows${ext}`);
19032
+ }
19033
+ function collectDatasetFollowUpCommands(value, state) {
19034
+ if (state.depth > 12 || !value || typeof value !== "object" || state.commands.length >= 8) {
19035
+ return;
19036
+ }
19037
+ if (Array.isArray(value)) {
19038
+ value.slice(0, 50).forEach(
19039
+ (entry, index) => collectDatasetFollowUpCommands(entry, {
19040
+ ...state,
19041
+ path: `${state.path}.${index}`,
19042
+ depth: state.depth + 1
19043
+ })
19044
+ );
19045
+ return;
19046
+ }
19047
+ const record = value;
19048
+ const isDataset = record.kind === "dataset";
19049
+ if (isDataset) {
19050
+ const selector = datasetSelectorForEnrichCommand(record, state.path);
19051
+ const labelPath = typeof record.path === "string" && record.path.trim() ? record.path.trim() : selector ?? state.path;
19052
+ if (typeof record.queryDatasetCommand === "string") {
19053
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19054
+ label: `query ${labelPath}`,
19055
+ path: labelPath,
19056
+ command: record.queryDatasetCommand
19057
+ });
19058
+ }
19059
+ const exportCommand = typeof record.slowExportAsCsvCommand === "string" ? record.slowExportAsCsvCommand : typeof record.fullExportCommand === "string" ? record.fullExportCommand : null;
19060
+ if (exportCommand) {
19061
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19062
+ label: `export ${labelPath}`,
19063
+ path: labelPath,
19064
+ command: exportCommand
19065
+ });
19066
+ } else if (state.runId && state.outputPath && selector) {
19067
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19068
+ label: selector === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE ? "export enrich rows" : `export ${labelPath}`,
19069
+ path: selector,
19070
+ command: `deepline runs export ${state.runId} --dataset ${shellSingleQuote2(
19071
+ selector
19072
+ )} --out ${shellSingleQuote2(resolve9(state.outputPath))}`
19073
+ });
19074
+ }
19075
+ }
19076
+ for (const [key, child] of Object.entries(record)) {
19077
+ if (key === "preview" || key === "access") {
19078
+ continue;
19079
+ }
19080
+ collectDatasetFollowUpCommands(child, {
19081
+ ...state,
19082
+ path: `${state.path}.${key}`,
19083
+ depth: state.depth + 1
19084
+ });
19085
+ if (state.commands.length >= 8) {
19086
+ return;
19087
+ }
19088
+ }
19089
+ }
19090
+ function enrichIssueNextSteps(input2) {
19091
+ const steps = [
19092
+ "Inspect the run output and returned dataset handles.",
19093
+ "If runs get returns queryDatasetCommand or slowExportAsCsvCommand, run that command to fetch durable rows from the customer DB.",
19094
+ "For provider-backed waterfalls, execute the child provider tool on a sample row to confirm the provider returns the expected field."
19095
+ ];
19096
+ if (!input2.runId) {
19097
+ return steps;
19098
+ }
19099
+ return [
19100
+ `Inspect run output: deepline runs get ${input2.runId} --full --json`,
19101
+ ...steps.slice(1)
19102
+ ];
19103
+ }
18601
19104
  function formatFailureReportCommand(reportPath) {
18602
19105
  const quoted = reportPath.replace(/'/g, `'\\''`);
18603
19106
  return `Inspect failed jobs: jq -r '.jobs[] | [.job_id,.row_id,.col_index,.column,.status,.last_error] | @tsv' '${quoted}'`;
18604
19107
  }
18605
19108
  async function persistEnrichFailureReport(input2) {
18606
- if (input2.jobs.length === 0) {
19109
+ if (input2.jobs.length === 0 && input2.issues.length === 0) {
18607
19110
  return null;
18608
19111
  }
18609
19112
  const stateDir = join7(homedir7(), ".local", "deepline", "runtime", "state");
19113
+ const reportPrefix = input2.jobs.length > 0 ? "run-block-failures" : "enrich-issues";
18610
19114
  await mkdir3(stateDir, { recursive: true });
18611
19115
  const reportPath = join7(
18612
19116
  stateDir,
18613
- `run-block-failures-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
19117
+ `${reportPrefix}-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
18614
19118
  );
18615
19119
  const report = {
18616
19120
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -18625,6 +19129,7 @@ async function persistEnrichFailureReport(input2) {
18625
19129
  },
18626
19130
  jobs: input2.jobs,
18627
19131
  failed_jobs: input2.jobs,
19132
+ enrich_issues: input2.issues,
18628
19133
  canceled_jobs: [],
18629
19134
  pending_jobs: [],
18630
19135
  missing_job_ids: []
@@ -18637,48 +19142,100 @@ async function persistEnrichFailureReport(input2) {
18637
19142
  return reportPath;
18638
19143
  }
18639
19144
  async function maybeEmitEnrichFailureReport(input2) {
19145
+ const fallbackRowsInfo = extractCanonicalRowsInfo(input2.status);
19146
+ const rowSetComplete = input2.rowSetComplete ?? Boolean(
19147
+ fallbackRowsInfo?.complete && input2.rows.length >= fallbackRowsInfo.totalRows
19148
+ );
18640
19149
  const rowJobs = collectEnrichFailureJobs({
18641
19150
  config: input2.config,
18642
19151
  rows: input2.rows,
18643
19152
  rowStart: input2.rowRange.rowStart
18644
19153
  });
18645
- const jobs = rowJobs.length > 0 || input2.status === void 0 ? rowJobs : collectStatusFailureJobs({
19154
+ const enrichIssues = collectEmptyWaterfallIssues({
19155
+ config: input2.config,
19156
+ rows: input2.rows,
19157
+ status: input2.waterfallStatus ?? input2.status,
19158
+ outputPath: input2.outputPath,
19159
+ followUpOutputPath: input2.followUpOutputPath,
19160
+ rowSetComplete
19161
+ });
19162
+ const statusJobs = input2.status === void 0 || rowJobs.length > 0 ? [] : collectStatusFailureJobs({
18646
19163
  config: input2.config,
18647
19164
  status: input2.status,
18648
19165
  rowRange: input2.statusRowRange ?? input2.rowRange
18649
19166
  });
18650
- if (jobs.length === 0) {
19167
+ const jobs = rowJobs.length > 0 || statusJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(rowJobs, statusJobs) : [];
19168
+ if (jobs.length === 0 && enrichIssues.length === 0) {
18651
19169
  return null;
18652
19170
  }
18653
19171
  const reportPath = await persistEnrichFailureReport({
18654
19172
  jobs,
19173
+ issues: enrichIssues,
18655
19174
  apiUrl: input2.client.baseUrl,
18656
19175
  outputPath: input2.outputPath,
18657
19176
  rows: input2.rowRange
18658
19177
  });
18659
- process.stderr.write("Execution failed.\n");
18660
- process.stderr.write("Failure preview (up to 5 failed jobs):\n");
18661
- process.stderr.write("job_id row_id col_index column status error\n");
18662
- for (const job of jobs.slice(0, 5)) {
18663
- process.stderr.write(
18664
- `${job.job_id} ${job.row_id} ${job.col_index} ${job.column} ${job.status} ${summarizeFailedJobError(job.last_error)}
19178
+ if (jobs.length > 0) {
19179
+ process.stderr.write("Execution failed.\n");
19180
+ process.stderr.write("Failure preview (up to 5 failed jobs):\n");
19181
+ process.stderr.write("job_id row_id col_index column status error\n");
19182
+ for (const job of jobs.slice(0, 5)) {
19183
+ process.stderr.write(
19184
+ `${job.job_id} ${job.row_id} ${job.col_index} ${job.column} ${job.status} ${summarizeFailedJobError(job.last_error)}
18665
19185
  `
18666
- );
19186
+ );
19187
+ }
19188
+ if (jobs.length > 5) {
19189
+ process.stderr.write(`Showing 5 of ${jobs.length} failed jobs.
19190
+ `);
19191
+ }
18667
19192
  }
18668
- if (jobs.length > 5) {
18669
- process.stderr.write(`Showing 5 of ${jobs.length} failed jobs.
19193
+ if (enrichIssues.length > 0) {
19194
+ process.stderr.write("Enrichment needs attention.\n");
19195
+ process.stderr.write("Issue preview (up to 5 enrichment issues):\n");
19196
+ process.stderr.write(
19197
+ "issue_id column severity selected_rows rows_with_value message\n"
19198
+ );
19199
+ for (const issue of enrichIssues.slice(0, 5)) {
19200
+ process.stderr.write(
19201
+ `${issue.issue_id} ${issue.column} ${issue.severity} ${issue.selected_rows} ${issue.rows_with_value} ${issue.message}
19202
+ `
19203
+ );
19204
+ for (const step of issue.next_steps.slice(0, 2)) {
19205
+ process.stderr.write(`Next: ${step}
19206
+ `);
19207
+ }
19208
+ for (const command of issue.follow_up_commands.slice(0, 4)) {
19209
+ process.stderr.write(`Command: ${command.label}: ${command.command}
18670
19210
  `);
19211
+ }
19212
+ }
19213
+ if (enrichIssues.length > 5) {
19214
+ process.stderr.write(
19215
+ `Showing 5 of ${enrichIssues.length} enrichment issues.
19216
+ `
19217
+ );
19218
+ }
18671
19219
  }
18672
19220
  if (reportPath) {
18673
- process.stderr.write(`Full failure report: ${reportPath}
19221
+ if (jobs.length > 0) {
19222
+ process.stderr.write(`Full failure report: ${reportPath}
18674
19223
  `);
18675
- process.stderr.write(`${formatFailureReportCommand(reportPath)}
19224
+ process.stderr.write(`${formatFailureReportCommand(reportPath)}
18676
19225
  `);
18677
- process.stderr.write("Enrichment failed. See failure report above.\n");
18678
- return { path: reportPath, jobs };
19226
+ } else {
19227
+ process.stderr.write(`Full enrich report: ${reportPath}
19228
+ `);
19229
+ }
19230
+ process.stderr.write(
19231
+ jobs.length > 0 ? "Enrichment failed. See report above.\n" : "Enrichment produced no values for at least one requested waterfall. See issue preview above.\n"
19232
+ );
19233
+ return { path: reportPath, jobs, issues: enrichIssues };
18679
19234
  }
18680
- process.stderr.write("Enrichment failed.\n");
18681
- return { path: "", jobs };
19235
+ process.stderr.write(
19236
+ jobs.length > 0 ? "Enrichment failed.\n" : "Enrichment needs attention.\n"
19237
+ );
19238
+ return { path: "", jobs, issues: enrichIssues };
18682
19239
  }
18683
19240
  function mergePreferredColumns(preferredColumns, rows) {
18684
19241
  const columns = [];
@@ -18778,10 +19335,12 @@ async function fetchBackingRowsForCsvExport(input2) {
18778
19335
  };
18779
19336
  }
18780
19337
  function mergeRowsForCsvExport(enrichedRows, options) {
19338
+ const compactAliases = options?.config ? enrichAiRuntimeCompactAliases(options.config) : /* @__PURE__ */ new Set();
18781
19339
  const rows = dataExportRows(
18782
19340
  normalizeEnrichRowsForCsvExport(enrichedRows, options?.config, {
18783
19341
  statusFailureMessages: options?.statusFailureMessages
18784
- })
19342
+ }),
19343
+ { preserveJsonStringColumns: compactAliases }
18785
19344
  );
18786
19345
  const range = options?.rows;
18787
19346
  if (!options?.sourceCsvPath) {
@@ -18801,16 +19360,16 @@ function mergeRowsForCsvExport(enrichedRows, options) {
18801
19360
  const maxEnd = Math.max(start, baseRows.length - 1);
18802
19361
  const inclusiveEnd = range?.rowEnd === null || range?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, range.rowEnd);
18803
19362
  const expectedSelectedRows = baseRows.length === 0 ? 0 : Math.max(0, inclusiveEnd - start + 1);
18804
- const canMergeSparseBySourceIndex = rows.length > 0 && rows.every(
19363
+ const hasRowsInSelectedRange = rows.some(
18805
19364
  (row) => sourceRowIndexFromEnrichRow(row, start, inclusiveEnd) !== null
18806
19365
  );
18807
- if (options.inPlace && rows.length < expectedSelectedRows && !options.allowPartial && !canMergeSparseBySourceIndex) {
19366
+ if (options.inPlace && rows.length < expectedSelectedRows && !options.allowPartial && !hasRowsInSelectedRange) {
18808
19367
  throw new Error(
18809
19368
  `Refusing to write a partial in-place CSV export: the run returned ${rows.length} row(s) for ${expectedSelectedRows} selected source row(s).`
18810
19369
  );
18811
19370
  }
18812
19371
  const merged = [...baseRows];
18813
- if (canMergeSparseBySourceIndex) {
19372
+ if (hasRowsInSelectedRange) {
18814
19373
  for (const rawEnriched of rows) {
18815
19374
  const rowIndex = sourceRowIndexFromEnrichRow(
18816
19375
  rawEnriched,
@@ -18945,9 +19504,45 @@ function materializeCsvCellValue(value) {
18945
19504
  }
18946
19505
  return value;
18947
19506
  }
18948
- function materializeAliasSuccessCell(row, alias) {
19507
+ function disambiguateCompactAiInferencePayload(value) {
19508
+ const parsed = parseMaybeJsonObject(value);
19509
+ if (!isRecord7(parsed) || !cellFailureError(parsed)) {
19510
+ return value;
19511
+ }
19512
+ return {
19513
+ status: "completed",
19514
+ extracted_json: parsed
19515
+ };
19516
+ }
19517
+ function compactAiInferenceCellForCsv(value) {
19518
+ if (!isRecord7(value)) {
19519
+ return value;
19520
+ }
19521
+ const extractedJson = value.extracted_json;
19522
+ if (extractedJson !== null && extractedJson !== void 0) {
19523
+ return disambiguateCompactAiInferencePayload(extractedJson);
19524
+ }
19525
+ const result = isRecord7(value.result) ? value.result : null;
19526
+ const object = result?.object;
19527
+ if (object !== null && object !== void 0) {
19528
+ return disambiguateCompactAiInferencePayload(object);
19529
+ }
19530
+ const text = result?.text;
19531
+ if (typeof text === "string" && text.trim()) {
19532
+ return disambiguateCompactAiInferencePayload(text);
19533
+ }
19534
+ const output2 = value.output;
19535
+ if (typeof output2 === "string" && output2.trim()) {
19536
+ return disambiguateCompactAiInferencePayload(output2);
19537
+ }
19538
+ return value;
19539
+ }
19540
+ function materializeEnrichAliasCellForCsv(row, alias, options) {
18949
19541
  const direct = row[alias];
18950
19542
  if (isRecord7(direct)) {
19543
+ if (options?.compactAiCell && direct.status === "completed" && (isRecord7(direct.result) || Object.prototype.hasOwnProperty.call(direct, "extracted_json") || typeof direct.output === "string")) {
19544
+ return materializeCsvCellValue(compactAiInferenceCellForCsv(direct));
19545
+ }
18951
19546
  if (Object.prototype.hasOwnProperty.call(direct, "matched_result") || Object.prototype.hasOwnProperty.call(direct, "matchedResult") || Object.prototype.hasOwnProperty.call(direct, "result")) {
18952
19547
  return materializeCsvCellValue(direct);
18953
19548
  }
@@ -19006,6 +19601,7 @@ function materializeAliasSuccessCell(row, alias) {
19006
19601
  }
19007
19602
  function normalizeEnrichRowsForCsvExport(rows, config, options) {
19008
19603
  const aliases = config ? collectConfigScalarAliasOrder(config) : [];
19604
+ const aiCompactAliases = config ? enrichAiRuntimeCompactAliases(config) : null;
19009
19605
  const failureOperationByAlias = hardFailureOperationByAlias(config);
19010
19606
  return rows.map((row) => {
19011
19607
  const metadata = legacyMetadataFromRow(row);
@@ -19048,7 +19644,9 @@ function normalizeEnrichRowsForCsvExport(rows, config, options) {
19048
19644
  }
19049
19645
  }
19050
19646
  for (const alias of aliases) {
19051
- const value = materializeAliasSuccessCell(normalized, alias);
19647
+ const value = materializeEnrichAliasCellForCsv(normalized, alias, {
19648
+ compactAiCell: aiCompactAliases?.has(normalizeAlias2(alias)) ?? false
19649
+ });
19052
19650
  if (value !== void 0) {
19053
19651
  normalized[alias] = value;
19054
19652
  continue;
@@ -19303,6 +19901,7 @@ function registerEnrichCommand(program) {
19303
19901
  const inPlaceFinalOutputPath = options.inPlace ? resolve9(inputCsv) : null;
19304
19902
  const inPlaceCommitOutputPath = options.inPlace ? (await lstat(inputCsv)).isSymbolicLink() ? await realpath(inputCsv) : inPlaceFinalOutputPath : null;
19305
19903
  const failureReportOutputPath = options.inPlace ? inPlaceFinalOutputPath : null;
19904
+ const enrichIssueFollowUpOutputPath = options.inPlace && inPlaceFinalOutputPath ? sidecarEnrichRowsExportPath(inPlaceFinalOutputPath) : null;
19306
19905
  let inPlaceCommitted = false;
19307
19906
  const commitInPlaceOutput = async (exportResult) => {
19308
19907
  if (!inPlaceTempOutputPath || !inPlaceCommitOutputPath || !inPlaceFinalOutputPath) {
@@ -19373,7 +19972,7 @@ function registerEnrichCommand(program) {
19373
19972
  capturedResult: captured2.result,
19374
19973
  client: client2,
19375
19974
  config,
19376
- sourceCsvPath: input2.sourceCsvPath,
19975
+ sourceCsvPath: input2.mergeSourceCsvPath ?? input2.sourceCsvPath,
19377
19976
  rows: input2.rows,
19378
19977
  inPlace: Boolean(options.inPlace)
19379
19978
  });
@@ -19389,11 +19988,13 @@ function registerEnrichCommand(program) {
19389
19988
  `
19390
19989
  );
19391
19990
  }
19392
- let workingSourceCsvPath = sourceCsvPath;
19991
+ let workingMergeSourceCsvPath = sourceCsvPath;
19393
19992
  let lastStatus = null;
19993
+ const batchStatuses = [];
19394
19994
  let finalExportResult = null;
19395
19995
  let totalEnrichedRows = 0;
19396
19996
  const batchFailureRows = [];
19997
+ const runtimeCompactAliases = enrichAiRuntimeCompactAliases(config);
19397
19998
  for (let chunkStart = selectedRange.start, chunkIndex = 0; chunkStart <= selectedRange.end; chunkStart += autoBatchRows, chunkIndex += 1) {
19398
19999
  const chunkRows = {
19399
20000
  rowStart: chunkStart,
@@ -19408,18 +20009,33 @@ function registerEnrichCommand(program) {
19408
20009
  `
19409
20010
  );
19410
20011
  }
20012
+ const runtimeSourceCsvPath = options.inPlace ? sourceCsvPath : workingMergeSourceCsvPath === inputCsv ? inputCsv : join7(tempDir, `runtime-batch-${chunkIndex}.csv`);
20013
+ if (!options.inPlace && runtimeSourceCsvPath !== inputCsv) {
20014
+ await writeSlimBatchedRuntimeCsv({
20015
+ cleanSourceCsvPath: inputCsv,
20016
+ mergeSourceCsvPath: workingMergeSourceCsvPath,
20017
+ rows: chunkRows,
20018
+ compactAliases: runtimeCompactAliases,
20019
+ outputPath: runtimeSourceCsvPath
20020
+ });
20021
+ }
19411
20022
  const chunk = await runOne({
19412
- sourceCsvPath: workingSourceCsvPath,
20023
+ sourceCsvPath: runtimeSourceCsvPath,
20024
+ mergeSourceCsvPath: workingMergeSourceCsvPath,
19413
20025
  rows: chunkRows,
19414
20026
  json: true,
19415
20027
  passthroughStdout: false,
19416
20028
  suppressOpen: true
19417
20029
  });
19418
20030
  lastStatus = chunk.status;
20031
+ batchStatuses.push(chunk.status);
19419
20032
  if (chunk.captured.result !== 0) {
19420
20033
  if (chunk.exportResult) {
19421
20034
  finalExportResult = chunk.exportResult;
19422
- totalEnrichedRows += chunk.exportResult.enrichedRows;
20035
+ totalEnrichedRows += countEnrichedRowsInSourceRange(
20036
+ chunk.exportResult,
20037
+ chunkRows
20038
+ );
19423
20039
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
19424
20040
  }
19425
20041
  const failureReport3 = await maybeEmitEnrichFailureReport({
@@ -19432,7 +20048,10 @@ function registerEnrichCommand(program) {
19432
20048
  statusRowRange: chunkRows,
19433
20049
  client: client2,
19434
20050
  outputPath: failureReportOutputPath ?? finalExportResult?.path ?? outputPath,
19435
- status: chunk.status
20051
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20052
+ status: chunk.status,
20053
+ waterfallStatus: batchStatuses,
20054
+ ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
19436
20055
  });
19437
20056
  const committedExportResult2 = finalExportResult ? await commitInPlaceOutput(finalExportResult) : null;
19438
20057
  if (options.json) {
@@ -19454,12 +20073,7 @@ function registerEnrichCommand(program) {
19454
20073
  partial: true
19455
20074
  } : {}
19456
20075
  } : null,
19457
- ...failureReport3 ? {
19458
- failure_report: {
19459
- path: failureReport3.path,
19460
- jobs: failureReport3.jobs.length
19461
- }
19462
- } : {}
20076
+ ...enrichReportJson(failureReport3)
19463
20077
  });
19464
20078
  } else {
19465
20079
  if (committedExportResult2) {
@@ -19480,9 +20094,12 @@ function registerEnrichCommand(program) {
19480
20094
  }
19481
20095
  if (chunk.exportResult) {
19482
20096
  finalExportResult = chunk.exportResult;
19483
- totalEnrichedRows += chunk.exportResult.enrichedRows;
20097
+ totalEnrichedRows += countEnrichedRowsInSourceRange(
20098
+ chunk.exportResult,
20099
+ chunkRows
20100
+ );
19484
20101
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
19485
- workingSourceCsvPath = outputPath;
20102
+ workingMergeSourceCsvPath = outputPath;
19486
20103
  }
19487
20104
  }
19488
20105
  const outputRows = readCsvRows(outputPath);
@@ -19495,7 +20112,10 @@ function registerEnrichCommand(program) {
19495
20112
  },
19496
20113
  client: client2,
19497
20114
  outputPath: failureReportOutputPath ?? finalExportResult?.path ?? outputPath,
19498
- status: lastStatus
20115
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20116
+ status: lastStatus,
20117
+ waterfallStatus: batchStatuses,
20118
+ ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
19499
20119
  });
19500
20120
  finalExportResult = await commitInPlaceOutput(finalExportResult);
19501
20121
  if (options.json) {
@@ -19527,12 +20147,7 @@ function registerEnrichCommand(program) {
19527
20147
  enrichedRows: totalEnrichedRows,
19528
20148
  path: finalExportResult.path
19529
20149
  } : null,
19530
- ...failureReport2 ? {
19531
- failure_report: {
19532
- path: failureReport2.path,
19533
- jobs: failureReport2.jobs.length
19534
- }
19535
- } : {}
20150
+ ...enrichReportJson(failureReport2)
19536
20151
  });
19537
20152
  }
19538
20153
  if (failureReport2) {
@@ -19563,6 +20178,7 @@ function registerEnrichCommand(program) {
19563
20178
  exportResult: committedExportResult2,
19564
20179
  outputPath,
19565
20180
  reportOutputPath: failureReportOutputPath,
20181
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
19566
20182
  status
19567
20183
  });
19568
20184
  if (options.json) {
@@ -19570,12 +20186,7 @@ function registerEnrichCommand(program) {
19570
20186
  ok: false,
19571
20187
  run: status,
19572
20188
  output: enrichOutputJson(committedExportResult2),
19573
- ...failureReport2 ? {
19574
- failure_report: {
19575
- path: failureReport2.path,
19576
- jobs: failureReport2.jobs.length
19577
- }
19578
- } : {}
20189
+ ...enrichReportJson(failureReport2)
19579
20190
  });
19580
20191
  }
19581
20192
  process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
@@ -19590,6 +20201,7 @@ function registerEnrichCommand(program) {
19590
20201
  exportResult,
19591
20202
  outputPath,
19592
20203
  reportOutputPath: failureReportOutputPath,
20204
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
19593
20205
  status
19594
20206
  });
19595
20207
  const committedExportResult2 = await commitInPlaceOutput(exportResult);
@@ -19604,12 +20216,7 @@ function registerEnrichCommand(program) {
19604
20216
  ok: !failureReport2,
19605
20217
  run,
19606
20218
  output: enrichOutputJson(committedExportResult2),
19607
- ...failureReport2 ? {
19608
- failure_report: {
19609
- path: failureReport2.path,
19610
- jobs: failureReport2.jobs.length
19611
- }
19612
- } : {}
20219
+ ...enrichReportJson(failureReport2)
19613
20220
  });
19614
20221
  if (failureReport2) {
19615
20222
  process.exitCode = EXIT_SERVER2;
@@ -19622,7 +20229,9 @@ function registerEnrichCommand(program) {
19622
20229
  rowRange: rows,
19623
20230
  client: client2,
19624
20231
  outputPath: failureReportOutputPath ?? exportResult?.path ?? null,
19625
- status
20232
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20233
+ status,
20234
+ ...exportResult ? { rowSetComplete: !exportResult.partial } : {}
19626
20235
  });
19627
20236
  const committedExportResult = await commitInPlaceOutput(exportResult);
19628
20237
  if (committedExportResult) {
@@ -19707,7 +20316,7 @@ import {
19707
20316
  writeFileSync as writeFileSync10
19708
20317
  } from "fs";
19709
20318
  import { homedir as homedir8, platform } from "os";
19710
- import { basename as basename2, dirname as dirname8, join as join8, resolve as resolve10 } from "path";
20319
+ import { basename as basename3, dirname as dirname8, join as join8, resolve as resolve10 } from "path";
19711
20320
  import { gzipSync } from "zlib";
19712
20321
  import { randomUUID as randomUUID2 } from "crypto";
19713
20322
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -19726,7 +20335,7 @@ function homeDir() {
19726
20335
  function detectShellContext() {
19727
20336
  const shellPath = process.env.SHELL?.trim() || process.env.ComSpec?.trim() || process.env.COMSPEC?.trim() || "";
19728
20337
  return {
19729
- shell: shellPath ? basename2(shellPath).replace(/\.exe$/i, "") : "unknown",
20338
+ shell: shellPath ? basename3(shellPath).replace(/\.exe$/i, "") : "unknown",
19730
20339
  shell_path: shellPath || null,
19731
20340
  os: platform(),
19732
20341
  cwd: process.cwd()
@@ -19832,10 +20441,10 @@ function newestSessionFile(agent) {
19832
20441
  return newest;
19833
20442
  }
19834
20443
  function sessionIdFromClaudeFilePath(filePath) {
19835
- return basename2(filePath, ".jsonl");
20444
+ return basename3(filePath, ".jsonl");
19836
20445
  }
19837
20446
  function sessionIdFromCodexFilePath(filePath) {
19838
- const match = basename2(filePath, ".jsonl").match(UUID_IN_TEXT_RE);
20447
+ const match = basename3(filePath, ".jsonl").match(UUID_IN_TEXT_RE);
19839
20448
  return match?.[0] ?? null;
19840
20449
  }
19841
20450
  function readCodexSessionId(filePath) {
@@ -20123,19 +20732,19 @@ async function handleSessionsSend(options) {
20123
20732
  }
20124
20733
  const response2 = await uploadPayload("/api/v2/cli/send-session", {
20125
20734
  file: readFileSync8(filePath).toString("base64"),
20126
- filename: basename2(filePath)
20735
+ filename: basename3(filePath)
20127
20736
  });
20128
20737
  printCommandEnvelope(
20129
20738
  {
20130
20739
  ...response2,
20131
20740
  ok: true,
20132
- filename: basename2(filePath),
20741
+ filename: basename3(filePath),
20133
20742
  render: {
20134
20743
  sections: [
20135
20744
  {
20136
20745
  title: "sessions send",
20137
20746
  lines: [
20138
- `File '${basename2(filePath)}' uploaded to #internal-reports.`
20747
+ `File '${basename3(filePath)}' uploaded to #internal-reports.`
20139
20748
  ]
20140
20749
  }
20141
20750
  ]