deepline 0.1.186 → 0.1.187

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
@@ -181,7 +181,7 @@ function configureProxyFromEnv() {
181
181
  configureProxyFromEnv();
182
182
 
183
183
  // src/cli/index.ts
184
- var import_promises5 = require("fs/promises");
184
+ var import_promises6 = require("fs/promises");
185
185
  var import_node_path20 = require("path");
186
186
  var import_node_os15 = require("os");
187
187
  var import_commander3 = require("commander");
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.186",
626
+ version: "0.1.187",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.186",
629
+ latest: "0.1.187",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -8278,13 +8278,155 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
8278
8278
  "email",
8279
8279
  "phone"
8280
8280
  ];
8281
+ var MONITOR_BOOTSTRAP_TEMPLATE = "monitor-triggered";
8282
+ var MONITOR_BOOTSTRAP_DEFAULT_TOOL = "instantly.campaign_events";
8283
+ var MONITOR_BOOTSTRAP_DEFAULT_STREAM = "webhook_events";
8284
+ function isMonitorBootstrapTemplate(value) {
8285
+ return value === MONITOR_BOOTSTRAP_TEMPLATE;
8286
+ }
8287
+ function hasMonitorBootstrapForbiddenChar(value) {
8288
+ for (const char of value) {
8289
+ const code = char.codePointAt(0) ?? 0;
8290
+ if (code < 32 || code === 127) return true;
8291
+ if (char === "'" || char === '"' || char === "`" || char === "\\") {
8292
+ return true;
8293
+ }
8294
+ }
8295
+ return false;
8296
+ }
8297
+ function validateMonitorBootstrapFlagValue(flag, value) {
8298
+ if (hasMonitorBootstrapForbiddenChar(value)) {
8299
+ throw new PlayBootstrapUsageError(
8300
+ `${flag} may not contain line breaks, control characters, quotes, or backticks. It is interpolated into the generated play source (including comments); use a plain monitor tool id / stream key / name.`
8301
+ );
8302
+ }
8303
+ return value;
8304
+ }
8305
+ function parseMonitorBootstrapOptions(args) {
8306
+ const [, ...rest] = args;
8307
+ const options = {
8308
+ name: MONITOR_BOOTSTRAP_TEMPLATE,
8309
+ tool: MONITOR_BOOTSTRAP_DEFAULT_TOOL,
8310
+ stream: MONITOR_BOOTSTRAP_DEFAULT_STREAM,
8311
+ out: null
8312
+ };
8313
+ for (let index = 0; index < rest.length; index += 1) {
8314
+ const arg = rest[index];
8315
+ const value = () => nextFlagValue(rest, index, arg);
8316
+ switch (arg) {
8317
+ case "--name":
8318
+ options.name = validateMonitorBootstrapFlagValue("--name", value());
8319
+ index += 1;
8320
+ break;
8321
+ case "--tool":
8322
+ options.tool = validateMonitorBootstrapFlagValue("--tool", value());
8323
+ index += 1;
8324
+ break;
8325
+ case "--stream":
8326
+ options.stream = validateMonitorBootstrapFlagValue("--stream", value());
8327
+ index += 1;
8328
+ break;
8329
+ case "--out":
8330
+ options.out = value();
8331
+ index += 1;
8332
+ break;
8333
+ default:
8334
+ throw new PlayBootstrapUsageError(
8335
+ `Unknown plays bootstrap option for ${MONITOR_BOOTSTRAP_TEMPLATE}: ${arg}
8336
+ Usage: deepline plays bootstrap ${MONITOR_BOOTSTRAP_TEMPLATE} [--tool <monitor-tool-id>] [--stream <stream-key>] [--name NAME] [--out monitor.play.ts]`
8337
+ );
8338
+ }
8339
+ }
8340
+ if (!options.tool) {
8341
+ throw new PlayBootstrapUsageError(
8342
+ `${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --tool.`
8343
+ );
8344
+ }
8345
+ if (!options.stream) {
8346
+ throw new PlayBootstrapUsageError(
8347
+ `${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --stream.`
8348
+ );
8349
+ }
8350
+ return options;
8351
+ }
8352
+ function generateMonitorTriggeredPlaySource(options) {
8353
+ return `import { definePlay } from 'deepline';
8354
+ import type { SqlListenerEvent } from 'deepline';
8355
+
8356
+ // Row shape delivered by ${options.tool} / ${options.stream}. This is a starting
8357
+ // point only: inspect the real columns with
8358
+ // deepline monitors available ${options.tool}
8359
+ // and tighten this type to the fields you read below.
8360
+ //
8361
+ // Before deploying a NEW monitor, run \`deepline monitors list\` \u2014 if one
8362
+ // already feeds this stream for your scope, this play will already react to its
8363
+ // rows (a play binds to the shared stream), so you may not need to deploy at all.
8364
+ type MonitorRow = Record<string, unknown>;
8365
+
8366
+ export default definePlay(
8367
+ ${jsString(options.name)},
8368
+ async (ctx, event: SqlListenerEvent<MonitorRow>) => {
8369
+ // The monitor delivers the changed row as event.after. It is null for
8370
+ // DELETE operations, so guard before reading fields.
8371
+ const row = event.after;
8372
+ if (!row) {
8373
+ ctx.log(\`Monitor \${event.tool}/\${event.stream} \${event.operation} with no row; nothing to do.\`);
8374
+ return { handled: false, operation: event.operation };
8375
+ }
8376
+
8377
+ ctx.log(
8378
+ \`Monitor \${event.tool}/\${event.stream} \${event.operation}: \${JSON.stringify(row).slice(0, 200)}\`,
8379
+ );
8380
+
8381
+ // Capture the changed row into a durable dataset so the run has inspectable,
8382
+ // exportable output. ctx.dataset is a CALLABLE: ctx.dataset(key, rows) where
8383
+ // key is a compile-time string LITERAL and rows is an array of row objects.
8384
+ // It returns a builder; add per-row columns with .withColumn(name, resolver)
8385
+ // and finish with .run(). There is no .push/.add \u2014 pass all rows up front.
8386
+ // TODO: replace this plain persist with your real per-row work \u2014 enrich each
8387
+ // row via .withColumn('...', (row, rowCtx) => rowCtx.tools.execute(...)),
8388
+ // notify, write to another table, or fan out with rowCtx.runPlay.
8389
+ const captured = await ctx.dataset('monitor_events', [row]).run({
8390
+ description: \`Captured \${event.tool}/\${event.stream} \${event.operation} rows.\`,
8391
+ });
8392
+
8393
+ return {
8394
+ handled: true,
8395
+ tool: event.tool,
8396
+ stream: event.stream,
8397
+ operation: event.operation,
8398
+ changedAt: event.changedAt,
8399
+ capturedRows: await captured.count(),
8400
+ };
8401
+ },
8402
+ {
8403
+ description: ${jsString(`Run whenever ${options.tool} writes a new ${options.stream} row.`)},
8404
+ // A monitor trigger: this play wakes on row changes written by the bound
8405
+ // monitor tool + stream. Discover a tool's streams and columns with:
8406
+ // deepline monitors available ${options.tool}
8407
+ // To bind a different monitor, swap tool/stream (and re-check operations)
8408
+ // for one of its (tool, stream) pairs.
8409
+ sqlListeners: [
8410
+ {
8411
+ id: 'events',
8412
+ tool: ${jsString(options.tool)},
8413
+ stream: ${jsString(options.stream)},
8414
+ operations: ['INSERT'],
8415
+ // Optional: only wake on some rows \u2014 add a where filter to the binding above:
8416
+ // where: { after: { <column>: { eq: 'value' } } } // operators: eq, neq, in, notIn, isNull, isNotNull, ilike
8417
+ },
8418
+ ],
8419
+ },
8420
+ );
8421
+ `;
8422
+ }
8281
8423
  function playBootstrapUsageLine() {
8282
8424
  return `Usage: deepline plays bootstrap <${formatPlayBootstrapTemplates()}> --from <csv:PATH|play:REF|provider:ID|providers:ID,ID> [--using <play:REF|providers:ID,ID>] [--people play:REF] [--email <play:REF|providers:ID,ID>] [--phone <play:REF|providers:ID,ID>] [--limit 5] [--out flow.play.ts]`;
8283
8425
  }
