deepline 0.1.146 → 0.1.148

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.
@@ -604,10 +604,11 @@ var SDK_RELEASE = {
604
604
  // 0.1.108 ships explicit dataset column/tool recompute policy and removes
605
605
  // the SDK enrich generator's one-second stale policy.
606
606
  // 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
607
- version: "0.1.146",
608
- apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
607
+ // 0.1.111 ships dataset-native tool list getters and result row datasets.
608
+ version: "0.1.148",
609
+ apiContract: "2026-06-dataset-handle-results-hard-cutover",
609
610
  supportPolicy: {
610
- latest: "0.1.146",
611
+ latest: "0.1.148",
611
612
  minimumSupported: "0.1.53",
612
613
  deprecatedBelow: "0.1.53",
613
614
  commandMinimumSupported: [
@@ -618,52 +619,79 @@ var SDK_RELEASE = {
618
619
  },
619
620
  {
620
621
  command: "plays",
621
- minimumSupported: "0.1.110",
622
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
622
+ minimumSupported: "0.1.111",
623
+ reason: "Play file commands now use dataset-native list getters and result row datasets."
623
624
  },
624
625
  {
625
626
  command: "plays run",
626
- minimumSupported: "0.1.110",
627
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
627
+ minimumSupported: "0.1.111",
628
+ reason: "Play run results now promote row-shaped outputs into dataset handles for safe export."
628
629
  },
629
630
  {
630
631
  command: "run",
631
632
  displayCommand: "plays run",
632
- minimumSupported: "0.1.110",
633
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
633
+ minimumSupported: "0.1.111",
634
+ reason: "Play run results now promote row-shaped outputs into dataset handles for safe export."
634
635
  },
635
636
  {
636
637
  command: "plays check",
637
- minimumSupported: "0.1.110",
638
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
638
+ minimumSupported: "0.1.111",
639
+ reason: "Play file checks now validate dataset-native list getter authoring."
639
640
  },
640
641
  {
641
642
  command: "check",
642
643
  displayCommand: "plays check",
643
- minimumSupported: "0.1.110",
644
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
644
+ minimumSupported: "0.1.111",
645
+ reason: "Play file checks now validate dataset-native list getter authoring."
645
646
  },
646
647
  {
647
648
  command: "plays publish",
648
- minimumSupported: "0.1.110",
649
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
649
+ minimumSupported: "0.1.111",
650
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
650
651
  },
651
652
  {
652
653
  command: "publish",
653
654
  displayCommand: "plays publish",
654
- minimumSupported: "0.1.110",
655
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
655
+ minimumSupported: "0.1.111",
656
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
656
657
  },
657
658
  {
658
659
  command: "plays set-live",
659
- minimumSupported: "0.1.110",
660
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
660
+ minimumSupported: "0.1.111",
661
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
661
662
  },
662
663
  {
663
664
  command: "set-live",
664
665
  displayCommand: "plays set-live",
665
- minimumSupported: "0.1.110",
666
- reason: "Play file commands now require top-level definePlay descriptions so agents and play surfaces can explain local plays."
666
+ minimumSupported: "0.1.111",
667
+ reason: "Published play artifacts now target dataset-native list getters and result row datasets."
668
+ },
669
+ {
670
+ command: "runs",
671
+ minimumSupported: "0.1.111",
672
+ reason: "Run result rows now render as dataset handles with explicit export commands."
673
+ },
674
+ {
675
+ command: "runs get",
676
+ minimumSupported: "0.1.111",
677
+ reason: "Run result rows now render as dataset handles with explicit export commands."
678
+ },
679
+ {
680
+ command: "get",
681
+ displayCommand: "runs get",
682
+ minimumSupported: "0.1.111",
683
+ reason: "Run result rows now render as dataset handles with explicit export commands."
684
+ },
685
+ {
686
+ command: "runs export",
687
+ minimumSupported: "0.1.111",
688
+ reason: "Run result row datasets now use the dataset-handle export contract."
689
+ },
690
+ {
691
+ command: "export",
692
+ displayCommand: "runs export",
693
+ minimumSupported: "0.1.111",
694
+ reason: "Run result row datasets now use the dataset-handle export contract."
667
695
  }
668
696
  ],
669
697
  autoUpdatePatchLag: 2
@@ -8319,9 +8347,10 @@ function generateProviderSourceBlock(input2) {
8319
8347
  input: ${inputName},
8320
8348
  description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
8321
8349
  });
8322
- // extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
8350
+ // extractedLists.${getter}.get() returns a dataset handle of provider-shaped rows. Do not assume canonical fields;
8323
8351
  // inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
8324
- const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
8352
+ const sourceRowsDataset_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get();
8353
+ const sourceRows_${input2.index} = (await sourceRowsDataset_${input2.index}.peek(limit)) as ${input2.collectionType}[];`;
8325
8354
  }
8326
8355
  function generateProviderSourceRowsBlock(input2) {
8327
8356
  const blocks = input2.source.values.map(
@@ -11007,6 +11036,9 @@ function formatPlayLogLine(line, status, state) {
11007
11036
  }
11008
11037
  return `${prefix}${message}`;
11009
11038
  }
11039
+ function isDatasetResultEnvelope(value) {
11040
+ return value !== null && typeof value === "object" && !Array.isArray(value) && value.kind === "dataset";
11041
+ }
11010
11042
  function compactReturnValue(value, depth = 0) {
11011
11043
  if (depth >= 4) {
11012
11044
  return value && typeof value === "object" ? "[Object]" : value;
@@ -11018,6 +11050,7 @@ function compactReturnValue(value, depth = 0) {
11018
11050
  if (!value || typeof value !== "object") {
11019
11051
  return value;
11020
11052
  }
11053
+ const isDatasetEnvelope = isDatasetResultEnvelope(value);
11021
11054
  const output2 = {};
11022
11055
  for (const [key, entry] of Object.entries(value)) {
11023
11056
  if (depth === 0 && key === "_metadata") {
@@ -11026,13 +11059,41 @@ function compactReturnValue(value, depth = 0) {
11026
11059
  if (BULKY_RETURN_KEYS.has(key)) {
11027
11060
  continue;
11028
11061
  }
11029
- if (key === "access") {
11062
+ if (isDatasetEnvelope && key === "access") {
11063
+ continue;
11064
+ }
11065
+ if (isDatasetEnvelope && (key === "queryDatasetCommand" || key === "cliCommand")) {
11066
+ continue;
11067
+ }
11068
+ if (isDatasetEnvelope && key === "slowExportAsCsvCommand") {
11069
+ output2.fullExportCommand = entry;
11030
11070
  continue;
11031
11071
  }
11032
11072
  output2[key] = compactReturnValue(entry, depth + 1);
11033
11073
  }
11034
11074
  return output2;
11035
11075
  }
11076
+ function defaultResultForEnvelope(value, depth = 0) {
11077
+ if (depth > 20 || value == null || typeof value !== "object") {
11078
+ return value;
11079
+ }
11080
+ if (Array.isArray(value)) {
11081
+ return value.map((entry) => defaultResultForEnvelope(entry, depth + 1));
11082
+ }
11083
+ const isDatasetEnvelope = isDatasetResultEnvelope(value);
11084
+ const output2 = {};
11085
+ for (const [key, entry] of Object.entries(value)) {
11086
+ if (isDatasetEnvelope && (key === "queryDatasetCommand" || key === "cliCommand")) {
11087
+ continue;
11088
+ }
11089
+ if (isDatasetEnvelope && key === "slowExportAsCsvCommand") {
11090
+ output2.fullExportCommand = entry;
11091
+ continue;
11092
+ }
11093
+ output2[key] = defaultResultForEnvelope(entry, depth + 1);
11094
+ }
11095
+ return output2;
11096
+ }
11036
11097
  function formatJsonPreview(value) {
11037
11098
  const json = JSON.stringify(value, null, 2);
11038
11099
  if (!json || json === "{}") {
@@ -11076,9 +11137,6 @@ function collectDatasetHandleLines(value, path = "result", datasetStats) {
11076
11137
  if (datasetStats && (datasetStats.source === path || datasetStats.source === record.path)) {
11077
11138
  lines2.push(...formatDatasetStatsLines(datasetStats.stats, " "));
11078
11139
  }
11079
- if (typeof record.queryDatasetCommand === "string") {
11080
- lines2.push(` query dataset: ${record.queryDatasetCommand}`);
11081
- }
11082
11140
  if (typeof record.slowExportAsCsvCommand === "string") {
11083
11141
  lines2.push(` export CSV: ${record.slowExportAsCsvCommand}`);
11084
11142
  }
@@ -11489,7 +11547,7 @@ function compactPlayStatus(status) {
11489
11547
  logs: normalizeLogsForEnvelope(status),
11490
11548
  ...displayError ? { error: displayError } : {},
11491
11549
  ...warnings.length > 0 ? { warnings } : {},
11492
- ...result !== void 0 ? { result } : {},
11550
+ ...result !== void 0 ? { result: defaultResultForEnvelope(result) } : {},
11493
11551
  ...billing ? { billing } : {},
11494
11552
  next: buildRunNextCommands(status)
11495
11553
  };
@@ -20372,7 +20430,7 @@ import { join as join10, resolve as resolve10 } from "path";
20372
20430
  // src/tool-output.ts
20373
20431
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync11 } from "fs";
20374
20432
  import { homedir as homedir9 } from "os";
20375
- import { join as join9 } from "path";
20433
+ import { dirname as dirname9, join as join9 } from "path";
20376
20434
  function isPlainObject(value) {
20377
20435
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
20378
20436
  }
@@ -20445,16 +20503,24 @@ function tryConvertToList(payload, options) {
20445
20503
  (entry) => typeof entry === "string" && entry.trim().length > 0
20446
20504
  ) : [];
20447
20505
  if (listExtractorPaths.length > 0) {
20506
+ let emptyMatch = null;
20448
20507
  for (const root of candidateRoots(payload)) {
20449
20508
  for (const extractorPath of listExtractorPaths) {
20450
20509
  const resolved = getByDottedPath(root.value, extractorPath);
20451
20510
  const rows = normalizeRows(resolved);
20452
- if (rows && rows.length > 0) {
20453
- const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
20511
+ if (!rows) {
20512
+ continue;
20513
+ }
20514
+ const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
20515
+ if (rows.length > 0) {
20454
20516
  return { rows, strategy: "configured_paths", sourcePath };
20455
20517
  }
20518
+ emptyMatch ??= { rows, strategy: "configured_paths", sourcePath };
20456
20519
  }
20457
20520
  }
20521
+ if (emptyMatch) {
20522
+ return emptyMatch;
20523
+ }
20458
20524
  }
20459
20525
  for (const root of candidateRoots(payload)) {
20460
20526
  const candidate = findBestArrayCandidate(root.value, root.path ?? "");
@@ -20478,9 +20544,9 @@ function writeJsonOutputFile(payload, stem) {
20478
20544
  writeFileSync11(outputPath, JSON.stringify(payload, null, 2), "utf-8");
20479
20545
  return outputPath;
20480
20546
  }
20481
- function writeCsvOutputFile(rows, stem) {
20482
- const outputDir = ensureOutputDir();
20483
- const outputPath = join9(outputDir, `${stem}_${Date.now()}.csv`);
20547
+ function writeCsvOutputFile(rows, stem, options) {
20548
+ const outputPath = options?.outPath ? options.outPath : join9(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
20549
+ mkdirSync7(dirname9(outputPath), { recursive: true });
20484
20550
  const seen = /* @__PURE__ */ new Set();
20485
20551
  const columns = [];
20486
20552
  for (const row of rows) {
@@ -21009,6 +21075,7 @@ Examples:
21009
21075
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
21010
21076
  deepline tools execute hunter_email_verifier -p email=a@b.com
21011
21077
  deepline tools execute test_rate_limit --input '{"key":"smoke"}' --json | jq '.status'
21078
+ deepline tools execute free_simple_company_search --input '{"sql":"SELECT company_name FROM companies LIMIT 10"}' --out companies.csv
21012
21079
  `
21013
21080
  ).option(
21014
21081
  "-p, --param <key=value>",
@@ -21030,6 +21097,9 @@ Examples:
21030
21097
  ).option(
21031
21098
  "--output-format <format>",
21032
21099
  "Output format: auto, csv, csv_file, json, or json_file"
21100
+ ).option(
21101
+ "-o, --out <path>",
21102
+ "Write row-shaped tool output to this CSV path"
21033
21103
  ).option(
21034
21104
  "--no-preview",
21035
21105
  "Only print the extracted output path when applicable"
@@ -21042,6 +21112,7 @@ Examples:
21042
21112
  ...options.input ? ["--input", options.input] : [],
21043
21113
  ...options.payload ? ["--payload", options.payload] : [],
21044
21114
  ...options.outputFormat ? ["--output-format", options.outputFormat] : [],
21115
+ ...options.out ? ["--out", options.out] : [],
21045
21116
  ...options.preview === false ? ["--no-preview"] : []
21046
21117
  ];
