agentbnb 8.4.3 → 8.4.5

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.
@@ -14,16 +14,11 @@ import {
14
14
  orchestrate,
15
15
  requestViaTemporaryRelay,
16
16
  resolvePendingRequest
17
- } from "../../chunk-J46N2TCC.js";
17
+ } from "../../chunk-OPRCWXD5.js";
18
18
  import {
19
- generateKeyPair,
20
- loadKeyPair,
21
19
  requestCapability,
22
- requestViaRelay,
23
- saveKeyPair,
24
- signEscrowReceipt,
25
- verifyEscrowReceipt
26
- } from "../../chunk-R4F4XII4.js";
20
+ requestViaRelay
21
+ } from "../../chunk-YKMBFQC2.js";
27
22
  import {
28
23
  RelayClient,
29
24
  RelayMessageSchema
@@ -32,9 +27,15 @@ import {
32
27
  loadPeers
33
28
  } from "../../chunk-HLUEOLSZ.js";
34
29
  import {
30
+ createLedger,
31
+ deriveAgentId,
32
+ ensureIdentity,
35
33
  executeCapabilityBatch,
36
- executeCapabilityRequest
37
- } from "../../chunk-PMRTQ2RL.js";
34
+ executeCapabilityRequest,
35
+ identityAuthPlugin,
36
+ loadOrRepairIdentity,
37
+ syncCreditsFromRegistry
38
+ } from "../../chunk-5SIGMKOD.js";
38
39
  import {
39
40
  bootstrapAgent,
40
41
  buildReputationMap,
@@ -56,6 +57,12 @@ import {
56
57
  settleEscrow
57
58
  } from "../../chunk-NQANA6WH.js";
58
59
  import "../../chunk-6QMDJVMS.js";
60
+ import {
61
+ generateKeyPair,
62
+ loadKeyPair,
63
+ signEscrowReceipt,
64
+ verifyEscrowReceipt
65
+ } from "../../chunk-GIEJVKZZ.js";
59
66
  import {
60
67
  getConfigDir,
61
68
  loadConfig
@@ -81,17 +88,15 @@ import {
81
88
  updateSkillAvailability,
82
89
  updateSkillIdleRate
83
90
  } from "../../chunk-ZU2TP7CN.js";
84
- import {
85
- lookupAgent
86
- } from "../../chunk-EE3V3DXK.js";
91
+ import "../../chunk-EE3V3DXK.js";
87
92
  import {
88
93
  AgentBnBError,
89
94
  AnyCardSchema
90
95
  } from "../../chunk-I7KWA7OB.js";
91
96
 
92
97
  // skills/agentbnb/bootstrap.ts
93
- import { join as join7, basename as basename2, dirname as dirname4 } from "path";
94
- import { existsSync as existsSync8, writeFileSync as writeFileSync3 } from "fs";
98
+ import { join as join6, basename as basename2, dirname as dirname4 } from "path";
99
+ import { existsSync as existsSync7, writeFileSync as writeFileSync2 } from "fs";
95
100
  import { homedir as homedir4 } from "os";
96
101
  import { exec } from "child_process";
97
102
  import { promisify as promisify2 } from "util";
@@ -1373,7 +1378,7 @@ var AgentRuntime = class {
1373
1378
  }
1374
1379
  const modes = /* @__PURE__ */ new Map();
1375
1380
  if (this.conductorEnabled) {
1376
- const { ConductorMode } = await import("../../conductor-mode-PXTMYGK5.js");
1381
+ const { ConductorMode } = await import("../../conductor-mode-2F5OP7Q4.js");
1377
1382
  const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-BN643ZOY.js");
1378
1383
  const { loadPeers: loadPeers2 } = await import("../../peers-CJ7T4RJO.js");
1379
1384
  registerConductorCard(this.registryDb);
@@ -1690,11 +1695,11 @@ import swagger from "@fastify/swagger";
1690
1695
  import swaggerUi from "@fastify/swagger-ui";
1691
1696
  import fastifyStatic from "@fastify/static";
1692
1697
  import fastifyWebsocket from "@fastify/websocket";
1693
- import { join as join3, dirname as dirname2 } from "path";
1698
+ import { join as join2, dirname as dirname2 } from "path";
1694
1699
  import { randomUUID as randomUUID7 } from "crypto";
1695
1700
  import { fileURLToPath } from "url";
1696
- import { existsSync as existsSync4 } from "fs";
1697
- import { z as z7 } from "zod";
1701
+ import { existsSync as existsSync3 } from "fs";
1702
+ import { z as z6 } from "zod";
1698
1703
 
1699
1704
  // src/registry/pricing.ts
1700
1705
  function getPricingStats(db, query) {
@@ -1737,566 +1742,6 @@ function computeMedian(sorted) {
1737
1742
  return (sorted[mid - 1] + sorted[mid]) / 2;
1738
1743
  }
1739
1744
 
1740
- // src/credit/local-credit-ledger.ts
1741
- var LocalCreditLedger = class {
1742
- constructor(db) {
1743
- this.db = db;
1744
- }
1745
- /**
1746
- * Holds credits in escrow during capability execution.
1747
- *
1748
- * @param owner - Agent identifier (requester).
1749
- * @param amount - Number of credits to hold.
1750
- * @param cardId - Capability Card ID being requested.
1751
- * @returns EscrowResult with the new escrowId.
1752
- * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
1753
- */
1754
- async hold(owner, amount, cardId) {
1755
- const escrowId = holdEscrow(this.db, owner, amount, cardId);
1756
- return { escrowId };
1757
- }
1758
- /**
1759
- * Settles an escrow — transfers held credits to the capability provider.
1760
- *
1761
- * @param escrowId - The escrow ID to settle.
1762
- * @param recipientOwner - Agent identifier who will receive the credits.
1763
- * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1764
- * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1765
- */
1766
- async settle(escrowId, recipientOwner) {
1767
- settleEscrow(this.db, escrowId, recipientOwner);
1768
- }
1769
- /**
1770
- * Releases an escrow — refunds credits back to the requester.
1771
- *
1772
- * @param escrowId - The escrow ID to release.
1773
- * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1774
- * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1775
- */
1776
- async release(escrowId) {
1777
- releaseEscrow(this.db, escrowId);
1778
- }
1779
- /**
1780
- * Returns the current credit balance for an agent.
1781
- *
1782
- * @param owner - Agent identifier.
1783
- * @returns Current balance in credits (0 if agent is unknown).
1784
- */
1785
- async getBalance(owner) {
1786
- return getBalance(this.db, owner);
1787
- }
1788
- /**
1789
- * Returns the transaction history for an agent, newest first.
1790
- *
1791
- * @param owner - Agent identifier.
1792
- * @param limit - Maximum number of transactions to return. Defaults to 100.
1793
- * @returns Array of credit transactions ordered newest first.
1794
- */
1795
- async getHistory(owner, limit) {
1796
- return getTransactions(this.db, owner, limit);
1797
- }
1798
- /**
1799
- * Grants initial credits to an agent (bootstrap grant).
1800
- * Idempotent — calling multiple times has no additional effect on balance.
1801
- *
1802
- * @param owner - Agent identifier.
1803
- * @param amount - Number of credits to grant. Defaults to 100.
1804
- */
1805
- async grant(owner, amount) {
1806
- bootstrapAgent(this.db, owner, amount);
1807
- }
1808
- async rename(oldOwner, newOwner) {
1809
- migrateOwner(this.db, oldOwner, newOwner);
1810
- }
1811
- };
1812
-
1813
- // src/identity/identity.ts
1814
- import { z as z2 } from "zod";
1815
- import { createHash, createPrivateKey, createPublicKey } from "crypto";
1816
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1817
- import { join as join2 } from "path";
1818
- var AgentIdentitySchema = z2.object({
1819
- /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
1820
- agent_id: z2.string().min(1),
1821
- /** Human-readable owner name (from config or init). */
1822
- owner: z2.string().min(1),
1823
- /** Hex-encoded Ed25519 public key. */
1824
- public_key: z2.string().min(1),
1825
- /** ISO 8601 timestamp of identity creation. */
1826
- created_at: z2.string().datetime(),
1827
- /** Optional guarantor info if linked to a human. */
1828
- guarantor: z2.object({
1829
- github_login: z2.string().min(1),
1830
- verified_at: z2.string().datetime()
1831
- }).optional()
1832
- });
1833
- var AgentCertificateSchema = z2.object({
1834
- identity: AgentIdentitySchema,
1835
- /** ISO 8601 timestamp of certificate issuance. */
1836
- issued_at: z2.string().datetime(),
1837
- /** ISO 8601 timestamp of certificate expiry. */
1838
- expires_at: z2.string().datetime(),
1839
- /** Hex-encoded public key of the issuer (same as identity for self-signed). */
1840
- issuer_public_key: z2.string().min(1),
1841
- /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
1842
- signature: z2.string().min(1)
1843
- });
1844
- var IDENTITY_FILENAME = "identity.json";
1845
- var PRIVATE_KEY_FILENAME = "private.key";
1846
- var PUBLIC_KEY_FILENAME = "public.key";
1847
- function derivePublicKeyFromPrivate(privateKey) {
1848
- const privateKeyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
1849
- const publicKeyObject = createPublicKey(privateKeyObject);
1850
- const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
1851
- return Buffer.from(publicKey);
1852
- }
1853
- function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
1854
- const publicKeyHex = publicKey.toString("hex");
1855
- return {
1856
- agent_id: deriveAgentId(publicKeyHex),
1857
- owner,
1858
- public_key: publicKeyHex,
1859
- created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
1860
- };
1861
- }
1862
- function generateFreshIdentity(configDir, owner) {
1863
- const keys = generateKeyPair();
1864
- saveKeyPair(configDir, keys);
1865
- const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
1866
- saveIdentity(configDir, identity);
1867
- return { identity, keys, status: "generated" };
1868
- }
1869
- function deriveAgentId(publicKeyHex) {
1870
- return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
1871
- }
1872
- function loadIdentity(configDir) {
1873
- const filePath = join2(configDir, IDENTITY_FILENAME);
1874
- if (!existsSync3(filePath)) return null;
1875
- try {
1876
- const raw = readFileSync3(filePath, "utf-8");
1877
- return AgentIdentitySchema.parse(JSON.parse(raw));
1878
- } catch {
1879
- return null;
1880
- }
1881
- }
1882
- function saveIdentity(configDir, identity) {
1883
- if (!existsSync3(configDir)) {
1884
- mkdirSync2(configDir, { recursive: true });
1885
- }
1886
- const filePath = join2(configDir, IDENTITY_FILENAME);
1887
- writeFileSync2(filePath, JSON.stringify(identity, null, 2), "utf-8");
1888
- }
1889
- function loadOrRepairIdentity(configDir, ownerHint) {
1890
- if (!existsSync3(configDir)) {
1891
- mkdirSync2(configDir, { recursive: true });
1892
- }
1893
- const identityPath = join2(configDir, IDENTITY_FILENAME);
1894
- const privateKeyPath = join2(configDir, PRIVATE_KEY_FILENAME);
1895
- const publicKeyPath = join2(configDir, PUBLIC_KEY_FILENAME);
1896
- const hasIdentity = existsSync3(identityPath);
1897
- const hasPrivateKey = existsSync3(privateKeyPath);
1898
- const hasPublicKey = existsSync3(publicKeyPath);
1899
- if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
1900
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
1901
- }
1902
- let keys;
1903
- try {
1904
- keys = loadKeyPair(configDir);
1905
- } catch {
1906
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
1907
- }
1908
- let derivedPublicKey;
1909
- try {
1910
- derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
1911
- } catch {
1912
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
1913
- }
1914
- let keypairRepaired = false;
1915
- if (!keys.publicKey.equals(derivedPublicKey)) {
1916
- keypairRepaired = true;
1917
- keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
1918
- saveKeyPair(configDir, keys);
1919
- }
1920
- const loadedIdentity = loadIdentity(configDir);
1921
- const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
1922
- const expectedPublicKeyHex = derivedPublicKey.toString("hex");
1923
- const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
1924
- if (identityMismatch) {
1925
- const repairedIdentity = buildIdentityFromPublicKey(
1926
- derivedPublicKey,
1927
- loadedIdentity?.owner ?? ownerHint ?? "agent",
1928
- loadedIdentity?.created_at
1929
- );
1930
- saveIdentity(configDir, repairedIdentity);
1931
- return { identity: repairedIdentity, keys, status: "repaired" };
1932
- }
1933
- if (ownerHint && loadedIdentity.owner !== ownerHint) {
1934
- const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
1935
- saveIdentity(configDir, updatedIdentity);
1936
- return { identity: updatedIdentity, keys, status: "repaired" };
1937
- }
1938
- return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
1939
- }
1940
- function ensureIdentity(configDir, owner) {
1941
- return loadOrRepairIdentity(configDir, owner).identity;
1942
- }
1943
-
1944
- // src/registry/identity-auth.ts
1945
- var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
1946
- function normalizeSignedParams(body) {
1947
- return body === void 0 ? null : body;
1948
- }
1949
- function buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, params) {
1950
- return {
1951
- method,
1952
- path,
1953
- timestamp,
1954
- publicKey: publicKeyHex,
1955
- agentId,
1956
- params: normalizeSignedParams(params)
1957
- };
1958
- }
1959
- function extractClaimedRequester(request) {
1960
- const extractFromObject = (obj) => {
1961
- const directOwner = typeof obj.owner === "string" ? obj.owner.trim() : "";
1962
- if (directOwner) return directOwner;
1963
- const directRequester = typeof obj.requester === "string" ? obj.requester.trim() : "";
1964
- if (directRequester) return directRequester;
1965
- const oldOwner = typeof obj.oldOwner === "string" ? obj.oldOwner.trim() : "";
1966
- if (oldOwner) return oldOwner;
1967
- const nestedParams = obj.params;
1968
- if (nestedParams && typeof nestedParams === "object" && !Array.isArray(nestedParams)) {
1969
- const nested = nestedParams;
1970
- const nestedOwner = typeof nested.owner === "string" ? nested.owner.trim() : "";
1971
- if (nestedOwner) return nestedOwner;
1972
- const nestedRequester = typeof nested.requester === "string" ? nested.requester.trim() : "";
1973
- if (nestedRequester) return nestedRequester;
1974
- }
1975
- return null;
1976
- };
1977
- if (request.body && typeof request.body === "object" && !Array.isArray(request.body)) {
1978
- const claimed = extractFromObject(request.body);
1979
- if (claimed) return claimed;
1980
- }
1981
- if (request.params && typeof request.params === "object" && !Array.isArray(request.params)) {
1982
- const claimed = extractFromObject(request.params);
1983
- if (claimed) return claimed;
1984
- }
1985
- return null;
1986
- }
1987
- async function verifyIdentity(request, reply, options) {
1988
- const agentIdHeader = request.headers["x-agent-id"];
1989
- const publicKeyHeader = request.headers["x-agent-publickey"];
1990
- const signatureHeader = request.headers["x-agent-signature"];
1991
- const timestampHeader = request.headers["x-agent-timestamp"];
1992
- const agentId = agentIdHeader?.trim();
1993
- const publicKeyHex = publicKeyHeader?.trim();
1994
- const signature = signatureHeader?.trim();
1995
- const timestamp = timestampHeader?.trim();
1996
- if (!agentId || !publicKeyHex || !signature || !timestamp) {
1997
- await reply.code(401).send({ error: "Missing identity headers" });
1998
- return false;
1999
- }
2000
- const requestTime = new Date(timestamp).getTime();
2001
- if (isNaN(requestTime) || Math.abs(Date.now() - requestTime) > MAX_REQUEST_AGE_MS) {
2002
- await reply.code(401).send({ error: "Request expired" });
2003
- return false;
2004
- }
2005
- if (!/^[0-9a-fA-F]+$/.test(publicKeyHex) || publicKeyHex.length % 2 !== 0) {
2006
- await reply.code(401).send({ error: "Invalid identity signature" });
2007
- return false;
2008
- }
2009
- let expectedAgentId;
2010
- try {
2011
- expectedAgentId = deriveAgentId(publicKeyHex);
2012
- } catch {
2013
- await reply.code(401).send({ error: "Invalid identity signature" });
2014
- return false;
2015
- }
2016
- if (agentId !== expectedAgentId) {
2017
- await reply.code(401).send({ error: "Invalid identity signature" });
2018
- return false;
2019
- }
2020
- let publicKeyBuffer;
2021
- try {
2022
- publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
2023
- } catch {
2024
- await reply.code(401).send({ error: "Invalid identity signature" });
2025
- return false;
2026
- }
2027
- const knownAgent = options.agentDb ? lookupAgent(options.agentDb, agentId) : null;
2028
- if (knownAgent && knownAgent.public_key.toLowerCase() !== publicKeyHex.toLowerCase()) {
2029
- await reply.code(401).send({ error: "Invalid identity signature" });
2030
- return false;
2031
- }
2032
- const payload = buildIdentityPayload(
2033
- request.method,
2034
- request.url,
2035
- timestamp,
2036
- publicKeyHex,
2037
- agentId,
2038
- request.body
2039
- );
2040
- const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
2041
- if (!valid) {
2042
- await reply.code(401).send({ error: "Invalid identity signature" });
2043
- return false;
2044
- }
2045
- const claimedRequester = extractClaimedRequester(request);
2046
- if (claimedRequester && knownAgent !== null) {
2047
- const matchesAgentId = claimedRequester === agentId;
2048
- const matchesDisplayName = knownAgent.display_name === claimedRequester;
2049
- const matchesLegacyOwner = knownAgent.legacy_owner === claimedRequester;
2050
- if (!matchesAgentId && !matchesDisplayName && !matchesLegacyOwner) {
2051
- await reply.code(401).send({ error: "Identity does not match requester" });
2052
- return false;
2053
- }
2054
- }
2055
- request.agentPublicKey = publicKeyHex;
2056
- request.agentId = agentId;
2057
- return true;
2058
- }
2059
- function identityAuthPlugin(fastify, options = {}) {
2060
- fastify.addHook("preHandler", async (request, reply) => {
2061
- const ok = await verifyIdentity(request, reply, options);
2062
- if (!ok) {
2063
- return reply;
2064
- }
2065
- });
2066
- }
2067
- function signRequest(method, path, body, privateKey, publicKeyHex, agentIdOverride) {
2068
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2069
- const agentId = agentIdOverride ?? deriveAgentId(publicKeyHex);
2070
- const payload = buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, body);
2071
- const signature = signEscrowReceipt(payload, privateKey);
2072
- return {
2073
- "X-Agent-Id": agentId,
2074
- "X-Agent-PublicKey": publicKeyHex,
2075
- "X-Agent-Signature": signature,
2076
- "X-Agent-Timestamp": timestamp
2077
- };
2078
- }
2079
-
2080
- // src/credit/registry-credit-ledger.ts
2081
- var HTTP_TIMEOUT_MS = 1e4;
2082
- var RegistryCreditLedger = class {
2083
- config;
2084
- constructor(config) {
2085
- this.config = config;
2086
- }
2087
- /**
2088
- * Holds credits in escrow during capability execution.
2089
- *
2090
- * @param owner - Agent identifier (requester).
2091
- * @param amount - Number of credits to hold.
2092
- * @param cardId - Capability Card ID being requested.
2093
- * @returns EscrowResult with the new escrowId.
2094
- * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
2095
- */
2096
- async hold(owner, amount, cardId) {
2097
- if (this.config.mode === "direct") {
2098
- const escrowId = holdEscrow(this.config.db, owner, amount, cardId);
2099
- return { escrowId };
2100
- }
2101
- const data = await this.post("/api/credits/hold", owner, {
2102
- owner,
2103
- amount,
2104
- cardId
2105
- });
2106
- return { escrowId: data.escrowId };
2107
- }
2108
- /**
2109
- * Settles an escrow — transfers held credits to the capability provider.
2110
- *
2111
- * @param escrowId - The escrow ID to settle.
2112
- * @param recipientOwner - Agent identifier who will receive the credits.
2113
- * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
2114
- * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
2115
- */
2116
- async settle(escrowId, recipientOwner) {
2117
- if (this.config.mode === "direct") {
2118
- settleEscrow(this.config.db, escrowId, recipientOwner);
2119
- return;
2120
- }
2121
- await this.post("/api/credits/settle", null, { escrowId, recipientOwner });
2122
- }
2123
- /**
2124
- * Releases an escrow — refunds credits back to the requester.
2125
- *
2126
- * @param escrowId - The escrow ID to release.
2127
- * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
2128
- * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
2129
- */
2130
- async release(escrowId) {
2131
- if (this.config.mode === "direct") {
2132
- releaseEscrow(this.config.db, escrowId);
2133
- return;
2134
- }
2135
- await this.post("/api/credits/release", null, { escrowId });
2136
- }
2137
- /**
2138
- * Returns the current credit balance for an agent.
2139
- *
2140
- * @param owner - Agent identifier.
2141
- * @returns Current balance in credits (0 if agent is unknown).
2142
- */
2143
- async getBalance(owner) {
2144
- if (this.config.mode === "direct") {
2145
- return getBalance(this.config.db, owner);
2146
- }
2147
- const data = await this.get(`/api/credits/${owner}`, owner);
2148
- return data.balance;
2149
- }
2150
- /**
2151
- * Returns the transaction history for an agent, newest first.
2152
- *
2153
- * @param owner - Agent identifier.
2154
- * @param limit - Maximum number of transactions to return. Defaults to 100.
2155
- * @returns Array of credit transactions ordered newest first.
2156
- */
2157
- async getHistory(owner, limit = 100) {
2158
- if (this.config.mode === "direct") {
2159
- return getTransactions(this.config.db, owner, limit);
2160
- }
2161
- const data = await this.get(
2162
- `/api/credits/${owner}/history?limit=${limit}`,
2163
- owner
2164
- );
2165
- return data.transactions;
2166
- }
2167
- /**
2168
- * Grants initial credits to an agent (bootstrap grant).
2169
- * Idempotent — calling multiple times has no additional effect on balance.
2170
- *
2171
- * @param owner - Agent identifier.
2172
- * @param amount - Number of credits to grant. Defaults to 100.
2173
- */
2174
- async grant(owner, amount = 100) {
2175
- if (this.config.mode === "direct") {
2176
- bootstrapAgent(this.config.db, owner, amount);
2177
- return;
2178
- }
2179
- await this.post("/api/credits/grant", owner, { owner, amount });
2180
- }
2181
- /**
2182
- * Renames an owner — migrates balance, transactions, and escrows.
2183
- */
2184
- async rename(oldOwner, newOwner) {
2185
- if (oldOwner === newOwner) return;
2186
- if (this.config.mode === "direct") {
2187
- migrateOwner(this.config.db, oldOwner, newOwner);
2188
- return;
2189
- }
2190
- await this.post("/api/credits/rename", null, { oldOwner, newOwner });
2191
- }
2192
- // ─── Private HTTP helpers ─────────────────────────────────────────────────
2193
- /**
2194
- * Makes an authenticated POST request to the Registry HTTP API.
2195
- * Includes a 10s timeout via AbortController.
2196
- *
2197
- * @param path - API path (e.g., '/api/credits/hold').
2198
- * @param ownerForHeader - Agent owner identifier for X-Agent-Owner header, or null to omit.
2199
- * @param body - JSON body to send.
2200
- * @returns Parsed JSON response body.
2201
- * @throws {AgentBnBError} on non-2xx responses or network errors.
2202
- */
2203
- async post(path, ownerForHeader, body) {
2204
- const cfg = this.config;
2205
- const controller = new AbortController();
2206
- const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
2207
- try {
2208
- const authHeaders = signRequest("POST", path, body, cfg.privateKey, cfg.ownerPublicKey);
2209
- const headers = {
2210
- "Content-Type": "application/json",
2211
- ...authHeaders
2212
- };
2213
- void ownerForHeader;
2214
- const res = await fetch(`${cfg.registryUrl}${path}`, {
2215
- method: "POST",
2216
- headers,
2217
- body: JSON.stringify(body),
2218
- signal: controller.signal
2219
- });
2220
- return await this.handleResponse(res);
2221
- } catch (err) {
2222
- if (err instanceof AgentBnBError) throw err;
2223
- throw new AgentBnBError(
2224
- `Registry unreachable: ${err.message}`,
2225
- "REGISTRY_UNREACHABLE"
2226
- );
2227
- } finally {
2228
- clearTimeout(timeoutId);
2229
- }
2230
- }
2231
- /**
2232
- * Makes an authenticated GET request to the Registry HTTP API.
2233
- * Includes a 10s timeout via AbortController.
2234
- *
2235
- * @param path - API path (e.g., '/api/credits/owner-id').
2236
- * @param owner - Agent owner identifier for X-Agent-Owner header.
2237
- * @returns Parsed JSON response body.
2238
- * @throws {AgentBnBError} on non-2xx responses or network errors.
2239
- */
2240
- async get(path, owner) {
2241
- const cfg = this.config;
2242
- const controller = new AbortController();
2243
- const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
2244
- try {
2245
- const authHeaders = signRequest("GET", path, null, cfg.privateKey, cfg.ownerPublicKey);
2246
- void owner;
2247
- const res = await fetch(`${cfg.registryUrl}${path}`, {
2248
- method: "GET",
2249
- headers: {
2250
- "Content-Type": "application/json",
2251
- ...authHeaders
2252
- },
2253
- signal: controller.signal
2254
- });
2255
- return await this.handleResponse(res);
2256
- } catch (err) {
2257
- if (err instanceof AgentBnBError) throw err;
2258
- throw new AgentBnBError(
2259
- `Registry unreachable: ${err.message}`,
2260
- "REGISTRY_UNREACHABLE"
2261
- );
2262
- } finally {
2263
- clearTimeout(timeoutId);
2264
- }
2265
- }
2266
- /**
2267
- * Handles an HTTP response — returns parsed JSON on 2xx, throws AgentBnBError on error.
2268
- */
2269
- async handleResponse(res) {
2270
- const json = await res.json();
2271
- if (!res.ok) {
2272
- const code = typeof json["code"] === "string" ? json["code"] : "REGISTRY_ERROR";
2273
- const message = typeof json["error"] === "string" ? json["error"] : `HTTP ${res.status}`;
2274
- throw new AgentBnBError(message, code);
2275
- }
2276
- return json;
2277
- }
2278
- };
2279
-
2280
- // src/credit/create-ledger.ts
2281
- function createLedger(opts) {
2282
- if ("registryUrl" in opts && opts.registryUrl !== void 0) {
2283
- return new RegistryCreditLedger({
2284
- mode: "http",
2285
- registryUrl: opts.registryUrl,
2286
- ownerPublicKey: opts.ownerPublicKey,
2287
- privateKey: opts.privateKey
2288
- });
2289
- }
2290
- if ("db" in opts && opts.db !== void 0) {
2291
- return new RegistryCreditLedger({
2292
- mode: "direct",
2293
- db: opts.db
2294
- });
2295
- }
2296
- const db = openCreditDb(opts.creditDbPath);
2297
- return new LocalCreditLedger(db);
2298
- }
2299
-
2300
1745
  // src/cli/onboarding.ts
