@signaliz/cli 1.0.16 → 1.0.17
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 +39 -3
- package/dist/bin.js +1127 -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;
|
|
@@ -609,6 +649,50 @@ function printExecutionRefs(refs) {
|
|
|
609
649
|
if (ref.replay_command) console.log(` replay: ${ref.replay_command}`);
|
|
610
650
|
}
|
|
611
651
|
}
|
|
652
|
+
function combineExecutionRefs(...groups) {
|
|
653
|
+
const refs = /* @__PURE__ */ new Map();
|
|
654
|
+
for (const group of groups) {
|
|
655
|
+
if (!Array.isArray(group)) continue;
|
|
656
|
+
for (const ref of group) {
|
|
657
|
+
if (!ref?.kind || !ref?.id) continue;
|
|
658
|
+
refs.set(`${ref.kind}:${ref.id}`, ref);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return Array.from(refs.values());
|
|
662
|
+
}
|
|
663
|
+
function opsWaitOptions() {
|
|
664
|
+
return {
|
|
665
|
+
interval_ms: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
666
|
+
max_polls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
667
|
+
timeout_ms: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms"),
|
|
668
|
+
limit: numberFlag("limit"),
|
|
669
|
+
cursor: flagArg("cursor"),
|
|
670
|
+
include_failed_runs: hasFlag("include-failed-runs"),
|
|
671
|
+
include_results: !hasFlag("no-results")
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function printOpsWaitForResults(result) {
|
|
675
|
+
const status = result.status || {};
|
|
676
|
+
console.log(`Op: ${result.op_id || result.opId || status.op_id || status.opId || "unknown"}`);
|
|
677
|
+
console.log(`Status: ${status.status || "unknown"}`);
|
|
678
|
+
console.log(`Phase: ${status.phase || "unknown"}`);
|
|
679
|
+
console.log(`Polls: ${result.polls ?? 0}${result.timed_out || result.timedOut ? " (timed out)" : ""}`);
|
|
680
|
+
if (result.results) {
|
|
681
|
+
const summary = result.results.summary || {};
|
|
682
|
+
const count = summary.results_count ?? summary.resultsCount ?? result.results.results_count ?? result.results.resultsCount ?? 0;
|
|
683
|
+
const total = summary.results_total ?? summary.resultsTotal ?? result.results.results_total ?? result.results.resultsTotal;
|
|
684
|
+
const delivery = summary.delivery_status ?? summary.deliveryStatus ?? result.results.delivery_status ?? result.results.deliveryStatus;
|
|
685
|
+
console.log(`Results: ${count}`);
|
|
686
|
+
if (total !== void 0 && total !== null) console.log(`Total: ${total}`);
|
|
687
|
+
if (delivery) console.log(`Deliver: ${delivery}`);
|
|
688
|
+
if (Array.isArray(result.results.results) && result.results.results.length) {
|
|
689
|
+
console.log("\nRows");
|
|
690
|
+
for (const row of result.results.results.slice(0, 10)) console.log(JSON.stringify(row));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
if (result.next_action || result.nextAction) console.log(`Next: ${result.next_action || result.nextAction}`);
|
|
694
|
+
printExecutionRefs(result.execution_refs || result.executionRefs);
|
|
695
|
+
}
|
|
612
696
|
function printQueueProducerEnvelope(envelope) {
|
|
613
697
|
if (!envelope || typeof envelope !== "object") return;
|
|
614
698
|
const queueName = envelope.queue_name ?? envelope.queueName;
|
|
@@ -635,6 +719,52 @@ function printPrimitiveGraph(primitives) {
|
|
|
635
719
|
console.log(`- ${primitive.id || "unknown"}@${primitive.version || "unknown"} (${primitive.permission_level || "unknown"}, ${retry}, ${concurrency}, ${rate})`);
|
|
636
720
|
}
|
|
637
721
|
}
|
|
722
|
+
function printOpsExecutionContract(plan) {
|
|
723
|
+
const contract = record(plan?.execution_contract || plan?.executionContract);
|
|
724
|
+
if (!Object.keys(contract).length) return;
|
|
725
|
+
const runNow = record(contract.run_now || contract.runNow);
|
|
726
|
+
const schedule = record(contract.schedule);
|
|
727
|
+
const approval = record(contract.approval);
|
|
728
|
+
const monitor = record(contract.monitor);
|
|
729
|
+
const resultContract = record(contract.result_contract || contract.resultContract);
|
|
730
|
+
const sequence = firstArray(contract.sequence);
|
|
731
|
+
const nangoRoute = record(contract.nango_route || contract.nangoRoute);
|
|
732
|
+
const createTool = schedule.create_tool || schedule.createTool || "ops_create";
|
|
733
|
+
const activateTool = schedule.activate_tool || schedule.activateTool || "ops_execute";
|
|
734
|
+
const schedulePath = createTool === activateTool ? String(createTool) : `${createTool} -> ${activateTool}`;
|
|
735
|
+
const statusTool = monitor.status_tool || monitor.statusTool || "ops_status";
|
|
736
|
+
const waitTool = monitor.wait_tool || monitor.waitTool || resultContract.wait_tool || resultContract.waitTool || "ops_wait";
|
|
737
|
+
const resultsTool = monitor.results_tool || monitor.resultsTool || "ops_results";
|
|
738
|
+
const resultShape = firstArray(resultContract.shape).map(String);
|
|
739
|
+
console.log("\nExecution contract");
|
|
740
|
+
console.log(`- Mode: ${contract.mode || "run_once"}`);
|
|
741
|
+
console.log(`- Run now: ${runNow.tool || "ops_execute"}`);
|
|
742
|
+
console.log(`- Schedule: ${schedule.cadence || "manual"} via ${schedulePath}`);
|
|
743
|
+
if (schedule.recurrence) console.log(`- Recurrence: ${schedule.recurrence}`);
|
|
744
|
+
console.log(`- Monitor/results: ${waitTool} (or ${statusTool} -> ${resultsTool})`);
|
|
745
|
+
if (resultShape.length) console.log(`- Result shape: ${resultShape.join(", ")}`);
|
|
746
|
+
if (approval.tool) {
|
|
747
|
+
console.log(`- Approval: ${approval.required ? `${approval.tool} required` : "not required"}${approval.reason ? ` - ${approval.reason}` : ""}`);
|
|
748
|
+
}
|
|
749
|
+
if (sequence.length) {
|
|
750
|
+
console.log(`- Sequence: ${sequence.map((step) => step.tool || "unknown_tool").join(" -> ")}`);
|
|
751
|
+
}
|
|
752
|
+
if (Object.keys(nangoRoute).length) {
|
|
753
|
+
console.log("\nNango API route");
|
|
754
|
+
console.log(`- Connect: ${nangoRoute.connect_tool || nangoRoute.connectTool || "nango_connect_session_create"}`);
|
|
755
|
+
console.log(`- Discover: ${nangoRoute.discover_tool || nangoRoute.discoverTool || "nango_mcp_tools_list"}`);
|
|
756
|
+
console.log(`- Dry run: ${nangoRoute.dry_run_tool || nangoRoute.dryRunTool || "nango_mcp_tool_call"}`);
|
|
757
|
+
console.log(`- Execute: ${nangoRoute.execute_tool || nangoRoute.executeTool || "nango_mcp_tool_call"} after approval`);
|
|
758
|
+
if (nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool) {
|
|
759
|
+
console.log(`- Execute and wait: ${nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool}`);
|
|
760
|
+
}
|
|
761
|
+
const nangoScheduleTool = nangoRoute.schedule_and_wait_tool || nangoRoute.scheduleAndWaitTool || nangoRoute.schedule_tool || nangoRoute.scheduleTool;
|
|
762
|
+
if (nangoScheduleTool) {
|
|
763
|
+
console.log(`- Schedule: ${nangoScheduleTool} after approval`);
|
|
764
|
+
}
|
|
765
|
+
if (nangoRoute.write_gate || nangoRoute.writeGate) console.log(`- Gate: ${nangoRoute.write_gate || nangoRoute.writeGate}`);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
638
768
|
function normalizeSavedCommandArgs(args) {
|
|
639
769
|
const separator = args.indexOf("--");
|
|
640
770
|
const raw = separator === -1 ? args : args.slice(separator + 1);
|
|
@@ -758,7 +888,7 @@ function opsSaved(sub, rest) {
|
|
|
758
888
|
stdio: "inherit",
|
|
759
889
|
env: process.env
|
|
760
890
|
});
|
|
761
|
-
const latest = loadConfig();
|
|
891
|
+
const latest = loadConfig({ refresh: true });
|
|
762
892
|
const latestSaved = latest.saved_commands || {};
|
|
763
893
|
const latestCommand = latestSaved[name];
|
|
764
894
|
if (latestCommand) {
|
|
@@ -943,11 +1073,9 @@ Discovery:
|
|
|
943
1073
|
--category NAME Optional category filter, e.g. ops or enrichment
|
|
944
1074
|
|
|
945
1075
|
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
|
|
1076
|
+
ai multi-model Run Custom AI Enrichment - Multi Model
|
|
1077
|
+
--prompt "..." Prompt/template for each record (required)
|
|
1078
|
+
--records-file FILE JSON array, or object with records/inputs/data
|
|
951
1079
|
--input-file FILE Single JSON record
|
|
952
1080
|
--output-fields a:text,b:number
|
|
953
1081
|
Structured fields to return
|
|
@@ -955,12 +1083,10 @@ AI:
|
|
|
955
1083
|
--pdf-url URL Attach a PDF URL to all records
|
|
956
1084
|
--attachment-file FILE
|
|
957
1085
|
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
|
|
1086
|
+
--attachment-fields a,b
|
|
1087
|
+
Record fields containing attachment URLs/arrays
|
|
1088
|
+
--max-concurrency N Record concurrency, default 3, maximum 5
|
|
1089
|
+
--confirm-spend Required to run spendful AI enrichment
|
|
964
1090
|
|
|
965
1091
|
Lead Generation:
|
|
966
1092
|
lead generate Start a B2B lead-generation job
|
|
@@ -1046,9 +1172,13 @@ GTM Kernel:
|
|
|
1046
1172
|
gtm learning <id> Plan Brain learning for a campaign
|
|
1047
1173
|
--include-network Include privacy-safe network lanes
|
|
1048
1174
|
--write-mode MODE dry_run or write
|
|
1175
|
+
--holdout-min-sample-size N
|
|
1176
|
+
Minimum control/treatment subjects for measured lift
|
|
1049
1177
|
gtm learning-run <id> Queue ready Brain learning phases
|
|
1050
1178
|
--phases a,b Optional phase allow-list
|
|
1051
1179
|
--write-mode MODE dry_run or write, default dry_run
|
|
1180
|
+
--holdout-min-sample-size N
|
|
1181
|
+
Minimum control/treatment subjects for measured lift
|
|
1052
1182
|
gtm calibrate <id> Calibrate deliverability predictions
|
|
1053
1183
|
--min-sample-size N Default server-side
|
|
1054
1184
|
--write Write calibrations/patterns; otherwise dry-run
|
|
@@ -1072,6 +1202,12 @@ GTM Kernel:
|
|
|
1072
1202
|
--provider NAME instantly, smartlead, heyreach, airbyte, custom_webhook
|
|
1073
1203
|
--campaign-id ID Optional campaign scope
|
|
1074
1204
|
--write-mode MODE Brain-cycle mode, default dry_run
|
|
1205
|
+
gtm feedback-pull Pull Instantly feedback into the learning loop
|
|
1206
|
+
--source SOURCE webhook_events or emails, default webhook_events
|
|
1207
|
+
--campaign-id ID Optional campaign scope
|
|
1208
|
+
--provider-campaign-id ID
|
|
1209
|
+
Instantly campaign id
|
|
1210
|
+
--confirm Write feedback/memory rows; otherwise dry-run
|
|
1075
1211
|
|
|
1076
1212
|
Native GTM Data Sources:
|
|
1077
1213
|
Use these when you already know the exact source you want to run.
|
|
@@ -1164,8 +1300,12 @@ Campaign Builder:
|
|
|
1164
1300
|
campaign rows <id> Retrieve build rows
|
|
1165
1301
|
--limit N Page size (default: 50, max: 500)
|
|
1166
1302
|
--cursor <id> Pagination cursor
|
|
1303
|
+
--include-data Include generated copy and rich row data
|
|
1304
|
+
--include-raw Include raw provider payloads
|
|
1167
1305
|
--all Dump all rows (caution: unbounded)
|
|
1168
1306
|
campaign artifacts <id> List artifacts with download URLs
|
|
1307
|
+
campaign download <id> Generate fresh signed artifact URLs
|
|
1308
|
+
--format csv|ndjson Artifact format (default: csv)
|
|
1169
1309
|
campaign approve <id> Approve pending delivery
|
|
1170
1310
|
--destination-type json|csv|webhook
|
|
1171
1311
|
--destination-id ID Optional destination/sink ID
|
|
@@ -1173,12 +1313,18 @@ Campaign Builder:
|
|
|
1173
1313
|
campaign cancel <id> Cancel a running build
|
|
1174
1314
|
|
|
1175
1315
|
Ops:
|
|
1176
|
-
Canonical path: ops plan -> ops
|
|
1316
|
+
Canonical path: ops plan -> ops execute -> ops wait
|
|
1177
1317
|
ops plan "..." Preview a prompt-first Op plan
|
|
1178
1318
|
--blueprint NAME monitor_companies|build_leads|enrich_list|route_signals|launch_campaign
|
|
1179
1319
|
--target-count N Target row count
|
|
1180
1320
|
--cadence NAME manual|hourly|daily|weekly
|
|
1321
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1181
1322
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1323
|
+
--workspace-connection-id ID
|
|
1324
|
+
Nango workspace connection for API delivery
|
|
1325
|
+
--provider-config-key KEY
|
|
1326
|
+
Nango integration/provider key
|
|
1327
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1182
1328
|
--company-domains a,b
|
|
1183
1329
|
Company domains for monitor/list-based Ops
|
|
1184
1330
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
@@ -1195,7 +1341,21 @@ Ops:
|
|
|
1195
1341
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1196
1342
|
--auto-run Run immediately after create when safe
|
|
1197
1343
|
--no-auto-run Create only
|
|
1344
|
+
--wait Auto-run, poll status, and fetch results
|
|
1345
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1346
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1347
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1348
|
+
--limit N Result rows after terminal status
|
|
1349
|
+
--no-results Stop after final status without fetching results
|
|
1350
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
1351
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1352
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1198
1353
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1354
|
+
--workspace-connection-id ID
|
|
1355
|
+
Nango workspace connection for API delivery
|
|
1356
|
+
--provider-config-key KEY
|
|
1357
|
+
Nango integration/provider key
|
|
1358
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1199
1359
|
--company-domains a,b
|
|
1200
1360
|
Company domains for monitor/list-based Ops
|
|
1201
1361
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
@@ -1204,19 +1364,78 @@ Ops:
|
|
|
1204
1364
|
ops create "..." Create an Op from a prompt
|
|
1205
1365
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1206
1366
|
--activate Create as active instead of draft
|
|
1367
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
1368
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1369
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1370
|
+
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1371
|
+
--workspace-connection-id ID
|
|
1372
|
+
Nango workspace connection for API delivery
|
|
1373
|
+
--provider-config-key KEY
|
|
1374
|
+
Nango integration/provider key
|
|
1375
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1376
|
+
--company-domains a,b
|
|
1377
|
+
Company domains for monitor/list-based Ops
|
|
1378
|
+
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
1379
|
+
--signal-prompt TEXT Custom signal-finding instruction
|
|
1380
|
+
--output-prompt TEXT Clean result formatting instruction
|
|
1381
|
+
ops schedule "..." Create and activate a recurring Op, daily by default
|
|
1382
|
+
ops recur "..." Alias for ops schedule
|
|
1383
|
+
--confirm-spend Acknowledge estimated credits/external writes
|
|
1384
|
+
--wait Run first tick and fetch results through ops_schedule_and_wait
|
|
1385
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1386
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1387
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1388
|
+
--limit N Result rows after terminal status
|
|
1389
|
+
--cadence NAME hourly|daily|weekly (default: daily)
|
|
1390
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
1391
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1207
1392
|
--destinations a,b Destinations such as slack,csv,google_sheets,webhook,airbyte,nango
|
|
1393
|
+
--workspace-connection-id ID
|
|
1394
|
+
Nango workspace connection for API delivery
|
|
1395
|
+
--provider-config-key KEY
|
|
1396
|
+
Nango integration/provider key
|
|
1397
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1208
1398
|
--company-domains a,b
|
|
1209
1399
|
Company domains for monitor/list-based Ops
|
|
1210
1400
|
--ai-prompt TEXT Custom AI enrichment or scoring instruction
|
|
1211
1401
|
--signal-prompt TEXT Custom signal-finding instruction
|
|
1212
1402
|
--output-prompt TEXT Clean result formatting instruction
|
|
1213
1403
|
ops run <op_id> Run an Op immediately
|
|
1404
|
+
--wait Poll status and fetch results after queueing
|
|
1405
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
1406
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
1407
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
1408
|
+
--limit N Result rows after terminal status
|
|
1409
|
+
--no-results Stop after final status without fetching results
|
|
1214
1410
|
ops status <op_id> Check simple Op status
|
|
1215
1411
|
ops results <op_id> Retrieve latest Op results
|
|
1216
1412
|
--limit N Page size, default 100, max 500
|
|
1217
1413
|
--cursor ID Pagination cursor
|
|
1218
1414
|
--include-failed-runs
|
|
1219
1415
|
Include failed run output when supported
|
|
1416
|
+
ops wait <op_id> Wait for an Op and return results (MCP parity: ops_wait)
|
|
1417
|
+
--interval-ms N Polling interval, default 5000
|
|
1418
|
+
--max-polls N Polling limit, default 12, max 30
|
|
1419
|
+
--timeout-ms N Total wait timeout, default 60000
|
|
1420
|
+
--limit N Result page size after terminal status
|
|
1421
|
+
--no-results Stop after final status without fetching results
|
|
1422
|
+
ops nango <subcommand> Connect, discover, call, schedule, and poll Nango tools
|
|
1423
|
+
flow|search Prepare a provider search/connect/Ops route plan
|
|
1424
|
+
connect Start Nango Connect auth for a provider
|
|
1425
|
+
tools List action tools for a workspace connection
|
|
1426
|
+
call <action> Dry-run or execute a Nango action
|
|
1427
|
+
proof|audit|read-write
|
|
1428
|
+
Audit connected rows and optional live read/write probes
|
|
1429
|
+
--read-proxy-path PATH
|
|
1430
|
+
Provider API path for approved live read proof
|
|
1431
|
+
--write-proxy-path PATH
|
|
1432
|
+
Provider API path for approved live write proof
|
|
1433
|
+
--execute-read-probe --confirm
|
|
1434
|
+
Run the read probe
|
|
1435
|
+
--execute-write-probe --confirm-write
|
|
1436
|
+
Run the write probe with safe test input
|
|
1437
|
+
schedule|recur Create a recurring Nango-backed Op; add --wait for first results
|
|
1438
|
+
result Poll async Nango action result
|
|
1220
1439
|
ops run-status <run_id>
|
|
1221
1440
|
Inspect a Trigger.dev run or batch with --run-ids a,b
|
|
1222
1441
|
--watch Poll until all runs reach a terminal state
|
|
@@ -1367,6 +1586,7 @@ Status and repair:
|
|
|
1367
1586
|
provider-prepare Build read-only recipe, route, and preview arguments
|
|
1368
1587
|
activate-route Dry-run or confirm provider route setup
|
|
1369
1588
|
feedback-webhook Prepare feedback ingress
|
|
1589
|
+
feedback-pull Dry-run or confirm Instantly feedback pull
|
|
1370
1590
|
learning <id> Plan Brain learning
|
|
1371
1591
|
learning-run <id> Queue Brain learning phases
|
|
1372
1592
|
calibrate <id> Calibrate deliverability
|
|
@@ -1770,6 +1990,35 @@ Options:
|
|
|
1770
1990
|
readiness: `signaliz gtm readiness <campaign_id> [options]
|
|
1771
1991
|
|
|
1772
1992
|
Alias for signaliz gtm execution.
|
|
1993
|
+
`,
|
|
1994
|
+
"feedback-pull": `signaliz gtm feedback-pull [options]
|
|
1995
|
+
|
|
1996
|
+
Dry-run or confirm an Instantly feedback pull. Dry-run is the default and
|
|
1997
|
+
counts provider records without writing feedback rows, memory, routine outcomes,
|
|
1998
|
+
or sync cursors. Confirmed writes require --confirm or --confirm-write.
|
|
1999
|
+
|
|
2000
|
+
Options:
|
|
2001
|
+
--source SOURCE webhook_events or emails, default webhook_events
|
|
2002
|
+
--provider-campaign-id ID
|
|
2003
|
+
Instantly campaign id
|
|
2004
|
+
--campaign-id ID Optional linked GTM campaign id
|
|
2005
|
+
--campaign-build-id ID Optional Campaign Builder build id
|
|
2006
|
+
--provider-link-id ID Optional provider link id
|
|
2007
|
+
--integration-id ID Optional Instantly integration id
|
|
2008
|
+
--from DATE Webhook-event pull window start
|
|
2009
|
+
--to DATE Webhook-event pull window end
|
|
2010
|
+
--limit N Page size, default server-side, max 100
|
|
2011
|
+
--max-pages N Max pages, default server-side, max 20
|
|
2012
|
+
--email-type TYPE received, sent, or manual when source=emails
|
|
2013
|
+
--mode MODE emode_focused, emode_others, or emode_all
|
|
2014
|
+
--sort-order ORDER asc or desc
|
|
2015
|
+
--no-memory Do not create memory rows on confirmed writes
|
|
2016
|
+
--no-routine-outcomes Do not write routine outcomes
|
|
2017
|
+
--no-brain-cycle Do not queue feedback-triggered Brain learning
|
|
2018
|
+
--write-mode MODE Brain-cycle mode, default dry_run
|
|
2019
|
+
--confirm Write feedback/memory rows; otherwise dry-run
|
|
2020
|
+
--confirm-write Alias for --confirm
|
|
2021
|
+
--json Machine-readable output
|
|
1773
2022
|
`,
|
|
1774
2023
|
campaigns: `signaliz gtm campaigns [options]
|
|
1775
2024
|
|
|
@@ -1834,7 +2083,13 @@ Options:
|
|
|
1834
2083
|
--blueprint NAME monitor_companies|build_leads|enrich_list|route_signals|launch_campaign
|
|
1835
2084
|
--target-count N Target row count
|
|
1836
2085
|
--cadence NAME manual|hourly|daily|weekly
|
|
2086
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1837
2087
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2088
|
+
--workspace-connection-id ID
|
|
2089
|
+
Nango workspace connection for API delivery
|
|
2090
|
+
--provider-config-key KEY
|
|
2091
|
+
Nango integration/provider key
|
|
2092
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1838
2093
|
--company-domains a,b Explicit account/domain list
|
|
1839
2094
|
--json Machine-readable output
|
|
1840
2095
|
|
|
@@ -1850,12 +2105,52 @@ Options:
|
|
|
1850
2105
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1851
2106
|
--activate Create as active instead of draft
|
|
1852
2107
|
--target-count N Target row count
|
|
2108
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
2109
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2110
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1853
2111
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2112
|
+
--workspace-connection-id ID
|
|
2113
|
+
Nango workspace connection for API delivery
|
|
2114
|
+
--provider-config-key KEY
|
|
2115
|
+
Nango integration/provider key
|
|
2116
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1854
2117
|
--company-domains a,b Explicit account/domain list
|
|
1855
2118
|
--json Machine-readable output
|
|
1856
2119
|
|
|
1857
2120
|
Safe next step:
|
|
1858
2121
|
signaliz ops run <op_id>
|
|
2122
|
+
`,
|
|
2123
|
+
schedule: `signaliz ops schedule "plain-English recurring GTM goal" [options]
|
|
2124
|
+
|
|
2125
|
+
Create and activate a recurring Op from a prompt. Defaults to daily cadence
|
|
2126
|
+
unless --cadence is provided. Requires --confirm-spend for spendful work.
|
|
2127
|
+
|
|
2128
|
+
Options:
|
|
2129
|
+
--confirm-spend Acknowledge estimated credits/external writes
|
|
2130
|
+
--wait Create the recurring Op, run the first tick, and fetch results
|
|
2131
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2132
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2133
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2134
|
+
--limit N Result rows after terminal status
|
|
2135
|
+
--target-count N Target row count
|
|
2136
|
+
--cadence NAME hourly|daily|weekly (default: daily)
|
|
2137
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2138
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
2139
|
+
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2140
|
+
--workspace-connection-id ID
|
|
2141
|
+
Nango workspace connection for API delivery
|
|
2142
|
+
--provider-config-key KEY
|
|
2143
|
+
Nango integration/provider key
|
|
2144
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
2145
|
+
--company-domains a,b Explicit account/domain list
|
|
2146
|
+
--json Machine-readable output
|
|
2147
|
+
|
|
2148
|
+
Safe next step:
|
|
2149
|
+
signaliz ops status <op_id>
|
|
2150
|
+
`,
|
|
2151
|
+
recur: `signaliz ops recur "plain-English recurring GTM goal" [options]
|
|
2152
|
+
|
|
2153
|
+
Alias for signaliz ops schedule.
|
|
1859
2154
|
`,
|
|
1860
2155
|
execute: `signaliz ops execute "plain-English GTM goal" [options]
|
|
1861
2156
|
|
|
@@ -1866,13 +2161,38 @@ Options:
|
|
|
1866
2161
|
--confirm-spend Acknowledge estimated credits/external writes
|
|
1867
2162
|
--auto-run Run immediately after create when safe
|
|
1868
2163
|
--no-auto-run Create only
|
|
2164
|
+
--wait Auto-run, poll status, and fetch results
|
|
2165
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2166
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2167
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2168
|
+
--limit N Result rows to return after terminal status
|
|
2169
|
+
--no-results Stop after final status without fetching results
|
|
1869
2170
|
--target-count N Target row count
|
|
2171
|
+
--cadence NAME manual|hourly|daily|weekly
|
|
2172
|
+
--timezone TZ IANA timezone for recurring Ops, e.g. America/Phoenix
|
|
2173
|
+
--wake-on-events a,b Event triggers such as company_funded,crm.updated
|
|
1870
2174
|
--destinations a,b Destinations such as json,csv,slack,airbyte,nango
|
|
2175
|
+
--workspace-connection-id ID
|
|
2176
|
+
Nango workspace connection for API delivery
|
|
2177
|
+
--provider-config-key KEY
|
|
2178
|
+
Nango integration/provider key
|
|
2179
|
+
--action-name NAME Nango action; use --proxy-path PATH for proxy mode
|
|
1871
2180
|
--json Machine-readable output
|
|
1872
2181
|
`,
|
|
1873
2182
|
run: `signaliz ops run <op_id> [options]
|
|
1874
2183
|
|
|
1875
2184
|
Run a created Op immediately.
|
|
2185
|
+
|
|
2186
|
+
Options:
|
|
2187
|
+
--force Force a run when supported
|
|
2188
|
+
--instruction TEXT Optional run instruction
|
|
2189
|
+
--wait Poll status and fetch results after queueing
|
|
2190
|
+
--interval-ms N Polling interval for --wait, default 5000
|
|
2191
|
+
--max-polls N Polling limit for --wait, default 12, max 30
|
|
2192
|
+
--timeout-ms N Total wait timeout for --wait, default 60000
|
|
2193
|
+
--limit N Result rows to return after terminal status
|
|
2194
|
+
--no-results Stop after final status without fetching results
|
|
2195
|
+
--json Machine-readable output
|
|
1876
2196
|
`,
|
|
1877
2197
|
status: `signaliz ops status <op_id> [options]
|
|
1878
2198
|
|
|
@@ -1887,6 +2207,51 @@ Options:
|
|
|
1887
2207
|
--cursor ID Pagination cursor
|
|
1888
2208
|
--include-failed-runs Include failed run output when supported
|
|
1889
2209
|
--json Machine-readable output
|
|
2210
|
+
`,
|
|
2211
|
+
wait: `signaliz ops wait <op_id> [options]
|
|
2212
|
+
|
|
2213
|
+
Poll Op status until it completes, blocks, fails, or needs action, then fetch
|
|
2214
|
+
the latest results automatically.
|
|
2215
|
+
|
|
2216
|
+
Options:
|
|
2217
|
+
--interval-ms N Polling interval, default 5000
|
|
2218
|
+
--max-polls N Polling limit, default 12, max 30
|
|
2219
|
+
--timeout-ms N Total wait timeout, default 60000
|
|
2220
|
+
--limit N Result rows to return after terminal status
|
|
2221
|
+
--include-failed-runs Include failed run output when fetching results
|
|
2222
|
+
--no-results Only wait for terminal status; do not fetch results
|
|
2223
|
+
--json Machine-readable output
|
|
2224
|
+
`,
|
|
2225
|
+
nango: `signaliz ops nango <flow|search|connect|tools|call|proof|schedule|result> [options]
|
|
2226
|
+
|
|
2227
|
+
Connect and operate customer-owned vendor APIs through Nango from the Ops
|
|
2228
|
+
namespace. This is the Ops-first route for "connect to any tool, do the work,
|
|
2229
|
+
and get the result" flows.
|
|
2230
|
+
|
|
2231
|
+
Examples:
|
|
2232
|
+
signaliz ops nango search hubspot
|
|
2233
|
+
signaliz ops nango connect --provider-id hubspot
|
|
2234
|
+
signaliz ops nango tools --workspace-connection-id <id> --provider-config-key hubspot
|
|
2235
|
+
signaliz ops nango call upsert-contact --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --dry-run
|
|
2236
|
+
signaliz ops nango call --workspace-connection-id <id> --proxy-path /v2/leads/list --method GET --dry-run
|
|
2237
|
+
signaliz ops nango call upsert-contact --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --execute --confirm --wait
|
|
2238
|
+
signaliz ops nango proof --json
|
|
2239
|
+
signaliz ops nango proof --workspace-connection-id <id> --read-proxy-path /v2/accounts --execute-read-probe --confirm
|
|
2240
|
+
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
|
|
2241
|
+
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
|
|
2242
|
+
signaliz ops nango result --status-url /action/<action_id>
|
|
2243
|
+
|
|
2244
|
+
Subcommands:
|
|
2245
|
+
flow|search Prepare provider search, connect, action, and Ops route calls
|
|
2246
|
+
connect Start Nango Connect auth for a provider
|
|
2247
|
+
tools List Nango action tools for a workspace connection
|
|
2248
|
+
call <action> Dry-run by default; add --execute --confirm for approved writes, --wait for result readback
|
|
2249
|
+
accepts --proxy-path for direct Nango proxy mode
|
|
2250
|
+
proof|audit|read-write Audit connected Nango rows, tools, proxy readiness, and optional live read/write probes
|
|
2251
|
+
accepts --read-proxy-path, --write-proxy-path, --execute-read-probe, --execute-write-probe
|
|
2252
|
+
schedule|recur PROMPT Create a recurring Nango-backed Op through ops_nango_schedule; --wait uses ops_nango_schedule_and_wait
|
|
2253
|
+
accepts --input-json/--input-file, --field-map-json, and --required-fields
|
|
2254
|
+
result Poll async Nango action result
|
|
1890
2255
|
`
|
|
1891
2256
|
};
|
|
1892
2257
|
function opsHelpFor(sub) {
|
|
@@ -1901,7 +2266,7 @@ Canonical path:
|
|
|
1901
2266
|
signaliz ops results <op_id>
|
|
1902
2267
|
|
|
1903
2268
|
Common commands:
|
|
1904
|
-
proof, autopilot, plan, execute, create, run, status, results, doctor, connections
|
|
2269
|
+
proof, autopilot, plan, execute, create, schedule, run, status, results, wait, nango, doctor, connections
|
|
1905
2270
|
|
|
1906
2271
|
Run: signaliz ops help <command>
|
|
1907
2272
|
`;
|
|
@@ -1932,6 +2297,13 @@ Options:
|
|
|
1932
2297
|
--outputs json,csv Delivery outputs, default json
|
|
1933
2298
|
--dry-run Validate and plan without launching spendful work
|
|
1934
2299
|
--allow-downscale Allow oversized target counts to be clamped
|
|
2300
|
+
--learning-holdout Assign explicit control vs learned cohorts
|
|
2301
|
+
--holdout-control-percentage N
|
|
2302
|
+
Control share, e.g. 0.2 or 20 for 20%
|
|
2303
|
+
--holdout-min-control-size N
|
|
2304
|
+
Minimum control rows for large builds, default 50
|
|
2305
|
+
--holdout-experiment-key KEY
|
|
2306
|
+
Stable experiment key for feedback attribution
|
|
1935
2307
|
--confirm-spend Acknowledge spendful generation
|
|
1936
2308
|
--input-file FILE JSON config file from campaign scope or gtm prepare-build
|
|
1937
2309
|
--wait Poll until completion
|
|
@@ -1953,12 +2325,22 @@ Options:
|
|
|
1953
2325
|
--cursor ID Pagination cursor
|
|
1954
2326
|
--qualified Only qualified rows
|
|
1955
2327
|
--disqualified Only disqualified rows
|
|
2328
|
+
--include-data Include rich row data such as generated copy
|
|
2329
|
+
--include-raw Include raw provider/qualification payloads
|
|
1956
2330
|
--all Dump all rows
|
|
1957
2331
|
--json Machine-readable output
|
|
1958
2332
|
`,
|
|
1959
2333
|
artifacts: `signaliz campaign artifacts <campaign_build_id> [options]
|
|
1960
2334
|
|
|
1961
2335
|
List generated artifacts and signed download URLs.
|
|
2336
|
+
`,
|
|
2337
|
+
download: `signaliz campaign download <campaign_build_id> [options]
|
|
2338
|
+
|
|
2339
|
+
Generate fresh signed URLs for a downloadable artifact.
|
|
2340
|
+
|
|
2341
|
+
Options:
|
|
2342
|
+
--format csv|ndjson Artifact format, default csv
|
|
2343
|
+
--json Machine-readable output
|
|
1962
2344
|
`,
|
|
1963
2345
|
approve: `signaliz campaign approve <campaign_build_id> --destination-type <json|csv|webhook>
|
|
1964
2346
|
|
|
@@ -1979,9 +2361,10 @@ Canonical path:
|
|
|
1979
2361
|
signaliz campaign build --prompt "VP Sales at B2B SaaS" --confirm-spend --wait
|
|
1980
2362
|
signaliz campaign rows <campaign_build_id> --limit 100
|
|
1981
2363
|
signaliz campaign artifacts <campaign_build_id>
|
|
2364
|
+
signaliz campaign download <campaign_build_id> --format csv
|
|
1982
2365
|
|
|
1983
2366
|
Commands:
|
|
1984
|
-
scope, build, status, rows, artifacts, approve, cancel
|
|
2367
|
+
scope, build, status, rows, artifacts, download, approve, cancel
|
|
1985
2368
|
|
|
1986
2369
|
Run: signaliz campaign help <command>
|
|
1987
2370
|
`;
|
|
@@ -2394,20 +2777,20 @@ function aiAttachmentsFromFlags() {
|
|
|
2394
2777
|
}
|
|
2395
2778
|
async function ai(sub, rest) {
|
|
2396
2779
|
if (sub !== "multi-model" && sub !== "multimodel") {
|
|
2397
|
-
die('Usage: signaliz ai multi-model --prompt "..." --
|
|
2780
|
+
die('Usage: signaliz ai multi-model --prompt "..." --confirm-spend');
|
|
2781
|
+
}
|
|
2782
|
+
if (flagArg("model") !== void 0 || hasFlag("model") || flagArg("analysis-models") !== void 0 || hasFlag("analysis-models") || flagArg("judge-model") !== void 0 || hasFlag("judge-model")) {
|
|
2783
|
+
die("Custom AI model selection is no longer supported. Signaliz-hosted custom AI uses the default model and returns model readback metadata.");
|
|
2398
2784
|
}
|
|
2399
2785
|
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.");
|
|
2786
|
+
if (!promptText) die('Usage: signaliz ai multi-model --prompt "..." --confirm-spend');
|
|
2403
2787
|
if (!hasFlag("confirm-spend")) {
|
|
2404
|
-
die("This
|
|
2788
|
+
die("This runs custom AI enrichment and can spend credits. Re-run with --confirm-spend to approve.");
|
|
2405
2789
|
}
|
|
2406
2790
|
const sdk = getSdk();
|
|
2407
2791
|
const records = aiRecordsFromFlags();
|
|
2408
2792
|
const result = await sdk.ai.multiModel({
|
|
2409
2793
|
prompt: promptText,
|
|
2410
|
-
model,
|
|
2411
2794
|
records,
|
|
2412
2795
|
systemPrompt: flagArg("system-prompt"),
|
|
2413
2796
|
temperature: numberFlag("temperature"),
|
|
@@ -2418,15 +2801,12 @@ async function ai(sub, rest) {
|
|
|
2418
2801
|
attachmentFields: csvFlag("attachment-fields") || csvFlag("attachment-field"),
|
|
2419
2802
|
pdfEngine: flagArg("pdf-engine"),
|
|
2420
2803
|
fusion: {
|
|
2421
|
-
required: !hasFlag("no-require-fusion"),
|
|
2422
|
-
analysis_models: csvFlag("analysis-models"),
|
|
2423
|
-
judge_model: flagArg("judge-model"),
|
|
2424
2804
|
include_raw_analysis: hasFlag("include-raw-analysis")
|
|
2425
2805
|
}
|
|
2426
2806
|
});
|
|
2427
2807
|
return output(result, () => {
|
|
2428
2808
|
console.log("Custom AI Enrichment - Multi Model complete");
|
|
2429
|
-
console.log(` Model: ${result.model ||
|
|
2809
|
+
console.log(` Model: ${result.model || "google/gemini-2.5-flash"}`);
|
|
2430
2810
|
console.log(` Records: ${result.results.length}`);
|
|
2431
2811
|
console.log(` Credits: ${result.creditsUsed}`);
|
|
2432
2812
|
console.log(` Attachments: ${result.multimodalCount}`);
|
|
@@ -2462,6 +2842,16 @@ async function campaignBuild() {
|
|
|
2462
2842
|
if (hasFlag("dry-run")) config.dryRun = true;
|
|
2463
2843
|
if (hasFlag("allow-downscale")) config.allowDownscale = true;
|
|
2464
2844
|
if (hasFlag("confirm-spend")) config.confirmSpend = true;
|
|
2845
|
+
if (hasFlag("learning-holdout") || flagArg("holdout-control-percentage") || flagArg("holdout-min-control-size") || flagArg("holdout-experiment-key")) {
|
|
2846
|
+
config.learningHoldout = {
|
|
2847
|
+
enabled: true,
|
|
2848
|
+
controlPercentage: numberFlag("holdout-control-percentage") ?? 0.2,
|
|
2849
|
+
minControlSize: numberFlag("holdout-min-control-size") ?? 50,
|
|
2850
|
+
experimentKey: flagArg("holdout-experiment-key") || void 0,
|
|
2851
|
+
sourceCampaignId: flagArg("holdout-source-campaign-id") || void 0,
|
|
2852
|
+
primaryMetric: flagArg("holdout-primary-metric") || void 0
|
|
2853
|
+
};
|
|
2854
|
+
}
|
|
2465
2855
|
const outputs = (flagArg("outputs") || "json").split(",").map((s) => s.trim());
|
|
2466
2856
|
const webhookUrl = flagArg("webhook-url");
|
|
2467
2857
|
if (outputs.includes("csv") || outputs.includes("webhook") || webhookUrl) {
|
|
@@ -2504,6 +2894,7 @@ async function campaignBuild() {
|
|
|
2504
2894
|
console.log(` Planned: ${result.plannedTargetCount ?? result.requestedTargetCount ?? config.targetCount ?? 50} leads`);
|
|
2505
2895
|
if (result.estimatedCredits !== void 0) console.log(` Credits: ~${result.estimatedCredits}`);
|
|
2506
2896
|
if (result.estimatedDurationSeconds !== void 0) console.log(` Duration: ~${result.estimatedDurationSeconds}s`);
|
|
2897
|
+
if (result.learningHoldout?.enabled) console.log(` Holdout: enabled (${Math.round(Number(result.learningHoldout.control_percentage || 0) * 100)}% control)`);
|
|
2507
2898
|
if (result.targetLimitApplied) console.log(` Note: ${result.targetLimitReason || "target count downscaled"}`);
|
|
2508
2899
|
hint("Remove --dry-run and add --confirm-spend when ready to launch.");
|
|
2509
2900
|
});
|
|
@@ -2517,6 +2908,7 @@ async function campaignBuild() {
|
|
|
2517
2908
|
console.log(` Status: ${result.status}`);
|
|
2518
2909
|
console.log(` Phase: ${result.currentPhase}`);
|
|
2519
2910
|
console.log(` Target: ${config.targetCount || 50} leads`);
|
|
2911
|
+
if (result.learningHoldout?.enabled) console.log(` Holdout: enabled (${Math.round(Number(result.learningHoldout.control_percentage || 0) * 100)}% control)`);
|
|
2520
2912
|
hint(`signaliz campaign status ${result.campaignBuildId}`);
|
|
2521
2913
|
});
|
|
2522
2914
|
}
|
|
@@ -2546,6 +2938,7 @@ async function campaignBuild() {
|
|
|
2546
2938
|
\u2713 Build ${finalStatus.status}`);
|
|
2547
2939
|
console.log(` Rows: ${finalStatus.recordsSucceeded}/${finalStatus.recordsTotal} succeeded`);
|
|
2548
2940
|
console.log(` Artifacts: ${finalStatus.artifactCount}`);
|
|
2941
|
+
printCampaignArtifactDownloadHint(finalStatus, result.campaignBuildId);
|
|
2549
2942
|
if (finalStatus.status === "completed") {
|
|
2550
2943
|
hint(`signaliz campaign rows ${result.campaignBuildId} --limit 100`);
|
|
2551
2944
|
}
|
|
@@ -2589,6 +2982,35 @@ async function campaignScope() {
|
|
|
2589
2982
|
hint("Next: run signaliz campaign build --input-file with the buildCampaignArgs JSON, or call build_campaign with the returned dry-run args.");
|
|
2590
2983
|
});
|
|
2591
2984
|
}
|
|
2985
|
+
function campaignArtifactDownloads(status) {
|
|
2986
|
+
const downloads = Array.isArray(status?.artifactDownloads) ? status.artifactDownloads : Array.isArray(status?.artifact_downloads) ? status.artifact_downloads : [];
|
|
2987
|
+
return downloads.map(record);
|
|
2988
|
+
}
|
|
2989
|
+
function campaignArtifactDownloadUrl(download) {
|
|
2990
|
+
const url = download.downloadUrl || download.download_url || download.signedUrl || download.signed_url;
|
|
2991
|
+
return typeof url === "string" && url.trim() ? url.trim() : null;
|
|
2992
|
+
}
|
|
2993
|
+
function campaignPreferredArtifactDownload(status) {
|
|
2994
|
+
const downloads = campaignArtifactDownloads(status);
|
|
2995
|
+
if (downloads.length === 0) return null;
|
|
2996
|
+
return downloads.find((download) => {
|
|
2997
|
+
const format = String(download.format || download.artifactType || download.artifact_type || "").toLowerCase();
|
|
2998
|
+
return format === "csv";
|
|
2999
|
+
}) || downloads[0];
|
|
3000
|
+
}
|
|
3001
|
+
function printCampaignArtifactDownloadHint(status, buildId) {
|
|
3002
|
+
const download = campaignPreferredArtifactDownload(status);
|
|
3003
|
+
const url = download ? campaignArtifactDownloadUrl(download) : null;
|
|
3004
|
+
if (url) {
|
|
3005
|
+
const format = String(download?.format || download?.artifactType || download?.artifact_type || "artifact");
|
|
3006
|
+
const rowCount = Number(download?.rowCount ?? download?.row_count ?? 0);
|
|
3007
|
+
console.log(`Download: ${format}${rowCount > 0 ? `, ${rowCount} rows` : ""}`);
|
|
3008
|
+
console.log(` ${url}`);
|
|
3009
|
+
return;
|
|
3010
|
+
}
|
|
3011
|
+
const artifactCount = Number(status?.artifactCount ?? status?.artifact_count ?? 0);
|
|
3012
|
+
if (artifactCount > 0) hint(`signaliz campaign download ${buildId} --format csv`);
|
|
3013
|
+
}
|
|
2592
3014
|
async function campaignStatus() {
|
|
2593
3015
|
const buildId = positionalAfter("status") || flagArg("campaign-build-id");
|
|
2594
3016
|
if (!buildId) die("Usage: signaliz campaign status <campaign_build_id>");
|
|
@@ -2600,7 +3022,9 @@ async function campaignStatus() {
|
|
|
2600
3022
|
console.log(`Status: ${status.status}`);
|
|
2601
3023
|
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
2602
3024
|
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
3025
|
+
printCampaignCustomerRowCounts(status);
|
|
2603
3026
|
console.log(`Artifacts: ${status.artifactCount}`);
|
|
3027
|
+
printCampaignArtifactDownloadHint(status, buildId);
|
|
2604
3028
|
if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
|
|
2605
3029
|
if (status.staleRunningPhase) {
|
|
2606
3030
|
const age = typeof status.phaseAgeSeconds === "number" ? `${status.phaseAgeSeconds}s` : "unknown age";
|
|
@@ -2614,12 +3038,18 @@ async function campaignStatus() {
|
|
|
2614
3038
|
console.log(`Errors: ${status.errors.length}`);
|
|
2615
3039
|
for (const error of status.errors.slice(0, 3)) console.log(` - ${error}`);
|
|
2616
3040
|
}
|
|
2617
|
-
if (status.status === "completed") {
|
|
3041
|
+
if (status.status === "completed" && status.nextAction) {
|
|
3042
|
+
hint(status.nextAction);
|
|
3043
|
+
} else if (status.status === "completed") {
|
|
2618
3044
|
hint(`signaliz campaign rows ${buildId} --limit 100`);
|
|
2619
3045
|
} else if (status.staleRunningPhase && status.triggerRunId) {
|
|
2620
3046
|
hint(`signaliz ops run-status ${status.triggerRunId} --watch`);
|
|
2621
3047
|
} else if (status.status === "running" || status.status === "queued") {
|
|
2622
3048
|
hint(`signaliz campaign status ${buildId} (poll again in ~10s)`);
|
|
3049
|
+
} else if (status.status === "pending_approval" && status.approvalAction) {
|
|
3050
|
+
hint(status.approvalAction);
|
|
3051
|
+
} else if (status.status === "pending_approval" && status.nextAction) {
|
|
3052
|
+
hint(status.nextAction);
|
|
2623
3053
|
} else if (status.status === "pending_approval") {
|
|
2624
3054
|
hint(`signaliz campaign approve ${buildId} --destination-type webhook`);
|
|
2625
3055
|
} else if (status.status === "failed" && status.nextAction) {
|
|
@@ -2627,6 +3057,22 @@ async function campaignStatus() {
|
|
|
2627
3057
|
}
|
|
2628
3058
|
});
|
|
2629
3059
|
}
|
|
3060
|
+
function printCampaignCustomerRowCounts(status) {
|
|
3061
|
+
const counts = status?.customerRowCounts || status?.customer_row_counts;
|
|
3062
|
+
if (!counts || typeof counts !== "object") return;
|
|
3063
|
+
const value = (camel, snake) => counts[camel] ?? counts[snake] ?? "n/a";
|
|
3064
|
+
const requested = value("requestedTarget", "requested_target");
|
|
3065
|
+
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")}`);
|
|
3066
|
+
const shortfalls = [
|
|
3067
|
+
["accepted", value("acceptedShortfall", "accepted_shortfall")],
|
|
3068
|
+
["usable", value("usableShortfall", "usable_shortfall")],
|
|
3069
|
+
["QA-ready", value("qaReadyShortfall", "qa_ready_shortfall")],
|
|
3070
|
+
["delivery", value("deliveryShortfall", "delivery_shortfall")]
|
|
3071
|
+
].filter(([, count]) => typeof count === "number" && count > 0);
|
|
3072
|
+
if (shortfalls.length > 0) {
|
|
3073
|
+
console.log(`Shortfalls: ${shortfalls.map(([label, count]) => `${label} ${count}`).join(", ")}`);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
2630
3076
|
async function campaignRows() {
|
|
2631
3077
|
const buildId = positionalAfter("rows") || flagArg("campaign-build-id");
|
|
2632
3078
|
if (!buildId) die("Usage: signaliz campaign rows <campaign_build_id>");
|
|
@@ -2641,6 +3087,8 @@ async function campaignRows() {
|
|
|
2641
3087
|
do {
|
|
2642
3088
|
const opts = { limit: Math.min(limit, 500) };
|
|
2643
3089
|
if (nextCursor) opts.cursor = nextCursor;
|
|
3090
|
+
if (hasFlag("include-data")) opts.includeData = true;
|
|
3091
|
+
if (hasFlag("include-raw")) opts.includeRaw = true;
|
|
2644
3092
|
const segment = flagArg("segment");
|
|
2645
3093
|
if (segment) opts.segment = segment;
|
|
2646
3094
|
const rowStatus = flagArg("row-status");
|
|
@@ -2665,6 +3113,8 @@ async function campaignRows() {
|
|
|
2665
3113
|
} else {
|
|
2666
3114
|
const opts = { limit: Math.min(limit, 500) };
|
|
2667
3115
|
if (cursor) opts.cursor = cursor;
|
|
3116
|
+
if (hasFlag("include-data")) opts.includeData = true;
|
|
3117
|
+
if (hasFlag("include-raw")) opts.includeRaw = true;
|
|
2668
3118
|
const segment = flagArg("segment");
|
|
2669
3119
|
if (segment) opts.segment = segment;
|
|
2670
3120
|
const rowStatus = flagArg("row-status");
|
|
@@ -2690,6 +3140,7 @@ async function campaignRows() {
|
|
|
2690
3140
|
status: r.status || "",
|
|
2691
3141
|
score: r.score ?? ""
|
|
2692
3142
|
})));
|
|
3143
|
+
printCampaignCopySnippets(operatorResult.rows);
|
|
2693
3144
|
console.log(`
|
|
2694
3145
|
Showing ${operatorResult.rows.length} row(s)${operatorResult.hasMore ? " (more available)" : ""}`);
|
|
2695
3146
|
if (operatorResult.nextCursor) {
|
|
@@ -2702,14 +3153,15 @@ function formatCampaignRowsForOperator(rows) {
|
|
|
2702
3153
|
return rows.map((row) => {
|
|
2703
3154
|
const rowRecord = record(row);
|
|
2704
3155
|
const data = record(rowRecord.data);
|
|
3156
|
+
const copyData = record(data.copy);
|
|
2705
3157
|
const rawCopy = record(data.raw_copy);
|
|
2706
3158
|
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
|
|
3159
|
+
subject: data.subject || copyData.subject || rawCopy.subject || null,
|
|
3160
|
+
opener: data.opener || copyData.opener || rawCopy.opener || null,
|
|
3161
|
+
body: data.body || copyData.body || rawCopy.body || null,
|
|
3162
|
+
cta: data.cta || copyData.cta || rawCopy.cta || null,
|
|
3163
|
+
engine: data.copy_engine || copyData.engine || rawCopy.engine || null,
|
|
3164
|
+
model: data.copy_model || copyData.model || null
|
|
2713
3165
|
};
|
|
2714
3166
|
return {
|
|
2715
3167
|
...rowRecord,
|
|
@@ -2739,6 +3191,26 @@ function formatCampaignRowsForOperator(rows) {
|
|
|
2739
3191
|
};
|
|
2740
3192
|
});
|
|
2741
3193
|
}
|
|
3194
|
+
function printCampaignCopySnippets(rows, limit = 5) {
|
|
3195
|
+
const rowsWithCopy = rows.filter((row) => {
|
|
3196
|
+
const copy = record(row.copy);
|
|
3197
|
+
return Boolean(copy.subject || copy.opener || copy.body || copy.cta);
|
|
3198
|
+
});
|
|
3199
|
+
if (rowsWithCopy.length === 0) return;
|
|
3200
|
+
console.log("\nCopy:");
|
|
3201
|
+
for (const row of rowsWithCopy.slice(0, limit)) {
|
|
3202
|
+
const copy = record(row.copy);
|
|
3203
|
+
const label = row.email || row.name || row.company || `row ${row.index ?? ""}`.toString().trim();
|
|
3204
|
+
console.log(`- ${label}`);
|
|
3205
|
+
if (copy.subject) console.log(` Subject: ${copy.subject}`);
|
|
3206
|
+
if (copy.opener) console.log(` Opener: ${copy.opener}`);
|
|
3207
|
+
if (copy.body) console.log(` Body: ${copy.body}`);
|
|
3208
|
+
if (copy.cta) console.log(` CTA: ${copy.cta}`);
|
|
3209
|
+
}
|
|
3210
|
+
if (rowsWithCopy.length > limit) {
|
|
3211
|
+
console.log(` ...${rowsWithCopy.length - limit} more row(s) with copy`);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
2742
3214
|
async function campaignArtifacts() {
|
|
2743
3215
|
const buildId = positionalAfter("artifacts") || flagArg("campaign-build-id");
|
|
2744
3216
|
if (!buildId) die("Usage: signaliz campaign artifacts <campaign_build_id>");
|
|
@@ -2756,6 +3228,24 @@ async function campaignArtifacts() {
|
|
|
2756
3228
|
}
|
|
2757
3229
|
});
|
|
2758
3230
|
}
|
|
3231
|
+
async function campaignDownload() {
|
|
3232
|
+
const buildId = positionalAfter("download") || flagArg("campaign-build-id");
|
|
3233
|
+
if (!buildId) die("Usage: signaliz campaign download <campaign_build_id> [--format csv|ndjson]");
|
|
3234
|
+
const sdk = getSdk();
|
|
3235
|
+
const format = flagArg("format") || "csv";
|
|
3236
|
+
const result = await sdk.campaigns.downloadCampaignArtifact(buildId, { format });
|
|
3237
|
+
output(result, () => {
|
|
3238
|
+
console.log(`Artifact: ${result.format} (${result.rowCount} rows)`);
|
|
3239
|
+
if (result.partCount > 1) console.log(`Parts: ${result.partCount}`);
|
|
3240
|
+
const parts = Array.isArray(result.parts) ? result.parts : [];
|
|
3241
|
+
for (const part of parts) {
|
|
3242
|
+
const url = part.signedUrl;
|
|
3243
|
+
if (!url) continue;
|
|
3244
|
+
const label = result.partCount > 1 ? `part ${part.partIndex}` : "download";
|
|
3245
|
+
console.log(`${label}: ${url}`);
|
|
3246
|
+
}
|
|
3247
|
+
});
|
|
3248
|
+
}
|
|
2759
3249
|
async function campaignApprove() {
|
|
2760
3250
|
const buildId = positionalAfter("approve") || positionalAfter("approve-delivery") || flagArg("campaign-build-id");
|
|
2761
3251
|
if (!buildId) die("Usage: signaliz campaign approve <campaign_build_id> --destination-type <json|csv|webhook>");
|
|
@@ -2811,6 +3301,8 @@ async function campaign(sub) {
|
|
|
2811
3301
|
return campaignRows();
|
|
2812
3302
|
case "artifacts":
|
|
2813
3303
|
return campaignArtifacts();
|
|
3304
|
+
case "download":
|
|
3305
|
+
return campaignDownload();
|
|
2814
3306
|
case "approve":
|
|
2815
3307
|
case "approve-delivery":
|
|
2816
3308
|
return campaignApprove();
|
|
@@ -2818,7 +3310,7 @@ async function campaign(sub) {
|
|
|
2818
3310
|
return campaignCancel();
|
|
2819
3311
|
default:
|
|
2820
3312
|
die(`Unknown campaign subcommand: ${sub}
|
|
2821
|
-
Available: scope, build, status, rows, artifacts, approve, cancel`);
|
|
3313
|
+
Available: scope, build, status, rows, artifacts, download, approve, cancel`);
|
|
2822
3314
|
}
|
|
2823
3315
|
}
|
|
2824
3316
|
var CAMPAIGN_AGENT_APPROVAL_TYPES = [
|
|
@@ -2864,9 +3356,9 @@ Examples:
|
|
|
2864
3356
|
signaliz campaign-agent dry-run --goal "Build a local services campaign" --target-count 250 --use-local-leads --json
|
|
2865
3357
|
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign" --confirm-launch --approve-all --approved-by operator@example.com --spend-limit 500
|
|
2866
3358
|
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
|
|
3359
|
+
signaliz campaign-agent review <campaign_build_id> --limit 100 --include-data --json
|
|
2868
3360
|
signaliz campaign-agent status <campaign_build_id> --json
|
|
2869
|
-
signaliz campaign-agent rows <campaign_build_id> --limit 100 --json
|
|
3361
|
+
signaliz campaign-agent rows <campaign_build_id> --limit 100 --include-data --json
|
|
2870
3362
|
|
|
2871
3363
|
Plan options:
|
|
2872
3364
|
--goal TEXT Campaign goal or brief
|
|
@@ -2874,7 +3366,7 @@ Plan options:
|
|
|
2874
3366
|
--kit-file FILE Write campaign-agent kit output to a JSON file
|
|
2875
3367
|
--seed-manifest-file FILE
|
|
2876
3368
|
Manifest path for memory-kit seed dry-runs
|
|
2877
|
-
--source NAME memory-kit seed source: agency, workflow-patterns, instantly-feedback, or all
|
|
3369
|
+
--source NAME memory-kit seed source: north-star, agency, workflow-patterns, instantly-feedback, or all
|
|
2878
3370
|
--request-output-file FILE
|
|
2879
3371
|
Request filename to reference inside kit commands
|
|
2880
3372
|
--request-file FILE Reusable JSON CampaignBuilderAgentRequest; flags override file fields
|
|
@@ -3118,6 +3610,8 @@ async function campaignAgentReview(sub, rest) {
|
|
|
3118
3610
|
cursor: commandStringFlag(flags, "cursor"),
|
|
3119
3611
|
segment: commandStringFlag(flags, "segment"),
|
|
3120
3612
|
rowStatus: commandStringFlag(flags, "row-status"),
|
|
3613
|
+
includeData: commandOptionalBooleanFlag(flags, "include-data"),
|
|
3614
|
+
includeRaw: commandOptionalBooleanFlag(flags, "include-raw"),
|
|
3121
3615
|
qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
|
|
3122
3616
|
};
|
|
3123
3617
|
const review = await agent.reviewBuild?.(buildId, rowOptions) || await campaignAgentBuildReviewFromCampaignApis(agent, campaigns, buildId, rowOptions);
|
|
@@ -3141,6 +3635,8 @@ async function campaignAgentReview(sub, rest) {
|
|
|
3141
3635
|
cursor: commandStringFlag(flags, "cursor"),
|
|
3142
3636
|
segment: commandStringFlag(flags, "segment"),
|
|
3143
3637
|
rowStatus: commandStringFlag(flags, "row-status"),
|
|
3638
|
+
includeData: commandOptionalBooleanFlag(flags, "include-data"),
|
|
3639
|
+
includeRaw: commandOptionalBooleanFlag(flags, "include-raw"),
|
|
3144
3640
|
qualified: commandBooleanFlag(flags, "qualified") ? true : commandBooleanFlag(flags, "disqualified") ? false : void 0
|
|
3145
3641
|
};
|
|
3146
3642
|
const result2 = await (agent.getBuildRows?.bind(agent) || campaigns.rows?.bind(campaigns) || campaigns.getCampaignBuildRows?.bind(campaigns))?.(buildId, rowOptions);
|
|
@@ -3732,7 +4228,9 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
3732
4228
|
console.log(`Status: ${status.status}`);
|
|
3733
4229
|
console.log(`Phase: ${status.currentPhase || "N/A"}`);
|
|
3734
4230
|
console.log(`Rows: ${status.recordsSucceeded}/${status.recordsTotal} succeeded, ${status.recordsFailed} failed`);
|
|
4231
|
+
printCampaignCustomerRowCounts(status);
|
|
3735
4232
|
console.log(`Artifacts: ${status.artifactCount}`);
|
|
4233
|
+
if (status.campaignBuildId) printCampaignArtifactDownloadHint(status, status.campaignBuildId);
|
|
3736
4234
|
if (status.triggerRunId) console.log(`Trigger: ${status.triggerRunId}`);
|
|
3737
4235
|
if (Array.isArray(status.warnings) && status.warnings.length) {
|
|
3738
4236
|
console.log(`Warnings: ${status.warnings.length}`);
|
|
@@ -3742,8 +4240,14 @@ function printCampaignAgentBuildStatus(status) {
|
|
|
3742
4240
|
console.log(`Errors: ${status.errors.length}`);
|
|
3743
4241
|
for (const error of status.errors.slice(0, 3)) console.log(` - ${error}`);
|
|
3744
4242
|
}
|
|
3745
|
-
if (status.status === "completed") {
|
|
4243
|
+
if (status.status === "completed" && status.nextAction) {
|
|
4244
|
+
hint(status.nextAction);
|
|
4245
|
+
} else if (status.status === "completed") {
|
|
3746
4246
|
hint(`signaliz campaign-agent rows ${status.campaignBuildId} --limit 100`);
|
|
4247
|
+
} else if (status.status === "pending_approval" && status.approvalAction) {
|
|
4248
|
+
hint(status.approvalAction);
|
|
4249
|
+
} else if (status.status === "pending_approval" && status.nextAction) {
|
|
4250
|
+
hint(status.nextAction);
|
|
3747
4251
|
} else if (status.status === "pending_approval") {
|
|
3748
4252
|
hint(`signaliz campaign-agent approve ${status.campaignBuildId} --destination-type webhook`);
|
|
3749
4253
|
} else if ((status.status === "running" || status.status === "queued") && status.triggerRunId) {
|
|
@@ -3761,6 +4265,7 @@ function printCampaignAgentBuildReview(review) {
|
|
|
3761
4265
|
console.log(`Emails: ${summary.rowsWithEmail || 0}`);
|
|
3762
4266
|
console.log(`Copy ready: ${summary.copyReadyRows || 0}`);
|
|
3763
4267
|
console.log(`Artifacts: ${summary.artifactCount || 0}`);
|
|
4268
|
+
if (review.campaignBuildId) printCampaignArtifactDownloadHint(status, review.campaignBuildId);
|
|
3764
4269
|
console.log(`Delivery approval ready: ${summary.readyForDeliveryApproval === true ? "yes" : "no"}`);
|
|
3765
4270
|
const gates = Array.isArray(review.gates) ? review.gates : [];
|
|
3766
4271
|
if (gates.length) {
|
|
@@ -3898,6 +4403,7 @@ function printCampaignAgentRows(result) {
|
|
|
3898
4403
|
status: row.status || "",
|
|
3899
4404
|
score: row.score ?? ""
|
|
3900
4405
|
})));
|
|
4406
|
+
printCampaignCopySnippets(result.rows);
|
|
3901
4407
|
console.log(`
|
|
3902
4408
|
Showing ${result.rows.length} row(s)${result.hasMore ? " (more available)" : ""}`);
|
|
3903
4409
|
if (result.nextCursor) {
|
|
@@ -4690,6 +5196,7 @@ async function gtm(sub, rest) {
|
|
|
4690
5196
|
days: numberFlag("days"),
|
|
4691
5197
|
networkDays: numberFlag("network-days"),
|
|
4692
5198
|
minSampleSize: numberFlag("min-sample-size"),
|
|
5199
|
+
holdoutMinSampleSize: numberFlag("holdout-min-sample-size"),
|
|
4693
5200
|
minWorkspaceCount: numberFlag("min-workspace-count"),
|
|
4694
5201
|
limit: numberFlag("limit")
|
|
4695
5202
|
});
|
|
@@ -4700,6 +5207,10 @@ async function gtm(sub, rest) {
|
|
|
4700
5207
|
console.log("GTM Brain learning plan");
|
|
4701
5208
|
console.log(` Campaign: ${campaignId}`);
|
|
4702
5209
|
console.log(` Lanes: ${ready}/${lanes.length} ready`);
|
|
5210
|
+
if (result.holdout_lift?.status) {
|
|
5211
|
+
const delta = result.holdout_lift?.lift?.primary_metric_delta;
|
|
5212
|
+
console.log(` Holdout: ${result.holdout_lift.status}${delta !== void 0 ? ` (${delta} ${result.holdout_lift.primary_metric || "primary_metric"})` : ""}`);
|
|
5213
|
+
}
|
|
4703
5214
|
console.log(` Calls: ${calls.length}`);
|
|
4704
5215
|
for (const call of calls.slice(0, 5)) {
|
|
4705
5216
|
const state = call.ready === false ? "blocked" : "ready";
|
|
@@ -4721,6 +5232,7 @@ async function gtm(sub, rest) {
|
|
|
4721
5232
|
days: numberFlag("days"),
|
|
4722
5233
|
networkDays: numberFlag("network-days"),
|
|
4723
5234
|
minSampleSize: numberFlag("min-sample-size"),
|
|
5235
|
+
holdoutMinSampleSize: numberFlag("holdout-min-sample-size"),
|
|
4724
5236
|
minWorkspaceCount: numberFlag("min-workspace-count"),
|
|
4725
5237
|
minPrivacyK: numberFlag("min-privacy-k"),
|
|
4726
5238
|
limit: numberFlag("limit")
|
|
@@ -4974,6 +5486,103 @@ async function gtm(sub, rest) {
|
|
|
4974
5486
|
hint(`signaliz gtm bootstrap${common.campaignId ? ` --campaign-id ${common.campaignId}` : ""} --include-samples`);
|
|
4975
5487
|
});
|
|
4976
5488
|
}
|
|
5489
|
+
if (sub === "feedback-pull" || sub === "instantly-feedback-pull" || sub === "pull-feedback") {
|
|
5490
|
+
const provider = (flagArg("provider") || "instantly").toLowerCase();
|
|
5491
|
+
if (provider !== "instantly") {
|
|
5492
|
+
die("gtm feedback-pull currently supports --provider instantly. Use gtm feedback-webhook for provider-agnostic ingress.");
|
|
5493
|
+
}
|
|
5494
|
+
const source = flagArg("source") || flagArg("pull-source") || "webhook_events";
|
|
5495
|
+
if (!["webhook_events", "emails"].includes(source)) {
|
|
5496
|
+
die("--source must be webhook_events or emails");
|
|
5497
|
+
}
|
|
5498
|
+
if (flagArg("source") && flagArg("pull-source") && flagArg("source") !== flagArg("pull-source")) {
|
|
5499
|
+
die("--source and --pull-source must match when both are provided");
|
|
5500
|
+
}
|
|
5501
|
+
const campaignId = flagArg("campaign-id");
|
|
5502
|
+
const campaignBuildId = flagArg("campaign-build-id") || flagArg("build-id");
|
|
5503
|
+
const providerLinkId = flagArg("provider-link-id");
|
|
5504
|
+
const providerCampaignId = flagArg("provider-campaign-id") || flagArg("instantly-campaign-id") || positionalAfter(sub);
|
|
5505
|
+
if (!campaignId && !campaignBuildId && !providerLinkId && !providerCampaignId) {
|
|
5506
|
+
die("Usage: signaliz gtm feedback-pull --provider-campaign-id <instantly_campaign_id> [--source webhook_events|emails] [--confirm]");
|
|
5507
|
+
}
|
|
5508
|
+
const hasEmailHistoryFlags = Boolean(flagArg("email-type") || flagArg("mode") || flagArg("sort-order"));
|
|
5509
|
+
if (hasEmailHistoryFlags && source !== "emails") {
|
|
5510
|
+
die("--email-type, --mode, and --sort-order require --source emails");
|
|
5511
|
+
}
|
|
5512
|
+
const emailType = source === "emails" ? flagArg("email-type") || "received" : void 0;
|
|
5513
|
+
if (emailType !== void 0 && !["received", "sent", "manual"].includes(emailType)) {
|
|
5514
|
+
die("--email-type must be received, sent, or manual");
|
|
5515
|
+
}
|
|
5516
|
+
const mode = source === "emails" ? flagArg("mode") || "emode_all" : void 0;
|
|
5517
|
+
if (mode !== void 0 && !["emode_focused", "emode_others", "emode_all"].includes(mode)) {
|
|
5518
|
+
die("--mode must be emode_focused, emode_others, or emode_all");
|
|
5519
|
+
}
|
|
5520
|
+
const sortOrder = source === "emails" ? flagArg("sort-order") || "asc" : void 0;
|
|
5521
|
+
if (sortOrder !== void 0 && !["asc", "desc"].includes(sortOrder)) {
|
|
5522
|
+
die("--sort-order must be asc or desc");
|
|
5523
|
+
}
|
|
5524
|
+
if (hasFlag("write") && !hasFlag("confirm") && !hasFlag("confirm-write")) {
|
|
5525
|
+
die("Write-mode feedback pulls require --confirm or --confirm-write. Run without --confirm first for a dry-run count.");
|
|
5526
|
+
}
|
|
5527
|
+
const confirmed = hasFlag("confirm") || hasFlag("confirm-write");
|
|
5528
|
+
const dryRun = !confirmed;
|
|
5529
|
+
const result = await sdk.gtm.pullInstantlyFeedback({
|
|
5530
|
+
campaignId,
|
|
5531
|
+
campaignBuildId,
|
|
5532
|
+
providerLinkId,
|
|
5533
|
+
providerCampaignId,
|
|
5534
|
+
instantlyCampaignId: flagArg("instantly-campaign-id"),
|
|
5535
|
+
integrationId: flagArg("integration-id"),
|
|
5536
|
+
source,
|
|
5537
|
+
instantlyProfile: flagArg("instantly-profile") || flagArg("profile"),
|
|
5538
|
+
cursor: flagArg("cursor"),
|
|
5539
|
+
from: flagArg("from") || flagArg("since"),
|
|
5540
|
+
to: flagArg("to") || flagArg("until"),
|
|
5541
|
+
limit: numberFlag("limit"),
|
|
5542
|
+
maxPages: numberFlag("max-pages"),
|
|
5543
|
+
emailType,
|
|
5544
|
+
mode,
|
|
5545
|
+
sortOrder,
|
|
5546
|
+
createMemory: !hasFlag("no-memory"),
|
|
5547
|
+
writeRoutineOutcomes: !hasFlag("no-routine-outcomes"),
|
|
5548
|
+
dryRun,
|
|
5549
|
+
runBrainCycle: !hasFlag("no-brain-cycle"),
|
|
5550
|
+
brainCycleWriteMode: flagArg("write-mode") || "dry_run",
|
|
5551
|
+
brainCyclePhases: csvFlag("brain-cycle-phases"),
|
|
5552
|
+
brainCycleMinIngested: numberFlag("brain-cycle-min-ingested"),
|
|
5553
|
+
brainCycleMinIntervalMinutes: numberFlag("brain-cycle-min-interval-minutes")
|
|
5554
|
+
});
|
|
5555
|
+
return output(result, () => {
|
|
5556
|
+
console.log("GTM Instantly feedback pull");
|
|
5557
|
+
console.log(` Mode: ${dryRun ? "dry_run" : "write"}`);
|
|
5558
|
+
console.log(` Source: ${result.source || source}`);
|
|
5559
|
+
if (result.provider_campaign_id || providerCampaignId) console.log(` Campaign: ${result.provider_campaign_id || providerCampaignId}`);
|
|
5560
|
+
if (result.run_id) console.log(` Run ID: ${result.run_id}`);
|
|
5561
|
+
if (result.status) console.log(` Status: ${result.status}`);
|
|
5562
|
+
if (result.max_pages !== void 0) console.log(` Pages: ${result.max_pages}`);
|
|
5563
|
+
const countFields = [
|
|
5564
|
+
["Seen", result.webhook_events_seen ?? result.email_records_seen ?? result.source_events],
|
|
5565
|
+
["Normalized", result.feedback_events_synced ?? result.events_normalized],
|
|
5566
|
+
["Ingested", result.ingested],
|
|
5567
|
+
["Duplicates", result.duplicates],
|
|
5568
|
+
["Unmatched", result.unmatched]
|
|
5569
|
+
];
|
|
5570
|
+
for (const [label, value] of countFields) {
|
|
5571
|
+
if (value !== void 0 && value !== null) console.log(` ${label}: ${value}`);
|
|
5572
|
+
}
|
|
5573
|
+
if (Array.isArray(result.blockers) && result.blockers.length) console.log(` Blockers: ${result.blockers.join("; ")}`);
|
|
5574
|
+
if (dryRun) {
|
|
5575
|
+
if (result.run_id) hint(`signaliz ops run-status ${result.run_id} --watch`);
|
|
5576
|
+
hint("Review the dry-run counts before writing feedback, memory, and outcomes: rerun with --confirm.");
|
|
5577
|
+
} else if (campaignId) {
|
|
5578
|
+
hint(`signaliz gtm learning ${campaignId} --include-network`);
|
|
5579
|
+
} else if (campaignBuildId) {
|
|
5580
|
+
hint(`signaliz gtm execution --campaign-build-id ${campaignBuildId}`);
|
|
5581
|
+
} else {
|
|
5582
|
+
hint("After the pull completes, run signaliz gtm bootstrap --include-samples to verify feedback and memory readiness.");
|
|
5583
|
+
}
|
|
5584
|
+
});
|
|
5585
|
+
}
|
|
4977
5586
|
if (sub === "nango") return gtmNango(rest[0], rest.slice(1));
|
|
4978
5587
|
if (!sub || sub === "list" || sub === "sources") {
|
|
4979
5588
|
const result = await sdk.leads.listNativeGtmCapabilities(flagArg("category"));
|
|
@@ -5034,7 +5643,7 @@ ${i + 1}. ${m.capability_id} (score ${m.score}) \u2014 ${m.label}`);
|
|
|
5034
5643
|
const result = await sdk.leads.checkStatus(jobId);
|
|
5035
5644
|
return output(result);
|
|
5036
5645
|
}
|
|
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>");
|
|
5646
|
+
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
5647
|
}
|
|
5039
5648
|
function nangoActionInput() {
|
|
5040
5649
|
const fromFile = readJsonFlag("input-file");
|
|
@@ -5051,30 +5660,146 @@ function nangoBaseOptions() {
|
|
|
5051
5660
|
nangoConnectionId: flagArg("nango-connection-id")
|
|
5052
5661
|
};
|
|
5053
5662
|
}
|
|
5054
|
-
function nangoConnectOptions() {
|
|
5663
|
+
function nangoConnectOptions(defaultSurface = "gtm_kernel") {
|
|
5055
5664
|
return {
|
|
5056
5665
|
providerId: flagArg("provider-id") || flagArg("provider"),
|
|
5057
5666
|
integrationId: flagArg("integration-id") || flagArg("provider-config-key"),
|
|
5058
5667
|
providerDisplayName: flagArg("provider-display-name") || flagArg("provider-name"),
|
|
5059
5668
|
integrationDisplayName: flagArg("integration-display-name"),
|
|
5060
5669
|
allowedIntegrations: csvFlag("allowed-integrations"),
|
|
5061
|
-
surface: flagArg("surface") ||
|
|
5670
|
+
surface: flagArg("surface") || defaultSurface,
|
|
5062
5671
|
source: flagArg("source") || "signaliz_cli",
|
|
5063
5672
|
userEmail: flagArg("user-email"),
|
|
5064
5673
|
userDisplayName: flagArg("user-display-name")
|
|
5065
5674
|
};
|
|
5066
5675
|
}
|
|
5676
|
+
function nangoPositionalValues(rest = []) {
|
|
5677
|
+
const values = [];
|
|
5678
|
+
for (let index = 0; index < rest.length; index++) {
|
|
5679
|
+
const value = rest[index];
|
|
5680
|
+
if (value.startsWith("--")) {
|
|
5681
|
+
if (!value.includes("=") && rest[index + 1] && !rest[index + 1].startsWith("--")) index++;
|
|
5682
|
+
continue;
|
|
5683
|
+
}
|
|
5684
|
+
values.push(value);
|
|
5685
|
+
}
|
|
5686
|
+
return values;
|
|
5687
|
+
}
|
|
5688
|
+
function nangoFlowOptions(rest = []) {
|
|
5689
|
+
const positionalSearch = nangoPositionalValues(rest).join(" ");
|
|
5690
|
+
const search = flagArg("search") || flagArg("query") || positionalSearch || void 0;
|
|
5691
|
+
return {
|
|
5692
|
+
...nangoBaseOptions(),
|
|
5693
|
+
query: flagArg("query"),
|
|
5694
|
+
search,
|
|
5695
|
+
providerId: flagArg("provider-id") || flagArg("provider"),
|
|
5696
|
+
provider: flagArg("provider"),
|
|
5697
|
+
intent: flagArg("intent"),
|
|
5698
|
+
actionName: flagArg("action-name") || flagArg("action"),
|
|
5699
|
+
toolName: flagArg("tool-name"),
|
|
5700
|
+
proxyPath: flagArg("proxy-path") || flagArg("nango-proxy-path"),
|
|
5701
|
+
method: flagArg("method"),
|
|
5702
|
+
input: nangoActionInput(),
|
|
5703
|
+
cadence: flagArg("cadence"),
|
|
5704
|
+
fieldMap: readInlineJsonFlag("field-map-json") || readJsonFlag("field-map-file"),
|
|
5705
|
+
requiredFields: csvFlag("required-fields") || csvFlag("required-field"),
|
|
5706
|
+
confirmSpend: hasFlag("confirm-spend"),
|
|
5707
|
+
writeConfirmed: hasFlag("write-confirmed") || hasFlag("confirm-write") || void 0,
|
|
5708
|
+
layer: flagArg("layer"),
|
|
5709
|
+
campaignId: flagArg("campaign-id"),
|
|
5710
|
+
limit: numberFlag("limit"),
|
|
5711
|
+
includeProviderCatalog: hasFlag("skip-provider-catalog") ? false : hasFlag("include-provider-catalog") ? true : void 0
|
|
5712
|
+
};
|
|
5713
|
+
}
|
|
5067
5714
|
function nangoStatusUrl(result) {
|
|
5068
5715
|
return result?.status_url || result?.statusUrl || result?.nango_result?.status_url || result?.nango_result?.statusUrl;
|
|
5069
5716
|
}
|
|
5070
|
-
|
|
5717
|
+
function nangoActionId(result) {
|
|
5718
|
+
return result?.action_id || result?.actionId || result?.nango_result?.action_id || result?.nango_result?.actionId || result?.nango_result?.id;
|
|
5719
|
+
}
|
|
5720
|
+
function nangoActionStatus(result) {
|
|
5721
|
+
return result?.status || result?.nango_result?.status;
|
|
5722
|
+
}
|
|
5723
|
+
function isTerminalNangoActionStatus(status) {
|
|
5724
|
+
return ["completed", "succeeded", "success", "failed", "error", "cancelled", "canceled"].includes(String(status || "").toLowerCase());
|
|
5725
|
+
}
|
|
5726
|
+
async function waitForNangoActionResult(nango, call, opts = {}) {
|
|
5727
|
+
const intervalMs = Math.max(250, Number(opts.intervalMs ?? 5e3));
|
|
5728
|
+
const maxPolls = Math.max(1, Math.min(60, Math.trunc(Number(opts.maxPolls ?? 12))));
|
|
5729
|
+
const timeoutMs = Math.max(250, Number(opts.timeoutMs ?? 6e4));
|
|
5730
|
+
let statusUrl = nangoStatusUrl(call);
|
|
5731
|
+
let actionId = nangoActionId(call);
|
|
5732
|
+
let latest = statusUrl || actionId ? void 0 : call;
|
|
5733
|
+
let polls = 0;
|
|
5734
|
+
const startedAt = Date.now();
|
|
5735
|
+
while ((statusUrl || actionId) && polls < maxPolls && Date.now() - startedAt <= timeoutMs) {
|
|
5736
|
+
polls += 1;
|
|
5737
|
+
latest = await nango.getNangoActionResult({ actionId, statusUrl });
|
|
5738
|
+
statusUrl = nangoStatusUrl(latest) || statusUrl;
|
|
5739
|
+
actionId = nangoActionId(latest) || actionId;
|
|
5740
|
+
if (isTerminalNangoActionStatus(nangoActionStatus(latest))) break;
|
|
5741
|
+
if (polls < maxPolls && Date.now() - startedAt < timeoutMs) await sleep(intervalMs);
|
|
5742
|
+
}
|
|
5743
|
+
const status = nangoActionStatus(latest || call);
|
|
5744
|
+
const timedOut = Boolean((statusUrl || actionId) && !isTerminalNangoActionStatus(status) && (polls >= maxPolls || Date.now() - startedAt > timeoutMs));
|
|
5745
|
+
return {
|
|
5746
|
+
call,
|
|
5747
|
+
result: latest,
|
|
5748
|
+
status,
|
|
5749
|
+
action_id: actionId,
|
|
5750
|
+
actionId,
|
|
5751
|
+
status_url: statusUrl,
|
|
5752
|
+
statusUrl,
|
|
5753
|
+
polls,
|
|
5754
|
+
max_polls: maxPolls,
|
|
5755
|
+
maxPolls,
|
|
5756
|
+
interval_ms: intervalMs,
|
|
5757
|
+
intervalMs,
|
|
5758
|
+
timeout_ms: timeoutMs,
|
|
5759
|
+
timeoutMs,
|
|
5760
|
+
timed_out: timedOut,
|
|
5761
|
+
timedOut
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
async function gtmNango(sub, rest, namespace = "gtm") {
|
|
5071
5765
|
const sdk = getSdk();
|
|
5766
|
+
const nango = namespace === "ops" ? sdk.ops : sdk.gtm;
|
|
5767
|
+
const commandPrefix = namespace === "ops" ? "signaliz ops nango" : "signaliz gtm nango";
|
|
5768
|
+
const defaultSurface = namespace === "ops" ? "ops_destinations" : "gtm_kernel";
|
|
5769
|
+
if (sub === "flow" || sub === "plan" || sub === "prepare" || sub === "search") {
|
|
5770
|
+
const result = await nango.prepareNangoIntegrationFlow(nangoFlowOptions(rest));
|
|
5771
|
+
return output(result, () => {
|
|
5772
|
+
console.log(`Nango integration flow: ${result?.status || "prepared"}`);
|
|
5773
|
+
if (result?.provider_id) console.log(` Provider: ${result.provider_id}`);
|
|
5774
|
+
if (result?.integration_id) console.log(` Integration: ${result.integration_id}`);
|
|
5775
|
+
if (result?.selected_connection?.id) console.log(` Workspace connection: ${result.selected_connection.id}`);
|
|
5776
|
+
const providers = Array.isArray(result?.provider_library?.providers) ? result.provider_library.providers : [];
|
|
5777
|
+
if (providers.length) {
|
|
5778
|
+
console.log(" Provider matches:");
|
|
5779
|
+
for (const provider of providers.slice(0, 5)) console.log(` - ${provider.name || provider.id} (${provider.id})`);
|
|
5780
|
+
}
|
|
5781
|
+
const connections = Array.isArray(result?.matched_connections) ? result.matched_connections : [];
|
|
5782
|
+
if (connections.length) {
|
|
5783
|
+
console.log(" Saved connections:");
|
|
5784
|
+
for (const connection of connections.slice(0, 5)) {
|
|
5785
|
+
const ready = connection.ready_for_route ? "ready" : connection.needs_attention ? "needs reconnect" : "not ready";
|
|
5786
|
+
console.log(` - ${connection.connector_name || connection.provider_config_key || connection.id}: ${ready} (${connection.id})`);
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5789
|
+
const nextActions = Array.isArray(result?.next_actions) ? result.next_actions : [];
|
|
5790
|
+
if (nextActions.length) {
|
|
5791
|
+
console.log(" Next calls:");
|
|
5792
|
+
for (const action of nextActions.slice(0, 5)) console.log(` - ${action.tool}: ${action.reason || "next step"}`);
|
|
5793
|
+
}
|
|
5794
|
+
if (result?.next_action) hint(result.next_action);
|
|
5795
|
+
});
|
|
5796
|
+
}
|
|
5072
5797
|
if (sub === "connect" || sub === "auth" || sub === "authorize") {
|
|
5073
|
-
const options = nangoConnectOptions();
|
|
5798
|
+
const options = nangoConnectOptions(defaultSurface);
|
|
5074
5799
|
if (!options.providerId && !options.integrationId && (!options.allowedIntegrations || options.allowedIntegrations.length === 0)) {
|
|
5075
|
-
die(
|
|
5800
|
+
die(`Usage: ${commandPrefix} connect --provider-id <provider> [--integration-id <key>] [--allowed-integrations a,b]`);
|
|
5076
5801
|
}
|
|
5077
|
-
const result = await
|
|
5802
|
+
const result = await nango.createNangoConnectSession(options);
|
|
5078
5803
|
return output(result, () => {
|
|
5079
5804
|
console.log(`Nango connect session: ${result?.status || "created"}`);
|
|
5080
5805
|
if (result?.provider_id || options.providerId) console.log(` Provider: ${result?.provider_id || options.providerId}`);
|
|
@@ -5082,11 +5807,11 @@ async function gtmNango(sub, rest) {
|
|
|
5082
5807
|
if (result?.connect_link || result?.auth_window_url) console.log(` Auth link: ${result.connect_link || result.auth_window_url}`);
|
|
5083
5808
|
if (result?.expires_at) console.log(` Expires: ${result.expires_at}`);
|
|
5084
5809
|
if (result?.next_action) console.log(` Next: ${result.next_action}`);
|
|
5085
|
-
hint(
|
|
5810
|
+
hint(`After authorization finishes, run ${commandPrefix} tools --workspace-connection-id <id> --provider-config-key <key>`);
|
|
5086
5811
|
});
|
|
5087
5812
|
}
|
|
5088
5813
|
if (!sub || sub === "tools" || sub === "list") {
|
|
5089
|
-
const result = await
|
|
5814
|
+
const result = await nango.listNangoTools({
|
|
5090
5815
|
...nangoBaseOptions(),
|
|
5091
5816
|
format: flagArg("format"),
|
|
5092
5817
|
includeRaw: hasFlag("include-raw")
|
|
@@ -5097,39 +5822,153 @@ async function gtmNango(sub, rest) {
|
|
|
5097
5822
|
for (const tool of tools2.slice(0, 10)) {
|
|
5098
5823
|
console.log(`- ${tool.name || tool.action_name || tool.id}: ${tool.description || tool.type || "action"}`);
|
|
5099
5824
|
}
|
|
5100
|
-
hint(
|
|
5825
|
+
hint(`${commandPrefix} call <action_name> --workspace-connection-id <id> --input-json '{"email":"buyer@example.com"}' --dry-run`);
|
|
5826
|
+
});
|
|
5827
|
+
}
|
|
5828
|
+
if (namespace === "ops" && (sub === "proof" || sub === "audit" || sub === "read-write")) {
|
|
5829
|
+
const result = await nango.proveNangoReadWrite({
|
|
5830
|
+
...nangoBaseOptions(),
|
|
5831
|
+
limit: numberFlag("limit"),
|
|
5832
|
+
includeRaw: hasFlag("include-raw"),
|
|
5833
|
+
readProxyPath: flagArg("read-proxy-path") || flagArg("proxy-path"),
|
|
5834
|
+
writeProxyPath: flagArg("write-proxy-path"),
|
|
5835
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5836
|
+
executeReadProbe: hasFlag("execute-read-probe"),
|
|
5837
|
+
executeWriteProbe: hasFlag("execute-write-probe"),
|
|
5838
|
+
confirm: hasFlag("confirm"),
|
|
5839
|
+
confirmWrite: hasFlag("confirm-write") || hasFlag("confirm"),
|
|
5840
|
+
input: nangoActionInput(),
|
|
5841
|
+
writeInput: readInlineJsonFlag("write-input-json") || readJsonFlag("write-input-file")
|
|
5842
|
+
});
|
|
5843
|
+
return output(result, () => {
|
|
5844
|
+
const summary = result?.summary || {};
|
|
5845
|
+
const connectedRows = summary.connected_connection_rows ?? summary.connection_rows ?? 0;
|
|
5846
|
+
const connectedUnique = summary.connected_unique_connections ?? summary.unique_connections ?? 0;
|
|
5847
|
+
console.log(`Nango proof: ${result?.status || "unknown"}`);
|
|
5848
|
+
console.log(`Connections: ${summary.connection_rows ?? 0} rows / ${summary.unique_connections ?? 0} unique`);
|
|
5849
|
+
console.log(`Connected: ${connectedRows} rows / ${connectedUnique} unique`);
|
|
5850
|
+
console.log(`Reconnect required: ${summary.reconnect_required ?? summary.needs_attention_connection_rows ?? 0}`);
|
|
5851
|
+
console.log(`Action tools: ${summary.action_tools ?? 0}`);
|
|
5852
|
+
console.log(`Runtime reads: ${summary.runtime_read_verified ?? 0}/${connectedRows}`);
|
|
5853
|
+
console.log(`Writes: ${summary.write_verified ?? 0}/${connectedRows}`);
|
|
5854
|
+
if (summary.duplicate_connection_rows) console.log(`Duplicates: ${summary.duplicate_connection_rows}`);
|
|
5855
|
+
if (summary.duplicate_connected_connection_rows) console.log(`Connected duplicates: ${summary.duplicate_connected_connection_rows}`);
|
|
5856
|
+
if (result?.next_action) console.log(`Next: ${result.next_action}`);
|
|
5857
|
+
});
|
|
5858
|
+
}
|
|
5859
|
+
if (namespace === "ops" && (sub === "schedule" || sub === "recur")) {
|
|
5860
|
+
const promptText = promptArg(rest);
|
|
5861
|
+
if (!promptText) {
|
|
5862
|
+
die(`Usage: ${commandPrefix} ${sub} "plain-English recurring goal" --workspace-connection-id <id> --action-name <action> [--confirm-spend] [--wait]`);
|
|
5863
|
+
}
|
|
5864
|
+
const scheduleInput = {
|
|
5865
|
+
prompt: promptText,
|
|
5866
|
+
blueprint: flagArg("blueprint"),
|
|
5867
|
+
targetCount: numberFlag("target-count"),
|
|
5868
|
+
cadence: flagArg("cadence") || "daily",
|
|
5869
|
+
wakeOnEvents: csvFlag("wake-on-events") || csvFlag("wake-events") || csvFlag("wake-event"),
|
|
5870
|
+
timezone: flagArg("timezone"),
|
|
5871
|
+
companyDomains: csvFlag("company-domains") || csvFlag("domains"),
|
|
5872
|
+
customAiPrompt: flagArg("ai-prompt") || flagArg("custom-ai-prompt"),
|
|
5873
|
+
signalPrompt: flagArg("signal-prompt"),
|
|
5874
|
+
outputPrompt: flagArg("output-prompt") || flagArg("result-prompt"),
|
|
5875
|
+
confirmSpend: hasFlag("confirm-spend"),
|
|
5876
|
+
...nangoBaseOptions(),
|
|
5877
|
+
actionName: flagArg("action-name") || flagArg("action") || flagArg("nango-action"),
|
|
5878
|
+
toolName: flagArg("tool-name"),
|
|
5879
|
+
proxyPath: flagArg("proxy-path") || flagArg("nango-proxy-path"),
|
|
5880
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5881
|
+
input: nangoActionInput(),
|
|
5882
|
+
fieldMap: readInlineJsonFlag("field-map-json") || readJsonFlag("field-map-file"),
|
|
5883
|
+
requiredFields: csvFlag("required-fields") || csvFlag("required-field"),
|
|
5884
|
+
writeConfirmed: hasFlag("write-confirmed") || hasFlag("confirm") || hasFlag("confirm-write") || void 0,
|
|
5885
|
+
agentWriteConfirmed: hasFlag("agent-write-confirmed") || void 0
|
|
5886
|
+
};
|
|
5887
|
+
if (hasFlag("wait")) {
|
|
5888
|
+
const combined = await nango.scheduleNangoActionAndWait({
|
|
5889
|
+
...scheduleInput,
|
|
5890
|
+
force: hasFlag("force"),
|
|
5891
|
+
instruction: flagArg("instruction"),
|
|
5892
|
+
intervalMs: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
5893
|
+
maxPolls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
5894
|
+
timeoutMs: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms"),
|
|
5895
|
+
limit: numberFlag("limit"),
|
|
5896
|
+
cursor: flagArg("cursor"),
|
|
5897
|
+
includeFailedRuns: hasFlag("include-failed-runs"),
|
|
5898
|
+
includeResults: !hasFlag("no-results")
|
|
5899
|
+
});
|
|
5900
|
+
return output(combined, () => {
|
|
5901
|
+
console.log(`Nango Op scheduled: ${combined.schedule?.op_id || combined.op_id}`);
|
|
5902
|
+
printOpsWaitForResults(combined);
|
|
5903
|
+
});
|
|
5904
|
+
}
|
|
5905
|
+
const result = await nango.scheduleNangoAction(scheduleInput);
|
|
5906
|
+
return output(result, () => {
|
|
5907
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
5908
|
+
console.log("Approval required");
|
|
5909
|
+
if (result.plan) {
|
|
5910
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
5911
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
5912
|
+
printPlanSchedule(result.plan);
|
|
5913
|
+
printOpsExecutionContract(result.plan);
|
|
5914
|
+
}
|
|
5915
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after review."}`);
|
|
5916
|
+
hint(`${commandPrefix} ${sub} ${JSON.stringify(promptText)} --confirm-spend`);
|
|
5917
|
+
return;
|
|
5918
|
+
}
|
|
5919
|
+
console.log(`Nango Op scheduled: ${result.op_id}`);
|
|
5920
|
+
console.log(`Status: ${result.status || "scheduled"}`);
|
|
5921
|
+
if (result.plan) printOpsExecutionContract(result.plan);
|
|
5922
|
+
console.log(`Next: ${result.next_action || "Run or wait for the next scheduled tick."}`);
|
|
5923
|
+
if (result.op_id) hint(`signaliz ops wait ${result.op_id}`);
|
|
5101
5924
|
});
|
|
5102
5925
|
}
|
|
5103
5926
|
if (sub === "call" || sub === "run") {
|
|
5104
|
-
const actionName = rest[0] || flagArg("action-name");
|
|
5927
|
+
const actionName = nangoPositionalValues(rest)[0] || flagArg("action-name");
|
|
5105
5928
|
const toolName = flagArg("tool-name");
|
|
5106
|
-
|
|
5107
|
-
|
|
5929
|
+
const proxyPath = flagArg("proxy-path") || flagArg("nango-proxy-path");
|
|
5930
|
+
if (!actionName && !toolName && !proxyPath) {
|
|
5931
|
+
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
5932
|
}
|
|
5109
|
-
const
|
|
5933
|
+
const callOptions = {
|
|
5110
5934
|
...nangoBaseOptions(),
|
|
5111
5935
|
actionName,
|
|
5112
5936
|
toolName,
|
|
5937
|
+
deliveryMode: proxyPath ? "proxy" : void 0,
|
|
5938
|
+
proxyPath,
|
|
5939
|
+
method: flagArg("method") || flagArg("http-method"),
|
|
5113
5940
|
input: nangoActionInput(),
|
|
5114
|
-
async: hasFlag("async") || void 0,
|
|
5941
|
+
async: hasFlag("async") || hasFlag("wait") || void 0,
|
|
5115
5942
|
maxRetries: numberFlag("max-retries"),
|
|
5116
5943
|
dryRun: hasFlag("execute") ? false : hasFlag("dry-run") ? true : void 0,
|
|
5117
5944
|
confirm: hasFlag("confirm") || void 0,
|
|
5118
5945
|
confirmWrite: hasFlag("confirm-write") || void 0
|
|
5119
|
-
}
|
|
5120
|
-
|
|
5946
|
+
};
|
|
5947
|
+
const waitOptions = {
|
|
5948
|
+
intervalMs: numberFlag("interval-ms") ?? numberFlag("wait-interval-ms"),
|
|
5949
|
+
maxPolls: numberFlag("max-polls") ?? numberFlag("wait-max-polls"),
|
|
5950
|
+
timeoutMs: numberFlag("timeout-ms") ?? numberFlag("wait-timeout-ms")
|
|
5951
|
+
};
|
|
5952
|
+
const waited = hasFlag("wait") && namespace === "ops" ? await nango.callNangoToolAndWait({ ...callOptions, ...waitOptions }) : null;
|
|
5953
|
+
const result = waited?.call || await nango.callNangoTool(callOptions);
|
|
5954
|
+
const finalResult = waited || (hasFlag("wait") ? await waitForNangoActionResult(nango, result, waitOptions) : result);
|
|
5955
|
+
return output(finalResult, () => {
|
|
5121
5956
|
console.log(`Nango action ${result?.status || "submitted"}: ${actionName || toolName}`);
|
|
5122
5957
|
const statusUrl = nangoStatusUrl(result);
|
|
5123
5958
|
if (statusUrl) console.log(` Status URL: ${statusUrl}`);
|
|
5959
|
+
if (finalResult !== result) {
|
|
5960
|
+
console.log(` Result: ${finalResult.status || "unknown"} (${finalResult.polls}/${finalResult.max_polls} polls)`);
|
|
5961
|
+
if (finalResult.timed_out) console.log(" Timed out before a terminal Nango result.");
|
|
5962
|
+
}
|
|
5124
5963
|
if (result?.next_action) console.log(` Next: ${result.next_action}`);
|
|
5125
|
-
if (statusUrl) hint(
|
|
5964
|
+
if (statusUrl && finalResult === result) hint(`${commandPrefix} result --status-url ${statusUrl}`);
|
|
5126
5965
|
});
|
|
5127
5966
|
}
|
|
5128
5967
|
if (sub === "result" || sub === "status") {
|
|
5129
|
-
const actionId = rest[0] || flagArg("action-id");
|
|
5968
|
+
const actionId = nangoPositionalValues(rest)[0] || flagArg("action-id");
|
|
5130
5969
|
const statusUrl = flagArg("status-url");
|
|
5131
|
-
if (!actionId && !statusUrl) die(
|
|
5132
|
-
const result = await
|
|
5970
|
+
if (!actionId && !statusUrl) die(`Usage: ${commandPrefix} result --action-id <id> OR --status-url /action/<id>`);
|
|
5971
|
+
const result = await nango.getNangoActionResult({ actionId, statusUrl });
|
|
5133
5972
|
return output(result, () => {
|
|
5134
5973
|
console.log(`Nango action result: ${result?.status || "unknown"}`);
|
|
5135
5974
|
if (result?.action_id || actionId) console.log(` Action ID: ${result?.action_id || actionId}`);
|
|
@@ -5137,7 +5976,7 @@ async function gtmNango(sub, rest) {
|
|
|
5137
5976
|
if (nextStatusUrl) console.log(` Status URL: ${nextStatusUrl}`);
|
|
5138
5977
|
});
|
|
5139
5978
|
}
|
|
5140
|
-
die(
|
|
5979
|
+
die(`Usage: ${commandPrefix} <flow|search|connect|tools|call|schedule|result>`);
|
|
5141
5980
|
}
|
|
5142
5981
|
async function email(sub, rest) {
|
|
5143
5982
|
const sdk = getSdk();
|
|
@@ -5342,26 +6181,74 @@ async function ops(sub, rest) {
|
|
|
5342
6181
|
const savedRest = sub === "save" ? rest : rest.slice(1);
|
|
5343
6182
|
return opsSaved(savedSub, savedRest);
|
|
5344
6183
|
}
|
|
6184
|
+
if (sub === "nango") return gtmNango(rest[0], rest.slice(1), "ops");
|
|
5345
6185
|
if (sub === "plan" && !promptArg(rest)) {
|
|
5346
6186
|
die('Usage: signaliz ops plan "monitor these companies daily..."');
|
|
5347
6187
|
}
|
|
5348
6188
|
if (sub === "create" && !promptArg(rest)) {
|
|
5349
6189
|
die('Usage: signaliz ops create "build 100 leads that fit..." [--confirm-spend]');
|
|
5350
6190
|
}
|
|
6191
|
+
if ((sub === "schedule" || sub === "recur") && !promptArg(rest)) {
|
|
6192
|
+
die('Usage: signaliz ops schedule "monitor these companies daily..." [--confirm-spend]');
|
|
6193
|
+
}
|
|
5351
6194
|
if (sub === "execute" && !promptArg(rest)) {
|
|
5352
6195
|
die('Usage: signaliz ops execute "launch a campaign for this ICP..." [--dry-run|--confirm-spend]');
|
|
5353
6196
|
}
|
|
5354
6197
|
const sdk = getSdk();
|
|
6198
|
+
const opsOptionalBooleanFlag = (name) => {
|
|
6199
|
+
const value = flagArg(name);
|
|
6200
|
+
if (value !== void 0) return !["0", "false", "no", "off"].includes(value.toLowerCase());
|
|
6201
|
+
return hasFlag(name) ? true : void 0;
|
|
6202
|
+
};
|
|
6203
|
+
const opsNangoDestination = () => {
|
|
6204
|
+
const destination = { type: "nango" };
|
|
6205
|
+
let hasDetails = false;
|
|
6206
|
+
const set = (key, value) => {
|
|
6207
|
+
if (value === void 0 || value === null || value === "") return;
|
|
6208
|
+
destination[key] = value;
|
|
6209
|
+
hasDetails = true;
|
|
6210
|
+
};
|
|
6211
|
+
const nangoAction = flagArg("nango-action");
|
|
6212
|
+
const nangoProxyPath = flagArg("nango-proxy-path");
|
|
6213
|
+
set("connectionId", flagArg("workspace-connection-id") || flagArg("connection-id"));
|
|
6214
|
+
set("providerConfigKey", flagArg("provider-config-key"));
|
|
6215
|
+
set("integrationId", flagArg("integration-id"));
|
|
6216
|
+
set("nangoConnectionId", flagArg("nango-connection-id"));
|
|
6217
|
+
set("actionName", flagArg("action-name") || nangoAction);
|
|
6218
|
+
set("nangoAction", nangoAction);
|
|
6219
|
+
set("proxyPath", flagArg("proxy-path") || nangoProxyPath);
|
|
6220
|
+
set("nangoProxyPath", nangoProxyPath);
|
|
6221
|
+
set("method", flagArg("method") || flagArg("http-method"));
|
|
6222
|
+
set("writeConfirmed", opsOptionalBooleanFlag("write-confirmed"));
|
|
6223
|
+
set("agentWriteConfirmed", opsOptionalBooleanFlag("agent-write-confirmed"));
|
|
6224
|
+
return hasDetails ? destination : void 0;
|
|
6225
|
+
};
|
|
6226
|
+
const isNangoDestinationType = (type) => {
|
|
6227
|
+
const normalized = type.toLowerCase().replace(/[-\s]/g, "_");
|
|
6228
|
+
return ["nango", "api", "managed_api", "customer_api", "external_api", "nango_api"].includes(normalized);
|
|
6229
|
+
};
|
|
5355
6230
|
const opsDestinations = () => {
|
|
5356
6231
|
const destinations = csvFlag("destinations") || csvFlag("destination");
|
|
5357
|
-
|
|
6232
|
+
const nangoDestination = opsNangoDestination();
|
|
6233
|
+
const out = (destinations || []).map((type) => nangoDestination && isNangoDestinationType(type) ? { ...nangoDestination, type } : { type });
|
|
6234
|
+
if (nangoDestination && !out.some((destination) => isNangoDestinationType(String(destination.type)))) {
|
|
6235
|
+
out.push(nangoDestination);
|
|
6236
|
+
}
|
|
6237
|
+
return out.length > 0 ? out : void 0;
|
|
5358
6238
|
};
|
|
6239
|
+
const opsWakeEvents = () => csvFlag("wake-on-events") || csvFlag("wake-events") || csvFlag("wake-event");
|
|
5359
6240
|
const opsCompanyDomains = () => csvFlag("company-domains") || csvFlag("domains");
|
|
5360
6241
|
const opsCustomPrompts = () => ({
|
|
5361
6242
|
custom_ai_prompt: flagArg("ai-prompt") || flagArg("custom-ai-prompt"),
|
|
5362
6243
|
signal_prompt: flagArg("signal-prompt"),
|
|
5363
6244
|
output_prompt: flagArg("output-prompt") || flagArg("result-prompt")
|
|
5364
6245
|
});
|
|
6246
|
+
const printPlanSchedule2 = (plan) => {
|
|
6247
|
+
if (!plan || typeof plan !== "object") return;
|
|
6248
|
+
const wakeEvents = Array.isArray(plan.wake_on_events) ? plan.wake_on_events : plan.wakeOnEvents;
|
|
6249
|
+
console.log(`Schedule: ${plan.cadence || "manual"}`);
|
|
6250
|
+
console.log(`Wake: ${Array.isArray(wakeEvents) && wakeEvents.length ? wakeEvents.join(", ") : "cadence only"}`);
|
|
6251
|
+
};
|
|
5365
6252
|
if (sub === "plan") {
|
|
5366
6253
|
const promptText = promptArg(rest);
|
|
5367
6254
|
const result = await sdk.ops.plan({
|
|
@@ -5369,6 +6256,7 @@ async function ops(sub, rest) {
|
|
|
5369
6256
|
blueprint: flagArg("blueprint"),
|
|
5370
6257
|
target_count: numberFlag("target-count"),
|
|
5371
6258
|
cadence: flagArg("cadence"),
|
|
6259
|
+
wake_on_events: opsWakeEvents(),
|
|
5372
6260
|
destinations: opsDestinations(),
|
|
5373
6261
|
company_domains: opsCompanyDomains(),
|
|
5374
6262
|
...opsCustomPrompts()
|
|
@@ -5378,10 +6266,11 @@ async function ops(sub, rest) {
|
|
|
5378
6266
|
if (result.ui_summary) console.log(`Summary: ${result.ui_summary}`);
|
|
5379
6267
|
console.log(`Status: ${result.status}`);
|
|
5380
6268
|
console.log(`Outcome: ${result.blueprint}`);
|
|
5381
|
-
|
|
6269
|
+
printPlanSchedule2(result);
|
|
5382
6270
|
console.log(`Target: ${result.target_count}`);
|
|
5383
6271
|
console.log(`Credits: ${result.estimated_credits}`);
|
|
5384
6272
|
if (result.destination_status) console.log(`Deliver: ${result.destination_status}`);
|
|
6273
|
+
printOpsExecutionContract(result);
|
|
5385
6274
|
printPrimitiveGraph(result.primitive_graph);
|
|
5386
6275
|
console.log(`Next: ${result.next_action}`);
|
|
5387
6276
|
});
|
|
@@ -5400,6 +6289,26 @@ async function ops(sub, rest) {
|
|
|
5400
6289
|
console.log(`${primary.title}: ${primary.outcome}`);
|
|
5401
6290
|
console.log(`Prompt: ${primary.prompt}`);
|
|
5402
6291
|
console.log(`CLI: ${primary.cli_command}`);
|
|
6292
|
+
const packet = primary.operating_packet || primary.operatingPacket || result.operating_packet || result.operatingPacket;
|
|
6293
|
+
if (packet?.schedule) {
|
|
6294
|
+
console.log(`Schedule: ${packet.schedule.cadence} - ${packet.schedule.recurrence}`);
|
|
6295
|
+
console.log(`Results: ${packet.result_contract?.wait_tool || packet.resultContract?.waitTool || packet.result_contract?.retrieve_tool || packet.resultContract?.retrieveTool || "ops_wait"}`);
|
|
6296
|
+
}
|
|
6297
|
+
const nangoRoute = packet?.nango_route || packet?.nangoRoute;
|
|
6298
|
+
if (nangoRoute?.enabled) {
|
|
6299
|
+
console.log("\nNango route");
|
|
6300
|
+
console.log(`- Discover: ${nangoRoute.discover_tool || nangoRoute.discoverTool}`);
|
|
6301
|
+
console.log(`- Dry run: ${nangoRoute.dry_run_tool || nangoRoute.dryRunTool}`);
|
|
6302
|
+
console.log(`- Execute: ${nangoRoute.execute_tool || nangoRoute.executeTool} after confirm=true`);
|
|
6303
|
+
if (nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool) {
|
|
6304
|
+
console.log(`- Wait: ${nangoRoute.execute_and_wait_tool || nangoRoute.executeAndWaitTool}`);
|
|
6305
|
+
}
|
|
6306
|
+
const nangoScheduleTool = nangoRoute.schedule_and_wait_tool || nangoRoute.scheduleAndWaitTool || nangoRoute.schedule_tool || nangoRoute.scheduleTool;
|
|
6307
|
+
if (nangoScheduleTool) {
|
|
6308
|
+
console.log(`- Schedule: ${nangoScheduleTool} after approval`);
|
|
6309
|
+
}
|
|
6310
|
+
console.log(`- Gate: ${nangoRoute.write_gate || nangoRoute.writeGate}`);
|
|
6311
|
+
}
|
|
5403
6312
|
if (primary.mcp_sequence?.length) {
|
|
5404
6313
|
console.log("\nMCP flow");
|
|
5405
6314
|
for (const [index, step] of primary.mcp_sequence.entries()) {
|
|
@@ -5411,22 +6320,49 @@ async function ops(sub, rest) {
|
|
|
5411
6320
|
}
|
|
5412
6321
|
if (sub === "execute") {
|
|
5413
6322
|
const promptText = promptArg(rest);
|
|
6323
|
+
const shouldWait = hasFlag("wait");
|
|
5414
6324
|
const result = await sdk.ops.execute({
|
|
5415
6325
|
prompt: promptText,
|
|
5416
6326
|
blueprint: flagArg("blueprint"),
|
|
5417
6327
|
target_count: numberFlag("target-count"),
|
|
5418
6328
|
cadence: flagArg("cadence"),
|
|
6329
|
+
wake_on_events: opsWakeEvents(),
|
|
6330
|
+
timezone: flagArg("timezone"),
|
|
5419
6331
|
destinations: opsDestinations(),
|
|
5420
6332
|
company_domains: opsCompanyDomains(),
|
|
5421
6333
|
...opsCustomPrompts(),
|
|
5422
6334
|
confirm_spend: hasFlag("confirm-spend"),
|
|
5423
6335
|
dry_run: hasFlag("dry-run"),
|
|
5424
|
-
auto_run: hasFlag("auto-run") ? true : hasFlag("no-auto-run") ? false : void 0,
|
|
6336
|
+
auto_run: hasFlag("auto-run") ? true : hasFlag("no-auto-run") ? false : shouldWait ? true : void 0,
|
|
5425
6337
|
output_format: flagArg("output-format") === "markdown" ? "markdown" : "json"
|
|
5426
6338
|
});
|
|
6339
|
+
if (shouldWait && result.op_id && !result.approval_required && result.error_code !== "APPROVAL_REQUIRED" && !hasFlag("dry-run")) {
|
|
6340
|
+
const waited = await sdk.ops.waitForResults({
|
|
6341
|
+
op_id: result.op_id,
|
|
6342
|
+
...opsWaitOptions()
|
|
6343
|
+
});
|
|
6344
|
+
const combined = {
|
|
6345
|
+
...waited,
|
|
6346
|
+
execute: result,
|
|
6347
|
+
run_id: result.run_id ?? waited.status?.run_id ?? waited.status?.runId,
|
|
6348
|
+
runId: result.runId ?? result.run_id ?? waited.status?.runId ?? waited.status?.run_id,
|
|
6349
|
+
execution_refs: combineExecutionRefs(result.execution_refs, waited.execution_refs)
|
|
6350
|
+
};
|
|
6351
|
+
return output(combined, () => {
|
|
6352
|
+
if (result.run_id || result.runId) console.log(`Run: ${result.run_id || result.runId}`);
|
|
6353
|
+
printOpsWaitForResults(combined);
|
|
6354
|
+
});
|
|
6355
|
+
}
|
|
5427
6356
|
return output(result, () => {
|
|
5428
6357
|
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
5429
6358
|
console.log("Approval required");
|
|
6359
|
+
if (result.plan) {
|
|
6360
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6361
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6362
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6363
|
+
printPlanSchedule2(result.plan);
|
|
6364
|
+
printOpsExecutionContract(result.plan);
|
|
6365
|
+
}
|
|
5430
6366
|
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
5431
6367
|
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
5432
6368
|
hint(`signaliz ops execute ${JSON.stringify(promptText)} --confirm-spend`);
|
|
@@ -5436,13 +6372,19 @@ async function ops(sub, rest) {
|
|
|
5436
6372
|
console.log(`Dry run: ${result.plan.title}`);
|
|
5437
6373
|
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
5438
6374
|
console.log(`Status: ${result.plan.status}`);
|
|
6375
|
+
printPlanSchedule2(result.plan);
|
|
5439
6376
|
console.log(`Credits: ${result.plan.estimated_credits}`);
|
|
6377
|
+
printOpsExecutionContract(result.plan);
|
|
5440
6378
|
console.log(`Next: ${result.next_action || result.plan.next_action}`);
|
|
5441
6379
|
return;
|
|
5442
6380
|
}
|
|
5443
6381
|
console.log(`Op: ${result.op_id || "not created"}`);
|
|
5444
6382
|
if (result.run_id) console.log(`Run: ${result.run_id}`);
|
|
5445
6383
|
console.log(`Status: ${result.status || "unknown"}`);
|
|
6384
|
+
if (result.plan) {
|
|
6385
|
+
printPlanSchedule2(result.plan);
|
|
6386
|
+
printOpsExecutionContract(result.plan);
|
|
6387
|
+
}
|
|
5446
6388
|
console.log(`Next: ${result.next_action || "Check status for progress."}`);
|
|
5447
6389
|
if (result.op_id) hint(`signaliz ops status ${result.op_id}`);
|
|
5448
6390
|
});
|
|
@@ -5505,6 +6447,8 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5505
6447
|
blueprint: flagArg("blueprint"),
|
|
5506
6448
|
target_count: numberFlag("target-count"),
|
|
5507
6449
|
cadence: flagArg("cadence"),
|
|
6450
|
+
wake_on_events: opsWakeEvents(),
|
|
6451
|
+
timezone: flagArg("timezone"),
|
|
5508
6452
|
destinations: opsDestinations(),
|
|
5509
6453
|
company_domains: opsCompanyDomains(),
|
|
5510
6454
|
...opsCustomPrompts(),
|
|
@@ -5512,15 +6456,99 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5512
6456
|
activate: hasFlag("activate")
|
|
5513
6457
|
});
|
|
5514
6458
|
return output(result, () => {
|
|
6459
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
6460
|
+
console.log("Approval required");
|
|
6461
|
+
if (result.plan) {
|
|
6462
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6463
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6464
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6465
|
+
printPlanSchedule2(result.plan);
|
|
6466
|
+
printOpsExecutionContract(result.plan);
|
|
6467
|
+
}
|
|
6468
|
+
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
6469
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
6470
|
+
hint(`signaliz ops create ${JSON.stringify(promptText)} --confirm-spend`);
|
|
6471
|
+
return;
|
|
6472
|
+
}
|
|
5515
6473
|
console.log(`Op created: ${result.op_id}`);
|
|
5516
6474
|
console.log(`Status: ${result.status}`);
|
|
6475
|
+
if (result.plan) {
|
|
6476
|
+
printPlanSchedule2(result.plan);
|
|
6477
|
+
printOpsExecutionContract(result.plan);
|
|
6478
|
+
}
|
|
5517
6479
|
console.log(`Next: ${result.next_action}`);
|
|
5518
6480
|
hint(`signaliz ops run ${result.op_id}`);
|
|
5519
6481
|
});
|
|
5520
6482
|
}
|
|
6483
|
+
if (sub === "schedule" || sub === "recur") {
|
|
6484
|
+
const promptText = promptArg(rest);
|
|
6485
|
+
const shouldWait = hasFlag("wait");
|
|
6486
|
+
const scheduleInput = {
|
|
6487
|
+
prompt: promptText,
|
|
6488
|
+
blueprint: flagArg("blueprint"),
|
|
6489
|
+
target_count: numberFlag("target-count"),
|
|
6490
|
+
cadence: flagArg("cadence") || "daily",
|
|
6491
|
+
wake_on_events: opsWakeEvents(),
|
|
6492
|
+
timezone: flagArg("timezone"),
|
|
6493
|
+
destinations: opsDestinations(),
|
|
6494
|
+
company_domains: opsCompanyDomains(),
|
|
6495
|
+
...opsCustomPrompts(),
|
|
6496
|
+
confirm_spend: hasFlag("confirm-spend")
|
|
6497
|
+
};
|
|
6498
|
+
if (shouldWait) {
|
|
6499
|
+
const combined = await sdk.ops.scheduleAndWait({
|
|
6500
|
+
...scheduleInput,
|
|
6501
|
+
force: hasFlag("force"),
|
|
6502
|
+
instruction: flagArg("instruction"),
|
|
6503
|
+
...opsWaitOptions()
|
|
6504
|
+
});
|
|
6505
|
+
return output(combined, () => {
|
|
6506
|
+
console.log(`Op scheduled: ${combined.schedule?.op_id || combined.op_id}`);
|
|
6507
|
+
printOpsWaitForResults(combined);
|
|
6508
|
+
});
|
|
6509
|
+
}
|
|
6510
|
+
const result = await sdk.ops.schedule(scheduleInput);
|
|
6511
|
+
return output(result, () => {
|
|
6512
|
+
if (result.approval_required || result.error_code === "APPROVAL_REQUIRED") {
|
|
6513
|
+
console.log("Approval required");
|
|
6514
|
+
if (result.plan) {
|
|
6515
|
+
console.log(`Plan: ${result.plan.title || result.plan.plan_id || "pending approval"}`);
|
|
6516
|
+
if (result.plan.ui_summary) console.log(`Summary: ${result.plan.ui_summary}`);
|
|
6517
|
+
console.log(`Status: ${result.plan.status || result.status || "needs_approval"}`);
|
|
6518
|
+
printPlanSchedule2(result.plan);
|
|
6519
|
+
printOpsExecutionContract(result.plan);
|
|
6520
|
+
}
|
|
6521
|
+
if (result.estimated_credits !== void 0) console.log(`Credits: ${result.estimated_credits}`);
|
|
6522
|
+
console.log(`Next: ${result.next_action || "Retry with --confirm-spend after approval."}`);
|
|
6523
|
+
hint(`signaliz ops schedule ${JSON.stringify(promptText)} --confirm-spend`);
|
|
6524
|
+
return;
|
|
6525
|
+
}
|
|
6526
|
+
console.log(`Op scheduled: ${result.op_id}`);
|
|
6527
|
+
if (result.run_id) console.log(`Run: ${result.run_id}`);
|
|
6528
|
+
console.log(`Status: ${result.status}`);
|
|
6529
|
+
if (result.plan) {
|
|
6530
|
+
printPlanSchedule2(result.plan);
|
|
6531
|
+
printOpsExecutionContract(result.plan);
|
|
6532
|
+
}
|
|
6533
|
+
console.log(`Next: ${result.next_action}`);
|
|
6534
|
+
if (result.op_id) hint(`signaliz ops run ${result.op_id} --wait --limit 100`);
|
|
6535
|
+
});
|
|
6536
|
+
}
|
|
5521
6537
|
if (sub === "run") {
|
|
5522
6538
|
const opId = rest[0];
|
|
5523
6539
|
if (!opId) die("Usage: signaliz ops run <op_id>");
|
|
6540
|
+
if (hasFlag("wait")) {
|
|
6541
|
+
const result2 = await sdk.ops.runAndWait({
|
|
6542
|
+
op_id: opId,
|
|
6543
|
+
force: hasFlag("force"),
|
|
6544
|
+
instruction: flagArg("instruction"),
|
|
6545
|
+
...opsWaitOptions()
|
|
6546
|
+
});
|
|
6547
|
+
return output(result2, () => {
|
|
6548
|
+
if (result2.run?.run_id || result2.run?.runId) console.log(`Run: ${result2.run.run_id || result2.run.runId}`);
|
|
6549
|
+
printOpsWaitForResults(result2);
|
|
6550
|
+
});
|
|
6551
|
+
}
|
|
5524
6552
|
const result = await sdk.ops.run({ op_id: opId, force: hasFlag("force"), instruction: flagArg("instruction") });
|
|
5525
6553
|
return output(result, () => {
|
|
5526
6554
|
console.log(`Op running: ${result.op_id}`);
|
|
@@ -5553,14 +6581,38 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5553
6581
|
include_failed_runs: hasFlag("include-failed-runs")
|
|
5554
6582
|
});
|
|
5555
6583
|
return output(result, () => {
|
|
5556
|
-
const
|
|
5557
|
-
const
|
|
5558
|
-
|
|
5559
|
-
|
|
6584
|
+
const summary = result.summary || {};
|
|
6585
|
+
const hasMore = summary.has_more ?? summary.hasMore ?? result.has_more ?? result.hasMore;
|
|
6586
|
+
const nextCursor = summary.next_cursor ?? summary.nextCursor ?? result.next_cursor ?? result.nextCursor;
|
|
6587
|
+
const resultsCount = summary.results_count ?? summary.resultsCount ?? result.results_count ?? result.resultsCount ?? 0;
|
|
6588
|
+
const resultsTotal = summary.results_total ?? summary.resultsTotal ?? result.results_total ?? result.resultsTotal;
|
|
6589
|
+
const deliveryStatus = summary.delivery_status ?? summary.deliveryStatus ?? result.delivery_status ?? result.deliveryStatus;
|
|
6590
|
+
const resultsUrl = summary.results_url ?? summary.resultsUrl ?? result.results_url ?? result.resultsUrl;
|
|
6591
|
+
const nextAction = summary.next_action ?? summary.nextAction ?? result.next_action ?? result.nextAction;
|
|
6592
|
+
console.log(`Results: ${resultsCount}${hasMore ? " (more available)" : ""}`);
|
|
6593
|
+
if (summary.label) console.log(`Summary: ${summary.label}`);
|
|
6594
|
+
console.log(`Status: ${summary.status || result.status || "unknown"} (${summary.phase || result.phase || "unknown"})`);
|
|
6595
|
+
if (resultsTotal !== void 0 && resultsTotal !== null) console.log(`Total: ${resultsTotal}`);
|
|
6596
|
+
if (deliveryStatus) console.log(`Deliver: ${deliveryStatus}`);
|
|
6597
|
+
if (resultsUrl) console.log(`Open: ${resultsUrl}`);
|
|
6598
|
+
if (nextAction) console.log(`Next: ${nextAction}`);
|
|
6599
|
+
if (result.results.length) {
|
|
6600
|
+
console.log("\nRows");
|
|
6601
|
+
for (const row of result.results.slice(0, 10)) console.log(JSON.stringify(row));
|
|
6602
|
+
}
|
|
5560
6603
|
if (hasMore && nextCursor) hint(`signaliz ops results ${opId} --cursor ${nextCursor}`);
|
|
5561
6604
|
printExecutionRefs(result.execution_refs);
|
|
5562
6605
|
});
|
|
5563
6606
|
}
|
|
6607
|
+
if (sub === "wait" || sub === "await") {
|
|
6608
|
+
const opId = rest[0] || flagArg("op-id");
|
|
6609
|
+
if (!opId) die("Usage: signaliz ops wait <op_id>");
|
|
6610
|
+
const result = await sdk.ops.waitForResults({
|
|
6611
|
+
op_id: opId,
|
|
6612
|
+
...opsWaitOptions()
|
|
6613
|
+
});
|
|
6614
|
+
return output(result, () => printOpsWaitForResults(result));
|
|
6615
|
+
}
|
|
5564
6616
|
if (sub === "run-status" || sub === "trigger-status" || sub === "watch") {
|
|
5565
6617
|
const runIds = csvFlag("run-ids");
|
|
5566
6618
|
const runId = rest[0] || flagArg("run-id");
|
|
@@ -5889,13 +6941,15 @@ Available: ${result.available_types.join(", ")}`);
|
|
|
5889
6941
|
const result = await sdk.ops.attachSinkToRoutine({ routine_id: routineId, sink_id: sinkId });
|
|
5890
6942
|
return output(result);
|
|
5891
6943
|
}
|
|
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>");
|
|
6944
|
+
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
6945
|
}
|
|
5894
6946
|
var OPS_SHORTCUTS = {
|
|
5895
6947
|
"/plan": "plan",
|
|
5896
6948
|
plan: "plan",
|
|
5897
6949
|
"/goal": "create",
|
|
5898
6950
|
goal: "create",
|
|
6951
|
+
schedule: "schedule",
|
|
6952
|
+
recur: "schedule",
|
|
5899
6953
|
quickstart: "quickstart",
|
|
5900
6954
|
template: "template",
|
|
5901
6955
|
proof: "proof",
|
|
@@ -5904,6 +6958,7 @@ var OPS_SHORTCUTS = {
|
|
|
5904
6958
|
run: "run",
|
|
5905
6959
|
status: "status",
|
|
5906
6960
|
results: "results",
|
|
6961
|
+
wait: "wait",
|
|
5907
6962
|
queue: "queue",
|
|
5908
6963
|
debug: "debug",
|
|
5909
6964
|
watch: "watch",
|