@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/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 import_node_child_process2 = require("child_process");
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, entry2] of Object.entries(record)) {
141
- if (typeof entry2 !== "string") {
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] = entry2;
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((entry2) => String(entry2)) : void 0,
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/server.ts
318
- var import_node_path5 = require("path");
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/agents/acp.ts
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, import_node_child_process.spawn)(command, args, {
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((resolve5) => setImmediate(resolve5));
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
- (entry2) => entry2.type === "select" && (entry2.id === "model" || entry2.category === "model")
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((resolve5) => {
587
- child.once("exit", () => resolve5());
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.0";
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((entry2) => `${entry2 === current ? "*" : " "} ${entry2}`).join("\n");
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 import_node_fs4 = require("fs");
903
- var import_node_path4 = require("path");
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 import_node_fs3 = require("fs");
944
+ var import_node_fs4 = require("fs");
908
945
  var import_node_os2 = require("os");
909
- var import_node_path3 = require("path");
946
+ var import_node_path4 = require("path");
910
947
  function vbotHome() {
911
- return process.env.VBOT_HOME?.trim() || (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".vbot");
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, import_node_path3.join)(vbotHome(), "state");
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, import_node_path3.join)(stateDir(), `${tokenHash(token)}.json`);
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, import_node_fs3.existsSync)(path)) return null;
973
+ if (!(0, import_node_fs4.existsSync)(path)) return null;
937
974
  try {
938
- const parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
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, import_node_fs3.mkdirSync)(dir, { recursive: true });
957
- const path = (0, import_node_path3.join)(dir, `${state.tokenHash}.json`);
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, import_node_fs3.writeFileSync)(tmp, `${JSON.stringify(state, null, 2)}
996
+ (0, import_node_fs4.writeFileSync)(tmp, `${JSON.stringify(state, null, 2)}
960
997
  `, { mode: 384 });
961
- (0, import_node_fs3.renameSync)(tmp, path);
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, import_node_path4.join)(stateDir(), `${tokenHash(token)}.lock`);
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, import_node_fs4.readFileSync)(path, "utf8").trim(), 10);
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, import_node_fs4.mkdirSync)(stateDir(), { recursive: true });
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, import_node_fs4.openSync)(path, "wx");
994
- (0, import_node_fs4.writeSync)(fd, String(process.pid));
995
- (0, import_node_fs4.closeSync)(fd);
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, import_node_fs4.unlinkSync)(path);
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, import_node_fs4.existsSync)(path)) return;
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, import_node_fs4.unlinkSync)(path);
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((resolve5, reject) => {
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 resolve5();
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 ENV_BIN = "/usr/bin/env";
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, import_node_child_process2.execFileSync)(ENV_BIN, ["pm2", ...args], {
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 serverEntry() {
1410
- const cliPath = process.argv[1];
1411
- if (!cliPath) throw new Error("Cannot resolve vbot entry; run the installed binary.");
1412
- const candidate = (0, import_node_path6.join)((0, import_node_path6.dirname)(cliPath), "server.js");
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(readVersion());
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 || !hasPm2()) {
1431
- if (!options.foreground) {
1432
- console.log(
1433
- import_picocolors2.default.yellow("pm2 not found; running in the foreground. Install pm2 for background mode.")
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
- serverEntry(),
1452
+ resolveServerEntry(cliPath()),
1447
1453
  "--name",
1448
1454
  name,
1449
1455
  "--stop-exit-codes",