weclaude 0.0.4 → 0.1.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.
Files changed (48) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +34 -22
  3. package/cli/{wrc.sh → weclaude.sh} +34 -18
  4. package/commands/wrc.md +4 -4
  5. package/config.example.jsonc +6 -6
  6. package/dist/cli/init.js +10 -10
  7. package/dist/cli/init.js.map +1 -1
  8. package/dist/cli/sync.js +35 -18
  9. package/dist/cli/sync.js.map +1 -1
  10. package/dist/daemon/approval.js +480 -36
  11. package/dist/daemon/approval.js.map +1 -1
  12. package/dist/daemon/cc-bridge.js +37 -20
  13. package/dist/daemon/cc-bridge.js.map +1 -1
  14. package/dist/daemon/claim.js +1 -1
  15. package/dist/daemon/claim.js.map +1 -1
  16. package/dist/daemon/detail.js +500 -0
  17. package/dist/daemon/detail.js.map +1 -0
  18. package/dist/daemon/http.js +2 -1
  19. package/dist/daemon/http.js.map +1 -1
  20. package/dist/daemon/inbound.js +115 -21
  21. package/dist/daemon/inbound.js.map +1 -1
  22. package/dist/daemon/index.js +24 -7
  23. package/dist/daemon/index.js.map +1 -1
  24. package/dist/daemon/mirror-bridge.js +972 -151
  25. package/dist/daemon/mirror-bridge.js.map +1 -1
  26. package/dist/daemon/mirror-store.js +39 -0
  27. package/dist/daemon/mirror-store.js.map +1 -0
  28. package/dist/daemon/pending.js +46 -0
  29. package/dist/daemon/pending.js.map +1 -1
  30. package/dist/daemon/session-cache.js +71 -3
  31. package/dist/daemon/session-cache.js.map +1 -1
  32. package/dist/daemon/spawn-tmux.js +132 -0
  33. package/dist/daemon/spawn-tmux.js.map +1 -0
  34. package/dist/mcp/server.js +104 -65
  35. package/dist/mcp/server.js.map +1 -1
  36. package/dist/shared/config-writer.js +1 -1
  37. package/dist/shared/config.js +34 -20
  38. package/dist/shared/config.js.map +1 -1
  39. package/dist/shared/paths.js +6 -0
  40. package/dist/shared/paths.js.map +1 -1
  41. package/docs/DESIGN-INIT.md +6 -6
  42. package/docs/ONBOARDING.md +25 -25
  43. package/hooks/pre-tool-use.sh +32 -7
  44. package/launchd/{com.cc-wecom.daemon.plist.template → com.weclaude.daemon.plist.template} +3 -3
  45. package/package.json +10 -11
  46. package/scripts/install.sh +6 -6
  47. package/scripts/uninstall.sh +3 -3
  48. package/systemd/{cc-wecom.service.template → weclaude.service.template} +3 -3
@@ -1,17 +1,15 @@
1
- // MCP server `wecom`. Stdio transport. Talks to local cc-wecom daemon over HTTP
2
- // for outbound, so this server is stateless w.r.t. WSdaemon owns the socket.
1
+ // MCP server `weclaude`. Stdio transport. Single tool `wrc` = "wecom remote
2
+ // control": attaches the *current* Claude session for WeCom mirrorsession
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.
3
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
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";
5
11
  import { z } from "zod";
6
- const DAEMON_BASE = process.env.CC_WECOM_DAEMON_BASE ?? "http://127.0.0.1:17890";
7
- const post = async (path, body) => {
8
- const r = await fetch(`${DAEMON_BASE}${path}`, {
9
- method: "POST",
10
- headers: { "content-type": "application/json" },
11
- body: JSON.stringify(body),
12
- });
13
- return (await r.json().catch(() => ({})));
14
- };
12
+ const DAEMON_BASE = process.env.WECLAUDE_DAEMON_BASE ?? "http://127.0.0.1:17890";
15
13
  const ok = (data) => ({
16
14
  content: [{ type: "text", text: JSON.stringify(data) }],
17
15
  });
@@ -19,63 +17,104 @@ const fail = (msg) => ({
19
17
  isError: true,
20
18
  content: [{ type: "text", text: msg }],
21
19
  });
