deepline 0.1.145 → 0.1.147

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
@@ -619,10 +619,11 @@ var SDK_RELEASE = {
619
619
  // 0.1.108 ships explicit dataset column/tool recompute policy and removes
620
620
  // the SDK enrich generator's one-second stale policy.
621
621
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
622
- version: "0.1.145",
623
- apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
622
+ // 0.1.111 ships dataset-native tool list getters and result row datasets.
623
+ version: "0.1.147",
624
+ apiContract: "2026-06-dataset-handle-results-hard-cutover",
624
625
  supportPolicy: {
625
- latest: "0.1.145",
626
+ latest: "0.1.147",
626
627
  minimumSupported: "0.1.53",
627
628
  deprecatedBelow: "0.1.53",
628
629
  commandMinimumSupported: [
@@ -633,52 +634,79 @@ var SDK_RELEASE = {
633
634
  },
634
635
  {
635
636
  command: "plays",
636
- minimumSupported: "0.1.110",
637
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
637
+ minimumSupported: "0.1.111",
638
+ reason: "Play file commands now use dataset-native list getters and result row datasets."
638
639
  },
639
640
  {
640
641
  command: "plays run",
641
- minimumSupported: "0.1.110",
642
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
642
+ minimumSupported: "0.1.111",
643
+ reason: "Play run results now promote row-shaped outputs into dataset handles for safe export."
643
644
  },
644
645
  {
645
646
  command: "run",
646
647
  displayCommand: "plays run",
647
- minimumSupported: "0.1.110",
648
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
648
+ minimumSupported: "0.1.111",
649
+ reason: "Play run results now promote row-shaped outputs into dataset handles for safe export."
649
650
  },
650
651
  {
651
652
  command: "plays check",
652
- minimumSupported: "0.1.110",
653
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
653
+ minimumSupported: "0.1.111",
654
+ reason: "Play file checks now validate dataset-native list getter authoring."
654
655
  },
655
656
  {
656
657
  command: "check",
657
658
  displayCommand: "plays check",
658
- minimumSupported: "0.1.110",
659
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
659
+ minimumSupported: "0.1.111",
660
+ reason: "Play file checks now validate dataset-native list getter authoring."
660
661
  },
661
662
  {
662
663
  command: "plays publish",
663
- minimumSupported: "0.1.110",
664
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
664
+ minimumSupported: "0.1.111",
665
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
665
666
  },
666
667
  {
667
668
  command: "publish",
668
669
  displayCommand: "plays publish",
669
- minimumSupported: "0.1.110",
670
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
670
+ minimumSupported: "0.1.111",
671
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
671
672
  },
672
673
  {
673
674
  command: "plays set-live",
674
- minimumSupported: "0.1.110",
675
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
675
+ minimumSupported: "0.1.111",
676
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
676
677
  },
677
678
  {
678
679
  command: "set-live",
679
680
  displayCommand: "plays set-live",
680
- minimumSupported: "0.1.110",
681
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
681
+ minimumSupported: "0.1.111",
682
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
683
+ },
684
+ {
685
+ command: "runs",
686
+ minimumSupported: "0.1.111",
687
+ reason: "Run result rows now render as dataset handles with explicit export commands."
688
+ },
689
+ {
690
+ command: "runs get",
691
+ minimumSupported: "0.1.111",
692
+ reason: "Run result rows now render as dataset handles with explicit export commands."
693
+ },
694
+ {
695
+ command: "get",
696
+ displayCommand: "runs get",
697
+ minimumSupported: "0.1.111",
698
+ reason: "Run result rows now render as dataset handles with explicit export commands."
699
+ },
700
+ {
701
+ command: "runs export",
702
+ minimumSupported: "0.1.111",
703
+ reason: "Run result row datasets now use the dataset-handle export contract."
704
+ },
705
+ {
706
+ command: "export",
707
+ displayCommand: "runs export",
708
+ minimumSupported: "0.1.111",
709
+ reason: "Run result row datasets now use the dataset-handle export contract."
682
710
  }
683
711
  ],
684
712
  autoUpdatePatchLag: 2
@@ -8302,9 +8330,10 @@ function generateProviderSourceBlock(input2) {
8302
8330
  input: ${inputName},
8303
8331
  description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
8304
8332
  });
8305
- // extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
8333
+ // extractedLists.${getter}.get() returns a dataset handle of provider-shaped rows. Do not assume canonical fields;
8306
8334
  // inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
8307
- const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
8335
+ const sourceRowsDataset_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get();
8336
+ const sourceRows_${input2.index} = (await sourceRowsDataset_${input2.index}.peek(limit)) as ${input2.collectionType}[];`;
8308
8337
  }
8309
8338
  function generateProviderSourceRowsBlock(input2) {
8310
8339
  const blocks = input2.source.values.map(
@@ -10990,6 +11019,9 @@ function formatPlayLogLine(line, status, state) {
10990
11019
  }
10991
11020
  return `${prefix}${message}`;
10992
11021
  }
11022
+ function isDatasetResultEnvelope(value) {
11023
+ return value !== null && typeof value === "object" && !Array.isArray(value) && value.kind === "dataset";
11024
+ }
10993
11025
  function compactReturnValue(value, depth = 0) {
10994
11026
  if (depth >= 4) {
10995
11027
  return value && typeof value === "object" ? "[Object]" : value;
@@ -11001,6 +11033,7 @@ function compactReturnValue(value, depth = 0) {
11001
11033
  if (!value || typeof value !== "object") {
11002
11034
  return value;
11003
11035
  }
11036
+ const isDatasetEnvelope = isDatasetResultEnvelope(value);
11004
11037
  const output2 = {};
11005
11038
  for (const [key, entry] of Object.entries(value)) {
11006
11039
  if (depth === 0 && key === "_metadata") {
@@ -11009,13 +11042,41 @@ function compactReturnValue(value, depth = 0) {
11009
11042
  if (BULKY_RETURN_KEYS.has(key)) {
11010
11043
  continue;
11011
11044
  }
11012
- if (key === "access") {
11045
+ if (isDatasetEnvelope && key === "access") {
11046
+ continue;
11047
+ }
11048
+ if (isDatasetEnvelope && (key === "queryDatasetCommand" || key === "cliCommand")) {
11049
+ continue;
11050
+ }
11051
+ if (isDatasetEnvelope && key === "slowExportAsCsvCommand") {
11052
+ output2.fullExportCommand = entry;
11013
11053
  continue;
11014
11054
  }
11015
11055
  output2[key] = compactReturnValue(entry, depth + 1);
11016
11056
  }
11017
11057
  return output2;
11018
11058
  }
11059
+ function defaultResultForEnvelope(value, depth = 0) {
11060
+ if (depth > 20 || value == null || typeof value !== "object") {
11061
+ return value;
11062
+ }
11063
+ if (Array.isArray(value)) {
11064
+ return value.map((entry) => defaultResultForEnvelope(entry, depth + 1));
11065
+ }
11066
+ const isDatasetEnvelope = isDatasetResultEnvelope(value);
11067
+ const output2 = {};
11068
+ for (const [key, entry] of Object.entries(value)) {
11069
+ if (isDatasetEnvelope && (key === "queryDatasetCommand" || key === "cliCommand")) {
11070
+ continue;
11071
+ }
11072
+ if (isDatasetEnvelope && key === "slowExportAsCsvCommand") {
11073
+ output2.fullExportCommand = entry;
11074
+ continue;
11075
+ }
11076
+ output2[key] = defaultResultForEnvelope(entry, depth + 1);
11077
+ }
11078
+ return output2;
11079
+ }
11019
11080
  function formatJsonPreview(value) {
11020
11081
  const json = JSON.stringify(value, null, 2);
11021
11082
  if (!json || json === "{}") {
@@ -11059,9 +11120,6 @@ function collectDatasetHandleLines(value, path = "result", datasetStats) {
11059
11120
  if (datasetStats && (datasetStats.source === path || datasetStats.source === record.path)) {
11060
11121
  lines2.push(...formatDatasetStatsLines(datasetStats.stats, " "));
11061
11122
  }
11062
- if (typeof record.queryDatasetCommand === "string") {
11063
- lines2.push(` query dataset: ${record.queryDatasetCommand}`);
11064
- }
11065
11123
  if (typeof record.slowExportAsCsvCommand === "string") {
11066
11124
  lines2.push(` export CSV: ${record.slowExportAsCsvCommand}`);
11067
11125
  }
@@ -11472,7 +11530,7 @@ function compactPlayStatus(status) {
11472
11530
  logs: normalizeLogsForEnvelope(status),
11473
11531
  ...displayError ? { error: displayError } : {},
11474
11532
  ...warnings.length > 0 ? { warnings } : {},
11475
- ...result !== void 0 ? { result } : {},
11533
+ ...result !== void 0 ? { result: defaultResultForEnvelope(result) } : {},
11476
11534
  ...billing ? { billing } : {},
11477
11535
  next: buildRunNextCommands(status)
11478
11536
  };
@@ -18946,6 +19004,221 @@ Examples:
18946
19004
  }
18947
19005
  }
18948
19006
 
19007
+ // src/cli/commands/monitors.ts
19008
+ var FORBIDDEN_AS_API_ERROR = { forbiddenAsApiError: true };
19009
+ function buildHttpClient() {
19010
+ return new HttpClient(resolveConfig());
19011
+ }
19012
+ function parseJsonObjectArg(raw, flag) {
19013
+ let parsed;
19014
+ try {
19015
+ parsed = JSON.parse(raw);
19016
+ } catch (error) {
19017
+ throw new Error(
19018
+ `${flag} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
19019
+ );
19020
+ }
19021
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
19022
+ throw new Error(`${flag} must be a JSON object.`);
19023
+ }
19024
+ return parsed;
19025
+ }
19026
+ function encodeKey(key) {
19027
+ return encodeURIComponent(key);
19028
+ }
19029
+ async function handleMonitorsTools(options) {
19030
+ const http = buildHttpClient();
19031
+ const params = new URLSearchParams();
19032
+ if (options.provider) params.set("provider", options.provider);
19033
+ if (options.tool) params.set("tool", options.tool);
19034
+ if (options.search) params.set("search", options.search);
19035
+ if (options.limit) params.set("limit", options.limit);
19036
+ const query = params.toString();
19037
+ const payload = await http.request(
19038
+ `/api/v2/monitors/tools${query ? `?${query}` : ""}`,
19039
+ { method: "GET", ...FORBIDDEN_AS_API_ERROR }
19040
+ );
19041
+ printCommandEnvelope(payload, { json: options.json });
19042
+ }
19043
+ async function handleMonitorsCheck(definition, options) {
19044
+ const http = buildHttpClient();
19045
+ const body = parseJsonObjectArg(definition, "--definition");
19046
+ const payload = await http.request(
19047
+ "/api/v2/monitors/check",
19048
+ { method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
19049
+ );
19050
+ printCommandEnvelope(payload, { json: options.json });
19051
+ }
19052
+ async function handleMonitorsDeploy(definition, options) {
19053
+ const http = buildHttpClient();
19054
+ const body = parseJsonObjectArg(definition, "--definition");
19055
+ const payload = await http.request(
19056
+ "/api/v2/monitors/deploy",
19057
+ { method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
19058
+ );
19059
+ printCommandEnvelope(payload, { json: options.json });
19060
+ }
19061
+ async function handleDeployedList(options) {
19062
+ const http = buildHttpClient();
19063
+ const params = new URLSearchParams();
19064
+ if (options.status) params.set("status", options.status);
19065
+ if (options.limit) params.set("limit", options.limit);
19066
+ const query = params.toString();
19067
+ const payload = await http.request(
19068
+ `/api/v2/monitors/deployed${query ? `?${query}` : ""}`,
19069
+ { method: "GET", ...FORBIDDEN_AS_API_ERROR }
19070
+ );
19071
+ printCommandEnvelope(payload, { json: options.json });
19072
+ }
19073
+ async function handleDeployedGet(key, options) {
19074
+ const http = buildHttpClient();
19075
+ const payload = await http.request(
19076
+ `/api/v2/monitors/deployed/${encodeKey(key)}`,
19077
+ { method: "GET", ...FORBIDDEN_AS_API_ERROR }
19078
+ );
19079
+ printCommandEnvelope(payload, { json: options.json });
19080
+ }
19081
+ async function handleDeployedDelete(key, options) {
19082
+ const http = buildHttpClient();
19083
+ const params = new URLSearchParams();
19084
+ if (options.localOnly) params.set("local_only", "true");
19085
+ const query = params.toString();
19086
+ const payload = await http.request(
19087
+ `/api/v2/monitors/deployed/${encodeKey(key)}${query ? `?${query}` : ""}`,
19088
+ { method: "DELETE", ...FORBIDDEN_AS_API_ERROR }
19089
+ );
19090
+ printCommandEnvelope(payload, { json: options.json });
19091
+ }
19092
+ async function handleDeployedUpdate(key, patch, options) {
19093
+ const http = buildHttpClient();
19094
+ const body = parseJsonObjectArg(patch, "<patch>");
19095
+ const payload = await http.request(
19096
+ `/api/v2/monitors/deployed/${encodeKey(key)}`,
19097
+ { method: "PATCH", body, ...FORBIDDEN_AS_API_ERROR }
19098
+ );
19099
+ printCommandEnvelope(payload, { json: options.json });
19100
+ }
19101
+ async function handleReactivate(key, options) {
19102
+ const http = buildHttpClient();
19103
+ const payload = await http.request(
19104
+ `/api/v2/monitors/deployed/${encodeKey(key)}/reactivate`,
19105
+ { method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
19106
+ );
19107
+ printCommandEnvelope(payload, { json: options.json });
19108
+ }
19109
+ function registerMonitorsCommands(program) {
19110
+ const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").addHelpText(
19111
+ "after",
19112
+ `
19113
+ Notes:
19114
+ Monitors are provider-backed signal feeds that deliver events into your
19115
+ workspace. Access is granted by a Deepline admin via Admin -> Rollouts; until
19116
+ then these commands return a clear monitor_access_required error.
19117
+
19118
+ Examples:
19119
+ deepline monitors tools --json
19120
+ deepline monitors check '{"key":"my-monitor","tool":"...","payload":{}}'
19121
+ deepline monitors deploy '{"key":"my-monitor","tool":"...","payload":{}}'
19122
+ deepline monitors deployed --json
19123
+ deepline monitors deployed get my-monitor --json
19124
+ deepline monitors reactivate my-monitor --json
19125
+ `
19126
+ );
19127
+ monitors.command("tools").description("List or describe the monitor tools available to your org.").addHelpText(
19128
+ "after",
19129
+ `
19130
+ Notes:
19131
+ Read-only. Filter the catalog with --provider, --tool, --search, or --limit.
19132
+ Pass --tool to describe a single monitor tool.
19133
+
19134
+ Examples:
19135
+ deepline monitors tools
19136
+ deepline monitors tools --provider theirstack --json
19137
+ deepline monitors tools --tool theirstack_jobs --json
19138
+ `
19139
+ ).option("--provider <provider>", "Filter by provider").option("--tool <tool>", "Describe a single monitor tool by id").option("--search <query>", "Search monitor tools by text").option("--limit <n>", "Limit the number of monitor tools returned").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsTools);
19140
+ monitors.command("check <definition>").description("Validate a monitor definition without deploying it.").addHelpText(
19141
+ "after",
19142
+ `
19143
+ Notes:
19144
+ Read-only validation. <definition> is a JSON object with key, tool, payload,
19145
+ and optional controls. Does not deploy or spend credits.
19146
+
19147
+ Examples:
19148
+ deepline monitors check '{"key":"my-monitor","tool":"theirstack_jobs","payload":{}}'
19149
+ `
19150
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsCheck);
19151
+ monitors.command("deploy <definition>").description("Deploy a monitor from a definition.").addHelpText(
19152
+ "after",
19153
+ `
19154
+ Notes:
19155
+ Mutates workspace state and may spend Deepline credits. <definition> is a JSON
19156
+ object with key, tool, payload, and optional controls.
19157
+
19158
+ Examples:
19159
+ deepline monitors deploy '{"key":"my-monitor","tool":"theirstack_jobs","payload":{}}'
19160
+ `
19161
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsDeploy);
19162
+ monitors.command("reactivate <key>").description("Reactivate a previously disabled deployed monitor.").addHelpText(
19163
+ "after",
19164
+ `
19165
+ Notes:
19166
+ Mutates workspace state and may spend Deepline credits.
19167
+
19168
+ Examples:
19169
+ deepline monitors reactivate my-monitor --json
19170
+ `
19171
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReactivate);
19172
+ const deployed = monitors.command("deployed").description("List and manage your deployed monitors.").addHelpText(
19173
+ "after",
19174
+ `
19175
+ Notes:
19176
+ With no subcommand, lists deployed monitors. Use get/update/delete to manage a
19177
+ single monitor by its public key.
19178
+
19179
+ Examples:
19180
+ deepline monitors deployed --json
19181
+ deepline monitors deployed --status all --json
19182
+ deepline monitors deployed get my-monitor --json
19183
+ `
19184
+ ).option("--status <status>", 'Filter by monitor status (or "all")').option("--limit <n>", "Limit the number of deployed monitors returned").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedList);
19185
+ deployed.command("get <key>").description("Show a single deployed monitor by its public key.").addHelpText(
19186
+ "after",
19187
+ `
19188
+ Notes:
19189
+ Read-only.
19190
+
19191
+ Examples:
19192
+ deepline monitors deployed get my-monitor --json
19193
+ `
19194
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedGet);
19195
+ deployed.command("update <key> <patch>").description("Update a deployed monitor by its public key.").addHelpText(
19196
+ "after",
19197
+ `
19198
+ Notes:
19199
+ Mutates workspace state. <patch> is a JSON object of fields to update.
19200
+
19201
+ Examples:
19202
+ deepline monitors deployed update my-monitor '{"controls":{"enabled":false}}' --json
19203
+ `
19204
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedUpdate);
19205
+ deployed.command("delete <key>").description("Delete a deployed monitor by its public key.").addHelpText(
19206
+ "after",
19207
+ `
19208
+ Notes:
19209
+ Mutates workspace state. By default deprovisions the upstream provider
19210
+ resource; pass --local-only to remove only the Deepline-managed record.
19211
+
19212
+ Examples:
19213
+ deepline monitors deployed delete my-monitor --json
19214
+ deepline monitors deployed delete my-monitor --local-only --json
19215
+ `
19216
+ ).option(
19217
+ "--local-only",
19218
+ "Remove only the Deepline-managed record, leaving the upstream resource"
19219
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedDelete);
19220
+ }
19221
+
18949
19222
  // src/cli/commands/org.ts
