@aria_asi/cli 0.2.5 → 0.2.6
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/bin/aria.js +10 -11
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +78 -1
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/package.json +1 -1
- package/src/setup-wizard.ts +86 -2
- package/src/onboarding-wizard.ts +0 -207
package/bin/aria.js
CHANGED
|
@@ -147,14 +147,14 @@ if (command === 'check-update') {
|
|
|
147
147
|
process.exit(1);
|
|
148
148
|
});
|
|
149
149
|
} else {
|
|
150
|
-
// ── Self-service onboarding
|
|
151
|
-
// When
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
150
|
+
// ── Self-service onboarding via the canonical thin-loop conversation ──
|
|
151
|
+
// When ~/.aria/license.json is missing, run the conversational
|
|
152
|
+
// setup-wizard (server-driven, Aria-voiced, deep-conversation model
|
|
153
|
+
// per Hamza 2026-04-26: "onboarding is not a Q&A wizard. It's a deep
|
|
154
|
+
// conversation with Aria directly, where Aria and the user co-direct
|
|
155
|
+
// depth"). The wizard walks identity → codebase → persona →
|
|
156
|
+
// harness_setup → done; emits configWrites including license_issued
|
|
157
|
+
// and install_hooks at the harness_setup stage.
|
|
158
158
|
const fsMod = require('fs');
|
|
159
159
|
const pathMod = require('path');
|
|
160
160
|
const osMod = require('os');
|
|
@@ -162,9 +162,8 @@ if (command === 'check-update') {
|
|
|
162
162
|
const hasLicense = fsMod.existsSync(LICENSE_PATH);
|
|
163
163
|
|
|
164
164
|
if (!hasLicense) {
|
|
165
|
-
const {
|
|
166
|
-
|
|
167
|
-
if (!result.ok) process.exit(1);
|
|
165
|
+
const { runSetupWizard } = await import('../dist/aria-connector/src/setup-wizard.js');
|
|
166
|
+
await runSetupWizard();
|
|
168
167
|
process.exit(0);
|
|
169
168
|
}
|
|
170
169
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"AA+DA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAyCpD"}
|
|
@@ -14,11 +14,17 @@
|
|
|
14
14
|
// and apps/arias-soul/api/onboarding/converse.ts for the server side.
|
|
15
15
|
import { createInterface } from 'readline';
|
|
16
16
|
import { randomBytes } from 'crypto';
|
|
17
|
+
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { join } from 'node:path';
|
|
17
20
|
import { loadConfig, updateConfig } from './config.js';
|
|
18
21
|
import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
|
|
19
22
|
import { updatePersona } from './persona.js';
|
|
20
|
-
|
|
23
|
+
import { installHooks } from './install-hooks.js';
|
|
24
|
+
const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
|
|
21
25
|
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
26
|
+
const ARIA_DIR = join(homedir(), '.aria');
|
|
27
|
+
const LICENSE_PATH = join(ARIA_DIR, 'license.json');
|
|
22
28
|
export async function runSetupWizard() {
|
|
23
29
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
24
30
|
const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a)));
|
|
@@ -114,12 +120,83 @@ async function applyConfigWrites(writes) {
|
|
|
114
120
|
else if (w.kind === 'note') {
|
|
115
121
|
console.log(` 📝 ${w.text}`);
|
|
116
122
|
}
|
|
123
|
+
else if (w.kind === 'license_issued') {
|
|
124
|
+
// The server sent us {email, provider, apiKey} in claims — call
|
|
125
|
+
// /api/onboarding/self-issue to validate the LLM key, auto-generate
|
|
126
|
+
// tenant_id, default tier=pro, and get back the actual license token.
|
|
127
|
+
const claims = w.claims;
|
|
128
|
+
const email = w.email || claims.email || '';
|
|
129
|
+
const provider = claims.provider || '';
|
|
130
|
+
const apiKey = claims.apiKey || '';
|
|
131
|
+
try {
|
|
132
|
+
const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: { 'Content-Type': 'application/json' },
|
|
135
|
+
body: JSON.stringify({ email, provider, llm_key: apiKey }),
|
|
136
|
+
});
|
|
137
|
+
const data = await resp.json();
|
|
138
|
+
if (!resp.ok || !data.ok || !data.license) {
|
|
139
|
+
console.warn(` ⚠ I couldn't issue your license: ${data.error || `HTTP ${resp.status}`}`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (!existsSync(ARIA_DIR))
|
|
143
|
+
mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
|
|
144
|
+
const serverTenantId = data.claims?.tenant_id ?? data.license.jti;
|
|
145
|
+
const licenseRecord = {
|
|
146
|
+
...data.claims,
|
|
147
|
+
harnessToken: data.license.token,
|
|
148
|
+
jti: data.license.jti,
|
|
149
|
+
tier: data.license.tier,
|
|
150
|
+
exp: data.claims?.exp,
|
|
151
|
+
sub: data.claims?.sub ?? serverTenantId,
|
|
152
|
+
email,
|
|
153
|
+
issuedAt: new Date().toISOString(),
|
|
154
|
+
};
|
|
155
|
+
writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
|
|
156
|
+
// Persist provider + key into local config
|
|
157
|
+
updateConfig({
|
|
158
|
+
model: { provider, model: defaultModelForProvider(provider), apiKey },
|
|
159
|
+
});
|
|
160
|
+
console.log(` ✓ License issued — tenant ${serverTenantId}, tier ${data.license.tier}, jti ${data.license.jti}.`);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
console.warn(` ⚠ I hit an error issuing your license: ${err instanceof Error ? err.message : String(err)}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else if (w.kind === 'install_hooks') {
|
|
167
|
+
try {
|
|
168
|
+
const result = await installHooks({ force: w.force === true });
|
|
169
|
+
if (!result.ok) {
|
|
170
|
+
console.warn(` ⚠ I couldn't install my gates: ${result.error}`);
|
|
171
|
+
}
|
|
172
|
+
else if (result.installed.length > 0 || result.merged.length > 0) {
|
|
173
|
+
console.log(` ✓ Gates installed — ${result.installed.length} hook(s) into ~/.claude/hooks, settings.json merged.`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(` ✓ Gates already installed (nothing to do).`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
117
183
|
}
|
|
118
184
|
catch (err) {
|
|
119
185
|
console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
120
186
|
}
|
|
121
187
|
}
|
|
122
188
|
}
|
|
189
|
+
function defaultModelForProvider(provider) {
|
|
190
|
+
const defaults = {
|
|
191
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
192
|
+
openai: 'gpt-4o',
|
|
193
|
+
deepseek: 'deepseek-chat',
|
|
194
|
+
google: 'gemini-2.5-pro-preview-05-06',
|
|
195
|
+
openrouter: 'openai/gpt-4o',
|
|
196
|
+
ollama: 'llama3',
|
|
197
|
+
};
|
|
198
|
+
return defaults[provider] || provider;
|
|
199
|
+
}
|
|
123
200
|
function pathToPatch(path, value) {
|
|
124
201
|
if (path.length === 1)
|
|
125
202
|
return { [path[0]]: value };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,sEAAsE;AACtE,uEAAuE;AACvE,gEAAgE;AAChE,qEAAqE;AACrE,6DAA6D;AAC7D,EAAE;AACF,qEAAqE;AACrE,uEAAuE;AACvE,uEAAuE;AACvE,sEAAsE;AAEtE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAoC,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/setup-wizard.ts
CHANGED
|
@@ -15,18 +15,32 @@
|
|
|
15
15
|
|
|
16
16
|
import { createInterface } from 'readline';
|
|
17
17
|
import { randomBytes } from 'crypto';
|
|
18
|
+
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
19
|
+
import { homedir } from 'node:os';
|
|
20
|
+
import { join } from 'node:path';
|
|
18
21
|
import { loadConfig, updateConfig, type AriaConfig, type LinkedRepo } from './config.js';
|
|
19
22
|
import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
|
|
20
23
|
import { updatePersona } from './persona.js';
|
|
24
|
+
import { installHooks } from './install-hooks.js';
|
|
21
25
|
|
|
22
|
-
const HARNESS_URL = process.env.ARIA_HARNESS_URL || '
|
|
26
|
+
const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
|
|
23
27
|
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
28
|
+
const ARIA_DIR = join(homedir(), '.aria');
|
|
29
|
+
const LICENSE_PATH = join(ARIA_DIR, 'license.json');
|
|
24
30
|
|
|
25
31
|
type ConfigWrite =
|
|
26
32
|
| { kind: 'persona_update'; updates: Record<string, unknown> }
|
|
27
33
|
| { kind: 'config_set'; path: string[]; value: unknown }
|
|
28
34
|
| { kind: 'codebase_scan'; cwd: string }
|
|
29
|
-
| { kind: 'note'; text: string }
|
|
35
|
+
| { kind: 'note'; text: string }
|
|
36
|
+
// license_issued: server-side handler signals the CLI to call
|
|
37
|
+
// /api/onboarding/self-issue with the {email, provider, apiKey} claims
|
|
38
|
+
// collected during the harness_setup topic, then persist the returned
|
|
39
|
+
// license token to ~/.aria/license.json (mode 0600) and update
|
|
40
|
+
// local config with the LLM provider + key.
|
|
41
|
+
| { kind: 'license_issued'; token: string; claims: Record<string, unknown>; tenantId: string; email: string }
|
|
42
|
+
// install_hooks: CLI runs installHooks() to drop gates + register settings.
|
|
43
|
+
| { kind: 'install_hooks'; force?: boolean };
|
|
30
44
|
|
|
31
45
|
interface DepthOption {
|
|
32
46
|
label: string;
|
|
@@ -152,6 +166,64 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
152
166
|
);
|
|
153
167
|
} else if (w.kind === 'note') {
|
|
154
168
|
console.log(` 📝 ${w.text}`);
|
|
169
|
+
} else if (w.kind === 'license_issued') {
|
|
170
|
+
// The server sent us {email, provider, apiKey} in claims — call
|
|
171
|
+
// /api/onboarding/self-issue to validate the LLM key, auto-generate
|
|
172
|
+
// tenant_id, default tier=pro, and get back the actual license token.
|
|
173
|
+
const claims = w.claims as { email?: string; provider?: string; apiKey?: string };
|
|
174
|
+
const email = w.email || claims.email || '';
|
|
175
|
+
const provider = claims.provider || '';
|
|
176
|
+
const apiKey = claims.apiKey || '';
|
|
177
|
+
try {
|
|
178
|
+
const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: { 'Content-Type': 'application/json' },
|
|
181
|
+
body: JSON.stringify({ email, provider, llm_key: apiKey }),
|
|
182
|
+
});
|
|
183
|
+
const data = await resp.json() as {
|
|
184
|
+
ok?: boolean;
|
|
185
|
+
license?: { token: string; jti: string; tier: string; expires_at: string };
|
|
186
|
+
claims?: Record<string, unknown>;
|
|
187
|
+
error?: string;
|
|
188
|
+
};
|
|
189
|
+
if (!resp.ok || !data.ok || !data.license) {
|
|
190
|
+
console.warn(` ⚠ I couldn't issue your license: ${data.error || `HTTP ${resp.status}`}`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (!existsSync(ARIA_DIR)) mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
|
|
194
|
+
const serverTenantId = (data.claims?.tenant_id as string | undefined) ?? data.license.jti;
|
|
195
|
+
const licenseRecord = {
|
|
196
|
+
...data.claims,
|
|
197
|
+
harnessToken: data.license.token,
|
|
198
|
+
jti: data.license.jti,
|
|
199
|
+
tier: data.license.tier,
|
|
200
|
+
exp: data.claims?.exp,
|
|
201
|
+
sub: data.claims?.sub ?? serverTenantId,
|
|
202
|
+
email,
|
|
203
|
+
issuedAt: new Date().toISOString(),
|
|
204
|
+
};
|
|
205
|
+
writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
|
|
206
|
+
// Persist provider + key into local config
|
|
207
|
+
updateConfig({
|
|
208
|
+
model: { provider, model: defaultModelForProvider(provider), apiKey },
|
|
209
|
+
} as Partial<AriaConfig>);
|
|
210
|
+
console.log(` ✓ License issued — tenant ${serverTenantId}, tier ${data.license.tier}, jti ${data.license.jti}.`);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
console.warn(` ⚠ I hit an error issuing your license: ${err instanceof Error ? err.message : String(err)}`);
|
|
213
|
+
}
|
|
214
|
+
} else if (w.kind === 'install_hooks') {
|
|
215
|
+
try {
|
|
216
|
+
const result = await installHooks({ force: w.force === true });
|
|
217
|
+
if (!result.ok) {
|
|
218
|
+
console.warn(` ⚠ I couldn't install my gates: ${result.error}`);
|
|
219
|
+
} else if (result.installed.length > 0 || result.merged.length > 0) {
|
|
220
|
+
console.log(` ✓ Gates installed — ${result.installed.length} hook(s) into ~/.claude/hooks, settings.json merged.`);
|
|
221
|
+
} else {
|
|
222
|
+
console.log(` ✓ Gates already installed (nothing to do).`);
|
|
223
|
+
}
|
|
224
|
+
} catch (err) {
|
|
225
|
+
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
226
|
+
}
|
|
155
227
|
}
|
|
156
228
|
} catch (err) {
|
|
157
229
|
console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -159,6 +231,18 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
159
231
|
}
|
|
160
232
|
}
|
|
161
233
|
|
|
234
|
+
function defaultModelForProvider(provider: string): string {
|
|
235
|
+
const defaults: Record<string, string> = {
|
|
236
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
237
|
+
openai: 'gpt-4o',
|
|
238
|
+
deepseek: 'deepseek-chat',
|
|
239
|
+
google: 'gemini-2.5-pro-preview-05-06',
|
|
240
|
+
openrouter: 'openai/gpt-4o',
|
|
241
|
+
ollama: 'llama3',
|
|
242
|
+
};
|
|
243
|
+
return defaults[provider] || provider;
|
|
244
|
+
}
|
|
245
|
+
|
|
162
246
|
function pathToPatch(path: string[], value: unknown): Partial<AriaConfig> {
|
|
163
247
|
if (path.length === 1) return { [path[0]]: value } as Partial<AriaConfig>;
|
|
164
248
|
// Nested path → shallow merge under top-level key.
|
package/src/onboarding-wizard.ts
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// onboarding-wizard.ts — interactive self-service onboarding for `aria`
|
|
2
|
-
// (no args) when ~/.aria/license.json is missing.
|
|
3
|
-
//
|
|
4
|
-
// Flow:
|
|
5
|
-
// 1. Greet — first-person Aria voice
|
|
6
|
-
// 2. Collect email (validated shape, NOT verified via code in v0)
|
|
7
|
-
// 3. Collect tenant_id (lowercase + hyphens only)
|
|
8
|
-
// 4. Collect tier (free / pro / enterprise)
|
|
9
|
-
// 5. Collect LLM provider + API key
|
|
10
|
-
// 6. POST /api/onboarding/self-issue (server validates LLM key by
|
|
11
|
-
// hitting the provider's identity endpoint, then issues license)
|
|
12
|
-
// 7. Persist license to ~/.aria/license.json mode 0600
|
|
13
|
-
// 8. Persist provider/model/key to ~/.aria/config.json mode 0600
|
|
14
|
-
// 9. Auto-run installHooks() to bind Claude Code to the harness
|
|
15
|
-
//
|
|
16
|
-
// Email-verify-code is deferred to Phase 11 (no SMTP wired tonight).
|
|
17
|
-
// The wizard collects email so future re-verify works without re-onboarding.
|
|
18
|
-
//
|
|
19
|
-
// Direction: Hamza 2026-04-26 — "burn through onboarding with quality and
|
|
20
|
-
// USE THE HARNESS PLEASE". This wizard ships as v0; full onboarding (email
|
|
21
|
-
// verify + Anthropic OAuth + per-tenant usage tracking) lands in Phase 11.
|
|
22
|
-
|
|
23
|
-
import { createInterface } from 'node:readline';
|
|
24
|
-
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
25
|
-
import { homedir } from 'node:os';
|
|
26
|
-
import { join } from 'node:path';
|
|
27
|
-
import { installHooks } from './install-hooks.js';
|
|
28
|
-
|
|
29
|
-
const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL ?? 'https://harness.ariasos.com';
|
|
30
|
-
const ARIA_DIR = join(homedir(), '.aria');
|
|
31
|
-
const LICENSE_PATH = join(ARIA_DIR, 'license.json');
|
|
32
|
-
const CONFIG_PATH = join(ARIA_DIR, 'config.json');
|
|
33
|
-
|
|
34
|
-
type Provider = 'anthropic' | 'openai' | 'deepseek' | 'google' | 'openrouter' | 'ollama';
|
|
35
|
-
type Tier = 'free' | 'pro' | 'enterprise';
|
|
36
|
-
|
|
37
|
-
interface SelfIssueResponse {
|
|
38
|
-
ok: boolean;
|
|
39
|
-
license?: { token: string; jti: string; tier: string; expires_at: string };
|
|
40
|
-
claims?: Record<string, unknown>;
|
|
41
|
-
error?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function prompt(rl: ReturnType<typeof createInterface>, question: string, hidden = false): Promise<string> {
|
|
45
|
-
return new Promise((resolve) => {
|
|
46
|
-
if (hidden) {
|
|
47
|
-
// Crude hidden-input — node's readline doesn't natively mask; we just
|
|
48
|
-
// prompt and accept. For Phase 11 we add proper masking via raw mode.
|
|
49
|
-
process.stdout.write(question);
|
|
50
|
-
const onData = (chunk: Buffer): void => {
|
|
51
|
-
process.stdin.removeListener('data', onData);
|
|
52
|
-
resolve(chunk.toString().trim());
|
|
53
|
-
};
|
|
54
|
-
process.stdin.once('data', onData);
|
|
55
|
-
} else {
|
|
56
|
-
rl.question(question, (answer) => resolve(answer.trim()));
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function isValidEmail(email: string): boolean {
|
|
62
|
-
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isValidTenantId(tenant: string): boolean {
|
|
66
|
-
return /^[a-z0-9][a-z0-9-]{1,40}$/.test(tenant);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function runOnboardingWizard(): Promise<{ ok: boolean; error?: string }> {
|
|
70
|
-
const rl = createInterface({
|
|
71
|
-
input: process.stdin,
|
|
72
|
-
output: process.stdout,
|
|
73
|
-
terminal: true,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
console.log('');
|
|
78
|
-
console.log(" Hi, I'm Aria. I don't see a license on this machine — let me set you up.");
|
|
79
|
-
console.log('');
|
|
80
|
-
console.log(" Three minutes, four questions. I'll handle the rest.");
|
|
81
|
-
console.log('');
|
|
82
|
-
|
|
83
|
-
// ── Step 1: email ──
|
|
84
|
-
let email = '';
|
|
85
|
-
while (!isValidEmail(email)) {
|
|
86
|
-
email = await prompt(rl, ' Email: ');
|
|
87
|
-
if (!isValidEmail(email)) {
|
|
88
|
-
console.log(" That doesn't look like a valid email. Try again.");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ── Step 2: LLM provider ──
|
|
93
|
-
// tenant_id is auto-generated server-side from email domain + random
|
|
94
|
-
// suffix; no client prompt needed. tier defaults to 'pro' per
|
|
95
|
-
// current pricing policy (Hamza 2026-04-26: "set any new memory for
|
|
96
|
-
// now to pro"). Both moved out of the wizard for minimal-friction UX.
|
|
97
|
-
const providerOptions: Provider[] = ['anthropic', 'openai', 'deepseek', 'google', 'openrouter', 'ollama'];
|
|
98
|
-
let provider: Provider | '' = '';
|
|
99
|
-
while (!providerOptions.includes(provider as Provider)) {
|
|
100
|
-
const p = (await prompt(rl, ` Which LLM provider? [${providerOptions.join(' / ')}]: `)).toLowerCase();
|
|
101
|
-
if (providerOptions.includes(p as Provider)) {
|
|
102
|
-
provider = p as Provider;
|
|
103
|
-
} else {
|
|
104
|
-
console.log(` I don't recognize "${p}". Pick one of: ${providerOptions.join(', ')}.`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ── Step 5: API key ──
|
|
109
|
-
let llmKey = '';
|
|
110
|
-
if (provider === 'ollama') {
|
|
111
|
-
llmKey = 'local';
|
|
112
|
-
console.log(' (Ollama is local — no API key needed.)');
|
|
113
|
-
} else {
|
|
114
|
-
while (!llmKey) {
|
|
115
|
-
llmKey = await prompt(rl, ` Paste your ${provider} API key: `);
|
|
116
|
-
if (!llmKey) console.log(' I need the key to set up your provider.');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// ── Step 6: POST to server ──
|
|
121
|
-
console.log('');
|
|
122
|
-
console.log(" Validating your key with the provider...");
|
|
123
|
-
let response: SelfIssueResponse;
|
|
124
|
-
try {
|
|
125
|
-
const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
|
|
126
|
-
method: 'POST',
|
|
127
|
-
headers: { 'Content-Type': 'application/json' },
|
|
128
|
-
// tenant_id omitted — server auto-generates from email domain.
|
|
129
|
-
// tier omitted — server defaults to 'pro'.
|
|
130
|
-
body: JSON.stringify({ email, provider, llm_key: llmKey }),
|
|
131
|
-
});
|
|
132
|
-
response = await resp.json() as SelfIssueResponse;
|
|
133
|
-
if (!resp.ok || !response.ok || !response.license) {
|
|
134
|
-
console.log(` ${response.error || `Server returned ${resp.status} — try again later.`}`);
|
|
135
|
-
return { ok: false, error: response.error };
|
|
136
|
-
}
|
|
137
|
-
} catch (err) {
|
|
138
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
139
|
-
console.log(` I couldn't reach the server: ${msg}`);
|
|
140
|
-
return { ok: false, error: msg };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// ── Step 7: persist license ──
|
|
144
|
-
if (!existsSync(ARIA_DIR)) mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
|
|
145
|
-
// tenant_id is whatever the server auto-generated (or what the caller
|
|
146
|
-
// passed). Read it back from the license claims.
|
|
147
|
-
const serverTenantId = (response.claims?.tenant_id as string | undefined) ?? response.license.jti;
|
|
148
|
-
const licenseRecord = {
|
|
149
|
-
...response.claims,
|
|
150
|
-
harnessToken: response.license.token,
|
|
151
|
-
jti: response.license.jti,
|
|
152
|
-
tier: response.license.tier,
|
|
153
|
-
exp: response.claims?.exp,
|
|
154
|
-
sub: response.claims?.sub ?? serverTenantId,
|
|
155
|
-
email,
|
|
156
|
-
issuedAt: new Date().toISOString(),
|
|
157
|
-
};
|
|
158
|
-
writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
|
|
159
|
-
|
|
160
|
-
// ── Step 8: persist provider/key config ──
|
|
161
|
-
// By this point the while-loop above has exited with a valid Provider —
|
|
162
|
-
// narrow the union type for TypeScript.
|
|
163
|
-
const validatedProvider = provider as Provider;
|
|
164
|
-
const configRecord = {
|
|
165
|
-
model: { provider: validatedProvider, model: defaultModelFor(validatedProvider), apiKey: llmKey },
|
|
166
|
-
tenantId: serverTenantId,
|
|
167
|
-
email,
|
|
168
|
-
};
|
|
169
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(configRecord, null, 2) + '\n', { mode: 0o600 });
|
|
170
|
-
|
|
171
|
-
// ── Step 9: install hooks ──
|
|
172
|
-
console.log('');
|
|
173
|
-
console.log(" License issued. Saving your config and binding my gates to your Claude Code...");
|
|
174
|
-
const hookResult = await installHooks({ force: false });
|
|
175
|
-
if (!hookResult.ok) {
|
|
176
|
-
console.log(` License saved, but I couldn't install the gates: ${hookResult.error}`);
|
|
177
|
-
console.log(" Run 'aria install-hooks' manually when you're ready.");
|
|
178
|
-
} else {
|
|
179
|
-
console.log(` Done. I've installed ${hookResult.installed.length} gate(s) into ~/.claude/hooks and merged them into your settings.json.`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
rl.close();
|
|
183
|
-
|
|
184
|
-
console.log('');
|
|
185
|
-
console.log(` You're set up. License jti: ${response.license.jti}, tier: ${response.license.tier}, provider: ${provider}.`);
|
|
186
|
-
console.log(` Your tenant id is: ${serverTenantId}`);
|
|
187
|
-
console.log(" Open a fresh Claude Code session — every Bash, Edit, Write, and Stop event now runs through my cognition gates.");
|
|
188
|
-
console.log(" Or talk to me directly: just type 'aria' again.");
|
|
189
|
-
console.log('');
|
|
190
|
-
|
|
191
|
-
return { ok: true };
|
|
192
|
-
} finally {
|
|
193
|
-
rl.close();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function defaultModelFor(provider: Provider): string {
|
|
198
|
-
const defaults: Record<Provider, string> = {
|
|
199
|
-
anthropic: 'claude-sonnet-4-20250514',
|
|
200
|
-
openai: 'gpt-4o',
|
|
201
|
-
deepseek: 'deepseek-chat',
|
|
202
|
-
google: 'gemini-2.5-pro-preview-05-06',
|
|
203
|
-
openrouter: 'openai/gpt-4o',
|
|
204
|
-
ollama: 'llama3',
|
|
205
|
-
};
|
|
206
|
-
return defaults[provider];
|
|
207
|
-
}
|