21047
21118
  process.exitCode = await executeTool(args);
@@ -21492,7 +21563,7 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
21492
21563
  invalidGetterHint: "If TypeScript says an extractedValues/extractedLists property does not exist, that field is not a declared Deepline getter.",
21493
21564
  observeActualShape: observedOutputCommand,
21494
21565
  observedOutput: observedOutputCommand,
21495
- forPlayGetterBugs: "Run a tiny play, inspect `deepline runs get <run-id> --full --json`, and export returned dataset handles with `deepline runs export`. Backing tables exist only for ctx.map(...).run(...) stages that actually executed.",
21566
+ forPlayGetterBugs: "Run a tiny play, inspect returned handles with `deepline runs get <run-id> --full --json`, then export row datasets with `deepline runs export`.",
21496
21567
  executeOutputFields: "tools execute JSON may include output_preview for this direct probe only; play debugging uses run output and returned dataset handles."
21497
21568
  },
21498
21569
  ...starterScript ? { starterScript } : {}
@@ -21699,12 +21770,13 @@ function parseExecuteOptions(args) {
21699
21770
  const toolId = args[0];
21700
21771
  if (!toolId) {
21701
21772
  throw new Error(
21702
- `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
21773
+ `Usage: deepline tools execute <toolId> [--param key=value ...] [--input '{"k":"v"}'] [--out rows.csv] [--output-format auto|csv|csv_file|json|json_file] [--no-preview]`
21703
21774
  );
21704
21775
  }
21705
21776
  const params = {};
21706
21777
  let outputFormat = "auto";
21707
21778
  let noPreview = false;
21779
+ let outPath = null;
21708
21780
  for (let index = 1; index < args.length; index += 1) {
21709
21781
  const arg = args[index];
21710
21782
  if ((arg === "--param" || arg === "-p") && args[index + 1]) {
@@ -21736,9 +21808,13 @@ function parseExecuteOptions(args) {
21736
21808
  noPreview = true;
21737
21809
  continue;
21738
21810
  }
21811
+ if ((arg === "--out" || arg === "-o") && args[index + 1]) {
21812
+ outPath = resolve10(args[++index]);
21813
+ continue;
21814
+ }
21739
21815
  throw new Error(`Unknown option: ${arg}`);
21740
21816
  }
21741
- return { toolId, params, outputFormat, noPreview };
21817
+ return { toolId, params, outputFormat, noPreview, outPath };
21742
21818
  }
21743
21819
  function safeFileStem(value) {
21744
21820
  return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
@@ -21782,9 +21858,14 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
21782
21858
  });
21783
21859
 
21784
21860
  const list = Object.values(result.extractedLists)[0];
21785
- const rows = (list?.get() ?? []).slice(0, 100);
21861
+ if (!list) {
21862
+ throw new Error('Expected ${input2.toolId} to expose an extracted list getter.');
21863
+ }
21864
+ const rows = list.get();
21786
21865
  // ${sampleRows}
21787
21866
  // columns: ${columns}
21867
+ // extractedLists.<name>.get() returns a dataset handle for row-shaped list outputs.
21868
+ // Pass it to ctx.dataset; use rows.peek/count/materialize only for deliberate bounded inspection.
21788
21869
  // .withColumn('email_waterfall', (row, rowCtx) => rowCtx.runPlay('name_domain_email', 'name-and-domain-to-email', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), domain: String(row.domain ?? '') }, { description: 'Resolve email.' }))
21789
21870
  // .withColumn('phone_waterfall', (row, rowCtx) => rowCtx.runPlay('contact_phone', 'contact-to-phone', { first_name: String(row.first_name ?? ''), last_name: String(row.last_name ?? ''), email: String(row.email ?? '') }, { description: 'Resolve phone.' }))
21790
21871
  // ctx.dataset is idempotent by dataset key + row key; reruns reuse completed rows.
@@ -21844,7 +21925,7 @@ function buildToolExecuteBaseEnvelope(input2) {
21844
21925
  ...summaryEntries.length > 0 ? { summary: input2.summary } : {},
21845
21926
  next: {
21846
21927
  inspect: inspectCommand,
21847
- playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
21928
+ playDebugging: "When fixing a play getter, inspect returned dataset handles with runs get and export rows with runs export; do not copy CLI preview paths blindly.",
21848
21929
  ...input2.listConversion ? {
21849
21930
  expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
21850
21931
  listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
@@ -21856,7 +21937,7 @@ function buildToolExecuteBaseEnvelope(input2) {
21856
21937
  title: "output",
21857
21938
  lines: [
21858
21939
  `${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
21859
- "paths above are observed from this execute response; use run table rows to debug play getters",
21940
+ "paths above are observed from this execute response; use runs get and runs export to validate play output",
21860
21941
  `columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
21861
21942
  `preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
21862
21943
  ]
@@ -21936,7 +22017,7 @@ async function executeTool(args) {
21936
22017
  listConversion,
21937
22018
  summary
21938
22019
  });
21939
- if (parsed.outputFormat === "json" || parsed.outputFormat === "auto" && shouldEmitJson()) {
22020
+ if (!parsed.outPath && (parsed.outputFormat === "json" || parsed.outputFormat === "auto" && shouldEmitJson())) {
21940
22021
  printCommandEnvelope(baseEnvelope, { json: true });
21941
22022
  return 0;
21942
22023
  }
@@ -21958,6 +22039,17 @@ async function executeTool(args) {
21958
22039
  return 0;
21959
22040
  }
21960
22041
  if (!listConversion) {
22042
+ if (parsed.outPath) {
22043
+ const error = new Error(
22044
+ `${parsed.toolId} did not expose row-shaped output to write as CSV. Re-run with --json to inspect the raw tool response.`
22045
+ );
22046
+ if (argsWantJson(args)) {
22047
+ printJsonError(error);
22048
+ } else {
22049
+ console.error(error.message);
22050
+ }
22051
+ return 1;
22052
+ }
21961
22053
  if (parsed.outputFormat === "csv" || parsed.outputFormat === "csv_file") {
21962
22054
  const jsonPath = writeJsonOutputFile(
21963
22055
  rawResponse,
@@ -21979,7 +22071,8 @@ async function executeTool(args) {
21979
22071
  }
21980
22072
  const csv = writeCsvOutputFile(
21981
22073
  listConversion.rows,
21982
- `${parsed.toolId}_output`
22074
+ `${parsed.toolId}_output`,
22075
+ parsed.outPath ? { outPath: parsed.outPath } : void 0
21983
22076
  );
21984
22077
  const seededScript = seedToolListScript({
21985
22078
  toolId: parsed.toolId,
@@ -22052,6 +22145,27 @@ async function executeTool(args) {
22052
22145
  );
22053
22146
  return 0;
22054
22147
  }
22148
+ if (parsed.outPath) {
22149
+ printCommandEnvelope(
22150
+ {
22151
+ ...materializedEnvelope,
22152
+ csv_path: csv.path,
22153
+ row_count: csv.rowCount,
22154
+ row_count_returned: csv.rowCount,
22155
+ columns: csv.columns,
22156
+ preview: csv.preview,
22157
+ list_strategy: listConversion.strategy,
22158
+ list_source_path: listConversion.sourcePath,
22159
+ summary
22160
+ },
22161
+ {
22162
+ json: argsWantJson(args) || shouldEmitJson(),
22163
+ text: `Wrote ${csv.rowCount} row(s) to ${csv.path}
22164
+ `
22165
+ }
22166
+ );
22167
+ return 0;
22168
+ }
22055
22169
  if (parsed.noPreview) {
22056
22170
  printCommandEnvelope(
22057
22171
  {
@@ -22072,7 +22186,7 @@ async function executeTool(args) {
22072
22186
 
22073
22187
  // src/cli/commands/workflow.ts
22074
22188
  import { mkdir as mkdir4, readFile as readFile2, writeFile as writeFile4 } from "fs/promises";
22075
- import { dirname as dirname9, join as join11, resolve as resolve11 } from "path";
22189
+ import { dirname as dirname10, join as join11, resolve as resolve11 } from "path";
22076
22190
 
22077
22191
  // src/cli/workflow-to-play.ts
22078
22192
  import { createHash as createHash3 } from "crypto";
@@ -22351,7 +22465,7 @@ async function transformOne(api, workflowId, outDir, publish) {
22351
22465
  { workflowName: workflow.name, version: revision.version }
22352
22466
  );
22353
22467
  const file = join11(resolve11(outDir), `${compiled.playName}.play.ts`);
22354
- await mkdir4(dirname9(file), { recursive: true });
22468
+ await mkdir4(dirname10(file), { recursive: true });
22355
22469
  await writeFile4(file, compiled.sourceCode, "utf8");
22356
22470
  let published = false;
22357
22471
  if (publish) {
@@ -22609,12 +22723,12 @@ import {
22609
22723
  writeFileSync as writeFileSync14
22610
22724
  } from "fs";
22611
22725
  import { homedir as homedir10 } from "os";
22612
- import { dirname as dirname11, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve as resolve12 } from "path";
22726
+ import { dirname as dirname12, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve as resolve12 } from "path";
22613
22727
 
22614
22728
  // src/cli/skills-sync.ts
22615
22729
  import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
22616
22730
  import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync13 } from "fs";
22617
- import { dirname as dirname10, join as join12 } from "path";
22731
+ import { dirname as dirname11, join as join12 } from "path";
22618
22732
 
22619
22733
  // ../shared_libs/cli/install-commands.json
22620
22734
  var install_commands_default = {
@@ -22748,7 +22862,7 @@ function sdkSkillsVersionPath(baseUrl) {
22748
22862
  return join12(sdkCliStateDirPath(baseUrl), "skills-version");
22749
22863
  }
22750
22864
  function legacySdkSkillsVersionPath(baseUrl) {
22751
- return join12(dirname10(sdkCliStateDirPath(baseUrl)), "sdk-skills", ".version");
22865
+ return join12(dirname11(sdkCliStateDirPath(baseUrl)), "sdk-skills", ".version");
22752
22866
  }
22753
22867
  function readSdkSkillsLocalVersion(baseUrl) {
22754
22868
  const pluginVersion = readPluginSkillsVersion();
@@ -22763,7 +22877,7 @@ function readSdkSkillsLocalVersion(baseUrl) {
22763
22877
  }
22764
22878
  function writeLocalSkillsVersion(baseUrl, version) {
22765
22879
  const path = sdkSkillsVersionPath(baseUrl);
22766
- mkdirSync8(dirname10(path), { recursive: true });
22880
+ mkdirSync8(dirname11(path), { recursive: true });
22767
22881
  writeFileSync13(path, `${version}
22768
22882
  `, "utf-8");
22769
22883
  }
@@ -23092,7 +23206,7 @@ function findRepoBackedSdkRoot(startPath) {
23092
23206
  if (existsSync11(join13(current, "sdk", "package.json")) && existsSync11(join13(current, "sdk", "bin", "deepline-dev.ts"))) {
23093
23207
  return current;
23094
23208
  }
23095
- const parent = dirname11(current);
23209
+ const parent = dirname12(current);
23096
23210
  if (parent === current) return null;
23097
23211
  current = parent;
23098
23212
  }
@@ -23122,7 +23236,7 @@ function resolveUpdatePlan(options = {}) {
23122
23236
  const env = options.env ?? process.env;
23123
23237
  const homeDir2 = options.homeDir ?? homedir10();
23124
23238
  const entrypoint = options.entrypoint ?? (process.argv[1] ? resolve12(process.argv[1]) : "");
23125
- const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname11(entrypoint)) : null;
23239
+ const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname12(entrypoint)) : null;
23126
23240
  if (sourceRoot) {
23127
23241
  return {
23128
23242
  kind: "source",
@@ -23201,7 +23315,7 @@ function writeAutoUpdateFailure(plan, exitCode) {
23201
23315
  manualCommand: plan.manualCommand
23202
23316
  };
23203
23317
  try {
23204
- mkdirSync9(dirname11(path), { recursive: true });
23318
+ mkdirSync9(dirname12(path), { recursive: true });
23205
23319
  writeFileSync14(path, `${JSON.stringify(marker, null, 2)}
23206
23320
  `, "utf8");
23207
23321
  } catch {
@@ -23288,7 +23402,7 @@ function runCommand(command, args, env = process.env) {
23288
23402
  });
23289
23403
  }
23290
23404
  function writeSidecarLauncher(input2) {
23291
- mkdirSync9(dirname11(input2.path), { recursive: true });
23405
+ mkdirSync9(dirname12(input2.path), { recursive: true });
23292
23406
  if (process.platform === "win32") {
23293
23407
  writeFileSync14(
23294
23408
  input2.path,
@@ -23325,7 +23439,7 @@ async function runPythonSidecarUpdatePlan(plan) {
23325
23439
  writeFileSync14(join13(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
23326
23440
  const env = {
23327
23441
  ...process.env,
23328
- PATH: `${dirname11(plan.nodeBin)}${process.platform === "win32" ? ";" : ":"}${process.env.PATH ?? ""}`
23442
+ PATH: `${dirname12(plan.nodeBin)}${process.platform === "win32" ? ";" : ":"}${process.env.PATH ?? ""}`
23329
23443
  };
23330
23444
  const installExitCode = await runCommand(
23331
23445
  plan.npmCommand,
@@ -23602,6 +23716,40 @@ function isCi() {
23602
23716
  function shouldSkipSelfUpdate() {
23603
23717
  return envTruthy("DEEPLINE_SKIP_SELF_UPDATE") || envTruthy("DEEPLINE_NO_AUTO_UPDATE") || envTruthy("DEEPLINE_SKIP_SDK_AUTO_UPDATE") || envTruthy("DEEPLINE_DISABLE_AUTO_UPDATE") || isCi();
23604
23718
  }
23719
+ function parseSemver(version) {
23720
+ const trimmed = version?.trim();
23721
+ if (!trimmed) return null;
23722
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(
23723
+ trimmed
23724
+ );
23725
+ if (!match) return null;
23726
+ return {
23727
+ major: Number(match[1]),
23728
+ minor: Number(match[2]),
23729
+ patch: Number(match[3]),
23730
+ prerelease: match[4] ?? ""
23731
+ };
23732
+ }
23733
+ function compareSemver(left, right) {
23734
+ const a = parseSemver(left);
23735
+ const b = parseSemver(right);
23736
+ if (!a || !b) {
23737
+ return left.localeCompare(right);
23738
+ }
23739
+ for (const key of ["major", "minor", "patch"]) {
23740
+ if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
23741
+ }
23742
+ if (a.prerelease === b.prerelease) return 0;
23743
+ if (!a.prerelease) return 1;
23744
+ if (!b.prerelease) return -1;
23745
+ return a.prerelease.localeCompare(b.prerelease);
23746
+ }
23747
+ function isDowngradeAutoUpdateResponse(response) {
23748
+ const target = response?.latest?.trim();
23749
+ const current = response?.current?.trim() || SDK_VERSION;
23750
+ if (!target) return false;
23751
+ return compareSemver(target, current) < 0;
23752
+ }
23605
23753
  function relaunchCurrentCommand(plan) {
23606
23754
  return new Promise((resolve13) => {
23607
23755
  const command = plan.kind === "python-sidecar" ? plan.sidecarPath : process.execPath;
@@ -23629,6 +23777,15 @@ async function maybeAutoUpdateAndRelaunch(response) {
23629
23777
  if (!response || !autoUpdate?.should_auto_update || shouldSkipSelfUpdate()) {
23630
23778
  return false;
23631
23779
  }
23780
+ if (isDowngradeAutoUpdateResponse(response)) {
23781
+ const target = response.latest;
23782
+ const current = response.current?.trim() || SDK_VERSION;
23783
+ process.stderr.write(
23784
+ `Deepline SDK/CLI auto-update refused: server advertised older ${target} than current ${current}. Continuing without mutating the CLI.
23785
+ `
23786
+ );
23787
+ return false;
23788
+ }
23632
23789
  const packageSpec = response.latest ? `deepline@${response.latest}` : void 0;
23633
23790
  const plan = resolveUpdatePlan({ packageSpec });
23634
23791
  if (plan.kind === "source") {