04 — 安装流程与多平台集成
npx claude-mem install 10 步自动化序列,通过平台适配器(Cursor rules/Gemini CLI/OpenCode)实现一套记忆核心多端复用,uid%100 端口策略解决多用户隔离。
一、npx 入口总览
src/npx-cli/index.ts(184 行)是整个 npx 命令的路由层,逻辑极简:
1
2
3
4
5
|
// index.ts:10-14
const command =
firstArg.startsWith('-') && !HELP_OR_VERSION_FLAGS.has(firstArg)
? 'install' // 裸标志(如 --provider claude)直接触发 install
: firstArg; // 否则取第一个参数作为子命令
|
子命令列表(index.ts:79-178):
| 子命令 |
功能 |
备注 |
install / 默认 |
安装向导 |
核心流程 |
repair |
重跑 Bun/uv 安装 |
修复运行时 |
update / upgrade |
升级到最新版本 |
复用 runInstallCommand |
uninstall / remove |
卸载 |
独立模块 |
start / stop / restart / status |
Worker 守护进程管理 |
需要 Bun |
search <query> |
搜索记忆 |
需要 Bun |
transcript watch |
启动 transcript 监视器 |
— |
💡 Tip 裸标志自动变 install
npx claude-mem --provider claude 这种写法能直接工作,因为 index.ts 检测到首参数以 - 开头且不是 -h/--help/-v/--version 时,自动把 command 设为 'install'。这是很友好的 CI 非交互安装用法。
二、npx claude-mem install 全流程
2.1 主流程时序
flowchart TD
A[npx claude-mem install] --> B{已安装?\nmarketplace/plugin.json 存在?}
B -- 是 --> C{TTY? 询问覆盖}
B -- 否 --> D[检测 IDE]
C -- 确认 --> D
C -- 取消 --> EXIT[exit 0]
D --> E{有 --ide flag?}
E -- 是 --> F[直接使用指定 IDE]
E -- TTY --> G[多选 IDE 列表]
E -- 非TTY --> H[默认 claude-code]
F & G & H --> I[promptProvider\n选 LLM 提供商]
I --> J[promptClaudeModel\n选模型]
J --> K[停止旧 Worker\nshutdownWorkerAndWait]
K --> L[copyPluginToMarketplace\ncopyPluginToCache]
L --> M[registerMarketplace\nregisterPlugin\nenablePlugin in ~/.claude/settings.json]
M --> N[ensureBun + ensureUv\n自动安装运行时]
N --> O{isInstallCurrent?\n版本+Bun版本匹配}
O -- 是 --> P[跳过 bun install]
O -- 否 --> Q[bun install in cache dir\nwriteInstallMarker]
P & Q --> R[setupIDEs: 各 IDE 安装任务]
R --> S{包含 claude-code?}
S -- 是 --> T[disableClaudeAutoMemory\n写 ~/.claude/settings.json]
S -- 否 --> U
T --> U[ensureWorkerStarted\n后台启动 Worker]
U --> V[打印安装摘要]2.2 已安装检测(install.ts:971-983)
1
2
3
4
5
|
// install.ts:971-972
const alreadyInstalled = existsSync(
join(marketplaceDir, 'plugin', '.claude-plugin', 'plugin.json')
);
// 同时读取现有版本号,区分 "重装" 还是 "升级" 提示
|
检测的是 ~/.claude/plugins/marketplaces/thedotmack/plugin/.claude-plugin/plugin.json 是否存在。文件即事实,不依赖注册表。
2.3 插件三目录架构
安装流程涉及三个目录,各有职责:
| 目录 |
路径 |
用途 |
| Marketplace |
~/.claude/plugins/marketplaces/thedotmack/ |
Claude Code 实际读取的插件目录 |
| Cache |
~/.claude/plugins/cache/thedotmack/claude-mem/<version>/ |
版本快照,hooks 脚本优先读取 |
| NPM Package |
npx 临时目录 |
安装源,cpSync 后可丢弃 |
1
2
3
4
5
6
7
8
9
|
// install.ts:521-553: copyPluginToMarketplace
// 白名单复制,只拷贝必要目录
const allowedTopLevelEntries = [
'plugin', 'package.json', 'dist', '.agents', '.mcp.json', 'README.md', ...
];
// install.ts:556-563: copyPluginToCache
// 只复制 plugin/ 目录到 cache/<version>/
cpSync(sourcePluginDirectory, cachePath, { recursive: true });
|
💡 Tip Cache 目录的版本保留意义
plugin/hooks/hooks.json 中的 bash 命令会优先查 cache 目录(按时间倒序 ls -dt,取最新版本),然后才回退到 marketplace。这样即使 marketplace 被覆盖升级,旧版本仍在 cache,hooks 不会断档。npx 安装新版本后,hooks 下次触发时自动切换,无需重启 Claude Code。
2.4 Claude Code 的 hooks.json 是静态资产
重要理解:Claude Code 的 hooks.json 不是由 install.ts 动态写入的,而是随插件文件 cpSync 过去的:
1
2
3
|
plugin/hooks/hooks.json (仓库里的源文件)
↓ cpSync
~/.claude/plugins/marketplaces/thedotmack/plugin/hooks/hooks.json
|
install.ts 通过 registerPlugin() / enablePluginInClaudeSettings() 把这个目录注册到 Claude Code 的插件系统,Claude Code 自己在启动时扫描并加载 hooks.json。
2.5 关闭 Claude 内置 Auto-Memory(install.ts:150-161)
1
2
3
4
5
6
7
8
|
export function disableClaudeAutoMemory(): boolean {
const settings = readJsonSafe(claudeSettingsPath(), {});
if (env.CLAUDE_CODE_DISABLE_AUTO_MEMORY === '1') return false; // 幂等
settings.env = { ...env, CLAUDE_CODE_DISABLE_AUTO_MEMORY: '1' };
writeJsonFileAtomic(claudeSettingsPath(), settings);
return true;
}
|
写入 ~/.claude/settings.json 的 env 块。注释解释了原因:Claude Code 内置的 MEMORY.md 系统会"创建用户无法控制的影子状态,并与 claude-mem 竞争 context window tokens"(对应 anthropics/claude-code#23544)。
三、多 IDE 集成矩阵
3.1 IDE 检测策略(ide-detection.ts:40-129)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
export function detectInstalledIDEs(): IDEInfo[] {
return [
// 命令行工具:which/where 探测
{ id: 'claude-code', detected: isCommandInPath('claude'), ... },
{ id: 'copilot-cli', detected: isCommandInPath('copilot'), ... },
// 桌面 IDE:检查配置目录
{ id: 'cursor', detected: existsSync(join(home, '.cursor')), ... },
{ id: 'windsurf', detected: existsSync(join(home, '.codeium', 'windsurf')), ... },
// VS Code 扩展:扫描 extensions 目录
{ id: 'roo-code', detected: hasVscodeExtension('roo-code'), ... },
// 共 12 种 IDE
];
}
|
💡 Tip 无副作用的存在性检测
不通过进程列表或注册表检测,而是检查配置目录/命令是否存在。简单、无权限要求、跨平台。
3.2 三种集成机制
graph LR
subgraph "Hook 机制(原生 hooks.json)"
A[Claude Code] -- "Plugin API\nhooks.json 由插件系统管理" --> W[Worker]
B[Cursor] -- "~/.cursor/hooks.json\ninstall 时主动写入" --> W
C[Gemini CLI] -- "~/.gemini/hooks.json" --> W
D[Windsurf] -- "hooks.json" --> W
E[Codex CLI] -- "native hooks" --> W
end
subgraph "MCP 机制(工具调用协议)"
F[Copilot CLI] -- "mcp.json" --> M[MCP Server]
G[Goose] -- "mcp.json" --> M
H[Roo Code] -- "mcp.json" --> M
I[Warp] -- "mcp.json" --> M
M --> W
end
subgraph "Plugin 包机制"
J[OpenCode] -- "plugin 目录" --> W
K[OpenClaw] -- "plugin 目录" --> W
end
| IDE |
集成方式 |
写入位置 |
功能完整度 |
| Claude Code |
Plugin API |
~/.claude/plugins/ |
★★★★★ 6个生命周期 |
| Cursor |
hooks.json + MCP + MDC |
~/.cursor/ |
★★★★☆ |
| Gemini CLI |
hooks.json |
~/.gemini/ |
★★★★☆ |
| Windsurf |
hooks.json |
~/.codeium/windsurf/ |
★★★☆☆ |
| Codex CLI |
native hooks |
~/.codex/ |
★★★☆☆ |
| OpenCode/OpenClaw |
Plugin 包 |
各自目录 |
★★★☆☆ |
| Copilot/Goose/Roo/Warp |
MCP only |
IDE 配置目录 |
★★☆☆☆ |
四、Cursor 集成深度解析
4.1 与 Claude Code 的本质区别
| 维度 |
Claude Code |
Cursor |
| 集成方式 |
Plugin API(Claude Code 主动加载) |
原生 hooks.json(install 时主动写入) |
| 记忆注入时机 |
SessionStart hook,直接注入 stdout |
.cursor/rules/*.mdc,下次 session 生效 |
| 安装位置 |
~/.claude/plugins/ |
~/.cursor/hooks.json |
| 附加功能 |
无 |
写 MDC 规则文件 + 配置 MCP Server |
4.2 Cursor hooks.json 结构(CursorHooksInstaller.ts:236-256)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
const makeHookCommand = (command: string) =>
`"${escapedBunPath}" "${escapedWorkerPath}" hook cursor ${command}`;
// ↑ 绝对路径 ↑ 同一个 worker-service.cjs ↑ IDE 标识
const hooksJson: CursorHooksJson = {
version: 1,
hooks: {
beforeSubmitPrompt: [
{ command: makeHookCommand('session-init') }, // 初始化 session
{ command: makeHookCommand('context') } // 注入历史记忆
],
afterMCPExecution: [{ command: makeHookCommand('observation') }],
afterShellExecution:[{ command: makeHookCommand('observation') }],
afterFileEdit: [{ command: makeHookCommand('file-edit') }],
stop: [{ command: makeHookCommand('summarize') }]
}
};
// 写入 ~/.cursor/hooks.json
|
💡 Tip 统一 Worker,IDE 只是参数
Cursor 和 Claude Code 调用的是同一个 worker-service.cjs。Worker 收到 hook cursor 或 hook claude-code 时区分来源,但核心记忆逻辑完全复用。增加新 IDE 支持时,只需要在 IDE 侧写 hooks,Worker 几乎不用改。
4.3 Cursor 独有的上下文注入机制(CursorHooksInstaller.ts:305-342)
Claude Code 可以在 SessionStart 时通过 stdout 把记忆直接注入 AI 的 system context,但 Cursor 没有这个 API。claude-mem 的绕法:
1
2
3
4
5
6
7
8
9
10
11
|
安装时:生成占位文件 .cursor/rules/claude-mem-context.mdc
↓ alwaysApply: true → Cursor 每次 chat 自动携带
每次 session 结束后:
stop hook → summarize → Worker 压缩本次观测
→ Worker 调用 /api/context/inject
→ writeContextFile(workspacePath, context)
→ 更新 .cursor/rules/claude-mem-context.mdc
下次 session 开始时:
Cursor 自动读取 rules/ 目录 → 携带最新记忆
|
1
2
3
4
5
6
7
|
// MDC 文件头(metadata)
const placeholder = `---
alwaysApply: true
description: "Claude-mem context from past sessions (auto-updated)"
---
# Memory Context from Past Sessions
*No context yet. Complete your first session...*`;
|
⚠️ Warning Cursor 记忆延迟一个 Session
Claude Code 在当前 session 的任意 UserPromptSubmit 都能注入记忆,而 Cursor 的记忆注入要等到下一个 session 才生效(当前 session 结束后才更新文件)。这是 Cursor API 的限制,不是 Bug。
4.4 三级安装目标与 MCP Server 配置
1
2
3
4
5
6
7
8
9
10
11
|
// 三级安装 scope
type CursorInstallTarget = 'project' | 'user' | 'enterprise';
// project → .cursor/ (只影响当前工程)
// user → ~/.cursor/ (默认,影响所有项目)
// enterprise → /Library/.../Cursor (macOS 企业级,需要 sudo)
// 额外配置 MCP server(~/.cursor/mcp.json)
config.mcpServers['claude-mem'] = {
command: 'node',
args: [mcpServerPath] // plugin/scripts/mcp-server.cjs
};
|
Cursor 是双轨集成:hooks 负责被动记录,MCP server 让 Cursor 可以主动查询历史记忆。
五、多 Profile 隔离机制
5.1 两个环境变量控制一切
1
2
|
CLAUDE_MEM_DATA_DIR — 数据根目录(默认 ~/.claude-mem)
CLAUDE_MEM_WORKER_PORT — Worker HTTP 端口(默认 37700 + uid%100)
|
5.2 路径派生:Single Source of Truth
src/shared/paths.ts 的核心设计是:DATA_DIR 在模块加载时计算一次,此后所有路径都从它派生,不存在任何硬编码的 ~/.claude-mem 子路径。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// paths.ts:18-40 — resolveDataDir() 三层优先级
export function resolveDataDir(): string {
// 1. 环境变量(最高优先级)
if (process.env.CLAUDE_MEM_DATA_DIR) return process.env.CLAUDE_MEM_DATA_DIR;
// 2. 默认路径下的 settings.json(持久化配置)
const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
try {
if (existsSync(settingsPath)) {
const raw = JSON.parse(readFileSync(settingsPath, 'utf-8'));
const settings = raw.env ?? raw;
if (settings.CLAUDE_MEM_DATA_DIR) return settings.CLAUDE_MEM_DATA_DIR;
}
} catch { /* 文件缺失或损坏,回退默认值 */ }
// 3. 硬编码默认值
return join(homedir(), '.claude-mem');
}
export const DATA_DIR = resolveDataDir(); // 模块级常量,加载时固定
// 所有子路径全部从 DATA_DIR 派生:
export const DB_PATH = join(DATA_DIR, 'claude-mem.db');
export const LOGS_DIR = join(DATA_DIR, 'logs');
export const paths = {
workerPid: () => join(DATA_DIR, 'worker.pid'),
settings: () => join(DATA_DIR, 'settings.json'),
database: () => join(DATA_DIR, 'claude-mem.db'),
chroma: () => join(DATA_DIR, 'chroma'),
transcriptsConfig: () => join(DATA_DIR, 'transcript-watch.json'),
envFile: () => join(DATA_DIR, '.env'),
// ... 共 15 个路径
};
|
完整路径树:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$CLAUDE_MEM_DATA_DIR (默认 ~/.claude-mem)
├── claude-mem.db # SQLite 数据库
├── settings.json # 用户配置
├── .env # 敏感 env(ANTHROPIC_API_KEY 等)
├── worker.pid # Worker 进程 PID
├── chroma/ # 向量数据库(Chroma)
├── logs/ # 日志文件
├── archives/ # 归档数据
├── corpora/ # 知识语料库
├── modes/ # 运行模式配置
├── transcript-watch.json # Transcript 监视配置
├── supervisor.json # Supervisor 注册表
└── cursor-projects.json # Cursor 项目注册表
|
💡 Tip 单一根路径的隔离完整性
改一个 CLAUDE_MEM_DATA_DIR 环境变量,所有子路径自动跟着变。不可能出现"数据库用了新路径,但 PID 文件还在旧路径"这种状态分裂。Profile 隔离的完整性由架构保证,而非规范要求。
5.3 多 Profile 使用方式
1
2
3
4
5
6
7
8
9
10
|
# 工作账号 profile
export CLAUDE_MEM_DATA_DIR="$HOME/.claude-mem-work"
export CLAUDE_MEM_WORKER_PORT=37801
npx claude-mem start
# 个人 profile(另一个终端)
export CLAUDE_MEM_DATA_DIR="$HOME/.claude-mem-personal"
export CLAUDE_MEM_WORKER_PORT=37802
npx claude-mem start
# 两个 Worker 完全隔离,各自有独立的 DB、Chroma、日志
|
六、端口计算:37700 + (uid % 100)
代码位置:src/shared/SettingsDefaultsManager.ts:73
1
2
|
CLAUDE_MEM_WORKER_PORT: String(37700 + ((process.getuid?.() ?? 77) % 100)),
// ↑ Windows 无 getuid,fallback 到 77 → 端口 37777
|
OpenCode 插件里的复制实现(opencode-plugin/index.ts:74-82):
1
2
3
4
5
6
|
function resolveWorkerPort(): string {
const fromEnv = process.env.CLAUDE_MEM_WORKER_PORT;
if (Number.isInteger(parsed) && parsed >= 1 && parsed <= 65535) return String(parsed);
const uid = typeof process.getuid === 'function' ? process.getuid() : 77;
return String(37700 + (uid % 100)); // 完全相同的逻辑
}
|
为什么用 uid 而不是随机端口?
| 方案 |
优点 |
缺点 |
| 随机端口 |
完全无冲突 |
每次重启端口变化,hooks 脚本里写死的端口失效 |
| 固定端口 (如 8080) |
简单 |
多用户机器必然冲突 |
37700 + (uid % 100) |
同一用户端口稳定;不同用户大概率不同 |
uid 差 100 的用户会碰撞(极罕见) |
💡 Tip uid % 100 的工程价值
hooks.json 里的 bash 命令通过 SettingsDefaultsManager.get('CLAUDE_MEM_WORKER_PORT') 读端口,而不是硬编码。但 Worker 启动是按 uid 计算的,所以同一用户在不同 shell、不同会话里总是找到同一个端口——这是稳定性的保证。
⚠️ Warning uid % 100 的碰撞风险
理论上 uid=1000 和 uid=1100 的用户会碰撞到同一端口(37800)。同机多 Profile 场景应该同时设 CLAUDE_MEM_WORKER_PORT 手动避免。另外,OpenCode 插件和 SettingsDefaultsManager 各自实现了相同的逻辑(DRY 问题),未来修改默认起始端口需要同步两处。
七、Setup Hook 的"缓存依赖检测"机制
7.1 version-check.js 的职责定位
plugin/scripts/version-check.js 作为 Setup 生命周期 hook,在每个 Claude Code session 启动时触发。但它的 timeout 只有 300ms(hooks.json 中配置),所以只做一件事:检测版本是否匹配,不执行安装。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// version-check.js:53-69
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
const markerPath = join(ROOT, '.install-version');
if (!existsSync(markerPath)) {
emitUpgradeHint('claude-mem: runtime not yet set up - run: npx claude-mem@latest install');
process.exit(0); // ← 永远 exit 0,从不阻塞 session
}
const markerVersion = readInstallMarkerVersion(markerPath);
if (markerVersion !== pkg.version) {
emitUpgradeHint(`claude-mem: upgraded to v${pkg.version} - run: npx claude-mem@latest install`);
}
process.exit(0);
|
两种提示场景:
.install-version 不存在 → 从未安装 runtime,提示用户运行 install
- marker 版本 ≠ package.json 版本 → 插件代码已更新但 runtime 未重装,提示升级
7.2 .install-version Marker 文件(setup-runtime.ts:262-287)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 安装完成后写入(setup-runtime.ts:262-274)
export function writeInstallMarker(targetDir, version, bunVersion, uvVersion) {
const payload: MarkerSchema = {
version, // "13.1.0"
bun: bunVersion, // "1.1.42" ← 关键:记录安装时的 Bun 版本
uv: uvVersion,
installedAt: new Date().toISOString(),
};
writeFileSync(join(targetDir, '.install-version'), JSON.stringify(payload));
}
// 判断是否需要重新安装(setup-runtime.ts:277-287)
export function isInstallCurrent(targetDir: string, expectedVersion: string): boolean {
if (!existsSync(join(targetDir, 'node_modules'))) return false; // node_modules 被删了
const marker = readInstallMarker(targetDir);
if (!marker) return false;
if (marker.version !== expectedVersion) return false; // 版本变了
// 关键检查:Bun 版本变了也要重装
const currentBun = getBunVersion();
if (currentBun && marker.bun && currentBun !== marker.bun) return false;
return true;
}
|
三重检查逻辑:
node_modules/ 必须存在(防止被手动删除)
- marker 版本 = 期望版本
- 安装时的 Bun 版本 = 现在的 Bun 版本 → Bun 升级后强制重装(防止 native bindings 不兼容)
💡 Tip Marker File 幂等安装模式
这是经典的"安装状态持久化"技巧:
- 安装完成后写入包含版本+工具链版本+时间戳的 marker 文件
- 下次安装前先比对 marker,匹配则跳过耗时的
bun install(可能 30s+)
- 不仅检查 plugin 版本,还检查 Bun 版本——这防止了 Bun 升级后 native addon 失效的隐患
结果:
npx claude-mem install 可以安全地反复运行,只在真正需要时才慢。
⚠️ Warning 职责分离:检测 vs 执行
Setup hook 只用 node(不用 Bun),因为它运行在 Bun 可能还未安装 的时机。这是鸡蛋问题:不能用 Bun 来检测 Bun 是否安装好。所以 version-check.js 是纯 Node.js 脚本,只做轻量的文件检查;真正的 bun install 在用户手动运行 npx claude-mem install 时才发生。
八、hooks.json 的动态路径发现机制
Claude Code 的每个 hook 命令都包含一段路径解析前缀(plugin/hooks/hooks.json 中):
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 简化版本,原版更复杂(处理 Cygwin/WSL 路径转换)
_C="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
_P=$({
# 优先查 cache 目录(按时间倒序,取最新版本)
ls -dt "$_C/plugins/cache/thedotmack/claude-mem"/[0-9]*/ 2>/dev/null
# 降级到 marketplace 目录
printf '%s\n' "$_C/plugins/marketplaces/thedotmack/plugin"
} | while IFS= read -r _R; do
_R="${_R%/}"
[ -d "$_R/plugin/scripts" ] && _Q="$_R/plugin" || _Q="$_R"
[ -f "$_Q/scripts/bun-runner.js" ] && { printf '%s\n' "$_Q"; break; }
done)
node "$_P/scripts/bun-runner.js" "$_P/scripts/worker-service.cjs" hook claude-code observation
|
路径查找优先级(高→低):
$CLAUDE_PLUGIN_ROOT(环境变量覆盖,开发调试用)
~/.claude/plugins/cache/thedotmack/claude-mem/<最新版本>/
~/.claude/plugins/marketplaces/thedotmack/plugin/
💡 Tip cache 优先的意义
当用户升级 claude-mem 后(npx claude-mem install 把新版写入 cache),下次 hook 触发时自动用新版本,无需重启 Claude Code。marketplace 目录作为降级方案(可能是旧版本),保证向后兼容。
Setup hook 的特殊性:Setup hook 使用 node version-check.js(而非 bun worker-service.cjs),且只在 Claude Code 自己的插件路径下工作,Cursor 等 IDE 没有 Setup 生命周期。
九、设置系统的三层优先级
SettingsDefaultsManager.ts 实现了完整的配置层级(get 方法,第 137-139 行):
1
2
3
4
5
6
7
|
// 实际读取:env var > settings.json > 代码默认值
static get(key: keyof SettingsDefaults): string {
return process.env[key] ?? this.DEFAULTS[key];
}
// loadFromFile() 在文件加载后再调用 applyEnvOverrides()
// 确保 env var 始终覆盖文件配置
|
优先级链(高→低):
1
2
3
|
1. process.env[KEY] # Shell 级,每次进程生效
2. ~/.claude-mem/settings.json # 用户持久配置(UI 可写)
3. SettingsDefaultsManager.DEFAULTS # 代码硬编码默认值
|
settings.json 的 Schema 迁移(loadFromFile:181-192):旧版把所有配置包在 env: {} 嵌套对象里,新版是扁平结构。加载时自动检测并迁移,迁移后立即写回文件。
十、总结:设计模式与可借鉴思路
| 模式 |
代码体现 |
可借鉴点 |
| 文件即事实 |
existsSync(plugin.json) 判断已安装 |
不依赖注册表,简单可靠 |
| Marker 文件缓存 |
.install-version 跳过 bun install |
幂等安装,避免重复耗时操作 |
| 单一路径根 |
DATA_DIR 派生所有子路径 |
隔离=改一个变量,不会状态分裂 |
| uid 派生端口 |
37700 + uid%100 |
多用户自动隔离,单用户端口稳定 |
| 不阻塞用户 |
version-check.js 永远 exit 0 |
检测与执行分离,启动不因插件失败而卡住 |
| 白名单 cpSync |
allowedTopLevelEntries 列表 |
避免意外复制敏感文件或大文件 |
| 裸标志路由 |
--provider 直接触发 install |
零摩擦 CI 安装体验 |
参考文件速查
| 文件 |
行数 |
核心内容 |
src/npx-cli/index.ts |
184 |
命令路由,裸标志→install |
src/npx-cli/commands/install.ts |
1371 |
完整安装流程,runInstallCommand |
src/npx-cli/commands/ide-detection.ts |
129 |
12 种 IDE 检测策略 |
src/npx-cli/install/setup-runtime.ts |
288 |
Bun/uv 安装,.install-version marker |
src/services/integrations/CursorHooksInstaller.ts |
588 |
Cursor hooks.json + MDC 写入 |
src/integrations/opencode-plugin/index.ts |
297 |
OpenCode 插件,复制端口计算逻辑 |
src/shared/SettingsDefaultsManager.ts |
207 |
三层优先级配置,uid%100 端口默认值 |
src/shared/paths.ts |
149 |
DATA_DIR 派生所有路径 |
plugin/scripts/version-check.js |
69 |
Setup hook,只检测不安装 |
plugin/hooks/hooks.json |
— |
Claude Code 6 个生命周期 hook 的 bash 命令 |