Doramagic 项目包 · 项目说明书

sanook-cli 项目

🪄 终端 AI 编程代理 —— BYOK,支持 12 家模型供应商、MCP 协议,并配备可跨会话持久记忆的第二大脑。使用 TypeScript 从零构建。

项目概述、快速开始与整体架构

sanook-cli 是一款「自带密钥(BYOK)的终端 AI 编程 agent」,使用 TypeScript 从零构建,作为 Claude Code 的替代品聚焦本地化、跨 session 记忆与模型可移植性。package.json 中的描述明确指出其覆盖 BYOK、9 家 LLM 提供方、MCP、cron 网关、技能系统与 Git 感知五大能力面。资料来源:packa...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 1. 环境与安装

继续阅读本节完整说明和来源证据。

章节 2. 第一次交互

继续阅读本节完整说明和来源证据。

一、项目定位与核心特性

sanook-cli 是一款「自带密钥(BYOK)的终端 AI 编程 agent」,使用 TypeScript 从零构建,作为 Claude Code 的替代品聚焦本地化、跨 session 记忆与模型可移植性。package.json 中的描述明确指出其覆盖 BYOK、9 家 LLM 提供方、MCP、cron 网关、技能系统与 Git 感知五大能力面。资料来源:package.json

核心特性可以归纳为四条主线:

  • 多模型可移植:通过 Vercel AI SDK 抽象统一接入 Anthropic、Google、OpenAI、xAI、Mistral、Groq 等云端服务,并支持 Ollama / LM Studio 本地推理,以及将执行委托给 codex CLI 的子代理模式。资料来源:src/providers/registry.ts
  • 跨会话记忆sanook brain 命令在本地生成 Obsidian vault 骨架,覆盖 Projects/Sessions/Shared/Intake/Runbooks/Skills/ 等目录,赋予 AI 长期记忆与知识管线。资料来源:second-brain/README.md
  • 本地 Web Dashboard:除终端 REPL 外,还内置 SSE 流式 Agent Console 与基于 ws + node-pty 的可选 PTY Web Shell。资料来源:src/dashboard/terminal.ts
  • 插件与扩展:通过 skills/ 目录、mcp 关键词以及可执行 npm run eval 的 eval 入口,支持技能系统、Model Context Protocol 与模型能力回归评测。资料来源:package.json

二、快速开始

1. 环境与安装

项目要求资料来源
Node.js>=22engines.node 声明)package.json
命令入口sanooksanookaidist/bin.jspackage.json
推荐安装npm install -g sanook-clinpx sanook-clisrc/dashboard/api-helpers.ts
可选依赖node-ptyws(用于 Dashboard Web Shell)package.json
开发运行npm run devtsx src/bin.tspackage.json

发布构建流程为:清理 dist/tsc -p tsconfig.build.json → 复制 dashboard 静态资源 → chmod 755 dist/bin.js,并通过 prepublishOnly 钩子强制在 npm publish 前重新构建。资料来源:package.json

2. 第一次交互

  1. 启动 sanook 后,hasUsableEnvKey() 会先校验环境变量里是否已经存在「可用」API key(含 OAuth/subscription token 拒绝策略)。无 key 或仅 OAuth 时引导用户进入首次运行向导。资料来源:src/providers/registry.ts
  2. 在 REPL 中可通过 provider:model 形式的 spec 切换模型,例如 openai:gpt-5.5anthropic:sonnetgroq:fastcanonicalSpec() 在写入 UI 状态前会自动归一化。资料来源:src/providers/registry.ts
  3. 开启 Dashboard 时,浏览器侧可访问 /api/terminal/run,前端通过 SSE 接收 AgentEvent,并按 sessionId 在服务端保留 ModelMessage[] 多轮历史(最多 20 个会话)。资料来源:src/dashboard/terminal.ts

三、整体架构

sanook-cli 在概念上由四层组成:CLI 入口与参数解析 → Agent 循环 → 提供方适配层 → 持久化与扩展层