2301
1746
  import { randomUUID as randomUUID2 } from "crypto";
2302
1747
  import { createConnection } from "net";
@@ -3586,16 +3031,16 @@ function registerWebSocketRelay(server, db, creditDb) {
3586
3031
  }
3587
3032
 
3588
3033
  // src/identity/guarantor.ts
3589
- import { z as z3 } from "zod";
3034
+ import { z as z2 } from "zod";
3590
3035
  import { randomUUID as randomUUID6 } from "crypto";
3591
3036
  var MAX_AGENTS_PER_GUARANTOR = 10;
3592
3037
  var GUARANTOR_CREDIT_POOL = 50;
3593
- var GuarantorRecordSchema = z3.object({
3594
- id: z3.string().uuid(),
3595
- github_login: z3.string().min(1),
3596
- agent_count: z3.number().int().nonnegative(),
3597
- credit_pool: z3.number().int().nonnegative(),
3598
- created_at: z3.string().datetime()
3038
+ var GuarantorRecordSchema = z2.object({
3039
+ id: z2.string().uuid(),
3040
+ github_login: z2.string().min(1),
3041
+ agent_count: z2.number().int().nonnegative(),
3042
+ credit_pool: z2.number().int().nonnegative(),
3043
+ created_at: z2.string().datetime()
3599
3044
  });
3600
3045
  var GUARANTOR_SCHEMA = `
3601
3046
  CREATE TABLE IF NOT EXISTS guarantors (
@@ -3732,6 +3177,75 @@ async function creditRoutesPlugin(fastify, options) {
3732
3177
  } catch {
3733
3178
  }
3734
3179
  initFreeTierTable(creditDb);
3180
+ if (!process.env.ADMIN_TOKEN) {
3181
+ console.warn("[agentbnb] ADMIN_TOKEN not set \u2014 POST /api/credits/grant will return 401 for admin override grants");
3182
+ }
3183
+ fastify.get("/api/credits/balance", {
3184
+ schema: {
3185
+ tags: ["credits"],
3186
+ summary: "Get credit balance by owner query param (public, no auth required)",
3187
+ querystring: {
3188
+ type: "object",
3189
+ properties: { owner: { type: "string", description: "Agent owner name" } },
3190
+ required: ["owner"]
3191
+ },
3192
+ response: {
3193
+ 200: {
3194
+ type: "object",
3195
+ properties: {
3196
+ owner: { type: "string" },
3197
+ balance: { type: "number" }
3198
+ }
3199
+ },
3200
+ 400: { type: "object", properties: { error: { type: "string" } } }
3201
+ }
3202
+ }
3203
+ }, async (request, reply) => {
3204
+ const query = request.query;
3205
+ const owner = typeof query.owner === "string" ? query.owner.trim() : "";
3206
+ if (!owner) {
3207
+ return reply.code(400).send({ error: "owner query param required" });
3208
+ }
3209
+ const balance = getBalance(creditDb, owner);
3210
+ return reply.send({ owner, balance });
3211
+ });
3212
+ fastify.get("/api/credits/transactions", {
3213
+ schema: {
3214
+ tags: ["credits"],
3215
+ summary: "Get transaction history by query params (public, no auth required)",
3216
+ querystring: {
3217
+ type: "object",
3218
+ properties: {
3219
+ owner: { type: "string", description: "Agent owner name" },
3220
+ since: { type: "string", description: "ISO 8601 timestamp \u2014 only return transactions after this time" },
3221
+ limit: { type: "integer", description: "Max entries (default 50, max 100)" }
3222
+ },
3223
+ required: ["owner"]
3224
+ },
3225
+ response: {
3226
+ 200: {
3227
+ type: "object",
3228
+ properties: {
3229
+ owner: { type: "string" },
3230
+ transactions: { type: "array" },
3231
+ limit: { type: "integer" }
3232
+ }
3233
+ },
3234
+ 400: { type: "object", properties: { error: { type: "string" } } }
3235
+ }
3236
+ }
3237
+ }, async (request, reply) => {
3238
+ const query = request.query;
3239
+ const owner = typeof query.owner === "string" ? query.owner.trim() : "";
3240
+ if (!owner) {
3241
+ return reply.code(400).send({ error: "owner query param required" });
3242
+ }
3243
+ const rawLimit = query.limit !== void 0 ? parseInt(query.limit, 10) : 50;
3244
+ const limit = Math.min(isNaN(rawLimit) || rawLimit < 1 ? 50 : rawLimit, 100);
3245
+ const since = typeof query.since === "string" && query.since.trim() ? query.since.trim() : void 0;
3246
+ const transactions = getTransactions(creditDb, owner, { limit, after: since });
3247
+ return reply.send({ owner, transactions, limit });
3248
+ });
3735
3249
  await fastify.register(async (scope) => {
3736
3250
  identityAuthPlugin(scope, { agentDb: creditDb });
3737
3251
  scope.post("/api/credits/hold", {
@@ -4127,38 +3641,38 @@ var HubAgentExecutor = class {
4127
3641
  };
4128
3642
 
4129
3643
  // src/hub-agent/types.ts
4130
- import { z as z4 } from "zod";
4131
- var SkillRouteSchema = z4.discriminatedUnion("mode", [
4132
- z4.object({
4133
- skill_id: z4.string().min(1),
4134
- mode: z4.literal("direct_api"),
3644
+ import { z as z3 } from "zod";
3645
+ var SkillRouteSchema = z3.discriminatedUnion("mode", [
3646
+ z3.object({
3647
+ skill_id: z3.string().min(1),
3648
+ mode: z3.literal("direct_api"),
4135
3649
  config: ApiSkillConfigSchema
4136
3650
  }),
4137
- z4.object({
4138
- skill_id: z4.string().min(1),
4139
- mode: z4.literal("relay"),
4140
- config: z4.object({ relay_owner: z4.string().min(1) })
3651
+ z3.object({
3652
+ skill_id: z3.string().min(1),
3653
+ mode: z3.literal("relay"),
3654
+ config: z3.object({ relay_owner: z3.string().min(1) })
4141
3655
  }),
4142
- z4.object({
4143
- skill_id: z4.string().min(1),
4144
- mode: z4.literal("queue"),
4145
- config: z4.object({ relay_owner: z4.string().min(1) }).passthrough()
3656
+ z3.object({
3657
+ skill_id: z3.string().min(1),
3658
+ mode: z3.literal("queue"),
3659
+ config: z3.object({ relay_owner: z3.string().min(1) }).passthrough()
4146
3660
  })
4147
3661
  ]);
4148
- var HubAgentSchema = z4.object({
4149
- agent_id: z4.string().min(1),
4150
- name: z4.string().min(1),
4151
- owner_public_key: z4.string().min(1),
4152
- public_key: z4.string().min(1),
4153
- skill_routes: z4.array(SkillRouteSchema),
4154
- status: z4.enum(["active", "paused"]),
4155
- created_at: z4.string(),
4156
- updated_at: z4.string()
3662
+ var HubAgentSchema = z3.object({
3663
+ agent_id: z3.string().min(1),
3664
+ name: z3.string().min(1),
3665
+ owner_public_key: z3.string().min(1),
3666
+ public_key: z3.string().min(1),
3667
+ skill_routes: z3.array(SkillRouteSchema),
3668
+ status: z3.enum(["active", "paused"]),
3669
+ created_at: z3.string(),
3670
+ updated_at: z3.string()
4157
3671
  });
4158
- var CreateAgentRequestSchema = z4.object({
4159
- name: z4.string().min(1),
4160
- skill_routes: z4.array(SkillRouteSchema),
4161
- secrets: z4.record(z4.string()).optional()
3672
+ var CreateAgentRequestSchema = z3.object({
3673
+ name: z3.string().min(1),
3674
+ skill_routes: z3.array(SkillRouteSchema),
3675
+ secrets: z3.record(z3.string()).optional()
4162
3676
  });
4163
3677
 
4164
3678
  // src/hub-agent/routes.ts
@@ -4586,24 +4100,24 @@ function deriveOperationId(method, path) {
4586
4100
  }
4587
4101
 
4588
4102
  // src/feedback/schema.ts
4589
- import { z as z5 } from "zod";
4590
- var StructuredFeedbackSchema = z5.object({
4591
- transaction_id: z5.string().uuid(),
4103
+ import { z as z4 } from "zod";
4104
+ var StructuredFeedbackSchema = z4.object({
4105
+ transaction_id: z4.string().uuid(),
4592
4106
  // must match a request_log entry id
4593
- provider_agent: z5.string().min(1),
4594
- skill_id: z5.string().min(1),
4595
- requester_agent: z5.string().min(1),
4596
- rating: z5.number().int().min(1).max(5),
4597
- latency_ms: z5.number().int().min(0),
4598
- result_quality: z5.enum(["excellent", "good", "acceptable", "poor", "failed"]),
4599
- quality_details: z5.string().max(500).optional(),
4600
- would_reuse: z5.boolean(),
4601
- cost_value_ratio: z5.enum(["great", "fair", "overpriced"]),
4602
- timestamp: z5.string().datetime()
4107
+ provider_agent: z4.string().min(1),
4108
+ skill_id: z4.string().min(1),
4109
+ requester_agent: z4.string().min(1),
4110
+ rating: z4.number().int().min(1).max(5),
4111
+ latency_ms: z4.number().int().min(0),
4112
+ result_quality: z4.enum(["excellent", "good", "acceptable", "poor", "failed"]),
4113
+ quality_details: z4.string().max(500).optional(),
4114
+ would_reuse: z4.boolean(),
4115
+ cost_value_ratio: z4.enum(["great", "fair", "overpriced"]),
4116
+ timestamp: z4.string().datetime()
4603
4117
  });
4604
- var FeedbackResponseSchema = z5.object({
4605
- feedback_id: z5.string().uuid(),
4606
- received_at: z5.string().datetime()
4118
+ var FeedbackResponseSchema = z4.object({
4119
+ feedback_id: z4.string().uuid(),
4120
+ received_at: z4.string().datetime()
4607
4121
  });
4608
4122
 
4609
4123
  // src/feedback/api.ts
@@ -4726,28 +4240,28 @@ var feedbackPlugin = async (fastify, opts) => {
4726
4240
  var api_default = feedbackPlugin;
4727
4241
 
4728
4242
  // src/evolution/schema.ts
4729
- import { z as z6 } from "zod";
4730
- var CoreMemoryEntrySchema = z6.object({
4731
- category: z6.string(),
4732
- importance: z6.number().min(0).max(1),
4733
- content: z6.string(),
4734
- scope: z6.string().optional()
4243
+ import { z as z5 } from "zod";
4244
+ var CoreMemoryEntrySchema = z5.object({
4245
+ category: z5.string(),
4246
+ importance: z5.number().min(0).max(1),
4247
+ content: z5.string(),
4248
+ scope: z5.string().optional()
4735
4249
  });
4736
- var TemplateEvolutionSchema = z6.object({
4250
+ var TemplateEvolutionSchema = z5.object({
4737
4251
  /** e.g. "genesis-template" */
4738
- template_name: z6.string().min(1),
4252
+ template_name: z5.string().min(1),
4739
4253
  /** Semantic version string, e.g. "1.2.3" */
4740
- template_version: z6.string().regex(/^\d+\.\d+\.\d+$/, "Must be a valid semver string (e.g. 1.2.3)"),
4254
+ template_version: z5.string().regex(/^\d+\.\d+\.\d+$/, "Must be a valid semver string (e.g. 1.2.3)"),
4741
4255
  /** Identifier of the agent publishing this evolution */
4742
- publisher_agent: z6.string().min(1),
4256
+ publisher_agent: z5.string().min(1),
4743
4257
  /** Human-readable description of what changed in this evolution */
4744
- changelog: z6.string().max(1e3),
4258
+ changelog: z5.string().max(1e3),
4745
4259
  /** Snapshot of the agent's core memory at the time of evolution (max 50 entries) */
4746
- core_memory_snapshot: z6.array(CoreMemoryEntrySchema).max(50),
4260
+ core_memory_snapshot: z5.array(CoreMemoryEntrySchema).max(50),
4747
4261
  /** Delta in fitness score from before evolution (range -1 to 1) */
4748
- fitness_improvement: z6.number().min(-1).max(1),
4262
+ fitness_improvement: z5.number().min(-1).max(1),
4749
4263
  /** ISO 8601 datetime string */
4750
- timestamp: z6.string().datetime()
4264
+ timestamp: z5.string().datetime()
4751
4265
  });
4752
4266
 
4753
4267
  // src/evolution/api.ts
@@ -4935,14 +4449,14 @@ function createRegistryServer(opts) {
4935
4449
  const __filename = fileURLToPath(import.meta.url);
4936
4450
  const __dirname = dirname2(__filename);
4937
4451
  const hubDistCandidates = [
4938
- join3(__dirname, "../hub/dist"),
4452
+ join2(__dirname, "../hub/dist"),
4939
4453
  // When in dist/ (tsup chunk, e.g. dist/server-XYZ.js)
4940
- join3(__dirname, "../../hub/dist"),
4454
+ join2(__dirname, "../../hub/dist"),
4941
4455
  // When in dist/registry/ or dist/cli/
4942
- join3(__dirname, "../../../hub/dist")
4456
+ join2(__dirname, "../../../hub/dist")
4943
4457
  // Fallback for alternative layouts
4944
4458
  ];
4945
- const hubDistDir = hubDistCandidates.find((p) => existsSync4(p));
4459
+ const hubDistDir = hubDistCandidates.find((p) => existsSync3(p));
4946
4460
  if (hubDistDir) {
4947
4461
  void server.register(fastifyStatic, {
4948
4462
  root: hubDistDir,
@@ -5738,16 +5252,16 @@ function createRegistryServer(opts) {
5738
5252
  const gptActions = convertToGptActions(openapiSpec, serverUrl);
5739
5253
  return reply.send(gptActions);
5740
5254
  });
5741
- const BatchRequestBodySchema = z7.object({
5742
- requests: z7.array(
5743
- z7.object({
5744
- skill_id: z7.string().min(1),
5745
- params: z7.record(z7.unknown()).default({}),
5746
- max_credits: z7.number().positive()
5255
+ const BatchRequestBodySchema = z6.object({
5256
+ requests: z6.array(
5257
+ z6.object({
5258
+ skill_id: z6.string().min(1),
5259
+ params: z6.record(z6.unknown()).default({}),
5260
+ max_credits: z6.number().positive()
5747
5261
  })
5748
5262
  ).min(1),
5749
- strategy: z7.enum(["parallel", "sequential", "best_effort"]),
5750
- total_budget: z7.number().positive()
5263
+ strategy: z6.enum(["parallel", "sequential", "best_effort"]),
5264
+ total_budget: z6.number().positive()
5751
5265
  });
5752
5266
  api.post("/api/request/batch", {
5753
5267
  schema: {
@@ -5818,7 +5332,7 @@ function createRegistryServer(opts) {
5818
5332
  });
5819
5333
  await relayClient.connect();
5820
5334
  }
5821
- const { requestViaRelay: requestViaRelay2 } = await import("../../client-OKJJ3UP2.js");
5335
+ const { requestViaRelay: requestViaRelay2 } = await import("../../client-UQBGCIPA.js");
5822
5336
  return requestViaRelay2(relayClient, {
5823
5337
  targetOwner: target.owner,
5824
5338
  cardId: target.cardId,
@@ -6287,10 +5801,10 @@ async function stopAnnouncement() {
6287
5801
 
6288
5802
  // src/runtime/resolve-self-cli.ts
6289
5803
  import { execFileSync as execFileSync2 } from "child_process";
6290
- import { existsSync as existsSync5, realpathSync } from "fs";
5804
+ import { existsSync as existsSync4, realpathSync } from "fs";
6291
5805
  import { createRequire } from "module";
6292
5806
  import { homedir as homedir2 } from "os";
6293
- import { basename, dirname as dirname3, isAbsolute, join as join4, resolve } from "path";
5807
+ import { basename, dirname as dirname3, isAbsolute, join as join3, resolve } from "path";
6294
5808
  function resolveSelfCli() {
6295
5809
  const require2 = createRequire(import.meta.url);
6296
5810
  return resolveSelfCliWithDeps({
@@ -6300,7 +5814,7 @@ function resolveSelfCli() {
6300
5814
  homeDir: homedir2(),
6301
5815
  envPath: process.env["PATH"],
6302
5816
  nodeExecDir: dirname3(process.execPath),
6303
- exists: existsSync5,
5817
+ exists: existsSync4,
6304
5818
  realpath: realpathSync,
6305
5819
  runWhich: (pathEnv) => execFileSync2("which", ["agentbnb"], {
6306
5820
  encoding: "utf8",
@@ -6345,7 +5859,7 @@ function resolveSelfCliWithDeps(deps) {
6345
5859
  }
6346
5860
  if (deps.nodeExecDir) {
6347
5861
  const execDirCandidate = tryCandidate(
6348
- join4(deps.nodeExecDir, "agentbnb"),
5862
+ join3(deps.nodeExecDir, "agentbnb"),
6349
5863
  "node-execpath-dir"
6350
5864
  );
6351
5865
  if (execDirCandidate) return execDirCandidate;
@@ -6376,9 +5890,9 @@ function buildFullPathEnv(pathEnv, homeDir, nodeExecDir) {
6376
5890
  "/bin",
6377
5891
  "/usr/sbin",
6378
5892
  "/sbin",
6379
- join4(homeDir, ".local", "bin"),
6380
- join4(homeDir, "Library", "pnpm"),
6381
- join4(homeDir, ".local", "share", "pnpm")
5893
+ join3(homeDir, ".local", "bin"),
5894
+ join3(homeDir, "Library", "pnpm"),
5895
+ join3(homeDir, ".local", "share", "pnpm")
6382
5896
  ]) {
6383
5897
  values.add(extra);
6384
5898
  }
@@ -6397,13 +5911,13 @@ function safeRealpath(realpath, path) {
6397
5911
  function getPnpmGlobalCandidates(platform, homeDir) {
6398
5912
  const candidates = /* @__PURE__ */ new Set();
6399
5913
  if (platform === "darwin") {
6400
- candidates.add(join4(homeDir, "Library", "pnpm", "agentbnb"));
5914
+ candidates.add(join3(homeDir, "Library", "pnpm", "agentbnb"));
6401
5915
  }
6402
5916
  if (platform === "linux") {
6403
- candidates.add(join4(homeDir, ".local", "share", "pnpm", "agentbnb"));
5917
+ candidates.add(join3(homeDir, ".local", "share", "pnpm", "agentbnb"));
6404
5918
  }
6405
- candidates.add(join4(homeDir, "Library", "pnpm", "agentbnb"));
6406
- candidates.add(join4(homeDir, ".local", "share", "pnpm", "agentbnb"));
5919
+ candidates.add(join3(homeDir, "Library", "pnpm", "agentbnb"));
5920
+ candidates.add(join3(homeDir, ".local", "share", "pnpm", "agentbnb"));
6407
5921
  return [...candidates];
6408
5922
  }
6409
5923
  function looksLikeAgentbnbCli(path) {
@@ -6421,9 +5935,10 @@ function extractErrorMessage(err) {
6421
5935
 
6422
5936
  // src/runtime/service-coordinator.ts
6423
5937
  import { spawn as spawn2 } from "child_process";
6424
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
6425
- import { join as join5 } from "path";
5938
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
5939
+ import { join as join4 } from "path";
6426
5940
  import { randomUUID as randomUUID8 } from "crypto";
5941
+ import { Cron as Cron2 } from "croner";
6427
5942
  function buildFallbackRelayCard(owner) {
6428
5943
  return {
6429
5944
  id: randomUUID8(),
@@ -6461,6 +5976,7 @@ var ServiceCoordinator = class {
6461
5976
  inProcessStartup = false;
6462
5977
  shutdownPromise = null;
6463
5978
  signalHandlersRegistered = false;
5979
+ creditSyncJob = null;
6464
5980
  constructor(config, guard) {
6465
5981
  this.config = config;
6466
5982
  this.guard = guard;
@@ -6569,7 +6085,7 @@ var ServiceCoordinator = class {
6569
6085
  return {
6570
6086
  port: opts?.port ?? this.config.gateway_port,
6571
6087
  handlerUrl: opts?.handlerUrl ?? "http://localhost:8080",
6572
- skillsYamlPath: opts?.skillsYamlPath ?? join5(getConfigDir(), "skills.yaml"),
6088
+ skillsYamlPath: opts?.skillsYamlPath ?? join4(getConfigDir(), "skills.yaml"),
6573
6089
  registryPort: opts?.registryPort ?? 7701,
6574
6090
  registryUrl: opts?.registryUrl ?? this.config.registry ?? "",
6575
6091
  relay: opts?.relay ?? true,
@@ -6625,6 +6141,22 @@ var ServiceCoordinator = class {
6625
6141
  const idleJob = idleMonitor.start();
6626
6142
  this.runtime.registerJob(idleJob);
6627
6143
  console.log("IdleMonitor started (60s poll interval, 70% idle threshold)");
6144
+ if (this.config.registry) {
6145
+ const startupSync = await syncCreditsFromRegistry(this.config, this.runtime.creditDb);
6146
+ if (startupSync.synced) {
6147
+ console.log(`[agentbnb] credits synced: ${startupSync.remoteBalance} (was ${startupSync.localWas})`);
6148
+ } else {
6149
+ console.warn(`[agentbnb] credit sync skipped: ${startupSync.error}`);
6150
+ }
6151
+ this.creditSyncJob = new Cron2("*/5 * * * *", async () => {
6152
+ const result = await syncCreditsFromRegistry(this.config, this.runtime.creditDb);
6153
+ if (result.synced) {
6154
+ console.log(`[agentbnb] credits synced: ${result.remoteBalance} (was ${result.localWas})`);
6155
+ } else {
6156
+ console.warn(`[agentbnb] credit sync failed: ${result.error}`);
6157
+ }
6158
+ });
6159
+ }
6628
6160
  this.gateway = createGatewayServer({
6629
6161
  port: opts.port,
6630
6162
  registryDb: this.runtime.registryDb,
@@ -6655,7 +6187,7 @@ var ServiceCoordinator = class {
6655
6187
  }
6656
6188
  if (opts.registryUrl && opts.relay) {
6657
6189
  const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
6658
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-UAD5T3BQ.js");
6190
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-VRTABQ6F.js");
6659
6191
  const localCards = listCards(this.runtime.registryDb, this.config.owner);
6660
6192
  const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
6661
6193
  if (this.config.conductor?.public) {
@@ -6714,6 +6246,10 @@ var ServiceCoordinator = class {
6714
6246
  return;
6715
6247
  }
6716
6248
  this.shutdownPromise = (async () => {
6249
+ if (this.creditSyncJob) {
6250
+ this.creditSyncJob.stop();
6251
+ this.creditSyncJob = null;
6252
+ }
6717
6253
  if (this.relayClient) {
6718
6254
  this.relayClient.disconnect();
6719
6255
  this.relayClient = null;
@@ -6909,10 +6445,10 @@ var ServiceCoordinator = class {
6909
6445
  };
6910
6446
  };
6911
6447
  function loadPersistedRuntime(configDir) {
6912
- const runtimePath = join5(configDir, "runtime.json");
6913
- if (!existsSync6(runtimePath)) return null;
6448
+ const runtimePath = join4(configDir, "runtime.json");
6449
+ if (!existsSync5(runtimePath)) return null;
6914
6450
  try {
6915
- const raw = readFileSync4(runtimePath, "utf8");
6451
+ const raw = readFileSync3(runtimePath, "utf8");
6916
6452
  const parsed = JSON.parse(raw);
6917
6453
  const nodeExec = parsed["node_exec"];
6918
6454
  if (typeof nodeExec !== "string" || nodeExec.trim().length === 0) {
@@ -6952,18 +6488,18 @@ function sleep2(ms) {
6952
6488
  import { randomUUID as randomUUID10 } from "crypto";
6953
6489
 
6954
6490
  // src/credit/escrow-receipt.ts
6955
- import { z as z8 } from "zod";
6491
+ import { z as z7 } from "zod";
6956
6492
  import { randomUUID as randomUUID9 } from "crypto";
6957
- var EscrowReceiptSchema = z8.object({
6958
- requester_owner: z8.string().min(1),
6959
- requester_agent_id: z8.string().optional(),
6960
- requester_public_key: z8.string().min(1),
6961
- amount: z8.number().positive(),
6962
- card_id: z8.string().min(1),
6963
- skill_id: z8.string().optional(),
6964
- timestamp: z8.string(),
6965
- nonce: z8.string().uuid(),
6966
- signature: z8.string().min(1)
6493
+ var EscrowReceiptSchema = z7.object({
6494
+ requester_owner: z7.string().min(1),
6495
+ requester_agent_id: z7.string().optional(),
6496
+ requester_public_key: z7.string().min(1),
6497
+ amount: z7.number().positive(),
6498
+ card_id: z7.string().min(1),
6499
+ skill_id: z7.string().optional(),
6500
+ timestamp: z7.string(),
6501
+ nonce: z7.string().uuid(),
6502
+ signature: z7.string().min(1)
6967
6503
  });
6968
6504
  function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
6969
6505
  const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
@@ -7329,16 +6865,16 @@ function isNetworkError(err) {
7329
6865
  }
7330
6866
 
7331
6867
  // skills/agentbnb/openclaw-tools.ts
7332
- import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
7333
- import { join as join6 } from "path";
6868
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
6869
+ import { join as join5 } from "path";
7334
6870
  import { homedir as homedir3 } from "os";
7335
6871
 
7336
6872
  // src/mcp/tools/discover.ts
7337
- import { z as z9 } from "zod";
6873
+ import { z as z8 } from "zod";
7338
6874
  var discoverInputSchema = {
7339
- query: z9.string().describe("Natural language search query"),
7340
- level: z9.number().optional().describe("Filter by capability level (1=Atomic, 2=Pipeline, 3=Environment)"),
7341
- online_only: z9.boolean().optional().describe("Only show online agents")
6875
+ query: z8.string().describe("Natural language search query"),
6876
+ level: z8.number().optional().describe("Filter by capability level (1=Atomic, 2=Pipeline, 3=Environment)"),
6877
+ online_only: z8.boolean().optional().describe("Only show online agents")
7342
6878
  };
7343
6879
  async function handleDiscover(args, ctx) {
7344
6880
  try {
@@ -7396,14 +6932,14 @@ async function handleDiscover(args, ctx) {
7396
6932
  }
7397
6933
 
7398
6934
  // src/mcp/tools/request.ts
7399
- import { z as z10 } from "zod";
6935
+ import { z as z9 } from "zod";
7400
6936
  var requestInputSchema = {
7401
- query: z10.string().optional().describe("Search query to find a matching capability (auto-request mode)"),
7402
- card_id: z10.string().optional().describe("Direct card ID to request (skips search)"),
7403
- skill_id: z10.string().optional().describe("Specific skill within a v2.0 card"),
7404
- params: z10.record(z10.unknown()).optional().describe("Input parameters for the capability"),
7405
- max_cost: z10.number().optional().default(50).describe("Maximum credits to spend"),
7406
- timeout_ms: z10.number().positive().optional().describe("Requester timeout override in milliseconds")
6937
+ query: z9.string().optional().describe("Search query to find a matching capability (auto-request mode)"),
6938
+ card_id: z9.string().optional().describe("Direct card ID to request (skips search)"),
6939
+ skill_id: z9.string().optional().describe("Specific skill within a v2.0 card"),
6940
+ params: z9.record(z9.unknown()).optional().describe("Input parameters for the capability"),
6941
+ max_cost: z9.number().optional().default(50).describe("Maximum credits to spend"),
6942
+ timeout_ms: z9.number().positive().optional().describe("Requester timeout override in milliseconds")
7407
6943
  };
7408
6944
  function parsePositiveNumber(value) {
7409
6945
  return typeof value === "number" && value > 0 ? value : void 0;
@@ -7603,7 +7139,7 @@ async function handleRequest(args, ctx) {
7603
7139
  }
7604
7140
 
7605
7141
  // src/mcp/tools/conduct.ts
7606
- import { z as z11 } from "zod";
7142
+ import { z as z10 } from "zod";
7607
7143
 
7608
7144
  // src/cli/conduct.ts
7609
7145
  async function conductAction(task, opts) {
@@ -7741,9 +7277,9 @@ async function conductAction(task, opts) {
7741
7277
 
7742
7278
  // src/mcp/tools/conduct.ts
7743
7279
  var conductInputSchema = {
7744
- task: z11.string().describe("Natural language task description"),
7745
- plan_only: z11.boolean().optional().default(false).describe("If true, return execution plan without executing"),
7746
- max_budget: z11.number().optional().default(100).describe("Maximum credits to spend")
7280
+ task: z10.string().describe("Natural language task description"),
7281
+ plan_only: z10.boolean().optional().default(false).describe("If true, return execution plan without executing"),
7282
+ max_budget: z10.number().optional().default(100).describe("Maximum credits to spend")
7747
7283
  };
7748
7284
  async function handleConduct(args, _ctx) {
7749
7285
  try {
@@ -7763,14 +7299,26 @@ async function handleConduct(args, _ctx) {
7763
7299
  }
7764
7300
 
7765
7301
  // src/mcp/tools/status.ts
7766
- import { z as z12 } from "zod";
7302
+ import { z as z11 } from "zod";
7767
7303
  var statusInputSchema = {
7768
- _unused: z12.string().optional().describe("No parameters needed")
7304
+ _unused: z11.string().optional().describe("No parameters needed")
7769
7305
  };
7306
+ function readLocalBalance(creditDbPath, creditKey) {
7307
+ const creditDb = openCreditDb(creditDbPath);
7308
+ try {
7309
+ return getBalance(creditDb, creditKey);
7310
+ } catch {
7311
+ return 0;
7312
+ } finally {
7313
+ creditDb.close();
7314
+ }
7315
+ }
7770
7316
  async function handleStatus(ctx) {
7771
7317
  try {
7772
- let balance = 0;
7773
7318
  const creditKey = ctx.identity.agent_id ?? ctx.identity.owner;
7319
+ const local_balance = readLocalBalance(ctx.config.credit_db_path, creditKey);
7320
+ let registry_balance = null;
7321
+ let sync_needed = false;
7774
7322
  if (ctx.config.registry) {
7775
7323
  try {
7776
7324
  const keys = loadKeyPair(ctx.configDir);
@@ -7779,28 +7327,19 @@ async function handleStatus(ctx) {
7779
7327
  ownerPublicKey: ctx.identity.public_key,
7780
7328
  privateKey: keys.privateKey
7781
7329
  });
7782
- balance = await ledger.getBalance(creditKey);
7330
+ registry_balance = await ledger.getBalance(creditKey);
7331
+ sync_needed = Math.abs(registry_balance - local_balance) > 1;
7783
7332
  } catch {
7784
- const creditDb = openCreditDb(ctx.config.credit_db_path);
7785
- try {
7786
- balance = getBalance(creditDb, creditKey);
7787
- } finally {
7788
- creditDb.close();
7789
- }
7790
- }
7791
- } else {
7792
- const creditDb = openCreditDb(ctx.config.credit_db_path);
7793
- try {
7794
- balance = getBalance(creditDb, creditKey);
7795
- } finally {
7796
- creditDb.close();
7797
7333
  }
7798
7334
  }
7335
+ const balance = registry_balance ?? local_balance;
7799
7336
  const result = {
7800
7337
  agent_id: ctx.identity.agent_id,
7801
7338
  owner: ctx.identity.owner,
7802
7339
  public_key: ctx.identity.public_key,
7803
7340
  balance,
7341
+ local_balance,
7342
+ ...ctx.config.registry ? { registry_balance, sync_needed } : {},
7804
7343
  registry_url: ctx.config.registry ?? null,
7805
7344
  config_dir: ctx.configDir
7806
7345
  };
@@ -7816,9 +7355,9 @@ async function handleStatus(ctx) {
7816
7355
  }
7817
7356
 
7818
7357
  // src/mcp/tools/publish.ts
7819
- import { z as z13 } from "zod";
7358
+ import { z as z12 } from "zod";
7820
7359
  var publishInputSchema = {
7821
- card_json: z13.string().describe("JSON string of the capability card to publish")
7360
+ card_json: z12.string().describe("JSON string of the capability card to publish")
7822
7361
  };
7823
7362
  async function handlePublish(args, ctx) {
7824
7363
  try {
@@ -7898,24 +7437,24 @@ async function handlePublish(args, ctx) {
7898
7437
  var contextCache = /* @__PURE__ */ new Map();
7899
7438
  function resolveConfigDir(toolCtx) {
7900
7439
  if (toolCtx.agentDir) {
7901
- return toolCtx.agentDir.endsWith(".agentbnb") ? toolCtx.agentDir : join6(toolCtx.agentDir, ".agentbnb");
7440
+ return toolCtx.agentDir.endsWith(".agentbnb") ? toolCtx.agentDir : join5(toolCtx.agentDir, ".agentbnb");
7902
7441
  }
7903
7442
  if (toolCtx.workspaceDir) {
7904
- return join6(toolCtx.workspaceDir, ".agentbnb");
7443
+ return join5(toolCtx.workspaceDir, ".agentbnb");
7905
7444
  }
7906
- return join6(homedir3(), ".agentbnb");
7445
+ return join5(homedir3(), ".agentbnb");
7907
7446
  }
7908
7447
  function buildMcpContext(toolCtx) {
7909
7448
  const configDir = resolveConfigDir(toolCtx);
7910
7449
  const cached = contextCache.get(configDir);
7911
7450
  if (cached) return cached;
7912
- const configPath = join6(configDir, "config.json");
7913
- if (!existsSync7(configPath)) {
7451
+ const configPath = join5(configDir, "config.json");
7452
+ if (!existsSync6(configPath)) {
7914
7453
  throw new Error(
7915
7454
  `AgentBnB not initialized at ${configDir}. Run \`agentbnb init\` or activate the plugin first.`
7916
7455
  );
7917
7456
  }
