atris 3.37.0 → 3.38.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/README.md +2 -0
- package/atris/PERSONA.md +3 -7
- package/atris.md +10 -2
- package/ax +158 -33
- package/bin/atris.js +49 -2
- package/commands/activate.js +16 -3
- package/commands/agent-spawn.js +0 -7
- package/commands/autoland.js +92 -14
- package/commands/autopilot-front.js +0 -4
- package/commands/autopilot.js +0 -12
- package/commands/brain.js +0 -7
- package/commands/brief.js +0 -2
- package/commands/business-sync.js +0 -1
- package/commands/business.js +107 -12
- package/commands/clean.js +31 -2
- package/commands/close.js +46 -11
- package/commands/cloud.js +0 -1
- package/commands/codex-goal.js +0 -2
- package/commands/computer.js +6 -5
- package/commands/console.js +46 -9
- package/commands/deck.js +29 -8
- package/commands/dream.js +0 -7
- package/commands/drill.js +0 -1
- package/commands/engine.js +10 -18
- package/commands/experiments.js +0 -4
- package/commands/fleet-report.js +12 -4
- package/commands/game.js +261 -0
- package/commands/gm.js +10 -2
- package/commands/goal.js +0 -6
- package/commands/harvest.js +0 -1
- package/commands/improve.js +29 -8
- package/commands/init.js +18 -34
- package/commands/integrations.js +0 -7
- package/commands/land.js +71 -8
- package/commands/launchpad.js +0 -2
- package/commands/lesson.js +17 -7
- package/commands/loop-front.js +0 -2
- package/commands/loops.js +6 -5
- package/commands/meet.js +0 -2
- package/commands/member.js +68 -3
- package/commands/mission.js +359 -102
- package/commands/next.js +0 -1
- package/commands/now.js +0 -12
- package/commands/one-lap.js +8 -8
- package/commands/orb.js +0 -4
- package/commands/pack-craft.js +0 -1
- package/commands/pack.js +670 -77
- package/commands/play.js +0 -2
- package/commands/probe.js +10 -4
- package/commands/pulse.js +73 -48
- package/commands/push.js +0 -4
- package/commands/radar.js +14 -11
- package/commands/recover.js +340 -0
- package/commands/report.js +0 -1
- package/commands/router.js +319 -0
- package/commands/run-front.js +0 -2
- package/commands/search.js +0 -3
- package/commands/skill.js +7 -2
- package/commands/slop.js +225 -7
- package/commands/status.js +6 -0
- package/commands/stream.js +0 -2
- package/commands/study.js +0 -3
- package/commands/sync-checkout.js +51 -0
- package/commands/sync.js +11 -40
- package/commands/task.js +125 -39
- package/commands/teach.js +86 -0
- package/commands/unknowns.js +0 -10
- package/commands/update.js +0 -1
- package/commands/visualize.js +0 -5
- package/commands/watch.js +0 -6
- package/commands/wiki.js +41 -11
- package/commands/wish.js +0 -1
- package/commands/worktree.js +87 -14
- package/commands/xp.js +1 -6
- package/commands/youtube.js +0 -2
- package/lib/accept-verify-gate.js +122 -0
- package/lib/activity-stream.js +0 -2
- package/lib/auto-accept-certified.js +145 -2
- package/lib/autoland.js +0 -3
- package/lib/ax-auto-lane.js +94 -10
- package/lib/bench/context.js +0 -2
- package/lib/bench/report.js +0 -1
- package/lib/bench/runner.js +0 -11
- package/lib/brief-ledger.js +0 -6
- package/lib/business-simulate.js +382 -0
- package/lib/chat-log-scan.js +0 -5
- package/lib/checkout-sync.js +52 -0
- package/lib/claude-boot-block.js +48 -0
- package/lib/cloud-mission.js +0 -6
- package/lib/codex-flight.js +0 -1
- package/lib/conductor-artifacts.js +25 -0
- package/lib/context-gatherer.js +0 -1
- package/lib/deck-compose.js +0 -1
- package/lib/deck-history.js +0 -1
- package/lib/deck-layout.js +0 -5
- package/lib/deck-review.js +0 -7
- package/lib/deck-schema.js +0 -1
- package/lib/default-verifier.js +0 -2
- package/lib/engine-registry.js +16 -8
- package/lib/experiments/daily.js +0 -6
- package/lib/fleet.js +210 -27
- package/lib/functional-owner.js +0 -3
- package/lib/inspect-fields.js +0 -1
- package/lib/known-commands.js +2 -2
- package/lib/learnings.js +0 -2
- package/lib/loop-doctor.js +11 -17
- package/lib/manifest.js +0 -2
- package/lib/member-alive.js +0 -1
- package/lib/member-switches.js +0 -5
- package/lib/mission-artifact.js +0 -1
- package/lib/mission-protected-lane.js +293 -0
- package/lib/mission-room.js +0 -2
- package/lib/mission-runtime-loop.js +0 -1
- package/lib/next-moves.js +0 -18
- package/lib/official-cli-integration.js +0 -4
- package/lib/orb-context.js +6 -3
- package/lib/orb-scorecard.js +0 -1
- package/lib/outbound-send-gate.js +0 -6
- package/lib/permission-grants.js +0 -6
- package/lib/policy-lessons.js +0 -2
- package/lib/pulse.js +68 -15
- package/lib/review-integrity.js +0 -2
- package/lib/router-brain.js +0 -2
- package/lib/runner-command.js +0 -4
- package/lib/runtime-bootstrap.js +0 -1
- package/lib/scorecard.js +0 -1
- package/lib/self-drive.js +1 -1
- package/lib/state-detection.js +0 -6
- package/lib/task-db.js +0 -4
- package/lib/team-presence.js +0 -1
- package/lib/voice-gate.js +63 -2
- package/lib/wiki.js +152 -9
- package/lib/wish-audit.js +20 -6
- package/lib/wish-delegate.js +26 -20
- package/lib/wish-stats.js +0 -5
- package/lib/wish-store.js +0 -1
- package/lib/workspace-safety.js +0 -2
- package/lib/zip.js +0 -1
- package/package.json +1 -1
package/commands/play.js
CHANGED
package/commands/probe.js
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
const https = require('https');
|
|
28
28
|
const http = require('http');
|
|
29
|
+
const path = require('path');
|
|
29
30
|
const { getApiBaseUrl } = require('../utils/api');
|
|
30
31
|
const { loadCredentials } = require('../utils/auth');
|
|
31
32
|
const { encodeToolResult } = require('../lib/tool-result-encode');
|
|
@@ -188,10 +189,13 @@ function runTerminal(base, token, command, businessId) {
|
|
|
188
189
|
// command runs in the mission's OWN workspace directory instead of the hosted
|
|
189
190
|
// ai-computer. Without this, a mission tick in a local workspace read the
|
|
190
191
|
// remote computer's files and reported local members (e.g. maze) as missing.
|
|
191
|
-
function runLocalTerminal(command, cwd) {
|
|
192
|
+
function runLocalTerminal(command, cwd, environment = process.env, pathPrefix = '') {
|
|
192
193
|
const { exec } = require('child_process');
|
|
193
194
|
const { envWithNodeDir } = require('../lib/spawn-env');
|
|
194
|
-
const
|
|
195
|
+
const baseEnv = envWithNodeDir(environment);
|
|
196
|
+
const env = pathPrefix
|
|
197
|
+
? { ...baseEnv, PATH: `${pathPrefix}${path.delimiter}${baseEnv.PATH || ''}` }
|
|
198
|
+
: baseEnv;
|
|
195
199
|
return new Promise((resolve) => {
|
|
196
200
|
exec(command, { cwd, env, timeout: 60000, maxBuffer: 4 * 1024 * 1024, shell: '/bin/bash' }, (error, stdout, stderr) => {
|
|
197
201
|
resolve({
|
|
@@ -237,6 +241,8 @@ async function runAtris2Turn(opts = {}) {
|
|
|
237
241
|
connectTimeoutMs = 60000,
|
|
238
242
|
signal = null,
|
|
239
243
|
localCwd = null,
|
|
244
|
+
localEnv = null,
|
|
245
|
+
localPathPrefix = '',
|
|
240
246
|
} = opts;
|
|
241
247
|
const t0 = Date.now();
|
|
242
248
|
const out = { ok: false, text: '', engine: null, tools_run: 0, cli_ops: [], unsupported: [], error: null, duration_ms: 0 };
|
|
@@ -322,7 +328,7 @@ async function runAtris2Turn(opts = {}) {
|
|
|
322
328
|
unsupported.push(`file_op:${op}`);
|
|
323
329
|
} else {
|
|
324
330
|
const term = localCwd
|
|
325
|
-
? await runLocalTerminal(cmd, localCwd)
|
|
331
|
+
? await runLocalTerminal(cmd, localCwd, localEnv || process.env, localPathPrefix)
|
|
326
332
|
: await runTerminal(base, token, cmd, business);
|
|
327
333
|
const ok = term.exit_code === 0;
|
|
328
334
|
out = ok
|
|
@@ -341,7 +347,7 @@ async function runAtris2Turn(opts = {}) {
|
|
|
341
347
|
unsupported.push(`cli_op:${op || '?'}`);
|
|
342
348
|
} else {
|
|
343
349
|
const term = localCwd
|
|
344
|
-
? await runLocalTerminal(cmd, localCwd)
|
|
350
|
+
? await runLocalTerminal(cmd, localCwd, localEnv || process.env, localPathPrefix)
|
|
345
351
|
: await runTerminal(base, token, cmd, business);
|
|
346
352
|
out = atrisCliResult(cmd, term);
|
|
347
353
|
cliOps.push(op || '?');
|
package/commands/pulse.js
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
// `atris pulse` - the durable overnight self-improvement heartbeat for atris-cli.
|
|
4
4
|
//
|
|
5
|
-
// atris pulse tick run ONE self-improvement tick (what
|
|
5
|
+
// atris pulse tick run ONE self-improvement tick (what launchd calls)
|
|
6
6
|
// atris pulse status liveness, reward sum, ghost-tick detection
|
|
7
|
-
// atris pulse install write the
|
|
8
|
-
// atris pulse uninstall remove the
|
|
7
|
+
// atris pulse install write the tick script + install a launchd agent
|
|
8
|
+
// atris pulse uninstall remove the launchd agent
|
|
9
9
|
// atris pulse run run N ticks in the foreground (manual / testing)
|
|
10
10
|
//
|
|
11
11
|
// One tick: lock -> 'started' receipt -> run mission engine -> verify -> write
|
|
12
12
|
// 'finished' receipt (pulse_agi_loop_receipts.jsonl) + reward scorecard
|
|
13
13
|
// (scorecards.jsonl, gated) -> release lock. The whole point is that this fires
|
|
14
|
-
// from
|
|
14
|
+
// from launchd, so it self-improves overnight without Claude Code open.
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const os = require('os');
|
|
@@ -41,8 +41,8 @@ Durable overnight self-improvement heartbeat.
|
|
|
41
41
|
Commands:
|
|
42
42
|
tick Run one heartbeat tick
|
|
43
43
|
status Show liveness, reward, and ghost-tick detection
|
|
44
|
-
install Install the
|
|
45
|
-
uninstall Remove the
|
|
44
|
+
install Install the launchd heartbeat
|
|
45
|
+
uninstall Remove the launchd heartbeat
|
|
46
46
|
run Run bounded ticks in the foreground
|
|
47
47
|
|
|
48
48
|
Options:
|
|
@@ -298,7 +298,12 @@ function tickCommand(args, root = process.cwd()) {
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
const elapsedMs = Date.now() - startedAt;
|
|
301
|
-
const reward = pulse.scoreTick({
|
|
301
|
+
const reward = pulse.scoreTick({
|
|
302
|
+
verifyPassed: verify.passed,
|
|
303
|
+
producedWork,
|
|
304
|
+
actorOk: engine.ok,
|
|
305
|
+
actorReason: engine.reason,
|
|
306
|
+
});
|
|
302
307
|
const changedTail = committed
|
|
303
308
|
? ' - committed'
|
|
304
309
|
: (changedFiles.length ? ` - ${changedFiles.length} file(s) changed` : '');
|
|
@@ -492,13 +497,21 @@ function statusCommand(args, root = process.cwd(), options = {}) {
|
|
|
492
497
|
const slot = pulse.resolvePulseSlot(root, options.homeDir ? { homeDir: options.homeDir } : {});
|
|
493
498
|
const receipts = pulse.readPulseReceipts(root);
|
|
494
499
|
const summary = pulse.summarizePulse(receipts);
|
|
495
|
-
const
|
|
500
|
+
const label = `com.atris.pulse.${slot.marker.toLowerCase().replace(/^atris_pulse_/, '').replace(/[^a-z0-9]+/g, '-')}`;
|
|
501
|
+
const homeDir = options.homeDir || os.homedir();
|
|
502
|
+
const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', `${label}.plist`);
|
|
503
|
+
const legacyCronInstalled = cronInstalled(slot.markers, options.spawnSync || spawnSync);
|
|
504
|
+
const installed = fs.existsSync(plistPath) || legacyCronInstalled;
|
|
496
505
|
const expiryBreadcrumb = installed ? null : readPulseExpiryBreadcrumb(root);
|
|
497
506
|
const writeOutput = options.writeOutput || ((text) => process.stdout.write(text));
|
|
498
507
|
const out = {
|
|
499
508
|
ok: true,
|
|
500
509
|
action: 'pulse_status',
|
|
501
510
|
cron_installed: installed,
|
|
511
|
+
launchd_installed: fs.existsSync(plistPath),
|
|
512
|
+
legacy_cron_installed: legacyCronInstalled,
|
|
513
|
+
label,
|
|
514
|
+
plist_path: plistPath,
|
|
502
515
|
expiry_breadcrumb: expiryBreadcrumb,
|
|
503
516
|
state_home: slot.activeStateHome,
|
|
504
517
|
marker: slot.activeMarker,
|
|
@@ -509,7 +522,7 @@ function statusCommand(args, root = process.cwd(), options = {}) {
|
|
|
509
522
|
};
|
|
510
523
|
if (!asJson) {
|
|
511
524
|
writeOutput([
|
|
512
|
-
`pulse: ${installed ? '
|
|
525
|
+
`pulse: ${installed ? 'scheduler installed' : 'scheduler not installed (run: atris pulse install)'}`,
|
|
513
526
|
expiryBreadcrumb ? `heartbeat expired on ${expiryBreadcrumb.expired_at}; renew with: ${expiryBreadcrumb.renew_command}` : '',
|
|
514
527
|
`state home: ${slot.activeStateHome} marker: ${slot.activeMarker}`,
|
|
515
528
|
`ticks: ${summary.total_ticks} | reward: ${summary.reward_sum} | verify pass/fail: ${summary.verify_pass}/${summary.verify_fail}`,
|
|
@@ -606,8 +619,12 @@ function installCommand(args, root = process.cwd(), options = {}) {
|
|
|
606
619
|
|
|
607
620
|
fs.mkdirSync(slot.stateHome, { recursive: true });
|
|
608
621
|
const scriptPath = path.join(slot.stateHome, 'tick.sh');
|
|
609
|
-
|
|
610
|
-
|
|
622
|
+
const label = `com.atris.pulse.${slot.marker.toLowerCase().replace(/^atris_pulse_/, '').replace(/[^a-z0-9]+/g, '-')}`;
|
|
623
|
+
const homeDir = options.homeDir || os.homedir();
|
|
624
|
+
const launchAgentsDir = path.join(homeDir, 'Library', 'LaunchAgents');
|
|
625
|
+
const plistPath = path.join(launchAgentsDir, `${label}.plist`);
|
|
626
|
+
// Resolve the real bin dirs the engine spawns by bare name, so launchd's
|
|
627
|
+
// minimal PATH doesn't break the worker spawn (claude lives in ~/.local/bin).
|
|
611
628
|
const pathDirs = resolveEngineBinDirs([runnerBin], commandSpawn);
|
|
612
629
|
const script = pulse.buildTickScript({
|
|
613
630
|
root,
|
|
@@ -621,18 +638,26 @@ function installCommand(args, root = process.cwd(), options = {}) {
|
|
|
621
638
|
runnerCommandTemplate,
|
|
622
639
|
verifyCmd,
|
|
623
640
|
pathDirs,
|
|
641
|
+
launchLabel: label,
|
|
642
|
+
launchPlistPath: plistPath,
|
|
624
643
|
});
|
|
625
644
|
fs.writeFileSync(scriptPath, script, { mode: 0o755 });
|
|
626
645
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
646
|
+
fs.mkdirSync(path.join(slot.stateHome, 'logs'), { recursive: true });
|
|
647
|
+
fs.mkdirSync(launchAgentsDir, { recursive: true });
|
|
648
|
+
fs.writeFileSync(plistPath, pulse.buildLaunchAgentPlist({ label, scriptPath, cron, stateHome: slot.stateHome }), 'utf8');
|
|
649
|
+
|
|
650
|
+
// Strip old cron entries while migrating existing installations.
|
|
630
651
|
const existing = commandSpawn('crontab', ['-l'], { encoding: 'utf8', timeout: 10000 });
|
|
631
652
|
const prior = existing.status === 0 ? String(existing.stdout || '') : '';
|
|
632
653
|
const cleaned = stripMarkedCrontabLines(prior, slot.markers);
|
|
633
|
-
const
|
|
634
|
-
|
|
654
|
+
const legacyHad = slot.markers.some((marker) => prior.includes(marker));
|
|
655
|
+
if (existing.status === 0 && legacyHad) commandSpawn('crontab', ['-'], { input: cleaned ? `${cleaned}\n` : '', encoding: 'utf8', timeout: 10000 });
|
|
656
|
+
const uid = options.uid != null ? options.uid : process.getuid();
|
|
657
|
+
commandSpawn('launchctl', ['bootout', `gui/${uid}/${label}`], { encoding: 'utf8', timeout: 10000 });
|
|
658
|
+
const apply = commandSpawn('launchctl', ['bootstrap', `gui/${uid}`, plistPath], { encoding: 'utf8', timeout: 10000 });
|
|
635
659
|
const expiryBreadcrumbCleared = apply.status === 0 && clearPulseExpiryBreadcrumb(root);
|
|
660
|
+
const cadenceMapping = pulse.launchIntervalFromCadence({ cron });
|
|
636
661
|
|
|
637
662
|
const out = {
|
|
638
663
|
ok: apply.status === 0,
|
|
@@ -641,7 +666,11 @@ function installCommand(args, root = process.cwd(), options = {}) {
|
|
|
641
666
|
state_home: slot.stateHome,
|
|
642
667
|
marker: slot.marker,
|
|
643
668
|
legacy_migrated: slot.legacyMatches,
|
|
644
|
-
|
|
669
|
+
label,
|
|
670
|
+
plist_path: plistPath,
|
|
671
|
+
crontab_line: null,
|
|
672
|
+
removed_legacy_crontab: legacyHad,
|
|
673
|
+
cadence_fallback: cadenceMapping.fallback,
|
|
645
674
|
cadence: cron,
|
|
646
675
|
cadence_input: cadenceInput,
|
|
647
676
|
expires_in_days: expiry.days,
|
|
@@ -656,46 +685,49 @@ function installCommand(args, root = process.cwd(), options = {}) {
|
|
|
656
685
|
if (!asJson) {
|
|
657
686
|
if (apply.status === 0) {
|
|
658
687
|
writeOutput([
|
|
659
|
-
`pulse installed. heartbeat fires '${cron}' against ${root}.`,
|
|
688
|
+
`pulse installed. launchd heartbeat fires '${cron}' against ${root}.`,
|
|
689
|
+
`label: ${label}`,
|
|
690
|
+
`plist: ${plistPath}`,
|
|
660
691
|
`script: ${scriptPath}`,
|
|
692
|
+
cadenceMapping.fallback ? `cadence '${cron}' is not directly mappable; using 3600 seconds.` : '',
|
|
661
693
|
`auto-expires in ${expiry.hours ? `${expiry.hours} hours` : `${expiry.days} days`}. stop early: atris pulse uninstall`,
|
|
662
|
-
].join('\n') + '\n');
|
|
694
|
+
].filter(Boolean).join('\n') + '\n');
|
|
663
695
|
} else {
|
|
664
|
-
writeOutput(`pulse install failed to
|
|
696
|
+
writeOutput(`pulse install failed to bootstrap ${label}: ${apply.stderr || apply.status}\nplist: ${plistPath}\n`);
|
|
665
697
|
}
|
|
666
698
|
}
|
|
667
699
|
return emit(out, asJson);
|
|
668
700
|
}
|
|
669
701
|
|
|
670
|
-
function uninstallCommand(args, root = process.cwd()) {
|
|
702
|
+
function uninstallCommand(args, root = process.cwd(), options = {}) {
|
|
671
703
|
const asJson = wantsJson(args);
|
|
672
|
-
const slot = pulse.resolvePulseSlot(root);
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
};
|
|
683
|
-
if (!asJson) process.stdout.write('pulse: no crontab to clean.\n');
|
|
684
|
-
return emit(out, asJson);
|
|
685
|
-
}
|
|
704
|
+
const slot = pulse.resolvePulseSlot(root, options.homeDir ? { homeDir: options.homeDir } : {});
|
|
705
|
+
const commandSpawn = options.spawnSync || spawnSync;
|
|
706
|
+
const homeDir = options.homeDir || os.homedir();
|
|
707
|
+
const label = `com.atris.pulse.${slot.marker.toLowerCase().replace(/^atris_pulse_/, '').replace(/[^a-z0-9]+/g, '-')}`;
|
|
708
|
+
const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', `${label}.plist`);
|
|
709
|
+
const uid = options.uid != null ? options.uid : process.getuid();
|
|
710
|
+
commandSpawn('launchctl', ['bootout', `gui/${uid}/${label}`], { encoding: 'utf8', timeout: 10000 });
|
|
711
|
+
const plistHad = fs.existsSync(plistPath);
|
|
712
|
+
fs.rmSync(plistPath, { force: true });
|
|
713
|
+
const existing = commandSpawn('crontab', ['-l'], { encoding: 'utf8', timeout: 10000 });
|
|
686
714
|
const prior = String(existing.stdout || '');
|
|
687
715
|
const had = slot.markers.some((marker) => prior.includes(marker));
|
|
688
716
|
const cleaned = stripMarkedCrontabLines(prior, slot.markers);
|
|
689
|
-
|
|
717
|
+
let apply = { status: 0 };
|
|
718
|
+
if (existing.status === 0 && had) apply = commandSpawn('crontab', ['-'], { input: cleaned ? cleaned + '\n' : '', encoding: 'utf8', timeout: 10000 });
|
|
690
719
|
const out = {
|
|
691
720
|
ok: apply.status === 0,
|
|
692
721
|
action: 'pulse_uninstall',
|
|
693
|
-
removed: had,
|
|
722
|
+
removed: plistHad || had,
|
|
723
|
+
label,
|
|
724
|
+
plist_path: plistPath,
|
|
725
|
+
removed_legacy_crontab: had,
|
|
694
726
|
state_home: slot.activeStateHome,
|
|
695
727
|
marker: slot.activeMarker,
|
|
696
728
|
legacy_slot: slot.legacyMatches,
|
|
697
729
|
};
|
|
698
|
-
if (!asJson) process.stdout.write(had ?
|
|
730
|
+
if (!asJson) process.stdout.write(plistHad || had ? `pulse uninstalled (${label}).\n` : 'pulse: no heartbeat agent found.\n');
|
|
699
731
|
return emit(out, asJson);
|
|
700
732
|
}
|
|
701
733
|
|
|
@@ -717,6 +749,9 @@ function pulseCommand(argv = []) {
|
|
|
717
749
|
const sub = argv[0];
|
|
718
750
|
const rest = argv.slice(1);
|
|
719
751
|
if (sub === '--help' || sub === '-h' || sub === 'help') return showHelp();
|
|
752
|
+
// `pulse <sub> --help` is a help request, not a run — never execute the
|
|
753
|
+
// subcommand (tick/status/etc. have real side effects) just to show usage.
|
|
754
|
+
if (rest.includes('--help') || rest.includes('-h')) return showHelp();
|
|
720
755
|
switch (sub) {
|
|
721
756
|
case 'tick':
|
|
722
757
|
return tickCommand(rest);
|
|
@@ -740,21 +775,11 @@ function pulseCommand(argv = []) {
|
|
|
740
775
|
|
|
741
776
|
module.exports = {
|
|
742
777
|
pulseCommand,
|
|
743
|
-
tickCommand,
|
|
744
778
|
statusCommand,
|
|
745
779
|
cronInstalled,
|
|
746
780
|
crontabHasActiveMarker,
|
|
747
781
|
pulseExpiryBreadcrumbPath,
|
|
748
|
-
readPulseExpiryBreadcrumb,
|
|
749
|
-
clearPulseExpiryBreadcrumb,
|
|
750
782
|
installCommand,
|
|
751
|
-
uninstallCommand,
|
|
752
783
|
runCommand,
|
|
753
|
-
runMissionEngine,
|
|
754
|
-
runAutopilotTick,
|
|
755
|
-
runEngine,
|
|
756
|
-
gitChangedFiles,
|
|
757
|
-
runVerify,
|
|
758
784
|
refreshOrbPolicyLessons,
|
|
759
|
-
stripMarkedCrontabLines,
|
|
760
785
|
};
|
package/commands/push.js
CHANGED
|
@@ -1055,7 +1055,6 @@ module.exports = {
|
|
|
1055
1055
|
buildPushUploadBatches,
|
|
1056
1056
|
shouldRetrySyncIndividually,
|
|
1057
1057
|
resolvePushSourceDir,
|
|
1058
|
-
canonicalWorkspaceRoot,
|
|
1059
1058
|
basenameOfManifestPath,
|
|
1060
1059
|
buildCloudHashMap,
|
|
1061
1060
|
isBusinessWorkspaceRoot,
|
|
@@ -1066,9 +1065,6 @@ module.exports = {
|
|
|
1066
1065
|
resolveChangedScopePaths,
|
|
1067
1066
|
mergePushScopes,
|
|
1068
1067
|
analyzePushSafety,
|
|
1069
|
-
isNestedWorkspacePollutionPath,
|
|
1070
|
-
isSyncReviewArtifactPath,
|
|
1071
|
-
renderPushSafetyBlock,
|
|
1072
1068
|
renderDriftBlock,
|
|
1073
1069
|
needsForceBroadWorkspaceConfirm,
|
|
1074
1070
|
promptConfirm,
|
package/commands/radar.js
CHANGED
|
@@ -396,16 +396,21 @@ function loadLoop(missions, root, deps) {
|
|
|
396
396
|
const events = readJsonLines(path.join(root, '.atris', 'state', 'mission_events.jsonl'), deps.readFile, deps.exists);
|
|
397
397
|
const codexGoal = readJsonFile(path.join(root, '.atris', 'state', 'codex_goal.json'), deps, {}) || {};
|
|
398
398
|
const tickEvents = events.filter(event => event.type === 'mission_tick');
|
|
399
|
+
// Live missions sit in planning/ready/running; counting only 'running'
|
|
400
|
+
// reported 0 while a worker was mid-flight (CLI-1183, seen live 2026-07-25).
|
|
401
|
+
const ACTIVE_MISSION_STATUSES = new Set(['planning', 'running', 'ready']);
|
|
402
|
+
const isActive = (mission) => ACTIVE_MISSION_STATUSES.has(String(mission.status || ''));
|
|
399
403
|
return {
|
|
400
|
-
running: missions.filter(
|
|
404
|
+
running: missions.filter(isActive).length,
|
|
405
|
+
paused: missions.filter(mission => mission.status === 'paused').length,
|
|
401
406
|
always_on: missions.filter(mission => mission.always_on).length,
|
|
402
407
|
stale: missions.filter(mission => mission.stale).length,
|
|
403
|
-
no_verifier: missions.filter(mission => mission
|
|
408
|
+
no_verifier: missions.filter(mission => isActive(mission) && !mission.verifier).length,
|
|
404
409
|
ticks: tickEvents.length,
|
|
405
410
|
last_event_at: events[events.length - 1]?.at || null,
|
|
406
411
|
codex_goal: codexGoal.goal?.objective || null,
|
|
407
412
|
codex_goal_mission: codexGoal.goal?.mission_id || null,
|
|
408
|
-
infinite_loop_risk: missions.some(mission => mission.stale || (mission
|
|
413
|
+
infinite_loop_risk: missions.some(mission => mission.stale || (isActive(mission) && !mission.verifier)),
|
|
409
414
|
};
|
|
410
415
|
}
|
|
411
416
|
|
|
@@ -735,7 +740,11 @@ function summarize(tasks, missions, worktrees, agents) {
|
|
|
735
740
|
review: count(tasks, t => t.status === 'review'),
|
|
736
741
|
certifiedReview: count(tasks, t => t.status === 'review' && t.metadata && t.metadata.agent_certified),
|
|
737
742
|
},
|
|
738
|
-
missions: {
|
|
743
|
+
missions: {
|
|
744
|
+
running: count(missions, m => ['planning', 'running', 'ready'].includes(String(m.status || ''))),
|
|
745
|
+
paused: count(missions, m => m.status === 'paused'),
|
|
746
|
+
stale: count(missions, m => m.stale),
|
|
747
|
+
},
|
|
739
748
|
worktrees: { total: worktrees.length, dirty: count(worktrees, w => Number(w.dirty) > 0) },
|
|
740
749
|
};
|
|
741
750
|
}
|
|
@@ -832,7 +841,7 @@ function renderRadar(data) {
|
|
|
832
841
|
lines.push('');
|
|
833
842
|
lines.push(`Agents: ${s.agents.active}/${s.agents.total} active`);
|
|
834
843
|
lines.push(`Tasks: ${s.tasks.open} open, ${s.tasks.claimed} claimed, ${s.tasks.review} review (${s.tasks.certifiedReview} certified)`);
|
|
835
|
-
lines.push(`Missions: ${s.missions.running}
|
|
844
|
+
lines.push(`Missions: ${s.missions.running} active, ${s.missions.paused || 0} paused, ${s.missions.stale} stale/no-verifier`);
|
|
836
845
|
lines.push(`Worktrees: ${s.worktrees.total} registered, ${s.worktrees.dirty} dirty`);
|
|
837
846
|
lines.push(`Next: ${data.next_action}`);
|
|
838
847
|
if (data.os) {
|
|
@@ -1188,16 +1197,10 @@ function radarCommand(args = [], options = {}) {
|
|
|
1188
1197
|
module.exports = {
|
|
1189
1198
|
agentTypeForCommand,
|
|
1190
1199
|
agentTopPayload,
|
|
1191
|
-
branchIdentityAtCwd,
|
|
1192
1200
|
collectRadar,
|
|
1193
|
-
isInteractiveClaudeCommand,
|
|
1194
|
-
loadAgentWorktreeSidecar,
|
|
1195
1201
|
parsePsOutput,
|
|
1196
|
-
parseSessionIdFromCommand,
|
|
1197
1202
|
parseWorktrees,
|
|
1198
1203
|
radarCommand,
|
|
1199
1204
|
renderAgentTop,
|
|
1200
1205
|
renderRadar,
|
|
1201
|
-
resolveAgentTaskBinding,
|
|
1202
|
-
taskForOwner,
|
|
1203
1206
|
};
|