18950
19223
  async function fetchOrganizations(http, apiKey) {
18951
19224
  return http.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
@@ -20200,16 +20473,24 @@ function tryConvertToList(payload, options) {
20200
20473
  (entry) => typeof entry === "string" && entry.trim().length > 0
20201
20474
  ) : [];
20202
20475
  if (listExtractorPaths.length > 0) {
20476
+ let emptyMatch = null;
20203
20477
  for (const root of candidateRoots(payload)) {
20204
20478
  for (const extractorPath of listExtractorPaths) {
20205
20479
  const resolved = getByDottedPath(root.value, extractorPath);
20206
20480
  const rows = normalizeRows(resolved);
20207
- if (rows && rows.length > 0) {
20208
- const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
20481
+ if (!rows) {
20482
+ continue;
20483
+ }
20484
+ const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
20485
+ if (rows.length > 0) {
20209
20486
  return { rows, strategy: "configured_paths", sourcePath };
20210
20487
  }
20488
+ emptyMatch ??= { rows, strategy: "configured_paths", sourcePath };
20211
20489
  }
20212
20490
  }
20491
+ if (emptyMatch) {
20492
+ return emptyMatch;
20493
+ }
20213
20494
  }
20214
20495
  for (const root of candidateRoots(payload)) {
20215
20496
  const candidate = findBestArrayCandidate(root.value, root.path ?? "");
@@ -20233,9 +20514,9 @@ function writeJsonOutputFile(payload, stem) {
20233
20514
  (0, import_node_fs12.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
20234
20515
  return outputPath;
20235
20516
  }
20236
- function writeCsvOutputFile(rows, stem) {
20237
- const outputDir = ensureOutputDir();
20238
- const outputPath = (0, import_node_path14.join)(outputDir, `${stem}_${Date.now()}.csv`);
20517
+ function writeCsvOutputFile(rows, stem, options) {
20518
+ const outputPath = options?.outPath ? options.outPath : (0, import_node_path14.join)(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
20519
+ (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(outputPath), { recursive: true });
20239
20520
  const seen = /* @__PURE__ */ new Set();
20240
20521
  const columns = [];
20241
20522
  for (const row of rows) {
@@ -20764,6 +21045,7 @@ Examples:
20764
21045
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
20765
21046
  deepline tools execute hunter_email_verifier -p email=a@b.com
20766
21047
  deepline tools execute test_rate_limit --input '{"key":"smoke"}' --json | jq '.status'
21048
+ deepline tools execute free_simple_company_search --input '{"sql":"SELECT company_name FROM companies LIMIT 10"}' --out companies.csv
20767
21049
  `
20768
21050
  ).option(
20769
21051
  "-p, --param <key=value>",
@@ -20785,6 +21067,9 @@ Examples:
20785
21067
  ).option(
20786
21068
  "--output-format <format>",
20787
21069
  "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"
20788
21073
  ).option(
20789
21074
  "--no-preview",
20790
21075
  "Only print the extracted output path when applicable"
@@ -20797,6 +21082,7 @@ Examples:
20797
21082
  ...options.input ? ["--input", options.input] : [],
20798
21083
  ...options.payload ? ["--payload", options.payload] : [],
20799
21084
  ...options.outputFormat ? ["--output-format", options.outputFormat] : [],
21085
+ ...options.out ? ["--out", options.out] : [],
20800
21086
  ...options.preview === false ? ["--no-preview"] : []
20801
21087
  ];
20802
21088
  process.exitCode = await executeTool(args);
@@ -21247,7 +21533,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
21247
21533
  invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
21248
21534
  observeActualShape: observedOutputCommand,
21249
21535
  observedOutput: observedOutputCommand,
21250
- forPlayGetterBugs: "Run a tiny play, inspect `deepline runs get <run-id> --full --json`, and export returned dataset handles with `deepline runs export`. Backing tables exist only for ctx.map(...).run(...) stages that actually executed.",
21536
+ forPlayGetterBugs: "Run a tiny play, inspect returned handles with `deepline runs get <run-id> --full --json`, then export row datasets with `deepline runs export`.",
21251
21537
  executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
21252
21538
  },
21253
21539
  ...starterScript ? { starterScript } : {}
@@ -21454,12 +21740,13 @@ function parseExecuteOptions(args) {
21454
21740
  const toolId = args[0];
21455
21741
  if (!toolId) {
21456
21742
  throw new Error(
21457
- `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
21743
+ `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--out rows.csv] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
21458
21744
  );
21459
21745
  }
21460
21746
  const params = {};
21461
21747
  let outputFormat = "auto";
21462
21748
  let noPreview = false;
21749
+ let outPath = null;
21463
21750
  for (let index = 1; index < args.length; index += 1) {
21464
21751
  const arg = args[index];
21465
21752
  if ((arg === "--param" || arg === "-p") && args[index + 1]) {
@@ -21491,9 +21778,13 @@ function parseExecuteOptions(args) {
21491
21778
  noPreview = true;
21492
21779
  continue;
21493
21780
  }
21781
+ if ((arg === "--out" || arg === "-o") && args[index + 1]) {
21782
+ outPath = (0, import_node_path15.resolve)(args[++index]);
21783
+ continue;
21784
+ }
21494
21785
  throw new Error(`Unknown option: ${arg}`);
21495
21786
  }
21496
- return { toolId, params, outputFormat, noPreview };
21787
+ return { toolId, params, outputFormat, noPreview, outPath };
21497
21788
  }
21498
21789
  function safeFileStem(value) {
21499
21790
  return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
@@ -21537,9 +21828,14 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
21537
21828
  });
21538
21829
 
21539
21830
  const list = Object.values(result.extractedLists)[0];
21540
- const rows = (list?.get() ?? []).slice(0, 100);
21831
+ if (!list) {
21832
+ throw new Error('Expected ${input2.toolId} to expose an extracted list getter.');
21833
+ }
21834
+ const rows = list.get();
21541
21835
  // ${sampleRows}
21542
21836
  // columns: ${columns}
21837
+ // extractedLists.<name>.get() returns a dataset handle for row-shaped list outputs.
21838
+ // Pass it to ctx.dataset; use rows.peek/count/materialize only for deliberate bounded inspection.
21543
21839
  // .withColumn('email_waterfall', (row, rowCtx) => rowCtx.runPlay('name_domain_email', 'name-and-domain-to-email', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), domain: String(row.domain ?? '') }, { description: 'Resolve email.' }))
21544
21840
  // .withColumn('phone_waterfall', (row, rowCtx) => rowCtx.runPlay('contact_phone', 'contact-to-phone', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), email: String(row.email ?? '') }, { description: 'Resolve phone.' }))
21545
21841
  // ctx.dataset is idempotent by dataset key + row key; reruns reuse completed rows.
@@ -21599,7 +21895,7 @@ function buildToolExecuteBaseEnvelope(input2) {
21599
21895
  ...summaryEntries.length > 0 ? { summary: input2.summary } : {},
21600
21896
  next: {
21601
21897
  inspect: inspectCommand,
21602
- playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
21898
+ playDebugging: "When fixing a play getter, inspect returned dataset handles with runs get and export rows with runs export; do not copy CLI preview paths blindly.",
21603
21899
  ...input2.listConversion ? {
21604
21900
  expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
21605
21901
  listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
@@ -21611,7 +21907,7 @@ function buildToolExecuteBaseEnvelope(input2) {
21611
21907
  title: "output",
21612
21908
  lines: [
21613
21909
  `${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
21614
- "paths above are observed from this execute response; use run table rows to debug play getters",
21910
+ "paths above are observed from this execute response; use runs get and runs export to validate play output",
21615
21911
  `columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
21616
21912
  `preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
21617
21913
  ]
@@ -21691,7 +21987,7 @@ async function executeTool(args) {
21691
21987
  listConversion,
21692
21988
  summary
21693
21989
  });
21694
- if (parsed.outputFormat === "json" || parsed.outputFormat === "auto" && shouldEmitJson()) {
21990
+ if (!parsed.outPath && (parsed.outputFormat === "json" || parsed.outputFormat === "auto" && shouldEmitJson())) {
21695
21991
  printCommandEnvelope(baseEnvelope, { json: true });
21696
21992
  return 0;
21697
21993
  }
@@ -21713,6 +22009,17 @@ async function executeTool(args) {
21713
22009
  return 0;
21714
22010
  }
21715
22011
  if (!listConversion) {
22012
+ if (parsed.outPath) {
22013
+ const error = new Error(
22014
+ `${parsed.toolId} did not expose row-shaped output to write as CSV. Re-run with --json to inspect the raw tool response.`
22015
+ );
22016
+ if (argsWantJson(args)) {
22017
+ printJsonError(error);
22018
+ } else {
22019
+ console.error(error.message);
22020
+ }
22021
+ return 1;
22022
+ }
21716
22023
  if (parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file") {
21717
22024
  const jsonPath = writeJsonOutputFile(
21718
22025
  rawResponse,
@@ -21734,7 +22041,8 @@ async function executeTool(args) {
21734
22041
  }
21735
22042
  const csv = writeCsvOutputFile(
21736
22043
  listConversion.rows,
21737
- `${parsed.toolId}_output`
22044
+ `${parsed.toolId}_output`,
22045
+ parsed.outPath ? { outPath: parsed.outPath } : void 0
21738
22046
  );
21739
22047
  const seededScript = seedToolListScript({
21740
22048
  toolId: parsed.toolId,
@@ -21807,6 +22115,27 @@ async function executeTool(args) {
21807
22115
  );
21808
22116
  return 0;
21809
22117
  }
22118
+ 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}
22134
+ `
22135
+ }
22136
+ );
22137
+ return 0;
22138
+ }
21810
22139
  if (parsed.noPreview) {
21811
22140
  printCommandEnvelope(
21812
22141
  {
@@ -23991,6 +24320,7 @@ Exit codes:
23991
24320
  registerWorkflowCommands(program);
23992
24321
  registerSecretsCommands(program);
23993
24322
  registerBillingCommands(program);
24323
+ registerMonitorsCommands(program);
23994
24324
  registerOrgCommands(program);
23995
24325
  registerEnrichCommand(program);
23996
24326
  registerCsvCommands(program);