@blinkdotnew/cli 0.3.2 → 0.3.3
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 +88 -4
- package/package.json +1 -1
- package/src/commands/agent.ts +44 -0
- package/src/commands/connector.ts +47 -1
- package/src/commands/linkedin.ts +14 -2
- package/src/commands/phone.ts +2 -1
package/dist/cli.js
CHANGED
|
@@ -1127,6 +1127,7 @@ The email is sent from your project's configured sender address (set in blink.ne
|
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
1129
1129
|
// src/commands/connector.ts
|
|
1130
|
+
init_agent();
|
|
1130
1131
|
import chalk6 from "chalk";
|
|
1131
1132
|
var PROVIDERS = [
|
|
1132
1133
|
// Communication
|
|
@@ -1233,8 +1234,10 @@ ${filtered.length} providers total. Connect at blink.new/settings?tab=connectors
|
|
|
1233
1234
|
if (d.metadata?.email) console.log(chalk6.dim(` Email: ${d.metadata.email}`));
|
|
1234
1235
|
if (d.metadata?.name) console.log(chalk6.dim(` Name: ${d.metadata.name}`));
|
|
1235
1236
|
} else {
|
|
1237
|
+
const agentUrl = process.env.BLINK_WORKSPACE_SLUG && process.env.BLINK_AGENT_ID ? `https://blink.new/${process.env.BLINK_WORKSPACE_SLUG}/claw/${process.env.BLINK_AGENT_ID}` : "https://blink.new/settings?tab=connectors";
|
|
1236
1238
|
console.log(chalk6.red("\u2717 Not connected"));
|
|
1237
|
-
console.log(chalk6.dim(`
|
|
1239
|
+
console.log(chalk6.dim(` Fix: blink connector link ${provider}`));
|
|
1240
|
+
console.log(chalk6.dim(` Or visit: ${agentUrl}`));
|
|
1238
1241
|
}
|
|
1239
1242
|
} else {
|
|
1240
1243
|
const result = await withSpinner(
|
|
@@ -1257,6 +1260,40 @@ ${filtered.length} providers total. Connect at blink.new/settings?tab=connectors
|
|
|
1257
1260
|
${connected.length} provider(s) connected`));
|
|
1258
1261
|
}
|
|
1259
1262
|
});
|
|
1263
|
+
connector.command("link <provider>").description("Auto-link a workspace connector to the current agent").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID)").addHelpText("after", `
|
|
1264
|
+
Links the workspace's connected account for <provider> to this agent automatically.
|
|
1265
|
+
The workspace must already have the account connected at blink.new/settings?tab=connectors.
|
|
1266
|
+
|
|
1267
|
+
This is the self-service fix when an agent gets "not linked" errors \u2014 run this once
|
|
1268
|
+
and the connector will be available for all subsequent commands.
|
|
1269
|
+
|
|
1270
|
+
Examples:
|
|
1271
|
+
$ blink connector link linkedin Link LinkedIn to this agent
|
|
1272
|
+
$ blink connector link notion Link Notion to this agent
|
|
1273
|
+
$ blink connector link slack Link Slack to this agent
|
|
1274
|
+
$ blink connector link linkedin --json Machine-readable output
|
|
1275
|
+
`).action(async (provider, opts) => {
|
|
1276
|
+
requireToken();
|
|
1277
|
+
const agentId = requireAgentId(opts.agent);
|
|
1278
|
+
const result = await withSpinner(
|
|
1279
|
+
`Linking ${provider} to agent ${agentId}...`,
|
|
1280
|
+
() => resourcesRequest(`/v1/connectors/${provider}/link`, {
|
|
1281
|
+
method: "POST",
|
|
1282
|
+
headers: { "x-blink-agent-id": agentId },
|
|
1283
|
+
body: {}
|
|
1284
|
+
})
|
|
1285
|
+
);
|
|
1286
|
+
if (!result?.success) {
|
|
1287
|
+
const agentUrl = process.env.BLINK_WORKSPACE_SLUG && process.env.BLINK_AGENT_ID ? `https://blink.new/${process.env.BLINK_WORKSPACE_SLUG}/claw/${process.env.BLINK_AGENT_ID}` : "https://blink.new/settings?tab=connectors";
|
|
1288
|
+
console.error(chalk6.red(`\u2717 ${result?.error ?? `No ${provider} account in workspace`}`));
|
|
1289
|
+
console.error(chalk6.dim(` Connect one first: ${agentUrl}`));
|
|
1290
|
+
process.exit(1);
|
|
1291
|
+
}
|
|
1292
|
+
if (isJsonMode()) return printJson(result.data);
|
|
1293
|
+
const label = result.data?.account_label ?? provider;
|
|
1294
|
+
console.log(chalk6.green(`\u2713 ${provider} linked`) + chalk6.dim(` (${label})`));
|
|
1295
|
+
console.log(chalk6.dim(` Agent ${agentId} can now use blink connector exec ${provider}`));
|
|
1296
|
+
});
|
|
1260
1297
|
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", `
|
|
1261
1298
|
<endpoint> is the API path relative to the provider's base URL, OR a GraphQL query string for Linear.
|
|
1262
1299
|
|
|
@@ -1332,13 +1369,24 @@ Provider base URLs used:
|
|
|
1332
1369
|
// src/commands/linkedin.ts
|
|
1333
1370
|
init_agent();
|
|
1334
1371
|
import chalk7 from "chalk";
|
|
1335
|
-
|
|
1372
|
+
function getAgentPageUrl() {
|
|
1373
|
+
const slug = process.env.BLINK_WORKSPACE_SLUG;
|
|
1374
|
+
const agentId = process.env.BLINK_AGENT_ID;
|
|
1375
|
+
if (slug && agentId) return `https://blink.new/${slug}/claw/${agentId}`;
|
|
1376
|
+
return "https://blink.new/claw";
|
|
1377
|
+
}
|
|
1378
|
+
function notLinkedError() {
|
|
1379
|
+
const url = getAgentPageUrl();
|
|
1380
|
+
return `LinkedIn not linked to this agent.
|
|
1381
|
+
Fix: blink connector link linkedin
|
|
1382
|
+
Or connect manually: ${url}`;
|
|
1383
|
+
}
|
|
1336
1384
|
async function liExec(method, httpMethod, params, agentId) {
|
|
1337
1385
|
const result = await resourcesRequest("/v1/connectors/linkedin/execute", {
|
|
1338
1386
|
body: { method, http_method: httpMethod, params },
|
|
1339
1387
|
headers: { "x-blink-agent-id": agentId }
|
|
1340
1388
|
});
|
|
1341
|
-
if (!result?.success) throw new Error(result?.error ??
|
|
1389
|
+
if (!result?.success) throw new Error(result?.error ?? notLinkedError());
|
|
1342
1390
|
return result.data;
|
|
1343
1391
|
}
|
|
1344
1392
|
async function getPersonId(agentId) {
|
|
@@ -1642,7 +1690,8 @@ Examples:
|
|
|
1642
1690
|
The number is permanently returned to the carrier pool. This action cannot be undone.
|
|
1643
1691
|
`).action(async (id, opts) => {
|
|
1644
1692
|
requireToken();
|
|
1645
|
-
|
|
1693
|
+
const skipConfirm = process.argv.includes("--yes") || process.argv.includes("-y") || isJsonMode();
|
|
1694
|
+
if (!skipConfirm) {
|
|
1646
1695
|
const { confirm } = await import("@clack/prompts");
|
|
1647
1696
|
const yes = await confirm({ message: `Release ${id}? This cannot be undone.` });
|
|
1648
1697
|
if (!yes) {
|
|
@@ -2050,6 +2099,41 @@ Examples:
|
|
|
2050
2099
|
console.log(chalk11.bold("Machine ") + (a.machine_size ?? "-"));
|
|
2051
2100
|
if (a.fly_app_name) console.log(chalk11.bold("Fly App ") + a.fly_app_name);
|
|
2052
2101
|
});
|
|
2102
|
+
agent.command("url [agent_id]").description("Print the blink.new page URL for this agent (for sharing / setup links)").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)").addHelpText("after", `
|
|
2103
|
+
Returns the direct URL to this agent's page on blink.new.
|
|
2104
|
+
On Claw machines, uses BLINK_WORKSPACE_SLUG + BLINK_AGENT_ID env vars (no API call).
|
|
2105
|
+
Otherwise fetches workspace slug from the API.
|
|
2106
|
+
|
|
2107
|
+
Examples:
|
|
2108
|
+
$ blink agent url
|
|
2109
|
+
https://blink.new/kai/claw/clw_xxx
|
|
2110
|
+
|
|
2111
|
+
$ blink agent url --json
|
|
2112
|
+
{"url":"https://blink.new/kai/claw/clw_xxx","agent_id":"clw_xxx","workspace_slug":"kai"}
|
|
2113
|
+
`).action(async (agentIdArg, opts) => {
|
|
2114
|
+
requireToken();
|
|
2115
|
+
const agentId = requireAgentId(opts.agent ?? agentIdArg);
|
|
2116
|
+
const envSlug = process.env.BLINK_WORKSPACE_SLUG;
|
|
2117
|
+
if (envSlug) {
|
|
2118
|
+
const url2 = `https://blink.new/${envSlug}/claw/${agentId}`;
|
|
2119
|
+
if (isJsonMode()) return printJson({ url: url2, agent_id: agentId, workspace_slug: envSlug });
|
|
2120
|
+
console.log(url2);
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
const result = await withSpinner(
|
|
2124
|
+
"Fetching agent details...",
|
|
2125
|
+
() => appRequest(`/api/claw/agents/${agentId}`)
|
|
2126
|
+
);
|
|
2127
|
+
const a = result?.agent ?? result;
|
|
2128
|
+
const workspaceSlug = a?.workspace_slug ?? a?.workspace_id;
|
|
2129
|
+
if (!workspaceSlug) {
|
|
2130
|
+
console.error(chalk11.red("Could not determine workspace slug"));
|
|
2131
|
+
process.exit(1);
|
|
2132
|
+
}
|
|
2133
|
+
const url = `https://blink.new/${workspaceSlug}/claw/${agentId}`;
|
|
2134
|
+
if (isJsonMode()) return printJson({ url, agent_id: agentId, workspace_slug: workspaceSlug });
|
|
2135
|
+
console.log(url);
|
|
2136
|
+
});
|
|
2053
2137
|
}
|
|
2054
2138
|
|
|
2055
2139
|
// src/commands/secrets.ts
|
package/package.json
CHANGED
package/src/commands/agent.ts
CHANGED
|
@@ -86,4 +86,48 @@ Examples:
|
|
|
86
86
|
console.log(chalk.bold('Machine ') + (a.machine_size ?? '-'))
|
|
87
87
|
if (a.fly_app_name) console.log(chalk.bold('Fly App ') + a.fly_app_name)
|
|
88
88
|
})
|
|
89
|
+
|
|
90
|
+
// blink agent url
|
|
91
|
+
agent.command('url [agent_id]')
|
|
92
|
+
.description('Print the blink.new page URL for this agent (for sharing / setup links)')
|
|
93
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)')
|
|
94
|
+
.addHelpText('after', `
|
|
95
|
+
Returns the direct URL to this agent's page on blink.new.
|
|
96
|
+
On Claw machines, uses BLINK_WORKSPACE_SLUG + BLINK_AGENT_ID env vars (no API call).
|
|
97
|
+
Otherwise fetches workspace slug from the API.
|
|
98
|
+
|
|
99
|
+
Examples:
|
|
100
|
+
$ blink agent url
|
|
101
|
+
https://blink.new/kai/claw/clw_xxx
|
|
102
|
+
|
|
103
|
+
$ blink agent url --json
|
|
104
|
+
{"url":"https://blink.new/kai/claw/clw_xxx","agent_id":"clw_xxx","workspace_slug":"kai"}
|
|
105
|
+
`)
|
|
106
|
+
.action(async (agentIdArg: string | undefined, opts) => {
|
|
107
|
+
requireToken()
|
|
108
|
+
const agentId = requireAgentId(opts.agent ?? agentIdArg)
|
|
109
|
+
|
|
110
|
+
// Fast path: env vars already set on Claw machines (no API call needed)
|
|
111
|
+
const envSlug = process.env.BLINK_WORKSPACE_SLUG
|
|
112
|
+
if (envSlug) {
|
|
113
|
+
const url = `https://blink.new/${envSlug}/claw/${agentId}`
|
|
114
|
+
if (isJsonMode()) return printJson({ url, agent_id: agentId, workspace_slug: envSlug })
|
|
115
|
+
console.log(url)
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Fallback: fetch workspace slug from API
|
|
120
|
+
const result = await withSpinner('Fetching agent details...', () =>
|
|
121
|
+
appRequest(`/api/claw/agents/${agentId}`)
|
|
122
|
+
)
|
|
123
|
+
const a = result?.agent ?? result
|
|
124
|
+
const workspaceSlug = a?.workspace_slug ?? a?.workspace_id
|
|
125
|
+
if (!workspaceSlug) {
|
|
126
|
+
console.error(chalk.red('Could not determine workspace slug'))
|
|
127
|
+
process.exit(1)
|
|
128
|
+
}
|
|
129
|
+
const url = `https://blink.new/${workspaceSlug}/claw/${agentId}`
|
|
130
|
+
if (isJsonMode()) return printJson({ url, agent_id: agentId, workspace_slug: workspaceSlug })
|
|
131
|
+
console.log(url)
|
|
132
|
+
})
|
|
89
133
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import { resourcesRequest } from '../lib/api-resources.js'
|
|
3
3
|
import { requireToken } from '../lib/auth.js'
|
|
4
|
+
import { requireAgentId } from '../lib/agent.js'
|
|
4
5
|
import { printJson, isJsonMode, withSpinner, createTable } from '../lib/output.js'
|
|
5
6
|
import chalk from 'chalk'
|
|
6
7
|
|
|
@@ -124,8 +125,12 @@ Use --account <id> if you have multiple linked accounts for the same provider.
|
|
|
124
125
|
if (d.metadata?.email) console.log(chalk.dim(` Email: ${d.metadata.email}`))
|
|
125
126
|
if (d.metadata?.name) console.log(chalk.dim(` Name: ${d.metadata.name}`))
|
|
126
127
|
} else {
|
|
128
|
+
const agentUrl = process.env.BLINK_WORKSPACE_SLUG && process.env.BLINK_AGENT_ID
|
|
129
|
+
? `https://blink.new/${process.env.BLINK_WORKSPACE_SLUG}/claw/${process.env.BLINK_AGENT_ID}`
|
|
130
|
+
: 'https://blink.new/settings?tab=connectors'
|
|
127
131
|
console.log(chalk.red('✗ Not connected'))
|
|
128
|
-
console.log(chalk.dim(`
|
|
132
|
+
console.log(chalk.dim(` Fix: blink connector link ${provider}`))
|
|
133
|
+
console.log(chalk.dim(` Or visit: ${agentUrl}`))
|
|
129
134
|
}
|
|
130
135
|
} else {
|
|
131
136
|
// List all connected providers
|
|
@@ -149,6 +154,47 @@ Use --account <id> if you have multiple linked accounts for the same provider.
|
|
|
149
154
|
}
|
|
150
155
|
})
|
|
151
156
|
|
|
157
|
+
// blink connector link <provider>
|
|
158
|
+
connector.command('link <provider>')
|
|
159
|
+
.description('Auto-link a workspace connector to the current agent')
|
|
160
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID)')
|
|
161
|
+
.addHelpText('after', `
|
|
162
|
+
Links the workspace's connected account for <provider> to this agent automatically.
|
|
163
|
+
The workspace must already have the account connected at blink.new/settings?tab=connectors.
|
|
164
|
+
|
|
165
|
+
This is the self-service fix when an agent gets "not linked" errors — run this once
|
|
166
|
+
and the connector will be available for all subsequent commands.
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
$ blink connector link linkedin Link LinkedIn to this agent
|
|
170
|
+
$ blink connector link notion Link Notion to this agent
|
|
171
|
+
$ blink connector link slack Link Slack to this agent
|
|
172
|
+
$ blink connector link linkedin --json Machine-readable output
|
|
173
|
+
`)
|
|
174
|
+
.action(async (provider: string, opts) => {
|
|
175
|
+
requireToken()
|
|
176
|
+
const agentId = requireAgentId(opts.agent)
|
|
177
|
+
const result = await withSpinner(`Linking ${provider} to agent ${agentId}...`, () =>
|
|
178
|
+
resourcesRequest(`/v1/connectors/${provider}/link`, {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: { 'x-blink-agent-id': agentId },
|
|
181
|
+
body: {},
|
|
182
|
+
})
|
|
183
|
+
)
|
|
184
|
+
if (!result?.success) {
|
|
185
|
+
const agentUrl = process.env.BLINK_WORKSPACE_SLUG && process.env.BLINK_AGENT_ID
|
|
186
|
+
? `https://blink.new/${process.env.BLINK_WORKSPACE_SLUG}/claw/${process.env.BLINK_AGENT_ID}`
|
|
187
|
+
: 'https://blink.new/settings?tab=connectors'
|
|
188
|
+
console.error(chalk.red(`✗ ${result?.error ?? `No ${provider} account in workspace`}`))
|
|
189
|
+
console.error(chalk.dim(` Connect one first: ${agentUrl}`))
|
|
190
|
+
process.exit(1)
|
|
191
|
+
}
|
|
192
|
+
if (isJsonMode()) return printJson(result.data)
|
|
193
|
+
const label = result.data?.account_label ?? provider
|
|
194
|
+
console.log(chalk.green(`✓ ${provider} linked`) + chalk.dim(` (${label})`))
|
|
195
|
+
console.log(chalk.dim(` Agent ${agentId} can now use blink connector exec ${provider}`))
|
|
196
|
+
})
|
|
197
|
+
|
|
152
198
|
// blink connector exec <provider> <endpoint> [method-or-params] [params]
|
|
153
199
|
// Supports both patterns:
|
|
154
200
|
// blink connector exec github /user/repos GET
|
package/src/commands/linkedin.ts
CHANGED
|
@@ -5,7 +5,19 @@ import { printJson, isJsonMode, withSpinner } from '../lib/output.js'
|
|
|
5
5
|
import { resourcesRequest } from '../lib/api-resources.js'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// Build agent page URL from env vars (set at machine creation via BLINK_WORKSPACE_SLUG).
|
|
9
|
+
// Falls back to generic URL if env vars aren't set (e.g. local dev).
|
|
10
|
+
function getAgentPageUrl(): string {
|
|
11
|
+
const slug = process.env.BLINK_WORKSPACE_SLUG
|
|
12
|
+
const agentId = process.env.BLINK_AGENT_ID
|
|
13
|
+
if (slug && agentId) return `https://blink.new/${slug}/claw/${agentId}`
|
|
14
|
+
return 'https://blink.new/claw'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function notLinkedError(): string {
|
|
18
|
+
const url = getAgentPageUrl()
|
|
19
|
+
return `LinkedIn not linked to this agent.\n Fix: blink connector link linkedin\n Or connect manually: ${url}`
|
|
20
|
+
}
|
|
9
21
|
|
|
10
22
|
async function liExec(
|
|
11
23
|
method: string,
|
|
@@ -17,7 +29,7 @@ async function liExec(
|
|
|
17
29
|
body: { method, http_method: httpMethod, params },
|
|
18
30
|
headers: { 'x-blink-agent-id': agentId },
|
|
19
31
|
})
|
|
20
|
-
if (!result?.success) throw new Error(result?.error ??
|
|
32
|
+
if (!result?.success) throw new Error(result?.error ?? notLinkedError())
|
|
21
33
|
return result.data
|
|
22
34
|
}
|
|
23
35
|
|
package/src/commands/phone.ts
CHANGED
|
@@ -163,7 +163,8 @@ The number is permanently returned to the carrier pool. This action cannot be un
|
|
|
163
163
|
`)
|
|
164
164
|
.action(async (id: string, opts) => {
|
|
165
165
|
requireToken()
|
|
166
|
-
|
|
166
|
+
const skipConfirm = process.argv.includes('--yes') || process.argv.includes('-y') || isJsonMode()
|
|
167
|
+
if (!skipConfirm) {
|
|
167
168
|
const { confirm } = await import('@clack/prompts')
|
|
168
169
|
const yes = await confirm({ message: `Release ${id}? This cannot be undone.` })
|
|
169
170
|
if (!yes) { console.log('Cancelled.'); return }
|