@phnx-labs/agents-cli 1.20.83 → 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 +30 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/sessions.js +12 -6
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/permissions.d.ts +21 -0
- package/dist/lib/permissions.js +57 -2
- 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 +15 -0
- package/dist/lib/session/active.js +17 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
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
|
+
|
|
3
33
|
## 1.20.83
|
|
4
34
|
|
|
5
35
|
- **Routines now treat date-specific cron schedules as one-shot jobs (RUSH-2074).**
|
package/dist/bin/agents
CHANGED
|
Binary file
|
|
@@ -247,7 +247,13 @@ export function buildSessionDescription(s) {
|
|
|
247
247
|
return cleanPreview([todo, base].filter(Boolean).join(' · '));
|
|
248
248
|
}
|
|
249
249
|
if (s.context === 'teams') {
|
|
250
|
+
// A teams row identifies its TEAM, then the teammate within it, then who
|
|
251
|
+
// spun it up, then what it's working on — so several teams from one
|
|
252
|
+
// orchestrator stay distinct and each shows its target, not just its slug.
|
|
250
253
|
const parts = [s.teamName];
|
|
254
|
+
// Teammate name (distinct from the team slug) — which member this row is.
|
|
255
|
+
if (s.label && s.label !== s.teamName)
|
|
256
|
+
parts.push(s.label);
|
|
251
257
|
// Lineage: which orchestrator spun up this team. Prefer the resolved label,
|
|
252
258
|
// else the short session id, so "by whom" is answerable at a glance.
|
|
253
259
|
const orch = s.orchestratorLabel || (s.orchestratorSessionId ? s.orchestratorSessionId.slice(0, 8) : '');
|
|
@@ -255,12 +261,12 @@ export function buildSessionDescription(s) {
|
|
|
255
261
|
parts.push(`by ${orch}`);
|
|
256
262
|
if (todo)
|
|
257
263
|
parts.push(todo);
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
parts.push(
|
|
264
|
+
// Target: the live latest turn if working, else the assigned mission (the
|
|
265
|
+
// team's task/target, shown even before the teammate has a transcript), else
|
|
266
|
+
// the transcript topic.
|
|
267
|
+
const target = s.preview || s.assignedTask || s.topic;
|
|
268
|
+
if (target)
|
|
269
|
+
parts.push(target);
|
|
264
270
|
return cleanPreview(parts.filter(Boolean).join(' · '));
|
|
265
271
|
}
|
|
266
272
|
// Terminal, headless, or sub-agent: todos + live preview, then label, then topic.
|
|
Binary file
|
|
@@ -233,6 +233,27 @@ export declare function convertToKimiFormat(set: PermissionSet): {
|
|
|
233
233
|
* OpenCode uses: { permission: { bash: { "git *": "allow", "rm *": "deny" } } }
|
|
234
234
|
*/
|
|
235
235
|
export declare function convertToOpenCodeFormat(set: PermissionSet): OpenCodePermissions;
|
|
236
|
+
/**
|
|
237
|
+
* Default extra writable roots for Codex's `workspace-write` sandbox: the
|
|
238
|
+
* regenerable package/toolchain caches that build/test/install write OUTSIDE the
|
|
239
|
+
* workspace (cargo registry, npm/bun/pnpm caches, GOPATH/GOCACHE, the OS cache
|
|
240
|
+
* root, …). Without these, a sandboxed `cargo build` / `go build` / `npm install`
|
|
241
|
+
* fails on its cache write, which is what pushes users to `--mode full` (YOLO).
|
|
242
|
+
*
|
|
243
|
+
* Credential dirs (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config`, `~/.netrc`) are
|
|
244
|
+
* deliberately EXCLUDED so the sandbox stays meaningful — this is far from
|
|
245
|
+
* danger-full-access. Resolved per platform + home; each box regenerates its own
|
|
246
|
+
* Codex config on sync, so the paths always match the box Codex runs on.
|
|
247
|
+
*/
|
|
248
|
+
export declare function codexDefaultWritableRoots(home?: string, platform?: NodeJS.Platform): string[];
|
|
249
|
+
/**
|
|
250
|
+
* Merge Codex `[sandbox_workspace_write]` config, UNIONing `writable_roots` so a
|
|
251
|
+
* baseline cache root never clobbers a root the user configured directly (a
|
|
252
|
+
* plain object spread would overwrite the whole array), while merging scalar
|
|
253
|
+
* keys (`network_access`) normally. Shared by the user- and version-scoped Codex
|
|
254
|
+
* config writers so the two can't drift.
|
|
255
|
+
*/
|
|
256
|
+
export declare function mergeCodexSandboxWrite(existing: Record<string, unknown> | undefined, incoming: NonNullable<CodexPermissions['sandbox_workspace_write']>): Record<string, unknown>;
|
|
236
257
|
/**
|
|
237
258
|
* Convert canonical permission set to Codex format.
|
|
238
259
|
* Codex uses coarse-grained modes, so we infer the best fit.
|
package/dist/lib/permissions.js
CHANGED
|
@@ -1007,6 +1007,48 @@ export function convertToOpenCodeFormat(set) {
|
|
|
1007
1007
|
},
|
|
1008
1008
|
};
|
|
1009
1009
|
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Default extra writable roots for Codex's `workspace-write` sandbox: the
|
|
1012
|
+
* regenerable package/toolchain caches that build/test/install write OUTSIDE the
|
|
1013
|
+
* workspace (cargo registry, npm/bun/pnpm caches, GOPATH/GOCACHE, the OS cache
|
|
1014
|
+
* root, …). Without these, a sandboxed `cargo build` / `go build` / `npm install`
|
|
1015
|
+
* fails on its cache write, which is what pushes users to `--mode full` (YOLO).
|
|
1016
|
+
*
|
|
1017
|
+
* Credential dirs (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config`, `~/.netrc`) are
|
|
1018
|
+
* deliberately EXCLUDED so the sandbox stays meaningful — this is far from
|
|
1019
|
+
* danger-full-access. Resolved per platform + home; each box regenerates its own
|
|
1020
|
+
* Codex config on sync, so the paths always match the box Codex runs on.
|
|
1021
|
+
*/
|
|
1022
|
+
export function codexDefaultWritableRoots(home = HOME, platform = process.platform) {
|
|
1023
|
+
const shared = ['.cargo', '.rustup', '.npm', '.bun', 'go', '.deno', '.gradle', '.m2', '.gem'];
|
|
1024
|
+
const roots = shared.map((d) => path.join(home, d));
|
|
1025
|
+
if (platform === 'darwin') {
|
|
1026
|
+
roots.push(path.join(home, 'Library', 'Caches'), path.join(home, 'Library', 'pnpm'));
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
// Linux/XDG: ~/.cache covers pip, uv, go-build, ms-playwright, etc.
|
|
1030
|
+
roots.push(path.join(home, '.cache'), path.join(home, '.local', 'share'), path.join(home, '.local', 'state'));
|
|
1031
|
+
}
|
|
1032
|
+
return roots;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Merge Codex `[sandbox_workspace_write]` config, UNIONing `writable_roots` so a
|
|
1036
|
+
* baseline cache root never clobbers a root the user configured directly (a
|
|
1037
|
+
* plain object spread would overwrite the whole array), while merging scalar
|
|
1038
|
+
* keys (`network_access`) normally. Shared by the user- and version-scoped Codex
|
|
1039
|
+
* config writers so the two can't drift.
|
|
1040
|
+
*/
|
|
1041
|
+
export function mergeCodexSandboxWrite(existing, incoming) {
|
|
1042
|
+
const existingRoots = Array.isArray(existing?.writable_roots)
|
|
1043
|
+
? existing.writable_roots
|
|
1044
|
+
: [];
|
|
1045
|
+
const unionRoots = [...new Set([...existingRoots, ...(incoming.writable_roots ?? [])])];
|
|
1046
|
+
return {
|
|
1047
|
+
...existing,
|
|
1048
|
+
...incoming,
|
|
1049
|
+
...(unionRoots.length > 0 ? { writable_roots: unionRoots } : {}),
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1010
1052
|
/**
|
|
1011
1053
|
* Convert canonical permission set to Codex format.
|
|
1012
1054
|
* Codex uses coarse-grained modes, so we infer the best fit.
|
|
@@ -1042,6 +1084,15 @@ export function convertToCodexFormat(set, cwd) {
|
|
|
1042
1084
|
network_access: true,
|
|
1043
1085
|
};
|
|
1044
1086
|
}
|
|
1087
|
+
// Baseline (unconditional): always grant the regenerable build/test/install
|
|
1088
|
+
// caches as writable roots so `agents run codex` in workspace-write can build,
|
|
1089
|
+
// test, and install without escalating to danger-full-access. Merged with
|
|
1090
|
+
// network_access above when set; applyCodexPermissions unions these with any
|
|
1091
|
+
// writable_roots the user configured directly.
|
|
1092
|
+
result.sandbox_workspace_write = {
|
|
1093
|
+
...result.sandbox_workspace_write,
|
|
1094
|
+
writable_roots: codexDefaultWritableRoots(),
|
|
1095
|
+
};
|
|
1045
1096
|
return result;
|
|
1046
1097
|
}
|
|
1047
1098
|
// ============================================================================
|
|
@@ -1333,8 +1384,10 @@ function applyCodexPermissions(set, scope = 'user', cwd, merge = true) {
|
|
|
1333
1384
|
}
|
|
1334
1385
|
if (newPermissions.sandbox_workspace_write) {
|
|
1335
1386
|
const existing = config.sandbox_workspace_write;
|
|
1387
|
+
// merge=false is a deliberate full replace (drops any user-custom roots);
|
|
1388
|
+
// production sync always passes merge=true, taking the union path.
|
|
1336
1389
|
config.sandbox_workspace_write = merge
|
|
1337
|
-
?
|
|
1390
|
+
? mergeCodexSandboxWrite(existing, newPermissions.sandbox_workspace_write)
|
|
1338
1391
|
: newPermissions.sandbox_workspace_write;
|
|
1339
1392
|
}
|
|
1340
1393
|
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
@@ -1450,8 +1503,10 @@ export function applyPermissionsToVersion(agentId, set, versionHome, merge = tru
|
|
|
1450
1503
|
}
|
|
1451
1504
|
if (newPermissions.sandbox_workspace_write) {
|
|
1452
1505
|
const existing = config.sandbox_workspace_write;
|
|
1506
|
+
// merge=false is a deliberate full replace (drops any user-custom roots);
|
|
1507
|
+
// production sync always passes merge=true, taking the union path.
|
|
1453
1508
|
config.sandbox_workspace_write = merge
|
|
1454
|
-
?
|
|
1509
|
+
? mergeCodexSandboxWrite(existing, newPermissions.sandbox_workspace_write)
|
|
1455
1510
|
: newPermissions.sandbox_workspace_write;
|
|
1456
1511
|
}
|
|
1457
1512
|
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
Binary file
|
|
Binary file
|
|
@@ -158,6 +158,15 @@ export interface ActiveSession {
|
|
|
158
158
|
/** Display label for the orchestrator (its topic/label), resolved when the
|
|
159
159
|
* orchestrator is itself present in the active set. Display-only. */
|
|
160
160
|
orchestratorLabel?: string;
|
|
161
|
+
/**
|
|
162
|
+
* For a teams teammate: a one-line summary of the mission it was spawned with
|
|
163
|
+
* (the `prompt` stored on the teammate record — the team's task/target), so the
|
|
164
|
+
* listing answers "what is this team working on", not just its name. Survives
|
|
165
|
+
* before the teammate has produced any transcript (a pending/staged teammate
|
|
166
|
+
* still shows its target). Distinct from `topic`, which is derived from the
|
|
167
|
+
* teammate's own transcript once it starts.
|
|
168
|
+
*/
|
|
169
|
+
assignedTask?: string;
|
|
161
170
|
agentId?: string;
|
|
162
171
|
cloudProvider?: string;
|
|
163
172
|
cloudTaskId?: string;
|
|
@@ -338,6 +347,12 @@ interface LiveSignals {
|
|
|
338
347
|
* {@link resolveFallbackStatus} reports the honest live floor (`running`).
|
|
339
348
|
*/
|
|
340
349
|
export declare function computeLiveSignals(kind: string, sessionFile: string | undefined, cwd: string | undefined, pidAlive: boolean): LiveSignals;
|
|
350
|
+
/**
|
|
351
|
+
* One-line summary of a teammate's spawn prompt — the team's task/target. Takes
|
|
352
|
+
* the first non-empty line, strips a leading `MISSION:`/`CONTEXT:`/`TASK:` label,
|
|
353
|
+
* and truncates. Exported for tests.
|
|
354
|
+
*/
|
|
355
|
+
export declare function summarizeMission(prompt: string | null | undefined): string | undefined;
|
|
341
356
|
/** Live teams teammates. Reuses AgentManager which already polls PIDs via `kill -0`. */
|
|
342
357
|
export declare function listTeamsActive(): Promise<ActiveSession[]>;
|
|
343
358
|
/** Live editor-terminal agents across every IDE window. */
|
|
@@ -576,6 +576,22 @@ function quickExtractTopic(sessionFile) {
|
|
|
576
576
|
}
|
|
577
577
|
return undefined;
|
|
578
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* One-line summary of a teammate's spawn prompt — the team's task/target. Takes
|
|
581
|
+
* the first non-empty line, strips a leading `MISSION:`/`CONTEXT:`/`TASK:` label,
|
|
582
|
+
* and truncates. Exported for tests.
|
|
583
|
+
*/
|
|
584
|
+
export function summarizeMission(prompt) {
|
|
585
|
+
if (!prompt)
|
|
586
|
+
return undefined;
|
|
587
|
+
const firstLine = prompt.split('\n').map((l) => l.trim()).find(Boolean);
|
|
588
|
+
if (!firstLine)
|
|
589
|
+
return undefined;
|
|
590
|
+
const cleaned = firstLine.replace(/^(MISSION|CONTEXT|TASK|GOAL|OBJECTIVE)\s*[:\-—]\s*/i, '').trim();
|
|
591
|
+
if (!cleaned)
|
|
592
|
+
return undefined;
|
|
593
|
+
return cleaned.length > 80 ? `${cleaned.slice(0, 79)}…` : cleaned;
|
|
594
|
+
}
|
|
579
595
|
/** Live teams teammates. Reuses AgentManager which already polls PIDs via `kill -0`. */
|
|
580
596
|
export async function listTeamsActive() {
|
|
581
597
|
const mgr = new AgentManager();
|
|
@@ -607,6 +623,7 @@ export async function listTeamsActive() {
|
|
|
607
623
|
startedAtMs: a.startedAt.getTime(),
|
|
608
624
|
lastActivityMs: sessionFileTimes(sessionFile).mtimeMs,
|
|
609
625
|
teamName: a.taskName,
|
|
626
|
+
assignedTask: summarizeMission(a.prompt),
|
|
610
627
|
agentId: a.agentId,
|
|
611
628
|
// The frozen actor stamped on the teammate record (RUSH-2028) — who ran
|
|
612
629
|
// this teammate, surfaced as the owner in --active (RUSH-2018); sidecar
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.84",
|
|
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",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"start": "node dist/index.js",
|
|
56
56
|
"test": "node ./node_modules/vitest/vitest.mjs run",
|
|
57
57
|
"test:remote": "scripts/sandbox.sh 'bun install && bun run build && bun run test'",
|
|
58
|
+
"verify-docs": "scripts/verify-docs.sh",
|
|
58
59
|
"test:watch": "node ./node_modules/vitest/vitest.mjs"
|
|
59
60
|
},
|
|
60
61
|
"keywords": [
|