atris 3.43.0 → 3.44.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 (43) hide show
  1. package/atris/skills/design/SKILL.md +7 -1
  2. package/atris/skills/engines/SKILL.md +44 -13
  3. package/atris/team/customer-lead/MEMBER.md +45 -0
  4. package/atris/team/customer-lead/SOUL.md +33 -0
  5. package/atris/team/customer-lead/START_HERE.md +7 -0
  6. package/atris/team/customer-lead/skills/customer-commitments/SKILL.md +45 -0
  7. package/atris/team/improver/MEMBER.md +33 -0
  8. package/bin/atris.js +36 -3
  9. package/commands/autoland.js +15 -1
  10. package/commands/caretaker.js +303 -0
  11. package/commands/clean.js +76 -0
  12. package/commands/engine-watch.js +212 -0
  13. package/commands/engine.js +99 -11
  14. package/commands/founder.js +304 -0
  15. package/commands/human-missions.js +844 -0
  16. package/commands/init.js +16 -7
  17. package/commands/mission.js +124 -69
  18. package/commands/slop.js +34 -3
  19. package/commands/task.js +51 -4
  20. package/commands/team.js +329 -13
  21. package/commands/verify.js +99 -6
  22. package/commands/worktree.js +119 -4
  23. package/lib/auto-accept-certified.js +302 -0
  24. package/lib/cloud-mission.js +59 -2
  25. package/lib/conductor-artifacts.js +1 -1
  26. package/lib/dispatch-scout.js +383 -0
  27. package/lib/engine-ask.js +645 -0
  28. package/lib/engine-job-lifecycle.js +65 -0
  29. package/lib/engine-receipt-sweep.js +98 -0
  30. package/lib/engine-registry.js +2 -2
  31. package/lib/engine-validate.js +374 -0
  32. package/lib/fleet.js +459 -106
  33. package/lib/known-commands.js +2 -2
  34. package/lib/member-alive.js +2 -2
  35. package/lib/policy-lessons.js +70 -0
  36. package/lib/receipt-evidence.js +56 -1
  37. package/lib/runner-command.js +1 -1
  38. package/lib/secret-gateway.js +588 -0
  39. package/lib/team-presence.js +13 -1
  40. package/lib/voice-gate.js +6 -0
  41. package/lib/wish-audit.js +5 -205
  42. package/lib/wish-delegate.js +5 -2
  43. package/package.json +6 -1
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const knownCommands = ['init', 'log', 'logs', 'wish', 'drill', 'dream', 'now', 'goal', 'wtf', 'orb', 'radar', 'stream', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
3
+ const knownCommands = ['init', 'log', 'logs', 'wish', 'ask', 'approve', 'stop', 'ready', 'check', 'drill', 'dream', 'now', 'goal', 'wtf', 'founder', 'orb', 'radar', 'stream', 'ctop', 'launchpad', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', '_start', 'plan', 'do', 'review', 'release',
4
4
  'activate', '_activate', 'agent', 'team', 'chat', 'fast', 'ax', 'console', 'serve', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
5
5
  'clean', 'close', 'harvest', 'verify', 'recover', 'search', 'scout', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'taste', 'teach', 'plugin', 'experiments', 'bench', 'router', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'watch', 'cloud', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
6
- 'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'decide', 'agents', 'probe', 'worktree', 'land', 'autoland', 'drive', 'aeo', 'slop', 'voice', 'strings', 'write', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'game', 'x', 'recap', 'report', 'signup', 'clarity', 'interview', 'meet', 'moves', 'unknowns', 'avail', 'sync-checkout',
6
+ 'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'decide', 'agents', 'probe', 'worktree', 'land', 'caretaker', 'autoland', 'drive', 'aeo', 'slop', 'voice', 'strings', 'write', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'study', 'rainmaker', 'xp', 'play', 'gm', 'game', 'x', 'recap', 'report', 'signup', 'clarity', 'interview', 'meet', 'moves', 'unknowns', 'avail', 'sync-checkout',
7
7
  'github', 'vercel', 'supabase', 'linear', 'stripe', 'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
8
8
  'fork', 'browse', 'publish', 'pack', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'fleet-report', 'loops', 'self-improve', 'compile', 'spaceship', 'truth', 'sign', 'engine', 'engines', 'feed', 'brief'];
9
9
 
@@ -84,7 +84,7 @@ function runMemberOperateScript(scriptPath, member, opts) {
84
84
  args.push('--execute');
85
85
  if (opts.confirmed) args.push('--confirm-autonomy-policy');
86
86
  }
87
- if (opts.agent === 'claude') args.push('--agent', 'claude');
87
+ if (opts.agent) args.push('--agent', String(opts.agent));
88
88
  if (opts.model) args.push('--model', String(opts.model));
89
89
  if (opts.noPrime) args.push('--no-prime');
90
90
  // Inherit stderr so member-operate progress lines reach the parent alive/loop process live.
@@ -194,7 +194,7 @@ function runAliveTick(name, opts = {}) {
194
194
  execute: true,
195
195
  confirmed: true,
196
196
  maxWallSeconds: opts.maxWallSeconds,
197
- agent: opts.agent || 'codex',
197
+ agent: opts.agent || null,
198
198
  model: opts.model || null,
199
199
  noPrime: true,
200
200
  });
