atris 3.34.0 → 3.35.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/AGENTS.md +0 -2
- package/FOR_AGENTS.md +5 -3
- package/atris/skills/engines/SKILL.md +16 -7
- package/atris/skills/render-cli/SKILL.md +88 -0
- package/atris.md +4 -2
- package/ax +475 -17
- package/bin/atris.js +197 -44
- package/commands/aeo.js +52 -0
- package/commands/autoland.js +313 -19
- package/commands/business.js +91 -8
- package/commands/codex-goal.js +26 -2
- package/commands/drive.js +187 -0
- package/commands/engine.js +73 -2
- package/commands/feed.js +202 -0
- package/commands/github.js +38 -0
- package/commands/gm.js +262 -3
- package/commands/init.js +13 -1
- package/commands/integrations.js +39 -11
- package/commands/interview.js +143 -0
- package/commands/land.js +114 -13
- package/commands/lesson.js +112 -1
- package/commands/linear.js +38 -0
- package/commands/member.js +398 -42
- package/commands/mission.js +554 -64
- package/commands/now.js +25 -1
- package/commands/radar.js +259 -14
- package/commands/serve.js +54 -0
- package/commands/status.js +50 -5
- package/commands/stripe.js +38 -0
- package/commands/supabase.js +39 -0
- package/commands/task.js +935 -71
- package/commands/truth.js +29 -3
- package/commands/unknowns.js +627 -0
- package/commands/update.js +44 -0
- package/commands/vercel.js +38 -0
- package/commands/worktree.js +68 -10
- package/commands/write.js +399 -0
- package/lib/auto-accept-certified.js +70 -19
- package/lib/autoland.js +39 -3
- package/lib/fleet.js +250 -9
- package/lib/memory-view.js +14 -5
- package/lib/mission-runtime-loop.js +7 -0
- package/lib/official-cli-integration.js +174 -0
- package/lib/outbound-send-gate.js +165 -0
- package/lib/permission-grants.js +293 -0
- package/lib/review-integrity.js +147 -0
- package/lib/runner-command.js +23 -0
- package/lib/task-db.js +220 -7
- package/lib/task-proof.js +20 -0
- package/lib/task-receipt.js +93 -0
- package/package.json +1 -1
- package/utils/update-check.js +27 -6
- package/atris/learnings.jsonl +0 -1
package/bin/atris.js
CHANGED
|
@@ -29,7 +29,6 @@ try {
|
|
|
29
29
|
const {
|
|
30
30
|
checkForUpdates,
|
|
31
31
|
showUpdateNotification,
|
|
32
|
-
autoUpdate,
|
|
33
32
|
inspectInstallGitState,
|
|
34
33
|
formatInstallGitWarning,
|
|
35
34
|
} = require('../utils/update-check');
|
|
@@ -91,14 +90,10 @@ const skipUpdateCheck = Boolean(process.env.ATRIS_SKIP_UPDATE_CHECK || process.e
|
|
|
91
90
|
if (!skipUpdateCheck && (!updateCommand || (updateCommand && !['version', 'update'].includes(updateCommand)))) {
|
|
92
91
|
updateCheckPromise = checkForUpdates()
|
|
93
92
|
.then((updateInfo) => {
|
|
94
|
-
// Show notification if update available (after command completes)
|
|
95
93
|
if (updateInfo) {
|
|
96
|
-
|
|
94
|
+
showUpdateNotification(updateInfo, {
|
|
97
95
|
packageRoot: path.join(__dirname, '..'),
|
|
98
96
|
});
|
|
99
|
-
if (!autoUpdateStarted) {
|
|
100
|
-
showUpdateNotification(updateInfo);
|
|
101
|
-
}
|
|
102
97
|
}
|
|
103
98
|
return updateInfo;
|
|
104
99
|
})
|
|
@@ -469,8 +464,8 @@ function showHelp() {
|
|
|
469
464
|
console.log(' 3. Atris acts with context, memory, tools, and a review loop');
|
|
470
465
|
console.log('');
|
|
471
466
|
console.log('Common invocations:');
|
|
472
|
-
console.log(' atris init
|
|
473
|
-
console.log(' npx atris init
|
|
467
|
+
console.log(' atris init [--yes] Global install: initialize this project');
|
|
468
|
+
console.log(' npx atris init [--yes] Local install: initialize this project');
|
|
474
469
|
console.log(' atris computer');
|
|
475
470
|
console.log(' atris business init "My Company"');
|
|
476
471
|
console.log(' atris run');
|
|
@@ -487,7 +482,7 @@ function showHelp() {
|
|
|
487
482
|
console.log('');
|
|
488
483
|
console.log('Setup:');
|
|
489
484
|
console.log(' setup - Guided first-time setup (login, pick business, pull)');
|
|
490
|
-
console.log(' init - Initialize Atris in current project');
|
|
485
|
+
console.log(' init - Initialize Atris in current project (--yes skips prompts)');
|
|
491
486
|
console.log(' update - Update local files to latest version');
|
|
492
487
|
console.log(' upgrade - Install latest Atris from npm');
|
|
493
488
|
console.log('');
|
|
@@ -517,6 +512,12 @@ function showHelp() {
|
|
|
517
512
|
console.log(' harvest - Find bugs and next actions from receipts, run logs, and thinking');
|
|
518
513
|
console.log(' verify - Validate work is done (tests, MAP.md, changes)');
|
|
519
514
|
console.log(' task - Local agent task plane (atomic claims, TODO import)');
|
|
515
|
+
console.log(' golden path (zero human turns):');
|
|
516
|
+
console.log(' atris task delegate "fix the login bug" --to <member>');
|
|
517
|
+
console.log(' atris task claim <id> --as <member>');
|
|
518
|
+
console.log(' ... build ...');
|
|
519
|
+
console.log(' atris task ready <id> --verify');
|
|
520
|
+
console.log(' atris autoland tick # second check runs, task lands');
|
|
520
521
|
console.log(' mission - Goal + loop + member owner + verifier + receipt');
|
|
521
522
|
console.log(' release - Tag release, bump version, create GitHub release, draft /launch');
|
|
522
523
|
console.log(' learn - Project learnings (patterns, pitfalls, preferences)');
|
|
@@ -526,6 +527,7 @@ function showHelp() {
|
|
|
526
527
|
console.log(' query - Local-first wiki query against atris/wiki/');
|
|
527
528
|
console.log(' lint - Local-first wiki lint for atris/wiki/');
|
|
528
529
|
console.log(' loop - Local wiki upkeep loop (stale pages, orphans, next ingest)');
|
|
530
|
+
console.log(' write - Guided writing sessions: you write every word, atris structures + reviews');
|
|
529
531
|
console.log('');
|
|
530
532
|
console.log('Optional helpers:');
|
|
531
533
|
console.log(' brainstorm - Explore ideas conversationally before planning');
|
|
@@ -533,8 +535,9 @@ function showHelp() {
|
|
|
533
535
|
console.log(' improve - Run one paid RL tick (POST /api/improve, deducts credits)');
|
|
534
536
|
console.log(' worktree - Isolated Git worktrees plus guarded ship/merge for parallel agents');
|
|
535
537
|
console.log(' land - The landing: what is actually done vs still in the air; --reap backs up + clears overdue');
|
|
538
|
+
console.log(' drive - One self-driving tick: mission doctor -> auto-fix -> count disengagements');
|
|
536
539
|
console.log(' autoland - Approve the policy once; certified work lands itself, you keep irreversible calls');
|
|
537
|
-
console.log(' engine - Bring any intelligence: roster of installed coding CLIs, default engine, --engine per run, `engine test` preflight');
|
|
540
|
+
console.log(' engine - Bring any intelligence: roster of installed coding CLIs, default engine, --engine per run, `engine test` preflight, `engine dispatch <task-id> --engine <name>` one-command claim/build/verify/ship');
|
|
538
541
|
console.log(' sign - Co-author trailer on every commit in an atris workspace (on/off/status)');
|
|
539
542
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
540
543
|
console.log(' youtube - Process YouTube videos with timestamped transcript-first analysis');
|
|
@@ -606,6 +609,11 @@ function showHelp() {
|
|
|
606
609
|
console.log(' accounts - Manage accounts (list, add, remove)');
|
|
607
610
|
console.log('');
|
|
608
611
|
console.log('Integrations:');
|
|
612
|
+
console.log(' github - github cli wrapper (doctor, auth, pr list/create/checks/view)');
|
|
613
|
+
console.log(' vercel - vercel cli wrapper (doctor, auth, deploy/ls/logs/inspect)');
|
|
614
|
+
console.log(' supabase - supabase cli wrapper (doctor, auth, status/db/functions)');
|
|
615
|
+
console.log(' linear - linear cli wrapper (doctor, auth, issue list/create/view/update)');
|
|
616
|
+
console.log(' stripe - stripe cli wrapper (doctor, auth, listen/trigger/products)');
|
|
609
617
|
console.log(' gmail - Email commands (inbox, read, archive)');
|
|
610
618
|
console.log(' calendar - Calendar commands (today, week)');
|
|
611
619
|
console.log(' twitter - Twitter commands (post)');
|
|
@@ -766,7 +774,8 @@ function showVerifyHelp() {
|
|
|
766
774
|
|
|
767
775
|
function showUpdateHelp(commandName = 'update') {
|
|
768
776
|
console.log('');
|
|
769
|
-
|
|
777
|
+
const selfFlag = commandName === 'update' ? ' [--self]' : '';
|
|
778
|
+
console.log(`Usage: atris ${commandName} [--all] [--dry-run] [--force]${selfFlag}`);
|
|
770
779
|
console.log('');
|
|
771
780
|
console.log('Description:');
|
|
772
781
|
console.log(' Sync Atris workspace files from the installed CLI templates.');
|
|
@@ -775,6 +784,9 @@ function showUpdateHelp(commandName = 'update') {
|
|
|
775
784
|
console.log(' --all Update Atris files across projects under the current tree.');
|
|
776
785
|
console.log(' --dry-run Preview update work without writing files.');
|
|
777
786
|
console.log(' --force Overwrite existing template files where supported.');
|
|
787
|
+
if (commandName === 'update') {
|
|
788
|
+
console.log(' --self Update the installed atris cli from npm (packaged installs only).');
|
|
789
|
+
}
|
|
778
790
|
console.log(' --help, -h Show this help.');
|
|
779
791
|
console.log('');
|
|
780
792
|
}
|
|
@@ -974,9 +986,9 @@ if (command === '2' && ['fast', 'pro'].includes(String(firstCommandArg || '').to
|
|
|
974
986
|
const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
|
|
975
987
|
'activate', '_activate', 'agent', 'chat', 'fast', 'ax', 'console', 'serve', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
|
|
976
988
|
'clean', 'harvest', 'verify', 'search', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'plugin', 'experiments', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
|
|
977
|
-
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'land', 'autoland', 'aeo', 'slop', 'strings', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap', 'signup', 'clarity', 'moves',
|
|
978
|
-
'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
979
|
-
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'loops', 'compile', 'spaceship', 'truth', 'sign', 'engine', 'engines'];
|
|
989
|
+
'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'land', 'autoland', 'drive', 'aeo', 'slop', 'strings', 'write', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap', 'signup', 'clarity', 'interview', 'moves', 'unknowns',
|
|
990
|
+
'github', 'vercel', 'supabase', 'linear', 'stripe', 'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
991
|
+
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'loops', 'compile', 'spaceship', 'truth', 'sign', 'engine', 'engines', 'feed'];
|
|
980
992
|
|
|
981
993
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
982
994
|
function isSpecFile(cmd) {
|
|
@@ -1086,6 +1098,19 @@ function printAtrisOverview() {
|
|
|
1086
1098
|
console.log('');
|
|
1087
1099
|
}
|
|
1088
1100
|
|
|
1101
|
+
function useInteractiveAtrisUi() {
|
|
1102
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.ATRIS_NO_INTERACTIVE);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
function initNonInteractiveFlag() {
|
|
1106
|
+
const args = process.argv.slice(2);
|
|
1107
|
+
return args.includes('--yes') || args.includes('-y');
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
function shouldSkipContextGatherer() {
|
|
1111
|
+
return !useInteractiveAtrisUi() || initNonInteractiveFlag();
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1089
1114
|
async function interactiveEntry(userInput) {
|
|
1090
1115
|
const workspaceDir = process.cwd();
|
|
1091
1116
|
const state = detectWorkspaceState(workspaceDir);
|
|
@@ -1174,33 +1199,62 @@ async function interactiveEntry(userInput) {
|
|
|
1174
1199
|
backlogCount,
|
|
1175
1200
|
inboxCount,
|
|
1176
1201
|
})) {
|
|
1177
|
-
const
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1202
|
+
const hotAnswer = String(userInput || '').trim();
|
|
1203
|
+
if (hotAnswer) {
|
|
1204
|
+
const answer = hotAnswer;
|
|
1205
|
+
if (isAtrisMetaQuestion(answer)) {
|
|
1206
|
+
printAtrisOverview();
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
const profile = saveContextProfile(workspaceDir, answer, { source: 'hot_start' });
|
|
1210
|
+
const starter = createStarterTask(workspaceDir, answer);
|
|
1183
1211
|
console.log('');
|
|
1184
|
-
console.log('
|
|
1185
|
-
console.log(
|
|
1212
|
+
console.log('Got it. I saved your first direction.');
|
|
1213
|
+
console.log(`Focus: ${profile.first_answer}`);
|
|
1214
|
+
if (starter && starter.display_id) {
|
|
1215
|
+
console.log(`First task: ${starter.display_id} — ${starter.title}`);
|
|
1216
|
+
} else if (starter && starter.title) {
|
|
1217
|
+
console.log(`First task: ${starter.title}`);
|
|
1218
|
+
}
|
|
1219
|
+
if (mapStatus !== 'ready') {
|
|
1220
|
+
printMapBootstrap({ userInput: answer, prefix: 'Next setup step' });
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
await planCmd(answer);
|
|
1186
1224
|
return;
|
|
1187
1225
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1226
|
+
if (shouldSkipContextGatherer()) {
|
|
1227
|
+
console.log('');
|
|
1228
|
+
console.log("context gatherer skipped (non-interactive). run 'atris plan' when you're ready.");
|
|
1229
|
+
} else {
|
|
1230
|
+
const answer = await askContextGatherer(workspaceDir);
|
|
1231
|
+
if (isAtrisMetaQuestion(answer)) {
|
|
1232
|
+
printAtrisOverview();
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
if (!answer.trim()) {
|
|
1236
|
+
console.log('');
|
|
1237
|
+
console.log('No problem. When you are ready, answer in normal words.');
|
|
1238
|
+
console.log('Example: "help me organize college applications" or "help me build a small website".');
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
const profile = saveContextProfile(workspaceDir, answer, { source: 'cold_start' });
|
|
1242
|
+
const starter = createStarterTask(workspaceDir, answer);
|
|
1243
|
+
console.log('');
|
|
1244
|
+
console.log('Got it. I saved your first direction.');
|
|
1245
|
+
console.log(`Focus: ${profile.first_answer}`);
|
|
1246
|
+
if (starter && starter.display_id) {
|
|
1247
|
+
console.log(`First task: ${starter.display_id} — ${starter.title}`);
|
|
1248
|
+
} else if (starter && starter.title) {
|
|
1249
|
+
console.log(`First task: ${starter.title}`);
|
|
1250
|
+
}
|
|
1251
|
+
if (mapStatus !== 'ready') {
|
|
1252
|
+
printMapBootstrap({ userInput: answer, prefix: 'Next setup step' });
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
await planCmd(answer);
|
|
1200
1256
|
return;
|
|
1201
1257
|
}
|
|
1202
|
-
await planCmd(answer);
|
|
1203
|
-
return;
|
|
1204
1258
|
}
|
|
1205
1259
|
|
|
1206
1260
|
if (mapStatus !== 'ready') {
|
|
@@ -1436,6 +1490,44 @@ function showWelcomeVisualization() {
|
|
|
1436
1490
|
const landText = `${landInfo.branches} in the air, ${landInfo.due} overdue`;
|
|
1437
1491
|
console.log(` │ 🛬 Land: ${landText.padEnd(26)}│`);
|
|
1438
1492
|
}
|
|
1493
|
+
let rotInfo = null;
|
|
1494
|
+
try {
|
|
1495
|
+
const { parseLessons } = require('../lib/memory-view');
|
|
1496
|
+
const resolved = path.resolve(cwd);
|
|
1497
|
+
const parent = path.dirname(resolved);
|
|
1498
|
+
const grandparent = path.dirname(parent);
|
|
1499
|
+
let worktreeDir;
|
|
1500
|
+
if (path.basename(grandparent) === '.agent-worktrees') {
|
|
1501
|
+
worktreeDir = parent;
|
|
1502
|
+
} else {
|
|
1503
|
+
worktreeDir = path.join(path.dirname(resolved), '.agent-worktrees', path.basename(resolved));
|
|
1504
|
+
}
|
|
1505
|
+
let worktrees = 0;
|
|
1506
|
+
if (fs.existsSync(worktreeDir)) {
|
|
1507
|
+
worktrees = fs.readdirSync(worktreeDir, { withFileTypes: true })
|
|
1508
|
+
.filter((entry) => entry.isDirectory()).length;
|
|
1509
|
+
}
|
|
1510
|
+
let lessonsText = '';
|
|
1511
|
+
try {
|
|
1512
|
+
lessonsText = fs.readFileSync(path.join(atrisDir, 'lessons.md'), 'utf8');
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
lessonsText = '';
|
|
1515
|
+
}
|
|
1516
|
+
// rot = fail lessons nobody has resolved. A `pass` lesson is knowledge
|
|
1517
|
+
// that worked — it has nothing to resolve and counting it guilt-trips
|
|
1518
|
+
// the operator with a number (600+) no one can ever drive to zero.
|
|
1519
|
+
const unresolvedLessons = parseLessons(lessonsText)
|
|
1520
|
+
.filter((lesson) => lesson.status === 'fail' && !lesson.resolved && !/\[resolved\]/i.test(lesson.text)).length;
|
|
1521
|
+
if (worktrees > 0 || unresolvedLessons > 0) {
|
|
1522
|
+
rotInfo = { worktrees, lessons: unresolvedLessons };
|
|
1523
|
+
}
|
|
1524
|
+
} catch (err) {
|
|
1525
|
+
rotInfo = null;
|
|
1526
|
+
}
|
|
1527
|
+
if (rotInfo) {
|
|
1528
|
+
const rotText = `${rotInfo.worktrees} stale worktree${rotInfo.worktrees === 1 ? '' : 's'}, ${rotInfo.lessons} unresolved lesson${rotInfo.lessons === 1 ? '' : 's'}`;
|
|
1529
|
+
console.log(` │ 🧹 rot: ${rotText.padEnd(26)}│`);
|
|
1530
|
+
}
|
|
1439
1531
|
console.log(` │ 📝 Journal: ${(journalEntries + ' entries today').padEnd(26)}│`);
|
|
1440
1532
|
if (endgameState.slug !== 'unset' && endgameState.horizon) {
|
|
1441
1533
|
const endgameLine = endgameState.slug + ' — ' + endgameState.horizon;
|
|
@@ -1550,6 +1642,11 @@ if (command === 'init') {
|
|
|
1550
1642
|
Promise.resolve(require('../commands/land').landCommand(process.argv.slice(3)))
|
|
1551
1643
|
.then((code) => process.exit(code || 0))
|
|
1552
1644
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1645
|
+
} else if (command === 'drive') {
|
|
1646
|
+
// Drive: one self-driving tick — mission doctor -> auto-fix safe findings -> count disengagements.
|
|
1647
|
+
Promise.resolve(require('../commands/drive').driveCommand(process.argv.slice(3)))
|
|
1648
|
+
.then((code) => process.exit(code || 0))
|
|
1649
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1553
1650
|
} else if (command === 'radar' || command === 'ctop') {
|
|
1554
1651
|
const radarArgs = command === 'ctop' ? ['--agents', ...process.argv.slice(3)] : process.argv.slice(3);
|
|
1555
1652
|
Promise.resolve(require('../commands/radar').radarCommand(radarArgs))
|
|
@@ -1643,6 +1740,11 @@ if (command === 'init') {
|
|
|
1643
1740
|
showUpdateHelp(command);
|
|
1644
1741
|
process.exit(0);
|
|
1645
1742
|
}
|
|
1743
|
+
if (command === 'update' && args.includes('--self')) {
|
|
1744
|
+
const { updateSelf } = require('../commands/update');
|
|
1745
|
+
const result = updateSelf({ packageRoot: path.join(__dirname, '..') });
|
|
1746
|
+
process.exit(result.ok ? 0 : 1);
|
|
1747
|
+
}
|
|
1646
1748
|
if (isBusinessSync) {
|
|
1647
1749
|
Promise.resolve(require('../commands/business-sync').businessSync(process.argv.slice(3)))
|
|
1648
1750
|
.then(() => process.exit(0))
|
|
@@ -2126,6 +2228,21 @@ if (command === 'init') {
|
|
|
2126
2228
|
require('../commands/gm').gmCommand(...process.argv.slice(3))
|
|
2127
2229
|
.then(() => process.exit(0))
|
|
2128
2230
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2231
|
+
} else if (command === 'github') {
|
|
2232
|
+
const status = require('../commands/github').githubCommand(process.argv.slice(3));
|
|
2233
|
+
process.exit(status);
|
|
2234
|
+
} else if (command === 'vercel') {
|
|
2235
|
+
const status = require('../commands/vercel').vercelCommand(process.argv.slice(3));
|
|
2236
|
+
process.exit(status);
|
|
2237
|
+
} else if (command === 'supabase') {
|
|
2238
|
+
const status = require('../commands/supabase').supabaseCommand(process.argv.slice(3));
|
|
2239
|
+
process.exit(status);
|
|
2240
|
+
} else if (command === 'linear') {
|
|
2241
|
+
const status = require('../commands/linear').linearCommand(process.argv.slice(3));
|
|
2242
|
+
process.exit(status);
|
|
2243
|
+
} else if (command === 'stripe') {
|
|
2244
|
+
const status = require('../commands/stripe').stripeCommand(process.argv.slice(3));
|
|
2245
|
+
process.exit(status);
|
|
2129
2246
|
} else if (command === 'gmail') {
|
|
2130
2247
|
const { gmailCommand } = require('../commands/integrations');
|
|
2131
2248
|
const subcommand = process.argv[3];
|
|
@@ -2326,10 +2443,13 @@ if (command === 'init') {
|
|
|
2326
2443
|
} else if (command === 'engine' || command === 'engines') {
|
|
2327
2444
|
// Engine: bring any intelligence — roster of installed coding CLIs, default
|
|
2328
2445
|
// engine per workspace, --engine <name> rides any loop for one run.
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2446
|
+
// `engine dispatch` runs an async claim -> build -> ship flight, so the
|
|
2447
|
+
// return value may be a promise or a plain number; Promise.resolve handles
|
|
2448
|
+
// both (mirrors the `compile` command dispatch just above).
|
|
2449
|
+
const engineArgs = command === 'engines' && process.argv.length <= 3 ? [] : process.argv.slice(3);
|
|
2450
|
+
Promise.resolve(require('../commands/engine').engineCommand(engineArgs))
|
|
2451
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2452
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2333
2453
|
} else if (command === 'sign') {
|
|
2334
2454
|
// Sign: prepare-commit-msg hook that credits Atris as co-author on commits in atris workspaces.
|
|
2335
2455
|
try { process.exit(require('../commands/sign').signCommand(process.argv[3]) || 0); }
|
|
@@ -2339,6 +2459,11 @@ if (command === 'init') {
|
|
|
2339
2459
|
Promise.resolve(require('../commands/slop').slopCommand(process.argv.slice(3)))
|
|
2340
2460
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2341
2461
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2462
|
+
} else if (command === 'write') {
|
|
2463
|
+
// Write: guided writing sessions — human types every word, atris structures + reviews (plan-do-review for prose).
|
|
2464
|
+
Promise.resolve(require('../commands/write').writeCommand(process.argv.slice(3)))
|
|
2465
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2466
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2342
2467
|
} else if (command === 'strings') {
|
|
2343
2468
|
// Strings: content design system from live code (no LLM). Extracts UI strings, flags variants,
|
|
2344
2469
|
// enforces preferred terms at the gate. Exit 1 = variants/banned terms found, for CI + the gate.
|
|
@@ -2361,11 +2486,27 @@ if (command === 'init') {
|
|
|
2361
2486
|
Promise.resolve(require('../commands/moves').movesCommand(process.argv.slice(3)))
|
|
2362
2487
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2363
2488
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2489
|
+
} else if (command === 'unknowns') {
|
|
2490
|
+
// Unknowns: blindspot pass from local territory context into the SQLite ledger.
|
|
2491
|
+
Promise.resolve(require('../commands/unknowns').unknownsCommand(process.argv.slice(3)))
|
|
2492
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2493
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2494
|
+
} else if (command === 'feed') {
|
|
2495
|
+
// Feed: read and post the business group feed — receipts and state changes only.
|
|
2496
|
+
// Sets exitCode instead of process.exit() so large --json output flushes fully.
|
|
2497
|
+
Promise.resolve(require('../commands/feed').feedCommand(process.argv.slice(3)))
|
|
2498
|
+
.then((code) => { process.exitCode = typeof code === 'number' ? code : 0; })
|
|
2499
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exitCode = 1; });
|
|
2364
2500
|
} else if (command === 'clarity') {
|
|
2365
2501
|
// Clarity: interview yourself once; agents read how you work so you stop repeating it.
|
|
2366
2502
|
Promise.resolve(require('../commands/clarity').clarityCommand(process.argv.slice(3)))
|
|
2367
2503
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2368
2504
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2505
|
+
} else if (command === 'interview') {
|
|
2506
|
+
// Interview: the interlinked 1-on-1 — live interview that extracts judgment into a member file.
|
|
2507
|
+
Promise.resolve(require('../commands/interview').interviewCommand(process.argv.slice(3)))
|
|
2508
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2509
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2369
2510
|
} else if (command === 'deck') {
|
|
2370
2511
|
// Deck: premium Google Slides from a plain content spec, via the Atris deck engine (anti-slop design system).
|
|
2371
2512
|
Promise.resolve(require('../commands/deck').run(process.argv.slice(3)))
|
|
@@ -2734,8 +2875,19 @@ async function agentAtris() {
|
|
|
2734
2875
|
async function chatAtris() {
|
|
2735
2876
|
// Get message from command line args; --agent forces the legacy cloud-agent lane
|
|
2736
2877
|
const rawArgs = process.argv.slice(3);
|
|
2737
|
-
const
|
|
2738
|
-
const
|
|
2878
|
+
const fastLaneFlags = [];
|
|
2879
|
+
const messageArgs = [];
|
|
2880
|
+
let agentLane = false;
|
|
2881
|
+
for (const arg of rawArgs) {
|
|
2882
|
+
if (arg === '--agent') {
|
|
2883
|
+
agentLane = true;
|
|
2884
|
+
} else if (arg === '--print' || arg === '--headless') {
|
|
2885
|
+
fastLaneFlags.push(arg);
|
|
2886
|
+
} else {
|
|
2887
|
+
messageArgs.push(arg);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
const message = messageArgs.join(' ').trim();
|
|
2739
2891
|
|
|
2740
2892
|
// Respect -h / --help before any auth/state checks
|
|
2741
2893
|
if (message === '-h' || message === '--help' || message === 'help') {
|
|
@@ -2746,6 +2898,7 @@ async function chatAtris() {
|
|
|
2746
2898
|
console.log('');
|
|
2747
2899
|
console.log(' atris chat Interactive chat (ax --fast --chat)');
|
|
2748
2900
|
console.log(' atris chat "what now?" One-shot message (ax --fast)');
|
|
2901
|
+
console.log(' atris chat --print "..." Headless JSON result (ax --fast --print)');
|
|
2749
2902
|
console.log(' atris chat --agent [...] Legacy cloud-agent lane (needs `atris agent`)');
|
|
2750
2903
|
process.exit(0);
|
|
2751
2904
|
}
|
|
@@ -2757,7 +2910,7 @@ async function chatAtris() {
|
|
|
2757
2910
|
process.exit(1);
|
|
2758
2911
|
}
|
|
2759
2912
|
|
|
2760
|
-
const missionIntent = missionRunIntentFromFastMessage(message);
|
|
2913
|
+
const missionIntent = fastLaneFlags.length ? null : missionRunIntentFromFastMessage(message);
|
|
2761
2914
|
if (missionIntent) {
|
|
2762
2915
|
process.exit(await runLocalFastMission(missionIntent));
|
|
2763
2916
|
}
|
|
@@ -2770,7 +2923,7 @@ async function chatAtris() {
|
|
|
2770
2923
|
if (!agentLane) {
|
|
2771
2924
|
try {
|
|
2772
2925
|
const axPath = path.join(__dirname, '..', 'ax');
|
|
2773
|
-
const axArgs = message ? ['--fast', message] : ['--fast', '--chat'];
|
|
2926
|
+
const axArgs = message || fastLaneFlags.length ? ['--fast', ...fastLaneFlags, message].filter(Boolean) : ['--fast', '--chat'];
|
|
2774
2927
|
const run = spawnSync(process.execPath, [axPath, ...axArgs], { stdio: 'inherit' });
|
|
2775
2928
|
process.exit(run.status || 0);
|
|
2776
2929
|
} catch {
|
package/commands/aeo.js
CHANGED
|
@@ -157,6 +157,9 @@ function pickSlug(args) {
|
|
|
157
157
|
|
|
158
158
|
function printHelp() {
|
|
159
159
|
console.log('Usage:');
|
|
160
|
+
console.log(' Live scan (no login needed):');
|
|
161
|
+
console.log(' atris aeo scan <url> [--vs <competitor-url>] [--json]');
|
|
162
|
+
console.log('');
|
|
160
163
|
console.log(' Backend / EC2:');
|
|
161
164
|
console.log(' atris aeo init [--workspace <slug>]');
|
|
162
165
|
console.log(' atris aeo draft "<topic>" [--workspace <slug>] [--queries q1,q2] [--slug X] [--url URL]');
|
|
@@ -178,6 +181,54 @@ function printHelp() {
|
|
|
178
181
|
console.log(' atris aeo discover https://atris.ai/aeo --canonical-url https://atris.ai/aeo');
|
|
179
182
|
}
|
|
180
183
|
|
|
184
|
+
const FREE_SCAN_BASE = process.env.ATRIS_API_BASE || 'https://api.atris.ai';
|
|
185
|
+
|
|
186
|
+
async function aeoScan(args) {
|
|
187
|
+
const asJson = args.includes('--json');
|
|
188
|
+
const vs = readArg(args, '--vs');
|
|
189
|
+
const url = args.filter((a) => !a.startsWith('--') && a !== vs)[0];
|
|
190
|
+
if (!url) {
|
|
191
|
+
console.error('Usage: atris aeo scan <url> [--vs <competitor-url>] [--json]');
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
const target = /^https?:\/\//i.test(url) ? url : `https://${url}`;
|
|
195
|
+
const qs = new URLSearchParams({ url: target });
|
|
196
|
+
if (vs) qs.set('vs', /^https?:\/\//i.test(vs) ? vs : `https://${vs}`);
|
|
197
|
+
const endpoint = `${FREE_SCAN_BASE}/api/business/aeo/free-scan?${qs}`;
|
|
198
|
+
let data;
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(endpoint, { signal: AbortSignal.timeout(60000) });
|
|
201
|
+
if (!res.ok) {
|
|
202
|
+
const body = await res.text().catch(() => '');
|
|
203
|
+
console.error(`Scan failed (${res.status}): ${body.slice(0, 200)}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
data = await res.json();
|
|
207
|
+
} catch (e) {
|
|
208
|
+
console.error(`Scan failed: ${e.message}`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
if (asJson) { console.log(JSON.stringify(data, null, 2)); return; }
|
|
212
|
+
console.log(`\n ${data.name || target}`);
|
|
213
|
+
console.log(` Score: ${data.score}/100 (${data.grade}) — ${data.status}`);
|
|
214
|
+
if (data.gap_statement) console.log(`\n ${data.gap_statement}`);
|
|
215
|
+
const gaps = data.gaps || [];
|
|
216
|
+
if (gaps.length) {
|
|
217
|
+
console.log('\n Gaps:');
|
|
218
|
+
for (const g of gaps) console.log(` ✗ ${g.title || g.key}: ${g.fix || ''}`);
|
|
219
|
+
}
|
|
220
|
+
const comp = data.competitors || [];
|
|
221
|
+
if (comp.length) {
|
|
222
|
+
console.log('\n Head-to-head:');
|
|
223
|
+
for (const c of comp) console.log(` ${pad(String(c.score ?? '?'), 4)} ${c.url || c.name}`);
|
|
224
|
+
}
|
|
225
|
+
if (data.draft_llms_txt) {
|
|
226
|
+
console.log('\n Draft llms.txt included — save it with:');
|
|
227
|
+
console.log(` atris aeo scan ${url} --json | jq -r .draft_llms_txt > llms.txt`);
|
|
228
|
+
}
|
|
229
|
+
console.log('');
|
|
230
|
+
}
|
|
231
|
+
|
|
181
232
|
async function aeoInit(args) {
|
|
182
233
|
const slug = pickSlug(args);
|
|
183
234
|
if (!slug) {
|
|
@@ -545,6 +596,7 @@ async function run(args = []) {
|
|
|
545
596
|
const sub = args[0];
|
|
546
597
|
if (!sub || sub === 'help' || sub === '--help' || sub === '-h') return printHelp();
|
|
547
598
|
const rest = args.slice(1);
|
|
599
|
+
if (sub === 'scan') return aeoScan(rest);
|
|
548
600
|
if (sub === 'init') return aeoInit(rest);
|
|
549
601
|
if (sub === 'draft') return aeoDraft(rest);
|
|
550
602
|
if (sub === 'log') return aeoLog(rest);
|