aether-code 0.6.0 → 0.6.2

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.
@@ -18,7 +18,7 @@ import { generateAndApprovePlan } from "../src/plan.js";
18
18
  import { listSessions, loadSession, loadMostRecent, deleteSession, truncatePreview, sessionsDir } from "../src/sessions.js";
19
19
  import { c, errorLine, divider } from "../src/render.js";
20
20
 
21
- const VERSION = "0.6.0";
21
+ const VERSION = "0.6.2";
22
22
 
23
23
  const HELP = `${c.bold("aether")} — uncensored AI coding agent
24
24
 
@@ -222,6 +222,9 @@ async function main() {
222
222
  sessionId: resumed?.id, // reuse the prior id when resuming
223
223
  sessionCreatedAt: resumed?.createdAt,
224
224
  saveSessions: !args.flags.noSave,
225
+ priorTotalCredits: resumed?.totalCredits ?? 0,
226
+ priorTotalIn: resumed?.totalIn ?? 0,
227
+ priorTotalOut: resumed?.totalOut ?? 0,
225
228
  });
226
229
 
227
230
  console.log("\n" + divider());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aether-code",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Uncensored AI coding agent for your terminal. Type `aether` to launch the interactive REPL — like Claude Code, with no refusal layer.",
5
5
  "homepage": "https://trynoguard.com",
6
6
  "repository": {
package/src/agent.js CHANGED
@@ -23,10 +23,16 @@ export async function runAgent({
23
23
  sessionId, // existing id (resume) or null (new)
24
24
  saveSessions = true, // disable with --no-save
25
25
  sessionCreatedAt, // ISO from prior session, or now
26
+ // Prior cumulative totals from a resumed session — used so the saved
27
+ // session reflects lifetime usage, not just this invocation.
28
+ priorTotalCredits = 0,
29
+ priorTotalIn = 0,
30
+ priorTotalOut = 0,
26
31
  }) {
27
32
  const messages = priorMessages
28
33
  ? [...priorMessages, { role: "user", content: initialPrompt }]
29
34
  : [{ role: "user", content: initialPrompt }];
35
+ // Per-invocation counters (used in the result summary).
30
36
  let totalCredits = 0;
31
37
  let totalIn = 0;
32
38
  let totalOut = 0;
@@ -46,9 +52,10 @@ export async function runAgent({
46
52
  id: activeSessionId,
47
53
  createdAt,
48
54
  cwd,
49
- totalCredits,
50
- totalIn,
51
- totalOut,
55
+ // Save cumulative lifetime totals so /sessions show reflects all runs.
56
+ totalCredits: priorTotalCredits + totalCredits,
57
+ totalIn: priorTotalIn + totalIn,
58
+ totalOut: priorTotalOut + totalOut,
52
59
  firstUserMessage,
53
60
  messages,
54
61
  });
@@ -106,8 +113,24 @@ export async function runAgent({
106
113
  throw err;
107
114
  }
108
115
 
109
- // End-of-turn: newline + cost meter
110
- if (textOpened) process.stdout.write("\n");
116
+ // End-of-turn: handle three render cases for the assistant message.
117
+ //
118
+ // 1. Deltas streamed normally → close the line we opened with onDelta.
119
+ // 2. No deltas fired BUT the final accumulated content has text → safety
120
+ // net: print it retroactively (defends against any SSE buffering
121
+ // race we haven't seen but could exist).
122
+ // 3. No deltas, no content, no tool calls → the model emitted only
123
+ // internal/whitespace tokens. Show a placeholder so the user isn't
124
+ // confused by a silent turn that still consumed credits.
125
+ const finalText = res.message.content ?? "";
126
+ const hasToolCalls = (res.message.tool_calls?.length ?? 0) > 0;
127
+ if (textOpened) {
128
+ process.stdout.write("\n");
129
+ } else if (finalText.length > 0) {
130
+ process.stdout.write(assistantPrefix() + " " + finalText + "\n");
131
+ } else if (!hasToolCalls) {
132
+ process.stdout.write(assistantPrefix() + " " + c.dim("(empty response)") + "\n");
133
+ }
111
134
  totalCredits += res.creditsCharged ?? 0;
112
135
  totalIn += res.usage?.prompt_tokens ?? 0;
113
136
  totalOut += res.usage?.completion_tokens ?? 0;
package/src/repl.js CHANGED
@@ -16,7 +16,7 @@ import { runSetup } from "./setup.js";
16
16
  import { listSessions, truncatePreview } from "./sessions.js";
17
17
  import { c, errorLine, banner, statusLine } from "./render.js";
18
18
 
19
- const VERSION = "0.6.0";
19
+ const VERSION = "0.6.2";
20
20
  const MODEL_NAME = "Aether Core";
21
21
 
22
22
  const SHORTCUTS = `
@@ -135,6 +135,11 @@ export async function runRepl({ cwd: initialCwd, autoYes: initialAutoYes, maxTur
135
135
  maxTurns: state.maxTurns,
136
136
  sessionId: state.sessionId,
137
137
  sessionCreatedAt: state.sessionCreatedAt,
138
+ // state.session* are cumulative — pass them so saved sessions
139
+ // reflect lifetime usage across both resume and in-REPL turns.
140
+ priorTotalCredits: state.sessionCredits,
141
+ priorTotalIn: state.sessionIn,
142
+ priorTotalOut: state.sessionOut,
138
143
  });
139
144
 
140
145
  // Capture the session id from the first turn so we keep appending to it