aether-code 0.42.0 → 0.43.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 +2 -0
- package/bin/aether-code.js +514 -514
- package/package.json +75 -75
- package/src/agent.js +54 -4
- package/src/project-context.js +712 -707
- package/src/render.js +254 -254
- package/src/repl.js +444 -444
- package/src/sessions.js +167 -167
- package/src/setup.js +141 -141
- package/src/tools.js +1288 -1288
- package/src/version.js +15 -15
package/package.json
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "aether-code",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Uncensored AI coding agent for your terminal — Claude Code alternative with MCP support. Reads code, writes files, runs commands. Drives IDA Pro, Roblox Studio, Wireshark, Blender, and any MCP server. No refusal layer.",
|
|
5
|
-
"homepage": "https://trynoguard.com",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "https://github.com/dannyphantomx64/aether-code"
|
|
9
|
-
},
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"type": "module",
|
|
12
|
-
"bin": {
|
|
13
|
-
"aether": "bin/aether-code.js"
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"bin",
|
|
17
|
-
"src",
|
|
18
|
-
"skills",
|
|
19
|
-
"README.md",
|
|
20
|
-
"LICENSE"
|
|
21
|
-
],
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=18"
|
|
24
|
-
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"lint": "node --check bin/aether-code.js src/agent.js src/api.js src/config.js src/render.js src/tools.js src/diff.js src/repl.js src/mcp.js src/mcp-cli.js src/mcp-registry.js src/skills.js src/update-check.js src/ink-input.js src/version.js src/sessions.js src/project-context.js",
|
|
27
|
-
"test": "node --test \"test/**/*.test.js\"",
|
|
28
|
-
"prepublishOnly": "npm run lint && npm test"
|
|
29
|
-
},
|
|
30
|
-
"keywords": [
|
|
31
|
-
"aether",
|
|
32
|
-
"ai",
|
|
33
|
-
"ai-agent",
|
|
34
|
-
"ai-cli",
|
|
35
|
-
"ai-coding-assistant",
|
|
36
|
-
"ai-coding-agent",
|
|
37
|
-
"ai-pair-programmer",
|
|
38
|
-
"agent",
|
|
39
|
-
"agentic",
|
|
40
|
-
"agentic-ai",
|
|
41
|
-
"cli",
|
|
42
|
-
"claude-code",
|
|
43
|
-
"claude-code-alternative",
|
|
44
|
-
"cursor-alternative",
|
|
45
|
-
"coding-agent",
|
|
46
|
-
"code-generation",
|
|
47
|
-
"developer-tools",
|
|
48
|
-
"llm",
|
|
49
|
-
"llm-agent",
|
|
50
|
-
"llm-tools",
|
|
51
|
-
"mcp",
|
|
52
|
-
"mcp-client",
|
|
53
|
-
"model-context-protocol",
|
|
54
|
-
"modelcontextprotocol",
|
|
55
|
-
"ida-pro",
|
|
56
|
-
"reverse-engineering",
|
|
57
|
-
"roblox",
|
|
58
|
-
"uncensored",
|
|
59
|
-
"uncensored-ai",
|
|
60
|
-
"uncensored-llm",
|
|
61
|
-
"terminal",
|
|
62
|
-
"tool-use",
|
|
63
|
-
"tool-calling",
|
|
64
|
-
"trynoguard"
|
|
65
|
-
],
|
|
66
|
-
"dependencies": {
|
|
67
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
68
|
-
"ink": "^7.1.0",
|
|
69
|
-
"ink-text-input": "^6.0.0",
|
|
70
|
-
"react": "^19.2.7"
|
|
71
|
-
},
|
|
72
|
-
"devDependencies": {
|
|
73
|
-
"ink-testing-library": "^4.0.0"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "aether-code",
|
|
3
|
+
"version": "0.43.0",
|
|
4
|
+
"description": "Uncensored AI coding agent for your terminal — Claude Code alternative with MCP support. Reads code, writes files, runs commands. Drives IDA Pro, Roblox Studio, Wireshark, Blender, and any MCP server. No refusal layer.",
|
|
5
|
+
"homepage": "https://trynoguard.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/dannyphantomx64/aether-code"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"aether": "bin/aether-code.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"src",
|
|
18
|
+
"skills",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"lint": "node --check bin/aether-code.js src/agent.js src/api.js src/config.js src/render.js src/tools.js src/diff.js src/repl.js src/mcp.js src/mcp-cli.js src/mcp-registry.js src/skills.js src/update-check.js src/ink-input.js src/version.js src/sessions.js src/project-context.js",
|
|
27
|
+
"test": "node --test \"test/**/*.test.js\"",
|
|
28
|
+
"prepublishOnly": "npm run lint && npm test"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"aether",
|
|
32
|
+
"ai",
|
|
33
|
+
"ai-agent",
|
|
34
|
+
"ai-cli",
|
|
35
|
+
"ai-coding-assistant",
|
|
36
|
+
"ai-coding-agent",
|
|
37
|
+
"ai-pair-programmer",
|
|
38
|
+
"agent",
|
|
39
|
+
"agentic",
|
|
40
|
+
"agentic-ai",
|
|
41
|
+
"cli",
|
|
42
|
+
"claude-code",
|
|
43
|
+
"claude-code-alternative",
|
|
44
|
+
"cursor-alternative",
|
|
45
|
+
"coding-agent",
|
|
46
|
+
"code-generation",
|
|
47
|
+
"developer-tools",
|
|
48
|
+
"llm",
|
|
49
|
+
"llm-agent",
|
|
50
|
+
"llm-tools",
|
|
51
|
+
"mcp",
|
|
52
|
+
"mcp-client",
|
|
53
|
+
"model-context-protocol",
|
|
54
|
+
"modelcontextprotocol",
|
|
55
|
+
"ida-pro",
|
|
56
|
+
"reverse-engineering",
|
|
57
|
+
"roblox",
|
|
58
|
+
"uncensored",
|
|
59
|
+
"uncensored-ai",
|
|
60
|
+
"uncensored-llm",
|
|
61
|
+
"terminal",
|
|
62
|
+
"tool-use",
|
|
63
|
+
"tool-calling",
|
|
64
|
+
"trynoguard"
|
|
65
|
+
],
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
68
|
+
"ink": "^7.1.0",
|
|
69
|
+
"ink-text-input": "^6.0.0",
|
|
70
|
+
"react": "^19.2.7"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"ink-testing-library": "^4.0.0"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/agent.js
CHANGED
|
@@ -14,6 +14,35 @@ import { c, divider, turn, toolLabel, toolSummary, makeTokenStripper, errorLine,
|
|
|
14
14
|
|
|
15
15
|
const DEFAULT_MAX_TURNS = 25;
|
|
16
16
|
|
|
17
|
+
// Rolling history window (messages) sent upstream per turn. The session keeps
|
|
18
|
+
// the full transcript locally, but we only forward the anchor (first message,
|
|
19
|
+
// which carries the [environment] block) plus the most recent N messages. This
|
|
20
|
+
// bounds per-turn token cost AND keeps us safely under the server's own cap —
|
|
21
|
+
// a long session used to grow unbounded and, past the server's limit, every
|
|
22
|
+
// send failed with "Error: Invalid input." with no recovery but /clear.
|
|
23
|
+
const HISTORY_WINDOW = 100;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Trim a message array to `maxMessages`, preserving:
|
|
27
|
+
* - the anchor message at index 0 (the first user turn carries the
|
|
28
|
+
* [environment] block with real absolute paths — dropping it makes the
|
|
29
|
+
* model lose cwd/home/desktop);
|
|
30
|
+
* - tool-call/tool-result pairing at the window boundary: a `tool` message
|
|
31
|
+
* must immediately follow the assistant message whose `tool_calls` produced
|
|
32
|
+
* it, so the window is never allowed to BEGIN on an orphaned `tool` result.
|
|
33
|
+
* Returns the original array untouched when it's already within the window.
|
|
34
|
+
*/
|
|
35
|
+
export function trimHistory(messages, maxMessages = HISTORY_WINDOW) {
|
|
36
|
+
if (messages.length <= maxMessages) return messages;
|
|
37
|
+
const head = [messages[0]];
|
|
38
|
+
const windowSize = Math.max(1, maxMessages - 1);
|
|
39
|
+
let window = messages.slice(1).slice(-windowSize);
|
|
40
|
+
let start = 0;
|
|
41
|
+
while (start < window.length && window[start]?.role === "tool") start++;
|
|
42
|
+
window = window.slice(start);
|
|
43
|
+
return [...head, ...window];
|
|
44
|
+
}
|
|
45
|
+
|
|
17
46
|
export const MOD_RE =
|
|
18
47
|
/\b(refactor|fix|add|adds?|change|update|implement|creat|writ|remov|delet|rename|extract|move|replace|build|generate|insert|append|convert|migrat|wire|hook|edit|modif|patch|integrat)/i;
|
|
19
48
|
|
|
@@ -130,7 +159,7 @@ export async function runAgent({
|
|
|
130
159
|
// to the last user message of a shallow-cloned messages array — we
|
|
131
160
|
// don't want skill text accumulating in the persisted history, only
|
|
132
161
|
// being available to the model for the turn where it's relevant.
|
|
133
|
-
const turnMessages = buildTurnMessages(messages, allSkills, referencedPaths);
|
|
162
|
+
const turnMessages = trimHistory(buildTurnMessages(messages, allSkills, referencedPaths));
|
|
134
163
|
|
|
135
164
|
let res;
|
|
136
165
|
// "Thinking" spinner: shown from request-send until the first token or tool
|
|
@@ -383,8 +412,23 @@ export async function runAgent({
|
|
|
383
412
|
return { ok: false, error: new Error("Max turns reached"), totalCredits, totalIn, totalOut, balance: lastBalance, messages };
|
|
384
413
|
}
|
|
385
414
|
|
|
415
|
+
// A build/verify command failing because the TOOLCHAIN ITSELF is missing (e.g.
|
|
416
|
+
// g++/cargo/dotnet not installed) is not a code bug — it must NOT be reported as
|
|
417
|
+
// "build failed" and fed back to the model, which would derail the run into
|
|
418
|
+
// 5 rounds of "fixing" code that's actually fine. These are the shell's
|
|
419
|
+
// command-not-found messages (Windows cmd.exe + POSIX sh); real compiler
|
|
420
|
+
// diagnostics look like `main.cpp:5:10: error: ...` and never match these.
|
|
421
|
+
// Matches ONLY the shell's "I can't find this executable" messages — Windows
|
|
422
|
+
// cmd.exe ("'g++' is not recognized…") and POSIX sh ("g++: command not found",
|
|
423
|
+
// "sh: 1: g++: not found"). Real compiler diagnostics (`main.cpp:5: error:`,
|
|
424
|
+
// `fatal error: foo.h: No such file or directory`) never match these, so a
|
|
425
|
+
// genuine build error is still reported and fixed.
|
|
426
|
+
const TOOLCHAIN_MISSING_RE =
|
|
427
|
+
/is not recognized as an internal or external command|: command not found|: not found\b/i;
|
|
428
|
+
|
|
386
429
|
// Auto-verify: run the project's typecheck/lint command silently and return
|
|
387
|
-
// { ok, output, label }. Returns null if no verify command is detected
|
|
430
|
+
// { ok, output, label }. Returns null if no verify command is detected OR the
|
|
431
|
+
// toolchain isn't installed (skip, don't report a false failure).
|
|
388
432
|
let cachedVerify = undefined;
|
|
389
433
|
async function runVerify(cwd) {
|
|
390
434
|
if (cachedVerify === undefined) cachedVerify = detectVerifyCommand(cwd);
|
|
@@ -400,6 +444,8 @@ async function runVerify(cwd) {
|
|
|
400
444
|
child.on("close", (code) => {
|
|
401
445
|
clearTimeout(timer);
|
|
402
446
|
const output = (stdout + "\n" + stderr).trim();
|
|
447
|
+
// Toolchain not installed → skip silently rather than nag the model.
|
|
448
|
+
if (code !== 0 && TOOLCHAIN_MISSING_RE.test(output)) { resolve(null); return; }
|
|
403
449
|
resolve({ ok: code === 0, output, label });
|
|
404
450
|
});
|
|
405
451
|
child.on("error", () => {
|
|
@@ -437,11 +483,15 @@ async function runBuildCmd(cwd, { cmd, label, type, runCmd }) {
|
|
|
437
483
|
child.on("close", (code) => {
|
|
438
484
|
clearTimeout(timer);
|
|
439
485
|
const output = (stdout + "\n" + stderr).trim();
|
|
486
|
+
// Compiler/toolchain not installed → skip auto-build silently instead of
|
|
487
|
+
// reporting a build failure and derailing the run.
|
|
488
|
+
if (code !== 0 && TOOLCHAIN_MISSING_RE.test(output)) { resolve(null); return; }
|
|
440
489
|
resolve({ ok: code === 0, output, label, type, runCmd });
|
|
441
490
|
});
|
|
442
|
-
child.on("error", (
|
|
491
|
+
child.on("error", () => {
|
|
443
492
|
clearTimeout(timer);
|
|
444
|
-
|
|
493
|
+
// ENOENT (command not found) → toolchain missing → skip.
|
|
494
|
+
resolve(null);
|
|
445
495
|
});
|
|
446
496
|
});
|
|
447
497
|
}
|