@aria_asi/cli 0.2.6 → 0.2.8
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 +17 -17
- 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.js +9 -11
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/hooks/aria-harness-via-sdk.mjs +41 -16
- package/hooks/aria-preprompt-consult.mjs +12 -2
- package/package.json +1 -1
- package/src/connectors/claude-code.ts +109 -21
- package/src/setup-wizard.ts +8 -9
- package/src/install-hooks.ts +0 -259
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) => {
|
|
@@ -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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"}
|
|
@@ -20,7 +20,7 @@ import { join } from 'node:path';
|
|
|
20
20
|
import { loadConfig, updateConfig } from './config.js';
|
|
21
21
|
import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
|
|
22
22
|
import { updatePersona } from './persona.js';
|
|
23
|
-
import {
|
|
23
|
+
import { connectClaudeCode } from './connectors/claude-code.js';
|
|
24
24
|
const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
|
|
25
25
|
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
26
26
|
const ARIA_DIR = join(homedir(), '.aria');
|
|
@@ -164,17 +164,15 @@ async function applyConfigWrites(writes) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
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.
|
|
167
171
|
try {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
}
|
|
172
|
+
const config = loadConfig();
|
|
173
|
+
const logs = await connectClaudeCode(config, { force: w.force === true });
|
|
174
|
+
for (const line of logs)
|
|
175
|
+
console.log(` ${line}`);
|
|
178
176
|
}
|
|
179
177
|
catch (err) {
|
|
180
178
|
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -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,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,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;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"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"}
|
|
@@ -121,30 +121,55 @@ function buildUrlList() {
|
|
|
121
121
|
const list = [];
|
|
122
122
|
const cached = loadCachedUrl();
|
|
123
123
|
if (cached) list.push(cached);
|
|
124
|
+
// Explicit override takes priority — owner mode sets ARIA_SOUL_URL or
|
|
125
|
+
// ARIA_HARNESS_URL/ARIA_HARNESS_BASE_URL to a local cluster path.
|
|
124
126
|
if (process.env.ARIA_SOUL_URL) list.push(process.env.ARIA_SOUL_URL.replace(/\/+$/, ''));
|
|
125
|
-
list.push(
|
|
126
|
-
list.push(
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
], { encoding: 'utf8', timeout: 3_000 });
|
|
133
|
-
if (r.status === 0 && r.stdout && r.stdout !== 'None') {
|
|
134
|
-
list.push(`http://${r.stdout.trim()}:8080`);
|
|
135
|
-
}
|
|
136
|
-
} catch {}
|
|
127
|
+
if (process.env.ARIA_HARNESS_URL) list.push(process.env.ARIA_HARNESS_URL.replace(/\/+$/, ''));
|
|
128
|
+
if (process.env.ARIA_HARNESS_BASE_URL) list.push(process.env.ARIA_HARNESS_BASE_URL.replace(/\/+$/, ''));
|
|
129
|
+
// Public default — what every client install uses. Cloudflare tunnel routes
|
|
130
|
+
// to aria-soul-stateful inside the cluster. This must be FIRST in the
|
|
131
|
+
// public-facing path so client installs don't waste 1–2s timing out on
|
|
132
|
+
// localhost/127.0.0.1 before reaching anything real.
|
|
133
|
+
list.push('https://harness.ariasos.com');
|
|
137
134
|
if (process.env.ARIA_PUBLIC_URL) list.push(process.env.ARIA_PUBLIC_URL.replace(/\/+$/, ''));
|
|
135
|
+
// Owner-mode fallbacks — only attempted when explicitly enabled, so client
|
|
136
|
+
// machines never burn time trying to reach Hamza's LAN. ARIA_OWNER_MODE=true
|
|
137
|
+
// is set in the dev box shell.
|
|
138
|
+
if ((process.env.ARIA_OWNER_MODE || '').toLowerCase() === 'true') {
|
|
139
|
+
list.push('http://localhost:30080', 'http://127.0.0.1:30080');
|
|
140
|
+
list.push('http://aria-soul.aria.svc.cluster.local:8080');
|
|
141
|
+
// Direct ClusterIP from kubectl — only relevant for in-cluster/owner runs.
|
|
142
|
+
try {
|
|
143
|
+
const r = spawnSync('kubectl', [
|
|
144
|
+
'get', 'svc', '-n', 'aria', 'aria-soul',
|
|
145
|
+
'-o', 'jsonpath={.spec.clusterIP}',
|
|
146
|
+
], { encoding: 'utf8', timeout: 3_000 });
|
|
147
|
+
if (r.status === 0 && r.stdout && r.stdout !== 'None') {
|
|
148
|
+
list.push(`http://${r.stdout.trim()}:8080`);
|
|
149
|
+
}
|
|
150
|
+
} catch {}
|
|
151
|
+
}
|
|
138
152
|
// Dedup preserving order
|
|
139
153
|
const seen = new Set();
|
|
140
154
|
return list.filter((u) => (seen.has(u) ? false : (seen.add(u), true)));
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
async function tryViaSdk(baseUrl, apiKey) {
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
158
|
+
// Owner-mode dynamic import of the canonical SDK from the monorepo. Client
|
|
159
|
+
// installs do not have this path — they fall through to the raw-fetch path
|
|
160
|
+
// below (same network call, identical body shape). Prior code hard-coded the
|
|
161
|
+
// owner-only path and crashed on every client turn.
|
|
162
|
+
const ownerSdkPath = process.env.ARIA_HARNESS_SDK_PATH ||
|
|
163
|
+
'/home/hamzaibrahim1/rei-ai-brain/harness/packages/harness-http-client/dist/index.js';
|
|
164
|
+
let HTTPHarnessClient = null;
|
|
165
|
+
try {
|
|
166
|
+
({ HTTPHarnessClient } = await import(ownerSdkPath));
|
|
167
|
+
} catch {
|
|
168
|
+
// SDK unavailable (the common case for client installs) — caller should
|
|
169
|
+
// catch this and fall through to the raw-fetch path. We surface a typed
|
|
170
|
+
// error instead of import-rejection noise so the caller can branch cleanly.
|
|
171
|
+
throw new Error('SDK_UNAVAILABLE');
|
|
172
|
+
}
|
|
148
173
|
HTTPHarnessClient.resetInstance();
|
|
149
174
|
const client = HTTPHarnessClient.getInstance({
|
|
150
175
|
baseUrl,
|
|
@@ -45,8 +45,18 @@ import { dirname } from 'node:path';
|
|
|
45
45
|
const HOME = process.env.HOME || '/tmp';
|
|
46
46
|
const LOG = `${HOME}/.claude/aria-preprompt-consult.log`;
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// Default to the public harness; client installs route to harness.ariasos.com.
|
|
49
|
+
// Owner mode (Hamza dev box): set ARIA_HARNESS_URL=http://localhost:30080 in shell.
|
|
50
|
+
const HARNESS_URL =
|
|
51
|
+
process.env.ARIA_HARNESS_URL ||
|
|
52
|
+
process.env.ARIA_HARNESS_BASE_URL ||
|
|
53
|
+
'https://harness.ariasos.com';
|
|
54
|
+
// NEVER bake a default token. Client installs must inject their own license token
|
|
55
|
+
// via ARIA_HARNESS_TOKEN (set by the connector after onboarding self-issue). If
|
|
56
|
+
// absent we send no Authorization header — the server can decide whether to
|
|
57
|
+
// allow anonymous preprompt consults or skip them. Prior code defaulted to the
|
|
58
|
+
// master token, leaking Hamza's master credential into every npm install.
|
|
59
|
+
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
50
60
|
const MIN_PROMPT_CHARS = 40; // skip auto-consult on trivial prompts
|
|
51
61
|
const MAX_DIRECTION_CHARS = 4000; // cap injected chunk size
|
|
52
62
|
|
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
|
@@ -21,7 +21,7 @@ import { join } from 'node:path';
|
|
|
21
21
|
import { loadConfig, updateConfig, type AriaConfig, type LinkedRepo } from './config.js';
|
|
22
22
|
import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
|
|
23
23
|
import { updatePersona } from './persona.js';
|
|
24
|
-
import {
|
|
24
|
+
import { connectClaudeCode } from './connectors/claude-code.js';
|
|
25
25
|
|
|
26
26
|
const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
|
|
27
27
|
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
@@ -212,15 +212,14 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
212
212
|
console.warn(` ⚠ I hit an error issuing your license: ${err instanceof Error ? err.message : String(err)}`);
|
|
213
213
|
}
|
|
214
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.
|
|
215
219
|
try {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
}
|
|
220
|
+
const config = loadConfig();
|
|
221
|
+
const logs = await connectClaudeCode(config, { force: w.force === true });
|
|
222
|
+
for (const line of logs) console.log(` ${line}`);
|
|
224
223
|
} catch (err) {
|
|
225
224
|
console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
|
|
226
225
|
}
|
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
|
-
}
|