mocode-ai 0.4.4 → 0.4.6

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,209 +1,219 @@
1
- <img src="./assets/banner-en.svg?v=2" alt="MoCode">
2
-
3
- <p align="right">English | <a href="./README.zh-CN.md">简体中文</a></p>
4
-
5
- # MoCode
6
-
7
- A terminal coding agent: give it a goal, and it **completes it autonomously** — no step-by-step hand-holding required.
8
-
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
-
11
- ## Why MoCode
12
-
13
- MoCode isn't a chat box with a coat of paint — it's an agent that actually gets things done:
14
-
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
- - **Working notepad (todolist)** — For complex multi-step tasks (≥3 file changes / ≥5 tool calls), the agent first writes a plan to `.mocode/plans/<id>.md` (file-based, survives context compression), then ticks each step as it goes. A live progress chip in the TUI status bar shows `plan: [title] (3/7) ▸ [current step]`. `finish` auto-archives completed plans to `plans/archive/`, with explicit `list / delete / unarchive` actions.
22
- - **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.
23
- - **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.
24
-
25
- ## Features
26
-
27
- - **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.
28
- - **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.
29
- - **Session persistence** — Every turn is saved automatically; `--resume` / `/resume` picks up a past session.
30
- - **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).
31
- - **Optional desktop pet** — A small floating window (`/pet`) shows a stateful character that mirrors agent activity (idle / thinking / tool running / waiting for human). Works as a separate process over WebSocket; quit it with `/pet quit`. Sits beside the terminal, never blocks it.
32
- - **Slash commands** — `/exit` `/clear` `/context` `/skills` `/compact` `/resume` `/rollback` `/memory` `/reflect` `/init` `/theme` `/model` `/plan` `/auto` `/pet`, with dropdown filtering as you type.
33
-
34
- ## Installation
35
-
36
- Requires Node.js ≥ 18.
37
-
38
- ```bash
39
- npm install -g mocode-ai
40
- ```
41
-
42
- This gives you the `mocode` command. Prefer not to install globally? Run it directly with `npx mocode-ai`.
43
-
44
- > 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).
45
-
46
- ### Run from source (development / contributing)
47
-
48
- ```bash
49
- git clone https://github.com/wanxunyang/mocode.git
50
- cd mocode
51
- npm install
52
- npm start
53
- ```
54
-
55
- 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`.
56
-
57
- ## Configuration
58
-
59
- 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):
60
-
61
- ```bash
62
- mocode config
63
- ```
64
-
65
- 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`.
66
-
67
- 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):
68
-
69
- 1. `<cwd>/.env` — legacy compatibility, lowest priority (see `.env.example` in the source repo for reference)
70
- 2. `~/.mocode/config` — global (written by `/model` and `mocode config`)
71
- 3. `<cwd>/.mocode/config` — project-level override, highest priority
72
-
73
- Three required fields:
74
-
75
- ```env
76
- LLM_BASE_URL=https://open.bigmodel.cn/api/v3 # swap in your backend
77
- LLM_API_KEY=your-key-here
78
- LLM_MODEL=glm-4.6 # swap in your model name
79
- ```
80
-
81
- Common backend `base_url` values:
82
-
83
- | Backend | base\_url |
84
- | -------------- | ---------------------------------------------------- |
85
- | GLM (Zhipu) | `https://open.bigmodel.cn/api/v3` |
86
- | DeepSeek | `https://api.deepseek.com` |
87
- | Qwen (Alibaba) | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
88
- | Local Ollama | `http://localhost:11434/v1` |
89
- | Local vLLM | `http://localhost:8000/v1` |
90
-
91
- > The model must support OpenAI-style function calling, otherwise tools won't be triggered.
92
-
93
- ### Optional configuration
94
-
95
- | Environment variable | Description | Default |
96
- | --------------------------- | ---------------------------------------------------------------------- | --------------------------- |
97
- | `MAX_TOKENS` | Max tokens per response | unlimited |
98
- | `CONTEXT_WINDOW_TOKENS` | Model context window; must match the real model | `128000` |
99
- | `COMPACT_THRESHOLD` | Auto-compaction trigger threshold (fraction of window) | `0.85` |
100
- | `LLM_STREAM_USAGE` | Include `stream_options.include_usage` on streaming requests for real usage | `true` |
101
- | `AUTO_COMPACT` | Auto-compaction master switch | `true` |
102
- | `AUTO_REFLECT` | Background reflection pass master switch (periodically mines memories from conversations) | `true` |
103
- | `REFLECT_EVERY_N` | Trigger a background reflection every N turns (runs alongside the agent, non-blocking) | `5` |
104
- | `ANYSEARCH_API_KEY` | Web search API key (falls back to anonymous free quota if unset) | none |
105
- | `ANYSEARCH_BASE_URL` | Search API endpoint | `https://api.anysearch.com` |
106
- | `SKILLS_DIRS` | Override the default skill scan directories (platform path separator) | three default directories |
107
- | `MOCODE_CONTEXT_OPTIMIZE` | Typed encoding of tool results before they reach the LLM (tree/search/log…); disable for raw passthrough (length trimming only) | `true` |
108
- | `MAX_STEPS` | Max agent loop steps per turn (prevents infinite loops) | `200` |
109
- | `SUB_AGENT_MAX_STEPS` | Default step cap for sub-agents (spawned via the `task` tool) | `50` |
110
- | `SANDBOX_ROOT` | Sandbox root directory (file operation boundary; falls back to cwd if unset) | none |
111
- | `MOCODE_THEME` | Color theme (default/dark/light…; shell env takes precedence over file) | `default` |
112
-
113
- ## Usage
114
-
115
- ```bash
116
- mocode # new session (run inside your target project directory)
117
- mocode --resume # list saved sessions
118
- mocode --resume <id> # resume a specific session
119
- mocode config # edit configuration
120
- ```
121
-
122
- Running from source uses `npm start` (equivalent to `mocode`, but skips the self-update check).
123
-
124
- 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.
125
-
126
- 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`.
127
-
128
- ## Tools
129
-
130
- | Tool | Purpose |
131
- | ---------------- | ------------------------------------------------------------------------- |
132
- | `read_file` | Read a file with line numbers; supports `offset` / `limit` |
133
- | `write_file` | Create/overwrite a file, auto-creating parent directories |
134
- | `edit_file` | Precise string replacement (`old_string` must match uniquely) |
135
- | `run_command` | Run a shell command, merging stdout+stderr, 120s default timeout |
136
- | `glob` | Find files by glob pattern (excludes node\_modules/.git) |
137
- | `grep` | Regex content search, pure JS implementation, no `rg` dependency |
138
- | `codegraph` | With a `.codegraph/` index built, query symbol source and call chains (more accurate and cheaper than read\_file/grep) |
139
- | `web_search` | Web search (AnySearch), returns title/URL/snippet/body |
140
- | `web_fetch` | Fetch a URL, cleaning HTML into plain text |
141
- | `use_skill` | Load the full SKILL.md instructions for a given skill |
142
- | `ask_human` | Pop up a Q&A panel at decision points; user picks a preset or types freely (blocks until answered) |
143
- | `switch_mode` | Switch between `plan` (read-only planning) and `auto` (full execution); the agent can call this itself to explore before acting |
144
- | `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) |
145
- | `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 |
146
- | `todolist` | Working notepad: write a multi-step plan to `.mocode/plans/<id>.md` (survives compression) and tick steps as you go; `finish` auto-archives, with `list / delete / unarchive` for history |
147
- | `memory_save` | Save a piece of cross-session long-term memory (title indexed, body fetched on demand) |
148
- | `memory_search` | Search memory bodies by keyword; hits boost the recall count (affects forgetting decay) |
149
- | `memory_list` | List the memory index (id/title/summary, no body) |
150
- | `memory_update` | Edit a memory in place (id unchanged; correct stale facts / update summary / toggle pin) |
151
- | `memory_forget` | Forget a memory: archived by default (recoverable), `mode=delete` for a hard delete (pinned memories can't be deleted) |
152
-
153
- ## Slash commands
154
-
155
- | Command | Purpose |
156
- | ------------------ | ----------------------------------------------------------------------- |
157
- | `/exit` `/quit` | Exit MoCode |
158
- | `/clear` | Clear history (keeps the system prompt) + clear screen |
159
- | `/context` | Show a context usage bar (tokens / message count, estimated or measured) |
160
- | `/skills` | List discovered skills |
161
- | `/compact` | Compress history (optionally with a focus hint: `/compact …`) |
162
- | `/resume` | Resume a saved session |
163
- | `/rollback` | Menu to pick a turn to roll back to (↑↓ · Enter) |
164
- | `/memory` | Show memory library: entry count + recent index |
165
- | `/reflect` | Manually trigger a background memory reflection pass |
166
- | `/model` | Configure the LLM (baseURL / apiKey / model / context window), applied immediately + persisted |
167
- | `/init` | Scan the project and generate `MOCODE.md` project memory (dispatched to the agent) |
168
- | `/theme` | Switch color theme (↑↓ · Enter, or `/theme <name>` directly) |
169
- | `/plan` | Switch to plan mode (read-only exploration + plan output, approve to switch to auto) |
170
- | `/auto` | Switch back to auto mode (full toolset execution) |
171
- | `/pet` | Toggle the optional desktop pet (floating window mirroring agent state) |
172
- | `/pet skin` | Pick a pet skin (↑↓ · Enter) |
173
- | `/pet quit` | Fully shut down the pet process (not just disconnect) |
174
-
175
- Type `/` to trigger the dropdown menu, keep typing to filter; Esc to cancel.
176
-
177
- ## Quick verification (after configuring your key)
178
-
179
- ```
180
- > hello, who are you # verify LLM connectivity
181
- > read sample.txt # triggers read_file
182
- > change foo to bar in sample.txt # triggers read_file + edit_file
183
- > list all .txt files in this directory # triggers glob
184
- > search the code for runAgent # triggers grep
185
- > run node -e "console.log(1+1)" # triggers run_command
186
- > search what's new in TypeScript 5.5 # triggers web_search
187
- ```
188
-
189
- 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.
190
-
191
- ## Skills
192
-
193
- MoCode automatically scans the following directories for skills (each skill is a `<name>/SKILL.md` with frontmatter):
194
-
195
- - `~/.claude/skills/`
196
- - `~/.mocode/skills/`
197
- - `<cwd>/.mocode/skills/`
198
-
199
- 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.
200
-
201
- ## Type checking
202
-
203
- ```bash
204
- npm run typecheck # tsc --noEmit
205
- ```
206
-
207
- ## Future extensions
208
-
209
- MCP tool integration, a permission confirmation UI, and a real worktree-isolated sub-agent mode. The current version is a streaming, reasoning-visible, rollback-capable terminal coding agent with 20 tools, working-notepad planning, cross-session memory, parallel sub-agents, and an optional desktop pet.
1
+ <img src="./assets/banner-en.svg?v=2" alt="MoCode">
2
+
3
+ <p align="right">English | <a href="./README.zh-CN.md">简体中文</a></p>
4
+
5
+ # MoCode
6
+
7
+ A terminal coding agent: give it a goal, and it **completes it autonomously** — no step-by-step hand-holding required.
8
+
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
+
11
+ ## Why MoCode
12
+
13
+ MoCode isn't a chat box with a coat of paint — it's an agent that actually gets things done:
14
+
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
+ - **Working notepad (todolist)** — For complex multi-step tasks (≥3 file changes / ≥5 tool calls), the agent first writes a plan to `.mocode/plans/<id>.md` (file-based, survives context compression), then ticks each step as it goes. A live progress chip in the TUI status bar shows `plan: [title] (3/7) ▸ [current step]`. `finish` auto-archives completed plans to `plans/archive/`, with explicit `list / delete / unarchive` actions.
22
+ - **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.
23
+ - **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.
24
+
25
+ ## Features
26
+
27
+ - **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.
28
+ - **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.
29
+ - **Session persistence** — Every turn is saved automatically; `--resume` / `/resume` picks up a past session.
30
+ - **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).
31
+ - **Optional desktop pet** — A small floating window (`/pet`) shows a stateful character that mirrors agent activity (idle / thinking / tool running / waiting for human). Works as a separate process over WebSocket; quit it with `/pet quit`. Sits beside the terminal, never blocks it.
32
+ - **Slash commands** — `/exit` `/clear` `/context` `/skills` `/compact` `/resume` `/rollback` `/memory` `/reflect` `/init` `/theme` `/model` `/plan` `/auto` `/pet`, with dropdown filtering as you type.
33
+
34
+ ## Installation
35
+
36
+ Requires Node.js ≥ 18.
37
+
38
+ ```bash
39
+ npm install -g mocode-ai
40
+ ```
41
+
42
+ This gives you the `mocode` command. Prefer not to install globally? Run it directly with `npx mocode-ai`.
43
+
44
+ > 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).
45
+
46
+ ### Run from source (development / contributing)
47
+
48
+ ```bash
49
+ git clone https://github.com/wanxunyang/mocode.git
50
+ cd mocode
51
+ npm install
52
+ npm start
53
+ ```
54
+
55
+ 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`.
56
+
57
+ ## Configuration
58
+
59
+ 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):
60
+
61
+ ```bash
62
+ mocode config
63
+ ```
64
+
65
+ 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`.
66
+
67
+ 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):
68
+
69
+ 1. `<cwd>/.env` — legacy compatibility, lowest priority (see `.env.example` in the source repo for reference)
70
+ 2. `~/.mocode/config` — global (written by `/model` and `mocode config`)
71
+ 3. `<cwd>/.mocode/config` — project-level override, highest priority
72
+
73
+ Three required fields:
74
+
75
+ ```env
76
+ LLM_BASE_URL=https://open.bigmodel.cn/api/v3 # swap in your backend
77
+ LLM_API_KEY=your-key-here
78
+ LLM_MODEL=glm-4.6 # swap in your model name
79
+ ```
80
+
81
+ Common backend `base_url` values:
82
+
83
+ | Backend | base\_url |
84
+ | -------------- | ---------------------------------------------------- |
85
+ | GLM (Zhipu) | `https://open.bigmodel.cn/api/v3` |
86
+ | DeepSeek | `https://api.deepseek.com` |
87
+ | Qwen (Alibaba) | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
88
+ | Local Ollama | `http://localhost:11434/v1` |
89
+ | Local vLLM | `http://localhost:8000/v1` |
90
+
91
+ > The model must support OpenAI-style function calling, otherwise tools won't be triggered.
92
+
93
+ ### Optional configuration
94
+
95
+ | Environment variable | Description | Default |
96
+ | --------------------------- | ---------------------------------------------------------------------- | --------------------------- |
97
+ | `MAX_TOKENS` | Max tokens per response | unlimited |
98
+ | `CONTEXT_WINDOW_TOKENS` | Model context window; must match the real model | `128000` |
99
+ | `COMPACT_THRESHOLD` | Auto-compaction trigger threshold (fraction of window) | `0.85` |
100
+ | `LLM_STREAM_USAGE` | Include `stream_options.include_usage` on streaming requests for real usage | `true` |
101
+ | `AUTO_COMPACT` | Auto-compaction master switch | `true` |
102
+ | `AUTO_REFLECT` | Background reflection pass master switch (periodically mines memories from conversations) | `true` |
103
+ | `REFLECT_EVERY_N` | Trigger a background reflection every N turns (runs alongside the agent, non-blocking) | `5` |
104
+ | `ANYSEARCH_API_KEY` | Web search API key (falls back to anonymous free quota if unset) | none |
105
+ | `ANYSEARCH_BASE_URL` | Search API endpoint | `https://api.anysearch.com` |
106
+ | `SKILLS_DIRS` | Override the default skill scan directories (platform path separator) | three default directories |
107
+ | `MOCODE_CONTEXT_OPTIMIZE` | Typed encoding of tool results before they reach the LLM (tree/search/log…); disable for raw passthrough (length trimming only) | `true` |
108
+ | `MAX_STEPS` | Max agent loop steps per turn (prevents infinite loops) | `200` |
109
+ | `SUB_AGENT_MAX_STEPS` | Default step cap for sub-agents (spawned via the `task` tool) | `50` |
110
+ | `SANDBOX_ROOT` | Sandbox root directory (file operation boundary; falls back to cwd if unset) | none |
111
+ | `MOCODE_THEME` | Color theme (default/dark/light…; shell env takes precedence over file) | `default` |
112
+
113
+ ## Usage
114
+
115
+ ```bash
116
+ mocode # new session (run inside your target project directory)
117
+ mocode --resume # list saved sessions
118
+ mocode --resume <id> # resume a specific session
119
+ mocode config # edit configuration
120
+ ```
121
+
122
+ Running from source uses `npm start` (equivalent to `mocode`, but skips the self-update check).
123
+
124
+ 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.
125
+
126
+ 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`.
127
+
128
+ ## Tools
129
+
130
+ | Tool | Purpose |
131
+ | ---------------- | ------------------------------------------------------------------------- |
132
+ | `read_file` | Read a file with line numbers; supports `offset` / `limit` |
133
+ | `write_file` | Create/overwrite a file, auto-creating parent directories |
134
+ | `edit_file` | Precise string replacement (`old_string` must match uniquely) |
135
+ | `run_command` | Run a shell command, merging stdout+stderr, 120s default timeout |
136
+ | `glob` | Find files by glob pattern (excludes node\_modules/.git) |
137
+ | `grep` | Regex content search, pure JS implementation, no `rg` dependency |
138
+ | `codegraph` | With a `.codegraph/` index built, query symbol source and call chains (more accurate and cheaper than read\_file/grep) |
139
+ | `web_search` | Web search (AnySearch), returns title/URL/snippet/body |
140
+ | `web_fetch` | Fetch a URL, cleaning HTML into plain text |
141
+ | `use_skill` | Load the full SKILL.md instructions for a given skill |
142
+ | `ask_human` | Pop up a Q&A panel at decision points; user picks a preset or types freely (blocks until answered) |
143
+ | `switch_mode` | Switch between `plan` (read-only planning) and `auto` (full execution); the agent can call this itself to explore before acting |
144
+ | `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) |
145
+ | `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 |
146
+ | `todolist` | Working notepad: write a multi-step plan to `.mocode/plans/<id>.md` (survives compression) and tick steps as you go; `finish` auto-archives, with `list / delete / unarchive` for history |
147
+ | `memory_save` | Save a piece of cross-session long-term memory (title indexed, body fetched on demand) |
148
+ | `memory_search` | Search memory bodies by keyword; hits boost the recall count (affects forgetting decay) |
149
+ | `memory_list` | List the memory index (id/title/summary, no body) |
150
+ | `memory_update` | Edit a memory in place (id unchanged; correct stale facts / update summary / toggle pin) |
151
+ | `memory_forget` | Forget a memory: archived by default (recoverable), `mode=delete` for a hard delete (pinned memories can't be deleted) |
152
+
153
+ The five `memory_*` tools are gated on `MEMORY_ENABLED=true` at startup; toggle at runtime with `/memory_switch` (REPL restart required, by design — see Skills section for the difference between Tier-1 `MOCODE.md` and Tier-2 memory).
154
+
155
+ ## Slash commands
156
+
157
+ | Command | Purpose |
158
+ | ------------------ | ----------------------------------------------------------------------- |
159
+ | `/exit` `/quit` | Exit MoCode |
160
+ | `/clear` | Clear history (keeps the system prompt) + clear screen |
161
+ | `/context` | Show a context usage bar (tokens / message count, estimated or measured) |
162
+ | `/skills` | List discovered skills |
163
+ | `/compact` | Compress history (optionally with a focus hint: `/compact …`) |
164
+ | `/resume` | Resume a saved session |
165
+ | `/rollback` | Menu to pick a turn to roll back to (↑↓ · Enter) |
166
+ | `/memory` | Show memory library: entry count + recent index |
167
+ | `/memory_switch` | Toggle Tier-2 memory on/off (REPL restart required by design) |
168
+ | `/reflect` | Manually trigger a background memory reflection pass |
169
+ | `/model` | Configure the LLM (baseURL / apiKey / model / context window), applied immediately + persisted |
170
+ | `/init` | Scan the project and generate `MOCODE.md` project memory (dispatched to the agent) |
171
+ | `/theme` | Switch color theme (↑↓ · Enter, or `/theme <name>` directly) |
172
+ | `/plan` | Switch to plan mode (read-only exploration + plan output, approve to switch to auto) |
173
+ | `/auto` | Switch back to auto mode (full toolset execution) |
174
+ | `/pet` | Toggle the optional desktop pet (floating window mirroring agent state) |
175
+ | `/pet skin` | Pick a pet skin (↑↓ · Enter) |
176
+ | `/pet quit` | Fully shut down the pet process (not just disconnect) |
177
+
178
+ Type `/` to trigger the dropdown menu, keep typing to filter; Esc to cancel.
179
+
180
+ ## Quick verification (after configuring your key)
181
+
182
+ ```
183
+ > hello, who are you # verify LLM connectivity
184
+ > read sample.txt # triggers read_file
185
+ > change foo to bar in sample.txt # triggers read_file + edit_file
186
+ > list all .txt files in this directory # triggers glob
187
+ > search the code for runAgent # triggers grep
188
+ > run node -e "console.log(1+1)" # triggers run_command
189
+ > search what's new in TypeScript 5.5 # triggers web_search
190
+ ```
191
+
192
+ 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.
193
+
194
+ ## Skills
195
+
196
+ MoCode automatically scans the following directories for skills (each skill is a `<name>/SKILL.md` with frontmatter):
197
+
198
+ - `~/.claude/skills/`
199
+ - `~/.mocode/skills/`
200
+ - `<cwd>/.mocode/skills/`
201
+
202
+ 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.
203
+
204
+ ## Project memory (MOCODE.md)
205
+
206
+ MoCode has a **two-tier memory** model distinct from skills:
207
+
208
+ - **Tier-1 — `MOCODE.md` (auto-loaded every session):** Markdown project memory that gets concatenated into the system prompt on every turn. Discovery walks `~/.mocode/MOCODE.md` → every `MOCODE.md` from the cwd up to the filesystem root (far→near, near wins). On overflow the body is truncated with a marker pointing back at the files. Generate or refresh one with `/init`, or write it by hand — it's plain Markdown, no schema. `MOCODE.md` is also where the agent itself persists "next-session facts" it deduces (architecture, conventions, pitfalls).
209
+ - **Tier-2 — `memory_*` tool library (agent-driven, opt-in):** Discrete tagged records (`decision` / `fact` / `pitfall` / `reference` / `feedback`) with recall-count-based decay (30-day → archived; 90-day GC). The agent saves / searches / updates / forgets via tools; titles go in the system-prompt index (≤50), bodies fetched on demand via `memory_search`. Off by default; toggle with `MEMORY_ENABLED=true` at startup or `/memory_switch` (REPL restart required).
210
+
211
+ ## Type checking
212
+
213
+ ```bash
214
+ npm run typecheck # tsc --noEmit
215
+ ```
216
+
217
+ ## Future extensions
218
+
219
+ MCP tool integration, a permission confirmation UI, and a real worktree-isolated sub-agent mode. The current version is a streaming, reasoning-visible, rollback-capable terminal coding agent with 20 tools, working-notepad planning, cross-session memory, parallel sub-agents, and an optional desktop pet.
package/README.zh-CN.md CHANGED
@@ -150,6 +150,8 @@ agent 工作在**启动时所在的工作目录**——想让它操作某个项
150
150
  | `memory_update` | 原地改一条记忆(id 不变;纠正过时事实 / 改摘要 / 改 pin) |
151
151
  | `memory_forget` | 遗忘记忆:默认归档(可复活),`mode=delete` 硬删(pinned 拒删) |
152
152
 
153
+ 5 个 `memory_*` 工具受启动时 `MEMORY_ENABLED=true` 总开关控制;运行时切换用 `/memory_switch`(需重启 REPL,刻意为之,见下「项目记忆」小节区分 Tier-1 / Tier-2)。
154
+
153
155
  ## 斜杠命令
154
156
 
155
157
  | 命令 | 作用 |
@@ -162,6 +164,7 @@ agent 工作在**启动时所在的工作目录**——想让它操作某个项
162
164
  | `/resume` | 续接已保存的会话 |
163
165
  | `/rollback` | 菜单选轮次回滚(↑↓ · Enter) |
164
166
  | `/memory` | 看记忆库:条目数 + 近期索引 |
167
+ | `/memory_switch` | 切换 Tier-2 记忆开关(需重启 REPL,刻意为之) |
165
168
  | `/reflect` | 手动触发一次后台记忆反思 pass |
166
169
  | `/model` | 配置大模型(baseURL / apiKey / model / 上下文窗口),即时生效 + 持久化 |
167
170
  | `/init` | 扫描项目生成 `MOCODE.md` 项目记忆(发给 agent 执行) |
@@ -198,6 +201,13 @@ mocode 自动扫描以下目录的 skill(每个 skill 是 `<name>/SKILL.md`,带
198
201
 
199
202
  skill 的 `description` 注入系统提示(渐进式披露第①层),模型只在任务相关时调 `use_skill` 加载完整正文(第②层)。用 `/skills` 查看已发现的 skill。
200
203
 
204
+ ## 项目记忆(MOCODE.md)
205
+
206
+ mocode 的**双层记忆**模型,跟 Skills 是两件事:
207
+
208
+ - **Tier-1 — `MOCODE.md`(每轮自动加载):** Markdown 项目记忆,每轮拼进 system prompt。发现路径:`~/.mocode/MOCODE.md` → 从 cwd 往上逐级 `MOCODE.md`(远→近拼接,近的覆盖更突出);超长截断并标注原始文件。运行 `/init` 生成或刷新,纯 Markdown,可手写,无 schema。agent 自己推得的「下次要记住的事实」(架构/约定/坑位)也写在这里。
209
+ - **Tier-2 — `memory_*` 工具库(agent 主导,需启用):** 离散带标签条目(`decision` / `fact` / `pitfall` / `reference` / `feedback`),按召回计数衰减(30 天 → archived,90 天 → 硬删 GC)。agent 用工具存 / 搜 / 改 / 删;索引(标题)进系统提示(≤50 条),正文按需 `memory_search` 取。默认关,启动 `MEMORY_ENABLED=true` 或 REPL 内 `/memory_switch`(需重启 REPL,刻意为之)。
210
+
201
211
  ## 类型检查
202
212
 
203
213
  ```bash
