atris 3.2.0 → 3.5.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/GETTING_STARTED.md +65 -131
- package/README.md +18 -2
- package/atris/GETTING_STARTED.md +65 -131
- package/atris/PERSONA.md +5 -1
- package/atris/atris.md +122 -153
- package/atris/skills/aeo/SKILL.md +117 -0
- package/atris/skills/atris/SKILL.md +49 -25
- package/atris/skills/create-member/SKILL.md +29 -9
- package/atris/skills/endgame/SKILL.md +9 -0
- package/atris/skills/research-search/SKILL.md +167 -0
- package/atris/skills/research-search/arxiv_search.py +157 -0
- package/atris/skills/research-search/program.md +48 -0
- package/atris/skills/research-search/results.tsv +6 -0
- package/atris/skills/research-search/scholar_search.py +154 -0
- package/atris/skills/tidy/SKILL.md +36 -21
- package/atris/team/_template/MEMBER.md +2 -0
- package/atris/team/validator/MEMBER.md +35 -1
- package/atris.md +118 -178
- package/bin/atris.js +30 -5
- package/cli/__pycache__/atris_code.cpython-314.pyc +0 -0
- package/cli/__pycache__/runtime_guard.cpython-312.pyc +0 -0
- package/cli/__pycache__/runtime_guard.cpython-314.pyc +0 -0
- package/cli/atris_code.py +889 -0
- package/cli/runtime_guard.py +693 -0
- package/commands/align.js +15 -0
- package/commands/app.js +316 -0
- package/commands/autopilot.js +390 -7
- package/commands/business.js +677 -2
- package/commands/computer.js +1979 -43
- package/commands/context-sync.js +5 -0
- package/commands/lifecycle.js +12 -0
- package/commands/plugin.js +24 -0
- package/commands/pull.js +40 -1
- package/commands/push.js +44 -0
- package/commands/serve.js +1 -0
- package/commands/sync.js +272 -76
- package/commands/verify.js +50 -1
- package/commands/wiki.js +27 -2
- package/lib/file-ops.js +13 -1
- package/lib/journal.js +23 -0
- package/lib/scorecard.js +42 -4
- package/lib/sync-telemetry.js +59 -0
- package/lib/todo.js +6 -0
- package/lib/wiki.js +150 -6
- package/package.json +2 -1
- package/utils/api.js +19 -0
- package/utils/auth.js +25 -1
- package/utils/config.js +24 -0
- package/utils/update-check.js +16 -0
package/commands/align.js
CHANGED
|
@@ -32,14 +32,29 @@ const SKIP_DIRS = new Set([
|
|
|
32
32
|
|
|
33
33
|
const SKIP_FILES = new Set(['.DS_Store', 'Thumbs.db']);
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Sleep for a given number of milliseconds.
|
|
37
|
+
* @param {number} ms - Milliseconds to sleep
|
|
38
|
+
* @returns {Promise<void>}
|
|
39
|
+
*/
|
|
35
40
|
function sleep(ms) {
|
|
36
41
|
return new Promise((r) => setTimeout(r, ms));
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Compute SHA-256 hash of content string.
|
|
46
|
+
* @param {string} content - Content to hash
|
|
47
|
+
* @returns {string} Hex-encoded hash
|
|
48
|
+
*/
|
|
39
49
|
function hashContent(content) {
|
|
40
50
|
return crypto.createHash('sha256').update(content).digest('hex');
|
|
41
51
|
}
|
|
42
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Compute SHA-256 hash of a file.
|
|
55
|
+
* @param {string} absPath - Absolute path to file
|
|
56
|
+
* @returns {string|null} Hex-encoded hash, or null if file unreadable
|
|
57
|
+
*/
|
|
43
58
|
function hashFile(absPath) {
|
|
44
59
|
try {
|
|
45
60
|
const buf = fs.readFileSync(absPath);
|
package/commands/app.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* atris app — manage APP.md manifests in the current workspace.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* atris app init <slug> [--runtime ec2|local|webhook|external|web|ios|template]
|
|
6
|
+
* Scaffolds apps/<slug>/{APP.md, README.md, data/, logs/}.
|
|
7
|
+
*
|
|
8
|
+
* atris app list
|
|
9
|
+
* Lists every apps/<slug>/APP.md in the current workspace.
|
|
10
|
+
*
|
|
11
|
+
* atris app show <slug>
|
|
12
|
+
* Prints the APP.md for a given app.
|
|
13
|
+
*
|
|
14
|
+
* APP.md is the third agent-native primitive alongside MEMBER.md and
|
|
15
|
+
* SKILL.md. One file, any runtime, every agent. See github.com/atrislabs/app.md.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const RUNTIMES = [
|
|
22
|
+
'local',
|
|
23
|
+
'subprocess',
|
|
24
|
+
'ec2',
|
|
25
|
+
'webhook',
|
|
26
|
+
'external',
|
|
27
|
+
'web',
|
|
28
|
+
'ios',
|
|
29
|
+
'template',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
function workspaceRoot() {
|
|
33
|
+
// An Atris workspace has either .atris/business.json (business workspace)
|
|
34
|
+
// or atris/atris.md (repo workspace). Walk up until we find one.
|
|
35
|
+
let cur = process.cwd();
|
|
36
|
+
while (cur !== path.dirname(cur)) {
|
|
37
|
+
if (
|
|
38
|
+
fs.existsSync(path.join(cur, '.atris', 'business.json')) ||
|
|
39
|
+
fs.existsSync(path.join(cur, 'atris', 'atris.md'))
|
|
40
|
+
) {
|
|
41
|
+
return cur;
|
|
42
|
+
}
|
|
43
|
+
cur = path.dirname(cur);
|
|
44
|
+
}
|
|
45
|
+
return process.cwd();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseRuntimeFlag(args) {
|
|
49
|
+
const idx = args.findIndex((a) => a === '--runtime' || a === '-r');
|
|
50
|
+
if (idx === -1) return 'local';
|
|
51
|
+
const val = args[idx + 1];
|
|
52
|
+
if (!RUNTIMES.includes(val)) {
|
|
53
|
+
console.error(`✗ --runtime must be one of: ${RUNTIMES.join(', ')}`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
return val;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function templateFor(slug, runtime) {
|
|
60
|
+
const header = [
|
|
61
|
+
'---',
|
|
62
|
+
'schema_version: 1',
|
|
63
|
+
`name: ${slug}`,
|
|
64
|
+
`slug: ${slug}`,
|
|
65
|
+
`description: One-line description of what ${slug} does.`,
|
|
66
|
+
'access: business',
|
|
67
|
+
`runtime: ${runtime}`,
|
|
68
|
+
'vault: atris-kms',
|
|
69
|
+
'runtime_auth: jwt',
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const body = [
|
|
73
|
+
`# ${slug}`,
|
|
74
|
+
'',
|
|
75
|
+
'What this app does, step by step.',
|
|
76
|
+
'',
|
|
77
|
+
'1. First action (reference secrets by name like `MY_API_KEY`).',
|
|
78
|
+
'2. Second action.',
|
|
79
|
+
'3. Where the output goes.',
|
|
80
|
+
'',
|
|
81
|
+
'## Guardrails',
|
|
82
|
+
'',
|
|
83
|
+
'- What this app will never do.',
|
|
84
|
+
'- What happens when a secret is missing.',
|
|
85
|
+
'',
|
|
86
|
+
].join('\n');
|
|
87
|
+
|
|
88
|
+
if (runtime === 'ec2' || runtime === 'subprocess' || runtime === 'local') {
|
|
89
|
+
header.push(
|
|
90
|
+
'block_pipeline_id: null',
|
|
91
|
+
'secrets: []',
|
|
92
|
+
'# schedule: "0 9 * * *" # uncomment for cron',
|
|
93
|
+
'# member: treasury # optional inherit',
|
|
94
|
+
'# skills: [] # optional inherit',
|
|
95
|
+
'surfaces: [web]',
|
|
96
|
+
'render: inline',
|
|
97
|
+
'monetization:',
|
|
98
|
+
' price_credits: 0',
|
|
99
|
+
' creator_share: 0.0',
|
|
100
|
+
'---',
|
|
101
|
+
'',
|
|
102
|
+
);
|
|
103
|
+
} else if (runtime === 'webhook') {
|
|
104
|
+
header.push(
|
|
105
|
+
'endpoints:',
|
|
106
|
+
' webhook: https://example.com/hook',
|
|
107
|
+
'auth:',
|
|
108
|
+
' type: hmac',
|
|
109
|
+
' secret_ref: HOOK_SECRET',
|
|
110
|
+
'secrets: [HOOK_SECRET]',
|
|
111
|
+
'surfaces: [web]',
|
|
112
|
+
'render: none',
|
|
113
|
+
'---',
|
|
114
|
+
'',
|
|
115
|
+
);
|
|
116
|
+
} else if (runtime === 'external') {
|
|
117
|
+
header.push(
|
|
118
|
+
'endpoints:',
|
|
119
|
+
' api: https://api.example.com',
|
|
120
|
+
' frontend: https://app.example.com',
|
|
121
|
+
' mcp: https://example.com/mcp',
|
|
122
|
+
'auth:',
|
|
123
|
+
' type: oauth',
|
|
124
|
+
' issuer: https://auth.example.com',
|
|
125
|
+
'capabilities: []',
|
|
126
|
+
'secrets: []',
|
|
127
|
+
'surfaces: [web, slack, mcp]',
|
|
128
|
+
'render: inline',
|
|
129
|
+
'---',
|
|
130
|
+
'',
|
|
131
|
+
);
|
|
132
|
+
} else if (runtime === 'web') {
|
|
133
|
+
header.push(
|
|
134
|
+
'endpoints:',
|
|
135
|
+
' frontend: https://example.com',
|
|
136
|
+
' mcp: https://example.com/mcp',
|
|
137
|
+
'auth:',
|
|
138
|
+
' type: none',
|
|
139
|
+
'capabilities: []',
|
|
140
|
+
'surfaces: [web, mcp]',
|
|
141
|
+
'render: embed',
|
|
142
|
+
'---',
|
|
143
|
+
'',
|
|
144
|
+
);
|
|
145
|
+
} else if (runtime === 'ios') {
|
|
146
|
+
header.push(
|
|
147
|
+
'endpoints:',
|
|
148
|
+
' bundle_id: com.example.app',
|
|
149
|
+
' deep_link_scheme: example',
|
|
150
|
+
'capabilities: []',
|
|
151
|
+
'secrets: []',
|
|
152
|
+
'surfaces: [mobile]',
|
|
153
|
+
'render: fullscreen',
|
|
154
|
+
'---',
|
|
155
|
+
'',
|
|
156
|
+
);
|
|
157
|
+
} else if (runtime === 'template') {
|
|
158
|
+
header.push(
|
|
159
|
+
'access: public',
|
|
160
|
+
'secrets: []',
|
|
161
|
+
'surfaces: [web]',
|
|
162
|
+
'render: none',
|
|
163
|
+
'monetization:',
|
|
164
|
+
' price_credits: 5',
|
|
165
|
+
' creator_share: 0.8',
|
|
166
|
+
'---',
|
|
167
|
+
'',
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return header.join('\n') + body;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function readmeFor(slug) {
|
|
175
|
+
return [
|
|
176
|
+
`# ${slug}`,
|
|
177
|
+
'',
|
|
178
|
+
'One-line description.',
|
|
179
|
+
'',
|
|
180
|
+
'See `APP.md` for the manifest.',
|
|
181
|
+
'',
|
|
182
|
+
'## Files',
|
|
183
|
+
'',
|
|
184
|
+
'- `APP.md` — app manifest (frontmatter + instructions). Source of truth.',
|
|
185
|
+
'- `data/` — per-run outputs.',
|
|
186
|
+
'- `logs/` — stdout/stderr per trigger.',
|
|
187
|
+
'',
|
|
188
|
+
'## Secrets',
|
|
189
|
+
'',
|
|
190
|
+
'Values live in the workspace vault, not this folder. Rotate with',
|
|
191
|
+
'`atris secrets set <NAME>` once that command lands.',
|
|
192
|
+
'',
|
|
193
|
+
].join('\n');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function init(slug, runtime) {
|
|
197
|
+
if (!slug) {
|
|
198
|
+
console.error('✗ usage: atris app init <slug> [--runtime <kind>]');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
if (!/^[a-z0-9-]+$/.test(slug)) {
|
|
202
|
+
console.error(`✗ slug must be lowercase alphanumerics + hyphens (got: ${slug})`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const root = workspaceRoot();
|
|
207
|
+
const appsDir = path.join(root, 'apps');
|
|
208
|
+
const slugDir = path.join(appsDir, slug);
|
|
209
|
+
if (fs.existsSync(slugDir)) {
|
|
210
|
+
console.error(`✗ ${slugDir} already exists`);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fs.mkdirSync(path.join(slugDir, 'data'), { recursive: true });
|
|
215
|
+
fs.mkdirSync(path.join(slugDir, 'logs'), { recursive: true });
|
|
216
|
+
fs.writeFileSync(path.join(slugDir, 'APP.md'), templateFor(slug, runtime), 'utf8');
|
|
217
|
+
fs.writeFileSync(path.join(slugDir, 'README.md'), readmeFor(slug), 'utf8');
|
|
218
|
+
|
|
219
|
+
console.log(`✓ scaffolded ${path.relative(process.cwd(), slugDir)}`);
|
|
220
|
+
console.log(` runtime: ${runtime}`);
|
|
221
|
+
console.log(' next:');
|
|
222
|
+
console.log(` 1. edit ${path.join('apps', slug, 'APP.md')}`);
|
|
223
|
+
console.log(' 2. atris app show ' + slug);
|
|
224
|
+
console.log(' 3. (coming) atris app sync ' + slug);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function findApps(root) {
|
|
228
|
+
const appsDir = path.join(root, 'apps');
|
|
229
|
+
if (!fs.existsSync(appsDir)) return [];
|
|
230
|
+
return fs
|
|
231
|
+
.readdirSync(appsDir)
|
|
232
|
+
.filter((name) => {
|
|
233
|
+
const f = path.join(appsDir, name, 'APP.md');
|
|
234
|
+
return fs.existsSync(f);
|
|
235
|
+
})
|
|
236
|
+
.map((name) => ({
|
|
237
|
+
slug: name,
|
|
238
|
+
path: path.join(appsDir, name),
|
|
239
|
+
}));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function list() {
|
|
243
|
+
const root = workspaceRoot();
|
|
244
|
+
const apps = findApps(root);
|
|
245
|
+
if (apps.length === 0) {
|
|
246
|
+
console.log(`no apps in ${path.relative(process.cwd(), path.join(root, 'apps')) || 'apps/'}`);
|
|
247
|
+
console.log('create one: atris app init <slug>');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
console.log(`apps in ${path.relative(process.cwd(), root) || '.'}:`);
|
|
251
|
+
for (const a of apps) {
|
|
252
|
+
const md = fs.readFileSync(path.join(a.path, 'APP.md'), 'utf8');
|
|
253
|
+
const runtime = (md.match(/^runtime:\s*(\S+)/m) || [])[1] || '?';
|
|
254
|
+
const access = (md.match(/^access:\s*(\S+)/m) || [])[1] || '?';
|
|
255
|
+
console.log(` ${a.slug.padEnd(28)} runtime=${runtime.padEnd(10)} access=${access}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function show(slug) {
|
|
260
|
+
if (!slug) {
|
|
261
|
+
console.error('✗ usage: atris app show <slug>');
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
const root = workspaceRoot();
|
|
265
|
+
const file = path.join(root, 'apps', slug, 'APP.md');
|
|
266
|
+
if (!fs.existsSync(file)) {
|
|
267
|
+
console.error(`✗ ${file} not found`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
process.stdout.write(fs.readFileSync(file, 'utf8'));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function help() {
|
|
274
|
+
console.log('atris app — manage APP.md manifests');
|
|
275
|
+
console.log('');
|
|
276
|
+
console.log('Subcommands:');
|
|
277
|
+
console.log(' init <slug> [--runtime <kind>] Scaffold a new app folder');
|
|
278
|
+
console.log(' list List apps in this workspace');
|
|
279
|
+
console.log(' show <slug> Print the APP.md for an app');
|
|
280
|
+
console.log('');
|
|
281
|
+
console.log(`Runtimes: ${RUNTIMES.join(', ')}`);
|
|
282
|
+
console.log('');
|
|
283
|
+
console.log('APP.md is the third agent-native primitive alongside MEMBER.md');
|
|
284
|
+
console.log('and SKILL.md. Spec: https://github.com/atrislabs/app.md');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function appCommand(subcommand, ...args) {
|
|
288
|
+
try {
|
|
289
|
+
switch (subcommand) {
|
|
290
|
+
case 'init':
|
|
291
|
+
await init(args[0], parseRuntimeFlag(args));
|
|
292
|
+
break;
|
|
293
|
+
case 'list':
|
|
294
|
+
case 'ls':
|
|
295
|
+
await list();
|
|
296
|
+
break;
|
|
297
|
+
case 'show':
|
|
298
|
+
case 'cat':
|
|
299
|
+
await show(args[0]);
|
|
300
|
+
break;
|
|
301
|
+
case 'help':
|
|
302
|
+
case undefined:
|
|
303
|
+
await help();
|
|
304
|
+
break;
|
|
305
|
+
default:
|
|
306
|
+
console.error(`✗ unknown subcommand: ${subcommand}`);
|
|
307
|
+
await help();
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error(`✗ ${err.message || err}`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
module.exports = { appCommand };
|