deepline 0.1.33 → 0.1.36

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
@@ -216,8 +216,8 @@ function resolveConfig(options) {
216
216
  }
217
217
 
218
218
  // src/version.ts
219
- var SDK_VERSION = "0.1.33";
220
- var SDK_API_CONTRACT = "2026-05-host-env-generic-play-input-flags";
219
+ var SDK_VERSION = "0.1.36";
220
+ var SDK_API_CONTRACT = "2026-05-v2-tool-response";
221
221
 
222
222
  // ../shared_libs/play-runtime/coordinator-headers.ts
223
223
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
@@ -299,7 +299,7 @@ var HttpClient = class {
299
299
  const response = await fetch(candidateUrl, {
300
300
  method,
301
301
  headers,
302
- body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
302
+ body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
303
303
  signal: controller.signal
304
304
  });
305
305
  clearTimeout(timeoutId);
@@ -382,10 +382,13 @@ var HttpClient = class {
382
382
  throw new AuthError();
383
383
  }
384
384
  if (!response.ok) {
385
+ const body = await response.text();
386
+ const parsed = parseResponseBody(body);
385
387
  throw new DeeplineError(
386
- `HTTP ${response.status}`,
388
+ apiErrorMessage(parsed, response.status),
387
389
  response.status,
388
- "API_ERROR"
390
+ "API_ERROR",
391
+ { response: parsed }
389
392
  );
390
393
  }
391
394
  if (!response.body) {
@@ -435,6 +438,26 @@ var HttpClient = class {
435
438
  return this.request(path, { method: "DELETE" });
436
439
  }
437
440
  };
441
+ function parseResponseBody(body) {
442
+ try {
443
+ return JSON.parse(body);
444
+ } catch {
445
+ return body;
446
+ }
447
+ }
448
+ function apiErrorMessage(parsed, status) {
449
+ const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
450
+ if (typeof errorValue === "string") {
451
+ return errorValue;
452
+ }
453
+ if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
454
+ return errorValue.message;
455
+ }
456
+ if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
457
+ return parsed.message;
458
+ }
459
+ return `HTTP ${status}`;
460
+ }
438
461
  function parseRetryAfter(response) {
439
462
  const header = response.headers.get("retry-after");
440
463
  if (header) {
@@ -498,15 +521,17 @@ function decodeSseFrame(frame) {
498
521
  return parsed;
499
522
  }
500
523
  function sleep(ms) {
501
- return new Promise((resolve10) => setTimeout(resolve10, ms));
524
+ return new Promise((resolve11) => setTimeout(resolve11, ms));
502
525
  }
503
526
 
504
527
  // src/client.ts
505
528
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
506
529
  var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
530
+ var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
531
+ var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
507
532
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
508
533
  function sleep2(ms) {
509
- return new Promise((resolve10) => setTimeout(resolve10, ms));
534
+ return new Promise((resolve11) => setTimeout(resolve11, ms));
510
535
  }
511
536
  function isTransientCompileManifestError(error) {
512
537
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -772,13 +797,16 @@ var DeeplineClient = class {
772
797
  /**
773
798
  * Execute a tool and return the standard execution envelope.
774
799
  *
775
- * The `result.data` field contains the provider payload. `result.meta`
776
- * contains provider/upstream metadata such as HTTP status or paging details.
800
+ * The `toolResponse.raw` field contains the raw tool response.
801
+ * `toolResponse.meta` contains tool/provider metadata.
777
802
  * Top-level fields such as `status`, `job_id`, and `billing` describe the
778
- * Deepline execution.
803
+ * Deepline execution envelope.
779
804
  */
780
805
  async executeTool(toolId, input, options) {
781
- const headers = options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : void 0;
806
+ const headers = {
807
+ [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
808
+ ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
809
+ };
782
810
  return this.http.post(
783
811
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
784
812
  { payload: input },
@@ -1076,34 +1104,37 @@ var DeeplineClient = class {
1076
1104
  * ```
1077
1105
  */
1078
1106
  async stagePlayFiles(files) {
1079
- const formData = new FormData();
1080
- formData.set(
1081
- "metadata",
1082
- JSON.stringify({
1083
- files: files.map((file, index) => ({
1084
- index,
1085
- logicalPath: file.logicalPath,
1086
- contentHash: file.contentHash,
1087
- contentType: file.contentType,
1088
- bytes: file.bytes
1089
- }))
1090
- })
1091
- );
1092
- for (const [index, file] of files.entries()) {
1093
- const bytes = decodeBase64Bytes(file.contentBase64);
1094
- const body = bytes.buffer.slice(
1095
- bytes.byteOffset,
1096
- bytes.byteOffset + bytes.byteLength
1097
- );
1107
+ const buildFormData = () => {
1108
+ const formData = new FormData();
1098
1109
  formData.set(
1099
- `file:${index}`,
1100
- new Blob([body], { type: file.contentType }),
1101
- file.logicalPath
1110
+ "metadata",
1111
+ JSON.stringify({
1112
+ files: files.map((file, index) => ({
1113
+ index,
1114
+ logicalPath: file.logicalPath,
1115
+ contentHash: file.contentHash,
1116
+ contentType: file.contentType,
1117
+ bytes: file.bytes
1118
+ }))
1119
+ })
1102
1120
  );
1103
- }
1121
+ for (const [index, file] of files.entries()) {
1122
+ const bytes = decodeBase64Bytes(file.contentBase64);
1123
+ const body = bytes.buffer.slice(
1124
+ bytes.byteOffset,
1125
+ bytes.byteOffset + bytes.byteLength
1126
+ );
1127
+ formData.set(
1128
+ `file:${index}`,
1129
+ new Blob([body], { type: file.contentType }),
1130
+ file.logicalPath
1131
+ );
1132
+ }
1133
+ return formData;
1134
+ };
1104
1135
  const response = await this.http.postFormData(
1105
1136
  "/api/v2/plays/files/stage",
1106
- formData
1137
+ buildFormData
1107
1138
  );
1108
1139
  return response.files;
1109
1140
  }
@@ -1892,6 +1923,103 @@ function csvStringFromRows(rows, columns) {
1892
1923
  ...columns?.length ? { columns } : {}
1893
1924
  });
1894
1925
  }
1926
+ function parseMaybeJsonObject(value) {
1927
+ if (typeof value !== "string") {
1928
+ return value;
1929
+ }
1930
+ const trimmed = value.trim();
1931
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
1932
+ return value;
1933
+ }
1934
+ try {
1935
+ return JSON.parse(trimmed);
1936
+ } catch {
1937
+ return value;
1938
+ }
1939
+ }
1940
+ function flattenObjectColumns(row) {
1941
+ const flattened = {};
1942
+ for (const [key, rawValue] of Object.entries(row)) {
1943
+ const value = parseMaybeJsonObject(rawValue);
1944
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1945
+ for (const [nestedKey, nestedValue] of Object.entries(
1946
+ value
1947
+ )) {
1948
+ flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? JSON.stringify(nestedValue) : nestedValue;
1949
+ }
1950
+ continue;
1951
+ }
1952
+ flattened[key] = Array.isArray(value) ? JSON.stringify(value) : value;
1953
+ }
1954
+ return flattened;
1955
+ }
1956
+ function recordRows(value) {
1957
+ return value.filter(
1958
+ (row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
1959
+ );
1960
+ }
1961
+ function dataExportRows(rows) {
1962
+ return rows.map((row) => flattenObjectColumns(row));
1963
+ }
1964
+ function dataExportColumns(rows, preferredColumns = []) {
1965
+ const discoveredColumns = [
1966
+ ...new Set(rows.flatMap((row) => Object.keys(row)))
1967
+ ];
1968
+ if (rows.length === 0) {
1969
+ return [...new Set(preferredColumns.filter(Boolean))];
1970
+ }
1971
+ const discovered = new Set(discoveredColumns);
1972
+ const columns = [];
1973
+ const seen = /* @__PURE__ */ new Set();
1974
+ for (const column of preferredColumns) {
1975
+ if (!column) {
1976
+ continue;
1977
+ }
1978
+ const expandedColumns = discovered.has(column) ? [column] : discoveredColumns.filter(
1979
+ (discoveredColumn) => discoveredColumn.startsWith(`${column}.`)
1980
+ );
1981
+ for (const expandedColumn of expandedColumns) {
1982
+ if (seen.has(expandedColumn)) {
1983
+ continue;
1984
+ }
1985
+ seen.add(expandedColumn);
1986
+ columns.push(expandedColumn);
1987
+ }
1988
+ }
1989
+ for (const column of discoveredColumns) {
1990
+ if (seen.has(column)) {
1991
+ continue;
1992
+ }
1993
+ seen.add(column);
1994
+ columns.push(column);
1995
+ }
1996
+ return columns;
1997
+ }
1998
+ function dataExportCsvString(rows, preferredColumns = []) {
1999
+ const flattenedRows = dataExportRows(rows);
2000
+ return csvStringFromRows(
2001
+ flattenedRows,
2002
+ dataExportColumns(flattenedRows, preferredColumns)
2003
+ );
2004
+ }
2005
+ function markdownCell(value) {
2006
+ if (value === null || value === void 0) {
2007
+ return "";
2008
+ }
2009
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
2010
+ return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
2011
+ }
2012
+ function markdownTableFromRows(rows, preferredColumns = []) {
2013
+ const flattenedRows = dataExportRows(rows);
2014
+ const columns = dataExportColumns(flattenedRows, preferredColumns);
2015
+ const header = `| ${columns.map(markdownCell).join(" | ")} |`;
2016
+ const separator = `| ${columns.map(() => "---").join(" | ")} |`;
2017
+ const body = flattenedRows.map(
2018
+ (row) => `| ${columns.map((column) => markdownCell(row[column])).join(" | ")} |`
2019
+ );
2020
+ return `${[header, separator, ...body].join("\n")}
2021
+ `;
2022
+ }
1895
2023
  function printJson(value) {
1896
2024
  process.stdout.write(`${JSON.stringify(value, null, 2)}
1897
2025
  `);
@@ -2068,7 +2196,7 @@ function buildCandidateUrls2(url) {
2068
2196
  }
2069
2197
  }
2070
2198
  function sleep3(ms) {
2071
- return new Promise((resolve10) => setTimeout(resolve10, ms));
2199
+ return new Promise((resolve11) => setTimeout(resolve11, ms));
2072
2200
  }
2073
2201
  function printDeeplineLogo() {
2074
2202
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -3268,10 +3396,12 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
3268
3396
  rows: rowsInfo.rows,
3269
3397
  columns: rowsInfo.columns
3270
3398
  });
3399
+ const rows = dataExportRows(sanitized.rows);
3400
+ const columns = dataExportColumns(rows, sanitized.columns);
3271
3401
  const resolved = (0, import_node_path5.resolve)(outPath);
3272
3402
  (0, import_node_fs4.writeFileSync)(
3273
3403
  resolved,
3274
- csvStringFromRows(sanitized.rows, sanitized.columns),
3404
+ csvStringFromRows(rows, columns),
3275
3405
  "utf-8"
3276
3406
  );
3277
3407
  return resolved;
@@ -3392,6 +3522,14 @@ Examples:
3392
3522
  }
3393
3523
 
3394
3524
  // src/cli/commands/db.ts
3525
+ var import_node_fs5 = require("fs");
3526
+ var import_node_path6 = require("path");
3527
+ var CUSTOMER_DB_QUERY_FORMATS = /* @__PURE__ */ new Set([
3528
+ "table",
3529
+ "json",
3530
+ "csv",
3531
+ "markdown"
3532
+ ]);
3395
3533
  function parsePositiveInteger(value, flagName) {
3396
3534
  const parsed = Number.parseInt(value, 10);
3397
3535
  if (!Number.isFinite(parsed) || parsed <= 0) {
@@ -3405,10 +3543,8 @@ function formatCell(value) {
3405
3543
  return text.length > 80 ? `${text.slice(0, 77)}...` : text;
3406
3544
  }
3407
3545
  function tableLines(result) {
3408
- const rows = result.rows.filter(
3409
- (row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
3410
- );
3411
- const responseColumns = result.columns.length > 0 ? result.columns.map((column) => column.name) : [...new Set(rows.flatMap((row) => Object.keys(row)))];
3546
+ const rows = dataExportRows(customerDbRows(result));
3547
+ const responseColumns = dataExportColumns(rows, customerDbColumnNames(result));
3412
3548
  const businessColumns = responseColumns.filter((column) => !column.startsWith("_"));
3413
3549
  const columns = businessColumns.length > 0 ? businessColumns : responseColumns;
3414
3550
  const hiddenColumns = responseColumns.filter((column) => !columns.includes(column));
@@ -3442,22 +3578,146 @@ function tableLines(result) {
3442
3578
  }
3443
3579
  return lines;
3444
3580
  }
3581
+ function customerDbRows(result) {
3582
+ return recordRows(result.rows);
3583
+ }
3584
+ function customerDbColumnNames(result) {
3585
+ return result.columns.map((column) => column.name).filter(Boolean);
3586
+ }
3587
+ function writeCustomerDbCsv(result, outPath) {
3588
+ const resolved = (0, import_node_path6.resolve)(outPath);
3589
+ (0, import_node_fs5.writeFileSync)(
3590
+ resolved,
3591
+ dataExportCsvString(customerDbRows(result), customerDbColumnNames(result)),
3592
+ "utf-8"
3593
+ );
3594
+ return resolved;
3595
+ }
3596
+ function dbQueryExportEnvelope(input) {
3597
+ const destination = input.outPath ?? "stdout";
3598
+ return {
3599
+ command: input.result.command,
3600
+ format: input.format,
3601
+ row_count: input.result.row_count,
3602
+ row_count_returned: input.result.row_count_returned,
3603
+ truncated: input.result.truncated,
3604
+ ...input.outPath ? { file: input.outPath, local: { file: input.outPath } } : {},
3605
+ next: { toolEquivalent: input.toolCommand },
3606
+ render: {
3607
+ sections: [
3608
+ {
3609
+ title: "customer db export",
3610
+ lines: [
3611
+ `Rendered ${input.result.row_count_returned} row(s) as ${input.format} to ${destination}`
3612
+ ]
3613
+ }
3614
+ ],
3615
+ actions: [{ label: "Tool equivalent", command: input.toolCommand }]
3616
+ }
3617
+ };
3618
+ }
3445
3619
  async function handleDbQuery(args) {
3446
3620
  const sqlIndex = args.indexOf("--sql");
3447
3621
  const sql = sqlIndex >= 0 ? args[sqlIndex + 1]?.trim() : "";
3448
3622
  if (!sql) {
3449
- console.error('Usage: deepline db query --sql "select * from table limit 20" [--max-rows N] [--json]');
3623
+ console.error(
3624
+ 'Usage: deepline db query --sql "select * from table limit 20" [--max-rows N] [--json]'
3625
+ );
3450
3626
  return 1;
3451
3627
  }
3452
3628
  const maxRowsIndex = args.indexOf("--max-rows");
3453
3629
  const maxRows = maxRowsIndex >= 0 && args[maxRowsIndex + 1] ? parsePositiveInteger(args[maxRowsIndex + 1], "--max-rows") : void 0;
3630
+ const formatIndex = args.indexOf("--format");
3631
+ const format = formatIndex >= 0 ? args[formatIndex + 1]?.trim().toLowerCase() : "";
3632
+ if (format && !CUSTOMER_DB_QUERY_FORMATS.has(format)) {
3633
+ console.error(
3634
+ 'Usage: deepline db query --sql "select * from table limit 20" [--format table|json|csv|markdown] [--out path]'
3635
+ );
3636
+ return 1;
3637
+ }
3638
+ const outIndex = args.indexOf("--out");
3639
+ const outPath = outIndex >= 0 ? args[outIndex + 1]?.trim() : "";
3640
+ if (outIndex >= 0 && !outPath) {
3641
+ console.error("--out requires a path.");
3642
+ return 1;
3643
+ }
3454
3644
  const jsonOutput = argsWantJson(args);
3645
+ const explicitJsonOutput = args.includes("--json");
3455
3646
  const client = new DeeplineClient();
3456
3647
  const result = await client.queryCustomerDb({ sql, maxRows });
3457
3648
  const toolCommand = `deepline tools execute query_customer_db --payload ${JSON.stringify({
3458
3649
  sql,
3459
3650
  ...maxRows ? { max_rows: maxRows } : {}
3460
3651
  })} --json`;
3652
+ if (format === "csv") {
3653
+ if (outPath) {
3654
+ const exportedPath = writeCustomerDbCsv(result, outPath);
3655
+ printCommandEnvelope(
3656
+ dbQueryExportEnvelope({
3657
+ result,
3658
+ format,
3659
+ outPath: exportedPath,
3660
+ toolCommand
3661
+ }),
3662
+ {
3663
+ json: jsonOutput,
3664
+ text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
3665
+ `
3666
+ }
3667
+ );
3668
+ return 0;
3669
+ }
3670
+ printCommandEnvelope(
3671
+ dbQueryExportEnvelope({
3672
+ result,
3673
+ format,
3674
+ outPath: null,
3675
+ toolCommand
3676
+ }),
3677
+ {
3678
+ json: explicitJsonOutput,
3679
+ text: dataExportCsvString(customerDbRows(result), customerDbColumnNames(result))
3680
+ }
3681
+ );
3682
+ return 0;
3683
+ }
3684
+ if (format === "markdown") {
3685
+ const content = markdownTableFromRows(
3686
+ customerDbRows(result),
3687
+ customerDbColumnNames(result)
3688
+ );
3689
+ if (outPath) {
3690
+ const exportedPath = (0, import_node_path6.resolve)(outPath);
3691
+ (0, import_node_fs5.writeFileSync)(exportedPath, content, "utf-8");
3692
+ printCommandEnvelope(
3693
+ dbQueryExportEnvelope({
3694
+ result,
3695
+ format,
3696
+ outPath: exportedPath,
3697
+ toolCommand
3698
+ }),
3699
+ {
3700
+ json: jsonOutput,
3701
+ text: `Exported ${result.row_count_returned} row(s) to ${exportedPath}
3702
+ `
3703
+ }
3704
+ );
3705
+ return 0;
3706
+ }
3707
+ printCommandEnvelope(
3708
+ dbQueryExportEnvelope({
3709
+ result,
3710
+ format,
3711
+ outPath: null,
3712
+ toolCommand
3713
+ }),
3714
+ {
3715
+ json: explicitJsonOutput,
3716
+ text: content
3717
+ }
3718
+ );
3719
+ return 0;
3720
+ }
3461
3721
  printCommandEnvelope({
3462
3722
  ...result,
3463
3723
  next: { toolEquivalent: toolCommand },
@@ -3465,7 +3725,7 @@ async function handleDbQuery(args) {
3465
3725
  sections: [{ title: "customer db query", lines: tableLines(result) }],
3466
3726
  actions: [{ label: "Tool equivalent", command: toolCommand }]
3467
3727
  }
3468
- }, { json: jsonOutput });
3728
+ }, { json: jsonOutput || format === "json" });
3469
3729
  return 0;
3470
3730
  }
3471
3731
  function registerDbCommands(program) {
@@ -3475,11 +3735,14 @@ function registerDbCommands(program) {
3475
3735
  Notes:
3476
3736
  Runs SQL against the active workspace customer database through Deepline APIs.
3477
3737
  Results are bounded by the server and --max-rows. Use --json for stable output.
3738
+ Use --format csv or --format markdown for agent-readable exports and display tables.
3478
3739
 
3479
3740
  Examples:
3480
3741
  deepline db query --sql "select * from companies limit 20"
3481
3742
  deepline db query --sql "select domain, name from companies limit 20" --json
3482
3743
  deepline db query --sql "select * from contacts" --max-rows 100 --json
3744
+ deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
3745
+ deepline db query --sql "select domain, name from companies limit 20" --format markdown
3483
3746
  `
3484
3747
  );
3485
3748
  db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
@@ -3488,17 +3751,23 @@ Examples:
3488
3751
  Notes:
3489
3752
  Requires --sql. Output is a compact table in a terminal and raw JSON with
3490
3753
  --json or when stdout is piped. The active auth workspace determines scope.
3754
+ --format csv and --format markdown are explicit data/display formats and can
3755
+ be written directly with --out.
3491
3756
 
3492
3757
  Examples:
3493
3758
  deepline db query --sql "select * from companies limit 20"
3494
3759
  deepline db query --sql "select domain, name from companies limit 20" --json
3495
3760
  deepline db psql --sql "select count(*) from contacts" --json
3761
+ deepline db query --sql "select * from contacts limit 20" --format csv --out contacts.csv
3762
+ deepline db query --sql "select domain, name from companies limit 20" --format markdown
3496
3763
  `
3497
- ).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
3764
+ ).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--format <format>", "Output format: table, json, csv, or markdown").option("--out <path>", "Write csv or markdown output to a file").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
3498
3765
  process.exitCode = await handleDbQuery([
3499
3766
  "--sql",
3500
3767
  options.sql,
3501
3768
  ...options.maxRows ? ["--max-rows", options.maxRows] : [],
3769
+ ...options.format ? ["--format", options.format] : [],
3770
+ ...options.out ? ["--out", options.out] : [],
3502
3771
  ...options.json ? ["--json"] : []
3503
3772
  ]);
3504
3773
  });
