atris 3.53.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 (119) 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/x-search/SKILL.md +24 -22
  7. package/atris/skills/youtube/SKILL.md +82 -33
  8. package/atris/team/_template/SOUL.md +40 -0
  9. package/atris/team/validator/MEMBER.md +1 -2
  10. package/bin/atris +21 -0
  11. package/bin/atris.js +563 -373
  12. package/commands/api-key.js +170 -0
  13. package/commands/auth.js +453 -43
  14. package/commands/autoland.js +3 -1
  15. package/commands/autopilot-front.js +58 -11
  16. package/commands/avail.js +5 -4
  17. package/commands/balance.js +55 -0
  18. package/commands/bench.js +29 -1
  19. package/commands/brain.js +63 -12
  20. package/commands/brainstorm.js +18 -0
  21. package/commands/business.js +149 -1
  22. package/commands/chat-scan.js +17 -4
  23. package/commands/close.js +5 -1
  24. package/commands/doctor.js +174 -0
  25. package/commands/dream.js +7 -0
  26. package/commands/drill.js +34 -2
  27. package/commands/engine.js +47 -35
  28. package/commands/errors.js +58 -8
  29. package/commands/experiments.js +14 -0
  30. package/commands/feedback.js +61 -2
  31. package/commands/fleet-report.js +27 -7
  32. package/commands/fleet.js +98 -11
  33. package/commands/founder.js +60 -21
  34. package/commands/human-missions.js +79 -4
  35. package/commands/improve.js +54 -4
  36. package/commands/init.js +68 -92
  37. package/commands/install.js +40 -0
  38. package/commands/integrations.js +399 -30
  39. package/commands/interview.js +8 -0
  40. package/commands/land.js +48 -17
  41. package/commands/learn.js +29 -4
  42. package/commands/log.js +51 -0
  43. package/commands/member.js +68 -10
  44. package/commands/mission.js +287 -50
  45. package/commands/now.js +15 -3
  46. package/commands/orb.js +97 -2
  47. package/commands/pack.js +83 -9
  48. package/commands/playbook.js +381 -0
  49. package/commands/plugin.js +16 -0
  50. package/commands/radar.js +31 -7
  51. package/commands/recap.js +128 -21
  52. package/commands/release.js +102 -2
  53. package/commands/review.js +5 -10
  54. package/commands/revisions.js +55 -0
  55. package/commands/run-front.js +12 -4
  56. package/commands/scout.js +12 -1
  57. package/commands/search.js +123 -28
  58. package/commands/sign.js +2 -2
  59. package/commands/signup.js +12 -3
  60. package/commands/site-deploy.js +17 -4
  61. package/commands/site.js +2 -2
  62. package/commands/skill-eval.js +289 -0
  63. package/commands/skill.js +56 -6
  64. package/commands/social.js +603 -0
  65. package/commands/spaceship.js +69 -6
  66. package/commands/stream.js +8 -1
  67. package/commands/study.js +32 -19
  68. package/commands/sync.js +28 -22
  69. package/commands/task.js +418 -60
  70. package/commands/teach.js +72 -63
  71. package/commands/terminal.js +25 -9
  72. package/commands/topup.js +88 -0
  73. package/commands/truth.js +52 -6
  74. package/commands/usage.js +91 -0
  75. package/commands/verify.js +3 -2
  76. package/commands/version.js +3 -1
  77. package/commands/voice.js +5 -1
  78. package/commands/who.js +69 -11
  79. package/commands/wiki.js +7 -4
  80. package/commands/wish.js +76 -5
  81. package/commands/workflow.js +327 -145
  82. package/commands/worktree.js +1 -0
  83. package/commands/write.js +5 -0
  84. package/commands/x-search.js +340 -0
  85. package/commands/xp.js +5 -1
  86. package/commands/youtube.js +551 -25
  87. package/lib/account-bound.js +47 -0
  88. package/lib/auto-accept-certified.js +8 -1
  89. package/lib/auto-lessons.js +186 -0
  90. package/lib/autoland.js +4 -2
  91. package/lib/chat-log-scan.js +7 -4
  92. package/lib/cli-json.js +77 -0
  93. package/lib/cli-scope.js +26 -0
  94. package/lib/codex-flight.js +1 -0
  95. package/lib/conductor-artifacts.js +1 -1
  96. package/lib/context-gatherer.js +11 -0
  97. package/lib/developer-api.js +116 -0
  98. package/lib/feedback-triage.js +274 -0
  99. package/lib/first-minute.js +398 -0
  100. package/lib/fleet.js +115 -34
  101. package/lib/functional-owner.js +22 -0
  102. package/lib/known-commands.js +31 -5
  103. package/lib/member-scaffold.js +197 -0
  104. package/lib/mission-root.js +4 -2
  105. package/lib/noninteractive.js +88 -0
  106. package/lib/policy-lessons.js +4 -1
  107. package/lib/revision-metric.js +279 -0
  108. package/lib/scratch-root.js +48 -0
  109. package/lib/skill-eval-gate.js +249 -0
  110. package/lib/task-db.js +4 -0
  111. package/lib/task-proof.js +69 -8
  112. package/lib/verifier-quality.js +69 -0
  113. package/lib/wish-audit.js +2 -2
  114. package/lib/wish-delegate.js +10 -1
  115. package/lib/workspace-scaffold.js +270 -0
  116. package/package.json +3 -2
  117. package/scripts/det/checklist-score.js +191 -0
  118. package/scripts/det/ytsearch +31 -0
  119. package/utils/update-check.js +15 -0