8284
8426
  function requireBootstrapTemplate(rawTemplate) {
8285
8427
  if (!rawTemplate) {
8286
8428
  throw new PlayBootstrapUsageError(
8287
- `plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
8429
+ `plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}.
8288
8430
  Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using play:prebuilt/name-and-domain-to-email-waterfall --out email-flow.play.ts`
8289
8431
  );
8290
8432
  }
@@ -8292,7 +8434,7 @@ Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using
8292
8434
  const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
8293
8435
  throw new PlayBootstrapUsageError(
8294
8436
  `Unknown plays bootstrap template: ${rawTemplate}
8295
- Supported templates: ${formatPlayBootstrapTemplates()}` + (looksLikePlayReference ? `
8437
+ Supported templates: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}` + (looksLikePlayReference ? `
8296
8438
 
8297
8439
  "${rawTemplate}" looks like an existing play reference or file, not a bootstrap template. Do not run plays bootstrap on prebuilt/<play-name>. Use "deepline plays run ${rawTemplate} --input '{...}' --watch" to run it directly, "deepline plays describe ${rawTemplate} --json" to inspect its contract, or "deepline plays get ${rawTemplate} --source --out scratchpad.play.ts" to clone/edit it.` : "")
8298
8440
  );
@@ -9501,7 +9643,25 @@ function renderPlayBootstrapError(error) {
9501
9643
  console.error(errorMessage2(error));
9502
9644
  return error instanceof PlayBootstrapError ? error.exitCode : 1;
9503
9645
  }
9646
+ function writeBootstrapSource(source, out) {
9647
+ if (out) {
9648
+ (0, import_node_fs9.writeFileSync)((0, import_node_path10.resolve)(out), source, "utf-8");
9649
+ process.stdout.write(`Wrote ${(0, import_node_path10.resolve)(out)}
9650
+ `);
9651
+ return 0;
9652
+ }
9653
+ process.stdout.write(source);
9654
+ return 0;
9655
+ }
9656
+ function runMonitorBootstrap(args) {
9657
+ const options = parseMonitorBootstrapOptions(args);
9658
+ const source = generateMonitorTriggeredPlaySource(options);
9659
+ return writeBootstrapSource(source, options.out);
9660
+ }
9504
9661
  async function runPlayBootstrap(args) {
9662
+ if (isMonitorBootstrapTemplate(args[0])) {
9663
+ return runMonitorBootstrap(args);
9664
+ }
9505
9665
  const options = parsePlayBootstrapOptions(args);
9506
9666
  const client2 = new DeeplineClient();
9507
9667
  const contracts = await loadBootstrapContracts(client2, options);
@@ -9511,20 +9671,15 @@ async function runPlayBootstrap(args) {
9511
9671
  ...contracts,
9512
9672
  ...csvContext
9513
9673
  });
9514
- if (options.out) {
9515
- (0, import_node_fs9.writeFileSync)((0, import_node_path10.resolve)(options.out), source, "utf-8");
9516
- process.stdout.write(`Wrote ${(0, import_node_path10.resolve)(options.out)}
9517
- `);
9518
- return 0;
9519
- }
9520
- process.stdout.write(source);
9521
- return 0;
9674
+ return writeBootstrapSource(source, options.out);
9522
9675
  }
9523
9676
  async function handlePlayBootstrap(args) {
9524
9677
  return runPlayBootstrap(args).catch(renderPlayBootstrapError);
9525
9678
  }
9526
9679
  function registerPlayBootstrapCommand(play) {
9527
- play.command("bootstrap <template>").description("Print a scratchpad play for a GTM route template.").addHelpText(
9680
+ play.command("bootstrap <template>").description(
9681
+ "Print a scratchpad play for a GTM route or monitor-triggered template."
9682
+ ).addHelpText(
9528
9683
  "after",
9529
9684
  `
9530
9685
  Notes:
@@ -9548,6 +9703,13 @@ Notes:
9548
9703
  company-people company/account rows -> people play
9549
9704
  company-people-email company/account rows -> people play -> email finder
9550
9705
  company-people-phone company/account rows -> people play -> phone finder
9706
+ monitor-triggered run a play whenever a monitor writes a new row
9707
+ (definePlay with sqlListeners; no --from/stage flags)
9708
+
9709
+ Monitor-triggered options (only for the monitor-triggered template):
9710
+ --tool <monitor-tool-id> monitor tool to bind (default instantly.campaign_events)
9711
+ --stream <stream-key> output stream to listen on (default webhook_events)
9712
+ Discover a tool's streams/columns with: deepline monitors available <id>
9551
9713
 
9552
9714
  Resource refs:
9553
9715
  csv:./contacts.csv
@@ -9577,6 +9739,9 @@ Examples:
9577
9739
  deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 --out prospecting.play.ts
9578
9740
  deepline plays bootstrap company-people-email --from provider:crustdata_companydb_search --people play:prebuilt/company-to-contact --email play:prebuilt/name-and-domain-to-email-waterfall --limit 5 --out account-contacts.play.ts
9579
9741
  deepline plays bootstrap company-list --from provider:crustdata_companydb_search --limit 5 --out companies.play.ts
9742
+
9743
+ deepline plays bootstrap monitor-triggered --out on-new-row.play.ts
9744
+ deepline plays bootstrap monitor-triggered --tool tamradar.company_radar --stream company_job_openings --out on-new-job.play.ts
9580
9745
  `
9581
9746
  ).option("--name <name>", "Generated play name").option(
9582
9747
  "--from <ref>",
@@ -9593,7 +9758,13 @@ Examples:
9593
9758
  ).option(
9594
9759
  "--phone <ref>",
9595
9760
  "Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
9596
- ).option("--limit <n>", "Maximum rows to fan out in the generated play").option("--out <path>", "Write generated play source to a file").action(async (template, options) => {
9761
+ ).option("--limit <n>", "Maximum rows to fan out in the generated play").option(
9762
+ "--tool <id>",
9763
+ "monitor-triggered only: monitor tool id to bind (e.g. instantly.campaign_events)"
9764
+ ).option(
9765
+ "--stream <key>",
9766
+ "monitor-triggered only: monitor output stream to listen on (e.g. webhook_events)"
9767
+ ).option("--out <path>", "Write generated play source to a file").action(async (template, options) => {
9597
9768
  process.exitCode = await handlePlayBootstrap([
9598
9769
  template,
9599
9770
  ...options.name ? ["--name", options.name] : [],
@@ -9603,6 +9774,8 @@ Examples:
9603
9774
  ...options.email ? ["--email", options.email] : [],
9604
9775
  ...options.phone ? ["--phone", options.phone] : [],
9605
9776
  ...options.limit ? ["--limit", options.limit] : [],
9777
+ ...options.tool ? ["--tool", options.tool] : [],
9778
+ ...options.stream ? ["--stream", options.stream] : [],
9606
9779
  ...options.out ? ["--out", options.out] : []
9607
9780
  ]);
9608
9781
  });
@@ -13527,6 +13700,89 @@ function printToolGetterHints(hints) {
13527
13700
  if (hint.unavailable) console.log(` - warning: ${hint.unavailable}`);
13528
13701
  }
13529
13702
  }
13703
+ function printPlayTriggers(triggers) {
13704
+ if (!triggers) return;
13705
+ const hasAny = (triggers.sqlListeners?.length ?? 0) > 0 || Boolean(triggers.cron) || triggers.webhook === true;
13706
+ if (!hasAny) return;
13707
+ console.log(" triggers:");
13708
+ for (const listener of triggers.sqlListeners ?? []) {
13709
+ const target = listener.tool && listener.stream ? `${listener.tool}/${listener.stream}` : listener.tool ?? listener.stream ?? listener.id;
13710
+ const operations = listener.operations.length ? listener.operations.join(", ") : "INSERT, UPDATE";
13711
+ const whereNote = listener.where ? " (with where filter)" : "";
13712
+ console.log(` sqlListeners \u2192 ${target} on ${operations}${whereNote}`);
13713
+ }
13714
+ if (triggers.cron) {
13715
+ const timezone = triggers.cron.timezone ? ` (${triggers.cron.timezone})` : "";
13716
+ console.log(` cron \u2192 ${triggers.cron.schedule}${timezone}`);
13717
+ }
13718
+ if (triggers.webhook === true) {
13719
+ console.log(" webhook \u2192 enabled");
13720
+ }
13721
+ }
13722
+ function printRecognizedSummary(recognized) {
13723
+ if (!recognized) return;
13724
+ if (recognized.tools?.length) {
13725
+ console.log(` tools: ${recognized.tools.join(", ")}`);
13726
+ }
13727
+ for (const dataset of recognized.datasets ?? []) {
13728
+ const columns = dataset.columns?.length ? ` (${dataset.columns.length} col${dataset.columns.length === 1 ? "" : "s"}: ${dataset.columns.join(", ")})` : "";
13729
+ console.log(` dataset ${dataset.name}${columns}`);
13730
+ }
13731
+ if (recognized.inputs?.length) {
13732
+ console.log(` inputs: ${recognized.inputs.join(", ")}`);
13733
+ }
13734
+ if (recognized.outputs?.length) {
13735
+ console.log(` outputs: ${recognized.outputs.join(", ")}`);
13736
+ }
13737
+ }
13738
+ function formatPlayCheckIssueLines(issue) {
13739
+ const lines = [` - ${issue.message}`];
13740
+ if (issue.path) {
13741
+ lines.push(` at ${issue.path}`);
13742
+ }
13743
+ if (issue.validOptions?.length) {
13744
+ lines.push(` \u2192 valid: [${issue.validOptions.join(", ")}]`);
13745
+ }
13746
+ if (issue.hint?.trim()) {
13747
+ lines.push(` hint: ${issue.hint.trim()}`);
13748
+ }
13749
+ if (issue.docsHint?.trim()) {
13750
+ lines.push(` next: ${issue.docsHint.trim()}`);
13751
+ }
13752
+ return lines;
13753
+ }
13754
+ function printPlayCheckIssues(issues, writer) {
13755
+ if (!issues?.length) return;
13756
+ const errorIssues = issues.filter((issue) => issue.severity === "error");
13757
+ const warningIssues = issues.filter((issue) => issue.severity === "warning");
13758
+ if (errorIssues.length) {
13759
+ writer(" issues:");
13760
+ for (const issue of errorIssues) {
13761
+ for (const line of formatPlayCheckIssueLines(issue)) writer(line);
13762
+ }
13763
+ }
13764
+ if (warningIssues.length) {
13765
+ writer(" warnings:");
13766
+ for (const issue of warningIssues) {
13767
+ for (const line of formatPlayCheckIssueLines(issue)) writer(line);
13768
+ }
13769
+ }
13770
+ }
13771
+ function partitionMirroredErrors(errors, issues) {
13772
+ const errorMessages = (issues ?? []).filter((issue) => issue.severity === "error").map((issue) => issue.message.trim()).filter((message) => message.length > 0);
13773
+ if (errorMessages.length === 0) {
13774
+ return { unstructuredErrors: errors ?? [] };
13775
+ }
13776
+ const isMirror = (error) => {
13777
+ const trimmed = error.trim();
13778
+ return errorMessages.some(
13779
+ (message) => trimmed === message || trimmed.startsWith(message)
13780
+ );
13781
+ };
13782
+ return {
13783
+ unstructuredErrors: (errors ?? []).filter((error) => !isMirror(error))
13784
+ };
13785
+ }
13530
13786
  async function handlePlayCheck(args) {
13531
13787
  const options = parsePlayCheckOptions(args);
13532
13788
  if (!isFileTarget(options.target)) {
@@ -13659,16 +13915,27 @@ async function handlePlayCheck(args) {
13659
13915
  `
13660
13916
  );
13661
13917
  } else if (enrichedResult.valid) {
13662
- console.log(`\u2713 ${playName} passed cloud play check`);
13918
+ const summary = enrichedResult.summary?.trim();
13919
+ console.log(
13920
+ summary ? `\u2713 ${playName} valid \u2014 ${summary}` : `\u2713 ${playName} passed cloud play check`
13921
+ );
13663
13922
  if (enrichedResult.artifactHash) {
13664
13923
  console.log(` artifact: ${enrichedResult.artifactHash.slice(0, 12)}`);
13665
13924
  }
13925
+ printPlayTriggers(enrichedResult.triggers);
13926
+ printRecognizedSummary(enrichedResult.recognized);
13927
+ printPlayCheckIssues(enrichedResult.issues, (line) => console.log(line));
13666
13928
  printToolGetterHints(enrichedResult.toolGetterHints);
13667
13929
  } else {
13668
13930
  console.error(`\u2717 ${playName} failed cloud play check`);
13669
- for (const error of enrichedResult.errors) {
13931
+ const { unstructuredErrors } = partitionMirroredErrors(
13932
+ enrichedResult.errors,
13933
+ enrichedResult.issues
13934
+ );
13935
+ for (const error of unstructuredErrors) {
13670
13936
  console.error(` ${error}`);
13671
13937
  }
13938
+ printPlayCheckIssues(enrichedResult.issues, (line) => console.error(line));
13672
13939
  printToolGetterHints(enrichedResult.toolGetterHints);
13673
13940
  }
13674
13941
  return enrichedResult.valid ? 0 : 1;
@@ -21763,44 +22030,455 @@ Examples:
21763
22030
  }
21764
22031
 
21765
22032
  // src/cli/commands/monitors.ts
22033
+ var import_node_fs12 = require("fs");
22034
+ var import_promises4 = require("readline/promises");
21766
22035
  var FORBIDDEN_AS_API_ERROR = { forbiddenAsApiError: true };
22036
+ var JSON_OPTION_DESCRIPTION = "Emit JSON output. Also automatic when stdout is piped";
22037
+ function withJsonOption(command) {
22038
+ return command.option("--json", JSON_OPTION_DESCRIPTION);
22039
+ }
22040
+ var COMPACT_OPTION_DESCRIPTION = "Ask the server for high-signal fields only (smaller output for agent loops)";
21767
22041
  function buildHttpClient() {
21768
22042
  return new HttpClient(resolveConfig());
21769
22043
  }
