mocode-ai 0.1.9 → 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.
package/README.md CHANGED
@@ -1,45 +1,47 @@
1
- <img src="./assets/banner.svg" alt="mocode">
1
+ <img src="./assets/banner-en.svg?v=2" alt="MoCode">
2
2
 
3
- # mocode
3
+ <p align="right">English | <a href="./README.zh-CN.md">简体中文</a></p>
4
4
 
5
- 一个终端编码 agent:你给一个目标,它**自主完成**——不需要你逐步指挥。
5
+ # MoCode
6
6
 
7
- mocode 自己探索代码、读写改文件、执行命令、联网查资料,以「思考 调用工具 观察结果 再思考」的循环一步步把任务推进到完成。接任意 OpenAI 兼容接口(GLM、DeepSeek、Qwen、本地 Ollama / vLLM 等),全屏 TUI 交互,流式输出、思考过程可见。
7
+ A terminal coding agent: give it a goal, and it **completes it autonomously** no step-by-step hand-holding required.
8
8
 
9
- ## 为什么用 mocode
9
+ MoCode explores your code, reads/writes/edits files, runs shell commands, and searches the web on its own, driving the task forward through a loop of "think → call a tool → observe the result → think again." It works with any OpenAI-compatible endpoint (GLM, DeepSeek, Qwen, local Ollama / vLLM, etc.), runs as a full-screen TUI with streaming output and visible reasoning.
10
10
 
11
- mocode 不是一个套壳聊天框,而是一个能真正动手干活的 agent:
11
+ ## Why MoCode
12
12
 
13
- - **自主多步推进**一次对话里连续多步:读代码、改代码、跑测试、根据报错再改……agent 自己决定下一步,中途不用你反复催。遇到卡点会调 `ask_human` 弹面板问你(阻塞到回应)。
14
- - **只读工具并行执行** — 一轮里连续的只读操作(读文件、grep、glob、codegraph、联网搜索/抓取)自动并发跑,总耗时 ≈ 最慢一个,而不是逐个排队。写文件 / 改文件这类有副作用的操作仍串行,保快照顺序与数据安全。
15
- - **子 agent 分而治之** — 复杂任务可派生独立子 agent:各自有自己的对话历史(不污染主线),可限定只读工具集和步数上限,并行探查多片代码 / 多个方向,最后只把摘要回灌主线。主线据此决定下一步。
16
- - **计划 / 执行双模式** — `plan` 模式下只读探查(读代码、查索引、搜索,绝不写盘、不跑命令、不派生子 agent),产出计划;`auto` 模式全量工具放开。agent 还能在两者间自切换——先把陌生代码库摸清,再动手改。
17
- - **上下文自动压缩** — 接近窗口上限时三层压缩(单条结果裁剪 → 旧工具结果原地微压缩 → 旧对话摘要),长会话也不爆窗口;`/context` 实时显示 token 用量,`/compact` 可手动压缩(能带焦点指令聚焦保留)。
18
- - **跨会话长期记忆** — agent 能把项目架构、约定、踩过的坑存成长期记忆,下次会话自动加载;后台还会定期从对话里反思挖掘值得记住的事。记忆可增删改、带召回衰减。
19
- - **可中断、可回滚** — Ctrl+C 随时打断当前轮次(树杀子进程,历史还原到本轮开始前,不留残半的工具调用);`/rollback` 按轮次快照恢复文件改动,逐个文件「保留/撤销」,不依赖 git。
20
- - **沙箱防护** — 文件读写经沙箱拦截,挡掉越界路径(`../../`、绝对外圈、软链出圈等),不碰工作目录之外的文件。
13
+ MoCode isn't a chat box with a coat of paint it's an agent that actually gets things done:
21
14
 
22
- ## 特性
15
+ - **Autonomous multi-step execution** — In a single conversation, the agent chains multiple steps on its own: read code, edit code, run tests, fix based on errors, and so on. It decides the next step without you nagging it. When it hits a decision point, it calls `ask_human` to pop up a panel and ask you (blocking until you respond).
16
+ - **Parallel read-only tools** — Consecutive read-only operations in a turn (reading files, grep, glob, codegraph, web search/fetch) run concurrently, so total time is roughly the slowest single call instead of the sum of all of them. Operations with side effects (writing/editing files) stay sequential to preserve snapshot ordering and data safety.
17
+ - **Sub-agents divide and conquer** — Complex tasks can spawn independent sub-agents, each with its own conversation history (isolated from the main thread), an optional restricted toolset, and a step cap. They can explore multiple code areas or directions in parallel and report back only a summary, which the main thread uses to decide what's next.
18
+ - **Plan / Auto dual mode** — In `plan` mode the agent is read-only (reads code, queries indexes, searches — never writes to disk, runs commands, or spawns sub-agents) and produces a plan; `auto` mode unlocks the full toolset. The agent can switch between the two on its own — scope out an unfamiliar codebase first, then start making changes.
19
+ - **Automatic context compression** — As the context window fills up, a three-tier compression kicks in (trim individual results → compact older tool results in place → summarize older turns), so long sessions never overflow. `/context` shows live token usage; `/compact` triggers manual compression (optionally with a focus hint to preserve what matters).
20
+ - **Cross-session long-term memory** — The agent can save project architecture, conventions, and lessons learned as long-term memory, auto-loaded in future sessions. A background process periodically reflects on conversations to mine things worth remembering. Memories can be created, searched, updated, and forgotten, with recall-based decay.
21
+ - **Interruptible and reversible** — Ctrl+C interrupts the current turn at any time (kills child processes recursively, rolls history back to before the turn started, leaves no half-finished tool calls). `/rollback` restores file changes from per-turn snapshots, with a per-file keep/undo choice — no git dependency required.
22
+ - **Sandbox protection** — File reads/writes go through a sandbox that blocks out-of-bounds paths (`../../`, absolute paths outside the root, symlink escapes, etc.), so the agent never touches files outside your working directory.
23
23
 
