aether-code 0.33.2 → 0.33.3

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.
@@ -28,7 +28,7 @@ import {
28
28
  import readline from "node:readline";
29
29
  import { c, errorLine, divider, setTerminalTitle } from "../src/render.js";
30
30
 
31
- const VERSION = "0.33.2";
31
+ const VERSION = "0.33.3";
32
32
 
33
33
  /**
34
34
  * Try to start MCP servers from ~/.aether/mcp.json. Returns a started
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aether-code",
3
- "version": "0.33.2",
3
+ "version": "0.33.3",
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/box-input.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Minimal prompt input — raw-mode, cmd.exe-safe.
2
- // No box/border — just a bare "> " prompt like Claude Code.
2
+ // Bare "> " prompt with bottom status bar, matching Claude Code's layout.
3
3
  //
4
4
  // Features:
5
5
  // - Ctrl+V / Alt+V: paste image from clipboard
@@ -23,7 +23,6 @@ const HIDE = "\x1b[?25l";
23
23
  const SHOW = "\x1b[?25h";
24
24
  const INV = (s) => `\x1b[7m${s}\x1b[27m`;
25
25
 
26
- // Save clipboard image to a temp file. Returns the file path or null.
27
26
  function grabClipboardImage() {
28
27
  const tmpFile = path.join(os.tmpdir(), `aether-paste-${Date.now()}.png`);
29
28
 
@@ -62,7 +61,7 @@ function grabClipboardImage() {
62
61
  return null;
63
62
  }
64
63
 
65
- export function promptBox({ history = [], placeholder = "Message Aether…" } = {}) {
64
+ export function promptBox({ history = [], placeholder = "Message Aether...", mode = "review" } = {}) {
66
65
  return new Promise((resolve) => {
67
66
  if (!process.stdin.isTTY) {
68
67
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -79,16 +78,15 @@ export function promptBox({ history = [], placeholder = "Message Aether…" } =
79
78
  let lastSigint = 0;
80
79
  const clipImages = [];
81
80
 
82
- const termW = () => Math.max(30, (process.stdout.columns || 80) - 4);
81
+ const termW = () => Math.max(30, (process.stdout.columns || 80) - 2);
83
82
 
84
83
  const draw = (first) => {
85
84
  const W = termW();
86
85
  if (!first) process.stdout.write(`\x1b[${drawn}A`);
87
86
  process.stdout.write("\x1b[J");
88
87
 
89
- // Horizontal scroll
90
- const prefix = c.cyan("> ");
91
- const prefixLen = 2; // "> " visible chars
88
+ const prefixStr = "> ";
89
+ const prefixLen = 2;
92
90
  const maxVisible = W - prefixLen;
93
91
  const start = pos > maxVisible ? pos - maxVisible : 0;
94
92
  const view = buf.slice(start, start + maxVisible);
@@ -112,12 +110,16 @@ export function promptBox({ history = [], placeholder = "Message Aether…" } =
112
110
  content = s;
113
111
  }
114
112
 
115
- // Prompt line — bare "> " like Claude Code
116
- const promptLine = prefix + content;
113
+ // Bare prompt — just "> " like Claude Code
114
+ const promptLine = c.dim(prefixStr) + content;
117
115
 
118
- // Status bar — mode + shortcuts, like Claude's bottom bar
119
- const imgHint = clipImages.length > 0 ? " · " + c.cyan("images queued") : "";
120
- const statusBar = c.dim(" ? for help · @file for images · Alt+V paste") + imgHint;
116
+ // Bottom status bar — matches Claude's "manual mode on · ? for shortcuts · + for agents"
117
+ const imgNote = clipImages.length > 0 ? c.cyan(" images queued") + c.dim(" \xB7 ") : "";
118
+ const statusBar = c.dim(
119
+ mode + " mode" +
120
+ " \xB7 " + "? for shortcuts" +
121
+ " \xB7 " + "@file for images",
122
+ ) + imgNote;
121
123
 
122
124
  process.stdout.write(promptLine + "\n" + statusBar + "\n");
123
125
  drawn = 2;
@@ -162,7 +164,6 @@ export function promptBox({ history = [], placeholder = "Message Aether…" } =
162
164
  }
163
165
  if (key.ctrl && k === "d") return finish(buf.length === 0 ? EXIT_SIGNAL : buf);
164
166
 
165
- // Alt+V or Ctrl+V: paste image from clipboard
166
167
  if ((key.meta && k === "v") || (key.ctrl && k === "v")) {
167
168
  const imgPath = grabClipboardImage();
168
169
  if (imgPath) {
package/src/repl.js CHANGED
@@ -9,7 +9,7 @@ import { c, errorLine } from "./render.js";
9
9
  import { autoUpdate } from "./update-check.js";
10
10
  import { promptBox, EXIT_SIGNAL } from "./box-input.js";
11
11
 
12
- const VERSION = "0.33.2";
12
+ const VERSION = "0.33.3";
13
13
  const MODEL_NAME = "Aether Core";
14
14
 
15
15
  const MODEL_ALIASES = {
@@ -49,7 +49,6 @@ export async function runRepl({ cwd: initialCwd, autoYes: initialAutoYes, unsafe
49
49
  sessionOut: 0,
50
50
  };
51
51
 
52
- // Auto-update + balance fetch in parallel — zero startup latency added.
53
52
  const updatePromise = autoUpdate().catch(() => null);
54
53
 
55
54
  let needsSetup = false;
@@ -86,7 +85,7 @@ export async function runRepl({ cwd: initialCwd, autoYes: initialAutoYes, unsafe
86
85
  const inputHistory = [];
87
86
 
88
87
  while (true) {
89
- const raw = await promptBox({ history: inputHistory });
88
+ const raw = await promptBox({ history: inputHistory, mode: state.autoYes ? "auto-yes" : "review" });
90
89
  if (raw === EXIT_SIGNAL) { console.log(c.gray("bye.")); return; }
91
90
  const line = (raw ?? "").trim();
92
91
  if (!line) continue;
@@ -96,7 +95,6 @@ export async function runRepl({ cwd: initialCwd, autoYes: initialAutoYes, unsafe
96
95
  if (line.startsWith("/") || line === "?") {
97
96
  const handled = await handleSlash(line, state);
98
97
  if (handled === "exit") return;
99
- printStatusLine(state);
100
98
  continue;
101
99
  }
102
100
 
@@ -120,8 +118,6 @@ export async function runRepl({ cwd: initialCwd, autoYes: initialAutoYes, unsafe
120
118
  if (!result.ok && result.error) {
121
119
  console.log("\n" + errorLine(result.error.message || String(result.error)));
122
120
  }
123
-
124
- printStatusLine(state);
125
121
  }
126
122
  }
127
123
 
@@ -169,7 +165,7 @@ async function handleSlash(line, state) {
169
165
  try {
170
166
  process.chdir(next);
171
167
  state.cwd = next;
172
- console.log(c.gray(`cwd → ${state.cwd}`));
168
+ console.log(c.gray(`cwd -> ${state.cwd}`));
173
169
  } catch (err) {
174
170
  console.log(errorLine(err.message));
175
171
  }
@@ -201,7 +197,7 @@ async function handleSlash(line, state) {
201
197
  state.modelName = MODEL_ALIASES[key].name;
202
198
  const premium = state.model !== null;
203
199
  console.log(
204
- c.gray(`model → ${c.cyan(state.modelName)}`) +
200
+ c.gray(`model -> ${c.cyan(state.modelName)}`) +
205
201
  (premium ? c.gray(" (premium — needs purchased credits, else falls back to Core)") : ""),
206
202
  );
207
203
  } else {
@@ -215,35 +211,36 @@ async function handleSlash(line, state) {
215
211
  return null;
216
212
  }
217
213
 
218
- /* ───────── banner + status ───────── */
214
+ /* ───────── banner ───────── */
219
215
 
220
216
  const shortenPath = (p, max) => (p.length <= max ? p : "..." + p.slice(p.length - max + 3));
221
217
 
222
218
  function printBanner(state) {
223
219
  const credits = state.balance != null ? `${state.balance.toLocaleString()} credits` : "";
224
- const mode = state.autoYes ? (state.unsafePaths ? "skip-permissions" : "auto-yes") : "review";
220
+ const plan = state.plan && state.plan !== "FREE" ? state.plan : "";
221
+
222
+ // Block logo — CP437-safe colored squares, like Claude Code's logo
223
+ const b1 = c.cyan("\xDB\xDB"); // ██ full blocks
224
+ const b2 = c.blue("\xDB\xDB"); // ██ darker accent
225
+ const gap = " ";
225
226
 
226
- // No boxes — plain text, exactly like Claude Code
227
+ // 3-line logo + text, no boxes — matches Claude Code layout
227
228
  console.log("");
228
229
  console.log(
229
- " " + c.bold(c.cyan("✦")) + " " +
230
+ " " + b1 + " " + b2 + gap +
230
231
  c.bold("Aether Code") + " " + c.dim("v" + VERSION),
231
232
  );
233
+
234
+ const modelParts = [state.modelName];
235
+ if (credits) modelParts.push(credits);
236
+ if (plan) modelParts.push(c.cyan(plan));
232
237
  console.log(
233
- " " + state.modelName +
234
- (credits ? c.dim(" · ") + credits : "") +
235
- (state.plan && state.plan !== "FREE" ? c.dim(" · ") + c.cyan(state.plan) : ""),
238
+ " " + b2 + " " + b1 + gap +
239
+ modelParts.join(c.dim(" \xB7 ")),
236
240
  );
237
- console.log(" " + c.dim(shortenPath(state.cwd, 60)));
238
- }
239
241
 
240
- function printStatusLine(state) {
241
- const parts = [];
242
- parts.push(c.gray(`session: ${state.sessionCredits} cr · ${state.sessionIn}→${state.sessionOut} tokens`));
243
- if (state.balance != null) parts.push(c.gray(`balance: ${state.balance.toLocaleString()}`));
244
- if (state.messages.length > 0) {
245
- parts.push(c.gray(`history: ${state.messages.length} msg${state.messages.length === 1 ? "" : "s"}`));
246
- }
247
- parts.push(c.cyan(state.autoYes ? "auto-yes" : "review"));
248
- console.log(c.dim(parts.join(" · ")));
242
+ console.log(
243
+ " " + b1 + " " + b2 + gap +
244
+ c.dim(shortenPath(state.cwd, 60)),
245
+ );
249
246
  }