21770
- function parseJsonObjectArg(raw, flag) {
22044
+ var MonitorsUsageError = class extends Error {
22045
+ code = "MONITORS_USAGE_ERROR";
22046
+ constructor(message) {
22047
+ super(message);
22048
+ this.name = "MonitorsUsageError";
22049
+ }
22050
+ };
22051
+ var MonitorDryRunUnsupportedError = class extends Error {
22052
+ code = "MONITOR_DRY_RUN_UNSUPPORTED";
22053
+ constructor(message) {
22054
+ super(message);
22055
+ this.name = "MonitorDryRunUnsupportedError";
22056
+ }
22057
+ };
22058
+ function monitorsErrorExitCode(error) {
22059
+ if (error instanceof MonitorsUsageError) return 2;
22060
+ if (error instanceof AuthError) return 3;
22061
+ if (error instanceof DeeplineError) {
22062
+ const status = error.statusCode;
22063
+ if (status === 401 || status === 403) return 3;
22064
+ if (status === 404) return 4;
22065
+ if (status === 400 || status === 422) return 7;
22066
+ return 5;
22067
+ }
22068
+ return 5;
22069
+ }
22070
+ function monitorsFailureNextCommand(error, exitCode) {
22071
+ if (error instanceof DeeplineError && error.code === "monitor_access_required") {
22072
+ return "deepline monitors status";
22073
+ }
22074
+ if (exitCode === 3) return "deepline auth status --json";
22075
+ if (exitCode === 4) return "deepline monitors list --status all --json";
22076
+ return void 0;
22077
+ }
22078
+ function readValidationIssues(error) {
22079
+ if (!(error instanceof DeeplineError)) return [];
22080
+ const response = asRecord(asRecord(error.details)?.response);
22081
+ const issues = Array.isArray(response?.issues) ? response.issues : [];
22082
+ return issues.flatMap((raw) => {
22083
+ const issue = asRecord(raw);
22084
+ if (!issue) return [];
22085
+ return [
22086
+ {
22087
+ ...asString(issue.path) ? { path: asString(issue.path) } : {},
22088
+ ...asString(issue.message) ? { message: asString(issue.message) } : {}
22089
+ }
22090
+ ];
22091
+ });
22092
+ }
22093
+ function reportMonitorsFailure(error) {
22094
+ const exitCode = monitorsErrorExitCode(error);
22095
+ const next = monitorsFailureNextCommand(error, exitCode);
22096
+ const wantsJson = shouldEmitJson(process.argv.includes("--json"));
22097
+ if (wantsJson) {
22098
+ const payload = errorToJsonPayload(error);
22099
+ printJson({
22100
+ ok: false,
22101
+ exitCode,
22102
+ ...next ? { next } : {},
22103
+ error: payload.error
22104
+ });
22105
+ } else {
22106
+ const message = error instanceof Error ? error.message : String(error);
22107
+ process.stderr.write(`Error: ${message}
22108
+ `);
22109
+ for (const issue of readValidationIssues(error)) {
22110
+ process.stderr.write(
22111
+ ` - ${issue.path ? `${issue.path}: ` : ""}${issue.message ?? ""}
22112
+ `
22113
+ );
22114
+ }
22115
+ if (next) process.stderr.write(`Next: ${next}
22116
+ `);
22117
+ }
22118
+ process.exitCode = exitCode;
22119
+ }
22120
+ function monitorsAction(handler) {
22121
+ return async (...args) => {
22122
+ try {
22123
+ await handler(...args);
22124
+ } catch (error) {
22125
+ reportMonitorsFailure(error);
22126
+ }
22127
+ };
22128
+ }
22129
+ function parseJsonObjectArg(raw, argLabel) {
21771
22130
  let parsed;
21772
22131
  try {
21773
22132
  parsed = JSON.parse(raw);
21774
22133
  } catch (error) {
21775
- throw new Error(
21776
- `${flag} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
22134
+ throw new MonitorsUsageError(
22135
+ `${argLabel} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
21777
22136
  );
21778
22137
  }
21779
22138
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
21780
- throw new Error(`${flag} must be a JSON object.`);
22139
+ throw new MonitorsUsageError(`${argLabel} must be a JSON object.`);
21781
22140
  }
21782
22141
  return parsed;
21783
22142
  }
22143
+ function resolveMonitorJsonBody(input2) {
22144
+ const readFile3 = input2.readFile ?? ((path) => (0, import_node_fs12.readFileSync)(path, "utf-8"));
22145
+ const readStdin = input2.readStdin ?? (() => (0, import_node_fs12.readFileSync)(0, "utf-8"));
22146
+ if (input2.positional !== void 0 && input2.file !== void 0) {
22147
+ throw new MonitorsUsageError(
22148
+ `Pass exactly one source for ${input2.argLabel}: the positional JSON or --file, not both.`
22149
+ );
22150
+ }
22151
+ if (input2.positional !== void 0) {
22152
+ return parseJsonObjectArg(input2.positional, input2.argLabel);
22153
+ }
22154
+ if (input2.file !== void 0) {
22155
+ if (input2.file === "-") {
22156
+ return parseJsonObjectArg(readStdin(), `${input2.argLabel} (stdin)`);
22157
+ }
22158
+ let raw;
22159
+ try {
22160
+ raw = readFile3(input2.file);
22161
+ } catch (error) {
22162
+ throw new MonitorsUsageError(
22163
+ `Could not read --file ${input2.file}: ${error instanceof Error ? error.message : String(error)}`
22164
+ );
22165
+ }
22166
+ return parseJsonObjectArg(raw, `${input2.argLabel} (--file ${input2.file})`);
22167
+ }
22168
+ throw new MonitorsUsageError(
22169
+ `${input2.command} needs ${input2.argLabel} (a JSON object). Pass it positionally:
22170
+ ${input2.command} '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
22171
+ or from a file / stdin:
22172
+ ${input2.command} --file monitor.json
22173
+ cat monitor.json | ${input2.command} --file -`
22174
+ );
22175
+ }
21784
22176
  function encodeKey(key) {
21785
22177
  return encodeURIComponent(key);
21786
22178
  }
