atris 3.15.23 → 3.15.30
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 +53 -0
- package/ax +1083 -0
- package/commands/aeo.js +377 -13
- package/commands/gm.js +25 -9
- package/commands/play.js +41 -9
- package/commands/sync.js +9 -4
- package/commands/xp.js +224 -1
- package/package.json +5 -2
package/commands/xp.js
CHANGED
|
@@ -17,6 +17,7 @@ const CAREER_XP_SESSIONS_DIR = path.join('.atris', 'state', 'career_xp_sessions'
|
|
|
17
17
|
const TASK_PROJECTION_FILE = path.join('.atris', 'state', 'tasks.projection.json');
|
|
18
18
|
const CODEX_STATE_FILE = path.join(os.homedir(), '.codex', 'state_5.sqlite');
|
|
19
19
|
const AGENT_XP_LABEL = 'AgentXP';
|
|
20
|
+
const AGENTXP_LEADERBOARD_URL = 'https://api.atris.ai/api/agentxp/leaderboard';
|
|
20
21
|
const LEVEL_XP = 1000;
|
|
21
22
|
const RECEIPT_CHAIN_VERSION = 'atris.career_xp_receipt_chain.v1';
|
|
22
23
|
const XP_STATE_FILES = new Set([
|
|
@@ -37,14 +38,16 @@ const SEARCH_EXCLUDED_DIRS = new Set([
|
|
|
37
38
|
const DEFAULT_SEARCH_DEPTH = 6;
|
|
38
39
|
|
|
39
40
|
function showHelp() {
|
|
40
|
-
console.log('Usage: atris xp [card|status|collect|session] [--json] [--workspace <path>] [--all] [--root <path>]');
|
|
41
|
+
console.log('Usage: atris xp [card|status|collect|session|sync] [--json] [--workspace <path>] [--all] [--root <path>]');
|
|
41
42
|
console.log(' atris xp session [--since today|tonight|YYYY-MM-DD] [--until <time>] [--mission <text>] [--thread <id>] [--no-write]');
|
|
43
|
+
console.log(' atris xp sync [--as <player>] [--local|--all] [--token <token>|logged-in] [--dry-run] [--json]');
|
|
42
44
|
console.log(' atris xp [--json] [--local] [--workspace <path>] [--operator <name>]');
|
|
43
45
|
console.log('');
|
|
44
46
|
console.log('Show your AgentXP graph for the active Atris account.');
|
|
45
47
|
console.log('Use status to show account-level AgentXP across verified local ledgers.');
|
|
46
48
|
console.log('Use collect or status --local to project accepted task proof in the current workspace.');
|
|
47
49
|
console.log('Use session to encapsulate the current work window into a local XP capsule.');
|
|
50
|
+
console.log('Use sync to upload a path-private AgentXP packet to the hosted leaderboard.');
|
|
48
51
|
console.log('Use status --all to explicitly aggregate verified local XP ledgers across workspaces.');
|
|
49
52
|
console.log('Use --local to render from proof receipts in the current workspace.');
|
|
50
53
|
}
|
|
@@ -187,6 +190,14 @@ function readFlag(args, name, fallback = null) {
|
|
|
187
190
|
return fallback;
|
|
188
191
|
}
|
|
189
192
|
|
|
193
|
+
function readFirstFlag(args, names, fallback = null) {
|
|
194
|
+
for (const name of names) {
|
|
195
|
+
const value = readFlag(args, name, null);
|
|
196
|
+
if (value !== null && value !== undefined && value !== '') return value;
|
|
197
|
+
}
|
|
198
|
+
return fallback;
|
|
199
|
+
}
|
|
200
|
+
|
|
190
201
|
function readFlagValues(args, names) {
|
|
191
202
|
const wanted = Array.isArray(names) ? names : [names];
|
|
192
203
|
const values = [];
|
|
@@ -312,6 +323,15 @@ function hashPayload(value) {
|
|
|
312
323
|
return sha256(canonicalJson(value));
|
|
313
324
|
}
|
|
314
325
|
|
|
326
|
+
function slugify(value) {
|
|
327
|
+
return String(value || '')
|
|
328
|
+
.trim()
|
|
329
|
+
.toLowerCase()
|
|
330
|
+
.replace(/@.*$/, '')
|
|
331
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
332
|
+
.replace(/^-+|-+$/g, '');
|
|
333
|
+
}
|
|
334
|
+
|
|
315
335
|
function readJsonFile(filePath, fallback = null) {
|
|
316
336
|
if (!fs.existsSync(filePath)) return fallback;
|
|
317
337
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
@@ -1418,7 +1438,191 @@ function loadLocalPayload(args) {
|
|
|
1418
1438
|
return normalizeLocalScore(JSON.parse(result.stdout), workspace);
|
|
1419
1439
|
}
|
|
1420
1440
|
|
|
1441
|
+
function publicAgentXp(value) {
|
|
1442
|
+
return Math.max(0, Math.min(99, asNumber(value)));
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
function verifiedProjection(projection) {
|
|
1446
|
+
return projection?.integrity_status === 'verified'
|
|
1447
|
+
&& projection?.integrity?.status === 'verified';
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
function projectionWorkspaceSummaries(projection) {
|
|
1451
|
+
if (Array.isArray(projection?.workspaces)) {
|
|
1452
|
+
return projection.workspaces.map(workspace => ({
|
|
1453
|
+
name: workspace.name || workspaceName(workspace.workspace_root || 'workspace'),
|
|
1454
|
+
workspace_root_hash: workspace.workspace_root ? sha256(path.resolve(workspace.workspace_root)) : null,
|
|
1455
|
+
included: Boolean(workspace.included),
|
|
1456
|
+
agent_xp: asNumber(workspace.total_xp),
|
|
1457
|
+
receipts_count: asNumber(workspace.receipts_count),
|
|
1458
|
+
integrity_status: workspace.integrity_status || 'unknown',
|
|
1459
|
+
}));
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
const workspaceRoot = projection?.workspace_root || path.resolve(process.cwd());
|
|
1463
|
+
return [{
|
|
1464
|
+
name: workspaceName(workspaceRoot),
|
|
1465
|
+
workspace_root_hash: sha256(path.resolve(workspaceRoot)),
|
|
1466
|
+
included: verifiedProjection(projection),
|
|
1467
|
+
agent_xp: asNumber(projection?.total_agent_xp ?? projection?.total_xp),
|
|
1468
|
+
receipts_count: asNumber(projection?.receipts_count),
|
|
1469
|
+
integrity_status: projection?.integrity_status || projection?.integrity?.status || 'unknown',
|
|
1470
|
+
}];
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function syncPlayer(args, projection) {
|
|
1474
|
+
const explicit = readFirstFlag(args, ['--as', '--player', '--user', '--operator'], null);
|
|
1475
|
+
return slugify(
|
|
1476
|
+
explicit
|
|
1477
|
+
|| process.env.ATRIS_PLAYER
|
|
1478
|
+
|| process.env.ATRIS_USERNAME
|
|
1479
|
+
|| process.env.ATRIS_PROFILE
|
|
1480
|
+
|| process.env.USER
|
|
1481
|
+
|| os.userInfo().username
|
|
1482
|
+
|| projection?.operator
|
|
1483
|
+
|| 'player'
|
|
1484
|
+
) || 'player';
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
function buildAgentXpSyncPacket(args = []) {
|
|
1488
|
+
const localMode = hasFlag(args, '--local') || hasFlag(args, '--workspace') || hasFlag(args, '--operator');
|
|
1489
|
+
const projectionArgs = args.filter(arg => !['--dry-run', '--no-post', '--packet'].includes(arg));
|
|
1490
|
+
const projection = hasFlag(args, '--all') || !localMode
|
|
1491
|
+
? collectAllLocalXpProjection(projectionArgs)
|
|
1492
|
+
: collectLocalXpProjection(projectionArgs);
|
|
1493
|
+
const player = syncPlayer(args, projection);
|
|
1494
|
+
const workspaces = projectionWorkspaceSummaries(projection);
|
|
1495
|
+
const totalXp = asNumber(projection.total_agent_xp ?? projection.agent_xp ?? projection.total_xp ?? projection.career_xp);
|
|
1496
|
+
const receiptsCount = asNumber(projection.receipts_count);
|
|
1497
|
+
const eligible = verifiedProjection(projection) && receiptsCount > 0 && totalXp > 0;
|
|
1498
|
+
const publicXp = publicAgentXp(totalXp);
|
|
1499
|
+
const entry = {
|
|
1500
|
+
user_id: player,
|
|
1501
|
+
username: player,
|
|
1502
|
+
agent_xp: publicXp,
|
|
1503
|
+
career_xp: publicXp,
|
|
1504
|
+
current_form: publicXp,
|
|
1505
|
+
ovr: publicXp,
|
|
1506
|
+
level: Math.max(1, asNumber(projection.level, 1)),
|
|
1507
|
+
verified_receipts: receiptsCount,
|
|
1508
|
+
reviewed_tasks: receiptsCount,
|
|
1509
|
+
recent_verified_receipts: receiptsCount,
|
|
1510
|
+
recent_reviewed_tasks: receiptsCount,
|
|
1511
|
+
leaderboard_eligible: eligible,
|
|
1512
|
+
integrity_status: eligible ? 'trusted' : (projection.integrity_status || projection.integrity?.status || 'unknown'),
|
|
1513
|
+
lock_reason: eligible ? null : 'not_enough_trusted_proof',
|
|
1514
|
+
public_adjustment: null,
|
|
1515
|
+
next_move: eligible ? 'Play the next proof-backed AgentXP mission.' : 'Complete one proof-backed AgentXP rep.',
|
|
1516
|
+
};
|
|
1517
|
+
const packet = {
|
|
1518
|
+
schema: 'atris.agentxp_sync_packet.v1',
|
|
1519
|
+
generated_at: new Date().toISOString(),
|
|
1520
|
+
workspace_root_hash: sha256(workspaces.map(item => item.workspace_root_hash || item.name).sort().join(':')),
|
|
1521
|
+
computer: projection.workspace_name || workspaces[0]?.name || 'local',
|
|
1522
|
+
operator: player,
|
|
1523
|
+
privacy: {
|
|
1524
|
+
raw_proofs_included: false,
|
|
1525
|
+
raw_receipts_included: false,
|
|
1526
|
+
contains_absolute_workspace_root: false,
|
|
1527
|
+
public_user_board_omits_lifetime_xp: true,
|
|
1528
|
+
},
|
|
1529
|
+
sync_contract: {
|
|
1530
|
+
anti_bs_rule: 'No accepted proof-backed task episodes means no AgentXP leaderboard movement.',
|
|
1531
|
+
trust_rule: 'Only verified local ledgers are uploaded; raw proof and paths stay local.',
|
|
1532
|
+
},
|
|
1533
|
+
local_evidence: {
|
|
1534
|
+
workspaces,
|
|
1535
|
+
verified_workspace_count: asNumber(projection.verified_workspace_count, verifiedProjection(projection) ? 1 : 0),
|
|
1536
|
+
receipts_count: receiptsCount,
|
|
1537
|
+
integrity_status: projection.integrity?.status || projection.integrity_status || 'unknown',
|
|
1538
|
+
ledger_head_hash: projection.integrity?.head_hash || null,
|
|
1539
|
+
},
|
|
1540
|
+
user_leaderboard: {
|
|
1541
|
+
schema: 'atris.agentxp_user_leaderboard.v1',
|
|
1542
|
+
score_name: AGENT_XP_LABEL,
|
|
1543
|
+
entries: [entry],
|
|
1544
|
+
},
|
|
1545
|
+
};
|
|
1546
|
+
packet.packet_hash = hashPayload(packet);
|
|
1547
|
+
return {
|
|
1548
|
+
schema: 'atris.agentxp_sync_preview.v1',
|
|
1549
|
+
generated_at: new Date().toISOString(),
|
|
1550
|
+
dry_run: true,
|
|
1551
|
+
player,
|
|
1552
|
+
entry,
|
|
1553
|
+
packet,
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
async function syncAgentXp(args = []) {
|
|
1558
|
+
const preview = buildAgentXpSyncPacket(args);
|
|
1559
|
+
const dryRun = hasFlag(args, '--dry-run') || hasFlag(args, '--no-post') || hasFlag(args, '--packet');
|
|
1560
|
+
if (dryRun) return preview;
|
|
1561
|
+
|
|
1562
|
+
const token = readFlag(args, '--token', process.env.ATRIS_AGENTXP_SYNC_TOKEN || process.env.AGENTXP_SYNC_TOKEN || '');
|
|
1563
|
+
const options = {
|
|
1564
|
+
method: 'POST',
|
|
1565
|
+
body: preview.packet,
|
|
1566
|
+
retries: 0,
|
|
1567
|
+
};
|
|
1568
|
+
if (token) {
|
|
1569
|
+
options.headers = { 'X-AgentXP-Sync-Token': token };
|
|
1570
|
+
} else {
|
|
1571
|
+
const ensured = await ensureValidCredentials(apiRequestJson);
|
|
1572
|
+
if (ensured.error) {
|
|
1573
|
+
throw new Error(`Missing sync auth. Run atris login, or set ATRIS_AGENTXP_SYNC_TOKEN${ensured.detail ? ` (${ensured.detail})` : ''}.`);
|
|
1574
|
+
}
|
|
1575
|
+
options.token = ensured.credentials.token;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
const response = await apiRequestJson('/agentxp/leaderboard/sync', options);
|
|
1579
|
+
if (!response.ok) {
|
|
1580
|
+
throw new Error(`AgentXP sync failed: ${response.error || response.status}`);
|
|
1581
|
+
}
|
|
1582
|
+
return {
|
|
1583
|
+
schema: 'atris.agentxp_sync_result.v1',
|
|
1584
|
+
generated_at: new Date().toISOString(),
|
|
1585
|
+
dry_run: false,
|
|
1586
|
+
player: preview.player,
|
|
1587
|
+
entry: preview.entry,
|
|
1588
|
+
packet_hash: preview.packet.packet_hash,
|
|
1589
|
+
server: response.data || {},
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function renderSync(payload) {
|
|
1594
|
+
const entry = payload.entry || {};
|
|
1595
|
+
console.log('AgentXP Sync');
|
|
1596
|
+
console.log(`Player ${payload.player || entry.username || 'player'} | AgentXP ${formatNumber(entry.agent_xp)} | receipts ${formatNumber(entry.verified_receipts)}`);
|
|
1597
|
+
if (payload.dry_run) {
|
|
1598
|
+
console.log(`Packet ${payload.packet?.packet_hash || 'unhashed'} ready; no network upload ran.`);
|
|
1599
|
+
console.log('Run with ATRIS_AGENTXP_SYNC_TOKEN set to publish to the hosted leaderboard.');
|
|
1600
|
+
console.log(`Leaderboard: ${AGENTXP_LEADERBOARD_URL}`);
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
const server = payload.server || {};
|
|
1604
|
+
console.log(`Uploaded: accepted ${formatNumber(server.accepted_count)} | stored ${formatNumber(server.stored_count)}`);
|
|
1605
|
+
const acceptedUsernames = Array.isArray(server.accepted_usernames)
|
|
1606
|
+
? server.accepted_usernames.map(value => String(value || '').trim()).filter(Boolean)
|
|
1607
|
+
: [];
|
|
1608
|
+
if (acceptedUsernames.length) {
|
|
1609
|
+
console.log(`Public identity: ${acceptedUsernames.join(', ')}`);
|
|
1610
|
+
}
|
|
1611
|
+
const player = String(payload.player || entry.username || '').trim().toLowerCase();
|
|
1612
|
+
const accepted = acceptedUsernames.map(value => value.toLowerCase());
|
|
1613
|
+
if (server.mapped_to_authenticated_user === true && player && !accepted.includes(player)) {
|
|
1614
|
+
console.log('Login auth mapped this sync to your Atris account.');
|
|
1615
|
+
}
|
|
1616
|
+
console.log(`Packet ${payload.packet_hash}`);
|
|
1617
|
+
console.log(`Leaderboard: ${AGENTXP_LEADERBOARD_URL}`);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1421
1620
|
function render(payload) {
|
|
1621
|
+
if (payload.schema === 'atris.agentxp_sync_preview.v1' || payload.schema === 'atris.agentxp_sync_result.v1') {
|
|
1622
|
+
renderSync(payload);
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1422
1626
|
if (payload.schema === 'atris.career_xp_session_capsule.v1') {
|
|
1423
1627
|
const xp = payload.xp || {};
|
|
1424
1628
|
const tasks = payload.tasks || {};
|
|
@@ -1508,6 +1712,23 @@ async function xpCommand(...args) {
|
|
|
1508
1712
|
}
|
|
1509
1713
|
|
|
1510
1714
|
const subcommand = args[0] && !args[0].startsWith('--') ? args[0] : null;
|
|
1715
|
+
if (subcommand === 'sync') {
|
|
1716
|
+
const commandArgs = args.slice(1);
|
|
1717
|
+
let payload;
|
|
1718
|
+
try {
|
|
1719
|
+
payload = await syncAgentXp(commandArgs);
|
|
1720
|
+
} catch (error) {
|
|
1721
|
+
console.error(`Failed to sync AgentXP: ${error.message}`);
|
|
1722
|
+
process.exit(1);
|
|
1723
|
+
}
|
|
1724
|
+
if (args.includes('--json')) {
|
|
1725
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
render(payload);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1511
1732
|
if (subcommand === 'session') {
|
|
1512
1733
|
const commandArgs = args.slice(1);
|
|
1513
1734
|
let payload;
|
|
@@ -1603,6 +1824,8 @@ module.exports = {
|
|
|
1603
1824
|
buildCareerXpSessionCapsule,
|
|
1604
1825
|
collectAllLocalXpProjection,
|
|
1605
1826
|
collectLocalXpProjection,
|
|
1827
|
+
buildAgentXpSyncPacket,
|
|
1828
|
+
syncAgentXp,
|
|
1606
1829
|
receiptFromTaskEpisode,
|
|
1607
1830
|
render,
|
|
1608
1831
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atris",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.30",
|
|
4
4
|
"main": "bin/atris.js",
|
|
5
5
|
"bin": {
|
|
6
|
-
"atris": "bin/atris.js"
|
|
6
|
+
"atris": "bin/atris.js",
|
|
7
|
+
"ax": "ax"
|
|
7
8
|
},
|
|
8
9
|
"files": [
|
|
10
|
+
"ax",
|
|
9
11
|
"bin/",
|
|
10
12
|
"cli/*.py",
|
|
11
13
|
"commands/",
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
],
|
|
57
59
|
"scripts": {
|
|
58
60
|
"test": "node --test",
|
|
61
|
+
"publish:release": "node scripts/publish-atris-release.js",
|
|
59
62
|
"prepare": "cp scripts/pre-commit .git/hooks/pre-commit 2>/dev/null && chmod +x .git/hooks/pre-commit || true"
|
|
60
63
|
},
|
|
61
64
|
"keywords": [
|