openclacky 0.9.7 → 0.9.9

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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.clacky/skills/gem-release/SKILL.md +16 -1
  3. data/CHANGELOG.md +51 -0
  4. data/docs/browser-cdp-native-design.md +195 -0
  5. data/docs/session-management-redesign.md +202 -0
  6. data/docs/system-skill-authoring-guide.md +47 -0
  7. data/lib/clacky/agent/cost_tracker.rb +2 -1
  8. data/lib/clacky/agent/message_compressor_helper.rb +2 -2
  9. data/lib/clacky/agent/session_serializer.rb +36 -3
  10. data/lib/clacky/agent/skill_manager.rb +68 -5
  11. data/lib/clacky/agent/system_prompt_builder.rb +30 -13
  12. data/lib/clacky/agent/tool_executor.rb +8 -12
  13. data/lib/clacky/agent.rb +172 -30
  14. data/lib/clacky/brand_config.rb +90 -0
  15. data/lib/clacky/cli.rb +37 -8
  16. data/lib/clacky/default_parsers/doc_parser.rb +69 -0
  17. data/lib/clacky/default_parsers/docx_parser.rb +172 -0
  18. data/lib/clacky/default_parsers/pdf_parser.rb +79 -0
  19. data/lib/clacky/default_parsers/pptx_parser.rb +140 -0
  20. data/lib/clacky/default_parsers/xlsx_parser.rb +121 -0
  21. data/lib/clacky/default_skills/browser-setup/SKILL.md +158 -0
  22. data/lib/clacky/default_skills/channel-setup/SKILL.md +139 -42
  23. data/lib/clacky/default_skills/channel-setup/feishu_setup.rb +582 -0
  24. data/lib/clacky/default_skills/channel-setup/weixin_setup.rb +274 -0
  25. data/lib/clacky/default_skills/onboard/SKILL.md +132 -6
  26. data/lib/clacky/default_skills/personal-website/SKILL.md +113 -0
  27. data/lib/clacky/default_skills/personal-website/publish.rb +214 -0
  28. data/lib/clacky/default_skills/skill-add/SKILL.md +6 -7
  29. data/lib/clacky/default_skills/skill-add/scripts/install_from_zip.rb +1 -1
  30. data/lib/clacky/default_skills/skill-creator/SKILL.md +3 -3
  31. data/lib/clacky/json_ui_controller.rb +5 -0
  32. data/lib/clacky/message_format/open_ai.rb +7 -1
  33. data/lib/clacky/plain_ui_controller.rb +5 -0
  34. data/lib/clacky/server/browser_manager.rb +308 -0
  35. data/lib/clacky/server/channel/adapters/feishu/adapter.rb +80 -15
  36. data/lib/clacky/server/channel/adapters/feishu/bot.rb +216 -7
  37. data/lib/clacky/server/channel/adapters/feishu/message_parser.rb +12 -0
  38. data/lib/clacky/server/channel/adapters/wecom/adapter.rb +2 -8
  39. data/lib/clacky/server/channel/adapters/weixin/adapter.rb +391 -0
  40. data/lib/clacky/server/channel/adapters/weixin/api_client.rb +374 -0
  41. data/lib/clacky/server/channel/channel_config.rb +6 -0
  42. data/lib/clacky/server/channel/channel_manager.rb +50 -15
  43. data/lib/clacky/server/channel/channel_ui_controller.rb +18 -0
  44. data/lib/clacky/server/channel.rb +1 -0
  45. data/lib/clacky/server/http_server.rb +210 -45
  46. data/lib/clacky/server/scheduler.rb +1 -1
  47. data/lib/clacky/server/session_registry.rb +131 -40
  48. data/lib/clacky/server/web_ui_controller.rb +21 -2
  49. data/lib/clacky/session_manager.rb +43 -73
  50. data/lib/clacky/skill.rb +64 -42
  51. data/lib/clacky/tools/browser.rb +728 -183
  52. data/lib/clacky/tools/invoke_skill.rb +18 -11
  53. data/lib/clacky/tools/shell.rb +16 -7
  54. data/lib/clacky/tools/web_fetch.rb +3 -1
  55. data/lib/clacky/ui2/README.md +1 -1
  56. data/lib/clacky/ui2/components/input_area.rb +5 -2
  57. data/lib/clacky/ui2/components/welcome_banner.rb +23 -0
  58. data/lib/clacky/ui2/ui_controller.rb +16 -2
  59. data/lib/clacky/ui_interface.rb +7 -0
  60. data/lib/clacky/utils/file_processor.rb +116 -139
  61. data/lib/clacky/utils/model_pricing.rb +5 -4
  62. data/lib/clacky/utils/parser_manager.rb +93 -0
  63. data/lib/clacky/utils/workspace_rules.rb +46 -0
  64. data/lib/clacky/version.rb +1 -1
  65. data/lib/clacky/web/app.css +696 -62
  66. data/lib/clacky/web/app.js +181 -51
  67. data/lib/clacky/web/brand.js +14 -0
  68. data/lib/clacky/web/channels.js +10 -1
  69. data/lib/clacky/web/i18n.js +49 -7
  70. data/lib/clacky/web/index.html +67 -10
  71. data/lib/clacky/web/onboard.js +2 -1
  72. data/lib/clacky/web/sessions.js +255 -69
  73. data/lib/clacky/web/settings.js +113 -1
  74. data/lib/clacky/web/skills.js +16 -3
  75. data/lib/clacky/web/tasks.js +11 -6
  76. data/lib/clacky/web/weixin-qr.html +104 -0
  77. data/lib/clacky.rb +2 -0
  78. data/scripts/install.sh +41 -11
  79. metadata +48 -7
  80. data/lib/clacky/default_skills/pdf-reader/SKILL.md +0 -90
  81. data/lib/clacky/utils/file_parser/docx_parser.rb +0 -156
  82. data/lib/clacky/utils/file_parser/pptx_parser.rb +0 -116
  83. data/lib/clacky/utils/file_parser/xlsx_parser.rb +0 -95
  84. data/lib/clacky/utils/file_parser/zip_parser.rb +0 -60
  85. data/scripts/install_agent_browser.sh +0 -67
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: browser-setup
3
+ description: |
4
+ Configure the browser tool for Clacky. Guides the user through Chrome setup,
5
+ verifies the connection, and writes ~/.clacky/browser.yml.
6
+ Trigger on: "browser setup", "setup browser", "配置浏览器", "browser config",
7
+ "browser doctor".
8
+ Subcommands: setup, doctor.
9
+ argument-hint: "setup | doctor"
10
+ allowed-tools:
11
+ - Bash
12
+ - Read
13
+ - Write
14
+ - browser
15
+ ---
16
+
17
+ # Browser Setup Skill
18
+
19
+ Configure the browser tool for Clacky. Config is stored at `~/.clacky/browser.yml`.
20
+
21
+ ## Command Parsing
22
+
23
+ | User says | Subcommand |
24
+ |---|---|
25
+ | `browser setup`, `配置浏览器`, `setup browser` | setup |
26
+ | `browser doctor` | doctor |
27
+
28
+ If no subcommand is clear, default to `setup`.
29
+
30
+ ---
31
+
32
+ ## `setup`
33
+
34
+ ### Step 1 — Check Node.js & install chrome-devtools-mcp
35
+
36
+ Run:
37
+ ```bash
38
+ node --version
39
+ ```
40
+
41
+ If Node.js is missing or version < 20, tell the user and stop:
42
+
43
+ > ❌ The browser tool requires Node.js 20+.
44
+ > Please install it first: https://nodejs.org/
45
+ > Let me know when done and I'll retry.
46
+
47
+ Then install/update `chrome-devtools-mcp`:
48
+ ```bash
49
+ npm install -g chrome-devtools-mcp@latest
50
+ ```
51
+
52
+ If this fails, stop and tell the user:
53
+
54
+ > ❌ Failed to install chrome-devtools-mcp. Please run manually:
55
+ > ```
56
+ > npm install -g chrome-devtools-mcp@latest
57
+ > ```
58
+ > Let me know when done.
59
+
60
+ ### Step 2 — Try to connect to Chrome
61
+
62
+ Immediately attempt to connect — do **not** ask the user anything first:
63
+
64
+ ```
65
+ browser(action="act", kind="evaluate", js="navigator.userAgentData?.brands?.find(b => b.brand === 'Google Chrome')?.version || navigator.userAgent.match(/Chrome\\/([\\d]+)/)?.[1] || 'unknown'")
66
+ ```
67
+
68
+ **If connection succeeds** → parse the Chrome version and jump to Step 3.
69
+
70
+ **If connection fails** → inspect the error message from the evaluate result to diagnose:
71
+
72
+ **Case A — error contains `"timed out"`**: The MCP daemon failed to start — Chrome is not running or remote debugging is not enabled. Try to open the page for the user:
73
+
74
+ ```bash
75
+ open "chrome://inspect/#remote-debugging"
76
+ ```
77
+
78
+ Tell the user:
79
+
80
+ > I've opened `chrome://inspect/#remote-debugging` in Chrome.
81
+ > Please click **"Allow remote debugging for this browser instance"** and let me know when done.
82
+
83
+ If `open` fails, fall back to:
84
+
85
+ > Please open this URL in Chrome:
86
+ > `chrome://inspect/#remote-debugging`
87
+ > Then click **"Allow remote debugging for this browser instance"** and let me know when done.
88
+
89
+ Wait for the user to confirm, then retry the connection once. If still failing, stop:
90
+
91
+ > ❌ Could not connect to Chrome. Please make sure Chrome is open and remote debugging is enabled, then run `/browser-setup` again.
92
+
93
+ **Case B — error contains `"Chrome MCP error:"`**: The MCP daemon is alive but Chrome's CDP connection is broken — this is a known Chrome issue after long sessions. Tell the user:
94
+
95
+ > Chrome's remote debugging connection is unstable.
96
+ > Please restart Chrome and let me know when done.
97
+
98
+ Wait for the user to confirm, then retry once. If still failing, stop with the same error message as Case A.
99
+
100
+ ### Step 3 — Check Chrome version
101
+
102
+ Parse the version number from Step 2:
103
+ - version >= 146 → proceed
104
+ - version 144–145 → warn but proceed:
105
+ > ⚠️ Your Chrome version is vXXX. Version 146+ is recommended. Continuing anyway...
106
+ - version < 144 or unknown → stop:
107
+ > ❌ Chrome vXXX is too old. Please upgrade to Chrome 146+: https://www.google.com/chrome/
108
+ > Let me know when you've upgraded and I'll retry.
109
+
110
+ ### Step 4 — Save config and start daemon
111
+
112
+ ```bash
113
+ curl -s -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/browser/configure \
114
+ -H "Content-Type: application/json" \
115
+ -d '{"chrome_version":"<VERSION>"}'
116
+ ```
117
+
118
+ This writes `~/.clacky/browser.yml` and hot-reloads the daemon in one step.
119
+ If this fails (server not running), skip silently — the daemon will start lazily on next use.
120
+
121
+ ### Step 5 — Done
122
+
123
+ > ✅ Browser configured.
124
+ >
125
+ > Chrome v<VERSION> is connected and ready to use.
126
+
127
+ ---
128
+
129
+ ## `doctor`
130
+
131
+ Run a diagnostic check and report each item:
132
+
133
+ ```
134
+ Browser Doctor
135
+ ──────────────
136
+ [✅/❌] Config file (~/.clacky/browser.yml)
137
+ [✅/❌] Node.js 20+ (node --version)
138
+ [✅/❌] chrome-devtools-mcp (chrome-devtools-mcp --version)
139
+ [✅/❌] Chrome connection (browser status)
140
+ [✅/❌] Chrome version (≥146 best, ≥144 OK)
141
+ ```
142
+
143
+ For any ❌ item, show the fix inline.
144
+
145
+ Steps:
146
+ 1. Check `~/.clacky/browser.yml`:
147
+ - File missing → ❌ Not configured. Stop and suggest running `/browser-setup`.
148
+ - File exists, `enabled: false` → ⏸ Configured but disabled. Suggest running `/browser-setup` to re-enable.
149
+ - File exists, `enabled: true` → ✅ Continue.
150
+ 2. Run `node --version` via Bash.
151
+ 3. Run `chrome-devtools-mcp --version` via Bash; if missing, suggest `npm install -g chrome-devtools-mcp`.
152
+ 4. Run `browser(action="status")`:
153
+ - If failed, inspect the error message to distinguish the cause:
154
+ - error contains `"timed out"` → MCP daemon failed to start; Chrome not running or remote debugging not enabled. Fix: open `chrome://inspect/#remote-debugging`, click **"Allow remote debugging for this browser instance"**.
155
+ - error contains `"Chrome MCP error:"` → daemon alive but CDP connection broken after long session. Fix: restart Chrome.
156
+ 5. If step 4 succeeded, run evaluate to get Chrome version.
157
+
158
+ Report all results together at the end.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: channel-setup
3
3
  description: |