21787
- async function handleMonitorsTools(options) {
22179
+ function asRecord(value) {
22180
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
22181
+ }
22182
+ function asString(value) {
22183
+ return typeof value === "string" && value.trim() ? value : void 0;
22184
+ }
22185
+ function asFiniteNumber(value) {
22186
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
22187
+ }
22188
+ function yesNo(value) {
22189
+ if (value === true) return "yes";
22190
+ if (value === false) return "no";
22191
+ return "unknown";
22192
+ }
22193
+ function readDeployOutputContract(payload) {
22194
+ const contract = asRecord(payload.output_contract);
22195
+ if (!contract) return { streams: [] };
22196
+ const rawOutputs = Array.isArray(contract.outputs) ? contract.outputs : [];
22197
+ const streams = rawOutputs.flatMap((raw) => {
22198
+ const output2 = asRecord(raw);
22199
+ const stream = output2 ? asString(output2.stream) : void 0;
22200
+ const table = output2 ? asString(output2.table) : void 0;
22201
+ if (!output2 || !stream || !table) return [];
22202
+ const columns = Array.isArray(output2.columns) ? output2.columns.flatMap((rawColumn) => {
22203
+ const column = asRecord(rawColumn);
22204
+ const name = column ? asString(column.name) : void 0;
22205
+ return name ? [name] : [];
22206
+ }) : [];
22207
+ return [
22208
+ {
22209
+ stream,
22210
+ table,
22211
+ columns,
22212
+ isEvent: output2.is_event_stream === true,
22213
+ matchesPayload: output2.matches_payload === true
22214
+ }
22215
+ ];
22216
+ });
22217
+ return { tool: asString(contract.tool), streams };
22218
+ }
22219
+ function renderMonitorDeployCompletion(payload) {
22220
+ const monitor = asRecord(payload.monitor);
22221
+ const key = monitor ? asString(monitor.key) : void 0;
22222
+ const { tool, streams } = readDeployOutputContract(payload);
22223
+ if (!key || streams.length === 0) return void 0;
22224
+ const toolId = tool ?? (monitor ? asString(monitor.tool) : void 0) ?? "<tool>";
22225
+ const name = monitor ? asString(monitor.name) : void 0;
22226
+ const status = monitor ? asString(monitor.status) : void 0;
22227
+ const eventStreams = streams.filter((stream) => stream.isEvent);
22228
+ const matched = eventStreams.filter((stream) => stream.matchesPayload);
22229
+ const shown = matched.length ? matched : eventStreams.length ? eventStreams : streams;
22230
+ const primary = shown[0];
22231
+ const lines = [
22232
+ `\u2713 Deployed monitor "${key}"${name ? ` (${name})` : ""} \u2014 tool ${toolId}${status ? `, status ${status}` : ""}`,
22233
+ "",
22234
+ "Output \u2192 Customer DB:"
22235
+ ];
22236
+ for (const stream of shown) {
22237
+ lines.push(` ${stream.table} (stream: ${stream.stream})`);
22238
+ lines.push(
22239
+ ` columns: ${stream.columns.length ? stream.columns.join(", ") : "(promoted dynamically as events arrive)"}`
22240
+ );
22241
+ }
22242
+ lines.push(
22243
+ "",
22244
+ "This monitor streams new rows into your Customer DB \u2014 there is no manual run.",
22245
+ "Next:",
22246
+ " \u2022 Query the table above directly, or",
22247
+ " \u2022 Run a play on each new row (third arg to definePlay in your .play.ts):",
22248
+ ` sqlListeners: [{ id: '${primary.stream}', tool: '${toolId}', stream: '${primary.stream}', operations: ['INSERT'] }]`,
22249
+ " The changed row arrives to your handler as the sqlListener event's `after`.",
22250
+ "",
22251
+ "Reuse: many plays can bind to this one stream \u2014 you do NOT need a separate",
22252
+ "monitor per play. Before deploying another monitor on this tool, run",
22253
+ "`deepline monitors list` and reuse an existing one that covers your scope."
22254
+ );
22255
+ return `${lines.join("\n")}
22256
+ `;
22257
+ }
22258
+ function renderMonitorDeployPlan(payload) {
22259
+ const valid = payload.valid !== false;
22260
+ const lines = [
22261
+ "DRY RUN \u2014 nothing was deployed.",
22262
+ valid ? "Definition: valid" : "Definition: INVALID"
22263
+ ];
22264
+ if (!valid) {
22265
+ const issues = Array.isArray(payload.issues) ? payload.issues : [];
22266
+ for (const raw of issues) {
22267
+ const issue = asRecord(raw);
22268
+ const path = issue ? asString(issue.path) : void 0;
22269
+ const message = issue ? asString(issue.message) : void 0;
22270
+ if (message) lines.push(` - ${path ? `${path}: ` : ""}${message}`);
22271
+ }
22272
+ }
22273
+ const estimate = asRecord(payload.deploy_cost_estimate);
22274
+ const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
22275
+ if (credits !== void 0) {
22276
+ const note = estimate ? asString(estimate.note) : void 0;
22277
+ lines.push(
22278
+ `Deploy cost: would cost ${credits} Deepline credits${note ? ` \u2014 ${note}` : ""}.`
22279
+ );
22280
+ } else {
22281
+ lines.push(
22282
+ "Deploy cost: estimate unavailable from this server (validation only)."
22283
+ );
22284
+ }
22285
+ const candidates = Array.isArray(payload.reuse_candidates) ? payload.reuse_candidates : [];
22286
+ const candidateLines = candidates.flatMap((raw) => {
22287
+ const candidate = asRecord(raw);
22288
+ const key = candidate ? asString(candidate.key) : void 0;
22289
+ if (!candidate || !key) return [];
22290
+ const name = asString(candidate.name);
22291
+ const status = asString(candidate.status);
22292
+ const covers = asString(candidate.covers);
22293
+ return [
22294
+ ` ${key}${name ? ` (${name})` : ""}${status ? ` \u2014 ${status}` : ""}${covers ? `; covers ${covers}` : ""}`
22295
+ ];
22296
+ });
22297
+ if (candidateLines.length > 0) {
22298
+ lines.push(
22299
+ "",
22300
+ "You may already have a monitor covering this \u2014 check before deploying:",
22301
+ ...candidateLines,
22302
+ " Inspect: deepline monitors get <key> --json"
22303
+ );
22304
+ }
22305
+ lines.push(
22306
+ "",
22307
+ valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
22308
+ );
22309
+ return `${lines.join("\n")}
22310
+ `;
22311
+ }
22312
+ function renderMonitorDeletePlan(payload, fallbackKey) {
22313
+ const plan = asRecord(payload.plan);
22314
+ const key = (plan ? asString(plan.monitor_key) : void 0) ?? fallbackKey;
22315
+ const lines = [
22316
+ "DRY RUN \u2014 nothing was deleted.",
22317
+ `Delete plan for monitor "${key}":`,
22318
+ ` delete Deepline record: ${yesNo(plan?.would_delete_record)}`,
22319
+ ` deprovision upstream provider resource: ${yesNo(plan?.would_deprovision_upstream)}`,
22320
+ "",
22321
+ `Delete for real: deepline monitors delete ${key} --yes`
22322
+ ];
22323
+ return `${lines.join("\n")}
22324
+ `;
22325
+ }
22326
+ function renderMonitorReactivatePlan(payload, key) {
22327
+ const estimate = asRecord(payload.cost_estimate);
22328
+ const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
22329
+ const lines = [
22330
+ "DRY RUN \u2014 nothing was reactivated.",
22331
+ credits !== void 0 ? `Reactivate cost: would cost ${credits} Deepline credits.` : "Reactivate cost: estimate unavailable from this server.",
22332
+ "",
22333
+ `Reactivate for real: deepline monitors reactivate ${key}`
22334
+ ];
22335
+ return `${lines.join("\n")}
22336
+ `;
22337
+ }
22338
+ function assertMonitorDryRunAcknowledged(payload, context) {
22339
+ if (payload.dry_run === true) return;
22340
+ throw new MonitorDryRunUnsupportedError(
22341
+ `${context.command} --dry-run: the server response did not acknowledge dry-run mode (missing "dry_run": true). This Deepline server may not support --dry-run for ${context.mutation}, so the response cannot be trusted as a plan. Nothing was rendered as a plan. Verify current state with \`deepline monitors get <key> --json\`, and re-run without --dry-run only when you intend the real ${context.mutation}.`
22342
+ );
22343
+ }
22344
+ function monitorDeleteRequiresYesError(key, options = {}) {
22345
+ const flags = options.localOnly ? " --local-only" : "";
22346
+ return new MonitorsUsageError(
22347
+ `monitors delete is destructive: it deletes monitor "${key}"${options.localOnly ? " (Deepline record only)" : " and deprovisions its upstream provider resource"}. Non-interactive runs must confirm with --yes:
22348
+ deepline monitors delete ${key}${flags} --yes
22349
+ Preview the plan first with:
22350
+ deepline monitors delete ${key}${flags} --dry-run`
22351
+ );
22352
+ }
22353
+ async function handleMonitorsStatus(options) {
22354
+ const http = buildHttpClient();
22355
+ const payload = await http.request(
22356
+ "/api/v2/monitors/access",
22357
+ { method: "GET" }
22358
+ );
22359
+ const hasAccess = payload.has_access === true;
22360
+ const reason = typeof payload.reason === "string" && payload.reason.trim() ? payload.reason.trim() : void 0;
22361
+ const text = hasAccess ? `\u2713 You have access to Deepline Monitors${reason ? `
22362
+ ${reason}` : ""}
22363
+ ` : `\u2717 No access to Deepline Monitors${reason ? ` \u2014 ${reason}` : ""}
22364
+ `;
22365
+ printCommandEnvelope(
22366
+ { has_access: hasAccess, ...reason ? { reason } : {} },
22367
+ { json: options.json, text }
22368
+ );
22369
+ if (!hasAccess) {
22370
+ process.exitCode = 1;
22371
+ }
22372
+ }
22373
+ function renderAvailableToolsText(payload) {
22374
+ const tools = Array.isArray(payload.tools) ? payload.tools : null;
22375
+ if (!tools) return void 0;
22376
+ const returned = asFiniteNumber(payload.returned) ?? tools.length;
22377
+ const total = asFiniteNumber(payload.total);
22378
+ const lines = [
22379
+ total !== void 0 ? `Monitor tools you can deploy (${returned} of ${total}):` : "Monitor tools you can deploy:"
22380
+ ];
22381
+ for (const raw of tools) {
22382
+ const entry = asRecord(raw);
22383
+ const id = entry ? asString(entry.tool) : void 0;
22384
+ if (!entry || !id) continue;
22385
+ const name = asString(entry.name) ?? asString(entry.display_name);
22386
+ const deployedCount = asFiniteNumber(entry.deployed_count);
22387
+ lines.push(
22388
+ ` ${id}${name ? ` \u2014 ${name}` : ""}${deployedCount !== void 0 ? ` (deployed: ${deployedCount})` : ""}`
22389
+ );
22390
+ }
22391
+ if (payload.is_truncated === true) {
22392
+ lines.push("List truncated; raise --limit to see more.");
22393
+ }
22394
+ lines.push(
22395
+ "",
22396
+ "Describe one (payload schema + output streams): deepline monitors available <tool-id> --json"
22397
+ );
22398
+ return `${lines.join("\n")}
22399
+ `;
22400
+ }
22401
+ async function handleMonitorsAvailable(toolId, options) {
22402
+ if (toolId !== void 0 && options.tool !== void 0) {
22403
+ if (toolId !== options.tool) {
22404
+ throw new MonitorsUsageError(
22405
+ `Pass the tool id once: got positional "${toolId}" and --tool "${options.tool}". Use: deepline monitors available ${toolId}`
22406
+ );
22407
+ }
22408
+ }
22409
+ const tool = toolId ?? options.tool;
21788
22410
  const http = buildHttpClient();
21789
22411
  const params = new URLSearchParams();
21790
22412
  if (options.provider) params.set("provider", options.provider);
21791
- if (options.tool) params.set("tool", options.tool);
22413
+ if (tool) params.set("tool", tool);
21792
22414
  if (options.search) params.set("search", options.search);
21793
22415
  if (options.limit) params.set("limit", options.limit);
22416
+ const compactList = !tool && !options.full;
22417
+ if (compactList || options.compact) params.set("compact", "true");
21794
22418
  const query = params.toString();
21795
22419
  const payload = await http.request(
21796
22420
  `/api/v2/monitors/tools${query ? `?${query}` : ""}`,
21797
22421
  { method: "GET", ...FORBIDDEN_AS_API_ERROR }
21798
22422
  );
21799
- printCommandEnvelope(payload, { json: options.json });
22423
+ printCommandEnvelope(payload, {
22424
+ json: options.json,
22425
+ // Human list view shows id + name + deployed_count ("deployed: N") so
22426
+ // can-deploy vs already-deployed is visible in one view. Describing a
22427
+ // single tool keeps the full JSON contract (payload schema, streams).
22428
+ text: tool ? void 0 : renderAvailableToolsText(payload)
22429
+ });
22430
+ }
22431
+ function renderDeployedListText(payload, requestedStatus) {
22432
+ const monitors = Array.isArray(payload.monitors) ? payload.monitors : null;
22433
+ if (!monitors) return void 0;
22434
+ const lines = [
22435
+ monitors.length === 0 ? "No deployed monitors matched." : `Deployed monitors (${monitors.length}):`
22436
+ ];
22437
+ for (const raw of monitors) {
22438
+ const entry = asRecord(raw);
22439
+ const key = entry ? asString(entry.key) ?? asString(entry.monitor_key) : void 0;
22440
+ if (!entry || !key) continue;
22441
+ const status = asString(entry.status);
22442
+ const tool = asString(entry.tool);
22443
+ const name = asString(entry.name);
22444
+ lines.push(
22445
+ ` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
22446
+ );
22447
+ }
22448
+ const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
22449
+ lines.push(
22450
+ `Status filter: ${applied}${requestedStatus === void 0 && applied === "active" ? " (default)" : ""} \u2014 use --status all to include disabled monitors.`
22451
+ );
22452
+ if (monitors.length > 0) {
22453
+ lines.push("", "Inspect one: deepline monitors get <key> --json");
22454
+ }
22455
+ return `${lines.join("\n")}
22456
+ `;
22457
+ }
22458
+ async function handleMonitorsList(options) {
22459
+ const http = buildHttpClient();
22460
+ const params = new URLSearchParams();
22461
+ if (options.status) params.set("status", options.status);
22462
+ if (options.limit) params.set("limit", options.limit);
22463
+ if (options.compact) params.set("compact", "true");
22464
+ const query = params.toString();
22465
+ const payload = await http.request(
22466
+ `/api/v2/monitors/deployed${query ? `?${query}` : ""}`,
22467
+ { method: "GET", ...FORBIDDEN_AS_API_ERROR }
22468
+ );
22469
+ printCommandEnvelope(payload, {
22470
+ json: options.json,
22471
+ text: renderDeployedListText(payload, options.status)
22472
+ });
21800
22473
  }
21801
22474
  async function handleMonitorsCheck(definition, options) {
21802
22475
  const http = buildHttpClient();
21803
- const body = parseJsonObjectArg(definition, "--definition");
22476
+ const body = resolveMonitorJsonBody({
22477
+ positional: definition,
22478
+ file: options.file,
22479
+ argLabel: "<definition>",
22480
+ command: "deepline monitors check"
22481
+ });
21804
22482
  const payload = await http.request(
21805
22483
  "/api/v2/monitors/check",
21806
22484
  { method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
@@ -21809,26 +22487,37 @@ async function handleMonitorsCheck(definition, options) {
21809
22487
  }
21810
22488
  async function handleMonitorsDeploy(definition, options) {
21811
22489
  const http = buildHttpClient();
21812
- const body = parseJsonObjectArg(definition, "--definition");
22490
+ const body = resolveMonitorJsonBody({
22491
+ positional: definition,
22492
+ file: options.file,
22493
+ argLabel: "<definition>",
22494
+ command: "deepline monitors deploy"
22495
+ });
22496
+ if (options.dryRun) {
22497
+ const payload2 = await http.request(
22498
+ "/api/v2/monitors/check",
22499
+ { method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
22500
+ );
22501
+ const valid = payload2.valid !== false;
22502
+ printCommandEnvelope(
22503
+ { dry_run: true, ...payload2 },
22504
+ { json: options.json, text: renderMonitorDeployPlan(payload2) }
22505
+ );
22506
+ if (!valid) {
22507
+ process.exitCode = 7;
22508
+ }
22509
+ return;
22510
+ }
21813
22511
  const payload = await http.request(
21814
22512
  "/api/v2/monitors/deploy",
21815
22513
  { method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
21816
22514
  );
21817
- printCommandEnvelope(payload, { json: options.json });
21818
- }
21819
- async function handleDeployedList(options) {
21820
- const http = buildHttpClient();
21821
- const params = new URLSearchParams();
21822
- if (options.status) params.set("status", options.status);
21823
- if (options.limit) params.set("limit", options.limit);
21824
- const query = params.toString();
21825
- const payload = await http.request(
21826
- `/api/v2/monitors/deployed${query ? `?${query}` : ""}`,
21827
- { method: "GET", ...FORBIDDEN_AS_API_ERROR }
21828
- );
21829
- printCommandEnvelope(payload, { json: options.json });
22515
+ printCommandEnvelope(payload, {
22516
+ json: options.json,
22517
+ text: renderMonitorDeployCompletion(payload)
22518
+ });
21830
22519
  }
21831
- async function handleDeployedGet(key, options) {
22520
+ async function handleMonitorsGet(key, options) {
21832
22521
  const http = buildHttpClient();
21833
22522
  const payload = await http.request(
21834
22523
  `/api/v2/monitors/deployed/${encodeKey(key)}`,
@@ -21836,10 +22525,58 @@ async function handleDeployedGet(key, options) {
21836
22525
  );
21837
22526
  printCommandEnvelope(payload, { json: options.json });
21838
22527
  }
21839
- async function handleDeployedDelete(key, options) {
22528
+ async function confirmMonitorDelete(key, options) {
22529
+ const rl = (0, import_promises4.createInterface)({
22530
+ input: process.stdin,
22531
+ output: process.stderr
22532
+ });
22533
+ try {
22534
+ const consequence = options.localOnly ? "This removes the Deepline record only (the upstream provider resource is left in place)." : "This deprovisions the upstream provider resource.";
22535
+ const answer = await rl.question(
22536
+ `Delete monitor "${key}"? ${consequence} [y/N] `
22537
+ );
22538
+ return /^y(es)?$/i.test(answer.trim());
22539
+ } finally {
22540
+ rl.close();
22541
+ }
22542
+ }
22543
+ async function handleMonitorsDelete(key, options) {
21840
22544
  const http = buildHttpClient();
21841
22545
  const params = new URLSearchParams();
21842
22546
  if (options.localOnly) params.set("local_only", "true");
22547
+ if (options.dryRun) {
22548
+ params.set("dry_run", "true");
22549
+ const payload2 = await http.request(
22550
+ `/api/v2/monitors/deployed/${encodeKey(key)}?${params.toString()}`,
22551
+ { method: "DELETE", ...FORBIDDEN_AS_API_ERROR }
22552
+ );
22553
+ assertMonitorDryRunAcknowledged(payload2, {
22554
+ command: "deepline monitors delete",
22555
+ mutation: "delete"
22556
+ });
22557
+ printCommandEnvelope(payload2, {
22558
+ json: options.json,
22559
+ text: renderMonitorDeletePlan(payload2, key)
22560
+ });
22561
+ return;
22562
+ }
22563
+ if (!options.yes) {
22564
+ const interactive = process.stdout.isTTY === true && process.stdin.isTTY === true;
22565
+ if (!interactive) {
22566
+ throw monitorDeleteRequiresYesError(key, {
22567
+ localOnly: options.localOnly
22568
+ });
22569
+ }
22570
+ const confirmed = await confirmMonitorDelete(key, {
22571
+ localOnly: options.localOnly
22572
+ });
22573
+ if (!confirmed) {
22574
+ process.stderr.write(`Aborted. Monitor "${key}" was not deleted.
22575
+ `);
22576
+ process.exitCode = 2;
22577
+ return;
22578
+ }
22579
+ }
21843
22580
  const query = params.toString();
21844
22581
  const payload = await http.request(
21845
22582
  `/api/v2/monitors/deployed/${encodeKey(key)}${query ? `?${query}` : ""}`,
@@ -21847,17 +22584,37 @@ async function handleDeployedDelete(key, options) {
21847
22584
  );
21848
22585
  printCommandEnvelope(payload, { json: options.json });
21849
22586
  }
21850
- async function handleDeployedUpdate(key, patch, options) {
22587
+ async function handleMonitorsUpdate(key, patch, options) {
21851
22588
  const http = buildHttpClient();
21852
- const body = parseJsonObjectArg(patch, "<patch>");
22589
+ const body = resolveMonitorJsonBody({
22590
+ positional: patch,
22591
+ file: options.file,
22592
+ argLabel: "<patch>",
22593
+ command: `deepline monitors update ${key}`
22594
+ });
21853
22595
  const payload = await http.request(
21854
22596
  `/api/v2/monitors/deployed/${encodeKey(key)}`,
21855
22597
  { method: "PATCH", body, ...FORBIDDEN_AS_API_ERROR }
21856
22598
  );
21857
22599
  printCommandEnvelope(payload, { json: options.json });
21858
22600
  }
21859
- async function handleReactivate(key, options) {
22601
+ async function handleMonitorsReactivate(key, options) {
21860
22602
  const http = buildHttpClient();
22603
+ if (options.dryRun) {
22604
+ const payload2 = await http.request(
22605
+ `/api/v2/monitors/deployed/${encodeKey(key)}/reactivate?dry_run=true`,
22606
+ { method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
22607
+ );
22608
+ assertMonitorDryRunAcknowledged(payload2, {
22609
+ command: "deepline monitors reactivate",
22610
+ mutation: "reactivate"
22611
+ });
22612
+ printCommandEnvelope(payload2, {
22613
+ json: options.json,
22614
+ text: renderMonitorReactivatePlan(payload2, key)
22615
+ });
22616
+ return;
22617
+ }
21861
22618
  const payload = await http.request(
21862
22619
  `/api/v2/monitors/deployed/${encodeKey(key)}/reactivate`,
21863
22620
  { method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
@@ -21865,116 +22622,240 @@ async function handleReactivate(key, options) {
21865
22622
  printCommandEnvelope(payload, { json: options.json });
21866
22623
  }
21867
22624
  function registerMonitorsCommands(program) {
21868
- const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").addHelpText(
22625
+ const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").showSuggestionAfterError(true).addHelpText(
21869
22626
  "after",
21870
22627
  `
21871
22628
  Notes:
21872
- Monitors are provider-backed signal feeds that deliver events into your
21873
- workspace. Access is granted by a Deepline admin via Admin -> Rollouts; until
21874
- then these commands return a clear monitor_access_required error.
22629
+ Deepline monitors are provider-backed signal feeds: a monitor writes provider
22630
+ events into a Customer DB table; a play reacts to each new row via a
22631
+ sqlListeners trigger \u2014 see \`deepline plays bootstrap monitor-triggered\`.
22632
+ Access is granted by a Deepline admin via Admin -> Rollouts; until then these
22633
+ commands return a clear monitor_access_required error.
22634
+
22635
+ Exit codes:
22636
+ 0 success; 2 usage/local input; 3 auth or permission; 4 not found;
22637
+ 5 server failure; 7 validation failed.
22638
+ \`monitors status\` exits 1 when you lack monitor access (documented contract).
21875
22639
 
21876
22640
  Examples:
21877
- deepline monitors tools --json
21878
- deepline monitors check '{"key":"my-monitor","tool":"...","payload":{}}'
21879
- deepline monitors deploy '{"key":"my-monitor","tool":"...","payload":{}}'
21880
- deepline monitors deployed --json
21881
- deepline monitors deployed get my-monitor --json
21882
- deepline monitors reactivate my-monitor --json
22641
+ deepline monitors status --json
22642
+ deepline monitors available --json # compact list by default
22643
+ deepline monitors available --full --json # complete catalog
22644
+ deepline monitors available theirstack.saved_search_webhook --json
22645
+ deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
22646
+ deepline monitors deploy --dry-run --file monitor.json
22647
+ deepline monitors deploy --file monitor.json
22648
+ deepline monitors list --status all --json
22649
+ deepline monitors get my-monitor --json
22650
+ deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
22651
+ deepline monitors delete my-monitor --dry-run
22652
+ deepline monitors reactivate my-monitor --dry-run
21883
22653
  `
21884
22654
  );
21885
- monitors.command("tools").description("List or describe the monitor tools available to your org.").addHelpText(
21886
- "after",
21887
- `
22655
+ withJsonOption(
22656
+ monitors.command("status").description("Check whether you have access to Deepline monitors.").addHelpText(
22657
+ "after",
22658
+ `
21888
22659
  Notes:
21889
- Read-only. Filter the catalog with --provider, --tool, --search, or --limit.
21890
- Pass --tool to describe a single monitor tool.
22660
+ Read-only access check. Requires authentication but NOT monitor access, so it
22661
+ is safe to run first to confirm whether you can use the monitor commands. Exits
22662
+ 0 when you have access and 1 when you do not, so agents can branch on it (this
22663
+ exit-1 denial contract predates the typed monitor exit codes and is kept).
21891
22664
 
21892
22665
  Examples:
21893
- deepline monitors tools
21894
- deepline monitors tools --provider theirstack --json
21895
- deepline monitors tools --tool theirstack_jobs --json
22666
+ deepline monitors status
22667
+ deepline monitors status --json
21896
22668
  `
21897
- ).option("--provider <provider>", "Filter by provider").option("--tool <tool>", "Describe a single monitor tool by id").option("--search <query>", "Search monitor tools by text").option("--limit <n>", "Limit the number of monitor tools returned").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsTools);
21898
- monitors.command("check <definition>").description("Validate a monitor definition without deploying it.").addHelpText(
21899
- "after",
21900
- `
22669
+ )
22670
+ ).action(monitorsAction(handleMonitorsStatus));
22671
+ withJsonOption(
22672
+ monitors.command("available [tool-id]").alias("tools").description(
22673
+ "List the monitor types you can deploy, or describe one by tool id."
22674
+ ).addHelpText(
22675
+ "after",
22676
+ `
21901
22677
  Notes:
21902
- Read-only validation. <definition> is a JSON object with key, tool, payload,
21903
- and optional controls. Does not deploy or spend credits.
22678
+ Read-only catalog of deployable monitor types. Pass a tool id positionally to
22679
+ describe one (payload schema + output streams). Filter the list with
22680
+ --provider, --search, or --limit. List entries include how many monitors you
22681
+ already have deployed on each tool ("deployed: N") when the server reports it.
22682
+ The list is compact by default (id + name + deployed count); pass --full to
22683
+ get the complete catalog (payload schemas + output streams for every tool).
22684
+ Describing a single tool by id always returns the full contract.
21904
22685
 
21905
22686
  Examples:
21906
- deepline monitors check '{"key":"my-monitor","tool":"theirstack_jobs","payload":{}}'
22687
+ deepline monitors available
22688
+ deepline monitors available --full --json
22689
+ deepline monitors available --provider theirstack --json
22690
+ deepline monitors available theirstack.saved_search_webhook --json
22691
+ deepline monitors available --search jobs --json
21907
22692
  `
21908
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsCheck);
21909
- monitors.command("deploy <definition>").description("Deploy a monitor from a definition.").addHelpText(
21910
- "after",
21911
- `
22693
+ ).option("--provider <provider>", "Filter by provider").option(
22694
+ "--tool <tool>",
22695
+ "Describe a single monitor tool by id (same as the positional tool-id)"
22696
+ ).option("--search <query>", "Search monitor tools by text").option("--limit <n>", "Limit the number of monitor tools returned").option(
22697
+ "--full",
22698
+ "Return the complete monitor catalog (payload schemas + output streams). The list is compact by default."
22699
+ ).option("--compact", COMPACT_OPTION_DESCRIPTION)
22700
+ ).action(monitorsAction(handleMonitorsAvailable));
22701
+ withJsonOption(
22702
+ monitors.command("list").description("List the monitors you have deployed.").addHelpText(
22703
+ "after",
22704
+ `
21912
22705
  Notes:
21913
- Mutates workspace state and may spend Deepline credits. <definition> is a JSON
21914
- object with key, tool, payload, and optional controls.
22706
+ Read-only. --status filters by monitor status: active (default), disabled, or
22707
+ all. The output echoes the status filter that was applied. --compact returns
22708
+ high-signal fields only.
21915
22709
 
21916
22710
  Examples:
21917
- deepline monitors deploy '{"key":"my-monitor","tool":"theirstack_jobs","payload":{}}'
22711
+ deepline monitors list
22712
+ deepline monitors list --status all --json
22713
+ deepline monitors list --compact --json
21918
22714
  `
21919
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleMonitorsDeploy);
21920
- monitors.command("reactivate <key>").description("Reactivate a previously disabled deployed monitor.").addHelpText(
21921
- "after",
21922
- `
22715
+ ).option(
22716
+ "--status <status>",
22717
+ "Filter by monitor status: active (default), disabled, or all"
22718
+ ).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
22719
+ ).action(monitorsAction(handleMonitorsList));
22720
+ withJsonOption(
22721
+ monitors.command("get <key>").description("Show a single deployed monitor by its public key.").addHelpText(
22722
+ "after",
22723
+ `
21923
22724
  Notes:
21924
- Mutates workspace state and may spend Deepline credits.
22725
+ Read-only.
21925
22726
 
21926
22727
  Examples:
21927
- deepline monitors reactivate my-monitor --json
22728
+ deepline monitors get my-monitor --json
21928
22729
  `
21929
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleReactivate);
21930
- const deployed = monitors.command("deployed").description("List and manage your deployed monitors.").addHelpText(
21931
- "after",
21932
- `
22730
+ )
22731
+ ).action(monitorsAction(handleMonitorsGet));
22732
+ withJsonOption(
22733
+ monitors.command("check [definition]").description("Validate a monitor definition without deploying it.").addHelpText(
22734
+ "after",
22735
+ `
21933
22736
  Notes:
21934
- With no subcommand, lists deployed monitors. Use get/update/delete to manage a
21935
- single monitor by its public key.
22737
+ Read-only validation. <definition> is a JSON object with key, tool, payload,
22738
+ and optional controls (Deepline lifecycle metadata, e.g.
22739
+ "controls":{"enabled":false}). Pass it positionally, via --file <path>, or
22740
+ from stdin with --file -. Does not deploy or spend credits.
21936
22741
 
21937
22742
  Examples:
21938
- deepline monitors deployed --json
21939
- deepline monitors deployed --status all --json
21940
- deepline monitors deployed get my-monitor --json
22743
+ deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
22744
+ deepline monitors check --file monitor.json
22745
+ cat monitor.json | deepline monitors check --file -
21941
22746
  `
21942
- ).option("--status <status>", 'Filter by monitor status (or "all")').option("--limit <n>", "Limit the number of deployed monitors returned").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedList);
21943
- deployed.command("get <key>").description("Show a single deployed monitor by its public key.").addHelpText(
21944
- "after",
21945
- `
22747
+ ).option(
22748
+ "-f, --file <path>",
22749
+ "Read the definition JSON from a file, or - for stdin"
22750
+ )
22751
+ ).action(monitorsAction(handleMonitorsCheck));
22752
+ withJsonOption(
22753
+ monitors.command("deploy [definition]").description("Deploy a monitor from a definition.").addHelpText(
22754
+ "after",
22755
+ `
21946
22756
  Notes:
21947
- Read-only.
22757
+ Mutates workspace state and may spend Deepline credits. <definition> is a JSON
22758
+ object with key, tool, payload, and optional controls (e.g.
22759
+ "controls":{"enabled":false}). Pass it positionally, via --file <path>, or
22760
+ from stdin with --file -.
22761
+ --dry-run validates the definition and shows the plan (deploy cost in Deepline
22762
+ credits when the server reports it, plus any existing monitors that may
22763
+ already cover this scope) WITHOUT deploying. Exits 0 when valid, 7 when not.
21948
22764
 
21949
22765
  Examples:
21950
- deepline monitors deployed get my-monitor --json
22766
+ deepline monitors deploy '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
22767
+ deepline monitors deploy --dry-run --file monitor.json
22768
+ deepline monitors deploy --file monitor.json
21951
22769
  `
21952
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedGet);
21953
- deployed.command("update <key> <patch>").description("Update a deployed monitor by its public key.").addHelpText(
21954
- "after",
21955
- `
22770
+ ).option(
22771
+ "-f, --file <path>",
22772
+ "Read the definition JSON from a file, or - for stdin"
22773
+ ).option(
22774
+ "--dry-run",
22775
+ "Validate and show the deploy plan (cost, reuse candidates) without deploying"
22776
+ )
22777
+ ).action(monitorsAction(handleMonitorsDeploy));
22778
+ withJsonOption(
22779
+ monitors.command("update <key> [patch]").description("Update a deployed monitor by its public key.").addHelpText(
22780
+ "after",
22781
+ `
21956
22782
  Notes:
21957
- Mutates workspace state. <patch> is a JSON object of fields to update.
22783
+ Mutates workspace state. <patch> is a JSON object of fields to update, e.g.
22784
+ '{"controls":{"enabled":false}}' to disable a monitor. Pass it positionally,
22785
+ via --file <path>, or from stdin with --file -.
21958
22786
 
21959
22787
  Examples:
21960
- deepline monitors deployed update my-monitor '{"controls":{"enabled":false}}' --json
22788
+ deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
22789
+ deepline monitors update my-monitor --file patch.json
21961
22790
  `
21962
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedUpdate);
21963
- deployed.command("delete <key>").description("Delete a deployed monitor by its public key.").addHelpText(
21964
- "after",
21965
- `
22791
+ ).option(
22792
+ "-f, --file <path>",
22793
+ "Read the patch JSON from a file, or - for stdin"
22794
+ )
22795
+ ).action(monitorsAction(handleMonitorsUpdate));
22796
+ withJsonOption(
22797
+ monitors.command("delete <key>").description("Delete a deployed monitor by its public key.").addHelpText(
22798
+ "after",
22799
+ `
21966
22800
  Notes:
21967
- Mutates workspace state. By default deprovisions the upstream provider
21968
- resource; pass --local-only to remove only the Deepline-managed record.
22801
+ DESTRUCTIVE. By default deprovisions the upstream provider resource; pass
22802
+ --local-only to remove only the Deepline-managed record.
22803
+ --dry-run shows the delete plan without deleting anything.
22804
+ Interactive terminals get a y/N confirmation; non-interactive runs (agents,
22805
+ scripts, pipes) must pass --yes.
21969
22806
 
21970
22807
  Examples:
21971
- deepline monitors deployed delete my-monitor --json
21972
- deepline monitors deployed delete my-monitor --local-only --json
22808
+ deepline monitors delete my-monitor --dry-run
22809
+ deepline monitors delete my-monitor --yes --json
22810
+ deepline monitors delete my-monitor --local-only --yes --json
21973
22811
  `
21974
- ).option(
21975
- "--local-only",
21976
- "Remove only the Deepline-managed record, leaving the upstream resource"
21977
- ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleDeployedDelete);
22812
+ ).option(
22813
+ "--local-only",
22814
+ "Remove only the Deepline-managed record, leaving the upstream resource"
22815
+ ).option("--dry-run", "Show the delete plan without deleting anything").option(
22816
+ "--yes",
22817
+ "Skip the confirmation prompt (required non-interactively)"
22818
+ )
22819
+ ).action(monitorsAction(handleMonitorsDelete));
22820
+ withJsonOption(
22821
+ monitors.command("reactivate <key>").description("Reactivate a previously disabled deployed monitor.").addHelpText(
22822
+ "after",
22823
+ `
22824
+ Notes:
22825
+ Mutates workspace state and may spend Deepline credits.
22826
+ --dry-run shows the reactivation cost (in Deepline credits) without changing
22827
+ anything.
22828
+
22829
+ Examples:
22830
+ deepline monitors reactivate my-monitor --dry-run
22831
+ deepline monitors reactivate my-monitor --json
22832
+ `
22833
+ ).option("--dry-run", "Show the reactivation cost without reactivating")
22834
+ ).action(monitorsAction(handleMonitorsReactivate));
22835
+ const deployed = withJsonOption(
22836
+ monitors.command("deployed", { hidden: true }).description("Alias of `monitors list` (plus get/update/delete aliases).").option(
22837
+ "--status <status>",
22838
+ "Filter by monitor status: active (default), disabled, or all"
22839
+ ).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
22840
+ ).action(monitorsAction(handleMonitorsList));
22841
+ withJsonOption(
22842
+ deployed.command("get <key>").description("Alias of `monitors get <key>`.")
22843
+ ).action(monitorsAction(handleMonitorsGet));
22844
+ withJsonOption(
22845
+ deployed.command("update <key> [patch]").description("Alias of `monitors update <key>`.").option(
22846
+ "-f, --file <path>",
22847
+ "Read the patch JSON from a file, or - for stdin"
22848
+ )
22849
+ ).action(monitorsAction(handleMonitorsUpdate));
22850
+ withJsonOption(
22851
+ deployed.command("delete <key>").description("Alias of `monitors delete <key>`.").option(
22852
+ "--local-only",
22853
+ "Remove only the Deepline-managed record, leaving the upstream resource"
22854
+ ).option("--dry-run", "Show the delete plan without deleting anything").option(
22855
+ "--yes",
22856
+ "Skip the confirmation prompt (required non-interactively)"
22857
+ )
22858
+ ).action(monitorsAction(handleMonitorsDelete));
21978
22859
  }
