@phnx-labs/agents-cli 1.22.57 → 1.22.59
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 +294 -0
- package/README.md +29 -0
- package/dist/bootstrap.js +39 -1
- package/dist/commands/accounts.js +7 -3
- package/dist/commands/apply.js +10 -2
- package/dist/commands/fork.d.ts +23 -10
- package/dist/commands/fork.js +115 -58
- package/dist/commands/monitors.js +198 -23
- package/dist/commands/prune.js +5 -3
- package/dist/commands/routines.d.ts +8 -0
- package/dist/commands/routines.js +57 -3
- package/dist/commands/routines.test-fixture.js +5 -0
- package/dist/commands/send.d.ts +2 -1
- package/dist/commands/send.js +7 -5
- package/dist/commands/sessions-picker.d.ts +11 -0
- package/dist/commands/sessions-picker.js +16 -0
- package/dist/commands/sessions-stats.js +37 -5
- package/dist/commands/sessions.js +40 -5
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +43 -2
- package/dist/commands/ssh.js +12 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/sync.js +83 -7
- package/dist/commands/traces.js +7 -0
- package/dist/commands/versions.js +12 -4
- package/dist/commands/view.js +7 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -1
- package/dist/lib/account-registry.d.ts +5 -1
- package/dist/lib/account-registry.js +47 -14
- package/dist/lib/accounting/capacity.d.ts +18 -7
- package/dist/lib/accounting/capacity.js +19 -8
- package/dist/lib/accounting/usage-sync.d.ts +29 -1
- package/dist/lib/accounting/usage-sync.js +76 -2
- package/dist/lib/accounting/usage.js +7 -1
- package/dist/lib/auth-mint.d.ts +11 -1
- package/dist/lib/auth-mint.js +21 -6
- package/dist/lib/auto-pull-worker.js +7 -2
- package/dist/lib/browser/ipc.d.ts +8 -0
- package/dist/lib/browser/ipc.js +87 -0
- package/dist/lib/browser/service.d.ts +19 -0
- package/dist/lib/browser/service.js +96 -11
- package/dist/lib/browser/sessions-list.js +10 -1
- package/dist/lib/cloud/rush.d.ts +7 -0
- package/dist/lib/cloud/rush.js +29 -1
- package/dist/lib/daemon/daemon.d.ts +22 -0
- package/dist/lib/daemon/daemon.js +39 -0
- package/dist/lib/daemon/runner.d.ts +3 -0
- package/dist/lib/daemon/runner.js +86 -45
- package/dist/lib/daemon/session-index-service.js +9 -1
- package/dist/lib/daemon/usage-sync-service.d.ts +3 -3
- package/dist/lib/daemon/usage-sync-service.js +14 -8
- package/dist/lib/daemon-services.js +1 -1
- package/dist/lib/daemon-ticks.d.ts +15 -0
- package/dist/lib/daemon-ticks.js +26 -0
- package/dist/lib/device-config.d.ts +5 -1
- package/dist/lib/device-config.js +2 -2
- package/dist/lib/devices/connect.d.ts +17 -8
- package/dist/lib/devices/connect.js +31 -14
- package/dist/lib/devices/health.js +5 -1
- package/dist/lib/devices/pool.d.ts +25 -2
- package/dist/lib/devices/pool.js +32 -2
- package/dist/lib/devices/stats-cache.d.ts +0 -6
- package/dist/lib/devices/stats-cache.js +2 -9
- package/dist/lib/doctor-diff.d.ts +14 -0
- package/dist/lib/doctor-diff.js +120 -9
- package/dist/lib/fleet/manifest.d.ts +17 -0
- package/dist/lib/fleet/manifest.js +26 -0
- package/dist/lib/git.d.ts +38 -0
- package/dist/lib/git.js +58 -0
- package/dist/lib/hooks/install.d.ts +27 -11
- package/dist/lib/hooks/install.js +42 -17
- package/dist/lib/hosts/ready.d.ts +8 -0
- package/dist/lib/hosts/ready.js +13 -2
- package/dist/lib/hosts/reconnect.d.ts +52 -203
- package/dist/lib/hosts/reconnect.js +64 -284
- package/dist/lib/installations/migrate.d.ts +6 -120
- package/dist/lib/installations/migrate.js +27 -259
- package/dist/lib/installations/shims.d.ts +13 -95
- package/dist/lib/installations/shims.js +22 -139
- package/dist/lib/installations/store.js +1 -1
- package/dist/lib/installations/versions.d.ts +43 -133
- package/dist/lib/installations/versions.js +94 -206
- package/dist/lib/monitors/config.d.ts +71 -3
- package/dist/lib/monitors/config.js +100 -12
- package/dist/lib/monitors/pid-watch.d.ts +35 -0
- package/dist/lib/monitors/pid-watch.js +45 -0
- package/dist/lib/monitors/remote.d.ts +18 -0
- package/dist/lib/monitors/remote.js +11 -0
- package/dist/lib/permissions.js +7 -2
- package/dist/lib/plugins/plugins.d.ts +17 -3
- package/dist/lib/plugins/plugins.js +84 -9
- package/dist/lib/plugins/skills.d.ts +8 -1
- package/dist/lib/plugins/skills.js +18 -2
- package/dist/lib/pty-server.d.ts +14 -0
- package/dist/lib/pty-server.js +49 -5
- package/dist/lib/refresh.d.ts +9 -0
- package/dist/lib/refresh.js +3 -1
- package/dist/lib/routine-readiness.d.ts +15 -1
- package/dist/lib/routine-readiness.js +41 -0
- package/dist/lib/sandbox.d.ts +4 -1
- package/dist/lib/sandbox.js +30 -1
- package/dist/lib/secrets/agent.d.ts +80 -225
- package/dist/lib/secrets/agent.js +139 -401
- package/dist/lib/secrets/bundles.d.ts +73 -222
- package/dist/lib/secrets/bundles.js +168 -467
- package/dist/lib/secrets/drivers/rush.js +5 -0
- package/dist/lib/secrets/reaper.d.ts +28 -70
- package/dist/lib/secrets/reaper.js +30 -85
- package/dist/lib/secrets/remote.d.ts +42 -129
- package/dist/lib/secrets/remote.js +55 -173
- package/dist/lib/self-heal/checks/install-staging.d.ts +4 -0
- package/dist/lib/self-heal/checks/install-staging.js +96 -0
- package/dist/lib/self-heal/registry.js +2 -0
- package/dist/lib/self-heal/types.d.ts +1 -1
- package/dist/lib/self-update.d.ts +65 -0
- package/dist/lib/self-update.js +138 -0
- package/dist/lib/session/active.d.ts +13 -1
- package/dist/lib/session/active.js +2 -0
- package/dist/lib/session/cloud.js +5 -0
- package/dist/lib/session/db.d.ts +51 -6
- package/dist/lib/session/db.js +266 -20
- package/dist/lib/session/fork.d.ts +45 -26
- package/dist/lib/session/fork.js +32 -95
- package/dist/lib/session/tool-calls.d.ts +43 -1
- package/dist/lib/session/tool-calls.js +74 -44
- package/dist/lib/session/tool-store.d.ts +33 -2
- package/dist/lib/session/tool-store.js +56 -3
- package/dist/lib/smart-launch.d.ts +6 -0
- package/dist/lib/smart-launch.js +5 -2
- package/dist/lib/staleness/writers/plugins.js +5 -2
- package/dist/lib/staleness/writers/sources.d.ts +5 -0
- package/dist/lib/staleness/writers/sources.js +2 -1
- package/dist/lib/staleness/writers/subagents.js +13 -3
- package/dist/lib/state.d.ts +7 -4
- package/dist/lib/state.js +7 -4
- package/dist/lib/subagents.js +8 -2
- package/dist/lib/sync-status.d.ts +22 -0
- package/dist/lib/sync-status.js +27 -0
- package/dist/lib/sync-umbrella.d.ts +9 -0
- package/dist/lib/sync-umbrella.js +21 -2
- package/dist/lib/teams/scheduler.d.ts +10 -0
- package/dist/lib/teams/scheduler.js +8 -0
- package/dist/lib/traces/insights.d.ts +47 -14
- package/dist/lib/traces/insights.js +92 -21
- package/dist/lib/traces/phenotype.d.ts +23 -3
- package/dist/lib/traces/phenotype.js +72 -24
- package/dist/lib/traces/sync.d.ts +128 -6
- package/dist/lib/traces/sync.js +294 -35
- package/dist/lib/traces/worker-template.js +154 -1
- package/dist/lib/view-types.d.ts +12 -0
- package/package.json +2 -2
|
@@ -1,128 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One-shot idempotent migrations for the FOUNDATION refactor.
|
|
3
|
-
*
|
|
4
|
-
* Called from postinstall and as a command-time fallback from agents view/use/pull.
|
|
5
|
-
* Each migration is guarded by an existence check so re-running is safe.
|
|
6
|
-
*/
|
|
1
|
+
/** One-shot idempotent migrations. Each is guarded by an existence check so re-running is safe. */
|
|
7
2
|
export { foldLegacySystemRepo } from '../migrate-fold.js';
|
|
8
|
-
/**
|
|
9
|
-
* Migrate a legacy single-repo agents.yaml into ~/.agents/agents.yaml.
|
|
10
|
-
*
|
|
11
|
-
* The post-fold system dir (~/.agents/.system) is a pull-only mirror of the
|
|
12
|
-
* npm-shipped defaults. Its agents.yaml is a TRACKED file that readMeta() reads
|
|
13
|
-
* in place as the defaults base (see SYSTEM_META_FILE in state.ts). Deleting or
|
|
14
|
-
* moving a tracked file out of the mirror dirties its working tree, which
|
|
15
|
-
* permanently wedges `agents setup`, `agents sync`, and background auto-pull
|
|
16
|
-
* ("Working tree has uncommitted changes.") because the mirror sync refuses a
|
|
17
|
-
* dirty tree. So when agents.yaml is tracked there, treat the mirror as strictly
|
|
18
|
-
* read-only and leave the file alone.
|
|
19
|
-
*
|
|
20
|
-
* Only an UNTRACKED agents.yaml is residue from the pre-split single-repo layout
|
|
21
|
-
* (or a legacy ~/.agents-system fold) and is safe to move/drop.
|
|
22
|
-
*
|
|
23
|
-
* Params default to the real on-disk locations; they are injectable so tests can
|
|
24
|
-
* drive a fixture tree without touching the user's ~/.agents.
|
|
25
|
-
*/
|
|
3
|
+
/** Migrate a legacy single-repo agents.yaml into ~/.agents/agents.yaml. Leaves the tracked system-mirror copy alone to avoid dirtying the npm-shipped defaults. */
|
|
26
4
|
export declare function migrateAgentsYaml(systemDir?: string, userDir?: string): void;
|
|
27
|
-
/**
|
|
28
|
-
* Fold the legacy GLOBAL browser captures root
|
|
29
|
-
* (`~/.agents/.cache/browser/sessions/<task>/`) into the new PER-PROFILE layout
|
|
30
|
-
* (`~/.agents/.cache/browser/<profile>/sessions/<task>/`), so each profile is one
|
|
31
|
-
* self-contained tree and the new `browser sessions` listing finds old captures.
|
|
32
|
-
*
|
|
33
|
-
* Attribution: a legacy `sessions/<task>` dir is owned by whichever profile's
|
|
34
|
-
* `tasks.json` still lists that task name. Tasks no profile claims (the profile
|
|
35
|
-
* was deleted, or tasks.json was cleared) move under a `_legacy` pseudo-profile so
|
|
36
|
-
* nothing is lost. Idempotent — once the global `sessions/` root is gone it no-ops.
|
|
37
|
-
*/
|
|
5
|
+
/** Fold the legacy global browser/sessions/<task>/ tree into the per-profile browser/<profile>/sessions/<task>/ layout. Unclaimed tasks move under `_legacy`. */
|
|
38
6
|
export declare function foldBrowserSessionsIntoProfiles(browserDir?: string): void;
|
|
39
|
-
/**
|
|
40
|
-
* Repair self-referential agent binary symlinks.
|
|
41
|
-
*
|
|
42
|
-
* Some installScript-based agents — notably Factory.ai's `droid`, whose installer
|
|
43
|
-
* drops a standalone native binary at ~/.local/bin/droid — were registered at
|
|
44
|
-
* install time by resolving the post-install binary with `which <cli>`. Because
|
|
45
|
-
* ~/.agents/.cache/shims sits ahead of ~/.local/bin on PATH, `which` could
|
|
46
|
-
* return OUR OWN dispatcher shim, and the install step symlinked
|
|
47
|
-
* ~/.agents/.history/versions/<agent>/<version>/node_modules/.bin/<cli>
|
|
48
|
-
* back at ~/.agents/.cache/shims/<cli>. Launching that agent then re-execs the
|
|
49
|
-
* dispatcher forever (an infinite exec loop that hangs the terminal).
|
|
50
|
-
*
|
|
51
|
-
* This walks every installed version's node_modules/.bin and, for any entry
|
|
52
|
-
* whose symlink resolves into the shims dir, re-points it at the real binary
|
|
53
|
-
* (found on PATH with the shims dir excluded) — or removes it when no real
|
|
54
|
-
* binary can be found, letting getBinaryPath's per-agent resolver take over.
|
|
55
|
-
* Idempotent: a correctly-pointed link is left untouched on re-run.
|
|
56
|
-
*
|
|
57
|
-
* Params default to the real on-disk locations; they are injectable so tests
|
|
58
|
-
* can drive a fixture tree without touching the user's ~/.agents.
|
|
59
|
-
*/
|
|
7
|
+
/** Repair node_modules/.bin/<cli> symlinks that resolve back into our own shims dir (infinite exec-loop fix). */
|
|
60
8
|
export declare function repairSelfReferentialBinShims(versionsRoot?: string, shimsDir?: string, historyDir?: string): void;
|
|
61
|
-
/**
|
|
62
|
-
* Move the auto-detected `default` browser profile OUT of the committed central
|
|
63
|
-
* agents.yaml and into this machine's per-device file.
|
|
64
|
-
*
|
|
65
|
-
* `browser` is a CENTRAL key because named profiles a user creates are real fleet
|
|
66
|
-
* config, but the ONE `default` entry inside it is machine-local: its `binary` is
|
|
67
|
-
* an OS-specific path and its endpoint is a locally-chosen free port.
|
|
68
|
-
* `createProfile`/`updateProfile` already route that entry to `deviceBrowser`
|
|
69
|
-
* (`isMachineLocalProfile`, browser/profiles.ts) — but nothing ever removed the
|
|
70
|
-
* copy older versions had already written into the shared file, and
|
|
71
|
-
* `serializeCentral` cannot: it deletes whole KEYS that are device-scoped, and
|
|
72
|
-
* `browser` is not one.
|
|
73
|
-
*
|
|
74
|
-
* So the entry sat in the committed file and every box rewrote it with its own
|
|
75
|
-
* browser. Measured 2026-08-13, all three boxes on 1.22.38 (which HAS the writer
|
|
76
|
-
* fix) with an empty `deviceBrowser` and a machine-specific `default` in central:
|
|
77
|
-
*
|
|
78
|
-
* zion browser: chrome binary: /Applications/Google Chrome.app/...
|
|
79
|
-
* yosemite-s1 browser: brave binary: /opt/brave.com/brave/brave
|
|
80
|
-
* mark-1 (same shape)
|
|
81
|
-
*
|
|
82
|
-
* `agents repos pull user` refuses when an incoming change touches a locally
|
|
83
|
-
* modified path, so agents.yaml being permanently dirty wedged the fleet config
|
|
84
|
-
* sync outright — those boxes sat 5, 8 and 79 commits behind. (RUSH-2161)
|
|
85
|
-
*
|
|
86
|
-
* Idempotent: no-op once central carries no `default` entry. The device file is
|
|
87
|
-
* written FIRST so a crash between the two writes can never lose the profile,
|
|
88
|
-
* and an entry already in the device file wins (this machine's live value is
|
|
89
|
-
* newer than the stale central copy by construction).
|
|
90
|
-
*
|
|
91
|
-
* Central is edited through a `yaml.Document` rather than re-stringified, so the
|
|
92
|
-
* hand-written comments in the committed agents.yaml survive — a plain
|
|
93
|
-
* `yaml.stringify` would drop every one of them and rewrite the whole file,
|
|
94
|
-
* which is the same churn this migration exists to stop (see `serializeCentral`).
|
|
95
|
-
*/
|
|
9
|
+
/** Move the auto-detected `default` browser profile from committed agents.yaml into the per-device file. The device file is written first so a crash cannot lose the profile; central is edited via yaml.Document to preserve comments. */
|
|
96
10
|
export declare function migrateMachineLocalBrowserProfileOutOfCentral(userDir?: string, machine?: string): void;
|
|
97
|
-
/**
|
|
98
|
-
* Rename the legacy `extras-extras/` plugin-marketplace dir to `agents-extras/`
|
|
99
|
-
* inside every installed agent version-home, and rewrite cross-references in
|
|
100
|
-
* `known_marketplaces.json` and the agent's `settings.json`.
|
|
101
|
-
*
|
|
102
|
-
* A previous dev build of `agents-cli` named the extras-aliased repo's
|
|
103
|
-
* synthesized marketplace dir `extras-extras` (double "extras" because the alias
|
|
104
|
-
* itself was `extras`). The new naming convention is `agents-<alias>`, so the
|
|
105
|
-
* directory should be `agents-extras`. Without this migration the orphan dir
|
|
106
|
-
* stays on disk and Claude Code loads two parallel marketplaces (the legacy
|
|
107
|
-
* `extras-extras` entry from `known_marketplaces.json` plus the freshly
|
|
108
|
-
* synthesized `agents-extras` from the new code path).
|
|
109
|
-
*
|
|
110
|
-
* Strategy per `<historyDir>/versions/<agent>/<ver>/home/.<agent>/plugins/`:
|
|
111
|
-
* 1. `marketplaces/extras-extras/` → `marketplaces/agents-extras/`
|
|
112
|
-
* (drops `extras-extras/` outright when `agents-extras/` already exists —
|
|
113
|
-
* previous incomplete migration ran)
|
|
114
|
-
* 2. Inside the renamed dir's `.claude-plugin/marketplace.json`, set
|
|
115
|
-
* `"name": "agents-extras"`.
|
|
116
|
-
* 3. In `<configDir>/plugins/known_marketplaces.json`, rename the
|
|
117
|
-
* `extras-extras` key to `agents-extras` and rewrite `source.path` /
|
|
118
|
-
* `installLocation`.
|
|
119
|
-
* 4. In `<configDir>/settings.json`'s `enabledPlugins`, rename every
|
|
120
|
-
* `<plugin>@extras-extras` key to `<plugin>@agents-extras` (preserving
|
|
121
|
-
* its boolean value, skipping if the new key already exists).
|
|
122
|
-
*
|
|
123
|
-
* Idempotent: re-running converges without further writes once everything is on
|
|
124
|
-
* the new name.
|
|
125
|
-
*/
|
|
11
|
+
/** Rename the legacy `extras-extras/` plugin marketplace dir to `agents-extras/` in every installed version home, and rewrite cross-references in `known_marketplaces.json` and `settings.json`. */
|
|
126
12
|
export declare function migrateExtrasExtrasToAgentsExtras(historyDir?: string): void;
|
|
127
13
|
/**
|
|
128
14
|
* Rewrite every routine YAML that carries the legacy singular `device: <value>`
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One-shot idempotent migrations for the FOUNDATION refactor.
|
|
3
|
-
*
|
|
4
|
-
* Called from postinstall and as a command-time fallback from agents view/use/pull.
|
|
5
|
-
* Each migration is guarded by an existence check so re-running is safe.
|
|
6
|
-
*/
|
|
1
|
+
/** One-shot idempotent migrations. Each is guarded by an existence check so re-running is safe. */
|
|
7
2
|
import * as fs from 'fs';
|
|
8
3
|
import * as path from 'path';
|
|
9
4
|
import * as os from 'os';
|
|
@@ -32,7 +27,6 @@ const USER_DIR = path.join(HOME, '.agents');
|
|
|
32
27
|
const SYSTEM_DIR = path.join(USER_DIR, '.system');
|
|
33
28
|
const HISTORY_DIR = path.join(USER_DIR, '.history');
|
|
34
29
|
const CACHE_DIR = path.join(USER_DIR, '.cache');
|
|
35
|
-
/** True when `relPath` is a file tracked by a git repo rooted at `repoDir`. */
|
|
36
30
|
function isTrackedInGitRepo(repoDir, relPath) {
|
|
37
31
|
try {
|
|
38
32
|
execSync(`git ls-files --error-unmatch -- ${relPath}`, { cwd: repoDir, stdio: 'ignore' });
|
|
@@ -43,31 +37,13 @@ function isTrackedInGitRepo(repoDir, relPath) {
|
|
|
43
37
|
return false;
|
|
44
38
|
}
|
|
45
39
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Migrate a legacy single-repo agents.yaml into ~/.agents/agents.yaml.
|
|
48
|
-
*
|
|
49
|
-
* The post-fold system dir (~/.agents/.system) is a pull-only mirror of the
|
|
50
|
-
* npm-shipped defaults. Its agents.yaml is a TRACKED file that readMeta() reads
|
|
51
|
-
* in place as the defaults base (see SYSTEM_META_FILE in state.ts). Deleting or
|
|
52
|
-
* moving a tracked file out of the mirror dirties its working tree, which
|
|
53
|
-
* permanently wedges `agents setup`, `agents sync`, and background auto-pull
|
|
54
|
-
* ("Working tree has uncommitted changes.") because the mirror sync refuses a
|
|
55
|
-
* dirty tree. So when agents.yaml is tracked there, treat the mirror as strictly
|
|
56
|
-
* read-only and leave the file alone.
|
|
57
|
-
*
|
|
58
|
-
* Only an UNTRACKED agents.yaml is residue from the pre-split single-repo layout
|
|
59
|
-
* (or a legacy ~/.agents-system fold) and is safe to move/drop.
|
|
60
|
-
*
|
|
61
|
-
* Params default to the real on-disk locations; they are injectable so tests can
|
|
62
|
-
* drive a fixture tree without touching the user's ~/.agents.
|
|
63
|
-
*/
|
|
40
|
+
/** Migrate a legacy single-repo agents.yaml into ~/.agents/agents.yaml. Leaves the tracked system-mirror copy alone to avoid dirtying the npm-shipped defaults. */
|
|
64
41
|
export function migrateAgentsYaml(systemDir = SYSTEM_DIR, userDir = USER_DIR) {
|
|
65
42
|
const src = path.join(systemDir, 'agents.yaml');
|
|
66
43
|
const dest = path.join(userDir, 'agents.yaml');
|
|
67
44
|
if (!fs.existsSync(src))
|
|
68
45
|
return;
|
|
69
|
-
//
|
|
70
|
-
// already surfaces it in place, so no user-dir copy is needed either.
|
|
46
|
+
// Never move the tracked system-mirror copy; doing so would dirty the npm-shipped defaults.
|
|
71
47
|
if (isTrackedInGitRepo(systemDir, 'agents.yaml'))
|
|
72
48
|
return;
|
|
73
49
|
if (fs.existsSync(dest)) {
|
|
@@ -85,9 +61,6 @@ export function migrateAgentsYaml(systemDir = SYSTEM_DIR, userDir = USER_DIR) {
|
|
|
85
61
|
}
|
|
86
62
|
catch { /* best-effort */ }
|
|
87
63
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Delete ~/.agents-system/prompts.json (dead file — zero refs in src/).
|
|
90
|
-
*/
|
|
91
64
|
function deleteSystemPromptsJson() {
|
|
92
65
|
const f = path.join(SYSTEM_DIR, 'prompts.json');
|
|
93
66
|
if (!fs.existsSync(f))
|
|
@@ -97,14 +70,7 @@ function deleteSystemPromptsJson() {
|
|
|
97
70
|
}
|
|
98
71
|
catch { /* best-effort */ }
|
|
99
72
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Move ~/.agents-system/config.json -> ~/.agents/teams/config.json.
|
|
102
|
-
* The teams persistence layer already reads the legacy path as a fallback;
|
|
103
|
-
* moving it here keeps the canonical location consistent.
|
|
104
|
-
*/
|
|
105
|
-
// Delete the legacy ~/.agents-system/config.json. This was the teams agent
|
|
106
|
-
// registry, which no longer exists — `agents teams` discovers agents through
|
|
107
|
-
// `listInstalledVersions` and invokes them through `agents run`.
|
|
73
|
+
/** Delete the legacy ~/.agents-system/config.json (dead teams agent registry). */
|
|
108
74
|
function migrateSystemConfigJson() {
|
|
109
75
|
const src = path.join(SYSTEM_DIR, 'config.json');
|
|
110
76
|
if (!fs.existsSync(src))
|
|
@@ -114,12 +80,7 @@ function migrateSystemConfigJson() {
|
|
|
114
80
|
}
|
|
115
81
|
catch { /* best-effort */ }
|
|
116
82
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Move promptcuts.yaml from each repo root into hooks/ subdir.
|
|
119
|
-
* ~/.agents-system/promptcuts.yaml -> ~/.agents-system/hooks/promptcuts.yaml
|
|
120
|
-
* ~/.agents/promptcuts.yaml -> ~/.agents/hooks/promptcuts.yaml
|
|
121
|
-
* Idempotent: skips if dest already exists or src absent.
|
|
122
|
-
*/
|
|
83
|
+
/** Move promptcuts.yaml from each repo root into hooks/. */
|
|
123
84
|
function migratePromptcutsIntoHooks() {
|
|
124
85
|
for (const root of [SYSTEM_DIR, USER_DIR]) {
|
|
125
86
|
const src = path.join(root, 'promptcuts.yaml');
|
|
@@ -133,23 +94,7 @@ function migratePromptcutsIntoHooks() {
|
|
|
133
94
|
catch { /* best-effort */ }
|
|
134
95
|
}
|
|
135
96
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Move installed agent versions from the legacy system-root layout
|
|
138
|
-
* (~/.agents-system/versions/<agent>/<ver>/) into the user root
|
|
139
|
-
* (~/.agents/versions/<agent>/<ver>/).
|
|
140
|
-
*
|
|
141
|
-
* Earlier installs (and an inverted prior version of this migrator) put
|
|
142
|
-
* binaries and home dirs under ~/.agents-system/. The current architecture
|
|
143
|
-
* keeps all operational state (versions, sessions, shims, trash) under
|
|
144
|
-
* ~/.agents/, and getVersionsDir() in state.ts resolves there. Without this
|
|
145
|
-
* migration the legacy versions become invisible to listInstalledVersions
|
|
146
|
-
* and every command that depends on it (view, prune, run, sync) writes a
|
|
147
|
-
* second copy to ~/.agents/versions/ while the agent CLIs keep reading the
|
|
148
|
-
* stale ~/.agents-system/versions/ copy via the existing ~/.<agent> symlink.
|
|
149
|
-
*
|
|
150
|
-
* Idempotent and non-destructive: if a same-named dest already exists we
|
|
151
|
-
* leave the legacy copy in place so the user can reconcile manually.
|
|
152
|
-
*/
|
|
97
|
+
/** Move installed versions from the legacy ~/.agents-system/versions/ tree into ~/.agents/versions/. Leaves collisions in place for manual reconciliation. */
|
|
153
98
|
function migrateSystemVersionsToUser() {
|
|
154
99
|
const sysVersions = path.join(SYSTEM_DIR, 'versions');
|
|
155
100
|
const userVersions = path.join(USER_DIR, 'versions');
|
|
@@ -213,10 +158,7 @@ function migrateSystemVersionsToUser() {
|
|
|
213
158
|
console.error(`Skipped ${skippedCount} version dir${skippedCount === 1 ? '' : 's'} already present in ~/.agents/versions/ (kept legacy copy at ~/.agents-system/versions/)`);
|
|
214
159
|
}
|
|
215
160
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Move ~/. agents/runs/ -> ~/.agents/routines/runs/.
|
|
218
|
-
* Runs now live inside routines directory for cleaner organization.
|
|
219
|
-
*/
|
|
161
|
+
/** Move ~/.agents/runs/ into ~/.agents/routines/runs/. */
|
|
220
162
|
function migrateRunsIntoRoutines() {
|
|
221
163
|
const src = path.join(USER_DIR, 'runs');
|
|
222
164
|
const dest = path.join(USER_DIR, 'routines', 'runs');
|
|
@@ -228,10 +170,7 @@ function migrateRunsIntoRoutines() {
|
|
|
228
170
|
}
|
|
229
171
|
catch { /* best-effort */ }
|
|
230
172
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Move ~/.agents/trash/ -> ~/.agents/.trash/.
|
|
233
|
-
* Hide the trash directory.
|
|
234
|
-
*/
|
|
173
|
+
/** Move ~/.agents/trash/ to ~/.agents/.trash/. */
|
|
235
174
|
function migrateTrashToHidden() {
|
|
236
175
|
const src = path.join(USER_DIR, 'trash');
|
|
237
176
|
const dest = path.join(USER_DIR, '.trash');
|
|
@@ -242,10 +181,7 @@ function migrateTrashToHidden() {
|
|
|
242
181
|
}
|
|
243
182
|
catch { /* best-effort */ }
|
|
244
183
|
}
|
|
245
|
-
/**
|
|
246
|
-
* Move ~/.agents/backups/ -> ~/.agents/.backups/.
|
|
247
|
-
* Hide the backups directory.
|
|
248
|
-
*/
|
|
184
|
+
/** Move ~/.agents/backups/ to ~/.agents/.backups/. */
|
|
249
185
|
function migrateBackupsToHidden() {
|
|
250
186
|
const src = path.join(USER_DIR, 'backups');
|
|
251
187
|
const dest = path.join(USER_DIR, '.backups');
|
|
@@ -256,17 +192,7 @@ function migrateBackupsToHidden() {
|
|
|
256
192
|
}
|
|
257
193
|
catch { /* best-effort */ }
|
|
258
194
|
}
|
|
259
|
-
/**
|
|
260
|
-
* Fold ~/.agents/hooks.yaml into ~/.agents/agents.yaml under a `hooks:` key,
|
|
261
|
-
* then delete the standalone hooks.yaml. Single user file to sync.
|
|
262
|
-
*
|
|
263
|
-
* On collision (a hook name already exists in agents.yaml hooks:), the
|
|
264
|
-
* existing agents.yaml entry wins and the standalone copy is dropped — this
|
|
265
|
-
* matches the behavior a user would get if they had already migrated
|
|
266
|
-
* manually and edited agents.yaml.
|
|
267
|
-
*
|
|
268
|
-
* Idempotent: skips if hooks.yaml is absent or unparseable.
|
|
269
|
-
*/
|
|
195
|
+
/** Fold ~/.agents/hooks.yaml into ~/.agents/agents.yaml under `hooks:`, dropping the standalone file. agents.yaml wins on collision. */
|
|
270
196
|
function foldUserHooksYamlIntoAgentsYaml() {
|
|
271
197
|
const hooksFile = path.join(USER_DIR, 'hooks.yaml');
|
|
272
198
|
if (!fs.existsSync(hooksFile))
|
|
@@ -309,17 +235,7 @@ function foldUserHooksYamlIntoAgentsYaml() {
|
|
|
309
235
|
}
|
|
310
236
|
catch { /* best-effort */ }
|
|
311
237
|
}
|
|
312
|
-
/**
|
|
313
|
-
* Fold the legacy GLOBAL browser captures root
|
|
314
|
-
* (`~/.agents/.cache/browser/sessions/<task>/`) into the new PER-PROFILE layout
|
|
315
|
-
* (`~/.agents/.cache/browser/<profile>/sessions/<task>/`), so each profile is one
|
|
316
|
-
* self-contained tree and the new `browser sessions` listing finds old captures.
|
|
317
|
-
*
|
|
318
|
-
* Attribution: a legacy `sessions/<task>` dir is owned by whichever profile's
|
|
319
|
-
* `tasks.json` still lists that task name. Tasks no profile claims (the profile
|
|
320
|
-
* was deleted, or tasks.json was cleared) move under a `_legacy` pseudo-profile so
|
|
321
|
-
* nothing is lost. Idempotent — once the global `sessions/` root is gone it no-ops.
|
|
322
|
-
*/
|
|
238
|
+
/** Fold the legacy global browser/sessions/<task>/ tree into the per-profile browser/<profile>/sessions/<task>/ layout. Unclaimed tasks move under `_legacy`. */
|
|
323
239
|
export function foldBrowserSessionsIntoProfiles(browserDir = path.join(CACHE_DIR, 'browser')) {
|
|
324
240
|
const legacySessionsDir = path.join(browserDir, 'sessions');
|
|
325
241
|
let taskDirs;
|
|
@@ -329,7 +245,6 @@ export function foldBrowserSessionsIntoProfiles(browserDir = path.join(CACHE_DIR
|
|
|
329
245
|
catch {
|
|
330
246
|
return; // no legacy global sessions/ root — already folded or never existed
|
|
331
247
|
}
|
|
332
|
-
// Map task name -> owning profile from every profile's tasks.json (first wins).
|
|
333
248
|
const taskOwner = new Map();
|
|
334
249
|
let profileDirs = [];
|
|
335
250
|
try {
|
|
@@ -359,15 +274,7 @@ export function foldBrowserSessionsIntoProfiles(browserDir = path.join(CACHE_DIR
|
|
|
359
274
|
}
|
|
360
275
|
rmEmptyDirTree(legacySessionsDir);
|
|
361
276
|
}
|
|
362
|
-
/**
|
|
363
|
-
* Fold ~/.agents/browser/profiles/*.yaml into ~/.agents/agents.yaml under a
|
|
364
|
-
* `browser:` key, then delete the profiles directory. Single user file to sync.
|
|
365
|
-
*
|
|
366
|
-
* On collision (a profile name already exists in agents.yaml browser:), the
|
|
367
|
-
* existing agents.yaml entry wins and the standalone copy is dropped.
|
|
368
|
-
*
|
|
369
|
-
* Idempotent: skips if profiles dir is absent or empty.
|
|
370
|
-
*/
|
|
277
|
+
/** Fold ~/.agents/browser/profiles/*.yaml into ~/.agents/agents.yaml under `browser:`. agents.yaml wins on collision. */
|
|
371
278
|
function foldBrowserProfilesIntoAgentsYaml() {
|
|
372
279
|
const profilesDir = path.join(USER_DIR, 'browser', 'profiles');
|
|
373
280
|
if (!fs.existsSync(profilesDir))
|
|
@@ -441,10 +348,7 @@ function foldBrowserProfilesIntoAgentsYaml() {
|
|
|
441
348
|
}
|
|
442
349
|
catch { /* best-effort */ }
|
|
443
350
|
}
|
|
444
|
-
/**
|
|
445
|
-
* Delete ~/.agents/linear.json. The linear-cli now manages its own
|
|
446
|
-
* credentials in the OS keychain; this file was a legacy plaintext store.
|
|
447
|
-
*/
|
|
351
|
+
/** Delete the legacy ~/.agents/linear.json plaintext credential store. */
|
|
448
352
|
function deleteUserLinearJson() {
|
|
449
353
|
const f = path.join(USER_DIR, 'linear.json');
|
|
450
354
|
if (!fs.existsSync(f))
|
|
@@ -454,11 +358,7 @@ function deleteUserLinearJson() {
|
|
|
454
358
|
}
|
|
455
359
|
catch { /* best-effort */ }
|
|
456
360
|
}
|
|
457
|
-
/**
|
|
458
|
-
* Delete ~/.agents/prompts.json. Dead file with zero refs in src/ (the
|
|
459
|
-
* system-repo copy was cleared by deleteSystemPromptsJson; this is the
|
|
460
|
-
* matching cleanup at the user layer).
|
|
461
|
-
*/
|
|
361
|
+
/** Delete the dead ~/.agents/prompts.json file. */
|
|
462
362
|
function deleteUserPromptsJson() {
|
|
463
363
|
const f = path.join(USER_DIR, 'prompts.json');
|
|
464
364
|
if (!fs.existsSync(f))
|
|
@@ -468,12 +368,7 @@ function deleteUserPromptsJson() {
|
|
|
468
368
|
}
|
|
469
369
|
catch { /* best-effort */ }
|
|
470
370
|
}
|
|
471
|
-
/**
|
|
472
|
-
* Delete ~/.agents/teams/config.json. The teams subsystem no longer carries
|
|
473
|
-
* its own agent registry — agent discovery flows through `listInstalledVersions`
|
|
474
|
-
* (the same source `agents view` uses) and invocation flows through
|
|
475
|
-
* `agents run`. The on-disk file is pure dead state on existing installs.
|
|
476
|
-
*/
|
|
371
|
+
/** Delete the dead ~/.agents/teams/config.json file. */
|
|
477
372
|
function deleteTeamsConfigJson() {
|
|
478
373
|
const f = path.join(USER_DIR, 'teams', 'config.json');
|
|
479
374
|
if (!fs.existsSync(f))
|
|
@@ -483,22 +378,13 @@ function deleteTeamsConfigJson() {
|
|
|
483
378
|
}
|
|
484
379
|
catch { /* best-effort */ }
|
|
485
380
|
}
|
|
486
|
-
/**
|
|
487
|
-
* Move ~/.agents/teams/registry.json → ~/.agents/.history/teams/registry.json.
|
|
488
|
-
* The registry is per-machine runtime state (timestamps + absolute worktree
|
|
489
|
-
* paths) and belongs in the durable-runtime bucket, not at the user-root
|
|
490
|
-
* where `agents repo push` would sync it across machines.
|
|
491
|
-
*/
|
|
381
|
+
/** Move ~/.agents/teams/registry.json (per-machine runtime state) into ~/.agents/.history/teams/. */
|
|
492
382
|
function moveTeamsRegistryToHistory() {
|
|
493
383
|
const src = path.join(USER_DIR, 'teams', 'registry.json');
|
|
494
384
|
const dest = path.join(HISTORY_DIR, 'teams', 'registry.json');
|
|
495
385
|
moveFileOnce(src, dest);
|
|
496
386
|
}
|
|
497
|
-
/**
|
|
498
|
-
* Delete ~/.agents/config.json. This was the legacy teams config location;
|
|
499
|
-
* the teams subsystem no longer carries a config file at all, so the legacy
|
|
500
|
-
* copy is simply removed.
|
|
501
|
-
*/
|
|
387
|
+
/** Delete the legacy ~/.agents/config.json teams config file. */
|
|
502
388
|
function cleanupUserConfigJson() {
|
|
503
389
|
const legacy = path.join(USER_DIR, 'config.json');
|
|
504
390
|
if (!fs.existsSync(legacy))
|
|
@@ -508,11 +394,7 @@ function cleanupUserConfigJson() {
|
|
|
508
394
|
}
|
|
509
395
|
catch { /* best-effort */ }
|
|
510
396
|
}
|
|
511
|
-
/**
|
|
512
|
-
* Remove an empty ~/.agents/runs/ directory left over after the
|
|
513
|
-
* migrateRunsIntoRoutines() rename. Some older code paths re-created the
|
|
514
|
-
* empty parent; this trims it once it has no contents.
|
|
515
|
-
*/
|
|
397
|
+
/** Remove an empty ~/.agents/runs/ directory left over after migrateRunsIntoRoutines(). */
|
|
516
398
|
function cleanupEmptyTopLevelRuns() {
|
|
517
399
|
const dir = path.join(USER_DIR, 'runs');
|
|
518
400
|
if (!fs.existsSync(dir))
|
|
@@ -523,11 +405,7 @@ function cleanupEmptyTopLevelRuns() {
|
|
|
523
405
|
}
|
|
524
406
|
catch { /* best-effort */ }
|
|
525
407
|
}
|
|
526
|
-
/**
|
|
527
|
-
* Move ~/.agents-system/aliases.json -> ~/.agents/aliases.json.
|
|
528
|
-
* Aliases are per-user state and were previously written to the system root
|
|
529
|
-
* by mistake. Idempotent: skips if dest already exists or src absent.
|
|
530
|
-
*/
|
|
408
|
+
/** Move ~/.agents-system/aliases.json into ~/.agents/aliases.json. */
|
|
531
409
|
function migrateAliasesToUser() {
|
|
532
410
|
const src = path.join(SYSTEM_DIR, 'aliases.json');
|
|
533
411
|
const dest = path.join(USER_DIR, 'aliases.json');
|
|
@@ -615,11 +493,7 @@ function mergeOverlappingVersionHomes() {
|
|
|
615
493
|
console.error(`Merged ${mergedCount} overlapping version home${mergedCount === 1 ? '' : 's'} from legacy ~/.agents-system/versions/ into ~/.agents/versions/ (legacy moved to ~/.agents/.trash/versions/)`);
|
|
616
494
|
}
|
|
617
495
|
}
|
|
618
|
-
/**
|
|
619
|
-
* Rename ~/.agents/permissions/sets/ -> ~/.agents/permissions/presets/.
|
|
620
|
-
* Also handles ~/.agents-system/permissions/sets/ for system repo.
|
|
621
|
-
* Idempotent: skips if dest already exists or src absent.
|
|
622
|
-
*/
|
|
496
|
+
/** Rename permissions/sets/ to permissions/presets/ in both user and system repos. */
|
|
623
497
|
function migratePermissionSetsToPresets() {
|
|
624
498
|
for (const root of [USER_DIR, SYSTEM_DIR]) {
|
|
625
499
|
const src = path.join(root, 'permissions', 'sets');
|
|
@@ -634,16 +508,7 @@ function migratePermissionSetsToPresets() {
|
|
|
634
508
|
catch { /* best-effort */ }
|
|
635
509
|
}
|
|
636
510
|
}
|
|
637
|
-
/**
|
|
638
|
-
* After versions are migrated to ~/.agents/versions/, rewrite the per-agent
|
|
639
|
-
* config symlinks (~/.claude, ~/.codex, …) to point at the user-side
|
|
640
|
-
* version-home so the agent CLIs read fresh resources.
|
|
641
|
-
*
|
|
642
|
-
* Idempotent: if the symlink already points at the right user-path target,
|
|
643
|
-
* leave it. If it points at the legacy system path, re-create it. If a real
|
|
644
|
-
* directory exists there (no symlink yet), leave it alone — version-config
|
|
645
|
-
* switching is owned by `agents use`, not the migrator.
|
|
646
|
-
*/
|
|
511
|
+
/** Rewrite per-agent config symlinks to point at the user-side version home after migration. Leaves real directories alone (switching is owned by `agents use`). */
|
|
647
512
|
function repairAgentConfigSymlinks() {
|
|
648
513
|
// Version pins live in the machine-local pins JSON (~/.agents/.history/
|
|
649
514
|
// devices/pins-<machine>.json); the tracked device doc and central
|
|
@@ -734,32 +599,9 @@ function repairAgentConfigSymlinks() {
|
|
|
734
599
|
console.error(`Repaired ${repaired} agent config symlink${repaired === 1 ? '' : 's'} to point at ~/.agents/versions/`);
|
|
735
600
|
}
|
|
736
601
|
}
|
|
737
|
-
/**
|
|
738
|
-
* Repair self-referential agent binary symlinks.
|
|
739
|
-
*
|
|
740
|
-
* Some installScript-based agents — notably Factory.ai's `droid`, whose installer
|
|
741
|
-
* drops a standalone native binary at ~/.local/bin/droid — were registered at
|
|
742
|
-
* install time by resolving the post-install binary with `which <cli>`. Because
|
|
743
|
-
* ~/.agents/.cache/shims sits ahead of ~/.local/bin on PATH, `which` could
|
|
744
|
-
* return OUR OWN dispatcher shim, and the install step symlinked
|
|
745
|
-
* ~/.agents/.history/versions/<agent>/<version>/node_modules/.bin/<cli>
|
|
746
|
-
* back at ~/.agents/.cache/shims/<cli>. Launching that agent then re-execs the
|
|
747
|
-
* dispatcher forever (an infinite exec loop that hangs the terminal).
|
|
748
|
-
*
|
|
749
|
-
* This walks every installed version's node_modules/.bin and, for any entry
|
|
750
|
-
* whose symlink resolves into the shims dir, re-points it at the real binary
|
|
751
|
-
* (found on PATH with the shims dir excluded) — or removes it when no real
|
|
752
|
-
* binary can be found, letting getBinaryPath's per-agent resolver take over.
|
|
753
|
-
* Idempotent: a correctly-pointed link is left untouched on re-run.
|
|
754
|
-
*
|
|
755
|
-
* Params default to the real on-disk locations; they are injectable so tests
|
|
756
|
-
* can drive a fixture tree without touching the user's ~/.agents.
|
|
757
|
-
*/
|
|
602
|
+
/** Repair node_modules/.bin/<cli> symlinks that resolve back into our own shims dir (infinite exec-loop fix). */
|
|
758
603
|
export function repairSelfReferentialBinShims(versionsRoot = path.join(HISTORY_DIR, 'versions'), shimsDir = path.resolve(CACHE_DIR, 'shims'), historyDir = path.dirname(versionsRoot)) {
|
|
759
|
-
//
|
|
760
|
-
// a symlinked ~/.agents (or macOS's /tmp -> /private/tmp): fs.realpathSync on
|
|
761
|
-
// the link target resolves those symlinks, so the dir we compare against must
|
|
762
|
-
// too, or every loop would read as "points at a real binary" and be skipped.
|
|
604
|
+
// realpath the shims dir so the prefix check survives symlinked paths (e.g. macOS /tmp -> /private/tmp).
|
|
763
605
|
shimsDir = path.resolve(shimsDir);
|
|
764
606
|
try {
|
|
765
607
|
shimsDir = fs.realpathSync(shimsDir);
|
|
@@ -831,14 +673,7 @@ export function repairSelfReferentialBinShims(versionsRoot = path.join(HISTORY_D
|
|
|
831
673
|
console.error(`Repaired ${repaired} self-referential agent binary symlink${repaired === 1 ? '' : 's'} (infinite exec-loop fix).`);
|
|
832
674
|
}
|
|
833
675
|
}
|
|
834
|
-
/**
|
|
835
|
-
* Move a directory from `src` to `dest`. No-op when src is absent. When dest
|
|
836
|
-
* already exists, merge by copying everything that isn't already there, then
|
|
837
|
-
* remove the source. Idempotent: re-running converges without duplicating.
|
|
838
|
-
*
|
|
839
|
-
* The merge-on-collision behavior matters because `ensureAgentsDir()` may have
|
|
840
|
-
* pre-created an empty `dest` during startup before the migrator gets to run.
|
|
841
|
-
*/
|
|
676
|
+
/** Move `src` to `dest`; when `dest` exists, merge missing entries then remove `src`. Idempotent. */
|
|
842
677
|
function moveDirOnce(src, dest) {
|
|
843
678
|
if (!fs.existsSync(src))
|
|
844
679
|
return;
|
|
@@ -858,11 +693,7 @@ function moveDirOnce(src, dest) {
|
|
|
858
693
|
}
|
|
859
694
|
catch { /* best-effort */ }
|
|
860
695
|
}
|
|
861
|
-
/**
|
|
862
|
-
* Move a single file from `src` to `dest`. No-op when src is absent. When
|
|
863
|
-
* dest exists, the source is simply deleted (the in-place version is treated
|
|
864
|
-
* as the canonical state). Idempotent.
|
|
865
|
-
*/
|
|
696
|
+
/** Move `src` to `dest`; when `dest` exists, delete `src` (dest is canonical). Idempotent. */
|
|
866
697
|
function moveFileOnce(src, dest) {
|
|
867
698
|
if (!fs.existsSync(src))
|
|
868
699
|
return;
|
|
@@ -885,7 +716,6 @@ function moveFileOnce(src, dest) {
|
|
|
885
716
|
catch { /* best-effort */ }
|
|
886
717
|
}
|
|
887
718
|
}
|
|
888
|
-
/** Remove a directory tree if it exists and contains no files (best-effort). */
|
|
889
719
|
function rmEmptyDirTree(dir) {
|
|
890
720
|
if (!fs.existsSync(dir))
|
|
891
721
|
return;
|
|
@@ -1711,41 +1541,7 @@ function migrateSplitDeviceLocalMeta() {
|
|
|
1711
1541
|
console.error('Split agents.yaml: agents: -> .history/devices/pins-*.json, versions: -> .history/version-resources.json');
|
|
1712
1542
|
}
|
|
1713
1543
|
}
|
|
1714
|
-
/**
|
|
1715
|
-
* Move the auto-detected `default` browser profile OUT of the committed central
|
|
1716
|
-
* agents.yaml and into this machine's per-device file.
|
|
1717
|
-
*
|
|
1718
|
-
* `browser` is a CENTRAL key because named profiles a user creates are real fleet
|
|
1719
|
-
* config, but the ONE `default` entry inside it is machine-local: its `binary` is
|
|
1720
|
-
* an OS-specific path and its endpoint is a locally-chosen free port.
|
|
1721
|
-
* `createProfile`/`updateProfile` already route that entry to `deviceBrowser`
|
|
1722
|
-
* (`isMachineLocalProfile`, browser/profiles.ts) — but nothing ever removed the
|
|
1723
|
-
* copy older versions had already written into the shared file, and
|
|
1724
|
-
* `serializeCentral` cannot: it deletes whole KEYS that are device-scoped, and
|
|
1725
|
-
* `browser` is not one.
|
|
1726
|
-
*
|
|
1727
|
-
* So the entry sat in the committed file and every box rewrote it with its own
|
|
1728
|
-
* browser. Measured 2026-08-13, all three boxes on 1.22.38 (which HAS the writer
|
|
1729
|
-
* fix) with an empty `deviceBrowser` and a machine-specific `default` in central:
|
|
1730
|
-
*
|
|
1731
|
-
* zion browser: chrome binary: /Applications/Google Chrome.app/...
|
|
1732
|
-
* yosemite-s1 browser: brave binary: /opt/brave.com/brave/brave
|
|
1733
|
-
* mark-1 (same shape)
|
|
1734
|
-
*
|
|
1735
|
-
* `agents repos pull user` refuses when an incoming change touches a locally
|
|
1736
|
-
* modified path, so agents.yaml being permanently dirty wedged the fleet config
|
|
1737
|
-
* sync outright — those boxes sat 5, 8 and 79 commits behind. (RUSH-2161)
|
|
1738
|
-
*
|
|
1739
|
-
* Idempotent: no-op once central carries no `default` entry. The device file is
|
|
1740
|
-
* written FIRST so a crash between the two writes can never lose the profile,
|
|
1741
|
-
* and an entry already in the device file wins (this machine's live value is
|
|
1742
|
-
* newer than the stale central copy by construction).
|
|
1743
|
-
*
|
|
1744
|
-
* Central is edited through a `yaml.Document` rather than re-stringified, so the
|
|
1745
|
-
* hand-written comments in the committed agents.yaml survive — a plain
|
|
1746
|
-
* `yaml.stringify` would drop every one of them and rewrite the whole file,
|
|
1747
|
-
* which is the same churn this migration exists to stop (see `serializeCentral`).
|
|
1748
|
-
*/
|
|
1544
|
+
/** Move the auto-detected `default` browser profile from committed agents.yaml into the per-device file. The device file is written first so a crash cannot lose the profile; central is edited via yaml.Document to preserve comments. */
|
|
1749
1545
|
export function migrateMachineLocalBrowserProfileOutOfCentral(userDir = USER_DIR, machine = machineId()) {
|
|
1750
1546
|
const metaFile = path.join(userDir, 'agents.yaml');
|
|
1751
1547
|
if (!fs.existsSync(metaFile))
|
|
@@ -1808,35 +1604,7 @@ export function migrateMachineLocalBrowserProfileOutOfCentral(userDir = USER_DIR
|
|
|
1808
1604
|
atomicWriteFileSync(metaFile, remaining === 0 ? DEVICE_META_HEADER : stringifyDoc(doc));
|
|
1809
1605
|
console.error(`Migrated agents.yaml: browser '${LEGACY_DEFAULT_BROWSER_PROFILE_NAME}' profile -> devices/${machine}/agents.yaml`);
|
|
1810
1606
|
}
|
|
1811
|
-
/**
|
|
1812
|
-
* Rename the legacy `extras-extras/` plugin-marketplace dir to `agents-extras/`
|
|
1813
|
-
* inside every installed agent version-home, and rewrite cross-references in
|
|
1814
|
-
* `known_marketplaces.json` and the agent's `settings.json`.
|
|
1815
|
-
*
|
|
1816
|
-
* A previous dev build of `agents-cli` named the extras-aliased repo's
|
|
1817
|
-
* synthesized marketplace dir `extras-extras` (double "extras" because the alias
|
|
1818
|
-
* itself was `extras`). The new naming convention is `agents-<alias>`, so the
|
|
1819
|
-
* directory should be `agents-extras`. Without this migration the orphan dir
|
|
1820
|
-
* stays on disk and Claude Code loads two parallel marketplaces (the legacy
|
|
1821
|
-
* `extras-extras` entry from `known_marketplaces.json` plus the freshly
|
|
1822
|
-
* synthesized `agents-extras` from the new code path).
|
|
1823
|
-
*
|
|
1824
|
-
* Strategy per `<historyDir>/versions/<agent>/<ver>/home/.<agent>/plugins/`:
|
|
1825
|
-
* 1. `marketplaces/extras-extras/` → `marketplaces/agents-extras/`
|
|
1826
|
-
* (drops `extras-extras/` outright when `agents-extras/` already exists —
|
|
1827
|
-
* previous incomplete migration ran)
|
|
1828
|
-
* 2. Inside the renamed dir's `.claude-plugin/marketplace.json`, set
|
|
1829
|
-
* `"name": "agents-extras"`.
|
|
1830
|
-
* 3. In `<configDir>/plugins/known_marketplaces.json`, rename the
|
|
1831
|
-
* `extras-extras` key to `agents-extras` and rewrite `source.path` /
|
|
1832
|
-
* `installLocation`.
|
|
1833
|
-
* 4. In `<configDir>/settings.json`'s `enabledPlugins`, rename every
|
|
1834
|
-
* `<plugin>@extras-extras` key to `<plugin>@agents-extras` (preserving
|
|
1835
|
-
* its boolean value, skipping if the new key already exists).
|
|
1836
|
-
*
|
|
1837
|
-
* Idempotent: re-running converges without further writes once everything is on
|
|
1838
|
-
* the new name.
|
|
1839
|
-
*/
|
|
1607
|
+
/** Rename the legacy `extras-extras/` plugin marketplace dir to `agents-extras/` in every installed version home, and rewrite cross-references in `known_marketplaces.json` and `settings.json`. */
|
|
1840
1608
|
export function migrateExtrasExtrasToAgentsExtras(historyDir = HISTORY_DIR) {
|
|
1841
1609
|
const versionsRoot = path.join(historyDir, 'versions');
|
|
1842
1610
|
if (!fs.existsSync(versionsRoot))
|