@@ -7,10 +7,13 @@ import { Spinner } from '../ui/spinner.js';
7
7
  import { summarizeToolCall, summarizeToolResult, truncateDisplay, fmtElapsed, } from '../ui/render.js';
8
8
  import { renderFileChange } from '../ui/diff.js';
9
9
  import * as layout from '../ui/layout.js';
10
+ import * as batch from '../ui/batch.js';
10
11
  import { beginTurn } from '../rollback/index.js';
11
12
  import { config } from '../config/index.js';
12
13
  import { runAgentCore, isMutationTool, } from './core.js';
13
14
  import { createPetHooks } from '../pet/state.js';
15
+ /** 当前 turn 的 batch id(runAgent 内闭包变量;一条 turn 一轮 tool batch 结束即清空)。 */
16
+ let currentBatchId = null;
14
17
  /** 取 userInput 的首行:字符串直接 split;多模态 parts 找首个 text part 再 split。 */
15
18
  function firstLineOf(ui) {
16
19
  if (typeof ui === 'string')
@@ -18,15 +21,22 @@ function firstLineOf(ui) {
18
21
  const first = ui.find((p) => p.type === 'text');
19
22
  return first?.text.split('\n')[0] ?? '';
20
23
  }
21
- /** 工具调用 ● 头:工具名 + 参数摘要(按 tool_calls 原顺序打印,让用户看到本轮跑哪些工具)。 */
24
+ /** 工具调用 ● 头:工具名 + 参数摘要(按 tool_calls 原顺序打印,让用户看到本轮跑哪些工具)。
25
+ * 重构后改为累积到 BatchRenderer,onToolBatchEnd 时统一打摘要行;
26
+ * 展开/折叠由 BatchRenderer + 鼠标 release 决定,本函数不再直接写屏。 */
22
27
  function writeToolHeader(tc) {
23
- const summary = summarizeToolCall(tc.name, tc.arguments);
24
- layout.contentWrite(` ${ui.brightMagenta}●${ui.reset} ${ui.cyan}${tc.name}${ui.reset} ${ui.dim}${summary}${ui.reset}\n`);
28
+ if (!currentBatchId)
29
+ currentBatchId = batch.beginBatch();
30
+ batch.recordCall(currentBatchId, tc.name, summarizeToolCall(tc.name, tc.arguments));
25
31
  }
26
- /** 渲染工具结果:mutation 成功走 diff 块(行号 + 语法高亮,仿 Claude Code);其余走一行 preview。 */
32
+ /** 渲染工具结果:mutation 成功走 diff 块(行号 + 语法高亮,仿 Claude Code);其余走一行 preview。
33
+ * 同 writeToolHeader,改为累积到 BatchRenderer(只缓存字符串,不写屏)。 */
27
34
  function writeToolResult(tc, output, parsed, preWriteOld, editStartLine) {
35
+ if (!currentBatchId)
36
+ return;
37
+ let diff = null;
28
38
  if (isMutationTool(tc.name) && parsed && !output.startsWith('错误')) {
29
- layout.contentWrite(renderFileChange({
39
+ diff = renderFileChange({
30
40
  path: String(parsed.path ?? ''),
31
41
  kind: tc.name === 'edit_file' ? 'edit' : 'write',
32
42
  oldStr: tc.name === 'edit_file'
@@ -34,14 +44,10 @@ function writeToolResult(tc, output, parsed, preWriteOld, editStartLine) {
34
44
  : preWriteOld,
35
45
  newStr: String((tc.name === 'edit_file' ? parsed.new_string : parsed.content) ?? ''),
36
46
  startLine: tc.name === 'edit_file' ? editStartLine : 1,
37
- }));
38
- }
39
- else {
40
- const preview = summarizeToolResult(tc.name, output);
41
- if (preview) {
42
- layout.contentWrite(` ${ui.gray}↳ ${preview}${ui.reset}\n`);
43
- }
47
+ });
44
48
  }
49
+ const preview = diff ? '' : summarizeToolResult(tc.name, output);
50
+ batch.recordResult(currentBatchId, tc.name, preview, diff);
45
51
  }
46
52
  /**
47
53
  * agent 核心循环(主 agent,TUI 渲染版):
@@ -63,6 +69,7 @@ onContextUpdate) {
63
69
  // 开新轮次(回滚用):首行截断 40,供 /rollback 轮次菜单展示。
64
70
  beginTurn(truncateDisplay(firstLineOf(userInput), 40));
65
71
  layout.contentMode(); // 防御性:运行态光标归输入框光标位供 IME 锚定(enterRunningMode 已置,这里兜底)
72
+ currentBatchId = null; // 新 turn 清旧 batch id(防上 turn 残留)
66
73
  // spinner:状态行最前面转圈(思考中 / 生成 / 执行 工具时,状态栏 lead 位显帧 + 文字)。
67
74
  // 经 setStatus 注入状态行(spinnerFrame + statusText),composeStatus 把帧 + 文字放 lead 位;
68
75
  // 不画内容区续写位——内容区在等待期间保持干净,首 token 到达即从续写位开始写正文。
@@ -101,7 +108,16 @@ onContextUpdate) {
101
108
  onToolStart: (name) => spinner.start(`执行 ${name}`),
102
109
  onToolDone: () => spinner.stop(),
103
110
  onToolResult: (tc, output, parsed, preWriteOld, editStartLine) => writeToolResult(tc, output, parsed, preWriteOld, editStartLine),
104
- onToolBatchEnd: () => layout.contentWrite('\n'),
111
+ onToolBatchEnd: () => {
112
+ // 收尾:把累积的 batch 渲染成单行摘要(批内 N 个 tool 调用共用一行,
113
+ // 鼠标点击该行可展开完整明细——见 ui/batch.ts)。无 batch(模型未调工具)则补空行保持间距。
114
+ if (currentBatchId) {
115
+ const id = currentBatchId;
116
+ currentBatchId = null;
117
+ batch.endBatch(id, layout);
118
+ }
119
+ layout.contentWrite('\n');
120
+ },
105
121
  onNoReply: () => layout.contentWrite(`${ui.dim}(无回复)${ui.reset}\n`),
106
122
  onMaxSteps: () => layout.contentWrite(` ${ui.yellow}●${ui.reset} ${ui.yellow}达到最大步数(${config.maxSteps}),本轮停止。${ui.reset}\n`),
107
123
  onAbort: () => {
@@ -109,6 +125,7 @@ onContextUpdate) {
109
125
  if (lastChar && lastChar !== '\n')
110
126
  layout.contentWrite('\n');
111
127
  layout.contentWrite(`${ui.dim}(已中断)${ui.reset}\n`);
128
+ currentBatchId = null; // 丢弃未收尾 batch
112
129
  },
113
130
  onDone: (elapsedMs, usage) => {
114
131
  const tok = formatTurnTokens(usage);