wezard 0.3.3

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 (117) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/.claude-plugin/plugin.json +14 -0
  3. package/CLAUDE.md +83 -0
  4. package/LICENSE +21 -0
  5. package/README.md +410 -0
  6. package/cli/weclaude.sh +236 -0
  7. package/commands/audit.md +7 -0
  8. package/commands/wrc.md +7 -0
  9. package/config.example.jsonc +102 -0
  10. package/dist/cli/audit.js +156 -0
  11. package/dist/cli/audit.js.map +1 -0
  12. package/dist/cli/init.js +311 -0
  13. package/dist/cli/init.js.map +1 -0
  14. package/dist/cli/sync.js +175 -0
  15. package/dist/cli/sync.js.map +1 -0
  16. package/dist/daemon/approval.js +1301 -0
  17. package/dist/daemon/approval.js.map +1 -0
  18. package/dist/daemon/ask.js +101 -0
  19. package/dist/daemon/ask.js.map +1 -0
  20. package/dist/daemon/audit.js +168 -0
  21. package/dist/daemon/audit.js.map +1 -0
  22. package/dist/daemon/cc-bridge.js +204 -0
  23. package/dist/daemon/cc-bridge.js.map +1 -0
  24. package/dist/daemon/cfg-sync.js +240 -0
  25. package/dist/daemon/cfg-sync.js.map +1 -0
  26. package/dist/daemon/claim.js +95 -0
  27. package/dist/daemon/claim.js.map +1 -0
  28. package/dist/daemon/detail.js +153 -0
  29. package/dist/daemon/detail.js.map +1 -0
  30. package/dist/daemon/graph.js +176 -0
  31. package/dist/daemon/graph.js.map +1 -0
  32. package/dist/daemon/http.js +83 -0
  33. package/dist/daemon/http.js.map +1 -0
  34. package/dist/daemon/inbound.js +919 -0
  35. package/dist/daemon/inbound.js.map +1 -0
  36. package/dist/daemon/index.js +569 -0
  37. package/dist/daemon/index.js.map +1 -0
  38. package/dist/daemon/last-response.js +59 -0
  39. package/dist/daemon/last-response.js.map +1 -0
  40. package/dist/daemon/mirror-bridge.js +3512 -0
  41. package/dist/daemon/mirror-bridge.js.map +1 -0
  42. package/dist/daemon/mirror-store.js +39 -0
  43. package/dist/daemon/mirror-store.js.map +1 -0
  44. package/dist/daemon/outbound.js +42 -0
  45. package/dist/daemon/outbound.js.map +1 -0
  46. package/dist/daemon/peers.js +146 -0
  47. package/dist/daemon/peers.js.map +1 -0
  48. package/dist/daemon/pending.js +90 -0
  49. package/dist/daemon/pending.js.map +1 -0
  50. package/dist/daemon/quota.js +164 -0
  51. package/dist/daemon/quota.js.map +1 -0
  52. package/dist/daemon/redact.js +27 -0
  53. package/dist/daemon/redact.js.map +1 -0
  54. package/dist/daemon/session-cache.js +149 -0
  55. package/dist/daemon/session-cache.js.map +1 -0
  56. package/dist/daemon/session-scan.js +273 -0
  57. package/dist/daemon/session-scan.js.map +1 -0
  58. package/dist/daemon/sessions.js +35 -0
  59. package/dist/daemon/sessions.js.map +1 -0
  60. package/dist/daemon/spawn-tmux.js +213 -0
  61. package/dist/daemon/spawn-tmux.js.map +1 -0
  62. package/dist/daemon/tips.js +25 -0
  63. package/dist/daemon/tips.js.map +1 -0
  64. package/dist/daemon/topics.js +197 -0
  65. package/dist/daemon/topics.js.map +1 -0
  66. package/dist/daemon/usage.js +358 -0
  67. package/dist/daemon/usage.js.map +1 -0
  68. package/dist/daemon/wedoc.js +210 -0
  69. package/dist/daemon/wedoc.js.map +1 -0
  70. package/dist/daemon/ws.js +67 -0
  71. package/dist/daemon/ws.js.map +1 -0
  72. package/dist/mcp/server.js +385 -0
  73. package/dist/mcp/server.js.map +1 -0
  74. package/dist/shared/ansi.js +134 -0
  75. package/dist/shared/ansi.js.map +1 -0
  76. package/dist/shared/chat-http.js +195 -0
  77. package/dist/shared/chat-http.js.map +1 -0
  78. package/dist/shared/chat-render.js +53 -0
  79. package/dist/shared/chat-render.js.map +1 -0
  80. package/dist/shared/chat-view.js +116 -0
  81. package/dist/shared/chat-view.js.map +1 -0
  82. package/dist/shared/cli-backends.js +304 -0
  83. package/dist/shared/cli-backends.js.map +1 -0
  84. package/dist/shared/config-writer.js +39 -0
  85. package/dist/shared/config-writer.js.map +1 -0
  86. package/dist/shared/config.js +278 -0
  87. package/dist/shared/config.js.map +1 -0
  88. package/dist/shared/detail-render.js +836 -0
  89. package/dist/shared/detail-render.js.map +1 -0
  90. package/dist/shared/detail-store.js +205 -0
  91. package/dist/shared/detail-store.js.map +1 -0
  92. package/dist/shared/highlight.js +154 -0
  93. package/dist/shared/highlight.js.map +1 -0
  94. package/dist/shared/lan-ip.js +35 -0
  95. package/dist/shared/lan-ip.js.map +1 -0
  96. package/dist/shared/log.js +18 -0
  97. package/dist/shared/log.js.map +1 -0
  98. package/dist/shared/md-chunk.js +99 -0
  99. package/dist/shared/md-chunk.js.map +1 -0
  100. package/dist/shared/paths.js +12 -0
  101. package/dist/shared/paths.js.map +1 -0
  102. package/dist/shared/session-label.js +67 -0
  103. package/dist/shared/session-label.js.map +1 -0
  104. package/dist/shared/web-assets.js +51 -0
  105. package/dist/shared/web-assets.js.map +1 -0
  106. package/dist/svr/index.js +246 -0
  107. package/dist/svr/index.js.map +1 -0
  108. package/hooks/hooks.json +16 -0
  109. package/hooks/pre-tool-use.sh +167 -0
  110. package/launchd/com.weclaude.daemon.plist.template +45 -0
  111. package/package.json +97 -0
  112. package/scripts/install.sh +73 -0
  113. package/scripts/postinstall.sh +12 -0
  114. package/scripts/uninstall.sh +44 -0
  115. package/systemd/weclaude.service.template +17 -0
  116. package/web/chat.css +171 -0
  117. package/web/chat.js +367 -0
