@phnx-labs/agents-cli 1.22.96 → 1.22.98
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 +12 -0
- package/dist/commands/browser.js +7 -3
- package/dist/commands/setup-browser.js +2 -1
- package/dist/lib/browser/chrome.js +4 -3
- package/dist/lib/browser/service.js +7 -4
- package/dist/lib/codex-home.d.ts +44 -12
- package/dist/lib/codex-home.js +123 -37
- package/dist/lib/harness/adapters/codex.js +7 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.98
|
|
4
|
+
|
|
5
|
+
- `agents run codex#<account>` on macOS now runs as that account. The SUN_LEN short-home relocation keyed `CODEX_HOME` by version alone, so an account slot (long enough to overflow too) was silently redirected to the default version's `~/.agents/.codex-homes/<version>/.codex` and its login — `agents run codex#getrush` opened the gmail session while the banner still said `getrush`. The short home is now keyed by the origin (`a-<account id>` for a slot). A version/account reinstall that recreates a fresh `.codex` adopts its existing short home (which holds the login) instead of failing, and a slot mis-linked onto a foreign home by the old layout is repointed to its own home rather than run as the wrong account.
|
|
6
|
+
|
|
7
|
+
- **A Firefox task no longer parks the browser-task reaper, and `record` on Firefox says "recording" (PHNX-4043).** The daemon's idle reaper asks every live task for its recording status before closing it; on a Firefox (or native Arc) task that query threw a capability error, so one Firefox task failed every reap tick and the `browser-task-reap` service parked after three failures, leaving abandoned tabs open for every profile on that box. Recording status on a backend that cannot record is now a truthful "not recording". `agents browser record start`/`stop` and `start --record` on a Firefox profile still fail loud, now naming `recording` instead of `screenshot` (screenshots do work on Firefox). Source: `cli/src/lib/browser/service.ts` `recordStart`/`recordStop`/`recordStatus`.
|
|
8
|
+
|
|
9
|
+
## 1.22.97
|
|
10
|
+
|
|
11
|
+
- `agents browser --help` and the `agents setup browser` install hint no longer claim Firefox is unsupported: they now state Chromium-family over CDP, Arc natively, and Firefox over WebDriver BiDi (Safari stays unsupported). `tabs --all` gains a help example and rows in the Arc and Firefox capability tables.
|
|
12
|
+
|
|
3
13
|
## 1.22.96
|
|
4
14
|
|
|
5
15
|
- **`agents browser tabs --all` shows every tab open in the profile browser, yours included (PHNX-4043).** Until now `tabs` listed only the task's own tabs, so an agent sharing an Arc Space, a Comet store, or a Firefox profile with you could not see what else was open. `--all` lists every top-level tab: OWNER names the agents-cli task that owns it, or `you` for a tab no task owns; `*` still marks the task's current tab. Read-only on every backend (Chromium `Target.getTargets`, the Arc Space's tabs, Firefox `browsingContext.getTree`). Source: `cli/src/lib/browser/service.ts` `profileTabs`, `cli/src/commands/browser.ts`.
|
|
6
16
|
|
|
17
|
+
## 1.22.95
|
|
18
|
+
|
|
7
19
|
- **Firefox automation over WebDriver BiDi (PHNX-4043).** `agents browser` now drives
|
|
8
20
|
Firefox, which dropped the Chrome DevTools Protocol in 129. Every Firefox profile in
|
|
9
21
|
`profiles.ini` is discovered read-only as a `firefox-<name>` browser profile
|
package/dist/commands/browser.js
CHANGED
|
@@ -329,6 +329,9 @@ export function registerBrowserCommand(program) {
|
|
|
329
329
|
agents browser navigate https://example.com
|
|
330
330
|
agents browser screenshot
|
|
331
331
|
|
|
332
|
+
# Every tab open in the profile browser, yours next to the task's (OWNER column)
|
|
333
|
+
agents browser tabs --all
|
|
334
|
+
|
|
332
335
|
# Keep one process and browser-service socket warm for repeated actions
|
|
333
336
|
agents browser stream --task "$AGENTS_BROWSER_TASK"
|
|
334
337
|
|
|
@@ -358,9 +361,10 @@ export function registerBrowserCommand(program) {
|
|
|
358
361
|
Most agent workflows should use the 'browser' skill instead of raw subcommands.
|
|
359
362
|
The skill wraps profile selection, snapshotting, and tunneling.
|
|
360
363
|
|
|
361
|
-
Browser support: Chromium-family
|
|
362
|
-
|
|
363
|
-
|
|
364
|
+
Browser support: Chromium-family over the Chrome DevTools Protocol (Chrome,
|
|
365
|
+
Comet, Chromium, Brave, Edge), Arc natively (one profile per Space), and
|
|
366
|
+
Firefox over WebDriver BiDi (one profile per profiles.ini entry; Firefox 129+
|
|
367
|
+
dropped CDP). Safari is not supported. On Windows, Edge is the default
|
|
364
368
|
because it's preinstalled. On macOS and Linux, Chrome is preferred when
|
|
365
369
|
installed; otherwise the first Chromium-family binary on disk wins.
|
|
366
370
|
`,
|
|
@@ -15,7 +15,8 @@ import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
|
|
|
15
15
|
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
16
16
|
import { defaultBrowserChoice } from './setup-preferences.js';
|
|
17
17
|
const INSTALL_HINT = 'Install one of: Google Chrome, Brave, Microsoft Edge, Chromium, Comet, or Arc, then re-run `agents setup browser`.\n' +
|
|
18
|
-
'(
|
|
18
|
+
'(This wizard picks a Chromium-family browser. An installed Firefox is not auto-picked here; its profiles are ' +
|
|
19
|
+
'discovered from profiles.ini and selected with `agents browser use firefox-<name>`. Safari is not supported.)';
|
|
19
20
|
/**
|
|
20
21
|
* Interactive browser setup. Returns true if a usable default profile exists
|
|
21
22
|
* afterwards, false if none exists / the user backed out. Non-interactively it
|
|
@@ -187,9 +187,10 @@ export function findBrowserPath(browserType, customBinary) {
|
|
|
187
187
|
throw new Error(`Browser "${browserType}" not found. Install it first.`);
|
|
188
188
|
}
|
|
189
189
|
// Per-platform Chromium-family priority list for "no --profile" auto-pick.
|
|
190
|
-
// Order is: most-likely-installed-and-stable first.
|
|
191
|
-
//
|
|
192
|
-
//
|
|
190
|
+
// Order is: most-likely-installed-and-stable first. Firefox is intentionally
|
|
191
|
+
// absent: it has its own WebDriver BiDi driver (drivers/firefox.ts) and its
|
|
192
|
+
// profiles come from profiles.ini discovery, never from this binary pick.
|
|
193
|
+
// Safari has no driver at all.
|
|
193
194
|
const DEFAULT_BROWSER_PRIORITY = {
|
|
194
195
|
// macOS: Chrome leads (>70% of dev machines), then the rest of the family.
|
|
195
196
|
// Arc is last: it's in maintenance mode and needs a blank tab to drive, so it
|
|
@@ -1592,7 +1592,7 @@ export class BrowserService {
|
|
|
1592
1592
|
throw new Error(`Task "${taskId}" is already recording. Call record stop first.`);
|
|
1593
1593
|
}
|
|
1594
1594
|
const { conn, task, key: runtimeKey } = await this.findTask(taskId);
|
|
1595
|
-
requireCdp(conn, '
|
|
1595
|
+
requireCdp(conn, 'recording');
|
|
1596
1596
|
const shortId = tabHint ? await this.resolveTabHint(conn, task, tabHint) : this.resolveCurrentTab(task);
|
|
1597
1597
|
const cdpTargetId = this.getCdpTargetId(task, shortId);
|
|
1598
1598
|
const target = await this.getTarget(conn, cdpTargetId);
|
|
@@ -1796,7 +1796,7 @@ export class BrowserService {
|
|
|
1796
1796
|
async recordStop(taskId, reason = 'manual') {
|
|
1797
1797
|
const activeTask = await this.findTask(taskId).catch(() => undefined);
|
|
1798
1798
|
if (activeTask)
|
|
1799
|
-
requireCdp(activeTask.conn, '
|
|
1799
|
+
requireCdp(activeTask.conn, 'recording');
|
|
1800
1800
|
const rec = this.recordings.get(taskId);
|
|
1801
1801
|
if (!rec) {
|
|
1802
1802
|
throw new Error(`Task "${taskId}" is not currently recording`);
|
|
@@ -1883,9 +1883,12 @@ export class BrowserService {
|
|
|
1883
1883
|
// not route an already-live task through findTask(), which stamps it as
|
|
1884
1884
|
// active and defeats idle detection. A cold daemon may still rehydrate for
|
|
1885
1885
|
// an explicit user query.
|
|
1886
|
+
// A status query, not an action: a backend that cannot record (Arc native,
|
|
1887
|
+
// Firefox BiDi) is truthfully "not recording". Throwing here took the
|
|
1888
|
+
// idle reaper down with it — one Firefox task parked reaping for every task.
|
|
1886
1889
|
const live = this.findTaskByHandle(taskId) ?? await this.findTask(taskId).catch(() => undefined);
|
|
1887
|
-
if (live)
|
|
1888
|
-
|
|
1890
|
+
if (live && (live.conn.backend === 'arc-native' || live.conn.backend === 'bidi'))
|
|
1891
|
+
return { recording: false };
|
|
1889
1892
|
const rec = this.recordings.get(taskId);
|
|
1890
1893
|
if (!rec)
|
|
1891
1894
|
return { recording: false };
|
package/dist/lib/codex-home.d.ts
CHANGED
|
@@ -8,24 +8,56 @@ export declare const CODEX_CONTROL_SOCKET_SUFFIX = "/app-server-control/app-serv
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function codexHomeOverflowsSunLen(home: string): boolean;
|
|
10
10
|
/**
|
|
11
|
-
* The short
|
|
12
|
-
* `~/.agents/.codex-homes/<
|
|
13
|
-
* SUN_LEN while staying stable across reboots (unlike $TMPDIR) and
|
|
14
|
-
*
|
|
11
|
+
* The short codex home used when an origin home overflows.
|
|
12
|
+
* `~/.agents/.codex-homes/<key>/.codex` keeps the socket path well under
|
|
13
|
+
* SUN_LEN while staying stable across reboots (unlike $TMPDIR) and isolated
|
|
14
|
+
* per origin.
|
|
15
15
|
*/
|
|
16
|
-
export declare function shortCodexHome(agentsUserDir: string,
|
|
16
|
+
export declare function shortCodexHome(agentsUserDir: string, key: string): string;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* The short-home key for a codex config home: the version for a version home,
|
|
19
|
+
* `a-<accountId prefix>` for an account slot under `<historyDir>/accounts/codex/`.
|
|
20
|
+
* Twelve hex characters keep the socket path under SUN_LEN for any home dir
|
|
21
|
+
* (`~/.agents/.codex-homes/a-XXXXXXXXXXXX/.codex` + suffix = 99 bytes on a
|
|
22
|
+
* `/Users/<user>` prefix); the origin-link check in {@link resolveCodexHome}
|
|
23
|
+
* is what rules out two accounts sharing a prefix.
|
|
24
|
+
*/
|
|
25
|
+
export declare function codexShortKey(home: string, version: string, historyDir: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a macOS SUN_LEN-safe CODEX_HOME for the given origin home, migrating
|
|
28
|
+
* the home to a short real path (once, idempotently) when needed. `key` is the
|
|
29
|
+
* short-home key from {@link codexShortKey} — it uniquely identifies the origin
|
|
30
|
+
* (the version for a version home, `a-<accountId>` for a slot), so
|
|
31
|
+
* `.codex-homes/<key>` can only ever be THIS origin's own short home. Two
|
|
32
|
+
* different origins never map to one key, which is what makes every branch
|
|
33
|
+
* below safe without guessing whose login a short home holds.
|
|
20
34
|
*
|
|
21
|
-
* On non-darwin platforms, or when the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
35
|
+
* On non-darwin platforms, or when the origin already fits, the origin is
|
|
36
|
+
* returned unchanged. Otherwise the short home is authoritative for `key`, and
|
|
37
|
+
* the origin is made a symlink onto it:
|
|
38
|
+
* - already linked onto it → return it (healthy, the common path).
|
|
39
|
+
* - linked onto a DIFFERENT target (a pre-fix layout where a slot's `.codex`
|
|
40
|
+
* was captured into a foreign version short home) → REPOINT to this key's own
|
|
41
|
+
* short home and warn; the foreign login is never run. The account may need a
|
|
42
|
+
* re-login, which is correct — its login was never isolated.
|
|
43
|
+
* - a real directory with the short home ALREADY present → a version/account
|
|
44
|
+
* reinstall recreated a fresh `.codex`; adopt the short home (which holds the
|
|
45
|
+
* real login), backing the fresh dir aside so freshly-synced resources are
|
|
46
|
+
* not lost. This is the case the earlier refuse-and-throw broke
|
|
47
|
+
* (`agents remove codex@x && agents add codex@x` then `agents run`).
|
|
48
|
+
* - a real directory with no short home yet → first migration: rename it into
|
|
49
|
+
* the short home and leave a symlink.
|
|
50
|
+
* - absent → create/adopt the short home and link the origin to it.
|
|
51
|
+
* If any filesystem step fails the origin is returned (no worse than the pre-fix
|
|
52
|
+
* behavior).
|
|
24
53
|
*/
|
|
25
|
-
export declare function resolveCodexHome(
|
|
54
|
+
export declare function resolveCodexHome(originHome: string, agentsUserDir: string, key: string, platform?: NodeJS.Platform): string;
|
|
26
55
|
/**
|
|
27
56
|
* Emit the bash block that a generated codex shim uses to export a
|
|
28
|
-
* SUN_LEN-safe CODEX_HOME. Mirrors {@link resolveCodexHome}
|
|
57
|
+
* SUN_LEN-safe CODEX_HOME. Mirrors {@link resolveCodexHome} for the one origin
|
|
58
|
+
* a shim ever sees, the version home: an account-slot launch reaches the shim
|
|
59
|
+
* with CODEX_HOME already pinned by `buildExecEnv`, and the block below keeps a
|
|
60
|
+
* caller-provided CODEX_HOME, so the slot key never has to be derived in bash.
|
|
29
61
|
*
|
|
30
62
|
* @param homeExpr shell expression for the versioned codex home
|
|
31
63
|
* (e.g. `$VERSION_DIR/home/.codex`)
|
package/dist/lib/codex-home.js
CHANGED
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
* the TS resolver for `agents run`/`agents exec`; `shims.ts` emits the bash
|
|
26
26
|
* equivalent (`codexHomeShimBash`) into the generated codex shims. Keep the two
|
|
27
27
|
* in lockstep.
|
|
28
|
+
*
|
|
29
|
+
* The short home is keyed by the ORIGIN it relocates, never by the version
|
|
30
|
+
* alone. An account slot (`~/.agents/.history/accounts/codex/<id>/.codex`) is
|
|
31
|
+
* long enough to overflow too, and keying it by version handed every
|
|
32
|
+
* `agents run codex#<account>` on macOS the default version's short home —
|
|
33
|
+
* whichever login that happened to hold. `codexShortKey` derives the key; a
|
|
34
|
+
* short home that is not the resolved link target of its origin is refused
|
|
35
|
+
* rather than reused.
|
|
28
36
|
*/
|
|
29
37
|
import * as fs from 'fs';
|
|
30
38
|
import * as path from 'path';
|
|
@@ -40,59 +48,137 @@ export function codexHomeOverflowsSunLen(home) {
|
|
|
40
48
|
return home.length + CODEX_CONTROL_SOCKET_SUFFIX.length > SUN_LEN;
|
|
41
49
|
}
|
|
42
50
|
/**
|
|
43
|
-
* The short
|
|
44
|
-
* `~/.agents/.codex-homes/<
|
|
45
|
-
* SUN_LEN while staying stable across reboots (unlike $TMPDIR) and
|
|
46
|
-
*
|
|
51
|
+
* The short codex home used when an origin home overflows.
|
|
52
|
+
* `~/.agents/.codex-homes/<key>/.codex` keeps the socket path well under
|
|
53
|
+
* SUN_LEN while staying stable across reboots (unlike $TMPDIR) and isolated
|
|
54
|
+
* per origin.
|
|
47
55
|
*/
|
|
48
|
-
export function shortCodexHome(agentsUserDir,
|
|
49
|
-
return path.join(agentsUserDir, '.codex-homes',
|
|
56
|
+
export function shortCodexHome(agentsUserDir, key) {
|
|
57
|
+
return path.join(agentsUserDir, '.codex-homes', key, '.codex');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The short-home key for a codex config home: the version for a version home,
|
|
61
|
+
* `a-<accountId prefix>` for an account slot under `<historyDir>/accounts/codex/`.
|
|
62
|
+
* Twelve hex characters keep the socket path under SUN_LEN for any home dir
|
|
63
|
+
* (`~/.agents/.codex-homes/a-XXXXXXXXXXXX/.codex` + suffix = 99 bytes on a
|
|
64
|
+
* `/Users/<user>` prefix); the origin-link check in {@link resolveCodexHome}
|
|
65
|
+
* is what rules out two accounts sharing a prefix.
|
|
66
|
+
*/
|
|
67
|
+
export function codexShortKey(home, version, historyDir) {
|
|
68
|
+
const slotsRoot = path.resolve(historyDir, 'accounts', 'codex');
|
|
69
|
+
const resolved = path.resolve(home);
|
|
70
|
+
if (!resolved.startsWith(slotsRoot + path.sep))
|
|
71
|
+
return version;
|
|
72
|
+
const accountId = resolved.slice(slotsRoot.length + 1).split(path.sep)[0] ?? '';
|
|
73
|
+
if (!accountId)
|
|
74
|
+
return version;
|
|
75
|
+
return `a-${accountId.slice(0, 12)}`;
|
|
76
|
+
}
|
|
77
|
+
function realpathOrNull(p) {
|
|
78
|
+
try {
|
|
79
|
+
return fs.realpathSync(p);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isSymlinkOnto(link, target) {
|
|
86
|
+
try {
|
|
87
|
+
if (!fs.lstatSync(link).isSymbolicLink())
|
|
88
|
+
return false;
|
|
89
|
+
const t = realpathOrNull(target);
|
|
90
|
+
return t !== null && realpathOrNull(link) === t;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
50
95
|
}
|
|
51
96
|
/**
|
|
52
|
-
* Resolve a macOS SUN_LEN-safe CODEX_HOME for the given
|
|
53
|
-
*
|
|
97
|
+
* Resolve a macOS SUN_LEN-safe CODEX_HOME for the given origin home, migrating
|
|
98
|
+
* the home to a short real path (once, idempotently) when needed. `key` is the
|
|
99
|
+
* short-home key from {@link codexShortKey} — it uniquely identifies the origin
|
|
100
|
+
* (the version for a version home, `a-<accountId>` for a slot), so
|
|
101
|
+
* `.codex-homes/<key>` can only ever be THIS origin's own short home. Two
|
|
102
|
+
* different origins never map to one key, which is what makes every branch
|
|
103
|
+
* below safe without guessing whose login a short home holds.
|
|
54
104
|
*
|
|
55
|
-
* On non-darwin platforms, or when the
|
|
56
|
-
*
|
|
57
|
-
*
|
|
105
|
+
* On non-darwin platforms, or when the origin already fits, the origin is
|
|
106
|
+
* returned unchanged. Otherwise the short home is authoritative for `key`, and
|
|
107
|
+
* the origin is made a symlink onto it:
|
|
108
|
+
* - already linked onto it → return it (healthy, the common path).
|
|
109
|
+
* - linked onto a DIFFERENT target (a pre-fix layout where a slot's `.codex`
|
|
110
|
+
* was captured into a foreign version short home) → REPOINT to this key's own
|
|
111
|
+
* short home and warn; the foreign login is never run. The account may need a
|
|
112
|
+
* re-login, which is correct — its login was never isolated.
|
|
113
|
+
* - a real directory with the short home ALREADY present → a version/account
|
|
114
|
+
* reinstall recreated a fresh `.codex`; adopt the short home (which holds the
|
|
115
|
+
* real login), backing the fresh dir aside so freshly-synced resources are
|
|
116
|
+
* not lost. This is the case the earlier refuse-and-throw broke
|
|
117
|
+
* (`agents remove codex@x && agents add codex@x` then `agents run`).
|
|
118
|
+
* - a real directory with no short home yet → first migration: rename it into
|
|
119
|
+
* the short home and leave a symlink.
|
|
120
|
+
* - absent → create/adopt the short home and link the origin to it.
|
|
121
|
+
* If any filesystem step fails the origin is returned (no worse than the pre-fix
|
|
122
|
+
* behavior).
|
|
58
123
|
*/
|
|
59
|
-
export function resolveCodexHome(
|
|
124
|
+
export function resolveCodexHome(originHome, agentsUserDir, key, platform = process.platform) {
|
|
60
125
|
if (platform !== 'darwin')
|
|
61
|
-
return
|
|
62
|
-
if (!codexHomeOverflowsSunLen(
|
|
63
|
-
return
|
|
64
|
-
const short = shortCodexHome(agentsUserDir,
|
|
126
|
+
return originHome;
|
|
127
|
+
if (!codexHomeOverflowsSunLen(originHome))
|
|
128
|
+
return originHome;
|
|
129
|
+
const short = shortCodexHome(agentsUserDir, key);
|
|
130
|
+
if (isSymlinkOnto(originHome, short))
|
|
131
|
+
return short;
|
|
132
|
+
const origin = fs.lstatSync(originHome, { throwIfNoEntry: false });
|
|
65
133
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
fs.renameSync(versionedHome, short);
|
|
74
|
-
fs.symlinkSync(short, versionedHome);
|
|
75
|
-
}
|
|
76
|
-
else if (!st) {
|
|
77
|
-
// Fresh install: create the short home and link the versioned path to it.
|
|
134
|
+
fs.mkdirSync(path.dirname(short), { recursive: true });
|
|
135
|
+
if (origin?.isSymbolicLink()) {
|
|
136
|
+
// Mis-linked onto a foreign target (pre-fix bug): never run that identity.
|
|
137
|
+
// Repoint onto this key's own short home, creating it if absent.
|
|
138
|
+
process.stderr.write(`[codex] ${originHome} was linked to a foreign home; repointing to ${short} `
|
|
139
|
+
+ `(this account may need to log in again).\n`);
|
|
140
|
+
if (!fs.existsSync(short))
|
|
78
141
|
fs.mkdirSync(short, { recursive: true });
|
|
79
|
-
|
|
142
|
+
fs.rmSync(originHome); // removes the symlink only, never its target
|
|
143
|
+
fs.symlinkSync(short, originHome);
|
|
144
|
+
}
|
|
145
|
+
else if (origin?.isDirectory()) {
|
|
146
|
+
if (fs.existsSync(short)) {
|
|
147
|
+
// Reinstall: the fresh real `.codex` has re-derivable resources but no
|
|
148
|
+
// login; the short home holds the real login. Adopt the short home and
|
|
149
|
+
// set the fresh dir aside (non-destructive) rather than lose either.
|
|
150
|
+
const superseded = `${originHome}.superseded-${Date.now()}`;
|
|
151
|
+
fs.renameSync(originHome, superseded);
|
|
152
|
+
fs.symlinkSync(short, originHome);
|
|
80
153
|
}
|
|
81
|
-
|
|
82
|
-
|
|
154
|
+
else {
|
|
155
|
+
// First migration: relocate the deep home so config/auth/state stay
|
|
156
|
+
// intact, then leave a symlink behind so anything referencing the origin
|
|
157
|
+
// path still resolves (session discovery, the slot record, the shim).
|
|
158
|
+
fs.renameSync(originHome, short);
|
|
159
|
+
fs.symlinkSync(short, originHome);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Fresh origin: create (or adopt) the short home and link the origin to it.
|
|
164
|
+
fs.mkdirSync(short, { recursive: true });
|
|
165
|
+
fs.mkdirSync(path.dirname(originHome), { recursive: true });
|
|
166
|
+
fs.symlinkSync(short, originHome);
|
|
83
167
|
}
|
|
84
168
|
}
|
|
85
169
|
catch {
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
return versionedHome;
|
|
170
|
+
// A filesystem step lost a race or hit a permission error. Fall back to the
|
|
171
|
+
// origin rather than crash the invocation.
|
|
172
|
+
return originHome;
|
|
90
173
|
}
|
|
91
|
-
return
|
|
174
|
+
return isSymlinkOnto(originHome, short) ? short : originHome;
|
|
92
175
|
}
|
|
93
176
|
/**
|
|
94
177
|
* Emit the bash block that a generated codex shim uses to export a
|
|
95
|
-
* SUN_LEN-safe CODEX_HOME. Mirrors {@link resolveCodexHome}
|
|
178
|
+
* SUN_LEN-safe CODEX_HOME. Mirrors {@link resolveCodexHome} for the one origin
|
|
179
|
+
* a shim ever sees, the version home: an account-slot launch reaches the shim
|
|
180
|
+
* with CODEX_HOME already pinned by `buildExecEnv`, and the block below keeps a
|
|
181
|
+
* caller-provided CODEX_HOME, so the slot key never has to be derived in bash.
|
|
96
182
|
*
|
|
97
183
|
* @param homeExpr shell expression for the versioned codex home
|
|
98
184
|
* (e.g. `$VERSION_DIR/home/.codex`)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as os from 'os';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { getHistoryDir } from '../../state.js';
|
|
4
|
-
import {
|
|
4
|
+
import { codexHomeShimBash, codexShortKey, resolveCodexHome } from '../../codex-home.js';
|
|
5
5
|
import { codexEditWritableRoots, codexPolicyArgs } from '../../codex-policy.js';
|
|
6
6
|
import { stripForeignConfigDir } from '../adapter.js';
|
|
7
7
|
/**
|
|
@@ -20,9 +20,12 @@ export const codexAdapter = {
|
|
|
20
20
|
// On macOS the deep versioned home overflows the Unix-socket SUN_LEN
|
|
21
21
|
// limit for codex's app-server control socket; resolve to a short,
|
|
22
22
|
// SUN_LEN-safe home (migrating once if needed). See codex-home.ts.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// ctx.versionHome is the account slot on a `codex#<account>` launch, so
|
|
24
|
+
// the short home is keyed by that origin, never by the version alone.
|
|
25
|
+
const originHome = path.join(ctx.versionHome, '.codex');
|
|
26
|
+
const historyDir = getHistoryDir();
|
|
27
|
+
const agentsUserDir = path.dirname(historyDir);
|
|
28
|
+
result.CODEX_HOME = resolveCodexHome(originHome, agentsUserDir, codexShortKey(originHome, ctx.version, historyDir));
|
|
26
29
|
}
|
|
27
30
|
stripForeignConfigDir(result, ['CODEX_HOME']);
|
|
28
31
|
},
|
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.98",
|
|
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",
|