@seasonkoh/webaz 0.1.3 → 0.1.5

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.
@@ -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,7 +172,13 @@ export function initDatabase() {
171
172
  );
172
173
 
173
174
  `);
174
- console.log('✅ L0-1 数据库初始化完成:', DB_PATH);
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`);
181
+ console.error('✅ L0-1 数据库初始化完成:', DB_PATH);
175
182
  return db;
176
183
  }
177
184
  // 生成唯一 ID 的工具函数
@@ -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.3",
3
+ "version": "0.1.5",
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": {