agentbnb 8.4.1 → 8.4.3

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.
@@ -4,7 +4,7 @@ import {
4
4
  decompose,
5
5
  matchSubTasks,
6
6
  orchestrate
7
- } from "./chunk-UF6R2RVN.js";
7
+ } from "./chunk-SME5LJTE.js";
8
8
  import {
9
9
  BudgetManager
10
10
  } from "./chunk-AZKVGC5T.js";
@@ -39,6 +39,7 @@ import { randomUUID } from "crypto";
39
39
  async function requestViaTemporaryRelay(opts) {
40
40
  const {
41
41
  registryUrl,
42
+ agent_id,
42
43
  owner,
43
44
  token,
44
45
  targetOwner,
@@ -48,7 +49,8 @@ async function requestViaTemporaryRelay(opts) {
48
49
  params,
49
50
  timeoutMs = 3e5
50
51
  } = opts;
51
- const requesterId = `${owner}:req:${randomUUID()}`;
52
+ const requesterIdentity = agent_id ?? owner ?? "";
53
+ const requesterId = `${requesterIdentity}:req:${randomUUID()}`;
52
54
  const relay = new RelayClient({
53
55
  registryUrl,
54
56
  owner: requesterId,
@@ -84,8 +86,8 @@ async function requestViaTemporaryRelay(opts) {
84
86
  cardId,
85
87
  skillId,
86
88
  params,
87
- requester: owner,
88
- // actual owner for credit tracking on relay server
89
+ requester: requesterIdentity,
90
+ // canonical identity for relay credit tracking
89
91
  timeoutMs
90
92
  });
91
93
  } finally {
@@ -273,6 +273,7 @@ import { randomUUID as randomUUID2 } from "crypto";
273
273
  async function requestViaTemporaryRelay(opts) {
274
274
  const {
275
275
  registryUrl,
276
+ agent_id,
276
277
  owner,
277
278
  token,
278
279
  targetOwner,
@@ -282,7 +283,8 @@ async function requestViaTemporaryRelay(opts) {
282
283
  params,
283
284
  timeoutMs = 3e5
284
285
  } = opts;
285
- const requesterId = `${owner}:req:${randomUUID2()}`;
286
+ const requesterIdentity = agent_id ?? owner ?? "";
287
+ const requesterId = `${requesterIdentity}:req:${randomUUID2()}`;
286
288
  const relay = new RelayClient({
287
289
  registryUrl,
288
290
  owner: requesterId,
@@ -318,8 +320,8 @@ async function requestViaTemporaryRelay(opts) {
318
320
  cardId,
319
321
  skillId,
320
322
  params,
321
- requester: owner,
322
- // actual owner for credit tracking on relay server
323
+ requester: requesterIdentity,
324
+ // canonical identity for relay credit tracking
323
325
  timeoutMs
324
326
  });
325
327
  } finally {
@@ -1,6 +1,6 @@
1
1
  // src/workspace/scanner.ts
2
2
  import { existsSync, readdirSync, readFileSync } from "fs";
3
- import { join } from "path";
3
+ import { join, dirname } from "path";
4
4
  import { homedir } from "os";
5
5
  function heuristicPrice(skillName) {
6
6
  const lower = skillName.toLowerCase();
@@ -48,9 +48,52 @@ function countSkills(brainDir) {
48
48
  return 0;
49
49
  }
50
50
  }
51
+ function getOpenClawWorkspaceDir() {
52
+ const openclawDir = join(homedir(), ".openclaw");
53
+ const configPath = join(openclawDir, "openclaw.json");
54
+ if (existsSync(configPath)) {
55
+ try {
56
+ const raw = readFileSync(configPath, "utf-8");
57
+ const config = JSON.parse(raw);
58
+ const agents = config["agents"];
59
+ const defaults = agents?.["defaults"];
60
+ const workspace = defaults?.["workspace"];
61
+ if (typeof workspace === "string" && workspace.length > 0) {
62
+ return workspace;
63
+ }
64
+ } catch {
65
+ }
66
+ }
67
+ const profile = process.env["OPENCLAW_PROFILE"];
68
+ if (profile && profile !== "default") {
69
+ return join(openclawDir, `workspace-${profile}`);
70
+ }
71
+ return join(openclawDir, "workspace");
72
+ }
73
+ function findSoulMd(agentName) {
74
+ const openclawDir = join(homedir(), ".openclaw");
75
+ const workspaceDir = getOpenClawWorkspaceDir();
76
+ const candidates = [
77
+ // Priority 1: brains directory (multi-agent)
78
+ join(workspaceDir, "brains", agentName, "SOUL.md"),
79
+ // Priority 2: agents directory (legacy)
80
+ join(openclawDir, "agents", agentName, "SOUL.md"),
81
+ // Priority 3: workspace root (single-agent or "main")
82
+ join(workspaceDir, "SOUL.md")
83
+ ];
84
+ for (const candidate of candidates) {
85
+ if (existsSync(candidate)) return candidate;
86
+ }
87
+ return null;
88
+ }
89
+ function inferBrainDir(soulPath, agentDir) {
90
+ const soulDir = dirname(soulPath);
91
+ return soulDir === agentDir ? "" : soulDir;
92
+ }
51
93
  function scanAgents() {
52
94
  const openclawDir = join(homedir(), ".openclaw");
53
- const brainsDir = join(openclawDir, "workspace", "brains");
95
+ const workspaceDir = getOpenClawWorkspaceDir();
96
+ const brainsDir = join(workspaceDir, "brains");
54
97
  const agentsDir = join(openclawDir, "agents");
55
98
  const results = [];
56
99
  const seenNames = /* @__PURE__ */ new Set();
@@ -88,6 +131,19 @@ function scanAgents() {
88
131
  seenNames.add(name);
89
132
  }
90
133
  }
134
+ const rootSoul = join(workspaceDir, "SOUL.md");
135
+ if (existsSync(rootSoul) && !seenNames.has("main")) {
136
+ const description = firstParagraph(readFileSync(rootSoul, "utf-8"));
137
+ results.push({
138
+ name: "main",
139
+ description,
140
+ skillCount: countSkills(workspaceDir),
141
+ channel: readChannel(agentsDir, "main"),
142
+ brainDir: workspaceDir,
143
+ agentbnbDir: join(agentsDir, "main", ".agentbnb")
144
+ });
145
+ seenNames.add("main");
146
+ }
91
147
  return results.sort((a, b) => a.name.localeCompare(b.name));
92
148
  }
93
149
  function parseCapabilitiesFromSoul(soulContent) {
@@ -166,8 +222,49 @@ function scanCapabilities(brainDir) {
166
222
  }
167
223
  return results;
168
224
  }
225
+ function scanWorkspaceSkills() {
226
+ const workspaceDir = getOpenClawWorkspaceDir();
227
+ const skillsDir = join(workspaceDir, "skills");
228
+ const results = [];
229
+ if (!existsSync(skillsDir)) return results;
230
+ let entries;
231
+ try {
232
+ entries = readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
233
+ } catch {
234
+ return results;
235
+ }
236
+ for (const skillDirName of entries) {
237
+ const skillMdPath = join(skillsDir, skillDirName, "SKILL.md");
238
+ if (!existsSync(skillMdPath)) continue;
239
+ try {
240
+ const content = readFileSync(skillMdPath, "utf-8");
241
+ const fmMatch = /^---\n([\s\S]*?)\n---/.exec(content);
242
+ let name = skillDirName;
243
+ let description = "";
244
+ if (fmMatch) {
245
+ const fm = fmMatch[1];
246
+ const nameMatch = /^name:\s*(.+)$/m.exec(fm);
247
+ const descMatch = /^description:\s*(.+)$/m.exec(fm);
248
+ if (nameMatch) name = nameMatch[1].trim();
249
+ if (descMatch) description = descMatch[1].trim();
250
+ }
251
+ results.push({
252
+ name,
253
+ description,
254
+ source: "skill_md",
255
+ suggestedPrice: heuristicPrice(name)
256
+ });
257
+ } catch {
258
+ }
259
+ }
260
+ return results;
261
+ }
169
262
 
170
263
  export {
264
+ getOpenClawWorkspaceDir,
265
+ findSoulMd,
266
+ inferBrainDir,
171
267
  scanAgents,
172
- scanCapabilities
268
+ scanCapabilities,
269
+ scanWorkspaceSkills
173
270
  };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-3MJT4PZG.js";
4
4
  import {
5
5
  scorePeers
6
- } from "./chunk-6XCN62YU.js";
6
+ } from "./chunk-IMLFBU3H.js";
7
7
  import {
8
8
  fetchRemoteCards
9
9
  } from "./chunk-PIPCGRCR.js";
package/dist/cli/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  AutoRequestor,
11
11
  requestViaTemporaryRelay
12
- } from "../chunk-6XCN62YU.js";
12
+ } from "../chunk-IMLFBU3H.js";
13
13
  import {
14
14
  BudgetManager,
15
15
  DEFAULT_BUDGET_CONFIG
@@ -227,7 +227,7 @@ Skills: ${skills2.skillCount} skill(s) in ${skills2.path}`);
227
227
  if (!skipServe) {
228
228
  try {
229
229
  const { ProcessGuard } = await import("../process-guard-TNSUNHSR.js");
230
- const { ServiceCoordinator } = await import("../service-coordinator-R5LZVM6A.js");
230
+ const { ServiceCoordinator } = await import("../service-coordinator-2HDVHDFD.js");
231
231
  const guard = new ProcessGuard(join(initResult.configDir, ".pid"));
232
232
  const coordinator = new ServiceCoordinator(initResult.config, guard);
233
233
  const result = await coordinator.ensureRunning({
@@ -289,7 +289,7 @@ Skills: ${skills2.skillCount} skill(s) in ${skills2.path}`);
289
289
  }
290
290
 
291
291
  // src/cli/index.ts
292
- var VERSION = true ? "8.4.1" : "0.0.0-dev";
292
+ var VERSION = true ? "8.4.3" : "0.0.0-dev";
293
293
  function loadIdentityAuth(owner) {
294
294
  const configDir = getConfigDir();
295
295
  let keys;
@@ -1072,7 +1072,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
1072
1072
  process.exit(1);
1073
1073
  }
1074
1074
  const { ProcessGuard } = await import("../process-guard-TNSUNHSR.js");
1075
- const { ServiceCoordinator } = await import("../service-coordinator-R5LZVM6A.js");
1075
+ const { ServiceCoordinator } = await import("../service-coordinator-2HDVHDFD.js");
1076
1076
  const port = opts.port ? parseInt(opts.port, 10) : config.gateway_port;
1077
1077
  const registryPort = parseInt(opts.registryPort, 10);
1078
1078
  if (!Number.isFinite(port) || !Number.isFinite(registryPort)) {
@@ -1446,34 +1446,34 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
1446
1446
  }
1447
1447
  });
