aether-code 0.42.0 → 0.43.1
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/LICENSE +21 -21
- package/README.md +2 -0
- package/bin/aether-code.js +515 -513
- package/package.json +77 -75
- package/scripts/postinstall.js +182 -0
- package/skills/adult-creative-writing.md +60 -60
- package/skills/debugging.md +51 -51
- package/skills/game-modding.md +73 -73
- package/skills/reverse-engineering.md +41 -41
- package/skills/scraping-automation.md +77 -77
- package/skills/security-research.md +67 -67
- package/src/agent.js +170 -219
- package/src/api.js +22 -32
- package/src/box-input.js +141 -36
- package/src/config.js +38 -38
- package/src/diff.js +49 -49
- package/src/ink-input.js +91 -91
- package/src/mcp-cli.js +94 -94
- package/src/mcp-registry.js +266 -266
- package/src/mcp.js +259 -260
- package/src/menu.js +83 -83
- package/src/render.js +141 -107
- package/src/repl.js +221 -257
- package/src/setup.js +139 -141
- package/src/tools.js +911 -1288
- package/src/update-check.js +64 -7
- package/src/project-context.js +0 -707
- package/src/sessions.js +0 -167
- package/src/version.js +0 -15
package/src/mcp-cli.js
CHANGED
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
// `aether mcp` subcommand machinery: add / remove / list MCP servers
|
|
2
|
-
// in ~/.aether/mcp.json without the user hand-editing JSON.
|
|
3
|
-
//
|
|
4
|
-
// All read/write goes through this module so the validation (delegated to
|
|
5
|
-
// mcp.js) is consistent with what MCPManager will accept at runtime.
|
|
6
|
-
// configPath is injectable for tests; production code uses DEFAULT_PATH.
|
|
7
|
-
|
|
8
|
-
import fs from "node:fs";
|
|
9
|
-
import os from "node:os";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { validateMcpConfig } from "./mcp.js";
|
|
12
|
-
|
|
13
|
-
const DEFAULT_PATH = path.join(os.homedir(), ".aether", "mcp.json");
|
|
14
|
-
|
|
15
|
-
function resolvePath(opts) {
|
|
16
|
-
return opts?.configPath || DEFAULT_PATH;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function readConfig(opts) {
|
|
20
|
-
const p = resolvePath(opts);
|
|
21
|
-
if (!fs.existsSync(p)) return { mcpServers: {} };
|
|
22
|
-
let raw;
|
|
23
|
-
try {
|
|
24
|
-
raw = fs.readFileSync(p, "utf8");
|
|
25
|
-
} catch (e) {
|
|
26
|
-
throw new Error(`MCP config at ${p} unreadable: ${e.message}`);
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const parsed = JSON.parse(raw);
|
|
30
|
-
if (!parsed.mcpServers || typeof parsed.mcpServers !== "object") {
|
|
31
|
-
return { ...parsed, mcpServers: {} };
|
|
32
|
-
}
|
|
33
|
-
return parsed;
|
|
34
|
-
} catch (e) {
|
|
35
|
-
throw new Error(`MCP config at ${p} is not valid JSON: ${e.message}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function writeConfig(config, opts) {
|
|
40
|
-
const p = resolvePath(opts);
|
|
41
|
-
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
42
|
-
// Pretty-print so users can read + hand-edit if they want, and trailing
|
|
43
|
-
// newline so diff tools don't bicker.
|
|
44
|
-
fs.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Add a server entry. Mutates ~/.aether/mcp.json (creating it + the dir
|
|
49
|
-
* if missing). Validates the full resulting config via validateMcpConfig
|
|
50
|
-
* so a bad add can't poison the file with a config the runtime would
|
|
51
|
-
* later reject.
|
|
52
|
-
*/
|
|
53
|
-
export function addServer({ configPath, name, command, args = [], env = {} }) {
|
|
54
|
-
const cfg = readConfig({ configPath });
|
|
55
|
-
if (cfg.mcpServers[name]) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
`MCP server "${name}" already configured. Remove it first with \`aether mcp remove ${name}\` or pick a different name.`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
const entry = { command };
|
|
61
|
-
if (args.length > 0) entry.args = args;
|
|
62
|
-
if (Object.keys(env).length > 0) entry.env = env;
|
|
63
|
-
const next = {
|
|
64
|
-
...cfg,
|
|
65
|
-
mcpServers: { ...cfg.mcpServers, [name]: entry },
|
|
66
|
-
};
|
|
67
|
-
validateMcpConfig(next, configPath || "<add>"); // throws on schema failure
|
|
68
|
-
writeConfig(next, { configPath });
|
|
69
|
-
return entry;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Remove a server entry by name. Throws if it doesn't exist (so the user
|
|
74
|
-
* notices typos instead of silently no-op'ing).
|
|
75
|
-
*/
|
|
76
|
-
export function removeServer({ configPath, name }) {
|
|
77
|
-
const cfg = readConfig({ configPath });
|
|
78
|
-
if (!cfg.mcpServers[name]) {
|
|
79
|
-
throw new Error(`MCP server "${name}" not configured.`);
|
|
80
|
-
}
|
|
81
|
-
const nextServers = { ...cfg.mcpServers };
|
|
82
|
-
delete nextServers[name];
|
|
83
|
-
const next = { ...cfg, mcpServers: nextServers };
|
|
84
|
-
writeConfig(next, { configPath });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Return [[name, entry], ...] for every configured server. Empty array
|
|
89
|
-
* when no config exists or mcpServers is empty.
|
|
90
|
-
*/
|
|
91
|
-
export function listServers(opts) {
|
|
92
|
-
const cfg = readConfig(opts);
|
|
93
|
-
return Object.entries(cfg.mcpServers);
|
|
94
|
-
}
|
|
1
|
+
// `aether mcp` subcommand machinery: add / remove / list MCP servers
|
|
2
|
+
// in ~/.aether/mcp.json without the user hand-editing JSON.
|
|
3
|
+
//
|
|
4
|
+
// All read/write goes through this module so the validation (delegated to
|
|
5
|
+
// mcp.js) is consistent with what MCPManager will accept at runtime.
|
|
6
|
+
// configPath is injectable for tests; production code uses DEFAULT_PATH.
|
|
7
|
+
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { validateMcpConfig } from "./mcp.js";
|
|
12
|
+
|
|
13
|
+
const DEFAULT_PATH = path.join(os.homedir(), ".aether", "mcp.json");
|
|
14
|
+
|
|
15
|
+
function resolvePath(opts) {
|
|
16
|
+
return opts?.configPath || DEFAULT_PATH;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function readConfig(opts) {
|
|
20
|
+
const p = resolvePath(opts);
|
|
21
|
+
if (!fs.existsSync(p)) return { mcpServers: {} };
|
|
22
|
+
let raw;
|
|
23
|
+
try {
|
|
24
|
+
raw = fs.readFileSync(p, "utf8");
|
|
25
|
+
} catch (e) {
|
|
26
|
+
throw new Error(`MCP config at ${p} unreadable: ${e.message}`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(raw);
|
|
30
|
+
if (!parsed.mcpServers || typeof parsed.mcpServers !== "object") {
|
|
31
|
+
return { ...parsed, mcpServers: {} };
|
|
32
|
+
}
|
|
33
|
+
return parsed;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
throw new Error(`MCP config at ${p} is not valid JSON: ${e.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function writeConfig(config, opts) {
|
|
40
|
+
const p = resolvePath(opts);
|
|
41
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
42
|
+
// Pretty-print so users can read + hand-edit if they want, and trailing
|
|
43
|
+
// newline so diff tools don't bicker.
|
|
44
|
+
fs.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Add a server entry. Mutates ~/.aether/mcp.json (creating it + the dir
|
|
49
|
+
* if missing). Validates the full resulting config via validateMcpConfig
|
|
50
|
+
* so a bad add can't poison the file with a config the runtime would
|
|
51
|
+
* later reject.
|
|
52
|
+
*/
|
|
53
|
+
export function addServer({ configPath, name, command, args = [], env = {} }) {
|
|
54
|
+
const cfg = readConfig({ configPath });
|
|
55
|
+
if (cfg.mcpServers[name]) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`MCP server "${name}" already configured. Remove it first with \`aether mcp remove ${name}\` or pick a different name.`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
const entry = { command };
|
|
61
|
+
if (args.length > 0) entry.args = args;
|
|
62
|
+
if (Object.keys(env).length > 0) entry.env = env;
|
|
63
|
+
const next = {
|
|
64
|
+
...cfg,
|
|
65
|
+
mcpServers: { ...cfg.mcpServers, [name]: entry },
|
|
66
|
+
};
|
|
67
|
+
validateMcpConfig(next, configPath || "<add>"); // throws on schema failure
|
|
68
|
+
writeConfig(next, { configPath });
|
|
69
|
+
return entry;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Remove a server entry by name. Throws if it doesn't exist (so the user
|
|
74
|
+
* notices typos instead of silently no-op'ing).
|
|
75
|
+
*/
|
|
76
|
+
export function removeServer({ configPath, name }) {
|
|
77
|
+
const cfg = readConfig({ configPath });
|
|
78
|
+
if (!cfg.mcpServers[name]) {
|
|
79
|
+
throw new Error(`MCP server "${name}" not configured.`);
|
|
80
|
+
}
|
|
81
|
+
const nextServers = { ...cfg.mcpServers };
|
|
82
|
+
delete nextServers[name];
|
|
83
|
+
const next = { ...cfg, mcpServers: nextServers };
|
|
84
|
+
writeConfig(next, { configPath });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Return [[name, entry], ...] for every configured server. Empty array
|
|
89
|
+
* when no config exists or mcpServers is empty.
|
|
90
|
+
*/
|
|
91
|
+
export function listServers(opts) {
|
|
92
|
+
const cfg = readConfig(opts);
|
|
93
|
+
return Object.entries(cfg.mcpServers);
|
|
94
|
+
}
|