atris 3.57.3 → 3.58.5

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 (175) hide show
  1. package/README.md +12 -1
  2. package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
  3. package/atris/skills/create-member/SKILL.md +16 -13
  4. package/atris/skills/design/SKILL.md +27 -4
  5. package/atris/skills/engines/SKILL.md +57 -13
  6. package/atris/skills/x-search/SKILL.md +13 -5
  7. package/atris/skills/youtube/SKILL.md +39 -8
  8. package/atris/team/brainstormer/MEMBER.md +2 -2
  9. package/atris/team/executor/MEMBER.md +3 -3
  10. package/atris/team/launcher/MEMBER.md +4 -4
  11. package/atris/team/navigator/MEMBER.md +3 -3
  12. package/atris/team/researcher/MEMBER.md +2 -2
  13. package/atris/team/validator/MEMBER.md +1 -1
  14. package/atris.md +14 -0
  15. package/ax +157 -24
  16. package/bin/atris.js +79 -31
  17. package/commands/aeo.js +4 -4
  18. package/commands/agents.js +1 -1
  19. package/commands/align.js +12 -12
  20. package/commands/analytics.js +3 -3
  21. package/commands/app.js +5 -5
  22. package/commands/ask.js +175 -0
  23. package/commands/auth.js +7 -7
  24. package/commands/autoland.js +29 -5
  25. package/commands/autopilot-front.js +6 -6
  26. package/commands/autopilot.js +90 -90
  27. package/commands/avail.js +5 -5
  28. package/commands/bench.js +63 -1
  29. package/commands/browse.js +2 -2
  30. package/commands/business.js +12 -12
  31. package/commands/card.js +2 -2
  32. package/commands/clean.js +13 -13
  33. package/commands/close.js +297 -15
  34. package/commands/compile.js +13 -13
  35. package/commands/computer.js +94 -27
  36. package/commands/console.js +5 -5
  37. package/commands/decide.js +1 -1
  38. package/commands/deck.js +9 -9
  39. package/commands/drive.js +4 -4
  40. package/commands/engine.js +173 -19
  41. package/commands/errors.js +3 -3
  42. package/commands/experiments.js +18 -1
  43. package/commands/feed.js +2 -2
  44. package/commands/feedback.js +4 -4
  45. package/commands/fleet.js +12 -12
  46. package/commands/game.js +1 -1
  47. package/commands/guide.js +49 -0
  48. package/commands/improve.js +19 -17
  49. package/commands/init.js +67 -19
  50. package/commands/interview.js +7 -7
  51. package/commands/land.js +40 -15
  52. package/commands/learn.js +12 -12
  53. package/commands/lesson.js +2 -2
  54. package/commands/log.js +1 -1
  55. package/commands/loops.js +4 -4
  56. package/commands/member.js +75 -50
  57. package/commands/mission.js +97 -98
  58. package/commands/one-lap.js +1 -1
  59. package/commands/pack.js +74 -8
  60. package/commands/plugin.js +6 -6
  61. package/commands/probe.js +9 -9
  62. package/commands/pull.js +35 -35
  63. package/commands/pulse.js +1 -1
  64. package/commands/push.js +21 -21
  65. package/commands/rainmaker.js +1 -1
  66. package/commands/recap.js +7 -7
  67. package/commands/reel.js +2 -2
  68. package/commands/release.js +3 -3
  69. package/commands/report.js +1 -1
  70. package/commands/review.js +5 -5
  71. package/commands/revisions.js +1 -1
  72. package/commands/run.js +1 -1
  73. package/commands/scout.js +3 -3
  74. package/commands/security-review.js +7 -7
  75. package/commands/serve.js +9 -9
  76. package/commands/setup.js +1 -1
  77. package/commands/sign.js +4 -4
  78. package/commands/signup.js +4 -4
  79. package/commands/site.js +8 -3
  80. package/commands/skill.js +6 -6
  81. package/commands/slop.js +18 -18
  82. package/commands/social.js +3 -3
  83. package/commands/soul.js +14 -14
  84. package/commands/spaceship.js +1 -1
  85. package/commands/status.js +2 -2
  86. package/commands/strings.js +13 -13
  87. package/commands/study.js +4 -4
  88. package/commands/sync.js +8 -8
  89. package/commands/task.js +50 -25
  90. package/commands/teach.js +2 -2
  91. package/commands/team.js +1 -1
  92. package/commands/theme.js +2 -2
  93. package/commands/tree.js +34 -0
  94. package/commands/truth.js +7 -7
  95. package/commands/verify.js +12 -12
  96. package/commands/visualize.js +2 -2
  97. package/commands/workflow.js +97 -40
  98. package/commands/worktree.js +57 -1
  99. package/commands/write.js +9 -9
  100. package/commands/x-search.js +304 -15
  101. package/commands/xp.js +6 -3
  102. package/commands/youtube.js +916 -65
  103. package/lib/accept-verify-gate.js +3 -3
  104. package/lib/activity-stream.js +1 -1
  105. package/lib/apply-gate.js +13 -0
  106. package/lib/auto-accept-certified.js +28 -12
  107. package/lib/autoland.js +6 -6
  108. package/lib/bench/engines.js +59 -8
  109. package/lib/bench/report.js +1 -1
  110. package/lib/bench/runner.js +204 -5
  111. package/lib/bench/tree-render.js +76 -0
  112. package/lib/card.js +1 -1
  113. package/lib/chat-log-scan.js +1 -1
  114. package/lib/claude-boot-block.js +2 -0
  115. package/lib/deck-compose.js +1 -1
  116. package/lib/deck-history.js +2 -2
  117. package/lib/deck-layout.js +1 -1
  118. package/lib/deck-review.js +5 -5
  119. package/lib/deck-schema.js +1 -1
  120. package/lib/default-verifier.js +1 -1
  121. package/lib/developer-api.js +3 -0
  122. package/lib/engine-ask.js +66 -9
  123. package/lib/engine-registry.js +15 -2
  124. package/lib/file-ops.js +1 -1
  125. package/lib/fleet.js +71 -35
  126. package/lib/html-render.js +1 -1
  127. package/lib/intents.js +172 -0
  128. package/lib/journal.js +1 -1
  129. package/lib/known-commands.js +2 -2
  130. package/lib/land-green.js +364 -0
  131. package/lib/lesson-contradiction.js +2 -2
  132. package/lib/lesson-preflight.js +1 -1
  133. package/lib/manifest.js +5 -5
  134. package/lib/member-alive.js +9 -5
  135. package/lib/memory-view.js +3 -3
  136. package/lib/mission-protected-lane.js +1 -1
  137. package/lib/mission-root.js +2 -2
  138. package/lib/orb-context.js +10 -10
  139. package/lib/pack-capabilities.js +861 -3
  140. package/lib/permission-grants.js +2 -2
  141. package/lib/policy-lessons.js +6 -6
  142. package/lib/pulse.js +8 -8
  143. package/lib/receipt-evidence.js +1 -1
  144. package/lib/reel.js +1 -1
  145. package/lib/review-integrity.js +1 -1
  146. package/lib/runner-command.js +35 -5
  147. package/lib/scorecard.js +4 -4
  148. package/lib/security-scan.js +5 -5
  149. package/lib/self-drive.js +1 -1
  150. package/lib/site-publish.js +372 -0
  151. package/lib/site.js +1 -1
  152. package/lib/slides-deck.js +2 -2
  153. package/lib/state-detection.js +2 -2
  154. package/lib/sync-telemetry.js +2 -2
  155. package/lib/task-db.js +17 -10
  156. package/lib/task-explanation.js +1 -1
  157. package/lib/task-proof.js +2 -2
  158. package/lib/task-receipt.js +3 -3
  159. package/lib/theme.js +12 -12
  160. package/lib/todo-fallback.js +3 -3
  161. package/lib/todo-sections.js +1 -1
  162. package/lib/tree-hash.js +79 -0
  163. package/lib/usage.js +1 -1
  164. package/lib/wish-delegate.js +1 -1
  165. package/lib/workspace-safety.js +4 -4
  166. package/lib/workspace-scaffold.js +3 -3
  167. package/package.json +1 -1
  168. package/scripts/det/concierge-bakeoff.sh +26 -0
  169. package/scripts/det/ytquote-repair.js +0 -1
  170. package/scripts/det/ytrail-race.js +0 -5
  171. package/scripts/member-operate.mjs +52 -14
  172. package/scripts/outbound-artifact-gate.js +0 -3
  173. package/utils/auth.js +0 -3
  174. package/utils/config.js +0 -1
  175. package/scripts/det/checklist-score.js +0 -191