flowchart TD
    A[CLI 入口 dist/bin.js] --> B[首次运行向导 / 配置]
    B --> C[REPL 主循环]
    B --> D[Web Dashboard /api/terminal/run]
    C --> E[Agent Loop /runAgent]
    D --> E
    E --> F[Provider 适配层 PROVIDERS]
    F --> F1[Anthropic / Google / OpenAI / xAI / Mistral / Groq]
    F --> F2[本地 Ollama / LM Studio]
    F --> F3[Codex 子进程委托]
    E --> G[Skills / MCP / 工具调用]
    E --> H[Second-Brain Vault]
    H --> I[Obsidian Shared/ + Sessions/]

架构要点说明:

  • Provider Registry 是单一事实源:新增厂商只需在 PROVIDERS 表中追加一条 ProviderConfig(含 id / envVar / requiresKey / models / create()),循环与成本逻辑无需改动。资料来源:src/providers/registry.ts
  • Key 策略统一校验assertDirectApiKey() 配合 keyFormat 正则会拦截 sk-ant-oat*ya29.* 等 OAuth 凭据,避免使用 ChatGPT/Codex/Claude 订阅 token 触发 ToS 风险。资料来源:src/providers/registry.ts
  • 动态模型发现listModelsFor() 针对 Google 走 generativelanguage.googleapis.com,对 Anthropic 走 x-api-key 头,其他云端走 /models 端点,并通过 AbortController 限时避免挂起。资料来源:src/providers/models.ts
  • Codex 委托模式runCodex() 通过 codex exec 启动非交互式子进程,解析 JSONL 事件并支持 cwd 隔离与 resumeThreadId,兼容 --json 被工具激活时忽略的已知 bug。资料来源:src/providers/codex.ts
  • Dashboard 优雅降级shellStatus() 会探测 node-ptyws 是否同时可用,缺失时返回 available: false 并附带原因,UI 不会因此崩溃。资料来源:src/dashboard/terminal.ts

四、测试与质量保障

项目使用 Vitest 作为唯一测试框架,关键契约均有对应单测覆盖:

  • Provider 注册表:验证 alias 解析(gptopenai:gpt-5.5)与 canonicalSpec() 在 UI 状态写入前的归一化行为,同时保证 OAuth 凭据在 embedder 路径上被降级为 null。资料来源:src/providers/registry.test.ts
  • Dashboard 元数据:确认 npm 是唯一 ready=true 且被推荐的安装方式,curl / homebrew / winget 都标注为尚未就绪并附带部署原因。资料来源:src/dashboard/api-helpers.test.ts
  • Eval 模型解析evalModelFromEnv() 会对 SANOOK_MODEL 去空白,缺省回退到 sonnet,与 npm run evaltsx src/eval/run.ts)形成闭环。资料来源:src/eval/run.test.ts · package.json

发布前可执行 npm run typecheck 保证 TypeScript 干净,再跑 npm test 验证关键不变量。

另请参阅

来源:https://github.com/Sir-chawakorn/sanook-cli / 项目说明书

代理循环、工具沙箱与模型提供商

sanook-cli 是一个 BYOK(自带密钥)的终端 AI 编程代理,本页聚焦其三大核心机制:代理循环(agent loop)、工具沙箱与审批、多模型提供商注册表。三者通过 runAgent 入口协同:循环驱动模型推理,模型返回的 toolcall 被沙箱拦截,审批通过后落地执行,结果再回到循环中继续。

章节 相关页面

继续阅读本节完整说明和来源证据。

整体架构与事件流

代理循环是整个系统的"心脏"。仪表板后端把 REPL 的体验复刻到了 Web 端,证据见 src/dashboard/terminal.ts:它显式导入 runAgent, type AgentEvent 并把代理事件以 SSE 形式流式转发给浏览器,包括文本、推理、工具调用、🧠 记忆事实以及 ✨ 自动生成的技能 资料来源:src/dashboard/terminal.ts:1-12。每个浏览器会话在后端维护独立的 ModelMessage[] 历史,上限 20 个并发会话 资料来源:src/dashboard/terminal.ts:5-8

flowchart LR
    A[用户输入] --> B[runAgent<br/>src/loop.ts]
    B --> C{模型提供商<br/>registry.ts}
    C -- text/reasoning --> D[事件流 SSE]
    C -- tool_call --> E[沙箱校验<br/>sandbox.ts]
    E --> F{需审批?<br/>approval.ts}
    F -- 是 --> G[checkpoint<br/>回滚锚点]
    F -- 否 --> H[执行工具]
    H --> I[结果回灌<br/>agentContext.ts]
    I --> B
    D --> J[REPL / Web 终端]
    G --> H