4
- Configure IM platform channels (Feishu, WeCom) for open-clacky.
4
+ Configure IM platform channels (Feishu, WeCom, Weixin) for open-clacky.
5
5
  Uses browser automation for navigation; guides the user to paste credentials and perform UI steps.
6
- Trigger on: "channel setup", "setup feishu", "setup wecom", "channel config",
6
+ Trigger on: "channel setup", "setup feishu", "setup wecom", "setup weixin", "setup wechat", "channel config",
7
7
  "channel status", "channel enable", "channel disable", "channel reconfigure", "channel doctor".
8
8
  Subcommands: setup, status, enable <platform>, disable <platform>, reconfigure, doctor.
9
9
  argument-hint: "setup | status | enable <platform> | disable <platform> | reconfigure | doctor"
@@ -21,14 +21,16 @@ allowed-tools:
21
21
 
22
22
  Configure IM platform channels for open-clacky. Config is stored at `~/.clacky/channels.yml`.
23
23
 
24
+ ---
25
+
24
26
  ## Command Parsing
25
27
 
26
28
  | User says | Subcommand |
27
29
  |---|---|
28
- | `channel setup`, `setup feishu`, `setup wecom` | setup |
30
+ | `channel setup`, `setup feishu`, `setup wecom`, `setup weixin`, `setup wechat` | setup |
29
31
  | `channel status` | status |
