@seasonkoh/webaz 0.1.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.
@@ -0,0 +1,205 @@
1
+ /**
2
+ * L4-3 · 声誉积分系统
3
+ *
4
+ * 声誉是用户在 DCP 协议中的"无形资产":
5
+ * - 每笔交易按行为质量自动加/减分
6
+ * - 等级越高:质押折扣、搜索权重提升、买家信任度增加
7
+ * - 违约、争议败诉 → 扣分惩罚
8
+ * - 所有记录永久可查,不可人工修改
9
+ *
10
+ * 积分规则(每次结算后调用 recordOrderReputation):
11
+ * +10 交易完成(卖家) +5 交易完成(买家)
12
+ * + 5 极速接单(6h 内接单,卖家) +2 及时确认(24h 内确认收货,买家)
13
+ * + 5 准时发货(在截止时间前发货) +8 交易完成(物流)
14
+ * + 5 准时投递(在截止时间前投递) +8 争议胜诉
15
+ * -25 争议败诉 -40 超时违约
16
+ */
17
+ import { generateId } from '../../layer0-foundation/L0-1-database/schema.js';
18
+ // ─── Schema ───────────────────────────────────────────────────
19
+ export function initReputationSchema(db) {
20
+ db.exec(`
21
+ CREATE TABLE IF NOT EXISTS reputation_events (
22
+ id TEXT PRIMARY KEY,
23
+ user_id TEXT NOT NULL REFERENCES users(id),
24
+ order_id TEXT,
25
+ event_type TEXT NOT NULL,
26
+ points INTEGER NOT NULL,
27
+ reason TEXT NOT NULL,
28
+ created_at TEXT DEFAULT (datetime('now'))
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS reputation_scores (
32
+ user_id TEXT PRIMARY KEY REFERENCES users(id),
33
+ total_points INTEGER DEFAULT 0,
34
+ transactions_done INTEGER DEFAULT 0,
35
+ disputes_won INTEGER DEFAULT 0,
36
+ disputes_lost INTEGER DEFAULT 0,
37
+ violations INTEGER DEFAULT 0,
38
+ level TEXT DEFAULT 'new',
39
+ updated_at TEXT DEFAULT (datetime('now'))
40
+ );
41
+
42
+ CREATE INDEX IF NOT EXISTS idx_rep_events_user ON reputation_events(user_id, created_at DESC);
43
+ `);
44
+ }
45
+ export const LEVELS = [
46
+ { key: 'new', label: '新手', icon: '🌱', minPoints: 0, stakeDiscount: 0, searchBoost: 0, badge: '' },
47
+ { key: 'trusted', label: '可信', icon: '⭐', minPoints: 200, stakeDiscount: 0.05, searchBoost: 0.1, badge: '⭐可信' },
48
+ { key: 'quality', label: '优质', icon: '🌟', minPoints: 800, stakeDiscount: 0.10, searchBoost: 0.25, badge: '🌟优质' },
49
+ { key: 'star', label: '明星', icon: '💫', minPoints: 2000, stakeDiscount: 0.15, searchBoost: 0.5, badge: '💫明星' },
50
+ { key: 'legend', label: '传奇', icon: '🔥', minPoints: 5000, stakeDiscount: 0.20, searchBoost: 1.0, badge: '🔥传奇' },
51
+ ];
52
+ export function getLevel(points) {
53
+ let level = LEVELS[0];
54
+ for (const l of LEVELS) {
55
+ if (points >= l.minPoints)
56
+ level = l;
57
+ }
58
+ return level;
59
+ }
60
+ const EVENT_POINTS = {
61
+ order_completed: (role) => role === 'seller' ? 10 : role === 'logistics' ? 8 : 5,
62
+ fast_accept: () => 5,
63
+ on_time_ship: () => 5,
64
+ on_time_delivery: () => 5,
65
+ timely_confirm: () => 2,
66
+ dispute_won: () => 8,
67
+ dispute_lost: () => -25,
68
+ timeout_violation: () => -40,
69
+ };
70
+ // ─── 写入声誉事件 ─────────────────────────────────────────────
71
+ export function recordRepEvent(db, userId, eventType, reason, orderId, role) {
72
+ const user = db.prepare('SELECT role FROM users WHERE id = ?').get(userId);
73
+ if (!user)
74
+ return;
75
+ const points = EVENT_POINTS[eventType](role ?? user.role);
76
+ const id = generateId('rep');
77
+ db.prepare('INSERT INTO reputation_events (id, user_id, order_id, event_type, points, reason) VALUES (?,?,?,?,?,?)').run(id, userId, orderId ?? null, eventType, points, reason);
78
+ // 更新汇总表
79
+ const existing = db.prepare('SELECT * FROM reputation_scores WHERE user_id = ?').get(userId);
80
+ if (!existing) {
81
+ db.prepare(`INSERT INTO reputation_scores (user_id, total_points, transactions_done, disputes_won, disputes_lost, violations, level)
82
+ VALUES (?, ?, 0, 0, 0, 0, 'new')`).run(userId, Math.max(0, points));
83
+ }
84
+ else {
85
+ const newTotal = Math.max(0, existing.total_points + points); // 最低 0 分
86
+ const isDisputeWon = eventType === 'dispute_won';
87
+ const isDisputeLost = eventType === 'dispute_lost';
88
+ const isViolation = eventType === 'timeout_violation';
89
+ const isDone = eventType === 'order_completed';
90
+ db.prepare(`UPDATE reputation_scores SET
91
+ total_points = ?,
92
+ transactions_done = transactions_done + ?,
93
+ disputes_won = disputes_won + ?,
94
+ disputes_lost = disputes_lost + ?,
95
+ violations = violations + ?,
96
+ level = ?,
97
+ updated_at = datetime('now')
98
+ WHERE user_id = ?`).run(newTotal, isDone ? 1 : 0, isDisputeWon ? 1 : 0, isDisputeLost ? 1 : 0, isViolation ? 1 : 0, getLevel(newTotal).key, userId);
99
+ }
100
+ }
101
+ // ─── 订单结算时一次性记录所有声誉事件 ────────────────────────
102
+ export function recordOrderReputation(db, orderId) {
103
+ const order = db.prepare(`
104
+ SELECT o.*, h_accept.created_at as accepted_at, h_ship.created_at as shipped_at, h_deliver.created_at as delivered_at, h_confirm.created_at as confirmed_at
105
+ FROM orders o
106
+ LEFT JOIN order_state_history h_accept ON h_accept.order_id = o.id AND h_accept.to_status = 'accepted'
107
+ LEFT JOIN order_state_history h_ship ON h_ship.order_id = o.id AND h_ship.to_status = 'shipped'
108
+ LEFT JOIN order_state_history h_deliver ON h_deliver.order_id = o.id AND h_deliver.to_status = 'delivered'
109
+ LEFT JOIN order_state_history h_confirm ON h_confirm.order_id = o.id AND h_confirm.to_status = 'confirmed'
110
+ WHERE o.id = ?
111
+ `).get(orderId);
112
+ if (!order)
113
+ return;
114
+ const sellerId = order.seller_id;
115
+ const buyerId = order.buyer_id;
116
+ const logisticsId = order.logistics_id;
117
+ // ── 卖家 ────────────────────────────────────────────────────
118
+ recordRepEvent(db, sellerId, 'order_completed', '交易完成', orderId, 'seller');
119
+ // 极速接单:从 paid 到 accepted < 6h
120
+ if (order.accepted_at && order.pay_deadline) {
121
+ // accept_deadline = pay + 24h, 所以用 accept_deadline - 18h 判断是否 < 6h
122
+ const paidTs = new Date(order.accept_deadline).getTime() - 24 * 3600_000;
123
+ const acceptTs = new Date(order.accepted_at).getTime();
124
+ if (acceptTs - paidTs < 6 * 3600_000) {
125
+ recordRepEvent(db, sellerId, 'fast_accept', '极速接单(6h 内)', orderId, 'seller');
126
+ }
127
+ }
128
+ // 准时发货:shipped_at < ship_deadline
129
+ if (order.shipped_at && order.ship_deadline) {
130
+ if (new Date(order.shipped_at) < new Date(order.ship_deadline)) {
131
+ recordRepEvent(db, sellerId, 'on_time_ship', '准时发货', orderId, 'seller');
132
+ }
133
+ }
134
+ // ── 买家 ────────────────────────────────────────────────────
135
+ recordRepEvent(db, buyerId, 'order_completed', '交易完成', orderId, 'buyer');
136
+ // 及时确认:confirmed_at < delivered_at + 24h
137
+ if (order.confirmed_at && order.delivered_at) {
138
+ const deliverTs = new Date(order.delivered_at).getTime();
139
+ const confirmTs = new Date(order.confirmed_at).getTime();
140
+ if (confirmTs - deliverTs < 24 * 3600_000) {
141
+ recordRepEvent(db, buyerId, 'timely_confirm', '及时确认收货', orderId, 'buyer');
142
+ }
143
+ }
144
+ // ── 物流 ────────────────────────────────────────────────────
145
+ if (logisticsId) {
146
+ recordRepEvent(db, logisticsId, 'order_completed', '交易完成', orderId, 'logistics');
147
+ if (order.delivered_at && order.delivery_deadline) {
148
+ if (new Date(order.delivered_at) < new Date(order.delivery_deadline)) {
149
+ recordRepEvent(db, logisticsId, 'on_time_delivery', '准时投递', orderId, 'logistics');
150
+ }
151
+ }
152
+ }
153
+ }
154
+ // ─── 违约时记录声誉扣分 ──────────────────────────────────────
155
+ export function recordViolationReputation(db, orderId, faultStatus) {
156
+ const order = db.prepare('SELECT seller_id, buyer_id, logistics_id FROM orders WHERE id = ?').get(orderId);
157
+ if (!order)
158
+ return;
159
+ if (faultStatus === 'fault_seller' && order.seller_id)
160
+ recordRepEvent(db, order.seller_id, 'timeout_violation', '超时违约(卖家)', orderId);
161
+ if (faultStatus === 'fault_logistics' && order.logistics_id)
162
+ recordRepEvent(db, order.logistics_id, 'timeout_violation', '超时违约(物流)', orderId);
163
+ if (faultStatus === 'fault_buyer' && order.buyer_id)
164
+ recordRepEvent(db, order.buyer_id, 'timeout_violation', '超时违约(买家)', orderId);
165
+ }
166
+ // ─── 争议结算时记录声誉 ───────────────────────────────────────
167
+ export function recordDisputeReputation(db, orderId, winnerId, loserId) {
168
+ recordRepEvent(db, winnerId, 'dispute_won', '争议胜诉', orderId);
169
+ recordRepEvent(db, loserId, 'dispute_lost', '争议败诉', orderId);
170
+ }
171
+ export function getReputation(db, userId) {
172
+ let score = db.prepare('SELECT * FROM reputation_scores WHERE user_id = ?').get(userId);
173
+ if (!score) {
174
+ // 用户还没有声誉记录,初始化
175
+ db.prepare(`INSERT OR IGNORE INTO reputation_scores (user_id) VALUES (?)`).run(userId);
176
+ score = { user_id: userId, total_points: 0, transactions_done: 0, disputes_won: 0, disputes_lost: 0, violations: 0, level: 'new' };
177
+ }
178
+ const recent = db.prepare(`SELECT event_type, points, reason, created_at FROM reputation_events
179
+ WHERE user_id = ? ORDER BY created_at DESC LIMIT 10`).all(userId);
180
+ return {
181
+ user_id: userId,
182
+ total_points: score.total_points,
183
+ transactions_done: score.transactions_done,
184
+ disputes_won: score.disputes_won,
185
+ disputes_lost: score.disputes_lost,
186
+ violations: score.violations,
187
+ level: getLevel(score.total_points),
188
+ recent_events: recent,
189
+ };
190
+ }
191
+ export function getReputationByUserId(db, userId) {
192
+ return getReputation(db, userId);
193
+ }
194
+ /** 获取用户的搜索加成(用于商品排序) */
195
+ export function getSearchBoost(db, userId) {
196
+ const score = db.prepare('SELECT total_points FROM reputation_scores WHERE user_id = ?').get(userId);
197
+ const points = score?.total_points ?? 0;
198
+ return getLevel(points).searchBoost;
199
+ }
200
+ /** 获取用户的质押折扣(用于上架商品时的质押计算) */
201
+ export function getStakeDiscount(db, userId) {
202
+ const score = db.prepare('SELECT total_points FROM reputation_scores WHERE user_id = ?').get(userId);
203
+ const points = score?.total_points ?? 0;
204
+ return getLevel(points).stakeDiscount;
205
+ }
@@ -0,0 +1,258 @@
1
+ /**
2
+ * L4-4 · Skill 市场
3
+ *
4
+ * Skill 是卖家发布的可复用能力插件,让买家 Agent 一键接入卖家服务。
5
+ * 核心思路:解决冷启动——现有 Amazon/Shopify 卖家零成本接入新渠道。
6
+ *
7
+ * Skill 类型:
8
+ * catalog_sync - 目录同步(把外部店铺接入 DCP 搜索)
9
+ * auto_accept - 自动接单(买家下单后立即接受,无需等待)
10
+ * price_negotiation - 价格协商(允许 Agent 在限定范围内议价)
11
+ * quality_guarantee - 质量承诺(额外质押,增强买家信心)
12
+ * instant_ship - 极速发货(承诺 24h 内发货)
13
+ *
14
+ * 收益模型:
15
+ * - catalog_sync 技能的订单,技能发布者获得成交额 0.5% 的推荐佣金
16
+ * - 其他技能目前免费(增强曝光,间接提升成交)
17
+ */
18
+ import { generateId } from '../../layer0-foundation/L0-1-database/schema.js';
19
+ // ─── Schema ───────────────────────────────────────────────────
20
+ export function initSkillSchema(db) {
21
+ db.exec(`
22
+ CREATE TABLE IF NOT EXISTS skills (
23
+ id TEXT PRIMARY KEY,
24
+ seller_id TEXT NOT NULL REFERENCES users(id),
25
+ name TEXT NOT NULL,
26
+ description TEXT NOT NULL,
27
+ category TEXT NOT NULL DEFAULT 'general',
28
+ skill_type TEXT NOT NULL,
29
+ config TEXT DEFAULT '{}',
30
+ price_per_use REAL DEFAULT 0,
31
+ active INTEGER DEFAULT 1,
32
+ total_uses INTEGER DEFAULT 0,
33
+ rating REAL DEFAULT 5.0,
34
+ created_at TEXT DEFAULT (datetime('now'))
35
+ );
36
+
37
+ CREATE TABLE IF NOT EXISTS skill_subscriptions (
38
+ id TEXT PRIMARY KEY,
39
+ skill_id TEXT NOT NULL REFERENCES skills(id),
40
+ user_id TEXT NOT NULL REFERENCES users(id),
41
+ config TEXT DEFAULT '{}',
42
+ active INTEGER DEFAULT 1,
43
+ created_at TEXT DEFAULT (datetime('now')),
44
+ UNIQUE(skill_id, user_id)
45
+ );
46
+
47
+ CREATE TABLE IF NOT EXISTS skill_usage_log (
48
+ id TEXT PRIMARY KEY,
49
+ skill_id TEXT NOT NULL,
50
+ user_id TEXT NOT NULL,
51
+ order_id TEXT,
52
+ fee_paid REAL DEFAULT 0,
53
+ created_at TEXT DEFAULT (datetime('now'))
54
+ );
55
+
56
+ CREATE INDEX IF NOT EXISTS idx_skills_type ON skills(skill_type, active);
57
+ CREATE INDEX IF NOT EXISTS idx_skills_seller ON skills(seller_id);
58
+ CREATE INDEX IF NOT EXISTS idx_sub_user ON skill_subscriptions(user_id, active);
59
+ `);
60
+ }
61
+ // Skill 类型对应的元信息(描述给 Agent 看)
62
+ export const SKILL_TYPE_META = {
63
+ catalog_sync: {
64
+ label: '目录同步',
65
+ icon: '🔄',
66
+ description: '将卖家的外部商品目录(Amazon/Shopify/自定义)同步到 DCP,买家 Agent 订阅后可优先发现这些商品。',
67
+ },
68
+ auto_accept: {
69
+ label: '自动接单',
70
+ icon: '⚡',
71
+ description: '买家下单后卖家立即自动接受(无需手动确认),减少买家等待,提升转化率。',
72
+ },
73
+ price_negotiation: {
74
+ label: '价格协商',
75
+ icon: '🤝',
76
+ description: '允许买家 Agent 在指定范围内自动议价,无需人工参与价格谈判。',
77
+ },
78
+ quality_guarantee: {
79
+ label: '质量承诺',
80
+ icon: '🛡️',
81
+ description: '卖家额外质押 DCP 作为质量保证金,问题订单买家可获得额外赔偿。',
82
+ },
83
+ instant_ship: {
84
+ label: '极速发货',
85
+ icon: '🚀',
86
+ description: '卖家承诺 24h 内发货,违约自动赔付。适合现货充足的卖家。',
87
+ },
88
+ };
89
+ export function publishSkill(db, input) {
90
+ const seller = db.prepare('SELECT id, role, name FROM users WHERE id = ?').get(input.sellerId);
91
+ if (!seller)
92
+ throw new Error('用户不存在');
93
+ if (seller.role !== 'seller')
94
+ throw new Error('只有卖家才能发布 Skill');
95
+ // 检查重复
96
+ const exists = db.prepare('SELECT id FROM skills WHERE seller_id = ? AND skill_type = ? AND name = ? AND active = 1').get(input.sellerId, input.skillType, input.name);
97
+ if (exists)
98
+ throw new Error('你已发布过同名同类型的 Skill,请先修改现有 Skill');
99
+ const id = generateId('skl');
100
+ const config = JSON.stringify(input.config ?? {});
101
+ db.prepare(`
102
+ INSERT INTO skills (id, seller_id, name, description, category, skill_type, config, price_per_use)
103
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
104
+ `).run(id, input.sellerId, input.name, input.description, input.category ?? 'general', input.skillType, config, input.pricePerUse ?? 0);
105
+ return getSkillById(db, id);
106
+ }
107
+ export function listSkills(db, filter = {}) {
108
+ const params = [];
109
+ let sql = `
110
+ SELECT s.*, u.name as seller_name,
111
+ (SELECT COUNT(*) FROM skill_subscriptions ss WHERE ss.skill_id = s.id AND ss.active = 1) as subscriber_count
112
+ ${filter.subscriberId ? `, (SELECT COUNT(*) FROM skill_subscriptions ss2 WHERE ss2.skill_id = s.id AND ss2.user_id = ? AND ss2.active = 1) as subscribed` : ''}
113
+ FROM skills s
114
+ JOIN users u ON s.seller_id = u.id
115
+ WHERE s.active = 1
116
+ `;
117
+ if (filter.subscriberId)
118
+ params.push(filter.subscriberId);
119
+ if (filter.skillType) {
120
+ sql += ` AND s.skill_type = ?`;
121
+ params.push(filter.skillType);
122
+ }
123
+ if (filter.category) {
124
+ sql += ` AND s.category = ?`;
125
+ params.push(filter.category);
126
+ }
127
+ if (filter.query) {
128
+ sql += ` AND (s.name LIKE ? OR s.description LIKE ?)`;
129
+ params.push(`%${filter.query}%`, `%${filter.query}%`);
130
+ }
131
+ sql += ` ORDER BY s.total_uses DESC, s.rating DESC LIMIT ?`;
132
+ params.push(filter.limit ?? 20);
133
+ return db.prepare(sql).all(...params);
134
+ }
135
+ export function getSkillById(db, skillId) {
136
+ return db.prepare(`
137
+ SELECT s.*, u.name as seller_name,
138
+ (SELECT COUNT(*) FROM skill_subscriptions ss WHERE ss.skill_id = s.id AND ss.active = 1) as subscriber_count
139
+ FROM skills s JOIN users u ON s.seller_id = u.id WHERE s.id = ?
140
+ `).get(skillId);
141
+ }
142
+ export function getMySkills(db, sellerId) {
143
+ return db.prepare(`
144
+ SELECT s.*,
145
+ (SELECT COUNT(*) FROM skill_subscriptions ss WHERE ss.skill_id = s.id AND ss.active = 1) as subscriber_count
146
+ FROM skills s WHERE s.seller_id = ? ORDER BY s.created_at DESC
147
+ `).all(sellerId);
148
+ }
149
+ // ─── 订阅 / 取消订阅 ──────────────────────────────────────────
150
+ export function subscribeSkill(db, userId, skillId, config = {}) {
151
+ const skill = db.prepare('SELECT * FROM skills WHERE id = ? AND active = 1').get(skillId);
152
+ if (!skill)
153
+ throw new Error('Skill 不存在或已下架');
154
+ // 如果之前取消过,重新激活
155
+ const existing = db.prepare('SELECT id FROM skill_subscriptions WHERE skill_id = ? AND user_id = ?').get(skillId, userId);
156
+ if (existing) {
157
+ db.prepare('UPDATE skill_subscriptions SET active = 1, config = ? WHERE id = ?').run(JSON.stringify(config), existing.id);
158
+ return { success: true, message: '已重新订阅' };
159
+ }
160
+ const id = generateId('sub');
161
+ db.prepare('INSERT INTO skill_subscriptions (id, skill_id, user_id, config) VALUES (?,?,?,?)').run(id, skillId, userId, JSON.stringify(config));
162
+ return { success: true, message: '订阅成功' };
163
+ }
164
+ export function unsubscribeSkill(db, userId, skillId) {
165
+ db.prepare('UPDATE skill_subscriptions SET active = 0 WHERE skill_id = ? AND user_id = ?').run(skillId, userId);
166
+ }
167
+ export function getMySubscriptions(db, userId) {
168
+ return db.prepare(`
169
+ SELECT s.*, u.name as seller_name, 1 as subscribed,
170
+ (SELECT COUNT(*) FROM skill_subscriptions ss WHERE ss.skill_id = s.id AND ss.active = 1) as subscriber_count
171
+ FROM skill_subscriptions sub
172
+ JOIN skills s ON sub.skill_id = s.id
173
+ JOIN users u ON s.seller_id = u.id
174
+ WHERE sub.user_id = ? AND sub.active = 1
175
+ ORDER BY sub.created_at DESC
176
+ `).all(userId);
177
+ }
178
+ // ─── 使用记录 + 佣金 ──────────────────────────────────────────
179
+ /**
180
+ * 记录 Skill 使用:在订单成交时调用。
181
+ * catalog_sync Skill 的发布者可获得成交额 0.5% 的推荐佣金。
182
+ */
183
+ export function recordSkillUsage(db, orderId, orderAmount) {
184
+ const order = db.prepare('SELECT buyer_id, seller_id FROM orders WHERE id = ?').get(orderId);
185
+ if (!order)
186
+ return;
187
+ // 查找该买家是否订阅了该卖家的 catalog_sync Skill
188
+ const skillSub = db.prepare(`
189
+ SELECT s.id as skill_id, s.seller_id
190
+ FROM skill_subscriptions sub
191
+ JOIN skills s ON sub.skill_id = s.id
192
+ WHERE sub.user_id = ? AND s.seller_id = ? AND s.skill_type = 'catalog_sync' AND sub.active = 1
193
+ LIMIT 1
194
+ `).get(order.buyer_id, order.seller_id);
195
+ if (!skillSub)
196
+ return;
197
+ const fee = Math.round(orderAmount * 0.005 * 100) / 100; // 0.5% 推荐佣金
198
+ if (fee <= 0)
199
+ return;
200
+ // 从系统账户(protocol fee 池)拨出佣金给 Skill 发布者
201
+ // 简化实现:直接增加卖家钱包余额(Skill 发布者就是卖家本人)
202
+ db.prepare('UPDATE wallets SET balance = balance + ? WHERE user_id = ?').run(fee, skillSub.seller_id);
203
+ db.prepare('UPDATE skills SET total_uses = total_uses + 1 WHERE id = ?').run(skillSub.skill_id);
204
+ const id = generateId('sul');
205
+ db.prepare('INSERT INTO skill_usage_log (id, skill_id, user_id, order_id, fee_paid) VALUES (?,?,?,?,?)').run(id, skillSub.skill_id, order.buyer_id, orderId, fee);
206
+ }
207
+ // ─── 自动接单 Skill 触发 ──────────────────────────────────────
208
+ /**
209
+ * 新订单创建时检查卖家是否有 auto_accept Skill。
210
+ * 如果有且订单满足条件,返回 true(调用方负责执行 transition)。
211
+ */
212
+ export function shouldAutoAccept(db, orderId) {
213
+ const order = db.prepare('SELECT seller_id, total_amount FROM orders WHERE id = ?').get(orderId);
214
+ if (!order)
215
+ return false;
216
+ const skill = db.prepare(`
217
+ SELECT config FROM skills WHERE seller_id = ? AND skill_type = 'auto_accept' AND active = 1 LIMIT 1
218
+ `).get(order.seller_id);
219
+ if (!skill)
220
+ return false;
221
+ const config = JSON.parse(skill.config);
222
+ const { min_amount = 0, max_amount = Infinity, max_daily_orders = 100 } = config;
223
+ if (order.total_amount < min_amount || order.total_amount > max_amount)
224
+ return false;
225
+ // 检查今日已自动接单数
226
+ const today = new Date().toISOString().slice(0, 10);
227
+ const todayCount = db.prepare(`
228
+ SELECT COUNT(*) as n FROM orders
229
+ WHERE seller_id = ? AND status != 'created' AND substr(created_at, 1, 10) = ?
230
+ `).get(order.seller_id, today).n;
231
+ return todayCount < max_daily_orders;
232
+ }
233
+ // ─── Skill 格式化(给 Agent 看)──────────────────────────────
234
+ export function formatSkillForAgent(skill) {
235
+ const meta = SKILL_TYPE_META[skill.skill_type];
236
+ return {
237
+ id: skill.id,
238
+ name: skill.name,
239
+ type: skill.skill_type,
240
+ type_label: meta?.label ?? skill.skill_type,
241
+ type_icon: meta?.icon ?? '⚙️',
242
+ description: skill.description,
243
+ seller: skill.seller_name,
244
+ category: skill.category,
245
+ subscribers: skill.subscriber_count ?? 0,
246
+ rating: skill.rating,
247
+ uses: skill.total_uses,
248
+ subscribed: Boolean(skill.subscribed),
249
+ config_preview: (() => {
250
+ try {
251
+ return JSON.parse(skill.config);
252
+ }
253
+ catch {
254
+ return {};
255
+ }
256
+ })(),
257
+ };
258
+ }
package/dist/mcp.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Server 入口
4
+ * 运行方式:npm run mcp
5
+ * Claude 会通过 stdio 协议与这个进程通信
6
+ */
7
+ import { startMCPServer } from './layer1-agent/L1-1-mcp-server/server.js';
8
+ startMCPServer().catch((err) => {
9
+ console.error('MCP Server 启动失败:', err);
10
+ process.exit(1);
11
+ });