工具沙箱、审批与检查点

任何模型发起的工具调用都必须穿越沙箱和审批两道关卡。src/sandbox.ts 负责把文件系统与命令执行约束在工作区范围内;src/approval.ts 决定该调用是否需要人类确认(写操作、对外网络、危险命令通常需要)。一旦执行开始,src/checkpoint.ts 记录回滚锚点——若后续步骤失败或用户拒绝,可以从锚点恢复。src/agentContext.ts 则把工具结果、记忆、技能等"上下文增量"累积起来,供下一轮循环使用。当上下文接近模型窗口上限时,src/compaction.ts 触发摘要压缩,保留关键事实与最近消息。

模型提供商注册表

src/providers/registry.ts 是多模型支持的"单一事实源"。它导出一个 PROVIDERS 表,每个条目描述一家提供商的鉴权方式、基础 URL、支持的模型别名以及工厂函数 资料来源:src/providers/registry.ts:1-25。模型规范(spec)支持三种写法:provider:modelprovider:alias、或裸别名(如 gpthaikusonnet),parseSpeccanonicalSpec 把它们规范化为 provider:model-id 资料来源:src/providers/registry.ts:79-96

提供商分两类:直接 API(如 anthropicopenaixaimistralgroq)和委托型 codex,后者不持有 key,而是依赖本地 codex CLI 的登录状态 资料来源:src/providers/codex.ts:1-25hasUsableEnvKey 会拒绝 OAuth/订阅型 token,避免把 ChatGPT 订阅 key 误当作 API key 使用 资料来源:src/providers/registry.ts:107-119

fastSibling(spec) 为循环内的"轻量任务"(摘要、压缩)选择同家的快速模型——比如 anthropic 自动落到 haikugoogle 落到 flash——无快档则原样返回 资料来源:src/providers/registry.ts:6-13。当用户希望使用"非别名"的新模型时,可通过 provider:full-id 直接覆盖 资料来源:src/providers/registry.ts:18-25

远程模型发现与评估回路

src/providers/models.tslistRemoteModels 直接调用各家 /models 端点,把权威模型 ID 拉回本地——google 用 query key、anthropicx-api-key、OpenAI 兼容用 Bearer,失败/超时/本地模型则返回 [],由调用方回退到 curated 别名 资料来源:src/providers/models.ts:1-25。评估脚本读取 SANOOK_MODEL 环境变量,trim 后空白则回退到 sonnet 资料来源:src/eval/run.test.ts:1-10,确保离线评估永远有可用的目标模型。

常见失败模式

  • OAuth key 误用:将 sk-ant-oat… 之类的订阅 token 设为 ANTHROPIC_API_KEY 时,assertDirectApiKey 抛错并提示去控制台取真 key 资料来源:src/providers/registry.ts:112-118
  • 不支持的提供商:解析到未知 provider 时,错误信息列出所有受支持的 provider 名称 资料来源:src/providers/registry.ts:55-60
  • Codex 未登录:委托型 provider 需要 codex login,否则 runCodex 给出明确安装/登录指引 资料来源:src/providers/codex.ts:6-20
  • SSE 连接断开sseSend 会检测 res.destroyed/writableEnded,避免向已关闭的 socket 写入 资料来源:src/dashboard/terminal.ts:9-15

See Also

来源:https://github.com/Sir-chawakorn/sanook-cli / 项目说明书

分层记忆系统与第二大脑工作区

sanook-cli 是一个面向终端的 AI 编程 agent,主打"BYOK(自带密钥)+跨会话记忆"两大能力。其记忆体系由两层组成:运行时分层记忆(短/长期事实、回合检索)与第二大脑工作区(Obsidian 风格的知识库脚手架)。两者协同工作,使 agent 在不同会话之间能保留上下文,并将对话成果沉淀为可被人类检索的结构化笔记。

章节 相关页面

继续阅读本节完整说明和来源证据。

概述

sanook-cli 是一个面向终端的 AI 编程 agent,主打"BYOK(自带密钥)+跨会话记忆"两大能力。其记忆体系由两层组成:运行时分层记忆(短/长期事实、回合检索)与第二大脑工作区(Obsidian 风格的知识库脚手架)。两者协同工作,使 agent 在不同会话之间能保留上下文,并将对话成果沉淀为可被人类检索的结构化笔记。

