@signaliz/cli 1.0.16 → 1.0.18
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/README.md +47 -4
- package/dist/bin.js +1176 -72
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -9,18 +9,23 @@ var import_node_readline = require("readline");
|
|
|
9
9
|
var import_node_child_process = require("child_process");
|
|
10
10
|
var CONFIG_DIR = (0, import_node_path.join)((0, import_node_os.homedir)(), ".signaliz");
|
|
11
11
|
var CONFIG_FILE = (0, import_node_path.join)(CONFIG_DIR, "config.json");
|
|
12
|
-
|
|
12
|
+
var cachedConfig;
|
|
13
|
+
function loadConfig(options = {}) {
|
|
14
|
+
if (cachedConfig && !options.refresh) return cachedConfig;
|
|
13
15
|
try {
|
|
14
16
|
if ((0, import_node_fs.existsSync)(CONFIG_FILE)) {
|
|
15
|
-
|
|
17
|
+
cachedConfig = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_FILE, "utf8"));
|
|
18
|
+
return cachedConfig;
|
|
16
19
|
}
|
|
17
20
|
} catch {
|
|
18
21
|
}
|
|
19
|
-
|
|
22
|
+
cachedConfig = {};
|
|
23
|
+
return cachedConfig;
|
|
20
24
|
}
|
|
21
25
|
function saveConfig(config) {
|
|
22
26
|
(0, import_node_fs.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
23
27
|
(0, import_node_fs.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
|
|
28
|
+
cachedConfig = config;
|
|
24
29
|
}
|
|
25
30
|
function arg(name) {
|
|
26
31
|
const found = process.argv.find((a) => a.startsWith(`--${name}=`));
|
|
@@ -98,6 +103,7 @@ function normalizeCampaignBuildInput(raw) {
|
|
|
98
103
|
const signals = nested("signals", "signals");
|
|
99
104
|
const copy = nested("copy", "copy");
|
|
100
105
|
const delivery = nested("delivery", "delivery");
|
|
106
|
+
const learningHoldout = nested("learning_holdout", "learningHoldout");
|
|
101
107
|
return {
|
|
102
108
|
name: get("name", "name"),
|
|
103
109
|
prompt: get("prompt", "prompt"),
|
|
@@ -110,6 +116,14 @@ function normalizeCampaignBuildInput(raw) {
|
|
|
110
116
|
dedupKeys: get("dedup_keys", "dedupKeys"),
|
|
111
117
|
brainPreflight: get("brain_preflight", "brainPreflight"),
|
|
112
118
|
brainDefaults: get("brain_defaults", "brainDefaults"),
|
|
119
|
+
learningHoldout: learningHoldout ? {
|
|
120
|
+
...learningHoldout,
|
|
121
|
+
controlPercentage: learningHoldout.control_percentage ?? learningHoldout.controlPercentage,
|
|
122
|
+
minControlSize: learningHoldout.min_control_size ?? learningHoldout.minControlSize,
|
|
123
|
+
experimentKey: learningHoldout.experiment_key ?? learningHoldout.experimentKey,
|
|
124
|
+
sourceCampaignId: learningHoldout.source_campaign_id ?? learningHoldout.sourceCampaignId,
|
|
125
|
+
primaryMetric: learningHoldout.primary_metric ?? learningHoldout.primaryMetric
|
|
126
|
+
} : void 0,
|
|
113
127
|
deliveryRisk: get("delivery_risk", "deliveryRisk"),
|
|
114
128
|
icp: nested("icp", "icp"),
|
|
115
129
|
policy: policy ? {
|
|
@@ -145,7 +159,6 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
145
159
|
"action-name",
|
|
146
160
|
"actor-id",
|
|
147
161
|
"actor-type",
|
|
148
|
-
"analysis-models",
|
|
149
162
|
"attachment-field",
|
|
150
163
|
"attachment-fields",
|
|
151
164
|
"attachment-file",
|
|
@@ -193,6 +206,8 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
193
206
|
"domains",
|
|
194
207
|
"enhancers-file",
|
|
195
208
|
"enhancers-json",
|
|
209
|
+
"field-map-file",
|
|
210
|
+
"field-map-json",
|
|
196
211
|
"file-url",
|
|
197
212
|
"integration-id",
|
|
198
213
|
"image-url",
|
|
@@ -203,13 +218,14 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
203
218
|
"icp",
|
|
204
219
|
"integration-display-name",
|
|
205
220
|
"integration-route",
|
|
206
|
-
"
|
|
221
|
+
"interval-ms",
|
|
207
222
|
"layer",
|
|
208
223
|
"layers",
|
|
209
224
|
"limit",
|
|
210
225
|
"lead-count",
|
|
211
226
|
"log-limit",
|
|
212
227
|
"max-concurrency",
|
|
228
|
+
"max-polls",
|
|
213
229
|
"max-retries",
|
|
214
230
|
"max-tokens",
|
|
215
231
|
"max-credits",
|
|
@@ -218,9 +234,18 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
218
234
|
"memory-type",
|
|
219
235
|
"model",
|
|
220
236
|
"name",
|
|
237
|
+
"holdout-min-sample-size",
|
|
238
|
+
"holdout-control-percentage",
|
|
239
|
+
"holdout-experiment-key",
|
|
240
|
+
"holdout-min-control-size",
|
|
241
|
+
"holdout-primary-metric",
|
|
242
|
+
"holdout-source-campaign-id",
|
|
243
|
+
"http-method",
|
|
221
244
|
"min-sample-size",
|
|
222
245
|
"min-workspace-count",
|
|
223
246
|
"nango-connection-id",
|
|
247
|
+
"nango-action",
|
|
248
|
+
"nango-proxy-path",
|
|
224
249
|
"network-days",
|
|
225
250
|
"output-format",
|
|
226
251
|
"output-file",
|
|
@@ -245,11 +270,14 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
245
270
|
"provider-link-id",
|
|
246
271
|
"provider-name",
|
|
247
272
|
"provider-workspace-id",
|
|
273
|
+
"proxy-path",
|
|
248
274
|
"qualification-file",
|
|
249
275
|
"qualification-json",
|
|
250
276
|
"request-file",
|
|
251
277
|
"records-file",
|
|
252
278
|
"records-json",
|
|
279
|
+
"required-field",
|
|
280
|
+
"required-fields",
|
|
253
281
|
"revenue-motion",
|
|
254
282
|
"readiness-json",
|
|
255
283
|
"rationale",
|
|
@@ -275,12 +303,20 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
275
303
|
"target-icp-file",
|
|
276
304
|
"target-icp-json",
|
|
277
305
|
"temperature",
|
|
306
|
+
"timeout-ms",
|
|
278
307
|
"tool-name",
|
|
279
308
|
"url",
|
|
280
309
|
"user-display-name",
|
|
281
310
|
"user-email",
|
|
282
311
|
"video-url",
|
|
312
|
+
"wait-interval-ms",
|
|
313
|
+
"wait-max-polls",
|
|
314
|
+
"wait-timeout-ms",
|
|
283
315
|
"write-mode",
|
|
316
|
+
"timezone",
|
|
317
|
+
"wake-event",
|
|
318
|
+
"wake-events",
|
|
319
|
+
"wake-on-events",
|
|
284
320
|
"workspace-connection-id",
|
|
285
321
|
"workspace-integration-id",
|
|
286
322
|
"workspace-label",
|
|
@@ -291,6 +327,7 @@ var promptValueFlags = /* @__PURE__ */ new Set([
|
|
|
291
327
|
"brain-defaults-file",
|
|
292
328
|
"memory-dimension-filters-file",
|
|
293
329
|
"memory-dimension-filters-json",
|
|
330
|
+
"method",
|
|
294
331
|
"metadata-file",
|
|
295
332
|
"metadata-json",
|
|
296
333
|
"plan-file",
|
|
@@ -361,6 +398,9 @@ function commandBooleanFlag(flags, name, defaultValue = false) {
|
|
|
361
398
|
if (Array.isArray(value)) return value.length > 0 ? parseCommandBoolean(value.at(-1), defaultValue) : defaultValue;
|
|
362
399
|
return parseCommandBoolean(value, defaultValue);
|
|
363
400
|
}
|
|
401
|
+
function commandOptionalBooleanFlag(flags, name) {
|
|
402
|
+
return commandFlagValue(flags, name) === void 0 ? void 0 : commandBooleanFlag(flags, name);
|
|
403
|
+
}
|
|
364
404
|
function parseCommandBoolean(value, defaultValue) {
|
|
365
405
|
if (value === void 0) return defaultValue;
|
|
366
406
|
if (typeof value === "boolean") return value;
|
|
@@ -439,6 +479,32 @@ function layerCommand(layer) {
|
|
|
439
479
|
const normalized = String(layer || "sender").trim() || "sender";
|
|
440
480
|
return `signaliz connect --layer ${normalized}`;
|
|
441
481
|
}
|
|
482
|
+
function campaignSourcePlanRecord(result) {
|
|
483
|
+
const root = record(result);
|
|
484
|
+
const plan = record(root.sourcePlan ?? root.source_plan);
|
|
485
|
+
if (Object.keys(plan).length > 0) return plan;
|
|
486
|
+
return record(record(root.plan).source_plan);
|
|
487
|
+
}
|
|
488
|
+
function campaignSourceRouteRecords(result) {
|
|
489
|
+
const root = record(result);
|
|
490
|
+
const plan = campaignSourcePlanRecord(result);
|
|
491
|
+
return firstArray(root.sourceRoutes, root.source_routes, plan.routes).filter((route) => route && typeof route === "object" && !Array.isArray(route)).sort((a, b) => Number(a.priority ?? 0) - Number(b.priority ?? 0));
|
|
492
|
+
}
|
|
493
|
+
function campaignSourceSummary(result) {
|
|
494
|
+
const plan = campaignSourcePlanRecord(result);
|
|
495
|
+
if (Object.keys(plan).length === 0) return void 0;
|
|
496
|
+
const decision = record(plan.route_decision);
|
|
497
|
+
const intent = capitalizeLabel(plan.intent);
|
|
498
|
+
const reason = String(decision.selected_reason || "").trim();
|
|
499
|
+
return [intent, reason].filter(Boolean).join(" - ");
|
|
500
|
+
}
|
|
501
|
+
function campaignSourceRouteLine(route) {
|
|
502
|
+
const role = capitalizeLabel(route.role);
|
|
503
|
+
const tool = labelize(route.tool || "source");
|
|
504
|
+
const providers = firstArray(route.providers).map(labelize).filter(Boolean).join(" + ");
|
|
505
|
+
const fallback = typeof route.fallback_when === "string" && route.fallback_when.trim() ? ` (${route.fallback_when.trim()})` : "";
|
|
506
|
+
return `${role ? `${role}: ` : ""}${tool}${providers ? ` via ${providers}` : ""}${fallback}`;
|
|
507
|
+
}
|
|
442
508
|
function blockedRouteLayers(result) {
|
|
443
509
|
const root = record(result);
|
|
444
510
|
const providerActivation = record(root.provider_activation);
|
|
@@ -609,6 +675,50 @@ function printExecutionRefs(refs) {
|
|
|
609
675
|
if (ref.replay_command) console.log(` replay: ${ref.replay_command}`);
|
|
610
676
|
}
|
|
611
677
|
}
|
|
678
|
+
function combineExecutionRefs(...groups) {
|
|
679
|
+
const refs = /* @__PURE__ */ new Map();
|
|
680
|
+
for (const group of groups) {
|
|
681
|
+
if (!Array.isArray(group)) continue;
|
|
682
|
+
for (const ref of group) {
|
|
683
|
+
if (!ref?.kind || !ref?.id) continue;
|
|
684
|
+
refs.set(`${ref.kind}:${ref.id}`, ref);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return Array.from(refs.values());
|
|
688
|
+
}
|
|
689
|
+
function opsWaitOptions() {
|
|
690
|
+
return {
|
|
691
|
+
interval_ms: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
692
|
+
max_polls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
693
|
+
timeout_ms: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms"),
|
|
694
|
+
limit: numberFlag("limit"),
|
|
695
|
+
cursor: flagArg("cursor"),
|
|
696
|
+
include_failed_runs: hasFlag("include-failed-runs"),
|
|
697
|
+
include_results: !hasFlag("no-results")
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
function printOpsWaitForResults(result) {
|
|
701
|
+
const status = result.status || {};
|
|
702
|
+
console.log(`Op: ${result.op_id || result.opId || status.op_id || status.opId || "unknown"}`);
|
|
703
|
+
console.log(`Status: ${status.status || "unknown"}`);
|
|
704
|
+
console.log(`Phase: ${status.phase || "unknown"}`);
|
|
705
|
+
console.log(`Polls: ${result.polls ?? 0}${result.timed_out || result.timedOut ? " (timed out)" : ""}`);
|
|
706
|
+
if (result.results) {
|
|
707
|
+
const summary = result.results.summary || {};
|
|
708
|
+
const count = summary.results_count ?? summary.resultsCount ?? result.results.results_count ?? result.results.resultsCount ?? 0;
|
|
709
|
+
const total = summary.results_total ?? summary.resultsTotal ?? result.results.results_total ?? result.results.resultsTotal;
|
|
710
|
+
const delivery = summary.delivery_status ?? summary.deliveryStatus ?? result.results.delivery_status ?? result.results.deliveryStatus;
|
|
711
|
+
console.log(`Results: ${count}`);
|
|
712
|
+
if (total !== void 0 && total !== null) console.log(`Total: ${total}`);
|
|
713
|
+
if (delivery) console.log(`Deliver: ${delivery}`);
|
|
714
|
+
if (Array.isArray(result.results.results) && result.results.results.length) {
|
|
715
|
+
console.log("\nRows");
|
|
716
|
+
for (const row of result.results.results.slice(0, 10)) console.log(JSON.stringify(row));
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (result.next_action || result.nextAction) console.log(`Next: ${result.next_action || result.nextAction}`);
|
|
720
|
+
printExecutionRefs(result.execution_refs || result.executionRefs);
|
|
721
|
+
}
|
|
612
722
|
function printQueueProducerEnvelope(envelope) {
|
|
613
723
|
if (!envelope || typeof envelope !== "object") return;
|
|
614
724
|
const queueName = envelope.queue_name ?? envelope.queueName;
|
|
@@ -635,6 +745,52 @@ function printPrimitiveGraph(primitives) {
|
|
|
635
745
|
console.log(`- ${primitive.id || "unknown"}@${primitive.version || "unknown"} (${primitive.permission_level || "unknown"}, ${retry}, ${concurrency}, ${rate})`);
|
|
636
746
|
}
|
|
637
747
|
}
|
|
748
|
+
function printOpsExecutionContract(plan) {
|
|
749
|
+
const contract = record(plan?.execution_contract || plan?.executionContract);
|
|
750
|
+
if (!Object.keys(contract).length) return;
|
|
751
|
+
const runNow = record(contract.run_now || contract.runNow);
|
|
752
|
+
const schedule = record(contract.schedule);
|
|
753
|
+
const approval = record(contract.approval);
|
|
754
|
+
const monitor = record(contract.monitor);
|
|
755
|
+
const resultContract = record(contract.result_contract || contract.resultContract);
|
|
756
|
+
const sequence = firstArray(contract.sequence);
|
|
757
|
+
const nangoRoute = record(contract.nango_route || contract.nangoRoute);
|
|
758
|
+
const createTool = schedule.create_tool || schedule.createTool || "ops_create";
|
|
759
|
+
const activateTool = schedule.activate_tool || schedule.activateTool || "ops_execute";
|
|
760
|
+
const schedulePath = createTool === activateTool ? String(createTool) : `${createTool} -> ${activateTool}`;
|
|
761
|
+
const statusTool = monitor.status_tool || monitor.statusTool || "ops_status";
|
|
762
|
+
const waitTool = monitor.wait_tool || monitor.waitTool || resultContract.wait_tool || resultContract.waitTool || "ops_wait";
|
|
763
|
+
const resultsTool = monitor.results_tool || monitor.resultsTool || "ops_results";
|
|
764
|
+
const resultShape = firstArray(resultContract.shape).map(String);
|
|
765
|
+
console.log("\nExecution contract");
|
|
766
|
+
console.log(`- Mode: ${contract.mode || "run_once"}`);
|
|
767
|
+
console.log(`- Run now: ${runNow.tool || "ops_execute"}`);
|
|
768
|
+
console.log(`- Schedule: ${schedule.cadence || "manual"} via ${schedulePath}`);
|
|
769
|
+
if (schedule.recurrence) console.log(`- Recurrence: ${schedule.recurrence}`);
|
|
770
|
+
console.log(`- Monitor/results: ${waitTool} (or ${statusTool} -> ${resultsTool})`);
|
|
771
|
+
if (resultShape.length) console.log(`- Result shape: ${resultShape.join(", ")}`);
|
|
772
|
+
if (approval.tool) {
|
|
773
|
+
console.log(`- Approval: ${approval.required ? `${approval.tool} required` : "not required"}${approval.reason ? ` - ${approval.reason}` : ""}`);
|
|
774
|
+
}
|
|
775
|
+
if (sequence.length) {
|
|
776
|
+
console.log(`- Sequence: ${sequence.map((step) => step.tool || "unknown_tool").join(" -> ")}`);
|
|
777
|
+
}
|
|
778
|
+
if (Object.keys(nangoRoute).length) {
|
|
779
|
+
console.log("\nNango API route");
|
|
780
|
+
console.log(`- Connect: ${nangoRoute.connect_tool || nangoRoute.connectTool || "nango_connect_session_create"}`);
|
|
781
|
+
console.log(`- Discover: ${nangoRoute.discover_tool || nangoRoute.discoverTool || "nango_mcp_tools_list"}`);
|
|
782
|
+
console.log(`- Dry run: ${nangoRoute.dry_run_tool || nangoRoute.dryRunTool || "nango_mcp_tool_call"}`);
|
|
783
|
+
console.log(`- Execute: ${nangoRoute.execute_tool || nangoRoute.executeTool || "nango_mcp_tool_call"} after approval`);
|
|
784
|
+
if (nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool) {
|
|
785
|
+
console.log(`- Execute and wait: ${nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool}`);
|
|
786
|
+
}
|
|
787
|
+
const nangoScheduleTool = nangoRoute.schedule_and_wait_tool || nangoRoute.scheduleAndWaitTool || nangoRoute.schedule_tool || nangoRoute.scheduleTool;
|
|
788
|
+
if (nangoScheduleTool) {
|
|
789
|
+
console.log(`- Schedule: ${nangoScheduleTool} after approval`);
|
|
790
|
+
}
|
|
791
|
+
if (nangoRoute.write_gate || nangoRoute.writeGate) console.log(`- Gate: ${nangoRoute.write_gate || nangoRoute.writeGate}`);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
638
794
|
function normalizeSavedCommandArgs(args) {
|
|
639
795
|
const separator = args.indexOf("--");
|
|
640
796
|
const raw = separator === -1 ? args : args.slice(separator + 1);
|
|
@@ -758,7 +914,7 @@ function opsSaved(sub, rest) {
|
|
|
758
914
|
stdio: "inherit",
|
|
759
915
|
env: process.env
|
|
760
916
|
});
|
|
761
|
-
const latest = loadConfig();
|
|
917
|
+
const latest = loadConfig({ refresh: true });
|
|
762
918
|
const latestSaved = latest.saved_commands || {};
|
|
763
919
|
const latestCommand = latestSaved[name];
|
|
764
920
|
if (latestCommand) {
|
|
@@ -943,11 +1099,9 @@ Discovery:
|
|
|
943
1099
|
--category NAME Optional category filter, e.g. ops or enrichment
|
|
944
1100
|
|
|
945
1101
|
AI:
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
OpenRouter model id, e.g. google/gemini-2.5-flash
|
|
950
|
-
--records-file FILE JSON array, or object with records/inputs/data
|
|
1102
|
+
ai multi-model Run Custom AI Enrichment - Multi Model
|
|
1103
|
+
--prompt "..." Prompt/template for each record (required)
|
|
1104
|
+
--records-file FILE JSON array, or object with records/inputs/data
|
|
951
1105
|
--input-file FILE Single JSON record
|
|
952
1106
|
--output-fields a:text,b:number
|
|
953
1107
|
Structured fields to return
|
|
@@ -955,12 +1109,10 @@ AI:
|
|
|
955
1109
|
--pdf-url URL Attach a PDF URL to all records
|
|
956
1110
|
--attachment-file FILE
|
|
957
1111
|
Attach a local image/PDF/audio/video as base64
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
--judge-model MODEL Optional Fusion judge model
|
|
963
|
-
--confirm-spend Required to run spendful Fusion enrichment
|
|
1112
|
+
--attachment-fields a,b
|
|
1113
|
+
Record fields containing attachment URLs/arrays
|
|
1114
|
+
--max-concurrency N Record concurrency, default 3, maximum 5
|
|
1115
|
+
--confirm-spend Required to run spendful AI enrichment
|
|
964
1116
|
|
|
965
1117
|
Lead Generation:
|
|
966
1118
|
lead generate Start a B2B lead-generation job
|
|
@@ -1046,9 +1198,13 @@ GTM Kernel:
|
|
|
1046
1198
|
gtm learning <id> Plan Brain learning for a campaign
|
|
1047
1199
|
--include-network Include privacy-safe network lanes
|
|
1048
1200
|
--write-mode MODE dry_run or write
|
|
1201
|
+
--holdout-min-sample-size N
|
|
1202
|
+
Minimum control/treatment subjects for measured lift
|
|
1049
1203
|
gtm learning-run <id> Queue ready Brain learning phases
|
|
1050
1204
|
--phases a,b Optional phase allow-list
|
|
1051
1205
|
--write-mode MODE dry_run or write, default dry_run
|
|
1206
|
+
--holdout-min-sample-size N
|
|
1207
|
+
Minimum control/treatment subjects for measured lift
|
|
1052
1208
|
gtm calibrate <id> Calibrate deliverability predictions
|
|
1053
1209
|
--min-sample-size N Default server-side
|
|
1054
1210
|
--write Write calibrations/patterns; otherwise dry-run
|
|
@@ -1072,6 +1228,12 @@ GTM Kernel:
|
|
|
1072
1228
|
--provider NAME instantly, smartlead, heyreach, airbyte, custom_webhook
|
|
1073
1229
|
--campaign-id ID Optional campaign scope
|
|
1074
1230
|
--write-mode MODE Brain-cycle mode, default dry_run
|
|
1231
|
+
gtm feedback-pull Pull Instantly feedback into the learning loop
|
|
1232
|
+
--source SOURCE webhook_events or emails, default webhook_events
|
|
1233
|
+
--campaign-id ID Optional campaign scope
|
|
1234
|
+
--provider-campaign-id ID
|
|
1235
|
+
Instantly campaign id
|
|
1236
|
+
--confirm Write feedback/memory rows; otherwise dry-run
|
|
1075
1237
|
|
|
1076
1238
|
Native GTM Data Sources:
|
|
1077
1239
|
Use these when you already know the exact source you want to run.
|
|
@@ -1164,8 +1326,12 @@ Campaign Builder:
|
|
|
1164
1326
|
campaign rows <id> Retrieve build rows
|
|
1165
1327
|
--limit N Page size (default: 50, max: 500)
|
|
1166
1328
|
--cursor <id> Pagination cursor
|
|
1329
|
+
--include-data Include generated copy and rich row data
|
|
1330
|
+
--include-raw Include raw provider payloads
|
|
1167
1331
|
--all Dump all rows (caution: unbounded)
|
|
1168
1332
|
campaign artifacts <id> List artifacts with download URLs
|
|
1333
|
+
campaign download <id> Generate fresh signed artifact URLs
|
|
1334
|
+
--format csv|ndjson Artifact format (default: csv)
|
|
1169
1335
|
campaign approve <id> Approve pending delivery
|
|
1170
1336
|
--destination-type json|csv|webhook
|
|
1171
1337
|
--destination-id ID Optional destination/sink ID
|
|
@@ -1173,12 +1339,18 @@ Campaign Builder:
|
|
|
1173
1339
|
campaign cancel <id> Cancel a running build
|
|
1174
1340
|
|
|
1175
1341
|
Ops:
|
|
1176
|
-
Canonical path: ops plan -> ops
|
|
1342
|
+
Canonical path: ops plan -> ops execute -> ops wait
|
|
1177
1343
|
ops plan "..." Preview a prompt-first Op plan
|
|
1178
1344
|
--blueprint NAME monitor_companies|build_leads|enrich_list|route_signals|launch_campaign
|
|
1179
1345
|
--target-count N Target row count
|
|
1180
1346
|
--cadence NAME manual|hourly|daily|weekly
|
|
1347
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1181
1348
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1349
|
+
--workspace-connection-id ID
|
|
1350
|
+
Nango workspace connection for API delivery
|
|
1351
|
+
--provider-config-key KEY
|
|
1352
|
+
Nango integration/provider key
|
|
1353
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1182
1354
|
--company-domains a,b
|
|
1183
1355
|
Company domains for monitor/list-based Ops
|
|
1184
1356
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
@@ -1195,7 +1367,21 @@ Ops:
|
|
|
1195
1367
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1196
1368
|
--auto-run Run immediately after create when safe
|
|
1197
1369
|
--no-auto-run Create only
|
|
1370
|
+
--wait Auto-run, poll status, and fetch results
|
|
1371
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1372
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1373
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1374
|
+
--limit N Result rows after terminal status
|
|
1375
|
+
--no-results Stop after final status without fetching results
|
|
1376
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
1377
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1378
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1198
1379
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1380
|
+
--workspace-connection-id ID
|
|
1381
|
+
Nango workspace connection for API delivery
|
|
1382
|
+
--provider-config-key KEY
|
|
1383
|
+
Nango integration/provider key
|
|
1384
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1199
1385
|
--company-domains a,b
|
|
1200
1386
|
Company domains for monitor/list-based Ops
|
|
1201
1387
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
@@ -1204,19 +1390,78 @@ Ops:
|
|
|
1204
1390
|
ops create "..." Create an Op from a prompt
|
|
1205
1391
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1206
1392
|
--activate Create as active instead of draft
|
|
1393
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
1394
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1395
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1396
|
+
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1397
|
+
--workspace-connection-id ID
|
|
1398
|
+
Nango workspace connection for API delivery
|
|
1399
|
+
--provider-config-key KEY
|
|
1400
|
+
Nango integration/provider key
|
|
1401
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1402
|
+
--company-domains a,b
|
|
1403
|
+
Company domains for monitor/list-based Ops
|
|
1404
|
+
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
1405
|
+
--signal-prompt TEXT Custom signal-finding instruction
|
|
1406
|
+
--output-prompt TEXT Clean result formatting instruction
|
|
1407
|
+
ops schedule "..." Create and activate a recurring Op, daily by default
|
|
1408
|
+
ops recur "..." Alias for ops schedule
|
|
1409
|
+
--confirm-spend Acknowledge estimated credits/external writes
|
|
1410
|
+
--wait Run first tick and fetch results through ops_schedule_and_wait
|
|
1411
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1412
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1413
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1414
|
+
--limit N Result rows after terminal status
|
|
1415
|
+
--cadence NAME hourly|daily|weekly (default: daily)
|
|
1416
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1417
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1207
1418
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1419
|
+
--workspace-connection-id ID
|
|
1420
|
+
Nango workspace connection for API delivery
|
|
1421
|
+
--provider-config-key KEY
|
|
1422
|
+
Nango integration/provider key
|
|
1423
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1208
1424
|
--company-domains a,b
|
|
1209
1425
|
Company domains for monitor/list-based Ops
|
|
1210
1426
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
1211
1427
|
--signal-prompt TEXT Custom signal-finding instruction
|
|
1212
1428
|
--output-prompt TEXT Clean result formatting instruction
|
|
1213
1429
|
ops run <op_id> Run an Op immediately
|
|
1430
|
+
--wait Poll status and fetch results after queueing
|
|
1431
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1432
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1433
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1434
|
+
--limit N Result rows after terminal status
|
|
1435
|
+
--no-results Stop after final status without fetching results
|
|
1214
1436
|
ops status <op_id> Check simple Op status
|
|
1215
1437
|
ops results <op_id> Retrieve latest Op results
|
|
1216
1438
|
--limit N Page size, default 100, max 500
|
|
1217
1439
|
--cursor ID Pagination cursor
|
|
1218
1440
|
--include-failed-runs
|
|
1219
1441
|
Include failed run output when supported
|
|
1442
|
+
ops wait <op_id> Wait for an Op and return results (MCP parity: ops_wait)
|
|
1443
|
+
--interval-ms N Polling interval, default 5000
|
|
1444
|
+
--max-polls N Polling limit, default 12, max 30
|
|
1445
|
+
--timeout-ms N Total wait timeout, default 60000
|
|
1446
|
+
--limit N Result page size after terminal status
|
|
1447
|
+
--no-results Stop after final status without fetching results
|
|
1448
|
+
ops nango <subcommand> Connect, discover, call, schedule, and poll Nango tools
|
|
1449
|
+
flow|search Prepare a provider search/connect/Ops route plan
|
|
1450
|
+
connect Start Nango Connect auth for a provider
|
|
1451
|
+
tools List action tools for a workspace connection
|
|
1452
|
+
call <action> Dry-run or execute a Nango action
|
|
1453
|
+
proof|audit|read-write
|
|
1454
|
+
Audit connected rows and optional live read/write probes
|
|
1455
|
+
--read-proxy-path PATH
|
|
1456
|
+
Provider API path for approved live read proof
|
|
1457
|
+
--write-proxy-path PATH
|
|
1458
|
+
Provider API path for approved live write proof
|
|
1459
|
+
--execute-read-probe --confirm
|
|
1460
|
+
Run the read probe
|
|
1461
|
+
--execute-write-probe --confirm-write
|
|
1462
|
+
Run the write probe with safe test input
|
|
1463
|
+
schedule|recur Create a recurring Nango-backed Op; add --wait for first results
|
|
1464
|
+
result Poll async Nango action result
|
|
1220
1465
|
ops run-status <run_id>
|
|
1221
1466
|
Inspect a Trigger.dev run or batch with --run-ids a,b
|
|
1222
1467
|
--watch Poll until all runs reach a terminal state
|
|
@@ -1367,6 +1612,7 @@ Status and repair:
|
|
|
1367
1612
|
provider-prepare Build read-only recipe, route, and preview arguments
|
|
1368
1613
|
activate-route Dry-run or confirm provider route setup
|
|
1369
1614
|
feedback-webhook Prepare feedback ingress
|
|
1615
|
+
feedback-pull Dry-run or confirm Instantly feedback pull
|
|
1370
1616
|
learning <id> Plan Brain learning
|
|
1371
1617
|
learning-run <id> Queue Brain learning phases
|
|
1372
1618
|
calibrate <id> Calibrate deliverability
|
|
@@ -1770,6 +2016,35 @@ Options:
|
|
|
1770
2016
|
readiness: `signaliz gtm readiness <campaign_id> [options]
|
|
1771
2017
|
|
|
1772
2018
|
Alias for signaliz gtm execution.
|
|
2019
|
+
`,
|
|
2020
|
+
"feedback-pull": `signaliz gtm feedback-pull [options]
|
|
2021
|
+
|
|
2022
|
+
Dry-run or confirm an Instantly feedback pull. Dry-run is the default and
|
|
2023
|
+
counts provider records without writing feedback rows, memory, routine outcomes,
|
|
2024
|
+
or sync cursors. Confirmed writes require --confirm or --confirm-write.
|
|
2025
|
+
|
|
2026
|
+
Options:
|
|
2027
|
+
--source SOURCE webhook_events or emails, default webhook_events
|
|
2028
|
+
--provider-campaign-id ID
|
|
2029
|
+
Instantly campaign id
|
|
2030
|
+
--campaign-id ID Optional linked GTM campaign id
|
|
2031
|
+
--campaign-build-id ID Optional Campaign Builder build id
|
|
2032
|
+
--provider-link-id ID Optional provider link id
|
|
2033
|
+
--integration-id ID Optional Instantly integration id
|
|
2034
|
+
--from DATE Webhook-event pull window start
|
|
2035
|
+
--to DATE Webhook-event pull window end
|
|
2036
|
+
--limit N Page size, default server-side, max 100
|
|
2037
|
+
--max-pages N Max pages, default server-side, max 20
|
|
2038
|
+
--email-type TYPE received, sent, or manual when source=emails
|
|
2039
|
+
--mode MODE emode_focused, emode_others, or emode_all
|
|
2040
|
+
--sort-order ORDER asc or desc
|
|
2041
|
+
--no-memory Do not create memory rows on confirmed writes
|
|
2042
|
+
--no-routine-outcomes Do not write routine outcomes
|
|
2043
|
+
--no-brain-cycle Do not queue feedback-triggered Brain learning
|
|
2044
|
+
--write-mode MODE Brain-cycle mode, default dry_run
|
|
2045
|
+
--confirm Write feedback/memory rows; otherwise dry-run
|
|
2046
|
+
--confirm-write Alias for --confirm
|
|
2047
|
+
--json Machine-readable output
|
|
1773
2048
|
`,
|
|
1774
2049
|
campaigns: `signaliz gtm campaigns [options]
|
|
1775
2050
|
|
|
@@ -1834,7 +2109,13 @@ Options:
|
|
|
1834
2109
|
--blueprint NAME monitor_companies|build_leads|enrich_list|route_signals|launch_campaign
|
|
1835
2110
|
--target-count N Target row count
|
|
1836
2111
|
--cadence NAME manual|hourly|daily|weekly
|
|
2112
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1837
2113
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2114
|
+
--workspace-connection-id ID
|
|
2115
|
+
Nango workspace connection for API delivery
|
|
2116
|
+
--provider-config-key KEY
|
|
2117
|
+
Nango integration/provider key
|
|
2118
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1838
2119
|
--company-domains a,b Explicit account/domain list
|
|
1839
2120
|
--json Machine-readable output
|
|
1840
2121
|
|
|
@@ -1850,12 +2131,52 @@ Options:
|
|
|
1850
2131
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1851
2132
|
--activate Create as active instead of draft
|
|
1852
2133
|
--target-count N Target row count
|
|
2134
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
2135
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2136
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1853
2137
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2138
|
+
--workspace-connection-id ID
|
|
2139
|
+
Nango workspace connection for API delivery
|
|
2140
|
+
--provider-config-key KEY
|
|
2141
|
+
Nango integration/provider key
|
|
2142
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1854
2143
|
--company-domains a,b Explicit account/domain list
|
|
1855
2144
|
--json Machine-readable output
|
|
1856
2145
|
|
|
1857
2146
|
Safe next step:
|
|
1858
2147
|
signaliz ops run <op_id>
|
|
2148
|
+
`,
|
|
2149
|
+
schedule: `signaliz ops schedule "plain-English recurring GTM goal" [options]
|
|
2150
|
+
|
|
2151
|
+
Create and activate a recurring Op from a prompt. Defaults to daily cadence
|
|
2152
|
+
unless --cadence is provided. Requires --confirm-spend for spendful work.
|
|
2153
|
+
|
|
2154
|
+
Options:
|
|
2155
|
+
--confirm-spend Acknowledge estimated credits/external writes
|
|
2156
|
+
--wait Create the recurring Op, run the first tick, and fetch results
|
|
2157
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2158
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2159
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2160
|
+
--limit N Result rows after terminal status
|
|
2161
|
+
--target-count N Target row count
|
|
2162
|
+
--cadence NAME hourly|daily|weekly (default: daily)
|
|
2163
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2164
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
2165
|
+
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2166
|
+
--workspace-connection-id ID
|
|
2167
|
+
Nango workspace connection for API delivery
|
|
2168
|
+
--provider-config-key KEY
|
|
2169
|
+
Nango integration/provider key
|
|
2170
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
2171
|
+
--company-domains a,b Explicit account/domain list
|
|
2172
|
+
--json Machine-readable output
|
|
2173
|
+
|
|
2174
|
+
Safe next step:
|
|
2175
|
+
signaliz ops status <op_id>
|
|
2176
|
+
`,
|
|
2177
|
+
recur: `signaliz ops recur "plain-English recurring GTM goal" [options]
|
|
2178
|
+
|
|
2179
|
+
Alias for signaliz ops schedule.
|
|
1859
2180
|
`,
|
|
1860
2181
|
execute: `signaliz ops execute "plain-English GTM goal" [options]
|
|
1861
2182
|
|
|
@@ -1866,13 +2187,38 @@ Options:
|
|
|
1866
2187
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1867
2188
|
--auto-run Run immediately after create when safe
|
|
1868
2189
|
--no-auto-run Create only
|
|
2190
|
+
--wait Auto-run, poll status, and fetch results
|
|
2191
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2192
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2193
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2194
|
+
--limit N Result rows to return after terminal status
|
|
2195
|
+
--no-results Stop after final status without fetching results
|
|
1869
2196
|
--target-count N Target row count
|
|
2197
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
2198
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2199
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1870
2200
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2201
|
+
--workspace-connection-id ID
|
|
2202
|
+
Nango workspace connection for API delivery
|
|
2203
|
+
--provider-config-key KEY
|
|
2204
|
+
Nango integration/provider key
|
|
2205
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1871
2206
|
--json Machine-readable output
|
|
1872
2207
|
`,
|
|
1873
2208
|
run: `signaliz ops run <op_id> [options]
|
|
1874
2209
|
|
|
1875
2210
|
Run a created Op immediately.
|
|
2211
|
+
|
|
2212
|
+
Options:
|
|
2213
|
+
--force Force a run when supported
|
|
2214
|
+
--instruction TEXT Optional run instruction
|
|
2215
|
+
--wait Poll status and fetch results after queueing
|
|
2216
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2217
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2218
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2219
|
+
--limit N Result rows to return after terminal status
|
|
2220
|
+
--no-results Stop after final status without fetching results
|
|
2221
|
+
--json Machine-readable output
|
|
1876
2222
|
`,
|
|
1877
2223
|
status: `signaliz ops status <op_id> [options]
|
|
1878
2224
|
|
|
@@ -1887,6 +2233,51 @@ Options:
|
|
|
1887
2233
|
--cursor ID Pagination cursor
|
|
1888
2234
|
--include-failed-runs Include failed run output when supported
|
|
1889
2235
|
--json Machine-readable output
|
|
2236
|
+
`,
|
|
2237
|
+
wait: `signaliz ops wait <op_id> [options]
|
|
2238
|
+
|
|
2239
|
+
Poll Op status until it completes, blocks, fails, or needs action, then fetch
|
|
2240
|
+
the latest results automatically.
|
|
2241
|
+
|
|
2242
|
+
Options:
|
|
2243
|
+
--interval-ms N Polling interval, default 5000
|
|
2244
|
+
--max-polls N Polling limit, default 12, max 30
|
|
2245
|
+
--timeout-ms N Total wait timeout, default 60000
|
|
2246
|
+
--limit N Result rows to return after terminal status
|
|
2247
|
+
--include-failed-runs Include failed run output when fetching results
|
|
2248
|
+
--no-results Only wait for terminal status; do not fetch results
|
|
2249
|
+
--json Machine-readable output
|
|
2250
|
+
`,
|
|
2251
|
+
nango: `signaliz ops nango <flow|search|connect|tools|call|proof|schedule|result> [options]
|
|
2252
|
+
|
|
2253
|
+
Connect and operate customer-owned vendor APIs through Nango from the Ops
|
|
2254
|
+
namespace. This is the Ops-first route for "connect to any tool, do the work,
|
|
2255
|
+
and get the result" flows.
|
|
2256
|
+
|
|
2257
|
+
Examples:
|
|
2258
|
+
signaliz ops nango search hubspot
|
|
2259
|
+
signaliz ops nango connect --provider-id hubspot
|
|
2260
|
+
signaliz ops nango tools --workspace-connection-id <id> --provider-config-key hubspot
|
|
2261
|
+
signaliz ops nango call upsert-contact --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --dry-run
|
|
2262
|
+
signaliz ops nango call --workspace-connection-id <id> --proxy-path /v2/leads/list --method GET --dry-run
|
|
2263
|
+
signaliz ops nango call upsert-contact --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --execute --confirm --wait
|
|
2264
|
+
signaliz ops nango proof --json
|
|
2265
|
+
signaliz ops nango proof --workspace-connection-id <id> --read-proxy-path /v2/accounts --execute-read-probe --confirm
|
|
2266
|
+
signaliz ops nango proof --workspace-connection-id <id> --write-proxy-path /v2/custom-tags --method POST --write-input-json '{"label":"safe-proof"}' --execute-write-probe --confirm-write
|
|
2267
|
+
signaliz ops nango schedule "Monitor accounts daily and upsert approved rows" --workspace-connection-id <id> --provider-config-key hubspot --action-name upsert-contact --confirm-spend --wait
|
|
2268
|
+
signaliz ops nango result --status-url /action/<action_id>
|
|
2269
|
+
|
|
2270
|
+
Subcommands:
|
|
2271
|
+
flow|search Prepare provider search, connect, action, and Ops route calls
|
|
2272
|
+
connect Start Nango Connect auth for a provider
|
|
2273
|
+
tools List Nango action tools for a workspace connection
|
|
2274
|
+
call <action> Dry-run by default; add --execute --confirm for approved writes, --wait for result readback
|
|
2275
|
+
accepts --proxy-path for direct Nango proxy mode
|
|
2276
|
+
proof|audit|read-write Audit connected Nango rows, tools, proxy readiness, and optional live read/write probes
|
|
2277
|
+
accepts --read-proxy-path, --write-proxy-path, --execute-read-probe, --execute-write-probe
|
|
2278
|
+
schedule|recur PROMPT Create a recurring Nango-backed Op through ops_nango_schedule; --wait uses ops_nango_schedule_and_wait
|
|
2279
|
+
accepts --input-json/--input-file, --field-map-json, and --required-fields
|
|
2280
|
+
result Poll async Nango action result
|
|
1890
2281
|
`
|
|
1891
2282
|
};
|
|
1892
2283
|
function opsHelpFor(sub) {
|
|
@@ -1901,7 +2292,7 @@ Canonical path:
|
|
|
1901
2292
|
signaliz ops results <op_id>
|
|
1902
2293
|
|
|
1903
2294
|
Common commands:
|
|
1904
|
-
proof, autopilot, plan, execute, create, run, status, results, doctor, connections
|
|
2295
|
+
proof, autopilot, plan, execute, create, schedule, run, status, results, wait, nango, doctor, connections
|
|
1905
2296
|
|
|
1906
2297
|
Run: signaliz ops help <command>
|
|
1907
2298
|
`;
|
|
@@ -1932,6 +2323,13 @@ Options:
|
|
|
1932
2323
|
--outputs json,csv Delivery outputs, default json
|
|
1933
2324
|
--dry-run Validate and plan without launching spendful work
|
|
1934
2325
|
--allow-downscale Allow oversized target counts to be clamped
|
|
2326
|
+
--learning-holdout Assign explicit control vs learned cohorts
|
|
2327
|
+
--holdout-control-percentage N
|
|
2328
|
+
Control share, e.g. 0.2 or 20 for 20%
|
|
2329
|
+
--holdout-min-control-size N
|
|
2330
|
+
Minimum control rows for large builds, default 50
|
|
2331
|
+
--holdout-experiment-key KEY
|
|
2332
|
+
Stable experiment key for feedback attribution
|
|
1935
2333
|
--confirm-spend Acknowledge spendful generation
|
|
1936
2334
|
--input-file FILE JSON config file from campaign scope or gtm prepare-build
|
|
1937
2335
|
--wait Poll until completion
|
|
@@ -1953,12 +2351,22 @@ Options:
|
|
|
1953
2351
|
--cursor ID Pagination cursor
|
|
1954
2352
|
--qualified Only qualified rows
|
|
1955
2353
|
--disqualified Only disqualified rows
|
|
2354
|
+
--include-data Include rich row data such as generated copy
|
|
2355
|
+
--include-raw Include raw provider/qualification payloads
|
|
1956
2356
|
--all Dump all rows
|
|
1957
2357
|
--json Machine-readable output
|
|
1958
2358
|
`,
|
|
1959
2359
|
artifacts: `signaliz campaign artifacts <campaign_build_id> [options]
|
|
1960
2360
|
|
|
1961
2361
|
List generated artifacts and signed download URLs.
|
|
2362
|
+
`,
|
|
2363
|
+
download: `signaliz campaign download <campaign_build_id> [options]
|
|
2364
|
+
|
|
2365
|
+
Generate fresh signed URLs for a downloadable artifact.
|
|
2366
|
+
|
|
2367
|
+
Options:
|
|
2368
|
+
--format csv|ndjson Artifact format, default csv
|
|
2369
|
+
--json Machine-readable output
|
|
1962
2370
|
`,
|
|
1963
2371
|
approve: `signaliz campaign approve <campaign_build_id> --destination-type <json|csv|webhook>
|
|
1964
2372
|
|
|
@@ -1979,9 +2387,10 @@ Canonical path:
|
|
|
1979
2387
|
signaliz campaign build --prompt "VP Sales at B2B SaaS" --confirm-spend --wait
|
|
1980
2388
|
signaliz campaign rows <campaign_build_id> --limit 100
|
|
1981
2389
|
signaliz campaign artifacts <campaign_build_id>
|
|
2390
|
+
signaliz campaign download <campaign_build_id> --format csv
|
|
1982
2391
|
|
|
1983
2392
|
Commands:
|
|
1984
|
-
scope, build, status, rows, artifacts, approve, cancel
|
|
2393
|
+
scope, build, status, rows, artifacts, download, approve, cancel
|
|
1985
2394
|
|
|
1986
2395
|
Run: signaliz campaign help <command>
|
|
1987
2396
|
`;
|
|
@@ -2394,20 +2803,20 @@ function aiAttachmentsFromFlags() {
|
|
|
2394
2803
|
}
|
|
2395
2804
|
async function ai(sub, rest) {
|
|
2396
2805
|
if (sub !== "multi-model" && sub !== "multimodel") {
|
|
2397
|
-
die('Usage: signaliz ai multi-model --prompt "..." --
|
|
2806
|
+
die('Usage: signaliz ai multi-model --prompt "..." --confirm-spend');
|
|
2807
|
+
}
|
|
2808
|
+
if (flagArg("model") !== void 0 || hasFlag("model") || flagArg("analysis-models") !== void 0 || hasFlag("analysis-models") || flagArg("judge-model") !== void 0 || hasFlag("judge-model")) {
|
|
2809
|
+
die("Custom AI model selection is no longer supported. Signaliz-hosted custom AI uses the default model and returns model readback metadata.");
|
|
2398
2810
|
}
|
|
2399
2811
|
const promptText = promptArg(rest);
|
|
2400
|
-
|
|
2401
|
-
if (!promptText) die('Usage: signaliz ai multi-model --prompt "..." --model provider/model --confirm-spend');
|
|
2402
|
-
if (!model) die("--model is required. Use an OpenRouter id such as google/gemini-2.5-flash.");
|
|
2812
|
+
if (!promptText) die('Usage: signaliz ai multi-model --prompt "..." --confirm-spend');
|
|
2403
2813
|
if (!hasFlag("confirm-spend")) {
|
|
2404
|
-
die("This
|
|
2814
|
+
die("This runs custom AI enrichment and can spend credits. Re-run with --confirm-spend to approve.");
|
|
2405
2815
|
}
|
|
2406
2816
|
const sdk = getSdk();
|
|
2407
2817
|
const records = aiRecordsFromFlags();
|
|
2408
2818
|
const result = await sdk.ai.multiModel({
|
|
2409
2819
|
prompt: promptText,
|
|
2410
|
-
model,
|
|
2411
2820
|
records,
|
|
2412
2821
|
systemPrompt: flagArg("system-prompt"),
|
|
2413
2822
|
temperature: numberFlag("temperature"),
|
|
@@ -2418,15 +2827,12 @@ async function ai(sub, rest) {
|
|
|
2418
2827
|
attachmentFields: csvFlag("attachment-fields") || csvFlag("attachment-field"),
|
|
2419
2828
|
pdfEngine: flagArg("pdf-engine"),
|
|
2420
2829
|
fusion: {
|
|
2421
|
-
required: !hasFlag("no-require-fusion"),
|
|
2422
|
-
analysis_models: csvFlag("analysis-models"),
|
|
2423
|
-
judge_model: flagArg("judge-model"),
|
|
2424
2830
|
include_raw_analysis: hasFlag("include-raw-analysis")
|
|
2425
2831
|
}
|
|
2426
2832
|
});
|
|
2427
2833
|
return output(result, () => {
|
|
2428
2834
|
console.log("Custom AI Enrichment - Multi Model complete");
|
|
2429
|
-
console.log(` Model: ${result.model ||
|
|
2835
|
+
console.log(` Model: ${result.model || "google/gemini-2.5-flash"}`);
|
|
2430
2836
|
console.log(` Records: ${result.results.length}`);
|
|
2431
2837
|
console.log(` Credits: ${result.creditsUsed}`);
|
|
2432
2838
|
console.log(` Attachments: ${result.multimodalCount}`);
|
|
@@ -2462,6 +2868,16 @@ async function campaignBuild() {
|
|
|
2462
2868
|
if (hasFlag("dry-run")) config.dryRun = true;
|
|
2463
2869
|
if (hasFlag("allow-downscale")) config.allowDownscale = true;
|
|
2464
2870
|
if (hasFlag("confirm-spend")) config.confirmSpend = true;
|
|
2871
|
+
if (hasFlag("learning-holdout") || flagArg("holdout-control-percentage") || flagArg("holdout-min-control-size") || flagArg("holdout-experiment-key")) {
|
|
2872
|
+
config.learningHoldout = {
|
|
2873
|
+
enabled: true,
|
|
2874
|
+
controlPercentage: numberFlag("holdout-control-percentage") ?? 0.2,
|
|
2875
|
+
minControlSize: numberFlag("holdout-min-control-size") ?? 50,
|
|
2876
|
+
experimentKey: flagArg("holdout-experiment-key") || void 0,
|
|
2877
|
+
sourceCampaignId: flagArg("holdout-source-campaign-id") || void 0,
|
|
2878
|
+
primaryMetric: flagArg("holdout-primary-metric") || void 0
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2465
2881
|
const outputs = (flagArg("outputs") || "json").split(",").map((s) => s.trim());
|
|
2466
2882
|
const webhookUrl = flagArg("webhook-url");
|
|
2467
2883
|
if (outputs.includes("csv") || outputs.includes("webhook") || webhookUrl) {
|
|
@@ -2502,8 +2918,14 @@ async function campaignBuild() {
|
|
|
2502
2918
|
console.log("\u2713 Campaign dry-run plan ready");
|
|
2503
2919
|
console.log(` Requested: ${result.requestedTargetCount ?? config.targetCount ?? 50} leads`);
|
|
2504
2920
|
console.log(` Planned: ${result.plannedTargetCount ?? result.requestedTargetCount ?? config.targetCount ?? 50} leads`);
|
|
2921
|
+
const sourceSummary = campaignSourceSummary(result);
|
|
2922
|
+
if (sourceSummary) console.log(` Source: ${sourceSummary}`);
|
|
2923
|
+
for (const [index, route] of campaignSourceRouteRecords(result).slice(0, 4).entries()) {
|
|
2924
|
+
console.log(` Route ${index + 1}: ${campaignSourceRouteLine(route)}`);
|
|
2925
|
+
}
|
|
2505
2926
|
if (result.estimatedCredits !== void 0) console.log(` Credits: ~${result.estimatedCredits}`);
|
|
2506
2927
|
if (result.estimatedDurationSeconds !== void 0) console.log(` Duration: ~${result.estimatedDurationSeconds}s`);
|
|
2928
|
+
if (result.learningHoldout?.enabled) console.log(` Holdout: enabled (${Math.round(Number(result.learningHoldout.control_percentage || 0) * 100)}% control)`);
|
|
2507
2929
|
if (result.targetLimitApplied) console.log(` Note: ${result.targetLimitReason || "target count downscaled"}`);
|
|
2508
2930
|
hint("Remove --dry-run and add --confirm-spend when ready to launch.");
|
|
2509
2931
|
});
|
|
@@ -2517,6 +2939,7 @@ async function campaignBuild() {
|
|
|
2517
2939
|
console.log(` Status: ${result.status}`);
|
|
2518
2940
|
console.log(` Phase: ${result.currentPhase}`);
|
|
2519
2941
|
console.log(` Target: ${config.targetCount || 50} leads`);
|
|
2942
|
+
if (result.learningHoldout?.enabled) console.log(` Holdout: enabled (${Math.round(Number(result.learningHoldout.control_percentage || 0) * 100)}% control)`);
|
|
2520
2943
|
hint(`signaliz campaign status ${result.campaignBuildId}`);
|
|
2521
2944
|
});
|
|
2522
2945
|
}
|
|
@@ -2546,6 +2969,7 @@ async function campaignBuild() {
|
|
|
2546
2969
|
\u2713 Build ${finalStatus.status}`);
|
|
2547
2970
|
console.log(` Rows: ${finalStatus.recordsSucceeded}/${finalStatus.recordsTotal} succeeded`);
|
|
2548
2971
|
console.log(` Artifacts: ${finalStatus.artifactCount}`);
|
|
2972
|
+
printCampaignArtifactDownloadHint(finalStatus, result.campaignBuildId);
|
|
2549
2973
|
if (finalStatus.status === "completed") {
|
|
2550
2974
|
hint(`signaliz campaign rows ${result.campaignBuildId} --limit 100`);
|
|
2551
2975
|
}
|
|
@@ -2589,6 +3013,35 @@ async function campaignScope() {
|
|
|
2589
3013
|
hint("Next: run signaliz campaign build --input-file with the buildCampaignArgs JSON, or call build_campaign with the returned dry-run args.");
|
|
2590
3014
|
});
|
|
2591
3015
|
}
|
|
3016
|
+
function campaignArtifactDownloads(status) {
|
|
3017
|
+
const downloads = Array.isArray(status?.artifactDownloads) ? status.artifactDownloads : Array.isArray(status?.artifact_downloads) ? status.artifact_downloads : [];
|
|
3018
|
+
return downloads.map(record);
|
|
3019
|
+
}
|
|
3020
|
+
function campaignArtifactDownloadUrl(download) {
|
|
3021
|
+
const url = download.downloadUrl || download.download_url || download.signedUrl || download.signed_url;
|
|
3022
|
+
return typeof url === "string" && url.trim() ? url.trim() : null;
|
|
3023
|
+
}
|
|
3024
|
+
function campaignPreferredArtifactDownload(status) {
|
|
3025
|
+
const downloads = campaignArtifactDownloads(status);
|
|
3026
|
+
if (downloads.length === 0) return null;
|
|
3027
|
+
return downloads.find((download) => {
|
|
3028
|
+
const format = String(download.format || download.artifactType || download.artifact_type || "").toLowerCase();
|
|
3029
|
+
return format === "csv";
|
|
3030
|
+
}) || downloads[0];
|
|
3031
|
+
}
|
|
3032
|
+
function printCampaignArtifactDownloadHint(status, buildId) {
|
|
3033
|
+
const download = campaignPreferredArtifactDownload(status);
|
|
3034
|
+
const url = download ? campaignArtifactDownloadUrl(download) : null;
|
|
3035
|
+
if (url) {
|
|
3036
|
+
const format = String(download?.format || download?.artifactType || download?.artifact_type || "artifact");
|
|
3037
|
+
const rowCount = Number(download?.rowCount ?? download?.row_count ?? 0);
|
|
3038
|
+
console.log(`Download: ${format}${rowCount > 0 ? `, ${rowCount} rows` : ""}`);
|
|
3039
|
+
console.log(` ${url}`);
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
const artifactCount = Number(status?.artifactCount ?? status?.artifact_count ?? 0);
|
|
3043
|
+
if (artifactCount > 0) hint(`signaliz campaign download ${buildId} --format csv`);
|
|
3044
|
+
}
|
|
2592
3045
|
async function campaignStatus() {
|
|
2593
3046
|
const buildId = positionalAfter("status") || flagArg("campaign-build-id");
|
|
2594
3047
|
if (!buildId) die("Usage: signaliz campaign status <campaign_build_id>");
|
|
@@ -2600,7 +3053,9 @@ async function campaignStatus() {
|
|
|
2600
3053
|
console.log(`Status: ${status.status}`);
|
|
2601
3054
|
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
2602
3055
|
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
3056
|
+
printCampaignCustomerRowCounts(status);
|
|
2603
3057
|
console.log(`Artifacts: ${status.artifactCount}`);
|
|
3058
|
+
printCampaignArtifactDownloadHint(status, buildId);
|
|
2604
3059
|
if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
|
|
2605
3060
|
if (status.staleRunningPhase) {
|
|
2606
3061
|
const age = typeof status.phaseAgeSeconds === "number" ? `${status.phaseAgeSeconds}s` : "unknown age";
|
|
@@ -2614,12 +3069,18 @@ async function campaignStatus() {
|
|
|
2614
3069
|
console.log(`Errors: ${status.errors.length}`);
|
|
2615
3070
|
for (const error of status.errors.slice(0, 3)) console.log(` - ${error}`);
|
|
2616
3071
|
}
|
|
2617
|
-
if (status.status === "completed") {
|
|
3072
|
+
if (status.status === "completed" && status.nextAction) {
|
|
3073
|
+
hint(status.nextAction);
|
|
3074
|
+
} else if (status.status === "completed") {
|
|
2618
3075
|
hint(`signaliz campaign rows ${buildId} --limit 100`);
|
|
2619
3076
|
} else if (status.staleRunningPhase && status.triggerRunId) {
|
|
2620
3077
|
hint(`signaliz ops run-status ${status.triggerRunId} --watch`);
|
|
2621
3078
|
} else if (status.status === "running" || status.status === "queued") {
|
|
2622
3079
|
hint(`signaliz campaign status ${buildId} (poll again in ~10s)`);
|
|
3080
|
+
} else if (status.status === "pending_approval" && status.approvalAction) {
|
|
3081
|
+
hint(status.approvalAction);
|
|
3082
|
+
} else if (status.status === "pending_approval" && status.nextAction) {
|
|
3083
|
+
hint(status.nextAction);
|
|
2623
3084
|
} else if (status.status === "pending_approval") {
|
|
2624
3085
|
hint(`signaliz campaign approve ${buildId} --destination-type webhook`);
|
|
2625
3086
|
} else if (status.status === "failed" && status.nextAction) {
|
|
@@ -2627,6 +3088,22 @@ async function campaignStatus() {
|
|
|
2627
3088
|
}
|
|
2628
3089
|
});
|
|
2629
3090
|
}
|
|
3091
|
+
function printCampaignCustomerRowCounts(status) {
|
|
3092
|
+
const counts = status?.customerRowCounts || status?.customer_row_counts;
|
|
3093
|
+
if (!counts || typeof counts !== "object") return;
|
|
3094
|
+
const value = (camel, snake) => counts[camel] ?? counts[snake] ?? "n/a";
|
|
3095
|
+
const requested = value("requestedTarget", "requested_target");
|
|
3096
|
+
console.log(`Customer rows: accepted ${value("acceptedRows", "accepted_rows")}/${requested}, copied ${value("copiedRows", "copied_rows")}, approval-ready ${value("approvalReadyRows", "approval_ready_rows")}, QA-ready ${value("qaReadyRows", "qa_ready_rows")}, delivered ${value("deliveredRows", "delivered_rows")}`);
|
|
3097
|
+
const shortfalls = [
|
|
3098
|
+
["accepted", value("acceptedShortfall", "accepted_shortfall")],
|
|
3099
|
+
["usable", value("usableShortfall", "usable_shortfall")],
|
|
3100
|
+
["QA-ready", value("qaReadyShortfall", "qa_ready_shortfall")],
|
|
3101
|
+
["delivery", value("deliveryShortfall", "delivery_shortfall")]
|
|
3102
|
+
].filter(([, count]) => typeof count === "number" && count > 0);
|
|
3103
|
+
if (shortfalls.length > 0) {
|
|
3104
|
+
console.log(`Shortfalls: ${shortfalls.map(([label, count]) => `${label} ${count}`).join(", ")}`);
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
2630
3107
|
async function campaignRows() {
|
|
2631
3108
|
const buildId = positionalAfter("rows") || flagArg("campaign-build-id");
|
|
2632
3109
|
if (!buildId) die("Usage: signaliz campaign rows <campaign_build_id>");
|
|
@@ -2641,6 +3118,8 @@ async function campaignRows() {
|
|
|
2641
3118
|
do {
|
|
2642
3119
|
const opts = { limit: Math.min(limit, 500) };
|
|
2643
3120
|
if (nextCursor) opts.cursor = nextCursor;
|
|
3121
|
+
if (hasFlag("include-data")) opts.includeData = true;
|
|
3122
|
+
if (hasFlag("include-raw")) opts.includeRaw = true;
|
|
2644
3123
|
const segment = flagArg("segment");
|
|
2645
3124
|
if (segment) opts.segment = segment;
|
|
2646
3125
|
const rowStatus = flagArg("row-status");
|
|
@@ -2665,6 +3144,8 @@ async function campaignRows() {
|
|
|
2665
3144
|
} else {
|
|
2666
3145
|
const opts = { limit: Math.min(limit, 500) };
|
|
2667
3146
|
if (cursor) opts.cursor = cursor;
|
|
3147
|
+
if (hasFlag("include-data")) opts.includeData = true;
|
|
3148
|
+
if (hasFlag("include-raw")) opts.includeRaw = true;
|
|
2668
3149
|
const segment = flagArg("segment");
|
|
2669
3150
|
if (segment) opts.segment = segment;
|
|
2670
3151
|
const rowStatus = flagArg("row-status");
|
|
@@ -2690,6 +3171,7 @@ async function campaignRows() {
|
|
|
2690
3171
|
status: r.status || "",
|
|
2691
3172
|
score: r.score ?? ""
|
|
2692
3173
|
})));
|
|
3174
|
+
printCampaignCopySnippets(operatorResult.rows);
|
|
2693
3175
|
console.log(`
|
|
2694
3176
|
Showing ${operatorResult.rows.length} row(s)${operatorResult.hasMore ? " (more available)" : ""}`);
|
|
2695
3177
|
if (operatorResult.nextCursor) {
|
|
@@ -2702,14 +3184,15 @@ function formatCampaignRowsForOperator(rows) {
|
|
|
2702
3184
|
return rows.map((row) => {
|
|
2703
3185
|
const rowRecord = record(row);
|
|
2704
3186
|
const data = record(rowRecord.data);
|
|
3187
|
+
const copyData = record(data.copy);
|
|
2705
3188
|
const rawCopy = record(data.raw_copy);
|
|
2706
3189
|
const copy = {
|
|
2707
|
-
subject: data.subject || rawCopy.subject || null,
|
|
2708
|
-
opener: data.opener || rawCopy.opener || null,
|
|
2709
|
-
body: data.body || rawCopy.body || null,
|
|
2710
|
-
cta: data.cta || rawCopy.cta || null,
|
|
2711
|
-
engine: data.copy_engine || rawCopy.engine || null,
|
|
2712
|
-
model: data.copy_model || null
|
|
3190
|
+
subject: data.subject || copyData.subject || rawCopy.subject || null,
|
|
3191
|
+
opener: data.opener || copyData.opener || rawCopy.opener || null,
|
|
3192
|
+
body: data.body || copyData.body || rawCopy.body || null,
|
|
3193
|
+
cta: data.cta || copyData.cta || rawCopy.cta || null,
|
|
3194
|
+
engine: data.copy_engine || copyData.engine || rawCopy.engine || null,
|
|
3195
|
+
model: data.copy_model || copyData.model || null
|
|
2713
3196
|
};
|
|
2714
3197
|
return {
|
|
2715
3198
|
...rowRecord,
|
|
@@ -2739,6 +3222,26 @@ function formatCampaignRowsForOperator(rows) {
|
|
|
2739
3222
|
};
|
|
2740
3223
|
});
|
|
2741
3224
|
}
|
|
3225
|
+
function printCampaignCopySnippets(rows, limit = 5) {
|
|
3226
|
+
const rowsWithCopy = rows.filter((row) => {
|
|
3227
|
+
const copy = record(row.copy);
|
|
3228
|
+
return Boolean(copy.subject || copy.opener || copy.body || copy.cta);
|
|
3229
|
+
});
|
|
3230
|
+
if (rowsWithCopy.length === 0) return;
|
|
3231
|
+
console.log("\nCopy:");
|
|
3232
|
+
for (const row of rowsWithCopy.slice(0, limit)) {
|
|
3233
|
+
const copy = record(row.copy);
|
|
3234
|
+
const label = row.email || row.name || row.company || `row ${row.index ?? ""}`.toString().trim();
|
|
3235
|
+
console.log(`- ${label}`);
|
|
3236
|
+
if (copy.subject) console.log(` Subject: ${copy.subject}`);
|
|
3237
|
+
if (copy.opener) console.log(` Opener: ${copy.opener}`);
|
|
3238
|
+
if (copy.body) console.log(` Body: ${copy.body}`);
|
|
3239
|
+
if (copy.cta) console.log(` CTA: ${copy.cta}`);
|
|
3240
|
+
}
|
|
3241
|
+
if (rowsWithCopy.length > limit) {
|
|
3242
|
+
console.log(` ...${rowsWithCopy.length - limit} more row(s) with copy`);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
2742
3245
|
async function campaignArtifacts() {
|
|
2743
3246
|
const buildId = positionalAfter("artifacts") || flagArg("campaign-build-id");
|
|
2744
3247
|
if (!buildId) die("Usage: signaliz campaign artifacts <campaign_build_id>");
|
|
@@ -2756,6 +3259,24 @@ async function campaignArtifacts() {
|
|
|
2756
3259
|
}
|
|
2757
3260
|
});
|
|
2758
3261
|
}
|
|
3262
|
+
async function campaignDownload() {
|
|
3263
|
+
const buildId = positionalAfter("download") || flagArg("campaign-build-id");
|
|
3264
|
+
if (!buildId) die("Usage: signaliz campaign download <campaign_build_id> [--format csv|ndjson]");
|
|
3265
|
+
const sdk = getSdk();
|
|
3266
|
+
const format = flagArg("format") || "csv";
|
|
3267
|
+
const result = await sdk.campaigns.downloadCampaignArtifact(buildId, { format });
|
|
3268
|
+
output(result, () => {
|
|
3269
|
+
console.log(`Artifact: ${result.format} (${result.rowCount} rows)`);
|
|
3270
|
+
if (result.partCount > 1) console.log(`Parts: ${result.partCount}`);
|
|
3271
|
+
const parts = Array.isArray(result.parts) ? result.parts : [];
|
|
3272
|
+
for (const part of parts) {
|
|
3273
|
+
const url = part.signedUrl;
|
|
3274
|
+
if (!url) continue;
|
|
3275
|
+
const label = result.partCount > 1 ? `part ${part.partIndex}` : "download";
|
|
3276
|
+
console.log(`${label}: ${url}`);
|
|
3277
|
+
}
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
2759
3280
|
async function campaignApprove() {
|
|
2760
3281
|
const buildId = positionalAfter("approve") || positionalAfter("approve-delivery") || flagArg("campaign-build-id");
|
|
2761
3282
|
if (!buildId) die("Usage: signaliz campaign approve <campaign_build_id> --destination-type <json|csv|webhook>");
|
|
@@ -2811,6 +3332,8 @@ async function campaign(sub) {
|
|
|
2811
3332
|
return campaignRows();
|
|
2812
3333
|
case "artifacts":
|
|
2813
3334
|
return campaignArtifacts();
|
|
3335
|
+
case "download":
|
|
3336
|
+
return campaignDownload();
|
|
2814
3337
|
case "approve":
|
|
2815
3338
|
case "approve-delivery":
|
|
2816
3339
|
return campaignApprove();
|
|
@@ -2818,7 +3341,7 @@ async function campaign(sub) {
|
|
|
2818
3341
|
return campaignCancel();
|
|
2819
3342
|
default:
|
|
2820
3343
|
die(`Unknown campaign subcommand: ${sub}
|
|
2821
|
-
Available: scope, build, status, rows, artifacts, approve, cancel`);
|
|
3344
|
+
Available: scope, build, status, rows, artifacts, download, approve, cancel`);
|
|
2822
3345
|
}
|
|
2823
3346
|
}
|
|
2824
3347
|
var CAMPAIGN_AGENT_APPROVAL_TYPES = [
|
|
@@ -2864,9 +3387,9 @@ Examples:
|
|
|
2864
3387
|
signaliz campaign-agent dry-run --goal "Build a local services campaign" --target-count 250 --use-local-leads --json
|
|
2865
3388
|
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign" --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500
|
|
2866
3389
|
signaliz campaign-agent build-approved --request-file campaign-builder-agent-request.json --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500 --wait --approve-delivery --delivery-destination-type json
|
|
2867
|
-
signaliz campaign-agent review <campaign_build_id> --limit 100 --json
|
|
3390
|
+
signaliz campaign-agent review <campaign_build_id> --limit 100 --include-data --json
|
|
2868
3391
|
signaliz campaign-agent status <campaign_build_id> --json
|
|
2869
|
-
signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
|
|
3392
|
+
signaliz campaign-agent rows <campaign_build_id> --limit 100 --include-data --json
|
|
2870
3393
|
|
|
2871
3394
|
Plan options:
|
|
2872
3395
|
--goal TEXT Campaign goal or brief
|
|
@@ -2874,7 +3397,7 @@ Plan options:
|
|
|
2874
3397
|
--kit-file FILE Write campaign-agent kit output to a JSON file
|
|
2875
3398
|
--seed-manifest-file FILE
|
|
2876
3399
|
Manifest path for memory-kit seed dry-runs
|
|
2877
|
-
--source NAME memory-kit seed source: agency, workflow-patterns, instantly-feedback, or all
|
|
3400
|
+
--source NAME memory-kit seed source: north-star, agency, workflow-patterns, instantly-feedback, or all
|
|
2878
3401
|
--request-output-file FILE
|
|
2879
3402
|
Request filename to reference inside kit commands
|
|
2880
3403
|
--request-file FILE Reusable JSON CampaignBuilderAgentRequest; flags override file fields
|
|
@@ -3118,6 +3641,8 @@ async function campaignAgentReview(sub, rest) {
|
|
|
3118
3641
|
cursor: commandStringFlag(flags, "cursor"),
|
|
3119
3642
|
segment: commandStringFlag(flags, "segment"),
|
|
3120
3643
|
rowStatus: commandStringFlag(flags, "row-status"),
|
|
3644
|
+
includeData: commandOptionalBooleanFlag(flags, "include-data"),
|
|
3645
|
+
includeRaw: commandOptionalBooleanFlag(flags, "include-raw"),
|
|
3121
3646
|
qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
|
|
3122
3647
|
};
|
|
3123
3648
|
const review = await agent.reviewBuild?.(buildId, rowOptions) || await campaignAgentBuildReviewFromCampaignApis(agent, campaigns, buildId, rowOptions);
|
|
@@ -3141,6 +3666,8 @@ async function campaignAgentReview(sub, rest) {
|
|
|
3141
3666
|
cursor: commandStringFlag(flags, "cursor"),
|
|
3142
3667
|
segment: commandStringFlag(flags, "segment"),
|
|
3143
3668
|
rowStatus: commandStringFlag(flags, "row-status"),
|
|
3669
|
+
includeData: commandOptionalBooleanFlag(flags, "include-data"),
|
|
3670
|
+
includeRaw: commandOptionalBooleanFlag(flags, "include-raw"),
|
|
3144
3671
|
qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
|
|
3145
3672
|
};
|
|
3146
3673
|
const result2 = await (agent.getBuildRows?.bind(agent) || campaigns.rows?.bind(campaigns) || campaigns.getCampaignBuildRows?.bind(campaigns))?.(buildId, rowOptions);
|
|
@@ -3731,8 +4258,11 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
3731
4258
|
if (status.campaignId) console.log(`Campaign ID: ${status.campaignId}`);
|
|
3732
4259
|
console.log(`Status: ${status.status}`);
|
|
3733
4260
|
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
4261
|
+
if (status.terminalState?.kind) console.log(`Terminal: ${status.terminalState.kind}`);
|
|
3734
4262
|
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
4263
|
+
printCampaignCustomerRowCounts(status);
|
|
3735
4264
|
console.log(`Artifacts: ${status.artifactCount}`);
|
|
4265
|
+
if (status.campaignBuildId) printCampaignArtifactDownloadHint(status, status.campaignBuildId);
|
|
3736
4266
|
if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
|
|
3737
4267
|
if (Array.isArray(status.warnings) && status.warnings.length) {
|
|
3738
4268
|
console.log(`Warnings: ${status.warnings.length}`);
|
|
@@ -3742,8 +4272,14 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
3742
4272
|
console.log(`Errors: ${status.errors.length}`);
|
|
3743
4273
|
for (const error of status.errors.slice(0, 3)) console.log(` - ${error}`);
|
|
3744
4274
|
}
|
|
3745
|
-
if (status.status === "completed") {
|
|
4275
|
+
if (status.status === "completed" && status.nextAction) {
|
|
4276
|
+
hint(status.nextAction);
|
|
4277
|
+
} else if (status.status === "completed") {
|
|
3746
4278
|
hint(`signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
|
|
4279
|
+
} else if (status.status === "pending_approval" && status.approvalAction) {
|
|
4280
|
+
hint(status.approvalAction);
|
|
4281
|
+
} else if (status.status === "pending_approval" && status.nextAction) {
|
|
4282
|
+
hint(status.nextAction);
|
|
3747
4283
|
} else if (status.status === "pending_approval") {
|
|
3748
4284
|
hint(`signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
3749
4285
|
} else if ((status.status === "running" || status.status === "queued") && status.triggerRunId) {
|
|
@@ -3756,11 +4292,14 @@ function printCampaignAgentBuildReview(review) {
|
|
|
3756
4292
|
console.log(`Campaign: ${status.name || review.campaignBuildId}`);
|
|
3757
4293
|
console.log(`Status: ${summary.status || status.status}`);
|
|
3758
4294
|
console.log(`Phase: ${summary.phase || status.currentPhase || "N/A"}`);
|
|
4295
|
+
console.log(`Terminal state: ${summary.terminalState || status.terminalState?.kind || "unknown"}`);
|
|
3759
4296
|
console.log(`Rows: ${summary.sampledRows || 0} sampled, ${summary.availableRows || 0} available`);
|
|
3760
4297
|
console.log(`Qualified: ${summary.qualifiedRows || 0}`);
|
|
3761
4298
|
console.log(`Emails: ${summary.rowsWithEmail || 0}`);
|
|
3762
4299
|
console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
|
|
3763
4300
|
console.log(`Artifacts: ${summary.artifactCount || 0}`);
|
|
4301
|
+
printCampaignAgentNorthStarScorecard(review.northStarScorecard);
|
|
4302
|
+
if (review.campaignBuildId) printCampaignArtifactDownloadHint(status, review.campaignBuildId);
|
|
3764
4303
|
console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
|
|
3765
4304
|
const gates = Array.isArray(review.gates) ? review.gates : [];
|
|
3766
4305
|
if (gates.length) {
|
|
@@ -3780,6 +4319,21 @@ function printCampaignAgentBuildReview(review) {
|
|
|
3780
4319
|
for (const action of nextActions) console.log(`- ${action}`);
|
|
3781
4320
|
}
|
|
3782
4321
|
}
|
|
4322
|
+
function printCampaignAgentNorthStarScorecard(scorecard) {
|
|
4323
|
+
const card = record(scorecard);
|
|
4324
|
+
if (!card.version) return;
|
|
4325
|
+
const score = card.score === null || card.score === void 0 ? "pending" : `${card.score}%`;
|
|
4326
|
+
console.log(`North Star: ${String(card.status || "unknown")} (${score})`);
|
|
4327
|
+
if (card.moatState) console.log(`Moat state: ${card.moatState}`);
|
|
4328
|
+
const metrics = Array.isArray(card.metrics) ? card.metrics : [];
|
|
4329
|
+
if (metrics.length) {
|
|
4330
|
+
console.log("\nNorth Star gates:");
|
|
4331
|
+
for (const metric of metrics.slice(0, 12)) {
|
|
4332
|
+
const item = record(metric);
|
|
4333
|
+
console.log(`- ${String(item.status || "review").toUpperCase()} ${item.label || item.id}: ${item.detail || ""}`);
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
3783
4337
|
function createCampaignAgentBuildReview(status, rows, artifacts) {
|
|
3784
4338
|
const rowList = Array.isArray(rows?.rows) ? rows.rows : [];
|
|
3785
4339
|
const sampledRows = rowList.length;
|
|
@@ -3898,6 +4452,7 @@ function printCampaignAgentRows(result) {
|
|
|
3898
4452
|
status: row.status || "",
|
|
3899
4453
|
score: row.score ?? ""
|
|
3900
4454
|
})));
|
|
4455
|
+
printCampaignCopySnippets(result.rows);
|
|
3901
4456
|
console.log(`
|
|
3902
4457
|
Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
|
|
3903
4458
|
if (result.nextCursor) {
|
|
@@ -4690,6 +5245,7 @@ async function gtm(sub, rest) {
|
|
|
4690
5245
|
days: numberFlag("days"),
|
|
4691
5246
|
networkDays: numberFlag("network-days"),
|
|
4692
5247
|
minSampleSize: numberFlag("min-sample-size"),
|
|
5248
|
+
holdoutMinSampleSize: numberFlag("holdout-min-sample-size"),
|
|
4693
5249
|
minWorkspaceCount: numberFlag("min-workspace-count"),
|
|
4694
5250
|
limit: numberFlag("limit")
|
|
4695
5251
|
});
|
|
@@ -4700,6 +5256,10 @@ async function gtm(sub, rest) {
|
|
|
4700
5256
|
console.log("GTM Brain learning plan");
|
|
4701
5257
|
console.log(` Campaign: ${campaignId}`);
|
|
4702
5258
|
console.log(` Lanes: ${ready}/${lanes.length} ready`);
|
|
5259
|
+
if (result.holdout_lift?.status) {
|
|
5260
|
+
const delta = result.holdout_lift?.lift?.primary_metric_delta;
|
|
5261
|
+
console.log(` Holdout: ${result.holdout_lift.status}${delta !== void 0 ? ` (${delta} ${result.holdout_lift.primary_metric || "primary_metric"})` : ""}`);
|
|
5262
|
+
}
|
|
4703
5263
|
console.log(` Calls: ${calls.length}`);
|
|
4704
5264
|
for (const call of calls.slice(0, 5)) {
|
|
4705
5265
|
const state = call.ready === false ? "blocked" : "ready";
|
|
@@ -4721,6 +5281,7 @@ async function gtm(sub, rest) {
|
|
|
4721
5281
|
days: numberFlag("days"),
|
|
4722
5282
|
networkDays: numberFlag("network-days"),
|
|
4723
5283
|
minSampleSize: numberFlag("min-sample-size"),
|
|
5284
|
+
holdoutMinSampleSize: numberFlag("holdout-min-sample-size"),
|
|
4724
5285
|
minWorkspaceCount: numberFlag("min-workspace-count"),
|
|
4725
5286
|
minPrivacyK: numberFlag("min-privacy-k"),
|
|
4726
5287
|
limit: numberFlag("limit")
|
|
@@ -4974,6 +5535,103 @@ async function gtm(sub, rest) {
|
|
|
4974
5535
|
hint(`signaliz gtm bootstrap${common.campaignId ? ` --campaign-id ${common.campaignId}` : ""} --include-samples`);
|
|
4975
5536
|
});
|
|
4976
5537
|
}
|
|
5538
|
+
if (sub === "feedback-pull" || sub === "instantly-feedback-pull" || sub === "pull-feedback") {
|
|
5539
|
+
const provider = (flagArg("provider") || "instantly").toLowerCase();
|
|
5540
|
+
if (provider !== "instantly") {
|
|
5541
|
+
die("gtm feedback-pull currently supports --provider instantly. Use gtm feedback-webhook for provider-agnostic ingress.");
|
|
5542
|
+
}
|
|
5543
|
+
const source = flagArg("source") || flagArg("pull-source") || "webhook_events";
|
|
5544
|
+
if (!["webhook_events", "emails"].includes(source)) {
|
|
5545
|
+
die("--source must be webhook_events or emails");
|
|
5546
|
+
}
|
|
5547
|
+
if (flagArg("source") && flagArg("pull-source") && flagArg("source") !== flagArg("pull-source")) {
|
|
5548
|
+
die("--source and --pull-source must match when both are provided");
|
|
5549
|
+
}
|
|
5550
|
+
const campaignId = flagArg("campaign-id");
|
|
5551
|
+
const campaignBuildId = flagArg("campaign-build-id") || flagArg("build-id");
|
|
5552
|
+
const providerLinkId = flagArg("provider-link-id");
|
|
5553
|
+
const providerCampaignId = flagArg("provider-campaign-id") || flagArg("instantly-campaign-id") || positionalAfter(sub);
|
|
5554
|
+
if (!campaignId && !campaignBuildId && !providerLinkId && !providerCampaignId) {
|
|
5555
|
+
die("Usage: signaliz gtm feedback-pull --provider-campaign-id <instantly_campaign_id> [--source webhook_events|emails] [--confirm]");
|
|
5556
|
+
}
|
|
5557
|
+
const hasEmailHistoryFlags = Boolean(flagArg("email-type") || flagArg("mode") || flagArg("sort-order"));
|
|
5558
|
+
if (hasEmailHistoryFlags && source !== "emails") {
|
|
5559
|
+
die("--email-type, --mode, and --sort-order require --source emails");
|
|
5560
|
+
}
|
|
5561
|
+
const emailType = source === "emails" ? flagArg("email-type") || "received" : void 0;
|
|
5562
|
+
if (emailType !== void 0 && !["received", "sent", "manual"].includes(emailType)) {
|
|
5563
|
+
die("--email-type must be received, sent, or manual");
|
|
5564
|
+
}
|
|
5565
|
+
const mode = source === "emails" ? flagArg("mode") || "emode_all" : void 0;
|
|
5566
|
+
if (mode !== void 0 && !["emode_focused", "emode_others", "emode_all"].includes(mode)) {
|
|
5567
|
+
die("--mode must be emode_focused, emode_others, or emode_all");
|
|
5568
|
+
}
|
|
5569
|
+
const sortOrder = source === "emails" ? flagArg("sort-order") || "asc" : void 0;
|
|
5570
|
+
if (sortOrder !== void 0 && !["asc", "desc"].includes(sortOrder)) {
|
|
5571
|
+
die("--sort-order must be asc or desc");
|
|
5572
|
+
}
|
|
5573
|
+
if (hasFlag("write") && !hasFlag("confirm") && !hasFlag("confirm-write")) {
|
|
5574
|
+
die("Write-mode feedback pulls require --confirm or --confirm-write. Run without --confirm first for a dry-run count.");
|
|
5575
|
+
}
|
|
5576
|
+
const confirmed = hasFlag("confirm") || hasFlag("confirm-write");
|
|
5577
|
+
const dryRun = !confirmed;
|
|
5578
|
+
const result = await sdk.gtm.pullInstantlyFeedback({
|
|
5579
|
+
campaignId,
|
|
5580
|
+
campaignBuildId,
|
|
5581
|
+
providerLinkId,
|
|
5582
|
+
providerCampaignId,
|
|
5583
|
+
instantlyCampaignId: flagArg("instantly-campaign-id"),
|
|
5584
|
+
integrationId: flagArg("integration-id"),
|
|
5585
|
+
source,
|
|
5586
|
+
instantlyProfile: flagArg("instantly-profile") || flagArg("profile"),
|
|
5587
|
+
cursor: flagArg("cursor"),
|
|
5588
|
+
from: flagArg("from") || flagArg("since"),
|
|
5589
|
+
to: flagArg("to") || flagArg("until"),
|
|
5590
|
+
limit: numberFlag("limit"),
|
|
5591
|
+
maxPages: numberFlag("max-pages"),
|
|
5592
|
+
emailType,
|
|
5593
|
+
mode,
|
|
5594
|
+
sortOrder,
|
|
5595
|
+
createMemory: !hasFlag("no-memory"),
|
|
5596
|
+
writeRoutineOutcomes: !hasFlag("no-routine-outcomes"),
|
|
5597
|
+
dryRun,
|
|
5598
|
+
runBrainCycle: !hasFlag("no-brain-cycle"),
|
|
5599
|
+
brainCycleWriteMode: flagArg("write-mode") || "dry_run",
|
|
5600
|
+
brainCyclePhases: csvFlag("brain-cycle-phases"),
|
|
5601
|
+
brainCycleMinIngested: numberFlag("brain-cycle-min-ingested"),
|
|
5602
|
+
brainCycleMinIntervalMinutes: numberFlag("brain-cycle-min-interval-minutes")
|
|
5603
|
+
});
|
|
5604
|
+
return output(result, () => {
|
|
5605
|
+
console.log("GTM Instantly feedback pull");
|
|
5606
|
+
console.log(` Mode: ${dryRun ? "dry_run" : "write"}`);
|
|
5607
|
+
console.log(` Source: ${result.source || source}`);
|
|
5608
|
+
if (result.provider_campaign_id || providerCampaignId) console.log(` Campaign: ${result.provider_campaign_id || providerCampaignId}`);
|
|
5609
|
+
if (result.run_id) console.log(` Run ID: ${result.run_id}`);
|
|
5610
|
+
if (result.status) console.log(` Status: ${result.status}`);
|
|
5611
|
+
if (result.max_pages !== void 0) console.log(` Pages: ${result.max_pages}`);
|
|
5612
|
+
const countFields = [
|
|
5613
|
+
["Seen", result.webhook_events_seen ?? result.email_records_seen ?? result.source_events],
|
|
5614
|
+
["Normalized", result.feedback_events_synced ?? result.events_normalized],
|
|
5615
|
+
["Ingested", result.ingested],
|
|
5616
|
+
["Duplicates", result.duplicates],
|
|
5617
|
+
["Unmatched", result.unmatched]
|
|
5618
|
+
];
|
|
5619
|
+
for (const [label, value] of countFields) {
|
|
5620
|
+
if (value !== void 0 && value !== null) console.log(` ${label}: ${value}`);
|
|
5621
|
+
}
|
|
5622
|
+
if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
|
|
5623
|
+
if (dryRun) {
|
|
5624
|
+
if (result.run_id) hint(`signaliz ops run-status ${result.run_id} --watch`);
|
|
5625
|
+
hint("Review the dry-run counts before writing feedback, memory, and outcomes: rerun with --confirm.");
|
|
5626
|
+
} else if (campaignId) {
|
|
5627
|
+
hint(`signaliz gtm learning ${campaignId} --include-network`);
|
|
5628
|
+
} else if (campaignBuildId) {
|
|
5629
|
+
hint(`signaliz gtm execution --campaign-build-id ${campaignBuildId}`);
|
|
5630
|
+
} else {
|
|
5631
|
+
hint("After the pull completes, run signaliz gtm bootstrap --include-samples to verify feedback and memory readiness.");
|
|
5632
|
+
}
|
|
5633
|
+
});
|
|
5634
|
+
}
|
|
4977
5635
|
if (sub === "nango") return gtmNango(rest[0], rest.slice(1));
|
|
4978
5636
|
if (!sub || sub === "list" || sub === "sources") {
|
|
4979
5637
|
const result = await sdk.leads.listNativeGtmCapabilities(flagArg("category"));
|
|
@@ -5034,7 +5692,7 @@ ${i + 1}. ${m.capability_id} (score ${m.score}) \u2014 ${m.label}`);
|
|
|
5034
5692
|
const result = await sdk.leads.checkStatus(jobId);
|
|
5035
5693
|
return output(result);
|
|
5036
5694
|
}
|
|
5037
|
-
die("Usage: signaliz gtm <context|bootstrap|strategy-memory|agent-template|agent-plan|plan|commit-plan|prepare-build|campaigns|campaign|existing-campaigns|audit-existing|memory|learning|execution|integrations|provider-prepare|activate-route|list|find|run|status|nango>");
|
|
5695
|
+
die("Usage: signaliz gtm <context|bootstrap|strategy-memory|agent-template|agent-plan|plan|commit-plan|prepare-build|campaigns|campaign|existing-campaigns|audit-existing|memory|learning|execution|integrations|provider-prepare|activate-route|feedback-webhook|feedback-pull|list|find|run|status|nango>");
|
|
5038
5696
|
}
|
|
5039
5697
|
function nangoActionInput() {
|
|
5040
5698
|
const fromFile = readJsonFlag("input-file");
|
|
@@ -5051,30 +5709,146 @@ function nangoBaseOptions() {
|
|
|
5051
5709
|
nangoConnectionId: flagArg("nango-connection-id")
|
|
5052
5710
|
};
|
|
5053
5711
|
}
|
|
5054
|
-
function nangoConnectOptions() {
|
|
5712
|
+
function nangoConnectOptions(defaultSurface = "gtm_kernel") {
|
|
5055
5713
|
return {
|
|
5056
5714
|
providerId: flagArg("provider-id") || flagArg("provider"),
|
|
5057
5715
|
integrationId: flagArg("integration-id") || flagArg("provider-config-key"),
|
|
5058
5716
|
providerDisplayName: flagArg("provider-display-name") || flagArg("provider-name"),
|
|
5059
5717
|
integrationDisplayName: flagArg("integration-display-name"),
|
|
5060
5718
|
allowedIntegrations: csvFlag("allowed-integrations"),
|
|
5061
|
-
surface: flagArg("surface") ||
|
|
5719
|
+
surface: flagArg("surface") || defaultSurface,
|
|
5062
5720
|
source: flagArg("source") || "signaliz_cli",
|
|
5063
5721
|
userEmail: flagArg("user-email"),
|
|
5064
5722
|
userDisplayName: flagArg("user-display-name")
|
|
5065
5723
|
};
|
|
5066
5724
|
}
|
|
5725
|
+
function nangoPositionalValues(rest = []) {
|
|
5726
|
+
const values = [];
|
|
5727
|
+
for (let index = 0; index < rest.length; index++) {
|
|
5728
|
+
const value = rest[index];
|
|
5729
|
+
if (value.startsWith("--")) {
|
|
5730
|
+
if (!value.includes("=") && rest[index + 1] && !rest[index + 1].startsWith("--")) index++;
|
|
5731
|
+
continue;
|
|
5732
|
+
}
|
|
5733
|
+
values.push(value);
|
|
5734
|
+
}
|
|
5735
|
+
return values;
|
|
5736
|
+
}
|
|
5737
|
+
function nangoFlowOptions(rest = []) {
|
|
5738
|
+
const positionalSearch = nangoPositionalValues(rest).join(" ");
|
|
5739
|
+
const search = flagArg("search") || flagArg("query") || positionalSearch || void 0;
|
|
5740
|
+
return {
|
|
5741
|
+
...nangoBaseOptions(),
|
|
5742
|
+
query: flagArg("query"),
|
|
5743
|
+
search,
|
|
5744
|
+
providerId: flagArg("provider-id") || flagArg("provider"),
|
|
5745
|
+
provider: flagArg("provider"),
|
|
5746
|
+
intent: flagArg("intent"),
|
|
5747
|
+
actionName: flagArg("action-name") || flagArg("action"),
|
|
5748
|
+
toolName: flagArg("tool-name"),
|
|
5749
|
+
proxyPath: flagArg("proxy-path") || flagArg("nango-proxy-path"),
|
|
5750
|
+
method: flagArg("method"),
|
|
5751
|
+
input: nangoActionInput(),
|
|
5752
|
+
cadence: flagArg("cadence"),
|
|
5753
|
+
fieldMap: readInlineJsonFlag("field-map-json") || readJsonFlag("field-map-file"),
|
|
5754
|
+
requiredFields: csvFlag("required-fields") || csvFlag("required-field"),
|
|
5755
|
+
confirmSpend: hasFlag("confirm-spend"),
|
|
5756
|
+
writeConfirmed: hasFlag("write-confirmed") || hasFlag("confirm-write") || void 0,
|
|
5757
|
+
layer: flagArg("layer"),
|
|
5758
|
+
campaignId: flagArg("campaign-id"),
|
|
5759
|
+
limit: numberFlag("limit"),
|
|
5760
|
+
includeProviderCatalog: hasFlag("skip-provider-catalog") ? false : hasFlag("include-provider-catalog") ? true : void 0
|
|
5761
|
+
};
|
|
5762
|
+
}
|
|
5067
5763
|
function nangoStatusUrl(result) {
|
|
5068
5764
|
return result?.status_url || result?.statusUrl || result?.nango_result?.status_url || result?.nango_result?.statusUrl;
|
|
5069
5765
|
}
|
|
5070
|
-
|
|
5766
|
+
function nangoActionId(result) {
|
|
5767
|
+
return result?.action_id || result?.actionId || result?.nango_result?.action_id || result?.nango_result?.actionId || result?.nango_result?.id;
|
|
5768
|
+
}
|
|
5769
|
+
function nangoActionStatus(result) {
|
|
5770
|
+
return result?.status || result?.nango_result?.status;
|
|
5771
|
+
}
|
|
5772
|
+
function isTerminalNangoActionStatus(status) {
|
|
5773
|
+
return ["completed", "succeeded", "success", "failed", "error", "cancelled", "canceled"].includes(String(status || "").toLowerCase());
|
|
5774
|
+
}
|
|
5775
|
+
async function waitForNangoActionResult(nango, call, opts = {}) {
|
|
5776
|
+
const intervalMs = Math.max(250, Number(opts.intervalMs ?? 5e3));
|
|
5777
|
+
const maxPolls = Math.max(1, Math.min(60, Math.trunc(Number(opts.maxPolls ?? 12))));
|
|
5778
|
+
const timeoutMs = Math.max(250, Number(opts.timeoutMs ?? 6e4));
|
|
5779
|
+
let statusUrl = nangoStatusUrl(call);
|
|
5780
|
+
let actionId = nangoActionId(call);
|
|
5781
|
+
let latest = statusUrl || actionId ? void 0 : call;
|
|
5782
|
+
let polls = 0;
|
|
5783
|
+
const startedAt = Date.now();
|
|
5784
|
+
while ((statusUrl || actionId) && polls < maxPolls && Date.now() - startedAt <= timeoutMs) {
|
|
5785
|
+
polls += 1;
|
|
5786
|
+
latest = await nango.getNangoActionResult({ actionId, statusUrl });
|
|
5787
|
+
statusUrl = nangoStatusUrl(latest) || statusUrl;
|
|
5788
|
+
actionId = nangoActionId(latest) || actionId;
|
|
5789
|
+
if (isTerminalNangoActionStatus(nangoActionStatus(latest))) break;
|
|
5790
|
+
if (polls < maxPolls && Date.now() - startedAt < timeoutMs) await sleep(intervalMs);
|
|
5791
|
+
}
|
|
5792
|
+
const status = nangoActionStatus(latest || call);
|
|
5793
|
+
const timedOut = Boolean((statusUrl || actionId) && !isTerminalNangoActionStatus(status) && (polls >= maxPolls || Date.now() - startedAt > timeoutMs));
|
|
5794
|
+
return {
|
|
5795
|
+
call,
|
|
5796
|
+
result: latest,
|
|
5797
|
+
status,
|
|
5798
|
+
action_id: actionId,
|
|
5799
|
+
actionId,
|
|
5800
|
+
status_url: statusUrl,
|
|
5801
|
+
statusUrl,
|
|
5802
|
+
polls,
|
|
5803
|
+
max_polls: maxPolls,
|
|
5804
|
+
maxPolls,
|
|
5805
|
+
interval_ms: intervalMs,
|
|
5806
|
+
intervalMs,
|
|
5807
|
+
timeout_ms: timeoutMs,
|
|
5808
|
+
timeoutMs,
|
|
5809
|
+
timed_out: timedOut,
|
|
5810
|
+
timedOut
|
|
5811
|
+
};
|
|
5812
|
+
}
|
|
5813
|
+
async function gtmNango(sub, rest, namespace = "gtm") {
|
|
5071
5814
|
const sdk = getSdk();
|
|
5815
|
+
const nango = namespace === "ops" ? sdk.ops : sdk.gtm;
|
|
5816
|
+
const commandPrefix = namespace === "ops" ? "signaliz ops nango" : "signaliz gtm nango";
|
|
5817
|
+
const defaultSurface = namespace === "ops" ? "ops_destinations" : "gtm_kernel";
|
|
5818
|
+
if (sub === "flow" || sub === "plan" || sub === "prepare" || sub === "search") {
|
|
5819
|
+
const result = await nango.prepareNangoIntegrationFlow(nangoFlowOptions(rest));
|
|
5820
|
+
return output(result, () => {
|
|
5821
|
+
console.log(`Nango integration flow: ${result?.status || "prepared"}`);
|
|
5822
|
+
if (result?.provider_id) console.log(` Provider: ${result.provider_id}`);
|
|
5823
|
+
if (result?.integration_id) console.log(` Integration: ${result.integration_id}`);
|
|
5824
|
+
if (result?.selected_connection?.id) console.log(` Workspace connection: ${result.selected_connection.id}`);
|
|
5825
|
+
const providers = Array.isArray(result?.provider_library?.providers) ? result.provider_library.providers : [];
|
|
5826
|
+
if (providers.length) {
|
|
5827
|
+
console.log(" Provider matches:");
|
|
5828
|
+
for (const provider of providers.slice(0, 5)) console.log(` - ${provider.name || provider.id} (${provider.id})`);
|
|
5829
|
+
}
|
|
5830
|
+
const connections = Array.isArray(result?.matched_connections) ? result.matched_connections : [];
|
|
5831
|
+
if (connections.length) {
|
|
5832
|
+
console.log(" Saved connections:");
|
|
5833
|
+
for (const connection of connections.slice(0, 5)) {
|
|
5834
|
+
const ready = connection.ready_for_route ? "ready" : connection.needs_attention ? "needs reconnect" : "not ready";
|
|
5835
|
+
console.log(` - ${connection.connector_name || connection.provider_config_key || connection.id}: ${ready} (${connection.id})`);
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
const nextActions = Array.isArray(result?.next_actions) ? result.next_actions : [];
|
|
5839
|
+
if (nextActions.length) {
|
|
5840
|
+
console.log(" Next calls:");
|
|
5841
|
+
for (const action of nextActions.slice(0, 5)) console.log(` - ${action.tool}: ${action.reason || "next step"}`);
|
|
5842
|
+
}
|
|
5843
|
+
if (result?.next_action) hint(result.next_action);
|
|
5844
|
+
});
|
|
5845
|
+
}
|
|
5072
5846
|
if (sub === "connect" || sub === "auth" || sub === "authorize") {
|
|
5073
|
-
const options = nangoConnectOptions();
|
|
5847
|
+
const options = nangoConnectOptions(defaultSurface);
|
|
5074
5848
|
if (!options.providerId && !options.integrationId && (!options.allowedIntegrations || options.allowedIntegrations.length === 0)) {
|
|
5075
|
-
die(
|
|
5849
|
+
die(`Usage: ${commandPrefix} connect --provider-id <provider> [--integration-id <key>] [--allowed-integrations a,b]`);
|
|
5076
5850
|
}
|
|
5077
|
-
const result = await
|
|
5851
|
+
const result = await nango.createNangoConnectSession(options);
|
|
5078
5852
|
return output(result, () => {
|
|
5079
5853
|
console.log(`Nango connect session: ${result?.status || "created"}`);
|
|
5080
5854
|
if (result?.provider_id || options.providerId) console.log(` Provider: ${result?.provider_id || options.providerId}`);
|
|
@@ -5082,11 +5856,11 @@ async function gtmNango(sub, rest) {
|
|
|
5082
5856
|
if (result?.connect_link || result?.auth_window_url) console.log(` Auth link: ${result.connect_link || result.auth_window_url}`);
|
|
5083
5857
|
if (result?.expires_at) console.log(` Expires: ${result.expires_at}`);
|
|
5084
5858
|
if (result?.next_action) console.log(` Next: ${result.next_action}`);
|
|
5085
|
-
hint(
|
|
5859
|
+
hint(`After authorization finishes, run ${commandPrefix} tools --workspace-connection-id <id> --provider-config-key <key>`);
|
|
5086
5860
|
});
|
|
5087
5861
|
}
|
|
5088
5862
|
if (!sub || sub === "tools" || sub === "list") {
|
|
5089
|
-
const result = await
|
|
5863
|
+
const result = await nango.listNangoTools({
|
|
5090
5864
|
...nangoBaseOptions(),
|
|
5091
5865
|
format: flagArg("format"),
|
|
5092
5866
|
includeRaw: hasFlag("include-raw")
|
|
@@ -5097,39 +5871,153 @@ async function gtmNango(sub, rest) {
|
|
|
5097
5871
|
for (const tool of tools2.slice(0, 10)) {
|
|
5098
5872
|
console.log(`- ${tool.name || tool.action_name || tool.id}: ${tool.description || tool.type || "action"}`);
|
|
5099
5873
|
}
|
|
5100
|
-
hint(
|
|
5874
|
+
hint(`${commandPrefix} call <action_name> --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --dry-run`);
|
|
5875
|
+
});
|
|
5876
|
+
}
|
|
5877
|
+
if (namespace === "ops" && (sub === "proof" || sub === "audit" || sub === "read-write")) {
|
|
5878
|
+
const result = await nango.proveNangoReadWrite({
|
|
5879
|
+
...nangoBaseOptions(),
|
|
5880
|
+
limit: numberFlag("limit"),
|
|
5881
|
+
includeRaw: hasFlag("include-raw"),
|
|
5882
|
+
readProxyPath: flagArg("read-proxy-path") || flagArg("proxy-path"),
|
|
5883
|
+
writeProxyPath: flagArg("write-proxy-path"),
|
|
5884
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5885
|
+
executeReadProbe: hasFlag("execute-read-probe"),
|
|
5886
|
+
executeWriteProbe: hasFlag("execute-write-probe"),
|
|
5887
|
+
confirm: hasFlag("confirm"),
|
|
5888
|
+
confirmWrite: hasFlag("confirm-write") || hasFlag("confirm"),
|
|
5889
|
+
input: nangoActionInput(),
|
|
5890
|
+
writeInput: readInlineJsonFlag("write-input-json") || readJsonFlag("write-input-file")
|
|
5891
|
+
});
|
|
5892
|
+
return output(result, () => {
|
|
5893
|
+
const summary = result?.summary || {};
|
|
5894
|
+
const connectedRows = summary.connected_connection_rows ?? summary.connection_rows ?? 0;
|
|
5895
|
+
const connectedUnique = summary.connected_unique_connections ?? summary.unique_connections ?? 0;
|
|
5896
|
+
console.log(`Nango proof: ${result?.status || "unknown"}`);
|
|
5897
|
+
console.log(`Connections: ${summary.connection_rows ?? 0} rows / ${summary.unique_connections ?? 0} unique`);
|
|
5898
|
+
console.log(`Connected: ${connectedRows} rows / ${connectedUnique} unique`);
|
|
5899
|
+
console.log(`Reconnect required: ${summary.reconnect_required ?? summary.needs_attention_connection_rows ?? 0}`);
|
|
5900
|
+
console.log(`Action tools: ${summary.action_tools ?? 0}`);
|
|
5901
|
+
console.log(`Runtime reads: ${summary.runtime_read_verified ?? 0}/${connectedRows}`);
|
|
5902
|
+
console.log(`Writes: ${summary.write_verified ?? 0}/${connectedRows}`);
|
|
5903
|
+
if (summary.duplicate_connection_rows) console.log(`Duplicates: ${summary.duplicate_connection_rows}`);
|
|
5904
|
+
if (summary.duplicate_connected_connection_rows) console.log(`Connected duplicates: ${summary.duplicate_connected_connection_rows}`);
|
|
5905
|
+
if (result?.next_action) console.log(`Next: ${result.next_action}`);
|
|
5906
|
+
});
|
|
5907
|
+
}
|
|
5908
|
+
if (namespace === "ops" && (sub === "schedule" || sub === "recur")) {
|
|
5909
|
+
const promptText = promptArg(rest);
|
|
5910
|
+
if (!promptText) {
|
|
5911
|
+
die(`Usage: ${commandPrefix} ${sub} "plain-English recurring goal" --workspace-connection-id <id> --action-name <action> [--confirm-spend] [--wait]`);
|
|
5912
|
+
}
|
|
5913
|
+
const scheduleInput = {
|
|
5914
|
+
prompt: promptText,
|
|
5915
|
+
blueprint: flagArg("blueprint"),
|
|
5916
|
+
targetCount: numberFlag("target-count"),
|
|
5917
|
+
cadence: flagArg("cadence") || "daily",
|
|
5918
|
+
wakeOnEvents: csvFlag("wake-on-events") || csvFlag("wake-events") || csvFlag("wake-event"),
|
|
5919
|
+
timezone: flagArg("timezone"),
|
|
5920
|
+
companyDomains: csvFlag("company-domains") || csvFlag("domains"),
|
|
5921
|
+
customAiPrompt: flagArg("ai-prompt") || flagArg("custom-ai-prompt"),
|
|
5922
|
+
signalPrompt: flagArg("signal-prompt"),
|
|
5923
|
+
outputPrompt: flagArg("output-prompt") || flagArg("result-prompt"),
|
|
5924
|
+
confirmSpend: hasFlag("confirm-spend"),
|
|
5925
|
+
...nangoBaseOptions(),
|
|
5926
|
+
actionName: flagArg("action-name") || flagArg("action") || flagArg("nango-action"),
|
|
5927
|
+
toolName: flagArg("tool-name"),
|
|
5928
|
+
proxyPath: flagArg("proxy-path") || flagArg("nango-proxy-path"),
|
|
5929
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5930
|
+
input: nangoActionInput(),
|
|
5931
|
+
fieldMap: readInlineJsonFlag("field-map-json") || readJsonFlag("field-map-file"),
|
|
5932
|
+
requiredFields: csvFlag("required-fields") || csvFlag("required-field"),
|
|
5933
|
+
writeConfirmed: hasFlag("write-confirmed") || hasFlag("confirm") || hasFlag("confirm-write") || void 0,
|
|
5934
|
+
agentWriteConfirmed: hasFlag("agent-write-confirmed") || void 0
|
|
5935
|
+
};
|
|
5936
|
+
if (hasFlag("wait")) {
|
|
5937
|
+
const combined = await nango.scheduleNangoActionAndWait({
|
|
5938
|
+
...scheduleInput,
|
|
5939
|
+
force: hasFlag("force"),
|
|
5940
|
+
instruction: flagArg("instruction"),
|
|
5941
|
+
intervalMs: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
5942
|
+
maxPolls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
5943
|
+
timeoutMs: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms"),
|
|
5944
|
+
limit: numberFlag("limit"),
|
|
5945
|
+
cursor: flagArg("cursor"),
|
|
5946
|
+
includeFailedRuns: hasFlag("include-failed-runs"),
|
|
5947
|
+
includeResults: !hasFlag("no-results")
|
|
5948
|
+
});
|
|
5949
|
+
return output(combined, () => {
|
|
5950
|
+
console.log(`Nango Op scheduled: ${combined.schedule?.op_id || combined.op_id}`);
|
|
5951
|
+
printOpsWaitForResults(combined);
|
|
5952
|
+
});
|
|
5953
|
+
}
|
|
5954
|
+
const result = await nango.scheduleNangoAction(scheduleInput);
|
|
5955
|
+
return output(result, () => {
|
|
5956
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
5957
|
+
console.log("Approval required");
|
|
5958
|
+
if (result.plan) {
|
|
5959
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
5960
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
5961
|
+
printPlanSchedule(result.plan);
|
|
5962
|
+
printOpsExecutionContract(result.plan);
|
|
5963
|
+
}
|
|
5964
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after review."}`);
|
|
5965
|
+
hint(`${commandPrefix} ${sub} ${JSON.stringify(promptText)} --confirm-spend`);
|
|
5966
|
+
return;
|
|
5967
|
+
}
|
|
5968
|
+
console.log(`Nango Op scheduled: ${result.op_id}`);
|
|
5969
|
+
console.log(`Status: ${result.status || "scheduled"}`);
|
|
5970
|
+
if (result.plan) printOpsExecutionContract(result.plan);
|
|
5971
|
+
console.log(`Next: ${result.next_action || "Run or wait for the next scheduled tick."}`);
|
|
5972
|
+
if (result.op_id) hint(`signaliz ops wait ${result.op_id}`);
|
|
5101
5973
|
});
|
|
5102
5974
|
}
|
|
5103
5975
|
if (sub === "call" || sub === "run") {
|
|
5104
|
-
const actionName = rest[0] || flagArg("action-name");
|
|
5976
|
+
const actionName = nangoPositionalValues(rest)[0] || flagArg("action-name");
|
|
5105
5977
|
const toolName = flagArg("tool-name");
|
|
5106
|
-
|
|
5107
|
-
|
|
5978
|
+
const proxyPath = flagArg("proxy-path") || flagArg("nango-proxy-path");
|
|
5979
|
+
if (!actionName && !toolName && !proxyPath) {
|
|
5980
|
+
die(`Usage: ${commandPrefix} call <action_name> --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' [--execute --confirm], or ${commandPrefix} call --workspace-connection-id <id> --proxy-path /provider/path --method GET`);
|
|
5108
5981
|
}
|
|
5109
|
-
const
|
|
5982
|
+
const callOptions = {
|
|
5110
5983
|
...nangoBaseOptions(),
|
|
5111
5984
|
actionName,
|
|
5112
5985
|
toolName,
|
|
5986
|
+
deliveryMode: proxyPath ? "proxy" : void 0,
|
|
5987
|
+
proxyPath,
|
|
5988
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5113
5989
|
input: nangoActionInput(),
|
|
5114
|
-
async: hasFlag("async") || void 0,
|
|
5990
|
+
async: hasFlag("async") || hasFlag("wait") || void 0,
|
|
5115
5991
|
maxRetries: numberFlag("max-retries"),
|
|
5116
5992
|
dryRun: hasFlag("execute") ? false : hasFlag("dry-run") ? true : void 0,
|
|
5117
5993
|
confirm: hasFlag("confirm") || void 0,
|
|
5118
5994
|
confirmWrite: hasFlag("confirm-write") || void 0
|
|
5119
|
-
}
|
|
5120
|
-
|
|
5995
|
+
};
|
|
5996
|
+
const waitOptions = {
|
|
5997
|
+
intervalMs: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
5998
|
+
maxPolls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
5999
|
+
timeoutMs: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms")
|
|
6000
|
+
};
|
|
6001
|
+
const waited = hasFlag("wait") && namespace === "ops" ? await nango.callNangoToolAndWait({ ...callOptions, ...waitOptions }) : null;
|
|
6002
|
+
const result = waited?.call || await nango.callNangoTool(callOptions);
|
|
6003
|
+
const finalResult = waited || (hasFlag("wait") ? await waitForNangoActionResult(nango, result, waitOptions) : result);
|
|
6004
|
+
return output(finalResult, () => {
|
|
5121
6005
|
console.log(`Nango action ${result?.status || "submitted"}: ${actionName || toolName}`);
|
|
5122
6006
|
const statusUrl = nangoStatusUrl(result);
|
|
5123
6007
|
if (statusUrl) console.log(` Status URL: ${statusUrl}`);
|
|
6008
|
+
if (finalResult !== result) {
|
|
6009
|
+
console.log(` Result: ${finalResult.status || "unknown"} (${finalResult.polls}/${finalResult.max_polls} polls)`);
|
|
6010
|
+
if (finalResult.timed_out) console.log(" Timed out before a terminal Nango result.");
|
|
6011
|
+
}
|
|
5124
6012
|
if (result?.next_action) console.log(` Next: ${result.next_action}`);
|
|
5125
|
-
if (statusUrl) hint(
|
|
6013
|
+
if (statusUrl && finalResult === result) hint(`${commandPrefix} result --status-url ${statusUrl}`);
|
|
5126
6014
|
});
|
|
5127
6015
|
}
|
|
5128
6016
|
if (sub === "result" || sub === "status") {
|
|
5129
|
-
const actionId = rest[0] || flagArg("action-id");
|
|
6017
|
+
const actionId = nangoPositionalValues(rest)[0] || flagArg("action-id");
|
|
5130
6018
|
const statusUrl = flagArg("status-url");
|
|
5131
|
-
if (!actionId && !statusUrl) die(
|
|
5132
|
-
const result = await
|
|
6019
|
+
if (!actionId && !statusUrl) die(`Usage: ${commandPrefix} result --action-id <id> OR --status-url /action/<id>`);
|
|
6020
|
+
const result = await nango.getNangoActionResult({ actionId, statusUrl });
|
|
5133
6021
|
return output(result, () => {
|
|
5134
6022
|
console.log(`Nango action result: ${result?.status || "unknown"}`);
|
|
5135
6023
|
if (result?.action_id || actionId) console.log(` Action ID: ${result?.action_id || actionId}`);
|
|
@@ -5137,7 +6025,7 @@ async function gtmNango(sub, rest) {
|
|
|
5137
6025
|
if (nextStatusUrl) console.log(` Status URL: ${nextStatusUrl}`);
|
|
5138
6026
|
});
|
|
5139
6027
|
}
|
|
5140
|
-
die(
|
|
6028
|
+
die(`Usage: ${commandPrefix} <flow|search|connect|tools|call|schedule|result>`);
|
|
5141
6029
|
}
|
|
5142
6030
|
async function email(sub, rest) {
|
|
5143
6031
|
const sdk = getSdk();
|
|
@@ -5342,26 +6230,74 @@ async function ops(sub, rest) {
|
|
|
5342
6230
|
const savedRest = sub === "save" ? rest : rest.slice(1);
|
|
5343
6231
|
return opsSaved(savedSub, savedRest);
|
|
5344
6232
|
}
|
|
6233
|
+
if (sub === "nango") return gtmNango(rest[0], rest.slice(1), "ops");
|
|
5345
6234
|
if (sub === "plan" && !promptArg(rest)) {
|
|
5346
6235
|
die('Usage: signaliz ops plan "monitor these companies daily..."');
|
|
5347
6236
|
}
|
|
5348
6237
|
if (sub === "create" && !promptArg(rest)) {
|
|
5349
6238
|
die('Usage: signaliz ops create "build 100 leads that fit..." [--confirm-spend]');
|
|
5350
6239
|
}
|
|
6240
|
+
if ((sub === "schedule" || sub === "recur") && !promptArg(rest)) {
|
|
6241
|
+
die('Usage: signaliz ops schedule "monitor these companies daily..." [--confirm-spend]');
|
|
6242
|
+
}
|
|
5351
6243
|
if (sub === "execute" && !promptArg(rest)) {
|
|
5352
6244
|
die('Usage: signaliz ops execute "launch a campaign for this ICP..." [--dry-run|--confirm-spend]');
|
|
5353
6245
|
}
|
|
5354
6246
|
const sdk = getSdk();
|
|
6247
|
+
const opsOptionalBooleanFlag = (name) => {
|
|
6248
|
+
const value = flagArg(name);
|
|
6249
|
+
if (value !== void 0) return !["0", "false", "no", "off"].includes(value.toLowerCase());
|
|
6250
|
+
return hasFlag(name) ? true : void 0;
|
|
6251
|
+
};
|
|
6252
|
+
const opsNangoDestination = () => {
|
|
6253
|
+
const destination = { type: "nango" };
|
|
6254
|
+
let hasDetails = false;
|
|
6255
|
+
const set = (key, value) => {
|
|
6256
|
+
if (value === void 0 || value === null || value === "") return;
|
|
6257
|
+
destination[key] = value;
|
|
6258
|
+
hasDetails = true;
|
|
6259
|
+
};
|
|
6260
|
+
const nangoAction = flagArg("nango-action");
|
|
6261
|
+
const nangoProxyPath = flagArg("nango-proxy-path");
|
|
6262
|
+
set("connectionId", flagArg("workspace-connection-id") || flagArg("connection-id"));
|
|
6263
|
+
set("providerConfigKey", flagArg("provider-config-key"));
|
|
6264
|
+
set("integrationId", flagArg("integration-id"));
|
|
6265
|
+
set("nangoConnectionId", flagArg("nango-connection-id"));
|
|
6266
|
+
set("actionName", flagArg("action-name") || nangoAction);
|
|
6267
|
+
set("nangoAction", nangoAction);
|
|
6268
|
+
set("proxyPath", flagArg("proxy-path") || nangoProxyPath);
|
|
6269
|
+
set("nangoProxyPath", nangoProxyPath);
|
|
6270
|
+
set("method", flagArg("method") || flagArg("http-method"));
|
|
6271
|
+
set("writeConfirmed", opsOptionalBooleanFlag("write-confirmed"));
|
|
6272
|
+
set("agentWriteConfirmed", opsOptionalBooleanFlag("agent-write-confirmed"));
|
|
6273
|
+
return hasDetails ? destination : void 0;
|
|
6274
|
+
};
|
|
6275
|
+
const isNangoDestinationType = (type) => {
|
|
6276
|
+
const normalized = type.toLowerCase().replace(/[-\s]/g, "_");
|
|
6277
|
+
return ["nango", "api", "managed_api", "customer_api", "external_api", "nango_api"].includes(normalized);
|
|
6278
|
+
};
|
|
5355
6279
|
const opsDestinations = () => {
|
|
5356
6280
|
const destinations = csvFlag("destinations") || csvFlag("destination");
|
|
5357
|
-
|
|
6281
|
+
const nangoDestination = opsNangoDestination();
|
|
6282
|
+
const out = (destinations || []).map((type) => nangoDestination && isNangoDestinationType(type) ? { ...nangoDestination, type } : { type });
|
|
6283
|
+
if (nangoDestination && !out.some((destination) => isNangoDestinationType(String(destination.type)))) {
|
|
6284
|
+
out.push(nangoDestination);
|
|
6285
|
+
}
|
|
6286
|
+
return out.length > 0 ? out : void 0;
|
|
5358
6287
|
};
|
|
6288
|
+
const opsWakeEvents = () => csvFlag("wake-on-events") || csvFlag("wake-events") || csvFlag("wake-event");
|
|
5359
6289
|
const opsCompanyDomains = () => csvFlag("company-domains") || csvFlag("domains");
|
|
5360
6290
|
const opsCustomPrompts = () => ({
|
|
5361
6291
|
custom_ai_prompt: flagArg("ai-prompt") || flagArg("custom-ai-prompt"),
|
|
5362
6292
|
signal_prompt: flagArg("signal-prompt"),
|
|
5363
6293
|
output_prompt: flagArg("output-prompt") || flagArg("result-prompt")
|
|
5364
6294
|
});
|
|
6295
|
+
const printPlanSchedule2 = (plan) => {
|
|
6296
|
+
if (!plan || typeof plan !== "object") return;
|
|
6297
|
+
const wakeEvents = Array.isArray(plan.wake_on_events) ? plan.wake_on_events : plan.wakeOnEvents;
|
|
6298
|
+
console.log(`Schedule: ${plan.cadence || "manual"}`);
|
|
6299
|
+
console.log(`Wake: ${Array.isArray(wakeEvents) && wakeEvents.length ? wakeEvents.join(", ") : "cadence only"}`);
|
|
6300
|
+
};
|
|
5365
6301
|
if (sub === "plan") {
|
|
5366
6302
|
const promptText = promptArg(rest);
|
|
5367
6303
|
const result = await sdk.ops.plan({
|
|
@@ -5369,6 +6305,7 @@ async function ops(sub, rest) {
|
|
|
5369
6305
|
blueprint: flagArg("blueprint"),
|
|
5370
6306
|
target_count: numberFlag("target-count"),
|
|
5371
6307
|
cadence: flagArg("cadence"),
|
|
6308
|
+
wake_on_events: opsWakeEvents(),
|
|
5372
6309
|
destinations: opsDestinations(),
|
|
5373
6310
|
company_domains: opsCompanyDomains(),
|
|
5374
6311
|
...opsCustomPrompts()
|
|
@@ -5378,10 +6315,11 @@ async function ops(sub, rest) {
|
|
|
5378
6315
|
if (result.ui_summary) console.log(`Summary: ${result.ui_summary}`);
|
|
5379
6316
|
console.log(`Status: ${result.status}`);
|
|
5380
6317
|
console.log(`Outcome: ${result.blueprint}`);
|
|
5381
|
-
|
|
6318
|
+
printPlanSchedule2(result);
|
|
5382
6319
|
console.log(`Target: ${result.target_count}`);
|
|
5383
6320
|
console.log(`Credits: ${result.estimated_credits}`);
|
|
5384
6321
|
if (result.destination_status) console.log(`Deliver: ${result.destination_status}`);
|
|
6322
|
+
printOpsExecutionContract(result);
|
|
5385
6323
|
printPrimitiveGraph(result.primitive_graph);
|
|
5386
6324
|
console.log(`Next: ${result.next_action}`);
|
|
5387
6325
|
});
|
|
@@ -5400,6 +6338,26 @@ async function ops(sub, rest) {
|
|
|
5400
6338
|
console.log(`${primary.title}: ${primary.outcome}`);
|
|
5401
6339
|
console.log(`Prompt: ${primary.prompt}`);
|
|
5402
6340
|
console.log(`CLI: ${primary.cli_command}`);
|
|
6341
|
+
const packet = primary.operating_packet || primary.operatingPacket || result.operating_packet || result.operatingPacket;
|
|
6342
|
+
if (packet?.schedule) {
|
|
6343
|
+
console.log(`Schedule: ${packet.schedule.cadence} - ${packet.schedule.recurrence}`);
|
|
6344
|
+
console.log(`Results: ${packet.result_contract?.wait_tool || packet.resultContract?.waitTool || packet.result_contract?.retrieve_tool || packet.resultContract?.retrieveTool || "ops_wait"}`);
|
|
6345
|
+
}
|
|
6346
|
+
const nangoRoute = packet?.nango_route || packet?.nangoRoute;
|
|
6347
|
+
if (nangoRoute?.enabled) {
|
|
6348
|
+
console.log("\nNango route");
|
|
6349
|
+
console.log(`- Discover: ${nangoRoute.discover_tool || nangoRoute.discoverTool}`);
|
|
6350
|
+
console.log(`- Dry run: ${nangoRoute.dry_run_tool || nangoRoute.dryRunTool}`);
|
|
6351
|
+
console.log(`- Execute: ${nangoRoute.execute_tool || nangoRoute.executeTool} after confirm=true`);
|
|
6352
|
+
if (nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool) {
|
|
6353
|
+
console.log(`- Wait: ${nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool}`);
|
|
6354
|
+
}
|
|
6355
|
+
const nangoScheduleTool = nangoRoute.schedule_and_wait_tool || nangoRoute.scheduleAndWaitTool || nangoRoute.schedule_tool || nangoRoute.scheduleTool;
|
|
6356
|
+
if (nangoScheduleTool) {
|
|
6357
|
+
console.log(`- Schedule: ${nangoScheduleTool} after approval`);
|
|
6358
|
+
}
|
|
6359
|
+
console.log(`- Gate: ${nangoRoute.write_gate || nangoRoute.writeGate}`);
|
|
6360
|
+
}
|
|
5403
6361
|
if (primary.mcp_sequence?.length) {
|
|
5404
6362
|
console.log("\nMCP flow");
|
|
5405
6363
|
for (const [index, step] of primary.mcp_sequence.entries()) {
|
|
@@ -5411,22 +6369,49 @@ async function ops(sub, rest) {
|
|
|
5411
6369
|
}
|
|
5412
6370
|
if (sub === "execute") {
|
|
5413
6371
|
const promptText = promptArg(rest);
|
|
6372
|
+
const shouldWait = hasFlag("wait");
|
|
5414
6373
|
const result = await sdk.ops.execute({
|
|
5415
6374
|
prompt: promptText,
|
|
5416
6375
|
blueprint: flagArg("blueprint"),
|
|
5417
6376
|
target_count: numberFlag("target-count"),
|
|
5418
6377
|
cadence: flagArg("cadence"),
|
|
6378
|
+
wake_on_events: opsWakeEvents(),
|
|
6379
|
+
timezone: flagArg("timezone"),
|
|
5419
6380
|
destinations: opsDestinations(),
|
|
5420
6381
|
company_domains: opsCompanyDomains(),
|
|
5421
6382
|
...opsCustomPrompts(),
|
|
5422
6383
|
confirm_spend: hasFlag("confirm-spend"),
|
|
5423
6384
|
dry_run: hasFlag("dry-run"),
|
|
5424
|
-
auto_run: hasFlag("auto-run") ? true : hasFlag("no-auto-run") ? false : void 0,
|
|
6385
|
+
auto_run: hasFlag("auto-run") ? true : hasFlag("no-auto-run") ? false : shouldWait ? true : void 0,
|
|
5425
6386
|
output_format: flagArg("output-format") === "markdown" ? "markdown" : "json"
|
|
5426
6387
|
});
|
|
6388
|
+
if (shouldWait && result.op_id && !result.approval_required && result.error_code !== "APPROVAL_REQUIRED" && !hasFlag("dry-run")) {
|
|
6389
|
+
const waited = await sdk.ops.waitForResults({
|
|
6390
|
+
op_id: result.op_id,
|
|
6391
|
+
...opsWaitOptions()
|
|
6392
|
+
});
|
|
6393
|
+
const combined = {
|
|
6394
|
+
...waited,
|
|
6395
|
+
execute: result,
|
|
6396
|
+
run_id: result.run_id ?? waited.status?.run_id ?? waited.status?.runId,
|
|
6397
|
+
runId: result.runId ?? result.run_id ?? waited.status?.runId ?? waited.status?.run_id,
|
|
6398
|
+
execution_refs: combineExecutionRefs(result.execution_refs, waited.execution_refs)
|
|
6399
|
+
};
|
|
6400
|
+
return output(combined, () => {
|
|
6401
|
+
if (result.run_id || result.runId) console.log(`Run: ${result.run_id || result.runId}`);
|
|
6402
|
+
printOpsWaitForResults(combined);
|
|
6403
|
+
});
|
|
6404
|
+
}
|
|
5427
6405
|
return output(result, () => {
|
|
5428
6406
|
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
5429
6407
|
console.log("Approval required");
|
|
6408
|
+
if (result.plan) {
|
|
6409
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6410
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6411
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6412
|
+
printPlanSchedule2(result.plan);
|
|
6413
|
+
printOpsExecutionContract(result.plan);
|
|
6414
|
+
}
|
|
5430
6415
|
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
5431
6416
|
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
5432
6417
|
hint(`signaliz ops execute ${JSON.stringify(promptText)} --confirm-spend`);
|
|
@@ -5436,13 +6421,19 @@ async function ops(sub, rest) {
|
|
|
5436
6421
|
console.log(`Dry run: ${result.plan.title}`);
|
|
5437
6422
|
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
5438
6423
|
console.log(`Status: ${result.plan.status}`);
|
|
6424
|
+
printPlanSchedule2(result.plan);
|
|
5439
6425
|
console.log(`Credits: ${result.plan.estimated_credits}`);
|
|
6426
|
+
printOpsExecutionContract(result.plan);
|
|
5440
6427
|
console.log(`Next: ${result.next_action || result.plan.next_action}`);
|
|
5441
6428
|
return;
|
|
5442
6429
|
}
|
|
5443
6430
|
console.log(`Op: ${result.op_id || "not created"}`);
|
|
5444
6431
|
if (result.run_id) console.log(`Run: ${result.run_id}`);
|
|
5445
6432
|
console.log(`Status: ${result.status || "unknown"}`);
|
|
6433
|
+
if (result.plan) {
|
|
6434
|
+
printPlanSchedule2(result.plan);
|
|
6435
|
+
printOpsExecutionContract(result.plan);
|
|
6436
|
+
}
|
|
5446
6437
|
console.log(`Next: ${result.next_action || "Check status for progress."}`);
|
|
5447
6438
|
if (result.op_id) hint(`signaliz ops status ${result.op_id}`);
|
|
5448
6439
|
});
|
|
@@ -5505,6 +6496,8 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5505
6496
|
blueprint: flagArg("blueprint"),
|
|
5506
6497
|
target_count: numberFlag("target-count"),
|
|
5507
6498
|
cadence: flagArg("cadence"),
|
|
6499
|
+
wake_on_events: opsWakeEvents(),
|
|
6500
|
+
timezone: flagArg("timezone"),
|
|
5508
6501
|
destinations: opsDestinations(),
|
|
5509
6502
|
company_domains: opsCompanyDomains(),
|
|
5510
6503
|
...opsCustomPrompts(),
|
|
@@ -5512,15 +6505,99 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5512
6505
|
activate: hasFlag("activate")
|
|
5513
6506
|
});
|
|
5514
6507
|
return output(result, () => {
|
|
6508
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
6509
|
+
console.log("Approval required");
|
|
6510
|
+
if (result.plan) {
|
|
6511
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6512
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6513
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6514
|
+
printPlanSchedule2(result.plan);
|
|
6515
|
+
printOpsExecutionContract(result.plan);
|
|
6516
|
+
}
|
|
6517
|
+
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
6518
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
6519
|
+
hint(`signaliz ops create ${JSON.stringify(promptText)} --confirm-spend`);
|
|
6520
|
+
return;
|
|
6521
|
+
}
|
|
5515
6522
|
console.log(`Op created: ${result.op_id}`);
|
|
5516
6523
|
console.log(`Status: ${result.status}`);
|
|
6524
|
+
if (result.plan) {
|
|
6525
|
+
printPlanSchedule2(result.plan);
|
|
6526
|
+
printOpsExecutionContract(result.plan);
|
|
6527
|
+
}
|
|
5517
6528
|
console.log(`Next: ${result.next_action}`);
|
|
5518
6529
|
hint(`signaliz ops run ${result.op_id}`);
|
|
5519
6530
|
});
|
|
5520
6531
|
}
|
|
6532
|
+
if (sub === "schedule" || sub === "recur") {
|
|
6533
|
+
const promptText = promptArg(rest);
|
|
6534
|
+
const shouldWait = hasFlag("wait");
|
|
6535
|
+
const scheduleInput = {
|
|
6536
|
+
prompt: promptText,
|
|
6537
|
+
blueprint: flagArg("blueprint"),
|
|
6538
|
+
target_count: numberFlag("target-count"),
|
|
6539
|
+
cadence: flagArg("cadence") || "daily",
|
|
6540
|
+
wake_on_events: opsWakeEvents(),
|
|
6541
|
+
timezone: flagArg("timezone"),
|
|
6542
|
+
destinations: opsDestinations(),
|
|
6543
|
+
company_domains: opsCompanyDomains(),
|
|
6544
|
+
...opsCustomPrompts(),
|
|
6545
|
+
confirm_spend: hasFlag("confirm-spend")
|
|
6546
|
+
};
|
|
6547
|
+
if (shouldWait) {
|
|
6548
|
+
const combined = await sdk.ops.scheduleAndWait({
|
|
6549
|
+
...scheduleInput,
|
|
6550
|
+
force: hasFlag("force"),
|
|
6551
|
+
instruction: flagArg("instruction"),
|
|
6552
|
+
...opsWaitOptions()
|
|
6553
|
+
});
|
|
6554
|
+
return output(combined, () => {
|
|
6555
|
+
console.log(`Op scheduled: ${combined.schedule?.op_id || combined.op_id}`);
|
|
6556
|
+
printOpsWaitForResults(combined);
|
|
6557
|
+
});
|
|
6558
|
+
}
|
|
6559
|
+
const result = await sdk.ops.schedule(scheduleInput);
|
|
6560
|
+
return output(result, () => {
|
|
6561
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
6562
|
+
console.log("Approval required");
|
|
6563
|
+
if (result.plan) {
|
|
6564
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6565
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6566
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6567
|
+
printPlanSchedule2(result.plan);
|
|
6568
|
+
printOpsExecutionContract(result.plan);
|
|
6569
|
+
}
|
|
6570
|
+
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
6571
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
6572
|
+
hint(`signaliz ops schedule ${JSON.stringify(promptText)} --confirm-spend`);
|
|
6573
|
+
return;
|
|
6574
|
+
}
|
|
6575
|
+
console.log(`Op scheduled: ${result.op_id}`);
|
|
6576
|
+
if (result.run_id) console.log(`Run: ${result.run_id}`);
|
|
6577
|
+
console.log(`Status: ${result.status}`);
|
|
6578
|
+
if (result.plan) {
|
|
6579
|
+
printPlanSchedule2(result.plan);
|
|
6580
|
+
printOpsExecutionContract(result.plan);
|
|
6581
|
+
}
|
|
6582
|
+
console.log(`Next: ${result.next_action}`);
|
|
6583
|
+
if (result.op_id) hint(`signaliz ops run ${result.op_id} --wait --limit 100`);
|
|
6584
|
+
});
|
|
6585
|
+
}
|
|
5521
6586
|
if (sub === "run") {
|
|
5522
6587
|
const opId = rest[0];
|
|
5523
6588
|
if (!opId) die("Usage: signaliz ops run <op_id>");
|
|
6589
|
+
if (hasFlag("wait")) {
|
|
6590
|
+
const result2 = await sdk.ops.runAndWait({
|
|
6591
|
+
op_id: opId,
|
|
6592
|
+
force: hasFlag("force"),
|
|
6593
|
+
instruction: flagArg("instruction"),
|
|
6594
|
+
...opsWaitOptions()
|
|
6595
|
+
});
|
|
6596
|
+
return output(result2, () => {
|
|
6597
|
+
if (result2.run?.run_id || result2.run?.runId) console.log(`Run: ${result2.run.run_id || result2.run.runId}`);
|
|
6598
|
+
printOpsWaitForResults(result2);
|
|
6599
|
+
});
|
|
6600
|
+
}
|
|
5524
6601
|
const result = await sdk.ops.run({ op_id: opId, force: hasFlag("force"), instruction: flagArg("instruction") });
|
|
5525
6602
|
return output(result, () => {
|
|
5526
6603
|
console.log(`Op running: ${result.op_id}`);
|
|
@@ -5553,14 +6630,38 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5553
6630
|
include_failed_runs: hasFlag("include-failed-runs")
|
|
5554
6631
|
});
|
|
5555
6632
|
return output(result, () => {
|
|
5556
|
-
const
|
|
5557
|
-
const
|
|
5558
|
-
|
|
5559
|
-
|
|
6633
|
+
const summary = result.summary || {};
|
|
6634
|
+
const hasMore = summary.has_more ?? summary.hasMore ?? result.has_more ?? result.hasMore;
|
|
6635
|
+
const nextCursor = summary.next_cursor ?? summary.nextCursor ?? result.next_cursor ?? result.nextCursor;
|
|
6636
|
+
const resultsCount = summary.results_count ?? summary.resultsCount ?? result.results_count ?? result.resultsCount ?? 0;
|
|
6637
|
+
const resultsTotal = summary.results_total ?? summary.resultsTotal ?? result.results_total ?? result.resultsTotal;
|
|
6638
|
+
const deliveryStatus = summary.delivery_status ?? summary.deliveryStatus ?? result.delivery_status ?? result.deliveryStatus;
|
|
6639
|
+
const resultsUrl = summary.results_url ?? summary.resultsUrl ?? result.results_url ?? result.resultsUrl;
|
|
6640
|
+
const nextAction = summary.next_action ?? summary.nextAction ?? result.next_action ?? result.nextAction;
|
|
6641
|
+
console.log(`Results: ${resultsCount}${hasMore ? " (more available)" : ""}`);
|
|
6642
|
+
if (summary.label) console.log(`Summary: ${summary.label}`);
|
|
6643
|
+
console.log(`Status: ${summary.status || result.status || "unknown"} (${summary.phase || result.phase || "unknown"})`);
|
|
6644
|
+
if (resultsTotal !== void 0 && resultsTotal !== null) console.log(`Total: ${resultsTotal}`);
|
|
6645
|
+
if (deliveryStatus) console.log(`Deliver: ${deliveryStatus}`);
|
|
6646
|
+
if (resultsUrl) console.log(`Open: ${resultsUrl}`);
|
|
6647
|
+
if (nextAction) console.log(`Next: ${nextAction}`);
|
|
6648
|
+
if (result.results.length) {
|
|
6649
|
+
console.log("\nRows");
|
|
6650
|
+
for (const row of result.results.slice(0, 10)) console.log(JSON.stringify(row));
|
|
6651
|
+
}
|
|
5560
6652
|
if (hasMore && nextCursor) hint(`signaliz ops results ${opId} --cursor ${nextCursor}`);
|
|
5561
6653
|
printExecutionRefs(result.execution_refs);
|
|
5562
6654
|
});
|
|
5563
6655
|
}
|
|
6656
|
+
if (sub === "wait" || sub === "await") {
|
|
6657
|
+
const opId = rest[0] || flagArg("op-id");
|
|
6658
|
+
if (!opId) die("Usage: signaliz ops wait <op_id>");
|
|
6659
|
+
const result = await sdk.ops.waitForResults({
|
|
6660
|
+
op_id: opId,
|
|
6661
|
+
...opsWaitOptions()
|
|
6662
|
+
});
|
|
6663
|
+
return output(result, () => printOpsWaitForResults(result));
|
|
6664
|
+
}
|
|
5564
6665
|
if (sub === "run-status" || sub === "trigger-status" || sub === "watch") {
|
|
5565
6666
|
const runIds = csvFlag("run-ids");
|
|
5566
6667
|
const runId = rest[0] || flagArg("run-id");
|
|
@@ -5889,13 +6990,15 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5889
6990
|
const result = await sdk.ops.attachSinkToRoutine({ routine_id: routineId, sink_id: sinkId });
|
|
5890
6991
|
return output(result);
|
|
5891
6992
|
}
|
|
5892
|
-
die("Usage: signaliz ops <proof|autopilot|plan|execute|quickstart|create|run|status|results|run-status|queue|logs|replay|dashboard|doctor|connections|sinks|routines|routine|attach-sink|saved>");
|
|
6993
|
+
die("Usage: signaliz ops <proof|autopilot|plan|execute|quickstart|create|schedule|run|status|results|wait|nango|run-status|queue|logs|replay|dashboard|doctor|connections|sinks|routines|routine|attach-sink|saved>");
|
|
5893
6994
|
}
|
|
5894
6995
|
var OPS_SHORTCUTS = {
|
|
5895
6996
|
"/plan": "plan",
|
|
5896
6997
|
plan: "plan",
|
|
5897
6998
|
"/goal": "create",
|
|
5898
6999
|
goal: "create",
|
|
7000
|
+
schedule: "schedule",
|
|
7001
|
+
recur: "schedule",
|
|
5899
7002
|
quickstart: "quickstart",
|
|
5900
7003
|
template: "template",
|
|
5901
7004
|
proof: "proof",
|
|
@@ -5904,6 +7007,7 @@ var OPS_SHORTCUTS = {
|
|
|
5904
7007
|
run: "run",
|
|
5905
7008
|
status: "status",
|
|
5906
7009
|
results: "results",
|
|
7010
|
+
wait: "wait",
|
|
5907
7011
|
queue: "queue",
|
|
5908
7012
|
debug: "debug",
|
|
5909
7013
|
watch: "watch",
|