agentbnb 4.0.4 → 5.1.1

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.
Files changed (58) hide show
  1. package/dist/chunk-AUBHR7HH.js +25 -0
  2. package/dist/chunk-B5FTAGFN.js +393 -0
  3. package/dist/{chunk-GGYC5U2Z.js → chunk-BTTL24TZ.js} +29 -91
  4. package/dist/chunk-C6KPAFCC.js +387 -0
  5. package/dist/{chunk-JXEOE7HX.js → chunk-CRFCWD6V.js} +163 -92
  6. package/dist/chunk-CSATDXZC.js +89 -0
  7. package/dist/{chunk-T7NS2J2B.js → chunk-DFBX3BBD.js} +84 -1
  8. package/dist/{chunk-DNWT5FZQ.js → chunk-EANI2N2V.js} +98 -1
  9. package/dist/{chunk-HH24WMFN.js → chunk-FLY3WIQR.js} +1 -1
  10. package/dist/{chunk-EVBX22YU.js → chunk-HLUEOLSZ.js} +11 -17
  11. package/dist/chunk-IVOYM3WG.js +25 -0
  12. package/dist/chunk-LCAIAAG2.js +916 -0
  13. package/dist/chunk-MLS6IGGG.js +294 -0
  14. package/dist/{chunk-4P3EMGL4.js → chunk-MNO4COST.js} +5 -3
  15. package/dist/chunk-NH2FIERR.js +138 -0
  16. package/dist/chunk-UKT6H7YT.js +29 -0
  17. package/dist/{chunk-BH6WGYFB.js → chunk-VE3E4AMH.js} +8 -8
  18. package/dist/{chunk-5QGXARLJ.js → chunk-W5BZMKMF.js} +159 -27
  19. package/dist/{chunk-FF226TIV.js → chunk-ZX5623ER.js} +0 -57
  20. package/dist/cli/index.js +362 -4633
  21. package/dist/{conduct-N52JX7RT.js → conduct-KM6ZNJGE.js} +10 -8
  22. package/dist/{conduct-GZQNFTRP.js → conduct-WGTMQND5.js} +10 -8
  23. package/dist/{conductor-mode-XUWGR4ZE.js → conductor-mode-OL2FNOYY.js} +6 -4
  24. package/dist/{conductor-mode-ESGFZ6T5.js → conductor-mode-VRO7TYW2.js} +20 -167
  25. package/dist/execute-CPFSOOO3.js +13 -0
  26. package/dist/execute-IP2QHALV.js +10 -0
  27. package/dist/index.d.ts +14 -8
  28. package/dist/index.js +190 -36
  29. package/dist/{peers-E4MKNNDN.js → peers-CJ7T4RJO.js} +2 -1
  30. package/dist/process-guard-CC7CNRQJ.js +176 -0
  31. package/dist/{request-4GQSSM4B.js → request-YOWPXVLQ.js} +13 -10
  32. package/dist/schema-7BSSLZ4S.js +8 -0
  33. package/dist/{serve-skill-Q6NHX2RA.js → serve-skill-JHFNR7BW.js} +8 -7
  34. package/dist/{server-B5E566CI.js → server-HKJJWFRG.js} +10 -8
  35. package/dist/service-coordinator-UTKI4FRI.js +4922 -0
  36. package/dist/skills/agentbnb/bootstrap.js +5034 -849
  37. package/dist/websocket-client-WRN3HO73.js +6 -0
  38. package/package.json +4 -1
  39. package/skills/agentbnb/SKILL.md +87 -70
  40. package/skills/agentbnb/bootstrap.test.ts +142 -242
  41. package/skills/agentbnb/bootstrap.ts +88 -95
  42. package/skills/agentbnb/install.sh +97 -27
  43. package/skills/deep-stock-analyst/package.json +24 -0
  44. package/skills/deep-stock-analyst/src/analysis/financial-health.ts +167 -0
  45. package/skills/deep-stock-analyst/src/analysis/sentiment.ts +68 -0
  46. package/skills/deep-stock-analyst/src/analysis/signal.ts +188 -0
  47. package/skills/deep-stock-analyst/src/analysis/technicals.ts +318 -0
  48. package/skills/deep-stock-analyst/src/analysis/utils.ts +137 -0
  49. package/skills/deep-stock-analyst/src/analysis/valuation.ts +95 -0
  50. package/skills/deep-stock-analyst/src/api/alpha-vantage.ts +133 -0
  51. package/skills/deep-stock-analyst/src/api/types.ts +238 -0
  52. package/skills/deep-stock-analyst/src/index.ts +84 -0
  53. package/skills/deep-stock-analyst/src/llm/thesis.ts +101 -0
  54. package/skills/deep-stock-analyst/src/orchestrator.ts +228 -0
  55. package/skills/deep-stock-analyst/tsconfig.json +21 -0
  56. package/dist/card-RNEWSAQ6.js +0 -88
  57. package/dist/chunk-UB2NPFC7.js +0 -165
  58. package/dist/execute-QH6F54D7.js +0 -10