package.json 的关键字同时列出 cross-session-memorysecond-brainobsidian,且将 second-brain/ 目录随 npm 包一并发布,说明该项目将"长期记忆"作为一等公民功能交付。资料来源:package.json

来源:https://github.com/Sir-chawakorn/sanook-cli / 项目说明书

网关、消息通道、MCP、技能与本地面板

sanook-cli 是一个 BYOK(Bring Your Own Key)的终端 AI 编程代理。它通过统一的"提供商注册表"将 9 家云端/本地 LLM 厂商接入同一个 agent 循环,再借由本地面板(dashboard)把这些能力暴露成 HTTP/SSE/WebSocket 端点,并允许子进程级"委托代理"(例如 codex CLI)作为另一种消息通道。本页汇总这...

章节 相关页面

继续阅读本节完整说明和来源证据。

sanook-cli 是一个 BYOK(Bring Your Own Key)的终端 AI 编程代理。它通过统一的"提供商注册表"将 9 家云端/本地 LLM 厂商接入同一个 agent 循环,再借由本地面板(dashboard)把这些能力暴露成 HTTP/SSE/WebSocket 端点,并允许子进程级"委托代理"(例如 codex CLI)作为另一种消息通道。本页汇总这几条通路的设计、配置与典型用法。

1. 架构总览

flowchart LR
    U[用户 / REPL] --> DASH[本地面板<br/>src/dashboard/terminal.ts]
    DASH -->|POST /api/terminal/run (SSE)| LOOP[agent loop<br/>runAgent]
    DASH -->|ws /api/terminal/shell| PTY[node-pty<br/>可选依赖]
    LOOP --> REG[提供商注册表<br/>src/providers/registry.ts]
    REG -->|sdk| SDK[Vercel AI SDK<br/>anthropic/google/openai/xai/mistral/groq]
    REG -->|delegate| CODEX[codex subprocess<br/>src/providers/codex.ts]
    SDK --> REMOTE[远端 /models 枚举<br/>src/providers/models.ts]
    REG --> SB[second-brain 记忆库<br/>second-brain/README.md]

