claude-mem 动画式安装器设计与实现:基于 @clack/prompts 的交互式 CLI 安装向导
【免费下载链接】claude-memPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More项目地址: https://gitcode.com/GitHub_Trending/cl/claude-mem
claude-mem 的核心使用门槛在于:用户需要手动克隆仓库、构建插件、配置settings.json、再单独启动 worker 服务。animated-installer 计划文档给出了一套完整方案:用@clack/prompts构建一个带动画效果的 CLI 安装向导,通过npx与curl | bash两种分发方式一键完成全部流程。本文以该计划文档为主线,逐阶段还原其 API 选型、工程结构与验证标准,并对照仓库中已落地的 npx CLI 实现 与 运行时准备逻辑,讲解这套安装器从设计到源码的实际形态。读完本文,你可以掌握交互式 CLI 安装器的 API 用法边界、TTY 防护、依赖自检与 worker 健康检查等关键工程实践。
一、计划目标与两种分发形态
计划文档的 Overview 明确了两条分发路径:
- npx 分发:
npx claude-mem-installer(计划阶段的包名;仓库最终实现为npx claude-mem install),package.json的bin字段指向带 shebang 的dist/index.js; - curl | bash 分发:Shell 引导脚本下载打包后的安装器 JS,直接用
node script.js执行——关键是保留 TTY,因为@clack/prompts的交互式提示在管道输入下会无限挂起。
安装器的价值在于替代四个手动环节:clone 仓库、构建插件、配置设置、启动 worker。文档同时注明设计工作在独立 worktree(feat/animated-installer)中推进,主仓库只保留规划与最终实现。
二、Phase 0:@clack/prompts API 选型与反模式清单
计划文档把 API 选型作为 Phase 0,列出了 v1.0.1(ESM-only)下允许使用的 API 及其用途,这是理解后续每个步骤实现的基础:
| API | 签名 | 用途 |
|---|---|---|
intro(title?) | void | 开场横幅 |
outro(message?) | void | 完成消息 |
cancel(message?) | void | 用户取消 |
isCancel(value) | boolean | 判断用户是否按了 Ctrl+C |
text(opts) | Promise<string \| symbol> | 输入 API key、端口、数据目录 |
password(opts) | Promise<string \| symbol> | 遮罩输入 API key |
select(opts) | Promise<Value \| symbol> | 选择 Provider、模型、认证方式 |
multiselect(opts) | Promise<Value[] \| symbol> | 多选 IDE、观测类型 |
confirm(opts) | Promise<boolean \| symbol> | 启用 Chroma、启动 worker |
spinner() | SpinnerResult | 安装依赖、构建、启动 worker 的动画 |
progress(opts) | ProgressResult | 多步骤安装进度 |
tasks(tasks[]) | Promise<void> | 顺序执行安装步骤 |
group(prompts, opts) | Promise<Results> | 链式提示并共享结果 |
note(message, title) | void | 显示配置摘要、下一步 |
log.info/success/warn/error(msg) | void | 状态消息 |
box(message, title, opts) | void | 欢迎框、完成摘要框 |
反模式清单(Anti-Patterns)
计划文档特别列出六条必须规避的写法,每一条都对应一类真实的运行故障:
- 不要使用
require()——@clack/prompts是 ESM-only; - 不要未做 TTY 检查就调用提示——非 TTY 环境下会无限挂起;
- 每个 prompt 之后都要检查
isCancel()(或使用带onCancel的group()); - 不要引入
chalk——统一用 clack 的依赖picocolors,保证颜色输出一致; text()没有数字模式——端口号必须手工做数值校验;spinner.stop()不接受状态码——失败场景要用spinner.error()。
分发包的技术模式
- npx:
bin字段指向./dist/index.js,产物首行需要#!/usr/bin/env node; - curl | bash:引导脚本直接
node script.js,不经 shell 中转,保住 TTY; - esbuild:打包成单文件 ESM,
platform: 'node',用banner注入 shebang。
文档还给出了实现时应参考的 8 个关键源文件:SettingsDefaultsManager(默认设置 schema)、SettingsRoutes.ts(设置校验)、worker-service.ts(worker 启动)、HealthMonitor(健康检查)、plugin.json 与 marketplace.json(插件注册)、sync-marketplace.cjs(marketplace 同步)、CursorHooksInstaller(Cursor 集成)、openclaw.sh(既有安装脚本的逻辑参考)。
三、Phase 1:包结构、构建配置与验证标准
计划给出的目录结构按「步骤」与「工具」分层:
installer/ ├── src/ │ ├── index.ts # 入口,含 TTY 防护 │ ├── steps/ │ │ ├── welcome.ts # intro + 版本检查 │ │ ├── dependencies.ts # bun、uv、git 检查 │ │ ├── ide-selection.ts # IDE 选择 + 注册 │ │ ├── provider.ts # AI 供应商 + API key │ │ ├── settings.ts # 附加设置 │ │ ├── install.ts # 克隆、构建、注册插件 │ │ ├── worker.ts # 启动 worker + 健康检查 │ │ └── complete.ts # 摘要 + 下一步 │ └── utils/ │ ├── system.ts # OS 检测、命令执行 │ ├── dependencies.ts # bun/uv 安装辅助 │ └── settings-writer.ts # 写 ~/.claude-mem/settings.json ├── build.mjs # esbuild 配置 ├── package.json # bin、type: module、依赖 └── tsconfig.jsonpackage.json的关键字段是type: "module"、bin指向dist/index.js、engines.node >= 18;build.mjs使用 esbuild 以format: 'esm'、platform: 'node'、target: 'node18'打包,banner 注入 shebang;tsconfig.json采用module: "ESNext"、target: "ES2022"、moduleResolution: "bundler"。验证标准三条:node build.mjs成功、产物带 shebang、空安装器也能运行。
仓库最终实现把这套结构落到了主包里:package.json的bin为"claude-mem": "./dist/npx-cli/index.js",运行时要求升级为"node": ">=20.12.0"、"bun": ">=1.0.0"(见 package.json)。值得注意的是 dependencies-note 的说明:@clack/prompts等库被 esbuild内联进 npx 包,属于构建期 devDependency,不会被消费该包的用户额外下载——这正是计划中「单文件 ESM 产物」模式的规模化版本,当前 package.json 中该依赖为^1.3.0。
四、Phase 2:入口 TTY 防护与欢迎步骤
计划中src/index.ts的三个要点:
- TTY 防护:
!process.stdin.isTTY时打印错误并引导用户改用npx claude-mem-installer,exit 1; - 导入并调用
steps中的runInstaller(); - 顶层 catch 统一走
p.cancel()并退出。
welcome.ts负责p.intro()(用 picocolors 加样式的标题)、版本号展示、已安装检测(探测~/.claude-mem/settings.json与~/.claude/plugins/marketplaces/thedotmack/)、升级确认,以及 Fresh Install / Upgrade / Configure Only 三选一。system.ts提供四个基础工具:detectOS()、commandExists()、runCommand()(返回 stdout/stderr/exitCode)、expandHome()。
仓库最终实现中,这一设计以 install.ts 的开头几行得到印证——交互性是全局一次性判定的,而非逐提示判断:
const isInteractive = process.stdin.isTTY === true; // src/npx-cli/commands/install.ts#L58 async function runTasks(tasks: TaskDescriptor[]): Promise<void> { if (isInteractive) { await p.tasks(tasks); } else { for (const t of tasks) { const result = await t.task((msg: string) => console.log(` ${msg}`)); console.log(` ${result}`); } } }这里比计划更进一步:非 TTY 不是简单报错退出,而是降级为纯文本顺序执行——p.tasks换成逐条console.log,让 CI / 脚本环境也能跑通安装。而isCancel检查则严格遵循了 Phase 0 反模式清单,install.ts 中几乎每个 prompt 之后都有成对的模式(如 L294-L295、L946-L947):
if (p.isCancel(choice)) { p.cancel('Installation cancelled.');欢迎横幅的样式实现位于 L1966:p.intro(styleText(['bgCyan', 'black'], ' claude-mem install '))——最终版用 Node 内置styleText替代了计划中的 picocolors,效果等价且零依赖。
五、Phase 3:依赖检查与自动安装
计划要求用p.tasks()依次以动画 spinner 检查四类依赖:
- Node.js:
process.version校验 >= 18.0.0; - git:
commandExists('git'),缺失时按 OS 给出安装指引(不能自动装则优雅失败); - Bun:查 PATH 与常见位置(
~/.bun/bin/bun、/usr/local/bin/bun、/opt/homebrew/bin/bun),最低 1.1.14,确认后从官方脚本自动安装; - uv:查 PATH 与
~/.local/bin/uv、~/.cargo/bin/uv,确认后自动安装。
安装尝试之后必须重新验证一遍。验证标准覆盖四种终态:找到的依赖显示绿色对勾、缺失的显示黄色警告并提供安装选项、确认后真的完成安装、git 缺失时优雅失败。
这部分在 setup-runtime.ts 中有完整且更精细的落地。二进制搜索逻辑与计划完全一致——先探测 PATH,再回退到常见安装位置:
const BUN_COMMON_PATHS = IS_WINDOWS ? [join(homedir(), '.bun', 'bin', 'bun.exe')] : [join(homedir(), '.bun', 'bin', 'bun'), '/usr/local/bin/bun', '/opt/homebrew/bin/bun', ...]; const UV_COMMON_PATHS = IS_WINDOWS ? [join(homedir(), '.local', 'bin', 'uv.exe'), join(homedir(), '.cargo', 'bin', 'uv.exe')] : [join(homedir(), '.local', 'bin', 'uv'), join(homedir(), '.cargo', 'bin', 'uv'), '/usr/local/bin/uv', '/opt/homebrew/bin/uv'];自动安装失败时的补救信息被做成平台感知的一等公民:Windows 下提示winget install Oven-sh.Bun/winget install astral-sh.uv,类 Unix 下提示curl -fsSL https://bun.sh/install | bash或 Homebrew 等价命令(见 setup-runtime.ts 中platformBunRemediation()/platformUvRemediation())。另一个工程化细节是安装超时可用环境变量覆盖,默认 5 分钟:
const INSTALL_TIMEOUT_MS = (() => { const override = process.env.CLAUDE_MEM_INSTALL_TIMEOUT_MS; if (override && Number.isFinite(Number(override))) return Number(override); return 5 * 60 * 1000; })();六、Phase 4:IDE 多选与 Provider 配置
IDE 选择用p.multiselect():Claude Code(默认选中,hint 为 "recommended")、Cursor、Windsurf(hint "coming soon",disabled: true)。选中 Claude Code 时提示插件将通过 marketplace 注册;选中 Cursor 时提示 hooks 将按 CursorHooksInstaller 的模式安装。
Provider 配置用p.select()三选一,每个分支的追问结构是计划的精华:
- Claude(hint:使用 Claude 订阅):再选认证方式——"CLI(Max Plan 订阅)" vs "API Key";API Key 走
p.password()遮罩输入; - Gemini(hint:有免费额度):
p.password()必填 key;p.select()选模型(默认 gemini-2.5-flash-lite,另有 gemini-2.5-flash、gemini-3-flash-preview);p.confirm()确认限流(默认 true); - OpenRouter(hint:有免费模型):
p.password()必填 key;p.text()填模型(默认xiaomi/mimo-v2-flash:free)。
所有 key 尽量做非空与格式校验。验证标准四条:多选可用、各分支追问正确、key 全程遮罩、任意步骤可取消且优雅退出。
仓库的 index.ts 把这一交互层同时翻译成了非交互命令行参数,这是计划文档没有展开、但生产环境必需的能力:
npx claude-mem install --provider claude|gemini|openrouter|host # 非交互指定供应商 npx claude-mem install --model <id> # provider=claude 时指定模型 npx claude-mem install --no-auto-start # 跳过结束时的 worker 自启动 npx claude-mem install --runtime worker|server # 非交互选择运行时参数解析用parseArgs(strict: false),并对--provider/--runtime做白名单校验,非法值直接报错退出(index.ts L66-L114)。还有一个关键的非交互默认值逻辑:当stdin.isTTY !== true且未显式传 provider 时,调用resolveInstallerProviderChoice({ ide })为特定 IDE 推导隐式 provider(L99-L104)——这正对应 Phase 0 反模式「不要未做 TTY 检查就调用提示」的彻底贯彻:非 TTY 下根本不会弹出任何 prompt。
七、Phase 5:设置向导与 Schema 对齐的设置写入
设置步骤的策略是「默认优先」:先用p.confirm()问 "Use default settings?"(推荐),选 yes 直接跳过明细;选自定义则用p.group()组织六个配置项,其中数值项都要手工校验——这正是反模式清单第 5 条text()无数字模式的应对:
- Worker 端口:默认 37777,校验 1024-65535;
- 数据目录:默认
~/.claude-mem; - Context 观测数:默认 50,校验 1-200;
- 日志级别:DEBUG / INFO(默认)/ WARN / ERROR;
- Python 版本:默认 3.13;
- Chroma 向量检索:默认 true;若启用再选 local(默认)/ remote,remote 时追问 host、port 与 SSL。
进入下一步前用p.note()展示设置摘要。设置写入器(settings-writer.ts)的要求是:构建与 SettingsDefaultsManager schema 完全一致的扁平键值对象、升级时与既有设置合并(保留用户自定义)、写入~/.claude-mem/settings.json、目录不存在则创建。验证标准包括:默认模式跳过全部明细提示、自定义模式全量校验、产物与 schema 精确匹配、升级保留既有设置。
八、Phase 6:安装执行、插件注册与两阶段健康检查
install.ts(计划阶段的步骤文件)用p.tasks()呈现四个视觉化步骤:克隆仓库到临时目录(--depth 1)、npm install、npm run build、注册插件。插件注册是四个落点:拷贝插件文件到~/.claude/plugins/marketplaces/thedotmack/并建立 marketplace.json / plugin.json 结构、更新known_marketplaces.json、更新installed_plugins.json、在~/.claude/settings.json的enabledPlugins下启用。若用户勾选了 Cursor,还要额外执行 hooks 安装逻辑:写hooks.json到~/.cursor/或项目级.cursor/,并在.cursor/mcp.json配置 MCP。
worker.ts的步骤用p.spinner()呈现,并采用两阶段健康检查(计划注明该模式参考 OpenClaw 安装脚本):
- 启动 worker:
bun plugin/scripts/worker-service.cjs,PID 写入~/.claude-mem/worker.pid; - Stage 1轮询
/api/health(spinner 文案 "Starting worker service..."); - Stage 2轮询
/api/readiness(spinner 文案 "Initializing database..."); - 预算:30 次尝试、间隔 1 秒;
- 成功:
spinner.stop("Worker running on port {port}");失败:spinner.error("Worker failed to start")并展示日志路径。
验证清单要求四个注册文件全部更新、worker 两个端点均返回 200。仓库侧对应的健康检查能力实现在 HealthMonitor,worker 启动路径见 worker-service.ts。
九、Phase 7 与 Phase 8:完成摘要与 curl | bash 引导
完成页用两段p.note():第一段是配置摘要(Provider + 模型、已配置 IDE、数据目录、worker 端口、Chroma 开关),第二段是下一步指引——打开 Claude Code 即可自动记忆、http://localhost:{port}查看记忆、用/mem-search搜索历史工作、若装了 Cursor 则 hooks 已生效——最后p.outro()收尾。验证要点:摘要与所选设置一致、URL 端口正确、下一步与已选 IDE 相关。
curl | bash 引导脚本(计划阶段的install/public/install.sh)要求:检查 Node >= 18、把打包好的安装器 JS 下载到临时文件、直接node执行以保留 TTY、用trap在成功和失败两种路径下都清理临时文件、透传--non-interactive与--provider=X --api-key=Y。配套要求 install/vercel.json 把install.sh作为站点根路径服务出去。
这里值得对照仓库现状说明一次设计演进:当前 install.sh 已经不再是引导脚本,而是一个明确的迁移提示——
echo -e "${YELLOW}The curl-pipe-bash installer has been replaced.${NC}" echo " ${CYAN}npx claude-mem install${NC}" echo "This requires Node.js >= 20. ..."也就是说,计划中 Phase 8 的 curl | bash 方案在演进中被npx claude-mem install取代(Node 门槛同步从 18 提到 20),而 vercel.json 的 rewrite 规则(/→/install.sh,.sh以text/plain服务并带短缓存头)保留了下来,用于继续承接旧安装命令的用户。这是「计划文档描述设计意图、仓库现状描述演进结果」的典型对照。
十、Phase 9:最终验证清单(可直接复用的验收模板)
计划把验收标准压缩成 12 条可勾选的检查项,这套清单本身就值得作为任何 CLI 安装器的模板:
npm run build产出单文件dist/index.js;node dist/index.js可完整跑通向导流程;- 干净系统全新安装端到端成功;
- 升级路径保留既有设置;
- 任意步骤 Ctrl+C 干净退出;
- 非 TTY 显示错误消息(最终实现中进一步演进为非交互降级模式);
- 写入的所有设置与 SettingsDefaultsManager.ts 的默认 schema 一致;
- 安装后 worker 健康检查成功;
- 插件出现在 Claude Code 插件列表中;
grep弃用/不存在的 API 结果为 0;- 源码中无
require()调用(ESM-only); - 无
chalk导入(统一 picocolors / 内置 styleText)。
小结
animated-installer.md 的价值不仅在于描述了一个安装器,更在于它示范了「计划文档如何与源码对齐」:Phase 0 的 API 表与反模式清单约束了全部代码形态(ESM-only、TTY 检查、isCancel成对出现);Phase 3 的常见二进制路径与平台补救话术在 setup-runtime.ts 中原样实现;Phase 4 的交互选择在 index.ts 中被扩展为非交互 CLI 参数,使同一套安装逻辑同时服务人类终端与自动化环境;Phase 8 的 curl | bash 则被npx claude-mem install平滑取代,旧入口改为迁移提示。对照计划与实现,可以推断出该仓库的 CLI 工程原则:交互体验由@clack/prompts承担、所有提示必须先过 TTY 判定、每个用户输入都有取消出口、设置产物必须与默认值 schema 逐字段对齐。
【免费下载链接】claude-memPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More项目地址: https://gitcode.com/GitHub_Trending/cl/claude-mem
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考