30
- | `channel enable feishu/wecom` | enable |
31
- | `channel disable feishu/wecom` | disable |
32
+ | `channel enable feishu/wecom/weixin` | enable |
33
+ | `channel disable feishu/wecom/weixin` | disable |
32
34
  | `channel reconfigure` | reconfigure |
33
35
  | `channel doctor` | doctor |
34
36
 
@@ -44,9 +46,12 @@ Channel Status
44
46
  Platform Enabled Details
45
47
  feishu ✅ yes app_id: cli_xxx... domain: feishu.cn
46
48
  wecom ❌ no (not configured)
49
+ weixin ✅ yes 2 account(s) logged in
47
50
  ─────────────────────────────────────────────────────
48
51
  ```
49
52
 
53
+ For Weixin, show `has_token: true/false` from the channels.yml entry (token is never displayed).
54
+
50
55
  If the file doesn't exist: "No channels configured yet. Run `/channel-setup setup` to get started."
51
56
 
52
57
  ---
@@ -58,34 +63,59 @@ Ask:
58
63
  >
59
64
  > 1. Feishu
60
65
  > 2. WeCom (Enterprise WeChat)
66
+ > 3. Weixin (Personal WeChat via iLink QR login)
61
67
 
62
68
  ---
63
69
 
64
70
  ### Feishu setup
65
71
 
66
- #### Phase 1 — Open Feishu Open Platform
72
+ #### Step 1 — Try automated setup (script)
73
+
74
+ Run the setup script (full path is available in the supporting files list above):
75
+ ```bash
76
+ ruby "SKILL_DIR/feishu_setup.rb"
77
+ ```
78
+
79
+ **If exit code is 0:**
80
+ - The script completed successfully.
81
+ - Config is already written to `~/.clacky/channels.yml`.
82
+ - Tell the user: "✅ Feishu channel configured automatically! The channel is ready."
83
+ - **Stop here — do not proceed to manual steps.**
84
+
85
+ **If exit code is non-0 (or script not found):**
86
+ - Note the failure reason from stdout (the last `❌` line).
87
+ - Tell the user: "Automated setup encountered an issue: `<reason>`. Switching to guided setup..."
88
+ - Continue to Step 2 (manual flow) below.
89
+
90
+ ---
91
+
92
+ #### Step 2 — Manual guided setup (fallback)
93
+
94
+ Only reach here if the automated script failed.
95
+
96
+ ##### Phase 1 — Open Feishu Open Platform
67
97
 
68
98
  1. Navigate: `open https://open.feishu.cn/app`. Pass `isolated: true`.
