atris 3.57.4 → 3.58.6
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/README.md +12 -1
- package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
- package/atris/skills/create-member/SKILL.md +16 -13
- package/atris/skills/design/SKILL.md +27 -4
- package/atris/skills/engines/SKILL.md +55 -12
- package/atris/skills/x-search/SKILL.md +8 -6
- package/atris/skills/youtube/SKILL.md +66 -21
- package/atris/team/brainstormer/MEMBER.md +2 -2
- package/atris/team/executor/MEMBER.md +3 -3
- package/atris/team/launcher/MEMBER.md +4 -4
- package/atris/team/navigator/MEMBER.md +3 -3
- package/atris/team/researcher/MEMBER.md +2 -2
- package/atris/team/validator/MEMBER.md +1 -1
- package/atris.md +14 -0
- package/ax +153 -23
- package/bin/atris.js +78 -30
- package/commands/aeo.js +4 -4
- package/commands/agents.js +1 -1
- package/commands/align.js +12 -12
- package/commands/analytics.js +3 -3
- package/commands/app.js +5 -5
- package/commands/ask.js +175 -0
- package/commands/auth.js +59 -31
- package/commands/autoland.js +29 -5
- package/commands/autopilot-front.js +6 -6
- package/commands/autopilot.js +90 -90
- package/commands/avail.js +5 -5
- package/commands/bench.js +63 -1
- package/commands/browse.js +2 -2
- package/commands/business.js +12 -12
- package/commands/card.js +2 -2
- package/commands/clean.js +13 -13
- package/commands/close.js +3 -3
- package/commands/compile.js +13 -13
- package/commands/computer.js +94 -27
- package/commands/console.js +5 -5
- package/commands/decide.js +1 -1
- package/commands/deck.js +9 -9
- package/commands/drive.js +4 -4
- package/commands/engine.js +173 -19
- package/commands/errors.js +3 -3
- package/commands/experiments.js +18 -1
- package/commands/feed.js +2 -2
- package/commands/feedback.js +4 -4
- package/commands/fleet.js +12 -12
- package/commands/game.js +1 -1
- package/commands/guide.js +49 -0
- package/commands/improve.js +19 -17
- package/commands/init.js +67 -19
- package/commands/interview.js +7 -7
- package/commands/land.js +40 -15
- package/commands/learn.js +216 -50
- package/commands/lesson.js +2 -2
- package/commands/log.js +1 -1
- package/commands/loops.js +4 -4
- package/commands/member.js +75 -50
- package/commands/mission.js +90 -82
- package/commands/one-lap.js +1 -1
- package/commands/pack.js +74 -8
- package/commands/plugin.js +6 -6
- package/commands/probe.js +9 -9
- package/commands/pull.js +35 -35
- package/commands/pulse.js +1 -1
- package/commands/push.js +21 -21
- package/commands/rainmaker.js +1 -1
- package/commands/recap.js +7 -7
- package/commands/reel.js +2 -2
- package/commands/release.js +3 -3
- package/commands/report.js +1 -1
- package/commands/review.js +5 -5
- package/commands/revisions.js +1 -1
- package/commands/run.js +1 -1
- package/commands/scout.js +3 -3
- package/commands/security-review.js +7 -7
- package/commands/serve.js +9 -9
- package/commands/setup.js +1 -1
- package/commands/sign.js +4 -4
- package/commands/signup.js +4 -4
- package/commands/site.js +8 -3
- package/commands/skill.js +6 -6
- package/commands/slop.js +18 -18
- package/commands/social.js +3 -3
- package/commands/soul.js +14 -14
- package/commands/spaceship.js +1 -1
- package/commands/status.js +2 -2
- package/commands/strings.js +13 -13
- package/commands/study.js +4 -4
- package/commands/sync.js +8 -8
- package/commands/task.js +50 -25
- package/commands/teach.js +2 -2
- package/commands/team.js +1 -1
- package/commands/theme.js +2 -2
- package/commands/tree.js +34 -0
- package/commands/truth.js +7 -7
- package/commands/verify.js +12 -12
- package/commands/visualize.js +2 -2
- package/commands/workflow.js +101 -48
- package/commands/worktree.js +1 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +93 -22
- package/commands/xp.js +6 -3
- package/commands/youtube.js +1019 -123
- package/lib/accept-verify-gate.js +3 -3
- package/lib/activity-stream.js +1 -1
- package/lib/auto-accept-certified.js +28 -12
- package/lib/autoland.js +6 -6
- package/lib/bench/engines.js +59 -8
- package/lib/bench/report.js +1 -1
- package/lib/bench/runner.js +204 -5
- package/lib/bench/tree-render.js +76 -0
- package/lib/card.js +1 -1
- package/lib/chat-log-scan.js +1 -1
- package/lib/claude-boot-block.js +2 -0
- package/lib/deck-compose.js +1 -1
- package/lib/deck-history.js +2 -2
- package/lib/deck-layout.js +1 -1
- package/lib/deck-review.js +5 -5
- package/lib/deck-schema.js +1 -1
- package/lib/default-verifier.js +1 -1
- package/lib/developer-api.js +3 -0
- package/lib/engine-ask.js +45 -7
- package/lib/engine-registry.js +15 -2
- package/lib/file-ops.js +1 -1
- package/lib/fleet.js +71 -35
- package/lib/html-render.js +1 -1
- package/lib/intents.js +172 -0
- package/lib/journal.js +1 -1
- package/lib/known-commands.js +2 -2
- package/lib/land-green.js +364 -0
- package/lib/lesson-contradiction.js +2 -2
- package/lib/lesson-preflight.js +1 -1
- package/lib/manifest.js +5 -5
- package/lib/member-alive.js +9 -5
- package/lib/memory-view.js +3 -3
- package/lib/mission-protected-lane.js +1 -1
- package/lib/mission-root.js +2 -2
- package/lib/orb-context.js +10 -10
- package/lib/pack-capabilities.js +861 -3
- package/lib/permission-grants.js +2 -2
- package/lib/policy-lessons.js +6 -6
- package/lib/pulse.js +8 -8
- package/lib/receipt-evidence.js +1 -1
- package/lib/reel.js +1 -1
- package/lib/review-integrity.js +1 -1
- package/lib/runner-command.js +35 -5
- package/lib/scorecard.js +4 -4
- package/lib/security-scan.js +5 -5
- package/lib/self-drive.js +1 -1
- package/lib/site-publish.js +372 -0
- package/lib/site.js +1 -1
- package/lib/slides-deck.js +2 -2
- package/lib/state-detection.js +2 -2
- package/lib/sync-telemetry.js +2 -2
- package/lib/task-db.js +17 -10
- package/lib/task-explanation.js +1 -1
- package/lib/task-proof.js +2 -2
- package/lib/task-receipt.js +3 -3
- package/lib/theme.js +12 -12
- package/lib/todo-fallback.js +3 -3
- package/lib/todo-sections.js +1 -1
- package/lib/tree-hash.js +79 -0
- package/lib/usage.js +1 -1
- package/lib/wish-delegate.js +1 -1
- package/lib/workspace-safety.js +4 -4
- package/lib/workspace-scaffold.js +3 -3
- package/package.json +1 -1
- package/scripts/det/concierge-bakeoff.sh +26 -0
- package/scripts/det/ytnotes +82 -5
- package/scripts/det/ytquote-repair.js +0 -1
- package/scripts/det/ytrail-race.js +0 -5
- package/scripts/member-operate.mjs +52 -14
- package/scripts/outbound-artifact-gate.js +0 -3
- package/utils/auth.js +47 -9
- package/utils/config.js +0 -1
- package/scripts/det/checklist-score.js +0 -191
package/bin/atris.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// Catch-all for uncaught async errors
|
|
3
|
+
// Catch-all for uncaught async errors, prevents silent crashes
|
|
4
4
|
process.on('unhandledRejection', (err) => {
|
|
5
5
|
console.error(`\n✗ Unexpected error: ${err?.message || err}`);
|
|
6
6
|
process.exit(1);
|
|
@@ -77,7 +77,7 @@ const {
|
|
|
77
77
|
const { getLogPath, ensureLogDirectory, createLogFile } = require('../lib/file-ops');
|
|
78
78
|
const { getConfigPath, loadConfig, saveConfig, loadLogSyncState, saveLogSyncState } = require('../utils/config');
|
|
79
79
|
|
|
80
|
-
// Auth & API (canonical modules
|
|
80
|
+
// Auth & API (canonical modules, eliminates duplicate inline code)
|
|
81
81
|
const {
|
|
82
82
|
decodeJwtClaims, getTokenExpiryEpochSeconds, shouldRefreshToken,
|
|
83
83
|
getCredentialsPath, saveCredentials, loadCredentials, deleteCredentials,
|
|
@@ -316,7 +316,7 @@ if (!helpRequested && !dryRunRequested && (
|
|
|
316
316
|
*
|
|
317
317
|
* Each mission: { id, owner, objective, status, verifier, verifier_passed, next_action, lane }.
|
|
318
318
|
*
|
|
319
|
-
* Returns [] if file missing or malformed
|
|
319
|
+
* Returns [] if file missing or malformed, never throws.
|
|
320
320
|
*/
|
|
321
321
|
function loadActiveMissions(workspaceDir) {
|
|
322
322
|
try {
|
|
@@ -350,7 +350,7 @@ function loadActiveMissions(workspaceDir) {
|
|
|
350
350
|
runner: m.runner || null,
|
|
351
351
|
});
|
|
352
352
|
}
|
|
353
|
-
// Most recently started first (rough
|
|
353
|
+
// Most recently started first (rough, relies on insertion order from reversed walk)
|
|
354
354
|
return live;
|
|
355
355
|
} catch {
|
|
356
356
|
return [];
|
|
@@ -499,6 +499,7 @@ function showHelpShort() {
|
|
|
499
499
|
console.log('');
|
|
500
500
|
console.log(' atris "what do you want here?" empty folder');
|
|
501
501
|
console.log(' atris later "..." remember without a room');
|
|
502
|
+
console.log(' atris guide "..." translate your words');
|
|
502
503
|
console.log(' atris do work already here');
|
|
503
504
|
console.log(' atris spaceship Keep working for a few hours');
|
|
504
505
|
console.log(' atris autopilot Keep working until you stop');
|
|
@@ -510,6 +511,7 @@ function showHelpShort() {
|
|
|
510
511
|
function helpCatalog() {
|
|
511
512
|
return [
|
|
512
513
|
{ name: 'init', summary: 'scaffold atris/ in this project', json: false, interactive_risk: 'medium' },
|
|
514
|
+
{ name: 'guide', summary: 'translate plain english into the right atris move', json: true, interactive_risk: 'none' },
|
|
513
515
|
{ name: 'task', summary: 'local task plane: new, claim, ready, accept', json: true, interactive_risk: 'low' },
|
|
514
516
|
{ name: 'review', summary: 'validate work and capture learnings', json: false, interactive_risk: 'low' },
|
|
515
517
|
{ name: 'recap', summary: 'spoken recap of what your team did', json: true, interactive_risk: 'low' },
|
|
@@ -528,6 +530,7 @@ function showHelpAll() {
|
|
|
528
530
|
console.log('you say what you want. already won. one next step.');
|
|
529
531
|
console.log('');
|
|
530
532
|
console.log(' atris later "..." remember without a room');
|
|
533
|
+
console.log(' atris guide "..." translate your words');
|
|
531
534
|
console.log(' atris do work already here');
|
|
532
535
|
console.log(' atris spaceship Keep working for a few hours');
|
|
533
536
|
console.log(' atris autopilot Keep working until you stop');
|
|
@@ -559,6 +562,7 @@ function showHelpAll() {
|
|
|
559
562
|
console.log(' spaceship - Bounded overnight runner that survives bad ticks and emails updates');
|
|
560
563
|
console.log('');
|
|
561
564
|
console.log('Context & tracking:');
|
|
565
|
+
console.log(' guide - Translate plain english into the right Atris move');
|
|
562
566
|
console.log(' log - Add ideas to inbox (`atris log "note"`; `log --repl` for the editor; see also `wish`)');
|
|
563
567
|
console.log(' wish - Say one plain sentence, then Atris asks only for gaps or delegates it');
|
|
564
568
|
console.log(' now - Show atris/now.md, the current operating truth');
|
|
@@ -581,6 +585,7 @@ function showHelpAll() {
|
|
|
581
585
|
console.log(' xp - Show Career XP and contribution graph');
|
|
582
586
|
console.log(' analytics - Show recent productivity from journals');
|
|
583
587
|
console.log(' revisions - show possible human revisions after atris-assisted landings');
|
|
588
|
+
console.log(' tree hash - hash the live agent text tree (--json for manifest)');
|
|
584
589
|
console.log(' search - Search workspace memory (atris search <keyword>)');
|
|
585
590
|
console.log(' clean - Housekeeping (stale tasks, archive journals, broken refs)');
|
|
586
591
|
console.log(' close - keep ten active loops and park the rest with their history');
|
|
@@ -638,7 +643,7 @@ function showHelpAll() {
|
|
|
638
643
|
console.log(' experiments keep <slug> - Keep a pack only when measure.py moves 0 to 1');
|
|
639
644
|
console.log(' experiments revert <slug> - Run a pack reset.py after a refused keep');
|
|
640
645
|
console.log(' experiments benchmark [m] - Run validate/runtime experiment benchmarks');
|
|
641
|
-
console.log(' bench - run
|
|
646
|
+
console.log(' bench - run benchmark gates or compare trees with bench pair');
|
|
642
647
|
console.log('');
|
|
643
648
|
console.log('Compile loop (learn like AI, run like code):');
|
|
644
649
|
console.log(' compile record <name> - Append an execution record (--input/--output)');
|
|
@@ -1112,7 +1117,7 @@ if (command === 'help' || command === '--help' || command === '-h') {
|
|
|
1112
1117
|
process.exit(0);
|
|
1113
1118
|
}
|
|
1114
1119
|
|
|
1115
|
-
// Core command handlers
|
|
1120
|
+
// Core command handlers, loaded eagerly (used by interactiveEntry default path)
|
|
1116
1121
|
const { initAtris: initCmd } = require('../commands/init');
|
|
1117
1122
|
const { syncAtris: syncCmd, syncAtrisAll: syncAllCmd } = require('../commands/sync');
|
|
1118
1123
|
const { logAtris: logCmd } = require('../commands/log');
|
|
@@ -1154,7 +1159,7 @@ if (command === '--version' || command === '-v' || process.argv.includes('--vers
|
|
|
1154
1159
|
}
|
|
1155
1160
|
|
|
1156
1161
|
// If no command OR command is not recognized, treat as natural language
|
|
1157
|
-
// Voice-friendly aliases
|
|
1162
|
+
// Voice-friendly aliases, natural language → command mapping
|
|
1158
1163
|
// Solves speech-to-text issues (inspired by gstack v0.14.6 voice-triggers)
|
|
1159
1164
|
// One-word voice aliases like start/go/audit/deploy must not spawn runners.
|
|
1160
1165
|
// Unmatched single verbs exit 2 with did-you-mean (see below). Keep phrases
|
|
@@ -1197,11 +1202,11 @@ if (!command || !knownCommands.includes(command)) {
|
|
|
1197
1202
|
const triggered = voiceTriggers[fullInput] || voiceTriggers[fullInputWithoutFlags];
|
|
1198
1203
|
if (triggered) {
|
|
1199
1204
|
command = triggered;
|
|
1200
|
-
// Re-check
|
|
1205
|
+
// Re-check, if it's now a known command, fall through to dispatch
|
|
1201
1206
|
if (knownCommands.includes(command)) {
|
|
1202
1207
|
// Rewrite argv so dispatch works
|
|
1203
1208
|
process.argv[2] = command;
|
|
1204
|
-
// Don't return
|
|
1209
|
+
// Don't return, let it fall through to the command dispatch below
|
|
1205
1210
|
}
|
|
1206
1211
|
}
|
|
1207
1212
|
}
|
|
@@ -1454,7 +1459,7 @@ async function interactiveEntry(userInput, options = {}) {
|
|
|
1454
1459
|
? context.inProgressFeaturesCount
|
|
1455
1460
|
: (context.inProgressFeatures || []).length;
|
|
1456
1461
|
|
|
1457
|
-
// Pull active missions (durable goals)
|
|
1462
|
+
// Pull active missions (durable goals), these outrank dev-pipeline state
|
|
1458
1463
|
// because a mission with an unverified verifier is a Keshav-attributable
|
|
1459
1464
|
// commitment that hasn't been closed yet.
|
|
1460
1465
|
const activeMissions = loadActiveMissions(workspaceDir);
|
|
@@ -1554,7 +1559,7 @@ async function interactiveEntry(userInput, options = {}) {
|
|
|
1554
1559
|
console.log('Got it. I saved your first direction.');
|
|
1555
1560
|
console.log(`Focus: ${profile.first_answer}`);
|
|
1556
1561
|
if (starter && starter.display_id) {
|
|
1557
|
-
console.log(`First task: ${starter.display_id}
|
|
1562
|
+
console.log(`First task: ${starter.display_id}, ${starter.title}`);
|
|
1558
1563
|
} else if (starter && starter.title) {
|
|
1559
1564
|
console.log(`First task: ${starter.title}`);
|
|
1560
1565
|
}
|
|
@@ -1581,7 +1586,7 @@ async function interactiveEntry(userInput, options = {}) {
|
|
|
1581
1586
|
console.log('Got it. I saved your first direction.');
|
|
1582
1587
|
console.log(`Focus: ${profile.first_answer}`);
|
|
1583
1588
|
if (starter && starter.display_id) {
|
|
1584
|
-
console.log(`First task: ${starter.display_id}
|
|
1589
|
+
console.log(`First task: ${starter.display_id}, ${starter.title}`);
|
|
1585
1590
|
} else if (starter && starter.title) {
|
|
1586
1591
|
console.log(`First task: ${starter.title}`);
|
|
1587
1592
|
}
|
|
@@ -1609,6 +1614,7 @@ async function askContextGatherer(workspaceDir) {
|
|
|
1609
1614
|
// this output it stays compact so it costs almost nothing in context.
|
|
1610
1615
|
function showWelcomeVisualization() {
|
|
1611
1616
|
const { getTaskGlance } = require('../lib/state-detection');
|
|
1617
|
+
const { INTENTS } = require('../lib/intents');
|
|
1612
1618
|
const { readEndgameState } = require('../commands/autopilot');
|
|
1613
1619
|
const cwd = process.cwd();
|
|
1614
1620
|
const atrisDir = path.join(cwd, 'atris');
|
|
@@ -1816,6 +1822,17 @@ function showWelcomeVisualization() {
|
|
|
1816
1822
|
console.log(row('goal', endgameState.horizon || endgameState.slug));
|
|
1817
1823
|
}
|
|
1818
1824
|
|
|
1825
|
+
const hasNoTasks = glance.active === 0
|
|
1826
|
+
&& glance.review === 0
|
|
1827
|
+
&& glance.reviewCertified === 0;
|
|
1828
|
+
if (hasNoTasks) {
|
|
1829
|
+
const phrases = INTENTS
|
|
1830
|
+
.filter((intent) => intent.offer === 'boot_empty')
|
|
1831
|
+
.map((intent) => intent.say[0])
|
|
1832
|
+
.slice(0, 2);
|
|
1833
|
+
console.log(row('say', `"${phrases[0]}" or "${phrases[1]}" (your agent translates)`));
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1819
1836
|
// The next command always carries a plain-english gloss: a newcomer should
|
|
1820
1837
|
// know what typing it will do before they type it.
|
|
1821
1838
|
let next;
|
|
@@ -1833,7 +1850,10 @@ function showWelcomeVisualization() {
|
|
|
1833
1850
|
console.log('');
|
|
1834
1851
|
}
|
|
1835
1852
|
|
|
1836
|
-
if (command === '
|
|
1853
|
+
if (command === 'guide') {
|
|
1854
|
+
const code = require('../commands/guide').guideCommand(process.argv.slice(3));
|
|
1855
|
+
process.exit(typeof code === 'number' ? code : 0);
|
|
1856
|
+
} else if (command === 'init') {
|
|
1837
1857
|
// Help flag must short-circuit before initCmd() (which scaffolds files)
|
|
1838
1858
|
// and before interactiveEntry (which loads workspace context).
|
|
1839
1859
|
const initArg = process.argv[3];
|
|
@@ -1884,7 +1904,7 @@ if (command === 'init') {
|
|
|
1884
1904
|
} else if (command === 'decide') {
|
|
1885
1905
|
// process.exit() can outrun a piped stdout: writes beyond the 64KB pipe
|
|
1886
1906
|
// buffer are async, so large --json payloads truncate at 64KB multiples.
|
|
1887
|
-
// Queue an empty write and exit from its callback
|
|
1907
|
+
// Queue an empty write and exit from its callback, it fires only after
|
|
1888
1908
|
// every earlier buffered write has drained (BCK-1306).
|
|
1889
1909
|
const exitAfterStdoutDrain = (code) => {
|
|
1890
1910
|
if (process.stdout.writableLength === 0) process.exit(code);
|
|
@@ -1912,7 +1932,7 @@ if (command === 'init') {
|
|
|
1912
1932
|
} else if (command === 'mission') {
|
|
1913
1933
|
// process.exit() can outrun a piped stdout: writes beyond the 64KB pipe
|
|
1914
1934
|
// buffer are async, so large --json payloads truncate at 64KB multiples.
|
|
1915
|
-
// Queue an empty write and exit from its callback
|
|
1935
|
+
// Queue an empty write and exit from its callback, it fires only after
|
|
1916
1936
|
// every earlier buffered write has drained (BCK-1306).
|
|
1917
1937
|
const exitAfterStdoutDrain = (code) => {
|
|
1918
1938
|
if (process.stdout.writableLength === 0) process.exit(code);
|
|
@@ -1975,7 +1995,7 @@ if (command === 'init') {
|
|
|
1975
1995
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
1976
1996
|
.catch((err) => { console.error(`\nerror: ${err.message || err}`); process.exit(1); });
|
|
1977
1997
|
} else if (command === 'drive') {
|
|
1978
|
-
// Drive: one self-driving tick
|
|
1998
|
+
// Drive: one self-driving tick, mission doctor -> auto-fix safe findings -> count disengagements.
|
|
1979
1999
|
Promise.resolve(require('../commands/drive').driveCommand(process.argv.slice(3)))
|
|
1980
2000
|
.then((code) => process.exit(code || 0))
|
|
1981
2001
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
@@ -2002,7 +2022,7 @@ if (command === 'init') {
|
|
|
2002
2022
|
.then(() => process.exit(process.exitCode || 0))
|
|
2003
2023
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2004
2024
|
} else if (command === 'aeo') {
|
|
2005
|
-
// AEO: AI Engine Optimization
|
|
2025
|
+
// AEO: AI Engine Optimization, credit-metered citation drafting against the customer workspace.
|
|
2006
2026
|
Promise.resolve(require('../commands/aeo').run(process.argv.slice(3)))
|
|
2007
2027
|
.then(() => process.exit(0))
|
|
2008
2028
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
@@ -2163,6 +2183,13 @@ if (command === 'init') {
|
|
|
2163
2183
|
process.exit(0);
|
|
2164
2184
|
}
|
|
2165
2185
|
upgradeAtris().then(() => process.exit(0)).catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2186
|
+
} else if (command === 'chat' && (process.argv[3] === '--personal' || process.argv[3] === '-p')) {
|
|
2187
|
+
require('../commands/ask').askAtris(process.argv.slice(4))
|
|
2188
|
+
.then(() => process.exit(0))
|
|
2189
|
+
.catch((error) => {
|
|
2190
|
+
console.error(`✗ Ask failed: ${error.message || error}`);
|
|
2191
|
+
process.exit(1);
|
|
2192
|
+
});
|
|
2166
2193
|
} else if (command === 'chat') {
|
|
2167
2194
|
if (process.argv[3] === 'scan') {
|
|
2168
2195
|
try {
|
|
@@ -2189,7 +2216,7 @@ if (command === 'init') {
|
|
|
2189
2216
|
} else if (command === 'console') {
|
|
2190
2217
|
consoleCmd();
|
|
2191
2218
|
} else if (command === 'serve') {
|
|
2192
|
-
// Start the local AI Computer bridge
|
|
2219
|
+
// Start the local AI Computer bridge, make this directory addressable
|
|
2193
2220
|
// by cloud agents via the Atris API
|
|
2194
2221
|
const serveArgs = process.argv.slice(3);
|
|
2195
2222
|
if (serveArgs.includes('--help') || serveArgs.includes('-h') || serveArgs[0] === 'help') {
|
|
@@ -2291,7 +2318,7 @@ if (command === 'init') {
|
|
|
2291
2318
|
// Hidden: copy profile to credentials.json (global switch, legacy)
|
|
2292
2319
|
require('../commands/auth').activateGlobal();
|
|
2293
2320
|
} else if (command === '_switch-session') {
|
|
2294
|
-
// Hidden: per-terminal switch
|
|
2321
|
+
// Hidden: per-terminal switch, writes session file so each tab keeps its own account
|
|
2295
2322
|
require('../commands/auth').switchSession();
|
|
2296
2323
|
} else if (command === 'shell-init') {
|
|
2297
2324
|
require('../commands/auth').shellInit();
|
|
@@ -3062,7 +3089,7 @@ if (command === 'init') {
|
|
|
3062
3089
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3063
3090
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3064
3091
|
} else if (command === 'write') {
|
|
3065
|
-
// Write: guided writing sessions
|
|
3092
|
+
// Write: guided writing sessions, human types every word, atris structures + reviews (plan-do-review for prose).
|
|
3066
3093
|
Promise.resolve(require('../commands/write').writeCommand(process.argv.slice(3)))
|
|
3067
3094
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3068
3095
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
@@ -3084,7 +3111,7 @@ if (command === 'init') {
|
|
|
3084
3111
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3085
3112
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3086
3113
|
} else if (command === 'moves') {
|
|
3087
|
-
// Moves: your 3 next moves
|
|
3114
|
+
// Moves: your 3 next moves, approve one into the loop, kill, or skip.
|
|
3088
3115
|
Promise.resolve(require('../commands/moves').movesCommand(process.argv.slice(3)))
|
|
3089
3116
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3090
3117
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
@@ -3094,7 +3121,7 @@ if (command === 'init') {
|
|
|
3094
3121
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3095
3122
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3096
3123
|
} else if (command === 'feed') {
|
|
3097
|
-
// Feed: read and post the business group feed
|
|
3124
|
+
// Feed: read and post the business group feed, receipts and state changes only.
|
|
3098
3125
|
// Sets exitCode instead of process.exit() so large --json output flushes fully.
|
|
3099
3126
|
Promise.resolve(require('../commands/feed').feedCommand(process.argv.slice(3)))
|
|
3100
3127
|
.then((code) => { process.exitCode = typeof code === 'number' ? code : 0; })
|
|
@@ -3105,7 +3132,7 @@ if (command === 'init') {
|
|
|
3105
3132
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3106
3133
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3107
3134
|
} else if (command === 'interview') {
|
|
3108
|
-
// Interview: the interlinked 1-on-1
|
|
3135
|
+
// Interview: the interlinked 1-on-1, live interview that extracts judgment into a member file.
|
|
3109
3136
|
Promise.resolve(require('../commands/interview').interviewCommand(process.argv.slice(3)))
|
|
3110
3137
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3111
3138
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
@@ -3115,7 +3142,7 @@ if (command === 'init') {
|
|
|
3115
3142
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3116
3143
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3117
3144
|
} else if (command === 'site') {
|
|
3118
|
-
// Site:
|
|
3145
|
+
// Site: build markdown sites or publish static web folders.
|
|
3119
3146
|
{
|
|
3120
3147
|
const raw = process.argv.slice(3);
|
|
3121
3148
|
const deployWrite = raw[0] === 'deploy'
|
|
@@ -3151,6 +3178,11 @@ if (command === 'init') {
|
|
|
3151
3178
|
Promise.resolve(require('../commands/reel').run(process.argv.slice(3)))
|
|
3152
3179
|
.then((code) => process.exit(typeof code === 'number' ? code : 0))
|
|
3153
3180
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
3181
|
+
} else if (command === 'tree') {
|
|
3182
|
+
const subcommand = process.argv[3];
|
|
3183
|
+
const args = process.argv.slice(4);
|
|
3184
|
+
const code = require('../commands/tree').treeCommand(subcommand, ...args);
|
|
3185
|
+
process.exit(code || 0);
|
|
3154
3186
|
} else if (command === 'receipt' || command === 'proof' || command === 'openclaw') {
|
|
3155
3187
|
const subcommand = process.argv[3];
|
|
3156
3188
|
const args = process.argv.slice(4);
|
|
@@ -3550,10 +3582,19 @@ async function chatAtris() {
|
|
|
3550
3582
|
const fastLaneFlags = [];
|
|
3551
3583
|
const messageArgs = [];
|
|
3552
3584
|
let agentLane = false;
|
|
3553
|
-
for (
|
|
3585
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
3586
|
+
const arg = rawArgs[index];
|
|
3554
3587
|
if (arg === '--agent') {
|
|
3555
3588
|
agentLane = true;
|
|
3556
|
-
} else if (arg === '--
|
|
3589
|
+
} else if (arg === '--effort') {
|
|
3590
|
+
const next = rawArgs[index + 1];
|
|
3591
|
+
if (next && !next.startsWith('-')) {
|
|
3592
|
+
fastLaneFlags.push('--effort', next);
|
|
3593
|
+
index += 1;
|
|
3594
|
+
} else {
|
|
3595
|
+
fastLaneFlags.push('--effort');
|
|
3596
|
+
}
|
|
3597
|
+
} else if (arg === '--print' || arg === '--headless' || arg === '--rapid' || arg === '--alpha' || arg === '--auto-approve') {
|
|
3557
3598
|
fastLaneFlags.push(arg);
|
|
3558
3599
|
} else {
|
|
3559
3600
|
messageArgs.push(arg);
|
|
@@ -3567,10 +3608,13 @@ async function chatAtris() {
|
|
|
3567
3608
|
console.log('');
|
|
3568
3609
|
console.log(' Chat with Atris 2 Fast in this workspace: tools attached, same turn as `ax --fast`.');
|
|
3569
3610
|
console.log(' Pass --rapid to use Atris Rapid instead.');
|
|
3611
|
+
console.log(' Pass --alpha to use Atris Alpha (experimental preview lane).');
|
|
3612
|
+
console.log(' Pass --effort medium|high|xhigh to override reasoning depth for the turn/session.');
|
|
3570
3613
|
console.log(' Requires `atris login`.');
|
|
3571
3614
|
console.log('');
|
|
3572
3615
|
console.log(' atris chat Interactive chat (ax --fast --chat)');
|
|
3573
3616
|
console.log(' atris chat --rapid Interactive Rapid chat (ax --rapid --chat)');
|
|
3617
|
+
console.log(' atris chat --alpha Interactive Alpha chat (ax --alpha --chat)');
|
|
3574
3618
|
console.log(' atris chat --rapid --auto-approve Rapid chat that auto-approves safe git push');
|
|
3575
3619
|
console.log(' atris chat "what now?" One-shot message (ax --fast)');
|
|
3576
3620
|
console.log(' atris chat --print "..." Headless JSON result (ax --fast --print)');
|
|
@@ -3598,8 +3642,12 @@ async function chatAtris() {
|
|
|
3598
3642
|
if (!agentLane) {
|
|
3599
3643
|
try {
|
|
3600
3644
|
const axPath = path.join(__dirname, '..', 'ax');
|
|
3601
|
-
const lane = fastLaneFlags.includes('--
|
|
3602
|
-
|
|
3645
|
+
const lane = fastLaneFlags.includes('--alpha')
|
|
3646
|
+
? '--alpha'
|
|
3647
|
+
: fastLaneFlags.includes('--rapid')
|
|
3648
|
+
? '--rapid'
|
|
3649
|
+
: '--fast';
|
|
3650
|
+
const extraFlags = fastLaneFlags.filter((flag) => flag !== '--rapid' && flag !== '--alpha');
|
|
3603
3651
|
const axArgs = message
|
|
3604
3652
|
? [lane, ...extraFlags, message].filter(Boolean)
|
|
3605
3653
|
: [lane, ...extraFlags, '--chat'];
|
|
@@ -3680,7 +3728,7 @@ async function chatInteractive(config, credentials) {
|
|
|
3680
3728
|
const conversationId = `cli-${Date.now()}`;
|
|
3681
3729
|
|
|
3682
3730
|
console.log('┌────────────────────────────────────────────────────────────┐');
|
|
3683
|
-
console.log(`│ Atris Chat
|
|
3731
|
+
console.log(`│ Atris Chat, ${agentName.padEnd(44)} │`);
|
|
3684
3732
|
console.log('├────────────────────────────────────────────────────────────┤');
|
|
3685
3733
|
console.log('│ Type your message and press Enter │');
|
|
3686
3734
|
console.log('│ Type "exit" to quit │');
|
|
@@ -3871,7 +3919,7 @@ async function atrisFastChat() {
|
|
|
3871
3919
|
// One routing brain: `atris fast` defers to ax's AX Context Standard. A
|
|
3872
3920
|
// workspace-shaped question asked from inside a workspace needs local tools
|
|
3873
3921
|
// (this lane is a tool-less cloud one-shot and confabulates on repo
|
|
3874
|
-
// questions
|
|
3922
|
+
// questions, SwapBench 2026-07-02), so delegate the whole turn to ax.
|
|
3875
3923
|
try {
|
|
3876
3924
|
const axModule = require('../ax');
|
|
3877
3925
|
if (axModule.resolveRoute(message) === 'local') {
|
package/commands/aeo.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* atris aeo
|
|
2
|
+
* atris aeo, AI Engine Optimization commands
|
|
3
3
|
*
|
|
4
4
|
* Backend-routed (require EC2):
|
|
5
5
|
* atris aeo init # create entity-graph skeleton
|
|
@@ -213,7 +213,7 @@ async function aeoScan(args) {
|
|
|
213
213
|
}
|
|
214
214
|
if (asJson) { console.log(JSON.stringify(data, null, 2)); return; }
|
|
215
215
|
console.log(`\n ${data.name || target}`);
|
|
216
|
-
console.log(` Score: ${data.score}/100 (${data.grade})
|
|
216
|
+
console.log(` Score: ${data.score}/100 (${data.grade}), ${data.status}`);
|
|
217
217
|
if (data.gap_statement) console.log(`\n ${data.gap_statement}`);
|
|
218
218
|
const gaps = data.gaps || [];
|
|
219
219
|
if (gaps.length) {
|
|
@@ -226,7 +226,7 @@ async function aeoScan(args) {
|
|
|
226
226
|
for (const c of comp) console.log(` ${pad(String(c.score ?? '?'), 4)} ${c.url || c.name}`);
|
|
227
227
|
}
|
|
228
228
|
if (data.draft_llms_txt) {
|
|
229
|
-
console.log('\n Draft llms.txt included
|
|
229
|
+
console.log('\n Draft llms.txt included, save it with:');
|
|
230
230
|
console.log(` atris aeo scan ${url} --json | jq -r .draft_llms_txt > llms.txt`);
|
|
231
231
|
}
|
|
232
232
|
console.log('');
|
|
@@ -511,7 +511,7 @@ async function aeoPacket(args) {
|
|
|
511
511
|
const onlyObjects = (v) => (Array.isArray(v) ? v.filter((x) => x && typeof x === 'object') : []);
|
|
512
512
|
const friction = onlyObjects(u.baseline_friction_points);
|
|
513
513
|
const fixes = onlyObjects(u.fix_backlog);
|
|
514
|
-
console.log(`AEO buyer packet
|
|
514
|
+
console.log(`AEO buyer packet, ${slug}`);
|
|
515
515
|
console.log(` surface: ${data.surface || ''}`);
|
|
516
516
|
console.log(` target url: ${data.target_url || ''}`);
|
|
517
517
|
console.log(` claim status: ${data.claim_status || ''}`);
|
package/commands/agents.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// atris agents
|
|
3
|
+
// atris agents, one glanceable view of every member's state.
|
|
4
4
|
// Reads .atris/state/missions.jsonl (schema atris.mission.v1) plus the
|
|
5
5
|
// directories in atris/team/, and prints who is stuck, waiting on you,
|
|
6
6
|
// working, or resting. Built from a dream card: "validator cannot plan
|
package/commands/align.js
CHANGED
|
@@ -100,7 +100,7 @@ function walkLocal(rootDir) {
|
|
|
100
100
|
* Why this instead of recursive /files walk: the recursive walk is rate-limited
|
|
101
101
|
* (60/min) and hangs on workspaces with many subdirs. The /snapshot endpoint
|
|
102
102
|
* returns the full file tree in one call. Trade-off: snapshot can be incomplete
|
|
103
|
-
* for very deep hierarchies (server-side bug we've seen)
|
|
103
|
+
* for very deep hierarchies (server-side bug we've seen), but it's vastly faster
|
|
104
104
|
* and we accept that risk in exchange for not hanging.
|
|
105
105
|
*/
|
|
106
106
|
async function walkCloud(token, businessId, workspaceId) {
|
|
@@ -126,14 +126,14 @@ async function walkCloud(token, businessId, workspaceId) {
|
|
|
126
126
|
out[p] = { hash: f.hash || null, size: f.size || 0 };
|
|
127
127
|
}
|
|
128
128
|
// CRITICAL: only return if snapshot actually had files. Empty snapshot is
|
|
129
|
-
// a known server-side bug
|
|
129
|
+
// a known server-side bug, fall back to recursive walk in that case so
|
|
130
130
|
// we don't report every local file as "only on local" against a phantom empty cloud.
|
|
131
131
|
if (Object.keys(out).length > 0) {
|
|
132
132
|
return { files: out, errors };
|
|
133
133
|
}
|
|
134
134
|
errors.push({ path: '<snapshot>', status: 'empty', fallback: 'recursive walk' });
|
|
135
135
|
} else {
|
|
136
|
-
// Snapshot failed entirely
|
|
136
|
+
// Snapshot failed entirely, fall back to recursive walk
|
|
137
137
|
errors.push({ path: '<snapshot>', status: snapshotResult.status, fallback: 'recursive walk' });
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -288,7 +288,7 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
288
288
|
const { buildManifest, saveManifest, computeLocalHashes } = require('../lib/manifest');
|
|
289
289
|
|
|
290
290
|
// 1. List top-level entries on cloud via /files (1 fast API call).
|
|
291
|
-
// We deliberately AVOID /snapshot here
|
|
291
|
+
// We deliberately AVOID /snapshot here, its hangs/timeouts on bloated
|
|
292
292
|
// workspaces are the whole reason --hard exists. /files at depth 0 is
|
|
293
293
|
// a single dir-listing call that returns reliably.
|
|
294
294
|
//
|
|
@@ -319,12 +319,12 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
319
319
|
const cloudTopEntries = (topResult.data && topResult.data.files) || [];
|
|
320
320
|
console.log(`${cloudTopEntries.length} entries`);
|
|
321
321
|
|
|
322
|
-
// The `workspace` top-level entry is the workspace root itself
|
|
322
|
+
// The `workspace` top-level entry is the workspace root itself, it's
|
|
323
323
|
// protected server-side (DELETE returns 400) and is NEVER cruft. Don't
|
|
324
324
|
// try to delete it; pretend it isn't there for the diff.
|
|
325
325
|
const PROTECTED_TOP = new Set(['workspace']);
|
|
326
326
|
|
|
327
|
-
// 2. Top-level local entries
|
|
327
|
+
// 2. Top-level local entries, track names AND types so we can detect
|
|
328
328
|
// type-mismatch (cloud has file `foo`, local has dir `foo/`).
|
|
329
329
|
const localTopByName = new Map(); // name -> 'dir' | 'file'
|
|
330
330
|
for (const e of fs.readdirSync(localDir, { withFileTypes: true })) {
|
|
@@ -341,7 +341,7 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
341
341
|
//
|
|
342
342
|
// NOTE: --hard intentionally does NOT respect SKIP_DIRS/SKIP_FILES here.
|
|
343
343
|
// Those skip lists exist for the diff/walk path so we don't enumerate
|
|
344
|
-
// node_modules/venv/__pycache__ locally
|
|
344
|
+
// node_modules/venv/__pycache__ locally, they are NOT protections that
|
|
345
345
|
// mean "don't delete on cloud." A bloated cloud workspace might genuinely
|
|
346
346
|
// contain stale `default/`, `venv/`, `__pycache__/` etc that the user
|
|
347
347
|
// wants nuked. --hard means "make cloud match local"; if local doesn't
|
|
@@ -354,7 +354,7 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
354
354
|
if (PROTECTED_TOP.has(name)) return false;
|
|
355
355
|
const localType = localTopByName.get(name);
|
|
356
356
|
if (!localType) return true; // not in local at all
|
|
357
|
-
if (localType !== entry.type) return true; // type mismatch
|
|
357
|
+
if (localType !== entry.type) return true; // type mismatch, must clear
|
|
358
358
|
return false;
|
|
359
359
|
});
|
|
360
360
|
|
|
@@ -413,7 +413,7 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
413
413
|
const r = await pushFiles(token, businessId, workspaceId, batch, 180000);
|
|
414
414
|
if (r.ok) {
|
|
415
415
|
// The server returns SyncResponse{written, unchanged, errors, results}
|
|
416
|
-
// inside a 200. A successful HTTP doesn't mean every file landed
|
|
416
|
+
// inside a 200. A successful HTTP doesn't mean every file landed,
|
|
417
417
|
// results can include status="error" entries (path-traversal attempts,
|
|
418
418
|
// permission errors, full disk, etc). Trust the server's count and
|
|
419
419
|
// record any per-file errors against batchFailures so we don't write
|
|
@@ -446,7 +446,7 @@ async function alignHardLocalToCloud(token, biz, localDir) {
|
|
|
446
446
|
if (failedPaths.length > 8) console.log(` ... +${failedPaths.length - 8} more`);
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
-
// 5. Save manifest so subsequent push/pull diffs work
|
|
449
|
+
// 5. Save manifest so subsequent push/pull diffs work, but ONLY if every
|
|
450
450
|
// batch, every per-file write, AND every cloud delete succeeded. If
|
|
451
451
|
// anything failed, leaving the manifest stale is safer than recording
|
|
452
452
|
// a mirror that doesn't actually exist on cloud (the manifest would
|
|
@@ -553,7 +553,7 @@ async function alignAtris() {
|
|
|
553
553
|
// --hard: skip the slow file-by-file walk. Nuke top-level cloud entries
|
|
554
554
|
// not present locally (1 DELETE per top-level dir, recursive on the server),
|
|
555
555
|
// then bulk-push every local file via /sync. Designed for "cloud is bloated,
|
|
556
|
-
// local is canonical, just make them match"
|
|
556
|
+
// local is canonical, just make them match", the force-push escape hatch.
|
|
557
557
|
if (hard && fix) {
|
|
558
558
|
console.log(` Local: ${localDir}`);
|
|
559
559
|
console.log(` Cloud: ${endpoint}`);
|
|
@@ -635,7 +635,7 @@ async function alignAtris() {
|
|
|
635
635
|
}
|
|
636
636
|
|
|
637
637
|
// FIX MODE
|
|
638
|
-
console.log(` Fixing
|
|
638
|
+
console.log(` Fixing, ${fromSide} is canonical:`);
|
|
639
639
|
|
|
640
640
|
if (fromSide === 'local') {
|
|
641
641
|
// Delete cloud-only files (they're cruft)
|
package/commands/analytics.js
CHANGED
|
@@ -68,8 +68,8 @@ function analyticsAtris() {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Parse timestamps for productivity hours. Match the journal heading
|
|
71
|
-
// format `### Title
|
|
72
|
-
const timestampMatches = content.match(/(
|
|
71
|
+
// format `### Title -- HH:MM` (the dashed form) and the legacy `**HH:MM:SS**` form.
|
|
72
|
+
const timestampMatches = content.match(/(?:\u2014|--)\s*(\d{2}):\d{2}(?::\d{2})?\b|\*\*(\d{2}):\d{2}(?::\d{2})?\*\*/g);
|
|
73
73
|
if (timestampMatches) {
|
|
74
74
|
timestampMatches.forEach(ts => {
|
|
75
75
|
const m = ts.match(/(\d{2}):/);
|
|
@@ -110,7 +110,7 @@ function analyticsAtris() {
|
|
|
110
110
|
const dateFormatted = `${year}-${month}-${day}`;
|
|
111
111
|
console.log('');
|
|
112
112
|
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
113
|
-
console.log(`│ Atris Analytics
|
|
113
|
+
console.log(`│ Atris Analytics, ${dateFormatted}${' '.repeat(35 - dateFormatted.length)}│`);
|
|
114
114
|
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
115
115
|
console.log('');
|
|
116
116
|
|
package/commands/app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* atris app
|
|
2
|
+
* atris app, manage APP.md manifests in the current workspace.
|
|
3
3
|
*
|
|
4
4
|
* Subcommands:
|
|
5
5
|
* atris app init <slug> [--runtime ec2|local|webhook|external|web|ios|template]
|
|
@@ -181,9 +181,9 @@ function readmeFor(slug) {
|
|
|
181
181
|
'',
|
|
182
182
|
'## Files',
|
|
183
183
|
'',
|
|
184
|
-
'- `APP.md
|
|
185
|
-
'- `data
|
|
186
|
-
'- `logs
|
|
184
|
+
'- `APP.md`, app manifest (frontmatter + instructions). Source of truth.',
|
|
185
|
+
'- `data/`, per-run outputs.',
|
|
186
|
+
'- `logs/`, stdout/stderr per trigger.',
|
|
187
187
|
'',
|
|
188
188
|
'## Secrets',
|
|
189
189
|
'',
|
|
@@ -271,7 +271,7 @@ async function show(slug) {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
async function help() {
|
|
274
|
-
console.log('atris app
|
|
274
|
+
console.log('atris app, manage APP.md manifests');
|
|
275
275
|
console.log('');
|
|
276
276
|
console.log('Subcommands:');
|
|
277
277
|
console.log(' init <slug> [--runtime <kind>] Scaffold a new app folder');
|