atris 2.0.21 → 2.2.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/AGENT.md +35 -0
- package/AGENTS.md +46 -0
- package/GETTING_STARTED.md +4 -4
- package/PERSONA.md +5 -1
- package/README.md +14 -6
- package/atris/AGENTS.md +25 -0
- package/atris/GEMINI.md +8 -0
- package/atris/GETTING_STARTED.md +4 -4
- package/atris/atris.md +3 -3
- package/atris/policies/LESSONS.md +1 -0
- package/atris/skills/README.md +19 -13
- package/atris/skills/autopilot/SKILL.md +97 -0
- package/atris/skills/autopilot/atris-autopilot.md +71 -0
- package/atris/skills/autopilot/hooks/stop-hook.sh +79 -0
- package/atris/skills/copy-editor/SKILL.md +471 -0
- package/atris/skills/email-agent/SKILL.md +288 -0
- package/atris/skills/memory/SKILL.md +5 -0
- package/atris/{agent_team → team}/executor.md +26 -0
- package/atris/{agent_team → team}/navigator.md +42 -5
- package/atris/{agent_team → team}/validator.md +29 -3
- package/atris.md +23 -4
- package/bin/atris.js +125 -32
- package/commands/auth.js +24 -4
- package/commands/brainstorm.js +8 -8
- package/commands/init.js +140 -30
- package/commands/integrations.js +330 -0
- package/commands/sync.js +69 -24
- package/commands/workflow.js +3 -3
- package/package.json +5 -3
- package/utils/auth.js +33 -0
- package/commands/stubs.txt +0 -10
- /package/atris/{agent_team → team}/brainstormer.md +0 -0
- /package/atris/{agent_team → team}/launcher.md +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration commands for Atris CLI
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* atris gmail inbox - List recent emails
|
|
6
|
+
* atris gmail read <id> - Read specific email
|
|
7
|
+
* atris calendar today - Show today's events
|
|
8
|
+
* atris calendar week - Show this week's events
|
|
9
|
+
* atris twitter post - Post a tweet (interactive)
|
|
10
|
+
* atris slack channels - List Slack channels
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { loadCredentials } = require('../utils/auth');
|
|
14
|
+
const { apiRequestJson } = require('../utils/api');
|
|
15
|
+
|
|
16
|
+
async function getAuthToken() {
|
|
17
|
+
const creds = loadCredentials();
|
|
18
|
+
if (!creds || !creds.token) {
|
|
19
|
+
console.error('Not logged in. Run: atris login');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
return creds.token;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// GMAIL
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
async function gmailInbox(options = {}) {
|
|
30
|
+
const token = await getAuthToken();
|
|
31
|
+
const limit = options.limit || 10;
|
|
32
|
+
|
|
33
|
+
console.log('📬 Fetching inbox...\n');
|
|
34
|
+
|
|
35
|
+
const result = await apiRequestJson(`/integrations/gmail/messages?max_results=${limit}`, {
|
|
36
|
+
method: 'GET',
|
|
37
|
+
token,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!result.ok) {
|
|
41
|
+
if (result.status === 401) {
|
|
42
|
+
console.error('Gmail not connected. Connect at: https://atris.ai/dashboard/settings');
|
|
43
|
+
} else {
|
|
44
|
+
console.error(`Error: ${result.error || 'Failed to fetch inbox'}`);
|
|
45
|
+
}
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const messages = result.data?.messages || result.data || [];
|
|
50
|
+
|
|
51
|
+
if (messages.length === 0) {
|
|
52
|
+
console.log('No messages found.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log(`Found ${messages.length} messages:\n`);
|
|
57
|
+
console.log('─'.repeat(60));
|
|
58
|
+
|
|
59
|
+
for (const msg of messages) {
|
|
60
|
+
const from = msg.from || msg.sender || 'Unknown';
|
|
61
|
+
const subject = msg.subject || '(no subject)';
|
|
62
|
+
const date = msg.date || msg.received_at || '';
|
|
63
|
+
const id = msg.id || msg.message_id || '';
|
|
64
|
+
|
|
65
|
+
console.log(`From: ${from}`);
|
|
66
|
+
console.log(`Subj: ${subject}`);
|
|
67
|
+
console.log(`Date: ${date}`);
|
|
68
|
+
console.log(`ID: ${id}`);
|
|
69
|
+
console.log('─'.repeat(60));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function gmailRead(messageId) {
|
|
74
|
+
if (!messageId) {
|
|
75
|
+
console.error('Usage: atris gmail read <message_id>');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const token = await getAuthToken();
|
|
80
|
+
|
|
81
|
+
console.log('📧 Fetching message...\n');
|
|
82
|
+
|
|
83
|
+
const result = await apiRequestJson(`/integrations/gmail/messages/${messageId}`, {
|
|
84
|
+
method: 'GET',
|
|
85
|
+
token,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
console.error(`Error: ${result.error || 'Failed to fetch message'}`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const msg = result.data;
|
|
94
|
+
|
|
95
|
+
console.log('─'.repeat(60));
|
|
96
|
+
console.log(`From: ${msg.from || 'Unknown'}`);
|
|
97
|
+
console.log(`To: ${msg.to || 'Unknown'}`);
|
|
98
|
+
console.log(`Subject: ${msg.subject || '(no subject)'}`);
|
|
99
|
+
console.log(`Date: ${msg.date || ''}`);
|
|
100
|
+
console.log('─'.repeat(60));
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(msg.body || msg.snippet || '(no body)');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function gmailCommand(subcommand, ...args) {
|
|
106
|
+
switch (subcommand) {
|
|
107
|
+
case 'inbox':
|
|
108
|
+
case 'list':
|
|
109
|
+
await gmailInbox();
|
|
110
|
+
break;
|
|
111
|
+
case 'read':
|
|
112
|
+
await gmailRead(args[0]);
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
console.log('Gmail commands:');
|
|
116
|
+
console.log(' atris gmail inbox - List recent emails');
|
|
117
|
+
console.log(' atris gmail read <id> - Read specific email');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// CALENDAR
|
|
123
|
+
// ============================================================================
|
|
124
|
+
|
|
125
|
+
async function calendarToday() {
|
|
126
|
+
const token = await getAuthToken();
|
|
127
|
+
|
|
128
|
+
console.log('📅 Today\'s events:\n');
|
|
129
|
+
|
|
130
|
+
const result = await apiRequestJson('/integrations/google-calendar/events/today', {
|
|
131
|
+
method: 'GET',
|
|
132
|
+
token,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
if (result.status === 401) {
|
|
137
|
+
console.error('Calendar not connected. Connect at: https://atris.ai/dashboard/settings');
|
|
138
|
+
} else {
|
|
139
|
+
console.error(`Error: ${result.error || 'Failed to fetch events'}`);
|
|
140
|
+
}
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const events = result.data?.events || result.data || [];
|
|
145
|
+
|
|
146
|
+
if (events.length === 0) {
|
|
147
|
+
console.log('No events today. 🎉');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
console.log('─'.repeat(50));
|
|
152
|
+
|
|
153
|
+
for (const event of events) {
|
|
154
|
+
const start = event.start?.dateTime || event.start?.date || '';
|
|
155
|
+
const time = start ? new Date(start).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }) : 'All day';
|
|
156
|
+
const title = event.summary || '(no title)';
|
|
157
|
+
|
|
158
|
+
console.log(`${time} ${title}`);
|
|
159
|
+
if (event.location) {
|
|
160
|
+
console.log(` 📍 ${event.location}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log('─'.repeat(50));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function calendarCommand(subcommand, ...args) {
|
|
168
|
+
switch (subcommand) {
|
|
169
|
+
case 'today':
|
|
170
|
+
await calendarToday();
|
|
171
|
+
break;
|
|
172
|
+
case 'week':
|
|
173
|
+
console.log('Week view coming soon...');
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
console.log('Calendar commands:');
|
|
177
|
+
console.log(' atris calendar today - Show today\'s events');
|
|
178
|
+
console.log(' atris calendar week - Show this week\'s events');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// TWITTER
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
async function twitterPost(text) {
|
|
187
|
+
const token = await getAuthToken();
|
|
188
|
+
|
|
189
|
+
if (!text) {
|
|
190
|
+
const readline = require('readline');
|
|
191
|
+
const rl = readline.createInterface({
|
|
192
|
+
input: process.stdin,
|
|
193
|
+
output: process.stdout
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
text = await new Promise((resolve) => {
|
|
197
|
+
rl.question('Tweet: ', (answer) => {
|
|
198
|
+
rl.close();
|
|
199
|
+
resolve(answer.trim());
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!text) {
|
|
205
|
+
console.error('Tweet text is required');
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log('\n🐦 Posting tweet...');
|
|
210
|
+
|
|
211
|
+
const result = await apiRequestJson('/integrations/twitter/tweet', {
|
|
212
|
+
method: 'POST',
|
|
213
|
+
token,
|
|
214
|
+
body: { text },
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (!result.ok) {
|
|
218
|
+
if (result.status === 401) {
|
|
219
|
+
console.error('Twitter not connected. Connect at: https://atris.ai/dashboard/settings');
|
|
220
|
+
} else {
|
|
221
|
+
console.error(`Error: ${result.error || 'Failed to post tweet'}`);
|
|
222
|
+
}
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
console.log('✓ Tweet posted!');
|
|
227
|
+
if (result.data?.id) {
|
|
228
|
+
console.log(` https://twitter.com/i/status/${result.data.id}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function twitterCommand(subcommand, ...args) {
|
|
233
|
+
switch (subcommand) {
|
|
234
|
+
case 'post':
|
|
235
|
+
case 'tweet':
|
|
236
|
+
await twitterPost(args.join(' '));
|
|
237
|
+
break;
|
|
238
|
+
default:
|
|
239
|
+
console.log('Twitter commands:');
|
|
240
|
+
console.log(' atris twitter post [text] - Post a tweet');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ============================================================================
|
|
245
|
+
// SLACK
|
|
246
|
+
// ============================================================================
|
|
247
|
+
|
|
248
|
+
async function slackChannels() {
|
|
249
|
+
const token = await getAuthToken();
|
|
250
|
+
|
|
251
|
+
console.log('💬 Fetching Slack channels...\n');
|
|
252
|
+
|
|
253
|
+
const result = await apiRequestJson('/integrations/slack/channels', {
|
|
254
|
+
method: 'GET',
|
|
255
|
+
token,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if (!result.ok) {
|
|
259
|
+
if (result.status === 401) {
|
|
260
|
+
console.error('Slack not connected. Connect at: https://atris.ai/dashboard/settings');
|
|
261
|
+
} else {
|
|
262
|
+
console.error(`Error: ${result.error || 'Failed to fetch channels'}`);
|
|
263
|
+
}
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const channels = result.data?.channels || result.data || [];
|
|
268
|
+
|
|
269
|
+
if (channels.length === 0) {
|
|
270
|
+
console.log('No channels found.');
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.log('Channels:');
|
|
275
|
+
for (const ch of channels) {
|
|
276
|
+
const name = ch.name || ch.id;
|
|
277
|
+
const priv = ch.is_private ? '🔒' : '#';
|
|
278
|
+
console.log(` ${priv} ${name}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async function slackCommand(subcommand, ...args) {
|
|
283
|
+
switch (subcommand) {
|
|
284
|
+
case 'channels':
|
|
285
|
+
case 'list':
|
|
286
|
+
await slackChannels();
|
|
287
|
+
break;
|
|
288
|
+
default:
|
|
289
|
+
console.log('Slack commands:');
|
|
290
|
+
console.log(' atris slack channels - List Slack channels');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ============================================================================
|
|
295
|
+
// STATUS
|
|
296
|
+
// ============================================================================
|
|
297
|
+
|
|
298
|
+
async function integrationsStatus() {
|
|
299
|
+
const token = await getAuthToken();
|
|
300
|
+
|
|
301
|
+
console.log('🔌 Integration Status:\n');
|
|
302
|
+
|
|
303
|
+
const integrations = ['gmail', 'google-calendar', 'slack', 'twitter', 'github'];
|
|
304
|
+
|
|
305
|
+
for (const name of integrations) {
|
|
306
|
+
try {
|
|
307
|
+
const result = await apiRequestJson(`/integrations/${name}/status`, {
|
|
308
|
+
method: 'GET',
|
|
309
|
+
token,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const connected = result.ok && result.data?.connected;
|
|
313
|
+
const icon = connected ? '✅' : '❌';
|
|
314
|
+
const displayName = name.replace('google-', '').replace('-', ' ');
|
|
315
|
+
console.log(` ${icon} ${displayName}`);
|
|
316
|
+
} catch {
|
|
317
|
+
console.log(` ❓ ${name}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
console.log('\nConnect integrations at: https://atris.ai/dashboard/settings');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
module.exports = {
|
|
325
|
+
gmailCommand,
|
|
326
|
+
calendarCommand,
|
|
327
|
+
twitterCommand,
|
|
328
|
+
slackCommand,
|
|
329
|
+
integrationsStatus,
|
|
330
|
+
};
|
package/commands/sync.js
CHANGED
|
@@ -3,15 +3,47 @@ const path = require('path');
|
|
|
3
3
|
|
|
4
4
|
function syncAtris() {
|
|
5
5
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
6
|
-
const
|
|
6
|
+
const teamDir = path.join(targetDir, 'team');
|
|
7
|
+
const legacyAgentTeamDir = path.join(targetDir, 'agent_team');
|
|
7
8
|
|
|
8
9
|
if (!fs.existsSync(targetDir)) {
|
|
9
10
|
console.error('✗ Error: atris/ folder not found. Run "atris init" first.');
|
|
10
11
|
process.exit(1);
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
// MIGRATION: agent_team/ → team/ (v2.0.x → v2.1.0)
|
|
15
|
+
if (fs.existsSync(legacyAgentTeamDir)) {
|
|
16
|
+
console.log('');
|
|
17
|
+
console.log('📦 Migrating agent_team/ → team/ (v2.1.0 update)');
|
|
18
|
+
|
|
19
|
+
// Create team/ if it doesn't exist
|
|
20
|
+
if (!fs.existsSync(teamDir)) {
|
|
21
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Copy any custom files from agent_team/ to team/
|
|
25
|
+
const legacyFiles = fs.readdirSync(legacyAgentTeamDir);
|
|
26
|
+
for (const file of legacyFiles) {
|
|
27
|
+
const srcPath = path.join(legacyAgentTeamDir, file);
|
|
28
|
+
const destPath = path.join(teamDir, file);
|
|
29
|
+
|
|
30
|
+
// Only copy if destination doesn't exist (preserve any customizations)
|
|
31
|
+
if (!fs.existsSync(destPath)) {
|
|
32
|
+
if (fs.statSync(srcPath).isFile()) {
|
|
33
|
+
fs.copyFileSync(srcPath, destPath);
|
|
34
|
+
console.log(` ✓ Migrated ${file}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Remove old agent_team/ folder
|
|
40
|
+
fs.rmSync(legacyAgentTeamDir, { recursive: true, force: true });
|
|
41
|
+
console.log(' ✓ Removed old agent_team/ folder');
|
|
42
|
+
console.log('');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(teamDir)) {
|
|
46
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
15
47
|
}
|
|
16
48
|
|
|
17
49
|
// Ensure policies folder exists
|
|
@@ -27,11 +59,11 @@ function syncAtris() {
|
|
|
27
59
|
{ source: 'PERSONA.md', target: 'PERSONA.md' },
|
|
28
60
|
{ source: 'GETTING_STARTED.md', target: 'GETTING_STARTED.md' },
|
|
29
61
|
{ source: 'atris/CLAUDE.md', target: 'CLAUDE.md' },
|
|
30
|
-
{ source: 'atris/
|
|
31
|
-
{ source: 'atris/
|
|
32
|
-
{ source: 'atris/
|
|
33
|
-
{ source: 'atris/
|
|
34
|
-
{ source: 'atris/
|
|
62
|
+
{ source: 'atris/team/navigator.md', target: 'team/navigator.md' },
|
|
63
|
+
{ source: 'atris/team/executor.md', target: 'team/executor.md' },
|
|
64
|
+
{ source: 'atris/team/validator.md', target: 'team/validator.md' },
|
|
65
|
+
{ source: 'atris/team/launcher.md', target: 'team/launcher.md' },
|
|
66
|
+
{ source: 'atris/team/brainstormer.md', target: 'team/brainstormer.md' },
|
|
35
67
|
{ source: 'atris/policies/ANTISLOP.md', target: 'policies/ANTISLOP.md' }
|
|
36
68
|
];
|
|
37
69
|
|
|
@@ -93,23 +125,36 @@ function syncAtris() {
|
|
|
93
125
|
const destSkillDir = path.join(userSkillsDir, skill);
|
|
94
126
|
const symlinkPath = path.join(claudeSkillsBaseDir, skill);
|
|
95
127
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
fs.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Copy/update SKILL.md
|
|
102
|
-
const srcSkillFile = path.join(srcSkillDir, 'SKILL.md');
|
|
103
|
-
const destSkillFile = path.join(destSkillDir, 'SKILL.md');
|
|
104
|
-
if (fs.existsSync(srcSkillFile)) {
|
|
105
|
-
const srcContent = fs.readFileSync(srcSkillFile, 'utf8');
|
|
106
|
-
const destContent = fs.existsSync(destSkillFile) ? fs.readFileSync(destSkillFile, 'utf8') : '';
|
|
107
|
-
if (srcContent !== destContent) {
|
|
108
|
-
fs.writeFileSync(destSkillFile, srcContent);
|
|
109
|
-
console.log(`✓ Updated atris/skills/${skill}/SKILL.md`);
|
|
110
|
-
updated++;
|
|
128
|
+
// Recursive sync function for skills (handles subdirs like hooks/)
|
|
129
|
+
const syncRecursive = (src, dest, skillName, basePath = '') => {
|
|
130
|
+
if (!fs.existsSync(dest)) {
|
|
131
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
111
132
|
}
|
|
112
|
-
|
|
133
|
+
const entries = fs.readdirSync(src);
|
|
134
|
+
for (const entry of entries) {
|
|
135
|
+
const srcPath = path.join(src, entry);
|
|
136
|
+
const destPath = path.join(dest, entry);
|
|
137
|
+
const relPath = basePath ? `${basePath}/${entry}` : entry;
|
|
138
|
+
|
|
139
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
140
|
+
syncRecursive(srcPath, destPath, skillName, relPath);
|
|
141
|
+
} else {
|
|
142
|
+
const srcContent = fs.readFileSync(srcPath, 'utf8');
|
|
143
|
+
const destContent = fs.existsSync(destPath) ? fs.readFileSync(destPath, 'utf8') : '';
|
|
144
|
+
if (srcContent !== destContent) {
|
|
145
|
+
fs.writeFileSync(destPath, srcContent);
|
|
146
|
+
// Preserve executable permission for shell scripts
|
|
147
|
+
if (entry.endsWith('.sh')) {
|
|
148
|
+
fs.chmodSync(destPath, 0o755);
|
|
149
|
+
}
|
|
150
|
+
console.log(`✓ Updated atris/skills/${skillName}/${relPath}`);
|
|
151
|
+
updated++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
syncRecursive(srcSkillDir, destSkillDir, skill);
|
|
113
158
|
|
|
114
159
|
// Create symlink if doesn't exist
|
|
115
160
|
if (!fs.existsSync(symlinkPath)) {
|
package/commands/workflow.js
CHANGED
|
@@ -14,7 +14,7 @@ async function planAtris(userInput = null) {
|
|
|
14
14
|
const executionMode = executeFlag ? 'agent' : (config.execution_mode || 'prompt');
|
|
15
15
|
|
|
16
16
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
17
|
-
const navigatorFile = path.join(targetDir, '
|
|
17
|
+
const navigatorFile = path.join(targetDir, 'team', 'navigator.md');
|
|
18
18
|
const personaPath = path.join(targetDir, 'PERSONA.md');
|
|
19
19
|
const mapFilePath = path.join(targetDir, 'MAP.md');
|
|
20
20
|
const featuresReadmePath = path.join(targetDir, 'features', 'README.md');
|
|
@@ -307,7 +307,7 @@ async function doAtris() {
|
|
|
307
307
|
|
|
308
308
|
const cwd = process.cwd();
|
|
309
309
|
const targetDir = path.join(cwd, 'atris');
|
|
310
|
-
const executorFile = path.join(targetDir, '
|
|
310
|
+
const executorFile = path.join(targetDir, 'team', 'executor.md');
|
|
311
311
|
|
|
312
312
|
if (!fs.existsSync(executorFile)) {
|
|
313
313
|
console.log('✗ executor.md not found. Run "atris init" first.');
|
|
@@ -676,7 +676,7 @@ async function reviewAtris() {
|
|
|
676
676
|
const executionMode = executeFlag ? 'agent' : (config.execution_mode || 'prompt');
|
|
677
677
|
|
|
678
678
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
679
|
-
const validatorFile = path.join(targetDir, '
|
|
679
|
+
const validatorFile = path.join(targetDir, 'team', 'validator.md');
|
|
680
680
|
|
|
681
681
|
if (!fs.existsSync(validatorFile)) {
|
|
682
682
|
console.log('✗ validator.md not found. Run "atris init" first.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atris",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "atrisDev (atris dev) - CLI for AI coding agents. Works with Claude Code, Cursor, Windsurf. Make any codebase AI-navigable.",
|
|
5
5
|
"main": "bin/atris.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
"utils/",
|
|
13
13
|
"lib/",
|
|
14
14
|
"README.md",
|
|
15
|
+
"AGENT.md",
|
|
16
|
+
"AGENTS.md",
|
|
15
17
|
"atris.md",
|
|
16
18
|
"GETTING_STARTED.md",
|
|
17
19
|
"PERSONA.md",
|
|
18
20
|
"atris/CLAUDE.md",
|
|
19
21
|
"atris/GEMINI.md",
|
|
20
|
-
"atris/
|
|
22
|
+
"atris/team/",
|
|
21
23
|
"atris/features/_templates/",
|
|
22
24
|
"atris/policies/",
|
|
23
25
|
"atris/skills/"
|
|
@@ -44,6 +46,6 @@
|
|
|
44
46
|
"license": "MIT",
|
|
45
47
|
"repository": {
|
|
46
48
|
"type": "git",
|
|
47
|
-
"url": "git+https://github.com/atrislabs/atris.
|
|
49
|
+
"url": "git+https://github.com/atrislabs/atris.git"
|
|
48
50
|
}
|
|
49
51
|
}
|
package/utils/auth.js
CHANGED
|
@@ -23,7 +23,40 @@ function openBrowser(url) {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// Shared readline for piped input
|
|
27
|
+
let sharedRl = null;
|
|
28
|
+
let inputLines = [];
|
|
29
|
+
let inputIndex = 0;
|
|
30
|
+
|
|
26
31
|
function promptUser(question) {
|
|
32
|
+
// If stdin is not a TTY (piped input), read all lines upfront
|
|
33
|
+
if (!process.stdin.isTTY && inputLines.length === 0 && !sharedRl) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let data = '';
|
|
36
|
+
process.stdin.setEncoding('utf8');
|
|
37
|
+
process.stdin.on('data', chunk => data += chunk);
|
|
38
|
+
process.stdin.on('end', () => {
|
|
39
|
+
inputLines = data.trim().split('\n');
|
|
40
|
+
process.stdout.write(question);
|
|
41
|
+
const answer = inputLines[inputIndex++] || '';
|
|
42
|
+
console.log(answer);
|
|
43
|
+
resolve(answer.trim());
|
|
44
|
+
});
|
|
45
|
+
process.stdin.resume();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If we already have buffered lines from piped input
|
|
50
|
+
if (inputLines.length > 0 && inputIndex < inputLines.length) {
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
process.stdout.write(question);
|
|
53
|
+
const answer = inputLines[inputIndex++] || '';
|
|
54
|
+
console.log(answer);
|
|
55
|
+
resolve(answer.trim());
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Interactive TTY mode - create readline per prompt
|
|
27
60
|
const rl = readline.createInterface({
|
|
28
61
|
input: process.stdin,
|
|
29
62
|
output: process.stdout
|
package/commands/stubs.txt
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
Still need to create:
|
|
2
|
-
- visualize.js (read from bin/atris.js lines 1825-1889)
|
|
3
|
-
- plan.js (lines 2639-2700)
|
|
4
|
-
- do.js (lines 2702-2874)
|
|
5
|
-
- console.js (lines 2876-3024)
|
|
6
|
-
- review.js (lines 3026-3109)
|
|
7
|
-
- launch.js (lines 3111-3184)
|
|
8
|
-
- status.js (lines 3186-3307)
|
|
9
|
-
- analytics.js (lines 3477-3611)
|
|
10
|
-
- autopilot.js (lines 2183-2408)
|
|
File without changes
|
|
File without changes
|