@aria_asi/cli 0.2.32 → 0.2.34
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/dist/aria-connector/src/connectors/codebase-awareness.d.ts +8 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.js +126 -71
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +98 -0
- 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 +91 -24
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +26 -8
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +60 -1
- package/dist/assets/hooks/aria-stop-gate.mjs +69 -3
- package/dist/assets/hooks/doctrine_trigger_map.json +43 -0
- package/dist/assets/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/dist/assets/opencode-plugins/harness-context/index.js +1 -1
- package/dist/assets/opencode-plugins/harness-gate/index.js +114 -10
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +39 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +234 -139
- package/dist/assets/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -0
- package/dist/runtime/codex-bridge.mjs +71 -8
- package/dist/runtime/discipline/CLAUDE.md +2 -2
- package/dist/runtime/discipline/doctrine_trigger_map.json +43 -0
- package/dist/runtime/discipline/skills/aria-harness/aria-harness-onboarding/SKILL.md +3 -3
- package/dist/runtime/doctrine_trigger_map.json +43 -0
- package/dist/runtime/harness-daemon.mjs +50 -2
- package/dist/runtime/hooks/aria-agent-handoff.mjs +247 -0
- package/dist/runtime/hooks/aria-agent-ledger-merge.mjs +164 -0
- package/dist/runtime/hooks/aria-architect-fallback.mjs +267 -0
- package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +761 -0
- package/dist/runtime/hooks/aria-discovery-record.mjs +101 -0
- package/dist/runtime/hooks/aria-harness-via-sdk.mjs +544 -0
- package/dist/runtime/hooks/aria-import-resolution-gate.mjs +330 -0
- package/dist/runtime/hooks/aria-outcome-record.mjs +84 -0
- package/dist/runtime/hooks/aria-pre-emit-dryrun.mjs +329 -0
- package/dist/runtime/hooks/aria-pre-text-gate.mjs +112 -0
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +2482 -0
- package/dist/runtime/hooks/aria-preprompt-consult.mjs +464 -0
- package/dist/runtime/hooks/aria-preturn-memory-gate.mjs +647 -0
- package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +429 -0
- package/dist/runtime/hooks/aria-stop-gate.mjs +1882 -0
- package/dist/runtime/hooks/aria-trigger-autolearn.mjs +229 -0
- package/dist/runtime/hooks/aria-userprompt-abandon-detect.mjs +192 -0
- package/dist/runtime/hooks/doctrine_trigger_map.json +577 -0
- package/dist/runtime/hooks/lib/canonical-lenses.mjs +65 -0
- package/dist/runtime/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/runtime/hooks/lib/gate-audit.mjs +43 -0
- package/dist/runtime/hooks/lib/gate-loop-state.mjs +50 -0
- package/dist/runtime/hooks/lib/hook-message-window.mjs +121 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/dist/runtime/hooks/test-aria-preturn-memory-gate.mjs +245 -0
- package/dist/runtime/hooks/test-tier-lens-labeling.mjs +367 -0
- package/dist/runtime/manifest.json +2 -2
- package/dist/runtime/sdk/BUNDLED.json +2 -2
- package/dist/runtime/sdk/index.d.ts +48 -0
- package/dist/runtime/sdk/index.js +140 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/sdk/runWithGovernance.d.ts +16 -0
- package/dist/runtime/sdk/runWithGovernance.js +54 -0
- package/dist/runtime/sdk/runWithGovernance.js.map +1 -0
- package/dist/runtime/service.mjs +339 -10
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +48 -0
- package/dist/sdk/index.js +140 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runWithGovernance.d.ts +16 -0
- package/dist/sdk/runWithGovernance.js +54 -0
- package/dist/sdk/runWithGovernance.js.map +1 -0
- package/hooks/aria-harness-via-sdk.mjs +26 -8
- package/hooks/aria-pre-tool-gate.mjs +60 -1
- package/hooks/aria-stop-gate.mjs +69 -3
- package/hooks/doctrine_trigger_map.json +43 -0
- package/hooks/lib/domain-output-quality.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +14 -0
- package/opencode-plugins/harness-context/index.js +1 -1
- package/opencode-plugins/harness-gate/index.js +114 -10
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +14 -0
- package/opencode-plugins/harness-outcome/index.js +39 -0
- package/opencode-plugins/harness-stop/index.js +234 -139
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +14 -0
- package/package.json +12 -5
- package/runtime-src/codex-bridge.mjs +71 -8
- package/runtime-src/harness-daemon.mjs +50 -2
- package/runtime-src/service.mjs +339 -10
- package/scripts/bundle-sdk.mjs +2 -0
- package/scripts/self-test-harness-gates.mjs +79 -0
- package/src/connectors/codebase-awareness.ts +141 -77
- package/src/connectors/codex.ts +98 -0
- package/src/setup-wizard.ts +105 -25
|
@@ -14,7 +14,10 @@ const ENV_PATH = path.join(ARIA_DIR, 'codebase-awareness.env');
|
|
|
14
14
|
const STATE_PATH = path.join(ARIA_DIR, 'codebase-awareness-state.json');
|
|
15
15
|
const INDEX_PATH = path.join(ARIA_DIR, 'codebase-awareness-index.json');
|
|
16
16
|
|
|
17
|
-
type AwarenessStatus = 'idle' | 'watching' | 'scanning' | 'error';
|
|
17
|
+
type AwarenessStatus = 'idle' | 'watching' | 'scanning' | 'degraded' | 'error';
|
|
18
|
+
const HEARTBEAT_INTERVAL_MS = Math.max(5_000, Number(process.env.ARIA_CODEBASE_AWARENESS_HEARTBEAT_MS || '15000'));
|
|
19
|
+
const REFRESH_INTERVAL_MS = Math.max(30_000, Number(process.env.ARIA_CODEBASE_AWARENESS_REFRESH_MS || '300000'));
|
|
20
|
+
const REPO_DISCOVERY_INTERVAL_MS = Math.max(30_000, Number(process.env.ARIA_CODEBASE_AWARENESS_RETRY_MS || '60000'));
|
|
18
21
|
|
|
19
22
|
interface RepoSnapshot {
|
|
20
23
|
path: string;
|
|
@@ -36,6 +39,13 @@ interface AwarenessState {
|
|
|
36
39
|
repoSnapshots: RepoSnapshot[];
|
|
37
40
|
lastError: string | null;
|
|
38
41
|
updatedAt: string;
|
|
42
|
+
daemon?: {
|
|
43
|
+
pid: number;
|
|
44
|
+
startedAt: string;
|
|
45
|
+
heartbeatAt: string;
|
|
46
|
+
refreshIntervalMs: number;
|
|
47
|
+
watcherModes: Record<string, string>;
|
|
48
|
+
};
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
function connectorPackageRoot(): string {
|
|
@@ -82,12 +92,17 @@ function readState(): AwarenessState {
|
|
|
82
92
|
repoSnapshots: Array.isArray(parsed.repoSnapshots) ? parsed.repoSnapshots as RepoSnapshot[] : [],
|
|
83
93
|
lastError: parsed.lastError || null,
|
|
84
94
|
updatedAt: parsed.updatedAt || new Date(0).toISOString(),
|
|
95
|
+
daemon: parsed.daemon,
|
|
85
96
|
};
|
|
86
97
|
} catch {
|
|
87
98
|
return defaultState();
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
function compactError(error: unknown): string {
|
|
103
|
+
return error instanceof Error ? error.message : String(error);
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
function writeState(update: Partial<AwarenessState>): AwarenessState {
|
|
92
107
|
const current = readState();
|
|
93
108
|
const next: AwarenessState = {
|
|
@@ -254,86 +269,135 @@ export async function startCodebaseAwarenessDaemon(options: {
|
|
|
254
269
|
repos?: string[];
|
|
255
270
|
fallbackRepoPath?: string;
|
|
256
271
|
} = {}): Promise<void> {
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
272
|
+
const startedAt = new Date().toISOString();
|
|
273
|
+
const handles = new Map<string, { stop: () => void; readonly mode: string }>();
|
|
274
|
+
const watcherModes: Record<string, string> = {};
|
|
275
|
+
let repos = resolveRepos(undefined, options.repos, options.fallbackRepoPath);
|
|
276
|
+
|
|
277
|
+
const writeDaemonState = (status: AwarenessStatus, update: Partial<AwarenessState> = {}): void => {
|
|
278
|
+
writeState({
|
|
279
|
+
status,
|
|
280
|
+
watchedRepos: repos,
|
|
281
|
+
...update,
|
|
282
|
+
daemon: {
|
|
283
|
+
pid: process.pid,
|
|
284
|
+
startedAt,
|
|
285
|
+
heartbeatAt: new Date().toISOString(),
|
|
286
|
+
refreshIntervalMs: REFRESH_INTERVAL_MS,
|
|
287
|
+
watcherModes,
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
};
|
|
262
291
|
|
|
263
|
-
|
|
264
|
-
|
|
292
|
+
const scanAll = async (reason: string): Promise<void> => {
|
|
293
|
+
repos = resolveRepos(undefined, options.repos, options.fallbackRepoPath);
|
|
294
|
+
if (!repos.length) {
|
|
295
|
+
writeDaemonState('degraded', { lastError: 'No git repositories configured for codebase awareness.' });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
265
298
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
299
|
+
writeDaemonState('scanning', { lastError: null });
|
|
300
|
+
const snapshots: RepoSnapshot[] = [];
|
|
301
|
+
const failures: string[] = [];
|
|
302
|
+
for (const repo of repos) {
|
|
303
|
+
try {
|
|
304
|
+
snapshots.push(await applyRepoScan(repo));
|
|
305
|
+
} catch (error) {
|
|
306
|
+
failures.push(`${repo}: ${compactError(error)}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const current = readState();
|
|
311
|
+
const repoSnapshots = [
|
|
312
|
+
...snapshots,
|
|
313
|
+
...current.repoSnapshots.filter((entry) => !snapshots.some((snapshot) => path.resolve(snapshot.path) === path.resolve(entry.path))),
|
|
314
|
+
];
|
|
315
|
+
writeDaemonState(failures.length ? 'degraded' : 'watching', {
|
|
316
|
+
repoSnapshots,
|
|
317
|
+
lastError: failures.length ? `${reason}: ${failures.join(' | ')}` : null,
|
|
318
|
+
});
|
|
319
|
+
writeIndex({
|
|
320
|
+
generatedAt: new Date().toISOString(),
|
|
321
|
+
reason,
|
|
322
|
+
watchedRepos: repos,
|
|
323
|
+
repoSnapshots,
|
|
324
|
+
schemaImages: loadConfig().schemaImages || {},
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const ensureWatchers = (): void => {
|
|
329
|
+
repos = resolveRepos(undefined, options.repos, options.fallbackRepoPath);
|
|
330
|
+
for (const [repo, handle] of handles.entries()) {
|
|
331
|
+
if (!repos.includes(repo)) {
|
|
332
|
+
handle.stop();
|
|
333
|
+
handles.delete(repo);
|
|
334
|
+
delete watcherModes[repo];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
for (const repo of repos) {
|
|
338
|
+
if (handles.has(repo)) continue;
|
|
339
|
+
try {
|
|
340
|
+
const handle = watchCodebase(
|
|
341
|
+
repo,
|
|
342
|
+
(image) => {
|
|
343
|
+
const schemaText = schemaImageToText(image);
|
|
344
|
+
const scanHash = hashSchema(schemaText);
|
|
345
|
+
const lastScan = new Date().toISOString();
|
|
346
|
+
const config = loadConfig();
|
|
347
|
+
const repositories = [
|
|
348
|
+
...(config.repositories || []).filter((entry) => path.resolve(entry.path) !== repo),
|
|
349
|
+
{ path: repo, name: image.projectName, scanHash, lastScan },
|
|
350
|
+
];
|
|
351
|
+
const nextConfig = {
|
|
352
|
+
...config,
|
|
353
|
+
repositories,
|
|
354
|
+
schemaImages: { ...(config.schemaImages || {}), [image.projectName]: schemaText },
|
|
355
|
+
};
|
|
356
|
+
saveConfig(nextConfig);
|
|
357
|
+
|
|
358
|
+
const current = readState();
|
|
359
|
+
const snapshot: RepoSnapshot = {
|
|
360
|
+
path: repo,
|
|
361
|
+
name: image.projectName,
|
|
362
|
+
scanHash,
|
|
363
|
+
lastScan,
|
|
364
|
+
fileCount: image.fileCount,
|
|
365
|
+
language: image.language,
|
|
366
|
+
framework: image.framework || null,
|
|
367
|
+
packageManager: image.packageManager || null,
|
|
368
|
+
database: image.database || null,
|
|
369
|
+
orm: image.orm || null,
|
|
370
|
+
architecture: architectureSummary(image),
|
|
371
|
+
};
|
|
372
|
+
const repoSnapshots = [snapshot, ...current.repoSnapshots.filter((entry) => path.resolve(entry.path) !== repo)];
|
|
373
|
+
writeDaemonState('watching', { repoSnapshots, lastError: null });
|
|
374
|
+
writeIndex({ generatedAt: new Date().toISOString(), reason: 'watch-change', watchedRepos: repos, repoSnapshots, schemaImages: nextConfig.schemaImages || {} });
|
|
281
375
|
},
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
376
|
+
{
|
|
377
|
+
debounceMs: 800,
|
|
378
|
+
pollIntervalMs: 4000,
|
|
379
|
+
onReady: (mode) => {
|
|
380
|
+
watcherModes[repo] = mode;
|
|
381
|
+
writeDaemonState('watching', { lastError: null });
|
|
382
|
+
},
|
|
383
|
+
onError: ({ phase, error }) => {
|
|
384
|
+
writeDaemonState('degraded', { lastError: `${repo} ${phase}: ${error.message}` });
|
|
385
|
+
},
|
|
289
386
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
orm: image.orm || null,
|
|
305
|
-
architecture: architectureSummary(image),
|
|
306
|
-
};
|
|
307
|
-
const repoSnapshots = [
|
|
308
|
-
snapshot,
|
|
309
|
-
...current.repoSnapshots.filter((entry) => path.resolve(entry.path) !== repo),
|
|
310
|
-
];
|
|
311
|
-
writeState({
|
|
312
|
-
status: 'watching',
|
|
313
|
-
watchedRepos: repos,
|
|
314
|
-
repoSnapshots,
|
|
315
|
-
lastError: null,
|
|
316
|
-
});
|
|
317
|
-
writeIndex({
|
|
318
|
-
generatedAt: new Date().toISOString(),
|
|
319
|
-
watchedRepos: repos,
|
|
320
|
-
repoSnapshots,
|
|
321
|
-
schemaImages: nextConfig.schemaImages || {},
|
|
322
|
-
});
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
debounceMs: 800,
|
|
326
|
-
pollIntervalMs: 4000,
|
|
327
|
-
onError: ({ error }) => {
|
|
328
|
-
writeState({
|
|
329
|
-
status: 'error',
|
|
330
|
-
watchedRepos: repos,
|
|
331
|
-
lastError: error.message,
|
|
332
|
-
});
|
|
333
|
-
},
|
|
334
|
-
},
|
|
335
|
-
);
|
|
336
|
-
}
|
|
387
|
+
);
|
|
388
|
+
handles.set(repo, handle);
|
|
389
|
+
watcherModes[repo] = handle.mode;
|
|
390
|
+
} catch (error) {
|
|
391
|
+
writeDaemonState('degraded', { lastError: `${repo} watcher init: ${compactError(error)}` });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
await scanAll('daemon-start');
|
|
397
|
+
ensureWatchers();
|
|
398
|
+
setInterval(() => writeDaemonState(repos.length ? 'watching' : 'degraded'), HEARTBEAT_INTERVAL_MS).unref();
|
|
399
|
+
setInterval(() => { ensureWatchers(); void scanAll('periodic-refresh'); }, REFRESH_INTERVAL_MS).unref();
|
|
400
|
+
setInterval(() => { ensureWatchers(); }, REPO_DISCOVERY_INTERVAL_MS).unref();
|
|
337
401
|
|
|
338
402
|
await new Promise(() => {});
|
|
339
403
|
}
|
package/src/connectors/codex.ts
CHANGED
|
@@ -90,6 +90,8 @@ function tomlString(value: string): string {
|
|
|
90
90
|
|
|
91
91
|
function buildCodexHookRuntimeClient(): string {
|
|
92
92
|
return `import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
93
|
+
import { spawnSync } from 'node:child_process';
|
|
94
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
93
95
|
import { homedir } from 'node:os';
|
|
94
96
|
import path from 'node:path';
|
|
95
97
|
import { HTTPHarnessClient } from '@aria_asi/harness-http-client';
|
|
@@ -97,6 +99,7 @@ import { HTTPHarnessClient } from '@aria_asi/harness-http-client';
|
|
|
97
99
|
const HOME = homedir();
|
|
98
100
|
const DEFAULT_RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\\/+$/, '');
|
|
99
101
|
const TURN_STATE_DIR = path.join(HOME, '.codex', 'tmp', 'aria-hook-turn-state');
|
|
102
|
+
const GOVERNANCE_GATE_PATH = path.join(HOME, '.aria', 'bin', 'aria-governance-gate');
|
|
100
103
|
|
|
101
104
|
function readToken() {
|
|
102
105
|
const envToken = process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN || process.env.OPENAI_API_KEY;
|
|
@@ -154,6 +157,28 @@ export function inferSessionId(event) {
|
|
|
154
157
|
return \`codex:\${threadId}:\${turnId}\`;
|
|
155
158
|
}
|
|
156
159
|
|
|
160
|
+
export function ensureTraceId(state = {}) {
|
|
161
|
+
return typeof state.traceId === 'string' && state.traceId ? state.traceId : \`trace_\${randomUUID()}\`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function stableEvidenceString(value) {
|
|
165
|
+
if (typeof value === 'string') return value;
|
|
166
|
+
try { return JSON.stringify(value); } catch { return String(value); }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function makeEvidenceRef(kind, value, metadata = {}) {
|
|
170
|
+
const raw = stableEvidenceString(value);
|
|
171
|
+
const sha256 = createHash('sha256').update(raw).digest('hex');
|
|
172
|
+
return {
|
|
173
|
+
evidenceId: \`ev_\${sha256.slice(0, 16)}\`,
|
|
174
|
+
kind,
|
|
175
|
+
at: new Date().toISOString(),
|
|
176
|
+
sha256,
|
|
177
|
+
preview: raw.slice(0, 500),
|
|
178
|
+
metadata,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
157
182
|
export function inferUserId(event) {
|
|
158
183
|
return (
|
|
159
184
|
extractFirst(event, ['user_id', 'userId']) ||
|
|
@@ -300,6 +325,22 @@ export function emitJson(payload, code = 0) {
|
|
|
300
325
|
process.stdout.write(\`\${JSON.stringify(payload)}\\n\`);
|
|
301
326
|
process.exit(code);
|
|
302
327
|
}
|
|
328
|
+
|
|
329
|
+
export function runGovernanceGate(payload = {}) {
|
|
330
|
+
if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
|
|
331
|
+
const child = spawnSync(GOVERNANCE_GATE_PATH, {
|
|
332
|
+
input: \`\${JSON.stringify(payload)}\\n\`,
|
|
333
|
+
encoding: 'utf8',
|
|
334
|
+
maxBuffer: 1024 * 1024,
|
|
335
|
+
});
|
|
336
|
+
const stdout = String(child.stdout || '').trim();
|
|
337
|
+
let result = null;
|
|
338
|
+
try { result = stdout ? JSON.parse(stdout) : null; } catch {}
|
|
339
|
+
if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
|
|
340
|
+
throw new Error(stdout || child.stderr || 'aria-governance-gate blocked this Codex hook.');
|
|
341
|
+
}
|
|
342
|
+
return result;
|
|
343
|
+
}
|
|
303
344
|
`;
|
|
304
345
|
}
|
|
305
346
|
|
|
@@ -309,10 +350,14 @@ import {
|
|
|
309
350
|
getHarnessClient,
|
|
310
351
|
inferSessionId,
|
|
311
352
|
inferUserId,
|
|
353
|
+
ensureTraceId,
|
|
312
354
|
extractUserText,
|
|
355
|
+
makeEvidenceRef,
|
|
313
356
|
readEventFromStdin,
|
|
314
357
|
runtimePost,
|
|
358
|
+
loadTurnState,
|
|
315
359
|
saveTurnState,
|
|
360
|
+
runGovernanceGate,
|
|
316
361
|
emitJson,
|
|
317
362
|
} from './lib/runtime-client.mjs';
|
|
318
363
|
|
|
@@ -321,6 +366,8 @@ const client = getHarnessClient();
|
|
|
321
366
|
const userText = extractUserText(event);
|
|
322
367
|
const sessionId = inferSessionId(event);
|
|
323
368
|
const userId = inferUserId(event);
|
|
369
|
+
const priorState = loadTurnState(sessionId);
|
|
370
|
+
const traceId = ensureTraceId(priorState);
|
|
324
371
|
|
|
325
372
|
try {
|
|
326
373
|
const packet = await client.getHarnessPacket({
|
|
@@ -328,6 +375,14 @@ try {
|
|
|
328
375
|
platform: 'codex',
|
|
329
376
|
message: userText || 'codex turn start',
|
|
330
377
|
});
|
|
378
|
+
const packetRef = makeEvidenceRef('harness_packet', packet, { sessionId, platform: 'codex' });
|
|
379
|
+
runGovernanceGate({
|
|
380
|
+
sessionId,
|
|
381
|
+
sourceRuntime: 'codex',
|
|
382
|
+
surface: 'codex-userprompt-submit',
|
|
383
|
+
text: userText.slice(0, 8000),
|
|
384
|
+
evidence: packetRef,
|
|
385
|
+
});
|
|
331
386
|
const result = await runtimePost('/mizan/pre', {
|
|
332
387
|
sessionId,
|
|
333
388
|
packet,
|
|
@@ -341,17 +396,21 @@ try {
|
|
|
341
396
|
},
|
|
342
397
|
context: {
|
|
343
398
|
sessionId,
|
|
399
|
+
traceId,
|
|
344
400
|
surface: 'codex-hooks',
|
|
345
401
|
platform: 'codex',
|
|
346
402
|
userText,
|
|
347
403
|
userId,
|
|
404
|
+
evidenceRefs: [packetRef],
|
|
348
405
|
},
|
|
349
406
|
});
|
|
350
407
|
saveTurnState(sessionId, {
|
|
408
|
+
traceId,
|
|
351
409
|
userId,
|
|
352
410
|
userText,
|
|
353
411
|
preReceiptId: result?.receipt?.receiptId || null,
|
|
354
412
|
packetTimestamp: packet?.timestamp || null,
|
|
413
|
+
packetRef,
|
|
355
414
|
lastEvent: 'UserPromptSubmit',
|
|
356
415
|
});
|
|
357
416
|
process.exit(0);
|
|
@@ -373,7 +432,9 @@ import {
|
|
|
373
432
|
summarizeTarget,
|
|
374
433
|
readEventFromStdin,
|
|
375
434
|
loadTurnState,
|
|
435
|
+
makeEvidenceRef,
|
|
376
436
|
saveTurnState,
|
|
437
|
+
runGovernanceGate,
|
|
377
438
|
emitJson,
|
|
378
439
|
} from './lib/runtime-client.mjs';
|
|
379
440
|
|
|
@@ -399,12 +460,24 @@ try {
|
|
|
399
460
|
});
|
|
400
461
|
}
|
|
401
462
|
const toolName = String(event?.tool_name || event?.toolName || '').trim() || null;
|
|
463
|
+
runGovernanceGate({
|
|
464
|
+
sessionId,
|
|
465
|
+
sourceRuntime: 'codex',
|
|
466
|
+
surface: 'codex-pre-tool-use',
|
|
467
|
+
text: JSON.stringify(event).slice(0, 8000),
|
|
468
|
+
action,
|
|
469
|
+
toolName,
|
|
470
|
+
isDeploy: action === 'deploy',
|
|
471
|
+
isMutation: action === 'write' || action === 'delete',
|
|
472
|
+
evidence: makeEvidenceRef('codex_tool_request', { action, toolName, target }, { sessionId }),
|
|
473
|
+
});
|
|
402
474
|
const tools = Array.isArray(state?.tools) ? state.tools.slice(-24) : [];
|
|
403
475
|
tools.push({
|
|
404
476
|
at: new Date().toISOString(),
|
|
405
477
|
action,
|
|
406
478
|
toolName,
|
|
407
479
|
target,
|
|
480
|
+
evidenceRef: makeEvidenceRef('tool_request', { action, toolName, target }, { sessionId }),
|
|
408
481
|
});
|
|
409
482
|
saveTurnState(sessionId, {
|
|
410
483
|
tools,
|
|
@@ -426,6 +499,7 @@ import {
|
|
|
426
499
|
inferSessionId,
|
|
427
500
|
readEventFromStdin,
|
|
428
501
|
loadTurnState,
|
|
502
|
+
makeEvidenceRef,
|
|
429
503
|
saveTurnState,
|
|
430
504
|
} from './lib/runtime-client.mjs';
|
|
431
505
|
|
|
@@ -435,11 +509,16 @@ const state = loadTurnState(sessionId);
|
|
|
435
509
|
|
|
436
510
|
try {
|
|
437
511
|
const toolResponse = JSON.stringify(event?.tool_response ?? event?.toolResponse ?? null).slice(0, 4000);
|
|
512
|
+
const evidenceRef = makeEvidenceRef('tool_response', event?.tool_response ?? event?.toolResponse ?? null, {
|
|
513
|
+
sessionId,
|
|
514
|
+
toolName: event?.tool_name || event?.toolName || null,
|
|
515
|
+
});
|
|
438
516
|
const toolOutputs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.slice(-24) : [];
|
|
439
517
|
toolOutputs.push({
|
|
440
518
|
at: new Date().toISOString(),
|
|
441
519
|
toolName: event?.tool_name || event?.toolName || null,
|
|
442
520
|
toolResponse,
|
|
521
|
+
evidenceRef,
|
|
443
522
|
});
|
|
444
523
|
saveTurnState(sessionId, {
|
|
445
524
|
toolOutputs,
|
|
@@ -461,8 +540,10 @@ import {
|
|
|
461
540
|
readEventFromStdin,
|
|
462
541
|
runtimePost,
|
|
463
542
|
loadTurnState,
|
|
543
|
+
makeEvidenceRef,
|
|
464
544
|
clearTurnState,
|
|
465
545
|
formatValidationFailure,
|
|
546
|
+
runGovernanceGate,
|
|
466
547
|
emitJson,
|
|
467
548
|
} from './lib/runtime-client.mjs';
|
|
468
549
|
|
|
@@ -471,11 +552,21 @@ const client = getHarnessClient();
|
|
|
471
552
|
const sessionId = inferSessionId(event);
|
|
472
553
|
const state = loadTurnState(sessionId);
|
|
473
554
|
const text = extractAssistantText(event);
|
|
555
|
+
const outputRef = makeEvidenceRef('assistant_output', text, { sessionId, traceId: state?.traceId || null });
|
|
556
|
+
const toolRefs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.map((entry) => entry.evidenceRef).filter(Boolean) : [];
|
|
474
557
|
|
|
475
558
|
try {
|
|
476
559
|
if (!text) {
|
|
477
560
|
emitJson({ continue: true });
|
|
478
561
|
}
|
|
562
|
+
runGovernanceGate({
|
|
563
|
+
sessionId,
|
|
564
|
+
sourceRuntime: 'codex',
|
|
565
|
+
surface: 'codex-stop',
|
|
566
|
+
text: text.slice(0, 8000),
|
|
567
|
+
isOutputCloseout: true,
|
|
568
|
+
evidence: outputRef,
|
|
569
|
+
});
|
|
479
570
|
const validation = await runtimePost('/validate-output', {
|
|
480
571
|
text,
|
|
481
572
|
sessionId,
|
|
@@ -505,12 +596,16 @@ try {
|
|
|
505
596
|
layer3_pass: validation?.layer3?.pass !== false,
|
|
506
597
|
surface: 'codex-hooks',
|
|
507
598
|
tool_count: Array.isArray(state?.tools) ? state.tools.length : 0,
|
|
599
|
+
trace_id: state?.traceId || null,
|
|
600
|
+
output_ref: outputRef,
|
|
601
|
+
tool_refs: toolRefs,
|
|
508
602
|
},
|
|
509
603
|
context: {
|
|
510
604
|
sessionId,
|
|
511
605
|
surface: 'codex-hooks',
|
|
512
606
|
platform: 'codex',
|
|
513
607
|
userText: state?.userText || null,
|
|
608
|
+
traceId: state?.traceId || null,
|
|
514
609
|
},
|
|
515
610
|
parentReceiptId: state?.preReceiptId || null,
|
|
516
611
|
});
|
|
@@ -527,6 +622,9 @@ try {
|
|
|
527
622
|
metadata: {
|
|
528
623
|
post_receipt_id: post?.receipt?.receiptId || null,
|
|
529
624
|
pre_receipt_id: state?.preReceiptId || null,
|
|
625
|
+
trace_id: state?.traceId || null,
|
|
626
|
+
output_ref: outputRef,
|
|
627
|
+
tool_refs: toolRefs,
|
|
530
628
|
tool_count: Array.isArray(state?.tools) ? state.tools.length : 0,
|
|
531
629
|
validation_severity: validation?.validation?.severity || 'pass',
|
|
532
630
|
layer3_pass: validation?.layer3?.pass !== false,
|
package/src/setup-wizard.ts
CHANGED
|
@@ -33,6 +33,22 @@ const HARNESS_URL =
|
|
|
33
33
|
const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
|
|
34
34
|
const ARIA_DIR = join(homedir(), '.aria');
|
|
35
35
|
const LICENSE_PATH = join(ARIA_DIR, 'license.json');
|
|
36
|
+
const ONBOARDING_FALLBACK_URLS = [
|
|
37
|
+
process.env.ARIA_ONBOARDING_URL || '',
|
|
38
|
+
HARNESS_URL,
|
|
39
|
+
process.env.ARIA_SOUL_URL || '',
|
|
40
|
+
process.env.ARIAS_SOUL_URL || '',
|
|
41
|
+
process.env.ARIA_SOUL_BASE_URL || '',
|
|
42
|
+
'https://api.ariasos.com',
|
|
43
|
+
'https://arias-soul-6zp3gtk2ca-uc.a.run.app',
|
|
44
|
+
'https://harness.ariasos.com',
|
|
45
|
+
]
|
|
46
|
+
.flatMap((entry) => String(entry || '').split(','))
|
|
47
|
+
.map((entry) => entry.trim().replace(/\/+$/, ''))
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.filter((entry, index, list) => list.indexOf(entry) === index);
|
|
50
|
+
|
|
51
|
+
let activeOnboardingBaseUrl = ONBOARDING_FALLBACK_URLS[0] || HARNESS_URL.replace(/\/+$/, '');
|
|
36
52
|
|
|
37
53
|
type ConfigWrite =
|
|
38
54
|
| { kind: 'persona_update'; updates: Record<string, unknown> }
|
|
@@ -57,7 +73,7 @@ interface DepthOption {
|
|
|
57
73
|
interface ConverseResponse {
|
|
58
74
|
ok: boolean;
|
|
59
75
|
sessionId: string;
|
|
60
|
-
topic: 'identity' | 'codebase' | 'persona' | 'done';
|
|
76
|
+
topic: 'identity' | 'codebase' | 'persona' | 'workforce' | 'harness_setup' | 'done';
|
|
61
77
|
ariaPrompt: string;
|
|
62
78
|
depthOptions: DepthOption[];
|
|
63
79
|
freeTextAllowed: boolean;
|
|
@@ -69,17 +85,32 @@ interface ConverseResponse {
|
|
|
69
85
|
|
|
70
86
|
export async function runSetupWizard(): Promise<void> {
|
|
71
87
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
88
|
+
let readlineClosed = false;
|
|
89
|
+
rl.on('close', () => { readlineClosed = true; });
|
|
72
90
|
const ask = (q: string): Promise<string> =>
|
|
73
|
-
new Promise((resolve) =>
|
|
91
|
+
new Promise((resolve) => {
|
|
92
|
+
if (readlineClosed) {
|
|
93
|
+
resolve('__ARIA_ONBOARDING_EOF__');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
rl.question(q, (a) => resolve(a));
|
|
97
|
+
});
|
|
74
98
|
|
|
75
99
|
const sessionId = `onboard_${Date.now()}_${randomBytes(4).toString('hex')}`;
|
|
76
100
|
let userMessage: string | undefined;
|
|
77
101
|
let action: 'start' | 'answer' = 'start';
|
|
102
|
+
let turnCount = 0;
|
|
78
103
|
|
|
79
104
|
console.log('\n💬 Aria: starting onboarding…\n');
|
|
80
105
|
|
|
81
106
|
try {
|
|
82
107
|
while (true) {
|
|
108
|
+
turnCount += 1;
|
|
109
|
+
if (turnCount > 40) {
|
|
110
|
+
console.error('\n❌ Onboarding stopped after too many turns. Please run `aria` again to resume.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
83
114
|
const resp = await callConverse({ sessionId, action, userMessage });
|
|
84
115
|
if (!resp.ok) {
|
|
85
116
|
console.error(`\n❌ Onboarding error: ${resp.error || 'unknown'}`);
|
|
@@ -100,6 +131,10 @@ export async function runSetupWizard(): Promise<void> {
|
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
userMessage = (await ask('> ')).trim();
|
|
134
|
+
if (userMessage === '__ARIA_ONBOARDING_EOF__') {
|
|
135
|
+
console.error('\n❌ Onboarding input ended before setup completed. Run `aria` again to resume.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
103
138
|
action = 'answer';
|
|
104
139
|
if (!userMessage) userMessage = resp.depthOptions[0]?.signal ?? 'next';
|
|
105
140
|
}
|
|
@@ -117,18 +152,8 @@ async function callConverse(body: {
|
|
|
117
152
|
action: 'start' | 'answer';
|
|
118
153
|
userMessage?: string;
|
|
119
154
|
}): Promise<ConverseResponse> {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
method: 'POST',
|
|
123
|
-
headers: {
|
|
124
|
-
'Content-Type': 'application/json',
|
|
125
|
-
...(HARNESS_TOKEN ? { Authorization: `Bearer ${HARNESS_TOKEN}` } : {}),
|
|
126
|
-
},
|
|
127
|
-
body: JSON.stringify(body),
|
|
128
|
-
});
|
|
129
|
-
return (await res.json()) as ConverseResponse;
|
|
130
|
-
} catch (err) {
|
|
131
|
-
return {
|
|
155
|
+
return requestOnboardingJson<ConverseResponse>('/api/onboarding/converse', body, {
|
|
156
|
+
fallback: {
|
|
132
157
|
ok: false,
|
|
133
158
|
sessionId: body.sessionId,
|
|
134
159
|
topic: 'identity',
|
|
@@ -137,9 +162,69 @@ async function callConverse(body: {
|
|
|
137
162
|
freeTextAllowed: false,
|
|
138
163
|
isComplete: false,
|
|
139
164
|
progressPct: 0,
|
|
140
|
-
|
|
141
|
-
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function requestOnboardingJson<T extends { ok?: boolean; error?: string }>(
|
|
170
|
+
pathname: string,
|
|
171
|
+
body: Record<string, unknown>,
|
|
172
|
+
options: { fallback: T },
|
|
173
|
+
): Promise<T> {
|
|
174
|
+
const failures: string[] = [];
|
|
175
|
+
const baseUrls = [
|
|
176
|
+
activeOnboardingBaseUrl,
|
|
177
|
+
...ONBOARDING_FALLBACK_URLS,
|
|
178
|
+
].filter((entry, index, list) => entry && list.indexOf(entry) === index);
|
|
179
|
+
|
|
180
|
+
for (const baseUrl of baseUrls) {
|
|
181
|
+
try {
|
|
182
|
+
const res = await fetch(`${baseUrl}${pathname}`, {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: {
|
|
185
|
+
'Content-Type': 'application/json',
|
|
186
|
+
Accept: 'application/json',
|
|
187
|
+
...(HARNESS_TOKEN ? { Authorization: `Bearer ${HARNESS_TOKEN}` } : {}),
|
|
188
|
+
},
|
|
189
|
+
body: JSON.stringify(body),
|
|
190
|
+
});
|
|
191
|
+
const text = await res.text();
|
|
192
|
+
const contentType = res.headers.get('content-type') || '';
|
|
193
|
+
const looksJson = /^\s*[\[{]/.test(text);
|
|
194
|
+
|
|
195
|
+
if (!contentType.includes('application/json') && !looksJson) {
|
|
196
|
+
failures.push(`${baseUrl}${pathname} returned HTTP ${res.status} ${contentType || 'without content-type'}`);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let data: T;
|
|
201
|
+
try {
|
|
202
|
+
data = JSON.parse(text || '{}') as T;
|
|
203
|
+
} catch (err) {
|
|
204
|
+
failures.push(`${baseUrl}${pathname} returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!res.ok) {
|
|
209
|
+
failures.push(`${baseUrl}${pathname} returned HTTP ${res.status}: ${data.error || 'no error message'}`);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
activeOnboardingBaseUrl = baseUrl;
|
|
214
|
+
return data;
|
|
215
|
+
} catch (err) {
|
|
216
|
+
failures.push(`${baseUrl}${pathname} transport failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
217
|
+
}
|
|
142
218
|
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
...options.fallback,
|
|
222
|
+
ok: false,
|
|
223
|
+
error:
|
|
224
|
+
'Onboarding API is unavailable or not returning JSON. ' +
|
|
225
|
+
failures.slice(0, 4).join(' | ') +
|
|
226
|
+
(failures.length > 4 ? ` | ${failures.length - 4} more endpoint(s) failed` : ''),
|
|
227
|
+
};
|
|
143
228
|
}
|
|
144
229
|
|
|
145
230
|
async function maybeOfferGitHubConnect(ask: (q: string) => Promise<string>): Promise<void> {
|
|
@@ -207,19 +292,14 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
|
|
|
207
292
|
const provider = claims.provider || '';
|
|
208
293
|
const apiKey = claims.apiKey || '';
|
|
209
294
|
try {
|
|
210
|
-
const
|
|
211
|
-
method: 'POST',
|
|
212
|
-
headers: { 'Content-Type': 'application/json' },
|
|
213
|
-
body: JSON.stringify({ email, provider, llm_key: apiKey }),
|
|
214
|
-
});
|
|
215
|
-
const data = await resp.json() as {
|
|
295
|
+
const data = await requestOnboardingJson<{
|
|
216
296
|
ok?: boolean;
|
|
217
297
|
license?: { token: string; jti: string; tier: string; expires_at: string };
|
|
218
298
|
claims?: Record<string, unknown>;
|
|
219
299
|
error?: string;
|
|
220
|
-
};
|
|
221
|
-
if (!
|
|
222
|
-
console.warn(` ⚠ I couldn't issue your license: ${data.error ||
|
|
300
|
+
}>('/api/onboarding/self-issue', { email, provider, llm_key: apiKey }, { fallback: { ok: false } });
|
|
301
|
+
if (!data.ok || !data.license) {
|
|
302
|
+
console.warn(` ⚠ I couldn't issue your license: ${data.error || 'license endpoint did not return a license'}`);
|
|
223
303
|
continue;
|
|
224
304
|
}
|
|
225
305
|
if (!existsSync(ARIA_DIR)) mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
|