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/dist/skills.js CHANGED
@@ -3,6 +3,7 @@ import { readFileSync, existsSync, readdirSync, statSync } from "fs";
3
3
  import os from "os";
4
4
  import path from "path";
5
5
  import { globSync } from "glob";
6
+ import { loadConfig } from "./config.js";
6
7
  /**
7
8
  * Skill scan order: later entries win on duplicate `name` in frontmatter.
8
9
  * Global user skills first, then project-local dirs so repo skills override ~/.agents.
@@ -15,7 +16,7 @@ const SKILL_DIRS = [
15
16
  path.join(process.cwd(), ".claude", "skills"),
16
17
  ];
17
18
  let loadedSkills = {};
18
- export function discoverSkills() {
19
+ export function discoverSkills(opts) {
19
20
  loadedSkills = {};
20
21
  for (const dir of SKILL_DIRS) {
21
22
  if (!existsSync(dir))
@@ -29,8 +30,10 @@ export function discoverSkills() {
29
30
  }
30
31
  }
31
32
  const count = Object.keys(loadedSkills).length;
32
- if (count > 0) {
33
- console.log(`\x1b[90m Skills loaded: ${count} (${Object.keys(loadedSkills).join(", ")})\x1b[0m`);
33
+ if (count > 0 && !opts?.silent) {
34
+ const disabled = new Set(loadConfig().disabledSkills ?? []);
35
+ const enabledCount = Object.keys(loadedSkills).filter((n) => !disabled.has(n)).length;
36
+ console.log(`\x1b[90m Skills: ${enabledCount} enabled${count > enabledCount ? `, ${count - enabledCount} disabled` : ""}\x1b[0m`);
34
37
  }
35
38
  }
36
39
  function parseSkillFile(filePath) {
@@ -58,7 +61,8 @@ function parseSkillFile(filePath) {
58
61
  }
59
62
  }
60
63
  export function getSkills() {
61
- return Object.values(loadedSkills);
64
+ const disabled = new Set(loadConfig().disabledSkills ?? []);
65
+ return Object.values(loadedSkills).filter((s) => !disabled.has(s.name));
62
66
  }
63
67
  export function getSkill(name) {
64
68
  return loadedSkills[name];
@@ -74,9 +78,13 @@ export function getSkillsTool() {
74
78
  required: ["name"],
75
79
  }),
76
80
  execute: async ({ name }) => {
81
+ const disabled = new Set(loadConfig().disabledSkills ?? []);
82
+ if (disabled.has(name)) {
83
+ return `Skill "${name}" is disabled. Available skills: ${getSkills().map((s) => s.name).join(", ") || "none"}`;
84
+ }
77
85
  const skill = loadedSkills[name];
78
86
  if (!skill) {
79
- const available = Object.keys(loadedSkills);
87
+ const available = getSkills().map((s) => s.name);
80
88
  return `Skill "${name}" not found. Available skills: ${available.length ? available.join(", ") : "none"}`;
81
89
  }
82
90
  const dir = path.dirname(skill.location);
@@ -104,7 +112,7 @@ export function getSkillsTool() {
104
112
  });
105
113
  }
106
114
  export function getSkillsSystemPrompt() {
107
- const skills = Object.values(loadedSkills);
115
+ const skills = getSkills();
108
116
  if (skills.length === 0)
109
117
  return "";
110
118
  return [
@@ -115,7 +123,7 @@ export function getSkillsSystemPrompt() {
115
123
  ].join("\n");
116
124
  }
117
125
  function buildSkillDescription() {
118
- const skills = Object.values(loadedSkills);
126
+ const skills = getSkills();
119
127
  if (skills.length === 0)
120
128
  return "Load a specialized skill. No skills are currently available.";
121
129
  return [
@@ -21,11 +21,15 @@ export const bashTool = tool({
21
21
  const chunks = [];
22
22
  let killed = false;
23
23
  let timer;
24
- const proc = spawn(command, [], {
24
+ // On Windows, force UTF-8 codepage to avoid Chinese garbled text
25
+ const isWin = process.platform === "win32";
26
+ const actualCommand = isWin ? `chcp 65001 >nul && ${command}` : command;
27
+ const proc = spawn(actualCommand, [], {
25
28
  shell: true,
26
29
  cwd: process.cwd(),
27
30
  stdio: ["ignore", "pipe", "pipe"],
28
31
  detached: process.platform !== "win32",
32
+ env: { ...process.env, ...(isWin ? { PYTHONIOENCODING: "utf-8" } : {}) },
29
33
  });
30
34
  proc.stdout?.on("data", (chunk) => chunks.push(chunk));
31
35
  proc.stderr?.on("data", (chunk) => chunks.push(chunk));
@@ -9,7 +9,23 @@ import { webFetchTool } from "./web_fetch.js";
9
9
  import { todoTool } from "./todo.js";
10
10
  import { questionTool } from "./question.js";
11
11
  import { codeSearchTool } from "./code_search.js";
12
- export function createTools() {
12
+ /** Chat mode: general assistant tools (fewer tools = less token overhead) */
13
+ export function createChatTools() {
14
+ const tools = {
15
+ bash: bashTool,
16
+ read: readTool,
17
+ write: writeTool,
18
+ edit: editTool,
19
+ glob: globTool,
20
+ grep: grepTool,
21
+ web_search: webSearchTool,
22
+ web_fetch: webFetchTool,
23
+ question: questionTool,
24
+ };
25
+ return tools;
26
+ }
27
+ /** Code mode: full tool set including task tracking and code search */
28
+ export function createCodeTools() {
13
29
  const tools = {
14
30
  bash: bashTool,
15
31
  read: readTool,
@@ -27,3 +43,7 @@ export function createTools() {
27
43
  }
28
44
  return tools;
29
45
  }
46
+ /** @deprecated Use createChatTools or createCodeTools */
47
+ export function createTools() {
48
+ return createChatTools();
49
+ }
package/docs/API.md CHANGED
@@ -1,21 +1,19 @@
1
1
  # min-agent HTTP API
2
2
 
3
- 通过 `min-agent serve` 启动本地 HTTP 服务,以编程方式调用与 CLI 相同的代理能力。
3
+ `min-agent serve` 启动本地 HTTP 服务,以编程方式调用代理能力。
4
4
 
5
5
  ## 启动
6
6
 
7
7
  ```bash
8
8
  min-agent serve
9
- min-agent serve --host 127.0.0.1 --port 8787
9
+ min-agent serve --host 0.0.0.0 --port 3000
10
10
  ```
11
11
 
12
- 环境变量:
13
-
14
- | 变量 | 说明 |
15
- |------|------|
12
+ | 环境变量 | 说明 |
13
+ |----------|------|
16
14
  | `MIN_AGENT_SERVE_HOST` | 监听地址(默认 `127.0.0.1`) |
17
15
  | `MIN_AGENT_SERVE_PORT` | 端口(默认 `8787`) |
18
- | `MIN_AGENT_SERVE_TOKEN` | 设置后所有请求须带 `Authorization: Bearer <token>` |
16
+ | `MIN_AGENT_SERVE_TOKEN` | Bearer token 鉴权 |
19
17
  | `MIN_AGENT_SERVE_CORS` | 设为 `1` 启用 CORS |
20
18
 
21
19
  ---
@@ -25,26 +23,26 @@ min-agent serve --host 127.0.0.1 --port 8787
25
23
  | 方法 | 路径 | 说明 |
26
24
  |------|------|------|
27
25
  | GET | `/health` | 存活检查 |
28
- | GET | `/v1/meta` | 运行环境摘要 |
26
+ | GET | `/v1/meta` | 运行环境 |
29
27
  | GET | `/v1/models` | 模型列表 |
30
28
  | GET | `/v1/context` | 上下文窗口信息 |
31
- | GET | `/v1/project` | 项目扫描(code 模式) |
32
- | POST | `/v1/chat` | 对话(支持流式) |
33
- | POST | `/v1/paste` | 粘贴图片 + 文本对话 |
34
- | POST | `/v1/code` | Code 模式对话(项目感知) |
29
+ | GET | `/v1/project` | 项目扫描 |
30
+ | POST | `/v1/chat` | 对话 |
31
+ | POST | `/v1/code` | Code 模式对话 |
32
+ | POST | `/v1/paste` | 图片+文本对话 |
35
33
  | POST | `/v1/chat/compact` | 手动压缩会话 |
36
34
  | POST | `/v1/chat/reload-instructions` | 重载规则 |
37
- | GET | `/v1/sessions` | 列出历史会话 |
35
+ | GET | `/v1/sessions` | 列出会话 |
38
36
  | DELETE | `/v1/sessions/:id` | 删除会话 |
39
37
  | GET | `/v1/memory` | 列出记忆 |
40
38
  | POST | `/v1/memory` | 添加记忆 |
41
39
  | GET | `/v1/memory/search?q=xxx` | 搜索记忆 |
42
40
  | DELETE | `/v1/memory/:index` | 删除记忆 |
43
- | GET | `/v1/mcp` | MCP 服务器状态 |
41
+ | GET | `/v1/mcp` | MCP 状态 |
44
42
  | POST | `/v1/mcp` | 添加 MCP 服务器 |
45
43
  | DELETE | `/v1/mcp/:name` | 删除 MCP 服务器 |
46
- | GET | `/v1/skills` | 可用技能列表 |
47
- | GET | `/v1/rules` | 已加载的规则 |
44
+ | GET | `/v1/skills` | 技能列表 |
45
+ | GET | `/v1/rules` | 已加载规则 |
48
46
 
49
47
  ---
50
48
 
@@ -54,42 +52,30 @@ min-agent serve --host 127.0.0.1 --port 8787
54
52
  { "ok": true, "service": "min-agent", "version": "0.1.0" }
55
53
  ```
56
54
 
57
- ---
58
-
59
55
  ## `GET /v1/meta`
60
56
 
61
57
  ```json
62
58
  { "version": "0.1.0", "cwd": "/path/to/project", "instructions_chars": 1234 }
63
59
  ```
64
60
 
65
- ---
66
-
67
61
  ## `GET /v1/models`
68
62
 
69
63
  ```json
70
- { "default_model": "gpt-4o", "models": ["gpt-4o", "gpt-4o-mini", "..."] }
64
+ { "default_model": "gpt-4o", "models": ["gpt-4o", "gpt-4o-mini"] }
71
65
  ```
72
66
 
73
- ---
74
-
75
67
  ## `GET /v1/context`
76
68
 
77
- 返回当前模型的上下文窗口大小(自动检测)。
78
-
79
69
  ```json
80
70
  { "context_window": 128000, "model": "gpt-4o" }
81
71
  ```
82
72
 
83
- ---
84
-
85
73
  ## `GET /v1/project`
86
74
 
87
- 扫描当前工作目录的项目信息(与 `min-agent code` 启动时相同)。
88
-
89
75
  ```json
90
76
  {
91
77
  "project": {
92
- "directory": "/path/to/project",
78
+ "directory": "/path",
93
79
  "isGitRepo": true,
94
80
  "branch": "main",
95
81
  "languages": ["TypeScript"],
@@ -106,15 +92,13 @@ min-agent serve --host 127.0.0.1 --port 8787
106
92
 
107
93
  ## `POST /v1/chat`
108
94
 
109
- ### 请求体
110
-
111
95
  | 字段 | 类型 | 说明 |
112
96
  |------|------|------|
113
- | `message` | string | 单轮用户消息 |
114
- | `messages` | array | 多轮 ModelMessage[](与 `message` 二选一) |
115
- | `model` | string | 覆盖默认模型 |
116
- | `stream` | boolean | SSE 流式返回 |
117
- | `session_id` | string | 恢复历史会话并追加 |
97
+ | `message` | string | 用户消息(与 `messages` 二选一) |
98
+ | `messages` | array | 完整 ModelMessage[] |
99
+ | `model` | string | 覆盖模型 |
100
+ | `stream` | boolean | SSE 流式 |
101
+ | `session_id` | string | 恢复会话 |
118
102
  | `images` | string[] | 本地图片路径 |
119
103
 
120
104
  ### 非流式响应
@@ -148,24 +132,43 @@ min-agent serve --host 127.0.0.1 --port 8787
148
132
 
149
133
  ---
150
134
 
151
- ## `POST /v1/chat/compact`
135
+ ## `POST /v1/code`
136
+
137
+ Code 模式对话(项目感知 prompt + explore 工具)。请求体与 `/v1/chat` 相同。
138
+
139
+ 响应额外包含:
140
+ ```json
141
+ { "mode": "code", "project": { "languages": [...], ... }, ... }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## `POST /v1/paste`
147
+
148
+ 图片 + 文本多模态对话。
149
+
150
+ | 字段 | 类型 | 说明 |
151
+ |------|------|------|
152
+ | `image_base64` | string | **必填** Base64 图片数据 |
153
+ | `mime_type` | string | MIME 类型(默认 `image/png`) |
154
+ | `message` | string | 文本 prompt |
155
+ | `model` | string | 覆盖模型 |
156
+ | `session_id` | string | 追加到会话 |
157
+ | `stream` | boolean | SSE 流式 |
152
158
 
153
- 手动压缩指定会话的上下文。
159
+ ---
160
+
161
+ ## `POST /v1/chat/compact`
154
162
 
155
163
  ```json
156
164
  // 请求
157
165
  { "session_id": "abc123" }
158
-
159
166
  // 响应
160
167
  { "ok": true, "compacted": true, "message_count": 5 }
161
168
  ```
162
169
 
163
- ---
164
-
165
170
  ## `POST /v1/chat/reload-instructions`
166
171
 
167
- 重新加载规则文件(不重启 MCP)。
168
-
169
172
  ```json
170
173
  { "ok": true, "instructions_chars": 1234 }
171
174
  ```
@@ -174,22 +177,12 @@ min-agent serve --host 127.0.0.1 --port 8787
174
177
 
175
178
  ## `GET /v1/sessions`
176
179
 
177
- 列出所有保存的会话。
178
-
179
180
  ```json
180
- {
181
- "sessions": [
182
- { "id": "abc123", "title": "Fix login bug", "created": "...", "updated": "...", "messageCount": 12 }
183
- ]
184
- }
181
+ { "sessions": [{ "id": "abc", "title": "Fix bug", "updated": "...", "messageCount": 12 }] }
185
182
  ```
186
183
 
187
- ---
188
-
189
184
  ## `DELETE /v1/sessions/:id`
190
185
 
191
- 删除指定会话。
192
-
193
186
  ```json
194
187
  { "ok": true, "deleted": "abc123" }
195
188
  ```
@@ -198,46 +191,27 @@ min-agent serve --host 127.0.0.1 --port 8787
198
191
 
199
192
  ## `GET /v1/memory`
200
193
 
201
- 列出所有记忆。
202
-
203
194
  ```json
204
- {
205
- "memories": [
206
- { "content": "用户喜欢中文回复", "tags": ["偏好"], "created": "2025-01-01T00:00:00Z" }
207
- ]
208
- }
195
+ { "memories": [{ "content": "...", "tags": [...], "created": "..." }] }
209
196
  ```
210
197
 
211
- ---
212
-
213
198
  ## `POST /v1/memory`
214
199
 
215
- 添加记忆。
216
-
217
200
  ```json
218
201
  // 请求
219
- { "content": "项目使用 bun 作为包管理器", "tags": ["project"] }
220
-
202
+ { "content": "prefer TypeScript", "tags": ["preference"] }
221
203
  // 响应
222
- { "ok": true, "memory": { "content": "...", "tags": [...], "created": "..." } }
204
+ { "ok": true, "memory": {...} }
223
205
  ```
224
206
 
225
- ---
226
-
227
- ## `GET /v1/memory/search?q=bun`
228
-
229
- 搜索记忆。
207
+ ## `GET /v1/memory/search?q=typescript`
230
208
 
231
209
  ```json
232
- { "results": [{ "content": "...", "tags": [...], "created": "...", "index": 0 }] }
210
+ { "results": [{ "content": "...", "tags": [...], "index": 0 }] }
233
211
  ```
234
212
 
235
- ---
236
-
237
213
  ## `DELETE /v1/memory/:index`
238
214
 
239
- 删除记忆(1-based index)。
240
-
241
215
  ```json
242
216
  { "ok": true, "deleted": 1 }
243
217
  ```
@@ -246,118 +220,41 @@ min-agent serve --host 127.0.0.1 --port 8787
246
220
 
247
221
  ## `GET /v1/mcp`
248
222
 
249
- MCP 服务器连接状态。
250
-
251
223
  ```json
252
- {
253
- "servers": {
254
- "filesystem": { "connected": true, "tools": ["read_file", "write_file", "list_dir"] },
255
- "fetch": { "connected": false, "tools": [] }
256
- }
257
- }
224
+ { "servers": { "filesystem": { "connected": true, "tools": ["read_file", "write_file"] } } }
258
225
  ```
259
226
 
260
- ---
261
-
262
- ## `GET /v1/skills`
263
-
264
- 可用技能列表。
265
-
266
- ```json
267
- {
268
- "skills": [
269
- { "name": "git-workflow", "description": "Git workflow guide", "location": "/path/to/SKILL.md" }
270
- ]
271
- }
272
- ```
273
-
274
- ---
275
-
276
- ## `GET /v1/rules`
277
-
278
- 已加载的规则来源。
227
+ ## `POST /v1/mcp`
279
228
 
280
229
  ```json
281
- {
282
- "count": 2,
283
- "rules": [
284
- { "source": "~/.min-agent/rules.md", "chars": 456 },
285
- { "source": "/project/AGENTS.md", "chars": 1200 }
286
- ]
287
- }
230
+ // 本地 stdio
231
+ { "name": "fs", "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }
232
+ // 远程
233
+ { "name": "remote", "url": "https://mcp.example.com", "token": "xxx" }
288
234
  ```
289
235
 
290
- ---
291
-
292
- ## `POST /v1/paste`
293
-
294
- 发送剪贴板图片 + 文本进行多模态对话。
295
-
296
236
  ```json
297
- // 请求
298
- {
299
- "image_base64": "<base64 encoded image>",
300
- "mime_type": "image/png",
301
- "message": "这张图片里是什么?",
302
- "model": "gpt-4o",
303
- "session_id": "abc123",
304
- "stream": true
305
- }
237
+ { "ok": true, "name": "fs" }
306
238
  ```
307
239
 
308
- | 字段 | 类型 | 说明 |
309
- |------|------|------|
310
- | `image_base64` | string | **必填** Base64 编码的图片数据 |
311
- | `mime_type` | string | 图片 MIME 类型(默认 `image/png`) |
312
- | `message` | string | 文本 prompt(默认 "What's in this image?") |
313
- | `model` | string | 覆盖模型 |
314
- | `session_id` | string | 追加到已有会话 |
315
- | `stream` | boolean | SSE 流式 |
316
-
317
- 响应格式与 `/v1/chat` 相同。
318
-
319
- ---
320
-
321
- ## `POST /v1/code`
322
-
323
- Code 模式对话(与 `min-agent code` 相同的项目感知 prompt 和工具集)。
324
-
325
- 请求体与 `/v1/chat` 相同,响应额外包含 `mode: "code"` 和 `project` 字段。
240
+ ## `DELETE /v1/mcp/:name`
326
241
 
327
242
  ```json
328
- // 请求
329
- { "message": "add error handling to the login function", "stream": true }
330
-
331
- // 响应(非流式)额外字段
332
- { "mode": "code", "project": { "languages": ["TypeScript"], "framework": "Next.js", ... }, ... }
243
+ { "ok": true, "deleted": "fs" }
333
244
  ```
334
245
 
335
246
  ---
336
247
 
337
- ## `POST /v1/mcp`
338
-
339
- 添加 MCP 服务器。
248
+ ## `GET /v1/skills`
340
249
 
341
250
  ```json
342
- // 本地 stdio
343
- { "name": "filesystem", "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }
344
-
345
- // 远程 HTTP
346
- { "name": "remote", "url": "https://mcp.example.com", "token": "xxx" }
251
+ { "skills": [{ "name": "git-workflow", "description": "...", "location": "..." }] }
347
252
  ```
348
253
 
349
- 响应:`{ "ok": true, "name": "filesystem" }`
350
-
351
- 注意:添加后需重启 serve 进程才能连接新服务器。
352
-
353
- ---
354
-
355
- ## `DELETE /v1/mcp/:name`
356
-
357
- 删除 MCP 服务器配置。
254
+ ## `GET /v1/rules`
358
255
 
359
256
  ```json
360
- { "ok": true, "deleted": "filesystem" }
257
+ { "count": 2, "rules": [{ "source": "~/.min-agent/rules.md", "chars": 456 }] }
361
258
  ```
362
259
 
363
260
  ---
@@ -378,7 +275,7 @@ Code 模式对话(与 `min-agent code` 相同的项目感知 prompt 和工具
378
275
  ## 示例
379
276
 
380
277
  ```bash
381
- # 单轮对话
278
+ # 对话
382
279
  curl http://127.0.0.1:8787/v1/chat \
383
280
  -H "Content-Type: application/json" \
384
281
  -d '{"message":"list files"}'
@@ -388,14 +285,26 @@ curl -N http://127.0.0.1:8787/v1/chat \
388
285
  -H "Content-Type: application/json" \
389
286
  -d '{"message":"say hi","stream":true}'
390
287
 
288
+ # Code 模式
289
+ curl http://127.0.0.1:8787/v1/code \
290
+ -H "Content-Type: application/json" \
291
+ -d '{"message":"add error handling to login"}'
292
+
293
+ # 图片
294
+ curl http://127.0.0.1:8787/v1/paste \
295
+ -H "Content-Type: application/json" \
296
+ -d '{"image_base64":"iVBOR...","message":"分析这张图"}'
297
+
298
+ # 添加 MCP
299
+ curl -X POST http://127.0.0.1:8787/v1/mcp \
300
+ -H "Content-Type: application/json" \
301
+ -d '{"name":"fs","command":["npx","-y","@modelcontextprotocol/server-filesystem","/tmp"]}'
302
+
391
303
  # 添加记忆
392
304
  curl -X POST http://127.0.0.1:8787/v1/memory \
393
305
  -H "Content-Type: application/json" \
394
306
  -d '{"content":"prefer TypeScript","tags":["preference"]}'
395
307
 
396
- # 项目扫描
397
- curl http://127.0.0.1:8787/v1/project
398
-
399
308
  # 压缩会话
400
309
  curl -X POST http://127.0.0.1:8787/v1/chat/compact \
401
310
  -H "Content-Type: application/json" \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "min-agent",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Minimal AI coding agent with tool use, MCP, and skills support",
6
6
  "license": "MIT",