69
99
  2. If a login page or QR code is shown, tell the user to log in and wait for "done".
70
100
  3. Confirm the app list is visible.
71
101
 
72
- #### Phase 2 — Create a new app
102
+ ##### Phase 2 — Create a new app
73
103
 
74
- 6. **Always create a new app** — do NOT reuse existing apps. Guide the user: "Click 'Create Enterprise Self-Built App', fill in name (e.g. Open Clacky) and description (e.g. AI assistant powered by open-clacky), then submit. Reply done." Wait for "done".
104
+ 4. **Always create a new app** — do NOT reuse existing apps. Guide the user: "Click 'Create Enterprise Self-Built App', fill in name (e.g. Open Clacky) and description (e.g. AI assistant powered by open-clacky), then submit. Reply done." Wait for "done".
75
105
 
76
- #### Phase 3 — Enable Bot capability
106
+ ##### Phase 3 — Enable Bot capability
77
107
 
78
- 7. Feishu opens Add App Capabilities by default after creating an app. Guide the user: "Find the Bot capability card and click the Add button next to it, then reply done." Wait for "done".
108
+ 5. Feishu opens Add App Capabilities by default after creating an app. Guide the user: "Find the Bot capability card and click the Add button next to it, then reply done." Wait for "done".
79
109
 
