wezard 2.2.0 → 2.2.2

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 CHANGED
@@ -4,7 +4,10 @@
4
4
 
5
5
  <h1>wezard</h1>
6
6
 
7
- <p><b>把 AI 编程 Agent 装进企业微信。</b><br/>在地铁上、被窝里、开会摸鱼时,照样能跟你电脑上的 Agent 干活。</p>
7
+ <p><b>在企业微信里远程操控本机的 AI 编程 Agent,并让多个 Agent 互相感知、协同干活。</b></p>
8
+
9
+ <p>地铁上发一句话,电脑上的 Agent 就开始干:每次工具调用推一张审批卡等你点,回复、工具调用、思考过程实时回到聊天,回到电脑前 <code>tmux attach</code> 接着干。<br/>
10
+ 一个聊天里住着多个 <b>wizard</b>——全局唯一的 <code>.name</code>、各自的职责与记忆,彼此看得见也叫得动。没点名的话落到管家,由它判断转给对口的那个还是新起一个;派出去的活不必守着等,对方干完结论自动回到发话方。</p>
8
11
 
9
12
  <p>
10
13
  <a href="https://www.npmjs.com/package/wezard"><img src="https://img.shields.io/npm/v/wezard?style=flat-square&color=07C160&label=npm" alt="npm version" /></a>
@@ -19,25 +22,23 @@
19
22
 
20
23
  ![demo](images/demo.png)
21
24
 
22
- | 功能<img width="160"> | 说明 |
23
- | --- | --- |
24
- | 🛎 **远程审批** | Agent 要跑 `Bash` / `Edit` 时,审批卡片直推 IM:`✅` 放行一次、`⏱` 一段时间内自动放行、`✅总是` 记成规则、`❌` 拒绝。危险操作(`rm` / 强推 / `DROP` / 敏感路径)每次都要单独确认。 |
25
- | 📋 **计划审批** | Agent 做完计划时,摘要和审批卡推到 IM:`✅同意` 开始执行,`✏️继续改` 接着完善。Agent 提的选择题也会变成投票卡。 |
26
- | 🪞 **会话镜像** | 电脑上 Agent 的回复、工具调用、思考过程实时同步到企业微信;IM 里发的消息原样落进 CLI 输入框。回到电脑前 `tmux attach -t wezard` 接着干,对话一字不少。 |
27
- | 🖼 **图片直贴** | 在企业微信里发图,Agent 直接当贴图处理。 |
28
- | 🔍 **详情页** | 每次工具调用 / 审批请求都有详情页,IM 里点链接看完整 input / result / git diff。 |
29
- | 📡 **主动汇报** | Agent 可以主动给你发消息、发卡片、向你提问。 |
30
- | 📄 **文档读写** | Agent 直接新建企业微信在线文档、写 Markdown、读文档链接、操作智能表格。 |
31
- | 🗂 **多会话** | 列出本机所有在跑的会话、切换 IM 镜像到哪一个、在指定目录新开会话。每个会话有一枚固定的 emoji,审批卡和回复一眼区分。 |
32
- | 🧙 **多 wizard 协同** | 每个会话是一个有名字的 wizard,写作 `.name`,在任何群里都叫得到;有职责、有记忆,能分身、能互相派活——派完就放手,对方干完结论自动送回,把一件大活拆成几路并行做完。 |
33
- | 🪪 **rolepage** | 每个 wizard 视角下的 IM:`⌘K` 搜遍 role / 会话 / 消息,关系图看清谁和谁对过话,用量条一眼看出模型、轮次、上下文与 token 花在哪。 |
34
- | ⏰ **定时任务** | 「每个工作日晚上 9:30 跑一遍回归」——到点自动起一个 wizard 去干,结果发回群里。 |
35
- | 🔄 **重启即续** | 电脑重启 / tmux 关了 / daemon 崩了都不掉档:下一条 IM 消息自动把会话拉起来,历史完整继承。 |
25
+ 1. 🪞 **远程控制本机 Agent CLI** — 企业微信里发的消息原样落进 CLI 输入框;Agent 的回复、工具调用、思考过程实时同步回聊天。回到电脑前 `tmux attach -t wezard` 接着干,对话一字不少。支持 `claude` / `claude-internal` / `codebuddy`。
26
+ 2. 🛎 **远程审批** — Agent 要跑 `Bash` / `Edit` 时审批卡直推 IM:`✅` 放行一次、`⏱` 一段时间内自动放行、`✅总是` 记成规则、`❌` 拒绝。危险操作(`rm` / 强推 / `DROP` / 敏感路径)每次都要单独确认;做完计划推计划卡(`✅同意` / `✏️继续改`),Agent 提的选择题变成投票卡。
27
+ 3. 🧙 **多 wizard** — 每个会话是一个有名字的 wizard,写作 `.name`,全局唯一,在任何群里都叫得到;有职责、有记忆,看得见彼此在干什么。克隆一个分身让它继承当前上下文,或者从白板新起一个。
28
+ 4. 🎩 **管家分派** — 没点名的话落到聊天的默认 wizard:一两句能答完的它自己答,其余判断转给对口的那个还是新起一个。转交是公开的,被转到的那个直接在群里回你。
29
+ 5. 📮 **派完就放手** — wizard 之间派活不必守着等:对方那一轮一结束,守护进程把它的结论作为新的一轮自动送回发话方。
30
+ 6. 🧠 **三层记忆** — 自己的、本群共享的、本工作区共享的。「这个仓库 reload 要先 build」这类约定写一次,之后每个新 wizard 开局就知道;共享的两层由一个定时整理者去重合并。
31
+ 7. 🪪 **rolepage** — 每个 wizard 视角下的 IM:`⌘K` 搜遍 role / 会话 / 消息,关系图看清谁和谁对过话,用量条一眼看出模型、轮次、上下文与 token 花在哪。
32
+ 8. ⏰ **定时任务** — 「每个工作日晚上 9:30 跑一遍回归」,到点自动起一个 wizard 去干,结果发回群里。任务本身是一个可以直接编辑的 `.mjs` 文件,存盘即生效。
33
+ 9. 🔍 **详情页与主动汇报** — 每次工具调用、审批请求都有详情页,IM 里点链接看完整 input / result / git diff;Agent 也能主动把一段话贴进任意一个群。
34
+ 10. 📄 **企业微信文档** — 新建在线文档、写 Markdown、读文档链接、操作智能表格。
35
+ 11. 🔄 **重启即续** — 电脑重启 / tmux 关了 / daemon 崩了都不掉档:下一条 IM 消息自动把会话拉起来,历史完整继承。
36
36
 
