vibe-coding-master 0.2.4 → 0.2.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.
@@ -0,0 +1,585 @@
1
+ # VCM Gateway Design
2
+
3
+ Last updated: 2026-06-10
4
+
5
+ This document defines the first VCM gateway product behavior and implementation
6
+ plan. It is 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
+ The first gateway channel is Tencent iLink Bot API / Weixin DM.
13
+
14
+ ## Product Definition
15
+
16
+ VCM Gateway is a mobile conversation bridge between one Weixin DM and one
17
+ desktop VCM instance. It is not a remote terminal, not a group-chat bot, and not
18
+ a multi-user collaboration feature.
19
+
20
+ Product rules:
21
+
22
+ - Support DM only. Group chat is not a supported product mode.
23
+ - Bind one mobile Weixin DM identity to one desktop VCM instance.
24
+ - The binding is not project-specific and not task-specific.
25
+ - The bound phone can manage every project and task available to that desktop
26
+ VCM instance.
27
+ - Gateway user messages talk only to the `project-manager` role.
28
+ - Gateway never sends directly to `architect`, `coder`, or `reviewer`.
29
+ - Gateway may push PM replies to Weixin whenever it is enabled, even when the PM
30
+ turn was started from the desktop UI rather than from Weixin.
31
+ - When translation is enabled, Chinese input is translated to English before it
32
+ is sent to PM.
33
+ - The prompt sent to PM does not include the original Chinese text.
34
+ - There is no allowed-user list. The security model is one bound DM identity.
35
+
36
+ The short product sentence is:
37
+
38
+ ```text
39
+ One phone DM binds to one desktop VCM; the phone can select project/task context,
40
+ send ordinary messages to the current task's PM, and receive translated PM
41
+ replies while gateway is enabled.
42
+ ```
43
+
44
+ ## Binding Model
45
+
46
+ The binding target is the desktop VCM instance.
47
+
48
+ ```text
49
+ Weixin DM identity
50
+ <-> desktop VCM instance
51
+ ```
52
+
53
+ The gateway stores the iLink bot account token and the bound Weixin user identity
54
+ in app-local state. If the QR login result provides a login user id, VCM stores
55
+ that identity. If the channel cannot determine the bound user id at login time,
56
+ VCM stores the first inbound DM user id after the user confirms binding from the
57
+ desktop UI.
58
+
59
+ Messages from the bound identity are accepted. Messages from any other identity
60
+ are ignored or receive a minimal "not bound" reply. They are not treated as
61
+ secondary users.
62
+
63
+ Changing phones or Weixin accounts is a rebind operation:
64
+
65
+ ```text
66
+ desktop settings -> disable gateway or reset binding -> QR login / bind again
67
+ ```
68
+
69
+ ## Mobile Context
70
+
71
+ Because the binding is to a desktop VCM instance, gateway needs a current mobile
72
+ context:
73
+
74
+ ```text
75
+ current project
76
+ current task
77
+ current role = project-manager
78
+ translation enabled/disabled
79
+ ```
80
+
81
+ Plain text messages are sent to the PM session of the current task. If no
82
+ project or task is selected, gateway replies with a short setup hint.
83
+
84
+ The desktop UI remains the source of truth. Gateway only changes context through
85
+ explicit commands.
86
+
87
+ ## Command Surface
88
+
89
+ MVP commands:
90
+
91
+ ```text
92
+ /help
93
+ /status
94
+ /projects
95
+ /use-project <index-or-path>
96
+ /tasks
97
+ /use-task <index-or-task-slug>
98
+ /translate on
99
+ /translate off
100
+ ```
101
+
102
+ Plain text that does not start with `/` is treated as a PM message for the
103
+ current task.
104
+
105
+ Commands intentionally not in MVP:
106
+
107
+ ```text
108
+ /approve
109
+ /reject
110
+ /pause
111
+ /resume
112
+ /start-session
113
+ /stop-session
114
+ ```
115
+
116
+ The first version should not expose state-changing workflow controls beyond
117
+ selecting the mobile context and toggling gateway translation. More controls can
118
+ be added later after the PM-only conversation path is reliable.
119
+
120
+ ## Inbound Message Flow
121
+
122
+ ```text
123
+ Tencent iLink getupdates
124
+ -> weixin-ilink channel
125
+ -> verify bound DM identity
126
+ -> dedupe message id
127
+ -> parse text / command
128
+ -> if command: execute gateway command and reply
129
+ -> if plain text:
130
+ -> require current project + current task
131
+ -> require current task PM session running and hook-idle
132
+ -> translate Chinese to English when enabled
133
+ -> submit English prompt to PM
134
+ -> reply with accepted / busy / error status
135
+ ```
136
+
137
+ PM prompt shape when translation is enabled:
138
+
139
+ ```text
140
+ [VCM Gateway]
141
+ <translated English instruction>
142
+ ```
143
+
144
+ The original Chinese is not included in the PM prompt.
145
+
146
+ If translation is disabled, the plain user text is submitted as-is with the same
147
+ `[VCM Gateway]` marker.
148
+
149
+ Gateway should use the same bracketed-paste terminal submission path as the VCM
150
+ desktop input path. A terminal write only proves the text was written to the PTY;
151
+ Claude Code `UserPromptSubmit` remains the acceptance signal.
152
+
153
+ ## PM Reply Push Flow
154
+
155
+ Gateway push is not limited to gateway-originated turns. If gateway is enabled,
156
+ VCM should push PM replies to Weixin after PM completes a turn.
157
+
158
+ ```text
159
+ PM Claude Code Stop hook
160
+ -> load PM session transcript
161
+ -> extract new assistant text since last pushed transcript cursor
162
+ -> ignore tool logs, raw terminal output, and non-PM roles
163
+ -> translate English reply to Chinese when enabled
164
+ -> send Weixin DM through iLink sendmessage
165
+ -> persist last pushed transcript cursor
166
+ ```
167
+
168
+ Rules:
169
+
170
+ - Push only PM assistant replies.
171
+ - Do not push token-by-token terminal output.
172
+ - Do not push raw tool logs.
173
+ - Do not push architect/coder/reviewer replies directly.
174
+ - Deduplicate by PM session id and transcript event id or timestamp.
175
+ - If translation fails, send the PM original text with a short translation
176
+ failure note.
177
+
178
+ This keeps the mobile side readable and avoids exposing the embedded terminal as
179
+ a chat stream.
180
+
181
+ ## Busy And Error Behavior
182
+
183
+ The MVP should be conservative.
184
+
185
+ If the PM session is busy, do not queue arbitrary mobile prompts. Reply:
186
+
187
+ ```text
188
+ PM is still working on the current turn. Please wait and send again later.
189
+ ```
190
+
191
+ If PM is not running:
192
+
193
+ ```text
194
+ The current task's PM session is not running. Start it from desktop VCM first.
195
+ ```
196
+
197
+ If no task is selected:
198
+
199
+ ```text
200
+ No task is selected. Use /tasks and /use-task first.
201
+ ```
202
+
203
+ If gateway translation fails before sending to PM, do not send the original
204
+ Chinese. Reply with a translation failure message and ask the user to retry.
205
+
206
+ ## Tencent iLink Feasibility
207
+
208
+ The local smoke test proves the required channel primitives:
209
+
210
+ - QR login with `ilink/bot/get_bot_qrcode`.
211
+ - QR status polling with `ilink/bot/get_qrcode_status`.
212
+ - Long-poll DM receive with `ilink/bot/getupdates`.
213
+ - Text reply with `ilink/bot/sendmessage`.
214
+ - Token and cursor persistence outside a repository.
215
+ - Handling session expiration through iLink error code `-14`.
216
+
217
+ Observed request details from the smoke test:
218
+
219
+ ```text
220
+ base URL: https://ilinkai.weixin.qq.com
221
+ default bot_type: 3
222
+ default channel_version: 2.4.3
223
+ ```
224
+
225
+ Common headers:
226
+
227
+ ```text
228
+ Content-Type: application/json
229
+ AuthorizationType: ilink_bot_token
230
+ Authorization: Bearer <token>
231
+ X-WECHAT-UIN: <random base64 uin>
232
+ iLink-App-Id: bot
233
+ iLink-App-ClientVersion: <encoded client version>
234
+ SKRouteTag: <optional route tag>
235
+ ```
236
+
237
+ QR login:
238
+
239
+ ```text
240
+ POST ilink/bot/get_bot_qrcode?bot_type=<bot_type>
241
+ body:
242
+ {
243
+ "local_token_list": ["<saved token>"]
244
+ }
245
+
246
+ GET ilink/bot/get_qrcode_status?qrcode=<qrcode>
247
+ GET ilink/bot/get_qrcode_status?qrcode=<qrcode>&verify_code=<code>
248
+ ```
249
+
250
+ QR statuses handled by the smoke test:
251
+
252
+ ```text
253
+ wait
254
+ scaned
255
+ need_verifycode
256
+ verify_code_blocked
257
+ expired
258
+ scaned_but_redirect
259
+ binded_redirect
260
+ confirmed
261
+ ```
262
+
263
+ Long poll receive:
264
+
265
+ ```text
266
+ POST ilink/bot/getupdates
267
+ body:
268
+ {
269
+ "get_updates_buf": "<cursor>",
270
+ "base_info": {
271
+ "channel_version": "2.4.3",
272
+ "bot_agent": "vcm-gateway/<version>"
273
+ }
274
+ }
275
+ ```
276
+
277
+ The response may include:
278
+
279
+ ```text
280
+ ret / errcode
281
+ errmsg
282
+ longpolling_timeout_ms
283
+ get_updates_buf
284
+ msgs[]
285
+ ```
286
+
287
+ Send text DM:
288
+
289
+ ```text
290
+ POST ilink/bot/sendmessage
291
+ body:
292
+ {
293
+ "msg": {
294
+ "from_user_id": "",
295
+ "to_user_id": "<bound user id>",
296
+ "client_id": "<unique client id>",
297
+ "message_type": 2,
298
+ "message_state": 2,
299
+ "item_list": [
300
+ {
301
+ "type": 1,
302
+ "text_item": {
303
+ "text": "<reply text>"
304
+ }
305
+ }
306
+ ],
307
+ "context_token": "<optional latest context token>"
308
+ },
309
+ "base_info": {
310
+ "channel_version": "2.4.3",
311
+ "bot_agent": "vcm-gateway/<version>"
312
+ }
313
+ }
314
+ ```
315
+
316
+ Inbound message handling:
317
+
318
+ - Ignore bot messages where `message_type` is bot.
319
+ - Accept user messages where `message_type` is user or absent.
320
+ - Extract text from `item_list[].text_item.text`.
321
+ - Voice text can be read from `item_list[].voice_item.text` if iLink supplies
322
+ it, but MVP should treat non-text input as unsupported unless text is present.
323
+ - Use `message_id`, then `client_id`, then sender/time fallback for dedupe.
324
+ - Persist `get_updates_buf` after each successful poll response.
325
+ - Persist latest `context_token` per bound user and reuse it for replies.
326
+
327
+ ## Local State
328
+
329
+ Gateway state must live outside connected repositories.
330
+
331
+ Recommended files:
332
+
333
+ ```text
334
+ ~/.vcm/gateway/settings.json
335
+ ~/.vcm/gateway/audit.jsonl
336
+ ```
337
+
338
+ Settings shape:
339
+
340
+ ```json
341
+ {
342
+ "version": 1,
343
+ "enabled": false,
344
+ "channel": "weixin-ilink",
345
+ "translationEnabled": true,
346
+ "currentProjectId": null,
347
+ "currentTaskSlug": null,
348
+ "binding": {
349
+ "accountId": null,
350
+ "baseUrl": "https://ilinkai.weixin.qq.com",
351
+ "boundUserId": null,
352
+ "loginUserId": null,
353
+ "token": null,
354
+ "getUpdatesBuf": "",
355
+ "contextTokens": {}
356
+ },
357
+ "dedupe": {
358
+ "recentInboundMessageIds": []
359
+ },
360
+ "pushCursors": {
361
+ "<taskSlug>:project-manager:<claudeSessionId>": {
362
+ "lastTranscriptEventId": null,
363
+ "lastTranscriptTimestamp": null
364
+ }
365
+ },
366
+ "updatedAt": "..."
367
+ }
368
+ ```
369
+
370
+ The token is sensitive. The settings file should be written with user-only file
371
+ permissions where the platform supports it.
372
+
373
+ Audit log rules:
374
+
375
+ - Record state transitions, command names, message ids, result codes, and error
376
+ classes.
377
+ - Redact token, Authorization header, QR URL, and full message bodies by default.
378
+ - Store short message previews only when needed for debugging.
379
+ - Never write gateway credentials to connected repositories, terminal logs,
380
+ `.ai/vcm/**`, PR descriptions, or generated harness files.
381
+
382
+ ## Backend Architecture
383
+
384
+ Suggested files:
385
+
386
+ ```text
387
+ src/shared/types/gateway.ts
388
+
389
+ src/backend/gateway/
390
+ gateway-service.ts
391
+ gateway-settings-service.ts
392
+ gateway-command-parser.ts
393
+ gateway-pm-bridge.ts
394
+ gateway-notifier.ts
395
+ gateway-audit-log.ts
396
+ channels/
397
+ weixin-ilink-channel.ts
398
+
399
+ src/backend/api/gateway-routes.ts
400
+ ```
401
+
402
+ Responsibilities:
403
+
404
+ - `gateway-settings-service`: load/save app-local gateway settings and secrets.
405
+ - `weixin-ilink-channel`: QR login, long polling, send text, token expiration.
406
+ - `gateway-command-parser`: parse `/help`, `/status`, `/projects`,
407
+ `/use-project`, `/tasks`, `/use-task`, and `/translate`.
408
+ - `gateway-pm-bridge`: submit plain messages to the current task PM session.
409
+ - `gateway-notifier`: push PM transcript replies to Weixin after PM Stop.
410
+ - `gateway-audit-log`: append redacted JSONL audit entries.
411
+ - `gateway-service`: lifecycle, poll loop, dispatch, and error backoff.
412
+ - `gateway-routes`: desktop UI settings, QR login start/status, enable/disable,
413
+ rebind, and gateway status.
414
+
415
+ Service dependencies:
416
+
417
+ - `ProjectService`: current project and recent project paths.
418
+ - `TaskService`: task list and selected task validation.
419
+ - `SessionService`: PM session state and Claude session metadata.
420
+ - `TerminalRuntime`: controlled PM terminal submission.
421
+ - `ClaudeTranscriptService`: PM assistant output extraction.
422
+ - `TranslationService` / translation provider: inbound Chinese-to-English and
423
+ outbound English-to-Chinese translation.
424
+ - `ClaudeHookService` or hook event integration: trigger PM reply push after PM
425
+ `Stop`.
426
+
427
+ ## Desktop UI
428
+
429
+ Add a Gateway section to the sidebar settings area or a dedicated modal:
430
+
431
+ ```text
432
+ Gateway: off / on
433
+ Channel: Weixin iLink
434
+ Binding: not bound / bound
435
+ Translation: off / on
436
+ Current project
437
+ Current task
438
+ QR login / Rebind
439
+ Last poll status
440
+ Last message status
441
+ ```
442
+
443
+ The user should be able to:
444
+
445
+ - enable or disable gateway
446
+ - start QR login
447
+ - see whether the phone is bound
448
+ - reset binding
449
+ - select current project/task from desktop
450
+ - toggle gateway translation
451
+ - inspect recent gateway errors
452
+
453
+ ## Implementation Plan
454
+
455
+ ### Phase 1: Types, Settings, And UI Skeleton
456
+
457
+ - Add `src/shared/types/gateway.ts`.
458
+ - Add app-local gateway settings service under `src/backend/gateway`.
459
+ - Add `src/backend/api/gateway-routes.ts`.
460
+ - Add desktop UI controls for enable/disable, translation, binding status, and
461
+ current project/task.
462
+ - Store settings under `~/.vcm/gateway/settings.json`.
463
+
464
+ Validation:
465
+
466
+ - Unit tests for settings normalization and secret redaction.
467
+ - API route tests for enable/disable and settings update.
468
+
469
+ ### Phase 2: iLink Channel Adapter
470
+
471
+ - Port the proven smoke-test behavior into `weixin-ilink-channel.ts`.
472
+ - Support QR login and status polling.
473
+ - Support token reuse from saved settings.
474
+ - Support `getupdates` long polling.
475
+ - Support `sendmessage` text DM.
476
+ - Persist `get_updates_buf` and context tokens.
477
+ - Handle `ret` / `errcode` `-14` as expired login.
478
+
479
+ Validation:
480
+
481
+ - Unit tests with mocked fetch for QR statuses, getupdates, sendmessage,
482
+ expiration, redirect host, and retry backoff.
483
+ - Manual smoke test with a real Weixin DM before wiring PM submission.
484
+
485
+ ### Phase 3: Inbound Command Handling
486
+
487
+ - Implement `/help`, `/status`, `/projects`, `/use-project`, `/tasks`,
488
+ `/use-task`, `/translate on`, and `/translate off`.
489
+ - Implement bound identity check.
490
+ - Implement persistent inbound message dedupe.
491
+ - Reply with short command results through iLink.
492
+
493
+ Validation:
494
+
495
+ - Parser tests for known commands and invalid commands.
496
+ - Gateway service tests for ignored unbound users and deduped messages.
497
+
498
+ ### Phase 4: PM Message Submission
499
+
500
+ - Treat plain DM text as PM input for the current task.
501
+ - Require current project, current task, running PM session, and idle PM
502
+ activity.
503
+ - If gateway translation is enabled, translate Chinese to English before
504
+ submission.
505
+ - Submit only the translated English text to PM with `[VCM Gateway]`.
506
+ - Do not include the original Chinese text in the PM prompt.
507
+ - Use bracketed paste plus Enter through `submitTerminalInput`.
508
+
509
+ Validation:
510
+
511
+ - Tests for no project/task/session/busy/translation failure paths.
512
+ - Tests that translated prompts do not include original Chinese.
513
+ - Tests that successful submit records a gateway turn audit entry.
514
+
515
+ ### Phase 5: PM Reply Push
516
+
517
+ - Hook PM `Stop` handling into `gateway-notifier`.
518
+ - Load PM transcript and extract new assistant text since the last push cursor.
519
+ - Push PM replies whenever gateway is enabled, regardless of whether the user
520
+ turn started from gateway or desktop.
521
+ - Translate PM reply to Chinese when gateway translation is enabled.
522
+ - Persist push cursors so restart does not duplicate old PM replies.
523
+
524
+ Validation:
525
+
526
+ - Transcript extraction tests with multiple assistant events.
527
+ - Deduplication tests across repeated Stop hooks and app restart.
528
+ - Translation failure fallback test.
529
+
530
+ ### Phase 6: Audit, Recovery, And Packaging
531
+
532
+ - Add redacted audit JSONL writer.
533
+ - Add gateway lifecycle shutdown on VCM server stop.
534
+ - Add status reporting for poll errors, expired login, disabled gateway, and
535
+ last successful message.
536
+ - Document manual smoke test steps.
537
+
538
+ Validation:
539
+
540
+ - Full unit test pass.
541
+ - Build pass.
542
+ - Manual iLink smoke test:
543
+ - QR bind
544
+ - `/status`
545
+ - `/tasks`
546
+ - `/use-task`
547
+ - Chinese plain text to PM
548
+ - PM reply pushed back to Weixin
549
+ - restart without replaying old messages
550
+
551
+ ## Key Risks And Decisions
552
+
553
+ PM reply extraction is the main implementation risk. VCM should use Claude
554
+ transcript events, not raw PTY output, because terminal output contains tool
555
+ logs, redraws, and partial text. The notifier must persist a per-PM-session
556
+ cursor.
557
+
558
+ The second risk is accidental command scope growth. The MVP must stay PM-only
559
+ and avoid workflow actions such as approve/reject/start/stop until the mobile
560
+ conversation path is proven.
561
+
562
+ The third risk is token and message leakage. Gateway credentials and audit logs
563
+ must stay under `~/.vcm/gateway`, with secrets redacted from logs and never
564
+ written into connected repositories.
565
+
566
+ The fourth risk is queueing. MVP should not queue multiple arbitrary user
567
+ prompts while PM is running. It should return a busy message and let the user
568
+ retry after PM stops.
569
+
570
+ ## Acceptance Criteria
571
+
572
+ Gateway MVP is complete when:
573
+
574
+ - Desktop VCM can enable/disable Weixin iLink gateway.
575
+ - Desktop VCM can QR-bind one Weixin DM identity.
576
+ - Bound phone can send `/status` and receive current VCM status.
577
+ - Bound phone can list and select current project/task context.
578
+ - Bound phone can send Chinese plain text to current task PM.
579
+ - PM receives only the translated English prompt, without original Chinese.
580
+ - Gateway can push PM assistant replies to Weixin whenever enabled.
581
+ - PM replies are translated to Chinese when gateway translation is enabled.
582
+ - Duplicate iLink messages and duplicate PM Stop hooks do not produce duplicate
583
+ sends.
584
+ - Expired iLink token is reported clearly and requires rebind.
585
+ - Gateway credentials and audit logs stay outside connected repositories.