80
- #### Phase 4 — Get credentials
110
+ ##### Phase 4 — Get credentials
81
111
 
82
- 8. Navigate to Credentials & Basic Info in the left menu.
83
- 9. Guide the user: "Copy App ID and App Secret, then paste here. Reply with: App ID: xxx, App Secret: xxx" Wait for "done".
112
+ 6. Navigate to Credentials & Basic Info in the left menu.
113
+ 7. Guide the user: "Copy App ID and App Secret, then paste here. Reply with: App ID: xxx, App Secret: xxx" Wait for the reply. Parse `app_id` and `app_secret`.
84
114
 
85
- #### Phase 5 — Add message permissions
115
+ ##### Phase 5 — Add message permissions
86
116
 
87
- 10. Navigate to Permission Management and open the bulk import dialog.
88
- 11. Guide the user: "In the bulk import dialog, clear the existing example first (select all, delete), then paste the following JSON. Reply done." Wait for "done". Do NOT try to clear or edit via browser — user does it.
117
+ 8. Navigate to Permission Management and open the bulk import dialog.
118
+ 9. Guide the user: "In the bulk import dialog, clear the existing example first (select all, delete), then paste the following JSON. Reply done." Wait for "done". Do NOT try to clear or edit via browser — user does it.
89
119
 
