atris 3.74.0 → 3.74.2

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 (59) hide show
  1. package/bin/atris.js +85 -82
  2. package/commands/aeo.js +2 -2
  3. package/commands/align.js +10 -19
  4. package/commands/auth.js +1 -1
  5. package/commands/autopilot.js +9 -10
  6. package/commands/avail.js +36 -7
  7. package/commands/clean.js +2 -1
  8. package/commands/close.js +7 -4
  9. package/commands/computer.js +3 -1
  10. package/commands/console.js +1 -1
  11. package/commands/context-sync.js +1 -60
  12. package/commands/experiments.js +4 -1
  13. package/commands/fleet.js +0 -1
  14. package/commands/improve.js +3 -1
  15. package/commands/interview.js +13 -5
  16. package/commands/land.js +5 -1
  17. package/commands/lifecycle.js +17 -6
  18. package/commands/log-sync.js +1 -1
  19. package/commands/loops.js +5 -2
  20. package/commands/member.js +17 -11
  21. package/commands/mission.js +1 -4
  22. package/commands/now.js +0 -7
  23. package/commands/play.js +3 -1
  24. package/commands/plugin.js +1 -1
  25. package/commands/pull.js +5 -3
  26. package/commands/push.js +0 -1
  27. package/commands/radar.js +0 -4
  28. package/commands/recap.js +25 -1
  29. package/commands/report.js +0 -4
  30. package/commands/review.js +1 -1
  31. package/commands/security-review.js +4 -1
  32. package/commands/setup.js +6 -2
  33. package/commands/soul.js +2 -1
  34. package/commands/sync.js +8 -2
  35. package/commands/task.js +0 -522
  36. package/commands/terminal.js +1 -1
  37. package/commands/x-search.js +5 -3
  38. package/commands/youtube.js +9 -7
  39. package/commands/zen.js +4 -4
  40. package/lib/agent-today.js +412 -0
  41. package/lib/apply-gate.js +5 -3
  42. package/lib/autoland.js +0 -8
  43. package/lib/bench/runner.js +0 -4
  44. package/lib/chat-log-scan.js +0 -28
  45. package/lib/cli-scope.js +4 -2
  46. package/lib/engine-registry.js +0 -4
  47. package/lib/experiments/daily.js +2 -1
  48. package/lib/file-ops.js +6 -1
  49. package/lib/first-minute.js +2 -0
  50. package/lib/gm-bet.js +73 -9
  51. package/lib/gm-phone-page.js +42 -5
  52. package/lib/gm-phone.js +3 -0
  53. package/lib/local-day.js +10 -0
  54. package/lib/manifest.js +0 -10
  55. package/lib/member-switches.js +0 -11
  56. package/lib/review-integrity.js +0 -4
  57. package/lib/scorecard.js +7 -6
  58. package/lib/wiki.js +4 -1
  59. package/package.json +1 -1
package/commands/play.js CHANGED
@@ -6,6 +6,7 @@ const fs = require('fs');
6
6
  const { spawnSync } = require('child_process');
7
7
  const { getSessionProfile, loadCredentials } = require('../utils/auth');
8
8
  const { hasFlag: hasExactFlag } = require('../lib/arg-parser');
9
+ const { localDay } = require('../lib/local-day');
9
10
 
10
11
  const AGENTXP_LEADERBOARD_URL = 'https://api.atris.ai/api/agentxp/leaderboard';
11
12
  const AGENTXP_GLOBAL_SYNC_RULE = 'Run atris login, then sync. Owner-provided sync tokens are guided-demo fallback only.';
@@ -298,7 +299,7 @@ function ensureStarterMission(taskDb, db, workspaceRoot, player, tasks, args = [
298
299
  assigned_to: player,
299
300
  delegate_via: 'agentxp_play',
300
301
  auto_seeded_by: 'atris play',
301
- created_for_day: new Date().toISOString().slice(0, 10),
302
+ created_for_day: localDay(),
302
303
  },
303
304
  });
