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/xp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { ensureValidCredentials } = require('../utils/auth');
|
|
1
|
+
const { ensureValidCredentials, getSessionProfile, loadCredentials, profileNameFromEmail } = require('../utils/auth');
|
|
2
2
|
const { apiRequestJson } = require('../utils/api');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
@@ -20,6 +20,50 @@ const AGENT_XP_LABEL = 'AgentXP';
|
|
|
20
20
|
const AGENTXP_LEADERBOARD_URL = 'https://api.atris.ai/api/agentxp/leaderboard';
|
|
21
21
|
const LEVEL_XP = 1000;
|
|
22
22
|
const RECEIPT_CHAIN_VERSION = 'atris.career_xp_receipt_chain.v1';
|
|
23
|
+
const VALIDATION_TERMS = ['verify', 'verified', 'verifier', 'passed', 'pytest', 'receipt', 'score', 'smoke', 'git diff --check'];
|
|
24
|
+
const QUALITY_TERMS = ['craft', 'scorecard', 'quality', 'critique', 'review', 'taste'];
|
|
25
|
+
const ATRIS_ACCEPTED_STATUSES = new Set(['accepted', 'approved', 'done', 'review', 'reviewed', 'unknown']);
|
|
26
|
+
const ATRIS_ACCEPTED_EVENTS = new Set(['accepted', 'approved', 'completed', 'done', 'reviewed', 'unknown']);
|
|
27
|
+
const EARNING_MODEL = {
|
|
28
|
+
schema: 'atris.agentxp_earning_model.v1',
|
|
29
|
+
score_name: AGENT_XP_LABEL,
|
|
30
|
+
primary_public_source: 'accepted_task_receipt',
|
|
31
|
+
public_rule: 'No accepted proof-backed task episodes means no AgentXP leaderboard movement.',
|
|
32
|
+
weights: [
|
|
33
|
+
{
|
|
34
|
+
id: 'accepted_task_receipt',
|
|
35
|
+
label: 'Accepted proof-backed task',
|
|
36
|
+
relative_weight: 1,
|
|
37
|
+
public_leaderboard: true,
|
|
38
|
+
rl_value: 'high',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'validated_agent_loop',
|
|
42
|
+
label: 'Verifier or agent loop inside an accepted task',
|
|
43
|
+
relative_weight: 0.35,
|
|
44
|
+
public_leaderboard: true,
|
|
45
|
+
rl_value: 'high',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'atris_action_signal',
|
|
49
|
+
label: 'Atris action signal',
|
|
50
|
+
relative_weight: 0.1,
|
|
51
|
+
public_leaderboard: false,
|
|
52
|
+
rl_value: 'medium',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'local_assistant_activity',
|
|
56
|
+
label: 'Local assistant activity',
|
|
57
|
+
relative_weight: 0.05,
|
|
58
|
+
public_leaderboard: false,
|
|
59
|
+
rl_value: 'medium',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
caps: {
|
|
63
|
+
local_assistant_activity: 'Capped below 10% of accepted-task XP and never unlocks public ranking alone.',
|
|
64
|
+
atris_action_signal: 'Routes RL and next moves, but does not outrank an accepted proof-backed task.',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
23
67
|
const XP_STATE_FILES = new Set([
|
|
24
68
|
path.basename(TASK_EPISODES_FILE),
|
|
25
69
|
path.basename(CAREER_XP_RECEIPTS_FILE),
|
|
@@ -421,6 +465,199 @@ function sqlString(value) {
|
|
|
421
465
|
return `'${String(value).replace(/'/g, "''")}'`;
|
|
422
466
|
}
|
|
423
467
|
|
|
468
|
+
function existingSignal(label, filePath) {
|
|
469
|
+
if (!filePath) return null;
|
|
470
|
+
try {
|
|
471
|
+
const stat = fs.statSync(expandHome(filePath));
|
|
472
|
+
return {
|
|
473
|
+
label,
|
|
474
|
+
kind: stat.isDirectory() ? 'dir' : 'file',
|
|
475
|
+
size_bytes: stat.isFile() ? stat.size : null,
|
|
476
|
+
mtime: stat.mtime.toISOString(),
|
|
477
|
+
};
|
|
478
|
+
} catch (_) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function localAssistantProviderSignals(workspace) {
|
|
484
|
+
const codexStatePath = process.env.CODEX_STATE_DB || CODEX_STATE_FILE;
|
|
485
|
+
const candidates = [
|
|
486
|
+
{
|
|
487
|
+
id: 'codex',
|
|
488
|
+
label: 'Codex',
|
|
489
|
+
signals: [
|
|
490
|
+
existingSignal('codex_state', codexStatePath),
|
|
491
|
+
existingSignal('codex_history', path.join(os.homedir(), '.codex', 'history.jsonl')),
|
|
492
|
+
existingSignal('codex_sessions', path.join(os.homedir(), '.codex', 'sessions')),
|
|
493
|
+
],
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: 'claude',
|
|
497
|
+
label: 'Claude',
|
|
498
|
+
signals: [
|
|
499
|
+
existingSignal('claude_home', path.join(os.homedir(), '.claude')),
|
|
500
|
+
existingSignal('claude_config', path.join(os.homedir(), '.claude.json')),
|
|
501
|
+
existingSignal('workspace_claude', path.join(workspace, '.claude')),
|
|
502
|
+
],
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
id: 'cursor',
|
|
506
|
+
label: 'Cursor',
|
|
507
|
+
signals: [
|
|
508
|
+
existingSignal('workspace_cursor', path.join(workspace, '.cursor')),
|
|
509
|
+
existingSignal('cursor_home', path.join(os.homedir(), '.cursor')),
|
|
510
|
+
existingSignal('cursor_app_support', path.join(os.homedir(), 'Library', 'Application Support', 'Cursor')),
|
|
511
|
+
],
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
id: 'devin',
|
|
515
|
+
label: 'Devin',
|
|
516
|
+
signals: [
|
|
517
|
+
existingSignal('workspace_devin', path.join(workspace, '.devin')),
|
|
518
|
+
existingSignal('devin_home', path.join(os.homedir(), '.devin')),
|
|
519
|
+
],
|
|
520
|
+
},
|
|
521
|
+
];
|
|
522
|
+
|
|
523
|
+
return candidates.map((provider) => {
|
|
524
|
+
const signals = provider.signals.filter(Boolean);
|
|
525
|
+
return {
|
|
526
|
+
id: provider.id,
|
|
527
|
+
label: provider.label,
|
|
528
|
+
detected: signals.length > 0,
|
|
529
|
+
signal_count: signals.length,
|
|
530
|
+
signals,
|
|
531
|
+
};
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function buildLocalAssistantActivity(workspace, acceptedTaskXp = 0) {
|
|
536
|
+
const providers = localAssistantProviderSignals(workspace);
|
|
537
|
+
const detected = providers.filter(provider => provider.detected);
|
|
538
|
+
const rawSignalCount = detected.reduce((sum, provider) => sum + provider.signal_count, 0);
|
|
539
|
+
const weight = EARNING_MODEL.weights.find(item => item.id === 'local_assistant_activity')?.relative_weight || 0.05;
|
|
540
|
+
const weightedContext = Math.round(rawSignalCount * weight * 100) / 100;
|
|
541
|
+
const acceptedXp = asNumber(acceptedTaskXp);
|
|
542
|
+
const contextCap = Math.round(acceptedXp * 0.1 * 100) / 100;
|
|
543
|
+
const contextAgentXp = acceptedXp > 0 ? Math.min(weightedContext, contextCap) : 0;
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
schema: 'atris.agentxp_local_assistant_activity.v1',
|
|
547
|
+
public_leaderboard: false,
|
|
548
|
+
source_type: 'local_assistant_activity',
|
|
549
|
+
weight,
|
|
550
|
+
context_weight: weight,
|
|
551
|
+
cap: {
|
|
552
|
+
max_public_xp_ratio: 0.1,
|
|
553
|
+
requires_accepted_task_xp: true,
|
|
554
|
+
},
|
|
555
|
+
cap_ratio_to_accepted_task_xp: 0.1,
|
|
556
|
+
cap_agent_xp: contextCap,
|
|
557
|
+
accepted_task_agent_xp: acceptedXp,
|
|
558
|
+
detected_providers: detected.map(provider => provider.id).sort(),
|
|
559
|
+
provider_count: detected.length,
|
|
560
|
+
providers,
|
|
561
|
+
raw_signal_count: rawSignalCount,
|
|
562
|
+
weighted_context_score: weightedContext,
|
|
563
|
+
context_agent_xp: contextAgentXp,
|
|
564
|
+
included_in_total_agent_xp: false,
|
|
565
|
+
role: 'context_only',
|
|
566
|
+
note: 'Local assistant activity helps context and RL; accepted proof-backed tasks are the public AgentXP source.',
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function safeSignalKey(value) {
|
|
571
|
+
const text = String(value || '').trim().toLowerCase().replace(/[\s_]+/g, '-');
|
|
572
|
+
const clean = [...text].filter(char => /[a-z0-9_-]/.test(char)).join('');
|
|
573
|
+
return clean.slice(0, 40) || 'unknown';
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function hasAnyTerm(text, terms) {
|
|
577
|
+
const lower = String(text || '').toLowerCase();
|
|
578
|
+
return terms.some(term => lower.includes(term));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function incrementCount(counts, key) {
|
|
582
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function buildAtrisActionSignalFromRows(rows = []) {
|
|
586
|
+
const eventTypeCounts = {};
|
|
587
|
+
const statusCounts = {};
|
|
588
|
+
const actors = new Set();
|
|
589
|
+
const claimants = new Set();
|
|
590
|
+
let proofBackedEpisodeCount = 0;
|
|
591
|
+
let acceptedEpisodeCount = 0;
|
|
592
|
+
let validationReceiptCount = 0;
|
|
593
|
+
let qualityReceiptCount = 0;
|
|
594
|
+
let claimedEpisodeCount = 0;
|
|
595
|
+
|
|
596
|
+
for (const row of rows || []) {
|
|
597
|
+
const action = row?.action && typeof row.action === 'object' ? row.action : {};
|
|
598
|
+
const state = row?.state && typeof row.state === 'object' ? row.state : {};
|
|
599
|
+
const eventType = safeSignalKey(action.event_type || action.type || action.name);
|
|
600
|
+
const status = safeSignalKey(state.status);
|
|
601
|
+
incrementCount(eventTypeCounts, eventType);
|
|
602
|
+
incrementCount(statusCounts, status);
|
|
603
|
+
|
|
604
|
+
const actor = slugify(action.actor || '');
|
|
605
|
+
if (actor) actors.add(actor);
|
|
606
|
+
const claimant = slugify(state.claimed_by || state.assigned_to || '');
|
|
607
|
+
if (claimant) {
|
|
608
|
+
claimants.add(claimant);
|
|
609
|
+
claimedEpisodeCount += 1;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
const proof = String(row?.proof || '').trim();
|
|
613
|
+
const proofBacked = proof.length >= 20;
|
|
614
|
+
if (proofBacked) proofBackedEpisodeCount += 1;
|
|
615
|
+
if (proofBacked && hasAnyTerm(proof, VALIDATION_TERMS)) validationReceiptCount += 1;
|
|
616
|
+
if (proofBacked && hasAnyTerm(proof, QUALITY_TERMS)) qualityReceiptCount += 1;
|
|
617
|
+
if (
|
|
618
|
+
proofBacked
|
|
619
|
+
&& status !== 'failed'
|
|
620
|
+
&& (ATRIS_ACCEPTED_STATUSES.has(status) || ATRIS_ACCEPTED_EVENTS.has(eventType))
|
|
621
|
+
) {
|
|
622
|
+
acceptedEpisodeCount += 1;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
schema: 'atris.agentxp_atris_action_signal.v1',
|
|
628
|
+
source: '.atris/state/task_episodes.jsonl',
|
|
629
|
+
episode_count: rows.length,
|
|
630
|
+
accepted_episode_count: acceptedEpisodeCount,
|
|
631
|
+
proof_backed_episode_count: proofBackedEpisodeCount,
|
|
632
|
+
validation_receipt_count: validationReceiptCount,
|
|
633
|
+
quality_receipt_count: qualityReceiptCount,
|
|
634
|
+
claimed_episode_count: claimedEpisodeCount,
|
|
635
|
+
reviewed_episode_count: eventTypeCounts.reviewed || 0,
|
|
636
|
+
distinct_actor_count: actors.size,
|
|
637
|
+
distinct_claimant_count: claimants.size,
|
|
638
|
+
event_type_counts: Object.fromEntries(Object.entries(eventTypeCounts).sort()),
|
|
639
|
+
status_counts: Object.fromEntries(Object.entries(statusCounts).sort()),
|
|
640
|
+
included_in_total_agent_xp: false,
|
|
641
|
+
public_leaderboard: false,
|
|
642
|
+
role: 'rl_routing_only',
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function readTaskEpisodesForWorkspace(workspace) {
|
|
647
|
+
if (!workspace) return [];
|
|
648
|
+
return readJsonl(path.join(workspace, TASK_EPISODES_FILE));
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function buildAtrisActionSignal(projection) {
|
|
652
|
+
const workspaceRoots = Array.isArray(projection?.workspaces)
|
|
653
|
+
? projection.workspaces
|
|
654
|
+
.filter(workspace => workspace?.included && workspace.workspace_root)
|
|
655
|
+
.map(workspace => workspace.workspace_root)
|
|
656
|
+
: [projection?.workspace_root].filter(Boolean);
|
|
657
|
+
const rows = workspaceRoots.flatMap(workspace => readTaskEpisodesForWorkspace(workspace));
|
|
658
|
+
return buildAtrisActionSignalFromRows(rows);
|
|
659
|
+
}
|
|
660
|
+
|
|
424
661
|
function runSqliteJsonOptional(dbPath, sql) {
|
|
425
662
|
if (!dbPath || !fs.existsSync(dbPath)) return [];
|
|
426
663
|
const result = spawnSync('sqlite3', ['-readonly', '-json', dbPath, sql], { encoding: 'utf8' });
|
|
@@ -682,6 +919,7 @@ function buildCareerXpProjection(receipts, workspace, integrity = {}) {
|
|
|
682
919
|
percent: Math.round((currentLevelXp / LEVEL_XP) * 1000) / 10,
|
|
683
920
|
};
|
|
684
921
|
const latest = latestReceipt(accepted);
|
|
922
|
+
const localActivity = buildLocalAssistantActivity(workspace, totalXp);
|
|
685
923
|
|
|
686
924
|
return {
|
|
687
925
|
schema: 'atris.career_xp_projection.v1',
|
|
@@ -707,6 +945,8 @@ function buildCareerXpProjection(receipts, workspace, integrity = {}) {
|
|
|
707
945
|
contribution_graph: buildAgentXpContributionGraph(accepted),
|
|
708
946
|
receipts_count: accepted.length,
|
|
709
947
|
sources: countBySource(accepted),
|
|
948
|
+
earning_model: EARNING_MODEL,
|
|
949
|
+
local_activity: localActivity,
|
|
710
950
|
latest_accepted_proof: latest ? {
|
|
711
951
|
label: receiptLabel(latest),
|
|
712
952
|
receipt_id: latest.receipt_id,
|
|
@@ -929,6 +1169,7 @@ function buildAllCareerXpProjection(projections, searchRoots = []) {
|
|
|
929
1169
|
integrity_status: projection?.integrity_status || projection?.integrity?.status || 'unknown',
|
|
930
1170
|
leaderboard_eligible: Boolean(projection?.leaderboard_eligible),
|
|
931
1171
|
latest_accepted_proof: projection?.latest_accepted_proof || null,
|
|
1172
|
+
local_activity: projection?.local_activity || null,
|
|
932
1173
|
ledger: projection?.ledger || null,
|
|
933
1174
|
};
|
|
934
1175
|
}).sort((a, b) => {
|
|
@@ -960,6 +1201,17 @@ function buildAllCareerXpProjection(projections, searchRoots = []) {
|
|
|
960
1201
|
const contributionGraph = combineAgentXpContributionGraphs(
|
|
961
1202
|
verified.map(projection => projection.contribution_graph),
|
|
962
1203
|
);
|
|
1204
|
+
const activityProviders = new Set();
|
|
1205
|
+
let rawActivitySignals = 0;
|
|
1206
|
+
let contextAgentXp = 0;
|
|
1207
|
+
for (const projection of verified) {
|
|
1208
|
+
const activity = projection.local_activity || {};
|
|
1209
|
+
rawActivitySignals += asNumber(activity.raw_signal_count);
|
|
1210
|
+
contextAgentXp += asNumber(activity.context_agent_xp);
|
|
1211
|
+
for (const provider of activity.detected_providers || []) {
|
|
1212
|
+
activityProviders.add(provider);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
963
1215
|
|
|
964
1216
|
return {
|
|
965
1217
|
schema: 'atris.career_xp_profile.v1',
|
|
@@ -985,8 +1237,19 @@ function buildAllCareerXpProjection(projections, searchRoots = []) {
|
|
|
985
1237
|
},
|
|
986
1238
|
contribution_graph: contributionGraph,
|
|
987
1239
|
receipts_count: verified.reduce((sum, projection) => sum + asNumber(projection.receipts_count), 0),
|
|
1240
|
+
earning_model: EARNING_MODEL,
|
|
1241
|
+
local_activity: {
|
|
1242
|
+
schema: 'atris.agentxp_local_activity_summary.v1',
|
|
1243
|
+
public_leaderboard: false,
|
|
1244
|
+
detected_providers: Array.from(activityProviders).sort(),
|
|
1245
|
+
raw_signal_count: rawActivitySignals,
|
|
1246
|
+
context_agent_xp: Math.round(contextAgentXp * 100) / 100,
|
|
1247
|
+
included_in_total_agent_xp: false,
|
|
1248
|
+
note: 'Aggregated local assistant activity is context only; verified receipts define total AgentXP.',
|
|
1249
|
+
},
|
|
988
1250
|
latest_accepted_proof: latest,
|
|
989
1251
|
workspaces,
|
|
1252
|
+
integrity_status: warnings.length ? 'warnings' : 'verified',
|
|
990
1253
|
integrity: {
|
|
991
1254
|
status: warnings.length ? 'warnings' : 'verified',
|
|
992
1255
|
warnings,
|
|
@@ -1408,6 +1671,13 @@ function renderContributionGraph(graph) {
|
|
|
1408
1671
|
console.log('Legend: blank none | . started | : solid | * heavy | # breakout');
|
|
1409
1672
|
}
|
|
1410
1673
|
|
|
1674
|
+
function renderLocalActivity(activity) {
|
|
1675
|
+
if (!activity || !Array.isArray(activity.detected_providers) || !activity.detected_providers.length) return;
|
|
1676
|
+
console.log(
|
|
1677
|
+
`Local activity: ${activity.detected_providers.join(', ')} | context ${formatNumber(activity.context_agent_xp)} | not public ${AGENT_XP_LABEL}`
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1411
1681
|
function loadLocalPayload(args) {
|
|
1412
1682
|
const workspace = path.resolve(readFlag(args, '--workspace', process.cwd()));
|
|
1413
1683
|
const operator = readFlag(
|
|
@@ -1470,18 +1740,54 @@ function projectionWorkspaceSummaries(projection) {
|
|
|
1470
1740
|
}];
|
|
1471
1741
|
}
|
|
1472
1742
|
|
|
1743
|
+
function credentialHandle(credentials) {
|
|
1744
|
+
return slugify(
|
|
1745
|
+
credentials?.username
|
|
1746
|
+
|| credentials?.handle
|
|
1747
|
+
|| credentials?.display_name
|
|
1748
|
+
|| credentials?.name
|
|
1749
|
+
|| profileNameFromEmail(credentials?.email)
|
|
1750
|
+
|| credentials?.user_id
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
function activeAccountHandle() {
|
|
1755
|
+
const envPlayer = slugify(process.env.ATRIS_PLAYER || process.env.ATRIS_USERNAME);
|
|
1756
|
+
if (envPlayer) return envPlayer;
|
|
1757
|
+
|
|
1758
|
+
const envProfile = slugify(process.env.ATRIS_PROFILE);
|
|
1759
|
+
if (envProfile) return envProfile;
|
|
1760
|
+
|
|
1761
|
+
try {
|
|
1762
|
+
const sessionProfile = slugify(getSessionProfile());
|
|
1763
|
+
if (sessionProfile) return sessionProfile;
|
|
1764
|
+
} catch {}
|
|
1765
|
+
|
|
1766
|
+
try {
|
|
1767
|
+
const credentials = loadCredentials();
|
|
1768
|
+
const handle = credentialHandle(credentials);
|
|
1769
|
+
if (handle) return handle;
|
|
1770
|
+
} catch {}
|
|
1771
|
+
|
|
1772
|
+
return null;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
function projectionHandle(projection) {
|
|
1776
|
+
return slugify(
|
|
1777
|
+
projection?.operator
|
|
1778
|
+
|| projection?.latest_accepted_proof?.actor
|
|
1779
|
+
|| projection?.latest_accepted_proof?.assignee
|
|
1780
|
+
|| projection?.latest_accepted_proof?.assigned_to
|
|
1781
|
+
);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1473
1784
|
function syncPlayer(args, projection) {
|
|
1474
1785
|
const explicit = readFirstFlag(args, ['--as', '--player', '--user', '--operator'], null);
|
|
1475
|
-
return slugify(
|
|
1476
|
-
|
|
1477
|
-
||
|
|
1478
|
-
|| process.env.
|
|
1479
|
-
||
|
|
1480
|
-
|| process.env.USER
|
|
1481
|
-
|| os.userInfo().username
|
|
1482
|
-
|| projection?.operator
|
|
1483
|
-
|| 'player'
|
|
1484
|
-
) || 'player';
|
|
1786
|
+
return slugify(explicit)
|
|
1787
|
+
|| activeAccountHandle()
|
|
1788
|
+
|| projectionHandle(projection)
|
|
1789
|
+
|| slugify(process.env.USER || os.userInfo().username)
|
|
1790
|
+
|| 'player';
|
|
1485
1791
|
}
|
|
1486
1792
|
|
|
1487
1793
|
function buildAgentXpSyncPacket(args = []) {
|
|
@@ -1532,11 +1838,28 @@ function buildAgentXpSyncPacket(args = []) {
|
|
|
1532
1838
|
trust_rule: 'Only verified local ledgers are uploaded; raw proof and paths stay local.',
|
|
1533
1839
|
},
|
|
1534
1840
|
local_evidence: {
|
|
1841
|
+
schema: 'atris.agentxp_local_evidence.v1',
|
|
1842
|
+
workspace_root_hash: workspaceRootHash,
|
|
1535
1843
|
workspaces,
|
|
1536
1844
|
verified_workspace_count: asNumber(projection.verified_workspace_count, verifiedProjection(projection) ? 1 : 0),
|
|
1537
1845
|
receipts_count: receiptsCount,
|
|
1538
1846
|
integrity_status: projection.integrity?.status || projection.integrity_status || 'unknown',
|
|
1539
1847
|
ledger_head_hash: projection.integrity?.head_hash || null,
|
|
1848
|
+
local_activity: {
|
|
1849
|
+
schema: projection.local_activity?.schema || 'atris.agentxp_local_assistant_activity.v1',
|
|
1850
|
+
detected_providers: projection.local_activity?.detected_providers || [],
|
|
1851
|
+
provider_count: asNumber(projection.local_activity?.provider_count, (projection.local_activity?.detected_providers || []).length),
|
|
1852
|
+
raw_signal_count: asNumber(projection.local_activity?.raw_signal_count),
|
|
1853
|
+
context_agent_xp: asNumber(projection.local_activity?.context_agent_xp),
|
|
1854
|
+
context_weight: asNumber(projection.local_activity?.context_weight, 0.05),
|
|
1855
|
+
cap_ratio_to_accepted_task_xp: asNumber(projection.local_activity?.cap_ratio_to_accepted_task_xp, 0.1),
|
|
1856
|
+
cap_agent_xp: asNumber(projection.local_activity?.cap_agent_xp),
|
|
1857
|
+
accepted_task_agent_xp: asNumber(projection.local_activity?.accepted_task_agent_xp, totalXp),
|
|
1858
|
+
included_in_total_agent_xp: false,
|
|
1859
|
+
public_leaderboard: false,
|
|
1860
|
+
role: 'context_only',
|
|
1861
|
+
},
|
|
1862
|
+
atris_actions: buildAtrisActionSignal(projection),
|
|
1540
1863
|
},
|
|
1541
1864
|
gm_projection: {
|
|
1542
1865
|
schema: 'atris.gm_xp_projection.v1',
|
|
@@ -1583,7 +1906,10 @@ async function syncAgentXp(args = []) {
|
|
|
1583
1906
|
} else {
|
|
1584
1907
|
const ensured = await ensureValidCredentials(apiRequestJson);
|
|
1585
1908
|
if (ensured.error) {
|
|
1586
|
-
throw new Error(
|
|
1909
|
+
throw new Error(
|
|
1910
|
+
`Missing sync auth. Run atris login, then retry atris xp sync. `
|
|
1911
|
+
+ `Guided demos can pass --token <owner-provided-token>${ensured.detail ? ` (${ensured.detail})` : ''}.`
|
|
1912
|
+
);
|
|
1587
1913
|
}
|
|
1588
1914
|
options.token = ensured.credentials.token;
|
|
1589
1915
|
}
|
|
@@ -1609,7 +1935,8 @@ function renderSync(payload) {
|
|
|
1609
1935
|
console.log(`Player ${payload.player || entry.username || 'player'} | AgentXP ${formatNumber(entry.agent_xp)} | receipts ${formatNumber(entry.verified_receipts)}`);
|
|
1610
1936
|
if (payload.dry_run) {
|
|
1611
1937
|
console.log(`Packet ${payload.packet?.packet_hash || 'unhashed'} ready; no network upload ran.`);
|
|
1612
|
-
console.log('Run
|
|
1938
|
+
console.log('Run atris login, then atris xp sync --local to publish to the hosted leaderboard.');
|
|
1939
|
+
console.log('Guided demos can pass --token <owner-provided-token>.');
|
|
1613
1940
|
console.log(`Leaderboard: ${AGENTXP_LEADERBOARD_URL}`);
|
|
1614
1941
|
return;
|
|
1615
1942
|
}
|
|
@@ -1673,6 +2000,7 @@ function render(payload) {
|
|
|
1673
2000
|
} else {
|
|
1674
2001
|
console.log('Latest proof: none accepted yet');
|
|
1675
2002
|
}
|
|
2003
|
+
renderLocalActivity(payload.local_activity);
|
|
1676
2004
|
const integrity = payload.integrity || {};
|
|
1677
2005
|
console.log(`Integrity: ${integrity.status || 'unknown'} (${integrity.local_trust || 'local'})`);
|
|
1678
2006
|
for (const warning of integrity.warnings || []) {
|
|
@@ -1694,6 +2022,7 @@ function render(payload) {
|
|
|
1694
2022
|
} else {
|
|
1695
2023
|
console.log('Latest proof: none accepted yet');
|
|
1696
2024
|
}
|
|
2025
|
+
renderLocalActivity(payload.local_activity);
|
|
1697
2026
|
console.log(`Ledger: ${payload.ledger?.projection_path || CAREER_XP_PROJECTION_FILE}`);
|
|
1698
2027
|
return;
|
|
1699
2028
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function getAtrisPackageVersion() {
|
|
5
|
+
try {
|
|
6
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
7
|
+
return pkg.version || null;
|
|
8
|
+
} catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function writeRuntimeReceipt(workspaceRoot, fields = {}) {
|
|
14
|
+
const stateDir = path.join(workspaceRoot, '.atris', 'state');
|
|
15
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
16
|
+
const receipt = {
|
|
17
|
+
schema: 'atris.runtime.v1',
|
|
18
|
+
scope: fields.scope || 'local',
|
|
19
|
+
boundary: fields.boundary || 'manual',
|
|
20
|
+
atris_version: fields.atris_version || getAtrisPackageVersion(),
|
|
21
|
+
install_status: fields.install_status || 'recorded',
|
|
22
|
+
sync_status: fields.sync_status || 'recorded',
|
|
23
|
+
updated_at: fields.updated_at || new Date().toISOString(),
|
|
24
|
+
...fields,
|
|
25
|
+
};
|
|
26
|
+
const filePath = path.join(stateDir, 'runtime.json');
|
|
27
|
+
fs.writeFileSync(filePath, `${JSON.stringify(receipt, null, 2)}\n`, 'utf8');
|
|
28
|
+
return { filePath, receipt };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function shellQuote(value) {
|
|
32
|
+
return `'${String(value || '').replace(/'/g, `'\\''`)}'`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildRemoteAtrisBootstrapCommand(options = {}) {
|
|
36
|
+
const boundary = options.boundary || 'computer-wake';
|
|
37
|
+
const businessSlug = options.businessSlug || '';
|
|
38
|
+
const workspaceId = options.workspaceId || '';
|
|
39
|
+
const businessId = options.businessId || '';
|
|
40
|
+
|
|
41
|
+
return [
|
|
42
|
+
'set +e',
|
|
43
|
+
'WORKSPACE="/workspace"',
|
|
44
|
+
'STATE_DIR="$WORKSPACE/.atris/state"',
|
|
45
|
+
'mkdir -p "$STATE_DIR"',
|
|
46
|
+
'RUNTIME_FILE="$STATE_DIR/runtime.json"',
|
|
47
|
+
'sanitize() { printf "%s" "$1" | tr "\\n\\r" " " | sed "s/[\\\\\\\"]/ /g" | cut -c1-160; }',
|
|
48
|
+
'version_text() { if command -v atris >/dev/null 2>&1; then atris version 2>/dev/null || atris --version 2>/dev/null || true; fi; }',
|
|
49
|
+
'BEFORE="$(sanitize "$(version_text)")"',
|
|
50
|
+
'[ -n "$BEFORE" ] || BEFORE="missing"',
|
|
51
|
+
'INSTALL_STATUS="skipped"',
|
|
52
|
+
'SYNC_STATUS="skipped"',
|
|
53
|
+
'RECOVERY_COMMAND=""',
|
|
54
|
+
'if [ "${ATRIS_SKIP_RUNTIME_BOOTSTRAP:-}" = "1" ]; then',
|
|
55
|
+
' INSTALL_STATUS="skipped_env"',
|
|
56
|
+
'elif command -v npm >/dev/null 2>&1; then',
|
|
57
|
+
' if npm install -g atris@latest >/tmp/atris-runtime-bootstrap-npm.log 2>&1; then',
|
|
58
|
+
' INSTALL_STATUS="installed_latest"',
|
|
59
|
+
' else',
|
|
60
|
+
' INSTALL_STATUS="failed"',
|
|
61
|
+
' RECOVERY_COMMAND="npm install -g atris@latest"',
|
|
62
|
+
' fi',
|
|
63
|
+
'else',
|
|
64
|
+
' INSTALL_STATUS="failed_no_npm"',
|
|
65
|
+
' RECOVERY_COMMAND="install node/npm, then npm install -g atris@latest"',
|
|
66
|
+
'fi',
|
|
67
|
+
'AFTER="$(sanitize "$(version_text)")"',
|
|
68
|
+
'[ -n "$AFTER" ] || AFTER="missing"',
|
|
69
|
+
'if command -v atris >/dev/null 2>&1 && [ -d "$WORKSPACE/atris" ]; then',
|
|
70
|
+
' if (cd "$WORKSPACE" && ATRIS_SKIP_UPDATE_CHECK=1 atris update >/tmp/atris-runtime-bootstrap-sync.log 2>&1); then',
|
|
71
|
+
' SYNC_STATUS="synced"',
|
|
72
|
+
' else',
|
|
73
|
+
' SYNC_STATUS="failed"',
|
|
74
|
+
' fi',
|
|
75
|
+
'fi',
|
|
76
|
+
'UPDATED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"',
|
|
77
|
+
`BOUNDARY=${shellQuote(boundary)}`,
|
|
78
|
+
`BUSINESS_SLUG=${shellQuote(businessSlug)}`,
|
|
79
|
+
`BUSINESS_ID=${shellQuote(businessId)}`,
|
|
80
|
+
`WORKSPACE_ID=${shellQuote(workspaceId)}`,
|
|
81
|
+
'cat > "$RUNTIME_FILE" <<JSON',
|
|
82
|
+
'{',
|
|
83
|
+
' "schema": "atris.runtime.v1",',
|
|
84
|
+
' "scope": "remote-business-computer",',
|
|
85
|
+
' "boundary": "$BOUNDARY",',
|
|
86
|
+
' "business_slug": "$BUSINESS_SLUG",',
|
|
87
|
+
' "business_id": "$BUSINESS_ID",',
|
|
88
|
+
' "workspace_id": "$WORKSPACE_ID",',
|
|
89
|
+
' "atris_before": "$BEFORE",',
|
|
90
|
+
' "atris_after": "$AFTER",',
|
|
91
|
+
' "install_status": "$INSTALL_STATUS",',
|
|
92
|
+
' "sync_status": "$SYNC_STATUS",',
|
|
93
|
+
' "recovery_command": "$RECOVERY_COMMAND",',
|
|
94
|
+
' "updated_at": "$UPDATED_AT"',
|
|
95
|
+
'}',
|
|
96
|
+
'JSON',
|
|
97
|
+
'echo "atris_runtime_bootstrap install=$INSTALL_STATUS version=$AFTER sync=$SYNC_STATUS receipt=.atris/state/runtime.json"',
|
|
98
|
+
'if [ -n "$RECOVERY_COMMAND" ]; then echo "recovery=$RECOVERY_COMMAND"; fi',
|
|
99
|
+
'exit 0',
|
|
100
|
+
].join('\n');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = {
|
|
104
|
+
buildRemoteAtrisBootstrapCommand,
|
|
105
|
+
getAtrisPackageVersion,
|
|
106
|
+
writeRuntimeReceipt,
|
|
107
|
+
};
|