min-agent 0.1.5 → 0.1.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,6 +1,6 @@
1
1
  # min-agent
2
2
 
3
- Minimal yet powerful AI coding agent for the terminal. Supports any OpenAI-compatible API, MCP servers, skills, memory, and multi-agent parallel execution.
3
+ Minimal AI coding agent for the terminal. Works with any OpenAI-compatible API.
4
4
 
5
5
  ## Install
6
6
 
@@ -11,335 +11,134 @@ npm install -g min-agent
11
11
  ## Quick Start
12
12
 
13
13
  ```bash
14
- # 1. Configure your LLM provider
15
- min-agent setup
16
-
17
- # 2. Chat mode (general assistant)
18
- min-agent chat "what files are in this directory?"
19
-
20
- # 3. Code mode (project-aware AI coding)
21
- min-agent code
14
+ min-agent setup # Configure provider
15
+ min-agent chat "hello" # Single message
16
+ min-agent chat # Interactive session
17
+ min-agent code # Project-aware coding mode
22
18
  ```
23
19
 
24
20
  ---
25
21
 
26
22
  ## Commands
27
23
 
28
- ### Chat
29
-
30
- ```bash
31
- min-agent chat <message> # Single-shot message
32
- min-agent chat # Interactive multi-turn session
33
- min-agent chat --resume <id> # Resume a previous session
34
- min-agent chat -m <model> "msg" # Use a specific model
35
- min-agent chat -i img.png "what's this?" # Attach image
36
- ```
37
-
38
- ### Code (AI Coding Mode)
39
-
40
- ```bash
41
- min-agent code # Project-aware coding session
42
- min-agent code --resume <id> # Resume coding session
43
- ```
44
-
45
- Code mode automatically:
46
- - Scans the project (language, framework, git status, structure)
47
- - Uses a coding-optimized system prompt
48
- - Includes the `explore` tool for deep codebase analysis
49
- - Follows project conventions (no comments, match existing style)
50
-
51
- ### Configuration
52
-
53
24
  ```bash
54
- min-agent setup # Interactive provider setup
25
+ min-agent chat [message] # Chat (interactive if no message)
26
+ min-agent chat -m <model> "msg" # Override model
27
+ min-agent chat -i img.png "msg" # Attach image
28
+ min-agent chat --resume <id> # Resume session
29
+ min-agent code # AI coding mode (project scan)
30
+ min-agent setup # Configure API provider
55
31
  min-agent models # List available models
56
- min-agent rules # Show loaded instruction rules
57
- min-agent rules edit # Edit global rules file
58
- ```
59
-
60
- ### Memory
61
-
62
- ```bash
63
- min-agent memory # List all memories
64
- min-agent memory add "text" # Add manually
65
- min-agent memory search "query" # Search
66
- min-agent memory delete <n> # Delete by number
67
- ```
68
-
69
- The agent also saves memories automatically during conversations when you share preferences or important context.
70
-
71
- ### Sessions
72
-
73
- ```bash
74
32
  min-agent history # List saved sessions
75
- min-agent chat --resume <id> # Resume a session
76
- ```
77
-
78
- Sessions are auto-saved when you exit interactive chat/code mode, with LLM-generated titles.
79
-
80
- ### MCP (Model Context Protocol)
81
-
82
- ```bash
83
- min-agent mcp add <name> <cmd...> # Add local stdio server
84
- min-agent mcp add <name> --url <url> [--token <t>] # Add remote HTTP server
85
- min-agent mcp remove <name> # Remove server
86
- min-agent mcp list # List servers
87
- min-agent mcp check # Check connectivity
88
- ```
89
-
90
- ### Skills
91
-
92
- ```bash
93
- min-agent skills list # List available skills
94
- ```
95
-
96
- ### HTTP API
97
-
98
- ```bash
99
- min-agent serve # Start HTTP server (default :8787)
100
- min-agent serve --port 3000 # Custom port
33
+ min-agent rules # Show loaded rules
34
+ min-agent rules edit # Edit global rules
35
+ min-agent memory # List memories
36
+ min-agent memory add "text" # Save memory
37
+ min-agent mcp -h # MCP server management
38
+ min-agent skills -h # Skills management
39
+ min-agent serve # Start HTTP API server
101
40
  ```
