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.
Files changed (131) hide show
  1. package/FOR_AGENTS.md +7 -0
  2. package/README.md +1 -1
  3. package/atris/policies/ANTISLOP.md +2 -1
  4. package/atris/skills/copy-editor/SKILL.md +2 -1
  5. package/atris/skills/design/SKILL.md +1 -1
  6. package/atris/skills/engines/SKILL.md +8 -7
  7. package/atris/skills/x-search/SKILL.md +24 -22
  8. package/atris/skills/youtube/SKILL.md +89 -40
  9. package/atris/team/_template/SOUL.md +40 -0
  10. package/atris/team/validator/MEMBER.md +1 -2
  11. package/ax +592 -91
  12. package/bin/atris +21 -0
  13. package/bin/atris.js +580 -378
  14. package/commands/api-key.js +170 -0
  15. package/commands/auth.js +453 -43
  16. package/commands/autoland.js +3 -1
  17. package/commands/autopilot-front.js +58 -11
  18. package/commands/avail.js +5 -4
  19. package/commands/balance.js +55 -0
  20. package/commands/bench.js +29 -1
  21. package/commands/brain.js +63 -12
  22. package/commands/brainstorm.js +18 -0
  23. package/commands/business.js +149 -1
  24. package/commands/chat-scan.js +17 -4
  25. package/commands/close.js +5 -1
  26. package/commands/computer.js +2 -2
  27. package/commands/doctor.js +174 -0
  28. package/commands/dream.js +7 -0
  29. package/commands/drill.js +34 -2
  30. package/commands/engine.js +47 -35
  31. package/commands/errors.js +58 -8
  32. package/commands/experiments.js +14 -0
  33. package/commands/feedback.js +61 -2
  34. package/commands/fleet-report.js +27 -7
  35. package/commands/fleet.js +98 -11
  36. package/commands/founder.js +60 -21
  37. package/commands/human-missions.js +79 -4
  38. package/commands/improve.js +54 -4
  39. package/commands/init.js +68 -92
  40. package/commands/install.js +40 -0
  41. package/commands/integrations.js +399 -30
  42. package/commands/interview.js +8 -0
  43. package/commands/land.js +48 -17
  44. package/commands/learn.js +29 -4
  45. package/commands/log.js +51 -0
  46. package/commands/member.js +68 -10
  47. package/commands/mission.js +339 -74
  48. package/commands/now.js +25 -6
  49. package/commands/orb.js +97 -2
  50. package/commands/pack.js +83 -9
  51. package/commands/playbook.js +381 -0
  52. package/commands/plugin.js +16 -0
  53. package/commands/radar.js +96 -40
  54. package/commands/recap.js +128 -21
  55. package/commands/release.js +102 -2
  56. package/commands/review.js +5 -10
  57. package/commands/revisions.js +55 -0
  58. package/commands/run-front.js +12 -4
  59. package/commands/scout.js +12 -1
  60. package/commands/search.js +123 -28
  61. package/commands/sign.js +2 -2
  62. package/commands/signup.js +12 -3
  63. package/commands/site-deploy.js +17 -4
  64. package/commands/site.js +2 -2
  65. package/commands/skill-eval.js +289 -0
  66. package/commands/skill.js +56 -6
  67. package/commands/social.js +603 -0
  68. package/commands/spaceship.js +69 -6
  69. package/commands/stream.js +8 -1
  70. package/commands/study.js +32 -19
  71. package/commands/sync.js +28 -22
  72. package/commands/task.js +418 -60
  73. package/commands/teach.js +72 -63
  74. package/commands/terminal.js +25 -9
  75. package/commands/topup.js +88 -0
  76. package/commands/truth.js +52 -6
  77. package/commands/usage.js +91 -0
  78. package/commands/verify.js +3 -2
  79. package/commands/version.js +3 -1
  80. package/commands/voice.js +5 -1
  81. package/commands/who.js +69 -11
  82. package/commands/wiki.js +7 -4
  83. package/commands/wish.js +76 -5
  84. package/commands/workflow.js +327 -145
  85. package/commands/worktree.js +1 -0
  86. package/commands/write.js +5 -0
  87. package/commands/x-search.js +340 -0
  88. package/commands/xp.js +5 -1
  89. package/commands/youtube.js +551 -33
  90. package/lib/account-bound.js +47 -0
  91. package/lib/auto-accept-certified.js +10 -2
  92. package/lib/auto-lessons.js +186 -0
  93. package/lib/autoland.js +4 -2
  94. package/lib/chat-log-scan.js +7 -4
  95. package/lib/cli-json.js +77 -0
  96. package/lib/cli-scope.js +26 -0
  97. package/lib/codex-flight.js +1 -0
  98. package/lib/conductor-artifacts.js +1 -1
  99. package/lib/context-gatherer.js +11 -0
  100. package/lib/developer-api.js +116 -0
  101. package/lib/engine-ask.js +11 -3
  102. package/lib/engine-registry.js +32 -7
  103. package/lib/feedback-triage.js +274 -0
  104. package/lib/first-minute.js +398 -0
  105. package/lib/fleet.js +115 -34
  106. package/lib/functional-owner.js +22 -0
  107. package/lib/known-commands.js +31 -5
  108. package/lib/member-scaffold.js +197 -0
  109. package/lib/mission-ledger-compact.js +127 -0
  110. package/lib/mission-root.js +4 -2
  111. package/lib/mission-runtime-loop.js +30 -2
  112. package/lib/next-moves.js +34 -34
  113. package/lib/noninteractive.js +88 -0
  114. package/lib/permission-grants.js +10 -1
  115. package/lib/policy-lessons.js +4 -1
  116. package/lib/revision-metric.js +279 -0
  117. package/lib/runner-command.js +5 -4
  118. package/lib/scratch-root.js +48 -0
  119. package/lib/skill-eval-gate.js +249 -0
  120. package/lib/task-db.js +22 -2
  121. package/lib/task-proof.js +75 -9
  122. package/lib/task-receipt.js +5 -1
  123. package/lib/verifier-quality.js +69 -0
  124. package/lib/wish-audit.js +2 -2
  125. package/lib/wish-delegate.js +10 -1
  126. package/lib/workspace-scaffold.js +270 -0
  127. package/package.json +4 -2
  128. package/scripts/det/checklist-score.js +191 -0
  129. package/scripts/det/ytsearch +31 -0
  130. package/scripts/outbound-artifact-gate.js +227 -0
  131. package/utils/update-check.js +15 -0
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  /**
2
4
  * atris spaceship — bounded, self-reporting overnight runner.
3
5
  *
@@ -7,26 +9,87 @@
7
9
  * `atris spaceship ...` and integrates with the CLI's command dispatch.
8
10
  *
9
11
  * Examples:
10
- * atris spaceship --hours 4
11
- * atris spaceship --hours 4 --repo /path/to/repo --interval 780
12
- * atris spaceship --hours 0.01 --tick-cmd /tmp/stub.sh --no-email # test
12
+ * atris spaceship --hours 4 --yes
13
+ * atris spaceship --hours 4 --repo /path/to/repo --interval 780 --yes
14
+ * atris spaceship --hours 0.01 --tick-cmd /tmp/stub.sh --no-email --yes
15
+ *
16
+ * Without --yes, spaceship only prints the plan (no email, no overnight run).
17
+ * `--json` without --yes prints a JSON refuse and still does not start.
13
18
  */