@@ -3674,21 +3943,21 @@ Examples:
3674
3943
 
3675
3944
  // src/cli/commands/play.ts
3676
3945
  var import_node_crypto3 = require("crypto");
3677
- var import_node_fs7 = require("fs");
3678
- var import_node_path9 = require("path");
3946
+ var import_node_fs8 = require("fs");
3947
+ var import_node_path10 = require("path");
3679
3948
 
3680
3949
  // src/plays/bundle-play-file.ts
3681
3950
  var import_node_os5 = require("os");
3682
- var import_node_path8 = require("path");
3951
+ var import_node_path9 = require("path");
3683
3952
  var import_node_url = require("url");
3684
- var import_node_fs6 = require("fs");
3953
+ var import_node_fs7 = require("fs");
3685
3954
 
3686
3955
  // ../shared_libs/plays/bundling/index.ts
3687
3956
  var import_node_crypto = require("crypto");
3688
- var import_node_fs5 = require("fs");
3957
+ var import_node_fs6 = require("fs");
3689
3958
  var import_promises3 = require("fs/promises");
3690
3959
  var import_node_os4 = require("os");
3691
- var import_node_path6 = require("path");
3960
+ var import_node_path7 = require("path");
3692
3961
  var import_node_module = require("module");
3693
3962
  var import_esbuild = require("esbuild");
3694
3963
 