上图中"网关"由 dashboard 的 HTTP/SSE 入口充当;"消息通道"由 PROVIDERS 表覆盖的 9 个厂商与 codex 子进程提供;"技能"与"本地面板"分别通过 skills/ 目录(打包到 npm,见 package.json)和 src/dashboard/* 实现。资料来源:src/dashboard/terminal.tssrc/providers/registry.ts

2. 提供商注册表:消息通道的核心

src/providers/registry.ts 维护一个 PROVIDERS 表,每条记录声明 envVarbaseURLrequiresKeykeyFormat(用正则拒绝 OAuth/subscription 凭证)、models(alias → 真实 model id 的映射)以及 create(key, baseURL) 工厂。新增厂商只需在表内增加一项,循环、计费、密钥策略不需改动。资料来源:src/providers/registry.ts

  • parseSpec(spec) 解析 "provider:model""provider:alias"、裸别名或裸 model id(默认 provider 为 anthropic)。
  • canonicalSpec(spec) 在写入 REPL 状态前把别名归一为 provider:model-id,避免状态机里残留别名。
  • fastSibling(spec) 返回同一 provider 的 fast/flash/haiku/air 兄弟型号,给 summarization、压缩等机械性任务省成本。
  • hasUsableEnvKey(provider) 既要看环境变量里有没有 key,还要跑一遍 assertDirectApiKey,确保不是 sk-ant-oat… 这类被 Anthropic/Google 禁止的 OAuth 复用 token。
  • consoleUrl(provider) 在错误信息/wizard 里直接给出去 console 拿 key 的 URL。

kind: 'sdk' | 'delegate' 字段区分"走 Vercel AI SDK"和"spawn 子进程 agent",目前 codex 是唯一的 delegate 通道——它不查 /models,而是由 src/providers/codex.tscodexCheck() 验证 CLI 安装与 codex login 状态。

3. 本地面板:SSE 通道与可选 PTY

src/dashboard/terminal.ts 实现了浏览器端的两种终端后端:

  • Agent consolePOST /api/terminal/run 接收 prompt,直接复用 runAgent 并通过 SSE 转发 text/reasoning/tool 事件,包含 🧠 remember 事实与 ✨ 自动创建的技能——与 REPL 完全一致。多轮历史在服务端按 sessionId 维护,最长 20 个 session,写入前会用 sseSend() 检查 socket 是否已销毁。
  • Raw shellws://…/api/terminal/shellnode-ptyws 两个可选依赖都装好时升级为真实 PTY;否则 UI 降级。shellStatus() 报告当前可用性。

由于 node-ptywspackage.json 中被声明为 optionalDependencies,缺少它们不会阻断 npm install,但本地面板会回退到纯 agent 通道。安装方式上,dashboardInstall() 暴露的 npm/npx 是当前唯一 ready: true 的方法,curl/irm 脚本需等 sanook.ai 域名与发布基础设施就绪。资料来源:src/dashboard/api-helpers.ts

4. 远端模型枚举与 Codex 委托

src/providers/models.tslistRemoteModels() 直接拉取 provider 的 GET /models,按厂商返回三种不同 shape:

厂商鉴权头列表字段
Google?key=… querymodels[].name(带 supportedGenerationMethods 过滤)
Anthropicx-api-key + anthropic-versiondata[].id
OpenAI 兼容Authorization: Bearer …data[].id

mergeModelOptions() 把别名按真实 model id 分组后展平成 ModelOption[],避免 React key 冲突(出现"两条选项对应同一个 model"这类 bug)。失败/超时/本地/无端点时返回 [],调用方会回退到 curated alias。

src/providers/codex.tsrunCodex() 通过 stdin 投递 prompt 并解析 JSONL 事件(text/usage/thread),对 codex bug #15451(--json 在启用 tools 时被忽略)做容错。可选的 cwd 让父 agent 把 codex 隔离到 worktree 子目录中。

5. 安装、引擎与打包

package.json 声明 bin 字段同时提供 sanooksanookai 两条命令,都指向 dist/bin.jsengines.node 强制 >=22build 脚本先清空 dist/、跑 tsc -p tsconfig.build.json、再执行 scripts/copy-dashboard-static.mjs 把静态资源复制进 dist、最后 chmod 0o755。发布包额外携带 skills/second-brain/scripts/postinstall.mjs.env.example,让 sanook brain 一键 scaffold 出一个 Obsidian vault(见 second-brain/README.md)作为跨 session 的"第二大脑"。

常见失败模式

  • OAuth token 被识别为直接 API keyANTHROPIC_API_KEY=sk-ant-oat… 会被 assertDirectApiKey 拒绝,hasUsableEnvKey() 返回 false,wizard 会强制进入而不是误判"已就绪"。
  • 可选依赖缺失导致 PTY 不可用shellStatus() 会报告 ready: false,浏览器自动回退到 agent console;不影响主路径。
  • codex 未登录codexCheck() 返回 { installed: true, loggedIn: false, reason: 'ยังไม่ได้ login — รัน: codex login' },调度层会跳过而非崩溃。
  • Node.js 版本过低<22 会直接被 engines 阻拦 npm install

See Also

  • 提供商与模型路由
  • 本地面板与 Web 终端
  • Second Brain 记忆库
  • Codex 委托代理

来源:https://github.com/Sir-chawakorn/sanook-cli / 项目说明书

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

medium 存在评分风险

风险会影响是否适合普通用户安装。

Pitfall Log / 踩坑日志

项目:Sir-chawakorn/sanook-cli

摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。

1. 配置坑 · 可能修改宿主 AI 配置

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
  • 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
  • 证据:capability.host_targets | https://github.com/Sir-chawakorn/sanook-cli | host_targets=mcp_host, claude, claude_code, gemini_cli, codex

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://github.com/Sir-chawakorn/sanook-cli | README/documentation is current enough for a first validation pass.

3. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://github.com/Sir-chawakorn/sanook-cli | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://github.com/Sir-chawakorn/sanook-cli | no_demo; severity=medium

5. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://github.com/Sir-chawakorn/sanook-cli | no_demo; severity=medium

6. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://github.com/Sir-chawakorn/sanook-cli | issue_or_pr_quality=unknown

7. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://github.com/Sir-chawakorn/sanook-cli | release_recency=unknown

来源:Doramagic 发现、验证与编译记录