304
305
  taskDb.noteTask(db, {
@@ -487,4 +488,5 @@ async function playCommand(...args) {
487
488
 
488
489
  module.exports = {
489
490
  playCommand,
491
+ ensureStarterMission,
490
492
  };
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
4
  const { execSync } = require('child_process');
5
- const { findAllSkills, parseFrontmatter } = require('./skill');
5
+ const { findAllSkills } = require('./skill');
6
6
 
7
7
  // --- Recursive Copy Helper ---
8
8
 
package/commands/pull.js CHANGED
@@ -7,7 +7,7 @@ const { loadConfig } = require('../utils/config');
7
7
  const { getLogPath } = require('../lib/file-ops');
8
8
  const { parseJournalSections, mergeSections, reconstructJournal } = require('../lib/journal');
9
9
  const { loadBusinesses, businessMatchesSlug } = require('./business');
10
- const { loadManifest, saveManifest, computeFileHash, buildManifest, computeLocalHashes, threeWayCompare, isIgnoredSyncPath } = require('../lib/manifest');
10
+ const { loadManifest, saveManifest, buildManifest, computeLocalHashes, threeWayCompare, isIgnoredSyncPath } = require('../lib/manifest');
11
11
  const { normalizeWikiOnlyPrefix } = require('../lib/wiki');
12
12
  const { emitSyncEvent, startTimer } = require('../lib/sync-telemetry');
13
13
  const { resolveSafeOutputDir } = require('../lib/workspace-safety');
@@ -1023,7 +1023,9 @@ async function pullGeneralJournal(token, agentId) {
1023
1023
  for (let i = 0; i < 3; i++) {
1024
1024
  const d = new Date(today);
1025
1025
  d.setDate(d.getDate() - i);
1026
- dates.push(d.toISOString().split('T')[0]);
1026
+ // Local calendar day, the same day log sync files the journal under.
1027
+ // toISOString() is the UTC day, already tomorrow in the evening here.
1028
+ dates.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`);
1027
1029
  }
1028
1030
 
1029
1031
  let synced = 0;
@@ -1118,4 +1120,4 @@ async function pullMemberJournal(token, agentId, memberName, memberDir) {
1118
1120
  return synced;
1119
1121
  }
1120
1122
 
1121
- module.exports = { buildPullConflictReviewPacket, mergeSmartPullFiles, normalizePullFilePath, pullAtris };
1123
+ module.exports = { buildPullConflictReviewPacket, mergeSmartPullFiles, normalizePullFilePath, pullAtris, pullGeneralJournal };
package/commands/push.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const crypto = require('crypto');
4
3
  const readline = require('readline');
5
4
  const { loadCredentials, abortOnAuthFailure } = require('../utils/auth');
6
5
  const { apiRequestJson } = require('../utils/api');
package/commands/radar.js CHANGED
@@ -685,10 +685,6 @@ function taskBinding(source, scope = null) {
685
685
  return { task_source: source, task_scope: scope };
686
686
  }
687
687
 
688
- function taskBindingForProjection(task) {
689
- return task ? taskBinding('repo_task_projection', 'repo') : taskBinding(null, null);
690
- }
691
-
692
688
  function taskSourceLabel(sources = []) {
693
689
  if (sources.includes('member_loop_lock')) return 'member loop lock';
694
690
  if (sources.includes('mission_lock')) return 'mission lock';
package/commands/recap.js CHANGED
@@ -13,6 +13,7 @@ const {
13
13
  taskCommand,
14
14
  } = require('../lib/first-minute');
15
15
  const { isRealTestRunnerProof, quoteVerifierCommand } = require('../lib/verifier-quality');
16
+ const { buildAgentToday, renderAgentToday, hasActivity, ranAgent } = require('../lib/agent-today');
16
17
 
17
18
  const DAY_MS = 24 * 60 * 60 * 1000;
18
19
  const DEFAULT_DAYS = 7;
@@ -38,7 +39,8 @@ function readProjection(root) {
38
39
 
39
40
  function loadTasks(root) {
40
41
  const taskDb = loadTaskDb();
41
- if (taskDb) {
42
+ // Reading never creates the db: a first run before any setup writes nothing.
43
+ if (taskDb && fs.existsSync(taskDb.getDbPath())) {
42
44
  try {
43
45
  const db = taskDb.open();
44
46
  const ws = taskDb.workspaceRoot(root);
@@ -335,11 +337,14 @@ function printRecapHelp() {
335
337
  atris recap - what got done, in spoken lines
336
338
 
337
339
  atris recap a few spoken lines: waiting for your ok, still being checked
340
+ atris recap today what your ai coding agent did in this folder today
338
341
  atris recap --verbose the old report
339
342
  atris recap --days 30 widen the window
340
343
  atris recap --share paste-ready summary for Slack, email, or a customer
341
344
  atris recap --json structured output for agents and dashboards
342
345
 
346
+ in a folder with no atris setup, recap shows today by default.
347
+ today reads claude code and codex logs on this computer plus git. it sends nothing.
343
348
  certified work names atris task accept. uncertified stays still being checked.
344
349
  use --verbose or --share for the old report.
345
350
  `);
@@ -351,6 +356,11 @@ function recapAtris(args = []) {
351
356
  return;
352
357
  }
353
358
  const cwd = process.cwd();
359
+ if (args[0] === 'today') {
360
+ const today = buildAgentToday({ cwd });
361
+ console.log(args.includes('--json') ? JSON.stringify(today, null, 2) : renderAgentToday(today));
362
+ return;
363
+ }
354
364
  const taskDb = loadTaskDb();
355
365
  let root = cwd;
356
366
  try {
@@ -370,6 +380,20 @@ function recapAtris(args = []) {
370
380
  const daysIdx = args.indexOf('--days');
371
381
  const days = daysIdx !== -1 ? Number(args[daysIdx + 1]) : DEFAULT_DAYS;
372
382
  const data = buildRecapData(root, { days });
383
+ // Before any setup, or when the board has nothing to say, the useful
384
+ // first minute is what your ai agent already did in this folder today.
385
+ const boardQuiet = data.empty
386
+ || ['shipped', 'waiting', 'checking', 'inProgress'].every((k) => !(data[k] || []).length);
387
+ if (boardQuiet && !args.includes('--verbose') && !args.includes('--full') && !args.includes('--share')) {
388
+ const today = buildAgentToday({ cwd });
389
+ // A brand new folder already names its last commit in the first
390
+ // minute, so commits alone keep that; an ai session here wins.
391
+ const fresh = data.empty && isFreshWorkspace(root) && !inProjectSubdir;
392
+ if (hasActivity(today) && (ranAgent(today) || !fresh)) {
393
+ console.log(args.includes('--json') ? JSON.stringify(today, null, 2) : renderAgentToday(today));
394
+ return;
395
+ }
396
+ }
373
397
  if (
374
398
  data.empty
375
399
  && isFreshWorkspace(root)
@@ -110,10 +110,6 @@ function buildDoneTasks(root, cutoff) {
110
110
  });
111
111
  }
112
112
 
113
- function buildLandings(root, cutoff) {
114
- return buildDoneTasks(root, cutoff).filter(task => task.landed);
115
- }
116
-
117
113
  function landingStatusText(task) {
118
114
  const status = String(task?.landing_status || 'unchecked').replace(/_/g, ' ');
119
115
  const reason = String(task?.landing_reason || '').replace(/_/g, ' ');
@@ -9,7 +9,7 @@
9
9
 
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
- const { execSync, spawnSync } = require('child_process');
12
+ const { spawnSync } = require('child_process');
13
13
 
14
14
  function findReviewEngine() {
15
15
  // Look for review_engine.py in common locations
@@ -227,7 +227,10 @@ function securityReviewCommand(argv = []) {
227
227
  // The landing: short, true, decision-ready. What you read after the overnight
228
228
  // loop, the opposite of a finding dump.
229
229
  function renderLanding(landing, threshold) {
230
- const date = new Date().toISOString().slice(0, 10);
230
+ // Local calendar day; toISOString is UTC and dates an evening run
231
+ // tomorrow anywhere west of Greenwich.
232
+ const now = new Date();
233
+ const date = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
231
234
  const L = ['', ` ✈ security landing, ${date}`, ''];
232
235
  if (landing.cleared) {
233
236
  L.push(` CLEARED TO SHIP no unresolved findings at the ${threshold.toUpperCase()} line`);
package/commands/setup.js CHANGED
@@ -1,5 +1,3 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
1
  const { loadCredentials, promptUser } = require('../utils/auth');
4
2
  const { apiRequestJson } = require('../utils/api');
5
3
 
@@ -73,6 +71,12 @@ async function setupAtris() {
73
71
  token: creds.token,
74
72
  });
75
73
 
74
+ if (!result.ok && result.status === 401) {
75
+ console.error('\n Your saved login has expired, so Atris could not list your businesses.');
76
+ console.error(' Run "atris login", then "atris setup" again.');
77
+ process.exit(1);
78
+ }
79
+
76
80
  if (!result.ok) {
77
81
  console.error(`\n Could not fetch businesses: ${result.error || 'Unknown error'}`);
78
82
  console.error(' You can add one later with: atris business add <slug>');
package/commands/soul.js CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  const fs = require('fs');
14
14
  const path = require('path');
15
+ const { localDay } = require('../lib/local-day');
15
16
 
16
17
  function findAtrisDir() {
17
18
  let dir = process.cwd();
@@ -272,7 +273,7 @@ function distillSoul(atrisDir) {
272
273
 
273
274
  // Append distilled section to persona
274
275
  const separator = '\n\n---\n\n';
275
- const distilledBlock = `<!-- Distilled ${new Date().toISOString().slice(0, 10)} | ${journalCount} journal entries, ${lessonItems.length} lessons, ${policyRules.length} policy rules -->\n\n` + distilled.join('\n');
276
+ const distilledBlock = `<!-- Distilled ${localDay()} | ${journalCount} journal entries, ${lessonItems.length} lessons, ${policyRules.length} policy rules -->\n\n` + distilled.join('\n');
276
277
 
277
278
  if (persona) {
278
279
  // Check if already has a distilled section, replace it
package/commands/sync.js CHANGED
@@ -43,6 +43,12 @@ function _walkTemplateDir(dir, base = dir) {
43
43
  return out;
44
44
  }
45
45
 
46
+ // Local calendar day (YYYY-MM-DD). toISOString() is the UTC day, which is
47
+ // already tomorrow in the evening anywhere west of Greenwich.
48
+ function localDay(date = new Date()) {
49
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
50
+ }
51
+
46
52
  /**
47
53
  * Substitute workspace metadata in template content.
48
54
  */
@@ -53,7 +59,7 @@ function _substituteParams(content, params) {
53
59
  .replace(/\{\{owner_email\}\}/g, params.owner_email || '')
54
60
  .replace(/\{\{business_id\}\}/g, params.business_id || '')
55
61
  .replace(/\{\{workspace_id\}\}/g, params.workspace_id || '')
56
- .replace(/\{\{today\}\}/g, params.today || new Date().toISOString().slice(0, 10))
62
+ .replace(/\{\{today\}\}/g, params.today || localDay())
57
63
  .replace(/\{\{workspace_template\}\}/g, params.workspace_template || 'business');
58
64
  }
59
65
 
@@ -337,7 +343,7 @@ function syncWorkspaceTemplate(targetRoot, bizMeta, options = {}) {
337
343
  owner_email: bizMeta.owner_email || '',
338
344
  business_id: bizMeta.business_id || '',
339
345
  workspace_id: bizMeta.workspace_id || '',
340
- today: new Date().toISOString().slice(0, 10),
346
+ today: localDay(),
341
347
  workspace_template: template.key,
342
348
  };
343
349
  const force = options.force != null ? options.force : process.argv.includes('--force');