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.
- package/FOR_AGENTS.md +7 -0
- package/README.md +1 -1
- package/atris/policies/ANTISLOP.md +2 -1
- package/atris/skills/copy-editor/SKILL.md +2 -1
- package/atris/skills/design/SKILL.md +1 -1
- package/atris/skills/x-search/SKILL.md +24 -22
- package/atris/skills/youtube/SKILL.md +82 -33
- package/atris/team/_template/SOUL.md +40 -0
- package/atris/team/validator/MEMBER.md +1 -2
- package/bin/atris +21 -0
- package/bin/atris.js +563 -373
- package/commands/api-key.js +170 -0
- package/commands/auth.js +453 -43
- package/commands/autoland.js +3 -1
- package/commands/autopilot-front.js +58 -11
- package/commands/avail.js +5 -4
- package/commands/balance.js +55 -0
- package/commands/bench.js +29 -1
- package/commands/brain.js +63 -12
- package/commands/brainstorm.js +18 -0
- package/commands/business.js +149 -1
- package/commands/chat-scan.js +17 -4
- package/commands/close.js +5 -1
- package/commands/doctor.js +174 -0
- package/commands/dream.js +7 -0
- package/commands/drill.js +34 -2
- package/commands/engine.js +47 -35
- package/commands/errors.js +58 -8
- package/commands/experiments.js +14 -0
- package/commands/feedback.js +61 -2
- package/commands/fleet-report.js +27 -7
- package/commands/fleet.js +98 -11
- package/commands/founder.js +60 -21
- package/commands/human-missions.js +79 -4
- package/commands/improve.js +54 -4
- package/commands/init.js +68 -92
- package/commands/install.js +40 -0
- package/commands/integrations.js +399 -30
- package/commands/interview.js +8 -0
- package/commands/land.js +48 -17
- package/commands/learn.js +29 -4
- package/commands/log.js +51 -0
- package/commands/member.js +68 -10
- package/commands/mission.js +287 -50
- package/commands/now.js +15 -3
- package/commands/orb.js +97 -2
- package/commands/pack.js +83 -9
- package/commands/playbook.js +381 -0
- package/commands/plugin.js +16 -0
- package/commands/radar.js +31 -7
- package/commands/recap.js +128 -21
- package/commands/release.js +102 -2
- package/commands/review.js +5 -10
- package/commands/revisions.js +55 -0
- package/commands/run-front.js +12 -4
- package/commands/scout.js +12 -1
- package/commands/search.js +123 -28
- package/commands/sign.js +2 -2
- package/commands/signup.js +12 -3
- package/commands/site-deploy.js +17 -4
- package/commands/site.js +2 -2
- package/commands/skill-eval.js +289 -0
- package/commands/skill.js +56 -6
- package/commands/social.js +603 -0
- package/commands/spaceship.js +69 -6
- package/commands/stream.js +8 -1
- package/commands/study.js +32 -19
- package/commands/sync.js +28 -22
- package/commands/task.js +418 -60
- package/commands/teach.js +72 -63
- package/commands/terminal.js +25 -9
- package/commands/topup.js +88 -0
- package/commands/truth.js +52 -6
- package/commands/usage.js +91 -0
- package/commands/verify.js +3 -2
- package/commands/version.js +3 -1
- package/commands/voice.js +5 -1
- package/commands/who.js +69 -11
- package/commands/wiki.js +7 -4
- package/commands/wish.js +76 -5
- package/commands/workflow.js +327 -145
- package/commands/worktree.js +1 -0
- package/commands/write.js +5 -0
- package/commands/x-search.js +340 -0
- package/commands/xp.js +5 -1
- package/commands/youtube.js +551 -25
- package/lib/account-bound.js +47 -0
- package/lib/auto-accept-certified.js +8 -1
- package/lib/auto-lessons.js +186 -0
- package/lib/autoland.js +4 -2
- package/lib/chat-log-scan.js +7 -4
- package/lib/cli-json.js +77 -0
- package/lib/cli-scope.js +26 -0
- package/lib/codex-flight.js +1 -0
- package/lib/conductor-artifacts.js +1 -1
- package/lib/context-gatherer.js +11 -0
- package/lib/developer-api.js +116 -0
- package/lib/feedback-triage.js +274 -0
- package/lib/first-minute.js +398 -0
- package/lib/fleet.js +115 -34
- package/lib/functional-owner.js +22 -0
- package/lib/known-commands.js +31 -5
- package/lib/member-scaffold.js +197 -0
- package/lib/mission-root.js +4 -2
- package/lib/noninteractive.js +88 -0
- package/lib/policy-lessons.js +4 -1
- package/lib/revision-metric.js +279 -0
- package/lib/scratch-root.js +48 -0
- package/lib/skill-eval-gate.js +249 -0
- package/lib/task-db.js +4 -0
- package/lib/task-proof.js +69 -8
- package/lib/verifier-quality.js +69 -0
- package/lib/wish-audit.js +2 -2
- package/lib/wish-delegate.js +10 -1
- package/lib/workspace-scaffold.js +270 -0
- package/package.json +3 -2
- package/scripts/det/checklist-score.js +191 -0
- package/scripts/det/ytsearch +31 -0
- package/utils/update-check.js +15 -0
package/commands/workflow.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { getLogPath } = require('../lib/journal');
|
|
4
|
+
const {
|
|
5
|
+
buildFirstMinute,
|
|
6
|
+
folderName,
|
|
7
|
+
freshMinuteJson,
|
|
8
|
+
isCertifiedReview,
|
|
9
|
+
isFreshWorkspace,
|
|
10
|
+
personName,
|
|
11
|
+
pickNext,
|
|
12
|
+
renderWorkspace,
|
|
13
|
+
speakFirstMinute,
|
|
14
|
+
taskCommand,
|
|
15
|
+
} = require('../lib/first-minute');
|
|
16
|
+
const { isNonInteractive } = require('../lib/noninteractive');
|
|
17
|
+
const { loadContext } = require('../lib/state-detection');
|
|
4
18
|
const { buildToolResultBody } = require('../lib/tool-result-encode');
|
|
5
19
|
|
|
6
20
|
function wrapWorkflowText(text, width = 76) {
|
|
@@ -42,6 +56,98 @@ function printWorkflowBrief(lines) {
|
|
|
42
56
|
console.log('');
|
|
43
57
|
}
|
|
44
58
|
|
|
59
|
+
function reviewSoftTitle(title, maxWords = 5) {
|
|
60
|
+
const words = String(title || '').replace(/\s+/g, ' ').trim().split(' ').filter(Boolean);
|
|
61
|
+
if (!words.length) return '';
|
|
62
|
+
const text = words.slice(0, maxWords).join(' ').replace(/[.,;:!?]+$/g, '');
|
|
63
|
+
return `"${text.toLowerCase()}"`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isHumanDeskNext(command) {
|
|
67
|
+
return /^atris task (?:claim|ready|accept)\b/.test(String(command || ''));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function loadReviewTasks(root = process.cwd()) {
|
|
71
|
+
try {
|
|
72
|
+
const taskDb = require('../lib/task-db');
|
|
73
|
+
const db = taskDb.open();
|
|
74
|
+
const workspaceRoot = taskDb.workspaceRoot(root);
|
|
75
|
+
const rows = taskDb.listTasks(db, { workspaceRoot, limit: 200 });
|
|
76
|
+
if (Array.isArray(rows) && rows.length) return taskDb.withTaskDisplayRefs(rows);
|
|
77
|
+
} catch {
|
|
78
|
+
// Fall through to the local projection. Tests and fresh folders often have no db.
|
|
79
|
+
}
|
|
80
|
+
const projectionPath = path.join(root, '.atris', 'state', 'tasks.projection.json');
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(fs.readFileSync(projectionPath, 'utf8'));
|
|
83
|
+
return Array.isArray(parsed.tasks) ? parsed.tasks : [];
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function wantsReviewQueue(args = []) {
|
|
90
|
+
const list = Array.isArray(args) ? args : [];
|
|
91
|
+
return list.includes('--json')
|
|
92
|
+
|| list.includes('--all')
|
|
93
|
+
|| list.includes('--limit')
|
|
94
|
+
|| list.includes('--group-by');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function renderReviewMinute({
|
|
98
|
+
root = process.cwd(),
|
|
99
|
+
person,
|
|
100
|
+
tasks,
|
|
101
|
+
} = {}) {
|
|
102
|
+
const who = person != null ? person : personName();
|
|
103
|
+
const greet = who ? `hey ${who}, ` : '';
|
|
104
|
+
const all = Array.isArray(tasks) ? tasks : loadReviewTasks(root);
|
|
105
|
+
const reviews = all.filter((task) => task && task.status === 'review');
|
|
106
|
+
const checking = reviews.filter((task) => !isCertifiedReview(task));
|
|
107
|
+
const picked = pickNext({ tasks: reviews, person: who });
|
|
108
|
+
const task = picked.task || null;
|
|
109
|
+
const title = task ? reviewSoftTitle(task.title) : '';
|
|
110
|
+
|
|
111
|
+
if (task && isCertifiedReview(task)) {
|
|
112
|
+
const win = title
|
|
113
|
+
? `${greet}${title} is waiting for your ok.`
|
|
114
|
+
: `${greet}one finished thing is waiting for your ok.`;
|
|
115
|
+
const lines = [win];
|
|
116
|
+
if (checking.length === 1) lines.push('1 still being checked.');
|
|
117
|
+
if (checking.length > 1) lines.push(`${checking.length} still being checked.`);
|
|
118
|
+
lines.push('');
|
|
119
|
+
lines.push(`next: ${taskCommand(task, who)}`);
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (checking.length === 1) {
|
|
124
|
+
const named = title || reviewSoftTitle(checking[0] && checking[0].title);
|
|
125
|
+
if (named) return `${greet}${named} is still being checked.`;
|
|
126
|
+
return `${greet}1 finished thing is still being checked.`;
|
|
127
|
+
}
|
|
128
|
+
if (checking.length > 1) {
|
|
129
|
+
return `${greet}${checking.length} finished things are still being checked.`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Review is the human desk. If first-minute next is claim, ready, or
|
|
133
|
+
// accept, say that same next. "nothing is waiting" is only for an empty desk.
|
|
134
|
+
if (tasks === undefined) {
|
|
135
|
+
const screen = buildFirstMinute({ root, person: who });
|
|
136
|
+
if (isHumanDeskNext(screen.nextCommand)) return screen.text;
|
|
137
|
+
} else {
|
|
138
|
+
const room = pickNext({ tasks: all, person: who });
|
|
139
|
+
if (isHumanDeskNext(room.command)) {
|
|
140
|
+
return renderWorkspace({
|
|
141
|
+
person: who,
|
|
142
|
+
folder: folderName(root),
|
|
143
|
+
task: room.task || null,
|
|
144
|
+
nextCommand: room.command,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return 'nothing is waiting on you.';
|
|
149
|
+
}
|
|
150
|
+
|
|
45
151
|
const CONFIDENCE_GATE_LINES = [
|
|
46
152
|
'Confidence Gate:',
|
|
47
153
|
'1) Ask: am I factually confident enough to move this forward?',
|
|
@@ -375,6 +481,11 @@ async function planAtris(userInput = null) {
|
|
|
375
481
|
const args = process.argv.slice(3);
|
|
376
482
|
const executeFlag = args.includes('--execute');
|
|
377
483
|
const showFull = args.includes('--full') || args.includes('--verbose');
|
|
484
|
+
const leftoverRequest = args
|
|
485
|
+
.filter((token) => !['--execute', '--full', '--verbose', '--json', '--prompt'].includes(token))
|
|
486
|
+
.join(' ')
|
|
487
|
+
.trim();
|
|
488
|
+
const showPrompt = showFull || args.includes('--prompt');
|
|
378
489
|
|
|
379
490
|
const config = loadConfig();
|
|
380
491
|
// Auto-enable local execution mode for "2 fast" / "2 pro" product aliases.
|
|
@@ -388,21 +499,32 @@ async function planAtris(userInput = null) {
|
|
|
388
499
|
return;
|
|
389
500
|
}
|
|
390
501
|
|
|
391
|
-
const
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
502
|
+
const cwd = process.cwd();
|
|
503
|
+
const targetDir = path.join(cwd, 'atris');
|
|
504
|
+
|
|
505
|
+
// Empty folder talks like bare atris. Missing navigator.md after
|
|
506
|
+
// init --minimal is optional context, not a factory bounce.
|
|
507
|
+
if (!fs.existsSync(targetDir)) {
|
|
508
|
+
if (args.includes('--json')) {
|
|
509
|
+
console.log(JSON.stringify(freshMinuteJson(), null, 2));
|
|
510
|
+
process.exit(2);
|
|
511
|
+
}
|
|
512
|
+
const screen = buildFirstMinute({ root: cwd, fresh: true });
|
|
513
|
+
console.log('');
|
|
514
|
+
console.log(screen.text);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const memberNavigator = path.join(targetDir, 'team', 'navigator', 'MEMBER.md');
|
|
519
|
+
const legacyNavigator = path.join(targetDir, 'team', 'navigator.md');
|
|
520
|
+
const navigatorFile = fs.existsSync(memberNavigator)
|
|
521
|
+
? memberNavigator
|
|
522
|
+
: (fs.existsSync(legacyNavigator) ? legacyNavigator : null);
|
|
395
523
|
const personaPath = path.join(targetDir, 'PERSONA.md');
|
|
396
524
|
const mapFilePath = path.join(targetDir, 'MAP.md');
|
|
397
525
|
const featuresReadmePath = path.join(targetDir, 'features', 'README.md');
|
|
398
526
|
|
|
399
|
-
|
|
400
|
-
console.log('✗ navigator.md not found. Run "atris init" first.');
|
|
401
|
-
process.exit(1);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Read navigator.md
|
|
405
|
-
const navigatorSpec = fs.readFileSync(navigatorFile, 'utf8');
|
|
527
|
+
const navigatorSpec = navigatorFile ? fs.readFileSync(navigatorFile, 'utf8') : '';
|
|
406
528
|
|
|
407
529
|
// Read journal Inbox for context
|
|
408
530
|
const { logFile } = getLogPath();
|
|
@@ -429,14 +551,15 @@ async function planAtris(userInput = null) {
|
|
|
429
551
|
|
|
430
552
|
// Detect uncertainty in inbox context (or direct user input)
|
|
431
553
|
const uncertaintySignals = ['not sure', 'maybe', 'but ', 'thinking about', 'uncertain', 'unclear', 'unsure', 'don\'t know'];
|
|
432
|
-
const
|
|
554
|
+
const requestText = String(userInput || leftoverRequest || '').trim();
|
|
555
|
+
const combinedContext = [requestText, inboxContext].filter(Boolean).join('\n');
|
|
433
556
|
const hasUncertainty = combinedContext && uncertaintySignals.some(signal =>
|
|
434
557
|
combinedContext.toLowerCase().includes(signal)
|
|
435
558
|
);
|
|
436
559
|
|
|
437
560
|
const taskSourcePath = taskFilePath ? path.relative(process.cwd(), taskFilePath) : null;
|
|
438
561
|
const journalPath = path.relative(process.cwd(), logFile);
|
|
439
|
-
const navigatorPath = path.relative(process.cwd(), navigatorFile);
|
|
562
|
+
const navigatorPath = navigatorFile ? path.relative(process.cwd(), navigatorFile) : null;
|
|
440
563
|
const personaFileRef = fs.existsSync(personaPath) ? path.relative(process.cwd(), personaPath) : null;
|
|
441
564
|
const mapFileRef = fs.existsSync(mapFilePath) ? path.relative(process.cwd(), mapFilePath) : null;
|
|
442
565
|
const featuresReadmeRef = fs.existsSync(featuresReadmePath) ? path.relative(process.cwd(), featuresReadmePath) : null;
|
|
@@ -460,7 +583,30 @@ async function planAtris(userInput = null) {
|
|
|
460
583
|
.length
|
|
461
584
|
: 0;
|
|
462
585
|
|
|
463
|
-
|
|
586
|
+
let firstMinute = null;
|
|
587
|
+
try {
|
|
588
|
+
firstMinute = buildFirstMinute({
|
|
589
|
+
root: cwd,
|
|
590
|
+
context: loadContext(cwd) || {},
|
|
591
|
+
});
|
|
592
|
+
} catch {
|
|
593
|
+
firstMinute = null;
|
|
594
|
+
}
|
|
595
|
+
const showFactory = showPrompt || Boolean(requestText);
|
|
596
|
+
|
|
597
|
+
if (showFactory || executionMode !== 'prompt') {
|
|
598
|
+
console.log(executionMode === 'prompt' ? 'PROMPT ONLY' : 'ACTION TAKEN');
|
|
599
|
+
console.log('');
|
|
600
|
+
if (firstMinute && firstMinute.text) {
|
|
601
|
+
console.log(firstMinute.text);
|
|
602
|
+
console.log('');
|
|
603
|
+
}
|
|
604
|
+
} else if (firstMinute && firstMinute.text) {
|
|
605
|
+
console.log('');
|
|
606
|
+
console.log(firstMinute.text);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (showFactory) {
|
|
464
610
|
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
465
611
|
console.log('│ Atris Plan — Navigator Agent Activated │');
|
|
466
612
|
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
@@ -479,16 +625,16 @@ async function planAtris(userInput = null) {
|
|
|
479
625
|
console.log('');
|
|
480
626
|
}
|
|
481
627
|
|
|
482
|
-
if (
|
|
628
|
+
if (requestText) {
|
|
483
629
|
console.log('🎯 DIRECT REQUEST:');
|
|
484
630
|
console.log('─────────────────────────────────────────────────────────────');
|
|
485
|
-
console.log(
|
|
631
|
+
console.log(requestText);
|
|
486
632
|
console.log('');
|
|
487
633
|
console.log('─────────────────────────────────────────────────────────────');
|
|
488
634
|
console.log('');
|
|
489
635
|
}
|
|
490
636
|
console.log('📁 CONTEXT FILES (agent should read):');
|
|
491
|
-
console.log(`- Navigator spec: ${navigatorPath}`);
|
|
637
|
+
console.log(`- Navigator spec: ${navigatorPath || 'atris/team/navigator/MEMBER.md (missing)'}`);
|
|
492
638
|
console.log(`- Persona: ${personaFileRef || 'atris/PERSONA.md (missing)'}`);
|
|
493
639
|
const mapDisplay = mapFileRef
|
|
494
640
|
? `${mapFileRef}${mapIsPlaceholder ? ' (placeholder — generate first)' : ''}`
|
|
@@ -519,10 +665,12 @@ async function planAtris(userInput = null) {
|
|
|
519
665
|
console.log('');
|
|
520
666
|
|
|
521
667
|
if (showFull) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
668
|
+
if (navigatorSpec) {
|
|
669
|
+
console.log('📋 NAVIGATOR SPEC (full):');
|
|
670
|
+
console.log('─────────────────────────────────────────────────────────────');
|
|
671
|
+
console.log(navigatorSpec);
|
|
672
|
+
console.log('');
|
|
673
|
+
}
|
|
526
674
|
console.log('📥 INBOX CONTEXT (full):');
|
|
527
675
|
console.log('─────────────────────────────────────────────────────────────');
|
|
528
676
|
console.log(inboxContext || '(No items in Inbox)');
|
|
@@ -540,7 +688,7 @@ async function planAtris(userInput = null) {
|
|
|
540
688
|
console.log('You are the Navigator.');
|
|
541
689
|
console.log('');
|
|
542
690
|
console.log('Read these files:');
|
|
543
|
-
console.log(`- ${navigatorPath}`);
|
|
691
|
+
if (navigatorPath) console.log(`- ${navigatorPath}`);
|
|
544
692
|
if (personaFileRef) console.log(`- ${personaFileRef}`);
|
|
545
693
|
if (mapFileRef) console.log(`- ${mapFileRef}`);
|
|
546
694
|
if (taskSourcePath) console.log(`- ${taskSourcePath}`);
|
|
@@ -552,9 +700,9 @@ async function planAtris(userInput = null) {
|
|
|
552
700
|
console.log('Note: If `atris/MAP.md` is missing or placeholder, generate it from `atris/atris.md` before writing tasks.');
|
|
553
701
|
console.log('');
|
|
554
702
|
}
|
|
555
|
-
if (
|
|
703
|
+
if (requestText) {
|
|
556
704
|
console.log('Direct request:');
|
|
557
|
-
console.log(
|
|
705
|
+
console.log(requestText);
|
|
558
706
|
console.log('');
|
|
559
707
|
}
|
|
560
708
|
console.log('Workflow:');
|
|
@@ -578,6 +726,7 @@ async function planAtris(userInput = null) {
|
|
|
578
726
|
}
|
|
579
727
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
580
728
|
console.log('');
|
|
729
|
+
}
|
|
581
730
|
|
|
582
731
|
// Check execution mode
|
|
583
732
|
if (executionMode === 'agent') {
|
|
@@ -613,8 +762,8 @@ async function planAtris(userInput = null) {
|
|
|
613
762
|
let userPrompt = `You are the Navigator. Take ideas from Inbox → break them down into perfect, manageable tasks.\n\n`;
|
|
614
763
|
userPrompt += `⚠️ CRITICAL: You MUST create visualizations BEFORE writing tasks!\n\n`;
|
|
615
764
|
|
|
616
|
-
if (
|
|
617
|
-
userPrompt += `## DIRECT REQUEST:\n${
|
|
765
|
+
if (requestText) {
|
|
766
|
+
userPrompt += `## DIRECT REQUEST:\n${requestText}\n\n`;
|
|
618
767
|
}
|
|
619
768
|
|
|
620
769
|
if (inboxContext) {
|
|
@@ -720,22 +869,33 @@ async function doAtris() {
|
|
|
720
869
|
const { executeCodeExecution } = require('../utils/claude_sdk');
|
|
721
870
|
const args = process.argv.slice(3);
|
|
722
871
|
const executeFlag = args.includes('--execute');
|
|
723
|
-
const showFull = args.includes('--full') || args.includes('--verbose');
|
|
872
|
+
const showFull = args.includes('--full') || args.includes('--verbose') || args.includes('--prompt');
|
|
724
873
|
|
|
725
874
|
const config = loadConfig();
|
|
726
875
|
const executionMode = executeFlag ? 'agent' : (config.execution_mode || 'prompt');
|
|
727
876
|
|
|
728
877
|
const cwd = process.cwd();
|
|
729
878
|
const targetDir = path.join(cwd, 'atris');
|
|
730
|
-
const executorFile = fs.existsSync(path.join(targetDir, 'team', 'executor', 'MEMBER.md'))
|
|
731
|
-
? path.join(targetDir, 'team', 'executor', 'MEMBER.md')
|
|
732
|
-
: path.join(targetDir, 'team', 'executor.md');
|
|
733
879
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
880
|
+
// Empty folder talks like bare atris. Missing executor.md after
|
|
881
|
+
// init --minimal is optional context, not a factory bounce.
|
|
882
|
+
if (!fs.existsSync(targetDir)) {
|
|
883
|
+
if (args.includes('--json')) {
|
|
884
|
+
console.log(JSON.stringify(freshMinuteJson(), null, 2));
|
|
885
|
+
process.exit(2);
|
|
886
|
+
}
|
|
887
|
+
const screen = buildFirstMinute({ root: cwd, fresh: true });
|
|
888
|
+
console.log('');
|
|
889
|
+
console.log(screen.text);
|
|
890
|
+
return;
|
|
737
891
|
}
|
|
738
892
|
|
|
893
|
+
const memberExecutor = path.join(targetDir, 'team', 'executor', 'MEMBER.md');
|
|
894
|
+
const legacyExecutor = path.join(targetDir, 'team', 'executor.md');
|
|
895
|
+
const executorFile = fs.existsSync(memberExecutor)
|
|
896
|
+
? memberExecutor
|
|
897
|
+
: (fs.existsSync(legacyExecutor) ? legacyExecutor : null);
|
|
898
|
+
|
|
739
899
|
// Load project profile for context
|
|
740
900
|
let context = 'ROOT';
|
|
741
901
|
let profile = null;
|
|
@@ -754,8 +914,7 @@ async function doAtris() {
|
|
|
754
914
|
}
|
|
755
915
|
}
|
|
756
916
|
|
|
757
|
-
|
|
758
|
-
const executorSpec = fs.readFileSync(executorFile, 'utf8');
|
|
917
|
+
const executorSpec = executorFile ? fs.readFileSync(executorFile, 'utf8') : '';
|
|
759
918
|
|
|
760
919
|
// Load PERSONA.md
|
|
761
920
|
const personaFile = path.join(targetDir, 'PERSONA.md');
|
|
@@ -798,7 +957,7 @@ async function doAtris() {
|
|
|
798
957
|
// All tasks available (no tag filtering)
|
|
799
958
|
const filteredTasks = tasksContent;
|
|
800
959
|
|
|
801
|
-
const executorPath = path.relative(process.cwd(), executorFile);
|
|
960
|
+
const executorPath = executorFile ? path.relative(process.cwd(), executorFile) : null;
|
|
802
961
|
const personaFileRef = fs.existsSync(personaFile) ? path.relative(process.cwd(), personaFile) : null;
|
|
803
962
|
const taskSourcePath = taskFilePath ? path.relative(process.cwd(), taskFilePath) : null;
|
|
804
963
|
const featuresReadmePath = path.join(targetDir, 'features', 'README.md');
|
|
@@ -829,44 +988,35 @@ async function doAtris() {
|
|
|
829
988
|
|
|
830
989
|
let workspaceSummary = null;
|
|
831
990
|
try {
|
|
832
|
-
const { loadContext } = require('../lib/state-detection');
|
|
833
991
|
workspaceSummary = loadContext(cwd);
|
|
834
992
|
} catch {
|
|
835
993
|
workspaceSummary = null;
|
|
836
994
|
}
|
|
837
995
|
|
|
838
|
-
|
|
839
|
-
console.log('');
|
|
840
|
-
console.log('┌─────────────────────────────────────────────────────────────┐');
|
|
841
|
-
console.log('│ Atris Do — Executor Agent Activated │');
|
|
842
|
-
console.log(`│ Context: ${context} │`);
|
|
843
|
-
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
844
|
-
console.log('');
|
|
845
|
-
|
|
846
|
-
console.log('📁 CONTEXT FILES (agent should read):');
|
|
847
|
-
console.log(`- Executor spec: ${executorPath}`);
|
|
848
|
-
console.log(`- Persona: ${personaFileRef || 'atris/PERSONA.md (missing)'}`);
|
|
849
|
-
const mapDisplay = mapPath
|
|
850
|
-
? `${mapPath}${mapIsPlaceholder ? ' (placeholder — generate first)' : ''}`
|
|
851
|
-
: 'atris/MAP.md (missing)';
|
|
852
|
-
console.log(`- MAP: ${mapDisplay}`);
|
|
853
|
-
console.log(`- TODO: ${taskSourcePath || 'atris/TODO.md (missing)'}`);
|
|
854
|
-
console.log(`- Features index: ${featuresReadmeRef || 'atris/features/README.md (missing)'}`);
|
|
855
|
-
|
|
856
|
-
// Show top learnings during execution
|
|
996
|
+
let firstMinute = null;
|
|
857
997
|
try {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
998
|
+
firstMinute = buildFirstMinute({
|
|
999
|
+
root: cwd,
|
|
1000
|
+
context: workspaceSummary || {},
|
|
1001
|
+
});
|
|
1002
|
+
} catch {
|
|
1003
|
+
firstMinute = null;
|
|
1004
|
+
}
|
|
1005
|
+
const liveStatus = firstMinute && firstMinute.task && firstMinute.task.status;
|
|
1006
|
+
const hasLiveTask = liveStatus === 'claimed' || liveStatus === 'review' || liveStatus === 'open';
|
|
1007
|
+
|
|
1008
|
+
// Default stays the first-minute two lines. The factory paste stays on --prompt.
|
|
1009
|
+
if (showFull || executionMode !== 'prompt') {
|
|
1010
|
+
console.log(executionMode === 'prompt' ? 'PROMPT ONLY' : 'ACTION TAKEN');
|
|
1011
|
+
console.log('');
|
|
1012
|
+
if (firstMinute && firstMinute.text) {
|
|
1013
|
+
console.log(firstMinute.text);
|
|
861
1014
|
console.log('');
|
|
862
|
-
console.log('🧠 Prior learnings (apply during build):');
|
|
863
|
-
for (const l of learnings) {
|
|
864
|
-
console.log(` [${l._effectiveConfidence}/10] ${l.type}/${l.key}: ${l.insight}`);
|
|
865
|
-
}
|
|
866
1015
|
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
|
|
1016
|
+
} else if (firstMinute && firstMinute.text) {
|
|
1017
|
+
console.log('');
|
|
1018
|
+
console.log(firstMinute.text);
|
|
1019
|
+
}
|
|
870
1020
|
|
|
871
1021
|
const backlogCount = workspaceSummary && Array.isArray(workspaceSummary.backlogTasks)
|
|
872
1022
|
? workspaceSummary.backlogTasks.length
|
|
@@ -875,51 +1025,77 @@ async function doAtris() {
|
|
|
875
1025
|
? workspaceSummary.inProgressFeatures.length
|
|
876
1026
|
: 0;
|
|
877
1027
|
|
|
878
|
-
if (
|
|
879
|
-
console.log(
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1028
|
+
if (showFull) {
|
|
1029
|
+
console.log('📁 CONTEXT FILES (agent should read):');
|
|
1030
|
+
console.log(`- Executor spec: ${executorPath || 'atris/team/executor/MEMBER.md (missing)'}`);
|
|
1031
|
+
console.log(`- Persona: ${personaFileRef || 'atris/PERSONA.md (missing)'}`);
|
|
1032
|
+
const mapDisplay = mapPath
|
|
1033
|
+
? `${mapPath}${mapIsPlaceholder ? ' (placeholder — generate first)' : ''}`
|
|
1034
|
+
: 'atris/MAP.md (missing)';
|
|
1035
|
+
console.log(`- MAP: ${mapDisplay}`);
|
|
1036
|
+
console.log(`- TODO: ${taskSourcePath || 'atris/TODO.md (missing)'}`);
|
|
1037
|
+
console.log(`- Features index: ${featuresReadmeRef || 'atris/features/README.md (missing)'}`);
|
|
1038
|
+
|
|
1039
|
+
try {
|
|
1040
|
+
const { loadLearnings } = require('../lib/learnings');
|
|
1041
|
+
const learnings = loadLearnings().filter(e => e._effectiveConfidence >= 7 && e.insight !== '[REMOVED]').slice(0, 3);
|
|
1042
|
+
if (learnings.length > 0) {
|
|
1043
|
+
console.log('');
|
|
1044
|
+
console.log('🧠 Prior learnings (apply during build):');
|
|
1045
|
+
for (const l of learnings) {
|
|
1046
|
+
console.log(` [${l._effectiveConfidence}/10] ${l.type}/${l.key}: ${l.insight}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
} catch {}
|
|
1050
|
+
|
|
1051
|
+
console.log('');
|
|
1052
|
+
|
|
1053
|
+
if (inProgressCount > 0) {
|
|
1054
|
+
console.log(`🔨 In-progress features: ${workspaceSummary.inProgressFeatures.join(', ')}`);
|
|
886
1055
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1056
|
+
console.log(`🧱 Feature build plans found: ${featureBuildPlanRefs.length}`);
|
|
1057
|
+
if (featureBuildPlanRefs.length > 0) {
|
|
1058
|
+
featureBuildPlanRefs.slice(0, 3).forEach((ref) => console.log(`- ${ref}`));
|
|
1059
|
+
if (featureBuildPlanRefs.length > 3) {
|
|
1060
|
+
console.log(`- ... (+${featureBuildPlanRefs.length - 3} more)`);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (!(hasLiveTask && backlogCount === 0)) {
|
|
1064
|
+
console.log(`📋 Backlog tasks: ${backlogCount}`);
|
|
1065
|
+
}
|
|
1066
|
+
console.log('');
|
|
890
1067
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1068
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1069
|
+
console.log('📋 COPY/PASTE PROMPT FOR YOUR CODING AGENT:');
|
|
1070
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1071
|
+
console.log('');
|
|
1072
|
+
console.log('You are the Executor.');
|
|
1073
|
+
console.log('');
|
|
1074
|
+
console.log('Read these files:');
|
|
1075
|
+
if (executorPath) console.log(`- ${executorPath}`);
|
|
1076
|
+
if (personaFileRef) console.log(`- ${personaFileRef}`);
|
|
1077
|
+
if (mapPath) console.log(`- ${mapPath}`);
|
|
1078
|
+
if (taskSourcePath) console.log(`- ${taskSourcePath}`);
|
|
1079
|
+
if (featuresReadmeRef) console.log(`- ${featuresReadmeRef}`);
|
|
1080
|
+
console.log('');
|
|
1081
|
+
if (!mapPath || mapIsPlaceholder) {
|
|
1082
|
+
console.log('Note: If `atris/MAP.md` is missing or placeholder, generate it from `atris/atris.md` before navigating the codebase.');
|
|
1083
|
+
console.log('');
|
|
1084
|
+
}
|
|
1085
|
+
console.log('Workflow:');
|
|
1086
|
+
console.log('1) Read atris/TODO.md — claim next unclaimed Backlog task');
|
|
1087
|
+
console.log(' Move to ## In Progress: add "Claimed by: executor at YYYY-MM-DD HH:MM"');
|
|
1088
|
+
console.log('2) Run the Confidence Gate against the task before editing');
|
|
1089
|
+
printConfidenceGate(' ');
|
|
1090
|
+
console.log('3) Execute step-by-step. Run tests as you go.');
|
|
1091
|
+
console.log('4) Before completion, rerun the gate against proof and residual risk');
|
|
1092
|
+
console.log('5) When done, move task to ## Completed');
|
|
1093
|
+
console.log('6) Log to atris/team/executor/logs/YYYY-MM-DD.md');
|
|
1094
|
+
console.log(' (Task, Delivered, Errors hit, Learned)');
|
|
1095
|
+
console.log('');
|
|
1096
|
+
console.log('⛔ Do NOT plan — just execute what\'s written.');
|
|
906
1097
|
console.log('');
|
|
907
|
-
}
|
|
908
|
-
console.log('Workflow:');
|
|
909
|
-
console.log('1) Read atris/TODO.md — claim next unclaimed Backlog task');
|
|
910
|
-
console.log(' Move to ## In Progress: add "Claimed by: executor at YYYY-MM-DD HH:MM"');
|
|
911
|
-
console.log('2) Run the Confidence Gate against the task before editing');
|
|
912
|
-
printConfidenceGate(' ');
|
|
913
|
-
console.log('3) Execute step-by-step. Run tests as you go.');
|
|
914
|
-
console.log('4) Before completion, rerun the gate against proof and residual risk');
|
|
915
|
-
console.log('5) When done, move task to ## Completed');
|
|
916
|
-
console.log('6) Log to atris/team/executor/logs/YYYY-MM-DD.md');
|
|
917
|
-
console.log(' (Task, Delivered, Errors hit, Learned)');
|
|
918
|
-
console.log('');
|
|
919
|
-
console.log('⛔ Do NOT plan — just execute what\'s written.');
|
|
920
|
-
console.log('');
|
|
921
1098
|
|
|
922
|
-
if (showFull) {
|
|
923
1099
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
924
1100
|
console.log('📎 APPENDIX (full context dumps):');
|
|
925
1101
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
@@ -932,10 +1108,12 @@ async function doAtris() {
|
|
|
932
1108
|
console.log('');
|
|
933
1109
|
}
|
|
934
1110
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1111
|
+
if (executorSpec) {
|
|
1112
|
+
console.log('🔧 EXECUTOR SPEC (full):');
|
|
1113
|
+
console.log('─────────────────────────────────────────────────────────────');
|
|
1114
|
+
console.log(executorSpec);
|
|
1115
|
+
console.log('');
|
|
1116
|
+
}
|
|
939
1117
|
|
|
940
1118
|
if (filteredTasks) {
|
|
941
1119
|
console.log(`📋 TASKS TO EXECUTE (full, from ${taskSource}):`);
|
|
@@ -944,16 +1122,14 @@ async function doAtris() {
|
|
|
944
1122
|
console.log('');
|
|
945
1123
|
}
|
|
946
1124
|
|
|
1125
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1126
|
+
if (!hasLiveTask) {
|
|
1127
|
+
console.log('💡 Next: Run "atris review" after execution');
|
|
1128
|
+
}
|
|
1129
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1130
|
+
console.log('');
|
|
947
1131
|
}
|
|
948
1132
|
|
|
949
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
950
|
-
console.log('💡 Next: Run "atris review" after execution');
|
|
951
|
-
if (!showFull) {
|
|
952
|
-
console.log(' Tip: `atris do --full` prints full spec/context for copy/paste.');
|
|
953
|
-
}
|
|
954
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
955
|
-
console.log('');
|
|
956
|
-
|
|
957
1133
|
// Check execution mode
|
|
958
1134
|
if (executionMode === 'agent') {
|
|
959
1135
|
// Agent mode: execute via backend API
|
|
@@ -1075,41 +1251,44 @@ async function reviewAtris() {
|
|
|
1075
1251
|
const executeFlag = args.includes('--execute');
|
|
1076
1252
|
const showFull = args.includes('--full') || args.includes('--verbose');
|
|
1077
1253
|
const wantsTaskJson = args.includes('--json');
|
|
1254
|
+
const root = process.cwd();
|
|
1255
|
+
const queueShape = args.some((arg) => arg === '--all' || arg === '--limit' || arg === '--group-by');
|
|
1256
|
+
|
|
1257
|
+
// Empty folder talks like bare atris, including --verbose. After init, stay
|
|
1258
|
+
// in the room. A missing validator spec is optional context, not "run init".
|
|
1259
|
+
if (isFreshWorkspace(root) && !queueShape) {
|
|
1260
|
+
const code = speakFirstMinute({
|
|
1261
|
+
root,
|
|
1262
|
+
fresh: true,
|
|
1263
|
+
asJson: wantsTaskJson,
|
|
1264
|
+
});
|
|
1265
|
+
if (code !== 0) process.exit(code);
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1078
1268
|
|
|
1079
1269
|
if (!executeFlag && !showFull) {
|
|
1080
1270
|
const forwarded = ['reviews', ...args.filter(arg => !['--execute', '--full', '--verbose'].includes(arg))];
|
|
1081
1271
|
const { run: runTaskCommand } = require('./task');
|
|
1082
|
-
if (
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
'Accept only when the proof is real; revise when the claim is vague, stale, or too narrow.',
|
|
1086
|
-
'Agents can add review proof here, but XP waits for human accept.',
|
|
1087
|
-
]);
|
|
1088
|
-
}
|
|
1089
|
-
await runTaskCommand(forwarded);
|
|
1090
|
-
if (!wantsTaskJson) {
|
|
1091
|
-
printWorkflowBrief([
|
|
1092
|
-
'Need the legacy Validator prompt? Run `atris review --verbose`.',
|
|
1093
|
-
]);
|
|
1272
|
+
if (wantsTaskJson || wantsReviewQueue(args)) {
|
|
1273
|
+
await runTaskCommand(forwarded);
|
|
1274
|
+
return;
|
|
1094
1275
|
}
|
|
1276
|
+
console.log('');
|
|
1277
|
+
console.log(renderReviewMinute());
|
|
1095
1278
|
return;
|
|
1096
1279
|
}
|
|
1097
1280
|
|
|
1098
1281
|
const config = loadConfig();
|
|
1099
1282
|
const executionMode = executeFlag ? 'agent' : (config.execution_mode || 'prompt');
|
|
1100
1283
|
|
|
1101
|
-
const targetDir = path.join(
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
console.log('✗ validator.md not found. Run "atris init" first.');
|
|
1108
|
-
process.exit(1);
|
|
1109
|
-
}
|
|
1284
|
+
const targetDir = path.join(root, 'atris');
|
|
1285
|
+
const memberValidator = path.join(targetDir, 'team', 'validator', 'MEMBER.md');
|
|
1286
|
+
const legacyValidator = path.join(targetDir, 'team', 'validator.md');
|
|
1287
|
+
const validatorFile = fs.existsSync(memberValidator)
|
|
1288
|
+
? memberValidator
|
|
1289
|
+
: (fs.existsSync(legacyValidator) ? legacyValidator : null);
|
|
1110
1290
|
|
|
1111
|
-
|
|
1112
|
-
const validatorSpec = fs.readFileSync(validatorFile, 'utf8');
|
|
1291
|
+
const validatorSpec = validatorFile ? fs.readFileSync(validatorFile, 'utf8') : '';
|
|
1113
1292
|
|
|
1114
1293
|
// Read project-specific testing guide if it exists (optional - projects can add their own)
|
|
1115
1294
|
// Checks common locations: root, backend/, atris/ directories
|
|
@@ -1188,7 +1367,9 @@ async function reviewAtris() {
|
|
|
1188
1367
|
}
|
|
1189
1368
|
})();
|
|
1190
1369
|
|
|
1191
|
-
const validatorPath =
|
|
1370
|
+
const validatorPath = validatorFile
|
|
1371
|
+
? path.relative(process.cwd(), validatorFile)
|
|
1372
|
+
: 'atris/team/validator/MEMBER.md (missing)';
|
|
1192
1373
|
const todoPathRef = taskFilePath ? path.relative(process.cwd(), taskFilePath) : null;
|
|
1193
1374
|
const journalPathRef = path.relative(process.cwd(), logFile);
|
|
1194
1375
|
const personaPath = path.join(targetDir, 'PERSONA.md');
|
|
@@ -1494,8 +1675,8 @@ async function reviewAtris() {
|
|
|
1494
1675
|
}
|
|
1495
1676
|
}
|
|
1496
1677
|
|
|
1497
|
-
// Prompt for learnings
|
|
1498
|
-
if (
|
|
1678
|
+
// Prompt for learnings. Headless and forced non-interactive never ask.
|
|
1679
|
+
if (isNonInteractive()) return;
|
|
1499
1680
|
|
|
1500
1681
|
console.log('');
|
|
1501
1682
|
if (showFull) {
|
|
@@ -1648,6 +1829,7 @@ module.exports = {
|
|
|
1648
1829
|
planAtris,
|
|
1649
1830
|
doAtris,
|
|
1650
1831
|
reviewAtris,
|
|
1832
|
+
renderReviewMinute,
|
|
1651
1833
|
executeAgentSDKFast,
|
|
1652
1834
|
makeCloudExecutor,
|
|
1653
1835
|
postToolResult
|