aether-code 0.12.0 → 0.14.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/LICENSE +21 -21
- package/bin/aether-code.js +457 -457
- package/package.json +69 -68
- package/src/agent.js +197 -197
- package/src/api.js +287 -234
- package/src/config.js +38 -38
- package/src/diff.js +48 -48
- package/src/render.js +58 -58
- package/src/repl.js +260 -247
- package/src/setup.js +139 -139
- package/src/skills.js +3 -0
- package/src/tools.js +803 -621
package/src/diff.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
// Tiny line-by-line diff for write_file confirmation prompts.
|
|
2
|
-
// Not a "real" diff — just a side-by-side highlight of what's changing.
|
|
3
|
-
// Good enough for confirmation prompts, deliberately not pretending to be `git diff`.
|
|
4
|
-
|
|
5
|
-
import { c } from "./render.js";
|
|
6
|
-
|
|
7
|
-
export function unifiedDiff(oldText, newText, filename) {
|
|
8
|
-
const oldLines = (oldText || "").split("\n");
|
|
9
|
-
const newLines = (newText || "").split("\n");
|
|
10
|
-
const max = Math.max(oldLines.length, newLines.length);
|
|
11
|
-
|
|
12
|
-
// Find common prefix and suffix to keep the diff focused
|
|
13
|
-
let prefix = 0;
|
|
14
|
-
while (prefix < max && oldLines[prefix] === newLines[prefix]) prefix++;
|
|
15
|
-
let suffix = 0;
|
|
16
|
-
while (
|
|
17
|
-
suffix < max - prefix &&
|
|
18
|
-
oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix]
|
|
19
|
-
) {
|
|
20
|
-
suffix++;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const changedOld = oldLines.slice(prefix, oldLines.length - suffix);
|
|
24
|
-
const changedNew = newLines.slice(prefix, newLines.length - suffix);
|
|
25
|
-
|
|
26
|
-
const lines = [];
|
|
27
|
-
lines.push(c.bold(c.cyan(`@@ ${filename} @@`)));
|
|
28
|
-
if (prefix > 0) lines.push(c.gray(` …${prefix} unchanged line${prefix === 1 ? "" : "s"} above…`));
|
|
29
|
-
for (const l of changedOld) lines.push(c.red(`- ${l}`));
|
|
30
|
-
for (const l of changedNew) lines.push(c.green(`+ ${l}`));
|
|
31
|
-
if (suffix > 0) lines.push(c.gray(` …${suffix} unchanged line${suffix === 1 ? "" : "s"} below…`));
|
|
32
|
-
|
|
33
|
-
// Cap output so massive writes don't flood the terminal
|
|
34
|
-
if (lines.length > 60) {
|
|
35
|
-
return [...lines.slice(0, 30), c.gray(` …${lines.length - 60} more lines hidden…`), ...lines.slice(-30)].join(
|
|
36
|
-
"\n",
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
return lines.join("\n");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function summarizeWrite(oldText, newText, filename) {
|
|
43
|
-
const oldLines = (oldText || "").split("\n").length;
|
|
44
|
-
const newLines = (newText || "").split("\n").length;
|
|
45
|
-
const isCreate = oldText === null || oldText === undefined;
|
|
46
|
-
const verb = isCreate ? "create" : "rewrite";
|
|
47
|
-
return c.dim(`${verb} ${filename} (${oldLines} → ${newLines} lines, ${(newText || "").length} bytes)`);
|
|
48
|
-
}
|
|
1
|
+
// Tiny line-by-line diff for write_file confirmation prompts.
|
|
2
|
+
// Not a "real" diff — just a side-by-side highlight of what's changing.
|
|
3
|
+
// Good enough for confirmation prompts, deliberately not pretending to be `git diff`.
|
|
4
|
+
|
|
5
|
+
import { c } from "./render.js";
|
|
6
|
+
|
|
7
|
+
export function unifiedDiff(oldText, newText, filename) {
|
|
8
|
+
const oldLines = (oldText || "").split("\n");
|
|
9
|
+
const newLines = (newText || "").split("\n");
|
|
10
|
+
const max = Math.max(oldLines.length, newLines.length);
|
|
11
|
+
|
|
12
|
+
// Find common prefix and suffix to keep the diff focused
|
|
13
|
+
let prefix = 0;
|
|
14
|
+
while (prefix < max && oldLines[prefix] === newLines[prefix]) prefix++;
|
|
15
|
+
let suffix = 0;
|
|
16
|
+
while (
|
|
17
|
+
suffix < max - prefix &&
|
|
18
|
+
oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix]
|
|
19
|
+
) {
|
|
20
|
+
suffix++;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const changedOld = oldLines.slice(prefix, oldLines.length - suffix);
|
|
24
|
+
const changedNew = newLines.slice(prefix, newLines.length - suffix);
|
|
25
|
+
|
|
26
|
+
const lines = [];
|
|
27
|
+
lines.push(c.bold(c.cyan(`@@ ${filename} @@`)));
|
|
28
|
+
if (prefix > 0) lines.push(c.gray(` …${prefix} unchanged line${prefix === 1 ? "" : "s"} above…`));
|
|
29
|
+
for (const l of changedOld) lines.push(c.red(`- ${l}`));
|
|
30
|
+
for (const l of changedNew) lines.push(c.green(`+ ${l}`));
|
|
31
|
+
if (suffix > 0) lines.push(c.gray(` …${suffix} unchanged line${suffix === 1 ? "" : "s"} below…`));
|
|
32
|
+
|
|
33
|
+
// Cap output so massive writes don't flood the terminal
|
|
34
|
+
if (lines.length > 60) {
|
|
35
|
+
return [...lines.slice(0, 30), c.gray(` …${lines.length - 60} more lines hidden…`), ...lines.slice(-30)].join(
|
|
36
|
+
"\n",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return lines.join("\n");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function summarizeWrite(oldText, newText, filename) {
|
|
43
|
+
const oldLines = (oldText || "").split("\n").length;
|
|
44
|
+
const newLines = (newText || "").split("\n").length;
|
|
45
|
+
const isCreate = oldText === null || oldText === undefined;
|
|
46
|
+
const verb = isCreate ? "create" : "rewrite";
|
|
47
|
+
return c.dim(`${verb} ${filename} (${oldLines} → ${newLines} lines, ${(newText || "").length} bytes)`);
|
|
48
|
+
}
|
package/src/render.js
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
// ANSI helpers — no chalk dependency.
|
|
2
|
-
|
|
3
|
-
const isTty = process.stdout.isTTY;
|
|
4
|
-
const noColor = !!process.env.NO_COLOR || !isTty;
|
|
5
|
-
|
|
6
|
-
function wrap(open, close) {
|
|
7
|
-
return (s) => (noColor ? String(s) : `\x1b[${open}m${s}\x1b[${close}m`);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const c = {
|
|
11
|
-
bold: wrap(1, 22),
|
|
12
|
-
dim: wrap(2, 22),
|
|
13
|
-
red: wrap(31, 39),
|
|
14
|
-
green: wrap(32, 39),
|
|
15
|
-
yellow: wrap(33, 39),
|
|
16
|
-
blue: wrap(34, 39),
|
|
17
|
-
magenta: wrap(35, 39),
|
|
18
|
-
cyan: wrap(36, 39),
|
|
19
|
-
gray: wrap(90, 39),
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function divider() {
|
|
23
|
-
const w = process.stdout.columns || 60;
|
|
24
|
-
return c.gray("─".repeat(Math.min(60, w)));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function turn(n) {
|
|
28
|
-
return c.gray(`turn ${n}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function toolHeader(name, args) {
|
|
32
|
-
// Format args compactly. If any value is huge, truncate it.
|
|
33
|
-
const compact = JSON.stringify(args);
|
|
34
|
-
const trimmed = compact.length > 120 ? compact.slice(0, 117) + "..." : compact;
|
|
35
|
-
return `${c.cyan(c.bold(name))}${c.gray("(")}${c.gray(trimmed)}${c.gray(")")}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function toolResult(text, ok = true) {
|
|
39
|
-
const prefix = ok ? c.green(" ✓ ") : c.red(" ✗ ");
|
|
40
|
-
// First line bold-ish, then dim continuation
|
|
41
|
-
const lines = text.split("\n");
|
|
42
|
-
const head = lines[0].slice(0, 200);
|
|
43
|
-
const rest = lines.slice(1, 6).join("\n").slice(0, 600);
|
|
44
|
-
return `${prefix}${head}${rest ? "\n" + c.dim(rest) : ""}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function assistant(text) {
|
|
48
|
-
// Indent each line for visual separation from tool calls
|
|
49
|
-
return text.split("\n").map((l) => ` ${l}`).join("\n");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function errorLine(msg) {
|
|
53
|
-
return `${c.red(c.bold("Error:"))} ${msg}`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function note(msg) {
|
|
57
|
-
return c.dim(msg);
|
|
58
|
-
}
|
|
1
|
+
// ANSI helpers — no chalk dependency.
|
|
2
|
+
|
|
3
|
+
const isTty = process.stdout.isTTY;
|
|
4
|
+
const noColor = !!process.env.NO_COLOR || !isTty;
|
|
5
|
+
|
|
6
|
+
function wrap(open, close) {
|
|
7
|
+
return (s) => (noColor ? String(s) : `\x1b[${open}m${s}\x1b[${close}m`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const c = {
|
|
11
|
+
bold: wrap(1, 22),
|
|
12
|
+
dim: wrap(2, 22),
|
|
13
|
+
red: wrap(31, 39),
|
|
14
|
+
green: wrap(32, 39),
|
|
15
|
+
yellow: wrap(33, 39),
|
|
16
|
+
blue: wrap(34, 39),
|
|
17
|
+
magenta: wrap(35, 39),
|
|
18
|
+
cyan: wrap(36, 39),
|
|
19
|
+
gray: wrap(90, 39),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function divider() {
|
|
23
|
+
const w = process.stdout.columns || 60;
|
|
24
|
+
return c.gray("─".repeat(Math.min(60, w)));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function turn(n) {
|
|
28
|
+
return c.gray(`turn ${n}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function toolHeader(name, args) {
|
|
32
|
+
// Format args compactly. If any value is huge, truncate it.
|
|
33
|
+
const compact = JSON.stringify(args);
|
|
34
|
+
const trimmed = compact.length > 120 ? compact.slice(0, 117) + "..." : compact;
|
|
35
|
+
return `${c.cyan(c.bold(name))}${c.gray("(")}${c.gray(trimmed)}${c.gray(")")}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function toolResult(text, ok = true) {
|
|
39
|
+
const prefix = ok ? c.green(" ✓ ") : c.red(" ✗ ");
|
|
40
|
+
// First line bold-ish, then dim continuation
|
|
41
|
+
const lines = text.split("\n");
|
|
42
|
+
const head = lines[0].slice(0, 200);
|
|
43
|
+
const rest = lines.slice(1, 6).join("\n").slice(0, 600);
|
|
44
|
+
return `${prefix}${head}${rest ? "\n" + c.dim(rest) : ""}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function assistant(text) {
|
|
48
|
+
// Indent each line for visual separation from tool calls
|
|
49
|
+
return text.split("\n").map((l) => ` ${l}`).join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function errorLine(msg) {
|
|
53
|
+
return `${c.red(c.bold("Error:"))} ${msg}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function note(msg) {
|
|
57
|
+
return c.dim(msg);
|
|
58
|
+
}
|