@boxcrew/cli 0.1.6 → 0.1.7
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 +125 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -451,10 +451,55 @@ function parseStreamJsonLine(line) {
|
|
|
451
451
|
}
|
|
452
452
|
return null;
|
|
453
453
|
}
|
|
454
|
+
function parseOpenCodeLine(line) {
|
|
455
|
+
let event;
|
|
456
|
+
try {
|
|
457
|
+
event = JSON.parse(line);
|
|
458
|
+
} catch {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
if (event.type === "text" && event.part?.type === "text" && event.part.text) {
|
|
462
|
+
return { kind: "text", text: event.part.text };
|
|
463
|
+
}
|
|
464
|
+
if (event.type) {
|
|
465
|
+
return { kind: "raw", raw: event, rawType: event.type };
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
function parseOpenClawOutput(stdout) {
|
|
470
|
+
try {
|
|
471
|
+
const firstBrace = stdout.indexOf("{");
|
|
472
|
+
if (firstBrace === -1) {
|
|
473
|
+
return [{ kind: "text", text: stdout.trim() || "No response" }];
|
|
474
|
+
}
|
|
475
|
+
const response = JSON.parse(stdout.slice(firstBrace));
|
|
476
|
+
const events = [];
|
|
477
|
+
events.push({ kind: "raw", raw: response, rawType: "openclaw_response" });
|
|
478
|
+
const sessionId = response.meta?.agentMeta?.sessionId;
|
|
479
|
+
if (sessionId) {
|
|
480
|
+
events.push({ kind: "session_id", sessionId });
|
|
481
|
+
}
|
|
482
|
+
const payloads = response.payloads;
|
|
483
|
+
if (Array.isArray(payloads)) {
|
|
484
|
+
const texts = payloads.map((p) => p.text).filter((t) => typeof t === "string" && t.length > 0);
|
|
485
|
+
if (texts.length > 0) {
|
|
486
|
+
events.push({ kind: "text", text: texts.join("\n\n") });
|
|
487
|
+
} else {
|
|
488
|
+
events.push({ kind: "text", text: "No response" });
|
|
489
|
+
}
|
|
490
|
+
} else {
|
|
491
|
+
events.push({ kind: "text", text: "No response" });
|
|
492
|
+
}
|
|
493
|
+
return events;
|
|
494
|
+
} catch {
|
|
495
|
+
return [{ kind: "text", text: stdout.trim() || "No response" }];
|
|
496
|
+
}
|
|
497
|
+
}
|
|
454
498
|
function runDaemon(agentName) {
|
|
455
499
|
const wsUrl = process.env._BX_WS_URL;
|
|
456
500
|
const claudePath = process.env._BX_CLAUDE_PATH || "claude";
|
|
457
501
|
const agentDisplayName = process.env._BX_AGENT_NAME || agentName;
|
|
502
|
+
const runtime = process.env._BX_RUNTIME || "claude-code";
|
|
458
503
|
if (!wsUrl) {
|
|
459
504
|
console.error("Missing _BX_WS_URL");
|
|
460
505
|
process.exit(1);
|
|
@@ -470,34 +515,71 @@ function runDaemon(agentName) {
|
|
|
470
515
|
activeProcess = null;
|
|
471
516
|
}
|
|
472
517
|
const { messageId, message, sessionId } = msg;
|
|
473
|
-
const args = ["-p", message, "--output-format", "stream-json", "--verbose"];
|
|
474
|
-
if (sessionId) args.push("--resume", sessionId);
|
|
475
518
|
const childEnv = { ...process.env };
|
|
476
519
|
delete childEnv.CLAUDECODE;
|
|
477
|
-
|
|
478
|
-
|
|
520
|
+
let cmd;
|
|
521
|
+
let args;
|
|
522
|
+
if (runtime === "opencode") {
|
|
523
|
+
cmd = "opencode";
|
|
524
|
+
args = ["run", "--format", "json"];
|
|
525
|
+
} else if (runtime === "openclaw") {
|
|
526
|
+
cmd = "openclaw";
|
|
527
|
+
args = ["agent", "--message", message, "--json", "--agent", "main", "--timeout", "300"];
|
|
528
|
+
} else {
|
|
529
|
+
cmd = claudePath;
|
|
530
|
+
args = ["-p", message, "--output-format", "stream-json", "--verbose"];
|
|
531
|
+
if (sessionId) args.push("--resume", sessionId);
|
|
532
|
+
}
|
|
533
|
+
const child = spawn(cmd, args, {
|
|
534
|
+
stdio: [runtime === "opencode" ? "pipe" : "ignore", "pipe", "pipe"],
|
|
479
535
|
env: childEnv
|
|
480
536
|
});
|
|
481
537
|
activeProcess = child;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
538
|
+
if (runtime === "opencode" && child.stdin) {
|
|
539
|
+
child.stdin.write(message);
|
|
540
|
+
child.stdin.end();
|
|
541
|
+
}
|
|
542
|
+
if (runtime === "openclaw") {
|
|
543
|
+
let stdout = "";
|
|
544
|
+
child.stdout.on("data", (chunk) => {
|
|
545
|
+
stdout += chunk.toString();
|
|
546
|
+
});
|
|
547
|
+
child.on("exit", (code) => {
|
|
548
|
+
if (activeProcess === child) activeProcess = null;
|
|
549
|
+
if (sendToServer) {
|
|
550
|
+
const events = parseOpenClawOutput(stdout);
|
|
551
|
+
for (const event of events) {
|
|
552
|
+
sendToServer({ type: "event", messageId, event });
|
|
553
|
+
}
|
|
554
|
+
sendToServer({ type: "event", messageId, event: { kind: "done" } });
|
|
555
|
+
}
|
|
556
|
+
if (code && code !== 0) {
|
|
557
|
+
console.error(`OpenClaw exited with code ${code}`);
|
|
558
|
+
sendToServer?.({ type: "error", messageId, error: `OpenClaw exited with code ${code}` });
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
} else {
|
|
562
|
+
const parseLine = runtime === "opencode" ? parseOpenCodeLine : parseStreamJsonLine;
|
|
563
|
+
const rl = createInterface3({ input: child.stdout });
|
|
564
|
+
rl.on("line", (line) => {
|
|
565
|
+
const event = parseLine(line);
|
|
566
|
+
if (event && sendToServer) {
|
|
567
|
+
sendToServer({ type: "event", messageId, event });
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
child.on("exit", (code) => {
|
|
571
|
+
if (activeProcess === child) activeProcess = null;
|
|
572
|
+
if (sendToServer) {
|
|
573
|
+
sendToServer({ type: "event", messageId, event: { kind: "done" } });
|
|
574
|
+
}
|
|
575
|
+
if (code && code !== 0) {
|
|
576
|
+
console.error(`${runtime} exited with code ${code}`);
|
|
577
|
+
sendToServer?.({ type: "error", messageId, error: `${runtime} exited with code ${code}` });
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
}
|
|
499
581
|
child.on("error", (err) => {
|
|
500
|
-
console.error(`Failed to spawn
|
|
582
|
+
console.error(`Failed to spawn ${runtime}: ${err.message}`);
|
|
501
583
|
sendToServer?.({ type: "error", messageId, error: `Failed to spawn: ${err.message}` });
|
|
502
584
|
});
|
|
503
585
|
};
|
|
@@ -573,7 +655,7 @@ function registerConnectCommand(program2) {
|
|
|
573
655
|
program2.command("_daemon <agent-name>", { hidden: true }).action((agentName) => {
|
|
574
656
|
runDaemon(agentName);
|
|
575
657
|
});
|
|
576
|
-
program2.command("connect <agent-name>").description("Connect a local
|
|
658
|
+
program2.command("connect <agent-name>").description("Connect a local agent to BoxCrew.").option("--claude-path <path>", "Path to claude CLI binary", "claude").action(async (agentName, options) => {
|
|
577
659
|
const existingPid = readPid(agentName);
|
|
578
660
|
if (existingPid) {
|
|
579
661
|
console.log(`Agent "${agentName}" is already connected (PID ${existingPid}).`);
|
|
@@ -591,12 +673,29 @@ function registerConnectCommand(program2) {
|
|
|
591
673
|
...process.env,
|
|
592
674
|
_BX_WS_URL: config2.websocket_url,
|
|
593
675
|
_BX_CLAUDE_PATH: options.claudePath,
|
|
594
|
-
_BX_AGENT_NAME: config2.agent_name
|
|
676
|
+
_BX_AGENT_NAME: config2.agent_name,
|
|
677
|
+
_BX_RUNTIME: config2.runtime
|
|
595
678
|
}
|
|
596
679
|
});
|
|
597
680
|
child.unref();
|
|
598
|
-
|
|
599
|
-
|
|
681
|
+
const runtimeNames = {
|
|
682
|
+
"claude-code": "Claude Code",
|
|
683
|
+
"opencode": "OpenCode",
|
|
684
|
+
"openclaw": "OpenClaw"
|
|
685
|
+
};
|
|
686
|
+
const runtimeDisplay = runtimeNames[config2.runtime] || config2.runtime;
|
|
687
|
+
const cwd = process.cwd();
|
|
688
|
+
const home = homedir();
|
|
689
|
+
const shortLog = logFile.startsWith(home) ? "~" + logFile.slice(home.length) : logFile;
|
|
690
|
+
console.log("");
|
|
691
|
+
console.log(` Agent "${config2.agent_name}" is online.`);
|
|
692
|
+
console.log("");
|
|
693
|
+
console.log(` Runtime: ${runtimeDisplay}`);
|
|
694
|
+
console.log(` Directory: ${cwd}`);
|
|
695
|
+
console.log(` Logs: ${shortLog}`);
|
|
696
|
+
console.log("");
|
|
697
|
+
console.log(` To disconnect: npx @boxcrew/cli disconnect ${agentName}`);
|
|
698
|
+
console.log("");
|
|
600
699
|
});
|
|
601
700
|
program2.command("disconnect <agent-name>").description("Disconnect a local agent.").action((agentName) => {
|
|
602
701
|
const pid = readPid(agentName);
|