@blinkdotnew/cli 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +121 -12
- package/package.json +1 -1
- package/src/commands/ai.ts +93 -0
- package/src/commands/linkedin.ts +34 -12
package/dist/cli.js
CHANGED
|
@@ -268,6 +268,7 @@ Commands:
|
|
|
268
268
|
animate Image-to-video animation (URL or local file)
|
|
269
269
|
speech Text-to-speech (saves .mp3)
|
|
270
270
|
transcribe Audio-to-text (file or URL)
|
|
271
|
+
call Make an AI phone call to any US/International number
|
|
271
272
|
|
|
272
273
|
Examples:
|
|
273
274
|
$ blink ai text "Write a product description for a CLI tool"
|
|
@@ -281,6 +282,7 @@ Examples:
|
|
|
281
282
|
$ blink ai speech "Hello, welcome to Blink." --voice nova --output hello.mp3
|
|
282
283
|
$ blink ai transcribe ./meeting.mp3 --language en
|
|
283
284
|
$ blink ai transcribe https://example.com/audio.mp3
|
|
285
|
+
$ blink ai call "+14155551234" "Collect payment from John Smith"
|
|
284
286
|
|
|
285
287
|
No project needed \u2014 AI commands are workspace-scoped.
|
|
286
288
|
Add --json to any command for machine-readable output.
|
|
@@ -476,6 +478,92 @@ Supported formats: mp3, wav, m4a, ogg
|
|
|
476
478
|
if (isJsonMode()) return printJson(result);
|
|
477
479
|
console.log(result?.text ?? result?.transcript ?? JSON.stringify(result));
|
|
478
480
|
});
|
|
481
|
+
ai.command("call <phone-number> <system-prompt>").description("Make an AI phone call to any number (US/International)").option("--voice <voice>", "Voice: openai:alloy | openai:nova | cartesia:sonic-english", "openai:alloy").option("--max-duration <seconds>", "Max call duration in seconds", "300").option("--no-wait", "Return call_id immediately without waiting for completion").addHelpText("after", `
|
|
482
|
+
Examples:
|
|
483
|
+
$ blink ai call "+14155551234" "You are collecting a payment of $240 from John Smith. Be polite but firm."
|
|
484
|
+
$ blink ai call "+14155551234" "Confirm John's appointment for tomorrow at 3pm" --voice openai:nova
|
|
485
|
+
$ blink ai call "+14155551234" "Leave a message about our new product launch" --no-wait
|
|
486
|
+
$ blink ai call "+14155551234" "Your task" --json | jq '.call_id'
|
|
487
|
+
|
|
488
|
+
Phone number must be in E.164 format: +1XXXXXXXXXX (US), +44XXXXXXXXXX (UK), etc.
|
|
489
|
+
|
|
490
|
+
Voices:
|
|
491
|
+
openai:alloy Balanced, neutral (default)
|
|
492
|
+
openai:nova Friendly, warm
|
|
493
|
+
openai:echo Clear, conversational
|
|
494
|
+
openai:onyx Deep, authoritative
|
|
495
|
+
openai:shimmer Soft, gentle
|
|
496
|
+
cartesia:sonic-english Low-latency, natural
|
|
497
|
+
|
|
498
|
+
Call is charged to your workspace credits after completion (~1 credit/min).
|
|
499
|
+
`).action(async (phoneNumber, systemPrompt, opts) => {
|
|
500
|
+
requireToken();
|
|
501
|
+
const result = await withSpinner(
|
|
502
|
+
"Initiating AI call...",
|
|
503
|
+
() => resourcesRequest("/api/v1/ai/call", {
|
|
504
|
+
body: {
|
|
505
|
+
phone_number: phoneNumber,
|
|
506
|
+
system_prompt: systemPrompt,
|
|
507
|
+
voice: opts.voice,
|
|
508
|
+
max_duration_seconds: parseInt(opts.maxDuration)
|
|
509
|
+
}
|
|
510
|
+
})
|
|
511
|
+
);
|
|
512
|
+
if (isJsonMode()) return printJson(result);
|
|
513
|
+
const callId = result?.call_id;
|
|
514
|
+
if (opts.noWait) {
|
|
515
|
+
console.log(`Call initiated: ${callId}`);
|
|
516
|
+
console.log(`Poll status: blink ai call-status ${callId}`);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
console.log(`Call started \u2192 ${callId}`);
|
|
520
|
+
console.log(`Calling ${phoneNumber}...`);
|
|
521
|
+
let status = "queued";
|
|
522
|
+
let attempts = 0;
|
|
523
|
+
while (!["completed", "failed", "no-answer", "busy"].includes(status) && attempts < 120) {
|
|
524
|
+
await new Promise((r) => setTimeout(r, 5e3));
|
|
525
|
+
attempts++;
|
|
526
|
+
const poll = await resourcesRequest(`/api/v1/ai/call/${callId}`, { method: "GET" }).catch(() => null);
|
|
527
|
+
if (poll) {
|
|
528
|
+
status = poll.status;
|
|
529
|
+
if (["completed", "failed", "no-answer", "busy"].includes(status)) {
|
|
530
|
+
if (status === "completed") {
|
|
531
|
+
console.log(`
|
|
532
|
+
Call completed (${poll.duration_seconds}s)`);
|
|
533
|
+
if (poll.transcript) console.log(`
|
|
534
|
+
Transcript:
|
|
535
|
+
${poll.transcript}`);
|
|
536
|
+
if (poll.credits_charged) console.log(`
|
|
537
|
+
Credits charged: ${poll.credits_charged}`);
|
|
538
|
+
} else {
|
|
539
|
+
console.log(`
|
|
540
|
+
Call ended: ${status}`);
|
|
541
|
+
}
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
console.log(`
|
|
547
|
+
Call in progress. Check status: blink ai call-status ${callId}`);
|
|
548
|
+
});
|
|
549
|
+
ai.command("call-status <call-id>").description("Get status of an AI phone call").addHelpText("after", `
|
|
550
|
+
Examples:
|
|
551
|
+
$ blink ai call-status vc_a1b2c3d4
|
|
552
|
+
$ blink ai call-status vc_a1b2c3d4 --json
|
|
553
|
+
`).action(async (callId, _opts) => {
|
|
554
|
+
requireToken();
|
|
555
|
+
const result = await withSpinner(
|
|
556
|
+
"Fetching call status...",
|
|
557
|
+
() => resourcesRequest(`/api/v1/ai/call/${callId}`, { method: "GET" })
|
|
558
|
+
);
|
|
559
|
+
if (isJsonMode()) return printJson(result);
|
|
560
|
+
console.log(`Status: ${result?.status}`);
|
|
561
|
+
if (result?.duration_seconds) console.log(`Duration: ${result.duration_seconds}s`);
|
|
562
|
+
if (result?.transcript) console.log(`
|
|
563
|
+
Transcript:
|
|
564
|
+
${result.transcript}`);
|
|
565
|
+
if (result?.credits_charged) console.log(`Credits: ${result.credits_charged}`);
|
|
566
|
+
});
|
|
479
567
|
}
|
|
480
568
|
|
|
481
569
|
// src/commands/web.ts
|
|
@@ -1211,9 +1299,9 @@ async function liExec(method, httpMethod, params, agentId) {
|
|
|
1211
1299
|
return result.data;
|
|
1212
1300
|
}
|
|
1213
1301
|
async function getPersonId(agentId) {
|
|
1214
|
-
const data = await liExec("/
|
|
1215
|
-
const id = data?.id;
|
|
1216
|
-
if (!id) throw new Error("Could not resolve LinkedIn person ID
|
|
1302
|
+
const data = await liExec("v2/userinfo", "GET", {}, agentId);
|
|
1303
|
+
const id = data?.sub ?? data?.id;
|
|
1304
|
+
if (!id) throw new Error("Could not resolve LinkedIn person ID");
|
|
1217
1305
|
return id;
|
|
1218
1306
|
}
|
|
1219
1307
|
function registerLinkedInCommands(program2) {
|
|
@@ -1240,14 +1328,15 @@ Examples:
|
|
|
1240
1328
|
const agentId = requireAgentId(opts.agent);
|
|
1241
1329
|
const data = await withSpinner(
|
|
1242
1330
|
"Fetching LinkedIn profile...",
|
|
1243
|
-
() => liExec("/
|
|
1331
|
+
() => liExec("v2/userinfo", "GET", {}, agentId)
|
|
1244
1332
|
);
|
|
1245
1333
|
if (isJsonMode()) return printJson(data);
|
|
1246
|
-
const name = [data?.
|
|
1334
|
+
const name = data?.name ?? [data?.given_name, data?.family_name].filter(Boolean).join(" ");
|
|
1335
|
+
const personId = data?.sub ?? data?.id;
|
|
1247
1336
|
console.log(chalk7.bold("LinkedIn Profile"));
|
|
1248
|
-
console.log(` ${chalk7.dim("ID:")}
|
|
1249
|
-
if (name) console.log(` ${chalk7.dim("Name:")}
|
|
1250
|
-
if (data?.
|
|
1337
|
+
if (personId) console.log(` ${chalk7.dim("ID:")} ${personId}`);
|
|
1338
|
+
if (name) console.log(` ${chalk7.dim("Name:")} ${name}`);
|
|
1339
|
+
if (data?.email) console.log(` ${chalk7.dim("Email:")} ${data.email}`);
|
|
1251
1340
|
});
|
|
1252
1341
|
li.command("posts").description("List your most recent LinkedIn posts (last 10)").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID)").option("--limit <n>", "Number of posts to fetch (default: 10)", "10").addHelpText("after", `
|
|
1253
1342
|
Examples:
|
|
@@ -1261,11 +1350,11 @@ Examples:
|
|
|
1261
1350
|
"Resolving your LinkedIn identity...",
|
|
1262
1351
|
() => getPersonId(agentId)
|
|
1263
1352
|
);
|
|
1264
|
-
const
|
|
1353
|
+
const authorUrn = encodeURIComponent(`urn:li:person:${personId}`);
|
|
1265
1354
|
const data = await withSpinner(
|
|
1266
1355
|
"Fetching posts...",
|
|
1267
1356
|
() => liExec(
|
|
1268
|
-
|
|
1357
|
+
`ugcPosts?q=authors&authors=List(${authorUrn})&sortBy=LAST_MODIFIED&count=${opts.limit}`,
|
|
1269
1358
|
"GET",
|
|
1270
1359
|
{},
|
|
1271
1360
|
agentId
|
|
@@ -1282,7 +1371,7 @@ Examples:
|
|
|
1282
1371
|
const content = post.specificContent;
|
|
1283
1372
|
const share = content?.["com.linkedin.ugc.ShareContent"];
|
|
1284
1373
|
const commentary = share?.shareCommentary;
|
|
1285
|
-
const text = commentary?.text ??
|
|
1374
|
+
const text = commentary?.text ?? "(no text)";
|
|
1286
1375
|
const preview = text.length > 120 ? text.slice(0, 120) + "\u2026" : text;
|
|
1287
1376
|
console.log(chalk7.bold(id));
|
|
1288
1377
|
console.log(` ${chalk7.dim(preview)}`);
|
|
@@ -1298,9 +1387,29 @@ Examples:
|
|
|
1298
1387
|
`).action(async (text, opts) => {
|
|
1299
1388
|
requireToken();
|
|
1300
1389
|
const agentId = requireAgentId(opts.agent);
|
|
1390
|
+
const personId = await withSpinner(
|
|
1391
|
+
"Resolving your LinkedIn identity...",
|
|
1392
|
+
() => getPersonId(agentId)
|
|
1393
|
+
);
|
|
1394
|
+
const visibilityMap = {
|
|
1395
|
+
PUBLIC: "PUBLIC",
|
|
1396
|
+
CONNECTIONS: "CONNECTIONS_ONLY"
|
|
1397
|
+
};
|
|
1301
1398
|
const data = await withSpinner(
|
|
1302
1399
|
"Publishing post...",
|
|
1303
|
-
() => liExec("
|
|
1400
|
+
() => liExec("ugcPosts", "POST", {
|
|
1401
|
+
author: `urn:li:person:${personId}`,
|
|
1402
|
+
lifecycleState: "PUBLISHED",
|
|
1403
|
+
specificContent: {
|
|
1404
|
+
"com.linkedin.ugc.ShareContent": {
|
|
1405
|
+
shareCommentary: { text },
|
|
1406
|
+
shareMediaCategory: "NONE"
|
|
1407
|
+
}
|
|
1408
|
+
},
|
|
1409
|
+
visibility: {
|
|
1410
|
+
"com.linkedin.ugc.MemberNetworkVisibility": visibilityMap[opts.visibility] ?? "PUBLIC"
|
|
1411
|
+
}
|
|
1412
|
+
}, agentId)
|
|
1304
1413
|
);
|
|
1305
1414
|
if (isJsonMode()) return printJson(data);
|
|
1306
1415
|
console.log(chalk7.green("\u2713 Post published"));
|
package/package.json
CHANGED
package/src/commands/ai.ts
CHANGED
|
@@ -42,6 +42,7 @@ Commands:
|
|
|
42
42
|
animate Image-to-video animation (URL or local file)
|
|
43
43
|
speech Text-to-speech (saves .mp3)
|
|
44
44
|
transcribe Audio-to-text (file or URL)
|
|
45
|
+
call Make an AI phone call to any US/International number
|
|
45
46
|
|
|
46
47
|
Examples:
|
|
47
48
|
$ blink ai text "Write a product description for a CLI tool"
|
|
@@ -55,6 +56,7 @@ Examples:
|
|
|
55
56
|
$ blink ai speech "Hello, welcome to Blink." --voice nova --output hello.mp3
|
|
56
57
|
$ blink ai transcribe ./meeting.mp3 --language en
|
|
57
58
|
$ blink ai transcribe https://example.com/audio.mp3
|
|
59
|
+
$ blink ai call "+14155551234" "Collect payment from John Smith"
|
|
58
60
|
|
|
59
61
|
No project needed — AI commands are workspace-scoped.
|
|
60
62
|
Add --json to any command for machine-readable output.
|
|
@@ -282,4 +284,95 @@ Supported formats: mp3, wav, m4a, ogg
|
|
|
282
284
|
if (isJsonMode()) return printJson(result)
|
|
283
285
|
console.log(result?.text ?? result?.transcript ?? JSON.stringify(result))
|
|
284
286
|
})
|
|
287
|
+
|
|
288
|
+
ai.command('call <phone-number> <system-prompt>')
|
|
289
|
+
.description('Make an AI phone call to any number (US/International)')
|
|
290
|
+
.option('--voice <voice>', 'Voice: openai:alloy | openai:nova | cartesia:sonic-english', 'openai:alloy')
|
|
291
|
+
.option('--max-duration <seconds>', 'Max call duration in seconds', '300')
|
|
292
|
+
.option('--no-wait', 'Return call_id immediately without waiting for completion')
|
|
293
|
+
.addHelpText('after', `
|
|
294
|
+
Examples:
|
|
295
|
+
$ blink ai call "+14155551234" "You are collecting a payment of $240 from John Smith. Be polite but firm."
|
|
296
|
+
$ blink ai call "+14155551234" "Confirm John's appointment for tomorrow at 3pm" --voice openai:nova
|
|
297
|
+
$ blink ai call "+14155551234" "Leave a message about our new product launch" --no-wait
|
|
298
|
+
$ blink ai call "+14155551234" "Your task" --json | jq '.call_id'
|
|
299
|
+
|
|
300
|
+
Phone number must be in E.164 format: +1XXXXXXXXXX (US), +44XXXXXXXXXX (UK), etc.
|
|
301
|
+
|
|
302
|
+
Voices:
|
|
303
|
+
openai:alloy Balanced, neutral (default)
|
|
304
|
+
openai:nova Friendly, warm
|
|
305
|
+
openai:echo Clear, conversational
|
|
306
|
+
openai:onyx Deep, authoritative
|
|
307
|
+
openai:shimmer Soft, gentle
|
|
308
|
+
cartesia:sonic-english Low-latency, natural
|
|
309
|
+
|
|
310
|
+
Call is charged to your workspace credits after completion (~1 credit/min).
|
|
311
|
+
`)
|
|
312
|
+
.action(async (phoneNumber, systemPrompt, opts) => {
|
|
313
|
+
requireToken()
|
|
314
|
+
const result = await withSpinner('Initiating AI call...', () =>
|
|
315
|
+
resourcesRequest('/api/v1/ai/call', {
|
|
316
|
+
body: {
|
|
317
|
+
phone_number: phoneNumber,
|
|
318
|
+
system_prompt: systemPrompt,
|
|
319
|
+
voice: opts.voice,
|
|
320
|
+
max_duration_seconds: parseInt(opts.maxDuration),
|
|
321
|
+
},
|
|
322
|
+
})
|
|
323
|
+
)
|
|
324
|
+
if (isJsonMode()) return printJson(result)
|
|
325
|
+
|
|
326
|
+
const callId = result?.call_id as string
|
|
327
|
+
|
|
328
|
+
if (opts.noWait) {
|
|
329
|
+
console.log(`Call initiated: ${callId}`)
|
|
330
|
+
console.log(`Poll status: blink ai call-status ${callId}`)
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Poll until completed
|
|
335
|
+
console.log(`Call started → ${callId}`)
|
|
336
|
+
console.log(`Calling ${phoneNumber}...`)
|
|
337
|
+
let status = 'queued'
|
|
338
|
+
let attempts = 0
|
|
339
|
+
while (!['completed', 'failed', 'no-answer', 'busy'].includes(status) && attempts < 120) {
|
|
340
|
+
await new Promise(r => setTimeout(r, 5000))
|
|
341
|
+
attempts++
|
|
342
|
+
const poll = await resourcesRequest(`/api/v1/ai/call/${callId}`, { method: 'GET' }).catch(() => null)
|
|
343
|
+
if (poll) {
|
|
344
|
+
status = poll.status as string
|
|
345
|
+
if (['completed', 'failed', 'no-answer', 'busy'].includes(status)) {
|
|
346
|
+
if (status === 'completed') {
|
|
347
|
+
console.log(`\nCall completed (${poll.duration_seconds}s)`)
|
|
348
|
+
if (poll.transcript) console.log(`\nTranscript:\n${poll.transcript}`)
|
|
349
|
+
if (poll.credits_charged) console.log(`\nCredits charged: ${poll.credits_charged}`)
|
|
350
|
+
} else {
|
|
351
|
+
console.log(`\nCall ended: ${status}`)
|
|
352
|
+
}
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
console.log(`\nCall in progress. Check status: blink ai call-status ${callId}`)
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
ai.command('call-status <call-id>')
|
|
361
|
+
.description('Get status of an AI phone call')
|
|
362
|
+
.addHelpText('after', `
|
|
363
|
+
Examples:
|
|
364
|
+
$ blink ai call-status vc_a1b2c3d4
|
|
365
|
+
$ blink ai call-status vc_a1b2c3d4 --json
|
|
366
|
+
`)
|
|
367
|
+
.action(async (callId, _opts) => {
|
|
368
|
+
requireToken()
|
|
369
|
+
const result = await withSpinner('Fetching call status...', () =>
|
|
370
|
+
resourcesRequest(`/api/v1/ai/call/${callId}`, { method: 'GET' })
|
|
371
|
+
)
|
|
372
|
+
if (isJsonMode()) return printJson(result)
|
|
373
|
+
console.log(`Status: ${result?.status}`)
|
|
374
|
+
if (result?.duration_seconds) console.log(`Duration: ${result.duration_seconds}s`)
|
|
375
|
+
if (result?.transcript) console.log(`\nTranscript:\n${result.transcript}`)
|
|
376
|
+
if (result?.credits_charged) console.log(`Credits: ${result.credits_charged}`)
|
|
377
|
+
})
|
|
285
378
|
}
|
package/src/commands/linkedin.ts
CHANGED
|
@@ -22,9 +22,10 @@ async function liExec(
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async function getPersonId(agentId: string): Promise<string> {
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
25
|
+
// Use OpenID Connect userinfo — more reliable than deprecated /v2/me
|
|
26
|
+
const data = await liExec('v2/userinfo', 'GET', {}, agentId)
|
|
27
|
+
const id = data?.sub ?? data?.id
|
|
28
|
+
if (!id) throw new Error('Could not resolve LinkedIn person ID')
|
|
28
29
|
return id
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -58,15 +59,17 @@ Examples:
|
|
|
58
59
|
.action(async (opts) => {
|
|
59
60
|
requireToken()
|
|
60
61
|
const agentId = requireAgentId(opts.agent)
|
|
62
|
+
// Use OpenID Connect userinfo endpoint — more reliable than /v2/me
|
|
61
63
|
const data = await withSpinner('Fetching LinkedIn profile...', () =>
|
|
62
|
-
liExec('/
|
|
64
|
+
liExec('v2/userinfo', 'GET', {}, agentId)
|
|
63
65
|
)
|
|
64
66
|
if (isJsonMode()) return printJson(data)
|
|
65
|
-
const name = [data?.
|
|
67
|
+
const name = data?.name ?? [data?.given_name, data?.family_name].filter(Boolean).join(' ')
|
|
68
|
+
const personId = data?.sub ?? data?.id
|
|
66
69
|
console.log(chalk.bold('LinkedIn Profile'))
|
|
67
|
-
console.log(` ${chalk.dim('ID:')}
|
|
68
|
-
if (name)
|
|
69
|
-
if (data?.
|
|
70
|
+
if (personId) console.log(` ${chalk.dim('ID:')} ${personId}`)
|
|
71
|
+
if (name) console.log(` ${chalk.dim('Name:')} ${name}`)
|
|
72
|
+
if (data?.email) console.log(` ${chalk.dim('Email:')} ${data.email}`)
|
|
70
73
|
})
|
|
71
74
|
|
|
72
75
|
// blink linkedin posts
|
|
@@ -86,10 +89,10 @@ Examples:
|
|
|
86
89
|
const personId = await withSpinner('Resolving your LinkedIn identity...', () =>
|
|
87
90
|
getPersonId(agentId)
|
|
88
91
|
)
|
|
89
|
-
const
|
|
92
|
+
const authorUrn = encodeURIComponent(`urn:li:person:${personId}`)
|
|
90
93
|
const data = await withSpinner('Fetching posts...', () =>
|
|
91
94
|
liExec(
|
|
92
|
-
|
|
95
|
+
`ugcPosts?q=authors&authors=List(${authorUrn})&sortBy=LAST_MODIFIED&count=${opts.limit}`,
|
|
93
96
|
'GET',
|
|
94
97
|
{},
|
|
95
98
|
agentId
|
|
@@ -103,7 +106,7 @@ Examples:
|
|
|
103
106
|
const content = post.specificContent as Record<string, unknown> | undefined
|
|
104
107
|
const share = content?.['com.linkedin.ugc.ShareContent'] as Record<string, unknown> | undefined
|
|
105
108
|
const commentary = share?.shareCommentary as Record<string, unknown> | undefined
|
|
106
|
-
const text = (commentary?.text ??
|
|
109
|
+
const text = (commentary?.text ?? '(no text)') as string
|
|
107
110
|
const preview = text.length > 120 ? text.slice(0, 120) + '…' : text
|
|
108
111
|
console.log(chalk.bold(id))
|
|
109
112
|
console.log(` ${chalk.dim(preview)}`)
|
|
@@ -126,8 +129,27 @@ Examples:
|
|
|
126
129
|
.action(async (text: string, opts) => {
|
|
127
130
|
requireToken()
|
|
128
131
|
const agentId = requireAgentId(opts.agent)
|
|
132
|
+
const personId = await withSpinner('Resolving your LinkedIn identity...', () =>
|
|
133
|
+
getPersonId(agentId)
|
|
134
|
+
)
|
|
135
|
+
const visibilityMap: Record<string, string> = {
|
|
136
|
+
PUBLIC: 'PUBLIC',
|
|
137
|
+
CONNECTIONS: 'CONNECTIONS_ONLY',
|
|
138
|
+
}
|
|
129
139
|
const data = await withSpinner('Publishing post...', () =>
|
|
130
|
-
liExec('
|
|
140
|
+
liExec('ugcPosts', 'POST', {
|
|
141
|
+
author: `urn:li:person:${personId}`,
|
|
142
|
+
lifecycleState: 'PUBLISHED',
|
|
143
|
+
specificContent: {
|
|
144
|
+
'com.linkedin.ugc.ShareContent': {
|
|
145
|
+
shareCommentary: { text },
|
|
146
|
+
shareMediaCategory: 'NONE',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
visibility: {
|
|
150
|
+
'com.linkedin.ugc.MemberNetworkVisibility': visibilityMap[opts.visibility] ?? 'PUBLIC',
|
|
151
|
+
},
|
|
152
|
+
}, agentId)
|
|
131
153
|
)
|
|
132
154
|
if (isJsonMode()) return printJson(data)
|
|
133
155
|
console.log(chalk.green('✓ Post published'))
|