chainlesschain 0.37.10 → 0.37.12
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/README.md +166 -10
- package/package.json +1 -1
- package/src/commands/a2a.js +374 -0
- package/src/commands/bi.js +240 -0
- package/src/commands/cowork.js +317 -0
- package/src/commands/economy.js +375 -0
- package/src/commands/evolution.js +398 -0
- package/src/commands/hmemory.js +273 -0
- package/src/commands/hook.js +260 -0
- package/src/commands/init.js +184 -0
- package/src/commands/lowcode.js +320 -0
- package/src/commands/plugin.js +55 -2
- package/src/commands/sandbox.js +366 -0
- package/src/commands/skill.js +254 -201
- package/src/commands/workflow.js +359 -0
- package/src/commands/zkp.js +277 -0
- package/src/index.js +44 -0
- package/src/lib/a2a-protocol.js +371 -0
- package/src/lib/agent-coordinator.js +273 -0
- package/src/lib/agent-economy.js +369 -0
- package/src/lib/app-builder.js +377 -0
- package/src/lib/bi-engine.js +299 -0
- package/src/lib/cowork/ab-comparator-cli.js +180 -0
- package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
- package/src/lib/cowork/debate-review-cli.js +144 -0
- package/src/lib/cowork/decision-kb-cli.js +153 -0
- package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
- package/src/lib/cowork-adapter.js +106 -0
- package/src/lib/evolution-system.js +508 -0
- package/src/lib/hierarchical-memory.js +471 -0
- package/src/lib/hook-manager.js +387 -0
- package/src/lib/plugin-manager.js +118 -0
- package/src/lib/project-detector.js +53 -0
- package/src/lib/sandbox-v2.js +503 -0
- package/src/lib/service-container.js +183 -0
- package/src/lib/skill-loader.js +274 -0
- package/src/lib/workflow-engine.js +503 -0
- package/src/lib/zkp-engine.js +241 -0
- package/src/repl/agent-repl.js +117 -112
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Economy — Token-based agent economy with payments, state channels,
|
|
3
|
+
* marketplace, NFTs, contributions, and revenue distribution.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
|
|
8
|
+
/* ── In-memory stores ──────────────────────────────────────── */
|
|
9
|
+
const _balances = new Map();
|
|
10
|
+
const _channels = new Map();
|
|
11
|
+
const _market = new Map();
|
|
12
|
+
const _nfts = new Map();
|
|
13
|
+
const _contributions = new Map();
|
|
14
|
+
const _priceList = new Map();
|
|
15
|
+
|
|
16
|
+
/* ── Schema ────────────────────────────────────────────────── */
|
|
17
|
+
|
|
18
|
+
export function ensureEconomyTables(db) {
|
|
19
|
+
db.exec(`
|
|
20
|
+
CREATE TABLE IF NOT EXISTS economy_balances (
|
|
21
|
+
agent_id TEXT PRIMARY KEY,
|
|
22
|
+
balance REAL DEFAULT 0,
|
|
23
|
+
locked REAL DEFAULT 0,
|
|
24
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
25
|
+
)
|
|
26
|
+
`);
|
|
27
|
+
db.exec(`
|
|
28
|
+
CREATE TABLE IF NOT EXISTS economy_transactions (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
from_agent TEXT,
|
|
31
|
+
to_agent TEXT,
|
|
32
|
+
amount REAL NOT NULL,
|
|
33
|
+
type TEXT DEFAULT 'transfer',
|
|
34
|
+
description TEXT,
|
|
35
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
36
|
+
)
|
|
37
|
+
`);
|
|
38
|
+
db.exec(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS economy_channels (
|
|
40
|
+
id TEXT PRIMARY KEY,
|
|
41
|
+
party_a TEXT NOT NULL,
|
|
42
|
+
party_b TEXT NOT NULL,
|
|
43
|
+
balance_a REAL DEFAULT 0,
|
|
44
|
+
balance_b REAL DEFAULT 0,
|
|
45
|
+
status TEXT DEFAULT 'open',
|
|
46
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
47
|
+
)
|
|
48
|
+
`);
|
|
49
|
+
db.exec(`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS economy_market (
|
|
51
|
+
id TEXT PRIMARY KEY,
|
|
52
|
+
resource_type TEXT NOT NULL,
|
|
53
|
+
provider TEXT NOT NULL,
|
|
54
|
+
price REAL NOT NULL,
|
|
55
|
+
available REAL DEFAULT 0,
|
|
56
|
+
unit TEXT DEFAULT 'unit',
|
|
57
|
+
status TEXT DEFAULT 'active',
|
|
58
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
59
|
+
)
|
|
60
|
+
`);
|
|
61
|
+
db.exec(`
|
|
62
|
+
CREATE TABLE IF NOT EXISTS economy_nfts (
|
|
63
|
+
id TEXT PRIMARY KEY,
|
|
64
|
+
owner TEXT NOT NULL,
|
|
65
|
+
type TEXT NOT NULL,
|
|
66
|
+
metadata TEXT,
|
|
67
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
68
|
+
)
|
|
69
|
+
`);
|
|
70
|
+
db.exec(`
|
|
71
|
+
CREATE TABLE IF NOT EXISTS economy_contributions (
|
|
72
|
+
id TEXT PRIMARY KEY,
|
|
73
|
+
agent_id TEXT NOT NULL,
|
|
74
|
+
type TEXT NOT NULL,
|
|
75
|
+
value REAL DEFAULT 0,
|
|
76
|
+
proof TEXT,
|
|
77
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
78
|
+
)
|
|
79
|
+
`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ── Pricing ───────────────────────────────────────────────── */
|
|
83
|
+
|
|
84
|
+
export function priceService(db, serviceId, price, metadata) {
|
|
85
|
+
_priceList.set(serviceId, {
|
|
86
|
+
serviceId,
|
|
87
|
+
price,
|
|
88
|
+
metadata,
|
|
89
|
+
updatedAt: new Date().toISOString(),
|
|
90
|
+
});
|
|
91
|
+
return _priceList.get(serviceId);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function getServicePrice(serviceId) {
|
|
95
|
+
return _priceList.get(serviceId) || null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* ── Payments ──────────────────────────────────────────────── */
|
|
99
|
+
|
|
100
|
+
function _getBalance(agentId) {
|
|
101
|
+
if (!_balances.has(agentId)) {
|
|
102
|
+
_balances.set(agentId, { balance: 0, locked: 0 });
|
|
103
|
+
}
|
|
104
|
+
return _balances.get(agentId);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getBalance(agentId) {
|
|
108
|
+
return { ..._getBalance(agentId) };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function pay(db, fromAgent, toAgent, amount, description) {
|
|
112
|
+
if (amount <= 0) throw new Error("Amount must be positive");
|
|
113
|
+
|
|
114
|
+
const fromBal = _getBalance(fromAgent);
|
|
115
|
+
if (fromBal.balance < amount) {
|
|
116
|
+
throw new Error(`Insufficient balance: ${fromBal.balance} < ${amount}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fromBal.balance -= amount;
|
|
120
|
+
const toBal = _getBalance(toAgent);
|
|
121
|
+
toBal.balance += amount;
|
|
122
|
+
|
|
123
|
+
const txId = crypto.randomUUID();
|
|
124
|
+
const now = new Date().toISOString();
|
|
125
|
+
|
|
126
|
+
db.prepare(
|
|
127
|
+
`INSERT INTO economy_transactions (id, from_agent, to_agent, amount, type, description, created_at)
|
|
128
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
129
|
+
).run(txId, fromAgent, toAgent, amount, "transfer", description || "", now);
|
|
130
|
+
|
|
131
|
+
db.prepare(
|
|
132
|
+
`INSERT OR REPLACE INTO economy_balances (agent_id, balance, locked, updated_at)
|
|
133
|
+
VALUES (?, ?, ?, ?)`,
|
|
134
|
+
).run(fromAgent, fromBal.balance, fromBal.locked, now);
|
|
135
|
+
|
|
136
|
+
db.prepare(
|
|
137
|
+
`INSERT OR REPLACE INTO economy_balances (agent_id, balance, locked, updated_at)
|
|
138
|
+
VALUES (?, ?, ?, ?)`,
|
|
139
|
+
).run(toAgent, toBal.balance, toBal.locked, now);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
txId,
|
|
143
|
+
from: fromAgent,
|
|
144
|
+
to: toAgent,
|
|
145
|
+
amount,
|
|
146
|
+
balance: fromBal.balance,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* ── State Channels ────────────────────────────────────────── */
|
|
151
|
+
|
|
152
|
+
export function openChannel(db, partyA, partyB, depositA) {
|
|
153
|
+
const deposit = depositA || 0;
|
|
154
|
+
const balA = _getBalance(partyA);
|
|
155
|
+
if (deposit > 0 && balA.balance < deposit) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Insufficient balance for deposit: ${balA.balance} < ${deposit}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (deposit > 0) {
|
|
162
|
+
balA.balance -= deposit;
|
|
163
|
+
balA.locked += deposit;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const id = crypto.randomUUID();
|
|
167
|
+
const now = new Date().toISOString();
|
|
168
|
+
const channel = {
|
|
169
|
+
id,
|
|
170
|
+
partyA,
|
|
171
|
+
partyB,
|
|
172
|
+
balanceA: deposit,
|
|
173
|
+
balanceB: 0,
|
|
174
|
+
status: "open",
|
|
175
|
+
createdAt: now,
|
|
176
|
+
};
|
|
177
|
+
_channels.set(id, channel);
|
|
178
|
+
|
|
179
|
+
db.prepare(
|
|
180
|
+
`INSERT INTO economy_channels (id, party_a, party_b, balance_a, balance_b, status, created_at)
|
|
181
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
182
|
+
).run(id, partyA, partyB, deposit, 0, "open", now);
|
|
183
|
+
|
|
184
|
+
return channel;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function closeChannel(db, channelId) {
|
|
188
|
+
const channel = _channels.get(channelId);
|
|
189
|
+
if (!channel) throw new Error(`Channel not found: ${channelId}`);
|
|
190
|
+
if (channel.status === "closed") throw new Error("Channel already closed");
|
|
191
|
+
|
|
192
|
+
channel.status = "closed";
|
|
193
|
+
|
|
194
|
+
// Settle: return balances to parties
|
|
195
|
+
const balA = _getBalance(channel.partyA);
|
|
196
|
+
const balB = _getBalance(channel.partyB);
|
|
197
|
+
balA.balance += channel.balanceA;
|
|
198
|
+
balA.locked = Math.max(0, balA.locked - channel.balanceA);
|
|
199
|
+
balB.balance += channel.balanceB;
|
|
200
|
+
|
|
201
|
+
db.prepare(`UPDATE economy_channels SET status = 'closed' WHERE id = ?`).run(
|
|
202
|
+
channelId,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
return { ...channel };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* ── Marketplace ───────────────────────────────────────────── */
|
|
209
|
+
|
|
210
|
+
export function listResource(
|
|
211
|
+
db,
|
|
212
|
+
resourceType,
|
|
213
|
+
provider,
|
|
214
|
+
price,
|
|
215
|
+
available,
|
|
216
|
+
unit,
|
|
217
|
+
) {
|
|
218
|
+
const id = crypto.randomUUID();
|
|
219
|
+
const now = new Date().toISOString();
|
|
220
|
+
const listing = {
|
|
221
|
+
id,
|
|
222
|
+
resourceType,
|
|
223
|
+
provider,
|
|
224
|
+
price,
|
|
225
|
+
available,
|
|
226
|
+
unit: unit || "unit",
|
|
227
|
+
status: "active",
|
|
228
|
+
createdAt: now,
|
|
229
|
+
};
|
|
230
|
+
_market.set(id, listing);
|
|
231
|
+
|
|
232
|
+
db.prepare(
|
|
233
|
+
`INSERT INTO economy_market (id, resource_type, provider, price, available, unit, status, created_at)
|
|
234
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
235
|
+
).run(
|
|
236
|
+
id,
|
|
237
|
+
resourceType,
|
|
238
|
+
provider,
|
|
239
|
+
price,
|
|
240
|
+
available,
|
|
241
|
+
listing.unit,
|
|
242
|
+
"active",
|
|
243
|
+
now,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
return listing;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function getMarketListings(filter) {
|
|
250
|
+
let listings = [..._market.values()].filter((l) => l.status === "active");
|
|
251
|
+
if (filter) {
|
|
252
|
+
if (filter.type)
|
|
253
|
+
listings = listings.filter((l) => l.resourceType === filter.type);
|
|
254
|
+
if (filter.provider)
|
|
255
|
+
listings = listings.filter((l) => l.provider === filter.provider);
|
|
256
|
+
}
|
|
257
|
+
return listings;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function tradeResource(listingId, buyer, quantity) {
|
|
261
|
+
const listing = _market.get(listingId);
|
|
262
|
+
if (!listing) throw new Error(`Listing not found: ${listingId}`);
|
|
263
|
+
if (listing.available < quantity) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
`Insufficient availability: ${listing.available} < ${quantity}`,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const cost = listing.price * quantity;
|
|
270
|
+
const buyerBal = _getBalance(buyer);
|
|
271
|
+
if (buyerBal.balance < cost) {
|
|
272
|
+
throw new Error(`Insufficient balance: ${buyerBal.balance} < ${cost}`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
buyerBal.balance -= cost;
|
|
276
|
+
const sellerBal = _getBalance(listing.provider);
|
|
277
|
+
sellerBal.balance += cost;
|
|
278
|
+
listing.available -= quantity;
|
|
279
|
+
|
|
280
|
+
if (listing.available <= 0) listing.status = "sold_out";
|
|
281
|
+
|
|
282
|
+
return { listingId, buyer, quantity, cost, remaining: listing.available };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* ── NFTs ──────────────────────────────────────────────────── */
|
|
286
|
+
|
|
287
|
+
export function mintNFT(db, owner, type, metadata) {
|
|
288
|
+
const id = crypto.randomUUID();
|
|
289
|
+
const now = new Date().toISOString();
|
|
290
|
+
const nft = { id, owner, type, metadata: metadata || {}, createdAt: now };
|
|
291
|
+
_nfts.set(id, nft);
|
|
292
|
+
|
|
293
|
+
db.prepare(
|
|
294
|
+
`INSERT INTO economy_nfts (id, owner, type, metadata, created_at)
|
|
295
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
296
|
+
).run(id, owner, type, JSON.stringify(nft.metadata), now);
|
|
297
|
+
|
|
298
|
+
return nft;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* ── Contributions ─────────────────────────────────────────── */
|
|
302
|
+
|
|
303
|
+
export function recordContribution(db, agentId, type, value, proof) {
|
|
304
|
+
const id = crypto.randomUUID();
|
|
305
|
+
const now = new Date().toISOString();
|
|
306
|
+
const contribution = {
|
|
307
|
+
id,
|
|
308
|
+
agentId,
|
|
309
|
+
type,
|
|
310
|
+
value,
|
|
311
|
+
proof: proof || "",
|
|
312
|
+
createdAt: now,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
if (!_contributions.has(agentId)) _contributions.set(agentId, []);
|
|
316
|
+
_contributions.get(agentId).push(contribution);
|
|
317
|
+
|
|
318
|
+
db.prepare(
|
|
319
|
+
`INSERT INTO economy_contributions (id, agent_id, type, value, proof, created_at)
|
|
320
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
321
|
+
).run(id, agentId, type, value, contribution.proof, now);
|
|
322
|
+
|
|
323
|
+
return contribution;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function getContributions(agentId) {
|
|
327
|
+
return _contributions.get(agentId) || [];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ── Revenue Distribution ──────────────────────────────────── */
|
|
331
|
+
|
|
332
|
+
export function distributeRevenue(db, pool, agentIds) {
|
|
333
|
+
if (!agentIds || agentIds.length === 0)
|
|
334
|
+
throw new Error("No agents specified");
|
|
335
|
+
if (pool <= 0) throw new Error("Pool must be positive");
|
|
336
|
+
|
|
337
|
+
const share = pool / agentIds.length;
|
|
338
|
+
const results = [];
|
|
339
|
+
|
|
340
|
+
for (const agentId of agentIds) {
|
|
341
|
+
const bal = _getBalance(agentId);
|
|
342
|
+
bal.balance += share;
|
|
343
|
+
|
|
344
|
+
const now = new Date().toISOString();
|
|
345
|
+
db.prepare(
|
|
346
|
+
`INSERT OR REPLACE INTO economy_balances (agent_id, balance, locked, updated_at)
|
|
347
|
+
VALUES (?, ?, ?, ?)`,
|
|
348
|
+
).run(agentId, bal.balance, bal.locked, now);
|
|
349
|
+
|
|
350
|
+
results.push({ agentId, share, newBalance: bal.balance });
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return results;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* ── Reset (for testing) ───────────────────────────────────── */
|
|
357
|
+
|
|
358
|
+
export function _resetState() {
|
|
359
|
+
_balances.clear();
|
|
360
|
+
_channels.clear();
|
|
361
|
+
_market.clear();
|
|
362
|
+
_nfts.clear();
|
|
363
|
+
_contributions.clear();
|
|
364
|
+
_priceList.clear();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function _setBalance(agentId, balance, locked) {
|
|
368
|
+
_balances.set(agentId, { balance, locked: locked || 0 });
|
|
369
|
+
}
|