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
package/bin/atris.js
CHANGED
|
@@ -164,6 +164,7 @@ function showHelp() {
|
|
|
164
164
|
console.log('Setup:');
|
|
165
165
|
console.log(' init - Initialize Atris in current project');
|
|
166
166
|
console.log(' update - Update local files to latest version');
|
|
167
|
+
console.log(' upgrade - Install latest Atris from npm');
|
|
167
168
|
console.log('');
|
|
168
169
|
console.log('Core workflow:');
|
|
169
170
|
console.log(' plan - Create build spec with visualization');
|
|
@@ -191,10 +192,17 @@ function showHelp() {
|
|
|
191
192
|
console.log('Cloud & agents:');
|
|
192
193
|
console.log(' agent - Select which Atris agent to use');
|
|
193
194
|
console.log(' chat - Chat with the selected Atris agent');
|
|
194
|
-
console.log(' login - Authenticate
|
|
195
|
+
console.log(' login - Authenticate (use --token <t> for non-interactive)');
|
|
195
196
|
console.log(' logout - Remove credentials');
|
|
196
197
|
console.log(' whoami - Show auth status');
|
|
197
198
|
console.log('');
|
|
199
|
+
console.log('Integrations:');
|
|
200
|
+
console.log(' gmail - Email commands (inbox, read)');
|
|
201
|
+
console.log(' calendar - Calendar commands (today, week)');
|
|
202
|
+
console.log(' twitter - Twitter commands (post)');
|
|
203
|
+
console.log(' slack - Slack commands (channels)');
|
|
204
|
+
console.log(' integrations - Show integration status');
|
|
205
|
+
console.log('');
|
|
198
206
|
console.log('Other:');
|
|
199
207
|
console.log(' version - Show Atris version');
|
|
200
208
|
console.log(' help - Show this help');
|
|
@@ -303,8 +311,9 @@ const { verifyAtris: verifyCmd } = require('../commands/verify');
|
|
|
303
311
|
|
|
304
312
|
// Check if this is a known command or natural language input
|
|
305
313
|
const knownCommands = ['init', 'log', 'status', 'analytics', 'visualize', 'brainstorm', 'autopilot', 'plan', 'do', 'review',
|
|
306
|
-
'activate', 'agent', 'chat', 'login', 'logout', 'whoami', 'update', 'version', 'help', 'next', 'atris',
|
|
307
|
-
'clean', 'verify', 'search'
|
|
314
|
+
'activate', 'agent', 'chat', 'login', 'logout', 'whoami', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
|
|
315
|
+
'clean', 'verify', 'search',
|
|
316
|
+
'gmail', 'calendar', 'twitter', 'slack', 'integrations'];
|
|
308
317
|
|
|
309
318
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
310
319
|
function isSpecFile(cmd) {
|
|
@@ -616,6 +625,8 @@ if (command === 'init') {
|
|
|
616
625
|
activateCmd();
|
|
617
626
|
} else if (command === 'update') {
|
|
618
627
|
syncCmd();
|
|
628
|
+
} else if (command === 'upgrade') {
|
|
629
|
+
upgradeAtris();
|
|
619
630
|
} else if (command === 'chat') {
|
|
620
631
|
chatAtris()
|
|
621
632
|
.then(() => process.exit(0))
|
|
@@ -746,6 +757,39 @@ if (command === 'init') {
|
|
|
746
757
|
} else if (command === 'search') {
|
|
747
758
|
const keyword = process.argv.slice(3).join(' ');
|
|
748
759
|
searchJournal(keyword);
|
|
760
|
+
} else if (command === 'gmail') {
|
|
761
|
+
const { gmailCommand } = require('../commands/integrations');
|
|
762
|
+
const subcommand = process.argv[3];
|
|
763
|
+
const args = process.argv.slice(4);
|
|
764
|
+
gmailCommand(subcommand, ...args)
|
|
765
|
+
.then(() => process.exit(0))
|
|
766
|
+
.catch((err) => { console.error(err.message); process.exit(1); });
|
|
767
|
+
} else if (command === 'calendar') {
|
|
768
|
+
const { calendarCommand } = require('../commands/integrations');
|
|
769
|
+
const subcommand = process.argv[3];
|
|
770
|
+
const args = process.argv.slice(4);
|
|
771
|
+
calendarCommand(subcommand, ...args)
|
|
772
|
+
.then(() => process.exit(0))
|
|
773
|
+
.catch((err) => { console.error(err.message); process.exit(1); });
|
|
774
|
+
} else if (command === 'twitter') {
|
|
775
|
+
const { twitterCommand } = require('../commands/integrations');
|
|
776
|
+
const subcommand = process.argv[3];
|
|
777
|
+
const args = process.argv.slice(4);
|
|
778
|
+
twitterCommand(subcommand, ...args)
|
|
779
|
+
.then(() => process.exit(0))
|
|
780
|
+
.catch((err) => { console.error(err.message); process.exit(1); });
|
|
781
|
+
} else if (command === 'slack') {
|
|
782
|
+
const { slackCommand } = require('../commands/integrations');
|
|
783
|
+
const subcommand = process.argv[3];
|
|
784
|
+
const args = process.argv.slice(4);
|
|
785
|
+
slackCommand(subcommand, ...args)
|
|
786
|
+
.then(() => process.exit(0))
|
|
787
|
+
.catch((err) => { console.error(err.message); process.exit(1); });
|
|
788
|
+
} else if (command === 'integrations') {
|
|
789
|
+
const { integrationsStatus } = require('../commands/integrations');
|
|
790
|
+
integrationsStatus()
|
|
791
|
+
.then(() => process.exit(0))
|
|
792
|
+
.catch((err) => { console.error(err.message); process.exit(1); });
|
|
749
793
|
} else {
|
|
750
794
|
console.log(`Unknown command: ${command}`);
|
|
751
795
|
console.log('Run "atris help" to see available commands');
|
|
@@ -754,7 +798,7 @@ if (command === 'init') {
|
|
|
754
798
|
|
|
755
799
|
function initAtris() {
|
|
756
800
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
757
|
-
const
|
|
801
|
+
const teamDir = path.join(targetDir, 'team');
|
|
758
802
|
const sourceFile = path.join(__dirname, '..', 'atris.md');
|
|
759
803
|
const targetFile = path.join(targetDir, 'atris.md');
|
|
760
804
|
|
|
@@ -766,10 +810,10 @@ function initAtris() {
|
|
|
766
810
|
console.log('✓ atris/ folder already exists');
|
|
767
811
|
}
|
|
768
812
|
|
|
769
|
-
// Create
|
|
770
|
-
if (!fs.existsSync(
|
|
771
|
-
fs.mkdirSync(
|
|
772
|
-
console.log('✓ Created atris/
|
|
813
|
+
// Create team/ subfolder
|
|
814
|
+
if (!fs.existsSync(teamDir)) {
|
|
815
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
816
|
+
console.log('✓ Created atris/team/ folder');
|
|
773
817
|
}
|
|
774
818
|
|
|
775
819
|
// Create policies/ subfolder
|
|
@@ -784,10 +828,10 @@ function initAtris() {
|
|
|
784
828
|
const personaFile = path.join(targetDir, 'PERSONA.md');
|
|
785
829
|
const mapFile = path.join(targetDir, 'MAP.md');
|
|
786
830
|
const taskContextsFile = path.join(targetDir, 'TASK_CONTEXTS.md');
|
|
787
|
-
const navigatorFile = path.join(
|
|
788
|
-
const executorFile = path.join(
|
|
789
|
-
const validatorFile = path.join(
|
|
790
|
-
const launcherFile = path.join(
|
|
831
|
+
const navigatorFile = path.join(teamDir, 'navigator.md');
|
|
832
|
+
const executorFile = path.join(teamDir, 'executor.md');
|
|
833
|
+
const validatorFile = path.join(teamDir, 'validator.md');
|
|
834
|
+
const launcherFile = path.join(teamDir, 'launcher.md');
|
|
791
835
|
|
|
792
836
|
const gettingStartedSource = path.join(__dirname, '..', 'GETTING_STARTED.md');
|
|
793
837
|
const personaSource = path.join(__dirname, '..', 'PERSONA.md');
|
|
@@ -815,29 +859,29 @@ function initAtris() {
|
|
|
815
859
|
}
|
|
816
860
|
|
|
817
861
|
// Copy agent templates from package
|
|
818
|
-
const navigatorSource = path.join(__dirname, '..', 'atris', '
|
|
819
|
-
const executorSource = path.join(__dirname, '..', 'atris', '
|
|
820
|
-
const validatorSource = path.join(__dirname, '..', 'atris', '
|
|
821
|
-
const launcherSource = path.join(__dirname, '..', 'atris', '
|
|
862
|
+
const navigatorSource = path.join(__dirname, '..', 'atris', 'team', 'navigator.md');
|
|
863
|
+
const executorSource = path.join(__dirname, '..', 'atris', 'team', 'executor.md');
|
|
864
|
+
const validatorSource = path.join(__dirname, '..', 'atris', 'team', 'validator.md');
|
|
865
|
+
const launcherSource = path.join(__dirname, '..', 'atris', 'team', 'launcher.md');
|
|
822
866
|
|
|
823
867
|
if (!fs.existsSync(navigatorFile) && fs.existsSync(navigatorSource)) {
|
|
824
868
|
fs.copyFileSync(navigatorSource, navigatorFile);
|
|
825
|
-
console.log('✓ Created
|
|
869
|
+
console.log('✓ Created team/navigator.md');
|
|
826
870
|
}
|
|
827
871
|
|
|
828
872
|
if (!fs.existsSync(executorFile) && fs.existsSync(executorSource)) {
|
|
829
873
|
fs.copyFileSync(executorSource, executorFile);
|
|
830
|
-
console.log('✓ Created
|
|
874
|
+
console.log('✓ Created team/executor.md');
|
|
831
875
|
}
|
|
832
876
|
|
|
833
877
|
if (!fs.existsSync(validatorFile) && fs.existsSync(validatorSource)) {
|
|
834
878
|
fs.copyFileSync(validatorSource, validatorFile);
|
|
835
|
-
console.log('✓ Created
|
|
879
|
+
console.log('✓ Created team/validator.md');
|
|
836
880
|
}
|
|
837
881
|
|
|
838
882
|
if (!fs.existsSync(launcherFile) && fs.existsSync(launcherSource)) {
|
|
839
883
|
fs.copyFileSync(launcherSource, launcherFile);
|
|
840
|
-
console.log('✓ Created
|
|
884
|
+
console.log('✓ Created team/launcher.md');
|
|
841
885
|
}
|
|
842
886
|
|
|
843
887
|
// Copy policies from package
|
|
@@ -859,7 +903,7 @@ function initAtris() {
|
|
|
859
903
|
console.log(' ├── atris.md (AI agent instructions)');
|
|
860
904
|
console.log(' ├── MAP.md (placeholder)');
|
|
861
905
|
console.log(' ├── TASK_CONTEXTS.md (placeholder)');
|
|
862
|
-
console.log(' ├──
|
|
906
|
+
console.log(' ├── team/');
|
|
863
907
|
console.log(' │ ├── navigator.md');
|
|
864
908
|
console.log(' │ ├── executor.md');
|
|
865
909
|
console.log(' │ ├── validator.md');
|
|
@@ -878,7 +922,7 @@ function initAtris() {
|
|
|
878
922
|
|
|
879
923
|
function syncAtris() {
|
|
880
924
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
881
|
-
const
|
|
925
|
+
const teamDir = path.join(targetDir, 'team');
|
|
882
926
|
|
|
883
927
|
// Check if atris/ folder exists
|
|
884
928
|
if (!fs.existsSync(targetDir)) {
|
|
@@ -886,9 +930,9 @@ function syncAtris() {
|
|
|
886
930
|
process.exit(1);
|
|
887
931
|
}
|
|
888
932
|
|
|
889
|
-
// Ensure
|
|
890
|
-
if (!fs.existsSync(
|
|
891
|
-
fs.mkdirSync(
|
|
933
|
+
// Ensure team folder exists
|
|
934
|
+
if (!fs.existsSync(teamDir)) {
|
|
935
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
892
936
|
}
|
|
893
937
|
|
|
894
938
|
// Ensure policies folder exists
|
|
@@ -904,10 +948,10 @@ function syncAtris() {
|
|
|
904
948
|
{ source: 'atrisDev.md', target: 'atrisDev.md' },
|
|
905
949
|
{ source: 'PERSONA.md', target: 'PERSONA.md' },
|
|
906
950
|
{ source: 'GETTING_STARTED.md', target: 'GETTING_STARTED.md' },
|
|
907
|
-
{ source: 'atris/
|
|
908
|
-
{ source: 'atris/
|
|
909
|
-
{ source: 'atris/
|
|
910
|
-
{ source: 'atris/
|
|
951
|
+
{ source: 'atris/team/navigator.md', target: 'team/navigator.md' },
|
|
952
|
+
{ source: 'atris/team/executor.md', target: 'team/executor.md' },
|
|
953
|
+
{ source: 'atris/team/validator.md', target: 'team/validator.md' },
|
|
954
|
+
{ source: 'atris/team/launcher.md', target: 'team/launcher.md' },
|
|
911
955
|
{ source: 'atris/policies/ANTISLOP.md', target: 'policies/ANTISLOP.md' }
|
|
912
956
|
];
|
|
913
957
|
|
|
@@ -944,6 +988,55 @@ function syncAtris() {
|
|
|
944
988
|
}
|
|
945
989
|
}
|
|
946
990
|
|
|
991
|
+
async function upgradeAtris() {
|
|
992
|
+
console.log('');
|
|
993
|
+
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
994
|
+
console.log('│ Atris Upgrade │');
|
|
995
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
996
|
+
console.log('');
|
|
997
|
+
console.log(`Current version: ${CLI_VERSION}`);
|
|
998
|
+
console.log('');
|
|
999
|
+
console.log('Checking for updates...');
|
|
1000
|
+
|
|
1001
|
+
// Force check npm for latest version
|
|
1002
|
+
const updateInfo = await checkForUpdates(true);
|
|
1003
|
+
|
|
1004
|
+
if (!updateInfo || !updateInfo.needsUpdate) {
|
|
1005
|
+
console.log('');
|
|
1006
|
+
console.log('✓ You are on the latest version!');
|
|
1007
|
+
console.log('');
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
console.log('');
|
|
1012
|
+
console.log(`📦 Update available: ${updateInfo.installed} → ${updateInfo.latest}`);
|
|
1013
|
+
console.log('');
|
|
1014
|
+
console.log('Installing update...');
|
|
1015
|
+
console.log('');
|
|
1016
|
+
|
|
1017
|
+
// Run npm update -g atris
|
|
1018
|
+
const result = spawnSync('npm', ['update', '-g', 'atris'], {
|
|
1019
|
+
stdio: 'inherit',
|
|
1020
|
+
shell: true
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
if (result.status === 0) {
|
|
1024
|
+
console.log('');
|
|
1025
|
+
console.log('✓ Atris upgraded successfully!');
|
|
1026
|
+
console.log('');
|
|
1027
|
+
console.log('Run `atris update` in your projects to sync local files.');
|
|
1028
|
+
console.log('');
|
|
1029
|
+
} else {
|
|
1030
|
+
console.log('');
|
|
1031
|
+
console.log('✗ Upgrade failed. Try running manually:');
|
|
1032
|
+
console.log(' npm update -g atris');
|
|
1033
|
+
console.log('');
|
|
1034
|
+
console.log('If you see permission errors, try:');
|
|
1035
|
+
console.log(' sudo npm update -g atris');
|
|
1036
|
+
console.log('');
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
947
1040
|
// ============================================
|
|
948
1041
|
// Log System
|
|
949
1042
|
// ============================================
|
|
@@ -1884,7 +1977,7 @@ async function loginAtris() {
|
|
|
1884
1977
|
process.exit(0);
|
|
1885
1978
|
} else if (choice === '2') {
|
|
1886
1979
|
console.log('\n📋 Manual Token Entry');
|
|
1887
|
-
console.log('Get your token from: https://
|
|
1980
|
+
console.log('Get your token from: https://atris.ai/auth/cli\n');
|
|
1888
1981
|
|
|
1889
1982
|
const tokenInput = await promptUser('Paste your API token: ');
|
|
1890
1983
|
|
|
@@ -2209,7 +2302,7 @@ async function agentAtris() {
|
|
|
2209
2302
|
const agents = result.data?.my_agents || [];
|
|
2210
2303
|
|
|
2211
2304
|
if (agents.length === 0) {
|
|
2212
|
-
console.log('No agents found. Create one at https://
|
|
2305
|
+
console.log('No agents found. Create one at https://atris.ai');
|
|
2213
2306
|
process.exit(0);
|
|
2214
2307
|
}
|
|
2215
2308
|
|
|
@@ -2528,7 +2621,7 @@ async function atrisDevEntry(userInput = null) {
|
|
|
2528
2621
|
|
|
2529
2622
|
function launchAtris() {
|
|
2530
2623
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
2531
|
-
const launcherFile = path.join(targetDir, '
|
|
2624
|
+
const launcherFile = path.join(targetDir, 'team', 'launcher.md');
|
|
2532
2625
|
|
|
2533
2626
|
if (!fs.existsSync(launcherFile)) {
|
|
2534
2627
|
console.log('✗ launcher.md not found. Run "atris init" first.');
|
package/commands/auth.js
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
const { loadCredentials, saveCredentials, deleteCredentials, getCredentialsPath, openBrowser, promptUser, displayAccountSummary } = require('../utils/auth');
|
|
2
2
|
const { getAppBaseUrl, apiRequestJson } = require('../utils/api');
|
|
3
3
|
|
|
4
|
-
async function loginAtris() {
|
|
5
|
-
|
|
4
|
+
async function loginAtris(options = {}) {
|
|
5
|
+
// Support: atris login --token <token> --force
|
|
6
|
+
const args = process.argv.slice(3);
|
|
7
|
+
const forceFlag = args.includes('--force') || args.includes('-f') || options.force;
|
|
8
|
+
const tokenIndex = args.indexOf('--token');
|
|
9
|
+
const directToken = tokenIndex !== -1 ? args[tokenIndex + 1] : options.token;
|
|
10
|
+
|
|
6
11
|
try {
|
|
7
12
|
console.log('🔐 Login to AtrisOS\n');
|
|
8
13
|
|
|
9
14
|
const existing = loadCredentials();
|
|
10
|
-
|
|
15
|
+
|
|
16
|
+
// Direct token mode (non-interactive)
|
|
17
|
+
if (directToken) {
|
|
18
|
+
const trimmed = directToken.trim();
|
|
19
|
+
saveCredentials(trimmed, null, existing?.email || null, existing?.user_id || null, existing?.provider || 'manual');
|
|
20
|
+
console.log('Token saved. Validating…\n');
|
|
21
|
+
const summary = await displayAccountSummary(apiRequestJson);
|
|
22
|
+
if (summary.error) {
|
|
23
|
+
console.log('\n⚠️ Token saved, but validation failed.');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
console.log('\n✓ Logged in successfully.');
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (existing && !forceFlag) {
|
|
11
31
|
const label = existing.email || existing.user_id || 'unknown user';
|
|
12
32
|
console.log(`Already logged in as: ${label}`);
|
|
13
33
|
const confirm = await promptUser('Do you want to login again? (y/N): ');
|
|
@@ -70,7 +90,7 @@ async function loginAtris() {
|
|
|
70
90
|
process.exit(0);
|
|
71
91
|
} else if (choice === '2') {
|
|
72
92
|
console.log('\n📋 Manual Token Entry');
|
|
73
|
-
console.log('Get your token from: https://
|
|
93
|
+
console.log('Get your token from: https://atris.ai/auth/cli\n');
|
|
74
94
|
|
|
75
95
|
const tokenInput = await promptUser('Paste your API token: ');
|
|
76
96
|
|
package/commands/brainstorm.js
CHANGED
|
@@ -354,10 +354,10 @@ function generateWorkflowFile(workflowFile, metadata) {
|
|
|
354
354
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
355
355
|
|
|
356
356
|
// Load all context needed for agents
|
|
357
|
-
const navigatorFile = path.join(targetDir, '
|
|
358
|
-
const executorFile = path.join(targetDir, '
|
|
359
|
-
const validatorFile = path.join(targetDir, '
|
|
360
|
-
const launcherFile = path.join(targetDir, '
|
|
357
|
+
const navigatorFile = path.join(targetDir, 'team', 'navigator.md');
|
|
358
|
+
const executorFile = path.join(targetDir, 'team', 'executor.md');
|
|
359
|
+
const validatorFile = path.join(targetDir, 'team', 'validator.md');
|
|
360
|
+
const launcherFile = path.join(targetDir, 'team', 'launcher.md');
|
|
361
361
|
const personaFile = path.join(targetDir, 'PERSONA.md');
|
|
362
362
|
const mapFile = path.join(targetDir, 'MAP.md');
|
|
363
363
|
const todoFile = path.join(targetDir, 'TODO.md');
|
|
@@ -471,10 +471,10 @@ async function autopilotAtris(initialIdea = null) {
|
|
|
471
471
|
throw new Error('atris/ folder not found. Run "atris init" first.');
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
const navigatorFile = path.join(targetDir, '
|
|
475
|
-
const executorFile = path.join(targetDir, '
|
|
476
|
-
const validatorFile = path.join(targetDir, '
|
|
477
|
-
const launcherFile = path.join(targetDir, '
|
|
474
|
+
const navigatorFile = path.join(targetDir, 'team', 'navigator.md');
|
|
475
|
+
const executorFile = path.join(targetDir, 'team', 'executor.md');
|
|
476
|
+
const validatorFile = path.join(targetDir, 'team', 'validator.md');
|
|
477
|
+
const launcherFile = path.join(targetDir, 'team', 'launcher.md');
|
|
478
478
|
|
|
479
479
|
const missingSpecs = [];
|
|
480
480
|
if (!fs.existsSync(navigatorFile)) missingSpecs.push('navigator.md');
|
package/commands/init.js
CHANGED
|
@@ -46,10 +46,13 @@ function detectProjectContext(projectRoot = process.cwd()) {
|
|
|
46
46
|
try {
|
|
47
47
|
const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
|
48
48
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
49
|
+
// Check meta-frameworks first (they include base frameworks as deps)
|
|
50
|
+
if (deps.next) return 'next';
|
|
51
|
+
if (deps.nuxt) return 'nuxt';
|
|
52
|
+
if (deps.angular || deps['@angular/core']) return 'angular';
|
|
53
|
+
// Then base frameworks
|
|
49
54
|
if (deps.react || deps['react-dom']) return 'react';
|
|
50
55
|
if (deps.vue) return 'vue';
|
|
51
|
-
if (deps.angular || deps['@angular/core']) return 'angular';
|
|
52
|
-
if (deps.next) return 'next';
|
|
53
56
|
if (deps['express']) return 'express';
|
|
54
57
|
if (deps['fastify']) return 'fastify';
|
|
55
58
|
return 'nodejs';
|
|
@@ -150,7 +153,7 @@ function detectProjectContext(projectRoot = process.cwd()) {
|
|
|
150
153
|
|
|
151
154
|
/**
|
|
152
155
|
* Inject project-specific patterns into agent specs
|
|
153
|
-
* @param {string} agentTeamDir - Directory containing
|
|
156
|
+
* @param {string} agentTeamDir - Directory containing team specs
|
|
154
157
|
* @param {Object} profile - Project profile from detectProjectContext()
|
|
155
158
|
*/
|
|
156
159
|
function injectProjectPatterns(agentTeamDir, profile) {
|
|
@@ -229,7 +232,8 @@ ${profile.hasCode ? `**Validation:** Run \`${profile.testCommand}\` to verify ch
|
|
|
229
232
|
|
|
230
233
|
function initAtris() {
|
|
231
234
|
const targetDir = path.join(process.cwd(), 'atris');
|
|
232
|
-
const
|
|
235
|
+
const teamDir = path.join(targetDir, 'team');
|
|
236
|
+
const legacyAgentTeamDir = path.join(targetDir, 'agent_team');
|
|
233
237
|
const sourceFile = path.join(__dirname, '..', 'atris.md');
|
|
234
238
|
const targetFile = path.join(targetDir, 'atris.md');
|
|
235
239
|
|
|
@@ -240,20 +244,51 @@ function initAtris() {
|
|
|
240
244
|
console.log('✓ atris/ folder already exists');
|
|
241
245
|
}
|
|
242
246
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.log('
|
|
247
|
+
// MIGRATION: agent_team/ → team/ (v2.0.x → v2.1.0)
|
|
248
|
+
if (fs.existsSync(legacyAgentTeamDir)) {
|
|
249
|
+
console.log('');
|
|
250
|
+
console.log('📦 Migrating agent_team/ → team/ (v2.1.0 update)');
|
|
251
|
+
|
|
252
|
+
// Create team/ if it doesn't exist
|
|
253
|
+
if (!fs.existsSync(teamDir)) {
|
|
254
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Copy any custom files from agent_team/ to team/
|
|
258
|
+
const legacyFiles = fs.readdirSync(legacyAgentTeamDir);
|
|
259
|
+
for (const file of legacyFiles) {
|
|
260
|
+
const srcPath = path.join(legacyAgentTeamDir, file);
|
|
261
|
+
const destPath = path.join(teamDir, file);
|
|
262
|
+
|
|
263
|
+
// Only copy if destination doesn't exist (preserve any customizations)
|
|
264
|
+
if (!fs.existsSync(destPath)) {
|
|
265
|
+
if (fs.statSync(srcPath).isFile()) {
|
|
266
|
+
fs.copyFileSync(srcPath, destPath);
|
|
267
|
+
console.log(` ✓ Migrated ${file}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Remove old agent_team/ folder
|
|
273
|
+
fs.rmSync(legacyAgentTeamDir, { recursive: true, force: true });
|
|
274
|
+
console.log(' ✓ Removed old agent_team/ folder');
|
|
275
|
+
console.log('');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!fs.existsSync(teamDir)) {
|
|
279
|
+
fs.mkdirSync(teamDir, { recursive: true });
|
|
280
|
+
console.log('✓ Created atris/team/ folder');
|
|
246
281
|
}
|
|
247
282
|
|
|
248
283
|
const gettingStartedFile = path.join(targetDir, 'GETTING_STARTED.md');
|
|
249
284
|
const personaFile = path.join(targetDir, 'PERSONA.md');
|
|
250
285
|
const mapFile = path.join(targetDir, 'MAP.md');
|
|
251
286
|
const todoFile = path.join(targetDir, 'TODO.md');
|
|
252
|
-
const navigatorFile = path.join(
|
|
253
|
-
const executorFile = path.join(
|
|
254
|
-
const validatorFile = path.join(
|
|
255
|
-
const launcherFile = path.join(
|
|
256
|
-
const brainstormerFile = path.join(
|
|
287
|
+
const navigatorFile = path.join(teamDir, 'navigator.md');
|
|
288
|
+
const executorFile = path.join(teamDir, 'executor.md');
|
|
289
|
+
const validatorFile = path.join(teamDir, 'validator.md');
|
|
290
|
+
const launcherFile = path.join(teamDir, 'launcher.md');
|
|
291
|
+
const brainstormerFile = path.join(teamDir, 'brainstormer.md');
|
|
257
292
|
|
|
258
293
|
const gettingStartedSource = path.join(__dirname, '..', 'GETTING_STARTED.md');
|
|
259
294
|
const personaSource = path.join(__dirname, '..', 'PERSONA.md');
|
|
@@ -427,35 +462,35 @@ function initAtris() {
|
|
|
427
462
|
});
|
|
428
463
|
|
|
429
464
|
|
|
430
|
-
const navigatorSource = path.join(__dirname, '..', 'atris', '
|
|
431
|
-
const executorSource = path.join(__dirname, '..', 'atris', '
|
|
432
|
-
const validatorSource = path.join(__dirname, '..', 'atris', '
|
|
433
|
-
const launcherSource = path.join(__dirname, '..', 'atris', '
|
|
434
|
-
const brainstormerSource = path.join(__dirname, '..', 'atris', '
|
|
465
|
+
const navigatorSource = path.join(__dirname, '..', 'atris', 'team', 'navigator.md');
|
|
466
|
+
const executorSource = path.join(__dirname, '..', 'atris', 'team', 'executor.md');
|
|
467
|
+
const validatorSource = path.join(__dirname, '..', 'atris', 'team', 'validator.md');
|
|
468
|
+
const launcherSource = path.join(__dirname, '..', 'atris', 'team', 'launcher.md');
|
|
469
|
+
const brainstormerSource = path.join(__dirname, '..', 'atris', 'team', 'brainstormer.md');
|
|
435
470
|
|
|
436
471
|
if (!fs.existsSync(navigatorFile) && fs.existsSync(navigatorSource)) {
|
|
437
472
|
fs.copyFileSync(navigatorSource, navigatorFile);
|
|
438
|
-
console.log('✓ Created
|
|
473
|
+
console.log('✓ Created team/navigator.md');
|
|
439
474
|
}
|
|
440
475
|
|
|
441
476
|
if (!fs.existsSync(executorFile) && fs.existsSync(executorSource)) {
|
|
442
477
|
fs.copyFileSync(executorSource, executorFile);
|
|
443
|
-
console.log('✓ Created
|
|
478
|
+
console.log('✓ Created team/executor.md');
|
|
444
479
|
}
|
|
445
480
|
|
|
446
481
|
if (!fs.existsSync(validatorFile) && fs.existsSync(validatorSource)) {
|
|
447
482
|
fs.copyFileSync(validatorSource, validatorFile);
|
|
448
|
-
console.log('✓ Created
|
|
483
|
+
console.log('✓ Created team/validator.md');
|
|
449
484
|
}
|
|
450
485
|
|
|
451
486
|
if (!fs.existsSync(launcherFile) && fs.existsSync(launcherSource)) {
|
|
452
487
|
fs.copyFileSync(launcherSource, launcherFile);
|
|
453
|
-
console.log('✓ Created
|
|
488
|
+
console.log('✓ Created team/launcher.md');
|
|
454
489
|
}
|
|
455
490
|
|
|
456
491
|
if (!fs.existsSync(brainstormerFile) && fs.existsSync(brainstormerSource)) {
|
|
457
492
|
fs.copyFileSync(brainstormerSource, brainstormerFile);
|
|
458
|
-
console.log('✓ Created
|
|
493
|
+
console.log('✓ Created team/brainstormer.md');
|
|
459
494
|
}
|
|
460
495
|
|
|
461
496
|
// Detect project context and generate profile
|
|
@@ -465,8 +500,8 @@ function initAtris() {
|
|
|
465
500
|
console.log(`✓ Generated .project-profile.json (detected: ${profile.type}${profile.framework !== 'none' ? '/' + profile.framework : ''})`);
|
|
466
501
|
|
|
467
502
|
// Inject project patterns into agent specs
|
|
468
|
-
injectProjectPatterns(
|
|
469
|
-
console.log('✓ Injected project patterns into
|
|
503
|
+
injectProjectPatterns(teamDir, profile);
|
|
504
|
+
console.log('✓ Injected project patterns into team specs');
|
|
470
505
|
|
|
471
506
|
// Create agent instruction files for different tools
|
|
472
507
|
const agentInstructions = `# AGENTS.md — Universal Agent Instructions
|
|
@@ -560,6 +595,62 @@ Rules: 3-4 sentences max, ASCII visuals, check MAP.md first.`;
|
|
|
560
595
|
console.log('✓ Created .claude/commands/atris.md (for Claude Code)');
|
|
561
596
|
}
|
|
562
597
|
|
|
598
|
+
// .claude/commands/atris-autopilot.md for autonomous loops
|
|
599
|
+
const autopilotCommandFile = path.join(claudeCommandsDir, 'atris-autopilot.md');
|
|
600
|
+
if (!fs.existsSync(autopilotCommandFile)) {
|
|
601
|
+
fs.mkdirSync(claudeCommandsDir, { recursive: true });
|
|
602
|
+
const autopilotCommand = `---
|
|
603
|
+
description: PRD-driven autonomous execution - give it a task, it loops until done
|
|
604
|
+
arguments:
|
|
605
|
+
- name: task
|
|
606
|
+
description: What to build (e.g., "Add dark mode toggle")
|
|
607
|
+
required: true
|
|
608
|
+
- name: max-iterations
|
|
609
|
+
description: Max loops before stopping (default 10)
|
|
610
|
+
required: false
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
# Atris Autopilot
|
|
614
|
+
|
|
615
|
+
Autonomous mode. Loop until task complete or max iterations.
|
|
616
|
+
|
|
617
|
+
## Setup State
|
|
618
|
+
|
|
619
|
+
\`\`\`bash
|
|
620
|
+
mkdir -p .claude
|
|
621
|
+
cat > .claude/atris-autopilot.state.md << 'STATEEOF'
|
|
622
|
+
---
|
|
623
|
+
iteration: 1
|
|
624
|
+
max_iterations: \${2:-10}
|
|
625
|
+
completion_promise: <promise>COMPLETE</promise>
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
$1
|
|
629
|
+
STATEEOF
|
|
630
|
+
\`\`\`
|
|
631
|
+
|
|
632
|
+
## Task: $1
|
|
633
|
+
|
|
634
|
+
## Process (each iteration)
|
|
635
|
+
|
|
636
|
+
1. **PLAN** — Read MAP.md, identify ONE thing to do
|
|
637
|
+
2. **DO** — Implement it, commit
|
|
638
|
+
3. **REVIEW** — Check acceptance criteria
|
|
639
|
+
|
|
640
|
+
## Rules
|
|
641
|
+
|
|
642
|
+
- ONE thing per iteration
|
|
643
|
+
- Check MAP.md before touching code
|
|
644
|
+
- Search before assuming not implemented
|
|
645
|
+
- When done: \`<promise>COMPLETE</promise>\`
|
|
646
|
+
|
|
647
|
+
## Start
|
|
648
|
+
|
|
649
|
+
Read atris/MAP.md. Begin iteration 1.`;
|
|
650
|
+
fs.writeFileSync(autopilotCommandFile, autopilotCommand);
|
|
651
|
+
console.log('✓ Created .claude/commands/atris-autopilot.md (autonomous loops)');
|
|
652
|
+
}
|
|
653
|
+
|
|
563
654
|
// Copy skills from package to atris/skills/ and symlink to .claude/skills/
|
|
564
655
|
const skillsSourceDir = path.join(__dirname, '..', 'atris', 'skills');
|
|
565
656
|
const skillsTargetDir = path.join(targetDir, 'skills');
|
|
@@ -582,12 +673,21 @@ Rules: 3-4 sentences max, ASCII visuals, check MAP.md first.`;
|
|
|
582
673
|
const destSkillDir = path.join(skillsTargetDir, skill);
|
|
583
674
|
|
|
584
675
|
if (!fs.existsSync(destSkillDir)) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
676
|
+
// Recursive copy function for skills (handles subdirs like hooks/)
|
|
677
|
+
const copyRecursive = (src, dest) => {
|
|
678
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
679
|
+
const entries = fs.readdirSync(src);
|
|
680
|
+
for (const entry of entries) {
|
|
681
|
+
const srcPath = path.join(src, entry);
|
|
682
|
+
const destPath = path.join(dest, entry);
|
|
683
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
684
|
+
copyRecursive(srcPath, destPath);
|
|
685
|
+
} else {
|
|
686
|
+
fs.copyFileSync(srcPath, destPath);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
copyRecursive(srcSkillDir, destSkillDir);
|
|
591
691
|
console.log(`✓ Copied skill: ${skill}`);
|
|
592
692
|
}
|
|
593
693
|
}
|
|
@@ -659,6 +759,16 @@ Rules: 3-4 sentences max, ASCII visuals, check MAP.md first.`;
|
|
|
659
759
|
}
|
|
660
760
|
]
|
|
661
761
|
}
|
|
762
|
+
],
|
|
763
|
+
Stop: [
|
|
764
|
+
{
|
|
765
|
+
hooks: [
|
|
766
|
+
{
|
|
767
|
+
type: "command",
|
|
768
|
+
command: "atris/skills/autopilot/hooks/stop-hook.sh"
|
|
769
|
+
}
|
|
770
|
+
]
|
|
771
|
+
}
|
|
662
772
|
]
|
|
663
773
|
}
|
|
664
774
|
};
|