14
19
 
15
20
  const path = require('path');
16
21
  const fs = require('fs');
17
22
  const { spawn } = require('child_process');
23
+ const { hasYesFlag, argsWantHelp, wantsJson } = require('../lib/noninteractive');
18
24
 
19
25
  const SCRIPT = path.join(__dirname, '..', 'scripts', 'spaceship.sh');
20
26
 
27
+ function printUsage() {
28
+ const lines = [
29
+ 'Usage: atris spaceship [--hours N] [--interval SEC] [--repo PATH]',
30
+ ' [--tick-cmd CMD] [--tick-timeout SEC]',
31
+ ' [--idle-alert N] [--halt-alert N] [--label NAME]',
32
+ ' [--no-email] [--yes]',
33
+ '',
34
+ 'Bounded overnight runner. Survives bad ticks and emails on state changes.',
35
+ 'Without --yes, prints the plan only (no email, no overnight run).',
36
+ 'Defaults: --hours 4, --interval 780, tick = atris autopilot --auto --iterations=1',
37
+ ];
38
+ console.log(lines.join('\n'));
39
+ }
40
+
41
+ function planLines(args = []) {
42
+ const hoursIdx = args.indexOf('--hours');
43
+ const hours = hoursIdx !== -1 && args[hoursIdx + 1] ? args[hoursIdx + 1] : '4';
44
+ return [
45
+ 'spaceship plan (no run):',
46
+ ` budget: ${hours}h`,
47
+ ' email: on meaningful state changes (unless --no-email)',
48
+ ' tick: atris autopilot --auto --iterations=1',
49
+ 'Pass --yes to start the overnight run.',
50
+ ];
51
+ }
52
+
21
53
  function spaceship(args = []) {
54
+ const list = Array.isArray(args) ? args : [];
55
+ if (argsWantHelp(list) || list.includes('--help') || list.includes('-h')) {
56
+ printUsage();
57
+ return Promise.resolve({ success: true, help: true });
58
+ }
59
+
60
+ // Same proceed-flag gate as autopilot: --json is not consent, --once is
61
+ // not consent. Only --yes / -y start the overnight run.
62
+ if (wantsJson(list) && !hasYesFlag(list)) {
63
+ console.log(JSON.stringify({
64
+ ok: false,
65
+ command: 'spaceship',
66
+ running: false,
67
+ error: 'pass --yes to start',
68
+ usage: 'atris spaceship [--yes|--auto] [--once]',
69
+ }, null, 2));
70
+ process.exit(2);
71
+ }
72
+
73
+ if (!hasYesFlag(list)) {
74
+ for (const line of planLines(list)) console.log(line);
75
+ process.exit(2);
76
+ }
77
+
78
+ const runArgs = list.filter((a) => a !== '--yes' && a !== '-y' && a !== '--json');
22
79
  return new Promise((resolve, reject) => {
23
80
  if (!fs.existsSync(SCRIPT)) {
24
81
  reject(new Error(`spaceship.sh not found at ${SCRIPT}`));
25
82
  return;
26
83
  }
27
- const child = spawn('bash', [SCRIPT, ...args], {
84
+ const env = { ...process.env };
85
+ if (!process.stdout.isTTY) {
86
+ env.NO_COLOR = '1';
87
+ env.CLICOLOR = '0';
88
+ env.FORCE_COLOR = '0';
89
+ }
90
+ const child = spawn('bash', [SCRIPT, ...runArgs], {
28
91
  stdio: 'inherit',
29
- env: process.env,
92
+ env,
30
93
  });
31
94
  child.on('error', reject);
32
95
  child.on('close', (code) => {
@@ -36,4 +99,4 @@ function spaceship(args = []) {
36
99
  });
37
100
  }
38
101
 
39
- module.exports = { spaceship, SCRIPT };
102
+ module.exports = { spaceship, SCRIPT, printUsage, planLines };
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { hasFlag, readFlag } = require('../lib/arg-parser');
6
+ const { isNonInteractive } = require('../lib/noninteractive');
6
7
  const escapeRegExp = require('../lib/escape-regexp');
7
8
  const { runGit: spawnGit } = require('../lib/git-spawn');
8
9
  const { collectBoard } = require('./land');
@@ -716,12 +717,16 @@ function parseArgs(args = [], nowMs = Date.now()) {
716
717
  const sinceRaw = readFlag(args, '--since', '');
717
718
  const intervalRaw = readFlag(args, '--interval', '');
718
719
  const interval = Number(intervalRaw);
720
+ const onceFlag = hasFlag(args, '--once');
721
+ // Watch loops must exit in agent/non-TTY sessions. --once is explicit;
722
+ // ATRIS_NONINTERACTIVE / non-TTY stdin also force a one-shot snapshot.
723
+ const once = onceFlag || isNonInteractive(args) || !process.stdin.isTTY || !process.stdout.isTTY;
719
724
  return {
720
725
  agent: readFlag(args, '--agent', ''),
721
726
  sinceMs: parseSince(sinceRaw, nowMs),
722
727
  json: hasFlag(args, '--json'),
723
728
  raw: hasFlag(args, '--raw'),
724
- once: hasFlag(args, '--once'),
729
+ once,
725
730
  intervalMs: Number.isFinite(interval) && interval > 0 ? Math.max(250, interval * 1000) : DEFAULT_INTERVAL_MS,
726
731
  };
727
732
  }
@@ -750,12 +755,14 @@ function showHelp() {
750
755
  console.log('atris stream - watch the whole team work live');
751
756
  console.log('');
752
757
  console.log(' atris stream');
758
+ console.log(' atris stream --once');
753
759
  console.log(' atris stream --agent codex');
754
760
  console.log(' atris stream --since 1h');
755
761
  console.log(' atris stream --json');
756
762
  console.log(' atris stream --raw');
757
763
  console.log('');
758
764
  console.log('Default lines hide ids, branch names, and paths. Use --raw or --json for source records.');
765
+ console.log('--once (or non-TTY / ATRIS_NONINTERACTIVE) prints one snapshot and exits.');
759
766
  console.log('');
760
767
  return 0;
761
768
  }
package/commands/study.js CHANGED
@@ -16,7 +16,6 @@ const path = require('path');
16
16
  const http = require('http');
17
17
  const { spawn, spawnSync } = require('child_process');
18
18
 
19
- const BACKEND_ROOT = '/Users/keshavrao/arena/atrisos-backend';
20
19
  const FEED_URL = 'http://localhost:8777';
21
20
  const FEED_STATS_URL = `${FEED_URL}/api/stats`;
22
21
  const FEED_NEXT_URL = `${FEED_URL}/api/next`;
@@ -91,18 +90,31 @@ function parseArgs(argv = []) {
91
90
  return opts;
92
91
  }
93
92
 
93
+ function resolveStudyRoot(cwd = process.cwd()) {
94
+ const candidates = [
95
+ process.env.ATRIS_STUDY_ROOT,
96
+ process.env.ATRIS_BACKEND_ROOT,
97
+ path.join(path.resolve(cwd), 'atris', 'study'),
98
+ ].filter(Boolean);
99
+ for (const root of candidates) {
100
+ const resolved = path.resolve(String(root));
101
+ if (fs.existsSync(resolved)) return resolved;
102
+ }
103
+ return null;
104
+ }
105
+
94
106
  function requireBackend() {
95
- if (!fs.existsSync(BACKEND_ROOT)) {
96
- console.error(`✗ Backend repo not found: ${BACKEND_ROOT}`);
97
- process.exit(1);
107
+ const backendRoot = resolveStudyRoot();
108
+ if (!backendRoot) {
109
+ console.error('not installed');
110
+ process.exit(2);
98
111
  }
99
- const venvPython = path.join(BACKEND_ROOT, 'venv/bin/python');
112
+ const venvPython = path.join(backendRoot, 'venv/bin/python');
100
113
  if (!fs.existsSync(venvPython)) {
101
- console.error(`✗ Backend venv not found: ${venvPython}`);
102
- console.error(' Create the venv in atrisos-backend before running atris study.');
103
- process.exit(1);
114
+ console.error('not installed');
115
+ process.exit(2);
104
116
  }
105
- return venvPython;
117
+ return { venvPython, backendRoot };
106
118
  }
107
119
 
108
120
  function detectLanguage(topic) {
@@ -608,11 +620,11 @@ async function runWhileMode(opts) {
608
620
  const topic = opts.topic;
609
621
 
610
622
  if (topic) {
611
- const venvPython = requireBackend();
623
+ const { venvPython, backendRoot } = requireBackend();
612
624
  const language = detectLanguage(topic);
613
- if (language) printTutorLoopBlock(BACKEND_ROOT, language);
625
+ if (language) printTutorLoopBlock(backendRoot, language);
614
626
  try {
615
- await runIngest(venvPython, BACKEND_ROOT, topic, opts.personal);
627
+ await runIngest(venvPython, backendRoot, topic, opts.personal);
616
628
  } catch (err) {
617
629
  console.error(`\n✗ ${err.message || err}`);
618
630
  }
@@ -625,9 +637,10 @@ async function runWhileMode(opts) {
625
637
  let statsAvailable = false;
626
638
  let useCards = false;
627
639
 
628
- if (fs.existsSync(BACKEND_ROOT) && fs.existsSync(path.join(BACKEND_ROOT, 'venv/bin/python'))) {
629
- const venvPython = path.join(BACKEND_ROOT, 'venv/bin/python');
630
- statsAvailable = await tryEnsureFeedServerSilent(venvPython, BACKEND_ROOT);
640
+ const studyRoot = resolveStudyRoot();
641
+ if (studyRoot && fs.existsSync(path.join(studyRoot, 'venv/bin/python'))) {
642
+ const venvPython = path.join(studyRoot, 'venv/bin/python');
643
+ statsAvailable = await tryEnsureFeedServerSilent(venvPython, studyRoot);
631
644
  useCards = statsAvailable;
632
645
  }
633
646
 
@@ -663,21 +676,21 @@ async function run(argv = []) {
663
676
  return 0;
664
677
  }
665
678
 
666
- const venvPython = requireBackend();
679
+ const { venvPython, backendRoot } = requireBackend();
667
680
  const language = detectLanguage(opts.topic);
668
681
 
669
682
  if (language) {
670
- printTutorLoopBlock(BACKEND_ROOT, language);
683
+ printTutorLoopBlock(backendRoot, language);
671
684
  }
672
685
 
673
686
  try {
674
- await runIngest(venvPython, BACKEND_ROOT, opts.topic, opts.personal);
687
+ await runIngest(venvPython, backendRoot, opts.topic, opts.personal);
675
688
  } catch (err) {
676
689
  console.error(`\n✗ ${err.message || err}`);
677
690
  return 1;
678
691
  }
679
692
 
680
- await ensureFeedServer(venvPython, BACKEND_ROOT);
693
+ await ensureFeedServer(venvPython, backendRoot);
681
694
  openFeed();
682
695
  return 0;
683
696
  }
package/commands/sync.js CHANGED
@@ -9,6 +9,7 @@ const {
9
9
  upsertCursorVoiceCard,
10
10
  voiceCardForRoot,
11
11
  } = require('../lib/voice-card');
12
+ const { isNonInteractive } = require('../lib/noninteractive');
12
13
 
13
14
  const TEMPLATE_ROOT_DIR = path.join(__dirname, '..', 'templates');
14
15
  const WORKSPACE_TEMPLATES = {
@@ -437,18 +438,28 @@ function syncBusinessCanonical(targetRoot, bizMeta, options = {}) {
437
438
  }
438
439
 
439
440
  function syncAtris(options = {}) {
440
- const dryRun = options.dryRun != null ? options.dryRun : process.argv.includes('--dry-run');
441
+ const explicitDryRun = options.dryRun != null ? options.dryRun : process.argv.includes('--dry-run');
442
+ const yes = options.yes != null
443
+ ? options.yes
444
+ : (process.argv.includes('--yes') || process.argv.includes('-y'));
445
+ // Default is plan-only. Writes require an explicit --yes.
446
+ const dryRun = explicitDryRun || !yes;
441
447
  const force = options.force != null ? options.force : process.argv.includes('--force');
442
448
  // Business mode detection: if .atris/business.json exists, use canonical templates
443
449
  const bizFile = path.join(process.cwd(), '.atris', 'business.json');
444
450
  if (fs.existsSync(bizFile)) {
445
451
  try {
446
452
  const bizMeta = JSON.parse(fs.readFileSync(bizFile, 'utf8'));
447
- return syncWorkspaceTemplate(process.cwd(), bizMeta, {
453
+ const result = syncWorkspaceTemplate(process.cwd(), bizMeta, {
448
454
  templateName: bizMeta.workspace_template || 'business',
449
455
  dryRun,
450
456
  force,
451
457
  });
458
+ if (!yes) {
459
+ console.log('\nPlan only. Re-run with --yes to write these files.');
460
+ if (!explicitDryRun && isNonInteractive()) process.exit(2);
461
+ }
462
+ return result;
452
463
  } catch (e) {
453
464
  console.error(`✗ Failed to read .atris/business.json: ${e.message}`);
454
465
  process.exit(1);
@@ -672,6 +683,10 @@ Key behaviors:
672
683
 
673
684
  if (dryRun) {
674
685
  console.log(`\nDry run: ${updated} file(s) would update, ${skipped} unchanged; no changes made.`);
686
+ if (!yes) {
687
+ console.log('Plan only. Re-run with --yes to write these files.');
688
+ if (!explicitDryRun && isNonInteractive()) process.exit(2);
689
+ }
675
690
  } else if (updated === 0) {
676
691
  ensureWikiScaffold(process.cwd());
677
692
  console.log('✓ Already up to date');
@@ -892,9 +907,13 @@ function buildSyncAllPlan({ root, pkgRoot, filesToSync = SYNC_ALL_FILES } = {})
892
907
  return { projects, plan };
893
908
  }
894
909
 
895
- function syncAtrisAll({ dryRun = false, force = false } = {}) {
910
+ function syncAtrisAll({ dryRun = false, force = false, yes = false } = {}) {
896
911
  const root = process.cwd();
897
912
  const pkgRoot = path.join(__dirname, '..');
913
+ const writeYes = yes || process.argv.includes('--yes') || process.argv.includes('-y');
914
+ const explicitDryRun = dryRun || process.argv.includes('--dry-run');
915
+ // Default is plan-only. Writes require --yes.
916
+ const planOnly = explicitDryRun || !writeYes;
898
917
 
899
918
  console.log('');
900
919
  console.log(`Scanning ${root} for atris projects...`);
@@ -931,8 +950,12 @@ function syncAtrisAll({ dryRun = false, force = false } = {}) {
931
950
  }
932
951
  console.log('');
933
952
 
934
- if (dryRun) {
953
+ if (planOnly) {
935
954
  console.log(`Dry run: ${wouldUpdate} project(s) would update, ${unchanged} unchanged, ${skipped} skipped.`);
955
+ if (!writeYes) {
956
+ console.log('Plan only. Re-run with --yes to write these files.');
957
+ if (!explicitDryRun && isNonInteractive()) process.exit(2);
958
+ }
936
959
  return;
937
960
  }
938
961
 
@@ -941,24 +964,7 @@ function syncAtrisAll({ dryRun = false, force = false } = {}) {
941
964
  return;
942
965
  }
943
966
 
944
- // Confirm unless forced.
945
- if (!force) {
946
- const readline = require('readline');
947
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
948
- return new Promise((resolve) => {
949
- rl.question(`Sync ${wouldUpdate} project(s)? (y/N) `, (answer) => {
950
- rl.close();
951
- if (!/^y(es)?$/i.test(answer.trim())) {
952
- console.log('Cancelled.');
953
- resolve();
954
- return;
955
- }
956
- _executeSyncAll(plan, pkgRoot, filesToSync, root);
957
- resolve();
958
- });
959
- });
960
- }
961
-
967
+ // --yes already consented; skip the interactive confirm.
962
968
  _executeSyncAll(plan, pkgRoot, filesToSync, root);
963
969
  }
964
970