1448
1448
  openclaw.command("setup").description("Interactive onboarding: connect an OpenClaw agent to AgentBnB").option("--agent <name>", "Agent name to set up (skip interactive selection)").option("--soul-path <path>", "Override SOUL.md path").option("-y, --yes", "Skip confirmation prompts").action(async (opts) => {
1449
- const { runOpenClawSetup } = await import("../openclaw-setup-KA72IIEW.js");
1449
+ const { runOpenClawSetup } = await import("../openclaw-setup-LVSGMXDF.js");
1450
1450
  await runOpenClawSetup(opts);
1451
1451
  });
1452
1452
  var skills = openclaw.command("skills").description("Manage shared skills on AgentBnB");
1453
1453
  skills.command("list").description("List all shared skills with stats").action(async () => {
1454
- const { skillsList } = await import("../openclaw-skills-CT673RBL.js");
1454
+ const { skillsList } = await import("../openclaw-skills-6ZWQJ5V6.js");
1455
1455
  await skillsList({});
1456
1456
  });
1457
1457
  skills.command("add").description("Add a skill to share (interactive or --manual)").option("--manual", "Non-interactive: use flags instead of prompts").option("--name <id>", "Skill ID").option("--type <type>", "Skill type (command|openclaw)").option("--price <n>", "Credits per call", parseFloat).option("--description <text>", "Skill description").action(
1458
1458
  async (opts) => {
1459
- const { skillsAdd } = await import("../openclaw-skills-CT673RBL.js");
1459
+ const { skillsAdd } = await import("../openclaw-skills-6ZWQJ5V6.js");
1460
1460
  await skillsAdd(opts);
1461
1461
  }
1462
1462
  );