24
- - **流式输出 + 思考可见** — 回复边生成边显示;模型支持 reasoning 时思考过程实时可见,思考段自动折叠(不占屏),`/think N` 按需展开
25
- - **全屏 TUI** — 备用屏(alt screen)+ 固定底栏状态行 + 滚动回看(PgUp/PgDn),运行中可打字(typeahead),下一轮自动预填
26
- - **会话持久化** — 每轮自动落盘,`--resume` / `/resume` 续接历史会话
27
- - **Skills 系统** — 自动扫描 `~/.mocode/skills/` 等目录,description 注入系统提示,模型按需调 `use_skill` 加载完整指令(渐进式披露:先看简介,任务相关才加载正文)
28
- - **斜杠命令** — `/exit` `/clear` `/context` `/skills` `/compact` `/resume` `/think` `/rollback`,输入时下拉过滤
24
+ ## Features
29
25
 
30
- ## 安装
26
+ - **Streaming output + visible reasoning** — Responses render as they're generated; when the model supports reasoning, the thinking process is visible in real time and auto-collapses to save screen space, with `/think N` to expand it on demand.
27
+ - **Full-screen TUI** — Alt-screen mode with a fixed status bar, scrollback (PgUp/PgDn), typeahead while the agent is running, and auto-prefill for the next turn.
28
+ - **Session persistence** — Every turn is saved automatically; `--resume` / `/resume` picks up a past session.
29
+ - **Skills system** — Scans directories like `~/.mocode/skills/` automatically; each skill's description is injected into the system prompt, and the model calls `use_skill` to load the full instructions only when relevant (progressive disclosure: skim the summary first, load the body only if needed).
30
+ - **Slash commands** — `/exit` `/clear` `/context` `/skills` `/compact` `/resume` `/think` `/rollback`, with dropdown filtering as you type.
31
31
 
32
- 要求 Node.js ≥ 18。
32
+ ## Installation
33
+
34
+ Requires Node.js ≥ 18.
33
35
 
34
36
  ```bash
35
37
  npm install -g mocode-ai
36
38
  ```
37
39
 
38
- 装完即得 `mocode` 命令。不想全局装也可免装直跑:`npx mocode-ai`。
40
+ This gives you the `mocode` command. Prefer not to install globally? Run it directly with `npx mocode-ai`.
39
41
 
40
- > mocode 启动时自动检测新版本,后台 `npm i -g mocode-ai@latest` 自更新——下次启动生效,零启动延迟、断网 / 失败静默。开发态 `npm start`(tsx `.ts`)不触发。
42
+ > MoCode checks for new versions on startup and self-updates in the background via `npm i -g mocode-ai@latest` the update takes effect on the next launch, with zero startup delay and silent failure if offline. This is skipped in dev mode (`npm start`, running via tsx).
41
43
 
42
- ### 从源码运行(开发 / 贡献)
44
+ ### Run from source (development / contributing)
43
45
 
44
46
  ```bash
45
47
  git clone https://github.com/wanxunyang/mocode.git
@@ -48,143 +50,153 @@ npm install
48
50
  npm start
49
51
  ```
50
52
 
51
- 源码经 tsx 直接跑,无构建步骤。改完代码需重启 `npm start` 生效(tsx 启动时加载模块,不热更新)。依赖:`openai`、`dotenv`、`fast-glob`(运行时);`tsx`、`typescript`、`@types/node`(开发)。
53
+ Source runs directly via tsx, no build step. After changing code, restart `npm start` for changes to take effect (tsx loads modules at startup, no hot reload). Runtime dependencies: `openai`, `dotenv`, `fast-glob`; dev dependencies: `tsx`, `typescript`, `@types/node`.
52
54
 
53
- ## 配置
55
+ ## Configuration
54
56
 
55
- 首次使用运行配置向导,交互填三项(API 地址 / key / 模型名),写入 `~/.mocode/config`(全局,任意目录、任意终端生效):
57
+ On first use, run the setup wizard to fill in three fields interactively (API base URL / key / model name), written to `~/.mocode/config` (global, works from any directory or terminal):
56
58
 
57
59
  ```bash
58
60
  mocode config
59
61
  ```
60
62
 
61
- 也可直接 `mocode` 进入 REPL 后用 `/model` 命令配置(交互选后端预设 + 逐项填写,即时生效 + 持久化)。未配置时 REPL 仍能打开,会提示你跑 `/model`。
63
+ You can also configure it from inside the REPL with the `/model` command (pick a backend preset interactively and fill in each field, applied immediately and persisted). Without configuration, the REPL still opens and prompts you to run `/model`.
62
64
 
63
- 也可手写配置文件。mocode 按以下优先级加载(后者覆盖前者,仅回填未设置的环境变量;shell `export` 的永远最优先):
65
+ You can also hand-edit the config files. MoCode loads them in the following priority order (later entries override earlier ones, only backfilling unset environment variables; anything `export`ed in your shell always takes precedence):
64
66
 
