@aria_asi/cli 0.2.37 → 0.2.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -0
- package/bin/aria.js +8 -4
- package/dist/aria-connector/src/auth.d.ts +1 -0
- package/dist/aria-connector/src/auth.d.ts.map +1 -1
- package/dist/aria-connector/src/auth.js +26 -1
- package/dist/aria-connector/src/auth.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +0 -42
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +41 -1
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/aria-connector/src/types.d.ts +6 -0
- package/dist/aria-connector/src/types.d.ts.map +1 -1
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +53 -0
- package/dist/assets/hooks/aria-pre-tool-use.mjs +75 -0
- package/dist/assets/hooks/lib/first-class-coach.mjs +3 -3
- package/dist/cli-0.2.38.tgz +0 -0
- package/dist/runtime/coach-kernel.mjs +66 -5
- package/dist/runtime/gated-ledger.mjs +237 -0
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +53 -0
- package/dist/runtime/hooks/aria-pre-tool-use.mjs +75 -0
- package/dist/runtime/hooks/lib/first-class-coach.mjs +3 -3
- package/dist/runtime/manifest.json +1 -1
- package/dist/runtime/quality-enforcer.mjs +257 -0
- package/dist/runtime/sdk/BUNDLED.json +1 -1
- package/dist/runtime/service.mjs +119 -0
- package/dist/sdk/BUNDLED.json +1 -1
- package/hooks/aria-pre-tool-gate.mjs +53 -0
- package/hooks/aria-pre-tool-use.mjs +75 -0
- package/hooks/lib/first-class-coach.mjs +3 -3
- package/package.json +1 -1
- package/runtime-src/coach-kernel.mjs +66 -5
- package/runtime-src/gated-ledger.mjs +237 -0
- package/runtime-src/quality-enforcer.mjs +257 -0
- package/runtime-src/service.mjs +119 -0
- package/scripts/install-client.sh +32 -2
- package/src/auth.ts +25 -1
- package/src/connectors/codex.ts +0 -42
- package/src/setup-wizard.ts +43 -1
- package/src/types.ts +6 -0
package/runtime-src/service.mjs
CHANGED
|
@@ -42,8 +42,11 @@ import {
|
|
|
42
42
|
formatCoachClientBlock,
|
|
43
43
|
readCoachState,
|
|
44
44
|
recordCoachPhase,
|
|
45
|
+
triggerMissingSkills,
|
|
45
46
|
} from './coach-kernel.mjs';
|
|
46
47
|
import { resolveAriaAuthToken } from './auth-token.mjs';
|
|
48
|
+
import { check, enforceWithRecovery as enforceQualityWithRecovery } from './quality-enforcer.mjs';
|
|
49
|
+
import { enforceGates } from './gated-ledger.mjs';
|
|
47
50
|
|
|
48
51
|
const require = createRequire(import.meta.url);
|
|
49
52
|
const { runFullChain } = require('./vendor/aria-gate-runtime/index.js');
|
|
@@ -3726,6 +3729,15 @@ async function evaluateProviderCandidate(req, body, client, apiKey, turn, provid
|
|
|
3726
3729
|
};
|
|
3727
3730
|
}
|
|
3728
3731
|
|
|
3732
|
+
function deriveEffectiveKernel(turn, body) {
|
|
3733
|
+
const msg = body?.message || body?.prompt || body?.input || '';
|
|
3734
|
+
if (turn?.turnClass === 'repair' || /repair|fix|debug|broken|bug|error|failing|crash|recover/i.test(msg)) return 'repair';
|
|
3735
|
+
if (turn?.turnClass === 'architect' || /architecture|design|system|pipeline|tradeoff|ADR/i.test(msg)) return 'architect';
|
|
3736
|
+
if (turn?.turnClass === 'action' || /deploy|execute|run|build|ship|rollout|restart|push/i.test(msg)) return 'action';
|
|
3737
|
+
if (turn?.turnClass === 'research' || /research|search|find|recall|retrieve|look.up|investigate/i.test(msg)) return 'research';
|
|
3738
|
+
return 'emotional_presence';
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3729
3741
|
async function handleProviderProxy(req, body, client, providerStyle, options = {}) {
|
|
3730
3742
|
const apiKey = resolveApiKey(req, body, options);
|
|
3731
3743
|
const startedAt = Date.now();
|
|
@@ -3819,6 +3831,44 @@ async function handleProviderProxy(req, body, client, providerStyle, options = {
|
|
|
3819
3831
|
],
|
|
3820
3832
|
});
|
|
3821
3833
|
coachRecords.push(preGenerationCoach);
|
|
3834
|
+
// ── Coach auto-trigger: load missing skills instead of blocking ──
|
|
3835
|
+
if (preGenerationCoach.decision === 'auto_trigger_skills' && turn.missingSkillIds?.length > 0) {
|
|
3836
|
+
const skillResult = await triggerMissingSkills(
|
|
3837
|
+
turn.missingSkillIds,
|
|
3838
|
+
SKILL_SEARCH_ROOTS,
|
|
3839
|
+
);
|
|
3840
|
+
const loadedCoach = recordRuntimeCoachPhase({
|
|
3841
|
+
phase: 'pre_generation',
|
|
3842
|
+
body,
|
|
3843
|
+
turn: { ...turn, loadedSkillIds: [...(turn.loadedSkillIds || []), ...skillResult.loaded], missingSkillIds: skillResult.stillMissing },
|
|
3844
|
+
providerStyle,
|
|
3845
|
+
providerPlan,
|
|
3846
|
+
text: turn.userMessage,
|
|
3847
|
+
evidenceRefs: [`skills_loaded:${skillResult.loaded.length}`, `skills_still_missing:${skillResult.stillMissing.length}`],
|
|
3848
|
+
metadata: { autoLoadedSkills: skillResult.loaded },
|
|
3849
|
+
});
|
|
3850
|
+
coachRecords.push(loadedCoach);
|
|
3851
|
+
if (loadedCoach.decision === 'hard_block') {
|
|
3852
|
+
const refusal = formatCoachClientBlock(loadedCoach);
|
|
3853
|
+
const autoBlockRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
3854
|
+
phase: 'pre_generation_skills_block',
|
|
3855
|
+
body, turn, providerStyle, providerPlan,
|
|
3856
|
+
releaseDecision: 'hard_block',
|
|
3857
|
+
blockers: loadedCoach.reasons,
|
|
3858
|
+
evidenceRefs: coachRecordRefs(coachRecords),
|
|
3859
|
+
}));
|
|
3860
|
+
ledgerRecords.push({ phase: 'pre_generation_skills_block', ...autoBlockRecord });
|
|
3861
|
+
return providerStyle === 'anthropic'
|
|
3862
|
+
? anthropicResponseEnvelope(refusal, { model: body.model || 'aria-runtime', finishReason: 'end_turn' }, {}, body?.ariaDebug === true)
|
|
3863
|
+
: openAiResponseEnvelope(body, refusal, { model: body.model || 'aria-runtime', finishReason: 'stop', usage: null }, {});
|
|
3864
|
+
}
|
|
3865
|
+
// Skills loaded — update turn for the rest of the pipeline
|
|
3866
|
+
turn.loadedSkillIds = [...(turn.loadedSkillIds || []), ...skillResult.loaded];
|
|
3867
|
+
turn.missingSkillIds = skillResult.stillMissing;
|
|
3868
|
+
if (skillResult.loadedBodies.length > 0) {
|
|
3869
|
+
turn.skillBodies = [...(turn.skillBodies || []), ...skillResult.loadedBodies.map((s) => s.body)];
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3822
3872
|
if (preGenerationCoach.decision === 'hard_block') {
|
|
3823
3873
|
const refusal = formatCoachClientBlock(preGenerationCoach);
|
|
3824
3874
|
const preBlockRecord = appendManagedRuntimeLedger(buildManagedRuntimeLedgerRecord({
|
|
@@ -3877,6 +3927,17 @@ async function handleProviderProxy(req, body, client, providerStyle, options = {
|
|
|
3877
3927
|
ledgerRecords.push({ phase: 'provider_call_failed', ...failureRecord });
|
|
3878
3928
|
throw error;
|
|
3879
3929
|
}
|
|
3930
|
+
|
|
3931
|
+
const providerQualityResult = await enforceQualityWithRecovery(
|
|
3932
|
+
providerMeta.text || '',
|
|
3933
|
+
deriveEffectiveKernel(turn, body),
|
|
3934
|
+
{ sessionId: turn.sessionId || body.sessionId },
|
|
3935
|
+
);
|
|
3936
|
+
if (providerQualityResult.enforced) {
|
|
3937
|
+
providerMeta.text = providerQualityResult.finalText;
|
|
3938
|
+
providerMeta.qualityEnforced = true;
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3880
3941
|
recordProviderUsage(body, turn, providerMeta);
|
|
3881
3942
|
let hardCoachBlock = null;
|
|
3882
3943
|
let evaluation = await evaluateProviderCandidate(req, body, client, apiKey, turn, providerStyle, providerMeta, providerMeta.text || '');
|
|
@@ -4125,11 +4186,55 @@ async function handleProviderProxy(req, body, client, providerStyle, options = {
|
|
|
4125
4186
|
records: coachRecords,
|
|
4126
4187
|
},
|
|
4127
4188
|
};
|
|
4189
|
+
const finalQualityResult = await enforceQualityWithRecovery(
|
|
4190
|
+
finalText,
|
|
4191
|
+
deriveEffectiveKernel(turn, body),
|
|
4192
|
+
{ sessionId: turn.sessionId || body.sessionId },
|
|
4193
|
+
);
|
|
4194
|
+
if (finalQualityResult.enforced) {
|
|
4195
|
+
finalText = finalQualityResult.finalText;
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
// ── Gated Ledger: final enforcement before release ──
|
|
4199
|
+
const gated = await enforceGates(finalText, {
|
|
4200
|
+
kernel: deriveEffectiveKernel(turn, body),
|
|
4201
|
+
sessionId: turn.sessionId || body.sessionId,
|
|
4202
|
+
});
|
|
4203
|
+
if (gated.enforced) {
|
|
4204
|
+
extra.gatedLedger = {
|
|
4205
|
+
enforced: true,
|
|
4206
|
+
gates: gated.gates,
|
|
4207
|
+
doctrineTriggers: gated.doctrineTriggers,
|
|
4208
|
+
recordId: gated.record.recordId,
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
finalText = gated.finalText;
|
|
4212
|
+
|
|
4128
4213
|
return providerStyle === 'anthropic'
|
|
4129
4214
|
? anthropicResponseEnvelope(finalText, providerMeta, extra, body?.ariaDebug === true)
|
|
4130
4215
|
: openAiResponseEnvelope(body, finalText, providerMeta, extra);
|
|
4131
4216
|
}
|
|
4132
4217
|
|
|
4218
|
+
function extractProviderResponseText(response) {
|
|
4219
|
+
if (!response || typeof response !== 'object') return null;
|
|
4220
|
+
const choices = response.choices;
|
|
4221
|
+
if (Array.isArray(choices) && choices.length > 0) {
|
|
4222
|
+
const content = choices[0]?.message?.content;
|
|
4223
|
+
return typeof content === 'string' ? content : null;
|
|
4224
|
+
}
|
|
4225
|
+
return null;
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4228
|
+
function extractAnthropicResponseText(response) {
|
|
4229
|
+
if (!response || typeof response !== 'object') return null;
|
|
4230
|
+
const content = response.content;
|
|
4231
|
+
if (Array.isArray(content)) {
|
|
4232
|
+
return content.map(c => (c && c.text ? c.text : '')).join(' ').trim() || null;
|
|
4233
|
+
}
|
|
4234
|
+
if (typeof content === 'string') return content;
|
|
4235
|
+
return null;
|
|
4236
|
+
}
|
|
4237
|
+
|
|
4133
4238
|
async function handleForgeSynthesis(req, body, client) {
|
|
4134
4239
|
const apiKey = resolveApiKey(req, body);
|
|
4135
4240
|
const startedAt = Date.now();
|
|
@@ -5338,6 +5443,13 @@ async function handleRoute(req, res) {
|
|
|
5338
5443
|
|
|
5339
5444
|
if (providerPath === '/v1/chat/completions') {
|
|
5340
5445
|
const response = await handleProviderProxy(req, body, client, 'openai', ariaAuthOptions);
|
|
5446
|
+
const responseText = extractProviderResponseText(response);
|
|
5447
|
+
if (responseText) {
|
|
5448
|
+
const qScan = check(responseText);
|
|
5449
|
+
if (!qScan.allowed) {
|
|
5450
|
+
console.warn(`[quality-enforcer] Gate labels detected in OpenAI response after handleProviderProxy. ${qScan.reasons.join(', ')}`);
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5341
5453
|
return json(res, 200, response);
|
|
5342
5454
|
}
|
|
5343
5455
|
|
|
@@ -5349,6 +5461,13 @@ async function handleRoute(req, res) {
|
|
|
5349
5461
|
|
|
5350
5462
|
if (providerPath === '/v1/messages') {
|
|
5351
5463
|
const response = await handleProviderProxy(req, body, client, 'anthropic', ariaAuthOptions);
|
|
5464
|
+
const responseText = extractAnthropicResponseText(response);
|
|
5465
|
+
if (responseText) {
|
|
5466
|
+
const qScan = check(responseText);
|
|
5467
|
+
if (!qScan.allowed) {
|
|
5468
|
+
console.warn(`[quality-enforcer] Gate labels detected in Anthropic response after handleProviderProxy. ${qScan.reasons.join(', ')}`);
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5352
5471
|
return json(res, 200, response);
|
|
5353
5472
|
}
|
|
5354
5473
|
|
|
@@ -159,8 +159,38 @@ case "${SOURCE}" in
|
|
|
159
159
|
;;
|
|
160
160
|
esac
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
aria
|
|
162
|
+
resolve_aria_bin() {
|
|
163
|
+
if command -v aria >/dev/null 2>&1; then
|
|
164
|
+
echo "aria"
|
|
165
|
+
return 0
|
|
166
|
+
fi
|
|
167
|
+
local npm_prefix
|
|
168
|
+
npm_prefix="$(npm config get prefix 2>/dev/null || echo '')"
|
|
169
|
+
local candidate="${npm_prefix}/bin/aria"
|
|
170
|
+
if [[ -n "${npm_prefix}" && -x "${candidate}" ]]; then
|
|
171
|
+
echo "${candidate}"
|
|
172
|
+
return 0
|
|
173
|
+
fi
|
|
174
|
+
candidate="${HOME}/.npm-global/bin/aria"
|
|
175
|
+
if [[ -x "${candidate}" ]]; then
|
|
176
|
+
echo "${candidate}"
|
|
177
|
+
return 0
|
|
178
|
+
fi
|
|
179
|
+
return 1
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
ARIA_BIN="$(resolve_aria_bin)" || true
|
|
183
|
+
if [[ -z "${ARIA_BIN}" ]]; then
|
|
184
|
+
echo "I couldn't find the aria binary after install." >&2
|
|
185
|
+
echo "Restart your shell (exec \$SHELL -l) and run: aria login ${TOKEN}" >&2
|
|
186
|
+
else
|
|
187
|
+
"${ARIA_BIN}" login "${TOKEN}"
|
|
188
|
+
if "${ARIA_BIN}" connect --force 2>&1 | grep -qi 'server\|unreachable\|backend\|unavailable'; then
|
|
189
|
+
echo ""
|
|
190
|
+
echo "Aria Soul backend is unreachable — running local-only connect."
|
|
191
|
+
"${ARIA_BIN}" connect --local
|
|
192
|
+
fi
|
|
193
|
+
fi
|
|
164
194
|
prompt_github_connect
|
|
165
195
|
|
|
166
196
|
cat <<'EOF'
|
package/src/auth.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
3
|
+
import { homedir, hostname } from 'node:os';
|
|
4
4
|
import { join, dirname } from 'node:path';
|
|
5
5
|
import type { AuthConfig } from './types.js';
|
|
6
6
|
|
|
@@ -127,6 +127,30 @@ export async function saveLicense(config: AuthConfig): Promise<void> {
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
export async function generateLocalLicense(): Promise<AuthConfig> {
|
|
131
|
+
const existing = await loadLicense();
|
|
132
|
+
if (existing?.token && existing?.sub) return existing;
|
|
133
|
+
const now = new Date();
|
|
134
|
+
const localToken = `local_${createHash('sha256').update(`${now.toISOString()}-${process.pid || 0}-${Math.random()}`).digest('hex').slice(0, 32)}`;
|
|
135
|
+
const ownerToken = `aria_${createHash('sha256').update(localToken).digest('hex').slice(0, 24)}`;
|
|
136
|
+
const license: AuthConfig = {
|
|
137
|
+
sub: `local-${createHash('sha256').update(hostname()).digest('hex').slice(0, 12)}`,
|
|
138
|
+
token: localToken,
|
|
139
|
+
harnessToken: ownerToken,
|
|
140
|
+
jti: `local-${Date.now()}`,
|
|
141
|
+
iat: Math.floor(now.getTime() / 1000),
|
|
142
|
+
iss: 'aria-local-runtime',
|
|
143
|
+
licenseVersion: 1,
|
|
144
|
+
features: { offline: true, localRuntime: true, coachGovernance: true },
|
|
145
|
+
};
|
|
146
|
+
await saveLicense(license);
|
|
147
|
+
try {
|
|
148
|
+
await mkdir(dirname(OWNER_TOKEN_PATH), { recursive: true, mode: 0o700 });
|
|
149
|
+
await writeFile(OWNER_TOKEN_PATH, ownerToken + '\n', { mode: 0o600, encoding: 'utf-8' });
|
|
150
|
+
} catch {}
|
|
151
|
+
return license;
|
|
152
|
+
}
|
|
153
|
+
|
|
130
154
|
export async function resolveHarnessToken(
|
|
131
155
|
options: ResolveHarnessTokenOptions = {},
|
|
132
156
|
): Promise<ResolvedHarnessToken> {
|
package/src/connectors/codex.ts
CHANGED
|
@@ -525,7 +525,6 @@ try {
|
|
|
525
525
|
function buildCodexPreToolHook(): string {
|
|
526
526
|
return `#!/usr/bin/env node
|
|
527
527
|
import {
|
|
528
|
-
getHarnessClient,
|
|
529
528
|
inferSessionId,
|
|
530
529
|
classifyAction,
|
|
531
530
|
summarizeTarget,
|
|
@@ -534,14 +533,11 @@ import {
|
|
|
534
533
|
makeEvidenceRef,
|
|
535
534
|
recordCoachPhase,
|
|
536
535
|
saveTurnState,
|
|
537
|
-
runGovernanceGate,
|
|
538
|
-
updateTaskProjectLedger,
|
|
539
536
|
formatCodexRecoveryBlock,
|
|
540
537
|
emitJson,
|
|
541
538
|
} from './lib/runtime-client.mjs';
|
|
542
539
|
|
|
543
540
|
const event = readEventFromStdin();
|
|
544
|
-
const client = getHarnessClient();
|
|
545
541
|
const sessionId = inferSessionId(event);
|
|
546
542
|
const action = classifyAction(event);
|
|
547
543
|
const target = summarizeTarget(event);
|
|
@@ -579,35 +575,6 @@ try {
|
|
|
579
575
|
}),
|
|
580
576
|
});
|
|
581
577
|
}
|
|
582
|
-
const actionCheck = await client.checkAction(action, target);
|
|
583
|
-
if (actionCheck?.allowed === false) {
|
|
584
|
-
emitJson({
|
|
585
|
-
decision: 'block',
|
|
586
|
-
reason: formatCodexRecoveryBlock({
|
|
587
|
-
surface: 'codex-pre-tool-action',
|
|
588
|
-
reason: actionCheck?.reason || \`Aria denied \${action}\`,
|
|
589
|
-
next: '6. Add the required verification/cognition contract for the action, then request the tool again.',
|
|
590
|
-
}),
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
updateTaskProjectLedger({
|
|
594
|
-
platform: 'codex',
|
|
595
|
-
phase: 'pre_tool',
|
|
596
|
-
source: 'codex-pre-tool-hook',
|
|
597
|
-
event: { ...event, sessionId, cwd: process.cwd() },
|
|
598
|
-
evidence: { action_ref: requestRef },
|
|
599
|
-
});
|
|
600
|
-
runGovernanceGate({
|
|
601
|
-
sessionId,
|
|
602
|
-
sourceRuntime: 'codex',
|
|
603
|
-
surface: 'codex-pre-tool-use',
|
|
604
|
-
text: JSON.stringify(event).slice(0, 8000),
|
|
605
|
-
action,
|
|
606
|
-
toolName,
|
|
607
|
-
isDeploy: action === 'deploy',
|
|
608
|
-
isMutation: action === 'write' || action === 'delete',
|
|
609
|
-
evidence: requestRef,
|
|
610
|
-
});
|
|
611
578
|
const tools = Array.isArray(state?.tools) ? state.tools.slice(-24) : [];
|
|
612
579
|
tools.push({
|
|
613
580
|
at: new Date().toISOString(),
|
|
@@ -712,7 +679,6 @@ import {
|
|
|
712
679
|
formatValidationFailure,
|
|
713
680
|
formatCodexRecoveryBlock,
|
|
714
681
|
isAriaControlBlock,
|
|
715
|
-
runGovernanceGate,
|
|
716
682
|
updateTaskProjectLedger,
|
|
717
683
|
evaluateTaskProjectClaim,
|
|
718
684
|
recordBlockedTaskProjectClaim,
|
|
@@ -777,14 +743,6 @@ try {
|
|
|
777
743
|
}),
|
|
778
744
|
});
|
|
779
745
|
}
|
|
780
|
-
runGovernanceGate({
|
|
781
|
-
sessionId,
|
|
782
|
-
sourceRuntime: 'codex',
|
|
783
|
-
surface: 'codex-stop',
|
|
784
|
-
text: text.slice(0, 8000),
|
|
785
|
-
isOutputCloseout: true,
|
|
786
|
-
evidence: outputRef,
|
|
787
|
-
});
|
|
788
746
|
const validation = await runtimePost('/validate-output', {
|
|
789
747
|
text,
|
|
790
748
|
sessionId,
|
package/src/setup-wizard.ts
CHANGED
|
@@ -113,7 +113,17 @@ export async function runSetupWizard(): Promise<void> {
|
|
|
113
113
|
|
|
114
114
|
const resp = await callConverse({ sessionId, action, userMessage });
|
|
115
115
|
if (!resp.ok) {
|
|
116
|
-
|
|
116
|
+
const errMsg = resp.error || 'unknown';
|
|
117
|
+
console.error(`\n⚠ Aria Soul backend is unreachable: ${errMsg}`);
|
|
118
|
+
console.log('\nYou can continue with local-only mode.');
|
|
119
|
+
console.log('Local mode gives you Coach governance, hooks, and runtime.');
|
|
120
|
+
console.log('Full features (hive sync, garden memory) activate when the server is reachable.\n');
|
|
121
|
+
const useLocal = await ask('Continue with local-only setup? [Y/n]: ');
|
|
122
|
+
if (useLocal.toLowerCase().startsWith('n')) {
|
|
123
|
+
console.log('\nRun `aria` again when the server is available, or use `aria login <token>`.\n');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
await runLocalOnlySetup(ask);
|
|
117
127
|
return;
|
|
118
128
|
}
|
|
119
129
|
|
|
@@ -345,6 +355,38 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
345
355
|
}
|
|
346
356
|
}
|
|
347
357
|
|
|
358
|
+
async function runLocalOnlySetup(ask: (q: string) => Promise<string>): Promise<void> {
|
|
359
|
+
const { generateLocalLicense } = await import('./auth.js');
|
|
360
|
+
const { connectClaudeCode } = await import('./connectors/claude-code.js');
|
|
361
|
+
const { connectCodex } = await import('./connectors/codex.js');
|
|
362
|
+
const { installSharedRuntime } = await import('./connectors/runtime.js');
|
|
363
|
+
const provider = (await ask('LLM provider (openai/anthropic/deepseek/xai/google/openrouter): ')).trim().toLowerCase() || 'openai';
|
|
364
|
+
const apiKey = await ask(`${provider} API key: `);
|
|
365
|
+
const license = await generateLocalLicense();
|
|
366
|
+
console.log(`\n Local license generated (${license.sub}).`);
|
|
367
|
+
const config = loadConfig();
|
|
368
|
+
const validProvider = (['openai', 'anthropic', 'deepseek', 'xai', 'google', 'openrouter', 'ollama'] as const).find(
|
|
369
|
+
(p) => provider === p,
|
|
370
|
+
) || 'openai';
|
|
371
|
+
config.model = {
|
|
372
|
+
provider: validProvider,
|
|
373
|
+
model: defaultModelForProvider(validProvider),
|
|
374
|
+
apiKey,
|
|
375
|
+
};
|
|
376
|
+
const { saveConfig: sc } = await import('./config.js');
|
|
377
|
+
sc(config as Parameters<typeof sc>[0]);
|
|
378
|
+
console.log(' Installing runtime and hooks...');
|
|
379
|
+
const logs = [
|
|
380
|
+
...(await installSharedRuntime()),
|
|
381
|
+
...(await connectClaudeCode(config, { force: true })),
|
|
382
|
+
...(await connectCodex(config)),
|
|
383
|
+
];
|
|
384
|
+
for (const line of logs) console.log(` ${line}`);
|
|
385
|
+
console.log('\n✅ Local setup complete.');
|
|
386
|
+
console.log(' Your CLIs are wired with Coach governance.');
|
|
387
|
+
console.log(' Run `aria login <token>` when the server becomes available for full features.\n');
|
|
388
|
+
}
|
|
389
|
+
|
|
348
390
|
function defaultModelForProvider(provider: string): string {
|
|
349
391
|
const defaults: Record<string, string> = {
|
|
350
392
|
anthropic: 'claude-sonnet-4-20250514',
|
package/src/types.ts
CHANGED
|
@@ -9,8 +9,14 @@ export interface AuthConfig {
|
|
|
9
9
|
token?: string;
|
|
10
10
|
/** License JWT identifier */
|
|
11
11
|
jti?: string;
|
|
12
|
+
/** License issuer */
|
|
13
|
+
iss?: string;
|
|
12
14
|
/** License tier (e.g. 'standard', 'pro') */
|
|
13
15
|
tier?: string;
|
|
16
|
+
/** License version */
|
|
17
|
+
licenseVersion?: number;
|
|
18
|
+
/** License features map */
|
|
19
|
+
features?: Record<string, boolean>;
|
|
14
20
|
/** License expiry unix timestamp */
|
|
15
21
|
exp?: number;
|
|
16
22
|
/** License issued-at unix timestamp */
|