@auroraflow/code 0.0.6 → 0.0.7

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.
@@ -0,0 +1,100 @@
1
+ import { readState, writeState } from "./state.js";
2
+
3
+ export async function login(email, password) {
4
+ const state = await readState();
5
+ const response = await fetch(`${trimSlash(state.controlPlaneURL)}/auth/login`, {
6
+ method: "POST",
7
+ headers: {
8
+ "content-type": "application/json",
9
+ "x-aurora-client": "cli"
10
+ },
11
+ body: JSON.stringify({ email, password })
12
+ });
13
+ const payload = await readJSON(response);
14
+ if (!response.ok) throw new Error(payload?.message || payload?.error?.message || `login failed: ${response.status}`);
15
+ const token = payload?.session?.token;
16
+ if (!token) throw new Error("login response did not include session token");
17
+ await writeState({ ...state, account: { sessionToken: token, user: payload.user ?? null } });
18
+ return payload;
19
+ }
20
+
21
+ export async function listModels() {
22
+ const state = await readState();
23
+ const response = await fetch(`${trimSlash(state.gatewayURL)}/v1/aurora-cli/models`, {
24
+ headers: selectedRuntimeHeaders(state)
25
+ });
26
+ const payload = await readJSON(response);
27
+ if (!response.ok) throw new Error(payload?.message || payload?.error?.message || `list models failed: ${response.status}`);
28
+ return Array.isArray(payload.data) ? payload.data : [];
29
+ }
30
+
31
+ export async function listKeys() {
32
+ const state = await readState();
33
+ const response = await fetch(`${trimSlash(state.controlPlaneURL)}/aurora-cli/api-keys`, {
34
+ headers: sessionHeaders(state)
35
+ });
36
+ const payload = await readJSON(response);
37
+ if (!response.ok) throw new Error(payload?.message || payload?.error?.message || `list keys failed: ${response.status}`);
38
+ return payload;
39
+ }
40
+
41
+ export async function revealKey(keyID) {
42
+ const state = await readState();
43
+ const response = await fetch(`${trimSlash(state.controlPlaneURL)}/aurora-cli/api-keys/${encodeURIComponent(keyID)}/reveal`, {
44
+ method: "POST",
45
+ headers: sessionHeaders(state)
46
+ });
47
+ const payload = await readJSON(response);
48
+ if (!response.ok) throw new Error(payload?.message || payload?.error?.message || `reveal key failed: ${response.status}`);
49
+ return payload;
50
+ }
51
+
52
+ export async function createKey({ keyKind, organizationID, label }) {
53
+ const state = await readState();
54
+ const body = {
55
+ key_kind: keyKind,
56
+ label
57
+ };
58
+ if (organizationID) {
59
+ body.organization_id = organizationID;
60
+ }
61
+ const response = await fetch(`${trimSlash(state.controlPlaneURL)}/aurora-cli/api-keys`, {
62
+ method: "POST",
63
+ headers: {
64
+ ...sessionHeaders(state),
65
+ "content-type": "application/json"
66
+ },
67
+ body: JSON.stringify(body)
68
+ });
69
+ const payload = await readJSON(response);
70
+ if (!response.ok) throw new Error(payload?.message || payload?.error?.message || `create key failed: ${response.status}`);
71
+ return payload;
72
+ }
73
+
74
+ function selectedRuntimeHeaders(state) {
75
+ const key = state.selectedKey?.presentedKey;
76
+ return key ? { authorization: `Bearer ${key}` } : {};
77
+ }
78
+
79
+ function sessionHeaders(state) {
80
+ const token = state.account?.sessionToken;
81
+ if (!token) throw new Error("Aurora login required. Run `aurora ctl login` first.");
82
+ return {
83
+ authorization: `Bearer ${token}`,
84
+ "x-aurora-client": "cli"
85
+ };
86
+ }
87
+
88
+ async function readJSON(response) {
89
+ const text = await response.text();
90
+ if (!text) return null;
91
+ try {
92
+ return JSON.parse(text);
93
+ } catch {
94
+ return { message: text };
95
+ }
96
+ }
97
+
98
+ function trimSlash(value) {
99
+ return String(value).replace(/\/+$/, "");
100
+ }
@@ -0,0 +1,27 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { CLAUDE_HOME } from "./state.js";
4
+
5
+ export async function installClaudeCommands() {
6
+ const commandsDir = join(CLAUDE_HOME, "commands");
7
+ await mkdir(commandsDir, { recursive: true });
8
+ await writeFile(join(commandsDir, "aurora.md"), commandFile("Open Aurora controls", "aurora ctl $ARGUMENTS"));
9
+ await writeFile(join(commandsDir, "aurora-model.md"), commandFile("Select Aurora model", "aurora ctl model $ARGUMENTS"));
10
+ await writeFile(join(commandsDir, "aurora-key.md"), commandFile("Select Aurora key", "aurora ctl key $ARGUMENTS"));
11
+ await writeFile(join(commandsDir, "aurora-status.md"), commandFile("Show Aurora status", "aurora ctl status"));
12
+ console.log(`Installed Claude commands into ${commandsDir}`);
13
+ }
14
+
15
+ function commandFile(description, command) {
16
+ return `---
17
+ description: ${description}
18
+ allowed-tools: Bash(aurora *)
19
+ ---
20
+
21
+ Run this command and report the result to the user:
22
+
23
+ \`\`\`bash
24
+ ${command}
25
+ \`\`\`
26
+ `;
27
+ }
@@ -0,0 +1,9 @@
1
+ import { runClient } from "../packages/clients/src/index.js";
2
+
3
+ export async function runClaude(args) {
4
+ await runClient("claude", args);
5
+ }
6
+
7
+ export async function runCodex(args) {
8
+ await runClient("codex", args);
9
+ }
package/lib/pickers.js ADDED
@@ -0,0 +1,137 @@
1
+ import { createKey, listKeys, listModels, login, revealKey } from "./aurora-api.js";
2
+ import { promptChoice, promptFields, promptLine } from "./prompt.js";
3
+ import { readState, writeState } from "./state.js";
4
+
5
+ export async function pickModel(args = []) {
6
+ const direct = args.join(" ").trim();
7
+ const state = await readState();
8
+ if (direct) {
9
+ await writeState({ ...state, selectedModel: { alias: direct, source: "manual" } });
10
+ console.log(`Selected model: ${direct}`);
11
+ return;
12
+ }
13
+ const models = await listModels();
14
+ if (models.length === 0) throw new Error("Aurora model catalog is empty");
15
+ const providers = unique(models.map(item => item.provider || "aurora")).sort();
16
+ const provider = await promptChoice("Provider", providers.map(value => ({ label: value, value })));
17
+ const providerModels = models
18
+ .filter(item => (item.provider || "aurora") === provider)
19
+ .sort((a, b) => String(a.model_id || a.alias || a.id).localeCompare(String(b.model_id || b.alias || b.id)));
20
+ const model = await promptChoice("Model", providerModels.map(item => ({
21
+ label: `${item.model_id || item.alias || item.id} ${item.display_name || ""}`.trim(),
22
+ value: item
23
+ })));
24
+ const alias = model.alias || model.id;
25
+ await writeState({ ...state, selectedModel: { alias, provider, modelID: model.model_id, source: "picker" } });
26
+ console.log(`Selected model: ${alias}`);
27
+ }
28
+
29
+ export async function pickKey(args = []) {
30
+ const direct = args.join(" ").trim();
31
+ const state = await readState();
32
+ if (direct) {
33
+ await writeState({ ...state, selectedKey: { presentedKey: direct, source: "manual" } });
34
+ console.log("Selected key updated.");
35
+ return;
36
+ }
37
+ const catalog = await listKeys();
38
+ const groups = Array.isArray(catalog.key_groups) ? catalog.key_groups : [];
39
+ const memberships = Array.isArray(catalog.memberships) ? catalog.memberships : [];
40
+ if (groups.length === 0) throw new Error("No Aurora key groups returned");
41
+ const group = await promptChoice("Key kind", groups.map(item => ({
42
+ label: keyKindLabel(item, memberships),
43
+ value: item
44
+ })));
45
+
46
+ let keys = Array.isArray(group.api_keys) ? group.api_keys : [];
47
+ let organization = null;
48
+ if (group.key_kind === "org") {
49
+ if (memberships.length === 0) throw new Error("No organization memberships are available");
50
+ organization = await promptChoice("Organization", memberships.map(item => {
51
+ const orgKeys = keys.filter(key => key.organization_id === item.organization_id);
52
+ return {
53
+ label: `${item.organization_name || item.organization_id} (${item.role || "member"} / ${orgKeys.length} keys)`,
54
+ value: item
55
+ };
56
+ }));
57
+ keys = keys.filter(key => key.organization_id === organization.organization_id);
58
+ }
59
+ const action = await promptChoice("Key", [
60
+ ...keys.map(item => ({
61
+ label: keyLabel(item),
62
+ value: { type: "existing", key: item }
63
+ })),
64
+ {
65
+ label: `Create new ${keyKindName(group.key_kind)} key`,
66
+ value: { type: "create" }
67
+ }
68
+ ]);
69
+
70
+ if (action.type === "create") {
71
+ const defaultLabel = `Aurora CLI ${Math.floor(Date.now() / 1000)}`;
72
+ const label = await promptLine(`New ${group.key_kind} key label`, defaultLabel);
73
+ const created = await createKey({
74
+ keyKind: group.key_kind,
75
+ organizationID: organization?.organization_id,
76
+ label
77
+ });
78
+ if (!created.api_key) throw new Error("create response did not include api_key");
79
+ if (!created.presented_key) throw new Error("create response did not include presented_key");
80
+ await saveSelectedKey(state, created.api_key, created.presented_key, "created");
81
+ console.log(`Created and selected key: ${created.api_key.label || created.api_key.id}`);
82
+ return;
83
+ }
84
+
85
+ const revealed = await revealKey(action.key.id);
86
+ if (!revealed.presented_key) throw new Error("reveal response did not include presented_key");
87
+ await saveSelectedKey(state, revealed.api_key || action.key, revealed.presented_key, "picker");
88
+ console.log(`Selected key: ${action.key.label || action.key.id}`);
89
+ }
90
+
91
+ function keyKindLabel(group, memberships) {
92
+ const keys = Array.isArray(group.api_keys) ? group.api_keys : [];
93
+ if (group.key_kind === "org") {
94
+ return `org (${memberships.length} organizations / ${keys.length} keys)`;
95
+ }
96
+ return `${group.key_kind} (${keys.length} keys)`;
97
+ }
98
+
99
+ export async function loginInteractive() {
100
+ const state = await readState();
101
+ const answers = await promptFields([
102
+ { name: "email", label: "Aurora email", defaultValue: state.account?.user?.email ?? "" },
103
+ { name: "password", label: "Aurora password", defaultValue: "" }
104
+ ]);
105
+ const payload = await login(answers.email, answers.password);
106
+ console.log(`Logged in as ${payload.user?.email || payload.user?.id || "Aurora user"}.`);
107
+ }
108
+
109
+ function keyLabel(item) {
110
+ const org = item.organization_name ? ` / ${item.organization_name}` : "";
111
+ const label = item.label || item.id;
112
+ const masked = item.masked_key ? ` ${item.masked_key}` : "";
113
+ return `${label}${org}${masked}`;
114
+ }
115
+
116
+ async function saveSelectedKey(state, key, presentedKey, source) {
117
+ await writeState({
118
+ ...state,
119
+ selectedKey: {
120
+ apiKeyID: key.id,
121
+ keyKind: key.key_kind,
122
+ organizationID: key.organization_id,
123
+ label: key.label,
124
+ presentedKey,
125
+ source
126
+ }
127
+ });
128
+ }
129
+
130
+ function keyKindName(value) {
131
+ if (value === "org") return "organization";
132
+ return value || "Aurora";
133
+ }
134
+
135
+ function unique(values) {
136
+ return [...new Set(values.filter(Boolean))];
137
+ }
package/lib/prompt.js ADDED
@@ -0,0 +1,136 @@
1
+ import { readFileSync } from "node:fs";
2
+ import * as readline from "node:readline";
3
+ import { createInterface } from "node:readline/promises";
4
+ import { stdin as input, stdout as output } from "node:process";
5
+
6
+ let pipedLines = null;
7
+ let pipedIndex = 0;
8
+
9
+ export async function promptLine(label, defaultValue = "") {
10
+ if (!input.isTTY) {
11
+ return nextPipedLine(defaultValue);
12
+ }
13
+ const rl = createInterface({ input, output });
14
+ const suffix = defaultValue ? ` [${defaultValue}]` : "";
15
+ const answer = await rl.question(`${label}${suffix}: `);
16
+ rl.close();
17
+ return answer.trim() || defaultValue;
18
+ }
19
+
20
+ export async function promptFields(fields) {
21
+ if (!input.isTTY) {
22
+ const out = {};
23
+ fields.forEach(field => {
24
+ const answer = nextPipedLine(field.defaultValue || "");
25
+ out[field.name] = answer || field.defaultValue || "";
26
+ });
27
+ return out;
28
+ }
29
+ const rl = createInterface({ input, output });
30
+ const out = {};
31
+ for (const field of fields) {
32
+ const suffix = field.defaultValue ? ` [${field.defaultValue}]` : "";
33
+ const answer = await rl.question(`${field.label}${suffix}: `);
34
+ out[field.name] = answer.trim() || field.defaultValue || "";
35
+ }
36
+ rl.close();
37
+ return out;
38
+ }
39
+
40
+ export async function chooseClient() {
41
+ if (!input.isTTY) {
42
+ const answer = nextPipedLine("claude").toLowerCase();
43
+ return answer === "codex" ? "codex" : "claude";
44
+ }
45
+ return terminalSelect("Choose client", [
46
+ { label: "Claude", value: "claude" },
47
+ { label: "Codex", value: "codex" }
48
+ ]);
49
+ }
50
+
51
+ export async function promptChoice(label, choices) {
52
+ if (!choices.length) throw new Error(`${label}: no choices available`);
53
+ if (!input.isTTY) {
54
+ const answer = nextPipedLine("1");
55
+ const index = Number(answer) - 1;
56
+ if (!Number.isInteger(index) || index < 0 || index >= choices.length) {
57
+ throw new Error(`invalid selection: ${answer}`);
58
+ }
59
+ return choices[index].value;
60
+ }
61
+ return terminalSelect(label, choices);
62
+ }
63
+
64
+ function terminalSelect(label, choices, defaultIndex = 0) {
65
+ if (!choices.length) throw new Error(`${label}: no choices available`);
66
+ let index = clamp(defaultIndex, 0, choices.length - 1);
67
+ let rendered = false;
68
+ const wasRaw = Boolean(input.isRaw);
69
+
70
+ readline.emitKeypressEvents(input);
71
+ if (input.setRawMode) input.setRawMode(true);
72
+ input.resume();
73
+ output.write("\x1b[?25l");
74
+ output.write(`${label}\n`);
75
+ renderChoices();
76
+
77
+ return new Promise(resolve => {
78
+ const onKeypress = (_chunk, key = {}) => {
79
+ if (key.ctrl && key.name === "c") {
80
+ cleanup();
81
+ output.write("\n");
82
+ process.exit(130);
83
+ }
84
+ if (key.name === "up" || key.name === "k") {
85
+ index = (index + choices.length - 1) % choices.length;
86
+ renderChoices();
87
+ return;
88
+ }
89
+ if (key.name === "down" || key.name === "j" || key.name === "tab") {
90
+ index = (index + 1) % choices.length;
91
+ renderChoices();
92
+ return;
93
+ }
94
+ if (key.name === "return" || key.name === "enter" || key.name === "space") {
95
+ const selected = choices[index].value;
96
+ cleanup();
97
+ output.write(`${selected}\n`);
98
+ resolve(selected);
99
+ }
100
+ };
101
+
102
+ input.on("keypress", onKeypress);
103
+
104
+ function cleanup() {
105
+ input.off("keypress", onKeypress);
106
+ if (input.setRawMode) input.setRawMode(wasRaw);
107
+ if (!wasRaw) input.pause();
108
+ output.write("\x1b[?25h");
109
+ }
110
+ });
111
+
112
+ function renderChoices() {
113
+ if (rendered) output.write(`\x1b[${choices.length}A`);
114
+ for (let i = 0; i < choices.length; i += 1) {
115
+ const selected = i === index;
116
+ const marker = selected ? "›" : " ";
117
+ const labelText = choices[i].label;
118
+ const line = selected ? `\x1b[36m${marker} ${labelText}\x1b[0m` : `${marker} ${labelText}`;
119
+ output.write(`\x1b[2K\r${line}\n`);
120
+ }
121
+ rendered = true;
122
+ }
123
+ }
124
+
125
+ function clamp(value, min, max) {
126
+ return Math.max(min, Math.min(max, value));
127
+ }
128
+
129
+ function nextPipedLine(defaultValue = "") {
130
+ if (pipedLines == null) {
131
+ pipedLines = readFileSync(0, "utf8").split(/\r?\n/);
132
+ }
133
+ const line = (pipedLines[pipedIndex] ?? "").trim();
134
+ pipedIndex += 1;
135
+ return line || defaultValue;
136
+ }
@@ -0,0 +1,10 @@
1
+ import { readSidecarInfo } from "./state.js";
2
+
3
+ export async function sidecarStatus() {
4
+ const info = await readSidecarInfo();
5
+ const response = await fetch(`${info.baseURL}/aurora/status`, {
6
+ headers: { authorization: `Bearer ${info.token}` }
7
+ });
8
+ if (!response.ok) throw new Error(`sidecar status failed: ${response.status}`);
9
+ return response.json();
10
+ }
package/lib/sidecar.js ADDED
@@ -0,0 +1 @@
1
+ export * from "../packages/sidecar/src/index.js";
package/lib/state.js ADDED
@@ -0,0 +1 @@
1
+ export * from "../packages/state/src/index.js";
package/package.json CHANGED
@@ -1,34 +1,25 @@
1
1
  {
2
2
  "name": "@auroraflow/code",
3
- "version": "0.0.6",
4
- "description": "Aurora Code is Aurora's local coding agent.",
5
- "license": "Apache-2.0",
3
+ "version": "0.0.7",
4
+ "type": "module",
5
+ "description": "Aurora launcher and sidecar for official Codex and Claude Code clients.",
6
6
  "bin": {
7
- "aurora": "bin/aurora.js"
7
+ "aurora": "bin/aurora.js",
8
+ "aurora-claude": "bin/aurora-claude.js",
9
+ "aurora-codex": "bin/aurora-codex.js",
10
+ "aurora-sidecar": "bin/aurora-sidecar.js"
8
11
  },
9
- "type": "module",
10
12
  "scripts": {
11
- "postinstall": "node scripts/install_posix_launcher.js"
13
+ "postinstall": "node bin/aurora-postinstall.js",
14
+ "check": "find bin lib packages -name '*.js' -print0 | xargs -0 -n1 node --check"
12
15
  },
13
16
  "engines": {
14
- "node": ">=16"
17
+ "node": ">=24"
15
18
  },
16
19
  "files": [
17
- "bin/aurora.js",
18
- "scripts/install_posix_launcher.js"
19
- ],
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/auroraflowintl/code.git",
23
- "directory": "codex-cli"
24
- },
25
- "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
26
- "optionalDependencies": {
27
- "@auroraflow/code-linux-x64": "0.0.6",
28
- "@auroraflow/code-linux-arm64": "0.0.6",
29
- "@auroraflow/code-darwin-x64": "0.0.6",
30
- "@auroraflow/code-darwin-arm64": "0.0.6",
31
- "@auroraflow/code-win32-x64": "0.0.6",
32
- "@auroraflow/code-win32-arm64": "0.0.6"
33
- }
20
+ "README.md",
21
+ "bin",
22
+ "packages",
23
+ "lib"
24
+ ]
34
25
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@aurora/cli",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.js"
8
+ }
9
+ }
@@ -0,0 +1,135 @@
1
+ import { ensureLayout, readAccount, readState, writeAccount, writeState } from "../../state/src/index.js";
2
+ import { officialClientStatuses, runClient, updateOfficialClients } from "../../clients/src/index.js";
3
+ import { chooseClient, promptFields } from "../../../lib/prompt.js";
4
+
5
+ export async function runAuroraCLI(argv = process.argv.slice(2)) {
6
+ await ensureLayout();
7
+ const command = argv[0] ?? "";
8
+ const rest = argv.slice(1);
9
+ switch (command) {
10
+ case "":
11
+ case "start":
12
+ await startInteractive(rest);
13
+ return;
14
+ case "init":
15
+ await init();
16
+ return;
17
+ case "claude":
18
+ await runClient("claude", rest);
19
+ return;
20
+ case "codex":
21
+ await runClient("codex", rest);
22
+ return;
23
+ case "status":
24
+ console.log(JSON.stringify({
25
+ account: maskAccount(await readAccount()),
26
+ runtime: await readState(),
27
+ officialClients: officialClientStatuses()
28
+ }, null, 2));
29
+ return;
30
+ case "install-clients":
31
+ case "install-official-clients":
32
+ case "update-clients":
33
+ case "upgrade-clients":
34
+ await updateOfficialClients();
35
+ console.log(JSON.stringify({ officialClients: officialClientStatuses() }, null, 2));
36
+ return;
37
+ default:
38
+ usage(1);
39
+ }
40
+ }
41
+
42
+ export async function runAuroraClaude(argv = process.argv.slice(2)) {
43
+ await ensureLayout();
44
+ await runClient("claude", argv);
45
+ }
46
+
47
+ export async function runAuroraCodex(argv = process.argv.slice(2)) {
48
+ await ensureLayout();
49
+ await runClient("codex", argv);
50
+ }
51
+
52
+ async function startInteractive(args) {
53
+ const account = await readAccount();
54
+ if (!account.sessionToken) {
55
+ await init();
56
+ }
57
+ const client = await chooseClient();
58
+ await runClient(client, args);
59
+ }
60
+
61
+ async function init() {
62
+ const existing = await readState();
63
+ const account = await readAccount();
64
+ const answers = await promptFields([
65
+ { name: "controlPlaneURL", label: "Aurora control-plane URL", defaultValue: account.controlPlaneURL ?? existing.controlPlaneURL ?? "https://auroramos.com/api/v1" },
66
+ { name: "gatewayURL", label: "Aurora gateway URL", defaultValue: account.gatewayURL ?? existing.gatewayURL ?? "https://auroramos.com" },
67
+ { name: "email", label: "Aurora email", defaultValue: account.user?.email ?? "" },
68
+ { name: "password", label: "Aurora password", defaultValue: "" },
69
+ { name: "presentedKey", label: "Initial Aurora API key", defaultValue: existing.selectedKey?.presentedKey ?? "" },
70
+ { name: "model", label: "Initial Aurora model alias", defaultValue: existing.selectedModel?.alias ?? "" }
71
+ ]);
72
+ const login = await loginAurora(answers.controlPlaneURL, answers.email, answers.password);
73
+ const sessionToken = login.session?.token?.trim();
74
+ if (!sessionToken) throw new Error("Aurora login did not return session.token");
75
+ await writeAccount({
76
+ controlPlaneURL: answers.controlPlaneURL,
77
+ gatewayURL: answers.gatewayURL,
78
+ sessionToken,
79
+ user: login.user ? {
80
+ id: login.user.id,
81
+ email: login.user.email,
82
+ name: login.user.display_name || login.user.email
83
+ } : null
84
+ });
85
+ await writeState({
86
+ ...existing,
87
+ controlPlaneURL: answers.controlPlaneURL,
88
+ gatewayURL: answers.gatewayURL,
89
+ selectedKey: answers.presentedKey ? { presentedKey: answers.presentedKey, source: "manual" } : existing.selectedKey,
90
+ selectedModel: answers.model ? { alias: answers.model, source: "manual" } : existing.selectedModel
91
+ });
92
+ console.log("Aurora local account and runtime state initialized.");
93
+ }
94
+
95
+ async function loginAurora(controlPlaneURL, email, password) {
96
+ if (!email.trim()) throw new Error("Aurora email is required");
97
+ if (!password.trim()) throw new Error("Aurora password is required");
98
+ const response = await fetch(`${trimSlash(controlPlaneURL)}/auth/login`, {
99
+ method: "POST",
100
+ headers: {
101
+ "content-type": "application/json",
102
+ "x-aurora-client": "cli"
103
+ },
104
+ body: JSON.stringify({ email, password })
105
+ });
106
+ const text = await response.text();
107
+ const payload = text ? JSON.parse(text) : {};
108
+ if (!response.ok) {
109
+ throw new Error(payload?.message || payload?.error?.message || `Aurora login failed: ${response.status}`);
110
+ }
111
+ return payload;
112
+ }
113
+
114
+ function trimSlash(value) {
115
+ return String(value).replace(/\/+$/, "");
116
+ }
117
+
118
+ function maskAccount(account) {
119
+ return {
120
+ ...account,
121
+ sessionToken: account.sessionToken ? "***" : null
122
+ };
123
+ }
124
+
125
+ function usage(exitCode) {
126
+ console.error(`Usage:
127
+ aurora
128
+ aurora init
129
+ aurora claude [args...]
130
+ aurora codex [args...]
131
+ aurora install-clients
132
+ aurora update-clients
133
+ aurora status`);
134
+ process.exit(exitCode);
135
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@aurora/clients",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.js"
8
+ }
9
+ }