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.
Files changed (59) hide show
  1. package/README.md +33 -7
  2. package/atris/skills/atris/SKILL.md +15 -2
  3. package/atris/skills/atris-feedback/SKILL.md +7 -0
  4. package/atris/skills/design/SKILL.md +29 -2
  5. package/atris/skills/engines/SKILL.md +44 -0
  6. package/atris/skills/flow/SKILL.md +1 -1
  7. package/atris/skills/wake/SKILL.md +37 -0
  8. package/atris/skills/youtube/SKILL.md +13 -39
  9. package/atris/team/validator/MEMBER.md +1 -0
  10. package/atris/wiki/concepts/agent-activation-contract.md +3 -3
  11. package/atris/wiki/concepts/workspace-initialization-contract.md +3 -3
  12. package/atris/wiki/index.md +1 -0
  13. package/atris.md +43 -19
  14. package/bin/atris.js +446 -43
  15. package/commands/agent-spawn.js +480 -0
  16. package/commands/analytics.js +6 -3
  17. package/commands/apps.js +11 -0
  18. package/commands/autopilot.js +466 -20
  19. package/commands/brain.js +74 -7
  20. package/commands/brainstorm.js +9 -58
  21. package/commands/clean.js +1 -4
  22. package/commands/compile.js +574 -0
  23. package/commands/console.js +8 -3
  24. package/commands/deck.js +135 -0
  25. package/commands/init.js +22 -11
  26. package/commands/lesson.js +76 -0
  27. package/commands/member.js +252 -48
  28. package/commands/mission.js +405 -13
  29. package/commands/now.js +4 -2
  30. package/commands/probe.js +444 -0
  31. package/commands/pulse.js +504 -0
  32. package/commands/radar.js +1 -0
  33. package/commands/recap.js +233 -0
  34. package/commands/run.js +615 -22
  35. package/commands/skill.js +6 -2
  36. package/commands/slop.js +173 -0
  37. package/commands/spaceship.js +39 -0
  38. package/commands/sync.js +0 -2
  39. package/commands/task.js +458 -43
  40. package/commands/verify.js +7 -3
  41. package/lib/activity-stream.js +166 -0
  42. package/lib/auto-accept-certified.js +23 -1
  43. package/lib/context-gatherer.js +170 -0
  44. package/lib/escape-regexp.js +13 -0
  45. package/lib/file-ops.js +6 -3
  46. package/lib/journal.js +1 -1
  47. package/lib/lesson-contradiction.js +113 -0
  48. package/lib/policy-lessons.js +3 -2
  49. package/lib/pulse.js +401 -0
  50. package/lib/runner-command.js +156 -0
  51. package/lib/slides-deck.js +236 -0
  52. package/lib/state-detection.js +40 -3
  53. package/lib/task-db.js +101 -4
  54. package/lib/task-proof.js +1 -1
  55. package/lib/todo-fallback.js +2 -1
  56. package/lib/todo-sections.js +33 -0
  57. package/package.json +1 -2
  58. package/utils/api.js +14 -2
  59. 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 };