@oxygen-agent/cli 1.1003.12 → 1.1010.644
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 +1 -1
- package/dist/column-decision-options.d.ts +20 -0
- package/dist/column-decision-options.js +54 -0
- package/dist/command-manifest.js +15 -2
- package/dist/functions-commands.js +11 -11
- package/dist/index.js +1222 -159
- package/dist/search-ai-filter-notice.d.ts +17 -0
- package/dist/search-ai-filter-notice.js +38 -0
- package/dist/skills.js +34 -10
- package/dist/util.d.ts +9 -0
- package/dist/util.js +14 -0
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +296 -140
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +9 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +34 -0
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/billing.js +45 -0
- package/node_modules/@oxygen/shared/dist/byok-connect.js +5 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +223 -13
- package/node_modules/@oxygen/shared/dist/cli-http-error.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/cli-http-error.js +8 -0
- package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.js +5 -23
- package/node_modules/@oxygen/shared/dist/column-decision.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/column-decision.js +228 -0
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +9 -4
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +11 -8
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +4 -4
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +4 -4
- package/node_modules/@oxygen/shared/dist/cutover-freeze.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/cutover-freeze.js +52 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.d.ts +57 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.js +59 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.d.ts +6 -2
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +13 -23
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +60 -4
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +125 -10
- package/node_modules/@oxygen/shared/dist/index.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/index.js +2 -0
- package/node_modules/@oxygen/shared/dist/langfuse.d.ts +44 -1
- package/node_modules/@oxygen/shared/dist/langfuse.js +407 -14
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +2 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.js +276 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.js +5 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.d.ts +44 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.js +116 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +123 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.js +89 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.d.ts +75 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.js +161 -0
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +90 -0
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.js +130 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +73 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +29 -4
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +189 -36
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +21 -2
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +21 -1
- package/node_modules/@oxygen/shared/dist/redaction.js +4 -1
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.js +23 -0
- package/node_modules/@oxygen/shared/dist/sequences.js +5 -1
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.d.ts +80 -0
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.js +198 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.js +25 -16
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.js +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.d.ts +31 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.js +103 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.js +213 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.js +78 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.js +51 -0
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +184 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.js +44 -0
- package/node_modules/@oxygen/shared/dist/table-limits.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/table-limits.js +3 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +94 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +298 -0
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +19 -1
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +22 -11
- package/node_modules/@oxygen/shared/dist/ugc.js +10 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/version.generated.js +2 -0
- package/node_modules/@oxygen/shared/dist/version.js +8 -1
- package/node_modules/@oxygen/shared/dist/workspace-event-catalog.js +0 -23
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +31 -0
- package/node_modules/@oxygen/shared/package.json +9 -0
- package/package.json +2 -1
|
@@ -2,13 +2,14 @@ import { parseField } from "./field-parser.js";
|
|
|
2
2
|
export function registerUgcCommands(program, { request: requestOxygen, handle }) {
|
|
3
3
|
const ugc = program
|
|
4
4
|
.command("ugc")
|
|
5
|
-
.description("Manage UGC programs and independent creator participations:
|
|
5
|
+
.description("Manage UGC programs and independent creator participations: voice, posts, approvals, sponsorship and bounded amplification. Requires UGC availability. Start with memberships list in a creator workspace. See the oxygen-ugc skill; JSON reads return web_url for inspection.");
|
|
6
6
|
const groupDescriptions = {
|
|
7
|
-
programs: "Programs you operate or joined. Lifecycle: create, update, duplicate (settings
|
|
8
|
-
creators: "Creator participations: invite, revoke an invite, accept in the creator workspace, connect a sender, change approval authority, or revoke.",
|
|
9
|
-
memberships: "Active programs this creator workspace has joined. Read these before choosing a program for a personal post.",
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
programs: "Programs you operate or joined; discover public programs from other brands and apply to them. Lifecycle: create, update, duplicate (settings), archive (stops future work, keeps shared history, reversible with restore) and delete (permanent; only while no creator has ever joined).",
|
|
8
|
+
creators: "Creator participations: invite, set one creator's own posting deal, revoke an invite, accept in the creator workspace, connect a sender, change approval authority, or revoke.",
|
|
9
|
+
memberships: "Active programs this creator workspace has joined, each with your deal (posting_target), this period's progress and your published posts. Your own numbers only. Read these before choosing a program for a personal post.",
|
|
10
|
+
applications: "Applications to public programs: the ones you sent as a creator, or the ones your program received as a brand.",
|
|
11
|
+
profile: "Your creator profile: the topics you post about, who follows you and your LinkedIn profile URL (used when you apply), readable by the brands whose programs you joined. Name, picture and headline come from your connected LinkedIn account.",
|
|
12
|
+
posts: "Enrolled program posts: enroll existing posts, draft from a topic, edit, schedule, record creator or brand approval, and schedule one-off comments on program posts.",
|
|
12
13
|
analytics: "Stored daily program and creator performance.",
|
|
13
14
|
knowledge: "Master Knowledge pages shared live with a program.",
|
|
14
15
|
voice: "Creator voice profiles and imports.",
|
|
@@ -62,7 +63,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
62
63
|
}));
|
|
63
64
|
group("creators")
|
|
64
65
|
.command("list")
|
|
65
|
-
.description("Read creators and invitations, including persisted email delivery status. Read-only.")
|
|
66
|
+
.description("Read creators (name, picture, LinkedIn URL and posting_target, their own deal; null follows the program standard) and invitations, including persisted email delivery status. Read-only.")
|
|
66
67
|
.option("--program-id <id>", "Program ID.")
|
|
67
68
|
.option("--participation-id <id>", "Creator participation ID.")
|
|
68
69
|
.option("--json", "Print a JSON envelope.")
|
|
@@ -74,26 +75,38 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
74
75
|
query.set("participation_id", String(options.participationId));
|
|
75
76
|
return requestOxygen(`/api/cli/ugc?${query}`);
|
|
76
77
|
}));
|
|
77
|
-
group("
|
|
78
|
-
.command("
|
|
79
|
-
.description("Read
|
|
78
|
+
group("creators")
|
|
79
|
+
.command("invitation")
|
|
80
|
+
.description("Read what an invitation link points at before accepting it: the program, the invited email (masked), the posting deal, and can_accept with the reason when this account or workspace cannot accept it. Free, read-only.")
|
|
81
|
+
.requiredOption("--token <token>", "The token from the invitation link (?invite=...).")
|
|
80
82
|
.option("--json", "Print a JSON envelope.")
|
|
81
|
-
.action((options) => handle("ugc
|
|
82
|
-
group("
|
|
83
|
+
.action((options) => handle("ugc creators invitation", options, () => requestOxygen(`/api/cli/ugc?${new URLSearchParams({ view: "invitation", token: String(options.token) })}`)));
|
|
84
|
+
group("programs")
|
|
85
|
+
.command("discover")
|
|
86
|
+
.description("Public programs from every brand on Oxygen that you can apply to, with each brand's deal and brief excerpt, and whether you already joined or applied. Free, read-only.")
|
|
87
|
+
.option("--json", "Print a JSON envelope.")
|
|
88
|
+
.action((options) => handle("ugc programs discover", options, () => requestOxygen("/api/cli/ugc?view=discover")));
|
|
89
|
+
group("applications")
|
|
83
90
|
.command("list")
|
|
84
|
-
.description("
|
|
85
|
-
.
|
|
86
|
-
.requiredOption("--program-id <id>", "Program ID.")
|
|
87
|
-
.option("--participation-id <id>", "Creator participation ID.")
|
|
91
|
+
.description("Applications to public programs. Without --program-id: the ones this creator workspace sent, with status. With --program-id: the ones your program received (brand), pending first. Read-only.")
|
|
92
|
+
.option("--program-id <id>", "Your program's ID, to see who applied to it.")
|
|
88
93
|
.option("--json", "Print a JSON envelope.")
|
|
89
|
-
.action((options) => handle("ugc
|
|
90
|
-
const query = new URLSearchParams({ view: "
|
|
94
|
+
.action((options) => handle("ugc applications list", options, () => {
|
|
95
|
+
const query = new URLSearchParams({ view: "applications" });
|
|
91
96
|
if (options.programId)
|
|
92
97
|
query.set("program_id", String(options.programId));
|
|
93
|
-
if (options.participationId)
|
|
94
|
-
query.set("participation_id", String(options.participationId));
|
|
95
98
|
return requestOxygen(`/api/cli/ugc?${query}`);
|
|
96
99
|
}));
|
|
100
|
+
group("profile")
|
|
101
|
+
.command("get")
|
|
102
|
+
.description("Read your creator profile (topics, audience and LinkedIn profile URL). Free, read-only.")
|
|
103
|
+
.option("--json", "Print a JSON envelope.")
|
|
104
|
+
.action((options) => handle("ugc profile get", options, () => requestOxygen("/api/cli/ugc?view=creator_profile")));
|
|
105
|
+
group("memberships")
|
|
106
|
+
.command("list")
|
|
107
|
+
.description("Read active program memberships for the creator workspace. Free, stored and provider-free.")
|
|
108
|
+
.option("--json", "Print a JSON envelope.")
|
|
109
|
+
.action((options) => handle("ugc memberships list", options, () => requestOxygen("/api/cli/ugc?view=memberships")));
|
|
97
110
|
group("posts")
|
|
98
111
|
.command("list")
|
|
99
112
|
.description("Read UGC posts in the active workspace. Read-only.")
|
|
@@ -122,7 +135,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
122
135
|
}));
|
|
123
136
|
group("analytics")
|
|
124
137
|
.command("get")
|
|
125
|
-
.description("Read UGC analytics in the active workspace. Read-only.")
|
|
138
|
+
.description("Read UGC analytics in the active workspace. Read-only. The brand workspace sees every creator; a creator workspace only ever gets its own row, with or without --participation-id.")
|
|
126
139
|
.requiredOption("--program-id <id>", "Program ID.")
|
|
127
140
|
.option("--participation-id <id>", "Creator participation ID.")
|
|
128
141
|
.option("--post-cursor <cursor>", "Next post_performance page from next_post_cursor; totals still cover all enrolled posts.")
|
|
@@ -276,19 +289,25 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
276
289
|
{
|
|
277
290
|
action: "program_create",
|
|
278
291
|
command: "programs create",
|
|
279
|
-
description: "Create a master UGC program. Free: 0 credits, no provider call.",
|
|
292
|
+
description: "Create a master UGC program from its product link. The name defaults to the site's name and its icon is fetched from the site. Free: 0 credits, no provider call.",
|
|
280
293
|
fields: [
|
|
281
294
|
{
|
|
282
|
-
name: "
|
|
295
|
+
name: "product_url",
|
|
283
296
|
kind: "string",
|
|
284
|
-
description: "
|
|
297
|
+
description: "Product domain or link, e.g. acme.com.",
|
|
285
298
|
required: true,
|
|
286
299
|
},
|
|
287
300
|
{
|
|
288
|
-
name: "
|
|
301
|
+
name: "name",
|
|
289
302
|
kind: "string",
|
|
290
|
-
description: "
|
|
291
|
-
required:
|
|
303
|
+
description: "Program name; defaults to the product site's name, else its domain.",
|
|
304
|
+
required: false,
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: "brief",
|
|
308
|
+
kind: "string",
|
|
309
|
+
description: "Short creator brief (up to 1,200 characters): what the product is, who it is for, key facts and the call to action. Drafts are grounded in it.",
|
|
310
|
+
required: false,
|
|
292
311
|
},
|
|
293
312
|
{
|
|
294
313
|
name: "description",
|
|
@@ -308,6 +327,18 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
308
327
|
description: "Require a separate brand approval before publishing.",
|
|
309
328
|
required: false,
|
|
310
329
|
},
|
|
330
|
+
{
|
|
331
|
+
name: "posting_target",
|
|
332
|
+
kind: "posting_target",
|
|
333
|
+
description: "Posts each creator should publish by default: <n>/month, <n>/week or <n>/total (n 1–100), or none to clear. One creator's own deal: creators set-target.",
|
|
334
|
+
required: false,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: "visibility",
|
|
338
|
+
kind: "string",
|
|
339
|
+
description: "private (default: invitation only) or public (listed in every creator's Discover, where creators apply and you approve).",
|
|
340
|
+
required: false,
|
|
341
|
+
},
|
|
311
342
|
],
|
|
312
343
|
},
|
|
313
344
|
{
|
|
@@ -330,7 +361,13 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
330
361
|
{
|
|
331
362
|
name: "product_url",
|
|
332
363
|
kind: "string",
|
|
333
|
-
description: "Product
|
|
364
|
+
description: "Product domain or link; a new one refreshes the icon.",
|
|
365
|
+
required: false,
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: "brief",
|
|
369
|
+
kind: "string",
|
|
370
|
+
description: "Short creator brief (up to 1,200 characters); an empty string clears it.",
|
|
334
371
|
required: false,
|
|
335
372
|
},
|
|
336
373
|
{
|
|
@@ -351,6 +388,18 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
351
388
|
description: "Require a separate brand approval before publishing.",
|
|
352
389
|
required: false,
|
|
353
390
|
},
|
|
391
|
+
{
|
|
392
|
+
name: "posting_target",
|
|
393
|
+
kind: "posting_target",
|
|
394
|
+
description: "Posts each creator should publish by default: <n>/month, <n>/week or <n>/total (n 1–100), or none to clear. One creator's own deal: creators set-target.",
|
|
395
|
+
required: false,
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: "visibility",
|
|
399
|
+
kind: "string",
|
|
400
|
+
description: "private (default: invitation only) or public (listed in every creator's Discover, where creators apply and you approve).",
|
|
401
|
+
required: false,
|
|
402
|
+
},
|
|
354
403
|
{
|
|
355
404
|
name: "peer_engagement_enabled",
|
|
356
405
|
kind: "boolean",
|
|
@@ -396,7 +445,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
396
445
|
{
|
|
397
446
|
action: "program_duplicate",
|
|
398
447
|
command: "programs duplicate",
|
|
399
|
-
description: "Copy a program's settings, shared knowledge
|
|
448
|
+
description: "Copy a program's settings, shared knowledge, brand review and posting target into a new active program. Free: 0 credits. Never copies creators, invitations, posts or sponsorship.",
|
|
400
449
|
fields: [
|
|
401
450
|
{
|
|
402
451
|
name: "program_id",
|
|
@@ -410,18 +459,12 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
410
459
|
description: 'Name of the copy; defaults to "<name> (copy)".',
|
|
411
460
|
required: false,
|
|
412
461
|
},
|
|
413
|
-
{
|
|
414
|
-
name: "include_briefs",
|
|
415
|
-
kind: "boolean",
|
|
416
|
-
description: "Copy the program's briefs (default true).",
|
|
417
|
-
required: false,
|
|
418
|
-
},
|
|
419
462
|
],
|
|
420
463
|
},
|
|
421
464
|
{
|
|
422
465
|
action: "program_delete",
|
|
423
466
|
command: "programs delete",
|
|
424
|
-
description: "Permanently delete a program
|
|
467
|
+
description: "Permanently delete a program and its pending invitations. A bare call previews the counts and whether it is deletable; pass --approved to delete. Allowed only while no creator has ever joined; otherwise use `programs archive`.",
|
|
425
468
|
fields: [
|
|
426
469
|
{
|
|
427
470
|
name: "program_id",
|
|
@@ -440,7 +483,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
440
483
|
{
|
|
441
484
|
action: "invite_create",
|
|
442
485
|
command: "creators invite",
|
|
443
|
-
description: "Preview an invitation email (0 credits); send with --approved --preview-token from that preview. Use --link-only to create
|
|
486
|
+
description: "Preview an invitation email (0 credits) for one creator (--email) or up to 50 at once (--emails); send with --approved --preview-token from that preview and the same recipients. Use --link-only to create links without email.",
|
|
444
487
|
fields: [
|
|
445
488
|
{
|
|
446
489
|
name: "program_id",
|
|
@@ -452,7 +495,31 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
452
495
|
name: "email",
|
|
453
496
|
kind: "string",
|
|
454
497
|
description: "Exact creator email to receive the invitation.",
|
|
455
|
-
required:
|
|
498
|
+
required: false,
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
name: "emails",
|
|
502
|
+
kind: "email_list",
|
|
503
|
+
description: "Several creator emails, comma-separated or a JSON array (1–50, duplicates removed).",
|
|
504
|
+
required: false,
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
name: "posting_target",
|
|
508
|
+
kind: "posting_target",
|
|
509
|
+
description: "These creators' own deal when it differs from the program standard, e.g. 1/month; omit to follow the program. Change it later with creators set-target.",
|
|
510
|
+
required: false,
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: "email_subject",
|
|
514
|
+
kind: "string",
|
|
515
|
+
description: "Your own email subject (up to 200 characters); omit for the default.",
|
|
516
|
+
required: false,
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: "email_message",
|
|
520
|
+
kind: "string",
|
|
521
|
+
description: "Your own message (up to 3,000 characters); the Accept button and join link are always added below it. Omit for the default.",
|
|
522
|
+
required: false,
|
|
456
523
|
},
|
|
457
524
|
{
|
|
458
525
|
name: "approved",
|
|
@@ -468,6 +535,92 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
468
535
|
},
|
|
469
536
|
],
|
|
470
537
|
},
|
|
538
|
+
{
|
|
539
|
+
action: "application_create",
|
|
540
|
+
command: "programs apply",
|
|
541
|
+
description: "Apply to a public program from programs discover, with a short note to the brand. The brand approves or declines; approval makes you a creator in the program and emails you. Free: 0 credits.",
|
|
542
|
+
fields: [
|
|
543
|
+
{ name: "program_id", kind: "string", description: "Public program ID from programs discover.", required: true },
|
|
544
|
+
{ name: "message", kind: "string", description: "Your note to the brand (up to 600 characters).", required: true },
|
|
545
|
+
{ name: "linkedin_url", kind: "string", description: "Your LinkedIn profile URL; passing it also saves it to your profile. Omit to use the one on your profile (ugc profile get); if neither exists, ask the person rather than guess.", required: false },
|
|
546
|
+
],
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
action: "application_decide",
|
|
550
|
+
command: "creators approve",
|
|
551
|
+
description: "Approve a pending application to your program (from applications list --program-id). The applicant becomes a creator at once and is emailed. Free: 0 credits.",
|
|
552
|
+
fixed: { decision: "approve" },
|
|
553
|
+
fields: [
|
|
554
|
+
{ name: "program_id", kind: "string", description: "Program ID.", required: true },
|
|
555
|
+
{ name: "application_id", kind: "string", description: "Pending application ID.", required: true },
|
|
556
|
+
],
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
action: "application_decide",
|
|
560
|
+
command: "creators decline",
|
|
561
|
+
description: "Decline a pending application to your program. No email is sent. Free: 0 credits.",
|
|
562
|
+
fixed: { decision: "decline" },
|
|
563
|
+
fields: [
|
|
564
|
+
{ name: "program_id", kind: "string", description: "Program ID.", required: true },
|
|
565
|
+
{ name: "application_id", kind: "string", description: "Pending application ID.", required: true },
|
|
566
|
+
],
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
action: "creator_profile_update",
|
|
570
|
+
command: "profile update",
|
|
571
|
+
description: "Save your creator profile, which brands whose programs you joined can read. --topics replaces the list; --audience \"\" clears it. Free: 0 credits.",
|
|
572
|
+
fields: [
|
|
573
|
+
{
|
|
574
|
+
name: "topics",
|
|
575
|
+
kind: "text_list",
|
|
576
|
+
description: "Topics you post about, comma-separated (up to 10, each up to 40 characters), e.g. \"B2B sales, outbound\".",
|
|
577
|
+
required: false,
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
name: "audience",
|
|
581
|
+
kind: "string",
|
|
582
|
+
description: "Who follows you, one line (up to 200 characters).",
|
|
583
|
+
required: false,
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
name: "linkedin_url",
|
|
587
|
+
kind: "string",
|
|
588
|
+
description: "Your LinkedIn profile URL, used when you apply to public programs; \"\" clears it.",
|
|
589
|
+
required: false,
|
|
590
|
+
},
|
|
591
|
+
],
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
action: "creator_target_update",
|
|
595
|
+
command: "creators set-target",
|
|
596
|
+
description: "Set one creator's own posting deal, e.g. 1/month while the program asks for 2/month, on a joined creator (--participation-id) or a pending invitation (--invitation-id). none returns them to the program standard. Organizer only. Free: 0 credits.",
|
|
597
|
+
fields: [
|
|
598
|
+
{
|
|
599
|
+
name: "program_id",
|
|
600
|
+
kind: "string",
|
|
601
|
+
description: "Program ID.",
|
|
602
|
+
required: true,
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
name: "participation_id",
|
|
606
|
+
kind: "string",
|
|
607
|
+
description: "A joined creator's participation ID from creators list.",
|
|
608
|
+
required: false,
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
name: "invitation_id",
|
|
612
|
+
kind: "string",
|
|
613
|
+
description: "A pending invitation ID from creators list.",
|
|
614
|
+
required: false,
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: "posting_target",
|
|
618
|
+
kind: "posting_target",
|
|
619
|
+
description: "The creator's deal: <n>/month, <n>/week or <n>/total (n 1–100), or none for the program standard.",
|
|
620
|
+
required: true,
|
|
621
|
+
},
|
|
622
|
+
],
|
|
623
|
+
},
|
|
471
624
|
{
|
|
472
625
|
action: "invite_send",
|
|
473
626
|
command: "creators send-invite",
|
|
@@ -485,6 +638,18 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
485
638
|
description: "Exact pending invitation ID from creators list.",
|
|
486
639
|
required: true,
|
|
487
640
|
},
|
|
641
|
+
{
|
|
642
|
+
name: "email_subject",
|
|
643
|
+
kind: "string",
|
|
644
|
+
description: "Your own email subject (up to 200 characters); omit for the default.",
|
|
645
|
+
required: false,
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
name: "email_message",
|
|
649
|
+
kind: "string",
|
|
650
|
+
description: "Your own message (up to 3,000 characters); the Accept button and join link are always added below it. Omit for the default.",
|
|
651
|
+
required: false,
|
|
652
|
+
},
|
|
488
653
|
{
|
|
489
654
|
name: "approved",
|
|
490
655
|
kind: "boolean",
|
|
@@ -521,7 +686,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
521
686
|
{
|
|
522
687
|
action: "invite_accept",
|
|
523
688
|
command: "creators accept",
|
|
524
|
-
description: "Accept an exact invitation in the creator workspace
|
|
689
|
+
description: "Accept an exact invitation in the creator workspace. Check it first with creators invitation --token; a refusal names its reason (wrong account, the program's own workspace, withdrawn or expired).",
|
|
525
690
|
fields: [
|
|
526
691
|
{
|
|
527
692
|
name: "token",
|
|
@@ -532,8 +697,8 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
532
697
|
{
|
|
533
698
|
name: "approval_mode",
|
|
534
699
|
kind: "string",
|
|
535
|
-
description: "creator:
|
|
536
|
-
required:
|
|
700
|
+
description: "creator (default): you approve each post; delegated: master operators may approve and schedule.",
|
|
701
|
+
required: false,
|
|
537
702
|
},
|
|
538
703
|
{
|
|
539
704
|
name: "linkedin_url",
|
|
@@ -574,86 +739,6 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
574
739
|
},
|
|
575
740
|
],
|
|
576
741
|
},
|
|
577
|
-
{
|
|
578
|
-
action: "brief_create",
|
|
579
|
-
command: "briefs create",
|
|
580
|
-
description: "Create a brief with ordered questions. Free: 0 credits, no provider call.",
|
|
581
|
-
fields: [
|
|
582
|
-
{
|
|
583
|
-
name: "program_id",
|
|
584
|
-
kind: "string",
|
|
585
|
-
description: "Program ID.",
|
|
586
|
-
required: true,
|
|
587
|
-
},
|
|
588
|
-
{
|
|
589
|
-
name: "title",
|
|
590
|
-
kind: "string",
|
|
591
|
-
description: "Brief or post title.",
|
|
592
|
-
required: true,
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
name: "prompt",
|
|
596
|
-
kind: "string",
|
|
597
|
-
description: "Instructions for this brief.",
|
|
598
|
-
required: true,
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
name: "questions",
|
|
602
|
-
kind: "array",
|
|
603
|
-
description: "Ordered questions for the creator.",
|
|
604
|
-
required: true,
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
name: "cycle",
|
|
608
|
-
kind: "string",
|
|
609
|
-
description: "Brief cycle label.",
|
|
610
|
-
required: false,
|
|
611
|
-
},
|
|
612
|
-
],
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
action: "brief_update",
|
|
616
|
-
command: "briefs update",
|
|
617
|
-
description: "Update a program brief.",
|
|
618
|
-
fields: [
|
|
619
|
-
{
|
|
620
|
-
name: "program_id",
|
|
621
|
-
kind: "string",
|
|
622
|
-
description: "Program ID.",
|
|
623
|
-
required: true,
|
|
624
|
-
},
|
|
625
|
-
{
|
|
626
|
-
name: "brief_id",
|
|
627
|
-
kind: "string",
|
|
628
|
-
description: "Brief ID.",
|
|
629
|
-
required: true,
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
name: "title",
|
|
633
|
-
kind: "string",
|
|
634
|
-
description: "Brief or post title.",
|
|
635
|
-
required: false,
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
name: "prompt",
|
|
639
|
-
kind: "string",
|
|
640
|
-
description: "Instructions for this brief.",
|
|
641
|
-
required: false,
|
|
642
|
-
},
|
|
643
|
-
{
|
|
644
|
-
name: "questions",
|
|
645
|
-
kind: "array",
|
|
646
|
-
description: "Ordered questions for the creator.",
|
|
647
|
-
required: false,
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
name: "cycle",
|
|
651
|
-
kind: "string",
|
|
652
|
-
description: "Brief cycle label.",
|
|
653
|
-
required: false,
|
|
654
|
-
},
|
|
655
|
-
],
|
|
656
|
-
},
|
|
657
742
|
{
|
|
658
743
|
action: "post_enroll",
|
|
659
744
|
command: "posts enroll",
|
|
@@ -707,12 +792,21 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
707
792
|
{
|
|
708
793
|
action: "draft_create",
|
|
709
794
|
command: "posts draft",
|
|
710
|
-
description: "
|
|
795
|
+
description: "Draft a post from your topic in your voice, grounded in the program's shared pages. A bare call is a free preview; the creator repeats it with --request-id --approved --max-credits to run it.",
|
|
796
|
+
help: [
|
|
797
|
+
"",
|
|
798
|
+
"Two steps:",
|
|
799
|
+
" 1. Free preview (0 credits): run without --approved. It returns request_id and estimated_credits.",
|
|
800
|
+
" 2. Paid draft: from the creator's own workspace, repeat with --request-id <id> --approved --max-credits <ceiling>.",
|
|
801
|
+
"An organizer with delegated approval may preview but can never spend the creator's credits.",
|
|
802
|
+
"After a timeout, keep the same request_id and check `ugc posts draft-status`.",
|
|
803
|
+
"If the result has needs_answers with questions, add those details to --topic and preview again.",
|
|
804
|
+
].join("\n"),
|
|
711
805
|
fields: [
|
|
712
806
|
{
|
|
713
807
|
name: "request_id",
|
|
714
808
|
kind: "string",
|
|
715
|
-
description: "
|
|
809
|
+
description: "request_id returned by the free preview. Reuse it after a timeout; a new ID is a new paid draft.",
|
|
716
810
|
required: false,
|
|
717
811
|
},
|
|
718
812
|
{
|
|
@@ -722,15 +816,9 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
722
816
|
required: true,
|
|
723
817
|
},
|
|
724
818
|
{
|
|
725
|
-
name: "
|
|
819
|
+
name: "topic",
|
|
726
820
|
kind: "string",
|
|
727
|
-
description: "
|
|
728
|
-
required: true,
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
name: "answers",
|
|
732
|
-
kind: "array",
|
|
733
|
-
description: "Answers in brief question order.",
|
|
821
|
+
description: "What you want to post about, including any personal experience to share (up to 4000 characters).",
|
|
734
822
|
required: true,
|
|
735
823
|
},
|
|
736
824
|
{
|
|
@@ -742,7 +830,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
742
830
|
{
|
|
743
831
|
name: "max_credits",
|
|
744
832
|
kind: "number",
|
|
745
|
-
description: "
|
|
833
|
+
description: "Credit ceiling for the paid run, at least the preview's estimate.",
|
|
746
834
|
required: false,
|
|
747
835
|
},
|
|
748
836
|
],
|
|
@@ -773,7 +861,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
773
861
|
{
|
|
774
862
|
name: "title",
|
|
775
863
|
kind: "string",
|
|
776
|
-
description: "
|
|
864
|
+
description: "Post title.",
|
|
777
865
|
required: false,
|
|
778
866
|
},
|
|
779
867
|
{
|
|
@@ -788,6 +876,12 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
788
876
|
description: "Future ISO-8601 publishing time with timezone.",
|
|
789
877
|
required: false,
|
|
790
878
|
},
|
|
879
|
+
{
|
|
880
|
+
name: "approve",
|
|
881
|
+
kind: "boolean",
|
|
882
|
+
description: "Your own post: true approves exactly what this saves, so it schedules without a separate posts approve. Signed-in creator only; brand review still applies.",
|
|
883
|
+
required: false,
|
|
884
|
+
},
|
|
791
885
|
],
|
|
792
886
|
},
|
|
793
887
|
{
|
|
@@ -1001,6 +1095,43 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1001
1095
|
},
|
|
1002
1096
|
],
|
|
1003
1097
|
},
|
|
1098
|
+
{
|
|
1099
|
+
action: "comment_schedule",
|
|
1100
|
+
command: "posts comment schedule",
|
|
1101
|
+
description: "Schedule one exact comment on a creator's program post from one of this workspace's LinkedIn accounts; on a post not live yet it waits. Organizer workspace only. A bare call is a free preview; repeat with --approved to schedule it. 0 credits.",
|
|
1102
|
+
help: [
|
|
1103
|
+
"",
|
|
1104
|
+
"Two steps:",
|
|
1105
|
+
" 1. Preview (free, nothing saved): run without --approved. It shows the post, the account, the exact text and when it runs.",
|
|
1106
|
+
" 2. Schedule: repeat the same command with --approved from a signed-in session. The comment posts publicly on LinkedIn at --at,",
|
|
1107
|
+
" inside the account's active hours and daily comment limit; it can be cancelled until it runs.",
|
|
1108
|
+
"",
|
|
1109
|
+
"The post need not be live. Live means published through OXYGEN, with a LinkedIn post OXYGEN has confirmed.",
|
|
1110
|
+
"On a draft, in-review or scheduled post, or one shown as published without a confirmed LinkedIn post, the",
|
|
1111
|
+
"comment waits (waiting_for_post: true) and posts once the post is live, not before --at. If the post is still",
|
|
1112
|
+
"not live 14 days after --at, the comment fails and is never posted. A removed post cannot take a comment.",
|
|
1113
|
+
"Find post IDs with `oxygen ugc posts list --program-id <id>` and LinkedIn accounts with `oxygen senders list --json`.",
|
|
1114
|
+
"Check the result with `oxygen ugc posts list --program-id <id> --post-id <id>` (scheduled_comments).",
|
|
1115
|
+
].join("\n"),
|
|
1116
|
+
fields: [
|
|
1117
|
+
{ name: "program_id", kind: "string", description: "Program ID.", required: true },
|
|
1118
|
+
{ name: "post_id", kind: "string", description: "Program post ID (post_id from posts list); it need not be live yet.", required: true },
|
|
1119
|
+
{ name: "sender_account_id", kind: "string", description: "LinkedIn account connected in this workspace that posts the comment.", required: true },
|
|
1120
|
+
{ name: "text", kind: "string", description: "Exact comment text, 1–1250 characters.", required: true },
|
|
1121
|
+
{ name: "scheduled_for", flag: "at", kind: "string", description: "When to post: an ISO datetime with offset, or now.", required: true },
|
|
1122
|
+
{ name: "approved", kind: "boolean", description: "Schedule the exact previewed comment. Never inferred.", required: false },
|
|
1123
|
+
{ name: "max_credits", kind: "number", description: "Optional credit ceiling; the comment itself costs 0 credits.", required: false },
|
|
1124
|
+
],
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
action: "comment_cancel",
|
|
1128
|
+
command: "posts comment cancel",
|
|
1129
|
+
description: "Cancel a scheduled comment before it runs, including one still waiting for its post. Organizer workspace only; a comment that is already posting or posted cannot be cancelled.",
|
|
1130
|
+
fields: [
|
|
1131
|
+
{ name: "program_id", kind: "string", description: "Program ID.", required: true },
|
|
1132
|
+
{ name: "comment_id", kind: "string", description: "Scheduled comment ID from the post's scheduled_comments.", required: true },
|
|
1133
|
+
],
|
|
1134
|
+
},
|
|
1004
1135
|
{
|
|
1005
1136
|
action: "amplification_reconcile",
|
|
1006
1137
|
command: "amplification reconcile",
|
|
@@ -1076,7 +1207,7 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1076
1207
|
{
|
|
1077
1208
|
name: "max_actions_per_post",
|
|
1078
1209
|
kind: "number",
|
|
1079
|
-
description: "Hard limit for amplification actions on each enrolled published post.",
|
|
1210
|
+
description: "Hard limit for amplification actions on each enrolled published post, at most 12.",
|
|
1080
1211
|
required: true,
|
|
1081
1212
|
},
|
|
1082
1213
|
{
|
|
@@ -1091,6 +1222,13 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1091
1222
|
description: "Explicit authorization of the exact preview or approval. Never inferred.",
|
|
1092
1223
|
required: false,
|
|
1093
1224
|
},
|
|
1225
|
+
{
|
|
1226
|
+
name: "risk_acknowledged",
|
|
1227
|
+
flag: "acknowledge_risk",
|
|
1228
|
+
kind: "boolean",
|
|
1229
|
+
description: "Acknowledge that LinkedIn may warn, restrict or close accounts used for automated engagement. Required to enable.",
|
|
1230
|
+
required: false,
|
|
1231
|
+
},
|
|
1094
1232
|
{
|
|
1095
1233
|
name: "delay_min_seconds",
|
|
1096
1234
|
kind: "number",
|
|
@@ -1116,9 +1254,10 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1116
1254
|
{ name: "actions", kind: "array", description: "Allowed peer actions: reaction, comment or repost.", required: true },
|
|
1117
1255
|
{ name: "enabled", kind: "boolean", description: "Enable or disable this creator-owned policy.", required: true },
|
|
1118
1256
|
{ name: "expected_policy_version", kind: "number", description: "Current policy version from peer-amplification get; omit or use 0 on first save.", required: false },
|
|
1119
|
-
{ name: "max_actions_per_post", kind: "number", description: "Hard action cap per peer post.", required: true },
|
|
1257
|
+
{ name: "max_actions_per_post", kind: "number", description: "Hard action cap per peer post, at most 12.", required: true },
|
|
1120
1258
|
{ name: "max_credits_per_cycle", kind: "number", description: "Hard creator-wallet credit cap per cycle.", required: true },
|
|
1121
1259
|
{ name: "approved", kind: "boolean", description: "Confirm this exact creator-owned scope; omit for preview.", required: false },
|
|
1260
|
+
{ name: "risk_acknowledged", flag: "acknowledge_risk", kind: "boolean", description: "Acknowledge that LinkedIn may warn, restrict or close accounts used for automated engagement. Required to enable.", required: false },
|
|
1122
1261
|
{ name: "delay_min_seconds", kind: "number", description: "Minimum delay, 60–3600 seconds.", required: false },
|
|
1123
1262
|
{ name: "delay_max_seconds", kind: "number", description: "Maximum delay, 60–86400 seconds.", required: false },
|
|
1124
1263
|
],
|
|
@@ -1136,18 +1275,33 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1136
1275
|
],
|
|
1137
1276
|
},
|
|
1138
1277
|
];
|
|
1278
|
+
const subcommandDescriptions = {
|
|
1279
|
+
"posts comment": "One-off comments on a program post, live or not yet live: preview, schedule with approval, cancel.",
|
|
1280
|
+
};
|
|
1139
1281
|
for (const spec of writes) {
|
|
1140
|
-
const [family,
|
|
1141
|
-
|
|
1282
|
+
const [family, ...path] = spec.command.split(" ");
|
|
1283
|
+
let parent = group(family);
|
|
1284
|
+
for (const [index, name] of path.slice(0, -1).entries()) {
|
|
1285
|
+
const existing = parent.commands.find((child) => child.name() === name);
|
|
1286
|
+
parent =
|
|
1287
|
+
existing ??
|
|
1288
|
+
parent
|
|
1289
|
+
.command(name)
|
|
1290
|
+
.description(subcommandDescriptions[[family, ...path.slice(0, index + 1)].join(" ")] ??
|
|
1291
|
+
name);
|
|
1292
|
+
}
|
|
1293
|
+
const command = parent.command(path.at(-1)).description(spec.description);
|
|
1294
|
+
if (spec.help)
|
|
1295
|
+
command.addHelpText("after", spec.help);
|
|
1142
1296
|
for (const field of spec.fields) {
|
|
1143
|
-
const flag = `--${field.name.replaceAll("_", "-")}${field.name === "approved" ? "" : ` <${field.kind === "array" || field.kind === "object" ? "json" : field.kind === "boolean" ? "true|false" : "value"}>`}`;
|
|
1297
|
+
const flag = `--${(field.flag ?? field.name).replaceAll("_", "-")}${field.name === "approved" || field.name === "risk_acknowledged" ? "" : ` <${field.kind === "array" || field.kind === "object" ? "json" : field.kind === "boolean" ? "true|false" : field.kind === "posting_target" ? "n/month|n/week|n/total|none" : field.kind === "email_list" ? "emails" : field.kind === "text_list" ? "a, b" : "value"}>`}`;
|
|
1144
1298
|
if (field.required)
|
|
1145
1299
|
command.requiredOption(flag, field.description);
|
|
1146
1300
|
else
|
|
1147
1301
|
command.option(flag, field.description);
|
|
1148
1302
|
}
|
|
1149
1303
|
if (spec.action === "invite_create")
|
|
1150
|
-
command.option("--link-only", "Create
|
|
1304
|
+
command.option("--link-only", "Create the invitation now and return its shareable link: no preview or approval token, no email, 0 credits.");
|
|
1151
1305
|
command
|
|
1152
1306
|
.option("--json", "Print a JSON envelope.")
|
|
1153
1307
|
.action((options) => handle(`ugc ${spec.command}`, options, () => {
|
|
@@ -1156,11 +1310,13 @@ export function registerUgcCommands(program, { request: requestOxygen, handle })
|
|
|
1156
1310
|
...(spec.fixed ?? {}),
|
|
1157
1311
|
};
|
|
1158
1312
|
for (const field of spec.fields) {
|
|
1159
|
-
const key = field.name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1313
|
+
const key = (field.flag ?? field.name).replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1160
1314
|
if (options[key] !== undefined)
|
|
1161
1315
|
body[field.name] = parseField(options[key], field);
|
|
1162
1316
|
}
|
|
1163
1317
|
if (spec.action === "invite_create") {
|
|
1318
|
+
if ((body.email === undefined) === (body.emails === undefined))
|
|
1319
|
+
throw new Error("Pass exactly one of --email or --emails.");
|
|
1164
1320
|
body.send_email = options.linkOnly !== true;
|
|
1165
1321
|
if (options.linkOnly && (body.approved || body.preview_token))
|
|
1166
1322
|
throw new Error("--link-only cannot be combined with --approved or --preview-token.");
|