@vicvic-im/agent-bot 0.1.0 → 0.1.2
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/README.md +1 -1
- package/dist/bin-server.cjs +1292 -0
- package/dist/bin-server.cjs.map +1 -0
- package/dist/bin-server.d.ts +2 -0
- package/dist/bin-server.d.ts.map +1 -0
- package/dist/bin-server.js +19 -0
- package/dist/bin-server.js.map +1 -0
- package/dist/{chunk-FYLVJB7J.js → chunk-6CK4XIJB.js} +2 -2
- package/dist/{chunk-DMDFB2QE.js → chunk-X5QSWCDH.js} +19 -35
- package/dist/chunk-X5QSWCDH.js.map +1 -0
- package/dist/cli.cjs +93 -87
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +58 -34
- package/dist/cli.js.map +1 -1
- package/dist/core/cli-path.d.ts +8 -0
- package/dist/core/cli-path.d.ts.map +1 -0
- package/dist/core/pm2.d.ts +7 -0
- package/dist/core/pm2.d.ts.map +1 -0
- package/dist/index.cjs +12 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/server.cjs +12 -26
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-DMDFB2QE.js.map +0 -1
- /package/dist/{chunk-FYLVJB7J.js.map → chunk-6CK4XIJB.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -24,8 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
-
var
|
|
28
|
-
var import_node_fs5 = require("fs");
|
|
27
|
+
var import_node_child_process3 = require("child_process");
|
|
29
28
|
var import_node_path6 = require("path");
|
|
30
29
|
var import_commander = require("commander");
|
|
31
30
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
@@ -137,11 +136,11 @@ function parseEnv(value) {
|
|
|
137
136
|
if (value === void 0 || value === null) return void 0;
|
|
138
137
|
const record = asRecord(value, "agent.env");
|
|
139
138
|
const env = {};
|
|
140
|
-
for (const [key,
|
|
141
|
-
if (typeof
|
|
139
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
140
|
+
if (typeof entry !== "string") {
|
|
142
141
|
throw new ConfigError(`Invalid "agent.env.${key}": expected a string`);
|
|
143
142
|
}
|
|
144
|
-
env[key] =
|
|
143
|
+
env[key] = entry;
|
|
145
144
|
}
|
|
146
145
|
return env;
|
|
147
146
|
}
|
|
@@ -185,7 +184,7 @@ function parseAgent(root, configDir) {
|
|
|
185
184
|
return {
|
|
186
185
|
name: agentName,
|
|
187
186
|
command: optionalString(agentRaw.command, "agent.command"),
|
|
188
|
-
args: Array.isArray(argsRaw) ? argsRaw.map((
|
|
187
|
+
args: Array.isArray(argsRaw) ? argsRaw.map((entry) => String(entry)) : void 0,
|
|
189
188
|
cwd,
|
|
190
189
|
model: optionalString(agentRaw.model, "agent.model") ?? null,
|
|
191
190
|
env: parseEnv(agentRaw.env)
|
|
@@ -314,11 +313,49 @@ async function ensureConfig(explicit) {
|
|
|
314
313
|
return { config, path: target };
|
|
315
314
|
}
|
|
316
315
|
|
|
317
|
-
// src/
|
|
318
|
-
var
|
|
316
|
+
// src/core/cli-path.ts
|
|
317
|
+
var import_node_fs3 = require("fs");
|
|
318
|
+
var import_node_path3 = require("path");
|
|
319
|
+
function resolveServerEntry(cliPath2) {
|
|
320
|
+
const real = (0, import_node_fs3.realpathSync)(cliPath2);
|
|
321
|
+
const candidate = (0, import_node_path3.join)((0, import_node_path3.dirname)(real), "bin-server.js");
|
|
322
|
+
if (!(0, import_node_fs3.existsSync)(candidate)) {
|
|
323
|
+
throw new Error(`Server bundle not found at ${candidate}. Reinstall @vicvic-im/agent-bot.`);
|
|
324
|
+
}
|
|
325
|
+
return candidate;
|
|
326
|
+
}
|
|
327
|
+
function readPackageVersion(cliPath2) {
|
|
328
|
+
try {
|
|
329
|
+
const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)((0, import_node_path3.dirname)((0, import_node_fs3.realpathSync)(cliPath2)), "..", "package.json"), "utf8");
|
|
330
|
+
return JSON.parse(raw).version ?? "0.1.0";
|
|
331
|
+
} catch {
|
|
332
|
+
return "0.1.0";
|
|
333
|
+
}
|
|
334
|
+
}
|
|
319
335
|
|
|
320
|
-
// src/
|
|
336
|
+
// src/core/pm2.ts
|
|
321
337
|
var import_node_child_process = require("child_process");
|
|
338
|
+
var ENV_BIN = "/usr/bin/env";
|
|
339
|
+
function hasPm2(exec = import_node_child_process.execFileSync) {
|
|
340
|
+
try {
|
|
341
|
+
exec(ENV_BIN, ["pm2", "--version"], { stdio: "ignore" });
|
|
342
|
+
return true;
|
|
343
|
+
} catch {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function ensurePm2(exec = import_node_child_process.execFileSync) {
|
|
348
|
+
if (hasPm2(exec)) return true;
|
|
349
|
+
try {
|
|
350
|
+
exec(ENV_BIN, ["npm", "i", "-g", "pm2"], { stdio: "inherit" });
|
|
351
|
+
return hasPm2(exec);
|
|
352
|
+
} catch {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/agents/acp.ts
|
|
358
|
+
var import_node_child_process2 = require("child_process");
|
|
322
359
|
var import_node_stream = require("stream");
|
|
323
360
|
var acp = __toESM(require("@agentclientprotocol/sdk"), 1);
|
|
324
361
|
|
|
@@ -385,7 +422,7 @@ var AcpAgent = class {
|
|
|
385
422
|
const definition = definitionOf(this.name);
|
|
386
423
|
const command = this.config.command ?? definition.command.command;
|
|
387
424
|
const args = this.config.args ?? definition.command.args;
|
|
388
|
-
const child = (0,
|
|
425
|
+
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
389
426
|
cwd: this.config.cwd,
|
|
390
427
|
env: { ...process.env, ...this.config.env },
|
|
391
428
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -524,7 +561,7 @@ var AcpAgent = class {
|
|
|
524
561
|
);
|
|
525
562
|
pending.catch(() => void 0);
|
|
526
563
|
const response = await Promise.race([pending, aborted]);
|
|
527
|
-
await new Promise((
|
|
564
|
+
await new Promise((resolve4) => setImmediate(resolve4));
|
|
528
565
|
if (response.stopReason === "cancelled" || request.signal.aborted) {
|
|
529
566
|
throw new AgentAbortError();
|
|
530
567
|
}
|
|
@@ -557,7 +594,7 @@ var AcpAgent = class {
|
|
|
557
594
|
return true;
|
|
558
595
|
}
|
|
559
596
|
const option = this.configOptions.find(
|
|
560
|
-
(
|
|
597
|
+
(entry) => entry.type === "select" && (entry.id === "model" || entry.category === "model")
|
|
561
598
|
);
|
|
562
599
|
if (!option) return false;
|
|
563
600
|
await this.ctx.request(acp.methods.agent.session.setConfigOption, {
|
|
@@ -583,8 +620,8 @@ var AcpAgent = class {
|
|
|
583
620
|
} catch {
|
|
584
621
|
}
|
|
585
622
|
if (!child || child.exitCode !== null) return;
|
|
586
|
-
const exited = new Promise((
|
|
587
|
-
child.once("exit", () =>
|
|
623
|
+
const exited = new Promise((resolve4) => {
|
|
624
|
+
child.once("exit", () => resolve4());
|
|
588
625
|
});
|
|
589
626
|
child.kill("SIGTERM");
|
|
590
627
|
const timer = setTimeout(() => child.kill("SIGKILL"), 3e3);
|
|
@@ -701,7 +738,7 @@ var BotQueue = class {
|
|
|
701
738
|
};
|
|
702
739
|
|
|
703
740
|
// src/version.ts
|
|
704
|
-
var VBOT_VERSION = "0.1.
|
|
741
|
+
var VBOT_VERSION = "0.1.2";
|
|
705
742
|
|
|
706
743
|
// src/core/dispatcher.ts
|
|
707
744
|
var HELP_TEXT = `Available commands:
|
|
@@ -782,7 +819,7 @@ function handleAgent(runtime, args, send) {
|
|
|
782
819
|
const name = args.join(" ").trim();
|
|
783
820
|
if (!name) {
|
|
784
821
|
const current = runtime.config().agent.name;
|
|
785
|
-
const list = AGENT_NAMES.map((
|
|
822
|
+
const list = AGENT_NAMES.map((entry) => `${entry === current ? "*" : " "} ${entry}`).join("\n");
|
|
786
823
|
send(`Current agent: ${current}
|
|
787
824
|
Available agents:
|
|
788
825
|
${list}`);
|
|
@@ -899,25 +936,25 @@ async function switchAgent(ctx, name) {
|
|
|
899
936
|
}
|
|
900
937
|
|
|
901
938
|
// src/core/lock.ts
|
|
902
|
-
var
|
|
903
|
-
var
|
|
939
|
+
var import_node_fs5 = require("fs");
|
|
940
|
+
var import_node_path5 = require("path");
|
|
904
941
|
|
|
905
942
|
// src/core/state.ts
|
|
906
943
|
var import_node_crypto = require("crypto");
|
|
907
|
-
var
|
|
944
|
+
var import_node_fs4 = require("fs");
|
|
908
945
|
var import_node_os2 = require("os");
|
|
909
|
-
var
|
|
946
|
+
var import_node_path4 = require("path");
|
|
910
947
|
function vbotHome() {
|
|
911
|
-
return process.env.VBOT_HOME?.trim() || (0,
|
|
948
|
+
return process.env.VBOT_HOME?.trim() || (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".vbot");
|
|
912
949
|
}
|
|
913
950
|
function stateDir() {
|
|
914
|
-
return (0,
|
|
951
|
+
return (0, import_node_path4.join)(vbotHome(), "state");
|
|
915
952
|
}
|
|
916
953
|
function tokenHash(token) {
|
|
917
954
|
return (0, import_node_crypto.createHash)("sha256").update(token).digest("hex").slice(0, 16);
|
|
918
955
|
}
|
|
919
956
|
function statePath(token) {
|
|
920
|
-
return (0,
|
|
957
|
+
return (0, import_node_path4.join)(stateDir(), `${tokenHash(token)}.json`);
|
|
921
958
|
}
|
|
922
959
|
function emptyState(token, agent, cwd) {
|
|
923
960
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -933,9 +970,9 @@ function emptyState(token, agent, cwd) {
|
|
|
933
970
|
}
|
|
934
971
|
function loadState(token) {
|
|
935
972
|
const path = statePath(token);
|
|
936
|
-
if (!(0,
|
|
973
|
+
if (!(0, import_node_fs4.existsSync)(path)) return null;
|
|
937
974
|
try {
|
|
938
|
-
const parsed = JSON.parse((0,
|
|
975
|
+
const parsed = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
939
976
|
if (typeof parsed.acpSessionId !== "string" && parsed.acpSessionId !== null) return null;
|
|
940
977
|
if (typeof parsed.agent !== "string") return null;
|
|
941
978
|
return {
|
|
@@ -953,12 +990,12 @@ function loadState(token) {
|
|
|
953
990
|
}
|
|
954
991
|
function saveState(state) {
|
|
955
992
|
const dir = stateDir();
|
|
956
|
-
(0,
|
|
957
|
-
const path = (0,
|
|
993
|
+
(0, import_node_fs4.mkdirSync)(dir, { recursive: true });
|
|
994
|
+
const path = (0, import_node_path4.join)(dir, `${state.tokenHash}.json`);
|
|
958
995
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
959
|
-
(0,
|
|
996
|
+
(0, import_node_fs4.writeFileSync)(tmp, `${JSON.stringify(state, null, 2)}
|
|
960
997
|
`, { mode: 384 });
|
|
961
|
-
(0,
|
|
998
|
+
(0, import_node_fs4.renameSync)(tmp, path);
|
|
962
999
|
}
|
|
963
1000
|
|
|
964
1001
|
// src/core/lock.ts
|
|
@@ -968,10 +1005,10 @@ var LockError = class extends Error {
|
|
|
968
1005
|
this.name = "LockError";
|
|
969
1006
|
}
|
|
970
1007
|
};
|
|
971
|
-
var lockPath = (token) => (0,
|
|
1008
|
+
var lockPath = (token) => (0, import_node_path5.join)(stateDir(), `${tokenHash(token)}.lock`);
|
|
972
1009
|
function readPid(path) {
|
|
973
1010
|
try {
|
|
974
|
-
const pid = Number.parseInt((0,
|
|
1011
|
+
const pid = Number.parseInt((0, import_node_fs5.readFileSync)(path, "utf8").trim(), 10);
|
|
975
1012
|
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
976
1013
|
} catch {
|
|
977
1014
|
return null;
|
|
@@ -986,13 +1023,13 @@ function isAlive(pid) {
|
|
|
986
1023
|
}
|
|
987
1024
|
}
|
|
988
1025
|
function acquireLock(token) {
|
|
989
|
-
(0,
|
|
1026
|
+
(0, import_node_fs5.mkdirSync)(stateDir(), { recursive: true });
|
|
990
1027
|
const path = lockPath(token);
|
|
991
1028
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
992
1029
|
try {
|
|
993
|
-
const fd = (0,
|
|
994
|
-
(0,
|
|
995
|
-
(0,
|
|
1030
|
+
const fd = (0, import_node_fs5.openSync)(path, "wx");
|
|
1031
|
+
(0, import_node_fs5.writeSync)(fd, String(process.pid));
|
|
1032
|
+
(0, import_node_fs5.closeSync)(fd);
|
|
996
1033
|
return () => releaseLock(token);
|
|
997
1034
|
} catch (error) {
|
|
998
1035
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") {
|
|
@@ -1003,7 +1040,7 @@ function acquireLock(token) {
|
|
|
1003
1040
|
throw new LockError(`This bot is already running in another vbot process (pid ${pid}).`);
|
|
1004
1041
|
}
|
|
1005
1042
|
try {
|
|
1006
|
-
(0,
|
|
1043
|
+
(0, import_node_fs5.unlinkSync)(path);
|
|
1007
1044
|
} catch {
|
|
1008
1045
|
}
|
|
1009
1046
|
}
|
|
@@ -1012,11 +1049,11 @@ function acquireLock(token) {
|
|
|
1012
1049
|
}
|
|
1013
1050
|
function releaseLock(token) {
|
|
1014
1051
|
const path = lockPath(token);
|
|
1015
|
-
if (!(0,
|
|
1052
|
+
if (!(0, import_node_fs5.existsSync)(path)) return;
|
|
1016
1053
|
const pid = readPid(path);
|
|
1017
1054
|
if (pid !== process.pid) return;
|
|
1018
1055
|
try {
|
|
1019
|
-
(0,
|
|
1056
|
+
(0, import_node_fs5.unlinkSync)(path);
|
|
1020
1057
|
} catch {
|
|
1021
1058
|
}
|
|
1022
1059
|
}
|
|
@@ -1066,10 +1103,10 @@ var VicvicWire = class {
|
|
|
1066
1103
|
if (!socket || socket.readyState !== import_ws.default.OPEN) {
|
|
1067
1104
|
throw new Error("Bot connection is not open");
|
|
1068
1105
|
}
|
|
1069
|
-
await new Promise((
|
|
1106
|
+
await new Promise((resolve4, reject) => {
|
|
1070
1107
|
socket.send(JSON.stringify({ type: "reply", msgUid, text }), (error) => {
|
|
1071
1108
|
if (error) reject(error);
|
|
1072
|
-
else
|
|
1109
|
+
else resolve4();
|
|
1073
1110
|
});
|
|
1074
1111
|
});
|
|
1075
1112
|
}
|
|
@@ -1363,35 +1400,14 @@ ${error.stderr}`);
|
|
|
1363
1400
|
console.error("[server] agent run failed:", error);
|
|
1364
1401
|
replySafe(reply, `Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1365
1402
|
}
|
|
1366
|
-
var entry = process.argv[1] ?? "";
|
|
1367
|
-
if (/(^|[\\/])server\.(js|cjs|ts)$/.test(entry)) {
|
|
1368
|
-
const configPath = process.argv[2];
|
|
1369
|
-
if (!configPath) {
|
|
1370
|
-
console.error("Usage: server.js <config-path>");
|
|
1371
|
-
process.exit(1);
|
|
1372
|
-
}
|
|
1373
|
-
runBot((0, import_node_path5.resolve)(configPath)).catch((error) => {
|
|
1374
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
1375
|
-
const expected = error instanceof ConfigError || error instanceof LockError;
|
|
1376
|
-
process.exit(expected ? 2 : 1);
|
|
1377
|
-
});
|
|
1378
|
-
}
|
|
1379
1403
|
|
|
1380
1404
|
// src/cli.ts
|
|
1381
1405
|
function processName(cwd) {
|
|
1382
1406
|
return `vbot-${(0, import_node_path6.basename)((0, import_node_path6.resolve)(cwd)).replace(/[^a-zA-Z0-9._-]+/g, "-")}`;
|
|
1383
1407
|
}
|
|
1384
|
-
var
|
|
1385
|
-
function hasPm2() {
|
|
1386
|
-
try {
|
|
1387
|
-
(0, import_node_child_process2.execFileSync)(ENV_BIN, ["pm2", "--version"], { stdio: "ignore" });
|
|
1388
|
-
return true;
|
|
1389
|
-
} catch {
|
|
1390
|
-
return false;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1408
|
+
var ENV_BIN2 = "/usr/bin/env";
|
|
1393
1409
|
function pm2(args, capture = false) {
|
|
1394
|
-
return (0,
|
|
1410
|
+
return (0, import_node_child_process3.execFileSync)(ENV_BIN2, ["pm2", ...args], {
|
|
1395
1411
|
stdio: capture ? "pipe" : "inherit",
|
|
1396
1412
|
encoding: "utf8"
|
|
1397
1413
|
});
|
|
@@ -1406,33 +1422,23 @@ function resolveName(configPath) {
|
|
|
1406
1422
|
return "vbot";
|
|
1407
1423
|
}
|
|
1408
1424
|
}
|
|
1409
|
-
function
|
|
1410
|
-
const
|
|
1411
|
-
if (!
|
|
1412
|
-
|
|
1413
|
-
if (!(0, import_node_fs5.existsSync)(candidate)) {
|
|
1414
|
-
throw new Error(`Server bundle not found at ${candidate}. Run "pnpm build" first.`);
|
|
1415
|
-
}
|
|
1416
|
-
return candidate;
|
|
1425
|
+
function cliPath() {
|
|
1426
|
+
const path = process.argv[1];
|
|
1427
|
+
if (!path) throw new Error("Cannot resolve vbot entry; run the installed binary.");
|
|
1428
|
+
return path;
|
|
1417
1429
|
}
|
|
1418
1430
|
var program = new import_commander.Command();
|
|
1419
|
-
program.name("vbot").description("Connect local coding agents to vicvic.im").version(
|
|
1420
|
-
function readVersion() {
|
|
1421
|
-
try {
|
|
1422
|
-
const raw = (0, import_node_fs5.readFileSync)((0, import_node_path6.join)((0, import_node_path6.dirname)(process.argv[1] ?? ""), "..", "package.json"), "utf8");
|
|
1423
|
-
return JSON.parse(raw).version ?? "0.1.0";
|
|
1424
|
-
} catch {
|
|
1425
|
-
return "0.1.0";
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1431
|
+
program.name("vbot").description("Connect local coding agents to vicvic.im").version(readPackageVersion(cliPath()));
|
|
1428
1432
|
program.command("start").description("Start vbot (prompts for config on first run)").option("--foreground", "run in the foreground instead of pm2").option("-c, --config <path>", "config file path").action(async (options) => {
|
|
1429
1433
|
const { path } = await ensureConfig(options.config);
|
|
1430
|
-
if (options.foreground
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1434
|
+
if (options.foreground) {
|
|
1435
|
+
await runBot(path);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (!hasPm2()) console.log(import_picocolors2.default.yellow("pm2 not found, installing globally..."));
|
|
1439
|
+
if (!ensurePm2()) {
|
|
1440
|
+
console.error(import_picocolors2.default.red("Failed to install pm2. Please install manually: npm i -g pm2"));
|
|
1441
|
+
console.log(import_picocolors2.default.yellow("Running in the foreground instead."));
|
|
1436
1442
|
await runBot(path);
|
|
1437
1443
|
return;
|
|
1438
1444
|
}
|
|
@@ -1443,7 +1449,7 @@ program.command("start").description("Start vbot (prompts for config on first ru
|
|
|
1443
1449
|
} catch {
|
|
1444
1450
|
pm2([
|
|
1445
1451
|
"start",
|
|
1446
|
-
|
|
1452
|
+
resolveServerEntry(cliPath()),
|
|
1447
1453
|
"--name",
|
|
1448
1454
|
name,
|
|
1449
1455
|
"--stop-exit-codes",
|