vibe-coding-master 0.4.41 → 0.5.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.
- package/dist/backend/api/task-routes.js +7 -0
- package/dist/backend/api/translation-routes.js +11 -0
- package/dist/backend/errors.js +2 -0
- package/dist/backend/gateway/gateway-service.js +31 -61
- package/dist/backend/server.js +11 -1
- package/dist/backend/services/round-service.js +34 -0
- package/dist/backend/services/task-launch-service.js +91 -0
- package/dist/backend/services/translation-service.js +87 -0
- package/dist/backend/services/translation-worker-service.js +228 -72
- package/dist-frontend/assets/index-BaDS9Ohj.js +96 -0
- package/dist-frontend/index.html +1 -1
- package/docs/ARCHITECTURE.md +123 -0
- package/docs/TESTING.md +121 -73
- package/docs/known-issues.md +155 -0
- package/package.json +1 -1
- package/dist-frontend/assets/index-CsxS5H0d.js +0 -96
- package/docs/claude-code-translation-plan.md +0 -1268
- package/docs/full-harness-baseline.md +0 -160
- package/docs/gate-review-gates.md +0 -132
- package/docs/gateway-design.md +0 -813
- package/docs/v0.2-implementation-plan.md +0 -408
- package/docs/v0.4-harness-optimization-plan.md +0 -664
package/docs/gateway-design.md
DELETED
|
@@ -1,813 +0,0 @@
|
|
|
1
|
-
# VCM Gateway Design
|
|
2
|
-
|
|
3
|
-
Last updated: 2026-06-24
|
|
4
|
-
|
|
5
|
-
This document defines VCM gateway product behavior and implementation plan. The
|
|
6
|
-
first channel was based on the local Tencent iLink smoke test at:
|
|
7
|
-
|
|
8
|
-
```text
|
|
9
|
-
/Users/sheldon/Documents/New project 3/weixin-ilink-gateway-test
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
Supported gateway channels:
|
|
13
|
-
|
|
14
|
-
- Tencent iLink Bot API / Weixin DM
|
|
15
|
-
- Lark QR setup plus bot WebSocket event delivery
|
|
16
|
-
|
|
17
|
-
## Product Definition
|
|
18
|
-
|
|
19
|
-
VCM Gateway is a mobile conversation bridge between chat clients and one
|
|
20
|
-
desktop VCM instance. It is not a remote terminal.
|
|
21
|
-
|
|
22
|
-
Product rules:
|
|
23
|
-
|
|
24
|
-
- Weixin supports DM only.
|
|
25
|
-
- Lark accepts direct messages and group messages only when the bot is
|
|
26
|
-
mentioned.
|
|
27
|
-
- Weixin binds one mobile chat identity to one desktop VCM instance.
|
|
28
|
-
- Lark does not require pairing. Any chat that can DM the bot or @mention it can
|
|
29
|
-
control Gateway; the most recent active Lark chat becomes the PM reply target.
|
|
30
|
-
- The active chat is not project-specific and not task-specific.
|
|
31
|
-
- The active chat can manage every project and task available to that desktop
|
|
32
|
-
VCM instance.
|
|
33
|
-
- Gateway user messages talk only to the `project-manager` role.
|
|
34
|
-
- Gateway never sends directly to `architect`, `coder`, or `reviewer`.
|
|
35
|
-
- When the desktop UI has a current task selected, Gateway should adopt that
|
|
36
|
-
project/task context automatically instead of requiring `/tasks` and
|
|
37
|
-
`/use-task` first.
|
|
38
|
-
- After channel setup succeeds, VCM keeps a channel connection even when Gateway is
|
|
39
|
-
disabled. Disabled Gateway accepts only `/help`, `/start`, `/status`,
|
|
40
|
-
`/projects`, and `/tasks`.
|
|
41
|
-
- VCM stores the latest PM reply for each task in local Gateway state. When
|
|
42
|
-
`/start` enables Gateway and the current task has a cached PM reply, Gateway
|
|
43
|
-
returns that reply immediately so the phone user sees the current task state.
|
|
44
|
-
- Gateway does not change the desktop `Pause alert sound` preference. The
|
|
45
|
-
desktop pause dialog remains a fixed local UI signal, and Gateway is the
|
|
46
|
-
mobile notification path.
|
|
47
|
-
- Gateway may push PM replies to the active mobile chat whenever it is enabled,
|
|
48
|
-
even when the PM turn was started from the desktop UI rather than from the
|
|
49
|
-
mobile chat.
|
|
50
|
-
- When translation is enabled, Chinese input is translated to English before it
|
|
51
|
-
is sent to PM.
|
|
52
|
-
- The prompt sent to PM does not include the original Chinese text.
|
|
53
|
-
- There is no allowed-user list. Weixin is a bound identity model; Lark is a
|
|
54
|
-
trusted-chat bot model.
|
|
55
|
-
|
|
56
|
-
The short product sentence is:
|
|
57
|
-
|
|
58
|
-
```text
|
|
59
|
-
One active mobile chat controls one desktop VCM; the chat can select project/task context,
|
|
60
|
-
pull the connected base repository, create and initialize a task through the
|
|
61
|
-
saved launch template, send ordinary messages to the current task's PM, receive
|
|
62
|
-
translated PM replies, and close completed tasks while gateway is enabled; when
|
|
63
|
-
gateway is disabled, the active chat can still run `/start` and read-only status
|
|
64
|
-
commands.
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Binding Model
|
|
68
|
-
|
|
69
|
-
The control target is the desktop VCM instance.
|
|
70
|
-
|
|
71
|
-
```text
|
|
72
|
-
Weixin DM or Lark chat
|
|
73
|
-
<-> desktop VCM instance
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
The gateway stores channel credentials and active chat metadata in app-local
|
|
77
|
-
state. Weixin stores the iLink bot account token from QR login. Lark QR setup
|
|
78
|
-
creates/configures the bot app and stores App ID/App Secret locally. VCM does
|
|
79
|
-
not support manual Lark App ID/App Secret configuration.
|
|
80
|
-
|
|
81
|
-
Weixin accepts messages from the bound identity. Lark accepts messages from any
|
|
82
|
-
chat that can reach the bot, and each accepted message updates the active Lark
|
|
83
|
-
chat used for PM reply push.
|
|
84
|
-
|
|
85
|
-
Changing Weixin phones or accounts is a rebind operation. Lark active chat
|
|
86
|
-
changes automatically whenever another reachable Lark chat messages the bot:
|
|
87
|
-
|
|
88
|
-
```text
|
|
89
|
-
desktop settings -> disable gateway or reset binding -> QR login again
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Mobile Context
|
|
93
|
-
|
|
94
|
-
Because Gateway controls a desktop VCM instance, it needs a current mobile
|
|
95
|
-
context:
|
|
96
|
-
|
|
97
|
-
```text
|
|
98
|
-
current project
|
|
99
|
-
current task
|
|
100
|
-
current role = project-manager
|
|
101
|
-
translation enabled/disabled
|
|
102
|
-
saved launch template
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Plain text messages are sent to the PM session of the current task only when
|
|
106
|
-
Gateway is enabled. If no project or task is selected, gateway replies with a
|
|
107
|
-
short setup hint.
|
|
108
|
-
|
|
109
|
-
VCM normally runs one project and one task at a time. When Gateway is enabled,
|
|
110
|
-
or when `/status` is called, VCM should refresh Gateway context from the
|
|
111
|
-
desktop-selected project/task when available.
|
|
112
|
-
|
|
113
|
-
The desktop UI remains the source of truth. Gateway changes mobile context or
|
|
114
|
-
task lifecycle state only through explicit commands.
|
|
115
|
-
|
|
116
|
-
## Command Surface
|
|
117
|
-
|
|
118
|
-
MVP commands:
|
|
119
|
-
|
|
120
|
-
```text
|
|
121
|
-
/help
|
|
122
|
-
/start
|
|
123
|
-
/retry
|
|
124
|
-
/status
|
|
125
|
-
/projects
|
|
126
|
-
/use-project <index-or-path>
|
|
127
|
-
/pull-current
|
|
128
|
-
/tasks
|
|
129
|
-
/use-task <index-or-task-slug>
|
|
130
|
-
/create-task <task-slug> [title]
|
|
131
|
-
/close-task
|
|
132
|
-
/close-task confirm <task-slug>
|
|
133
|
-
/translate on
|
|
134
|
-
/translate off
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Plain text that does not start with `/` is treated as a PM message for the
|
|
138
|
-
current task only when Gateway is enabled.
|
|
139
|
-
|
|
140
|
-
When Gateway is disabled but the channel is still connected, only this subset is accepted:
|
|
141
|
-
|
|
142
|
-
```text
|
|
143
|
-
/help
|
|
144
|
-
/start
|
|
145
|
-
/status
|
|
146
|
-
/projects
|
|
147
|
-
/tasks
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
`/start` enables Gateway from the active mobile chat. If there is a current task
|
|
151
|
-
and VCM has cached a latest PM reply for that task, `/start` includes that reply
|
|
152
|
-
in the command response. All plain text, task-changing commands,
|
|
153
|
-
project-changing commands, translation toggles, and repository pull commands
|
|
154
|
-
require Gateway to be enabled.
|
|
155
|
-
|
|
156
|
-
When Gateway output translation is enabled, PM replies are translated before
|
|
157
|
-
being sent to Weixin. If translation fails or times out, Gateway sends a
|
|
158
|
-
translation failure notice instead of the English source. The latest failed
|
|
159
|
-
output translation is kept in memory only, and `/retry` retries that source
|
|
160
|
-
content. Successful retry clears the memory item; failed retry keeps it for a
|
|
161
|
-
later `/retry`.
|
|
162
|
-
|
|
163
|
-
Task lifecycle commands:
|
|
164
|
-
|
|
165
|
-
- `/pull-current` calls `POST /api/projects/current/pull` for the selected
|
|
166
|
-
desktop VCM project. It runs the same connected-repository fast-forward-only
|
|
167
|
-
pull as the desktop button. It must fail if the base repo has uncommitted
|
|
168
|
-
changes or if the branch has no upstream.
|
|
169
|
-
- `/create-task <task-slug> [title]` creates a task worktree,
|
|
170
|
-
selects it as the mobile current task, applies the saved launch template, and
|
|
171
|
-
starts the four role sessions (`project-manager`, `architect`, `coder`,
|
|
172
|
-
`reviewer`) using the saved desktop launch-template values. The saved template
|
|
173
|
-
controls permission mode, model, effort, and auto orchestration.
|
|
174
|
-
If no template has been saved, VCM uses the default launch template.
|
|
175
|
-
- `/close-task` starts a destructive confirmation flow for the current task.
|
|
176
|
-
Gateway replies with the exact confirmation command.
|
|
177
|
-
- `/close-task confirm <task-slug>` calls VCM Close Task cleanup for that task:
|
|
178
|
-
stop VCM-managed role sessions, remove the task worktree and task branch when
|
|
179
|
-
the task owns them, and remove VCM task/runtime metadata.
|
|
180
|
-
|
|
181
|
-
Commands intentionally not in MVP:
|
|
182
|
-
|
|
183
|
-
```text
|
|
184
|
-
/approve
|
|
185
|
-
/reject
|
|
186
|
-
/pause
|
|
187
|
-
/resume
|
|
188
|
-
/stop-session
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
The first version should not expose arbitrary terminal controls, role-specific
|
|
192
|
-
start/stop controls, approve/reject gates, or shell execution. The state-changing
|
|
193
|
-
commands are limited to the VCM task lifecycle primitives needed to run a task
|
|
194
|
-
end to end from mobile.
|
|
195
|
-
|
|
196
|
-
## Inbound Message Flow
|
|
197
|
-
|
|
198
|
-
```text
|
|
199
|
-
Tencent iLink getupdates
|
|
200
|
-
-> weixin-ilink channel
|
|
201
|
-
-> verify bound DM identity for Weixin, or update active chat for Lark
|
|
202
|
-
-> dedupe message id
|
|
203
|
-
-> parse text / command
|
|
204
|
-
-> if command: execute gateway command and reply
|
|
205
|
-
-> if plain text:
|
|
206
|
-
-> require current project + current task
|
|
207
|
-
-> require current task PM session running and hook-idle
|
|
208
|
-
-> translate Chinese to English when enabled
|
|
209
|
-
-> submit English prompt to PM
|
|
210
|
-
-> reply with accepted / busy / error status
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
PM prompt shape when translation is enabled:
|
|
214
|
-
|
|
215
|
-
```text
|
|
216
|
-
[VCM Gateway]
|
|
217
|
-
<translated English instruction>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
The original Chinese is not included in the PM prompt.
|
|
221
|
-
|
|
222
|
-
If translation is disabled, the plain user text is submitted as-is with the same
|
|
223
|
-
`[VCM Gateway]` marker.
|
|
224
|
-
|
|
225
|
-
Gateway should use the same bracketed-paste terminal submission path as the VCM
|
|
226
|
-
desktop input path. A terminal write only proves the text was written to the PTY;
|
|
227
|
-
Claude Code `UserPromptSubmit` remains the acceptance signal.
|
|
228
|
-
|
|
229
|
-
## Task Lifecycle Command Flows
|
|
230
|
-
|
|
231
|
-
### Pull Current Base Repository
|
|
232
|
-
|
|
233
|
-
```text
|
|
234
|
-
/pull-current
|
|
235
|
-
-> require current project
|
|
236
|
-
-> call POST /api/projects/current/pull
|
|
237
|
-
-> backend runs git pull --ff-only on connected base repo
|
|
238
|
-
-> refresh current project status
|
|
239
|
-
-> reply with branch, upstream, ahead/behind, and short commit
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
Rules:
|
|
243
|
-
|
|
244
|
-
- Pull only the connected base repository, never a task worktree.
|
|
245
|
-
- Use the same backend guard as desktop Connected Repository Pull.
|
|
246
|
-
- Do not stash, merge, or continue after divergence.
|
|
247
|
-
- If pull fails, reply with the VCM error message and hint.
|
|
248
|
-
|
|
249
|
-
### Create And Initialize Task
|
|
250
|
-
|
|
251
|
-
```text
|
|
252
|
-
/create-task <task-slug> [title]
|
|
253
|
-
-> require current project
|
|
254
|
-
-> create a task branch and worktree through existing task service/API
|
|
255
|
-
-> select it as gateway current task
|
|
256
|
-
-> load saved launch template from app preferences
|
|
257
|
-
-> set orchestration from template
|
|
258
|
-
-> start four role sessions with template permission/model/effort
|
|
259
|
-
-> switch mobile current role to project-manager
|
|
260
|
-
-> reply with task slug, branch, worktree, template summary, and session status
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
Rules:
|
|
264
|
-
|
|
265
|
-
- Use the same task creation validation as desktop VCM.
|
|
266
|
-
- Use the same one-click-start semantics as desktop VCM: only start from a newly
|
|
267
|
-
created task with no existing role sessions.
|
|
268
|
-
- If one role session fails to start, reply with the role that failed and leave
|
|
269
|
-
the partially created task visible in desktop VCM for manual recovery.
|
|
270
|
-
- Do not send the task request as a PM prompt. Task creation is a VCM control
|
|
271
|
-
command, not natural-language work for Claude.
|
|
272
|
-
|
|
273
|
-
### Close Task
|
|
274
|
-
|
|
275
|
-
```text
|
|
276
|
-
/close-task
|
|
277
|
-
-> require current task
|
|
278
|
-
-> reply with destructive confirmation text
|
|
279
|
-
|
|
280
|
-
/close-task confirm <task-slug>
|
|
281
|
-
-> require current task slug matches confirmation slug
|
|
282
|
-
-> call VCM Close Task cleanup
|
|
283
|
-
-> clear mobile current task if cleanup succeeds
|
|
284
|
-
-> reply with removed worktree, deleted branch, and cleaned state paths
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Rules:
|
|
288
|
-
|
|
289
|
-
- Close Task is destructive, so mobile requires explicit confirmation with the
|
|
290
|
-
task slug.
|
|
291
|
-
- Use the same cleanup path as desktop Close Task.
|
|
292
|
-
- Do not preflight or preserve uncommitted work beyond the existing desktop
|
|
293
|
-
Close Task behavior.
|
|
294
|
-
- After cleanup, gateway should ask the user to run `/tasks` or
|
|
295
|
-
`/create-task <task-slug>` for the next task.
|
|
296
|
-
|
|
297
|
-
## PM Reply Push Flow
|
|
298
|
-
|
|
299
|
-
Gateway push is not limited to gateway-originated turns. If gateway is enabled,
|
|
300
|
-
VCM should push PM replies to Weixin after PM completes a turn.
|
|
301
|
-
|
|
302
|
-
```text
|
|
303
|
-
PM Claude Code Stop hook
|
|
304
|
-
-> load PM session transcript
|
|
305
|
-
-> extract new assistant text since last pushed transcript cursor
|
|
306
|
-
-> ignore tool logs, raw terminal output, and non-PM roles
|
|
307
|
-
-> translate English reply to Chinese when enabled
|
|
308
|
-
-> send Weixin DM through iLink sendmessage
|
|
309
|
-
-> persist last pushed transcript cursor
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
Rules:
|
|
313
|
-
|
|
314
|
-
- Push only PM assistant replies.
|
|
315
|
-
- Do not push token-by-token terminal output.
|
|
316
|
-
- Do not push raw tool logs.
|
|
317
|
-
- Do not push architect/coder/reviewer replies directly.
|
|
318
|
-
- Deduplicate by PM session id and transcript event id or timestamp.
|
|
319
|
-
- If translation fails, send the PM original text with a short translation
|
|
320
|
-
failure note.
|
|
321
|
-
|
|
322
|
-
This keeps the mobile side readable and avoids exposing the embedded terminal as
|
|
323
|
-
a chat stream.
|
|
324
|
-
|
|
325
|
-
## Busy And Error Behavior
|
|
326
|
-
|
|
327
|
-
The MVP should be conservative.
|
|
328
|
-
|
|
329
|
-
If the PM session is busy, do not queue arbitrary mobile prompts. Reply:
|
|
330
|
-
|
|
331
|
-
```text
|
|
332
|
-
PM is still working on the current turn. Please wait and send again later.
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
If PM is not running:
|
|
336
|
-
|
|
337
|
-
```text
|
|
338
|
-
The current task's PM session is not running. Start it from desktop VCM first.
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
If no task is selected:
|
|
342
|
-
|
|
343
|
-
```text
|
|
344
|
-
No task is selected. Use /tasks and /use-task first.
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
If `/pull-current` cannot run because the base repo is dirty or has no upstream,
|
|
348
|
-
reply with the same VCM reason shown in the desktop Connected Repository section.
|
|
349
|
-
|
|
350
|
-
If `/create-task` fails task validation, reply with the VCM error and hint.
|
|
351
|
-
Common examples are invalid task slug, dirty base repo, existing task branch, or
|
|
352
|
-
missing harness ignore rules for `.ai/vcm/` / `.claude/worktrees/`.
|
|
353
|
-
|
|
354
|
-
If `/create-task` creates the task but one of the four role sessions fails to
|
|
355
|
-
start, do not hide the partial state. Reply with:
|
|
356
|
-
|
|
357
|
-
```text
|
|
358
|
-
Task was created, but <role> failed to start. Open desktop VCM to recover or retry.
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
If `/close-task confirm <task-slug>` does not match the current task, do not
|
|
362
|
-
clean up anything. Reply with the current task slug and the exact confirmation
|
|
363
|
-
command.
|
|
364
|
-
|
|
365
|
-
If gateway translation fails before sending to PM, do not send the original
|
|
366
|
-
Chinese. Reply with a translation failure message and ask the user to retry.
|
|
367
|
-
|
|
368
|
-
## Tencent iLink Feasibility
|
|
369
|
-
|
|
370
|
-
The local smoke test proves the required channel primitives:
|
|
371
|
-
|
|
372
|
-
- QR login with `ilink/bot/get_bot_qrcode`.
|
|
373
|
-
- QR status polling with `ilink/bot/get_qrcode_status`.
|
|
374
|
-
- Long-poll DM receive with `ilink/bot/getupdates`.
|
|
375
|
-
- Text reply with `ilink/bot/sendmessage`.
|
|
376
|
-
- Token and cursor persistence outside a repository.
|
|
377
|
-
- Handling session expiration through iLink error code `-14`.
|
|
378
|
-
|
|
379
|
-
Observed request details from the smoke test:
|
|
380
|
-
|
|
381
|
-
```text
|
|
382
|
-
base URL: https://ilinkai.weixin.qq.com
|
|
383
|
-
default bot_type: 3
|
|
384
|
-
default channel_version: 2.4.3
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
Common headers:
|
|
388
|
-
|
|
389
|
-
```text
|
|
390
|
-
Content-Type: application/json
|
|
391
|
-
AuthorizationType: ilink_bot_token
|
|
392
|
-
Authorization: Bearer <token>
|
|
393
|
-
X-WECHAT-UIN: <random base64 uin>
|
|
394
|
-
iLink-App-Id: bot
|
|
395
|
-
iLink-App-ClientVersion: <encoded client version>
|
|
396
|
-
SKRouteTag: <optional route tag>
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
QR login:
|
|
400
|
-
|
|
401
|
-
```text
|
|
402
|
-
POST ilink/bot/get_bot_qrcode?bot_type=<bot_type>
|
|
403
|
-
body:
|
|
404
|
-
{
|
|
405
|
-
"local_token_list": ["<saved token>"]
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
GET ilink/bot/get_qrcode_status?qrcode=<qrcode>
|
|
409
|
-
GET ilink/bot/get_qrcode_status?qrcode=<qrcode>&verify_code=<code>
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
QR statuses handled by the smoke test:
|
|
413
|
-
|
|
414
|
-
```text
|
|
415
|
-
wait
|
|
416
|
-
scaned
|
|
417
|
-
need_verifycode
|
|
418
|
-
verify_code_blocked
|
|
419
|
-
expired
|
|
420
|
-
scaned_but_redirect
|
|
421
|
-
binded_redirect
|
|
422
|
-
confirmed
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
Long poll receive:
|
|
426
|
-
|
|
427
|
-
```text
|
|
428
|
-
POST ilink/bot/getupdates
|
|
429
|
-
body:
|
|
430
|
-
{
|
|
431
|
-
"get_updates_buf": "<cursor>",
|
|
432
|
-
"base_info": {
|
|
433
|
-
"channel_version": "2.4.3",
|
|
434
|
-
"bot_agent": "vcm-gateway/<version>"
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
The response may include:
|
|
440
|
-
|
|
441
|
-
```text
|
|
442
|
-
ret / errcode
|
|
443
|
-
errmsg
|
|
444
|
-
longpolling_timeout_ms
|
|
445
|
-
get_updates_buf
|
|
446
|
-
msgs[]
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
Send text DM:
|
|
450
|
-
|
|
451
|
-
```text
|
|
452
|
-
POST ilink/bot/sendmessage
|
|
453
|
-
body:
|
|
454
|
-
{
|
|
455
|
-
"msg": {
|
|
456
|
-
"from_user_id": "",
|
|
457
|
-
"to_user_id": "<bound user id>",
|
|
458
|
-
"client_id": "<unique client id>",
|
|
459
|
-
"message_type": 2,
|
|
460
|
-
"message_state": 2,
|
|
461
|
-
"item_list": [
|
|
462
|
-
{
|
|
463
|
-
"type": 1,
|
|
464
|
-
"text_item": {
|
|
465
|
-
"text": "<reply text>"
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
],
|
|
469
|
-
"context_token": "<optional latest context token>"
|
|
470
|
-
},
|
|
471
|
-
"base_info": {
|
|
472
|
-
"channel_version": "2.4.3",
|
|
473
|
-
"bot_agent": "vcm-gateway/<version>"
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
Inbound message handling:
|
|
479
|
-
|
|
480
|
-
- Ignore bot messages where `message_type` is bot.
|
|
481
|
-
- Accept user messages where `message_type` is user or absent.
|
|
482
|
-
- Extract text from `item_list[].text_item.text`.
|
|
483
|
-
- Voice text can be read from `item_list[].voice_item.text` if iLink supplies
|
|
484
|
-
it, but MVP should treat non-text input as unsupported unless text is present.
|
|
485
|
-
- Use `message_id`, then `client_id`, then sender/time fallback for dedupe.
|
|
486
|
-
- Persist `get_updates_buf` after each successful poll response.
|
|
487
|
-
- Persist latest `context_token` per active user/chat and reuse it for replies.
|
|
488
|
-
|
|
489
|
-
## Local State
|
|
490
|
-
|
|
491
|
-
Gateway state must live outside connected repositories.
|
|
492
|
-
|
|
493
|
-
Recommended files:
|
|
494
|
-
|
|
495
|
-
```text
|
|
496
|
-
<vcmDataDir>/gateway/settings.json
|
|
497
|
-
<vcmDataDir>/gateway/audit.jsonl
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
VCM resolves `vcmDataDir` from `VCM_DATA_DIR`; when it is unset or empty, VCM
|
|
501
|
-
uses `~/.vcm`.
|
|
502
|
-
|
|
503
|
-
Settings shape:
|
|
504
|
-
|
|
505
|
-
```json
|
|
506
|
-
{
|
|
507
|
-
"version": 1,
|
|
508
|
-
"enabled": false,
|
|
509
|
-
"channel": "weixin-ilink",
|
|
510
|
-
"translationEnabled": true,
|
|
511
|
-
"currentProjectId": null,
|
|
512
|
-
"currentTaskSlug": null,
|
|
513
|
-
"binding": {
|
|
514
|
-
"accountId": null,
|
|
515
|
-
"baseUrl": "https://ilinkai.weixin.qq.com",
|
|
516
|
-
"boundUserId": null,
|
|
517
|
-
"loginUserId": null,
|
|
518
|
-
"token": null,
|
|
519
|
-
"getUpdatesBuf": "",
|
|
520
|
-
"contextTokens": {}
|
|
521
|
-
},
|
|
522
|
-
"dedupe": {
|
|
523
|
-
"recentInboundMessageIds": []
|
|
524
|
-
},
|
|
525
|
-
"pendingConfirmations": {
|
|
526
|
-
"closeTask": {
|
|
527
|
-
"taskSlug": null,
|
|
528
|
-
"createdAt": null,
|
|
529
|
-
"expiresAt": null
|
|
530
|
-
}
|
|
531
|
-
},
|
|
532
|
-
"pushCursors": {
|
|
533
|
-
"<taskSlug>:project-manager:<claudeSessionId>": {
|
|
534
|
-
"lastTranscriptEventId": null,
|
|
535
|
-
"lastTranscriptTimestamp": null
|
|
536
|
-
}
|
|
537
|
-
},
|
|
538
|
-
"updatedAt": "..."
|
|
539
|
-
}
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
The token is sensitive. The settings file should be written with user-only file
|
|
543
|
-
permissions where the platform supports it.
|
|
544
|
-
|
|
545
|
-
Audit log rules:
|
|
546
|
-
|
|
547
|
-
- Record state transitions, command names, message ids, result codes, and error
|
|
548
|
-
classes.
|
|
549
|
-
- Redact token, Authorization header, QR URL, and full message bodies by default.
|
|
550
|
-
- Store short message previews only when needed for debugging.
|
|
551
|
-
- Never write gateway credentials to connected repositories, terminal logs,
|
|
552
|
-
`.ai/vcm/**`, PR descriptions, or generated harness files.
|
|
553
|
-
|
|
554
|
-
## Backend Architecture
|
|
555
|
-
|
|
556
|
-
Implemented files:
|
|
557
|
-
|
|
558
|
-
```text
|
|
559
|
-
src/shared/types/gateway.ts
|
|
560
|
-
|
|
561
|
-
src/backend/gateway/
|
|
562
|
-
gateway-channel.ts
|
|
563
|
-
gateway-service.ts
|
|
564
|
-
gateway-settings-service.ts
|
|
565
|
-
gateway-command-parser.ts
|
|
566
|
-
gateway-audit-log.ts
|
|
567
|
-
channels/
|
|
568
|
-
lark-channel.ts
|
|
569
|
-
lark-registration.ts
|
|
570
|
-
weixin-ilink-channel.ts
|
|
571
|
-
|
|
572
|
-
src/backend/api/gateway-routes.ts
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
Responsibilities:
|
|
576
|
-
|
|
577
|
-
- `gateway-settings-service`: load/save app-local gateway settings and secrets.
|
|
578
|
-
- `gateway-channel`: define the generic channel adapter contract and registry.
|
|
579
|
-
- `weixin-ilink-channel`: implement the generic adapter with Weixin iLink QR
|
|
580
|
-
login, long polling, send text, and token expiration detection.
|
|
581
|
-
- `lark-channel`: implement the generic adapter with Lark WebSocket event
|
|
582
|
-
delivery, text send, chat id routing, and mention filtering for groups.
|
|
583
|
-
- `lark-registration`: implement QR setup (`init`, `begin`, `poll`) against
|
|
584
|
-
Lark account registration, then save the returned App ID/App Secret locally.
|
|
585
|
-
- `gateway-command-parser`: parse `/help`, `/status`, `/projects`,
|
|
586
|
-
`/use-project`, `/pull-current`, `/tasks`, `/use-task`, `/create-task`,
|
|
587
|
-
`/close-task`, and `/translate`.
|
|
588
|
-
- `gateway-audit-log`: append redacted JSONL audit entries.
|
|
589
|
-
- `gateway-service`: lifecycle, poll loop, command dispatch, PM terminal
|
|
590
|
-
submission, PM Stop reply push, and error backoff. It must depend on the
|
|
591
|
-
channel registry and generic adapter types, not Weixin/iLink-specific types.
|
|
592
|
-
- `gateway-routes`: desktop UI settings, QR login start/status, Lark QR setup,
|
|
593
|
-
enable/disable, rebind, and gateway status.
|
|
594
|
-
|
|
595
|
-
Service dependencies:
|
|
596
|
-
|
|
597
|
-
- `ProjectService`: current project, recent project paths, connected-repo
|
|
598
|
-
status, and fast-forward-only pull.
|
|
599
|
-
- `TaskService`: task list, task creation, selected task validation, and Close
|
|
600
|
-
Task cleanup.
|
|
601
|
-
- `SessionService`: PM session state, Claude session metadata, and role session
|
|
602
|
-
start for launch-template initialization.
|
|
603
|
-
- `AppSettingsService`: saved launch template with permission mode, model,
|
|
604
|
-
effort, auto orchestration, plus the global Gateway translation preference.
|
|
605
|
-
- `MessageService` / orchestration state service: set the newly created task to
|
|
606
|
-
template auto/manual orchestration mode.
|
|
607
|
-
- `TerminalRuntime`: controlled PM terminal submission.
|
|
608
|
-
- `ClaudeTranscriptService`: PM assistant output extraction.
|
|
609
|
-
- `TranslationService` / Translator: inbound Chinese-to-English and
|
|
610
|
-
outbound target-language translation.
|
|
611
|
-
- `ClaudeHookService` or hook event integration: trigger PM reply push after PM
|
|
612
|
-
`Stop`.
|
|
613
|
-
|
|
614
|
-
## Desktop UI
|
|
615
|
-
|
|
616
|
-
Add a Gateway section to the sidebar settings area or a dedicated modal:
|
|
617
|
-
|
|
618
|
-
```text
|
|
619
|
-
Gateway: off / on
|
|
620
|
-
Channel: Weixin iLink / Lark
|
|
621
|
-
Active chat: none / active
|
|
622
|
-
Translation: off / on
|
|
623
|
-
Current project
|
|
624
|
-
Current task
|
|
625
|
-
QR login / Lark QR setup / Rebind
|
|
626
|
-
Last poll status
|
|
627
|
-
Last message status
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
The user should be able to:
|
|
631
|
-
|
|
632
|
-
- enable or disable gateway
|
|
633
|
-
- select the gateway channel
|
|
634
|
-
- start Weixin QR login
|
|
635
|
-
- start Lark QR setup
|
|
636
|
-
- see whether the phone or Lark chat is active
|
|
637
|
-
- reset binding or channel setup
|
|
638
|
-
- inspect the current gateway project/task context
|
|
639
|
-
- toggle gateway translation
|
|
640
|
-
- inspect recent gateway errors
|
|
641
|
-
|
|
642
|
-
## Implementation Plan
|
|
643
|
-
|
|
644
|
-
### Phase 1: Types, Settings, And UI Skeleton
|
|
645
|
-
|
|
646
|
-
- Add `src/shared/types/gateway.ts`.
|
|
647
|
-
- Add app-local gateway settings service under `src/backend/gateway`.
|
|
648
|
-
- Add `src/backend/api/gateway-routes.ts`.
|
|
649
|
-
- Add desktop UI controls for enable/disable, translation, binding status, and
|
|
650
|
-
current project/task.
|
|
651
|
-
- Store settings under `<vcmDataDir>/gateway/settings.json`.
|
|
652
|
-
|
|
653
|
-
Validation:
|
|
654
|
-
|
|
655
|
-
- Unit tests for settings normalization and secret redaction.
|
|
656
|
-
- API route tests for enable/disable and settings update.
|
|
657
|
-
|
|
658
|
-
### Phase 2: iLink Channel Adapter
|
|
659
|
-
|
|
660
|
-
- Port the proven smoke-test behavior into `weixin-ilink-channel.ts`.
|
|
661
|
-
- Support QR login and status polling.
|
|
662
|
-
- Support token reuse from saved settings.
|
|
663
|
-
- Support `getupdates` long polling.
|
|
664
|
-
- Support `sendmessage` text DM.
|
|
665
|
-
- Persist `get_updates_buf` and context tokens.
|
|
666
|
-
- Handle `ret` / `errcode` `-14` as expired login.
|
|
667
|
-
|
|
668
|
-
Validation:
|
|
669
|
-
|
|
670
|
-
- Unit tests with mocked fetch for QR statuses, getupdates, sendmessage,
|
|
671
|
-
expiration, redirect host, and retry backoff.
|
|
672
|
-
- Manual smoke test with a real Weixin DM before wiring PM submission.
|
|
673
|
-
|
|
674
|
-
### Phase 3: Inbound Context Commands
|
|
675
|
-
|
|
676
|
-
- Implement `/help`, `/start`, `/retry`, `/status`, `/projects`,
|
|
677
|
-
`/use-project`, `/tasks`, `/use-task`, `/translate on`, and `/translate off`.
|
|
678
|
-
- Implement Weixin bound identity check and Lark latest-active-chat updates.
|
|
679
|
-
- Implement persistent inbound message dedupe.
|
|
680
|
-
- Reply with short command results through iLink.
|
|
681
|
-
|
|
682
|
-
Validation:
|
|
683
|
-
|
|
684
|
-
- Parser tests for known commands and invalid commands.
|
|
685
|
-
- Gateway service tests for ignored unbound Weixin users, Lark active chat
|
|
686
|
-
updates, and deduped messages.
|
|
687
|
-
|
|
688
|
-
### Phase 4: Task Lifecycle Commands
|
|
689
|
-
|
|
690
|
-
- Implement `/pull-current` by calling the connected repository pull path:
|
|
691
|
-
`POST /api/projects/current/pull` or the equivalent project service method.
|
|
692
|
-
- Implement `/create-task <task-slug> [title]` by creating a task worktree
|
|
693
|
-
task, selecting it as mobile current task, applying the saved launch template,
|
|
694
|
-
setting orchestration mode, applying the global Gateway translation state, and
|
|
695
|
-
starting the four core role sessions.
|
|
696
|
-
- Implement `/close-task` and `/close-task confirm <task-slug>` as a two-step
|
|
697
|
-
destructive confirmation around the same Close Task cleanup path as desktop
|
|
698
|
-
VCM.
|
|
699
|
-
- Persist close-task pending confirmation outside the repository.
|
|
700
|
-
|
|
701
|
-
Validation:
|
|
702
|
-
|
|
703
|
-
- Parser tests for `/pull-current`, `/create-task`, `/close-task`, and
|
|
704
|
-
confirmation mismatch.
|
|
705
|
-
- Service tests for pull success and pull-blocked reasons.
|
|
706
|
-
- Service tests that task creation creates a task worktree and uses launch
|
|
707
|
-
template role settings.
|
|
708
|
-
- Service tests for partial role-session start failure reporting.
|
|
709
|
-
- Service tests that Close Task calls the existing cleanup path only after exact
|
|
710
|
-
slug confirmation.
|
|
711
|
-
|
|
712
|
-
### Phase 5: PM Message Submission
|
|
713
|
-
|
|
714
|
-
- Treat plain DM text as PM input for the current task.
|
|
715
|
-
- Require current project, current task, running PM session, and idle PM
|
|
716
|
-
activity.
|
|
717
|
-
- If gateway translation is enabled, translate Chinese to English before
|
|
718
|
-
submission.
|
|
719
|
-
- Submit only the translated English text to PM with `[VCM Gateway]`.
|
|
720
|
-
- Do not include the original Chinese text in the PM prompt.
|
|
721
|
-
- Use bracketed paste plus Enter through `submitTerminalInput`.
|
|
722
|
-
|
|
723
|
-
Validation:
|
|
724
|
-
|
|
725
|
-
- Tests for no project/task/session/busy/translation failure paths.
|
|
726
|
-
- Tests that translated prompts do not include original Chinese.
|
|
727
|
-
- Tests that successful submit records a gateway turn audit entry.
|
|
728
|
-
|
|
729
|
-
### Phase 6: PM Reply Push
|
|
730
|
-
|
|
731
|
-
- Hook PM `Stop` handling into `gateway-service`.
|
|
732
|
-
- Load PM transcript and extract new assistant text since the last push cursor.
|
|
733
|
-
- Push PM replies whenever gateway is enabled, regardless of whether the user
|
|
734
|
-
turn started from gateway or desktop.
|
|
735
|
-
- Translate PM reply to Chinese when gateway translation is enabled.
|
|
736
|
-
- Persist push cursors so restart does not duplicate old PM replies.
|
|
737
|
-
|
|
738
|
-
Validation:
|
|
739
|
-
|
|
740
|
-
- Transcript extraction tests with multiple assistant events.
|
|
741
|
-
- Deduplication tests across repeated Stop hooks and app restart.
|
|
742
|
-
- Translation failure fallback test.
|
|
743
|
-
|
|
744
|
-
### Phase 7: Audit, Recovery, And Packaging
|
|
745
|
-
|
|
746
|
-
- Add redacted audit JSONL writer.
|
|
747
|
-
- Add gateway lifecycle shutdown on VCM server stop.
|
|
748
|
-
- Add status reporting for poll errors, expired login, disabled gateway, and
|
|
749
|
-
last successful message.
|
|
750
|
-
- Document manual smoke test steps.
|
|
751
|
-
|
|
752
|
-
Validation:
|
|
753
|
-
|
|
754
|
-
- Full unit test pass.
|
|
755
|
-
- Build pass.
|
|
756
|
-
- Manual iLink smoke test:
|
|
757
|
-
- QR bind
|
|
758
|
-
- `/status`
|
|
759
|
-
- `/pull-current`
|
|
760
|
-
- `/create-task mobile-demo`
|
|
761
|
-
- `/tasks`
|
|
762
|
-
- `/use-task`
|
|
763
|
-
- Chinese plain text to PM
|
|
764
|
-
- PM reply pushed back to Weixin
|
|
765
|
-
- `/close-task` + `/close-task confirm mobile-demo`
|
|
766
|
-
- restart without replaying old messages
|
|
767
|
-
|
|
768
|
-
## Key Risks And Decisions
|
|
769
|
-
|
|
770
|
-
PM reply extraction is the main implementation risk. VCM should use Claude
|
|
771
|
-
transcript events, not raw PTY output, because terminal output contains tool
|
|
772
|
-
logs, redraws, and partial text. The notifier must persist a per-PM-session
|
|
773
|
-
cursor.
|
|
774
|
-
|
|
775
|
-
The second risk is accidental command scope growth. Gateway should support the
|
|
776
|
-
small task lifecycle needed to run work end to end from mobile: pull base repo,
|
|
777
|
-
create and initialize a task, talk to PM, receive PM replies, and close the
|
|
778
|
-
task. It should still avoid arbitrary terminal control, approve/reject gates,
|
|
779
|
-
role-specific start/stop controls, shell commands, and direct non-PM prompts.
|
|
780
|
-
|
|
781
|
-
The third risk is token and message leakage. Gateway credentials and audit logs
|
|
782
|
-
must stay under `<vcmDataDir>/gateway`, with secrets redacted from logs and never
|
|
783
|
-
written into connected repositories.
|
|
784
|
-
|
|
785
|
-
The fourth risk is queueing. MVP should not queue multiple arbitrary user
|
|
786
|
-
prompts while PM is running. It should return a busy message and let the user
|
|
787
|
-
retry after PM stops.
|
|
788
|
-
|
|
789
|
-
## Acceptance Criteria
|
|
790
|
-
|
|
791
|
-
Gateway MVP is complete when:
|
|
792
|
-
|
|
793
|
-
- Desktop VCM can enable/disable Weixin iLink gateway.
|
|
794
|
-
- Desktop VCM can QR-bind one Weixin DM identity.
|
|
795
|
-
- Desktop VCM can use the most recent active Lark DM or group @mention as the
|
|
796
|
-
Gateway reply target.
|
|
797
|
-
- Bound phone can send `/status` and receive current VCM status.
|
|
798
|
-
- Bound phone can list and select current project/task context.
|
|
799
|
-
- Bound phone can run `/pull-current` to update the connected base repository
|
|
800
|
-
through VCM's fast-forward-only pull path.
|
|
801
|
-
- Bound phone can run `/create-task <task-slug> [title]` to create a task
|
|
802
|
-
worktree, select it, apply the saved launch template, and start
|
|
803
|
-
the four core role sessions.
|
|
804
|
-
- Bound phone can send Chinese plain text to current task PM.
|
|
805
|
-
- PM receives only the translated English prompt, without original Chinese.
|
|
806
|
-
- Gateway can push PM assistant replies to Weixin whenever enabled.
|
|
807
|
-
- PM replies are translated to Chinese when gateway translation is enabled.
|
|
808
|
-
- Bound phone can close a completed task through `/close-task` plus exact slug
|
|
809
|
-
confirmation, using the same cleanup path as desktop Close Task.
|
|
810
|
-
- Duplicate iLink messages and duplicate PM Stop hooks do not produce duplicate
|
|
811
|
-
sends.
|
|
812
|
-
- Expired iLink token is reported clearly and requires rebind.
|
|
813
|
-
- Gateway credentials and audit logs stay outside connected repositories.
|