22
- const server = new McpServer({ name: "wecom", version: "0.0.1" }, { capabilities: { tools: {} } });
23
- server.registerTool("send_markdown", {
24
- title: "Send WeCom markdown",
25
- description: "Proactively send a markdown message to a WeCom chat (user or group).",
26
- inputSchema: {
27
- chat: z
28
- .string()
29
- .describe('Target chat: "user:<userid>" for DM, "chat:<chatid>" for group, or raw id.'),
30
- content: z.string().describe("Markdown content."),
31
- },
32
- }, async ({ chat, content }) => {
33
- const r = await post("/message", { chat, markdown: content });
34
- return r.ok ? ok({ ok: true }) : fail(`send failed: ${r.error ?? "unknown"}`);
35
- });
36
- server.registerTool("send_card", {
37
- title: "Send WeCom template card",
38
- description: "Send a structured template card (button_interaction / text_notice / news_notice / vote_interaction / multiple_interaction). Pass the full TemplateCard object as `card`.",
39
- inputSchema: {
40
- chat: z.string(),
41
- card: z.record(z.string(), z.unknown()).describe("WeCom TemplateCard object."),
42
- },
43
- }, async ({ chat, card }) => {
44
- const r = await post("/card", { chat, card });
45
- return r.ok ? ok({ ok: true, reqId: r.reqId }) : fail(`send card failed: ${r.error ?? "unknown"}`);
20
+ // claude encodes a project's cwd into a dir name by replacing each `/` with `-`
21
+ const encodeProjectDir = (absCwd) => absCwd.replace(/\//g, "-");
22
+ const findProjectDir = (cwd) => {
23
+ const enc = encodeProjectDir(cwd);
24
+ return [
25
+ join(homedir(), ".claude-internal", "projects", enc),
26
+ join(homedir(), ".claude", "projects", enc),
27
+ ].find((p) => existsSync(p));
28
+ };
29
+ const latestJsonlByMtime = (projectDir) => {
30
+ const files = readdirSync(projectDir).filter((n) => n.endsWith(".jsonl"));
31
+ if (files.length === 0)
32
+ return null;
33
+ return files
34
+ .map((n) => ({ p: join(projectDir, n), m: statSync(join(projectDir, n)).mtimeMs }))
35
+ .reduce((a, b) => (b.m > a.m ? b : a)).p;
36
+ };
37
+ const resolveCallerSession = () => {
38
+ const cwd = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
39
+ const projectDir = findProjectDir(cwd);
40
+ if (!projectDir)
41
+ return { error: `no claude project dir for cwd ${cwd}` };
42
+ // Primary: env tells us exactly which session invoked us.
43
+ const envSid = process.env.CLAUDE_CODE_SESSION_ID ?? process.env.CLAUDE_SESSION_ID;
44
+ if (envSid) {
45
+ const p = join(projectDir, `${envSid}.jsonl`);
46
+ if (existsSync(p))
47
+ return { sessionId: envSid, jsonlPath: p };
48
+ }
49
+ // Fallback: most-recently-written jsonl. Imperfect when other Claude windows
50
+ // share the cwd, but the env-var path catches that case.
51
+ const jsonlPath = latestJsonlByMtime(projectDir);
52
+ if (!jsonlPath)
53
+ return { error: `no .jsonl under ${projectDir}` };
54
+ return { sessionId: basename(jsonlPath, ".jsonl"), jsonlPath };
55
+ };
56
+ // Resolve the current pane's tmux session name. `tmux display-message -p` runs
57
+ // against the tmux server pointed at by $TMUX (set in every process running
58
+ // inside tmux), so it returns the session containing *this* pane without us
59
+ // needing to pass a target. Returns undefined if not in tmux or query failed.
60
+ const detectTmuxSession = () => new Promise((resolve) => {
61
+ if (!process.env.TMUX)
62
+ return resolve(undefined);
63
+ const p = spawn("tmux", ["display-message", "-p", "#{session_name}"], { stdio: ["ignore", "pipe", "ignore"] });
64
+ let out = "";
65
+ p.stdout?.on("data", (c) => (out += c.toString("utf8")));
66
+ p.on("error", () => resolve(undefined));
67
+ p.on("close", (code) => resolve(code === 0 ? out.trim() || undefined : undefined));
46
68
  });
47
- server.registerTool("ask_user", {
48
- title: "Ask user via WeCom button card",
49
- description: "Push a yes/no/options button card to the user, block until they click, return the selected key. Useful for in-task confirmation that needs human input.",
69
+ const server = new McpServer({ name: "weclaude", version: "0.0.1" }, { capabilities: { tools: {} } });
70
+ // Accept user-friendly prefixes from the LLM: vid:<id> user:<id>, chatid:<id> chat:<id>.
71
+ // Pass anything else (already user:/chat:/group:, or empty) through unchanged.
72
+ const normalizeTarget = (raw) => {
73
+ if (!raw)
74
+ return undefined;
75
+ if (raw.startsWith("vid:"))
76
+ return `user:${raw.slice(4)}`;
77
+ if (raw.startsWith("chatid:"))
78
+ return `chat:${raw.slice(7)}`;
79
+ return raw;
80
+ };
81
+ server.registerTool("wrc", {
82
+ title: "WeCom remote control",
83
+ description: "wecom remote control — attach current Claude session to a WeCom chat for live mirror push",
50
84
  inputSchema: {
51
- chat: z.string(),
52
- title: z.string(),
53
- detail: z.string().optional(),
54
- options: z
55
- .array(z.object({ key: z.string(), label: z.string(), style: z.number().int().optional() }))
56
- .min(1)
57
- .max(6),
58
- timeoutSec: z.number().int().positive().default(600),
85
+ target: z
86
+ .string()
87
+ .optional()
88
+ .describe('Optional push target. Accepts "vid:<userid>" (DM), "chatid:<chatid>" (group), or raw "user:<id>"/"chat:<id>". Empty → use config defaultChat / mirror.pushChat.'),
59
89
  },
60
- }, async ({ chat, title, detail, options, timeoutSec }) => {
61
- const r = await post("/ask", { chat, title, detail, options, timeoutSec });
62
- if (r.ok)
63
- return ok({ choice: r.choice });
64
- return fail(`ask failed: ${r.error ?? "unknown"}`);
65
- });
66
- server.registerTool("daemon_status", {
67
- title: "WeCom daemon status",
68
- description: "Return health / connection state of the local cc-wecom daemon.",
69
- inputSchema: {},
70
- }, async () => {
71
- try {
72
- const r = await fetch(`${DAEMON_BASE}/status`);
73
- const j = await r.json();
74
- return ok(j);
75
- }
76
- catch (e) {
77
- return fail(`daemon unreachable: ${e.message}`);
78
- }
90
+ }, async ({ target }) => {
91
+ const r = resolveCallerSession();
92
+ if ("error" in r)
93
+ return fail(r.error);
94
+ const normalizedTarget = normalizeTarget(target);
95
+ // tmux sets $TMUX_PANE for every process inside a pane (e.g. `%5`); we
96
+ // inherit it through claude → MCP child, so each /wrc auto-picks its own
97
+ // pane without the user touching config. Pane ids are not stable across
98
+ // tmux server restarts, so we also capture the session name — the daemon
99
+ // uses it to re-derive a fresh paneId after reload, and as the "user wants
100
+ // a tmux pane" signal that drives respawn when their pane dies.
101
+ const tmuxPane = process.env.TMUX_PANE?.trim();
102
+ const tmuxSession = tmuxPane ? await detectTmuxSession() : undefined;
103
+ const resp = await fetch(`${DAEMON_BASE}/mirror/attach`, {
104
+ method: "POST",
105
+ headers: { "content-type": "application/json" },
106
+ body: JSON.stringify({
107
+ sessionId: r.sessionId,
108
+ jsonlPath: r.jsonlPath,
109
+ ...(normalizedTarget ? { target: normalizedTarget } : {}),
110
+ ...(tmuxPane ? { tmuxPane } : {}),
111
+ ...(tmuxSession ? { tmuxSession } : {}),
112
+ }),
113
+ });
114
+ const j = (await resp.json().catch(() => ({})));
115
+ return j.ok
116
+ ? ok({ ok: true, sessionId: r.sessionId, target: j.target })
117
+ : fail(`attach failed: ${j.reason ?? "unknown"}`);
79
118
  });
80
119
  const transport = new StdioServerTransport();
81
120
  await server.connect(transport);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../mcp/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../mcp/server.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- // Surgical edits to ~/.cc-wecom/config.jsonc and secrets.json — preserves
1
+ // Surgical edits to ~/.weclaude/config.jsonc and secrets.json — preserves
2
2
  // comments + formatting via jsonc-parser's `modify` patches.
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import { dirname } from "node:path";
@@ -12,9 +12,14 @@ const Bot = z.object({
12
12
  const Daemon = z.object({
13
13
  host: z.string().default("127.0.0.1"),
14
14
  port: z.number().int().min(1).max(65535).default(17890),
15
- stateDir: z.string().default("~/.cc-wecom/state"),
16
- logFile: z.string().default("~/.cc-wecom/daemon.log"),
15
+ stateDir: z.string().default("~/.weclaude/state"),
16
+ logFile: z.string().default("~/.weclaude/daemon.log"),
17
17
  logLevel: z.enum(["trace", "debug", "info", "warn", "error"]).default("info"),
18
+ // 工具调用 / 授权详情页 URL。空则用 http://<host>:<port> (回环)。
19
+ // 想让手机 WeCom 也能点开, 需要在反向代理后填外网地址。桌面端用回环即可。
20
+ detailPublicBase: z.string().default(""),
21
+ // 镜像消息里给每个 tool_use 行包成 markdown 链接, 点开本地 HTML 详情页。
22
+ detailLinksInMirror: z.boolean().default(true),
18
23
  });
19
24
  const Mirror = z.object({
20
25
  // Where Claude Code writes per-project transcripts. Forks like `claude-internal`
@@ -24,17 +29,14 @@ const Mirror = z.object({
24
29
  // Pin a specific Claude session to mirror. Empty → auto-pick latest .jsonl
25
30
  // under `<projectsDir>/<encoded(wrc.cwd)>/` by mtime.
26
31
  sessionId: z.string().default(""),
27
- // Inbound (WeCom→CLI) inject target. Empty → spawn `claude --resume -p`
28
- // (response lands in jsonl but NOT in the live TTY). Set to a tmux target
29
- // (e.g. "_cc-wecom" or "_cc-wecom:0.0") to paste into the live interactive
30
- // claude — the only way to make WeCom messages visible in the CLI window.
31
- tmuxTarget: z.string().default(""),
32
32
  // Where to push live assistant output. Empty → fall back to defaultChat.
33
33
  pushChat: z.string().default(""),
34
34
  // Cap a single push payload (WeCom markdown ~2048 limit). Long replies are split.
35
35
  chunkChars: z.number().int().positive().default(1800),
36
- // Mirror the user's CLI prompts (type:"user" with string content).
37
- includeUser: z.boolean().default(true),
36
+ // Mirror the user's CLI prompts (type:"user" with string content). Off by
37
+ // default: WeCom-sourced inbounds get dedup'd anyway, and local CLI typing
38
+ // is rare in the bot-driven flow — keeping it on mostly produced echo noise.
39
+ includeUser: z.boolean().default(false),
38
40
  // Mirror assistant tool_use blocks (Bash/Edit/Read/...).
39
41
  includeTools: z.boolean().default(true),
40
42
  // Mirror tool_result blocks. Off by default — usually noisy.
@@ -43,16 +45,28 @@ const Mirror = z.object({
43
45
  toolResultMaxChars: z.number().int().positive().default(400),
44
46
  // Where inbound images/files from WeCom get saved before being pasted into
45
47
  // the live TTY. Files persist — claude reads them by absolute path.
46
- inboxDir: z.string().default("~/.cc-wecom/inbox"),
48
+ inboxDir: z.string().default("~/.weclaude/inbox"),
49
+ // Persisted mirror attachments (principal → sessionId/jsonl/tmux). Restored
50
+ // on daemon boot + lazily on first inbound after reload — so reloading the
51
+ // daemon doesn't re-spawn a fresh claude for an already-bound chat.
52
+ attachmentsFile: z.string().default("~/.weclaude/mirror-attachments.json"),
53
+ // Standalone fallback 路径(liveStream 已 closed/dead/capped) 上的防抖聚合窗口
54
+ // (ms)。窗口内同一 attachment 的多个 item 合并为一条 markdown, 抑制连续工具
55
+ // 调用刷屏。liveStream 仍活时不受影响——直接走 typewriter。0 = 关闭。
56
+ standaloneDebounceMs: z.number().int().nonnegative().default(3000),
47
57
  });
48
58
  const Wrc = z.object({
49
59
  allowFrom: z.array(z.string()).default([]),
50
60
  mode: z.enum(["headless", "mirror"]).default("headless"),
51
61
  claudeBin: z.string().default("claude"),
52
- cwd: z.string().default("~"),
53
- sessionMapFile: z.string().default("~/.cc-wecom/sessions.json"),
62
+ cwd: z.string().default("~/.weclaude/workspace"),
63
+ sessionMapFile: z.string().default("~/.weclaude/sessions.json"),
54
64
  extraArgs: z.array(z.string()).default([]),
55
65
  mirror: Mirror.default({}),
66
+ // Mirror-only: tmux session name prefix for auto-spawn. Final name is
67
+ // `${prefix}-<short>`. Auto-spawn fires when an authorized inbound finds no
68
+ // mirror attached for that chat — allowFrom IS the authorization.
69
+ tmuxPrefix: z.string().default("weclaude"),
56
70
  });
57
71
  const Approval = z.object({
58
72
  enabled: z.boolean().default(true),
@@ -83,10 +97,10 @@ export const ConfigSchema = z.object({
83
97
  });
84
98
  // ── Loader ──────────────────────────────────────────────────────────
85
99
  const DEFAULT_CONFIG_PATHS = [
86
- "~/.cc-wecom/config.jsonc",
87
- "~/.cc-wecom/config.json",
100
+ "~/.weclaude/config.jsonc",
101
+ "~/.weclaude/config.json",
88
102
  ];
89
- const SECRETS_PATH = "~/.cc-wecom/secrets.json";
103
+ const SECRETS_PATH = "~/.weclaude/secrets.json";
90
104
  const readJsoncIfExists = (p) => {
91
105
  const abs = expandHome(p);
92
106
  if (!existsSync(abs))
@@ -107,12 +121,12 @@ const deepMerge = (a, b) => {
107
121
  }
108
122
  return out;
109
123
  };
110
- /** Resolve config path: explicit > $CC_WECOM_CONFIG > defaults. */
124
+ /** Resolve config path: explicit > $WECLAUDE_CONFIG > defaults. */
111
125
  const resolveConfigPath = (explicit) => {
112
126
  if (explicit)
113
127
  return explicit;
114
- if (process.env.CC_WECOM_CONFIG)
115
- return process.env.CC_WECOM_CONFIG;
128
+ if (process.env.WECLAUDE_CONFIG)
129
+ return process.env.WECLAUDE_CONFIG;
116
130
  for (const p of DEFAULT_CONFIG_PATHS) {
117
131
  if (existsSync(expandHome(p)))
118
132
  return p;
@@ -122,7 +136,7 @@ const resolveConfigPath = (explicit) => {
122
136
  export const loadConfig = (explicitPath) => {
123
137
  const sourcePath = resolveConfigPath(explicitPath);
124
138
  if (!sourcePath) {
125
- throw new Error(`cc-wecom config not found. Create ~/.cc-wecom/config.jsonc (see config.example.jsonc) or set $CC_WECOM_CONFIG.`);
139
+ throw new Error(`weclaude config not found. Create ~/.weclaude/config.jsonc (see config.example.jsonc) or set $WECLAUDE_CONFIG.`);
126
140
  }
127
141
  const base = (readJsoncIfExists(sourcePath) ?? {});
128
142
  const secrets = (readJsoncIfExists(SECRETS_PATH) ?? {});
@@ -132,7 +146,7 @@ export const loadConfig = (explicitPath) => {
132
146
  const issues = parsed.error.issues
133
147
  .map((i) => ` - ${i.path.join(".") || "<root>"}: ${i.message}`)
134
148
  .join("\n");
135
- throw new Error(`cc-wecom config invalid (${sourcePath}):\n${issues}`);
149
+ throw new Error(`weclaude config invalid (${sourcePath}):\n${issues}`);
136
150
  }
137
151
  return { config: parsed.data, sourcePath: expandHome(sourcePath) };
138
152
  };
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../shared/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../shared/config.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,10 @@ import { homedir } from "node:os";
3
3
  import { resolve } from "node:path";
4
4
  /** Expand leading `~` and normalize. */
5
5
  export const expandHome = (p) => p.startsWith("~") ? resolve(homedir(), p.slice(p.startsWith("~/") ? 2 : 1)) : resolve(p);
6
+ // IM principals ("user:xxx" / "chat:xxx") get pasted around — copy-paste from
7
+ // WeCom UI sometimes drags along zero-width / invisible-separator chars
8
+ // (U+200B-U+200D, U+2060-U+206F, U+FEFF). They render identical but break
9
+ // `===` matches between allowFrom and the wire-side principal.
10
+ const INVISIBLE = /[​-‍⁠-]/g;
11
+ export const sanitizeId = (s) => s.replace(INVISIBLE, "").trim();
6
12
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../shared/paths.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,wCAAwC;AACxC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAC9C,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../shared/paths.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,wCAAwC;AACxC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAC9C,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3F,8EAA8E;AAC9E,wEAAwE;AACxE,0EAA0E;AAC1E,+DAA+D;AAC/D,MAAM,SAAS,GAAG,YAAY,CAAC;AAC/B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC"}
@@ -24,7 +24,7 @@
24
24
 
25
25
  如果 `config.jsonc` 整个塞进 dotfile,`secret` 就会进 git。
26
26
 
27
- **方案**:复用 `loadConfig()` 里早就有的 `secrets.json` deep-merge 钩子。init 时把 `botId/secret` 写到 `~/.cc-wecom/secrets.json`,其他写 `config.jsonc`。两份文件运行时合并。`config.jsonc` 可入 dotfiles,`secrets.json` 留本机。
27
+ **方案**:复用 `loadConfig()` 里早就有的 `secrets.json` deep-merge 钩子。init 时把 `botId/secret` 写到 `~/.weclaude/secrets.json`,其他写 `config.jsonc`。两份文件运行时合并。`config.jsonc` 可入 dotfiles,`secrets.json` 留本机。
28
28
 
29
29
  ### 3. 配置写入要保留注释
30
30
 
@@ -91,7 +91,7 @@ CLAIMED (cleared) (cleared)
91
91
  ## 演示选什么 prompt
92
92
 
93
93
  ```
94
- 1. Bash: echo hello world from cc-wecom
94
+ 1. Bash: echo hello world from weclaude
95
95
  2. Bash: sleep 3
96
96
  3. wecom__send_markdown chat="<defaultChat>" content="✅ ..."
97
97
  ```
@@ -109,7 +109,7 @@ prompt 里**显式拼出 chat id**而不是依赖 LLM 推断「default chat」
109
109
  | 场景 | init 行为 | 状态可恢复性 |
110
110
  | --- | --- | --- |
111
111
  | 用户 Ctrl-C 在 prompt 中 | 进程退出,未写任何文件 | ✅ 完全干净 |
112
- | 写完 config 但 daemon 起不来 | 抛 `daemon did not become ready` | ✅ config 保留,下次 `wrc reload` 即可 |
112
+ | 写完 config 但 daemon 起不来 | 抛 `daemon did not become ready` | ✅ config 保留,下次 `weclaude reload` 即可 |
113
113
  | Claim 超时 | 报「超时未收到消息」并退出 | ✅ daemon 还在跑,可手填 config 或重跑 init |
114
114
  | 演示 spawn `claude` 失败 | 红字打印 spawn 错误,正常退出 | ✅ 前两步成果都保留 |
115
115
 
@@ -119,7 +119,7 @@ prompt 里**显式拼出 chat id**而不是依赖 LLM 推断「default chat」
119
119
 
120
120
  不在本次范围,但留给未来:
121
121
 
122
- - `wrc init --reset` 一键清空(unsync + uninstall daemon + 删 ~/.cc-wecom
122
+ - `weclaude init --reset` 一键清空(unsync + uninstall daemon + 删 ~/.weclaude
123
123
  - claim 暗号支持自定义(防多人共用同一台 daemon 的暗号冲突)
124
- - 演示步骤后做一次 `wrc status` 的彩色断言,给用户一个「绿色对勾合集」
125
- - ink 化的 daemon dashboard(独立工具,`wrc tui`)
124
+ - 演示步骤后做一次 `weclaude status` 的彩色断言,给用户一个「绿色对勾合集」
125
+ - ink 化的 daemon dashboard(独立工具,`weclaude tui`)
@@ -1,4 +1,4 @@
1
- # cc-wecom 上手指南
1
+ # weclaude 上手指南
2
2
 
3
3
  3 步在一台新机器上把「IM 授权转发 + 远程 CC 控制」跑通。
4
4
 
@@ -13,20 +13,20 @@
13
13
 
14
14
  ```bash
15
15
  # 方式 A:npm 全局安装(推荐)
16
- npm install -g cc-wecom
17
- wrc init
16
+ npm install -g weclaude
17
+ weclaude init
18
18
 
19
19
  # 方式 B:免安装一次性试用
20
- npx cc-wecom init
20
+ npx weclaude init
21
21
 
22
22
  # 方式 C:本地开发
23
- git clone <repo> && cd cc-wecom
23
+ git clone <repo> && cd weclaude
24
24
  npm install && npm run build
25
- ./cli/wrc.sh init
25
+ ./cli/weclaude.sh init
26
26
  ```
27
27
 
28
- > ⚠️ 卸载时**先**跑 `wrc uninstall`(unsync settings.json + 卸载 daemon),**再** `npm uninstall -g cc-wecom`。否则 launchd/systemd 会反复尝试启动已删除的二进制。
29
- > `~/.cc-wecom/` 下的 config/secrets/state 不会被清掉,二次安装可无缝复用。
28
+ > ⚠️ 卸载时**先**跑 `weclaude uninstall`(unsync settings.json + 卸载 daemon),**再** `npm uninstall -g weclaude`。否则 launchd/systemd 会反复尝试启动已删除的二进制。
29
+ > `~/.weclaude/` 下的 config/secrets/state 不会被清掉,二次安装可无缝复用。
30
30
 
31
31
  ### [1/3] 采集配置
32
32
 
@@ -34,10 +34,10 @@ npm install && npm run build
34
34
 
35
35
  | 字段 | 写到 |
36
36
  | --- | --- |
37
- | botId | `~/.cc-wecom/secrets.json` |
38
- | secret | `~/.cc-wecom/secrets.json` |
39
- | Claude agent | `~/.cc-wecom/config.jsonc` (`wrc.claudeBin` + `sync.targets[0].settingsPath`) |
40
- | 是否启用 PreToolUse hook | `~/.cc-wecom/config.jsonc` (`approval.enabled`) |
37
+ | botId | `~/.weclaude/secrets.json` |
38
+ | secret | `~/.weclaude/secrets.json` |
39
+ | Claude agent | `~/.weclaude/config.jsonc` (`wrc.claudeBin` + `sync.targets[0].settingsPath`) |
40
+ | 是否启用 PreToolUse hook | `~/.weclaude/config.jsonc` (`approval.enabled`) |
41
41
 
42
42
  Agent 选项:
43
43
 
@@ -49,7 +49,7 @@ Agent 选项:
49
49
 
50
50
  完成后自动:
51
51
  1. `npx tsc` 编译 dist
52
- 2. `wrc sync` 把 hook / MCP / env 写进选定的 settings.json
52
+ 2. `weclaude sync` 把 hook / MCP / env 写进选定的 settings.json
53
53
  3. 安装常驻 daemon(macOS launchd / Linux systemd --user)
54
54
  4. 等 WebSocket 鉴权通过
55
55
 
@@ -75,7 +75,7 @@ Daemon 在内存里临时打开 claim 窗口(10 分钟)。这条消息精确
75
75
  CLI 自动 `spawn claude -p` 跑一条三步指令:
76
76
 
77
77
  ```
78
- 1. Bash: echo hello world from cc-wecom ← 触发 PreToolUse hook
78
+ 1. Bash: echo hello world from weclaude ← 触发 PreToolUse hook
79
79
  2. Bash: sleep 3 ← 再触发一次
80
80
  3. wecom__send_markdown ← 通过 MCP 主动推送结果
81
81
  ```
@@ -85,34 +85,34 @@ CLI 自动 `spawn claude -p` 跑一条三步指令:
85
85
  - IM 收到按钮卡片:`授权请求: Bash`
86
86
  - 点 ✅ → 卡片就地刷新成 `✅ Bash · 已允许`
87
87
  - 3 秒后再来一张卡片(或被 5 分钟自动窗口短路)
88
- - 最终收到 `✅ cc-wecom 演示完成:hello world`
88
+ - 最终收到 `✅ weclaude 演示完成:hello world`
89
89
 
90
90
  如果第 1 步选「不开 hook」,会跳过演示。
91
91
 
92
92
  ## 完成后
93
93
 
94
94
  ```bash
95
- wrc status # daemon + WS 健康
96
- wrc logs -f # 实时日志
97
- wrc send <chat> <text> # 主动推消息
98
- wrc unsync # 卸载 hook/MCP(保留 daemon)
95
+ weclaude status # daemon + WS 健康
96
+ weclaude logs -f # 实时日志
97
+ weclaude send <chat> <text> # 主动推消息
98
+ weclaude unsync # 卸载 hook/MCP(保留 daemon)
99
99
  ```
100
100
 
101
101
  ## 排错
102
102
 
103
103
  | 现象 | 处理 |
104
104
  | --- | --- |
105
- | `daemon: down` | `wrc reload`;看 `~/.cc-wecom/daemon.stderr.log` |
106
- | 发完暗号 daemon 没反应 | 检查 `wrc status` 的 `wsConnected` 是不是 true;机器人 `secret` 错会卡在 auth |
107
- | Hook 不触发 | `cat ~/.claude/settings.json | jq .hooks.PreToolUse`;`wrc sync` 重写 |
105
+ | `daemon: down` | `weclaude reload`;看 `~/.weclaude/daemon.stderr.log` |
106
+ | 发完暗号 daemon 没反应 | 检查 `weclaude status` 的 `wsConnected` 是不是 true;机器人 `secret` 错会卡在 auth |
107
+ | Hook 不触发 | `cat ~/.claude/settings.json | jq .hooks.PreToolUse`;`weclaude sync` 重写 |
108
108
  | 卡片点了没反应 | 5 秒内才能就地更新;超时是正常情况,决策仍然生效 |
109
- | MCP 调用 404 | `mcpServers.wecom._managedBy=="cc-wecom"` 应在 settings.json;`wrc sync` 修复 |
109
+ | MCP 调用 404 | `mcpServers.wecom._managedBy=="weclaude"` 应在 settings.json;`weclaude sync` 修复 |
110
110
 
111
111
  ## 多机部署
112
112
 
113
113
  `config.jsonc` 可以纳入 dotfiles;`secrets.json` 每台机器独立填。`init` 跑过一次后,第二台机器:
114
114
 
115
115
  ```bash
116
- cp ~/dotfiles/cc-wecom-config.jsonc ~/.cc-wecom/config.jsonc
117
- ./cli/wrc.sh init # 跳过覆盖提示,但仍走 claim 步骤拿到本机的 IM principal
116
+ cp ~/dotfiles/weclaude-config.jsonc ~/.weclaude/config.jsonc
117
+ ./cli/weclaude.sh init # 跳过覆盖提示,但仍走 claim 步骤拿到本机的 IM principal
118
118
  ```
@@ -1,18 +1,43 @@
1
1
  #!/usr/bin/env bash
2
- # cc-wecom PreToolUse hook: forward to local daemon → long-poll → emit decision.
2
+ # weclaude PreToolUse hook: forward to local daemon → long-poll → emit decision.
3
3
  # Any failure → ask (never break workflow).
4
4
  set -uo pipefail
5
5
 
6
- DAEMON_URL="${CC_WECOM_DAEMON_URL:-http://127.0.0.1:17890/approve}"
7
- HOOK_TIMEOUT="${CC_WECOM_HOOK_TIMEOUT:-1810}"
6
+ DAEMON_URL="${WECLAUDE_DAEMON_URL:-http://127.0.0.1:17890/approve}"
7
+ HOOK_TIMEOUT="${WECLAUDE_HOOK_TIMEOUT:-1810}"
8
+ STATE_DIR="${WECLAUDE_STATE_DIR:-$HOME/.weclaude/state}"
9
+ # Fallback policy when the daemon is unreachable / replies garbage. ask|allow|deny.
10
+ # Default keeps the safe behavior; set to `allow` in trusted local-only setups.
11
+ FALLBACK="${WECLAUDE_HOOK_FALLBACK:-ask}"
8
12
 
9
13
  emit() {
10
14
  local decision="$1" reason="${2:-}"
11
- printf '%s\n' "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"${decision}\",\"permissionDecisionReason\":\"cc-wecom: ${reason}\"}}"
15
+ printf '%s\n' "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"${decision}\",\"permissionDecisionReason\":\"weclaude: ${reason}\"}}"
12
16
  exit 0
13
17
  }
14
18
  ask() { emit "ask" "${1:-bridge unreachable}"; }
15
19
 
20
+ # Daemon-down fallback. Consults the persisted auto-approve window first so a
21
+ # session-level "allow N min" survives daemon restart / outage; otherwise falls
22
+ # back to FALLBACK. SESSION_ID must already be parsed.
23
+ bridge_down() {
24
+ local reason="$1"
25
+ local sf="$STATE_DIR/auto-windows.json"
26
+ if [[ -n "${SESSION_ID:-}" && -r "$sf" ]] && command -v jq >/dev/null 2>&1; then
27
+ local active
28
+ active=$(jq -r --arg s "$SESSION_ID" \
29
+ 'if (.windows[$s].until // 0) > (now * 1000) then "1" else "0" end' \
30
+ "$sf" 2>/dev/null) || active=""
31
+ if [[ "$active" == "1" ]]; then
32
+ emit "allow" "auto-window (offline): $reason"
33
+ fi
34
+ fi
35
+ case "$FALLBACK" in
36
+ allow|deny|ask) emit "$FALLBACK" "$reason" ;;
37
+ *) emit "ask" "$reason" ;;
38
+ esac
39
+ }
40
+
16
41
  PAYLOAD=$(cat) || ask "stdin read failed"
17
42
  command -v jq >/dev/null 2>&1 || ask "jq missing"
18
43
 
@@ -70,12 +95,12 @@ BODY=$(jq -nc \
70
95
  RESP=$(curl -sS --max-time "$HOOK_TIMEOUT" \
71
96
  -H 'Content-Type: application/json' \
72
97
  -d "$BODY" \
73
- "$DAEMON_URL" 2>/dev/null) || ask "daemon curl failed"
98
+ "$DAEMON_URL" 2>/dev/null) || bridge_down "daemon curl failed"
74
99
 
75
- DECISION=$(printf '%s' "$RESP" | jq -r '.decision // "ask"' 2>/dev/null) || ask "bad daemon response"
100
+ DECISION=$(printf '%s' "$RESP" | jq -r '.decision // "ask"' 2>/dev/null) || bridge_down "bad daemon response"
76
101
  REASON=$(printf '%s' "$RESP" | jq -r '.reason // ""' 2>/dev/null)
77
102
 
78
103
  case "$DECISION" in
79
104
  allow|deny|ask) emit "$DECISION" "$REASON" ;;
80
- *) ask "unknown decision: $DECISION" ;;
105
+ *) bridge_down "unknown decision: $DECISION" ;;
81
106
  esac