@auroraflow/code 0.0.19 → 0.0.21
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 +11 -0
- package/package.json +1 -1
- package/packages/cli/src/index.js +76 -4
- package/packages/clients/src/index.js +171 -12
package/README.md
CHANGED
|
@@ -37,6 +37,10 @@ aurora update-clients
|
|
|
37
37
|
aurora install codex
|
|
38
38
|
aurora install claude
|
|
39
39
|
aurora install all
|
|
40
|
+
aurora repair codex
|
|
41
|
+
aurora repair claude
|
|
42
|
+
aurora doctor
|
|
43
|
+
aurora doctor --json
|
|
40
44
|
```
|
|
41
45
|
|
|
42
46
|
## Commands
|
|
@@ -50,6 +54,9 @@ node bin/aurora.js claude
|
|
|
50
54
|
node bin/aurora.js codex
|
|
51
55
|
node bin/aurora.js install codex
|
|
52
56
|
node bin/aurora.js install claude
|
|
57
|
+
node bin/aurora.js repair codex
|
|
58
|
+
node bin/aurora.js doctor
|
|
59
|
+
node bin/aurora.js doctor --json
|
|
53
60
|
node bin/aurora.js install-clients
|
|
54
61
|
node bin/aurora.js update-clients
|
|
55
62
|
node bin/aurora.js status
|
|
@@ -59,6 +66,10 @@ Running `aurora` without a subcommand opens an interactive client selector. Use
|
|
|
59
66
|
Up/Down (or `j`/`k`) and Enter to launch Claude or Codex through Aurora.
|
|
60
67
|
If the selected official client is missing, Aurora prompts to install that
|
|
61
68
|
specific client before launch.
|
|
69
|
+
If the package exists but its command is not usable, Aurora reports a broken
|
|
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.
|
|
62
73
|
|
|
63
74
|
The launcher stores shared local state under `~/.aurora` and starts a local
|
|
64
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, 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
|
|
|
@@ -28,9 +28,15 @@ export async function runAuroraCLI(argv = process.argv.slice(2)) {
|
|
|
28
28
|
officialClients: officialClientStatuses()
|
|
29
29
|
}, null, 2));
|
|
30
30
|
return;
|
|
31
|
+
case "doctor":
|
|
32
|
+
await doctorCommand(rest);
|
|
33
|
+
return;
|
|
31
34
|
case "install":
|
|
32
35
|
await installCommand(rest);
|
|
33
36
|
return;
|
|
37
|
+
case "repair":
|
|
38
|
+
await repairCommand(rest);
|
|
39
|
+
return;
|
|
34
40
|
case "install-clients":
|
|
35
41
|
case "install-official-clients":
|
|
36
42
|
case "update-clients":
|
|
@@ -93,6 +99,58 @@ async function installCommand(args) {
|
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
|
|
102
|
+
async function repairCommand(args) {
|
|
103
|
+
const target = args[0] ?? "";
|
|
104
|
+
switch (target) {
|
|
105
|
+
case "codex":
|
|
106
|
+
case "claude":
|
|
107
|
+
await repairOfficialClient(target);
|
|
108
|
+
console.log(JSON.stringify({ officialClients: officialClientStatuses() }, null, 2));
|
|
109
|
+
return;
|
|
110
|
+
case "all":
|
|
111
|
+
case "clients":
|
|
112
|
+
case "official-clients":
|
|
113
|
+
await repairOfficialClient("claude");
|
|
114
|
+
await repairOfficialClient("codex");
|
|
115
|
+
console.log(JSON.stringify({ officialClients: officialClientStatuses() }, null, 2));
|
|
116
|
+
return;
|
|
117
|
+
default:
|
|
118
|
+
console.error("Usage: aurora repair [codex|claude|all]");
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
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}`);
|
|
142
|
+
if (status.state === "broken") {
|
|
143
|
+
console.log(` fix: aurora repair ${status.id}`);
|
|
144
|
+
if (process.platform === "win32") {
|
|
145
|
+
console.log(` if locked: taskkill /F /IM ${status.id === "claude" ? "claude.exe" : "codex.exe"}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
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
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
96
154
|
export async function runAuroraClaude(argv = process.argv.slice(2)) {
|
|
97
155
|
await ensureLayout();
|
|
98
156
|
await runClient("claude", argv);
|
|
@@ -116,12 +174,22 @@ async function startInteractive(args) {
|
|
|
116
174
|
async function ensureOfficialClientForInteractive(client) {
|
|
117
175
|
const status = officialClientStatus(client);
|
|
118
176
|
if (status?.installed) return;
|
|
119
|
-
const
|
|
120
|
-
|
|
177
|
+
const broken = status?.state === "broken";
|
|
178
|
+
const action = await promptChoice(`${status?.name ?? client} ${broken ? "is installed but not usable" : "is not installed"}`, [
|
|
179
|
+
{ label: `${broken ? "Repair" : "Install"} ${status?.name ?? client} now`, value: broken ? "repair" : "install" },
|
|
180
|
+
{ label: "Show fix command", value: "manual" },
|
|
121
181
|
{ label: "Exit", value: "exit" }
|
|
122
182
|
]);
|
|
183
|
+
if (action === "manual") {
|
|
184
|
+
const command = broken ? `aurora repair ${client}` : `aurora install ${client}`;
|
|
185
|
+
throw new Error(`${status?.name ?? client} is required. Run: ${command}`);
|
|
186
|
+
}
|
|
187
|
+
if (action === "repair") {
|
|
188
|
+
await repairOfficialClient(client);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
123
191
|
if (action !== "install") {
|
|
124
|
-
throw new Error(`${status?.name ?? client} is required. Run: aurora install ${client}`);
|
|
192
|
+
throw new Error(`${status?.name ?? client} is required. Run: aurora ${broken ? "repair" : "install"} ${client}`);
|
|
125
193
|
}
|
|
126
194
|
await installOfficialClient(client);
|
|
127
195
|
}
|
|
@@ -204,6 +272,10 @@ function usage(exitCode) {
|
|
|
204
272
|
aurora install codex
|
|
205
273
|
aurora install claude
|
|
206
274
|
aurora install all
|
|
275
|
+
aurora repair codex
|
|
276
|
+
aurora repair claude
|
|
277
|
+
aurora doctor
|
|
278
|
+
aurora doctor --json
|
|
207
279
|
aurora install-clients
|
|
208
280
|
aurora update-clients
|
|
209
281
|
aurora status
|
|
@@ -67,14 +67,20 @@ export function officialClientStatuses() {
|
|
|
67
67
|
return Object.entries(OFFICIAL_CLIENTS).map(([id, client]) => {
|
|
68
68
|
const bin = resolveOfficialClientBin(client.binName);
|
|
69
69
|
const packagePath = officialClientPackageJSONPath(client.packageName);
|
|
70
|
-
const
|
|
70
|
+
const binVersion = readOfficialClientVersion(bin);
|
|
71
|
+
const packageVersion = packagePath ? JSON.parse(readFileSync(packagePath, "utf8")).version : null;
|
|
72
|
+
const state = bin && binVersion ? "installed" : packagePath ? "broken" : "missing";
|
|
71
73
|
return {
|
|
72
74
|
id,
|
|
73
75
|
name: client.name,
|
|
74
76
|
packageName: client.packageName,
|
|
75
77
|
bin,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
packagePath,
|
|
79
|
+
installed: state === "installed",
|
|
80
|
+
packagePresent: Boolean(packagePath),
|
|
81
|
+
state,
|
|
82
|
+
version: binVersion ?? packageVersion,
|
|
83
|
+
problem: officialClientProblem(state, bin, packagePath)
|
|
78
84
|
};
|
|
79
85
|
});
|
|
80
86
|
}
|
|
@@ -88,13 +94,25 @@ export async function installOfficialClients() {
|
|
|
88
94
|
await installOfficialClient("codex");
|
|
89
95
|
}
|
|
90
96
|
|
|
91
|
-
export async function installOfficialClient(client) {
|
|
97
|
+
export async function installOfficialClient(client, options = {}) {
|
|
92
98
|
const spec = OFFICIAL_CLIENTS[client];
|
|
93
99
|
if (!spec) throw new Error(`unknown official client: ${client}`);
|
|
100
|
+
const preflight = officialClientPreflight(client);
|
|
101
|
+
if (!preflight.ok) throw new Error(formatOfficialClientPreflightError(spec, preflight));
|
|
94
102
|
const npm = npmCommandSpec();
|
|
95
|
-
const args = ["install", "-g"
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
const args = ["install", "-g"];
|
|
104
|
+
if (options.repair) args.push("--force");
|
|
105
|
+
args.push(`${spec.packageName}@latest`);
|
|
106
|
+
console.error(`[aurora] ${options.repair ? "repairing" : "installing"} ${spec.name}: ${npm.command} ${[...npm.args, ...args].join(" ")}`);
|
|
107
|
+
try {
|
|
108
|
+
await spawnAndWait(npm.command, [...npm.args, ...args], { ...process.env });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
throw new Error(formatOfficialClientInstallError(spec, client, error));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function repairOfficialClient(client) {
|
|
115
|
+
await installOfficialClient(client, { repair: true });
|
|
98
116
|
}
|
|
99
117
|
|
|
100
118
|
export function isGlobalNpmLifecycle() {
|
|
@@ -105,14 +123,27 @@ export function officialClientStatus(client) {
|
|
|
105
123
|
return officialClientStatuses().find(status => status.id === client) ?? null;
|
|
106
124
|
}
|
|
107
125
|
|
|
126
|
+
export function officialClientsDoctor() {
|
|
127
|
+
return {
|
|
128
|
+
platform: process.platform,
|
|
129
|
+
npm: npmDoctor(),
|
|
130
|
+
disk: diskDoctor(),
|
|
131
|
+
processHints: processHints(),
|
|
132
|
+
officialClients: officialClientStatuses()
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
108
136
|
function officialClientBin(client) {
|
|
109
137
|
const spec = OFFICIAL_CLIENTS[client];
|
|
110
138
|
if (!spec) throw new Error(`unknown official client: ${client}`);
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
139
|
+
const status = officialClientStatus(client);
|
|
140
|
+
if (!status?.installed) {
|
|
141
|
+
if (status?.state === "broken") {
|
|
142
|
+
throw new Error(`${spec.name} is installed but not usable. Run: aurora doctor, then aurora repair ${client}`);
|
|
143
|
+
}
|
|
113
144
|
throw new Error(`${spec.name} is not installed. Run: aurora install ${client}`);
|
|
114
145
|
}
|
|
115
|
-
return bin;
|
|
146
|
+
return status.bin;
|
|
116
147
|
}
|
|
117
148
|
|
|
118
149
|
function resolveOfficialClientBin(binName) {
|
|
@@ -139,8 +170,136 @@ function findPathCommand(binName) {
|
|
|
139
170
|
|
|
140
171
|
function officialClientPackageJSONPath(packageName) {
|
|
141
172
|
const parts = packageName.startsWith("@") ? packageName.split("/") : [packageName];
|
|
142
|
-
const
|
|
143
|
-
|
|
173
|
+
for (const root of officialClientPackageRoots()) {
|
|
174
|
+
const packagePath = join(root, ...parts, "package.json");
|
|
175
|
+
if (existsSync(packagePath)) return packagePath;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function officialClientPackageRoots() {
|
|
181
|
+
const roots = [join(packageRoot, "node_modules")];
|
|
182
|
+
const npmBin = findPathCommand("npm");
|
|
183
|
+
if (npmBin) roots.push(join(dirname(npmBin), "node_modules"));
|
|
184
|
+
if (process.platform === "win32" && process.env.APPDATA) {
|
|
185
|
+
roots.push(join(process.env.APPDATA, "npm", "node_modules"));
|
|
186
|
+
}
|
|
187
|
+
return [...new Set(roots)];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function officialClientProblem(state, bin, packagePath) {
|
|
191
|
+
if (state === "installed") return null;
|
|
192
|
+
if (state === "missing") return "package_not_found";
|
|
193
|
+
if (!bin) return "package_present_but_command_not_found";
|
|
194
|
+
if (packagePath) return "command_found_but_version_check_failed";
|
|
195
|
+
return "unknown";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function officialClientPreflight(client) {
|
|
199
|
+
const disk = diskDoctor();
|
|
200
|
+
if (disk.availableBytes != null && disk.availableBytes < 512 * 1024 * 1024) {
|
|
201
|
+
return { ok: false, reason: "low_disk_space", disk };
|
|
202
|
+
}
|
|
203
|
+
const processes = processHints();
|
|
204
|
+
const locked = processes.find(item => item.client === client && item.running);
|
|
205
|
+
if (locked) return { ok: false, reason: "client_process_running", process: locked };
|
|
206
|
+
return { ok: true, disk, processes };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function npmDoctor() {
|
|
210
|
+
try {
|
|
211
|
+
const npm = npmCommandSpec();
|
|
212
|
+
const result = spawnSyncCompat(npm.command, [...npm.args, "--version"]);
|
|
213
|
+
return {
|
|
214
|
+
command: npm.command,
|
|
215
|
+
args: npm.args,
|
|
216
|
+
ok: result.status === 0,
|
|
217
|
+
version: String(result.stdout || result.stderr || "").trim() || null
|
|
218
|
+
};
|
|
219
|
+
} catch (error) {
|
|
220
|
+
return { ok: false, error: error?.message || String(error) };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function diskDoctor() {
|
|
225
|
+
if (process.platform !== "win32") return { checked: false, reason: "not_windows" };
|
|
226
|
+
try {
|
|
227
|
+
const drive = (process.env.APPDATA || process.cwd()).slice(0, 2);
|
|
228
|
+
const result = spawnSync("powershell.exe", [
|
|
229
|
+
"-NoProfile",
|
|
230
|
+
"-Command",
|
|
231
|
+
`(Get-PSDrive -Name ${JSON.stringify(drive.charAt(0))}).Free`
|
|
232
|
+
], { encoding: "utf8" });
|
|
233
|
+
const availableBytes = Number(String(result.stdout || "").trim());
|
|
234
|
+
return {
|
|
235
|
+
checked: true,
|
|
236
|
+
drive,
|
|
237
|
+
availableBytes: Number.isFinite(availableBytes) ? availableBytes : null,
|
|
238
|
+
availableMB: Number.isFinite(availableBytes) ? Math.floor(availableBytes / 1024 / 1024) : null
|
|
239
|
+
};
|
|
240
|
+
} catch (error) {
|
|
241
|
+
return { checked: false, error: error?.message || String(error) };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function processHints() {
|
|
246
|
+
if (process.platform !== "win32") return [];
|
|
247
|
+
return [
|
|
248
|
+
{ client: "claude", image: "claude.exe", running: isWindowsProcessRunning("claude.exe") },
|
|
249
|
+
{ client: "codex", image: "codex.exe", running: isWindowsProcessRunning("codex.exe") },
|
|
250
|
+
{ client: "codex", image: "node.exe", running: false, note: "Codex may run through node.exe depending on npm package version." }
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isWindowsProcessRunning(image) {
|
|
255
|
+
try {
|
|
256
|
+
const result = spawnSync("tasklist", ["/FI", `IMAGENAME eq ${image}`], { encoding: "utf8" });
|
|
257
|
+
return String(result.stdout || "").toLowerCase().includes(image.toLowerCase());
|
|
258
|
+
} catch {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function formatOfficialClientPreflightError(spec, preflight) {
|
|
264
|
+
if (preflight.reason === "low_disk_space") {
|
|
265
|
+
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.`;
|
|
266
|
+
}
|
|
267
|
+
if (preflight.reason === "client_process_running") {
|
|
268
|
+
return `${spec.name} repair/install blocked: ${preflight.process.image} is running. Close ${spec.name} or run: taskkill /F /IM ${preflight.process.image}`;
|
|
269
|
+
}
|
|
270
|
+
return `${spec.name} repair/install preflight failed: ${preflight.reason}`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function formatOfficialClientInstallError(spec, client, error) {
|
|
274
|
+
const message = error?.message || String(error);
|
|
275
|
+
const suggestions = officialClientFailureSuggestions(client, message);
|
|
276
|
+
return [`${spec.name} install/repair failed: ${message}`, ...suggestions].join("\n");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function officialClientFailureSuggestions(client, message) {
|
|
280
|
+
const text = String(message);
|
|
281
|
+
const image = client === "claude" ? "claude.exe" : "codex.exe";
|
|
282
|
+
if (/ENOSPC|no space left/i.test(text)) {
|
|
283
|
+
return [
|
|
284
|
+
"Detected cause: disk is full.",
|
|
285
|
+
"Fix: free disk space, then run: npm cache clean --force",
|
|
286
|
+
`Retry: aurora repair ${client}`
|
|
287
|
+
];
|
|
288
|
+
}
|
|
289
|
+
if (/EBUSY|EPERM|resource busy|operation not permitted/i.test(text)) {
|
|
290
|
+
return [
|
|
291
|
+
"Detected cause: files are locked by a running process or antivirus.",
|
|
292
|
+
process.platform === "win32" ? `Fix: close the client, then run: taskkill /F /IM ${image}` : "Fix: close the running client process.",
|
|
293
|
+
`Retry: aurora repair ${client}`
|
|
294
|
+
];
|
|
295
|
+
}
|
|
296
|
+
if (/ENOENT|not found/i.test(text)) {
|
|
297
|
+
return [
|
|
298
|
+
"Detected cause: npm or a required command was not found.",
|
|
299
|
+
"Fix: reinstall Node.js/npm or add npm to PATH, then retry."
|
|
300
|
+
];
|
|
301
|
+
}
|
|
302
|
+
return [`Run diagnostics: aurora doctor`, `Retry after fixing the reported issue: aurora repair ${client}`];
|
|
144
303
|
}
|
|
145
304
|
|
|
146
305
|
function readOfficialClientVersion(bin) {
|