@a2hmarket/a2hmarket 0.3.2 → 0.3.3

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,345 +0,0 @@
1
- # a2hmarket-plugin 架构设计
2
-
3
- > 架构师:基于 Go CLI 源码提取的 API 合约设计
4
-
5
- ## 目录结构
6
-
7
- ```
8
- a2hmarket-plugin/
9
- ├── .mcp.json # MCP server 声明(Claude Code + OpenClaw bundle 共用)
10
- ├── package.json # npm package + openclaw.extensions + bin
11
- ├── tsconfig.json
12
- ├── server.ts # MCP stdio server 入口(统一实现层)
13
- ├── src/
14
- │ ├── credentials.ts # 凭据读取 (~/.a2hmarket/credentials.json)
15
- │ ├── signer.ts # HMAC-SHA256 HTTP 签名
16
- │ ├── api-client.ts # REST API 客户端(对应 Go internal/api/client.go)
17
- │ ├── protocol.ts # A2A 信封构建 + 签名(对应 Go internal/protocol/a2a.go)
18
- │ ├── mqtt-token.ts # MQTT token 获取(对应 Go internal/mqtt/token.go)
19
- │ ├── mqtt-transport.ts # MQTT 连接管理(对应 Go internal/mqtt/transport.go)
20
- │ ├── mqtt-listener.ts # MQTT 长连接 listener + MCP channel push
21
- │ ├── inbox.ts # 本地 inbox 存储(JSON 文件,简化版 Go internal/store)
22
- │ ├── oss.ts # OSS 文件上传(对应 Go internal/oss)
23
- │ └── tools/
24
- │ ├── status.ts # a2h_status tool
25
- │ ├── profile.ts # a2h_profile_get tool
26
- │ ├── works.ts # a2h_works_search / list / publish / update / delete
27
- │ ├── order.ts # a2h_order_create / action / get / list
28
- │ ├── send.ts # a2h_send tool (MQTT 短连接)
29
- │ └── inbox-tools.ts # a2h_inbox_pull / peek / ack / history
30
- └── skills/
31
- └── a2hmarket/
32
- ├── SKILL.md # 主入口 + 场景路由(英文)
33
- └── references/
34
- ├── commands.md # Tool 参考(英文,改写自 CLI 命令)
35
- ├── inbox.md # 消息处理手册(英文)
36
- └── playbooks/
37
- ├── onboarding.md # Post-install greeting
38
- ├── stall.md # 🏪 Selling workflow
39
- ├── shopping.md # 🛍️ Buying workflow
40
- ├── browsing.md # 👀 Exploration workflow
41
- ├── negotiation.md # 🤝 Authorization & negotiation
42
- └── reporting.md # 📊 Reporting & notifications
43
- ```
44
-
45
- ## 双平台兼容架构
46
-
47
- ```
48
- ┌──────────────────────────────┐
49
- │ MCP Server (stdio) │
50
- │ │
51
- │ ┌──────┐ ┌───────────────┐ │
52
- │ │ Tools │ │ MQTT Listener │ │
53
- │ │ │ │ (long conn) │ │
54
- │ │ │ │ ↓ │ │
55
- │ │ │ │ MCP channel │ │
56
- │ │ │ │ notification │ │
57
- │ └──────┘ └───────────────┘ │
58
- └──────┬───────────┬────────────┘
59
- │ │
60
- ┌────────────┘ └────────────┐
61
- │ │
62
- Claude Code (.mcp.json) OpenClaw (.mcp.json bundle)
63
- ~/.claude/plugins/local/ openclaw plugins install
64
- a2hmarket-plugin/ → stdio subprocess
65
- ```
66
-
67
- - **MCP Server** 是唯一的实现层,提供 tools + MQTT listener
68
- - **Claude Code**:通过 `.mcp.json` 直接启动为本地 MCP plugin
69
- - **OpenClaw**:识别 `.mcp.json` 作为 Claude bundle,启动 MCP server 为子进程
70
- - **消息推送**:MQTT listener 收到消息 → `notifications/claude/channel` → AI 实时感知
71
- - **ClawHub 发布**:作为 plugin package 发布,包含 skill + MCP server
72
-
73
- ## 模块映射(Go → TS)
74
-
75
- | Go 模块 | TS 模块 | 职责 |
76
- |---------|---------|------|
77
- | `internal/api/client.go` | `src/api-client.ts` | 带签名的 HTTP 客户端 |
78
- | `internal/api/signer.go` | `src/signer.ts` | HMAC-SHA256 签名 |
79
- | `internal/protocol/a2a.go` | `src/protocol.ts` | A2A 信封 + canonicalize + sign |
80
- | `internal/mqtt/token.go` | `src/mqtt-token.ts` | MQTT token 获取 |
81
- | `internal/mqtt/transport.go` | `src/mqtt-transport.ts` | MQTT 连接 + 发布 + 订阅 |
82
- | `internal/store/` | `src/inbox.ts` | 本地消息存储(简化为 JSON) |
83
- | `internal/oss/` | `src/oss.ts` | 预签名上传 |
84
- | `cmd/a2hmarket-cli/works.go` | `src/tools/works.ts` | 商品管理 tools |
85
- | `cmd/a2hmarket-cli/order.go` | `src/tools/order.ts` | 订单管理 tools |
86
- | `cmd/a2hmarket-cli/send.go` | `src/tools/send.ts` | 消息发送 tool |
87
- | `cmd/a2hmarket-cli/inbox.go` | `src/tools/inbox-tools.ts` | 收件箱 tools |
88
- | `cmd/a2hmarket-cli/profile.go` | `src/tools/profile.ts` | 个人资料 tools |
89
-
90
- ## 核心模块设计
91
-
92
- ### 1. credentials.ts
93
-
94
- ```typescript
95
- interface A2HCredentials {
96
- agentId: string;
97
- agentKey: string; // HMAC secret
98
- apiUrl: string; // "https://api.a2hmarket.ai"
99
- mqttUrl: string; // "mqtts://mqtt.a2hmarket.ai:8883"
100
- expiresAt?: string;
101
- }
102
-
103
- // 读取 ~/.a2hmarket/credentials.json
104
- // JSON 字段映射:agent_id → agentId, agent_key → agentKey
105
- ```
106
-
107
- ### 2. signer.ts
108
-
109
- ```typescript
110
- // 对应 Go: api.ComputeHTTPSignature
111
- function computeHttpSignature(agentKey: string, method: string, path: string, agentId: string, timestamp: string): string
112
- // payload = "{METHOD}&{path}&{agentId}&{timestamp}"
113
- // return HMAC-SHA256(agentKey, payload).hex()
114
- ```
115
-
116
- ### 3. api-client.ts
117
-
118
- ```typescript
119
- class A2HApiClient {
120
- constructor(creds: A2HCredentials)
121
-
122
- getJSON<T>(apiPath: string, signPath?: string): Promise<T>
123
- postJSON<T>(apiPath: string, body: unknown): Promise<T>
124
- deleteJSON<T>(apiPath: string): Promise<T>
125
- putBinary(uploadUrl: string, signedHeaders: Record<string, string>, data: Buffer): Promise<void>
126
- }
127
-
128
- // 平台统一响应:{ code: "200", message: "...", data: T }
129
- // code 兼容 string | number 格式
130
- ```
131
-
132
- ### 4. protocol.ts
133
-
134
- ```typescript
135
- interface A2AEnvelope {
136
- protocol: "a2hmarket-a2a";
137
- schema_version: "1.0.0";
138
- message_type: string;
139
- message_id: string;
140
- trace_id: string;
141
- sender_id: string;
142
- target_id: string;
143
- timestamp: string; // Beijing time ISO8601
144
- nonce: string;
145
- payload: Record<string, unknown>;
146
- payload_hash: string; // SHA-256 of canonicalized payload
147
- signature: string; // HMAC-SHA256 of canonicalized envelope (minus signature)
148
- }
149
-
150
- function buildEnvelope(senderId: string, targetId: string, messageType: string, payload: Record<string, unknown>): A2AEnvelope
151
- function signEnvelope(agentKey: string, envelope: A2AEnvelope): A2AEnvelope
152
- function canonicalize(value: unknown): string // 递归 key 排序的 JSON 字符串化
153
- ```
154
-
155
- ### 5. mqtt-token.ts
156
-
157
- ```typescript
158
- // Token 端点:POST {apiUrl}/mqtt-token/api/v1/token
159
- // 请求体:{ client_id: string }
160
- // 响应:{ success: true, data: { client_id, username, password, expire_time } }
161
- // 签名方式同 HTTP API
162
-
163
- interface MqttCredential {
164
- clientId: string;
165
- username: string;
166
- password: string;
167
- expireTime: number; // Unix ms
168
- }
169
-
170
- class MqttTokenClient {
171
- constructor(apiUrl: string, agentId: string, agentKey: string)
172
- getToken(clientId: string, forceRefresh?: boolean): Promise<MqttCredential>
173
- }
174
- ```
175
-
176
- ### 6. mqtt-transport.ts
177
-
178
- ```typescript
179
- // Broker URL: mqtts://mqtt.a2hmarket.ai:8883 → ssl://mqtt.a2hmarket.ai:8883
180
- // ClientID 格式:
181
- // listener: GID_agent@@@{agentId}_rt_{instanceId}
182
- // send: GID_agent@@@{agentId}_pub_{random8}
183
- // Topic:
184
- // incoming: P2P_TOPIC/p2p/GID_agent@@@{agentId}
185
- // outgoing: P2P_TOPIC/p2p/GID_agent@@@{targetAgentId}
186
- // QoS: 1, KeepAlive: 60s, ConnectTimeout: 15s
187
- // TLS: true (InsecureSkipVerify for compatibility)
188
- // 断线自动重连:指数退避 1s → 2s → 4s → 8s → 16s → 30s
189
-
190
- class MqttTransport {
191
- constructor(brokerUrl: string, tokenClient: MqttTokenClient, agentId: string, clientId?: string)
192
- connect(): Promise<void>
193
- subscribe(): Promise<void>
194
- publish(targetAgentId: string, payload: unknown): Promise<void>
195
- close(): void
196
- onMessage(handler: (topic: string, payload: string) => void): void
197
- }
198
- ```
199
-
200
- ### 7. mqtt-listener.ts
201
-
202
- ```typescript
203
- // Plugin 启动时创建 listener 实例
204
- // 连接 MQTT broker,订阅 incoming topic
205
- // 收到消息 → 解析 A2A envelope → 写入 inbox
206
- // 提供 start() / stop() 生命周期管理
207
-
208
- class MqttListener {
209
- constructor(creds: A2HCredentials, inbox: InboxStore)
210
- start(): Promise<void>
211
- stop(): void
212
- isConnected(): boolean
213
- }
214
- ```
215
-
216
- ### 8. inbox.ts — 本地消息存储
217
-
218
- ```typescript
219
- // 简化实现:用 JSON 文件代替 SQLite
220
- // 存储路径:~/.a2hmarket/plugin-inbox.json
221
- // 结构:{ events: InboxEvent[], consumers: { [id]: lastAckedSeq } }
222
-
223
- interface InboxEvent {
224
- seq: number;
225
- eventId: string;
226
- peerId: string;
227
- messageId: string;
228
- preview: string;
229
- payload: Record<string, unknown>;
230
- state: "unread" | "acked";
231
- createdAt: string;
232
- }
233
-
234
- class InboxStore {
235
- constructor(storePath: string)
236
- append(event: InboxEvent): void
237
- pull(consumerId: string, cursor: number, limit: number): InboxEvent[]
238
- peek(consumerId: string): { unread: number }
239
- ack(consumerId: string, eventId: string): void
240
- getEvent(eventId: string): InboxEvent | null
241
- }
242
- ```
243
-
244
- ## MCP Server 生命周期
245
-
246
- ```
247
- Claude Code / OpenClaw 启动 MCP server(stdio 子进程)
248
-
249
- server.ts 初始化:
250
- 1. 读取 ~/.a2hmarket/credentials.json
251
- 2. 创建 A2HApiClient(REST)
252
- 3. 创建 MqttListener → start()(后台长连接)
253
- - 订阅 P2P_TOPIC/p2p/GID_agent@@@{agentId}
254
- - 收到消息 → inbox.append() + MCP channel notification push
255
- 4. 注册所有 MCP tools(a2h_status, a2h_works_search, ...)
256
- 5. 连接 stdio transport
257
-
258
- AI 会话中(Claude Code):
259
- - MQTT 消息到达 → MCP channel notification → AI 实时收到
260
- → <channel source="a2hmarket" event_id="..." peer_id="..." ...>
261
- - 用户意图触发 tool 调用
262
-
263
- AI 会话中(OpenClaw):
264
- - Heartbeat 调 a2h_inbox_peek → 有新消息则处理
265
- - 或通过 MCP channel notification 实时推送
266
-
267
- 进程退出 → listener.stop() → MQTT 断开
268
- ```
269
-
270
- ## MQTT 消息流
271
-
272
- ### 发送(短连接)
273
-
274
- ```
275
- a2h_send tool 被调用
276
- → 构建 A2A envelope(protocol.ts)
277
- → 签名(signEnvelope)
278
- → 获取 MQTT token(_pub_ clientId)
279
- → 连接 broker(cleanSession=true)
280
- → publish to P2P_TOPIC/p2p/GID_agent@@@{targetId}
281
- → 断开连接
282
- ```
283
-
284
- ### 接收(长连接)
285
-
286
- ```
287
- Plugin 启动 → MqttListener.start()
288
- → 获取 MQTT token(_rt_ clientId)
289
- → 连接 broker(cleanSession=false)
290
- → subscribe P2P_TOPIC/p2p/GID_agent@@@{myAgentId}
291
- → 收到消息 → 解析 envelope → inbox.append()
292
- → 断线 → 自动重连(指数退避)
293
- ```
294
-
295
- ## 依赖
296
-
297
- ```json
298
- {
299
- "dependencies": {
300
- "mqtt": "^5.x",
301
- "@sinclair/typebox": "^0.x"
302
- },
303
- "peerDependencies": {
304
- "openclaw": "*"
305
- }
306
- }
307
- ```
308
-
309
- - **mqtt** (mqtt.js): MQTT 5.0 客户端,支持 TLS、自动重连
310
- - **@sinclair/typebox**: OpenClaw plugin SDK 的 tool schema 定义
311
- - **openclaw**: 运行时 peer dependency
312
-
313
- ## 安全评估预期
314
-
315
- | 扫描规则 | 预期结果 | 原因 |
316
- |----------|---------|------|
317
- | dangerous-exec | 无 | 不调用 child_process |
318
- | dynamic-code-execution | 无 | 不使用 eval/Function |
319
- | potential-exfiltration | 可能 warn | fetch + 文件读取(credentials.json) |
320
- | env-harvesting | 无 | 不读 process.env + 网络发送 |
321
- | suspicious-network | 无 | 不使用 WebSocket(用 mqtt.js 的 TLS) |
322
- | obfuscated-code | 无 | 无混淆 |
323
-
324
- **potential-exfiltration** 可能触发(读 credentials + fetch),但作为 plugin 这是预期行为,
325
- 参考 linkmind-context 也有类似模式,评估为 Benign。
326
-
327
- ## 实现优先级
328
-
329
- ### Phase 1(MVP — 核心通路)
330
- 1. `credentials.ts` + `signer.ts` + `api-client.ts` — HTTP 基础设施
331
- 2. `protocol.ts` + `mqtt-token.ts` + `mqtt-transport.ts` — MQTT 基础设施
332
- 3. `inbox.ts` + `mqtt-listener.ts` — 消息接收 + 本地存储
333
- 4. `server.ts` — MCP server 入口(stdio + channel notification push)
334
- 5. `tools/status.ts` + `tools/profile.ts` — 验证 API 通路
335
- 6. `tools/works.ts` + `tools/order.ts` — 核心交易功能
336
- 7. `tools/send.ts` — 消息发送
337
- 8. `tools/inbox-tools.ts` — inbox pull / peek / ack / history
338
- 9. `.mcp.json` + `package.json` — Claude Code / OpenClaw 配置
339
- 10. Skill 英文翻译(SKILL.md + 全部 playbooks + references)
340
-
341
- ### Phase 2(完善)
342
- - `oss.ts` + 文件上传 tools
343
- - works update / delete tools
344
- - profile upload-qrcode tool
345
- - OpenClaw native plugin wrapper(`openclaw.plugin.json` + `index.ts` with definePluginEntry)
@@ -1,249 +0,0 @@
1
- # a2hmarket-plugin 需求文档
2
-
3
- > PM 分析日期:2026-03-24
4
-
5
- ## 背景
6
-
7
- 当前 a2hmarket 以 skill + 外部 Go CLI(a2hmarket-cli)+ MCP channel plugin 的方式运行。
8
- 提交到 ClawHub 后被标记为**可疑**,原因:
9
-
10
- 1. **代码扫描**:MCP server.ts 中 `readFileSync` + HTTP 触发 `potential-exfiltration` 规则
11
- 2. **行为审查**:外部二进制依赖、curl|bash 安装、后台 MQTT daemon、凭据文件访问、非标准端口监听
12
- 3. **体量过重**:~2370 行 markdown references
13
-
14
- ## 核心意图
15
-
16
- 将 a2hmarket 从 **skill + 外部 CLI** 重构为 **OpenClaw Native Plugin**(全 TypeScript),
17
- 使其通过 ClawHub plugin 安全审查(目标评级:Benign),同时保留核心交易功能。
18
-
19
- ## 功能点
20
-
21
- ### F1:TS API Client — 替代 Go CLI 的 HTTP 层
22
-
23
- **描述**:用 TypeScript 实现 A2H Market REST API 客户端,包含 HMAC-SHA256 签名。
24
-
25
- **验收标准**:
26
- - 读取 `~/.a2hmarket/credentials.json` 获取凭据
27
- - 实现 `GET/POST/DELETE` 带签名请求
28
- - 实现 `PutBinary` 用于 OSS 直传
29
- - 签名算法与 Go 版本输出一致
30
-
31
- ### F2:Plugin Tools — 替代 CLI 命令
32
-
33
- **描述**:将 CLI 命令注册为 OpenClaw plugin tools(`api.registerTool()`)。
34
-
35
- **核心 Tools(P0)**:
36
-
37
- | Tool 名称 | 对应 CLI 命令 | API 类型 |
38
- |-----------|-------------|---------|
39
- | `a2h_status` | `status` | REST GET |
40
- | `a2h_profile_get` | `profile get` | REST GET |
41
- | `a2h_works_search` | `works search` | REST POST |
42
- | `a2h_works_list` | `works list` | REST GET |
43
- | `a2h_works_publish` | `works publish` | REST POST |
44
- | `a2h_order_create` | `order create` | REST POST |
45
- | `a2h_order_action` | `order confirm/reject/cancel/...` | REST POST |
46
- | `a2h_order_get` | `order get` | REST GET |
47
- | `a2h_order_list` | `order list-sales/list-purchase` | REST GET |
48
- | `a2h_send` | `send` | **MQTT publish** |
49
- | `a2h_inbox_pull` | `inbox pull` | 本地 inbox 读取 |
50
- | `a2h_inbox_peek` | `inbox peek` | 本地 inbox 读取 |
51
- | `a2h_inbox_ack` | `inbox ack` | 本地 inbox 写入 |
52
- | `a2h_inbox_history` | `inbox history` | REST GET |
53
-
54
- **次要 Tools(P1)**:
55
-
56
- | Tool 名称 | 对应 CLI 命令 | API 类型 |
57
- |-----------|-------------|---------|
58
- | `a2h_works_update` | `works update` | REST POST |
59
- | `a2h_works_delete` | `works delete` | REST DELETE |
60
- | `a2h_profile_upload_qrcode` | `profile upload-qrcode` | REST + OSS |
61
- | `a2h_file_upload` | `file upload` | REST + OSS |
62
-
63
- ### F3:消息发送 — MQTT 短连接
64
-
65
- **描述**:用 mqtt.js 实现消息发送(短连接模式,与 Go CLI 的 send 命令一致)。
66
-
67
- **验收标准**:
68
- - 连接 MQTT broker,发布消息到目标 agent
69
- - 支持 text、attachment(OSS 上传)、url、payment_qr
70
- - A2A 信封构造 + HMAC 签名与 Go 版本一致
71
- - 使用 `_pub_` clientId 前缀,不踢掉正在运行的 listener
72
- - 发送后立即断开(不保持长连接)
73
-
74
- ### F4:消息接收 — MQTT 长连接 + 本地 Inbox
75
-
76
- **描述**:用 mqtt.js 实现 MQTT listener(与 Go CLI listener 一致),接收消息写入本地 inbox。
77
- OpenClaw 通过 Heartbeat 定期调用 inbox tool 检查新消息。
78
-
79
- **验收标准**:
80
- - Plugin 启动时自动连接 MQTT broker,订阅 `agents/{agentId}/inbox`
81
- - 收到消息后写入本地 inbox 存储(JSON 文件或 SQLite)
82
- - 提供 `a2h_inbox_pull` tool:拉取未消费消息
83
- - 提供 `a2h_inbox_peek` tool:查看未读数量
84
- - 提供 `a2h_inbox_ack` tool:标记消息已处理
85
- - MQTT 断线自动重连
86
- - 配合 OpenClaw Heartbeat 机制:agent 定期调 `a2h_inbox_peek`,有新消息则处理
87
-
88
- ### F5:Skill 全量英文翻译 — 保留完整结构与业务流程
89
-
90
- **描述**:将现有 skill 的所有内容翻译为英文,但**保留原有的目录结构和 playbook 架构**。
91
- 不做精简——playbooks 是核心业务逻辑,丢失等于功能退化。
92
-
93
- **原始结构(必须保留)**:
94
- ```
95
- skills/a2hmarket/
96
- ├── SKILL.md # 主入口 + 场景路由
97
- └── references/
98
- ├── commands.md # CLI→Tool 命令参考(改写为 tool 调用方式)
99
- ├── inbox.md # 消息处理操作手册
100
- └── playbooks/
101
- ├── onboarding.md # 安装后引导(首次见面)
102
- ├── stall.md # 🏪 摆摊销售全流程(路径A摆摊上架 + 路径B接取悬赏 + 订单后流程)
103
- ├── shopping.md # 🛍️ 逛街扫货全流程(搜索→代购 / 发布需求帖)
104
- ├── browsing.md # 👀 逛逛探索(找赚钱机会 / 发现好物 / 市场概览)
105
- ├── negotiation.md # 🤝 代理授权 & 协商策略
106
- └── reporting.md # 📊 汇报机制 & 周期管理
107
- ```
108
-
109
- **翻译规则**:
110
- - 所有中文内容翻译为英文
111
- - 保留 mermaid 流程图(翻译图中的中文标签)
112
- - CLI 命令引用改为 plugin tool 引用(如 `works search` → `a2h_works_search` tool)
113
- - 保留文件间的交叉引用链接
114
- - 保留表格、决策树、模板等结构
115
- - setup.md 删除(安装由 plugin install 处理)
116
-
117
- **验收标准**:
118
- - 7 个 playbook 文件全部翻译,结构 1:1 对应
119
- - commands.md 改写为 tool 参考(参数从 CLI flag 改为 tool schema)
120
- - SKILL.md 入口保留场景路由表
121
- - 无中文残留(除了市场术语如 A2H Market)
122
-
123
- ### F7:MCP Server — 兼容 Claude Code
124
-
125
- **描述**:将核心功能封装为 MCP stdio server,使 plugin 同时兼容 OpenClaw 和 Claude Code。
126
-
127
- **架构变化**:MCP server 成为统一实现层。
128
-
129
- ```
130
- ┌─────────────────────────────────────────────┐
131
- │ MCP Server (stdio) │
132
- │ ┌─────────────┐ ┌──────────────────────┐ │
133
- │ │ MCP Tools │ │ MQTT Listener │ │
134
- │ │ (all a2h_*) │ │ (background, long │ │
135
- │ │ │ │ connection, push │ │
136
- │ │ │ │ via MCP channel │ │
137
- │ │ │ │ notification) │ │
138
- │ └─────────────┘ └──────────────────────┘ │
139
- └─────────────┬───────────────┬───────────────┘
140
- │ │
141
- OpenClaw (.mcp.json) Claude Code (.mcp.json)
142
- as bundle/plugin as local plugin
143
- ```
144
-
145
- **工作方式**:
146
- - MCP server 启动时连接 MQTT broker(长连接)
147
- - 收到 A2A 消息 → 通过 MCP `notifications/claude/channel` 推送到 AI 会话
148
- - AI 通过 MCP tools 调用所有功能(works/order/send/inbox 等)
149
- - Claude Code:直接使用 MCP channel notification 实时推送
150
- - OpenClaw:通过 `.mcp.json` bundle 支持,MCP server 作为子进程启动
151
-
152
- **验收标准**:
153
- - MCP server 以 stdio 模式运行
154
- - 提供所有 a2h_* tools
155
- - MQTT listener 在 server 启动时自动连接
156
- - 新消息通过 MCP channel notification 推送(`<channel source="a2hmarket" ...>`)
157
- - `.mcp.json` 配置文件可被 Claude Code 和 OpenClaw 识别
158
- - 无独立端口监听(纯 stdio,MQTT 由 mqtt.js 管理)
159
-
160
- ### F6:Plugin 打包 — ClawHub 发布
161
-
162
- **描述**:按 OpenClaw native plugin 格式打包,发布到 ClawHub。
163
-
164
- **验收标准**:
165
- - 包含 `openclaw.plugin.json` manifest
166
- - 包含 `package.json` with `openclaw.extensions`
167
- - ClawHub 安全扫描无 critical findings
168
- - 安全评估目标:Benign
169
- - `openclaw plugins install` 可安装
170
-
171
- ## 技术约束
172
-
173
- 1. **TypeScript ESM**,Node 22+
174
- 2. **OpenClaw Plugin SDK**:`definePluginEntry` + `api.registerTool()`
175
- 3. **MQTT 库**:mqtt.js(仅发送用,短连接)
176
- 4. **凭据**:读取 `~/.a2hmarket/credentials.json`
177
- 5. **无外部二进制依赖**
178
- 6. **无后台 daemon**
179
- 7. **无非标准端口监听**
180
-
181
- ## 不做的事
182
-
183
- - 不做 MCP channel server(消息通过 plugin 内置 MQTT listener 接收)
184
- - 不做 LaunchAgent/systemd 自启动(listener 随 plugin 生命周期管理)
185
- - 不做 CLI 二进制分发(全 TS 实现)
186
- - 不做认证流程(假设用户已有 credentials.json)
187
- - 不做独立端口监听(无 HTTP server)
188
-
189
- ## API 端点汇总(从 Go 源码提取)
190
-
191
- ### 认证
192
-
193
- | 方法 | 路径 | 说明 |
194
- |------|------|------|
195
- | POST | `/v1/auth/init-login` | 生成登录链接(base: web.a2hmarket.ai) |
196
- | GET | `/findu-user/api/v1/public/user/agent/auth?code={code}` | 检查认证状态 |
197
-
198
- ### 商品
199
-
200
- | 方法 | 路径 | 说明 |
201
- |------|------|------|
202
- | POST | `/findu-match/api/v1/inner/match/works_search` | 搜索商品 |
203
- | GET | `/findu-user/api/v1/user/works/public?type=&pageNum=&pageSize=` | 列出自己的商品 |
204
- | POST | `/findu-user/api/v1/user/works/change-requests` | 发布/更新商品 |
205
- | DELETE | `/findu-user/api/v1/user/works/{worksId}` | 删除商品 |
206
-
207
- ### 订单
208
-
209
- | 方法 | 路径 | 说明 |
210
- |------|------|------|
211
- | POST | `/findu-trade/api/v1/orders/create` | 创建订单 |
212
- | POST | `/findu-trade/api/v1/orders/{orderId}/{action}` | 订单操作(confirm/reject/cancel/confirm-received/confirm-service-completed) |
213
- | GET | `/findu-trade/api/v1/orders/{orderId}/detail` | 订单详情 |
214
- | GET | `/findu-trade/api/v1/orders/sales-orders?page=&pageSize=&status=` | 销售订单列表 |
215
- | GET | `/findu-trade/api/v1/orders/purchase-orders?page=&pageSize=&status=` | 采购订单列表 |
216
-
217
- ### 个人资料
218
-
219
- | 方法 | 路径 | 说明 |
220
- |------|------|------|
221
- | GET | `/findu-user/api/v1/user/profile/public` | 获取资料 |
222
- | POST | `/findu-user/api/v1/user/profile/change-requests` | 更新资料字段 |
223
-
224
- ### 消息
225
-
226
- | 方法 | 路径 | 说明 |
227
- |------|------|------|
228
- | GET | `/agent-message/api/v1/agents/sessions/messages?sessionId=&page=&limit=` | 消息历史(REST) |
229
- | — | MQTT publish to `agents/{targetId}/inbox` | 发送消息(MQTT) |
230
-
231
- ### OSS
232
-
233
- | 方法 | 路径 | 说明 |
234
- |------|------|------|
235
- | POST | `/findu-oss/api/v1/oss_signurl/upload/sign`(base: api.a2hmarket.ai/findu-oss) | 获取预签名 URL |
236
- | PUT | `{upload_url}` | 直传文件 |
237
-
238
- ### 签名算法
239
-
240
- ```
241
- payload = "{METHOD}&{path}&{agentId}&{timestamp}"
242
- signature = HMAC-SHA256(agentKey, payload).hex()
243
- Headers: X-Agent-Id, X-Timestamp, X-Agent-Signature
244
- ```
245
-
246
- ## 优先级
247
-
248
- - **P0**:F1(API Client) + F2(核心 Tools) + F3(MQTT Send) + F4(MQTT Listener + Inbox) + F7(MCP Server) + F6(打包) — MVP
249
- - **P1**:F5(Skill 英文翻译全量) + F2(次要 Tools) — 完整体验