@mu-cabin/muc-cli 0.3.0 → 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/README.md +262 -393
- package/dist/muc.mjs +14170 -2900
- package/dist/templates/code-handler/bin/prep-repo +386 -0
- package/dist/templates/code-handler/setup-notes.md +63 -0
- package/dist/templates/code-handler/system-prompt.md +153 -0
- package/dist/templates/code-handler/template.json +15 -0
- package/dist/templates/general-chat/setup-notes.md +64 -0
- package/dist/templates/general-chat/system-prompt.md +44 -0
- package/dist/templates/general-chat/template.json +12 -0
- package/dist/templates/image-generator/setup-notes.md +64 -0
- package/dist/templates/image-generator/system-prompt.md +74 -0
- package/dist/templates/image-generator/template.json +14 -0
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -1,459 +1,328 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MUC-cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
called MUC.app). Drives the same REST surface the desktop talks to, plus the
|
|
5
|
-
binary chat protocol on raw TCP 8101 for sending messages, withdrawing, and
|
|
6
|
-
syncing sessions.
|
|
3
|
+
**muc-cli** 把 MUC IM(com.meicloud.im.dh)搬进终端。在 shell 里登录、找人、列群、读历史、收发消息和文件,不用打开桌面端 GUI。它同时附带**MUC Skill**,让你直接对 agent 说"把这个报告发给 张三",Skill 会自动选命令、解析返回值。
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
allows concurrent `accessToken`s. Chat-channel commands share online slots
|
|
10
|
-
with real devices; see [Coexistence](#coexistence) below before sending.
|
|
5
|
+
---
|
|
11
6
|
|
|
12
|
-
##
|
|
7
|
+
## 快速安装(复制给 Agent)
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
把下面这段话发给 Agent, 它会帮你完成全部安装:
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
```
|
|
12
|
+
帮我安装 muc-cli 和 MUC Skill:
|
|
13
|
+
1. 运行 `npm install -g @mu-cabin/muc-cli` 安装 CLI
|
|
14
|
+
2. 运行 `npx skills add <everything-cli 仓库地址>/packages/muc/skills -y -g` 注册 Skill(全局安装到所有 agent)
|
|
15
|
+
3. 运行下面这条 `muc init` 一次性写入租户配置(值见你的 MUC 部署管理员):
|
|
16
|
+
muc init --no-interactive \
|
|
17
|
+
--app-key <APP_KEY> \
|
|
18
|
+
--app-id <APP_ID> \
|
|
19
|
+
--sign-secret-rest '<SIGN_SECRET_REST>' \
|
|
20
|
+
--sign-secret-secure '<SIGN_SECRET_SECURE>'
|
|
21
|
+
4. 运行 `muc login --account <UID大写,如 ALICE> --password '<密码>'` 登录
|
|
22
|
+
5. 运行 `muc whoami` 确认登录成功
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## MUC 租户配置
|
|
28
|
+
|
|
29
|
+
CLI 不把租户密钥编进发布包;首次安装后必须用 `muc init` 把这四个值写入
|
|
30
|
+
`~/.muc/config.json`(权限 0600)。**这些值因部署而异——向你的 MUC 管理员索取,
|
|
31
|
+
不要外发。**
|
|
32
|
+
|
|
33
|
+
| 字段 | 值 |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `APP_KEY` | `<APP_KEY>`(8 位小写 hex) |
|
|
36
|
+
| `APP_ID` | `<APP_ID>`(24 位小写 hex) |
|
|
37
|
+
| `SIGN_SECRET_REST` | `<SIGN_SECRET_REST>` |
|
|
38
|
+
| `SIGN_SECRET_SECURE` | `<SIGN_SECRET_SECURE>` |
|
|
39
|
+
| `PWD_DES_KEY` | 留空(自动用 `APP_KEY`) |
|
|
40
|
+
|
|
41
|
+
主机/端口(向管理员索取你的部署地址,CLI 内置默认仅适用于特定租户):
|
|
42
|
+
|
|
43
|
+
| 字段 | 示例 |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `restHost` | `https://muc.example.com/` |
|
|
46
|
+
| `ssoHost` | `https://store.example.com/` |
|
|
47
|
+
| `imHost` / `imPort` | `muc.example.com` / `8101` |
|
|
48
|
+
| `fileHost` / `filePort` | `muc.example.com` / `6101` |
|
|
27
49
|
|
|
28
|
-
|
|
50
|
+
一行式(非交互,CI/Agent 友好):
|
|
29
51
|
|
|
30
52
|
```bash
|
|
31
|
-
|
|
32
|
-
|
|
53
|
+
muc init --no-interactive \
|
|
54
|
+
--app-key <APP_KEY> \
|
|
55
|
+
--app-id <APP_ID> \
|
|
56
|
+
--sign-secret-rest '<SIGN_SECRET_REST>' \
|
|
57
|
+
--sign-secret-secure '<SIGN_SECRET_SECURE>'
|
|
33
58
|
```
|
|
34
59
|
|
|
35
|
-
|
|
36
|
-
DES-CBC password encryption is `crypto-js` (pure JS) — no
|
|
37
|
-
`--openssl-legacy-provider` flag needed.
|
|
38
|
-
|
|
39
|
-
`~/.muc/credentials.json` and `~/.muc/config.json` are written with mode
|
|
40
|
-
`600` and the parent dir with mode `700`. POSIX honors that; on Windows the
|
|
41
|
-
modes are silently ignored — protect the files with NTFS ACLs if you're on a
|
|
42
|
-
shared host.
|
|
60
|
+
或交互式:
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
```bash
|
|
63
|
+
muc init # 逐项提示,密钥手输,主机/端口按回车采用默认
|
|
64
|
+
```
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
CLI is generic across MUC deployments — your MUC admin provides the
|
|
48
|
-
tenant-specific values.
|
|
66
|
+
校验:
|
|
49
67
|
|
|
50
68
|
```bash
|
|
51
|
-
muc init
|
|
69
|
+
muc init --check --json # exit 0=ok, 6=missing, 7=invalid
|
|
70
|
+
muc init --show # 仅显示打码后的指纹(不会回显原值)
|
|
52
71
|
```
|
|
53
72
|
|
|
54
|
-
|
|
73
|
+
> 这些值是租户级密钥,**绝不要复制到 npm 包、Skill 包或任何公开渠道**。向你的
|
|
74
|
+
> MUC 部署管理员索取,并只通过私有渠道传递。
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|---|---|---|
|
|
58
|
-
| `appKey` | admin | 8 hex chars |
|
|
59
|
-
| `appId` | admin | 24 hex chars |
|
|
60
|
-
| `signSecretRest` | admin | secret for the regular-API signing scheme |
|
|
61
|
-
| `signSecretSecure` | admin | secret for the `/contacts/secure/...` signing scheme |
|
|
62
|
-
| `pwdDesKey` | admin (optional) | DES-CBC key for password encryption; defaults to `appKey` |
|
|
63
|
-
| `restHost` | default `https://muc.ceair.com/` | press enter to accept |
|
|
64
|
-
| `ssoHost` | default `https://store.ceair.com/` | reserved (advanced) |
|
|
65
|
-
| `imHost` / `imPort` | default `muc.ceair.com` / `8101` | TCP chat channel |
|
|
66
|
-
| `fileHost` / `filePort` | default `muc.ceair.com` / `6101` | TCP file channel |
|
|
76
|
+
---
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
`appKey`, `appId`, or signing secrets.
|
|
78
|
+
## 安装 CLI
|
|
70
79
|
|
|
71
|
-
|
|
80
|
+
环境: Node ≥ 18
|
|
72
81
|
|
|
73
|
-
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @mu-cabin/muc-cli
|
|
84
|
+
muc --version
|
|
85
|
+
```
|
|
74
86
|
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
### 首次配置(一次性)
|
|
88
|
+
|
|
89
|
+
CLI 没有内置可用的租户密钥,必须先用 `muc init` 写入。值见上面 "MUC 租户配置" 表:
|
|
77
90
|
|
|
78
91
|
```bash
|
|
79
|
-
# Flag form
|
|
80
92
|
muc init --no-interactive \
|
|
81
|
-
--app-key
|
|
82
|
-
--app-id
|
|
83
|
-
--sign-secret-rest
|
|
84
|
-
--sign-secret-secure
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# Env-var form
|
|
88
|
-
MUC_APP_KEY="$APP_KEY" \
|
|
89
|
-
MUC_APP_ID="$APP_ID" \
|
|
90
|
-
MUC_SIGN_SECRET_REST="$SIGN_SECRET_REST" \
|
|
91
|
-
MUC_SIGN_SECRET_SECURE="$SIGN_SECRET_SECURE" \
|
|
92
|
-
muc init --no-interactive
|
|
93
|
+
--app-key <APP_KEY> \
|
|
94
|
+
--app-id <APP_ID> \
|
|
95
|
+
--sign-secret-rest '<SIGN_SECRET_REST>' \
|
|
96
|
+
--sign-secret-secure '<SIGN_SECRET_SECURE>'
|
|
97
|
+
|
|
98
|
+
muc init --check # 应输出 ok
|
|
93
99
|
```
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
`MUC_SIGN_SECRET_SECURE`, `MUC_PWD_DES_KEY`, `MUC_REST_HOST`, `MUC_SSO_HOST`,
|
|
97
|
-
`MUC_IM_HOST`, `MUC_IM_PORT`, `MUC_FILE_HOST`, `MUC_FILE_PORT`.
|
|
101
|
+
### 首次登录
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
> prefer the **interactive** prompt or **flag-based** invocation — you can
|
|
104
|
-
> protect the flag values with secret-manager retrieval that never touches
|
|
105
|
-
> the env.
|
|
103
|
+
```bash
|
|
104
|
+
muc login --account ALICE --password '<你的密码>'
|
|
105
|
+
muc whoami
|
|
106
|
+
```
|
|
106
107
|
|
|
107
|
-
|
|
108
|
+
登录成功后凭证写入 `~/.muc/credentials.json`(权限 600),有效期约 7 天;`tokenPwd`(30 天)可用于静默续登:
|
|
108
109
|
|
|
109
110
|
```bash
|
|
110
|
-
muc
|
|
111
|
-
muc init --check --json # same, machine-readable
|
|
112
|
-
muc init --show # print config (secrets always redacted)
|
|
113
|
-
muc init --show --json # JSON envelope — secrets are also redacted here
|
|
114
|
-
# (read ~/.muc/config.json directly for raw values)
|
|
115
|
-
muc init --reset --yes # delete ~/.muc/config.json
|
|
111
|
+
muc login --token-pwd # 无需密码,直接续登
|
|
116
112
|
```
|
|
117
113
|
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 安装并使用 Agent Code Skill
|
|
120
117
|
|
|
121
|
-
|
|
118
|
+
Skill 注册之后,你可以直接用自然语言驱动 `muc`,不用记命令格式。
|
|
122
119
|
|
|
123
|
-
|
|
124
|
-
for a password. Pass it via flag, stdin, env var, or `--token-pwd` (reuse
|
|
125
|
-
the saved tokenPwd).
|
|
120
|
+
### 安装 Skill
|
|
126
121
|
|
|
127
122
|
```bash
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
npx skills add <everything-cli 仓库地址>/packages/muc/skills -y -g
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
注册后 Agent Code 会自动识别 muc 相关请求并调用对应命令。
|
|
130
127
|
|
|
131
|
-
|
|
132
|
-
printf '%s' "$MY_PWD" | muc login --account WANGLULU8 --password-stdin
|
|
128
|
+
### 对 Agent 说什么
|
|
133
129
|
|
|
134
|
-
|
|
135
|
-
muc login --token-pwd
|
|
130
|
+
以下这些说法都会触发 muc-cli Skill:
|
|
136
131
|
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
```
|
|
133
|
+
"把今天的周报发给 张三"
|
|
134
|
+
"拉一下 王五 本周的聊天记录"
|
|
135
|
+
"列一下我在 MUC 的群"
|
|
136
|
+
"帮我搜一下 MUC 上叫 李四 的人"
|
|
137
|
+
"IT 值班群发个通知:今晚 22:00 有计划性维护"
|
|
138
|
+
"把 muc 上刚才发的消息撤回"
|
|
139
|
+
"下载一下 <mid> 这条消息里的附件"
|
|
139
140
|
```
|
|
140
141
|
|
|
141
|
-
|
|
142
|
-
to `$MUC_ACCOUNT` or the previously-saved uid if `--account` is omitted.
|
|
143
|
-
- One of `--password` / `--password-stdin` / `--token-pwd` / `$MUC_PASSWORD`
|
|
144
|
-
is required — running `muc login` with no creds fails fast with
|
|
145
|
-
`AUTH_REQUIRED` (exit 3).
|
|
146
|
-
- The password is encrypted client-side (DES-CBC) before being sent — same
|
|
147
|
-
scheme the desktop client uses.
|
|
148
|
-
- A successful login saves to `~/.muc/credentials.json` (mode `600`):
|
|
149
|
-
`accessToken` (≈7 day TTL) and `tokenPwd` (≈30 day TTL, used for silent
|
|
150
|
-
re-login with `--token-pwd`).
|
|
151
|
-
- A stable per-CLI device id is generated at `~/.muc/device-id` on first
|
|
152
|
-
run. It is intentionally **different** from the desktop's machine-id so
|
|
153
|
-
REST sessions stay independent.
|
|
154
|
-
|
|
155
|
-
## Output contract
|
|
156
|
-
|
|
157
|
-
- **Default:** human-readable plain text on stdout, errors on stderr in the
|
|
158
|
-
form `error: <msg>` / `hint: <hint>` / `code: <code> (exit <n>)`.
|
|
159
|
-
- **`--json`** (anywhere on the command line): every command emits a single
|
|
160
|
-
stable JSON envelope on stdout — `{ok:true, schema_version:1, data}` or
|
|
161
|
-
`{ok:false, schema_version:1, code, msg, hint?}` — and stderr stays
|
|
162
|
-
silent. Agents and scripts should always pass `--json`.
|
|
163
|
-
- **Exit codes** are typed and identical in both modes: `0` success, `1`
|
|
164
|
-
internal bug, `2` usage, `3` auth required / expired, `4` not found, `5`
|
|
165
|
-
remote / network error, `6` config missing, `7` config invalid.
|
|
166
|
-
- `--help` / `--version` are human escape hatches and bypass the JSON
|
|
167
|
-
envelope by design. The canonical agent surface is `muc manifest --json`.
|
|
168
|
-
|
|
169
|
-
## Commands
|
|
170
|
-
|
|
171
|
-
### Setup
|
|
172
|
-
|
|
173
|
-
| Command | What it does |
|
|
174
|
-
|---|---|
|
|
175
|
-
| `muc init` | Seed / inspect / reset tenant config (`~/.muc/config.json`). Run before `login`. See [First-time setup](#first-time-setup). |
|
|
142
|
+
### Skill 的行为规则
|
|
176
143
|
|
|
177
|
-
|
|
144
|
+
- **首次 TCP 命令前**:Skill 会弹 `AskUserQuestion` 提示槽位风险,等你确认后再执行。
|
|
145
|
+
- **不确定发给谁**:先用 `muc search` 缩小候选名单,通过 `AskUserQuestion` 让你选,不会猜。
|
|
146
|
+
- **非自身目标**:必须经过你显式确认,不会偷偷给真实联系人发消息。
|
|
147
|
+
- **token 过期**:自动用 `--token-pwd` 静默续登,续登失败才要求你手动 `muc login`。
|
|
178
148
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
149
|
+
### Agent 场景示例
|
|
150
|
+
|
|
151
|
+
MUC Skill 的价值在于嵌入更大的 agent 工作流——先让 agent 完成主任务,再用 MUC 传递结果或读取上下文。
|
|
152
|
+
|
|
153
|
+
**跑测试 → 失败通知值班群**
|
|
154
|
+
> 帮我跑一下单测,如果有失败把结果发到 IT 值班群
|
|
155
|
+
|
|
156
|
+
Agent 跑完测试、整理失败摘要,再通过 MUC 推送到群里。MUC 是"结果出口"。
|
|
157
|
+
|
|
158
|
+
**Code Review → 通知作者**
|
|
159
|
+
> 帮我 review 这个 PR,review 完把结论发给作者
|
|
160
|
+
|
|
161
|
+
Agent 分析 diff、生成意见,从 git log 拿到作者,搜出对应 MUC 账号后发消息。
|
|
162
|
+
|
|
163
|
+
**读群聊上下文 → 代为回复**
|
|
164
|
+
> IT 值班群今天在讨论什么?帮我接着回复,说为什么要用 Redis 而不是本地缓存
|
|
165
|
+
|
|
166
|
+
Agent 拉取今日群消息,理解讨论脉络,起草回复并等你确认后发出。MUC 历史是**输入上下文**。
|
|
167
|
+
|
|
168
|
+
**分析日志 → 发文件给同事**
|
|
169
|
+
> 帮我分析 logs/access.log,生成访问量报告发给 王五
|
|
170
|
+
|
|
171
|
+
Agent 统计 PV/UV、Top 路径、错误率,写成报告文件,搜出收件人后 `muc send-file` 发出。
|
|
172
|
+
|
|
173
|
+
**读 MUC 需求 → 生成代码骨架**
|
|
174
|
+
> 看看 王五 昨天发给我的需求,整理成 TODO 并创建对应的函数骨架
|
|
175
|
+
|
|
176
|
+
Agent 拉取消息、提取功能点、在项目里生成文件,最后用 MUC 回复确认。MUC 历史是**任务来源**。
|
|
177
|
+
|
|
178
|
+
**定时周报(配合 `/schedule`)**
|
|
179
|
+
> /schedule 每周五 17:00 帮我把本周 git 提交整理成周报发给上级
|
|
180
|
+
|
|
181
|
+
Agent 定时触发,跑 `git log`、整理自然语言周报、确认收件人、发送。
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## cli 命令速查
|
|
186
|
+
|
|
187
|
+
### 查人 / 查组织
|
|
203
188
|
|
|
204
189
|
```bash
|
|
205
|
-
muc
|
|
206
|
-
muc
|
|
207
|
-
muc
|
|
190
|
+
muc search 李四 # 关键字搜员工
|
|
191
|
+
muc search-dept "信息技术部" # 按部门搜(含员工数 + 层级路径)
|
|
192
|
+
muc search-app "审批" # 搜应用/小程序
|
|
193
|
+
muc whois BOB # 单人完整档案
|
|
194
|
+
muc groups # 我的星标群 + 部门群
|
|
195
|
+
muc search-team "值班" --enrich # 查已加入群(TCP)
|
|
196
|
+
muc team-members 9009876543210000 --profiles # 查群成员 + 部门/岗位(TCP + REST)
|
|
208
197
|
```
|
|
209
198
|
|
|
210
|
-
###
|
|
199
|
+
### 聊天历史
|
|
211
200
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
tell automated traffic from a typed message. The check is idempotent —
|
|
236
|
-
if your text already ends with the resolved tail, it is not appended a
|
|
237
|
-
second time. Customise it with the
|
|
238
|
-
`messageTail` field in `~/.muc/config.json` — set to a non-empty string to
|
|
239
|
-
override, or to `""` to disable entirely. You can also use
|
|
240
|
-
`muc init --message-tail "<custom>"` / `muc init --no-message-tail` to
|
|
241
|
-
write the value, and per-call flags `muc send --tail "<one-off>"` /
|
|
242
|
-
`muc send --no-tail` to override on a single send. Only `muc send`
|
|
243
|
-
(plain-text) is affected; `send-file` / `send-image` / `send-voice` are
|
|
244
|
-
not.
|
|
201
|
+
```bash
|
|
202
|
+
muc history --peer WANGWU --days 7 --limit 200
|
|
203
|
+
muc history --team 9009876543210000 --days 30 --json | jq '.data.messages[]'
|
|
204
|
+
muc history --to-self --days 1
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 发消息
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
muc send --to-self "hello from CLI" # 发给自己(安全测试)
|
|
211
|
+
muc send --peer BOB "明天上午有空吗?" --yes-not-self
|
|
212
|
+
muc send --team 9009876543210000 "值班通知" --yes-not-self
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 发文件 / 图片 / 语音
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
muc send-file ./dist/release.dmg --peer QA_LEAD --yes-not-self
|
|
219
|
+
muc send-image ~/Desktop/screenshot.png --to-self # 自动探测宽高
|
|
220
|
+
muc send-voice ./recording.amr --duration 3500 --to-self # duration 单位 ms
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 下载 / 撤回
|
|
245
224
|
|
|
246
225
|
```bash
|
|
247
|
-
muc
|
|
248
|
-
muc
|
|
249
|
-
muc send --peer ZHANG_W2 "ping" --yes-not-self
|
|
250
|
-
muc send --team 9009876543210000 "team message" --yes-not-self
|
|
251
|
-
|
|
252
|
-
muc send-file ./report.pdf --to-self # self test
|
|
253
|
-
muc send-image ./screenshot.png --peer ZHANG_W2 --yes-not-self # auto width/height
|
|
254
|
-
muc send-voice ./clip.amr --duration 3500 --to-self # 3.5 s clip
|
|
255
|
-
|
|
256
|
-
muc download --file-key /chat/m/WANGLULU8/.../<md5> --out ./got.bin # by explicit key
|
|
257
|
-
muc download --mid 69ef1ae07e5462c465c05e00 --to-self # look up body via roaming
|
|
258
|
-
muc download --mid <MID> --peer YANWENYU --out ./inbox/ # save into a directory
|
|
226
|
+
muc download --mid <mid> --to-self --out ./got.bin # 通过消息 ID 下载附件
|
|
227
|
+
muc withdraw --mid <mid> --to-self # 撤回自己发出的消息
|
|
259
228
|
```
|
|
260
229
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
230
|
+
> 任何命令加 `--json` 输出稳定的机器可读信封:成功 `{ok:true, data}` / 失败 `{ok:false, code, msg}`。
|
|
231
|
+
> 退出码:`0` 成功 / `2` 用法错误 / `3` 鉴权 / `4` 未找到 / `5` 远端或网络 / `1` 内部错误。
|
|
232
|
+
|
|
233
|
+
---
|
|
264
234
|
|
|
265
|
-
##
|
|
235
|
+
## 和桌面端 / 手机端共存
|
|
266
236
|
|
|
267
|
-
|
|
268
|
-
server allows concurrent `accessToken`s. `whoami`, `search`, `search-dept`,
|
|
269
|
-
`search-app`, `search-sno`, `history`, `whois`, `groups`, `emoticons`, and
|
|
270
|
-
`download` are REST-only (or 6101-only, in `download`'s case) and safe to
|
|
271
|
-
run anytime.
|
|
237
|
+
REST 命令(`search`、`history`、`whois`、`groups` 等)**永远可以共存**,与桌面端、手机端同时在线互不影响。
|
|
272
238
|
|
|
273
|
-
|
|
274
|
-
`send-image`, `send-voice`, `withdraw`, `clear-session`) open a TCP-8101
|
|
275
|
-
session and share a per-user **two-slot** model with real devices:
|
|
239
|
+
聊天通道命令(`send*`、`withdraw`、`sync`、`search-team`、`team-members`)受 MUC **单点登录**规则约束:每个账号在 **PC 端**和**移动端**各只允许**一个**在线设备,同一端登第二个会把第一个挤下线(和"在另一台 Mac 上登 MUC 就把当前这台顶掉"是一回事)。CLI 通过 `--os` 决定自己算哪一端:
|
|
276
240
|
|
|
277
|
-
|
|
|
241
|
+
| 算作哪端 | 对应的 `--os` 取值 |
|
|
278
242
|
|---|---|
|
|
279
|
-
| PC | `Windows
|
|
280
|
-
|
|
|
243
|
+
| PC 端 | `Windows` / `OS X` / `Mac`(Mac 桌面端登录时上报的是 `OS X`) |
|
|
244
|
+
| 移动端 | `iOS`(CLI 默认)/ `Android` |
|
|
281
245
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
246
|
+
> ⚠️ **默认发送消息会使移动端下线,谨慎使用。** CLI 默认 `--os iOS`,算"移动端"。
|
|
247
|
+
> 只要跑了 `send` / `withdraw` 等聊天通道命令,**正在登录 MUC 的 iPhone 会被立刻挤下线**
|
|
248
|
+
> (`accessToken` 不失效,但要重新打开 App 才能继续收实时消息)。
|
|
249
|
+
>
|
|
250
|
+
> - 测试或跑通流程时,先用 `muc send --to-self ...` 发给自己。
|
|
251
|
+
> - 真要 `--peer` / `--team` 发出去之前,确认**没人在等 iPhone 上 MUC 的实时消息**。
|
|
252
|
+
> - 如果手机 MUC 必须保持在线,**整段流程改用 REST 命令**(`history`、`search`、`groups`…),别碰聊天通道。
|
|
253
|
+
> - **不要**显式传 `--os Windows / OS X / Mac`——那会把 Mac 桌面端 MUC 也顶下去。
|
|
286
254
|
|
|
287
|
-
|
|
288
|
-
iPhone is also signed in, both slots are taken and any TCP command will
|
|
289
|
-
kick one of them — fall back to REST-only commands.
|
|
255
|
+
`muc tcp-ping` 只做 TCP 连接和 NEGOTIATE,**不发登录帧**,不占任何在线名额,纯连通性测试,可以随时跑。
|
|
290
256
|
|
|
291
|
-
|
|
292
|
-
kick anything. Run it first to confirm the wire protocol is happy on your
|
|
293
|
-
network.
|
|
257
|
+
---
|
|
294
258
|
|
|
295
|
-
|
|
296
|
-
app to recover — tokens stay valid.
|
|
259
|
+
## 开发者指南
|
|
297
260
|
|
|
298
|
-
|
|
261
|
+
### 从源码运行
|
|
299
262
|
|
|
300
263
|
```bash
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
accessTokenExpireAt: 1745678340000
|
|
307
|
-
tokenPwdRefreshed: true
|
|
308
|
-
tokenPwdExpireAt: 1748097540000
|
|
309
|
-
|
|
310
|
-
$ muc whoami
|
|
311
|
-
uid: WANGLULU8
|
|
312
|
-
empId: 5394483846707200
|
|
313
|
-
name: 王璐璐
|
|
314
|
-
deviceId: 8e413b4141…
|
|
315
|
-
deviceName: WANGLULU8-mbp.local (muc-cli)
|
|
316
|
-
accessToken: TV5l…u9kQ (redacted; use --json for raw)
|
|
317
|
-
accessTokenExpireAt: 1745678340000
|
|
318
|
-
tokenPwdSet: true
|
|
319
|
-
tokenPwdExpireAt: 1748097540000
|
|
320
|
-
savedAt: 1745073540000
|
|
321
|
-
credentialsPath: ~/.muc/credentials.json
|
|
322
|
-
|
|
323
|
-
$ muc search 张
|
|
324
|
-
ZHANG_W2 张伟 飞行部 / 机长室
|
|
325
|
-
ZHANGSAN03 张三 地面服务部
|
|
326
|
-
…
|
|
327
|
-
|
|
328
|
-
$ muc whois ZHANG_W2
|
|
329
|
-
uid ZHANG_W2
|
|
330
|
-
name 张伟
|
|
331
|
-
empId 4892173049281024
|
|
332
|
-
mobile 1380013…
|
|
333
|
-
email zhang.wei@ceair.com
|
|
334
|
-
dept 飞行部 / 机长室
|
|
335
|
-
title 机长
|
|
336
|
-
|
|
337
|
-
$ muc groups
|
|
338
|
-
starred:
|
|
339
|
-
[常用] (3)
|
|
340
|
-
9001234567890123 IT 值班群
|
|
341
|
-
9001234567890124 运行联络
|
|
342
|
-
9001234567890125 部门通知
|
|
343
|
-
dept groups: 1
|
|
344
|
-
9009876543210000 飞行部 / 机长室
|
|
345
|
-
|
|
346
|
-
$ muc emoticons
|
|
347
|
-
1001 默认表情包 (32)
|
|
348
|
-
1042 航空主题 (18)
|
|
264
|
+
git clone <repo> everything-cli && cd everything-cli
|
|
265
|
+
pnpm install # 工作区依赖装在仓库根
|
|
266
|
+
cd packages/muc
|
|
267
|
+
pnpm run typecheck # tsc --noEmit,必须先过
|
|
268
|
+
./bin/muc <command> # 直接走 tsx 跑 src/,零构建
|
|
349
269
|
```
|
|
350
270
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
-
|
|
409
|
-
secrets and `appKey` / `appId` you supplied to `muc init` against the
|
|
410
|
-
values your MUC admin provided. `muc init --show` (secrets redacted) lets
|
|
411
|
-
you confirm what's currently saved; `muc init` (interactive) lets you
|
|
412
|
-
re-enter the values.
|
|
413
|
-
- `error: not logged in` (exit 3, code `AUTH_REQUIRED`) — the saved
|
|
414
|
-
credentials file is missing or unreadable. Check `~/.muc/credentials.json`
|
|
415
|
-
and re-run `muc login`.
|
|
416
|
-
- `code: AUTH_EXPIRED` (exit 3) — accessToken or tokenPwd was rejected by
|
|
417
|
-
the server. Re-run `muc login --token-pwd` (or full `muc login` if
|
|
418
|
-
`tokenPwd` is also stale).
|
|
419
|
-
- `EPROTO` / TLS errors — corporate proxy or VPN intercepting traffic.
|
|
420
|
-
`muc-cli` does not pin certificates, so adding the proxy CA to your Node
|
|
421
|
-
trust store should suffice (`NODE_EXTRA_CA_CERTS=/path/to/ca.pem`).
|
|
422
|
-
- A TCP send kicks your desktop off the IM panel — the CLI's `--os` value
|
|
423
|
-
collided with the desktop's slot. See [Coexistence](#coexistence) above:
|
|
424
|
-
default `--os iOS` only risks the Mobile slot (your iPhone), not the
|
|
425
|
-
desktop. If both desktop and phone are online, drop to REST-only
|
|
426
|
-
commands.
|
|
427
|
-
|
|
428
|
-
### Exit-code summary
|
|
429
|
-
|
|
430
|
-
| Exit | Code |
|
|
431
|
-
|---|---|
|
|
432
|
-
| 0 | success |
|
|
433
|
-
| 1 | INTERNAL |
|
|
434
|
-
| 2 | USAGE |
|
|
435
|
-
| 3 | AUTH_REQUIRED, AUTH_EXPIRED |
|
|
436
|
-
| 4 | NOT_FOUND |
|
|
437
|
-
| 5 | REMOTE_ERROR, NETWORK, TIMEOUT, KICKED |
|
|
438
|
-
| 6 | CONFIG_MISSING |
|
|
439
|
-
| 7 | CONFIG_INVALID |
|
|
440
|
-
|
|
441
|
-
## Security
|
|
442
|
-
|
|
443
|
-
- Both files in `~/.muc/` are written with mode `600`. **Don't** check them
|
|
444
|
-
into git or copy them to shared machines.
|
|
445
|
-
- **Don't share `~/.muc/config.json`** — it contains your tenant's signing
|
|
446
|
-
secrets (`signSecretRest`, `signSecretSecure`, `pwdDesKey`, `appKey`).
|
|
447
|
-
Anyone with these can impersonate API calls against your MUC tenant.
|
|
448
|
-
- `MUC_PASSWORD` ends up in shell history; prefer `--password-stdin` or
|
|
449
|
-
`--token-pwd` for refreshes.
|
|
450
|
-
- **Prefer interactive `muc init` over env vars.** Environment variables
|
|
451
|
-
leak through shell history and `/proc/<pid>/environ` to other processes
|
|
452
|
-
on the same machine. Use the interactive prompt or one-shot flags pulled
|
|
453
|
-
from a secret manager rather than persistent `MUC_*` exports.
|
|
454
|
-
- TCP login over 8101 registers a device session in one of two slots per
|
|
455
|
-
user (PC or Mobile). A second login in the same slot kicks the first.
|
|
456
|
-
Default `--os iOS` keeps the CLI on the Mobile slot; only your iPhone is
|
|
457
|
-
ever at risk.
|
|
458
|
-
- `tcp-ping` is the only chat-channel command that cannot kick anything —
|
|
459
|
-
use it as a network smoke-test before trying TCP sends.
|
|
271
|
+
### 仓库结构
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
packages/muc/ (everything-cli 工作区中的一个包)
|
|
275
|
+
├── src/index.ts 命令分发器
|
|
276
|
+
├── src/commands/*.ts 每个子命令一个文件
|
|
277
|
+
├── src/lib/ 协议层:wire.ts / chat.ts / sign.ts / …
|
|
278
|
+
├── src/assistant/ auto-reply 守护进程 + 各 backend
|
|
279
|
+
├── skills/ muc-* Agent Skills(muc-message / muc-chat / muc-shared / …)
|
|
280
|
+
├── scripts/build.mjs esbuild 打包脚本(→ dist/muc.mjs)
|
|
281
|
+
├── bin/muc tsx 入口(零构建直接跑 src/)
|
|
282
|
+
├── README.md 本文件
|
|
283
|
+
└── REFERENCE.md 完整命令 / 协议参考
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
> 协议研究文档与抓包脚本保留在内部源码研究仓库,未随本包导入;下文"协议抓包 /
|
|
287
|
+
> 改动后测试 / 协议层参考"小节中对它们的引用均指内部仓库。
|
|
288
|
+
|
|
289
|
+
### 协议抓包:通过 Surge.app
|
|
290
|
+
|
|
291
|
+
不用切系统代理、不用安装额外 CA —— Surge.app 已在本机运行即可。
|
|
292
|
+
|
|
293
|
+
**一次性配置**:在 Surge UI 里把你的 MUC 主机(如 `*.example.com`)加进 MITM hostname,打开 MITM + Capture + HTTP API。
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# 抓 60 秒的 muc HTTP/S 流量,输出 NDJSON
|
|
297
|
+
python3 surge_capture.py --key <surge-http-api-key> --process MUC --duration 60 > flows.ndjson
|
|
298
|
+
|
|
299
|
+
# 聚合成 API 地图(人读)
|
|
300
|
+
python3 analyze_api.py flows.ndjson
|
|
301
|
+
|
|
302
|
+
# 机器读
|
|
303
|
+
python3 analyze_api.py flows.ndjson --json
|
|
304
|
+
|
|
305
|
+
# 只看某个主机
|
|
306
|
+
python3 analyze_api.py flows.ndjson --host muc.example.com
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
> 如果 Surge 配置了 `http-api-tls = true`,用 `https://127.0.0.1:6171` + 关闭 SSL 验证访问,或直接去掉该配置项。
|
|
310
|
+
|
|
311
|
+
### 改动后测试流程
|
|
312
|
+
|
|
313
|
+
1. `pnpm run typecheck`(在 `packages/muc` 下)— 先过类型检查。
|
|
314
|
+
2. 按内部 `TEST_CASES.md` 从头到尾跑一遍(§1 REST 读 + §2 `tcp-ping` 无条件跑;Mac 桌面 + iPhone 同时在线时跳过 §3 §4)。
|
|
315
|
+
3. 任何一项失败:把 `--json` 原始信封贴给用户,停下来,不要"修一修再跑"。
|
|
316
|
+
|
|
317
|
+
### 协议层参考(内部文档)
|
|
318
|
+
|
|
319
|
+
- `HANDOFF.md` — 当前状态、已验证里程碑、常量(hosts / 密钥 / transport AES key)、关键算法的踩坑笔记。
|
|
320
|
+
- `MUC_API.md` — REST 端点全图(`/muc /imm /msm /contacts /mam /...`)+ TCP 8101 帧规范 + 6101 文件通道。
|
|
321
|
+
- `API_CLIENT.md` — 从解包客户端摘出的全量 API 目录,找 CLI 还没封装的端点去这里翻。
|
|
322
|
+
|
|
323
|
+
### 红线
|
|
324
|
+
|
|
325
|
+
- **绝不入库** `accessToken`、`tokenPwd`、明文密码、`clientSecret`、`pfxPass`、`bsSecretKey`、`encrypt_key`,以及租户密钥(`APP_KEY` / `sign secrets`)。
|
|
326
|
+
- **CLI 默认会顶掉同账号的 iPhone 端 MUC**(默认 `--os iOS`,单点登录规则);显式传 PC 类 `--os` 会顶 Mac 桌面端;桌面 + 手机都需要保持在线时,整段流程退到 REST 命令。
|
|
327
|
+
- **CLI 发的消息所有参与方都可见。** 非自身目标必须带 `--yes-not-self`,先用 `--to-self` 测。
|
|
328
|
+
- **不要擅自改 Surge 配置文件**(`~/Library/Application Support/Surge/Profiles/*.conf`)。要加 MITM hostname 让用户在 Surge UI 里加。
|