deepline 0.1.185 → 0.1.187
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +43 -4
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +2 -2
- 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 +1424 -239
- package/dist/cli/index.mjs +1371 -186
- 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.mjs
CHANGED
|
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
|
|
|
608
608
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
609
609
|
// fields shipped in 0.1.153.
|
|
610
610
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
611
|
-
version: "0.1.
|
|
611
|
+
version: "0.1.187",
|
|
612
612
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
613
613
|
supportPolicy: {
|
|
614
|
-
latest: "0.1.
|
|
614
|
+
latest: "0.1.187",
|
|
615
615
|
minimumSupported: "0.1.53",
|
|
616
616
|
deprecatedBelow: "0.1.53",
|
|
617
617
|
commandMinimumSupported: [
|
|
@@ -8305,13 +8305,155 @@ var PLAY_BOOTSTRAP_STAGE_NAMES = [
|
|
|
8305
8305
|
"email",
|
|
8306
8306
|
"phone"
|
|
8307
8307
|
];
|
|
8308
|
+
var MONITOR_BOOTSTRAP_TEMPLATE = "monitor-triggered";
|
|
8309
|
+
var MONITOR_BOOTSTRAP_DEFAULT_TOOL = "instantly.campaign_events";
|
|
8310
|
+
var MONITOR_BOOTSTRAP_DEFAULT_STREAM = "webhook_events";
|
|
8311
|
+
function isMonitorBootstrapTemplate(value) {
|
|
8312
|
+
return value === MONITOR_BOOTSTRAP_TEMPLATE;
|
|
8313
|
+
}
|
|
8314
|
+
function hasMonitorBootstrapForbiddenChar(value) {
|
|
8315
|
+
for (const char of value) {
|
|
8316
|
+
const code = char.codePointAt(0) ?? 0;
|
|
8317
|
+
if (code < 32 || code === 127) return true;
|
|
8318
|
+
if (char === "'" || char === '"' || char === "`" || char === "\\") {
|
|
8319
|
+
return true;
|
|
8320
|
+
}
|
|
8321
|
+
}
|
|
8322
|
+
return false;
|
|
8323
|
+
}
|
|
8324
|
+
function validateMonitorBootstrapFlagValue(flag, value) {
|
|
8325
|
+
if (hasMonitorBootstrapForbiddenChar(value)) {
|
|
8326
|
+
throw new PlayBootstrapUsageError(
|
|
8327
|
+
`${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.`
|
|
8328
|
+
);
|
|
8329
|
+
}
|
|
8330
|
+
return value;
|
|
8331
|
+
}
|
|
8332
|
+
function parseMonitorBootstrapOptions(args) {
|
|
8333
|
+
const [, ...rest] = args;
|
|
8334
|
+
const options = {
|
|
8335
|
+
name: MONITOR_BOOTSTRAP_TEMPLATE,
|
|
8336
|
+
tool: MONITOR_BOOTSTRAP_DEFAULT_TOOL,
|
|
8337
|
+
stream: MONITOR_BOOTSTRAP_DEFAULT_STREAM,
|
|
8338
|
+
out: null
|
|
8339
|
+
};
|
|
8340
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
8341
|
+
const arg = rest[index];
|
|
8342
|
+
const value = () => nextFlagValue(rest, index, arg);
|
|
8343
|
+
switch (arg) {
|
|
8344
|
+
case "--name":
|
|
8345
|
+
options.name = validateMonitorBootstrapFlagValue("--name", value());
|
|
8346
|
+
index += 1;
|
|
8347
|
+
break;
|
|
8348
|
+
case "--tool":
|
|
8349
|
+
options.tool = validateMonitorBootstrapFlagValue("--tool", value());
|
|
8350
|
+
index += 1;
|
|
8351
|
+
break;
|
|
8352
|
+
case "--stream":
|
|
8353
|
+
options.stream = validateMonitorBootstrapFlagValue("--stream", value());
|
|
8354
|
+
index += 1;
|
|
8355
|
+
break;
|
|
8356
|
+
case "--out":
|
|
8357
|
+
options.out = value();
|
|
8358
|
+
index += 1;
|
|
8359
|
+
break;
|
|
8360
|
+
default:
|
|
8361
|
+
throw new PlayBootstrapUsageError(
|
|
8362
|
+
`Unknown plays bootstrap option for ${MONITOR_BOOTSTRAP_TEMPLATE}: ${arg}
|
|
8363
|
+
Usage: deepline plays bootstrap ${MONITOR_BOOTSTRAP_TEMPLATE} [--tool <monitor-tool-id>] [--stream <stream-key>] [--name NAME] [--out monitor.play.ts]`
|
|
8364
|
+
);
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
if (!options.tool) {
|
|
8368
|
+
throw new PlayBootstrapUsageError(
|
|
8369
|
+
`${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --tool.`
|
|
8370
|
+
);
|
|
8371
|
+
}
|
|
8372
|
+
if (!options.stream) {
|
|
8373
|
+
throw new PlayBootstrapUsageError(
|
|
8374
|
+
`${MONITOR_BOOTSTRAP_TEMPLATE} needs a non-empty --stream.`
|
|
8375
|
+
);
|
|
8376
|
+
}
|
|
8377
|
+
return options;
|
|
8378
|
+
}
|
|
8379
|
+
function generateMonitorTriggeredPlaySource(options) {
|
|
8380
|
+
return `import { definePlay } from 'deepline';
|
|
8381
|
+
import type { SqlListenerEvent } from 'deepline';
|
|
8382
|
+
|
|
8383
|
+
// Row shape delivered by ${options.tool} / ${options.stream}. This is a starting
|
|
8384
|
+
// point only: inspect the real columns with
|
|
8385
|
+
// deepline monitors available ${options.tool}
|
|
8386
|
+
// and tighten this type to the fields you read below.
|
|
8387
|
+
//
|
|
8388
|
+
// Before deploying a NEW monitor, run \`deepline monitors list\` \u2014 if one
|
|
8389
|
+
// already feeds this stream for your scope, this play will already react to its
|
|
8390
|
+
// rows (a play binds to the shared stream), so you may not need to deploy at all.
|
|
8391
|
+
type MonitorRow = Record<string, unknown>;
|
|
8392
|
+
|
|
8393
|
+
export default definePlay(
|
|
8394
|
+
${jsString(options.name)},
|
|
8395
|
+
async (ctx, event: SqlListenerEvent<MonitorRow>) => {
|
|
8396
|
+
// The monitor delivers the changed row as event.after. It is null for
|
|
8397
|
+
// DELETE operations, so guard before reading fields.
|
|
8398
|
+
const row = event.after;
|
|
8399
|
+
if (!row) {
|
|
8400
|
+
ctx.log(\`Monitor \${event.tool}/\${event.stream} \${event.operation} with no row; nothing to do.\`);
|
|
8401
|
+
return { handled: false, operation: event.operation };
|
|
8402
|
+
}
|
|
8403
|
+
|
|
8404
|
+
ctx.log(
|
|
8405
|
+
\`Monitor \${event.tool}/\${event.stream} \${event.operation}: \${JSON.stringify(row).slice(0, 200)}\`,
|
|
8406
|
+
);
|
|
8407
|
+
|
|
8408
|
+
// Capture the changed row into a durable dataset so the run has inspectable,
|
|
8409
|
+
// exportable output. ctx.dataset is a CALLABLE: ctx.dataset(key, rows) where
|
|
8410
|
+
// key is a compile-time string LITERAL and rows is an array of row objects.
|
|
8411
|
+
// It returns a builder; add per-row columns with .withColumn(name, resolver)
|
|
8412
|
+
// and finish with .run(). There is no .push/.add \u2014 pass all rows up front.
|
|
8413
|
+
// TODO: replace this plain persist with your real per-row work \u2014 enrich each
|
|
8414
|
+
// row via .withColumn('...', (row, rowCtx) => rowCtx.tools.execute(...)),
|
|
8415
|
+
// notify, write to another table, or fan out with rowCtx.runPlay.
|
|
8416
|
+
const captured = await ctx.dataset('monitor_events', [row]).run({
|
|
8417
|
+
description: \`Captured \${event.tool}/\${event.stream} \${event.operation} rows.\`,
|
|
8418
|
+
});
|
|
8419
|
+
|
|
8420
|
+
return {
|
|
8421
|
+
handled: true,
|
|
8422
|
+
tool: event.tool,
|
|
8423
|
+
stream: event.stream,
|
|
8424
|
+
operation: event.operation,
|
|
8425
|
+
changedAt: event.changedAt,
|
|
8426
|
+
capturedRows: await captured.count(),
|
|
8427
|
+
};
|
|
8428
|
+
},
|
|
8429
|
+
{
|
|
8430
|
+
description: ${jsString(`Run whenever ${options.tool} writes a new ${options.stream} row.`)},
|
|
8431
|
+
// A monitor trigger: this play wakes on row changes written by the bound
|
|
8432
|
+
// monitor tool + stream. Discover a tool's streams and columns with:
|
|
8433
|
+
// deepline monitors available ${options.tool}
|
|
8434
|
+
// To bind a different monitor, swap tool/stream (and re-check operations)
|
|
8435
|
+
// for one of its (tool, stream) pairs.
|
|
8436
|
+
sqlListeners: [
|
|
8437
|
+
{
|
|
8438
|
+
id: 'events',
|
|
8439
|
+
tool: ${jsString(options.tool)},
|
|
8440
|
+
stream: ${jsString(options.stream)},
|
|
8441
|
+
operations: ['INSERT'],
|
|
8442
|
+
// Optional: only wake on some rows \u2014 add a where filter to the binding above:
|
|
8443
|
+
// where: { after: { <column>: { eq: 'value' } } } // operators: eq, neq, in, notIn, isNull, isNotNull, ilike
|
|
8444
|
+
},
|
|
8445
|
+
],
|
|
8446
|
+
},
|
|
8447
|
+
);
|
|
8448
|
+
`;
|
|
8449
|
+
}
|
|
8308
8450
|
function playBootstrapUsageLine() {
|
|
8309
8451
|
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]`;
|
|
8310
8452
|
}
|
|
8311
8453
|
function requireBootstrapTemplate(rawTemplate) {
|
|
8312
8454
|
if (!rawTemplate) {
|
|
8313
8455
|
throw new PlayBootstrapUsageError(
|
|
8314
|
-
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}.
|
|
8456
|
+
`plays bootstrap needs a route template: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}.
|
|
8315
8457
|
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`
|
|
8316
8458
|
);
|
|
8317
8459
|
}
|
|
@@ -8319,7 +8461,7 @@ Example: deepline plays bootstrap people-email --from csv:data/leads.csv --using
|
|
|
8319
8461
|
const looksLikePlayReference = rawTemplate.includes("/") || rawTemplate.endsWith(".play.ts");
|
|
8320
8462
|
throw new PlayBootstrapUsageError(
|
|
8321
8463
|
`Unknown plays bootstrap template: ${rawTemplate}
|
|
8322
|
-
Supported templates: ${formatPlayBootstrapTemplates()}` + (looksLikePlayReference ? `
|
|
8464
|
+
Supported templates: ${formatPlayBootstrapTemplates()}|${MONITOR_BOOTSTRAP_TEMPLATE}` + (looksLikePlayReference ? `
|
|
8323
8465
|
|
|
8324
8466
|
"${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.` : "")
|
|
8325
8467
|
);
|
|
@@ -9528,7 +9670,25 @@ function renderPlayBootstrapError(error) {
|
|
|
9528
9670
|
console.error(errorMessage2(error));
|
|
9529
9671
|
return error instanceof PlayBootstrapError ? error.exitCode : 1;
|
|
9530
9672
|
}
|
|
9673
|
+
function writeBootstrapSource(source, out) {
|
|
9674
|
+
if (out) {
|
|
9675
|
+
writeFileSync8(resolve7(out), source, "utf-8");
|
|
9676
|
+
process.stdout.write(`Wrote ${resolve7(out)}
|
|
9677
|
+
`);
|
|
9678
|
+
return 0;
|
|
9679
|
+
}
|
|
9680
|
+
process.stdout.write(source);
|
|
9681
|
+
return 0;
|
|
9682
|
+
}
|
|
9683
|
+
function runMonitorBootstrap(args) {
|
|
9684
|
+
const options = parseMonitorBootstrapOptions(args);
|
|
9685
|
+
const source = generateMonitorTriggeredPlaySource(options);
|
|
9686
|
+
return writeBootstrapSource(source, options.out);
|
|
9687
|
+
}
|
|
9531
9688
|
async function runPlayBootstrap(args) {
|
|
9689
|
+
if (isMonitorBootstrapTemplate(args[0])) {
|
|
9690
|
+
return runMonitorBootstrap(args);
|
|
9691
|
+
}
|
|
9532
9692
|
const options = parsePlayBootstrapOptions(args);
|
|
9533
9693
|
const client2 = new DeeplineClient();
|
|
9534
9694
|
const contracts = await loadBootstrapContracts(client2, options);
|
|
@@ -9538,20 +9698,15 @@ async function runPlayBootstrap(args) {
|
|
|
9538
9698
|
...contracts,
|
|
9539
9699
|
...csvContext
|
|
9540
9700
|
});
|
|
9541
|
-
|
|
9542
|
-
writeFileSync8(resolve7(options.out), source, "utf-8");
|
|
9543
|
-
process.stdout.write(`Wrote ${resolve7(options.out)}
|
|
9544
|
-
`);
|
|
9545
|
-
return 0;
|
|
9546
|
-
}
|
|
9547
|
-
process.stdout.write(source);
|
|
9548
|
-
return 0;
|
|
9701
|
+
return writeBootstrapSource(source, options.out);
|
|
9549
9702
|
}
|
|
9550
9703
|
async function handlePlayBootstrap(args) {
|
|
9551
9704
|
return runPlayBootstrap(args).catch(renderPlayBootstrapError);
|
|
9552
9705
|
}
|
|
9553
9706
|
function registerPlayBootstrapCommand(play) {
|
|
9554
|
-
play.command("bootstrap <template>").description(
|
|
9707
|
+
play.command("bootstrap <template>").description(
|
|
9708
|
+
"Print a scratchpad play for a GTM route or monitor-triggered template."
|
|
9709
|
+
).addHelpText(
|
|
9555
9710
|
"after",
|
|
9556
9711
|
`
|
|
9557
9712
|
Notes:
|
|
@@ -9575,6 +9730,13 @@ Notes:
|
|
|
9575
9730
|
company-people company/account rows -> people play
|
|
9576
9731
|
company-people-email company/account rows -> people play -> email finder
|
|
9577
9732
|
company-people-phone company/account rows -> people play -> phone finder
|
|
9733
|
+
monitor-triggered run a play whenever a monitor writes a new row
|
|
9734
|
+
(definePlay with sqlListeners; no --from/stage flags)
|
|
9735
|
+
|
|
9736
|
+
Monitor-triggered options (only for the monitor-triggered template):
|
|
9737
|
+
--tool <monitor-tool-id> monitor tool to bind (default instantly.campaign_events)
|
|
9738
|
+
--stream <stream-key> output stream to listen on (default webhook_events)
|
|
9739
|
+
Discover a tool's streams/columns with: deepline monitors available <id>
|
|
9578
9740
|
|
|
9579
9741
|
Resource refs:
|
|
9580
9742
|
csv:./contacts.csv
|
|
@@ -9604,6 +9766,9 @@ Examples:
|
|
|
9604
9766
|
deepline plays bootstrap people-email --from provider:dropleads_search_people --using providers:hunter_email_finder,leadmagic_email_finder --limit 5 --out prospecting.play.ts
|
|
9605
9767
|
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
|
|
9606
9768
|
deepline plays bootstrap company-list --from provider:crustdata_companydb_search --limit 5 --out companies.play.ts
|
|
9769
|
+
|
|
9770
|
+
deepline plays bootstrap monitor-triggered --out on-new-row.play.ts
|
|
9771
|
+
deepline plays bootstrap monitor-triggered --tool tamradar.company_radar --stream company_job_openings --out on-new-job.play.ts
|
|
9607
9772
|
`
|
|
9608
9773
|
).option("--name <name>", "Generated play name").option(
|
|
9609
9774
|
"--from <ref>",
|
|
@@ -9620,7 +9785,13 @@ Examples:
|
|
|
9620
9785
|
).option(
|
|
9621
9786
|
"--phone <ref>",
|
|
9622
9787
|
"Phone finder stage: play:REF, provider:ID, or providers:ID,ID"
|
|
9623
|
-
).option("--limit <n>", "Maximum rows to fan out in the generated play").option(
|
|
9788
|
+
).option("--limit <n>", "Maximum rows to fan out in the generated play").option(
|
|
9789
|
+
"--tool <id>",
|
|
9790
|
+
"monitor-triggered only: monitor tool id to bind (e.g. instantly.campaign_events)"
|
|
9791
|
+
).option(
|
|
9792
|
+
"--stream <key>",
|
|
9793
|
+
"monitor-triggered only: monitor output stream to listen on (e.g. webhook_events)"
|
|
9794
|
+
).option("--out <path>", "Write generated play source to a file").action(async (template, options) => {
|
|
9624
9795
|
process.exitCode = await handlePlayBootstrap([
|
|
9625
9796
|
template,
|
|
9626
9797
|
...options.name ? ["--name", options.name] : [],
|
|
@@ -9630,6 +9801,8 @@ Examples:
|
|
|
9630
9801
|
...options.email ? ["--email", options.email] : [],
|
|
9631
9802
|
...options.phone ? ["--phone", options.phone] : [],
|
|
9632
9803
|
...options.limit ? ["--limit", options.limit] : [],
|
|
9804
|
+
...options.tool ? ["--tool", options.tool] : [],
|
|
9805
|
+
...options.stream ? ["--stream", options.stream] : [],
|
|
9633
9806
|
...options.out ? ["--out", options.out] : []
|
|
9634
9807
|
]);
|
|
9635
9808
|
});
|
|
@@ -13554,6 +13727,89 @@ function printToolGetterHints(hints) {
|
|
|
13554
13727
|
if (hint.unavailable) console.log(` - warning: ${hint.unavailable}`);
|
|
13555
13728
|
}
|
|
13556
13729
|
}
|
|
13730
|
+
function printPlayTriggers(triggers) {
|
|
13731
|
+
if (!triggers) return;
|
|
13732
|
+
const hasAny = (triggers.sqlListeners?.length ?? 0) > 0 || Boolean(triggers.cron) || triggers.webhook === true;
|
|
13733
|
+
if (!hasAny) return;
|
|
13734
|
+
console.log(" triggers:");
|
|
13735
|
+
for (const listener of triggers.sqlListeners ?? []) {
|
|
13736
|
+
const target = listener.tool && listener.stream ? `${listener.tool}/${listener.stream}` : listener.tool ?? listener.stream ?? listener.id;
|
|
13737
|
+
const operations = listener.operations.length ? listener.operations.join(", ") : "INSERT, UPDATE";
|
|
13738
|
+
const whereNote = listener.where ? " (with where filter)" : "";
|
|
13739
|
+
console.log(` sqlListeners \u2192 ${target} on ${operations}${whereNote}`);
|
|
13740
|
+
}
|
|
13741
|
+
if (triggers.cron) {
|
|
13742
|
+
const timezone = triggers.cron.timezone ? ` (${triggers.cron.timezone})` : "";
|
|
13743
|
+
console.log(` cron \u2192 ${triggers.cron.schedule}${timezone}`);
|
|
13744
|
+
}
|
|
13745
|
+
if (triggers.webhook === true) {
|
|
13746
|
+
console.log(" webhook \u2192 enabled");
|
|
13747
|
+
}
|
|
13748
|
+
}
|
|
13749
|
+
function printRecognizedSummary(recognized) {
|
|
13750
|
+
if (!recognized) return;
|
|
13751
|
+
if (recognized.tools?.length) {
|
|
13752
|
+
console.log(` tools: ${recognized.tools.join(", ")}`);
|
|
13753
|
+
}
|
|
13754
|
+
for (const dataset of recognized.datasets ?? []) {
|
|
13755
|
+
const columns = dataset.columns?.length ? ` (${dataset.columns.length} col${dataset.columns.length === 1 ? "" : "s"}: ${dataset.columns.join(", ")})` : "";
|
|
13756
|
+
console.log(` dataset ${dataset.name}${columns}`);
|
|
13757
|
+
}
|
|
13758
|
+
if (recognized.inputs?.length) {
|
|
13759
|
+
console.log(` inputs: ${recognized.inputs.join(", ")}`);
|
|
13760
|
+
}
|
|
13761
|
+
if (recognized.outputs?.length) {
|
|
13762
|
+
console.log(` outputs: ${recognized.outputs.join(", ")}`);
|
|
13763
|
+
}
|
|
13764
|
+
}
|
|
13765
|
+
function formatPlayCheckIssueLines(issue) {
|
|
13766
|
+
const lines = [` - ${issue.message}`];
|
|
13767
|
+
if (issue.path) {
|
|
13768
|
+
lines.push(` at ${issue.path}`);
|
|
13769
|
+
}
|
|
13770
|
+
if (issue.validOptions?.length) {
|
|
13771
|
+
lines.push(` \u2192 valid: [${issue.validOptions.join(", ")}]`);
|
|
13772
|
+
}
|
|
13773
|
+
if (issue.hint?.trim()) {
|
|
13774
|
+
lines.push(` hint: ${issue.hint.trim()}`);
|
|
13775
|
+
}
|
|
13776
|
+
if (issue.docsHint?.trim()) {
|
|
13777
|
+
lines.push(` next: ${issue.docsHint.trim()}`);
|
|
13778
|
+
}
|
|
13779
|
+
return lines;
|
|
13780
|
+
}
|
|
13781
|
+
function printPlayCheckIssues(issues, writer) {
|
|
13782
|
+
if (!issues?.length) return;
|
|
13783
|
+
const errorIssues = issues.filter((issue) => issue.severity === "error");
|
|
13784
|
+
const warningIssues = issues.filter((issue) => issue.severity === "warning");
|
|
13785
|
+
if (errorIssues.length) {
|
|
13786
|
+
writer(" issues:");
|
|
13787
|
+
for (const issue of errorIssues) {
|
|
13788
|
+
for (const line of formatPlayCheckIssueLines(issue)) writer(line);
|
|
13789
|
+
}
|
|
13790
|
+
}
|
|
13791
|
+
if (warningIssues.length) {
|
|
13792
|
+
writer(" warnings:");
|
|
13793
|
+
for (const issue of warningIssues) {
|
|
13794
|
+
for (const line of formatPlayCheckIssueLines(issue)) writer(line);
|
|
13795
|
+
}
|
|
13796
|
+
}
|
|
13797
|
+
}
|
|
13798
|
+
function partitionMirroredErrors(errors, issues) {
|
|
13799
|
+
const errorMessages = (issues ?? []).filter((issue) => issue.severity === "error").map((issue) => issue.message.trim()).filter((message) => message.length > 0);
|
|
13800
|
+
if (errorMessages.length === 0) {
|
|
13801
|
+
return { unstructuredErrors: errors ?? [] };
|
|
13802
|
+
}
|
|
13803
|
+
const isMirror = (error) => {
|
|
13804
|
+
const trimmed = error.trim();
|
|
13805
|
+
return errorMessages.some(
|
|
13806
|
+
(message) => trimmed === message || trimmed.startsWith(message)
|
|
13807
|
+
);
|
|
13808
|
+
};
|
|
13809
|
+
return {
|
|
13810
|
+
unstructuredErrors: (errors ?? []).filter((error) => !isMirror(error))
|
|
13811
|
+
};
|
|
13812
|
+
}
|
|
13557
13813
|
async function handlePlayCheck(args) {
|
|
13558
13814
|
const options = parsePlayCheckOptions(args);
|
|
13559
13815
|
if (!isFileTarget(options.target)) {
|
|
@@ -13686,16 +13942,27 @@ async function handlePlayCheck(args) {
|
|
|
13686
13942
|
`
|
|
13687
13943
|
);
|
|
13688
13944
|
} else if (enrichedResult.valid) {
|
|
13689
|
-
|
|
13945
|
+
const summary = enrichedResult.summary?.trim();
|
|
13946
|
+
console.log(
|
|
13947
|
+
summary ? `\u2713 ${playName} valid \u2014 ${summary}` : `\u2713 ${playName} passed cloud play check`
|
|
13948
|
+
);
|
|
13690
13949
|
if (enrichedResult.artifactHash) {
|
|
13691
13950
|
console.log(` artifact: ${enrichedResult.artifactHash.slice(0, 12)}`);
|
|
13692
13951
|
}
|
|
13952
|
+
printPlayTriggers(enrichedResult.triggers);
|
|
13953
|
+
printRecognizedSummary(enrichedResult.recognized);
|
|
13954
|
+
printPlayCheckIssues(enrichedResult.issues, (line) => console.log(line));
|
|
13693
13955
|
printToolGetterHints(enrichedResult.toolGetterHints);
|
|
13694
13956
|
} else {
|
|
13695
13957
|
console.error(`\u2717 ${playName} failed cloud play check`);
|
|
13696
|
-
|
|
13958
|
+
const { unstructuredErrors } = partitionMirroredErrors(
|
|
13959
|
+
enrichedResult.errors,
|
|
13960
|
+
enrichedResult.issues
|
|
13961
|
+
);
|
|
13962
|
+
for (const error of unstructuredErrors) {
|
|
13697
13963
|
console.error(` ${error}`);
|
|
13698
13964
|
}
|
|
13965
|
+
printPlayCheckIssues(enrichedResult.issues, (line) => console.error(line));
|
|
13699
13966
|
printToolGetterHints(enrichedResult.toolGetterHints);
|
|
13700
13967
|
}
|
|
13701
13968
|
return enrichedResult.valid ? 0 : 1;
|
|
@@ -16215,7 +16482,7 @@ function canInlineRunJavascript(command) {
|
|
|
16215
16482
|
return true;
|
|
16216
16483
|
}
|
|
16217
16484
|
function renderExtractFunction(command, indentSpaces) {
|
|
16218
|
-
return command.extract_js ? `({ row, result, data, raw, pick, extract, extractList, target, get }) => { const input = row; const context = row;
|
|
16485
|
+
return command.extract_js ? `({ row, result, data, raw, pick, extract, extractList, target, get }) => { const input = row; const context = row; const output_data = __dlLegacyOutputData(result, raw);
|
|
16219
16486
|
${indent(renderJavascriptBody(command.extract_js), indentSpaces)}
|
|
16220
16487
|
}` : "null";
|
|
16221
16488
|
}
|
|
@@ -16843,8 +17110,13 @@ function helperSource() {
|
|
|
16843
17110
|
` __dlPushCandidate(candidates, record.data);`,
|
|
16844
17111
|
` __dlPushCandidate(candidates, record.result);`,
|
|
16845
17112
|
` __dlPushCandidate(candidates, record.output);`,
|
|
17113
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'data.data'));`,
|
|
16846
17114
|
` __dlPushCandidate(candidates, __dlGetByPath(record, 'result.data'));`,
|
|
17115
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'result.data.data'));`,
|
|
17116
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'output.data'));`,
|
|
17117
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'output.data.data'));`,
|
|
16847
17118
|
` __dlPushCandidate(candidates, __dlGetByPath(record, 'output.body'));`,
|
|
17119
|
+
` __dlPushCandidate(candidates, __dlGetByPath(record, 'output.body.data'));`,
|
|
16848
17120
|
` __dlPushCandidate(candidates, __dlGetByPath(record, 'toolResponse.raw'));`,
|
|
16849
17121
|
` __dlPushCandidate(candidates, __dlGetByPath(record, 'toolOutput.raw'));`,
|
|
16850
17122
|
` return candidates;`,
|
|
@@ -17241,13 +17513,37 @@ function helperSource() {
|
|
|
17241
17513
|
` return { ...defaults, ...(existing as Record<string, unknown>) };`,
|
|
17242
17514
|
`}`,
|
|
17243
17515
|
``,
|
|
17516
|
+
`function __dlCompactJavascriptContext(value: unknown, depth = 0): unknown {`,
|
|
17517
|
+
` if (depth > 8) return '[Object]';`,
|
|
17518
|
+
` if (typeof value === 'string') return value.length > 20000 ? value.slice(0, 20000) + '...[truncated]' : value;`,
|
|
17519
|
+
` if (!value || typeof value !== 'object') return value;`,
|
|
17520
|
+
` if (Array.isArray(value)) {`,
|
|
17521
|
+
` const limit = depth <= 2 ? 25 : 10;`,
|
|
17522
|
+
` const items = value.slice(0, limit).map((entry) => __dlCompactJavascriptContext(entry, depth + 1));`,
|
|
17523
|
+
` if (value.length > limit) items.push({ __deepline_truncated_items: value.length - limit });`,
|
|
17524
|
+
` return items;`,
|
|
17525
|
+
` }`,
|
|
17526
|
+
` const out: Record<string, unknown> = {};`,
|
|
17527
|
+
` let count = 0;`,
|
|
17528
|
+
` for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {`,
|
|
17529
|
+
` count += 1;`,
|
|
17530
|
+
` if (count > 80) {`,
|
|
17531
|
+
` out.__deepline_truncated_fields = count - 80;`,
|
|
17532
|
+
` break;`,
|
|
17533
|
+
` }`,
|
|
17534
|
+
` out[key] = __dlCompactJavascriptContext(entry, depth + 1);`,
|
|
17535
|
+
` }`,
|
|
17536
|
+
` return out;`,
|
|
17537
|
+
`}`,
|
|
17538
|
+
``,
|
|
17244
17539
|
`function __dlRuntimePayload(tool: string, payload: Record<string, unknown>, row: Record<string, unknown>): Record<string, unknown> {`,
|
|
17245
17540
|
` if (tool !== 'run_javascript') return payload;`,
|
|
17541
|
+
` const compactRow = __dlCompactJavascriptContext(row) as Record<string, unknown>;`,
|
|
17246
17542
|
` return {`,
|
|
17247
17543
|
` ...payload,`,
|
|
17248
|
-
` row: __dlMergeContextRecord(payload.row,
|
|
17249
|
-
` input: __dlMergeContextRecord(payload.input,
|
|
17250
|
-
` context: __dlMergeContextRecord(payload.context,
|
|
17544
|
+
` row: __dlMergeContextRecord(payload.row, compactRow),`,
|
|
17545
|
+
` input: __dlMergeContextRecord(payload.input, compactRow),`,
|
|
17546
|
+
` context: __dlMergeContextRecord(payload.context, compactRow),`,
|
|
17251
17547
|
` };`,
|
|
17252
17548
|
`}`,
|
|
17253
17549
|
``,
|
|
@@ -18250,6 +18546,125 @@ function enrichOutputJson(exportResult) {
|
|
|
18250
18546
|
...exportResult.partial ? { rows: exportResult.rows, partial: true } : {}
|
|
18251
18547
|
};
|
|
18252
18548
|
}
|
|
18549
|
+
function readFirstEnrichDatasetActions(value) {
|
|
18550
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18551
|
+
const walk = (candidate, options) => {
|
|
18552
|
+
if (!candidate || typeof candidate !== "object" || seen.has(candidate)) {
|
|
18553
|
+
return null;
|
|
18554
|
+
}
|
|
18555
|
+
seen.add(candidate);
|
|
18556
|
+
if (Array.isArray(candidate)) {
|
|
18557
|
+
for (const entry of candidate) {
|
|
18558
|
+
const found = walk(entry, options);
|
|
18559
|
+
if (found) return found;
|
|
18560
|
+
}
|
|
18561
|
+
return null;
|
|
18562
|
+
}
|
|
18563
|
+
const record = candidate;
|
|
18564
|
+
const actions = isRecord7(record.actions) ? record.actions : null;
|
|
18565
|
+
const query = isRecord7(actions?.query) ? actions.query : null;
|
|
18566
|
+
if (query?.kind === "deepline_db_query") {
|
|
18567
|
+
return {
|
|
18568
|
+
dataset: record,
|
|
18569
|
+
query,
|
|
18570
|
+
...isRecord7(actions?.exportCsv) ? { exportCsv: actions.exportCsv } : {}
|
|
18571
|
+
};
|
|
18572
|
+
}
|
|
18573
|
+
if (options.allowLegacy && record.kind === "dataset" && typeof record.queryDatasetCommand === "string" && record.queryDatasetCommand.trim()) {
|
|
18574
|
+
return {
|
|
18575
|
+
dataset: record,
|
|
18576
|
+
queryDatasetCommand: record.queryDatasetCommand.trim(),
|
|
18577
|
+
...typeof record.slowExportAsCsvCommand === "string" && record.slowExportAsCsvCommand.trim() ? { slowExportAsCsvCommand: record.slowExportAsCsvCommand.trim() } : {}
|
|
18578
|
+
};
|
|
18579
|
+
}
|
|
18580
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
18581
|
+
if (key === "preview") {
|
|
18582
|
+
continue;
|
|
18583
|
+
}
|
|
18584
|
+
const found = walk(entry, options);
|
|
18585
|
+
if (found) return found;
|
|
18586
|
+
}
|
|
18587
|
+
return null;
|
|
18588
|
+
};
|
|
18589
|
+
const modern = walk(value, { allowLegacy: false });
|
|
18590
|
+
if (modern) {
|
|
18591
|
+
return modern;
|
|
18592
|
+
}
|
|
18593
|
+
seen.clear();
|
|
18594
|
+
return walk(value, { allowLegacy: true });
|
|
18595
|
+
}
|
|
18596
|
+
function actionStringField(record, key) {
|
|
18597
|
+
const value = record[key];
|
|
18598
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
18599
|
+
}
|
|
18600
|
+
function parseSqlFromDbQueryCommand(command) {
|
|
18601
|
+
if (!command) {
|
|
18602
|
+
return null;
|
|
18603
|
+
}
|
|
18604
|
+
const match = command.match(/\s--sql\s+('(?:'\\''|[^'])*'|"(?:"\\"|[^"])*")/);
|
|
18605
|
+
if (!match?.[1]) {
|
|
18606
|
+
return null;
|
|
18607
|
+
}
|
|
18608
|
+
const raw = match[1];
|
|
18609
|
+
if (raw.startsWith("'") && raw.endsWith("'")) {
|
|
18610
|
+
return raw.slice(1, -1).replace(/'\\''/g, "'");
|
|
18611
|
+
}
|
|
18612
|
+
return decodeStringLiteral(raw);
|
|
18613
|
+
}
|
|
18614
|
+
function enrichCustomerDbJson(input2) {
|
|
18615
|
+
const actions = readFirstEnrichDatasetActions(input2.status);
|
|
18616
|
+
if (!actions) {
|
|
18617
|
+
return null;
|
|
18618
|
+
}
|
|
18619
|
+
const query = actions.query ?? {};
|
|
18620
|
+
const dataset = actions.dataset;
|
|
18621
|
+
const sql = actionStringField(query, "sql") ?? parseSqlFromDbQueryCommand(actions.queryDatasetCommand);
|
|
18622
|
+
const datasetPath = actionStringField(query, "datasetPath") ?? actionStringField(dataset, "path") ?? actionStringField(dataset, "tableNamespace");
|
|
18623
|
+
const api = isRecord7(query.api) ? query.api : null;
|
|
18624
|
+
const apiPath = actionStringField(api ?? {}, "path") ?? "/api/v2/db/query";
|
|
18625
|
+
const apiMethod = actionStringField(api ?? {}, "method") ?? "POST";
|
|
18626
|
+
if (!datasetPath) {
|
|
18627
|
+
return null;
|
|
18628
|
+
}
|
|
18629
|
+
const maxRows = typeof query.maxRows === "number" && Number.isFinite(query.maxRows) ? Math.trunc(query.maxRows) : void 0;
|
|
18630
|
+
const runId = extractRunId(input2.status) ?? actionStringField(actions.exportCsv ?? {}, "runId");
|
|
18631
|
+
const exportDatasetPath = actionStringField(actions.exportCsv ?? {}, "datasetPath") ?? datasetPath;
|
|
18632
|
+
const tableNamespace = actionStringField(query, "tableNamespace") ?? actionStringField(dataset, "tableNamespace");
|
|
18633
|
+
const sqlTableName = actionStringField(query, "sqlTableName");
|
|
18634
|
+
const sqlQualifiedTableName = actionStringField(
|
|
18635
|
+
query,
|
|
18636
|
+
"sqlQualifiedTableName"
|
|
18637
|
+
);
|
|
18638
|
+
const command = actions.queryDatasetCommand ?? (sql ? `deepline db query --sql ${shellSingleQuote2(sql)}${maxRows !== void 0 ? ` --max-rows ${maxRows}` : ""} --json` : null);
|
|
18639
|
+
return {
|
|
18640
|
+
runId,
|
|
18641
|
+
datasetPath,
|
|
18642
|
+
...tableNamespace ? { tableNamespace } : {},
|
|
18643
|
+
...sqlTableName ? { sqlTableName } : {},
|
|
18644
|
+
...sqlQualifiedTableName ? { sqlQualifiedTableName } : {},
|
|
18645
|
+
...sql ? { sql } : {},
|
|
18646
|
+
...actions.query ? {
|
|
18647
|
+
api: {
|
|
18648
|
+
method: apiMethod,
|
|
18649
|
+
path: apiPath,
|
|
18650
|
+
url: `${input2.client.baseUrl.replace(/\/$/, "")}${apiPath}`
|
|
18651
|
+
}
|
|
18652
|
+
} : {},
|
|
18653
|
+
...maxRows !== void 0 ? { maxRows } : {},
|
|
18654
|
+
...command ? { command } : {},
|
|
18655
|
+
...actions.exportCsv || actions.slowExportAsCsvCommand ? {
|
|
18656
|
+
export: {
|
|
18657
|
+
datasetPath: exportDatasetPath,
|
|
18658
|
+
...actions.slowExportAsCsvCommand ? { command: actions.slowExportAsCsvCommand } : runId && input2.outputPath ? {
|
|
18659
|
+
command: `deepline runs export ${runId} --dataset ${shellSingleQuote2(
|
|
18660
|
+
exportDatasetPath
|
|
18661
|
+
)} --out ${shellSingleQuote2(resolve9(input2.outputPath))}`
|
|
18662
|
+
} : {},
|
|
18663
|
+
action: actions.exportCsv ?? {}
|
|
18664
|
+
}
|
|
18665
|
+
} : {}
|
|
18666
|
+
};
|
|
18667
|
+
}
|
|
18253
18668
|
function enrichReportJson(report) {
|
|
18254
18669
|
if (!report) {
|
|
18255
18670
|
return {};
|
|
@@ -18270,6 +18685,78 @@ function enrichReportJson(report) {
|
|
|
18270
18685
|
} : {}
|
|
18271
18686
|
};
|
|
18272
18687
|
}
|
|
18688
|
+
function sqlStringLiteral(value) {
|
|
18689
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
18690
|
+
}
|
|
18691
|
+
function failureAliasFromCellMeta(cellMeta) {
|
|
18692
|
+
if (!isRecord7(cellMeta)) {
|
|
18693
|
+
return null;
|
|
18694
|
+
}
|
|
18695
|
+
for (const [alias, meta] of Object.entries(cellMeta)) {
|
|
18696
|
+
if (!isRecord7(meta)) {
|
|
18697
|
+
continue;
|
|
18698
|
+
}
|
|
18699
|
+
const failure = failureCellFromMeta(meta, {});
|
|
18700
|
+
if (!failure) {
|
|
18701
|
+
continue;
|
|
18702
|
+
}
|
|
18703
|
+
return {
|
|
18704
|
+
alias,
|
|
18705
|
+
...typeof failure.error === "string" ? { error: failure.error } : {},
|
|
18706
|
+
...typeof failure.operation === "string" ? { operation: failure.operation } : {},
|
|
18707
|
+
...typeof failure.provider === "string" ? { provider: failure.provider } : {}
|
|
18708
|
+
};
|
|
18709
|
+
}
|
|
18710
|
+
return null;
|
|
18711
|
+
}
|
|
18712
|
+
async function collectCustomerDbFailureJobs(input2) {
|
|
18713
|
+
const customerDb = enrichCustomerDbJson({
|
|
18714
|
+
status: input2.status,
|
|
18715
|
+
client: input2.client
|
|
18716
|
+
});
|
|
18717
|
+
if (!customerDb?.runId || !customerDb.sqlQualifiedTableName) {
|
|
18718
|
+
return [];
|
|
18719
|
+
}
|
|
18720
|
+
const fallbackAliases = collectHardFailureAliasSpecs(input2.config);
|
|
18721
|
+
const fallbackAlias = fallbackAliases[0]?.alias ?? "enrich";
|
|
18722
|
+
const aliasIndexByName = new Map(
|
|
18723
|
+
fallbackAliases.map((spec, index) => [normalizeAlias2(spec.alias), index])
|
|
18724
|
+
);
|
|
18725
|
+
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`;
|
|
18726
|
+
const result = await input2.client.queryCustomerDb({
|
|
18727
|
+
sql,
|
|
18728
|
+
maxRows: 1e3
|
|
18729
|
+
});
|
|
18730
|
+
const rows = Array.isArray(result.rows) ? result.rows : [];
|
|
18731
|
+
const failedRows = rows.filter((row) => {
|
|
18732
|
+
const status = typeof row._status === "string" ? row._status.trim().toLowerCase() : "";
|
|
18733
|
+
return typeof row._error === "string" && row._error.trim() || status === "failed" || status === "error";
|
|
18734
|
+
});
|
|
18735
|
+
return failedRows.map((row, index) => {
|
|
18736
|
+
const metaFailure = failureAliasFromCellMeta(row._cell_meta);
|
|
18737
|
+
const alias = metaFailure?.alias ?? fallbackAlias;
|
|
18738
|
+
const normalizedAlias = normalizeAlias2(alias);
|
|
18739
|
+
const rowId = typeof row._input_index === "number" ? row._input_index : typeof row._input_index === "string" && row._input_index.trim() ? Number.parseInt(row._input_index, 10) : index;
|
|
18740
|
+
const rawError = metaFailure?.error ?? (typeof row._error === "string" && row._error.trim() ? row._error.trim() : `Column status: ${String(row._status ?? "failed")}`);
|
|
18741
|
+
const message = enrichFailureMessageWithOperation(
|
|
18742
|
+
rawError,
|
|
18743
|
+
metaFailure?.operation ?? fallbackAliases.find(
|
|
18744
|
+
(spec) => normalizeAlias2(spec.alias) === normalizedAlias
|
|
18745
|
+
)?.operation
|
|
18746
|
+
);
|
|
18747
|
+
return {
|
|
18748
|
+
job_id: `row-${Number.isFinite(rowId) ? rowId : index}-${normalizedAlias || "enrich"}`,
|
|
18749
|
+
row_id: Number.isFinite(rowId) ? rowId : index,
|
|
18750
|
+
col_index: aliasIndexByName.get(normalizedAlias) ?? 0,
|
|
18751
|
+
column: alias,
|
|
18752
|
+
status: "failed",
|
|
18753
|
+
last_error: message,
|
|
18754
|
+
error: message,
|
|
18755
|
+
...metaFailure?.operation ? { operation: metaFailure.operation } : {},
|
|
18756
|
+
...metaFailure?.provider ? { provider: metaFailure.provider } : {}
|
|
18757
|
+
};
|
|
18758
|
+
});
|
|
18759
|
+
}
|
|
18273
18760
|
async function buildEnrichFailureReport(input2) {
|
|
18274
18761
|
const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
|
|
18275
18762
|
return maybeEmitEnrichFailureReport({
|
|
@@ -18371,9 +18858,7 @@ async function writeSlimBatchedRuntimeCsv(input2) {
|
|
|
18371
18858
|
};
|
|
18372
18859
|
cleanRows[rowIndex] = {
|
|
18373
18860
|
...baseRow,
|
|
18374
|
-
...Object.fromEntries(
|
|
18375
|
-
Object.entries(mergeRow).map(compactOverlayCell)
|
|
18376
|
-
)
|
|
18861
|
+
...Object.fromEntries(Object.entries(mergeRow).map(compactOverlayCell))
|
|
18377
18862
|
};
|
|
18378
18863
|
}
|
|
18379
18864
|
const columns = dataExportColumns(
|
|
@@ -18797,6 +19282,11 @@ function collectWaterfallAliasSpecs(config) {
|
|
|
18797
19282
|
aliases.push({
|
|
18798
19283
|
alias,
|
|
18799
19284
|
childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
|
|
19285
|
+
childRunIfJsByAlias: new Map(
|
|
19286
|
+
activeChildren.map(
|
|
19287
|
+
(child) => [child.alias, child.run_if_js]
|
|
19288
|
+
)
|
|
19289
|
+
),
|
|
18800
19290
|
childToolsByAlias: new Map(
|
|
18801
19291
|
activeChildren.map(
|
|
18802
19292
|
(child) => [child.alias, child.tool.trim()]
|
|
@@ -19031,7 +19521,8 @@ function collectEmptyWaterfallIssues(input2) {
|
|
|
19031
19521
|
});
|
|
19032
19522
|
const issues = [];
|
|
19033
19523
|
aliases.forEach((spec) => {
|
|
19034
|
-
|
|
19524
|
+
const executionSignal = waterfallExecutionSignal(input2.status, spec);
|
|
19525
|
+
if (executionSignal === "all_condition_skipped" || executionSignal === "unknown" && waterfallChildrenAreStaticallySkipped(spec)) {
|
|
19035
19526
|
return;
|
|
19036
19527
|
}
|
|
19037
19528
|
const logicalRows = /* @__PURE__ */ new Map();
|
|
@@ -19073,6 +19564,22 @@ function collectEmptyWaterfallIssues(input2) {
|
|
|
19073
19564
|
});
|
|
19074
19565
|
return issues;
|
|
19075
19566
|
}
|
|
19567
|
+
function waterfallChildrenAreStaticallySkipped(spec) {
|
|
19568
|
+
const childAliases = spec.childAliases ?? [];
|
|
19569
|
+
if (childAliases.length === 0 || !spec.childRunIfJsByAlias) {
|
|
19570
|
+
return false;
|
|
19571
|
+
}
|
|
19572
|
+
return childAliases.every(
|
|
19573
|
+
(alias) => runIfJsAlwaysReturnsFalse(spec.childRunIfJsByAlias?.get(alias))
|
|
19574
|
+
);
|
|
19575
|
+
}
|
|
19576
|
+
function runIfJsAlwaysReturnsFalse(source) {
|
|
19577
|
+
if (typeof source !== "string") {
|
|
19578
|
+
return false;
|
|
19579
|
+
}
|
|
19580
|
+
const normalized = source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "").trim();
|
|
19581
|
+
return /^(?:return\s+)?\(?\s*false\s*\)?\s*;?$/.test(normalized);
|
|
19582
|
+
}
|
|
19076
19583
|
function waterfallExecutionSignal(status, spec) {
|
|
19077
19584
|
const childAliases = spec.childAliases ?? [];
|
|
19078
19585
|
if (childAliases.length === 0) {
|
|
@@ -19349,10 +19856,11 @@ function rewriteEnrichJsonStatus(input2) {
|
|
|
19349
19856
|
if (failedRows === 0 || !isRecord7(rewritten)) {
|
|
19350
19857
|
return rewritten;
|
|
19351
19858
|
}
|
|
19859
|
+
const partialStatus = selectedRows > 0 && failedRows < selectedRows ? "partial_success" : "failed";
|
|
19352
19860
|
return {
|
|
19353
19861
|
...rewritten,
|
|
19354
|
-
...rewritten.status === "completed" ? { status:
|
|
19355
|
-
...isRecord7(rewritten.run) && rewritten.run.status === "completed" ? { run: { ...rewritten.run, status:
|
|
19862
|
+
...rewritten.status === "completed" || rewritten.status === "failed" ? { status: partialStatus } : {},
|
|
19863
|
+
...isRecord7(rewritten.run) && (rewritten.run.status === "completed" || rewritten.run.status === "failed") ? { run: { ...rewritten.run, status: partialStatus } } : {}
|
|
19356
19864
|
};
|
|
19357
19865
|
}
|
|
19358
19866
|
function summarizeFailedJobError(value) {
|
|
@@ -19388,6 +19896,12 @@ function collectEnrichFollowUpCommands(input2) {
|
|
|
19388
19896
|
command: `deepline runs get ${input2.runId} --full --json`
|
|
19389
19897
|
});
|
|
19390
19898
|
}
|
|
19899
|
+
if (input2.runId && input2.outputPath) {
|
|
19900
|
+
addEnrichRowsExportFollowUpCommand(commands, seen, {
|
|
19901
|
+
runId: input2.runId,
|
|
19902
|
+
outputPath: input2.outputPath
|
|
19903
|
+
});
|
|
19904
|
+
}
|
|
19391
19905
|
collectDatasetFollowUpCommands(input2.status, {
|
|
19392
19906
|
runId: input2.runId,
|
|
19393
19907
|
outputPath: input2.outputPath,
|
|
@@ -19396,17 +19910,17 @@ function collectEnrichFollowUpCommands(input2) {
|
|
|
19396
19910
|
path: "result",
|
|
19397
19911
|
depth: 0
|
|
19398
19912
|
});
|
|
19399
|
-
if (input2.runId && input2.outputPath && !commands.some((command) => command.label === "export enrich rows")) {
|
|
19400
|
-
addEnrichFollowUpCommand(commands, seen, {
|
|
19401
|
-
label: "export enrich rows",
|
|
19402
|
-
path: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
|
|
19403
|
-
command: `deepline runs export ${input2.runId} --dataset ${GENERATED_ENRICH_ROWS_TABLE_NAMESPACE} --out ${shellSingleQuote2(
|
|
19404
|
-
resolve9(input2.outputPath)
|
|
19405
|
-
)}`
|
|
19406
|
-
});
|
|
19407
|
-
}
|
|
19408
19913
|
return commands.slice(0, 8);
|
|
19409
19914
|
}
|
|
19915
|
+
function addEnrichRowsExportFollowUpCommand(commands, seen, input2) {
|
|
19916
|
+
addEnrichFollowUpCommand(commands, seen, {
|
|
19917
|
+
label: "export enrich rows",
|
|
19918
|
+
path: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
|
|
19919
|
+
command: `deepline runs export ${input2.runId} --dataset ${GENERATED_ENRICH_ROWS_TABLE_NAMESPACE} --out ${shellSingleQuote2(
|
|
19920
|
+
resolve9(input2.outputPath)
|
|
19921
|
+
)}`
|
|
19922
|
+
});
|
|
19923
|
+
}
|
|
19410
19924
|
function sidecarEnrichRowsExportPath(outputPath) {
|
|
19411
19925
|
const resolved = resolve9(outputPath);
|
|
19412
19926
|
const ext = extname(resolved) || ".csv";
|
|
@@ -19547,7 +20061,15 @@ async function maybeEmitEnrichFailureReport(input2) {
|
|
|
19547
20061
|
status: input2.status,
|
|
19548
20062
|
rowRange: input2.statusRowRange ?? input2.rowRange
|
|
19549
20063
|
});
|
|
19550
|
-
const
|
|
20064
|
+
const customerDbJobs = input2.status === void 0 || rowJobs.length > 0 || statusJobs.length > 0 ? [] : await collectCustomerDbFailureJobs({
|
|
20065
|
+
client: input2.client,
|
|
20066
|
+
status: input2.status,
|
|
20067
|
+
config: input2.config
|
|
20068
|
+
});
|
|
20069
|
+
const jobs = rowJobs.length > 0 || statusJobs.length > 0 || customerDbJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(
|
|
20070
|
+
mergeEnrichFailureJobs(rowJobs, statusJobs),
|
|
20071
|
+
customerDbJobs
|
|
20072
|
+
) : [];
|
|
19551
20073
|
if (jobs.length === 0 && enrichIssues.length === 0) {
|
|
19552
20074
|
return null;
|
|
19553
20075
|
}
|
|
@@ -19653,6 +20175,8 @@ async function fetchBackingRowsForCsvExport(input2) {
|
|
|
19653
20175
|
const hasExplicitExpectedRows = typeof input2.expectedRows === "number" && input2.expectedRows > 0;
|
|
19654
20176
|
const minimumExpectedRows = hasExplicitExpectedRows ? Math.trunc(Number(input2.expectedRows)) : input2.rowsInfo.totalRows;
|
|
19655
20177
|
let lastExpectedTotal = minimumExpectedRows;
|
|
20178
|
+
const expectedSourceRowStart = input2.sourceRowStart ?? 0;
|
|
20179
|
+
const expectedSourceRowEnd = expectedSourceRowStart + Math.max(0, minimumExpectedRows) - 1;
|
|
19656
20180
|
for (; ; ) {
|
|
19657
20181
|
const sheetRows = [];
|
|
19658
20182
|
let offset = 0;
|
|
@@ -19668,19 +20192,39 @@ async function fetchBackingRowsForCsvExport(input2) {
|
|
|
19668
20192
|
});
|
|
19669
20193
|
sheetRows.push(...page.rows);
|
|
19670
20194
|
const summaryTotal = page.summary?.stats?.total;
|
|
19671
|
-
if (typeof summaryTotal === "number" && Number.isFinite(summaryTotal)) {
|
|
20195
|
+
if (!hasExplicitExpectedRows && typeof summaryTotal === "number" && Number.isFinite(summaryTotal)) {
|
|
19672
20196
|
expectedTotal = Math.max(expectedTotal, Math.trunc(summaryTotal));
|
|
19673
20197
|
}
|
|
19674
|
-
|
|
20198
|
+
let hasRequiredRows = sheetRows.length >= expectedTotal;
|
|
20199
|
+
if (hasExplicitExpectedRows) {
|
|
20200
|
+
const exportableRows = coalesceExportableSheetRows(
|
|
20201
|
+
sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row)),
|
|
20202
|
+
input2.sourceRowStart ?? 0
|
|
20203
|
+
).filter(
|
|
20204
|
+
(row) => sourceRowIndexFromEnrichRow(
|
|
20205
|
+
row,
|
|
20206
|
+
expectedSourceRowStart,
|
|
20207
|
+
expectedSourceRowEnd
|
|
20208
|
+
) !== null
|
|
20209
|
+
);
|
|
20210
|
+
hasRequiredRows = exportableRows.length >= minimumExpectedRows;
|
|
20211
|
+
}
|
|
20212
|
+
if (page.rows.length < ENRICH_EXPORT_PAGE_SIZE || hasRequiredRows) {
|
|
19675
20213
|
break;
|
|
19676
20214
|
}
|
|
19677
20215
|
offset += page.rows.length;
|
|
19678
20216
|
}
|
|
19679
20217
|
const rawRows = sheetRows.map((row) => exportableSheetRow2(row, input2.sourceRowStart ?? 0)).filter((row) => Boolean(row));
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19683
|
-
|
|
20218
|
+
let rows = coalesceExportableSheetRows(rawRows, input2.sourceRowStart ?? 0);
|
|
20219
|
+
if (hasExplicitExpectedRows) {
|
|
20220
|
+
rows = rows.filter(
|
|
20221
|
+
(row) => sourceRowIndexFromEnrichRow(
|
|
20222
|
+
row,
|
|
20223
|
+
expectedSourceRowStart,
|
|
20224
|
+
expectedSourceRowEnd
|
|
20225
|
+
) !== null
|
|
20226
|
+
);
|
|
20227
|
+
}
|
|
19684
20228
|
lastRows = rows;
|
|
19685
20229
|
lastExpectedTotal = expectedTotal;
|
|
19686
20230
|
const requiredExportRows = hasExplicitExpectedRows ? minimumExpectedRows : expectedTotal;
|
|
@@ -20334,6 +20878,7 @@ function registerEnrichCommand(program) {
|
|
|
20334
20878
|
}
|
|
20335
20879
|
if (input2.json) {
|
|
20336
20880
|
runArgs.push("--json");
|
|
20881
|
+
runArgs.push("--full");
|
|
20337
20882
|
} else {
|
|
20338
20883
|
runArgs.push("--logs");
|
|
20339
20884
|
}
|
|
@@ -20456,6 +21001,11 @@ function registerEnrichCommand(program) {
|
|
|
20456
21001
|
partial: true
|
|
20457
21002
|
} : {}
|
|
20458
21003
|
} : null,
|
|
21004
|
+
customer_db: enrichCustomerDbJson({
|
|
21005
|
+
status: chunk.status,
|
|
21006
|
+
client: client2,
|
|
21007
|
+
outputPath: enrichIssueFollowUpOutputPath ?? committedExportResult2?.path ?? outputPath
|
|
21008
|
+
}),
|
|
20459
21009
|
...enrichReportJson(failureReport3)
|
|
20460
21010
|
});
|
|
20461
21011
|
} else {
|
|
@@ -20530,6 +21080,11 @@ function registerEnrichCommand(program) {
|
|
|
20530
21080
|
enrichedRows: totalEnrichedRows,
|
|
20531
21081
|
path: finalExportResult.path
|
|
20532
21082
|
} : null,
|
|
21083
|
+
customer_db: enrichCustomerDbJson({
|
|
21084
|
+
status: lastStatus,
|
|
21085
|
+
client: client2,
|
|
21086
|
+
outputPath: enrichIssueFollowUpOutputPath ?? finalExportResult?.path ?? outputPath
|
|
21087
|
+
}),
|
|
20533
21088
|
...enrichReportJson(failureReport2)
|
|
20534
21089
|
});
|
|
20535
21090
|
}
|
|
@@ -20569,6 +21124,11 @@ function registerEnrichCommand(program) {
|
|
|
20569
21124
|
ok: false,
|
|
20570
21125
|
run: status,
|
|
20571
21126
|
output: enrichOutputJson(committedExportResult2),
|
|
21127
|
+
customer_db: enrichCustomerDbJson({
|
|
21128
|
+
status,
|
|
21129
|
+
client: client2,
|
|
21130
|
+
outputPath: enrichIssueFollowUpOutputPath ?? committedExportResult2?.path ?? outputPath
|
|
21131
|
+
}),
|
|
20572
21132
|
...enrichReportJson(failureReport2)
|
|
20573
21133
|
});
|
|
20574
21134
|
}
|
|
@@ -20599,6 +21159,11 @@ function registerEnrichCommand(program) {
|
|
|
20599
21159
|
ok: !failureReport2,
|
|
20600
21160
|
run,
|
|
20601
21161
|
output: enrichOutputJson(committedExportResult2),
|
|
21162
|
+
customer_db: enrichCustomerDbJson({
|
|
21163
|
+
status,
|
|
21164
|
+
client: client2,
|
|
21165
|
+
outputPath: enrichIssueFollowUpOutputPath ?? committedExportResult2?.path ?? outputPath
|
|
21166
|
+
}),
|
|
20602
21167
|
...enrichReportJson(failureReport2)
|
|
20603
21168
|
});
|
|
20604
21169
|
if (failureReport2) {
|
|
@@ -21499,72 +22064,494 @@ Examples:
|
|
|
21499
22064
|
}
|
|
21500
22065
|
|
|
21501
22066
|
// src/cli/commands/monitors.ts
|
|
22067
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
22068
|
+
import { createInterface } from "readline/promises";
|
|
21502
22069
|
var FORBIDDEN_AS_API_ERROR = { forbiddenAsApiError: true };
|
|
22070
|
+
var JSON_OPTION_DESCRIPTION = "Emit JSON output. Also automatic when stdout is piped";
|
|
22071
|
+
function withJsonOption(command) {
|
|
22072
|
+
return command.option("--json", JSON_OPTION_DESCRIPTION);
|
|
22073
|
+
}
|
|
22074
|
+
var COMPACT_OPTION_DESCRIPTION = "Ask the server for high-signal fields only (smaller output for agent loops)";
|
|
21503
22075
|
function buildHttpClient() {
|
|
21504
22076
|
return new HttpClient(resolveConfig());
|
|
21505
22077
|
}
|
|
21506
|
-
|
|
21507
|
-
|
|
21508
|
-
|
|
21509
|
-
|
|
21510
|
-
|
|
21511
|
-
throw new Error(
|
|
21512
|
-
`${flag} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
|
|
21513
|
-
);
|
|
22078
|
+
var MonitorsUsageError = class extends Error {
|
|
22079
|
+
code = "MONITORS_USAGE_ERROR";
|
|
22080
|
+
constructor(message) {
|
|
22081
|
+
super(message);
|
|
22082
|
+
this.name = "MonitorsUsageError";
|
|
21514
22083
|
}
|
|
21515
|
-
|
|
21516
|
-
|
|
22084
|
+
};
|
|
22085
|
+
var MonitorDryRunUnsupportedError = class extends Error {
|
|
22086
|
+
code = "MONITOR_DRY_RUN_UNSUPPORTED";
|
|
22087
|
+
constructor(message) {
|
|
22088
|
+
super(message);
|
|
22089
|
+
this.name = "MonitorDryRunUnsupportedError";
|
|
21517
22090
|
}
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
22091
|
+
};
|
|
22092
|
+
function monitorsErrorExitCode(error) {
|
|
22093
|
+
if (error instanceof MonitorsUsageError) return 2;
|
|
22094
|
+
if (error instanceof AuthError) return 3;
|
|
22095
|
+
if (error instanceof DeeplineError) {
|
|
22096
|
+
const status = error.statusCode;
|
|
22097
|
+
if (status === 401 || status === 403) return 3;
|
|
22098
|
+
if (status === 404) return 4;
|
|
22099
|
+
if (status === 400 || status === 422) return 7;
|
|
22100
|
+
return 5;
|
|
22101
|
+
}
|
|
22102
|
+
return 5;
|
|
21522
22103
|
}
|
|
21523
|
-
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
if (
|
|
21528
|
-
if (
|
|
21529
|
-
|
|
21530
|
-
const query = params.toString();
|
|
21531
|
-
const payload = await http.request(
|
|
21532
|
-
`/api/v2/monitors/tools${query ? `?${query}` : ""}`,
|
|
21533
|
-
{ method: "GET", ...FORBIDDEN_AS_API_ERROR }
|
|
21534
|
-
);
|
|
21535
|
-
printCommandEnvelope(payload, { json: options.json });
|
|
22104
|
+
function monitorsFailureNextCommand(error, exitCode) {
|
|
22105
|
+
if (error instanceof DeeplineError && error.code === "monitor_access_required") {
|
|
22106
|
+
return "deepline monitors status";
|
|
22107
|
+
}
|
|
22108
|
+
if (exitCode === 3) return "deepline auth status --json";
|
|
22109
|
+
if (exitCode === 4) return "deepline monitors list --status all --json";
|
|
22110
|
+
return void 0;
|
|
21536
22111
|
}
|
|
21537
|
-
|
|
21538
|
-
|
|
21539
|
-
const
|
|
22112
|
+
function readValidationIssues(error) {
|
|
22113
|
+
if (!(error instanceof DeeplineError)) return [];
|
|
22114
|
+
const response = asRecord(asRecord(error.details)?.response);
|
|
22115
|
+
const issues = Array.isArray(response?.issues) ? response.issues : [];
|
|
22116
|
+
return issues.flatMap((raw) => {
|
|
22117
|
+
const issue = asRecord(raw);
|
|
22118
|
+
if (!issue) return [];
|
|
22119
|
+
return [
|
|
22120
|
+
{
|
|
22121
|
+
...asString(issue.path) ? { path: asString(issue.path) } : {},
|
|
22122
|
+
...asString(issue.message) ? { message: asString(issue.message) } : {}
|
|
22123
|
+
}
|
|
22124
|
+
];
|
|
22125
|
+
});
|
|
22126
|
+
}
|
|
22127
|
+
function reportMonitorsFailure(error) {
|
|
22128
|
+
const exitCode = monitorsErrorExitCode(error);
|
|
22129
|
+
const next = monitorsFailureNextCommand(error, exitCode);
|
|
22130
|
+
const wantsJson = shouldEmitJson(process.argv.includes("--json"));
|
|
22131
|
+
if (wantsJson) {
|
|
22132
|
+
const payload = errorToJsonPayload(error);
|
|
22133
|
+
printJson({
|
|
22134
|
+
ok: false,
|
|
22135
|
+
exitCode,
|
|
22136
|
+
...next ? { next } : {},
|
|
22137
|
+
error: payload.error
|
|
22138
|
+
});
|
|
22139
|
+
} else {
|
|
22140
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22141
|
+
process.stderr.write(`Error: ${message}
|
|
22142
|
+
`);
|
|
22143
|
+
for (const issue of readValidationIssues(error)) {
|
|
22144
|
+
process.stderr.write(
|
|
22145
|
+
` - ${issue.path ? `${issue.path}: ` : ""}${issue.message ?? ""}
|
|
22146
|
+
`
|
|
22147
|
+
);
|
|
22148
|
+
}
|
|
22149
|
+
if (next) process.stderr.write(`Next: ${next}
|
|
22150
|
+
`);
|
|
22151
|
+
}
|
|
22152
|
+
process.exitCode = exitCode;
|
|
22153
|
+
}
|
|
22154
|
+
function monitorsAction(handler) {
|
|
22155
|
+
return async (...args) => {
|
|
22156
|
+
try {
|
|
22157
|
+
await handler(...args);
|
|
22158
|
+
} catch (error) {
|
|
22159
|
+
reportMonitorsFailure(error);
|
|
22160
|
+
}
|
|
22161
|
+
};
|
|
22162
|
+
}
|
|
22163
|
+
function parseJsonObjectArg(raw, argLabel) {
|
|
22164
|
+
let parsed;
|
|
22165
|
+
try {
|
|
22166
|
+
parsed = JSON.parse(raw);
|
|
22167
|
+
} catch (error) {
|
|
22168
|
+
throw new MonitorsUsageError(
|
|
22169
|
+
`${argLabel} must be a JSON object. ${error instanceof Error ? error.message : String(error)}`
|
|
22170
|
+
);
|
|
22171
|
+
}
|
|
22172
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
22173
|
+
throw new MonitorsUsageError(`${argLabel} must be a JSON object.`);
|
|
22174
|
+
}
|
|
22175
|
+
return parsed;
|
|
22176
|
+
}
|
|
22177
|
+
function resolveMonitorJsonBody(input2) {
|
|
22178
|
+
const readFile3 = input2.readFile ?? ((path) => readFileSync9(path, "utf-8"));
|
|
22179
|
+
const readStdin = input2.readStdin ?? (() => readFileSync9(0, "utf-8"));
|
|
22180
|
+
if (input2.positional !== void 0 && input2.file !== void 0) {
|
|
22181
|
+
throw new MonitorsUsageError(
|
|
22182
|
+
`Pass exactly one source for ${input2.argLabel}: the positional JSON or --file, not both.`
|
|
22183
|
+
);
|
|
22184
|
+
}
|
|
22185
|
+
if (input2.positional !== void 0) {
|
|
22186
|
+
return parseJsonObjectArg(input2.positional, input2.argLabel);
|
|
22187
|
+
}
|
|
22188
|
+
if (input2.file !== void 0) {
|
|
22189
|
+
if (input2.file === "-") {
|
|
22190
|
+
return parseJsonObjectArg(readStdin(), `${input2.argLabel} (stdin)`);
|
|
22191
|
+
}
|
|
22192
|
+
let raw;
|
|
22193
|
+
try {
|
|
22194
|
+
raw = readFile3(input2.file);
|
|
22195
|
+
} catch (error) {
|
|
22196
|
+
throw new MonitorsUsageError(
|
|
22197
|
+
`Could not read --file ${input2.file}: ${error instanceof Error ? error.message : String(error)}`
|
|
22198
|
+
);
|
|
22199
|
+
}
|
|
22200
|
+
return parseJsonObjectArg(raw, `${input2.argLabel} (--file ${input2.file})`);
|
|
22201
|
+
}
|
|
22202
|
+
throw new MonitorsUsageError(
|
|
22203
|
+
`${input2.command} needs ${input2.argLabel} (a JSON object). Pass it positionally:
|
|
22204
|
+
${input2.command} '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22205
|
+
or from a file / stdin:
|
|
22206
|
+
${input2.command} --file monitor.json
|
|
22207
|
+
cat monitor.json | ${input2.command} --file -`
|
|
22208
|
+
);
|
|
22209
|
+
}
|
|
22210
|
+
function encodeKey(key) {
|
|
22211
|
+
return encodeURIComponent(key);
|
|
22212
|
+
}
|
|
22213
|
+
function asRecord(value) {
|
|
22214
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22215
|
+
}
|
|
22216
|
+
function asString(value) {
|
|
22217
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
22218
|
+
}
|
|
22219
|
+
function asFiniteNumber(value) {
|
|
22220
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
22221
|
+
}
|
|
22222
|
+
function yesNo(value) {
|
|
22223
|
+
if (value === true) return "yes";
|
|
22224
|
+
if (value === false) return "no";
|
|
22225
|
+
return "unknown";
|
|
22226
|
+
}
|
|
22227
|
+
function readDeployOutputContract(payload) {
|
|
22228
|
+
const contract = asRecord(payload.output_contract);
|
|
22229
|
+
if (!contract) return { streams: [] };
|
|
22230
|
+
const rawOutputs = Array.isArray(contract.outputs) ? contract.outputs : [];
|
|
22231
|
+
const streams = rawOutputs.flatMap((raw) => {
|
|
22232
|
+
const output2 = asRecord(raw);
|
|
22233
|
+
const stream = output2 ? asString(output2.stream) : void 0;
|
|
22234
|
+
const table = output2 ? asString(output2.table) : void 0;
|
|
22235
|
+
if (!output2 || !stream || !table) return [];
|
|
22236
|
+
const columns = Array.isArray(output2.columns) ? output2.columns.flatMap((rawColumn) => {
|
|
22237
|
+
const column = asRecord(rawColumn);
|
|
22238
|
+
const name = column ? asString(column.name) : void 0;
|
|
22239
|
+
return name ? [name] : [];
|
|
22240
|
+
}) : [];
|
|
22241
|
+
return [
|
|
22242
|
+
{
|
|
22243
|
+
stream,
|
|
22244
|
+
table,
|
|
22245
|
+
columns,
|
|
22246
|
+
isEvent: output2.is_event_stream === true,
|
|
22247
|
+
matchesPayload: output2.matches_payload === true
|
|
22248
|
+
}
|
|
22249
|
+
];
|
|
22250
|
+
});
|
|
22251
|
+
return { tool: asString(contract.tool), streams };
|
|
22252
|
+
}
|
|
22253
|
+
function renderMonitorDeployCompletion(payload) {
|
|
22254
|
+
const monitor = asRecord(payload.monitor);
|
|
22255
|
+
const key = monitor ? asString(monitor.key) : void 0;
|
|
22256
|
+
const { tool, streams } = readDeployOutputContract(payload);
|
|
22257
|
+
if (!key || streams.length === 0) return void 0;
|
|
22258
|
+
const toolId = tool ?? (monitor ? asString(monitor.tool) : void 0) ?? "<tool>";
|
|
22259
|
+
const name = monitor ? asString(monitor.name) : void 0;
|
|
22260
|
+
const status = monitor ? asString(monitor.status) : void 0;
|
|
22261
|
+
const eventStreams = streams.filter((stream) => stream.isEvent);
|
|
22262
|
+
const matched = eventStreams.filter((stream) => stream.matchesPayload);
|
|
22263
|
+
const shown = matched.length ? matched : eventStreams.length ? eventStreams : streams;
|
|
22264
|
+
const primary = shown[0];
|
|
22265
|
+
const lines = [
|
|
22266
|
+
`\u2713 Deployed monitor "${key}"${name ? ` (${name})` : ""} \u2014 tool ${toolId}${status ? `, status ${status}` : ""}`,
|
|
22267
|
+
"",
|
|
22268
|
+
"Output \u2192 Customer DB:"
|
|
22269
|
+
];
|
|
22270
|
+
for (const stream of shown) {
|
|
22271
|
+
lines.push(` ${stream.table} (stream: ${stream.stream})`);
|
|
22272
|
+
lines.push(
|
|
22273
|
+
` columns: ${stream.columns.length ? stream.columns.join(", ") : "(promoted dynamically as events arrive)"}`
|
|
22274
|
+
);
|
|
22275
|
+
}
|
|
22276
|
+
lines.push(
|
|
22277
|
+
"",
|
|
22278
|
+
"This monitor streams new rows into your Customer DB \u2014 there is no manual run.",
|
|
22279
|
+
"Next:",
|
|
22280
|
+
" \u2022 Query the table above directly, or",
|
|
22281
|
+
" \u2022 Run a play on each new row (third arg to definePlay in your .play.ts):",
|
|
22282
|
+
` sqlListeners: [{ id: '${primary.stream}', tool: '${toolId}', stream: '${primary.stream}', operations: ['INSERT'] }]`,
|
|
22283
|
+
" The changed row arrives to your handler as the sqlListener event's `after`.",
|
|
22284
|
+
"",
|
|
22285
|
+
"Reuse: many plays can bind to this one stream \u2014 you do NOT need a separate",
|
|
22286
|
+
"monitor per play. Before deploying another monitor on this tool, run",
|
|
22287
|
+
"`deepline monitors list` and reuse an existing one that covers your scope."
|
|
22288
|
+
);
|
|
22289
|
+
return `${lines.join("\n")}
|
|
22290
|
+
`;
|
|
22291
|
+
}
|
|
22292
|
+
function renderMonitorDeployPlan(payload) {
|
|
22293
|
+
const valid = payload.valid !== false;
|
|
22294
|
+
const lines = [
|
|
22295
|
+
"DRY RUN \u2014 nothing was deployed.",
|
|
22296
|
+
valid ? "Definition: valid" : "Definition: INVALID"
|
|
22297
|
+
];
|
|
22298
|
+
if (!valid) {
|
|
22299
|
+
const issues = Array.isArray(payload.issues) ? payload.issues : [];
|
|
22300
|
+
for (const raw of issues) {
|
|
22301
|
+
const issue = asRecord(raw);
|
|
22302
|
+
const path = issue ? asString(issue.path) : void 0;
|
|
22303
|
+
const message = issue ? asString(issue.message) : void 0;
|
|
22304
|
+
if (message) lines.push(` - ${path ? `${path}: ` : ""}${message}`);
|
|
22305
|
+
}
|
|
22306
|
+
}
|
|
22307
|
+
const estimate = asRecord(payload.deploy_cost_estimate);
|
|
22308
|
+
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
22309
|
+
if (credits !== void 0) {
|
|
22310
|
+
const note = estimate ? asString(estimate.note) : void 0;
|
|
22311
|
+
lines.push(
|
|
22312
|
+
`Deploy cost: would cost ${credits} Deepline credits${note ? ` \u2014 ${note}` : ""}.`
|
|
22313
|
+
);
|
|
22314
|
+
} else {
|
|
22315
|
+
lines.push(
|
|
22316
|
+
"Deploy cost: estimate unavailable from this server (validation only)."
|
|
22317
|
+
);
|
|
22318
|
+
}
|
|
22319
|
+
const candidates = Array.isArray(payload.reuse_candidates) ? payload.reuse_candidates : [];
|
|
22320
|
+
const candidateLines = candidates.flatMap((raw) => {
|
|
22321
|
+
const candidate = asRecord(raw);
|
|
22322
|
+
const key = candidate ? asString(candidate.key) : void 0;
|
|
22323
|
+
if (!candidate || !key) return [];
|
|
22324
|
+
const name = asString(candidate.name);
|
|
22325
|
+
const status = asString(candidate.status);
|
|
22326
|
+
const covers = asString(candidate.covers);
|
|
22327
|
+
return [
|
|
22328
|
+
` ${key}${name ? ` (${name})` : ""}${status ? ` \u2014 ${status}` : ""}${covers ? `; covers ${covers}` : ""}`
|
|
22329
|
+
];
|
|
22330
|
+
});
|
|
22331
|
+
if (candidateLines.length > 0) {
|
|
22332
|
+
lines.push(
|
|
22333
|
+
"",
|
|
22334
|
+
"You may already have a monitor covering this \u2014 check before deploying:",
|
|
22335
|
+
...candidateLines,
|
|
22336
|
+
" Inspect: deepline monitors get <key> --json"
|
|
22337
|
+
);
|
|
22338
|
+
}
|
|
22339
|
+
lines.push(
|
|
22340
|
+
"",
|
|
22341
|
+
valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
|
|
22342
|
+
);
|
|
22343
|
+
return `${lines.join("\n")}
|
|
22344
|
+
`;
|
|
22345
|
+
}
|
|
22346
|
+
function renderMonitorDeletePlan(payload, fallbackKey) {
|
|
22347
|
+
const plan = asRecord(payload.plan);
|
|
22348
|
+
const key = (plan ? asString(plan.monitor_key) : void 0) ?? fallbackKey;
|
|
22349
|
+
const lines = [
|
|
22350
|
+
"DRY RUN \u2014 nothing was deleted.",
|
|
22351
|
+
`Delete plan for monitor "${key}":`,
|
|
22352
|
+
` delete Deepline record: ${yesNo(plan?.would_delete_record)}`,
|
|
22353
|
+
` deprovision upstream provider resource: ${yesNo(plan?.would_deprovision_upstream)}`,
|
|
22354
|
+
"",
|
|
22355
|
+
`Delete for real: deepline monitors delete ${key} --yes`
|
|
22356
|
+
];
|
|
22357
|
+
return `${lines.join("\n")}
|
|
22358
|
+
`;
|
|
22359
|
+
}
|
|
22360
|
+
function renderMonitorReactivatePlan(payload, key) {
|
|
22361
|
+
const estimate = asRecord(payload.cost_estimate);
|
|
22362
|
+
const credits = estimate ? asFiniteNumber(estimate.credits) : void 0;
|
|
22363
|
+
const lines = [
|
|
22364
|
+
"DRY RUN \u2014 nothing was reactivated.",
|
|
22365
|
+
credits !== void 0 ? `Reactivate cost: would cost ${credits} Deepline credits.` : "Reactivate cost: estimate unavailable from this server.",
|
|
22366
|
+
"",
|
|
22367
|
+
`Reactivate for real: deepline monitors reactivate ${key}`
|
|
22368
|
+
];
|
|
22369
|
+
return `${lines.join("\n")}
|
|
22370
|
+
`;
|
|
22371
|
+
}
|
|
22372
|
+
function assertMonitorDryRunAcknowledged(payload, context) {
|
|
22373
|
+
if (payload.dry_run === true) return;
|
|
22374
|
+
throw new MonitorDryRunUnsupportedError(
|
|
22375
|
+
`${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}.`
|
|
22376
|
+
);
|
|
22377
|
+
}
|
|
22378
|
+
function monitorDeleteRequiresYesError(key, options = {}) {
|
|
22379
|
+
const flags = options.localOnly ? " --local-only" : "";
|
|
22380
|
+
return new MonitorsUsageError(
|
|
22381
|
+
`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:
|
|
22382
|
+
deepline monitors delete ${key}${flags} --yes
|
|
22383
|
+
Preview the plan first with:
|
|
22384
|
+
deepline monitors delete ${key}${flags} --dry-run`
|
|
22385
|
+
);
|
|
22386
|
+
}
|
|
22387
|
+
async function handleMonitorsStatus(options) {
|
|
22388
|
+
const http = buildHttpClient();
|
|
21540
22389
|
const payload = await http.request(
|
|
21541
|
-
"/api/v2/monitors/
|
|
21542
|
-
{ method: "
|
|
22390
|
+
"/api/v2/monitors/access",
|
|
22391
|
+
{ method: "GET" }
|
|
22392
|
+
);
|
|
22393
|
+
const hasAccess = payload.has_access === true;
|
|
22394
|
+
const reason = typeof payload.reason === "string" && payload.reason.trim() ? payload.reason.trim() : void 0;
|
|
22395
|
+
const text = hasAccess ? `\u2713 You have access to Deepline Monitors${reason ? `
|
|
22396
|
+
${reason}` : ""}
|
|
22397
|
+
` : `\u2717 No access to Deepline Monitors${reason ? ` \u2014 ${reason}` : ""}
|
|
22398
|
+
`;
|
|
22399
|
+
printCommandEnvelope(
|
|
22400
|
+
{ has_access: hasAccess, ...reason ? { reason } : {} },
|
|
22401
|
+
{ json: options.json, text }
|
|
21543
22402
|
);
|
|
21544
|
-
|
|
22403
|
+
if (!hasAccess) {
|
|
22404
|
+
process.exitCode = 1;
|
|
22405
|
+
}
|
|
21545
22406
|
}
|
|
21546
|
-
|
|
22407
|
+
function renderAvailableToolsText(payload) {
|
|
22408
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : null;
|
|
22409
|
+
if (!tools) return void 0;
|
|
22410
|
+
const returned = asFiniteNumber(payload.returned) ?? tools.length;
|
|
22411
|
+
const total = asFiniteNumber(payload.total);
|
|
22412
|
+
const lines = [
|
|
22413
|
+
total !== void 0 ? `Monitor tools you can deploy (${returned} of ${total}):` : "Monitor tools you can deploy:"
|
|
22414
|
+
];
|
|
22415
|
+
for (const raw of tools) {
|
|
22416
|
+
const entry = asRecord(raw);
|
|
22417
|
+
const id = entry ? asString(entry.tool) : void 0;
|
|
22418
|
+
if (!entry || !id) continue;
|
|
22419
|
+
const name = asString(entry.name) ?? asString(entry.display_name);
|
|
22420
|
+
const deployedCount = asFiniteNumber(entry.deployed_count);
|
|
22421
|
+
lines.push(
|
|
22422
|
+
` ${id}${name ? ` \u2014 ${name}` : ""}${deployedCount !== void 0 ? ` (deployed: ${deployedCount})` : ""}`
|
|
22423
|
+
);
|
|
22424
|
+
}
|
|
22425
|
+
if (payload.is_truncated === true) {
|
|
22426
|
+
lines.push("List truncated; raise --limit to see more.");
|
|
22427
|
+
}
|
|
22428
|
+
lines.push(
|
|
22429
|
+
"",
|
|
22430
|
+
"Describe one (payload schema + output streams): deepline monitors available <tool-id> --json"
|
|
22431
|
+
);
|
|
22432
|
+
return `${lines.join("\n")}
|
|
22433
|
+
`;
|
|
22434
|
+
}
|
|
22435
|
+
async function handleMonitorsAvailable(toolId, options) {
|
|
22436
|
+
if (toolId !== void 0 && options.tool !== void 0) {
|
|
22437
|
+
if (toolId !== options.tool) {
|
|
22438
|
+
throw new MonitorsUsageError(
|
|
22439
|
+
`Pass the tool id once: got positional "${toolId}" and --tool "${options.tool}". Use: deepline monitors available ${toolId}`
|
|
22440
|
+
);
|
|
22441
|
+
}
|
|
22442
|
+
}
|
|
22443
|
+
const tool = toolId ?? options.tool;
|
|
21547
22444
|
const http = buildHttpClient();
|
|
21548
|
-
const
|
|
22445
|
+
const params = new URLSearchParams();
|
|
22446
|
+
if (options.provider) params.set("provider", options.provider);
|
|
22447
|
+
if (tool) params.set("tool", tool);
|
|
22448
|
+
if (options.search) params.set("search", options.search);
|
|
22449
|
+
if (options.limit) params.set("limit", options.limit);
|
|
22450
|
+
const compactList = !tool && !options.full;
|
|
22451
|
+
if (compactList || options.compact) params.set("compact", "true");
|
|
22452
|
+
const query = params.toString();
|
|
21549
22453
|
const payload = await http.request(
|
|
21550
|
-
|
|
21551
|
-
{ method: "
|
|
22454
|
+
`/api/v2/monitors/tools${query ? `?${query}` : ""}`,
|
|
22455
|
+
{ method: "GET", ...FORBIDDEN_AS_API_ERROR }
|
|
21552
22456
|
);
|
|
21553
|
-
printCommandEnvelope(payload, {
|
|
22457
|
+
printCommandEnvelope(payload, {
|
|
22458
|
+
json: options.json,
|
|
22459
|
+
// Human list view shows id + name + deployed_count ("deployed: N") so
|
|
22460
|
+
// can-deploy vs already-deployed is visible in one view. Describing a
|
|
22461
|
+
// single tool keeps the full JSON contract (payload schema, streams).
|
|
22462
|
+
text: tool ? void 0 : renderAvailableToolsText(payload)
|
|
22463
|
+
});
|
|
22464
|
+
}
|
|
22465
|
+
function renderDeployedListText(payload, requestedStatus) {
|
|
22466
|
+
const monitors = Array.isArray(payload.monitors) ? payload.monitors : null;
|
|
22467
|
+
if (!monitors) return void 0;
|
|
22468
|
+
const lines = [
|
|
22469
|
+
monitors.length === 0 ? "No deployed monitors matched." : `Deployed monitors (${monitors.length}):`
|
|
22470
|
+
];
|
|
22471
|
+
for (const raw of monitors) {
|
|
22472
|
+
const entry = asRecord(raw);
|
|
22473
|
+
const key = entry ? asString(entry.key) ?? asString(entry.monitor_key) : void 0;
|
|
22474
|
+
if (!entry || !key) continue;
|
|
22475
|
+
const status = asString(entry.status);
|
|
22476
|
+
const tool = asString(entry.tool);
|
|
22477
|
+
const name = asString(entry.name);
|
|
22478
|
+
lines.push(
|
|
22479
|
+
` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
|
|
22480
|
+
);
|
|
22481
|
+
}
|
|
22482
|
+
const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
|
|
22483
|
+
lines.push(
|
|
22484
|
+
`Status filter: ${applied}${requestedStatus === void 0 && applied === "active" ? " (default)" : ""} \u2014 use --status all to include disabled monitors.`
|
|
22485
|
+
);
|
|
22486
|
+
if (monitors.length > 0) {
|
|
22487
|
+
lines.push("", "Inspect one: deepline monitors get <key> --json");
|
|
22488
|
+
}
|
|
22489
|
+
return `${lines.join("\n")}
|
|
22490
|
+
`;
|
|
21554
22491
|
}
|
|
21555
|
-
async function
|
|
22492
|
+
async function handleMonitorsList(options) {
|
|
21556
22493
|
const http = buildHttpClient();
|
|
21557
22494
|
const params = new URLSearchParams();
|
|
21558
22495
|
if (options.status) params.set("status", options.status);
|
|
21559
22496
|
if (options.limit) params.set("limit", options.limit);
|
|
22497
|
+
if (options.compact) params.set("compact", "true");
|
|
21560
22498
|
const query = params.toString();
|
|
21561
22499
|
const payload = await http.request(
|
|
21562
22500
|
`/api/v2/monitors/deployed${query ? `?${query}` : ""}`,
|
|
21563
22501
|
{ method: "GET", ...FORBIDDEN_AS_API_ERROR }
|
|
21564
22502
|
);
|
|
22503
|
+
printCommandEnvelope(payload, {
|
|
22504
|
+
json: options.json,
|
|
22505
|
+
text: renderDeployedListText(payload, options.status)
|
|
22506
|
+
});
|
|
22507
|
+
}
|
|
22508
|
+
async function handleMonitorsCheck(definition, options) {
|
|
22509
|
+
const http = buildHttpClient();
|
|
22510
|
+
const body = resolveMonitorJsonBody({
|
|
22511
|
+
positional: definition,
|
|
22512
|
+
file: options.file,
|
|
22513
|
+
argLabel: "<definition>",
|
|
22514
|
+
command: "deepline monitors check"
|
|
22515
|
+
});
|
|
22516
|
+
const payload = await http.request(
|
|
22517
|
+
"/api/v2/monitors/check",
|
|
22518
|
+
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
22519
|
+
);
|
|
21565
22520
|
printCommandEnvelope(payload, { json: options.json });
|
|
21566
22521
|
}
|
|
21567
|
-
async function
|
|
22522
|
+
async function handleMonitorsDeploy(definition, options) {
|
|
22523
|
+
const http = buildHttpClient();
|
|
22524
|
+
const body = resolveMonitorJsonBody({
|
|
22525
|
+
positional: definition,
|
|
22526
|
+
file: options.file,
|
|
22527
|
+
argLabel: "<definition>",
|
|
22528
|
+
command: "deepline monitors deploy"
|
|
22529
|
+
});
|
|
22530
|
+
if (options.dryRun) {
|
|
22531
|
+
const payload2 = await http.request(
|
|
22532
|
+
"/api/v2/monitors/check",
|
|
22533
|
+
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
22534
|
+
);
|
|
22535
|
+
const valid = payload2.valid !== false;
|
|
22536
|
+
printCommandEnvelope(
|
|
22537
|
+
{ dry_run: true, ...payload2 },
|
|
22538
|
+
{ json: options.json, text: renderMonitorDeployPlan(payload2) }
|
|
22539
|
+
);
|
|
22540
|
+
if (!valid) {
|
|
22541
|
+
process.exitCode = 7;
|
|
22542
|
+
}
|
|
22543
|
+
return;
|
|
22544
|
+
}
|
|
22545
|
+
const payload = await http.request(
|
|
22546
|
+
"/api/v2/monitors/deploy",
|
|
22547
|
+
{ method: "POST", body, ...FORBIDDEN_AS_API_ERROR }
|
|
22548
|
+
);
|
|
22549
|
+
printCommandEnvelope(payload, {
|
|
22550
|
+
json: options.json,
|
|
22551
|
+
text: renderMonitorDeployCompletion(payload)
|
|
22552
|
+
});
|
|
22553
|
+
}
|
|
22554
|
+
async function handleMonitorsGet(key, options) {
|
|
21568
22555
|
const http = buildHttpClient();
|
|
21569
22556
|
const payload = await http.request(
|
|
21570
22557
|
`/api/v2/monitors/deployed/${encodeKey(key)}`,
|
|
@@ -21572,10 +22559,58 @@ async function handleDeployedGet(key, options) {
|
|
|
21572
22559
|
);
|
|
21573
22560
|
printCommandEnvelope(payload, { json: options.json });
|
|
21574
22561
|
}
|
|
21575
|
-
async function
|
|
22562
|
+
async function confirmMonitorDelete(key, options) {
|
|
22563
|
+
const rl = createInterface({
|
|
22564
|
+
input: process.stdin,
|
|
22565
|
+
output: process.stderr
|
|
22566
|
+
});
|
|
22567
|
+
try {
|
|
22568
|
+
const consequence = options.localOnly ? "This removes the Deepline record only (the upstream provider resource is left in place)." : "This deprovisions the upstream provider resource.";
|
|
22569
|
+
const answer = await rl.question(
|
|
22570
|
+
`Delete monitor "${key}"? ${consequence} [y/N] `
|
|
22571
|
+
);
|
|
22572
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
22573
|
+
} finally {
|
|
22574
|
+
rl.close();
|
|
22575
|
+
}
|
|
22576
|
+
}
|
|
22577
|
+
async function handleMonitorsDelete(key, options) {
|
|
21576
22578
|
const http = buildHttpClient();
|
|
21577
22579
|
const params = new URLSearchParams();
|
|
21578
22580
|
if (options.localOnly) params.set("local_only", "true");
|
|
22581
|
+
if (options.dryRun) {
|
|
22582
|
+
params.set("dry_run", "true");
|
|
22583
|
+
const payload2 = await http.request(
|
|
22584
|
+
`/api/v2/monitors/deployed/${encodeKey(key)}?${params.toString()}`,
|
|
22585
|
+
{ method: "DELETE", ...FORBIDDEN_AS_API_ERROR }
|
|
22586
|
+
);
|
|
22587
|
+
assertMonitorDryRunAcknowledged(payload2, {
|
|
22588
|
+
command: "deepline monitors delete",
|
|
22589
|
+
mutation: "delete"
|
|
22590
|
+
});
|
|
22591
|
+
printCommandEnvelope(payload2, {
|
|
22592
|
+
json: options.json,
|
|
22593
|
+
text: renderMonitorDeletePlan(payload2, key)
|
|
22594
|
+
});
|
|
22595
|
+
return;
|
|
22596
|
+
}
|
|
22597
|
+
if (!options.yes) {
|
|
22598
|
+
const interactive = process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
22599
|
+
if (!interactive) {
|
|
22600
|
+
throw monitorDeleteRequiresYesError(key, {
|
|
22601
|
+
localOnly: options.localOnly
|
|
22602
|
+
});
|
|
22603
|
+
}
|
|
22604
|
+
const confirmed = await confirmMonitorDelete(key, {
|
|
22605
|
+
localOnly: options.localOnly
|
|
22606
|
+
});
|
|
22607
|
+
if (!confirmed) {
|
|
22608
|
+
process.stderr.write(`Aborted. Monitor "${key}" was not deleted.
|
|
22609
|
+
`);
|
|
22610
|
+
process.exitCode = 2;
|
|
22611
|
+
return;
|
|
22612
|
+
}
|
|
22613
|
+
}
|
|
21579
22614
|
const query = params.toString();
|
|
21580
22615
|
const payload = await http.request(
|
|
21581
22616
|
`/api/v2/monitors/deployed/${encodeKey(key)}${query ? `?${query}` : ""}`,
|
|
@@ -21583,17 +22618,37 @@ async function handleDeployedDelete(key, options) {
|
|
|
21583
22618
|
);
|
|
21584
22619
|
printCommandEnvelope(payload, { json: options.json });
|
|
21585
22620
|
}
|
|
21586
|
-
async function
|
|
22621
|
+
async function handleMonitorsUpdate(key, patch, options) {
|
|
21587
22622
|
const http = buildHttpClient();
|
|
21588
|
-
const body =
|
|
22623
|
+
const body = resolveMonitorJsonBody({
|
|
22624
|
+
positional: patch,
|
|
22625
|
+
file: options.file,
|
|
22626
|
+
argLabel: "<patch>",
|
|
22627
|
+
command: `deepline monitors update ${key}`
|
|
22628
|
+
});
|
|
21589
22629
|
const payload = await http.request(
|
|
21590
22630
|
`/api/v2/monitors/deployed/${encodeKey(key)}`,
|
|
21591
22631
|
{ method: "PATCH", body, ...FORBIDDEN_AS_API_ERROR }
|
|
21592
22632
|
);
|
|
21593
22633
|
printCommandEnvelope(payload, { json: options.json });
|
|
21594
22634
|
}
|
|
21595
|
-
async function
|
|
22635
|
+
async function handleMonitorsReactivate(key, options) {
|
|
21596
22636
|
const http = buildHttpClient();
|
|
22637
|
+
if (options.dryRun) {
|
|
22638
|
+
const payload2 = await http.request(
|
|
22639
|
+
`/api/v2/monitors/deployed/${encodeKey(key)}/reactivate?dry_run=true`,
|
|
22640
|
+
{ method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
|
|
22641
|
+
);
|
|
22642
|
+
assertMonitorDryRunAcknowledged(payload2, {
|
|
22643
|
+
command: "deepline monitors reactivate",
|
|
22644
|
+
mutation: "reactivate"
|
|
22645
|
+
});
|
|
22646
|
+
printCommandEnvelope(payload2, {
|
|
22647
|
+
json: options.json,
|
|
22648
|
+
text: renderMonitorReactivatePlan(payload2, key)
|
|
22649
|
+
});
|
|
22650
|
+
return;
|
|
22651
|
+
}
|
|
21597
22652
|
const payload = await http.request(
|
|
21598
22653
|
`/api/v2/monitors/deployed/${encodeKey(key)}/reactivate`,
|
|
21599
22654
|
{ method: "POST", body: {}, ...FORBIDDEN_AS_API_ERROR }
|
|
@@ -21601,116 +22656,240 @@ async function handleReactivate(key, options) {
|
|
|
21601
22656
|
printCommandEnvelope(payload, { json: options.json });
|
|
21602
22657
|
}
|
|
21603
22658
|
function registerMonitorsCommands(program) {
|
|
21604
|
-
const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").addHelpText(
|
|
22659
|
+
const monitors = program.command("monitors").description("Discover, deploy, and manage Deepline monitors.").showSuggestionAfterError(true).addHelpText(
|
|
21605
22660
|
"after",
|
|
21606
22661
|
`
|
|
21607
22662
|
Notes:
|
|
21608
|
-
|
|
21609
|
-
|
|
21610
|
-
|
|
22663
|
+
Deepline monitors are provider-backed signal feeds: a monitor writes provider
|
|
22664
|
+
events into a Customer DB table; a play reacts to each new row via a
|
|
22665
|
+
sqlListeners trigger \u2014 see \`deepline plays bootstrap monitor-triggered\`.
|
|
22666
|
+
Access is granted by a Deepline admin via Admin -> Rollouts; until then these
|
|
22667
|
+
commands return a clear monitor_access_required error.
|
|
22668
|
+
|
|
22669
|
+
Exit codes:
|
|
22670
|
+
0 success; 2 usage/local input; 3 auth or permission; 4 not found;
|
|
22671
|
+
5 server failure; 7 validation failed.
|
|
22672
|
+
\`monitors status\` exits 1 when you lack monitor access (documented contract).
|
|
21611
22673
|
|
|
21612
22674
|
Examples:
|
|
21613
|
-
deepline monitors
|
|
21614
|
-
deepline monitors
|
|
21615
|
-
deepline monitors
|
|
21616
|
-
deepline monitors
|
|
21617
|
-
deepline monitors
|
|
21618
|
-
deepline monitors
|
|
22675
|
+
deepline monitors status --json
|
|
22676
|
+
deepline monitors available --json # compact list by default
|
|
22677
|
+
deepline monitors available --full --json # complete catalog
|
|
22678
|
+
deepline monitors available theirstack.saved_search_webhook --json
|
|
22679
|
+
deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22680
|
+
deepline monitors deploy --dry-run --file monitor.json
|
|
22681
|
+
deepline monitors deploy --file monitor.json
|
|
22682
|
+
deepline monitors list --status all --json
|
|
22683
|
+
deepline monitors get my-monitor --json
|
|
22684
|
+
deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
|
|
22685
|
+
deepline monitors delete my-monitor --dry-run
|
|
22686
|
+
deepline monitors reactivate my-monitor --dry-run
|
|
21619
22687
|
`
|
|
21620
22688
|
);
|
|
21621
|
-
|
|
21622
|
-
"
|
|
21623
|
-
|
|
22689
|
+
withJsonOption(
|
|
22690
|
+
monitors.command("status").description("Check whether you have access to Deepline monitors.").addHelpText(
|
|
22691
|
+
"after",
|
|
22692
|
+
`
|
|
21624
22693
|
Notes:
|
|
21625
|
-
Read-only.
|
|
21626
|
-
|
|
22694
|
+
Read-only access check. Requires authentication but NOT monitor access, so it
|
|
22695
|
+
is safe to run first to confirm whether you can use the monitor commands. Exits
|
|
22696
|
+
0 when you have access and 1 when you do not, so agents can branch on it (this
|
|
22697
|
+
exit-1 denial contract predates the typed monitor exit codes and is kept).
|
|
21627
22698
|
|
|
21628
22699
|
Examples:
|
|
21629
|
-
deepline monitors
|
|
21630
|
-
deepline monitors
|
|
21631
|
-
deepline monitors tools --tool theirstack_jobs --json
|
|
22700
|
+
deepline monitors status
|
|
22701
|
+
deepline monitors status --json
|
|
21632
22702
|
`
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
22703
|
+
)
|
|
22704
|
+
).action(monitorsAction(handleMonitorsStatus));
|
|
22705
|
+
withJsonOption(
|
|
22706
|
+
monitors.command("available [tool-id]").alias("tools").description(
|
|
22707
|
+
"List the monitor types you can deploy, or describe one by tool id."
|
|
22708
|
+
).addHelpText(
|
|
22709
|
+
"after",
|
|
22710
|
+
`
|
|
21637
22711
|
Notes:
|
|
21638
|
-
Read-only
|
|
21639
|
-
|
|
22712
|
+
Read-only catalog of deployable monitor types. Pass a tool id positionally to
|
|
22713
|
+
describe one (payload schema + output streams). Filter the list with
|
|
22714
|
+
--provider, --search, or --limit. List entries include how many monitors you
|
|
22715
|
+
already have deployed on each tool ("deployed: N") when the server reports it.
|
|
22716
|
+
The list is compact by default (id + name + deployed count); pass --full to
|
|
22717
|
+
get the complete catalog (payload schemas + output streams for every tool).
|
|
22718
|
+
Describing a single tool by id always returns the full contract.
|
|
21640
22719
|
|
|
21641
22720
|
Examples:
|
|
21642
|
-
deepline monitors
|
|
22721
|
+
deepline monitors available
|
|
22722
|
+
deepline monitors available --full --json
|
|
22723
|
+
deepline monitors available --provider theirstack --json
|
|
22724
|
+
deepline monitors available theirstack.saved_search_webhook --json
|
|
22725
|
+
deepline monitors available --search jobs --json
|
|
21643
22726
|
`
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
22727
|
+
).option("--provider <provider>", "Filter by provider").option(
|
|
22728
|
+
"--tool <tool>",
|
|
22729
|
+
"Describe a single monitor tool by id (same as the positional tool-id)"
|
|
22730
|
+
).option("--search <query>", "Search monitor tools by text").option("--limit <n>", "Limit the number of monitor tools returned").option(
|
|
22731
|
+
"--full",
|
|
22732
|
+
"Return the complete monitor catalog (payload schemas + output streams). The list is compact by default."
|
|
22733
|
+
).option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22734
|
+
).action(monitorsAction(handleMonitorsAvailable));
|
|
22735
|
+
withJsonOption(
|
|
22736
|
+
monitors.command("list").description("List the monitors you have deployed.").addHelpText(
|
|
22737
|
+
"after",
|
|
22738
|
+
`
|
|
21648
22739
|
Notes:
|
|
21649
|
-
|
|
21650
|
-
|
|
22740
|
+
Read-only. --status filters by monitor status: active (default), disabled, or
|
|
22741
|
+
all. The output echoes the status filter that was applied. --compact returns
|
|
22742
|
+
high-signal fields only.
|
|
21651
22743
|
|
|
21652
22744
|
Examples:
|
|
21653
|
-
deepline monitors
|
|
22745
|
+
deepline monitors list
|
|
22746
|
+
deepline monitors list --status all --json
|
|
22747
|
+
deepline monitors list --compact --json
|
|
21654
22748
|
`
|
|
21655
|
-
|
|
21656
|
-
|
|
21657
|
-
|
|
21658
|
-
|
|
22749
|
+
).option(
|
|
22750
|
+
"--status <status>",
|
|
22751
|
+
"Filter by monitor status: active (default), disabled, or all"
|
|
22752
|
+
).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22753
|
+
).action(monitorsAction(handleMonitorsList));
|
|
22754
|
+
withJsonOption(
|
|
22755
|
+
monitors.command("get <key>").description("Show a single deployed monitor by its public key.").addHelpText(
|
|
22756
|
+
"after",
|
|
22757
|
+
`
|
|
21659
22758
|
Notes:
|
|
21660
|
-
|
|
22759
|
+
Read-only.
|
|
21661
22760
|
|
|
21662
22761
|
Examples:
|
|
21663
|
-
deepline monitors
|
|
22762
|
+
deepline monitors get my-monitor --json
|
|
21664
22763
|
`
|
|
21665
|
-
|
|
21666
|
-
|
|
21667
|
-
|
|
21668
|
-
|
|
22764
|
+
)
|
|
22765
|
+
).action(monitorsAction(handleMonitorsGet));
|
|
22766
|
+
withJsonOption(
|
|
22767
|
+
monitors.command("check [definition]").description("Validate a monitor definition without deploying it.").addHelpText(
|
|
22768
|
+
"after",
|
|
22769
|
+
`
|
|
21669
22770
|
Notes:
|
|
21670
|
-
|
|
21671
|
-
|
|
22771
|
+
Read-only validation. <definition> is a JSON object with key, tool, payload,
|
|
22772
|
+
and optional controls (Deepline lifecycle metadata, e.g.
|
|
22773
|
+
"controls":{"enabled":false}). Pass it positionally, via --file <path>, or
|
|
22774
|
+
from stdin with --file -. Does not deploy or spend credits.
|
|
21672
22775
|
|
|
21673
22776
|
Examples:
|
|
21674
|
-
deepline monitors
|
|
21675
|
-
deepline monitors
|
|
21676
|
-
deepline monitors
|
|
22777
|
+
deepline monitors check '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22778
|
+
deepline monitors check --file monitor.json
|
|
22779
|
+
cat monitor.json | deepline monitors check --file -
|
|
21677
22780
|
`
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
22781
|
+
).option(
|
|
22782
|
+
"-f, --file <path>",
|
|
22783
|
+
"Read the definition JSON from a file, or - for stdin"
|
|
22784
|
+
)
|
|
22785
|
+
).action(monitorsAction(handleMonitorsCheck));
|
|
22786
|
+
withJsonOption(
|
|
22787
|
+
monitors.command("deploy [definition]").description("Deploy a monitor from a definition.").addHelpText(
|
|
22788
|
+
"after",
|
|
22789
|
+
`
|
|
21682
22790
|
Notes:
|
|
21683
|
-
|
|
22791
|
+
Mutates workspace state and may spend Deepline credits. <definition> is a JSON
|
|
22792
|
+
object with key, tool, payload, and optional controls (e.g.
|
|
22793
|
+
"controls":{"enabled":false}). Pass it positionally, via --file <path>, or
|
|
22794
|
+
from stdin with --file -.
|
|
22795
|
+
--dry-run validates the definition and shows the plan (deploy cost in Deepline
|
|
22796
|
+
credits when the server reports it, plus any existing monitors that may
|
|
22797
|
+
already cover this scope) WITHOUT deploying. Exits 0 when valid, 7 when not.
|
|
21684
22798
|
|
|
21685
22799
|
Examples:
|
|
21686
|
-
deepline monitors
|
|
22800
|
+
deepline monitors deploy '{"key":"my-monitor","tool":"theirstack.saved_search_webhook","payload":{}}'
|
|
22801
|
+
deepline monitors deploy --dry-run --file monitor.json
|
|
22802
|
+
deepline monitors deploy --file monitor.json
|
|
21687
22803
|
`
|
|
21688
|
-
|
|
21689
|
-
|
|
21690
|
-
|
|
21691
|
-
|
|
22804
|
+
).option(
|
|
22805
|
+
"-f, --file <path>",
|
|
22806
|
+
"Read the definition JSON from a file, or - for stdin"
|
|
22807
|
+
).option(
|
|
22808
|
+
"--dry-run",
|
|
22809
|
+
"Validate and show the deploy plan (cost, reuse candidates) without deploying"
|
|
22810
|
+
)
|
|
22811
|
+
).action(monitorsAction(handleMonitorsDeploy));
|
|
22812
|
+
withJsonOption(
|
|
22813
|
+
monitors.command("update <key> [patch]").description("Update a deployed monitor by its public key.").addHelpText(
|
|
22814
|
+
"after",
|
|
22815
|
+
`
|
|
21692
22816
|
Notes:
|
|
21693
|
-
Mutates workspace state. <patch> is a JSON object of fields to update.
|
|
22817
|
+
Mutates workspace state. <patch> is a JSON object of fields to update, e.g.
|
|
22818
|
+
'{"controls":{"enabled":false}}' to disable a monitor. Pass it positionally,
|
|
22819
|
+
via --file <path>, or from stdin with --file -.
|
|
21694
22820
|
|
|
21695
22821
|
Examples:
|
|
21696
|
-
deepline monitors
|
|
22822
|
+
deepline monitors update my-monitor '{"controls":{"enabled":false}}' --json
|
|
22823
|
+
deepline monitors update my-monitor --file patch.json
|
|
21697
22824
|
`
|
|
21698
|
-
|
|
21699
|
-
|
|
21700
|
-
|
|
21701
|
-
|
|
22825
|
+
).option(
|
|
22826
|
+
"-f, --file <path>",
|
|
22827
|
+
"Read the patch JSON from a file, or - for stdin"
|
|
22828
|
+
)
|
|
22829
|
+
).action(monitorsAction(handleMonitorsUpdate));
|
|
22830
|
+
withJsonOption(
|
|
22831
|
+
monitors.command("delete <key>").description("Delete a deployed monitor by its public key.").addHelpText(
|
|
22832
|
+
"after",
|
|
22833
|
+
`
|
|
21702
22834
|
Notes:
|
|
21703
|
-
|
|
21704
|
-
|
|
22835
|
+
DESTRUCTIVE. By default deprovisions the upstream provider resource; pass
|
|
22836
|
+
--local-only to remove only the Deepline-managed record.
|
|
22837
|
+
--dry-run shows the delete plan without deleting anything.
|
|
22838
|
+
Interactive terminals get a y/N confirmation; non-interactive runs (agents,
|
|
22839
|
+
scripts, pipes) must pass --yes.
|
|
21705
22840
|
|
|
21706
22841
|
Examples:
|
|
21707
|
-
deepline monitors
|
|
21708
|
-
deepline monitors
|
|
22842
|
+
deepline monitors delete my-monitor --dry-run
|
|
22843
|
+
deepline monitors delete my-monitor --yes --json
|
|
22844
|
+
deepline monitors delete my-monitor --local-only --yes --json
|
|
21709
22845
|
`
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
|
|
22846
|
+
).option(
|
|
22847
|
+
"--local-only",
|
|
22848
|
+
"Remove only the Deepline-managed record, leaving the upstream resource"
|
|
22849
|
+
).option("--dry-run", "Show the delete plan without deleting anything").option(
|
|
22850
|
+
"--yes",
|
|
22851
|
+
"Skip the confirmation prompt (required non-interactively)"
|
|
22852
|
+
)
|
|
22853
|
+
).action(monitorsAction(handleMonitorsDelete));
|
|
22854
|
+
withJsonOption(
|
|
22855
|
+
monitors.command("reactivate <key>").description("Reactivate a previously disabled deployed monitor.").addHelpText(
|
|
22856
|
+
"after",
|
|
22857
|
+
`
|
|
22858
|
+
Notes:
|
|
22859
|
+
Mutates workspace state and may spend Deepline credits.
|
|
22860
|
+
--dry-run shows the reactivation cost (in Deepline credits) without changing
|
|
22861
|
+
anything.
|
|
22862
|
+
|
|
22863
|
+
Examples:
|
|
22864
|
+
deepline monitors reactivate my-monitor --dry-run
|
|
22865
|
+
deepline monitors reactivate my-monitor --json
|
|
22866
|
+
`
|
|
22867
|
+
).option("--dry-run", "Show the reactivation cost without reactivating")
|
|
22868
|
+
).action(monitorsAction(handleMonitorsReactivate));
|
|
22869
|
+
const deployed = withJsonOption(
|
|
22870
|
+
monitors.command("deployed", { hidden: true }).description("Alias of `monitors list` (plus get/update/delete aliases).").option(
|
|
22871
|
+
"--status <status>",
|
|
22872
|
+
"Filter by monitor status: active (default), disabled, or all"
|
|
22873
|
+
).option("--limit <n>", "Limit the number of deployed monitors returned").option("--compact", COMPACT_OPTION_DESCRIPTION)
|
|
22874
|
+
).action(monitorsAction(handleMonitorsList));
|
|
22875
|
+
withJsonOption(
|
|
22876
|
+
deployed.command("get <key>").description("Alias of `monitors get <key>`.")
|
|
22877
|
+
).action(monitorsAction(handleMonitorsGet));
|
|
22878
|
+
withJsonOption(
|
|
22879
|
+
deployed.command("update <key> [patch]").description("Alias of `monitors update <key>`.").option(
|
|
22880
|
+
"-f, --file <path>",
|
|
22881
|
+
"Read the patch JSON from a file, or - for stdin"
|
|
22882
|
+
)
|
|
22883
|
+
).action(monitorsAction(handleMonitorsUpdate));
|
|
22884
|
+
withJsonOption(
|
|
22885
|
+
deployed.command("delete <key>").description("Alias of `monitors delete <key>`.").option(
|
|
22886
|
+
"--local-only",
|
|
22887
|
+
"Remove only the Deepline-managed record, leaving the upstream resource"
|
|
22888
|
+
).option("--dry-run", "Show the delete plan without deleting anything").option(
|
|
22889
|
+
"--yes",
|
|
22890
|
+
"Skip the confirmation prompt (required non-interactively)"
|
|
22891
|
+
)
|
|
22892
|
+
).action(monitorsAction(handleMonitorsDelete));
|
|
21714
22893
|
}
|
|
21715
22894
|
|
|
21716
22895
|
// src/cli/commands/org.ts
|
|
@@ -22735,7 +23914,7 @@ Examples:
|
|
|
22735
23914
|
}
|
|
22736
23915
|
|
|
22737
23916
|
// src/cli/commands/switch.ts
|
|
22738
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as
|
|
23917
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
|
|
22739
23918
|
import { homedir as homedir9 } from "os";
|
|
22740
23919
|
import { dirname as dirname9, join as join9 } from "path";
|
|
22741
23920
|
function hostSlugFromBaseUrl(baseUrl) {
|
|
@@ -22770,7 +23949,7 @@ function activeFamilyPath() {
|
|
|
22770
23949
|
function readActiveFamily() {
|
|
22771
23950
|
const path = activeFamilyPath();
|
|
22772
23951
|
try {
|
|
22773
|
-
return
|
|
23952
|
+
return readFileSync10(path, "utf-8").trim() || "sdk";
|
|
22774
23953
|
} catch {
|
|
22775
23954
|
return "sdk";
|
|
22776
23955
|
}
|
|
@@ -22899,7 +24078,7 @@ import {
|
|
|
22899
24078
|
chmodSync,
|
|
22900
24079
|
existsSync as existsSync10,
|
|
22901
24080
|
mkdtempSync,
|
|
22902
|
-
readFileSync as
|
|
24081
|
+
readFileSync as readFileSync11,
|
|
22903
24082
|
writeFileSync as writeFileSync13
|
|
22904
24083
|
} from "fs";
|
|
22905
24084
|
import { tmpdir as tmpdir3 } from "os";
|
|
@@ -24302,7 +25481,7 @@ function readJsonArgument(raw, flagName) {
|
|
|
24302
25481
|
throw new Error(`Invalid ${flagName} value: empty @file path.`);
|
|
24303
25482
|
}
|
|
24304
25483
|
try {
|
|
24305
|
-
return
|
|
25484
|
+
return readFileSync11(resolveAtFilePath(filePath), "utf8").replace(
|
|
24306
25485
|
/^\uFEFF/,
|
|
24307
25486
|
""
|
|
24308
25487
|
);
|
|
@@ -24972,9 +26151,10 @@ var PLAY_EQUIVALENT = {
|
|
|
24972
26151
|
delete: "deepline plays delete <name>"
|
|
24973
26152
|
};
|
|
24974
26153
|
var MIGRATE_HINT = "deepline workflows transform <id>";
|
|
24975
|
-
var
|
|
24976
|
-
|
|
24977
|
-
|
|
26154
|
+
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`.";
|
|
26155
|
+
var JSON_OPTION_DESCRIPTION2 = "Emit JSON output. Also automatic when stdout is piped";
|
|
26156
|
+
function withJsonOption2(command) {
|
|
26157
|
+
return command.option("--json", JSON_OPTION_DESCRIPTION2);
|
|
24978
26158
|
}
|
|
24979
26159
|
var TERMINAL_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
24980
26160
|
"completed",
|
|
@@ -24999,6 +26179,7 @@ function noticeToStderr(command) {
|
|
|
24999
26179
|
`note: \`deepline workflows ${command}\` is a legacy surface \u2014 workflows are becoming plays.
|
|
25000
26180
|
equivalent: \`${deprecation.use}\`
|
|
25001
26181
|
migrate this workflow: \`${MIGRATE_HINT}\`
|
|
26182
|
+
${TRIGGER_REDIRECT}
|
|
25002
26183
|
`
|
|
25003
26184
|
);
|
|
25004
26185
|
}
|
|
@@ -25232,7 +26413,7 @@ async function handleTail(id, runId, options) {
|
|
|
25232
26413
|
}
|
|
25233
26414
|
function registerWorkflowCommands(program) {
|
|
25234
26415
|
const workflows = program.command("workflows").description(
|
|
25235
|
-
"Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play."
|
|
26416
|
+
"Legacy cloud workflows (now becoming plays). Commands still work; use `workflows transform` to migrate one to a play. " + TRIGGER_REDIRECT
|
|
25236
26417
|
).addHelpText(
|
|
25237
26418
|
"after",
|
|
25238
26419
|
`
|
|
@@ -25244,9 +26425,13 @@ keep working, but new work belongs in plays. Migrate a workflow with:
|
|
|
25244
26425
|
|
|
25245
26426
|
Equivalents: list\u2192plays list \xB7 call\u2192plays run \xB7 apply\u2192plays publish \xB7
|
|
25246
26427
|
lint\u2192plays check \xB7 runs\u2192runs list.
|
|
26428
|
+
|
|
26429
|
+
${TRIGGER_REDIRECT}
|
|
26430
|
+
Add the binding as the third arg to definePlay in your .play.ts; the
|
|
26431
|
+
deepline-monitors skill has a monitor-triggered example.
|
|
25247
26432
|
`
|
|
25248
26433
|
);
|
|
25249
|
-
|
|
26434
|
+
withJsonOption2(
|
|
25250
26435
|
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")
|
|
25251
26436
|
).addHelpText(
|
|
25252
26437
|
"after",
|
|
@@ -25263,48 +26448,48 @@ Notes:
|
|
|
25263
26448
|
).action(async (id, options) => {
|
|
25264
26449
|
process.exitCode = await handleTransform(id, options);
|
|
25265
26450
|
});
|
|
25266
|
-
|
|
26451
|
+
withJsonOption2(
|
|
25267
26452
|
workflows.command("list").description("List workspace workflows.").option("--limit <n>", "Max workflows to return")
|
|
25268
26453
|
).action(handleList2);
|
|
25269
|
-
|
|
26454
|
+
withJsonOption2(
|
|
25270
26455
|
workflows.command("get <id>").description(
|
|
25271
26456
|
"Fetch a workflow, including its published-revision config."
|
|
25272
26457
|
)
|
|
25273
26458
|
).action(handleGet);
|
|
25274
|
-
|
|
26459
|
+
withJsonOption2(
|
|
25275
26460
|
workflows.command("disable <id>").description("Turn a workflow off.")
|
|
25276
26461
|
).action(handleDisable);
|
|
25277
|
-
|
|
26462
|
+
withJsonOption2(
|
|
25278
26463
|
workflows.command("enable <id>").description("Turn a workflow back on.")
|
|
25279
26464
|
).action(handleEnable);
|
|
25280
|
-
|
|
26465
|
+
withJsonOption2(
|
|
25281
26466
|
workflows.command("delete <id>").description("Delete a workflow and its revisions/runs.")
|
|
25282
26467
|
).action(handleDelete);
|
|
25283
|
-
|
|
26468
|
+
withJsonOption2(
|
|
25284
26469
|
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")
|
|
25285
26470
|
).action(handleApply);
|
|
25286
|
-
|
|
26471
|
+
withJsonOption2(
|
|
25287
26472
|
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")
|
|
25288
26473
|
).action(handleLint);
|
|
25289
|
-
|
|
26474
|
+
withJsonOption2(
|
|
25290
26475
|
workflows.command("schema").description("Fetch live workflow request schemas.").option(
|
|
25291
26476
|
"--subject <subject>",
|
|
25292
26477
|
"Schema subject (apply|call|trigger|all|\u2026)"
|
|
25293
26478
|
)
|
|
25294
26479
|
).action(handleSchema);
|
|
25295
|
-
|
|
26480
|
+
withJsonOption2(
|
|
25296
26481
|
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")
|
|
25297
26482
|
).action(handleCall);
|
|
25298
|
-
|
|
26483
|
+
withJsonOption2(
|
|
25299
26484
|
workflows.command("runs <id>").description("List a workflow\u2019s runs.").option("--limit <n>", "Max runs to return")
|
|
25300
26485
|
).action(handleRuns);
|
|
25301
|
-
|
|
26486
|
+
withJsonOption2(
|
|
25302
26487
|
workflows.command("run <id> <runId>").description("Fetch a single workflow run.")
|
|
25303
26488
|
).action(handleRun);
|
|
25304
|
-
|
|
26489
|
+
withJsonOption2(
|
|
25305
26490
|
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)")
|
|
25306
26491
|
).action(handleTail);
|
|
25307
|
-
|
|
26492
|
+
withJsonOption2(
|
|
25308
26493
|
workflows.command("cancel <id> <runId>").description("Cancel a running workflow run.")
|
|
25309
26494
|
).action(handleCancel);
|
|
25310
26495
|
}
|
|
@@ -25315,7 +26500,7 @@ import {
|
|
|
25315
26500
|
existsSync as existsSync12,
|
|
25316
26501
|
mkdirSync as mkdirSync10,
|
|
25317
26502
|
realpathSync as realpathSync3,
|
|
25318
|
-
readFileSync as
|
|
26503
|
+
readFileSync as readFileSync13,
|
|
25319
26504
|
renameSync,
|
|
25320
26505
|
rmSync as rmSync4,
|
|
25321
26506
|
unlinkSync,
|
|
@@ -25326,7 +26511,7 @@ import { dirname as dirname13, isAbsolute as isAbsolute2, join as join14, relati
|
|
|
25326
26511
|
|
|
25327
26512
|
// src/cli/skills-sync.ts
|
|
25328
26513
|
import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
|
|
25329
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as
|
|
26514
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync14 } from "fs";
|
|
25330
26515
|
import { dirname as dirname12, join as join13 } from "path";
|
|
25331
26516
|
|
|
25332
26517
|
// ../shared_libs/cli/install-commands.json
|
|
@@ -25455,7 +26640,7 @@ function readPluginSkillsVersion() {
|
|
|
25455
26640
|
const dir = activePluginSkillsDir();
|
|
25456
26641
|
if (!dir) return "";
|
|
25457
26642
|
try {
|
|
25458
|
-
return
|
|
26643
|
+
return readFileSync12(join13(dir, ".version"), "utf-8").trim();
|
|
25459
26644
|
} catch {
|
|
25460
26645
|
return "";
|
|
25461
26646
|
}
|
|
@@ -25472,7 +26657,7 @@ function readSdkSkillsLocalVersion(baseUrl) {
|
|
|
25472
26657
|
const path = existsSync11(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
|
|
25473
26658
|
if (!existsSync11(path)) return "";
|
|
25474
26659
|
try {
|
|
25475
|
-
return
|
|
26660
|
+
return readFileSync12(path, "utf-8").trim();
|
|
25476
26661
|
} catch {
|
|
25477
26662
|
return "";
|
|
25478
26663
|
}
|
|
@@ -25767,7 +26952,7 @@ function sidecarStateDir(input2) {
|
|
|
25767
26952
|
}
|
|
25768
26953
|
function readOptionalText(path) {
|
|
25769
26954
|
try {
|
|
25770
|
-
return
|
|
26955
|
+
return readFileSync13(path, "utf8").trim();
|
|
25771
26956
|
} catch {
|
|
25772
26957
|
return "";
|
|
25773
26958
|
}
|
|
@@ -25902,7 +27087,7 @@ function readAutoUpdateFailure(plan) {
|
|
|
25902
27087
|
if (!path) return null;
|
|
25903
27088
|
try {
|
|
25904
27089
|
const parsed = JSON.parse(
|
|
25905
|
-
|
|
27090
|
+
readFileSync13(path, "utf8")
|
|
25906
27091
|
);
|
|
25907
27092
|
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") {
|
|
25908
27093
|
return parsed;
|
|
@@ -25986,7 +27171,7 @@ function installedPackageVersion(versionDir) {
|
|
|
25986
27171
|
"package.json"
|
|
25987
27172
|
);
|
|
25988
27173
|
try {
|
|
25989
|
-
const parsed = JSON.parse(
|
|
27174
|
+
const parsed = JSON.parse(readFileSync13(packageJsonPath, "utf8"));
|
|
25990
27175
|
return typeof parsed.version === "string" ? safeVersionSegment(parsed.version) : "";
|
|
25991
27176
|
} catch {
|
|
25992
27177
|
return "";
|