atris 3.34.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 +35 -0
- package/FOR_AGENTS.md +5 -3
- 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 +35 -8
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/render-cli/SKILL.md +88 -0
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +6 -2
- package/ax +617 -31
- package/bin/atris.js +719 -266
- package/commands/activate.js +194 -88
- package/commands/aeo.js +52 -0
- package/commands/agents.js +166 -0
- package/commands/autoland.js +718 -72
- 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/business.js +91 -8
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/codex-goal.js +26 -2
- 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/drive.js +187 -0
- package/commands/engine.js +1061 -29
- package/commands/experiments.js +28 -0
- package/commands/feed.js +202 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/github.js +38 -0
- package/commands/gm.js +285 -3
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +83 -43
- package/commands/integrations.js +39 -11
- package/commands/interview.js +209 -0
- package/commands/land.js +253 -52
- package/commands/lesson.js +112 -1
- package/commands/lifecycle.js +39 -3
- package/commands/linear.js +38 -0
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +899 -66
- package/commands/mission.js +3512 -332
- package/commands/next.js +137 -0
- package/commands/now.js +240 -21
- 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/radar.js +259 -14
- 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/serve.js +54 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/status.js +50 -5
- package/commands/stream.js +861 -0
- package/commands/stripe.js +38 -0
- package/commands/study.js +693 -0
- package/commands/supabase.js +39 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +2275 -182
- package/commands/team.js +73 -0
- 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/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 +299 -20
- package/commands/write.js +399 -0
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +391 -43
- package/lib/autoland.js +353 -52
- 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 +2431 -38
- 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/memory-view.js +14 -5
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/mission-runtime-loop.js +7 -0
- package/lib/next-moves.js +327 -10
- package/lib/official-cli-integration.js +174 -0
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/outbound-send-gate.js +165 -0
- package/lib/permission-grants.js +293 -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/review-integrity.js +147 -0
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +33 -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 +319 -27
- package/lib/task-proof.js +43 -1
- package/lib/task-receipt.js +93 -0
- 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/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');
|
|
@@ -66,6 +65,8 @@ const {
|
|
|
66
65
|
DEFAULT_CLIENT_ID, DEFAULT_USER_AGENT,
|
|
67
66
|
} = require('../utils/api');
|
|
68
67
|
const missionRuntime = require('../lib/mission-runtime-loop');
|
|
68
|
+
const { knownCommands, suggestCommand } = require('../lib/known-commands');
|
|
69
|
+
const { recordUsage } = require('../lib/usage');
|
|
69
70
|
|
|
70
71
|
// Bind DI wrappers (utils/auth uses dependency injection for apiRequestJson)
|
|
71
72
|
const validateAccessToken = (token) => _validateAccessToken(token, apiRequestJson);
|
|
@@ -86,19 +87,16 @@ const helpRequested = updateCommand === 'help'
|
|
|
86
87
|
|| updateArgs.includes('--help')
|
|
87
88
|
|| updateArgs.includes('-h')
|
|
88
89
|
|| updateArgs[0] === 'help';
|
|
89
|
-
const jsonRequested =
|
|
90
|
+
const jsonRequested = process.argv.slice(2).includes('--json');
|
|
91
|
+
const dryRunRequested = updateArgs.includes('--dry-run');
|
|
90
92
|
const skipUpdateCheck = Boolean(process.env.ATRIS_SKIP_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER || helpRequested || jsonRequested);
|
|
91
93
|
if (!skipUpdateCheck && (!updateCommand || (updateCommand && !['version', 'update'].includes(updateCommand)))) {
|
|
92
94
|
updateCheckPromise = checkForUpdates()
|
|
93
95
|
.then((updateInfo) => {
|
|
94
|
-
// Show notification if update available (after command completes)
|
|
95
96
|
if (updateInfo) {
|
|
96
|
-
|
|
97
|
+
showUpdateNotification(updateInfo, {
|
|
97
98
|
packageRoot: path.join(__dirname, '..'),
|
|
98
99
|
});
|
|
99
|
-
if (!autoUpdateStarted) {
|
|
100
|
-
showUpdateNotification(updateInfo);
|
|
101
|
-
}
|
|
102
100
|
}
|
|
103
101
|
return updateInfo;
|
|
104
102
|
})
|
|
@@ -112,6 +110,12 @@ let command = process.argv[2];
|
|
|
112
110
|
const commandArgs = process.argv.slice(3);
|
|
113
111
|
const firstCommandArg = process.argv[3];
|
|
114
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
|
+
]);
|
|
115
119
|
|
|
116
120
|
function readOptionArg(args, name) {
|
|
117
121
|
const prefix = `${name}=`;
|
|
@@ -126,6 +130,50 @@ function isOptionValue(args, index, optionNames) {
|
|
|
126
130
|
return index > 0 && optionNames.includes(args[index - 1]);
|
|
127
131
|
}
|
|
128
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
|
+
|
|
129
177
|
function applyRunnerFlags(args) {
|
|
130
178
|
// --engine <name> is the operator-facing spelling of --runner-profile:
|
|
131
179
|
// one flag rents a specific intelligence for this run.
|
|
@@ -201,13 +249,14 @@ const isBusinessSyncSafetyCommand = command === 'sync'
|
|
|
201
249
|
|| firstCommandArg === 'resolve'
|
|
202
250
|
);
|
|
203
251
|
|
|
204
|
-
// Auto-sync skills only for commands that modify workspace state
|
|
205
|
-
|
|
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))) {
|
|
206
255
|
try {
|
|
207
256
|
const { syncSkills } = require('../commands/sync');
|
|
208
257
|
const skillsUpdated = syncSkills({ silent: true });
|
|
209
258
|
if (skillsUpdated > 0) {
|
|
210
|
-
console.log(
|
|
259
|
+
console.log(`${skillsUpdated} skill${skillsUpdated > 1 ? 's' : ''} updated`);
|
|
211
260
|
}
|
|
212
261
|
} catch (e) {
|
|
213
262
|
// Non-critical
|
|
@@ -350,76 +399,7 @@ function printAtrisGoalBanner(workspaceDir = process.cwd(), label = 'Atris goal'
|
|
|
350
399
|
}
|
|
351
400
|
|
|
352
401
|
function showSearchHelp() {
|
|
353
|
-
|
|
354
|
-
console.log('Example: atris search auth');
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function searchJournal(keyword) {
|
|
358
|
-
if (!keyword) {
|
|
359
|
-
showSearchHelp();
|
|
360
|
-
process.exit(1);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (keyword === '--help' || keyword === '-h') {
|
|
364
|
-
showSearchHelp();
|
|
365
|
-
process.exit(0);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (process.argv.slice(4).includes('--help') || process.argv.slice(4).includes('-h')) {
|
|
369
|
-
showSearchHelp();
|
|
370
|
-
process.exit(1);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const logsDir = path.join(process.cwd(), 'atris', 'logs');
|
|
374
|
-
if (!fs.existsSync(logsDir)) {
|
|
375
|
-
console.log('No atris/logs/ directory found. Run "atris init" first.');
|
|
376
|
-
process.exit(1);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
console.log(`Searching for "${keyword}" in atris/logs/**/*.md...\n`);
|
|
380
|
-
|
|
381
|
-
const results = [];
|
|
382
|
-
const keywordLower = keyword.toLowerCase();
|
|
383
|
-
|
|
384
|
-
// Recursively find all .md files in logs directory
|
|
385
|
-
function walkDir(dir) {
|
|
386
|
-
let files;
|
|
387
|
-
try { files = fs.readdirSync(dir); } catch { return; }
|
|
388
|
-
for (const file of files) {
|
|
389
|
-
try {
|
|
390
|
-
const filePath = path.join(dir, file);
|
|
391
|
-
const stat = fs.statSync(filePath);
|
|
392
|
-
if (stat.isDirectory()) {
|
|
393
|
-
walkDir(filePath);
|
|
394
|
-
} else if (file.endsWith('.md')) {
|
|
395
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
396
|
-
const lines = content.split('\n');
|
|
397
|
-
lines.forEach((line, idx) => {
|
|
398
|
-
if (line.toLowerCase().includes(keywordLower)) {
|
|
399
|
-
results.push({
|
|
400
|
-
file: path.relative(process.cwd(), filePath),
|
|
401
|
-
line: idx + 1,
|
|
402
|
-
content: line.trim()
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
} catch { /* skip unreadable files */ }
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
walkDir(logsDir);
|
|
412
|
-
|
|
413
|
-
if (results.length === 0) {
|
|
414
|
-
console.log('No matches found.');
|
|
415
|
-
} else {
|
|
416
|
-
console.log(`Found ${results.length} match${results.length > 1 ? 'es' : ''}:\n`);
|
|
417
|
-
results.forEach(r => {
|
|
418
|
-
console.log(`${r.file}:${r.line}`);
|
|
419
|
-
console.log(` ${r.content.substring(0, 100)}${r.content.length > 100 ? '...' : ''}`);
|
|
420
|
-
console.log('');
|
|
421
|
-
});
|
|
422
|
-
}
|
|
402
|
+
require('../commands/search').showSearchHelp();
|
|
423
403
|
}
|
|
424
404
|
|
|
425
405
|
function consoleCmd() {
|
|
@@ -458,7 +438,8 @@ function consoleCmd() {
|
|
|
458
438
|
function showHelp() {
|
|
459
439
|
console.log('');
|
|
460
440
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
461
|
-
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.');
|
|
462
443
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
463
444
|
console.log('');
|
|
464
445
|
console.log('Quick Start:');
|
|
@@ -469,11 +450,15 @@ function showHelp() {
|
|
|
469
450
|
console.log(' 3. Atris acts with context, memory, tools, and a review loop');
|
|
470
451
|
console.log('');
|
|
471
452
|
console.log('Common invocations:');
|
|
472
|
-
console.log(' atris
|
|
473
|
-
console.log('
|
|
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');
|
|
456
|
+
console.log(' atris init [--yes] Global install: initialize this project');
|
|
457
|
+
console.log(' npx atris init [--yes] Local install: initialize this project');
|
|
474
458
|
console.log(' atris computer');
|
|
475
459
|
console.log(' atris business init "My Company"');
|
|
476
460
|
console.log(' atris run');
|
|
461
|
+
console.log(' atris drill');
|
|
477
462
|
console.log(' atris status');
|
|
478
463
|
console.log(' atris soul');
|
|
479
464
|
console.log(' atris fleet status');
|
|
@@ -487,7 +472,7 @@ function showHelp() {
|
|
|
487
472
|
console.log('');
|
|
488
473
|
console.log('Setup:');
|
|
489
474
|
console.log(' setup - Guided first-time setup (login, pick business, pull)');
|
|
490
|
-
console.log(' init - Initialize Atris in current project');
|
|
475
|
+
console.log(' init - Initialize Atris in current project (--yes skips prompts)');
|
|
491
476
|
console.log(' update - Update local files to latest version');
|
|
492
477
|
console.log(' upgrade - Install latest Atris from npm');
|
|
493
478
|
console.log('');
|
|
@@ -503,29 +488,49 @@ function showHelp() {
|
|
|
503
488
|
console.log('');
|
|
504
489
|
console.log('Context & tracking:');
|
|
505
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');
|
|
506
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');
|
|
507
495
|
console.log(' activate - Load Atris context');
|
|
508
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');
|
|
509
500
|
console.log(' ctop - Show a process-first live agent CPU/memory view');
|
|
510
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');
|
|
511
503
|
console.log(' status - See local work and completions (`atris status <business>` for remote)');
|
|
512
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');
|
|
513
506
|
console.log(' xp - Show Career XP and contribution graph');
|
|
514
507
|
console.log(' analytics - Show recent productivity from journals');
|
|
515
|
-
console.log(' search - Search
|
|
508
|
+
console.log(' search - Search workspace memory (atris search <keyword>)');
|
|
516
509
|
console.log(' clean - Housekeeping (stale tasks, archive journals, broken refs)');
|
|
510
|
+
console.log(' close - track open loops with deadlines and daily escalation');
|
|
517
511
|
console.log(' harvest - Find bugs and next actions from receipts, run logs, and thinking');
|
|
518
512
|
console.log(' verify - Validate work is done (tests, MAP.md, changes)');
|
|
519
513
|
console.log(' task - Local agent task plane (atomic claims, TODO import)');
|
|
520
|
-
console.log('
|
|
514
|
+
console.log(' golden path (zero human turns):');
|
|
515
|
+
console.log(' atris task delegate "fix the login bug" --to <member>');
|
|
516
|
+
console.log(' atris task claim <id> --as <member>');
|
|
517
|
+
console.log(' ... build ...');
|
|
518
|
+
console.log(' atris task ready <id> --verify');
|
|
519
|
+
console.log(' atris autoland tick # second check runs, task lands');
|
|
520
|
+
console.log(' mission - Goal + loop + member owner + verifier + receipt; --budget quick|long|deep sets bounded tiers');
|
|
521
521
|
console.log(' release - Tag release, bump version, create GitHub release, draft /launch');
|
|
522
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)');
|
|
523
527
|
console.log(' brain - Compile MAP/TODO/wiki/state into a loadable agent brain');
|
|
524
528
|
console.log(' lesson - Append a one-line lesson to atris/lessons.md (mine: distill receipts/episodes/scorecards into policy lessons)');
|
|
525
529
|
console.log(' ingest - Local-first wiki ingest into atris/wiki/');
|
|
526
530
|
console.log(' query - Local-first wiki query against atris/wiki/');
|
|
527
531
|
console.log(' lint - Local-first wiki lint for atris/wiki/');
|
|
528
532
|
console.log(' loop - Local wiki upkeep loop (stale pages, orphans, next ingest)');
|
|
533
|
+
console.log(' write - Guided writing sessions: you write every word, atris structures + reviews');
|
|
529
534
|
console.log('');
|
|
530
535
|
console.log('Optional helpers:');
|
|
531
536
|
console.log(' brainstorm - Explore ideas conversationally before planning');
|
|
@@ -533,8 +538,9 @@ function showHelp() {
|
|
|
533
538
|
console.log(' improve - Run one paid RL tick (POST /api/improve, deducts credits)');
|
|
534
539
|
console.log(' worktree - Isolated Git worktrees plus guarded ship/merge for parallel agents');
|
|
535
540
|
console.log(' land - The landing: what is actually done vs still in the air; --reap backs up + clears overdue');
|
|
541
|
+
console.log(' drive - One self-driving tick: mission doctor -> auto-fix -> count disengagements');
|
|
536
542
|
console.log(' autoland - Approve the policy once; certified work lands itself, you keep irreversible calls');
|
|
537
|
-
console.log(' engine -
|
|
543
|
+
console.log(' engine - Engine registry: list/resolve roles, health flips, default engine, `engine test`, and dispatch flights');
|
|
538
544
|
console.log(' sign - Co-author trailer on every commit in an atris workspace (on/off/status)');
|
|
539
545
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
540
546
|
console.log(' youtube - Process YouTube videos with timestamped transcript-first analysis');
|
|
@@ -544,6 +550,7 @@ function showHelp() {
|
|
|
544
550
|
console.log(' experiments validate - Validate experiment packs');
|
|
545
551
|
console.log(' experiments run <slug> - Execute a pack or record an Endstate receipt');
|
|
546
552
|
console.log(' experiments benchmark [m] - Run validate/runtime experiment benchmarks');
|
|
553
|
+
console.log(' bench - run core benchmark gates');
|
|
547
554
|
console.log('');
|
|
548
555
|
console.log('Compile loop (learn like AI, run like code):');
|
|
549
556
|
console.log(' compile record <name> - Append an execution record (--input/--output)');
|
|
@@ -559,6 +566,7 @@ function showHelp() {
|
|
|
559
566
|
console.log('Sync:');
|
|
560
567
|
console.log(' pull - Pull journals + member data from cloud');
|
|
561
568
|
console.log(' push - Push workspace files to cloud');
|
|
569
|
+
console.log(' cloud - Delete cloud files not present locally (cloud clean --dry-run|--yes)');
|
|
562
570
|
console.log(' live - Keep a business brain fresh (doctor, pull, watch, push)');
|
|
563
571
|
console.log(' clean-workspace <slug> - Analyze & remove junk files from a workspace (alias: cw)');
|
|
564
572
|
console.log('');
|
|
@@ -566,8 +574,9 @@ function showHelp() {
|
|
|
566
574
|
console.log(' browse [query] - Discover workspace templates');
|
|
567
575
|
console.log(' fork <template> - Clone a template into a new workspace');
|
|
568
576
|
console.log(' publish - Share your workspace as a template');
|
|
569
|
-
console.log('
|
|
570
|
-
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');
|
|
571
580
|
console.log('');
|
|
572
581
|
console.log('Business:');
|
|
573
582
|
console.log(' business init <name> - Create shared owner + first/default computer');
|
|
@@ -594,7 +603,8 @@ function showHelp() {
|
|
|
594
603
|
console.log(' console - Start/attach always-on coding console (tmux daemon)');
|
|
595
604
|
console.log(' soul - Show, snapshot, or fork workspace identity');
|
|
596
605
|
console.log(' fleet - Inspect local fleet status');
|
|
597
|
-
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`');
|
|
598
608
|
console.log(' agent - Select cloud agent, spawn worker requests, or run `agent doctor`');
|
|
599
609
|
console.log(' chat - Chat with Atris 2 Fast in this workspace (--agent for cloud agent; or: atris chat scan)');
|
|
600
610
|
console.log(' fast - Chat with Atris2 Fast');
|
|
@@ -606,6 +616,11 @@ function showHelp() {
|
|
|
606
616
|
console.log(' accounts - Manage accounts (list, add, remove)');
|
|
607
617
|
console.log('');
|
|
608
618
|
console.log('Integrations:');
|
|
619
|
+
console.log(' github - github cli wrapper (doctor, auth, pr list/create/checks/view)');
|
|
620
|
+
console.log(' vercel - vercel cli wrapper (doctor, auth, deploy/ls/logs/inspect)');
|
|
621
|
+
console.log(' supabase - supabase cli wrapper (doctor, auth, status/db/functions)');
|
|
622
|
+
console.log(' linear - linear cli wrapper (doctor, auth, issue list/create/view/update)');
|
|
623
|
+
console.log(' stripe - stripe cli wrapper (doctor, auth, listen/trigger/products)');
|
|
609
624
|
console.log(' gmail - Email commands (inbox, read, archive)');
|
|
610
625
|
console.log(' calendar - Calendar commands (today, week)');
|
|
611
626
|
console.log(' twitter - Twitter commands (post)');
|
|
@@ -754,19 +769,26 @@ function showVerifyHelp() {
|
|
|
754
769
|
console.log('');
|
|
755
770
|
console.log('Usage: atris verify [task]');
|
|
756
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]');
|
|
757
773
|
console.log('');
|
|
758
774
|
console.log('Description:');
|
|
759
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).');
|
|
760
778
|
console.log('');
|
|
761
779
|
console.log('Options:');
|
|
762
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.');
|
|
763
784
|
console.log(' --help, -h Show this help.');
|
|
764
785
|
console.log('');
|
|
765
786
|
}
|
|
766
787
|
|
|
767
788
|
function showUpdateHelp(commandName = 'update') {
|
|
768
789
|
console.log('');
|
|
769
|
-
|
|
790
|
+
const selfFlag = commandName === 'update' ? ' [--self]' : '';
|
|
791
|
+
console.log(`Usage: atris ${commandName} [--all] [--dry-run] [--force]${selfFlag}`);
|
|
770
792
|
console.log('');
|
|
771
793
|
console.log('Description:');
|
|
772
794
|
console.log(' Sync Atris workspace files from the installed CLI templates.');
|
|
@@ -775,6 +797,9 @@ function showUpdateHelp(commandName = 'update') {
|
|
|
775
797
|
console.log(' --all Update Atris files across projects under the current tree.');
|
|
776
798
|
console.log(' --dry-run Preview update work without writing files.');
|
|
777
799
|
console.log(' --force Overwrite existing template files where supported.');
|
|
800
|
+
if (commandName === 'update') {
|
|
801
|
+
console.log(' --self Update the installed atris cli from npm (packaged installs only).');
|
|
802
|
+
}
|
|
778
803
|
console.log(' --help, -h Show this help.');
|
|
779
804
|
console.log('');
|
|
780
805
|
}
|
|
@@ -956,6 +981,7 @@ const { logAtris: logCmd } = require('../commands/log');
|
|
|
956
981
|
const { activateAtris: activateCmd } = require('../commands/activate');
|
|
957
982
|
const { statusAtris: statusCmd } = require('../commands/status');
|
|
958
983
|
const { planAtris: planCmd, doAtris: doCmd, reviewAtris: reviewCmd } = require('../commands/workflow');
|
|
984
|
+
const { runOrb: orbCmd } = require('../commands/orb');
|
|
959
985
|
|
|
960
986
|
// All other commands are lazy-loaded inline (require() only when invoked)
|
|
961
987
|
|
|
@@ -971,12 +997,6 @@ if (command === '2' && ['fast', 'pro'].includes(String(firstCommandArg || '').to
|
|
|
971
997
|
}
|
|
972
998
|
|
|
973
999
|
// Check if this is a known command or natural language input
|
|
974
|
-
const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
|
|
975
|
-
'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
|
-
'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'];
|
|
980
1000
|
|
|
981
1001
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
982
1002
|
function isSpecFile(cmd) {
|
|
@@ -1031,11 +1051,7 @@ const voiceTriggers = {
|
|
|
1031
1051
|
if (!command || !knownCommands.includes(command)) {
|
|
1032
1052
|
// Check voice triggers before falling through to natural language
|
|
1033
1053
|
const fullInput = process.argv.slice(2).join(' ').toLowerCase().trim();
|
|
1034
|
-
const fullInputWithoutFlags = process.argv.slice(2)
|
|
1035
|
-
.filter((arg, index, args) => !String(arg).startsWith('-') && !isOptionValue(args, index, RUNNER_FLAG_NAMES))
|
|
1036
|
-
.join(' ')
|
|
1037
|
-
.toLowerCase()
|
|
1038
|
-
.trim();
|
|
1054
|
+
const fullInputWithoutFlags = parseNaturalEntryArgs(process.argv.slice(2)).input.toLowerCase();
|
|
1039
1055
|
const triggered = voiceTriggers[fullInput] || voiceTriggers[fullInputWithoutFlags];
|
|
1040
1056
|
if (triggered) {
|
|
1041
1057
|
command = triggered;
|
|
@@ -1049,28 +1065,36 @@ if (!command || !knownCommands.includes(command)) {
|
|
|
1049
1065
|
}
|
|
1050
1066
|
|
|
1051
1067
|
if (!command || !knownCommands.includes(command)) {
|
|
1052
|
-
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());
|
|
1053
1073
|
|
|
1054
|
-
if (
|
|
1074
|
+
if (natural.asJson && !natural.multiword && !directSingleWordNatural) {
|
|
1055
1075
|
console.log(JSON.stringify({
|
|
1056
1076
|
ok: false,
|
|
1057
1077
|
error: command ? `unknown command: ${command}` : 'unknown command',
|
|
1058
1078
|
command: command || null,
|
|
1059
|
-
input:
|
|
1079
|
+
input: rawNaturalArgs.join(' '),
|
|
1060
1080
|
usage: 'atris help',
|
|
1061
1081
|
}, null, 2));
|
|
1062
1082
|
process.exit(2);
|
|
1063
1083
|
}
|
|
1064
1084
|
|
|
1065
1085
|
// Warn if this looks like a mistyped single-word command (no spaces)
|
|
1066
|
-
if (command && !
|
|
1086
|
+
if (command && !natural.multiword && !directSingleWordNatural) {
|
|
1067
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
|
+
}
|
|
1068
1092
|
console.log(' Treating as natural language input...\n');
|
|
1069
1093
|
}
|
|
1070
1094
|
|
|
1071
1095
|
// Launch interactive entry (the "Performance")
|
|
1072
|
-
interactiveEntry(userInput)
|
|
1073
|
-
.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))
|
|
1074
1098
|
.catch((error) => {
|
|
1075
1099
|
console.error(`✗ Error: ${error.message || error}`);
|
|
1076
1100
|
process.exit(1);
|
|
@@ -1078,6 +1102,12 @@ if (!command || !knownCommands.includes(command)) {
|
|
|
1078
1102
|
return;
|
|
1079
1103
|
}
|
|
1080
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
|
+
|
|
1081
1111
|
function printAtrisOverview() {
|
|
1082
1112
|
console.log('');
|
|
1083
1113
|
console.log('Atris is an AI computer for a workspace.');
|
|
@@ -1086,23 +1116,103 @@ function printAtrisOverview() {
|
|
|
1086
1116
|
console.log('');
|
|
1087
1117
|
}
|
|
1088
1118
|
|
|
1089
|
-
|
|
1119
|
+
function useInteractiveAtrisUi() {
|
|
1120
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.ATRIS_NO_INTERACTIVE);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
function initNonInteractiveFlag() {
|
|
1124
|
+
const args = process.argv.slice(2);
|
|
1125
|
+
return args.includes('--yes') || args.includes('-y');
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
function shouldSkipContextGatherer() {
|
|
1129
|
+
return !useInteractiveAtrisUi() || initNonInteractiveFlag();
|
|
1130
|
+
}
|
|
1131
|
+
|
|
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 = {}) {
|
|
1090
1170
|
const workspaceDir = process.cwd();
|
|
1091
1171
|
const state = detectWorkspaceState(workspaceDir);
|
|
1092
1172
|
const context = loadContext(workspaceDir);
|
|
1093
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
|
+
|
|
1094
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
|
+
}
|
|
1095
1196
|
printAtrisOverview();
|
|
1096
1197
|
return;
|
|
1097
1198
|
}
|
|
1098
1199
|
|
|
1099
1200
|
// Fresh install - offer init
|
|
1100
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
|
+
}
|
|
1101
1212
|
console.log('\nNo atris/ folder found.');
|
|
1102
1213
|
console.log('');
|
|
1103
|
-
console.log('
|
|
1104
|
-
console.log('
|
|
1105
|
-
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');
|
|
1106
1216
|
return;
|
|
1107
1217
|
}
|
|
1108
1218
|
|
|
@@ -1130,6 +1240,55 @@ async function interactiveEntry(userInput) {
|
|
|
1130
1240
|
// commitment that hasn't been closed yet.
|
|
1131
1241
|
const activeMissions = loadActiveMissions(workspaceDir);
|
|
1132
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
|
+
}
|
|
1133
1292
|
// Mission needs a tick when: it has a verifier configured AND that verifier
|
|
1134
1293
|
// hasn't passed yet. Planning-state missions count too — first tick is what
|
|
1135
1294
|
// moves them to running.
|
|
@@ -1139,68 +1298,89 @@ async function interactiveEntry(userInput) {
|
|
|
1139
1298
|
|
|
1140
1299
|
// Build status line
|
|
1141
1300
|
const parts = [];
|
|
1142
|
-
const wipCount = inProgressTasksCount + inProgressFeaturesCount;
|
|
1143
1301
|
if (wipCount > 0) {
|
|
1144
|
-
parts.push(`
|
|
1302
|
+
parts.push(`work in progress: ${wipCount}`);
|
|
1145
1303
|
}
|
|
1146
1304
|
if (liveMissionsCount > 0) {
|
|
1147
|
-
parts.push(`
|
|
1305
|
+
parts.push(`missions: ${liveMissionsCount}`);
|
|
1148
1306
|
}
|
|
1149
1307
|
if (inboxCount > 0) {
|
|
1150
|
-
parts.push(`
|
|
1308
|
+
parts.push(`inbox: ${inboxCount}`);
|
|
1151
1309
|
}
|
|
1152
1310
|
if (backlogCount > 0) {
|
|
1153
|
-
parts.push(`
|
|
1311
|
+
parts.push(`backlog: ${backlogCount}`);
|
|
1154
1312
|
}
|
|
1155
1313
|
if (completedTasksCount > 0) {
|
|
1156
|
-
parts.push(`
|
|
1314
|
+
parts.push(`done: ${completedTasksCount}`);
|
|
1157
1315
|
}
|
|
1158
|
-
const statusLine = parts.length > 0 ? parts.join(' | ') : '
|
|
1316
|
+
const statusLine = parts.length > 0 ? parts.join(' | ') : 'clean slate';
|
|
1159
1317
|
|
|
1160
1318
|
console.log('');
|
|
1161
|
-
|
|
1162
|
-
console.log('
|
|
1163
|
-
console.log('
|
|
1164
|
-
console.log(`│ ${statusLine.padEnd(60)}│`);
|
|
1165
|
-
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1319
|
+
const contextRow = (label, value) => ` ${label.padEnd(9)}${value}`;
|
|
1320
|
+
console.log(contextRow('context', 'loaded'));
|
|
1321
|
+
console.log(contextRow('status', statusLine));
|
|
1166
1322
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1323
|
+
if (gatherContext) {
|
|
1324
|
+
const hotAnswer = String(userInput || '').trim();
|
|
1325
|
+
if (hotAnswer) {
|
|
1326
|
+
const answer = hotAnswer;
|
|
1327
|
+
if (isAtrisMetaQuestion(answer)) {
|
|
1328
|
+
printAtrisOverview();
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const profile = saveContextProfile(workspaceDir, answer, { source: 'hot_start' });
|
|
1332
|
+
const starter = createStarterTask(workspaceDir, answer);
|
|
1333
|
+
console.log('');
|
|
1334
|
+
console.log('Got it. I saved your first direction.');
|
|
1335
|
+
console.log(`Focus: ${profile.first_answer}`);
|
|
1336
|
+
if (starter && starter.display_id) {
|
|
1337
|
+
console.log(`First task: ${starter.display_id} — ${starter.title}`);
|
|
1338
|
+
} else if (starter && starter.title) {
|
|
1339
|
+
console.log(`First task: ${starter.title}`);
|
|
1340
|
+
}
|
|
1341
|
+
if (mapStatus !== 'ready') {
|
|
1342
|
+
printStarterTaskNext(starter);
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
await planCmd(answer);
|
|
1180
1346
|
return;
|
|
1181
1347
|
}
|
|
1182
|
-
if (
|
|
1348
|
+
if (shouldSkipContextGatherer()) {
|
|
1183
1349
|
console.log('');
|
|
1184
|
-
|
|
1185
|
-
|
|
1350
|
+
if (process.argv.includes('--verbose')) {
|
|
1351
|
+
console.log('context gatherer skipped (non-interactive).');
|
|
1352
|
+
}
|
|
1353
|
+
printFirstUseNext();
|
|
1186
1354
|
return;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1355
|
+
} else {
|
|
1356
|
+
const answer = await askContextGatherer(workspaceDir);
|
|
1357
|
+
if (isAtrisMetaQuestion(answer)) {
|
|
1358
|
+
printAtrisOverview();
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
if (!answer.trim()) {
|
|
1362
|
+
console.log('');
|
|
1363
|
+
console.log('No problem. When you are ready, answer in normal words.');
|
|
1364
|
+
console.log('Example: "help me organize college applications" or "help me build a small website".');
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
const profile = saveContextProfile(workspaceDir, answer, { source: 'cold_start' });
|
|
1368
|
+
const starter = createStarterTask(workspaceDir, answer);
|
|
1369
|
+
console.log('');
|
|
1370
|
+
console.log('Got it. I saved your first direction.');
|
|
1371
|
+
console.log(`Focus: ${profile.first_answer}`);
|
|
1372
|
+
if (starter && starter.display_id) {
|
|
1373
|
+
console.log(`First task: ${starter.display_id} — ${starter.title}`);
|
|
1374
|
+
} else if (starter && starter.title) {
|
|
1375
|
+
console.log(`First task: ${starter.title}`);
|
|
1376
|
+
}
|
|
1377
|
+
if (mapStatus !== 'ready') {
|
|
1378
|
+
printStarterTaskNext(starter);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
await planCmd(answer);
|
|
1200
1382
|
return;
|
|
1201
1383
|
}
|
|
1202
|
-
await planCmd(answer);
|
|
1203
|
-
return;
|
|
1204
1384
|
}
|
|
1205
1385
|
|
|
1206
1386
|
if (mapStatus !== 'ready') {
|
|
@@ -1330,54 +1510,62 @@ function printMapBootstrap({ userInput, prefix = 'Bootstrap required' } = {}) {
|
|
|
1330
1510
|
console.log('');
|
|
1331
1511
|
}
|
|
1332
1512
|
|
|
1333
|
-
//
|
|
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.
|
|
1334
1516
|
function showWelcomeVisualization() {
|
|
1335
|
-
const {
|
|
1517
|
+
const { getTaskGlance } = require('../lib/state-detection');
|
|
1336
1518
|
const { readEndgameState } = require('../commands/autopilot');
|
|
1337
1519
|
const cwd = process.cwd();
|
|
1338
1520
|
const atrisDir = path.join(cwd, 'atris');
|
|
1339
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));
|
|
1340
1525
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
let tasksInReview = 0;
|
|
1346
|
-
let tasksCertified = 0;
|
|
1526
|
+
let glance = {
|
|
1527
|
+
backlog: 0, active: 0, review: 0, reviewCertified: 0,
|
|
1528
|
+
activeTitles: [], backlogTitles: [], certifiedTitles: []
|
|
1529
|
+
};
|
|
1347
1530
|
let journalEntries = 0;
|
|
1348
|
-
let
|
|
1349
|
-
let
|
|
1531
|
+
let latestBriefName = '';
|
|
1532
|
+
let latestBriefTitle = '';
|
|
1533
|
+
const isInitialized = fs.existsSync(atrisDir);
|
|
1350
1534
|
let endgameState = { slug: 'unset', horizon: '' };
|
|
1351
1535
|
|
|
1352
1536
|
if (isInitialized) {
|
|
1353
|
-
// Check MAP.md
|
|
1354
|
-
const mapPath = path.join(atrisDir, 'MAP.md');
|
|
1355
|
-
if (fs.existsSync(mapPath)) {
|
|
1356
|
-
hasMap = true;
|
|
1357
|
-
const mapContent = fs.readFileSync(mapPath, 'utf8');
|
|
1358
|
-
// Count file references (lines with file paths)
|
|
1359
|
-
const fileRefs = mapContent.match(/`[^`]+\.(js|ts|py|go|rs|md|json|yaml|yml)`/g);
|
|
1360
|
-
filesIndexed = fileRefs ? fileRefs.length : 0;
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
// Task lane counts — DB truth first, TODO.md parse as fallback
|
|
1364
1537
|
try {
|
|
1365
|
-
|
|
1366
|
-
tasksInBacklog = counts.backlog;
|
|
1367
|
-
tasksInProgress = counts.active;
|
|
1368
|
-
tasksInReview = counts.review;
|
|
1369
|
-
tasksCertified = counts.reviewCertified;
|
|
1538
|
+
glance = getTaskGlance(atrisDir);
|
|
1370
1539
|
} catch {
|
|
1371
1540
|
// Silently fail - show 0 tasks if reading fails
|
|
1372
1541
|
}
|
|
1373
1542
|
|
|
1374
|
-
// Read endgame state
|
|
1375
1543
|
try {
|
|
1376
1544
|
endgameState = readEndgameState(cwd);
|
|
1377
1545
|
} catch {
|
|
1378
1546
|
// Silently fail - show unset if reading fails
|
|
1379
1547
|
}
|
|
1380
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
|
+
|
|
1381
1569
|
// Count journal entries today
|
|
1382
1570
|
const today = new Date();
|
|
1383
1571
|
const year = today.getFullYear();
|
|
@@ -1392,81 +1580,136 @@ function showWelcomeVisualization() {
|
|
|
1392
1580
|
}
|
|
1393
1581
|
|
|
1394
1582
|
console.log('');
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
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}`);
|
|
1405
1597
|
console.log('');
|
|
1406
1598
|
|
|
1407
1599
|
if (!isInitialized) {
|
|
1408
|
-
console.log('
|
|
1600
|
+
console.log(' no atris workspace here yet.');
|
|
1409
1601
|
console.log('');
|
|
1410
|
-
console.log('
|
|
1411
|
-
console.log(' │ │');
|
|
1412
|
-
console.log(` │ 📍 Project: ${projectName.substring(0, 25).padEnd(25)}│`);
|
|
1413
|
-
console.log(` │ 📄 Spec: atris.md v${CLI_VERSION.padEnd(18)}│`);
|
|
1414
|
-
console.log(' │ │');
|
|
1415
|
-
console.log(' │ Run "atris init" to create workspace │');
|
|
1416
|
-
console.log(' │ │');
|
|
1417
|
-
console.log(' └──────────────────────────────────────────┘');
|
|
1418
|
-
} else {
|
|
1419
|
-
console.log(' ⚡ Scanning spec...');
|
|
1602
|
+
console.log(row('next', 'atris init (set up this folder)'));
|
|
1420
1603
|
console.log('');
|
|
1421
|
-
|
|
1422
|
-
console.log(' │ │');
|
|
1423
|
-
console.log(` │ 📍 Project: ${projectName.substring(0, 25).padEnd(25)}│`);
|
|
1424
|
-
console.log(` │ 📄 Spec: atris.md v${CLI_VERSION.padEnd(18)}│`);
|
|
1425
|
-
console.log(` │ 🗺️ Map: ${hasMap ? (filesIndexed + ' files indexed').padEnd(26) : 'not generated yet'.padEnd(26)}│`);
|
|
1426
|
-
console.log(` │ 📋 Tasks: ${(tasksInBacklog + ' backlog, ' + tasksInProgress + ' active').padEnd(26)}│`);
|
|
1427
|
-
if (tasksInReview > 0) {
|
|
1428
|
-
const reviewText = tasksCertified > 0
|
|
1429
|
-
? `${tasksInReview} waiting (${tasksCertified} certified)`
|
|
1430
|
-
: `${tasksInReview} waiting`;
|
|
1431
|
-
console.log(` │ ⏳ Review: ${reviewText.padEnd(26)}│`);
|
|
1432
|
-
}
|
|
1433
|
-
let landInfo = null;
|
|
1434
|
-
try { landInfo = require('../commands/land').landSummary(process.cwd()); } catch (err) { landInfo = null; }
|
|
1435
|
-
if (landInfo && landInfo.branches > 0) {
|
|
1436
|
-
const landText = `${landInfo.branches} in the air, ${landInfo.due} overdue`;
|
|
1437
|
-
console.log(` │ 🛬 Land: ${landText.padEnd(26)}│`);
|
|
1438
|
-
}
|
|
1439
|
-
console.log(` │ 📝 Journal: ${(journalEntries + ' entries today').padEnd(26)}│`);
|
|
1440
|
-
if (endgameState.slug !== 'unset' && endgameState.horizon) {
|
|
1441
|
-
const endgameLine = endgameState.slug + ' — ' + endgameState.horizon;
|
|
1442
|
-
const paddedEndgame = endgameLine.padEnd(26);
|
|
1443
|
-
console.log(` │ 🎯 Endgame: ${paddedEndgame}│`);
|
|
1444
|
-
}
|
|
1445
|
-
console.log(' │ │');
|
|
1446
|
-
console.log(' │ ┌──────────────────────────────────┐ │');
|
|
1447
|
-
console.log(' │ │ MAP.md ←──── YOU ARE HERE │ │');
|
|
1448
|
-
console.log(' │ │ ↓ │ │');
|
|
1449
|
-
const taskText = `${tasksInBacklog} task${tasksInBacklog === 1 ? '' : 's'} waiting`;
|
|
1450
|
-
console.log(` │ │ TODO.md ←── ${taskText.padEnd(20)}│ │`);
|
|
1451
|
-
console.log(' │ │ ↓ │ │');
|
|
1452
|
-
console.log(' │ │ navigator → executor → validator│ │');
|
|
1453
|
-
console.log(' │ └──────────────────────────────────┘ │');
|
|
1454
|
-
console.log(' │ │');
|
|
1455
|
-
console.log(' └──────────────────────────────────────────┘');
|
|
1604
|
+
return;
|
|
1456
1605
|
}
|
|
1457
|
-
|
|
1458
|
-
if (
|
|
1459
|
-
console.log(`
|
|
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`);
|
|
1460
1633
|
} else {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
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;
|
|
1465
1649
|
} else {
|
|
1466
|
-
|
|
1650
|
+
worktreeDir = path.join(path.dirname(resolved), '.agent-worktrees', path.basename(resolved));
|
|
1651
|
+
}
|
|
1652
|
+
let worktrees = 0;
|
|
1653
|
+
if (fs.existsSync(worktreeDir)) {
|
|
1654
|
+
worktrees = fs.readdirSync(worktreeDir, { withFileTypes: true })
|
|
1655
|
+
.filter((entry) => entry.isDirectory()).length;
|
|
1656
|
+
}
|
|
1657
|
+
let lessonsText = '';
|
|
1658
|
+
try {
|
|
1659
|
+
lessonsText = fs.readFileSync(path.join(atrisDir, 'lessons.md'), 'utf8');
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
lessonsText = '';
|
|
1662
|
+
}
|
|
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 };
|
|
1467
1670
|
}
|
|
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)';
|
|
1707
|
+
} else {
|
|
1708
|
+
next = 'atris plan (plan the first tasks)';
|
|
1468
1709
|
}
|
|
1469
1710
|
console.log('');
|
|
1711
|
+
console.log(row('next', next));
|
|
1712
|
+
console.log('');
|
|
1470
1713
|
}
|
|
1471
1714
|
|
|
1472
1715
|
if (command === 'init') {
|
|
@@ -1524,10 +1767,38 @@ if (command === 'init') {
|
|
|
1524
1767
|
Promise.resolve(require('../commands/task').run(process.argv.slice(3)))
|
|
1525
1768
|
.then(() => process.exit(0))
|
|
1526
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); });
|
|
1527
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
|
+
};
|
|
1528
1795
|
Promise.resolve(require('../commands/mission').missionCommand(process.argv.slice(3)))
|
|
1529
|
-
.then(() =>
|
|
1530
|
-
.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);
|
|
1531
1802
|
} else if (command === 'pulse') {
|
|
1532
1803
|
// Pulse: durable overnight self-improvement heartbeat (OS cron) for atris-cli.
|
|
1533
1804
|
Promise.resolve(require('../commands/pulse').pulseCommand(process.argv.slice(3)))
|
|
@@ -1550,11 +1821,32 @@ if (command === 'init') {
|
|
|
1550
1821
|
Promise.resolve(require('../commands/land').landCommand(process.argv.slice(3)))
|
|
1551
1822
|
.then((code) => process.exit(code || 0))
|
|
1552
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); });
|
|
1832
|
+
} else if (command === 'drive') {
|
|
1833
|
+
// Drive: one self-driving tick — mission doctor -> auto-fix safe findings -> count disengagements.
|
|
1834
|
+
Promise.resolve(require('../commands/drive').driveCommand(process.argv.slice(3)))
|
|
1835
|
+
.then((code) => process.exit(code || 0))
|
|
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); });
|
|
1553
1841
|
} else if (command === 'radar' || command === 'ctop') {
|
|
1554
1842
|
const radarArgs = command === 'ctop' ? ['--agents', ...process.argv.slice(3)] : process.argv.slice(3);
|
|
1555
1843
|
Promise.resolve(require('../commands/radar').radarCommand(radarArgs))
|
|
1556
1844
|
.then((code) => process.exit(code || 0))
|
|
1557
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); });
|
|
1558
1850
|
} else if (command === 'truth') {
|
|
1559
1851
|
// Truth: one table rolling up mission state, tasks, feature proof receipts, and loop heartbeats.
|
|
1560
1852
|
Promise.resolve(require('../commands/truth').truthCommand(process.argv.slice(3)))
|
|
@@ -1574,6 +1866,22 @@ if (command === 'init') {
|
|
|
1574
1866
|
Promise.resolve(require('../commands/improve').run(process.argv.slice(3)))
|
|
1575
1867
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1576
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); });
|
|
1577
1885
|
} else if (command === 'brain') {
|
|
1578
1886
|
Promise.resolve()
|
|
1579
1887
|
.then(() => require('../commands/brain').brainCommand(process.argv.slice(3)))
|
|
@@ -1613,6 +1921,14 @@ if (command === 'init') {
|
|
|
1613
1921
|
} else {
|
|
1614
1922
|
logCmd();
|
|
1615
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
|
+
}
|
|
1616
1932
|
} else if (command === 'now') {
|
|
1617
1933
|
const args = process.argv.slice(3);
|
|
1618
1934
|
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
@@ -1629,6 +1945,8 @@ if (command === 'init') {
|
|
|
1629
1945
|
process.exit(0);
|
|
1630
1946
|
}
|
|
1631
1947
|
activateCmd();
|
|
1948
|
+
} else if (command === 'watch') {
|
|
1949
|
+
require('../commands/watch').watchAtris();
|
|
1632
1950
|
} else if (command === 'update' || command === 'sync') {
|
|
1633
1951
|
const args = process.argv.slice(3);
|
|
1634
1952
|
const firstSyncArg = process.argv[3];
|
|
@@ -1643,6 +1961,11 @@ if (command === 'init') {
|
|
|
1643
1961
|
showUpdateHelp(command);
|
|
1644
1962
|
process.exit(0);
|
|
1645
1963
|
}
|
|
1964
|
+
if (command === 'update' && args.includes('--self')) {
|
|
1965
|
+
const { updateSelf } = require('../commands/update');
|
|
1966
|
+
const result = updateSelf({ packageRoot: path.join(__dirname, '..') });
|
|
1967
|
+
process.exit(result.ok ? 0 : 1);
|
|
1968
|
+
}
|
|
1646
1969
|
if (isBusinessSync) {
|
|
1647
1970
|
Promise.resolve(require('../commands/business-sync').businessSync(process.argv.slice(3)))
|
|
1648
1971
|
.then(() => process.exit(0))
|
|
@@ -1654,7 +1977,10 @@ if (command === 'init') {
|
|
|
1654
1977
|
.then(() => process.exit(0))
|
|
1655
1978
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1656
1979
|
} else {
|
|
1657
|
-
syncCmd(
|
|
1980
|
+
syncCmd({
|
|
1981
|
+
dryRun: args.includes('--dry-run'),
|
|
1982
|
+
force: args.includes('--force') || args.includes('--yes') || args.includes('-y'),
|
|
1983
|
+
});
|
|
1658
1984
|
}
|
|
1659
1985
|
} else if (command === 'upgrade') {
|
|
1660
1986
|
const args = process.argv.slice(3);
|
|
@@ -1998,15 +2324,36 @@ if (command === 'init') {
|
|
|
1998
2324
|
console.error(`✗ Brainstorm failed: ${error.message || error}`);
|
|
1999
2325
|
process.exit(1);
|
|
2000
2326
|
});
|
|
2001
|
-
} 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') {
|
|
2002
2343
|
const rawArgs = process.argv.slice(3);
|
|
2003
2344
|
if (rawArgs.includes('--help') || rawArgs.includes('-h') || rawArgs[0] === 'help') {
|
|
2004
2345
|
showNextHelp(command);
|
|
2005
2346
|
process.exit(0);
|
|
2006
2347
|
}
|
|
2007
|
-
const
|
|
2008
|
-
interactiveEntry(
|
|
2009
|
-
|
|
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))
|
|
2010
2357
|
.catch((error) => {
|
|
2011
2358
|
console.error(`✗ Error: ${error.message || error}`);
|
|
2012
2359
|
process.exit(1);
|
|
@@ -2092,6 +2439,26 @@ if (command === 'init') {
|
|
|
2092
2439
|
showVerifyHelp();
|
|
2093
2440
|
process.exit(0);
|
|
2094
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
|
+
}
|
|
2095
2462
|
const sectionIdx = process.argv.indexOf('--section');
|
|
2096
2463
|
if (sectionIdx > 0 && process.argv[sectionIdx + 1]) {
|
|
2097
2464
|
const slug = process.argv[3] && !process.argv[3].startsWith('--') ? process.argv[3] : null;
|
|
@@ -2112,12 +2479,24 @@ if (command === 'init') {
|
|
|
2112
2479
|
.then(() => process.exit(0))
|
|
2113
2480
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2114
2481
|
} else if (command === 'search') {
|
|
2115
|
-
const
|
|
2116
|
-
|
|
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); });
|
|
2117
2488
|
} else if (command === 'xp') {
|
|
2118
2489
|
require('../commands/xp').xpCommand(...process.argv.slice(3))
|
|
2119
2490
|
.then(() => { process.exitCode = 0; })
|
|
2120
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));
|
|
2121
2500
|
} else if (command === 'play') {
|
|
2122
2501
|
require('../commands/play').playCommand(...process.argv.slice(3))
|
|
2123
2502
|
.then(() => process.exit(0))
|
|
@@ -2126,6 +2505,21 @@ if (command === 'init') {
|
|
|
2126
2505
|
require('../commands/gm').gmCommand(...process.argv.slice(3))
|
|
2127
2506
|
.then(() => process.exit(0))
|
|
2128
2507
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2508
|
+
} else if (command === 'github') {
|
|
2509
|
+
const status = require('../commands/github').githubCommand(process.argv.slice(3));
|
|
2510
|
+
process.exit(status);
|
|
2511
|
+
} else if (command === 'vercel') {
|
|
2512
|
+
const status = require('../commands/vercel').vercelCommand(process.argv.slice(3));
|
|
2513
|
+
process.exit(status);
|
|
2514
|
+
} else if (command === 'supabase') {
|
|
2515
|
+
const status = require('../commands/supabase').supabaseCommand(process.argv.slice(3));
|
|
2516
|
+
process.exit(status);
|
|
2517
|
+
} else if (command === 'linear') {
|
|
2518
|
+
const status = require('../commands/linear').linearCommand(process.argv.slice(3));
|
|
2519
|
+
process.exit(status);
|
|
2520
|
+
} else if (command === 'stripe') {
|
|
2521
|
+
const status = require('../commands/stripe').stripeCommand(process.argv.slice(3));
|
|
2522
|
+
process.exit(status);
|
|
2129
2523
|
} else if (command === 'gmail') {
|
|
2130
2524
|
const { gmailCommand } = require('../commands/integrations');
|
|
2131
2525
|
const subcommand = process.argv[3];
|
|
@@ -2217,10 +2611,15 @@ if (command === 'init') {
|
|
|
2217
2611
|
require('../commands/align').alignAtris()
|
|
2218
2612
|
.then(() => process.exit(0))
|
|
2219
2613
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2614
|
+
} else if (command === 'cloud') {
|
|
2615
|
+
require('../commands/cloud').cloudAtris();
|
|
2220
2616
|
} else if (command === 'terminal') {
|
|
2221
2617
|
require('../commands/terminal').terminalAtris()
|
|
2222
2618
|
.then(() => process.exit(0))
|
|
2223
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); });
|
|
2224
2623
|
} else if (command === 'x') {
|
|
2225
2624
|
// Fast Agent SDK execution - like "atris x echo hello" or "atris x ls -la"
|
|
2226
2625
|
const userInput = process.argv.slice(3).join(' ').trim();
|
|
@@ -2268,10 +2667,19 @@ if (command === 'init') {
|
|
|
2268
2667
|
require('../commands/fleet').fleet(args)
|
|
2269
2668
|
.then(() => process.exit(0))
|
|
2270
2669
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2271
|
-
} else if (command === 'loops') {
|
|
2670
|
+
} else if (command === 'loops' || command === 'self-improve') {
|
|
2272
2671
|
try {
|
|
2273
|
-
require('../commands/loops')
|
|
2274
|
-
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);
|
|
2275
2683
|
} catch (error) {
|
|
2276
2684
|
console.error(`\n✗ Error: ${error.message || error}`);
|
|
2277
2685
|
process.exit(1);
|
|
@@ -2326,10 +2734,13 @@ if (command === 'init') {
|
|
|
2326
2734
|
} else if (command === 'engine' || command === 'engines') {
|
|
2327
2735
|
// Engine: bring any intelligence — roster of installed coding CLIs, default
|
|
2328
2736
|
// engine per workspace, --engine <name> rides any loop for one run.
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2737
|
+
// `engine dispatch` runs an async claim -> build -> ship flight, so the
|
|
2738
|
+
// return value may be a promise or a plain number; Promise.resolve handles
|
|
2739
|
+
// both (mirrors the `compile` command dispatch just above).
|
|
2740
|
+
const engineArgs = command === 'engines' && process.argv.length <= 3 ? [] : process.argv.slice(3);
|
|
2741
|
+
Promise.resolve(require('../commands/engine').engineCommand(engineArgs))
|
|
2742
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2743
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2333
2744
|
} else if (command === 'sign') {
|
|
2334
2745
|
// Sign: prepare-commit-msg hook that credits Atris as co-author on commits in atris workspaces.
|
|
2335
2746
|
try { process.exit(require('../commands/sign').signCommand(process.argv[3]) || 0); }
|
|
@@ -2339,6 +2750,11 @@ if (command === 'init') {
|
|
|
2339
2750
|
Promise.resolve(require('../commands/slop').slopCommand(process.argv.slice(3)))
|
|
2340
2751
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2341
2752
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2753
|
+
} else if (command === 'write') {
|
|
2754
|
+
// Write: guided writing sessions — human types every word, atris structures + reviews (plan-do-review for prose).
|
|
2755
|
+
Promise.resolve(require('../commands/write').writeCommand(process.argv.slice(3)))
|
|
2756
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2757
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2342
2758
|
} else if (command === 'strings') {
|
|
2343
2759
|
// Strings: content design system from live code (no LLM). Extracts UI strings, flags variants,
|
|
2344
2760
|
// enforces preferred terms at the gate. Exit 1 = variants/banned terms found, for CI + the gate.
|
|
@@ -2361,11 +2777,27 @@ if (command === 'init') {
|
|
|
2361
2777
|
Promise.resolve(require('../commands/moves').movesCommand(process.argv.slice(3)))
|
|
2362
2778
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2363
2779
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2780
|
+
} else if (command === 'unknowns') {
|
|
2781
|
+
// Unknowns: blindspot pass from local territory context into the SQLite ledger.
|
|
2782
|
+
Promise.resolve(require('../commands/unknowns').unknownsCommand(process.argv.slice(3)))
|
|
2783
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2784
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2785
|
+
} else if (command === 'feed') {
|
|
2786
|
+
// Feed: read and post the business group feed — receipts and state changes only.
|
|
2787
|
+
// Sets exitCode instead of process.exit() so large --json output flushes fully.
|
|
2788
|
+
Promise.resolve(require('../commands/feed').feedCommand(process.argv.slice(3)))
|
|
2789
|
+
.then((code) => { process.exitCode = typeof code === 'number' ? code : 0; })
|
|
2790
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exitCode = 1; });
|
|
2364
2791
|
} else if (command === 'clarity') {
|
|
2365
2792
|
// Clarity: interview yourself once; agents read how you work so you stop repeating it.
|
|
2366
2793
|
Promise.resolve(require('../commands/clarity').clarityCommand(process.argv.slice(3)))
|
|
2367
2794
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2368
2795
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2796
|
+
} else if (command === 'interview') {
|
|
2797
|
+
// Interview: the interlinked 1-on-1 — live interview that extracts judgment into a member file.
|
|
2798
|
+
Promise.resolve(require('../commands/interview').interviewCommand(process.argv.slice(3)))
|
|
2799
|
+
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2800
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2369
2801
|
} else if (command === 'deck') {
|
|
2370
2802
|
// Deck: premium Google Slides from a plain content spec, via the Atris deck engine (anti-slop design system).
|
|
2371
2803
|
Promise.resolve(require('../commands/deck').run(process.argv.slice(3)))
|
|
@@ -2386,6 +2818,15 @@ if (command === 'init') {
|
|
|
2386
2818
|
Promise.resolve(require('../commands/card').run(process.argv.slice(3)))
|
|
2387
2819
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
2388
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); });
|
|
2389
2830
|
} else if (command === 'reel') {
|
|
2390
2831
|
// Reel: one line of text into a short on-brand video (an animated card; frames via Chrome + ffmpeg).
|
|
2391
2832
|
Promise.resolve(require('../commands/reel').run(process.argv.slice(3)))
|
|
@@ -2734,8 +3175,19 @@ async function agentAtris() {
|
|
|
2734
3175
|
async function chatAtris() {
|
|
2735
3176
|
// Get message from command line args; --agent forces the legacy cloud-agent lane
|
|
2736
3177
|
const rawArgs = process.argv.slice(3);
|
|
2737
|
-
const
|
|
2738
|
-
const
|
|
3178
|
+
const fastLaneFlags = [];
|
|
3179
|
+
const messageArgs = [];
|
|
3180
|
+
let agentLane = false;
|
|
3181
|
+
for (const arg of rawArgs) {
|
|
3182
|
+
if (arg === '--agent') {
|
|
3183
|
+
agentLane = true;
|
|
3184
|
+
} else if (arg === '--print' || arg === '--headless') {
|
|
3185
|
+
fastLaneFlags.push(arg);
|
|
3186
|
+
} else {
|
|
3187
|
+
messageArgs.push(arg);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
const message = messageArgs.join(' ').trim();
|
|
2739
3191
|
|
|
2740
3192
|
// Respect -h / --help before any auth/state checks
|
|
2741
3193
|
if (message === '-h' || message === '--help' || message === 'help') {
|
|
@@ -2746,6 +3198,7 @@ async function chatAtris() {
|
|
|
2746
3198
|
console.log('');
|
|
2747
3199
|
console.log(' atris chat Interactive chat (ax --fast --chat)');
|
|
2748
3200
|
console.log(' atris chat "what now?" One-shot message (ax --fast)');
|
|
3201
|
+
console.log(' atris chat --print "..." Headless JSON result (ax --fast --print)');
|
|
2749
3202
|
console.log(' atris chat --agent [...] Legacy cloud-agent lane (needs `atris agent`)');
|
|
2750
3203
|
process.exit(0);
|
|
2751
3204
|
}
|
|
@@ -2757,7 +3210,7 @@ async function chatAtris() {
|
|
|
2757
3210
|
process.exit(1);
|
|
2758
3211
|
}
|
|
2759
3212
|
|
|
2760
|
-
const missionIntent = missionRunIntentFromFastMessage(message);
|
|
3213
|
+
const missionIntent = fastLaneFlags.length ? null : missionRunIntentFromFastMessage(message);
|
|
2761
3214
|
if (missionIntent) {
|
|
2762
3215
|
process.exit(await runLocalFastMission(missionIntent));
|
|
2763
3216
|
}
|
|
@@ -2770,7 +3223,7 @@ async function chatAtris() {
|
|
|
2770
3223
|
if (!agentLane) {
|
|
2771
3224
|
try {
|
|
2772
3225
|
const axPath = path.join(__dirname, '..', 'ax');
|
|
2773
|
-
const axArgs = message ? ['--fast', message] : ['--fast', '--chat'];
|
|
3226
|
+
const axArgs = message || fastLaneFlags.length ? ['--fast', ...fastLaneFlags, message].filter(Boolean) : ['--fast', '--chat'];
|
|
2774
3227
|
const run = spawnSync(process.execPath, [axPath, ...axArgs], { stdio: 'inherit' });
|
|
2775
3228
|
process.exit(run.status || 0);
|
|
2776
3229
|
} catch {
|