@signaliz/sdk 1.0.6 → 1.0.7
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 +100 -8
- package/dist/{chunk-GRVV37LD.mjs → chunk-BHL5NHVO.mjs} +1413 -55
- package/dist/cli.js +2370 -62
- package/dist/cli.mjs +962 -9
- package/dist/index.d.mts +245 -10
- package/dist/index.d.ts +245 -10
- package/dist/index.js +1423 -55
- package/dist/index.mjs +21 -1
- package/dist/mcp-config.js +1301 -55
- package/dist/mcp-config.mjs +1 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
Signaliz
|
|
4
|
-
|
|
3
|
+
Signaliz,
|
|
4
|
+
createCampaignBuilderAgentRequestTemplate,
|
|
5
|
+
createCampaignBuilderApproval
|
|
6
|
+
} from "./chunk-BHL5NHVO.mjs";
|
|
5
7
|
|
|
6
8
|
// src/cli.ts
|
|
9
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
7
10
|
var apiKey = process.env.SIGNALIZ_API_KEY;
|
|
11
|
+
var baseUrl = process.env.SIGNALIZ_BASE_URL || process.env.SIGNALIZ_API_URL;
|
|
8
12
|
async function main() {
|
|
9
13
|
const command = process.argv[2];
|
|
10
|
-
if (!
|
|
14
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
15
|
+
printHelp();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const offlineCampaignAgentTemplate = (command === "campaign-agent" || command === "campaign-builder") && ["init", "template", "request-template", "new"].includes(String(process.argv[3] || ""));
|
|
19
|
+
if (!apiKey && !offlineCampaignAgentTemplate) {
|
|
11
20
|
console.error("\u274C SIGNALIZ_API_KEY environment variable is required.");
|
|
12
21
|
console.error(" Set it with: export SIGNALIZ_API_KEY=sk_...");
|
|
13
22
|
process.exit(1);
|
|
14
23
|
}
|
|
15
|
-
const signaliz = new Signaliz({ apiKey });
|
|
24
|
+
const signaliz = new Signaliz({ apiKey: apiKey || "offline", baseUrl });
|
|
16
25
|
switch (command) {
|
|
17
26
|
case "test": {
|
|
18
27
|
try {
|
|
@@ -43,18 +52,962 @@ async function main() {
|
|
|
43
52
|
}
|
|
44
53
|
break;
|
|
45
54
|
}
|
|
55
|
+
case "gtm": {
|
|
56
|
+
await handleGtmCommand(signaliz, process.argv.slice(3));
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "campaign-agent":
|
|
60
|
+
case "campaign-builder": {
|
|
61
|
+
await handleCampaignAgentCommand(signaliz, process.argv.slice(3));
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
46
64
|
default:
|
|
47
|
-
|
|
65
|
+
printHelp();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function handleGtmCommand(signaliz, argv) {
|
|
69
|
+
const subcommand = argv[0];
|
|
70
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
71
|
+
printGtmHelp();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (subcommand === "context") {
|
|
75
|
+
const flags = parseFlags(argv.slice(1));
|
|
76
|
+
const result = await signaliz.gtm.context({
|
|
77
|
+
includeCampaigns: booleanFlag(flags, "include-campaigns"),
|
|
78
|
+
includeMemory: booleanFlag(flags, "include-memory"),
|
|
79
|
+
includeBrain: booleanFlag(flags, "include-brain"),
|
|
80
|
+
includeConnections: booleanFlag(flags, "include-connections"),
|
|
81
|
+
limit: numberFlag(flags, "limit")
|
|
82
|
+
});
|
|
83
|
+
printResult(result, flags);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (subcommand === "bootstrap") {
|
|
87
|
+
const flags = parseFlags(argv.slice(1));
|
|
88
|
+
const result = await signaliz.gtm.bootstrapStatus({
|
|
89
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
90
|
+
days: numberFlag(flags, "days"),
|
|
91
|
+
minSampleSize: numberFlag(flags, "min-sample-size"),
|
|
92
|
+
includeConnections: booleanFlag(flags, "include-connections"),
|
|
93
|
+
includeSamples: booleanFlag(flags, "include-samples"),
|
|
94
|
+
limit: numberFlag(flags, "limit")
|
|
95
|
+
});
|
|
96
|
+
printResult(result, flags);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (subcommand === "memory" && argv[1] === "search") {
|
|
100
|
+
const flags = parseFlags(argv.slice(2));
|
|
101
|
+
const query = stringFlag(flags, "query", "q");
|
|
102
|
+
if (!query) throw new Error("gtm memory search requires --query");
|
|
103
|
+
const options = {
|
|
104
|
+
query,
|
|
105
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
106
|
+
memoryType: stringFlag(flags, "memory-type"),
|
|
107
|
+
keywords: csvFlag(flags, "keywords"),
|
|
108
|
+
outcomeType: stringFlag(flags, "outcome-type"),
|
|
109
|
+
layers: csvFlag(flags, "layers"),
|
|
110
|
+
providerChain: csvFlag(flags, "provider-chain", "providers"),
|
|
111
|
+
days: numberFlag(flags, "days"),
|
|
112
|
+
limit: numberFlag(flags, "limit")
|
|
113
|
+
};
|
|
114
|
+
const result = await signaliz.gtm.searchMemory(options);
|
|
115
|
+
printResult(result, flags);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (subcommand === "templates" || subcommand === "strategy-templates") {
|
|
119
|
+
const flags = parseFlags(argv.slice(1));
|
|
120
|
+
const result = await signaliz.gtm.campaignStrategyTemplates({
|
|
121
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
122
|
+
query: stringFlag(flags, "query", "q"),
|
|
123
|
+
includeDetails: !booleanFlag(flags, "summary")
|
|
124
|
+
});
|
|
125
|
+
printResult(result, flags);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (subcommand === "start-context" || subcommand === "start") {
|
|
129
|
+
const flags = parseFlags(argv.slice(1));
|
|
130
|
+
const campaignBrief = stringFlag(flags, "brief", "campaign-brief", "goal");
|
|
131
|
+
const strategyTemplate = stringFlag(flags, "strategy-template", "template");
|
|
132
|
+
const targetIcp = jsonObjectFlag(flags, "target-icp", "icp");
|
|
133
|
+
if (!campaignBrief && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id") && !strategyTemplate && !targetIcp) {
|
|
134
|
+
throw new Error("gtm start-context requires --brief, --campaign-id, --campaign-build-id, --strategy-template, or --target-icp");
|
|
135
|
+
}
|
|
136
|
+
const input = {
|
|
137
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
138
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id"),
|
|
139
|
+
campaignBrief,
|
|
140
|
+
strategyTemplate,
|
|
141
|
+
targetIcp,
|
|
142
|
+
leadCount: numberFlag(flags, "lead-count", "target-count"),
|
|
143
|
+
layers: csvFlag(flags, "layers"),
|
|
144
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
145
|
+
memoryDimensionFilters: jsonObjectFlag(flags, "memory-dimension-filters"),
|
|
146
|
+
requireMemoryDimensionMatch: booleanFlag(flags, "require-memory-dimension-match"),
|
|
147
|
+
includeMemory: booleanFlag(flags, "include-memory", true),
|
|
148
|
+
includeBrain: booleanFlag(flags, "include-brain", true),
|
|
149
|
+
includeProviderRoutes: booleanFlag(flags, "include-provider-routes", true),
|
|
150
|
+
includeFailurePatterns: booleanFlag(flags, "include-failure-patterns", true),
|
|
151
|
+
includeDeliveryRisk: booleanFlag(flags, "include-delivery-risk", true),
|
|
152
|
+
includeGlobalBrain: booleanFlag(flags, "include-global-brain", true),
|
|
153
|
+
includePlannedProviders: booleanFlag(flags, "include-planned-providers", true),
|
|
154
|
+
days: numberFlag(flags, "days"),
|
|
155
|
+
minConfidence: numberFlag(flags, "min-confidence"),
|
|
156
|
+
minSampleSize: numberFlag(flags, "min-sample-size"),
|
|
157
|
+
limit: numberFlag(flags, "limit")
|
|
158
|
+
};
|
|
159
|
+
const result = await signaliz.gtm.campaignStartContext(input);
|
|
160
|
+
printResult(result, flags);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (subcommand === "strategy-memory" || subcommand === "memory-status" || subcommand === "strategy-memory-status") {
|
|
164
|
+
const flags = parseFlags(argv.slice(1));
|
|
165
|
+
const input = {
|
|
166
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
167
|
+
query: stringFlag(flags, "query", "goal", "q"),
|
|
168
|
+
campaignBrief: stringFlag(flags, "brief", "campaign-brief"),
|
|
169
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
170
|
+
memoryDimensionFilters: jsonObjectFlag(flags, "memory-dimension-filters"),
|
|
171
|
+
requireMemoryDimensionMatch: booleanFlag(flags, "require-memory-dimension-match"),
|
|
172
|
+
includeSamples: booleanFlag(flags, "include-samples"),
|
|
173
|
+
includeSources: !booleanFlag(flags, "no-sources"),
|
|
174
|
+
days: numberFlag(flags, "days"),
|
|
175
|
+
limit: numberFlag(flags, "limit")
|
|
176
|
+
};
|
|
177
|
+
const result = await signaliz.gtm.campaignStrategyMemoryStatus(input);
|
|
178
|
+
printResult(result, flags);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (subcommand === "plan") {
|
|
182
|
+
const flags = parseFlags(argv.slice(1));
|
|
183
|
+
const campaignBrief = stringFlag(flags, "brief", "campaign-brief", "goal");
|
|
184
|
+
if (!campaignBrief && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id")) {
|
|
185
|
+
throw new Error("gtm plan requires --brief, --campaign-id, or --campaign-build-id");
|
|
186
|
+
}
|
|
187
|
+
const input = {
|
|
188
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
189
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id"),
|
|
190
|
+
campaignBrief,
|
|
191
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
192
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
193
|
+
leadCount: numberFlag(flags, "lead-count", "target-count"),
|
|
194
|
+
layers: csvFlag(flags, "layers"),
|
|
195
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
196
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
197
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns") && !booleanFlag(flags, "no-agency-patterns"),
|
|
198
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns") && !booleanFlag(flags, "no-clay-patterns"),
|
|
199
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
200
|
+
partnerEcosystem: csvFlag(flags, "partner-ecosystem", "partners"),
|
|
201
|
+
includeMemory: booleanFlag(flags, "include-memory", true),
|
|
202
|
+
includeBrain: booleanFlag(flags, "include-brain", true),
|
|
203
|
+
includeProviderRoutes: booleanFlag(flags, "include-provider-routes", true),
|
|
204
|
+
includeFailurePatterns: booleanFlag(flags, "include-failure-patterns", true),
|
|
205
|
+
includePlannedProviders: booleanFlag(flags, "include-planned-providers", true),
|
|
206
|
+
days: numberFlag(flags, "days"),
|
|
207
|
+
limit: numberFlag(flags, "limit")
|
|
208
|
+
};
|
|
209
|
+
const result = await signaliz.gtm.campaignBuildPlan(input);
|
|
210
|
+
printResult(result, flags);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (subcommand === "agent-plan" || subcommand === "campaign-agent-plan") {
|
|
214
|
+
const flags = parseFlags(argv.slice(1));
|
|
215
|
+
const goal = stringFlag(flags, "goal", "brief", "campaign-brief");
|
|
216
|
+
if (!goal && !stringFlag(flags, "campaign-id") && !stringFlag(flags, "campaign-build-id") && !stringFlag(flags, "strategy-template", "template")) {
|
|
217
|
+
throw new Error("gtm agent-plan requires --goal, --campaign-id, --campaign-build-id, or --strategy-template");
|
|
218
|
+
}
|
|
219
|
+
const input = {
|
|
220
|
+
goal,
|
|
221
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
222
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
223
|
+
campaignBuildId: stringFlag(flags, "campaign-build-id", "build-id"),
|
|
224
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
225
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
226
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
227
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
228
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
229
|
+
builtIns: campaignAgentBuiltInsFromFlags(flags),
|
|
230
|
+
useLocalLeads: booleanFlag(flags, "use-local-leads") || void 0,
|
|
231
|
+
layers: csvFlag(flags, "layers"),
|
|
232
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
233
|
+
customTools: campaignAgentCustomToolRoutesFromFlags(flags),
|
|
234
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
235
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns"),
|
|
236
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns"),
|
|
237
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
238
|
+
partnerEcosystem: csvFlag(flags, "partner-ecosystem", "partners"),
|
|
239
|
+
includeMemory: !booleanFlag(flags, "no-memory"),
|
|
240
|
+
includeBrain: !booleanFlag(flags, "no-brain"),
|
|
241
|
+
includeProviderRoutes: !booleanFlag(flags, "no-provider-routes"),
|
|
242
|
+
includeFailurePatterns: !booleanFlag(flags, "no-failure-patterns"),
|
|
243
|
+
includeDeliveryRisk: !booleanFlag(flags, "no-delivery-risk"),
|
|
244
|
+
includePlannedProviders: !booleanFlag(flags, "no-planned-providers"),
|
|
245
|
+
days: numberFlag(flags, "days"),
|
|
246
|
+
limit: numberFlag(flags, "limit")
|
|
247
|
+
};
|
|
248
|
+
const result = await signaliz.gtm.campaignAgentPlan(input);
|
|
249
|
+
printResult(result, flags);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (subcommand === "agent-template" || subcommand === "campaign-agent-template" || subcommand === "request-template") {
|
|
253
|
+
const flags = parseFlags(argv.slice(1));
|
|
254
|
+
const input = {
|
|
255
|
+
goal: stringFlag(flags, "goal", "brief", "campaign-brief"),
|
|
256
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
257
|
+
accountLabel: stringFlag(flags, "workspace-label", "account-label"),
|
|
258
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
259
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
260
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
261
|
+
targetIcp: jsonObjectFlag(flags, "target-icp", "icp"),
|
|
262
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
263
|
+
builtIns: campaignAgentBuiltInsFromFlags(flags),
|
|
264
|
+
includeLocalLeads: booleanFlag(flags, "use-local-leads") || booleanFlag(flags, "include-local-leads") || void 0,
|
|
265
|
+
includeByoPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-byo-placeholder") || void 0,
|
|
266
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
267
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers"),
|
|
268
|
+
privacyMode: stringFlag(flags, "privacy-mode"),
|
|
269
|
+
destinationType: stringFlag(flags, "destination", "destination-type")
|
|
270
|
+
};
|
|
271
|
+
const result = await signaliz.gtm.campaignAgentRequestTemplate(input);
|
|
272
|
+
printResult(result, flags);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (subcommand === "provider-prepare" || subcommand === "prepare-provider" || subcommand === "recipe-prepare" || subcommand === "prepare-recipe") {
|
|
276
|
+
const flags = parseFlags(argv.slice(1));
|
|
277
|
+
const providerId = stringFlag(flags, "provider-id", "provider") || argv[1];
|
|
278
|
+
if (!providerId) {
|
|
279
|
+
throw new Error("gtm provider-prepare requires --provider-id or provider id");
|
|
280
|
+
}
|
|
281
|
+
const input = {
|
|
282
|
+
providerId,
|
|
283
|
+
providerName: stringFlag(flags, "provider-name", "name"),
|
|
284
|
+
description: stringFlag(flags, "description"),
|
|
285
|
+
layerCapabilities: csvFlag(flags, "layer-capabilities", "layers"),
|
|
286
|
+
invocationType: stringFlag(flags, "invocation-type"),
|
|
287
|
+
authStrategy: stringFlag(flags, "auth-strategy"),
|
|
288
|
+
endpointUrl: stringFlag(flags, "endpoint-url"),
|
|
289
|
+
httpMethod: stringFlag(flags, "http-method") || void 0,
|
|
290
|
+
secretRef: stringFlag(flags, "secret-ref"),
|
|
291
|
+
workspaceIntegrationId: stringFlag(flags, "workspace-integration-id"),
|
|
292
|
+
workspaceMcpServerId: stringFlag(flags, "workspace-mcp-server-id"),
|
|
293
|
+
workspaceConnectionId: stringFlag(flags, "workspace-connection-id"),
|
|
294
|
+
requestTemplate: jsonObjectFlag(flags, "request-template"),
|
|
295
|
+
responseMapping: jsonObjectFlag(flags, "response-mapping"),
|
|
296
|
+
inputSchema: jsonObjectFlag(flags, "input-schema"),
|
|
297
|
+
outputSchema: jsonObjectFlag(flags, "output-schema"),
|
|
298
|
+
readiness: jsonObjectFlag(flags, "readiness"),
|
|
299
|
+
metadata: jsonObjectFlag(flags, "metadata"),
|
|
300
|
+
layer: stringFlag(flags, "layer"),
|
|
301
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
302
|
+
useSignalizFallback: !booleanFlag(flags, "no-signaliz-fallback"),
|
|
303
|
+
priority: numberFlag(flags, "priority"),
|
|
304
|
+
status: stringFlag(flags, "status"),
|
|
305
|
+
context: jsonObjectFlag(flags, "context")
|
|
306
|
+
};
|
|
307
|
+
const result = await signaliz.gtm.prepareProviderRecipe(input);
|
|
308
|
+
printResult(result, flags);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (subcommand === "activate-route" || subcommand === "route-activate") {
|
|
312
|
+
const flags = parseFlags(argv.slice(1));
|
|
313
|
+
const providerId = stringFlag(flags, "provider-id", "provider") || argv[1];
|
|
314
|
+
if (!providerId) {
|
|
315
|
+
throw new Error("gtm activate-route requires --provider-id or provider id");
|
|
316
|
+
}
|
|
317
|
+
const layers = csvFlag(flags, "layers");
|
|
318
|
+
const layer = stringFlag(flags, "layer");
|
|
319
|
+
if (!layer && !layers?.length) {
|
|
320
|
+
throw new Error("gtm activate-route requires --layer or --layers");
|
|
321
|
+
}
|
|
322
|
+
const confirm = booleanFlag(flags, "confirm");
|
|
323
|
+
const input = {
|
|
324
|
+
providerId,
|
|
325
|
+
providerName: stringFlag(flags, "provider-name", "name"),
|
|
326
|
+
description: stringFlag(flags, "description"),
|
|
327
|
+
campaignId: stringFlag(flags, "campaign-id"),
|
|
328
|
+
layer,
|
|
329
|
+
layers,
|
|
330
|
+
invocationType: stringFlag(flags, "invocation-type"),
|
|
331
|
+
authStrategy: stringFlag(flags, "auth-strategy"),
|
|
332
|
+
endpointUrl: stringFlag(flags, "endpoint-url"),
|
|
333
|
+
httpMethod: stringFlag(flags, "http-method") || void 0,
|
|
334
|
+
secretRef: stringFlag(flags, "secret-ref"),
|
|
335
|
+
workspaceIntegrationId: stringFlag(flags, "workspace-integration-id"),
|
|
336
|
+
workspaceMcpServerId: stringFlag(flags, "workspace-mcp-server-id"),
|
|
337
|
+
workspaceConnectionId: stringFlag(flags, "workspace-connection-id"),
|
|
338
|
+
useSignalizFallback: !booleanFlag(flags, "no-signaliz-fallback"),
|
|
339
|
+
priority: numberFlag(flags, "priority"),
|
|
340
|
+
routeConfig: jsonObjectFlag(flags, "route-config"),
|
|
341
|
+
requestTemplate: jsonObjectFlag(flags, "request-template"),
|
|
342
|
+
responseMapping: jsonObjectFlag(flags, "response-mapping"),
|
|
343
|
+
inputSchema: jsonObjectFlag(flags, "input-schema"),
|
|
344
|
+
outputSchema: jsonObjectFlag(flags, "output-schema"),
|
|
345
|
+
readiness: jsonObjectFlag(flags, "readiness"),
|
|
346
|
+
metadata: jsonObjectFlag(flags, "metadata"),
|
|
347
|
+
status: stringFlag(flags, "status"),
|
|
348
|
+
routeStatus: stringFlag(flags, "route-status"),
|
|
349
|
+
replaceExistingRoutes: !booleanFlag(flags, "keep-existing-routes"),
|
|
350
|
+
dryRun: !confirm,
|
|
351
|
+
confirm,
|
|
352
|
+
context: jsonObjectFlag(flags, "context")
|
|
353
|
+
};
|
|
354
|
+
const result = await signaliz.gtm.activateProviderRoute(input);
|
|
355
|
+
printResult(result, flags);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
printGtmHelp();
|
|
359
|
+
}
|
|
360
|
+
async function handleCampaignAgentCommand(signaliz, argv) {
|
|
361
|
+
const subcommand = argv[0];
|
|
362
|
+
if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
363
|
+
printCampaignAgentHelp();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (["init", "template", "request-template", "new"].includes(subcommand)) {
|
|
367
|
+
const flags2 = parseFlags(argv.slice(1));
|
|
368
|
+
const request2 = campaignAgentRequestTemplateFromFlags(flags2);
|
|
369
|
+
const outputFile = stringFlag(flags2, "output-file", "out");
|
|
370
|
+
if (outputFile) {
|
|
371
|
+
writeFileSync(outputFile, `${JSON.stringify(request2, null, 2)}
|
|
372
|
+
`, "utf8");
|
|
373
|
+
}
|
|
374
|
+
if (booleanFlag(flags2, "json") || !outputFile) {
|
|
375
|
+
printJson(request2);
|
|
376
|
+
} else {
|
|
377
|
+
console.log(`Campaign request template written: ${outputFile}`);
|
|
378
|
+
console.log(`Next: signaliz campaign-agent plan --request-file ${outputFile} --json`);
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (!["plan", "proof", "smoke", "commit-plan", "dry-run", "build-approved", "launch-approved"].includes(subcommand)) {
|
|
383
|
+
printCampaignAgentHelp();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const flags = parseFlags(argv.slice(1));
|
|
387
|
+
const requestFromFile = campaignAgentRequestFileFromFlags(flags);
|
|
388
|
+
const goal = stringFlag(flags, "goal", "brief") ?? stringOrUndefined(requestFromFile?.goal);
|
|
389
|
+
if (!goal) throw new Error(`campaign-agent ${subcommand} requires --goal or a request file with goal`);
|
|
390
|
+
const isApprovedBuild = subcommand === "build-approved" || subcommand === "launch-approved";
|
|
391
|
+
const isCommitPlan = subcommand === "commit-plan";
|
|
392
|
+
const isConfirmedCommit = isCommitPlan && booleanFlag(flags, "confirm-write");
|
|
393
|
+
const approvedBy = stringFlag(flags, "approved-by");
|
|
394
|
+
if (isApprovedBuild) {
|
|
395
|
+
if (!booleanFlag(flags, "confirm-launch")) {
|
|
396
|
+
throw new Error(`campaign-agent ${subcommand} requires --confirm-launch`);
|
|
397
|
+
}
|
|
398
|
+
if (!approvedBy) throw new Error(`campaign-agent ${subcommand} requires --approved-by`);
|
|
399
|
+
}
|
|
400
|
+
if (isConfirmedCommit && !approvedBy) {
|
|
401
|
+
throw new Error("campaign-agent commit-plan --confirm-write requires --approved-by");
|
|
402
|
+
}
|
|
403
|
+
const request = mergeCampaignAgentRequests(
|
|
404
|
+
requestFromFile,
|
|
405
|
+
campaignAgentRequestFromFlags(goal, flags, { includeDefaults: !requestFromFile })
|
|
406
|
+
);
|
|
407
|
+
const plan = await signaliz.campaignBuilderAgent.createPlan(request, {
|
|
408
|
+
discoverCapabilities: !booleanFlag(flags, "skip-discovery"),
|
|
409
|
+
scopeCampaign: !booleanFlag(flags, "skip-scope"),
|
|
410
|
+
includeStrategyMemoryStatus: !booleanFlag(flags, "no-strategy-memory"),
|
|
411
|
+
includeKernelPlan: !booleanFlag(flags, "no-kernel-plan"),
|
|
412
|
+
includeDeliveryRisk: !booleanFlag(flags, "no-delivery-risk")
|
|
413
|
+
});
|
|
414
|
+
if (subcommand === "proof" || subcommand === "smoke") {
|
|
415
|
+
const result = await signaliz.campaignBuilderAgent.dryRunPlan(plan, {
|
|
416
|
+
idempotencyKey: stringFlag(flags, "idempotency-key")
|
|
417
|
+
});
|
|
418
|
+
const proof = createCampaignAgentProofReceipt(plan, result);
|
|
419
|
+
if (booleanFlag(flags, "json")) {
|
|
420
|
+
printJson(proof);
|
|
421
|
+
} else {
|
|
422
|
+
printCampaignAgentProof(proof);
|
|
423
|
+
}
|
|
424
|
+
if (!proof.success) process.exitCode = 1;
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (isCommitPlan) {
|
|
428
|
+
const result = await signaliz.campaignBuilderAgent.commitPlan(plan, {
|
|
429
|
+
confirm: isConfirmedCommit,
|
|
430
|
+
dryRun: !isConfirmedCommit,
|
|
431
|
+
approvedBy,
|
|
432
|
+
idempotencyKey: stringFlag(flags, "idempotency-key"),
|
|
433
|
+
rationale: stringFlag(flags, "rationale")
|
|
434
|
+
});
|
|
435
|
+
printCampaignAgentExecution({ plan, result }, flags);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
if (subcommand === "dry-run") {
|
|
439
|
+
const result = await signaliz.campaignBuilderAgent.dryRunPlan(plan, {
|
|
440
|
+
idempotencyKey: stringFlag(flags, "idempotency-key")
|
|
441
|
+
});
|
|
442
|
+
printCampaignAgentExecution({ plan, result }, flags);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (isApprovedBuild) {
|
|
446
|
+
const approvedTypes = approvedTypesFromFlags(plan, flags);
|
|
447
|
+
const approval = createCampaignBuilderApproval(plan, {
|
|
448
|
+
approvedBy,
|
|
449
|
+
approvedTypes,
|
|
450
|
+
spendLimitCredits: numberFlag(flags, "spend-limit", "spend-limit-credits", "max-credits"),
|
|
451
|
+
approvedRouteIds: approvedRouteIdsFromFlags(plan, flags),
|
|
452
|
+
notes: stringFlag(flags, "approval-notes", "notes")
|
|
453
|
+
});
|
|
454
|
+
const result = await signaliz.campaignBuilderAgent.buildApprovedPlan(plan, approval, {
|
|
455
|
+
idempotencyKey: stringFlag(flags, "idempotency-key"),
|
|
456
|
+
commitBeforeLaunch: booleanFlag(flags, "commit-before-launch")
|
|
457
|
+
});
|
|
458
|
+
printCampaignAgentExecution({ plan, approval, result }, flags);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (booleanFlag(flags, "json")) {
|
|
462
|
+
printJson(plan);
|
|
463
|
+
} else {
|
|
464
|
+
printCampaignAgentPlan(plan);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function campaignAgentRequestTemplateFromFlags(flags) {
|
|
468
|
+
const goal = stringFlag(flags, "goal", "brief") || "Build a strategy-template campaign for mature operators in the target ICP.";
|
|
469
|
+
const request = campaignAgentRequestFromFlags(goal, flags, { includeDefaults: true });
|
|
470
|
+
const options = {
|
|
471
|
+
...request,
|
|
472
|
+
includeLocalLeads: booleanFlag(flags, "use-local-leads"),
|
|
473
|
+
includeCustomToolPlaceholder: booleanFlag(flags, "with-byo-placeholder") || booleanFlag(flags, "include-custom-tool-placeholder") || booleanFlag(flags, "include-byo-placeholder"),
|
|
474
|
+
includeNango: !booleanFlag(flags, "no-nango-catalog")
|
|
475
|
+
};
|
|
476
|
+
return createCampaignBuilderAgentRequestTemplate(options);
|
|
477
|
+
}
|
|
478
|
+
function campaignAgentRequestFileFromFlags(flags) {
|
|
479
|
+
const file = stringFlag(flags, "request-file", "input-file", "campaign-file");
|
|
480
|
+
if (!file) return void 0;
|
|
481
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
482
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
483
|
+
throw new Error(`Expected JSON object for --request-file`);
|
|
484
|
+
}
|
|
485
|
+
return parsed;
|
|
486
|
+
}
|
|
487
|
+
function campaignAgentRequestFromFlags(goal, flags, options = {}) {
|
|
488
|
+
const builtIns = campaignAgentBuiltInsFromFlags(flags);
|
|
489
|
+
const integrations = campaignAgentCustomToolRoutesFromFlags(flags);
|
|
490
|
+
const includeDefaults = options.includeDefaults !== false;
|
|
491
|
+
const request = {
|
|
492
|
+
goal,
|
|
493
|
+
campaignName: stringFlag(flags, "campaign-name", "name"),
|
|
494
|
+
accountLabel: stringFlag(flags, "workspace-label", "account-label"),
|
|
495
|
+
strategyTemplate: stringFlag(flags, "strategy-template", "template"),
|
|
496
|
+
accountContext: stringFlag(flags, "account-context", "workspace-context"),
|
|
497
|
+
targetCount: numberFlag(flags, "target-count", "lead-count"),
|
|
498
|
+
gtmCampaignId: stringFlag(flags, "gtm-campaign-id", "campaign-id"),
|
|
499
|
+
icp: jsonObjectFlag(flags, "icp", "target-icp"),
|
|
500
|
+
brainDefaults: jsonObjectFlag(flags, "brain-defaults"),
|
|
501
|
+
deliveryRisk: jsonObjectFlag(flags, "delivery-risk"),
|
|
502
|
+
builtIns,
|
|
503
|
+
operatingPlaybooks: csvFlag(flags, "operating-playbooks", "playbooks"),
|
|
504
|
+
integrations,
|
|
505
|
+
preferredProviders: csvFlag(flags, "preferred-providers", "providers")
|
|
506
|
+
};
|
|
507
|
+
if (includeDefaults || flagValue(flags, "strategy-model", "no-strategy-patterns", "no-agency-patterns", "no-workflow-patterns", "no-clay-patterns", "no-nango-catalog", "partners", "revenue-motion") !== void 0) {
|
|
508
|
+
request.agencyContext = {
|
|
509
|
+
strategyModel: stringFlag(flags, "strategy-model"),
|
|
510
|
+
includeStrategyPatterns: !booleanFlag(flags, "no-strategy-patterns") && !booleanFlag(flags, "no-agency-patterns"),
|
|
511
|
+
includeWorkflowPatterns: !booleanFlag(flags, "no-workflow-patterns") && !booleanFlag(flags, "no-clay-patterns"),
|
|
512
|
+
includeNangoCatalog: !booleanFlag(flags, "no-nango-catalog"),
|
|
513
|
+
partnerEcosystem: csvFlag(flags, "partners"),
|
|
514
|
+
revenueMotion: stringFlag(flags, "revenue-motion")
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
if (includeDefaults || flagValue(flags, "no-memory", "no-workspace-history", "use-network-patterns", "privacy-mode") !== void 0) {
|
|
518
|
+
request.memory = {
|
|
519
|
+
enabled: !booleanFlag(flags, "no-memory"),
|
|
520
|
+
useWorkspaceHistory: !booleanFlag(flags, "no-workspace-history"),
|
|
521
|
+
useNetworkPatterns: booleanFlag(flags, "use-network-patterns"),
|
|
522
|
+
privacyMode: stringFlag(flags, "privacy-mode")
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
if (includeDefaults || flagValue(flags, "max-credits", "no-delivery", "destination") !== void 0) {
|
|
526
|
+
request.signalizDefaults = {
|
|
527
|
+
maxCredits: numberFlag(flags, "max-credits"),
|
|
528
|
+
delivery: {
|
|
529
|
+
enabled: !booleanFlag(flags, "no-delivery"),
|
|
530
|
+
destinationType: stringFlag(flags, "destination"),
|
|
531
|
+
approvalRequired: true
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
if (includeDefaults || flagValue(flags, "no-human-approval", "max-credits-without-approval") !== void 0) {
|
|
536
|
+
request.approvalPolicy = {
|
|
537
|
+
requireHumanApproval: !booleanFlag(flags, "no-human-approval"),
|
|
538
|
+
maxCreditsWithoutApproval: numberFlag(flags, "max-credits-without-approval"),
|
|
539
|
+
requireApprovalFor: ["memory_retrieval", "spend", "customer_tool", "external_write", "delivery", "launch"]
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return compactRequest(request);
|
|
543
|
+
}
|
|
544
|
+
function mergeCampaignAgentRequests(base, override) {
|
|
545
|
+
if (!base) return override;
|
|
546
|
+
return compactRequest({
|
|
547
|
+
...base,
|
|
548
|
+
...override,
|
|
549
|
+
icp: mergeRecords(base.icp, override.icp),
|
|
550
|
+
memory: mergeRecords(base.memory, override.memory),
|
|
551
|
+
agencyContext: mergeRecords(base.agencyContext, override.agencyContext),
|
|
552
|
+
signalizDefaults: mergeRecords(base.signalizDefaults, override.signalizDefaults),
|
|
553
|
+
approvalPolicy: mergeRecords(base.approvalPolicy, override.approvalPolicy),
|
|
554
|
+
constraints: mergeRecords(base.constraints, override.constraints),
|
|
555
|
+
workspaceContext: mergeRecords(base.workspaceContext, override.workspaceContext),
|
|
556
|
+
builtIns: override.builtIns ?? base.builtIns,
|
|
557
|
+
operatingPlaybooks: override.operatingPlaybooks ?? base.operatingPlaybooks,
|
|
558
|
+
integrations: override.integrations ?? base.integrations,
|
|
559
|
+
customerTools: override.customerTools ?? base.customerTools,
|
|
560
|
+
preferredProviders: override.preferredProviders ?? base.preferredProviders
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
function mergeRecords(base, override) {
|
|
564
|
+
if (!base) return override;
|
|
565
|
+
if (!override) return base;
|
|
566
|
+
if (typeof base === "object" && typeof override === "object" && !Array.isArray(base) && !Array.isArray(override)) {
|
|
567
|
+
return { ...base, ...override };
|
|
568
|
+
}
|
|
569
|
+
return override;
|
|
570
|
+
}
|
|
571
|
+
function compactRequest(record) {
|
|
572
|
+
return Object.fromEntries(
|
|
573
|
+
Object.entries(record).filter(([, value]) => value !== void 0)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
function campaignAgentBuiltInsFromFlags(flags) {
|
|
577
|
+
const explicit = csvFlag(flags, "builtins", "builtin-tools", "signaliz-tools");
|
|
578
|
+
const hasBuiltinFlag = Boolean(
|
|
579
|
+
explicit?.length || flagValue(flags, "use-local-leads") !== void 0 || flagValue(flags, "no-lead-generation") !== void 0 || flagValue(flags, "no-email-finding") !== void 0 || flagValue(flags, "no-verification") !== void 0 || flagValue(flags, "no-signals") !== void 0
|
|
580
|
+
);
|
|
581
|
+
if (!hasBuiltinFlag) return void 0;
|
|
582
|
+
const builtIns = new Set(
|
|
583
|
+
explicit?.length ? explicit : ["lead_generation", "email_finding", "email_verification", "signals"]
|
|
584
|
+
);
|
|
585
|
+
if (booleanFlag(flags, "use-local-leads")) builtIns.add("local_leads");
|
|
586
|
+
if (booleanFlag(flags, "no-lead-generation")) builtIns.delete("lead_generation");
|
|
587
|
+
if (booleanFlag(flags, "no-email-finding")) builtIns.delete("email_finding");
|
|
588
|
+
if (booleanFlag(flags, "no-verification")) builtIns.delete("email_verification");
|
|
589
|
+
if (booleanFlag(flags, "no-signals")) builtIns.delete("signals");
|
|
590
|
+
return [...builtIns];
|
|
591
|
+
}
|
|
592
|
+
function campaignAgentCustomToolRoutesFromFlags(flags) {
|
|
593
|
+
const values = repeatedStringFlag(flags, "custom-tool", "customer-tool", "byo-tool", "integration-route");
|
|
594
|
+
const routes = values.map(parseCampaignAgentCustomToolRoute);
|
|
595
|
+
return routes.length > 0 ? routes : void 0;
|
|
596
|
+
}
|
|
597
|
+
function parseCampaignAgentCustomToolRoute(raw) {
|
|
598
|
+
const record = raw.trim().startsWith("{") ? jsonObjectFromString(raw, "--custom-tool") : raw.includes("=") ? keyValueObject(raw) : colonRouteObject(raw);
|
|
599
|
+
const layer = normalizeCampaignBuilderLayer(String(record.layer ?? record.use_for_layer ?? record.useForLayer ?? "enrichment"));
|
|
600
|
+
const gtmLayers = stringArrayValue(record.gtm_layers ?? record.gtmLayers ?? record.capabilities);
|
|
601
|
+
const provider = String(record.provider ?? record.provider_id ?? record.providerId ?? "custom_mcp");
|
|
602
|
+
const toolName = stringOrUndefined(record.tool ?? record.tool_name ?? record.toolName);
|
|
603
|
+
const label = stringOrUndefined(record.label ?? record.name) ?? provider;
|
|
604
|
+
const mcpServerName = stringOrUndefined(record.mcp ?? record.server ?? record.mcp_server_name ?? record.mcpServerName);
|
|
605
|
+
const mode = normalizeRouteMode(String(record.mode ?? "required"));
|
|
606
|
+
return {
|
|
607
|
+
provider,
|
|
608
|
+
layer,
|
|
609
|
+
gtmLayers,
|
|
610
|
+
mode,
|
|
611
|
+
toolName,
|
|
612
|
+
mcpServerName,
|
|
613
|
+
label,
|
|
614
|
+
approvalRequired: optionalBoolean(record.approval_required ?? record.approvalRequired, true),
|
|
615
|
+
config: {
|
|
616
|
+
provider_id: record.provider_id ?? record.providerId,
|
|
617
|
+
available_tools: stringArrayValue(record.available_tools ?? record.availableTools ?? record.tools),
|
|
618
|
+
raw: raw.trim()
|
|
619
|
+
},
|
|
620
|
+
rationale: `${label} is a user-provided campaign-builder route declared from the CLI.`
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function colonRouteObject(raw) {
|
|
624
|
+
const [provider, layer, tool, mcp] = raw.split(":").map((part) => part.trim()).filter(Boolean);
|
|
625
|
+
if (!provider || !layer) {
|
|
626
|
+
throw new Error("Expected --custom-tool provider:layer:tool[:mcp] or key=value pairs");
|
|
627
|
+
}
|
|
628
|
+
return { provider, layer, tool, mcp };
|
|
629
|
+
}
|
|
630
|
+
function keyValueObject(raw) {
|
|
631
|
+
const record = {};
|
|
632
|
+
for (const segment of raw.split(",")) {
|
|
633
|
+
const eq = segment.indexOf("=");
|
|
634
|
+
if (eq < 0) continue;
|
|
635
|
+
const key = segment.slice(0, eq).trim().replace(/-/g, "_");
|
|
636
|
+
const value = segment.slice(eq + 1).trim();
|
|
637
|
+
record[key] = value;
|
|
638
|
+
}
|
|
639
|
+
return record;
|
|
640
|
+
}
|
|
641
|
+
function normalizeCampaignBuilderLayer(value) {
|
|
642
|
+
const normalized = normalizeEnumValue(value);
|
|
643
|
+
const allowed = ["workspace_context", "memory", "source", "enrichment", "qualification", "copy", "delivery", "feedback", "approval"];
|
|
644
|
+
if (!allowed.includes(normalized)) {
|
|
645
|
+
throw new Error(`Unknown campaign-builder layer "${value}". Use source, enrichment, qualification, copy, delivery, feedback, or approval.`);
|
|
646
|
+
}
|
|
647
|
+
return normalized;
|
|
648
|
+
}
|
|
649
|
+
function normalizeRouteMode(value) {
|
|
650
|
+
const normalized = normalizeEnumValue(value);
|
|
651
|
+
return ["required", "if_available", "fallback", "disabled"].includes(normalized) ? normalized : "required";
|
|
652
|
+
}
|
|
653
|
+
function normalizeEnumValue(value) {
|
|
654
|
+
return value.trim().toLowerCase().replace(/-/g, "_");
|
|
655
|
+
}
|
|
656
|
+
function stringArrayValue(value) {
|
|
657
|
+
const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
658
|
+
const parsed = values.flatMap((item) => String(item).split(/[|,]/).map((part) => part.trim()).filter(Boolean));
|
|
659
|
+
return parsed.length > 0 ? parsed : void 0;
|
|
660
|
+
}
|
|
661
|
+
function stringOrUndefined(value) {
|
|
662
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
663
|
+
}
|
|
664
|
+
function optionalBoolean(value, defaultValue) {
|
|
665
|
+
if (value === void 0) return defaultValue;
|
|
666
|
+
if (typeof value === "boolean") return value;
|
|
667
|
+
return parseBoolean(String(value), defaultValue);
|
|
668
|
+
}
|
|
669
|
+
function approvedTypesFromFlags(plan, flags) {
|
|
670
|
+
const requested = csvFlag(flags, "approved-types", "approve-types");
|
|
671
|
+
if (requested?.length) return requested;
|
|
672
|
+
if (!booleanFlag(flags, "approve-all")) {
|
|
673
|
+
throw new Error("campaign-agent build-approved requires --approve-all or --approved-types");
|
|
674
|
+
}
|
|
675
|
+
return [...new Set(plan.approvals.map((item) => item.type))];
|
|
676
|
+
}
|
|
677
|
+
function approvedRouteIdsFromFlags(plan, flags) {
|
|
678
|
+
const requested = csvFlag(flags, "approved-route-ids", "route-ids");
|
|
679
|
+
if (requested?.length) return requested;
|
|
680
|
+
if (!booleanFlag(flags, "approve-all")) return void 0;
|
|
681
|
+
const routeIds = plan.approvals.map((item) => item.routeId).filter((id) => Boolean(id));
|
|
682
|
+
return routeIds.length > 0 ? routeIds : void 0;
|
|
683
|
+
}
|
|
684
|
+
function parseFlags(argv) {
|
|
685
|
+
const flags = {};
|
|
686
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
687
|
+
const token = argv[i];
|
|
688
|
+
if (!token.startsWith("--")) continue;
|
|
689
|
+
const eq = token.indexOf("=");
|
|
690
|
+
const key = normalizeFlagName(eq >= 0 ? token.slice(2, eq) : token.slice(2));
|
|
691
|
+
const value = eq >= 0 ? token.slice(eq + 1) : argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : true;
|
|
692
|
+
const existing = flags[key];
|
|
693
|
+
if (existing === void 0) {
|
|
694
|
+
flags[key] = value;
|
|
695
|
+
} else if (Array.isArray(existing)) {
|
|
696
|
+
existing.push(String(value));
|
|
697
|
+
} else {
|
|
698
|
+
flags[key] = [String(existing), String(value)];
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return flags;
|
|
702
|
+
}
|
|
703
|
+
function normalizeFlagName(name) {
|
|
704
|
+
return name.replace(/_/g, "-");
|
|
705
|
+
}
|
|
706
|
+
function flagValue(flags, ...names) {
|
|
707
|
+
for (const name of names.map(normalizeFlagName)) {
|
|
708
|
+
if (flags[name] !== void 0) return flags[name];
|
|
709
|
+
}
|
|
710
|
+
return void 0;
|
|
711
|
+
}
|
|
712
|
+
function stringFlag(flags, ...names) {
|
|
713
|
+
const value = flagValue(flags, ...names);
|
|
714
|
+
if (Array.isArray(value)) return value.at(-1);
|
|
715
|
+
if (value === void 0 || value === true || value === false) return void 0;
|
|
716
|
+
const trimmed = String(value).trim();
|
|
717
|
+
return trimmed || void 0;
|
|
718
|
+
}
|
|
719
|
+
function numberFlag(flags, ...names) {
|
|
720
|
+
const value = stringFlag(flags, ...names);
|
|
721
|
+
if (!value) return void 0;
|
|
722
|
+
const parsed = Number(value);
|
|
723
|
+
if (!Number.isFinite(parsed)) throw new Error(`Expected numeric value for --${names[0]}`);
|
|
724
|
+
return parsed;
|
|
725
|
+
}
|
|
726
|
+
function booleanFlag(flags, name, defaultValue = false) {
|
|
727
|
+
const value = flagValue(flags, name);
|
|
728
|
+
if (value === void 0) return defaultValue;
|
|
729
|
+
if (Array.isArray(value)) return value.length > 0 ? parseBoolean(value.at(-1), defaultValue) : defaultValue;
|
|
730
|
+
return parseBoolean(value, defaultValue);
|
|
731
|
+
}
|
|
732
|
+
function parseBoolean(value, defaultValue) {
|
|
733
|
+
if (value === void 0) return defaultValue;
|
|
734
|
+
if (typeof value === "boolean") return value;
|
|
735
|
+
return !["0", "false", "no", "off"].includes(value.toLowerCase());
|
|
736
|
+
}
|
|
737
|
+
function csvFlag(flags, ...names) {
|
|
738
|
+
const value = flagValue(flags, ...names);
|
|
739
|
+
const values = Array.isArray(value) ? value : value === void 0 || typeof value === "boolean" ? [] : [value];
|
|
740
|
+
const parsed = values.flatMap((item) => String(item).split(",").map((part) => part.trim()).filter(Boolean));
|
|
741
|
+
return parsed.length > 0 ? parsed : void 0;
|
|
742
|
+
}
|
|
743
|
+
function repeatedStringFlag(flags, ...names) {
|
|
744
|
+
const value = flagValue(flags, ...names);
|
|
745
|
+
if (Array.isArray(value)) return value.map(String).map((item) => item.trim()).filter(Boolean);
|
|
746
|
+
if (value === void 0 || typeof value === "boolean") return [];
|
|
747
|
+
const trimmed = String(value).trim();
|
|
748
|
+
return trimmed ? [trimmed] : [];
|
|
749
|
+
}
|
|
750
|
+
function jsonObjectFlag(flags, ...names) {
|
|
751
|
+
const value = stringFlag(flags, ...names);
|
|
752
|
+
if (!value) return void 0;
|
|
753
|
+
return jsonObjectFromString(value, `--${names[0]}`);
|
|
754
|
+
}
|
|
755
|
+
function jsonObjectFromString(value, label) {
|
|
756
|
+
const parsed = JSON.parse(value);
|
|
757
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
758
|
+
throw new Error(`Expected JSON object for ${label}`);
|
|
759
|
+
}
|
|
760
|
+
return parsed;
|
|
761
|
+
}
|
|
762
|
+
function printResult(result, flags) {
|
|
763
|
+
if (booleanFlag(flags, "json")) {
|
|
764
|
+
printJson(result);
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (result && typeof result === "object") {
|
|
768
|
+
const record = result;
|
|
769
|
+
const title = record.summary || record.message || record.next_action || record.status;
|
|
770
|
+
if (title) console.log(String(title));
|
|
771
|
+
printJson(result);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
console.log(String(result ?? ""));
|
|
775
|
+
}
|
|
776
|
+
function printCampaignAgentPlan(plan) {
|
|
777
|
+
console.log(`Plan: ${plan.campaignName}`);
|
|
778
|
+
console.log(`Plan ID: ${plan.planId}`);
|
|
779
|
+
console.log(`Target: ${plan.targetCount}`);
|
|
780
|
+
console.log(`Estimated credits: ${plan.estimatedCredits}`);
|
|
781
|
+
console.log(`Memory: ${plan.memory.enabled ? plan.memory.privacyMode : "disabled"}`);
|
|
782
|
+
console.log(`Playbooks: ${plan.operatingPlaybooks.map((item) => item.slug).join(", ") || "none"}`);
|
|
783
|
+
console.log(`Strategy memory: ${plan.strategyMemoryStatus ? plan.strategyMemoryStatus.ready === false ? "needs seeding" : "ready" : "not loaded"}`);
|
|
784
|
+
console.log(`Kernel plan: ${plan.kernelPlan ? "loaded" : "not loaded"}`);
|
|
785
|
+
console.log(`Approvals: ${plan.approvals.map((item) => item.type).join(", ") || "none"}`);
|
|
786
|
+
if (plan.warnings.length > 0) {
|
|
787
|
+
console.log(`Warnings: ${plan.warnings.join("; ")}`);
|
|
788
|
+
}
|
|
789
|
+
console.log("\nMCP flow:");
|
|
790
|
+
for (const step of plan.mcpFlow) {
|
|
791
|
+
console.log(`- ${step.id}: ${step.tool}${step.approvalRequired ? " (approval required)" : ""}`);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function printCampaignAgentExecution(payload, flags) {
|
|
795
|
+
if (booleanFlag(flags, "json")) {
|
|
796
|
+
printJson(payload);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
printCampaignAgentPlan(payload.plan);
|
|
800
|
+
console.log("\nResult:");
|
|
801
|
+
printJson(payload.result);
|
|
802
|
+
}
|
|
803
|
+
function asRecord(value) {
|
|
804
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
805
|
+
}
|
|
806
|
+
function createCampaignAgentProofReceipt(plan, result) {
|
|
807
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
808
|
+
const dryRunResult = asRecord(result);
|
|
809
|
+
const memoryReady = plan.strategyMemoryStatus ? strategyMemory.ready !== false : false;
|
|
810
|
+
const dryRunCompleted = dryRunResult.dryRun === true || dryRunResult.dry_run === true || dryRunResult.status === "dry_run";
|
|
811
|
+
const noLaunch = dryRunCompleted && !dryRunResult.campaignBuildId && !dryRunResult.campaign_build_id;
|
|
812
|
+
const gates = [
|
|
813
|
+
{
|
|
814
|
+
id: "strategy_memory_ready",
|
|
815
|
+
passed: memoryReady,
|
|
816
|
+
ready: strategyMemory.ready ?? null,
|
|
817
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
id: "campaign_plan_ready",
|
|
821
|
+
passed: Boolean(plan.planId && plan.mcpFlow.length > 0),
|
|
822
|
+
plan_id: plan.planId,
|
|
823
|
+
flow_steps: plan.mcpFlow.length
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
id: "approval_gates_present",
|
|
827
|
+
passed: plan.approvals.length > 0,
|
|
828
|
+
approval_types: plan.approvals.map((approval) => approval.type)
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
id: "dry_run_completed",
|
|
832
|
+
passed: dryRunCompleted,
|
|
833
|
+
status: dryRunResult.status ?? null,
|
|
834
|
+
current_phase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
id: "no_spendful_launch",
|
|
838
|
+
passed: noLaunch,
|
|
839
|
+
campaign_build_id: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null
|
|
840
|
+
}
|
|
841
|
+
];
|
|
842
|
+
return {
|
|
843
|
+
receipt_version: "campaign-agent-proof.v1",
|
|
844
|
+
source: "signaliz campaign-agent proof",
|
|
845
|
+
success: gates.every((gate) => gate.passed),
|
|
846
|
+
safety: {
|
|
847
|
+
spendful_tools_called: false,
|
|
848
|
+
external_writes_called: false,
|
|
849
|
+
sender_loads_called: false,
|
|
850
|
+
email_sends_called: false,
|
|
851
|
+
dry_run_only: true
|
|
852
|
+
},
|
|
853
|
+
campaign: {
|
|
854
|
+
plan_id: plan.planId,
|
|
855
|
+
campaign_name: plan.campaignName,
|
|
856
|
+
strategy_template: campaignAgentStrategyTemplate(plan),
|
|
857
|
+
target_count: plan.targetCount,
|
|
858
|
+
estimated_credits: plan.estimatedCredits,
|
|
859
|
+
operating_playbooks: plan.operatingPlaybooks.map((playbook) => playbook.slug)
|
|
860
|
+
},
|
|
861
|
+
gates,
|
|
862
|
+
strategy_memory_status: summarizeCampaignAgentStrategyMemory(strategyMemory),
|
|
863
|
+
dry_run_result: summarizeCampaignAgentDryRun(dryRunResult),
|
|
864
|
+
recommended_next_actions: [
|
|
865
|
+
"Review the plan, approvals, and dry-run result.",
|
|
866
|
+
"Use campaign-agent commit-plan --confirm-write only after review.",
|
|
867
|
+
"Use campaign-agent build-approved only with --confirm-launch, approval identity, approval types, and spend limit."
|
|
868
|
+
]
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function campaignAgentString(...values) {
|
|
872
|
+
for (const value of values) {
|
|
873
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
874
|
+
}
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
function campaignAgentStrategyTemplate(plan) {
|
|
878
|
+
const buildRequest = asRecord(plan.buildRequest);
|
|
879
|
+
const strategyMemory = asRecord(plan.strategyMemoryStatus);
|
|
880
|
+
const statusTemplate = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
881
|
+
const statusTemplateRecord = asRecord(statusTemplate);
|
|
882
|
+
const flowTemplate = plan.mcpFlow.map((step) => asRecord(step.arguments).strategy_template ?? asRecord(step.arguments).strategyTemplate).find((value) => typeof value === "string" && value.trim());
|
|
883
|
+
return campaignAgentString(
|
|
884
|
+
buildRequest.strategyTemplate,
|
|
885
|
+
buildRequest.strategy_template,
|
|
886
|
+
statusTemplate,
|
|
887
|
+
statusTemplateRecord.slug,
|
|
888
|
+
statusTemplateRecord.id,
|
|
889
|
+
flowTemplate
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
function summarizeCampaignAgentStrategyMemory(strategyMemory) {
|
|
893
|
+
if (Object.keys(strategyMemory).length === 0) return { ready: false };
|
|
894
|
+
const template = strategyMemory.strategy_template ?? strategyMemory.strategyTemplate;
|
|
895
|
+
const templateRecord = asRecord(template);
|
|
896
|
+
const coverage = asRecord(strategyMemory.coverage);
|
|
897
|
+
const rawSourceGroups = Array.isArray(strategyMemory.source_groups) ? strategyMemory.source_groups : Array.isArray(strategyMemory.sourceGroups) ? strategyMemory.sourceGroups : [];
|
|
898
|
+
const sourceGroups = rawSourceGroups.map((group) => {
|
|
899
|
+
const sourceGroup = asRecord(group);
|
|
900
|
+
return {
|
|
901
|
+
id: sourceGroup.id ?? null,
|
|
902
|
+
required: sourceGroup.required ?? null,
|
|
903
|
+
ready: sourceGroup.ready ?? null,
|
|
904
|
+
counts: asRecord(sourceGroup.counts)
|
|
905
|
+
};
|
|
906
|
+
});
|
|
907
|
+
return {
|
|
908
|
+
ready: strategyMemory.ready ?? null,
|
|
909
|
+
read_only: strategyMemory.read_only ?? strategyMemory.readOnly ?? null,
|
|
910
|
+
source_tool: campaignAgentString(strategyMemory.source_tool, strategyMemory.sourceTool),
|
|
911
|
+
strategy_template: {
|
|
912
|
+
slug: campaignAgentString(template, templateRecord.slug, templateRecord.id),
|
|
913
|
+
label: campaignAgentString(templateRecord.label)
|
|
914
|
+
},
|
|
915
|
+
coverage: {
|
|
916
|
+
required_groups_ready: coverage.required_groups_ready ?? coverage.requiredGroupsReady ?? null,
|
|
917
|
+
required_groups_total: coverage.required_groups_total ?? coverage.requiredGroupsTotal ?? null,
|
|
918
|
+
source_groups_ready: coverage.source_groups_ready ?? coverage.sourceGroupsReady ?? null,
|
|
919
|
+
source_groups_total: coverage.source_groups_total ?? coverage.sourceGroupsTotal ?? null,
|
|
920
|
+
knowledge_docs: coverage.knowledge_docs ?? coverage.knowledgeDocs ?? null,
|
|
921
|
+
memories: coverage.memories ?? null
|
|
922
|
+
},
|
|
923
|
+
source_groups: sourceGroups,
|
|
924
|
+
blocker_count: Array.isArray(strategyMemory.blockers) ? strategyMemory.blockers.length : 0,
|
|
925
|
+
warning_count: Array.isArray(strategyMemory.warnings) ? strategyMemory.warnings.length : 0
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
function summarizeCampaignAgentDryRun(dryRunResult) {
|
|
929
|
+
return {
|
|
930
|
+
dryRun: dryRunResult.dryRun ?? dryRunResult.dry_run ?? null,
|
|
931
|
+
status: dryRunResult.status ?? null,
|
|
932
|
+
currentPhase: dryRunResult.currentPhase ?? dryRunResult.current_phase ?? null,
|
|
933
|
+
campaignBuildId: dryRunResult.campaignBuildId ?? dryRunResult.campaign_build_id ?? null,
|
|
934
|
+
plannedTargetCount: dryRunResult.plannedTargetCount ?? dryRunResult.planned_target_count ?? null
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
function printCampaignAgentProof(proof) {
|
|
938
|
+
console.log(`Campaign-agent proof: ${proof.success ? "passed" : "failed"}`);
|
|
939
|
+
const campaign = asRecord(proof.campaign);
|
|
940
|
+
if (campaign.plan_id) console.log(`Plan ID: ${campaign.plan_id}`);
|
|
941
|
+
if (campaign.strategy_template) console.log(`Strategy template: ${campaign.strategy_template}`);
|
|
942
|
+
if (campaign.target_count !== void 0) console.log(`Target: ${campaign.target_count}`);
|
|
943
|
+
console.log("\nGates:");
|
|
944
|
+
const gates = Array.isArray(proof.gates) ? proof.gates : [];
|
|
945
|
+
for (const gate of gates) {
|
|
946
|
+
const gateRecord = asRecord(gate);
|
|
947
|
+
console.log(`- ${gateRecord.id}: ${gateRecord.passed ? "passed" : "failed"}`);
|
|
948
|
+
}
|
|
949
|
+
console.log("\nSafety: dry-run only; no spendful launch, external write, sender load, or email send.");
|
|
950
|
+
}
|
|
951
|
+
function printJson(value) {
|
|
952
|
+
console.log(JSON.stringify(value, null, 2));
|
|
953
|
+
}
|
|
954
|
+
function printHelp() {
|
|
955
|
+
console.log(`
|
|
48
956
|
Signaliz CLI v1.0.0
|
|
49
957
|
|
|
50
958
|
Usage:
|
|
51
|
-
signaliz test
|
|
52
|
-
signaliz tools
|
|
959
|
+
signaliz test Verify API connectivity
|
|
960
|
+
signaliz tools List all available MCP tools
|
|
961
|
+
signaliz gtm context --json Load GTM Kernel workspace context
|
|
962
|
+
signaliz gtm bootstrap --json Inspect GTM Kernel readiness
|
|
963
|
+
signaliz gtm templates --json List private-safe campaign strategy templates
|
|
964
|
+
signaliz gtm start-context --strategy-template non-medical-home-care --json
|
|
965
|
+
signaliz gtm strategy-memory --strategy-template non-medical-home-care --include-samples --json
|
|
966
|
+
signaliz gtm agent-plan --goal "Build a strategy-template campaign" --strategy-template non-medical-home-care --target-count 500 --json
|
|
967
|
+
signaliz gtm provider-prepare --provider-id customer_mcp --layer company_enrichment --invocation-type mcp_tool --json
|
|
968
|
+
signaliz gtm memory search --query "proof-first vertical gate" --json
|
|
969
|
+
signaliz gtm plan --brief "Build 500 verified leads for..." --strategy-template non-medical-home-care --lead-count 500 --json
|
|
970
|
+
signaliz campaign-agent init --strategy-template non-medical-home-care --target-count 250 --use-local-leads --json > campaign-request.json
|
|
971
|
+
signaliz campaign-agent plan --goal "Build a strategy-template campaign..." --strategy-template industrial-ot-resilience --target-count 500 --builtins lead_generation,email_finding,email_verification,signals
|
|
972
|
+
signaliz campaign-agent proof --goal "Build a strategy-template campaign..." --strategy-template non-medical-home-care --target-count 100 --json
|
|
973
|
+
signaliz campaign-agent plan --request-file examples/campaign-builder-agent-request.json --target-count 250 --json
|
|
974
|
+
signaliz campaign-agent commit-plan --goal "Build a strategy-template campaign..." --json
|
|
975
|
+
signaliz campaign-agent dry-run --goal "Build a strategy-template campaign..." --target-count 500 --use-local-leads --json
|
|
976
|
+
signaliz campaign-agent build-approved --goal "Build a strategy-template campaign..." --confirm-launch --approve-all --approved-by you@example.com --spend-limit 500
|
|
53
977
|
|
|
54
978
|
Environment:
|
|
55
|
-
SIGNALIZ_API_KEY
|
|
979
|
+
SIGNALIZ_API_KEY Your API key (not required for campaign-agent init)
|
|
980
|
+
SIGNALIZ_BASE_URL Optional API base URL override
|
|
981
|
+
`);
|
|
982
|
+
}
|
|
983
|
+
function printGtmHelp() {
|
|
984
|
+
console.log(`
|
|
985
|
+
Signaliz GTM commands:
|
|
986
|
+
|
|
987
|
+
signaliz gtm context [--include-campaigns] [--include-memory] [--include-brain] [--include-connections] [--limit N] [--json]
|
|
988
|
+
signaliz gtm bootstrap [--campaign-id ID] [--days N] [--include-connections] [--include-samples] [--json]
|
|
989
|
+
signaliz gtm templates [--query TEXT] [--strategy-template ID] [--summary] [--json]
|
|
990
|
+
signaliz gtm start-context [--brief TEXT] [--strategy-template ID] [--target-count N] [--layers a,b] [--providers a,b] [--json]
|
|
991
|
+
signaliz gtm strategy-memory [--query TEXT] [--strategy-template ID] [--include-samples] [--json]
|
|
992
|
+
signaliz gtm provider-prepare --provider-id ID [--layer NAME] [--invocation-type webhook|mcp_tool|api] [--json]
|
|
993
|
+
signaliz gtm activate-route --provider-id ID --layer NAME [--confirm] [--json]
|
|
994
|
+
signaliz gtm memory search --query TEXT [--layers a,b] [--provider-chain a,b] [--limit N] [--json]
|
|
995
|
+
signaliz gtm plan --brief TEXT [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--lead-count N] [--layers a,b] [--providers a,b] [--partners clay,instantly,nango] [--target-icp JSON] [--json]
|
|
996
|
+
`);
|
|
997
|
+
}
|
|
998
|
+
function printCampaignAgentHelp() {
|
|
999
|
+
console.log(`
|
|
1000
|
+
Signaliz campaign-agent commands:
|
|
1001
|
+
|
|
1002
|
+
signaliz campaign-agent init [--goal TEXT] [--strategy-template ID] [--target-count N] [--use-local-leads] [--with-byo-placeholder] [--output-file FILE] [--json]
|
|
1003
|
+
signaliz campaign-agent plan (--goal TEXT | --request-file FILE) [--campaign-name NAME] [--workspace-label NAME] [--strategy-template industrial-ot-resilience|non-medical-home-care|agency-founder-led|cloud-infrastructure-displacement] [--operating-playbooks proof-first-vertical-gate,signal-led-copy-approval] [--target-count N] [--icp JSON] [--builtins lead_generation,email_finding,email_verification,signals,local_leads] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--preferred-providers signaliz_native,octave] [--partners clay,instantly,nango] [--no-strategy-memory] [--no-kernel-plan] [--no-delivery-risk] [--json]
|
|
1004
|
+
signaliz campaign-agent proof (--goal TEXT | --request-file FILE) [--strategy-template ID] [--target-count N] [--use-local-leads] [--custom-tool provider:layer:tool[:mcp]] [--idempotency-key KEY] [--json]
|
|
1005
|
+
signaliz campaign-agent commit-plan (--goal TEXT | --request-file FILE) [--confirm-write --approved-by EMAIL] [--idempotency-key KEY] [--json]
|
|
1006
|
+
signaliz campaign-agent dry-run (--goal TEXT | --request-file FILE) [--gtm-campaign-id ID] [--delivery-risk JSON] [--idempotency-key KEY] [--json]
|
|
1007
|
+
signaliz campaign-agent build-approved (--goal TEXT | --request-file FILE) --confirm-launch --approved-by EMAIL (--approve-all | --approved-types a,b) [--commit-before-launch] [--spend-limit N] [--approved-route-ids a,b] [--idempotency-key KEY] [--json]
|
|
1008
|
+
|
|
1009
|
+
The init command emits a reusable JSON CampaignBuilderAgentRequest. The plan command composes an approval-gated strategy-template MCP flow. Proof runs the same plan path plus build_campaign dry_run=true and returns a no-spend receipt. Use --request-file to load a reusable request, then override fields such as --target-count or --strategy-template from the command line. Use --strategy-template to merge a private-safe strategy pattern into the plan without exposing private account labels, and --operating-playbooks to add reusable build-loop gates such as proof-first vertical qualification, net-new suppression, cache-first inventory, and signal-led copy approval. Built-ins map to Signaliz-native tools: lead_generation -> generate_leads, local_leads -> generate_local_leads, email_finding -> find_and_verify_emails, email_verification -> verify_emails, signals -> enrich_company_signals. Add BYO tools with --custom-tool provider:layer:tool[:mcp] or key=value pairs such as provider=apollo,layer=source,tool=apollo_search,mcp=apollo. Use --no-strategy-patterns or --no-workflow-patterns to disable default private strategy memory hints. Commit-plan dry-runs by default and writes only with --confirm-write plus approval identity. Dry-run executes build_campaign with dry_run=true. Approved build requires explicit launch confirmation and approval metadata; add --commit-before-launch to persist the reviewed plan as a GTM campaign before launch.
|
|
56
1010
|
`);
|
|
57
|
-
}
|
|
58
1011
|
}
|
|
59
1012
|
main().catch((e) => {
|
|
60
1013
|
console.error(e);
|