agentbnb 8.4.4 → 8.4.7

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/index.js CHANGED
@@ -1251,11 +1251,47 @@ function openCreditDb(path = ":memory:") {
1251
1251
  ensureAgentsTable(db);
1252
1252
  return db;
1253
1253
  }
1254
+ function bootstrapAgent(db, owner, amount = 100) {
1255
+ const canonicalOwner = canonicalizeCreditOwner(db, owner);
1256
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1257
+ let isNew = false;
1258
+ db.transaction(() => {
1259
+ const result = db.prepare("INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, ?, ?)").run(canonicalOwner, amount, now);
1260
+ if (result.changes > 0) {
1261
+ isNew = true;
1262
+ db.prepare(
1263
+ "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
1264
+ ).run(randomUUID3(), canonicalOwner, amount, "bootstrap", null, now);
1265
+ }
1266
+ })();
1267
+ if (isNew) {
1268
+ issueVoucher(db, canonicalOwner, 50, 30);
1269
+ }
1270
+ }
1254
1271
  function getBalance(db, owner) {
1255
1272
  const canonicalOwner = canonicalizeCreditOwner(db, owner);
1256
1273
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(canonicalOwner);
1257
1274
  return row?.balance ?? 0;
1258
1275
  }
1276
+ function getTransactions(db, owner, opts = 100) {
1277
+ const canonicalOwner = canonicalizeCreditOwner(db, owner);
1278
+ const page = typeof opts === "number" ? { limit: opts } : opts;
1279
+ const limit = page.limit ?? 100;
1280
+ const conditions = ["owner = ?"];
1281
+ const params = [canonicalOwner];
1282
+ if (page.before) {
1283
+ conditions.push("created_at < ?");
1284
+ params.push(page.before);
1285
+ }
1286
+ if (page.after) {
1287
+ conditions.push("created_at > ?");
1288
+ params.push(page.after);
1289
+ }
1290
+ params.push(limit);
1291
+ return db.prepare(
1292
+ `SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
1293
+ ).all(...params);
1294
+ }
1259
1295
  function registerProvider(db, owner) {
1260
1296
  const canonicalOwner = canonicalizeCreditOwner(db, owner);
1261
1297
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1275,6 +1311,16 @@ function getProviderBonus(providerNumber) {
1275
1311
  if (providerNumber <= 200) return 1.5;
1276
1312
  return 1;
1277
1313
  }
1314
+ function issueVoucher(db, owner, amount = 50, daysValid = 30) {
1315
+ const canonicalOwner = canonicalizeCreditOwner(db, owner);
1316
+ const id = randomUUID3();
1317
+ const now = /* @__PURE__ */ new Date();
1318
+ const expiresAt = new Date(now.getTime() + daysValid * 24 * 60 * 60 * 1e3);
1319
+ db.prepare(
1320
+ "INSERT INTO demand_vouchers (id, owner, amount, remaining, created_at, expires_at, is_active) VALUES (?, ?, ?, ?, ?, ?, 1)"
1321
+ ).run(id, canonicalOwner, amount, amount, now.toISOString(), expiresAt.toISOString());
1322
+ return id;
1323
+ }
1278
1324
  function getActiveVoucher(db, owner) {
1279
1325
  const canonicalOwner = canonicalizeCreditOwner(db, owner);
1280
1326
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1307,6 +1353,11 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
1307
1353
  ).run(randomUUID3(), canonicalOwner, amount, "remote_earning", receiptNonce, now);
1308
1354
  })();
1309
1355
  }
1356
+ function migrateOwner(db, oldOwner, newOwner) {
1357
+ if (oldOwner === newOwner) return;
1358
+ const canonicalNewOwner = canonicalizeCreditOwner(db, newOwner);
1359
+ migrateCreditOwnerData(db, oldOwner, canonicalNewOwner);
1360
+ }
1310
1361
 
1311
1362
  // src/gateway/server.ts
1312
1363
  import Fastify from "fastify";
@@ -1524,6 +1575,629 @@ function loadConfig() {
1524
1575
  }
1525
1576
  }
1526
1577
 
1578
+ // src/identity/identity.ts
1579
+ import { z as z2 } from "zod";
1580
+ import { createHash, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
1581
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1582
+ import { join as join3 } from "path";
1583
+
1584
+ // src/credit/signing.ts
1585
+ import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
1586
+ import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, chmodSync } from "fs";
1587
+ import { join as join2 } from "path";
1588
+ function generateKeyPair() {
1589
+ const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
1590
+ publicKeyEncoding: { type: "spki", format: "der" },
1591
+ privateKeyEncoding: { type: "pkcs8", format: "der" }
1592
+ });
1593
+ return {
1594
+ publicKey: Buffer.from(publicKey),
1595
+ privateKey: Buffer.from(privateKey)
1596
+ };
1597
+ }
1598
+ function saveKeyPair(configDir, keys) {
1599
+ const privatePath = join2(configDir, "private.key");
1600
+ const publicPath = join2(configDir, "public.key");
1601
+ writeFileSync2(privatePath, keys.privateKey);
1602
+ chmodSync(privatePath, 384);
1603
+ writeFileSync2(publicPath, keys.publicKey);
1604
+ }
1605
+ function loadKeyPair(configDir) {
1606
+ const privatePath = join2(configDir, "private.key");
1607
+ const publicPath = join2(configDir, "public.key");
1608
+ if (!existsSync2(privatePath) || !existsSync2(publicPath)) {
1609
+ throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
1610
+ }
1611
+ return {
1612
+ publicKey: readFileSync2(publicPath),
1613
+ privateKey: readFileSync2(privatePath)
1614
+ };
1615
+ }
1616
+ function canonicalJson(data) {
1617
+ return JSON.stringify(sortForCanonicalJson(data));
1618
+ }
1619
+ function sortForCanonicalJson(value) {
1620
+ if (Array.isArray(value)) {
1621
+ return value.map((item) => sortForCanonicalJson(item));
1622
+ }
1623
+ if (value !== null && typeof value === "object") {
1624
+ const proto = Object.getPrototypeOf(value);
1625
+ if (proto === Object.prototype || proto === null) {
1626
+ const input = value;
1627
+ const output = {};
1628
+ const sortedKeys = Object.keys(input).sort();
1629
+ for (const key of sortedKeys) {
1630
+ output[key] = sortForCanonicalJson(input[key]);
1631
+ }
1632
+ return output;
1633
+ }
1634
+ }
1635
+ return value;
1636
+ }
1637
+ function signEscrowReceipt(data, privateKey) {
1638
+ const message = Buffer.from(canonicalJson(data), "utf-8");
1639
+ const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
1640
+ const signature = sign(null, message, keyObject);
1641
+ return signature.toString("base64url");
1642
+ }
1643
+ function verifyEscrowReceipt(data, signature, publicKey) {
1644
+ try {
1645
+ const message = Buffer.from(canonicalJson(data), "utf-8");
1646
+ const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
1647
+ const sigBuffer = Buffer.from(signature, "base64url");
1648
+ return verify(null, message, keyObject, sigBuffer);
1649
+ } catch {
1650
+ return false;
1651
+ }
1652
+ }
1653
+
1654
+ // src/identity/identity.ts
1655
+ var AgentIdentitySchema = z2.object({
1656
+ /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
1657
+ agent_id: z2.string().min(1),
1658
+ /** Human-readable owner name (from config or init). */
1659
+ owner: z2.string().min(1),
1660
+ /** Hex-encoded Ed25519 public key. */
1661
+ public_key: z2.string().min(1),
1662
+ /** ISO 8601 timestamp of identity creation. */
1663
+ created_at: z2.string().datetime(),
1664
+ /** Optional guarantor info if linked to a human. */
1665
+ guarantor: z2.object({
1666
+ github_login: z2.string().min(1),
1667
+ verified_at: z2.string().datetime()
1668
+ }).optional()
1669
+ });
1670
+ var AgentCertificateSchema = z2.object({
1671
+ identity: AgentIdentitySchema,
1672
+ /** ISO 8601 timestamp of certificate issuance. */
1673
+ issued_at: z2.string().datetime(),
1674
+ /** ISO 8601 timestamp of certificate expiry. */
1675
+ expires_at: z2.string().datetime(),
1676
+ /** Hex-encoded public key of the issuer (same as identity for self-signed). */
1677
+ issuer_public_key: z2.string().min(1),
1678
+ /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
1679
+ signature: z2.string().min(1)
1680
+ });
1681
+ var IDENTITY_FILENAME = "identity.json";
1682
+ var PRIVATE_KEY_FILENAME = "private.key";
1683
+ var PUBLIC_KEY_FILENAME = "public.key";
1684
+ function derivePublicKeyFromPrivate(privateKey) {
1685
+ const privateKeyObject = createPrivateKey2({ key: privateKey, format: "der", type: "pkcs8" });
1686
+ const publicKeyObject = createPublicKey2(privateKeyObject);
1687
+ const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
1688
+ return Buffer.from(publicKey);
1689
+ }
1690
+ function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
1691
+ const publicKeyHex = publicKey.toString("hex");
1692
+ return {
1693
+ agent_id: deriveAgentId(publicKeyHex),
1694
+ owner,
1695
+ public_key: publicKeyHex,
1696
+ created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
1697
+ };
1698
+ }
1699
+ function generateFreshIdentity(configDir, owner) {
1700
+ const keys = generateKeyPair();
1701
+ saveKeyPair(configDir, keys);
1702
+ const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
1703
+ saveIdentity(configDir, identity);
1704
+ return { identity, keys, status: "generated" };
1705
+ }
1706
+ function deriveAgentId(publicKeyHex) {
1707
+ return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
1708
+ }
1709
+ function createIdentity(configDir, owner) {
1710
+ if (!existsSync3(configDir)) {
1711
+ mkdirSync2(configDir, { recursive: true });
1712
+ }
1713
+ let keys;
1714
+ try {
1715
+ keys = loadKeyPair(configDir);
1716
+ } catch {
1717
+ keys = generateKeyPair();
1718
+ saveKeyPair(configDir, keys);
1719
+ }
1720
+ const publicKeyHex = keys.publicKey.toString("hex");
1721
+ const agentId = deriveAgentId(publicKeyHex);
1722
+ const identity = {
1723
+ agent_id: agentId,
1724
+ owner,
1725
+ public_key: publicKeyHex,
1726
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
1727
+ };
1728
+ saveIdentity(configDir, identity);
1729
+ return identity;
1730
+ }
1731
+ function loadIdentity(configDir) {
1732
+ const filePath = join3(configDir, IDENTITY_FILENAME);
1733
+ if (!existsSync3(filePath)) return null;
1734
+ try {
1735
+ const raw = readFileSync3(filePath, "utf-8");
1736
+ return AgentIdentitySchema.parse(JSON.parse(raw));
1737
+ } catch {
1738
+ return null;
1739
+ }
1740
+ }
1741
+ function saveIdentity(configDir, identity) {
1742
+ if (!existsSync3(configDir)) {
1743
+ mkdirSync2(configDir, { recursive: true });
1744
+ }
1745
+ const filePath = join3(configDir, IDENTITY_FILENAME);
1746
+ writeFileSync3(filePath, JSON.stringify(identity, null, 2), "utf-8");
1747
+ }
1748
+ function loadOrRepairIdentity(configDir, ownerHint) {
1749
+ if (!existsSync3(configDir)) {
1750
+ mkdirSync2(configDir, { recursive: true });
1751
+ }
1752
+ const identityPath = join3(configDir, IDENTITY_FILENAME);
1753
+ const privateKeyPath = join3(configDir, PRIVATE_KEY_FILENAME);
1754
+ const publicKeyPath = join3(configDir, PUBLIC_KEY_FILENAME);
1755
+ const hasIdentity = existsSync3(identityPath);
1756
+ const hasPrivateKey = existsSync3(privateKeyPath);
1757
+ const hasPublicKey = existsSync3(publicKeyPath);
1758
+ if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
1759
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
1760
+ }
1761
+ let keys;
1762
+ try {
1763
+ keys = loadKeyPair(configDir);
1764
+ } catch {
1765
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
1766
+ }
1767
+ let derivedPublicKey;
1768
+ try {
1769
+ derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
1770
+ } catch {
1771
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
1772
+ }
1773
+ let keypairRepaired = false;
1774
+ if (!keys.publicKey.equals(derivedPublicKey)) {
1775
+ keypairRepaired = true;
1776
+ keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
1777
+ saveKeyPair(configDir, keys);
1778
+ }
1779
+ const loadedIdentity = loadIdentity(configDir);
1780
+ const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
1781
+ const expectedPublicKeyHex = derivedPublicKey.toString("hex");
1782
+ const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
1783
+ if (identityMismatch) {
1784
+ const repairedIdentity = buildIdentityFromPublicKey(
1785
+ derivedPublicKey,
1786
+ loadedIdentity?.owner ?? ownerHint ?? "agent",
1787
+ loadedIdentity?.created_at
1788
+ );
1789
+ saveIdentity(configDir, repairedIdentity);
1790
+ return { identity: repairedIdentity, keys, status: "repaired" };
1791
+ }
1792
+ if (ownerHint && loadedIdentity.owner !== ownerHint) {
1793
+ const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
1794
+ saveIdentity(configDir, updatedIdentity);
1795
+ return { identity: updatedIdentity, keys, status: "repaired" };
1796
+ }
1797
+ return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
1798
+ }
1799
+ function issueAgentCertificate(identity, privateKey) {
1800
+ const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
1801
+ const expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toISOString();
1802
+ const payload = {
1803
+ identity,
1804
+ issued_at: issuedAt,
1805
+ expires_at: expiresAt,
1806
+ issuer_public_key: identity.public_key
1807
+ };
1808
+ const signature = signEscrowReceipt(payload, privateKey);
1809
+ return {
1810
+ identity,
1811
+ issued_at: issuedAt,
1812
+ expires_at: expiresAt,
1813
+ issuer_public_key: identity.public_key,
1814
+ signature
1815
+ };
1816
+ }
1817
+ function verifyAgentCertificate(cert) {
1818
+ if (new Date(cert.expires_at) < /* @__PURE__ */ new Date()) {
1819
+ return false;
1820
+ }
1821
+ const publicKeyHex = cert.issuer_public_key;
1822
+ const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
1823
+ const payload = {
1824
+ identity: cert.identity,
1825
+ issued_at: cert.issued_at,
1826
+ expires_at: cert.expires_at,
1827
+ issuer_public_key: cert.issuer_public_key
1828
+ };
1829
+ return verifyEscrowReceipt(payload, cert.signature, publicKeyBuf);
1830
+ }
1831
+ function ensureIdentity(configDir, owner) {
1832
+ return loadOrRepairIdentity(configDir, owner).identity;
1833
+ }
1834
+
1835
+ // src/credit/local-credit-ledger.ts
1836
+ var LocalCreditLedger = class {
1837
+ constructor(db) {
1838
+ this.db = db;
1839
+ }
1840
+ /**
1841
+ * Holds credits in escrow during capability execution.
1842
+ *
1843
+ * @param owner - Agent identifier (requester).
1844
+ * @param amount - Number of credits to hold.
1845
+ * @param cardId - Capability Card ID being requested.
1846
+ * @returns EscrowResult with the new escrowId.
1847
+ * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
1848
+ */
1849
+ async hold(owner, amount, cardId) {
1850
+ const escrowId = holdEscrow(this.db, owner, amount, cardId);
1851
+ return { escrowId };
1852
+ }
1853
+ /**
1854
+ * Settles an escrow — transfers held credits to the capability provider.
1855
+ *
1856
+ * @param escrowId - The escrow ID to settle.
1857
+ * @param recipientOwner - Agent identifier who will receive the credits.
1858
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1859
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1860
+ */
1861
+ async settle(escrowId, recipientOwner) {
1862
+ settleEscrow(this.db, escrowId, recipientOwner);
1863
+ }
1864
+ /**
1865
+ * Releases an escrow — refunds credits back to the requester.
1866
+ *
1867
+ * @param escrowId - The escrow ID to release.
1868
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1869
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1870
+ */
1871
+ async release(escrowId) {
1872
+ releaseEscrow(this.db, escrowId);
1873
+ }
1874
+ /**
1875
+ * Returns the current credit balance for an agent.
1876
+ *
1877
+ * @param owner - Agent identifier.
1878
+ * @returns Current balance in credits (0 if agent is unknown).
1879
+ */
1880
+ async getBalance(owner) {
1881
+ return getBalance(this.db, owner);
1882
+ }
1883
+ /**
1884
+ * Returns the transaction history for an agent, newest first.
1885
+ *
1886
+ * @param owner - Agent identifier.
1887
+ * @param limit - Maximum number of transactions to return. Defaults to 100.
1888
+ * @returns Array of credit transactions ordered newest first.
1889
+ */
1890
+ async getHistory(owner, limit) {
1891
+ return getTransactions(this.db, owner, limit);
1892
+ }
1893
+ /**
1894
+ * Grants initial credits to an agent (bootstrap grant).
1895
+ * Idempotent — calling multiple times has no additional effect on balance.
1896
+ *
1897
+ * @param owner - Agent identifier.
1898
+ * @param amount - Number of credits to grant. Defaults to 100.
1899
+ */
1900
+ async grant(owner, amount) {
1901
+ bootstrapAgent(this.db, owner, amount);
1902
+ }
1903
+ async rename(oldOwner, newOwner) {
1904
+ migrateOwner(this.db, oldOwner, newOwner);
1905
+ }
1906
+ };
1907
+
1908
+ // src/registry/identity-auth.ts
1909
+ var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
1910
+ function normalizeSignedParams(body) {
1911
+ return body === void 0 ? null : body;
1912
+ }
1913
+ function buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, params) {
1914
+ return {
1915
+ method,
1916
+ path,
1917
+ timestamp,
1918
+ publicKey: publicKeyHex,
1919
+ agentId,
1920
+ params: normalizeSignedParams(params)
1921
+ };
1922
+ }
1923
+ function signRequest(method, path, body, privateKey, publicKeyHex, agentIdOverride) {
1924
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1925
+ const agentId = agentIdOverride ?? deriveAgentId(publicKeyHex);
1926
+ const payload = buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, body);
1927
+ const signature = signEscrowReceipt(payload, privateKey);
1928
+ return {
1929
+ "X-Agent-Id": agentId,
1930
+ "X-Agent-PublicKey": publicKeyHex,
1931
+ "X-Agent-Signature": signature,
1932
+ "X-Agent-Timestamp": timestamp
1933
+ };
1934
+ }
1935
+
1936
+ // src/credit/registry-credit-ledger.ts
1937
+ var HTTP_TIMEOUT_MS = 1e4;
1938
+ var RegistryCreditLedger = class {
1939
+ config;
1940
+ constructor(config) {
1941
+ this.config = config;
1942
+ }
1943
+ /**
1944
+ * Holds credits in escrow during capability execution.
1945
+ *
1946
+ * @param owner - Agent identifier (requester).
1947
+ * @param amount - Number of credits to hold.
1948
+ * @param cardId - Capability Card ID being requested.
1949
+ * @returns EscrowResult with the new escrowId.
1950
+ * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
1951
+ */
1952
+ async hold(owner, amount, cardId) {
1953
+ if (this.config.mode === "direct") {
1954
+ const escrowId = holdEscrow(this.config.db, owner, amount, cardId);
1955
+ return { escrowId };
1956
+ }
1957
+ const data = await this.post("/api/credits/hold", owner, {
1958
+ owner,
1959
+ amount,
1960
+ cardId
1961
+ });
1962
+ return { escrowId: data.escrowId };
1963
+ }
1964
+ /**
1965
+ * Settles an escrow — transfers held credits to the capability provider.
1966
+ *
1967
+ * @param escrowId - The escrow ID to settle.
1968
+ * @param recipientOwner - Agent identifier who will receive the credits.
1969
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1970
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1971
+ */
1972
+ async settle(escrowId, recipientOwner) {
1973
+ if (this.config.mode === "direct") {
1974
+ settleEscrow(this.config.db, escrowId, recipientOwner);
1975
+ return;
1976
+ }
1977
+ await this.post("/api/credits/settle", null, { escrowId, recipientOwner });
1978
+ }
1979
+ /**
1980
+ * Releases an escrow — refunds credits back to the requester.
1981
+ *
1982
+ * @param escrowId - The escrow ID to release.
1983
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
1984
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
1985
+ */
1986
+ async release(escrowId) {
1987
+ if (this.config.mode === "direct") {
1988
+ releaseEscrow(this.config.db, escrowId);
1989
+ return;
1990
+ }
1991
+ await this.post("/api/credits/release", null, { escrowId });
1992
+ }
1993
+ /**
1994
+ * Returns the current credit balance for an agent.
1995
+ *
1996
+ * @param owner - Agent identifier.
1997
+ * @returns Current balance in credits (0 if agent is unknown).
1998
+ */
1999
+ async getBalance(owner) {
2000
+ if (this.config.mode === "direct") {
2001
+ return getBalance(this.config.db, owner);
2002
+ }
2003
+ const data = await this.get(`/api/credits/${owner}`, owner);
2004
+ return data.balance;
2005
+ }
2006
+ /**
2007
+ * Returns the transaction history for an agent, newest first.
2008
+ *
2009
+ * @param owner - Agent identifier.
2010
+ * @param limit - Maximum number of transactions to return. Defaults to 100.
2011
+ * @returns Array of credit transactions ordered newest first.
2012
+ */
2013
+ async getHistory(owner, limit = 100) {
2014
+ if (this.config.mode === "direct") {
2015
+ return getTransactions(this.config.db, owner, limit);
2016
+ }
2017
+ const data = await this.get(
2018
+ `/api/credits/${owner}/history?limit=${limit}`,
2019
+ owner
2020
+ );
2021
+ return data.transactions;
2022
+ }
2023
+ /**
2024
+ * Grants initial credits to an agent (bootstrap grant).
2025
+ * Idempotent — calling multiple times has no additional effect on balance.
2026
+ *
2027
+ * @param owner - Agent identifier.
2028
+ * @param amount - Number of credits to grant. Defaults to 100.
2029
+ */
2030
+ async grant(owner, amount = 100) {
2031
+ if (this.config.mode === "direct") {
2032
+ bootstrapAgent(this.config.db, owner, amount);
2033
+ return;
2034
+ }
2035
+ await this.post("/api/credits/grant", owner, { owner, amount });
2036
+ }
2037
+ /**
2038
+ * Renames an owner — migrates balance, transactions, and escrows.
2039
+ */
2040
+ async rename(oldOwner, newOwner) {
2041
+ if (oldOwner === newOwner) return;
2042
+ if (this.config.mode === "direct") {
2043
+ migrateOwner(this.config.db, oldOwner, newOwner);
2044
+ return;
2045
+ }
2046
+ await this.post("/api/credits/rename", null, { oldOwner, newOwner });
2047
+ }
2048
+ // ─── Private HTTP helpers ─────────────────────────────────────────────────
2049
+ /**
2050
+ * Makes an authenticated POST request to the Registry HTTP API.
2051
+ * Includes a 10s timeout via AbortController.
2052
+ *
2053
+ * @param path - API path (e.g., '/api/credits/hold').
2054
+ * @param ownerForHeader - Agent owner identifier for X-Agent-Owner header, or null to omit.
2055
+ * @param body - JSON body to send.
2056
+ * @returns Parsed JSON response body.
2057
+ * @throws {AgentBnBError} on non-2xx responses or network errors.
2058
+ */
2059
+ async post(path, ownerForHeader, body) {
2060
+ const cfg = this.config;
2061
+ const controller = new AbortController();
2062
+ const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
2063
+ try {
2064
+ const authHeaders = signRequest("POST", path, body, cfg.privateKey, cfg.ownerPublicKey);
2065
+ const headers = {
2066
+ "Content-Type": "application/json",
2067
+ ...authHeaders
2068
+ };
2069
+ void ownerForHeader;
2070
+ const res = await fetch(`${cfg.registryUrl}${path}`, {
2071
+ method: "POST",
2072
+ headers,
2073
+ body: JSON.stringify(body),
2074
+ signal: controller.signal
2075
+ });
2076
+ return await this.handleResponse(res);
2077
+ } catch (err) {
2078
+ if (err instanceof AgentBnBError) throw err;
2079
+ throw new AgentBnBError(
2080
+ `Registry unreachable: ${err.message}`,
2081
+ "REGISTRY_UNREACHABLE"
2082
+ );
2083
+ } finally {
2084
+ clearTimeout(timeoutId);
2085
+ }
2086
+ }
2087
+ /**
2088
+ * Makes an authenticated GET request to the Registry HTTP API.
2089
+ * Includes a 10s timeout via AbortController.
2090
+ *
2091
+ * @param path - API path (e.g., '/api/credits/owner-id').
2092
+ * @param owner - Agent owner identifier for X-Agent-Owner header.
2093
+ * @returns Parsed JSON response body.
2094
+ * @throws {AgentBnBError} on non-2xx responses or network errors.
2095
+ */
2096
+ async get(path, owner) {
2097
+ const cfg = this.config;
2098
+ const controller = new AbortController();
2099
+ const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
2100
+ try {
2101
+ const authHeaders = signRequest("GET", path, null, cfg.privateKey, cfg.ownerPublicKey);
2102
+ void owner;
2103
+ const res = await fetch(`${cfg.registryUrl}${path}`, {
2104
+ method: "GET",
2105
+ headers: {
2106
+ "Content-Type": "application/json",
2107
+ ...authHeaders
2108
+ },
2109
+ signal: controller.signal
2110
+ });
2111
+ return await this.handleResponse(res);
2112
+ } catch (err) {
2113
+ if (err instanceof AgentBnBError) throw err;
2114
+ throw new AgentBnBError(
2115
+ `Registry unreachable: ${err.message}`,
2116
+ "REGISTRY_UNREACHABLE"
2117
+ );
2118
+ } finally {
2119
+ clearTimeout(timeoutId);
2120
+ }
2121
+ }
2122
+ /**
2123
+ * Handles an HTTP response — returns parsed JSON on 2xx, throws AgentBnBError on error.
2124
+ */
2125
+ async handleResponse(res) {
2126
+ const json = await res.json();
2127
+ if (!res.ok) {
2128
+ const code = typeof json["code"] === "string" ? json["code"] : "REGISTRY_ERROR";
2129
+ const message = typeof json["error"] === "string" ? json["error"] : `HTTP ${res.status}`;
2130
+ throw new AgentBnBError(message, code);
2131
+ }
2132
+ return json;
2133
+ }
2134
+ };
2135
+
2136
+ // src/credit/create-ledger.ts
2137
+ function createLedger(opts) {
2138
+ if ("registryUrl" in opts && opts.registryUrl !== void 0) {
2139
+ return new RegistryCreditLedger({
2140
+ mode: "http",
2141
+ registryUrl: opts.registryUrl,
2142
+ ownerPublicKey: opts.ownerPublicKey,
2143
+ privateKey: opts.privateKey
2144
+ });
2145
+ }
2146
+ if ("db" in opts && opts.db !== void 0) {
2147
+ return new RegistryCreditLedger({
2148
+ mode: "direct",
2149
+ db: opts.db
2150
+ });
2151
+ }
2152
+ const db = openCreditDb(opts.creditDbPath);
2153
+ return new LocalCreditLedger(db);
2154
+ }
2155
+
2156
+ // src/credit/registry-sync.ts
2157
+ async function syncCreditsFromRegistry(config, localDb) {
2158
+ if (!config.registry) {
2159
+ return { synced: false, error: "no registry configured" };
2160
+ }
2161
+ try {
2162
+ const configDir = getConfigDir();
2163
+ const { identity, keys } = loadOrRepairIdentity(configDir, config.owner);
2164
+ const ledger = createLedger({
2165
+ registryUrl: config.registry,
2166
+ ownerPublicKey: identity.public_key,
2167
+ privateKey: keys.privateKey
2168
+ });
2169
+ const [remoteBalance, remoteHistory] = await Promise.all([
2170
+ ledger.getBalance(config.owner),
2171
+ ledger.getHistory(config.owner, 50)
2172
+ ]);
2173
+ const localWas = getBalance(localDb, config.owner);
2174
+ localDb.transaction(() => {
2175
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2176
+ const canonicalOwner = canonicalizeCreditOwner(localDb, config.owner);
2177
+ localDb.prepare(
2178
+ "INSERT OR REPLACE INTO credit_balances (owner, balance, updated_at) VALUES (?, ?, ?)"
2179
+ ).run(canonicalOwner, remoteBalance, now);
2180
+ const insertTxn = localDb.prepare(
2181
+ "INSERT OR IGNORE INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
2182
+ );
2183
+ for (const txn of remoteHistory) {
2184
+ insertTxn.run(
2185
+ txn.id,
2186
+ txn.owner,
2187
+ txn.amount,
2188
+ txn.reason,
2189
+ txn.reference_id,
2190
+ txn.created_at
2191
+ );
2192
+ }
2193
+ })();
2194
+ return { synced: true, remoteBalance, localWas };
2195
+ } catch (err) {
2196
+ const message = err instanceof Error ? err.message : String(err);
2197
+ return { synced: false, error: message };
2198
+ }
2199
+ }
2200
+
1527
2201
  // src/cli/remote-registry.ts
1528
2202
  var RegistryTimeoutError = class extends AgentBnBError {
1529
2203
  constructor(url) {
@@ -1705,6 +2379,18 @@ async function executeCapabilityRequest(opts) {
1705
2379
  };
1706
2380
  }
1707
2381
  } else {
2382
+ const cfg = loadConfig();
2383
+ if (cfg?.registry) {
2384
+ try {
2385
+ await Promise.race([
2386
+ syncCreditsFromRegistry(cfg, creditDb),
2387
+ new Promise(
2388
+ (_, reject) => setTimeout(() => reject(new Error("sync timeout")), 2e3)
2389
+ )
2390
+ ]);
2391
+ } catch {
2392
+ }
2393
+ }
1708
2394
  try {
1709
2395
  const balance = getBalance(creditDb, requester);
1710
2396
  if (balance < creditsNeeded) {
@@ -1785,125 +2471,55 @@ async function executeCapabilityRequest(opts) {
1785
2471
  let targetSkillId = resolvedSkillId ?? skillId;
1786
2472
  if (!targetSkillId) {
1787
2473
  const available = skillExecutor.listSkills();
1788
- if (available.length > 0) {
1789
- targetSkillId = available[0];
1790
- } else {
1791
- return handleFailure(
1792
- "failure",
1793
- Date.now() - startMs,
1794
- "No skill_id specified and no skills registered on this provider.",
1795
- "not_found"
1796
- );
1797
- }
1798
- }
1799
- try {
1800
- const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
1801
- if (!execResult.success) {
1802
- return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed", "bad_execution");
1803
- }
1804
- return handleSuccess(execResult.result, execResult.latency_ms);
1805
- } catch (err) {
1806
- const message = err instanceof Error ? err.message : "Execution error";
1807
- return handleFailure("failure", Date.now() - startMs, message, "bad_execution");
1808
- }
1809
- }
1810
- if (!handlerUrl) {
1811
- return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured", "bad_execution");
1812
- }
1813
- const controller = new AbortController();
1814
- const timer = setTimeout(() => controller.abort(), timeoutMs);
1815
- try {
1816
- const response = await fetch(handlerUrl, {
1817
- method: "POST",
1818
- headers: { "Content-Type": "application/json" },
1819
- body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
1820
- signal: controller.signal
1821
- });
1822
- clearTimeout(timer);
1823
- if (!response.ok) {
1824
- return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`, "bad_execution");
1825
- }
1826
- const result = await response.json();
1827
- return handleSuccess(result, Date.now() - startMs);
1828
- } catch (err) {
1829
- clearTimeout(timer);
1830
- const isTimeout = err instanceof Error && err.name === "AbortError";
1831
- return handleFailure(
1832
- isTimeout ? "timeout" : "failure",
1833
- Date.now() - startMs,
1834
- isTimeout ? "Execution timeout" : "Handler error",
1835
- isTimeout ? "timeout" : "bad_execution"
1836
- );
1837
- }
1838
- }
1839
-
1840
- // src/credit/signing.ts
1841
- import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
1842
- import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, chmodSync } from "fs";
1843
- import { join as join2 } from "path";
1844
- function generateKeyPair() {
1845
- const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
1846
- publicKeyEncoding: { type: "spki", format: "der" },
1847
- privateKeyEncoding: { type: "pkcs8", format: "der" }
1848
- });
1849
- return {
1850
- publicKey: Buffer.from(publicKey),
1851
- privateKey: Buffer.from(privateKey)
1852
- };
1853
- }
1854
- function saveKeyPair(configDir, keys) {
1855
- const privatePath = join2(configDir, "private.key");
1856
- const publicPath = join2(configDir, "public.key");
1857
- writeFileSync2(privatePath, keys.privateKey);
1858
- chmodSync(privatePath, 384);
1859
- writeFileSync2(publicPath, keys.publicKey);
1860
- }
1861
- function loadKeyPair(configDir) {
1862
- const privatePath = join2(configDir, "private.key");
1863
- const publicPath = join2(configDir, "public.key");
1864
- if (!existsSync2(privatePath) || !existsSync2(publicPath)) {
1865
- throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
1866
- }
1867
- return {
1868
- publicKey: readFileSync2(publicPath),
1869
- privateKey: readFileSync2(privatePath)
1870
- };
1871
- }
1872
- function canonicalJson(data) {
1873
- return JSON.stringify(sortForCanonicalJson(data));
1874
- }
1875
- function sortForCanonicalJson(value) {
1876
- if (Array.isArray(value)) {
1877
- return value.map((item) => sortForCanonicalJson(item));
1878
- }
1879
- if (value !== null && typeof value === "object") {
1880
- const proto = Object.getPrototypeOf(value);
1881
- if (proto === Object.prototype || proto === null) {
1882
- const input = value;
1883
- const output = {};
1884
- const sortedKeys = Object.keys(input).sort();
1885
- for (const key of sortedKeys) {
1886
- output[key] = sortForCanonicalJson(input[key]);
2474
+ if (available.length > 0) {
2475
+ targetSkillId = available[0];
2476
+ } else {
2477
+ return handleFailure(
2478
+ "failure",
2479
+ Date.now() - startMs,
2480
+ "No skill_id specified and no skills registered on this provider.",
2481
+ "not_found"
2482
+ );
1887
2483
  }
1888
- return output;
2484
+ }
2485
+ try {
2486
+ const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
2487
+ if (!execResult.success) {
2488
+ return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed", "bad_execution");
2489
+ }
2490
+ return handleSuccess(execResult.result, execResult.latency_ms);
2491
+ } catch (err) {
2492
+ const message = err instanceof Error ? err.message : "Execution error";
2493
+ return handleFailure("failure", Date.now() - startMs, message, "bad_execution");
1889
2494
  }
1890
2495
  }
1891
- return value;
1892
- }
1893
- function signEscrowReceipt(data, privateKey) {
1894
- const message = Buffer.from(canonicalJson(data), "utf-8");
1895
- const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
1896
- const signature = sign(null, message, keyObject);
1897
- return signature.toString("base64url");
1898
- }
1899
- function verifyEscrowReceipt(data, signature, publicKey) {
2496
+ if (!handlerUrl) {
2497
+ return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured", "bad_execution");
2498
+ }
2499
+ const controller = new AbortController();
2500
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1900
2501
  try {
1901
- const message = Buffer.from(canonicalJson(data), "utf-8");
1902
- const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
1903
- const sigBuffer = Buffer.from(signature, "base64url");
1904
- return verify(null, message, keyObject, sigBuffer);
1905
- } catch {
1906
- return false;
2502
+ const response = await fetch(handlerUrl, {
2503
+ method: "POST",
2504
+ headers: { "Content-Type": "application/json" },
2505
+ body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
2506
+ signal: controller.signal
2507
+ });
2508
+ clearTimeout(timer);
2509
+ if (!response.ok) {
2510
+ return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`, "bad_execution");
2511
+ }
2512
+ const result = await response.json();
2513
+ return handleSuccess(result, Date.now() - startMs);
2514
+ } catch (err) {
2515
+ clearTimeout(timer);
2516
+ const isTimeout = err instanceof Error && err.name === "AbortError";
2517
+ return handleFailure(
2518
+ isTimeout ? "timeout" : "failure",
2519
+ Date.now() - startMs,
2520
+ isTimeout ? "Execution timeout" : "Handler error",
2521
+ isTimeout ? "timeout" : "bad_execution"
2522
+ );
1907
2523
  }
1908
2524
  }
1909
2525
 
@@ -2217,127 +2833,127 @@ function createSkillExecutor(configs, modes, concurrencyGuard) {
2217
2833
  }
2218
2834
 
2219
2835
  // src/skills/skill-config.ts
2220
- import { z as z2 } from "zod";
2836
+ import { z as z3 } from "zod";
2221
2837
  import yaml from "js-yaml";
2222
- var CapacitySchema = z2.object({
2223
- max_concurrent: z2.number().positive().int().optional()
2838
+ var CapacitySchema = z3.object({
2839
+ max_concurrent: z3.number().positive().int().optional()
2224
2840
  }).optional();
2225
- var PricingSchema = z2.object({
2226
- credits_per_call: z2.number().nonnegative(),
2227
- credits_per_minute: z2.number().nonnegative().optional(),
2228
- free_tier: z2.number().nonnegative().optional()
2841
+ var PricingSchema = z3.object({
2842
+ credits_per_call: z3.number().nonnegative(),
2843
+ credits_per_minute: z3.number().nonnegative().optional(),
2844
+ free_tier: z3.number().nonnegative().optional()
2229
2845
  });
2230
- var ApiAuthSchema = z2.discriminatedUnion("type", [
2231
- z2.object({
2232
- type: z2.literal("bearer"),
2233
- token: z2.string()
2846
+ var ApiAuthSchema = z3.discriminatedUnion("type", [
2847
+ z3.object({
2848
+ type: z3.literal("bearer"),
2849
+ token: z3.string()
2234
2850
  }),
2235
- z2.object({
2236
- type: z2.literal("apikey"),
2237
- header: z2.string().default("X-API-Key"),
2238
- key: z2.string()
2851
+ z3.object({
2852
+ type: z3.literal("apikey"),
2853
+ header: z3.string().default("X-API-Key"),
2854
+ key: z3.string()
2239
2855
  }),
2240
- z2.object({
2241
- type: z2.literal("basic"),
2242
- username: z2.string(),
2243
- password: z2.string()
2856
+ z3.object({
2857
+ type: z3.literal("basic"),
2858
+ username: z3.string(),
2859
+ password: z3.string()
2244
2860
  })
2245
2861
  ]);
2246
2862
  var CapabilityDeclarationSchema = {
2247
- description: z2.string().optional(),
2248
- capability_types: z2.array(z2.string()).optional(),
2249
- requires_capabilities: z2.array(z2.string()).optional(),
2250
- visibility: z2.enum(["public", "private"]).optional(),
2251
- expected_duration_ms: z2.number().positive().optional()
2863
+ description: z3.string().optional(),
2864
+ capability_types: z3.array(z3.string()).optional(),
2865
+ requires_capabilities: z3.array(z3.string()).optional(),
2866
+ visibility: z3.enum(["public", "private"]).optional(),
2867
+ expected_duration_ms: z3.number().positive().optional()
2252
2868
  };
2253
- var ApiSkillConfigSchema = z2.object({
2254
- id: z2.string().min(1),
2255
- type: z2.literal("api"),
2256
- name: z2.string().min(1),
2257
- endpoint: z2.string().min(1),
2258
- method: z2.enum(["GET", "POST", "PUT", "DELETE"]),
2869
+ var ApiSkillConfigSchema = z3.object({
2870
+ id: z3.string().min(1),
2871
+ type: z3.literal("api"),
2872
+ name: z3.string().min(1),
2873
+ endpoint: z3.string().min(1),
2874
+ method: z3.enum(["GET", "POST", "PUT", "DELETE"]),
2259
2875
  auth: ApiAuthSchema.optional(),
2260
- input_mapping: z2.record(z2.string()).default({}),
2261
- output_mapping: z2.record(z2.string()).default({}),
2876
+ input_mapping: z3.record(z3.string()).default({}),
2877
+ output_mapping: z3.record(z3.string()).default({}),
2262
2878
  pricing: PricingSchema,
2263
- timeout_ms: z2.number().positive().default(3e4),
2264
- retries: z2.number().nonnegative().int().default(0),
2265
- provider: z2.string().optional(),
2879
+ timeout_ms: z3.number().positive().default(3e4),
2880
+ retries: z3.number().nonnegative().int().default(0),
2881
+ provider: z3.string().optional(),
2266
2882
  capacity: CapacitySchema,
2267
2883
  ...CapabilityDeclarationSchema
2268
2884
  });
2269
- var PipelineStepSchema = z2.union([
2270
- z2.object({
2271
- skill_id: z2.string().min(1),
2272
- input_mapping: z2.record(z2.string()).default({})
2885
+ var PipelineStepSchema = z3.union([
2886
+ z3.object({
2887
+ skill_id: z3.string().min(1),
2888
+ input_mapping: z3.record(z3.string()).default({})
2273
2889
  }),
2274
- z2.object({
2275
- command: z2.string().min(1),
2276
- input_mapping: z2.record(z2.string()).default({})
2890
+ z3.object({
2891
+ command: z3.string().min(1),
2892
+ input_mapping: z3.record(z3.string()).default({})
2277
2893
  })
2278
2894
  ]);
2279
- var PipelineSkillConfigSchema = z2.object({
2280
- id: z2.string().min(1),
2281
- type: z2.literal("pipeline"),
2282
- name: z2.string().min(1),
2283
- steps: z2.array(PipelineStepSchema).min(1),
2895
+ var PipelineSkillConfigSchema = z3.object({
2896
+ id: z3.string().min(1),
2897
+ type: z3.literal("pipeline"),
2898
+ name: z3.string().min(1),
2899
+ steps: z3.array(PipelineStepSchema).min(1),
2284
2900
  pricing: PricingSchema,
2285
- timeout_ms: z2.number().positive().optional(),
2901
+ timeout_ms: z3.number().positive().optional(),
2286
2902
  capacity: CapacitySchema,
2287
2903
  ...CapabilityDeclarationSchema
2288
2904
  });
2289
- var OpenClawSkillConfigSchema = z2.object({
2290
- id: z2.string().min(1),
2291
- type: z2.literal("openclaw"),
2292
- name: z2.string().min(1),
2293
- agent_name: z2.string().min(1),
2294
- channel: z2.enum(["telegram", "webhook", "process"]),
2905
+ var OpenClawSkillConfigSchema = z3.object({
2906
+ id: z3.string().min(1),
2907
+ type: z3.literal("openclaw"),
2908
+ name: z3.string().min(1),
2909
+ agent_name: z3.string().min(1),
2910
+ channel: z3.enum(["telegram", "webhook", "process"]),
2295
2911
  pricing: PricingSchema,
2296
- timeout_ms: z2.number().positive().optional(),
2912
+ timeout_ms: z3.number().positive().optional(),
2297
2913
  capacity: CapacitySchema,
2298
2914
  ...CapabilityDeclarationSchema
2299
2915
  });
2300
- var ClaudeCodeConfigSchema = z2.object({
2916
+ var ClaudeCodeConfigSchema = z3.object({
2301
2917
  /** Optional system prompt passed via `-p` flag. */
2302
- system_prompt: z2.string().optional(),
2918
+ system_prompt: z3.string().optional(),
2303
2919
  /** Model to use (e.g. 'claude-opus-4-6', 'claude-sonnet-4-6'). */
2304
- model: z2.string().optional(),
2920
+ model: z3.string().optional(),
2305
2921
  /** When true, passes `--dangerously-skip-permissions` to claude CLI. */
2306
- auto_mode: z2.boolean().default(false)
2922
+ auto_mode: z3.boolean().default(false)
2307
2923
  });
2308
- var CommandSkillConfigSchema = z2.object({
2309
- id: z2.string().min(1),
2310
- type: z2.literal("command"),
2311
- name: z2.string().min(1),
2312
- command: z2.string().min(1),
2313
- output_type: z2.enum(["json", "text", "file"]),
2314
- allowed_commands: z2.array(z2.string()).optional(),
2315
- working_dir: z2.string().optional(),
2924
+ var CommandSkillConfigSchema = z3.object({
2925
+ id: z3.string().min(1),
2926
+ type: z3.literal("command"),
2927
+ name: z3.string().min(1),
2928
+ command: z3.string().min(1),
2929
+ output_type: z3.enum(["json", "text", "file"]),
2930
+ allowed_commands: z3.array(z3.string()).optional(),
2931
+ working_dir: z3.string().optional(),
2316
2932
  claude_code: ClaudeCodeConfigSchema.optional(),
2317
- timeout_ms: z2.number().positive().default(3e4),
2933
+ timeout_ms: z3.number().positive().default(3e4),
2318
2934
  pricing: PricingSchema,
2319
2935
  capacity: CapacitySchema,
2320
2936
  ...CapabilityDeclarationSchema
2321
2937
  });
2322
- var ConductorSkillConfigSchema = z2.object({
2323
- id: z2.string().min(1),
2324
- type: z2.literal("conductor"),
2325
- name: z2.string().min(1),
2326
- conductor_skill: z2.enum(["orchestrate", "plan"]),
2938
+ var ConductorSkillConfigSchema = z3.object({
2939
+ id: z3.string().min(1),
2940
+ type: z3.literal("conductor"),
2941
+ name: z3.string().min(1),
2942
+ conductor_skill: z3.enum(["orchestrate", "plan"]),
2327
2943
  pricing: PricingSchema,
2328
- timeout_ms: z2.number().positive().optional(),
2944
+ timeout_ms: z3.number().positive().optional(),
2329
2945
  capacity: CapacitySchema,
2330
2946
  ...CapabilityDeclarationSchema
2331
2947
  });
2332
- var SkillConfigSchema = z2.discriminatedUnion("type", [
2948
+ var SkillConfigSchema = z3.discriminatedUnion("type", [
2333
2949
  ApiSkillConfigSchema,
2334
2950
  PipelineSkillConfigSchema,
2335
2951
  OpenClawSkillConfigSchema,
2336
2952
  CommandSkillConfigSchema,
2337
2953
  ConductorSkillConfigSchema
2338
2954
  ]);
2339
- var SkillsFileSchema = z2.object({
2340
- skills: z2.array(SkillConfigSchema)
2955
+ var SkillsFileSchema = z3.object({
2956
+ skills: z3.array(SkillConfigSchema)
2341
2957
  });
2342
2958
  function expandEnvVars(value) {
2343
2959
  return value.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
@@ -2916,27 +3532,37 @@ var KILL_GRACE_MS = 5e3;
2916
3532
  function shellEscape2(value) {
2917
3533
  return "'" + value.replace(/'/g, "'\\''") + "'";
2918
3534
  }
2919
- function safeInterpolateCommand2(template, context) {
2920
- return template.replace(/\$\{([^}]+)\}/g, (_match, expr) => {
2921
- const parts = expr.split(".");
2922
- let current = context;
2923
- for (const part of parts) {
2924
- if (current === null || typeof current !== "object") return "";
2925
- const bracketMatch = part.match(/^(\w+)\[(\d+)\]$/);
2926
- if (bracketMatch) {
2927
- current = current[bracketMatch[1]];
2928
- if (Array.isArray(current)) {
2929
- current = current[parseInt(bracketMatch[2], 10)];
2930
- } else {
2931
- return "";
2932
- }
3535
+ function resolveExpression(expr, context) {
3536
+ const parts = expr.split(".");
3537
+ let current = context;
3538
+ for (const part of parts) {
3539
+ if (current === null || typeof current !== "object") return void 0;
3540
+ const bracketMatch = part.match(/^(\w+)\[(\d+)\]$/);
3541
+ if (bracketMatch) {
3542
+ current = current[bracketMatch[1]];
3543
+ if (Array.isArray(current)) {
3544
+ current = current[parseInt(bracketMatch[2], 10)];
2933
3545
  } else {
2934
- current = current[part];
3546
+ return void 0;
3547
+ }
3548
+ } else {
3549
+ current = current[part];
3550
+ }
3551
+ }
3552
+ return current;
3553
+ }
3554
+ function safeInterpolateCommand2(template, context) {
3555
+ const result = template.replace(
3556
+ /(--[\w-]+\s+)?\$\{([^}]+)\}/g,
3557
+ (_match, flagPrefix, expr) => {
3558
+ const value = resolveExpression(expr, context);
3559
+ if (value === void 0 || value === null) {
3560
+ return "";
2935
3561
  }
3562
+ return (flagPrefix ?? "") + shellEscape2(String(value));
2936
3563
  }
2937
- if (current === void 0 || current === null) return "";
2938
- return shellEscape2(String(current));
2939
- });
3564
+ );
3565
+ return result.replace(/ +/g, " ").trim();
2940
3566
  }
2941
3567
  function spawnWithKill(command, options, registry) {
2942
3568
  return new Promise((resolve, reject) => {
@@ -3598,159 +4224,159 @@ import WebSocket from "ws";
3598
4224
  import { randomUUID as randomUUID9 } from "crypto";
3599
4225
 
3600
4226
  // src/relay/types.ts
3601
- import { z as z3 } from "zod";
3602
- var RegisterMessageSchema = z3.object({
3603
- type: z3.literal("register"),
3604
- owner: z3.string().min(1),
4227
+ import { z as z4 } from "zod";
4228
+ var RegisterMessageSchema = z4.object({
4229
+ type: z4.literal("register"),
4230
+ owner: z4.string().min(1),
3605
4231
  /** V8: Cryptographic agent identity. When present, used as the canonical key. */
3606
- agent_id: z3.string().optional(),
4232
+ agent_id: z4.string().optional(),
3607
4233
  /** V8 Phase 3: Server identifier for multi-agent delegation. */
3608
- server_id: z3.string().optional(),
3609
- token: z3.string().min(1),
3610
- card: z3.record(z3.unknown()),
4234
+ server_id: z4.string().optional(),
4235
+ token: z4.string().min(1),
4236
+ card: z4.record(z4.unknown()),
3611
4237
  // CapabilityCard (validated separately)
3612
- cards: z3.array(z3.record(z3.unknown())).optional(),
4238
+ cards: z4.array(z4.record(z4.unknown())).optional(),
3613
4239
  // Additional cards (e.g., conductor card)
3614
4240
  /** V8 Phase 3: Additional agents served by this server (multi-agent registration). */
3615
- agents: z3.array(z3.object({
3616
- agent_id: z3.string().min(1),
3617
- display_name: z3.string().min(1),
3618
- cards: z3.array(z3.record(z3.unknown())),
3619
- delegation_token: z3.record(z3.unknown()).optional()
4241
+ agents: z4.array(z4.object({
4242
+ agent_id: z4.string().min(1),
4243
+ display_name: z4.string().min(1),
4244
+ cards: z4.array(z4.record(z4.unknown())),
4245
+ delegation_token: z4.record(z4.unknown()).optional()
3620
4246
  })).optional()
3621
4247
  });
3622
- var RegisteredMessageSchema = z3.object({
3623
- type: z3.literal("registered"),
3624
- agent_id: z3.string()
4248
+ var RegisteredMessageSchema = z4.object({
4249
+ type: z4.literal("registered"),
4250
+ agent_id: z4.string()
3625
4251
  });
3626
- var RelayRequestMessageSchema = z3.object({
3627
- type: z3.literal("relay_request"),
3628
- id: z3.string().uuid(),
3629
- target_owner: z3.string().min(1),
4252
+ var RelayRequestMessageSchema = z4.object({
4253
+ type: z4.literal("relay_request"),
4254
+ id: z4.string().uuid(),
4255
+ target_owner: z4.string().min(1),
3630
4256
  /** V8: Target agent's cryptographic identity. Preferred over target_owner. */
3631
- target_agent_id: z3.string().optional(),
3632
- card_id: z3.string(),
3633
- skill_id: z3.string().optional(),
3634
- params: z3.record(z3.unknown()).default({}),
3635
- requester: z3.string().optional(),
3636
- escrow_receipt: z3.record(z3.unknown()).optional()
4257
+ target_agent_id: z4.string().optional(),
4258
+ card_id: z4.string(),
4259
+ skill_id: z4.string().optional(),
4260
+ params: z4.record(z4.unknown()).default({}),
4261
+ requester: z4.string().optional(),
4262
+ escrow_receipt: z4.record(z4.unknown()).optional()
3637
4263
  });
3638
- var IncomingRequestMessageSchema = z3.object({
3639
- type: z3.literal("incoming_request"),
3640
- id: z3.string().uuid(),
3641
- from_owner: z3.string().min(1),
3642
- card_id: z3.string(),
3643
- skill_id: z3.string().optional(),
3644
- params: z3.record(z3.unknown()).default({}),
3645
- requester: z3.string().optional(),
3646
- escrow_receipt: z3.record(z3.unknown()).optional()
4264
+ var IncomingRequestMessageSchema = z4.object({
4265
+ type: z4.literal("incoming_request"),
4266
+ id: z4.string().uuid(),
4267
+ from_owner: z4.string().min(1),
4268
+ card_id: z4.string(),
4269
+ skill_id: z4.string().optional(),
4270
+ params: z4.record(z4.unknown()).default({}),
4271
+ requester: z4.string().optional(),
4272
+ escrow_receipt: z4.record(z4.unknown()).optional()
3647
4273
  });
3648
- var RelayResponseMessageSchema = z3.object({
3649
- type: z3.literal("relay_response"),
3650
- id: z3.string().uuid(),
3651
- result: z3.unknown().optional(),
3652
- error: z3.object({
3653
- code: z3.number(),
3654
- message: z3.string()
4274
+ var RelayResponseMessageSchema = z4.object({
4275
+ type: z4.literal("relay_response"),
4276
+ id: z4.string().uuid(),
4277
+ result: z4.unknown().optional(),
4278
+ error: z4.object({
4279
+ code: z4.number(),
4280
+ message: z4.string()
3655
4281
  }).optional()
3656
4282
  });
3657
- var ResponseMessageSchema = z3.object({
3658
- type: z3.literal("response"),
3659
- id: z3.string().uuid(),
3660
- result: z3.unknown().optional(),
3661
- error: z3.object({
3662
- code: z3.number(),
3663
- message: z3.string()
4283
+ var ResponseMessageSchema = z4.object({
4284
+ type: z4.literal("response"),
4285
+ id: z4.string().uuid(),
4286
+ result: z4.unknown().optional(),
4287
+ error: z4.object({
4288
+ code: z4.number(),
4289
+ message: z4.string()
3664
4290
  }).optional()
3665
4291
  });
3666
- var ErrorMessageSchema = z3.object({
3667
- type: z3.literal("error"),
3668
- code: z3.string(),
3669
- message: z3.string(),
3670
- request_id: z3.string().optional()
4292
+ var ErrorMessageSchema = z4.object({
4293
+ type: z4.literal("error"),
4294
+ code: z4.string(),
4295
+ message: z4.string(),
4296
+ request_id: z4.string().optional()
3671
4297
  });
3672
- var RelayProgressMessageSchema = z3.object({
3673
- type: z3.literal("relay_progress"),
3674
- id: z3.string().uuid(),
4298
+ var RelayProgressMessageSchema = z4.object({
4299
+ type: z4.literal("relay_progress"),
4300
+ id: z4.string().uuid(),
3675
4301
  // request ID this progress relates to
3676
- progress: z3.number().min(0).max(100).optional(),
4302
+ progress: z4.number().min(0).max(100).optional(),
3677
4303
  // optional percentage
3678
- message: z3.string().optional()
4304
+ message: z4.string().optional()
3679
4305
  // optional status message
3680
4306
  });
3681
- var RelayStartedMessageSchema = z3.object({
3682
- type: z3.literal("relay_started"),
3683
- id: z3.string().uuid(),
3684
- message: z3.string().optional()
4307
+ var RelayStartedMessageSchema = z4.object({
4308
+ type: z4.literal("relay_started"),
4309
+ id: z4.string().uuid(),
4310
+ message: z4.string().optional()
3685
4311
  });
3686
- var HeartbeatMessageSchema = z3.object({
3687
- type: z3.literal("heartbeat"),
3688
- owner: z3.string().min(1),
3689
- capacity: z3.object({
3690
- current_load: z3.number(),
3691
- max_concurrent: z3.number(),
3692
- queue_depth: z3.number()
4312
+ var HeartbeatMessageSchema = z4.object({
4313
+ type: z4.literal("heartbeat"),
4314
+ owner: z4.string().min(1),
4315
+ capacity: z4.object({
4316
+ current_load: z4.number(),
4317
+ max_concurrent: z4.number(),
4318
+ queue_depth: z4.number()
3693
4319
  }),
3694
- self_summary: z3.object({
3695
- capabilities: z3.array(z3.string()),
3696
- success_rate: z3.number(),
3697
- credit_balance: z3.number(),
3698
- total_completed: z3.number(),
3699
- provider_number: z3.number(),
3700
- reliability: z3.object({
3701
- current_streak: z3.number(),
3702
- repeat_hire_rate: z3.number(),
3703
- avg_feedback: z3.number()
4320
+ self_summary: z4.object({
4321
+ capabilities: z4.array(z4.string()),
4322
+ success_rate: z4.number(),
4323
+ credit_balance: z4.number(),
4324
+ total_completed: z4.number(),
4325
+ provider_number: z4.number(),
4326
+ reliability: z4.object({
4327
+ current_streak: z4.number(),
4328
+ repeat_hire_rate: z4.number(),
4329
+ avg_feedback: z4.number()
3704
4330
  })
3705
4331
  })
3706
4332
  });
3707
- var EscrowHoldMessageSchema = z3.object({
3708
- type: z3.literal("escrow_hold"),
3709
- consumer_agent_id: z3.string().min(1),
3710
- provider_agent_id: z3.string().min(1),
3711
- skill_id: z3.string().min(1),
3712
- amount: z3.number().positive(),
3713
- request_id: z3.string().uuid(),
3714
- signature: z3.string().optional(),
3715
- public_key: z3.string().optional()
4333
+ var EscrowHoldMessageSchema = z4.object({
4334
+ type: z4.literal("escrow_hold"),
4335
+ consumer_agent_id: z4.string().min(1),
4336
+ provider_agent_id: z4.string().min(1),
4337
+ skill_id: z4.string().min(1),
4338
+ amount: z4.number().positive(),
4339
+ request_id: z4.string().uuid(),
4340
+ signature: z4.string().optional(),
4341
+ public_key: z4.string().optional()
3716
4342
  });
3717
- var EscrowHoldConfirmedMessageSchema = z3.object({
3718
- type: z3.literal("escrow_hold_confirmed"),
3719
- request_id: z3.string(),
3720
- escrow_id: z3.string(),
3721
- hold_amount: z3.number(),
3722
- consumer_remaining: z3.number()
4343
+ var EscrowHoldConfirmedMessageSchema = z4.object({
4344
+ type: z4.literal("escrow_hold_confirmed"),
4345
+ request_id: z4.string(),
4346
+ escrow_id: z4.string(),
4347
+ hold_amount: z4.number(),
4348
+ consumer_remaining: z4.number()
3723
4349
  });
3724
- var EscrowSettleMessageSchema = z3.object({
3725
- type: z3.literal("escrow_settle"),
3726
- escrow_id: z3.string().min(1),
3727
- request_id: z3.string().uuid(),
3728
- success: z3.boolean(),
3729
- failure_reason: z3.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
3730
- result_hash: z3.string().optional(),
3731
- signature: z3.string().optional(),
3732
- public_key: z3.string().optional(),
3733
- consumer_agent_id: z3.string().optional()
4350
+ var EscrowSettleMessageSchema = z4.object({
4351
+ type: z4.literal("escrow_settle"),
4352
+ escrow_id: z4.string().min(1),
4353
+ request_id: z4.string().uuid(),
4354
+ success: z4.boolean(),
4355
+ failure_reason: z4.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
4356
+ result_hash: z4.string().optional(),
4357
+ signature: z4.string().optional(),
4358
+ public_key: z4.string().optional(),
4359
+ consumer_agent_id: z4.string().optional()
3734
4360
  });
3735
- var EscrowSettledMessageSchema = z3.object({
3736
- type: z3.literal("escrow_settled"),
3737
- escrow_id: z3.string(),
3738
- request_id: z3.string(),
3739
- provider_earned: z3.number(),
3740
- network_fee: z3.number(),
3741
- consumer_remaining: z3.number(),
3742
- provider_balance: z3.number()
4361
+ var EscrowSettledMessageSchema = z4.object({
4362
+ type: z4.literal("escrow_settled"),
4363
+ escrow_id: z4.string(),
4364
+ request_id: z4.string(),
4365
+ provider_earned: z4.number(),
4366
+ network_fee: z4.number(),
4367
+ consumer_remaining: z4.number(),
4368
+ provider_balance: z4.number()
3743
4369
  });
3744
- var BalanceSyncMessageSchema = z3.object({
3745
- type: z3.literal("balance_sync"),
3746
- agent_id: z3.string().min(1)
4370
+ var BalanceSyncMessageSchema = z4.object({
4371
+ type: z4.literal("balance_sync"),
4372
+ agent_id: z4.string().min(1)
3747
4373
  });
3748
- var BalanceSyncResponseMessageSchema = z3.object({
3749
- type: z3.literal("balance_sync_response"),
3750
- agent_id: z3.string(),
3751
- balance: z3.number()
4374
+ var BalanceSyncResponseMessageSchema = z4.object({
4375
+ type: z4.literal("balance_sync_response"),
4376
+ agent_id: z4.string(),
4377
+ balance: z4.number()
3752
4378
  });
3753
- var RelayMessageSchema = z3.discriminatedUnion("type", [
4379
+ var RelayMessageSchema = z4.discriminatedUnion("type", [
3754
4380
  RegisterMessageSchema,
3755
4381
  RegisteredMessageSchema,
3756
4382
  RelayRequestMessageSchema,
@@ -4153,8 +4779,8 @@ import { randomUUID as randomUUID11 } from "crypto";
4153
4779
  import { randomUUID as randomUUID12 } from "crypto";
4154
4780
 
4155
4781
  // src/cli/peers.ts
4156
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
4157
- import { join as join3 } from "path";
4782
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
4783
+ import { join as join4 } from "path";
4158
4784
 
4159
4785
  // src/autonomy/auto-request.ts
4160
4786
  function minMaxNormalize(values) {
@@ -4338,11 +4964,11 @@ var BudgetController = class {
4338
4964
  };
4339
4965
 
4340
4966
  // src/conductor/card.ts
4341
- import { createHash } from "crypto";
4967
+ import { createHash as createHash2 } from "crypto";
4342
4968
  var CONDUCTOR_OWNER = "agentbnb-conductor";
4343
4969
  var CONDUCTOR_CARD_ID = "00000000-0000-4000-8000-000000000001";
4344
4970
  function ownerToCardId(owner) {
4345
- const hash = createHash("sha256").update(owner).digest("hex").slice(0, 32);
4971
+ const hash = createHash2("sha256").update(owner).digest("hex").slice(0, 32);
4346
4972
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-4${hash.slice(13, 16)}-8${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
4347
4973
  }
4348
4974
  function buildConductorCard(owner) {
@@ -4980,18 +5606,18 @@ var ConductorMode = class {
4980
5606
  };
4981
5607
 
4982
5608
  // src/credit/escrow-receipt.ts
4983
- import { z as z4 } from "zod";
5609
+ import { z as z5 } from "zod";
4984
5610
  import { randomUUID as randomUUID14 } from "crypto";
4985
- var EscrowReceiptSchema = z4.object({
4986
- requester_owner: z4.string().min(1),
4987
- requester_agent_id: z4.string().optional(),
4988
- requester_public_key: z4.string().min(1),
4989
- amount: z4.number().positive(),
4990
- card_id: z4.string().min(1),
4991
- skill_id: z4.string().optional(),
4992
- timestamp: z4.string(),
4993
- nonce: z4.string().uuid(),
4994
- signature: z4.string().min(1)
5611
+ var EscrowReceiptSchema = z5.object({
5612
+ requester_owner: z5.string().min(1),
5613
+ requester_agent_id: z5.string().optional(),
5614
+ requester_public_key: z5.string().min(1),
5615
+ amount: z5.number().positive(),
5616
+ card_id: z5.string().min(1),
5617
+ skill_id: z5.string().optional(),
5618
+ timestamp: z5.string(),
5619
+ nonce: z5.string().uuid(),
5620
+ signature: z5.string().min(1)
4995
5621
  });
4996
5622
  function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
4997
5623
  const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
@@ -5033,191 +5659,6 @@ function releaseRequesterEscrow(requesterDb, escrowId) {
5033
5659
  releaseEscrow(requesterDb, escrowId);
5034
5660
  }
5035
5661
 
5036
- // src/identity/identity.ts
5037
- import { z as z5 } from "zod";
5038
- import { createHash as createHash2, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
5039
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
5040
- import { join as join4 } from "path";
5041
- var AgentIdentitySchema = z5.object({
5042
- /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
5043
- agent_id: z5.string().min(1),
5044
- /** Human-readable owner name (from config or init). */
5045
- owner: z5.string().min(1),
5046
- /** Hex-encoded Ed25519 public key. */
5047
- public_key: z5.string().min(1),
5048
- /** ISO 8601 timestamp of identity creation. */
5049
- created_at: z5.string().datetime(),
5050
- /** Optional guarantor info if linked to a human. */
5051
- guarantor: z5.object({
5052
- github_login: z5.string().min(1),
5053
- verified_at: z5.string().datetime()
5054
- }).optional()
5055
- });
5056
- var AgentCertificateSchema = z5.object({
5057
- identity: AgentIdentitySchema,
5058
- /** ISO 8601 timestamp of certificate issuance. */
5059
- issued_at: z5.string().datetime(),
5060
- /** ISO 8601 timestamp of certificate expiry. */
5061
- expires_at: z5.string().datetime(),
5062
- /** Hex-encoded public key of the issuer (same as identity for self-signed). */
5063
- issuer_public_key: z5.string().min(1),
5064
- /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
5065
- signature: z5.string().min(1)
5066
- });
5067
- var IDENTITY_FILENAME = "identity.json";
5068
- var PRIVATE_KEY_FILENAME = "private.key";
5069
- var PUBLIC_KEY_FILENAME = "public.key";
5070
- function derivePublicKeyFromPrivate(privateKey) {
5071
- const privateKeyObject = createPrivateKey2({ key: privateKey, format: "der", type: "pkcs8" });
5072
- const publicKeyObject = createPublicKey2(privateKeyObject);
5073
- const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
5074
- return Buffer.from(publicKey);
5075
- }
5076
- function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
5077
- const publicKeyHex = publicKey.toString("hex");
5078
- return {
5079
- agent_id: deriveAgentId(publicKeyHex),
5080
- owner,
5081
- public_key: publicKeyHex,
5082
- created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
5083
- };
5084
- }
5085
- function generateFreshIdentity(configDir, owner) {
5086
- const keys = generateKeyPair();
5087
- saveKeyPair(configDir, keys);
5088
- const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
5089
- saveIdentity(configDir, identity);
5090
- return { identity, keys, status: "generated" };
5091
- }
5092
- function deriveAgentId(publicKeyHex) {
5093
- return createHash2("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
5094
- }
5095
- function createIdentity(configDir, owner) {
5096
- if (!existsSync4(configDir)) {
5097
- mkdirSync3(configDir, { recursive: true });
5098
- }
5099
- let keys;
5100
- try {
5101
- keys = loadKeyPair(configDir);
5102
- } catch {
5103
- keys = generateKeyPair();
5104
- saveKeyPair(configDir, keys);
5105
- }
5106
- const publicKeyHex = keys.publicKey.toString("hex");
5107
- const agentId = deriveAgentId(publicKeyHex);
5108
- const identity = {
5109
- agent_id: agentId,
5110
- owner,
5111
- public_key: publicKeyHex,
5112
- created_at: (/* @__PURE__ */ new Date()).toISOString()
5113
- };
5114
- saveIdentity(configDir, identity);
5115
- return identity;
5116
- }
5117
- function loadIdentity(configDir) {
5118
- const filePath = join4(configDir, IDENTITY_FILENAME);
5119
- if (!existsSync4(filePath)) return null;
5120
- try {
5121
- const raw = readFileSync4(filePath, "utf-8");
5122
- return AgentIdentitySchema.parse(JSON.parse(raw));
5123
- } catch {
5124
- return null;
5125
- }
5126
- }
5127
- function saveIdentity(configDir, identity) {
5128
- if (!existsSync4(configDir)) {
5129
- mkdirSync3(configDir, { recursive: true });
5130
- }
5131
- const filePath = join4(configDir, IDENTITY_FILENAME);
5132
- writeFileSync4(filePath, JSON.stringify(identity, null, 2), "utf-8");
5133
- }
5134
- function loadOrRepairIdentity(configDir, ownerHint) {
5135
- if (!existsSync4(configDir)) {
5136
- mkdirSync3(configDir, { recursive: true });
5137
- }
5138
- const identityPath = join4(configDir, IDENTITY_FILENAME);
5139
- const privateKeyPath = join4(configDir, PRIVATE_KEY_FILENAME);
5140
- const publicKeyPath = join4(configDir, PUBLIC_KEY_FILENAME);
5141
- const hasIdentity = existsSync4(identityPath);
5142
- const hasPrivateKey = existsSync4(privateKeyPath);
5143
- const hasPublicKey = existsSync4(publicKeyPath);
5144
- if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
5145
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
5146
- }
5147
- let keys;
5148
- try {
5149
- keys = loadKeyPair(configDir);
5150
- } catch {
5151
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
5152
- }
5153
- let derivedPublicKey;
5154
- try {
5155
- derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
5156
- } catch {
5157
- return generateFreshIdentity(configDir, ownerHint ?? "agent");
5158
- }
5159
- let keypairRepaired = false;
5160
- if (!keys.publicKey.equals(derivedPublicKey)) {
5161
- keypairRepaired = true;
5162
- keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
5163
- saveKeyPair(configDir, keys);
5164
- }
5165
- const loadedIdentity = loadIdentity(configDir);
5166
- const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
5167
- const expectedPublicKeyHex = derivedPublicKey.toString("hex");
5168
- const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
5169
- if (identityMismatch) {
5170
- const repairedIdentity = buildIdentityFromPublicKey(
5171
- derivedPublicKey,
5172
- loadedIdentity?.owner ?? ownerHint ?? "agent",
5173
- loadedIdentity?.created_at
5174
- );
5175
- saveIdentity(configDir, repairedIdentity);
5176
- return { identity: repairedIdentity, keys, status: "repaired" };
5177
- }
5178
- if (ownerHint && loadedIdentity.owner !== ownerHint) {
5179
- const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
5180
- saveIdentity(configDir, updatedIdentity);
5181
- return { identity: updatedIdentity, keys, status: "repaired" };
5182
- }
5183
- return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
5184
- }
5185
- function issueAgentCertificate(identity, privateKey) {
5186
- const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
5187
- const expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toISOString();
5188
- const payload = {
5189
- identity,
5190
- issued_at: issuedAt,
5191
- expires_at: expiresAt,
5192
- issuer_public_key: identity.public_key
5193
- };
5194
- const signature = signEscrowReceipt(payload, privateKey);
5195
- return {
5196
- identity,
5197
- issued_at: issuedAt,
5198
- expires_at: expiresAt,
5199
- issuer_public_key: identity.public_key,
5200
- signature
5201
- };
5202
- }
5203
- function verifyAgentCertificate(cert) {
5204
- if (new Date(cert.expires_at) < /* @__PURE__ */ new Date()) {
5205
- return false;
5206
- }
5207
- const publicKeyHex = cert.issuer_public_key;
5208
- const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
5209
- const payload = {
5210
- identity: cert.identity,
5211
- issued_at: cert.issued_at,
5212
- expires_at: cert.expires_at,
5213
- issuer_public_key: cert.issuer_public_key
5214
- };
5215
- return verifyEscrowReceipt(payload, cert.signature, publicKeyBuf);
5216
- }
5217
- function ensureIdentity(configDir, owner) {
5218
- return loadOrRepairIdentity(configDir, owner).identity;
5219
- }
5220
-
5221
5662
  // src/sdk/consumer.ts
5222
5663
  var AgentBnBConsumer = class {
5223
5664
  configDir;