65
- 1. `~/.mocode/config` — 全局(`mocode config` 写此文件)
66
- 2. `<cwd>/.mocode/config` — 项目级覆盖
67
- 3. `<cwd>/.env` — 旧用法兼容(源码仓库内有 `.env.example` 可参考)
67
+ 1. `<cwd>/.env` — legacy compatibility, lowest priority (see `.env.example` in the source repo for reference)
68
+ 2. `~/.mocode/config` — global (written by `/model` and `mocode config`)
69
+ 3. `<cwd>/.mocode/config` — project-level override, highest priority
68
70
 
69
- 必填三项:
71
+ Three required fields:
70
72
 
71
73
  ```env
72
- LLM_BASE_URL=https://open.bigmodel.cn/api/v3 # 换成你的后端
74
+ LLM_BASE_URL=https://open.bigmodel.cn/api/v3 # swap in your backend
73
75
  LLM_API_KEY=your-key-here
74
- LLM_MODEL=glm-4.6 # 换成你的模型名
76
+ LLM_MODEL=glm-4.6 # swap in your model name
75
77
  ```
76
78
 
77
- 常见后端 `base_url`:
78
-
79
- | 后端 | base_url |
80
- |------|----------|
81
- | GLM(智谱) | `https://open.bigmodel.cn/api/v3` |
82
- | DeepSeek | `https://api.deepseek.com` |
83
- | Qwen(阿里) | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
84
- | 本地 Ollama | `http://localhost:11434/v1` |
85
- | 本地 vLLM | `http://localhost:8000/v1` |
86
-
87
- > 模型必须支持 OpenAI 风格的 function calling,否则工具不会触发。
88
-
89
- ### 可选配置
90
-
91
- | 环境变量 | 说明 | 默认值 |
92
- |----------|------|--------|
93
- | `MAX_TOKENS` | 单次回复最大 token | 不限 |
94
- | `CONTEXT_WINDOW_TOKENS` | 模型上下文窗口,须对齐真实模型 | `128000` |
95
- | `COMPACT_THRESHOLD` | 自动压缩触发阈值(占窗口比例) | `0.85` |
96
- | `LLM_STREAM_USAGE` | 流式请求带 `stream_options.include_usage` 拿真实用量 | `true` |
97
- | `AUTO_COMPACT` | 自动压缩总开关 | `true` |
98
- | `AUTO_REFLECT` | 后台反思 pass 总开关(定期从会话挖掘记忆) | `true` |
99
- | `REFLECT_EVERY_N` | N 轮触发一次后台反思( agent 并发,不阻塞) | `5` |
100
- | `ANYSEARCH_API_KEY` | 联网搜索 API key(不配走匿名免费额度) | |
101
- | `ANYSEARCH_BASE_URL` | 搜索 API 端点 | `https://api.anysearch.com` |
102
- | `SKILLS_DIRS` | 覆盖默认 skill 扫描目录(平台分隔符) | 三目录自动扫描 |
103
-
104
- ## 运行
79
+ Common backend `base_url` values:
80
+
81
+ | Backend | base\_url |
82
+ | -------------- | ---------------------------------------------------- |
83
+ | GLM (Zhipu) | `https://open.bigmodel.cn/api/v3` |
84
+ | DeepSeek | `https://api.deepseek.com` |
85
+ | Qwen (Alibaba) | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
86
+ | Local Ollama | `http://localhost:11434/v1` |
87
+ | Local vLLM | `http://localhost:8000/v1` |
88
+
89
+ > The model must support OpenAI-style function calling, otherwise tools won't be triggered.
90
+
91
+ ### Optional configuration
92
+
93
+ | Environment variable | Description | Default |
94
+ | --------------------------- | ---------------------------------------------------------------------- | --------------------------- |
95
+ | `MAX_TOKENS` | Max tokens per response | unlimited |
96
+ | `CONTEXT_WINDOW_TOKENS` | Model context window; must match the real model | `128000` |
97
+ | `COMPACT_THRESHOLD` | Auto-compaction trigger threshold (fraction of window) | `0.85` |
98
+ | `LLM_STREAM_USAGE` | Include `stream_options.include_usage` on streaming requests for real usage | `true` |
99
+ | `AUTO_COMPACT` | Auto-compaction master switch | `true` |
100
+ | `AUTO_REFLECT` | Background reflection pass master switch (periodically mines memories from conversations) | `true` |
101
+ | `REFLECT_EVERY_N` | Trigger a background reflection every N turns (runs alongside the agent, non-blocking) | `5` |
102
+ | `ANYSEARCH_API_KEY` | Web search API key (falls back to anonymous free quota if unset) | none |
103
+ | `ANYSEARCH_BASE_URL` | Search API endpoint | `https://api.anysearch.com` |
104
+ | `SKILLS_DIRS` | Override the default skill scan directories (platform path separator) | three default directories |
105
+ | `MOCODE_CONTEXT_OPTIMIZE` | Typed encoding of tool results before they reach the LLM (tree/search/log…); disable for raw passthrough (length trimming only) | `true` |
106
+ | `MAX_STEPS` | Max agent loop steps per turn (prevents infinite loops) | `200` |
107
+ | `SUB_AGENT_MAX_STEPS` | Default step cap for sub-agents (spawned via the `task` tool) | `50` |
108
+ | `SANDBOX_ROOT` | Sandbox root directory (file operation boundary; falls back to cwd if unset) | none |
109
+ | `MOCODE_THEME` | Color theme (default/dark/light…; shell env takes precedence over file) | `default` |
110
+
111
+ ## Usage
105
112
 
106
113
  ```bash
107
- mocode # 新会话(在目标项目目录里跑)
108
- mocode --resume # 列出已保存会话
109
- mocode --resume <id> # 续接指定会话
110
- mocode config # 改配置
114
+ mocode # new session (run inside your target project directory)
115
+ mocode --resume # list saved sessions
116
+ mocode --resume <id> # resume a specific session
117
+ mocode config # edit configuration
111
118
  ```