7918
- const config = JSON.parse(readFileSync5(configPath, "utf-8"));
7457
+ const config = JSON.parse(readFileSync4(configPath, "utf-8"));
7919
7458
  const identity = ensureIdentity(configDir, config.owner);
7920
7459
  const ctx = { configDir, config, identity };
7921
7460
  contextCache.set(configDir, ctx);
@@ -8075,18 +7614,18 @@ function resolveWorkspaceDir() {
8075
7614
  if (process.env["AGENTBNB_DIR"]) {
8076
7615
  return process.env["AGENTBNB_DIR"];
8077
7616
  }
8078
- const openclawAgentsDir = join7(homedir4(), ".openclaw", "agents");
7617
+ const openclawAgentsDir = join6(homedir4(), ".openclaw", "agents");
8079
7618
  const cwd = process.cwd();
8080
7619
  if (cwd.startsWith(openclawAgentsDir + "/")) {
8081
7620
  const relative = cwd.slice(openclawAgentsDir.length + 1);
8082
7621
  const agentName = relative.split("/")[0];
8083
- return join7(openclawAgentsDir, agentName, ".agentbnb");
7622
+ return join6(openclawAgentsDir, agentName, ".agentbnb");
8084
7623
  }
8085
- return join7(homedir4(), ".agentbnb");
7624
+ return join6(homedir4(), ".agentbnb");
8086
7625
  }
