@phnx-labs/agents-cli 1.20.82 → 1.20.84
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 +138 -0
- package/README.md +1 -1
- package/dist/bin/agents +0 -0
- package/dist/commands/doctor.d.ts +2 -1
- package/dist/commands/doctor.js +25 -6
- package/dist/commands/menubar.js +12 -0
- package/dist/commands/routines.d.ts +8 -1
- package/dist/commands/routines.js +229 -75
- package/dist/commands/sessions.d.ts +84 -0
- package/dist/commands/sessions.js +60 -25
- package/dist/index.js +47 -0
- package/dist/lib/exec.d.ts +7 -0
- package/dist/lib/exec.js +34 -3
- package/dist/lib/hooks.d.ts +29 -0
- package/dist/lib/hooks.js +109 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +24 -0
- package/dist/lib/menubar/install-menubar.js +52 -2
- package/dist/lib/permissions.d.ts +21 -0
- package/dist/lib/permissions.js +57 -2
- package/dist/lib/routines.d.ts +13 -0
- package/dist/lib/routines.js +116 -0
- package/dist/lib/scheduler.js +16 -4
- 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/session/active.d.ts +33 -0
- package/dist/lib/session/active.js +49 -4
- package/dist/lib/state.js +57 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,143 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.20.84
|
|
4
|
+
|
|
5
|
+
- **Agent onboarding cheat sheet and docs drift guard.** Added
|
|
6
|
+
`apps/cli/docs/AGENT-CHEATSHEET.md` as a one-page on-ramp for agents, wired it
|
|
7
|
+
from `apps/cli/AGENTS.md` and `apps/cli/docs/README.md`, and added
|
|
8
|
+
`scripts/verify-docs.sh` (plus a `verify-docs` npm script and CI job) to catch
|
|
9
|
+
broken relative links and missing entry-point wiring before merge.
|
|
10
|
+
|
|
11
|
+
- **Codex can now build, test, and install without escalating to YOLO.** Codex's
|
|
12
|
+
`workspace-write` sandbox blocks `$HOME`, so `cargo build`, `go build`, `npm/bun install`,
|
|
13
|
+
`pip install` etc. failed on their out-of-workspace cache writes (`~/.cargo`, `GOCACHE`,
|
|
14
|
+
`~/.npm`, `~/.cache`, …) — which is what pushed people to `--mode full`
|
|
15
|
+
(`--dangerously-bypass-approvals-and-sandbox`). agents-cli now writes a platform-resolved
|
|
16
|
+
baseline of **regenerable toolchain caches** into Codex's `config.toml`
|
|
17
|
+
(`[sandbox_workspace_write].writable_roots`) on permission sync — `~/.cargo`, `~/.rustup`,
|
|
18
|
+
`~/.npm`, `~/.bun`, `~/go`, `~/.deno`, `~/.gradle`, `~/.m2`, `~/.gem`, plus `~/Library/Caches`
|
|
19
|
+
+ `~/Library/pnpm` on macOS or `~/.cache` + `~/.local/{share,state}` on Linux. Credential dirs
|
|
20
|
+
(`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config`, `~/.netrc`) are deliberately excluded, so
|
|
21
|
+
`--mode auto` stays a real sandbox — far narrower than danger-full-access. Any
|
|
22
|
+
`writable_roots` you set yourself are preserved (unioned, never clobbered). Source:
|
|
23
|
+
`apps/cli/src/lib/permissions.ts` (`codexDefaultWritableRoots`, `mergeCodexSandboxWrite`).
|
|
24
|
+
|
|
25
|
+
- **`agents sessions` team rows now show the team's target and teammate, not just
|
|
26
|
+
the slug.** Each teammate row reads `<team> · <teammate> · by <orchestrator> ·
|
|
27
|
+
<live turn | mission>`, where the mission is a one-line summary of the teammate's
|
|
28
|
+
spawn prompt (`assignedTask`, shown even before it has a transcript). Several
|
|
29
|
+
teams from one orchestrator stay legible (distinct team names) and each says what
|
|
30
|
+
it is for. `--active --json` carries `assignedTask`. Source:
|
|
31
|
+
`apps/cli/src/lib/session/active.ts`, `apps/cli/src/commands/sessions.ts`.
|
|
32
|
+
|
|
33
|
+
## 1.20.83
|
|
34
|
+
|
|
35
|
+
- **Routines now treat date-specific cron schedules as one-shot jobs (RUSH-2074).**
|
|
36
|
+
`agents routines add --schedule "0 14 29 7 *"` now warns, persists
|
|
37
|
+
`runOnce: true`, marks the routine as one-shot in `routines list`, and
|
|
38
|
+
`agents routines cleanup` removes completed expired one-shots that still have
|
|
39
|
+
user-layer YAML. Source: `apps/cli/src/lib/routines.ts`,
|
|
40
|
+
`apps/cli/src/lib/scheduler.ts`, `apps/cli/src/commands/routines.ts`.
|
|
41
|
+
|
|
42
|
+
- **`agents routines list` groups terminal output by device and placement
|
|
43
|
+
(RUSH-2075).** The default table is bucketed under this machine, fleet-wide,
|
|
44
|
+
cloud, named devices, and named hosts with offline/unknown registry hints;
|
|
45
|
+
`--flat` keeps the legacy single table and `--json` remains a flat payload.
|
|
46
|
+
Source: `apps/cli/src/commands/routines.ts`.
|
|
47
|
+
|
|
48
|
+
- **`agents.yaml` no longer churns on every meta write.** `writeMetaUnlocked` wrote
|
|
49
|
+
the central config with `yaml.stringify`, which strips all comments — so the
|
|
50
|
+
freshly-serialized bytes never matched the comment-annotated file on disk,
|
|
51
|
+
`writeIfChanged` rewrote it on every meta write, and the perpetually-dirty tree
|
|
52
|
+
wedged `agents sync` ("Blocked by local changes") across the fleet. It now
|
|
53
|
+
serializes via a `yaml.Document` round-trip (`serializeCentral`) that edits only
|
|
54
|
+
the keys that actually changed, so comments, key ordering, and untouched
|
|
55
|
+
top-level blocks (e.g. `hosts:`) are byte-stable — and a write that changes no
|
|
56
|
+
central field leaves `agents.yaml` untouched. Source: `apps/cli/src/lib/state.ts`.
|
|
57
|
+
|
|
58
|
+
- **`agents run codex` can now reach the fleet from inside its sandbox.** Codex's
|
|
59
|
+
`workspace-write` sandbox blocks `$HOME` (verified against the live CLI and OpenAI's
|
|
60
|
+
sandbox docs), but the model routinely shells out to `agents ...`, whose runtime state
|
|
61
|
+
lives under `~/.agents` — the SSH askpass shim (`~/.agents/.cache/devices/askpass.sh`),
|
|
62
|
+
the device/stats cache, secrets, session writes, config tunings. Those inner writes hit
|
|
63
|
+
`EROFS` (`agents ssh` died before connecting, so a remote `agents run codex` could not
|
|
64
|
+
SSH or self-tune), and the fix was previously left to the caller (teams pass
|
|
65
|
+
`--add-dir ~/.agents` explicitly; a plain `agents run` never did). `buildExecCommand`
|
|
66
|
+
now grants `~/.agents` as an extra writable root whenever Codex runs `workspace-write`
|
|
67
|
+
(`--mode edit`/`auto`) — via `--add-dir` on fresh runs (deduped against user
|
|
68
|
+
`--add-dir`s) and via `-c sandbox_workspace_write.writable_roots` on resume forms (which
|
|
69
|
+
reject `--add-dir`). This is the officially-recommended way to widen scope "without
|
|
70
|
+
removing the sandbox entirely" — far narrower than `--mode skip` (danger-full-access).
|
|
71
|
+
`plan` (read-only) and `skip` (sandbox already dropped) are unaffected. Source:
|
|
72
|
+
`apps/cli/src/lib/exec.ts` (`buildExecCommand`, `codexWritableRootsConfig`).
|
|
73
|
+
|
|
74
|
+
- **Fix headless release signing (`errSecInternalComponent`).** `headless-sign-context.sh` now runs `security set-key-partition-list` right after unlocking `rush-signing.keychain-db`, authorizing `codesign`/`apple-tool` to use the Developer ID key non-interactively. Without it, the key's ACL prompts for UI approval that a headless SSH release session can't answer, so `codesign` fails and the npm publish halts. Idempotent; runs every release. Source: `apps/cli/scripts/headless-sign-context.sh`.
|
|
75
|
+
|
|
76
|
+
- **Cmd-Shift-V clip paste no longer breaks with an "sshd-keygen-wrapper would like
|
|
77
|
+
to control this computer" prompt.** A menu-bar helper started from an ssh session
|
|
78
|
+
registered the global chords but could never service them: macOS attributes its
|
|
79
|
+
Accessibility request to the responsible process, `/usr/libexec/sshd-keygen-wrapper`,
|
|
80
|
+
not to the helper's bundle, so the prompt named a process whose grant does nothing
|
|
81
|
+
for the paste (and, if granted, hands keystroke synthesis to everything any ssh
|
|
82
|
+
session spawns). `RegisterEventHotKey` is first-come, and the prompt naming
|
|
83
|
+
sshd-keygen-wrapper is itself the evidence that this copy — not the trusted
|
|
84
|
+
launchd-managed one — had registered Cmd-Shift-V and was servicing it. The
|
|
85
|
+
interactive mode now refuses to start over a remote shell, and refuses
|
|
86
|
+
unrecognized arguments: an unknown flag used to fall straight through to the
|
|
87
|
+
status-bar app, which is how a stray `MenubarHelper --self-test` from a verify run
|
|
88
|
+
became a permanent second helper. `launchctl bootstrap` (`agents menubar enable`)
|
|
89
|
+
is unaffected, including when run over ssh. Source:
|
|
90
|
+
`apps/cli/menubar/Sources/MenubarHelper/Guards.swift`.
|
|
91
|
+
|
|
92
|
+
- **`agents menubar status` now names a second helper process instead of reporting a
|
|
93
|
+
healthy `running: yes`.** The check was `pgrep -f MenubarHelper`, which matches any
|
|
94
|
+
process with that name, so a stray copy holding the global chords looked identical
|
|
95
|
+
to a working install. Status now identifies the helper by its resolved executable
|
|
96
|
+
(`ps -o comm=`), reports `running` only for the installed bundle, and lists every
|
|
97
|
+
other live copy with its pid under `foreignInstances` (also in `--json`). Source:
|
|
98
|
+
`apps/cli/src/lib/menubar/install-menubar.ts`.
|
|
99
|
+
|
|
100
|
+
- **The menu bar now says so when a hotkey is unavailable or the paste is not
|
|
101
|
+
permitted.** A `RegisterEventHotKey` conflict only wrote a line to a launchd log,
|
|
102
|
+
and a missing Accessibility grant made `Clip.inject` return silently — both looked
|
|
103
|
+
exactly like a dead hotkey. A stolen chord now posts a notification naming it, and a
|
|
104
|
+
denied grant copies the `host:path` reference to the clipboard and says which
|
|
105
|
+
setting to grant, so the clip is never lost. Source:
|
|
106
|
+
`apps/cli/menubar/Sources/MenubarHelper/Hotkey.swift`,
|
|
107
|
+
`apps/cli/menubar/Sources/MenubarHelper/Clip.swift`.
|
|
108
|
+
|
|
109
|
+
- **Fix the release catch-up path aborting on an unbound variable.** When a release PR had already merged and only the tag + publish remained, `release.sh` re-validated CI and then aborted with `line 933: RELEASE_COMMIT: unbound variable`, so the retry never reached npm. The catch-up block that runs when `main` sits exactly at the release merge commit never set `HISTORICAL_CATCHUP`, so phase 4 took the normal-release branch and read `RELEASE_COMMIT`, which only the branch-creating path defines. It now sets the flag, and phase 4 resolves the release commit from the merged PR (`MERGED_RELEASE_SHA` + `CI_TESTED_HEAD`) as intended. This is why 1.20.79, 1.20.80, and 1.20.81 were tagged but never published. Source: `apps/cli/scripts/release.sh`.
|
|
110
|
+
|
|
111
|
+
- **Removed `agents check` / `agents resources` now forward to their replacements
|
|
112
|
+
instead of erroring (RUSH-1234).** After the command consolidation, running the
|
|
113
|
+
removed names produced a bare `unknown command` (their edit-distance to `doctor`
|
|
114
|
+
was too far to even trigger a "did you mean"). They are now hidden tombstone
|
|
115
|
+
commands that print a one-line deprecation notice to stderr and re-run the
|
|
116
|
+
replacement, preserving flags and exit codes: `agents check …` runs
|
|
117
|
+
`agents doctor --check …` (so `--json` / `--quiet` / `--devices` and the CI
|
|
118
|
+
drift-gate exit code carry through), and `agents resources …` runs
|
|
119
|
+
`agents view --merged …` (with `agents inspect <target>` pointed to for
|
|
120
|
+
per-agent/per-repo detail). The notice goes to stderr so a `--json` consumer's
|
|
121
|
+
stdout stays clean. Source: `apps/cli/src/index.ts`.
|
|
122
|
+
|
|
123
|
+
- **`agents sessions --host`/`--device <box>` now opens the interactive fleet
|
|
124
|
+
browser instead of a raw text dump.** A bare remote listing on a TTY folds the
|
|
125
|
+
named box into the same preview-rich, selectable picker as the local view (it
|
|
126
|
+
previously short-circuited to the legacy per-host stream — non-interactive, no
|
|
127
|
+
previews). A `--host` *query*, a render/filter flag, `--json`, or a
|
|
128
|
+
non-interactive caller keep the streamed output. Source:
|
|
129
|
+
`apps/cli/src/commands/sessions.ts`.
|
|
130
|
+
|
|
131
|
+
- **`agents sessions` now shows which orchestrator spawned each team.** A teams
|
|
132
|
+
teammate row was keyed off its orchestrator's session id (captured from
|
|
133
|
+
`AGENTS_SESSION_ID` at spawn), which both hid the lineage and mislabeled the
|
|
134
|
+
teammate with the orchestrator's id/topic. The teammate now keys off its own
|
|
135
|
+
transcript, exposes the orchestrator as `orchestratorSessionId` (+ a resolved
|
|
136
|
+
`orchestratorLabel`) in `--active --json`, and the listing renders
|
|
137
|
+
`<team> · by <orchestrator>` so "which session spun up this team" is answerable
|
|
138
|
+
at a glance. Source: `apps/cli/src/lib/session/active.ts`,
|
|
139
|
+
`apps/cli/src/commands/sessions.ts`.
|
|
140
|
+
|
|
3
141
|
## 1.20.82
|
|
4
142
|
|
|
5
143
|
- **Codex hook sync no longer leaves startup warnings after upgrades.** The Codex
|
package/README.md
CHANGED
|
@@ -306,7 +306,7 @@ agents sessions detach a1b2c3d4 # go headless in the background, keep workin
|
|
|
306
306
|
agents sessions attach a1b2c3d4 # resume it interactively, right here
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
-
Both are agent-agnostic -- they route through the same `agents run --resume` path (native resume for Claude/Codex, `/continue` replay for the rest). `agents sessions --active`
|
|
309
|
+
Both are agent-agnostic -- they route through the same `agents run --resume` path (native resume for Claude/Codex, `/continue` replay for the rest). `agents sessions --active` shows each session's **owner** (the human who launched it, resolved from the tailnet identity, or `-` for an unresolved local run) and its `presence` -- `attached` (you're watching it), `background` (running headless), or `parked` (its background run finished) -- so the menu bar and Factory show who is running what, and where. In the Factory extension, **Agents: Detach** (`Cmd/Ctrl+K B`) and **Agents: Attach** (`Cmd/Ctrl+K A`) do the same over the focused terminal.
|
|
310
310
|
|
|
311
311
|
---
|
|
312
312
|
|
package/dist/bin/agents
CHANGED
|
Binary file
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import type { Command } from 'commander';
|
|
25
25
|
import { type FleetDivergenceReport } from '../lib/devices/fleet-divergence.js';
|
|
26
26
|
import { type VersionResourceReport } from '../lib/doctor-diff.js';
|
|
27
|
+
import { type DuplicateVersionHook } from '../lib/hooks.js';
|
|
27
28
|
import { type SyncStatusRow, type OrphanRow } from '../lib/drift.js';
|
|
28
29
|
import { type FetchStatusMarker } from '../lib/auto-pull.js';
|
|
29
30
|
export declare function wrapLine(prefix: string, text: string, width?: number): string[];
|
|
@@ -106,5 +107,5 @@ export declare function healthBlockLines(verdict: DoctorVerdict, opts: {
|
|
|
106
107
|
* and orphan resources into severity-tagged findings. Agent-agnostic: every
|
|
107
108
|
* installed version is classified the same way. Pure, so it is unit-testable.
|
|
108
109
|
*/
|
|
109
|
-
export declare function computeOverviewHealth(syncRows: SyncStatusRow[], orphanRows: OrphanRow[], repoBehindMarkers: FetchStatusMarker[]): DoctorVerdict;
|
|
110
|
+
export declare function computeOverviewHealth(syncRows: SyncStatusRow[], orphanRows: OrphanRow[], repoBehindMarkers: FetchStatusMarker[], duplicateHooks?: DuplicateVersionHook[]): DoctorVerdict;
|
|
110
111
|
export declare function registerDoctorCommand(program: Command): void;
|
package/dist/commands/doctor.js
CHANGED
|
@@ -18,7 +18,7 @@ import { formatSignInBadge } from '../lib/signin-badge.js';
|
|
|
18
18
|
import { getGlobalDefault, getVersionHomePath, isVersionInstalled, listInstalledVersions, parseAgentSpec, } from '../lib/versions.js';
|
|
19
19
|
import { loadManifest, isStale } from '../lib/staleness/index.js';
|
|
20
20
|
import { diffVersionResources, DOCTOR_ALL_KINDS, } from '../lib/doctor-diff.js';
|
|
21
|
-
import { checkVersionHookWiring, registerHooksToSettings } from '../lib/hooks.js';
|
|
21
|
+
import { checkVersionHookWiring, inspectDuplicateVersionHooks, registerHooksToSettings } from '../lib/hooks.js';
|
|
22
22
|
import { isVersionIsolated } from '../lib/versions.js';
|
|
23
23
|
import { computeDrift, checkSyncStatus, countOrphans, computeSourceBehind } from '../lib/drift.js';
|
|
24
24
|
import { readAuthHealthCache, summarizeHostAuth } from '../lib/auth-health.js';
|
|
@@ -67,11 +67,11 @@ function printWrappedLine(prefix, text) {
|
|
|
67
67
|
for (const line of wrapLine(prefix, text))
|
|
68
68
|
console.log(chalk.gray(line));
|
|
69
69
|
}
|
|
70
|
-
function renderOverviewText(clis, syncRows, orphanRows, hostClis, signIn, repoBehindMarkers) {
|
|
70
|
+
function renderOverviewText(clis, syncRows, orphanRows, hostClis, signIn, repoBehindMarkers, duplicateHooks) {
|
|
71
71
|
// Triaged health banner FIRST, so a user running bare `agents doctor` sees what
|
|
72
72
|
// is unhealthy, why it matters, and the exact fix before scrolling the detail
|
|
73
73
|
// sections below. Same triage model as target mode, aggregated across versions.
|
|
74
|
-
const overviewHealth = computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers);
|
|
74
|
+
const overviewHealth = computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers, duplicateHooks);
|
|
75
75
|
console.log(chalk.bold('Health'));
|
|
76
76
|
renderHealthBlock(overviewHealth, {
|
|
77
77
|
healthySummary: syncRows.length
|
|
@@ -827,9 +827,26 @@ function renderHealthBlock(verdict, opts) {
|
|
|
827
827
|
* and orphan resources into severity-tagged findings. Agent-agnostic: every
|
|
828
828
|
* installed version is classified the same way. Pure, so it is unit-testable.
|
|
829
829
|
*/
|
|
830
|
-
export function computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers) {
|
|
830
|
+
export function computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers, duplicateHooks = []) {
|
|
831
831
|
const issues = [];
|
|
832
832
|
const pretty = (agent, version) => `${AGENT_NAMES[agent] || agent}@${version}`;
|
|
833
|
+
// critical/warning: same hook resource materialized in several version homes.
|
|
834
|
+
// Different content is more severe because a stale copy can disagree with
|
|
835
|
+
// the active gate; byte-identical copies are noise and duplicate runtime cost.
|
|
836
|
+
for (const finding of duplicateHooks) {
|
|
837
|
+
const versions = finding.copies.map((copy) => copy.version).join(', ');
|
|
838
|
+
const active = finding.authoritative.version;
|
|
839
|
+
const drift = finding.kind === 'drift';
|
|
840
|
+
issues.push({
|
|
841
|
+
severity: drift ? 'critical' : 'warning',
|
|
842
|
+
category: drift ? 'duplicate-hook-drift' : 'duplicate-hook',
|
|
843
|
+
subject: `${finding.agent}/${finding.name}`,
|
|
844
|
+
impact: `${drift ? 'different content' : 'identical content'} across versions ${versions}; ${active} is authoritative`,
|
|
845
|
+
fix: `agents sync ${finding.agent}@${active} --yes`,
|
|
846
|
+
text: `${finding.name} ${drift ? 'drift' : 'duplicated'} across ${versions}`,
|
|
847
|
+
color: drift ? 'red' : 'yellow',
|
|
848
|
+
});
|
|
849
|
+
}
|
|
833
850
|
// critical: unwired hooks / broken settings.json per version
|
|
834
851
|
for (const row of syncRows) {
|
|
835
852
|
const n = row.unwiredHooks ?? 0;
|
|
@@ -1406,6 +1423,7 @@ export function registerDoctorCommand(program) {
|
|
|
1406
1423
|
const orphanRows = countOrphans();
|
|
1407
1424
|
const hostClis = listCliStatus(cwd);
|
|
1408
1425
|
const repoBehindMarkers = readRepoBehindMarkers();
|
|
1426
|
+
const duplicateHooks = inspectDuplicateVersionHooks(cwd);
|
|
1409
1427
|
// Advisory login state per installed agent (file-based getAccountInfo,
|
|
1410
1428
|
// no home → the account-global/active credential). Best-effort: a probe
|
|
1411
1429
|
// failure just leaves that agent's badge as "logged out".
|
|
@@ -1433,7 +1451,8 @@ export function registerDoctorCommand(program) {
|
|
|
1433
1451
|
// Triaged overview health — severity/category/subject/impact/fix per
|
|
1434
1452
|
// finding, aggregated across versions. Additive; existing consumers
|
|
1435
1453
|
// reading `sync`/`orphans`/`repos` are unaffected.
|
|
1436
|
-
health: computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers),
|
|
1454
|
+
health: computeOverviewHealth(syncRows, orphanRows, repoBehindMarkers, duplicateHooks),
|
|
1455
|
+
duplicateHooks,
|
|
1437
1456
|
// This host's harness inventory — installed resources per kind,
|
|
1438
1457
|
// installed version ids per agent, and `.agents`/`.system` repo
|
|
1439
1458
|
// state — so `agents doctor --devices` can compare presence across
|
|
@@ -1461,7 +1480,7 @@ export function registerDoctorCommand(program) {
|
|
|
1461
1480
|
}, null, 2));
|
|
1462
1481
|
return;
|
|
1463
1482
|
}
|
|
1464
|
-
renderOverviewText(clis, syncRows, orphanRows, hostClis, signIn, repoBehindMarkers);
|
|
1483
|
+
renderOverviewText(clis, syncRows, orphanRows, hostClis, signIn, repoBehindMarkers, duplicateHooks);
|
|
1465
1484
|
// Point at the interactive reconcile when anything is out of sync — the
|
|
1466
1485
|
// report shouldn't be a dead end. `agents status` runs the unified
|
|
1467
1486
|
// home-reading engine and offers to sync (opt-in, never auto-fires here).
|
package/dist/commands/menubar.js
CHANGED
|
@@ -65,6 +65,18 @@ export function registerMenubarCommands(program) {
|
|
|
65
65
|
console.log(` current version ${chalk.gray(s.currentVersion)}`);
|
|
66
66
|
console.log(` bundle source ${s.source ? chalk.gray(s.source) : chalk.red('missing (cannot enable)')}`);
|
|
67
67
|
console.log(` disabled by user ${yn(s.disabledByUser)}`);
|
|
68
|
+
if (s.foreignInstances.length > 0) {
|
|
69
|
+
// RegisterEventHotKey is first-come, so the helper that registered the
|
|
70
|
+
// chord first owns Cmd-Shift-V/O. A process list cannot say which that
|
|
71
|
+
// was — only that a rival exists — so report the conflict, not a
|
|
72
|
+
// winner. The loser
|
|
73
|
+
// has no other symptom: its chords simply never fire.
|
|
74
|
+
const n = s.foreignInstances.length;
|
|
75
|
+
console.log(chalk.yellow(`\n ${n} other helper process${n === 1 ? '' : 'es'} running — ${n === 1 ? 'it' : 'they'} may hold Cmd-Shift-V/O instead of the installed one:`));
|
|
76
|
+
for (const p of s.foreignInstances)
|
|
77
|
+
console.log(chalk.gray(` ${p.pid} ${p.executable}`));
|
|
78
|
+
console.log(chalk.gray(' End it, then `agents menubar enable` to restart the installed helper.'));
|
|
79
|
+
}
|
|
68
80
|
if (s.stale) {
|
|
69
81
|
console.log(chalk.yellow('\n Installed helper is stale — runs on next `agents` startup, or `agents menubar enable` now.'));
|
|
70
82
|
}
|
|
@@ -6,13 +6,20 @@
|
|
|
6
6
|
* Also exposes scheduler lifecycle controls (start/stop/status/logs).
|
|
7
7
|
*/
|
|
8
8
|
import type { Command } from 'commander';
|
|
9
|
-
import type { RunMeta } from '../lib/routines.js';
|
|
9
|
+
import type { JobConfig, RunMeta } from '../lib/routines.js';
|
|
10
|
+
import type { DeviceRegistry } from '../lib/devices/registry.js';
|
|
10
11
|
/**
|
|
11
12
|
* Human-friendly wall-clock a run took (e.g. " · 3 min", " · 45 sec"), or ""
|
|
12
13
|
* when it hasn't completed or timestamps are unparseable. Leading separator lets
|
|
13
14
|
* callers drop it straight into a status line.
|
|
14
15
|
*/
|
|
15
16
|
export declare function formatRunDuration(startedAt: string, completedAt: string | null): string;
|
|
17
|
+
export interface RoutineListGroup {
|
|
18
|
+
key: string;
|
|
19
|
+
title: string;
|
|
20
|
+
jobs: JobConfig[];
|
|
21
|
+
}
|
|
22
|
+
export declare function groupRoutineJobsByDevice(jobs: JobConfig[], registry: DeviceRegistry, self?: string): RoutineListGroup[];
|
|
16
23
|
export declare function buildRunsJson(runs: RunMeta[]): Record<string, unknown>[];
|
|
17
24
|
/** Register the `agents routines` command tree. */
|
|
18
25
|
export declare function registerRoutinesCommands(program: Command): void;
|