cc-vision-hook 0.1.1 → 0.2.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 (44) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +31 -7
  3. package/README.zh-CN.md +31 -7
  4. package/dist/claudeMcp.d.ts +29 -0
  5. package/dist/claudeMcp.js +85 -0
  6. package/dist/claudeMcp.js.map +1 -0
  7. package/dist/cli.d.ts +2 -1
  8. package/dist/cli.js +22 -2
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/configCmd.js +18 -5
  11. package/dist/commands/configCmd.js.map +1 -1
  12. package/dist/commands/doctor.js +29 -1
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/init.d.ts +16 -0
  15. package/dist/commands/init.js +112 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/commands/install.d.ts +3 -1
  18. package/dist/commands/install.js +13 -5
  19. package/dist/commands/install.js.map +1 -1
  20. package/dist/commands/mcpCmd.d.ts +29 -0
  21. package/dist/commands/mcpCmd.js +58 -0
  22. package/dist/commands/mcpCmd.js.map +1 -0
  23. package/dist/commands/status.js +6 -0
  24. package/dist/commands/status.js.map +1 -1
  25. package/dist/commands/testImage.js +1 -7
  26. package/dist/commands/testImage.js.map +1 -1
  27. package/dist/config.d.ts +8 -2
  28. package/dist/config.js +16 -1
  29. package/dist/config.js.map +1 -1
  30. package/dist/imageMime.d.ts +14 -0
  31. package/dist/imageMime.js +22 -0
  32. package/dist/imageMime.js.map +1 -0
  33. package/dist/mcpServer.d.ts +31 -0
  34. package/dist/mcpServer.js +141 -0
  35. package/dist/mcpServer.js.map +1 -0
  36. package/dist/pasteScanner.js +1 -7
  37. package/dist/pasteScanner.js.map +1 -1
  38. package/dist/sdk/index.d.ts +2 -0
  39. package/dist/sdk/index.js +2 -0
  40. package/dist/sdk/index.js.map +1 -1
  41. package/dist/vision.d.ts +13 -1
  42. package/dist/vision.js +58 -17
  43. package/dist/vision.js.map +1 -1
  44. package/package.json +4 -2
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `cvh init` 命令实现:交互式安装向导,一步到位完成
3
+ * 「选 provider → 填 model/baseUrl/apiKey → 写配置 → 注册 Hook → 可选注册 MCP → 可选立即 enable」。
4
+ *
5
+ * 设计取舍:
6
+ * - 只在 TTY 环境下可用(`process.stdin.isTTY`),非交互环境(CI/脚本管道)直接报错并提示
7
+ * 改用 `cvh install` + `cvh config set` 组合命令,避免卡在 readline 等待输入。
8
+ * - 不提供 `--json` 模式——`init` 的本质是"人工问答",脚本化场景应该走 `install`/`config set`,
9
+ * 这与其他命令的 `--json` 支持约定不冲突(`init` 本来就不是给脚本用的)。
10
+ */
11
+ import { createInterface } from "node:readline/promises";
12
+ import { DEFAULT_CONFIG, configFileExists, getConfigPath, loadConfig, saveConfig } from "../config.js";
13
+ import { installHooks } from "../claudeSettings.js";
14
+ import { installMcpServer } from "../claudeMcp.js";
15
+ const VALID_PROVIDERS = ["oai", "responses", "anthropic", "gemini"];
16
+ /** provider -> 默认模型名的建议值,减少用户输入负担(可直接回车采用默认值)。 */
17
+ const DEFAULT_MODEL_BY_PROVIDER = {
18
+ oai: "gpt-4o-mini",
19
+ responses: "gpt-4o-mini",
20
+ anthropic: "claude-3-5-sonnet-latest",
21
+ gemini: "gemini-2.5-flash",
22
+ };
23
+ /**
24
+ * 向用户提问一行文字,返回去除首尾空白的回答;回答为空时使用 `defaultValue`。
25
+ *
26
+ * @param rl - readline 接口实例
27
+ * @param question - 提示文字(不含默认值展示,由调用方自行拼接)
28
+ * @param defaultValue - 用户直接回车时采用的默认值
29
+ * @returns 用户输入或默认值
30
+ */
31
+ const ask = async (rl, question, defaultValue) => {
32
+ const suffix = defaultValue ? ` [${defaultValue}]` : "";
33
+ const answer = (await rl.question(`${question}${suffix}: `)).trim();
34
+ return answer || defaultValue || "";
35
+ };
36
+ /**
37
+ * 向用户提问一个 y/n 问题。
38
+ *
39
+ * @param rl - readline 接口实例
40
+ * @param question - 提示文字
41
+ * @param defaultYes - 用户直接回车时是否视为"是"
42
+ * @returns 用户的选择
43
+ */
44
+ const askYesNo = async (rl, question, defaultYes) => {
45
+ const suffix = defaultYes ? "[Y/n]" : "[y/N]";
46
+ const answer = (await rl.question(`${question} ${suffix}: `)).trim().toLowerCase();
47
+ if (!answer)
48
+ return defaultYes;
49
+ return answer === "y" || answer === "yes";
50
+ };
51
+ /**
52
+ * 运行交互式安装向导。
53
+ *
54
+ * @throws 当 stdin 不是 TTY(非交互环境)时抛出错误,提示改用 `install`/`config set`
55
+ */
56
+ export const runInit = async () => {
57
+ if (!process.stdin.isTTY) {
58
+ throw new Error("cvh init 需要交互式终端(TTY),当前环境不支持。非交互场景请改用:\n" +
59
+ " cvh install && cvh config set provider <provider> && cvh config set model <model> && cvh config set apiKey <key> && cvh enable");
60
+ }
61
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
62
+ try {
63
+ console.log("cc-vision-hook 交互式安装向导\n");
64
+ const existed = await configFileExists();
65
+ const current = existed ? await loadConfig() : { ...DEFAULT_CONFIG };
66
+ if (existed) {
67
+ console.log(`检测到已有配置(${getConfigPath()}),当前值将作为默认值,直接回车可保留。\n`);
68
+ }
69
+ let provider = current.provider;
70
+ // eslint-disable-next-line no-constant-condition
71
+ while (true) {
72
+ const input = await ask(rl, `视觉模型上游 provider(可选:${VALID_PROVIDERS.join("/")})`, current.provider);
73
+ if (VALID_PROVIDERS.includes(input)) {
74
+ provider = input;
75
+ break;
76
+ }
77
+ console.log(`⚠️ 不支持的 provider:${input},请重新输入`);
78
+ }
79
+ const model = await ask(rl, "视觉模型名", current.model !== DEFAULT_CONFIG.model ? current.model : DEFAULT_MODEL_BY_PROVIDER[provider]);
80
+ const baseUrlInput = await ask(rl, "上游 API base URL(留空使用 provider 官方默认地址)", current.baseUrl ?? "");
81
+ // apiKey 单独处理:不能像其他字段那样把"脱敏展示值"直接当默认值塞回 ask()——
82
+ // 那样用户直接回车时,写入配置的就会是 "sk-xxx***" 这段脱敏字符串本身,而不是真实 key。
83
+ // 直接问一个新值,用户想保留原 key 时留空即可。
84
+ const apiKeyPrompt = current.apiKey ? `API Key(当前已设置 ${current.apiKey.slice(0, 6)}***,回车保留)` : "API Key";
85
+ const apiKeyInput = (await rl.question(`${apiKeyPrompt}: `)).trim();
86
+ const resolvedApiKey = apiKeyInput || current.apiKey;
87
+ const installMcp = await askYesNo(rl, "是否同时注册 MCP server(vision_ask 等追问工具,与主开关无关)", false);
88
+ const enableNow = await askYesNo(rl, "是否立即启用(enabled=true)", true);
89
+ const finalConfig = {
90
+ ...current,
91
+ provider,
92
+ model,
93
+ baseUrl: baseUrlInput || undefined,
94
+ apiKey: resolvedApiKey || undefined,
95
+ enabled: enableNow,
96
+ };
97
+ await saveConfig(finalConfig);
98
+ const hooksAdded = await installHooks();
99
+ const mcpChanged = installMcp ? await installMcpServer() : false;
100
+ console.log("\n✅ cvh 初始化完成");
101
+ console.log(` 配置文件:${getConfigPath()}`);
102
+ console.log(` Provider / 模型:${provider} / ${model}`);
103
+ console.log(` 新增 Hook 注册数:${hooksAdded}`);
104
+ console.log(` MCP server:${installMcp ? (mcpChanged ? "已注册" : "已经是最新状态") : "未注册(可后续运行 cvh mcp install)"}`);
105
+ console.log(` 开关状态:${enableNow ? "已启用" : "已停用(运行 cvh enable 手动启用)"}`);
106
+ console.log("\n建议运行 `cvh doctor` 验证配置和连通性。");
107
+ }
108
+ finally {
109
+ rl.close();
110
+ }
111
+ };
112
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,9 @@
8
8
  */
