atris 3.34.0 → 3.35.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/AGENTS.md +0 -2
- package/FOR_AGENTS.md +5 -3
- package/atris/skills/engines/SKILL.md +16 -7
- package/atris/skills/render-cli/SKILL.md +88 -0
- package/atris.md +4 -2
- package/ax +475 -17
- package/bin/atris.js +197 -44
- package/commands/aeo.js +52 -0
- package/commands/autoland.js +313 -19
- package/commands/business.js +91 -8
- package/commands/codex-goal.js +26 -2
- package/commands/drive.js +187 -0
- package/commands/engine.js +73 -2
- package/commands/feed.js +202 -0
- package/commands/github.js +38 -0
- package/commands/gm.js +262 -3
- package/commands/init.js +13 -1
- package/commands/integrations.js +39 -11
- package/commands/interview.js +143 -0
- package/commands/land.js +114 -13
- package/commands/lesson.js +112 -1
- package/commands/linear.js +38 -0
- package/commands/member.js +398 -42
- package/commands/mission.js +554 -64
- package/commands/now.js +25 -1
- package/commands/radar.js +259 -14
- package/commands/serve.js +54 -0
- package/commands/status.js +50 -5
- package/commands/stripe.js +38 -0
- package/commands/supabase.js +39 -0
- package/commands/task.js +935 -71
- package/commands/truth.js +29 -3
- package/commands/unknowns.js +627 -0
- package/commands/update.js +44 -0
- package/commands/vercel.js +38 -0
- package/commands/worktree.js +68 -10
- package/commands/write.js +399 -0
- package/lib/auto-accept-certified.js +70 -19
- package/lib/autoland.js +39 -3
- package/lib/fleet.js +250 -9
- package/lib/memory-view.js +14 -5
- package/lib/mission-runtime-loop.js +7 -0
- package/lib/official-cli-integration.js +174 -0
- package/lib/outbound-send-gate.js +165 -0
- package/lib/permission-grants.js +293 -0
- package/lib/review-integrity.js +147 -0
- package/lib/runner-command.js +23 -0
- package/lib/task-db.js +220 -7
- package/lib/task-proof.js +20 -0
- package/lib/task-receipt.js +93 -0
- package/package.json +1 -1
- package/utils/update-check.js +27 -6
- package/atris/learnings.jsonl +0 -1
package/commands/member.js
CHANGED
|
@@ -440,6 +440,170 @@ function memberRunOwnedActiveMissionId(name, missionMap) {
|
|
|
440
440
|
return candidates[0]?.id || '';
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
+
const MEMBER_LIVE_MISSION_STATUSES = new Set(['running', 'planning']);
|
|
444
|
+
const MEMBER_ACTIVE_ACTIVITY_MS = 24 * 60 * 60 * 1000;
|
|
445
|
+
const MEMBER_RECENT_ACTIVITY_MS = 72 * 60 * 60 * 1000;
|
|
446
|
+
|
|
447
|
+
function memberSlugFromRecord(member) {
|
|
448
|
+
if (member?.format === 'directory' && member.dir) return path.basename(member.dir);
|
|
449
|
+
if (member?.format === 'flat' && member.path) return path.basename(member.path, '.md');
|
|
450
|
+
return lowerCompact(member?.name || '');
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function isFleetMember(member) {
|
|
454
|
+
if (!member || member.format !== 'directory') return false;
|
|
455
|
+
const slug = memberSlugFromRecord(member);
|
|
456
|
+
return Boolean(slug) && !new Set(['_archive', '_archived', '_template']).has(slug);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function missionTimeMs(mission) {
|
|
460
|
+
return Date.parse(mission?.last_tick_at || mission?.updated_at || mission?.created_at || '') || 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function memberOwnedMissions(name, missionMap = memberRunMissionMap()) {
|
|
464
|
+
const owner = lowerCompact(name);
|
|
465
|
+
return Array.from(missionMap.values())
|
|
466
|
+
.filter((mission) => lowerCompact(mission?.owner) === owner)
|
|
467
|
+
.sort((a, b) => missionTimeMs(b) - missionTimeMs(a));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function memberLatestMission(name, missionMap = memberRunMissionMap()) {
|
|
471
|
+
return memberOwnedMissions(name, missionMap)[0] || null;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function memberLiveMission(name, missionMap = memberRunMissionMap()) {
|
|
475
|
+
return memberOwnedMissions(name, missionMap)
|
|
476
|
+
.find((mission) => MEMBER_LIVE_MISSION_STATUSES.has(String(mission?.status || '').toLowerCase())) || null;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function missionShortName(mission, max = 36) {
|
|
480
|
+
return compactSentence(mission?.slug || mission?.title || mission?.objective || mission?.id || '', max) || '-';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function ageLabelFromMs(ms, nowMs = Date.now()) {
|
|
484
|
+
if (!ms) return '-';
|
|
485
|
+
const seconds = Math.max(0, Math.floor((nowMs - ms) / 1000));
|
|
486
|
+
if (seconds < 60) return 'now';
|
|
487
|
+
const minutes = Math.floor(seconds / 60);
|
|
488
|
+
if (minutes < 60) return `${minutes}m`;
|
|
489
|
+
const hours = Math.floor(minutes / 60);
|
|
490
|
+
if (hours < 48) return `${hours}h`;
|
|
491
|
+
return `${Math.floor(hours / 24)}d`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function timestampMs(value) {
|
|
495
|
+
const ms = Date.parse(value || '');
|
|
496
|
+
return Number.isFinite(ms) ? ms : 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function newestMtimeRecursive(root) {
|
|
500
|
+
if (!fs.existsSync(root)) return 0;
|
|
501
|
+
let newest = 0;
|
|
502
|
+
const stack = [root];
|
|
503
|
+
while (stack.length) {
|
|
504
|
+
const current = stack.pop();
|
|
505
|
+
let stat = null;
|
|
506
|
+
try {
|
|
507
|
+
stat = fs.statSync(current);
|
|
508
|
+
} catch {
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
newest = Math.max(newest, stat.mtimeMs || 0);
|
|
512
|
+
if (!stat.isDirectory()) continue;
|
|
513
|
+
let entries = [];
|
|
514
|
+
try {
|
|
515
|
+
entries = fs.readdirSync(current);
|
|
516
|
+
} catch {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
for (const entry of entries) stack.push(path.join(current, entry));
|
|
520
|
+
}
|
|
521
|
+
return newest;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function newestRunActivityMtime(name, root = process.cwd()) {
|
|
525
|
+
const runsDir = path.join(root, 'atris', 'runs');
|
|
526
|
+
if (!fs.existsSync(runsDir)) return 0;
|
|
527
|
+
const needle = lowerCompact(name);
|
|
528
|
+
let newest = 0;
|
|
529
|
+
for (const entry of fs.readdirSync(runsDir)) {
|
|
530
|
+
if (!lowerCompact(entry).includes(needle)) continue;
|
|
531
|
+
try {
|
|
532
|
+
newest = Math.max(newest, fs.statSync(path.join(runsDir, entry)).mtimeMs || 0);
|
|
533
|
+
} catch { /* ignore unreadable activity entries */ }
|
|
534
|
+
}
|
|
535
|
+
return newest;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function memberLastActivity(name, paths = memberPaths(name), root = process.cwd()) {
|
|
539
|
+
const logsMs = newestMtimeRecursive(path.join(paths.memberDir, 'logs'));
|
|
540
|
+
const runsMs = newestRunActivityMtime(name, root);
|
|
541
|
+
const ms = Math.max(logsMs, runsMs);
|
|
542
|
+
return {
|
|
543
|
+
at_ms: ms,
|
|
544
|
+
age: ageLabelFromMs(ms),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function memberMissionSummary(name, missionMap = memberRunMissionMap()) {
|
|
549
|
+
const latest = memberLatestMission(name, missionMap);
|
|
550
|
+
const live = memberLiveMission(name, missionMap);
|
|
551
|
+
const lastTickMs = timestampMs(latest?.last_tick_at);
|
|
552
|
+
return {
|
|
553
|
+
latest,
|
|
554
|
+
live,
|
|
555
|
+
name: missionShortName(latest),
|
|
556
|
+
state: latest?.status || '-',
|
|
557
|
+
last_tick_at: latest?.last_tick_at || null,
|
|
558
|
+
last_tick_age: ageLabelFromMs(lastTickMs),
|
|
559
|
+
live_mission: Boolean(live),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function memberVerdict({ mission, activity }, nowMs = Date.now()) {
|
|
564
|
+
const activityAge = activity?.at_ms ? nowMs - activity.at_ms : Number.POSITIVE_INFINITY;
|
|
565
|
+
if (mission?.live_mission || activityAge < MEMBER_ACTIVE_ACTIVITY_MS) return 'ACTIVE';
|
|
566
|
+
if (activityAge < MEMBER_RECENT_ACTIVITY_MS) return 'RECENT';
|
|
567
|
+
return 'IDLE';
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function memberGoalPlaneStatus(name, paths = requireMemberDir(name)) {
|
|
571
|
+
const state = loadMemberGoals(name, paths);
|
|
572
|
+
const goal = activeGoal(state);
|
|
573
|
+
const current = memberOpenExperiment(state);
|
|
574
|
+
const lastReviewed = memberLastReviewedExperiment(state);
|
|
575
|
+
const value = memberValueSummary(state);
|
|
576
|
+
const logs = recentLogLines(paths.memberDir);
|
|
577
|
+
const needsUser = current?.status === 'blocked';
|
|
578
|
+
const stateLabel = !goal
|
|
579
|
+
? 'no_goal'
|
|
580
|
+
: needsUser
|
|
581
|
+
? 'needs_user'
|
|
582
|
+
: current
|
|
583
|
+
? current.status
|
|
584
|
+
: 'ready';
|
|
585
|
+
const ask = needsUser ? (current.block?.ask || 'Needs operator input.') : null;
|
|
586
|
+
const nextCommand = !goal
|
|
587
|
+
? `atris member goal ${name} "..."`
|
|
588
|
+
: needsUser
|
|
589
|
+
? `atris member review ${name} ${current.id} --discard --proof "..."`
|
|
590
|
+
: current
|
|
591
|
+
? `atris member review ${name} ${current.id} --accept --proof "..." --value 4`
|
|
592
|
+
: `atris member tick ${name}`;
|
|
593
|
+
return {
|
|
594
|
+
state,
|
|
595
|
+
goal,
|
|
596
|
+
current,
|
|
597
|
+
lastReviewed,
|
|
598
|
+
value,
|
|
599
|
+
logs,
|
|
600
|
+
needsUser,
|
|
601
|
+
stateLabel,
|
|
602
|
+
ask,
|
|
603
|
+
nextCommand,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
443
607
|
function resolveMemberRunMissionId(name, args = []) {
|
|
444
608
|
const override = readFlag(args, '--mission', '') || readFlag(args, '--mission-id', '');
|
|
445
609
|
if (override) return override;
|
|
@@ -3540,8 +3704,8 @@ function findAllMembers(teamDir) {
|
|
|
3540
3704
|
const entries = fs.readdirSync(teamDir);
|
|
3541
3705
|
|
|
3542
3706
|
for (const entry of entries) {
|
|
3543
|
-
// Skip template
|
|
3544
|
-
if (entry === '_template' || entry.startsWith('.')) continue;
|
|
3707
|
+
// Skip template/archive directories and hidden files
|
|
3708
|
+
if (entry === '_template' || entry === '_archive' || entry === '_archived' || entry.startsWith('.')) continue;
|
|
3545
3709
|
|
|
3546
3710
|
const fullPath = path.join(teamDir, entry);
|
|
3547
3711
|
const stat = fs.statSync(fullPath);
|
|
@@ -6876,6 +7040,7 @@ function readMemberScope(name, paths) {
|
|
|
6876
7040
|
function isAutoGeneratedArtifact(filePath, name) {
|
|
6877
7041
|
const memberLogs = `atris/team/${name}/logs/`;
|
|
6878
7042
|
if (filePath.startsWith(memberLogs)) return true;
|
|
7043
|
+
if (filePath === `atris/team/${name}/goals.json`) return true;
|
|
6879
7044
|
if (filePath === `atris/team/${name}/now.md`) return true;
|
|
6880
7045
|
return false;
|
|
6881
7046
|
}
|
|
@@ -7431,11 +7596,105 @@ async function memberWake(name, ...args) {
|
|
|
7431
7596
|
}
|
|
7432
7597
|
|
|
7433
7598
|
function memberAlive(name, ...args) {
|
|
7599
|
+
if (name === '--all' || name === 'all') return memberAliveAll(...args);
|
|
7434
7600
|
const nextArgs = args.includes('--alive') ? args : [...args, '--alive'];
|
|
7435
7601
|
return memberLoop(name, ...nextArgs);
|
|
7436
7602
|
}
|
|
7437
7603
|
|
|
7604
|
+
function collectFleetActivationRows(root = process.cwd()) {
|
|
7605
|
+
const teamDir = path.join(root, 'atris', 'team');
|
|
7606
|
+
const missionMap = memberRunMissionMap();
|
|
7607
|
+
return findAllMembers(teamDir)
|
|
7608
|
+
.filter(isFleetMember)
|
|
7609
|
+
.map((member) => {
|
|
7610
|
+
const slug = memberSlugFromRecord(member);
|
|
7611
|
+
const paths = memberPaths(slug);
|
|
7612
|
+
const goalPlane = memberGoalPlaneStatus(slug, paths);
|
|
7613
|
+
const activeMission = memberLiveMission(slug, missionMap);
|
|
7614
|
+
const latestMission = memberLatestMission(slug, missionMap);
|
|
7615
|
+
const skipped = !goalPlane.goal && !activeMission;
|
|
7616
|
+
return {
|
|
7617
|
+
member: slug,
|
|
7618
|
+
goal: goalPlane.goal || null,
|
|
7619
|
+
active_mission: activeMission || null,
|
|
7620
|
+
latest_mission: latestMission || null,
|
|
7621
|
+
skipped,
|
|
7622
|
+
skip_reason: skipped ? 'no_goal_and_no_active_mission' : null,
|
|
7623
|
+
};
|
|
7624
|
+
})
|
|
7625
|
+
.sort((a, b) => a.member.localeCompare(b.member));
|
|
7626
|
+
}
|
|
7627
|
+
|
|
7628
|
+
async function callMemberLoopForFleet(kind, member, args, captureOutput) {
|
|
7629
|
+
if (!captureOutput) {
|
|
7630
|
+
if (kind === 'alive') return memberAlive(member, ...args);
|
|
7631
|
+
return memberLoop(member, ...args);
|
|
7632
|
+
}
|
|
7633
|
+
const captured = [];
|
|
7634
|
+
const originalLog = console.log;
|
|
7635
|
+
console.log = (...parts) => captured.push(parts.join(' '));
|
|
7636
|
+
try {
|
|
7637
|
+
const result = kind === 'alive'
|
|
7638
|
+
? await memberAlive(member, ...args)
|
|
7639
|
+
: await memberLoop(member, ...args);
|
|
7640
|
+
return { result, output: captured };
|
|
7641
|
+
} finally {
|
|
7642
|
+
console.log = originalLog;
|
|
7643
|
+
}
|
|
7644
|
+
}
|
|
7645
|
+
|
|
7646
|
+
async function memberLoopAll(kind, ...args) {
|
|
7647
|
+
const asJson = hasFlag(args, '--json');
|
|
7648
|
+
const rows = collectFleetActivationRows();
|
|
7649
|
+
const activated = [];
|
|
7650
|
+
const skipped = [];
|
|
7651
|
+
if (!asJson) console.log(`Member fleet ${kind}`);
|
|
7652
|
+
for (const row of rows) {
|
|
7653
|
+
if (row.skipped) {
|
|
7654
|
+
skipped.push(row);
|
|
7655
|
+
if (!asJson) console.log(`Skip ${row.member}: no goal and no active mission.`);
|
|
7656
|
+
continue;
|
|
7657
|
+
}
|
|
7658
|
+
if (!asJson) console.log(`Activate ${row.member}: ${row.goal ? 'goal' : `mission ${row.active_mission?.id || 'active'}`}`);
|
|
7659
|
+
const result = await callMemberLoopForFleet(kind, row.member, args, asJson);
|
|
7660
|
+
activated.push({
|
|
7661
|
+
member: row.member,
|
|
7662
|
+
reason: row.goal ? 'has_goal' : 'has_active_mission',
|
|
7663
|
+
mission_id: row.active_mission?.id || null,
|
|
7664
|
+
result: asJson ? result?.result || null : null,
|
|
7665
|
+
output: asJson ? result?.output || [] : undefined,
|
|
7666
|
+
});
|
|
7667
|
+
}
|
|
7668
|
+
const reasonCounts = skipped.reduce((acc, row) => {
|
|
7669
|
+
acc[row.skip_reason] = (acc[row.skip_reason] || 0) + 1;
|
|
7670
|
+
return acc;
|
|
7671
|
+
}, {});
|
|
7672
|
+
const payload = {
|
|
7673
|
+
ok: true,
|
|
7674
|
+
action: `${kind}_all`,
|
|
7675
|
+
activated: activated.length,
|
|
7676
|
+
skipped: skipped.length,
|
|
7677
|
+
skipped_reasons: reasonCounts,
|
|
7678
|
+
activated_members: activated,
|
|
7679
|
+
skipped_members: skipped.map((row) => ({
|
|
7680
|
+
member: row.member,
|
|
7681
|
+
reason: row.skip_reason,
|
|
7682
|
+
latest_mission_id: row.latest_mission?.id || null,
|
|
7683
|
+
latest_mission_status: row.latest_mission?.status || null,
|
|
7684
|
+
})),
|
|
7685
|
+
};
|
|
7686
|
+
printJsonOrText(payload, [
|
|
7687
|
+
`Summary: ${activated.length} activated, ${skipped.length} skipped (${Object.entries(reasonCounts).map(([reason, count]) => `${reason} x${count}`).join(', ') || 'none'}).`,
|
|
7688
|
+
], asJson);
|
|
7689
|
+
return payload;
|
|
7690
|
+
}
|
|
7691
|
+
|
|
7692
|
+
function memberAliveAll(...args) {
|
|
7693
|
+
return memberLoopAll('alive', ...args);
|
|
7694
|
+
}
|
|
7695
|
+
|
|
7438
7696
|
async function memberLoop(name, ...args) {
|
|
7697
|
+
if (name === '--all' || name === 'all') return memberLoopAll('loop', ...args);
|
|
7439
7698
|
requireMemberDir(name);
|
|
7440
7699
|
const asJson = hasFlag(args, '--json');
|
|
7441
7700
|
const aliveMode = hasFlag(args, '--alive');
|
|
@@ -7962,44 +8221,136 @@ function memberBlock(name, experimentId, ...args) {
|
|
|
7962
8221
|
);
|
|
7963
8222
|
}
|
|
7964
8223
|
|
|
8224
|
+
function collectFleetMemberStatus(root = process.cwd()) {
|
|
8225
|
+
const teamDir = path.join(root, 'atris', 'team');
|
|
8226
|
+
const missionMap = memberRunMissionMap();
|
|
8227
|
+
return findAllMembers(teamDir)
|
|
8228
|
+
.filter(isFleetMember)
|
|
8229
|
+
.map((member) => {
|
|
8230
|
+
const slug = memberSlugFromRecord(member);
|
|
8231
|
+
const paths = memberPaths(slug);
|
|
8232
|
+
const goalPlane = memberGoalPlaneStatus(slug, paths);
|
|
8233
|
+
const mission = memberMissionSummary(slug, missionMap);
|
|
8234
|
+
const activity = memberLastActivity(slug, paths, root);
|
|
8235
|
+
const verdict = memberVerdict({ mission, activity });
|
|
8236
|
+
return {
|
|
8237
|
+
member: slug,
|
|
8238
|
+
role: member.role,
|
|
8239
|
+
goal_state: goalPlane.stateLabel,
|
|
8240
|
+
goal_title: goalPlane.goal?.title || null,
|
|
8241
|
+
mission: mission.latest ? {
|
|
8242
|
+
id: mission.latest.id || null,
|
|
8243
|
+
name: mission.name,
|
|
8244
|
+
state: mission.state,
|
|
8245
|
+
last_tick_at: mission.last_tick_at,
|
|
8246
|
+
last_tick_age: mission.last_tick_age,
|
|
8247
|
+
live: mission.live_mission,
|
|
8248
|
+
} : null,
|
|
8249
|
+
last_activity: activity,
|
|
8250
|
+
verdict,
|
|
8251
|
+
};
|
|
8252
|
+
})
|
|
8253
|
+
.sort((a, b) => a.member.localeCompare(b.member));
|
|
8254
|
+
}
|
|
8255
|
+
|
|
8256
|
+
function clipCell(value, width) {
|
|
8257
|
+
const clean = String(value || '-').replace(/\s+/g, ' ').trim() || '-';
|
|
8258
|
+
if (clean.length <= width) return clean.padEnd(width);
|
|
8259
|
+
if (width <= 3) return clean.slice(0, width);
|
|
8260
|
+
return `${clean.slice(0, width - 3)}...`;
|
|
8261
|
+
}
|
|
8262
|
+
|
|
8263
|
+
function renderMemberFleetStatusTable(rows) {
|
|
8264
|
+
if (!rows.length) return ['No active team members found in atris/team/.'];
|
|
8265
|
+
const widths = {
|
|
8266
|
+
member: 18,
|
|
8267
|
+
goal: 11,
|
|
8268
|
+
mission: 34,
|
|
8269
|
+
state: 10,
|
|
8270
|
+
tick: 8,
|
|
8271
|
+
activity: 8,
|
|
8272
|
+
verdict: 8,
|
|
8273
|
+
};
|
|
8274
|
+
const header = [
|
|
8275
|
+
clipCell('Member', widths.member),
|
|
8276
|
+
clipCell('Goal', widths.goal),
|
|
8277
|
+
clipCell('Mission', widths.mission),
|
|
8278
|
+
clipCell('State', widths.state),
|
|
8279
|
+
clipCell('Tick', widths.tick),
|
|
8280
|
+
clipCell('Activity', widths.activity),
|
|
8281
|
+
clipCell('Verdict', widths.verdict),
|
|
8282
|
+
].join(' ');
|
|
8283
|
+
const rule = [
|
|
8284
|
+
'-'.repeat(widths.member),
|
|
8285
|
+
'-'.repeat(widths.goal),
|
|
8286
|
+
'-'.repeat(widths.mission),
|
|
8287
|
+
'-'.repeat(widths.state),
|
|
8288
|
+
'-'.repeat(widths.tick),
|
|
8289
|
+
'-'.repeat(widths.activity),
|
|
8290
|
+
'-'.repeat(widths.verdict),
|
|
8291
|
+
].join(' ');
|
|
8292
|
+
return [
|
|
8293
|
+
'Member fleet status',
|
|
8294
|
+
header,
|
|
8295
|
+
rule,
|
|
8296
|
+
...rows.map((row) => [
|
|
8297
|
+
clipCell(row.member, widths.member),
|
|
8298
|
+
clipCell(row.goal_state, widths.goal),
|
|
8299
|
+
clipCell(row.mission?.name || '-', widths.mission),
|
|
8300
|
+
clipCell(row.mission?.state || '-', widths.state),
|
|
8301
|
+
clipCell(row.mission?.last_tick_age || '-', widths.tick),
|
|
8302
|
+
clipCell(row.last_activity?.age || '-', widths.activity),
|
|
8303
|
+
clipCell(row.verdict, widths.verdict),
|
|
8304
|
+
].join(' ')),
|
|
8305
|
+
];
|
|
8306
|
+
}
|
|
8307
|
+
|
|
8308
|
+
function memberStatusAll(...args) {
|
|
8309
|
+
const asJson = hasFlag(args, '--json');
|
|
8310
|
+
const rows = collectFleetMemberStatus();
|
|
8311
|
+
printJsonOrText(
|
|
8312
|
+
{
|
|
8313
|
+
ok: true,
|
|
8314
|
+
action: 'status_all',
|
|
8315
|
+
members: rows,
|
|
8316
|
+
},
|
|
8317
|
+
renderMemberFleetStatusTable(rows),
|
|
8318
|
+
asJson,
|
|
8319
|
+
);
|
|
8320
|
+
}
|
|
8321
|
+
|
|
7965
8322
|
function memberStatus(name, ...args) {
|
|
8323
|
+
if (name === '--all' || name === 'all') return memberStatusAll(...args);
|
|
7966
8324
|
const paths = requireMemberDir(name);
|
|
7967
8325
|
const asJson = hasFlag(args, '--json');
|
|
7968
|
-
const
|
|
7969
|
-
const
|
|
7970
|
-
const
|
|
7971
|
-
const
|
|
7972
|
-
const
|
|
7973
|
-
const logs = recentLogLines(paths.memberDir);
|
|
7974
|
-
const needsUser = current?.status === 'blocked';
|
|
7975
|
-
const stateLabel = !goal
|
|
7976
|
-
? 'no_goal'
|
|
7977
|
-
: needsUser
|
|
7978
|
-
? 'needs_user'
|
|
7979
|
-
: current
|
|
7980
|
-
? current.status
|
|
7981
|
-
: 'ready';
|
|
7982
|
-
const ask = needsUser ? (current.block?.ask || 'Needs operator input.') : null;
|
|
7983
|
-
const nextCommand = !goal
|
|
7984
|
-
? `atris member goal ${name} "..."`
|
|
7985
|
-
: needsUser
|
|
7986
|
-
? `atris member review ${name} ${current.id} --discard --proof "..."`
|
|
7987
|
-
: current
|
|
7988
|
-
? `atris member review ${name} ${current.id} --accept --proof "..." --value 4`
|
|
7989
|
-
: `atris member tick ${name}`;
|
|
8326
|
+
const goalPlane = memberGoalPlaneStatus(name, paths);
|
|
8327
|
+
const owner = paths.storageName || name;
|
|
8328
|
+
const mission = memberMissionSummary(owner, memberRunMissionMap());
|
|
8329
|
+
const activity = memberLastActivity(owner, paths);
|
|
8330
|
+
const verdict = memberVerdict({ mission, activity });
|
|
7990
8331
|
const payload = {
|
|
7991
8332
|
ok: true,
|
|
7992
8333
|
action: 'status',
|
|
7993
8334
|
member: name,
|
|
7994
|
-
state: stateLabel,
|
|
7995
|
-
needs_user: needsUser,
|
|
7996
|
-
ask,
|
|
7997
|
-
active_goal: goal || null,
|
|
7998
|
-
current_experiment: current || null,
|
|
7999
|
-
last_reviewed: lastReviewed || null,
|
|
8000
|
-
value,
|
|
8001
|
-
|
|
8002
|
-
|
|
8335
|
+
state: goalPlane.stateLabel,
|
|
8336
|
+
needs_user: goalPlane.needsUser,
|
|
8337
|
+
ask: goalPlane.ask,
|
|
8338
|
+
active_goal: goalPlane.goal || null,
|
|
8339
|
+
current_experiment: goalPlane.current || null,
|
|
8340
|
+
last_reviewed: goalPlane.lastReviewed || null,
|
|
8341
|
+
value: goalPlane.value,
|
|
8342
|
+
mission: mission.latest ? {
|
|
8343
|
+
id: mission.latest.id || null,
|
|
8344
|
+
name: mission.name,
|
|
8345
|
+
state: mission.state,
|
|
8346
|
+
last_tick_at: mission.last_tick_at,
|
|
8347
|
+
last_tick_age: mission.last_tick_age,
|
|
8348
|
+
live: mission.live_mission,
|
|
8349
|
+
} : null,
|
|
8350
|
+
last_activity: activity,
|
|
8351
|
+
verdict,
|
|
8352
|
+
next_command: goalPlane.nextCommand,
|
|
8353
|
+
recent_log: goalPlane.logs,
|
|
8003
8354
|
goals_path: paths.goalsJson,
|
|
8004
8355
|
goals_md_path: paths.goalsMd,
|
|
8005
8356
|
};
|
|
@@ -8007,13 +8358,16 @@ function memberStatus(name, ...args) {
|
|
|
8007
8358
|
payload,
|
|
8008
8359
|
[
|
|
8009
8360
|
`Member: ${name}`,
|
|
8010
|
-
`State: ${stateLabel}`,
|
|
8011
|
-
`Goal: ${goal?.title || 'No goal yet'}`,
|
|
8012
|
-
`Current: ${current ? `${current.status} - ${current.title}` : 'No open experiment'}`,
|
|
8013
|
-
...(ask ? [`Ask: ${ask}`] : []),
|
|
8014
|
-
`Value: ${value.line}`,
|
|
8015
|
-
`
|
|
8016
|
-
|
|
8361
|
+
`State: ${goalPlane.stateLabel}`,
|
|
8362
|
+
`Goal: ${goalPlane.goal?.title || 'No goal yet'}`,
|
|
8363
|
+
`Current: ${goalPlane.current ? `${goalPlane.current.status} - ${goalPlane.current.title}` : 'No open experiment'}`,
|
|
8364
|
+
...(goalPlane.ask ? [`Ask: ${goalPlane.ask}`] : []),
|
|
8365
|
+
`Value: ${goalPlane.value.line}`,
|
|
8366
|
+
`Mission: ${mission.latest ? `${mission.name} (${mission.state}, last tick ${mission.last_tick_age})` : 'No owned mission'}`,
|
|
8367
|
+
`Activity: ${activity.age}`,
|
|
8368
|
+
`Verdict: ${verdict}`,
|
|
8369
|
+
`Next: ${goalPlane.nextCommand}`,
|
|
8370
|
+
...(goalPlane.logs.length ? ['Recent log:', ...goalPlane.logs.map((line) => ` ${line}`)] : []),
|
|
8017
8371
|
],
|
|
8018
8372
|
asJson,
|
|
8019
8373
|
);
|
|
@@ -8186,11 +8540,11 @@ async function memberCommand(subcommand, ...args) {
|
|
|
8186
8540
|
console.log(' goal-from-score <name> Create/reuse an active goal from Team score evidence');
|
|
8187
8541
|
console.log(' wake <name> Read Mission state and decide tick/wait/ask/stop');
|
|
8188
8542
|
console.log(' run <name> ["..."] Start a budgeted member mission, or run its active Mission Runtime');
|
|
8189
|
-
console.log(' loop <name>
|
|
8543
|
+
console.log(' loop <name|--all> Repeat wake on a bounded cadence with a no-overlap lease');
|
|
8190
8544
|
console.log(' tick <name> Propose the next bounded experiment');
|
|
8191
8545
|
console.log(' review <name> <id> Accept/discard an experiment with proof');
|
|
8192
8546
|
console.log(' block <name> <id> Mark an experiment blocked with a human/orchestrator ask');
|
|
8193
|
-
console.log(' status <name>
|
|
8547
|
+
console.log(' status <name|--all> Show goal, mission, activity, value, ask, and recent log');
|
|
8194
8548
|
console.log(' history <name> Show git history of member identity files (MEMBER.md, SOUL.md)');
|
|
8195
8549
|
console.log(' supervisor recommendations Show advisory supervisor recommendations');
|
|
8196
8550
|
console.log(' objective-generator proposals Show autonomous objective proposal');
|
|
@@ -8225,10 +8579,12 @@ async function memberCommand(subcommand, ...args) {
|
|
|
8225
8579
|
console.log(' atris member loop growth --minutes 10 --interval 60 --json');
|
|
8226
8580
|
console.log(' atris member alive growth --hourly --forever --execute --confirm-autonomy-policy --json');
|
|
8227
8581
|
console.log(' atris member alive growth --install --hourly --forever --execute --confirm-autonomy-policy --json');
|
|
8582
|
+
console.log(' atris member alive --all --install --hourly --forever --dry-run');
|
|
8228
8583
|
console.log(' atris member alive growth --minutes 480 --interval 900 --execute --confirm-autonomy-policy --json');
|
|
8229
8584
|
console.log(' atris member loop growth --ticks 2 --interval 0 --json');
|
|
8230
8585
|
console.log(' atris member tick growth --json');
|
|
8231
8586
|
console.log(' atris member status growth');
|
|
8587
|
+
console.log(' atris member status --all');
|
|
8232
8588
|
console.log(' atris member review growth exp_123 --accept --proof "validated" --value 4');
|
|
8233
8589
|
console.log(' atris member archive old-member');
|
|
8234
8590
|
console.log(' atris member purge-archived --days=60 --confirm "delete archived members"');
|