atris 3.34.0 → 3.36.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 +35 -0
- package/FOR_AGENTS.md +5 -3
- package/README.md +5 -3
- package/atris/GETTING_STARTED.md +1 -1
- package/atris/atris.md +3 -0
- package/atris/policies/day-loop-voice.md +102 -0
- package/atris/policies/outbound-artifact-gate.md +2 -0
- package/atris/skills/design/SKILL.md +56 -32
- package/atris/skills/endgame/SKILL.md +12 -6
- package/atris/skills/engines/SKILL.md +35 -8
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/render-cli/SKILL.md +88 -0
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +6 -2
- package/ax +617 -31
- package/bin/atris.js +719 -266
- package/commands/activate.js +194 -88
- package/commands/aeo.js +52 -0
- package/commands/agents.js +166 -0
- package/commands/autoland.js +718 -72
- package/commands/autopilot-front.js +20 -2
- package/commands/autopilot.js +118 -2
- package/commands/avail.js +407 -0
- package/commands/bench.js +188 -0
- package/commands/brain.js +3 -0
- package/commands/brief.js +651 -0
- package/commands/business-sync.js +192 -6
- package/commands/business.js +91 -8
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/codex-goal.js +26 -2
- package/commands/compile.js +292 -1
- package/commands/computer.js +150 -3
- package/commands/dream.js +365 -0
- package/commands/drill.js +371 -0
- package/commands/drive.js +187 -0
- package/commands/engine.js +1061 -29
- package/commands/experiments.js +28 -0
- package/commands/feed.js +202 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/github.js +38 -0
- package/commands/gm.js +285 -3
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +83 -43
- package/commands/integrations.js +39 -11
- package/commands/interview.js +209 -0
- package/commands/land.js +253 -52
- package/commands/lesson.js +112 -1
- package/commands/lifecycle.js +39 -3
- package/commands/linear.js +38 -0
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +899 -66
- package/commands/mission.js +3512 -332
- package/commands/next.js +137 -0
- package/commands/now.js +240 -21
- package/commands/one-lap.js +776 -0
- package/commands/orb.js +314 -0
- package/commands/pack-craft.js +179 -0
- package/commands/pack.js +823 -0
- package/commands/play.js +3 -2
- package/commands/probe.js +30 -3
- package/commands/pulse.js +241 -46
- package/commands/push.js +260 -82
- package/commands/radar.js +259 -14
- package/commands/rainmaker.js +49 -0
- package/commands/report.js +415 -0
- package/commands/scout.js +147 -0
- package/commands/search.js +363 -0
- package/commands/serve.js +54 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/status.js +50 -5
- package/commands/stream.js +861 -0
- package/commands/stripe.js +38 -0
- package/commands/study.js +693 -0
- package/commands/supabase.js +39 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +2275 -182
- package/commands/team.js +73 -0
- 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/verify.js +96 -0
- package/commands/watch.js +303 -0
- package/commands/wish.js +500 -0
- package/commands/workflow.js +11 -5
- package/commands/worktree.js +299 -20
- package/commands/write.js +399 -0
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +391 -43
- package/lib/autoland.js +353 -52
- package/lib/ax-auto-lane.js +79 -0
- package/lib/bench/context.js +147 -0
- package/lib/bench/engines.js +141 -0
- package/lib/bench/report.js +140 -0
- package/lib/bench/runner.js +512 -0
- package/lib/brief-ledger.js +350 -0
- package/lib/cloud-mission.js +259 -0
- package/lib/codex-flight.js +154 -0
- package/lib/default-runner.js +45 -0
- package/lib/default-verifier.js +70 -0
- package/lib/engine-registry.js +232 -0
- package/lib/experiments/daily.js +640 -0
- package/lib/fleet.js +2431 -38
- package/lib/improve-vitals-html.js +171 -0
- package/lib/known-commands.js +58 -0
- package/lib/loop-doctor.js +416 -0
- package/lib/member-switches.js +144 -0
- package/lib/memory-view.js +14 -5
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/mission-runtime-loop.js +7 -0
- package/lib/next-moves.js +327 -10
- package/lib/official-cli-integration.js +174 -0
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/outbound-send-gate.js +165 -0
- package/lib/permission-grants.js +293 -0
- package/lib/policy-lessons.js +52 -1
- package/lib/pulse.js +277 -3
- package/lib/receipt-block.js +168 -0
- package/lib/receipt-evidence.js +65 -4
- package/lib/review-integrity.js +147 -0
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +33 -0
- package/lib/self-drive.js +258 -0
- package/lib/short-name.js +103 -0
- package/lib/spawn-env.js +18 -0
- package/lib/state-detection.js +56 -1
- package/lib/sync-status.js +59 -0
- package/lib/task-db.js +319 -27
- package/lib/task-proof.js +43 -1
- package/lib/task-receipt.js +93 -0
- package/lib/team-presence.js +260 -0
- package/lib/tool-result-encode.js +7 -0
- package/lib/trust-tiers.js +90 -0
- package/lib/usage.js +107 -0
- package/lib/voice-gate.js +163 -0
- package/lib/wish-audit.js +1368 -0
- package/lib/wish-delegate.js +1840 -0
- package/lib/wish-design.js +110 -0
- package/lib/wish-stats.js +183 -0
- package/lib/wish-store.js +354 -0
- package/lib/zip.js +221 -0
- package/package.json +3 -1
- package/templates/loops/atris/loops/LOOPS.md +55 -0
- package/templates/loops/atris/loops/TICK.md +24 -0
- package/templates/loops/atris/loops/feedback.md +22 -0
- package/templates/loops/atris/loops/quality.md +22 -0
- package/templates/loops/atris/wiki/systems/loops.md +41 -0
- package/utils/api.js +5 -1
- package/utils/auth.js +57 -21
- package/utils/update-check.js +27 -6
- package/atris/learnings.jsonl +0 -1
package/commands/radar.js
CHANGED
|
@@ -100,6 +100,7 @@ function collectAgents(deps) {
|
|
|
100
100
|
return {
|
|
101
101
|
pid: row.pid,
|
|
102
102
|
agent: row.agent,
|
|
103
|
+
command: row.command,
|
|
103
104
|
status: row.stat.includes('Z') ? 'zombie' : row.stat.includes('T') ? 'stopped' : 'active',
|
|
104
105
|
cwd,
|
|
105
106
|
repo: repoLabel(cwd),
|
|
@@ -148,7 +149,8 @@ function loadTasksCached(root, deps, cache) {
|
|
|
148
149
|
return cache.get(root);
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
function untaskedReason(agent, taskWorkspaceRoot, tasks) {
|
|
152
|
+
function untaskedReason(agent, taskWorkspaceRoot, tasks, binding = null) {
|
|
153
|
+
if (binding?.interactive) return 'interactive session';
|
|
152
154
|
if (!agent.cwd) return 'cwd unknown';
|
|
153
155
|
if (!taskWorkspaceRoot) return 'no task projection';
|
|
154
156
|
if (!tasks.length) return 'empty task projection';
|
|
@@ -159,10 +161,11 @@ function shellQuote(value) {
|
|
|
159
161
|
return `'${String(value || '').replace(/'/g, "'\\''")}'`;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
function untaskedAction(agent, taskWorkspaceRoot, tasks) {
|
|
163
|
-
const reason = untaskedReason(agent, taskWorkspaceRoot, tasks);
|
|
164
|
+
function untaskedAction(agent, taskWorkspaceRoot, tasks, binding = null) {
|
|
165
|
+
const reason = untaskedReason(agent, taskWorkspaceRoot, tasks, binding);
|
|
164
166
|
const pid = agent.pid || '?';
|
|
165
167
|
const actor = agent.agent || 'agent';
|
|
168
|
+
if (reason === 'interactive session') return `inspect pid ${pid} interactive claude session; bind via member lock, worktree sidecar, or branch identity before assuming a repo task`;
|
|
166
169
|
if (reason === 'cwd unknown') return `inspect pid ${pid} cwd with lsof`;
|
|
167
170
|
if (reason === 'no active task') return `cd ${shellQuote(taskWorkspaceRoot)} && atris task next --as ${actor}`;
|
|
168
171
|
if (reason === 'empty task projection') return `cd ${shellQuote(taskWorkspaceRoot)} && atris task new "<small concrete title>" --tag ops`;
|
|
@@ -410,6 +413,213 @@ function taskRef(task) {
|
|
|
410
413
|
return task ? (task.display_id || task.legacy_ref || task.id || '-') : '-';
|
|
411
414
|
}
|
|
412
415
|
|
|
416
|
+
function isInteractiveClaudeCommand(command) {
|
|
417
|
+
const cmd = String(command || '');
|
|
418
|
+
if (!/(^|\s|\/)claude(\s|$)/.test(cmd) || /Claude\.app/.test(cmd)) return false;
|
|
419
|
+
return !/(^|\s)-p(\s|$)/.test(cmd) && !/(^|\s)--print(\s|$)/.test(cmd);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function parseSessionIdFromCommand(command) {
|
|
423
|
+
const parts = String(command || '').split(/\s+/);
|
|
424
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
425
|
+
if ((parts[i] === '--session-id' || parts[i] === '--resume') && parts[i + 1]) return parts[i + 1];
|
|
426
|
+
const inline = parts[i].match(/^--session-id=(.+)$/);
|
|
427
|
+
if (inline) return inline[1];
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function loadAgentWorktreeSidecar(cwd, deps) {
|
|
433
|
+
if (!cwd) return null;
|
|
434
|
+
let current = path.resolve(cwd);
|
|
435
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
436
|
+
const payload = readJsonFile(path.join(current, '.atris', 'agent-worktree.json'), deps, null);
|
|
437
|
+
if (payload) return payload;
|
|
438
|
+
const parent = path.dirname(current);
|
|
439
|
+
if (!parent || parent === current) break;
|
|
440
|
+
current = parent;
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function branchIdentityAtCwd(cwd, execFile) {
|
|
446
|
+
if (!cwd) return null;
|
|
447
|
+
try {
|
|
448
|
+
const branch = String(execFile('git', ['-C', cwd, 'branch', '--show-current'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] })).trim();
|
|
449
|
+
if (!branch) return null;
|
|
450
|
+
const owner = String(execFile('git', ['-C', cwd, 'config', '--get', `branch.${branch}.atris-owner`], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] })).trim();
|
|
451
|
+
const taskHint = String(execFile('git', ['-C', cwd, 'config', '--get', `branch.${branch}.atris-task`], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] })).trim();
|
|
452
|
+
if (!owner) return null;
|
|
453
|
+
return { owner, task_hint: taskHint || null, branch };
|
|
454
|
+
} catch {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function loadMissionLocks(stateDir, deps) {
|
|
460
|
+
const locks = [];
|
|
461
|
+
for (const name of listNames(stateDir, deps)) {
|
|
462
|
+
const match = name.match(/^mission-(.+)\.lock$/);
|
|
463
|
+
if (!match) continue;
|
|
464
|
+
const payload = readJsonFile(path.join(stateDir, name), deps, null);
|
|
465
|
+
if (!payload || payload.pid == null) continue;
|
|
466
|
+
locks.push({
|
|
467
|
+
...payload,
|
|
468
|
+
mission_id: payload.mission_id || match[1],
|
|
469
|
+
lock_file: name,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
return locks;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function loadMemberLoopLocks(stateDir, deps) {
|
|
476
|
+
const dir = path.join(stateDir, 'member-loops');
|
|
477
|
+
const locks = [];
|
|
478
|
+
for (const name of listNames(dir, deps)) {
|
|
479
|
+
if (!name.endsWith('.lock.json')) continue;
|
|
480
|
+
const payload = readJsonFile(path.join(dir, name), deps, null);
|
|
481
|
+
if (!payload || payload.pid == null) continue;
|
|
482
|
+
locks.push({
|
|
483
|
+
...payload,
|
|
484
|
+
member: payload.member || name.replace(/\.lock\.json$/, ''),
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
return locks;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function loadWorkspaceIdentity(root, deps, cache, nowMs) {
|
|
491
|
+
if (!root) return { missions: [], missionLocks: [], memberLocks: [] };
|
|
492
|
+
if (cache.has(root)) return cache.get(root);
|
|
493
|
+
const stateDir = path.join(root, '.atris', 'state');
|
|
494
|
+
const bundle = {
|
|
495
|
+
missions: loadMissions(root, deps, nowMs),
|
|
496
|
+
missionLocks: loadMissionLocks(stateDir, deps),
|
|
497
|
+
memberLocks: loadMemberLoopLocks(stateDir, deps),
|
|
498
|
+
};
|
|
499
|
+
cache.set(root, bundle);
|
|
500
|
+
return bundle;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function taskOwnerValues(task) {
|
|
504
|
+
return [
|
|
505
|
+
task?.assigned_to,
|
|
506
|
+
task?.claimed_by,
|
|
507
|
+
task?.metadata?.assigned_to,
|
|
508
|
+
task?.metadata?.claimed_by,
|
|
509
|
+
task?.metadata?.owner,
|
|
510
|
+
].filter(Boolean).map(value => String(value));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function taskMatchesOwner(task, owner) {
|
|
514
|
+
if (!task || !owner) return false;
|
|
515
|
+
const want = String(owner).toLowerCase();
|
|
516
|
+
return taskOwnerValues(task).some(value => value.toLowerCase() === want);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function findTaskByRef(tasks, ref) {
|
|
520
|
+
if (!ref) return null;
|
|
521
|
+
return tasks.find(task => taskRef(task) === ref) || null;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function taskForOwner(tasks, owner, statuses = ['claimed', 'open', 'review']) {
|
|
525
|
+
if (!owner) return null;
|
|
526
|
+
for (const status of statuses) {
|
|
527
|
+
const matches = tasks.filter(task => task.status === status && taskMatchesOwner(task, owner));
|
|
528
|
+
if (matches.length === 1) return matches[0];
|
|
529
|
+
if (matches.length > 1) return matches[0];
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function resolveAgentTaskBinding(context) {
|
|
535
|
+
const {
|
|
536
|
+
agent,
|
|
537
|
+
tasks,
|
|
538
|
+
missions,
|
|
539
|
+
missionLocks,
|
|
540
|
+
memberLocks,
|
|
541
|
+
sidecar,
|
|
542
|
+
branchIdentity,
|
|
543
|
+
sessionId,
|
|
544
|
+
interactive,
|
|
545
|
+
taskWorkspaceRoot,
|
|
546
|
+
} = context;
|
|
547
|
+
const pid = String(agent?.pid || '');
|
|
548
|
+
|
|
549
|
+
const missionLock = missionLocks.find(row => String(row.pid) === pid);
|
|
550
|
+
if (missionLock) {
|
|
551
|
+
const mission = missions.find(row => row.id === missionLock.mission_id);
|
|
552
|
+
const task = findTaskByRef(tasks, mission?.task_spine?.task_ref) || taskForOwner(tasks, mission?.owner);
|
|
553
|
+
return {
|
|
554
|
+
task,
|
|
555
|
+
owner: mission?.owner || ownerForTask(task),
|
|
556
|
+
member: mission?.owner || sidecar?.member || null,
|
|
557
|
+
session_id: mission?.claude_session_id || sessionId || null,
|
|
558
|
+
mission_id: mission?.id || missionLock.mission_id,
|
|
559
|
+
...taskBinding('mission_lock', 'process'),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const memberLock = memberLocks.find(row => String(row.pid) === pid);
|
|
564
|
+
if (memberLock) {
|
|
565
|
+
const task = taskForOwner(tasks, memberLock.member);
|
|
566
|
+
return {
|
|
567
|
+
task,
|
|
568
|
+
owner: memberLock.member,
|
|
569
|
+
member: memberLock.member,
|
|
570
|
+
session_id: sessionId || null,
|
|
571
|
+
...taskBinding('member_loop_lock', 'process'),
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (sessionId) {
|
|
576
|
+
const mission = missions.find(row => row.claude_session_id === sessionId || row.pending_session_id === sessionId);
|
|
577
|
+
if (mission) {
|
|
578
|
+
const task = findTaskByRef(tasks, mission.task_spine?.task_ref) || taskForOwner(tasks, mission.owner);
|
|
579
|
+
return {
|
|
580
|
+
task,
|
|
581
|
+
owner: mission.owner || ownerForTask(task),
|
|
582
|
+
member: mission.owner || sidecar?.member || null,
|
|
583
|
+
session_id: sessionId,
|
|
584
|
+
mission_id: mission.id,
|
|
585
|
+
...taskBinding('claude_session', 'process'),
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const ownerHint = sidecar?.owner || sidecar?.member || branchIdentity?.owner || null;
|
|
591
|
+
if (ownerHint) {
|
|
592
|
+
const task = taskForOwner(tasks, ownerHint);
|
|
593
|
+
return {
|
|
594
|
+
task,
|
|
595
|
+
owner: ownerHint,
|
|
596
|
+
member: sidecar?.member || ownerHint,
|
|
597
|
+
session_id: sessionId || null,
|
|
598
|
+
...taskBinding(sidecar ? 'agent_worktree' : 'branch_identity', 'process'),
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (interactive) {
|
|
603
|
+
return {
|
|
604
|
+
task: null,
|
|
605
|
+
owner: 'interactive',
|
|
606
|
+
member: null,
|
|
607
|
+
session_id: sessionId || null,
|
|
608
|
+
interactive: true,
|
|
609
|
+
...taskBinding('interactive_session', 'process'),
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const fallbackTask = taskForCwd(tasks, agent?.cwd, taskWorkspaceRoot, agent);
|
|
614
|
+
return {
|
|
615
|
+
task: fallbackTask,
|
|
616
|
+
owner: ownerForTask(fallbackTask),
|
|
617
|
+
member: null,
|
|
618
|
+
session_id: sessionId || null,
|
|
619
|
+
...(fallbackTask ? taskBinding('repo_task_projection', 'repo') : taskBinding(null, null)),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
413
623
|
function taskOwnerMatchesAgent(task, agent) {
|
|
414
624
|
const actor = String(agent?.agent || '').toLowerCase();
|
|
415
625
|
if (!actor) return false;
|
|
@@ -438,15 +648,22 @@ function taskForCwd(tasks, cwd, workspaceRoot = cwd, agent = null) {
|
|
|
438
648
|
|| null;
|
|
439
649
|
}
|
|
440
650
|
|
|
651
|
+
function taskBinding(source, scope = null) {
|
|
652
|
+
if (!source) return { task_source: null, task_scope: null };
|
|
653
|
+
return { task_source: source, task_scope: scope };
|
|
654
|
+
}
|
|
655
|
+
|
|
441
656
|
function taskBindingForProjection(task) {
|
|
442
|
-
|
|
443
|
-
return {
|
|
444
|
-
task_source: 'repo_task_projection',
|
|
445
|
-
task_scope: 'repo',
|
|
446
|
-
};
|
|
657
|
+
return task ? taskBinding('repo_task_projection', 'repo') : taskBinding(null, null);
|
|
447
658
|
}
|
|
448
659
|
|
|
449
660
|
function taskSourceLabel(sources = []) {
|
|
661
|
+
if (sources.includes('member_loop_lock')) return 'member loop lock';
|
|
662
|
+
if (sources.includes('mission_lock')) return 'mission lock';
|
|
663
|
+
if (sources.includes('claude_session')) return 'claude session id';
|
|
664
|
+
if (sources.includes('agent_worktree')) return 'agent worktree sidecar';
|
|
665
|
+
if (sources.includes('branch_identity')) return 'branch identity';
|
|
666
|
+
if (sources.includes('interactive_session')) return 'interactive session';
|
|
450
667
|
if (sources.includes('repo_task_projection')) return 'repo projection; verify ownership';
|
|
451
668
|
return sources.filter(Boolean).join(', ');
|
|
452
669
|
}
|
|
@@ -556,23 +773,45 @@ function collectRadar(options = {}) {
|
|
|
556
773
|
const nowMs = options.nowMs || Date.now();
|
|
557
774
|
const tasks = loadTasks(root, deps);
|
|
558
775
|
const taskCache = new Map([[root, tasks]]);
|
|
776
|
+
const identityCache = new Map();
|
|
559
777
|
const missions = loadMissions(root, deps, nowMs);
|
|
778
|
+
identityCache.set(root, { missions, missionLocks: loadMissionLocks(path.join(root, '.atris', 'state'), deps), memberLocks: loadMemberLoopLocks(path.join(root, '.atris', 'state'), deps) });
|
|
560
779
|
const worktrees = loadWorktrees(root, deps);
|
|
561
780
|
const agents = collectAgents(deps).map(agent => {
|
|
562
781
|
const taskWorkspaceRoot = findTaskWorkspaceRoot(agent.cwd, deps);
|
|
563
782
|
const agentTasks = taskWorkspaceRoot ? loadTasksCached(taskWorkspaceRoot, deps, taskCache) : [];
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
const
|
|
783
|
+
const identity = taskWorkspaceRoot ? loadWorkspaceIdentity(taskWorkspaceRoot, deps, identityCache, nowMs) : { missions: [], missionLocks: [], memberLocks: [] };
|
|
784
|
+
const sidecar = loadAgentWorktreeSidecar(agent.cwd, deps);
|
|
785
|
+
const branchIdentity = branchIdentityAtCwd(agent.cwd, deps.execFile);
|
|
786
|
+
const sessionId = parseSessionIdFromCommand(agent.command);
|
|
787
|
+
const interactive = agent.agent === 'claude' && isInteractiveClaudeCommand(agent.command);
|
|
788
|
+
const resolved = resolveAgentTaskBinding({
|
|
789
|
+
agent,
|
|
790
|
+
tasks: agentTasks,
|
|
791
|
+
missions: identity.missions,
|
|
792
|
+
missionLocks: identity.missionLocks,
|
|
793
|
+
memberLocks: identity.memberLocks,
|
|
794
|
+
sidecar,
|
|
795
|
+
branchIdentity,
|
|
796
|
+
sessionId,
|
|
797
|
+
interactive,
|
|
798
|
+
taskWorkspaceRoot,
|
|
799
|
+
});
|
|
800
|
+
const task = resolved.task;
|
|
801
|
+
const taskReason = task ? taskSessionReason(task) : untaskedReason(agent, taskWorkspaceRoot, agentTasks, resolved);
|
|
802
|
+
const binding = { task_source: resolved.task_source, task_scope: resolved.task_scope };
|
|
567
803
|
return {
|
|
568
804
|
...agent,
|
|
569
805
|
task: taskRef(task),
|
|
570
806
|
task_status: task?.status || null,
|
|
571
|
-
owner: ownerForTask(task),
|
|
807
|
+
owner: resolved.owner || ownerForTask(task),
|
|
808
|
+
member: resolved.member || null,
|
|
809
|
+
session_id: resolved.session_id || null,
|
|
810
|
+
mission_id: resolved.mission_id || null,
|
|
572
811
|
task_workspace: taskWorkspaceRoot ? repoLabel(taskWorkspaceRoot) : null,
|
|
573
|
-
...
|
|
812
|
+
...binding,
|
|
574
813
|
task_reason: taskReason,
|
|
575
|
-
task_action: task ? taskSessionAction(agent, task, taskWorkspaceRoot) : untaskedAction(agent, taskWorkspaceRoot, agentTasks),
|
|
814
|
+
task_action: task ? taskSessionAction(agent, task, taskWorkspaceRoot) : untaskedAction(agent, taskWorkspaceRoot, agentTasks, resolved),
|
|
576
815
|
};
|
|
577
816
|
});
|
|
578
817
|
const osState = {
|
|
@@ -949,10 +1188,16 @@ function radarCommand(args = [], options = {}) {
|
|
|
949
1188
|
module.exports = {
|
|
950
1189
|
agentTypeForCommand,
|
|
951
1190
|
agentTopPayload,
|
|
1191
|
+
branchIdentityAtCwd,
|
|
952
1192
|
collectRadar,
|
|
1193
|
+
isInteractiveClaudeCommand,
|
|
1194
|
+
loadAgentWorktreeSidecar,
|
|
953
1195
|
parsePsOutput,
|
|
1196
|
+
parseSessionIdFromCommand,
|
|
954
1197
|
parseWorktrees,
|
|
955
1198
|
radarCommand,
|
|
956
1199
|
renderAgentTop,
|
|
957
1200
|
renderRadar,
|
|
1201
|
+
resolveAgentTaskBinding,
|
|
1202
|
+
taskForOwner,
|
|
958
1203
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* atris rainmaker — passthrough to atrisos-backend/scripts/rainmaker.py
|
|
5
|
+
*
|
|
6
|
+
* atris rainmaker # ASCII status dashboard
|
|
7
|
+
* atris rainmaker instinct # one morning opinion
|
|
8
|
+
* atris rainmaker batting # accuracy scorecard
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { spawnSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
function resolveBackendRoot() {
|
|
17
|
+
const candidates = [
|
|
18
|
+
process.env.ATRIS_BACKEND_DIR,
|
|
19
|
+
path.resolve(__dirname, '..', '..', 'atrisos-backend'),
|
|
20
|
+
path.resolve(process.cwd(), '..', 'atrisos-backend'),
|
|
21
|
+
path.join(os.homedir(), 'arena', 'atrisos-backend'),
|
|
22
|
+
].filter(Boolean);
|
|
23
|
+
for (const root of candidates) {
|
|
24
|
+
if (fs.existsSync(path.join(root, 'scripts', 'rainmaker.py'))) return root;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function rainmakerCommand(args = []) {
|
|
30
|
+
if (args[0] === '--help' || args[0] === '-h') {
|
|
31
|
+
console.log('Usage: atris rainmaker [args...]\n\nPassthrough to python3 scripts/rainmaker.py in atrisos-backend.');
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
const root = resolveBackendRoot();
|
|
35
|
+
if (!root) {
|
|
36
|
+
console.error('Cannot find scripts/rainmaker.py. Set ATRIS_BACKEND_DIR to atrisos-backend.');
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
const script = path.join(root, 'scripts', 'rainmaker.py');
|
|
40
|
+
const py = process.env.ATRIS_PYTHON || 'python3';
|
|
41
|
+
const result = spawnSync(py, [script, ...args], { cwd: root, stdio: 'inherit', env: process.env });
|
|
42
|
+
if (result.error) {
|
|
43
|
+
console.error(`Failed to spawn ${py}: ${result.error.message}`);
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
return result.status ?? 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { rainmakerCommand, resolveBackendRoot };
|