@blinkdotnew/cli 0.1.6 → 0.1.8
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 +252 -11
- package/package.json +1 -1
- package/src/cli.ts +18 -0
- package/src/commands/agent.ts +89 -0
- package/src/commands/project.ts +32 -6
- package/src/commands/secrets.ts +110 -0
- package/src/lib/agent.ts +29 -0
- package/src/lib/api-resources.ts +9 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
6
|
var __esm = (fn, res) => function __init() {
|
|
5
7
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
8
|
};
|
|
@@ -8,6 +10,15 @@ var __export = (target, all) => {
|
|
|
8
10
|
for (var name in all)
|
|
9
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
12
|
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
11
22
|
|
|
12
23
|
// src/lib/project.ts
|
|
13
24
|
var project_exports = {};
|
|
@@ -53,6 +64,34 @@ var init_project = __esm({
|
|
|
53
64
|
}
|
|
54
65
|
});
|
|
55
66
|
|
|
67
|
+
// src/lib/agent.ts
|
|
68
|
+
var agent_exports = {};
|
|
69
|
+
__export(agent_exports, {
|
|
70
|
+
requireAgentId: () => requireAgentId,
|
|
71
|
+
resolveAgentId: () => resolveAgentId
|
|
72
|
+
});
|
|
73
|
+
function resolveAgentId(explicitId) {
|
|
74
|
+
if (explicitId) return explicitId;
|
|
75
|
+
if (process.env.BLINK_AGENT_ID) return process.env.BLINK_AGENT_ID;
|
|
76
|
+
if (process.env.BLINK_ACTIVE_AGENT) return process.env.BLINK_ACTIVE_AGENT;
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
function requireAgentId(explicitId) {
|
|
80
|
+
const id = resolveAgentId(explicitId);
|
|
81
|
+
if (!id) {
|
|
82
|
+
process.stderr.write(
|
|
83
|
+
"\nError: No agent set.\n On Claw machines this is automatic (BLINK_AGENT_ID is injected).\n Otherwise:\n blink agent list # find your agent ID\n eval $(blink agent use clw_xxx --export) # set it for this session\n blink secrets set --agent clw_xxx KEY val # or pass --agent directly\n"
|
|
84
|
+
);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
return id;
|
|
88
|
+
}
|
|
89
|
+
var init_agent = __esm({
|
|
90
|
+
"src/lib/agent.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
56
95
|
// src/cli.ts
|
|
57
96
|
import { Command } from "commander";
|
|
58
97
|
import { createRequire } from "module";
|
|
@@ -135,8 +174,12 @@ function requireToken() {
|
|
|
135
174
|
|
|
136
175
|
// src/lib/api-resources.ts
|
|
137
176
|
var BASE_URL = process.env.BLINK_APIS_URL ?? "https://core.blink.new";
|
|
177
|
+
function resolveResourceToken() {
|
|
178
|
+
if (process.env.BLINK_PROJECT_KEY) return process.env.BLINK_PROJECT_KEY;
|
|
179
|
+
return resolveToken();
|
|
180
|
+
}
|
|
138
181
|
async function resourcesRequest(path, opts = {}) {
|
|
139
|
-
const token =
|
|
182
|
+
const token = resolveResourceToken();
|
|
140
183
|
const headers = {
|
|
141
184
|
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
142
185
|
...process.env.BLINK_AGENT_ID ? { "x-blink-agent-id": process.env.BLINK_AGENT_ID } : {},
|
|
@@ -1204,16 +1247,30 @@ After linking, most commands work without specifying a project_id:
|
|
|
1204
1247
|
clearProjectConfig();
|
|
1205
1248
|
console.log("Unlinked.");
|
|
1206
1249
|
});
|
|
1207
|
-
program2.command("status").description("Show
|
|
1250
|
+
program2.command("status").description("Show current agent, project, and auth context").action(() => {
|
|
1208
1251
|
const config = readProjectConfig();
|
|
1209
|
-
const
|
|
1252
|
+
const { resolveAgentId: resolveAgentId3 } = (init_agent(), __toCommonJS(agent_exports));
|
|
1253
|
+
const agentId = resolveAgentId3();
|
|
1254
|
+
const agentSource = process.env.BLINK_AGENT_ID ? "BLINK_AGENT_ID env" : process.env.BLINK_ACTIVE_AGENT ? "BLINK_ACTIVE_AGENT env" : null;
|
|
1255
|
+
if (agentId) {
|
|
1256
|
+
console.log(chalk7.bold("Agent ") + agentId + chalk7.dim(" (" + agentSource + ")"));
|
|
1257
|
+
} else {
|
|
1258
|
+
console.log(chalk7.dim("Agent not set (use: eval $(blink agent use clw_xxx --export))"));
|
|
1259
|
+
}
|
|
1210
1260
|
if (config) {
|
|
1211
|
-
|
|
1212
|
-
|
|
1261
|
+
const projectSource = process.env.BLINK_ACTIVE_PROJECT ? "BLINK_ACTIVE_PROJECT env" : ".blink/project.json";
|
|
1262
|
+
console.log(chalk7.bold("Project ") + config.projectId + chalk7.dim(" (" + projectSource + ")"));
|
|
1263
|
+
} else if (process.env.BLINK_ACTIVE_PROJECT) {
|
|
1264
|
+
console.log(chalk7.bold("Project ") + process.env.BLINK_ACTIVE_PROJECT + chalk7.dim(" (BLINK_ACTIVE_PROJECT env)"));
|
|
1213
1265
|
} else {
|
|
1214
|
-
console.log(chalk7.dim("
|
|
1266
|
+
console.log(chalk7.dim("Project not linked (use: blink link or eval $(blink use proj_xxx --export))"));
|
|
1267
|
+
}
|
|
1268
|
+
const authSource = process.env.BLINK_API_KEY ? "BLINK_API_KEY env" : "~/.config/blink/config.toml";
|
|
1269
|
+
const hasProjectKey = !!process.env.BLINK_PROJECT_KEY;
|
|
1270
|
+
console.log(chalk7.bold("Auth ") + authSource);
|
|
1271
|
+
if (hasProjectKey) {
|
|
1272
|
+
console.log(chalk7.bold("ProjKey ") + "BLINK_PROJECT_KEY env" + chalk7.dim(" (used for db/storage/rag)"));
|
|
1215
1273
|
}
|
|
1216
|
-
console.log(chalk7.bold("Auth ") + token);
|
|
1217
1274
|
});
|
|
1218
1275
|
}
|
|
1219
1276
|
|
|
@@ -1267,6 +1324,174 @@ For CI/GitHub Actions: set BLINK_API_KEY as a secret, skip login entirely.
|
|
|
1267
1324
|
});
|
|
1268
1325
|
}
|
|
1269
1326
|
|
|
1327
|
+
// src/commands/agent.ts
|
|
1328
|
+
init_agent();
|
|
1329
|
+
import chalk9 from "chalk";
|
|
1330
|
+
function registerAgentCommands(program2) {
|
|
1331
|
+
const agent = program2.command("agent").description("Manage Blink Claw agents in your workspace").addHelpText("after", `
|
|
1332
|
+
Examples:
|
|
1333
|
+
$ blink agent list List all agents in workspace
|
|
1334
|
+
$ blink agent use clw_xxx Show how to set active agent
|
|
1335
|
+
$ eval $(blink agent use clw_xxx --export) Set active agent for this session
|
|
1336
|
+
$ blink agent status Show current agent details
|
|
1337
|
+
|
|
1338
|
+
Agent ID resolution for all agent/secrets commands (priority: high \u2192 low):
|
|
1339
|
+
1. --agent <id> flag
|
|
1340
|
+
2. BLINK_AGENT_ID env var \u2190 always set on Claw Fly machines (zero config)
|
|
1341
|
+
3. BLINK_ACTIVE_AGENT env \u2190 set via eval $(blink agent use clw_xxx --export)
|
|
1342
|
+
`);
|
|
1343
|
+
agent.command("list").description("List all Claw agents in the workspace").action(async () => {
|
|
1344
|
+
requireToken();
|
|
1345
|
+
const result = await withSpinner("Loading agents...", () => appRequest("/api/claw/agents"));
|
|
1346
|
+
if (isJsonMode()) return printJson(result);
|
|
1347
|
+
const agents = Array.isArray(result) ? result : result?.agents ?? [];
|
|
1348
|
+
if (!agents.length) {
|
|
1349
|
+
console.log(chalk9.dim("No agents found. Deploy one at blink.new/claw"));
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
const table = createTable(["ID", "Name", "Status", "Size", "Model"]);
|
|
1353
|
+
for (const a of agents) {
|
|
1354
|
+
table.push([a.id, a.name, a.status, a.machine_size ?? "-", a.model ?? "-"]);
|
|
1355
|
+
}
|
|
1356
|
+
console.log(table.toString());
|
|
1357
|
+
});
|
|
1358
|
+
agent.command("use <agent_id>").description("Set active agent for this shell session").option("--export", "Output shell export statement for eval").addHelpText("after", `
|
|
1359
|
+
Examples:
|
|
1360
|
+
$ blink agent use clw_xxx Prints the export command to run
|
|
1361
|
+
$ eval $(blink agent use clw_xxx --export) Actually sets it in your shell
|
|
1362
|
+
$ export BLINK_ACTIVE_AGENT=clw_xxx Same thing, manual
|
|
1363
|
+
|
|
1364
|
+
After setting, secrets commands use this agent automatically:
|
|
1365
|
+
$ blink secrets list
|
|
1366
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx
|
|
1367
|
+
`).action(async (agentId, opts) => {
|
|
1368
|
+
if (opts.export) {
|
|
1369
|
+
process.stdout.write(`export BLINK_ACTIVE_AGENT=${agentId}
|
|
1370
|
+
`);
|
|
1371
|
+
} else {
|
|
1372
|
+
console.log(chalk9.bold("Active agent: ") + agentId);
|
|
1373
|
+
console.log(chalk9.dim(`Run: export BLINK_ACTIVE_AGENT=${agentId}`));
|
|
1374
|
+
console.log(chalk9.dim(`Or: eval $(blink agent use ${agentId} --export)`));
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1377
|
+
agent.command("status [agent_id]").description("Show details for an agent").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)").addHelpText("after", `
|
|
1378
|
+
Examples:
|
|
1379
|
+
$ blink agent status Show current agent (from BLINK_AGENT_ID)
|
|
1380
|
+
$ blink agent status clw_xxx Show specific agent
|
|
1381
|
+
`).action(async (agentIdArg, opts) => {
|
|
1382
|
+
requireToken();
|
|
1383
|
+
const agentId = requireAgentId(opts.agent ?? agentIdArg);
|
|
1384
|
+
const result = await withSpinner(
|
|
1385
|
+
"Loading agent...",
|
|
1386
|
+
() => appRequest(`/api/claw/agents/${agentId}`)
|
|
1387
|
+
);
|
|
1388
|
+
if (isJsonMode()) return printJson(result);
|
|
1389
|
+
const a = result?.agent ?? result;
|
|
1390
|
+
console.log(chalk9.bold("ID ") + a.id);
|
|
1391
|
+
console.log(chalk9.bold("Name ") + a.name);
|
|
1392
|
+
console.log(chalk9.bold("Status ") + a.status);
|
|
1393
|
+
console.log(chalk9.bold("Model ") + (a.model ?? "-"));
|
|
1394
|
+
console.log(chalk9.bold("Machine ") + (a.machine_size ?? "-"));
|
|
1395
|
+
if (a.fly_app_name) console.log(chalk9.bold("Fly App ") + a.fly_app_name);
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// src/commands/secrets.ts
|
|
1400
|
+
init_agent();
|
|
1401
|
+
import chalk10 from "chalk";
|
|
1402
|
+
function registerSecretsCommands(program2) {
|
|
1403
|
+
const secrets = program2.command("secrets").description("Manage encrypted secrets vault for a Claw agent").addHelpText("after", `
|
|
1404
|
+
Secrets are encrypted key-value pairs stored in the agent's vault.
|
|
1405
|
+
They are available as $KEY_NAME in all shell commands run by the agent.
|
|
1406
|
+
Values are NEVER shown after being set \u2014 only key names are listed.
|
|
1407
|
+
|
|
1408
|
+
Agent ID resolution (priority: high \u2192 low):
|
|
1409
|
+
1. --agent <id> flag
|
|
1410
|
+
2. BLINK_AGENT_ID env var \u2190 always set on Claw Fly machines (zero config)
|
|
1411
|
+
3. BLINK_ACTIVE_AGENT env \u2190 set via eval $(blink agent use clw_xxx --export)
|
|
1412
|
+
|
|
1413
|
+
Examples:
|
|
1414
|
+
$ blink secrets list List key names for current agent
|
|
1415
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx Add/update a secret
|
|
1416
|
+
$ blink secrets delete OLD_KEY Remove a secret
|
|
1417
|
+
|
|
1418
|
+
Cross-agent management (an agent manager setting secrets on another agent):
|
|
1419
|
+
$ blink secrets set --agent clw_other OPENAI_KEY sk-xxx
|
|
1420
|
+
$ blink secrets list --agent clw_other
|
|
1421
|
+
`);
|
|
1422
|
+
secrets.command("list").description("List secret key names (values are never displayed)").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)").addHelpText("after", `
|
|
1423
|
+
Examples:
|
|
1424
|
+
$ blink secrets list List current agent's secrets
|
|
1425
|
+
$ blink secrets list --agent clw_xxx List another agent's secrets
|
|
1426
|
+
$ blink secrets list --json Machine-readable output
|
|
1427
|
+
`).action(async (opts) => {
|
|
1428
|
+
requireToken();
|
|
1429
|
+
const agentId = requireAgentId(opts.agent);
|
|
1430
|
+
const result = await withSpinner(
|
|
1431
|
+
"Loading secrets...",
|
|
1432
|
+
() => appRequest(`/api/claw/agents/${agentId}/secrets`)
|
|
1433
|
+
);
|
|
1434
|
+
if (isJsonMode()) return printJson(result);
|
|
1435
|
+
const keys = result?.secrets?.map((s) => s.key) ?? result?.keys ?? [];
|
|
1436
|
+
if (!keys.length) {
|
|
1437
|
+
console.log(chalk10.dim("(no secrets set \u2014 use `blink secrets set KEY value`)"));
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
for (const k of keys) console.log(chalk10.bold(k));
|
|
1441
|
+
console.log(chalk10.dim(`
|
|
1442
|
+
${keys.length} secret${keys.length === 1 ? "" : "s"} (values hidden)`));
|
|
1443
|
+
});
|
|
1444
|
+
secrets.command("set <key> <value>").description("Add or update a secret (stored encrypted, value never shown again)").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)").addHelpText("after", `
|
|
1445
|
+
Examples:
|
|
1446
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx
|
|
1447
|
+
$ blink secrets set OPENAI_KEY sk-xxx
|
|
1448
|
+
$ blink secrets set --agent clw_other DATABASE_URL postgres://...
|
|
1449
|
+
|
|
1450
|
+
Key naming convention: UPPER_SNAKE_CASE (e.g. GITHUB_TOKEN, OPENAI_KEY)
|
|
1451
|
+
After setting, the secret is available as $KEY_NAME in agent shell commands.
|
|
1452
|
+
`).action(async (key, value, opts) => {
|
|
1453
|
+
requireToken();
|
|
1454
|
+
const agentId = requireAgentId(opts.agent);
|
|
1455
|
+
await withSpinner(
|
|
1456
|
+
`Setting ${key}...`,
|
|
1457
|
+
() => appRequest(`/api/claw/agents/${agentId}/secrets`, {
|
|
1458
|
+
method: "POST",
|
|
1459
|
+
body: { key, value }
|
|
1460
|
+
})
|
|
1461
|
+
);
|
|
1462
|
+
const normalised = key.toUpperCase();
|
|
1463
|
+
if (!isJsonMode()) {
|
|
1464
|
+
console.log(chalk10.green("\u2713") + ` ${normalised} saved`);
|
|
1465
|
+
console.log(chalk10.dim(" Value hidden. Use $" + normalised + " in shell commands."));
|
|
1466
|
+
} else {
|
|
1467
|
+
printJson({ status: "ok", key: normalised, agent_id: agentId });
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
secrets.command("delete <key>").description("Delete a secret from the agent vault").option("--agent <id>", "Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)").option("--yes", "Skip confirmation").addHelpText("after", `
|
|
1471
|
+
Examples:
|
|
1472
|
+
$ blink secrets delete OLD_KEY
|
|
1473
|
+
$ blink secrets delete OLD_KEY --yes
|
|
1474
|
+
$ blink secrets delete --agent clw_xxx OLD_KEY
|
|
1475
|
+
`).action(async (key, opts) => {
|
|
1476
|
+
requireToken();
|
|
1477
|
+
const agentId = requireAgentId(opts.agent);
|
|
1478
|
+
if (!opts.yes && !isJsonMode()) {
|
|
1479
|
+
const { confirm } = await import("@clack/prompts");
|
|
1480
|
+
const ok = await confirm({ message: `Delete secret "${key}" from agent ${agentId}?` });
|
|
1481
|
+
if (!ok) {
|
|
1482
|
+
console.log("Cancelled.");
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
await withSpinner(
|
|
1487
|
+
`Deleting ${key}...`,
|
|
1488
|
+
() => appRequest(`/api/claw/agents/${agentId}/secrets?key=${encodeURIComponent(key)}`, { method: "DELETE" })
|
|
1489
|
+
);
|
|
1490
|
+
if (!isJsonMode()) console.log("Deleted: " + key);
|
|
1491
|
+
else printJson({ status: "ok", key, agent_id: agentId });
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1270
1495
|
// src/cli.ts
|
|
1271
1496
|
var require2 = createRequire(import.meta.url);
|
|
1272
1497
|
var pkg = require2("../package.json");
|
|
@@ -1322,6 +1547,20 @@ Connectors (Notion, Slack, Google, HubSpot, etc.):
|
|
|
1322
1547
|
$ blink connector exec notion search_pages '{"query":"meeting notes"}'
|
|
1323
1548
|
$ blink connector exec slack post_message '{"channel":"C123","text":"hi"}' --method POST
|
|
1324
1549
|
|
|
1550
|
+
Agents (Claw \u2014 zero config on Fly machines, BLINK_AGENT_ID is already set):
|
|
1551
|
+
$ blink agent list List all agents in workspace
|
|
1552
|
+
$ blink agent status Show current agent details
|
|
1553
|
+
$ eval $(blink agent use clw_xxx --export) Set active agent for session
|
|
1554
|
+
|
|
1555
|
+
Secrets (encrypted agent vault \u2014 values never shown):
|
|
1556
|
+
$ blink secrets list List secret key names
|
|
1557
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx Add/update a secret
|
|
1558
|
+
$ blink secrets delete OLD_KEY Remove a secret
|
|
1559
|
+
$ blink secrets set --agent clw_other KEY v Set secret on another agent (agent manager pattern)
|
|
1560
|
+
|
|
1561
|
+
Tip \u2014 check full context (agent + project + auth):
|
|
1562
|
+
$ blink status
|
|
1563
|
+
|
|
1325
1564
|
Scripting tip \u2014 add --json to any command for machine-readable output:
|
|
1326
1565
|
$ blink deploy ./dist --prod --json | jq '.url'
|
|
1327
1566
|
$ blink db query "SELECT email FROM users" --json | jq '.[].email'
|
|
@@ -1334,6 +1573,8 @@ Docs: https://blink.new/docs/cli
|
|
|
1334
1573
|
if (opts.profile) setProfile(opts.profile);
|
|
1335
1574
|
});
|
|
1336
1575
|
registerAuthCommands(program);
|
|
1576
|
+
registerAgentCommands(program);
|
|
1577
|
+
registerSecretsCommands(program);
|
|
1337
1578
|
registerProjectCommands(program);
|
|
1338
1579
|
registerDeployCommands(program);
|
|
1339
1580
|
registerAiCommands(program);
|
|
@@ -1359,10 +1600,10 @@ After setting:
|
|
|
1359
1600
|
process.stdout.write(`export BLINK_ACTIVE_PROJECT=${projectId}
|
|
1360
1601
|
`);
|
|
1361
1602
|
} else {
|
|
1362
|
-
const { default:
|
|
1363
|
-
console.log(
|
|
1364
|
-
console.log(
|
|
1365
|
-
console.log(
|
|
1603
|
+
const { default: chalk11 } = await import("chalk");
|
|
1604
|
+
console.log(chalk11.bold("Active project: ") + projectId);
|
|
1605
|
+
console.log(chalk11.dim(`Run: export BLINK_ACTIVE_PROJECT=${projectId}`));
|
|
1606
|
+
console.log(chalk11.dim(`Or: eval $(blink use ${projectId} --export)`));
|
|
1366
1607
|
}
|
|
1367
1608
|
});
|
|
1368
1609
|
program.action(async () => {
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { registerConnectorCommands } from './commands/connector.js'
|
|
|
12
12
|
import { registerDeployCommands } from './commands/deploy.js'
|
|
13
13
|
import { registerProjectCommands } from './commands/project.js'
|
|
14
14
|
import { registerAuthCommands } from './commands/auth.js'
|
|
15
|
+
import { registerAgentCommands } from './commands/agent.js'
|
|
16
|
+
import { registerSecretsCommands } from './commands/secrets.js'
|
|
15
17
|
|
|
16
18
|
const require = createRequire(import.meta.url)
|
|
17
19
|
const pkg = require('../package.json') as { version: string }
|
|
@@ -78,6 +80,20 @@ Connectors (Notion, Slack, Google, HubSpot, etc.):
|
|
|
78
80
|
$ blink connector exec notion search_pages '{"query":"meeting notes"}'
|
|
79
81
|
$ blink connector exec slack post_message '{"channel":"C123","text":"hi"}' --method POST
|
|
80
82
|
|
|
83
|
+
Agents (Claw — zero config on Fly machines, BLINK_AGENT_ID is already set):
|
|
84
|
+
$ blink agent list List all agents in workspace
|
|
85
|
+
$ blink agent status Show current agent details
|
|
86
|
+
$ eval $(blink agent use clw_xxx --export) Set active agent for session
|
|
87
|
+
|
|
88
|
+
Secrets (encrypted agent vault — values never shown):
|
|
89
|
+
$ blink secrets list List secret key names
|
|
90
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx Add/update a secret
|
|
91
|
+
$ blink secrets delete OLD_KEY Remove a secret
|
|
92
|
+
$ blink secrets set --agent clw_other KEY v Set secret on another agent (agent manager pattern)
|
|
93
|
+
|
|
94
|
+
Tip — check full context (agent + project + auth):
|
|
95
|
+
$ blink status
|
|
96
|
+
|
|
81
97
|
Scripting tip — add --json to any command for machine-readable output:
|
|
82
98
|
$ blink deploy ./dist --prod --json | jq '.url'
|
|
83
99
|
$ blink db query "SELECT email FROM users" --json | jq '.[].email'
|
|
@@ -92,6 +108,8 @@ Docs: https://blink.new/docs/cli
|
|
|
92
108
|
})
|
|
93
109
|
|
|
94
110
|
registerAuthCommands(program)
|
|
111
|
+
registerAgentCommands(program)
|
|
112
|
+
registerSecretsCommands(program)
|
|
95
113
|
registerProjectCommands(program)
|
|
96
114
|
registerDeployCommands(program)
|
|
97
115
|
registerAiCommands(program)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { appRequest } from '../lib/api-app.js'
|
|
3
|
+
import { requireToken } from '../lib/auth.js'
|
|
4
|
+
import { requireAgentId, resolveAgentId } from '../lib/agent.js'
|
|
5
|
+
import { printJson, isJsonMode, withSpinner, createTable } from '../lib/output.js'
|
|
6
|
+
import chalk from 'chalk'
|
|
7
|
+
|
|
8
|
+
export function registerAgentCommands(program: Command) {
|
|
9
|
+
const agent = program.command('agent')
|
|
10
|
+
.description('Manage Blink Claw agents in your workspace')
|
|
11
|
+
.addHelpText('after', `
|
|
12
|
+
Examples:
|
|
13
|
+
$ blink agent list List all agents in workspace
|
|
14
|
+
$ blink agent use clw_xxx Show how to set active agent
|
|
15
|
+
$ eval $(blink agent use clw_xxx --export) Set active agent for this session
|
|
16
|
+
$ blink agent status Show current agent details
|
|
17
|
+
|
|
18
|
+
Agent ID resolution for all agent/secrets commands (priority: high → low):
|
|
19
|
+
1. --agent <id> flag
|
|
20
|
+
2. BLINK_AGENT_ID env var ← always set on Claw Fly machines (zero config)
|
|
21
|
+
3. BLINK_ACTIVE_AGENT env ← set via eval \$(blink agent use clw_xxx --export)
|
|
22
|
+
`)
|
|
23
|
+
|
|
24
|
+
agent.command('list')
|
|
25
|
+
.description('List all Claw agents in the workspace')
|
|
26
|
+
.action(async () => {
|
|
27
|
+
requireToken()
|
|
28
|
+
const result = await withSpinner('Loading agents...', () => appRequest('/api/claw/agents'))
|
|
29
|
+
if (isJsonMode()) return printJson(result)
|
|
30
|
+
const agents: Array<{ id: string; name: string; status: string; model?: string; machine_size?: string }> =
|
|
31
|
+
Array.isArray(result) ? result : result?.agents ?? []
|
|
32
|
+
if (!agents.length) {
|
|
33
|
+
console.log(chalk.dim('No agents found. Deploy one at blink.new/claw'))
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
const table = createTable(['ID', 'Name', 'Status', 'Size', 'Model'])
|
|
37
|
+
for (const a of agents) {
|
|
38
|
+
table.push([a.id, a.name, a.status, a.machine_size ?? '-', a.model ?? '-'])
|
|
39
|
+
}
|
|
40
|
+
console.log(table.toString())
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
agent.command('use <agent_id>')
|
|
44
|
+
.description('Set active agent for this shell session')
|
|
45
|
+
.option('--export', 'Output shell export statement for eval')
|
|
46
|
+
.addHelpText('after', `
|
|
47
|
+
Examples:
|
|
48
|
+
$ blink agent use clw_xxx Prints the export command to run
|
|
49
|
+
$ eval $(blink agent use clw_xxx --export) Actually sets it in your shell
|
|
50
|
+
$ export BLINK_ACTIVE_AGENT=clw_xxx Same thing, manual
|
|
51
|
+
|
|
52
|
+
After setting, secrets commands use this agent automatically:
|
|
53
|
+
$ blink secrets list
|
|
54
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx
|
|
55
|
+
`)
|
|
56
|
+
.action(async (agentId: string, opts) => {
|
|
57
|
+
if (opts.export) {
|
|
58
|
+
process.stdout.write(`export BLINK_ACTIVE_AGENT=${agentId}\n`)
|
|
59
|
+
} else {
|
|
60
|
+
console.log(chalk.bold('Active agent: ') + agentId)
|
|
61
|
+
console.log(chalk.dim(`Run: export BLINK_ACTIVE_AGENT=${agentId}`))
|
|
62
|
+
console.log(chalk.dim(`Or: eval $(blink agent use ${agentId} --export)`))
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
agent.command('status [agent_id]')
|
|
67
|
+
.description('Show details for an agent')
|
|
68
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)')
|
|
69
|
+
.addHelpText('after', `
|
|
70
|
+
Examples:
|
|
71
|
+
$ blink agent status Show current agent (from BLINK_AGENT_ID)
|
|
72
|
+
$ blink agent status clw_xxx Show specific agent
|
|
73
|
+
`)
|
|
74
|
+
.action(async (agentIdArg: string | undefined, opts) => {
|
|
75
|
+
requireToken()
|
|
76
|
+
const agentId = requireAgentId(opts.agent ?? agentIdArg)
|
|
77
|
+
const result = await withSpinner('Loading agent...', () =>
|
|
78
|
+
appRequest(`/api/claw/agents/${agentId}`)
|
|
79
|
+
)
|
|
80
|
+
if (isJsonMode()) return printJson(result)
|
|
81
|
+
const a = result?.agent ?? result
|
|
82
|
+
console.log(chalk.bold('ID ') + a.id)
|
|
83
|
+
console.log(chalk.bold('Name ') + a.name)
|
|
84
|
+
console.log(chalk.bold('Status ') + a.status)
|
|
85
|
+
console.log(chalk.bold('Model ') + (a.model ?? '-'))
|
|
86
|
+
console.log(chalk.bold('Machine ') + (a.machine_size ?? '-'))
|
|
87
|
+
if (a.fly_app_name) console.log(chalk.bold('Fly App ') + a.fly_app_name)
|
|
88
|
+
})
|
|
89
|
+
}
|
package/src/commands/project.ts
CHANGED
|
@@ -99,16 +99,42 @@ After linking, most commands work without specifying a project_id:
|
|
|
99
99
|
})
|
|
100
100
|
|
|
101
101
|
program.command('status')
|
|
102
|
-
.description('Show
|
|
102
|
+
.description('Show current agent, project, and auth context')
|
|
103
103
|
.action(() => {
|
|
104
104
|
const config = readProjectConfig()
|
|
105
|
-
const
|
|
105
|
+
const { resolveAgentId } = require('../lib/agent.js') as typeof import('../lib/agent.js')
|
|
106
|
+
|
|
107
|
+
// Agent context
|
|
108
|
+
const agentId = resolveAgentId()
|
|
109
|
+
const agentSource = process.env.BLINK_AGENT_ID
|
|
110
|
+
? 'BLINK_AGENT_ID env'
|
|
111
|
+
: process.env.BLINK_ACTIVE_AGENT
|
|
112
|
+
? 'BLINK_ACTIVE_AGENT env'
|
|
113
|
+
: null
|
|
114
|
+
if (agentId) {
|
|
115
|
+
console.log(chalk.bold('Agent ') + agentId + chalk.dim(' (' + agentSource + ')'))
|
|
116
|
+
} else {
|
|
117
|
+
console.log(chalk.dim('Agent not set (use: eval $(blink agent use clw_xxx --export))'))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Project context
|
|
106
121
|
if (config) {
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
const projectSource = process.env.BLINK_ACTIVE_PROJECT
|
|
123
|
+
? 'BLINK_ACTIVE_PROJECT env'
|
|
124
|
+
: '.blink/project.json'
|
|
125
|
+
console.log(chalk.bold('Project ') + config.projectId + chalk.dim(' (' + projectSource + ')'))
|
|
126
|
+
} else if (process.env.BLINK_ACTIVE_PROJECT) {
|
|
127
|
+
console.log(chalk.bold('Project ') + process.env.BLINK_ACTIVE_PROJECT + chalk.dim(' (BLINK_ACTIVE_PROJECT env)'))
|
|
109
128
|
} else {
|
|
110
|
-
console.log(chalk.dim('
|
|
129
|
+
console.log(chalk.dim('Project not linked (use: blink link or eval $(blink use proj_xxx --export))'))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Auth
|
|
133
|
+
const authSource = process.env.BLINK_API_KEY ? 'BLINK_API_KEY env' : '~/.config/blink/config.toml'
|
|
134
|
+
const hasProjectKey = !!process.env.BLINK_PROJECT_KEY
|
|
135
|
+
console.log(chalk.bold('Auth ') + authSource)
|
|
136
|
+
if (hasProjectKey) {
|
|
137
|
+
console.log(chalk.bold('ProjKey ') + 'BLINK_PROJECT_KEY env' + chalk.dim(' (used for db/storage/rag)'))
|
|
111
138
|
}
|
|
112
|
-
console.log(chalk.bold('Auth ') + token)
|
|
113
139
|
})
|
|
114
140
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { appRequest } from '../lib/api-app.js'
|
|
3
|
+
import { requireToken } from '../lib/auth.js'
|
|
4
|
+
import { requireAgentId } from '../lib/agent.js'
|
|
5
|
+
import { printJson, isJsonMode, withSpinner } from '../lib/output.js'
|
|
6
|
+
import chalk from 'chalk'
|
|
7
|
+
|
|
8
|
+
export function registerSecretsCommands(program: Command) {
|
|
9
|
+
const secrets = program.command('secrets')
|
|
10
|
+
.description('Manage encrypted secrets vault for a Claw agent')
|
|
11
|
+
.addHelpText('after', `
|
|
12
|
+
Secrets are encrypted key-value pairs stored in the agent's vault.
|
|
13
|
+
They are available as $KEY_NAME in all shell commands run by the agent.
|
|
14
|
+
Values are NEVER shown after being set — only key names are listed.
|
|
15
|
+
|
|
16
|
+
Agent ID resolution (priority: high → low):
|
|
17
|
+
1. --agent <id> flag
|
|
18
|
+
2. BLINK_AGENT_ID env var ← always set on Claw Fly machines (zero config)
|
|
19
|
+
3. BLINK_ACTIVE_AGENT env ← set via eval \$(blink agent use clw_xxx --export)
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
$ blink secrets list List key names for current agent
|
|
23
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx Add/update a secret
|
|
24
|
+
$ blink secrets delete OLD_KEY Remove a secret
|
|
25
|
+
|
|
26
|
+
Cross-agent management (an agent manager setting secrets on another agent):
|
|
27
|
+
$ blink secrets set --agent clw_other OPENAI_KEY sk-xxx
|
|
28
|
+
$ blink secrets list --agent clw_other
|
|
29
|
+
`)
|
|
30
|
+
|
|
31
|
+
secrets.command('list')
|
|
32
|
+
.description('List secret key names (values are never displayed)')
|
|
33
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)')
|
|
34
|
+
.addHelpText('after', `
|
|
35
|
+
Examples:
|
|
36
|
+
$ blink secrets list List current agent's secrets
|
|
37
|
+
$ blink secrets list --agent clw_xxx List another agent's secrets
|
|
38
|
+
$ blink secrets list --json Machine-readable output
|
|
39
|
+
`)
|
|
40
|
+
.action(async (opts) => {
|
|
41
|
+
requireToken()
|
|
42
|
+
const agentId = requireAgentId(opts.agent)
|
|
43
|
+
const result = await withSpinner('Loading secrets...', () =>
|
|
44
|
+
appRequest(`/api/claw/agents/${agentId}/secrets`)
|
|
45
|
+
)
|
|
46
|
+
if (isJsonMode()) return printJson(result)
|
|
47
|
+
const keys: string[] = result?.secrets?.map((s: { key: string }) => s.key) ?? result?.keys ?? []
|
|
48
|
+
if (!keys.length) {
|
|
49
|
+
console.log(chalk.dim('(no secrets set — use `blink secrets set KEY value`)'))
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
for (const k of keys) console.log(chalk.bold(k))
|
|
53
|
+
console.log(chalk.dim(`\n${keys.length} secret${keys.length === 1 ? '' : 's'} (values hidden)`))
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
secrets.command('set <key> <value>')
|
|
57
|
+
.description('Add or update a secret (stored encrypted, value never shown again)')
|
|
58
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)')
|
|
59
|
+
.addHelpText('after', `
|
|
60
|
+
Examples:
|
|
61
|
+
$ blink secrets set GITHUB_TOKEN ghp_xxx
|
|
62
|
+
$ blink secrets set OPENAI_KEY sk-xxx
|
|
63
|
+
$ blink secrets set --agent clw_other DATABASE_URL postgres://...
|
|
64
|
+
|
|
65
|
+
Key naming convention: UPPER_SNAKE_CASE (e.g. GITHUB_TOKEN, OPENAI_KEY)
|
|
66
|
+
After setting, the secret is available as $KEY_NAME in agent shell commands.
|
|
67
|
+
`)
|
|
68
|
+
.action(async (key: string, value: string, opts) => {
|
|
69
|
+
requireToken()
|
|
70
|
+
const agentId = requireAgentId(opts.agent)
|
|
71
|
+
await withSpinner(`Setting ${key}...`, () =>
|
|
72
|
+
appRequest(`/api/claw/agents/${agentId}/secrets`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
body: { key, value },
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
const normalised = key.toUpperCase()
|
|
78
|
+
if (!isJsonMode()) {
|
|
79
|
+
console.log(chalk.green('✓') + ` ${normalised} saved`)
|
|
80
|
+
console.log(chalk.dim(' Value hidden. Use $' + normalised + ' in shell commands.'))
|
|
81
|
+
} else {
|
|
82
|
+
printJson({ status: 'ok', key: normalised, agent_id: agentId })
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
secrets.command('delete <key>')
|
|
87
|
+
.description('Delete a secret from the agent vault')
|
|
88
|
+
.option('--agent <id>', 'Agent ID (defaults to BLINK_AGENT_ID or BLINK_ACTIVE_AGENT)')
|
|
89
|
+
.option('--yes', 'Skip confirmation')
|
|
90
|
+
.addHelpText('after', `
|
|
91
|
+
Examples:
|
|
92
|
+
$ blink secrets delete OLD_KEY
|
|
93
|
+
$ blink secrets delete OLD_KEY --yes
|
|
94
|
+
$ blink secrets delete --agent clw_xxx OLD_KEY
|
|
95
|
+
`)
|
|
96
|
+
.action(async (key: string, opts) => {
|
|
97
|
+
requireToken()
|
|
98
|
+
const agentId = requireAgentId(opts.agent)
|
|
99
|
+
if (!opts.yes && !isJsonMode()) {
|
|
100
|
+
const { confirm } = await import('@clack/prompts')
|
|
101
|
+
const ok = await confirm({ message: `Delete secret "${key}" from agent ${agentId}?` })
|
|
102
|
+
if (!ok) { console.log('Cancelled.'); return }
|
|
103
|
+
}
|
|
104
|
+
await withSpinner(`Deleting ${key}...`, () =>
|
|
105
|
+
appRequest(`/api/claw/agents/${agentId}/secrets?key=${encodeURIComponent(key)}`, { method: 'DELETE' })
|
|
106
|
+
)
|
|
107
|
+
if (!isJsonMode()) console.log('Deleted: ' + key)
|
|
108
|
+
else printJson({ status: 'ok', key, agent_id: agentId })
|
|
109
|
+
})
|
|
110
|
+
}
|
package/src/lib/agent.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Agent ID resolution — parallel to lib/project.ts for project ID resolution
|
|
2
|
+
//
|
|
3
|
+
// Priority (high → low):
|
|
4
|
+
// 1. Explicit --agent <id> flag passed to the command
|
|
5
|
+
// 2. BLINK_AGENT_ID env var ← always set on Claw Fly machines (zero config)
|
|
6
|
+
// 3. BLINK_ACTIVE_AGENT env ← set via `eval $(blink agent use clw_xxx --export)`
|
|
7
|
+
|
|
8
|
+
export function resolveAgentId(explicitId?: string): string | undefined {
|
|
9
|
+
if (explicitId) return explicitId
|
|
10
|
+
if (process.env.BLINK_AGENT_ID) return process.env.BLINK_AGENT_ID
|
|
11
|
+
if (process.env.BLINK_ACTIVE_AGENT) return process.env.BLINK_ACTIVE_AGENT
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function requireAgentId(explicitId?: string): string {
|
|
16
|
+
const id = resolveAgentId(explicitId)
|
|
17
|
+
if (!id) {
|
|
18
|
+
process.stderr.write(
|
|
19
|
+
'\nError: No agent set.\n' +
|
|
20
|
+
' On Claw machines this is automatic (BLINK_AGENT_ID is injected).\n' +
|
|
21
|
+
' Otherwise:\n' +
|
|
22
|
+
' blink agent list # find your agent ID\n' +
|
|
23
|
+
' eval $(blink agent use clw_xxx --export) # set it for this session\n' +
|
|
24
|
+
' blink secrets set --agent clw_xxx KEY val # or pass --agent directly\n'
|
|
25
|
+
)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
return id
|
|
29
|
+
}
|
package/src/lib/api-resources.ts
CHANGED
|
@@ -2,6 +2,14 @@ import { resolveToken } from './auth.js'
|
|
|
2
2
|
|
|
3
3
|
const BASE_URL = process.env.BLINK_APIS_URL ?? 'https://core.blink.new'
|
|
4
4
|
|
|
5
|
+
// BLINK_PROJECT_KEY overrides the workspace key for project-scoped endpoints
|
|
6
|
+
// (db, storage, realtime, rag, notifications). Set it per-command:
|
|
7
|
+
// BLINK_PROJECT_KEY=$BLINK_PROJECT_KEY_1 blink db query "SELECT * FROM users"
|
|
8
|
+
function resolveResourceToken(): string | undefined {
|
|
9
|
+
if (process.env.BLINK_PROJECT_KEY) return process.env.BLINK_PROJECT_KEY
|
|
10
|
+
return resolveToken()
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
interface RequestOptions {
|
|
6
14
|
method?: string
|
|
7
15
|
body?: unknown
|
|
@@ -10,7 +18,7 @@ interface RequestOptions {
|
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
export async function resourcesRequest(path: string, opts: RequestOptions = {}) {
|
|
13
|
-
const token =
|
|
21
|
+
const token = resolveResourceToken()
|
|
14
22
|
const headers: Record<string, string> = {
|
|
15
23
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
16
24
|
...(process.env.BLINK_AGENT_ID ? { 'x-blink-agent-id': process.env.BLINK_AGENT_ID } : {}),
|