21979
22860
 
21980
22861
  // src/cli/commands/org.ts
@@ -22999,7 +23880,7 @@ Examples:
22999
23880
  }
23000
23881
 
23001
23882
  // src/cli/commands/switch.ts
23002
- var import_node_fs12 = require("fs");
23883
+ var import_node_fs13 = require("fs");
23003
23884
  var import_node_os10 = require("os");
23004
23885
  var import_node_path14 = require("path");
23005
23886
  function hostSlugFromBaseUrl(baseUrl) {
@@ -23034,15 +23915,15 @@ function activeFamilyPath() {
23034
23915
  function readActiveFamily() {
23035
23916
  const path = activeFamilyPath();
23036
23917
  try {
23037
- return (0, import_node_fs12.readFileSync)(path, "utf-8").trim() || "sdk";
23918
+ return (0, import_node_fs13.readFileSync)(path, "utf-8").trim() || "sdk";
23038
23919
  } catch {
23039
23920
  return "sdk";
23040
23921
  }
23041
23922
  }
23042
23923
  function writeActiveFamily(family) {
23043
23924
  const path = activeFamilyPath();
23044
- (0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
23045
- (0, import_node_fs12.writeFileSync)(path, `${family}
23925
+ (0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
23926
+ (0, import_node_fs13.writeFileSync)(path, `${family}
23046
23927
  `, "utf-8");
23047
23928
  return path;
23048
23929
  }
@@ -23059,7 +23940,7 @@ function handleSwitch(action, options) {
23059
23940
  ok: true,
23060
23941
  active_family: activeFamily,
23061
23942
  active_family_path: path,
23062
- active_family_file_exists: (0, import_node_fs12.existsSync)(path),
23943
+ active_family_file_exists: (0, import_node_fs13.existsSync)(path),
23063
23944
  render: {
23064
23945
  sections: [
23065
23946
  {
@@ -23159,12 +24040,12 @@ Examples:
23159
24040
 
23160
24041
  // src/cli/commands/tools.ts
23161
24042
  var import_commander2 = require("commander");
23162
- var import_node_fs14 = require("fs");
24043
+ var import_node_fs15 = require("fs");
23163
24044
  var import_node_os12 = require("os");
23164
24045
  var import_node_path16 = require("path");
23165
24046
 
23166
24047
  // src/tool-output.ts
23167
- var import_node_fs13 = require("fs");
24048
+ var import_node_fs14 = require("fs");
23168
24049
  var import_node_os11 = require("os");
23169
24050
  var import_node_path15 = require("path");
23170
24051
  function isPlainObject(value) {
@@ -23294,18 +24175,18 @@ function projectRowOutput(conversion) {
23294
24175
  }
23295
24176
  function ensureOutputDir() {
23296
24177
  const outputDir = (0, import_node_path15.join)((0, import_node_os11.homedir)(), ".local", "share", "deepline", "data");
23297
- (0, import_node_fs13.mkdirSync)(outputDir, { recursive: true });
24178
+ (0, import_node_fs14.mkdirSync)(outputDir, { recursive: true });
23298
24179
  return outputDir;
23299
24180
  }
23300
24181
  function writeJsonOutputFile(payload, stem) {
23301
24182
  const outputDir = ensureOutputDir();
23302
24183
  const outputPath = (0, import_node_path15.join)(outputDir, `${stem}_${Date.now()}.json`);
23303
- (0, import_node_fs13.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
24184
+ (0, import_node_fs14.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
23304
24185
  return outputPath;
23305
24186
  }
23306
24187
  function writeCsvOutputFile(rows, stem, options) {
23307
24188
  const outputPath = options?.outPath ? options.outPath : (0, import_node_path15.join)(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
23308
- (0, import_node_fs13.mkdirSync)((0, import_node_path15.dirname)(outputPath), { recursive: true });
24189
+ (0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(outputPath), { recursive: true });
23309
24190
  const columns = columnsForRows(rows);
23310
24191
  const escapeCell = (value) => {
23311
24192
  const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
@@ -23314,19 +24195,19 @@ function writeCsvOutputFile(rows, stem, options) {
23314
24195
  }
23315
24196
  return normalized;
23316
24197
  };
23317
- const fd = (0, import_node_fs13.openSync)(outputPath, "w");
24198
+ const fd = (0, import_node_fs14.openSync)(outputPath, "w");
23318
24199
  try {
23319
- (0, import_node_fs13.writeSync)(fd, `${columns.map(escapeCell).join(",")}
24200
+ (0, import_node_fs14.writeSync)(fd, `${columns.map(escapeCell).join(",")}
23320
24201
  `);
23321
24202
  for (const row of rows) {
23322
- (0, import_node_fs13.writeSync)(
24203
+ (0, import_node_fs14.writeSync)(
23323
24204
  fd,
23324
24205
  `${columns.map((column) => escapeCell(row[column])).join(",")}
23325
24206
  `
23326
24207
  );
23327
24208
  }
23328
24209
  } finally {
23329
- (0, import_node_fs13.closeSync)(fd);
24210
+ (0, import_node_fs14.closeSync)(fd);
23330
24211
  }
23331
24212
  const previewRows = rows.slice(0, 5);
23332
24213
  const previewColumns = columns.slice(0, 5);
@@ -24540,10 +25421,10 @@ function normalizeOutputFormat(raw) {
24540
25421
  function resolveAtFilePath(rawPath) {
24541
25422
  const trimmed = rawPath.trim();
24542
25423
  const resolved = (0, import_node_path16.resolve)(trimmed);
24543
- if ((0, import_node_fs14.existsSync)(resolved)) return resolved;
25424
+ if ((0, import_node_fs15.existsSync)(resolved)) return resolved;
24544
25425
  if (process.platform !== "win32" && trimmed.includes("\\")) {
24545
25426
  const normalized = (0, import_node_path16.resolve)(trimmed.replace(/\\/g, "/"));
24546
- if ((0, import_node_fs14.existsSync)(normalized)) return normalized;
25427
+ if ((0, import_node_fs15.existsSync)(normalized)) return normalized;
24547
25428
  }
24548
25429
  return resolved;
24549
25430
  }
@@ -24554,7 +25435,7 @@ function readJsonArgument(raw, flagName) {
24554
25435
  throw new Error(`Invalid ${flagName} value: empty @file path.`);
24555
25436
  }
24556
25437
  try {
24557
- return (0, import_node_fs14.readFileSync)(resolveAtFilePath(filePath), "utf8").replace(
25438
+ return (0, import_node_fs15.readFileSync)(resolveAtFilePath(filePath), "utf8").replace(
24558
25439
  /^\uFEFF/,
24559
25440
  ""
24560
25441
  );
@@ -24661,8 +25542,8 @@ function starterScriptJson(script) {
24661
25542
  function seedToolListScript(input2) {
24662
25543
  const stem = safeFileStem(input2.toolId);
24663
25544
  const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
24664
- const scriptDir = (0, import_node_fs14.mkdtempSync)((0, import_node_path16.join)((0, import_node_os12.tmpdir)(), "deepline-workflow-seed-"));
24665
- (0, import_node_fs14.chmodSync)(scriptDir, 448);
25545
+ const scriptDir = (0, import_node_fs15.mkdtempSync)((0, import_node_path16.join)((0, import_node_os12.tmpdir)(), "deepline-workflow-seed-"));
25546
+ (0, import_node_fs15.chmodSync)(scriptDir, 448);
24666
25547
  const scriptPath = (0, import_node_path16.join)(scriptDir, fileName);
24667
25548
  const projectDir = `deepline/projects/${stem}-workflow`;
24668
25549
  const playName = `${stem}-workflow`;
@@ -24706,7 +25587,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
24706
25587
  description: ${JSON.stringify(`Seed ${input2.toolId} rows into a Deepline workflow-ready dataset.`)},
24707
25588
  });
24708
25589
  `;
24709
- (0, import_node_fs14.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
25590
+ (0, import_node_fs15.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
24710
25591
  return {
24711
25592
  path: scriptPath,
24712
25593
  sourceCode: script,
@@ -25036,7 +25917,7 @@ async function executeTool(args) {
25036
25917
  }
25037
25918
 
25038
25919
  // src/cli/commands/workflow.ts
25039
- var import_promises4 = require("fs/promises");
25920
+ var import_promises5 = require("fs/promises");
25040
25921
  var import_node_path17 = require("path");
25041
25922
 
25042
25923
  // src/cli/workflow-to-play.ts
@@ -25224,9 +26105,10 @@ var PLAY_EQUIVALENT = {
25224
26105
  delete: "deepline plays delete <name>"
25225
26106
  };
25226
26107
  var MIGRATE_HINT = "deepline workflows transform <id>";
25227
- var JSON_OPTION_DESCRIPTION = "Emit JSON output. Also automatic when stdout is piped";
25228
- function withJsonOption(command) {
25229
- return command.option("--json", JSON_OPTION_DESCRIPTION);
26108
+ var TRIGGER_REDIRECT = "Looking to trigger a play automatically? Use a trigger binding in definePlay \u2014 `cron`/`webhook`, or `sqlListeners` to run on a monitor\u2019s output (see `deepline monitors available <id>` for a monitor\u2019s streams and the deepline-monitors skill). `workflows` only manages prebuilt plays and is deprecated in favor of `plays`.";
26109
+ var JSON_OPTION_DESCRIPTION2 = "Emit JSON output. Also automatic when stdout is piped";
26110
+ function withJsonOption2(command) {
26111
+ return command.option("--json", JSON_OPTION_DESCRIPTION2);
25230
26112
  }
25231
26113
  var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set([
25232
26114
  "completed",
@@ -25251,6 +26133,7 @@ function noticeToStderr(command) {
25251
26133
  `note: \`deepline workflows ${command}\` is a legacy surface \u2014 workflows are becoming plays.
25252
26134
  equivalent: \`${deprecation.use}\`
25253
26135
  migrate this workflow: \`${MIGRATE_HINT}\`
26136
+ ${TRIGGER_REDIRECT}
25254
26137
  `
25255
26138
  );
25256
26139
  }
@@ -25281,7 +26164,7 @@ function readStatus(payload) {
25281
26164
  }
25282
26165
  async function readJsonOption(payload, file) {
25283
26166
  if (file) {
25284
- const raw = await (0, import_promises4.readFile)((0, import_node_path17.resolve)(file), "utf8");
26167
+ const raw = await (0, import_promises5.readFile)((0, import_node_path17.resolve)(file), "utf8");
25285
26168
  return JSON.parse(raw);
25286
26169
  }
25287
26170
  if (payload) {
@@ -25316,8 +26199,8 @@ async function transformOne(api, workflowId, outDir, publish) {
25316
26199
  { workflowName: workflow.name, version: revision.version }
25317
26200
  );
25318
26201
  const file = (0, import_node_path17.join)((0, import_node_path17.resolve)(outDir), `${compiled.playName}.play.ts`);
25319
- await (0, import_promises4.mkdir)((0, import_node_path17.dirname)(file), { recursive: true });
25320
- await (0, import_promises4.writeFile)(file, compiled.sourceCode, "utf8");
26202
+ await (0, import_promises5.mkdir)((0, import_node_path17.dirname)(file), { recursive: true });
26203
+ await (0, import_promises5.writeFile)(file, compiled.sourceCode, "utf8");
25321
26204
  let published = false;
25322
26205
  if (publish) {
25323
26206
  const code = await handlePlayPublish([file]);
@@ -25484,7 +26367,7 @@ async function handleTail(id, runId, options) {
25484
26367
  }
25485
26368
  function registerWorkflowCommands(program) {
25486
26369
  const workflows = program.command("workflows").description(
25487
- "Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play."
26370
+ "Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play. " + TRIGGER_REDIRECT
25488
26371
  ).addHelpText(
25489
26372
  "after",
25490
26373
  `
@@ -25496,9 +26379,13 @@ keep working, but new work belongs in plays. Migrate a workflow with:
25496
26379
 
25497
26380
  Equivalents: list\u2192plays list \xB7 call\u2192plays run \xB7 apply\u2192plays publish \xB7
25498
26381
  lint\u2192plays check \xB7 runs\u2192runs list.
26382
+
26383
+ ${TRIGGER_REDIRECT}
26384
+ Add the binding as the third arg to definePlay in your .play.ts; the
26385
+ deepline-monitors skill has a monitor-triggered example.
25499
26386
  `
25500
26387
  );
25501
- withJsonOption(
26388
+ withJsonOption2(
25502
26389
  workflows.command("transform [id]").description("Compile a workflow into a reviewable V2 play (.play.ts).").option("--all", "Transform every workflow in the workspace").option("--out <dir>", "Output directory for generated plays", "./plays").option("--publish", "Publish each clean play immediately")
25503
26390
  ).addHelpText(
25504
26391
  "after",
@@ -25515,61 +26402,61 @@ Notes:
25515
26402
  ).action(async (id, options) => {
25516
26403
  process.exitCode = await handleTransform(id, options);
25517
26404
  });
25518
- withJsonOption(
26405
+ withJsonOption2(
25519
26406
  workflows.command("list").description("List workspace workflows.").option("--limit <n>", "Max workflows to return")
25520
26407
  ).action(handleList2);
25521
- withJsonOption(
26408
+ withJsonOption2(
25522
26409
  workflows.command("get <id>").description(
25523
26410
  "Fetch a workflow, including its published-revision config."
25524
26411
  )
25525
26412
  ).action(handleGet);
25526
- withJsonOption(
26413
+ withJsonOption2(
25527
26414
  workflows.command("disable <id>").description("Turn a workflow off.")
25528
26415
  ).action(handleDisable);
25529
- withJsonOption(
26416
+ withJsonOption2(
25530
26417
  workflows.command("enable <id>").description("Turn a workflow back on.")
25531
26418
  ).action(handleEnable);
25532
- withJsonOption(
26419
+ withJsonOption2(
25533
26420
  workflows.command("delete <id>").description("Delete a workflow and its revisions/runs.")
25534
26421
  ).action(handleDelete);
25535
- withJsonOption(
26422
+ withJsonOption2(
25536
26423
  workflows.command("apply").description("Create or update a workflow from config.").option("--payload <json>", "Inline config JSON").option("--file <path>", "Path to a config JSON file")
25537
26424
  ).action(handleApply);
25538
- withJsonOption(
26425
+ withJsonOption2(
25539
26426
  workflows.command("lint").description("Validate a workflow config without saving.").option("--payload <json>", "Inline config JSON").option("--file <path>", "Path to a config JSON file")
25540
26427
  ).action(handleLint);
25541
- withJsonOption(
26428
+ withJsonOption2(
25542
26429
  workflows.command("schema").description("Fetch live workflow request schemas.").option(
25543
26430
  "--subject <subject>",
25544
26431
  "Schema subject (apply|call|trigger|all|\u2026)"
25545
26432
  )
25546
26433
  ).action(handleSchema);
25547
- withJsonOption(
26434
+ withJsonOption2(
25548
26435
  workflows.command("call").description("Queue a workflow run.").option("--workflow-id <id>", "Workflow id").option("--workflow-name <name>", "Workflow name").option("--payload <json>", "Run input JSON").option("--mode <mode>", "live | dry_run | smoke_test")
25549
26436
  ).action(handleCall);
25550
- withJsonOption(
26437
+ withJsonOption2(
25551
26438
  workflows.command("runs <id>").description("List a workflow\u2019s runs.").option("--limit <n>", "Max runs to return")
25552
26439
  ).action(handleRuns);
25553
- withJsonOption(
26440
+ withJsonOption2(
25554
26441
  workflows.command("run <id> <runId>").description("Fetch a single workflow run.")
25555
26442
  ).action(handleRun);
25556
- withJsonOption(
26443
+ withJsonOption2(
25557
26444
  workflows.command("tail <id> <runId>").description("Poll a workflow run until it reaches a terminal status.").option("--interval-ms <n>", "Poll interval in ms (default 2000)")
25558
26445
  ).action(handleTail);
25559
- withJsonOption(
26446
+ withJsonOption2(
25560
26447
  workflows.command("cancel <id> <runId>").description("Cancel a running workflow run.")
25561
26448
  ).action(handleCancel);
25562
26449
  }
25563
26450
 
25564
26451
  // src/cli/commands/update.ts
25565
26452
  var import_node_child_process4 = require("child_process");
25566
- var import_node_fs16 = require("fs");
26453
+ var import_node_fs17 = require("fs");
25567
26454
  var import_node_os13 = require("os");
25568
26455
  var import_node_path19 = require("path");
25569
26456
 
25570
26457
  // src/cli/skills-sync.ts
25571
26458
  var import_node_child_process3 = require("child_process");
25572
- var import_node_fs15 = require("fs");
26459
+ var import_node_fs16 = require("fs");
25573
26460
  var import_node_path18 = require("path");
25574
26461
 
25575
26462
  // ../shared_libs/cli/install-commands.json
@@ -25692,13 +26579,13 @@ function activePluginSkillsDir() {
25692
26579
  return "";
25693
26580
  }
25694
26581
  const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
25695
- return dir && (0, import_node_fs15.existsSync)(dir) ? dir : "";
26582
+ return dir && (0, import_node_fs16.existsSync)(dir) ? dir : "";
25696
26583
  }
25697
26584
  function readPluginSkillsVersion() {
25698
26585
  const dir = activePluginSkillsDir();
25699
26586
  if (!dir) return "";
25700
26587
  try {
25701
- return (0, import_node_fs15.readFileSync)((0, import_node_path18.join)(dir, ".version"), "utf-8").trim();
26588
+ return (0, import_node_fs16.readFileSync)((0, import_node_path18.join)(dir, ".version"), "utf-8").trim();
25702
26589
  } catch {
25703
26590
  return "";
25704
26591
  }
@@ -25712,18 +26599,18 @@ function legacySdkSkillsVersionPath(baseUrl) {
25712
26599
  function readSdkSkillsLocalVersion(baseUrl) {
25713
26600
  const pluginVersion = readPluginSkillsVersion();
25714
26601
  if (pluginVersion) return pluginVersion;
25715
- const path = (0, import_node_fs15.existsSync)(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
25716
- if (!(0, import_node_fs15.existsSync)(path)) return "";
26602
+ const path = (0, import_node_fs16.existsSync)(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
26603
+ if (!(0, import_node_fs16.existsSync)(path)) return "";
25717
26604
  try {
25718
- return (0, import_node_fs15.readFileSync)(path, "utf-8").trim();
26605
+ return (0, import_node_fs16.readFileSync)(path, "utf-8").trim();
25719
26606
  } catch {
25720
26607
  return "";
25721
26608
  }
25722
26609
  }
25723
26610
  function writeLocalSkillsVersion(baseUrl, version) {
25724
26611
  const path = sdkSkillsVersionPath(baseUrl);
25725
- (0, import_node_fs15.mkdirSync)((0, import_node_path18.dirname)(path), { recursive: true });
25726
- (0, import_node_fs15.writeFileSync)(path, `${version}
26612
+ (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(path), { recursive: true });
26613
+ (0, import_node_fs16.writeFileSync)(path, `${version}
25727
26614
  `, "utf-8");
25728
26615
  }
25729
26616
  function sortedUniqueSkillNames(names) {
@@ -26010,7 +26897,7 @@ function sidecarStateDir(input2) {
26010
26897
  }
26011
26898
  function readOptionalText(path) {
26012
26899
  try {
26013
- return (0, import_node_fs16.readFileSync)(path, "utf8").trim();
26900
+ return (0, import_node_fs17.readFileSync)(path, "utf8").trim();
26014
26901
  } catch {
26015
26902
  return "";
26016
26903
  }
@@ -26054,7 +26941,7 @@ function resolvePythonSidecarUpdatePlan(options) {
26054
26941
  function findRepoBackedSdkRoot(startPath) {
26055
26942
  let current = (0, import_node_path19.resolve)(startPath);
26056
26943
  while (true) {
26057
- if ((0, import_node_fs16.existsSync)((0, import_node_path19.join)(current, "sdk", "package.json")) && (0, import_node_fs16.existsSync)((0, import_node_path19.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
26944
+ if ((0, import_node_fs17.existsSync)((0, import_node_path19.join)(current, "sdk", "package.json")) && (0, import_node_fs17.existsSync)((0, import_node_path19.join)(current, "sdk", "bin", "deepline-dev.ts"))) {
26058
26945
  return current;
26059
26946
  }
26060
26947
  const parent = (0, import_node_path19.dirname)(current);
@@ -26065,7 +26952,7 @@ function findRepoBackedSdkRoot(startPath) {
26065
26952
  function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
26066
26953
  const normalized = (() => {
26067
26954
  try {
26068
- return (0, import_node_fs16.realpathSync)(entrypoint);
26955
+ return (0, import_node_fs17.realpathSync)(entrypoint);
26069
26956
  } catch {
26070
26957
  return (0, import_node_path19.resolve)(entrypoint);
26071
26958
  }
@@ -26145,7 +27032,7 @@ function readAutoUpdateFailure(plan) {
26145
27032
  if (!path) return null;
26146
27033
  try {
26147
27034
  const parsed = JSON.parse(
26148
- (0, import_node_fs16.readFileSync)(path, "utf8")
27035
+ (0, import_node_fs17.readFileSync)(path, "utf8")
26149
27036
  );
26150
27037
  if ((parsed.kind === "npm-global" || parsed.kind === "python-sidecar") && typeof parsed.packageSpec === "string" && typeof parsed.failedAt === "string" && typeof parsed.exitCode === "number" && typeof parsed.manualCommand === "string") {
26151
27038
  return parsed;
@@ -26166,8 +27053,8 @@ function writeAutoUpdateFailure(plan, exitCode) {
26166
27053
  manualCommand: plan.manualCommand
26167
27054
  };
26168
27055
  try {
26169
- (0, import_node_fs16.mkdirSync)((0, import_node_path19.dirname)(path), { recursive: true });
26170
- (0, import_node_fs16.writeFileSync)(path, `${JSON.stringify(marker, null, 2)}
27056
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(path), { recursive: true });
27057
+ (0, import_node_fs17.writeFileSync)(path, `${JSON.stringify(marker, null, 2)}
26171
27058
  `, "utf8");
26172
27059
  } catch {
26173
27060
  }
@@ -26176,7 +27063,7 @@ function clearAutoUpdateFailure(plan) {
26176
27063
  const path = autoUpdateFailurePath(plan);
26177
27064
  if (!path) return;
26178
27065
  try {
26179
- (0, import_node_fs16.unlinkSync)(path);
27066
+ (0, import_node_fs17.unlinkSync)(path);
26180
27067
  } catch {
26181
27068
  }
26182
27069
  }
@@ -26229,7 +27116,7 @@ function installedPackageVersion(versionDir) {
26229
27116
  "package.json"
26230
27117
  );
26231
27118
  try {
26232
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(packageJsonPath, "utf8"));
27119
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(packageJsonPath, "utf8"));
26233
27120
  return typeof parsed.version === "string" ? safeVersionSegment(parsed.version) : "";
26234
27121
  } catch {
26235
27122
  return "";
@@ -26261,9 +27148,9 @@ function runCommand(command, args, env = process.env, options = {}) {
26261
27148
  });
26262
27149
  }
26263
27150
  function writeSidecarLauncher(input2) {
26264
- (0, import_node_fs16.mkdirSync)((0, import_node_path19.dirname)(input2.path), { recursive: true });
27151
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(input2.path), { recursive: true });
26265
27152
  if (process.platform === "win32") {
26266
- (0, import_node_fs16.writeFileSync)(
27153
+ (0, import_node_fs17.writeFileSync)(
26267
27154
  input2.path,
26268
27155
  [
26269
27156
  `@set DEEPLINE_HOST_URL=${input2.hostUrl.replace(/\r?\n/g, "")}`,
@@ -26275,7 +27162,7 @@ function writeSidecarLauncher(input2) {
26275
27162
  );
26276
27163
  return;
26277
27164
  }
26278
- (0, import_node_fs16.writeFileSync)(
27165
+ (0, import_node_fs17.writeFileSync)(
26279
27166
  input2.path,
26280
27167
  [
26281
27168
  "#!/usr/bin/env sh",
@@ -26293,9 +27180,9 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
26293
27180
  versionsDir,
26294
27181
  `.tmp-sdk-update-${process.pid}-${Date.now()}`
26295
27182
  );
26296
- (0, import_node_fs16.rmSync)(tempDir, { recursive: true, force: true });
26297
- (0, import_node_fs16.mkdirSync)(tempDir, { recursive: true });
26298
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
27183
+ (0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
27184
+ (0, import_node_fs17.mkdirSync)(tempDir, { recursive: true });
27185
+ (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
26299
27186
  const env = {
26300
27187
  ...process.env,
26301
27188
  PATH: `${(0, import_node_path19.dirname)(plan.nodeBin)}${process.platform === "win32" ? ";" : ":"}${process.env.PATH ?? ""}`
@@ -26313,7 +27200,7 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
26313
27200
  options
26314
27201
  );
26315
27202
  if (installExitCode !== 0) {
26316
- (0, import_node_fs16.rmSync)(tempDir, { recursive: true, force: true });
27203
+ (0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
26317
27204
  return installExitCode;
26318
27205
  }
26319
27206
  const installedVersion = installedPackageVersion(tempDir);
@@ -26321,19 +27208,19 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
26321
27208
  process.stderr.write(
26322
27209
  "Updated Deepline SDK package did not report a version.\n"
26323
27210
  );
26324
- (0, import_node_fs16.rmSync)(tempDir, { recursive: true, force: true });
27211
+ (0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
26325
27212
  return 1;
26326
27213
  }
26327
27214
  const finalDir = (0, import_node_path19.join)(versionsDir, installedVersion);
26328
27215
  const finalEntryPath = entryPathInVersionDir(finalDir);
26329
- if ((0, import_node_fs16.existsSync)(finalEntryPath)) {
26330
- (0, import_node_fs16.rmSync)(tempDir, { recursive: true, force: true });
27216
+ if ((0, import_node_fs17.existsSync)(finalEntryPath)) {
27217
+ (0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
26331
27218
  } else {
26332
- (0, import_node_fs16.rmSync)(finalDir, { recursive: true, force: true });
27219
+ (0, import_node_fs17.rmSync)(finalDir, { recursive: true, force: true });
26333
27220
  try {
26334
- (0, import_node_fs16.renameSync)(tempDir, finalDir);
27221
+ (0, import_node_fs17.renameSync)(tempDir, finalDir);
26335
27222
  } catch (error) {
26336
- (0, import_node_fs16.rmSync)(tempDir, { recursive: true, force: true });
27223
+ (0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
26337
27224
  process.stderr.write(
26338
27225
  `Failed to publish Deepline SDK sidecar update: ${error.message}
26339
27226
  `
@@ -26341,7 +27228,7 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
26341
27228
  return 1;
26342
27229
  }
26343
27230
  }
26344
- if (!(0, import_node_fs16.existsSync)(finalEntryPath)) {
27231
+ if (!(0, import_node_fs17.existsSync)(finalEntryPath)) {
26345
27232
  process.stderr.write(
26346
27233
  `Updated Deepline SDK CLI entrypoint missing: ${finalEntryPath}
26347
27234
  `
@@ -26355,27 +27242,27 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
26355
27242
  nodeBin: plan.nodeBin,
26356
27243
  entryPath: finalEntryPath
26357
27244
  });
26358
- (0, import_node_fs16.writeFileSync)(
27245
+ (0, import_node_fs17.writeFileSync)(
26359
27246
  (0, import_node_path19.join)(plan.stateDir, ".version"),
26360
27247
  `${installedVersion}
26361
27248
  `,
26362
27249
  "utf8"
26363
27250
  );
26364
- (0, import_node_fs16.writeFileSync)(
27251
+ (0, import_node_fs17.writeFileSync)(
26365
27252
  (0, import_node_path19.join)(plan.stateDir, ".install-method"),
26366
27253
  "python-sidecar\n",
26367
27254
  "utf8"
26368
27255
  );
26369
- (0, import_node_fs16.writeFileSync)(
27256
+ (0, import_node_fs17.writeFileSync)(
26370
27257
  (0, import_node_path19.join)(plan.stateDir, ".command-path"),
26371
27258
  `${plan.sidecarPath}
26372
27259
  `,
26373
27260
  "utf8"
26374
27261
  );
26375
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".runner"), "node\n", "utf8");
26376
- (0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".node-bin"), `${plan.nodeBin}
27262
+ (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".runner"), "node\n", "utf8");
27263
+ (0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".node-bin"), `${plan.nodeBin}
26377
27264
  `, "utf8");
26378
- (0, import_node_fs16.writeFileSync)(
27265
+ (0, import_node_fs17.writeFileSync)(
26379
27266
  (0, import_node_path19.join)(plan.stateDir, ".entry-path"),
26380
27267
  `${finalEntryPath}
26381
27268
  `,
@@ -26979,10 +27866,10 @@ function topLevelCommandKnown(program, commandName) {
26979
27866
  );
26980
27867
  }
26981
27868
  async function runPlayRunnerHealthCheck() {
26982
- const dir = await (0, import_promises5.mkdtemp)((0, import_node_path20.join)((0, import_node_os15.tmpdir)(), "deepline-health-play-"));
27869
+ const dir = await (0, import_promises6.mkdtemp)((0, import_node_path20.join)((0, import_node_os15.tmpdir)(), "deepline-health-play-"));
26983
27870
  const file = (0, import_node_path20.join)(dir, "health-check.play.ts");
26984
27871
  try {
26985
- await (0, import_promises5.writeFile)(
27872
+ await (0, import_promises6.writeFile)(
26986
27873
  file,
26987
27874
  [
26988
27875
  "import { definePlay } from 'deepline';",
@@ -27032,7 +27919,7 @@ async function runPlayRunnerHealthCheck() {
27032
27919
  }
27033
27920
  };
27034
27921
  } finally {
27035
- await (0, import_promises5.rm)(dir, { recursive: true, force: true });
27922
+ await (0, import_promises6.rm)(dir, { recursive: true, force: true });
27036
27923
  }
27037
27924
  }
27038
27925
  function pickString(value, ...keys) {