deepline 0.1.186 → 0.1.188
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/bundling-sources/apps/play-runner-workers/src/entry.ts +53 -17
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +26 -0
- package/dist/bundling-sources/sdk/src/play.ts +24 -3
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/sdk/src/types.ts +88 -0
- package/dist/cli/index.js +1206 -216
- package/dist/cli/index.mjs +1152 -162
- package/dist/index.d.mts +113 -3
- package/dist/index.d.ts +113 -3
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
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
|
|
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.
|
|
626
|
+
version: "0.1.188",
|
|
627
627
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
628
628
|
supportPolicy: {
|
|
629
|
-
latest: "0.1.
|
|
629
|
+
latest: "0.1.188",
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -17320,11 +17587,12 @@ function helperSource() {
|
|
|
17320
17587
|
|
|
17321
17588
|
// src/cli/commands/enrich.ts
|
|
17322
17589
|
var ENRICH_EXPORT_PAGE_SIZE = 5e3;
|
|
17323
|
-
var ENRICH_AUTO_BATCH_ROWS =
|
|
17590
|
+
var ENRICH_AUTO_BATCH_ROWS = 200;
|
|
17324
17591
|
var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 25;
|
|
17325
17592
|
var ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS = 50;
|
|
17326
17593
|
var ENRICH_EXPORT_BACKING_ROWS_WAIT_MS = 6e4;
|
|
17327
17594
|
var ENRICH_EXPORT_BACKING_ROWS_POLL_MS = 1e3;
|
|
17595
|
+
var ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS = [1e3, 3e3, 7e3];
|
|
17328
17596
|
var ENRICH_SOURCE_ROW_INDEX_COLUMN = "__deeplineSourceRowIndex";
|
|
17329
17597
|
var ENRICH_ORIGINAL_SOURCE_ROW_INDEX_COLUMN = "__deeplineOriginalSourceRowIndex";
|
|
17330
17598
|
var ENRICH_CELL_META_FIELD = "__deeplineCellMeta";
|
|
@@ -17475,6 +17743,13 @@ function enrichExportBackingRowsWaitMs() {
|
|
|
17475
17743
|
const parsed = Number.parseInt(raw, 10);
|
|
17476
17744
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : ENRICH_EXPORT_BACKING_ROWS_WAIT_MS;
|
|
17477
17745
|
}
|
|
17746
|
+
function enrichCustomerDbFailureLookupRetryDelaysMs() {
|
|
17747
|
+
const raw = process.env.DEEPLINE_ENRICH_CUSTOMER_DB_LOOKUP_RETRY_DELAYS_MS?.trim();
|
|
17748
|
+
if (!raw) {
|
|
17749
|
+
return ENRICH_CUSTOMER_DB_FAILURE_LOOKUP_RETRY_DELAYS_MS;
|
|
17750
|
+
}
|
|
17751
|
+
return raw.split(",").map((part) => Number.parseInt(part.trim(), 10)).filter((value) => Number.isFinite(value) && value >= 0);
|
|
17752
|
+
}
|
|
17478
17753
|
function emitEnrichDebugValidationLines(config) {
|
|
17479
17754
|
for (const line of buildEnrichDebugValidationLines(config)) {
|
|
17480
17755
|
emitEnrichDebug(line);
|
|
@@ -18415,13 +18690,71 @@ function failureAliasFromCellMeta(cellMeta) {
|
|
|
18415
18690
|
}
|
|
18416
18691
|
return null;
|
|
18417
18692
|
}
|
|
18693
|
+
function formatEnrichDiagnosticError(error) {
|
|
18694
|
+
if (error instanceof DeeplineError) {
|
|
18695
|
+
const status = error.statusCode ? `HTTP ${error.statusCode}: ` : "";
|
|
18696
|
+
const code = error.code && error.code !== "API_ERROR" ? ` [${error.code}]` : "";
|
|
18697
|
+
return `${status}${error.message}${code}`;
|
|
18698
|
+
}
|
|
18699
|
+
return error instanceof Error ? error.message : String(error);
|
|
18700
|
+
}
|
|
18701
|
+
function isRetryableCustomerDbLookupError(error) {
|
|
18702
|
+
if (error instanceof DeeplineError) {
|
|
18703
|
+
const status = error.statusCode;
|
|
18704
|
+
if (status === 408 || status === 425 || status === 429 || status === 503 || typeof status === "number" && status >= 500) {
|
|
18705
|
+
return true;
|
|
18706
|
+
}
|
|
18707
|
+
if (error.code === "NETWORK_TIMEOUT" || error.code === "NETWORK_ABORTED" || error.code === "NETWORK_ERROR" || error.code === "42P01") {
|
|
18708
|
+
return true;
|
|
18709
|
+
}
|
|
18710
|
+
}
|
|
18711
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18712
|
+
return /Internal Server Error|fetch failed|ECONNRESET|ETIMEDOUT|timed out after \d+ms while waiting for a response|Unable to connect|relation .* does not exist|Neon API request failed \(404\)|ingestion plane .*not ready/i.test(
|
|
18713
|
+
message
|
|
18714
|
+
);
|
|
18715
|
+
}
|
|
18716
|
+
function customerDbLookupUnavailableIssue(input2) {
|
|
18717
|
+
const command = input2.customerDb.command ?? (input2.customerDb.sql ? `deepline db query --sql ${shellSingleQuote2(input2.customerDb.sql)} --json` : void 0);
|
|
18718
|
+
return {
|
|
18719
|
+
issue_id: `customer-db-failure-lookup-${input2.customerDb.runId ?? "run"}`,
|
|
18720
|
+
kind: "customer_db_lookup_unavailable",
|
|
18721
|
+
severity: "needs_attention",
|
|
18722
|
+
message: "Enrich completed, but Deepline could not inspect the Customer DB backing table for failed row details yet.",
|
|
18723
|
+
next_steps: [
|
|
18724
|
+
"Use the Customer DB query command below to inspect the durable rows after the data plane settles.",
|
|
18725
|
+
"If the command keeps failing, inspect the run output and runtime sheet export instead of rerunning provider enrichments blindly."
|
|
18726
|
+
],
|
|
18727
|
+
follow_up_commands: command ? [
|
|
18728
|
+
{
|
|
18729
|
+
label: "query customer db",
|
|
18730
|
+
command,
|
|
18731
|
+
path: input2.customerDb.datasetPath
|
|
18732
|
+
}
|
|
18733
|
+
] : [],
|
|
18734
|
+
...input2.customerDb.runId ? { run_id: input2.customerDb.runId } : {},
|
|
18735
|
+
error: formatEnrichDiagnosticError(input2.error),
|
|
18736
|
+
attempts: input2.attempts
|
|
18737
|
+
};
|
|
18738
|
+
}
|
|
18739
|
+
function emitCustomerDbLookupUnavailableWarning(issue) {
|
|
18740
|
+
process.stderr.write(`Warning: ${issue.message}
|
|
18741
|
+
`);
|
|
18742
|
+
if (issue.error) {
|
|
18743
|
+
process.stderr.write(`Warning detail: ${issue.error}
|
|
18744
|
+
`);
|
|
18745
|
+
}
|
|
18746
|
+
for (const command of issue.follow_up_commands) {
|
|
18747
|
+
process.stderr.write(`Command: ${command.label}: ${command.command}
|
|
18748
|
+
`);
|
|
18749
|
+
}
|
|
18750
|
+
}
|
|
18418
18751
|
async function collectCustomerDbFailureJobs(input2) {
|
|
18419
18752
|
const customerDb = enrichCustomerDbJson({
|
|
18420
18753
|
status: input2.status,
|
|
18421
18754
|
client: input2.client
|
|
18422
18755
|
});
|
|
18423
18756
|
if (!customerDb?.runId || !customerDb.sqlQualifiedTableName) {
|
|
18424
|
-
return [];
|
|
18757
|
+
return { jobs: [], issue: null };
|
|
18425
18758
|
}
|
|
18426
18759
|
const fallbackAliases = collectHardFailureAliasSpecs(input2.config);
|
|
18427
18760
|
const fallbackAlias = fallbackAliases[0]?.alias ?? "enrich";
|
|
@@ -18429,16 +18762,49 @@ async function collectCustomerDbFailureJobs(input2) {
|
|
|
18429
18762
|
fallbackAliases.map((spec, index) => [normalizeAlias2(spec.alias), index])
|
|
18430
18763
|
);
|
|
18431
18764
|
const sql = `select _input_index, _status, _error, _cell_meta from ${customerDb.sqlQualifiedTableName} where _run_id = ${sqlStringLiteral(customerDb.runId)} and (_error is not null or lower(coalesce(_status, '')) in ('failed', 'error')) order by _input_index limit 1000`;
|
|
18432
|
-
const
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18765
|
+
const retryDelays = enrichCustomerDbFailureLookupRetryDelaysMs();
|
|
18766
|
+
let lastError = null;
|
|
18767
|
+
let attempts = 0;
|
|
18768
|
+
let result = null;
|
|
18769
|
+
for (let attempt = 0; attempt <= retryDelays.length; attempt += 1) {
|
|
18770
|
+
try {
|
|
18771
|
+
attempts = attempt + 1;
|
|
18772
|
+
result = await input2.client.queryCustomerDb({
|
|
18773
|
+
sql,
|
|
18774
|
+
maxRows: 1e3
|
|
18775
|
+
});
|
|
18776
|
+
lastError = null;
|
|
18777
|
+
break;
|
|
18778
|
+
} catch (error) {
|
|
18779
|
+
lastError = error;
|
|
18780
|
+
if (attempt >= retryDelays.length || !isRetryableCustomerDbLookupError(error)) {
|
|
18781
|
+
break;
|
|
18782
|
+
}
|
|
18783
|
+
const delayMs = retryDelays[attempt] ?? 0;
|
|
18784
|
+
emitEnrichDebug(
|
|
18785
|
+
`customer_db failure lookup retrying after ${delayMs}ms: ${formatEnrichDiagnosticError(error)}`
|
|
18786
|
+
);
|
|
18787
|
+
if (delayMs > 0) {
|
|
18788
|
+
await sleep6(delayMs);
|
|
18789
|
+
}
|
|
18790
|
+
}
|
|
18791
|
+
}
|
|
18792
|
+
if (!result) {
|
|
18793
|
+
return {
|
|
18794
|
+
jobs: [],
|
|
18795
|
+
issue: customerDbLookupUnavailableIssue({
|
|
18796
|
+
customerDb,
|
|
18797
|
+
error: lastError,
|
|
18798
|
+
attempts
|
|
18799
|
+
})
|
|
18800
|
+
};
|
|
18801
|
+
}
|
|
18436
18802
|
const rows = Array.isArray(result.rows) ? result.rows : [];
|
|
18437
18803
|
const failedRows = rows.filter((row) => {
|
|
18438
18804
|
const status = typeof row._status === "string" ? row._status.trim().toLowerCase() : "";
|
|
18439
18805
|
return typeof row._error === "string" && row._error.trim() || status === "failed" || status === "error";
|
|
18440
18806
|
});
|
|
18441
|
-
|
|
18807
|
+
const jobs = failedRows.map((row, index) => {
|
|
18442
18808
|
const metaFailure = failureAliasFromCellMeta(row._cell_meta);
|
|
18443
18809
|
const alias = metaFailure?.alias ?? fallbackAlias;
|
|
18444
18810
|
const normalizedAlias = normalizeAlias2(alias);
|
|
@@ -18462,6 +18828,7 @@ async function collectCustomerDbFailureJobs(input2) {
|
|
|
18462
18828
|
...metaFailure?.provider ? { provider: metaFailure.provider } : {}
|
|
18463
18829
|
};
|
|
18464
18830
|
});
|
|
18831
|
+
return { jobs, issue: null };
|
|
18465
18832
|
}
|
|
18466
18833
|
async function buildEnrichFailureReport(input2) {
|
|
18467
18834
|
const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
|
|
@@ -18989,9 +19356,7 @@ function collectWaterfallAliasSpecs(config) {
|
|
|
18989
19356
|
alias,
|
|
18990
19357
|
childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
|
|
18991
19358
|
childRunIfJsByAlias: new Map(
|
|
18992
|
-
activeChildren.map(
|
|
18993
|
-
(child) => [child.alias, child.run_if_js]
|
|
18994
|
-
)
|
|
19359
|
+
activeChildren.map((child) => [child.alias, child.run_if_js])
|
|
18995
19360
|
),
|
|
18996
19361
|
childToolsByAlias: new Map(
|
|
18997
19362
|
activeChildren.map(
|
|
@@ -19767,21 +20132,26 @@ async function maybeEmitEnrichFailureReport(input2) {
|
|
|
19767
20132
|
status: input2.status,
|
|
19768
20133
|
rowRange: input2.statusRowRange ?? input2.rowRange
|
|
19769
20134
|
});
|
|
19770
|
-
const
|
|
20135
|
+
const customerDbDiagnostics = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? { jobs: [], issue: null } : await collectCustomerDbFailureJobs({
|
|
19771
20136
|
client: input2.client,
|
|
19772
20137
|
status: input2.status,
|
|
19773
20138
|
config: input2.config
|
|
19774
20139
|
});
|
|
20140
|
+
const customerDbJobs = customerDbDiagnostics.jobs;
|
|
20141
|
+
if (customerDbDiagnostics.issue) {
|
|
20142
|
+
emitCustomerDbLookupUnavailableWarning(customerDbDiagnostics.issue);
|
|
20143
|
+
}
|
|
20144
|
+
const allEnrichIssues = enrichIssues;
|
|
19775
20145
|
const jobs = rowJobs.length > 0 || statusJobs.length > 0 || customerDbJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(
|
|
19776
20146
|
mergeEnrichFailureJobs(rowJobs, statusJobs),
|
|
19777
20147
|
customerDbJobs
|
|
19778
20148
|
) : [];
|
|
19779
|
-
if (jobs.length === 0 &&
|
|
20149
|
+
if (jobs.length === 0 && allEnrichIssues.length === 0) {
|
|
19780
20150
|
return null;
|
|
19781
20151
|
}
|
|
19782
20152
|
const reportPath = await persistEnrichFailureReport({
|
|
19783
20153
|
jobs,
|
|
19784
|
-
issues:
|
|
20154
|
+
issues: allEnrichIssues,
|
|
19785
20155
|
apiUrl: input2.client.baseUrl,
|
|
19786
20156
|
outputPath: input2.outputPath,
|
|
19787
20157
|
rows: input2.rowRange
|
|
@@ -19801,13 +20171,13 @@ async function maybeEmitEnrichFailureReport(input2) {
|
|
|
19801
20171
|
`);
|
|
19802
20172
|
}
|
|
19803
20173
|
}
|
|
19804
|
-
if (
|
|
20174
|
+
if (allEnrichIssues.length > 0) {
|
|
19805
20175
|
process.stderr.write("Enrichment needs attention.\n");
|
|
19806
20176
|
process.stderr.write("Issue preview (up to 5 enrichment issues):\n");
|
|
19807
20177
|
process.stderr.write(
|
|
19808
20178
|
"issue_id column severity selected_rows rows_with_value message\n"
|
|
19809
20179
|
);
|
|
19810
|
-
for (const issue of
|
|
20180
|
+
for (const issue of allEnrichIssues.slice(0, 5)) {
|
|
19811
20181
|
process.stderr.write(
|
|
19812
20182
|
`${issue.issue_id} ${issue.column} ${issue.severity} ${issue.selected_rows} ${issue.rows_with_value} ${issue.message}
|
|
19813
20183
|
`
|
|
@@ -19821,9 +20191,9 @@ async function maybeEmitEnrichFailureReport(input2) {
|
|
|
19821
20191
|
`);
|
|
19822
20192
|
}
|
|
19823
20193
|
}
|
|
19824
|
-
if (
|
|
20194
|
+
if (allEnrichIssues.length > 5) {
|
|
19825
20195
|
process.stderr.write(
|
|
19826
|
-
`Showing 5 of ${
|
|
20196
|
+
`Showing 5 of ${allEnrichIssues.length} enrichment issues.
|
|
19827
20197
|
`
|
|
19828
20198
|
);
|
|
19829
20199
|
}
|
|
@@ -19841,12 +20211,12 @@ async function maybeEmitEnrichFailureReport(input2) {
|
|
|
19841
20211
|
process.stderr.write(
|
|
19842
20212
|
jobs.length > 0 ? "Enrichment failed. See report above.\n" : "Enrichment produced no values for at least one requested waterfall. See issue preview above.\n"
|
|
19843
20213
|
);
|
|
19844
|
-
return { path: reportPath, jobs, issues:
|
|
20214
|
+
return { path: reportPath, jobs, issues: allEnrichIssues };
|
|
19845
20215
|
}
|
|
19846
20216
|
process.stderr.write(
|
|
19847
20217
|
jobs.length > 0 ? "Enrichment failed.\n" : "Enrichment needs attention.\n"
|
|
19848
20218
|
);
|
|
19849
|
-
return { path: "", jobs, issues:
|
|
20219
|
+
return { path: "", jobs, issues: allEnrichIssues };
|
|
19850
20220
|
}
|
|
19851
20221
|
function mergePreferredColumns(preferredColumns, rows) {
|
|
19852
20222
|
const columns = [];
|
|
@@ -21763,44 +22133,455 @@ Examples:
|
|
|
21763
22133
|
}
|
|
21764
22134
|
|
|
21765
22135
|
// src/cli/commands/monitors.ts
|
|
22136
|
+
var import_node_fs12 = require("fs");
|
|
22137
|
+
var import_promises4 = require("readline/promises");
|
|
21766
22138
|
var FORBIDDEN_AS_API_ERROR = { forbiddenAsApiError: true };
|
|
22139
|
+
var JSON_OPTION_DESCRIPTION = "Emit JSON output. Also automatic when stdout is piped";
|
|
22140
|
+
function withJsonOption(command) {
|
|
22141
|
+
return command.option("--json", JSON_OPTION_DESCRIPTION);
|
|
22142
|
+
}
|
|
22143
|
+
var COMPACT_OPTION_DESCRIPTION = "Ask the server for high-signal fields only (smaller output for agent loops)";
|
|
21767
22144
|
function buildHttpClient() {
|
|
21768
22145
|
return new HttpClient(resolveConfig());
|
|
21769
22146
|
}
|
|
21770
|
-
|
|
22147
|
+
var MonitorsUsageError = class extends Error {
|
|
22148
|
+
code = "MONITORS_USAGE_ERROR";
|
|
22149
|
+
constructor(message) {
|
|
22150
|
+
super(message);
|
|
22151
|
+
this.name = "MonitorsUsageError";
|
|
22152
|
+
}
|
|
22153
|
+
};
|
|
22154
|
+
var MonitorDryRunUnsupportedError = class extends Error {
|
|
22155
|
+
code = "MONITOR_DRY_RUN_UNSUPPORTED";
|
|
22156
|
+
constructor(message) {
|
|
22157
|
+
super(message);
|
|
22158
|
+
this.name = "MonitorDryRunUnsupportedError";
|
|
22159
|
+
}
|
|
22160
|
+
};
|
|
22161
|
+
function monitorsErrorExitCode(error) {
|
|
22162
|
+
if (error instanceof MonitorsUsageError) return 2;
|
|
22163
|
+
if (error instanceof AuthError) return 3;
|
|
22164
|
+
if (error instanceof DeeplineError) {
|
|
22165
|
+
const status = error.statusCode;
|
|
22166
|
+
if (status === 401 || status === 403) return 3;
|
|
22167
|
+
if (status === 404) return 4;
|
|
22168
|
+
if (status === 400 || status === 422) return 7;
|
|
22169
|
+
return 5;
|
|
22170
|
+
}
|
|
22171
|
+
return 5;
|
|
22172
|
+
}
|
|
22173
|
+
function monitorsFailureNextCommand(error, exitCode) {
|
|
22174
|
+
if (error instanceof DeeplineError && error.code === "monitor_access_required") {
|
|
22175
|
+
return "deepline monitors status";
|
|
22176
|
+
}
|
|
22177
|
+
if (exitCode === 3) return "deepline auth status --json";
|
|
22178
|
+
if (exitCode === 4) return "deepline monitors list --status all --json";
|
|
22179
|
+
return void 0;
|
|
22180
|
+
}
|
|
22181
|
+
function readValidationIssues(error) {
|
|
22182
|
+
if (!(error instanceof DeeplineError)) return [];
|
|
22183
|
+
const response = asRecord(asRecord(error.details)?.response);
|
|
22184
|
+
const issues = Array.isArray(response?.issues) ? response.issues : [];
|
|
22185
|
+
return issues.flatMap((raw) => {
|
|
22186
|
+
const issue = asRecord(raw);
|
|
22187
|
+
if (!issue) return [];
|
|
22188
|
+
return [
|
|
22189
|
+
{
|
|
22190
|
+
...asString(issue.path) ? { path: asString(issue.path) } : {},
|
|
22191
|
+
...asString(issue.message) ? { message: asString(issue.message) } : {}
|
|
22192
|
+
}
|
|
22193
|
+
];
|
|
22194
|
+
});
|
|
22195
|
+
}
|
|
22196
|
+
function reportMonitorsFailure(error) {
|
|
22197
|
+
const exitCode = monitorsErrorExitCode(error);
|
|
22198
|
+
const next = monitorsFailureNextCommand(error, exitCode);
|
|
22199
|
+
const wantsJson = shouldEmitJson(process.argv.includes("--json"));
|
|
22200
|
+
if (wantsJson) {
|
|
22201
|
+
const payload = errorToJsonPayload(error);
|
|
22202
|
+
printJson({
|
|
22203
|
+
ok: false,
|
|
22204
|
+
exitCode,
|
|
22205
|
+
...next ? { next } : {},
|
|
22206
|
+
error: payload.error
|
|
22207
|
+
});
|
|
22208
|
+
} else {
|
|
22209
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22210
|
+
process.stderr.write(`Error: ${message}
|
|
22211
|
+
`);
|
|
22212
|
+
for (const issue of readValidationIssues(error)) {
|
|
22213
|
+
process.stderr.write(
|
|
22214
|
+
` - ${issue.path ? `${issue.path}: ` : ""}${issue.message ?? ""}
|
|
22215
|
+
`
|
|
22216
|
+
);
|
|
22217
|
+
}
|
|
22218
|
+
if (next) process.stderr.write(`Next: ${next}
|
|
22219
|
+
`);
|
|
22220
|
+
}
|
|
22221
|
+
process.exitCode = exitCode;
|
|
22222
|
+
}
|
|
22223
|
+
function monitorsAction(handler) {
|
|
22224
|
+
return async (...args) => {
|
|
22225
|
+
try {
|
|
22226
|
+
await handler(...args);
|
|
22227
|
+
} catch (error) {
|
|
22228
|
+
reportMonitorsFailure(error);
|
|
22229
|
+
}
|
|
22230
|
+
};
|
|
22231
|
+
}
|
|
22232
|
+
function parseJsonObjectArg(raw, argLabel) {
|
|
21771
22233
|
let parsed;
|
|
21772
22234
|
try {
|
|
21773
22235
|
parsed = JSON.parse(raw);
|
|
21774
22236
|
} catch (error) {
|
|
21775
|
-
throw new
|
|
21776
|
-
`${
|
|
22237
|
+
throw new MonitorsUsageError(
|
|
22238
|
+
`${argLabel} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
|
|
21777
22239
|
);
|
|
21778
22240
|
}
|
|
21779
22241
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
21780
|
-
throw new
|
|
22242
|
+
throw new MonitorsUsageError(`${argLabel} must be a JSON object.`);
|
|
21781
22243
|
}
|
|
21782
22244
|
return parsed;
|
|
21783
22245
|
}
|
|
22246
|
+
function resolveMonitorJsonBody(input2) {
|
|
22247
|
+
const readFile3 = input2.readFile ?? ((path) => (0, import_node_fs12.readFileSync)(path, "utf-8"));
|
|
22248
|
+
const readStdin = input2.readStdin ?? (() => (0, import_node_fs12.readFileSync)(0, "utf-8"));
|
|
22249
|
+
if (input2.positional !== void 0 && input2.file !== void 0) {
|
|
22250
|
+
throw new MonitorsUsageError(
|
|
22251
|
+
`Pass exactly one source for ${input2.argLabel}: the positional JSON or --file, not both.`
|
|
22252
|
+
);
|
|
22253
|
+
}
|
|
22254
|
+
if (input2.positional !== void 0) {
|
|
22255
|
+
return parseJsonObjectArg(input2.positional, input2.argLabel);
|
|
22256
|
+
}
|
|
22257
|
+
if (input2.file !== void 0) {
|
|
22258
|
+
if (input2.file === "-") {
|
|
22259
|
+
return parseJsonObjectArg(readStdin(), `${input2.argLabel} (stdin)`);
|
|
22260
|
+
}
|
|
22261
|
+
let raw;
|
|
22262
|
+
try {
|
|
22263
|
+
raw = readFile3(input2.file);
|
|
22264
|
+
} catch (error) {
|
|
22265
|
+
throw new MonitorsUsageError(
|
|
22266
|
+
`Could not read --file ${input2.file}: ${error instanceof Error ? error.message : String(error)}`
|
|
22267
|
+
);
|
|
22268
|
+
}
|
|
22269
|
+
return parseJsonObjectArg(raw, `${input2.argLabel} (--file ${input2.file})`);
|
|
22270
|
+
}
|
|
22271
|
+
throw new MonitorsUsageError(
|
|
22272
|
+
`${input2.command} needs ${input2.argLabel} (a JSON object). Pass it positionally:
|
|
22273
|
+
${input2.command} '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22274
|
+
or from a file / stdin:
|
|
22275
|
+
${input2.command} --file monitor.json
|
|
22276
|
+
cat monitor.json | ${input2.command} --file -`
|
|
22277
|
+
);
|
|
22278
|
+
}
|
|
21784
22279
|
function encodeKey(key) {
|
|
21785
22280
|
return encodeURIComponent(key);
|
|
21786
22281
|
}
|
|
21787
|
-
|
|
22282
|
+
function asRecord(value) {
|
|
22283
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22284
|
+
}
|
|
22285
|
+
function asString(value) {
|
|
22286
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
22287
|
+
}
|
|
22288
|
+
function asFiniteNumber(value) {
|
|
22289
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
22290
|
+
}
|
|
22291
|
+
function yesNo(value) {
|
|
22292
|
+
if (value === true) return "yes";
|
|
22293
|
+
if (value === false) return "no";
|
|
22294
|
+
return "unknown";
|
|
22295
|
+
}
|
|
22296
|
+
function readDeployOutputContract(payload) {
|
|
22297
|
+
const contract = asRecord(payload.output_contract);
|
|
22298
|
+
if (!contract) return { streams: [] };
|
|
22299
|
+
const rawOutputs = Array.isArray(contract.outputs) ? contract.outputs : [];
|
|
22300
|
+
const streams = rawOutputs.flatMap((raw) => {
|
|
22301
|
+
const output2 = asRecord(raw);
|
|
22302
|
+
const stream = output2 ? asString(output2.stream) : void 0;
|
|
22303
|
+
const table = output2 ? asString(output2.table) : void 0;
|
|
22304
|
+
if (!output2 || !stream || !table) return [];
|
|
22305
|
+
const columns = Array.isArray(output2.columns) ? output2.columns.flatMap((rawColumn) => {
|
|
22306
|
+
const column = asRecord(rawColumn);
|
|
22307
|
+
const name = column ? asString(column.name) : void 0;
|
|
22308
|
+
return name ? [name] : [];
|
|
22309
|
+
}) : [];
|
|
22310
|
+
return [
|
|
22311
|
+
{
|
|
22312
|
+
stream,
|
|
22313
|
+
table,
|
|
22314
|
+
columns,
|
|
22315
|
+
isEvent: output2.is_event_stream === true,
|
|
22316
|
+
matchesPayload: output2.matches_payload === true
|
|
22317
|
+
}
|
|
22318
|
+
];
|
|
22319
|
+
});
|
|
22320
|
+
return { tool: asString(contract.tool), streams };
|
|
22321
|
+
}
|
|
22322
|
+
function renderMonitorDeployCompletion(payload) {
|
|
22323
|
+
const monitor = asRecord(payload.monitor);
|
|
22324
|
+
const key = monitor ? asString(monitor.key) : void 0;
|
|
22325
|
+
const { tool, streams } = readDeployOutputContract(payload);
|
|
22326
|
+
if (!key || streams.length === 0) return void 0;
|
|
22327
|
+
const toolId = tool ?? (monitor ? asString(monitor.tool) : void 0) ?? "<tool>";
|
|
22328
|
+
const name = monitor ? asString(monitor.name) : void 0;
|
|
22329
|
+
const status = monitor ? asString(monitor.status) : void 0;
|
|
22330
|
+
const eventStreams = streams.filter((stream) => stream.isEvent);
|
|
22331
|
+
const matched = eventStreams.filter((stream) => stream.matchesPayload);
|
|
22332
|
+
const shown = matched.length ? matched : eventStreams.length ? eventStreams : streams;
|
|
22333
|
+
const primary = shown[0];
|
|
22334
|
+
const lines = [
|
|
22335
|
+
`\u2713 Deployed monitor "${key}"${name ? ` (${name})` : ""} \u2014 tool ${toolId}${status ? `, status ${status}` : ""}`,
|
|
22336
|
+
"",
|
|
22337
|
+
"Output \u2192 Customer DB:"
|
|
22338
|
+
];
|
|
22339
|
+
for (const stream of shown) {
|
|
22340
|
+
lines.push(` ${stream.table} (stream: ${stream.stream})`);
|
|
22341
|
+
lines.push(
|
|
22342
|
+
` columns: ${stream.columns.length ? stream.columns.join(", ") : "(promoted dynamically as events arrive)"}`
|
|
22343
|
+
);
|
|
22344
|
+
}
|
|
22345
|
+
lines.push(
|
|
22346
|
+
"",
|
|
22347
|
+
"This monitor streams new rows into your Customer DB \u2014 there is no manual run.",
|
|
22348
|
+
"Next:",
|
|
22349
|
+
" \u2022 Query the table above directly, or",
|
|
22350
|
+
" \u2022 Run a play on each new row (third arg to definePlay in your .play.ts):",
|
|
22351
|
+
` sqlListeners: [{ id: '${primary.stream}', tool: '${toolId}', stream: '${primary.stream}', operations: ['INSERT'] }]`,
|
|
22352
|
+
" The changed row arrives to your handler as the sqlListener event's `after`.",
|
|
22353
|
+
"",
|
|
22354
|
+
"Reuse: many plays can bind to this one stream \u2014 you do NOT need a separate",
|
|
22355
|
+
"monitor per play. Before deploying another monitor on this tool, run",
|
|
22356
|
+
"`deepline monitors list` and reuse an existing one that covers your scope."
|
|
22357
|
+
);
|
|
22358
|
+
return `${lines.join("\n")}
|
|
22359
|
+
`;
|
|
22360
|
+
}
|
|
22361
|
+
function renderMonitorDeployPlan(payload) {
|
|
22362
|
+
const valid = payload.valid !== false;
|
|
22363
|
+
const lines = [
|
|
22364
|
+
"DRY RUN \u2014 nothing was deployed.",
|
|
22365
|
+
valid ? "Definition: valid" : "Definition: INVALID"
|
|
22366
|
+
];
|
|
22367
|
+
if (!valid) {
|
|
22368
|
+
const issues = Array.isArray(payload.issues) ? payload.issues : [];
|
|
22369
|
+
for (const raw of issues) {
|
|
22370
|
+
const issue = asRecord(raw);
|
|
22371
|
+
const path = issue ? asString(issue.path) : void 0;
|
|
22372
|
+
const message = issue ? asString(issue.message) : void 0;
|
|
22373
|
+
if (message) lines.push(` - ${path ? `${path}: ` : ""}${message}`);
|
|
22374
|
+
}
|
|
22375
|
+
}
|
|
22376
|
+
const estimate = asRecord(payload.deploy_cost_estimate);
|
|
22377
|
+
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
22378
|
+
if (credits !== void 0) {
|
|
22379
|
+
const note = estimate ? asString(estimate.note) : void 0;
|
|
22380
|
+
lines.push(
|
|
22381
|
+
`Deploy cost: would cost ${credits} Deepline credits${note ? ` \u2014 ${note}` : ""}.`
|
|
22382
|
+
);
|
|
22383
|
+
} else {
|
|
22384
|
+
lines.push(
|
|
22385
|
+
"Deploy cost: estimate unavailable from this server (validation only)."
|
|
22386
|
+
);
|
|
22387
|
+
}
|
|
22388
|
+
const candidates = Array.isArray(payload.reuse_candidates) ? payload.reuse_candidates : [];
|
|
22389
|
+
const candidateLines = candidates.flatMap((raw) => {
|
|
22390
|
+
const candidate = asRecord(raw);
|
|
22391
|
+
const key = candidate ? asString(candidate.key) : void 0;
|
|
22392
|
+
if (!candidate || !key) return [];
|
|
22393
|
+
const name = asString(candidate.name);
|
|
22394
|
+
const status = asString(candidate.status);
|
|
22395
|
+
const covers = asString(candidate.covers);
|
|
22396
|
+
return [
|
|
22397
|
+
` ${key}${name ? ` (${name})` : ""}${status ? ` \u2014 ${status}` : ""}${covers ? `; covers ${covers}` : ""}`
|
|
22398
|
+
];
|
|
22399
|
+
});
|
|
22400
|
+
if (candidateLines.length > 0) {
|
|
22401
|
+
lines.push(
|
|
22402
|
+
"",
|
|
22403
|
+
"You may already have a monitor covering this \u2014 check before deploying:",
|
|
22404
|
+
...candidateLines,
|
|
22405
|
+
" Inspect: deepline monitors get <key> --json"
|
|
22406
|
+
);
|
|
22407
|
+
}
|
|
22408
|
+
lines.push(
|
|
22409
|
+
"",
|
|
22410
|
+
valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
|
|
22411
|
+
);
|
|
22412
|
+
return `${lines.join("\n")}
|
|
22413
|
+
`;
|
|
22414
|
+
}
|
|
22415
|
+
function renderMonitorDeletePlan(payload, fallbackKey) {
|
|
22416
|
+
const plan = asRecord(payload.plan);
|
|
22417
|
+
const key = (plan ? asString(plan.monitor_key) : void 0) ?? fallbackKey;
|
|
22418
|
+
const lines = [
|
|
22419
|
+
"DRY RUN \u2014 nothing was deleted.",
|
|
22420
|
+
`Delete plan for monitor "${key}":`,
|
|
22421
|
+
` delete Deepline record: ${yesNo(plan?.would_delete_record)}`,
|
|
22422
|
+
` deprovision upstream provider resource: ${yesNo(plan?.would_deprovision_upstream)}`,
|
|
22423
|
+
"",
|
|
22424
|
+
`Delete for real: deepline monitors delete ${key} --yes`
|
|
22425
|
+
];
|
|
22426
|
+
return `${lines.join("\n")}
|
|
22427
|
+
`;
|
|
22428
|
+
}
|
|
22429
|
+
function renderMonitorReactivatePlan(payload, key) {
|
|
22430
|
+
const estimate = asRecord(payload.cost_estimate);
|
|
22431
|
+
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
22432
|
+
const lines = [
|
|
22433
|
+
"DRY RUN \u2014 nothing was reactivated.",
|
|
22434
|
+
credits !== void 0 ? `Reactivate cost: would cost ${credits} Deepline credits.` : "Reactivate cost: estimate unavailable from this server.",
|
|
22435
|
+
"",
|
|
22436
|
+
`Reactivate for real: deepline monitors reactivate ${key}`
|
|
22437
|
+
];
|
|
22438
|
+
return `${lines.join("\n")}
|
|
22439
|
+
`;
|
|
22440
|
+
}
|
|
22441
|
+
function assertMonitorDryRunAcknowledged(payload, context) {
|
|
22442
|
+
if (payload.dry_run === true) return;
|
|
22443
|
+
throw new MonitorDryRunUnsupportedError(
|
|
22444
|
+
`${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}.`
|
|
22445
|
+
);
|
|
22446
|
+
}
|
|
22447
|
+
function monitorDeleteRequiresYesError(key, options = {}) {
|
|
22448
|
+
const flags = options.localOnly ? " --local-only" : "";
|
|
22449
|
+
return new MonitorsUsageError(
|
|
22450
|
+
`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:
|
|
22451
|
+
deepline monitors delete ${key}${flags} --yes
|
|
22452
|
+
Preview the plan first with:
|
|
22453
|
+
deepline monitors delete ${key}${flags} --dry-run`
|
|
22454
|
+
);
|
|
22455
|
+
}
|
|
22456
|
+
async function handleMonitorsStatus(options) {
|
|
22457
|
+
const http = buildHttpClient();
|
|
22458
|
+
const payload = await http.request(
|
|
22459
|
+
"/api/v2/monitors/access",
|
|
22460
|
+
{ method: "GET" }
|
|
22461
|
+
);
|
|
22462
|
+
const hasAccess = payload.has_access === true;
|
|
22463
|
+
const reason = typeof payload.reason === "string" && payload.reason.trim() ? payload.reason.trim() : void 0;
|
|
22464
|
+
const text = hasAccess ? `\u2713 You have access to Deepline Monitors${reason ? `
|
|
22465
|
+
${reason}` : ""}
|
|
22466
|
+
` : `\u2717 No access to Deepline Monitors${reason ? ` \u2014 ${reason}` : ""}
|
|
22467
|
+
`;
|
|
22468
|
+
printCommandEnvelope(
|
|
22469
|
+
{ has_access: hasAccess, ...reason ? { reason } : {} },
|
|
22470
|
+
{ json: options.json, text }
|
|
22471
|
+
);
|
|
22472
|
+
if (!hasAccess) {
|
|
22473
|
+
process.exitCode = 1;
|
|
22474
|
+
}
|
|
22475
|
+
}
|
|
22476
|
+
function renderAvailableToolsText(payload) {
|
|
22477
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : null;
|
|
22478
|
+
if (!tools) return void 0;
|
|
22479
|
+
const returned = asFiniteNumber(payload.returned) ?? tools.length;
|
|
22480
|
+
const total = asFiniteNumber(payload.total);
|
|
22481
|
+
const lines = [
|
|
22482
|
+
total !== void 0 ? `Monitor tools you can deploy (${returned} of ${total}):` : "Monitor tools you can deploy:"
|
|
22483
|
+
];
|
|
22484
|
+
for (const raw of tools) {
|
|
22485
|
+
const entry = asRecord(raw);
|
|
22486
|
+
const id = entry ? asString(entry.tool) : void 0;
|
|
22487
|
+
if (!entry || !id) continue;
|
|
22488
|
+
const name = asString(entry.name) ?? asString(entry.display_name);
|
|
22489
|
+
const deployedCount = asFiniteNumber(entry.deployed_count);
|
|
22490
|
+
lines.push(
|
|
22491
|
+
` ${id}${name ? ` \u2014 ${name}` : ""}${deployedCount !== void 0 ? ` (deployed: ${deployedCount})` : ""}`
|
|
22492
|
+
);
|
|
22493
|
+
}
|
|
22494
|
+
if (payload.is_truncated === true) {
|
|
22495
|
+
lines.push("List truncated; raise --limit to see more.");
|
|
22496
|
+
}
|
|
22497
|
+
lines.push(
|
|
22498
|
+
"",
|
|
22499
|
+
"Describe one (payload schema + output streams): deepline monitors available <tool-id> --json"
|
|
22500
|
+
);
|
|
22501
|
+
return `${lines.join("\n")}
|
|
22502
|
+
`;
|
|
22503
|
+
}
|
|
22504
|
+
async function handleMonitorsAvailable(toolId, options) {
|
|
22505
|
+
if (toolId !== void 0 && options.tool !== void 0) {
|
|
22506
|
+
if (toolId !== options.tool) {
|
|
22507
|
+
throw new MonitorsUsageError(
|
|
22508
|
+
`Pass the tool id once: got positional "${toolId}" and --tool "${options.tool}". Use: deepline monitors available ${toolId}`
|
|
22509
|
+
);
|
|
22510
|
+
}
|
|
22511
|
+
}
|
|
22512
|
+
const tool = toolId ?? options.tool;
|
|
21788
22513
|
const http = buildHttpClient();
|
|
21789
22514
|
const params = new URLSearchParams();
|
|
21790
22515
|
if (options.provider) params.set("provider", options.provider);
|
|
21791
|
-
if (
|
|
22516
|
+
if (tool) params.set("tool", tool);
|
|
21792
22517
|
if (options.search) params.set("search", options.search);
|
|
21793
22518
|
if (options.limit) params.set("limit", options.limit);
|
|
22519
|
+
const compactList = !tool && !options.full;
|
|
22520
|
+
if (compactList || options.compact) params.set("compact", "true");
|
|
21794
22521
|
const query = params.toString();
|
|
21795
22522
|
const payload = await http.request(
|
|
21796
22523
|
`/api/v2/monitors/tools${query ? `?${query}` : ""}`,
|
|
21797
22524
|
{ method: "GET", ...FORBIDDEN_AS_API_ERROR }
|
|
21798
22525
|
);
|
|
21799
|
-
printCommandEnvelope(payload, {
|
|
22526
|
+
printCommandEnvelope(payload, {
|
|
22527
|
+
json: options.json,
|
|
22528
|
+
// Human list view shows id + name + deployed_count ("deployed: N") so
|
|
22529
|
+
// can-deploy vs already-deployed is visible in one view. Describing a
|
|
22530
|
+
// single tool keeps the full JSON contract (payload schema, streams).
|
|
22531
|
+
text: tool ? void 0 : renderAvailableToolsText(payload)
|
|
22532
|
+
});
|
|
22533
|
+
}
|
|
22534
|
+
function renderDeployedListText(payload, requestedStatus) {
|
|
22535
|
+
const monitors = Array.isArray(payload.monitors) ? payload.monitors : null;
|
|
22536
|
+
if (!monitors) return void 0;
|
|
22537
|
+
const lines = [
|
|
22538
|
+
monitors.length === 0 ? "No deployed monitors matched." : `Deployed monitors (${monitors.length}):`
|
|
22539
|
+
];
|
|
22540
|
+
for (const raw of monitors) {
|
|
22541
|
+
const entry = asRecord(raw);
|
|
22542
|
+
const key = entry ? asString(entry.key) ?? asString(entry.monitor_key) : void 0;
|
|
22543
|
+
if (!entry || !key) continue;
|
|
22544
|
+
const status = asString(entry.status);
|
|
22545
|
+
const tool = asString(entry.tool);
|
|
22546
|
+
const name = asString(entry.name);
|
|
22547
|
+
lines.push(
|
|
22548
|
+
` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
|
|
22549
|
+
);
|
|
22550
|
+
}
|
|
22551
|
+
const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
|
|
22552
|
+
lines.push(
|
|
22553
|
+
`Status filter: ${applied}${requestedStatus === void 0 && applied === "active" ? " (default)" : ""} \u2014 use --status all to include disabled monitors.`
|
|
22554
|
+
);
|
|
22555
|
+
if (monitors.length > 0) {
|
|
22556
|
+
lines.push("", "Inspect one: deepline monitors get <key> --json");
|
|
22557
|
+
}
|
|
22558
|
+
return `${lines.join("\n")}
|
|
22559
|
+
`;
|
|
22560
|
+
}
|
|
22561
|
+
async function handleMonitorsList(options) {
|
|
22562
|
+
const http = buildHttpClient();
|
|
22563
|
+
const params = new URLSearchParams();
|
|
22564
|
+
if (options.status) params.set("status", options.status);
|
|
22565
|
+
if (options.limit) params.set("limit", options.limit);
|
|
22566
|
+
if (options.compact) params.set("compact", "true");
|
|
22567
|
+
const query = params.toString();
|
|
22568
|
+
const payload = await http.request(
|
|
22569
|
+
`/api/v2/monitors/deployed${query ? `?${query}` : ""}`,
|
|
22570
|
+
{ method: "GET", ...FORBIDDEN_AS_API_ERROR }
|
|
22571
|
+
);
|
|
22572
|
+
printCommandEnvelope(payload, {
|
|
22573
|
+
json: options.json,
|
|
22574
|
+
text: renderDeployedListText(payload, options.status)
|
|
22575
|
+
});
|
|
21800
22576
|
}
|
|
21801
22577
|
async function handleMonitorsCheck(definition, options) {
|
|
21802
22578
|
const http = buildHttpClient();
|
|
21803
|
-
const body =
|
|
22579
|
+
const body = resolveMonitorJsonBody({
|
|
22580
|
+
positional: definition,
|
|
22581
|
+
file: options.file,
|
|
22582
|
+
argLabel: "<definition>",
|
|
22583
|
+
command: "deepline monitors check"
|
|
22584
|
+
});
|
|
21804
22585
|
const payload = await http.request(
|
|
21805
22586
|
"/api/v2/monitors/check",
|
|
21806
22587
|
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
@@ -21809,26 +22590,37 @@ async function handleMonitorsCheck(definition, options) {
|
|
|
21809
22590
|
}
|
|
21810
22591
|
async function handleMonitorsDeploy(definition, options) {
|
|
21811
22592
|
const http = buildHttpClient();
|
|
21812
|
-
const body =
|
|
22593
|
+
const body = resolveMonitorJsonBody({
|
|
22594
|
+
positional: definition,
|
|
22595
|
+
file: options.file,
|
|
22596
|
+
argLabel: "<definition>",
|
|
22597
|
+
command: "deepline monitors deploy"
|
|
22598
|
+
});
|
|
22599
|
+
if (options.dryRun) {
|
|
22600
|
+
const payload2 = await http.request(
|
|
22601
|
+
"/api/v2/monitors/check",
|
|
22602
|
+
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
22603
|
+
);
|
|
22604
|
+
const valid = payload2.valid !== false;
|
|
22605
|
+
printCommandEnvelope(
|
|
22606
|
+
{ dry_run: true, ...payload2 },
|
|
22607
|
+
{ json: options.json, text: renderMonitorDeployPlan(payload2) }
|
|
22608
|
+
);
|
|
22609
|
+
if (!valid) {
|
|
22610
|
+
process.exitCode = 7;
|
|
22611
|
+
}
|
|
22612
|
+
return;
|
|
22613
|
+
}
|
|
21813
22614
|
const payload = await http.request(
|
|
21814
22615
|
"/api/v2/monitors/deploy",
|
|
21815
22616
|
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
21816
22617
|
);
|
|
21817
|
-
printCommandEnvelope(payload, {
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
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 });
|
|
22618
|
+
printCommandEnvelope(payload, {
|
|
22619
|
+
json: options.json,
|
|
22620
|
+
text: renderMonitorDeployCompletion(payload)
|
|
22621
|
+
});
|
|
21830
22622
|
}
|
|
21831
|
-
async function
|
|
22623
|
+
async function handleMonitorsGet(key, options) {
|
|
21832
22624
|
const http = buildHttpClient();
|
|
21833
22625
|
const payload = await http.request(
|
|
21834
22626
|
`/api/v2/monitors/deployed/${encodeKey(key)}`,
|
|
@@ -21836,10 +22628,58 @@ async function handleDeployedGet(key, options) {
|
|
|
21836
22628
|
);
|
|
21837
22629
|
printCommandEnvelope(payload, { json: options.json });
|
|
21838
22630
|
}
|
|
21839
|
-
async function
|
|
22631
|
+
async function confirmMonitorDelete(key, options) {
|
|
22632
|
+
const rl = (0, import_promises4.createInterface)({
|
|
22633
|
+
input: process.stdin,
|
|
22634
|
+
output: process.stderr
|
|
22635
|
+
});
|
|
22636
|
+
try {
|
|
22637
|
+
const consequence = options.localOnly ? "This removes the Deepline record only (the upstream provider resource is left in place)." : "This deprovisions the upstream provider resource.";
|
|
22638
|
+
const answer = await rl.question(
|
|
22639
|
+
`Delete monitor "${key}"? ${consequence} [y/N] `
|
|
22640
|
+
);
|
|
22641
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
22642
|
+
} finally {
|
|
22643
|
+
rl.close();
|
|
22644
|
+
}
|
|
22645
|
+
}
|
|
22646
|
+
async function handleMonitorsDelete(key, options) {
|
|
21840
22647
|
const http = buildHttpClient();
|
|
21841
22648
|
const params = new URLSearchParams();
|
|
21842
22649
|
if (options.localOnly) params.set("local_only", "true");
|
|
22650
|
+
if (options.dryRun) {
|
|
22651
|
+
params.set("dry_run", "true");
|
|
22652
|
+
const payload2 = await http.request(
|
|
22653
|
+
`/api/v2/monitors/deployed/${encodeKey(key)}?${params.toString()}`,
|
|
22654
|
+
{ method: "DELETE", ...FORBIDDEN_AS_API_ERROR }
|
|
22655
|
+
);
|
|
22656
|
+
assertMonitorDryRunAcknowledged(payload2, {
|
|
22657
|
+
command: "deepline monitors delete",
|
|
22658
|
+
mutation: "delete"
|
|
22659
|
+
});
|
|
22660
|
+
printCommandEnvelope(payload2, {
|
|
22661
|
+
json: options.json,
|
|
22662
|
+
text: renderMonitorDeletePlan(payload2, key)
|
|
22663
|
+
});
|
|
22664
|
+
return;
|
|
22665
|
+
}
|
|
22666
|
+
if (!options.yes) {
|
|
22667
|
+
const interactive = process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
22668
|
+
if (!interactive) {
|
|
22669
|
+
throw monitorDeleteRequiresYesError(key, {
|
|
22670
|
+
localOnly: options.localOnly
|
|
22671
|
+
});
|
|
22672
|
+
}
|
|
22673
|
+
const confirmed = await confirmMonitorDelete(key, {
|
|
22674
|
+
localOnly: options.localOnly
|
|
22675
|
+
});
|
|
22676
|
+
if (!confirmed) {
|
|
22677
|
+
process.stderr.write(`Aborted. Monitor "${key}" was not deleted.
|
|
22678
|
+
`);
|
|
22679
|
+
process.exitCode = 2;
|
|
22680
|
+
return;
|
|
22681
|
+
}
|
|
22682
|
+
}
|
|
21843
22683
|
const query = params.toString();
|
|
21844
22684
|
const payload = await http.request(
|
|
21845
22685
|
`/api/v2/monitors/deployed/${encodeKey(key)}${query ? `?${query}` : ""}`,
|
|
@@ -21847,17 +22687,37 @@ async function handleDeployedDelete(key, options) {
|
|
|
21847
22687
|
);
|
|
21848
22688
|
printCommandEnvelope(payload, { json: options.json });
|
|
21849
22689
|
}
|
|
21850
|
-
async function
|
|
22690
|
+
async function handleMonitorsUpdate(key, patch, options) {
|
|
21851
22691
|
const http = buildHttpClient();
|
|
21852
|
-
const body =
|
|
22692
|
+
const body = resolveMonitorJsonBody({
|
|
22693
|
+
positional: patch,
|
|
22694
|
+
file: options.file,
|
|
22695
|
+
argLabel: "<patch>",
|
|
22696
|
+
command: `deepline monitors update ${key}`
|
|
22697
|
+
});
|
|
21853
22698
|
const payload = await http.request(
|
|
21854
22699
|
`/api/v2/monitors/deployed/${encodeKey(key)}`,
|
|
21855
22700
|
{ method: "PATCH", body, ...FORBIDDEN_AS_API_ERROR }
|
|
21856
22701
|
);
|
|
21857
22702
|
printCommandEnvelope(payload, { json: options.json });
|
|
21858
22703
|
}
|
|
21859
|
-
async function
|
|
22704
|
+
async function handleMonitorsReactivate(key, options) {
|
|
21860
22705
|
const http = buildHttpClient();
|
|
22706
|
+
if (options.dryRun) {
|
|
22707
|
+
const payload2 = await http.request(
|
|
22708
|
+
`/api/v2/monitors/deployed/${encodeKey(key)}/reactivate?dry_run=true`,
|
|
22709
|
+
{ method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
|
|
22710
|
+
);
|
|
22711
|
+
assertMonitorDryRunAcknowledged(payload2, {
|
|
22712
|
+
command: "deepline monitors reactivate",
|
|
22713
|
+
mutation: "reactivate"
|
|
22714
|
+
});
|
|
22715
|
+
printCommandEnvelope(payload2, {
|
|
22716
|
+
json: options.json,
|
|
22717
|
+
text: renderMonitorReactivatePlan(payload2, key)
|
|
22718
|
+
});
|
|
22719
|
+
return;
|
|
22720
|
+
}
|
|
21861
22721
|
const payload = await http.request(
|
|
21862
22722
|
`/api/v2/monitors/deployed/${encodeKey(key)}/reactivate`,
|
|
21863
22723
|
{ method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
|
|
@@ -21865,116 +22725,240 @@ async function handleReactivate(key, options) {
|
|
|
21865
22725
|
printCommandEnvelope(payload, { json: options.json });
|
|
21866
22726
|
}
|
|
21867
22727
|
function registerMonitorsCommands(program) {
|
|
21868
|
-
const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").addHelpText(
|
|
22728
|
+
const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").showSuggestionAfterError(true).addHelpText(
|
|
21869
22729
|
"after",
|
|
21870
22730
|
`
|
|
21871
22731
|
Notes:
|
|
21872
|
-
|
|
21873
|
-
|
|
21874
|
-
|
|
22732
|
+
Deepline monitors are provider-backed signal feeds: a monitor writes provider
|
|
22733
|
+
events into a Customer DB table; a play reacts to each new row via a
|
|
22734
|
+
sqlListeners trigger \u2014 see \`deepline plays bootstrap monitor-triggered\`.
|
|
22735
|
+
Access is granted by a Deepline admin via Admin -> Rollouts; until then these
|
|
22736
|
+
commands return a clear monitor_access_required error.
|
|
22737
|
+
|
|
22738
|
+
Exit codes:
|
|
22739
|
+
0 success; 2 usage/local input; 3 auth or permission; 4 not found;
|
|
22740
|
+
5 server failure; 7 validation failed.
|
|
22741
|
+
\`monitors status\` exits 1 when you lack monitor access (documented contract).
|
|
21875
22742
|
|
|
21876
22743
|
Examples:
|
|
21877
|
-
deepline monitors
|
|
21878
|
-
deepline monitors
|
|
21879
|
-
deepline monitors
|
|
21880
|
-
deepline monitors
|
|
21881
|
-
deepline monitors
|
|
21882
|
-
deepline monitors
|
|
22744
|
+
deepline monitors status --json
|
|
22745
|
+
deepline monitors available --json # compact list by default
|
|
22746
|
+
deepline monitors available --full --json # complete catalog
|
|
22747
|
+
deepline monitors available theirstack.saved_search_webhook --json
|
|
22748
|
+
deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22749
|
+
deepline monitors deploy --dry-run --file monitor.json
|
|
22750
|
+
deepline monitors deploy --file monitor.json
|
|
22751
|
+
deepline monitors list --status all --json
|
|
22752
|
+
deepline monitors get my-monitor --json
|
|
22753
|
+
deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
|
|
22754
|
+
deepline monitors delete my-monitor --dry-run
|
|
22755
|
+
deepline monitors reactivate my-monitor --dry-run
|
|
21883
22756
|
`
|
|
21884
22757
|
);
|
|
21885
|
-
|
|
21886
|
-
"
|
|
21887
|
-
|
|
22758
|
+
withJsonOption(
|
|
22759
|
+
monitors.command("status").description("Check whether you have access to Deepline monitors.").addHelpText(
|
|
22760
|
+
"after",
|
|
22761
|
+
`
|
|
21888
22762
|
Notes:
|
|
21889
|
-
Read-only.
|
|
21890
|
-
|
|
22763
|
+
Read-only access check. Requires authentication but NOT monitor access, so it
|
|
22764
|
+
is safe to run first to confirm whether you can use the monitor commands. Exits
|
|
22765
|
+
0 when you have access and 1 when you do not, so agents can branch on it (this
|
|
22766
|
+
exit-1 denial contract predates the typed monitor exit codes and is kept).
|
|
21891
22767
|
|
|
21892
22768
|
Examples:
|
|
21893
|
-
deepline monitors
|
|
21894
|
-
deepline monitors
|
|
21895
|
-
deepline monitors tools --tool theirstack_jobs --json
|
|
22769
|
+
deepline monitors status
|
|
22770
|
+
deepline monitors status --json
|
|
21896
22771
|
`
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21900
|
-
|
|
22772
|
+
)
|
|
22773
|
+
).action(monitorsAction(handleMonitorsStatus));
|
|
22774
|
+
withJsonOption(
|
|
22775
|
+
monitors.command("available [tool-id]").alias("tools").description(
|
|
22776
|
+
"List the monitor types you can deploy, or describe one by tool id."
|
|
22777
|
+
).addHelpText(
|
|
22778
|
+
"after",
|
|
22779
|
+
`
|
|
21901
22780
|
Notes:
|
|
21902
|
-
Read-only
|
|
21903
|
-
|
|
22781
|
+
Read-only catalog of deployable monitor types. Pass a tool id positionally to
|
|
22782
|
+
describe one (payload schema + output streams). Filter the list with
|
|
22783
|
+
--provider, --search, or --limit. List entries include how many monitors you
|
|
22784
|
+
already have deployed on each tool ("deployed: N") when the server reports it.
|
|
22785
|
+
The list is compact by default (id + name + deployed count); pass --full to
|
|
22786
|
+
get the complete catalog (payload schemas + output streams for every tool).
|
|
22787
|
+
Describing a single tool by id always returns the full contract.
|
|
21904
22788
|
|
|
21905
22789
|
Examples:
|
|
21906
|
-
deepline monitors
|
|
22790
|
+
deepline monitors available
|
|
22791
|
+
deepline monitors available --full --json
|
|
22792
|
+
deepline monitors available --provider theirstack --json
|
|
22793
|
+
deepline monitors available theirstack.saved_search_webhook --json
|
|
22794
|
+
deepline monitors available --search jobs --json
|
|
21907
22795
|
`
|
|
21908
|
-
|
|
21909
|
-
|
|
21910
|
-
|
|
21911
|
-
|
|
22796
|
+
).option("--provider <provider>", "Filter by provider").option(
|
|
22797
|
+
"--tool <tool>",
|
|
22798
|
+
"Describe a single monitor tool by id (same as the positional tool-id)"
|
|
22799
|
+
).option("--search <query>", "Search monitor tools by text").option("--limit <n>", "Limit the number of monitor tools returned").option(
|
|
22800
|
+
"--full",
|
|
22801
|
+
"Return the complete monitor catalog (payload schemas + output streams). The list is compact by default."
|
|
22802
|
+
).option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22803
|
+
).action(monitorsAction(handleMonitorsAvailable));
|
|
22804
|
+
withJsonOption(
|
|
22805
|
+
monitors.command("list").description("List the monitors you have deployed.").addHelpText(
|
|
22806
|
+
"after",
|
|
22807
|
+
`
|
|
21912
22808
|
Notes:
|
|
21913
|
-
|
|
21914
|
-
|
|
22809
|
+
Read-only. --status filters by monitor status: active (default), disabled, or
|
|
22810
|
+
all. The output echoes the status filter that was applied. --compact returns
|
|
22811
|
+
high-signal fields only.
|
|
21915
22812
|
|
|
21916
22813
|
Examples:
|
|
21917
|
-
deepline monitors
|
|
22814
|
+
deepline monitors list
|
|
22815
|
+
deepline monitors list --status all --json
|
|
22816
|
+
deepline monitors list --compact --json
|
|
21918
22817
|
`
|
|
21919
|
-
|
|
21920
|
-
|
|
21921
|
-
|
|
21922
|
-
|
|
22818
|
+
).option(
|
|
22819
|
+
"--status <status>",
|
|
22820
|
+
"Filter by monitor status: active (default), disabled, or all"
|
|
22821
|
+
).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22822
|
+
).action(monitorsAction(handleMonitorsList));
|
|
22823
|
+
withJsonOption(
|
|
22824
|
+
monitors.command("get <key>").description("Show a single deployed monitor by its public key.").addHelpText(
|
|
22825
|
+
"after",
|
|
22826
|
+
`
|
|
21923
22827
|
Notes:
|
|
21924
|
-
|
|
22828
|
+
Read-only.
|
|
21925
22829
|
|
|
21926
22830
|
Examples:
|
|
21927
|
-
deepline monitors
|
|
22831
|
+
deepline monitors get my-monitor --json
|
|
21928
22832
|
`
|
|
21929
|
-
|
|
21930
|
-
|
|
21931
|
-
|
|
21932
|
-
|
|
22833
|
+
)
|
|
22834
|
+
).action(monitorsAction(handleMonitorsGet));
|
|
22835
|
+
withJsonOption(
|
|
22836
|
+
monitors.command("check [definition]").description("Validate a monitor definition without deploying it.").addHelpText(
|
|
22837
|
+
"after",
|
|
22838
|
+
`
|
|
21933
22839
|
Notes:
|
|
21934
|
-
|
|
21935
|
-
|
|
22840
|
+
Read-only validation. <definition> is a JSON object with key, tool, payload,
|
|
22841
|
+
and optional controls (Deepline lifecycle metadata, e.g.
|
|
22842
|
+
"controls":{"enabled":false}). Pass it positionally, via --file <path>, or
|
|
22843
|
+
from stdin with --file -. Does not deploy or spend credits.
|
|
21936
22844
|
|
|
21937
22845
|
Examples:
|
|
21938
|
-
deepline monitors
|
|
21939
|
-
deepline monitors
|
|
21940
|
-
deepline monitors
|
|
22846
|
+
deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22847
|
+
deepline monitors check --file monitor.json
|
|
22848
|
+
cat monitor.json | deepline monitors check --file -
|
|
21941
22849
|
`
|
|
21942
|
-
|
|
21943
|
-
|
|
21944
|
-
|
|
21945
|
-
|
|
22850
|
+
).option(
|
|
22851
|
+
"-f, --file <path>",
|
|
22852
|
+
"Read the definition JSON from a file, or - for stdin"
|
|
22853
|
+
)
|
|
22854
|
+
).action(monitorsAction(handleMonitorsCheck));
|
|
22855
|
+
withJsonOption(
|
|
22856
|
+
monitors.command("deploy [definition]").description("Deploy a monitor from a definition.").addHelpText(
|
|
22857
|
+
"after",
|
|
22858
|
+
`
|
|
21946
22859
|
Notes:
|
|
21947
|
-
|
|
22860
|
+
Mutates workspace state and may spend Deepline credits. <definition> is a JSON
|
|
22861
|
+
object with key, tool, payload, and optional controls (e.g.
|
|
22862
|
+
"controls":{"enabled":false}). Pass it positionally, via --file <path>, or
|
|
22863
|
+
from stdin with --file -.
|
|
22864
|
+
--dry-run validates the definition and shows the plan (deploy cost in Deepline
|
|
22865
|
+
credits when the server reports it, plus any existing monitors that may
|
|
22866
|
+
already cover this scope) WITHOUT deploying. Exits 0 when valid, 7 when not.
|
|
21948
22867
|
|
|
21949
22868
|
Examples:
|
|
21950
|
-
deepline monitors
|
|
22869
|
+
deepline monitors deploy '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22870
|
+
deepline monitors deploy --dry-run --file monitor.json
|
|
22871
|
+
deepline monitors deploy --file monitor.json
|
|
21951
22872
|
`
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
|
|
22873
|
+
).option(
|
|
22874
|
+
"-f, --file <path>",
|
|
22875
|
+
"Read the definition JSON from a file, or - for stdin"
|
|
22876
|
+
).option(
|
|
22877
|
+
"--dry-run",
|
|
22878
|
+
"Validate and show the deploy plan (cost, reuse candidates) without deploying"
|
|
22879
|
+
)
|
|
22880
|
+
).action(monitorsAction(handleMonitorsDeploy));
|
|
22881
|
+
withJsonOption(
|
|
22882
|
+
monitors.command("update <key> [patch]").description("Update a deployed monitor by its public key.").addHelpText(
|
|
22883
|
+
"after",
|
|
22884
|
+
`
|
|
21956
22885
|
Notes:
|
|
21957
|
-
Mutates workspace state. <patch> is a JSON object of fields to update.
|
|
22886
|
+
Mutates workspace state. <patch> is a JSON object of fields to update, e.g.
|
|
22887
|
+
'{"controls":{"enabled":false}}' to disable a monitor. Pass it positionally,
|
|
22888
|
+
via --file <path>, or from stdin with --file -.
|
|
21958
22889
|
|
|
21959
22890
|
Examples:
|
|
21960
|
-
deepline monitors
|
|
22891
|
+
deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
|
|
22892
|
+
deepline monitors update my-monitor --file patch.json
|
|
21961
22893
|
`
|
|
21962
|
-
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
|
|
22894
|
+
).option(
|
|
22895
|
+
"-f, --file <path>",
|
|
22896
|
+
"Read the patch JSON from a file, or - for stdin"
|
|
22897
|
+
)
|
|
22898
|
+
).action(monitorsAction(handleMonitorsUpdate));
|
|
22899
|
+
withJsonOption(
|
|
22900
|
+
monitors.command("delete <key>").description("Delete a deployed monitor by its public key.").addHelpText(
|
|
22901
|
+
"after",
|
|
22902
|
+
`
|
|
21966
22903
|
Notes:
|
|
21967
|
-
|
|
21968
|
-
|
|
22904
|
+
DESTRUCTIVE. By default deprovisions the upstream provider resource; pass
|
|
22905
|
+
--local-only to remove only the Deepline-managed record.
|
|
22906
|
+
--dry-run shows the delete plan without deleting anything.
|
|
22907
|
+
Interactive terminals get a y/N confirmation; non-interactive runs (agents,
|
|
22908
|
+
scripts, pipes) must pass --yes.
|
|
21969
22909
|
|
|
21970
22910
|
Examples:
|
|
21971
|
-
deepline monitors
|
|
21972
|
-
deepline monitors
|
|
22911
|
+
deepline monitors delete my-monitor --dry-run
|
|
22912
|
+
deepline monitors delete my-monitor --yes --json
|
|
22913
|
+
deepline monitors delete my-monitor --local-only --yes --json
|
|
21973
22914
|
`
|
|
21974
|
-
|
|
21975
|
-
|
|
21976
|
-
|
|
21977
|
-
|
|
22915
|
+
).option(
|
|
22916
|
+
"--local-only",
|
|
22917
|
+
"Remove only the Deepline-managed record, leaving the upstream resource"
|
|
22918
|
+
).option("--dry-run", "Show the delete plan without deleting anything").option(
|
|
22919
|
+
"--yes",
|
|
22920
|
+
"Skip the confirmation prompt (required non-interactively)"
|
|
22921
|
+
)
|
|
22922
|
+
).action(monitorsAction(handleMonitorsDelete));
|
|
22923
|
+
withJsonOption(
|
|
22924
|
+
monitors.command("reactivate <key>").description("Reactivate a previously disabled deployed monitor.").addHelpText(
|
|
22925
|
+
"after",
|
|
22926
|
+
`
|
|
22927
|
+
Notes:
|
|
22928
|
+
Mutates workspace state and may spend Deepline credits.
|
|
22929
|
+
--dry-run shows the reactivation cost (in Deepline credits) without changing
|
|
22930
|
+
anything.
|
|
22931
|
+
|
|
22932
|
+
Examples:
|
|
22933
|
+
deepline monitors reactivate my-monitor --dry-run
|
|
22934
|
+
deepline monitors reactivate my-monitor --json
|
|
22935
|
+
`
|
|
22936
|
+
).option("--dry-run", "Show the reactivation cost without reactivating")
|
|
22937
|
+
).action(monitorsAction(handleMonitorsReactivate));
|
|
22938
|
+
const deployed = withJsonOption(
|
|
22939
|
+
monitors.command("deployed", { hidden: true }).description("Alias of `monitors list` (plus get/update/delete aliases).").option(
|
|
22940
|
+
"--status <status>",
|
|
22941
|
+
"Filter by monitor status: active (default), disabled, or all"
|
|
22942
|
+
).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22943
|
+
).action(monitorsAction(handleMonitorsList));
|
|
22944
|
+
withJsonOption(
|
|
22945
|
+
deployed.command("get <key>").description("Alias of `monitors get <key>`.")
|
|
22946
|
+
).action(monitorsAction(handleMonitorsGet));
|
|
22947
|
+
withJsonOption(
|
|
22948
|
+
deployed.command("update <key> [patch]").description("Alias of `monitors update <key>`.").option(
|
|
22949
|
+
"-f, --file <path>",
|
|
22950
|
+
"Read the patch JSON from a file, or - for stdin"
|
|
22951
|
+
)
|
|
22952
|
+
).action(monitorsAction(handleMonitorsUpdate));
|
|
22953
|
+
withJsonOption(
|
|
22954
|
+
deployed.command("delete <key>").description("Alias of `monitors delete <key>`.").option(
|
|
22955
|
+
"--local-only",
|
|
22956
|
+
"Remove only the Deepline-managed record, leaving the upstream resource"
|
|
22957
|
+
).option("--dry-run", "Show the delete plan without deleting anything").option(
|
|
22958
|
+
"--yes",
|
|
22959
|
+
"Skip the confirmation prompt (required non-interactively)"
|
|
22960
|
+
)
|
|
22961
|
+
).action(monitorsAction(handleMonitorsDelete));
|
|
21978
22962
|
}
|
|
21979
22963
|
|
|
21980
22964
|
// src/cli/commands/org.ts
|
|
@@ -22999,7 +23983,7 @@ Examples:
|
|
|
22999
23983
|
}
|
|
23000
23984
|
|
|
23001
23985
|
// src/cli/commands/switch.ts
|
|
23002
|
-
var
|
|
23986
|
+
var import_node_fs13 = require("fs");
|
|
23003
23987
|
var import_node_os10 = require("os");
|
|
23004
23988
|
var import_node_path14 = require("path");
|
|
23005
23989
|
function hostSlugFromBaseUrl(baseUrl) {
|
|
@@ -23034,15 +24018,15 @@ function activeFamilyPath() {
|
|
|
23034
24018
|
function readActiveFamily() {
|
|
23035
24019
|
const path = activeFamilyPath();
|
|
23036
24020
|
try {
|
|
23037
|
-
return (0,
|
|
24021
|
+
return (0, import_node_fs13.readFileSync)(path, "utf-8").trim() || "sdk";
|
|
23038
24022
|
} catch {
|
|
23039
24023
|
return "sdk";
|
|
23040
24024
|
}
|
|
23041
24025
|
}
|
|
23042
24026
|
function writeActiveFamily(family) {
|
|
23043
24027
|
const path = activeFamilyPath();
|
|
23044
|
-
(0,
|
|
23045
|
-
(0,
|
|
24028
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
24029
|
+
(0, import_node_fs13.writeFileSync)(path, `${family}
|
|
23046
24030
|
`, "utf-8");
|
|
23047
24031
|
return path;
|
|
23048
24032
|
}
|
|
@@ -23059,7 +24043,7 @@ function handleSwitch(action, options) {
|
|
|
23059
24043
|
ok: true,
|
|
23060
24044
|
active_family: activeFamily,
|
|
23061
24045
|
active_family_path: path,
|
|
23062
|
-
active_family_file_exists: (0,
|
|
24046
|
+
active_family_file_exists: (0, import_node_fs13.existsSync)(path),
|
|
23063
24047
|
render: {
|
|
23064
24048
|
sections: [
|
|
23065
24049
|
{
|
|
@@ -23159,12 +24143,12 @@ Examples:
|
|
|
23159
24143
|
|
|
23160
24144
|
// src/cli/commands/tools.ts
|
|
23161
24145
|
var import_commander2 = require("commander");
|
|
23162
|
-
var
|
|
24146
|
+
var import_node_fs15 = require("fs");
|
|
23163
24147
|
var import_node_os12 = require("os");
|
|
23164
24148
|
var import_node_path16 = require("path");
|
|
23165
24149
|
|
|
23166
24150
|
// src/tool-output.ts
|
|
23167
|
-
var
|
|
24151
|
+
var import_node_fs14 = require("fs");
|
|
23168
24152
|
var import_node_os11 = require("os");
|
|
23169
24153
|
var import_node_path15 = require("path");
|
|
23170
24154
|
function isPlainObject(value) {
|
|
@@ -23294,18 +24278,18 @@ function projectRowOutput(conversion) {
|
|
|
23294
24278
|
}
|
|
23295
24279
|
function ensureOutputDir() {
|
|
23296
24280
|
const outputDir = (0, import_node_path15.join)((0, import_node_os11.homedir)(), ".local", "share", "deepline", "data");
|
|
23297
|
-
(0,
|
|
24281
|
+
(0, import_node_fs14.mkdirSync)(outputDir, { recursive: true });
|
|
23298
24282
|
return outputDir;
|
|
23299
24283
|
}
|
|
23300
24284
|
function writeJsonOutputFile(payload, stem) {
|
|
23301
24285
|
const outputDir = ensureOutputDir();
|
|
23302
24286
|
const outputPath = (0, import_node_path15.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
23303
|
-
(0,
|
|
24287
|
+
(0, import_node_fs14.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
23304
24288
|
return outputPath;
|
|
23305
24289
|
}
|
|
23306
24290
|
function writeCsvOutputFile(rows, stem, options) {
|
|
23307
24291
|
const outputPath = options?.outPath ? options.outPath : (0, import_node_path15.join)(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
|
|
23308
|
-
(0,
|
|
24292
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(outputPath), { recursive: true });
|
|
23309
24293
|
const columns = columnsForRows(rows);
|
|
23310
24294
|
const escapeCell = (value) => {
|
|
23311
24295
|
const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
|
|
@@ -23314,19 +24298,19 @@ function writeCsvOutputFile(rows, stem, options) {
|
|
|
23314
24298
|
}
|
|
23315
24299
|
return normalized;
|
|
23316
24300
|
};
|
|
23317
|
-
const fd = (0,
|
|
24301
|
+
const fd = (0, import_node_fs14.openSync)(outputPath, "w");
|
|
23318
24302
|
try {
|
|
23319
|
-
(0,
|
|
24303
|
+
(0, import_node_fs14.writeSync)(fd, `${columns.map(escapeCell).join(",")}
|
|
23320
24304
|
`);
|
|
23321
24305
|
for (const row of rows) {
|
|
23322
|
-
(0,
|
|
24306
|
+
(0, import_node_fs14.writeSync)(
|
|
23323
24307
|
fd,
|
|
23324
24308
|
`${columns.map((column) => escapeCell(row[column])).join(",")}
|
|
23325
24309
|
`
|
|
23326
24310
|
);
|
|
23327
24311
|
}
|
|
23328
24312
|
} finally {
|
|
23329
|
-
(0,
|
|
24313
|
+
(0, import_node_fs14.closeSync)(fd);
|
|
23330
24314
|
}
|
|
23331
24315
|
const previewRows = rows.slice(0, 5);
|
|
23332
24316
|
const previewColumns = columns.slice(0, 5);
|
|
@@ -24540,10 +25524,10 @@ function normalizeOutputFormat(raw) {
|
|
|
24540
25524
|
function resolveAtFilePath(rawPath) {
|
|
24541
25525
|
const trimmed = rawPath.trim();
|
|
24542
25526
|
const resolved = (0, import_node_path16.resolve)(trimmed);
|
|
24543
|
-
if ((0,
|
|
25527
|
+
if ((0, import_node_fs15.existsSync)(resolved)) return resolved;
|
|
24544
25528
|
if (process.platform !== "win32" && trimmed.includes("\\")) {
|
|
24545
25529
|
const normalized = (0, import_node_path16.resolve)(trimmed.replace(/\\/g, "/"));
|
|
24546
|
-
if ((0,
|
|
25530
|
+
if ((0, import_node_fs15.existsSync)(normalized)) return normalized;
|
|
24547
25531
|
}
|
|
24548
25532
|
return resolved;
|
|
24549
25533
|
}
|
|
@@ -24554,7 +25538,7 @@ function readJsonArgument(raw, flagName) {
|
|
|
24554
25538
|
throw new Error(`Invalid ${flagName} value: empty @file path.`);
|
|
24555
25539
|
}
|
|
24556
25540
|
try {
|
|
24557
|
-
return (0,
|
|
25541
|
+
return (0, import_node_fs15.readFileSync)(resolveAtFilePath(filePath), "utf8").replace(
|
|
24558
25542
|
/^\uFEFF/,
|
|
24559
25543
|
""
|
|
24560
25544
|
);
|
|
@@ -24661,8 +25645,8 @@ function starterScriptJson(script) {
|
|
|
24661
25645
|
function seedToolListScript(input2) {
|
|
24662
25646
|
const stem = safeFileStem(input2.toolId);
|
|
24663
25647
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
24664
|
-
const scriptDir = (0,
|
|
24665
|
-
(0,
|
|
25648
|
+
const scriptDir = (0, import_node_fs15.mkdtempSync)((0, import_node_path16.join)((0, import_node_os12.tmpdir)(), "deepline-workflow-seed-"));
|
|
25649
|
+
(0, import_node_fs15.chmodSync)(scriptDir, 448);
|
|
24666
25650
|
const scriptPath = (0, import_node_path16.join)(scriptDir, fileName);
|
|
24667
25651
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
24668
25652
|
const playName = `${stem}-workflow`;
|
|
@@ -24706,7 +25690,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
24706
25690
|
description: ${JSON.stringify(`Seed ${input2.toolId} rows into a Deepline workflow-ready dataset.`)},
|
|
24707
25691
|
});
|
|
24708
25692
|
`;
|
|
24709
|
-
(0,
|
|
25693
|
+
(0, import_node_fs15.writeFileSync)(scriptPath, script, { encoding: "utf-8", mode: 384 });
|
|
24710
25694
|
return {
|
|
24711
25695
|
path: scriptPath,
|
|
24712
25696
|
sourceCode: script,
|
|
@@ -25036,7 +26020,7 @@ async function executeTool(args) {
|
|
|
25036
26020
|
}
|
|
25037
26021
|
|
|
25038
26022
|
// src/cli/commands/workflow.ts
|
|
25039
|
-
var
|
|
26023
|
+
var import_promises5 = require("fs/promises");
|
|
25040
26024
|
var import_node_path17 = require("path");
|
|
25041
26025
|
|
|
25042
26026
|
// src/cli/workflow-to-play.ts
|
|
@@ -25224,9 +26208,10 @@ var PLAY_EQUIVALENT = {
|
|
|
25224
26208
|
delete: "deepline plays delete <name>"
|
|
25225
26209
|
};
|
|
25226
26210
|
var MIGRATE_HINT = "deepline workflows transform <id>";
|
|
25227
|
-
var
|
|
25228
|
-
|
|
25229
|
-
|
|
26211
|
+
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`.";
|
|
26212
|
+
var JSON_OPTION_DESCRIPTION2 = "Emit JSON output. Also automatic when stdout is piped";
|
|
26213
|
+
function withJsonOption2(command) {
|
|
26214
|
+
return command.option("--json", JSON_OPTION_DESCRIPTION2);
|
|
25230
26215
|
}
|
|
25231
26216
|
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
25232
26217
|
"completed",
|
|
@@ -25251,6 +26236,7 @@ function noticeToStderr(command) {
|
|
|
25251
26236
|
`note: \`deepline workflows ${command}\` is a legacy surface \u2014 workflows are becoming plays.
|
|
25252
26237
|
equivalent: \`${deprecation.use}\`
|
|
25253
26238
|
migrate this workflow: \`${MIGRATE_HINT}\`
|
|
26239
|
+
${TRIGGER_REDIRECT}
|
|
25254
26240
|
`
|
|
25255
26241
|
);
|
|
25256
26242
|
}
|
|
@@ -25281,7 +26267,7 @@ function readStatus(payload) {
|
|
|
25281
26267
|
}
|
|
25282
26268
|
async function readJsonOption(payload, file) {
|
|
25283
26269
|
if (file) {
|
|
25284
|
-
const raw = await (0,
|
|
26270
|
+
const raw = await (0, import_promises5.readFile)((0, import_node_path17.resolve)(file), "utf8");
|
|
25285
26271
|
return JSON.parse(raw);
|
|
25286
26272
|
}
|
|
25287
26273
|
if (payload) {
|
|
@@ -25316,8 +26302,8 @@ async function transformOne(api, workflowId, outDir, publish) {
|
|
|
25316
26302
|
{ workflowName: workflow.name, version: revision.version }
|
|
25317
26303
|
);
|
|
25318
26304
|
const file = (0, import_node_path17.join)((0, import_node_path17.resolve)(outDir), `${compiled.playName}.play.ts`);
|
|
25319
|
-
await (0,
|
|
25320
|
-
await (0,
|
|
26305
|
+
await (0, import_promises5.mkdir)((0, import_node_path17.dirname)(file), { recursive: true });
|
|
26306
|
+
await (0, import_promises5.writeFile)(file, compiled.sourceCode, "utf8");
|
|
25321
26307
|
let published = false;
|
|
25322
26308
|
if (publish) {
|
|
25323
26309
|
const code = await handlePlayPublish([file]);
|
|
@@ -25484,7 +26470,7 @@ async function handleTail(id, runId, options) {
|
|
|
25484
26470
|
}
|
|
25485
26471
|
function registerWorkflowCommands(program) {
|
|
25486
26472
|
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."
|
|
26473
|
+
"Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play. " + TRIGGER_REDIRECT
|
|
25488
26474
|
).addHelpText(
|
|
25489
26475
|
"after",
|
|
25490
26476
|
`
|
|
@@ -25496,9 +26482,13 @@ keep working, but new work belongs in plays. Migrate a workflow with:
|
|
|
25496
26482
|
|
|
25497
26483
|
Equivalents: list\u2192plays list \xB7 call\u2192plays run \xB7 apply\u2192plays publish \xB7
|
|
25498
26484
|
lint\u2192plays check \xB7 runs\u2192runs list.
|
|
26485
|
+
|
|
26486
|
+
${TRIGGER_REDIRECT}
|
|
26487
|
+
Add the binding as the third arg to definePlay in your .play.ts; the
|
|
26488
|
+
deepline-monitors skill has a monitor-triggered example.
|
|
25499
26489
|
`
|
|
25500
26490
|
);
|
|
25501
|
-
|
|
26491
|
+
withJsonOption2(
|
|
25502
26492
|
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
26493
|
).addHelpText(
|
|
25504
26494
|
"after",
|
|
@@ -25515,61 +26505,61 @@ Notes:
|
|
|
25515
26505
|
).action(async (id, options) => {
|
|
25516
26506
|
process.exitCode = await handleTransform(id, options);
|
|
25517
26507
|
});
|
|
25518
|
-
|
|
26508
|
+
withJsonOption2(
|
|
25519
26509
|
workflows.command("list").description("List workspace workflows.").option("--limit <n>", "Max workflows to return")
|
|
25520
26510
|
).action(handleList2);
|
|
25521
|
-
|
|
26511
|
+
withJsonOption2(
|
|
25522
26512
|
workflows.command("get <id>").description(
|
|
25523
26513
|
"Fetch a workflow, including its published-revision config."
|
|
25524
26514
|
)
|
|
25525
26515
|
).action(handleGet);
|
|
25526
|
-
|
|
26516
|
+
withJsonOption2(
|
|
25527
26517
|
workflows.command("disable <id>").description("Turn a workflow off.")
|
|
25528
26518
|
).action(handleDisable);
|
|
25529
|
-
|
|
26519
|
+
withJsonOption2(
|
|
25530
26520
|
workflows.command("enable <id>").description("Turn a workflow back on.")
|
|
25531
26521
|
).action(handleEnable);
|
|
25532
|
-
|
|
26522
|
+
withJsonOption2(
|
|
25533
26523
|
workflows.command("delete <id>").description("Delete a workflow and its revisions/runs.")
|
|
25534
26524
|
).action(handleDelete);
|
|
25535
|
-
|
|
26525
|
+
withJsonOption2(
|
|
25536
26526
|
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
26527
|
).action(handleApply);
|
|
25538
|
-
|
|
26528
|
+
withJsonOption2(
|
|
25539
26529
|
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
26530
|
).action(handleLint);
|
|
25541
|
-
|
|
26531
|
+
withJsonOption2(
|
|
25542
26532
|
workflows.command("schema").description("Fetch live workflow request schemas.").option(
|
|
25543
26533
|
"--subject <subject>",
|
|
25544
26534
|
"Schema subject (apply|call|trigger|all|\u2026)"
|
|
25545
26535
|
)
|
|
25546
26536
|
).action(handleSchema);
|
|
25547
|
-
|
|
26537
|
+
withJsonOption2(
|
|
25548
26538
|
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
26539
|
).action(handleCall);
|
|
25550
|
-
|
|
26540
|
+
withJsonOption2(
|
|
25551
26541
|
workflows.command("runs <id>").description("List a workflow\u2019s runs.").option("--limit <n>", "Max runs to return")
|
|
25552
26542
|
).action(handleRuns);
|
|
25553
|
-
|
|
26543
|
+
withJsonOption2(
|
|
25554
26544
|
workflows.command("run <id> <runId>").description("Fetch a single workflow run.")
|
|
25555
26545
|
).action(handleRun);
|
|
25556
|
-
|
|
26546
|
+
withJsonOption2(
|
|
25557
26547
|
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
26548
|
).action(handleTail);
|
|
25559
|
-
|
|
26549
|
+
withJsonOption2(
|
|
25560
26550
|
workflows.command("cancel <id> <runId>").description("Cancel a running workflow run.")
|
|
25561
26551
|
).action(handleCancel);
|
|
25562
26552
|
}
|
|
25563
26553
|
|
|
25564
26554
|
// src/cli/commands/update.ts
|
|
25565
26555
|
var import_node_child_process4 = require("child_process");
|
|
25566
|
-
var
|
|
26556
|
+
var import_node_fs17 = require("fs");
|
|
25567
26557
|
var import_node_os13 = require("os");
|
|
25568
26558
|
var import_node_path19 = require("path");
|
|
25569
26559
|
|
|
25570
26560
|
// src/cli/skills-sync.ts
|
|
25571
26561
|
var import_node_child_process3 = require("child_process");
|
|
25572
|
-
var
|
|
26562
|
+
var import_node_fs16 = require("fs");
|
|
25573
26563
|
var import_node_path18 = require("path");
|
|
25574
26564
|
|
|
25575
26565
|
// ../shared_libs/cli/install-commands.json
|
|
@@ -25692,13 +26682,13 @@ function activePluginSkillsDir() {
|
|
|
25692
26682
|
return "";
|
|
25693
26683
|
}
|
|
25694
26684
|
const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
|
|
25695
|
-
return dir && (0,
|
|
26685
|
+
return dir && (0, import_node_fs16.existsSync)(dir) ? dir : "";
|
|
25696
26686
|
}
|
|
25697
26687
|
function readPluginSkillsVersion() {
|
|
25698
26688
|
const dir = activePluginSkillsDir();
|
|
25699
26689
|
if (!dir) return "";
|
|
25700
26690
|
try {
|
|
25701
|
-
return (0,
|
|
26691
|
+
return (0, import_node_fs16.readFileSync)((0, import_node_path18.join)(dir, ".version"), "utf-8").trim();
|
|
25702
26692
|
} catch {
|
|
25703
26693
|
return "";
|
|
25704
26694
|
}
|
|
@@ -25712,18 +26702,18 @@ function legacySdkSkillsVersionPath(baseUrl) {
|
|
|
25712
26702
|
function readSdkSkillsLocalVersion(baseUrl) {
|
|
25713
26703
|
const pluginVersion = readPluginSkillsVersion();
|
|
25714
26704
|
if (pluginVersion) return pluginVersion;
|
|
25715
|
-
const path = (0,
|
|
25716
|
-
if (!(0,
|
|
26705
|
+
const path = (0, import_node_fs16.existsSync)(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
|
|
26706
|
+
if (!(0, import_node_fs16.existsSync)(path)) return "";
|
|
25717
26707
|
try {
|
|
25718
|
-
return (0,
|
|
26708
|
+
return (0, import_node_fs16.readFileSync)(path, "utf-8").trim();
|
|
25719
26709
|
} catch {
|
|
25720
26710
|
return "";
|
|
25721
26711
|
}
|
|
25722
26712
|
}
|
|
25723
26713
|
function writeLocalSkillsVersion(baseUrl, version) {
|
|
25724
26714
|
const path = sdkSkillsVersionPath(baseUrl);
|
|
25725
|
-
(0,
|
|
25726
|
-
(0,
|
|
26715
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(path), { recursive: true });
|
|
26716
|
+
(0, import_node_fs16.writeFileSync)(path, `${version}
|
|
25727
26717
|
`, "utf-8");
|
|
25728
26718
|
}
|
|
25729
26719
|
function sortedUniqueSkillNames(names) {
|
|
@@ -26010,7 +27000,7 @@ function sidecarStateDir(input2) {
|
|
|
26010
27000
|
}
|
|
26011
27001
|
function readOptionalText(path) {
|
|
26012
27002
|
try {
|
|
26013
|
-
return (0,
|
|
27003
|
+
return (0, import_node_fs17.readFileSync)(path, "utf8").trim();
|
|
26014
27004
|
} catch {
|
|
26015
27005
|
return "";
|
|
26016
27006
|
}
|
|
@@ -26054,7 +27044,7 @@ function resolvePythonSidecarUpdatePlan(options) {
|
|
|
26054
27044
|
function findRepoBackedSdkRoot(startPath) {
|
|
26055
27045
|
let current = (0, import_node_path19.resolve)(startPath);
|
|
26056
27046
|
while (true) {
|
|
26057
|
-
if ((0,
|
|
27047
|
+
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
27048
|
return current;
|
|
26059
27049
|
}
|
|
26060
27050
|
const parent = (0, import_node_path19.dirname)(current);
|
|
@@ -26065,7 +27055,7 @@ function findRepoBackedSdkRoot(startPath) {
|
|
|
26065
27055
|
function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
|
|
26066
27056
|
const normalized = (() => {
|
|
26067
27057
|
try {
|
|
26068
|
-
return (0,
|
|
27058
|
+
return (0, import_node_fs17.realpathSync)(entrypoint);
|
|
26069
27059
|
} catch {
|
|
26070
27060
|
return (0, import_node_path19.resolve)(entrypoint);
|
|
26071
27061
|
}
|
|
@@ -26145,7 +27135,7 @@ function readAutoUpdateFailure(plan) {
|
|
|
26145
27135
|
if (!path) return null;
|
|
26146
27136
|
try {
|
|
26147
27137
|
const parsed = JSON.parse(
|
|
26148
|
-
(0,
|
|
27138
|
+
(0, import_node_fs17.readFileSync)(path, "utf8")
|
|
26149
27139
|
);
|
|
26150
27140
|
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
27141
|
return parsed;
|
|
@@ -26166,8 +27156,8 @@ function writeAutoUpdateFailure(plan, exitCode) {
|
|
|
26166
27156
|
manualCommand: plan.manualCommand
|
|
26167
27157
|
};
|
|
26168
27158
|
try {
|
|
26169
|
-
(0,
|
|
26170
|
-
(0,
|
|
27159
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(path), { recursive: true });
|
|
27160
|
+
(0, import_node_fs17.writeFileSync)(path, `${JSON.stringify(marker, null, 2)}
|
|
26171
27161
|
`, "utf8");
|
|
26172
27162
|
} catch {
|
|
26173
27163
|
}
|
|
@@ -26176,7 +27166,7 @@ function clearAutoUpdateFailure(plan) {
|
|
|
26176
27166
|
const path = autoUpdateFailurePath(plan);
|
|
26177
27167
|
if (!path) return;
|
|
26178
27168
|
try {
|
|
26179
|
-
(0,
|
|
27169
|
+
(0, import_node_fs17.unlinkSync)(path);
|
|
26180
27170
|
} catch {
|
|
26181
27171
|
}
|
|
26182
27172
|
}
|
|
@@ -26229,7 +27219,7 @@ function installedPackageVersion(versionDir) {
|
|
|
26229
27219
|
"package.json"
|
|
26230
27220
|
);
|
|
26231
27221
|
try {
|
|
26232
|
-
const parsed = JSON.parse((0,
|
|
27222
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(packageJsonPath, "utf8"));
|
|
26233
27223
|
return typeof parsed.version === "string" ? safeVersionSegment(parsed.version) : "";
|
|
26234
27224
|
} catch {
|
|
26235
27225
|
return "";
|
|
@@ -26261,9 +27251,9 @@ function runCommand(command, args, env = process.env, options = {}) {
|
|
|
26261
27251
|
});
|
|
26262
27252
|
}
|
|
26263
27253
|
function writeSidecarLauncher(input2) {
|
|
26264
|
-
(0,
|
|
27254
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(input2.path), { recursive: true });
|
|
26265
27255
|
if (process.platform === "win32") {
|
|
26266
|
-
(0,
|
|
27256
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26267
27257
|
input2.path,
|
|
26268
27258
|
[
|
|
26269
27259
|
`@set DEEPLINE_HOST_URL=${input2.hostUrl.replace(/\r?\n/g, "")}`,
|
|
@@ -26275,7 +27265,7 @@ function writeSidecarLauncher(input2) {
|
|
|
26275
27265
|
);
|
|
26276
27266
|
return;
|
|
26277
27267
|
}
|
|
26278
|
-
(0,
|
|
27268
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26279
27269
|
input2.path,
|
|
26280
27270
|
[
|
|
26281
27271
|
"#!/usr/bin/env sh",
|
|
@@ -26293,9 +27283,9 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
|
|
|
26293
27283
|
versionsDir,
|
|
26294
27284
|
`.tmp-sdk-update-${process.pid}-${Date.now()}`
|
|
26295
27285
|
);
|
|
26296
|
-
(0,
|
|
26297
|
-
(0,
|
|
26298
|
-
(0,
|
|
27286
|
+
(0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
|
|
27287
|
+
(0, import_node_fs17.mkdirSync)(tempDir, { recursive: true });
|
|
27288
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
|
|
26299
27289
|
const env = {
|
|
26300
27290
|
...process.env,
|
|
26301
27291
|
PATH: `${(0, import_node_path19.dirname)(plan.nodeBin)}${process.platform === "win32" ? ";" : ":"}${process.env.PATH ?? ""}`
|
|
@@ -26313,7 +27303,7 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
|
|
|
26313
27303
|
options
|
|
26314
27304
|
);
|
|
26315
27305
|
if (installExitCode !== 0) {
|
|
26316
|
-
(0,
|
|
27306
|
+
(0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
|
|
26317
27307
|
return installExitCode;
|
|
26318
27308
|
}
|
|
26319
27309
|
const installedVersion = installedPackageVersion(tempDir);
|
|
@@ -26321,19 +27311,19 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
|
|
|
26321
27311
|
process.stderr.write(
|
|
26322
27312
|
"Updated Deepline SDK package did not report a version.\n"
|
|
26323
27313
|
);
|
|
26324
|
-
(0,
|
|
27314
|
+
(0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
|
|
26325
27315
|
return 1;
|
|
26326
27316
|
}
|
|
26327
27317
|
const finalDir = (0, import_node_path19.join)(versionsDir, installedVersion);
|
|
26328
27318
|
const finalEntryPath = entryPathInVersionDir(finalDir);
|
|
26329
|
-
if ((0,
|
|
26330
|
-
(0,
|
|
27319
|
+
if ((0, import_node_fs17.existsSync)(finalEntryPath)) {
|
|
27320
|
+
(0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
|
|
26331
27321
|
} else {
|
|
26332
|
-
(0,
|
|
27322
|
+
(0, import_node_fs17.rmSync)(finalDir, { recursive: true, force: true });
|
|
26333
27323
|
try {
|
|
26334
|
-
(0,
|
|
27324
|
+
(0, import_node_fs17.renameSync)(tempDir, finalDir);
|
|
26335
27325
|
} catch (error) {
|
|
26336
|
-
(0,
|
|
27326
|
+
(0, import_node_fs17.rmSync)(tempDir, { recursive: true, force: true });
|
|
26337
27327
|
process.stderr.write(
|
|
26338
27328
|
`Failed to publish Deepline SDK sidecar update: ${error.message}
|
|
26339
27329
|
`
|
|
@@ -26341,7 +27331,7 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
|
|
|
26341
27331
|
return 1;
|
|
26342
27332
|
}
|
|
26343
27333
|
}
|
|
26344
|
-
if (!(0,
|
|
27334
|
+
if (!(0, import_node_fs17.existsSync)(finalEntryPath)) {
|
|
26345
27335
|
process.stderr.write(
|
|
26346
27336
|
`Updated Deepline SDK CLI entrypoint missing: ${finalEntryPath}
|
|
26347
27337
|
`
|
|
@@ -26355,27 +27345,27 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
|
|
|
26355
27345
|
nodeBin: plan.nodeBin,
|
|
26356
27346
|
entryPath: finalEntryPath
|
|
26357
27347
|
});
|
|
26358
|
-
(0,
|
|
27348
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26359
27349
|
(0, import_node_path19.join)(plan.stateDir, ".version"),
|
|
26360
27350
|
`${installedVersion}
|
|
26361
27351
|
`,
|
|
26362
27352
|
"utf8"
|
|
26363
27353
|
);
|
|
26364
|
-
(0,
|
|
27354
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26365
27355
|
(0, import_node_path19.join)(plan.stateDir, ".install-method"),
|
|
26366
27356
|
"python-sidecar\n",
|
|
26367
27357
|
"utf8"
|
|
26368
27358
|
);
|
|
26369
|
-
(0,
|
|
27359
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26370
27360
|
(0, import_node_path19.join)(plan.stateDir, ".command-path"),
|
|
26371
27361
|
`${plan.sidecarPath}
|
|
26372
27362
|
`,
|
|
26373
27363
|
"utf8"
|
|
26374
27364
|
);
|
|
26375
|
-
(0,
|
|
26376
|
-
(0,
|
|
27365
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".runner"), "node\n", "utf8");
|
|
27366
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path19.join)(plan.stateDir, ".node-bin"), `${plan.nodeBin}
|
|
26377
27367
|
`, "utf8");
|
|
26378
|
-
(0,
|
|
27368
|
+
(0, import_node_fs17.writeFileSync)(
|
|
26379
27369
|
(0, import_node_path19.join)(plan.stateDir, ".entry-path"),
|
|
26380
27370
|
`${finalEntryPath}
|
|
26381
27371
|
`,
|
|
@@ -26979,10 +27969,10 @@ function topLevelCommandKnown(program, commandName) {
|
|
|
26979
27969
|
);
|
|
26980
27970
|
}
|
|
26981
27971
|
async function runPlayRunnerHealthCheck() {
|
|
26982
|
-
const dir = await (0,
|
|
27972
|
+
const dir = await (0, import_promises6.mkdtemp)((0, import_node_path20.join)((0, import_node_os15.tmpdir)(), "deepline-health-play-"));
|
|
26983
27973
|
const file = (0, import_node_path20.join)(dir, "health-check.play.ts");
|
|
26984
27974
|
try {
|
|
26985
|
-
await (0,
|
|
27975
|
+
await (0, import_promises6.writeFile)(
|
|
26986
27976
|
file,
|
|
26987
27977
|
[
|
|
26988
27978
|
"import { definePlay } from 'deepline';",
|
|
@@ -27032,7 +28022,7 @@ async function runPlayRunnerHealthCheck() {
|
|
|
27032
28022
|
}
|
|
27033
28023
|
};
|
|
27034
28024
|
} finally {
|
|
27035
|
-
await (0,
|
|
28025
|
+
await (0, import_promises6.rm)(dir, { recursive: true, force: true });
|
|
27036
28026
|
}
|
|
27037
28027
|
}
|
|
27038
28028
|
function pickString(value, ...keys) {
|