@phnx-labs/agents-cli 1.22.28 → 1.22.29
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/CHANGELOG.md +6 -0
- package/dist/bin/agents +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/snapshot.d.ts +16 -0
- package/dist/lib/menubar/snapshot.js +22 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/usage.js +18 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.29
|
|
4
|
+
|
|
5
|
+
- **Menu bar: collapsible DEVICES roster, a Focus action on sessions, and richer routine submenus.** The dropdown now has a **DEVICES** section near the bottom — the full registered fleet as one accordion, folded by default so the long list never walls the menu, each row `<name> · <platform>` with live load% merged from the warm fleet cache (never a faked online/offline) and a Copy `agents ssh <name>` action; **NEW DEVICES** moved to sit just above it. Each live-session `›` submenu leads with **▶ Focus session** (attaches locally or SSHes to the owning box via `agents sessions focus`). Each routine submenu now leads with a last-run line — `● running now` (server-verified), `✓ completed · ran 45s · 2h ago`, or `✕ failed exit 1` — plus the next fire. The device roster rides the existing 3-minute `menubar snapshot --json` poll (a cheap local registry read, `MenubarSnapshot.devices`); everything else renders from fields the snapshot already carried, so no new timer and no per-open shell-out. Source: `apps/cli/src/lib/menubar/snapshot.ts`, `apps/cli/menubar/Sources/MenubarHelper/{StatusItemController,Models,LocalState}.swift`.
|
|
6
|
+
|
|
7
|
+
- Fix `agents view` and `agents usage` labeling Codex's weekly or monthly quota as session usage when the native CLI publishes the long-duration limit in its `primary` rate-limit window. Codex windows are now labeled from their reported duration (`S`, `W`, or `M`) instead of their primary/secondary position.
|
|
8
|
+
|
|
3
9
|
## 1.22.28
|
|
4
10
|
|
|
5
11
|
- **`agents run` / `agents teams` `--device`/`--host`: fail loud when a pinned harness version is not installed on the target (RUSH-2313).** A concrete pin like `codex@0.145.0` is checked against the remote `agents view --json` listing during `ensureHostReady` *before* the run is marked dispatched. Missing pins exit non-zero naming the box, the pin, what is installed there, and `agents ssh <box> -- agents add <agent>@<ver>` — so detached fleet drains no longer print `Dispatched` and then die only in the remote log. Aliases (`@latest` / …) still resolve on the remote; a bare agent name still only warns. Source: `apps/cli/src/lib/hosts/ready.ts`, `dispatch.ts`, `teams/agents.ts`.
|
package/dist/bin/agents
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import type { WatchdogTickResult } from '../watchdog/runner.js';
|
|
2
|
+
/**
|
|
3
|
+
* One registered fleet device, for the menu-bar's collapsible DEVICES section.
|
|
4
|
+
* Sourced from the local registry read (`loadDevices`) — no network probe — so
|
|
5
|
+
* it carries only what the registry knows for sure (name, platform, whether it
|
|
6
|
+
* is the interactive host, whether it is this machine). Live load% is merged in
|
|
7
|
+
* on the Swift side from the daemon-warmed `.fleet-stats.json`; online/offline
|
|
8
|
+
* is deliberately NOT claimed here (the registry's cached tailscale flag is
|
|
9
|
+
* documented as stale in both directions — registry.ts isLikelyOnline).
|
|
10
|
+
*/
|
|
11
|
+
export interface MenubarDevice {
|
|
12
|
+
name: string;
|
|
13
|
+
platform: string;
|
|
14
|
+
interactive: boolean;
|
|
15
|
+
isLocal: boolean;
|
|
16
|
+
}
|
|
2
17
|
export interface MenubarSnapshot {
|
|
3
18
|
version: 1;
|
|
4
19
|
capturedAt: string;
|
|
5
20
|
routines: Record<string, unknown>[];
|
|
6
21
|
recentSessions: Record<string, unknown>[];
|
|
7
22
|
activeSessions: Record<string, unknown>[];
|
|
23
|
+
devices: MenubarDevice[];
|
|
8
24
|
watchdog: {
|
|
9
25
|
enabled: boolean;
|
|
10
26
|
lastTick: Pick<WatchdogTickResult, 'didNudge' | 'counts'> | null;
|
|
@@ -3,10 +3,29 @@ import * as path from 'path';
|
|
|
3
3
|
import { buildRoutineListJson } from '../../commands/routines.js';
|
|
4
4
|
import { backfillActiveRowsFromIndex, isRunningLiveSession, serializeActiveSessionsForJson, serializeSessionsJson } from '../../commands/sessions.js';
|
|
5
5
|
import { getConfigValue } from '../device-config.js';
|
|
6
|
+
import { loadDevices } from '../devices/registry.js';
|
|
6
7
|
import { machineId } from '../machine-id.js';
|
|
7
8
|
import { querySessions } from '../session/db.js';
|
|
8
9
|
import { readActiveSessionsCache } from '../session/session-cache.js';
|
|
9
10
|
import { getRuntimeStateDir } from '../state.js';
|
|
11
|
+
/**
|
|
12
|
+
* The full registered-device roster for the menu bar, from the local registry
|
|
13
|
+
* file only (no ssh, no stats probe) — as cheap as `buildRoutineListJson()`, so
|
|
14
|
+
* it rides the same 3-minute snapshot poll instead of a second timer.
|
|
15
|
+
*/
|
|
16
|
+
async function buildMenubarDevices() {
|
|
17
|
+
const reg = await loadDevices();
|
|
18
|
+
const interactiveHost = getConfigValue('interactive.host').value;
|
|
19
|
+
const self = machineId();
|
|
20
|
+
return Object.keys(reg)
|
|
21
|
+
.sort()
|
|
22
|
+
.map((name) => ({
|
|
23
|
+
name,
|
|
24
|
+
platform: reg[name].platform,
|
|
25
|
+
interactive: name === interactiveHost,
|
|
26
|
+
isLocal: name === self,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
10
29
|
export function readLastWatchdogTick(stateDir = path.join(getRuntimeStateDir(), 'watchdog')) {
|
|
11
30
|
try {
|
|
12
31
|
return JSON.parse(fs.readFileSync(path.join(stateDir, 'last-tick.json'), 'utf-8'));
|
|
@@ -17,9 +36,10 @@ export function readLastWatchdogTick(stateDir = path.join(getRuntimeStateDir(),
|
|
|
17
36
|
}
|
|
18
37
|
/** One-process read model for AGI Menu's repeating three-minute refresh. */
|
|
19
38
|
export async function computeMenubarSnapshot() {
|
|
20
|
-
const [routines, recent] = await Promise.all([
|
|
39
|
+
const [routines, recent, devices] = await Promise.all([
|
|
21
40
|
Promise.resolve(buildRoutineListJson()),
|
|
22
41
|
Promise.resolve(querySessions({ limit: 40, skipExistenceCheck: true })),
|
|
42
|
+
buildMenubarDevices(),
|
|
23
43
|
]);
|
|
24
44
|
const active = readActiveSessionsCache('local');
|
|
25
45
|
const rawSessions = active?.sessions ?? [];
|
|
@@ -42,6 +62,7 @@ export async function computeMenubarSnapshot() {
|
|
|
42
62
|
routines,
|
|
43
63
|
recentSessions: JSON.parse(serializeSessionsJson(recent)),
|
|
44
64
|
activeSessions: serializeActiveSessionsForJson(activeSessions),
|
|
65
|
+
devices,
|
|
45
66
|
watchdog: {
|
|
46
67
|
enabled: getConfigValue('watchdog.enabled').value === true,
|
|
47
68
|
lastTick: (() => {
|
|
Binary file
|
|
Binary file
|
package/dist/lib/usage.js
CHANGED
|
@@ -1186,29 +1186,37 @@ async function readLatestCodexRateLimits(filePath) {
|
|
|
1186
1186
|
}
|
|
1187
1187
|
/** Normalize Codex rate-limit windows into the common UsageWindow shape. */
|
|
1188
1188
|
function normalizeCodexWindows(rateLimits) {
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const secondary = normalizeCodexWindow(rateLimits.secondary, 'week', 'Current week', 'W');
|
|
1194
|
-
if (secondary)
|
|
1195
|
-
windows.push(secondary);
|
|
1196
|
-
return windows;
|
|
1189
|
+
return [rateLimits.primary, rateLimits.secondary]
|
|
1190
|
+
.map(normalizeCodexWindow)
|
|
1191
|
+
.filter((window) => window !== null)
|
|
1192
|
+
.sort((a, b) => (a.windowMinutes ?? 0) - (b.windowMinutes ?? 0));
|
|
1197
1193
|
}
|
|
1198
1194
|
/** Normalize a single Codex rate-limit window. */
|
|
1199
|
-
function normalizeCodexWindow(window
|
|
1195
|
+
function normalizeCodexWindow(window) {
|
|
1200
1196
|
const usedPercent = normalizePercent(window?.used_percent);
|
|
1201
1197
|
if (usedPercent === null)
|
|
1202
1198
|
return null;
|
|
1199
|
+
const windowMinutes = normalizeWindowMinutes(window?.window_minutes);
|
|
1200
|
+
const { key, label, shortLabel } = classifyCodexWindow(windowMinutes);
|
|
1203
1201
|
return {
|
|
1204
1202
|
key,
|
|
1205
1203
|
label,
|
|
1206
1204
|
shortLabel,
|
|
1207
1205
|
usedPercent,
|
|
1208
1206
|
resetsAt: parseDateValue(window?.resets_at),
|
|
1209
|
-
windowMinutes
|
|
1207
|
+
windowMinutes,
|
|
1210
1208
|
};
|
|
1211
1209
|
}
|
|
1210
|
+
/** Codex assigns quota windows to primary/secondary by plan, so duration carries their meaning. */
|
|
1211
|
+
function classifyCodexWindow(windowMinutes) {
|
|
1212
|
+
if (windowMinutes !== null && windowMinutes >= 28 * 24 * 60) {
|
|
1213
|
+
return { key: 'month', label: 'Current month', shortLabel: 'M' };
|
|
1214
|
+
}
|
|
1215
|
+
if (windowMinutes !== null && windowMinutes >= 7 * 24 * 60) {
|
|
1216
|
+
return { key: 'week', label: 'Current week', shortLabel: 'W' };
|
|
1217
|
+
}
|
|
1218
|
+
return { key: 'session', label: 'Current session', shortLabel: 'S' };
|
|
1219
|
+
}
|
|
1212
1220
|
/** Normalize Claude API usage windows into the common UsageWindow shape. */
|
|
1213
1221
|
function normalizeClaudeWindows(data) {
|
|
1214
1222
|
const windows = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.29",
|
|
4
4
|
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|