min-agent 0.5.1 → 0.6.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 +18 -18
- package/dist/cli.js +538 -12
- package/docs/API.md +6 -6
- package/package.json +6 -6
- package/skills/self-config/SKILL.md +4 -2
- package/skills/self-config/reference.md +4 -1
- package/dist/agent.js +0 -1388
- package/dist/assistant-stream.js +0 -131
- package/dist/cli/commands/chat.js +0 -13
- package/dist/cli/commands/ctx.js +0 -7
- package/dist/cli/commands/exec.js +0 -35
- package/dist/cli/commands/history.js +0 -58
- package/dist/cli/commands/index.js +0 -249
- package/dist/cli/commands/init.js +0 -18
- package/dist/cli/commands/mcp.js +0 -173
- package/dist/cli/commands/memory.js +0 -87
- package/dist/cli/commands/models.js +0 -21
- package/dist/cli/commands/permission.js +0 -12
- package/dist/cli/commands/rules.js +0 -33
- package/dist/cli/commands/sandbox.js +0 -13
- package/dist/cli/commands/serve.js +0 -9
- package/dist/cli/commands/setup.js +0 -56
- package/dist/cli/commands/shared.js +0 -25
- package/dist/cli/commands/skills.js +0 -119
- package/dist/cli/commands/think.js +0 -12
- package/dist/cli/commands/update.js +0 -7
- package/dist/cli/commands/write-config.js +0 -52
- package/dist/cli/errors.js +0 -36
- package/dist/cli/exec-prompt.js +0 -26
- package/dist/cli/option-helpers.js +0 -65
- package/dist/cli/program.js +0 -223
- package/dist/cli/setup/detect.js +0 -17
- package/dist/cli/setup/flags.js +0 -12
- package/dist/cli/setup/flow.js +0 -108
- package/dist/cli/setup/provider-form.js +0 -102
- package/dist/cli/setup/ui.js +0 -534
- package/dist/clipboard.js +0 -142
- package/dist/code-mode.js +0 -184
- package/dist/compaction.js +0 -644
- package/dist/config.js +0 -363
- package/dist/confirm.js +0 -172
- package/dist/context-window.js +0 -256
- package/dist/ctx-cli.js +0 -30
- package/dist/ctx.js +0 -80
- package/dist/doom-loop.js +0 -278
- package/dist/fetch-timeout.js +0 -152
- package/dist/http-approvals.js +0 -60
- package/dist/http.js +0 -119
- package/dist/instructions.js +0 -196
- package/dist/logger.js +0 -95
- package/dist/markdown.js +0 -259
- package/dist/mcp.js +0 -1036
- package/dist/memory-cli.js +0 -33
- package/dist/memory.js +0 -295
- package/dist/model-catalog.js +0 -285
- package/dist/ollama-model.js +0 -234
- package/dist/ollama-openai-bridge.js +0 -383
- package/dist/output.js +0 -76
- package/dist/paste-handler.js +0 -41
- package/dist/permission-cli.js +0 -40
- package/dist/plugins.js +0 -131
- package/dist/pricing.js +0 -119
- package/dist/provider.js +0 -63
- package/dist/question-format.js +0 -60
- package/dist/reasoning-stream.js +0 -158
- package/dist/sandbox-cli.js +0 -79
- package/dist/sandbox.js +0 -403
- package/dist/save-throttle.js +0 -45
- package/dist/scope.js +0 -23
- package/dist/serve/common.js +0 -425
- package/dist/serve/routes-chat.js +0 -367
- package/dist/serve/routes-mcp.js +0 -212
- package/dist/serve/routes-memory.js +0 -95
- package/dist/serve/routes-meta.js +0 -268
- package/dist/serve/routes-sessions.js +0 -61
- package/dist/serve/routes-skills.js +0 -70
- package/dist/serve.js +0 -138
- package/dist/sessions.js +0 -265
- package/dist/skills.js +0 -599
- package/dist/structured-output.js +0 -29
- package/dist/synthetic.js +0 -7
- package/dist/think-cli.js +0 -36
- package/dist/thinking-wire.js +0 -239
- package/dist/thinking.js +0 -166
- package/dist/title-gen.js +0 -55
- package/dist/token-display.js +0 -39
- package/dist/tool-display.js +0 -178
- package/dist/tool-output.js +0 -126
- package/dist/tools/apply_patch.js +0 -265
- package/dist/tools/atomic-file.js +0 -35
- package/dist/tools/backend.js +0 -61
- package/dist/tools/bash.js +0 -231
- package/dist/tools/code_search.js +0 -98
- package/dist/tools/edit.js +0 -68
- package/dist/tools/explore.js +0 -232
- package/dist/tools/glob.js +0 -40
- package/dist/tools/grep.js +0 -174
- package/dist/tools/index.js +0 -34
- package/dist/tools/question.js +0 -54
- package/dist/tools/read.js +0 -109
- package/dist/tools/search-searxng.js +0 -223
- package/dist/tools/search-serper.js +0 -189
- package/dist/tools/task.js +0 -165
- package/dist/tools/todo.js +0 -213
- package/dist/tools/web_fetch.js +0 -195
- package/dist/tools/web_search.js +0 -228
- package/dist/tools/write.js +0 -55
- package/dist/tui/App.js +0 -138
- package/dist/tui/ConfirmBar.js +0 -66
- package/dist/tui/CtxPicker.js +0 -68
- package/dist/tui/InputBar.js +0 -618
- package/dist/tui/MessageList.js +0 -718
- package/dist/tui/ModelPicker.js +0 -113
- package/dist/tui/QuestionBar.js +0 -136
- package/dist/tui/SessionPicker.js +0 -79
- package/dist/tui/Spinner.js +0 -6
- package/dist/tui/StatusBar.js +0 -22
- package/dist/tui/ThinkPicker.js +0 -75
- package/dist/tui/agent-runner.js +0 -223
- package/dist/tui/bracketed-paste.js +0 -37
- package/dist/tui/caret-pos.js +0 -179
- package/dist/tui/caret.js +0 -69
- package/dist/tui/click-count.js +0 -13
- package/dist/tui/diff-view.js +0 -61
- package/dist/tui/drag-state.js +0 -49
- package/dist/tui/hydrate.js +0 -129
- package/dist/tui/index.js +0 -264
- package/dist/tui/input-history.js +0 -125
- package/dist/tui/layout.js +0 -105
- package/dist/tui/mouse.js +0 -46
- package/dist/tui/overlay-input.js +0 -12
- package/dist/tui/paste-draft.js +0 -173
- package/dist/tui/prompt-queue.js +0 -24
- package/dist/tui/selection.js +0 -232
- package/dist/tui/session-switch.js +0 -28
- package/dist/tui/slash-commands.js +0 -129
- package/dist/tui/slash-handler.js +0 -615
- package/dist/tui/text-width.js +0 -113
- package/dist/tui/theme.js +0 -12
- package/dist/tui/token-info.js +0 -7
- package/dist/tui/tool-children.js +0 -19
- package/dist/tui/types.js +0 -1
- package/dist/tui/undo-stack.js +0 -14
- package/dist/tui/use-sgr-mouse.js +0 -29
- package/dist/tui-chat.js +0 -478
- package/dist/updater.js +0 -116
- package/dist/xml-search.js +0 -194
- package/docs/superpowers/plans/2026-08-16-batch1-tui-improvements.md +0 -1510
- package/docs/superpowers/plans/2026-08-16-batch2-cli-tools-api.md +0 -2105
- package/docs/superpowers/plans/2026-08-16-batch3-config-engineering.md +0 -1595
- package/docs/superpowers/plans/2026-08-16-input-caret.md +0 -782
- package/docs/superpowers/plans/2026-08-20-tui-completeness.md +0 -873
- package/docs/superpowers/plans/2026-08-20-unified-tui-default.md +0 -631
- package/docs/superpowers/plans/2026-08-23-cli-setup.md +0 -501
- package/docs/superpowers/plans/2026-08-23-input-paste-attachments.md +0 -475
- package/docs/superpowers/plans/2026-08-23-thinking-wire-profile.md +0 -450
- package/docs/superpowers/specs/2026-08-16-batch1-tui-improvements-design.md +0 -183
- package/docs/superpowers/specs/2026-08-16-batch2-cli-tools-api-design.md +0 -220
- package/docs/superpowers/specs/2026-08-16-batch3-config-engineering-design.md +0 -196
- package/docs/superpowers/specs/2026-08-16-input-caret-design.md +0 -63
- package/docs/superpowers/specs/2026-08-17-mouse-selection-design.md +0 -116
- package/docs/superpowers/specs/2026-08-20-config-http-alignment-design.md +0 -47
- package/docs/superpowers/specs/2026-08-20-mcp-plugins-alignment-design.md +0 -37
- package/docs/superpowers/specs/2026-08-20-sandbox-permissions-design.md +0 -68
- package/docs/superpowers/specs/2026-08-20-tui-completeness-design.md +0 -273
- package/docs/superpowers/specs/2026-08-20-unified-tui-default-design.md +0 -165
- package/docs/superpowers/specs/2026-08-23-cli-setup-design.md +0 -282
- package/docs/superpowers/specs/2026-08-23-input-paste-attachments-design.md +0 -174
- package/docs/superpowers/specs/2026-08-23-thinking-wire-profile-design.md +0 -140
package/dist/cli/commands/mcp.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { loadMcpConfigFile, loadMcpConfigEntries, saveMcpConfig, checkMcpServer, checkAllMcpServers, formatMcpServerBinding, getMcpStatus, listMcpCatalog, } from "../../mcp.js";
|
|
2
|
-
import { CliError } from "../errors.js";
|
|
3
|
-
function parseEnvPairs(pairs) {
|
|
4
|
-
const environment = {};
|
|
5
|
-
for (const kv of pairs ?? []) {
|
|
6
|
-
const eq = kv.indexOf("=");
|
|
7
|
-
if (eq <= 0)
|
|
8
|
-
throw new CliError(`Invalid --env format: ${kv}`, { hint: "use KEY=VALUE" });
|
|
9
|
-
environment[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
10
|
-
}
|
|
11
|
-
return environment;
|
|
12
|
-
}
|
|
13
|
-
export async function runMcpAdd(name, cmd, opts) {
|
|
14
|
-
const scope = opts.project ? "project" : "global";
|
|
15
|
-
if (opts.sse && opts.streamableHttp) {
|
|
16
|
-
throw new CliError("--sse and --streamable-http are mutually exclusive");
|
|
17
|
-
}
|
|
18
|
-
const usage = "Usage: min-agent mcp add <name> [--project] [--skip-check] <command...>\n" +
|
|
19
|
-
" or: min-agent mcp add <name> --url <https://host/mcp> [--sse|--streamable-http] [--token <bearer>] [--project] [--skip-check]";
|
|
20
|
-
let entry;
|
|
21
|
-
if (opts.url?.trim()) {
|
|
22
|
-
entry = {
|
|
23
|
-
url: opts.url.trim(),
|
|
24
|
-
enabled: true,
|
|
25
|
-
remoteTransport: opts.streamableHttp ? "streamable-http" : opts.sse ? "sse" : "auto",
|
|
26
|
-
...(opts.timeout ? { timeout: opts.timeout } : {}),
|
|
27
|
-
};
|
|
28
|
-
if (opts.token?.trim())
|
|
29
|
-
entry.token = opts.token.trim();
|
|
30
|
-
}
|
|
31
|
-
else if (cmd.length > 0) {
|
|
32
|
-
entry = { command: cmd, enabled: true, ...(opts.timeout ? { timeout: opts.timeout } : {}) };
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
throw new CliError(usage);
|
|
36
|
-
}
|
|
37
|
-
const environment = parseEnvPairs(opts.env);
|
|
38
|
-
if (Object.keys(environment).length > 0)
|
|
39
|
-
entry.environment = environment;
|
|
40
|
-
let detectedTools = 0;
|
|
41
|
-
if (!opts.skipCheck) {
|
|
42
|
-
console.log(`Validating MCP server "${name}"...`);
|
|
43
|
-
const checkResult = await checkMcpServer(name, entry);
|
|
44
|
-
if (!checkResult.ok) {
|
|
45
|
-
throw new CliError(`MCP server "${name}" validation failed: ${checkResult.error ?? "unknown error"}`, {
|
|
46
|
-
exitCode: 2,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
detectedTools = checkResult.toolCount;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
console.log(`Skipping MCP validation for "${name}" (--skip-check).`);
|
|
53
|
-
}
|
|
54
|
-
const config = loadMcpConfigFile(scope);
|
|
55
|
-
config.mcpServers[name] = entry;
|
|
56
|
-
saveMcpConfig(config, scope);
|
|
57
|
-
const toolsSuffix = opts.skipCheck ? "" : ` (${detectedTools} tools detected)`;
|
|
58
|
-
const scopeSuffix = opts.project ? " [project]" : "";
|
|
59
|
-
console.log(`✓ MCP server "${name}" added${scopeSuffix}: ${formatMcpServerBinding(entry)}${toolsSuffix}`);
|
|
60
|
-
}
|
|
61
|
-
export async function runMcpRemove(name, opts) {
|
|
62
|
-
const scope = opts.project ? "project" : "global";
|
|
63
|
-
const config = loadMcpConfigFile(scope);
|
|
64
|
-
if (!config.mcpServers[name]) {
|
|
65
|
-
const elsewhere = loadMcpConfigEntries().find((e) => e.name === name);
|
|
66
|
-
throw new CliError(elsewhere
|
|
67
|
-
? `MCP server "${name}" is defined in ${elsewhere.scope} scope, not ${scope}.`
|
|
68
|
-
: `MCP server "${name}" not found`);
|
|
69
|
-
}
|
|
70
|
-
delete config.mcpServers[name];
|
|
71
|
-
saveMcpConfig(config, scope);
|
|
72
|
-
console.log(`✓ MCP server "${name}" removed${opts.project ? " [project]" : ""}`);
|
|
73
|
-
}
|
|
74
|
-
export async function runMcpList() {
|
|
75
|
-
const entries = loadMcpConfigEntries();
|
|
76
|
-
if (entries.length === 0) {
|
|
77
|
-
console.log("No MCP servers configured.");
|
|
78
|
-
console.log("Add one with: min-agent mcp add <name> <command...>");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
console.log("MCP Servers:");
|
|
82
|
-
for (const { name, config, scope } of entries) {
|
|
83
|
-
const status = config.enabled === false ? "\x1b[90mdisabled\x1b[0m" : "\x1b[32menabled\x1b[0m";
|
|
84
|
-
const scopeMark = scope === "project" ? " \x1b[90m[project]\x1b[0m" : "";
|
|
85
|
-
console.log(` ${name} ${status}${scopeMark}`);
|
|
86
|
-
}
|
|
87
|
-
console.log("\nUse: min-agent mcp info <name> for details");
|
|
88
|
-
}
|
|
89
|
-
export async function runMcpInfo(name) {
|
|
90
|
-
const found = loadMcpConfigEntries().find((e) => e.name === name);
|
|
91
|
-
if (!found)
|
|
92
|
-
throw new CliError(`MCP server "${name}" not found`);
|
|
93
|
-
const cfg = found.config;
|
|
94
|
-
console.log(`Name: ${name}`);
|
|
95
|
-
console.log(`Scope: ${found.scope}`);
|
|
96
|
-
console.log(`Status: ${cfg.enabled === false ? "disabled" : "enabled"}`);
|
|
97
|
-
console.log(`Binding: ${formatMcpServerBinding(cfg)}`);
|
|
98
|
-
if (cfg.command)
|
|
99
|
-
console.log(`Command: ${Array.isArray(cfg.command) ? cfg.command.join(" ") : `${cfg.command} ${(cfg.args ?? []).join(" ")}`.trim()}`);
|
|
100
|
-
if (cfg.url) {
|
|
101
|
-
console.log(`URL: ${cfg.url}`);
|
|
102
|
-
if (cfg.remoteTransport)
|
|
103
|
-
console.log(`Transport: ${cfg.remoteTransport}`);
|
|
104
|
-
if (cfg.oauth === false)
|
|
105
|
-
console.log(`OAuth: disabled`);
|
|
106
|
-
else if (cfg.oauth)
|
|
107
|
-
console.log(`OAuth: enabled${cfg.oauth.clientId ? ` (clientId set)` : ""}`);
|
|
108
|
-
}
|
|
109
|
-
if (cfg.headers)
|
|
110
|
-
console.log(`Headers: ${Object.keys(cfg.headers).join(", ")} (values hidden)`);
|
|
111
|
-
if (cfg.token)
|
|
112
|
-
console.log(`Token: ***`);
|
|
113
|
-
if (cfg.environment)
|
|
114
|
-
console.log(`Env: ${Object.keys(cfg.environment).join(", ")}`);
|
|
115
|
-
if (cfg.timeout)
|
|
116
|
-
console.log(`Timeout: ${cfg.timeout}ms`);
|
|
117
|
-
if (cfg.connectTimeout)
|
|
118
|
-
console.log(`ConnectTimeout: ${cfg.connectTimeout}ms`);
|
|
119
|
-
if (cfg.callTimeout)
|
|
120
|
-
console.log(`CallTimeout: ${cfg.callTimeout}ms`);
|
|
121
|
-
const st = getMcpStatus()[name];
|
|
122
|
-
if (st?.connected) {
|
|
123
|
-
const catalog = listMcpCatalog(name).servers[0];
|
|
124
|
-
if (catalog) {
|
|
125
|
-
console.log(`Tools: ${st.tools.join(", ") || "(none)"}`);
|
|
126
|
-
console.log(`Resources: ${catalog.resources.length === 0 ? "(none)" : catalog.resources.map((r) => r.uri).join(", ")}`);
|
|
127
|
-
console.log(`Prompts: ${catalog.prompts.length === 0 ? "(none)" : catalog.prompts.map((p) => p.name).join(", ")}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
export async function runMcpCheck() {
|
|
132
|
-
const results = await checkAllMcpServers();
|
|
133
|
-
if (results.length === 0) {
|
|
134
|
-
console.log("No MCP servers configured.");
|
|
135
|
-
console.log("Add one with: min-agent mcp add <name> <command...> or --url <https://...>");
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
let failed = 0;
|
|
139
|
-
console.log("MCP Check Results:");
|
|
140
|
-
for (const result of results) {
|
|
141
|
-
if (!result.enabled) {
|
|
142
|
-
console.log(` ${result.name}: skipped (disabled)`);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
if (result.ok) {
|
|
146
|
-
console.log(` ${result.name}: ok (${result.toolCount} tools)`);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
failed++;
|
|
150
|
-
console.log(` ${result.name}: failed${result.error ? ` - ${result.error}` : ""}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (failed > 0) {
|
|
154
|
-
throw new CliError(`${failed} MCP server(s) failed.`, { exitCode: 1 });
|
|
155
|
-
}
|
|
156
|
-
console.log("\nAll enabled MCP servers are available.");
|
|
157
|
-
}
|
|
158
|
-
export async function runMcpToggle(names, enabled, opts) {
|
|
159
|
-
const scope = opts.project ? "project" : "global";
|
|
160
|
-
const verb = enabled ? "enable" : "disable";
|
|
161
|
-
if (names.length === 0)
|
|
162
|
-
throw new CliError(`Usage: min-agent mcp ${verb} <name...> [--project]`);
|
|
163
|
-
const config = loadMcpConfigFile(scope);
|
|
164
|
-
for (const name of names) {
|
|
165
|
-
if (!config.mcpServers[name]) {
|
|
166
|
-
console.error(`MCP server "${name}" not found${opts.project ? " in project scope" : ""}`);
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
config.mcpServers[name].enabled = enabled;
|
|
170
|
-
console.log(`✓ MCP server "${name}" ${verb}d${opts.project ? " [project]" : ""}`);
|
|
171
|
-
}
|
|
172
|
-
saveMcpConfig(config, scope);
|
|
173
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { loadMemories, addMemory, deleteMemory, searchMemories, defaultMemoryScope, formatMemoryLine, parseMemoryMode, resolveMemoryMode, memoryModeLabel, memorySourceLabel, isMemoryEnabled, } from "../../memory.js";
|
|
2
|
-
import { runMemoryCli } from "../../memory-cli.js";
|
|
3
|
-
import { CliError } from "../errors.js";
|
|
4
|
-
function printList(which) {
|
|
5
|
-
const memories = loadMemories(which);
|
|
6
|
-
const label = which === "project" ? "Project memories" : "Global memories";
|
|
7
|
-
if (memories.length === 0) {
|
|
8
|
-
console.log(`${label}: none`);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
console.log(`${label} (${memories.length}):`);
|
|
12
|
-
for (const line of memories.map((m, i) => formatMemoryLine(m, i, { date: true }))) {
|
|
13
|
-
console.log(line);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export async function runMemoryMode(state, scope, flagMode) {
|
|
17
|
-
if (!state && flagMode === undefined)
|
|
18
|
-
return false;
|
|
19
|
-
if (state && state !== "list" && !parseMemoryMode(state))
|
|
20
|
-
return false;
|
|
21
|
-
if (state === "list")
|
|
22
|
-
return false;
|
|
23
|
-
const result = runMemoryCli({
|
|
24
|
-
positionals: state ? [state] : [],
|
|
25
|
-
flagMode,
|
|
26
|
-
scope,
|
|
27
|
-
});
|
|
28
|
-
console.log(result.lines.join("\n"));
|
|
29
|
-
if (!result.ok)
|
|
30
|
-
process.exitCode = 1;
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
export async function runMemoryList(scope) {
|
|
34
|
-
const { memory, source } = resolveMemoryMode();
|
|
35
|
-
console.log(`Current memory: ${memoryModeLabel(memory)} (${memorySourceLabel(source)})`);
|
|
36
|
-
if (!scope && loadMemories("project").length === 0 && loadMemories("global").length === 0) {
|
|
37
|
-
console.log("No memories stored.");
|
|
38
|
-
if (!isMemoryEnabled())
|
|
39
|
-
console.log("Turn on with: min-agent memory on");
|
|
40
|
-
console.log('Or add manually: min-agent memory add "prefer TypeScript over JavaScript"');
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const scopes = scope ? [scope] : ["project", "global"];
|
|
44
|
-
for (const s of scopes)
|
|
45
|
-
printList(s);
|
|
46
|
-
if (!isMemoryEnabled())
|
|
47
|
-
console.log("Memories are stored but not used in chat until you run: min-agent memory on");
|
|
48
|
-
}
|
|
49
|
-
export async function runMemoryAdd(textTokens, scope) {
|
|
50
|
-
const text = textTokens.join(" ");
|
|
51
|
-
if (!text)
|
|
52
|
-
throw new CliError("Usage: min-agent memory add <text> [--project|--global]");
|
|
53
|
-
const resolved = scope ?? defaultMemoryScope();
|
|
54
|
-
addMemory(text, [], resolved);
|
|
55
|
-
const hint = isMemoryEnabled() ? "" : " (memory is off — turn on with: min-agent memory on)";
|
|
56
|
-
console.log(`✓ ${resolved === "project" ? "Project" : "Global"} memory saved: "${text}"${hint}`);
|
|
57
|
-
}
|
|
58
|
-
export async function runMemorySearch(queryTokens, scope) {
|
|
59
|
-
const query = queryTokens.join(" ");
|
|
60
|
-
if (!query)
|
|
61
|
-
throw new CliError("Usage: min-agent memory search <query> [--project|--global]");
|
|
62
|
-
const scopes = scope ? [scope] : ["project", "global"];
|
|
63
|
-
const lines = scopes.flatMap((s) => searchMemories(query, s).map((m) => {
|
|
64
|
-
const tags = m.tags.length > 0 ? ` [${m.tags.join(", ")}]` : "";
|
|
65
|
-
return ` [${s}] #${m.index + 1}: ${m.content}${tags}`;
|
|
66
|
-
}));
|
|
67
|
-
if (lines.length === 0) {
|
|
68
|
-
console.log(`No memories matching "${query}"`);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
console.log(`Found ${lines.length} memory(s):`);
|
|
72
|
-
for (const line of lines)
|
|
73
|
-
console.log(line);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
export async function runMemoryDelete(indexArg, scope) {
|
|
77
|
-
const idx = Number.parseInt(indexArg, 10);
|
|
78
|
-
if (Number.isNaN(idx))
|
|
79
|
-
throw new CliError("Usage: min-agent memory delete <number> [--project|--global]");
|
|
80
|
-
const resolved = scope ?? defaultMemoryScope();
|
|
81
|
-
if (deleteMemory(idx - 1, resolved)) {
|
|
82
|
-
console.log(`✓ ${resolved === "project" ? "Project" : "Global"} memory #${idx} deleted`);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
throw new CliError(`${resolved === "project" ? "Project" : "Global"} memory #${idx} not found`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { loadConfig, fetchModels, getActiveProvider } from "../../config.js";
|
|
2
|
-
import { CliError } from "../errors.js";
|
|
3
|
-
export async function runModelsCommand(opts) {
|
|
4
|
-
const config = loadConfig();
|
|
5
|
-
const provider = opts.provider ? config.providers?.find((p) => p.name === opts.provider) : getActiveProvider(config);
|
|
6
|
-
if (!provider?.baseURL || !provider?.apiKey) {
|
|
7
|
-
throw new CliError("Not configured.", { hint: "Run: min-agent setup" });
|
|
8
|
-
}
|
|
9
|
-
console.log(`Fetching models (${provider.name ?? "default"})...`);
|
|
10
|
-
const models = await fetchModels(provider.baseURL, provider.apiKey);
|
|
11
|
-
if (models.length === 0) {
|
|
12
|
-
console.log("No models found or unable to fetch model list.");
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
console.log(`\nAvailable models (${models.length}):`);
|
|
16
|
-
for (const m of models) {
|
|
17
|
-
const marker = m === provider.defaultModel ? " ← default" : "";
|
|
18
|
-
console.log(` ${m}${marker}`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { runPermissionCli } from "../../permission-cli.js";
|
|
2
|
-
export async function runPermissionCommand(args, opts, parentOpts) {
|
|
3
|
-
const scope = opts.project ? "project" : opts.global ? "global" : undefined;
|
|
4
|
-
const result = runPermissionCli({
|
|
5
|
-
positionals: args,
|
|
6
|
-
flagMode: parentOpts.permission,
|
|
7
|
-
scope,
|
|
8
|
-
});
|
|
9
|
-
console.log(result.lines.join("\n"));
|
|
10
|
-
if (!result.ok)
|
|
11
|
-
process.exitCode = 1;
|
|
12
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
2
|
-
import { getConfigDir, getRulesFile } from "../../config.js";
|
|
3
|
-
export async function runRulesShow() {
|
|
4
|
-
const { loadInstructions } = await import("../../instructions.js");
|
|
5
|
-
const instructions = await loadInstructions();
|
|
6
|
-
if (instructions.length === 0) {
|
|
7
|
-
console.log("No instruction rules loaded.");
|
|
8
|
-
console.log("");
|
|
9
|
-
console.log("Add rules by creating:");
|
|
10
|
-
console.log(` Global: ${getRulesFile()}`);
|
|
11
|
-
console.log(" Project: ./AGENTS.md or ./RULES.md");
|
|
12
|
-
console.log("");
|
|
13
|
-
console.log("Or add paths/URLs in ~/.min-agent/config.json:");
|
|
14
|
-
console.log(' { "instructions": ["./docs/rules.md", "https://..."] }');
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
console.log(`Loaded ${instructions.length} instruction source(s):\n`);
|
|
18
|
-
for (const inst of instructions) {
|
|
19
|
-
const firstLine = inst.split("\n")[0];
|
|
20
|
-
console.log(` ${firstLine}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export async function runRulesEdit() {
|
|
25
|
-
const rulesFile = getRulesFile();
|
|
26
|
-
if (!existsSync(rulesFile)) {
|
|
27
|
-
mkdirSync(getConfigDir(), { recursive: true });
|
|
28
|
-
writeFileSync(rulesFile, `# Global Agent Rules\n\n<!-- Add your custom instructions here. They will be included in every conversation. -->\n`, "utf-8");
|
|
29
|
-
}
|
|
30
|
-
const editor = process.env.EDITOR || "vi";
|
|
31
|
-
const { execSync } = await import("child_process");
|
|
32
|
-
execSync(`${editor} "${rulesFile}"`, { stdio: "inherit" });
|
|
33
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { runSandboxCli } from "../../sandbox-cli.js";
|
|
2
|
-
export async function runSandboxCommand(args, opts, parentOpts) {
|
|
3
|
-
const scope = opts.project ? "project" : opts.global ? "global" : undefined;
|
|
4
|
-
const result = runSandboxCli({
|
|
5
|
-
positionals: args,
|
|
6
|
-
flagMode: parentOpts.sandbox,
|
|
7
|
-
flagNetwork: parentOpts.network ?? opts.network,
|
|
8
|
-
scope,
|
|
9
|
-
});
|
|
10
|
-
console.log(result.lines.join("\n"));
|
|
11
|
-
if (!result.ok)
|
|
12
|
-
process.exitCode = 1;
|
|
13
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { isConfigured } from "../../config.js";
|
|
2
|
-
import { CliError } from "../errors.js";
|
|
3
|
-
export async function runServeCommand(opts) {
|
|
4
|
-
if (!isConfigured()) {
|
|
5
|
-
throw new CliError("Not configured.", { hint: "Run: min-agent setup" });
|
|
6
|
-
}
|
|
7
|
-
const { runServe } = await import("../../serve.js");
|
|
8
|
-
await runServe({ port: opts.port, host: opts.host });
|
|
9
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { Option } from "commander";
|
|
3
|
-
import { fetchModelsLive, getConfigDir, loadConfig, saveConfig } from "../../config.js";
|
|
4
|
-
import { parsePositiveIntArg } from "../option-helpers.js";
|
|
5
|
-
import { parseProviderType } from "../setup/flags.js";
|
|
6
|
-
import { runSetup } from "../setup/flow.js";
|
|
7
|
-
export function registerSetupCommand(program, rootOpts) {
|
|
8
|
-
program
|
|
9
|
-
.command("setup")
|
|
10
|
-
.description("Configure providers (interactively, or with flags)")
|
|
11
|
-
.addOption(new Option("--type <type>", "openai-compatible, openai, or ollama").argParser(parseProviderType))
|
|
12
|
-
.option("--url <url>", "API base URL")
|
|
13
|
-
.option("--api-key <key>", "API key")
|
|
14
|
-
.option("--name <name>", "Provider name")
|
|
15
|
-
.option("--default-model <id>", "Default model to save")
|
|
16
|
-
.addOption(new Option("--context-window <n>", "Context window in tokens").argParser(parsePositiveIntArg("--context-window")))
|
|
17
|
-
.option("--switch <name>", "Set the active provider")
|
|
18
|
-
.option("--remove <name>", "Remove a provider")
|
|
19
|
-
.option("-y, --yes", "Skip overwrite and delete confirmation")
|
|
20
|
-
.action(async (opts) => {
|
|
21
|
-
await runSetupCommand(opts, { yes: Boolean(opts.yes || rootOpts().yes) });
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
function createSetupDeps() {
|
|
25
|
-
return {
|
|
26
|
-
isTty: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
27
|
-
load: loadConfig,
|
|
28
|
-
save: saveConfig,
|
|
29
|
-
fetchLive: fetchModelsLive,
|
|
30
|
-
log: (message) => {
|
|
31
|
-
console.log(message);
|
|
32
|
-
},
|
|
33
|
-
configPath: () => path.join(getConfigDir(), "config.json"),
|
|
34
|
-
runWizard: async (wizardMode) => {
|
|
35
|
-
const { renderSetupWizard } = await import("../setup/ui.js");
|
|
36
|
-
return renderSetupWizard(wizardMode);
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export async function offerInteractiveSetup(mode) {
|
|
41
|
-
await runSetup({}, { ...createSetupDeps(), isTty: true }, mode);
|
|
42
|
-
}
|
|
43
|
-
export async function runSetupCommand(opts, session) {
|
|
44
|
-
const flags = {
|
|
45
|
-
type: opts.type,
|
|
46
|
-
url: opts.url,
|
|
47
|
-
apiKey: opts.apiKey,
|
|
48
|
-
name: opts.name,
|
|
49
|
-
defaultModel: opts.defaultModel,
|
|
50
|
-
contextWindow: opts.contextWindow,
|
|
51
|
-
switch: opts.switch,
|
|
52
|
-
remove: opts.remove,
|
|
53
|
-
yes: Boolean(session.yes || opts.yes),
|
|
54
|
-
};
|
|
55
|
-
await runSetup(flags, createSetupDeps());
|
|
56
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { isConfigured } from "../../config.js";
|
|
2
|
-
import { CliError } from "../errors.js";
|
|
3
|
-
import { shouldOfferSetupWizard } from "../setup/flow.js";
|
|
4
|
-
export async function startTuiSession(input) {
|
|
5
|
-
if (!isConfigured()) {
|
|
6
|
-
const tty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
7
|
-
if (!shouldOfferSetupWizard(false, tty)) {
|
|
8
|
-
throw new CliError("Not configured.", { hint: "Run: min-agent setup" });
|
|
9
|
-
}
|
|
10
|
-
const { offerInteractiveSetup } = await import("./setup.js");
|
|
11
|
-
await offerInteractiveSetup("session-gate");
|
|
12
|
-
if (!isConfigured()) {
|
|
13
|
-
throw new CliError("Not configured.", { hint: "Run: min-agent setup" });
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
const { runTui } = await import("../../tui-chat.js");
|
|
17
|
-
const prompt = input.positionals.join(" ").trim();
|
|
18
|
-
await runTui({
|
|
19
|
-
modelId: input.model,
|
|
20
|
-
providerName: input.provider,
|
|
21
|
-
resumeSessionId: input.resume,
|
|
22
|
-
images: input.images,
|
|
23
|
-
initialPrompt: prompt || undefined,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { discoverSkills } from "../../skills.js";
|
|
2
|
-
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import os from "os";
|
|
5
|
-
import { CliError } from "../errors.js";
|
|
6
|
-
/** One-line, length-capped text for list output. */
|
|
7
|
-
function truncate(text, max) {
|
|
8
|
-
const flat = text.replace(/\s+/g, " ").trim();
|
|
9
|
-
return flat.length <= max ? flat : `${flat.slice(0, max - 1)}…`;
|
|
10
|
-
}
|
|
11
|
-
export async function runSkillsList(json) {
|
|
12
|
-
discoverSkills({ silent: true });
|
|
13
|
-
const { getAllSkills, getStaleDisabledSkills } = await import("../../skills.js");
|
|
14
|
-
const all = getAllSkills().sort((a, b) => a.name.localeCompare(b.name));
|
|
15
|
-
const stale = getStaleDisabledSkills();
|
|
16
|
-
if (json) {
|
|
17
|
-
console.log(JSON.stringify({
|
|
18
|
-
count: all.length,
|
|
19
|
-
enabled_count: all.filter((s) => s.enabled).length,
|
|
20
|
-
stale_disabled: stale,
|
|
21
|
-
skills: all.map((s) => ({
|
|
22
|
-
name: s.name,
|
|
23
|
-
description: s.description,
|
|
24
|
-
location: s.location,
|
|
25
|
-
enabled: s.enabled,
|
|
26
|
-
...(s.disabledScope ? { disabled_scope: s.disabledScope } : {}),
|
|
27
|
-
...(s.version ? { version: s.version } : {}),
|
|
28
|
-
...(s.allowedTools.length ? { allowed_tools: s.allowedTools } : {}),
|
|
29
|
-
...(s.requiredBins.length ? { requires_bins: s.requiredBins } : {}),
|
|
30
|
-
...(s.builtin ? { builtin: true } : {}),
|
|
31
|
-
...(s.alwaysLoad ? { always_load: true } : {}),
|
|
32
|
-
})),
|
|
33
|
-
}, null, 2));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (all.length === 0 && stale.length === 0) {
|
|
37
|
-
console.log("No skills found. Add SKILL.md files in .min-agent/skills/<name>/");
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
console.log(`Skills (${all.filter((s) => s.enabled).length} enabled, ${all.filter((s) => !s.enabled).length} disabled):`);
|
|
41
|
-
for (const skill of all) {
|
|
42
|
-
const status = skill.enabled
|
|
43
|
-
? "\x1b[32menabled \x1b[0m"
|
|
44
|
-
: `\x1b[90mdisabled(${skill.disabledScope === "project" ? "proj" : "glob"})\x1b[0m`;
|
|
45
|
-
const origin = skill.builtin ? " \x1b[90mbuiltin\x1b[0m" : "";
|
|
46
|
-
console.log(` ${skill.name} ${status}${origin} \x1b[90m${truncate(skill.description, 60)}\x1b[0m`);
|
|
47
|
-
console.log(` \x1b[90m${skill.location}\x1b[0m`);
|
|
48
|
-
}
|
|
49
|
-
if (stale.length > 0) {
|
|
50
|
-
console.log(`\n\x1b[33m⚠ disabledSkills/enabledSkills entries matching no skill: ${stale.join(", ")}\x1b[0m`);
|
|
51
|
-
console.log(`\x1b[33m Remove them with: min-agent skills enable ${stale.join(" ")} (add --project if the entry is project-scoped)\x1b[0m`);
|
|
52
|
-
}
|
|
53
|
-
console.log("\nUse: min-agent skills info <name> for details");
|
|
54
|
-
}
|
|
55
|
-
export async function runSkillsInfo(name, json) {
|
|
56
|
-
discoverSkills({ silent: true });
|
|
57
|
-
const { getSkill, getAllSkills } = await import("../../skills.js");
|
|
58
|
-
const skill = getSkill(name);
|
|
59
|
-
if (!skill) {
|
|
60
|
-
const names = getAllSkills().map((s) => s.name);
|
|
61
|
-
throw new CliError(`Skill "${name}" not found.${names.length ? ` Available: ${names.join(", ")}` : " No skills discovered."}`);
|
|
62
|
-
}
|
|
63
|
-
if (json) {
|
|
64
|
-
console.log(JSON.stringify(skill, null, 2));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
console.log(`Name: ${skill.name}`);
|
|
68
|
-
console.log(`Status: ${skill.enabled ? "enabled" : `disabled (${skill.disabledScope} scope)`}`);
|
|
69
|
-
if (skill.builtin)
|
|
70
|
-
console.log("Source: builtin");
|
|
71
|
-
if (skill.version)
|
|
72
|
-
console.log(`Version: ${skill.version}`);
|
|
73
|
-
console.log(`Description: ${skill.description}`);
|
|
74
|
-
console.log(`Location: ${skill.location}`);
|
|
75
|
-
if (skill.allowedTools.length > 0)
|
|
76
|
-
console.log(`Tools: ${skill.allowedTools.join(", ")}`);
|
|
77
|
-
if (skill.requiredBins.length > 0)
|
|
78
|
-
console.log(`Requires: ${skill.requiredBins.join(", ")}`);
|
|
79
|
-
if (skill.content.trim()) {
|
|
80
|
-
console.log("\n--- Content ---\n");
|
|
81
|
-
console.log(skill.content.trim());
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export async function runSkillsToggle(names, enabled, scope) {
|
|
85
|
-
const verb = enabled ? "enable" : "disable";
|
|
86
|
-
if (names.length === 0)
|
|
87
|
-
throw new CliError(`Usage: min-agent skills ${verb} <name...> [--project]`);
|
|
88
|
-
discoverSkills({ silent: true });
|
|
89
|
-
const { getAllSkills, setSkillEnabled, getStaleDisabledSkills } = await import("../../skills.js");
|
|
90
|
-
const known = new Set(getAllSkills().map((s) => s.name));
|
|
91
|
-
const stale = new Set(getStaleDisabledSkills());
|
|
92
|
-
// `enable` must accept stale names so they can be cleaned up from config;
|
|
93
|
-
// `disable` on an unknown name is always an error.
|
|
94
|
-
const unknown = names.filter((n) => !known.has(n) && !(enabled && stale.has(n)));
|
|
95
|
-
if (unknown.length > 0) {
|
|
96
|
-
throw new CliError(`Skill${unknown.length > 1 ? "s" : ""} not found: ${unknown.join(", ")}`, {
|
|
97
|
-
hint: known.size ? `Available: ${[...known].join(", ")}` : "No skills discovered.",
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
for (const result of setSkillEnabled(names, enabled, scope)) {
|
|
101
|
-
console.log(`✓ Skill "${result.name}" ${verb}d (${scope} scope)`);
|
|
102
|
-
if (result.blockedBy) {
|
|
103
|
-
console.log(`\x1b[33m ⚠ still ${result.enabled ? "enabled" : "disabled"} — overridden by ${result.blockedBy} scope\x1b[0m`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
export async function runSkillsNew(name, global) {
|
|
108
|
-
if (!/^[\w-]+$/.test(name)) {
|
|
109
|
-
throw new CliError("Invalid skill name", { hint: "use letters, digits, _ or -" });
|
|
110
|
-
}
|
|
111
|
-
const root = global ? path.join(os.homedir(), ".agents", "skills") : path.join(process.cwd(), ".min-agent", "skills");
|
|
112
|
-
const dir = path.join(root, name);
|
|
113
|
-
if (existsSync(path.join(dir, "SKILL.md"))) {
|
|
114
|
-
throw new CliError(`Skill "${name}" already exists at ${dir}`);
|
|
115
|
-
}
|
|
116
|
-
mkdirSync(dir, { recursive: true });
|
|
117
|
-
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");
|
|
118
|
-
console.log(`✓ Created skill "${name}" at ${path.join(dir, "SKILL.md")}`);
|
|
119
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { runThinkCli } from "../../think-cli.js";
|
|
2
|
-
export async function runThinkCommand(args, opts, parentOpts) {
|
|
3
|
-
const scope = opts.project ? "project" : opts.global ? "global" : undefined;
|
|
4
|
-
const result = runThinkCli({
|
|
5
|
-
positionals: args,
|
|
6
|
-
flagEffort: parentOpts.think,
|
|
7
|
-
scope,
|
|
8
|
-
});
|
|
9
|
-
console.log(result.lines.join("\n"));
|
|
10
|
-
if (!result.ok)
|
|
11
|
-
process.exitCode = 1;
|
|
12
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { runSandboxCli } from "../../sandbox-cli.js";
|
|
2
|
-
import { runPermissionCli } from "../../permission-cli.js";
|
|
3
|
-
import { runThinkCli } from "../../think-cli.js";
|
|
4
|
-
import { runMemoryCli } from "../../memory-cli.js";
|
|
5
|
-
export async function runWriteConfig(input) {
|
|
6
|
-
const lines = [];
|
|
7
|
-
let ok = true;
|
|
8
|
-
if (input.sandbox !== undefined || input.network !== undefined) {
|
|
9
|
-
const result = runSandboxCli({
|
|
10
|
-
positionals: [],
|
|
11
|
-
flagMode: input.sandbox,
|
|
12
|
-
flagNetwork: input.network,
|
|
13
|
-
scope: input.scope,
|
|
14
|
-
});
|
|
15
|
-
lines.push(...result.lines);
|
|
16
|
-
if (!result.ok)
|
|
17
|
-
ok = false;
|
|
18
|
-
}
|
|
19
|
-
if (input.permission !== undefined) {
|
|
20
|
-
const result = runPermissionCli({
|
|
21
|
-
positionals: [],
|
|
22
|
-
flagMode: input.permission,
|
|
23
|
-
scope: input.scope,
|
|
24
|
-
});
|
|
25
|
-
lines.push(...result.lines);
|
|
26
|
-
if (!result.ok)
|
|
27
|
-
ok = false;
|
|
28
|
-
}
|
|
29
|
-
if (input.think !== undefined) {
|
|
30
|
-
const result = runThinkCli({
|
|
31
|
-
positionals: [],
|
|
32
|
-
flagEffort: input.think,
|
|
33
|
-
scope: input.scope,
|
|
34
|
-
});
|
|
35
|
-
lines.push(...result.lines);
|
|
36
|
-
if (!result.ok)
|
|
37
|
-
ok = false;
|
|
38
|
-
}
|
|
39
|
-
if (input.memory !== undefined) {
|
|
40
|
-
const result = runMemoryCli({
|
|
41
|
-
positionals: [],
|
|
42
|
-
flagMode: input.memory,
|
|
43
|
-
scope: input.scope,
|
|
44
|
-
});
|
|
45
|
-
lines.push(...result.lines);
|
|
46
|
-
if (!result.ok)
|
|
47
|
-
ok = false;
|
|
48
|
-
}
|
|
49
|
-
console.log(lines.join("\n"));
|
|
50
|
-
if (!ok)
|
|
51
|
-
process.exitCode = 1;
|
|
52
|
-
}
|
package/dist/cli/errors.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unified CLI error contract.
|
|
3
|
-
*
|
|
4
|
-
* Exit code convention:
|
|
5
|
-
* 1 - user error (bad arguments, missing input, not found, validation failure)
|
|
6
|
-
* 2 - runtime error (network failure, subprocess failure, unexpected exception)
|
|
7
|
-
*/
|
|
8
|
-
export class CliError extends Error {
|
|
9
|
-
exitCode;
|
|
10
|
-
hint;
|
|
11
|
-
constructor(message, options) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.name = "CliError";
|
|
14
|
-
this.exitCode = options?.exitCode ?? 1;
|
|
15
|
-
this.hint = options?.hint;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export function userError(message, hint) {
|
|
19
|
-
return new CliError(message, { exitCode: 1, hint });
|
|
20
|
-
}
|
|
21
|
-
export function runtimeError(message, hint) {
|
|
22
|
-
return new CliError(message, { exitCode: 2, hint });
|
|
23
|
-
}
|
|
24
|
-
/** Render a CliError (or any error) as the standard `✖ message` block on stderr. */
|
|
25
|
-
export function formatCliError(err) {
|
|
26
|
-
if (err instanceof CliError) {
|
|
27
|
-
return err.hint ? `✖ ${err.message}\n → ${err.hint}` : `✖ ${err.message}`;
|
|
28
|
-
}
|
|
29
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
-
return `✖ ${message}`;
|
|
31
|
-
}
|
|
32
|
-
export function exitCodeFor(err) {
|
|
33
|
-
if (err instanceof CliError)
|
|
34
|
-
return err.exitCode;
|
|
35
|
-
return 2;
|
|
36
|
-
}
|