@@ -0,0 +1,387 @@
1
+ // src/relay/websocket-client.ts
2
+ import WebSocket from "ws";
3
+ import { randomUUID } from "crypto";
4
+
5
+ // src/relay/types.ts
6
+ import { z } from "zod";
7
+ var RegisterMessageSchema = z.object({
8
+ type: z.literal("register"),
9
+ owner: z.string().min(1),
10
+ token: z.string().min(1),
11
+ card: z.record(z.unknown()),
12
+ // CapabilityCard (validated separately)
13
+ cards: z.array(z.record(z.unknown())).optional()
14
+ // Additional cards (e.g., conductor card)
15
+ });
16
+ var RegisteredMessageSchema = z.object({
17
+ type: z.literal("registered"),
18
+ agent_id: z.string()
19
+ });
20
+ var RelayRequestMessageSchema = z.object({
21
+ type: z.literal("relay_request"),
22
+ id: z.string().uuid(),
23
+ target_owner: z.string().min(1),
24
+ card_id: z.string(),
25
+ skill_id: z.string().optional(),
26
+ params: z.record(z.unknown()).default({}),
27
+ requester: z.string().optional(),
28
+ escrow_receipt: z.record(z.unknown()).optional()
29
+ });
30
+ var IncomingRequestMessageSchema = z.object({
31
+ type: z.literal("incoming_request"),
32
+ id: z.string().uuid(),
33
+ from_owner: z.string().min(1),
34
+ card_id: z.string(),
35
+ skill_id: z.string().optional(),
36
+ params: z.record(z.unknown()).default({}),
37
+ requester: z.string().optional(),
38
+ escrow_receipt: z.record(z.unknown()).optional()
39
+ });
40
+ var RelayResponseMessageSchema = z.object({
41
+ type: z.literal("relay_response"),
42
+ id: z.string().uuid(),
43
+ result: z.unknown().optional(),
44
+ error: z.object({
45
+ code: z.number(),
46
+ message: z.string()
47
+ }).optional()
48
+ });
49
+ var ResponseMessageSchema = z.object({
50
+ type: z.literal("response"),
51
+ id: z.string().uuid(),
52
+ result: z.unknown().optional(),
53
+ error: z.object({
54
+ code: z.number(),
55
+ message: z.string()
56
+ }).optional()
57
+ });
58
+ var ErrorMessageSchema = z.object({
59
+ type: z.literal("error"),
60
+ code: z.string(),
61
+ message: z.string(),
62
+ request_id: z.string().optional()
63
+ });
64
+ var RelayProgressMessageSchema = z.object({
65
+ type: z.literal("relay_progress"),
66
+ id: z.string().uuid(),
67
+ // request ID this progress relates to
68
+ progress: z.number().min(0).max(100).optional(),
69
+ // optional percentage
70
+ message: z.string().optional()
71
+ // optional status message
72
+ });
73
+ var RelayMessageSchema = z.discriminatedUnion("type", [
74
+ RegisterMessageSchema,
75
+ RegisteredMessageSchema,
76
+ RelayRequestMessageSchema,
77
+ IncomingRequestMessageSchema,
78
+ RelayResponseMessageSchema,
79
+ ResponseMessageSchema,
80
+ ErrorMessageSchema,
81
+ RelayProgressMessageSchema
82
+ ]);
83
+
84
+ // src/relay/websocket-client.ts
85
+ var RelayClient = class {
86
+ ws = null;
87
+ opts;
88
+ pendingRequests = /* @__PURE__ */ new Map();
89
+ reconnectAttempts = 0;
90
+ reconnectTimer = null;
91
+ intentionalClose = false;
92
+ registered = false;
93
+ pongTimeout = null;
94
+ pingInterval = null;
95
+ constructor(opts) {
96
+ this.opts = opts;
97
+ }
98
+ /**
99
+ * Connect to the registry relay and register.
100
+ * Resolves when registration is acknowledged.
101
+ */
102
+ async connect() {
103
+ return new Promise((resolve, reject) => {
104
+ this.intentionalClose = false;
105
+ this.registered = false;
106
+ const wsUrl = this.buildWsUrl();
107
+ this.ws = new WebSocket(wsUrl);
108
+ let resolved = false;
109
+ this.ws.on("open", () => {
110
+ this.reconnectAttempts = 0;
111
+ this.startPingInterval();
112
+ this.send({
113
+ type: "register",
114
+ owner: this.opts.owner,
115
+ token: this.opts.token,
116
+ card: this.opts.card,
117
+ ...this.opts.cards && this.opts.cards.length > 0 ? { cards: this.opts.cards } : {}
118
+ });
119
+ });
120
+ this.ws.on("message", (raw) => {
121
+ this.handleMessage(raw, (err) => {
122
+ if (!resolved) {
123
+ resolved = true;
124
+ if (err) reject(err);
125
+ else resolve();
126
+ }
127
+ });
128
+ });
129
+ this.ws.on("close", () => {
130
+ this.cleanup();
131
+ if (!this.intentionalClose) {
132
+ if (!resolved) {
133
+ resolved = true;
134
+ reject(new Error("WebSocket closed before registration"));
135
+ }
136
+ this.scheduleReconnect();
137
+ }
138
+ });
139
+ this.ws.on("error", (err) => {
140
+ if (!resolved) {
141
+ resolved = true;
142
+ reject(err);
143
+ }
144
+ });
145
+ setTimeout(() => {
146
+ if (!resolved) {
147
+ resolved = true;
148
+ reject(new Error("Connection timeout"));
149
+ this.ws?.close();
150
+ }
151
+ }, 1e4);
152
+ });
153
+ }
154
+ /**
155
+ * Disconnect from the registry relay.
156
+ */
157
+ disconnect() {
158
+ this.intentionalClose = true;
159
+ this.cleanup();
160
+ if (this.ws) {
161
+ try {
162
+ this.ws.close(1e3, "Client disconnect");
163
+ } catch {
164
+ }
165
+ this.ws = null;
166
+ }
167
+ for (const [id, pending] of this.pendingRequests) {
168
+ clearTimeout(pending.timeout);
169
+ pending.reject(new Error("Client disconnected"));
170
+ this.pendingRequests.delete(id);
171
+ }
172
+ }
173
+ /**
174
+ * Send a relay request to another agent via the registry.
175
+ * @returns The result from the target agent.
176
+ */
177
+ async request(opts) {
178
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.registered) {
179
+ throw new Error("Not connected to registry relay");
180
+ }
181
+ const id = randomUUID();
182
+ const timeoutMs = opts.timeoutMs ?? 3e5;
183
+ return new Promise((resolve, reject) => {
184
+ const timeout = setTimeout(() => {
185
+ this.pendingRequests.delete(id);
186
+ reject(new Error("Relay request timeout"));
187
+ }, timeoutMs);
188
+ this.pendingRequests.set(id, { resolve, reject, timeout, timeoutMs, onProgress: opts.onProgress });
189
+ this.send({
190
+ type: "relay_request",
191
+ id,
192
+ target_owner: opts.targetOwner,
193
+ card_id: opts.cardId,
194
+ skill_id: opts.skillId,
195
+ params: opts.params,
196
+ requester: opts.requester ?? this.opts.owner,
197
+ escrow_receipt: opts.escrowReceipt
198
+ });
199
+ });
200
+ }
201
+ /**
202
+ * Send a relay_progress message to the relay server for a given request.
203
+ * Used by the onRequest handler to forward SkillExecutor progress updates
204
+ * to the requesting agent so it can reset its timeout window.
205
+ *
206
+ * @param requestId - The relay request ID to associate progress with.
207
+ * @param info - Progress details (step, total, message).
208
+ */
209
+ sendProgress(requestId, info) {
210
+ this.send({
211
+ type: "relay_progress",
212
+ id: requestId,
213
+ progress: Math.round(info.step / info.total * 100),
214
+ message: info.message
215
+ });
216
+ }
217
+ /** Whether the client is connected and registered */
218
+ get isConnected() {
219
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
220
+ }
221
+ // ── Private methods ─────────────────────────────────────────────────────────
222
+ buildWsUrl() {
223
+ let url = this.opts.registryUrl;
224
+ if (url.startsWith("http://")) {
225
+ url = "ws://" + url.slice(7);
226
+ } else if (url.startsWith("https://")) {
227
+ url = "wss://" + url.slice(8);
228
+ } else if (!url.startsWith("ws://") && !url.startsWith("wss://")) {
229
+ url = "wss://" + url;
230
+ }
231
+ if (!url.endsWith("/ws")) {
232
+ url = url.replace(/\/$/, "") + "/ws";
233
+ }
234
+ return url;
235
+ }
236
+ handleMessage(raw, onRegistered) {
237
+ let data;
238
+ try {
239
+ data = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf-8"));
240
+ } catch {
241
+ return;
242
+ }
243
+ const parsed = RelayMessageSchema.safeParse(data);
244
+ if (!parsed.success) return;
245
+ const msg = parsed.data;
246
+ switch (msg.type) {
247
+ case "registered":
248
+ this.registered = true;
249
+ if (!this.opts.silent) {
250
+ console.log(` \u2713 Registered with registry (agent_id: ${msg.agent_id})`);
251
+ }
252
+ onRegistered?.();
253
+ break;
254
+ case "incoming_request":
255
+ this.handleIncomingRequest(msg);
256
+ break;
257
+ case "response":
258
+ this.handleResponse(msg);
259
+ break;
260
+ case "error":
261
+ this.handleError(msg);
262
+ break;
263
+ case "relay_progress":
264
+ this.handleProgress(msg);
265
+ break;
266
+ default:
267
+ break;
268
+ }
269
+ }
270
+ async handleIncomingRequest(msg) {
271
+ try {
272
+ const result = await this.opts.onRequest(msg);
273
+ this.send({
274
+ type: "relay_response",
275
+ id: msg.id,
276
+ result: result.result,
277
+ error: result.error
278
+ });
279
+ } catch (err) {
280
+ this.send({
281
+ type: "relay_response",
282
+ id: msg.id,
283
+ error: {
284
+ code: -32603,
285
+ message: err instanceof Error ? err.message : "Internal error"
286
+ }
287
+ });
288
+ }
289
+ }
290
+ handleResponse(msg) {
291
+ const pending = this.pendingRequests.get(msg.id);
292
+ if (!pending) return;
293
+ clearTimeout(pending.timeout);
294
+ this.pendingRequests.delete(msg.id);
295
+ if (msg.error) {
296
+ pending.reject(new Error(msg.error.message));
297
+ } else {
298
+ pending.resolve(msg.result);
299
+ }
300
+ }
301
+ handleError(msg) {
302
+ if (msg.request_id) {
303
+ const pending = this.pendingRequests.get(msg.request_id);
304
+ if (pending) {
305
+ clearTimeout(pending.timeout);
306
+ this.pendingRequests.delete(msg.request_id);
307
+ pending.reject(new Error(`${msg.code}: ${msg.message}`));
308
+ }
309
+ }
310
+ }
311
+ handleProgress(msg) {
312
+ const pending = this.pendingRequests.get(msg.id);
313
+ if (!pending) return;
314
+ clearTimeout(pending.timeout);
315
+ const newTimeout = setTimeout(() => {
316
+ this.pendingRequests.delete(msg.id);
317
+ pending.reject(new Error("Relay request timeout"));
318
+ }, pending.timeoutMs);
319
+ pending.timeout = newTimeout;
320
+ if (pending.onProgress) {
321
+ pending.onProgress({ id: msg.id, progress: msg.progress, message: msg.message });
322
+ }
323
+ }
324
+ send(msg) {
325
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
326
+ this.ws.send(JSON.stringify(msg));
327
+ }
328
+ }
329
+ startPingInterval() {
330
+ this.stopPingInterval();
331
+ this.pingInterval = setInterval(() => {
332
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
333
+ this.ws.ping();
334
+ this.pongTimeout = setTimeout(() => {
335
+ if (!this.opts.silent) {
336
+ console.log(" \u26A0 Registry pong timeout, reconnecting...");
337
+ }
338
+ this.ws?.terminate();
339
+ }, 15e3);
340
+ }
341
+ }, 3e4);
342
+ this.ws?.on("pong", () => {
343
+ if (this.pongTimeout) {
344
+ clearTimeout(this.pongTimeout);
345
+ this.pongTimeout = null;
346
+ }
347
+ });
348
+ }
349
+ stopPingInterval() {
350
+ if (this.pingInterval) {
351
+ clearInterval(this.pingInterval);
352
+ this.pingInterval = null;
353
+ }
354
+ if (this.pongTimeout) {
355
+ clearTimeout(this.pongTimeout);
356
+ this.pongTimeout = null;
357
+ }
358
+ }
359
+ cleanup() {
360
+ this.stopPingInterval();
361
+ this.registered = false;
362
+ }
363
+ scheduleReconnect() {
364
+ if (this.intentionalClose) return;
365
+ if (this.reconnectTimer) return;
366
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4);
367
+ this.reconnectAttempts++;
368
+ if (!this.opts.silent) {
369
+ console.log(` \u21BB Reconnecting to registry in ${delay / 1e3}s...`);
370
+ }
371
+ this.reconnectTimer = setTimeout(async () => {
372
+ this.reconnectTimer = null;
373
+ try {
374
+ await this.connect();
375
+ if (!this.opts.silent) {
376
+ console.log(" \u2713 Reconnected to registry");
377
+ }
378
+ } catch {
379
+ }
380
+ }, delay);
381
+ }
382
+ };
383
+
384
+ export {
385
+ RelayMessageSchema,
386
+ RelayClient
387
+ };
@@ -1,46 +1,10 @@
1
1
  import {
2
2
  AgentBnBError
3
- } from "./chunk-UB2NPFC7.js";
4
-
5
- // src/autonomy/tiers.ts
6
- import { randomUUID } from "crypto";
7
- var DEFAULT_AUTONOMY_CONFIG = {
8
- tier1_max_credits: 0,
9
- tier2_max_credits: 0
10
- };
11
- function getAutonomyTier(creditAmount, config) {
12
- if (creditAmount < config.tier1_max_credits) return 1;
13
- if (creditAmount < config.tier2_max_credits) return 2;
14
- return 3;
15
- }
16
- function insertAuditEvent(db, event) {
17
- const isShareEvent = event.type === "auto_share" || event.type === "auto_share_notify" || event.type === "auto_share_pending";
18
- const cardId = isShareEvent ? "system" : event.card_id;
19
- const creditsCharged = isShareEvent ? 0 : event.credits;
20
- const stmt = db.prepare(`
21
- INSERT INTO request_log (
22
- id, card_id, card_name, requester, status, latency_ms, credits_charged,
23
- created_at, skill_id, action_type, tier_invoked
24
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
25
- `);
26
- stmt.run(
27
- randomUUID(),
28
- cardId,
29
- "autonomy-audit",
30
- "self",
31
- "success",
32
- 0,
33
- creditsCharged,
34
- (/* @__PURE__ */ new Date()).toISOString(),
35
- event.skill_id,
36
- event.type,
37
- event.tier_invoked
38
- );
39
- }
3
+ } from "./chunk-WGZ5AGOX.js";
40
4
 