@@ -1,20 +1,20 @@
1
1
  /**
2
- * Atris Computer interact with your EC2 AI Computer
2
+ * Atris Computer: interact with your EC2 AI Computer
3
3
  *
4
- * atris computer Open SMART mode (cloud in business workspace, local elsewhere)
5
- * atris computer setup Connect coding accounts to a computer
6
- * atris computer --cloud Open CLOUD workspace mode
7
- * atris computer create <name> Create and wake a business computer
8
- * atris computer wake Start the computer
9
- * atris computer sleep Stop (files persist)
10
- * atris computer delete Sleep, confirm, and delete a business computer
11
- * atris computer card Show the local computer card
12
- * atris computer run <command> Run bash on EC2 (no LLM)
13
- * atris computer grep <pattern> Search files on EC2
14
- * atris computer ls [path] List files
15
- * atris computer cat <path> Read a file
16
- * atris computer exec <prompt> Run with LLM (Claude Code)
17
- * atris computer recruiting Open the recruiting workflow shortcut
4
+ * atris computer : Open SMART mode (cloud in business workspace, local elsewhere)
5
+ * atris computer setup : Connect coding accounts to a computer
6
+ * atris computer --cloud : Open CLOUD workspace mode
7
+ * atris computer create <name> : Create and wake a business computer
8
+ * atris computer wake : Start the computer
9
+ * atris computer sleep : Stop (files persist)
10
+ * atris computer delete : Sleep, confirm, and delete a business computer
11
+ * atris computer card : Show the local computer card
12
+ * atris computer run <command> : Run bash on EC2 (no LLM)
13
+ * atris computer grep <pattern> : Search files on EC2
14
+ * atris computer ls [path] : List files
15
+ * atris computer cat <path> : Read a file
16
+ * atris computer exec <prompt> : Run with LLM (Claude Code)
17
+ * atris computer recruiting : Open the recruiting workflow shortcut
18
18
  */