37
37
  <details>
38
38
  <summary><b>目录</b></summary>
39
39
 
40
40
  - [快速开始](#快速开始)
41
+ - [双向镜像](#双向镜像)
41
42
  - [多 wizard 协同](#多-wizard-协同)
42
43
  - [任务编排](#任务编排)
43
44
  - [rolepage](#rolepage)
@@ -88,11 +89,23 @@ wezard init
88
89
 
89
90
  ---
90
91
 
92
+ ## 双向镜像
93
+
94
+ 左边是 tmux 里的 CLI,右边是企业微信里的同一段对话。
95
+
96
+ ![tmux 与企业微信双向镜像](images/mirror.png)
97
+
98
+ - **IM → CLI**:企业微信里发的消息由守护进程 `tmux paste-buffer` 进 CLI 的输入框——这是唯一能让远程消息出现在你本机窗口里的通路,你坐回电脑前看到的,就是它替你敲的那一行。
99
+ - **CLI → IM**:Agent 的回复、工具调用、思考过程实时推回聊天。默认只推**聊天自己发起的那一轮**:你在电脑前敲出来的轮次只记进 [rolepage](#rolepage),不刷群;审批卡、投票卡和 `[mirror]` 通知不受这条限制。
100
+ - **随时接管**:`tmux attach -t wezard` 回到那个 pane 接着干,对话一字不少。
101
+
102
+ ---
103
+
91
104
  ## 多 wizard 协同
92
105
 
93
106
  一个绑定了聊天的会话叫一个 **wizard**:有自己的终端、工作区、名字和职责,知道还有谁在,也叫得动它们。名字**全局唯一**,写作 `.name`——不管它住在哪个群,在任何群里都叫得到。
94
107
 
95
- ![多会话](images/multi-session.png)
108
+ ![多 wizard 协同](images/wizards.png)
96
109
 
97
110
  **创建**
98
111
 
@@ -116,6 +129,32 @@ wezard init
116
129
 
117
130
  每条回复都带 `emoji .name` 头(emoji 固定),在群里引用它的气泡就等于跟它说话。句中的 `a.ts`、`.gitignore` 这类不会被当成名字。
118
131
 
132
+ **管家**
133
+
134
+ 每个聊天的默认 wizard 是这个群的**管家**。没点名的话都落到它这儿——它一两句能答完的(问进度、谁在干什么、闲聊)自己答;要读很多代码、改文件、跑很久的活,哪怕它自己做得了也**转出去**:它一忙,这个群里没点名的话就都排在它后面。
135
+
136
+ 转给谁由它判断:上下文里已经看得出该给谁(刚派过同一摊活的、职责对口的)就直接转;拿不准才调一张候选表——谁的职责、最近的话、读过的文件和这件活有交集,在不在同一个工作区,忙不忙,上下文多重。相关且接着用那段上下文划算就转给它;没有对口的,或对口的那个上下文已经太重,就从白板新起一个。
137
+
138
+ **转交是公开的**:群里出现一条 `.管家 → .它` 的气泡,它的回复直接发进这个群。你不用等管家转述,管家也只回一句「已转给 `.它`」。
139
+
140
+ ```mermaid
141
+ flowchart TD
142
+ msg["群里的一条消息"] --> named{"点了 .name ?"}
143
+ named -- "是" --> direct["直达那个 wizard<br/>不经过管家"]
144
+ named -- "否" --> butler["管家 (聊天的默认 wizard)"]
145
+ butler --> small{"一两句能答完 ?"}
146
+ small -- "是" --> self["自己答"]
147
+ small -- "否" --> who{"该给谁 ?"}
148
+ who -- "上下文里看得出" --> pick["选中已有的"]
149
+ who -- "拿不准" --> table["候选表<br/>职责 · 最近的话 · 读过的文件<br/>工作区 · 忙闲 · ctx"]
150
+ table --> judge{"相关, 且接着用<br/>那段上下文划算 ?"}
151
+ judge -- "是" --> pick
152
+ judge -- "否 / 没有候选" --> fresh["白板新起一个"]
153
+ pick --> relay["公开转交<br/>群里一条气泡"]
154
+ fresh --> relay
155
+ relay --> reply["它的回复直接进群"]
156
+ ```
157
+
119
158
  **名字**
120
159
 
121
160
  | wizard | 名字 |
@@ -139,13 +178,12 @@ wezard init
139
178
  | 分个身去把这三个目录都扫一遍 | 分出三个带着当前上下文的分身并行干,干完收掉 |
140
179
  | 切到 /path/to/proj | 换工作区,重开会话 |
141
180
 
142
- - **记忆分三层**:自己的、本群共享的、本工作区共享的。「这个群习惯先出方案再动手」「这个仓库 reload 要先 build」不必每来一个新 wizard 再教一遍。
181
+ - **记忆分三层**:自己的、本群共享的、本工作区共享的。「这个群习惯先出方案再动手」「这个仓库 reload 要先 build」不必每来一个新 wizard 再教一遍。共享的那两层是**提议**——一个定时的整理者去重、改写、合并后才写进去,所以不会立刻生效,也不会被几十个 wizard 越写越长。
143
182
  - **分身继承上下文**:分身开局就带着原 wizard 读过的全部材料,原 wizard 不受影响;也可以生一个白板的子 wizard,顺便换个工作区。分身还能再分身。
144
183
  - **模型可以挑**:`/new [cli] [model]`,或让它生分身时指定——要判断的给 opus,跑腿的给 haiku。
145
184
  - **派完就放手**:wizard 之间说一句就走,不守着等;对方那一轮一结束,守护进程把它的结论作为新的一轮送回发话方(约 0.2 秒内,由 CLI 自己的忙闲事件触发)。对方正忙时可以约好「等它闲下来再说」,同样是它一停下就投。
146
- - **管家分派**:交给聊天默认 wizard 的活,它先判断是派给已有的 wizard 还是新起一个——拿不准时,守护进程给它一张候选表:谁的职责、最近说的话、上下文里读过的文件和这件活对得上,忙不忙、上下文多重;末尾永远附「新起一个」。
147
185
  - **群里只留结论**:wizard 之间派活、来回默认是私聊,不刷群;生分身、收工、交接这类生命周期事件也不进群。群里只出现回给你的那条回复、通知、工单的开工 / 收工、定时任务的 ⏰,以及它们主动公开的讨论。过程想看去 [rolepage](#rolepage)。
148
- - **上下文满了自己交接**:它会写一份简报、原地重开,接着干。
186
+ - **上下文满了自己交接**:它把工作压成一份简报、原地换一个全新会话接着干,名字和职责都不变。交接那几秒里进来的话(人说的、同伴派的、回执、定时任务)一律等它重开完再送进去,一句不丢。
149
187
 
150
188
  ---
151
189
 
@@ -1,17 +1,55 @@
1
+ // 「命令词位置」前缀: 行首 / 换行 / `;` `&&` `||` `(` 之后 / 引号紧邻处 /
2
+ // 包装器命令之后 / `do` `then` `else` 之后 / `--` 参数分隔符之后。
3
+ //
4
+ // 为什么需要它: 名单是对**整条命令文本**做 test 的, 光靠 `\b` 界定的词只要在
5
+ // 任何位置出现就算命中 —— 而 `-` `/` 都是非单词字符, 于是分支名、文件名、参数值
6
+ // 里带上这些词就会让所有沾边的命令被判危险。真实案例: 分支
7
+ // `feature/graceful-shutdown` 让 `git checkout` / `git push` /
8
+ // `npm run test -- graceful-shutdown.spec.ts` 全部命中「关机/重启」必发单卡,
9
+ // 流程被审批卡堵死; 同族的 `\brm\b` 还会把 `docker run --rm` 判成删除文件。
10
+ //
11
+ // 包装器 (提权/计时/限流/改环境, 自己不干事只把后面的命令包一层跑) 是开放集合,
12
+ // 初版只列了 sudo·nohup·exec·xargs·env·time, 于是 `command rm` / `timeout 5 rm` /
13
+ // `nice rm` / `env FOO=1 rm` / `watch reboot` 全部漏报 —— 这里尽量收全, 并允许
14
+ // 包装器与命令之间隔一串参数 token。token 只认 `-` 开头的选项 / 纯数字时长 /
15
+ // `K=V` 赋值: 普通单词会打断链条, `timeout 5 rg -n sudo` 里的检索词钓不出命中。
16
+ const WRAPPERS = String.raw `sudo|doas|nohup|exec|xargs|env|time|command|builtin|timeout|nice|ionice|stdbuf|setsid|watch|caffeinate|do|then|else`;
17
+ const WRAP_ARG = String.raw `(?:-[^\s;|&]*|\d+(?:\.\d+)?[smhd]?|\w+=[^\s;|&]*)\s+`;
18
+ const CMD_HEAD = String.raw `(?:^|[\n;&|(]\s*|["'\`]\s*|\b(?:${WRAPPERS})\s+(?:${WRAP_ARG})*|--\s+)`;
19
+ // 「远程执行」上下文: 命令把动作送到别的机器/容器里跑时, 位置约束失效 ——
20
+ // `ssh host rm -rf /`、`kubectl exec pod -- halt` 里危险词前面是主机名或 `--`。
21
+ // 因为前置了 ssh / exec 才触发, 不会误伤本机的普通命令, 所以这里保持宽匹配。
22
+ const REMOTE_CTX = String.raw `\b(?:ssh|(?:kubectl|docker)\s+exec)\b[\s\S]*\b`;
23
+ /**
24
+ * 给「词本身太常见、只有出现在命令位置才危险」的规则配一对正则: 本机版带
25
+ * 命令词位置约束, 远程版在 ssh/exec 上下文里放宽。
26
+ *
27
+ * 只用于纯单词触发的规则 —— `kubectl delete`、`dd if=` 这类自带结构约束的
28
+ * 不需要, 它们的第二个 token 已经把误伤面挡住了。
29
+ */
30
+ const cmdWord = (label, words, flags = "") => [
31
+ // `\\?`: `\rm` 这种反斜杠转义 (绕开 alias 的惯用写法) 仍处于命令词位置。
32
+ [label, new RegExp(`${CMD_HEAD}\\\\?(?:${words})\\b`, flags)],
33
+ [`远程${label}`, new RegExp(`${REMOTE_CTX}(?:${words})\\b`, flags)],
34
+ ];
1
35
  // ── 内置命令名单 (Bash / 任何带 command 的工具) ────────────────────────
2
36
  const CMD_RULES = [
3
- ["删除文件 rm", /\brm\b/],
4
- ["删除目录 rmdir", /\brmdir\b/],
37
+ ...cmdWord("删除文件 rm", "rm"),
38
+ ...cmdWord("删除目录 rmdir", "rmdir"),
5
39
  ["批量删除 find -delete", /\bfind\b[\s\S]*(-delete|-exec\s+rm)\b/],
40
+ // xargs 传参形态 (`xargs -I{} rm {}`) 里 rm 前面是 `}`, 命令词位置约束够不着,
41
+ // 靠这条宽规则兜住 —— 有 xargs 前置, 同样不会误伤普通命令。
6
42
  ["管道删除 xargs rm", /\bxargs\b[\s\S]*\brm\b/],
7
- ["清空文件 truncate", /\btruncate\b/],
43
+ ...cmdWord("清空文件 truncate", "truncate"),
8
44
  ["裸设备写入 dd", /\bdd\s+(if|of)=/],
9
45
  ["格式化 mkfs", /\bmkfs\b|\bdiskutil\s+(erase|partition)/],
10
46
  ["重定向到设备", />\s*\/dev\/(?!null\b|stdout\b|stderr\b)/],
11
- ["提权 sudo", /\bsudo\b|\bsu\s+-/],
47
+ ...cmdWord("提权 sudo", "sudo"),
48
+ ["切换用户 su", /\bsu\s+-/],
12
49
  ["递归改权限", /\bch(mod|own)\b[\s\S]*(-R|\b777\b)/],
13
- ["强制杀进程", /\bkill\s+-9\b|\bkillall\b|\bpkill\b/],
14
- ["关机/重启", /\b(shutdown|reboot|halt|poweroff)\b/],
50
+ ["强制杀进程", /\bkill\s+-9\b/],
51
+ ...cmdWord("强制杀进程", "killall|pkill"),
52
+ ...cmdWord("关机/重启", "shutdown|reboot|halt|poweroff"),
15
53
  ["服务停用", /\blaunchctl\s+(unload|bootout|remove)\b|\bsystemctl\s+(stop|disable|mask)\b/],
16
54
  ["git 强推", /\bgit\b[\s\S]*\bpush\b[\s\S]*(--force|-f\b)/],
17
55
  ["git 丢弃改动", /\bgit\s+(reset\s+--hard|clean\b|checkout\s+--\s|restore\b)/],
@@ -24,7 +62,10 @@ const CMD_RULES = [
24
62
  ["GitHub 删除", /\bgh\s+(repo|release|secret|ssh-key)\s+delete\b/],
25
63
  ["数据库 DROP/TRUNCATE", /\b(drop|truncate)\s+(table|database|schema|index)\b/i],
26
64
  ["无条件 DELETE", /\bdelete\s+from\b(?![\s\S]*\bwhere\b)/i],
27
- ["Redis 清库", /\bflush(all|db)\b/i],
65
+ // flushall/flushdb 是 redis-cli 的**子命令**, 永远不在 shell 命令词位置, 所以
66
+ // 这里用 redis 上下文约束而不是 CMD_HEAD —— 同样挡住 `feat/flushdb-guard`
67
+ // 这类分支名, 又不会漏掉 `redis-cli -h h flushall`。
68
+ ["Redis 清库", /\bredis(-cli)?\b[\s\S]*\bflush(all|db)\b/i],
28
69
  ["下载即执行", /\b(curl|wget)\b[\s\S]*\|\s*(sudo\s+)?(ba)?sh\b/],
29
70
  ["fork 炸弹", /:\(\)\s*\{.*\|.*&.*\}/],
30
71
  ["清历史", /\bhistory\s+-c\b|\bdefaults\s+delete\b/],
@@ -1 +1 @@
1
- {"version":3,"file":"danger.js","sourceRoot":"","sources":["../../daemon/danger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"danger.js","sourceRoot":"","sources":["../../daemon/danger.ts"],"names":[],"mappings":"AAgBA,sDAAsD;AACtD,kDAAkD;AAClD,EAAE;AACF,kDAAkD;AAClD,iDAAiD;AACjD,gCAAgC;AAChC,8DAA8D;AAC9D,+DAA+D;AAC/D,uDAAuD;AACvD,EAAE;AACF,8CAA8C;AAC9C,2EAA2E;AAC3E,kEAAkE;AAClE,mDAAmD;AACnD,0DAA0D;AAC1D,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA,qHAAqH,CAAC;AACjJ,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA,sDAAsD,CAAC;AAClF,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA,mCAAmC,QAAQ,UAAU,QAAQ,WAAW,CAAC;AAEpG,0CAA0C;AAC1C,mEAAmE;AACnE,gDAAgD;AAChD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA,gDAAgD,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,KAAK,GAAG,EAAE,EAAU,EAAE,CAAC;IACpE,kDAAkD;IAClD,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,GAAG,QAAQ,WAAW,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC,KAAK,KAAK,EAAE,EAAE,IAAI,MAAM,CAAC,GAAG,UAAU,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC;CAClE,CAAC;AAEF,8DAA8D;AAC9D,MAAM,SAAS,GAAoB;IACjC,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;IAC3B,GAAG,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;IACjC,CAAC,mBAAmB,EAAE,uCAAuC,CAAC;IAC9D,4DAA4D;IAC5D,sCAAsC;IACtC,CAAC,eAAe,EAAE,wBAAwB,CAAC;IAC3C,GAAG,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC;IACvC,CAAC,UAAU,EAAE,iBAAiB,CAAC;IAC/B,CAAC,UAAU,EAAE,yCAAyC,CAAC;IACvD,CAAC,QAAQ,EAAE,yCAAyC,CAAC;IACrD,GAAG,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;IAC7B,CAAC,SAAS,EAAE,UAAU,CAAC;IACvB,CAAC,OAAO,EAAE,oCAAoC,CAAC;IAC/C,CAAC,OAAO,EAAE,eAAe,CAAC;IAC1B,GAAG,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC;IACpC,GAAG,OAAO,CAAC,OAAO,EAAE,+BAA+B,CAAC;IACpD,CAAC,MAAM,EAAE,6EAA6E,CAAC;IACvF,CAAC,QAAQ,EAAE,6CAA6C,CAAC;IACzD,CAAC,UAAU,EAAE,4DAA4D,CAAC;IAC1E,CAAC,SAAS,EAAE,uDAAuD,CAAC;IACpE,CAAC,KAAK,EAAE,qEAAqE,CAAC;IAC9E,CAAC,MAAM,EAAE,iEAAiE,CAAC;IAC3E,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAClC,CAAC,QAAQ,EAAE,yBAAyB,CAAC;IACrC,CAAC,OAAO,EAAE,0EAA0E,CAAC;IACrF,CAAC,WAAW,EAAE,iDAAiD,CAAC;IAChE,CAAC,mBAAmB,EAAE,sDAAsD,CAAC;IAC7E,CAAC,YAAY,EAAE,wCAAwC,CAAC;IACxD,8DAA8D;IAC9D,2DAA2D;IAC3D,0CAA0C;IAC1C,CAAC,UAAU,EAAE,2CAA2C,CAAC;IACzD,CAAC,OAAO,EAAE,gDAAgD,CAAC;IAC3D,CAAC,SAAS,EAAE,uBAAuB,CAAC;IACpC,CAAC,KAAK,EAAE,wCAAwC,CAAC;CAClD,CAAC;AAEF,0DAA0D;AAC1D,MAAM,UAAU,GAAoB;IAClC,CAAC,OAAO,EAAE,iEAAiE,CAAC;CAC7E,CAAC;AAEF,sDAAsD;AACtD,MAAM,UAAU,GAAoB;IAClC,CAAC,QAAQ,EAAE,0DAA0D,CAAC;IACtE,CAAC,MAAM,EAAE,kFAAkF,CAAC;IAC5F,CAAC,MAAM,EAAE,4DAA4D,CAAC;IACtE,CAAC,UAAU,EAAE,0BAA0B,CAAC;CACzC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,OAA0B,EAAU,EAAE,CACrD,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;IACpB,IAAI,CAAC;QACH,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAS,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,iBAAiB;IAC9B,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,MAAM,QAAQ,GAAG,CAAC,KAAsB,EAAE,IAAY,EAAyB,EAAE;IAC/E,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC,CAAC;AAEF,oCAAoC;AACpC,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,OAAO,GAAG,CAAC,CAAU,EAAE,KAAK,GAAG,CAAC,EAAE,MAAgB,EAAE,EAAY,EAAE;IACtE,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACrD,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,OAAO,GAAG,CAAC;IAAC,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAAC,OAAO,GAAG,CAAC;IAAC,CAAC;IACnF,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAA4B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,2DAA2D;AAC3D,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AACpE,MAAM,UAAU,GAAG,CAAC,KAAc,EAAY,EAAE;IAC9C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SACpD,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;SAChE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAW,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,oCAAoC;AACpC,MAAM,OAAO,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,GAA0B,EAAW,EAAE,CAClF,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC;AAExE,mDAAmD;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,GAA0B,EAAW,EAAE,CAC9E,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;AAEpC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAW,EACX,GAA0B,EAC1B,cAAuB,EACyB,EAAE;IAClD,IAAI,cAAc;QAAE,OAAO,SAAS,CAAC;IACrC,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,OAAO,aAAa,CAAC;IAChD,IAAI,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,OAAO,kBAAkB,CAAC;IACzD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,wCAAwC;AACxC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAE,SAAkB,EAAyB,EAAE;IACnG,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9B,IAAI,CAAC,CAAC,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAEjC,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACvC,sCAAsC;IACtC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAE9F,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;IAClF,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IAEjF,OAAO,CACL,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAwB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;QACvF,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CACvC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EACzC,SAAS,CACV,CACF,CAAC;AACJ,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wezard",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "Bridge Claude Code and WeCom: PreToolUse approval cards + bidirectional tmux session mirror with image paste",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/web/chat.css CHANGED
@@ -59,18 +59,22 @@ button { font: inherit; color: inherit }
59
59
  flex-wrap: nowrap; align-items: stretch;
60
60
  }
61
61
  .rolebar > .who { min-width: 0 }
62
- .rolebar .id { display: flex; gap: 10px; align-items: center; min-width: 0 }
63
- .rolebar .id .av { font-size: 26px; line-height: 1; flex: none }
64
- .rolebar .id .l { min-width: 0; display: flex; flex-direction: column; gap: 2px }
62
+ .rolebar .id { display: flex; gap: 12px; align-items: center; min-width: 0 }
63
+ /* 与会话项头像同一套不透明底, 放大到名片尺寸。 */
64
+ .rolebar .id .av {
65
+ flex: none; display: grid; place-items: center; width: 48px; height: 48px; border-radius: 14px;
66
+ background: var(--av-bg); box-shadow: inset 0 0 0 1px var(--av-line); font-size: 28px; line-height: 1;
67
+ }
68
+ .rolebar .id .l { min-width: 0; display: flex; flex-direction: column; gap: 3px }
65
69
  .rolebar .id .nm { font-size: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
66
- .rolebar .id .k { font-size: 11.5px; color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
67
70
  /* 职责是一句话, 至多两行; 截掉的悬停看全文 (chat.js 的截断提示)。 */
68
71
  .rolebar .job {
69
72
  margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--ink); opacity: .8; word-break: break-word;
70
73
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
71
74
  }
72
- .rolebar .facts { display: flex; gap: 6px 12px; flex-wrap: wrap; font-size: 11.5px; color: var(--mute); min-width: 0 }
73
- /* 每条事实自身不折行, 一行排不下就落到下一行; 独占一行仍超宽 (长路径 / 长群名) 才省略。 */
75
+ /* 名字下的描述: 📁 cwd · 🏠 home · 🐣 出生, 一段低调的灰字, 排不下就整项落到下一行。 */
76
+ .rolebar .facts { display: flex; flex-wrap: wrap; gap: 0 10px; font-size: 11.5px; line-height: 1.45; color: var(--faint); min-width: 0 }
77
+ /* 每条自身不折行; 独占一行仍超宽 (长路径 / 长群名) 才省略。 */
74
78
  .rolebar .facts span { white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis }
75
79
  .rolebar .go { cursor: pointer; color: var(--accent) }
76
80
  .rolebar .go:hover { text-decoration: underline }
@@ -110,10 +114,8 @@ button { font: inherit; color: inherit }
110
114
  }
111
115
  .sp-btn:hover, .sp.open .sp-btn { background: var(--paper); color: var(--ink) }
112
116
  /* 箭头用边框画, 不用 ▾ 字形 —— 字形贴着基线, 放大后总是偏下。 */
113
- .sp-btn .car {
114
- width: 0; height: 0; margin-left: 3px; border: 5px solid transparent; border-top: 6px solid var(--faint); border-bottom: 0;
115
- transition: transform .15s;
116
- }
117
+ .sp-btn .car { flex: none; display: grid; place-items: center; width: 16px; height: 16px; transition: transform .15s }
118
+ .sp-btn .car::before { content: ""; border: 5px solid transparent; border-top: 6px solid var(--faint); border-bottom: 0 }
117
119
  .sp.open .sp-btn .car { transform: rotate(180deg) }
118
120
  .sp-list {
119
121
  /* 以触发器左下角为锚向右下展开 —— 触发器贴着 name 右边, 朝左开会被侧栏左沿裁掉。 */
package/web/chat.js CHANGED
@@ -599,37 +599,25 @@
599
599
  for (var el = e.target; el && el.nodeType === 1 && el !== document.body && !clipTip(el); el = el.parentElement);
600
600
  });
601
601
 
602
- // 名片: 身份 · 出身 · cwd · 出生; 名片下面一排是关系 / 日程入口。
602
+ // 名片: 头像 · 名字 (忙闲 / session) · 名字下一行低调的描述 (📁 cwd · 🏠 home · 🐣 出生) · 职责;
603
+ // 名片下面一排是关系 / 日程入口。身份与出身 (谁的分身 / 子 wizard) 交给关系图, 名片不写。
603
604
  var renderRole = function () {
604
605
  var r = R.role;
605
606
  if (!r) return;
606
- // 名字下面那一行就是出身 —— 有父亲的直接写成「谁的什么」(可点过去), 不再另起一条重复。
607
- // 分身 = 从父亲某个 session 节点 fork 出来的 (带着那一刻的上下文);
608
- // 子 wizard = 父亲 spawn 的白板, 只有出身、没有继承。
609
- // 人不挂身份行 —— 名字本身就够了。
610
- var kind = r.kind === 'human' ? ''
611
- : !r.parent ? 'wizard'
612
- : r.forkedFrom
613
- ? '<span class="go" data-r="' + esc(r.parent.id) + '" title="从它的 session ' + esc(r.forkedFrom) + ' fork, 开局带着那一刻的上下文">⧉ .' + esc(r.parent.name) + ' 的分身 · @' + esc(r.forkedFrom.slice(0, 8)) + '</span>'
614
- : '<span class="go" data-r="' + esc(r.parent.id) + '" title="它 spawn 的白板, 没有继承上下文">↳ .' + esc(r.parent.name) + ' 的子 wizard</span>';
615
- var facts = [];
616
- if (r.cwd) facts.push('<span title="' + esc(r.cwd) + '">📁 ' + esc(shortCwd(r.cwd)) + '</span>');
617
- // 生在哪个群、什么时候 —— 一件事, 一行。
618
- // 时刻跟着选中的 session 走: 选了一段就是那一段的开始与轮数, 全部就是最早那段起、共几轮。
619
- var cur = R.sessions.filter(function (x) { return x.sessionId === SESSION; })[0];
620
- var span = cur ? [cur] : R.sessions;
621
- var t0 = span.reduce(function (m, x) { return x.start && (!m || x.start < m) ? x.start : m; }, 0);
622
- var turns = span.reduce(function (n, x) { return n + (x.turns || 0); }, 0);
623
- var when = [r.chat, t0 ? (cur ? '' : '自 ') + fmtClock(t0) : '', turns ? turns + ' 轮' : ''].filter(Boolean);
624
- if (when.length) facts.push('<span title="' + esc((cur ? 'session ' + cur.sessionId : '全部 ' + R.sessions.length + ' 段 session') +
625
- (t0 ? ' · 开始于 ' + fmtDay(t0) : '')) + '">🕘 ' + esc(when.join(' · ')) + '</span>');
607
+ // 出生 = 注册表记的 bornAt; 没记 (老 wizard / 人) 就退到最早一段 session 的开始。
608
+ var born = r.bornAt || R.sessions.reduce(function (m, x) { return x.start && (!m || x.start < m) ? x.start : m; }, 0);
609
+ var facts = [
610
+ r.cwd ? ['📁', shortCwd(r.cwd), r.cwd] : null,
611
+ r.chat ? ['🏠', r.chat, 'home'] : null,
612
+ born ? ['🐣', fmtClock(born), '出生于 ' + fmtDay(born)] : null
613
+ ].filter(Boolean).map(function (f) { return '<span title="' + esc(f[2]) + '">' + f[0] + ' ' + esc(f[1]) + '</span>'; });
614
+ // 只有一段 session 也挂选择器 —— 它同时是「现在看的是哪一段」的标签, 不该随段数忽隐忽现。
626
615
  $('#rb-who').innerHTML =
627
616
  '<div class="id"><span class="av">' + esc(r.label) + '</span>' +
628
617
  '<span class="l"><span class="nl"><span class="cp" title="' + esc('复制 ' + nameOf(r.id)) + '">' + nm(r.id, r.name) + '</span>' + (r.kind === 'wizard' ? '<span id="rb-st"></span>' : '') +
629
- '<span id="rb-sp">' + (R.sessions.length > 1 ? sessPicker() : '') + '</span></span>' +
630
- (kind ? '<span class="k">' + kind + '</span>' : '') + '</span></div>' +
631
- (r.description ? '<p class="job">' + esc(r.description) + '</p>' : '') +
632
- '<div class="facts">' + facts.join('') + '</div>';
618
+ '<span id="rb-sp">' + (R.sessions.length ? sessPicker() : '') + '</span></span>' +
619
+ (facts.length ? '<span class="facts">' + facts.join('') + '</span>' : '') + '</span></div>' +
620
+ (r.description ? '<p class="job">' + esc(r.description) + '</p>' : '');
633
621
  paintStatus();
634
622
  $('#rb-who').querySelector('.cp').onclick = function () { copyText(nameOf(r.id)); };
635
623
  $('#rb-who').querySelectorAll('.go').forEach(function (g) {