min-agent 0.1.5 → 0.1.7
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 +73 -277
- package/dist/agent.js +72 -40
- package/dist/assistant-stream.js +14 -1
- package/dist/cli.js +157 -26
- package/dist/confirm.js +15 -6
- package/dist/markdown.js +147 -3
- package/dist/mcp.js +54 -12
- package/dist/paste-handler.js +41 -0
- package/dist/skills.js +15 -7
- package/dist/tools/bash.js +5 -1
- package/dist/tools/index.js +21 -1
- package/docs/API.md +82 -173
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# min-agent
|
|
2
2
|
|
|
3
|
-
Minimal
|
|
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
|
-
#
|
|
15
|
-
min-agent
|
|
16
|
-
|
|
17
|
-
#
|
|
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
|
|
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
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
114
|
-
| `/compact` | Force
|
|
115
|
-
| `/model [name]` | Show
|
|
116
|
-
| `/memory [text]` | List
|
|
117
|
-
| `/tokens` |
|
|
118
|
-
| `/
|
|
119
|
-
| `/
|
|
120
|
-
| `/
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
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-
|
|
71
|
+
"defaultModel": "gpt-5.5",
|
|
150
72
|
"contextWindow": 128000
|
|
151
73
|
},
|
|
152
|
-
"instructions": [
|
|
153
|
-
|
|
154
|
-
"https://example.com/team-rules.md"
|
|
155
|
-
]
|
|
74
|
+
"instructions": ["./docs/rules.md"],
|
|
75
|
+
"disabledSkills": []
|
|
156
76
|
}
|
|
157
77
|
```
|
|
158
78
|
|
|
159
|
-
|
|
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
|
-
##
|
|
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
|
|
239
|
-
min-agent mcp add
|
|
240
|
-
min-agent mcp
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
min-agent mcp
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
|
108
|
+
description: What it does
|
|
269
109
|
---
|
|
270
|
-
|
|
271
|
-
# Instructions for the agent...
|
|
110
|
+
# Instructions...
|
|
272
111
|
```
|
|
273
112
|
|
|
274
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
+
Custom tools: `.min-agent/tools/*.ts` or `~/.min-agent/tools/*.ts`
|
|
299
124
|
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
137
|
+
```bash
|
|
138
|
+
min-agent serve [--port 8787]
|
|
139
|
+
```
|
|
335
140
|
|
|
336
|
-
|
|
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
|
-
| `
|
|
351
|
-
| `
|
|
352
|
-
| `
|
|
353
|
-
| `
|
|
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
|
@@ -2,7 +2,7 @@ import { streamText, stepCountIs } from "ai";
|
|
|
2
2
|
import { readFileSync, existsSync } from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { resolveModel } from "./provider.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createChatTools, createCodeTools } from "./tools/index.js";
|
|
6
6
|
import { initMcp, shutdownMcp, getMcpTools, loadMcpConfig, getMcpStatus } from "./mcp.js";
|
|
7
7
|
import { discoverSkills, getSkillsTool, getSkillsSystemPrompt, getSkills } from "./skills.js";
|
|
8
8
|
import { loadInstructions } from "./instructions.js";
|
|
@@ -53,7 +53,7 @@ function buildSystemPrompt(instructions) {
|
|
|
53
53
|
`Platform: ${process.platform}`,
|
|
54
54
|
`Date: ${new Date().toDateString()}`,
|
|
55
55
|
"",
|
|
56
|
-
|
|
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,45 +159,63 @@ export async function runChat(modelId, resumeSessionId) {
|
|
|
159
159
|
});
|
|
160
160
|
console.log("\x1b[90m输入消息开始对话,输入 /help 查看命令,/exit 退出\x1b[0m\n");
|
|
161
161
|
rl.prompt();
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
}
|
|
193
|
-
|
|
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));
|
|
213
|
+
// Auto-save session on exit
|
|
194
214
|
if (messages.length > 0) {
|
|
195
|
-
const {
|
|
196
|
-
|
|
197
|
-
sessionId = await saveSessionWithTitle(messages, model, sessionId);
|
|
215
|
+
const { saveSession } = await import("./sessions.js");
|
|
216
|
+
sessionId = saveSession(messages, sessionId);
|
|
198
217
|
console.log(`\x1b[90m Session saved: ${sessionId}\x1b[0m`);
|
|
199
218
|
}
|
|
200
|
-
rl.close();
|
|
201
219
|
printDivider();
|
|
202
220
|
console.log("\x1b[90mBye!\x1b[0m");
|
|
203
221
|
await shutdownMcp();
|
|
@@ -248,41 +266,57 @@ export async function runCode(modelId, resumeSessionId) {
|
|
|
248
266
|
});
|
|
249
267
|
console.log("\x1b[90m输入任务开始编码,/help 查看命令,Ctrl+C 中断\x1b[0m\n");
|
|
250
268
|
rl.prompt();
|
|
251
|
-
|
|
252
|
-
|
|
269
|
+
let pasteBuffer = [];
|
|
270
|
+
let pasteTimer = null;
|
|
271
|
+
const PASTE_DEBOUNCE_MS = 50;
|
|
272
|
+
const processCodeInput = async (text) => {
|
|
273
|
+
const input = text.trim();
|
|
253
274
|
if (!input) {
|
|
254
275
|
rl.prompt();
|
|
255
|
-
|
|
276
|
+
return;
|
|
256
277
|
}
|
|
257
278
|
if (input.startsWith("/")) {
|
|
258
279
|
const handled = await handleSlashCommand(input, messages, [codePrompt], modelId, rl, tracker);
|
|
259
|
-
if (handled === "exit")
|
|
260
|
-
|
|
280
|
+
if (handled === "exit") {
|
|
281
|
+
rl.close();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
261
284
|
if (handled === "paste") {
|
|
262
285
|
console.log();
|
|
263
286
|
abortController = new AbortController();
|
|
264
287
|
await runOnceWithSystem(messages, codePrompt, modelId, abortController.signal, undefined, tracker);
|
|
265
288
|
abortController = null;
|
|
266
289
|
console.log();
|
|
267
|
-
rl.prompt();
|
|
268
|
-
continue;
|
|
269
290
|
}
|
|
270
291
|
rl.prompt();
|
|
271
|
-
|
|
292
|
+
return;
|
|
272
293
|
}
|
|
294
|
+
const { processPastedInput, printPasteFeedback } = await import("./paste-handler.js");
|
|
295
|
+
const pasteResult = processPastedInput(input);
|
|
296
|
+
printPasteFeedback(pasteResult);
|
|
273
297
|
console.log();
|
|
274
|
-
messages.push({ role: "user", content:
|
|
298
|
+
messages.push({ role: "user", content: pasteResult.fullText });
|
|
275
299
|
abortController = new AbortController();
|
|
276
|
-
// Use code system prompt instead of generic one
|
|
277
300
|
await runOnceWithSystem(messages, codePrompt, modelId, abortController.signal, undefined, tracker);
|
|
278
301
|
abortController = null;
|
|
279
302
|
console.log();
|
|
280
303
|
rl.prompt();
|
|
281
|
-
}
|
|
304
|
+
};
|
|
305
|
+
rl.on("line", (line) => {
|
|
306
|
+
pasteBuffer.push(line);
|
|
307
|
+
if (pasteTimer)
|
|
308
|
+
clearTimeout(pasteTimer);
|
|
309
|
+
pasteTimer = setTimeout(() => {
|
|
310
|
+
const combined = pasteBuffer.join("\n");
|
|
311
|
+
pasteBuffer = [];
|
|
312
|
+
pasteTimer = null;
|
|
313
|
+
processCodeInput(combined);
|
|
314
|
+
}, PASTE_DEBOUNCE_MS);
|
|
315
|
+
});
|
|
316
|
+
await new Promise((resolve) => rl.on("close", resolve));
|
|
282
317
|
if (messages.length > 0) {
|
|
283
|
-
const {
|
|
284
|
-
|
|
285
|
-
sessionId = await saveSessionWithTitle(messages, model, sessionId);
|
|
318
|
+
const { saveSession } = await import("./sessions.js");
|
|
319
|
+
sessionId = saveSession(messages, sessionId);
|
|
286
320
|
console.log(`\x1b[90m Session saved: ${sessionId}\x1b[0m`);
|
|
287
321
|
}
|
|
288
322
|
rl.close();
|
|
@@ -308,7 +342,7 @@ export async function runOnceWithSystem(messages, systemPrompt, modelId, abortSi
|
|
|
308
342
|
console.log(`\x1b[90m ✓ Compacted (${estimateTokens(messages)} tokens estimated)\x1b[0m`);
|
|
309
343
|
}
|
|
310
344
|
}
|
|
311
|
-
const builtinTools =
|
|
345
|
+
const builtinTools = createCodeTools();
|
|
312
346
|
const mcpTools = getMcpTools();
|
|
313
347
|
const memoryTools = getMemoryTools();
|
|
314
348
|
const pluginTools = await loadPluginTools();
|
|
@@ -499,6 +533,7 @@ async function handleSlashCommand(input, messages, instructions, modelId, rl, tr
|
|
|
499
533
|
case "exit":
|
|
500
534
|
case "quit":
|
|
501
535
|
case "q":
|
|
536
|
+
console.log("\x1b[90m⟳ Exiting...\x1b[0m");
|
|
502
537
|
return "exit";
|
|
503
538
|
case "clear":
|
|
504
539
|
messages.length = 0;
|
|
@@ -581,12 +616,11 @@ async function handleSlashCommand(input, messages, instructions, modelId, rl, tr
|
|
|
581
616
|
discoverSkills();
|
|
582
617
|
const skills = getSkills();
|
|
583
618
|
if (skills.length === 0) {
|
|
584
|
-
console.log("\x1b[90m No skills
|
|
619
|
+
console.log("\x1b[90m No skills available\x1b[0m");
|
|
585
620
|
}
|
|
586
621
|
else {
|
|
587
|
-
console.log(`\x1b[90m Available skills (${skills.length}):\x1b[0m`);
|
|
588
622
|
for (const skill of skills) {
|
|
589
|
-
console.log(`\x1b[90m
|
|
623
|
+
console.log(`\x1b[90m ${skill.name} enabled\x1b[0m`);
|
|
590
624
|
}
|
|
591
625
|
}
|
|
592
626
|
return "handled";
|
|
@@ -698,12 +732,11 @@ export async function runOnce(messages, instructions, modelId, abortSignal, call
|
|
|
698
732
|
}
|
|
699
733
|
}
|
|
700
734
|
}
|
|
701
|
-
// Merge
|
|
702
|
-
const builtinTools =
|
|
735
|
+
// Merge tools: chat builtin + MCP + skill + memory + plugins (no task/explore in chat mode)
|
|
736
|
+
const builtinTools = createChatTools();
|
|
703
737
|
const mcpTools = getMcpTools();
|
|
704
738
|
const memoryTools = getMemoryTools();
|
|
705
739
|
const pluginTools = await loadPluginTools();
|
|
706
|
-
const { createTaskTool } = await import("./tools/task.js");
|
|
707
740
|
const skills = getSkills();
|
|
708
741
|
const allTools = { ...builtinTools, ...memoryTools, ...pluginTools };
|
|
709
742
|
for (const [id, t] of Object.entries(mcpTools)) {
|
|
@@ -712,7 +745,6 @@ export async function runOnce(messages, instructions, modelId, abortSignal, call
|
|
|
712
745
|
if (skills.length > 0) {
|
|
713
746
|
allTools["skill"] = getSkillsTool();
|
|
714
747
|
}
|
|
715
|
-
allTools["task"] = createTaskTool(modelId);
|
|
716
748
|
let stepCount = 0;
|
|
717
749
|
let hasError = false;
|
|
718
750
|
const doomLoop = new DoomLoopDetector();
|