90
120
  ```json
91
121
  {
@@ -100,31 +130,38 @@ Ask:
100
130
  }
101
131
  ```
102
132
 
103
- #### Phase 6 — Configure event subscription (Long Connection)
104
-
105
- **CRITICAL**: Feishu requires the long connection to be established *before* you can save the event config. The platform shows "No application connection detected, ensure long connection is established before saving" until `clacky server` is running and connected. Do NOT try to save until the connection is established.
133
+ ##### Phase 6 — Configure event subscription (Long Connection)
106
134
 
107
- 12. **Apply config and establish connection** Run `curl -X POST http://localhost:7070/api/channels/feishu -H "Content-Type: application/json" -d '{"app_id":"...","app_secret":"...","domain":"..."}'`. The server hot-reloads the Feishu adapter and establishes the WebSocket.
108
- 13. **Wait for connection** — Wait until the log shows `[feishu-ws] WebSocket connected ✅`.
109
- 14. **Navigate to Events & Callbacks** — Then guide the user: "Select 'Long Connection' mode. Click Save. Then click Add Event, type `im.message.receive_v1` in the search box, select it, click Add. Reply done." Wait for "done".
135
+ **CRITICAL**: Feishu requires the long connection to be established *before* you can save the event config. The platform shows "No application connection detected" until `clacky server` is running and connected.
110
136
 
111
- #### Phase 7 Publish the app
137
+ 10. **Apply config and establish connection** — Run:
138
+ ```bash
139
+ curl -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/channels/feishu \
140
+ -H "Content-Type: application/json" \
141
+ -d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>","domain":"https://open.feishu.cn"}'
142
+ ```
143
+ 11. **Wait for connection** — Poll until log shows `[feishu-ws] WebSocket connected ✅`:
144
+ ```bash
145
+ for i in $(seq 1 20); do
146
+ grep -q "\[feishu-ws\] WebSocket connected" ~/.clacky/logger/clacky-$(date +%Y-%m-%d).log 2>/dev/null && echo "CONNECTED" && break
147
+ sleep 1
148
+ done
149
+ ```
150
+ 12. **Configure events** — Guide the user: "In Events & Callbacks, select 'Long Connection' mode. Click Save. Then click Add Event, search `im.message.receive_v1`, select it, click Add. Reply done." Wait for "done".
112
151
 
113
- 15. Navigate to Version Management & Release. Then guide the user: "Create a new version, fill in version (e.g. 1.0.0) and update description (e.g. Initial release for Open Clacky), then publish. Reply done." Wait for "done".
152
+ ##### Phase 7 Publish the app
114
153
 
115
- #### Phase 8 Finalize config and validate
154
+ 13. Navigate to Version Management & Release. Guide the user: "Create a new version (e.g. 1.0.0, note: Initial release for Open Clacky) and publish it. Reply done." Wait for "done".
116
155
 
117
- Config was applied in step 12 (via API).
156
+ ##### Phase 8 Validate
118
157
 
119
- Validate:
120
158
  ```bash
121
- curl -s -X POST "${DOMAIN}/open-apis/auth/v3/tenant_access_token/internal" \
159
+ curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
122
160
  -H "Content-Type: application/json" \
123
- -d "{\"app_id\":\"${APP_ID}\",\"app_secret\":\"${APP_SECRET}\"}"
161
+ -d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}'
124
162
  ```
125
- Check for `"code":0`. If it fails, explain and offer to retry.
126
163
 
127
- On success: "✅ Feishu channel configured. The channel is already active."
164
+ Check for `"code":0`. On success: "✅ Feishu channel configured."
128
165
 
129
166
  ---
130
167
 
