@aria-cli/cli 1.0.15 → 1.0.18
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/README.md +56 -0
- package/bin/aria-dev.js +1 -14
- package/bin/aria.js +13 -365
- package/bin/install-owner-lease.js +1 -53
- package/dist/.aria-build-stamp.json +1 -1
- package/package.json +30 -28
- package/dist/repl-cleanup.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# ARIA — Adaptive Reasoning Intelligence Agent
|
|
2
|
+
|
|
3
|
+
A terminal-native AI coding assistant with persistent memory, multi-agent collaboration, and native code intelligence.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g @aria-cli/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js ≥ 20.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
aria # Start interactive session
|
|
17
|
+
aria "fix the login bug" # One-shot task
|
|
18
|
+
aria --daemon # Start background daemon
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **🧠 Persistent Memory** — Remembers context across sessions via Memoria
|
|
24
|
+
- **⚡ Native Code Search** — Rust-powered indexed grep (sub-millisecond)
|
|
25
|
+
- **🔗 LSP Intelligence** — Compiler-accurate go-to-definition, references, hover
|
|
26
|
+
- **🤖 Multi-Agent** — Hatch arions for parallel tasks, delegate across machines
|
|
27
|
+
- **🌐 Mesh Network** — WireGuard-encrypted peer-to-peer agent collaboration
|
|
28
|
+
- **🎨 Rich Terminal UI** — Ink-powered interface with 87 tool renderers
|
|
29
|
+
- **📡 MCP Support** — Connect to any Model Context Protocol server
|
|
30
|
+
|
|
31
|
+
## Packages
|
|
32
|
+
|
|
33
|
+
| Package | Description |
|
|
34
|
+
|---------|-------------|
|
|
35
|
+
| [`@aria-cli/cli`](https://www.npmjs.com/package/@aria-cli/cli) | CLI entry point and terminal UI |
|
|
36
|
+
| [`@aria-cli/aria`](https://www.npmjs.com/package/@aria-cli/aria) | Core runtime, agent loop, orchestration |
|
|
37
|
+
| [`@aria-cli/tools`](https://www.npmjs.com/package/@aria-cli/tools) | 87 built-in tools (fs, shell, web, code search, LSP) |
|
|
38
|
+
| [`@aria-cli/models`](https://www.npmjs.com/package/@aria-cli/models) | LLM provider adapters (Anthropic, OpenAI, etc.) |
|
|
39
|
+
| [`@aria-cli/memoria`](https://www.npmjs.com/package/@aria-cli/memoria) | Persistent memory system (SQLite + vector search) |
|
|
40
|
+
| [`@aria-cli/server`](https://www.npmjs.com/package/@aria-cli/server) | Daemon server, HTTP API, session management |
|
|
41
|
+
| [`@aria-cli/fastripgrep`](https://www.npmjs.com/package/@aria-cli/fastripgrep) | Native Rust indexed code search |
|
|
42
|
+
| [`@aria-cli/wireguard`](https://www.npmjs.com/package/@aria-cli/wireguard) | Native WireGuard mesh networking |
|
|
43
|
+
|
|
44
|
+
## Platform Support
|
|
45
|
+
|
|
46
|
+
| Platform | Architecture | Status |
|
|
47
|
+
|----------|-------------|--------|
|
|
48
|
+
| macOS | arm64 (Apple Silicon) | ✅ |
|
|
49
|
+
| macOS | x64 (Intel) | ✅ |
|
|
50
|
+
| Linux | x64 | ✅ |
|
|
51
|
+
| Linux | arm64 (Graviton, RPi) | ✅ |
|
|
52
|
+
| Windows | x64 | ✅ |
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
package/bin/aria-dev.js
CHANGED
|
@@ -1,15 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ARIA CLI — Development entry point (runs from source, no build needed)
|
|
5
|
-
* Registers tsx loader then delegates to the production entry point.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { register } from "node:module";
|
|
9
|
-
import { pathToFileURL } from "node:url";
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
register("tsx/esm", pathToFileURL("./"));
|
|
13
|
-
} catch {}
|
|
14
|
-
|
|
15
|
-
await import("./aria.js");
|
|
2
|
+
"use strict";import{register as t}from"node:module";import{pathToFileURL as r}from"node:url";try{t("tsx/esm",r("./"))}catch{}await import("./aria.js");
|
package/bin/aria.js
CHANGED
|
@@ -1,366 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* If --max-old-space-size is not set, the script re-execs once
|
|
16
|
-
* with the flag. The re-exec parent does zero application work.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// ── Crash diagnostic infrastructure ─────────────────────────────────
|
|
20
|
-
// Registered before ANY other code so uncaught errors are always captured.
|
|
21
|
-
import { writeFileSync, appendFileSync, mkdirSync } from "node:fs";
|
|
22
|
-
import { join } from "node:path";
|
|
23
|
-
import { homedir } from "node:os";
|
|
24
|
-
import { createHash } from "node:crypto";
|
|
25
|
-
import { RESTART_KIND_ENV, RESUME_SESSION_ENV } from "@aria-cli/types";
|
|
26
|
-
import { withReplCleanup } from "../dist/repl-cleanup.js";
|
|
27
|
-
import { installOwnerLease } from "./install-owner-lease.js";
|
|
28
|
-
|
|
29
|
-
function writeCrashReport(type, error) {
|
|
30
|
-
try {
|
|
31
|
-
const crashDir = join(homedir(), ".aria", "crash-reports");
|
|
32
|
-
mkdirSync(crashDir, { recursive: true });
|
|
33
|
-
const sessionId = process.env[RESUME_SESSION_ENV] || "unknown";
|
|
34
|
-
const mem = process.memoryUsage();
|
|
35
|
-
const report = {
|
|
36
|
-
timestamp: new Date().toISOString(),
|
|
37
|
-
sessionId,
|
|
38
|
-
type,
|
|
39
|
-
error: {
|
|
40
|
-
message: error?.message ?? String(error),
|
|
41
|
-
stack: error?.stack ?? undefined,
|
|
42
|
-
name: error?.name ?? undefined,
|
|
43
|
-
},
|
|
44
|
-
process: {
|
|
45
|
-
pid: process.pid,
|
|
46
|
-
heapUsedMb: Math.round((mem.heapUsed / 1024 / 1024) * 100) / 100,
|
|
47
|
-
rssMb: Math.round((mem.rss / 1024 / 1024) * 100) / 100,
|
|
48
|
-
uptime: Math.round(process.uptime()),
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
writeFileSync(join(crashDir, "latest.json"), JSON.stringify(report, null, 2));
|
|
52
|
-
|
|
53
|
-
// Also append to the central error events journal (CEH integration)
|
|
54
|
-
const ariaDir = join(homedir(), ".aria");
|
|
55
|
-
const errorEventsPath = join(ariaDir, "error-events.jsonl");
|
|
56
|
-
const firstFrame = error?.stack?.split("\n")[1]?.trim() ?? "";
|
|
57
|
-
const bucketedTime = Math.floor(Date.now() / 10000);
|
|
58
|
-
const errorId = createHash("sha256")
|
|
59
|
-
.update(`${error?.message ?? ""}|${firstFrame}|${bucketedTime}`)
|
|
60
|
-
.digest("hex")
|
|
61
|
-
.slice(0, 12);
|
|
62
|
-
|
|
63
|
-
const causeChain = [];
|
|
64
|
-
let cause = error?.cause;
|
|
65
|
-
const seen = new Set();
|
|
66
|
-
while (cause instanceof Error && !seen.has(cause)) {
|
|
67
|
-
seen.add(cause);
|
|
68
|
-
causeChain.push(`${cause.name}: ${cause.message}`);
|
|
69
|
-
cause = cause.cause;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const relatedFiles = [];
|
|
73
|
-
if (error?.stack) {
|
|
74
|
-
for (const line of error.stack.split("\n")) {
|
|
75
|
-
const match = line.match(/\((?:file:\/\/)?([^:)]+):\d+:\d+\)/);
|
|
76
|
-
if (match?.[1]?.includes("packages/") && !match[1].includes("node_modules")) {
|
|
77
|
-
relatedFiles.push(match[1]);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const errorEntry = {
|
|
83
|
-
id: `crash-${errorId}`,
|
|
84
|
-
timestamp: report.timestamp,
|
|
85
|
-
severity: 0,
|
|
86
|
-
category: "crash",
|
|
87
|
-
domain: "cli",
|
|
88
|
-
name: error?.name ?? "UnknownError",
|
|
89
|
-
message: error?.message ?? String(error),
|
|
90
|
-
code: error?.code ?? undefined,
|
|
91
|
-
stackTrace: error?.stack,
|
|
92
|
-
causeChain,
|
|
93
|
-
recoverable: false,
|
|
94
|
-
state: {
|
|
95
|
-
environment: { nodeVersion: process.version, platform: process.platform },
|
|
96
|
-
processInfo: report.process,
|
|
97
|
-
},
|
|
98
|
-
relatedFiles,
|
|
99
|
-
relatedErrors: [],
|
|
100
|
-
status: "new",
|
|
101
|
-
};
|
|
102
|
-
appendFileSync(errorEventsPath, JSON.stringify(errorEntry) + "\n", "utf-8");
|
|
103
|
-
} catch {
|
|
104
|
-
// Best effort — crash report writing must never itself throw
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
process.on("uncaughtException", (error, origin) => {
|
|
109
|
-
writeCrashReport("uncaughtException", error);
|
|
110
|
-
process.stderr.write(`[aria] FATAL uncaughtException (origin: ${origin}):\n`);
|
|
111
|
-
process.stderr.write(`${error?.stack ?? error}\n`);
|
|
112
|
-
process.exit(1);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
process.on("unhandledRejection", (reason) => {
|
|
116
|
-
writeCrashReport("unhandledRejection", reason);
|
|
117
|
-
process.stderr.write(`[aria] FATAL unhandledRejection:\n`);
|
|
118
|
-
process.stderr.write(`${reason?.stack ?? reason}\n`);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
installOwnerLease();
|
|
123
|
-
|
|
124
|
-
// Determine mode based on arguments
|
|
125
|
-
const args = process.argv.slice(2);
|
|
126
|
-
|
|
127
|
-
if (args[0] === "-v" || args[0] === "--version") {
|
|
128
|
-
// Global flags that shouldn't be treated as REPL messages
|
|
129
|
-
import("../dist/commands/index.js")
|
|
130
|
-
.then(({ program }) => program.parseAsync(process.argv))
|
|
131
|
-
.catch((error) => {
|
|
132
|
-
process.stderr.write(`Error: ${error.message}\n`);
|
|
133
|
-
process.exitCode = 1;
|
|
134
|
-
});
|
|
135
|
-
} else {
|
|
136
|
-
// Existing routing: subcommand check + REPL
|
|
137
|
-
const subcommands = [
|
|
138
|
-
"daemon",
|
|
139
|
-
"auth",
|
|
140
|
-
"arions",
|
|
141
|
-
"headless",
|
|
142
|
-
"call",
|
|
143
|
-
"pairing",
|
|
144
|
-
"runtime-cutover-reset",
|
|
145
|
-
"--help",
|
|
146
|
-
"-h",
|
|
147
|
-
];
|
|
148
|
-
const isSubcommand =
|
|
149
|
-
args.length > 0 && (subcommands.includes(args[0]) || args[0].startsWith("--"));
|
|
150
|
-
|
|
151
|
-
// Parse -r/--resume and -c/--continue flags for REPL session resume
|
|
152
|
-
let resumeArg = null;
|
|
153
|
-
let continueSession = false;
|
|
154
|
-
const remainingArgs = [];
|
|
155
|
-
for (let i = 0; i < args.length; i++) {
|
|
156
|
-
if ((args[i] === "-r" || args[i] === "--resume") && !isSubcommand) {
|
|
157
|
-
if (i + 1 >= args.length) {
|
|
158
|
-
process.stderr.write("Error: -r/--resume requires a session ID\n");
|
|
159
|
-
process.exit(2);
|
|
160
|
-
}
|
|
161
|
-
resumeArg = args[++i];
|
|
162
|
-
} else if ((args[i] === "-c" || args[i] === "--continue") && !isSubcommand) {
|
|
163
|
-
continueSession = true;
|
|
164
|
-
} else {
|
|
165
|
-
remainingArgs.push(args[i]);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
if (resumeArg && continueSession) {
|
|
169
|
-
process.stderr.write("Error: -r/--resume and -c/--continue are mutually exclusive\n");
|
|
170
|
-
process.exit(2);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Auto-resume from supervisor: session ID passed via env var.
|
|
174
|
-
// The child always resumes silently; only explicit CLI args become an
|
|
175
|
-
// auto-submitted initial message.
|
|
176
|
-
if (!resumeArg && !continueSession && process.env[RESUME_SESSION_ENV]) {
|
|
177
|
-
resumeArg = process.env[RESUME_SESSION_ENV];
|
|
178
|
-
// Clear the env vars so they don't propagate to further restarts
|
|
179
|
-
delete process.env[RESUME_SESSION_ENV];
|
|
180
|
-
delete process.env[RESTART_KIND_ENV];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Treat non-flag remaining args as initial message: `aria "hello"` → REPL with first message
|
|
184
|
-
// Both crash resume and explicit /restart resume the session silently.
|
|
185
|
-
const initialMessage =
|
|
186
|
-
!isSubcommand && remainingArgs.length > 0 ? remainingArgs.join(" ") : undefined;
|
|
187
|
-
|
|
188
|
-
if (!isSubcommand) {
|
|
189
|
-
// Ensure adequate V8 heap for large Memoria databases (history.db > 1 GB).
|
|
190
|
-
// Re-exec once if the flag is missing. The re-exec parent does zero
|
|
191
|
-
// application work — just forwards stdio and exit code.
|
|
192
|
-
if (!process.execArgv.some((a) => a.includes("max-old-space-size"))) {
|
|
193
|
-
process.on("SIGINT", () => {
|
|
194
|
-
/* child owns the terminal */
|
|
195
|
-
});
|
|
196
|
-
import("node:child_process").then(({ spawn }) => {
|
|
197
|
-
const child = spawn(
|
|
198
|
-
process.execPath,
|
|
199
|
-
[
|
|
200
|
-
"--max-old-space-size=8192",
|
|
201
|
-
...process.execArgv,
|
|
202
|
-
process.argv[1],
|
|
203
|
-
...process.argv.slice(2),
|
|
204
|
-
],
|
|
205
|
-
{ stdio: "inherit" },
|
|
206
|
-
);
|
|
207
|
-
child.on("close", (code) => process.exit(code ?? 1));
|
|
208
|
-
});
|
|
209
|
-
} else {
|
|
210
|
-
// Run the Ink REPL directly — no supervisor loop.
|
|
211
|
-
// createCliContext runs in parallel with module imports to overlap
|
|
212
|
-
// the ~1.2s auth resolution with ~0.5s of import/init work.
|
|
213
|
-
Promise.resolve()
|
|
214
|
-
.then(async () => {
|
|
215
|
-
const { createCliContext } = await import("../dist/cli-context.js");
|
|
216
|
-
const { getAriaDir } = await import("../dist/config.js");
|
|
217
|
-
const { ensureDaemon } = await import("../dist/ensure-daemon.js");
|
|
218
|
-
|
|
219
|
-
const ariaDir = getAriaDir();
|
|
220
|
-
|
|
221
|
-
// Start auth resolution immediately — runs in parallel with imports below
|
|
222
|
-
const ctxPromise = createCliContext();
|
|
223
|
-
|
|
224
|
-
// Parallel: import heavy modules while auth resolves
|
|
225
|
-
const [
|
|
226
|
-
{ attachExistingLocalControlClient },
|
|
227
|
-
{ startInkRepl },
|
|
228
|
-
{ ArionManager, ArionStorage },
|
|
229
|
-
{ Memoria },
|
|
230
|
-
{ ArionSession },
|
|
231
|
-
{ SessionHistory },
|
|
232
|
-
] = await Promise.all([
|
|
233
|
-
import("../dist/local-control-client.js"),
|
|
234
|
-
import("../dist/ink-repl.js"),
|
|
235
|
-
import("@aria-cli/aria"),
|
|
236
|
-
import("@aria-cli/memoria"),
|
|
237
|
-
import("../dist/session.js"),
|
|
238
|
-
import("../dist/history/index.js"),
|
|
239
|
-
]);
|
|
240
|
-
|
|
241
|
-
// Await the context (auth likely finished during parallel imports)
|
|
242
|
-
const ctx = await ctxPromise;
|
|
243
|
-
await ensureDaemon(ctx);
|
|
244
|
-
|
|
245
|
-
const bootstrapAttachedLocalControl = await attachExistingLocalControlClient({
|
|
246
|
-
ariaHome: ariaDir,
|
|
247
|
-
clientKind: "tui",
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const ariaMemoriaPath =
|
|
251
|
-
process.env.ARIA_MEMORY_PATH || `${ctx.ariaDir}/arions/ARIA/memory.db`;
|
|
252
|
-
const ariaMemoria = new Memoria({ path: ariaMemoriaPath, router: ctx.router });
|
|
253
|
-
ariaMemoria.initialize().catch((err) => {
|
|
254
|
-
console.debug(
|
|
255
|
-
`[aria] Memoria background init failed (will retry on use): ${err?.message ?? err}`,
|
|
256
|
-
);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const aria = {
|
|
260
|
-
components: { memoria: ariaMemoria },
|
|
261
|
-
async recallUserName() {
|
|
262
|
-
try {
|
|
263
|
-
const db = ariaMemoria.storage?.getDatabase?.();
|
|
264
|
-
if (!db) return null;
|
|
265
|
-
const row = db.prepare("SELECT value FROM config WHERE key = 'user_profile'").get();
|
|
266
|
-
if (!row?.value) return null;
|
|
267
|
-
const profile = JSON.parse(row.value);
|
|
268
|
-
return profile.name ?? null;
|
|
269
|
-
} catch {
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
async shutdown() {
|
|
274
|
-
await ariaMemoria.close();
|
|
275
|
-
},
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const arionStorage = new ArionStorage(ctx.ariaDir);
|
|
279
|
-
const arionManager = new ArionManager(arionStorage, ctx.memoriaFactory);
|
|
280
|
-
await arionManager.initialize();
|
|
281
|
-
arionManager.setRouter(ctx.router);
|
|
282
|
-
if (!bootstrapAttachedLocalControl) {
|
|
283
|
-
throw new Error("[aria] Attached REPL requires an existing local-control runtime");
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Initialize session history for input persistence
|
|
287
|
-
const arionName = ctx.config.activeArion?.trim() || "ARIA";
|
|
288
|
-
const historyDbPath = SessionHistory.resolvePerArionPath(ctx.ariaDir, arionName);
|
|
289
|
-
SessionHistory.migrateJsonlLogs(ctx.ariaDir, arionName);
|
|
290
|
-
const sessionHistory = new SessionHistory(historyDbPath);
|
|
291
|
-
const inputHistory = sessionHistory.getInputHistory(100);
|
|
292
|
-
const saveInputHistory = (input) => sessionHistory.addInputHistory(input);
|
|
293
|
-
|
|
294
|
-
// Resolve -r / -c to a session ID
|
|
295
|
-
let resumeSessionId = undefined;
|
|
296
|
-
if (resumeArg) {
|
|
297
|
-
const resolved = sessionHistory.findSessionByPrefix(resumeArg);
|
|
298
|
-
if (!resolved) {
|
|
299
|
-
process.stderr.write(`Error: No session found matching "${resumeArg}"\n`);
|
|
300
|
-
process.exit(2);
|
|
301
|
-
}
|
|
302
|
-
resumeSessionId = resolved;
|
|
303
|
-
} else if (continueSession) {
|
|
304
|
-
const recent = sessionHistory.listSessions(1);
|
|
305
|
-
if (recent.length === 0) {
|
|
306
|
-
process.stderr.write("Error: No recent sessions to continue\n");
|
|
307
|
-
process.exit(2);
|
|
308
|
-
}
|
|
309
|
-
resumeSessionId = recent[0].id;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const session = new ArionSession({
|
|
313
|
-
manager: arionManager,
|
|
314
|
-
router: ctx.router,
|
|
315
|
-
memoria: aria.components.memoria,
|
|
316
|
-
onArionRest: async () => {},
|
|
317
|
-
});
|
|
318
|
-
await session.initialize(ctx.config.activeArion);
|
|
319
|
-
|
|
320
|
-
// Pre-cache username for instant display
|
|
321
|
-
let cachedUserName = null;
|
|
322
|
-
try {
|
|
323
|
-
const db = ariaMemoria.storage?.getDatabase?.();
|
|
324
|
-
if (db) {
|
|
325
|
-
const row = db.prepare("SELECT value FROM config WHERE key = 'user_profile'").get();
|
|
326
|
-
if (row?.value) {
|
|
327
|
-
cachedUserName = JSON.parse(row.value).name ?? null;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
} catch {}
|
|
331
|
-
|
|
332
|
-
await startInkRepl(
|
|
333
|
-
session,
|
|
334
|
-
arionManager,
|
|
335
|
-
ctx.router,
|
|
336
|
-
aria,
|
|
337
|
-
bootstrapAttachedLocalControl,
|
|
338
|
-
ctx,
|
|
339
|
-
inputHistory,
|
|
340
|
-
saveInputHistory,
|
|
341
|
-
sessionHistory,
|
|
342
|
-
initialMessage,
|
|
343
|
-
cachedUserName,
|
|
344
|
-
resumeSessionId,
|
|
345
|
-
ctx.availableModels,
|
|
346
|
-
ctx.refreshAvailableModels,
|
|
347
|
-
ctx.credentialHints,
|
|
348
|
-
ctx.authResolver,
|
|
349
|
-
);
|
|
350
|
-
})
|
|
351
|
-
.catch((error) => {
|
|
352
|
-
writeCrashReport("ink-repl-rejected", error);
|
|
353
|
-
console.error("Error starting Ink REPL:", error.message);
|
|
354
|
-
process.exit(1);
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
} else {
|
|
358
|
-
// Subcommand provided - parse commands
|
|
359
|
-
import("../dist/commands/index.js").then(({ program }) => {
|
|
360
|
-
program.parseAsync(process.argv).catch((error) => {
|
|
361
|
-
console.error("Error:", error.message);
|
|
362
|
-
process.exit(1);
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
}
|
|
2
|
+
"use strict";import{writeFileSync as F,appendFileSync as U,mkdirSync as z}from"node:fs";import{join as y}from"node:path";import{homedir as L}from"node:os";import{createHash as J}from"node:crypto";import{RESTART_KIND_ENV as V,RESUME_SESSION_ENV as A}from"@aria-cli/types";import"../dist/repl-cleanup.js";import{installOwnerLease as W}from"./install-owner-lease.js";function $(o,r){try{const i=y(L(),".aria","crash-reports");z(i,{recursive:!0});const p=process.env[A]||"unknown",m=process.memoryUsage(),u={timestamp:new Date().toISOString(),sessionId:p,type:o,error:{message:r?.message??String(r),stack:r?.stack??void 0,name:r?.name??void 0},process:{pid:process.pid,heapUsedMb:Math.round(m.heapUsed/1024/1024*100)/100,rssMb:Math.round(m.rss/1024/1024*100)/100,uptime:Math.round(process.uptime())}};F(y(i,"latest.json"),JSON.stringify(u,null,2));const e=y(L(),".aria"),c=y(e,"error-events.jsonl"),S=r?.stack?.split(`
|
|
3
|
+
`)[1]?.trim()??"",x=Math.floor(Date.now()/1e4),R=J("sha256").update(`${r?.message??""}|${S}|${x}`).digest("hex").slice(0,12),v=[];let n=r?.cause;const f=new Set;for(;n instanceof Error&&!f.has(n);)f.add(n),v.push(`${n.name}: ${n.message}`),n=n.cause;const w=[];if(r?.stack)for(const M of r.stack.split(`
|
|
4
|
+
`)){const l=M.match(/\((?:file:\/\/)?([^:)]+):\d+:\d+\)/);l?.[1]?.includes("packages/")&&!l[1].includes("node_modules")&&w.push(l[1])}const k={id:`crash-${R}`,timestamp:u.timestamp,severity:0,category:"crash",domain:"cli",name:r?.name??"UnknownError",message:r?.message??String(r),code:r?.code??void 0,stackTrace:r?.stack,causeChain:v,recoverable:!1,state:{environment:{nodeVersion:process.version,platform:process.platform},processInfo:u.process},relatedFiles:w,relatedErrors:[],status:"new"};U(c,JSON.stringify(k)+`
|
|
5
|
+
`,"utf-8")}catch{}}process.on("uncaughtException",(o,r)=>{$("uncaughtException",o),process.stderr.write(`[aria] FATAL uncaughtException (origin: ${r}):
|
|
6
|
+
`),process.stderr.write(`${o?.stack??o}
|
|
7
|
+
`),process.exit(1)}),process.on("unhandledRejection",o=>{$("unhandledRejection",o),process.stderr.write(`[aria] FATAL unhandledRejection:
|
|
8
|
+
`),process.stderr.write(`${o?.stack??o}
|
|
9
|
+
`),process.exit(1)}),W();const a=process.argv.slice(2);if(a[0]==="-v"||a[0]==="--version")import("../dist/commands/index.js").then(({program:o})=>o.parseAsync(process.argv)).catch(o=>{process.stderr.write(`Error: ${o.message}
|
|
10
|
+
`),process.exitCode=1});else{const o=["daemon","auth","arions","headless","call","pairing","runtime-cutover-reset","--help","-h"],r=a.length>0&&(o.includes(a[0])||a[0].startsWith("--"));let i=null,p=!1;const m=[];for(let e=0;e<a.length;e++)(a[e]==="-r"||a[e]==="--resume")&&!r?(e+1>=a.length&&(process.stderr.write(`Error: -r/--resume requires a session ID
|
|
11
|
+
`),process.exit(2)),i=a[++e]):(a[e]==="-c"||a[e]==="--continue")&&!r?p=!0:m.push(a[e]);i&&p&&(process.stderr.write(`Error: -r/--resume and -c/--continue are mutually exclusive
|
|
12
|
+
`),process.exit(2)),!i&&!p&&process.env[A]&&(i=process.env[A],delete process.env[A],delete process.env[V]);const u=!r&&m.length>0?m.join(" "):void 0;r?import("../dist/commands/index.js").then(({program:e})=>{e.parseAsync(process.argv).catch(c=>{console.error("Error:",c.message),process.exit(1)})}):process.execArgv.some(e=>e.includes("max-old-space-size"))?Promise.resolve().then(async()=>{const{createCliContext:e}=await import("../dist/cli-context.js"),{getAriaDir:c}=await import("../dist/config.js"),{ensureDaemon:S}=await import("../dist/ensure-daemon.js"),x=c(),R=e(),[{attachExistingLocalControlClient:v},{startInkRepl:n},{ArionManager:f,ArionStorage:w},{Memoria:k},{ArionSession:M},{SessionHistory:l}]=await Promise.all([import("../dist/local-control-client.js"),import("../dist/ink-repl.js"),import("@aria-cli/aria"),import("@aria-cli/memoria"),import("../dist/session.js"),import("../dist/history/index.js")]),s=await R;await S(s);const D=await v({ariaHome:x,clientKind:"tui"}),P=process.env.ARIA_MEMORY_PATH||`${s.ariaDir}/arions/ARIA/memory.db`,d=new k({path:P,router:s.router});d.initialize().catch(t=>{console.debug(`[aria] Memoria background init failed (will retry on use): ${t?.message??t}`)});const N={components:{memoria:d},async recallUserName(){try{const t=d.storage?.getDatabase?.();if(!t)return null;const h=t.prepare("SELECT value FROM config WHERE key = 'user_profile'").get();return h?.value?JSON.parse(h.value).name??null:null}catch{return null}},async shutdown(){await d.close()}},T=new w(s.ariaDir),E=new f(T,s.memoriaFactory);if(await E.initialize(),E.setRouter(s.router),!D)throw new Error("[aria] Attached REPL requires an existing local-control runtime");const b=s.config.activeArion?.trim()||"ARIA",_=l.resolvePerArionPath(s.ariaDir,b);l.migrateJsonlLogs(s.ariaDir,b);const g=new l(_),j=g.getInputHistory(100),C=t=>g.addInputHistory(t);let I;if(i){const t=g.findSessionByPrefix(i);t||(process.stderr.write(`Error: No session found matching "${i}"
|
|
13
|
+
`),process.exit(2)),I=t}else if(p){const t=g.listSessions(1);t.length===0&&(process.stderr.write(`Error: No recent sessions to continue
|
|
14
|
+
`),process.exit(2)),I=t[0].id}const O=new M({manager:E,router:s.router,memoria:N.components.memoria,onArionRest:async()=>{}});await O.initialize(s.config.activeArion);let H=null;try{const t=d.storage?.getDatabase?.();if(t){const h=t.prepare("SELECT value FROM config WHERE key = 'user_profile'").get();h?.value&&(H=JSON.parse(h.value).name??null)}}catch{}await n(O,E,s.router,N,D,s,j,C,g,u,H,I,s.availableModels,s.refreshAvailableModels,s.credentialHints,s.authResolver)}).catch(e=>{$("ink-repl-rejected",e),console.error("Error starting Ink REPL:",e.message),process.exit(1)}):(process.on("SIGINT",()=>{}),import("node:child_process").then(({spawn:e})=>{e(process.execPath,["--max-old-space-size=8192",...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit"}).on("close",c=>process.exit(c??1))}))}
|
|
@@ -1,53 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
export function installOwnerLease({
|
|
4
|
-
env = process.env,
|
|
5
|
-
processRef = process,
|
|
6
|
-
pollMs = DEFAULT_OWNER_LEASE_POLL_MS,
|
|
7
|
-
onOwnerGone,
|
|
8
|
-
} = {}) {
|
|
9
|
-
const ownerPidRaw = env.ARIA_HARNESS_OWNER_PID;
|
|
10
|
-
if (!ownerPidRaw) {
|
|
11
|
-
return () => {};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const ownerPid = Number.parseInt(ownerPidRaw, 10);
|
|
15
|
-
if (!Number.isFinite(ownerPid) || ownerPid <= 0) {
|
|
16
|
-
throw new Error(`ARIA_HARNESS_OWNER_PID must be a positive integer, got: ${ownerPidRaw}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let released = false;
|
|
20
|
-
const interval = setInterval(() => {
|
|
21
|
-
if (released) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
processRef.kill(ownerPid, 0);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
29
|
-
if (code && code !== "ESRCH") {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
released = true;
|
|
33
|
-
clearInterval(interval);
|
|
34
|
-
if (onOwnerGone) {
|
|
35
|
-
onOwnerGone(ownerPid);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
processRef.kill(processRef.pid, "SIGTERM");
|
|
39
|
-
}
|
|
40
|
-
}, pollMs);
|
|
41
|
-
interval.unref?.();
|
|
42
|
-
|
|
43
|
-
const dispose = () => {
|
|
44
|
-
if (released) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
released = true;
|
|
48
|
-
clearInterval(interval);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
processRef.once("exit", dispose);
|
|
52
|
-
return dispose;
|
|
53
|
-
}
|
|
1
|
+
"use strict";const f=1e3;export function installOwnerLease({env:u=process.env,processRef:e=process,pollMs:a=1e3,onOwnerGone:i}={}){const o=u.ARIA_HARNESS_OWNER_PID;if(!o)return()=>{};const t=Number.parseInt(o,10);if(!Number.isFinite(t)||t<=0)throw new Error(`ARIA_HARNESS_OWNER_PID must be a positive integer, got: ${o}`);let r=!1;const s=setInterval(()=>{if(!r)try{e.kill(t,0)}catch(n){const l=n&&typeof n=="object"&&"code"in n?n.code:void 0;if(l&&l!=="ESRCH")return;if(r=!0,clearInterval(s),i){i(t);return}e.kill(e.pid,"SIGTERM")}},a);s.unref?.();const c=()=>{r||(r=!0,clearInterval(s))};return e.once("exit",c),c}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aria-cli/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,14 +13,38 @@
|
|
|
13
13
|
"import": "./dist/index.js"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "vitest run --config vitest.config.ts",
|
|
18
|
+
"test:list": "tsx tests/print-default-test-lane.ts",
|
|
19
|
+
"test:watch": "vitest --config vitest.config.ts",
|
|
20
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
21
|
+
"test:native": "vitest run --config vitest.native.config.ts",
|
|
22
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
23
|
+
"test:e2e:watch": "vitest --config vitest.e2e.config.ts",
|
|
24
|
+
"test:e2e:mocked": "vitest run --config vitest.e2e.config.ts --testNamePattern='mocked|error|rejects|handles|prevents'",
|
|
25
|
+
"test:real": "vitest run --config vitest.real.config.ts",
|
|
26
|
+
"test:lanes": "tsx tests/print-test-lane-manifest.ts",
|
|
27
|
+
"test:parity": "node ../../scripts/run-cli-parity-tests.mjs",
|
|
28
|
+
"start": "node dist/index.js",
|
|
29
|
+
"dev": "node --import tsx bin/aria-dev.js",
|
|
30
|
+
"dev:repl": "node --import tsx bin/aria-dev.js"
|
|
31
|
+
},
|
|
16
32
|
"dependencies": {
|
|
33
|
+
"@aria-cli/aria": "1.0.18",
|
|
34
|
+
"@aria-cli/auth": "1.0.18",
|
|
35
|
+
"@aria-cli/memoria": "1.0.18",
|
|
36
|
+
"@aria-cli/memoria-bridge": "1.0.18",
|
|
37
|
+
"@aria-cli/models": "1.0.18",
|
|
38
|
+
"@aria-cli/server": "1.0.18",
|
|
39
|
+
"@aria-cli/tools": "1.0.18",
|
|
40
|
+
"@aria-cli/types": "1.0.18",
|
|
41
|
+
"@aria-cli/wireguard": "1.0.18",
|
|
17
42
|
"better-sqlite3": "^12.6.2",
|
|
18
43
|
"chalk": "^5.6.2",
|
|
19
44
|
"cli-highlight": "^2.1.11",
|
|
20
45
|
"color-name": "^2.1.0",
|
|
21
46
|
"commander": "^14.0.3",
|
|
22
47
|
"diff": "^8.0.3",
|
|
23
|
-
"figures": "^6.1.0",
|
|
24
48
|
"gradient-string": "^3.0.0",
|
|
25
49
|
"ink": "npm:@jrichman/ink@^6.4.11",
|
|
26
50
|
"ink-spinner": "^5.0.0",
|
|
@@ -31,16 +55,7 @@
|
|
|
31
55
|
"string-width": "^8.2.0",
|
|
32
56
|
"wrap-ansi": "^10.0.0",
|
|
33
57
|
"yaml": "^2.8.2",
|
|
34
|
-
"zod": "^4.3.6"
|
|
35
|
-
"@aria-cli/memoria": "1.0.15",
|
|
36
|
-
"@aria-cli/aria": "1.0.15",
|
|
37
|
-
"@aria-cli/memoria-bridge": "1.0.15",
|
|
38
|
-
"@aria-cli/auth": "1.0.15",
|
|
39
|
-
"@aria-cli/tools": "1.0.15",
|
|
40
|
-
"@aria-cli/types": "1.0.15",
|
|
41
|
-
"@aria-cli/models": "1.0.15",
|
|
42
|
-
"@aria-cli/server": "1.0.15",
|
|
43
|
-
"@aria-cli/wireguard": "1.0.15"
|
|
58
|
+
"zod": "^4.3.6"
|
|
44
59
|
},
|
|
45
60
|
"devDependencies": {
|
|
46
61
|
"@testing-library/react": "^16.3.2",
|
|
@@ -57,20 +72,7 @@
|
|
|
57
72
|
"!**/*.map",
|
|
58
73
|
"!**/*.tsbuildinfo"
|
|
59
74
|
],
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"test:list": "tsx tests/print-default-test-lane.ts",
|
|
63
|
-
"test:watch": "vitest --config vitest.config.ts",
|
|
64
|
-
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
65
|
-
"test:native": "vitest run --config vitest.native.config.ts",
|
|
66
|
-
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
67
|
-
"test:e2e:watch": "vitest --config vitest.e2e.config.ts",
|
|
68
|
-
"test:e2e:mocked": "vitest run --config vitest.e2e.config.ts --testNamePattern='mocked|error|rejects|handles|prevents'",
|
|
69
|
-
"test:real": "vitest run --config vitest.real.config.ts",
|
|
70
|
-
"test:lanes": "tsx tests/print-test-lane-manifest.ts",
|
|
71
|
-
"test:parity": "node ../../scripts/run-cli-parity-tests.mjs",
|
|
72
|
-
"start": "node dist/index.js",
|
|
73
|
-
"dev": "node --import tsx bin/aria-dev.js",
|
|
74
|
-
"dev:repl": "node --import tsx bin/aria-dev.js"
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=20.0.0"
|
|
75
77
|
}
|
|
76
|
-
}
|
|
78
|
+
}
|
package/dist/repl-cleanup.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./index-9j6r3gr8.js";function G(j){console.warn(j)}function z(j){return j instanceof Error?j.message:String(j)}async function I(j,A){try{return await j()}finally{let{release:B,sessionHistory:C,pool:D,aria:F,warn:v=G}=A();try{await B?.()}catch(q){v(`[aria] Local-control cleanup failed: ${z(q)}`)}try{C?.close?.()}catch(q){v(`[aria] SessionHistory cleanup failed: ${z(q)}`)}try{await D?.closeAll?.()}catch(q){v(`[aria] Memoria pool cleanup failed: ${z(q)}`)}try{await F?.shutdown?.()}catch(q){v(`[aria] Fallback aria shutdown failed: ${z(q)}`)}}}export{I as withReplCleanup};
|