19
19
 
20
20
  const fs = require('fs');
@@ -440,7 +440,7 @@ function appendSystemPrompt(basePrompt, extraPrompt) {
440
440
  function codeOpsCloudOptions(options = {}) {
441
441
  return {
442
442
  ...options,
443
- worker: options.worker || 'claude',
443
+ worker: options.worker || null,
444
444
  mode: 'codeops',
445
445
  systemPrompt: appendSystemPrompt(options.systemPrompt, CODEOPS_WORKFLOW_PROMPT),
446
446
  };
@@ -449,7 +449,7 @@ function codeOpsCloudOptions(options = {}) {
449
449
  function recruitingCloudOptions(options = {}) {
450
450
  return {
451
451
  ...options,
452
- worker: options.worker || 'claude',
452
+ worker: options.worker || null,
453
453
  mode: 'recruiting',
454
454
  systemPrompt: appendSystemPrompt(options.systemPrompt, RECRUITING_WORKFLOW_PROMPT),
455
455
  };
@@ -1124,7 +1124,7 @@ async function chooseComputerSurface(hasBusinessBinding, hasLocalHarness) {
1124
1124
  }
1125
1125
 
1126
1126
  async function chooseCloudLane(token, ctx, initialOptions = {}) {
1127
- let worker = initialOptions.worker || null;
1127
+ let worker = initialOptions.worker || ctx?.worker || null;
1128
1128
  let model = initialOptions.model || null;
1129
1129
 
1130
1130
  if (!worker && useInteractiveCloudUi()) {
@@ -1664,6 +1664,19 @@ function computerCard(args = [], cwd = process.cwd()) {
1664
1664
  return card;
1665
1665
  }
1666
1666
 
1667
+ function savedBusinessWorker(slug) {
1668
+ if (!slug) return null;
1669
+ const wanted = String(slug).toLowerCase();
1670
+ const businesses = loadBusinesses();
1671
+ const entry = businesses[slug] || Object.values(businesses).find((item) => {
1672
+ if (!item) return false;
1673
+ return String(item.slug || '').toLowerCase() === wanted
1674
+ || String(item.canonical_slug || '').toLowerCase() === wanted
1675
+ || String(item.name || '').toLowerCase() === wanted;
1676
+ });
1677
+ return entry?.worker || null;
1678
+ }
1679
+
1667
1680
  async function resolveBusinessContext(token) {
1668
1681
  const binding = readBusinessBinding();
1669
1682
  if (!binding) return null;
@@ -1674,6 +1687,7 @@ async function resolveBusinessContext(token) {
1674
1687
  businessId: binding.business_id,
1675
1688
  workspaceId: binding.workspace_id,
1676
1689
  businessName: binding.name || binding.slug || 'business',
1690
+ worker: savedBusinessWorker(binding.slug),
1677
1691
  };
1678
1692
  }
1679
1693
 
@@ -1688,6 +1702,7 @@ async function resolveBusinessContext(token) {
1688
1702
  );
1689
1703
  if (match) {
1690
1704
  businesses[slug] = {
1705
+ ...(businesses[slug] || {}),
1691
1706
  business_id: match.id,
1692
1707
  workspace_id: match.workspace_id,
1693
1708
  name: match.name,
@@ -1700,6 +1715,7 @@ async function resolveBusinessContext(token) {
1700
1715
  businessId: match.id,
1701
1716
  workspaceId: match.workspace_id,
1702
1717
  businessName: match.name || match.slug,
1718
+ worker: businesses[slug].worker || null,
1703
1719
  };
1704
1720
  }
1705
1721
  }
@@ -1711,6 +1727,7 @@ async function resolveBusinessContext(token) {
1711
1727
  businessId: cached.business_id,
1712
1728
  workspaceId: cached.workspace_id,
1713
1729
  businessName: cached.name || slug,
1730
+ worker: cached.worker || null,
1714
1731
  };
1715
1732
  }
1716
1733
 
@@ -1733,6 +1750,7 @@ function cachedBusinessContext(slug) {
1733
1750
  businessId: cached.business_id,
1734
1751
  workspaceId: cached.workspace_id || null,
1735
1752
  businessName: cached.name || cached.slug || slug,
1753
+ worker: cached.worker || null,
1736
1754
  };
1737
1755
  }
1738
1756
 
@@ -1751,7 +1769,9 @@ async function resolveBusinessContextBySlug(token, slug, options = {}) {
1751
1769
  (b) => b.slug === slug || (b.name || '').toLowerCase() === slug.toLowerCase()
1752
1770
  );
1753
1771
  if (match) {
1754
- businesses[match.slug || slug] = {
1772
+ const key = match.slug || slug;
1773
+ businesses[key] = {
1774
+ ...(businesses[key] || {}),
1755
1775
  business_id: match.id,
1756
1776
  workspace_id: match.workspace_id,
1757
1777
  name: match.name,
@@ -1764,6 +1784,7 @@ async function resolveBusinessContextBySlug(token, slug, options = {}) {
1764
1784
  businessId: match.id,
1765
1785
  workspaceId: match.workspace_id,
1766
1786
  businessName: match.name || match.slug,
1787
+ worker: businesses[key].worker || null,
1767
1788
  };
1768
1789
  }
1769
1790
  }
@@ -1790,6 +1811,7 @@ async function resolveSingleBusinessShortcutFallback(token, slug) {
1790
1811
  const businesses = loadBusinesses();
1791
1812
  const businessName = shortcutBusinessLabel(wantedSlug, match.name || match.slug);
1792
1813
  businesses[wantedSlug] = {
1814
+ ...(businesses[wantedSlug] || {}),
1793
1815
  business_id: match.id,
1794
1816
  workspace_id: match.workspace_id,
1795
1817
  name: businessName,
@@ -1803,6 +1825,7 @@ async function resolveSingleBusinessShortcutFallback(token, slug) {
1803
1825
  businessId: match.id,
1804
1826
  workspaceId: match.workspace_id,
1805
1827
  businessName,
1828
+ worker: businesses[wantedSlug].worker || null,
1806
1829
  };
1807
1830
  }
1808
1831
 
@@ -2839,12 +2862,12 @@ async function computerDiff(token, remotePath, ctx = null) {
2839
2862
  for (const f of remoteFiles) {
2840
2863
  const localPath = path.join(localDir, f.name);
2841
2864
  if (!fs.existsSync(localPath)) {
2842
- console.log(` + ${f.name} (${f.size}b) new on EC2`);
2865
+ console.log(` + ${f.name} (${f.size}b), new on EC2`);
2843
2866
  added++;
2844
2867
  } else {
2845
2868
  const localSize = fs.statSync(localPath).size;
2846
2869
  if (Math.abs(localSize - (f.size || 0)) > 10) {
2847
- console.log(` ~ ${f.name} (local: ${localSize}b, EC2: ${f.size}b) changed`);
2870
+ console.log(` ~ ${f.name} (local: ${localSize}b, EC2: ${f.size}b), changed`);
2848
2871
  modified++;
2849
2872
  } else {
2850
2873
  same++;
@@ -2857,7 +2880,7 @@ async function computerDiff(token, remotePath, ctx = null) {
2857
2880
  const remoteNames = new Set(remoteFiles.map(f => f.name));
2858
2881
  for (const localFile of fs.readdirSync(localDir)) {
2859
2882
  if (!remoteNames.has(localFile) && localFile.endsWith('.md')) {
2860
- console.log(` - ${localFile} deleted on EC2`);
2883
+ console.log(` - ${localFile}, deleted on EC2`);
2861
2884
  deleted++;
2862
2885
  }
2863
2886
  }
@@ -2924,7 +2947,7 @@ async function computerOnboard(token, businessSlug) {
2924
2947
 
2925
2948
  // Step 1: Push soul template
2926
2949
  console.log('\n 1. Pushing soul template...');
2927
- const soulTemplate = `# Soul ${businessSlug}\n\n## Identity\nBusiness computer for ${businessSlug}. Self-improving context system.\n\n## Goals\n- Learn the business overnight\n- Accumulate context that makes the agent smarter\n- Track what works and what doesn't\n\n## Rules\n- No emails without approval\n- No destructive actions\n- Save everything to soul/\n`;
2950
+ const soulTemplate = `# Soul: ${businessSlug}\n\n## Identity\nBusiness computer for ${businessSlug}. Self-improving context system.\n\n## Goals\n- Learn the business overnight\n- Accumulate context that makes the agent smarter\n- Track what works and what doesn't\n\n## Rules\n- No emails without approval\n- No destructive actions\n- Save everything to soul/\n`;
2928
2951
 
2929
2952
  const templateResult = await apiRequestJson('/ai-computer/terminal', {
2930
2953
  method: 'POST', token,
@@ -2949,7 +2972,7 @@ async function computerOnboard(token, businessSlug) {
2949
2972
  ' NAME=$(basename $f .md)',
2950
2973
  ' FIRST_LINE=$(head -1 $f | sed "s/^# //")',
2951
2974
  ' SIZE=$(wc -c < $f | tr -d " ")',
2952
- ' echo "- [$NAME]($NAME.md) $FIRST_LINE ($SIZE bytes)" >> soul/INDEX.md',
2975
+ ' echo "- [$NAME]($NAME.md), $FIRST_LINE ($SIZE bytes)" >> soul/INDEX.md',
2953
2976
  ' COUNT=$((COUNT + 1)); TOTAL_SIZE=$((TOTAL_SIZE + SIZE))',
2954
2977
  'done',
2955
2978
  'echo "" >> soul/INDEX.md',
@@ -3024,6 +3047,48 @@ async function computerLearn(token, ctx = null) {
3024
3047
  console.log(` The computer is thinking... check back with: atris computer diff soul`);
3025
3048
  }
3026
3049
 
3050
+ function computerLane(rest, ctx) {
3051
+ if (!ctx?.slug && !ctx?.businessId) {
3052
+ console.error('No business selected. Pass --business <slug>.');
3053
+ process.exitCode = 1;
3054
+ return;
3055
+ }
3056
+ const businesses = loadBusinesses();
3057
+ const key = Object.keys(businesses).find((slug) => {
3058
+ const entry = businesses[slug] || {};
3059
+ return slug === ctx.slug || entry.business_id === ctx.businessId;
3060
+ });
3061
+ if (!key) {
3062
+ console.error(`Business ${ctx.slug || ctx.businessId} is not in the local business list yet. Run any computer command against it once, then retry.`);
3063
+ process.exitCode = 1;
3064
+ return;
3065
+ }
3066
+ const requested = (rest || '').trim().toLowerCase();
3067
+ if (!requested) {
3068
+ const current = businesses[key].worker || null;
3069
+ console.log(current
3070
+ ? ` Saved lane for ${key}: ${formatWorkerName(current)}`
3071
+ : ` No saved lane for ${key}. Runs default to Claude unless you pass --worker.`);
3072
+ console.log(` Set one: atris computer lane <claude|openai> --business ${key}`);
3073
+ return;
3074
+ }
3075
+ if (requested === 'clear' || requested === 'none') {
3076
+ delete businesses[key].worker;
3077
+ saveBusinesses(businesses);
3078
+ console.log(` Cleared saved lane for ${key}.`);
3079
+ return;
3080
+ }
3081
+ if (!['claude', 'openai', 'codex'].includes(requested)) {
3082
+ console.error(`Unknown lane "${requested}". Use claude, openai, or clear.`);
3083
+ process.exitCode = 1;
3084
+ return;
3085
+ }
3086
+ const normalized = requested === 'codex' ? 'openai' : requested;
3087
+ businesses[key].worker = normalized;
3088
+ saveBusinesses(businesses);
3089
+ console.log(` Saved lane for ${key}: ${formatWorkerName(normalized)}. Every run for this business now uses it unless you pass --worker.`);
3090
+ }
3091
+
3027
3092
  async function computerExec(token, prompt, ctx = null, options = {}) {
3028
3093
  if (!prompt) {
3029
3094
  console.error('Usage: atris computer exec "<prompt>"');
@@ -3037,8 +3102,9 @@ async function computerExec(token, prompt, ctx = null, options = {}) {
3037
3102
  console.error(' Computer did not become ready in time.');
3038
3103
  return;
3039
3104
  }
3040
- const worker = activeWorker(options.worker);
3041
- console.log(` Lane: ${formatWorkerName(worker)} ${formatCloudSelection({ worker, model: options.model })}`);
3105
+ const worker = activeWorker(options.worker || ctx.worker);
3106
+ const laneSource = options.worker ? '' : ctx.worker ? ' (saved for this business)' : '';
3107
+ console.log(` Lane: ${formatWorkerName(worker)} ${formatCloudSelection({ worker, model: options.model })}${laneSource}`);
3042
3108
  const result = await apiRequestJson(`/business/${ctx.businessId}/chat`, {
3043
3109
  method: 'POST',
3044
3110
  token,
@@ -3451,7 +3517,7 @@ async function computerChat(token, ctx, initialOptions = {}) {
3451
3517
  const scriptedInput = initialOptions.message != null ? String(initialOptions.message) : pipedInput;
3452
3518
  if (!oneShotMessage) printCloudWordmark();
3453
3519
  const selection = oneShotMessage
3454
- ? { worker: initialOptions.worker, model: initialOptions.model }
3520
+ ? { worker: initialOptions.worker || ctx?.worker || null, model: initialOptions.model }
3455
3521
  : await chooseCloudLane(token, ctx, initialOptions);
3456
3522
  if (selection.cancelled) return;
3457
3523
  let worker = activeWorker(selection.worker);
@@ -4377,6 +4443,7 @@ async function runComputer(argv = process.argv.slice(3), deps = {}) {
4377
4443
  case 'ls': return computerLs(token, rest || undefined, ctx);
4378
4444
  case 'cat': return computerCat(token, rest, ctx);
4379
4445
  case 'exec': return computerExec(token, rest, ctx, cloudOptions);
4446
+ case 'lane': return computerLane(rest, ctx);
4380
4447
  case 'pull': {
4381
4448
  const parts = rest.split(' ').filter(Boolean);
4382
4449
  return computerPull(token, parts[0], parts[1], ctx);
@@ -15,7 +15,7 @@ const { resolveClaudeRunnerBin } = require('../lib/runner-command');
15
15
  //
16
16
  // packet: <dir>/{pack.json,skills,team,docs,...}
17
17
  // A packet built in root mode (pack.js exports with prefix '' when the
18
- // source dir has pack.json at its root this is how the shipped packs are
18
+ // source dir has pack.json at its root, this is how the shipped packs are
19
19
  // built and what the web /packs/<slug>/download route serves). `pack
20
20
  // install` preserves that flat layout, so the packet folder IS the atris
21
21
  // root; there is no nested atris/ to find.
@@ -50,7 +50,7 @@ function gatherAtrisContext(workspaceDir) {
50
50
 
51
51
  if (!ctx.hasAtris) return ctx;
52
52
 
53
- // Skills scan atris/skills/ and .claude/skills/
53
+ // Skills, scan atris/skills/ and .claude/skills/
54
54
  for (const skillsRoot of [
55
55
  path.join(atrisDir, 'skills'),
56
56
  path.join(workspaceDir, '.claude', 'skills'),
@@ -92,7 +92,7 @@ function gatherAtrisContext(workspaceDir) {
92
92
  return true;
93
93
  });
94
94
 
95
- // Team members scan atris/team/
95
+ // Team members, scan atris/team/
96
96
  const teamDir = path.join(atrisDir, 'team');
97
97
  if (fs.existsSync(teamDir)) {
98
98
  for (const name of fs.readdirSync(teamDir)) {
@@ -137,7 +137,7 @@ function buildSystemPrompt(ctx) {
137
137
  const lines = [];
138
138
 
139
139
  lines.push('# Atris Console');
140
- lines.push('You are running inside the Atris Console an AI workspace operating system.');
140
+ lines.push('You are running inside the Atris Console, an AI workspace operating system.');
141
141
  lines.push('');
142
142
 
143
143
  if (ctx.persona) {
@@ -293,7 +293,7 @@ function offerInstall(target, callback) {
293
293
 
294
294
  function checkAuth(backend) {
295
295
  if (backend === 'claude') {
296
- // Claude handles its own auth interactively always allow
296
+ // Claude handles its own auth interactively, always allow
297
297
  return true;
298
298
  }
299
299
  if (backend === 'codex') {
@@ -132,7 +132,7 @@ function decideCommand(args = []) {
132
132
  const decision = decisions[number - 1];
133
133
  if (!decision) return fail(`decision ${number} is not open`, asJson, 1);
134
134
 
135
- const message = `Decision on "${decision.text}": ${answer.toUpperCase()}${note ? ` ${note}` : ''}`;
135
+ const message = `Decision on "${decision.text}": ${answer.toUpperCase()}${note ? `, ${note}` : ''}`;
136
136
  pingMission([decision.mission_id, message, '--from', 'decide'], { silent: true });
137
137
  const mission = answerMissionHumanAsk(decision.mission_id, decision.ask_index, answer, note);
138
138
  const remainingOpenAsks = openHumanAsks(mission.human_asks).length;
package/commands/deck.js CHANGED
@@ -1,4 +1,4 @@
1
- // atris deck generate a premium, on-brand Google Slides deck from a plain
1
+ // atris deck: generate a premium, on-brand Google Slides deck from a plain
2
2
  // content spec, using the Atris deck engine (lib/slides-deck.js). The pitch:
3
3
  // describe the deck, get the design system for free. No Arial-on-white slop.
4
4
  //
@@ -171,7 +171,7 @@ function printLint(findings) {
171
171
  async function runReviewFlow({ presentationId, spec, specPath, json, auto = false }) {
172
172
  const tok = token();
173
173
  if (!tok) {
174
- console.error(' no credentials at ~/.atris/credentials.json run `atris login` and connect Google Drive.');
174
+ console.error(' no credentials at ~/.atris/credentials.json. run `atris login` and connect Google Drive.');
175
175
  return 1;
176
176
  }
177
177
  const { packet, manifestPath, outDir } = await reviewDeck({
@@ -278,7 +278,7 @@ async function videoToDeck({ analysisText, title, theme, style, url, api: apiFn,
278
278
  async function runBatch(specPaths, { themeOverride }) {
279
279
  const tok = token();
280
280
  if (!tok) {
281
- console.error(' no credentials at ~/.atris/credentials.json run `atris login` and connect Google Drive.');
281
+ console.error(' no credentials at ~/.atris/credentials.json. run `atris login` and connect Google Drive.');
282
282
  return 1;
283
283
  }
284
284
  let failures = 0;
@@ -456,7 +456,7 @@ async function run(argv) {
456
456
  }
457
457
  const tok = token();
458
458
  if (!tok) {
459
- console.error(' no credentials at ~/.atris/credentials.json run `atris login` and connect Google Drive.');
459
+ console.error(' no credentials at ~/.atris/credentials.json. run `atris login` and connect Google Drive.');
460
460
  return 1;
461
461
  }
462
462
  let analysisText;
@@ -484,7 +484,7 @@ async function run(argv) {
484
484
  token: tok,
485
485
  });
486
486
  if (!result.ok) {
487
- console.error('\n ✗ composed spec failed lint not building:');
487
+ console.error('\n ✗ composed spec failed lint, not building:');
488
488
  printLint(result.findings);
489
489
  return 1;
490
490
  }
@@ -521,7 +521,7 @@ async function run(argv) {
521
521
  const schemaFindings = validateSpec(spec);
522
522
  if (hasErrors(schemaFindings)) {
523
523
  printLint(schemaFindings);
524
- console.error('\n ✗ spec invalid fix the errors above before building\n');
524
+ console.error('\n ✗ spec invalid, fix the errors above before building\n');
525
525
  return 2;
526
526
  }
527
527
  const title = flag(argv, '--title') || `${(spec.brand && spec.brand.name) || 'Atris'} deck`;
@@ -532,14 +532,14 @@ async function run(argv) {
532
532
  const findings = lintSpec(spec);
533
533
  printLint(findings);
534
534
  if (findings.some((f) => f.severity === 'error')) {
535
- console.error('\n ✗ lint failed fix spec before building\n');
535
+ console.error('\n ✗ lint failed, fix spec before building\n');
536
536
  return 1;
537
537
  }
538
538
  }
539
539
 
540
540
  const tok = token();
541
541
  if (!tok) {
542
- console.error(' no credentials at ~/.atris/credentials.json run `atris login` and connect Google Drive.');
542
+ console.error(' no credentials at ~/.atris/credentials.json. run `atris login` and connect Google Drive.');
543
543
  return 1;
544
544
  }
545
545
 
@@ -556,7 +556,7 @@ async function run(argv) {
556
556
  }
557
557
 
558
558
  console.log(`
559
- atris deck premium Google Slides from a plain content spec
559
+ atris deck: premium Google Slides from a plain content spec
560
560
 
561
561
  atris deck sample [--theme paper] > my.json
562
562
  atris deck compose --md notes.md --out my.json [--style narrative]
package/commands/drive.js CHANGED
@@ -1,4 +1,4 @@
1
- // atris drive self-driving tick over the mission plane.
1
+ // atris drive: self-driving tick over the mission plane.
2
2
  // One tick: run mission doctor, auto-execute the fixes it prescribes that are
3
3
  // safe to run (stale ready receipts -> verify tick), and log everything that
4
4
  // still needs a human as an explicit disengagement. The metric that matters:
@@ -66,7 +66,7 @@ async function driveCommand(argv) {
66
66
  const history = loadHistory(cwd);
67
67
  if (!history.length) { console.log('No drive ticks yet. Run: atris drive'); return 0; }
68
68
  if (json) { console.log(JSON.stringify({ ok: true, ticks: history }, null, 2)); return 0; }
69
- console.log('drive disengagements per tick (goal: 0)\n');
69
+ console.log('drive: disengagements per tick (goal: 0)\n');
70
70
  for (const t of history) {
71
71
  console.log(` ${t.at} fixed ${t.fixed}/${t.findings} disengagements ${t.disengagements}`);
72
72
  }
@@ -86,7 +86,7 @@ async function driveCommand(argv) {
86
86
 
87
87
  // Missions the doctor says have no verifier. A verify-tick physically cannot
88
88
  // pass without one, so promising to verify-tick such a mission is a phantom
89
- // fix that never sticks count it as a wheel-grab instead.
89
+ // fix that never sticks, count it as a wheel-grab instead.
90
90
  const noVerifier = new Set(
91
91
  report.findings.filter((f) => f.code === 'missing_verifier' && f.mission_id).map((f) => f.mission_id),
92
92
  );
@@ -169,7 +169,7 @@ async function driveCommand(argv) {
169
169
 
170
170
  if (json) { console.log(JSON.stringify({ ok: true, ...record }, null, 2)); return 0; }
171
171
 
172
- console.log(`drive tick ${report.checked_count} missions checked, ${report.findings.length} findings`);
172
+ console.log(`drive tick: ${report.checked_count} missions checked, ${report.findings.length} findings`);
173
173
  console.log(` auto-fixed: ${fixed.length}`);
174
174
  for (const x of fixed) console.log(` ✓ ${x.action} ${x.mission_id}`);
175
175
  console.log(` disengagements: ${disengagements.length} (a human has to grab the wheel)`);