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 +73 -277
- package/dist/agent.js +63 -27
- package/dist/cli.js +157 -26
- 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/docs/API.md +82 -173
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import { runAgent, runChat } from "./agent.js";
|
|
|
2
2
|
import { loadMcpConfig, saveMcpConfig, checkMcpServer, checkAllMcpServers, formatMcpServerBinding, } from "./mcp.js";
|
|
3
3
|
import { discoverSkills, getSkills } from "./skills.js";
|
|
4
4
|
import { loadMemories, addMemory, deleteMemory, searchMemories } from "./memory.js";
|
|
5
|
-
import { runSetup, isConfigured, loadConfig, fetchModels, getConfigDir, getRulesFile } from "./config.js";
|
|
5
|
+
import { runSetup, isConfigured, loadConfig, saveConfig, fetchModels, getConfigDir, getRulesFile } from "./config.js";
|
|
6
6
|
import { setAutoApprove } from "./confirm.js";
|
|
7
7
|
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
8
8
|
import path from "path";
|
|
@@ -207,6 +207,19 @@ async function main() {
|
|
|
207
207
|
}
|
|
208
208
|
case "mcp": {
|
|
209
209
|
const subcommand = args[1];
|
|
210
|
+
if (subcommand === "-h" || subcommand === "--help" || !subcommand) {
|
|
211
|
+
console.log(`Usage: min-agent mcp <command>
|
|
212
|
+
|
|
213
|
+
Commands:
|
|
214
|
+
list List configured MCP servers (name + status)
|
|
215
|
+
info <name> Show details of a server
|
|
216
|
+
add <name> ... Add a new server (stdio or remote)
|
|
217
|
+
remove <name> Remove a server
|
|
218
|
+
enable <name> Enable a disabled server
|
|
219
|
+
disable <name> Disable a server
|
|
220
|
+
check Test connectivity of all servers`);
|
|
221
|
+
process.exit(0);
|
|
222
|
+
}
|
|
210
223
|
switch (subcommand) {
|
|
211
224
|
case "add": {
|
|
212
225
|
const name = args[2];
|
|
@@ -275,15 +288,43 @@ async function main() {
|
|
|
275
288
|
const servers = Object.entries(config.mcpServers);
|
|
276
289
|
if (servers.length === 0) {
|
|
277
290
|
console.log("No MCP servers configured.");
|
|
278
|
-
console.log("Add one with: min-agent mcp add <name> <command...>
|
|
291
|
+
console.log("Add one with: min-agent mcp add <name> <command...>");
|
|
279
292
|
}
|
|
280
293
|
else {
|
|
281
294
|
console.log("MCP Servers:");
|
|
282
295
|
for (const [name, cfg] of servers) {
|
|
283
|
-
const status = cfg.enabled === false ? "
|
|
284
|
-
console.log(` ${name}
|
|
296
|
+
const status = cfg.enabled === false ? "\x1b[90mdisabled\x1b[0m" : "\x1b[32menabled\x1b[0m";
|
|
297
|
+
console.log(` ${name} ${status}`);
|
|
285
298
|
}
|
|
299
|
+
console.log("\nUse: min-agent mcp info <name> for details");
|
|
300
|
+
}
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
case "info": {
|
|
304
|
+
const name = args[2];
|
|
305
|
+
if (!name) {
|
|
306
|
+
console.error("Usage: min-agent mcp info <name>");
|
|
307
|
+
process.exit(1);
|
|
286
308
|
}
|
|
309
|
+
const config = loadMcpConfig();
|
|
310
|
+
const cfg = config.mcpServers[name];
|
|
311
|
+
if (!cfg) {
|
|
312
|
+
console.error(`MCP server "${name}" not found`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
console.log(`Name: ${name}`);
|
|
316
|
+
console.log(`Status: ${cfg.enabled === false ? "disabled" : "enabled"}`);
|
|
317
|
+
console.log(`Binding: ${formatMcpServerBinding(cfg)}`);
|
|
318
|
+
if (cfg.command)
|
|
319
|
+
console.log(`Command: ${Array.isArray(cfg.command) ? cfg.command.join(" ") : `${cfg.command} ${(cfg.args ?? []).join(" ")}`.trim()}`);
|
|
320
|
+
if (cfg.url)
|
|
321
|
+
console.log(`URL: ${cfg.url}`);
|
|
322
|
+
if (cfg.token)
|
|
323
|
+
console.log(`Token: ***`);
|
|
324
|
+
if (cfg.environment)
|
|
325
|
+
console.log(`Env: ${Object.keys(cfg.environment).join(", ")}`);
|
|
326
|
+
if (cfg.timeout)
|
|
327
|
+
console.log(`Timeout: ${cfg.timeout}ms`);
|
|
287
328
|
break;
|
|
288
329
|
}
|
|
289
330
|
case "check": {
|
|
@@ -317,8 +358,44 @@ async function main() {
|
|
|
317
358
|
}
|
|
318
359
|
break;
|
|
319
360
|
}
|
|
361
|
+
case "enable": {
|
|
362
|
+
const names = args.slice(2);
|
|
363
|
+
if (names.length === 0) {
|
|
364
|
+
console.error("Usage: min-agent mcp enable <name...>");
|
|
365
|
+
process.exit(1);
|
|
366
|
+
}
|
|
367
|
+
const config = loadMcpConfig();
|
|
368
|
+
for (const name of names) {
|
|
369
|
+
if (!config.mcpServers[name]) {
|
|
370
|
+
console.error(`MCP server "${name}" not found`);
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
config.mcpServers[name].enabled = true;
|
|
374
|
+
console.log(`✓ MCP server "${name}" enabled`);
|
|
375
|
+
}
|
|
376
|
+
saveMcpConfig(config);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
case "disable": {
|
|
380
|
+
const names = args.slice(2);
|
|
381
|
+
if (names.length === 0) {
|
|
382
|
+
console.error("Usage: min-agent mcp disable <name...>");
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
const config = loadMcpConfig();
|
|
386
|
+
for (const name of names) {
|
|
387
|
+
if (!config.mcpServers[name]) {
|
|
388
|
+
console.error(`MCP server "${name}" not found`);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
config.mcpServers[name].enabled = false;
|
|
392
|
+
console.log(`✓ MCP server "${name}" disabled`);
|
|
393
|
+
}
|
|
394
|
+
saveMcpConfig(config);
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
320
397
|
default:
|
|
321
|
-
console.error("Usage: min-agent mcp
|
|
398
|
+
console.error("Usage: min-agent mcp -h");
|
|
322
399
|
process.exit(1);
|
|
323
400
|
}
|
|
324
401
|
break;
|
|
@@ -410,35 +487,89 @@ async function main() {
|
|
|
410
487
|
}
|
|
411
488
|
case "skills": {
|
|
412
489
|
const subcommand = args[1];
|
|
490
|
+
if (subcommand === "-h" || subcommand === "--help" || !subcommand) {
|
|
491
|
+
console.log(`Usage: min-agent skills <command>
|
|
492
|
+
|
|
493
|
+
Commands:
|
|
494
|
+
list List skills (name + status)
|
|
495
|
+
info <name> Show details of a skill
|
|
496
|
+
enable <name> Enable a disabled skill
|
|
497
|
+
disable <name> Disable a skill`);
|
|
498
|
+
process.exit(0);
|
|
499
|
+
}
|
|
413
500
|
switch (subcommand) {
|
|
501
|
+
case "info": {
|
|
502
|
+
const name = args[2];
|
|
503
|
+
if (!name) {
|
|
504
|
+
console.error("Usage: min-agent skills info <name>");
|
|
505
|
+
process.exit(1);
|
|
506
|
+
}
|
|
507
|
+
discoverSkills({ silent: true });
|
|
508
|
+
const { getSkill } = await import("./skills.js");
|
|
509
|
+
const skill = getSkill(name);
|
|
510
|
+
if (!skill) {
|
|
511
|
+
console.error(`Skill "${name}" not found`);
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
const config = loadConfig();
|
|
515
|
+
const isDisabled = (config.disabledSkills ?? []).includes(name);
|
|
516
|
+
console.log(`Name: ${skill.name}`);
|
|
517
|
+
console.log(`Status: ${isDisabled ? "disabled" : "enabled"}`);
|
|
518
|
+
console.log(`Description: ${skill.description}`);
|
|
519
|
+
console.log(`Location: ${skill.location}`);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
case "enable": {
|
|
523
|
+
const names = args.slice(2);
|
|
524
|
+
if (names.length === 0) {
|
|
525
|
+
console.error("Usage: min-agent skills enable <name...>");
|
|
526
|
+
process.exit(1);
|
|
527
|
+
}
|
|
528
|
+
const config = loadConfig();
|
|
529
|
+
config.disabledSkills = (config.disabledSkills ?? []).filter((s) => !names.includes(s));
|
|
530
|
+
saveConfig(config);
|
|
531
|
+
for (const name of names)
|
|
532
|
+
console.log(`✓ Skill "${name}" enabled`);
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
case "disable": {
|
|
536
|
+
const names = args.slice(2);
|
|
537
|
+
if (names.length === 0) {
|
|
538
|
+
console.error("Usage: min-agent skills disable <name...>");
|
|
539
|
+
process.exit(1);
|
|
540
|
+
}
|
|
541
|
+
const config = loadConfig();
|
|
542
|
+
const disabled = config.disabledSkills ?? [];
|
|
543
|
+
for (const name of names) {
|
|
544
|
+
if (!disabled.includes(name))
|
|
545
|
+
disabled.push(name);
|
|
546
|
+
console.log(`✓ Skill "${name}" disabled`);
|
|
547
|
+
}
|
|
548
|
+
config.disabledSkills = disabled;
|
|
549
|
+
saveConfig(config);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
414
552
|
case "list": {
|
|
415
|
-
discoverSkills();
|
|
553
|
+
discoverSkills({ silent: true });
|
|
416
554
|
const skills = getSkills();
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
console.log("
|
|
421
|
-
|
|
422
|
-
console.log(" .opencode/skills/<name>/SKILL.md");
|
|
423
|
-
console.log("");
|
|
424
|
-
console.log("SKILL.md format:");
|
|
425
|
-
console.log(" ---");
|
|
426
|
-
console.log(" name: my-skill");
|
|
427
|
-
console.log(" description: What this skill does");
|
|
428
|
-
console.log(" ---");
|
|
429
|
-
console.log(" # Instructions content...");
|
|
555
|
+
const config = loadConfig();
|
|
556
|
+
const disabledNames = config.disabledSkills ?? [];
|
|
557
|
+
if (skills.length === 0 && disabledNames.length === 0) {
|
|
558
|
+
console.log("No skills found. Add SKILL.md files in .min-agent/skills/<name>/");
|
|
559
|
+
break;
|
|
430
560
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
561
|
+
console.log("Skills:");
|
|
562
|
+
for (const skill of skills) {
|
|
563
|
+
console.log(` ${skill.name} \x1b[32menabled\x1b[0m`);
|
|
564
|
+
}
|
|
565
|
+
for (const n of disabledNames) {
|
|
566
|
+
console.log(` ${n} \x1b[90mdisabled\x1b[0m`);
|
|
437
567
|
}
|
|
568
|
+
console.log("\nUse: min-agent skills info <name> for details");
|
|
438
569
|
break;
|
|
439
570
|
}
|
|
440
571
|
default:
|
|
441
|
-
console.error("Usage: min-agent skills
|
|
572
|
+
console.error("Usage: min-agent skills -h");
|
|
442
573
|
process.exit(1);
|
|
443
574
|
}
|
|
444
575
|
break;
|
package/dist/mcp.js
CHANGED
|
@@ -7,24 +7,47 @@ import { tool, jsonSchema } from "ai";
|
|
|
7
7
|
import { readFileSync, existsSync, writeFileSync, mkdirSync } from "fs";
|
|
8
8
|
import path from "path";
|
|
9
9
|
import { truncateToolOutput } from "./tool-output.js";
|
|
10
|
+
import { getConfigDir } from "./config.js";
|
|
10
11
|
const DEFAULT_TIMEOUT = 30000;
|
|
11
12
|
function getMcpConfigPath() {
|
|
12
|
-
|
|
13
|
+
// Check project-local first, then global
|
|
14
|
+
const local = path.join(process.cwd(), ".min-agent", "mcp.json");
|
|
15
|
+
if (existsSync(local))
|
|
16
|
+
return local;
|
|
17
|
+
return path.join(getConfigDir(), "mcp.json");
|
|
18
|
+
}
|
|
19
|
+
function getMcpConfigWritePath() {
|
|
20
|
+
// Write to project-local if it exists, otherwise global
|
|
21
|
+
const local = path.join(process.cwd(), ".min-agent", "mcp.json");
|
|
22
|
+
if (existsSync(path.dirname(local)))
|
|
23
|
+
return local;
|
|
24
|
+
return path.join(getConfigDir(), "mcp.json");
|
|
13
25
|
}
|
|
14
26
|
let connectedServers = {};
|
|
15
27
|
export function loadMcpConfig() {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
const globalPath = path.join(getConfigDir(), "mcp.json");
|
|
29
|
+
const localPath = path.join(process.cwd(), ".min-agent", "mcp.json");
|
|
30
|
+
let config = { mcpServers: {} };
|
|
31
|
+
// Load global first
|
|
32
|
+
if (existsSync(globalPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const global = JSON.parse(readFileSync(globalPath, "utf-8"));
|
|
35
|
+
config.mcpServers = { ...config.mcpServers, ...global.mcpServers };
|
|
36
|
+
}
|
|
37
|
+
catch { }
|
|
21
38
|
}
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
// Local overrides global
|
|
40
|
+
if (existsSync(localPath) && localPath !== globalPath) {
|
|
41
|
+
try {
|
|
42
|
+
const local = JSON.parse(readFileSync(localPath, "utf-8"));
|
|
43
|
+
config.mcpServers = { ...config.mcpServers, ...local.mcpServers };
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
24
46
|
}
|
|
47
|
+
return config;
|
|
25
48
|
}
|
|
26
49
|
export function saveMcpConfig(config) {
|
|
27
|
-
const configPath =
|
|
50
|
+
const configPath = path.join(getConfigDir(), "mcp.json");
|
|
28
51
|
const dir = path.dirname(configPath);
|
|
29
52
|
mkdirSync(dir, { recursive: true });
|
|
30
53
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
@@ -43,7 +66,21 @@ function buildRemoteRequestInit(config) {
|
|
|
43
66
|
return { headers };
|
|
44
67
|
}
|
|
45
68
|
async function openStdioMcpServer(name, config) {
|
|
46
|
-
|
|
69
|
+
// Support both formats:
|
|
70
|
+
// { command: ["uvx", "mcp-server-time"] } — min-agent native
|
|
71
|
+
// { command: "uvx", args: ["mcp-server-time"] } — opencode/claude style
|
|
72
|
+
let cmd;
|
|
73
|
+
let args;
|
|
74
|
+
if (Array.isArray(config.command)) {
|
|
75
|
+
[cmd, ...args] = config.command;
|
|
76
|
+
}
|
|
77
|
+
else if (typeof config.command === "string") {
|
|
78
|
+
cmd = config.command;
|
|
79
|
+
args = config.args ?? [];
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new Error(`MCP "${name}" has empty command`);
|
|
83
|
+
}
|
|
47
84
|
if (!cmd) {
|
|
48
85
|
throw new Error(`MCP "${name}" has empty command`);
|
|
49
86
|
}
|
|
@@ -131,13 +168,18 @@ export function formatMcpServerBinding(config) {
|
|
|
131
168
|
const mode = config.remoteTransport ?? "auto";
|
|
132
169
|
return `${config.url} [remote:${mode}]`;
|
|
133
170
|
}
|
|
134
|
-
|
|
171
|
+
const cmd = Array.isArray(config.command) ? config.command.join(" ") : `${config.command ?? ""} ${(config.args ?? []).join(" ")}`.trim();
|
|
172
|
+
return cmd || "(no command)";
|
|
135
173
|
}
|
|
136
174
|
export async function connectMcpServer(name, config) {
|
|
137
175
|
if (config.enabled === false)
|
|
138
176
|
return null;
|
|
177
|
+
const timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
139
178
|
try {
|
|
140
|
-
const server = await
|
|
179
|
+
const server = await Promise.race([
|
|
180
|
+
openMcpServer(name, config),
|
|
181
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`connection timed out after ${timeout}ms`)), timeout)),
|
|
182
|
+
]);
|
|
141
183
|
console.log(`\x1b[90m MCP "${name}" connected (${server.tools.length} tools)\x1b[0m`);
|
|
142
184
|
return server;
|
|
143
185
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste handler for large text input.
|
|
3
|
+
*
|
|
4
|
+
* When the user pastes large content (multi-line or >150 chars),
|
|
5
|
+
* shows a collapsed summary in the terminal but preserves the full
|
|
6
|
+
* text for sending to the model.
|
|
7
|
+
*
|
|
8
|
+
* Based on opencode's paste handling in the TUI prompt component.
|
|
9
|
+
*/
|
|
10
|
+
const PASTE_LINE_THRESHOLD = 3;
|
|
11
|
+
const PASTE_CHAR_THRESHOLD = 150;
|
|
12
|
+
const PREVIEW_LINES = 3;
|
|
13
|
+
/**
|
|
14
|
+
* Process input text and detect if it's a large paste.
|
|
15
|
+
* Returns the full text plus display metadata.
|
|
16
|
+
*/
|
|
17
|
+
export function processPastedInput(text) {
|
|
18
|
+
const lineCount = (text.match(/\n/g)?.length ?? 0) + 1;
|
|
19
|
+
if (lineCount < PASTE_LINE_THRESHOLD && text.length <= PASTE_CHAR_THRESHOLD) {
|
|
20
|
+
return { fullText: text, isLargePaste: false };
|
|
21
|
+
}
|
|
22
|
+
const lines = text.split("\n");
|
|
23
|
+
const preview = lines.slice(0, PREVIEW_LINES).join("\n");
|
|
24
|
+
const remaining = lineCount - PREVIEW_LINES;
|
|
25
|
+
return {
|
|
26
|
+
fullText: text,
|
|
27
|
+
isLargePaste: true,
|
|
28
|
+
summary: remaining > 0
|
|
29
|
+
? `${preview}\n\x1b[90m ... (${remaining} more lines, ~${text.length} chars total)\x1b[0m`
|
|
30
|
+
: `\x1b[90m[Pasted ${text.length} chars]\x1b[0m`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Print paste feedback to the user.
|
|
35
|
+
*/
|
|
36
|
+
export function printPasteFeedback(result) {
|
|
37
|
+
if (!result.isLargePaste)
|
|
38
|
+
return;
|
|
39
|
+
const lineCount = (result.fullText.match(/\n/g)?.length ?? 0) + 1;
|
|
40
|
+
console.log(`\x1b[90m 📋 Pasted ~${lineCount} lines (${result.fullText.length} chars)\x1b[0m`);
|
|
41
|
+
}
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 [
|
package/dist/tools/bash.js
CHANGED
|
@@ -21,11 +21,15 @@ export const bashTool = tool({
|
|
|
21
21
|
const chunks = [];
|
|
22
22
|
let killed = false;
|
|
23
23
|
let timer;
|
|
24
|
-
|
|
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));
|