112
119
 
113
- 从源码跑则用 `npm start`(等价于 `mocode`,但不触发自更新)
114
-
115
- 进入 REPL 后直接对话。启动即进全屏 TUI,显示横幅(模型 / 后端 / 工作目录 / 工具列表)。回复流式打印,思考段实时可见后折叠。
116
-
117
- agent 工作在**启动时所在的工作目录**——想让它操作某个项目,就 `cd` 到那个项目再 `mocode`。
118
-
119
- ## 工具
120
-
121
- | 工具 | 作用 |
122
- |------|------|
123
- | `read_file` | 读文件,带行号,支持 `offset` / `limit` |
124
- | `write_file` | 创建/覆盖文件,自动建父目录 |
125
- | `edit_file` | 精确字符串替换(`old_string` 须唯一匹配) |
126
- | `run_command` | 执行 shell 命令,合并 stdout+stderr,默认 120s 超时 |
127
- | `glob` | glob 模式找文件(排除 node_modules/.git) |
128
- | `grep` | 内容正则搜索,纯 JS 实现,不依赖 `rg` |
129
- | `codegraph` | 已建 `.codegraph/` 索引时,查代码符号源码与调用链( read_file/grep 更准更省) |
130
- | `web_search` | 联网搜索(AnySearch),返回标题/URL/摘要/正文 |
131
- | `web_fetch` | 抓取指定 URL,HTML 清洗成纯文本 |
132
- | `use_skill` | 加载某 skill 的完整 SKILL.md 指令 |
133
- | `ask_human` | 决策点弹终端问答面板,用户选预设项或自由输入(阻塞至回应) |
134
- | `switch_mode` | `plan`(只读规划) `auto`(全量执行)间切换;agent 可自行调用,先探查再动手 |
135
- | `task` | 派生子 agent 执行独立子任务(独立历史、可受限工具集、可设步数上限);连续多个自动并行,只回摘要 |
136
- | `memory_save` | 存一条跨会话长期记忆(标题进索引,正文按需取) |
137
- | `memory_search` | 按关键词搜记忆正文,命中即提升召回计数(影响遗忘衰减) |
138
- | `memory_list` | 列记忆索引(id/标题/摘要,无正文) |
139
- | `memory_update` | 原地改一条记忆(id 不变;纠正过时事实 / 改摘要 / pin) |
140
- | `memory_forget` | 遗忘记忆:默认归档(可复活),`mode=delete` 硬删(pinned 拒删) |
141
-
142
- ## 斜杠命令
143
-
144
- | 命令 | 作用 |
145
- |------|------|
146
- | `/exit` `/quit` | 退出 mocode |
147
- | `/clear` | 清空历史(保留系统提示)+ 清屏 |
148
- | `/context` | 显示上下文用量条(token / 消息数 / 估算或实测) |
149
- | `/skills` | 列出已发现的 skill |
150
- | `/compact` | 压缩历史(可带焦点 `/compact …`) |
151
- | `/resume` | 续接已保存的会话 |
152
- | `/think` | 展开折叠思考段(`/think N`) |
153
- | `/rollback` | 菜单选轮次回滚(↑↓ · Enter) |
154
- | `/model` | 配置大模型(baseURL / apiKey / model / 上下文窗口),即时生效 + 持久化 |
155
-
156
- 输入 `/` 触发下拉菜单,继续打字过滤;Esc 取消。
157
-
158
- ## 快速验证(配好 key )
120
+ Running from source uses `npm start` (equivalent to `mocode`, but skips the self-update check).
121
+
122
+ Once in the REPL, just start chatting. It launches straight into the full-screen TUI, showing a banner (model / backend / working directory / tool list). Responses stream in, with the reasoning section visible in real time before collapsing.
123
+
124
+ The agent operates in **the working directory it was launched from** — to have it work on a specific project, `cd` into that project before running `mocode`.
125
+
126
+ ## Tools
127
+
128
+ | Tool | Purpose |
129
+ | ---------------- | ------------------------------------------------------------------------- |
130
+ | `read_file` | Read a file with line numbers; supports `offset` / `limit` |
131
+ | `write_file` | Create/overwrite a file, auto-creating parent directories |
132
+ | `edit_file` | Precise string replacement (`old_string` must match uniquely) |
133
+ | `run_command` | Run a shell command, merging stdout+stderr, 120s default timeout |
134
+ | `glob` | Find files by glob pattern (excludes node\_modules/.git) |
135
+ | `grep` | Regex content search, pure JS implementation, no `rg` dependency |
136
+ | `codegraph` | With a `.codegraph/` index built, query symbol source and call chains (more accurate and cheaper than read\_file/grep) |
137
+ | `web_search` | Web search (AnySearch), returns title/URL/snippet/body |
138
+ | `web_fetch` | Fetch a URL, cleaning HTML into plain text |
139
+ | `use_skill` | Load the full SKILL.md instructions for a given skill |
140
+ | `ask_human` | Pop up a Q&A panel at decision points; user picks a preset or types freely (blocks until answered) |
141
+ | `switch_mode` | Switch between `plan` (read-only planning) and `auto` (full execution); the agent can call this itself to explore before acting |
142
+ | `drop_context` | Replace irrelevant old tool results in history with stubs to free up context (preserves tool_call_id pairing, leaves system prompt and current turn untouched, idempotent) |
143
+ | `task` | Spawn a sub-agent for an independent subtask (isolated history, optional restricted toolset, optional step cap); consecutive calls run in parallel automatically, returning only a summary |
144
+ | `memory_save` | Save a piece of cross-session long-term memory (title indexed, body fetched on demand) |
145
+ | `memory_search` | Search memory bodies by keyword; hits boost the recall count (affects forgetting decay) |
146
+ | `memory_list` | List the memory index (id/title/summary, no body) |
147
+ | `memory_update` | Edit a memory in place (id unchanged; correct stale facts / update summary / toggle pin) |
148
+ | `memory_forget` | Forget a memory: archived by default (recoverable), `mode=delete` for a hard delete (pinned memories can't be deleted) |
149
+
150
+ ## Slash commands
151
+
152
+ | Command | Purpose |
153
+ | ------------------ | ----------------------------------------------------------------------- |
154
+ | `/exit` `/quit` | Exit MoCode |
155
+ | `/clear` | Clear history (keeps the system prompt) + clear screen |
156
+ | `/context` | Show a context usage bar (tokens / message count, estimated or measured) |
157
+ | `/skills` | List discovered skills |
158
+ | `/compact` | Compress history (optionally with a focus hint: `/compact …`) |
159
+ | `/resume` | Resume a saved session |
160
+ | `/think` | Expand a collapsed reasoning section (`/think N`) |
161
+ | `/rollback` | Menu to pick a turn to roll back to (↑↓ · Enter) |
162
+ | `/model` | Configure the LLM (baseURL / apiKey / model / context window), applied immediately + persisted |
163
+ | `/init` | Scan the project and generate `MOCODE.md` project memory (dispatched to the agent) |
164
+ | `/theme` | Switch color theme (↑↓ · Enter, or `/theme <name>` directly) |
165
+ | `/plan` | Switch to plan mode (read-only exploration + plan output, approve to switch to auto) |
166
+ | `/auto` | Switch back to auto mode (full toolset execution) |
167
+
168
+ Type `/` to trigger the dropdown menu, keep typing to filter; Esc to cancel.
169
+
170
+ ## Quick verification (after configuring your key)
159
171
 
160
172
  ```
161
- > 你好,你是谁 # 验证 LLM 连通
162
- > 读一下 sample.txt # 触发 read_file
163
- > sample.txt 里的 foo 改成 bar # 触发 read_file + edit_file
164
- > 列出当前目录所有 .txt 文件 # 触发 glob
165
- > 搜一下代码里出现 runAgent 的地方 # 触发 grep
166
- > 跑一下 node -e "console.log(1+1)" # 触发 run_command
167
- > 搜一下 TypeScript 5.5 有什么新特性 # 触发 web_search
173
+ > hello, who are you # verify LLM connectivity
174
+ > read sample.txt # triggers read_file
175
+ > change foo to bar in sample.txt # triggers read_file + edit_file
176
+ > list all .txt files in this directory # triggers glob
177
+ > search the code for runAgent # triggers grep
178
+ > run node -e "console.log(1+1)" # triggers run_command
179
+ > search what's new in TypeScript 5.5 # triggers web_search
168
180
  ```
169
181
 
170
- 每步终端会打印 `● 工具名 + 参数摘要` `↳ 结果预览`,agent 在循环里自己决定下一步;回复流式打印,边生成边显示。
182
+ Each step prints `● tool name + argument summary` and `↳ result preview` in the terminal; the agent decides the next step on its own within the loop, with responses streaming in as they're generated.
171
183
 
172
184
  ## Skills
173
185
 
174
- mocode 自动扫描以下目录的 skill(每个 skill `<name>/SKILL.md`,带 frontmatter):
186
+ MoCode automatically scans the following directories for skills (each skill is a `<name>/SKILL.md` with frontmatter):
175
187
 
176
188
  - `~/.claude/skills/`
177
189
  - `~/.mocode/skills/`
178
190
  - `<cwd>/.mocode/skills/`
179
191
 
180
- skill `description` 注入系统提示(渐进式披露第①层),模型只在任务相关时调 `use_skill` 加载完整正文(第②层)。用 `/skills` 查看已发现的 skill。
192
+ A skill's `description` is injected into the system prompt (progressive disclosure, tier 1); the model calls `use_skill` to load the full body (tier 2) only when the task is relevant. Use `/skills` to see discovered skills.
181
193
 
182
- ## 类型检查
194
+ ## Type checking
183
195
 
184
196
  ```bash
185
197
  npm run typecheck # tsc --noEmit
186
198
  ```
187
199
 
188
- ## 可后续扩展
200
+ ## Future extensions
189
201
 
190
- agent / 并行任务、MCP 工具集成、权限确认 UI。当前版本是一个流式、思考可见、可回滚的终端编码 agent
202
+ Sub-agents / parallel tasks, MCP tool integration, a permission confirmation UI. The current version is a streaming, reasoning-visible, rollback-capable terminal coding agent.
@@ -0,0 +1,202 @@
1
+ <img src="./assets/banner-zh-CN.svg?v=2" alt="MoCode">
2
+
3
+ <p align="right"><a href="./README.md">English</a> | 简体中文</p>
4
+
5
+ # MoCode
6
+
7
+ 一个终端编码 agent:你给一个目标,它**自主完成**——不需要你逐步指挥。
8
+
9
+ mocode 自己探索代码、读写改文件、执行命令、联网查资料,以「思考 → 调用工具 → 观察结果 → 再思考」的循环一步步把任务推进到完成。接任意 OpenAI 兼容接口(GLM、DeepSeek、Qwen、本地 Ollama / vLLM 等),全屏 TUI 交互,流式输出、思考过程可见。
10
+
11
+ ## 为什么用 mocode
12
+
13
+ mocode 不是一个套壳聊天框,而是一个能真正动手干活的 agent:
14
+
15
+ - **自主多步推进** — 一次对话里连续多步:读代码、改代码、跑测试、根据报错再改……agent 自己决定下一步,中途不用你反复催。遇到卡点会调 `ask_human` 弹面板问你(阻塞到回应)。
16
+ - **只读工具并行执行** — 一轮里连续的只读操作(读文件、grep、glob、codegraph、联网搜索/抓取)自动并发跑,总耗时 ≈ 最慢一个,而不是逐个排队。写文件 / 改文件这类有副作用的操作仍串行,保快照顺序与数据安全。
17
+ - **子 agent 分而治之** — 复杂任务可派生独立子 agent:各自有自己的对话历史(不污染主线),可限定只读工具集和步数上限,并行探查多片代码 / 多个方向,最后只把摘要回灌主线。主线据此决定下一步。
18
+ - **计划 / 执行双模式** — `plan` 模式下只读探查(读代码、查索引、搜索,绝不写盘、不跑命令、不派生子 agent),产出计划;`auto` 模式全量工具放开。agent 还能在两者间自切换——先把陌生代码库摸清,再动手改。
19
+ - **上下文自动压缩** — 接近窗口上限时三层压缩(单条结果裁剪 → 旧工具结果原地微压缩 → 旧对话摘要),长会话也不爆窗口;`/context` 实时显示 token 用量,`/compact` 可手动压缩(能带焦点指令聚焦保留)。
20
+ - **跨会话长期记忆** — agent 能把项目架构、约定、踩过的坑存成长期记忆,下次会话自动加载;后台还会定期从对话里反思挖掘值得记住的事。记忆可增删改、带召回衰减。
21
+ - **可中断、可回滚** — Ctrl+C 随时打断当前轮次(树杀子进程,历史还原到本轮开始前,不留残半的工具调用);`/rollback` 按轮次快照恢复文件改动,逐个文件「保留/撤销」,不依赖 git。
22
+ - **沙箱防护** — 文件读写经沙箱拦截,挡掉越界路径(`../../`、绝对外圈、软链出圈等),不碰工作目录之外的文件。
23
+
24
+ ## 特性
25
+
26
+ - **流式输出 + 思考可见** — 回复边生成边显示;模型支持 reasoning 时思考过程实时可见,思考段自动折叠(不占屏),`/think N` 按需展开
27
+ - **全屏 TUI** — 备用屏(alt screen)+ 固定底栏状态行 + 滚动回看(PgUp/PgDn),运行中可打字(typeahead),下一轮自动预填
28
+ - **会话持久化** — 每轮自动落盘,`--resume` / `/resume` 续接历史会话
29
+ - **Skills 系统** — 自动扫描 `~/.mocode/skills/` 等目录,description 注入系统提示,模型按需调 `use_skill` 加载完整指令(渐进式披露:先看简介,任务相关才加载正文)
30
+ - **斜杠命令** — `/exit` `/clear` `/context` `/skills` `/compact` `/resume` `/think` `/rollback`,输入时下拉过滤
31
+
32
+ ## 安装
33
+
34
+ 要求 Node.js ≥ 18。
35
+
36
+ ```bash
37
+ npm install -g mocode-ai
38
+ ```
39
+
40
+ 装完即得 `mocode` 命令。不想全局装也可免装直跑:`npx mocode-ai`。
41
+
42
+ > mocode 启动时自动检测新版本,后台 `npm i -g mocode-ai@latest` 自更新——下次启动生效,零启动延迟、断网 / 失败静默。开发态 `npm start`(tsx 跑 `.ts`)不触发。
43
+
44
+ ### 从源码运行(开发 / 贡献)
45
+
46
+ ```bash
47
+ git clone https://github.com/wanxunyang/mocode.git
48
+ cd mocode
49
+ npm install
50
+ npm start
51
+ ```
52
+
53
+ 源码经 tsx 直接跑,无构建步骤。改完代码需重启 `npm start` 生效(tsx 启动时加载模块,不热更新)。依赖:`openai`、`dotenv`、`fast-glob`(运行时);`tsx`、`typescript`、`@types/node`(开发)。
54
+
55
+ ## 配置
56
+
57
+ 首次使用运行配置向导,交互填三项(API 地址 / key / 模型名),写入 `~/.mocode/config`(全局,任意目录、任意终端生效):
58
+
59
+ ```bash
60
+ mocode config
61
+ ```
62
+
63
+ 也可直接 `mocode` 进入 REPL 后用 `/model` 命令配置(交互选后端预设 + 逐项填写,即时生效 + 持久化)。未配置时 REPL 仍能打开,会提示你跑 `/model`。
64
+
65
+ 也可手写配置文件。mocode 按以下优先级加载(后者覆盖前者,仅回填未设置的环境变量;shell 里 `export` 的永远最优先):
66
+
67
+ 1. `<cwd>/.env` — 旧用法兼容,优先级最低(源码仓库内有 `.env.example` 可参考)
68
+ 2. `~/.mocode/config` — 全局(`/model` 与 `mocode config` 写此文件)
69
+ 3. `<cwd>/.mocode/config` — 项目级覆盖,优先级最高
70
+
71
+ 必填三项:
72
+
73
+ ```env
74
+ LLM_BASE_URL=https://open.bigmodel.cn/api/v3 # 换成你的后端
75
+ LLM_API_KEY=your-key-here
76
+ LLM_MODEL=glm-4.6 # 换成你的模型名
77
+ ```
78
+
79
+ 常见后端 `base_url`:
80
+
81
+ | 后端 | base\_url |
82
+ | --------- | --------------------------------------------------- |
83
+ | GLM(智谱) | `https://open.bigmodel.cn/api/v3` |
84
+ | DeepSeek | `https://api.deepseek.com` |
85
+ | Qwen(阿里) | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
86
+ | 本地 Ollama | `http://localhost:11434/v1` |
87
+ | 本地 vLLM | `http://localhost:8000/v1` |
88
+
89
+ > 模型必须支持 OpenAI 风格的 function calling,否则工具不会触发。
90
+
91
+ ### 可选配置
92
+
93
+ | 环境变量 | 说明 | 默认值 |
94
+ | ----------------------- | ------------------------------------------ | --------------------------- |
95
+ | `MAX_TOKENS` | 单次回复最大 token | 不限 |
96
+ | `CONTEXT_WINDOW_TOKENS` | 模型上下文窗口,须对齐真实模型 | `128000` |
97
+ | `COMPACT_THRESHOLD` | 自动压缩触发阈值(占窗口比例) | `0.85` |
98
+ | `LLM_STREAM_USAGE` | 流式请求带 `stream_options.include_usage` 拿真实用量 | `true` |
99
+ | `AUTO_COMPACT` | 自动压缩总开关 | `true` |
100
+ | `AUTO_REFLECT` | 后台反思 pass 总开关(定期从会话挖掘记忆) | `true` |
101
+ | `REFLECT_EVERY_N` | 每 N 轮触发一次后台反思(与 agent 并发,不阻塞) | `5` |
102
+ | `ANYSEARCH_API_KEY` | 联网搜索 API key(不配走匿名免费额度) | 无 |
103
+ | `ANYSEARCH_BASE_URL` | 搜索 API 端点 | `https://api.anysearch.com` |
104
+ | `SKILLS_DIRS` | 覆盖默认 skill 扫描目录(平台分隔符) | 三目录自动扫描 |
105
+ | `MOCODE_CONTEXT_OPTIMIZE` | 工具结果进 LLM 前的类型化编码(树/搜索/日志…),关掉则原样进(仅长度裁剪) | `true` |
106
+ | `MAX_STEPS` | 每轮 agent 循环最大步数(防无限循环) | `200` |
107
+ | `SUB_AGENT_MAX_STEPS` | 子 agent(task 工具派生)默认步数上限 | `50` |
108
+ | `SANDBOX_ROOT` | 沙箱根目录(文件操作边界;未配则用 cwd 兜底) | 无 |
109
+ | `MOCODE_THEME` | 颜色主题(default/dark/light…;shell 设置优先于文件) | `default` |
110
+
111
+ ## 运行
112
+
113
+ ```bash
114
+ mocode # 新会话(在目标项目目录里跑)
115
+ mocode --resume # 列出已保存会话
116
+ mocode --resume <id> # 续接指定会话
117
+ mocode config # 改配置
118
+ ```
119
+
120
+ 从源码跑则用 `npm start`(等价于 `mocode`,但不触发自更新)。
121
+
122
+ 进入 REPL 后直接对话。启动即进全屏 TUI,显示横幅(模型 / 后端 / 工作目录 / 工具列表)。回复流式打印,思考段实时可见后折叠。
123
+
124
+ agent 工作在**启动时所在的工作目录**——想让它操作某个项目,就 `cd` 到那个项目再 `mocode`。
125
+
126
+ ## 工具
127
+
128
+ | 工具 | 作用 |
129
+ | --------------- | -------------------------------------------------------- |
130
+ | `read_file` | 读文件,带行号,支持 `offset` / `limit` |
131
+ | `write_file` | 创建/覆盖文件,自动建父目录 |
132
+ | `edit_file` | 精确字符串替换(`old_string` 须唯一匹配) |
133
+ | `run_command` | 执行 shell 命令,合并 stdout+stderr,默认 120s 超时 |
134
+ | `glob` | 按 glob 模式找文件(排除 node\_modules/.git) |
135
+ | `grep` | 内容正则搜索,纯 JS 实现,不依赖 `rg` |
136
+ | `codegraph` | 已建 `.codegraph/` 索引时,查代码符号源码与调用链(比 read\_file/grep 更准更省) |
137
+ | `web_search` | 联网搜索(AnySearch),返回标题/URL/摘要/正文 |
138
+ | `web_fetch` | 抓取指定 URL,HTML 清洗成纯文本 |
139
+ | `use_skill` | 加载某 skill 的完整 SKILL.md 指令 |
140
+ | `ask_human` | 决策点弹终端问答面板,用户选预设项或自由输入(阻塞至回应) |
141
+ | `switch_mode` | 在 `plan`(只读规划)与 `auto`(全量执行)间切换;agent 可自行调用,先探查再动手 |
142
+ | `drop_context` | 把历史里无关的旧工具结果替换为存根释放上下文(保 tool_call_id 配对,不动 system 与当前轮;幂等) |
143
+ | `task` | 派生子 agent 执行独立子任务(独立历史、可受限工具集、可设步数上限);连续多个自动并行,只回摘要 |
144
+ | `memory_save` | 存一条跨会话长期记忆(标题进索引,正文按需取) |
145
+ | `memory_search` | 按关键词搜记忆正文,命中即提升召回计数(影响遗忘衰减) |
146
+ | `memory_list` | 列记忆索引(id/标题/摘要,无正文) |
147
+ | `memory_update` | 原地改一条记忆(id 不变;纠正过时事实 / 改摘要 / 改 pin) |
148
+ | `memory_forget` | 遗忘记忆:默认归档(可复活),`mode=delete` 硬删(pinned 拒删) |
149
+
150
+ ## 斜杠命令
151
+
152
+ | 命令 | 作用 |
153
+ | --------------- | -------------------------------------------------- |
154
+ | `/exit` `/quit` | 退出 mocode |
155
+ | `/clear` | 清空历史(保留系统提示)+ 清屏 |
156
+ | `/context` | 显示上下文用量条(token / 消息数 / 估算或实测) |
157
+ | `/skills` | 列出已发现的 skill |
158
+ | `/compact` | 压缩历史(可带焦点 `/compact …`) |
159
+ | `/resume` | 续接已保存的会话 |
160
+ | `/think` | 展开折叠思考段(`/think N`) |
161
+ | `/rollback` | 菜单选轮次回滚(↑↓ · Enter) |
162
+ | `/model` | 配置大模型(baseURL / apiKey / model / 上下文窗口),即时生效 + 持久化 |
163
+ | `/init` | 扫描项目生成 `MOCODE.md` 项目记忆(发给 agent 执行) |
164
+ | `/theme` | 切换颜色主题(↑↓ · Enter,或 `/theme <name>` 直切) |
165
+ | `/plan` | 切到 plan 模式(只读探查 + 产出计划,审批后切 auto 执行) |
166
+ | `/auto` | 切回 auto 模式(全量工具执行) |
167
+
168
+ 输入 `/` 触发下拉菜单,继续打字过滤;Esc 取消。
169
+
170
+ ## 快速验证(配好 key 后)
171
+
172
+ ```
173
+ > 你好,你是谁 # 验证 LLM 连通
174
+ > 读一下 sample.txt # 触发 read_file
175
+ > 把 sample.txt 里的 foo 改成 bar # 触发 read_file + edit_file
176
+ > 列出当前目录所有 .txt 文件 # 触发 glob
177
+ > 搜一下代码里出现 runAgent 的地方 # 触发 grep
178
+ > 跑一下 node -e "console.log(1+1)" # 触发 run_command
179
+ > 搜一下 TypeScript 5.5 有什么新特性 # 触发 web_search
180
+ ```
181
+
182
+ 每步终端会打印 `● 工具名 + 参数摘要` 与 `↳ 结果预览`,agent 在循环里自己决定下一步;回复流式打印,边生成边显示。
183
+
184
+ ## Skills
185
+
186
+ mocode 自动扫描以下目录的 skill(每个 skill 是 `<name>/SKILL.md`,带 frontmatter):
187
+
188
+ - `~/.claude/skills/`
189
+ - `~/.mocode/skills/`
190
+ - `<cwd>/.mocode/skills/`
191
+
192
+ skill 的 `description` 注入系统提示(渐进式披露第①层),模型只在任务相关时调 `use_skill` 加载完整正文(第②层)。用 `/skills` 查看已发现的 skill。
193
+
194
+ ## 类型检查
195
+
196
+ ```bash
197
+ npm run typecheck # tsc --noEmit
198
+ ```
199
+
200
+ ## 可后续扩展
201
+
202
+ 子 agent / 并行任务、MCP 工具集成、权限确认 UI。当前版本是一个流式、思考可见、可回滚的终端编码 agent。
@@ -55,16 +55,11 @@ onContextUpdate) {
55
55
  // 开新轮次(回滚用):首行截断 40,供 /rollback 轮次菜单展示。
56
56
  beginTurn(truncateDisplay(userInput.split('\n')[0] ?? '', 40));
57
57
  layout.contentMode(); // 防御性:运行态光标归输入框光标位供 IME 锚定(enterRunningMode 已置,这里兜底)
58
- // spinner:续写位内联转圈(思考中 / 执行 工具时,内容区不再「干等」)。
59
- // 只走内联 paintLiveAtCursor——不调 setStatus,状态行不重复 spinner 文字(状态行只显走时,
60
- // turnTimer 200ms 续刷);内联帧不进缓冲、停时清掉,随后结果即写在该行——故 spinner 不入历史、PgUp 看不到。
58
+ // spinner:状态行最前面转圈(思考中 / 生成 / 执行 工具时,状态栏 lead 位显帧 + 文字)。
59
+ // setStatus 注入状态行(spinnerFrame + statusText),composeStatus 把帧 + 文字放 lead 位;
60
+ // 不画内容区续写位——内容区在等待期间保持干净,首 token 到达即从续写位开始写正文。
61
61
  const spinner = new Spinner((msg, frame) => {
62
- if (frame) {
63
- layout.paintLiveAtCursor(` ${ui.brightMagenta}${frame}${ui.reset} ${ui.dim}${msg}…${ui.reset}`);
64
- }
65
- else {
66
- layout.clearLiveAtCursor();
67
- }
62
+ layout.setStatus(frame ? `${msg}…` : '', frame ?? undefined);
68
63
  });
69
64
  // lastChar 镜像:core 跟踪流式末字符决定补换行,但 TUI hooks 需读它决定 layout.contentWrite('\n')。
70
65
  // core 的 onTextEnd hook 只在 lastChar !== '\n' 时才调,调后置 '\n';镜像与此同步。
@@ -84,7 +79,7 @@ onContextUpdate) {
84
79
  lastChar = '\n';
85
80
  }
86
81
  if (name)
87
- spinner.start(`生成 ${name}…`);
82
+ spinner.start(`生成 ${name}`);
88
83
  },
89
84
  onStepStart: () => spinner.start('思考中'),
90
85
  onChatDone: () => spinner.stop(),