1463
1463
  skills.command("remove <skillId>").description("Remove a skill from AgentBnB").action(async (skillId) => {
1464
- const { skillsRemove } = await import("../openclaw-skills-CT673RBL.js");
1464
+ const { skillsRemove } = await import("../openclaw-skills-6ZWQJ5V6.js");
1465
1465
  await skillsRemove(skillId);
1466
1466
  });
1467
1467
  skills.command("price <skillId> <price>").description("Update skill price").action(async (skillId, price) => {
1468
- const { skillsPrice } = await import("../openclaw-skills-CT673RBL.js");
1468
+ const { skillsPrice } = await import("../openclaw-skills-6ZWQJ5V6.js");
1469
1469
  await skillsPrice(skillId, parseFloat(price));
1470
1470
  });
1471
1471
  skills.command("stats").description("Revenue and performance report").option("--days <n>", "Days to look back", parseInt, 7).action(async (opts) => {
1472
- const { skillsStats } = await import("../openclaw-skills-CT673RBL.js");
1472
+ const { skillsStats } = await import("../openclaw-skills-6ZWQJ5V6.js");
1473
1473
  await skillsStats(opts);
1474
1474
  });
1475
1475
  program.command("conduct <task>").description("Orchestrate a complex task across the AgentBnB network").option("--plan-only", "Show execution plan without executing").option("--max-budget <credits>", "Maximum credits to spend", "100").option("--json", "Output as JSON").action(async (task, opts) => {
1476
- const { conductAction } = await import("../conduct-FZPUMPCI.js");
1476
+ const { conductAction } = await import("../conduct-2RD45QKB.js");
1477
1477
  const result = await conductAction(task, opts);
1478
1478
  if (opts.json) {
1479
1479
  console.log(JSON.stringify(result, null, 2));
@@ -1585,7 +1585,7 @@ Feedback for skill: ${opts.skill} (${feedbacks.length} entries)
1585
1585
  });
1586
1586
  program.command("quickstart").alias("qs").description("One-command setup: init + skills.yaml + MCP registration + serve daemon").option("--owner <name>", "Agent owner name").option("--port <port>", "Gateway port", "7700").option("--no-serve", "Skip starting background daemon").option("--no-mcp", "Skip MCP registration with Claude Code").option("--json", "Output as JSON").action(runQuickstart);
1587
1587
  program.command("mcp-server").description("Start an MCP (Model Context Protocol) server for IDE integration").action(async () => {
1588
- const { startMcpServer } = await import("../server-MH7FTZFN.js");
1588
+ const { startMcpServer } = await import("../server-QG3FKU5Q.js");
1589
1589
  await startMcpServer();
1590
1590
  });
1591
1591
  await program.parseAsync(process.argv);
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  conductAction
3
- } from "./chunk-Z5726VPY.js";
4
- import "./chunk-UF6R2RVN.js";
3
+ } from "./chunk-EKLVNIIY.js";
4
+ import "./chunk-SME5LJTE.js";
5
5
  import "./chunk-3MJT4PZG.js";
