@auroraflow/code 0.0.20 → 0.0.22
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
CHANGED
|
@@ -40,6 +40,7 @@ aurora install all
|
|
|
40
40
|
aurora repair codex
|
|
41
41
|
aurora repair claude
|
|
42
42
|
aurora doctor
|
|
43
|
+
aurora doctor --json
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
## Commands
|
|
@@ -55,6 +56,7 @@ node bin/aurora.js install codex
|
|
|
55
56
|
node bin/aurora.js install claude
|
|
56
57
|
node bin/aurora.js repair codex
|
|
57
58
|
node bin/aurora.js doctor
|
|
59
|
+
node bin/aurora.js doctor --json
|
|
58
60
|
node bin/aurora.js install-clients
|
|
59
61
|
node bin/aurora.js update-clients
|
|
60
62
|
node bin/aurora.js status
|
|
@@ -66,6 +68,8 @@ If the selected official client is missing, Aurora prompts to install that
|
|
|
66
68
|
specific client before launch.
|
|
67
69
|
If the package exists but its command is not usable, Aurora reports a broken
|
|
68
70
|
client state and prompts to repair instead of calling it "not installed".
|
|
71
|
+
`aurora doctor` prints a human-readable health summary, including npm, disk
|
|
72
|
+
space on Windows, and repair commands for missing or broken clients.
|
|
69
73
|
|
|
70
74
|
The launcher stores shared local state under `~/.aurora` and starts a local
|
|
71
75
|
sidecar at `127.0.0.1:17878`. Official clients talk to the sidecar; the sidecar
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ensureLayout, readAccount, readState, writeAccount, writeState } from "../../state/src/index.js";
|
|
2
|
-
import { installOfficialClient, officialClientStatus, officialClientStatuses, repairOfficialClient, runClient, updateOfficialClients } from "../../clients/src/index.js";
|
|
2
|
+
import { installOfficialClient, officialClientStatus, officialClientStatuses, officialClientsDoctor, repairOfficialClient, runClient, updateOfficialClients } from "../../clients/src/index.js";
|
|
3
3
|
import { ensureSidecarRunning, installSidecarService, sidecarServiceStatus, uninstallSidecarService } from "../../service/src/index.js";
|
|
4
4
|
import { chooseClient, promptChoice, promptFields } from "../../../lib/prompt.js";
|
|
5
5
|
|
|
@@ -29,7 +29,7 @@ export async function runAuroraCLI(argv = process.argv.slice(2)) {
|
|
|
29
29
|
}, null, 2));
|
|
30
30
|
return;
|
|
31
31
|
case "doctor":
|
|
32
|
-
await doctorCommand();
|
|
32
|
+
await doctorCommand(rest);
|
|
33
33
|
return;
|
|
34
34
|
case "install":
|
|
35
35
|
await installCommand(rest);
|
|
@@ -120,18 +120,35 @@ async function repairCommand(args) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
async function doctorCommand() {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
async function doctorCommand(args = []) {
|
|
124
|
+
const report = officialClientsDoctor();
|
|
125
|
+
if (args.includes("--json")) {
|
|
126
|
+
console.log(JSON.stringify(report, null, 2));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log("Aurora doctor\n");
|
|
130
|
+
console.log(`Platform: ${report.platform}`);
|
|
131
|
+
console.log(`npm: ${report.npm.ok ? `ok (${report.npm.version})` : `problem (${report.npm.error || "unknown"})`}`);
|
|
132
|
+
if (report.disk.checked) {
|
|
133
|
+
console.log(`Disk ${report.disk.drive}: ${report.disk.availableMB ?? "unknown"} MB free`);
|
|
134
|
+
}
|
|
135
|
+
console.log("");
|
|
136
|
+
for (const status of report.officialClients) {
|
|
137
|
+
console.log(`${status.name}: ${status.state}${status.version ? ` (${status.version})` : ""}`);
|
|
138
|
+
if (status.bin) console.log(` command: ${status.bin}`);
|
|
139
|
+
if (status.packagePath) console.log(` package: ${status.packagePath}`);
|
|
140
|
+
if (status.problem) console.log(` problem: ${status.problem}`);
|
|
141
|
+
if (status.state === "missing") console.log(` fix: aurora install ${status.id}`);
|
|
127
142
|
if (status.state === "broken") {
|
|
128
|
-
console.
|
|
129
|
-
console.error(`Repair: aurora repair ${status.id}`);
|
|
143
|
+
console.log(` fix: aurora repair ${status.id}`);
|
|
130
144
|
if (process.platform === "win32") {
|
|
131
|
-
console.
|
|
145
|
+
console.log(` if locked: taskkill /F /IM ${status.id === "claude" ? "claude.exe" : "codex.exe"}`);
|
|
132
146
|
}
|
|
133
147
|
}
|
|
134
148
|
}
|
|
149
|
+
if (report.disk.checked && report.disk.availableBytes != null && report.disk.availableBytes < 512 * 1024 * 1024) {
|
|
150
|
+
console.log("\nWarning: low disk space can break npm install/repair. Free space and run: npm cache clean --force");
|
|
151
|
+
}
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
export async function runAuroraClaude(argv = process.argv.slice(2)) {
|
|
@@ -258,6 +275,7 @@ function usage(exitCode) {
|
|
|
258
275
|
aurora repair codex
|
|
259
276
|
aurora repair claude
|
|
260
277
|
aurora doctor
|
|
278
|
+
aurora doctor --json
|
|
261
279
|
aurora install-clients
|
|
262
280
|
aurora update-clients
|
|
263
281
|
aurora status
|
|
@@ -5,6 +5,7 @@ import { delimiter, dirname, join, resolve } from "node:path";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { CLAUDE_HOME, CODEX_HOME, readState } from "../../state/src/index.js";
|
|
7
7
|
import { ensureSidecarRunning } from "../../service/src/index.js";
|
|
8
|
+
import { codexModelRuntimeLimits } from "../../protocol/src/index.js";
|
|
8
9
|
|
|
9
10
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
const packageRoot = resolve(here, "..", "..", "..");
|
|
@@ -97,12 +98,18 @@ export async function installOfficialClients() {
|
|
|
97
98
|
export async function installOfficialClient(client, options = {}) {
|
|
98
99
|
const spec = OFFICIAL_CLIENTS[client];
|
|
99
100
|
if (!spec) throw new Error(`unknown official client: ${client}`);
|
|
101
|
+
const preflight = officialClientPreflight(client);
|
|
102
|
+
if (!preflight.ok) throw new Error(formatOfficialClientPreflightError(spec, preflight));
|
|
100
103
|
const npm = npmCommandSpec();
|
|
101
104
|
const args = ["install", "-g"];
|
|
102
105
|
if (options.repair) args.push("--force");
|
|
103
106
|
args.push(`${spec.packageName}@latest`);
|
|
104
107
|
console.error(`[aurora] ${options.repair ? "repairing" : "installing"} ${spec.name}: ${npm.command} ${[...npm.args, ...args].join(" ")}`);
|
|
105
|
-
|
|
108
|
+
try {
|
|
109
|
+
await spawnAndWait(npm.command, [...npm.args, ...args], { ...process.env });
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new Error(formatOfficialClientInstallError(spec, client, error));
|
|
112
|
+
}
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
export async function repairOfficialClient(client) {
|
|
@@ -117,6 +124,16 @@ export function officialClientStatus(client) {
|
|
|
117
124
|
return officialClientStatuses().find(status => status.id === client) ?? null;
|
|
118
125
|
}
|
|
119
126
|
|
|
127
|
+
export function officialClientsDoctor() {
|
|
128
|
+
return {
|
|
129
|
+
platform: process.platform,
|
|
130
|
+
npm: npmDoctor(),
|
|
131
|
+
disk: diskDoctor(),
|
|
132
|
+
processHints: processHints(),
|
|
133
|
+
officialClients: officialClientStatuses()
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
120
137
|
function officialClientBin(client) {
|
|
121
138
|
const spec = OFFICIAL_CLIENTS[client];
|
|
122
139
|
if (!spec) throw new Error(`unknown official client: ${client}`);
|
|
@@ -179,6 +196,113 @@ function officialClientProblem(state, bin, packagePath) {
|
|
|
179
196
|
return "unknown";
|
|
180
197
|
}
|
|
181
198
|
|
|
199
|
+
function officialClientPreflight(client) {
|
|
200
|
+
const disk = diskDoctor();
|
|
201
|
+
if (disk.availableBytes != null && disk.availableBytes < 512 * 1024 * 1024) {
|
|
202
|
+
return { ok: false, reason: "low_disk_space", disk };
|
|
203
|
+
}
|
|
204
|
+
const processes = processHints();
|
|
205
|
+
const locked = processes.find(item => item.client === client && item.running);
|
|
206
|
+
if (locked) return { ok: false, reason: "client_process_running", process: locked };
|
|
207
|
+
return { ok: true, disk, processes };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function npmDoctor() {
|
|
211
|
+
try {
|
|
212
|
+
const npm = npmCommandSpec();
|
|
213
|
+
const result = spawnSyncCompat(npm.command, [...npm.args, "--version"]);
|
|
214
|
+
return {
|
|
215
|
+
command: npm.command,
|
|
216
|
+
args: npm.args,
|
|
217
|
+
ok: result.status === 0,
|
|
218
|
+
version: String(result.stdout || result.stderr || "").trim() || null
|
|
219
|
+
};
|
|
220
|
+
} catch (error) {
|
|
221
|
+
return { ok: false, error: error?.message || String(error) };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function diskDoctor() {
|
|
226
|
+
if (process.platform !== "win32") return { checked: false, reason: "not_windows" };
|
|
227
|
+
try {
|
|
228
|
+
const drive = (process.env.APPDATA || process.cwd()).slice(0, 2);
|
|
229
|
+
const result = spawnSync("powershell.exe", [
|
|
230
|
+
"-NoProfile",
|
|
231
|
+
"-Command",
|
|
232
|
+
`(Get-PSDrive -Name ${JSON.stringify(drive.charAt(0))}).Free`
|
|
233
|
+
], { encoding: "utf8" });
|
|
234
|
+
const availableBytes = Number(String(result.stdout || "").trim());
|
|
235
|
+
return {
|
|
236
|
+
checked: true,
|
|
237
|
+
drive,
|
|
238
|
+
availableBytes: Number.isFinite(availableBytes) ? availableBytes : null,
|
|
239
|
+
availableMB: Number.isFinite(availableBytes) ? Math.floor(availableBytes / 1024 / 1024) : null
|
|
240
|
+
};
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return { checked: false, error: error?.message || String(error) };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function processHints() {
|
|
247
|
+
if (process.platform !== "win32") return [];
|
|
248
|
+
return [
|
|
249
|
+
{ client: "claude", image: "claude.exe", running: isWindowsProcessRunning("claude.exe") },
|
|
250
|
+
{ client: "codex", image: "codex.exe", running: isWindowsProcessRunning("codex.exe") },
|
|
251
|
+
{ client: "codex", image: "node.exe", running: false, note: "Codex may run through node.exe depending on npm package version." }
|
|
252
|
+
];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function isWindowsProcessRunning(image) {
|
|
256
|
+
try {
|
|
257
|
+
const result = spawnSync("tasklist", ["/FI", `IMAGENAME eq ${image}`], { encoding: "utf8" });
|
|
258
|
+
return String(result.stdout || "").toLowerCase().includes(image.toLowerCase());
|
|
259
|
+
} catch {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function formatOfficialClientPreflightError(spec, preflight) {
|
|
265
|
+
if (preflight.reason === "low_disk_space") {
|
|
266
|
+
return `${spec.name} repair/install blocked: low disk space on ${preflight.disk.drive} (${preflight.disk.availableMB} MB free). Free at least 512 MB, run npm cache clean --force, then retry.`;
|
|
267
|
+
}
|
|
268
|
+
if (preflight.reason === "client_process_running") {
|
|
269
|
+
return `${spec.name} repair/install blocked: ${preflight.process.image} is running. Close ${spec.name} or run: taskkill /F /IM ${preflight.process.image}`;
|
|
270
|
+
}
|
|
271
|
+
return `${spec.name} repair/install preflight failed: ${preflight.reason}`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function formatOfficialClientInstallError(spec, client, error) {
|
|
275
|
+
const message = error?.message || String(error);
|
|
276
|
+
const suggestions = officialClientFailureSuggestions(client, message);
|
|
277
|
+
return [`${spec.name} install/repair failed: ${message}`, ...suggestions].join("\n");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function officialClientFailureSuggestions(client, message) {
|
|
281
|
+
const text = String(message);
|
|
282
|
+
const image = client === "claude" ? "claude.exe" : "codex.exe";
|
|
283
|
+
if (/ENOSPC|no space left/i.test(text)) {
|
|
284
|
+
return [
|
|
285
|
+
"Detected cause: disk is full.",
|
|
286
|
+
"Fix: free disk space, then run: npm cache clean --force",
|
|
287
|
+
`Retry: aurora repair ${client}`
|
|
288
|
+
];
|
|
289
|
+
}
|
|
290
|
+
if (/EBUSY|EPERM|resource busy|operation not permitted/i.test(text)) {
|
|
291
|
+
return [
|
|
292
|
+
"Detected cause: files are locked by a running process or antivirus.",
|
|
293
|
+
process.platform === "win32" ? `Fix: close the client, then run: taskkill /F /IM ${image}` : "Fix: close the running client process.",
|
|
294
|
+
`Retry: aurora repair ${client}`
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
if (/ENOENT|not found/i.test(text)) {
|
|
298
|
+
return [
|
|
299
|
+
"Detected cause: npm or a required command was not found.",
|
|
300
|
+
"Fix: reinstall Node.js/npm or add npm to PATH, then retry."
|
|
301
|
+
];
|
|
302
|
+
}
|
|
303
|
+
return [`Run diagnostics: aurora doctor`, `Retry after fixing the reported issue: aurora repair ${client}`];
|
|
304
|
+
}
|
|
305
|
+
|
|
182
306
|
function readOfficialClientVersion(bin) {
|
|
183
307
|
if (!bin) return null;
|
|
184
308
|
try {
|
|
@@ -193,11 +317,13 @@ function readOfficialClientVersion(bin) {
|
|
|
193
317
|
async function writeCodexRuntimeFiles({ sidecar, model }) {
|
|
194
318
|
await mkdir(CODEX_HOME, { recursive: true });
|
|
195
319
|
const modelCatalogPath = join(CODEX_HOME, "model_catalog.json");
|
|
196
|
-
await writeCodexModelCatalog(sidecar, modelCatalogPath);
|
|
320
|
+
const limits = await writeCodexModelCatalog(sidecar, modelCatalogPath, model);
|
|
197
321
|
const config = `model = ${tomlString(model)}
|
|
198
322
|
model_provider = "aurora"
|
|
199
323
|
model_catalog_json = ${tomlString(modelCatalogPath)}
|
|
200
324
|
suppress_unstable_features_warning = true
|
|
325
|
+
model_context_window = ${limits.contextWindow}
|
|
326
|
+
model_auto_compact_token_limit = ${limits.autoCompactTokenLimit}
|
|
201
327
|
|
|
202
328
|
[model_providers.aurora]
|
|
203
329
|
name = "Aurora"
|
|
@@ -218,7 +344,7 @@ stream_idle_timeout_ms = 300000
|
|
|
218
344
|
await writeFile(join(CODEX_HOME, "auth.json"), `${JSON.stringify(auth, null, 2)}\n`, { mode: 0o600 });
|
|
219
345
|
}
|
|
220
346
|
|
|
221
|
-
async function writeCodexModelCatalog(sidecar, modelCatalogPath) {
|
|
347
|
+
async function writeCodexModelCatalog(sidecar, modelCatalogPath, selectedModelAlias) {
|
|
222
348
|
const clientVersion = "0.137.0";
|
|
223
349
|
let response;
|
|
224
350
|
try {
|
|
@@ -239,6 +365,11 @@ async function writeCodexModelCatalog(sidecar, modelCatalogPath) {
|
|
|
239
365
|
if (!Array.isArray(payload.models) || payload.models.length === 0) {
|
|
240
366
|
throw new Error("Aurora Codex model catalog is empty");
|
|
241
367
|
}
|
|
368
|
+
const selectedModel = payload.models.find(item => item.slug === selectedModelAlias);
|
|
369
|
+
if (!selectedModel) {
|
|
370
|
+
throw new Error(`Aurora Codex model catalog does not include selected model: ${selectedModelAlias}`);
|
|
371
|
+
}
|
|
372
|
+
const limits = codexModelRuntimeLimits(selectedModel);
|
|
242
373
|
const catalog = { models: payload.models };
|
|
243
374
|
const cache = {
|
|
244
375
|
fetched_at: new Date().toISOString(),
|
|
@@ -247,6 +378,7 @@ async function writeCodexModelCatalog(sidecar, modelCatalogPath) {
|
|
|
247
378
|
};
|
|
248
379
|
await writeFile(modelCatalogPath, `${JSON.stringify(catalog, null, 2)}\n`, { mode: 0o600 });
|
|
249
380
|
await writeFile(join(CODEX_HOME, "models_cache.json"), `${JSON.stringify(cache, null, 2)}\n`, { mode: 0o600 });
|
|
381
|
+
return limits;
|
|
250
382
|
}
|
|
251
383
|
|
|
252
384
|
function selectedModelAlias(state) {
|
|
@@ -52,7 +52,7 @@ export function toCodexModelInfo(item, priority = 0) {
|
|
|
52
52
|
const supportsTools = Boolean(item.supports_tools);
|
|
53
53
|
const supportsImages = Boolean(item.supports_images);
|
|
54
54
|
const supportsWebSearch = Boolean(item.supports_web_search);
|
|
55
|
-
const contextWindow = positiveNumber(item.context_window ?? item.context_window_tokens,
|
|
55
|
+
const contextWindow = positiveNumber(item.context_window ?? item.context_window_tokens, null);
|
|
56
56
|
const maxContextWindow = positiveNumber(item.max_context_window, contextWindow);
|
|
57
57
|
const reasoningLevels = Array.isArray(item.supported_reasoning_levels)
|
|
58
58
|
? item.supported_reasoning_levels
|
|
@@ -114,6 +114,21 @@ export function toCodexModelInfo(item, priority = 0) {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
export function codexModelRuntimeLimits(model) {
|
|
118
|
+
const contextWindow = positiveNumber(model?.context_window ?? model?.context_window_tokens, 0);
|
|
119
|
+
if (!contextWindow) {
|
|
120
|
+
throw new Error(`Codex model metadata is missing context_window for ${model?.slug ?? model?.alias ?? model?.id ?? "unknown model"}`);
|
|
121
|
+
}
|
|
122
|
+
const publishedCompactLimit = positiveNumber(model?.auto_compact_token_limit, 0);
|
|
123
|
+
if (!publishedCompactLimit) {
|
|
124
|
+
throw new Error(`Codex model metadata is missing auto_compact_token_limit for ${model?.slug ?? model?.alias ?? model?.id ?? "unknown model"}`);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
contextWindow,
|
|
128
|
+
autoCompactTokenLimit: publishedCompactLimit
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
117
132
|
function positiveNumber(value, defaultValue) {
|
|
118
133
|
const parsed = Number(value);
|
|
119
134
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultValue;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
|
|
4
|
-
import { rewriteRuntimeModel, toCodexModelInfo } from "./index.js";
|
|
4
|
+
import { codexModelRuntimeLimits, rewriteRuntimeModel, toCodexModelInfo } from "./index.js";
|
|
5
5
|
|
|
6
6
|
const CODEX_MODEL_INFO_FIELDS = [
|
|
7
7
|
"additional_speed_tiers",
|
|
@@ -178,3 +178,28 @@ test("keeps hosted web search for supported selected models", () => {
|
|
|
178
178
|
assert.equal(rewritten.model, "cx/gpt-5.5");
|
|
179
179
|
assert.deepEqual(rewritten.tools, [{ type: "web_search" }]);
|
|
180
180
|
});
|
|
181
|
+
|
|
182
|
+
test("uses published Codex compaction limit", () => {
|
|
183
|
+
const limits = codexModelRuntimeLimits({
|
|
184
|
+
slug: "cx/gpt-5.5",
|
|
185
|
+
context_window: 128000,
|
|
186
|
+
auto_compact_token_limit: 96000
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
assert.equal(limits.contextWindow, 128000);
|
|
190
|
+
assert.equal(limits.autoCompactTokenLimit, 96000);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("rejects Codex model metadata without a context window", () => {
|
|
194
|
+
assert.throws(
|
|
195
|
+
() => codexModelRuntimeLimits({ slug: "cx/missing" }),
|
|
196
|
+
/missing context_window/
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("rejects Codex model metadata without a published compaction limit", () => {
|
|
201
|
+
assert.throws(
|
|
202
|
+
() => codexModelRuntimeLimits({ slug: "cx/missing", context_window: 128000 }),
|
|
203
|
+
/missing auto_compact_token_limit/
|
|
204
|
+
);
|
|
205
|
+
});
|