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.
@@ -222,6 +222,8 @@ var PROD_URL = "https://code.deepline.com";
222
222
  var DEFAULT_TIMEOUT = 6e4;
223
223
  var DEFAULT_MAX_RETRIES = 3;
224
224
  var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
225
+ var WORKSPACE_RESTORE_ENV_DIR = ".deepline";
226
+ var WORKSPACE_RESTORE_ENV_FILE = ".env";
225
227
  var COWORK_IGNORED_WORKSPACE_DIRS = /* @__PURE__ */ new Set([
226
228
  ".auto-memory",
227
229
  ".claude",
@@ -536,6 +538,18 @@ function ensureProjectEnvIsIgnored(dir) {
536
538
  writeFileSync(gitignorePath, `${existing}${prefix}${entry}
537
539
  `, "utf-8");
538
540
  }
541
+ function ensureWorkspaceRestoreEnvIsIgnored(workspaceDir) {
542
+ const gitignorePath = join(workspaceDir, ".gitignore");
543
+ const entry = `${WORKSPACE_RESTORE_ENV_DIR}/`;
544
+ const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
545
+ const alreadyIgnored = existing.split(/\r?\n/).map((line) => line.trim()).some(
546
+ (line) => line === entry || line === `/${entry}` || line === WORKSPACE_RESTORE_ENV_DIR || line === `/${WORKSPACE_RESTORE_ENV_DIR}`
547
+ );
548
+ if (alreadyIgnored) return;
549
+ const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
550
+ writeFileSync(gitignorePath, `${existing}${prefix}${entry}
551
+ `, "utf-8");
552
+ }
539
553
  function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
540
554
  const target = resolveProjectPinTarget(startDir);
541
555
  if (!target.ok) {
@@ -549,6 +563,27 @@ function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
549
563
  mergeProjectEnvFile(filePath, values);
550
564
  return [filePath];
551
565
  }
566
+ function saveCoworkWorkspaceRestoreEnvValues(values, startDir = process.cwd()) {
567
+ if (!isCoworkLikeSandbox()) return [];
568
+ const target = resolveProjectPinTarget(startDir);
569
+ if (!target.ok || target.source === "cwd") return [];
570
+ const workspaceDir = target.dir;
571
+ const filePath = join(
572
+ workspaceDir,
573
+ WORKSPACE_RESTORE_ENV_DIR,
574
+ WORKSPACE_RESTORE_ENV_FILE
575
+ );
576
+ const existing = parseEnvFile(filePath);
577
+ const merged = { ...existing, ...values };
578
+ const dir = dirname(filePath);
579
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
580
+ ensureWorkspaceRestoreEnvIsIgnored(workspaceDir);
581
+ const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
582
+ const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
583
+ writeFileSync(filePath, `${lines.join("\n")}
584
+ `, "utf-8");
585
+ return [filePath];
586
+ }
552
587
  function resolveProjectPinTarget(startDir = process.cwd()) {
553
588
  const nearestFile = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
554
589
  if (nearestFile && !isInIgnoredCoworkMount(nearestFile)) {
@@ -605,10 +640,10 @@ var SDK_RELEASE = {
605
640
  // the SDK enrich generator's one-second stale policy.
606
641
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
607
642
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
608
- version: "0.1.148",
643
+ version: "0.1.150",
609
644
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
610
645
  supportPolicy: {
611
- latest: "0.1.148",
646
+ latest: "0.1.150",
612
647
  minimumSupported: "0.1.53",
613
648
  deprecatedBelow: "0.1.53",
614
649
  commandMinimumSupported: [
@@ -2072,6 +2107,7 @@ async function* observeRunEvents(options) {
2072
2107
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
2073
2108
  var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
2074
2109
  var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
2110
+ var EXECUTE_RESPONSE_INTENT_HEADER = "x-deepline-execute-response-intent";
2075
2111
  var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
2076
2112
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
2077
2113
  var REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
@@ -2556,7 +2592,8 @@ var DeeplineClient = class {
2556
2592
  async executeTool(toolId, input2, options) {
2557
2593
  const headers = {
2558
2594
  [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
2559
- ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
2595
+ ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {},
2596
+ ...options?.responseIntent ? { [EXECUTE_RESPONSE_INTENT_HEADER]: options.responseIntent } : {}
2560
2597
  };
2561
2598
  return this.http.post(
2562
2599
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
@@ -4690,6 +4727,9 @@ function saveEnvValues(values, baseUrl) {
4690
4727
  ...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
4691
4728
  };
4692
4729
  saveHostEnvValues(baseUrl, filtered);
4730
+ if (filtered[API_KEY_ENV]) {
4731
+ saveCoworkWorkspaceRestoreEnvValues(filtered);
4732
+ }
4693
4733
  }
4694
4734
  async function httpJson(method, url, apiKey, body) {
4695
4735
  const headers = {
@@ -6920,6 +6960,7 @@ Examples:
6920
6960
  import { writeFileSync as writeFileSync6 } from "fs";
6921
6961
  import { resolve as resolve5 } from "path";
6922
6962
  var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set(["table", "json", "csv", "markdown"]);
6963
+ var CUSTOMER_DB_QUERY_MAX_ROWS = 1e3;
6923
6964
  function parsePositiveInteger(value, flagName) {
6924
6965
  const parsed = Number.parseInt(value, 10);
6925
6966
  if (!Number.isFinite(parsed) || parsed <= 0) {
@@ -6927,6 +6968,15 @@ function parsePositiveInteger(value, flagName) {
6927
6968
  }
6928
6969
  return parsed;
6929
6970
  }
6971
+ function parseMaxRows(value) {
6972
+ const parsed = parsePositiveInteger(value, "--max-rows");
6973
+ if (parsed > CUSTOMER_DB_QUERY_MAX_ROWS) {
6974
+ throw new Error(
6975
+ `--max-rows must be ${CUSTOMER_DB_QUERY_MAX_ROWS} or less. Add LIMIT/OFFSET to page larger exports.`
6976
+ );
6977
+ }
6978
+ return parsed;
6979
+ }
6930
6980
  function formatCell(value) {
6931
6981
  if (value === null || value === void 0) return "";
6932
6982
  const text = typeof value === "object" ? JSON.stringify(value) : String(value);
@@ -7072,7 +7122,7 @@ async function handleDbQuery(args) {
7072
7122
  return 1;
7073
7123
  }
7074
7124
  const maxRowsIndex = args.indexOf("--max-rows");
7075
- const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
7125
+ const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parseMaxRows(args[maxRowsIndex + 1]) : void 0;
7076
7126
  const formatIndex = args.indexOf("--format");
7077
7127
  const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
7078
7128
  if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
@@ -17046,8 +17096,14 @@ async function writeOutputCsv(outputPath, status, options) {
17046
17096
  rowsInfo
17047
17097
  }).catch(() => null) ?? rowsInfo;
17048
17098
  }
17049
- assertCompleteRowsForCsvExport(rowsInfo, status, outputPath);
17050
- const merged = mergeRowsForCsvExport(rowsInfo.rows, options);
17099
+ const allowPartial = options?.allowPartial === true && !rowsInfo.complete && rowsInfo.rows.length > 0 && Boolean(options?.sourceCsvPath);
17100
+ assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, {
17101
+ allowPartial
17102
+ });
17103
+ const merged = mergeRowsForCsvExport(rowsInfo.rows, {
17104
+ ...options,
17105
+ allowPartial
17106
+ });
17051
17107
  const columns = orderEnrichCsvColumns(
17052
17108
  dataExportColumns(merged.rows, [
17053
17109
  ...merged.preferredColumns,
@@ -17067,9 +17123,52 @@ async function writeOutputCsv(outputPath, status, options) {
17067
17123
  enrichedRows: rowsInfo.rows.length,
17068
17124
  rows: merged.rows.length,
17069
17125
  path: resolve8(outputPath),
17126
+ partial: !rowsInfo.complete,
17070
17127
  enrichedDataRows: rowsInfo.rows
17071
17128
  };
17072
17129
  }
17130
+ function isMissingRowsForCsvExportError(error) {
17131
+ return error instanceof Error && (error.message.includes("did not return row-shaped output") || error.message.includes("run returned 0 preview row(s)"));
17132
+ }
17133
+ async function maybeWriteOutputCsv(input2) {
17134
+ if (!input2.outputPath) return null;
17135
+ try {
17136
+ return await writeOutputCsv(input2.outputPath, input2.status, {
17137
+ client: input2.client,
17138
+ config: input2.config,
17139
+ sourceCsvPath: input2.sourceCsvPath,
17140
+ rows: input2.rows,
17141
+ inPlace: input2.inPlace,
17142
+ allowPartial: input2.capturedResult !== 0
17143
+ });
17144
+ } catch (error) {
17145
+ if (input2.capturedResult !== 0 && isMissingRowsForCsvExportError(error)) {
17146
+ return null;
17147
+ }
17148
+ throw error;
17149
+ }
17150
+ }
17151
+ function enrichOutputJson(exportResult) {
17152
+ if (!exportResult) {
17153
+ return null;
17154
+ }
17155
+ return {
17156
+ sourceCsvRows: exportResult.sourceCsvRows,
17157
+ selectedRows: exportResult.selectedRows,
17158
+ enrichedRows: exportResult.enrichedRows,
17159
+ path: exportResult.path,
17160
+ ...exportResult.partial ? { rows: exportResult.rows, partial: true } : {}
17161
+ };
17162
+ }
17163
+ async function buildEnrichFailureReport(input2) {
17164
+ return maybeEmitEnrichFailureReport({
17165
+ config: input2.config,
17166
+ rows: input2.rows,
17167
+ rowRange: input2.rowRange,
17168
+ client: input2.client,
17169
+ outputPath: input2.exportResult?.path ?? input2.outputPath ?? null
17170
+ });
17171
+ }
17073
17172
  function recordField(value, key) {
17074
17173
  return value && typeof value === "object" && !Array.isArray(value) ? value[key] : void 0;
17075
17174
  }
@@ -17591,10 +17690,7 @@ async function fetchBackingRowsForCsvExport(input2) {
17591
17690
  function mergeRowsForCsvExport(enrichedRows, options) {
17592
17691
  const rows = dataExportRows(normalizeEnrichRowsForCsvExport(enrichedRows));
17593
17692
  const range = options?.rows;
17594
- if (!options?.inPlace && (range?.rowStart === null || range?.rowStart === void 0)) {
17595
- return { rows, preferredColumns: [] };
17596
- }
17597
- if (!options?.sourceCsvPath) {
17693
+ if (!options?.sourceCsvPath || !options.inPlace && !options.allowPartial && (range?.rowStart === null || range?.rowStart === void 0)) {
17598
17694
  return { rows, preferredColumns: [] };
17599
17695
  }
17600
17696
  const parsedBaseRows = readCsvRows(options.sourceCsvPath);
@@ -17606,7 +17702,7 @@ function mergeRowsForCsvExport(enrichedRows, options) {
17606
17702
  const maxEnd = Math.max(start, baseRows.length - 1);
17607
17703
  const inclusiveEnd = range?.rowEnd === null || range?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, range.rowEnd);
17608
17704
  const expectedSelectedRows = baseRows.length === 0 ? 0 : Math.max(0, inclusiveEnd - start + 1);
17609
- if (rows.length < expectedSelectedRows) {
17705
+ if (rows.length < expectedSelectedRows && !options.allowPartial) {
17610
17706
  throw new Error(
17611
17707
  `Refusing to write a partial in-place CSV export: the run returned ${rows.length} row(s) for ${expectedSelectedRows} selected source row(s).`
17612
17708
  );
@@ -17805,10 +17901,13 @@ function mergeLegacyMetadataCell(base, enriched) {
17805
17901
  }
17806
17902
  return void 0;
17807
17903
  }
17808
- function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath) {
17904
+ function assertCompleteRowsForCsvExport(rowsInfo, status, outputPath, options = {}) {
17809
17905
  if (rowsInfo.complete) {
17810
17906
  return;
17811
17907
  }
17908
+ if (options.allowPartial) {
17909
+ return;
17910
+ }
17812
17911
  const runId = status && typeof status === "object" && !Array.isArray(status) && typeof status.runId === "string" ? status.runId : null;
17813
17912
  const dataset = rowsInfo.source ?? "result.rows";
17814
17913
  const retry = runId ? ` Retry after the run finalizes its backing dataset with: deepline runs export ${runId} --dataset ${dataset} --out ${outputPath}` : "";
@@ -17964,13 +18063,16 @@ function registerEnrichCommand(program) {
17964
18063
  stdout: captured2.stdout,
17965
18064
  exitCode: captured2.result
17966
18065
  });
17967
- const exportResult2 = captured2.result === 0 && outputPath ? await writeOutputCsv(outputPath, status2, {
18066
+ const exportResult2 = await maybeWriteOutputCsv({
18067
+ outputPath,
18068
+ status: status2,
18069
+ capturedResult: captured2.result,
17968
18070
  client: client2,
17969
18071
  config,
17970
18072
  sourceCsvPath: input2.sourceCsvPath,
17971
18073
  rows: input2.rows,
17972
18074
  inPlace: Boolean(options.inPlace)
17973
- }) : null;
18075
+ });
17974
18076
  return { captured: captured2, status: status2, exportResult: exportResult2 };
17975
18077
  };
17976
18078
  const selectedRange = selectedSourceCsvRange(sourceCsvPath, rows);
@@ -18020,9 +18122,16 @@ function registerEnrichCommand(program) {
18020
18122
  chunks: chunkCount,
18021
18123
  rows: chunkRows
18022
18124
  },
18023
- result: chunk.status
18125
+ result: chunk.status,
18126
+ output: enrichOutputJson(chunk.exportResult)
18024
18127
  });
18025
18128
  } else {
18129
+ if (chunk.exportResult) {
18130
+ process.stderr.write(
18131
+ `Wrote ${chunk.exportResult.rows} row(s) to ${chunk.exportResult.path}${chunk.exportResult.partial ? " (partial run output)" : ""}
18132
+ `
18133
+ );
18134
+ }
18026
18135
  emitPlainBatchRunFailure({
18027
18136
  chunkIndex,
18028
18137
  chunkCount,
@@ -18099,23 +18208,46 @@ function registerEnrichCommand(program) {
18099
18208
  json: Boolean(options.json),
18100
18209
  passthroughStdout: !options.json
18101
18210
  });
18211
+ const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18102
18212
  if (captured.result !== 0) {
18213
+ if (exportResult) {
18214
+ process.stderr.write(
18215
+ `Wrote ${exportResult.rows} row(s) to ${exportResult.path}${exportResult.partial ? " (partial run output)" : ""}
18216
+ `
18217
+ );
18218
+ }
18219
+ const failureReport2 = await buildEnrichFailureReport({
18220
+ config,
18221
+ rows: rowsForFailureReport,
18222
+ rowRange: rows,
18223
+ client: client2,
18224
+ exportResult,
18225
+ outputPath
18226
+ });
18103
18227
  if (options.json) {
18104
18228
  printJson({
18105
- result: status
18229
+ ok: false,
18230
+ run: status,
18231
+ output: enrichOutputJson(exportResult),
18232
+ ...failureReport2 ? {
18233
+ failure_report: {
18234
+ path: failureReport2.path,
18235
+ jobs: failureReport2.jobs.length
18236
+ }
18237
+ } : {}
18106
18238
  });
18107
18239
  }
18108
- process.exitCode = captured.result;
18240
+ process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
18109
18241
  return;
18110
18242
  }
18111
- const rowsForFailureReport = exportResult?.enrichedDataRows ?? extractCanonicalRowsInfo(status)?.rows ?? [];
18112
18243
  if (options.json) {
18113
- const failureReport2 = await maybeEmitEnrichFailureReport({
18244
+ const failureReport2 = await buildEnrichFailureReport({
18114
18245
  config,
18115
18246
  rows: rowsForFailureReport,
18116
18247
  rowRange: rows,
18117
18248
  client: client2,
18118
- outputPath: exportResult?.path ?? outputPath ?? null
18249
+ exportResult,
18250
+ outputPath
18119
18251
  });
18120
18252
  const run = rewriteEnrichJsonStatus({
18121
18253
  status,
@@ -18127,12 +18259,7 @@ function registerEnrichCommand(program) {
18127
18259
  printJson({
18128
18260
  ok: !failureReport2,
18129
18261
  run,
18130
- output: exportResult ? {
18131
- sourceCsvRows: exportResult.sourceCsvRows,
18132
- selectedRows: exportResult.selectedRows,
18133
- enrichedRows: exportResult.enrichedRows,
18134
- path: exportResult.path
18135
- } : null,
18262
+ output: enrichOutputJson(exportResult),
18136
18263
  ...failureReport2 ? {
18137
18264
  failure_report: {
18138
18265
  path: failureReport2.path,
@@ -19493,16 +19620,17 @@ async function handleOrgSwitch(selection, options) {
19493
19620
  const authTarget = resolveOrgSwitchAuthTarget(authScope, config);
19494
19621
  if (target.is_current) {
19495
19622
  let project_env_paths2 = [];
19623
+ const authValues2 = {
19624
+ [HOST_URL_ENV]: config.baseUrl,
19625
+ [API_KEY_ENV]: config.apiKey
19626
+ };
19496
19627
  if (authTarget.kind === "folder") {
19497
- project_env_paths2 = saveProjectDeeplineEnvValues({
19498
- DEEPLINE_HOST_URL: config.baseUrl,
19499
- DEEPLINE_API_KEY: config.apiKey
19500
- });
19628
+ project_env_paths2 = saveProjectDeeplineEnvValues(authValues2);
19501
19629
  } else {
19502
- saveHostEnvValues(config.baseUrl, {
19503
- DEEPLINE_HOST_URL: config.baseUrl,
19504
- DEEPLINE_API_KEY: config.apiKey
19505
- });
19630
+ saveHostEnvValues(config.baseUrl, authValues2);
19631
+ }
19632
+ if (authTarget.kind === "folder") {
19633
+ saveCoworkWorkspaceRestoreEnvValues(authValues2);
19506
19634
  }
19507
19635
  const renderLines2 = [`Already on ${target.name}.`];
19508
19636
  for (const projectPath of project_env_paths2) {
@@ -19551,19 +19679,22 @@ async function handleOrgSwitch(selection, options) {
19551
19679
  org_id: target.org_id
19552
19680
  });
19553
19681
  let project_env_paths = [];
19682
+ const authValues = {
19683
+ [HOST_URL_ENV]: config.baseUrl,
19684
+ [API_KEY_ENV]: switched.api_key
19685
+ };
19554
19686
  if (authTarget.kind === "folder") {
19555
- project_env_paths = saveProjectDeeplineEnvValues({
19556
- DEEPLINE_HOST_URL: config.baseUrl,
19557
- DEEPLINE_API_KEY: switched.api_key
19558
- });
19687
+ project_env_paths = saveProjectDeeplineEnvValues(authValues);
19559
19688
  } else {
19560
19689
  saveHostEnvValues(config.baseUrl, {
19561
- DEEPLINE_HOST_URL: config.baseUrl,
19562
- DEEPLINE_API_KEY: switched.api_key,
19690
+ ...authValues,
19563
19691
  DEEPLINE_ACTIVE_ORG_ID: switched.org_id,
19564
19692
  DEEPLINE_ACTIVE_ORG_NAME: switched.org_name
19565
19693
  });
19566
19694
  }
19695
+ if (authTarget.kind === "folder") {
19696
+ saveCoworkWorkspaceRestoreEnvValues(authValues);
19697
+ }
19567
19698
  const { api_key: _apiKey, ...publicSwitched } = switched;
19568
19699
  const renderLines = [`Switched to ${switched.org_name}.`];
19569
19700
  if (authTarget.kind === "folder") {
@@ -19619,12 +19750,16 @@ async function handleOrgCreate(name, options) {
19619
19750
  api_key: config.apiKey,
19620
19751
  name
19621
19752
  });
19753
+ const authValues = {
19754
+ [HOST_URL_ENV]: config.baseUrl,
19755
+ [API_KEY_ENV]: created.api_key
19756
+ };
19622
19757
  saveHostEnvValues(config.baseUrl, {
19623
- DEEPLINE_HOST_URL: config.baseUrl,
19624
- DEEPLINE_API_KEY: created.api_key,
19758
+ ...authValues,
19625
19759
  DEEPLINE_ACTIVE_ORG_ID: created.org_id,
19626
19760
  DEEPLINE_ACTIVE_ORG_NAME: created.org_name
19627
19761
  });
19762
+ saveCoworkWorkspaceRestoreEnvValues(authValues);
19628
19763
  const { api_key: _apiKey, ...publicCreated } = created;
19629
19764
  printCommandEnvelope(
19630
19765
  {
@@ -20428,7 +20563,13 @@ import { tmpdir as tmpdir3 } from "os";
20428
20563
  import { join as join10, resolve as resolve10 } from "path";
20429
20564
 
20430
20565
  // src/tool-output.ts
20431
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync11 } from "fs";
20566
+ import {
20567
+ closeSync as closeSync2,
20568
+ mkdirSync as mkdirSync7,
20569
+ openSync as openSync2,
20570
+ writeFileSync as writeFileSync11,
20571
+ writeSync
20572
+ } from "fs";
20432
20573
  import { homedir as homedir9 } from "os";
20433
20574
  import { dirname as dirname9, join as join9 } from "path";
20434
20575
  function isPlainObject(value) {
@@ -20451,6 +20592,19 @@ function normalizeRows(value) {
20451
20592
  return { value: entry };
20452
20593
  });
20453
20594
  }
20595
+ function columnsForRows(rows) {
20596
+ const seen = /* @__PURE__ */ new Set();
20597
+ const columns = [];
20598
+ for (const row of rows) {
20599
+ for (const key of Object.keys(row)) {
20600
+ if (!seen.has(key)) {
20601
+ seen.add(key);
20602
+ columns.push(key);
20603
+ }
20604
+ }
20605
+ }
20606
+ return columns;
20607
+ }
20454
20608
  function candidateRoots(payload) {
20455
20609
  const roots = [
20456
20610
  { path: null, value: payload }
@@ -20533,6 +20687,16 @@ function tryConvertToList(payload, options) {
20533
20687
  }
20534
20688
  return null;
20535
20689
  }
20690
+ function projectRowOutput(conversion) {
20691
+ return {
20692
+ rows: conversion.rows,
20693
+ rowCount: conversion.rows.length,
20694
+ columns: columnsForRows(conversion.rows),
20695
+ previewRows: conversion.rows.slice(0, 5),
20696
+ strategy: conversion.strategy,
20697
+ sourcePath: conversion.sourcePath
20698
+ };
20699
+ }
20536
20700
  function ensureOutputDir() {
20537
20701
  const outputDir = join9(homedir9(), ".local", "share", "deepline", "data");
20538
20702
  mkdirSync7(outputDir, { recursive: true });
@@ -20547,16 +20711,7 @@ function writeJsonOutputFile(payload, stem) {
20547
20711
  function writeCsvOutputFile(rows, stem, options) {
20548
20712
  const outputPath = options?.outPath ? options.outPath : join9(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
20549
20713
  mkdirSync7(dirname9(outputPath), { recursive: true });
20550
- const seen = /* @__PURE__ */ new Set();
20551
- const columns = [];
20552
- for (const row of rows) {
20553
- for (const key of Object.keys(row)) {
20554
- if (!seen.has(key)) {
20555
- seen.add(key);
20556
- columns.push(key);
20557
- }
20558
- }
20559
- }
20714
+ const columns = columnsForRows(rows);
20560
20715
  const escapeCell = (value) => {
20561
20716
  const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
20562
20717
  if (/[",\n]/.test(normalized)) {
@@ -20564,13 +20719,20 @@ function writeCsvOutputFile(rows, stem, options) {
20564
20719
  }
20565
20720
  return normalized;
20566
20721
  };
20567
- const lines = [];
20568
- lines.push(columns.map(escapeCell).join(","));
20569
- for (const row of rows) {
20570
- lines.push(columns.map((column) => escapeCell(row[column])).join(","));
20722
+ const fd = openSync2(outputPath, "w");
20723
+ try {
20724
+ writeSync(fd, `${columns.map(escapeCell).join(",")}
20725
+ `);
20726
+ for (const row of rows) {
20727
+ writeSync(
20728
+ fd,
20729
+ `${columns.map((column) => escapeCell(row[column])).join(",")}
20730
+ `
20731
+ );
20732
+ }
20733
+ } finally {
20734
+ closeSync2(fd);
20571
20735
  }
20572
- writeFileSync11(outputPath, `${lines.join("\n")}
20573
- `, "utf-8");
20574
20736
  const previewRows = rows.slice(0, 5);
20575
20737
  const previewColumns = columns.slice(0, 5);
20576
20738
  const preview = [
@@ -21097,10 +21259,7 @@ Examples:
21097
21259
  ).option(
21098
21260
  "--output-format <format>",
21099
21261
  "Output format: auto, csv, csv_file, json, or json_file"
21100
- ).option(
21101
- "-o, --out <path>",
21102
- "Write row-shaped tool output to this CSV path"
21103
- ).option(
21262
+ ).option("-o, --out <path>", "Write row-shaped tool output to this CSV path").option(
21104
21263
  "--no-preview",
21105
21264
  "Only print the extracted output path when applicable"
21106
21265
  ).action(async (toolId, options) => {
@@ -21954,6 +22113,100 @@ function buildToolExecuteBaseEnvelope(input2) {
21954
22113
  }
21955
22114
  };
21956
22115
  }
22116
+ function buildToolExecuteRowArtifactEnvelope(input2) {
22117
+ const {
22118
+ toolResponse: _toolResponse,
22119
+ result: _result,
22120
+ output: _output,
22121
+ output_preview: _outputPreview,
22122
+ render: _render,
22123
+ next: _next,
22124
+ local: _local,
22125
+ ...base
22126
+ } = input2.baseEnvelope;
22127
+ void _toolResponse;
22128
+ void _result;
22129
+ void _output;
22130
+ void _outputPreview;
22131
+ void _render;
22132
+ void _next;
22133
+ void _local;
22134
+ return {
22135
+ ...base,
22136
+ status: typeof base.status === "string" ? base.status : "completed",
22137
+ output_preview: {
22138
+ kind: "list",
22139
+ rowCount: input2.rowOutput.rowCount,
22140
+ columns: input2.rowOutput.columns,
22141
+ preview: input2.rowOutput.previewRows,
22142
+ listStrategy: input2.rowOutput.strategy,
22143
+ listSourcePath: input2.rowOutput.sourcePath
22144
+ },
22145
+ csv_path: input2.csv.path,
22146
+ row_count: input2.csv.rowCount,
22147
+ row_count_returned: input2.csv.rowCount,
22148
+ columns: input2.csv.columns,
22149
+ extracted_csv: input2.csv.path,
22150
+ extracted_csv_rows: input2.csv.rowCount,
22151
+ extracted_csv_columns: input2.csv.columns,
22152
+ preview: input2.csv.preview,
22153
+ list_strategy: input2.rowOutput.strategy,
22154
+ list_source_path: input2.rowOutput.sourcePath,
22155
+ summary: input2.summary,
22156
+ local: {
22157
+ extracted_csv: input2.csv.path,
22158
+ extracted_csv_rows: input2.csv.rowCount,
22159
+ extracted_csv_columns: input2.csv.columns,
22160
+ preview: input2.csv.preview,
22161
+ starter_script: input2.seededScript.path,
22162
+ project_dir: input2.seededScript.projectDir,
22163
+ copy_to_project: {
22164
+ macos_linux: input2.seededScript.macCopyCommand,
22165
+ windows_powershell: input2.seededScript.windowsCopyCommand
22166
+ }
22167
+ },
22168
+ starter_script: input2.seededScript.path,
22169
+ project_dir: input2.seededScript.projectDir,
22170
+ copy_to_project: {
22171
+ macos_linux: input2.seededScript.macCopyCommand,
22172
+ windows_powershell: input2.seededScript.windowsCopyCommand
22173
+ },
22174
+ next: {
22175
+ inspect: "Re-run with --json only when you need the raw provider/tool response.",
22176
+ listSourcePath: input2.rowOutput.sourcePath,
22177
+ expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
22178
+ },
22179
+ render: {
22180
+ sections: [
22181
+ {
22182
+ title: `${input2.csv.path} (${input2.csv.rowCount} rows)`,
22183
+ lines: [
22184
+ ...input2.csv.columns.length > 0 ? [`columns: ${JSON.stringify(input2.csv.columns)}`] : [],
22185
+ ...Object.keys(input2.summary).length > 0 ? [
22186
+ `summary: ${Object.entries(input2.summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
22187
+ ] : [],
22188
+ `preview: ${JSON.stringify(input2.rowOutput.previewRows)}`,
22189
+ `starter script: ${input2.seededScript.path}`
22190
+ ]
22191
+ }
22192
+ ],
22193
+ actions: [
22194
+ {
22195
+ label: "next",
22196
+ 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."
22197
+ },
22198
+ {
22199
+ label: "macOS/Linux",
22200
+ command: input2.seededScript.macCopyCommand
22201
+ },
22202
+ {
22203
+ label: "Windows PowerShell",
22204
+ command: input2.seededScript.windowsCopyCommand
22205
+ }
22206
+ ]
22207
+ }
22208
+ };
22209
+ }
21957
22210
  async function executeTool(args) {
21958
22211
  let parsed;
21959
22212
  try {
@@ -22005,7 +22258,9 @@ async function executeTool(args) {
22005
22258
  }
22006
22259
  return 2;
22007
22260
  }
22008
- const rawResponse = await client2.executeTool(parsed.toolId, parsed.params);
22261
+ const rawResponse = await client2.executeTool(parsed.toolId, parsed.params, {
22262
+ responseIntent: parsed.outPath || parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file" ? "row_artifact" : "raw"
22263
+ });
22009
22264
  const listConversion = tryConvertToList(rawResponse, {
22010
22265
  listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
22011
22266
  });
@@ -22069,6 +22324,7 @@ async function executeTool(args) {
22069
22324
  printCommandEnvelope(baseEnvelope, { json: false });
22070
22325
  return 0;
22071
22326
  }
22327
+ const rowOutput = projectRowOutput(listConversion);
22072
22328
  const csv = writeCsvOutputFile(
22073
22329
  listConversion.rows,
22074
22330
  `${parsed.toolId}_output`,
@@ -22079,91 +22335,23 @@ async function executeTool(args) {
22079
22335
  payload: parsed.params,
22080
22336
  rows: listConversion.rows
22081
22337
  });
22082
- const materializedEnvelope = {
22083
- ...baseEnvelope,
22084
- local: {
22085
- extracted_csv: csv.path,
22086
- extracted_csv_rows: csv.rowCount,
22087
- extracted_csv_columns: csv.columns,
22088
- preview: csv.preview,
22089
- starter_script: seededScript.path,
22090
- project_dir: seededScript.projectDir,
22091
- copy_to_project: {
22092
- macos_linux: seededScript.macCopyCommand,
22093
- windows_powershell: seededScript.windowsCopyCommand
22094
- }
22095
- },
22096
- render: {
22097
- sections: [
22098
- {
22099
- title: `${csv.path} (${csv.rowCount} rows)`,
22100
- lines: [
22101
- ...csv.columns.length > 0 ? [`columns: ${JSON.stringify(csv.columns)}`] : [],
22102
- ...Object.keys(summary).length > 0 ? [
22103
- `summary: ${Object.entries(summary).map(([key, value]) => `${key}=${String(value)}`).join(", ")}`
22104
- ] : [],
22105
- `preview: ${JSON.stringify(csv.preview)}`,
22106
- `starter script: ${seededScript.path}`
22107
- ]
22108
- }
22109
- ],
22110
- actions: [
22111
- {
22112
- label: "next",
22113
- 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."
22114
- },
22115
- {
22116
- label: "macOS/Linux",
22117
- command: seededScript.macCopyCommand
22118
- },
22119
- {
22120
- label: "Windows PowerShell",
22121
- command: seededScript.windowsCopyCommand
22122
- }
22123
- ]
22124
- }
22125
- };
22338
+ const materializedEnvelope = buildToolExecuteRowArtifactEnvelope({
22339
+ baseEnvelope,
22340
+ csv,
22341
+ rowOutput,
22342
+ summary,
22343
+ seededScript
22344
+ });
22126
22345
  if (parsed.outputFormat === "csv_file") {
22127
- printCommandEnvelope(
22128
- {
22129
- ...materializedEnvelope,
22130
- extracted_csv: csv.path,
22131
- extracted_csv_rows: csv.rowCount,
22132
- extracted_csv_columns: csv.columns,
22133
- preview: csv.preview,
22134
- list_strategy: listConversion.strategy,
22135
- list_source_path: listConversion.sourcePath,
22136
- starter_script: seededScript.path,
22137
- project_dir: seededScript.projectDir,
22138
- copy_to_project: {
22139
- macos_linux: seededScript.macCopyCommand,
22140
- windows_powershell: seededScript.windowsCopyCommand
22141
- },
22142
- summary
22143
- },
22144
- { json: true }
22145
- );
22346
+ printCommandEnvelope(materializedEnvelope, { json: true });
22146
22347
  return 0;
22147
22348
  }
22148
22349
  if (parsed.outPath) {
22149
- printCommandEnvelope(
22150
- {
22151
- ...materializedEnvelope,
22152
- csv_path: csv.path,
22153
- row_count: csv.rowCount,
22154
- row_count_returned: csv.rowCount,
22155
- columns: csv.columns,
22156
- preview: csv.preview,
22157
- list_strategy: listConversion.strategy,
22158
- list_source_path: listConversion.sourcePath,
22159
- summary
22160
- },
22161
- {
22162
- json: argsWantJson(args) || shouldEmitJson(),
22163
- text: `Wrote ${csv.rowCount} row(s) to ${csv.path}
22350
+ printCommandEnvelope(materializedEnvelope, {
22351
+ json: argsWantJson(args) || shouldEmitJson(),
22352
+ text: `Wrote ${csv.rowCount} row(s) to ${csv.path}
22164
22353
  `
22165
- }
22166
- );
22354
+ });
22167
22355
  return 0;
22168
22356
  }
22169
22357
  if (parsed.noPreview) {
@@ -23353,7 +23541,7 @@ async function runAutomaticUpdatePlan(plan) {
23353
23541
  previousFailure
23354
23542
  };
23355
23543
  }
23356
- const exitCode = await runUpdatePlan(plan);
23544
+ const exitCode = await runUpdatePlan(plan, { stdio: "stderr" });
23357
23545
  return exitCode === 0 ? { status: "updated", exitCode: 0 } : { status: "failed", exitCode };
23358
23546
  }
23359
23547
  function safeVersionSegment(value) {
@@ -23384,13 +23572,21 @@ function installedPackageVersion(versionDir) {
23384
23572
  return "";
23385
23573
  }
23386
23574
  }
23387
- function runCommand(command, args, env = process.env) {
23575
+ function runCommand(command, args, env = process.env, options = {}) {
23388
23576
  return new Promise((resolveExitCode) => {
23389
23577
  const child = spawn3(command, args, {
23390
- stdio: "inherit",
23578
+ stdio: options.stdio === "stderr" ? ["inherit", "pipe", "pipe"] : "inherit",
23391
23579
  shell: process.platform === "win32",
23392
23580
  env
23393
23581
  });
23582
+ if (options.stdio === "stderr") {
23583
+ child.stdout?.on("data", (chunk) => {
23584
+ process.stderr.write(chunk);
23585
+ });
23586
+ child.stderr?.on("data", (chunk) => {
23587
+ process.stderr.write(chunk);
23588
+ });
23589
+ }
23394
23590
  child.on("error", (error) => {
23395
23591
  process.stderr.write(`Failed to start ${command}: ${error.message}
23396
23592
  `);
@@ -23428,7 +23624,7 @@ function writeSidecarLauncher(input2) {
23428
23624
  { encoding: "utf8", mode: 493 }
23429
23625
  );
23430
23626
  }
23431
- async function runPythonSidecarUpdatePlan(plan) {
23627
+ async function runPythonSidecarUpdatePlan(plan, options = {}) {
23432
23628
  const versionsDir = join13(plan.stateDir, "versions");
23433
23629
  const tempDir = join13(
23434
23630
  versionsDir,
@@ -23450,7 +23646,8 @@ async function runPythonSidecarUpdatePlan(plan) {
23450
23646
  ...NPM_SDK_INSTALL_COMMON_FLAGS,
23451
23647
  plan.packageSpec
23452
23648
  ],
23453
- env
23649
+ env,
23650
+ options
23454
23651
  );
23455
23652
  if (installExitCode !== 0) {
23456
23653
  rmSync3(tempDir, { recursive: true, force: true });
@@ -23523,12 +23720,12 @@ async function runPythonSidecarUpdatePlan(plan) {
23523
23720
  );
23524
23721
  return 0;
23525
23722
  }
23526
- async function runUpdatePlan(plan) {
23723
+ async function runUpdatePlan(plan, options = {}) {
23527
23724
  let exitCode = 1;
23528
23725
  if (plan.kind === "npm-global") {
23529
- exitCode = await runCommand(plan.command, plan.args);
23726
+ exitCode = await runCommand(plan.command, plan.args, process.env, options);
23530
23727
  } else if (plan.kind === "python-sidecar") {
23531
- exitCode = await runPythonSidecarUpdatePlan(plan);
23728
+ exitCode = await runPythonSidecarUpdatePlan(plan, options);
23532
23729
  }
23533
23730
  if (exitCode === 0) {
23534
23731
  clearAutoUpdateFailure(plan);