41
5
  // src/credit/ledger.ts
42
6
  import Database from "better-sqlite3";
43
- import { randomUUID as randomUUID2 } from "crypto";
7
+ import { randomUUID } from "crypto";
44
8
  var CREDIT_SCHEMA = `
45
9
  CREATE TABLE IF NOT EXISTS credit_balances (
46
10
  owner TEXT PRIMARY KEY,
@@ -77,10 +41,26 @@ function openCreditDb(path = ":memory:") {
77
41
  db.exec(CREDIT_SCHEMA);
78
42
  return db;
79
43
  }
44
+ function bootstrapAgent(db, owner, amount = 100) {
45
+ const now = (/* @__PURE__ */ new Date()).toISOString();
46
+ db.transaction(() => {
47
+ const result = db.prepare("INSERT OR IGNORE INTO credit_balances (owner, balance, updated_at) VALUES (?, ?, ?)").run(owner, amount, now);
48
+ if (result.changes > 0) {
49
+ db.prepare(
50
+ "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
51
+ ).run(randomUUID(), owner, amount, "bootstrap", null, now);
52
+ }
53
+ })();
54
+ }
80
55
  function getBalance(db, owner) {
81
56
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
82
57
  return row?.balance ?? 0;
83
58
  }
59
+ function getTransactions(db, owner, limit = 100) {
60
+ return db.prepare(
61
+ "SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE owner = ? ORDER BY created_at DESC LIMIT ?"
62
+ ).all(owner, limit);
63
+ }
84
64
  function recordEarning(db, owner, amount, _cardId, receiptNonce) {
85
65
  const now = (/* @__PURE__ */ new Date()).toISOString();
86
66
  db.transaction(() => {
@@ -96,14 +76,33 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
96
76
  ).run(amount, now, owner);
97
77
  db.prepare(
98
78
  "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
99
- ).run(randomUUID2(), owner, amount, "remote_earning", receiptNonce, now);
79
+ ).run(randomUUID(), owner, amount, "remote_earning", receiptNonce, now);
80
+ })();
81
+ }
82
+ function migrateOwner(db, oldOwner, newOwner) {
83
+ if (oldOwner === newOwner) return;
84
+ const now = (/* @__PURE__ */ new Date()).toISOString();
85
+ db.transaction(() => {
86
+ const oldRow = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(oldOwner);
87
+ if (!oldRow) return;
88
+ const newRow = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(newOwner);
89
+ if (newRow) {
90
+ db.prepare("UPDATE credit_balances SET balance = balance + ?, updated_at = ? WHERE owner = ?").run(oldRow.balance, now, newOwner);
91
+ } else {
92
+ db.prepare("UPDATE credit_balances SET owner = ?, updated_at = ? WHERE owner = ?").run(newOwner, now, oldOwner);
93
+ }
94
+ if (newRow) {
95
+ db.prepare("DELETE FROM credit_balances WHERE owner = ?").run(oldOwner);
96
+ }
97
+ db.prepare("UPDATE credit_transactions SET owner = ? WHERE owner = ?").run(newOwner, oldOwner);
98
+ db.prepare("UPDATE credit_escrow SET owner = ? WHERE owner = ?").run(newOwner, oldOwner);
100
99
  })();
101
100
  }
102
101
 
103
102
  // src/credit/escrow.ts
104
- import { randomUUID as randomUUID3 } from "crypto";
103
+ import { randomUUID as randomUUID2 } from "crypto";
105
104
  function holdEscrow(db, owner, amount, cardId) {
106
- const escrowId = randomUUID3();
105
+ const escrowId = randomUUID2();
107
106
  const now = (/* @__PURE__ */ new Date()).toISOString();
108
107
  const hold = db.transaction(() => {
109
108
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
@@ -118,7 +117,7 @@ function holdEscrow(db, owner, amount, cardId) {
118
117
  ).run(escrowId, owner, amount, cardId, "held", now);
119
118
  db.prepare(
120
119
  "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
121
- ).run(randomUUID3(), owner, -amount, "escrow_hold", escrowId, now);
120
+ ).run(randomUUID2(), owner, -amount, "escrow_hold", escrowId, now);
122
121
  });
123
122
  hold();
124
123
  return escrowId;
@@ -147,7 +146,7 @@ function settleEscrow(db, escrowId, recipientOwner) {
147
146
  ).run("settled", now, escrowId);
148
147
  db.prepare(
149
148
  "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
150
- ).run(randomUUID3(), recipientOwner, escrow.amount, "settlement", escrowId, now);
149
+ ).run(randomUUID2(), recipientOwner, escrow.amount, "settlement", escrowId, now);
151
150
  });
152
151
  settle();
153
152
  }
@@ -172,56 +171,31 @@ function releaseEscrow(db, escrowId) {
172
171
  ).run("released", now, escrowId);
173
172
  db.prepare(
174
173
  "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
175
- ).run(randomUUID3(), escrow.owner, escrow.amount, "refund", escrowId, now);
174
+ ).run(randomUUID2(), escrow.owner, escrow.amount, "refund", escrowId, now);
176
175
  });
177
176
  release();
178
177
  }
179
-
180
- // src/utils/interpolation.ts
181
- function resolvePath(obj, path) {
182
- const segments = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter((s) => s.length > 0);
183
- let current = obj;
184
- for (const segment of segments) {
185
- if (current === null || current === void 0) {
186
- return void 0;
187
- }
188
- if (typeof current !== "object") {
189
- return void 0;
190
- }
191
- current = current[segment];
192
- }
193
- return current;
194
- }
195
- function interpolate(template, context) {
196
- return template.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
197
- const resolved = resolvePath(context, expression.trim());
198
- if (resolved === void 0 || resolved === null) {
199
- return "";
178
+ function confirmEscrowDebit(db, escrowId) {
179
+ const now = (/* @__PURE__ */ new Date()).toISOString();
180
+ const confirm = db.transaction(() => {
181
+ const escrow = db.prepare("SELECT id, owner, amount, status FROM credit_escrow WHERE id = ?").get(escrowId);
182
+ if (!escrow) {
183
+ throw new AgentBnBError(`Escrow not found: ${escrowId}`, "ESCROW_NOT_FOUND");
200
184
  }
201
- if (typeof resolved === "object") {
202
- return JSON.stringify(resolved);
185
+ if (escrow.status !== "held") {
186
+ throw new AgentBnBError(
187
+ `Escrow ${escrowId} is already ${escrow.status}`,
188
+ "ESCROW_ALREADY_SETTLED"
189
+ );
203
190
  }
204
- return String(resolved);
191
+ db.prepare(
192
+ "UPDATE credit_escrow SET status = ?, settled_at = ? WHERE id = ?"
193
+ ).run("settled", now, escrowId);
194
+ db.prepare(
195
+ "INSERT INTO credit_transactions (id, owner, amount, reason, reference_id, created_at) VALUES (?, ?, ?, ?, ?, ?)"
196
+ ).run(randomUUID2(), escrow.owner, 0, "remote_settlement_confirmed", escrowId, now);
205
197
  });
206
- }
207
- function interpolateObject(obj, context) {
208
- const result = {};
209
- for (const [key, value] of Object.entries(obj)) {
210
- result[key] = interpolateValue(value, context);
211
- }
212
- return result;
213
- }
214
- function interpolateValue(value, context) {
215
- if (typeof value === "string") {
216
- return interpolate(value, context);
217
- }
218
- if (Array.isArray(value)) {
219
- return value.map((item) => interpolateValue(item, context));
220
- }
221
- if (value !== null && typeof value === "object") {
222
- return interpolateObject(value, context);
223
- }
224
- return value;
198
+ confirm();
225
199
  }
226
200
 
227
201
  // src/credit/signing.ts
@@ -276,20 +250,117 @@ function verifyEscrowReceipt(data, signature, publicKey) {
276
250
  }
277
251
  }
278
252
 
253
+ // src/feedback/store.ts
254
+ import { randomUUID as randomUUID3 } from "crypto";
255
+ function initFeedbackTable(db) {
256
+ db.exec(`
257
+ CREATE TABLE IF NOT EXISTS feedback (
258
+ id TEXT PRIMARY KEY,
259
+ transaction_id TEXT NOT NULL,
260
+ provider_agent TEXT NOT NULL,
261
+ skill_id TEXT NOT NULL,
262
+ requester_agent TEXT NOT NULL,
263
+ rating INTEGER NOT NULL,
264
+ latency_ms INTEGER NOT NULL,
265
+ result_quality TEXT NOT NULL,
266
+ quality_details TEXT,
267
+ would_reuse INTEGER NOT NULL,
268
+ cost_value_ratio TEXT NOT NULL,
269
+ timestamp TEXT NOT NULL,
270
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
271
+ );
272
+
273
+ CREATE INDEX IF NOT EXISTS feedback_provider_idx ON feedback(provider_agent);
274
+ CREATE INDEX IF NOT EXISTS feedback_skill_idx ON feedback(skill_id);
275
+ `);
276
+ }
277
+ function insertFeedback(db, feedback) {
278
+ const id = randomUUID3();
279
+ const now = (/* @__PURE__ */ new Date()).toISOString();
280
+ db.prepare(`
281
+ INSERT INTO feedback (
282
+ id, transaction_id, provider_agent, skill_id, requester_agent,
283
+ rating, latency_ms, result_quality, quality_details,
284
+ would_reuse, cost_value_ratio, timestamp, created_at
285
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
286
+ `).run(
287
+ id,
288
+ feedback.transaction_id,
289
+ feedback.provider_agent,
290
+ feedback.skill_id,
291
+ feedback.requester_agent,
292
+ feedback.rating,
293
+ feedback.latency_ms,
294
+ feedback.result_quality,
295
+ feedback.quality_details ?? null,
296
+ feedback.would_reuse ? 1 : 0,
297
+ feedback.cost_value_ratio,
298
+ feedback.timestamp,
299
+ now
300
+ );
301
+ return id;
302
+ }
303
+ function getFeedbackForSkill(db, skillId, limit = 20) {
304
+ const rows = db.prepare(`
305
+ SELECT * FROM feedback
306
+ WHERE skill_id = ?
307
+ ORDER BY timestamp DESC
308
+ LIMIT ?
309
+ `).all(skillId, limit);
310
+ return rows.map(rowToFeedback);
311
+ }
312
+ function getFeedbackForProvider(db, providerAgent, sinceDays) {
313
+ let rows;
314
+ if (sinceDays !== void 0) {
315
+ rows = db.prepare(`
316
+ SELECT * FROM feedback
317
+ WHERE provider_agent = ?
318
+ AND timestamp >= datetime('now', ? || ' days')
319
+ ORDER BY timestamp DESC
320
+ `).all(providerAgent, `-${sinceDays}`);
321
+ } else {
322
+ rows = db.prepare(`
323
+ SELECT * FROM feedback
324
+ WHERE provider_agent = ?
325
+ ORDER BY timestamp DESC
326
+ `).all(providerAgent);
327
+ }
328
+ return rows.map(rowToFeedback);
329
+ }
330
+ function rowToFeedback(row) {
331
+ return {
332
+ transaction_id: row["transaction_id"],
333
+ provider_agent: row["provider_agent"],
334
+ skill_id: row["skill_id"],
335
+ requester_agent: row["requester_agent"],
336
+ rating: row["rating"],
337
+ latency_ms: row["latency_ms"],
338
+ result_quality: row["result_quality"],
339
+ quality_details: row["quality_details"] ?? void 0,
340
+ would_reuse: row["would_reuse"] === 1,
341
+ cost_value_ratio: row["cost_value_ratio"],
342
+ timestamp: row["timestamp"]
343
+ };
344
+ }
345
+
279
346
  export {
347
+ initFeedbackTable,
348
+ insertFeedback,
349
+ getFeedbackForSkill,
350
+ getFeedbackForProvider,
280
351
  openCreditDb,
352
+ bootstrapAgent,
281
353
  getBalance,
354
+ getTransactions,
282
355
  recordEarning,
356
+ migrateOwner,
283
357
  holdEscrow,
284
358
  settleEscrow,
285
359
  releaseEscrow,
286
- interpolateObject,
360
+ confirmEscrowDebit,
287
361
  generateKeyPair,
288
362
  saveKeyPair,
289
363
  loadKeyPair,
290
364
  signEscrowReceipt,
291
- verifyEscrowReceipt,
292
- DEFAULT_AUTONOMY_CONFIG,
293
- getAutonomyTier,
294
- insertAuditEvent
365
+ verifyEscrowReceipt
295
366
  };