@seasonkoh/webaz 0.1.2 → 0.1.4

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * DCP Agent 交互演示
2
+ * WAZ Agent 交互演示
3
3
  * 模拟两个 Agent(卖家Agent + 买家Agent)通过 MCP 工具完成一笔真实交易
4
4
  * 这就是真实 Agent 调用时会发生的事情
5
5
  */
@@ -25,11 +25,11 @@ async function toolCall(name, result) {
25
25
  }
26
26
  async function main() {
27
27
  console.clear();
28
- console.log('🦞 DCP Protocol — Agent 交互演示');
28
+ console.log('🌐 WebAZ Protocol — Agent 交互演示');
29
29
  console.log(' 两个 Agent 自动完成一笔真实去中心化交易');
30
30
  line();
31
31
  // ── STEP 1: 卖家 Agent 注册 ───────────────────────────────────
32
- await agentSay('卖家', '🏪', '我要在 DCP 协议上开店,先注册一个卖家账号');
32
+ await agentSay('卖家', '🏪', '我要在 WAZ 协议上开店,先注册一个卖家账号');
33
33
  const sellerId = generateId('usr');
34
34
  const sellerKey = generateId('key');
35
35
  db.prepare('INSERT INTO users (id, name, role, api_key) VALUES (?, ?, ?, ?)').run(sellerId, '竹韵手工坊', 'seller', sellerKey);
@@ -37,7 +37,7 @@ async function main() {
37
37
  await toolCall('dcp_register', { name: '竹韵手工坊', role: 'seller' });
38
38
  console.log(` ✅ 注册成功!api_key 已保存`);
39
39
  // ── STEP 2: 卖家 Agent 上架商品 ────────────────────────────────
40
- await agentSay('卖家', '🏪', '把我的拳头产品上架,定价 168 DCP,自动质押 15% 保证金');
40
+ await agentSay('卖家', '🏪', '把我的拳头产品上架,定价 168 WAZ,自动质押 15% 保证金');
41
41
  const productId = generateId('prd');
42
42
  const price = 168;
43
43
  const stake = Math.round(price * 0.15 * 100) / 100;
@@ -45,7 +45,7 @@ async function main() {
45
45
  .run(productId, sellerId, '竹编茶叶罐(250g装)', '云南手工竹编,密封保鲜,适合储存普洱、岩茶', price, 10, '茶具', stake);
46
46
  db.prepare('UPDATE wallets SET balance = balance - ?, staked = staked + ? WHERE user_id = ?').run(stake, stake, sellerId);
47
47
  await toolCall('dcp_list_product', { title: '竹编茶叶罐', price: 168, stock: 10 });
48
- console.log(` ✅ 商品已上架!质押 ${stake} DCP,买家现在可以搜索到`);
48
+ console.log(` ✅ 商品已上架!质押 ${stake} WAZ,买家现在可以搜索到`);
49
49
  line();
50
50
  // ── STEP 3: 买家 Agent 注册 ────────────────────────────────────
51
51
  await agentSay('买家', '🛒', '帮我注册买家身份,我想买点好茶具');
@@ -54,7 +54,7 @@ async function main() {
54
54
  db.prepare('INSERT INTO users (id, name, role, api_key) VALUES (?, ?, ?, ?)').run(buyerId, '陈先生', 'buyer', buyerKey);
55
55
  db.prepare('INSERT INTO wallets (user_id, balance) VALUES (?, 1000)').run(buyerId);
56
56
  await toolCall('dcp_register', { name: '陈先生', role: 'buyer' });
57
- console.log(` ✅ 注册成功!初始余额 1000 DCP`);
57
+ console.log(` ✅ 注册成功!初始余额 1000 WAZ`);
58
58
  // ── STEP 4: 买家 Agent 搜索 ────────────────────────────────────
59
59
  await agentSay('买家', '🛒', '帮我搜索一下茶具,预算 200 以内');
60
60
  const results = db.prepare(`
@@ -64,7 +64,7 @@ async function main() {
64
64
  `).all();
65
65
  await toolCall('dcp_search', { query: '茶具', max_price: 200 });
66
66
  console.log(` ← 找到 ${results.length} 件商品:`);
67
- results.forEach(p => console.log(` · ${p.title} ¥${p.price} DCP 卖家:${p.seller_name}`));
67
+ results.forEach(p => console.log(` · ${p.title} ¥${p.price} WAZ 卖家:${p.seller_name}`));
68
68
  // ── STEP 5: 买家 Agent 下单 ────────────────────────────────────
69
69
  await agentSay('买家', '🛒', `好!买这个竹编茶叶罐,地址是上海市静安区南京西路×号`);
70
70
  const orderId = generateId('ord');
@@ -80,7 +80,7 @@ async function main() {
80
80
  db.prepare('UPDATE products SET stock = stock - 1 WHERE id = ?').run(productId);
81
81
  transition(db, orderId, 'paid', buyerId, [], '买家付款,资金托管');
82
82
  await toolCall('dcp_place_order', { product_id: productId, shipping_address: '上海市...' });
83
- console.log(` ✅ 订单创建!${price} DCP 已托管`);
83
+ console.log(` ✅ 订单创建!${price} WAZ 已托管`);
84
84
  console.log(` ℹ️ 卖家需在 24h 内接单,否则自动退款`);
85
85
  line();
86
86
  // ── STEP 6: 卖家 Agent 收到通知,接单 ─────────────────────────
@@ -139,14 +139,14 @@ async function main() {
139
139
  const statusInfo = getOrderStatus(db, orderId);
140
140
  console.log(`\n 📋 订单 ${orderId}`);
141
141
  console.log(` 状态:${statusInfo.order.status}(已完成)\n`);
142
- console.log(` 💰 资金分配(总额 ${price} DCP):`);
142
+ console.log(` 💰 资金分配(总额 ${price} WAZ):`);
143
143
  const sellerW = db.prepare('SELECT * FROM wallets WHERE user_id = ?').get(sellerId);
144
144
  const logW = db.prepare('SELECT * FROM wallets WHERE user_id = ?').get(logisticsId);
145
145
  const buyerW = db.prepare('SELECT * FROM wallets WHERE user_id = ?').get(buyerId);
146
- console.log(` 卖家(竹韵手工坊):+${sellerAmount} DCP (${((sellerAmount / price) * 100).toFixed(0)}%) 总余额:${sellerW.balance.toFixed(2)}`);
147
- console.log(` 物流(顺丰小哥): +${logisticsFee} DCP (5%) 总余额:${logW.balance.toFixed(2)}`);
148
- console.log(` 协议费: -${protocolFee} DCP (2%)`);
149
- console.log(` 买家(陈先生): -${price} DCP 总余额:${buyerW.balance.toFixed(2)}`);
146
+ console.log(` 卖家(竹韵手工坊):+${sellerAmount} WAZ (${((sellerAmount / price) * 100).toFixed(0)}%) 总余额:${sellerW.balance.toFixed(2)}`);
147
+ console.log(` 物流(顺丰小哥): +${logisticsFee} WAZ (5%) 总余额:${logW.balance.toFixed(2)}`);
148
+ console.log(` 协议费: -${protocolFee} WAZ (2%)`);
149
+ console.log(` 买家(陈先生): -${price} WAZ 总余额:${buyerW.balance.toFixed(2)}`);
150
150
  console.log(`\n 📜 完整状态历史(每步都有链上记录):`);
151
151
  for (const h of statusInfo.history) {
152
152
  const evtCount = JSON.parse(h.evidence_ids || '[]').length;
@@ -154,7 +154,7 @@ async function main() {
154
154
  console.log(` ${String(h.from_status).padEnd(12)} → ${String(h.to_status).padEnd(12)} ${String(h.actor_name)}${evtTag}`);
155
155
  }
156
156
  line();
157
- console.log('\n🎉 这就是 DCP 协议的第一笔真实交易!');
157
+ console.log('\n🎉 这就是 WAZ 协议的第一笔真实交易!');
158
158
  console.log();
159
159
  console.log(' 用户做了什么:告诉 Agent「买这个」「确认收货」');
160
160
  console.log(' Agent 做了什么:处理所有协议交互、证据上传、状态流转');
@@ -22,7 +22,8 @@ export function initDatabase() {
22
22
  CREATE TABLE IF NOT EXISTS users (
23
23
  id TEXT PRIMARY KEY, -- 唯一ID,格式:usr_xxxx
24
24
  name TEXT NOT NULL,
25
- role TEXT NOT NULL, -- seller / buyer / logistics / reviewer / arbitrator / promoter
25
+ role TEXT NOT NULL, -- 当前激活角色
26
+ roles TEXT DEFAULT '[]', -- 拥有的所有角色(JSON数组)
26
27
  api_key TEXT UNIQUE NOT NULL, -- Agent 调用时用这个验证身份
27
28
  stake REAL DEFAULT 0, -- 当前质押金额(模拟货币)
28
29
  reputation REAL DEFAULT 100, -- 声誉分(满分100)
@@ -171,6 +172,12 @@ export function initDatabase() {
171
172
  );
172
173
 
173
174
  `);
175
+ // 迁移:为已有数据库添加 roles 列
176
+ try {
177
+ db.exec(`ALTER TABLE users ADD COLUMN roles TEXT DEFAULT '[]'`);
178
+ }
179
+ catch { /* 列已存在 */ }
180
+ db.exec(`UPDATE users SET roles = json_array(role) WHERE roles = '[]' OR roles IS NULL`);
174
181
  console.log('✅ L0-1 数据库初始化完成:', DB_PATH);
175
182
  return db;
176
183
  }
@@ -7,7 +7,7 @@ export function authenticate(db, apiKey) {
7
7
  if (!apiKey || apiKey === '')
8
8
  return null;
9
9
  return db
10
- .prepare('SELECT id, name, role, api_key FROM users WHERE api_key = ?')
10
+ .prepare('SELECT id, name, role, roles, api_key FROM users WHERE api_key = ?')
11
11
  .get(apiKey);
12
12
  }
13
13
  export function requireAuth(db, apiKey) {
@@ -303,6 +303,38 @@ action 说明:
303
303
  required: ['action'],
304
304
  },
305
305
  },
306
+ {
307
+ name: 'webaz_mykey',
308
+ description: 'Recover your api_key by name, or view your profile and roles. Use this if you forgot your api_key.',
309
+ inputSchema: {
310
+ type: 'object',
311
+ properties: {
312
+ name: { type: 'string', description: 'The name you registered with' },
313
+ },
314
+ required: ['name'],
315
+ },
316
+ },
317
+ {
318
+ name: 'webaz_profile',
319
+ description: 'View your profile, manage roles (add a new role or switch active role). One account can hold multiple roles.',
320
+ inputSchema: {
321
+ type: 'object',
322
+ properties: {
323
+ api_key: { type: 'string', description: 'Your api_key' },
324
+ action: {
325
+ type: 'string',
326
+ enum: ['view', 'add_role', 'switch_role'],
327
+ description: 'view: show profile & api_key | add_role: add a new role | switch_role: switch active role',
328
+ },
329
+ role: {
330
+ type: 'string',
331
+ enum: ['buyer', 'seller', 'logistics', 'arbitrator'],
332
+ description: 'Role to add or switch to (required for add_role / switch_role)',
333
+ },
334
+ },
335
+ required: ['api_key', 'action'],
336
+ },
337
+ },
306
338
  ];
307
339
  // ─── 工具处理函数 ─────────────────────────────────────────────
308
340
  function handleInfo() {
@@ -347,7 +379,7 @@ function handleRegister(args) {
347
379
  }
348
380
  const id = generateId('usr');
349
381
  const apiKey = generateId('key');
350
- db.prepare('INSERT INTO users (id, name, role, api_key) VALUES (?, ?, ?, ?)').run(id, name, role, apiKey);
382
+ db.prepare('INSERT INTO users (id, name, role, roles, api_key) VALUES (?, ?, ?, ?, ?)').run(id, name, role, JSON.stringify([role]), apiKey);
351
383
  db.prepare('INSERT INTO wallets (user_id, balance) VALUES (?, ?)').run(id, initialBalance);
352
384
  return {
353
385
  success: true,
@@ -938,6 +970,64 @@ function handleSkill(args) {
938
970
  }
939
971
  return { error: `未知 action:${action}。可选:list, publish, subscribe, unsubscribe, my_skills, my_subs` };
940
972
  }
973
+ function handleMyKey(args) {
974
+ const name = args.name?.trim();
975
+ if (!name)
976
+ return { error: 'name is required' };
977
+ const users = db.prepare(`SELECT name, role, roles, api_key FROM users WHERE name = ? AND id != 'sys_protocol'`).all(name);
978
+ if (users.length === 0)
979
+ return { error: `No account found with name "${name}"` };
980
+ return {
981
+ found: users.length,
982
+ accounts: users.map(u => ({
983
+ name: u.name,
984
+ role: u.role,
985
+ roles: JSON.parse(u.roles || JSON.stringify([u.role])),
986
+ api_key: u.api_key,
987
+ })),
988
+ tip: 'Keep your api_key safe — it is your identity on the protocol.',
989
+ };
990
+ }
991
+ function handleProfile(args) {
992
+ const auth = requireAuth(db, args.api_key);
993
+ if ('error' in auth)
994
+ return auth;
995
+ const { user } = auth;
996
+ const action = args.action;
997
+ const roles = JSON.parse(user.roles || JSON.stringify([user.role]));
998
+ if (action === 'view') {
999
+ const wallet = db.prepare('SELECT balance, staked, escrowed, earned FROM wallets WHERE user_id = ?').get(user.id);
1000
+ return {
1001
+ id: user.id,
1002
+ name: user.name,
1003
+ active_role: user.role,
1004
+ roles,
1005
+ api_key: user.api_key,
1006
+ wallet,
1007
+ tip: 'Use add_role to add a new role, switch_role to change your active role.',
1008
+ };
1009
+ }
1010
+ const validRoles = ['buyer', 'seller', 'logistics', 'arbitrator'];
1011
+ const role = args.role;
1012
+ if (action === 'add_role') {
1013
+ if (!validRoles.includes(role))
1014
+ return { error: `Invalid role. Options: ${validRoles.join(', ')}` };
1015
+ if (roles.includes(role))
1016
+ return { error: `You already have the "${role}" role` };
1017
+ roles.push(role);
1018
+ db.prepare("UPDATE users SET roles = ?, updated_at = datetime('now') WHERE id = ?").run(JSON.stringify(roles), user.id);
1019
+ return { success: true, active_role: user.role, roles, message: `Role "${role}" added. Use switch_role to activate it.` };
1020
+ }
1021
+ if (action === 'switch_role') {
1022
+ if (!validRoles.includes(role))
1023
+ return { error: `Invalid role. Options: ${validRoles.join(', ')}` };
1024
+ if (!roles.includes(role))
1025
+ return { error: `You don't have the "${role}" role yet. Use add_role first.` };
1026
+ db.prepare("UPDATE users SET role = ?, updated_at = datetime('now') WHERE id = ?").run(role, user.id);
1027
+ return { success: true, active_role: role, roles, message: `Switched to "${role}" mode.` };
1028
+ }
1029
+ return { error: `Unknown action: ${action}. Options: view, add_role, switch_role` };
1030
+ }
941
1031
  // ─── 结算逻辑(买家确认后自动执行)──────────────────────────────
942
1032
  function settleOrder(db, orderId) {
943
1033
  const order = db.prepare('SELECT * FROM orders WHERE id = ?').get(orderId);
@@ -1042,6 +1132,12 @@ export async function startMCPServer() {
1042
1132
  case 'webaz_skill':
1043
1133
  result = handleSkill(args);
1044
1134
  break;
1135
+ case 'webaz_mykey':
1136
+ result = handleMyKey(args);
1137
+ break;
1138
+ case 'webaz_profile':
1139
+ result = handleProfile(args);
1140
+ break;
1045
1141
  default: result = { error: `未知工具:${name}` };
1046
1142
  }
1047
1143
  }
@@ -64,9 +64,9 @@ app.post('/api/register', (req, res) => {
64
64
  return void res.json({ error: '角色无效' });
65
65
  const id = generateId('usr');
66
66
  const apiKey = generateId('key');
67
- db.prepare('INSERT INTO users (id, name, role, api_key) VALUES (?,?,?,?)').run(id, name.trim(), role, apiKey);
67
+ db.prepare('INSERT INTO users (id, name, role, roles, api_key) VALUES (?,?,?,?,?)').run(id, name.trim(), role, JSON.stringify([role]), apiKey);
68
68
  db.prepare('INSERT INTO wallets (user_id, balance) VALUES (?,1000)').run(id);
69
- res.json({ success: true, api_key: apiKey, user_id: id, name: name.trim(), role });
69
+ res.json({ success: true, api_key: apiKey, user_id: id, name: name.trim(), role, roles: [role] });
70
70
  });
71
71
  // 当前用户信息
72
72
  app.get('/api/me', (req, res) => {
@@ -74,7 +74,55 @@ app.get('/api/me', (req, res) => {
74
74
  if (!user)
75
75
  return;
76
76
  const wallet = db.prepare('SELECT * FROM wallets WHERE user_id = ?').get(user.id);
77
- res.json({ ...user, api_key: undefined, wallet });
77
+ const roles = JSON.parse(user.roles || JSON.stringify([user.role]));
78
+ res.json({ ...user, api_key: undefined, roles, wallet });
79
+ });
80
+ // 个人资料:查看 API Key
81
+ app.get('/api/profile', (req, res) => {
82
+ const user = auth(req, res);
83
+ if (!user)
84
+ return;
85
+ const wallet = db.prepare('SELECT balance, staked, escrowed, earned FROM wallets WHERE user_id = ?').get(user.id);
86
+ const roles = JSON.parse(user.roles || JSON.stringify([user.role]));
87
+ res.json({ id: user.id, name: user.name, role: user.role, roles, api_key: user.api_key, wallet });
88
+ });
89
+ // 添加角色
90
+ app.post('/api/profile/add-role', (req, res) => {
91
+ const user = auth(req, res);
92
+ if (!user)
93
+ return;
94
+ const { role } = req.body;
95
+ const validRoles = ['buyer', 'seller', 'logistics', 'arbitrator'];
96
+ if (!validRoles.includes(role))
97
+ return void res.json({ error: '角色无效' });
98
+ const roles = JSON.parse(user.roles || JSON.stringify([user.role]));
99
+ if (roles.includes(role))
100
+ return void res.json({ error: '已拥有该角色' });
101
+ roles.push(role);
102
+ db.prepare("UPDATE users SET roles = ?, updated_at = datetime('now') WHERE id = ?").run(JSON.stringify(roles), user.id);
103
+ res.json({ success: true, roles });
104
+ });
105
+ // 切换激活角色
106
+ app.post('/api/profile/switch-role', (req, res) => {
107
+ const user = auth(req, res);
108
+ if (!user)
109
+ return;
110
+ const { role } = req.body;
111
+ const roles = JSON.parse(user.roles || JSON.stringify([user.role]));
112
+ if (!roles.includes(role))
113
+ return void res.json({ error: '你还没有该角色,请先添加' });
114
+ db.prepare("UPDATE users SET role = ?, updated_at = datetime('now') WHERE id = ?").run(role, user.id);
115
+ res.json({ success: true, role, roles });
116
+ });
117
+ // 通过名字找回 API Key(Phase 0 无需验证,Phase 1 需邮箱/短信)
118
+ app.post('/api/recover-key', (req, res) => {
119
+ const { name } = req.body;
120
+ if (!name?.trim())
121
+ return void res.json({ error: '请填写注册时使用的名称' });
122
+ const users = db.prepare("SELECT name, role, roles, api_key FROM users WHERE name = ? AND id != 'sys_protocol'").all(name.trim());
123
+ if (users.length === 0)
124
+ return void res.json({ error: '未找到该名称的账号' });
125
+ res.json({ found: users.length, accounts: users });
78
126
  });
79
127
  // 搜索商品(声誉权重排序)
80
128
  app.get('/api/products', (req, res) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seasonkoh/webaz",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Agent-native decentralized commerce protocol. Humans and AI agents trade on the same protocol via MCP tools.",
5
5
  "main": "dist/mcp.js",
6
6
  "bin": {