atris 3.15.31 → 3.15.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/ax +479 -21
- package/bin/atris.js +1 -1
- package/commands/aeo.js +377 -13
- package/commands/business.js +21 -2
- package/commands/computer.js +346 -16
- package/commands/gm.js +4 -4
- package/commands/lifecycle.js +115 -0
- package/commands/mission.js +9 -3
- package/commands/play.js +4 -4
- package/commands/pull.js +11 -7
- package/commands/xp.js +342 -13
- package/lib/runtime-bootstrap.js +107 -0
- package/package.json +1 -1
package/commands/aeo.js
CHANGED
|
@@ -1,24 +1,98 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* atris aeo — AI Engine Optimization commands
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* atris aeo
|
|
4
|
+
* Backend-routed (require EC2):
|
|
5
|
+
* atris aeo init # create entity-graph skeleton
|
|
6
|
+
* atris aeo draft "<topic>" [opts] # generate citation-optimized article
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Local-read against ~/arena/atrisos-backend/atris/features/aeo/proof/:
|
|
9
|
+
* atris aeo log [--engine X] [--limit N] # citation attempt log
|
|
10
|
+
* atris aeo status # engine + proof + buyer summary
|
|
11
|
+
* atris aeo packet <slug> # buyer packet for a surface
|
|
12
|
+
* atris aeo proofs [--filter X] # list proof receipt categories
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
+
* Shell out to atrisos-backend/scripts/aeo_*.py:
|
|
15
|
+
* atris aeo discover <source> [...] # discovery audit
|
|
16
|
+
* atris aeo audit <source> [...] # agent-usability audit
|
|
17
|
+
*
|
|
18
|
+
* Backend root resolution: $ATRIS_BACKEND_ROOT or ~/arena/atrisos-backend.
|
|
14
19
|
*/
|
|
15
20
|
|
|
16
21
|
const fs = require('fs');
|
|
22
|
+
const os = require('os');
|
|
17
23
|
const path = require('path');
|
|
24
|
+
const { spawnSync } = require('child_process');
|
|
18
25
|
const { loadCredentials } = require('../utils/auth');
|
|
19
26
|
const { apiRequestJson } = require('../utils/api');
|
|
20
27
|
const { loadBusinesses, saveBusinesses } = require('./business');
|
|
21
28
|
|
|
29
|
+
function resolveBackendRoot() {
|
|
30
|
+
const candidates = [
|
|
31
|
+
process.env.ATRIS_BACKEND_ROOT,
|
|
32
|
+
path.join(os.homedir(), 'arena', 'atrisos-backend'),
|
|
33
|
+
].filter(Boolean);
|
|
34
|
+
for (const root of candidates) {
|
|
35
|
+
if (fs.existsSync(path.join(root, 'atris', 'features', 'aeo'))) return root;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requireBackendRoot() {
|
|
41
|
+
const root = resolveBackendRoot();
|
|
42
|
+
if (!root) {
|
|
43
|
+
console.error('Cannot find atrisos-backend. Set $ATRIS_BACKEND_ROOT or clone to ~/arena/atrisos-backend.');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
return root;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readJsonSafe(p) {
|
|
50
|
+
if (!fs.existsSync(p)) return null;
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(` warning: malformed JSON at ${p} (${err.message})`);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function pad(s, n) { s = String(s); return s.length >= n ? s.slice(0, n) : s + ' '.repeat(n - s.length); }
|
|
60
|
+
|
|
61
|
+
function assertNoExtras(sub, args, allowedFlags) {
|
|
62
|
+
const allowed = new Set(allowedFlags);
|
|
63
|
+
const unknownFlags = args.filter((a) => a.startsWith('--') && !allowed.has(a));
|
|
64
|
+
const positional = args.filter((a) => !a.startsWith('--'));
|
|
65
|
+
if (unknownFlags.length) {
|
|
66
|
+
console.error(`Unknown flag for aeo ${sub}: ${unknownFlags.join(' ')}. Supported: ${[...allowed].join(' ') || '(none)'}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
if (positional.length) {
|
|
70
|
+
console.error(`Unexpected argument for aeo ${sub}: ${positional.join(' ')}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function readArg(args, ...keys) {
|
|
76
|
+
for (const k of keys) {
|
|
77
|
+
const eqIdx = args.findIndex((a) => a.startsWith(`${k}=`));
|
|
78
|
+
if (eqIdx !== -1) {
|
|
79
|
+
const v = args[eqIdx].slice(k.length + 1);
|
|
80
|
+
args.splice(eqIdx, 1);
|
|
81
|
+
return v;
|
|
82
|
+
}
|
|
83
|
+
const i = args.findIndex((a) => a === k);
|
|
84
|
+
if (i === -1) continue;
|
|
85
|
+
const v = args[i + 1];
|
|
86
|
+
if (v === undefined || v.startsWith('--')) {
|
|
87
|
+
console.error(`Flag ${k} requires a value.`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
args.splice(i, 2);
|
|
91
|
+
return v;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
22
96
|
function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
|
|
23
97
|
|
|
24
98
|
async function ensureAwake(token, businessId, maxWaitSec = 90) {
|
|
@@ -83,13 +157,25 @@ function pickSlug(args) {
|
|
|
83
157
|
|
|
84
158
|
function printHelp() {
|
|
85
159
|
console.log('Usage:');
|
|
86
|
-
console.log('
|
|
87
|
-
console.log('
|
|
160
|
+
console.log(' Backend / EC2:');
|
|
161
|
+
console.log(' atris aeo init [--workspace <slug>]');
|
|
162
|
+
console.log(' atris aeo draft "<topic>" [--workspace <slug>] [--queries q1,q2] [--slug X] [--url URL]');
|
|
163
|
+
console.log('');
|
|
164
|
+
console.log(' Local read (atris/features/aeo/proof/):');
|
|
165
|
+
console.log(' atris aeo log [--engine X] [--limit N] [--json]');
|
|
166
|
+
console.log(' atris aeo status [--json]');
|
|
167
|
+
console.log(' atris aeo packet <slug> [--json]');
|
|
168
|
+
console.log(' atris aeo proofs [--filter X]');
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(' Script wrappers (scripts/aeo_*.py):');
|
|
171
|
+
console.log(' atris aeo discover <source> [--question Q ...] [--canonical-url URL] [--out-dir DIR]');
|
|
172
|
+
console.log(' atris aeo audit <source> [--baseline B] [--canonical-url URL] [--out-dir DIR]');
|
|
88
173
|
console.log('');
|
|
89
174
|
console.log('Examples:');
|
|
90
|
-
console.log(' atris aeo
|
|
91
|
-
console.log(' atris aeo
|
|
92
|
-
console.log(' atris aeo
|
|
175
|
+
console.log(' atris aeo log --engine perplexity --limit 5');
|
|
176
|
+
console.log(' atris aeo packet pallet');
|
|
177
|
+
console.log(' atris aeo status');
|
|
178
|
+
console.log(' atris aeo discover https://atris.ai/aeo --canonical-url https://atris.ai/aeo');
|
|
93
179
|
}
|
|
94
180
|
|
|
95
181
|
async function aeoInit(args) {
|
|
@@ -183,12 +269,290 @@ async function aeoDraft(args) {
|
|
|
183
269
|
if (data.hint) console.log(` hint: ${data.hint}`);
|
|
184
270
|
}
|
|
185
271
|
|
|
272
|
+
// ---------- LOCAL READ SUBCOMMANDS ----------
|
|
273
|
+
|
|
274
|
+
function loadCitationAttempts(root) {
|
|
275
|
+
const dir = path.join(root, 'atris', 'features', 'aeo', 'proof', 'live-citation-attempts');
|
|
276
|
+
if (!fs.existsSync(dir)) return [];
|
|
277
|
+
const rows = [];
|
|
278
|
+
for (const file of fs.readdirSync(dir)) {
|
|
279
|
+
if (!file.endsWith('.json')) continue;
|
|
280
|
+
const data = readJsonSafe(path.join(dir, file));
|
|
281
|
+
if (!data || !Array.isArray(data.attempts)) continue;
|
|
282
|
+
for (const attempt of data.attempts) {
|
|
283
|
+
if (!attempt || typeof attempt !== 'object') continue;
|
|
284
|
+
const cited = attempt.answer_cites_target_url === true;
|
|
285
|
+
const mentioned = attempt.answer_mentions_target_entity === true;
|
|
286
|
+
let status;
|
|
287
|
+
if (cited) status = 'verified';
|
|
288
|
+
else if (mentioned) status = 'pending';
|
|
289
|
+
else status = 'failed';
|
|
290
|
+
const str = (v) => (typeof v === 'string' ? v : '');
|
|
291
|
+
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
292
|
+
rows.push({
|
|
293
|
+
file,
|
|
294
|
+
attempted_at: str(data.attempted_at),
|
|
295
|
+
engine: str(data.engine),
|
|
296
|
+
prompt_id: str(attempt.prompt_id),
|
|
297
|
+
prompt: str(attempt.exact_prompt),
|
|
298
|
+
target_entity: str(data.target_entity),
|
|
299
|
+
target_urls: arr(data.target_url_candidates),
|
|
300
|
+
answer_evidence_uri: str(attempt.answer_evidence_uri),
|
|
301
|
+
status,
|
|
302
|
+
competitors: arr(attempt.observed_competitor_or_alternative_entities),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
rows.sort((a, b) => (b.attempted_at || '').localeCompare(a.attempted_at || ''));
|
|
307
|
+
return rows;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function aeoLog(args) {
|
|
311
|
+
const engine = readArg(args, '--engine', '-e');
|
|
312
|
+
const limitRaw = readArg(args, '--limit', '-n');
|
|
313
|
+
assertNoExtras('log', args, ['--json']);
|
|
314
|
+
const wantJson = args.includes('--json');
|
|
315
|
+
let limit = 20;
|
|
316
|
+
if (limitRaw != null) {
|
|
317
|
+
const trimmed = String(limitRaw).trim();
|
|
318
|
+
const parsed = parseInt(trimmed, 10);
|
|
319
|
+
if (!/^[+-]?\d+$/.test(trimmed) || !Number.isFinite(parsed) || parsed < 1) {
|
|
320
|
+
console.error(`Invalid --limit value: "${limitRaw}". Expected a positive integer.`);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
limit = parsed;
|
|
324
|
+
}
|
|
325
|
+
const root = requireBackendRoot();
|
|
326
|
+
let rows = loadCitationAttempts(root);
|
|
327
|
+
if (engine) rows = rows.filter((r) => r.engine.toLowerCase() === engine.toLowerCase());
|
|
328
|
+
rows = rows.slice(0, limit);
|
|
329
|
+
|
|
330
|
+
if (wantJson) {
|
|
331
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (!rows.length) {
|
|
336
|
+
console.log('No citation attempts found.');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const counts = rows.reduce((acc, r) => { acc[r.status] = (acc[r.status] || 0) + 1; return acc; }, {});
|
|
341
|
+
console.log(`AEO citation log (${rows.length} attempt${rows.length === 1 ? '' : 's'})`);
|
|
342
|
+
console.log(` ${Object.entries(counts).map(([k, v]) => `${k}=${v}`).join(' ')}`);
|
|
343
|
+
console.log('');
|
|
344
|
+
console.log(` ${pad('ts', 22)}${pad('engine', 12)}${pad('prompt_id', 26)}${pad('status', 10)}`);
|
|
345
|
+
console.log(` ${'-'.repeat(70)}`);
|
|
346
|
+
for (const r of rows) {
|
|
347
|
+
console.log(` ${pad(r.attempted_at.slice(0, 19), 22)}${pad(r.engine, 12)}${pad(r.prompt_id, 26)}${pad(r.status, 10)}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async function aeoStatus(args) {
|
|
352
|
+
assertNoExtras('status', args, ['--json']);
|
|
353
|
+
const wantJson = args.includes('--json');
|
|
354
|
+
const root = requireBackendRoot();
|
|
355
|
+
const proofRoot = path.join(root, 'atris', 'features', 'aeo', 'proof');
|
|
356
|
+
|
|
357
|
+
const attempts = loadCitationAttempts(root);
|
|
358
|
+
const enginesSeen = new Set(attempts.map((a) => a.engine).filter(Boolean));
|
|
359
|
+
const verified = attempts.filter((a) => a.status === 'verified').length;
|
|
360
|
+
const pending = attempts.filter((a) => a.status === 'pending').length;
|
|
361
|
+
const failed = attempts.filter((a) => a.status === 'failed').length;
|
|
362
|
+
|
|
363
|
+
const packets = [];
|
|
364
|
+
if (fs.existsSync(proofRoot)) {
|
|
365
|
+
for (const entry of fs.readdirSync(proofRoot)) {
|
|
366
|
+
if (!entry.endsWith('-buyer-packet')) continue;
|
|
367
|
+
const p = path.join(proofRoot, entry, 'packet.json');
|
|
368
|
+
const data = readJsonSafe(p);
|
|
369
|
+
if (!data) continue;
|
|
370
|
+
packets.push({
|
|
371
|
+
slug: entry.replace(/-buyer-packet$/, ''),
|
|
372
|
+
surface: data.surface || entry,
|
|
373
|
+
target_url: data.target_url || '',
|
|
374
|
+
baseline: data?.agent_usability?.baseline_score ?? null,
|
|
375
|
+
proposed: data?.agent_usability?.proposed_score ?? null,
|
|
376
|
+
claim_status: data.claim_status || '',
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const operator = readJsonSafe(path.join(proofRoot, 'live-citation-operator', 'live-citation-operator.json'));
|
|
382
|
+
|
|
383
|
+
const proofDirs = fs.existsSync(proofRoot)
|
|
384
|
+
? fs.readdirSync(proofRoot).filter((e) => fs.statSync(path.join(proofRoot, e)).isDirectory()).length
|
|
385
|
+
: 0;
|
|
386
|
+
|
|
387
|
+
if (wantJson) {
|
|
388
|
+
console.log(JSON.stringify({
|
|
389
|
+
backend_root: root,
|
|
390
|
+
proof_dirs: proofDirs,
|
|
391
|
+
citation: { total: attempts.length, verified, pending, failed, engines: [...enginesSeen] },
|
|
392
|
+
packets,
|
|
393
|
+
operator_status: operator?.status || null,
|
|
394
|
+
operator_blocker: operator?.current_blocker || null,
|
|
395
|
+
}, null, 2));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
console.log('Atris AEO status');
|
|
400
|
+
console.log(` backend root: ${root}`);
|
|
401
|
+
console.log(` proof receipts: ${proofDirs} categories`);
|
|
402
|
+
console.log('');
|
|
403
|
+
console.log('Live citations');
|
|
404
|
+
console.log(` attempts: ${attempts.length}`);
|
|
405
|
+
console.log(` verified: ${verified}`);
|
|
406
|
+
console.log(` pending: ${pending}`);
|
|
407
|
+
console.log(` failed: ${failed}`);
|
|
408
|
+
console.log(` engines observed: ${[...enginesSeen].join(', ') || '(none)'}`);
|
|
409
|
+
if (operator) {
|
|
410
|
+
console.log(` operator state: ${operator.status || '?'} (blocker: ${operator.current_blocker || 'none'})`);
|
|
411
|
+
}
|
|
412
|
+
console.log('');
|
|
413
|
+
console.log(`Buyer packets (${packets.length})`);
|
|
414
|
+
for (const p of packets) {
|
|
415
|
+
const delta = p.baseline != null && p.proposed != null ? `${p.baseline} → ${p.proposed}` : '?';
|
|
416
|
+
console.log(` ${pad(p.slug, 16)} ${pad(p.target_url || p.surface, 36)} ${pad(delta, 12)} ${p.claim_status}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async function aeoPacket(args) {
|
|
421
|
+
const known = new Set(['--json']);
|
|
422
|
+
const positional = [];
|
|
423
|
+
for (const a of args) {
|
|
424
|
+
if (a.startsWith('--')) {
|
|
425
|
+
if (!known.has(a)) {
|
|
426
|
+
console.error(`Unknown flag: ${a}. Supported: --json`);
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
positional.push(a);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (positional.length === 0) {
|
|
434
|
+
console.error('Missing slug. Usage: atris aeo packet <slug>');
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
if (positional.length > 1) {
|
|
438
|
+
console.error(`Too many arguments: ${positional.join(' ')}. Expected one slug.`);
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
const slug = positional[0];
|
|
442
|
+
const wantJson = args.includes('--json');
|
|
443
|
+
const root = requireBackendRoot();
|
|
444
|
+
const file = path.join(root, 'atris', 'features', 'aeo', 'proof', `${slug}-buyer-packet`, 'packet.json');
|
|
445
|
+
const data = readJsonSafe(file);
|
|
446
|
+
if (!data) {
|
|
447
|
+
console.error(`Packet not found: ${file}`);
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (wantJson) {
|
|
452
|
+
console.log(JSON.stringify(data, null, 2));
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const u = (data && typeof data.agent_usability === 'object' && data.agent_usability) || {};
|
|
457
|
+
const onlyObjects = (v) => (Array.isArray(v) ? v.filter((x) => x && typeof x === 'object') : []);
|
|
458
|
+
const friction = onlyObjects(u.baseline_friction_points);
|
|
459
|
+
const fixes = onlyObjects(u.fix_backlog);
|
|
460
|
+
console.log(`AEO buyer packet — ${slug}`);
|
|
461
|
+
console.log(` surface: ${data.surface || ''}`);
|
|
462
|
+
console.log(` target url: ${data.target_url || ''}`);
|
|
463
|
+
console.log(` claim status: ${data.claim_status || ''}`);
|
|
464
|
+
console.log(` positioning: ${u.positioning || ''}`);
|
|
465
|
+
console.log('');
|
|
466
|
+
console.log('Agent usability scores');
|
|
467
|
+
console.log(` baseline: ${u.baseline_score ?? '?'}`);
|
|
468
|
+
console.log(` proposed: ${u.proposed_score ?? '?'}`);
|
|
469
|
+
console.log(` delta: ${u.score_delta ?? '?'}`);
|
|
470
|
+
console.log(` verified: ${u.movement_verified ? 'yes' : 'no'}`);
|
|
471
|
+
console.log('');
|
|
472
|
+
console.log(`Baseline friction (${friction.length})`);
|
|
473
|
+
for (const f of friction) {
|
|
474
|
+
console.log(` [${f.severity || '?'}] ${f.stage || '?'}: ${f.missing_artifact || f.id || ''}`);
|
|
475
|
+
}
|
|
476
|
+
console.log('');
|
|
477
|
+
console.log(`Fix backlog (${fixes.length})`);
|
|
478
|
+
for (const f of fixes) {
|
|
479
|
+
console.log(` #${f.priority ?? '?'} ${f.stage || '?'}: ${f.action || ''}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function aeoProofs(args) {
|
|
484
|
+
const filter = readArg(args, '--filter', '-f');
|
|
485
|
+
assertNoExtras('proofs', args, []);
|
|
486
|
+
const root = requireBackendRoot();
|
|
487
|
+
const proofRoot = path.join(root, 'atris', 'features', 'aeo', 'proof');
|
|
488
|
+
if (!fs.existsSync(proofRoot)) {
|
|
489
|
+
console.error(`Proof root not found: ${proofRoot}`);
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
const needle = filter ? filter.toLowerCase() : null;
|
|
493
|
+
const entries = fs.readdirSync(proofRoot)
|
|
494
|
+
.filter((e) => fs.statSync(path.join(proofRoot, e)).isDirectory())
|
|
495
|
+
.filter((e) => !needle || e.toLowerCase().includes(needle))
|
|
496
|
+
.sort();
|
|
497
|
+
console.log(`AEO proof receipts at ${path.relative(process.cwd(), proofRoot)}`);
|
|
498
|
+
console.log('');
|
|
499
|
+
for (const e of entries) {
|
|
500
|
+
const files = fs.readdirSync(path.join(proofRoot, e)).filter((f) => f.endsWith('.json'));
|
|
501
|
+
console.log(` ${pad(e, 44)} ${files.length} file${files.length === 1 ? '' : 's'}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// ---------- SCRIPT WRAPPERS ----------
|
|
506
|
+
|
|
507
|
+
function runBackendScript(scriptName, args) {
|
|
508
|
+
const root = requireBackendRoot();
|
|
509
|
+
const script = path.join(root, 'scripts', scriptName);
|
|
510
|
+
if (!fs.existsSync(script)) {
|
|
511
|
+
console.error(`Script not found: ${script}`);
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
const py = process.env.ATRIS_PYTHON || 'python3';
|
|
515
|
+
const result = spawnSync(py, [script, ...args], { cwd: root, stdio: 'inherit' });
|
|
516
|
+
if (result.error) {
|
|
517
|
+
console.error(`Failed to spawn ${py}: ${result.error.message}`);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
if (result.signal) {
|
|
521
|
+
const signum = os.constants?.signals?.[result.signal] ?? 0;
|
|
522
|
+
console.error(`${scriptName} terminated by signal ${result.signal}`);
|
|
523
|
+
process.exit(128 + signum);
|
|
524
|
+
}
|
|
525
|
+
process.exit(result.status ?? 1);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async function aeoDiscover(args) {
|
|
529
|
+
if (!args.length || args[0] === '--help' || args[0] === '-h') {
|
|
530
|
+
console.log('Usage: atris aeo discover <source> [--question Q]... [--canonical-url URL] [--out-dir DIR] [--json]');
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
runBackendScript('aeo_discovery_audit.py', args);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async function aeoAudit(args) {
|
|
537
|
+
if (!args.length || args[0] === '--help' || args[0] === '-h') {
|
|
538
|
+
console.log('Usage: atris aeo audit <source> [--baseline B] [--canonical-url URL] [--out-dir DIR] [--task T]');
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
runBackendScript('aeo_agent_usability_audit.py', args);
|
|
542
|
+
}
|
|
543
|
+
|
|
186
544
|
async function run(args = []) {
|
|
187
545
|
const sub = args[0];
|
|
188
546
|
if (!sub || sub === 'help' || sub === '--help' || sub === '-h') return printHelp();
|
|
189
547
|
const rest = args.slice(1);
|
|
190
548
|
if (sub === 'init') return aeoInit(rest);
|
|
191
549
|
if (sub === 'draft') return aeoDraft(rest);
|
|
550
|
+
if (sub === 'log') return aeoLog(rest);
|
|
551
|
+
if (sub === 'status') return aeoStatus(rest);
|
|
552
|
+
if (sub === 'packet') return aeoPacket(rest);
|
|
553
|
+
if (sub === 'proofs') return aeoProofs(rest);
|
|
554
|
+
if (sub === 'discover') return aeoDiscover(rest);
|
|
555
|
+
if (sub === 'audit') return aeoAudit(rest);
|
|
192
556
|
console.error(`Unknown aeo subcommand: ${sub}`);
|
|
193
557
|
printHelp();
|
|
194
558
|
process.exit(1);
|
package/commands/business.js
CHANGED
|
@@ -5,6 +5,7 @@ const { loadCredentials } = require('../utils/auth');
|
|
|
5
5
|
const { apiRequestJson } = require('../utils/api');
|
|
6
6
|
const { syncBusinessCanonical, ensureWorkspaceStateFiles } = require('./sync');
|
|
7
7
|
const { ensureContextScaffold, writeWikiStatus, appendWikiLog } = require('../lib/wiki');
|
|
8
|
+
const { writeRuntimeReceipt } = require('../lib/runtime-bootstrap');
|
|
8
9
|
|
|
9
10
|
function getBusinessConfigPath() {
|
|
10
11
|
const home = require('os').homedir();
|
|
@@ -398,6 +399,17 @@ function createCanonicalBusinessWorkspace(targetRoot, bizMeta, options = {}) {
|
|
|
398
399
|
}, null, 2));
|
|
399
400
|
|
|
400
401
|
syncBusinessCanonical(targetRoot, bizMeta, { force: false, dryRun: false, templateName: workspaceTemplate });
|
|
402
|
+
writeRuntimeReceipt(targetRoot, {
|
|
403
|
+
scope: 'local-business-computer',
|
|
404
|
+
boundary: 'business-workspace-scaffold',
|
|
405
|
+
business_id: bizMeta.business_id,
|
|
406
|
+
workspace_id: bizMeta.workspace_id,
|
|
407
|
+
business_slug: bizMeta.slug,
|
|
408
|
+
business_name: bizMeta.name,
|
|
409
|
+
workspace_template: workspaceTemplate,
|
|
410
|
+
install_status: 'local_cli_present',
|
|
411
|
+
sync_status: 'templates_seeded',
|
|
412
|
+
});
|
|
401
413
|
return { targetRoot, businessJsonPath, workspaceTemplate };
|
|
402
414
|
}
|
|
403
415
|
|
|
@@ -1827,8 +1839,15 @@ async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
|
1827
1839
|
console.log(` Dashboard: https://atris.ai/dashboard/gm/${biz.id}`);
|
|
1828
1840
|
if (shouldCreateCanonicalWorkspace) {
|
|
1829
1841
|
const workspaceRoot = resolveWorkspaceRoot(biz.slug, options);
|
|
1830
|
-
console.log(
|
|
1831
|
-
console.log('
|
|
1842
|
+
console.log(' Atris: seeded local computer + operator + validator');
|
|
1843
|
+
console.log('');
|
|
1844
|
+
console.log(' Start here:');
|
|
1845
|
+
console.log(` cd ${workspaceRoot}`);
|
|
1846
|
+
console.log(' atris member activate operator');
|
|
1847
|
+
console.log(' atris business onboard --website <url> --contact "Name" --note "what they do"');
|
|
1848
|
+
console.log('');
|
|
1849
|
+
console.log(' Sync when ready:');
|
|
1850
|
+
console.log(` atris align ${biz.slug} --fix`);
|
|
1832
1851
|
}
|
|
1833
1852
|
console.log('');
|
|
1834
1853
|
}
|