@aria_asi/cli 0.2.32 → 0.2.33
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 +51 -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 +10 -5
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +19 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +27 -2
- package/dist/assets/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +67 -3
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +39 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +61 -1
- 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 +1 -0
- package/dist/runtime/codex-bridge.mjs +71 -8
- package/dist/runtime/harness-daemon.mjs +50 -2
- package/dist/runtime/manifest.json +1 -1
- package/dist/runtime/sdk/BUNDLED.json +1 -1
- package/dist/runtime/sdk/index.d.ts +9 -0
- package/dist/runtime/sdk/index.js +23 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +339 -10
- package/dist/sdk/BUNDLED.json +1 -1
- package/dist/sdk/index.d.ts +9 -0
- package/dist/sdk/index.js +23 -1
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-harness-via-sdk.mjs +10 -5
- package/hooks/aria-pre-tool-gate.mjs +19 -0
- package/hooks/aria-stop-gate.mjs +27 -2
- package/hooks/lib/domain-output-quality.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/opencode-plugins/harness-gate/index.js +67 -3
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/opencode-plugins/harness-outcome/index.js +39 -0
- package/opencode-plugins/harness-stop/index.js +61 -1
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -0
- package/package.json +1 -1
- package/runtime-src/codex-bridge.mjs +71 -8
- package/runtime-src/harness-daemon.mjs +50 -2
- package/runtime-src/service.mjs +339 -10
- package/src/connectors/codebase-awareness.ts +141 -77
- package/src/connectors/codex.ts +51 -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,7 @@ 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 { createHash, randomUUID } from 'node:crypto';
|
|
93
94
|
import { homedir } from 'node:os';
|
|
94
95
|
import path from 'node:path';
|
|
95
96
|
import { HTTPHarnessClient } from '@aria_asi/harness-http-client';
|
|
@@ -154,6 +155,28 @@ export function inferSessionId(event) {
|
|
|
154
155
|
return \`codex:\${threadId}:\${turnId}\`;
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
export function ensureTraceId(state = {}) {
|
|
159
|
+
return typeof state.traceId === 'string' && state.traceId ? state.traceId : \`trace_\${randomUUID()}\`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function stableEvidenceString(value) {
|
|
163
|
+
if (typeof value === 'string') return value;
|
|
164
|
+
try { return JSON.stringify(value); } catch { return String(value); }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function makeEvidenceRef(kind, value, metadata = {}) {
|
|
168
|
+
const raw = stableEvidenceString(value);
|
|
169
|
+
const sha256 = createHash('sha256').update(raw).digest('hex');
|
|
170
|
+
return {
|
|
171
|
+
evidenceId: \`ev_\${sha256.slice(0, 16)}\`,
|
|
172
|
+
kind,
|
|
173
|
+
at: new Date().toISOString(),
|
|
174
|
+
sha256,
|
|
175
|
+
preview: raw.slice(0, 500),
|
|
176
|
+
metadata,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
157
180
|
export function inferUserId(event) {
|
|
158
181
|
return (
|
|
159
182
|
extractFirst(event, ['user_id', 'userId']) ||
|
|
@@ -309,9 +332,12 @@ import {
|
|
|
309
332
|
getHarnessClient,
|
|
310
333
|
inferSessionId,
|
|
311
334
|
inferUserId,
|
|
335
|
+
ensureTraceId,
|
|
312
336
|
extractUserText,
|
|
337
|
+
makeEvidenceRef,
|
|
313
338
|
readEventFromStdin,
|
|
314
339
|
runtimePost,
|
|
340
|
+
loadTurnState,
|
|
315
341
|
saveTurnState,
|
|
316
342
|
emitJson,
|
|
317
343
|
} from './lib/runtime-client.mjs';
|
|
@@ -321,6 +347,8 @@ const client = getHarnessClient();
|
|
|
321
347
|
const userText = extractUserText(event);
|
|
322
348
|
const sessionId = inferSessionId(event);
|
|
323
349
|
const userId = inferUserId(event);
|
|
350
|
+
const priorState = loadTurnState(sessionId);
|
|
351
|
+
const traceId = ensureTraceId(priorState);
|
|
324
352
|
|
|
325
353
|
try {
|
|
326
354
|
const packet = await client.getHarnessPacket({
|
|
@@ -328,6 +356,7 @@ try {
|
|
|
328
356
|
platform: 'codex',
|
|
329
357
|
message: userText || 'codex turn start',
|
|
330
358
|
});
|
|
359
|
+
const packetRef = makeEvidenceRef('harness_packet', packet, { sessionId, platform: 'codex' });
|
|
331
360
|
const result = await runtimePost('/mizan/pre', {
|
|
332
361
|
sessionId,
|
|
333
362
|
packet,
|
|
@@ -341,17 +370,21 @@ try {
|
|
|
341
370
|
},
|
|
342
371
|
context: {
|
|
343
372
|
sessionId,
|
|
373
|
+
traceId,
|
|
344
374
|
surface: 'codex-hooks',
|
|
345
375
|
platform: 'codex',
|
|
346
376
|
userText,
|
|
347
377
|
userId,
|
|
378
|
+
evidenceRefs: [packetRef],
|
|
348
379
|
},
|
|
349
380
|
});
|
|
350
381
|
saveTurnState(sessionId, {
|
|
382
|
+
traceId,
|
|
351
383
|
userId,
|
|
352
384
|
userText,
|
|
353
385
|
preReceiptId: result?.receipt?.receiptId || null,
|
|
354
386
|
packetTimestamp: packet?.timestamp || null,
|
|
387
|
+
packetRef,
|
|
355
388
|
lastEvent: 'UserPromptSubmit',
|
|
356
389
|
});
|
|
357
390
|
process.exit(0);
|
|
@@ -373,6 +406,7 @@ import {
|
|
|
373
406
|
summarizeTarget,
|
|
374
407
|
readEventFromStdin,
|
|
375
408
|
loadTurnState,
|
|
409
|
+
makeEvidenceRef,
|
|
376
410
|
saveTurnState,
|
|
377
411
|
emitJson,
|
|
378
412
|
} from './lib/runtime-client.mjs';
|
|
@@ -405,6 +439,7 @@ try {
|
|
|
405
439
|
action,
|
|
406
440
|
toolName,
|
|
407
441
|
target,
|
|
442
|
+
evidenceRef: makeEvidenceRef('tool_request', { action, toolName, target }, { sessionId }),
|
|
408
443
|
});
|
|
409
444
|
saveTurnState(sessionId, {
|
|
410
445
|
tools,
|
|
@@ -426,6 +461,7 @@ import {
|
|
|
426
461
|
inferSessionId,
|
|
427
462
|
readEventFromStdin,
|
|
428
463
|
loadTurnState,
|
|
464
|
+
makeEvidenceRef,
|
|
429
465
|
saveTurnState,
|
|
430
466
|
} from './lib/runtime-client.mjs';
|
|
431
467
|
|
|
@@ -435,11 +471,16 @@ const state = loadTurnState(sessionId);
|
|
|
435
471
|
|
|
436
472
|
try {
|
|
437
473
|
const toolResponse = JSON.stringify(event?.tool_response ?? event?.toolResponse ?? null).slice(0, 4000);
|
|
474
|
+
const evidenceRef = makeEvidenceRef('tool_response', event?.tool_response ?? event?.toolResponse ?? null, {
|
|
475
|
+
sessionId,
|
|
476
|
+
toolName: event?.tool_name || event?.toolName || null,
|
|
477
|
+
});
|
|
438
478
|
const toolOutputs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.slice(-24) : [];
|
|
439
479
|
toolOutputs.push({
|
|
440
480
|
at: new Date().toISOString(),
|
|
441
481
|
toolName: event?.tool_name || event?.toolName || null,
|
|
442
482
|
toolResponse,
|
|
483
|
+
evidenceRef,
|
|
443
484
|
});
|
|
444
485
|
saveTurnState(sessionId, {
|
|
445
486
|
toolOutputs,
|
|
@@ -461,6 +502,7 @@ import {
|
|
|
461
502
|
readEventFromStdin,
|
|
462
503
|
runtimePost,
|
|
463
504
|
loadTurnState,
|
|
505
|
+
makeEvidenceRef,
|
|
464
506
|
clearTurnState,
|
|
465
507
|
formatValidationFailure,
|
|
466
508
|
emitJson,
|
|
@@ -471,6 +513,8 @@ const client = getHarnessClient();
|
|
|
471
513
|
const sessionId = inferSessionId(event);
|
|
472
514
|
const state = loadTurnState(sessionId);
|
|
473
515
|
const text = extractAssistantText(event);
|
|
516
|
+
const outputRef = makeEvidenceRef('assistant_output', text, { sessionId, traceId: state?.traceId || null });
|
|
517
|
+
const toolRefs = Array.isArray(state?.toolOutputs) ? state.toolOutputs.map((entry) => entry.evidenceRef).filter(Boolean) : [];
|
|
474
518
|
|
|
475
519
|
try {
|
|
476
520
|
if (!text) {
|
|
@@ -505,12 +549,16 @@ try {
|
|
|
505
549
|
layer3_pass: validation?.layer3?.pass !== false,
|
|
506
550
|
surface: 'codex-hooks',
|
|
507
551
|
tool_count: Array.isArray(state?.tools) ? state.tools.length : 0,
|
|
552
|
+
trace_id: state?.traceId || null,
|
|
553
|
+
output_ref: outputRef,
|
|
554
|
+
tool_refs: toolRefs,
|
|
508
555
|
},
|
|
509
556
|
context: {
|
|
510
557
|
sessionId,
|
|
511
558
|
surface: 'codex-hooks',
|
|
512
559
|
platform: 'codex',
|
|
513
560
|
userText: state?.userText || null,
|
|
561
|
+
traceId: state?.traceId || null,
|
|
514
562
|
},
|
|
515
563
|
parentReceiptId: state?.preReceiptId || null,
|
|
516
564
|
});
|
|
@@ -527,6 +575,9 @@ try {
|
|
|
527
575
|
metadata: {
|
|
528
576
|
post_receipt_id: post?.receipt?.receiptId || null,
|
|
529
577
|
pre_receipt_id: state?.preReceiptId || null,
|
|
578
|
+
trace_id: state?.traceId || null,
|
|
579
|
+
output_ref: outputRef,
|
|
580
|
+
tool_refs: toolRefs,
|
|
530
581
|
tool_count: Array.isArray(state?.tools) ? state.tools.length : 0,
|
|
531
582
|
validation_severity: validation?.validation?.severity || 'pass',
|
|
532
583
|
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 });
|