@@ -3747,7 +4016,7 @@ function buildPlayContractCompatibility(input) {
3747
4016
  var PLAY_BUNDLE_CACHE_VERSION = 24;
3748
4017
  var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
3749
4018
  var MAX_ESM_WORKERS_BUNDLE_BYTES = 115e4;
3750
- var PLAY_ARTIFACT_CACHE_DIR = (0, import_node_path6.join)(
4019
+ var PLAY_ARTIFACT_CACHE_DIR = (0, import_node_path7.join)(
3751
4020
  (0, import_node_os4.tmpdir)(),
3752
4021
  `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION}`
3753
4022
  );
@@ -3780,13 +4049,13 @@ async function normalizeLocalPath(filePath) {
3780
4049
  try {
3781
4050
  return await (0, import_promises3.realpath)(filePath);
3782
4051
  } catch {
3783
- return (0, import_node_path6.resolve)(filePath);
4052
+ return (0, import_node_path7.resolve)(filePath);
3784
4053
  }
3785
4054
  }
3786
4055
  function createPlayWorkspace(entryFile) {
3787
4056
  return {
3788
4057
  entryFile,
3789
- rootDir: (0, import_node_path6.dirname)(entryFile)
4058
+ rootDir: (0, import_node_path7.dirname)(entryFile)
3790
4059
  };
3791
4060
  }
3792
4061
  function isPathInsideDirectory(filePath, directory) {
@@ -3939,7 +4208,7 @@ function extractDefinedPlayName(sourceCode) {
3939
4208
  }
3940
4209
  function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
3941
4210
  try {
3942
- const packageJson = JSON.parse((0, import_node_fs5.readFileSync)(packageJsonPath, "utf-8"));
4211
+ const packageJson = JSON.parse((0, import_node_fs6.readFileSync)(packageJsonPath, "utf-8"));
3943
4212
  if (packageJson.name === packageName && typeof packageJson.version === "string") {
3944
4213
  return packageJson.version;
3945
4214
  }
@@ -3949,18 +4218,18 @@ function readPackageVersionFromPackageJson(packageJsonPath, packageName) {
3949
4218
  return null;
3950
4219
  }
3951
4220
  function findPackageJsonPathFrom(startDir, packageName) {
3952
- let current = (0, import_node_path6.resolve)(startDir);
4221
+ let current = (0, import_node_path7.resolve)(startDir);
3953
4222
  while (true) {
3954
- const packageJsonPath = (0, import_node_path6.join)(
4223
+ const packageJsonPath = (0, import_node_path7.join)(
3955
4224
  current,
3956
4225
  "node_modules",
3957
4226
  packageName,
3958
4227
  "package.json"
3959
4228
  );
3960
- if ((0, import_node_fs5.existsSync)(packageJsonPath)) {
4229
+ if ((0, import_node_fs6.existsSync)(packageJsonPath)) {
3961
4230
  return packageJsonPath;
3962
4231
  }
3963
- const parent = (0, import_node_path6.dirname)(current);
4232
+ const parent = (0, import_node_path7.dirname)(current);
3964
4233
  if (parent === current) {
3965
4234
  return null;
3966
4235
  }
@@ -3969,29 +4238,29 @@ function findPackageJsonPathFrom(startDir, packageName) {
3969
4238
  }
3970
4239
  function findPackageJsonPath(packageName, fromFile, adapter) {
3971
4240
  const startDirs = [
3972
- (0, import_node_path6.dirname)(fromFile),
4241
+ (0, import_node_path7.dirname)(fromFile),
3973
4242
  adapter.projectRoot,
3974
- (0, import_node_path6.dirname)(adapter.sdkPackageJson),
4243
+ (0, import_node_path7.dirname)(adapter.sdkPackageJson),
3975
4244
  process.cwd()
3976
4245
  ];
3977
4246
  const seen = /* @__PURE__ */ new Set();
3978
4247
  for (const startDir of startDirs) {
3979
- const normalized = (0, import_node_path6.resolve)(startDir);
4248
+ const normalized = (0, import_node_path7.resolve)(startDir);
3980
4249
  if (seen.has(normalized)) continue;
3981
4250
  seen.add(normalized);
3982
4251
  const packageJsonPath = findPackageJsonPathFrom(normalized, packageName);
3983
4252
  if (packageJsonPath) return packageJsonPath;
3984
4253
  }
3985
- const adapterNodeModulesPackageJson = (0, import_node_path6.join)(
4254
+ const adapterNodeModulesPackageJson = (0, import_node_path7.join)(
3986
4255
  adapter.nodeModulesDir,
3987
4256
  packageName,
3988
4257
  "package.json"
3989
4258
  );
3990
- return (0, import_node_fs5.existsSync)(adapterNodeModulesPackageJson) ? adapterNodeModulesPackageJson : null;
4259
+ return (0, import_node_fs6.existsSync)(adapterNodeModulesPackageJson) ? adapterNodeModulesPackageJson : null;
3991
4260
  }
3992
4261
  function localSdkAliasPlugin(adapter, options) {
3993
4262
  const entryFile = options?.workersRuntime ? adapter.sdkWorkersEntryFile : adapter.sdkEntryFile;
3994
- if (!(0, import_node_fs5.existsSync)(entryFile)) {
4263
+ if (!(0, import_node_fs6.existsSync)(entryFile)) {
3995
4264
  return null;
3996
4265
  }
3997
4266
  return {
@@ -4031,7 +4300,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
4031
4300
  contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
4032
4301
  `,
4033
4302
  loader: "ts",
4034
- resolveDir: (0, import_node_path6.dirname)(playFilePath)
4303
+ resolveDir: (0, import_node_path7.dirname)(playFilePath)
4035
4304
  })
4036
4305
  );
4037
4306
  }
@@ -4195,7 +4464,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
4195
4464
  return {
4196
4465
  contents: buildImportedPlayProxyModule(dependency.playName),
4197
4466
  loader: "ts",
4198
- resolveDir: (0, import_node_path6.dirname)(args.path)
4467
+ resolveDir: (0, import_node_path7.dirname)(args.path)
4199
4468
  };
4200
4469
  });
4201
4470
  }
@@ -4213,12 +4482,12 @@ async function resolveLocalImport(fromFile, specifier) {
4213
4482
  if (specifier.startsWith("file:")) {
4214
4483
  return normalizeLocalPath(new URL(specifier).pathname);
4215
4484
  }
4216
- const base = (0, import_node_path6.isAbsolute)(specifier) ? (0, import_node_path6.resolve)(specifier) : (0, import_node_path6.resolve)((0, import_node_path6.dirname)(fromFile), specifier);
4485
+ const base = (0, import_node_path7.isAbsolute)(specifier) ? (0, import_node_path7.resolve)(specifier) : (0, import_node_path7.resolve)((0, import_node_path7.dirname)(fromFile), specifier);
4217
4486
  const candidates = [base];
4218
- const explicitExtension = (0, import_node_path6.extname)(base).toLowerCase();
4487
+ const explicitExtension = (0, import_node_path7.extname)(base).toLowerCase();
4219
4488
  if (!explicitExtension) {
4220
4489
  candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`));
4221
- candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0, import_node_path6.join)(base, `index${extension}`)));
4490
+ candidates.push(...SOURCE_EXTENSIONS.map((extension) => (0, import_node_path7.join)(base, `index${extension}`)));
4222
4491
  } else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
4223
4492
  const stem = base.slice(0, -explicitExtension.length);
4224
4493
  candidates.push(...SOURCE_EXTENSIONS.map((extension) => `${stem}${extension}`));
@@ -4232,9 +4501,9 @@ async function resolveLocalImport(fromFile, specifier) {
4232
4501
  }
4233
4502
  function resolvePackageImport(specifier, fromFile, adapter) {
4234
4503
  const packageName = getPackageName(specifier);
4235
- if (packageName === "deepline" && (0, import_node_fs5.existsSync)(adapter.sdkPackageJson)) {
4504
+ if (packageName === "deepline" && (0, import_node_fs6.existsSync)(adapter.sdkPackageJson)) {
4236
4505
  const packageJson = JSON.parse(
4237
- (0, import_node_fs5.readFileSync)(adapter.sdkPackageJson, "utf-8")
4506
+ (0, import_node_fs6.readFileSync)(adapter.sdkPackageJson, "utf-8")
4238
4507
  );
4239
4508
  return {
4240
4509
  name: "deepline",
@@ -4266,7 +4535,7 @@ async function analyzeSourceGraph(entryFile, adapter) {
4266
4535
  visited.add(absolutePath);
4267
4536
  const sourceCode2 = await (0, import_promises3.readFile)(absolutePath, "utf-8");
4268
4537
  localFiles.set(absolutePath, sourceCode2);
4269
- if ((0, import_node_path6.extname)(absolutePath).toLowerCase() === ".json") {
4538
+ if ((0, import_node_path7.extname)(absolutePath).toLowerCase() === ".json") {
4270
4539
  return;
4271
4540
  }
4272
4541
  const handleSpecifier = async (specifier, line, column, kind) => {
@@ -4370,13 +4639,13 @@ async function computeWorkersHarnessFingerprintWithAdapter(adapter) {
4370
4639
  const tsFiles = entries.filter((e) => e.isFile() && /\.[cm]?ts$/.test(e.name)).map((e) => e.name).sort();
4371
4640
  const parts = [];
4372
4641
  for (const name of tsFiles) {
4373
- const contents = await (0, import_promises3.readFile)((0, import_node_path6.join)(adapter.workersHarnessFilesDir, name), "utf-8");
4642
+ const contents = await (0, import_promises3.readFile)((0, import_node_path7.join)(adapter.workersHarnessFilesDir, name), "utf-8");
4374
4643
  parts.push({ name, hash: sha256(contents) });
4375
4644
  }
4376
4645
  return sha256(JSON.stringify(parts));
4377
4646
  }
4378
4647
  function artifactCachePath(graphHash, artifactKind, adapter) {
4379
- return (0, import_node_path6.join)(
4648
+ return (0, import_node_path7.join)(
4380
4649
  adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
4381
4650
  `${graphHash}.${artifactKind}.json`
4382
4651
  );
@@ -4411,7 +4680,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
4411
4680
  if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
4412
4681
  return sourcePath;
4413
4682
  }
4414
- return (0, import_node_path6.resolve)(process.cwd(), sourcePath);
4683
+ return (0, import_node_path7.resolve)(process.cwd(), sourcePath);
4415
4684
  });
4416
4685
  parsed.sourceRoot = void 0;
4417
4686
  return JSON.stringify(parsed);
@@ -4443,8 +4712,8 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
4443
4712
  ...namedExportShim ? {
4444
4713
  stdin: {
4445
4714
  contents: namedExportShim,
4446
- resolveDir: (0, import_node_path6.dirname)(entryFile),
4447
- sourcefile: `${(0, import_node_path6.basename)(entryFile)}.${exportName}.entry.ts`,
4715
+ resolveDir: (0, import_node_path7.dirname)(entryFile),
4716
+ sourcefile: `${(0, import_node_path7.basename)(entryFile)}.${exportName}.entry.ts`,
4448
4717
  loader: "ts"
4449
4718
  }
4450
4719
  } : { entryPoints: [entryFile] },
@@ -4620,10 +4889,10 @@ workers-harness:${harnessFingerprint}`
4620
4889
  }
4621
4890
  const { bundledCode, sourceMapText, outputExtension } = buildOutcome;
4622
4891
  const normalizedSourceMap = normalizeSourceMapForRuntime(sourceMapText);
4623
- const virtualBaseName = exportName === "default" ? (0, import_node_path6.basename)(absolutePath).replace(/\.[^.]+$/, "") : `${(0, import_node_path6.basename)(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
4892
+ const virtualBaseName = exportName === "default" ? (0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "") : `${(0, import_node_path7.basename)(absolutePath).replace(/\.[^.]+$/, "")}.${exportName}`;
4624
4893
  const virtualFilename = `/virtual/deepline-plays/${analysis.graphHash}/${virtualBaseName}.${outputExtension}`;
4625
4894
  const executableCode = `${bundledCode}
4626
- //# sourceMappingURL=${(0, import_node_path6.basename)(virtualFilename)}.map
4895
+ //# sourceMappingURL=${(0, import_node_path7.basename)(virtualFilename)}.map
4627
4896
  `;
4628
4897
  const bundleSizeError = getBundleSizeError(
4629
4898
  absolutePath,
@@ -4733,13 +5002,13 @@ function resolveExecutionProfile(override) {
4733
5002
  // src/plays/local-file-discovery.ts
4734
5003
  var import_node_crypto2 = require("crypto");
4735
5004
  var import_promises4 = require("fs/promises");
4736
- var import_node_path7 = require("path");
5005
+ var import_node_path8 = require("path");
4737
5006
  var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
4738
5007
  function sha2562(buffer) {
4739
5008
  return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
4740
5009
  }
4741
5010
  function contentTypeForFile(filePath) {
4742
- const extension = (0, import_node_path7.extname)(filePath).toLowerCase();
5011
+ const extension = (0, import_node_path8.extname)(filePath).toLowerCase();
4743
5012
  if (extension === ".csv") return "text/csv";
4744
5013
  if (extension === ".json") return "application/json";
4745
5014
  if (extension === ".txt") return "text/plain";
@@ -4930,16 +5199,16 @@ async function fileExists2(filePath) {
4930
5199
  }
4931
5200
  }
4932
5201
  function isPathInsideDirectory2(filePath, directory) {
4933
- const relativePath = (0, import_node_path7.relative)(directory, filePath);
4934
- return relativePath === "" || !relativePath.startsWith("..") && !(0, import_node_path7.isAbsolute)(relativePath);
5202
+ const relativePath = (0, import_node_path8.relative)(directory, filePath);
5203
+ return relativePath === "" || !relativePath.startsWith("..") && !(0, import_node_path8.isAbsolute)(relativePath);
4935
5204
  }
4936
5205
  async function resolveLocalImport2(fromFile, specifier) {
4937
- const base = (0, import_node_path7.isAbsolute)(specifier) ? (0, import_node_path7.resolve)(specifier) : (0, import_node_path7.resolve)((0, import_node_path7.dirname)(fromFile), specifier);
5206
+ const base = (0, import_node_path8.isAbsolute)(specifier) ? (0, import_node_path8.resolve)(specifier) : (0, import_node_path8.resolve)((0, import_node_path8.dirname)(fromFile), specifier);
4938
5207
  const candidates = [base];
4939
- const explicitExtension = (0, import_node_path7.extname)(base).toLowerCase();
5208
+ const explicitExtension = (0, import_node_path8.extname)(base).toLowerCase();
4940
5209
  if (!explicitExtension) {
4941
5210
  candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${base}${extension}`));
4942
- candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0, import_node_path7.join)(base, `index${extension}`)));
5211
+ candidates.push(...SOURCE_EXTENSIONS2.map((extension) => (0, import_node_path8.join)(base, `index${extension}`)));
4943
5212
  } else if ([".js", ".jsx", ".mjs", ".cjs"].includes(explicitExtension)) {
4944
5213
  const stem = base.slice(0, -explicitExtension.length);
4945
5214
  candidates.push(...SOURCE_EXTENSIONS2.map((extension) => `${stem}${extension}`));
@@ -4952,13 +5221,13 @@ async function resolveLocalImport2(fromFile, specifier) {
4952
5221
  throw new Error(`Could not resolve local import "${specifier}" from ${fromFile}`);
4953
5222
  }
4954
5223
  async function discoverPackagedLocalFiles(entryFile) {
4955
- const absoluteEntryFile = (0, import_node_path7.resolve)(entryFile);
4956
- const packagingRoot = (0, import_node_path7.dirname)(absoluteEntryFile);
5224
+ const absoluteEntryFile = (0, import_node_path8.resolve)(entryFile);
5225
+ const packagingRoot = (0, import_node_path8.dirname)(absoluteEntryFile);
4957
5226
  const files = /* @__PURE__ */ new Map();
4958
5227
  const unresolved = [];
4959
5228
  const visitedFiles = /* @__PURE__ */ new Set();
4960
5229
  const visitSourceFile = async (filePath) => {
4961
- const absolutePath = (0, import_node_path7.resolve)(filePath);
5230
+ const absolutePath = (0, import_node_path8.resolve)(filePath);
4962
5231
  if (visitedFiles.has(absolutePath)) {
4963
5232
  return;
4964
5233
  }
@@ -4990,8 +5259,8 @@ async function discoverPackagedLocalFiles(entryFile) {
4990
5259
  message: "Could not resolve this ctx.csv(...) path at submit time. Use a string literal, a top-level const string, or pass a runtime input like input.file."
4991
5260
  });
4992
5261
  } else {
4993
- const absoluteCsvPath = (0, import_node_path7.resolve)((0, import_node_path7.dirname)(absolutePath), resolvedPath);
4994
- if ((0, import_node_path7.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
5262
+ const absoluteCsvPath = (0, import_node_path8.resolve)((0, import_node_path8.dirname)(absolutePath), resolvedPath);
5263
+ if ((0, import_node_path8.isAbsolute)(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
4995
5264
  unresolved.push({
4996
5265
  sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
4997
5266
  message: "ctx.csv(...) packaged file paths must be relative paths inside the play directory. Pass external files at runtime with input.file instead."
@@ -5030,24 +5299,24 @@ async function discoverPackagedLocalFiles(entryFile) {
5030
5299
  // src/plays/bundle-play-file.ts
5031
5300
  var import_meta = {};
5032
5301
  var PLAY_BUNDLE_CACHE_VERSION2 = 30;
5033
- var MODULE_DIR = (0, import_node_path8.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
5034
- var SDK_PACKAGE_ROOT = (0, import_node_path8.resolve)(MODULE_DIR, "..", "..");
5035
- var SOURCE_REPO_ROOT = (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "..");
5036
- var HAS_SOURCE_BUNDLING_SOURCES = (0, import_node_fs6.existsSync)(
5037
- (0, import_node_path8.resolve)(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
5302
+ var MODULE_DIR = (0, import_node_path9.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
5303
+ var SDK_PACKAGE_ROOT = (0, import_node_path9.resolve)(MODULE_DIR, "..", "..");
5304
+ var SOURCE_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
5305
+ var HAS_SOURCE_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
5306
+ (0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
5038
5307
  );
5039
- var PACKAGED_REPO_ROOT = (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "dist", "repo");
5040
- var HAS_PACKAGED_BUNDLING_SOURCES = (0, import_node_fs6.existsSync)(
5041
- (0, import_node_path8.resolve)(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
5308
+ var PACKAGED_REPO_ROOT = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "repo");
5309
+ var HAS_PACKAGED_BUNDLING_SOURCES = (0, import_node_fs7.existsSync)(
5310
+ (0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
5042
5311
  );
5043
- var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "..");
5044
- var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0, import_node_path8.resolve)(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? (0, import_node_path8.resolve)(PACKAGED_REPO_ROOT, "sdk", "src") : (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "src");
5045
- var SDK_PACKAGE_JSON = (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "package.json");
5046
- var SDK_ENTRY_FILE = (0, import_node_path8.resolve)(SDK_SOURCE_ROOT, "index.ts");
5047
- var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0, import_node_path8.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
5048
- var SDK_WORKERS_ENTRY_FILE = (0, import_node_path8.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
5049
- var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path8.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
5050
- var WORKERS_HARNESS_FILES_DIR = (0, import_node_path8.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
5312
+ var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "..");
5313
+ var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? (0, import_node_path9.resolve)(PACKAGED_REPO_ROOT, "sdk", "src") : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "src");
5314
+ var SDK_PACKAGE_JSON = (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "package.json");
5315
+ var SDK_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "index.ts");
5316
+ var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : (0, import_node_path9.resolve)(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
5317
+ var SDK_WORKERS_ENTRY_FILE = (0, import_node_path9.resolve)(SDK_SOURCE_ROOT, "worker-play-entry.ts");
5318
+ var WORKERS_HARNESS_ENTRY_FILE = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
5319
+ var WORKERS_HARNESS_FILES_DIR = (0, import_node_path9.resolve)(PROJECT_ROOT, "apps", "play-runner-workers", "src");
5051
5320
  var hasWarnedAboutNonDevelopmentBundling = false;
5052
5321
  function warnAboutNonDevelopmentBundling(filePath) {
5053
5322
  if (hasWarnedAboutNonDevelopmentBundling) {
@@ -5071,12 +5340,12 @@ function defaultPlayBundleTarget() {
5071
5340
  function createSdkPlayBundlingAdapter() {
5072
5341
  return {
5073
5342
  projectRoot: PROJECT_ROOT,
5074
- nodeModulesDir: (0, import_node_path8.resolve)(PROJECT_ROOT, "node_modules"),
5075
- cacheDir: (0, import_node_path8.join)((0, import_node_os5.tmpdir)(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
5343
+ nodeModulesDir: (0, import_node_path9.resolve)(PROJECT_ROOT, "node_modules"),
5344
+ cacheDir: (0, import_node_path9.join)((0, import_node_os5.tmpdir)(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
5076
5345
  sdkSourceRoot: SDK_SOURCE_ROOT,
5077
5346
  sdkPackageJson: SDK_PACKAGE_JSON,
5078
5347
  sdkEntryFile: SDK_ENTRY_FILE,
5079
- sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs6.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
5348
+ sdkTypesEntryFile: HAS_SOURCE_BUNDLING_SOURCES || !(0, import_node_fs7.existsSync)(SDK_TYPES_ENTRY_FILE) ? SDK_ENTRY_FILE : SDK_TYPES_ENTRY_FILE,
5080
5349
  sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
5081
5350
  workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
5082
5351
  workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
@@ -5309,7 +5578,7 @@ function traceCliSync(phase, fields, run) {
5309
5578
  }
5310
5579
  }
5311
5580
  function sleep4(ms) {
5312
- return new Promise((resolve10) => setTimeout(resolve10, ms));
5581
+ return new Promise((resolve11) => setTimeout(resolve11, ms));
5313
5582
  }
5314
5583
  function parseReferencedPlayTarget(target) {
5315
5584
  const trimmed = target.trim();
@@ -5355,7 +5624,7 @@ function formatPlayListReference(play) {
5355
5624
  function defaultMaterializedPlayPath(reference) {
5356
5625
  const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
5357
5626
  const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
5358
- return (0, import_node_path9.resolve)(`${safeName || "play"}.play.ts`);
5627
+ return (0, import_node_path10.resolve)(`${safeName || "play"}.play.ts`);
5359
5628
  }
5360
5629
  function materializeRemotePlaySource(input) {
5361
5630
  if (isFileTarget(input.target)) {
@@ -5365,15 +5634,15 @@ function materializeRemotePlaySource(input) {
5365
5634
  return null;
5366
5635
  }
5367
5636
  const outputPath = input.outPath ?? defaultMaterializedPlayPath(input.playName);
5368
- if ((0, import_node_fs7.existsSync)(outputPath)) {
5369
- const existingSource = (0, import_node_fs7.readFileSync)(outputPath, "utf-8");
5637
+ if ((0, import_node_fs8.existsSync)(outputPath)) {
5638
+ const existingSource = (0, import_node_fs8.readFileSync)(outputPath, "utf-8");
5370
5639
  if (existingSource === input.sourceCode) {
5371
5640
  return { path: outputPath, status: "unchanged", created: false };
5372
5641
  }
5373
- (0, import_node_fs7.writeFileSync)(outputPath, input.sourceCode, "utf-8");
5642
+ (0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
5374
5643
  return { path: outputPath, status: "updated", created: false };
5375
5644
  }
5376
- (0, import_node_fs7.writeFileSync)(outputPath, input.sourceCode, "utf-8");
5645
+ (0, import_node_fs8.writeFileSync)(outputPath, input.sourceCode, "utf-8");
5377
5646
  return { path: outputPath, status: "created", created: true };
5378
5647
  }
5379
5648
  function formatLoadedPlayMessage(materializedFile) {
@@ -5418,7 +5687,7 @@ function extractPlayName(code, filePath) {
5418
5687
  throw buildMissingDefinePlayError(filePath);
5419
5688
  }
5420
5689
  function isFileTarget(target) {
5421
- return (0, import_node_fs7.existsSync)((0, import_node_path9.resolve)(target));
5690
+ return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(target));
5422
5691
  }
5423
5692
  function looksLikeFilePath(target) {
5424
5693
  if (target.trim().toLowerCase().startsWith("prebuilt/")) {
@@ -5437,7 +5706,7 @@ function parsePositiveInteger2(value, flagName) {
5437
5706
  return parsed;
5438
5707
  }
5439
5708
  function parseJsonInput(raw) {
5440
- const source = raw.startsWith("@") ? (0, import_node_fs7.readFileSync)((0, import_node_path9.resolve)(raw.slice(1)), "utf-8") : raw;
5709
+ const source = raw.startsWith("@") ? (0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(raw.slice(1)), "utf-8") : raw;
5441
5710
  const parsed = JSON.parse(source);
5442
5711
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5443
5712
  throw new Error("--input must be a JSON object.");
@@ -5538,7 +5807,7 @@ function fileInputBindingsFromStaticPipeline(staticPipeline) {
5538
5807
  function isLocalFilePathValue(value) {
5539
5808
  if (typeof value !== "string" || !value.trim()) return false;
5540
5809
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
5541
- return (0, import_node_fs7.existsSync)((0, import_node_path9.resolve)(value));
5810
+ return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(value));
5542
5811
  }
5543
5812
  function inputContainsLocalFilePath(value) {
5544
5813
  if (isLocalFilePathValue(value)) {
@@ -5564,8 +5833,8 @@ async function stageFileInputArgs(input) {
5564
5833
  const localFiles = uniqueBindings.flatMap((binding) => {
5565
5834
  const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
5566
5835
  if (!isLocalFilePathValue(value)) return [];
5567
- const absolutePath = (0, import_node_path9.resolve)(value);
5568
- return [{ binding, absolutePath, logicalPath: (0, import_node_path9.basename)(absolutePath) }];
5836
+ const absolutePath = (0, import_node_path10.resolve)(value);
5837
+ return [{ binding, absolutePath, logicalPath: (0, import_node_path10.basename)(absolutePath) }];
5569
5838
  });
5570
5839
  if (localFiles.length === 0) {
5571
5840
  return { inputFile: null, packagedFiles: [] };
@@ -5589,7 +5858,7 @@ async function stageFileInputArgs(input) {
5589
5858
  };
5590
5859
  }
5591
5860
  function stageFile(logicalPath, absolutePath) {
5592
- const buffer = (0, import_node_fs7.readFileSync)(absolutePath);
5861
+ const buffer = (0, import_node_fs8.readFileSync)(absolutePath);
5593
5862
  return {
5594
5863
  logicalPath,
5595
5864
  contentBase64: buffer.toString("base64"),
@@ -5600,9 +5869,9 @@ function stageFile(logicalPath, absolutePath) {
5600
5869
  }
5601
5870
  function normalizePlayPath(filePath) {
5602
5871
  try {
5603
- return import_node_fs7.realpathSync.native((0, import_node_path9.resolve)(filePath));
5872
+ return import_node_fs8.realpathSync.native((0, import_node_path10.resolve)(filePath));
5604
5873
  } catch {
5605
- return (0, import_node_path9.resolve)(filePath);
5874
+ return (0, import_node_path10.resolve)(filePath);
5606
5875
  }
5607
5876
  }
5608
5877
  function formatBundlingErrors(filePath, errors) {
@@ -5755,11 +6024,42 @@ function isTransientPlayStreamError(error) {
5755
6024
  text
5756
6025
  );
5757
6026
  }
6027
+ function playStatusErrorText(status) {
6028
+ const chunks = [];
6029
+ const progressError = status.progress?.error;
6030
+ if (typeof progressError === "string" && progressError.trim()) {
6031
+ chunks.push(progressError.trim());
6032
+ }
6033
+ const errorValue = status.error;
6034
+ if (typeof errorValue === "string" && errorValue.trim()) {
6035
+ chunks.push(errorValue.trim());
6036
+ }
6037
+ const errors = status.errors;
6038
+ if (Array.isArray(errors)) {
6039
+ for (const error of errors) {
6040
+ if (typeof error === "string" && error.trim()) {
6041
+ chunks.push(error.trim());
6042
+ } else if (error && typeof error === "object") {
6043
+ const message = error.message;
6044
+ if (typeof message === "string" && message.trim()) {
6045
+ chunks.push(message.trim());
6046
+ }
6047
+ }
6048
+ }
6049
+ }
6050
+ return chunks.join("; ") || status.status;
6051
+ }
6052
+ function isRetryablePendingStartFailure(status) {
6053
+ if (status.status !== "failed") return false;
6054
+ if (status.runId && status.runId !== "pending") return false;
6055
+ return isTransientPlayStreamError(new Error(playStatusErrorText(status)));
6056
+ }
5758
6057
  var TERMINAL_PLAY_STATUSES2 = /* @__PURE__ */ new Set([
5759
6058
  "completed",
5760
6059
  "failed",
5761
6060
  "cancelled"
5762
6061
  ]);
6062
+ var PLAY_START_TRANSIENT_RETRY_DELAYS_MS = [500, 1500];
5763
6063
  function getEventPayload(event) {
5764
6064
  return event.payload && typeof event.payload === "object" ? event.payload : {};
5765
6065
  }
@@ -5921,6 +6221,34 @@ async function waitForPlayCompletionByStream(input) {
5921
6221
  );
5922
6222
  }
5923
6223
  async function startAndWaitForPlayCompletionByStream(input) {
6224
+ for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
6225
+ const status = await startAndWaitForPlayCompletionByStreamOnce(input);
6226
+ const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
6227
+ if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
6228
+ return status;
6229
+ }
6230
+ if (!input.jsonOutput) {
6231
+ input.progress.writeLine(
6232
+ `[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
6233
+ );
6234
+ }
6235
+ recordCliTrace({
6236
+ phase: "cli.play_start_stream_retry",
6237
+ ms: 0,
6238
+ ok: true,
6239
+ playName: input.playName,
6240
+ attempt: attempt + 1,
6241
+ reason: playStatusErrorText(status)
6242
+ });
6243
+ await sleep4(retryDelayMs);
6244
+ }
6245
+ throw new DeeplineError(
6246
+ `Play ${input.playName} did not start after retrying transient start failures.`,
6247
+ void 0,
6248
+ "PLAY_START_RETRY_EXHAUSTED"
6249
+ );
6250
+ }
6251
+ async function startAndWaitForPlayCompletionByStreamOnce(input) {
5924
6252
  const startedAt = Date.now();
5925
6253
  const dashboardUrl = buildPlayDashboardUrl(
5926
6254
  input.client.baseUrl,
@@ -6247,14 +6575,24 @@ function buildRunWarnings(status, rowsInfo) {
6247
6575
  }
6248
6576
  return [];
6249
6577
  }
6250
- function buildRunNextCommands(runId, dashboardUrl) {
6578
+ function buildRunNextCommands(status) {
6579
+ const runId = status.runId?.trim();
6580
+ if (!runId) {
6581
+ const playName = extractRunPlayName(status);
6582
+ return playName ? {
6583
+ list: `deepline runs list --play ${playName} --json`
6584
+ } : {
6585
+ list: "deepline runs list --json"
6586
+ };
6587
+ }
6251
6588
  const commands = {
6252
6589
  get: `deepline runs get ${runId} --json`,
6590
+ full: `deepline runs get ${runId} --full --json`,
6253
6591
  stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
6254
6592
  logs: `deepline runs logs ${runId} --out run.log --json`
6255
6593
  };
6256
- if (dashboardUrl) {
6257
- commands.open = `Open ${dashboardUrl} to see results.`;
6594
+ if (status.dashboardUrl) {
6595
+ commands.open = `Open ${status.dashboardUrl} to see results.`;
6258
6596
  }
6259
6597
  return commands;
6260
6598
  }
@@ -6277,6 +6615,121 @@ function getTimestampField(value, key) {
6277
6615
  }
6278
6616
  return typeof field === "string" && field.trim() ? field : null;
6279
6617
  }
6618
+ function getObjectField(value, key) {
6619
+ const field = getRecordField(value, key);
6620
+ return field && typeof field === "object" && !Array.isArray(field) ? field : null;
6621
+ }
6622
+ function formatCreditAmount(value) {
6623
+ if (typeof value !== "number" || !Number.isFinite(value)) {
6624
+ return String(value ?? "-");
6625
+ }
6626
+ return Number(value.toFixed(8)).toString();
6627
+ }
6628
+ function extractJsonObjectFromText(text) {
6629
+ const start = text.indexOf("{");
6630
+ if (start < 0) {
6631
+ return null;
6632
+ }
6633
+ const suffix = text.slice(start);
6634
+ try {
6635
+ const parsed = JSON.parse(suffix);
6636
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
6637
+ } catch {
6638
+ let depth = 0;
6639
+ let inString = false;
6640
+ let escaped = false;
6641
+ for (let index = start; index < text.length; index += 1) {
6642
+ const char = text[index];
6643
+ if (inString) {
6644
+ if (escaped) {
6645
+ escaped = false;
6646
+ } else if (char === "\\") {
6647
+ escaped = true;
6648
+ } else if (char === '"') {
6649
+ inString = false;
6650
+ }
6651
+ continue;
6652
+ }
6653
+ if (char === '"') {
6654
+ inString = true;
6655
+ } else if (char === "{") {
6656
+ depth += 1;
6657
+ } else if (char === "}") {
6658
+ depth -= 1;
6659
+ if (depth === 0) {
6660
+ try {
6661
+ const parsed = JSON.parse(text.slice(start, index + 1));
6662
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
6663
+ } catch {
6664
+ return null;
6665
+ }
6666
+ }
6667
+ }
6668
+ }
6669
+ }
6670
+ return null;
6671
+ }
6672
+ function extractBillingFromText(text) {
6673
+ if (!text) {
6674
+ return null;
6675
+ }
6676
+ const parsed = extractJsonObjectFromText(text);
6677
+ return getObjectField(parsed, "billing");
6678
+ }
6679
+ function extractToolIdFromErrorText(text) {
6680
+ if (!text) {
6681
+ return null;
6682
+ }
6683
+ const lowerToolMatch = /\btool\s+([A-Za-z0-9_.:-]+)\s+\d{3}\b/.exec(text);
6684
+ if (lowerToolMatch?.[1]) {
6685
+ return lowerToolMatch[1];
6686
+ }
6687
+ const upperToolMatch = /\bTool\s+([A-Za-z0-9_.:-]+)\s+failed\b/.exec(text);
6688
+ return upperToolMatch?.[1] ?? null;
6689
+ }
6690
+ function isInsufficientCreditsBilling(billing) {
6691
+ return billing?.kind === "insufficient_credits";
6692
+ }
6693
+ function extractBillingForStatus(status, error) {
6694
+ const errorBilling = getObjectField(status, "errorBilling");
6695
+ if (errorBilling) {
6696
+ return errorBilling;
6697
+ }
6698
+ const directErrors = getRecordField(status, "errors");
6699
+ if (Array.isArray(directErrors)) {
6700
+ for (const entry of directErrors) {
6701
+ const billing = getObjectField(entry, "billing");
6702
+ if (billing) {
6703
+ return billing;
6704
+ }
6705
+ }
6706
+ }
6707
+ const progressError = getStringField(status.progress, "error");
6708
+ return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
6709
+ }
6710
+ function formatInsufficientCreditsMessage(input) {
6711
+ const operation = getStringField(input.billing, "operation_id") ?? getStringField(input.billing, "operation") ?? extractToolIdFromErrorText(input.error) ?? getStringField(input.billing, "provider") ?? "tool call";
6712
+ const balance = formatCreditAmount(input.billing.balance_credits);
6713
+ const required = formatCreditAmount(input.billing.required_credits);
6714
+ const recommended = formatCreditAmount(
6715
+ input.billing.recommended_add_credits ?? input.billing.needed_credits
6716
+ );
6717
+ const billingUrl = getStringField(input.billing, "billing_url");
6718
+ const workspace = getStringField(input.billing, "workspace_id") ?? getStringField(input.billing, "workspaceId");
6719
+ const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
6720
+ const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
6721
+ return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
6722
+ }
6723
+ function formatPlayErrorForDisplay(status, error) {
6724
+ if (!error) {
6725
+ return null;
6726
+ }
6727
+ const billing = extractBillingForStatus(status, error);
6728
+ if (isInsufficientCreditsBilling(billing)) {
6729
+ return formatInsufficientCreditsMessage({ billing, error });
6730
+ }
6731
+ return error;
6732
+ }
6280
6733
  function normalizeRunStatusForEnvelope(status) {
6281
6734
  const run = status.run ?? null;
6282
6735
  return {
@@ -6327,18 +6780,33 @@ function normalizeErrorsForEnvelope(status, error) {
6327
6780
  if (Array.isArray(directErrors)) {
6328
6781
  return directErrors.filter(
6329
6782
  (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
6330
- );
6783
+ ).map((entry) => {
6784
+ const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
6785
+ const billing2 = getObjectField(entry, "billing");
6786
+ if (!isInsufficientCreditsBilling(billing2) || !message2) {
6787
+ return entry;
6788
+ }
6789
+ return {
6790
+ ...entry,
6791
+ message: formatInsufficientCreditsMessage({ billing: billing2, error: message2 }),
6792
+ billing: stripProviderSpendFromBilling(billing2)
6793
+ };
6794
+ });
6331
6795
  }
6332
6796
  if (!error) {
6333
6797
  return [];
6334
6798
  }
6799
+ const nextCommands = buildRunNextCommands(status);
6800
+ const billing = extractBillingForStatus(status, error);
6801
+ const message = formatPlayErrorForDisplay(status, error) ?? error;
6335
6802
  return [
6336
6803
  {
6337
6804
  code: getStringField(status, "errorCode") ?? "RUN_FAILED",
6338
6805
  phase: getStringField(status, "errorPhase") ?? "runtime",
6339
- message: error,
6806
+ message,
6340
6807
  retryable: typeof getRecordField(status, "retryable") === "boolean" ? getRecordField(status, "retryable") : null,
6341
- nextAction: `deepline runs get ${status.runId} --json`
6808
+ ...billing ? { billing: stripProviderSpendFromBilling(billing) } : {},
6809
+ nextAction: nextCommands.get ?? nextCommands.list
6342
6810
  }
6343
6811
  ];
6344
6812
  }
@@ -6387,6 +6855,7 @@ function compactPlayStatus(status) {
6387
6855
  ) : null;
6388
6856
  const progressError = status.progress?.error;
6389
6857
  const error = typeof progressError === "string" ? progressError : typeof status.error === "string" ? String(status.error) : null;
6858
+ const displayError = formatPlayErrorForDisplay(status, error);
6390
6859
  return {
6391
6860
  runId: status.runId,
6392
6861
  apiVersion: status.apiVersion ?? 1,
@@ -6399,13 +6868,13 @@ function compactPlayStatus(status) {
6399
6868
  steps: normalizeStepsForEnvelope(status),
6400
6869
  errors: normalizeErrorsForEnvelope(status, error),
6401
6870
  logs: normalizeLogsForEnvelope(status),
6402
- ...error ? { error } : {},
6871
+ ...displayError ? { error: displayError } : {},
6403
6872
  ...warnings.length > 0 ? { warnings } : {},
6404
6873
  ...result !== void 0 ? { result } : {},
6405
6874
  ...status.resultView ? { resultView: status.resultView } : {},
6406
6875
  ...datasetStats ? { dataset_stats: datasetStats } : {},
6407
6876
  ...billing ? { billing } : {},
6408
- next: buildRunNextCommands(status.runId, status.dashboardUrl)
6877
+ next: buildRunNextCommands(status)
6409
6878
  };
6410
6879
  }
6411
6880
  function enrichPlayStatusWithDatasetStats(status) {
@@ -6479,7 +6948,8 @@ function writePlayResult(status, jsonOutput, options) {
6479
6948
  lines.push(...formatDatasetStatsLines(datasetStats));
6480
6949
  const progressError = status.progress?.error;
6481
6950
  if (progressError && typeof progressError === "string") {
6482
- lines.push(` error: ${progressError.slice(0, 200)}`);
6951
+ const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
6952
+ lines.push(` error: ${displayError.slice(0, 200)}`);
6483
6953
  }
6484
6954
  const renderedServerView = renderServerResultView(status.resultView);
6485
6955
  if (result) {
@@ -6503,8 +6973,11 @@ var RUN_EXPORT_PAGE_SIZE = 5e3;
6503
6973
  function shellSingleQuote(value) {
6504
6974
  return `'${value.replace(/'/g, `'\\''`)}'`;
6505
6975
  }
6976
+ function sqlStringLiteral(value) {
6977
+ return `'${value.replace(/'/g, "''")}'`;
6978
+ }
6506
6979
  function runExportRetryCommand(runId, outPath, datasetPath) {
6507
- return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path9.resolve)(outPath))}`;
6980
+ return `deepline runs export ${runId}${datasetPath ? ` --dataset ${shellSingleQuote(datasetPath)}` : ""} --out ${shellSingleQuote((0, import_node_path10.resolve)(outPath))}`;
6508
6981
  }
6509
6982
  function extractRunPlayName(status) {
6510
6983
  const run = status.run;
@@ -6521,6 +6994,26 @@ function extractRunPlayName(status) {
6521
6994
  }
6522
6995
  return null;
6523
6996
  }
6997
+ function normalizeCustomerDbIdentifier(value) {
6998
+ return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
6999
+ }
7000
+ function buildCustomerDbQueryPlan(input) {
7001
+ const playName = extractRunPlayName(input.status);
7002
+ const tableNamespace = input.rowsInfo.tableNamespace?.trim();
7003
+ if (!playName || !tableNamespace || input.rowsInfo.totalRows <= 0) {
7004
+ return null;
7005
+ }
7006
+ const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
7007
+ tableNamespace
7008
+ )}`;
7009
+ const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input.status.runId)} limit ${input.rowsInfo.totalRows}`;
7010
+ const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input.rowsInfo.totalRows}`;
7011
+ return {
7012
+ sql,
7013
+ json: `${base} --json`,
7014
+ csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path10.resolve)(input.outPath))}`
7015
+ };
7016
+ }
6524
7017
  function exportableSheetRow(row) {
6525
7018
  if (!row || typeof row !== "object" || Array.isArray(row)) {
6526
7019
  return null;
@@ -6692,6 +7185,60 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
6692
7185
  }
6693
7186
  return { path: writeCanonicalRowsCsv(rowsInfo, outPath), rowsInfo };
6694
7187
  }
7188
+ function extractActiveRunsFromError(error) {
7189
+ if (!(error instanceof DeeplineError)) {
7190
+ return [];
7191
+ }
7192
+ const response = error.details?.response;
7193
+ if (!response || typeof response !== "object" || Array.isArray(response)) {
7194
+ return [];
7195
+ }
7196
+ const details = response.details;
7197
+ if (!details || typeof details !== "object" || Array.isArray(details)) {
7198
+ return [];
7199
+ }
7200
+ const activeRuns = details.activeRuns;
7201
+ return Array.isArray(activeRuns) ? activeRuns.filter(
7202
+ (run) => Boolean(run) && typeof run === "object" && !Array.isArray(run)
7203
+ ) : [];
7204
+ }
7205
+ function activeRunId(run) {
7206
+ return getStringField(run, "workflowId") ?? getStringField(run, "runId");
7207
+ }
7208
+ function formatActiveRunConflictError(input) {
7209
+ const lines = [
7210
+ `Active run exists for ${input.playName}. Use --force to supersede, or inspect/stop the active run first.`
7211
+ ];
7212
+ for (const run of input.activeRuns.slice(0, 3)) {
7213
+ const runId = activeRunId(run);
7214
+ if (!runId) {
7215
+ continue;
7216
+ }
7217
+ const status = getStringField(run, "status");
7218
+ const startedAt = getStringField(run, "startedAt") ?? getStringField(run, "startTime");
7219
+ lines.push(
7220
+ ` active: ${runId}${status ? ` status=${status}` : ""}${startedAt ? ` startedAt=${startedAt}` : ""}`
7221
+ );
7222
+ lines.push(` get: deepline runs get ${runId} --json`);
7223
+ lines.push(
7224
+ ` stop: deepline runs stop ${runId} --reason "stale lock" --json`
7225
+ );
7226
+ }
7227
+ lines.push(` rerun: add --force to the same deepline plays run command`);
7228
+ return lines.join("\n");
7229
+ }
7230
+ function normalizePlayStartError(error, playName) {
7231
+ const activeRuns = extractActiveRunsFromError(error);
7232
+ if (activeRuns.length === 0) {
7233
+ return error;
7234
+ }
7235
+ return new DeeplineError(
7236
+ formatActiveRunConflictError({ playName, activeRuns }),
7237
+ error instanceof DeeplineError ? error.statusCode : 409,
7238
+ "ACTIVE_RUN_EXISTS",
7239
+ error instanceof DeeplineError ? error.details : void 0
7240
+ );
7241
+ }
6695
7242
  function renderServerResultView(value) {
6696
7243
  if (!value || typeof value !== "object" || Array.isArray(value)) {
6697
7244
  return { lines: [], actions: [] };
@@ -6735,6 +7282,10 @@ function renderServerResultView(value) {
6735
7282
  );
6736
7283
  }
6737
7284
  const tables = Array.isArray(view.tables) ? view.tables : [];
7285
+ const topLevelOutputTable = view.topLevelOutputTable && typeof view.topLevelOutputTable === "object" && !Array.isArray(view.topLevelOutputTable) ? view.topLevelOutputTable : null;
7286
+ if (typeof topLevelOutputTable?.queryCommand === "string") {
7287
+ lines.push(` top-level outputs: ${topLevelOutputTable.queryCommand}`);
7288
+ }
6738
7289
  if (tables.length > 0) {
6739
7290
  lines.push(" tables:");
6740
7291
  for (const table of tables.slice(0, 6)) {
@@ -6751,6 +7302,21 @@ function renderServerResultView(value) {
6751
7302
  lines.push(
6752
7303
  ` ${String(table.tableNamespace ?? "table")}${lineLabel}: ${rowLabel}${details.join(" ")}`
6753
7304
  );
7305
+ if (typeof table.queryDatasetCommand === "string") {
7306
+ lines.push(` inspect rows: ${table.queryDatasetCommand}`);
7307
+ }
7308
+ if (table.debugHelp && typeof table.debugHelp === "object" && !Array.isArray(table.debugHelp)) {
7309
+ const debugHelp = table.debugHelp;
7310
+ const rawResultFields = Array.isArray(debugHelp.rawResultFields) ? debugHelp.rawResultFields.filter(
7311
+ (field) => typeof field === "string"
7312
+ ) : [];
7313
+ if (rawResultFields.length > 0) {
7314
+ lines.push(` tool-result columns: ${rawResultFields.join(", ")}`);
7315
+ }
7316
+ }
7317
+ if (typeof table.slowExportAsCsvCommand === "string") {
7318
+ lines.push(` export rows: ${table.slowExportAsCsvCommand}`);
7319
+ }
6754
7320
  }
6755
7321
  }
6756
7322
  return { lines: lines.length > 1 ? lines : [], actions: [] };
@@ -6776,7 +7342,8 @@ function writeStartedPlayRun(input) {
6776
7342
  ` get status: deepline runs get ${input.runId} --json`,
6777
7343
  ` logs: deepline runs logs ${input.runId} --json`,
6778
7344
  ` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
6779
- ` result JSON: deepline runs get ${input.runId} --json`
7345
+ ` result JSON: deepline runs get ${input.runId} --json`,
7346
+ ` full debug JSON: deepline runs get ${input.runId} --full --json`
6780
7347
  ];
6781
7348
  if (input.dashboardUrl) {
6782
7349
  lines.push(` play page: ${input.dashboardUrl}`);
@@ -6927,12 +7494,12 @@ function shouldUseLocalOnlyPlayCheck() {
6927
7494
  async function handlePlayCheck(args) {
6928
7495
  const options = parsePlayCheckOptions(args);
6929
7496
  if (!isFileTarget(options.target)) {
6930
- const resolved = (0, import_node_path9.resolve)(options.target);
7497
+ const resolved = (0, import_node_path10.resolve)(options.target);
6931
7498
  console.error(`File not found: ${resolved}`);
6932
7499
  return 1;
6933
7500
  }
6934
- const absolutePlayPath = (0, import_node_path9.resolve)(options.target);
6935
- const sourceCode = (0, import_node_fs7.readFileSync)(absolutePlayPath, "utf-8");
7501
+ const absolutePlayPath = (0, import_node_path10.resolve)(options.target);
7502
+ const sourceCode = (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8");
6936
7503
  let graph;
6937
7504
  try {
6938
7505
  graph = await collectBundledPlayGraph(absolutePlayPath);
@@ -6995,12 +7562,12 @@ async function handleFileBackedRun(options) {
6995
7562
  }
6996
7563
  const client = new DeeplineClient();
6997
7564
  const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
6998
- const absolutePlayPath = (0, import_node_path9.resolve)(options.target.path);
7565
+ const absolutePlayPath = (0, import_node_path10.resolve)(options.target.path);
6999
7566
  progress.phase("compiling play");
7000
7567
  const sourceCode = traceCliSync(
7001
7568
  "cli.play_file_read_source",
7002
7569
  { targetKind: "file" },
7003
- () => (0, import_node_fs7.readFileSync)(absolutePlayPath, "utf-8")
7570
+ () => (0, import_node_fs8.readFileSync)(absolutePlayPath, "utf-8")
7004
7571
  );
7005
7572
  const runtimeInput = options.input ? { ...options.input } : {};
7006
7573
  let graph;
@@ -7081,6 +7648,8 @@ async function handleFileBackedRun(options) {
7081
7648
  waitTimeoutMs: options.waitTimeoutMs,
7082
7649
  noOpen: options.noOpen,
7083
7650
  progress
7651
+ }).catch((error) => {
7652
+ throw normalizePlayStartError(error, playName);
7084
7653
  })
7085
7654
  );
7086
7655
  if (finalStatus.status === "completed") {
@@ -7099,7 +7668,9 @@ async function handleFileBackedRun(options) {
7099
7668
  const started = await traceCliSpan(
7100
7669
  "cli.play_start_unwatched",
7101
7670
  { targetKind: "file", playName },
7102
- () => client.startPlayRun(startRequest)
7671
+ () => client.startPlayRun(startRequest).catch((error) => {
7672
+ throw normalizePlayStartError(error, playName);
7673
+ })
7103
7674
  );
7104
7675
  const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
7105
7676
  openPlayDashboard({
@@ -7216,6 +7787,8 @@ async function handleNamedRun(options) {
7216
7787
  waitTimeoutMs: options.waitTimeoutMs,
7217
7788
  noOpen: options.noOpen,
7218
7789
  progress
7790
+ }).catch((error) => {
7791
+ throw normalizePlayStartError(error, playName);
7219
7792
  })
7220
7793
  );
7221
7794
  if (finalStatus.status === "completed") {
@@ -7234,7 +7807,9 @@ async function handleNamedRun(options) {
7234
7807
  const started = await traceCliSpan(
7235
7808
  "cli.play_start_unwatched",
7236
7809
  { targetKind: "name", playName },
7237
- () => client.startPlayRun(startRequest)
7810
+ () => client.startPlayRun(startRequest).catch((error) => {
7811
+ throw normalizePlayStartError(error, playName);
7812
+ })
7238
7813
  );
7239
7814
  const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
7240
7815
  openPlayDashboard({
@@ -7260,19 +7835,19 @@ async function handlePlayRun(args) {
7260
7835
  if (isFileTarget(options.target.path)) {
7261
7836
  return handleFileBackedRun(options);
7262
7837
  }
7263
- const resolved = (0, import_node_path9.resolve)(options.target.path);
7838
+ const resolved = (0, import_node_path10.resolve)(options.target.path);
7264
7839
  console.error(`File not found: ${resolved}`);
7265
- const dir = (0, import_node_path9.dirname)(resolved);
7266
- if ((0, import_node_fs7.existsSync)(dir)) {
7267
- const base = (0, import_node_path9.basename)(resolved);
7840
+ const dir = (0, import_node_path10.dirname)(resolved);
7841
+ if ((0, import_node_fs8.existsSync)(dir)) {
7842
+ const base = (0, import_node_path10.basename)(resolved);
7268
7843
  try {
7269
- const siblings = (0, import_node_fs7.readdirSync)(dir).filter(
7844
+ const siblings = (0, import_node_fs8.readdirSync)(dir).filter(
7270
7845
  (f) => f.includes(base.replace(/\.(play\.)?ts$/, "")) || f.endsWith(".play.ts")
7271
7846
  );
7272
7847
  if (siblings.length > 0) {
7273
7848
  console.error(`Did you mean one of these?`);
7274
7849
  for (const s of siblings.slice(0, 5)) {
7275
- console.error(` ${(0, import_node_path9.join)(dir, s)}`);
7850
+ console.error(` ${(0, import_node_path10.join)(dir, s)}`);
7276
7851
  }
7277
7852
  }
7278
7853
  } catch {
@@ -7407,14 +7982,14 @@ async function handleRunLogs(args) {
7407
7982
  continue;
7408
7983
  }
7409
7984
  if (arg === "--out" && args[index + 1]) {
7410
- outPath = (0, import_node_path9.resolve)(args[++index]);
7985
+ outPath = (0, import_node_path10.resolve)(args[++index]);
7411
7986
  }
7412
7987
  }
7413
7988
  const client = new DeeplineClient();
7414
7989
  const status = await client.runs.get(runId);
7415
7990
  const logs = status.progress?.logs ?? [];
7416
7991
  if (outPath) {
7417
- (0, import_node_fs7.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
7992
+ (0, import_node_fs8.writeFileSync)(outPath, `${logs.join("\n")}${logs.length > 0 ? "\n" : ""}`);
7418
7993
  printCommandEnvelope({
7419
7994
  runId: status.runId,
7420
7995
  log_path: outPath,
@@ -7470,7 +8045,7 @@ async function handleRunStop(args) {
7470
8045
  return 0;
7471
8046
  }
7472
8047
  async function handleRunExport(args) {
7473
- const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--json]";
8048
+ const usage = "Usage: deepline runs export <run-id> [--dataset result.rows] --out output.csv [--metadata-out export.json] [--json]";
7474
8049
  let runId;
7475
8050
  try {
7476
8051
  runId = parseRunIdPositional(args, usage);
@@ -7480,14 +8055,19 @@ async function handleRunExport(args) {
7480
8055
  }
7481
8056
  let outPath = null;
7482
8057
  let datasetPath = null;
8058
+ let metadataOutPath = null;
7483
8059
  for (let index = 0; index < args.length; index += 1) {
7484
8060
  const arg = args[index];
7485
8061
  if (arg === "--out" && args[index + 1]) {
7486
- outPath = (0, import_node_path9.resolve)(args[++index]);
8062
+ outPath = (0, import_node_path10.resolve)(args[++index]);
7487
8063
  continue;
7488
8064
  }
7489
8065
  if (arg === "--dataset" && args[index + 1]) {
7490
8066
  datasetPath = args[++index];
8067
+ continue;
8068
+ }
8069
+ if (arg === "--metadata-out" && args[index + 1]) {
8070
+ metadataOutPath = (0, import_node_path10.resolve)(args[++index]);
7491
8071
  }
7492
8072
  }
7493
8073
  if (!outPath) {
@@ -7499,15 +8079,59 @@ async function handleRunExport(args) {
7499
8079
  const exportResult = await exportPlayStatusRows(client, status, outPath, {
7500
8080
  datasetPath
7501
8081
  });
7502
- printCommandEnvelope({
8082
+ const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
8083
+ const queryPlan = exportResult && outPath ? buildCustomerDbQueryPlan({
8084
+ status,
8085
+ rowsInfo: exportResult.rowsInfo,
8086
+ outPath
8087
+ }) : null;
8088
+ const next = {
8089
+ ...buildRunNextCommands(status),
8090
+ export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source),
8091
+ ...queryPlan ? {
8092
+ queryJson: queryPlan.json,
8093
+ queryCsv: queryPlan.csv
8094
+ } : {}
8095
+ };
8096
+ const payload = {
7503
8097
  runId: status.runId,
7504
8098
  ...datasetPath ? { dataset: datasetPath } : {},
7505
8099
  csv_path: exportResult?.path ?? null,
8100
+ source,
7506
8101
  rowCount: exportResult?.rowsInfo.totalRows ?? null,
7507
8102
  columns: exportResult?.rowsInfo.columns ?? [],
8103
+ ...queryPlan ? {
8104
+ query: {
8105
+ sql: queryPlan.sql,
8106
+ json: queryPlan.json,
8107
+ csv: queryPlan.csv
8108
+ }
8109
+ } : {},
8110
+ ...metadataOutPath ? { metadata_path: metadataOutPath } : {},
7508
8111
  local: { csv_path: exportResult?.path ?? null },
7509
- render: { sections: [{ title: "run export", lines: [`Exported ${status.runId} to ${exportResult?.path ?? outPath}`] }] }
7510
- }, { json: argsWantJson(args) });
8112
+ next,
8113
+ render: {
8114
+ sections: [
8115
+ {
8116
+ title: "run export",
8117
+ lines: [
8118
+ `Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
8119
+ ...source ? [`source=${source}`] : [],
8120
+ ...queryPlan ? [`query=${queryPlan.json}`] : []
8121
+ ]
8122
+ }
8123
+ ]
8124
+ }
8125
+ };
8126
+ if (metadataOutPath) {
8127
+ (0, import_node_fs8.writeFileSync)(
8128
+ metadataOutPath,
8129
+ `${JSON.stringify(payload, null, 2)}
8130
+ `,
8131
+ "utf-8"
8132
+ );
8133
+ }
8134
+ printCommandEnvelope(payload, { json: argsWantJson(args) });
7511
8135
  return 0;
7512
8136
  }
7513
8137
  async function handlePlayGet(args) {
@@ -7524,10 +8148,10 @@ async function handlePlayGet(args) {
7524
8148
  for (let index = 1; index < args.length; index += 1) {
7525
8149
  const arg = args[index];
7526
8150
  if (arg === "--out" && args[index + 1]) {
7527
- outPath = (0, import_node_path9.resolve)(args[++index]);
8151
+ outPath = (0, import_node_path10.resolve)(args[++index]);
7528
8152
  }
7529
8153
  }
7530
- const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs7.readFileSync)((0, import_node_path9.resolve)(target), "utf-8"), (0, import_node_path9.resolve)(target)) : parseReferencedPlayTarget(target).playName;
8154
+ const playName = isFileTarget(target) ? extractPlayName((0, import_node_fs8.readFileSync)((0, import_node_path10.resolve)(target), "utf-8"), (0, import_node_path10.resolve)(target)) : parseReferencedPlayTarget(target).playName;
7531
8155
  const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
7532
8156
  const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
7533
8157
  const materializedFile = outPath ? materializeRemotePlaySource({
@@ -7819,7 +8443,7 @@ async function handlePlayPublish(args) {
7819
8443
  }
7820
8444
  let graph;
7821
8445
  try {
7822
- graph = await collectBundledPlayGraph((0, import_node_path9.resolve)(playName));
8446
+ graph = await collectBundledPlayGraph((0, import_node_path10.resolve)(playName));
7823
8447
  await compileBundledPlayGraphManifests(client, graph);
7824
8448
  await publishImportedPlayDependencies(client, graph);
7825
8449
  } catch (error) {
@@ -8305,32 +8929,36 @@ Examples:
8305
8929
  Notes:
8306
8930
  Writes a returned dataset handle to the requested local CSV path. Use runs get
8307
8931
  first to inspect dataset paths like result.rows or result.nested.contacts.
8932
+ --metadata-out writes the same export metadata object returned by --json,
8933
+ including source and follow-on customer-db query commands when available.
8308
8934
 
8309
8935
  Examples:
8310
8936
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
8311
8937
  deepline runs export play/my-play/run/20260501t000000-000 --dataset result.rows --out output.csv
8938
+ deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --metadata-out output.meta.json
8312
8939
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
8313
8940
  `
8314
- ).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
8941
+ ).requiredOption("--out <path>", "Output CSV path").option("--dataset <path>", "Returned dataset handle path, such as result.rows").option("--metadata-out <path>", "Write export metadata JSON to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
8315
8942
  process.exitCode = await handleRunExport([
8316
8943
  runId,
8317
8944
  ...options.dataset ? ["--dataset", options.dataset] : [],
8318
8945
  "--out",
8319
8946
  options.out,
8947
+ ...options.metadataOut ? ["--metadata-out", options.metadataOut] : [],
8320
8948
  ...options.json ? ["--json"] : []
8321
8949
  ]);
8322
8950
  });
8323
8951
  }
8324
8952
 
8325
8953
  // src/cli/commands/tools.ts
8326
- var import_node_fs9 = require("fs");
8954
+ var import_node_fs10 = require("fs");
8327
8955
  var import_node_os7 = require("os");
8328
- var import_node_path11 = require("path");
8956
+ var import_node_path12 = require("path");
8329
8957
 
8330
8958
  // src/tool-output.ts
8331
- var import_node_fs8 = require("fs");
8959
+ var import_node_fs9 = require("fs");
8332
8960
  var import_node_os6 = require("os");
8333
- var import_node_path10 = require("path");
8961
+ var import_node_path11 = require("path");
8334
8962
  function isPlainObject(value) {
8335
8963
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8336
8964
  }
@@ -8353,6 +8981,21 @@ function normalizeRows(value) {
8353
8981
  }
8354
8982
  function candidateRoots(payload) {
8355
8983
  const roots = [{ path: null, value: payload }];
8984
+ if (isPlainObject(payload) && isPlainObject(payload.toolResponse)) {
8985
+ roots.push({ path: "toolResponse", value: payload.toolResponse });
8986
+ if (Object.prototype.hasOwnProperty.call(payload.toolResponse, "raw")) {
8987
+ roots.push({
8988
+ path: "toolResponse.raw",
8989
+ value: payload.toolResponse.raw
8990
+ });
8991
+ }
8992
+ }
8993
+ if (isPlainObject(payload) && isPlainObject(payload.output)) {
8994
+ roots.push({ path: "output", value: payload.output });
8995
+ if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
8996
+ roots.push({ path: "output.body", value: payload.output.body });
8997
+ }
8998
+ }
8356
8999
  if (isPlainObject(payload) && isPlainObject(payload.result)) {
8357
9000
  roots.push({ path: "result", value: payload.result });
8358
9001
  if (isPlainObject(payload.result.data)) {
@@ -8405,19 +9048,19 @@ function tryConvertToList(payload, options) {
8405
9048
  return null;
8406
9049
  }
8407
9050
  function ensureOutputDir() {
8408
- const outputDir = (0, import_node_path10.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
8409
- (0, import_node_fs8.mkdirSync)(outputDir, { recursive: true });
9051
+ const outputDir = (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share", "deepline", "data");
9052
+ (0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
8410
9053
  return outputDir;
8411
9054
  }
8412
9055
  function writeJsonOutputFile(payload, stem) {
8413
9056
  const outputDir = ensureOutputDir();
8414
- const outputPath = (0, import_node_path10.join)(outputDir, `${stem}_${Date.now()}.json`);
8415
- (0, import_node_fs8.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
9057
+ const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.json`);
9058
+ (0, import_node_fs9.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
8416
9059
  return outputPath;
8417
9060
  }
8418
9061
  function writeCsvOutputFile(rows, stem) {
8419
9062
  const outputDir = ensureOutputDir();
8420
- const outputPath = (0, import_node_path10.join)(outputDir, `${stem}_${Date.now()}.csv`);
9063
+ const outputPath = (0, import_node_path11.join)(outputDir, `${stem}_${Date.now()}.csv`);
8421
9064
  const seen = /* @__PURE__ */ new Set();
8422
9065
  const columns = [];
8423
9066
  for (const row of rows) {
@@ -8440,7 +9083,7 @@ function writeCsvOutputFile(rows, stem) {
8440
9083
  for (const row of rows) {
8441
9084
  lines.push(columns.map((column) => escapeCell(row[column])).join(","));
8442
9085
  }
8443
- (0, import_node_fs8.writeFileSync)(outputPath, `${lines.join("\n")}
9086
+ (0, import_node_fs9.writeFileSync)(outputPath, `${lines.join("\n")}
8444
9087
  `, "utf-8");
8445
9088
  const previewRows = rows.slice(0, 5);
8446
9089
  const previewColumns = columns.slice(0, 5);
@@ -8486,8 +9129,7 @@ async function listTools(args) {
8486
9129
  title: `${items.length} tools available:`,
8487
9130
  lines: items.flatMap((item) => {
8488
9131
  const cats = item.categories.length ? ` [${item.categories.join(", ")}]` : "";
8489
- const listHint = item.listExtractorPaths?.length ? ` listExtractorPaths=${item.listExtractorPaths.join(",")}` : "";
8490
- return [`${item.toolId}${cats}`, ` ${item.description}${listHint}`];
9132
+ return [`${item.toolId}${cats}`, ` ${item.description}`];
8491
9133
  })
8492
9134
  }
8493
9135
  ]
@@ -8566,7 +9208,7 @@ Common commands:
8566
9208
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
8567
9209
 
8568
9210
  Output:
8569
- Use describe for tool contracts. get is accepted as a compatibility alias.
9211
+ Use describe for tool contracts.
8570
9212
  Use execute to run a tool. run is accepted as a compatibility alias.
8571
9213
  `
8572
9214
  );
@@ -8613,8 +9255,8 @@ Examples:
8613
9255
  `
8614
9256
  Notes:
8615
9257
  Shows the tool contract, input schema, output schema, Deepline cost, aliases,
8616
- and metadata. describe is the preferred discovery verb. get is kept as a
8617
- compatibility alias for the same metadata surface.
9258
+ and metadata. describe is the supported discovery verb. get is removed in
9259
+ the V2 SDK CLI; use describe for the same metadata surface.
8618
9260
 
8619
9261
  Examples:
8620
9262
  deepline tools describe hunter_email_verifier
@@ -8627,7 +9269,22 @@ Examples:
8627
9269
  ...options.json ? ["--json"] : []
8628
9270
  ]);
8629
9271
  });
8630
- addToolMetadataCommand(tools.command("describe <toolId>").alias("get"));
9272
+ addToolMetadataCommand(tools.command("describe <toolId>"));
9273
+ tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
9274
+ "after",
9275
+ `
9276
+ Examples:
9277
+ deepline tools describe hunter_email_verifier --json
9278
+ `
9279
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
9280
+ const message = `tools get has been removed from the V2 SDK CLI. Use: deepline tools describe ${toolId} --json`;
9281
+ if (options.json || shouldEmitJson()) {
9282
+ printJsonError({ message, code: "TOOLS_GET_REMOVED" });
9283
+ } else {
9284
+ console.error(message);
9285
+ }
9286
+ process.exitCode = 2;
9287
+ });
8631
9288
  tools.command("execute <toolId>").alias("run").description("Execute a tool by id.").addHelpText(
8632
9289
  "after",
8633
9290
  `
@@ -8636,7 +9293,7 @@ Notes:
8636
9293
  waterfalls, row maps, checkpoints, and retries.
8637
9294
  execute is the canonical execution verb. run is a compatibility alias.
8638
9295
  Calling a provider-backed tool can spend Deepline credits. Use --json for the
8639
- stable result payload and --full-output when debugging response metadata.
9296
+ stable result payload plus output preview and debugging helpers.
8640
9297
 
8641
9298
  Examples:
8642
9299
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
@@ -8649,7 +9306,7 @@ Examples:
8649
9306
  }, []).option("--json [payload]", "Emit JSON output. Use `--input` or `--payload` for passing JSON params.").option("--input <payload>", "Merge a JSON object into the tool params").option("--payload <payload>", "Merge a JSON object into the tool params").option(
8650
9307
  "--output-format <format>",
8651
9308
  "Output format: auto, csv, csv_file, json, or json_file"
8652
- ).option("--full-output", "Emit the full JSON payload").option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
9309
+ ).option("--no-preview", "Only print the extracted output path when applicable").action(async (toolId, options) => {
8653
9310
  const args = [
8654
9311
  toolId,
8655
9312
  ...options.param.flatMap((value) => ["--param", value]),
@@ -8658,7 +9315,6 @@ Examples:
8658
9315
  ...options.input ? ["--input", options.input] : [],
8659
9316
  ...options.payload ? ["--payload", options.payload] : [],
8660
9317
  ...options.outputFormat ? ["--output-format", options.outputFormat] : [],
8661
- ...options.fullOutput ? ["--full-output"] : [],
8662
9318
  ...options.preview === false ? ["--no-preview"] : []
8663
9319
  ];
8664
9320
  process.exitCode = await executeTool(args);
@@ -8683,13 +9339,29 @@ async function getTool(args) {
8683
9339
  throw error;
8684
9340
  }
8685
9341
  if (argsWantJson(args)) {
8686
- process.stdout.write(`${JSON.stringify(tool)}
9342
+ process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
8687
9343
  `);
8688
9344
  return 0;
8689
9345
  }
8690
9346
  printToolDetails(tool, toolId);
8691
9347
  return 0;
8692
9348
  }
9349
+ function toolMetadataJsonForDescribe(tool, requestedToolId) {
9350
+ const toolId = String(tool.toolId || requestedToolId);
9351
+ return {
9352
+ ...tool,
9353
+ toolId,
9354
+ provider: tool.provider,
9355
+ displayName: tool.displayName,
9356
+ runtimeOutputHelp: {
9357
+ contract: "tools describe shows the declared schema and semantic getters; it is not an observed provider response.",
9358
+ observeActualShape: `deepline tools execute ${toolId} --input '{...}' --json`,
9359
+ observedOutput: `deepline tools execute ${toolId} --input '{...}' --json`,
9360
+ forPlayGetterBugs: "Run the play, then inspect the emitted table commands from runs get. Use deepline db query against the run tables before editing getters.",
9361
+ executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run tables."
9362
+ }
9363
+ };
9364
+ }
8693
9365
  function printToolDetails(tool, requestedToolId) {
8694
9366
  const toolId = String(tool.toolId || requestedToolId);
8695
9367
  const operation = typeof tool.operation === "string" ? tool.operation : "";
@@ -8708,7 +9380,12 @@ function printToolDetails(tool, requestedToolId) {
8708
9380
  const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
8709
9381
  const playExpansion = recordField(tool, "playExpansion", "play_expansion");
8710
9382
  const samples = recordField(tool, "samples");
9383
+ const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
8711
9384
  console.log(`Tool: ${toolId}`);
9385
+ console.log(" Runtime output help:");
9386
+ console.log(" describe shows declared schema/getters, not an observed provider response");
9387
+ console.log(` observe actual shape: deepline tools execute ${toolId} --input '{...}' --json`);
9388
+ console.log(" for play getter bugs: run the play, then use the db query commands printed by runs get");
8712
9389
  if (displayName) {
8713
9390
  console.log(" Display name:");
8714
9391
  console.log(` ${displayName}`);
@@ -8771,14 +9448,16 @@ function printToolDetails(tool, requestedToolId) {
8771
9448
  console.log(" Tip: pass --payload with a JSON object.");
8772
9449
  }
8773
9450
  printSamples(samples);
9451
+ printUsageGuidance(usageGuidance);
8774
9452
  if (isPlayTool(tool)) {
8775
9453
  console.log(" Play contract:");
8776
9454
  console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
8777
9455
  if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
8778
9456
  console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
8779
9457
  }
8780
- const getters = recordField(tool, "resultIdentityGetters", "result_identity_getters");
8781
- const targets = Object.keys(getters).filter(Boolean).sort();
9458
+ const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
9459
+ const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
9460
+ const targets = extractedValues.map((entry) => isRecord3(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
8782
9461
  if (targets.length) {
8783
9462
  console.log(` - Built-in extract targets: ${targets.join(", ")}`);
8784
9463
  }
@@ -8797,7 +9476,39 @@ function printToolDetails(tool, requestedToolId) {
8797
9476
  } else {
8798
9477
  console.log(` deepline tools execute ${toolId} --payload '{...}'`);
8799
9478
  }
8800
- console.log(" deepline tools get <tool_id> --json # full machine-readable output");
9479
+ console.log(" deepline tools describe <tool_id> --json");
9480
+ }
9481
+ function printUsageGuidance(usageGuidance) {
9482
+ if (Object.keys(usageGuidance).length === 0) return;
9483
+ const execute = stringField(usageGuidance, "execute");
9484
+ const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
9485
+ const toolResponse = recordField(toolExecutionResult, "toolResponse", "tool_response");
9486
+ const extractedLists = arrayField(toolExecutionResult, "extractedLists", "extracted_lists");
9487
+ const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
9488
+ console.log(" Usage guidance:");
9489
+ if (execute) console.log(` ${execute}`);
9490
+ const raw = stringField(toolResponse, "raw");
9491
+ const meta = stringField(toolResponse, "meta");
9492
+ if (raw) console.log(` Raw tool response: ${raw}`);
9493
+ if (meta) console.log(` Tool response metadata: ${meta}`);
9494
+ printExtractions("Extracted lists", extractedLists);
9495
+ printExtractions("Extracted values", extractedValues);
9496
+ }
9497
+ function printExtractions(label, entries) {
9498
+ if (!entries.length) return;
9499
+ console.log(` ${label}:`);
9500
+ for (const entry of entries) {
9501
+ if (!isRecord3(entry)) continue;
9502
+ const name = stringField(entry, "name");
9503
+ const expression = stringField(entry, "expression");
9504
+ const details = recordField(entry, "details");
9505
+ const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
9506
+ const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
9507
+ if (!name || !expression) continue;
9508
+ const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
9509
+ const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
9510
+ console.log(` - ${name}: ${expression}${pathSuffix}`);
9511
+ }
8801
9512
  }
8802
9513
  function printToolCost(input) {
8803
9514
  const { cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
@@ -8865,6 +9576,17 @@ function samplePayload(samples, key) {
8865
9576
  function commandEnvelopeFromRawResponse(rawResponse) {
8866
9577
  return isRecord3(rawResponse) ? { ...rawResponse } : { status: "completed", result: rawResponse };
8867
9578
  }
9579
+ function listExtractorPathsFromUsageGuidance(tool) {
9580
+ const toolExecutionResult = tool.usageGuidance?.toolExecutionResult;
9581
+ const extractedLists = Array.isArray(toolExecutionResult?.extractedLists) ? toolExecutionResult.extractedLists : isRecord3(toolExecutionResult?.extractedLists) ? Object.values(toolExecutionResult.extractedLists) : [];
9582
+ return extractedLists.flatMap((entry) => {
9583
+ const paths = entry.details?.candidatePaths ?? entry.details?.rawToolOutputPaths;
9584
+ if (!Array.isArray(paths)) return [];
9585
+ return paths.map(
9586
+ (path) => path.trim().replace(/^toolExecutionResult\.toolResponse\.raw\.?/, "").replace(/^toolExecutionResult\.toolOutput\.raw\.?/, "").replace(/^\./, "")
9587
+ ).filter(Boolean);
9588
+ });
9589
+ }
8868
9590
  function isPlayTool(tool) {
8869
9591
  const provider = typeof tool.provider === "string" ? tool.provider : "";
8870
9592
  return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
@@ -8933,7 +9655,7 @@ function normalizeOutputFormat(raw) {
8933
9655
  function parseExecuteOptions(args) {
8934
9656
  const toolId = args[0];
8935
9657
  if (!toolId) {
8936
- throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--full-output] [--no-preview]`);
9658
+ throw new Error(`Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`);
8937
9659
  }
8938
9660
  const params = {};
8939
9661
  let outputFormat = "auto";
@@ -8962,10 +9684,6 @@ function parseExecuteOptions(args) {
8962
9684
  outputFormat = normalizeOutputFormat(args[++index]);
8963
9685
  continue;
8964
9686
  }
8965
- if (arg === "--full-output") {
8966
- outputFormat = "json";
8967
- continue;
8968
- }
8969
9687
  if (arg === "--no-preview") {
8970
9688
  noPreview = true;
8971
9689
  continue;
@@ -8986,9 +9704,9 @@ function powerShellQuote(value) {
8986
9704
  function seedToolListScript(input) {
8987
9705
  const stem = safeFileStem(input.toolId);
8988
9706
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
8989
- const scriptDir = (0, import_node_fs9.mkdtempSync)((0, import_node_path11.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
8990
- (0, import_node_fs9.chmodSync)(scriptDir, 448);
8991
- const scriptPath = (0, import_node_path11.join)(scriptDir, fileName);
9707
+ const scriptDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "deepline-workflow-seed-"));
9708
+ (0, import_node_fs10.chmodSync)(scriptDir, 448);
9709
+ const scriptPath = (0, import_node_path12.join)(scriptDir, fileName);
8992
9710
  const projectDir = `deepline/projects/${stem}-workflow`;
8993
9711
  const playName = `${stem}-workflow`;
8994
9712
  const sampleRows = input.rows.length > 0 ? `${JSON.stringify(input.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
@@ -9004,7 +9722,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
9004
9722
  description: ${JSON.stringify(`Seed ${input.toolId} rows for workflow expansion.`)},
9005
9723
  });
9006
9724
 
9007
- const list = Object.values(result.lists)[0];
9725
+ const list = Object.values(result.extractedLists)[0];
9008
9726
  const rows = (list?.get() ?? []).slice(0, 100);
9009
9727
  // ${sampleRows}
9010
9728
  // columns: ${columns}
@@ -9021,7 +9739,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
9021
9739
  };
9022
9740
  });
9023
9741
  `;
9024
- (0, import_node_fs9.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
9742
+ (0, import_node_fs10.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
9025
9743
  return {
9026
9744
  path: scriptPath,
9027
9745
  projectDir,
@@ -9032,7 +9750,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
9032
9750
  function buildToolExecuteBaseEnvelope(input) {
9033
9751
  const envelope = commandEnvelopeFromRawResponse(input.rawResponse);
9034
9752
  const summaryEntries = Object.entries(input.summary);
9035
- const output = input.listConversion ? {
9753
+ const outputPreview = input.listConversion ? {
9036
9754
  kind: "list",
9037
9755
  rowCount: input.listConversion.rows.length,
9038
9756
  columns: Object.keys(input.listConversion.rows[0] ?? {}),
@@ -9043,6 +9761,8 @@ function buildToolExecuteBaseEnvelope(input) {
9043
9761
  kind: summaryEntries.length > 0 ? "object" : "raw",
9044
9762
  summary: input.summary
9045
9763
  };
9764
+ const envelopeHasCanonicalOutput = isRecord3(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
9765
+ const inspectCommand = `deepline tools execute ${input.toolId} --input ${shellQuote(JSON.stringify(input.params))} --json`;
9046
9766
  const actions = input.listConversion ? [
9047
9767
  {
9048
9768
  label: "next",
@@ -9051,17 +9771,23 @@ function buildToolExecuteBaseEnvelope(input) {
9051
9771
  ] : [];
9052
9772
  return {
9053
9773
  ...envelope,
9054
- output,
9774
+ ...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
9055
9775
  ...summaryEntries.length > 0 ? { summary: input.summary } : {},
9056
- next: input.listConversion ? {
9057
- expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again."
9058
- } : {},
9776
+ next: {
9777
+ inspect: inspectCommand,
9778
+ playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
9779
+ ...input.listConversion ? {
9780
+ expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
9781
+ listSourcePath: input.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
9782
+ } : {}
9783
+ },
9059
9784
  render: {
9060
9785
  sections: input.listConversion ? [
9061
9786
  {
9062
9787
  title: "output",
9063
9788
  lines: [
9064
9789
  `${input.listConversion.rows.length} row(s) extracted from ${input.listConversion.sourcePath ?? "auto-detected list"}`,
9790
+ "paths above are observed from this execute response; use run table rows to debug play getters",
9065
9791
  `columns: ${JSON.stringify(Object.keys(input.listConversion.rows[0] ?? {}))}`,
9066
9792
  `preview: ${JSON.stringify(input.listConversion.rows.slice(0, 5))}`
9067
9793
  ]
@@ -9105,11 +9831,12 @@ async function executeTool(args) {
9105
9831
  }
9106
9832
  const rawResponse = await client.executeTool(parsed.toolId, parsed.params);
9107
9833
  const listConversion = tryConvertToList(rawResponse, {
9108
- listExtractorPaths: metadata.listExtractorPaths ?? []
9834
+ listExtractorPaths: listExtractorPathsFromUsageGuidance(metadata)
9109
9835
  });
9110
9836
  const summary = extractSummaryFields(rawResponse);
9111
9837
  const baseEnvelope = buildToolExecuteBaseEnvelope({
9112
9838
  toolId: parsed.toolId,
9839
+ params: parsed.params,
9113
9840
  rawResponse,
9114
9841
  listConversion,
9115
9842
  summary
@@ -9236,8 +9963,8 @@ async function executeTool(args) {
9236
9963
 
9237
9964
  // src/cli/commands/update.ts
9238
9965
  var import_node_child_process = require("child_process");
9239
- var import_node_fs10 = require("fs");
9240
- var import_node_path12 = require("path");
9966
+ var import_node_fs11 = require("fs");
9967
+ var import_node_path13 = require("path");
9241
9968
  function posixShellQuote(value) {
9242
9969
  return `'${value.replace(/'/g, `'\\''`)}'`;
9243
9970
  }
@@ -9256,19 +9983,19 @@ function buildSourceUpdateCommand(sourceRoot) {
9256
9983
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
9257
9984
  }
9258
9985
  function findRepoBackedSdkRoot(startPath) {
9259
- let current = (0, import_node_path12.resolve)(startPath);
9986
+ let current = (0, import_node_path13.resolve)(startPath);
9260
9987
  while (true) {
9261
- if ((0, import_node_fs10.existsSync)((0, import_node_path12.join)(current, "sdk", "package.json")) && (0, import_node_fs10.existsSync)((0, import_node_path12.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
9988
+ if ((0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "package.json")) && (0, import_node_fs11.existsSync)((0, import_node_path13.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
9262
9989
  return current;
9263
9990
  }
9264
- const parent = (0, import_node_path12.dirname)(current);
9991
+ const parent = (0, import_node_path13.dirname)(current);
9265
9992
  if (parent === current) return null;
9266
9993
  current = parent;
9267
9994
  }
9268
9995
  }
9269
9996
  function resolveUpdatePlan() {
9270
- const entrypoint = process.argv[1] ? (0, import_node_path12.resolve)(process.argv[1]) : "";
9271
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path12.dirname)(entrypoint)) : null;
9997
+ const entrypoint = process.argv[1] ? (0, import_node_path13.resolve)(process.argv[1]) : "";
9998
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path13.dirname)(entrypoint)) : null;
9272
9999
  if (sourceRoot) {
9273
10000
  return {
9274
10001
  kind: "source",
@@ -9361,9 +10088,9 @@ Examples:
9361
10088
 
9362
10089
  // src/cli/skills-sync.ts
9363
10090
  var import_node_child_process2 = require("child_process");
9364
- var import_node_fs11 = require("fs");
10091
+ var import_node_fs12 = require("fs");
9365
10092
  var import_node_os8 = require("os");
9366
- var import_node_path13 = require("path");
10093
+ var import_node_path14 = require("path");
9367
10094
  var CHECK_TIMEOUT_MS2 = 3e3;
9368
10095
  var SDK_SKILL_NAME = "deepline-sdk";
9369
10096
  var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
@@ -9374,23 +10101,59 @@ function shouldSkipSkillsSync() {
9374
10101
  }
9375
10102
  function sdkSkillsVersionPath(baseUrl) {
9376
10103
  const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
9377
- return (0, import_node_path13.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
10104
+ return (0, import_node_path14.join)(home, ".local", "deepline", baseUrlSlug(baseUrl), "sdk-skills", ".version");
9378
10105
  }
9379
10106
  function readLocalSkillsVersion(baseUrl) {
9380
10107
  const path = sdkSkillsVersionPath(baseUrl);
9381
- if (!(0, import_node_fs11.existsSync)(path)) return "";
10108
+ if (!(0, import_node_fs12.existsSync)(path)) return "";
9382
10109
  try {
9383
- return (0, import_node_fs11.readFileSync)(path, "utf-8").trim();
10110
+ return (0, import_node_fs12.readFileSync)(path, "utf-8").trim();
9384
10111
  } catch {
9385
10112
  return "";
9386
10113
  }
9387
10114
  }
9388
10115
  function writeLocalSkillsVersion(baseUrl, version) {
9389
10116
  const path = sdkSkillsVersionPath(baseUrl);
9390
- (0, import_node_fs11.mkdirSync)((0, import_node_path13.dirname)(path), { recursive: true });
9391
- (0, import_node_fs11.writeFileSync)(path, `${version}
10117
+ (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
10118
+ (0, import_node_fs12.writeFileSync)(path, `${version}
9392
10119
  `, "utf-8");
9393
10120
  }
10121
+ function installedSdkSkillHasStalePositionalExecuteExamples() {
10122
+ const home = process.env.HOME?.trim() || (0, import_node_os8.homedir)();
10123
+ const roots = [
10124
+ (0, import_node_path14.join)(home, ".claude", "skills", SDK_SKILL_NAME),
10125
+ (0, import_node_path14.join)(home, ".agents", "skills", SDK_SKILL_NAME)
10126
+ ];
10127
+ const staleMarkers = [
10128
+ "ctx.tools.execute(key",
10129
+ "ctx.tools.execute('",
10130
+ 'ctx.tools.execute("',
10131
+ "rowCtx.tools.execute('",
10132
+ 'rowCtx.tools.execute("'
10133
+ ];
10134
+ const scan = (dir) => {
10135
+ for (const entry of (0, import_node_fs12.readdirSync)(dir)) {
10136
+ const path = (0, import_node_path14.join)(dir, entry);
10137
+ const stat3 = (0, import_node_fs12.statSync)(path);
10138
+ if (stat3.isDirectory()) {
10139
+ if (scan(path)) return true;
10140
+ continue;
10141
+ }
10142
+ if (!entry.endsWith(".md")) continue;
10143
+ const text = (0, import_node_fs12.readFileSync)(path, "utf-8");
10144
+ if (staleMarkers.some((marker) => text.includes(marker))) return true;
10145
+ }
10146
+ return false;
10147
+ };
10148
+ for (const root of roots) {
10149
+ try {
10150
+ if ((0, import_node_fs12.existsSync)(root) && scan(root)) return true;
10151
+ } catch {
10152
+ continue;
10153
+ }
10154
+ }
10155
+ return false;
10156
+ }
9394
10157
  async function fetchSkillsUpdate(baseUrl, localVersion) {
9395
10158
  const controller = new AbortController();
9396
10159
  const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
@@ -9426,7 +10189,7 @@ function buildSkillsInstallArgs(baseUrl) {
9426
10189
  "skills",
9427
10190
  "add",
9428
10191
  packageUrl,
9429
- "--agents",
10192
+ "--agent",
9430
10193
  ...SKILL_AGENTS,
9431
10194
  "--global",
9432
10195
  "--yes",
@@ -9442,7 +10205,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
9442
10205
  "skills",
9443
10206
  "add",
9444
10207
  packageUrl,
9445
- "--agents",
10208
+ "--agent",
9446
10209
  ...SKILL_AGENTS,
9447
10210
  "--global",
9448
10211
  "--yes",
@@ -9482,7 +10245,7 @@ function resolveSkillsInstallCommands(baseUrl) {
9482
10245
  return [npxInstall];
9483
10246
  }
9484
10247
  function runOneSkillsInstall(install) {
9485
- return new Promise((resolve10) => {
10248
+ return new Promise((resolve11) => {
9486
10249
  const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
9487
10250
  stdio: ["ignore", "ignore", "pipe"],
9488
10251
  env: process.env
@@ -9492,7 +10255,7 @@ function runOneSkillsInstall(install) {
9492
10255
  stderr += chunk.toString("utf-8");
9493
10256
  });
9494
10257
  child.on("error", (error) => {
9495
- resolve10({
10258
+ resolve11({
9496
10259
  ok: false,
9497
10260
  detail: `failed to start ${install.command}: ${error.message}`,
9498
10261
  manualCommand: install.manualCommand
@@ -9500,11 +10263,11 @@ function runOneSkillsInstall(install) {
9500
10263
  });
9501
10264
  child.on("close", (code) => {
9502
10265
  if (code === 0) {
9503
- resolve10({ ok: true, detail: "", manualCommand: install.manualCommand });
10266
+ resolve11({ ok: true, detail: "", manualCommand: install.manualCommand });
9504
10267
  return;
9505
10268
  }
9506
10269
  const detail = stderr.trim();
9507
- resolve10({
10270
+ resolve11({
9508
10271
  ok: false,
9509
10272
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
9510
10273
  manualCommand: install.manualCommand
@@ -9543,10 +10306,19 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
9543
10306
  attemptedSync = true;
9544
10307
  const localVersion = readLocalSkillsVersion(baseUrl);
9545
10308
  const update = await fetchSkillsUpdate(baseUrl, localVersion);
9546
- if (!update?.needsUpdate || !update.remoteVersion) return;
10309
+ const hasStaleInstalledSkill = installedSdkSkillHasStalePositionalExecuteExamples();
10310
+ if (!update?.needsUpdate && !hasStaleInstalledSkill || !update?.remoteVersion) {
10311
+ return;
10312
+ }
9547
10313
  writeSdkSkillsStatusLine("SDK skills changed; syncing deepline-sdk skill...");
9548
10314
  const installed = await runSkillsInstall(baseUrl);
9549
10315
  if (!installed) return;
10316
+ if (installedSdkSkillHasStalePositionalExecuteExamples()) {
10317
+ process.stderr.write(
10318
+ "SDK skills sync completed, but installed deepline-sdk docs still contain stale positional ctx.tools.execute examples.\n"
10319
+ );
10320
+ return;
10321
+ }
9550
10322
  writeLocalSkillsVersion(baseUrl, update.remoteVersion);
9551
10323
  writeSdkSkillsStatusLine("SDK skills are up to date.");
9552
10324
  }