@@ -0,0 +1,385 @@
1
+ // MCP server `weclaude`. Stdio transport. Single tool `wrc` = "wecom remote
2
+ // control": attaches the *current* Claude session for WeCom mirror — session
3
+ // resolved via CLAUDE_CODE_SESSION_ID env (Claude Code populates this for
4
+ // every child process), so multiple windows can each /wrc without trampling.
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { spawn } from "node:child_process";
8
+ import { existsSync, readdirSync, statSync } from "node:fs";
9
+ import { join, basename } from "node:path";
10
+ import { homedir } from "node:os";
11
+ import { z } from "zod";
12
+ const DAEMON_BASE = process.env.WECLAUDE_DAEMON_BASE ?? "http://127.0.0.1:17890";
13
+ const ok = (data) => ({
14
+ content: [{ type: "text", text: JSON.stringify(data) }],
15
+ });
16
+ const fail = (msg) => ({
17
+ isError: true,
18
+ content: [{ type: "text", text: msg }],
19
+ });
20
+ // Project-dir encoding is backend-specific:
21
+ // Claude Code / claude-internal: `/` `.` → `-` (yields leading `-`)
22
+ // CodeBuddy: strip leading `/`, then `/` `.` → `-` (no leading `-`)
23
+ const encodeClaude = (absCwd) => absCwd.replace(/[/.]/g, "-");
24
+ const encodeCodebuddy = (absCwd) => absCwd.replace(/^[/]+/, "").replace(/[/.]/g, "-");
25
+ const PROJECT_ROOTS = [
26
+ { dir: join(homedir(), ".claude-internal", "projects"), encode: encodeClaude },
27
+ { dir: join(homedir(), ".claude", "projects"), encode: encodeClaude },
28
+ { dir: join(homedir(), ".codebuddy", "projects"), encode: encodeCodebuddy },
29
+ ];
30
+ const findProjectDir = (cwd) => {
31
+ for (const root of PROJECT_ROOTS) {
32
+ const p = join(root.dir, root.encode(cwd));
33
+ if (existsSync(p))
34
+ return p;
35
+ }
36
+ return undefined;
37
+ };
38
+ const latestJsonlByMtime = (projectDir) => {
39
+ const files = readdirSync(projectDir).filter((n) => n.endsWith(".jsonl"));
40
+ if (files.length === 0)
41
+ return null;
42
+ return files
43
+ .map((n) => ({ p: join(projectDir, n), m: statSync(join(projectDir, n)).mtimeMs }))
44
+ .reduce((a, b) => (b.m > a.m ? b : a)).p;
45
+ };
46
+ const resolveCallerSession = () => {
47
+ // CodeBuddy exports CODEBUDDY_PROJECT_DIR / CODEBUDDY_SESSION_ID (native) and
48
+ // also CLAUDE_PROJECT_DIR / CLAUDE_SESSION_ID (compat). Check native first so
49
+ // a codebuddy session inside a claude project dir doesn't mis-resolve.
50
+ const cwd = process.env.CODEBUDDY_PROJECT_DIR
51
+ ?? process.env.CLAUDE_PROJECT_DIR
52
+ ?? process.cwd();
53
+ const projectDir = findProjectDir(cwd);
54
+ if (!projectDir)
55
+ return { error: `no claude project dir for cwd ${cwd}` };
56
+ // Primary: env tells us exactly which session invoked us. Trust it
57
+ // unconditionally — claude only writes the jsonl after the first user
58
+ // message lands, so a fresh session (e.g. /clear-then-/wrc, or a brand-new
59
+ // CLI window) will have envSid set but no file yet. The daemon's tail
60
+ // tolerates a missing path (see mirror-bridge.ts attach()), and any
61
+ // existsSync gate here would mis-route to a stale jsonl picked by mtime.
62
+ const envSid = process.env.CODEBUDDY_SESSION_ID
63
+ ?? process.env.CLAUDE_CODE_SESSION_ID
64
+ ?? process.env.CLAUDE_SESSION_ID;
65
+ if (envSid)
66
+ return { sessionId: envSid, jsonlPath: join(projectDir, `${envSid}.jsonl`) };
67
+ // Fallback: most-recently-written jsonl. Only reached when env is absent
68
+ // (older claude versions, exotic launchers).
69
+ const jsonlPath = latestJsonlByMtime(projectDir);
70
+ if (!jsonlPath)
71
+ return { error: `no .jsonl under ${projectDir}` };
72
+ return { sessionId: basename(jsonlPath, ".jsonl"), jsonlPath };
73
+ };
74
+ // Resolve the current pane's tmux session name. `tmux display-message -p` runs
75
+ // against the tmux server pointed at by $TMUX (set in every process running
76
+ // inside tmux), so it returns the session containing *this* pane without us
77
+ // needing to pass a target. Returns undefined if not in tmux or query failed.
78
+ const detectTmuxSession = () => new Promise((resolve) => {
79
+ if (!process.env.TMUX)
80
+ return resolve(undefined);
81
+ const p = spawn("tmux", ["display-message", "-p", "#{session_name}"], { stdio: ["ignore", "pipe", "ignore"] });
82
+ let out = "";
83
+ p.stdout?.on("data", (c) => (out += c.toString("utf8")));
84
+ p.on("error", () => resolve(undefined));
85
+ p.on("close", (code) => resolve(code === 0 ? out.trim() || undefined : undefined));
86
+ });
87
+ const server = new McpServer({ name: "weclaude", version: "0.0.1" }, { capabilities: { tools: {} } });
88
+ // Accept user-friendly prefixes from the LLM: vid:<id> → user:<id>, chatid:<id> → chat:<id>.
89
+ // Pass anything else (already user:/chat:/group:, or empty) through unchanged.
90
+ const normalizeTarget = (raw) => {
91
+ if (!raw)
92
+ return undefined;
93
+ if (raw.startsWith("vid:"))
94
+ return `user:${raw.slice(4)}`;
95
+ if (raw.startsWith("chatid:"))
96
+ return `chat:${raw.slice(7)}`;
97
+ return raw;
98
+ };
99
+ server.registerTool("wrc", {
100
+ title: "WeCom remote control",
101
+ description: "wecom remote control — attach current Claude session to a WeCom chat for live mirror push",
102
+ inputSchema: {
103
+ target: z
104
+ .string()
105
+ .optional()
106
+ .describe('Optional push target. Accepts "vid:<userid>" (DM), "chatid:<chatid>" (group), or raw "user:<id>"/"chat:<id>". Empty → use config defaultChat / mirror.pushChat.'),
107
+ },
108
+ }, async ({ target }) => {
109
+ const r = resolveCallerSession();
110
+ if ("error" in r)
111
+ return fail(r.error);
112
+ const normalizedTarget = normalizeTarget(target);
113
+ // tmux sets $TMUX_PANE for every process inside a pane (e.g. `%5`); we
114
+ // inherit it through claude → MCP child, so each /wrc auto-picks its own
115
+ // pane without the user touching config. Pane ids are not stable across
116
+ // tmux server restarts, so we also capture the session name — the daemon
117
+ // uses it to re-derive a fresh paneId after reload, and as the "user wants
118
+ // a tmux pane" signal that drives respawn when their pane dies.
119
+ const tmuxPane = process.env.TMUX_PANE?.trim();
120
+ const tmuxSession = tmuxPane ? await detectTmuxSession() : undefined;
121
+ const resp = await fetch(`${DAEMON_BASE}/mirror/attach`, {
122
+ method: "POST",
123
+ headers: { "content-type": "application/json" },
124
+ body: JSON.stringify({
125
+ sessionId: r.sessionId,
126
+ jsonlPath: r.jsonlPath,
127
+ ...(normalizedTarget ? { target: normalizedTarget } : {}),
128
+ ...(tmuxPane ? { tmuxPane } : {}),
129
+ ...(tmuxSession ? { tmuxSession } : {}),
130
+ }),
131
+ });
132
+ const j = (await resp.json().catch(() => ({})));
133
+ return j.ok
134
+ ? ok({ ok: true, sessionId: r.sessionId, target: j.target })
135
+ : fail(`attach failed: ${j.reason ?? "unknown"}`);
136
+ });
137
+ // cd — bind a per-chat project cwd in the daemon's mirror store. Doesn't
138
+ // move the live claude (cwd is set at pane spawn time); instead writes to
139
+ // `pendingCwd`. Apply only fires for `/clear` or `/new` sent **from the
140
+ // WeCom side** — that's the only path that goes through `dispatch` where
141
+ // the kill-pane + respawn-in-pendingCwd upgrade lives (mirror-bridge.ts
142
+ // `dispatch` armMigration branch). A `/clear` typed in the local REPL just
143
+ // rotates claude's sessionId in the same pane; the daemon never sees it
144
+ // and the pane stays in the old cwd.
145
+ server.registerTool("cd", {
146
+ title: "Bind project path to current chat",
147
+ description: "Persist a project cwd binding for the WeCom chat that mirrors this Claude session. To apply: send `/clear` or `/new` FROM THE WECOM SIDE — only WeCom-originated commands flow through the daemon's dispatch which kills+respawns the pane in the new cwd. A `/clear` typed in the local Claude REPL does NOT apply the cwd switch; it only rotates the sessionId in the existing pane (still in the old directory). Use absolute paths (or paths starting with ~).",
148
+ inputSchema: {
149
+ cwd: z.string().describe("Absolute project path, e.g. /Users/foo/projects/bar. ~ is expanded."),
150
+ target: z
151
+ .string()
152
+ .optional()
153
+ .describe('Optional target override. "vid:<userid>" / "chatid:<chatid>" / raw "user:<id>"/"chat:<id>". Empty → derive from this Claude session.'),
154
+ },
155
+ }, async ({ cwd, target }) => {
156
+ const sessionId = process.env.CLAUDE_CODE_SESSION_ID ?? process.env.CLAUDE_SESSION_ID ?? "";
157
+ // sessionId in our env is frozen at MCP spawn; a `/clear` rotates the live
158
+ // session, stranding pendingCwd on defaultChat. TMUX_PANE is stable across
159
+ // clears, so send it as the reliable fallback key.
160
+ const tmuxPane = process.env.TMUX_PANE?.trim();
161
+ const normalizedTarget = normalizeTarget(target);
162
+ const resp = await fetch(`${DAEMON_BASE}/mirror/cwd`, {
163
+ method: "POST",
164
+ headers: { "content-type": "application/json" },
165
+ body: JSON.stringify({
166
+ cwd,
167
+ ...(normalizedTarget ? { target: normalizedTarget } : {}),
168
+ ...(sessionId ? { sessionId } : {}),
169
+ ...(tmuxPane ? { tmuxPane } : {}),
170
+ }),
171
+ });
172
+ const j = (await resp.json().catch(() => ({})));
173
+ if (!j.ok)
174
+ return fail(`cd failed: ${j.reason ?? "unknown"}`);
175
+ return ok({
176
+ ok: true,
177
+ target: j.target,
178
+ runningCwd: j.runningCwd,
179
+ pendingCwd: j.pendingCwd,
180
+ hint: "Send `/clear` or `/new` FROM THE WECOM SIDE to apply. Local-REPL `/clear` will NOT switch cwd — only WeCom-originated commands flow through the daemon's kill-pane + respawn-in-pendingCwd path.",
181
+ });
182
+ });
183
+ // 企业微信 doc / smartsheet / contact MCP 桥接。把 daemon 远端的 MCP 转发
184
+ // 给本地 Claude: list_tools 列工具, call_tool 调用 (创建文档 / 写表格 / 读
185
+ // 内容)。category 当前可选: "doc" | "smartsheet" | "contact"。
186
+ // 大模型先调 list_tools 看可用方法和入参 schema, 再 call_tool。
187
+ server.registerTool("wecom_doc_list_tools", {
188
+ title: "List WeCom doc/smartsheet tools",
189
+ description: "List available WeCom MCP tools for a given category. Categories: 'doc' (online documents), 'smartsheet' (smart sheets), 'contact'. Returns tool names + JSON Schema. Call this BEFORE wecom_doc_call to discover method names and required arguments.",
190
+ inputSchema: {
191
+ category: z.string().describe("MCP category: 'doc' | 'smartsheet' | 'contact'."),
192
+ requesterUserId: z
193
+ .string()
194
+ .optional()
195
+ .describe("WeCom userid that owns the resulting docs. Optional — daemon falls back to config.wedoc.requesterUserId or defaultChat. 'user:xxx' prefix accepted."),
196
+ },
197
+ }, async ({ category, requesterUserId }) => {
198
+ const resp = await fetch(`${DAEMON_BASE}/wedoc/list`, {
199
+ method: "POST",
200
+ headers: { "content-type": "application/json" },
201
+ body: JSON.stringify({ category, ...(requesterUserId ? { requesterUserId } : {}) }),
202
+ });
203
+ const j = (await resp.json().catch(() => ({})));
204
+ return j.ok ? ok(j.result) : fail(`wecom_doc_list_tools failed: ${j.error ?? `http ${resp.status}`}`);
205
+ });
206
+ server.registerTool("wecom_doc_call", {
207
+ title: "Call WeCom doc/smartsheet tool",
208
+ description: "Invoke a specific WeCom MCP tool (after discovering it via wecom_doc_list_tools). Typical flow: list tools for 'doc' → pick a method like 'doc_create' → call it with args matching its inputSchema. Daily quota: 20 docs per requesterUserId.",
209
+ inputSchema: {
210
+ category: z.string().describe("MCP category: 'doc' | 'smartsheet' | 'contact'."),
211
+ method: z.string().describe("Tool name from wecom_doc_list_tools (e.g. 'doc_create', 'smartsheet_add_records')."),
212
+ args: z
213
+ .record(z.string(), z.unknown())
214
+ .optional()
215
+ .describe("JSON object matching the tool's inputSchema. Empty object if the tool takes no params."),
216
+ requesterUserId: z
217
+ .string()
218
+ .optional()
219
+ .describe("WeCom userid acting as document owner. Optional — daemon falls back to config / defaultChat. 'user:xxx' prefix accepted."),
220
+ },
221
+ }, async ({ category, method, args, requesterUserId }) => {
222
+ const resp = await fetch(`${DAEMON_BASE}/wedoc/call`, {
223
+ method: "POST",
224
+ headers: { "content-type": "application/json" },
225
+ body: JSON.stringify({
226
+ category,
227
+ method,
228
+ args: args ?? {},
229
+ ...(requesterUserId ? { requesterUserId } : {}),
230
+ }),
231
+ });
232
+ const j = (await resp.json().catch(() => ({})));
233
+ return j.ok ? ok(j.result) : fail(`wecom_doc_call failed: ${j.error ?? `http ${resp.status}`}`);
234
+ });
235
+ // ── Session discovery / switching (conversational) ─────────────────────────
236
+ // These let the WeCom-side Claude answer "列出所有 claude session" / "切到 xxx
237
+ // 那个" / "在 /path 下新建一个 session" in natural language. The daemon does the
238
+ // host-wide /proc + tmux scan (an MCP tool can only see its OWN session).
239
+ server.registerTool("list_claude_sessions", {
240
+ title: "List running Claude sessions",
241
+ description: "List all Claude Code sessions currently running in tmux on this host, each with a stable animal-emoji label, its working directory, tmux location, and a short summary of what it's recently been doing. Call this whenever the user asks to see / list / switch between Claude sessions (e.g. '列出所有 claude session', '有哪些会话在跑', '我想切换 session'). Present the result to the user as a readable numbered list (emoji + dir + summary), and note which one is the current mirror target (`current: true`).",
242
+ inputSchema: {},
243
+ }, async () => {
244
+ const resp = await fetch(`${DAEMON_BASE}/sessions/list`, { method: "GET" });
245
+ const j = (await resp.json().catch(() => ({})));
246
+ return j.ok ? ok(j) : fail(`list_claude_sessions failed: ${j.reason ?? `http ${resp.status}`}`);
247
+ });
248
+ server.registerTool("switch_claude_session", {
249
+ title: "Switch WeCom mirror to another Claude session",
250
+ description: "Re-point the WeCom mirror at a different already-running Claude session, so the user's IM chat starts mirroring (and injecting into) that session instead. Call this when the user picks a session to switch to — e.g. '切到 weclaude 那个', '镜像第2个', '换到 🦊 那个会话'. First call list_claude_sessions to resolve the user's natural-language reference (emoji / directory / topic) to a concrete sessionId, then pass that sessionId here.",
251
+ inputSchema: {
252
+ sessionId: z.string().describe("The target session's sessionId (a UUID), as returned by list_claude_sessions."),
253
+ },
254
+ }, async ({ sessionId }) => {
255
+ const resp = await fetch(`${DAEMON_BASE}/sessions/switch`, {
256
+ method: "POST",
257
+ headers: { "content-type": "application/json" },
258
+ body: JSON.stringify({ sessionId }),
259
+ });
260
+ const j = (await resp.json().catch(() => ({})));
261
+ return j.ok ? ok(j) : fail(`switch_claude_session failed: ${j.reason ?? `http ${resp.status}`}`);
262
+ });
263
+ server.registerTool("new_claude_session", {
264
+ title: "Spawn a new Claude session and mirror it",
265
+ description: "Spawn a brand-new Claude Code session in a fresh tmux pane rooted at the given project path, then switch the WeCom mirror to it. Call this when the user asks to start a new session somewhere — e.g. '在 /path/to/proj 下新建一个 claude session', '帮我在 xxx 目录起个新会话'. The directory is created if it doesn't exist.",
266
+ inputSchema: {
267
+ cwd: z.string().describe("Absolute project path to start the new session in, e.g. /Users/foo/projects/bar. Created if missing."),
268
+ cli: z
269
+ .enum(["claude", "claude-internal", "codebuddy"])
270
+ .optional()
271
+ .describe("Which CLI to launch. Omit unless the user names one (e.g. '用 codebuddy 起一个'); the daemon's default backend is used otherwise. Multiple backends can run side by side."),
272
+ },
273
+ }, async ({ cwd, cli }) => {
274
+ const resp = await fetch(`${DAEMON_BASE}/sessions/new`, {
275
+ method: "POST",
276
+ headers: { "content-type": "application/json" },
277
+ body: JSON.stringify({ cwd, cli }),
278
+ });
279
+ const j = (await resp.json().catch(() => ({})));
280
+ return j.ok ? ok(j) : fail(`new_claude_session failed: ${j.reason ?? `http ${resp.status}`}`);
281
+ });
282
+ // ── Peer collaboration (agent ↔ agent inside one WeCom chat) ───────────────
283
+ // One WeCom chat can host several concurrent agent sessions, each addressed by
284
+ // a `#tag` (`#fix`, `#docs`, …) and each free to run a different CLI / model /
285
+ // project. They are peers: siblings that can watch and drive each other. This
286
+ // process can only see ITSELF, so every question about a sibling goes to the
287
+ // daemon, which owns all the attachments.
288
+ //
289
+ // `selfRef` is how the daemon figures out which session is asking: sessionId
290
+ // from env (frozen at MCP spawn — goes stale after a `/clear`) plus TMUX_PANE
291
+ // (stable for the pane's lifetime), so one of the two always resolves.
292
+ const selfRef = () => {
293
+ const sessionId = process.env.CODEBUDDY_SESSION_ID ??
294
+ process.env.CLAUDE_CODE_SESSION_ID ??
295
+ process.env.CLAUDE_SESSION_ID;
296
+ const tmuxPane = process.env.TMUX_PANE?.trim();
297
+ return { ...(sessionId ? { sessionId } : {}), ...(tmuxPane ? { tmuxPane } : {}) };
298
+ };
299
+ const daemonPost = async (path, body) => {
300
+ const resp = await fetch(`${DAEMON_BASE}${path}`, {
301
+ method: "POST",
302
+ headers: { "content-type": "application/json" },
303
+ body: JSON.stringify({ ...selfRef(), ...body }),
304
+ });
305
+ return { j: (await resp.json().catch(() => ({}))), status: resp.status };
306
+ };
307
+ const unwrap = (name, { j, status }) => j.ok ? ok(j) : fail(`${name} failed: ${j.reason ?? `http ${status}`}`);
308
+ server.registerTool("list_peers", {
309
+ title: "List sibling agent sessions in this chat",
310
+ description: "List the OTHER agent sessions running in the SAME WeCom chat as this one. A chat hosts one default session plus any number of `#tag` sessions (e.g. `#fix`, `#review`), each with its own tmux pane, CLI, model and working directory. Returns for each peer: its tag, emoji label, cwd, CLI, whether its pane is alive, whether it is mid-turn (`busy`), when it last did anything, and a one-line summary of its recent conversation. `self: true` marks your own session. Call this FIRST whenever the user refers to another agent or tag — '#fix 进展如何', '还有谁在跑', '让 #docs 也看看' — then use peek_peer / send_peer / wait_peer to actually collaborate.",
311
+ inputSchema: {},
312
+ }, async () => unwrap("list_peers", await daemonPost("/peers/list", {})));
313
+ server.registerTool("peek_peer", {
314
+ title: "See what a sibling agent is doing right now",
315
+ description: "Observe another agent in this chat WITHOUT interrupting it: returns the live tail of its terminal (tmux pane — shows in-flight tool calls and prompts that its transcript hasn't recorded yet), whether it is currently mid-turn (`busy`), and its most recent complete reply (`lastText`). Use this to answer '查看 #fix 的进展' or to decide whether a peer needs a nudge. Read-only and safe to poll.",
316
+ inputSchema: {
317
+ tag: z.string().describe("The peer's tag WITHOUT '#', e.g. 'fix'. Empty string = the chat's default (untagged) session."),
318
+ rows: z.number().optional().describe("How many non-blank terminal lines to return (8-120, default 24)."),
319
+ },
320
+ }, async ({ tag, rows }) => unwrap("peek_peer", await daemonPost("/peers/peek", { tag, ...(rows ? { rows } : {}) })));
321
+ server.registerTool("send_peer", {
322
+ title: "Send a message into a sibling agent's session",
323
+ description: "Type a message into another agent's session in this chat, exactly as if the user had sent it there — the peer picks it up as a new turn. This is how you DRIVE a peer: unblock it, answer its question, hand it work, or tell it to keep going. Typical loop for '推动 #fix 直到结束': peek_peer → send_peer with the nudge → wait_peer until it goes idle → peek_peer again, repeat until its reply says it is done. If the peer's session doesn't exist yet, create it first (run_agent_graph declares nodes, or ask the user to `/new #tag`). Refuses to target your own session.",
324
+ inputSchema: {
325
+ tag: z.string().describe("The peer's tag WITHOUT '#', e.g. 'fix'. Empty string = the chat's default (untagged) session."),
326
+ text: z.string().describe("Message to inject. Plain prompt text; slash commands like '/clear' also work."),
327
+ },
328
+ }, async ({ tag, text }) => unwrap("send_peer", await daemonPost("/peers/send", { tag, text })));
329
+ server.registerTool("wait_peer", {
330
+ title: "Wait until a sibling agent finishes its turn",
331
+ description: "Block until the named peer stops working (its terminal no longer shows an interrupt hint), then return its latest reply. Use it after send_peer so you act on a finished answer instead of a half-written one. Returns `idle: false` with a reason if the timeout hits first — the peer is simply still working, so you can peek and wait again. Cheap: the daemon polls the pane, it does not consume tokens.",
332
+ inputSchema: {
333
+ tag: z.string().describe("The peer's tag WITHOUT '#'. Empty string = the chat's default session."),
334
+ timeoutSec: z.number().optional().describe("Max seconds to wait (10-7200, default 900)."),
335
+ },
336
+ }, async ({ tag, timeoutSec }) => unwrap("wait_peer", await daemonPost("/peers/wait", { tag, ...(timeoutSec ? { timeoutSec } : {}) })));
337
+ server.registerTool("run_agent_graph", {
338
+ title: "Run a loop graph over several tagged agents",
339
+ description: "Declare a multi-agent loop inside this chat and let the daemon drive it. `nodes` are the participating `#tag` sessions (each may pick its own cli / model / cwd; missing sessions are spawned, existing ones are reused with their context intact). `steps` is the ordered pipeline — each step sends a prompt to one node, waits for it to finish, captures its reply, and feeds it forward. The step list is walked `rounds` times, which is what makes it a LOOP: `fix → review → fix → review …` until `until` appears in a reply or the rounds run out. Prompt templates may reference earlier output: `{{last}}` = the previous step's reply, `{{<tag>}}` = that node's latest reply, `{{round}}` = round number. Returns a runId immediately and narrates progress into the chat; poll with graph_status, cancel with stop_graph. Use this when the user asks for several agents to work together / review each other / iterate to a conclusion. For a one-off nudge to a single peer, prefer send_peer + wait_peer.",
340
+ inputSchema: {
341
+ nodes: z
342
+ .array(z.object({
343
+ tag: z.string().describe("Session tag without '#', e.g. 'fix'."),
344
+ cli: z.enum(["claude", "claude-internal", "codebuddy"]).optional().describe("CLI backend for this node. Omit to inherit the chat's."),
345
+ model: z.string().optional().describe("Model slug passed as --model when the node has to be spawned, e.g. 'opus' / 'haiku'. Ignored for an already-running session."),
346
+ cwd: z.string().optional().describe("Absolute project path for this node. Omit to inherit the chat's."),
347
+ }))
348
+ .describe("Participating sessions. Every step's `to` must name one of these tags."),
349
+ steps: z
350
+ .array(z.object({
351
+ to: z.string().describe("Tag of the node this step drives."),
352
+ prompt: z.string().describe("Prompt template. Supports {{last}}, {{<tag>}}, {{round}}."),
353
+ }))
354
+ .describe("Ordered pipeline, replayed once per round."),
355
+ rounds: z.number().optional().describe("How many times to walk the step list (1-50, default 1). >1 makes it a genuine loop."),
356
+ until: z.string().optional().describe("Case-insensitive substring; when a node's reply contains it the run stops early and reports 'converged'. E.g. 'LGTM' or 'DONE'."),
357
+ idleTimeoutSec: z.number().optional().describe("Per-step ceiling on waiting for a node to finish (30-7200, default 900). A timeout is reported but the graph keeps walking."),
358
+ },
359
+ }, async ({ nodes, steps, rounds, until, idleTimeoutSec }) => unwrap("run_agent_graph", await daemonPost("/graph/run", {
360
+ nodes,
361
+ steps,
362
+ ...(rounds ? { rounds } : {}),
363
+ ...(until ? { until } : {}),
364
+ ...(idleTimeoutSec ? { idleTimeoutSec } : {}),
365
+ })));
366
+ server.registerTool("graph_status", {
367
+ title: "Inspect running / finished agent graphs",
368
+ description: "Report progress of loop graphs started by run_agent_graph: per-step round, target tag, status (running / done / timeout / error) and each node's captured reply. Omit runId to list every graph belonging to this chat. Note graphs live in daemon memory — a daemon reload clears them (the panes survive).",
369
+ inputSchema: {
370
+ runId: z.string().optional().describe("Run id from run_agent_graph. Omit to list all runs for this chat."),
371
+ },
372
+ }, async ({ runId }) => {
373
+ const qs = runId ? `?runId=${encodeURIComponent(runId)}` : "";
374
+ const resp = await fetch(`${DAEMON_BASE}/graph/status${qs}`);
375
+ const j = (await resp.json().catch(() => ({})));
376
+ return j.ok ? ok(j) : fail(`graph_status failed: ${j.reason ?? `http ${resp.status}`}`);
377
+ });
378
+ server.registerTool("stop_graph", {
379
+ title: "Cancel a running agent graph",
380
+ description: "Stop a loop graph after its current step. Does NOT interrupt the agent that is mid-turn — it finishes, then no further steps are dispatched. Use when the user says to abort the loop.",
381
+ inputSchema: { runId: z.string().describe("Run id from run_agent_graph.") },
382
+ }, async ({ runId }) => unwrap("stop_graph", await daemonPost("/graph/stop", { runId })));
383
+ const transport = new StdioServerTransport();
384
+ await server.connect(transport);
385
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ // Convert ANSI SGR escapes to HTML <span> with inline styles. Non-SGR CSI
2
+ // (cursor moves, clears) and OSC sequences are stripped. Non-escape text is
3
+ // HTML-escaped. Single-pass fold — no globals.
4
+ //
5
+ // Called at render time on tool_result / transcript strings that may contain
6
+ // escape codes from `ls --color`, `grep --color`, npm/pnpm output, etc.
7
+ // If input has no ANSI, output equals escHtml(input).
8
+ const PALETTE = {
9
+ 30: "#1f2328", 31: "#cf222e", 32: "#1a7f37", 33: "#9a6700",
10
+ 34: "#0969da", 35: "#8250df", 36: "#1b7c83", 37: "#6e7781",
11
+ 90: "#57606a", 91: "#f85149", 92: "#3fb950", 93: "#d29922",
12
+ 94: "#58a6ff", 95: "#bc8cff", 96: "#39c5cf", 97: "#8c959f",
13
+ };
14
+ const xterm256 = (n) => {
15
+ if (n < 16)
16
+ return PALETTE[n < 8 ? 30 + n : 90 + (n - 8)] ?? "#1f2328";
17
+ if (n < 232) {
18
+ const i = n - 16;
19
+ const r = Math.floor(i / 36), g = Math.floor((i % 36) / 6), b = i % 6;
20
+ const v = (x) => (x === 0 ? 0 : 55 + x * 40);
21
+ return `rgb(${v(r)},${v(g)},${v(b)})`;
22
+ }
23
+ const gray = 8 + (n - 232) * 10;
24
+ return `rgb(${gray},${gray},${gray})`;
25
+ };
26
+ const applyParams = (init, ps) => {
27
+ let s = { ...init };
28
+ for (let i = 0; i < ps.length; i++) {
29
+ const p = ps[i];
30
+ if (p === 0)
31
+ s = {};
32
+ else if (p === 1)
33
+ s.bold = true;
34
+ else if (p === 2)
35
+ s.dim = true;
36
+ else if (p === 3)
37
+ s.italic = true;
38
+ else if (p === 4)
39
+ s.underline = true;
40
+ else if (p === 22) {
41
+ s.bold = false;
42
+ s.dim = false;
43
+ }
44
+ else if (p === 23)
45
+ s.italic = false;
46
+ else if (p === 24)
47
+ s.underline = false;
48
+ else if (p >= 30 && p <= 37)
49
+ s.fg = PALETTE[p];
50
+ else if (p === 39)
51
+ s.fg = undefined;
52
+ else if (p >= 40 && p <= 47)
53
+ s.bg = PALETTE[p - 10];
54
+ else if (p === 49)
55
+ s.bg = undefined;
56
+ else if (p >= 90 && p <= 97)
57
+ s.fg = PALETTE[p];
58
+ else if (p >= 100 && p <= 107)
59
+ s.bg = PALETTE[p - 10];
60
+ else if (p === 38 || p === 48) {
61
+ const mode = ps[i + 1];
62
+ if (mode === 5) {
63
+ const col = xterm256(ps[i + 2] ?? 0);
64
+ if (p === 38)
65
+ s.fg = col;
66
+ else
67
+ s.bg = col;
68
+ i += 2;
69
+ }
70
+ else if (mode === 2) {
71
+ const r = ps[i + 2] ?? 0, g = ps[i + 3] ?? 0, b = ps[i + 4] ?? 0;
72
+ const col = `rgb(${r},${g},${b})`;
73
+ if (p === 38)
74
+ s.fg = col;
75
+ else
76
+ s.bg = col;
77
+ i += 4;
78
+ }
79
+ }
80
+ }
81
+ return s;
82
+ };
83
+ const isEmpty = (s) => !s.fg && !s.bg && !s.bold && !s.dim && !s.italic && !s.underline;
84
+ const styleAttr = (s) => {
85
+ const parts = [];
86
+ if (s.fg)
87
+ parts.push(`color:${s.fg}`);
88
+ if (s.bg)
89
+ parts.push(`background:${s.bg}`);
90
+ if (s.bold)
91
+ parts.push("font-weight:600");
92
+ if (s.dim)
93
+ parts.push("opacity:.7");
94
+ if (s.italic)
95
+ parts.push("font-style:italic");
96
+ if (s.underline)
97
+ parts.push("text-decoration:underline");
98
+ return parts.join(";");
99
+ };
100
+ const esc = (s) => s.replace(/[&<>"']/g, (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : c === ">" ? "&gt;" : c === '"' ? "&quot;" : "&#39;");
101
+ // eslint-disable-next-line no-control-regex
102
+ const OSC_RE = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
103
+ // eslint-disable-next-line no-control-regex
104
+ const CSI_RE = /\x1b\[([\d;?]*)([A-Za-z])/g;
105
+ export const ansiToHtml = (raw) => {
106
+ const cleaned = raw.replace(OSC_RE, "").replace(/\r(?!\n)/g, "");
107
+ let out = "";
108
+ let sty = {};
109
+ let open = false;
110
+ let last = 0;
111
+ const re = new RegExp(CSI_RE.source, "g");
112
+ let m;
113
+ while ((m = re.exec(cleaned)) !== null) {
114
+ out += esc(cleaned.slice(last, m.index));
115
+ last = re.lastIndex;
116
+ if (m[2] === "m") {
117
+ const ps = m[1] === "" ? [0] : m[1].split(";").map((n) => Number(n) || 0);
118
+ sty = applyParams(sty, ps);
119
+ if (open) {
120
+ out += "</span>";
121
+ open = false;
122
+ }
123
+ if (!isEmpty(sty)) {
124
+ out += `<span style="${styleAttr(sty)}">`;
125
+ open = true;
126
+ }
127
+ }
128
+ }
129
+ out += esc(cleaned.slice(last));
130
+ if (open)
131
+ out += "</span>";
132
+ return out;
133
+ };
134
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../shared/ansi.ts"],"names":[],"mappings":"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"}