6
- import "./chunk-6XCN62YU.js";
6
+ import "./chunk-IMLFBU3H.js";
7
7
  import "./chunk-AZKVGC5T.js";
8
8
  import "./chunk-MZSVVG55.js";
9
9
  import "./chunk-G5WKW3ED.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  conductAction
3
- } from "./chunk-Z5726VPY.js";
4
- import "./chunk-UF6R2RVN.js";
3
+ } from "./chunk-EKLVNIIY.js";
4
+ import "./chunk-SME5LJTE.js";
5
5
  import "./chunk-3MJT4PZG.js";
6
- import "./chunk-6XCN62YU.js";
6
+ import "./chunk-IMLFBU3H.js";
7
7
  import "./chunk-AZKVGC5T.js";
8
8
  import "./chunk-MZSVVG55.js";
9
9
  import "./chunk-G5WKW3ED.js";
@@ -5,7 +5,7 @@ import {
5
5
  matchSubTasks,
6
6
  orchestrate,
7
7
  validateAndNormalizeSubtasks
8
- } from "./chunk-RVBW2QXU.js";
8
+ } from "./chunk-J46N2TCC.js";
9
9
  import {
10
10
  requestCapability
11
11
  } from "./chunk-R4F4XII4.js";
@@ -4,9 +4,9 @@ import {
4
4
  matchSubTasks,
5
5
  orchestrate,
6
6
  validateAndNormalizeSubtasks
7
- } from "./chunk-UF6R2RVN.js";
7
+ } from "./chunk-SME5LJTE.js";
8
8
  import "./chunk-3MJT4PZG.js";
9
- import "./chunk-6XCN62YU.js";
9
+ import "./chunk-IMLFBU3H.js";
10
10
  import {
11
11
  BudgetManager
12
12
  } from "./chunk-AZKVGC5T.js";