9
9
  export declare const runInstall: (jsonOutput: boolean) => Promise<void>;
10
10
  /**
11
- * 卸载 cvh:移除 Hook 注册,可选连带删除配置和缓存。
11
+ * 卸载 cvh:移除 Hook 注册 + MCP server 注册,可选连带删除配置和缓存。
12
+ * MCP 注册无论是否 `--purge` 都会移除——保留配置/缓存但留一个孤立的 MCP server 注册
13
+ * 没有意义(用户显式执行了 uninstall,说明不想再让 Claude Code 感知到 cvh 的存在)。
12
14
  *
13
15
  * @param purge - 是否连带删除配置文件和缓存目录
14
16
  * @param jsonOutput - 是否以 JSON 格式输出结果
@@ -2,16 +2,20 @@
2
2
  * `cvh install` / `cvh uninstall` 命令实现。
3
3
  */
4
4
  import { rm } from "node:fs/promises";
5
- import { DEFAULT_CONFIG, getConfigPath, getCvhHomeDir, loadConfig, saveConfig } from "../config.js";
5
+ import { DEFAULT_CONFIG, configFileExists, getConfigPath, getCvhHomeDir, saveConfig } from "../config.js";
6
6
  import { installHooks, uninstallHooks } from "../claudeSettings.js";