102
41
 
103
- See [docs/API.md](docs/API.md) for full API reference.
104
-
105
- ---
106
-
107
42
  ## Interactive Commands
108
43
 
109
- In chat/code mode, use slash commands:
110
-
111
44
  | Command | Description |
112
45
  |---------|-------------|
113
- | `/clear` | Clear conversation history |
114
- | `/compact` | Force context compaction |
115
- | `/model [name]` | Show or change model |
116
- | `/memory [text]` | List or save memory |
117
- | `/tokens` | Show context window usage |
118
- | `/path` | Show working directory |
119
- | `/help` | Show all commands |
120
- | `/exit` | Exit session |
121
-
122
- **Ctrl+C** interrupts the current generation without exiting.
46
+ | `/clear` | Clear history |
47
+ | `/compact` | Force compaction |
48
+ | `/model [name]` | Show/change model |
49
+ | `/memory [text]` | List/save memory |
50
+ | `/tokens` | Context usage |
51
+ | `/paste [text]` | Clipboard image |
52
+ | `/path` | Working directory |
53
+ | `/help` | All commands |
54
+ | `/exit` | Exit |
55
+
56
+ **Ctrl+C** interrupts current generation.
123
57
 
124
58
  ---
125
59
 
126
60
  ## Configuration
127
61
 
128
- All config lives in `~/.min-agent/`:
129
-
130
- ```
131
- ~/.min-agent/
132
- ├── config.json # Provider, model, instructions
133
- ├── rules.md # Global rules (always injected)
134
- ├── mcp.json # MCP server definitions
135
- ├── memory.json # Persistent memories
136
- ├── models-cache.json # Model list cache (fallback)
137
- ├── context-window-cache.json # Context window cache
138
- └── sessions/ # Saved conversation sessions
139
- ```
140
-
141
- ### config.json
62
+ All config in `~/.min-agent/`:
142
63
 
143
64
  ```json
65
+ // ~/.min-agent/config.json
144
66
  {
145
67
  "provider": {
146
68
  "type": "openai-compatible",
147
69
  "baseURL": "https://api.openai.com/v1",
148
70
  "apiKey": "sk-...",
149
- "defaultModel": "gpt-4o",
71
+ "defaultModel": "gpt-5.5",
150
72
  "contextWindow": 128000
151
73
  },
152
- "instructions": [
153
- "./docs/CODING_RULES.md",
154
- "https://example.com/team-rules.md"
155
- ]
74
+ "instructions": ["./docs/rules.md"],
75
+ "disabledSkills": []
156
76
  }
157
77
  ```
158
78
 