8087
7626
  function registerDecomposerCard(configDir, owner) {
8088
7627
  try {
8089
- const db = openDatabase(join7(configDir, "registry.db"));
7628
+ const db = openDatabase(join6(configDir, "registry.db"));
8090
7629
  const existing = db.prepare(
8091
7630
  "SELECT id FROM capability_cards WHERE owner = ? AND json_extract(data, '$.capability_type') = ?"
8092
7631
  ).get(owner, "task_decomposition");
@@ -8216,7 +7755,7 @@ function writeBootstrapMd(bootstrapPath, configDir) {
8216
7755
  "---",
8217
7756
  "_Generated by AgentBnB bootstrap on first install._"
8218
7757
  ].join("\n");
8219
- writeFileSync3(bootstrapPath, content, "utf-8");
7758
+ writeFileSync2(bootstrapPath, content, "utf-8");
8220
7759
  }
8221
7760
  async function activate(config = {}, _onboardDeps) {
8222
7761
  const debug = process.env["AGENTBNB_DEBUG"] === "1";
@@ -8225,7 +7764,7 @@ async function activate(config = {}, _onboardDeps) {
8225
7764
  if (debug) process.stderr.write(`[agentbnb] AGENTBNB_DIR set from config.agentDir: ${config.agentDir}
8226
7765
  `);
8227
7766
  } else if (config.workspaceDir) {
8228
- const derived = join7(config.workspaceDir, ".agentbnb");
7767
+ const derived = join6(config.workspaceDir, ".agentbnb");
8229
7768
  process.env["AGENTBNB_DIR"] = derived;
8230
7769
  if (debug) process.stderr.write(`[agentbnb] AGENTBNB_DIR derived from config.workspaceDir: ${derived}
8231
7770
  `);
@@ -8245,11 +7784,11 @@ async function activate(config = {}, _onboardDeps) {
8245
7784
  let agentConfig = loadConfig();
8246
7785
  if (!agentConfig) {
8247
7786
  const agentName = deriveAgentName(configDir);
8248
- const brainsDir = join7(homedir4(), ".openclaw", "workspace", "brains");
8249
- const brainDir = join7(brainsDir, agentName);
8250
- if (existsSync8(brainDir)) {
8251
- const bootstrapPath = join7(brainDir, "BOOTSTRAP.md");
8252
- if (!existsSync8(bootstrapPath)) {
7787
+ const brainsDir = join6(homedir4(), ".openclaw", "workspace", "brains");
7788
+ const brainDir = join6(brainsDir, agentName);
7789
+ if (existsSync7(brainDir)) {
7790
+ const bootstrapPath = join6(brainDir, "BOOTSTRAP.md");
7791
+ if (!existsSync7(bootstrapPath)) {
8253
7792
  try {
8254
7793
  writeBootstrapMd(bootstrapPath, configDir);
8255
7794
  if (debug) process.stderr.write("[agentbnb] Created BOOTSTRAP.md for first-run setup\n");
@@ -8265,7 +7804,7 @@ async function activate(config = {}, _onboardDeps) {
8265
7804
  `
8266
7805
  );
8267
7806
  }
8268
- const guard = new ProcessGuard(join7(configDir, ".pid"));
7807
+ const guard = new ProcessGuard(join6(configDir, ".pid"));
8269
7808
  const coordinator = new ServiceCoordinator(agentConfig, guard);
8270
7809
  const service = new AgentBnBService(coordinator, agentConfig);
8271
7810
  const opts = {