atris 3.16.0 → 3.17.0
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 +33 -7
- package/atris/skills/atris/SKILL.md +15 -2
- package/atris/skills/atris-feedback/SKILL.md +7 -0
- package/atris/skills/design/SKILL.md +29 -2
- package/atris/skills/engines/SKILL.md +44 -0
- package/atris/skills/flow/SKILL.md +1 -1
- package/atris/skills/wake/SKILL.md +37 -0
- package/atris/skills/youtube/SKILL.md +13 -39
- package/atris/team/validator/MEMBER.md +1 -0
- package/atris/wiki/concepts/agent-activation-contract.md +3 -3
- package/atris/wiki/concepts/workspace-initialization-contract.md +3 -3
- package/atris/wiki/index.md +1 -0
- package/atris.md +43 -19
- package/bin/atris.js +446 -43
- package/commands/agent-spawn.js +480 -0
- package/commands/analytics.js +6 -3
- package/commands/apps.js +11 -0
- package/commands/autopilot.js +466 -20
- package/commands/brain.js +74 -7
- package/commands/brainstorm.js +9 -58
- package/commands/clean.js +1 -4
- package/commands/compile.js +574 -0
- package/commands/console.js +8 -3
- package/commands/deck.js +135 -0
- package/commands/init.js +22 -11
- package/commands/lesson.js +76 -0
- package/commands/member.js +252 -48
- package/commands/mission.js +405 -13
- package/commands/now.js +4 -2
- package/commands/probe.js +444 -0
- package/commands/pulse.js +504 -0
- package/commands/radar.js +1 -0
- package/commands/recap.js +233 -0
- package/commands/run.js +615 -22
- package/commands/skill.js +6 -2
- package/commands/slop.js +173 -0
- package/commands/spaceship.js +39 -0
- package/commands/sync.js +0 -2
- package/commands/task.js +458 -43
- package/commands/verify.js +7 -3
- package/lib/activity-stream.js +166 -0
- package/lib/auto-accept-certified.js +23 -1
- package/lib/context-gatherer.js +170 -0
- package/lib/escape-regexp.js +13 -0
- package/lib/file-ops.js +6 -3
- package/lib/journal.js +1 -1
- package/lib/lesson-contradiction.js +113 -0
- package/lib/policy-lessons.js +3 -2
- package/lib/pulse.js +401 -0
- package/lib/runner-command.js +156 -0
- package/lib/slides-deck.js +236 -0
- package/lib/state-detection.js +40 -3
- package/lib/task-db.js +101 -4
- package/lib/task-proof.js +1 -1
- package/lib/todo-fallback.js +2 -1
- package/lib/todo-sections.js +33 -0
- package/package.json +1 -2
- package/utils/api.js +14 -2
- package/atris/atrisDev.md +0 -717
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
5
|
+
const DEFAULT_DAYS = 7;
|
|
6
|
+
|
|
7
|
+
function loadTaskDb() {
|
|
8
|
+
try {
|
|
9
|
+
return require('../lib/task-db');
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function readProjection(root) {
|
|
16
|
+
const projectionPath = path.join(root, '.atris', 'state', 'tasks.projection.json');
|
|
17
|
+
if (!fs.existsSync(projectionPath)) return null;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(fs.readFileSync(projectionPath, 'utf8'));
|
|
20
|
+
return Array.isArray(parsed.tasks) ? parsed.tasks : null;
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function loadTasks(root) {
|
|
27
|
+
const taskDb = loadTaskDb();
|
|
28
|
+
if (taskDb) {
|
|
29
|
+
try {
|
|
30
|
+
const db = taskDb.open();
|
|
31
|
+
const ws = taskDb.workspaceRoot(root);
|
|
32
|
+
const rows = taskDb.listTasks(db, { workspaceRoot: ws });
|
|
33
|
+
const refs = taskDb.taskDisplayRefMap(rows);
|
|
34
|
+
return rows.map(row => ({ ...row, display_id: refs.get(row.id) || row.id.slice(-6) }));
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// fall through to projection
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return readProjection(root);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function taskProof(task) {
|
|
43
|
+
const meta = task.metadata || {};
|
|
44
|
+
const proof = String(meta.latest_agent_proof || '').trim();
|
|
45
|
+
if (proof) return proof;
|
|
46
|
+
if (meta.agent_certified === true) return 'verified by repeated agent review';
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function shortProof(proof, width = 70) {
|
|
51
|
+
if (!proof) return null;
|
|
52
|
+
const flat = proof.replace(/\s+/g, ' ').trim();
|
|
53
|
+
return flat.length <= width ? flat : `${flat.slice(0, width - 1)}…`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function plainCheck(proof, width = 70) {
|
|
57
|
+
if (!proof) return null;
|
|
58
|
+
const flat = proof.replace(/\s+/g, ' ').trim();
|
|
59
|
+
const checks = [];
|
|
60
|
+
const add = label => { if (!checks.includes(label)) checks.push(label); };
|
|
61
|
+
|
|
62
|
+
if (/\b(PR|pull request)\b.*\b(merged|MERGED)\b|\bmerged\b.*\b(PR|pull request)\b/i.test(flat)) add('merged');
|
|
63
|
+
if (/\b(node --test|npm test|npm run test|pytest|go test|cargo test|test\/|tests?)\b/i.test(flat)
|
|
64
|
+
&& /\b(pass|passed|green|ok|0 failures?|9\/9|12\/12)\b/i.test(flat)) add('tests passed');
|
|
65
|
+
if (/\b(node --check|git diff --check|git diff --exit-code|git diff --quiet|rg\b|grep\b|diff --brief|cmp -s)\b/i.test(flat)) add('code check passed');
|
|
66
|
+
if (/\b(bench|benchmark|measured|latency|speed)\b/i.test(flat)) add('measured improvement');
|
|
67
|
+
if (/\brepeated agent review\b|\bagent review\b/i.test(flat)) add('reviewed repeatedly');
|
|
68
|
+
if (/\batris\/runs\/[^\s]+\.json\b|receipt\b/i.test(flat)) add('record saved');
|
|
69
|
+
if (/\b(human approved|accepted by|accepted_at|reward)\b/i.test(flat)) add('human accepted');
|
|
70
|
+
|
|
71
|
+
if (checks.length) return checks.join(', ');
|
|
72
|
+
return shortProof(proof, width);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function shortTitle(title, width = 64) {
|
|
76
|
+
const flat = String(title || '')
|
|
77
|
+
.replace(/\bproof\b/gi, 'checks')
|
|
78
|
+
.replace(/\breceipts?\b/gi, 'records')
|
|
79
|
+
.replace(/\bsign[- ]off\b/gi, 'approval')
|
|
80
|
+
.replace(/\bpolicy\b/gi, 'rules')
|
|
81
|
+
.replace(/\bAgentXP\b/g, 'reward')
|
|
82
|
+
.replace(/\bcertified\b/gi, 'checked')
|
|
83
|
+
.replace(/\s+/g, ' ')
|
|
84
|
+
.trim();
|
|
85
|
+
return flat.length <= width ? flat : `${flat.slice(0, width - 1)}…`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function buildRecapData(root = process.cwd(), { days = DEFAULT_DAYS } = {}) {
|
|
89
|
+
const windowDays = Number.isFinite(Number(days)) && Number(days) > 0 ? Number(days) : DEFAULT_DAYS;
|
|
90
|
+
const tasks = loadTasks(root);
|
|
91
|
+
if (!tasks || tasks.length === 0) return { empty: true, days: windowDays, workspace: path.basename(root) };
|
|
92
|
+
|
|
93
|
+
const cutoff = Date.now() - windowDays * DAY_MS;
|
|
94
|
+
const pick = t => ({
|
|
95
|
+
id: t.display_id || t.id,
|
|
96
|
+
title: String(t.title || '').trim(),
|
|
97
|
+
proof: taskProof(t),
|
|
98
|
+
owner: t.claimed_by || (t.metadata && t.metadata.assigned_to) || null,
|
|
99
|
+
done_at: t.done_at || null,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const shipped = tasks
|
|
103
|
+
.filter(t => t.status === 'done' && Number(t.done_at || 0) >= cutoff)
|
|
104
|
+
.sort((a, b) => Number(b.done_at || 0) - Number(a.done_at || 0))
|
|
105
|
+
.map(pick);
|
|
106
|
+
const waiting = tasks
|
|
107
|
+
.filter(t => t.status === 'review')
|
|
108
|
+
.sort((a, b) => Number(b.updated_at || 0) - Number(a.updated_at || 0))
|
|
109
|
+
.map(pick);
|
|
110
|
+
const inProgress = tasks
|
|
111
|
+
.filter(t => t.status === 'open' || t.status === 'claimed')
|
|
112
|
+
.map(pick);
|
|
113
|
+
|
|
114
|
+
const withProof = [...shipped, ...waiting].filter(t => t.proof).length;
|
|
115
|
+
return {
|
|
116
|
+
empty: false,
|
|
117
|
+
days: windowDays,
|
|
118
|
+
workspace: path.basename(root),
|
|
119
|
+
shipped,
|
|
120
|
+
waiting,
|
|
121
|
+
inProgress,
|
|
122
|
+
proof_attached: withProof,
|
|
123
|
+
proof_total: shipped.length + waiting.length,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function renderRecap(data) {
|
|
128
|
+
if (data.empty) {
|
|
129
|
+
return [
|
|
130
|
+
`RECAP — ${data.workspace}`,
|
|
131
|
+
'',
|
|
132
|
+
'No task history yet.',
|
|
133
|
+
'Run "atris init", then let Atris do one small job. Finished work will show up here with the checks that passed.',
|
|
134
|
+
].join('\n');
|
|
135
|
+
}
|
|
136
|
+
const lines = [];
|
|
137
|
+
lines.push(`RECAP — ${data.workspace} — last ${data.days} day${data.days === 1 ? '' : 's'}`);
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push('Plain English: what changed, how it was checked, and what still needs you.');
|
|
140
|
+
const headline = [];
|
|
141
|
+
if (data.shipped.length) headline.push(`${data.shipped.length} done`);
|
|
142
|
+
if (data.waiting.length) headline.push(`${data.waiting.length} needs you`);
|
|
143
|
+
if (data.inProgress.length) headline.push(`${data.inProgress.length} still working`);
|
|
144
|
+
lines.push(headline.length ? headline.join(' · ') : 'Quiet window — no movement in this period.');
|
|
145
|
+
|
|
146
|
+
if (data.shipped.length) {
|
|
147
|
+
lines.push('');
|
|
148
|
+
lines.push(`DONE — ${data.shipped.length}`);
|
|
149
|
+
for (const t of data.shipped.slice(0, 12)) {
|
|
150
|
+
lines.push(` ${t.id} ${shortTitle(t.title)}`);
|
|
151
|
+
const check = plainCheck(t.proof);
|
|
152
|
+
if (check) lines.push(` checked: ${check}`);
|
|
153
|
+
}
|
|
154
|
+
if (data.shipped.length > 12) lines.push(` … and ${data.shipped.length - 12} more`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (data.waiting.length) {
|
|
158
|
+
lines.push('');
|
|
159
|
+
lines.push(`NEEDS YOU — ${data.waiting.length}`);
|
|
160
|
+
for (const t of data.waiting.slice(0, 10)) {
|
|
161
|
+
lines.push(` ${t.id} ${shortTitle(t.title)}`);
|
|
162
|
+
const check = plainCheck(t.proof);
|
|
163
|
+
if (check) lines.push(` checked: ${check}`);
|
|
164
|
+
}
|
|
165
|
+
if (data.waiting.length > 10) lines.push(` … and ${data.waiting.length - 10} more`);
|
|
166
|
+
lines.push(' next: run atris task reviews');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (data.inProgress.length) {
|
|
170
|
+
lines.push('');
|
|
171
|
+
lines.push(`STILL WORKING — ${data.inProgress.length}`);
|
|
172
|
+
for (const t of data.inProgress) {
|
|
173
|
+
lines.push(` ${t.id} ${shortTitle(t.title)}${t.owner ? ` @${t.owner}` : ''}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
lines.push('');
|
|
178
|
+
lines.push(`Checked: ${data.proof_attached}/${data.proof_total} finished items.`);
|
|
179
|
+
lines.push('Share this: atris recap --share');
|
|
180
|
+
return lines.join('\n');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function renderShare(data) {
|
|
184
|
+
if (data.empty) return `Nothing to share yet on ${data.workspace} — no finished tasks on record.`;
|
|
185
|
+
const lines = [];
|
|
186
|
+
lines.push(`What got done on ${data.workspace} in the last ${data.days} day${data.days === 1 ? '' : 's'}:`);
|
|
187
|
+
lines.push('');
|
|
188
|
+
if (data.shipped.length) lines.push(`- ${data.shipped.length} done and accepted`);
|
|
189
|
+
if (data.waiting.length) lines.push(`- ${data.waiting.length} ready for you to approve or send back`);
|
|
190
|
+
if (data.inProgress.length) lines.push(`- ${data.inProgress.length} still being worked on`);
|
|
191
|
+
const highlights = [...data.shipped, ...data.waiting].filter(t => t.proof).slice(0, 5);
|
|
192
|
+
if (highlights.length) {
|
|
193
|
+
lines.push('');
|
|
194
|
+
lines.push('Highlights:');
|
|
195
|
+
for (const t of highlights) {
|
|
196
|
+
lines.push(`- ${shortTitle(t.title, 80)} (${plainCheck(t.proof, 60)})`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
lines.push('');
|
|
200
|
+
lines.push('The finished items are backed by actual checks that ran, not a status update someone typed.');
|
|
201
|
+
return lines.join('\n');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function printRecapHelp() {
|
|
205
|
+
console.log(`
|
|
206
|
+
atris recap - what got done, in plain English
|
|
207
|
+
|
|
208
|
+
atris recap Last 7 days: done, needs you, still working
|
|
209
|
+
atris recap --days 30 Widen the window
|
|
210
|
+
atris recap --share Paste-ready summary for Slack, email, or a customer
|
|
211
|
+
atris recap --json Structured output for agents and dashboards
|
|
212
|
+
|
|
213
|
+
Looks at Atris' saved work and explains it without internal jargon:
|
|
214
|
+
what changed, how it was checked, and what still needs you.
|
|
215
|
+
`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function recapAtris(args = []) {
|
|
219
|
+
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
220
|
+
printRecapHelp();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const daysIdx = args.indexOf('--days');
|
|
224
|
+
const days = daysIdx !== -1 ? Number(args[daysIdx + 1]) : DEFAULT_DAYS;
|
|
225
|
+
const data = buildRecapData(process.cwd(), { days });
|
|
226
|
+
if (args.includes('--json')) {
|
|
227
|
+
console.log(JSON.stringify(data, null, 2));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
console.log(args.includes('--share') ? renderShare(data) : renderRecap(data));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
module.exports = { recapAtris, buildRecapData, renderRecap, renderShare };
|