@@ -1063,6 +1063,7 @@ module.exports = {
1063
1063
  deniedLaneForShip,
1064
1064
  createOrFindPr,
1065
1065
  cleanupWorktrees,
1066
+ defaultMainlineBase,
1066
1067
  defaultStartBase,
1067
1068
  describeFlightAge,
1068
1069
  flightStampMs,
package/commands/write.js CHANGED
@@ -23,6 +23,7 @@ const fs = require('fs');
23
23
  const path = require('path');
24
24
  const { spawnSync } = require('child_process');
25
25
  const { scanFile, RULES, loadProjectRules } = require('./slop');
26
+ const { isHelpToken } = require('../lib/noninteractive');
26
27
 
27
28
  const WRITING_DIR = path.join('atris', 'writing');
28
29
  // Beats are question-shaped (Pollan: "almost everything I write is a quest to
@@ -125,6 +126,10 @@ function syncStates(slug, root = process.cwd()) {
125
126
  }
126
127
 
127
128
  function start(argv, root = process.cwd()) {
129
+ if ((argv || []).some(isHelpToken)) {
130
+ console.error(' usage: atris write start "<topic>" [--dump "..."] [--beats "a | b | c"]');
131
+ return 2;
132
+ }
128
133
  const topic = argv.find((a) => !a.startsWith('-'));
129
134
  if (!topic) { console.error(' usage: atris write start "<topic>" [--dump "..."] [--beats "a | b | c"]'); return 2; }
130
135
  const flag = (name) => { const i = argv.indexOf(name); return i !== -1 ? argv[i + 1] : null; };
@@ -0,0 +1,340 @@
1
+ 'use strict';
2
+
3
+ const { apiRequestJson } = require('../utils/api');
4
+ const { ensureBilledCommandAuth } = require('./auth');
5
+
6
+ const DEFAULT_TIMEOUT_MS = 120000;
7
+ const COST_HINT = '5 credits per search';
8
+
9
+ function showXSearchHelp(output = console.log, commandName = 'atris x-search') {
10
+ output('');
11
+ output(`Usage: ${commandName} "<query>" [--limit N] [--days N] [--json]`);
12
+ output(` ${commandName} person --name <name> [--handle <h>] [--company <c>] [--context <text>] [--json]`);
13
+ output('');
14
+ output(`Search X/Twitter via Atris (${COST_HINT}).`);
15
+ output('Requires login. Same auth path as atris youtube process.');
16
+ output('');
17
+ output('Options:');
18
+ output(' --limit <n> Max results hint (search only)');
19
+ output(' --days <n> Only tweets from the last N days (search only)');
20
+ output(' --json Print the raw JSON response');
21
+ output(' -h, --help This help');
22
+ output('');
23
+ output('Person options:');
24
+ output(' --name <text> Person to research (required)');
25
+ output(' --handle <text> X handle without @');
26
+ output(' --company <text> Company or org');
27
+ output(' --context <text> Why you are researching them');
28
+ output('');
29
+ output('Examples:');
30
+ output(` ${commandName} "MCP agents"`);
31
+ output(` ${commandName} "MCP agents" --limit 5 --days 2`);
32
+ output(` ${commandName} person --name "Leah Bonvissuto" --handle leahbon`);
33
+ output('');
34
+ }
35
+
36
+ function readValue(args, index, name) {
37
+ if (index >= args.length - 1 || String(args[index + 1]).startsWith('--')) {
38
+ throw new Error(`${name} requires a value`);
39
+ }
40
+ return args[index + 1];
41
+ }
42
+
43
+ function parsePositiveInt(raw, name) {
44
+ const value = Number(raw);
45
+ if (!Number.isInteger(value) || value <= 0) {
46
+ throw new Error(`${name} must be a positive integer`);
47
+ }
48
+ return value;
49
+ }
50
+
51
+ function parseSearchArgs(argv = []) {
52
+ const args = [...argv];
53
+ const options = {
54
+ mode: 'search',
55
+ help: false,
56
+ json: false,
57
+ query: null,
58
+ limit: null,
59
+ daysBack: null,
60
+ timeoutMs: DEFAULT_TIMEOUT_MS,
61
+ };
62
+
63
+ if (args.length === 0 || ['help', '--help', '-h'].includes(args[0])) {
64
+ options.help = true;
65
+ return options;
66
+ }
67
+
68
+ for (let i = 0; i < args.length; i++) {
69
+ const arg = args[i];
70
+ if (arg === '--help' || arg === '-h' || arg === 'help') {
71
+ options.help = true;
72
+ } else if (arg === '--json') {
73
+ options.json = true;
74
+ } else if (arg === '--limit') {
75
+ options.limit = parsePositiveInt(readValue(args, i, arg), '--limit');
76
+ i++;
77
+ } else if (arg.startsWith('--limit=')) {
78
+ options.limit = parsePositiveInt(arg.slice('--limit='.length), '--limit');
79
+ } else if (arg === '--days' || arg === '--days-back' || arg === '--days_back') {
80
+ options.daysBack = parsePositiveInt(readValue(args, i, arg), '--days');
81
+ i++;
82
+ } else if (arg.startsWith('--days=')) {
83
+ options.daysBack = parsePositiveInt(arg.slice('--days='.length), '--days');
84
+ } else if (arg.startsWith('--days-back=') || arg.startsWith('--days_back=')) {
85
+ const raw = arg.includes('=') ? arg.slice(arg.indexOf('=') + 1) : '';
86
+ options.daysBack = parsePositiveInt(raw, '--days');
87
+ } else if (arg === '--timeout') {
88
+ const seconds = Number(readValue(args, i, arg));
89
+ if (!Number.isFinite(seconds) || seconds <= 0) {
90
+ throw new Error('--timeout must be a positive number of seconds');
91
+ }
92
+ options.timeoutMs = Math.round(seconds * 1000);
93
+ i++;
94
+ } else if (arg.startsWith('--timeout=')) {
95
+ const seconds = Number(arg.slice('--timeout='.length));
96
+ if (!Number.isFinite(seconds) || seconds <= 0) {
97
+ throw new Error('--timeout must be a positive number of seconds');
98
+ }
99
+ options.timeoutMs = Math.round(seconds * 1000);
100
+ } else if (arg.startsWith('-')) {
101
+ throw new Error(`Unknown option: ${arg}`);
102
+ } else if (!options.query) {
103
+ options.query = arg;
104
+ } else {
105
+ throw new Error(`Unexpected argument: ${arg}`);
106
+ }
107
+ }
108
+
109
+ if (options.help) return options;
110
+ if (!options.query) throw new Error('Missing query. Run "atris x-search --help".');
111
+ return options;
112
+ }
113
+
114
+ function parsePersonArgs(argv = []) {
115
+ const args = [...argv];
116
+ const options = {
117
+ mode: 'person',
118
+ help: false,
119
+ json: false,
120
+ name: null,
121
+ handle: null,
122
+ company: null,
123
+ context: null,
124
+ timeoutMs: DEFAULT_TIMEOUT_MS,
125
+ };
126
+
127
+ if (args.length === 0 || ['help', '--help', '-h'].includes(args[0])) {
128
+ options.help = true;
129
+ return options;
130
+ }
131
+
132
+ for (let i = 0; i < args.length; i++) {
133
+ const arg = args[i];
134
+ if (arg === '--help' || arg === '-h' || arg === 'help') {
135
+ options.help = true;
136
+ } else if (arg === '--json') {
137
+ options.json = true;
138
+ } else if (arg === '--name') {
139
+ options.name = readValue(args, i, arg);
140
+ i++;
141
+ } else if (arg.startsWith('--name=')) {
142
+ options.name = arg.slice('--name='.length);
143
+ } else if (arg === '--handle') {
144
+ options.handle = String(readValue(args, i, arg)).replace(/^@/, '');
145
+ i++;
146
+ } else if (arg.startsWith('--handle=')) {
147
+ options.handle = arg.slice('--handle='.length).replace(/^@/, '');
148
+ } else if (arg === '--company') {
149
+ options.company = readValue(args, i, arg);
150
+ i++;
151
+ } else if (arg.startsWith('--company=')) {
152
+ options.company = arg.slice('--company='.length);
153
+ } else if (arg === '--context') {
154
+ options.context = readValue(args, i, arg);
155
+ i++;
156
+ } else if (arg.startsWith('--context=')) {
157
+ options.context = arg.slice('--context='.length);
158
+ } else if (arg === '--timeout') {
159
+ const seconds = Number(readValue(args, i, arg));
160
+ if (!Number.isFinite(seconds) || seconds <= 0) {
161
+ throw new Error('--timeout must be a positive number of seconds');
162
+ }
163
+ options.timeoutMs = Math.round(seconds * 1000);
164
+ i++;
165
+ } else if (arg.startsWith('--timeout=')) {
166
+ const seconds = Number(arg.slice('--timeout='.length));
167
+ if (!Number.isFinite(seconds) || seconds <= 0) {
168
+ throw new Error('--timeout must be a positive number of seconds');
169
+ }
170
+ options.timeoutMs = Math.round(seconds * 1000);
171
+ } else if (arg.startsWith('-')) {
172
+ throw new Error(`Unknown option: ${arg}`);
173
+ } else {
174
+ throw new Error(`Unexpected argument: ${arg}`);
175
+ }
176
+ }
177
+
178
+ if (options.help) return options;
179
+ if (!options.name) throw new Error('Missing --name. Run "atris x-search person --help".');
180
+ return options;
181
+ }
182
+
183
+ function parseXSearchArgs(argv = []) {
184
+ const args = [...argv];
185
+ if (args[0] === 'person') {
186
+ return parsePersonArgs(args.slice(1));
187
+ }
188
+ return parseSearchArgs(args);
189
+ }
190
+
191
+ function buildSearchPayload(options) {
192
+ const payload = { query: options.query };
193
+ if (options.limit != null) payload.limit = options.limit;
194
+ if (options.daysBack != null) payload.days_back = options.daysBack;
195
+ return payload;
196
+ }
197
+
198
+ function buildPersonPayload(options) {
199
+ const payload = { name: options.name };
200
+ if (options.handle) payload.handle = options.handle;
201
+ if (options.company) payload.company = options.company;
202
+ if (options.context) payload.context = options.context;
203
+ return payload;
204
+ }
205
+
206
+ function resultErrorText(result) {
207
+ const raw = result?.error || result?.text || 'unknown error';
208
+ if (typeof raw === 'string') return raw;
209
+ try {
210
+ return JSON.stringify(raw);
211
+ } catch {
212
+ return String(raw);
213
+ }
214
+ }
215
+
216
+ function xSearchFailureError(result) {
217
+ const hint = result.status === 401
218
+ ? ' Run "atris login --force".'
219
+ : result.status === 402
220
+ ? ' Check Atris credits.'
221
+ : result.status === 502
222
+ ? ' xAI is unavailable; retry in a few seconds.'
223
+ : '';
224
+ return new Error(`X search failed (${result.status}): ${resultErrorText(result)}.${hint}`);
225
+ }
226
+
227
+ async function ensureToken(deps = {}) {
228
+ const ensureBilled = deps.ensureBilledCommandAuth || ensureBilledCommandAuth;
229
+ const auth = await ensureBilled('x-search', deps);
230
+ if (!auth?.ok || !auth.token) {
231
+ throw new Error(auth?.error || 'not signed in. run atris login first.');
232
+ }
233
+ return auth;
234
+ }
235
+
236
+ async function runXSearch(options, deps = {}) {
237
+ const apiFn = deps.apiRequestJson || apiRequestJson;
238
+ let auth = await ensureToken(deps);
239
+ const pathname = options.mode === 'person' ? '/x-search/research-person' : '/x-search/search';
240
+ const body = options.mode === 'person' ? buildPersonPayload(options) : buildSearchPayload(options);
241
+
242
+ const call = (token) => apiFn(pathname, {
243
+ method: 'POST',
244
+ token,
245
+ timeoutMs: options.timeoutMs,
246
+ retries: 0,
247
+ body,
248
+ });
249
+
250
+ let result = await call(auth.token);
251
+ if (!result.ok && result.status === 401 && !auth.minted) {
252
+ const remint = await (deps.ensureBilledCommandAuth || ensureBilledCommandAuth)('x-search', {
253
+ ...deps,
254
+ forceMint: true,
255
+ });
256
+ if (remint?.ok && remint.token) {
257
+ auth = remint;
258
+ result = await call(auth.token);
259
+ }
260
+ }
261
+
262
+ if (!result.ok) {
263
+ throw xSearchFailureError(result);
264
+ }
265
+ return result.data;
266
+ }
267
+
268
+ function formatXSearchResult(data) {
269
+ const lines = [];
270
+ const payload = data?.data && typeof data.data === 'object' ? data.data : data;
271
+ const content = payload?.content != null ? String(payload.content).trim() : '';
272
+ const citations = Array.isArray(payload?.citations)
273
+ ? payload.citations
274
+ : (Array.isArray(data?.citations) ? data.citations : []);
275
+
276
+ if (content) {
277
+ lines.push(content);
278
+ } else if (data?.message) {
279
+ lines.push(String(data.message).trim());
280
+ } else {
281
+ lines.push('X search completed');
282
+ }
283
+
284
+ if (citations.length) {
285
+ lines.push('');
286
+ lines.push('Citations:');
287
+ for (const cite of citations) {
288
+ lines.push(` ${cite}`);
289
+ }
290
+ }
291
+
292
+ const used = data?.credits_used !== undefined ? data.credits_used : payload?.credits_used;
293
+ const remaining = data?.credits_remaining !== undefined
294
+ ? data.credits_remaining
295
+ : payload?.credits_remaining;
296
+ if (used !== undefined || remaining !== undefined) {
297
+ lines.push('');
298
+ lines.push(`Credits: ${used !== undefined ? used : '?'} used, ${remaining !== undefined ? remaining : '?'} remaining`);
299
+ }
300
+
301
+ return lines.join('\n');
302
+ }
303
+
304
+ async function xSearchCommand(argv = process.argv.slice(3), deps = {}) {
305
+ const output = deps.output || ((line = '') => console.log(line));
306
+ let options;
307
+ try {
308
+ options = parseXSearchArgs(argv);
309
+ } catch (err) {
310
+ output(err.message);
311
+ return 2;
312
+ }
313
+
314
+ if (options.help) {
315
+ showXSearchHelp(output, deps.commandName || 'atris x-search');
316
+ return 0;
317
+ }
318
+
319
+ let status = 0;
320
+ try {
321
+ const data = await runXSearch(options, deps);
322
+ output(options.json ? JSON.stringify(data, null, 2) : formatXSearchResult(data));
323
+ } catch (err) {
324
+ output(err.message);
325
+ status = 1;
326
+ }
327
+ if (!deps.output && !deps.apiRequestJson && !deps.ensureValidCredentials && !deps.ensureBilledCommandAuth) {
328
+ process.exit(status);
329
+ }
330
+ return status;
331
+ }
332
+
333
+ module.exports = {
334
+ DEFAULT_TIMEOUT_MS,
335
+ parseXSearchArgs,
336
+ buildSearchPayload,
337
+ buildPersonPayload,
338
+ formatXSearchResult,
339
+ xSearchCommand,
340
+ };
package/commands/xp.js CHANGED
@@ -112,6 +112,7 @@ function showHelp() {
112
112
  console.log(' atris xp [--json] [--local] [--workspace <path>] [--operator <name>]');
113
113
  console.log('');
114
114
  console.log('Show your AgentXP graph for the active Atris account.');
115
+ console.log('With no bound business (.atris/business.json), defaults to --local workspace receipts.');
115
116
  console.log('Use status to show account-level AgentXP across verified local ledgers.');
116
117
  console.log('Use collect or status --local to project accepted task proof in the current workspace.');
117
118
  console.log('Use session to encapsulate the current work window into a local XP capsule.');
@@ -2327,7 +2328,10 @@ async function xpCommand(...args) {
2327
2328
  }
2328
2329
 
2329
2330
  const jsonMode = args.includes('--json');
2330
- const localMode = hasFlagOrValue(args, '--local') || hasFlagOrValue(args, '--workspace') || hasFlagOrValue(args, '--operator');
2331
+ const explicitLocal = hasFlagOrValue(args, '--local') || hasFlagOrValue(args, '--workspace') || hasFlagOrValue(args, '--operator');
2332
+ // No bound business means cloud graph has nothing useful; default to local receipts.
2333
+ const boundBusiness = publicWorkspaceBinding(defaultXpWorkspace());
2334
+ const localMode = explicitLocal || !boundBusiness;
2331
2335
  if (localMode) {
2332
2336
  let payload;
2333
2337
  try {