@@ -16,6 +16,7 @@ const POLICY_LESSONS_FILE = path.join('.atris', 'state', 'policy_lessons.json');
16
16
  const CAREER_XP_RECEIPTS_FILE = path.join('.atris', 'state', 'career_xp_receipts.jsonl');
17
17
  const TASK_EPISODES_FILE = path.join('.atris', 'state', 'task_episodes.jsonl');
18
18
  const SCORECARDS_FILE = path.join('.atris', 'state', 'scorecards.jsonl');
19
+ const TYPED_LESSONS_FILE = path.join('atris', 'lessons.json');
19
20
  const DAY_MS = 24 * 60 * 60 * 1000;
20
21
 
21
22
  // Review actors that are agents, not the human gate. Mining must split the
@@ -266,6 +267,74 @@ function policyHintsForProof(proofText, mined, root = process.cwd()) {
266
267
  return hints;
267
268
  }
268
269
 
270
+ function normalizeLessonPath(value) {
271
+ return String(value || '')
272
+ .trim()
273
+ .replace(/\\/g, '/')
274
+ .replace(/^\.\//, '')
275
+ .replace(/\/{2,}/g, '/')
276
+ .replace(/\/$/, '');
277
+ }
278
+
279
+ function lessonPathOverlaps(left, right) {
280
+ const lessonPath = normalizeLessonPath(left).toLowerCase();
281
+ const candidatePath = normalizeLessonPath(right).toLowerCase();
282
+ if (!lessonPath || !candidatePath) return false;
283
+ return lessonPath === candidatePath
284
+ || lessonPath.startsWith(`${candidatePath}/`)
285
+ || candidatePath.startsWith(`${lessonPath}/`);
286
+ }
287
+
288
+ function readTypedPolicyLessons(root) {
289
+ try {
290
+ const parsed = JSON.parse(fs.readFileSync(path.join(root, TYPED_LESSONS_FILE), 'utf8'));
291
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return [];
292
+ return Object.entries(parsed)
293
+ .filter(([id, lesson]) => id !== '_schema' && lesson && typeof lesson === 'object')
294
+ .map(([id, lesson]) => ({ id, ...lesson, source: 'typed_lessons' }));
295
+ } catch {
296
+ return [];
297
+ }
298
+ }
299
+
300
+ // A lesson is relevant to a landing only when its declared file scope overlaps
301
+ // the candidate's exact paths. Repo-wide or prose-only lessons remain advice,
302
+ // because running them as global blockers would make old debt stop new work.
303
+ function policyLessonsForFiles(files, mined, root = process.cwd()) {
304
+ const candidatePaths = (Array.isArray(files) ? files : [files])
305
+ .map(normalizeLessonPath)
306
+ .filter(Boolean);
307
+ if (!candidatePaths.length) return [];
308
+ const minedLessons = mined && Array.isArray(mined.lessons)
309
+ ? mined.lessons.map((lesson) => ({ ...lesson, source: 'mined_policy' }))
310
+ : [];
311
+ // The typed sidecar is the promoted source. If a mined advisory later uses
312
+ // the same id, the promoted detector and file scope must win.
313
+ const combined = [...readTypedPolicyLessons(root), ...minedLessons];
314
+ const matches = [];
315
+ const seen = new Set();
316
+ for (const lesson of combined) {
317
+ const id = String(lesson && lesson.id || '').trim();
318
+ if (!id || seen.has(id)) continue;
319
+ const appliesTo = Array.isArray(lesson.applies_to)
320
+ ? lesson.applies_to
321
+ : (Array.isArray(lesson.paths) ? lesson.paths : []);
322
+ const matchedPath = appliesTo.find((lessonPath) =>
323
+ candidatePaths.some((candidatePath) => lessonPathOverlaps(lessonPath, candidatePath)));
324
+ if (!matchedPath) continue;
325
+ seen.add(id);
326
+ matches.push({
327
+ id,
328
+ detector: typeof lesson.detector === 'string' ? lesson.detector.trim() : '',
329
+ lesson: String(lesson.lesson || lesson.text || '').trim(),
330
+ status: lesson.status || null,
331
+ source: lesson.source,
332
+ matched_path: normalizeLessonPath(matchedPath),
333
+ });
334
+ }
335
+ return matches;
336
+ }
337
+
269
338
  function policyLessonsPath(root) {
270
339
  return path.join(root, POLICY_LESSONS_FILE);
271
340
  }
@@ -324,6 +393,7 @@ module.exports = {
324
393
  loadHistory,
325
394
  mineProofPolicy,
326
395
  policyHintsForProof,
396
+ policyLessonsForFiles,
327
397
  readPolicyLessons,
328
398
  writePolicyLessons,
329
399
  syncLessonsMd,
@@ -122,4 +122,59 @@ function extractReceiptEvidence(proofText, root = process.cwd()) {
122
122
  };
123
123
  }
124
124
 
125
- module.exports = { extractReceiptEvidence, receiptVerifierPassed, RECEIPT_PATH_PATTERN };
125
+ // Resume short-circuit: when a tick already wrote its receipt but the mission
126
+ // record never advanced (interrupt between writeReceipt and saveMission), the
127
+ // next run would re-derive the same tick_index. Look up that completed receipt
128
+ // and reuse it instead of re-running the step.
129
+ function findCachedMissionStepReceipt(root, { missionId, tickIndex } = {}) {
130
+ const id = String(missionId || '').trim();
131
+ const idx = Number(tickIndex);
132
+ if (!id || !Number.isInteger(idx) || idx < 1) return null;
133
+
134
+ const runsDir = path.resolve(root, 'atris', 'runs');
135
+ let names;
136
+ try {
137
+ names = fs.readdirSync(runsDir).filter((name) => name.startsWith('mission-') && name.endsWith('.json'));
138
+ } catch {
139
+ return null;
140
+ }
141
+
142
+ let best = null;
143
+ for (const name of names) {
144
+ let parsed = null;
145
+ try {
146
+ parsed = JSON.parse(fs.readFileSync(path.join(runsDir, name), 'utf8'));
147
+ } catch {
148
+ continue;
149
+ }
150
+ if (!parsed || parsed.mission_id !== id) continue;
151
+ const tick = parsed.result && parsed.result.tick;
152
+ if (!tick || Number(tick.tick_index) !== idx) continue;
153
+ // Only completed successful steps are safe to skip. Failed ticks stay
154
+ // eligible for a fresh attempt on resume.
155
+ if (tick.status !== 'ran') continue;
156
+ const atMs = Date.parse(tick.finished_at || parsed.at || '') || 0;
157
+ if (best && atMs < best.atMs) continue;
158
+ best = {
159
+ atMs,
160
+ receipt_path: path.join('atris', 'runs', name),
161
+ receipt: parsed,
162
+ tick,
163
+ verifier_result: parsed.result.verifier_result || null,
164
+ };
165
+ }
166
+ if (!best) return null;
167
+ return {
168
+ receipt_path: best.receipt_path,
169
+ receipt: best.receipt,
170
+ tick: best.tick,
171
+ verifier_result: best.verifier_result,
172
+ };
173
+ }
174
+
175
+ module.exports = {
176
+ extractReceiptEvidence,
177
+ receiptVerifierPassed,
178
+ findCachedMissionStepReceipt,
179
+ RECEIPT_PATH_PATTERN,
180
+ };
@@ -64,7 +64,7 @@ const RUNNER_PROFILE_DEFS = Object.freeze({
64
64
  }),
65
65
  grok: Object.freeze({
66
66
  bin: 'grok',
67
- model: 'grok-4.5',
67
+ model: 'grok-4.6',
68
68
  commandTemplate: '{bin} --always-approve -p {prompt}',
69
69
  }),
70
70
  droid: Object.freeze({