atris 3.52.0 → 3.55.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/FOR_AGENTS.md +7 -0
- package/README.md +1 -1
- package/atris/policies/ANTISLOP.md +2 -1
- package/atris/skills/copy-editor/SKILL.md +2 -1
- package/atris/skills/design/SKILL.md +1 -1
- package/atris/skills/engines/SKILL.md +8 -7
- package/atris/skills/x-search/SKILL.md +24 -22
- package/atris/skills/youtube/SKILL.md +89 -40
- package/atris/team/_template/SOUL.md +40 -0
- package/atris/team/validator/MEMBER.md +1 -2
- package/ax +592 -91
- package/bin/atris +21 -0
- package/bin/atris.js +580 -378
- package/commands/api-key.js +170 -0
- package/commands/auth.js +453 -43
- package/commands/autoland.js +3 -1
- package/commands/autopilot-front.js +58 -11
- package/commands/avail.js +5 -4
- package/commands/balance.js +55 -0
- package/commands/bench.js +29 -1
- package/commands/brain.js +63 -12
- package/commands/brainstorm.js +18 -0
- package/commands/business.js +149 -1
- package/commands/chat-scan.js +17 -4
- package/commands/close.js +5 -1
- package/commands/computer.js +2 -2
- package/commands/doctor.js +174 -0
- package/commands/dream.js +7 -0
- package/commands/drill.js +34 -2
- package/commands/engine.js +47 -35
- package/commands/errors.js +58 -8
- package/commands/experiments.js +14 -0
- package/commands/feedback.js +61 -2
- package/commands/fleet-report.js +27 -7
- package/commands/fleet.js +98 -11
- package/commands/founder.js +60 -21
- package/commands/human-missions.js +79 -4
- package/commands/improve.js +54 -4
- package/commands/init.js +68 -92
- package/commands/install.js +40 -0
- package/commands/integrations.js +399 -30
- package/commands/interview.js +8 -0
- package/commands/land.js +48 -17
- package/commands/learn.js +29 -4
- package/commands/log.js +51 -0
- package/commands/member.js +68 -10
- package/commands/mission.js +339 -74
- package/commands/now.js +25 -6
- package/commands/orb.js +97 -2
- package/commands/pack.js +83 -9
- package/commands/playbook.js +381 -0
- package/commands/plugin.js +16 -0
- package/commands/radar.js +96 -40
- package/commands/recap.js +128 -21
- package/commands/release.js +102 -2
- package/commands/review.js +5 -10
- package/commands/revisions.js +55 -0
- package/commands/run-front.js +12 -4
- package/commands/scout.js +12 -1
- package/commands/search.js +123 -28
- package/commands/sign.js +2 -2
- package/commands/signup.js +12 -3
- package/commands/site-deploy.js +17 -4
- package/commands/site.js +2 -2
- package/commands/skill-eval.js +289 -0
- package/commands/skill.js +56 -6
- package/commands/social.js +603 -0
- package/commands/spaceship.js +69 -6
- package/commands/stream.js +8 -1
- package/commands/study.js +32 -19
- package/commands/sync.js +28 -22
- package/commands/task.js +418 -60
- package/commands/teach.js +72 -63
- package/commands/terminal.js +25 -9
- package/commands/topup.js +88 -0
- package/commands/truth.js +52 -6
- package/commands/usage.js +91 -0
- package/commands/verify.js +3 -2
- package/commands/version.js +3 -1
- package/commands/voice.js +5 -1
- package/commands/who.js +69 -11
- package/commands/wiki.js +7 -4
- package/commands/wish.js +76 -5
- package/commands/workflow.js +327 -145
- package/commands/worktree.js +1 -0
- package/commands/write.js +5 -0
- package/commands/x-search.js +340 -0
- package/commands/xp.js +5 -1
- package/commands/youtube.js +551 -33
- package/lib/account-bound.js +47 -0
- package/lib/auto-accept-certified.js +10 -2
- package/lib/auto-lessons.js +186 -0
- package/lib/autoland.js +4 -2
- package/lib/chat-log-scan.js +7 -4
- package/lib/cli-json.js +77 -0
- package/lib/cli-scope.js +26 -0
- package/lib/codex-flight.js +1 -0
- package/lib/conductor-artifacts.js +1 -1
- package/lib/context-gatherer.js +11 -0
- package/lib/developer-api.js +116 -0
- package/lib/engine-ask.js +11 -3
- package/lib/engine-registry.js +32 -7
- package/lib/feedback-triage.js +274 -0
- package/lib/first-minute.js +398 -0
- package/lib/fleet.js +115 -34
- package/lib/functional-owner.js +22 -0
- package/lib/known-commands.js +31 -5
- package/lib/member-scaffold.js +197 -0
- package/lib/mission-ledger-compact.js +127 -0
- package/lib/mission-root.js +4 -2
- package/lib/mission-runtime-loop.js +30 -2
- package/lib/next-moves.js +34 -34
- package/lib/noninteractive.js +88 -0
- package/lib/permission-grants.js +10 -1
- package/lib/policy-lessons.js +4 -1
- package/lib/revision-metric.js +279 -0
- package/lib/runner-command.js +5 -4
- package/lib/scratch-root.js +48 -0
- package/lib/skill-eval-gate.js +249 -0
- package/lib/task-db.js +22 -2
- package/lib/task-proof.js +75 -9
- package/lib/task-receipt.js +5 -1
- package/lib/verifier-quality.js +69 -0
- package/lib/wish-audit.js +2 -2
- package/lib/wish-delegate.js +10 -1
- package/lib/workspace-scaffold.js +270 -0
- package/package.json +4 -2
- package/scripts/det/checklist-score.js +191 -0
- package/scripts/det/ytsearch +31 -0
- package/scripts/outbound-artifact-gate.js +227 -0
- package/utils/update-check.js +15 -0
package/commands/avail.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const { ensureValidCredentials } = require('../utils/auth');
|
|
12
12
|
const { apiRequestJson, getAppBaseUrl, httpRequest } = require('../utils/api');
|
|
13
|
+
const { argsWantHelp } = require('../lib/noninteractive');
|
|
13
14
|
|
|
14
15
|
const DAY_INDEX = { mon: 0, tue: 1, wed: 2, thu: 3, fri: 4, sat: 5, sun: 6 };
|
|
15
16
|
const DAY_LABEL = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
@@ -381,14 +382,14 @@ Examples:
|
|
|
381
382
|
}
|
|
382
383
|
|
|
383
384
|
async function availCommand(argv = []) {
|
|
385
|
+
if (argsWantHelp(argv)) {
|
|
386
|
+
printHelp();
|
|
387
|
+
return 2;
|
|
388
|
+
}
|
|
384
389
|
if (!argv.length || argv[0]?.startsWith('-') || argv[0] === 'show' || argv[0] === 'get') {
|
|
385
390
|
return showAvail({ json: argv.includes('--json') });
|
|
386
391
|
}
|
|
387
392
|
const sub = argv[0].toLowerCase();
|
|
388
|
-
if (sub === '--help' || sub === '-h' || sub === 'help') {
|
|
389
|
-
printHelp();
|
|
390
|
-
return 0;
|
|
391
|
-
}
|
|
392
393
|
if (sub === 'set' || sub === 'update') return setAvail(argv.slice(1));
|
|
393
394
|
if (sub === 'slots') return slotsAvail(argv.slice(1));
|
|
394
395
|
console.error(`Unknown subcommand: ${sub}`);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { apiRequestJson } = require('../utils/api');
|
|
4
|
+
const { loadCredentials } = require('../utils/auth');
|
|
5
|
+
const {
|
|
6
|
+
NOT_LOGGED_IN,
|
|
7
|
+
wantsHelp,
|
|
8
|
+
wantsJson,
|
|
9
|
+
tokenFrom,
|
|
10
|
+
oneLine,
|
|
11
|
+
printResult,
|
|
12
|
+
formatDollars,
|
|
13
|
+
normalizeBalance,
|
|
14
|
+
} = require('../lib/developer-api');
|
|
15
|
+
|
|
16
|
+
function showBalanceHelp() {
|
|
17
|
+
console.log('usage: atris balance [--json]');
|
|
18
|
+
console.log('show your credit balance in dollars, with credits on the next line.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function balanceCommand(args = [], deps = {}) {
|
|
22
|
+
if (wantsHelp(args)) {
|
|
23
|
+
showBalanceHelp();
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const json = wantsJson(args);
|
|
28
|
+
const io = { log: deps.log || console.log, err: deps.err || console.error };
|
|
29
|
+
const load = deps.loadCredentials || loadCredentials;
|
|
30
|
+
const request = deps.apiRequestJson || apiRequestJson;
|
|
31
|
+
const token = tokenFrom(load());
|
|
32
|
+
if (!token) {
|
|
33
|
+
printResult({ json, ok: false, error: NOT_LOGGED_IN, payload: { ok: false, error: NOT_LOGGED_IN } }, io);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const result = await request('/credits/balance', { method: 'GET', token });
|
|
39
|
+
if (!result || !result.ok) {
|
|
40
|
+
const error = oneLine(result && result.error);
|
|
41
|
+
printResult({ json, ok: false, error, payload: { ok: false, error, status: result && result.status } }, io);
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
const balance = normalizeBalance(result.data || {});
|
|
45
|
+
const text = `${formatDollars(balance.dollars)}\n${balance.credits} credits`;
|
|
46
|
+
printResult({ json, ok: true, text, payload: { ok: true, ...balance } }, io);
|
|
47
|
+
return 0;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const message = oneLine(error && error.message);
|
|
50
|
+
printResult({ json, ok: false, error: message, payload: { ok: false, error: message } }, io);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { balanceCommand, showBalanceHelp };
|
package/commands/bench.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
3
6
|
const {
|
|
4
7
|
BenchInfraError,
|
|
5
8
|
packMetadata,
|
|
@@ -10,6 +13,18 @@ const {
|
|
|
10
13
|
const { buildBenchReport, renderBenchReportText } = require('../lib/bench/report');
|
|
11
14
|
const { hasFlag } = require('../lib/arg-parser');
|
|
12
15
|
|
|
16
|
+
function isAtrisCliRepo(cwd = process.cwd()) {
|
|
17
|
+
const root = path.resolve(cwd);
|
|
18
|
+
try {
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
20
|
+
if (pkg.name !== 'atris') return false;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return fs.existsSync(path.join(root, 'bin', 'atris.js'))
|
|
25
|
+
&& fs.existsSync(path.join(root, 'atris', 'benchmarks'));
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
// Preserve the existing rule that any inline value wins over a split value.
|
|
14
29
|
function readInlineFirstFlag(args, name) {
|
|
15
30
|
const prefix = `${name}=`;
|
|
@@ -41,6 +56,9 @@ function printHelp() {
|
|
|
41
56
|
console.log('Usage: atris bench tasks [--pack <id>] [--json]');
|
|
42
57
|
console.log('Usage: atris bench packs [--json]');
|
|
43
58
|
console.log('Usage: atris bench report [--pack agents-v1] [--json]');
|
|
59
|
+
console.log('');
|
|
60
|
+
console.log('Bench runs product gates and only belongs in the atris CLI repo.');
|
|
61
|
+
console.log('Pass --here to allow running outside that repo.');
|
|
44
62
|
}
|
|
45
63
|
|
|
46
64
|
function printRunText(record) {
|
|
@@ -167,11 +185,20 @@ function reportCommand(args) {
|
|
|
167
185
|
|
|
168
186
|
async function benchCommand(args = []) {
|
|
169
187
|
const subcommand = args[0] || 'run';
|
|
170
|
-
const rest = args.slice(1);
|
|
188
|
+
const rest = args.slice(1).filter((arg) => arg !== '--here');
|
|
171
189
|
if (subcommand === '--help' || subcommand === '-h' || subcommand === 'help') {
|
|
172
190
|
printHelp();
|
|
173
191
|
return 0;
|
|
174
192
|
}
|
|
193
|
+
if (!hasFlag(args, '--here') && !isAtrisCliRepo(process.cwd())) {
|
|
194
|
+
const message = 'refuse outside the atris cli repo; pass --here to run here';
|
|
195
|
+
if (hasFlag(args, '--json') || hasFlag(rest, '--json')) {
|
|
196
|
+
console.log(JSON.stringify({ schema: 'atris.bench.error.v1', error: message }));
|
|
197
|
+
} else {
|
|
198
|
+
console.error(`atris bench: ${message}`);
|
|
199
|
+
}
|
|
200
|
+
return 2;
|
|
201
|
+
}
|
|
175
202
|
if (subcommand === 'run') return runCommand(rest);
|
|
176
203
|
if (subcommand === 'tasks') return tasksCommand(rest);
|
|
177
204
|
if (subcommand === 'packs') return packsCommand(rest);
|
|
@@ -183,4 +210,5 @@ async function benchCommand(args = []) {
|
|
|
183
210
|
|
|
184
211
|
module.exports = {
|
|
185
212
|
benchCommand,
|
|
213
|
+
isAtrisCliRepo,
|
|
186
214
|
};
|
package/commands/brain.js
CHANGED
|
@@ -5,6 +5,7 @@ const { spawnSync } = require('child_process');
|
|
|
5
5
|
const { refreshNowFile } = require('./now');
|
|
6
6
|
const escapeRegExp = require('../lib/escape-regexp');
|
|
7
7
|
const { hasRenderedSections, isOpenSection, isDoneSection } = require('../lib/todo-sections');
|
|
8
|
+
const { isNonInteractive } = require('../lib/noninteractive');
|
|
8
9
|
const {
|
|
9
10
|
renderVoiceCardBlock,
|
|
10
11
|
upsertCursorVoiceCard,
|
|
@@ -70,6 +71,7 @@ function parseArgs(args) {
|
|
|
70
71
|
root: process.cwd(),
|
|
71
72
|
verify: false,
|
|
72
73
|
json: false,
|
|
74
|
+
yes: false,
|
|
73
75
|
rating: null,
|
|
74
76
|
recommendation: null,
|
|
75
77
|
note: '',
|
|
@@ -88,6 +90,8 @@ function parseArgs(args) {
|
|
|
88
90
|
options.verify = true;
|
|
89
91
|
} else if (arg === '--json') {
|
|
90
92
|
options.json = true;
|
|
93
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
94
|
+
options.yes = true;
|
|
91
95
|
} else if (arg === '--rating' && args[i + 1]) {
|
|
92
96
|
options.rating = args[++i];
|
|
93
97
|
} else if (arg.startsWith('--rating=')) {
|
|
@@ -1436,7 +1440,7 @@ function generatedBootBlock(state, voiceCard = voiceCardForRoot(state.root)) {
|
|
|
1436
1440
|
This workspace has a compiled agent brain.
|
|
1437
1441
|
|
|
1438
1442
|
On session start, activate it first:
|
|
1439
|
-
\`atris brain activate --root . --verify\`
|
|
1443
|
+
\`atris brain activate --root . --yes --verify\`
|
|
1440
1444
|
|
|
1441
1445
|
Load these first:
|
|
1442
1446
|
${renderBulletedLoadOrder(state)}
|
|
@@ -1450,7 +1454,7 @@ Keep this voice beside every reply:
|
|
|
1450
1454
|
${renderVoiceCardBlock(voiceCard)}
|
|
1451
1455
|
|
|
1452
1456
|
Re-run after meaningful work:
|
|
1453
|
-
\`atris brain compile --root
|
|
1457
|
+
\`atris brain compile --root . --yes\`
|
|
1454
1458
|
${GENERATED_END}
|
|
1455
1459
|
`;
|
|
1456
1460
|
}
|
|
@@ -1471,6 +1475,40 @@ function upsertGeneratedBlock(filePath, title, block) {
|
|
|
1471
1475
|
fs.writeFileSync(filePath, `${current.trimEnd()}\n\n${block}`, 'utf8');
|
|
1472
1476
|
}
|
|
1473
1477
|
|
|
1478
|
+
function plannedBrainWrites(state) {
|
|
1479
|
+
const files = [
|
|
1480
|
+
'atris/brain/STATUS.md',
|
|
1481
|
+
'atris/brain/self_improvement_ledger.md',
|
|
1482
|
+
'atris/brain/state.json',
|
|
1483
|
+
'AGENTS.md',
|
|
1484
|
+
'CLAUDE.md',
|
|
1485
|
+
'GEMINI.md',
|
|
1486
|
+
'.cursor/rules/atris-voice.mdc',
|
|
1487
|
+
];
|
|
1488
|
+
if (fs.existsSync(path.join(state.root, 'atris', 'wiki', 'STATUS.md'))) {
|
|
1489
|
+
files.push('atris/wiki/STATUS.md');
|
|
1490
|
+
}
|
|
1491
|
+
return files;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
function refuseBrainWriteWithoutYes(state, options = {}) {
|
|
1495
|
+
const files = plannedBrainWrites(state);
|
|
1496
|
+
if (options.json) {
|
|
1497
|
+
console.log(JSON.stringify({
|
|
1498
|
+
ok: true,
|
|
1499
|
+
action: 'brain_plan',
|
|
1500
|
+
files,
|
|
1501
|
+
next_command: 'atris brain compile --yes',
|
|
1502
|
+
}, null, 2));
|
|
1503
|
+
} else {
|
|
1504
|
+
console.log('Plan only. Would write:');
|
|
1505
|
+
for (const file of files) console.log(` ${file}`);
|
|
1506
|
+
console.log('Re-run with --yes to write these files.');
|
|
1507
|
+
}
|
|
1508
|
+
if (isNonInteractive()) process.exit(2);
|
|
1509
|
+
return { planned: true, files };
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1474
1512
|
function writeBrain(state) {
|
|
1475
1513
|
const brainDir = path.join(state.root, 'atris', 'brain');
|
|
1476
1514
|
fs.mkdirSync(brainDir, { recursive: true });
|
|
@@ -1529,9 +1567,9 @@ function verifyBrain(root) {
|
|
|
1529
1567
|
|
|
1530
1568
|
function brainUsageLines() {
|
|
1531
1569
|
return [
|
|
1532
|
-
'Usage: atris brain compile [--root <workspace>] [--verify] [--json]',
|
|
1533
|
-
' atris brain activate [--member <slug>] [--root <workspace>] [--verify] [--json]',
|
|
1534
|
-
' atris brain gallery [--root <workspace>] [--verify] [--json]',
|
|
1570
|
+
'Usage: atris brain compile [--root <workspace>] [--yes] [--verify] [--json]',
|
|
1571
|
+
' atris brain activate [--member <slug>] [--root <workspace>] [--yes] [--verify] [--json]',
|
|
1572
|
+
' atris brain gallery [--root <workspace>] [--yes] [--verify] [--json]',
|
|
1535
1573
|
' atris brain go|hold [note] [--recommendation <text>] [--root <workspace>] [--verify]',
|
|
1536
1574
|
' atris brain approval go|edit|hold [note] [--recommendation <text>] [--root <workspace>] [--verify]',
|
|
1537
1575
|
' atris brain scorecard [--root <workspace>] [--verify] [--json]',
|
|
@@ -1618,6 +1656,10 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1618
1656
|
|
|
1619
1657
|
if (subcommand === 'activate') {
|
|
1620
1658
|
const state = prepareBrainState(options.root);
|
|
1659
|
+
if (!options.yes) {
|
|
1660
|
+
refuseBrainWriteWithoutYes(state, options);
|
|
1661
|
+
return 0;
|
|
1662
|
+
}
|
|
1621
1663
|
writeBrain(state);
|
|
1622
1664
|
if (options.verify) verifyBrain(options.root);
|
|
1623
1665
|
const card = renderActivationCard(state, options);
|
|
@@ -1636,7 +1678,7 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1636
1678
|
}
|
|
1637
1679
|
}
|
|
1638
1680
|
console.log(JSON.stringify({ ok: true, state, card }, null, 2));
|
|
1639
|
-
return;
|
|
1681
|
+
return 0;
|
|
1640
1682
|
}
|
|
1641
1683
|
console.log('');
|
|
1642
1684
|
console.log(card);
|
|
@@ -1645,7 +1687,7 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1645
1687
|
verifyActivationCard(card);
|
|
1646
1688
|
} catch (error) {
|
|
1647
1689
|
printVerifyFailure(error);
|
|
1648
|
-
return;
|
|
1690
|
+
return 1;
|
|
1649
1691
|
}
|
|
1650
1692
|
const operator = (card.match(/^OPERATOR:\s*(.+)$/m) || [null, 'unknown'])[1];
|
|
1651
1693
|
if (operator === 'unknown') {
|
|
@@ -1655,10 +1697,14 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1655
1697
|
}
|
|
1656
1698
|
}
|
|
1657
1699
|
console.log('');
|
|
1658
|
-
return;
|
|
1700
|
+
return 0;
|
|
1659
1701
|
}
|
|
1660
1702
|
if (subcommand === 'gallery') {
|
|
1661
1703
|
const state = prepareBrainState(options.root);
|
|
1704
|
+
if (!options.yes) {
|
|
1705
|
+
refuseBrainWriteWithoutYes(state, options);
|
|
1706
|
+
return 0;
|
|
1707
|
+
}
|
|
1662
1708
|
writeBrain(state);
|
|
1663
1709
|
if (options.verify) verifyBrain(options.root);
|
|
1664
1710
|
const gallery = renderActivationGallery(state);
|
|
@@ -1676,18 +1722,18 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1676
1722
|
process.exit(1);
|
|
1677
1723
|
}
|
|
1678
1724
|
printVerifyFailure(error);
|
|
1679
|
-
return;
|
|
1725
|
+
return 1;
|
|
1680
1726
|
}
|
|
1681
1727
|
}
|
|
1682
1728
|
if (options.json) {
|
|
1683
1729
|
console.log(JSON.stringify({ ok: true, members: listMemberSlugs(options.root), gallery }, null, 2));
|
|
1684
|
-
return;
|
|
1730
|
+
return 0;
|
|
1685
1731
|
}
|
|
1686
1732
|
console.log('');
|
|
1687
1733
|
console.log(gallery);
|
|
1688
1734
|
if (options.verify) console.log('\nVERIFY: brain artifacts and member readiness present');
|
|
1689
1735
|
console.log('');
|
|
1690
|
-
return;
|
|
1736
|
+
return 0;
|
|
1691
1737
|
}
|
|
1692
1738
|
if (subcommand !== 'compile' && subcommand !== 'status') {
|
|
1693
1739
|
if (options.json) {
|
|
@@ -1703,12 +1749,16 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1703
1749
|
}
|
|
1704
1750
|
|
|
1705
1751
|
const state = prepareBrainState(options.root);
|
|
1752
|
+
if (!options.yes) {
|
|
1753
|
+
refuseBrainWriteWithoutYes(state, options);
|
|
1754
|
+
return 0;
|
|
1755
|
+
}
|
|
1706
1756
|
const written = writeBrain(state);
|
|
1707
1757
|
if (options.verify) verifyBrain(options.root);
|
|
1708
1758
|
|
|
1709
1759
|
if (options.json) {
|
|
1710
1760
|
console.log(JSON.stringify({ ok: true, state, written }, null, 2));
|
|
1711
|
-
return;
|
|
1761
|
+
return 0;
|
|
1712
1762
|
}
|
|
1713
1763
|
|
|
1714
1764
|
console.log('');
|
|
@@ -1720,6 +1770,7 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1720
1770
|
console.log(` Next: ${nextMove(state)}`);
|
|
1721
1771
|
if (options.verify) console.log(' Verify: passed');
|
|
1722
1772
|
console.log('');
|
|
1773
|
+
return 0;
|
|
1723
1774
|
}
|
|
1724
1775
|
|
|
1725
1776
|
module.exports = {
|
package/commands/brainstorm.js
CHANGED
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
const { loadConfig } = require('../utils/config');
|
|
15
15
|
const { loadCredentials, ensureValidCredentials } = require('../utils/auth');
|
|
16
16
|
const { apiRequestJson } = require('../utils/api');
|
|
17
|
+
const { isNonInteractive } = require('../lib/noninteractive');
|
|
17
18
|
const { planAtris, doAtris, reviewAtris } = require('./workflow');
|
|
18
19
|
|
|
19
20
|
const pkg = require('../package.json');
|
|
@@ -27,10 +28,12 @@ async function brainstormAtris() {
|
|
|
27
28
|
console.log('Description:');
|
|
28
29
|
console.log(' Guided prompt generator for exploration before planning.');
|
|
29
30
|
console.log(' Default is local-first; pass --cloud to include AtrisOS journal context.');
|
|
31
|
+
console.log(' Headless agents: pass the idea on the command line (never prompts).');
|
|
30
32
|
console.log('');
|
|
31
33
|
console.log('Options:');
|
|
32
34
|
console.log(' --cloud Include AtrisOS journal context (optional).');
|
|
33
35
|
console.log(' --no-cloud Force local-only mode (skip AtrisOS).');
|
|
36
|
+
console.log(' --yes Non-interactive: capture idea args and exit.');
|
|
34
37
|
console.log('');
|
|
35
38
|
return;
|
|
36
39
|
}
|
|
@@ -49,6 +52,21 @@ async function brainstormAtris() {
|
|
|
49
52
|
const useCloudJournal = args.includes('--cloud') && !args.includes('--no-cloud');
|
|
50
53
|
const topicFromArgs = args.filter((arg) => !arg.startsWith('-')).join(' ').trim() || null;
|
|
51
54
|
|
|
55
|
+
// Headless agents must never hang on "Describe the desired outcome".
|
|
56
|
+
if (isNonInteractive(args)) {
|
|
57
|
+
if (topicFromArgs) {
|
|
58
|
+
const newId = addInboxIdea(logFile, topicFromArgs);
|
|
59
|
+
console.log(`captured I${newId}: ${topicFromArgs}`);
|
|
60
|
+
console.log(`journal: ${path.relative(process.cwd(), logFile) || logFile}`);
|
|
61
|
+
console.log('Next: atris plan');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
console.log('brainstorm is interactive without an idea on the command line.');
|
|
65
|
+
console.log(`journal: ${path.relative(process.cwd(), logFile) || logFile}`);
|
|
66
|
+
console.log('Next: atris brainstorm "<idea>"');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
52
70
|
console.log('');
|
|
53
71
|
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
54
72
|
console.log('│ Atris Brainstorm — structured prompt generator │');
|
package/commands/business.js
CHANGED
|
@@ -35,6 +35,7 @@ function isHelpToken(arg) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const BUSINESS_CREATE_USAGE = 'Usage: atris business create <name> [--description "..."] [--workspace] [--here|--root <dir>]';
|
|
38
|
+
const BUSINESS_SHIP_USAGE = 'Usage: atris business ship "<paragraph>" [--name <name>] [--email <email>] --yes';
|
|
38
39
|
|
|
39
40
|
function isAccidentalHelpBusiness(value) {
|
|
40
41
|
const raw = String(value || '').trim();
|
|
@@ -70,6 +71,75 @@ function validateBusinessCreateName(name) {
|
|
|
70
71
|
return { ok: true };
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
function compactShipText(value) {
|
|
75
|
+
return String(value || '').replace(/\s+/g, ' ').trim();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function parseBusinessShipArgs(args = []) {
|
|
79
|
+
const positional = [];
|
|
80
|
+
let name = '';
|
|
81
|
+
let email = '';
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < args.length; i++) {
|
|
84
|
+
const arg = args[i];
|
|
85
|
+
const next = args[i + 1];
|
|
86
|
+
|
|
87
|
+
if (arg === '--name') {
|
|
88
|
+
if (!next || String(next).startsWith('-')) {
|
|
89
|
+
return { ok: false, usage: BUSINESS_SHIP_USAGE, detail: 'Missing value for --name.' };
|
|
90
|
+
}
|
|
91
|
+
name = next;
|
|
92
|
+
i++;
|
|
93
|
+
} else if (typeof arg === 'string' && arg.startsWith('--name=')) {
|
|
94
|
+
name = arg.slice('--name='.length);
|
|
95
|
+
} else if (arg === '--email') {
|
|
96
|
+
if (!next || String(next).startsWith('-')) {
|
|
97
|
+
return { ok: false, usage: BUSINESS_SHIP_USAGE, detail: 'Missing value for --email.' };
|
|
98
|
+
}
|
|
99
|
+
email = next;
|
|
100
|
+
i++;
|
|
101
|
+
} else if (typeof arg === 'string' && arg.startsWith('--email=')) {
|
|
102
|
+
email = arg.slice('--email='.length);
|
|
103
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
104
|
+
// proceed flag; checked by shipBusiness
|
|
105
|
+
} else if (typeof arg === 'string' && arg.startsWith('-')) {
|
|
106
|
+
return { ok: false, usage: BUSINESS_SHIP_USAGE, detail: `Unknown option: ${arg}` };
|
|
107
|
+
} else {
|
|
108
|
+
positional.push(arg);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const description = compactShipText(positional.join(' '));
|
|
113
|
+
if (!description) {
|
|
114
|
+
return { ok: false, usage: BUSINESS_SHIP_USAGE };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
description,
|
|
120
|
+
name: compactShipText(name),
|
|
121
|
+
email: compactShipText(email),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function shipTeamNames(team) {
|
|
126
|
+
const rows = Array.isArray(team)
|
|
127
|
+
? team
|
|
128
|
+
: (Array.isArray(team?.members) ? team.members : []);
|
|
129
|
+
return rows.map((member) => {
|
|
130
|
+
if (typeof member === 'string') return compactShipText(member);
|
|
131
|
+
if (!member || typeof member !== 'object') return '';
|
|
132
|
+
return compactShipText(member.display_name || member.name || member.slug || '');
|
|
133
|
+
}).filter(Boolean);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function shipTaskTitle(task) {
|
|
137
|
+
if (!task) return '';
|
|
138
|
+
if (typeof task === 'string') return compactShipText(task);
|
|
139
|
+
if (typeof task !== 'object') return '';
|
|
140
|
+
return compactShipText(task.title || task.name || '');
|
|
141
|
+
}
|
|
142
|
+
|
|
73
143
|
function loadBusinesses() {
|
|
74
144
|
const p = getBusinessConfigPath();
|
|
75
145
|
if (!fs.existsSync(p)) return {};
|
|
@@ -2789,6 +2859,73 @@ async function initBusinessWorkspace(name, ...flags) {
|
|
|
2789
2859
|
return createBusinessInternal(name, flags, 'canonical');
|
|
2790
2860
|
}
|
|
2791
2861
|
|
|
2862
|
+
function printBusinessShipHelp() {
|
|
2863
|
+
console.log(BUSINESS_SHIP_USAGE);
|
|
2864
|
+
console.log('');
|
|
2865
|
+
console.log('Create a live business from one paragraph.');
|
|
2866
|
+
console.log(' --name <name> Optional business name');
|
|
2867
|
+
console.log(' --email <email> Optional customer email');
|
|
2868
|
+
console.log(' --yes Required to POST /business/ship');
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
async function shipBusiness(...args) {
|
|
2872
|
+
if (args.some(isHelpToken)) {
|
|
2873
|
+
printBusinessShipHelp();
|
|
2874
|
+
return;
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
if (!args.includes('--yes') && !args.includes('-y')) {
|
|
2878
|
+
console.error(BUSINESS_SHIP_USAGE);
|
|
2879
|
+
console.error('Pass --yes to create a live business.');
|
|
2880
|
+
process.exit(2);
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
const parsed = parseBusinessShipArgs(args);
|
|
2884
|
+
if (!parsed.ok) {
|
|
2885
|
+
console.error(parsed.usage);
|
|
2886
|
+
if (parsed.detail) console.error(`\n ${parsed.detail}`);
|
|
2887
|
+
process.exit(1);
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
const creds = loadCredentials();
|
|
2891
|
+
if (!creds || !creds.token) {
|
|
2892
|
+
console.error('Not logged in. Run: atris login');
|
|
2893
|
+
process.exit(1);
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
const body = { description: parsed.description };
|
|
2897
|
+
if (parsed.name) body.name = parsed.name;
|
|
2898
|
+
if (parsed.email) body.customer_email = parsed.email;
|
|
2899
|
+
|
|
2900
|
+
console.log(`Shipping business: ${parsed.name || parsed.description}...`);
|
|
2901
|
+
|
|
2902
|
+
const result = await apiRequestJson('/business/ship', {
|
|
2903
|
+
method: 'POST',
|
|
2904
|
+
token: creds.token,
|
|
2905
|
+
body,
|
|
2906
|
+
});
|
|
2907
|
+
|
|
2908
|
+
if (!result.ok) {
|
|
2909
|
+
console.error(`Failed: ${result.errorMessage || result.error || result.status}`);
|
|
2910
|
+
process.exit(1);
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
const payload = result.data || {};
|
|
2914
|
+
const slug = payload.slug || '';
|
|
2915
|
+
const label = payload.name || parsed.name || slug || 'business';
|
|
2916
|
+
const pageUrl = payload.public_page_url || '';
|
|
2917
|
+
const names = shipTeamNames(payload.team);
|
|
2918
|
+
const firstTask = shipTaskTitle(payload.seeded_task);
|
|
2919
|
+
|
|
2920
|
+
console.log('');
|
|
2921
|
+
console.log(` ${label}${slug ? ` (${slug})` : ''}`);
|
|
2922
|
+
if (pageUrl) console.log(` Public page: ${pageUrl}`);
|
|
2923
|
+
if (names.length > 0) console.log(` Team: ${names.join(', ')}`);
|
|
2924
|
+
if (firstTask) console.log(` First task: ${firstTask}`);
|
|
2925
|
+
console.log('');
|
|
2926
|
+
return payload;
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2792
2929
|
|
|
2793
2930
|
async function businessStatus(slug) {
|
|
2794
2931
|
const creds = loadCredentials();
|
|
@@ -3364,6 +3501,7 @@ function printBusinessHelp() {
|
|
|
3364
3501
|
console.log(' init <name> RECOMMENDED: create a business environment (cloud + local)');
|
|
3365
3502
|
console.log(' workspace <name> Alias for init');
|
|
3366
3503
|
console.log(' create <name> Cloud-only business record; add --workspace to also scaffold local');
|
|
3504
|
+
console.log(' ship "<paragraph>" One paragraph, live business (optional --name, --email; --yes required)');
|
|
3367
3505
|
console.log(' simulate <idea> Create a business, four-role team, missions, and endgame loop');
|
|
3368
3506
|
console.log(' add <slug> Register an existing cloud business');
|
|
3369
3507
|
console.log(' list Show registered businesses');
|
|
@@ -3401,7 +3539,11 @@ async function businessCommand(subcommand, ...args) {
|
|
|
3401
3539
|
printBusinessSimulateHelp();
|
|
3402
3540
|
return;
|
|
3403
3541
|
}
|
|
3404
|
-
|
|
3542
|
+
if (subcommand === 'ship' && args.some(isHelpToken)) {
|
|
3543
|
+
printBusinessShipHelp();
|
|
3544
|
+
return;
|
|
3545
|
+
}
|
|
3546
|
+
const nameTakingSubcommands = new Set(['create', 'new', 'init', 'workspace', 'ship']);
|
|
3405
3547
|
if (nameTakingSubcommands.has(subcommand) && args.some(isHelpToken)) {
|
|
3406
3548
|
printBusinessHelp();
|
|
3407
3549
|
return;
|
|
@@ -3419,6 +3561,9 @@ async function businessCommand(subcommand, ...args) {
|
|
|
3419
3561
|
case 'new':
|
|
3420
3562
|
await createBusiness(args[0], ...args.slice(1));
|
|
3421
3563
|
break;
|
|
3564
|
+
case 'ship':
|
|
3565
|
+
await shipBusiness(...args);
|
|
3566
|
+
break;
|
|
3422
3567
|
case 'init':
|
|
3423
3568
|
case 'workspace':
|
|
3424
3569
|
await initBusinessWorkspace(args[0], ...args.slice(1));
|
|
@@ -3523,6 +3668,9 @@ module.exports = {
|
|
|
3523
3668
|
businessMatchesSlug,
|
|
3524
3669
|
isAccidentalHelpBusiness,
|
|
3525
3670
|
validateBusinessCreateName,
|
|
3671
|
+
parseBusinessShipArgs,
|
|
3672
|
+
shipTeamNames,
|
|
3673
|
+
shipTaskTitle,
|
|
3526
3674
|
analyzeBusinessDoctor,
|
|
3527
3675
|
createCanonicalBusinessWorkspace,
|
|
3528
3676
|
onboardBusiness,
|
package/commands/chat-scan.js
CHANGED
|
@@ -2,6 +2,8 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { hasFlag } = require('../lib/arg-parser');
|
|
4
4
|
const { scanChatLogs, writeLatestScan } = require('../lib/chat-log-scan');
|
|
5
|
+
const { parseScopeFlag } = require('../lib/cli-scope');
|
|
6
|
+
const { requireAccountBound, refuseAccountGlobal } = require('../lib/account-bound');
|
|
5
7
|
|
|
6
8
|
// Preserve the existing rule that the next token is a value, even if it is a flag.
|
|
7
9
|
function readFollowingFlag(args, name, fallback) {
|
|
@@ -57,7 +59,7 @@ function printReport(report) {
|
|
|
57
59
|
function chatScanCommand(argv = []) {
|
|
58
60
|
const args = argv.filter((a) => a !== '--');
|
|
59
61
|
if (hasFlag(args, '--help') || hasFlag(args, '-h') || args[0] === 'help') {
|
|
60
|
-
console.log(`Usage: atris chat scan [--json] [--hours <n>] [--limit <n>] [--no-write]
|
|
62
|
+
console.log(`Usage: atris chat scan [--json] [--hours <n>] [--limit <n>] [--no-write] [--global]
|
|
61
63
|
|
|
62
64
|
Read recent ax chat logs and Cursor agent transcripts; surface friction/errors.
|
|
63
65
|
|
|
@@ -65,10 +67,20 @@ Options:
|
|
|
65
67
|
--hours <n> Lookback window (default 720 = 30 days)
|
|
66
68
|
--limit <n> Max sessions per source (default 12)
|
|
67
69
|
--no-write Skip writing .atris/state/chat_scan.latest.json
|
|
68
|
-
--json Machine-readable output
|
|
70
|
+
--json Machine-readable output
|
|
71
|
+
--global Include ~/.atris/runs (unbound folders need --account)`);
|
|
69
72
|
return { ok: true };
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
const scope = parseScopeFlag(args);
|
|
76
|
+
if (scope.global) {
|
|
77
|
+
const gate = requireAccountBound(scope.args);
|
|
78
|
+
if (!gate.ok) {
|
|
79
|
+
refuseAccountGlobal();
|
|
80
|
+
process.exit(2);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
const root = process.cwd();
|
|
73
85
|
if (!fs.existsSync(path.join(root, 'atris'))) {
|
|
74
86
|
console.error('✗ atris/ folder not found. Run from an Atris workspace.');
|
|
@@ -77,8 +89,9 @@ Options:
|
|
|
77
89
|
|
|
78
90
|
const report = scanChatLogs({
|
|
79
91
|
cwd: root,
|
|
80
|
-
hours: readFollowingFlag(args, '--hours', 720),
|
|
81
|
-
limit: readFollowingFlag(args, '--limit', 12),
|
|
92
|
+
hours: readFollowingFlag(scope.args, '--hours', 720),
|
|
93
|
+
limit: readFollowingFlag(scope.args, '--limit', 12),
|
|
94
|
+
global: scope.global,
|
|
82
95
|
});
|
|
83
96
|
|
|
84
97
|
let latestPath = null;
|
package/commands/close.js
CHANGED
|
@@ -1239,7 +1239,11 @@ function run(args = [], context = {}) {
|
|
|
1239
1239
|
const subcommand = args[0];
|
|
1240
1240
|
const rest = args.slice(1);
|
|
1241
1241
|
try {
|
|
1242
|
-
if (!subcommand
|
|
1242
|
+
if (!subcommand) {
|
|
1243
|
+
printHelp();
|
|
1244
|
+
return 2;
|
|
1245
|
+
}
|
|
1246
|
+
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
1243
1247
|
printHelp();
|
|
1244
1248
|
return 0;
|
|
1245
1249
|
}
|
package/commands/computer.js
CHANGED
|
@@ -2141,7 +2141,7 @@ async function runBusinessPromptViaRunnerProxy(token, ctx, prompt, options = {})
|
|
|
2141
2141
|
const payload = {
|
|
2142
2142
|
prompt,
|
|
2143
2143
|
permission_mode: 'bypassPermissions',
|
|
2144
|
-
max_turns: Math.min(Math.max(Number(options.maxTurns ||
|
|
2144
|
+
max_turns: Math.min(Math.max(Number(options.maxTurns || 40), 1), 100),
|
|
2145
2145
|
reset_context: Boolean(options.resetContext),
|
|
2146
2146
|
};
|
|
2147
2147
|
if (options.worker) payload.worker = options.worker;
|
|
@@ -3399,7 +3399,7 @@ async function sendBusinessChat(token, ctx, message, sessionId, resetContext = f
|
|
|
3399
3399
|
const fallback = await runBusinessPromptViaRunnerProxy(token, ctx, message, {
|
|
3400
3400
|
...options,
|
|
3401
3401
|
resetContext,
|
|
3402
|
-
maxTurns:
|
|
3402
|
+
maxTurns: 60,
|
|
3403
3403
|
});
|
|
3404
3404
|
if (!fallback.ok) {
|
|
3405
3405
|
if (typeof options.onFailure === 'function') {
|