159
- ### Provider Types
160
-
161
- | Type | Description |
162
- |------|-------------|
163
- | `openai-compatible` | Any OpenAI-compatible API (MiniMax, DeepSeek, vLLM, etc.) |
164
- | `openai` | OpenAI official |
165
- | `ollama` | Local Ollama (`http://localhost:11434/v1`) |
166
-
167
- ### Context Window Auto-Detection
168
-
169
- The context window size is automatically detected from:
170
- 1. `config.provider.contextWindow` (manual override)
171
- 2. OpenRouter API (`context_length`)
172
- 3. Ollama API (`/api/show`)
173
- 4. vLLM API (`max_model_len`)
174
- 5. [models.dev](https://models.dev) database
175
- 6. Fallback: 128,000 tokens
79
+ Provider types: `openai-compatible` | `openai` | `ollama`
176
80
 
177
81
  ---
178
82
 
179
- ## Tools
180
-
181
- ### Built-in
182
-
183
- | Tool | Description |
184
- |------|-------------|
185
- | `bash` | Shell commands (async, timeout, Ctrl+C killable) |
186
- | `read` | Read files (with context-aware instruction discovery) |
187
- | `write` | Write/create files (with overwrite confirmation) |
188
- | `edit` | Search/replace precise editing |
189
- | `glob` | Find files by pattern |
190
- | `grep` | Search file contents with regex |
191
- | `web_search` | Web search via SearXNG |
192
- | `web_fetch` | Fetch URLs (with Firecrawl fallback for SPAs) |
193
- | `todo` | Task tracking with progress visibility |
194
- | `question` | Ask user for clarification |
195
- | `task` | Spawn parallel sub-agents |
196
- | `explore` | Deep codebase exploration (read-only sub-agent) |
197
- | `skill` | Load domain-specific instructions |
198
- | `memory_save` | Save information for future sessions |
199
- | `memory_search` | Search saved memories |
200
- | `memory_delete` | Remove a memory |
201
- | `codesearch` | Semantic code search via Exa (requires `EXA_API_KEY`) |
202
-
203
- ### Sub-Agent System
204
-
205
- The `task` tool spawns independent sub-agents that:
206
- - Have their own context and tool access
207
- - Can run in parallel (call multiple tasks at once)
208
- - Are limited to 15 steps with doom loop detection
209
- - Cannot spawn further sub-agents (no recursion)
210
-
211
- The `explore` tool is a specialized read-only sub-agent for codebase exploration with configurable thoroughness (quick/medium/thorough).
212
-
213
- ### Plugins
214
-
215
- Custom tools can be loaded from:
216
- - `.min-agent/tools/*.ts` (project-level)
217
- - `~/.min-agent/tools/*.ts` (global)
218
-
219
- ```typescript
220
- // .min-agent/tools/deploy.ts
221
- export const deploy = {
222
- description: "Deploy the application",
223
- parameters: { env: { type: "string", description: "Target environment" } },
224
- execute: async ({ env }) => {
225
- // your logic
226
- return `Deployed to ${env}`
227
- }
228
- }
229
- ```
230
-
231
- ---
232
-
233
- ## MCP (Model Context Protocol)
234
-
235
- Connect external tool servers:
83
+ ## MCP
236
84
 
237
85
  ```bash
238
- # Local stdio servers
239
- min-agent mcp add filesystem npx -y @modelcontextprotocol/server-filesystem /tmp
240
- min-agent mcp add fetch npx -y @modelcontextprotocol/server-fetch
241
-
242
- # Remote HTTP servers
243
- min-agent mcp add remote-api --url https://mcp.example.com --token $TOKEN
86
+ min-agent mcp add <name> <cmd...> # Local stdio
87
+ min-agent mcp add <name> --url <url> --token T # Remote HTTP
88
+ min-agent mcp list # List (name + status)
89
+ min-agent mcp info <name> # Details
90
+ min-agent mcp enable/disable <name...> # Toggle
91
+ min-agent mcp remove <name> # Remove
92
+ min-agent mcp check # Test connectivity
244
93
  ```
245
94
 
246
- MCP tools are automatically namespaced (`servername_toolname`) and available in all modes.
247
-
248
- Supports:
249
- - Stdio transport (local processes)
250
- - Streamable HTTP transport
251
- - SSE transport (legacy)
252
- - OAuth authentication detection
253
- - Auto-reconnect on failure
254
-
255
- ---
256
-
257
95
  ## Skills
258
96
 
259
- Skills provide domain-specific instructions loaded on demand.
260
-
261
- ```
262
- .min-agent/skills/my-skill/SKILL.md
97
+ ```bash
98
+ min-agent skills list # List (name + status)
99
+ min-agent skills info <name> # Details
100
+ min-agent skills enable/disable <name...> # Toggle
263
101
  ```
264
102
 
103
+ Create: `.min-agent/skills/<name>/SKILL.md` or `~/.agents/skills/<name>/SKILL.md`
104
+
265
105
  ```markdown
266
106
  ---
267
107
  name: my-skill
268
- description: What this skill does
108
+ description: What it does
269
109
  ---
270
-
271
- # Instructions for the agent...
110
+ # Instructions...
272
111
  ```
273
112
 
274
- Discovery locations:
275
- - `.min-agent/skills/` (project)
276
- - `.opencode/skills/` (project)
277
- - `.claude/skills/` (project, compatibility)
278
-
279
- ---
280
-
281
- ## Rules (Instructions)
282
-
283
- Rules are injected into every conversation as system instructions.
284
-
285
- | Source | Priority |
286
- |--------|----------|
287
- | `~/.min-agent/rules.md` | Global (always loaded) |
288
- | `./AGENTS.md` or `./RULES.md` | Project-level |
289
- | `.min-agent/AGENTS.md` | Project-level |
290
- | `config.instructions[]` | Paths or URLs |
113
+ ## Rules
291
114
 
292
- **Context-aware**: When the agent reads a file, nearby `AGENTS.md`/`RULES.md` files are automatically discovered and injected.
115
+ | Source | Scope |
116
+ |--------|-------|
117
+ | `~/.min-agent/rules.md` | Global |
118
+ | `./AGENTS.md` or `./RULES.md` | Project |
119
+ | `config.instructions[]` | Custom paths/URLs |
293
120
 
294
- ---
295
-
296
- ## Memory
121
+ ## Plugins
297
122
 
298
- The agent remembers things across sessions:
123
+ Custom tools: `.min-agent/tools/*.ts` or `~/.min-agent/tools/*.ts`
299
124
 
300
- ```bash
301
- min-agent memory add "I prefer functional style"
302
- min-agent memory add "Project uses PostgreSQL"
125
+ ```typescript
126
+ export const myTool = {
127
+ description: "...",
128
+ parameters: { arg: { type: "string", description: "..." } },
129
+ execute: async ({ arg }) => "result"
130
+ }
303
131
  ```
304
132
 
305
- Or just tell the agent: "记住:我喜欢用中文回复" — it will automatically save the memory.
306
-
307
- Memories are injected into the system prompt so the agent always has access to them.
308
-
309
- ---
310
-
311
- ## Safety Features
312
-
313
- - **Dangerous command confirmation**: `rm -rf`, `sudo`, `git push --force` etc. require approval
314
- - **File overwrite confirmation**: Existing files prompt before overwriting
315
- - **Doom loop detection**: Breaks infinite tool call loops (3 identical calls)
316
- - **Auto-compaction**: Prevents context overflow with structured summarization
317
- - **`--yes` / `-y` flag**: Skip all confirmations (for automation)
318
-
319
- ---
320
-
321
- ## Context Management
322
-
323
- - **Real token tracking**: Uses API response usage data (not estimation)
324
- - **Auto-compaction**: Triggers at 75% of context window
325
- - **Structured summaries**: Goal/Progress/Decisions/Files format
326
- - **Incremental updates**: Updates existing summary instead of rewriting
327
- - **Tool output pruning**: Trims old tool outputs to save space
328
- - **Auto-continue**: After compaction, agent continues working automatically
329
-
330
133
  ---
331
134
 
332
135
  ## HTTP API
333
136
 
334
- Start with `min-agent serve`. Full reference: [docs/API.md](docs/API.md)
137
+ ```bash
138
+ min-agent serve [--port 8787]
139
+ ```
335
140
 
336
- Key endpoints:
337
- - `POST /v1/chat` — Chat (streaming SSE or JSON)
338
- - `GET /v1/sessions` — List sessions
339
- - `GET /v1/memory` — List memories
340
- - `GET /v1/mcp` — MCP status
341
- - `GET /v1/project` — Project scan
342
- - `POST /v1/chat/compact` — Manual compaction
141
+ Full reference: [docs/API.md](docs/API.md)
343
142
 
344
143
  ---
345
144
 
@@ -347,13 +146,10 @@ Key endpoints:
347
146
 
348
147
  | Variable | Description |
349
148
  |----------|-------------|
350
- | `AGENT_MODEL` | Override default model |
351
- | `EXA_API_KEY` | Enable Exa code search tool |
352
- | `MIN_AGENT_SHOW_THINKING` | Set to `0` to hide thinking output |
353
- | `MIN_AGENT_SERVE_TOKEN` | API auth token for serve mode |
354
- | `MIN_AGENT_SERVE_CORS` | Enable CORS for serve mode |
355
-
356
- ---
149
+ | `EXA_API_KEY` | Enable Exa code search |
150
+ | `MIN_AGENT_SHOW_THINKING` | `0` to hide thinking |
151
+ | `MIN_AGENT_SERVE_TOKEN` | API auth token |
152
+ | `MIN_AGENT_SERVE_CORS` | `1` to enable CORS |
357
153
 
358
154
  ## License
359
155
 
package/dist/agent.js CHANGED
@@ -53,7 +53,7 @@ function buildSystemPrompt(instructions) {
53
53
  `Platform: ${process.platform}`,
54
54
  `Date: ${new Date().toDateString()}`,
55
55
  "",
56
- "min-agent: when the user asks to configure or install this agent (MCP, skills, rules, CLI, HTTP API, etc.), use the **read** tool on `README.md` in the working directory first, then follow what it says.",
56
+ `When the user asks to configure, install, or manage MCP servers, skills, rules, memory, or other min-agent features, use the read tool on the file at ${path.resolve(path.dirname(new URL(import.meta.url).pathname), "../README.md")} first, then follow what it says.`,
57
57
  ];
58
58
  const skillsPrompt = getSkillsSystemPrompt();
59
59
  if (skillsPrompt) {
@@ -159,37 +159,57 @@ export async function runChat(modelId, resumeSessionId) {
159
159
  });
160
160
  console.log("\x1b[90m输入消息开始对话,输入 /help 查看命令,/exit 退出\x1b[0m\n");
161
161
  rl.prompt();
162
- for await (const line of rl) {
163
- const input = line.trim();
162
+ // Multi-line paste detection: collect rapid successive lines
163
+ let pasteBuffer = [];
164
+ let pasteTimer = null;
165
+ const PASTE_DEBOUNCE_MS = 50;
166
+ const processInput = async (text) => {
167
+ const input = text.trim();
164
168
  if (!input) {
165
169
  rl.prompt();
166
- continue;
170
+ return;
167
171
  }
168
- // Handle slash commands
169
172
  if (input.startsWith("/")) {
170
173
  const handled = await handleSlashCommand(input, messages, instructions, modelId, rl, tracker);
171
- if (handled === "exit")
172
- break;
174
+ if (handled === "exit") {
175
+ rl.close();
176
+ return;
177
+ }
173
178
  if (handled === "paste") {
174
179
  console.log();
175
180
  abortController = new AbortController();
176
181
  await runOnce(messages, instructions, modelId, abortController.signal, undefined, tracker);
177
182
  abortController = null;
178
183
  console.log();
179
- rl.prompt();
180
- continue;
181
184
  }
182
185
  rl.prompt();
183
- continue;
186
+ return;
184
187
  }
188
+ // Show paste feedback for large inputs
189
+ const { processPastedInput, printPasteFeedback } = await import("./paste-handler.js");
190
+ const pasteResult = processPastedInput(input);
191
+ printPasteFeedback(pasteResult);
185
192
  console.log();
186
- messages.push({ role: "user", content: input });
193
+ messages.push({ role: "user", content: pasteResult.fullText });
187
194
  abortController = new AbortController();
188
195
  await runOnce(messages, instructions, modelId, abortController.signal, undefined, tracker);
189
196
  abortController = null;
190
197
  console.log();
191
198
  rl.prompt();
192
- }
199
+ };
200
+ rl.on("line", (line) => {
201
+ pasteBuffer.push(line);
202
+ if (pasteTimer)
203
+ clearTimeout(pasteTimer);
204
+ pasteTimer = setTimeout(() => {
205
+ const combined = pasteBuffer.join("\n");
206
+ pasteBuffer = [];
207
+ pasteTimer = null;
208
+ processInput(combined);
209
+ }, PASTE_DEBOUNCE_MS);
210
+ });
211
+ // Wait for close
212
+ await new Promise((resolve) => rl.on("close", resolve));
193
213
  // Auto-save session on exit with LLM-generated title
194
214
  if (messages.length > 0) {
195
215
  const { saveSessionWithTitle } = await import("./sessions.js");
@@ -197,7 +217,6 @@ export async function runChat(modelId, resumeSessionId) {
197
217
  sessionId = await saveSessionWithTitle(messages, model, sessionId);
198
218
  console.log(`\x1b[90m Session saved: ${sessionId}\x1b[0m`);
199
219
  }
200
- rl.close();
201
220
  printDivider();
202
221
  console.log("\x1b[90mBye!\x1b[0m");
203
222
  await shutdownMcp();
@@ -248,37 +267,54 @@ export async function runCode(modelId, resumeSessionId) {
248
267
  });
249
268
  console.log("\x1b[90m输入任务开始编码,/help 查看命令,Ctrl+C 中断\x1b[0m\n");
250
269
  rl.prompt();
251
- for await (const line of rl) {
252
- const input = line.trim();
270
+ let pasteBuffer = [];
271
+ let pasteTimer = null;
272
+ const PASTE_DEBOUNCE_MS = 50;
273
+ const processCodeInput = async (text) => {
274
+ const input = text.trim();
253
275
  if (!input) {
254
276
  rl.prompt();
255
- continue;
277
+ return;
256
278
  }
257
279
  if (input.startsWith("/")) {
258
280
  const handled = await handleSlashCommand(input, messages, [codePrompt], modelId, rl, tracker);
259
- if (handled === "exit")
260
- break;
281
+ if (handled === "exit") {
282
+ rl.close();
283
+ return;
284
+ }
261
285
  if (handled === "paste") {
262
286
  console.log();
263
287
  abortController = new AbortController();
264
288
  await runOnceWithSystem(messages, codePrompt, modelId, abortController.signal, undefined, tracker);
265
289
  abortController = null;
266
290
  console.log();
267
- rl.prompt();
268
- continue;
269
291
  }
270
292
  rl.prompt();
271
- continue;
293
+ return;
272
294
  }
295
+ const { processPastedInput, printPasteFeedback } = await import("./paste-handler.js");
296
+ const pasteResult = processPastedInput(input);
297
+ printPasteFeedback(pasteResult);
273
298
  console.log();
274
- messages.push({ role: "user", content: input });
299
+ messages.push({ role: "user", content: pasteResult.fullText });
275
300
  abortController = new AbortController();
276
- // Use code system prompt instead of generic one
277
301
  await runOnceWithSystem(messages, codePrompt, modelId, abortController.signal, undefined, tracker);
278
302
  abortController = null;
279
303
  console.log();
280
304
  rl.prompt();
281
- }
305
+ };
306
+ rl.on("line", (line) => {
307
+ pasteBuffer.push(line);
308
+ if (pasteTimer)
309
+ clearTimeout(pasteTimer);
310
+ pasteTimer = setTimeout(() => {
311
+ const combined = pasteBuffer.join("\n");
312
+ pasteBuffer = [];
313
+ pasteTimer = null;
314
+ processCodeInput(combined);
315
+ }, PASTE_DEBOUNCE_MS);
316
+ });
317
+ await new Promise((resolve) => rl.on("close", resolve));
282
318
  if (messages.length > 0) {
283
319
  const { saveSessionWithTitle } = await import("./sessions.js");
284
320
  const model = resolveModel(modelId);
@@ -499,6 +535,7 @@ async function handleSlashCommand(input, messages, instructions, modelId, rl, tr
499
535
  case "exit":
500
536
  case "quit":
501
537
  case "q":
538
+ console.log("\x1b[90m⟳ Exiting...\x1b[0m");
502
539
  return "exit";
503
540
  case "clear":
504
541
  messages.length = 0;
@@ -581,12 +618,11 @@ async function handleSlashCommand(input, messages, instructions, modelId, rl, tr
581
618
  discoverSkills();
582
619
  const skills = getSkills();
583
620
  if (skills.length === 0) {
584
- console.log("\x1b[90m No skills found\x1b[0m");
621
+ console.log("\x1b[90m No skills available\x1b[0m");
585
622
  }
586
623
  else {
587
- console.log(`\x1b[90m Available skills (${skills.length}):\x1b[0m`);
588
624
  for (const skill of skills) {
589
- console.log(`\x1b[90m - ${skill.name}: ${skill.description}\x1b[0m`);
625
+ console.log(`\x1b[90m ${skill.name} enabled\x1b[0m`);
590
626
  }
591
627
  }
592
628
  return "handled";