atris 3.15.56 → 3.15.57
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/bin/atris.js +1 -1
- package/commands/computer.js +45 -23
- package/commands/integrations.js +71 -5
- package/commands/skill.js +37 -6
- package/commands/xp.js +35 -0
- package/package.json +1 -1
package/bin/atris.js
CHANGED
|
@@ -1567,7 +1567,7 @@ if (command === 'init') {
|
|
|
1567
1567
|
searchJournal(keyword);
|
|
1568
1568
|
} else if (command === 'xp') {
|
|
1569
1569
|
require('../commands/xp').xpCommand(...process.argv.slice(3))
|
|
1570
|
-
.then(() => process.
|
|
1570
|
+
.then(() => { process.exitCode = 0; })
|
|
1571
1571
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1572
1572
|
} else if (command === 'play') {
|
|
1573
1573
|
require('../commands/play').playCommand(...process.argv.slice(3))
|
package/commands/computer.js
CHANGED
|
@@ -2550,34 +2550,56 @@ async function streamBusinessChatResult(token, ctx, executionId, rl = null, opti
|
|
|
2550
2550
|
|
|
2551
2551
|
errors = 0;
|
|
2552
2552
|
let done = false;
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
sawVisibleOutput
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2553
|
+
const emitEvents = (items, { showTools = true } = {}) => {
|
|
2554
|
+
let batchDone = false;
|
|
2555
|
+
for (const event of (items || [])) {
|
|
2556
|
+
if ((event.type === 'assistant_text' || event.type === 'text') && event.content) {
|
|
2557
|
+
sawVisibleOutput = true;
|
|
2558
|
+
process.stdout.write(event.content);
|
|
2559
|
+
} else if (event.type === 'result' && event.result && !sawVisibleOutput) {
|
|
2560
|
+
sawVisibleOutput = true;
|
|
2561
|
+
process.stdout.write(String(event.result));
|
|
2562
|
+
} else if (showTools && !options.quiet && event.type === 'tool_use' && event.tool) {
|
|
2563
|
+
const arg = event.input?.file_path || event.input?.path || event.input?.pattern || event.input?.command || '';
|
|
2564
|
+
if (arg) {
|
|
2565
|
+
console.log(`\n [${event.tool}] ${String(arg).slice(0, 120)}`);
|
|
2566
|
+
} else {
|
|
2567
|
+
console.log(`\n [${event.tool}]`);
|
|
2568
|
+
}
|
|
2569
|
+
} else if (event.type === 'error') {
|
|
2570
|
+
if (event.error) console.error(`\n${event.error}`);
|
|
2571
|
+
terminalStatus = 'error';
|
|
2572
|
+
batchDone = true;
|
|
2573
|
+
break;
|
|
2574
|
+
} else if (event.type === 'complete') {
|
|
2575
|
+
terminalStatus = 'completed';
|
|
2576
|
+
batchDone = true;
|
|
2577
|
+
break;
|
|
2567
2578
|
}
|
|
2568
|
-
} else if (event.type === 'error') {
|
|
2569
|
-
if (event.error) console.error(`\n${event.error}`);
|
|
2570
|
-
terminalStatus = 'error';
|
|
2571
|
-
done = true;
|
|
2572
|
-
break;
|
|
2573
|
-
} else if (event.type === 'complete') {
|
|
2574
|
-
terminalStatus = 'completed';
|
|
2575
|
-
done = true;
|
|
2576
|
-
break;
|
|
2577
2579
|
}
|
|
2580
|
+
return batchDone;
|
|
2581
|
+
};
|
|
2582
|
+
|
|
2583
|
+
const batch = events.data?.events || [];
|
|
2584
|
+
done = emitEvents(batch);
|
|
2585
|
+
const nextIndex = events.data?.next_index;
|
|
2586
|
+
if (Number.isInteger(nextIndex) && nextIndex >= fromIndex) {
|
|
2587
|
+
fromIndex = nextIndex;
|
|
2588
|
+
} else {
|
|
2589
|
+
fromIndex += batch.length;
|
|
2578
2590
|
}
|
|
2579
2591
|
|
|
2580
2592
|
if (done || ['completed', 'error', 'failed', 'cancelled'].includes(events.data?.status)) {
|
|
2593
|
+
if (!sawVisibleOutput && events.data?.status === 'completed') {
|
|
2594
|
+
const fullEvents = await apiRequestJson(
|
|
2595
|
+
`/business/${ctx.businessId}/chat/events?execution_id=${executionId}&workspace_id=${ctx.workspaceId}&from_index=0`,
|
|
2596
|
+
{ method: 'GET', token, timeoutMs: 60000 }
|
|
2597
|
+
);
|
|
2598
|
+
if (fullEvents.ok) {
|
|
2599
|
+
emitEvents(fullEvents.data?.events || [], { showTools: false });
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2581
2603
|
if (!process.stdout.write('\n')) {
|
|
2582
2604
|
// no-op: keep line handling stable
|
|
2583
2605
|
}
|
package/commands/integrations.js
CHANGED
|
@@ -614,6 +614,31 @@ function printImessageDoctor(result, json = false) {
|
|
|
614
614
|
}
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
+
function boundedImessageLimit(value) {
|
|
618
|
+
const parsed = Number(value || 20);
|
|
619
|
+
if (!Number.isFinite(parsed)) return 20;
|
|
620
|
+
return Math.max(1, Math.min(100, Math.trunc(parsed)));
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function printImessageRows(result, options = {}) {
|
|
624
|
+
if (options.json) {
|
|
625
|
+
const rows = String(result.stdout || '').trim();
|
|
626
|
+
let messages = [];
|
|
627
|
+
try {
|
|
628
|
+
messages = rows ? JSON.parse(rows) : [];
|
|
629
|
+
} catch {
|
|
630
|
+
messages = [];
|
|
631
|
+
}
|
|
632
|
+
console.log(JSON.stringify({
|
|
633
|
+
ok: result.status === 0,
|
|
634
|
+
count: Array.isArray(messages) ? messages.length : 0,
|
|
635
|
+
messages: Array.isArray(messages) ? messages : [],
|
|
636
|
+
}, null, 2));
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
console.log(String(result.stdout || '').trim() || 'No recent messages found.');
|
|
640
|
+
}
|
|
641
|
+
|
|
617
642
|
function imessageRecent(handle, options = {}) {
|
|
618
643
|
if (!handle) {
|
|
619
644
|
console.error('Usage: atris imessage recent <phone-or-email> [--limit 20]');
|
|
@@ -625,7 +650,7 @@ function imessageRecent(handle, options = {}) {
|
|
|
625
650
|
process.exit(1);
|
|
626
651
|
}
|
|
627
652
|
|
|
628
|
-
const limit =
|
|
653
|
+
const limit = boundedImessageLimit(options.limit);
|
|
629
654
|
const chatDb = path.join(os.homedir(), 'Library', 'Messages', 'chat.db');
|
|
630
655
|
const sql = `
|
|
631
656
|
SELECT datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS ts,
|
|
@@ -635,14 +660,44 @@ function imessageRecent(handle, options = {}) {
|
|
|
635
660
|
JOIN handle h ON h.rowid = m.handle_id
|
|
636
661
|
WHERE h.id = '${String(handle).replace(/'/g, "''")}'
|
|
637
662
|
ORDER BY m.date DESC
|
|
638
|
-
LIMIT ${
|
|
663
|
+
LIMIT ${limit};
|
|
639
664
|
`;
|
|
640
|
-
const
|
|
665
|
+
const sqliteArgs = options.json ? ['-json', '-readonly', chatDb, sql] : ['-readonly', chatDb, sql];
|
|
666
|
+
const result = spawnSync('sqlite3', sqliteArgs, { encoding: 'utf8' });
|
|
667
|
+
if (result.status !== 0) {
|
|
668
|
+
console.error(result.stderr || 'Failed to read Messages database.');
|
|
669
|
+
process.exit(1);
|
|
670
|
+
}
|
|
671
|
+
printImessageRows(result, options);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function imessageLatest(options = {}) {
|
|
675
|
+
const doctor = imessageDoctor();
|
|
676
|
+
if (!doctor.connected) {
|
|
677
|
+
printImessageDoctor(doctor, Boolean(options.json));
|
|
678
|
+
process.exit(1);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const limit = boundedImessageLimit(options.limit);
|
|
682
|
+
const chatDb = path.join(os.homedir(), 'Library', 'Messages', 'chat.db');
|
|
683
|
+
const sql = `
|
|
684
|
+
SELECT datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS ts,
|
|
685
|
+
CASE m.is_from_me WHEN 1 THEN 'me' ELSE COALESCE(h.id, 'unknown') END AS sender,
|
|
686
|
+
COALESCE(h.id, 'unknown') AS handle,
|
|
687
|
+
replace(replace(COALESCE(m.text,''), char(10), ' '), char(13), ' ') AS text
|
|
688
|
+
FROM message m
|
|
689
|
+
LEFT JOIN handle h ON h.rowid = m.handle_id
|
|
690
|
+
WHERE length(COALESCE(m.text,'')) > 0
|
|
691
|
+
ORDER BY m.date DESC
|
|
692
|
+
LIMIT ${limit};
|
|
693
|
+
`;
|
|
694
|
+
const sqliteArgs = options.json ? ['-json', '-readonly', chatDb, sql] : ['-readonly', chatDb, sql];
|
|
695
|
+
const result = spawnSync('sqlite3', sqliteArgs, { encoding: 'utf8' });
|
|
641
696
|
if (result.status !== 0) {
|
|
642
697
|
console.error(result.stderr || 'Failed to read Messages database.');
|
|
643
698
|
process.exit(1);
|
|
644
699
|
}
|
|
645
|
-
|
|
700
|
+
printImessageRows(result, options);
|
|
646
701
|
}
|
|
647
702
|
|
|
648
703
|
function escapeSqlString(value) {
|
|
@@ -1169,12 +1224,22 @@ async function imessageCommand(subcommand, ...args) {
|
|
|
1169
1224
|
break;
|
|
1170
1225
|
}
|
|
1171
1226
|
case 'recent': {
|
|
1172
|
-
const handle = args[0];
|
|
1173
1227
|
const limitFlag = args.findIndex((x) => x === '--limit');
|
|
1174
1228
|
const limit = limitFlag >= 0 ? args[limitFlag + 1] : 20;
|
|
1229
|
+
const handle = args.find((arg) => arg && !arg.startsWith('--') && arg !== String(limit));
|
|
1230
|
+
if (!handle) {
|
|
1231
|
+
imessageLatest({ limit, json: args.includes('--json') });
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1175
1234
|
imessageRecent(handle, { limit, json: args.includes('--json') });
|
|
1176
1235
|
break;
|
|
1177
1236
|
}
|
|
1237
|
+
case 'latest': {
|
|
1238
|
+
const limitFlag = args.findIndex((x) => x === '--limit');
|
|
1239
|
+
const limit = limitFlag >= 0 ? args[limitFlag + 1] : 20;
|
|
1240
|
+
imessageLatest({ limit, json: args.includes('--json') });
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1178
1243
|
case 'lookup': {
|
|
1179
1244
|
imessageLookup(args);
|
|
1180
1245
|
break;
|
|
@@ -1188,6 +1253,7 @@ async function imessageCommand(subcommand, ...args) {
|
|
|
1188
1253
|
console.log(' atris imessage doctor [--json] - Check local Messages access');
|
|
1189
1254
|
console.log(' atris imessage lookup --name <name> [--json] [--refresh]');
|
|
1190
1255
|
console.log(' atris imessage recent <handle> - Read recent local messages');
|
|
1256
|
+
console.log(' atris imessage latest [--limit 20] [--json] - Read latest local messages');
|
|
1191
1257
|
console.log(' atris imessage send --to <handle> --text <text> --approved [--json] [--receipt]');
|
|
1192
1258
|
}
|
|
1193
1259
|
}
|
package/commands/skill.js
CHANGED
|
@@ -88,6 +88,39 @@ function findAllSkills(skillsDir) {
|
|
|
88
88
|
return skills;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function localSkillsDir() {
|
|
92
|
+
return path.join(process.cwd(), 'atris', 'skills');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function bundledSkillsDir() {
|
|
96
|
+
return path.join(__dirname, '..', 'atris', 'skills');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function readableSkillRoots() {
|
|
100
|
+
const roots = [localSkillsDir(), bundledSkillsDir()];
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
return roots.filter((root) => {
|
|
103
|
+
if (!root || !fs.existsSync(root)) return false;
|
|
104
|
+
const real = fs.realpathSync(root);
|
|
105
|
+
if (seen.has(real)) return false;
|
|
106
|
+
seen.add(real);
|
|
107
|
+
return true;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function findReadableSkills() {
|
|
112
|
+
const seen = new Set();
|
|
113
|
+
const skills = [];
|
|
114
|
+
for (const root of readableSkillRoots()) {
|
|
115
|
+
for (const skill of findAllSkills(root)) {
|
|
116
|
+
if (seen.has(skill.folder)) continue;
|
|
117
|
+
seen.add(skill.folder);
|
|
118
|
+
skills.push(skill);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return skills;
|
|
122
|
+
}
|
|
123
|
+
|
|
91
124
|
// --- Audit Checks ---
|
|
92
125
|
|
|
93
126
|
function runAuditChecks(skill) {
|
|
@@ -355,11 +388,10 @@ function generateTags(folderName, description) {
|
|
|
355
388
|
// --- Subcommand Handlers ---
|
|
356
389
|
|
|
357
390
|
function skillList() {
|
|
358
|
-
const
|
|
359
|
-
const skills = findAllSkills(skillsDir);
|
|
391
|
+
const skills = findReadableSkills();
|
|
360
392
|
|
|
361
393
|
if (skills.length === 0) {
|
|
362
|
-
console.log('No skills found in
|
|
394
|
+
console.log('No skills found in local or bundled Atris skill roots.');
|
|
363
395
|
return;
|
|
364
396
|
}
|
|
365
397
|
|
|
@@ -396,15 +428,14 @@ function skillList() {
|
|
|
396
428
|
}
|
|
397
429
|
|
|
398
430
|
function skillAudit(name) {
|
|
399
|
-
const
|
|
400
|
-
const allSkills = findAllSkills(skillsDir);
|
|
431
|
+
const allSkills = findReadableSkills();
|
|
401
432
|
|
|
402
433
|
const targets = name === '--all'
|
|
403
434
|
? allSkills
|
|
404
435
|
: allSkills.filter(s => s.folder === name || s.leafFolder === name);
|
|
405
436
|
|
|
406
437
|
if (targets.length === 0) {
|
|
407
|
-
console.error(`Skill "${name}" not found. Run "atris skill list" to see available skills.`);
|
|
438
|
+
console.error(`Skill "${name}" not found. Run "atris skill list" to see available local and bundled skills.`);
|
|
408
439
|
process.exit(1);
|
|
409
440
|
}
|
|
410
441
|
|
package/commands/xp.js
CHANGED
|
@@ -7,6 +7,7 @@ const crypto = require('crypto');
|
|
|
7
7
|
const { spawnSync } = require('child_process');
|
|
8
8
|
|
|
9
9
|
const DEFAULT_GRAPH_DAYS = 365;
|
|
10
|
+
const MAX_SYNC_GRAPH_DAYS = 370;
|
|
10
11
|
const INTENSITY_CHARS = [' ', '.', ':', '*', '#'];
|
|
11
12
|
const ROW_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
12
13
|
const TASK_EPISODES_FILE = path.join('.atris', 'state', 'task_episodes.jsonl');
|
|
@@ -210,6 +211,38 @@ function combineAgentXpContributionGraphs(graphs, windowDays = DEFAULT_GRAPH_DAY
|
|
|
210
211
|
return graphFromDailyTotals(totals, windowDays);
|
|
211
212
|
}
|
|
212
213
|
|
|
214
|
+
function sanitizeContributionGraphForSync(graph) {
|
|
215
|
+
if (!graph || typeof graph !== 'object') return null;
|
|
216
|
+
const rawDays = Array.isArray(graph.days) ? graph.days : [];
|
|
217
|
+
const days = rawDays
|
|
218
|
+
.slice(-MAX_SYNC_GRAPH_DAYS)
|
|
219
|
+
.map((day) => {
|
|
220
|
+
const date = typeof day?.date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(day.date)
|
|
221
|
+
? day.date
|
|
222
|
+
: null;
|
|
223
|
+
if (!date) return null;
|
|
224
|
+
const xp = Math.max(0, asNumber(day.xp ?? day.total_xp));
|
|
225
|
+
return {
|
|
226
|
+
date,
|
|
227
|
+
xp,
|
|
228
|
+
total_xp: Math.max(0, asNumber(day.total_xp, xp)),
|
|
229
|
+
intensity: Math.max(0, Math.min(4, asNumber(day.intensity))),
|
|
230
|
+
};
|
|
231
|
+
})
|
|
232
|
+
.filter(Boolean);
|
|
233
|
+
if (days.length === 0) return null;
|
|
234
|
+
return {
|
|
235
|
+
schema: 'atris.agent_xp_contribution_graph.v1',
|
|
236
|
+
metric_label: AGENT_XP_LABEL,
|
|
237
|
+
window_days: days.length,
|
|
238
|
+
total_xp: days.reduce((sum, day) => sum + day.xp, 0),
|
|
239
|
+
active_days: days.filter(day => day.xp > 0).length,
|
|
240
|
+
first_date: days[0]?.date || null,
|
|
241
|
+
last_date: days[days.length - 1]?.date || null,
|
|
242
|
+
days,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
213
246
|
function currentForm(payload) {
|
|
214
247
|
const arenas = payload.current_form_by_arena || {};
|
|
215
248
|
const local = arenas.local_workspace || {};
|
|
@@ -1945,6 +1978,7 @@ function buildAgentXpSyncPacket(args = []) {
|
|
|
1945
1978
|
const publicXp = earnedAgentXp(totalXp);
|
|
1946
1979
|
const currentForm = currentFormScore(totalXp);
|
|
1947
1980
|
const levelProgress = agentXpLevelProgress(publicXp);
|
|
1981
|
+
const contributionGraph = sanitizeContributionGraphForSync(projection.contribution_graph);
|
|
1948
1982
|
const workspaceRootHash = sha256(workspaces.map(item => item.workspace_root_hash || item.name).sort().join(':'));
|
|
1949
1983
|
const entry = {
|
|
1950
1984
|
user_id: player,
|
|
@@ -1964,6 +1998,7 @@ function buildAgentXpSyncPacket(args = []) {
|
|
|
1964
1998
|
lock_reason: eligible ? null : 'not_enough_trusted_proof',
|
|
1965
1999
|
public_adjustment: null,
|
|
1966
2000
|
next_move: eligible ? 'Play the next proof-backed AgentXP mission.' : 'Complete one proof-backed AgentXP rep.',
|
|
2001
|
+
contribution_graph: contributionGraph,
|
|
1967
2002
|
};
|
|
1968
2003
|
const packet = {
|
|
1969
2004
|
schema: 'atris.agentxp_sync_packet.v1',
|