@@ -132,13 +169,70 @@ On success: "✅ Feishu channel configured. The channel is already active."
132
169
 
133
170
  1. Navigate: `open https://work.weixin.qq.com/wework_admin/frame#/aiHelper/create`. Pass `isolated: true`.
134
171
  2. If a login page or QR code is shown, tell the user to log in and wait for "done".
135
- 3. Steps 3–7: Do NOT take snapshots. Guide the user: "Scroll to the bottom of the right panel and click 'API mode creation'. Reply done." Wait for "done".
136
- 4. Guide the user: "Click 'Add' next to 'Visible Range'. In the scope dialog, select the top-level company node (or specific users/departments). Click Confirm. Reply done." Wait for "done".
137
- 5. Guide the user: "If Secret is not visible, click 'Get Secret'. Copy Bot ID and Secret **before** clicking Save — do NOT click 'Get Secret' again after copying (it invalidates the previous secret). Paste here. Reply with: Bot ID: xxx, Secret: xxx" Wait for "done".
138
- 6. Guide the user: "Click Save. In the dialog, enter name (e.g. Open Clacky) and description (e.g. AI assistant powered by open-clacky). Click Confirm. Click Save again. Reply done." Wait for "done".
139
- 7. **Apply config and hot-reload** — Parse credentials from step 5. Trim leading/trailing whitespace from bot_id and secret. Run `curl -X POST http://localhost:7070/api/channels/wecom -H "Content-Type: application/json" -d '{"bot_id":"...","secret":"..."}'`. Ensure bot_id (starts with `aib`) and secret (longer string) are not swapped.
172
+ 3. Guide the user: "Scroll to the bottom of the right panel and click 'API mode creation'. Reply done." Wait for "done".
173
+ 4. Guide the user: "Click 'Add' next to 'Visible Range'. Select the top-level company node. Click Confirm. Reply done." Wait for "done".
174
+ 5. Guide the user: "If Secret is not visible, click 'Get Secret'. Copy Bot ID and Secret **before** clicking Save. Paste here. Reply with: Bot ID: xxx, Secret: xxx" Wait for "done".
175
+ 6. Guide the user: "Click Save. Enter name (e.g. Open Clacky) and description. Click Confirm. Click Save again. Reply done." Wait for "done".
176
+ 7. Parse credentials. Trim whitespace. Ensure bot_id (starts with `aib`) and secret are not swapped. Run:
177
+ ```bash
178
+ curl -X POST http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/api/channels/wecom \
179
+ -H "Content-Type: application/json" \
180
+ -d '{"bot_id":"<BOT_ID>","secret":"<SECRET>"}'
181
+ ```
182
+
183
+ On success: "✅ WeCom channel configured. WeCom client → Contacts → Smart Bot to find it."
184
+
185
+ ---
186
+
187
+ ### Weixin setup (Personal WeChat via iLink QR login)
188
+
189
+ Weixin uses a QR code login — no app_id/app_secret needed. The token from the QR scan is saved directly in `channels.yml`.
190
+
191
+ #### Step 1 — Fetch QR code and open in browser
192
+
193
+ Run the script in `--fetch-qr` mode to get the QR URL without blocking:
194
+
195
+ ```bash
196
+ QR_JSON=$(ruby "SKILL_DIR/weixin_setup.rb" --fetch-qr 2>/dev/null)
197
+ echo "$QR_JSON"
198
+ ```
199
+
200
+ Parse the JSON output:
201
+ - `qrcode_url` — the URL to open in browser (this IS the QR code content)
202
+ - `qrcode_id` — the session ID needed for polling
203
+
204
+ If the output contains `"error"`, show it and stop.
205
+
206
+ Tell the user:
207
+ > Opening the WeChat QR code in your browser. Please scan it with WeChat, then confirm in the app.
208
+
209
+ **Open the QR code page in browser** — build a local URL and navigate to it:
210
+
211
+ ```
212
+ http://${CLACKY_SERVER_HOST}:${CLACKY_SERVER_PORT}/weixin-qr.html?url=<URL-encoded qrcode_url>
213
+ ```
214
+
215
+ Use the browser tool to open this URL. The page renders a proper scannable QR code image using qrcode.js.
216
+ Do NOT open the raw `qrcode_url` directly — that page shows "请使用微信扫码打开" with no actual QR image.
217
+
218
+ #### Step 3 — Wait for scan and save credentials
219
+
220
+ Once the browser shows the QR page, immediately run the polling script in the background:
221
+
222
+ ```bash
223
+ ruby "SKILL_DIR/weixin_setup.rb" --qrcode-id "$QRCODE_ID"
224
+ ```
225
+
226
+ Where `$QRCODE_ID` is the `qrcode_id` from Step 2's JSON output.
227
+
228
+ This command blocks until the user scans and confirms in WeChat (up to 5 minutes), then automatically saves the token via `POST /api/channels/weixin`.
229
+
230
+ Tell the user while waiting:
231
+ > Waiting for you to scan the QR code and confirm in WeChat... (this may take a moment)
232
+
233
+ **If exit code is 0:** "✅ Weixin channel configured! You can now message your bot on WeChat."
140
234
 