package/dist/index.js CHANGED
@@ -4090,6 +4090,7 @@ var RelayClient = class {
4090
4090
  async function requestViaTemporaryRelay(opts) {
4091
4091
  const {
4092
4092
  registryUrl,
4093
+ agent_id,
4093
4094
  owner,
4094
4095
  token,
4095
4096
  targetOwner,
@@ -4099,7 +4100,8 @@ async function requestViaTemporaryRelay(opts) {
4099
4100
  params,
4100
4101
  timeoutMs = 3e5
4101
4102
  } = opts;
4102
- const requesterId = `${owner}:req:${randomUUID10()}`;
4103
+ const requesterIdentity = agent_id ?? owner ?? "";
4104
+ const requesterId = `${requesterIdentity}:req:${randomUUID10()}`;
4103
4105
  const relay = new RelayClient({
4104
4106
  registryUrl,
4105
4107
  owner: requesterId,
@@ -4135,8 +4137,8 @@ async function requestViaTemporaryRelay(opts) {
4135
4137
  cardId,
4136
4138
  skillId,
4137
4139
  params,
4138
- requester: owner,
4139
- // actual owner for credit tracking on relay server
4140
+ requester: requesterIdentity,
4141
+ // canonical identity for relay credit tracking
4140
4142
  timeoutMs
4141
4143
  });
4142
4144
  } finally {
@@ -3,8 +3,11 @@ import {
3
3
  appendSoulMdTradingSection
4
4
  } from "./chunk-WPB5LFGI.js";
5
5
  import {
6
+ findSoulMd,
7
+ getOpenClawWorkspaceDir,
8
+ inferBrainDir,
6
9
  scanAgents
7
- } from "./chunk-XGOA5J2K.js";
10
+ } from "./chunk-RJNKX347.js";
8
11
  import {
9
12
  performInit,
10
13
  publishFromSoulV2
@@ -99,8 +102,9 @@ async function runOpenClawSetup(opts) {
99
102
  }
100
103
  }
101
104
  const agentsDir = joinPath(homedir(), ".openclaw", "agents");
102
- const brainsDir = joinPath(homedir(), ".openclaw", "workspace", "brains");
103
- if (!existsSync2(agentsDir) && !existsSync2(brainsDir)) {
105
+ const workspaceDir = getOpenClawWorkspaceDir();
106
+ const brainsDir = joinPath(workspaceDir, "brains");
107
+ if (!existsSync2(agentsDir) && !existsSync2(brainsDir) && !existsSync2(workspaceDir)) {
104
108
  console.error(`Error: OpenClaw directory not found at ${agentsDir}`);
105
109
  console.error("Install OpenClaw first: https://openclaw.dev");
106
110
  process.exit(1);
@@ -109,12 +113,19 @@ async function runOpenClawSetup(opts) {
109
113
  let agentBrainDir = "";
110
114
  if (opts.agent) {
111
115
  agentName = opts.agent;
112
- agentBrainDir = existsSync2(joinPath(brainsDir, agentName)) ? joinPath(brainsDir, agentName) : "";
116
+ if (existsSync2(joinPath(brainsDir, agentName))) {
117
+ agentBrainDir = joinPath(brainsDir, agentName);
118
+ } else if (agentName === "main" && existsSync2(joinPath(workspaceDir, "SOUL.md"))) {
119
+ agentBrainDir = workspaceDir;
120
+ } else {
121
+ agentBrainDir = "";
122
+ }
113
123
  } else {
114
124
  console.log("Scanning for available agents...\n");
115
125
  const detected = scanAgents();
116
126
  if (detected.length === 0) {
117
- console.error("No agents found in ~/.openclaw/workspace/brains/ or ~/.openclaw/agents/");
127
+ console.error("No agents found in OpenClaw workspace.");
128
+ console.error(`Checked: ${brainsDir}, ${agentsDir}, ${workspaceDir}/SOUL.md`);
118
129
  process.exit(1);
119
130
  }
120
131
  console.log("Available agents:");
@@ -142,22 +153,85 @@ async function runOpenClawSetup(opts) {
142
153
  let soulPath;
143
154
  if (opts.soulPath) {
144
155
  soulPath = opts.soulPath;
145
- } else if (agentBrainDir && existsSync2(joinPath(agentBrainDir, "SOUL.md"))) {
146
- soulPath = joinPath(agentBrainDir, "SOUL.md");
147
- } else if (existsSync2(joinPath(agentDir, "SOUL.md"))) {
148
- soulPath = joinPath(agentDir, "SOUL.md");
156
+ if (!agentBrainDir) {
157
+ agentBrainDir = inferBrainDir(soulPath, agentDir);
158
+ }
149
159
  } else {
150
- console.error(`Error: SOUL.md not found for agent "${agentName}"`);
151
- console.error(`Checked: ${agentBrainDir ? agentBrainDir + "/SOUL.md, " : ""}${agentDir}/SOUL.md`);
152
- process.exit(1);
160
+ const found = findSoulMd(agentName);
161
+ if (found) {
162
+ soulPath = found;
163
+ if (!agentBrainDir) {
164
+ agentBrainDir = inferBrainDir(found, agentDir);
165
+ }
166
+ } else {
167
+ console.log(`
168
+ Agent "${agentName}" has no SOUL.md. Capability detection will be limited.`);
169
+ console.log(`Checked: ${joinPath(workspaceDir, "brains", agentName, "SOUL.md")}`);
170
+ console.log(` ${joinPath(agentsDir, agentName, "SOUL.md")}`);
171
+ console.log(` ${joinPath(workspaceDir, "SOUL.md")}`);
172
+ if (!opts.yes) {
173
+ const answer = await prompt("\nProceed with manual skill setup? (Y/n) ");
174
+ if (answer.toLowerCase() === "n") {
175
+ console.log("Setup cancelled.");
176
+ process.exit(0);
177
+ }
178
+ }
179
+ console.log("\nInitializing...");
180
+ const agentbnbDir2 = joinPath(agentDir, ".agentbnb");
181
+ process.env["AGENTBNB_DIR"] = agentbnbDir2;
182
+ const alreadyInit2 = existsSync2(joinPath(agentbnbDir2, "config.json"));
183
+ if (!alreadyInit2) {
184
+ const freePort = await detectFreePort();
185
+ await performInit({
186
+ owner: agentName,
187
+ port: String(freePort),
188
+ yes: true,
189
+ nonInteractive: true,
190
+ detect: false
191
+ });
192
+ console.log(` \u2713 Created ${agentbnbDir2}/config.json`);
193
+ } else {
194
+ console.log(` \u2713 ${agentbnbDir2}/config.json already exists`);
195
+ }
196
+ const effectiveBrainDir2 = agentBrainDir || agentDir;
197
+ try {
198
+ initGepDir(effectiveBrainDir2);
199
+ console.log(` \u2713 Initialized evolution assets (gep/)`);
200
+ } catch {
201
+ }
202
+ const heartbeatCandidates2 = [
203
+ agentBrainDir ? joinPath(agentBrainDir, "HEARTBEAT.md") : null,
204
+ joinPath(agentDir, "HEARTBEAT.md")
205
+ ].filter(Boolean);
206
+ const { existsSync: fsExists2 } = await import("fs");
207
+ for (const hbPath of heartbeatCandidates2) {
208
+ if (fsExists2(hbPath)) {
209
+ try {
210
+ appendHeartbeatTradingSection(hbPath, agentbnbDir2);
211
+ console.log(` \u2713 Updated HEARTBEAT.md`);
212
+ } catch {
213
+ }
214
+ break;
215
+ }
216
+ }
217
+ console.log(`
218
+ ${agentName} initialized on AgentBnB (no skills yet).`);
219
+ console.log(`Add skills manually: agentbnb openclaw skills add --manual --name <id> --type command --price 3`);
220
+ console.log(`
221
+ Useful commands:`);
222
+ console.log(` AGENTBNB_DIR=${agentbnbDir2} agentbnb openclaw skills list`);
223
+ console.log(` AGENTBNB_DIR=${agentbnbDir2} agentbnb status`);
224
+ return;
225
+ }
153
226
  }
154
227
  console.log(`
155
228
  Reading ${agentName}/SOUL.md...`);
156
229
  const soulContent = readFileSync(soulPath, "utf-8");
157
230
  const parsed = parseSoulMd(soulContent);
158
231
  if (parsed.capabilities.length === 0) {
159
- console.error("No skills (H2 sections) found in SOUL.md.");
160
- process.exit(1);
232
+ console.log("No skills (H2 sections) found in SOUL.md.");
233
+ console.log(`Add skills manually: agentbnb openclaw skills add --manual --name <id> --type command --price 3`);
234
+ process.exit(0);
161
235
  }
162
236
  const agentbnbDir = joinPath(agentDir, ".agentbnb");
163
237
  const alreadyInit = existsSync2(joinPath(agentbnbDir, "config.json"));