min-agent 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -18
- package/dist/agent.js +293 -408
- package/dist/assistant-stream.js +11 -7
- package/dist/cli.js +397 -139
- package/dist/clipboard.js +59 -23
- package/dist/code-mode.js +3 -3
- package/dist/compaction.js +182 -81
- package/dist/config.js +186 -35
- package/dist/confirm.js +55 -6
- package/dist/context-window.js +67 -54
- package/dist/doom-loop.js +19 -12
- package/dist/http.js +119 -0
- package/dist/instructions.js +51 -33
- package/dist/logger.js +66 -0
- package/dist/markdown.js +3 -44
- package/dist/mcp.js +547 -100
- package/dist/memory.js +48 -6
- package/dist/output.js +36 -27
- package/dist/paste-handler.js +3 -3
- package/dist/plugins.js +33 -6
- package/dist/pricing.js +119 -0
- package/dist/provider.js +17 -15
- package/dist/serve.js +658 -369
- package/dist/sessions.js +151 -13
- package/dist/skills.js +466 -76
- package/dist/synthetic.js +7 -0
- package/dist/title-gen.js +2 -1
- package/dist/tool-display.js +173 -0
- package/dist/tool-output.js +54 -45
- package/dist/tools/apply_patch.js +191 -0
- package/dist/tools/backend.js +61 -0
- package/dist/tools/bash.js +147 -70
- package/dist/tools/code_search.js +6 -5
- package/dist/tools/edit.js +23 -7
- package/dist/tools/explore.js +80 -12
- package/dist/tools/glob.js +3 -3
- package/dist/tools/grep.js +146 -14
- package/dist/tools/index.js +7 -7
- package/dist/tools/question.js +4 -22
- package/dist/tools/read.js +71 -11
- package/dist/tools/task.js +33 -20
- package/dist/tools/todo.js +83 -73
- package/dist/tools/web_fetch.js +150 -46
- package/dist/tools/web_search.js +706 -28
- package/dist/tools/write.js +13 -7
- package/dist/tui/App.js +40 -6
- package/dist/tui/ConfirmBar.js +24 -3
- package/dist/tui/InputBar.js +390 -45
- package/dist/tui/MessageList.js +533 -20
- package/dist/tui/ModelPicker.js +108 -0
- package/dist/tui/QuestionBar.js +104 -0
- package/dist/tui/StatusBar.js +19 -11
- package/dist/tui/agent-runner.js +103 -0
- package/dist/tui/caret-pos.js +134 -0
- package/dist/tui/caret.js +69 -0
- package/dist/tui/diff-view.js +61 -0
- package/dist/tui/drag-state.js +44 -0
- package/dist/tui/index.js +153 -24
- package/dist/tui/input-history.js +44 -0
- package/dist/tui/layout.js +17 -0
- package/dist/tui/mouse.js +46 -0
- package/dist/tui/selection.js +134 -0
- package/dist/tui/slash-commands.js +90 -0
- package/dist/tui/slash-handler.js +370 -0
- package/dist/tui/text-width.js +91 -0
- package/dist/tui/theme.js +12 -0
- package/dist/tui/undo-stack.js +14 -0
- package/dist/tui/use-sgr-mouse.js +27 -0
- package/dist/tui-chat.js +111 -331
- package/dist/updater.js +57 -0
- package/docs/API.md +160 -14
- package/docs/superpowers/plans/2026-08-16-batch1-tui-improvements.md +1510 -0
- package/docs/superpowers/plans/2026-08-16-batch2-cli-tools-api.md +2105 -0
- package/docs/superpowers/plans/2026-08-16-batch3-config-engineering.md +1595 -0
- package/docs/superpowers/plans/2026-08-16-input-caret.md +782 -0
- package/docs/superpowers/specs/2026-08-16-batch1-tui-improvements-design.md +183 -0
- package/docs/superpowers/specs/2026-08-16-batch2-cli-tools-api-design.md +220 -0
- package/docs/superpowers/specs/2026-08-16-batch3-config-engineering-design.md +196 -0
- package/docs/superpowers/specs/2026-08-16-input-caret-design.md +63 -0
- package/docs/superpowers/specs/2026-08-17-mouse-selection-design.md +116 -0
- package/package.json +7 -8
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { runAgent } from "./agent.js";
|
|
2
|
-
import {
|
|
3
|
-
import { discoverSkills
|
|
2
|
+
import { loadMcpConfigFile, loadMcpConfigEntries, saveMcpConfig, checkMcpServer, checkAllMcpServers, formatMcpServerBinding, } from "./mcp.js";
|
|
3
|
+
import { discoverSkills } from "./skills.js";
|
|
4
4
|
import { loadMemories, addMemory, deleteMemory, searchMemories } from "./memory.js";
|
|
5
|
-
import { runSetup, isConfigured, loadConfig,
|
|
5
|
+
import { runSetup, isConfigured, loadConfig, fetchModels, getConfigDir, getRulesFile, getActiveProvider } from "./config.js";
|
|
6
6
|
import { setAutoApprove } from "./confirm.js";
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
8
8
|
import path from "path";
|
|
9
|
+
import os from "os";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import { initLogger, log } from "./logger.js";
|
|
9
12
|
const rawArgs = process.argv.slice(2);
|
|
10
13
|
// Extract leading global flags only, so subcommands can still use "-y"
|
|
11
14
|
const args = [...rawArgs];
|
|
@@ -16,6 +19,45 @@ while (args[0] === "--yes" || args[0] === "-y") {
|
|
|
16
19
|
}
|
|
17
20
|
if (hasYes)
|
|
18
21
|
setAutoApprove(true);
|
|
22
|
+
/** Parse common flags in any position; unknown args become positionals. */
|
|
23
|
+
function parseFlags(argv) {
|
|
24
|
+
let model;
|
|
25
|
+
let provider;
|
|
26
|
+
let resume;
|
|
27
|
+
const images = [];
|
|
28
|
+
let port;
|
|
29
|
+
let host;
|
|
30
|
+
const positionals = [];
|
|
31
|
+
for (let i = 0; i < argv.length; i++) {
|
|
32
|
+
const a = argv[i];
|
|
33
|
+
const take = () => (argv[i + 1] ? argv[++i] : "");
|
|
34
|
+
if ((a === "--model" || a === "-m") && argv[i + 1]) {
|
|
35
|
+
model = take();
|
|
36
|
+
}
|
|
37
|
+
else if (a === "--provider" && argv[i + 1]) {
|
|
38
|
+
provider = take();
|
|
39
|
+
}
|
|
40
|
+
else if (a === "--resume" && argv[i + 1]) {
|
|
41
|
+
resume = take();
|
|
42
|
+
}
|
|
43
|
+
else if ((a === "--image" || a === "-i") && argv[i + 1]) {
|
|
44
|
+
images.push(take());
|
|
45
|
+
}
|
|
46
|
+
else if ((a === "--port" || a === "-p") && argv[i + 1]) {
|
|
47
|
+
port = parseInt(take(), 10);
|
|
48
|
+
}
|
|
49
|
+
else if (a === "--host" && argv[i + 1]) {
|
|
50
|
+
host = take();
|
|
51
|
+
}
|
|
52
|
+
else if (a === "--yes" || a === "-y") {
|
|
53
|
+
setAutoApprove(true);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
positionals.push(a);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { model, provider, resume, images, port, host, positionals };
|
|
60
|
+
}
|
|
19
61
|
function printUsage() {
|
|
20
62
|
console.log(`
|
|
21
63
|
min-agent - Minimal AI coding agent
|
|
@@ -26,9 +68,13 @@ Usage:
|
|
|
26
68
|
min-agent chat Start interactive multi-turn chat
|
|
27
69
|
min-agent chat --resume <id> Resume a previous session
|
|
28
70
|
min-agent code AI coding mode (project-aware)
|
|
29
|
-
min-agent setup Configure
|
|
71
|
+
min-agent setup Configure providers (interactive)
|
|
30
72
|
min-agent models List available models
|
|
31
73
|
min-agent history List saved sessions
|
|
74
|
+
min-agent history delete <id> Delete a saved session
|
|
75
|
+
min-agent history rename <id> <t> Rename a saved session
|
|
76
|
+
min-agent history export <id> [-o <file>] Export a session as JSON
|
|
77
|
+
min-agent update Check for updates and upgrade
|
|
32
78
|
min-agent rules Show loaded instruction rules
|
|
33
79
|
min-agent rules edit Edit global rules file
|
|
34
80
|
min-agent memory List all memories
|
|
@@ -36,15 +82,18 @@ Usage:
|
|
|
36
82
|
min-agent memory search <query> Search memories
|
|
37
83
|
min-agent memory delete <index> Delete a memory by number
|
|
38
84
|
min-agent mcp add <name> <cmd> Add a local MCP server (stdio)
|
|
39
|
-
min-agent mcp add <name> --url <url> [--sse] [--token <t>] Add remote MCP (HTTP)
|
|
85
|
+
min-agent mcp add <name> --url <url> [--sse] [--streamable-http] [--token <t>] Add remote MCP (HTTP)
|
|
40
86
|
min-agent mcp remove <name> Remove an MCP server
|
|
41
87
|
min-agent mcp list List configured MCP servers
|
|
42
88
|
min-agent mcp check Check MCP server availability
|
|
43
89
|
min-agent skills list List available skills
|
|
90
|
+
min-agent skills info <name> Show skill details
|
|
91
|
+
min-agent skills enable|disable <name...> [--project] Toggle skills
|
|
44
92
|
min-agent serve [--host H] [--port P] HTTP API (see docs/API.md)
|
|
45
93
|
|
|
46
94
|
Options:
|
|
47
95
|
--model, -m <model> Override model for this request
|
|
96
|
+
--provider <name> Use a specific configured provider
|
|
48
97
|
--image, -i <path> Attach an image (can be used multiple times)
|
|
49
98
|
--yes, -y Auto-approve all confirmations (dangerous commands, file overwrites)
|
|
50
99
|
|
|
@@ -72,6 +121,10 @@ function parseMcpAddArgs(argv) {
|
|
|
72
121
|
let url;
|
|
73
122
|
let token;
|
|
74
123
|
let sse = false;
|
|
124
|
+
let streamableHttp = false;
|
|
125
|
+
let project = false;
|
|
126
|
+
let timeout;
|
|
127
|
+
const environment = {};
|
|
75
128
|
const cmd = [];
|
|
76
129
|
for (let i = 0; i < argv.length; i++) {
|
|
77
130
|
const a = argv[i];
|
|
@@ -83,6 +136,14 @@ function parseMcpAddArgs(argv) {
|
|
|
83
136
|
sse = true;
|
|
84
137
|
continue;
|
|
85
138
|
}
|
|
139
|
+
if (a === "--streamable-http") {
|
|
140
|
+
streamableHttp = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (a === "--project") {
|
|
144
|
+
project = true;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
86
147
|
if (a === "--url" && argv[i + 1]) {
|
|
87
148
|
url = argv[++i];
|
|
88
149
|
continue;
|
|
@@ -91,9 +152,38 @@ function parseMcpAddArgs(argv) {
|
|
|
91
152
|
token = argv[++i];
|
|
92
153
|
continue;
|
|
93
154
|
}
|
|
155
|
+
if (a === "--timeout" && argv[i + 1]) {
|
|
156
|
+
const value = parseInt(argv[++i], 10);
|
|
157
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
158
|
+
console.error(`Invalid --timeout value: ${argv[i]} (must be a positive number of ms)`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
timeout = value;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (a === "--env") {
|
|
165
|
+
const kv = argv[i + 1];
|
|
166
|
+
if (!kv) {
|
|
167
|
+
console.error("Invalid --env: missing KEY=VALUE");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const eq = kv.indexOf("=");
|
|
171
|
+
if (eq <= 0) {
|
|
172
|
+
console.error(`Invalid --env format: ${kv} (use KEY=VALUE)`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
i++;
|
|
176
|
+
environment[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
94
179
|
cmd.push(a);
|
|
95
180
|
}
|
|
96
|
-
return { skipCheck, url, token, sse, cmd };
|
|
181
|
+
return { skipCheck, url, token, sse, streamableHttp, project, timeout, environment, cmd };
|
|
182
|
+
}
|
|
183
|
+
/** One-line, length-capped text for list output. */
|
|
184
|
+
function truncate(text, max) {
|
|
185
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
186
|
+
return flat.length <= max ? flat : `${flat.slice(0, max - 1)}…`;
|
|
97
187
|
}
|
|
98
188
|
function ensureProjectDefaults() {
|
|
99
189
|
const projectConfigDir = path.join(process.cwd(), ".min-agent");
|
|
@@ -113,32 +203,38 @@ async function main() {
|
|
|
113
203
|
process.exit(0);
|
|
114
204
|
}
|
|
115
205
|
if (args[0] === "--version" || args[0] === "-v") {
|
|
116
|
-
const pkgPath = path.resolve(path.dirname(
|
|
206
|
+
const pkgPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
117
207
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
118
208
|
console.log(pkg.version);
|
|
119
209
|
process.exit(0);
|
|
120
210
|
}
|
|
121
211
|
const command = args[0];
|
|
212
|
+
initLogger();
|
|
213
|
+
log("info", `min-agent started: ${command}`);
|
|
122
214
|
switch (command) {
|
|
123
215
|
case "setup": {
|
|
124
216
|
await runSetup();
|
|
125
217
|
break;
|
|
126
218
|
}
|
|
127
219
|
case "models": {
|
|
220
|
+
const flags = parseFlags(args.slice(1));
|
|
128
221
|
const config = loadConfig();
|
|
129
|
-
|
|
222
|
+
const provider = flags.provider
|
|
223
|
+
? config.providers?.find((p) => p.name === flags.provider)
|
|
224
|
+
: getActiveProvider(config);
|
|
225
|
+
if (!provider?.baseURL || !provider?.apiKey) {
|
|
130
226
|
console.error("Not configured. Run: min-agent setup");
|
|
131
227
|
process.exit(1);
|
|
132
228
|
}
|
|
133
|
-
console.log(
|
|
134
|
-
const models = await fetchModels(
|
|
229
|
+
console.log(`Fetching models (${provider.name ?? "default"})...`);
|
|
230
|
+
const models = await fetchModels(provider.baseURL, provider.apiKey);
|
|
135
231
|
if (models.length === 0) {
|
|
136
232
|
console.log("No models found or unable to fetch model list.");
|
|
137
233
|
}
|
|
138
234
|
else {
|
|
139
235
|
console.log(`\nAvailable models (${models.length}):`);
|
|
140
236
|
for (const m of models) {
|
|
141
|
-
const marker = m ===
|
|
237
|
+
const marker = m === provider.defaultModel ? " ← default" : "";
|
|
142
238
|
console.log(` ${m}${marker}`);
|
|
143
239
|
}
|
|
144
240
|
}
|
|
@@ -149,32 +245,18 @@ async function main() {
|
|
|
149
245
|
console.error("Not configured. Run: min-agent setup");
|
|
150
246
|
process.exit(1);
|
|
151
247
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for (let i = 1; i < args.length; i++) {
|
|
158
|
-
if ((args[i] === "--model" || args[i] === "-m") && args[i + 1]) {
|
|
159
|
-
modelOverride = args[++i];
|
|
160
|
-
}
|
|
161
|
-
else if (args[i] === "--resume" && args[i + 1]) {
|
|
162
|
-
resumeId = args[++i];
|
|
163
|
-
}
|
|
164
|
-
else if ((args[i] === "--image" || args[i] === "-i") && args[i + 1]) {
|
|
165
|
-
images.push(args[++i]);
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
chatArgs.push(args[i]);
|
|
169
|
-
}
|
|
248
|
+
const { model: modelOverride, provider: providerOverride, resume: resumeId, images, positionals } = parseFlags(args.slice(1));
|
|
249
|
+
const message = positionals.join(" ");
|
|
250
|
+
if (resumeId && message) {
|
|
251
|
+
console.error("--resume <id> cannot be combined with a message; run `min-agent chat --resume <id>` to continue that session");
|
|
252
|
+
process.exit(1);
|
|
170
253
|
}
|
|
171
|
-
const message = chatArgs.join(" ");
|
|
172
254
|
if (!message) {
|
|
173
255
|
const { runTui } = await import("./tui-chat.js");
|
|
174
|
-
await runTui({ modelId: modelOverride, resumeSessionId: resumeId, mode: "chat" });
|
|
256
|
+
await runTui({ modelId: modelOverride, providerName: providerOverride, resumeSessionId: resumeId, mode: "chat", images });
|
|
175
257
|
}
|
|
176
258
|
else {
|
|
177
|
-
await runAgent(message, modelOverride, images.length > 0 ? images : undefined);
|
|
259
|
+
await runAgent(message, modelOverride, images.length > 0 ? images : undefined, providerOverride);
|
|
178
260
|
}
|
|
179
261
|
break;
|
|
180
262
|
}
|
|
@@ -183,18 +265,9 @@ async function main() {
|
|
|
183
265
|
console.error("Not configured. Run: min-agent setup");
|
|
184
266
|
process.exit(1);
|
|
185
267
|
}
|
|
186
|
-
|
|
187
|
-
let resumeId;
|
|
188
|
-
for (let i = 1; i < args.length; i++) {
|
|
189
|
-
if ((args[i] === "--model" || args[i] === "-m") && args[i + 1]) {
|
|
190
|
-
modelOverride = args[++i];
|
|
191
|
-
}
|
|
192
|
-
else if (args[i] === "--resume" && args[i + 1]) {
|
|
193
|
-
resumeId = args[++i];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
268
|
+
const { model: modelOverride, provider: providerOverride, resume: resumeId } = parseFlags(args.slice(1));
|
|
196
269
|
const { runTui } = await import("./tui-chat.js");
|
|
197
|
-
await runTui({ modelId: modelOverride, resumeSessionId: resumeId, mode: "code" });
|
|
270
|
+
await runTui({ modelId: modelOverride, providerName: providerOverride, resumeSessionId: resumeId, mode: "code" });
|
|
198
271
|
break;
|
|
199
272
|
}
|
|
200
273
|
case "serve": {
|
|
@@ -202,16 +275,7 @@ async function main() {
|
|
|
202
275
|
console.error("Not configured. Run: min-agent setup");
|
|
203
276
|
process.exit(1);
|
|
204
277
|
}
|
|
205
|
-
|
|
206
|
-
let serveHost;
|
|
207
|
-
for (let i = 1; i < args.length; i++) {
|
|
208
|
-
if ((args[i] === "--port" || args[i] === "-p") && args[i + 1]) {
|
|
209
|
-
servePort = parseInt(args[++i], 10);
|
|
210
|
-
}
|
|
211
|
-
else if (args[i] === "--host" && args[i + 1]) {
|
|
212
|
-
serveHost = args[++i];
|
|
213
|
-
}
|
|
214
|
-
}
|
|
278
|
+
const { port: servePort, host: serveHost } = parseFlags(args.slice(1));
|
|
215
279
|
const { runServe } = await import("./serve.js");
|
|
216
280
|
await runServe({ port: servePort, host: serveHost });
|
|
217
281
|
break;
|
|
@@ -222,42 +286,59 @@ async function main() {
|
|
|
222
286
|
console.log(`Usage: min-agent mcp <command>
|
|
223
287
|
|
|
224
288
|
Commands:
|
|
225
|
-
list
|
|
226
|
-
info <name>
|
|
227
|
-
add <name> ...
|
|
228
|
-
remove <name> Remove a server
|
|
229
|
-
enable <name
|
|
230
|
-
disable <name
|
|
231
|
-
check
|
|
289
|
+
list List configured MCP servers (name + status + scope)
|
|
290
|
+
info <name> Show details of a server
|
|
291
|
+
add <name> ... Add a new server (stdio or remote)
|
|
292
|
+
remove <name> [--project] Remove a server
|
|
293
|
+
enable <name...> [--project] Enable a disabled server
|
|
294
|
+
disable <name...> [--project] Disable a server
|
|
295
|
+
check Test connectivity of all servers
|
|
296
|
+
|
|
297
|
+
Add flags:
|
|
298
|
+
--project Write to .min-agent/mcp.json (project scope)
|
|
299
|
+
--url <url> Remote server URL
|
|
300
|
+
--sse | --streamable-http Remote transport mode (default: auto)
|
|
301
|
+
--token <t> Bearer token for remote servers
|
|
302
|
+
--env KEY=VALUE Extra env for stdio servers (repeatable)
|
|
303
|
+
--timeout <ms> Connection/call timeout
|
|
304
|
+
--skip-check Skip validation before saving`);
|
|
232
305
|
process.exit(0);
|
|
233
306
|
}
|
|
234
307
|
switch (subcommand) {
|
|
235
308
|
case "add": {
|
|
236
309
|
const name = args[2];
|
|
237
310
|
if (!name) {
|
|
238
|
-
console.error("Usage: min-agent mcp add <name> [--skip-check] <command...>");
|
|
239
|
-
console.error(" or: min-agent mcp add <name> --url <https://host/mcp> [--sse] [--token <bearer>] [--skip-check]");
|
|
311
|
+
console.error("Usage: min-agent mcp add <name> [--project] [--skip-check] <command...>");
|
|
312
|
+
console.error(" or: min-agent mcp add <name> --url <https://host/mcp> [--sse|--streamable-http] [--token <bearer>] [--project] [--skip-check]");
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
const { skipCheck, url, token, sse, streamableHttp, project, timeout, environment, cmd } = parseMcpAddArgs(args.slice(3));
|
|
316
|
+
const scope = project ? "project" : "global";
|
|
317
|
+
if (sse && streamableHttp) {
|
|
318
|
+
console.error("--sse and --streamable-http are mutually exclusive");
|
|
240
319
|
process.exit(1);
|
|
241
320
|
}
|
|
242
|
-
const { skipCheck, url, token, sse, cmd } = parseMcpAddArgs(args.slice(3));
|
|
243
321
|
let entry;
|
|
244
322
|
if (url?.trim()) {
|
|
245
323
|
entry = {
|
|
246
324
|
url: url.trim(),
|
|
247
325
|
enabled: true,
|
|
248
|
-
remoteTransport: sse ? "sse" : "auto",
|
|
326
|
+
remoteTransport: streamableHttp ? "streamable-http" : sse ? "sse" : "auto",
|
|
327
|
+
...(timeout ? { timeout } : {}),
|
|
249
328
|
};
|
|
250
329
|
if (token?.trim())
|
|
251
330
|
entry.token = token.trim();
|
|
252
331
|
}
|
|
253
332
|
else if (cmd.length > 0) {
|
|
254
|
-
entry = { command: cmd, enabled: true };
|
|
333
|
+
entry = { command: cmd, enabled: true, ...(timeout ? { timeout } : {}) };
|
|
255
334
|
}
|
|
256
335
|
else {
|
|
257
|
-
console.error("Usage: min-agent mcp add <name> [--skip-check] <command...>");
|
|
258
|
-
console.error(" or: min-agent mcp add <name> --url <https://host/mcp> [--sse] [--token <bearer>] [--skip-check]");
|
|
336
|
+
console.error("Usage: min-agent mcp add <name> [--project] [--skip-check] <command...>");
|
|
337
|
+
console.error(" or: min-agent mcp add <name> --url <https://host/mcp> [--sse|--streamable-http] [--token <bearer>] [--project] [--skip-check]");
|
|
259
338
|
process.exit(1);
|
|
260
339
|
}
|
|
340
|
+
if (Object.keys(environment).length > 0)
|
|
341
|
+
entry.environment = environment;
|
|
261
342
|
let detectedTools = 0;
|
|
262
343
|
if (!skipCheck) {
|
|
263
344
|
console.log(`Validating MCP server "${name}"...`);
|
|
@@ -271,41 +352,47 @@ Commands:
|
|
|
271
352
|
else {
|
|
272
353
|
console.log(`Skipping MCP validation for "${name}" (--skip-check).`);
|
|
273
354
|
}
|
|
274
|
-
const config =
|
|
355
|
+
const config = loadMcpConfigFile(scope);
|
|
275
356
|
config.mcpServers[name] = entry;
|
|
276
|
-
saveMcpConfig(config);
|
|
357
|
+
saveMcpConfig(config, scope);
|
|
277
358
|
const toolsSuffix = skipCheck ? "" : ` (${detectedTools} tools detected)`;
|
|
278
|
-
|
|
359
|
+
const scopeSuffix = project ? " [project]" : "";
|
|
360
|
+
console.log(`✓ MCP server "${name}" added${scopeSuffix}: ${formatMcpServerBinding(entry)}${toolsSuffix}`);
|
|
279
361
|
break;
|
|
280
362
|
}
|
|
281
363
|
case "remove": {
|
|
282
|
-
const
|
|
364
|
+
const project = args.includes("--project");
|
|
365
|
+
const scope = project ? "project" : "global";
|
|
366
|
+
const name = args.slice(2).find((a) => a !== "--project");
|
|
283
367
|
if (!name) {
|
|
284
|
-
console.error("Usage: min-agent mcp remove <name>");
|
|
368
|
+
console.error("Usage: min-agent mcp remove <name> [--project]");
|
|
285
369
|
process.exit(1);
|
|
286
370
|
}
|
|
287
|
-
const config =
|
|
371
|
+
const config = loadMcpConfigFile(scope);
|
|
288
372
|
if (!config.mcpServers[name]) {
|
|
289
|
-
|
|
373
|
+
const elsewhere = loadMcpConfigEntries().find((e) => e.name === name);
|
|
374
|
+
console.error(elsewhere
|
|
375
|
+
? `MCP server "${name}" is defined in ${elsewhere.scope} scope, not ${scope}.`
|
|
376
|
+
: `MCP server "${name}" not found`);
|
|
290
377
|
process.exit(1);
|
|
291
378
|
}
|
|
292
379
|
delete config.mcpServers[name];
|
|
293
|
-
saveMcpConfig(config);
|
|
294
|
-
console.log(`✓ MCP server "${name}" removed`);
|
|
380
|
+
saveMcpConfig(config, scope);
|
|
381
|
+
console.log(`✓ MCP server "${name}" removed${project ? " [project]" : ""}`);
|
|
295
382
|
break;
|
|
296
383
|
}
|
|
297
384
|
case "list": {
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
if (servers.length === 0) {
|
|
385
|
+
const entries = loadMcpConfigEntries();
|
|
386
|
+
if (entries.length === 0) {
|
|
301
387
|
console.log("No MCP servers configured.");
|
|
302
388
|
console.log("Add one with: min-agent mcp add <name> <command...>");
|
|
303
389
|
}
|
|
304
390
|
else {
|
|
305
391
|
console.log("MCP Servers:");
|
|
306
|
-
for (const
|
|
307
|
-
const status =
|
|
308
|
-
|
|
392
|
+
for (const { name, config, scope } of entries) {
|
|
393
|
+
const status = config.enabled === false ? "\x1b[90mdisabled\x1b[0m" : "\x1b[32menabled\x1b[0m";
|
|
394
|
+
const scopeMark = scope === "project" ? " \x1b[90m[project]\x1b[0m" : "";
|
|
395
|
+
console.log(` ${name} ${status}${scopeMark}`);
|
|
309
396
|
}
|
|
310
397
|
console.log("\nUse: min-agent mcp info <name> for details");
|
|
311
398
|
}
|
|
@@ -317,25 +404,39 @@ Commands:
|
|
|
317
404
|
console.error("Usage: min-agent mcp info <name>");
|
|
318
405
|
process.exit(1);
|
|
319
406
|
}
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
if (!cfg) {
|
|
407
|
+
const found = loadMcpConfigEntries().find((e) => e.name === name);
|
|
408
|
+
if (!found) {
|
|
323
409
|
console.error(`MCP server "${name}" not found`);
|
|
324
410
|
process.exit(1);
|
|
325
411
|
}
|
|
412
|
+
const cfg = found.config;
|
|
326
413
|
console.log(`Name: ${name}`);
|
|
414
|
+
console.log(`Scope: ${found.scope}`);
|
|
327
415
|
console.log(`Status: ${cfg.enabled === false ? "disabled" : "enabled"}`);
|
|
328
416
|
console.log(`Binding: ${formatMcpServerBinding(cfg)}`);
|
|
329
417
|
if (cfg.command)
|
|
330
418
|
console.log(`Command: ${Array.isArray(cfg.command) ? cfg.command.join(" ") : `${cfg.command} ${(cfg.args ?? []).join(" ")}`.trim()}`);
|
|
331
|
-
if (cfg.url)
|
|
419
|
+
if (cfg.url) {
|
|
332
420
|
console.log(`URL: ${cfg.url}`);
|
|
421
|
+
if (cfg.remoteTransport)
|
|
422
|
+
console.log(`Transport: ${cfg.remoteTransport}`);
|
|
423
|
+
if (cfg.oauth === false)
|
|
424
|
+
console.log(`OAuth: disabled`);
|
|
425
|
+
else if (cfg.oauth)
|
|
426
|
+
console.log(`OAuth: enabled${cfg.oauth.clientId ? ` (clientId set)` : ""}`);
|
|
427
|
+
}
|
|
428
|
+
if (cfg.headers)
|
|
429
|
+
console.log(`Headers: ${Object.keys(cfg.headers).join(", ")} (values hidden)`);
|
|
333
430
|
if (cfg.token)
|
|
334
431
|
console.log(`Token: ***`);
|
|
335
432
|
if (cfg.environment)
|
|
336
433
|
console.log(`Env: ${Object.keys(cfg.environment).join(", ")}`);
|
|
337
434
|
if (cfg.timeout)
|
|
338
435
|
console.log(`Timeout: ${cfg.timeout}ms`);
|
|
436
|
+
if (cfg.connectTimeout)
|
|
437
|
+
console.log(`ConnectTimeout: ${cfg.connectTimeout}ms`);
|
|
438
|
+
if (cfg.callTimeout)
|
|
439
|
+
console.log(`CallTimeout: ${cfg.callTimeout}ms`);
|
|
339
440
|
break;
|
|
340
441
|
}
|
|
341
442
|
case "check": {
|
|
@@ -370,39 +471,43 @@ Commands:
|
|
|
370
471
|
break;
|
|
371
472
|
}
|
|
372
473
|
case "enable": {
|
|
373
|
-
const
|
|
474
|
+
const project = args.includes("--project");
|
|
475
|
+
const scope = project ? "project" : "global";
|
|
476
|
+
const names = args.slice(2).filter((a) => a !== "--project");
|
|
374
477
|
if (names.length === 0) {
|
|
375
|
-
console.error("Usage: min-agent mcp enable <name...>");
|
|
478
|
+
console.error("Usage: min-agent mcp enable <name...> [--project]");
|
|
376
479
|
process.exit(1);
|
|
377
480
|
}
|
|
378
|
-
const config =
|
|
481
|
+
const config = loadMcpConfigFile(scope);
|
|
379
482
|
for (const name of names) {
|
|
380
483
|
if (!config.mcpServers[name]) {
|
|
381
|
-
console.error(`MCP server "${name}" not found`);
|
|
484
|
+
console.error(`MCP server "${name}" not found${project ? " in project scope" : ""}`);
|
|
382
485
|
continue;
|
|
383
486
|
}
|
|
384
487
|
config.mcpServers[name].enabled = true;
|
|
385
|
-
console.log(`✓ MCP server "${name}" enabled`);
|
|
488
|
+
console.log(`✓ MCP server "${name}" enabled${project ? " [project]" : ""}`);
|
|
386
489
|
}
|
|
387
|
-
saveMcpConfig(config);
|
|
490
|
+
saveMcpConfig(config, scope);
|
|
388
491
|
break;
|
|
389
492
|
}
|
|
390
493
|
case "disable": {
|
|
391
|
-
const
|
|
494
|
+
const project = args.includes("--project");
|
|
495
|
+
const scope = project ? "project" : "global";
|
|
496
|
+
const names = args.slice(2).filter((a) => a !== "--project");
|
|
392
497
|
if (names.length === 0) {
|
|
393
|
-
console.error("Usage: min-agent mcp disable <name...>");
|
|
498
|
+
console.error("Usage: min-agent mcp disable <name...> [--project]");
|
|
394
499
|
process.exit(1);
|
|
395
500
|
}
|
|
396
|
-
const config =
|
|
501
|
+
const config = loadMcpConfigFile(scope);
|
|
397
502
|
for (const name of names) {
|
|
398
503
|
if (!config.mcpServers[name]) {
|
|
399
|
-
console.error(`MCP server "${name}" not found`);
|
|
504
|
+
console.error(`MCP server "${name}" not found${project ? " in project scope" : ""}`);
|
|
400
505
|
continue;
|
|
401
506
|
}
|
|
402
507
|
config.mcpServers[name].enabled = false;
|
|
403
|
-
console.log(`✓ MCP server "${name}" disabled`);
|
|
508
|
+
console.log(`✓ MCP server "${name}" disabled${project ? " [project]" : ""}`);
|
|
404
509
|
}
|
|
405
|
-
saveMcpConfig(config);
|
|
510
|
+
saveMcpConfig(config, scope);
|
|
406
511
|
break;
|
|
407
512
|
}
|
|
408
513
|
default:
|
|
@@ -412,6 +517,74 @@ Commands:
|
|
|
412
517
|
break;
|
|
413
518
|
}
|
|
414
519
|
case "history": {
|
|
520
|
+
const subcommand = args[1];
|
|
521
|
+
if (subcommand === "delete") {
|
|
522
|
+
const id = args[2];
|
|
523
|
+
if (!id) {
|
|
524
|
+
console.error("Usage: min-agent history delete <id>");
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
const { deleteSession } = await import("./sessions.js");
|
|
528
|
+
if (deleteSession(id)) {
|
|
529
|
+
console.log(`✓ 会话 ${id} 已删除`);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
console.error(`会话 ${id} 不存在`);
|
|
533
|
+
process.exit(1);
|
|
534
|
+
}
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
if (subcommand === "rename") {
|
|
538
|
+
const id = args[2];
|
|
539
|
+
const title = args.slice(3).join(" ");
|
|
540
|
+
if (!id || !title) {
|
|
541
|
+
console.error("Usage: min-agent history rename <id> <title>");
|
|
542
|
+
process.exit(1);
|
|
543
|
+
}
|
|
544
|
+
const { renameSession } = await import("./sessions.js");
|
|
545
|
+
if (renameSession(id, title)) {
|
|
546
|
+
console.log(`✓ 会话 ${id} 已重命名为: ${title}`);
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
console.error(`会话 ${id} 不存在`);
|
|
550
|
+
process.exit(1);
|
|
551
|
+
}
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
if (subcommand === "export") {
|
|
555
|
+
const id = args[2];
|
|
556
|
+
if (!id) {
|
|
557
|
+
console.error("Usage: min-agent history export <id> [-o <file>]");
|
|
558
|
+
process.exit(1);
|
|
559
|
+
}
|
|
560
|
+
const { loadSession } = await import("./sessions.js");
|
|
561
|
+
const session = loadSession(id);
|
|
562
|
+
if (!session) {
|
|
563
|
+
console.error(`会话 ${id} 不存在`);
|
|
564
|
+
process.exit(1);
|
|
565
|
+
}
|
|
566
|
+
const json = JSON.stringify(session, null, 2);
|
|
567
|
+
const outIdx = args.indexOf("-o");
|
|
568
|
+
const outFile = outIdx !== -1 ? args[outIdx + 1] : undefined;
|
|
569
|
+
if (outFile) {
|
|
570
|
+
try {
|
|
571
|
+
writeFileSync(outFile, json, "utf-8");
|
|
572
|
+
console.log(`✓ 会话 ${id} 已导出到 ${outFile}`);
|
|
573
|
+
}
|
|
574
|
+
catch (err) {
|
|
575
|
+
console.error(`导出失败: ${err.message}`);
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
if (outIdx !== -1) {
|
|
581
|
+
console.error("Usage: min-agent history export <id> [-o <file>](-o 后缺少文件路径)");
|
|
582
|
+
process.exit(1);
|
|
583
|
+
}
|
|
584
|
+
console.log(json);
|
|
585
|
+
}
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
415
588
|
const { listSessions } = await import("./sessions.js");
|
|
416
589
|
const sessions = listSessions();
|
|
417
590
|
if (sessions.length === 0) {
|
|
@@ -502,89 +675,174 @@ Commands:
|
|
|
502
675
|
console.log(`Usage: min-agent skills <command>
|
|
503
676
|
|
|
504
677
|
Commands:
|
|
505
|
-
list
|
|
506
|
-
info <name>
|
|
507
|
-
|
|
508
|
-
|
|
678
|
+
list List skills (name + status + description)
|
|
679
|
+
info <name> Show details of a skill
|
|
680
|
+
new <name> Create a new skill scaffold
|
|
681
|
+
enable <name...> Enable disabled skills
|
|
682
|
+
disable <name...> Disable skills
|
|
683
|
+
|
|
684
|
+
Options (enable/disable):
|
|
685
|
+
--project Apply to this project only (.min-agent/config.json)
|
|
686
|
+
--global Apply to every project (default, ~/.min-agent/config.json)
|
|
687
|
+
|
|
688
|
+
Options (list/info):
|
|
689
|
+
--json Machine-readable JSON output
|
|
690
|
+
|
|
691
|
+
Options (new):
|
|
692
|
+
--global Create in ~/.agents/skills/ instead of .min-agent/skills/
|
|
693
|
+
|
|
694
|
+
Project scope wins over global, so a skill disabled globally can be
|
|
695
|
+
re-enabled for one repo with: min-agent skills enable <name> --project
|
|
696
|
+
|
|
697
|
+
Skills are discovered in (later paths override earlier ones):
|
|
698
|
+
~/.agents/skills/ .min-agent/skills/ .agents/skills/
|
|
699
|
+
.opencode/skills/ .claude/skills/`);
|
|
509
700
|
process.exit(0);
|
|
510
701
|
}
|
|
511
702
|
switch (subcommand) {
|
|
512
703
|
case "info": {
|
|
513
|
-
const
|
|
704
|
+
const flags = args.slice(2);
|
|
705
|
+
const name = flags.find((a) => !a.startsWith("-"));
|
|
514
706
|
if (!name) {
|
|
515
|
-
console.error("Usage: min-agent skills info <name>");
|
|
707
|
+
console.error("Usage: min-agent skills info <name> [--json]");
|
|
516
708
|
process.exit(1);
|
|
517
709
|
}
|
|
518
710
|
discoverSkills({ silent: true });
|
|
519
|
-
const { getSkill } = await import("./skills.js");
|
|
711
|
+
const { getSkill, getAllSkills } = await import("./skills.js");
|
|
520
712
|
const skill = getSkill(name);
|
|
521
713
|
if (!skill) {
|
|
522
|
-
|
|
714
|
+
const names = getAllSkills().map((s) => s.name);
|
|
715
|
+
console.error(`Skill "${name}" not found.${names.length ? ` Available: ${names.join(", ")}` : " No skills discovered."}`);
|
|
523
716
|
process.exit(1);
|
|
524
717
|
}
|
|
525
|
-
|
|
526
|
-
|
|
718
|
+
if (flags.includes("--json")) {
|
|
719
|
+
console.log(JSON.stringify(skill, null, 2));
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
527
722
|
console.log(`Name: ${skill.name}`);
|
|
528
|
-
console.log(`Status: ${
|
|
723
|
+
console.log(`Status: ${skill.enabled ? "enabled" : `disabled (${skill.disabledScope} scope)`}`);
|
|
724
|
+
if (skill.version)
|
|
725
|
+
console.log(`Version: ${skill.version}`);
|
|
529
726
|
console.log(`Description: ${skill.description}`);
|
|
530
727
|
console.log(`Location: ${skill.location}`);
|
|
728
|
+
if (skill.allowedTools.length > 0)
|
|
729
|
+
console.log(`Tools: ${skill.allowedTools.join(", ")}`);
|
|
730
|
+
if (skill.requiredBins.length > 0)
|
|
731
|
+
console.log(`Requires: ${skill.requiredBins.join(", ")}`);
|
|
732
|
+
if (skill.content.trim()) {
|
|
733
|
+
console.log("\n--- Content ---\n");
|
|
734
|
+
console.log(skill.content.trim());
|
|
735
|
+
}
|
|
531
736
|
break;
|
|
532
737
|
}
|
|
533
|
-
case "enable":
|
|
534
|
-
|
|
738
|
+
case "enable":
|
|
739
|
+
case "disable": {
|
|
740
|
+
const flags = args.slice(2);
|
|
741
|
+
const scope = flags.includes("--project") ? "project" : "global";
|
|
742
|
+
const names = flags.filter((a) => a !== "--project" && a !== "--global");
|
|
743
|
+
const unknownFlag = flags.find((a) => a.startsWith("-") && a !== "--project" && a !== "--global");
|
|
744
|
+
if (unknownFlag) {
|
|
745
|
+
console.error(`Unknown option: ${unknownFlag} (use --project or --global)`);
|
|
746
|
+
process.exit(1);
|
|
747
|
+
}
|
|
535
748
|
if (names.length === 0) {
|
|
536
|
-
console.error(
|
|
749
|
+
console.error(`Usage: min-agent skills ${subcommand} <name...> [--project]`);
|
|
750
|
+
process.exit(1);
|
|
751
|
+
}
|
|
752
|
+
discoverSkills({ silent: true });
|
|
753
|
+
const { getAllSkills, setSkillEnabled, getStaleDisabledSkills } = await import("./skills.js");
|
|
754
|
+
const known = new Set(getAllSkills().map((s) => s.name));
|
|
755
|
+
const stale = new Set(getStaleDisabledSkills());
|
|
756
|
+
// `enable` must accept stale names so they can be cleaned up from config;
|
|
757
|
+
// `disable` on an unknown name is always an error.
|
|
758
|
+
const unknown = names.filter((n) => !known.has(n) && !(subcommand === "enable" && stale.has(n)));
|
|
759
|
+
if (unknown.length > 0) {
|
|
760
|
+
console.error(`Skill${unknown.length > 1 ? "s" : ""} not found: ${unknown.join(", ")}`);
|
|
761
|
+
console.error(known.size ? `Available: ${[...known].join(", ")}` : "No skills discovered.");
|
|
537
762
|
process.exit(1);
|
|
538
763
|
}
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
764
|
+
for (const result of setSkillEnabled(names, subcommand === "enable", scope)) {
|
|
765
|
+
console.log(`✓ Skill "${result.name}" ${subcommand}d (${scope} scope)`);
|
|
766
|
+
if (result.blockedBy) {
|
|
767
|
+
console.log(`\x1b[33m ⚠ still ${result.enabled ? "enabled" : "disabled"} — overridden by ${result.blockedBy} scope\x1b[0m`);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
544
770
|
break;
|
|
545
771
|
}
|
|
546
|
-
case "
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
772
|
+
case "new": {
|
|
773
|
+
const flags = args.slice(2);
|
|
774
|
+
const name = flags.find((a) => !a.startsWith("-"));
|
|
775
|
+
if (!name || !/^[\w-]+$/.test(name)) {
|
|
776
|
+
console.error("Usage: min-agent skills new <name> [--global] (name: letters, digits, _ or -)");
|
|
550
777
|
process.exit(1);
|
|
551
778
|
}
|
|
552
|
-
const
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
779
|
+
const global = flags.includes("--global");
|
|
780
|
+
const root = global ? path.join(os.homedir(), ".agents", "skills") : path.join(process.cwd(), ".min-agent", "skills");
|
|
781
|
+
const dir = path.join(root, name);
|
|
782
|
+
if (existsSync(path.join(dir, "SKILL.md"))) {
|
|
783
|
+
console.error(`Skill "${name}" already exists at ${dir}`);
|
|
784
|
+
process.exit(1);
|
|
558
785
|
}
|
|
559
|
-
|
|
560
|
-
|
|
786
|
+
mkdirSync(dir, { recursive: true });
|
|
787
|
+
writeFileSync(path.join(dir, "SKILL.md"), `---\nname: ${name}\ndescription: What this skill does\n# version: 1.0.0\n# allowed-tools: [read, grep]\n# metadata:\n# requires:\n# bins: ["some-cli"]\n---\n\n# ${name}\n\nWrite the skill instructions here.\n`, "utf-8");
|
|
788
|
+
console.log(`✓ Created skill "${name}" at ${path.join(dir, "SKILL.md")}`);
|
|
561
789
|
break;
|
|
562
790
|
}
|
|
563
791
|
case "list": {
|
|
792
|
+
const json = args.includes("--json");
|
|
564
793
|
discoverSkills({ silent: true });
|
|
565
|
-
const
|
|
566
|
-
const
|
|
567
|
-
const
|
|
568
|
-
if (
|
|
794
|
+
const { getAllSkills, getStaleDisabledSkills } = await import("./skills.js");
|
|
795
|
+
const all = getAllSkills().sort((a, b) => a.name.localeCompare(b.name));
|
|
796
|
+
const stale = getStaleDisabledSkills();
|
|
797
|
+
if (json) {
|
|
798
|
+
console.log(JSON.stringify({
|
|
799
|
+
count: all.length,
|
|
800
|
+
enabled_count: all.filter((s) => s.enabled).length,
|
|
801
|
+
stale_disabled: stale,
|
|
802
|
+
skills: all.map((s) => ({
|
|
803
|
+
name: s.name,
|
|
804
|
+
description: s.description,
|
|
805
|
+
location: s.location,
|
|
806
|
+
enabled: s.enabled,
|
|
807
|
+
...(s.disabledScope ? { disabled_scope: s.disabledScope } : {}),
|
|
808
|
+
...(s.version ? { version: s.version } : {}),
|
|
809
|
+
...(s.allowedTools.length ? { allowed_tools: s.allowedTools } : {}),
|
|
810
|
+
...(s.requiredBins.length ? { requires_bins: s.requiredBins } : {}),
|
|
811
|
+
})),
|
|
812
|
+
}, null, 2));
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
if (all.length === 0 && stale.length === 0) {
|
|
569
816
|
console.log("No skills found. Add SKILL.md files in .min-agent/skills/<name>/");
|
|
570
817
|
break;
|
|
571
818
|
}
|
|
572
|
-
console.log(
|
|
573
|
-
for (const skill of
|
|
574
|
-
|
|
819
|
+
console.log(`Skills (${all.filter((s) => s.enabled).length} enabled, ${all.filter((s) => !s.enabled).length} disabled):`);
|
|
820
|
+
for (const skill of all) {
|
|
821
|
+
const status = skill.enabled
|
|
822
|
+
? "\x1b[32menabled \x1b[0m"
|
|
823
|
+
: `\x1b[90mdisabled(${skill.disabledScope === "project" ? "proj" : "glob"})\x1b[0m`;
|
|
824
|
+
console.log(` ${skill.name} ${status} \x1b[90m${truncate(skill.description, 60)}\x1b[0m`);
|
|
825
|
+
console.log(` \x1b[90m${skill.location}\x1b[0m`);
|
|
575
826
|
}
|
|
576
|
-
|
|
577
|
-
console.log(
|
|
827
|
+
if (stale.length > 0) {
|
|
828
|
+
console.log(`\n\x1b[33m⚠ disabledSkills/enabledSkills entries matching no skill: ${stale.join(", ")}\x1b[0m`);
|
|
829
|
+
console.log(`\x1b[33m Remove them with: min-agent skills enable ${stale.join(" ")} (add --project if the entry is project-scoped)\x1b[0m`);
|
|
578
830
|
}
|
|
579
831
|
console.log("\nUse: min-agent skills info <name> for details");
|
|
580
832
|
break;
|
|
581
833
|
}
|
|
582
834
|
default:
|
|
583
|
-
console.error(
|
|
835
|
+
console.error(`Unknown skills command: ${subcommand}`);
|
|
836
|
+
console.error("Available: list, info, new, enable, disable (see: min-agent skills -h)");
|
|
584
837
|
process.exit(1);
|
|
585
838
|
}
|
|
586
839
|
break;
|
|
587
840
|
}
|
|
841
|
+
case "update": {
|
|
842
|
+
const { runUpdate } = await import("./updater.js");
|
|
843
|
+
await runUpdate();
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
588
846
|
case "init": {
|
|
589
847
|
ensureProjectDefaults();
|
|
590
848
|
console.log(`✓ Initialized .min-agent/ in ${process.cwd()}`);
|