141
- On success: "✅ WeCom channel configured. To use the bot: WeCom client → Contacts → select Smart Bot to see the newly created bot.".
235
+ **If exit code is non-0 or times out:** Show the error and offer to retry from Step 2.
142
236
 
143
237
  ---
144
238
 
@@ -164,7 +258,7 @@ Say: "❌ `<platform>` channel disabled. Restart `clacky server` to deactivate."
164
258
 
165
259
  1. Show current config (mask secrets).
166
260
  2. Ask: update credentials / change allowed users / add a new platform / enable or disable a platform.
167
- 3. For credential updates, re-run the relevant setup flow (Admin Console or Client flow for WeCom).
261
+ 3. For credential updates, re-run the relevant setup flow.
168
262
  4. Write atomically: write to `~/.clacky/channels.yml.tmp` then rename to `~/.clacky/channels.yml`.
169
263
  5. Say: "Restart `clacky server` to apply changes."
170
264
 
@@ -178,13 +272,16 @@ Check each item, report ✅ / ❌ with remediation:
178
272
  2. **Required keys** — for each enabled platform:
179
273
  - Feishu: `app_id`, `app_secret` present and non-empty
180
274
  - WeCom: `bot_id`, `secret` present and non-empty
275
+ - Weixin: `token` present and non-empty in `channels.yml`
181
276
  3. **Feishu credentials** (if enabled) — run the token API call, check `code=0`.
182
- 4. **WeCom credentials** (if enabled) — search today's log for auth-related lines:
277
+ 4. **Weixin token** (if enabled) — call `GET /api/channels` and check `has_token: true` for the weixin entry.
278
+ 5. **WeCom credentials** (if enabled) — search today's log:
183
279
  ```bash
184
- grep -iE "wecom adapter loop started|WeCom authentication failed|WeCom WS error response|WecomAdapter" ~/.clacky/logger/clacky-$(date +%Y-%m-%d).log
280
+ grep -iE "wecom adapter loop started|WeCom authentication failed|WeCom WS error response|WecomAdapter" \
281
+ ~/.clacky/logger/clacky-$(date +%Y-%m-%d).log
185
282
  ```
186
- - If output contains `WeCom authentication failed` or `WeCom WS error response` with non-zero errcode: ❌ "WeCom Bot ID or Secret is incorrect — re-run `/channel-setup reconfigure`"
187
- - If output contains `[ChannelManager] :wecom adapter loop started` with no auth error after it:
283
+ - `WeCom authentication failed` or non-zero errcode ❌ "WeCom credentials incorrect"
284
+ - `adapter loop started` with no auth error
188
285
 
189
286
  ---
190
287