agentbnb 8.2.3 → 8.3.0
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/{card-EX2EYGCZ.js → card-BN643ZOY.js} +6 -2
- package/dist/card-T2XJZA5A.js +92 -0
- package/dist/{chunk-3LWBH7P3.js → chunk-4NFJ3VYZ.js} +20 -1
- package/dist/chunk-5AIYALBX.js +857 -0
- package/dist/chunk-6QMDJVMS.js +238 -0
- package/dist/{chunk-LKLKYXLV.js → chunk-74LZDEDT.js} +6 -4
- package/dist/{chunk-GKVTD4EZ.js → chunk-77KGEDH4.js} +1 -1
- package/dist/{chunk-QCGIG7WW.js → chunk-7IQE34QK.js} +14 -7
- package/dist/{chunk-QHZGOG3O.js → chunk-D242QZCR.js} +168 -41
- package/dist/chunk-EE3V3DXK.js +60 -0
- package/dist/{chunk-RYISHSHB.js → chunk-F3KIEVJ2.js} +207 -265
- package/dist/{chunk-XBGVQMQJ.js → chunk-FELGHDCA.js} +16 -39
- package/dist/{chunk-EJKW57ZV.js → chunk-GIEJVKZZ.js} +1 -1
- package/dist/{chunk-WVY2W7AA.js → chunk-I7KWA7OB.js} +20 -0
- package/dist/{chunk-4IPJJRTP.js → chunk-IGQNP3ZO.js} +5 -2
- package/dist/chunk-NQANA6WH.js +797 -0
- package/dist/{chunk-Z4MCGKTL.js → chunk-NX27AFPA.js} +15 -2
- package/dist/{chunk-Z2GEFFDO.js → chunk-O4Q7BRG6.js} +2 -2
- package/dist/{chunk-SSK653A6.js → chunk-PQIP7EXY.js} +6 -0
- package/dist/{chunk-EG6RS4JC.js → chunk-QFPXZITP.js} +20 -65
- package/dist/chunk-R4F4XII4.js +264 -0
- package/dist/{chunk-DYQOFGGI.js → chunk-RVBW2QXU.js} +178 -49
- package/dist/{chunk-CQFBNTGT.js → chunk-S7DZHKCG.js} +25 -12
- package/dist/chunk-U6LP4KWN.js +238 -0
- package/dist/{chunk-MWOXW7JQ.js → chunk-VJ7XBEY6.js} +24 -16
- package/dist/chunk-WTHMHNKC.js +129 -0
- package/dist/{chunk-OCSU2S6W.js → chunk-WX3GZVFG.js} +2 -1
- package/dist/{chunk-CKOOVZOI.js → chunk-YKMBFQC2.js} +37 -5
- package/dist/{chunk-S3V6R3EN.js → chunk-ZU2TP7CN.js} +70 -27
- package/dist/cli/index.js +203 -237
- package/dist/client-OKJJ3UP2.js +19 -0
- package/dist/client-UQBGCIPA.js +20 -0
- package/dist/conduct-4JDMWBQD.js +22 -0
- package/dist/{conduct-AZFLNUX3.js → conduct-VYYBCPHA.js} +14 -13
- package/dist/{conductor-mode-WKB42PYM.js → conductor-mode-OPGQJFLA.js} +12 -8
- package/dist/{conductor-mode-PLTB6MS3.js → conductor-mode-SBDCRIX6.js} +16 -11
- package/dist/execute-FZLQGIXB.js +14 -0
- package/dist/execute-TEZPQ5WP.js +15 -0
- package/dist/index.d.ts +172 -11
- package/dist/index.js +1529 -433
- package/dist/{process-guard-GH5LRNWO.js → process-guard-TNSUNHSR.js} +1 -1
- package/dist/{publish-capability-QDR2QIZ2.js → publish-capability-HVYILTPR.js} +4 -3
- package/dist/{reliability-metrics-QG7WC5QK.js → reliability-metrics-G7LPUYJD.js} +3 -1
- package/dist/reliability-metrics-RRUKJ4ME.js +20 -0
- package/dist/{request-OERS5BE7.js → request-KJNKR27T.js} +76 -71
- package/dist/{serve-skill-E6EJQYAK.js → serve-skill-GC6NIQ5T.js} +10 -11
- package/dist/{server-46VEG2W7.js → server-YV3XPTX5.js} +11 -10
- package/dist/{service-coordinator-KMSA6BST.js → service-coordinator-RY5AKUZS.js} +420 -171
- package/dist/{skill-config-FETXPNVP.js → skill-config-5O2VR546.js} +1 -1
- package/dist/skills/agentbnb/bootstrap.js +528 -253
- package/dist/websocket-client-3U27WJUU.js +7 -0
- package/dist/{websocket-client-4Z5P54RU.js → websocket-client-SNDF3B6N.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-MCED4GDW.js +0 -1572
- package/dist/chunk-NWIQJ2CL.js +0 -108
- package/dist/chunk-TUCEDQGM.js +0 -44
- package/dist/chunk-WNXXLCV5.js +0 -32
- package/dist/client-XOLP5IUZ.js +0 -12
- package/dist/conduct-VPUYTNEA.js +0 -21
- package/dist/execute-NNDCXTN4.js +0 -13
- package/dist/execute-RIRHTIBU.js +0 -16
- package/dist/websocket-client-QOVARTRN.js +0 -7
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/identity/agent-identity.ts
|
|
2
|
+
var AGENTS_SCHEMA = `
|
|
3
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
4
|
+
agent_id TEXT PRIMARY KEY,
|
|
5
|
+
display_name TEXT NOT NULL,
|
|
6
|
+
public_key TEXT NOT NULL,
|
|
7
|
+
operator_id TEXT,
|
|
8
|
+
server_id TEXT,
|
|
9
|
+
legacy_owner TEXT,
|
|
10
|
+
created_at TEXT NOT NULL,
|
|
11
|
+
updated_at TEXT NOT NULL
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_agents_operator ON agents(operator_id);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_agents_legacy_owner ON agents(legacy_owner);
|
|
16
|
+
`;
|
|
17
|
+
function ensureAgentsTable(db) {
|
|
18
|
+
db.exec(AGENTS_SCHEMA);
|
|
19
|
+
}
|
|
20
|
+
function lookupAgent(db, agentId) {
|
|
21
|
+
return db.prepare("SELECT * FROM agents WHERE agent_id = ?").get(agentId) ?? null;
|
|
22
|
+
}
|
|
23
|
+
function lookupAgentByOwner(db, owner) {
|
|
24
|
+
return db.prepare("SELECT * FROM agents WHERE legacy_owner = ?").get(owner) ?? null;
|
|
25
|
+
}
|
|
26
|
+
function resolveCanonicalIdentity(db, identifier) {
|
|
27
|
+
ensureAgentsTable(db);
|
|
28
|
+
if (/^[a-f0-9]{16}$/.test(identifier)) {
|
|
29
|
+
const byAgentId = lookupAgent(db, identifier);
|
|
30
|
+
if (byAgentId) {
|
|
31
|
+
return {
|
|
32
|
+
agent_id: byAgentId.agent_id,
|
|
33
|
+
legacy_owner: byAgentId.legacy_owner,
|
|
34
|
+
resolved: true,
|
|
35
|
+
source: "agent_id"
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const byOwner = lookupAgentByOwner(db, identifier);
|
|
40
|
+
if (byOwner) {
|
|
41
|
+
return {
|
|
42
|
+
agent_id: byOwner.agent_id,
|
|
43
|
+
legacy_owner: byOwner.legacy_owner,
|
|
44
|
+
resolved: true,
|
|
45
|
+
source: "legacy_owner"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
agent_id: identifier,
|
|
50
|
+
legacy_owner: null,
|
|
51
|
+
resolved: false,
|
|
52
|
+
source: "unresolved"
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
ensureAgentsTable,
|
|
58
|
+
lookupAgent,
|
|
59
|
+
resolveCanonicalIdentity
|
|
60
|
+
};
|
|
@@ -1,79 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
canonicalizeCreditOwner,
|
|
2
3
|
ensureReliabilityTable,
|
|
4
|
+
migrateCreditOwnerData,
|
|
3
5
|
recordSuccessfulHire
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-U6LP4KWN.js";
|
|
5
7
|
import {
|
|
6
8
|
getFeedbackForProvider
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5AIYALBX.js";
|
|
10
|
+
import {
|
|
11
|
+
ensureAgentsTable
|
|
12
|
+
} from "./chunk-WTHMHNKC.js";
|
|
8
13
|
import {
|
|
9
14
|
AgentBnBError
|
|
10
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-I7KWA7OB.js";
|
|
11
16
|
|
|
12
17
|
// src/credit/ledger.ts
|
|
13
18
|
import Database from "better-sqlite3";
|
|
14
19
|
import { randomUUID } from "crypto";
|
|
15
|
-
|
|
16
|
-
// src/identity/agent-identity.ts
|
|
17
|
-
var AGENTS_SCHEMA = `
|
|
18
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
19
|
-
agent_id TEXT PRIMARY KEY,
|
|
20
|
-
display_name TEXT NOT NULL,
|
|
21
|
-
public_key TEXT NOT NULL,
|
|
22
|
-
operator_id TEXT,
|
|
23
|
-
server_id TEXT,
|
|
24
|
-
legacy_owner TEXT,
|
|
25
|
-
created_at TEXT NOT NULL,
|
|
26
|
-
updated_at TEXT NOT NULL
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
CREATE INDEX IF NOT EXISTS idx_agents_operator ON agents(operator_id);
|
|
30
|
-
CREATE INDEX IF NOT EXISTS idx_agents_legacy_owner ON agents(legacy_owner);
|
|
31
|
-
`;
|
|
32
|
-
function ensureAgentsTable(db) {
|
|
33
|
-
db.exec(AGENTS_SCHEMA);
|
|
34
|
-
}
|
|
35
|
-
function createAgentRecord(db, agent) {
|
|
36
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
37
|
-
const record = {
|
|
38
|
-
agent_id: agent.agent_id,
|
|
39
|
-
display_name: agent.display_name,
|
|
40
|
-
public_key: agent.public_key,
|
|
41
|
-
operator_id: agent.operator_id ?? null,
|
|
42
|
-
server_id: agent.server_id ?? null,
|
|
43
|
-
legacy_owner: agent.legacy_owner ?? null,
|
|
44
|
-
created_at: now,
|
|
45
|
-
updated_at: now
|
|
46
|
-
};
|
|
47
|
-
const result = db.prepare(
|
|
48
|
-
`INSERT OR IGNORE INTO agents
|
|
49
|
-
(agent_id, display_name, public_key, operator_id, server_id, legacy_owner, created_at, updated_at)
|
|
50
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
51
|
-
).run(
|
|
52
|
-
record.agent_id,
|
|
53
|
-
record.display_name,
|
|
54
|
-
record.public_key,
|
|
55
|
-
record.operator_id,
|
|
56
|
-
record.server_id,
|
|
57
|
-
record.legacy_owner,
|
|
58
|
-
record.created_at,
|
|
59
|
-
record.updated_at
|
|
60
|
-
);
|
|
61
|
-
if (result.changes === 0) {
|
|
62
|
-
throw new AgentBnBError(
|
|
63
|
-
"AGENT_EXISTS",
|
|
64
|
-
`Agent ${agent.agent_id} already exists`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return record;
|
|
68
|
-
}
|
|
69
|
-
function lookupAgent(db, agentId) {
|
|
70
|
-
return db.prepare("SELECT * FROM agents WHERE agent_id = ?").get(agentId) ?? null;
|
|
71
|
-
}
|
|
72
|
-
function lookupAgentByOwner(db, owner) {
|
|
73
|
-
return db.prepare("SELECT * FROM agents WHERE legacy_owner = ?").get(owner) ?? null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/credit/ledger.ts
|
|
77
20
|
var CREDIT_SCHEMA = `
|
|
78
21
|
CREATE TABLE IF NOT EXISTS credit_balances (
|
|
79
22
|
owner TEXT PRIMARY KEY,
|
|
@@ -133,30 +76,33 @@ function openCreditDb(path = ":memory:") {
|
|
|
133
76
|
return db;
|
|
134
77
|
}
|
|
135
78
|
function bootstrapAgent(db, owner, amount = 100) {
|
|
79
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
136
80
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
137
81
|
let isNew = false;
|
|
138
82
|
db.transaction(() => {
|
|
139
|
-
const result = db.prepare("INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, ?, ?)").run(
|
|
83
|
+
const result = db.prepare("INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, ?, ?)").run(canonicalOwner, amount, now);
|
|
140
84
|
if (result.changes > 0) {
|
|
141
85
|
isNew = true;
|
|
142
86
|
db.prepare(
|
|
143
87
|
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
144
|
-
).run(randomUUID(),
|
|
88
|
+
).run(randomUUID(), canonicalOwner, amount, "bootstrap", null, now);
|
|
145
89
|
}
|
|
146
90
|
})();
|
|
147
91
|
if (isNew) {
|
|
148
|
-
issueVoucher(db,
|
|
92
|
+
issueVoucher(db, canonicalOwner, 50, 30);
|
|
149
93
|
}
|
|
150
94
|
}
|
|
151
95
|
function getBalance(db, owner) {
|
|
152
|
-
const
|
|
96
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
97
|
+
const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(canonicalOwner);
|
|
153
98
|
return row?.balance ?? 0;
|
|
154
99
|
}
|
|
155
100
|
function getTransactions(db, owner, opts = 100) {
|
|
101
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
156
102
|
const page = typeof opts === "number" ? { limit: opts } : opts;
|
|
157
103
|
const limit = page.limit ?? 100;
|
|
158
104
|
const conditions = ["owner = ?"];
|
|
159
|
-
const params = [
|
|
105
|
+
const params = [canonicalOwner];
|
|
160
106
|
if (page.before) {
|
|
161
107
|
conditions.push("created_at < ?");
|
|
162
108
|
params.push(page.before);
|
|
@@ -171,15 +117,17 @@ function getTransactions(db, owner, opts = 100) {
|
|
|
171
117
|
).all(...params);
|
|
172
118
|
}
|
|
173
119
|
function registerProvider(db, owner) {
|
|
120
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
174
121
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
175
122
|
const maxRow = db.prepare("SELECT MAX(provider_number) as maxNum FROM provider_registry").get();
|
|
176
123
|
const nextNum = (maxRow?.maxNum ?? 0) + 1;
|
|
177
|
-
db.prepare("INSERT OR IGNORE INTO provider_registry (owner, provider_number, registered_at) VALUES (?, ?, ?)").run(
|
|
178
|
-
const row = db.prepare("SELECT provider_number FROM provider_registry WHERE owner = ?").get(
|
|
124
|
+
db.prepare("INSERT OR IGNORE INTO provider_registry (owner, provider_number, registered_at) VALUES (?, ?, ?)").run(canonicalOwner, nextNum, now);
|
|
125
|
+
const row = db.prepare("SELECT provider_number FROM provider_registry WHERE owner = ?").get(canonicalOwner);
|
|
179
126
|
return row.provider_number;
|
|
180
127
|
}
|
|
181
128
|
function getProviderNumber(db, owner) {
|
|
182
|
-
const
|
|
129
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
130
|
+
const row = db.prepare("SELECT provider_number FROM provider_registry WHERE owner = ?").get(canonicalOwner);
|
|
183
131
|
return row?.provider_number ?? null;
|
|
184
132
|
}
|
|
185
133
|
function getProviderBonus(providerNumber) {
|
|
@@ -188,19 +136,21 @@ function getProviderBonus(providerNumber) {
|
|
|
188
136
|
return 1;
|
|
189
137
|
}
|
|
190
138
|
function issueVoucher(db, owner, amount = 50, daysValid = 30) {
|
|
139
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
191
140
|
const id = randomUUID();
|
|
192
141
|
const now = /* @__PURE__ */ new Date();
|
|
193
142
|
const expiresAt = new Date(now.getTime() + daysValid * 24 * 60 * 60 * 1e3);
|
|
194
143
|
db.prepare(
|
|
195
144
|
"INSERT INTO demand_vouchers (id, owner, amount, remaining, created_at, expires_at, is_active) VALUES (?, ?, ?, ?, ?, ?, 1)"
|
|
196
|
-
).run(id,
|
|
145
|
+
).run(id, canonicalOwner, amount, amount, now.toISOString(), expiresAt.toISOString());
|
|
197
146
|
return id;
|
|
198
147
|
}
|
|
199
148
|
function getActiveVoucher(db, owner) {
|
|
149
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
200
150
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
201
151
|
const row = db.prepare(
|
|
202
152
|
"SELECT id, remaining, expires_at FROM demand_vouchers WHERE owner = ? AND is_active = 1 AND remaining > 0 AND expires_at > ? ORDER BY created_at ASC LIMIT 1"
|
|
203
|
-
).get(
|
|
153
|
+
).get(canonicalOwner, now);
|
|
204
154
|
return row ?? null;
|
|
205
155
|
}
|
|
206
156
|
function consumeVoucher(db, voucherId, amount) {
|
|
@@ -208,189 +158,10 @@ function consumeVoucher(db, voucherId, amount) {
|
|
|
208
158
|
"UPDATE demand_vouchers SET remaining = remaining - ? WHERE id = ? AND remaining >= ?"
|
|
209
159
|
).run(amount, voucherId, amount);
|
|
210
160
|
}
|
|
211
|
-
function recordEarning(db, owner, amount, _cardId, receiptNonce) {
|
|
212
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
213
|
-
db.transaction(() => {
|
|
214
|
-
const existing = db.prepare(
|
|
215
|
-
"SELECT id FROM credit_transactions WHERE reference_id = ? AND reason = 'remote_earning'"
|
|
216
|
-
).get(receiptNonce);
|
|
217
|
-
if (existing) return;
|
|
218
|
-
db.prepare(
|
|
219
|
-
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
220
|
-
).run(owner, now);
|
|
221
|
-
db.prepare(
|
|
222
|
-
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
223
|
-
).run(amount, now, owner);
|
|
224
|
-
db.prepare(
|
|
225
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
226
|
-
).run(randomUUID(), owner, amount, "remote_earning", receiptNonce, now);
|
|
227
|
-
})();
|
|
228
|
-
}
|
|
229
161
|
function migrateOwner(db, oldOwner, newOwner) {
|
|
230
162
|
if (oldOwner === newOwner) return;
|
|
231
|
-
const
|
|
232
|
-
db
|
|
233
|
-
const oldRow = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(oldOwner);
|
|
234
|
-
if (!oldRow) return;
|
|
235
|
-
const newRow = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(newOwner);
|
|
236
|
-
if (newRow) {
|
|
237
|
-
db.prepare("UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?").run(oldRow.balance, now, newOwner);
|
|
238
|
-
} else {
|
|
239
|
-
db.prepare("UPDATE credit_balances SET owner = ?, updated_at = ? WHERE owner = ?").run(newOwner, now, oldOwner);
|
|
240
|
-
}
|
|
241
|
-
if (newRow) {
|
|
242
|
-
db.prepare("DELETE FROM credit_balances WHERE owner = ?").run(oldOwner);
|
|
243
|
-
}
|
|
244
|
-
db.prepare("UPDATE credit_transactions SET owner = ? WHERE owner = ?").run(newOwner, oldOwner);
|
|
245
|
-
db.prepare("UPDATE credit_escrow SET owner = ? WHERE owner = ?").run(newOwner, oldOwner);
|
|
246
|
-
})();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// src/credit/escrow.ts
|
|
250
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
251
|
-
var NETWORK_FEE_RATE = 0.05;
|
|
252
|
-
function holdEscrow(db, owner, amount, cardId) {
|
|
253
|
-
const escrowId = randomUUID2();
|
|
254
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
255
|
-
const hold = db.transaction(() => {
|
|
256
|
-
const voucher = getActiveVoucher(db, owner);
|
|
257
|
-
if (voucher && voucher.remaining >= amount) {
|
|
258
|
-
consumeVoucher(db, voucher.id, amount);
|
|
259
|
-
db.prepare(
|
|
260
|
-
"INSERT INTO credit_escrow (id, owner, amount, card_id, status, created_at, funding_source) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
261
|
-
).run(escrowId, owner, amount, cardId, "held", now, "voucher");
|
|
262
|
-
db.prepare(
|
|
263
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
264
|
-
).run(randomUUID2(), owner, -amount, "voucher_hold", escrowId, now);
|
|
265
|
-
} else {
|
|
266
|
-
const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
|
|
267
|
-
if (!row || row.balance < amount) {
|
|
268
|
-
throw new AgentBnBError("Insufficient credits", "INSUFFICIENT_CREDITS");
|
|
269
|
-
}
|
|
270
|
-
db.prepare(
|
|
271
|
-
"UPDATE credit_balances SET balance = balance - ?, updated_at = ? WHERE owner = ? AND balance >= ?"
|
|
272
|
-
).run(amount, now, owner, amount);
|
|
273
|
-
db.prepare(
|
|
274
|
-
"INSERT INTO credit_escrow (id, owner, amount, card_id, status, created_at, funding_source) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
275
|
-
).run(escrowId, owner, amount, cardId, "held", now, "balance");
|
|
276
|
-
db.prepare(
|
|
277
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
278
|
-
).run(randomUUID2(), owner, -amount, "escrow_hold", escrowId, now);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
hold();
|
|
282
|
-
return escrowId;
|
|
283
|
-
}
|
|
284
|
-
function settleEscrow(db, escrowId, recipientOwner) {
|
|
285
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
286
|
-
const settle = db.transaction(() => {
|
|
287
|
-
const escrow = db.prepare("SELECT id, owner, amount, status, funding_source FROM credit_escrow WHERE id = ?").get(escrowId);
|
|
288
|
-
if (!escrow) {
|
|
289
|
-
throw new AgentBnBError(`Escrow not found: ${escrowId}`, "ESCROW_NOT_FOUND");
|
|
290
|
-
}
|
|
291
|
-
if (escrow.status !== "held") {
|
|
292
|
-
throw new AgentBnBError(
|
|
293
|
-
`Escrow ${escrowId} is already ${escrow.status}`,
|
|
294
|
-
"ESCROW_ALREADY_SETTLED"
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
const feeAmount = Math.floor(escrow.amount * NETWORK_FEE_RATE);
|
|
298
|
-
const providerAmount = escrow.amount - feeAmount;
|
|
299
|
-
db.prepare(
|
|
300
|
-
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
301
|
-
).run(recipientOwner, now);
|
|
302
|
-
db.prepare(
|
|
303
|
-
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
304
|
-
).run(providerAmount, now, recipientOwner);
|
|
305
|
-
if (feeAmount > 0) {
|
|
306
|
-
db.prepare(
|
|
307
|
-
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
308
|
-
).run("platform_treasury", now);
|
|
309
|
-
db.prepare(
|
|
310
|
-
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
311
|
-
).run(feeAmount, now, "platform_treasury");
|
|
312
|
-
db.prepare(
|
|
313
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
314
|
-
).run(randomUUID2(), "platform_treasury", feeAmount, "network_fee", escrowId, now);
|
|
315
|
-
}
|
|
316
|
-
db.prepare(
|
|
317
|
-
"UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
|
|
318
|
-
).run("settled", now, escrowId);
|
|
319
|
-
db.prepare(
|
|
320
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
321
|
-
).run(randomUUID2(), recipientOwner, providerAmount, "settlement", escrowId, now);
|
|
322
|
-
let providerNum = getProviderNumber(db, recipientOwner);
|
|
323
|
-
if (providerNum === null) {
|
|
324
|
-
providerNum = registerProvider(db, recipientOwner);
|
|
325
|
-
}
|
|
326
|
-
const bonus = getProviderBonus(providerNum);
|
|
327
|
-
if (bonus > 1) {
|
|
328
|
-
const bonusAmount = Math.floor(providerAmount * (bonus - 1));
|
|
329
|
-
if (bonusAmount > 0) {
|
|
330
|
-
db.prepare(
|
|
331
|
-
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
332
|
-
).run("platform_treasury", now);
|
|
333
|
-
db.prepare(
|
|
334
|
-
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
335
|
-
).run(bonusAmount, now, recipientOwner);
|
|
336
|
-
db.prepare(
|
|
337
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
338
|
-
).run(randomUUID2(), recipientOwner, bonusAmount, "provider_bonus", escrowId, now);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
try {
|
|
342
|
-
recordSuccessfulHire(db, recipientOwner, escrow.owner);
|
|
343
|
-
} catch {
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
settle();
|
|
347
|
-
}
|
|
348
|
-
function releaseEscrow(db, escrowId) {
|
|
349
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
350
|
-
const release = db.transaction(() => {
|
|
351
|
-
const escrow = db.prepare("SELECT id, owner, amount, status, funding_source FROM credit_escrow WHERE id = ?").get(escrowId);
|
|
352
|
-
if (!escrow) {
|
|
353
|
-
throw new AgentBnBError(`Escrow not found: ${escrowId}`, "ESCROW_NOT_FOUND");
|
|
354
|
-
}
|
|
355
|
-
if (escrow.status !== "held") {
|
|
356
|
-
throw new AgentBnBError(
|
|
357
|
-
`Escrow ${escrowId} is already ${escrow.status}`,
|
|
358
|
-
"ESCROW_ALREADY_SETTLED"
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
db.prepare(
|
|
362
|
-
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
363
|
-
).run(escrow.amount, now, escrow.owner);
|
|
364
|
-
db.prepare(
|
|
365
|
-
"UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
|
|
366
|
-
).run("released", now, escrowId);
|
|
367
|
-
db.prepare(
|
|
368
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
369
|
-
).run(randomUUID2(), escrow.owner, escrow.amount, "refund", escrowId, now);
|
|
370
|
-
});
|
|
371
|
-
release();
|
|
372
|
-
}
|
|
373
|
-
function confirmEscrowDebit(db, escrowId) {
|
|
374
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
375
|
-
const confirm = db.transaction(() => {
|
|
376
|
-
const escrow = db.prepare("SELECT id, owner, amount, status, funding_source FROM credit_escrow WHERE id = ?").get(escrowId);
|
|
377
|
-
if (!escrow) {
|
|
378
|
-
throw new AgentBnBError(`Escrow not found: ${escrowId}`, "ESCROW_NOT_FOUND");
|
|
379
|
-
}
|
|
380
|
-
if (escrow.status !== "held") {
|
|
381
|
-
throw new AgentBnBError(
|
|
382
|
-
`Escrow ${escrowId} is already ${escrow.status}`,
|
|
383
|
-
"ESCROW_ALREADY_SETTLED"
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
db.prepare(
|
|
387
|
-
"UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
|
|
388
|
-
).run("settled", now, escrowId);
|
|
389
|
-
db.prepare(
|
|
390
|
-
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
391
|
-
).run(randomUUID2(), escrow.owner, 0, "remote_settlement_confirmed", escrowId, now);
|
|
392
|
-
});
|
|
393
|
-
confirm();
|
|
163
|
+
const canonicalNewOwner = canonicalizeCreditOwner(db, newOwner);
|
|
164
|
+
migrateCreditOwnerData(db, oldOwner, canonicalNewOwner);
|
|
394
165
|
}
|
|
395
166
|
|
|
396
167
|
// src/feedback/reputation.ts
|
|
@@ -586,6 +357,180 @@ function buildReputationMap(db, owners) {
|
|
|
586
357
|
return map;
|
|
587
358
|
}
|
|
588
359
|
|
|
360
|
+
// src/credit/escrow.ts
|
|
361
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
362
|
+
var NETWORK_FEE_RATE = 0.05;
|
|
363
|
+
var FINALIZABLE_ESCROW_STATUSES = /* @__PURE__ */ new Set([
|
|
364
|
+
"held",
|
|
365
|
+
"started",
|
|
366
|
+
"progressing",
|
|
367
|
+
"abandoned"
|
|
368
|
+
]);
|
|
369
|
+
var TERMINAL_ESCROW_STATUSES = /* @__PURE__ */ new Set(["settled", "released"]);
|
|
370
|
+
function getEscrowForMutation(db, escrowId) {
|
|
371
|
+
const escrow = db.prepare("SELECT id, owner, amount, status, funding_source FROM credit_escrow WHERE id = ?").get(escrowId);
|
|
372
|
+
if (!escrow) {
|
|
373
|
+
throw new AgentBnBError(`Escrow not found: ${escrowId}`, "ESCROW_NOT_FOUND");
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
...escrow,
|
|
377
|
+
owner: canonicalizeCreditOwner(db, escrow.owner)
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function updateEscrowStatus(db, escrowId, fromStatuses, toStatus) {
|
|
381
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
382
|
+
const transition = db.transaction(() => {
|
|
383
|
+
const escrow = getEscrowForMutation(db, escrowId);
|
|
384
|
+
const current = escrow.status;
|
|
385
|
+
if (!fromStatuses.includes(current)) {
|
|
386
|
+
throw new AgentBnBError(
|
|
387
|
+
`Invalid escrow transition for ${escrowId}: ${current} -> ${toStatus}`,
|
|
388
|
+
"ESCROW_INVALID_TRANSITION"
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
if (current === toStatus) return;
|
|
392
|
+
const settledAt = TERMINAL_ESCROW_STATUSES.has(toStatus) ? now : null;
|
|
393
|
+
db.prepare("UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?").run(
|
|
394
|
+
toStatus,
|
|
395
|
+
settledAt,
|
|
396
|
+
escrowId
|
|
397
|
+
);
|
|
398
|
+
});
|
|
399
|
+
transition();
|
|
400
|
+
}
|
|
401
|
+
function assertEscrowCanFinalize(escrow) {
|
|
402
|
+
const status = escrow.status;
|
|
403
|
+
if (FINALIZABLE_ESCROW_STATUSES.has(status)) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (TERMINAL_ESCROW_STATUSES.has(status)) {
|
|
407
|
+
throw new AgentBnBError(
|
|
408
|
+
`Escrow ${escrow.id} is already ${status}`,
|
|
409
|
+
"ESCROW_ALREADY_SETTLED"
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
throw new AgentBnBError(
|
|
413
|
+
`Escrow ${escrow.id} has invalid lifecycle status: ${escrow.status}`,
|
|
414
|
+
"ESCROW_INVALID_TRANSITION"
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
function holdEscrow(db, owner, amount, cardId) {
|
|
418
|
+
const canonicalOwner = canonicalizeCreditOwner(db, owner);
|
|
419
|
+
const escrowId = randomUUID2();
|
|
420
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
421
|
+
const hold = db.transaction(() => {
|
|
422
|
+
const voucher = getActiveVoucher(db, canonicalOwner);
|
|
423
|
+
if (voucher && voucher.remaining >= amount) {
|
|
424
|
+
consumeVoucher(db, voucher.id, amount);
|
|
425
|
+
db.prepare(
|
|
426
|
+
"INSERT INTO credit_escrow (id, owner, amount, card_id, status, created_at, funding_source) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
427
|
+
).run(escrowId, canonicalOwner, amount, cardId, "held", now, "voucher");
|
|
428
|
+
db.prepare(
|
|
429
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
430
|
+
).run(randomUUID2(), canonicalOwner, -amount, "voucher_hold", escrowId, now);
|
|
431
|
+
} else {
|
|
432
|
+
const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(canonicalOwner);
|
|
433
|
+
if (!row || row.balance < amount) {
|
|
434
|
+
throw new AgentBnBError("Insufficient credits", "INSUFFICIENT_CREDITS");
|
|
435
|
+
}
|
|
436
|
+
db.prepare(
|
|
437
|
+
"UPDATE credit_balances SET balance = balance - ?, updated_at = ? WHERE owner = ? AND balance >= ?"
|
|
438
|
+
).run(amount, now, canonicalOwner, amount);
|
|
439
|
+
db.prepare(
|
|
440
|
+
"INSERT INTO credit_escrow (id, owner, amount, card_id, status, created_at, funding_source) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
441
|
+
).run(escrowId, canonicalOwner, amount, cardId, "held", now, "balance");
|
|
442
|
+
db.prepare(
|
|
443
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
444
|
+
).run(randomUUID2(), canonicalOwner, -amount, "escrow_hold", escrowId, now);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
hold();
|
|
448
|
+
return escrowId;
|
|
449
|
+
}
|
|
450
|
+
function markEscrowStarted(db, escrowId) {
|
|
451
|
+
updateEscrowStatus(db, escrowId, ["held", "started"], "started");
|
|
452
|
+
}
|
|
453
|
+
function markEscrowProgressing(db, escrowId) {
|
|
454
|
+
updateEscrowStatus(db, escrowId, ["held", "started", "progressing"], "progressing");
|
|
455
|
+
}
|
|
456
|
+
function markEscrowAbandoned(db, escrowId) {
|
|
457
|
+
updateEscrowStatus(db, escrowId, ["started", "progressing", "abandoned"], "abandoned");
|
|
458
|
+
}
|
|
459
|
+
function settleEscrow(db, escrowId, recipientOwner) {
|
|
460
|
+
const canonicalRecipientOwner = canonicalizeCreditOwner(db, recipientOwner);
|
|
461
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
462
|
+
const settle = db.transaction(() => {
|
|
463
|
+
const escrow = getEscrowForMutation(db, escrowId);
|
|
464
|
+
assertEscrowCanFinalize(escrow);
|
|
465
|
+
const feeAmount = Math.floor(escrow.amount * NETWORK_FEE_RATE);
|
|
466
|
+
const providerAmount = escrow.amount - feeAmount;
|
|
467
|
+
db.prepare(
|
|
468
|
+
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
469
|
+
).run(canonicalRecipientOwner, now);
|
|
470
|
+
db.prepare(
|
|
471
|
+
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
472
|
+
).run(providerAmount, now, canonicalRecipientOwner);
|
|
473
|
+
if (feeAmount > 0) {
|
|
474
|
+
db.prepare(
|
|
475
|
+
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
476
|
+
).run("platform_treasury", now);
|
|
477
|
+
db.prepare(
|
|
478
|
+
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
479
|
+
).run(feeAmount, now, "platform_treasury");
|
|
480
|
+
db.prepare(
|
|
481
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
482
|
+
).run(randomUUID2(), "platform_treasury", feeAmount, "network_fee", escrowId, now);
|
|
483
|
+
}
|
|
484
|
+
db.prepare(
|
|
485
|
+
"UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
|
|
486
|
+
).run("settled", now, escrowId);
|
|
487
|
+
db.prepare(
|
|
488
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
489
|
+
).run(randomUUID2(), canonicalRecipientOwner, providerAmount, "settlement", escrowId, now);
|
|
490
|
+
let providerNum = getProviderNumber(db, canonicalRecipientOwner);
|
|
491
|
+
if (providerNum === null) {
|
|
492
|
+
providerNum = registerProvider(db, canonicalRecipientOwner);
|
|
493
|
+
}
|
|
494
|
+
const bonus = getProviderBonus(providerNum);
|
|
495
|
+
if (bonus > 1) {
|
|
496
|
+
const bonusAmount = Math.floor(providerAmount * (bonus - 1));
|
|
497
|
+
if (bonusAmount > 0) {
|
|
498
|
+
db.prepare(
|
|
499
|
+
"INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, 0, ?)"
|
|
500
|
+
).run("platform_treasury", now);
|
|
501
|
+
db.prepare(
|
|
502
|
+
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
503
|
+
).run(bonusAmount, now, canonicalRecipientOwner);
|
|
504
|
+
db.prepare(
|
|
505
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
506
|
+
).run(randomUUID2(), canonicalRecipientOwner, bonusAmount, "provider_bonus", escrowId, now);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
recordSuccessfulHire(db, canonicalRecipientOwner, escrow.owner);
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
settle();
|
|
515
|
+
}
|
|
516
|
+
function releaseEscrow(db, escrowId) {
|
|
517
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
518
|
+
const release = db.transaction(() => {
|
|
519
|
+
const escrow = getEscrowForMutation(db, escrowId);
|
|
520
|
+
assertEscrowCanFinalize(escrow);
|
|
521
|
+
db.prepare(
|
|
522
|
+
"UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?"
|
|
523
|
+
).run(escrow.amount, now, escrow.owner);
|
|
524
|
+
db.prepare(
|
|
525
|
+
"UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
|
|
526
|
+
).run("released", now, escrowId);
|
|
527
|
+
db.prepare(
|
|
528
|
+
"INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
529
|
+
).run(randomUUID2(), escrow.owner, escrow.amount, "refund", escrowId, now);
|
|
530
|
+
});
|
|
531
|
+
release();
|
|
532
|
+
}
|
|
533
|
+
|
|
589
534
|
// src/cli/remote-registry.ts
|
|
590
535
|
var RegistryTimeoutError = class extends AgentBnBError {
|
|
591
536
|
constructor(url) {
|
|
@@ -670,24 +615,21 @@ function mergeResults(localCards, remoteCards, hasQuery) {
|
|
|
670
615
|
}
|
|
671
616
|
|
|
672
617
|
export {
|
|
673
|
-
createAgentRecord,
|
|
674
|
-
lookupAgent,
|
|
675
|
-
lookupAgentByOwner,
|
|
676
618
|
openCreditDb,
|
|
677
619
|
bootstrapAgent,
|
|
678
620
|
getBalance,
|
|
679
621
|
getTransactions,
|
|
680
|
-
recordEarning,
|
|
681
622
|
migrateOwner,
|
|
682
|
-
NETWORK_FEE_RATE,
|
|
683
|
-
holdEscrow,
|
|
684
|
-
settleEscrow,
|
|
685
|
-
releaseEscrow,
|
|
686
|
-
confirmEscrowDebit,
|
|
687
623
|
computeReputation,
|
|
688
624
|
searchCards,
|
|
689
625
|
filterCards,
|
|
690
626
|
buildReputationMap,
|
|
627
|
+
holdEscrow,
|
|
628
|
+
markEscrowStarted,
|
|
629
|
+
markEscrowProgressing,
|
|
630
|
+
markEscrowAbandoned,
|
|
631
|
+
settleEscrow,
|
|
632
|
+
releaseEscrow,
|
|
691
633
|
fetchRemoteCards,
|
|
692
634
|
mergeResults
|
|
693
635
|
};
|