@boxcrew/cli 0.1.3 → 0.1.4
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/index.js +55 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,6 +16,22 @@ var config = new Conf({
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
// src/auth.ts
|
|
20
|
+
function getAuthToken() {
|
|
21
|
+
if (process.env.BOXCREW_API_KEY) return process.env.BOXCREW_API_KEY;
|
|
22
|
+
return config.get("apiKey") ?? null;
|
|
23
|
+
}
|
|
24
|
+
function requireAuth() {
|
|
25
|
+
const token = getAuthToken();
|
|
26
|
+
if (!token) {
|
|
27
|
+
console.error(
|
|
28
|
+
"Not authenticated. Run `bx login` or set the BOXCREW_API_KEY environment variable."
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
return token;
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
// src/commands/login.ts
|
|
20
36
|
var DEFAULT_FRONTEND_URL = "https://boxcrew.ai";
|
|
21
37
|
function registerLoginCommand(program2) {
|
|
@@ -28,32 +44,38 @@ function registerLoginCommand(program2) {
|
|
|
28
44
|
if (options.apiUrl) {
|
|
29
45
|
config.set("apiUrl", options.apiUrl);
|
|
30
46
|
}
|
|
31
|
-
|
|
32
|
-
console.log("Opening browser to authenticate...");
|
|
33
|
-
console.log(`If the browser doesn't open, visit: ${authUrl}
|
|
34
|
-
`);
|
|
35
|
-
open(authUrl).catch(() => {
|
|
36
|
-
});
|
|
37
|
-
const rl = createInterface({
|
|
38
|
-
input: process.stdin,
|
|
39
|
-
output: process.stdout
|
|
40
|
-
});
|
|
41
|
-
const apiKey = await new Promise((resolve) => {
|
|
42
|
-
rl.question("Paste your API key: ", (answer) => {
|
|
43
|
-
rl.close();
|
|
44
|
-
resolve(answer.trim());
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
if (!apiKey.startsWith("bxk_")) {
|
|
48
|
-
console.error('Invalid API key. Keys should start with "bxk_".');
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
config.set("apiKey", apiKey);
|
|
52
|
-
console.log("\nAuthenticated successfully! Credentials stored.");
|
|
53
|
-
console.log(`API URL: ${config.get("apiUrl")}`);
|
|
47
|
+
await ensureLoggedIn(options.frontendUrl);
|
|
54
48
|
}
|
|
55
49
|
);
|
|
56
50
|
}
|
|
51
|
+
async function ensureLoggedIn(frontendUrl = DEFAULT_FRONTEND_URL) {
|
|
52
|
+
if (getAuthToken()) {
|
|
53
|
+
console.log("Already authenticated.");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const authUrl = `${frontendUrl}/cli-auth`;
|
|
57
|
+
console.log("Opening browser to authenticate...");
|
|
58
|
+
console.log(`If the browser doesn't open, visit: ${authUrl}
|
|
59
|
+
`);
|
|
60
|
+
open(authUrl).catch(() => {
|
|
61
|
+
});
|
|
62
|
+
const rl = createInterface({
|
|
63
|
+
input: process.stdin,
|
|
64
|
+
output: process.stdout
|
|
65
|
+
});
|
|
66
|
+
const apiKey = await new Promise((resolve) => {
|
|
67
|
+
rl.question("Paste your API key: ", (answer) => {
|
|
68
|
+
rl.close();
|
|
69
|
+
resolve(answer.trim());
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
if (!apiKey.startsWith("bxk_")) {
|
|
73
|
+
console.error('Invalid API key. Keys should start with "bxk_".');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
config.set("apiKey", apiKey);
|
|
77
|
+
console.log("Authenticated successfully!\n");
|
|
78
|
+
}
|
|
57
79
|
|
|
58
80
|
// src/commands/logout.ts
|
|
59
81
|
function registerLogoutCommand(program2) {
|
|
@@ -63,22 +85,6 @@ function registerLogoutCommand(program2) {
|
|
|
63
85
|
});
|
|
64
86
|
}
|
|
65
87
|
|
|
66
|
-
// src/auth.ts
|
|
67
|
-
function getAuthToken() {
|
|
68
|
-
if (process.env.BOXCREW_API_KEY) return process.env.BOXCREW_API_KEY;
|
|
69
|
-
return config.get("apiKey") ?? null;
|
|
70
|
-
}
|
|
71
|
-
function requireAuth() {
|
|
72
|
-
const token = getAuthToken();
|
|
73
|
-
if (!token) {
|
|
74
|
-
console.error(
|
|
75
|
-
"Not authenticated. Run `bx login` or set the BOXCREW_API_KEY environment variable."
|
|
76
|
-
);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
return token;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
88
|
// src/client.ts
|
|
83
89
|
function getBaseUrl() {
|
|
84
90
|
return process.env.BOXCREW_API_URL || config.get("apiUrl");
|
|
@@ -401,16 +407,18 @@ function parseStreamJsonLine(line) {
|
|
|
401
407
|
return null;
|
|
402
408
|
}
|
|
403
409
|
function registerConnectCommand(program2) {
|
|
404
|
-
program2.command("connect <agent-name>").description(
|
|
405
|
-
"
|
|
406
|
-
|
|
407
|
-
|
|
410
|
+
program2.command("connect <agent-name>").description("Connect a local Claude Code instance to a BoxCrew agent.").option("--claude-path <path>", "Path to claude CLI binary", "claude").option(
|
|
411
|
+
"--frontend-url <url>",
|
|
412
|
+
"BoxCrew frontend URL",
|
|
413
|
+
process.env.BOXCREW_FRONTEND_URL || "https://boxcrew.ai"
|
|
414
|
+
).action(async (agentName, options) => {
|
|
415
|
+
if (!getAuthToken()) {
|
|
416
|
+
await ensureLoggedIn(options.frontendUrl);
|
|
417
|
+
}
|
|
408
418
|
const config2 = await apiFetchJson(
|
|
409
419
|
`/agents/${encodeURIComponent(agentName)}/connection-config`
|
|
410
420
|
);
|
|
411
421
|
const wsUrl = config2.websocket_url;
|
|
412
|
-
console.log(`Agent: ${config2.agent_name} (${config2.agent_id.slice(0, 8)}...)`);
|
|
413
|
-
console.log(`Proxy: ${config2.proxy_base_url}`);
|
|
414
422
|
const claudePath = options.claudePath;
|
|
415
423
|
let activeProcess = null;
|
|
416
424
|
let sendToServer = null;
|
|
@@ -422,8 +430,6 @@ function registerConnectCommand(program2) {
|
|
|
422
430
|
activeProcess = null;
|
|
423
431
|
}
|
|
424
432
|
const { messageId, message, sessionId } = msg;
|
|
425
|
-
console.log(`
|
|
426
|
-
Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ? "..." : ""}`);
|
|
427
433
|
const args = ["-p", message, "--output-format", "stream-json", "--verbose"];
|
|
428
434
|
if (sessionId) args.push("--resume", sessionId);
|
|
429
435
|
const childEnv = { ...process.env };
|
|
@@ -440,12 +446,6 @@ Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ?
|
|
|
440
446
|
sendToServer({ type: "event", messageId, event });
|
|
441
447
|
}
|
|
442
448
|
});
|
|
443
|
-
if (child.stderr) {
|
|
444
|
-
const stderrRl = createInterface2({ input: child.stderr });
|
|
445
|
-
stderrRl.on("line", (line) => {
|
|
446
|
-
if (line.trim()) console.error(` [claude] ${line}`);
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
449
|
child.on("exit", (code) => {
|
|
450
450
|
if (activeProcess === child) activeProcess = null;
|
|
451
451
|
if (sendToServer) {
|
|
@@ -462,7 +462,6 @@ Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ?
|
|
|
462
462
|
});
|
|
463
463
|
};
|
|
464
464
|
const connect = () => {
|
|
465
|
-
console.log("Connecting to BoxCrew...");
|
|
466
465
|
const ws = new WebSocket(wsUrl);
|
|
467
466
|
const send = (msg) => {
|
|
468
467
|
if (ws.readyState === WebSocket.OPEN) {
|
|
@@ -472,7 +471,7 @@ Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ?
|
|
|
472
471
|
ws.on("open", () => {
|
|
473
472
|
reconnectAttempt = 0;
|
|
474
473
|
sendToServer = send;
|
|
475
|
-
console.log("
|
|
474
|
+
console.log(`Agent "${config2.agent_name}" is online. Press Ctrl+C to disconnect.`);
|
|
476
475
|
});
|
|
477
476
|
ws.on("message", (data) => {
|
|
478
477
|
let msg;
|
|
@@ -486,7 +485,6 @@ Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ?
|
|
|
486
485
|
return;
|
|
487
486
|
}
|
|
488
487
|
if (msg.type === "stop" && activeProcess) {
|
|
489
|
-
console.log(`Stopping chat ${msg.messageId.slice(0, 8)}...`);
|
|
490
488
|
activeProcess.kill("SIGINT");
|
|
491
489
|
return;
|
|
492
490
|
}
|
|
@@ -511,7 +509,7 @@ Chat ${messageId.slice(0, 8)}: ${message.slice(0, 120)}${message.length > 120 ?
|
|
|
511
509
|
}
|
|
512
510
|
});
|
|
513
511
|
ws.on("error", (err) => {
|
|
514
|
-
console.error("
|
|
512
|
+
console.error("Connection error:", err.message);
|
|
515
513
|
});
|
|
516
514
|
const shutdown = () => {
|
|
517
515
|
shouldReconnect = false;
|