7
+ import { uninstallMcpServer } from "../claudeMcp.js";
7
8
  /**
8
9
  * 安装 cvh:创建配置文件(若不存在)+ 注册 Hook。幂等,可重复执行。
9
10
  *
10
11
  * @param jsonOutput - 是否以 JSON 格式输出结果
11
12
  */
12
13
  export const runInstall = async (jsonOutput) => {
13
- const existing = await loadConfig().catch(() => null);
14
- if (!existing)
14
+ // 注意:不能用 loadConfig().catch(...) 判断文件是否存在——loadConfig() 内部自带
15
+ // try/catch 兜底,文件不存在时会静默返回默认配置对象而不是抛错,外层 catch 永远不会
16
+ // 触发。之前的实现正是因为这个假设错误,导致 cvh install 从未真正创建过配置文件。
17
+ const existed = await configFileExists();
18
+ if (!existed)
15
19
  await saveConfig(DEFAULT_CONFIG);
16
20
  const added = await installHooks();
17
21
  if (jsonOutput) {
@@ -25,23 +29,27 @@ export const runInstall = async (jsonOutput) => {
25
29
  console.log(` ⚠️ cvh 仅对"静默忽略图片"型模型有效,对协议层硬拒绝型模型(如某些不支持视觉的模型)无效,详见 README`);
26
30
  };
27
31
  /**
28
- * 卸载 cvh:移除 Hook 注册,可选连带删除配置和缓存。
32
+ * 卸载 cvh:移除 Hook 注册 + MCP server 注册,可选连带删除配置和缓存。
33
+ * MCP 注册无论是否 `--purge` 都会移除——保留配置/缓存但留一个孤立的 MCP server 注册
34
+ * 没有意义(用户显式执行了 uninstall,说明不想再让 Claude Code 感知到 cvh 的存在)。
29
35
  *
30
36
  * @param purge - 是否连带删除配置文件和缓存目录
31
37
  * @param jsonOutput - 是否以 JSON 格式输出结果
32
38
  */
33
39
  export const runUninstall = async (purge, jsonOutput) => {
34
40
  const removed = await uninstallHooks();
41
+ const mcpRemoved = await uninstallMcpServer();
35
42
  if (purge) {
36
43
  await rm(getConfigPath(), { force: true });
37
44
  await rm(getCvhHomeDir(), { recursive: true, force: true });
38
45
  }
39
46
  if (jsonOutput) {
40
- console.log(JSON.stringify({ ok: true, hooksRemoved: removed, purged: purge }));
47
+ console.log(JSON.stringify({ ok: true, hooksRemoved: removed, mcpRemoved, purged: purge }));
41
48
  return;
42
49
  }
43
50
  console.log("✅ cvh 卸载完成");
44
51
  console.log(` 移除 Hook 注册数:${removed}`);
52
+ console.log(` MCP server 注册:${mcpRemoved ? "已移除" : "未发现(无需移除)"}`);
45
53
  if (purge)
46
54
  console.log(" 已删除配置文件与缓存目录(--purge)");
47
55
  };
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEpE;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACrE,MAAM,QAAQ,GAAG,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,QAAQ;QAAE,MAAM,UAAU,CAAC,cAAc,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;IAEnC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1F,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,sBAAsB,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,KAAc,EAAE,UAAmB,EAAiB,EAAE;IACvF,MAAM,OAAO,GAAG,MAAM,cAAc,EAAE,CAAC;IACvC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAChF,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;IACzC,IAAI,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AACrD,CAAC,CAAC"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1G,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACrE,6DAA6D;IAC7D,oDAAoD;IACpD,iDAAiD;IACjD,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACzC,IAAI,CAAC,OAAO;QAAE,MAAM,UAAU,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;IAEnC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1F,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,sBAAsB,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,KAAc,EAAE,UAAmB,EAAiB,EAAE;IACvF,MAAM,OAAO,GAAG,MAAM,cAAc,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC9C,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC5F,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,oBAAoB,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACpE,IAAI,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AACrD,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `cvh mcp install` / `cvh mcp uninstall` / `cvh mcp serve` 命令实现。
3
+ *
4
+ * 三个子命令与主开关(enabled)完全独立:install/uninstall 只负责注册/移除
5
+ * `~/.claude.json` 里的 MCP server 条目,serve 才是真正跑 stdio server 的长驻进程入口。
6
+ */
7
+ /**
8
+ * 安装 MCP server 注册(幂等)。
9
+ *
10
+ * @param jsonOutput - 是否以 JSON 格式输出结果
11
+ */
12
+ export declare const runMcpInstall: (jsonOutput: boolean) => Promise<void>;
13
+ /**
14
+ * 卸载 MCP server 注册。
15
+ *
16
+ * @param jsonOutput - 是否以 JSON 格式输出结果
17
+ */
18
+ export declare const runMcpUninstall: (jsonOutput: boolean) => Promise<void>;
19
+ /**
20
+ * 打印 MCP 注册状态(供 `cvh mcp status` 或整合进 `cvh status` 使用)。
21
+ *
22
+ * @param jsonOutput - 是否以 JSON 格式输出结果
23
+ */
24
+ export declare const runMcpStatus: (jsonOutput: boolean) => Promise<void>;
25
+ /**
26
+ * 以 stdio 模式启动 MCP server(由 Claude Code 作为子进程调起,不应由用户手动运行)。
27
+ * 这是一个长驻进程,函数不会主动退出。
28
+ */
29
+ export declare const runMcpServe: () => Promise<void>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `cvh mcp install` / `cvh mcp uninstall` / `cvh mcp serve` 命令实现。
3
+ *
4
+ * 三个子命令与主开关(enabled)完全独立:install/uninstall 只负责注册/移除
5
+ * `~/.claude.json` 里的 MCP server 条目,serve 才是真正跑 stdio server 的长驻进程入口。
6
+ */
7
+ import { installMcpServer, uninstallMcpServer, checkMcpInstalled } from "../claudeMcp.js";
8
+ import { serveMcpStdio } from "../mcpServer.js";
9
+ /**
10
+ * 安装 MCP server 注册(幂等)。
11
+ *
12
+ * @param jsonOutput - 是否以 JSON 格式输出结果
13
+ */
14
+ export const runMcpInstall = async (jsonOutput) => {
15
+ const changed = await installMcpServer();
16
+ if (jsonOutput) {
17
+ console.log(JSON.stringify({ ok: true, changed }));
18
+ return;
19
+ }
20
+ console.log("✅ cvh MCP server 已注册到 ~/.claude.json");
21
+ console.log(` ${changed ? "本次为新增/更新条目" : "已经是最新状态,未发生变化"}`);
22
+ console.log(" 工具:vision_ask / vision_describe_image / vision_describe_data_url");
23
+ console.log(" ⚠️ MCP 与主开关(enabled)无关,即使 cvh disable,Agent 仍可主动调用这些工具解析图片");
24
+ };
25
+ /**
26
+ * 卸载 MCP server 注册。
27
+ *
28
+ * @param jsonOutput - 是否以 JSON 格式输出结果
29
+ */
30
+ export const runMcpUninstall = async (jsonOutput) => {
31
+ const removed = await uninstallMcpServer();
32
+ if (jsonOutput) {
33
+ console.log(JSON.stringify({ ok: true, removed }));
34
+ return;
35
+ }
36
+ console.log(removed ? "✅ 已从 ~/.claude.json 移除 cc-vision-hook MCP server" : "⚠️ 未发现已注册的 MCP server,无需移除");
37
+ };
38
+ /**
39
+ * 打印 MCP 注册状态(供 `cvh mcp status` 或整合进 `cvh status` 使用)。
40
+ *
41
+ * @param jsonOutput - 是否以 JSON 格式输出结果
42
+ */
43
+ export const runMcpStatus = async (jsonOutput) => {
44
+ const installed = await checkMcpInstalled();
45
+ if (jsonOutput) {
46
+ console.log(JSON.stringify({ installed }));
47
+ return;
48
+ }
49
+ console.log(`MCP server 注册:${installed ? "✅ 已注册" : "❌ 未注册(运行 cvh mcp install)"}`);
50
+ };
51
+ /**
52
+ * 以 stdio 模式启动 MCP server(由 Claude Code 作为子进程调起,不应由用户手动运行)。
53
+ * 这是一个长驻进程,函数不会主动退出。
54
+ */
55
+ export const runMcpServe = async () => {
56
+ await serveMcpStdio();
57
+ };
58
+ //# sourceMappingURL=mcpCmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpCmd.js","sourceRoot":"","sources":["../../src/commands/mcpCmd.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACxE,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACzC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;IACnF,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IAC1E,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,kDAAkD,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;AAC5G,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACvE,MAAM,SAAS,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC5C,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,iBAAiB,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAC,CAAC;AACpF,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,IAAmB,EAAE;IACnD,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC,CAAC"}
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { loadConfig, getConfigPath } from "../config.js";
5
5
  import { checkHooksInstalled } from "../claudeSettings.js";
6
+ import { checkMcpInstalled } from "../claudeMcp.js";
6
7
  import { countCacheEntries, getCacheDiskUsage } from "../cache.js";
7
8
  /**
8
9
  * 打印当前 cvh 的运行状态。
@@ -12,6 +13,9 @@ import { countCacheEntries, getCacheDiskUsage } from "../cache.js";
12
13
  export const runStatus = async (jsonOutput) => {
13
14
  const config = await loadConfig();
14
15
  const hooks = await checkHooksInstalled();
16
+ // MCP 注册状态实时读取 ~/.claude.json,而不是 config.mcpInstalled 静态字段——
17
+ // 后者仅作展示用途的历史字段,不会被 mcp install/uninstall 更新,容易与真实状态不一致。
18
+ const mcpInstalled = await checkMcpInstalled();
15
19
  const cacheCount = await countCacheEntries();
16
20
  const cacheBytes = await getCacheDiskUsage();
17
21
  const result = {
@@ -20,6 +24,7 @@ export const runStatus = async (jsonOutput) => {
20
24
  model: config.model,
21
25
  configPath: getConfigPath(),
22
26
  hooksInstalled: hooks,
27
+ mcpInstalled,
23
28
  cache: { entries: cacheCount, bytes: cacheBytes, ttlDays: config.cache.ttlDays },
24
29
  };
25
30
  if (jsonOutput) {
@@ -30,6 +35,7 @@ export const runStatus = async (jsonOutput) => {
30
35
  console.log(`视觉 provider:${config.provider} / 模型:${config.model}`);
31
36
  console.log(`配置文件:${config.enabled ? "" : ""}${getConfigPath()}`);
32
37
  console.log(`Hook 注册:UserPromptSubmit=${hooks.userPromptSubmit ? "✅" : "❌"} PostToolUse=${hooks.postToolUse ? "✅" : "❌"}`);
38
+ console.log(`MCP server:${mcpInstalled ? "✅ 已注册" : "❌ 未注册(运行 cvh mcp install)"}`);
33
39
  console.log(`本地缓存:${cacheCount} 条,约 ${(cacheBytes / 1024).toFixed(1)} KB,TTL ${config.cache.ttlDays} 天`);
34
40
  };
35
41
  //# sourceMappingURL=status.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACpE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAE7C,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,UAAU,EAAE,aAAa,EAAE;QAC3B,cAAc,EAAE,KAAK;QACrB,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;KACjF,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,SAAS,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,aAAa,EAAE,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3H,OAAO,CAAC,GAAG,CAAC,QAAQ,UAAU,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAC3G,CAAC,CAAC"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAmB,EAAiB,EAAE;IACpE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC1C,6DAA6D;IAC7D,yDAAyD;IACzD,MAAM,YAAY,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAE7C,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,UAAU,EAAE,aAAa,EAAE;QAC3B,cAAc,EAAE,KAAK;QACrB,YAAY;QACZ,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;KACjF,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,QAAQ,SAAS,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,aAAa,EAAE,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,gBAAgB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3H,OAAO,CAAC,GAAG,CAAC,cAAc,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,QAAQ,UAAU,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAC3G,CAAC,CAAC"}
@@ -5,13 +5,7 @@ import { readFile } from "node:fs/promises";
5
5
  import { extname } from "node:path";
6
6
  import { loadConfig } from "../config.js";
7
7
  import { describeImage } from "../vision.js";
8
- const EXT_TO_MIME = {
9
- ".png": "image/png",
10
- ".jpg": "image/jpeg",
11
- ".jpeg": "image/jpeg",
12
- ".webp": "image/webp",
13
- ".gif": "image/gif",
14
- };
8
+ import { EXT_TO_MIME } from "../imageMime.js";
15
9
  /**
16
10
  * 读取本地图片文件,调用当前配置的视觉模型解析并打印结果。
17
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"testImage.js","sourceRoot":"","sources":["../../src/commands/testImage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,IAAY,EAAE,UAAmB,EAAiB,EAAE;IACrF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,4BAA4B,CAAC,CAAC;IAE7E,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAErF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAErC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAClE,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,MAAM,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC3B,CAAC,CAAC"}
1
+ {"version":3,"file":"testImage.js","sourceRoot":"","sources":["../../src/commands/testImage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,IAAY,EAAE,UAAmB,EAAiB,EAAE;IACrF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,4BAA4B,CAAC,CAAC;IAE7E,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAErF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAErC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAClE,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,MAAM,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC3B,CAAC,CAAC"}
package/dist/config.d.ts CHANGED
@@ -26,8 +26,6 @@ export interface CvhConfig {
26
26
  cache: {
27
27
  ttlDays: number;
28
28
  };
29
- /** 是否已安装 MCP server(仅用于 status/doctor 展示,不参与开关逻辑)。 */
30
- mcpInstalled: boolean;
31
29
  }
32
30
  export declare const DEFAULT_CONFIG: CvhConfig;
33
31
  /**
@@ -51,6 +49,14 @@ export declare const getConfigPath: () => string;
51
49
  * @returns 合并后的配置对象
52
50
  */
53
51
  export declare const loadConfig: () => Promise<CvhConfig>;
52
+ /**
53
+ * 检查配置文件是否已存在于磁盘(区别于 `loadConfig()`——后者文件不存在时会静默兜底返回
54
+ * 默认配置对象,不能用来判断"文件是否真的存在",`cvh install` 需要这个区分来决定是否要
55
+ * 首次落盘写入默认配置)。
56
+ *
57
+ * @returns 配置文件是否存在
58
+ */
59
+ export declare const configFileExists: () => Promise<boolean>;
54
60
  /**
55
61
  * 写入配置文件,并设置 `0600` 权限(仅当前用户可读写,因为里面可能存明文 API key)。
56
62
  *
package/dist/config.js CHANGED
@@ -12,7 +12,6 @@ export const DEFAULT_CONFIG = {
12
12
  timeoutMs: 45000,
13
13
  maxTokens: 1200,
14
14
  cache: { ttlDays: 7 },
15
- mcpInstalled: false,
16
15
  };
17
16
  /**
18
17
  * Claude Code 配置根目录(即 `~/.claude`)。
@@ -44,6 +43,22 @@ export const loadConfig = async () => {
44
43
  return { ...DEFAULT_CONFIG };
45
44
  }
46
45
  };
46
+ /**
47
+ * 检查配置文件是否已存在于磁盘(区别于 `loadConfig()`——后者文件不存在时会静默兜底返回
48
+ * 默认配置对象,不能用来判断"文件是否真的存在",`cvh install` 需要这个区分来决定是否要
49
+ * 首次落盘写入默认配置)。
50
+ *
51
+ * @returns 配置文件是否存在
52
+ */
53
+ export const configFileExists = async () => {
54
+ try {
55
+ await readFile(getConfigPath(), "utf8");
56
+ return true;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ };
47
62
  /**
48
63
  * 写入配置文件,并设置 `0600` 权限(仅当前用户可读写,因为里面可能存明文 API key)。
49
64
  *
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6B1C,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,aAAa;IACpB,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,IAAI;IACf,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;IACrB,YAAY,EAAE,KAAK;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAExG,qDAAqD;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAEtF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,qBAAqB,CAAC,CAAC;AAE3F;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAwB,EAAE;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QACrD,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,MAAiB,EAAiB,EAAE;IACnE,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,8CAA8C;IAC9C,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAuB,EAAE;IACvD,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,SAAS;QAAE,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,MAAM,CAAC;IACrI,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAA2B,CAAC;IAC3F,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS;QAAE,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IACnE,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC3E,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW;QAAE,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACxE,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,SAAS,CAAC,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,SAAS,CAAC,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzF,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAwB,EAAE;IAC1D,MAAM,UAAU,GAAG,MAAM,UAAU,EAAE,CAAC;IACtC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;IACxC,6EAA6E;IAC7E,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;AACrE,CAAC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 图片文件扩展名 -> MIME 类型的共享映射表。
3
+ *
4
+ * 之前 `pasteScanner.ts`/`testImage.ts` 各自维护了一份相同的映射,MCP 的
5
+ * `vision_describe_image` 工具也需要同样的逻辑,抽成单一来源避免三处漂移。
6
+ */
7
+ export declare const EXT_TO_MIME: Record<string, string>;
8
+ /**
9
+ * 根据文件路径的扩展名推断 MIME 类型。
10
+ *
11
+ * @param path - 文件路径(只看扩展名,不检查文件是否存在)
12
+ * @returns 识别出的 MIME 类型,扩展名未知时返回 undefined
13
+ */
14
+ export declare const mimeFromPath: (path: string) => string | undefined;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 图片文件扩展名 -> MIME 类型的共享映射表。
3
+ *
4
+ * 之前 `pasteScanner.ts`/`testImage.ts` 各自维护了一份相同的映射,MCP 的
5
+ * `vision_describe_image` 工具也需要同样的逻辑,抽成单一来源避免三处漂移。
6
+ */
7
+ import { extname } from "node:path";
8
+ export const EXT_TO_MIME = {
9
+ ".png": "image/png",
10
+ ".jpg": "image/jpeg",
11
+ ".jpeg": "image/jpeg",
12
+ ".webp": "image/webp",
13
+ ".gif": "image/gif",
14
+ };
15
+ /**
16
+ * 根据文件路径的扩展名推断 MIME 类型。
17
+ *
18
+ * @param path - 文件路径(只看扩展名,不检查文件是否存在)
19
+ * @returns 识别出的 MIME 类型,扩展名未知时返回 undefined
20
+ */
21
+ export const mimeFromPath = (path) => EXT_TO_MIME[extname(path).toLowerCase()];
22
+ //# sourceMappingURL=imageMime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageMime.js","sourceRoot":"","sources":["../src/imageMime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAsB,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * MCP stdio server:暴露 `vision_ask` / `vision_describe_image` / `vision_describe_data_url`
3
+ * 三个工具,让 Claude 主模型在对话中可以主动追问此前已被 Hook 处理过的图片,
4
+ * 或直接解析一张新的本地图片/data URL(不依赖磁盘缓存命中)。
5
+ *
6
+ * 设计对齐 docs/research/cc-vision-hook-design-2026-07-08.md §8.3:
7
+ * - `vision_ask`:按 image_id 从磁盘缓存取回原图字节,用 describeImage() 追问,
8
+ * 不写回缓存的 description 字段(避免用一次追问的针对性回答覆盖掉原本的通用描述)。
9
+ * - `vision_describe_image` / `vision_describe_data_url`:直接解析,不依赖历史缓存命中,
10
+ * 但解析结果仍然按内容 hash 落盘缓存,方便后续 `vision_ask` 追问同一张图。
11
+ *
12
+ * MCP 本身与 enabled 开关无关(见 claudeSettings.ts 顶部注释的既定设计:
13
+ * "cvh disable 不卸载 MCP,cvh enable 不安装 MCP")——但工具执行时仍然遵守 enabled
14
+ * 开关,因为调用视觉模型本身就是"处理图片"这件事,enabled=false 时应视为功能关闭。
15
+ */
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ /**
18
+ * 创建并配置好三个视觉工具的 MCP Server 实例(尚未连接 transport)。
19
+ * 拆成独立函数是为了方便单测:可以直接调用 `server.server` 上的能力做集成测试,
20
+ * 不需要真的起一个 stdio 子进程。
21
+ *
22
+ * @returns 配置完毕、可直接 connect(transport) 的 McpServer 实例
23
+ */
24
+ export declare const createVisionMcpServer: () => McpServer;
25
+ /**
26
+ * 以 stdio 模式启动 MCP server(由 Claude Code 作为子进程调起,`cvh mcp serve` 的入口)。
27
+ * 这是一个长驻进程,函数本身不会 resolve(除非 transport 关闭)。
28
+ *
29
+ * @returns 在 transport 关闭前不会 resolve 的 Promise
30
+ */
31
+ export declare const serveMcpStdio: () => Promise<void>;