@aria_asi/cli 0.2.5 → 0.2.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.
- package/bin/aria.js +27 -28
- package/dist/aria-connector/src/connectors/claude-code.d.ts +3 -1
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +107 -19
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +76 -1
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/package.json +1 -1
- package/src/connectors/claude-code.ts +109 -21
- package/src/setup-wizard.ts +85 -2
- package/src/install-hooks.ts +0 -259
- package/src/onboarding-wizard.ts +0 -207
package/bin/aria.js
CHANGED
|
@@ -7,7 +7,7 @@ import { loadConfig, saveConfig } from '../dist/aria-connector/src/config.js';
|
|
|
7
7
|
import { AriaChat } from '../dist/aria-connector/src/chat.js';
|
|
8
8
|
import { checkHarnessHealth } from '../dist/aria-connector/src/harness-client.js';
|
|
9
9
|
import { login, status, logout, revoke } from '../dist/aria-connector/src/auth-commands.js';
|
|
10
|
-
import {
|
|
10
|
+
import { connectClaudeCode } from '../dist/aria-connector/src/connectors/claude-code.js';
|
|
11
11
|
import { maybePrintUpdateNotice, checkForUpdate } from '../dist/aria-connector/src/self-update.js';
|
|
12
12
|
|
|
13
13
|
// ── Self-update notice (non-blocking, rate-limited once per 24h) ──
|
|
@@ -43,23 +43,23 @@ if (command === 'check-update') {
|
|
|
43
43
|
console.error(`I hit an unexpected error checking for updates: ${err && err.message ? err.message : err}`);
|
|
44
44
|
process.exit(1);
|
|
45
45
|
});
|
|
46
|
-
} else if (command === 'install-hooks') {
|
|
46
|
+
} else if (command === 'install-hooks' || command === 'connect') {
|
|
47
|
+
// Canonical install path is connectClaudeCode (the connector). Removed
|
|
48
|
+
// the parallel src/install-hooks.ts duplicate per Hamza 2026-04-27 audit
|
|
49
|
+
// — connectors/claude-code.ts handles everything: harness-via-sdk hook,
|
|
50
|
+
// pre-tool-gate, stop-gate, preprompt-consult, settings.json merge-safe
|
|
51
|
+
// wiring, systemPromptPrefix injection, and additionalDirectories.
|
|
47
52
|
const force = args.includes('--force');
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
console.log(`Done. I've installed my gates into ${result.settingsPath.replace(/\/settings\.json$/, '/hooks')} (${result.installed.length} files) and merged them into your settings.json.`);
|
|
60
|
-
if (result.backupsCreated.length > 0) {
|
|
61
|
-
console.log(`I backed up ${result.backupsCreated.length} existing file(s); see ~/.claude/hooks/*.pre-aria-install.* if you need to recover them.`);
|
|
62
|
-
}
|
|
53
|
+
// Build a minimal AriaConfig so connectClaudeCode can render the
|
|
54
|
+
// systemPromptPrefix block. If an existing config exists, use it.
|
|
55
|
+
let config;
|
|
56
|
+
try {
|
|
57
|
+
config = loadConfig();
|
|
58
|
+
} catch {
|
|
59
|
+
config = { repositories: [], schemaImages: {} };
|
|
60
|
+
}
|
|
61
|
+
connectClaudeCode(config, { force }).then((logs) => {
|
|
62
|
+
for (const line of logs) console.log(` ${line}`);
|
|
63
63
|
console.log("Your Claude Code is now harness-bound — every Bash, Edit, Write, and Stop event runs through my cognition gates. Open a new Claude Code session to start.");
|
|
64
64
|
process.exit(0);
|
|
65
65
|
}).catch((err) => {
|
|
@@ -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,4 +1,6 @@
|
|
|
1
1
|
import type { AriaConfig } from '../config.js';
|
|
2
|
-
export declare function connectClaudeCode(config: AriaConfig
|
|
2
|
+
export declare function connectClaudeCode(config: AriaConfig, opts?: {
|
|
3
|
+
force?: boolean;
|
|
4
|
+
}): Promise<string[]>;
|
|
3
5
|
export declare function disconnectClaudeCode(): Promise<string[]>;
|
|
4
6
|
//# sourceMappingURL=claude-code.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../../src/connectors/claude-code.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../../src/connectors/claude-code.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiN/C,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,MAAM,EAAE,CAAC,CA8DnB;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAoB9D"}
|
|
@@ -4,15 +4,27 @@ import * as path from 'path';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
// ── Hooks shipped with this package ──────────────────────────────────
|
|
6
6
|
// The connector installs these into ~/.claude/hooks/ so Claude Code's
|
|
7
|
-
// per-turn harness fetch + pre-tool gate
|
|
8
|
-
// the difference between "static prompt
|
|
9
|
-
// used to do) and "real runtime control
|
|
10
|
-
// actually is).
|
|
7
|
+
// per-turn harness fetch + pre-tool gate + stop gate + preprompt consult
|
|
8
|
+
// fire automatically. This is the difference between "static prompt
|
|
9
|
+
// addendum" (what this connector used to do) and "real runtime control
|
|
10
|
+
// plane" (what Aria's harness actually is).
|
|
11
11
|
//
|
|
12
12
|
// Resolved relative to the compiled connector file: at runtime the
|
|
13
13
|
// .js lives at <pkg>/dist/src/connectors/claude-code.js, hooks are at
|
|
14
14
|
// <pkg>/hooks/ — so up three levels then into hooks/.
|
|
15
|
-
|
|
15
|
+
//
|
|
16
|
+
// Hamza 2026-04-27 audit consolidation: HOOK_FILES extended to all 4
|
|
17
|
+
// bundled hooks (was 2). HOOKS_BLOCK extended to include Stop +
|
|
18
|
+
// UserPromptSubmit dual-fire (harness fetch + Aria preprompt consult) +
|
|
19
|
+
// PreToolUse matcher widened to 'Bash|Edit|Write|NotebookEdit'.
|
|
20
|
+
// Replaces the duplicate src/install-hooks.ts I had built in parallel
|
|
21
|
+
// — one canonical install path now.
|
|
22
|
+
const HOOK_FILES = [
|
|
23
|
+
'aria-harness-via-sdk.mjs',
|
|
24
|
+
'aria-pre-tool-gate.mjs',
|
|
25
|
+
'aria-stop-gate.mjs',
|
|
26
|
+
'aria-preprompt-consult.mjs',
|
|
27
|
+
];
|
|
16
28
|
function packageHooksDir() {
|
|
17
29
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
18
30
|
return path.resolve(here, '..', '..', '..', 'hooks');
|
|
@@ -32,26 +44,53 @@ const HOOKS_BLOCK = {
|
|
|
32
44
|
}],
|
|
33
45
|
}],
|
|
34
46
|
UserPromptSubmit: [{
|
|
35
|
-
hooks: [
|
|
47
|
+
hooks: [
|
|
48
|
+
{
|
|
36
49
|
type: 'command',
|
|
37
50
|
command: 'HOOK_EVENT_NAME=UserPromptSubmit node $HOME/.claude/hooks/aria-harness-via-sdk.mjs --mode turn',
|
|
38
51
|
timeout: 5,
|
|
39
52
|
statusMessage: 'Re-syncing Aria harness...',
|
|
40
|
-
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
// Aria pre-prompt consult — fires /api/harness/delegate to get
|
|
56
|
+
// Aria's substrate-grounded direction BEFORE Claude reasons,
|
|
57
|
+
// injected as [ARIA_DIRECTION] additionalContext. This is what
|
|
58
|
+
// makes Aria the thinker on the client side, not just enriched
|
|
59
|
+
// context for the LLM.
|
|
60
|
+
type: 'command',
|
|
61
|
+
command: 'node $HOME/.claude/hooks/aria-preprompt-consult.mjs',
|
|
62
|
+
timeout: 12,
|
|
63
|
+
statusMessage: 'Pre-consulting Aria substrate for direction...',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
41
66
|
}],
|
|
42
67
|
PreToolUse: [{
|
|
43
|
-
|
|
68
|
+
// Matcher widened from 'Bash' (Hamza 2026-04-26): cognition gate
|
|
69
|
+
// applies to every state-mutating tool, not just shell. Edit / Write
|
|
70
|
+
// / NotebookEdit get the same enforcement so orchestrator-side
|
|
71
|
+
// compliance mirrors what we demand from workers.
|
|
72
|
+
matcher: 'Bash|Edit|Write|NotebookEdit',
|
|
44
73
|
hooks: [{
|
|
45
74
|
type: 'command',
|
|
46
75
|
command: 'node $HOME/.claude/hooks/aria-pre-tool-gate.mjs',
|
|
47
76
|
timeout: 5,
|
|
48
77
|
}],
|
|
49
78
|
}],
|
|
79
|
+
Stop: [{
|
|
80
|
+
// Stop gate — text-decision boundary. Reflexive replies fail this
|
|
81
|
+
// gate the same way reflexive Bash does. Mirrors PreToolUse
|
|
82
|
+
// enforcement at the text-emission surface.
|
|
83
|
+
hooks: [{
|
|
84
|
+
type: 'command',
|
|
85
|
+
command: 'node $HOME/.claude/hooks/aria-stop-gate.mjs',
|
|
86
|
+
timeout: 5,
|
|
87
|
+
}],
|
|
88
|
+
}],
|
|
50
89
|
};
|
|
51
|
-
function installHooks(claudeDir, logs) {
|
|
90
|
+
function installHooks(claudeDir, logs, opts = {}) {
|
|
52
91
|
const hooksTargetDir = path.join(claudeDir, 'hooks');
|
|
53
92
|
if (!existsSync(hooksTargetDir)) {
|
|
54
|
-
mkdirSync(hooksTargetDir, { recursive: true });
|
|
93
|
+
mkdirSync(hooksTargetDir, { recursive: true, mode: 0o700 });
|
|
55
94
|
}
|
|
56
95
|
const sourceDir = packageHooksDir();
|
|
57
96
|
for (const name of HOOK_FILES) {
|
|
@@ -61,6 +100,19 @@ function installHooks(claudeDir, logs) {
|
|
|
61
100
|
continue;
|
|
62
101
|
}
|
|
63
102
|
const dst = path.join(hooksTargetDir, name);
|
|
103
|
+
// Idempotent skip — if existing file matches bundled file byte-for-byte,
|
|
104
|
+
// no overwrite + no backup churn. Re-running connect stays clean.
|
|
105
|
+
if (existsSync(dst) && !isSamePath(src, dst) && !opts.force) {
|
|
106
|
+
try {
|
|
107
|
+
const existingContent = readFileSync(dst, 'utf-8');
|
|
108
|
+
const newContent = readFileSync(src, 'utf-8');
|
|
109
|
+
if (existingContent === newContent) {
|
|
110
|
+
logs.push(`Hook unchanged: ${name}`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch { /* fall through to backup+overwrite */ }
|
|
115
|
+
}
|
|
64
116
|
// Back up any existing real file before overwriting (never silently
|
|
65
117
|
// clobber a user's customizations).
|
|
66
118
|
if (existsSync(dst) && !isSamePath(src, dst)) {
|
|
@@ -88,14 +140,50 @@ function isSamePath(a, b) {
|
|
|
88
140
|
}
|
|
89
141
|
}
|
|
90
142
|
function wireHooksBlock(settings, logs) {
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
143
|
+
// Merge-safe registration: preserve existing hook entries from other
|
|
144
|
+
// tools the client may have installed under different matchers, only
|
|
145
|
+
// append/replace OUR entries. Earlier wholesale replacement was
|
|
146
|
+
// deterministic but clobbered third-party hooks. Hamza 2026-04-27
|
|
147
|
+
// audit consolidation — absorb merge-safety from the duplicate
|
|
148
|
+
// src/install-hooks.ts before deletion.
|
|
149
|
+
if (!settings.hooks || typeof settings.hooks !== 'object') {
|
|
150
|
+
settings.hooks = {};
|
|
151
|
+
}
|
|
152
|
+
const hooks = settings.hooks;
|
|
153
|
+
let mergedEvents = 0;
|
|
154
|
+
for (const [event, ourEntries] of Object.entries(HOOKS_BLOCK)) {
|
|
155
|
+
const existingEntries = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
156
|
+
for (const ourEntry of ourEntries) {
|
|
157
|
+
const ourMatcher = ourEntry.matcher ?? '';
|
|
158
|
+
const ourCommands = (ourEntry.hooks ?? [])
|
|
159
|
+
.map((h) => h.command)
|
|
160
|
+
.filter((c) => typeof c === 'string');
|
|
161
|
+
// Idempotent: skip if an entry with the same matcher AND same set
|
|
162
|
+
// of commands already exists. Re-running connect stays clean.
|
|
163
|
+
const alreadyPresent = existingEntries.some((e) => {
|
|
164
|
+
if (typeof e !== 'object' || e === null)
|
|
165
|
+
return false;
|
|
166
|
+
const eMatcher = e.matcher ?? '';
|
|
167
|
+
if (eMatcher !== ourMatcher)
|
|
168
|
+
return false;
|
|
169
|
+
const eCommands = (e.hooks ?? [])
|
|
170
|
+
.map((h) => h.command)
|
|
171
|
+
.filter((c) => typeof c === 'string');
|
|
172
|
+
return ourCommands.every((c) => eCommands.includes(c));
|
|
173
|
+
});
|
|
174
|
+
if (!alreadyPresent) {
|
|
175
|
+
existingEntries.push(ourEntry);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
hooks[event] = existingEntries;
|
|
179
|
+
mergedEvents++;
|
|
96
180
|
}
|
|
97
181
|
settings.hooks = hooks;
|
|
98
|
-
|
|
182
|
+
// Ensure $schema is set (helpful for editors + future-proofing).
|
|
183
|
+
if (!settings.$schema) {
|
|
184
|
+
settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
|
|
185
|
+
}
|
|
186
|
+
logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse, Stop) — merge-safe, preserves third-party entries`);
|
|
99
187
|
}
|
|
100
188
|
function buildAriaSystemBlock(config) {
|
|
101
189
|
const repoList = config.repositories.map((r) => `- ${r.name} (${r.path})`).join('\n');
|
|
@@ -129,7 +217,7 @@ ${schemaText || '(no schema images yet — run `aria repo scan`)'}
|
|
|
129
217
|
- Flag uncertainty; never fabricate code or facts.
|
|
130
218
|
<!-- END ARIA HARNESS -->`;
|
|
131
219
|
}
|
|
132
|
-
export async function connectClaudeCode(config) {
|
|
220
|
+
export async function connectClaudeCode(config, opts = {}) {
|
|
133
221
|
const logs = [];
|
|
134
222
|
const claudeDir = path.join(homedir(), '.claude');
|
|
135
223
|
if (!existsSync(claudeDir)) {
|
|
@@ -163,9 +251,9 @@ export async function connectClaudeCode(config) {
|
|
|
163
251
|
// Install hook scripts + wire them into settings.hooks block. This is
|
|
164
252
|
// what makes the connector a real runtime control plane rather than
|
|
165
253
|
// just a system-prompt addendum.
|
|
166
|
-
installHooks(claudeDir, logs);
|
|
254
|
+
installHooks(claudeDir, logs, { force: opts.force });
|
|
167
255
|
wireHooksBlock(settings, logs);
|
|
168
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
256
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 });
|
|
169
257
|
const configJsonPath = path.join(claudeDir, 'config.json');
|
|
170
258
|
if (existsSync(configJsonPath)) {
|
|
171
259
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/connectors/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,wEAAwE;AACxE,sEAAsE;AACtE,
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/connectors/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 { connectClaudeCode } from './connectors/claude-code.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,81 @@ 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
|
+
// Canonical install via connectClaudeCode — same path as
|
|
168
|
+
// `aria install-hooks` / `aria connect` runs. Hamza 2026-04-27
|
|
169
|
+
// audit: replaced duplicate installHooks() call with the
|
|
170
|
+
// canonical connector entry point.
|
|
171
|
+
try {
|
|
172
|
+
const config = loadConfig();
|
|
173
|
+
const logs = await connectClaudeCode(config, { force: w.force === true });
|
|
174
|
+
for (const line of logs)
|
|
175
|
+
console.log(` ${line}`);
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
117
181
|
}
|
|
118
182
|
catch (err) {
|
|
119
183
|
console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
120
184
|
}
|
|
121
185
|
}
|
|
122
186
|
}
|
|
187
|
+
function defaultModelForProvider(provider) {
|
|
188
|
+
const defaults = {
|
|
189
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
190
|
+
openai: 'gpt-4o',
|
|
191
|
+
deepseek: 'deepseek-chat',
|
|
192
|
+
google: 'gemini-2.5-pro-preview-05-06',
|
|
193
|
+
openrouter: 'openai/gpt-4o',
|
|
194
|
+
ollama: 'llama3',
|
|
195
|
+
};
|
|
196
|
+
return defaults[provider] || provider;
|
|
197
|
+
}
|
|
123
198
|
function pathToPatch(path, value) {
|
|
124
199
|
if (path.length === 1)
|
|
125
200
|
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
|
@@ -6,15 +6,27 @@ import type { AriaConfig } from '../config.js';
|
|
|
6
6
|
|
|
7
7
|
// ── Hooks shipped with this package ──────────────────────────────────
|
|
8
8
|
// The connector installs these into ~/.claude/hooks/ so Claude Code's
|
|
9
|
-
// per-turn harness fetch + pre-tool gate
|
|
10
|
-
// the difference between "static prompt
|
|
11
|
-
// used to do) and "real runtime control
|
|
12
|
-
// actually is).
|
|
9
|
+
// per-turn harness fetch + pre-tool gate + stop gate + preprompt consult
|
|
10
|
+
// fire automatically. This is the difference between "static prompt
|
|
11
|
+
// addendum" (what this connector used to do) and "real runtime control
|
|
12
|
+
// plane" (what Aria's harness actually is).
|
|
13
13
|
//
|
|
14
14
|
// Resolved relative to the compiled connector file: at runtime the
|
|
15
15
|
// .js lives at <pkg>/dist/src/connectors/claude-code.js, hooks are at
|
|
16
16
|
// <pkg>/hooks/ — so up three levels then into hooks/.
|
|
17
|
-
|
|
17
|
+
//
|
|
18
|
+
// Hamza 2026-04-27 audit consolidation: HOOK_FILES extended to all 4
|
|
19
|
+
// bundled hooks (was 2). HOOKS_BLOCK extended to include Stop +
|
|
20
|
+
// UserPromptSubmit dual-fire (harness fetch + Aria preprompt consult) +
|
|
21
|
+
// PreToolUse matcher widened to 'Bash|Edit|Write|NotebookEdit'.
|
|
22
|
+
// Replaces the duplicate src/install-hooks.ts I had built in parallel
|
|
23
|
+
// — one canonical install path now.
|
|
24
|
+
const HOOK_FILES = [
|
|
25
|
+
'aria-harness-via-sdk.mjs',
|
|
26
|
+
'aria-pre-tool-gate.mjs',
|
|
27
|
+
'aria-stop-gate.mjs',
|
|
28
|
+
'aria-preprompt-consult.mjs',
|
|
29
|
+
];
|
|
18
30
|
function packageHooksDir(): string {
|
|
19
31
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
20
32
|
return path.resolve(here, '..', '..', '..', 'hooks');
|
|
@@ -35,27 +47,54 @@ const HOOKS_BLOCK = {
|
|
|
35
47
|
}],
|
|
36
48
|
}],
|
|
37
49
|
UserPromptSubmit: [{
|
|
50
|
+
hooks: [
|
|
51
|
+
{
|
|
52
|
+
type: 'command',
|
|
53
|
+
command: 'HOOK_EVENT_NAME=UserPromptSubmit node $HOME/.claude/hooks/aria-harness-via-sdk.mjs --mode turn',
|
|
54
|
+
timeout: 5,
|
|
55
|
+
statusMessage: 'Re-syncing Aria harness...',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
// Aria pre-prompt consult — fires /api/harness/delegate to get
|
|
59
|
+
// Aria's substrate-grounded direction BEFORE Claude reasons,
|
|
60
|
+
// injected as [ARIA_DIRECTION] additionalContext. This is what
|
|
61
|
+
// makes Aria the thinker on the client side, not just enriched
|
|
62
|
+
// context for the LLM.
|
|
63
|
+
type: 'command',
|
|
64
|
+
command: 'node $HOME/.claude/hooks/aria-preprompt-consult.mjs',
|
|
65
|
+
timeout: 12,
|
|
66
|
+
statusMessage: 'Pre-consulting Aria substrate for direction...',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}],
|
|
70
|
+
PreToolUse: [{
|
|
71
|
+
// Matcher widened from 'Bash' (Hamza 2026-04-26): cognition gate
|
|
72
|
+
// applies to every state-mutating tool, not just shell. Edit / Write
|
|
73
|
+
// / NotebookEdit get the same enforcement so orchestrator-side
|
|
74
|
+
// compliance mirrors what we demand from workers.
|
|
75
|
+
matcher: 'Bash|Edit|Write|NotebookEdit',
|
|
38
76
|
hooks: [{
|
|
39
77
|
type: 'command',
|
|
40
|
-
command: '
|
|
78
|
+
command: 'node $HOME/.claude/hooks/aria-pre-tool-gate.mjs',
|
|
41
79
|
timeout: 5,
|
|
42
|
-
statusMessage: 'Re-syncing Aria harness...',
|
|
43
80
|
}],
|
|
44
81
|
}],
|
|
45
|
-
|
|
46
|
-
|
|
82
|
+
Stop: [{
|
|
83
|
+
// Stop gate — text-decision boundary. Reflexive replies fail this
|
|
84
|
+
// gate the same way reflexive Bash does. Mirrors PreToolUse
|
|
85
|
+
// enforcement at the text-emission surface.
|
|
47
86
|
hooks: [{
|
|
48
87
|
type: 'command',
|
|
49
|
-
command: 'node $HOME/.claude/hooks/aria-
|
|
88
|
+
command: 'node $HOME/.claude/hooks/aria-stop-gate.mjs',
|
|
50
89
|
timeout: 5,
|
|
51
90
|
}],
|
|
52
91
|
}],
|
|
53
92
|
};
|
|
54
93
|
|
|
55
|
-
function installHooks(claudeDir: string, logs: string[]): void {
|
|
94
|
+
function installHooks(claudeDir: string, logs: string[], opts: { force?: boolean } = {}): void {
|
|
56
95
|
const hooksTargetDir = path.join(claudeDir, 'hooks');
|
|
57
96
|
if (!existsSync(hooksTargetDir)) {
|
|
58
|
-
mkdirSync(hooksTargetDir, { recursive: true });
|
|
97
|
+
mkdirSync(hooksTargetDir, { recursive: true, mode: 0o700 });
|
|
59
98
|
}
|
|
60
99
|
const sourceDir = packageHooksDir();
|
|
61
100
|
for (const name of HOOK_FILES) {
|
|
@@ -65,6 +104,18 @@ function installHooks(claudeDir: string, logs: string[]): void {
|
|
|
65
104
|
continue;
|
|
66
105
|
}
|
|
67
106
|
const dst = path.join(hooksTargetDir, name);
|
|
107
|
+
// Idempotent skip — if existing file matches bundled file byte-for-byte,
|
|
108
|
+
// no overwrite + no backup churn. Re-running connect stays clean.
|
|
109
|
+
if (existsSync(dst) && !isSamePath(src, dst) && !opts.force) {
|
|
110
|
+
try {
|
|
111
|
+
const existingContent = readFileSync(dst, 'utf-8');
|
|
112
|
+
const newContent = readFileSync(src, 'utf-8');
|
|
113
|
+
if (existingContent === newContent) {
|
|
114
|
+
logs.push(`Hook unchanged: ${name}`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
} catch {/* fall through to backup+overwrite */}
|
|
118
|
+
}
|
|
68
119
|
// Back up any existing real file before overwriting (never silently
|
|
69
120
|
// clobber a user's customizations).
|
|
70
121
|
if (existsSync(dst) && !isSamePath(src, dst)) {
|
|
@@ -82,14 +133,48 @@ function isSamePath(a: string, b: string): boolean {
|
|
|
82
133
|
}
|
|
83
134
|
|
|
84
135
|
function wireHooksBlock(settings: Record<string, unknown>, logs: string[]): void {
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
136
|
+
// Merge-safe registration: preserve existing hook entries from other
|
|
137
|
+
// tools the client may have installed under different matchers, only
|
|
138
|
+
// append/replace OUR entries. Earlier wholesale replacement was
|
|
139
|
+
// deterministic but clobbered third-party hooks. Hamza 2026-04-27
|
|
140
|
+
// audit consolidation — absorb merge-safety from the duplicate
|
|
141
|
+
// src/install-hooks.ts before deletion.
|
|
142
|
+
if (!settings.hooks || typeof settings.hooks !== 'object') {
|
|
143
|
+
settings.hooks = {};
|
|
144
|
+
}
|
|
145
|
+
const hooks = settings.hooks as Record<string, unknown[]>;
|
|
146
|
+
let mergedEvents = 0;
|
|
147
|
+
for (const [event, ourEntries] of Object.entries(HOOKS_BLOCK)) {
|
|
148
|
+
const existingEntries = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
149
|
+
for (const ourEntry of ourEntries) {
|
|
150
|
+
const ourMatcher = (ourEntry as { matcher?: string }).matcher ?? '';
|
|
151
|
+
const ourCommands = ((ourEntry as { hooks?: Array<{ command?: string }> }).hooks ?? [])
|
|
152
|
+
.map((h) => h.command)
|
|
153
|
+
.filter((c): c is string => typeof c === 'string');
|
|
154
|
+
// Idempotent: skip if an entry with the same matcher AND same set
|
|
155
|
+
// of commands already exists. Re-running connect stays clean.
|
|
156
|
+
const alreadyPresent = existingEntries.some((e) => {
|
|
157
|
+
if (typeof e !== 'object' || e === null) return false;
|
|
158
|
+
const eMatcher = (e as { matcher?: string }).matcher ?? '';
|
|
159
|
+
if (eMatcher !== ourMatcher) return false;
|
|
160
|
+
const eCommands = ((e as { hooks?: Array<{ command?: string }> }).hooks ?? [])
|
|
161
|
+
.map((h) => h.command)
|
|
162
|
+
.filter((c): c is string => typeof c === 'string');
|
|
163
|
+
return ourCommands.every((c) => eCommands.includes(c));
|
|
164
|
+
});
|
|
165
|
+
if (!alreadyPresent) {
|
|
166
|
+
existingEntries.push(ourEntry);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
hooks[event] = existingEntries;
|
|
170
|
+
mergedEvents++;
|
|
90
171
|
}
|
|
91
172
|
settings.hooks = hooks;
|
|
92
|
-
|
|
173
|
+
// Ensure $schema is set (helpful for editors + future-proofing).
|
|
174
|
+
if (!settings.$schema) {
|
|
175
|
+
settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
|
|
176
|
+
}
|
|
177
|
+
logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse, Stop) — merge-safe, preserves third-party entries`);
|
|
93
178
|
}
|
|
94
179
|
|
|
95
180
|
function buildAriaSystemBlock(config: AriaConfig): string {
|
|
@@ -126,7 +211,10 @@ ${schemaText || '(no schema images yet — run `aria repo scan`)'}
|
|
|
126
211
|
<!-- END ARIA HARNESS -->`;
|
|
127
212
|
}
|
|
128
213
|
|
|
129
|
-
export async function connectClaudeCode(
|
|
214
|
+
export async function connectClaudeCode(
|
|
215
|
+
config: AriaConfig,
|
|
216
|
+
opts: { force?: boolean } = {},
|
|
217
|
+
): Promise<string[]> {
|
|
130
218
|
const logs: string[] = [];
|
|
131
219
|
const claudeDir = path.join(homedir(), '.claude');
|
|
132
220
|
|
|
@@ -165,9 +253,9 @@ export async function connectClaudeCode(config: AriaConfig): Promise<string[]> {
|
|
|
165
253
|
// Install hook scripts + wire them into settings.hooks block. This is
|
|
166
254
|
// what makes the connector a real runtime control plane rather than
|
|
167
255
|
// just a system-prompt addendum.
|
|
168
|
-
installHooks(claudeDir, logs);
|
|
256
|
+
installHooks(claudeDir, logs, { force: opts.force });
|
|
169
257
|
wireHooksBlock(settings, logs);
|
|
170
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
258
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 });
|
|
171
259
|
|
|
172
260
|
const configJsonPath = path.join(claudeDir, 'config.json');
|
|
173
261
|
if (existsSync(configJsonPath)) {
|
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 { connectClaudeCode } from './connectors/claude-code.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,63 @@ 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
|
+
// Canonical install via connectClaudeCode — same path as
|
|
216
|
+
// `aria install-hooks` / `aria connect` runs. Hamza 2026-04-27
|
|
217
|
+
// audit: replaced duplicate installHooks() call with the
|
|
218
|
+
// canonical connector entry point.
|
|
219
|
+
try {
|
|
220
|
+
const config = loadConfig();
|
|
221
|
+
const logs = await connectClaudeCode(config, { force: w.force === true });
|
|
222
|
+
for (const line of logs) console.log(` ${line}`);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
225
|
+
}
|
|
155
226
|
}
|
|
156
227
|
} catch (err) {
|
|
157
228
|
console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -159,6 +230,18 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
159
230
|
}
|
|
160
231
|
}
|
|
161
232
|
|
|
233
|
+
function defaultModelForProvider(provider: string): string {
|
|
234
|
+
const defaults: Record<string, string> = {
|
|
235
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
236
|
+
openai: 'gpt-4o',
|
|
237
|
+
deepseek: 'deepseek-chat',
|
|
238
|
+
google: 'gemini-2.5-pro-preview-05-06',
|
|
239
|
+
openrouter: 'openai/gpt-4o',
|
|
240
|
+
ollama: 'llama3',
|
|
241
|
+
};
|
|
242
|
+
return defaults[provider] || provider;
|
|
243
|
+
}
|
|
244
|
+
|
|
162
245
|
function pathToPatch(path: string[], value: unknown): Partial<AriaConfig> {
|
|
163
246
|
if (path.length === 1) return { [path[0]]: value } as Partial<AriaConfig>;
|
|
164
247
|
// Nested path → shallow merge under top-level key.
|
package/src/install-hooks.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
// install-hooks — drops the harness gate hooks into the client's
|
|
2
|
-
// ~/.claude/hooks/ directory and registers them in their settings.json.
|
|
3
|
-
//
|
|
4
|
-
// This is what makes @aria_asi/cli a self-installing harness. Without it,
|
|
5
|
-
// clients install the CLI and have a license-aware HTTP client. With it,
|
|
6
|
-
// running `aria install-hooks` once turns their Claude Code (or any
|
|
7
|
-
// Claude Code Code session on that machine) into a harness-bound
|
|
8
|
-
// session — every Bash, Edit, Write, NotebookEdit, and text-emit event
|
|
9
|
-
// runs through cognition gates + Mizan + harness packet.
|
|
10
|
-
//
|
|
11
|
-
// Soldier-and-thinker (Hamza 2026-04-26 directive): the CLI is the
|
|
12
|
-
// thinker (carries doctrine, gates, substrate); the LLM in Claude Code
|
|
13
|
-
// is the soldier (executes under harness binding). install-hooks is
|
|
14
|
-
// what wires the soldier to the thinker on the client's machine.
|
|
15
|
-
|
|
16
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync, chmodSync, readdirSync, statSync } from 'node:fs';
|
|
17
|
-
import { homedir } from 'node:os';
|
|
18
|
-
import { join, dirname, resolve } from 'node:path';
|
|
19
|
-
import { fileURLToPath } from 'node:url';
|
|
20
|
-
|
|
21
|
-
export interface InstallHooksOptions {
|
|
22
|
-
/** Overwrite existing hooks even if present. Default false. */
|
|
23
|
-
force?: boolean;
|
|
24
|
-
/** Override the harness URL written into settings.json env (clients with private deployments). */
|
|
25
|
-
harnessUrl?: string;
|
|
26
|
-
/** Override the home directory (used by tests). */
|
|
27
|
-
homeDir?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface InstallHooksResult {
|
|
31
|
-
ok: boolean;
|
|
32
|
-
installed: string[];
|
|
33
|
-
merged: string[];
|
|
34
|
-
backupsCreated: string[];
|
|
35
|
-
settingsPath: string;
|
|
36
|
-
error?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const HOOK_FILES = [
|
|
40
|
-
'aria-pre-tool-gate.mjs',
|
|
41
|
-
'aria-stop-gate.mjs',
|
|
42
|
-
'aria-preprompt-consult.mjs',
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
const HOOK_REGISTRATION = {
|
|
46
|
-
UserPromptSubmit: [
|
|
47
|
-
{
|
|
48
|
-
hooks: [
|
|
49
|
-
{
|
|
50
|
-
type: 'command',
|
|
51
|
-
command: 'node $HOME/.claude/hooks/aria-preprompt-consult.mjs',
|
|
52
|
-
timeout: 12,
|
|
53
|
-
statusMessage: 'Pre-consulting Aria substrate for direction...',
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
PreToolUse: [
|
|
59
|
-
{
|
|
60
|
-
matcher: 'Bash|Edit|Write|NotebookEdit',
|
|
61
|
-
hooks: [
|
|
62
|
-
{
|
|
63
|
-
type: 'command',
|
|
64
|
-
command: 'node $HOME/.claude/hooks/aria-pre-tool-gate.mjs',
|
|
65
|
-
timeout: 5,
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
Stop: [
|
|
71
|
-
{
|
|
72
|
-
hooks: [
|
|
73
|
-
{
|
|
74
|
-
type: 'command',
|
|
75
|
-
command: 'node $HOME/.claude/hooks/aria-stop-gate.mjs',
|
|
76
|
-
timeout: 5,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
function bundledHooksDir(): string {
|
|
84
|
-
// The hooks/ dir is bundled in the package alongside dist/. Find it by
|
|
85
|
-
// walking upward from this file's runtime path until we hit a directory
|
|
86
|
-
// that contains both package.json (with name @aria_asi/cli) and a hooks/
|
|
87
|
-
// sibling. Robust across:
|
|
88
|
-
// - dev: src/install-hooks.ts → ../hooks
|
|
89
|
-
// - flat compile: dist/install-hooks.js → ../hooks
|
|
90
|
-
// - nested compile: dist/aria-connector/src/install-hooks.js → ../../../hooks
|
|
91
|
-
// - npm global install: /usr/lib/node_modules/@aria_asi/cli/dist/.../install-hooks.js
|
|
92
|
-
const here = fileURLToPath(import.meta.url);
|
|
93
|
-
let cur = dirname(here);
|
|
94
|
-
const tried: string[] = [];
|
|
95
|
-
for (let i = 0; i < 8; i++) {
|
|
96
|
-
const candidate = join(cur, 'hooks');
|
|
97
|
-
tried.push(candidate);
|
|
98
|
-
if (existsSync(candidate) && existsSync(join(cur, 'package.json'))) {
|
|
99
|
-
return candidate;
|
|
100
|
-
}
|
|
101
|
-
const parent = dirname(cur);
|
|
102
|
-
if (parent === cur) break;
|
|
103
|
-
cur = parent;
|
|
104
|
-
}
|
|
105
|
-
throw new Error(
|
|
106
|
-
`I can't find my bundled hooks/ dir. Tried: ${tried.join(', ')}. Reinstall @aria_asi/cli or report this as a bug.`,
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function backupExisting(target: string): string {
|
|
111
|
-
const ts = Date.now();
|
|
112
|
-
const backup = `${target}.pre-aria-install.${ts}`;
|
|
113
|
-
copyFileSync(target, backup);
|
|
114
|
-
return backup;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function mergeRegistrationInto(existing: Record<string, unknown>): { merged: Record<string, unknown>; mergedKeys: string[] } {
|
|
118
|
-
const mergedKeys: string[] = [];
|
|
119
|
-
const out = { ...existing };
|
|
120
|
-
if (!out.hooks || typeof out.hooks !== 'object') {
|
|
121
|
-
out.hooks = {};
|
|
122
|
-
}
|
|
123
|
-
const hooks = out.hooks as Record<string, unknown[]>;
|
|
124
|
-
|
|
125
|
-
for (const [event, ourEntries] of Object.entries(HOOK_REGISTRATION)) {
|
|
126
|
-
const existingEntries = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
127
|
-
|
|
128
|
-
// For each of our entries, append unless an entry with the same matcher
|
|
129
|
-
// and command already exists (idempotent re-install).
|
|
130
|
-
for (const ourEntry of ourEntries) {
|
|
131
|
-
const ourMatcher = (ourEntry as { matcher?: string }).matcher ?? '';
|
|
132
|
-
const ourCommands = ((ourEntry as { hooks?: Array<{ command?: string }> }).hooks ?? [])
|
|
133
|
-
.map((h) => h.command)
|
|
134
|
-
.filter((c): c is string => typeof c === 'string');
|
|
135
|
-
|
|
136
|
-
const alreadyPresent = existingEntries.some((e) => {
|
|
137
|
-
if (typeof e !== 'object' || e === null) return false;
|
|
138
|
-
const eMatcher = (e as { matcher?: string }).matcher ?? '';
|
|
139
|
-
if (eMatcher !== ourMatcher) return false;
|
|
140
|
-
const eCommands = ((e as { hooks?: Array<{ command?: string }> }).hooks ?? [])
|
|
141
|
-
.map((h) => h.command)
|
|
142
|
-
.filter((c): c is string => typeof c === 'string');
|
|
143
|
-
return ourCommands.every((c) => eCommands.includes(c));
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
if (!alreadyPresent) {
|
|
147
|
-
existingEntries.push(ourEntry);
|
|
148
|
-
if (!mergedKeys.includes(event)) mergedKeys.push(event);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
hooks[event] = existingEntries;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return { merged: out, mergedKeys };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export async function installHooks(opts: InstallHooksOptions = {}): Promise<InstallHooksResult> {
|
|
159
|
-
const home = opts.homeDir ?? homedir();
|
|
160
|
-
const claudeDir = join(home, '.claude');
|
|
161
|
-
const hooksDir = join(claudeDir, 'hooks');
|
|
162
|
-
const settingsPath = join(claudeDir, 'settings.json');
|
|
163
|
-
|
|
164
|
-
const installed: string[] = [];
|
|
165
|
-
const merged: string[] = [];
|
|
166
|
-
const backupsCreated: string[] = [];
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
if (!existsSync(claudeDir)) mkdirSync(claudeDir, { recursive: true, mode: 0o700 });
|
|
170
|
-
if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true, mode: 0o700 });
|
|
171
|
-
|
|
172
|
-
const sourceDir = bundledHooksDir();
|
|
173
|
-
|
|
174
|
-
for (const name of HOOK_FILES) {
|
|
175
|
-
const src = join(sourceDir, name);
|
|
176
|
-
if (!existsSync(src)) {
|
|
177
|
-
return {
|
|
178
|
-
ok: false,
|
|
179
|
-
installed,
|
|
180
|
-
merged,
|
|
181
|
-
backupsCreated,
|
|
182
|
-
settingsPath,
|
|
183
|
-
error: `I can't find ${name} in my bundle (${sourceDir}). Reinstall @aria_asi/cli.`,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const dst = join(hooksDir, name);
|
|
187
|
-
|
|
188
|
-
if (existsSync(dst)) {
|
|
189
|
-
const existingContent = readFileSync(dst, 'utf-8');
|
|
190
|
-
const newContent = readFileSync(src, 'utf-8');
|
|
191
|
-
if (existingContent === newContent) {
|
|
192
|
-
// Already up-to-date — skip. Idempotent.
|
|
193
|
-
installed.push(`${name} (unchanged)`);
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
if (!opts.force) {
|
|
197
|
-
// Default behavior: back up + overwrite. The override pattern
|
|
198
|
-
// keeps prior hooks recoverable (e.g. if client had custom hooks).
|
|
199
|
-
const backup = backupExisting(dst);
|
|
200
|
-
backupsCreated.push(backup);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
copyFileSync(src, dst);
|
|
205
|
-
chmodSync(dst, 0o755);
|
|
206
|
-
installed.push(name);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Settings merge
|
|
210
|
-
let existingSettings: Record<string, unknown> = {};
|
|
211
|
-
if (existsSync(settingsPath)) {
|
|
212
|
-
try {
|
|
213
|
-
existingSettings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
214
|
-
} catch {
|
|
215
|
-
// Malformed — back up and start fresh.
|
|
216
|
-
const backup = backupExisting(settingsPath);
|
|
217
|
-
backupsCreated.push(backup);
|
|
218
|
-
existingSettings = {};
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const { merged: mergedSettings, mergedKeys } = mergeRegistrationInto(existingSettings);
|
|
223
|
-
merged.push(...mergedKeys);
|
|
224
|
-
|
|
225
|
-
// Inject ARIA_HARNESS_URL env into settings.json if the caller specified
|
|
226
|
-
// a harness URL override (clients on private deployments).
|
|
227
|
-
if (opts.harnessUrl) {
|
|
228
|
-
if (!mergedSettings.env || typeof mergedSettings.env !== 'object') {
|
|
229
|
-
mergedSettings.env = {};
|
|
230
|
-
}
|
|
231
|
-
(mergedSettings.env as Record<string, string>).ARIA_HARNESS_URL = opts.harnessUrl;
|
|
232
|
-
if (!merged.includes('env.ARIA_HARNESS_URL')) merged.push('env.ARIA_HARNESS_URL');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Always write settings.json (even if no merges) so the schema field is set.
|
|
236
|
-
if (!('$schema' in mergedSettings)) {
|
|
237
|
-
mergedSettings['$schema'] = 'https://json.schemastore.org/claude-code-settings.json';
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2) + '\n', { mode: 0o600 });
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
ok: true,
|
|
244
|
-
installed,
|
|
245
|
-
merged,
|
|
246
|
-
backupsCreated,
|
|
247
|
-
settingsPath,
|
|
248
|
-
};
|
|
249
|
-
} catch (err) {
|
|
250
|
-
return {
|
|
251
|
-
ok: false,
|
|
252
|
-
installed,
|
|
253
|
-
merged,
|
|
254
|
-
backupsCreated,
|
|
255
|
-
settingsPath,
|
|
256
|
-
error: err instanceof Error ? err.message : String(err),
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
}
|
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
|
-
}
|