deepline 0.1.148 → 0.1.150

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.
package/dist/cli/index.js CHANGED
@@ -237,6 +237,8 @@ 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";
240
242
  var COWORK_IGNORED_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
241
243
  ".auto-memory",
242
244
  ".claude",
@@ -551,6 +553,18 @@ function ensureProjectEnvIsIgnored(dir) {
551
553
  (0, import_node_fs.writeFileSync)(gitignorePath, `${existing}${prefix}${entry}
552
554
  `, "utf-8");
553
555
  }
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
+ }
554
568
  function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
555
569
  const target = resolveProjectPinTarget(startDir);
556
570
  if (!target.ok) {
@@ -564,6 +578,27 @@ function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
564
578
  mergeProjectEnvFile(filePath, values);
565
579
  return [filePath];
566
580
  }
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
+ }
567
602
  function resolveProjectPinTarget(startDir = process.cwd()) {
568
603
  const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
569
604
  if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
@@ -620,10 +655,10 @@ var SDK_RELEASE = {
620
655
  // the SDK enrich generator's one-second stale policy.
621
656
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
622
657
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
623
- version: "0.1.148",
658
+ version: "0.1.150",
624
659
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
625
660
  supportPolicy: {
626
- latest: "0.1.148",
661
+ latest: "0.1.150",
627
662
  minimumSupported: "0.1.53",
628
663
  deprecatedBelow: "0.1.53",
629
664
  commandMinimumSupported: [
@@ -2087,6 +2122,7 @@ async function* observeRunEvents(options) {
2087
2122
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
2088
2123
  var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
2089
2124
  var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
2125
+ var EXECUTE_RESPONSE_INTENT_HEADER = "x-deepline-execute-response-intent";
2090
2126
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
2091
2127
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
2092
2128
  var REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
@@ -2571,7 +2607,8 @@ var DeeplineClient = class {
2571
2607
  async executeTool(toolId, input2, options) {
2572
2608
  const headers = {
2573
2609
  [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
2574
- ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
2610
+ ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {},
2611
+ ...options?.responseIntent ? { [EXECUTE_RESPONSE_INTENT_HEADER]: options.responseIntent } : {}
2575
2612
  };
2576
2613
  return this.http.post(
2577
2614
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
@@ -4693,6 +4730,9 @@ function saveEnvValues(values, baseUrl) {
4693
4730
  ...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
4694
4731
  };
4695
4732
  saveHostEnvValues(baseUrl, filtered);
4733
+ if (filtered[API_KEY_ENV]) {
4734
+ saveCoworkWorkspaceRestoreEnvValues(filtered);
4735
+ }
4696
4736
  }
4697
4737
  async function httpJson(method, url, apiKey, body) {
4698
4738
  const headers = {
@@ -6923,6 +6963,7 @@ Examples:
6923
6963
  var import_node_fs7 = require("fs");
6924
6964
  var import_node_path8 = require("path");
6925
6965
  var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set(["table", "json", "csv", "markdown"]);
6966
+ var CUSTOMER_DB_QUERY_MAX_ROWS = 1e3;
6926
6967
  function parsePositiveInteger(value, flagName) {
6927
6968
  const parsed = Number.parseInt(value, 10);
6928
6969
  if (!Number.isFinite(parsed) || parsed <= 0) {
@@ -6930,6 +6971,15 @@ function parsePositiveInteger(value, flagName) {
6930
6971
  }
6931
6972
  return parsed;
6932
6973
  }
6974
+ function parseMaxRows(value) {
6975
+ const parsed = parsePositiveInteger(value, "--max-rows");
6976
+ if (parsed > CUSTOMER_DB_QUERY_MAX_ROWS) {
6977
+ throw new Error(
6978
+ `--max-rows must be ${CUSTOMER_DB_QUERY_MAX_ROWS} or less. Add LIMIT/OFFSET to page larger exports.`
6979
+ );
6980
+ }
6981
+ return parsed;
6982
+ }
6933
6983
  function formatCell(value) {
6934
6984
  if (value === null || value === void 0) return "";
6935
6985
  const text = typeof value === "object" ? JSON.stringify(value) : String(value);
@@ -7075,7 +7125,7 @@ async function handleDbQuery(args) {
7075
7125
  return 1;
7076
7126
  }
7077
7127
  const maxRowsIndex = args.indexOf("--max-rows");
7078
- const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
7128
+ const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parseMaxRows(args[maxRowsIndex + 1]) : void 0;
7079
7129
  const formatIndex = args.indexOf("--format");
7080
7130
  const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
7081
7131
  if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
@@ -17029,8 +17079,14 @@ async function writeOutputCsv(outputPath, status, options) {
17029
17079
  rowsInfo
17030
17080
  }).catch(() => null) ?? rowsInfo;
17031
17081
  }
17032
- assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
17033
- const merged = mergeRowsForCsvExport(rowsInfo.rows, options);
17082
+ const allowPartial = options?.allowPartial === true && !rowsInfo.complete && rowsInfo.rows.length > 0 && Boolean(options?.sourceCsvPath);
17083
+ assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, {
17084
+ allowPartial
17085
+ });
17086
+ const merged = mergeRowsForCsvExport(rowsInfo.rows, {
17087
+ ...options,
17088
+ allowPartial
17089
+ });
17034
17090
  const columns = orderEnrichCsvColumns(
17035
17091
  dataExportColumns(merged.rows, [
17036
17092
  ...merged.preferredColumns,
@@ -17050,9 +17106,52 @@ async function writeOutputCsv(outputPath, status, options) {
17050
17106
  enrichedRows: rowsInfo.rows.length,
17051
17107
  rows: merged.rows.length,
17052
17108
  path: (0, import_node_path11.resolve)(outputPath),
17109
+ partial: !rowsInfo.complete,
17053
17110
  enrichedDataRows: rowsInfo.rows
17054
17111
  };
17055
17112
  }
17113
+ function isMissingRowsForCsvExportError(error) {
17114
+ return error instanceof Error && (error.message.includes("did not return row-shaped output") || error.message.includes("run returned 0 preview row(s)"));
17115
+ }
17116
+ async function maybeWriteOutputCsv(input2) {
17117
+ if (!input2.outputPath) return null;
17118
+ try {
17119
+ return await writeOutputCsv(input2.outputPath, input2.status, {
17120
+ client: input2.client,
17121
+ config: input2.config,
17122
+ sourceCsvPath: input2.sourceCsvPath,
17123
+ rows: input2.rows,
17124
+ inPlace: input2.inPlace,
17125
+ allowPartial: input2.capturedResult !== 0
17126
+ });
17127
+ } catch (error) {
17128
+ if (input2.capturedResult !== 0 && isMissingRowsForCsvExportError(error)) {
17129
+ return null;
17130
+ }
17131
+ throw error;
17132
+ }
17133
+ }
17134
+ function enrichOutputJson(exportResult) {
17135
+ if (!exportResult) {
17136
+ return null;
17137
+ }
17138
+ return {
17139
+ sourceCsvRows: exportResult.sourceCsvRows,
17140
+ selectedRows: exportResult.selectedRows,
17141
+ enrichedRows: exportResult.enrichedRows,
17142
+ path: exportResult.path,
17143
+ ...exportResult.partial ? { rows: exportResult.rows, partial: true } : {}
17144
+ };
17145
+ }
17146
+ async function buildEnrichFailureReport(input2) {
17147
+ return maybeEmitEnrichFailureReport({
17148
+ config: input2.config,
17149
+ rows: input2.rows,
17150
+ rowRange: input2.rowRange,
17151
+ client: input2.client,
17152
+ outputPath: input2.exportResult?.path ?? input2.outputPath ?? null
17153
+ });
17154
+ }
17056
17155
  function recordField(value, key) {
17057
17156
  return value && typeof value === "object" && !Array.isArray(value) ? value[key] : void 0;
17058
17157
  }
@@ -17574,10 +17673,7 @@ async function fetchBackingRowsForCsvExport(input2) {
17574
17673
  function mergeRowsForCsvExport(enrichedRows, options) {
17575
17674
  const rows = dataExportRows(normalizeEnrichRowsForCsvExport(enrichedRows));
17576
17675
  const range = options?.rows;
17577
- if (!options?.inPlace && (range?.rowStart === null || range?.rowStart === void 0)) {
17578
- return { rows, preferredColumns: [] };
17579
- }
17580
- if (!options?.sourceCsvPath) {
17676
+ if (!options?.sourceCsvPath || !options.inPlace && !options.allowPartial && (range?.rowStart === null || range?.rowStart === void 0)) {
17581
17677
  return { rows, preferredColumns: [] };
17582
17678
  }
17583
17679
  const parsedBaseRows = readCsvRows(options.sourceCsvPath);
@@ -17589,7 +17685,7 @@ function mergeRowsForCsvExport(enrichedRows, options) {
17589
17685
  const maxEnd = Math.max(start, baseRows.length - 1);
17590
17686
  const inclusiveEnd = range?.rowEnd === null || range?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, range.rowEnd);
17591
17687
  const expectedSelectedRows = baseRows.length === 0 ? 0 : Math.max(0, inclusiveEnd - start + 1);
17592
- if (rows.length < expectedSelectedRows) {
17688
+ if (rows.length < expectedSelectedRows && !options.allowPartial) {
17593
17689
  throw new Error(
17594
17690
  `Refusing to write a partial in-place CSV export: the run returned ${rows.length} row(s) for ${expectedSelectedRows} selected source row(s).`
17595
17691
  );
@@ -17788,10 +17884,13 @@ function mergeLegacyMetadataCell(base, enriched) {
17788
17884
  }
17789
17885
  return void 0;
17790
17886
  }
17791
- function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath) {
17887
+ function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, options = {}) {
17792
17888
  if (rowsInfo.complete) {
17793
17889
  return;
17794
17890
  }
17891
+ if (options.allowPartial) {
17892
+ return;
17893
+ }
17795
17894
  const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
17796
17895
  const dataset = rowsInfo.source ?? "result.rows";
17797
17896
  const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
@@ -17947,13 +18046,16 @@ function registerEnrichCommand(program) {
17947
18046
  stdout: captured2.stdout,
17948
18047
  exitCode: captured2.result
17949
18048
  });
17950
- const exportResult2 = captured2.result === 0 && outputPath ? await writeOutputCsv(outputPath, status2, {
18049
+ const exportResult2 = await maybeWriteOutputCsv({
18050
+ outputPath,
18051
+ status: status2,
18052
+ capturedResult: captured2.result,
17951
18053
  client: client2,
17952
18054
  config,
17953
18055
  sourceCsvPath: input2.sourceCsvPath,
17954
18056
  rows: input2.rows,
17955
18057
  inPlace: Boolean(options.inPlace)
17956
- }) : null;
18058
+ });
17957
18059
  return { captured: captured2, status: status2, exportResult: exportResult2 };
17958
18060
  };
17959
18061
  const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
@@ -18003,9 +18105,16 @@ function registerEnrichCommand(program) {
18003
18105
  chunks: chunkCount,
18004
18106
  rows: chunkRows
18005
18107
  },
18006
- result: chunk.status
18108
+ result: chunk.status,
18109
+ output: enrichOutputJson(chunk.exportResult)
18007
18110
  });
18008
18111
  } else {
18112
+ if (chunk.exportResult) {
18113
+ process.stderr.write(
18114
+ `Wrote ${chunk.exportResult.rows} row(s) to ${chunk.exportResult.path}${chunk.exportResult.partial ? " (partial run output)" : ""}
18115
+ `
18116
+ );
18117
+ }
18009
18118
  emitPlainBatchRunFailure({
18010
18119
  chunkIndex,
18011
18120
  chunkCount,
@@ -18082,23 +18191,46 @@ function registerEnrichCommand(program) {
18082
18191
  json: Boolean(options.json),
18083
18192
  passthroughStdout: !options.json
18084
18193
  });
18194
+ const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18085
18195
  if (captured.result !== 0) {
18196
+ if (exportResult) {
18197
+ process.stderr.write(
18198
+ `Wrote ${exportResult.rows} row(s) to ${exportResult.path}${exportResult.partial ? " (partial run output)" : ""}
18199
+ `
18200
+ );
18201
+ }
18202
+ const failureReport2 = await buildEnrichFailureReport({
18203
+ config,
18204
+ rows: rowsForFailureReport,
18205
+ rowRange: rows,
18206
+ client: client2,
18207
+ exportResult,
18208
+ outputPath
18209
+ });
18086
18210
  if (options.json) {
18087
18211
  printJson({
18088
- result: status
18212
+ ok: false,
18213
+ run: status,
18214
+ output: enrichOutputJson(exportResult),
18215
+ ...failureReport2 ? {
18216
+ failure_report: {
18217
+ path: failureReport2.path,
18218
+ jobs: failureReport2.jobs.length
18219
+ }
18220
+ } : {}
18089
18221
  });
18090
18222
  }
18091
- process.exitCode = captured.result;
18223
+ process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
18092
18224
  return;
18093
18225
  }
18094
- const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18095
18226
  if (options.json) {
18096
- const failureReport2 = await maybeEmitEnrichFailureReport({
18227
+ const failureReport2 = await buildEnrichFailureReport({
18097
18228
  config,
18098
18229
  rows: rowsForFailureReport,
18099
18230
  rowRange: rows,
18100
18231
  client: client2,
18101
- outputPath: exportResult?.path ?? outputPath ?? null
18232
+ exportResult,
18233
+ outputPath
18102
18234
  });
18103
18235
  const run = rewriteEnrichJsonStatus({
18104
18236
  status,
@@ -18110,12 +18242,7 @@ function registerEnrichCommand(program) {
18110
18242
  printJson({
18111
18243
  ok: !failureReport2,
18112
18244
  run,
18113
- output: exportResult ? {
18114
- sourceCsvRows: exportResult.sourceCsvRows,
18115
- selectedRows: exportResult.selectedRows,
18116
- enrichedRows: exportResult.enrichedRows,
18117
- path: exportResult.path
18118
- } : null,
18245
+ output: enrichOutputJson(exportResult),
18119
18246
  ...failureReport2 ? {
18120
18247
  failure_report: {
18121
18248
  path: failureReport2.path,
@@ -19469,16 +19596,17 @@ async function handleOrgSwitch(selection, options) {
19469
19596
  const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
19470
19597
  if (target.is_current) {
19471
19598
  let project_env_paths2 = [];
19599
+ const authValues2 = {
19600
+ [HOST_URL_ENV]: config.baseUrl,
19601
+ [API_KEY_ENV]: config.apiKey
19602
+ };
19472
19603
  if (authTarget.kind === "folder") {
19473
- project_env_paths2 = saveProjectDeeplineEnvValues({
19474
- DEEPLINE_HOST_URL: config.baseUrl,
19475
- DEEPLINE_API_KEY: config.apiKey
19476
- });
19604
+ project_env_paths2 = saveProjectDeeplineEnvValues(authValues2);
19477
19605
  } else {
19478
- saveHostEnvValues(config.baseUrl, {
19479
- DEEPLINE_HOST_URL: config.baseUrl,
19480
- DEEPLINE_API_KEY: config.apiKey
19481
- });
19606
+ saveHostEnvValues(config.baseUrl, authValues2);
19607
+ }
19608
+ if (authTarget.kind === "folder") {
19609
+ saveCoworkWorkspaceRestoreEnvValues(authValues2);
19482
19610
  }
19483
19611
  const renderLines2 = [`Already on ${target.name}.`];
19484
19612
  for (const projectPath of project_env_paths2) {
@@ -19527,19 +19655,22 @@ async function handleOrgSwitch(selection, options) {
19527
19655
  org_id: target.org_id
19528
19656
  });
19529
19657
  let project_env_paths = [];
19658
+ const authValues = {
19659
+ [HOST_URL_ENV]: config.baseUrl,
19660
+ [API_KEY_ENV]: switched.api_key
19661
+ };
19530
19662
  if (authTarget.kind === "folder") {
19531
- project_env_paths = saveProjectDeeplineEnvValues({
19532
- DEEPLINE_HOST_URL: config.baseUrl,
19533
- DEEPLINE_API_KEY: switched.api_key
19534
- });
19663
+ project_env_paths = saveProjectDeeplineEnvValues(authValues);
19535
19664
  } else {
19536
19665
  saveHostEnvValues(config.baseUrl, {
19537
- DEEPLINE_HOST_URL: config.baseUrl,
19538
- DEEPLINE_API_KEY: switched.api_key,
19666
+ ...authValues,
19539
19667
  DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
19540
19668
  DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
19541
19669
  });
19542
19670
  }
19671
+ if (authTarget.kind === "folder") {
19672
+ saveCoworkWorkspaceRestoreEnvValues(authValues);
19673
+ }
19543
19674
  const { api_key: _apiKey, ...publicSwitched } = switched;
19544
19675
  const renderLines = [`Switched to ${switched.org_name}.`];
19545
19676
  if (authTarget.kind === "folder") {
@@ -19595,12 +19726,16 @@ async function handleOrgCreate(name, options) {
19595
19726
  api_key: config.apiKey,
19596
19727
  name
19597
19728
  });
19729
+ const authValues = {
19730
+ [HOST_URL_ENV]: config.baseUrl,
19731
+ [API_KEY_ENV]: created.api_key
19732
+ };
19598
19733
  saveHostEnvValues(config.baseUrl, {
19599
- DEEPLINE_HOST_URL: config.baseUrl,
19600
- DEEPLINE_API_KEY: created.api_key,
19734
+ ...authValues,
19601
19735
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
19602
19736
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
19603
19737
  });
19738
+ saveCoworkWorkspaceRestoreEnvValues(authValues);
19604
19739
  const { api_key: _apiKey, ...publicCreated } = created;
19605
19740
  printCommandEnvelope(
19606
19741
  {
@@ -20421,6 +20556,19 @@ function normalizeRows(value) {
20421
20556
  return { value: entry };
20422
20557
  });
20423
20558
  }
20559
+ function columnsForRows(rows) {
20560
+ const seen = /* @__PURE__ */ new Set();
20561
+ const columns = [];
20562
+ for (const row of rows) {
20563
+ for (const key of Object.keys(row)) {
20564
+ if (!seen.has(key)) {
20565
+ seen.add(key);
20566
+ columns.push(key);
20567
+ }
20568
+ }
20569
+ }
20570
+ return columns;
20571
+ }
20424
20572
  function candidateRoots(payload) {
20425
20573
  const roots = [
20426
20574
  { path: null, value: payload }
@@ -20503,6 +20651,16 @@ function tryConvertToList(payload, options) {
20503
20651
  }
20504
20652
  return null;
20505
20653
  }
20654
+ function projectRowOutput(conversion) {
20655
+ return {
20656
+ rows: conversion.rows,
20657
+ rowCount: conversion.rows.length,
20658
+ columns: columnsForRows(conversion.rows),
20659
+ previewRows: conversion.rows.slice(0, 5),
20660
+ strategy: conversion.strategy,
20661
+ sourcePath: conversion.sourcePath
20662
+ };
20663
+ }
20506
20664
  function ensureOutputDir() {
20507
20665
  const outputDir = (0, import_node_path14.join)((0, import_node_os10.homedir)(), ".local", "share", "deepline", "data");
20508
20666
  (0, import_node_fs12.mkdirSync)(outputDir, { recursive: true });
@@ -20517,16 +20675,7 @@ function writeJsonOutputFile(payload, stem) {
20517
20675
  function writeCsvOutputFile(rows, stem, options) {
20518
20676
  const outputPath = options?.outPath ? options.outPath : (0, import_node_path14.join)(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
20519
20677
  (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(outputPath), { recursive: true });
20520
- const seen = /* @__PURE__ */ new Set();
20521
- const columns = [];
20522
- for (const row of rows) {
20523
- for (const key of Object.keys(row)) {
20524
- if (!seen.has(key)) {
20525
- seen.add(key);
20526
- columns.push(key);
20527
- }
20528
- }
20529
- }
20678
+ const columns = columnsForRows(rows);
20530
20679
  const escapeCell = (value) => {
20531
20680
  const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
20532
20681
  if (/[",\n]/.test(normalized)) {
@@ -20534,13 +20683,20 @@ function writeCsvOutputFile(rows, stem, options) {
20534
20683
  }
20535
20684
  return normalized;
20536
20685
  };
20537
- const lines = [];
20538
- lines.push(columns.map(escapeCell).join(","));
20539
- for (const row of rows) {
20540
- lines.push(columns.map((column) => escapeCell(row[column])).join(","));
20686
+ const fd = (0, import_node_fs12.openSync)(outputPath, "w");
20687
+ try {
20688
+ (0, import_node_fs12.writeSync)(fd, `${columns.map(escapeCell).join(",")}
20689
+ `);
20690
+ for (const row of rows) {
20691
+ (0, import_node_fs12.writeSync)(
20692
+ fd,
20693
+ `${columns.map((column) => escapeCell(row[column])).join(",")}
20694
+ `
20695
+ );
20696
+ }
20697
+ } finally {
20698
+ (0, import_node_fs12.closeSync)(fd);
20541
20699
  }
20542
- (0, import_node_fs12.writeFileSync)(outputPath, `${lines.join("\n")}
20543
- `, "utf-8");
20544
20700
  const previewRows = rows.slice(0, 5);
20545
20701
  const previewColumns = columns.slice(0, 5);
20546
20702
  const preview = [
@@ -21067,10 +21223,7 @@ Examples:
21067
21223
  ).option(
21068
21224
  "--output-format <format>",
21069
21225
  "Output format: auto, csv, csv_file, json, or json_file"
21070
- ).option(
21071
- "-o, --out <path>",
21072
- "Write row-shaped tool output to this CSV path"
21073
- ).option(
21226
+ ).option("-o, --out <path>", "Write row-shaped tool output to this CSV path").option(
21074
21227
  "--no-preview",
21075
21228
  "Only print the extracted output path when applicable"
21076
21229
  ).action(async (toolId, options) => {
@@ -21924,6 +22077,100 @@ function buildToolExecuteBaseEnvelope(input2) {
21924
22077
  }
21925
22078
  };
21926
22079
  }
22080
+ function buildToolExecuteRowArtifactEnvelope(input2) {
22081
+ const {
22082
+ toolResponse: _toolResponse,
22083
+ result: _result,
22084
+ output: _output,
22085
+ output_preview: _outputPreview,
22086
+ render: _render,
22087
+ next: _next,
22088
+ local: _local,
22089
+ ...base
22090
+ } = input2.baseEnvelope;
22091
+ void _toolResponse;
22092
+ void _result;
22093
+ void _output;
22094
+ void _outputPreview;
22095
+ void _render;
22096
+ void _next;
22097
+ void _local;
22098
+ return {
22099
+ ...base,
22100
+ status: typeof base.status === "string" ? base.status : "completed",
22101
+ output_preview: {
22102
+ kind: "list",
22103
+ rowCount: input2.rowOutput.rowCount,
22104
+ columns: input2.rowOutput.columns,
22105
+ preview: input2.rowOutput.previewRows,
22106
+ listStrategy: input2.rowOutput.strategy,
22107
+ listSourcePath: input2.rowOutput.sourcePath
22108
+ },
22109
+ csv_path: input2.csv.path,
22110
+ row_count: input2.csv.rowCount,
22111
+ row_count_returned: input2.csv.rowCount,
22112
+ columns: input2.csv.columns,
22113
+ extracted_csv: input2.csv.path,
22114
+ extracted_csv_rows: input2.csv.rowCount,
22115
+ extracted_csv_columns: input2.csv.columns,
22116
+ preview: input2.csv.preview,
22117
+ list_strategy: input2.rowOutput.strategy,
22118
+ list_source_path: input2.rowOutput.sourcePath,
22119
+ summary: input2.summary,
22120
+ local: {
22121
+ extracted_csv: input2.csv.path,
22122
+ extracted_csv_rows: input2.csv.rowCount,
22123
+ extracted_csv_columns: input2.csv.columns,
22124
+ preview: input2.csv.preview,
22125
+ starter_script: input2.seededScript.path,
22126
+ project_dir: input2.seededScript.projectDir,
22127
+ copy_to_project: {
22128
+ macos_linux: input2.seededScript.macCopyCommand,
22129
+ windows_powershell: input2.seededScript.windowsCopyCommand
22130
+ }
22131
+ },
22132
+ starter_script: input2.seededScript.path,
22133
+ project_dir: input2.seededScript.projectDir,
22134
+ copy_to_project: {
22135
+ macos_linux: input2.seededScript.macCopyCommand,
22136
+ windows_powershell: input2.seededScript.windowsCopyCommand
22137
+ },
22138
+ next: {
22139
+ inspect: "Re-run with --json only when you need the raw provider/tool response.",
22140
+ listSourcePath: input2.rowOutput.sourcePath,
22141
+ expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
22142
+ },
22143
+ render: {
22144
+ sections: [
22145
+ {
22146
+ title: `${input2.csv.path} (${input2.csv.rowCount} rows)`,
22147
+ lines: [
22148
+ ...input2.csv.columns.length > 0 ? [`columns: ${JSON.stringify(input2.csv.columns)}`] : [],
22149
+ ...Object.keys(input2.summary).length > 0 ? [
22150
+ `summary: ${Object.entries(input2.summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
22151
+ ] : [],
22152
+ `preview: ${JSON.stringify(input2.rowOutput.previewRows)}`,
22153
+ `starter script: ${input2.seededScript.path}`
22154
+ ]
22155
+ }
22156
+ ],
22157
+ actions: [
22158
+ {
22159
+ label: "next",
22160
+ command: "Move the script into a project folder and expand it into a Deepline play. Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
22161
+ },
22162
+ {
22163
+ label: "macOS/Linux",
22164
+ command: input2.seededScript.macCopyCommand
22165
+ },
22166
+ {
22167
+ label: "Windows PowerShell",
22168
+ command: input2.seededScript.windowsCopyCommand
22169
+ }
22170
+ ]
22171
+ }
22172
+ };
22173
+ }
21927
22174
  async function executeTool(args) {
21928
22175
  let parsed;
21929
22176
  try {
@@ -21975,7 +22222,9 @@ async function executeTool(args) {
21975
22222
  }
21976
22223
  return 2;
21977
22224
  }
21978
- const rawResponse = await client2.executeTool(parsed.toolId, parsed.params);
22225
+ const rawResponse = await client2.executeTool(parsed.toolId, parsed.params, {
22226
+ responseIntent: parsed.outPath || parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file" ? "row_artifact" : "raw"
22227
+ });
21979
22228
  const listConversion = tryConvertToList(rawResponse, {
21980
22229
  listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
21981
22230
  });
@@ -22039,6 +22288,7 @@ async function executeTool(args) {
22039
22288
  printCommandEnvelope(baseEnvelope, { json: false });
22040
22289
  return 0;
22041
22290
  }
22291
+ const rowOutput = projectRowOutput(listConversion);
22042
22292
  const csv = writeCsvOutputFile(
22043
22293
  listConversion.rows,
22044
22294
  `${parsed.toolId}_output`,
@@ -22049,91 +22299,23 @@ async function executeTool(args) {
22049
22299
  payload: parsed.params,
22050
22300
  rows: listConversion.rows
22051
22301
  });
22052
- const materializedEnvelope = {
22053
- ...baseEnvelope,
22054
- local: {
22055
- extracted_csv: csv.path,
22056
- extracted_csv_rows: csv.rowCount,
22057
- extracted_csv_columns: csv.columns,
22058
- preview: csv.preview,
22059
- starter_script: seededScript.path,
22060
- project_dir: seededScript.projectDir,
22061
- copy_to_project: {
22062
- macos_linux: seededScript.macCopyCommand,
22063
- windows_powershell: seededScript.windowsCopyCommand
22064
- }
22065
- },
22066
- render: {
22067
- sections: [
22068
- {
22069
- title: `${csv.path} (${csv.rowCount} rows)`,
22070
- lines: [
22071
- ...csv.columns.length > 0 ? [`columns: ${JSON.stringify(csv.columns)}`] : [],
22072
- ...Object.keys(summary).length > 0 ? [
22073
- `summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
22074
- ] : [],
22075
- `preview: ${JSON.stringify(csv.preview)}`,
22076
- `starter script: ${seededScript.path}`
22077
- ]
22078
- }
22079
- ],
22080
- actions: [
22081
- {
22082
- label: "next",
22083
- command: "Move the script into a project folder and expand it into a Deepline play. Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
22084
- },
22085
- {
22086
- label: "macOS/Linux",
22087
- command: seededScript.macCopyCommand
22088
- },
22089
- {
22090
- label: "Windows PowerShell",
22091
- command: seededScript.windowsCopyCommand
22092
- }
22093
- ]
22094
- }
22095
- };
22302
+ const materializedEnvelope = buildToolExecuteRowArtifactEnvelope({
22303
+ baseEnvelope,
22304
+ csv,
22305
+ rowOutput,
22306
+ summary,
22307
+ seededScript
22308
+ });
22096
22309
  if (parsed.outputFormat === "csv_file") {
22097
- printCommandEnvelope(
22098
- {
22099
- ...materializedEnvelope,
22100
- extracted_csv: csv.path,
22101
- extracted_csv_rows: csv.rowCount,
22102
- extracted_csv_columns: csv.columns,
22103
- preview: csv.preview,
22104
- list_strategy: listConversion.strategy,
22105
- list_source_path: listConversion.sourcePath,
22106
- starter_script: seededScript.path,
22107
- project_dir: seededScript.projectDir,
22108
- copy_to_project: {
22109
- macos_linux: seededScript.macCopyCommand,
22110
- windows_powershell: seededScript.windowsCopyCommand
22111
- },
22112
- summary
22113
- },
22114
- { json: true }
22115
- );
22310
+ printCommandEnvelope(materializedEnvelope, { json: true });
22116
22311
  return 0;
22117
22312
  }
22118
22313
  if (parsed.outPath) {
22119
- printCommandEnvelope(
22120
- {
22121
- ...materializedEnvelope,
22122
- csv_path: csv.path,
22123
- row_count: csv.rowCount,
22124
- row_count_returned: csv.rowCount,
22125
- columns: csv.columns,
22126
- preview: csv.preview,
22127
- list_strategy: listConversion.strategy,
22128
- list_source_path: listConversion.sourcePath,
22129
- summary
22130
- },
22131
- {
22132
- json: argsWantJson(args) || shouldEmitJson(),
22133
- text: `Wrote ${csv.rowCount} row(s) to ${csv.path}
22314
+ printCommandEnvelope(materializedEnvelope, {
22315
+ json: argsWantJson(args) || shouldEmitJson(),
22316
+ text: `Wrote ${csv.rowCount} row(s) to ${csv.path}
22134
22317
  `
22135
- }
22136
- );
22318
+ });
22137
22319
  return 0;
22138
22320
  }
22139
22321
  if (parsed.noPreview) {
@@ -23314,7 +23496,7 @@ async function runAutomaticUpdatePlan(plan) {
23314
23496
  previousFailure
23315
23497
  };
23316
23498
  }
23317
- const exitCode = await runUpdatePlan(plan);
23499
+ const exitCode = await runUpdatePlan(plan, { stdio: "stderr" });
23318
23500
  return exitCode === 0 ? { status: "updated", exitCode: 0 } : { status: "failed", exitCode };
23319
23501
  }
23320
23502
  function safeVersionSegment(value) {
@@ -23345,13 +23527,21 @@ function installedPackageVersion(versionDir) {
23345
23527
  return "";
23346
23528
  }
23347
23529
  }
23348
- function runCommand(command, args, env = process.env) {
23530
+ function runCommand(command, args, env = process.env, options = {}) {
23349
23531
  return new Promise((resolveExitCode) => {
23350
23532
  const child = (0, import_node_child_process3.spawn)(command, args, {
23351
- stdio: "inherit",
23533
+ stdio: options.stdio === "stderr" ? ["inherit", "pipe", "pipe"] : "inherit",
23352
23534
  shell: process.platform === "win32",
23353
23535
  env
23354
23536
  });
23537
+ if (options.stdio === "stderr") {
23538
+ child.stdout?.on("data", (chunk) => {
23539
+ process.stderr.write(chunk);
23540
+ });
23541
+ child.stderr?.on("data", (chunk) => {
23542
+ process.stderr.write(chunk);
23543
+ });
23544
+ }
23355
23545
  child.on("error", (error) => {
23356
23546
  process.stderr.write(`Failed to start ${command}: ${error.message}
23357
23547
  `);
@@ -23389,7 +23579,7 @@ function writeSidecarLauncher(input2) {
23389
23579
  { encoding: "utf8", mode: 493 }
23390
23580
  );
23391
23581
  }
23392
- async function runPythonSidecarUpdatePlan(plan) {
23582
+ async function runPythonSidecarUpdatePlan(plan, options = {}) {
23393
23583
  const versionsDir = (0, import_node_path18.join)(plan.stateDir, "versions");
23394
23584
  const tempDir = (0, import_node_path18.join)(
23395
23585
  versionsDir,
@@ -23411,7 +23601,8 @@ async function runPythonSidecarUpdatePlan(plan) {
23411
23601
  ...NPM_SDK_INSTALL_COMMON_FLAGS,
23412
23602
  plan.packageSpec
23413
23603
  ],
23414
- env
23604
+ env,
23605
+ options
23415
23606
  );
23416
23607
  if (installExitCode !== 0) {
23417
23608
  (0, import_node_fs15.rmSync)(tempDir, { recursive: true, force: true });
@@ -23484,12 +23675,12 @@ async function runPythonSidecarUpdatePlan(plan) {
23484
23675
  );
23485
23676
  return 0;
23486
23677
  }
23487
- async function runUpdatePlan(plan) {
23678
+ async function runUpdatePlan(plan, options = {}) {
23488
23679
  let exitCode = 1;
23489
23680
  if (plan.kind === "npm-global") {
23490
- exitCode = await runCommand(plan.command, plan.args);
23681
+ exitCode = await runCommand(plan.command, plan.args, process.env, options);
23491
23682
  } else if (plan.kind === "python-sidecar") {
23492
- exitCode = await runPythonSidecarUpdatePlan(plan);
23683
+ exitCode = await runPythonSidecarUpdatePlan(plan, options);
23493
23684
  }
23494
23685
  if (exitCode === 0) {
23495
23686
  clearAutoUpdateFailure(plan);