@agentvault/agentvault 0.14.21 → 0.14.23

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 CHANGED
@@ -46432,10 +46432,11 @@ async function handleSendRequest(parsed, channel2) {
46432
46432
  const hubAddr = channel2.resolveA2AChannelHub(parsed.channel_id);
46433
46433
  if (hubAddr) a2aTarget = hubAddr;
46434
46434
  }
46435
+ const roomId = parsed.room_id ?? channel2.lastInboundRoomId;
46435
46436
  if (a2aTarget && typeof a2aTarget === "string") {
46436
46437
  await channel2.sendToAgent(a2aTarget, text);
46437
- } else if (parsed.room_id && typeof parsed.room_id === "string") {
46438
- await channel2.sendToRoom(parsed.room_id, text, {
46438
+ } else if (roomId) {
46439
+ await channel2.sendToRoom(roomId, text, {
46439
46440
  messageType: parsed.message_type,
46440
46441
  priority: parsed.priority,
46441
46442
  metadata: parsed.metadata
@@ -46753,6 +46754,8 @@ var init_channel = __esm({
46753
46754
  _telemetryReporter = null;
46754
46755
  /** Topic ID from the most recent inbound message — used as fallback for replies. */
46755
46756
  _lastIncomingTopicId;
46757
+ /** Room ID from the most recent inbound room message — used as fallback for HTTP /send replies. */
46758
+ _lastInboundRoomId;
46756
46759
  /** Rate-limit: last resync_request timestamp per conversation (5-min cooldown). */
46757
46760
  _lastResyncRequest = /* @__PURE__ */ new Map();
46758
46761
  /** Debounce timer for server backup uploads (60s). */
@@ -46786,6 +46789,10 @@ var init_channel = __esm({
46786
46789
  get sessionCount() {
46787
46790
  return this._sessions.size;
46788
46791
  }
46792
+ /** Room ID from the most recent inbound room message (for HTTP /send fallback). */
46793
+ get lastInboundRoomId() {
46794
+ return this._lastInboundRoomId;
46795
+ }
46789
46796
  /** Returns hub addresses of all persisted A2A peer channels. */
46790
46797
  get a2aPeerAddresses() {
46791
46798
  if (!this._persisted?.a2aChannels) return [];
@@ -48691,6 +48698,7 @@ ${messageText}`;
48691
48698
  }
48692
48699
  }
48693
48700
  }
48701
+ if (!roomId) this._lastInboundRoomId = void 0;
48694
48702
  const metadata = {
48695
48703
  messageId: msgData.message_id,
48696
48704
  conversationId: convId,
@@ -49070,6 +49078,7 @@ ${messageText}`;
49070
49078
  */
49071
49079
  async _handleRoomMessage(msgData) {
49072
49080
  if (msgData.sender_device_id === this._deviceId) return;
49081
+ this._lastInboundRoomId = msgData.room_id;
49073
49082
  const convId = msgData.conversation_id ?? this._findConversationForSender(msgData.sender_device_id, msgData.room_id);
49074
49083
  if (!convId) {
49075
49084
  console.warn(
@@ -70513,265 +70522,6 @@ var init_index = __esm({
70513
70522
  }
70514
70523
  });
70515
70524
 
70516
- // src/create-agent.ts
70517
- var create_agent_exports = {};
70518
- __export(create_agent_exports, {
70519
- findNextPort: () => findNextPort,
70520
- generateWorkspaceFiles: () => generateWorkspaceFiles,
70521
- openclawHome: () => openclawHome,
70522
- readOpenClawConfig: () => readOpenClawConfig,
70523
- runCreateCommand: () => runCreateCommand
70524
- });
70525
- import { execSync } from "node:child_process";
70526
- import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from "node:fs";
70527
- import { join as join4 } from "node:path";
70528
- function openclawHome() {
70529
- const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
70530
- return join4(home, ".openclaw");
70531
- }
70532
- function readOpenClawConfig(home) {
70533
- const configPath = join4(home, "openclaw.json");
70534
- const raw = readFileSync(configPath, "utf-8");
70535
- return JSON.parse(raw);
70536
- }
70537
- function writeOpenClawConfig(home, config2, backupSuffix) {
70538
- const configPath = join4(home, "openclaw.json");
70539
- const backupPath = `${configPath}.bak.pre-${backupSuffix}`;
70540
- copyFileSync(configPath, backupPath);
70541
- writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
70542
- }
70543
- function collectPorts(config2) {
70544
- const ports = [];
70545
- const accounts = config2?.channels?.agentvault?.accounts;
70546
- if (accounts && typeof accounts === "object") {
70547
- for (const acct of Object.values(accounts)) {
70548
- if (typeof acct.httpPort === "number") {
70549
- ports.push(acct.httpPort);
70550
- }
70551
- }
70552
- }
70553
- return ports;
70554
- }
70555
- function findNextPort(config2, startPort = 18800) {
70556
- const ports = collectPorts(config2);
70557
- if (ports.length === 0) return startPort;
70558
- return Math.max(...ports, startPort - 1) + 1;
70559
- }
70560
- function isPortInUse(config2, port) {
70561
- return collectPorts(config2).includes(port);
70562
- }
70563
- function generateWorkspaceFiles(name2) {
70564
- const displayName = name2.charAt(0).toUpperCase() + name2.slice(1).toLowerCase();
70565
- return {
70566
- "IDENTITY.md": `# IDENTITY.md - Who Am I?
70567
-
70568
- - **Name:** ${displayName}
70569
- - **Creature:** AI assistant \u2014 a capable peer agent in the AgentVault network
70570
- - **Vibe:** Direct, competent, focused on their specialty domain
70571
- - **Emoji:** (placeholder \u2014 update to something fitting)
70572
- - **Avatar:** _(none set yet)_
70573
-
70574
- > TODO: Customize this file to give ${name2} a distinct identity.
70575
- `,
70576
- "SOUL.md": `# SOUL.md - Who You Are
70577
-
70578
- > TODO: Define ${name2}'s personality, tone, and behavioral rules.
70579
- > Copy and adapt from ~/.openclaw/workspace/SOUL.md as a starting point.
70580
-
70581
- ## Core Truths
70582
-
70583
- - Be genuinely helpful, not performatively helpful.
70584
- - Have opinions. Be resourceful before asking.
70585
- - Earn trust through competence.
70586
-
70587
- ## Channel Reply Rules
70588
-
70589
- - Never include reasoning or internal logic in visible replies.
70590
- - No narrating your approach before or after tool calls.
70591
- - Just deliver the answer \u2014 clean and direct.
70592
-
70593
- ## Vibe
70594
-
70595
- _(Define ${name2}'s specific personality here.)_
70596
- `,
70597
- "HEARTBEAT.md": `# Heartbeat
70598
-
70599
- - Stay available. If nothing needs attention, reply HEARTBEAT_OK.
70600
- - **Heartbeat replies are INTERNAL ONLY.** Reply with ONLY \`HEARTBEAT_OK\` when nothing needs attention.
70601
- - If something genuinely urgent needs attention, send it proactively FIRST, THEN reply HEARTBEAT_OK.
70602
- `,
70603
- "MEMORY.md": `# MEMORY.md - Long-Term Memory
70604
-
70605
- _(Empty \u2014 ${name2} starts with a clean memory. Update as the agent learns.)_
70606
- `
70607
- };
70608
- }
70609
- async function runCreateCommand(options) {
70610
- const { name: name2, token: token2, apiUrl: apiUrl2, force } = options;
70611
- const home = openclawHome();
70612
- const configPath = join4(home, "openclaw.json");
70613
- const workspaceDir = join4(home, `workspace-${name2}`);
70614
- const dataDir2 = join4(home, "agents", name2, "agentvault-data");
70615
- const templateDir = join4(home, "workspace");
70616
- console.log(`
70617
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
70618
- \u2551 AgentVault \u2014 Create New Agent \u2551
70619
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
70620
- `);
70621
- console.log(" Step 1/7 \u2014 Preflight checks...");
70622
- try {
70623
- execSync("openclaw --version", { stdio: "pipe" });
70624
- } catch {
70625
- console.error(" Error: 'openclaw' not found in PATH. Is OpenClaw installed?");
70626
- process.exit(1);
70627
- }
70628
- if (!existsSync(configPath)) {
70629
- console.error(` Error: openclaw.json not found at ${configPath}`);
70630
- process.exit(1);
70631
- }
70632
- console.log(" Preflight passed.\n");
70633
- console.log(" Step 2/7 \u2014 Detecting port...");
70634
- const config2 = readOpenClawConfig(home);
70635
- let port;
70636
- if (options.port != null) {
70637
- port = options.port;
70638
- if (isPortInUse(config2, port)) {
70639
- console.error(` Error: Port ${port} is already in use in openclaw.json.`);
70640
- process.exit(1);
70641
- }
70642
- console.log(` Using explicit port ${port}.
70643
- `);
70644
- } else {
70645
- port = findNextPort(config2);
70646
- console.log(` Auto-assigned port ${port}.
70647
- `);
70648
- }
70649
- console.log(" Step 3/7 \u2014 Creating agent with OpenClaw...");
70650
- try {
70651
- execSync(`openclaw agents add -- ${name2}`, { stdio: "pipe" });
70652
- console.log(` Agent '${name2}' created.
70653
- `);
70654
- } catch {
70655
- console.log(` Warning: 'openclaw agents add' failed \u2014 agent may already exist. Continuing.
70656
- `);
70657
- }
70658
- console.log(" Step 4/7 \u2014 Creating directories...");
70659
- mkdirSync(workspaceDir, { recursive: true });
70660
- mkdirSync(dataDir2, { recursive: true });
70661
- console.log(` Workspace: ${workspaceDir}`);
70662
- console.log(` DataDir: ${dataDir2}
70663
- `);
70664
- console.log(" Step 5/7 \u2014 Writing workspace files...");
70665
- const files = generateWorkspaceFiles(name2);
70666
- for (const [filename, content] of Object.entries(files)) {
70667
- writeFileSync(join4(workspaceDir, filename), content, "utf-8");
70668
- }
70669
- for (const copyFile of ["AGENTS.md", "USER.md"]) {
70670
- const src = join4(templateDir, copyFile);
70671
- if (existsSync(src)) {
70672
- copyFileSync(src, join4(workspaceDir, copyFile));
70673
- console.log(` Copied ${copyFile} from template workspace.`);
70674
- }
70675
- }
70676
- console.log(" Workspace files written.\n");
70677
- console.log(" Step 6/7 \u2014 Enrolling with AgentVault...\n");
70678
- await runSetupCommand({
70679
- token: token2,
70680
- name: name2,
70681
- apiUrl: apiUrl2,
70682
- dataDir: dataDir2,
70683
- accountId: name2,
70684
- force
70685
- });
70686
- console.log("\n Step 7/7 \u2014 Patching openclaw.json...");
70687
- try {
70688
- const freshConfig = readOpenClawConfig(home);
70689
- let patched = false;
70690
- const avChannel = freshConfig?.channels?.agentvault;
70691
- if (avChannel?.accounts) {
70692
- const acct = avChannel.accounts[name2];
70693
- if (acct) {
70694
- acct.httpPort = port;
70695
- patched = true;
70696
- }
70697
- }
70698
- if (avChannel) {
70699
- const bindings = avChannel.bindings;
70700
- const hasWildcard = bindings?.some(
70701
- (b2) => b2.match?.accountId === "*"
70702
- );
70703
- if (!hasWildcard) {
70704
- avChannel.bindings = [{ match: { accountId: "*" } }, ...bindings ?? []];
70705
- console.log(` Added wildcard binding (accountId: "*").`);
70706
- }
70707
- }
70708
- if (patched) {
70709
- writeOpenClawConfig(home, freshConfig, name2);
70710
- console.log(` httpPort set to ${port}.
70711
- `);
70712
- } else {
70713
- console.log(` Warning: Could not find account '${name2}' in channels.agentvault.accounts.`);
70714
- console.log(` You may need to manually set httpPort: ${port} in openclaw.json.
70715
- `);
70716
- }
70717
- } catch (err) {
70718
- console.log(` Warning: Failed to patch openclaw.json: ${err.message}
70719
- `);
70720
- }
70721
- console.log(" Verifying agent...");
70722
- try {
70723
- const http = await import("node:http");
70724
- await new Promise((resolve4) => {
70725
- const req = http.get(`http://127.0.0.1:${port}/status`, { timeout: 3e3 }, (res) => {
70726
- console.log(` Port ${port} responded (HTTP ${res.statusCode}).`);
70727
- res.resume();
70728
- resolve4();
70729
- });
70730
- req.on("error", () => {
70731
- console.log(` Port ${port} not yet responding \u2014 gateway may need a moment.`);
70732
- resolve4();
70733
- });
70734
- req.on("timeout", () => {
70735
- req.destroy();
70736
- console.log(` Port ${port} timed out \u2014 check gateway logs.`);
70737
- resolve4();
70738
- });
70739
- });
70740
- } catch {
70741
- console.log(" Verification skipped.");
70742
- }
70743
- if (process.platform === "darwin") {
70744
- const { validatePlist: validatePlist2 } = await init_doctor().then(() => doctor_exports);
70745
- const plistResult = validatePlist2();
70746
- if (plistResult.status === "stale") {
70747
- console.log(`
70748
- \u26A0\uFE0F macOS LaunchAgent plist has stale paths.
70749
- Run to diagnose and fix: npx @agentvault/agentvault doctor
70750
- `);
70751
- }
70752
- }
70753
- console.log(`
70754
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
70755
- Agent '${name2}' created successfully!
70756
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
70757
-
70758
- Workspace: ${workspaceDir}
70759
- DataDir: ${dataDir2}
70760
- HTTP Port: ${port}
70761
-
70762
- Next steps:
70763
- 1. Edit ${workspaceDir}/SOUL.md \u2014 give ${name2} a personality
70764
- 2. Edit ${workspaceDir}/IDENTITY.md \u2014 set name, emoji, vibe
70765
- 3. Approve the agent in the AgentVault app
70766
- `);
70767
- }
70768
- var init_create_agent = __esm({
70769
- async "src/create-agent.ts"() {
70770
- "use strict";
70771
- await init_setup();
70772
- }
70773
- });
70774
-
70775
70525
  // src/doctor.ts
70776
70526
  var doctor_exports = {};
70777
70527
  __export(doctor_exports, {
@@ -70789,13 +70539,13 @@ __export(doctor_exports, {
70789
70539
  runDoctorCommand: () => runDoctorCommand,
70790
70540
  validatePlist: () => validatePlist
70791
70541
  });
70792
- import { execSync as execSync2 } from "node:child_process";
70793
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, chmodSync } from "node:fs";
70794
- import { join as join5 } from "node:path";
70542
+ import { execSync } from "node:child_process";
70543
+ import { existsSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
70544
+ import { join as join4 } from "node:path";
70795
70545
  import { createInterface } from "node:readline";
70796
70546
  function checkOpenClawInstalled() {
70797
70547
  try {
70798
- const out = execSync2("openclaw --version", { stdio: "pipe", timeout: 1e4 });
70548
+ const out = execSync("openclaw --version", { stdio: "pipe", timeout: 1e4 });
70799
70549
  const version2 = out.toString().trim();
70800
70550
  return { name: "OpenClaw installed", status: "pass", message: version2 };
70801
70551
  } catch {
@@ -70807,8 +70557,8 @@ function checkOpenClawInstalled() {
70807
70557
  }
70808
70558
  }
70809
70559
  function checkConfigExists(home) {
70810
- const configPath = join5(home, "openclaw.json");
70811
- if (!existsSync2(configPath)) {
70560
+ const configPath = join4(home, "openclaw.json");
70561
+ if (!existsSync(configPath)) {
70812
70562
  return {
70813
70563
  name: "Config exists",
70814
70564
  status: "fail",
@@ -70816,7 +70566,7 @@ function checkConfigExists(home) {
70816
70566
  };
70817
70567
  }
70818
70568
  try {
70819
- JSON.parse(readFileSync2(configPath, "utf-8"));
70569
+ JSON.parse(readFileSync(configPath, "utf-8"));
70820
70570
  return { name: "Config exists", status: "pass", message: configPath };
70821
70571
  } catch {
70822
70572
  return {
@@ -70892,7 +70642,7 @@ function checkPlist() {
70892
70642
  }
70893
70643
  function checkGatewayPort() {
70894
70644
  try {
70895
- execSync2("curl -sf --max-time 3 http://127.0.0.1:18789/", { stdio: "pipe" });
70645
+ execSync("curl -sf --max-time 3 http://127.0.0.1:18789/", { stdio: "pipe" });
70896
70646
  return { name: "Gateway port (18789)", status: "pass", message: "Responding" };
70897
70647
  } catch {
70898
70648
  return {
@@ -70914,12 +70664,12 @@ function checkAgentDataDirs(config2) {
70914
70664
  }
70915
70665
  const checkDir = (label, dataDir2) => {
70916
70666
  const resolved = dataDir2.replace(/^~/, home);
70917
- if (!existsSync2(resolved)) {
70667
+ if (!existsSync(resolved)) {
70918
70668
  warnings.push(`${label}: dir missing (${resolved})`);
70919
70669
  return;
70920
70670
  }
70921
- const statePath2 = join5(resolved, "agentvault.json");
70922
- if (!existsSync2(statePath2)) {
70671
+ const statePath2 = join4(resolved, "agentvault.json");
70672
+ if (!existsSync(statePath2)) {
70923
70673
  warnings.push(`${label}: no agentvault.json`);
70924
70674
  }
70925
70675
  };
@@ -70937,12 +70687,12 @@ function checkAgentDataDirs(config2) {
70937
70687
  }
70938
70688
  function checkPm2Status() {
70939
70689
  try {
70940
- execSync2("pm2 --version", { stdio: "pipe", timeout: 5e3 });
70690
+ execSync("pm2 --version", { stdio: "pipe", timeout: 5e3 });
70941
70691
  } catch {
70942
70692
  return { name: "pm2 status", status: "skip", message: "pm2 not installed" };
70943
70693
  }
70944
70694
  try {
70945
- const info = execSync2("pm2 describe openclaw-gateway", { stdio: "pipe", timeout: 5e3 });
70695
+ const info = execSync("pm2 describe openclaw-gateway", { stdio: "pipe", timeout: 5e3 });
70946
70696
  const out = info.toString();
70947
70697
  if (out.includes("online")) {
70948
70698
  return { name: "pm2 status", status: "pass", message: "openclaw-gateway: online" };
@@ -70957,22 +70707,22 @@ function checkPm2Status() {
70957
70707
  }
70958
70708
  function plistPath() {
70959
70709
  const home = process.env.HOME ?? "";
70960
- return join5(home, "Library", "LaunchAgents", PLIST_FILENAME);
70710
+ return join4(home, "Library", "LaunchAgents", PLIST_FILENAME);
70961
70711
  }
70962
70712
  function parsePlist(plistFile) {
70963
- if (!existsSync2(plistFile)) return null;
70713
+ if (!existsSync(plistFile)) return null;
70964
70714
  try {
70965
- const json2 = execSync2(`plutil -convert json -o - "${plistFile}"`, {
70715
+ const json2 = execSync(`plutil -convert json -o - "${plistFile}"`, {
70966
70716
  stdio: "pipe",
70967
70717
  timeout: 5e3
70968
70718
  }).toString();
70969
70719
  const parsed = JSON.parse(json2);
70970
70720
  const programArgs = parsed.ProgramArguments ?? [];
70971
70721
  const stalePaths = [];
70972
- const wrapperPath = join5(process.env.HOME ?? "", ".openclaw", WRAPPER_SCRIPT_NAME);
70722
+ const wrapperPath = join4(process.env.HOME ?? "", ".openclaw", WRAPPER_SCRIPT_NAME);
70973
70723
  for (const arg of programArgs) {
70974
70724
  if (arg.startsWith("/") && arg !== "/bin/bash" && arg !== wrapperPath) {
70975
- if (!existsSync2(arg)) {
70725
+ if (!existsSync(arg)) {
70976
70726
  stalePaths.push(arg);
70977
70727
  }
70978
70728
  }
@@ -70987,7 +70737,7 @@ function validatePlist() {
70987
70737
  return { status: "skip" };
70988
70738
  }
70989
70739
  const path = plistPath();
70990
- if (!existsSync2(path)) {
70740
+ if (!existsSync(path)) {
70991
70741
  return { status: "missing", plistPath: path };
70992
70742
  }
70993
70743
  const info = parsePlist(path);
@@ -70995,7 +70745,7 @@ function validatePlist() {
70995
70745
  return { status: "missing", plistPath: path };
70996
70746
  }
70997
70747
  const home = process.env.HOME ?? "";
70998
- const wrapperPath = join5(home, ".openclaw", WRAPPER_SCRIPT_NAME);
70748
+ const wrapperPath = join4(home, ".openclaw", WRAPPER_SCRIPT_NAME);
70999
70749
  if (info.programArgs.includes(wrapperPath)) {
71000
70750
  return { status: "already-fixed", plistPath: path };
71001
70751
  }
@@ -71006,14 +70756,14 @@ function validatePlist() {
71006
70756
  }
71007
70757
  function applyPlistFix(info) {
71008
70758
  const home = process.env.HOME ?? "";
71009
- const openclawDir = join5(home, ".openclaw");
71010
- const wrapperPath = join5(openclawDir, WRAPPER_SCRIPT_NAME);
70759
+ const openclawDir = join4(home, ".openclaw");
70760
+ const wrapperPath = join4(openclawDir, WRAPPER_SCRIPT_NAME);
71011
70761
  const wrapperContent = `#!/bin/bash
71012
70762
  export PATH="$HOME/.local/bin:$HOME/.pnpm/bin:$HOME/Library/pnpm/bin:$HOME/Library/pnpm:/opt/homebrew/bin:/usr/local/bin:$PATH"
71013
70763
  exec "$(which openclaw)" gateway start "$@"
71014
70764
  `;
71015
70765
  try {
71016
- writeFileSync2(wrapperPath, wrapperContent, "utf-8");
70766
+ writeFileSync(wrapperPath, wrapperContent, "utf-8");
71017
70767
  chmodSync(wrapperPath, 493);
71018
70768
  console.log(` Created wrapper: ${wrapperPath}`);
71019
70769
  } catch (err) {
@@ -71023,16 +70773,16 @@ exec "$(which openclaw)" gateway start "$@"
71023
70773
  const plistBuddy = "/usr/libexec/PlistBuddy";
71024
70774
  const plist = info.plistPath;
71025
70775
  try {
71026
- execSync2(`${plistBuddy} -c "Set :ProgramArguments:0 /bin/bash" "${plist}"`, { stdio: "pipe" });
70776
+ execSync(`${plistBuddy} -c "Set :ProgramArguments:0 /bin/bash" "${plist}"`, { stdio: "pipe" });
71027
70777
  try {
71028
- execSync2(`${plistBuddy} -c "Set :ProgramArguments:1 ${wrapperPath}" "${plist}"`, { stdio: "pipe" });
70778
+ execSync(`${plistBuddy} -c "Set :ProgramArguments:1 ${wrapperPath}" "${plist}"`, { stdio: "pipe" });
71029
70779
  } catch {
71030
- execSync2(`${plistBuddy} -c "Add :ProgramArguments:1 string ${wrapperPath}" "${plist}"`, { stdio: "pipe" });
70780
+ execSync(`${plistBuddy} -c "Add :ProgramArguments:1 string ${wrapperPath}" "${plist}"`, { stdio: "pipe" });
71031
70781
  }
71032
70782
  let argCount = info.programArgs.length;
71033
70783
  for (let i2 = argCount - 1; i2 >= 2; i2--) {
71034
70784
  try {
71035
- execSync2(`${plistBuddy} -c "Delete :ProgramArguments:${i2}" "${plist}"`, { stdio: "pipe" });
70785
+ execSync(`${plistBuddy} -c "Delete :ProgramArguments:${i2}" "${plist}"`, { stdio: "pipe" });
71036
70786
  } catch {
71037
70787
  }
71038
70788
  }
@@ -71042,11 +70792,11 @@ exec "$(which openclaw)" gateway start "$@"
71042
70792
  return false;
71043
70793
  }
71044
70794
  try {
71045
- execSync2(`launchctl unload "${plist}"`, { stdio: "pipe" });
70795
+ execSync(`launchctl unload "${plist}"`, { stdio: "pipe" });
71046
70796
  } catch {
71047
70797
  }
71048
70798
  try {
71049
- execSync2(`launchctl load "${plist}"`, { stdio: "pipe" });
70799
+ execSync(`launchctl load "${plist}"`, { stdio: "pipe" });
71050
70800
  console.log(" Reloaded LaunchAgent.");
71051
70801
  } catch (err) {
71052
70802
  console.error(` Failed to reload LaunchAgent: ${err.message}`);
@@ -71151,11 +70901,304 @@ var init_doctor = __esm({
71151
70901
  }
71152
70902
  });
71153
70903
 
71154
- // src/setup.ts
71155
- var setup_exports = {};
71156
- __export(setup_exports, {
71157
- configurePm2: () => configurePm2,
71158
- installPlugin: () => installPlugin,
70904
+ // src/create-agent.ts
70905
+ var create_agent_exports = {};
70906
+ __export(create_agent_exports, {
70907
+ findNextPort: () => findNextPort,
70908
+ generateWorkspaceFiles: () => generateWorkspaceFiles,
70909
+ openclawHome: () => openclawHome,
70910
+ readOpenClawConfig: () => readOpenClawConfig,
70911
+ runCreateCommand: () => runCreateCommand
70912
+ });
70913
+ import { execSync as execSync2 } from "node:child_process";
70914
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2, copyFileSync } from "node:fs";
70915
+ import { join as join5 } from "node:path";
70916
+ function openclawHome() {
70917
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
70918
+ return join5(home, ".openclaw");
70919
+ }
70920
+ function readOpenClawConfig(home) {
70921
+ const configPath = join5(home, "openclaw.json");
70922
+ const raw = readFileSync2(configPath, "utf-8");
70923
+ return JSON.parse(raw);
70924
+ }
70925
+ function writeOpenClawConfig(home, config2, backupSuffix) {
70926
+ const configPath = join5(home, "openclaw.json");
70927
+ const backupPath = `${configPath}.bak.pre-${backupSuffix}`;
70928
+ copyFileSync(configPath, backupPath);
70929
+ writeFileSync2(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
70930
+ }
70931
+ function collectPorts(config2) {
70932
+ const ports = [];
70933
+ const accounts = config2?.channels?.agentvault?.accounts;
70934
+ if (accounts && typeof accounts === "object") {
70935
+ for (const acct of Object.values(accounts)) {
70936
+ if (typeof acct.httpPort === "number") {
70937
+ ports.push(acct.httpPort);
70938
+ }
70939
+ }
70940
+ }
70941
+ return ports;
70942
+ }
70943
+ function findNextPort(config2, startPort = 18800) {
70944
+ const ports = collectPorts(config2);
70945
+ if (ports.length === 0) return startPort;
70946
+ return Math.max(...ports, startPort - 1) + 1;
70947
+ }
70948
+ function isPortInUse(config2, port) {
70949
+ return collectPorts(config2).includes(port);
70950
+ }
70951
+ function generateWorkspaceFiles(name2) {
70952
+ const displayName = name2.charAt(0).toUpperCase() + name2.slice(1).toLowerCase();
70953
+ return {
70954
+ "IDENTITY.md": `# IDENTITY.md - Who Am I?
70955
+
70956
+ - **Name:** ${displayName}
70957
+ - **Creature:** AI assistant \u2014 a capable peer agent in the AgentVault network
70958
+ - **Vibe:** Direct, competent, focused on their specialty domain
70959
+ - **Emoji:** (placeholder \u2014 update to something fitting)
70960
+ - **Avatar:** _(none set yet)_
70961
+
70962
+ > TODO: Customize this file to give ${name2} a distinct identity.
70963
+ `,
70964
+ "SOUL.md": `# SOUL.md - Who You Are
70965
+
70966
+ > TODO: Define ${name2}'s personality, tone, and behavioral rules.
70967
+ > Copy and adapt from ~/.openclaw/workspace/SOUL.md as a starting point.
70968
+
70969
+ ## Core Truths
70970
+
70971
+ - Be genuinely helpful, not performatively helpful.
70972
+ - Have opinions. Be resourceful before asking.
70973
+ - Earn trust through competence.
70974
+
70975
+ ## Channel Reply Rules
70976
+
70977
+ - Never include reasoning or internal logic in visible replies.
70978
+ - No narrating your approach before or after tool calls.
70979
+ - Just deliver the answer \u2014 clean and direct.
70980
+
70981
+ ## Vibe
70982
+
70983
+ _(Define ${name2}'s specific personality here.)_
70984
+ `,
70985
+ "HEARTBEAT.md": `# Heartbeat
70986
+
70987
+ - Stay available. If nothing needs attention, reply HEARTBEAT_OK.
70988
+ - **Heartbeat replies are INTERNAL ONLY.** Reply with ONLY \`HEARTBEAT_OK\` when nothing needs attention.
70989
+ - If something genuinely urgent needs attention, send it proactively FIRST, THEN reply HEARTBEAT_OK.
70990
+ `,
70991
+ "MEMORY.md": `# MEMORY.md - Long-Term Memory
70992
+
70993
+ _(Empty \u2014 ${name2} starts with a clean memory. Update as the agent learns.)_
70994
+ `
70995
+ };
70996
+ }
70997
+ async function runCreateCommand(options) {
70998
+ const { name: name2, token: token2, apiUrl: apiUrl2, force } = options;
70999
+ const home = openclawHome();
71000
+ const configPath = join5(home, "openclaw.json");
71001
+ const workspaceDir = join5(home, `workspace-${name2}`);
71002
+ const dataDir2 = join5(home, "agents", name2, "agentvault-data");
71003
+ const templateDir = join5(home, "workspace");
71004
+ console.log(`
71005
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
71006
+ \u2551 AgentVault \u2014 Create New Agent \u2551
71007
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
71008
+ `);
71009
+ console.log(" Step 1/7 \u2014 Preflight checks...");
71010
+ try {
71011
+ execSync2("openclaw --version", { stdio: "pipe" });
71012
+ } catch {
71013
+ console.error(" Error: 'openclaw' not found in PATH. Is OpenClaw installed?");
71014
+ process.exit(1);
71015
+ }
71016
+ if (!existsSync2(configPath)) {
71017
+ console.error(` Error: openclaw.json not found at ${configPath}`);
71018
+ process.exit(1);
71019
+ }
71020
+ console.log(" Preflight passed.\n");
71021
+ console.log(" Step 2/7 \u2014 Detecting port...");
71022
+ const config2 = readOpenClawConfig(home);
71023
+ let port;
71024
+ if (options.port != null) {
71025
+ port = options.port;
71026
+ if (isPortInUse(config2, port)) {
71027
+ console.error(` Error: Port ${port} is already in use in openclaw.json.`);
71028
+ process.exit(1);
71029
+ }
71030
+ console.log(` Using explicit port ${port}.
71031
+ `);
71032
+ } else {
71033
+ port = findNextPort(config2);
71034
+ console.log(` Auto-assigned port ${port}.
71035
+ `);
71036
+ }
71037
+ console.log(" Step 3/7 \u2014 Creating agent with OpenClaw...");
71038
+ try {
71039
+ execSync2(`openclaw agents add -- ${name2}`, { stdio: "pipe" });
71040
+ console.log(` Agent '${name2}' created.
71041
+ `);
71042
+ } catch {
71043
+ console.log(` Warning: 'openclaw agents add' failed \u2014 agent may already exist. Continuing.
71044
+ `);
71045
+ }
71046
+ console.log(" Step 4/7 \u2014 Creating directories...");
71047
+ mkdirSync(workspaceDir, { recursive: true });
71048
+ mkdirSync(dataDir2, { recursive: true });
71049
+ console.log(` Workspace: ${workspaceDir}`);
71050
+ console.log(` DataDir: ${dataDir2}
71051
+ `);
71052
+ console.log(" Step 5/7 \u2014 Writing workspace files...");
71053
+ const files = generateWorkspaceFiles(name2);
71054
+ for (const [filename, content] of Object.entries(files)) {
71055
+ writeFileSync2(join5(workspaceDir, filename), content, "utf-8");
71056
+ }
71057
+ for (const copyFile of ["AGENTS.md", "USER.md"]) {
71058
+ const src = join5(templateDir, copyFile);
71059
+ if (existsSync2(src)) {
71060
+ copyFileSync(src, join5(workspaceDir, copyFile));
71061
+ console.log(` Copied ${copyFile} from template workspace.`);
71062
+ }
71063
+ }
71064
+ console.log(" Workspace files written.\n");
71065
+ console.log(" Step 6/7 \u2014 Enrolling with AgentVault...\n");
71066
+ await runSetupCommand({
71067
+ token: token2,
71068
+ name: name2,
71069
+ apiUrl: apiUrl2,
71070
+ dataDir: dataDir2,
71071
+ accountId: name2,
71072
+ force
71073
+ });
71074
+ console.log("\n Step 7/7 \u2014 Patching openclaw.json...");
71075
+ try {
71076
+ const freshConfig = readOpenClawConfig(home);
71077
+ let patched = false;
71078
+ const avChannel = freshConfig?.channels?.agentvault;
71079
+ if (avChannel?.accounts) {
71080
+ const acct = avChannel.accounts[name2];
71081
+ if (acct) {
71082
+ acct.httpPort = port;
71083
+ patched = true;
71084
+ }
71085
+ }
71086
+ if (avChannel) {
71087
+ const channelBindings = avChannel.bindings;
71088
+ const hasAccountBinding = channelBindings?.some(
71089
+ (b2) => b2.match?.accountId === name2
71090
+ );
71091
+ if (!hasAccountBinding) {
71092
+ const arr = channelBindings ?? [];
71093
+ const wildcardIdx = arr.findIndex((b2) => b2.match?.accountId === "*");
71094
+ const entry = { match: { accountId: name2 } };
71095
+ if (wildcardIdx >= 0) {
71096
+ arr.splice(wildcardIdx, 0, entry);
71097
+ } else {
71098
+ arr.push(entry);
71099
+ }
71100
+ avChannel.bindings = arr;
71101
+ patched = true;
71102
+ console.log(` Added channel binding for account "${name2}".`);
71103
+ }
71104
+ const hasWildcard = avChannel.bindings.some(
71105
+ (b2) => b2.match?.accountId === "*"
71106
+ );
71107
+ if (!hasWildcard) {
71108
+ avChannel.bindings.push({ match: { accountId: "*" } });
71109
+ patched = true;
71110
+ console.log(` Added wildcard channel binding (accountId: "*").`);
71111
+ }
71112
+ }
71113
+ const topBindings = freshConfig.bindings;
71114
+ const hasTopBinding = topBindings?.some(
71115
+ (b2) => b2.agentId === name2 && b2.match?.accountId === name2
71116
+ );
71117
+ if (!hasTopBinding) {
71118
+ const entry = {
71119
+ agentId: name2,
71120
+ match: { channel: "agentvault", accountId: name2 }
71121
+ };
71122
+ if (topBindings) {
71123
+ topBindings.push(entry);
71124
+ } else {
71125
+ freshConfig.bindings = [entry];
71126
+ }
71127
+ patched = true;
71128
+ console.log(` Added top-level binding: ${name2} \u2192 agentvault:${name2}.`);
71129
+ }
71130
+ if (patched) {
71131
+ writeOpenClawConfig(home, freshConfig, name2);
71132
+ console.log(` httpPort set to ${port}.
71133
+ `);
71134
+ } else {
71135
+ console.log(` Warning: Could not find account '${name2}' in channels.agentvault.accounts.`);
71136
+ console.log(` You may need to manually set httpPort: ${port} in openclaw.json.
71137
+ `);
71138
+ }
71139
+ } catch (err) {
71140
+ console.log(` Warning: Failed to patch openclaw.json: ${err.message}
71141
+ `);
71142
+ }
71143
+ console.log(" Verifying agent...");
71144
+ try {
71145
+ const http = await import("node:http");
71146
+ await new Promise((resolve4) => {
71147
+ const req = http.get(`http://127.0.0.1:${port}/status`, { timeout: 3e3 }, (res) => {
71148
+ console.log(` Port ${port} responded (HTTP ${res.statusCode}).`);
71149
+ res.resume();
71150
+ resolve4();
71151
+ });
71152
+ req.on("error", () => {
71153
+ console.log(` Port ${port} not yet responding \u2014 gateway may need a moment.`);
71154
+ resolve4();
71155
+ });
71156
+ req.on("timeout", () => {
71157
+ req.destroy();
71158
+ console.log(` Port ${port} timed out \u2014 check gateway logs.`);
71159
+ resolve4();
71160
+ });
71161
+ });
71162
+ } catch {
71163
+ console.log(" Verification skipped.");
71164
+ }
71165
+ if (process.platform === "darwin") {
71166
+ const { validatePlist: validatePlist2 } = await init_doctor().then(() => doctor_exports);
71167
+ const plistResult = validatePlist2();
71168
+ if (plistResult.status === "stale") {
71169
+ console.log(`
71170
+ \u26A0\uFE0F macOS LaunchAgent plist has stale paths.
71171
+ Run to diagnose and fix: npx @agentvault/agentvault doctor
71172
+ `);
71173
+ }
71174
+ }
71175
+ console.log(`
71176
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
71177
+ Agent '${name2}' created successfully!
71178
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
71179
+
71180
+ Workspace: ${workspaceDir}
71181
+ DataDir: ${dataDir2}
71182
+ HTTP Port: ${port}
71183
+
71184
+ Next steps:
71185
+ 1. Edit ${workspaceDir}/SOUL.md \u2014 give ${name2} a personality
71186
+ 2. Edit ${workspaceDir}/IDENTITY.md \u2014 set name, emoji, vibe
71187
+ 3. Approve the agent in the AgentVault app
71188
+ `);
71189
+ }
71190
+ var init_create_agent = __esm({
71191
+ async "src/create-agent.ts"() {
71192
+ "use strict";
71193
+ await init_setup();
71194
+ }
71195
+ });
71196
+
71197
+ // src/setup.ts
71198
+ var setup_exports = {};
71199
+ __export(setup_exports, {
71200
+ configurePm2: () => configurePm2,
71201
+ installPlugin: () => installPlugin,
71159
71202
  runSetupCommand: () => runSetupCommand
71160
71203
  });
71161
71204
  import { execSync as execSync3, spawnSync } from "node:child_process";
@@ -71329,27 +71372,53 @@ async function runSetupCommand(options) {
71329
71372
  break;
71330
71373
  }
71331
71374
  }
71332
- if (configPatched) {
71375
+ if (configPatched && options.accountId) {
71333
71376
  try {
71334
- const raw = execSync3("openclaw config get channels.agentvault.bindings", {
71335
- stdio: "pipe",
71336
- env
71337
- }).toString().trim();
71338
- const hasWildcard = raw.includes('"*"') || raw.includes("'*'");
71339
- if (!hasWildcard) {
71340
- execSync3(
71341
- `openclaw config set channels.agentvault.bindings '[{"match":{"accountId":"*"}}]'`,
71342
- { stdio: "pipe", env }
71343
- );
71377
+ const { readOpenClawConfig: readOpenClawConfig2 } = await init_create_agent().then(() => create_agent_exports);
71378
+ const home2 = process.env.HOME ?? "";
71379
+ const ocHome = `${home2}/.openclaw`;
71380
+ const fs = await import("node:fs");
71381
+ const path = await import("node:path");
71382
+ const configPath = path.join(ocHome, "openclaw.json");
71383
+ if (fs.existsSync(configPath)) {
71384
+ const raw = fs.readFileSync(configPath, "utf-8");
71385
+ const cfg = JSON.parse(raw);
71386
+ let changed = false;
71387
+ const avChannel = cfg?.channels?.agentvault;
71388
+ if (avChannel) {
71389
+ const channelBindings = avChannel.bindings ?? [];
71390
+ if (!channelBindings.some((b2) => b2.match?.accountId === options.accountId)) {
71391
+ const wildcardIdx = channelBindings.findIndex((b2) => b2.match?.accountId === "*");
71392
+ const entry = { match: { accountId: options.accountId } };
71393
+ if (wildcardIdx >= 0) {
71394
+ channelBindings.splice(wildcardIdx, 0, entry);
71395
+ } else {
71396
+ channelBindings.push(entry);
71397
+ }
71398
+ avChannel.bindings = channelBindings;
71399
+ changed = true;
71400
+ }
71401
+ if (!channelBindings.some((b2) => b2.match?.accountId === "*")) {
71402
+ channelBindings.push({ match: { accountId: "*" } });
71403
+ changed = true;
71404
+ }
71405
+ }
71406
+ const topBindings = cfg.bindings ?? [];
71407
+ if (!topBindings.some((b2) => b2.agentId === options.accountId && b2.match?.accountId === options.accountId)) {
71408
+ topBindings.push({
71409
+ agentId: options.accountId,
71410
+ match: { channel: "agentvault", accountId: options.accountId }
71411
+ });
71412
+ cfg.bindings = topBindings;
71413
+ changed = true;
71414
+ }
71415
+ if (changed) {
71416
+ const backupPath = `${configPath}.bak.pre-setup-${options.accountId}`;
71417
+ fs.copyFileSync(configPath, backupPath);
71418
+ fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
71419
+ }
71344
71420
  }
71345
71421
  } catch {
71346
- try {
71347
- execSync3(
71348
- `openclaw config set channels.agentvault.bindings '[{"match":{"accountId":"*"}}]'`,
71349
- { stdio: "pipe", env }
71350
- );
71351
- } catch {
71352
- }
71353
71422
  }
71354
71423
  }
71355
71424
  if (configPatched) {