aether-code 0.43.0 → 0.43.1
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 +6 -4
- package/package.json +4 -2
- package/scripts/postinstall.js +182 -0
- package/skills/adult-creative-writing.md +60 -60
- package/skills/debugging.md +51 -51
- package/skills/game-modding.md +73 -73
- package/skills/reverse-engineering.md +41 -41
- package/skills/scraping-automation.md +77 -77
- package/skills/security-research.md +67 -67
- package/src/agent.js +168 -267
- package/src/api.js +22 -32
- package/src/box-input.js +141 -36
- package/src/config.js +38 -38
- package/src/diff.js +49 -49
- package/src/ink-input.js +91 -91
- package/src/mcp-cli.js +94 -94
- package/src/mcp-registry.js +266 -266
- package/src/mcp.js +259 -260
- package/src/menu.js +83 -83
- package/src/render.js +288 -254
- package/src/repl.js +408 -444
- package/src/setup.js +6 -8
- package/src/tools.js +16 -393
- package/src/update-check.js +64 -7
- package/src/project-context.js +0 -712
- package/src/sessions.js +0 -167
- package/src/version.js +0 -15
package/src/sessions.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
// Session persistence. Saves conversation state to ~/.aether/sessions/ so
|
|
2
|
-
// users can close the terminal, come back tomorrow, and resume exactly
|
|
3
|
-
// where they left off. Auto-saves after every agent turn.
|
|
4
|
-
|
|
5
|
-
import fs from "node:fs";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import crypto from "node:crypto";
|
|
9
|
-
|
|
10
|
-
const SESSIONS_DIR = path.join(os.homedir(), ".aether", "sessions");
|
|
11
|
-
const MAX_SESSIONS = 50;
|
|
12
|
-
const STALE_DAYS = 14;
|
|
13
|
-
|
|
14
|
-
function ensureDir() {
|
|
15
|
-
fs.mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function cwdHash(cwd) {
|
|
19
|
-
return crypto.createHash("sha256").update(cwd.toLowerCase()).digest("hex").slice(0, 12);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function sessionPath(id) {
|
|
23
|
-
return path.join(SESSIONS_DIR, `${id}.json`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function generateSessionId(cwd) {
|
|
27
|
-
const hash = cwdHash(cwd);
|
|
28
|
-
const ts = Date.now().toString(36);
|
|
29
|
-
return `${hash}-${ts}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function saveSession(session) {
|
|
33
|
-
ensureDir();
|
|
34
|
-
const data = {
|
|
35
|
-
id: session.id,
|
|
36
|
-
cwd: session.cwd,
|
|
37
|
-
model: session.model ?? null,
|
|
38
|
-
modelName: session.modelName ?? "Aether Core",
|
|
39
|
-
messages: session.messages ?? [],
|
|
40
|
-
credits: session.credits ?? 0,
|
|
41
|
-
tokensIn: session.tokensIn ?? 0,
|
|
42
|
-
tokensOut: session.tokensOut ?? 0,
|
|
43
|
-
createdAt: session.createdAt ?? new Date().toISOString(),
|
|
44
|
-
updatedAt: new Date().toISOString(),
|
|
45
|
-
summary: session.summary ?? "",
|
|
46
|
-
turnCount: session.turnCount ?? 0,
|
|
47
|
-
};
|
|
48
|
-
const filePath = sessionPath(data.id);
|
|
49
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
50
|
-
try { fs.chmodSync(filePath, 0o600); } catch { /* windows */ }
|
|
51
|
-
pruneOldSessions();
|
|
52
|
-
return data;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function loadSession(id) {
|
|
56
|
-
const filePath = sessionPath(id);
|
|
57
|
-
try {
|
|
58
|
-
const raw = fs.readFileSync(filePath, "utf8");
|
|
59
|
-
return JSON.parse(raw);
|
|
60
|
-
} catch {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function deleteSession(id) {
|
|
66
|
-
try {
|
|
67
|
-
fs.unlinkSync(sessionPath(id));
|
|
68
|
-
return true;
|
|
69
|
-
} catch {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function listSessions(filterCwd) {
|
|
75
|
-
ensureDir();
|
|
76
|
-
let files;
|
|
77
|
-
try {
|
|
78
|
-
files = fs.readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
79
|
-
} catch {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
const sessions = [];
|
|
83
|
-
for (const f of files) {
|
|
84
|
-
try {
|
|
85
|
-
const raw = fs.readFileSync(path.join(SESSIONS_DIR, f), "utf8");
|
|
86
|
-
const data = JSON.parse(raw);
|
|
87
|
-
if (filterCwd && data.cwd?.toLowerCase() !== filterCwd.toLowerCase()) continue;
|
|
88
|
-
sessions.push({
|
|
89
|
-
id: data.id,
|
|
90
|
-
cwd: data.cwd,
|
|
91
|
-
model: data.model,
|
|
92
|
-
modelName: data.modelName,
|
|
93
|
-
summary: data.summary,
|
|
94
|
-
turnCount: data.turnCount ?? 0,
|
|
95
|
-
messageCount: data.messages?.length ?? 0,
|
|
96
|
-
credits: data.credits ?? 0,
|
|
97
|
-
createdAt: data.createdAt,
|
|
98
|
-
updatedAt: data.updatedAt,
|
|
99
|
-
});
|
|
100
|
-
} catch {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
sessions.sort((a, b) => (b.updatedAt || "").localeCompare(a.updatedAt || ""));
|
|
105
|
-
return sessions;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function findRecentSession(cwd, maxAgeMs = 24 * 60 * 60 * 1000) {
|
|
109
|
-
const sessions = listSessions(cwd);
|
|
110
|
-
if (sessions.length === 0) return null;
|
|
111
|
-
const newest = sessions[0];
|
|
112
|
-
if (!newest.updatedAt) return null;
|
|
113
|
-
const age = Date.now() - new Date(newest.updatedAt).getTime();
|
|
114
|
-
if (age > maxAgeMs) return null;
|
|
115
|
-
if (newest.messageCount < 2) return null;
|
|
116
|
-
return newest;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function pruneOldSessions() {
|
|
120
|
-
let files;
|
|
121
|
-
try {
|
|
122
|
-
files = fs.readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
123
|
-
} catch {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
if (files.length <= MAX_SESSIONS) return;
|
|
127
|
-
const entries = [];
|
|
128
|
-
for (const f of files) {
|
|
129
|
-
try {
|
|
130
|
-
const stat = fs.statSync(path.join(SESSIONS_DIR, f));
|
|
131
|
-
entries.push({ file: f, mtime: stat.mtimeMs });
|
|
132
|
-
} catch {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
entries.sort((a, b) => b.mtime - a.mtime);
|
|
137
|
-
const cutoff = Date.now() - STALE_DAYS * 24 * 60 * 60 * 1000;
|
|
138
|
-
for (const e of entries.slice(MAX_SESSIONS)) {
|
|
139
|
-
if (e.mtime < cutoff) {
|
|
140
|
-
try { fs.unlinkSync(path.join(SESSIONS_DIR, e.file)); } catch { /* ignore */ }
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function extractSummary(messages) {
|
|
146
|
-
if (!messages || messages.length === 0) return "";
|
|
147
|
-
const firstUser = messages.find((m) => m.role === "user");
|
|
148
|
-
if (!firstUser || typeof firstUser.content !== "string") return "";
|
|
149
|
-
const text = firstUser.content
|
|
150
|
-
.replace(/\[environment\][\s\S]*?\[\/environment\]\s*/g, "")
|
|
151
|
-
.replace(/\[project\][\s\S]*?\[\/project\]\s*/g, "")
|
|
152
|
-
.replace(/=== LOADED SKILLS[\s\S]*?---\s*/g, "")
|
|
153
|
-
.trim();
|
|
154
|
-
return text.length > 120 ? text.slice(0, 117) + "..." : text;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function formatAge(isoDate) {
|
|
158
|
-
if (!isoDate) return "unknown";
|
|
159
|
-
const ms = Date.now() - new Date(isoDate).getTime();
|
|
160
|
-
const mins = Math.floor(ms / 60_000);
|
|
161
|
-
if (mins < 1) return "just now";
|
|
162
|
-
if (mins < 60) return `${mins}m ago`;
|
|
163
|
-
const hours = Math.floor(mins / 60);
|
|
164
|
-
if (hours < 24) return `${hours}h ago`;
|
|
165
|
-
const days = Math.floor(hours / 24);
|
|
166
|
-
return `${days}d ago`;
|
|
167
|
-
}
|
package/src/version.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
let cached;
|
|
6
|
-
export function getVersion() {
|
|
7
|
-
if (cached) return cached;
|
|
8
|
-
try {
|
|
9
|
-
const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
10
|
-
cached = JSON.parse(fs.readFileSync(pkgPath, "utf8")).version || "0";
|
|
11
|
-
} catch {
|
|
12
|
-
cached = "0";
|
|
13
|
-
}
|
|
14
|
-
return cached;
|
|
15
|
-
}
|