@aria_asi/cli 0.2.36 → 0.2.38
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/CLIENT-ONBOARDING.md +4 -2
- package/bin/aria.js +11 -7
- package/dist/aria-connector/src/auth.d.ts +14 -0
- package/dist/aria-connector/src/auth.d.ts.map +1 -1
- package/dist/aria-connector/src/auth.js +103 -1
- package/dist/aria-connector/src/auth.js.map +1 -1
- package/dist/aria-connector/src/chat.d.ts.map +1 -1
- package/dist/aria-connector/src/chat.js +13 -8
- package/dist/aria-connector/src/chat.js.map +1 -1
- package/dist/aria-connector/src/config.d.ts +6 -1
- package/dist/aria-connector/src/config.d.ts.map +1 -1
- package/dist/aria-connector/src/config.js.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +50 -6
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +290 -32
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +35 -11
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.d.ts +10 -0
- package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.js +110 -164
- package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.js +17 -7
- package/dist/aria-connector/src/connectors/runtime.js.map +1 -1
- package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/shell.js +12 -8
- package/dist/aria-connector/src/connectors/shell.js.map +1 -1
- package/dist/aria-connector/src/harness-client.d.ts +3 -1
- package/dist/aria-connector/src/harness-client.d.ts.map +1 -1
- package/dist/aria-connector/src/harness-client.js +7 -20
- package/dist/aria-connector/src/harness-client.js.map +1 -1
- package/dist/aria-connector/src/model-context.d.ts.map +1 -1
- package/dist/aria-connector/src/model-context.js +5 -0
- package/dist/aria-connector/src/model-context.js.map +1 -1
- package/dist/aria-connector/src/providers/types.d.ts +1 -1
- package/dist/aria-connector/src/providers/types.d.ts.map +1 -1
- package/dist/aria-connector/src/providers/xai.d.ts +3 -0
- package/dist/aria-connector/src/providers/xai.d.ts.map +1 -0
- package/dist/aria-connector/src/providers/xai.js +40 -0
- package/dist/aria-connector/src/providers/xai.js.map +1 -0
- package/dist/aria-connector/src/setup-wizard.js +1 -0
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/aria-connector/src/types.d.ts +2 -0
- package/dist/aria-connector/src/types.d.ts.map +1 -1
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/dist/assets/hooks/aria-first-class-coach.mjs +129 -0
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +33 -6
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +86 -8
- package/dist/assets/hooks/aria-pre-tool-use.mjs +75 -0
- package/dist/assets/hooks/aria-preprompt-consult.mjs +5 -6
- package/dist/assets/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +125 -17
- package/dist/assets/hooks/doctrine_trigger_map.json +11 -0
- package/dist/assets/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/dist/assets/hooks/lib/emergency-gateoff.mjs +6 -0
- package/dist/assets/hooks/lib/first-class-coach.mjs +755 -0
- package/dist/assets/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/dist/assets/opencode-plugins/harness-context/auth-token.mjs +126 -0
- package/dist/assets/opencode-plugins/harness-context/inject-context.mjs +62 -22
- package/dist/assets/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +87 -27
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
- package/dist/assets/opencode-plugins/harness-outcome/index.js +29 -24
- package/dist/assets/opencode-plugins/harness-stop/index.js +229 -68
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
- package/dist/runtime/auth-token.mjs +121 -0
- package/dist/runtime/coach-kernel.mjs +377 -0
- package/dist/runtime/codex-bridge.mjs +440 -69
- package/dist/runtime/discipline/doctrine_trigger_map.json +11 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-essence/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/mizan/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/predictor/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-cognition/soul-domains/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-intra-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-post-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-aristotle-pre-phase/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-deploy/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-no-stripping/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-output-discipline/SKILL.md +18 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-substrate-binding/SKILL.md +18 -0
- package/dist/runtime/doctrine_trigger_map.json +11 -0
- package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/dist/runtime/hooks/aria-first-class-coach.mjs +129 -0
- package/dist/runtime/hooks/aria-harness-via-sdk.mjs +33 -6
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +86 -8
- package/dist/runtime/hooks/aria-pre-tool-use.mjs +75 -0
- package/dist/runtime/hooks/aria-preprompt-consult.mjs +5 -6
- package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/dist/runtime/hooks/aria-stop-gate.mjs +125 -17
- package/dist/runtime/hooks/doctrine_trigger_map.json +11 -0
- package/dist/runtime/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/dist/runtime/hooks/lib/emergency-gateoff.mjs +6 -0
- package/dist/runtime/hooks/lib/first-class-coach.mjs +755 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/dist/runtime/local-phase.mjs +8 -0
- package/dist/runtime/manifest.json +2 -2
- package/dist/runtime/provider-proxy.mjs +136 -33
- package/dist/runtime/sdk/BUNDLED.json +2 -2
- package/dist/runtime/sdk/auth.d.ts +17 -0
- package/dist/runtime/sdk/auth.js +158 -0
- package/dist/runtime/sdk/auth.js.map +1 -0
- package/dist/runtime/sdk/index.d.ts +8 -1
- package/dist/runtime/sdk/index.js +15 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +1711 -74
- package/dist/runtime/task-project-ledger.mjs +290 -0
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/auth.d.ts +17 -0
- package/dist/sdk/auth.js +158 -0
- package/dist/sdk/auth.js.map +1 -0
- package/dist/sdk/index.d.ts +8 -1
- package/dist/sdk/index.js +15 -1
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-cognition-substrate-binding.mjs +51 -9
- package/hooks/aria-first-class-coach.mjs +129 -0
- package/hooks/aria-harness-via-sdk.mjs +33 -6
- package/hooks/aria-pre-tool-gate.mjs +86 -8
- package/hooks/aria-pre-tool-use.mjs +75 -0
- package/hooks/aria-preprompt-consult.mjs +5 -6
- package/hooks/aria-preturn-memory-gate.mjs +5 -0
- package/hooks/aria-repo-doctrine-gate.mjs +15 -0
- package/hooks/aria-stop-gate.mjs +125 -17
- package/hooks/doctrine_trigger_map.json +11 -0
- package/hooks/lib/emergency-gateoff-impl.mjs +39 -0
- package/hooks/lib/emergency-gateoff.mjs +6 -0
- package/hooks/lib/first-class-coach.mjs +755 -0
- package/hooks/lib/skill-autoload-gate-impl.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +1 -14
- package/opencode-plugins/harness-context/auth-token.mjs +126 -0
- package/opencode-plugins/harness-context/inject-context.mjs +62 -22
- package/opencode-plugins/harness-context/task-project-ledger.mjs +290 -0
- package/opencode-plugins/harness-gate/index.js +87 -27
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -14
- package/opencode-plugins/harness-outcome/index.js +29 -24
- package/opencode-plugins/harness-stop/index.js +229 -68
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -14
- package/package.json +8 -2
- package/runtime-src/auth-token.mjs +121 -0
- package/runtime-src/coach-kernel.mjs +377 -0
- package/runtime-src/codex-bridge.mjs +440 -69
- package/runtime-src/local-phase.mjs +8 -0
- package/runtime-src/provider-proxy.mjs +136 -33
- package/runtime-src/service.mjs +1711 -74
- package/scripts/bundle-sdk.mjs +8 -0
- package/scripts/check-client-compatibility.mjs +422 -0
- package/scripts/check-coach-kernel.mjs +204 -0
- package/scripts/check-managed-runtime-ledger.mjs +107 -0
- package/scripts/check-opencode-config-contract.mjs +78 -0
- package/scripts/check-quality-ledger.mjs +121 -0
- package/scripts/self-test-harness-gates.mjs +179 -11
- package/scripts/self-test-repo-guard.mjs +38 -0
- package/scripts/validate-skill-prompts.mjs +14 -1
- package/skills/aria-cognition/aria-essence/SKILL.md +18 -0
- package/skills/aria-cognition/aria-forge-guardrails/SKILL.md +18 -0
- package/skills/aria-cognition/aria-repo-doctrine/SKILL.md +18 -0
- package/skills/aria-cognition/forge-quality-rules/SKILL.md +18 -0
- package/skills/aria-cognition/ghazali-8lens/SKILL.md +18 -0
- package/skills/aria-cognition/istiqra-induction/SKILL.md +18 -0
- package/skills/aria-cognition/ladunni-22/SKILL.md +18 -0
- package/skills/aria-cognition/mizan/SKILL.md +18 -0
- package/skills/aria-cognition/nadia/SKILL.md +18 -0
- package/skills/aria-cognition/nadia-psi/SKILL.md +18 -0
- package/skills/aria-cognition/predictor/SKILL.md +18 -0
- package/skills/aria-cognition/qiyas-analogy/SKILL.md +18 -0
- package/skills/aria-cognition/soul-domains/SKILL.md +18 -0
- package/src/auth.ts +136 -1
- package/src/chat.ts +13 -8
- package/src/config.ts +6 -1
- package/src/connectors/claude-code.ts +62 -18
- package/src/connectors/codex.ts +288 -32
- package/src/connectors/opencode.ts +35 -12
- package/src/connectors/repo-guard.ts +117 -172
- package/src/connectors/runtime.ts +19 -7
- package/src/connectors/shell.ts +12 -8
- package/src/harness-client.ts +8 -22
- package/src/model-context.ts +6 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/xai.ts +55 -0
- package/src/setup-wizard.ts +1 -0
- package/src/types.ts +2 -0
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import chokidar from 'chokidar';
|
|
2
2
|
import { execFileSync } from 'child_process';
|
|
3
|
-
import { createHash } from 'crypto';
|
|
4
3
|
import {
|
|
5
4
|
existsSync,
|
|
6
5
|
mkdirSync,
|
|
7
|
-
readdirSync,
|
|
8
6
|
readFileSync,
|
|
9
7
|
statSync,
|
|
10
|
-
renameSync,
|
|
11
8
|
writeFileSync,
|
|
12
9
|
} from 'fs';
|
|
13
10
|
import { homedir } from 'os';
|
|
@@ -22,17 +19,10 @@ const ENV_PATH = path.join(ARIA_DIR, 'repo-guard.env');
|
|
|
22
19
|
const STATE_PATH = path.join(ARIA_DIR, 'repo-guard-state.json');
|
|
23
20
|
const EVENTS_PATH = path.join(ARIA_DIR, 'repo-guard-events.jsonl');
|
|
24
21
|
const LAST_ALERT_PATH = path.join(ARIA_DIR, 'repo-guard-last-alert.json');
|
|
25
|
-
const
|
|
22
|
+
const APPROVALS_PATH = path.join(ARIA_DIR, 'repo-guard-approvals.json');
|
|
26
23
|
const QUARANTINE_ROOT = path.join(ARIA_DIR, 'repo-guard', 'quarantine');
|
|
27
24
|
const DEFAULT_DEBOUNCE_MS = Number(process.env.ARIA_REPO_GUARD_DEBOUNCE_MS || 350);
|
|
28
25
|
const BLOCKING_MODE = !/^(0|false|no)$/i.test(process.env.ARIA_REPO_GUARD_BLOCKING || 'true');
|
|
29
|
-
const DOCTRINE_PREFIXES = ['apps/', 'packages/', 'harness/', 'ops/', 'scripts/'];
|
|
30
|
-
const DOCTRINE_EXTENSIONS = new Set([
|
|
31
|
-
'.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
|
|
32
|
-
'.py', '.sh', '.bash', '.zsh', '.rb', '.go',
|
|
33
|
-
'.rs', '.java', '.kt', '.cs', '.php', '.swift',
|
|
34
|
-
'.scala', '.yml', '.yaml',
|
|
35
|
-
]);
|
|
36
26
|
const IGNORED_SEGMENTS = new Set([
|
|
37
27
|
'.git',
|
|
38
28
|
'node_modules',
|
|
@@ -44,10 +34,13 @@ const IGNORED_SEGMENTS = new Set([
|
|
|
44
34
|
'coverage',
|
|
45
35
|
'archive',
|
|
46
36
|
'generated',
|
|
37
|
+
'vendor',
|
|
47
38
|
'telegram_env',
|
|
48
39
|
'backup-opencode-config',
|
|
49
40
|
'training-data',
|
|
50
41
|
]);
|
|
42
|
+
const IGNORED_FILE_RX = /(?:^|\/)(?:package-lock\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb?|\.DS_Store)$/i;
|
|
43
|
+
const DEFAULT_APPROVAL_TTL_MS = Number(process.env.ARIA_REPO_GUARD_APPROVAL_TTL_MS || 10 * 60 * 1000);
|
|
51
44
|
|
|
52
45
|
type GuardStatus = 'idle' | 'watching' | 'violation' | 'error';
|
|
53
46
|
|
|
@@ -72,7 +65,16 @@ interface AlertPayload {
|
|
|
72
65
|
relPath?: string;
|
|
73
66
|
action?: string;
|
|
74
67
|
detail?: string;
|
|
75
|
-
type: '
|
|
68
|
+
type: 'blocked-delete' | 'watcher-error' | 'status' | 'observed-change' | 'approved-delete' | 'ignored-delete';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface DeleteApproval {
|
|
72
|
+
repoRoot: string;
|
|
73
|
+
relPath: string;
|
|
74
|
+
approvedBy: string;
|
|
75
|
+
approvedAt: string;
|
|
76
|
+
expiresAt: string;
|
|
77
|
+
reason: string;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
function writeState(update: Partial<GuardState>): GuardState {
|
|
@@ -177,19 +179,6 @@ function normalizeRel(input: string): string {
|
|
|
177
179
|
return input.split(path.sep).join('/');
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
function repoHash(repoRoot: string): string {
|
|
181
|
-
return createHash('sha256').update(repoRoot).digest('hex').slice(0, 16);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function shadowPath(repoRoot: string, relPath: string): string {
|
|
185
|
-
return path.join(SHADOW_ROOT, repoHash(repoRoot), relPath);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function quarantinePath(repoRoot: string, relPath: string): string {
|
|
189
|
-
const stamped = `${Date.now()}-${relPath.replace(/[\\/]/g, '__')}`;
|
|
190
|
-
return path.join(QUARANTINE_ROOT, repoHash(repoRoot), stamped);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
182
|
function ensureParent(filePath: string): void {
|
|
194
183
|
mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o755 });
|
|
195
184
|
}
|
|
@@ -231,168 +220,150 @@ function resolveRepos(config?: AriaConfig, explicit?: string[], fallbackRepoPath
|
|
|
231
220
|
return cwd ? [cwd] : [];
|
|
232
221
|
}
|
|
233
222
|
|
|
234
|
-
function
|
|
223
|
+
export function isRepoGuardedPath(relPath: string): boolean {
|
|
235
224
|
const normalized = normalizeRel(relPath);
|
|
236
|
-
if (!DOCTRINE_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return false;
|
|
237
|
-
if (!DOCTRINE_EXTENSIONS.has(path.extname(normalized))) return false;
|
|
238
225
|
const parts = normalized.split('/');
|
|
239
226
|
if (parts.some((part) => IGNORED_SEGMENTS.has(part))) return false;
|
|
240
|
-
if (normalized.endsWith('.map')) return false;
|
|
241
|
-
if (/package-lock\.json$|pnpm-lock\.yaml$|yarn\.lock$/i.test(normalized)) return false;
|
|
227
|
+
if (normalized.endsWith('.map') || IGNORED_FILE_RX.test(normalized)) return false;
|
|
242
228
|
return true;
|
|
243
229
|
}
|
|
244
230
|
|
|
245
|
-
function
|
|
246
|
-
const found: string[] = [];
|
|
247
|
-
|
|
248
|
-
function visit(absPath: string): void {
|
|
249
|
-
const stat = statSync(absPath);
|
|
250
|
-
if (stat.isDirectory()) {
|
|
251
|
-
const base = path.basename(absPath);
|
|
252
|
-
if (IGNORED_SEGMENTS.has(base)) return;
|
|
253
|
-
for (const child of readdirSync(absPath)) {
|
|
254
|
-
visit(path.join(absPath, child));
|
|
255
|
-
}
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const rel = path.relative(repoRoot, absPath);
|
|
260
|
-
if (isDoctrineBound(rel)) found.push(absPath);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
for (const prefix of DOCTRINE_PREFIXES) {
|
|
264
|
-
const abs = path.join(repoRoot, prefix.slice(0, -1));
|
|
265
|
-
if (existsSync(abs)) visit(abs);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return found;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function gateFile(repoRoot: string, relPath: string): { ok: true } | { ok: false; detail: string } {
|
|
272
|
-
const hookPath = path.join(homedir(), '.claude', 'hooks', 'aria-repo-doctrine-gate.mjs');
|
|
231
|
+
function isGitTracked(repoRoot: string, relPath: string): boolean {
|
|
273
232
|
try {
|
|
274
|
-
execFileSync('
|
|
275
|
-
stdio: ['ignore', '
|
|
276
|
-
encoding: 'utf8',
|
|
233
|
+
execFileSync('git', ['-C', repoRoot, 'ls-files', '--error-unmatch', normalizeRel(relPath)], {
|
|
234
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
277
235
|
});
|
|
278
|
-
return
|
|
279
|
-
} catch
|
|
280
|
-
|
|
281
|
-
? String((error as { stderr?: string }).stderr || (error as { stdout?: string }).stdout || error.message)
|
|
282
|
-
: String(error);
|
|
283
|
-
return { ok: false, detail: detail.trim() || 'aria repo doctrine gate rejected the file' };
|
|
236
|
+
return true;
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
284
239
|
}
|
|
285
240
|
}
|
|
286
241
|
|
|
287
|
-
function
|
|
288
|
-
const dst = shadowPath(repoRoot, relPath);
|
|
289
|
-
ensureParent(dst);
|
|
290
|
-
writeFileSync(dst, content, { mode: 0o600 });
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function readShadowContent(repoRoot: string, relPath: string): string | null {
|
|
294
|
-
const shadow = shadowPath(repoRoot, relPath);
|
|
295
|
-
if (!existsSync(shadow)) return null;
|
|
242
|
+
function readTrackedContent(repoRoot: string, relPath: string): Buffer | null {
|
|
296
243
|
try {
|
|
297
|
-
return
|
|
244
|
+
return execFileSync('git', ['-C', repoRoot, 'show', `HEAD:${normalizeRel(relPath)}`], {
|
|
245
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
246
|
+
encoding: 'buffer',
|
|
247
|
+
});
|
|
298
248
|
} catch {
|
|
299
249
|
return null;
|
|
300
250
|
}
|
|
301
251
|
}
|
|
302
252
|
|
|
303
|
-
function
|
|
253
|
+
function isGitDirectory(repoRoot: string, relPath: string): boolean {
|
|
304
254
|
try {
|
|
305
|
-
|
|
255
|
+
const output = execFileSync('git', ['-C', repoRoot, 'ls-files', `${normalizeRel(relPath).replace(/\/+$/, '')}/`], {
|
|
306
256
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
307
257
|
encoding: 'utf8',
|
|
308
258
|
});
|
|
259
|
+
return output.trim().length > 0;
|
|
309
260
|
} catch {
|
|
310
|
-
return
|
|
261
|
+
return false;
|
|
311
262
|
}
|
|
312
263
|
}
|
|
313
264
|
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
function restorePriorContent(repoRoot: string, absPath: string, relPath: string): 'restored' | 'moved' | 'none' {
|
|
319
|
-
const prior = recoveryContent(repoRoot, relPath);
|
|
265
|
+
function restoreTrackedPath(repoRoot: string, absPath: string, relPath: string): 'file-restored' | 'tree-restored' | 'none' {
|
|
266
|
+
const prior = readTrackedContent(repoRoot, relPath);
|
|
320
267
|
if (prior !== null) {
|
|
321
268
|
ensureParent(absPath);
|
|
322
269
|
writeFileSync(absPath, prior, { mode: 0o644 });
|
|
323
|
-
|
|
324
|
-
return 'restored';
|
|
270
|
+
return 'file-restored';
|
|
325
271
|
}
|
|
326
272
|
|
|
327
|
-
if (!
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
273
|
+
if (!isGitDirectory(repoRoot, relPath)) return 'none';
|
|
274
|
+
try {
|
|
275
|
+
execFileSync('git', ['-C', repoRoot, 'checkout', 'HEAD', '--', normalizeRel(relPath)], {
|
|
276
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
277
|
+
});
|
|
278
|
+
return 'tree-restored';
|
|
279
|
+
} catch {
|
|
280
|
+
return 'none';
|
|
281
|
+
}
|
|
333
282
|
}
|
|
334
283
|
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
284
|
+
function readApprovals(): DeleteApproval[] {
|
|
285
|
+
try {
|
|
286
|
+
const parsed = JSON.parse(readFileSync(APPROVALS_PATH, 'utf8')) as unknown;
|
|
287
|
+
if (!Array.isArray(parsed)) return [];
|
|
288
|
+
return parsed.filter((item): item is DeleteApproval => {
|
|
289
|
+
if (!item || typeof item !== 'object') return false;
|
|
290
|
+
const approval = item as Partial<DeleteApproval>;
|
|
291
|
+
return Boolean(approval.repoRoot && approval.relPath && approval.approvedBy && approval.expiresAt);
|
|
292
|
+
});
|
|
293
|
+
} catch {
|
|
294
|
+
return [];
|
|
341
295
|
}
|
|
342
296
|
}
|
|
343
297
|
|
|
344
|
-
function
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
298
|
+
function writeApprovals(approvals: DeleteApproval[]): void {
|
|
299
|
+
mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
|
|
300
|
+
writeFileSync(APPROVALS_PATH, JSON.stringify(approvals, null, 2) + '\n', { mode: 0o600 });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function hasDeleteApproval(repoRoot: string, relPath: string): boolean {
|
|
304
|
+
const now = Date.now();
|
|
305
|
+
const approvals = readApprovals();
|
|
306
|
+
const active = approvals.filter((approval) => Date.parse(approval.expiresAt) > now);
|
|
307
|
+
if (active.length !== approvals.length) writeApprovals(active);
|
|
308
|
+
const normalizedRepo = path.resolve(repoRoot);
|
|
309
|
+
const normalizedPath = normalizeRel(relPath);
|
|
310
|
+
return active.some((approval) => path.resolve(approval.repoRoot) === normalizedRepo && normalizeRel(approval.relPath) === normalizedPath);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function approveRepoGuardDelete(repoRoot: string, relPath: string, approvedBy = 'owner', reason = 'explicit owner approval', ttlMs = DEFAULT_APPROVAL_TTL_MS): DeleteApproval {
|
|
314
|
+
const approval: DeleteApproval = {
|
|
315
|
+
repoRoot: path.resolve(repoRoot),
|
|
316
|
+
relPath: normalizeRel(relPath),
|
|
317
|
+
approvedBy,
|
|
318
|
+
approvedAt: new Date().toISOString(),
|
|
319
|
+
expiresAt: new Date(Date.now() + ttlMs).toISOString(),
|
|
320
|
+
reason,
|
|
321
|
+
};
|
|
322
|
+
writeApprovals([...readApprovals(), approval]);
|
|
323
|
+
appendEvent({ type: 'delete-approved', ...approval });
|
|
324
|
+
return approval;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function handleDeletedGuardedPath(repoRoot: string, absPath: string, relPath: string): void {
|
|
328
|
+
const tracked = isGitTracked(repoRoot, relPath) || isGitDirectory(repoRoot, relPath);
|
|
329
|
+
if (!tracked) {
|
|
330
|
+
appendEvent({
|
|
331
|
+
type: 'ignored-delete',
|
|
332
|
+
repoRoot,
|
|
333
|
+
relPath,
|
|
334
|
+
detail: 'Untracked path deletion observed; nothing can be restored from git.',
|
|
335
|
+
});
|
|
336
|
+
writeState({ status: 'watching', lastEvent: `${repoRoot}:${relPath}`, lastError: null });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
351
339
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
relPath,
|
|
358
|
-
quarantineDst,
|
|
359
|
-
blockingMode: BLOCKING_MODE,
|
|
360
|
-
action,
|
|
361
|
-
detail,
|
|
362
|
-
});
|
|
363
|
-
emitAlert({
|
|
364
|
-
type: 'violation',
|
|
365
|
-
title: 'Aria Repo Guard blocked a doctrine violation',
|
|
366
|
-
message: BLOCKING_MODE
|
|
367
|
-
? 'The changed file was quarantined and the last known good content was restored.'
|
|
368
|
-
: 'A doctrine violation was detected while repo guard was in non-blocking mode.',
|
|
369
|
-
repoRoot,
|
|
370
|
-
relPath,
|
|
371
|
-
action,
|
|
372
|
-
detail,
|
|
373
|
-
});
|
|
374
|
-
}
|
|
340
|
+
if (hasDeleteApproval(repoRoot, relPath)) {
|
|
341
|
+
appendEvent({ type: 'approved-delete', repoRoot, relPath });
|
|
342
|
+
writeState({ status: 'watching', lastEvent: `${repoRoot}:${relPath}`, lastError: null });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
375
345
|
|
|
376
|
-
|
|
377
|
-
const action = BLOCKING_MODE ? restorePriorContent(repoRoot, absPath, relPath) : 'none';
|
|
378
|
-
if (action === 'none') return;
|
|
346
|
+
const action = BLOCKING_MODE ? restoreTrackedPath(repoRoot, absPath, relPath) : 'none';
|
|
379
347
|
const summary = `${repoRoot}:${relPath}`;
|
|
380
|
-
writeState({ status: 'violation', lastViolation: summary, lastEvent: summary, lastError: '
|
|
348
|
+
writeState({ status: 'violation', lastViolation: summary, lastEvent: summary, lastError: 'Tracked path deletion requires explicit approval.' });
|
|
381
349
|
appendEvent({
|
|
382
350
|
type: 'blocked-delete',
|
|
383
351
|
repoRoot,
|
|
384
352
|
relPath,
|
|
385
353
|
blockingMode: BLOCKING_MODE,
|
|
386
354
|
action,
|
|
355
|
+
detail: 'Tracked path deletion restored from git because no active delete approval matched this path.',
|
|
387
356
|
});
|
|
388
357
|
emitAlert({
|
|
389
358
|
type: 'blocked-delete',
|
|
390
|
-
title: 'Aria Repo Guard blocked
|
|
391
|
-
message:
|
|
359
|
+
title: 'Aria Repo Guard blocked an unapproved tracked deletion',
|
|
360
|
+
message: BLOCKING_MODE
|
|
361
|
+
? 'A tracked repo path was deleted without active approval and was restored from git.'
|
|
362
|
+
: 'A tracked repo path was deleted without active approval while repo guard was non-blocking.',
|
|
392
363
|
repoRoot,
|
|
393
364
|
relPath,
|
|
394
365
|
action,
|
|
395
|
-
detail: '
|
|
366
|
+
detail: 'Tracked path deletion requires explicit approval.',
|
|
396
367
|
});
|
|
397
368
|
}
|
|
398
369
|
|
|
@@ -411,22 +382,14 @@ function findOwningRepo(repos: string[], absPath: string): string | null {
|
|
|
411
382
|
|
|
412
383
|
function processChangedFile(repoRoot: string, absPath: string): void {
|
|
413
384
|
const relPath = path.relative(repoRoot, absPath);
|
|
414
|
-
if (!
|
|
385
|
+
if (!isRepoGuardedPath(relPath)) return;
|
|
415
386
|
if (!existsSync(absPath)) {
|
|
416
|
-
|
|
387
|
+
handleDeletedGuardedPath(repoRoot, absPath, relPath);
|
|
417
388
|
return;
|
|
418
389
|
}
|
|
419
390
|
if (statSync(absPath).isDirectory()) return;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (gate.ok) {
|
|
423
|
-
writeShadow(repoRoot, relPath, readFileSync(absPath, 'utf8'));
|
|
424
|
-
const summary = `${repoRoot}:${relPath}`;
|
|
425
|
-
writeState({ status: 'watching', lastEvent: summary, lastError: null });
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
handleViolation(repoRoot, absPath, relPath, gate.detail);
|
|
391
|
+
appendEvent({ type: 'observed-change', repoRoot, relPath });
|
|
392
|
+
writeState({ status: 'watching', lastEvent: `${repoRoot}:${relPath}`, lastError: null });
|
|
430
393
|
}
|
|
431
394
|
|
|
432
395
|
export async function startRepoGuardDaemon(options: RepoGuardOptions = {}): Promise<void> {
|
|
@@ -436,19 +399,16 @@ export async function startRepoGuardDaemon(options: RepoGuardOptions = {}): Prom
|
|
|
436
399
|
throw new Error('No git repositories configured for repo guard.');
|
|
437
400
|
}
|
|
438
401
|
|
|
439
|
-
mkdirSync(SHADOW_ROOT, { recursive: true, mode: 0o700 });
|
|
440
402
|
mkdirSync(QUARANTINE_ROOT, { recursive: true, mode: 0o700 });
|
|
441
|
-
for (const repo of repos) initializeBaseline(repo);
|
|
442
403
|
|
|
443
404
|
writeState({ status: 'watching', watchedRepos: repos, lastError: null });
|
|
444
405
|
emitAlert({
|
|
445
406
|
type: 'status',
|
|
446
407
|
title: 'Aria Repo Guard watching repositories',
|
|
447
|
-
message: `Watching ${repos.length} repo(s) for
|
|
408
|
+
message: `Watching ${repos.length} repo(s) for unapproved tracked deletions.`,
|
|
448
409
|
});
|
|
449
410
|
|
|
450
411
|
const pending = new Map<string, NodeJS.Timeout>();
|
|
451
|
-
const restoring = new Map<string, number>();
|
|
452
412
|
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
453
413
|
|
|
454
414
|
const watcher = chokidar.watch(repos, {
|
|
@@ -469,30 +429,16 @@ export async function startRepoGuardDaemon(options: RepoGuardOptions = {}): Prom
|
|
|
469
429
|
|
|
470
430
|
const timer = setTimeout(() => {
|
|
471
431
|
pending.delete(absPath);
|
|
472
|
-
const restoredAt = restoring.get(absPath);
|
|
473
|
-
if (restoredAt && Date.now() - restoredAt < 1500) {
|
|
474
|
-
restoring.delete(absPath);
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
432
|
|
|
478
433
|
const relPath = path.relative(repoRoot, absPath);
|
|
479
|
-
if (!
|
|
434
|
+
if (!isRepoGuardedPath(relPath)) return;
|
|
480
435
|
if (!existsSync(absPath)) {
|
|
481
|
-
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const gate = gateFile(repoRoot, relPath);
|
|
486
|
-
if (gate.ok) {
|
|
487
|
-
if (!statSync(absPath).isDirectory()) {
|
|
488
|
-
writeShadow(repoRoot, relPath, readFileSync(absPath, 'utf8'));
|
|
489
|
-
}
|
|
490
|
-
writeState({ status: 'watching', lastEvent: `${repoRoot}:${relPath}`, lastError: null });
|
|
436
|
+
handleDeletedGuardedPath(repoRoot, absPath, relPath);
|
|
491
437
|
return;
|
|
492
438
|
}
|
|
493
439
|
|
|
494
|
-
|
|
495
|
-
|
|
440
|
+
if (!statSync(absPath).isDirectory()) appendEvent({ type: 'observed-change', repoRoot, relPath });
|
|
441
|
+
writeState({ status: 'watching', lastEvent: `${repoRoot}:${relPath}`, lastError: null });
|
|
496
442
|
}, debounceMs);
|
|
497
443
|
|
|
498
444
|
pending.set(absPath, timer);
|
|
@@ -576,7 +522,6 @@ export async function installRepoGuardDaemon(config?: AriaConfig, fallbackRepoPa
|
|
|
576
522
|
}
|
|
577
523
|
|
|
578
524
|
mkdirSync(BIN_DIR, { recursive: true, mode: 0o755 });
|
|
579
|
-
mkdirSync(SHADOW_ROOT, { recursive: true, mode: 0o700 });
|
|
580
525
|
mkdirSync(QUARANTINE_ROOT, { recursive: true, mode: 0o700 });
|
|
581
526
|
const envPath = writeRepoGuardEnv(repos);
|
|
582
527
|
writeWrapper(path.join(BIN_DIR, 'aria-repo-guard'), ['repo-guard']);
|
|
@@ -89,11 +89,14 @@ function writeRuntimeEnv(runtimeDst: string): string {
|
|
|
89
89
|
const envPath = path.join(runtimeDst, 'runtime.env');
|
|
90
90
|
const config = loadConfig();
|
|
91
91
|
const runtimeProfiles = config.runtimeProfiles || {};
|
|
92
|
-
const defaultProvider = config.defaultProvider || config.model?.provider || '
|
|
93
|
-
const chatModel = runtimeProfiles.chatModel || '
|
|
92
|
+
const defaultProvider = config.defaultProvider || config.model?.provider || 'xai';
|
|
93
|
+
const chatModel = runtimeProfiles.chatModel || 'grok-4-3';
|
|
94
94
|
const deepModel = runtimeProfiles.deepModel || 'deepseek-v4-pro';
|
|
95
|
-
const xaiFallbackModel = runtimeProfiles.xaiFallbackModel || 'grok-4-
|
|
95
|
+
const xaiFallbackModel = runtimeProfiles.xaiFallbackModel || 'grok-4-3';
|
|
96
96
|
const nimFallbackModel = runtimeProfiles.nimFallbackModel || 'qwen/qwen3.5-122b-a10b';
|
|
97
|
+
const localFallbackModel = runtimeProfiles.localFallbackModel || 'mlx-community/Qwen2.5-7B-Instruct-4bit';
|
|
98
|
+
const localFallbackBaseUrl =
|
|
99
|
+
runtimeProfiles.localFallbackBaseUrl || 'http://aria-lane-gateway.aria.svc.cluster.local:8089/v1/chat/completions';
|
|
97
100
|
const localHarnessUrl = 'http://127.0.0.1:8790';
|
|
98
101
|
const upstreamHarnessUrl = canonicalUpstreamHarnessUrl();
|
|
99
102
|
const harnessFallbackUrls = [
|
|
@@ -141,8 +144,11 @@ function writeRuntimeEnv(runtimeDst: string): string {
|
|
|
141
144
|
`ARIA_DEEP_MODEL=${deepModel}`,
|
|
142
145
|
`ARIA_XAI_FALLBACK_MODEL=${xaiFallbackModel}`,
|
|
143
146
|
`ARIA_NIM_FALLBACK_MODEL=${nimFallbackModel}`,
|
|
147
|
+
`ARIA_DEEPSEEK_FALLBACK_MODEL=${deepModel}`,
|
|
148
|
+
`ARIA_LOCAL_FALLBACK_MODEL=${localFallbackModel}`,
|
|
149
|
+
`ARIA_LOCAL_FALLBACK_BASE_URL=${localFallbackBaseUrl}`,
|
|
144
150
|
'OPENAI_BASE_URL=http://127.0.0.1:4319/v1',
|
|
145
|
-
'ANTHROPIC_BASE_URL=http://127.0.0.1:4319
|
|
151
|
+
'ANTHROPIC_BASE_URL=http://127.0.0.1:4319',
|
|
146
152
|
'',
|
|
147
153
|
].join('\n'),
|
|
148
154
|
{ mode: 0o600 },
|
|
@@ -176,16 +182,22 @@ function ensureRuntimeProviderDefaults(): void {
|
|
|
176
182
|
const config = loadConfig();
|
|
177
183
|
saveConfig({
|
|
178
184
|
...config,
|
|
179
|
-
defaultProvider: config.defaultProvider || config.model?.provider || '
|
|
185
|
+
defaultProvider: config.defaultProvider || config.model?.provider || 'xai',
|
|
180
186
|
runtimeProfiles: {
|
|
181
|
-
chatModel: config.runtimeProfiles?.chatModel || '
|
|
187
|
+
chatModel: config.runtimeProfiles?.chatModel || 'grok-4-3',
|
|
182
188
|
deepModel: config.runtimeProfiles?.deepModel || 'deepseek-v4-pro',
|
|
183
|
-
xaiFallbackModel: config.runtimeProfiles?.xaiFallbackModel || 'grok-4-
|
|
189
|
+
xaiFallbackModel: config.runtimeProfiles?.xaiFallbackModel || 'grok-4-3',
|
|
184
190
|
nimFallbackModel: config.runtimeProfiles?.nimFallbackModel || 'qwen/qwen3.5-122b-a10b',
|
|
185
191
|
xaiApiKey: config.runtimeProfiles?.xaiApiKey || '',
|
|
192
|
+
deepseekApiKey: config.runtimeProfiles?.deepseekApiKey || '',
|
|
186
193
|
nimApiKey: config.runtimeProfiles?.nimApiKey || '',
|
|
187
194
|
xaiBaseUrl: config.runtimeProfiles?.xaiBaseUrl || 'https://api.x.ai/v1/chat/completions',
|
|
195
|
+
deepseekBaseUrl: config.runtimeProfiles?.deepseekBaseUrl || 'https://api.deepseek.com/v1/chat/completions',
|
|
188
196
|
nimBaseUrl: config.runtimeProfiles?.nimBaseUrl || 'https://integrate.api.nvidia.com/v1/chat/completions',
|
|
197
|
+
localFallbackModel: config.runtimeProfiles?.localFallbackModel || 'mlx-community/Qwen2.5-7B-Instruct-4bit',
|
|
198
|
+
localFallbackBaseUrl:
|
|
199
|
+
config.runtimeProfiles?.localFallbackBaseUrl || 'http://aria-lane-gateway.aria.svc.cluster.local:8089/v1/chat/completions',
|
|
200
|
+
localFallbackApiKey: config.runtimeProfiles?.localFallbackApiKey || '',
|
|
189
201
|
},
|
|
190
202
|
});
|
|
191
203
|
}
|
package/src/connectors/shell.ts
CHANGED
|
@@ -76,21 +76,25 @@ if [ -f "$RUNTIME_ENV" ]; then
|
|
|
76
76
|
. "$RUNTIME_ENV"
|
|
77
77
|
set +a
|
|
78
78
|
fi
|
|
79
|
+
ARIA_SECRETS_SH="$HOME/.aria/secrets/aria-secrets.sh"
|
|
80
|
+
if [ -f "$ARIA_SECRETS_SH" ]; then
|
|
81
|
+
. "$ARIA_SECRETS_SH"
|
|
82
|
+
fi
|
|
79
83
|
export ARIA_RUNTIME_URL="\${ARIA_RUNTIME_URL:-http://127.0.0.1:4319}"
|
|
80
84
|
export OPENAI_BASE_URL="\${OPENAI_BASE_URL:-$ARIA_RUNTIME_URL/v1}"
|
|
81
|
-
export ANTHROPIC_BASE_URL="\${ANTHROPIC_BASE_URL:-$ARIA_RUNTIME_URL
|
|
82
|
-
if [ -z "\${
|
|
85
|
+
export ANTHROPIC_BASE_URL="\${ANTHROPIC_BASE_URL:-$ARIA_RUNTIME_URL}"
|
|
86
|
+
if [ -z "\${ARIA_HARNESS_TOKEN:-}" ]; then
|
|
83
87
|
if [ -f "$HOME/.aria/owner-token" ]; then
|
|
84
|
-
export
|
|
88
|
+
export ARIA_HARNESS_TOKEN="$(tr -d '\\n' < "$HOME/.aria/owner-token")"
|
|
85
89
|
elif [ -f "$HOME/.aria/license.json" ]; then
|
|
86
|
-
export
|
|
87
|
-
if [ -z "$
|
|
88
|
-
export
|
|
90
|
+
export ARIA_HARNESS_TOKEN="$(sed -n 's/.*"harnessToken"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' "$HOME/.aria/license.json" | head -n 1)"
|
|
91
|
+
if [ -z "$ARIA_HARNESS_TOKEN" ]; then
|
|
92
|
+
export ARIA_HARNESS_TOKEN="$(sed -n 's/.*"token"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' "$HOME/.aria/license.json" | head -n 1)"
|
|
89
93
|
fi
|
|
90
94
|
fi
|
|
91
95
|
fi
|
|
92
|
-
if [ -n "\${
|
|
93
|
-
export
|
|
96
|
+
if [ -n "\${ARIA_HARNESS_TOKEN:-}" ] && [ -z "\${ARIA_API_KEY:-}" ]; then
|
|
97
|
+
export ARIA_API_KEY="$ARIA_HARNESS_TOKEN"
|
|
94
98
|
fi
|
|
95
99
|
`;
|
|
96
100
|
}
|
package/src/harness-client.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { HarnessResponse, HarnessGateDecision } from './types.js';
|
|
2
|
+
import { resolveHarnessToken } from './auth.js';
|
|
3
3
|
import { pushCognitionLog } from './cognition-log.js';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
@@ -91,7 +91,9 @@ export class HarnessClient {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Resolve the bearer token
|
|
94
|
+
* Resolve the bearer token through the shared survival resolver.
|
|
95
|
+
* Explicit/env tokens are persisted per client scope so later sessions do not
|
|
96
|
+
* silently lose auth when the process environment changes.
|
|
95
97
|
* Cache the promise so we don't re-read the file on every call.
|
|
96
98
|
*/
|
|
97
99
|
private async getToken(): Promise<string | null> {
|
|
@@ -103,25 +105,9 @@ export class HarnessClient {
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
private async resolveToken(): Promise<string | null> {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (license?.harnessToken) {
|
|
110
|
-
this.token = license.harnessToken;
|
|
111
|
-
return this.token;
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
// file not found or parse error — fall through
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 2. Fallback to env var
|
|
118
|
-
const envToken = process.env.ARIA_HARNESS_TOKEN;
|
|
119
|
-
if (envToken) {
|
|
120
|
-
this.token = envToken;
|
|
121
|
-
return this.token;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return null;
|
|
108
|
+
const resolved = await resolveHarnessToken({ baseUrl: this.baseUrl });
|
|
109
|
+
this.token = resolved.token;
|
|
110
|
+
return this.token;
|
|
125
111
|
}
|
|
126
112
|
|
|
127
113
|
/**
|
package/src/model-context.ts
CHANGED
|
@@ -46,9 +46,14 @@ const MODEL_CONTEXT: Record<string, number> = {
|
|
|
46
46
|
// DeepSeek
|
|
47
47
|
'deepseek-v3': 64_000,
|
|
48
48
|
'deepseek-chat': 64_000,
|
|
49
|
+
'deepseek-v4-pro': 128_000,
|
|
49
50
|
'deepseek-r1': 128_000,
|
|
50
51
|
'deepseek-coder': 128_000,
|
|
51
52
|
|
|
53
|
+
// xAI
|
|
54
|
+
'grok-4-3': 256_000,
|
|
55
|
+
'grok-4.3': 256_000,
|
|
56
|
+
|
|
52
57
|
// Open / local
|
|
53
58
|
'qwen2.5:7b-instruct': 32_000,
|
|
54
59
|
'qwen3.5-122b-a10b': 128_000,
|
|
@@ -68,6 +73,7 @@ const PROVIDER_DEFAULT: Record<ProviderName, number> = {
|
|
|
68
73
|
google: 1_000_000,
|
|
69
74
|
deepseek: 64_000,
|
|
70
75
|
openrouter: 32_000, // wide range routed through; conservative chunks safer
|
|
76
|
+
xai: 256_000,
|
|
71
77
|
ollama: 32_000, // local models vary wildly; default low
|
|
72
78
|
};
|
|
73
79
|
|
package/src/providers/types.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface ChatResult {
|
|
|
23
23
|
runtimeProof?: RuntimeProofSnapshot;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export type ProviderName = 'openai' | 'anthropic' | 'google' | 'deepseek' | 'openrouter' | 'ollama';
|
|
26
|
+
export type ProviderName = 'openai' | 'anthropic' | 'google' | 'deepseek' | 'openrouter' | 'xai' | 'ollama';
|
|
27
27
|
|
|
28
28
|
export type ChatFn = (
|
|
29
29
|
messages: Message[],
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Message, ChatOptions, ChatResult } from './types.js';
|
|
2
|
+
|
|
3
|
+
function xaiChatCompletionsUrl(): string {
|
|
4
|
+
const base = process.env.XAI_API_BASE || 'https://api.x.ai/v1/chat/completions';
|
|
5
|
+
const trimmed = base.replace(/\/+$/, '');
|
|
6
|
+
return trimmed.endsWith('/chat/completions') ? trimmed : `${trimmed}/chat/completions`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function xaiApiModel(model: string): string {
|
|
10
|
+
return model === 'grok-4-3' ? 'grok-4.3' : model;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function chat(
|
|
14
|
+
messages: Message[],
|
|
15
|
+
apiKey: string,
|
|
16
|
+
model: string,
|
|
17
|
+
opts?: ChatOptions,
|
|
18
|
+
): Promise<ChatResult> {
|
|
19
|
+
const token = apiKey || process.env.XAI_API_KEY || process.env.GROK_API_KEY || process.env.ARIA_XAI_KEY || '';
|
|
20
|
+
if (!token) {
|
|
21
|
+
throw new Error('xAI API key missing. Configure XAI_API_KEY, GROK_API_KEY, ARIA_XAI_KEY, or ~/.aria/config.json.');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const resp = await fetch(xaiChatCompletionsUrl(), {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
Authorization: `Bearer ${token}`,
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
model: xaiApiModel(model || 'grok-4-3'),
|
|
32
|
+
messages,
|
|
33
|
+
max_tokens: opts?.maxTokens ?? 4096,
|
|
34
|
+
stream: false,
|
|
35
|
+
}),
|
|
36
|
+
signal: opts?.signal,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!resp.ok) {
|
|
40
|
+
const err = await resp.text().catch(() => resp.statusText);
|
|
41
|
+
throw new Error(`xAI error ${resp.status}: ${err}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const data = (await resp.json()) as {
|
|
45
|
+
choices: { message: { content: string } }[];
|
|
46
|
+
usage?: { prompt_tokens: number; completion_tokens: number };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
text: data.choices[0]?.message?.content ?? '',
|
|
51
|
+
usage: data.usage
|
|
52
|
+
? { promptTokens: data.usage.prompt_tokens, completionTokens: data.usage.completion_tokens }
|
|
53
|
+
: undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|