atris 3.35.0 → 3.36.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 +37 -0
- package/README.md +5 -3
- package/atris/GETTING_STARTED.md +1 -1
- package/atris/atris.md +3 -0
- package/atris/policies/day-loop-voice.md +102 -0
- package/atris/policies/outbound-artifact-gate.md +2 -0
- package/atris/skills/design/SKILL.md +56 -32
- package/atris/skills/endgame/SKILL.md +12 -6
- package/atris/skills/engines/SKILL.md +22 -4
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +2 -0
- package/ax +147 -19
- package/bin/atris.js +565 -265
- package/commands/activate.js +194 -88
- package/commands/agents.js +166 -0
- package/commands/autoland.js +459 -107
- package/commands/autopilot-front.js +20 -2
- package/commands/autopilot.js +118 -2
- package/commands/avail.js +407 -0
- package/commands/bench.js +188 -0
- package/commands/brain.js +3 -0
- package/commands/brief.js +651 -0
- package/commands/business-sync.js +192 -6
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/compile.js +292 -1
- package/commands/computer.js +150 -3
- package/commands/dream.js +365 -0
- package/commands/drill.js +371 -0
- package/commands/engine.js +993 -32
- package/commands/experiments.js +28 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/gm.js +23 -0
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +72 -44
- package/commands/interview.js +67 -1
- package/commands/land.js +152 -52
- package/commands/lifecycle.js +39 -3
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +511 -34
- package/commands/mission.js +3029 -339
- package/commands/next.js +137 -0
- package/commands/now.js +220 -25
- package/commands/one-lap.js +776 -0
- package/commands/orb.js +314 -0
- package/commands/pack-craft.js +179 -0
- package/commands/pack.js +823 -0
- package/commands/play.js +3 -2
- package/commands/probe.js +30 -3
- package/commands/pulse.js +241 -46
- package/commands/push.js +260 -82
- package/commands/rainmaker.js +49 -0
- package/commands/report.js +415 -0
- package/commands/scout.js +147 -0
- package/commands/search.js +363 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/stream.js +861 -0
- package/commands/study.js +693 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +1346 -117
- package/commands/team.js +73 -0
- package/commands/verify.js +96 -0
- package/commands/watch.js +303 -0
- package/commands/wish.js +500 -0
- package/commands/workflow.js +11 -5
- package/commands/worktree.js +234 -13
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +331 -34
- package/lib/autoland.js +319 -54
- package/lib/ax-auto-lane.js +79 -0
- package/lib/bench/context.js +147 -0
- package/lib/bench/engines.js +141 -0
- package/lib/bench/report.js +140 -0
- package/lib/bench/runner.js +512 -0
- package/lib/brief-ledger.js +350 -0
- package/lib/cloud-mission.js +259 -0
- package/lib/codex-flight.js +154 -0
- package/lib/default-runner.js +45 -0
- package/lib/default-verifier.js +70 -0
- package/lib/engine-registry.js +232 -0
- package/lib/experiments/daily.js +640 -0
- package/lib/fleet.js +2219 -67
- package/lib/improve-vitals-html.js +171 -0
- package/lib/known-commands.js +58 -0
- package/lib/loop-doctor.js +416 -0
- package/lib/member-switches.js +144 -0
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/next-moves.js +327 -10
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/policy-lessons.js +52 -1
- package/lib/pulse.js +277 -3
- package/lib/receipt-block.js +168 -0
- package/lib/receipt-evidence.js +65 -4
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +10 -0
- package/lib/self-drive.js +258 -0
- package/lib/short-name.js +103 -0
- package/lib/spawn-env.js +18 -0
- package/lib/state-detection.js +56 -1
- package/lib/sync-status.js +59 -0
- package/lib/task-db.js +108 -29
- package/lib/task-proof.js +23 -1
- package/lib/team-presence.js +260 -0
- package/lib/tool-result-encode.js +7 -0
- package/lib/trust-tiers.js +90 -0
- package/lib/usage.js +107 -0
- package/lib/voice-gate.js +163 -0
- package/lib/wish-audit.js +1368 -0
- package/lib/wish-delegate.js +1840 -0
- package/lib/wish-design.js +110 -0
- package/lib/wish-stats.js +183 -0
- package/lib/wish-store.js +354 -0
- package/lib/zip.js +221 -0
- package/package.json +3 -1
- package/templates/loops/atris/loops/LOOPS.md +55 -0
- package/templates/loops/atris/loops/TICK.md +24 -0
- package/templates/loops/atris/loops/feedback.md +22 -0
- package/templates/loops/atris/loops/quality.md +22 -0
- package/templates/loops/atris/wiki/systems/loops.md +41 -0
- package/utils/api.js +5 -1
- package/utils/auth.js +57 -21
package/bin/atris.js
CHANGED
|
@@ -65,6 +65,8 @@ const {
|
|
|
65
65
|
DEFAULT_CLIENT_ID, DEFAULT_USER_AGENT,
|
|
66
66
|
} = require('../utils/api');
|
|
67
67
|
const missionRuntime = require('../lib/mission-runtime-loop');
|
|
68
|
+
const { knownCommands, suggestCommand } = require('../lib/known-commands');
|
|
69
|
+
const { recordUsage } = require('../lib/usage');
|
|
68
70
|
|
|
69
71
|
// Bind DI wrappers (utils/auth uses dependency injection for apiRequestJson)
|
|
70
72
|
const validateAccessToken = (token) => _validateAccessToken(token, apiRequestJson);
|
|
@@ -85,7 +87,8 @@ const helpRequested = updateCommand === 'help'
|
|
|
85
87
|
|| updateArgs.includes('--help')
|
|
86
88
|
|| updateArgs.includes('-h')
|
|
87
89
|
|| updateArgs[0] === 'help';
|
|
88
|
-
const jsonRequested =
|
|
90
|
+
const jsonRequested = process.argv.slice(2).includes('--json');
|
|
91
|
+
const dryRunRequested = updateArgs.includes('--dry-run');
|
|
89
92
|
const skipUpdateCheck = Boolean(process.env.ATRIS_SKIP_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER || helpRequested || jsonRequested);
|
|
90
93
|
if (!skipUpdateCheck && (!updateCommand || (updateCommand && !['version', 'update'].includes(updateCommand)))) {
|
|
91
94
|
updateCheckPromise = checkForUpdates()
|
|
@@ -107,6 +110,12 @@ let command = process.argv[2];
|
|
|
107
110
|
const commandArgs = process.argv.slice(3);
|
|
108
111
|
const firstCommandArg = process.argv[3];
|
|
109
112
|
const RUNNER_FLAG_NAMES = ['--runner-bin', '--runner-template', '--runner-model', '--runner-profile'];
|
|
113
|
+
const NATURAL_VALUE_FLAGS = [...RUNNER_FLAG_NAMES, '--engine', '--verify'];
|
|
114
|
+
const SINGLE_WORD_NATURAL_INTENTS = new Set([
|
|
115
|
+
'add', 'analyze', 'build', 'change', 'check', 'create', 'debug', 'document',
|
|
116
|
+
'edit', 'fix', 'implement', 'inspect', 'investigate', 'make', 'patch',
|
|
117
|
+
'refactor', 'remove', 'rename', 'research', 'test', 'update', 'validate', 'write',
|
|
118
|
+
]);
|
|
110
119
|
|
|
111
120
|
function readOptionArg(args, name) {
|
|
112
121
|
const prefix = `${name}=`;
|
|
@@ -121,6 +130,50 @@ function isOptionValue(args, index, optionNames) {
|
|
|
121
130
|
return index > 0 && optionNames.includes(args[index - 1]);
|
|
122
131
|
}
|
|
123
132
|
|
|
133
|
+
function parseNaturalEntryArgs(args = []) {
|
|
134
|
+
const positionals = [];
|
|
135
|
+
let asJson = false;
|
|
136
|
+
let engine = '';
|
|
137
|
+
let verifier = '';
|
|
138
|
+
let error = '';
|
|
139
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
140
|
+
const value = String(args[i] || '');
|
|
141
|
+
if (value === '--json') {
|
|
142
|
+
asJson = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const inlineFlag = NATURAL_VALUE_FLAGS.find((name) => value.startsWith(`${name}=`));
|
|
146
|
+
if (inlineFlag) {
|
|
147
|
+
const optionValue = value.slice(inlineFlag.length + 1);
|
|
148
|
+
if (!optionValue) error = `${inlineFlag} needs a value`;
|
|
149
|
+
if (inlineFlag === '--engine') engine = optionValue;
|
|
150
|
+
if (inlineFlag === '--verify') verifier = optionValue;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (NATURAL_VALUE_FLAGS.includes(value)) {
|
|
154
|
+
const optionValue = String(args[i + 1] || '');
|
|
155
|
+
if (!optionValue || optionValue.startsWith('--')) {
|
|
156
|
+
error = `${value} needs a value`;
|
|
157
|
+
} else {
|
|
158
|
+
if (value === '--engine') engine = optionValue;
|
|
159
|
+
if (value === '--verify') verifier = optionValue;
|
|
160
|
+
i += 1;
|
|
161
|
+
}
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
positionals.push(value);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
asJson,
|
|
168
|
+
engine,
|
|
169
|
+
verifier,
|
|
170
|
+
error,
|
|
171
|
+
positionals,
|
|
172
|
+
input: positionals.join(' ').replace(/\s+/g, ' ').trim(),
|
|
173
|
+
multiword: positionals.length > 1 || positionals.some((value) => /\s/.test(value.trim())),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
124
177
|
function applyRunnerFlags(args) {
|
|
125
178
|
// --engine <name> is the operator-facing spelling of --runner-profile:
|
|
126
179
|
// one flag rents a specific intelligence for this run.
|
|
@@ -196,13 +249,14 @@ const isBusinessSyncSafetyCommand = command === 'sync'
|
|
|
196
249
|
|| firstCommandArg === 'resolve'
|
|
197
250
|
);
|
|
198
251
|
|
|
199
|
-
// Auto-sync skills only for commands that modify workspace state
|
|
200
|
-
|
|
252
|
+
// Auto-sync skills only for commands that modify workspace state. Help must
|
|
253
|
+
// stay read-only, including global ~/.claude and ~/.codex skill directories.
|
|
254
|
+
if (!helpRequested && !dryRunRequested && (['init', 'update', 'upgrade'].includes(command) || (command === 'sync' && !isBusinessSyncSafetyCommand))) {
|
|
201
255
|
try {
|
|
202
256
|
const { syncSkills } = require('../commands/sync');
|
|
203
257
|
const skillsUpdated = syncSkills({ silent: true });
|
|
204
258
|
if (skillsUpdated > 0) {
|
|
205
|
-
console.log(
|
|
259
|
+
console.log(`${skillsUpdated} skill${skillsUpdated > 1 ? 's' : ''} updated`);
|
|
206
260
|
}
|
|
207
261
|
} catch (e) {
|
|
208
262
|
// Non-critical
|
|
@@ -345,76 +399,7 @@ function printAtrisGoalBanner(workspaceDir = process.cwd(), label = 'Atris goal'
|
|
|
345
399
|
}
|
|
346
400
|
|
|
347
401
|
function showSearchHelp() {
|
|
348
|
-
|
|
349
|
-
console.log('Example: atris search auth');
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function searchJournal(keyword) {
|
|
353
|
-
if (!keyword) {
|
|
354
|
-
showSearchHelp();
|
|
355
|
-
process.exit(1);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (keyword === '--help' || keyword === '-h') {
|
|
359
|
-
showSearchHelp();
|
|
360
|
-
process.exit(0);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (process.argv.slice(4).includes('--help') || process.argv.slice(4).includes('-h')) {
|
|
364
|
-
showSearchHelp();
|
|
365
|
-
process.exit(1);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const logsDir = path.join(process.cwd(), 'atris', 'logs');
|
|
369
|
-
if (!fs.existsSync(logsDir)) {
|
|
370
|
-
console.log('No atris/logs/ directory found. Run "atris init" first.');
|
|
371
|
-
process.exit(1);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
console.log(`Searching for "${keyword}" in atris/logs/**/*.md...\n`);
|
|
375
|
-
|
|
376
|
-
const results = [];
|
|
377
|
-
const keywordLower = keyword.toLowerCase();
|
|
378
|
-
|
|
379
|
-
// Recursively find all .md files in logs directory
|
|
380
|
-
function walkDir(dir) {
|
|
381
|
-
let files;
|
|
382
|
-
try { files = fs.readdirSync(dir); } catch { return; }
|
|
383
|
-
for (const file of files) {
|
|
384
|
-
try {
|
|
385
|
-
const filePath = path.join(dir, file);
|
|
386
|
-
const stat = fs.statSync(filePath);
|
|
387
|
-
if (stat.isDirectory()) {
|
|
388
|
-
walkDir(filePath);
|
|
389
|
-
} else if (file.endsWith('.md')) {
|
|
390
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
391
|
-
const lines = content.split('\n');
|
|
392
|
-
lines.forEach((line, idx) => {
|
|
393
|
-
if (line.toLowerCase().includes(keywordLower)) {
|
|
394
|
-
results.push({
|
|
395
|
-
file: path.relative(process.cwd(), filePath),
|
|
396
|
-
line: idx + 1,
|
|
397
|
-
content: line.trim()
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
} catch { /* skip unreadable files */ }
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
walkDir(logsDir);
|
|
407
|
-
|
|
408
|
-
if (results.length === 0) {
|
|
409
|
-
console.log('No matches found.');
|
|
410
|
-
} else {
|
|
411
|
-
console.log(`Found ${results.length} match${results.length > 1 ? 'es' : ''}:\n`);
|
|
412
|
-
results.forEach(r => {
|
|
413
|
-
console.log(`${r.file}:${r.line}`);
|
|
414
|
-
console.log(` ${r.content.substring(0, 100)}${r.content.length > 100 ? '...' : ''}`);
|
|
415
|
-
console.log('');
|
|
416
|
-
});
|
|
417
|
-
}
|
|
402
|
+
require('../commands/search').showSearchHelp();
|
|
418
403
|
}
|
|
419
404
|
|
|
420
405
|
function consoleCmd() {
|
|
@@ -453,7 +438,8 @@ function consoleCmd() {
|
|
|
453
438
|
function showHelp() {
|
|
454
439
|
console.log('');
|
|
455
440
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
456
|
-
console.log('atris
|
|
441
|
+
console.log('atris');
|
|
442
|
+
console.log('you say what you want in plain words. atris builds it, checks it, and shows you proof.');
|
|
457
443
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
458
444
|
console.log('');
|
|
459
445
|
console.log('Quick Start:');
|
|
@@ -464,11 +450,15 @@ function showHelp() {
|
|
|
464
450
|
console.log(' 3. Atris acts with context, memory, tools, and a review loop');
|
|
465
451
|
console.log('');
|
|
466
452
|
console.log('Common invocations:');
|
|
453
|
+
console.log(' atris "<request>" Build one isolated change, verify it, and stop in Review');
|
|
454
|
+
console.log(' atris "<request>" --verify "<cmd>" --json');
|
|
455
|
+
console.log(' Supply proof explicitly and return one JSON result');
|
|
467
456
|
console.log(' atris init [--yes] Global install: initialize this project');
|
|
468
457
|
console.log(' npx atris init [--yes] Local install: initialize this project');
|
|
469
458
|
console.log(' atris computer');
|
|
470
459
|
console.log(' atris business init "My Company"');
|
|
471
460
|
console.log(' atris run');
|
|
461
|
+
console.log(' atris drill');
|
|
472
462
|
console.log(' atris status');
|
|
473
463
|
console.log(' atris soul');
|
|
474
464
|
console.log(' atris fleet status');
|
|
@@ -498,17 +488,26 @@ function showHelp() {
|
|
|
498
488
|
console.log('');
|
|
499
489
|
console.log('Context & tracking:');
|
|
500
490
|
console.log(' log - Add ideas to inbox');
|
|
491
|
+
console.log(' wish - Say one plain sentence, then Atris asks only for gaps or delegates it');
|
|
501
492
|
console.log(' now - Show atris/now.md, the current operating truth');
|
|
493
|
+
console.log(' goal - goal, distance, and what moved today (alias: wtf)');
|
|
494
|
+
console.log(' orb - Pick next moves while engine jobs work in the background');
|
|
502
495
|
console.log(' activate - Load Atris context');
|
|
503
496
|
console.log(' radar - Show live agents joined with tasks, missions, and worktrees');
|
|
497
|
+
console.log(' stream - Watch the whole team work live in one terminal');
|
|
498
|
+
console.log(' team - Show who is awake, what they are doing, and running loops');
|
|
499
|
+
console.log(' watch - Turn one sentence into an always-on background watcher');
|
|
504
500
|
console.log(' ctop - Show a process-first live agent CPU/memory view');
|
|
505
501
|
console.log(' launchpad - Show the next action from local brain, task, mission, and proof state');
|
|
502
|
+
console.log(' brief - Show the one-glance operator brief');
|
|
506
503
|
console.log(' status - See local work and completions (`atris status <business>` for remote)');
|
|
507
504
|
console.log(' recap - What your AI team did, in plain English (--share for paste-ready)');
|
|
505
|
+
console.log(' report - Weekly block: landings, journal completions, and Career XP');
|
|
508
506
|
console.log(' xp - Show Career XP and contribution graph');
|
|
509
507
|
console.log(' analytics - Show recent productivity from journals');
|
|
510
|
-
console.log(' search - Search
|
|
508
|
+
console.log(' search - Search workspace memory (atris search <keyword>)');
|
|
511
509
|
console.log(' clean - Housekeeping (stale tasks, archive journals, broken refs)');
|
|
510
|
+
console.log(' close - track open loops with deadlines and daily escalation');
|
|
512
511
|
console.log(' harvest - Find bugs and next actions from receipts, run logs, and thinking');
|
|
513
512
|
console.log(' verify - Validate work is done (tests, MAP.md, changes)');
|
|
514
513
|
console.log(' task - Local agent task plane (atomic claims, TODO import)');
|
|
@@ -518,9 +517,13 @@ function showHelp() {
|
|
|
518
517
|
console.log(' ... build ...');
|
|
519
518
|
console.log(' atris task ready <id> --verify');
|
|
520
519
|
console.log(' atris autoland tick # second check runs, task lands');
|
|
521
|
-
console.log(' mission - Goal + loop + member owner + verifier + receipt');
|
|
520
|
+
console.log(' mission - Goal + loop + member owner + verifier + receipt; --budget quick|long|deep sets bounded tiers');
|
|
522
521
|
console.log(' release - Tag release, bump version, create GitHub release, draft /launch');
|
|
523
522
|
console.log(' learn - Project learnings (patterns, pitfalls, preferences)');
|
|
523
|
+
console.log(' study - On-demand learning feed: ingest topic, start server, open browser');
|
|
524
|
+
console.log(' rainmaker - Relationship manager dashboard (atrisos-backend/scripts/rainmaker.py)');
|
|
525
|
+
console.log(' meet - onboard a stranger in one sitting and print their /book link');
|
|
526
|
+
console.log(' avail - Booking availability (/book/{username} weekly windows)');
|
|
524
527
|
console.log(' brain - Compile MAP/TODO/wiki/state into a loadable agent brain');
|
|
525
528
|
console.log(' lesson - Append a one-line lesson to atris/lessons.md (mine: distill receipts/episodes/scorecards into policy lessons)');
|
|
526
529
|
console.log(' ingest - Local-first wiki ingest into atris/wiki/');
|
|
@@ -537,7 +540,7 @@ function showHelp() {
|
|
|
537
540
|
console.log(' land - The landing: what is actually done vs still in the air; --reap backs up + clears overdue');
|
|
538
541
|
console.log(' drive - One self-driving tick: mission doctor -> auto-fix -> count disengagements');
|
|
539
542
|
console.log(' autoland - Approve the policy once; certified work lands itself, you keep irreversible calls');
|
|
540
|
-
console.log(' engine -
|
|
543
|
+
console.log(' engine - Engine registry: list/resolve roles, health flips, default engine, `engine test`, and dispatch flights');
|
|
541
544
|
console.log(' sign - Co-author trailer on every commit in an atris workspace (on/off/status)');
|
|
542
545
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
543
546
|
console.log(' youtube - Process YouTube videos with timestamped transcript-first analysis');
|
|
@@ -547,6 +550,7 @@ function showHelp() {
|
|
|
547
550
|
console.log(' experiments validate - Validate experiment packs');
|
|
548
551
|
console.log(' experiments run <slug> - Execute a pack or record an Endstate receipt');
|
|
549
552
|
console.log(' experiments benchmark [m] - Run validate/runtime experiment benchmarks');
|
|
553
|
+
console.log(' bench - run core benchmark gates');
|
|
550
554
|
console.log('');
|
|
551
555
|
console.log('Compile loop (learn like AI, run like code):');
|
|
552
556
|
console.log(' compile record <name> - Append an execution record (--input/--output)');
|
|
@@ -562,6 +566,7 @@ function showHelp() {
|
|
|
562
566
|
console.log('Sync:');
|
|
563
567
|
console.log(' pull - Pull journals + member data from cloud');
|
|
564
568
|
console.log(' push - Push workspace files to cloud');
|
|
569
|
+
console.log(' cloud - Delete cloud files not present locally (cloud clean --dry-run|--yes)');
|
|
565
570
|
console.log(' live - Keep a business brain fresh (doctor, pull, watch, push)');
|
|
566
571
|
console.log(' clean-workspace <slug> - Analyze & remove junk files from a workspace (alias: cw)');
|
|
567
572
|
console.log('');
|
|
@@ -569,8 +574,9 @@ function showHelp() {
|
|
|
569
574
|
console.log(' browse [query] - Discover workspace templates');
|
|
570
575
|
console.log(' fork <template> - Clone a template into a new workspace');
|
|
571
576
|
console.log(' publish - Share your workspace as a template');
|
|
572
|
-
console.log('
|
|
573
|
-
console.log('
|
|
577
|
+
console.log(' pack - Publish or install an Atris brain zip');
|
|
578
|
+
console.log(' sleep [business|member] [--loop id] - Pause compute or flip a member switch');
|
|
579
|
+
console.log(' wake [business|member] [--loop id] - Resume compute or flip a member switch');
|
|
574
580
|
console.log('');
|
|
575
581
|
console.log('Business:');
|
|
576
582
|
console.log(' business init <name> - Create shared owner + first/default computer');
|
|
@@ -597,7 +603,8 @@ function showHelp() {
|
|
|
597
603
|
console.log(' console - Start/attach always-on coding console (tmux daemon)');
|
|
598
604
|
console.log(' soul - Show, snapshot, or fork workspace identity');
|
|
599
605
|
console.log(' fleet - Inspect local fleet status');
|
|
600
|
-
console.log(' loops -
|
|
606
|
+
console.log(' loops - Self-improving loop audit/scaffold (`init`, `audit`, `tick`, `board`)');
|
|
607
|
+
console.log(' self-improve - Alias for `atris loops init`');
|
|
601
608
|
console.log(' agent - Select cloud agent, spawn worker requests, or run `agent doctor`');
|
|
602
609
|
console.log(' chat - Chat with Atris 2 Fast in this workspace (--agent for cloud agent; or: atris chat scan)');
|
|
603
610
|
console.log(' fast - Chat with Atris2 Fast');
|
|
@@ -762,12 +769,18 @@ function showVerifyHelp() {
|
|
|
762
769
|
console.log('');
|
|
763
770
|
console.log('Usage: atris verify [task]');
|
|
764
771
|
console.log('Usage: atris verify <feature-slug> --section <name>');
|
|
772
|
+
console.log('Usage: atris verify artifact <path> [--objective "<text>"] [--min-lines N] [--max-age-hours H] [--json]');
|
|
765
773
|
console.log('');
|
|
766
774
|
console.log('Description:');
|
|
767
775
|
console.log(' Validate workspace health, a specific task, or a feature rubric section.');
|
|
776
|
+
console.log(' The artifact form runs deterministic substance checks on a mission artifact');
|
|
777
|
+
console.log(' (a pre-filter for empty/skeleton/placeholder output, not a quality judgment).');
|
|
768
778
|
console.log('');
|
|
769
779
|
console.log('Options:');
|
|
770
780
|
console.log(' --section <name> Run a fenced bash check from atris/features/<slug>/validate.md.');
|
|
781
|
+
console.log(' --objective <t> Require the artifact to cover the objective vocabulary.');
|
|
782
|
+
console.log(' --min-lines <n> Minimum substantive lines (default 10).');
|
|
783
|
+
console.log(' --max-age-hours <h> Require the artifact to be modified within this window.');
|
|
771
784
|
console.log(' --help, -h Show this help.');
|
|
772
785
|
console.log('');
|
|
773
786
|
}
|
|
@@ -968,6 +981,7 @@ const { logAtris: logCmd } = require('../commands/log');
|
|
|
968
981
|
const { activateAtris: activateCmd } = require('../commands/activate');
|
|
969
982
|
const { statusAtris: statusCmd } = require('../commands/status');
|
|
970
983
|
const { planAtris: planCmd, doAtris: doCmd, reviewAtris: reviewCmd } = require('../commands/workflow');
|
|
984
|
+
const { runOrb: orbCmd } = require('../commands/orb');
|
|
971
985
|
|
|
972
986
|
// All other commands are lazy-loaded inline (require() only when invoked)
|
|
973
987
|
|
|
@@ -983,12 +997,6 @@ if (command === '2' && ['fast', 'pro'].includes(String(firstCommandArg || '').to
|
|
|
983
997
|
}
|
|
984
998
|
|
|
985
999
|
// Check if this is a known command or natural language input
|
|
986
|
-
const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
|
|
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',
|
|
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',
|
|
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'];
|
|
992
1000
|
|
|
993
1001
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
994
1002
|
function isSpecFile(cmd) {
|
|
@@ -1043,11 +1051,7 @@ const voiceTriggers = {
|
|
|
1043
1051
|
if (!command || !knownCommands.includes(command)) {
|
|
1044
1052
|
// Check voice triggers before falling through to natural language
|
|
1045
1053
|
const fullInput = process.argv.slice(2).join(' ').toLowerCase().trim();
|
|
1046
|
-
const fullInputWithoutFlags = process.argv.slice(2)
|
|
1047
|
-
.filter((arg, index, args) => !String(arg).startsWith('-') && !isOptionValue(args, index, RUNNER_FLAG_NAMES))
|
|
1048
|
-
.join(' ')
|
|
1049
|
-
.toLowerCase()
|
|
1050
|
-
.trim();
|
|
1054
|
+
const fullInputWithoutFlags = parseNaturalEntryArgs(process.argv.slice(2)).input.toLowerCase();
|
|
1051
1055
|
const triggered = voiceTriggers[fullInput] || voiceTriggers[fullInputWithoutFlags];
|
|
1052
1056
|
if (triggered) {
|
|
1053
1057
|
command = triggered;
|
|
@@ -1061,28 +1065,36 @@ if (!command || !knownCommands.includes(command)) {
|
|
|
1061
1065
|
}
|
|
1062
1066
|
|
|
1063
1067
|
if (!command || !knownCommands.includes(command)) {
|
|
1064
|
-
const
|
|
1068
|
+
const rawNaturalArgs = process.argv.slice(2);
|
|
1069
|
+
const natural = parseNaturalEntryArgs(rawNaturalArgs);
|
|
1070
|
+
const userInput = natural.input;
|
|
1071
|
+
const directSingleWordNatural = !natural.multiword
|
|
1072
|
+
&& SINGLE_WORD_NATURAL_INTENTS.has(userInput.toLowerCase());
|
|
1065
1073
|
|
|
1066
|
-
if (
|
|
1074
|
+
if (natural.asJson && !natural.multiword && !directSingleWordNatural) {
|
|
1067
1075
|
console.log(JSON.stringify({
|
|
1068
1076
|
ok: false,
|
|
1069
1077
|
error: command ? `unknown command: ${command}` : 'unknown command',
|
|
1070
1078
|
command: command || null,
|
|
1071
|
-
input:
|
|
1079
|
+
input: rawNaturalArgs.join(' '),
|
|
1072
1080
|
usage: 'atris help',
|
|
1073
1081
|
}, null, 2));
|
|
1074
1082
|
process.exit(2);
|
|
1075
1083
|
}
|
|
1076
1084
|
|
|
1077
1085
|
// Warn if this looks like a mistyped single-word command (no spaces)
|
|
1078
|
-
if (command && !
|
|
1086
|
+
if (command && !natural.multiword && !directSingleWordNatural) {
|
|
1079
1087
|
console.log(`⚠ Unknown command: "${command}". Run "atris help" for available commands.`);
|
|
1088
|
+
const suggestion = suggestCommand(command);
|
|
1089
|
+
if (suggestion) {
|
|
1090
|
+
console.log(` Did you mean "atris ${suggestion}"?`);
|
|
1091
|
+
}
|
|
1080
1092
|
console.log(' Treating as natural language input...\n');
|
|
1081
1093
|
}
|
|
1082
1094
|
|
|
1083
1095
|
// Launch interactive entry (the "Performance")
|
|
1084
|
-
interactiveEntry(userInput)
|
|
1085
|
-
.then(() => process.exit(0))
|
|
1096
|
+
interactiveEntry(userInput, { oneLap: true, asJson: natural.asJson, engine: natural.engine, verifier: natural.verifier, optionError: natural.error })
|
|
1097
|
+
.then((code) => process.exit(Number.isInteger(code) ? code : 0))
|
|
1086
1098
|
.catch((error) => {
|
|
1087
1099
|
console.error(`✗ Error: ${error.message || error}`);
|
|
1088
1100
|
process.exit(1);
|
|
@@ -1090,6 +1102,12 @@ if (!command || !knownCommands.includes(command)) {
|
|
|
1090
1102
|
return;
|
|
1091
1103
|
}
|
|
1092
1104
|
|
|
1105
|
+
// Help and previews promise a write-free workspace. Business workspaces
|
|
1106
|
+
// already have .atris/, so ordinary usage telemetry would break that promise.
|
|
1107
|
+
if (!(helpRequested || dryRunRequested)) {
|
|
1108
|
+
recordUsage(command, process.cwd());
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1093
1111
|
function printAtrisOverview() {
|
|
1094
1112
|
console.log('');
|
|
1095
1113
|
console.log('Atris is an AI computer for a workspace.');
|
|
@@ -1111,23 +1129,90 @@ function shouldSkipContextGatherer() {
|
|
|
1111
1129
|
return !useInteractiveAtrisUi() || initNonInteractiveFlag();
|
|
1112
1130
|
}
|
|
1113
1131
|
|
|
1114
|
-
|
|
1132
|
+
function firstUseCommand() {
|
|
1133
|
+
return 'atris "help me choose the first useful step for this project"';
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function firstMissionObjective() {
|
|
1137
|
+
return 'Verify this Atris workspace is ready';
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function localOwnerName() {
|
|
1141
|
+
return process.env.USER || os.userInfo?.().username || 'operator';
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
function firstMissionOwner(root = process.cwd()) {
|
|
1145
|
+
const defaultOwner = path.join(root, 'atris', 'team', 'validator', 'MEMBER.md');
|
|
1146
|
+
return fs.existsSync(defaultOwner) ? 'validator' : localOwnerName();
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
function firstMissionCommand() {
|
|
1150
|
+
return `atris mission start "${firstMissionObjective()}" --owner ${firstMissionOwner()} --runner manual --lane workspace --verify "node -e \\"require('fs').accessSync('atris/atris.md')\\"" --stop "workspace readiness is verified"`;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function printFirstUseNext() {
|
|
1154
|
+
const row = (label, value) => ` ${label.padEnd(9)}${value}`;
|
|
1155
|
+
console.log(row('next', 'run `atris` and describe what you want in plain words.'));
|
|
1156
|
+
console.log(`agents: ${firstMissionCommand()}`);
|
|
1157
|
+
console.log(`Then: ${firstUseCommand()}`);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function printStarterTaskNext(starter) {
|
|
1161
|
+
console.log('next setup: open atris/MAP.md, then claim the starter task.');
|
|
1162
|
+
if (starter && starter.display_id) {
|
|
1163
|
+
console.log(`Next: atris task claim ${starter.display_id} --as ${localOwnerName()}`);
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
console.log('Next: atris task next --as ' + localOwnerName());
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
async function interactiveEntry(userInput, options = {}) {
|
|
1115
1170
|
const workspaceDir = process.cwd();
|
|
1116
1171
|
const state = detectWorkspaceState(workspaceDir);
|
|
1117
1172
|
const context = loadContext(workspaceDir);
|
|
1118
1173
|
|
|
1174
|
+
if (options.asJson && !String(userInput || '').trim()) {
|
|
1175
|
+
console.log(JSON.stringify({
|
|
1176
|
+
schema: 'atris.one_lap.v1',
|
|
1177
|
+
ok: false,
|
|
1178
|
+
status: 'stuck',
|
|
1179
|
+
reason: 'a request is required',
|
|
1180
|
+
next_action: 'atris "<request>" --json',
|
|
1181
|
+
}, null, 2));
|
|
1182
|
+
return 2;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1119
1185
|
if (isAtrisMetaQuestion(userInput)) {
|
|
1186
|
+
if (options.asJson) {
|
|
1187
|
+
console.log(JSON.stringify({
|
|
1188
|
+
schema: 'atris.overview.v1',
|
|
1189
|
+
ok: true,
|
|
1190
|
+
product: 'Atris',
|
|
1191
|
+
description: 'An AI computer for a workspace with context, tasks, memory, tools, and proof.',
|
|
1192
|
+
workflow: ['plan', 'do', 'review'],
|
|
1193
|
+
}, null, 2));
|
|
1194
|
+
return 0;
|
|
1195
|
+
}
|
|
1120
1196
|
printAtrisOverview();
|
|
1121
1197
|
return;
|
|
1122
1198
|
}
|
|
1123
1199
|
|
|
1124
1200
|
// Fresh install - offer init
|
|
1125
1201
|
if (state.state === 'fresh') {
|
|
1202
|
+
if (options.asJson) {
|
|
1203
|
+
console.log(JSON.stringify({
|
|
1204
|
+
schema: 'atris.one_lap.v1',
|
|
1205
|
+
ok: false,
|
|
1206
|
+
status: 'stuck',
|
|
1207
|
+
reason: 'this workspace is not initialized',
|
|
1208
|
+
next_action: 'atris init --yes',
|
|
1209
|
+
}, null, 2));
|
|
1210
|
+
return 2;
|
|
1211
|
+
}
|
|
1126
1212
|
console.log('\nNo atris/ folder found.');
|
|
1127
1213
|
console.log('');
|
|
1128
|
-
console.log('
|
|
1129
|
-
console.log('
|
|
1130
|
-
console.log(' npx atris init if Atris was installed in this project');
|
|
1214
|
+
console.log('Next: atris init');
|
|
1215
|
+
console.log('Local project install instead? Run: npx atris init');
|
|
1131
1216
|
return;
|
|
1132
1217
|
}
|
|
1133
1218
|
|
|
@@ -1155,6 +1240,55 @@ async function interactiveEntry(userInput) {
|
|
|
1155
1240
|
// commitment that hasn't been closed yet.
|
|
1156
1241
|
const activeMissions = loadActiveMissions(workspaceDir);
|
|
1157
1242
|
const liveMissionsCount = activeMissions.length;
|
|
1243
|
+
const wipCount = inProgressTasksCount + inProgressFeaturesCount;
|
|
1244
|
+
const mapStatus = context.mapStatus || (context.mapExists ? 'ready' : 'missing');
|
|
1245
|
+
const gatherContext = shouldGatherContext({
|
|
1246
|
+
root: workspaceDir,
|
|
1247
|
+
userInput,
|
|
1248
|
+
mapStatus,
|
|
1249
|
+
liveMissionsCount,
|
|
1250
|
+
wipCount,
|
|
1251
|
+
backlogCount,
|
|
1252
|
+
inboxCount,
|
|
1253
|
+
completedTasksCount,
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
if (options.optionError) {
|
|
1257
|
+
const result = {
|
|
1258
|
+
schema: 'atris.one_lap.v1',
|
|
1259
|
+
ok: false,
|
|
1260
|
+
status: 'stuck',
|
|
1261
|
+
reason: options.optionError,
|
|
1262
|
+
next_action: 'atris "<request>" [--engine <id>] [--verify "<cmd>"] [--json]',
|
|
1263
|
+
};
|
|
1264
|
+
if (options.asJson) console.log(JSON.stringify(result, null, 2));
|
|
1265
|
+
else {
|
|
1266
|
+
console.log('lap: stuck');
|
|
1267
|
+
console.log(`why it matters: ${result.reason}`);
|
|
1268
|
+
console.log(`next: ${result.next_action}`);
|
|
1269
|
+
}
|
|
1270
|
+
return 2;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
if (userInput && mapStatus === 'ready' && !gatherContext && options.oneLap !== false) {
|
|
1274
|
+
return require('../commands/one-lap').runOneLap(userInput, {
|
|
1275
|
+
root: workspaceDir,
|
|
1276
|
+
asJson: options.asJson === true,
|
|
1277
|
+
engine: options.engine || '',
|
|
1278
|
+
verifier: options.verifier || '',
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
if (options.asJson && userInput) {
|
|
1283
|
+
console.log(JSON.stringify({
|
|
1284
|
+
schema: 'atris.one_lap.v1',
|
|
1285
|
+
ok: false,
|
|
1286
|
+
status: 'stuck',
|
|
1287
|
+
reason: mapStatus !== 'ready' ? 'the workspace map is not ready' : 'first-contact context is required',
|
|
1288
|
+
next_action: mapStatus !== 'ready' ? 'atris init --yes' : 'atris "<first direction>"',
|
|
1289
|
+
}, null, 2));
|
|
1290
|
+
return 2;
|
|
1291
|
+
}
|
|
1158
1292
|
// Mission needs a tick when: it has a verifier configured AND that verifier
|
|
1159
1293
|
// hasn't passed yet. Planning-state missions count too — first tick is what
|
|
1160
1294
|
// moves them to running.
|
|
@@ -1164,41 +1298,29 @@ async function interactiveEntry(userInput) {
|
|
|
1164
1298
|
|
|
1165
1299
|
// Build status line
|
|
1166
1300
|
const parts = [];
|
|
1167
|
-
const wipCount = inProgressTasksCount + inProgressFeaturesCount;
|
|
1168
1301
|
if (wipCount > 0) {
|
|
1169
|
-
parts.push(`
|
|
1302
|
+
parts.push(`work in progress: ${wipCount}`);
|
|
1170
1303
|
}
|
|
1171
1304
|
if (liveMissionsCount > 0) {
|
|
1172
|
-
parts.push(`
|
|
1305
|
+
parts.push(`missions: ${liveMissionsCount}`);
|
|
1173
1306
|
}
|
|
1174
1307
|
if (inboxCount > 0) {
|
|
1175
|
-
parts.push(`
|
|
1308
|
+
parts.push(`inbox: ${inboxCount}`);
|
|
1176
1309
|
}
|
|
1177
1310
|
if (backlogCount > 0) {
|
|
1178
|
-
parts.push(`
|
|
1311
|
+
parts.push(`backlog: ${backlogCount}`);
|
|
1179
1312
|
}
|
|
1180
1313
|
if (completedTasksCount > 0) {
|
|
1181
|
-
parts.push(`
|
|
1314
|
+
parts.push(`done: ${completedTasksCount}`);
|
|
1182
1315
|
}
|
|
1183
|
-
const statusLine = parts.length > 0 ? parts.join(' | ') : '
|
|
1316
|
+
const statusLine = parts.length > 0 ? parts.join(' | ') : 'clean slate';
|
|
1184
1317
|
|
|
1185
1318
|
console.log('');
|
|
1186
|
-
|
|
1187
|
-
console.log('
|
|
1188
|
-
console.log('
|
|
1189
|
-
console.log(`│ ${statusLine.padEnd(60)}│`);
|
|
1190
|
-
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1319
|
+
const contextRow = (label, value) => ` ${label.padEnd(9)}${value}`;
|
|
1320
|
+
console.log(contextRow('context', 'loaded'));
|
|
1321
|
+
console.log(contextRow('status', statusLine));
|
|
1191
1322
|
|
|
1192
|
-
|
|
1193
|
-
if (shouldGatherContext({
|
|
1194
|
-
root: workspaceDir,
|
|
1195
|
-
userInput,
|
|
1196
|
-
mapStatus,
|
|
1197
|
-
liveMissionsCount,
|
|
1198
|
-
wipCount,
|
|
1199
|
-
backlogCount,
|
|
1200
|
-
inboxCount,
|
|
1201
|
-
})) {
|
|
1323
|
+
if (gatherContext) {
|
|
1202
1324
|
const hotAnswer = String(userInput || '').trim();
|
|
1203
1325
|
if (hotAnswer) {
|
|
1204
1326
|
const answer = hotAnswer;
|
|
@@ -1217,7 +1339,7 @@ async function interactiveEntry(userInput) {
|
|
|
1217
1339
|
console.log(`First task: ${starter.title}`);
|
|
1218
1340
|
}
|
|
1219
1341
|
if (mapStatus !== 'ready') {
|
|
1220
|
-
|
|
1342
|
+
printStarterTaskNext(starter);
|
|
1221
1343
|
return;
|
|
1222
1344
|
}
|
|
1223
1345
|
await planCmd(answer);
|
|
@@ -1225,7 +1347,11 @@ async function interactiveEntry(userInput) {
|
|
|
1225
1347
|
}
|
|
1226
1348
|
if (shouldSkipContextGatherer()) {
|
|
1227
1349
|
console.log('');
|
|
1228
|
-
|
|
1350
|
+
if (process.argv.includes('--verbose')) {
|
|
1351
|
+
console.log('context gatherer skipped (non-interactive).');
|
|
1352
|
+
}
|
|
1353
|
+
printFirstUseNext();
|
|
1354
|
+
return;
|
|
1229
1355
|
} else {
|
|
1230
1356
|
const answer = await askContextGatherer(workspaceDir);
|
|
1231
1357
|
if (isAtrisMetaQuestion(answer)) {
|
|
@@ -1249,7 +1375,7 @@ async function interactiveEntry(userInput) {
|
|
|
1249
1375
|
console.log(`First task: ${starter.title}`);
|
|
1250
1376
|
}
|
|
1251
1377
|
if (mapStatus !== 'ready') {
|
|
1252
|
-
|
|
1378
|
+
printStarterTaskNext(starter);
|
|
1253
1379
|
return;
|
|
1254
1380
|
}
|
|
1255
1381
|
await planCmd(answer);
|
|
@@ -1384,54 +1510,62 @@ function printMapBootstrap({ userInput, prefix = 'Bootstrap required' } = {}) {
|
|
|
1384
1510
|
console.log('');
|
|
1385
1511
|
}
|
|
1386
1512
|
|
|
1387
|
-
//
|
|
1513
|
+
// Boot status: plain rows, honest numbers, one next action.
|
|
1514
|
+
// The banner only renders in a real terminal; when a hook or agent captures
|
|
1515
|
+
// this output it stays compact so it costs almost nothing in context.
|
|
1388
1516
|
function showWelcomeVisualization() {
|
|
1389
|
-
const {
|
|
1517
|
+
const { getTaskGlance } = require('../lib/state-detection');
|
|
1390
1518
|
const { readEndgameState } = require('../commands/autopilot');
|
|
1391
1519
|
const cwd = process.cwd();
|
|
1392
1520
|
const atrisDir = path.join(cwd, 'atris');
|
|
1393
1521
|
const projectName = path.basename(cwd);
|
|
1522
|
+
const row = (label, value) => ` ${label.padEnd(9)}${value}`;
|
|
1523
|
+
const sub = (text) => ` ${' '.repeat(9)}- ${text}`;
|
|
1524
|
+
const trimTitle = (t) => (String(t).length > 64 ? `${String(t).slice(0, 61)}...` : String(t));
|
|
1394
1525
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
let tasksInReview = 0;
|
|
1400
|
-
let tasksCertified = 0;
|
|
1526
|
+
let glance = {
|
|
1527
|
+
backlog: 0, active: 0, review: 0, reviewCertified: 0,
|
|
1528
|
+
activeTitles: [], backlogTitles: [], certifiedTitles: []
|
|
1529
|
+
};
|
|
1401
1530
|
let journalEntries = 0;
|
|
1402
|
-
let
|
|
1403
|
-
let
|
|
1531
|
+
let latestBriefName = '';
|
|
1532
|
+
let latestBriefTitle = '';
|
|
1533
|
+
const isInitialized = fs.existsSync(atrisDir);
|
|
1404
1534
|
let endgameState = { slug: 'unset', horizon: '' };
|
|
1405
1535
|
|
|
1406
1536
|
if (isInitialized) {
|
|
1407
|
-
// Check MAP.md
|
|
1408
|
-
const mapPath = path.join(atrisDir, 'MAP.md');
|
|
1409
|
-
if (fs.existsSync(mapPath)) {
|
|
1410
|
-
hasMap = true;
|
|
1411
|
-
const mapContent = fs.readFileSync(mapPath, 'utf8');
|
|
1412
|
-
// Count file references (lines with file paths)
|
|
1413
|
-
const fileRefs = mapContent.match(/`[^`]+\.(js|ts|py|go|rs|md|json|yaml|yml)`/g);
|
|
1414
|
-
filesIndexed = fileRefs ? fileRefs.length : 0;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
// Task lane counts — DB truth first, TODO.md parse as fallback
|
|
1418
1537
|
try {
|
|
1419
|
-
|
|
1420
|
-
tasksInBacklog = counts.backlog;
|
|
1421
|
-
tasksInProgress = counts.active;
|
|
1422
|
-
tasksInReview = counts.review;
|
|
1423
|
-
tasksCertified = counts.reviewCertified;
|
|
1538
|
+
glance = getTaskGlance(atrisDir);
|
|
1424
1539
|
} catch {
|
|
1425
1540
|
// Silently fail - show 0 tasks if reading fails
|
|
1426
1541
|
}
|
|
1427
1542
|
|
|
1428
|
-
// Read endgame state
|
|
1429
1543
|
try {
|
|
1430
1544
|
endgameState = readEndgameState(cwd);
|
|
1431
1545
|
} catch {
|
|
1432
1546
|
// Silently fail - show unset if reading fails
|
|
1433
1547
|
}
|
|
1434
1548
|
|
|
1549
|
+
try {
|
|
1550
|
+
const briefsDir = path.join(atrisDir, 'wiki', 'briefs');
|
|
1551
|
+
latestBriefName = fs.readdirSync(briefsDir, { withFileTypes: true })
|
|
1552
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
1553
|
+
.map((entry) => ({ name: entry.name, mtimeMs: fs.statSync(path.join(briefsDir, entry.name)).mtimeMs }))
|
|
1554
|
+
.sort((a, b) => b.mtimeMs - a.mtimeMs || a.name.localeCompare(b.name))[0]?.name || '';
|
|
1555
|
+
if (latestBriefName) {
|
|
1556
|
+
// Prefer the brief's own H1 over its filename; strip miner boilerplate
|
|
1557
|
+
// like "YouTube brief: <slug>" so boot reads like a sentence.
|
|
1558
|
+
const head = fs.readFileSync(path.join(briefsDir, latestBriefName), 'utf8').slice(0, 2000);
|
|
1559
|
+
const h1 = head.split('\n').find((line) => line.startsWith('# '));
|
|
1560
|
+
let title = h1 ? h1.slice(2).trim() : '';
|
|
1561
|
+
title = title.replace(/^youtube brief:\s*/i, '').trim();
|
|
1562
|
+
const slug = path.basename(latestBriefName, '.md');
|
|
1563
|
+
latestBriefTitle = title && title.toLowerCase() !== slug.toLowerCase() ? title : slug;
|
|
1564
|
+
}
|
|
1565
|
+
} catch {
|
|
1566
|
+
// Briefs are optional, so missing or unreadable directories stay silent.
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1435
1569
|
// Count journal entries today
|
|
1436
1570
|
const today = new Date();
|
|
1437
1571
|
const year = today.getFullYear();
|
|
@@ -1446,119 +1580,136 @@ function showWelcomeVisualization() {
|
|
|
1446
1580
|
}
|
|
1447
1581
|
|
|
1448
1582
|
console.log('');
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1583
|
+
if (process.stdout.isTTY) {
|
|
1584
|
+
console.log(' ╭──────────────────────────────────────────╮');
|
|
1585
|
+
console.log(' │ │');
|
|
1586
|
+
console.log(' │ █████╗ ████████╗██████╗ ██╗███████╗ │');
|
|
1587
|
+
console.log(' │ ██╔══██╗╚══██╔══╝██╔══██╗██║██╔════╝ │');
|
|
1588
|
+
console.log(' │ ███████║ ██║ ██████╔╝██║███████╗ │');
|
|
1589
|
+
console.log(' │ ██╔══██║ ██║ ██╔══██╗██║╚════██║ │');
|
|
1590
|
+
console.log(' │ ██║ ██║ ██║ ██║ ██║██║███████║ │');
|
|
1591
|
+
console.log(' │ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝ │');
|
|
1592
|
+
console.log(' │ │');
|
|
1593
|
+
console.log(' ╰──────────────────────────────────────────╯');
|
|
1594
|
+
console.log('');
|
|
1595
|
+
}
|
|
1596
|
+
console.log(` atris v${CLI_VERSION} · ${projectName}`);
|
|
1459
1597
|
console.log('');
|
|
1460
1598
|
|
|
1461
1599
|
if (!isInitialized) {
|
|
1462
|
-
console.log('
|
|
1600
|
+
console.log(' no atris workspace here yet.');
|
|
1463
1601
|
console.log('');
|
|
1464
|
-
console.log('
|
|
1465
|
-
console.log(' │ │');
|
|
1466
|
-
console.log(` │ 📍 Project: ${projectName.substring(0, 25).padEnd(25)}│`);
|
|
1467
|
-
console.log(` │ 📄 Spec: atris.md v${CLI_VERSION.padEnd(18)}│`);
|
|
1468
|
-
console.log(' │ │');
|
|
1469
|
-
console.log(' │ Run "atris init" to create workspace │');
|
|
1470
|
-
console.log(' │ │');
|
|
1471
|
-
console.log(' └──────────────────────────────────────────┘');
|
|
1472
|
-
} else {
|
|
1473
|
-
console.log(' ⚡ Scanning spec...');
|
|
1602
|
+
console.log(row('next', 'atris init (set up this folder)'));
|
|
1474
1603
|
console.log('');
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
console.log(`
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
if (latestBriefName) {
|
|
1608
|
+
console.log(` learned \"${latestBriefTitle}\" overnight -> atris/wiki/briefs/${latestBriefName}`);
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
// Show the work itself, not counts. A newcomer in any domain (code, docs,
|
|
1612
|
+
// a travel plan) should read actual task names and know what's happening.
|
|
1613
|
+
// Waiting-on-you comes first: the one thing only a human can do.
|
|
1614
|
+
if (glance.reviewCertified > 0) {
|
|
1615
|
+
console.log(row('you', `${glance.reviewCertified} done, waiting for your ok:`));
|
|
1616
|
+
glance.certifiedTitles.forEach((t) => console.log(sub(trimTitle(t))));
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
if (glance.active > 0) {
|
|
1620
|
+
console.log(row('now', trimTitle(glance.activeTitles[0] || 'work moving')));
|
|
1621
|
+
glance.activeTitles.slice(1).forEach((t) => console.log(sub(trimTitle(t))));
|
|
1622
|
+
const tail = [];
|
|
1623
|
+
const moreActive = glance.active - glance.activeTitles.length;
|
|
1624
|
+
if (moreActive > 0) tail.push(`${moreActive} more moving`);
|
|
1625
|
+
if (glance.backlog > 0) tail.push(`${glance.backlog} waiting to start`);
|
|
1626
|
+
if (glance.review > 0) tail.push(`${glance.review} getting a final look`);
|
|
1627
|
+
if (tail.length) console.log(` ${' '.repeat(9)}...and ${tail.join(', ')}`);
|
|
1628
|
+
} else if (glance.backlog > 0) {
|
|
1629
|
+
console.log(row('soon', trimTitle(glance.backlogTitles[0] || 'work queued')));
|
|
1630
|
+
glance.backlogTitles.slice(1).forEach((t) => console.log(sub(trimTitle(t))));
|
|
1631
|
+
const moreBacklog = glance.backlog - glance.backlogTitles.length;
|
|
1632
|
+
if (moreBacklog > 0) console.log(` ${' '.repeat(9)}...and ${moreBacklog} more waiting`);
|
|
1633
|
+
} else {
|
|
1634
|
+
console.log(row('now', 'nothing on the list yet'));
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// landSummary is expensive (git board classification) - compute once per boot.
|
|
1638
|
+
let landInfo = null;
|
|
1639
|
+
try { landInfo = require('../commands/land').landSummary(cwd); } catch (err) { landInfo = null; }
|
|
1640
|
+
let rotInfo = null;
|
|
1641
|
+
try {
|
|
1642
|
+
const { parseLessons } = require('../lib/memory-view');
|
|
1643
|
+
const resolved = path.resolve(cwd);
|
|
1644
|
+
const parent = path.dirname(resolved);
|
|
1645
|
+
const grandparent = path.dirname(parent);
|
|
1646
|
+
let worktreeDir;
|
|
1647
|
+
if (path.basename(grandparent) === '.agent-worktrees') {
|
|
1648
|
+
worktreeDir = parent;
|
|
1649
|
+
} else {
|
|
1650
|
+
worktreeDir = path.join(path.dirname(resolved), '.agent-worktrees', path.basename(resolved));
|
|
1486
1651
|
}
|
|
1487
|
-
let
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
console.log(` │ 🛬 Land: ${landText.padEnd(26)}│`);
|
|
1652
|
+
let worktrees = 0;
|
|
1653
|
+
if (fs.existsSync(worktreeDir)) {
|
|
1654
|
+
worktrees = fs.readdirSync(worktreeDir, { withFileTypes: true })
|
|
1655
|
+
.filter((entry) => entry.isDirectory()).length;
|
|
1492
1656
|
}
|
|
1493
|
-
let
|
|
1657
|
+
let lessonsText = '';
|
|
1494
1658
|
try {
|
|
1495
|
-
|
|
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
|
-
}
|
|
1659
|
+
lessonsText = fs.readFileSync(path.join(atrisDir, 'lessons.md'), 'utf8');
|
|
1524
1660
|
} catch (err) {
|
|
1525
|
-
|
|
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)}│`);
|
|
1661
|
+
lessonsText = '';
|
|
1530
1662
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1663
|
+
// cleanup = fail lessons nobody has resolved. A `pass` lesson is knowledge
|
|
1664
|
+
// that worked - it has nothing to resolve and counting it guilt-trips
|
|
1665
|
+
// the operator with a number (600+) no one can ever drive to zero.
|
|
1666
|
+
const unresolvedLessons = parseLessons(lessonsText)
|
|
1667
|
+
.filter((lesson) => lesson.status === 'fail' && !lesson.resolved && !/\[resolved[\]:]/i.test(lesson.text)).length;
|
|
1668
|
+
if (worktrees > 0 || unresolvedLessons > 0) {
|
|
1669
|
+
rotInfo = { worktrees, lessons: unresolvedLessons };
|
|
1536
1670
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
if (
|
|
1551
|
-
console.log(
|
|
1671
|
+
} catch (err) {
|
|
1672
|
+
rotInfo = null;
|
|
1673
|
+
}
|
|
1674
|
+
// One tidy row for all loose ends, in words that work outside engineering:
|
|
1675
|
+
// unlanded finished work = "to put away", stale worktrees = "old copies".
|
|
1676
|
+
const tidyBits = [];
|
|
1677
|
+
if (landInfo && landInfo.branches > 0) {
|
|
1678
|
+
let landText = `${landInfo.branches} finished piece${landInfo.branches === 1 ? '' : 's'} to put away`;
|
|
1679
|
+
if (landInfo.due > 0) landText += ` (${landInfo.due} overdue)`;
|
|
1680
|
+
tidyBits.push(landText);
|
|
1681
|
+
}
|
|
1682
|
+
if (rotInfo && rotInfo.worktrees > 0) tidyBits.push(`${rotInfo.worktrees} old cop${rotInfo.worktrees === 1 ? 'y' : 'ies'} to toss`);
|
|
1683
|
+
if (rotInfo && rotInfo.lessons > 0) tidyBits.push(`${rotInfo.lessons} open problem${rotInfo.lessons === 1 ? '' : 's'}`);
|
|
1684
|
+
if (tidyBits.length) {
|
|
1685
|
+
console.log(row('tidy', tidyBits.join(', ')));
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
console.log(row('logs', journalEntries > 0
|
|
1689
|
+
? `${journalEntries} note${journalEntries === 1 ? '' : 's'} today`
|
|
1690
|
+
: 'nothing yet today'));
|
|
1691
|
+
|
|
1692
|
+
if (endgameState.slug !== 'unset') {
|
|
1693
|
+
// Repeated impression: the horizon sentence renders verbatim every boot
|
|
1694
|
+
// so agents keep the target in mind (test/boot-impression.test.js).
|
|
1695
|
+
console.log(row('goal', endgameState.horizon || endgameState.slug));
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// The next command always carries a plain-english gloss: a newcomer should
|
|
1699
|
+
// know what typing it will do before they type it.
|
|
1700
|
+
let next;
|
|
1701
|
+
if (glance.reviewCertified > 0) {
|
|
1702
|
+
next = `atris task reviews (approve the finished work)`;
|
|
1703
|
+
} else if (landInfo && landInfo.due > 0) {
|
|
1704
|
+
next = `atris land --reap (put away the overdue work)`;
|
|
1705
|
+
} else if (endgameState.slug !== 'unset') {
|
|
1706
|
+
next = 'atris autopilot (do the next piece of work)';
|
|
1552
1707
|
} else {
|
|
1553
|
-
|
|
1554
|
-
try { landHint = require('../commands/land').landSummary(process.cwd()); } catch (err) { landHint = null; }
|
|
1555
|
-
if (landHint && landHint.due > 0) {
|
|
1556
|
-
console.log(` Ready. ${landHint.due} overdue in the landing — run 'atris land --reap'.`);
|
|
1557
|
-
} else {
|
|
1558
|
-
console.log(` Ready. Run 'atris plan' to start.`);
|
|
1559
|
-
}
|
|
1708
|
+
next = 'atris plan (plan the first tasks)';
|
|
1560
1709
|
}
|
|
1561
1710
|
console.log('');
|
|
1711
|
+
console.log(row('next', next));
|
|
1712
|
+
console.log('');
|
|
1562
1713
|
}
|
|
1563
1714
|
|
|
1564
1715
|
if (command === 'init') {
|
|
@@ -1616,10 +1767,38 @@ if (command === 'init') {
|
|
|
1616
1767
|
Promise.resolve(require('../commands/task').run(process.argv.slice(3)))
|
|
1617
1768
|
.then(() => process.exit(0))
|
|
1618
1769
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1770
|
+
} else if (command === 'team') {
|
|
1771
|
+
Promise.resolve(require('../commands/team').teamCommand(process.argv.slice(3)))
|
|
1772
|
+
.then((code) => process.exit(code || 0))
|
|
1773
|
+
.catch((err) => { console.error(`\nerror: ${err.message || err}`); process.exit(1); });
|
|
1774
|
+
} else if (command === 'wish') {
|
|
1775
|
+
Promise.resolve(require('../commands/wish').wishCommand(process.argv.slice(3)))
|
|
1776
|
+
.then((code) => process.exit(code || 0))
|
|
1777
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1778
|
+
} else if (command === 'drill') {
|
|
1779
|
+
Promise.resolve(require('../commands/drill').drillCommand(process.argv.slice(3)))
|
|
1780
|
+
.then((code) => process.exit(code || 0))
|
|
1781
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1782
|
+
} else if (command === 'bench') {
|
|
1783
|
+
Promise.resolve(require('../commands/bench').benchCommand(process.argv.slice(3)))
|
|
1784
|
+
.then((code) => process.exit(code || 0))
|
|
1785
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(2); });
|
|
1619
1786
|
} else if (command === 'mission') {
|
|
1787
|
+
// process.exit() can outrun a piped stdout: writes beyond the 64KB pipe
|
|
1788
|
+
// buffer are async, so large --json payloads truncate at 64KB multiples.
|
|
1789
|
+
// Queue an empty write and exit from its callback — it fires only after
|
|
1790
|
+
// every earlier buffered write has drained (BCK-1306).
|
|
1791
|
+
const exitAfterStdoutDrain = (code) => {
|
|
1792
|
+
if (process.stdout.writableLength === 0) process.exit(code);
|
|
1793
|
+
else process.stdout.write('', () => process.exit(code));
|
|
1794
|
+
};
|
|
1620
1795
|
Promise.resolve(require('../commands/mission').missionCommand(process.argv.slice(3)))
|
|
1621
|
-
.then(() =>
|
|
1622
|
-
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`);
|
|
1796
|
+
.then(() => exitAfterStdoutDrain(process.exitCode || 0))
|
|
1797
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); exitAfterStdoutDrain(1); });
|
|
1798
|
+
} else if (command === 'agents') {
|
|
1799
|
+
// Glanceable view of every member's state: stuck, waiting on you, working, resting.
|
|
1800
|
+
const code = require('../commands/agents').agentsCommand(process.argv.slice(3));
|
|
1801
|
+
process.exit(code || 0);
|
|
1623
1802
|
} else if (command === 'pulse') {
|
|
1624
1803
|
// Pulse: durable overnight self-improvement heartbeat (OS cron) for atris-cli.
|
|
1625
1804
|
Promise.resolve(require('../commands/pulse').pulseCommand(process.argv.slice(3)))
|
|
@@ -1642,16 +1821,32 @@ if (command === 'init') {
|
|
|
1642
1821
|
Promise.resolve(require('../commands/land').landCommand(process.argv.slice(3)))
|
|
1643
1822
|
.then((code) => process.exit(code || 0))
|
|
1644
1823
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1824
|
+
} else if (command === 'close') {
|
|
1825
|
+
Promise.resolve(require('../commands/close').run(process.argv.slice(3)))
|
|
1826
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1827
|
+
.catch((err) => { console.error(`\nerror: ${err.message || err}`); process.exit(1); });
|
|
1828
|
+
} else if (command === 'goal' || command === 'wtf') {
|
|
1829
|
+
Promise.resolve(require('../commands/goal').run(process.argv.slice(3)))
|
|
1830
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1831
|
+
.catch((err) => { console.error(`\nerror: ${err.message || err}`); process.exit(1); });
|
|
1645
1832
|
} else if (command === 'drive') {
|
|
1646
1833
|
// Drive: one self-driving tick — mission doctor -> auto-fix safe findings -> count disengagements.
|
|
1647
1834
|
Promise.resolve(require('../commands/drive').driveCommand(process.argv.slice(3)))
|
|
1648
1835
|
.then((code) => process.exit(code || 0))
|
|
1649
1836
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1837
|
+
} else if (command === 'orb') {
|
|
1838
|
+
Promise.resolve(orbCmd(process.argv.slice(3)))
|
|
1839
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1840
|
+
.catch((err) => { console.error(`\nError: ${err.message || err}`); process.exit(1); });
|
|
1650
1841
|
} else if (command === 'radar' || command === 'ctop') {
|
|
1651
1842
|
const radarArgs = command === 'ctop' ? ['--agents', ...process.argv.slice(3)] : process.argv.slice(3);
|
|
1652
1843
|
Promise.resolve(require('../commands/radar').radarCommand(radarArgs))
|
|
1653
1844
|
.then((code) => process.exit(code || 0))
|
|
1654
1845
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1846
|
+
} else if (command === 'stream') {
|
|
1847
|
+
Promise.resolve(require('../commands/stream').streamCommand(process.argv.slice(3)))
|
|
1848
|
+
.then((code) => process.exit(code || 0))
|
|
1849
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1655
1850
|
} else if (command === 'truth') {
|
|
1656
1851
|
// Truth: one table rolling up mission state, tasks, feature proof receipts, and loop heartbeats.
|
|
1657
1852
|
Promise.resolve(require('../commands/truth').truthCommand(process.argv.slice(3)))
|
|
@@ -1671,6 +1866,22 @@ if (command === 'init') {
|
|
|
1671
1866
|
Promise.resolve(require('../commands/improve').run(process.argv.slice(3)))
|
|
1672
1867
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1673
1868
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1869
|
+
} else if (command === 'study') {
|
|
1870
|
+
// Study: on-demand learning feed ingest + local server + browser open.
|
|
1871
|
+
Promise.resolve(require('../commands/study').run(process.argv.slice(3)))
|
|
1872
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1873
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1874
|
+
} else if (command === 'rainmaker') {
|
|
1875
|
+
const code = require('../commands/rainmaker').rainmakerCommand(process.argv.slice(3));
|
|
1876
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
1877
|
+
} else if (command === 'avail') {
|
|
1878
|
+
Promise.resolve(require('../commands/avail').availCommand(process.argv.slice(3)))
|
|
1879
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1880
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1881
|
+
} else if (command === 'meet') {
|
|
1882
|
+
Promise.resolve(require('../commands/meet').meetCommand(process.argv.slice(3)))
|
|
1883
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1884
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1674
1885
|
} else if (command === 'brain') {
|
|
1675
1886
|
Promise.resolve()
|
|
1676
1887
|
.then(() => require('../commands/brain').brainCommand(process.argv.slice(3)))
|
|
@@ -1710,6 +1921,14 @@ if (command === 'init') {
|
|
|
1710
1921
|
} else {
|
|
1711
1922
|
logCmd();
|
|
1712
1923
|
}
|
|
1924
|
+
} else if (command === 'logs') {
|
|
1925
|
+
try {
|
|
1926
|
+
require('../commands/log').logsDigest(process.argv.slice(3));
|
|
1927
|
+
process.exit(0);
|
|
1928
|
+
} catch (error) {
|
|
1929
|
+
console.error(error.message || String(error));
|
|
1930
|
+
process.exit(1);
|
|
1931
|
+
}
|
|
1713
1932
|
} else if (command === 'now') {
|
|
1714
1933
|
const args = process.argv.slice(3);
|
|
1715
1934
|
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
@@ -1726,6 +1945,8 @@ if (command === 'init') {
|
|
|
1726
1945
|
process.exit(0);
|
|
1727
1946
|
}
|
|
1728
1947
|
activateCmd();
|
|
1948
|
+
} else if (command === 'watch') {
|
|
1949
|
+
require('../commands/watch').watchAtris();
|
|
1729
1950
|
} else if (command === 'update' || command === 'sync') {
|
|
1730
1951
|
const args = process.argv.slice(3);
|
|
1731
1952
|
const firstSyncArg = process.argv[3];
|
|
@@ -1756,7 +1977,10 @@ if (command === 'init') {
|
|
|
1756
1977
|
.then(() => process.exit(0))
|
|
1757
1978
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1758
1979
|
} else {
|
|
1759
|
-
syncCmd(
|
|
1980
|
+
syncCmd({
|
|
1981
|
+
dryRun: args.includes('--dry-run'),
|
|
1982
|
+
force: args.includes('--force') || args.includes('--yes') || args.includes('-y'),
|
|
1983
|
+
});
|
|
1760
1984
|
}
|
|
1761
1985
|
} else if (command === 'upgrade') {
|
|
1762
1986
|
const args = process.argv.slice(3);
|
|
@@ -2100,15 +2324,36 @@ if (command === 'init') {
|
|
|
2100
2324
|
console.error(`✗ Brainstorm failed: ${error.message || error}`);
|
|
2101
2325
|
process.exit(1);
|
|
2102
2326
|
});
|
|
2103
|
-
} else if (command === 'next'
|
|
2327
|
+
} else if (command === 'next') {
|
|
2328
|
+
Promise.resolve(require('../commands/next').nextCommand(process.argv.slice(3)))
|
|
2329
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2330
|
+
.catch((error) => {
|
|
2331
|
+
console.error(`✗ Error: ${error.message || error}`);
|
|
2332
|
+
process.exit(1);
|
|
2333
|
+
});
|
|
2334
|
+
} else if (command === 'dream') {
|
|
2335
|
+
Promise.resolve(require('../commands/dream').dreamCommand(process.argv.slice(3)))
|
|
2336
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2337
|
+
.catch((error) => {
|
|
2338
|
+
console.log('No dreams tonight: could not finish dream');
|
|
2339
|
+
console.log('Run me nightly: atris dream');
|
|
2340
|
+
process.exit(0);
|
|
2341
|
+
});
|
|
2342
|
+
} else if (command === 'atris') {
|
|
2104
2343
|
const rawArgs = process.argv.slice(3);
|
|
2105
2344
|
if (rawArgs.includes('--help') || rawArgs.includes('-h') || rawArgs[0] === 'help') {
|
|
2106
2345
|
showNextHelp(command);
|
|
2107
2346
|
process.exit(0);
|
|
2108
2347
|
}
|
|
2109
|
-
const
|
|
2110
|
-
interactiveEntry(
|
|
2111
|
-
|
|
2348
|
+
const natural = parseNaturalEntryArgs(rawArgs);
|
|
2349
|
+
interactiveEntry(natural.input || null, {
|
|
2350
|
+
oneLap: Boolean(natural.input),
|
|
2351
|
+
asJson: natural.asJson,
|
|
2352
|
+
engine: natural.engine,
|
|
2353
|
+
verifier: natural.verifier,
|
|
2354
|
+
optionError: natural.error,
|
|
2355
|
+
})
|
|
2356
|
+
.then((code) => process.exit(Number.isInteger(code) ? code : 0))
|
|
2112
2357
|
.catch((error) => {
|
|
2113
2358
|
console.error(`✗ Error: ${error.message || error}`);
|
|
2114
2359
|
process.exit(1);
|
|
@@ -2194,6 +2439,26 @@ if (command === 'init') {
|
|
|
2194
2439
|
showVerifyHelp();
|
|
2195
2440
|
process.exit(0);
|
|
2196
2441
|
}
|
|
2442
|
+
if (args[0] === 'artifact') {
|
|
2443
|
+
const target = args[1] && !args[1].startsWith('--') ? args[1] : null;
|
|
2444
|
+
if (!target) {
|
|
2445
|
+
showVerifyHelp();
|
|
2446
|
+
process.exit(2);
|
|
2447
|
+
}
|
|
2448
|
+
const readValue = (flag) => {
|
|
2449
|
+
const idx = args.indexOf(flag);
|
|
2450
|
+
return idx > 0 && args[idx + 1] ? args[idx + 1] : null;
|
|
2451
|
+
};
|
|
2452
|
+
const minLinesRaw = readValue('--min-lines');
|
|
2453
|
+
const maxAgeRaw = readValue('--max-age-hours');
|
|
2454
|
+
const code = require('../commands/verify').verifyArtifact(target, {
|
|
2455
|
+
objective: readValue('--objective') || undefined,
|
|
2456
|
+
minLines: minLinesRaw !== null ? Number(minLinesRaw) : undefined,
|
|
2457
|
+
maxAgeHours: maxAgeRaw !== null ? Number(maxAgeRaw) : undefined,
|
|
2458
|
+
json: args.includes('--json'),
|
|
2459
|
+
});
|
|
2460
|
+
process.exit(code);
|
|
2461
|
+
}
|
|
2197
2462
|
const sectionIdx = process.argv.indexOf('--section');
|
|
2198
2463
|
if (sectionIdx > 0 && process.argv[sectionIdx + 1]) {
|
|
2199
2464
|
const slug = process.argv[3] && !process.argv[3].startsWith('--') ? process.argv[3] : null;
|
|
@@ -2214,12 +2479,24 @@ if (command === 'init') {
|
|
|
2214
2479
|
.then(() => process.exit(0))
|
|
2215
2480
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2216
2481
|
} else if (command === 'search') {
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2482
|
+
const code = require('../commands/search').searchCommand(process.argv.slice(3));
|
|
2483
|
+
process.exitCode = code;
|
|
2484
|
+
} else if (command === 'scout') {
|
|
2485
|
+
require('../commands/scout').scoutCommand(process.argv.slice(3))
|
|
2486
|
+
.then((code) => { process.exitCode = code; })
|
|
2487
|
+
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2219
2488
|
} else if (command === 'xp') {
|
|
2220
2489
|
require('../commands/xp').xpCommand(...process.argv.slice(3))
|
|
2221
2490
|
.then(() => { process.exitCode = 0; })
|
|
2222
2491
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2492
|
+
} else if (command === 'report') {
|
|
2493
|
+
const args = process.argv.slice(3);
|
|
2494
|
+
const { reportCommand, showReportHelp } = require('../commands/report');
|
|
2495
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
2496
|
+
showReportHelp();
|
|
2497
|
+
process.exit(0);
|
|
2498
|
+
}
|
|
2499
|
+
process.exit(reportCommand(args));
|
|
2223
2500
|
} else if (command === 'play') {
|
|
2224
2501
|
require('../commands/play').playCommand(...process.argv.slice(3))
|
|
2225
2502
|
.then(() => process.exit(0))
|
|
@@ -2334,10 +2611,15 @@ if (command === 'init') {
|
|
|
2334
2611
|
require('../commands/align').alignAtris()
|
|
2335
2612
|
.then(() => process.exit(0))
|
|
2336
2613
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2614
|
+
} else if (command === 'cloud') {
|
|
2615
|
+
require('../commands/cloud').cloudAtris();
|
|
2337
2616
|
} else if (command === 'terminal') {
|
|
2338
2617
|
require('../commands/terminal').terminalAtris()
|
|
2339
2618
|
.then(() => process.exit(0))
|
|
2340
2619
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2620
|
+
} else if (command === 'fleet-report') {
|
|
2621
|
+
require('../commands/fleet-report').fleetReport()
|
|
2622
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2341
2623
|
} else if (command === 'x') {
|
|
2342
2624
|
// Fast Agent SDK execution - like "atris x echo hello" or "atris x ls -la"
|
|
2343
2625
|
const userInput = process.argv.slice(3).join(' ').trim();
|
|
@@ -2385,10 +2667,19 @@ if (command === 'init') {
|
|
|
2385
2667
|
require('../commands/fleet').fleet(args)
|
|
2386
2668
|
.then(() => process.exit(0))
|
|
2387
2669
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2388
|
-
} else if (command === 'loops') {
|
|
2670
|
+
} else if (command === 'loops' || command === 'self-improve') {
|
|
2389
2671
|
try {
|
|
2390
|
-
require('../commands/loops')
|
|
2391
|
-
process.
|
|
2672
|
+
const loops = require('../commands/loops');
|
|
2673
|
+
const aliasArgs = process.argv.slice(3);
|
|
2674
|
+
const aliasWantsHelp = ['help', '--help', '-h'].includes(aliasArgs[0]);
|
|
2675
|
+
const subcommand = command === 'self-improve'
|
|
2676
|
+
? (aliasWantsHelp ? aliasArgs[0] : 'init')
|
|
2677
|
+
: process.argv[3];
|
|
2678
|
+
const args = command === 'self-improve'
|
|
2679
|
+
? (aliasWantsHelp ? aliasArgs.slice(1) : aliasArgs)
|
|
2680
|
+
: process.argv.slice(4);
|
|
2681
|
+
const exitCode = loops.loopsCommand(subcommand, ...args);
|
|
2682
|
+
process.exit(typeof exitCode === 'number' ? exitCode : 0);
|
|
2392
2683
|
} catch (error) {
|
|
2393
2684
|
console.error(`\n✗ Error: ${error.message || error}`);
|
|
2394
2685
|
process.exit(1);
|
|
@@ -2527,6 +2818,15 @@ if (command === 'init') {
|
|
|
2527
2818
|
Promise.resolve(require('../commands/card').run(process.argv.slice(3)))
|
|
2528
2819
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2529
2820
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2821
|
+
} else if (command === 'brief') {
|
|
2822
|
+
// Brief: one-glance operator surface for landings, waits, and next moves.
|
|
2823
|
+
Promise.resolve(require('../commands/brief').run(process.argv.slice(3)))
|
|
2824
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2825
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2826
|
+
} else if (command === 'pack') {
|
|
2827
|
+
Promise.resolve(require('../commands/pack').run(process.argv.slice(3)))
|
|
2828
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2829
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2530
2830
|
} else if (command === 'reel') {
|
|
2531
2831
|
// Reel: one line of text into a short on-brand video (an animated card; frames via Chrome + ffmpeg).
|
|
2532
2832
|
Promise.resolve(require('../commands/reel').run(process.argv.slice(3)))
|