aether-code 0.24.0 → 0.25.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.
@@ -9,6 +9,8 @@
9
9
 
10
10
  import process from "node:process";
11
11
  import path from "node:path";
12
+ import os from "node:os";
13
+ import fs from "node:fs";
12
14
  import { runAgent } from "../src/agent.js";
13
15
  import { runRepl } from "../src/repl.js";
14
16
  import { runSetup } from "../src/setup.js";
@@ -26,7 +28,7 @@ import {
26
28
  import readline from "node:readline";
27
29
  import { c, errorLine, divider, setTerminalTitle } from "../src/render.js";
28
30
 
29
- const VERSION = "0.24.0";
31
+ const VERSION = "0.25.0";
30
32
 
31
33
  /**
32
34
  * Try to start MCP servers from ~/.aether/mcp.json. Returns a started
@@ -132,6 +134,18 @@ function die(msg, code = 1) {
132
134
  process.exit(code);
133
135
  }
134
136
 
137
+ // True for Windows system folders we should never write a user's project into.
138
+ function isSystemDir(p) {
139
+ const low = p.toLowerCase().replace(/[\\/]+$/, "").replace(/\//g, "\\");
140
+ return (
141
+ low.endsWith("\\windows\\system32") ||
142
+ low.endsWith("\\windows\\syswow64") ||
143
+ low.endsWith("\\windows") ||
144
+ low.endsWith("\\system32") ||
145
+ /\\program files( \(x86\))?$/.test(low)
146
+ );
147
+ }
148
+
135
149
  async function main() {
136
150
  const args = parseArgs(process.argv.slice(2));
137
151
  setTerminalTitle("Aether");
@@ -145,7 +159,16 @@ async function main() {
145
159
  return;
146
160
  }
147
161
 
148
- const cwd = args.flags.cwd ? path.resolve(args.flags.cwd) : process.cwd();
162
+ // Where files land. If the user didn't pass --cwd and we were launched from a
163
+ // Windows system folder (admin cmd opens in C:\WINDOWS\system32), don't dump
164
+ // their project there — they'd never find it. Work in the Desktop instead.
165
+ let cwd = args.flags.cwd ? path.resolve(args.flags.cwd) : process.cwd();
166
+ let redirectedFrom = null;
167
+ if (!args.flags.cwd && isSystemDir(cwd)) {
168
+ const desktop = path.join(os.homedir(), "Desktop");
169
+ const target = fs.existsSync(desktop) ? desktop : os.homedir();
170
+ if (target.toLowerCase() !== cwd.toLowerCase()) { redirectedFrom = cwd; cwd = target; }
171
+ }
149
172
  // Skip-permissions by DEFAULT (like `claude --dangerously-skip-permissions`):
150
173
  // auto-approve writes/shell and don't sandbox file paths, so the agent can
151
174
  // just build. Opt back in with --review (y/N before each action) and
@@ -184,6 +207,10 @@ async function main() {
184
207
  if (!prompt) {
185
208
  if (cwd !== process.cwd()) process.chdir(cwd);
186
209
  const mcpManager = await bootMcp();
210
+ if (redirectedFrom) {
211
+ console.log(c.gray(`Note: launched from a system folder (${redirectedFrom}).`));
212
+ console.log(c.gray(`Your files will be saved to ${c.cyan(cwd)} so you can find them. Use ${c.cyan("--cwd <path>")} or ${c.cyan("/cwd")} to change.`));
213
+ }
187
214
  await runRepl({ cwd, autoYes, unsafePaths, maxTurns, mcpManager });
188
215
  return;
189
216
  }
@@ -198,6 +225,7 @@ async function main() {
198
225
  console.log(divider());
199
226
  const modeLabel = autoYes && unsafePaths ? " · skip-permissions" : `${autoYes ? " · auto-yes" : " · review"}${unsafePaths ? "" : " · sandboxed"}`;
200
227
  console.log(c.magenta(c.bold("aether-code")) + c.gray(` · cwd ${cwd}${modeLabel}`));
228
+ if (redirectedFrom) console.log(c.gray(`(launched from ${redirectedFrom} — saving to ${cwd} instead)`));
201
229
  console.log(c.gray(`task: `) + prompt);
202
230
  console.log(divider());
203
231
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aether-code",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
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
5
  "homepage": "https://trynoguard.com",
6
6
  "repository": {
package/src/agent.js CHANGED
@@ -80,6 +80,9 @@ export async function runAgent({
80
80
  // Loop guard: count identical (name+args) tool calls across the whole run so a
81
81
  // confused model can't burn turns re-running the same call (e.g. glob *.md x9).
82
82
  const callCounts = new Map();
83
+ // Files the run created/edited, shown in a summary at the end so the user
84
+ // knows exactly what was produced and where to find it.
85
+ const filesTouched = new Map();
83
86
 
84
87
  for (let i = 0; i < maxTurns; i++) {
85
88
  // No turn header and no leading blank here — each step (assistant text and
@@ -167,6 +170,12 @@ export async function runAgent({
167
170
 
168
171
  const toolCalls = res.message.tool_calls ?? [];
169
172
  if (toolCalls.length === 0) {
173
+ if (filesTouched.size) {
174
+ console.log("\n" + c.bold("Files") + c.gray(` in ${cwd}`));
175
+ for (const [p, action] of filesTouched) {
176
+ console.log(" " + c.green("●") + " " + p + c.gray(` — ${action}`));
177
+ }
178
+ }
170
179
  return { ok: true, totalCredits, totalIn, totalOut, turns: i + 1, balance: lastBalance, messages };
171
180
  }
172
181
 
@@ -218,6 +227,10 @@ export async function runAgent({
218
227
  if (call.function.name === "read_file" || call.function.name === "edit_file" || call.function.name === "write_file") {
219
228
  if (typeof args.path === "string") referencedPaths.push(args.path);
220
229
  }
230
+ if (result.ok && typeof args.path === "string" && (call.function.name === "write_file" || call.function.name === "edit_file")) {
231
+ const rel = path.relative(cwd, path.resolve(cwd, args.path)) || args.path;
232
+ filesTouched.set(rel, call.function.name === "write_file" ? "created" : "edited");
233
+ }
221
234
  const summary = toolSummary(call.function.name, result);
222
235
  if (summary) console.log(summary);
223
236
 
package/src/render.js CHANGED
@@ -63,7 +63,7 @@ export function toolLabel(name, args) {
63
63
  case "write_file": return `${verb("write")} ${arg(a.path)}`;
64
64
  case "edit_file": return `${verb("edit")} ${arg(a.path)}`;
65
65
  case "list_dir": return `${verb("list")} ${arg(a.path)}`;
66
- case "glob_files": return `${verb("glob")} ${arg(a.pattern)}`;
66
+ case "glob_files": return `${verb("find")} ${arg(a.pattern)}`;
67
67
  case "search_files": return `${verb("search")} ${arg(`/${a.pattern}/ in ${a.path ?? "."}`)}`;
68
68
  case "run_shell": return `${verb("run")} ${arg(a.command)}`;
69
69
  case "web_search": return `${verb("search web")} ${arg(JSON.stringify(a.query ?? ""))}`;
package/src/repl.js CHANGED
@@ -16,7 +16,7 @@ import { c, errorLine, box } from "./render.js";
16
16
  import { checkForUpdate } from "./update-check.js";
17
17
  import { promptBox, EXIT_SIGNAL } from "./box-input.js";
18
18
 
19
- const VERSION = "0.24.0";
19
+ const VERSION = "0.25.0";
20
20
  const MODEL_NAME = "Aether Core";
21
21
 
22
22
  const SHORTCUTS = `