@blinkdotnew/cli 0.2.7 → 0.3.0
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 +51 -12
- package/package.json +1 -1
- package/src/commands/ai.ts +4 -1
- package/src/commands/connector.ts +22 -7
- package/src/commands/linkedin.ts +30 -0
package/dist/cli.js
CHANGED
|
@@ -478,7 +478,7 @@ Supported formats: mp3, wav, m4a, ogg
|
|
|
478
478
|
if (isJsonMode()) return printJson(result);
|
|
479
479
|
console.log(result?.text ?? result?.transcript ?? JSON.stringify(result));
|
|
480
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", `
|
|
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").option("--from <number>", "Phone number to call from (E.164 format, e.g. +14155551234). Uses primary number if omitted.").addHelpText("after", `
|
|
482
482
|
Examples:
|
|
483
483
|
$ blink ai call "+14155551234" "You are collecting a payment of $240 from John Smith. Be polite but firm."
|
|
484
484
|
$ blink ai call "+14155551234" "Confirm John's appointment for tomorrow at 3pm" --voice openai:nova
|
|
@@ -496,6 +496,7 @@ Voices:
|
|
|
496
496
|
cartesia:sonic-english Low-latency, natural
|
|
497
497
|
|
|
498
498
|
Call is charged to your workspace credits after completion (~1 credit/min).
|
|
499
|
+
Use --from to specify which of your workspace numbers to call from.
|
|
499
500
|
`).action(async (phoneNumber, systemPrompt, opts) => {
|
|
500
501
|
requireToken();
|
|
501
502
|
const result = await withSpinner(
|
|
@@ -505,13 +506,14 @@ Call is charged to your workspace credits after completion (~1 credit/min).
|
|
|
505
506
|
phone_number: phoneNumber,
|
|
506
507
|
system_prompt: systemPrompt,
|
|
507
508
|
voice: opts.voice,
|
|
508
|
-
max_duration_seconds: parseInt(opts.maxDuration)
|
|
509
|
+
max_duration_seconds: parseInt(opts.maxDuration),
|
|
510
|
+
...opts.from ? { from_number: opts.from } : {}
|
|
509
511
|
}
|
|
510
512
|
})
|
|
511
513
|
);
|
|
512
514
|
if (isJsonMode()) return printJson(result);
|
|
513
515
|
const callId = result?.call_id;
|
|
514
|
-
if (opts.
|
|
516
|
+
if (!opts.wait) {
|
|
515
517
|
console.log(`Call initiated: ${callId}`);
|
|
516
518
|
console.log(`Poll status: blink ai call-status ${callId}`);
|
|
517
519
|
return;
|
|
@@ -1227,7 +1229,7 @@ ${filtered.length} providers total. Connect at blink.new/settings?tab=connectors
|
|
|
1227
1229
|
${connected.length} provider(s) connected`));
|
|
1228
1230
|
}
|
|
1229
1231
|
});
|
|
1230
|
-
connector.command("exec <provider> <endpoint> [params]").description("Execute a call on a connected OAuth provider").option("--account <id>", "Specific account ID (if you have multiple accounts)").option("--method <method>", "HTTP method: GET | POST | PUT | PATCH | DELETE (default: POST)", "POST").addHelpText("after", `
|
|
1232
|
+
connector.command("exec <provider> <endpoint> [method-or-params] [params]").description("Execute a call on a connected OAuth provider").option("--account <id>", "Specific account ID (if you have multiple accounts)").option("--method <method>", "HTTP method: GET | POST | PUT | PATCH | DELETE (default: POST)", "POST").addHelpText("after", `
|
|
1231
1233
|
<endpoint> is the API path relative to the provider's base URL, OR a GraphQL query string for Linear.
|
|
1232
1234
|
|
|
1233
1235
|
Examples (REST):
|
|
@@ -1260,22 +1262,35 @@ Provider base URLs used:
|
|
|
1260
1262
|
jira https://api.atlassian.com/ex/jira/{cloudId}/rest/api/3/
|
|
1261
1263
|
shopify https://{shop}.myshopify.com/admin/api/2024-10/
|
|
1262
1264
|
... run \`blink connector providers\` for all 38 providers
|
|
1263
|
-
`).action(async (provider, endpoint,
|
|
1265
|
+
`).action(async (provider, endpoint, arg1, arg2, opts) => {
|
|
1264
1266
|
requireToken();
|
|
1267
|
+
const HTTP_METHODS = /^(GET|POST|PUT|PATCH|DELETE|HEAD)$/i;
|
|
1268
|
+
let httpMethod = opts.method;
|
|
1265
1269
|
let params = {};
|
|
1266
|
-
if (
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1270
|
+
if (arg1) {
|
|
1271
|
+
if (HTTP_METHODS.test(arg1)) {
|
|
1272
|
+
httpMethod = arg1.toUpperCase();
|
|
1273
|
+
if (arg2) {
|
|
1274
|
+
try {
|
|
1275
|
+
params = JSON.parse(arg2);
|
|
1276
|
+
} catch {
|
|
1277
|
+
params = {};
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
} else {
|
|
1281
|
+
try {
|
|
1282
|
+
params = JSON.parse(arg1);
|
|
1283
|
+
} catch {
|
|
1284
|
+
params = {};
|
|
1285
|
+
}
|
|
1271
1286
|
}
|
|
1272
1287
|
}
|
|
1273
1288
|
const result = await withSpinner(
|
|
1274
|
-
`${
|
|
1289
|
+
`${httpMethod} ${provider}${endpoint}...`,
|
|
1275
1290
|
() => resourcesRequest(`/v1/connectors/${provider}/execute`, {
|
|
1276
1291
|
body: {
|
|
1277
1292
|
method: endpoint,
|
|
1278
|
-
http_method:
|
|
1293
|
+
http_method: httpMethod,
|
|
1279
1294
|
params,
|
|
1280
1295
|
...opts.account ? { account_id: opts.account } : {}
|
|
1281
1296
|
}
|
|
@@ -1380,6 +1395,30 @@ Examples:
|
|
|
1380
1395
|
console.log(chalk7.green("\u2713 Post published"));
|
|
1381
1396
|
if (data?.id) console.log(chalk7.dim(` URN: ${data.id}`));
|
|
1382
1397
|
});
|
|
1398
|
+
li.command("upload-media <media-url>").description("Upload an image or video to LinkedIn storage, returns asset URN for use in posts").option("--type <type>", "Media type: image | video (default: image)", "image").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID)").addHelpText("after", `
|
|
1399
|
+
Returns an asset URN to use when composing a post with media via blink connector exec.
|
|
1400
|
+
|
|
1401
|
+
Examples:
|
|
1402
|
+
$ blink linkedin upload-media https://example.com/photo.jpg
|
|
1403
|
+
$ blink linkedin upload-media https://example.com/demo.mp4 --type video
|
|
1404
|
+
$ ASSET_URN=$(blink linkedin upload-media https://example.com/photo.jpg --json | python3 -c "import json,sys; print(json.load(sys.stdin)['asset_urn'])")
|
|
1405
|
+
`).action(async (mediaUrl, opts) => {
|
|
1406
|
+
requireToken();
|
|
1407
|
+
const agentId = requireAgentId(opts.agent);
|
|
1408
|
+
const result = await withSpinner(
|
|
1409
|
+
`Uploading ${opts.type}...`,
|
|
1410
|
+
() => resourcesRequest("/v1/connectors/linkedin/upload-media", {
|
|
1411
|
+
body: { media_url: mediaUrl, media_type: opts.type },
|
|
1412
|
+
headers: { "x-blink-agent-id": agentId }
|
|
1413
|
+
})
|
|
1414
|
+
);
|
|
1415
|
+
if (isJsonMode()) return printJson(result?.data ?? result);
|
|
1416
|
+
const assetUrn = result?.data?.asset_urn;
|
|
1417
|
+
if (assetUrn) {
|
|
1418
|
+
console.log(chalk7.green("\u2713 Upload complete"));
|
|
1419
|
+
console.log(chalk7.dim(` Asset URN: ${assetUrn}`));
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1383
1422
|
li.command("delete <postUrn>").description("Delete one of your LinkedIn posts").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID)").addHelpText("after", `
|
|
1384
1423
|
<postUrn> is the LinkedIn post URN returned when the post was created.
|
|
1385
1424
|
e.g. urn:li:ugcPost:1234567890
|
package/package.json
CHANGED
package/src/commands/ai.ts
CHANGED
|
@@ -290,6 +290,7 @@ Supported formats: mp3, wav, m4a, ogg
|
|
|
290
290
|
.option('--voice <voice>', 'Voice: openai:alloy | openai:nova | cartesia:sonic-english', 'openai:alloy')
|
|
291
291
|
.option('--max-duration <seconds>', 'Max call duration in seconds', '300')
|
|
292
292
|
.option('--no-wait', 'Return call_id immediately without waiting for completion')
|
|
293
|
+
.option('--from <number>', 'Phone number to call from (E.164 format, e.g. +14155551234). Uses primary number if omitted.')
|
|
293
294
|
.addHelpText('after', `
|
|
294
295
|
Examples:
|
|
295
296
|
$ blink ai call "+14155551234" "You are collecting a payment of $240 from John Smith. Be polite but firm."
|
|
@@ -308,6 +309,7 @@ Voices:
|
|
|
308
309
|
cartesia:sonic-english Low-latency, natural
|
|
309
310
|
|
|
310
311
|
Call is charged to your workspace credits after completion (~1 credit/min).
|
|
312
|
+
Use --from to specify which of your workspace numbers to call from.
|
|
311
313
|
`)
|
|
312
314
|
.action(async (phoneNumber, systemPrompt, opts) => {
|
|
313
315
|
requireToken()
|
|
@@ -318,6 +320,7 @@ Call is charged to your workspace credits after completion (~1 credit/min).
|
|
|
318
320
|
system_prompt: systemPrompt,
|
|
319
321
|
voice: opts.voice,
|
|
320
322
|
max_duration_seconds: parseInt(opts.maxDuration),
|
|
323
|
+
...(opts.from ? { from_number: opts.from } : {}),
|
|
321
324
|
},
|
|
322
325
|
})
|
|
323
326
|
)
|
|
@@ -325,7 +328,7 @@ Call is charged to your workspace credits after completion (~1 credit/min).
|
|
|
325
328
|
|
|
326
329
|
const callId = result?.call_id as string
|
|
327
330
|
|
|
328
|
-
if (opts.
|
|
331
|
+
if (!opts.wait) { // Commander --no-wait sets opts.wait=false (not opts.noWait)
|
|
329
332
|
console.log(`Call initiated: ${callId}`)
|
|
330
333
|
console.log(`Poll status: blink ai call-status ${callId}`)
|
|
331
334
|
return
|
|
@@ -149,8 +149,12 @@ Use --account <id> if you have multiple linked accounts for the same provider.
|
|
|
149
149
|
}
|
|
150
150
|
})
|
|
151
151
|
|
|
152
|
-
// blink connector exec <provider> <endpoint> [params]
|
|
153
|
-
|
|
152
|
+
// blink connector exec <provider> <endpoint> [method-or-params] [params]
|
|
153
|
+
// Supports both patterns:
|
|
154
|
+
// blink connector exec github /user/repos GET
|
|
155
|
+
// blink connector exec notion /search POST '{"query":"notes"}'
|
|
156
|
+
// blink connector exec notion /search '{"query":"notes"}'
|
|
157
|
+
connector.command('exec <provider> <endpoint> [method-or-params] [params]')
|
|
154
158
|
.description('Execute a call on a connected OAuth provider')
|
|
155
159
|
.option('--account <id>', 'Specific account ID (if you have multiple accounts)')
|
|
156
160
|
.option('--method <method>', 'HTTP method: GET | POST | PUT | PATCH | DELETE (default: POST)', 'POST')
|
|
@@ -188,17 +192,28 @@ Provider base URLs used:
|
|
|
188
192
|
shopify https://{shop}.myshopify.com/admin/api/2024-10/
|
|
189
193
|
... run \`blink connector providers\` for all 38 providers
|
|
190
194
|
`)
|
|
191
|
-
.action(async (provider: string, endpoint: string,
|
|
195
|
+
.action(async (provider: string, endpoint: string, arg1: string | undefined, arg2: string | undefined, opts) => {
|
|
192
196
|
requireToken()
|
|
197
|
+
const HTTP_METHODS = /^(GET|POST|PUT|PATCH|DELETE|HEAD)$/i
|
|
198
|
+
let httpMethod = opts.method
|
|
193
199
|
let params: Record<string, unknown> = {}
|
|
194
|
-
|
|
195
|
-
|
|
200
|
+
|
|
201
|
+
if (arg1) {
|
|
202
|
+
if (HTTP_METHODS.test(arg1)) {
|
|
203
|
+
// Pattern: exec provider endpoint GET ['{"key":"val"}']
|
|
204
|
+
httpMethod = arg1.toUpperCase()
|
|
205
|
+
if (arg2) { try { params = JSON.parse(arg2) } catch { params = {} } }
|
|
206
|
+
} else {
|
|
207
|
+
// Pattern: exec provider endpoint '{"key":"val"}'
|
|
208
|
+
try { params = JSON.parse(arg1) } catch { params = {} }
|
|
209
|
+
}
|
|
196
210
|
}
|
|
197
|
-
|
|
211
|
+
|
|
212
|
+
const result = await withSpinner(`${httpMethod} ${provider}${endpoint}...`, () =>
|
|
198
213
|
resourcesRequest(`/v1/connectors/${provider}/execute`, {
|
|
199
214
|
body: {
|
|
200
215
|
method: endpoint,
|
|
201
|
-
http_method:
|
|
216
|
+
http_method: httpMethod,
|
|
202
217
|
params,
|
|
203
218
|
...(opts.account ? { account_id: opts.account } : {}),
|
|
204
219
|
}
|
package/src/commands/linkedin.ts
CHANGED
|
@@ -117,6 +117,36 @@ Examples:
|
|
|
117
117
|
if (data?.id) console.log(chalk.dim(` URN: ${data.id}`))
|
|
118
118
|
})
|
|
119
119
|
|
|
120
|
+
// blink linkedin upload-media <media-url>
|
|
121
|
+
li.command('upload-media <media-url>')
|
|
122
|
+
.description('Upload an image or video to LinkedIn storage, returns asset URN for use in posts')
|
|
123
|
+
.option('--type <type>', 'Media type: image | video (default: image)', 'image')
|
|
124
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID)')
|
|
125
|
+
.addHelpText('after', `
|
|
126
|
+
Returns an asset URN to use when composing a post with media via blink connector exec.
|
|
127
|
+
|
|
128
|
+
Examples:
|
|
129
|
+
$ blink linkedin upload-media https://example.com/photo.jpg
|
|
130
|
+
$ blink linkedin upload-media https://example.com/demo.mp4 --type video
|
|
131
|
+
$ ASSET_URN=$(blink linkedin upload-media https://example.com/photo.jpg --json | python3 -c "import json,sys; print(json.load(sys.stdin)['asset_urn'])")
|
|
132
|
+
`)
|
|
133
|
+
.action(async (mediaUrl: string, opts) => {
|
|
134
|
+
requireToken()
|
|
135
|
+
const agentId = requireAgentId(opts.agent)
|
|
136
|
+
const result = await withSpinner(`Uploading ${opts.type}...`, () =>
|
|
137
|
+
resourcesRequest('/v1/connectors/linkedin/upload-media', {
|
|
138
|
+
body: { media_url: mediaUrl, media_type: opts.type },
|
|
139
|
+
headers: { 'x-blink-agent-id': agentId },
|
|
140
|
+
})
|
|
141
|
+
)
|
|
142
|
+
if (isJsonMode()) return printJson(result?.data ?? result)
|
|
143
|
+
const assetUrn = result?.data?.asset_urn
|
|
144
|
+
if (assetUrn) {
|
|
145
|
+
console.log(chalk.green('✓ Upload complete'))
|
|
146
|
+
console.log(chalk.dim(` Asset URN: ${assetUrn}`))
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
120
150
|
// blink linkedin delete <postUrn>
|
|
121
151
|
li.command('delete <postUrn>')
|
|
122
152
|
.description('Delete one of your LinkedIn posts')
|