@phnx-labs/agents-cli 1.20.77 → 1.20.82
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 +589 -0
- package/README.md +27 -25
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +9 -0
- package/dist/commands/activity.js +153 -24
- package/dist/commands/apply.js +11 -4
- package/dist/commands/cli.js +1 -1
- package/dist/commands/commands.d.ts +1 -1
- package/dist/commands/commands.js +7 -6
- package/dist/commands/defaults.js +3 -11
- package/dist/commands/doctor.d.ts +74 -0
- package/dist/commands/doctor.js +718 -40
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +53 -8
- package/dist/commands/feed.d.ts +4 -0
- package/dist/commands/feed.js +87 -11
- package/dist/commands/harness.js +2 -2
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +8 -4
- package/dist/commands/logs.js +6 -0
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -6
- package/dist/commands/permissions.js +1 -1
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.js +4 -4
- package/dist/commands/repo.d.ts +78 -0
- package/dist/commands/repo.js +195 -11
- package/dist/commands/routines.js +16 -4
- package/dist/commands/rules.js +13 -12
- package/dist/commands/secrets.d.ts +3 -1
- package/dist/commands/secrets.js +108 -34
- package/dist/commands/sessions-browser.d.ts +45 -3
- package/dist/commands/sessions-browser.js +118 -12
- package/dist/commands/sessions-export.d.ts +3 -0
- package/dist/commands/sessions-export.js +13 -10
- package/dist/commands/sessions-inject.d.ts +7 -4
- package/dist/commands/sessions-inject.js +18 -18
- package/dist/commands/sessions-picker.d.ts +15 -1
- package/dist/commands/sessions-picker.js +90 -7
- package/dist/commands/sessions-resume.d.ts +16 -0
- package/dist/commands/sessions-resume.js +14 -13
- package/dist/commands/sessions.d.ts +126 -1
- package/dist/commands/sessions.js +365 -42
- package/dist/commands/set.d.ts +15 -0
- package/dist/commands/set.js +79 -0
- package/dist/commands/setup-fleet.d.ts +21 -0
- package/dist/commands/setup-fleet.js +201 -0
- package/dist/commands/setup-secrets.d.ts +20 -0
- package/dist/commands/setup-secrets.js +223 -0
- package/dist/commands/setup.js +17 -3
- package/dist/commands/skills.js +1 -1
- package/dist/commands/ssh.js +9 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/teams-picker.js +0 -1
- package/dist/commands/teams.d.ts +33 -1
- package/dist/commands/teams.js +208 -44
- package/dist/commands/versions.js +10 -5
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.js +11 -0
- package/dist/index.js +8 -13
- package/dist/lib/acp/harnesses.js +0 -7
- package/dist/lib/activity.d.ts +156 -0
- package/dist/lib/activity.js +282 -0
- package/dist/lib/agents.d.ts +9 -23
- package/dist/lib/agents.js +72 -100
- package/dist/lib/auto-pull.d.ts +16 -8
- package/dist/lib/auto-pull.js +23 -28
- package/dist/lib/browser/service.js +3 -0
- package/dist/lib/browser/types.d.ts +7 -0
- package/dist/lib/capabilities.js +6 -2
- package/dist/lib/crabbox/lease.js +2 -2
- package/dist/lib/crabbox/setup-copy.d.ts +4 -4
- package/dist/lib/crabbox/setup-copy.js +4 -4
- package/dist/lib/daemon.d.ts +26 -40
- package/dist/lib/daemon.js +63 -123
- package/dist/lib/devices/fleet-divergence.d.ts +101 -0
- package/dist/lib/devices/fleet-divergence.js +188 -0
- package/dist/lib/devices/fleet-inventory.d.ts +19 -0
- package/dist/lib/devices/fleet-inventory.js +57 -0
- package/dist/lib/devices/fleet.d.ts +1 -1
- package/dist/lib/devices/fleet.js +1 -1
- package/dist/lib/devices/health-report.d.ts +10 -2
- package/dist/lib/devices/health-report.js +32 -1
- package/dist/lib/doctor-diff.d.ts +20 -0
- package/dist/lib/doctor-diff.js +6 -1
- package/dist/lib/drift.d.ts +31 -11
- package/dist/lib/drift.js +58 -7
- package/dist/lib/events.d.ts +8 -1
- package/dist/lib/events.js +10 -1
- package/dist/lib/exec.js +35 -8
- package/dist/lib/feed-post.d.ts +28 -1
- package/dist/lib/feed-post.js +110 -2
- package/dist/lib/fleet/apply.js +8 -1
- package/dist/lib/fleet/auth-sync.d.ts +18 -1
- package/dist/lib/fleet/auth-sync.js +25 -11
- package/dist/lib/fleet/remote-login.js +5 -0
- package/dist/lib/git.d.ts +27 -14
- package/dist/lib/git.js +138 -43
- package/dist/lib/hooks.d.ts +42 -0
- package/dist/lib/hooks.js +137 -93
- package/dist/lib/hosts/dispatch.d.ts +28 -1
- package/dist/lib/hosts/dispatch.js +33 -5
- package/dist/lib/hosts/option.js +2 -2
- package/dist/lib/hosts/passthrough.d.ts +22 -1
- package/dist/lib/hosts/passthrough.js +238 -13
- package/dist/lib/hosts/remote-cmd.js +2 -0
- package/dist/lib/hosts/run-target.d.ts +2 -0
- package/dist/lib/hosts/run-target.js +1 -0
- package/dist/lib/hq/floor.d.ts +1 -1
- package/dist/lib/hq/floor.js +6 -1
- package/dist/lib/mcp.js +3 -71
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +2 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +15 -2
- package/dist/lib/menubar/notify-desktop.d.ts +15 -0
- package/dist/lib/menubar/notify-desktop.js +41 -5
- package/dist/lib/merged-resources.d.ts +11 -0
- package/dist/{commands/resources.js → lib/merged-resources.js} +11 -19
- package/dist/lib/permissions.d.ts +0 -32
- package/dist/lib/permissions.js +4 -157
- package/dist/lib/picker.js +1 -1
- package/dist/lib/platform/process.d.ts +16 -5
- package/dist/lib/platform/process.js +54 -0
- package/dist/lib/plugins.d.ts +0 -8
- package/dist/lib/plugins.js +4 -110
- package/dist/lib/project-resources.js +4 -1
- package/dist/lib/refresh.d.ts +5 -3
- package/dist/lib/refresh.js +7 -5
- package/dist/lib/resources/commands.js +4 -1
- package/dist/lib/resources/mcp.js +0 -4
- package/dist/lib/resources/permissions.d.ts +1 -1
- package/dist/lib/resources/permissions.js +1 -5
- package/dist/lib/resources/rules.js +4 -1
- package/dist/lib/resources/skills.js +4 -1
- package/dist/lib/resources/subagents.js +4 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/routines.d.ts +20 -0
- package/dist/lib/routines.js +6 -0
- package/dist/lib/run-defaults.d.ts +1 -0
- package/dist/lib/run-defaults.js +9 -0
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.js +71 -29
- package/dist/lib/sandbox.js +0 -16
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +2 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +13 -1
- package/dist/lib/secrets/agent.d.ts +18 -0
- package/dist/lib/secrets/agent.js +131 -17
- package/dist/lib/secrets/audit.d.ts +46 -0
- package/dist/lib/secrets/audit.js +56 -0
- package/dist/lib/secrets/bundles.d.ts +12 -9
- package/dist/lib/secrets/bundles.js +47 -31
- package/dist/lib/secrets/index.d.ts +2 -1
- package/dist/lib/secrets/index.js +8 -2
- package/dist/lib/secrets/remote.d.ts +75 -2
- package/dist/lib/secrets/remote.js +139 -5
- package/dist/lib/secrets/scope.d.ts +26 -0
- package/dist/lib/secrets/scope.js +29 -0
- package/dist/lib/secrets/session-store.d.ts +10 -0
- package/dist/lib/secrets/session-store.js +64 -11
- package/dist/lib/secrets/sync.js +3 -3
- package/dist/lib/session/active.d.ts +117 -26
- package/dist/lib/session/active.js +199 -53
- package/dist/lib/session/actor-sidecar.d.ts +23 -0
- package/dist/lib/session/actor-sidecar.js +101 -0
- package/dist/lib/session/db.d.ts +41 -1
- package/dist/lib/session/db.js +173 -8
- package/dist/lib/session/digest.js +126 -21
- package/dist/lib/session/discover.d.ts +19 -2
- package/dist/lib/session/discover.js +32 -11
- package/dist/lib/session/hook-sessions.d.ts +9 -0
- package/dist/lib/session/hook-sessions.js +57 -8
- package/dist/lib/session/origin-machine.d.ts +18 -0
- package/dist/lib/session/origin-machine.js +34 -0
- package/dist/lib/session/pid-registry.d.ts +13 -0
- package/dist/lib/session/render.d.ts +2 -0
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/state.d.ts +1 -0
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.js +2 -2
- package/dist/lib/session/types.d.ts +16 -0
- package/dist/lib/smart-launch.d.ts +86 -0
- package/dist/lib/smart-launch.js +172 -0
- package/dist/lib/staleness/detectors/commands.js +2 -2
- package/dist/lib/staleness/detectors/permissions.js +1 -45
- package/dist/lib/staleness/writers/commands.js +4 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +1 -2
- package/dist/lib/startup/command-registry.js +2 -4
- package/dist/lib/subagents-registry.js +5 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -12
- package/dist/lib/teams/agents.d.ts +0 -2
- package/dist/lib/teams/agents.js +10 -27
- package/dist/lib/teams/index.d.ts +1 -1
- package/dist/lib/teams/index.js +1 -1
- package/dist/lib/types.d.ts +17 -9
- package/dist/lib/usage.d.ts +28 -5
- package/dist/lib/usage.js +271 -8
- package/dist/lib/versions.js +7 -1
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdog.js +25 -13
- package/package.json +1 -2
- package/dist/commands/check.d.ts +0 -15
- package/dist/commands/check.js +0 -180
- package/dist/commands/resources.d.ts +0 -5
- package/dist/lib/secrets/account-token.d.ts +0 -20
- package/dist/lib/secrets/account-token.js +0 -64
package/dist/lib/agents.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core agent configuration and detection module.
|
|
3
3
|
*
|
|
4
|
-
* Defines the canonical registry of
|
|
5
|
-
* Gemini, Cursor, OpenCode, OpenClaw, Copilot, Amp, Kiro, Goose, Grok)
|
|
6
|
-
* CLI commands, config paths, capability flags, and MCP integration
|
|
4
|
+
* Defines the canonical registry of current and legacy AI coding agents (Claude,
|
|
5
|
+
* Codex, Gemini, Cursor, OpenCode, OpenClaw, Copilot, Amp, Kiro, Goose, Grok)
|
|
6
|
+
* with their CLI commands, config paths, capability flags, and MCP integration
|
|
7
|
+
* points.
|
|
7
8
|
*
|
|
8
9
|
* Provides functions for detecting installed CLIs, resolving version-managed binaries,
|
|
9
10
|
* reading account/auth info, and managing MCP server registrations across agents.
|
|
@@ -256,13 +257,15 @@ export const AGENTS = {
|
|
|
256
257
|
nativeAgentsSkillsDir: true,
|
|
257
258
|
// Google retired the Gemini CLI (announced at Google I/O 2026, May 19); the `gemini`
|
|
258
259
|
// command stopped serving free/Pro/Ultra requests on June 18, 2026. Antigravity CLI
|
|
259
|
-
// (`agy`) is the official successor.
|
|
260
|
+
// (`agy`) is the official successor. Hard deprecation keeps legacy Gemini
|
|
261
|
+
// sessions/config parseable while blocking install/import/sync.
|
|
260
262
|
deprecated: {
|
|
261
263
|
by: 'Google',
|
|
262
264
|
date: 'June 18, 2026',
|
|
263
265
|
reason: 'The Gemini CLI was retired for free, Pro, and Ultra tiers and no longer serves requests (announced at Google I/O 2026 on May 19).',
|
|
264
266
|
replacement: 'antigravity',
|
|
265
267
|
url: 'https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/',
|
|
268
|
+
hard: true,
|
|
266
269
|
},
|
|
267
270
|
// gemini hooks: shipped in v0.26.0 (Jan 2026); older binaries silently ignore the `hooks` key.
|
|
268
271
|
// extensions: gemini-extension.json bundles shipped in v0.8.0; custom subagents in v0.36.0.
|
|
@@ -697,58 +700,18 @@ export const AGENTS = {
|
|
|
697
700
|
rulesImports: false,
|
|
698
701
|
},
|
|
699
702
|
},
|
|
700
|
-
// ForgeCode (`forge`) from Tailcall. It reads AGENTS.md project rules,
|
|
701
|
-
// SKILL.md directories, and MCP servers from `.mcp.json` files.
|
|
702
|
-
forge: {
|
|
703
|
-
id: 'forge',
|
|
704
|
-
name: 'ForgeCode',
|
|
705
|
-
color: 'greenBright',
|
|
706
|
-
cliCommand: 'forge',
|
|
707
|
-
npmPackage: '',
|
|
708
|
-
installScript: 'curl -fsSL https://forgecode.dev/cli | sh',
|
|
709
|
-
configDir: path.join(HOME, '.forge'),
|
|
710
|
-
commandsDir: path.join(HOME, '.forge', 'commands'),
|
|
711
|
-
commandsSubdir: 'commands',
|
|
712
|
-
skillsDir: path.join(HOME, '.forge', 'skills'),
|
|
713
|
-
hooksDir: 'hooks',
|
|
714
|
-
instructionsFile: 'AGENTS.md',
|
|
715
|
-
format: 'markdown',
|
|
716
|
-
variableSyntax: '$ARGUMENTS',
|
|
717
|
-
supportsHooks: false,
|
|
718
|
-
// Commands: ForgeCode reads Markdown slash commands from `~/.forge/commands/<name>.md`
|
|
719
|
-
// (also the shared `~/.agents/commands/`); the filename is the command name.
|
|
720
|
-
// Subagents: named `.md` agent definitions with YAML frontmatter under
|
|
721
|
-
// `~/.forge/agents/<name>.md` — same Markdown+frontmatter shape as Droid/Copilot
|
|
722
|
-
// (no `color` field), so transformSubagentForForge aliases transformSubagentForDroid.
|
|
723
|
-
// See https://forgecode.dev/docs/commands/ and /docs/agent-definition-guide/.
|
|
724
|
-
capabilities: {
|
|
725
|
-
hooks: false,
|
|
726
|
-
mcp: true,
|
|
727
|
-
mcpHttp: true,
|
|
728
|
-
mcpHeaders: false,
|
|
729
|
-
// Permissions: ~/.forge/permissions.yaml (or $FORGE_CONFIG/permissions.yaml)
|
|
730
|
-
// carries ordered operation-family glob policies. It is active only when
|
|
731
|
-
// `.forge.toml` sets `restricted = true`; MCP tools bypass this file.
|
|
732
|
-
allowlist: true,
|
|
733
|
-
skills: true,
|
|
734
|
-
commands: true,
|
|
735
|
-
plugins: false,
|
|
736
|
-
subagents: true,
|
|
737
|
-
rules: { file: 'AGENTS.md' },
|
|
738
|
-
workflows: false,
|
|
739
|
-
memory: false,
|
|
740
|
-
modes: ['edit'],
|
|
741
|
-
rulesImports: false,
|
|
742
|
-
},
|
|
743
|
-
},
|
|
744
703
|
};
|
|
745
|
-
/** All
|
|
704
|
+
/** All current and legacy agent IDs derived from the AGENTS registry. */
|
|
746
705
|
export const ALL_AGENT_IDS = Object.keys(AGENTS);
|
|
706
|
+
/** Agents retained only for legacy reads, not install/import/sync targets. */
|
|
707
|
+
export const HARD_DEPRECATED_AGENT_IDS = ALL_AGENT_IDS.filter((id) => AGENTS[id].deprecated?.hard);
|
|
708
|
+
/** Agents that can receive managed installs, imports, and resource sync writes. */
|
|
709
|
+
export const MANAGED_AGENT_IDS = ALL_AGENT_IDS.filter((id) => !AGENTS[id].deprecated?.hard);
|
|
747
710
|
/**
|
|
748
711
|
* A self-updating agent is a single global binary installed by an official
|
|
749
712
|
* `curl … | sh` / `brew install` script that carries NO version token — the
|
|
750
713
|
* installer can only ever fetch the *current* release, and the binary then keeps
|
|
751
|
-
* itself up to date in place (droid, grok, antigravity, cursor, hermes,
|
|
714
|
+
* itself up to date in place (droid, grok, antigravity, cursor, hermes,
|
|
752
715
|
* kiro, goose). There is no semver to pin, so agents-cli must not model these as
|
|
753
716
|
* having multiple installable version-homes the way it does for npm-packaged
|
|
754
717
|
* agents (claude, codex, kimi, …).
|
|
@@ -768,6 +731,9 @@ export function isSelfUpdatingAgent(agent) {
|
|
|
768
731
|
const cfg = AGENTS[agent];
|
|
769
732
|
return !cfg.npmPackage && !!cfg.installScript && !cfg.installScript.includes('VERSION');
|
|
770
733
|
}
|
|
734
|
+
export function isAgentHardDeprecated(agent) {
|
|
735
|
+
return AGENTS[agent].deprecated?.hard === true;
|
|
736
|
+
}
|
|
771
737
|
// Capability-filtered agent lists used to live here as `*_CAPABLE_AGENTS`
|
|
772
738
|
// constants. They were a frequent source of silent-skip bugs (e.g. grok
|
|
773
739
|
// rules sync gated on `COMMANDS_CAPABLE_AGENTS`). Use `capableAgents(cap)`
|
|
@@ -1404,43 +1370,6 @@ export function isClaudeCredentialFileBlank(base, platform = process.platform) {
|
|
|
1404
1370
|
return false;
|
|
1405
1371
|
}
|
|
1406
1372
|
}
|
|
1407
|
-
/**
|
|
1408
|
-
* Whether a Claude version home holds its OWN on-disk credential — a non-blank
|
|
1409
|
-
* `.claude/.credentials.json` (the store Claude Code writes on login off macOS)
|
|
1410
|
-
* or a `.claude/.oauth_token` file (the keychain-less shim fallback, shims.ts).
|
|
1411
|
-
*
|
|
1412
|
-
* RUSH-1979: the routines daemon injects one ambient `CLAUDE_CODE_OAUTH_TOKEN`
|
|
1413
|
-
* (RUSH-1759) so a token-less default account still authenticates. But Claude —
|
|
1414
|
-
* and the Linux shim's own `-z CLAUDE_CODE_OAUTH_TOKEN` guard — both prefer that
|
|
1415
|
-
* env var over a pinned account's config dir, so when balanced rotation pins a
|
|
1416
|
-
* specific account's `CLAUDE_CONFIG_DIR` the ambient token shadows it: the pool
|
|
1417
|
-
* is inert and every fire 401s on the one stale token. A routine spawn drops the
|
|
1418
|
-
* ambient token when the pinned account has its own credential (this returns
|
|
1419
|
-
* true) so the account authenticates itself; when it does not (the RUSH-1759
|
|
1420
|
-
* default), the injected token is kept.
|
|
1421
|
-
*
|
|
1422
|
-
* Off-darwin only, mirroring {@link isClaudeCredentialFileBlank}: on macOS the
|
|
1423
|
-
* login Keychain is the canonical store and probing it raises an auth sheet, and
|
|
1424
|
-
* there the daemon injects no token to shadow (broker-only, usually absent), so
|
|
1425
|
-
* returning false changes nothing. Sync, no Keychain, no network.
|
|
1426
|
-
*/
|
|
1427
|
-
export function claudeHomeHasOwnCredential(base, platform = process.platform) {
|
|
1428
|
-
if (platform === 'darwin')
|
|
1429
|
-
return false;
|
|
1430
|
-
if (fs.existsSync(path.join(base, '.claude', '.oauth_token')))
|
|
1431
|
-
return true;
|
|
1432
|
-
try {
|
|
1433
|
-
const raw = fs.readFileSync(path.join(base, '.claude', '.credentials.json'), 'utf-8');
|
|
1434
|
-
const oauth = JSON.parse(raw).claudeAiOauth;
|
|
1435
|
-
if (!oauth)
|
|
1436
|
-
return false;
|
|
1437
|
-
const nonEmpty = (v) => typeof v === 'string' && v.trim().length > 0;
|
|
1438
|
-
return nonEmpty(oauth.accessToken) || nonEmpty(oauth.refreshToken);
|
|
1439
|
-
}
|
|
1440
|
-
catch {
|
|
1441
|
-
return false;
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
1373
|
export async function getAccountInfo(agentId, home) {
|
|
1445
1374
|
const base = home || os.homedir();
|
|
1446
1375
|
const empty = {
|
|
@@ -1589,6 +1518,38 @@ export async function getAccountInfo(agentId, home) {
|
|
|
1589
1518
|
const email = data.active || null;
|
|
1590
1519
|
return { ...empty, email, signedIn: !!email, lastActive };
|
|
1591
1520
|
}
|
|
1521
|
+
case 'cursor': {
|
|
1522
|
+
// Cursor CLI keeps account metadata in ~/.cursor/cli-config.json
|
|
1523
|
+
// (authInfo: { email, userId, authId }) and its OAuth tokens SEPARATELY
|
|
1524
|
+
// in ~/.config/cursor/auth.json ({ accessToken, refreshToken }). Presence
|
|
1525
|
+
// of an access token is the signed-in signal; email/ids come from
|
|
1526
|
+
// cli-config. authId is the OAuth subject (e.g. "google-oauth2|<n>") — the
|
|
1527
|
+
// same value the usage endpoint keys on (see getCursorUsageInfo).
|
|
1528
|
+
const cfgPath = resolveAccountCredentialPath(base, '.cursor', 'cli-config.json');
|
|
1529
|
+
if (!cfgPath)
|
|
1530
|
+
return { ...empty, lastActive };
|
|
1531
|
+
try {
|
|
1532
|
+
const cfg = JSON.parse(await fs.promises.readFile(cfgPath, 'utf-8'));
|
|
1533
|
+
const authInfo = cfg?.authInfo;
|
|
1534
|
+
const email = typeof authInfo?.email === 'string' ? authInfo.email : null;
|
|
1535
|
+
const accountId = normalizeIdentityPart(authInfo?.authId ?? authInfo?.userId);
|
|
1536
|
+
if (!email && !accountId)
|
|
1537
|
+
return { ...empty, lastActive };
|
|
1538
|
+
const authPath = resolveAccountCredentialPath(base, '.config', 'cursor', 'auth.json');
|
|
1539
|
+
let hasToken = false;
|
|
1540
|
+
if (authPath) {
|
|
1541
|
+
try {
|
|
1542
|
+
const tok = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
|
|
1543
|
+
hasToken = typeof tok?.accessToken === 'string' && tok.accessToken.length > 0;
|
|
1544
|
+
}
|
|
1545
|
+
catch { /* unreadable token file */ }
|
|
1546
|
+
}
|
|
1547
|
+
const accountKey = buildIdentityKey(agentId, [['user', accountId]]);
|
|
1548
|
+
return { ...empty, email, accountId, accountKey, signedIn: hasToken || !!email, lastActive };
|
|
1549
|
+
}
|
|
1550
|
+
catch { }
|
|
1551
|
+
return { ...empty, lastActive };
|
|
1552
|
+
}
|
|
1592
1553
|
case 'grok': {
|
|
1593
1554
|
// Grok stores auth in ~/.grok/auth.json as a map keyed by
|
|
1594
1555
|
// "<oidc_issuer>::<client_id>" -> { email, user_id, refresh_token,
|
|
@@ -1904,7 +1865,7 @@ function buildIdentityKey(agentId, parts) {
|
|
|
1904
1865
|
/** Register an MCP server with an agent's CLI via `mcp add`. */
|
|
1905
1866
|
export async function registerMcp(agentId, name, command, scope = 'user', transport = 'stdio', options) {
|
|
1906
1867
|
const agent = AGENTS[agentId];
|
|
1907
|
-
if (!
|
|
1868
|
+
if (!supports(agentId, 'mcp').ok) {
|
|
1908
1869
|
return { success: false, error: 'Agent does not support MCP' };
|
|
1909
1870
|
}
|
|
1910
1871
|
if (transport === 'http' && !supports(agentId, 'mcpHttp').ok) {
|
|
@@ -1913,7 +1874,7 @@ export async function registerMcp(agentId, name, command, scope = 'user', transp
|
|
|
1913
1874
|
if (transport === 'http' && options?.headers && Object.keys(options.headers).length > 0 && !supports(agentId, 'mcpHeaders').ok) {
|
|
1914
1875
|
return { success: false, error: 'skipped: HTTP MCP headers are only supported for Claude registration' };
|
|
1915
1876
|
}
|
|
1916
|
-
if (agentId === 'hermes'
|
|
1877
|
+
if (agentId === 'hermes') {
|
|
1917
1878
|
try {
|
|
1918
1879
|
writeMcpToConfig(agentId, name, command, scope, transport, options?.home);
|
|
1919
1880
|
return { success: true };
|
|
@@ -1964,10 +1925,10 @@ export async function registerMcp(agentId, name, command, scope = 'user', transp
|
|
|
1964
1925
|
/** Unregister (remove) a named MCP server from an agent's CLI config. */
|
|
1965
1926
|
export async function unregisterMcp(agentId, name, options) {
|
|
1966
1927
|
const agent = AGENTS[agentId];
|
|
1967
|
-
if (!
|
|
1928
|
+
if (!supports(agentId, 'mcp').ok) {
|
|
1968
1929
|
return { success: false, error: 'Agent does not support MCP' };
|
|
1969
1930
|
}
|
|
1970
|
-
if (agentId === 'hermes'
|
|
1931
|
+
if (agentId === 'hermes') {
|
|
1971
1932
|
try {
|
|
1972
1933
|
removeMcpFromConfig(agentId, name, options?.home);
|
|
1973
1934
|
return { success: true };
|
|
@@ -2319,8 +2280,6 @@ export function getUserMcpConfigPath(agentId) {
|
|
|
2319
2280
|
return path.join(agent.configDir, 'mcp.json');
|
|
2320
2281
|
case 'hermes':
|
|
2321
2282
|
return path.join(agent.configDir, 'config.yaml');
|
|
2322
|
-
case 'forge':
|
|
2323
|
-
return path.join(agent.configDir, '.mcp.json');
|
|
2324
2283
|
default:
|
|
2325
2284
|
// Gemini and others use settings.json
|
|
2326
2285
|
return path.join(agent.configDir, 'settings.json');
|
|
@@ -2357,8 +2316,6 @@ export function getMcpConfigPathForHome(agentId, home) {
|
|
|
2357
2316
|
return path.join(home, '.factory', 'mcp.json');
|
|
2358
2317
|
case 'hermes':
|
|
2359
2318
|
return path.join(home, '.hermes', 'config.yaml');
|
|
2360
|
-
case 'forge':
|
|
2361
|
-
return path.join(home, '.forge', '.mcp.json');
|
|
2362
2319
|
default:
|
|
2363
2320
|
return path.join(home, agentConfigDirName(agentId), 'settings.json');
|
|
2364
2321
|
}
|
|
@@ -2398,8 +2355,6 @@ export function getProjectMcpConfigPath(agentId, cwd = process.cwd()) {
|
|
|
2398
2355
|
return path.join(cwd, '.factory', 'mcp.json');
|
|
2399
2356
|
case 'hermes':
|
|
2400
2357
|
return path.join(cwd, '.hermes', 'config.yaml');
|
|
2401
|
-
case 'forge':
|
|
2402
|
-
return path.join(cwd, '.mcp.json');
|
|
2403
2358
|
default:
|
|
2404
2359
|
return path.join(cwd, `.${agentId}`, 'settings.json');
|
|
2405
2360
|
}
|
|
@@ -2543,9 +2498,6 @@ export const AGENT_NAME_ALIASES = {
|
|
|
2543
2498
|
droid: 'droid',
|
|
2544
2499
|
hermes: 'hermes',
|
|
2545
2500
|
'hermes-agent': 'hermes',
|
|
2546
|
-
forge: 'forge',
|
|
2547
|
-
forgecode: 'forge',
|
|
2548
|
-
'forge-code': 'forge',
|
|
2549
2501
|
};
|
|
2550
2502
|
/**
|
|
2551
2503
|
* Resolve a user-provided agent name (alias, shorthand, or canonical) to its AgentId.
|
|
@@ -2596,6 +2548,26 @@ export function deprecationNotice(agent) {
|
|
|
2596
2548
|
lines.push(` ${dep.url}`);
|
|
2597
2549
|
return lines;
|
|
2598
2550
|
}
|
|
2551
|
+
export function hardDeprecationNotice(agent) {
|
|
2552
|
+
const dep = AGENTS[agent].deprecated;
|
|
2553
|
+
if (!dep?.hard)
|
|
2554
|
+
return null;
|
|
2555
|
+
const name = AGENTS[agent].name;
|
|
2556
|
+
const lines = [
|
|
2557
|
+
`${name} is no longer supported by agents-cli because ${dep.by} retired it (${dep.date}).`,
|
|
2558
|
+
` ${dep.reason}`,
|
|
2559
|
+
];
|
|
2560
|
+
if (dep.replacement) {
|
|
2561
|
+
const rep = AGENTS[dep.replacement];
|
|
2562
|
+
lines.push(` Use ${rep.name} instead: agents add ${rep.id}`);
|
|
2563
|
+
}
|
|
2564
|
+
if (dep.url)
|
|
2565
|
+
lines.push(` ${dep.url}`);
|
|
2566
|
+
return lines;
|
|
2567
|
+
}
|
|
2568
|
+
export function hardDeprecationError(agent) {
|
|
2569
|
+
return hardDeprecationNotice(agent)?.join('\n') ?? `${AGENTS[agent].name} is no longer supported.`;
|
|
2570
|
+
}
|
|
2599
2571
|
/**
|
|
2600
2572
|
* Print a deprecation warning (yellow) if the agent's registry entry carries a
|
|
2601
2573
|
* `deprecated` marker; no-op otherwise. Call from any user entry point that
|
package/dist/lib/auto-pull.d.ts
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Background sync for tracked git repos:
|
|
3
3
|
* - System repo (~/.agents/.system/) is read-only locally — fast-forward auto-pull is safe.
|
|
4
4
|
* - User repo (~/.agents/) and enabled extras may have local commits, so we only
|
|
5
|
-
* `git fetch` and write a status marker.
|
|
6
|
-
*
|
|
5
|
+
* `git fetch` and write a status marker. `agents doctor` surfaces these markers
|
|
6
|
+
* as a "Repo updates" section instead of printing to stderr on every command.
|
|
7
|
+
* Pulling is left to the user via `agents repo pull`.
|
|
7
8
|
*
|
|
8
9
|
* Public API:
|
|
9
|
-
* spawnDetachedSync()
|
|
10
|
-
*
|
|
10
|
+
* spawnDetachedSync() — fire-and-forget; never blocks the foreground command.
|
|
11
|
+
* readRepoBehindMarkers() — synchronous; reads markers without consuming them.
|
|
11
12
|
*/
|
|
12
13
|
/** Per-repo lock file path. mtime acts as a recency check. */
|
|
13
14
|
export declare function lockFilePath(alias: string): string;
|
|
@@ -24,8 +25,15 @@ export interface FetchStatusMarker {
|
|
|
24
25
|
/** Spawn the detached worker. No-op when AGENTS_NO_AUTOPULL=1 is set. */
|
|
25
26
|
export declare function spawnDetachedSync(): void;
|
|
26
27
|
/**
|
|
27
|
-
* Read
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* Read all current status markers and return those where the local repo is
|
|
29
|
+
* behind upstream. Markers are NOT deleted — they persist until the next
|
|
30
|
+
* background fetch overwrites them with fresh data.
|
|
31
|
+
*
|
|
32
|
+
* Synchronous, cheap (small JSON files). Used by `agents doctor` to surface
|
|
33
|
+
* repo-behind warnings in one place instead of printing to stderr on every
|
|
34
|
+
* command.
|
|
35
|
+
*
|
|
36
|
+
* @param fetchDir - Override the fetch state dir (for tests). Defaults to the
|
|
37
|
+
* production getFetchCacheDir() path.
|
|
30
38
|
*/
|
|
31
|
-
export declare function
|
|
39
|
+
export declare function readRepoBehindMarkers(fetchDir?: string): FetchStatusMarker[];
|
package/dist/lib/auto-pull.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Background sync for tracked git repos:
|
|
3
3
|
* - System repo (~/.agents/.system/) is read-only locally — fast-forward auto-pull is safe.
|
|
4
4
|
* - User repo (~/.agents/) and enabled extras may have local commits, so we only
|
|
5
|
-
* `git fetch` and write a status marker.
|
|
6
|
-
*
|
|
5
|
+
* `git fetch` and write a status marker. `agents doctor` surfaces these markers
|
|
6
|
+
* as a "Repo updates" section instead of printing to stderr on every command.
|
|
7
|
+
* Pulling is left to the user via `agents repo pull`.
|
|
7
8
|
*
|
|
8
9
|
* Public API:
|
|
9
|
-
* spawnDetachedSync()
|
|
10
|
-
*
|
|
10
|
+
* spawnDetachedSync() — fire-and-forget; never blocks the foreground command.
|
|
11
|
+
* readRepoBehindMarkers() — synchronous; reads markers without consuming them.
|
|
11
12
|
*/
|
|
12
13
|
import * as fs from 'fs';
|
|
13
14
|
import * as path from 'path';
|
|
@@ -57,21 +58,29 @@ export function spawnDetachedSync() {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
60
|
-
* Read
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* Read all current status markers and return those where the local repo is
|
|
62
|
+
* behind upstream. Markers are NOT deleted — they persist until the next
|
|
63
|
+
* background fetch overwrites them with fresh data.
|
|
64
|
+
*
|
|
65
|
+
* Synchronous, cheap (small JSON files). Used by `agents doctor` to surface
|
|
66
|
+
* repo-behind warnings in one place instead of printing to stderr on every
|
|
67
|
+
* command.
|
|
68
|
+
*
|
|
69
|
+
* @param fetchDir - Override the fetch state dir (for tests). Defaults to the
|
|
70
|
+
* production getFetchCacheDir() path.
|
|
63
71
|
*/
|
|
64
|
-
export function
|
|
65
|
-
const dir = fetchStateDir();
|
|
72
|
+
export function readRepoBehindMarkers(fetchDir) {
|
|
73
|
+
const dir = fetchDir ?? fetchStateDir();
|
|
66
74
|
if (!fs.existsSync(dir))
|
|
67
|
-
return;
|
|
75
|
+
return [];
|
|
68
76
|
let entries = [];
|
|
69
77
|
try {
|
|
70
78
|
entries = fs.readdirSync(dir);
|
|
71
79
|
}
|
|
72
80
|
catch {
|
|
73
|
-
return;
|
|
81
|
+
return [];
|
|
74
82
|
}
|
|
83
|
+
const result = [];
|
|
75
84
|
for (const name of entries) {
|
|
76
85
|
if (!name.endsWith('.status.json'))
|
|
77
86
|
continue;
|
|
@@ -81,25 +90,11 @@ export function printPendingUpdateNotices() {
|
|
|
81
90
|
marker = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
82
91
|
}
|
|
83
92
|
catch {
|
|
84
|
-
try {
|
|
85
|
-
fs.unlinkSync(file);
|
|
86
|
-
}
|
|
87
|
-
catch { /* ignore */ }
|
|
88
93
|
continue;
|
|
89
94
|
}
|
|
90
|
-
if (!marker || marker.behind <= 0)
|
|
91
|
-
try {
|
|
92
|
-
fs.unlinkSync(file);
|
|
93
|
-
}
|
|
94
|
-
catch { /* ignore */ }
|
|
95
|
+
if (!marker || marker.behind <= 0)
|
|
95
96
|
continue;
|
|
96
|
-
|
|
97
|
-
const repoLabel = marker.alias === 'user' ? '~/.agents/' : marker.alias;
|
|
98
|
-
process.stderr.write(`agents-cli: ${repoLabel} is ${marker.behind} commit${marker.behind === 1 ? '' : 's'} ` +
|
|
99
|
-
`behind ${marker.branch} — run 'agents repo pull ${marker.alias}' to update.\n`);
|
|
100
|
-
try {
|
|
101
|
-
fs.unlinkSync(file);
|
|
102
|
-
}
|
|
103
|
-
catch { /* ignore */ }
|
|
97
|
+
result.push(marker);
|
|
104
98
|
}
|
|
99
|
+
return result;
|
|
105
100
|
}
|
|
@@ -14,6 +14,7 @@ import { clickAtCoords, hoverAtCoords, scrollAtCoords, typeText, pressKey, focus
|
|
|
14
14
|
import { typeEditorText } from './editor.js';
|
|
15
15
|
import { detectUploadPattern, stageUploadFile, uploadToDropTarget, uploadToFileInput, uploadViaFileChooser, } from './upload.js';
|
|
16
16
|
import { emit } from '../events.js';
|
|
17
|
+
import { resolveActor } from '../actor.js';
|
|
17
18
|
import { sshExecAsync } from '../ssh-exec.js';
|
|
18
19
|
function isPathInside(candidate, dir) {
|
|
19
20
|
const rel = path.relative(dir, candidate);
|
|
@@ -331,6 +332,7 @@ export class BrowserService {
|
|
|
331
332
|
currentTabId: undefined,
|
|
332
333
|
createdAt: Date.now(),
|
|
333
334
|
pid: conn.pid,
|
|
335
|
+
owner: resolveActor().id, // who launched this browser task (RUSH-2020)
|
|
334
336
|
};
|
|
335
337
|
// For Electron, get the existing window as the tab
|
|
336
338
|
if (conn.electron) {
|
|
@@ -2012,6 +2014,7 @@ export class BrowserService {
|
|
|
2012
2014
|
endedAt: Date.now(),
|
|
2013
2015
|
domains,
|
|
2014
2016
|
tabCount: Object.keys(task.tabs).length,
|
|
2017
|
+
...(task.owner ? { owner: task.owner } : {}), // carry who launched it (RUSH-2020)
|
|
2015
2018
|
});
|
|
2016
2019
|
// Keep only last 50 entries
|
|
2017
2020
|
history = history.slice(0, 50);
|
|
@@ -78,6 +78,11 @@ export interface Task {
|
|
|
78
78
|
currentTabId?: string;
|
|
79
79
|
createdAt: number;
|
|
80
80
|
pid: number;
|
|
81
|
+
/**
|
|
82
|
+
* Resolved actor id (`resolveActor().id`) stamped at task start — who launched
|
|
83
|
+
* this browser task. Optional: tasks persisted before RUSH-2020 carry none.
|
|
84
|
+
*/
|
|
85
|
+
owner?: string;
|
|
81
86
|
/**
|
|
82
87
|
* Per-tab snapshot of the last ref listing captured for that tab
|
|
83
88
|
* (shortId -> {descriptors, opts}). Persisted to tasks.json so a later
|
|
@@ -126,6 +131,8 @@ export interface HistoricalTask {
|
|
|
126
131
|
endedAt: number;
|
|
127
132
|
domains: string[];
|
|
128
133
|
tabCount: number;
|
|
134
|
+
/** Actor id who launched the task (RUSH-2020); absent for pre-RUSH-2020 history. */
|
|
135
|
+
owner?: string;
|
|
129
136
|
}
|
|
130
137
|
export type IPCAction = 'start' | 'record-start' | 'record-stop' | 'done' | 'stop' | 'status' | 'history' | 'navigate' | 'tab-add' | 'tab-focus' | 'tab-close' | 'tab-list' | 'evaluate' | 'screenshot' | 'pdf' | 'refs' | 'click' | 'type' | 'press' | 'hover' | 'scroll' | 'set-viewport' | 'set-device' | 'console' | 'errors' | 'requests' | 'response-body' | 'wait' | 'set-download-path' | 'wait-download' | 'upload' | 'getAppLogs' | 'version';
|
|
131
138
|
export interface IPCRequest {
|
package/dist/lib/capabilities.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* is below `since`, the install path skips the write and surfaces a clear
|
|
8
8
|
* reason instead of silently corrupting an older binary's settings file.
|
|
9
9
|
*/
|
|
10
|
-
import { AGENTS } from './agents.js';
|
|
10
|
+
import { AGENTS, MANAGED_AGENT_IDS } from './agents.js';
|
|
11
11
|
/**
|
|
12
12
|
* Compare semver-like versions ("0.116.0" vs "0.115.9"). Local copy to avoid
|
|
13
13
|
* importing versions.ts (which imports agents.ts, which imports this file).
|
|
@@ -37,6 +37,8 @@ function getCapability(agent, cap) {
|
|
|
37
37
|
* Useful for filtering UI lists; does not check installed version.
|
|
38
38
|
*/
|
|
39
39
|
export function isCapable(agent, cap) {
|
|
40
|
+
if (AGENTS[agent]?.deprecated?.hard)
|
|
41
|
+
return false;
|
|
40
42
|
const c = getCapability(agent, cap);
|
|
41
43
|
return c !== false;
|
|
42
44
|
}
|
|
@@ -47,6 +49,8 @@ export function isCapable(agent, cap) {
|
|
|
47
49
|
* capable" filters but NOT for install-time gating.
|
|
48
50
|
*/
|
|
49
51
|
export function supports(agent, cap, version) {
|
|
52
|
+
if (AGENTS[agent]?.deprecated?.hard)
|
|
53
|
+
return { ok: false, reason: 'unsupported' };
|
|
50
54
|
const c = getCapability(agent, cap);
|
|
51
55
|
if (c === false)
|
|
52
56
|
return { ok: false, reason: 'unsupported' };
|
|
@@ -78,5 +82,5 @@ export function explainSkip(agent, cap, result, version) {
|
|
|
78
82
|
}
|
|
79
83
|
/** All agents whose `capabilities[cap]` is anything other than `false`. */
|
|
80
84
|
export function capableAgents(cap) {
|
|
81
|
-
return
|
|
85
|
+
return MANAGED_AGENT_IDS.filter((id) => isCapable(id, cap));
|
|
82
86
|
}
|
|
@@ -137,7 +137,7 @@ export function buildBootstrapScript(opts) {
|
|
|
137
137
|
// (leaseAndRun, before this script). Here — after ENSURE_AGENTS_CLI installed
|
|
138
138
|
// the CLI — we materialize that config into the runtime home. Gated by
|
|
139
139
|
// copySetup (cleared for --bare). Best-effort; a refresh failure never aborts.
|
|
140
|
-
copySetup ? [step('copy-setup'), 'agents
|
|
140
|
+
copySetup ? [step('copy-setup'), 'agents sync --local -y >/dev/null 2>&1 || true'].join('\n') : '',
|
|
141
141
|
// Marker on its own line: the command layer shows everything before this as
|
|
142
142
|
// setup progress and everything after (the agent's output) verbatim.
|
|
143
143
|
`echo ${q(LEASE_AGENT_MARKER)}`,
|
|
@@ -176,7 +176,7 @@ export async function leaseAndRun(opts) {
|
|
|
176
176
|
// Setup-copy (F1, RUSH-1920): push the git-tracked ~/.agents config onto the
|
|
177
177
|
// box from the host, over crabbox's own per-lease ssh (a raw ssh fails
|
|
178
178
|
// publickey). rsync only here — the box has no agents-cli yet, so the matching
|
|
179
|
-
// `agents
|
|
179
|
+
// `agents sync --local` runs inside the bootstrap script, after the install
|
|
180
180
|
// step. Best-effort: a copy failure never aborts the run (the agent just runs
|
|
181
181
|
// without the config).
|
|
182
182
|
if (opts.copySetup !== false) {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 2. `rsync` that exact file set to `~/.agents` on the box over crabbox's OWN
|
|
13
13
|
* ssh invocation (`crabboxSshArgv`) — crabbox provisions a per-lease identity
|
|
14
14
|
* key, so a raw `ssh crabbox@ip` fails publickey; only crabbox's key works.
|
|
15
|
-
* 3. `agents
|
|
15
|
+
* 3. `agents sync --local` on the box so the copied config takes effect.
|
|
16
16
|
*
|
|
17
17
|
* NEVER copies `~/.claude` / `~/.claude.json` — they live in `$HOME`, not
|
|
18
18
|
* `~/.agents`, and are rebuilt on the box by `agents add` + refresh; an explicit
|
|
@@ -34,7 +34,7 @@ export interface CopySetupOptions {
|
|
|
34
34
|
/** Receives combined stdout/stderr of the rsync + refresh, if set. */
|
|
35
35
|
onData?: (chunk: string) => void;
|
|
36
36
|
/**
|
|
37
|
-
* Run `agents
|
|
37
|
+
* Run `agents sync --local` on the box after the push (default `true`). Set
|
|
38
38
|
* `false` when the caller runs the refresh itself in the box bootstrap — the
|
|
39
39
|
* lease path does this so the refresh runs AFTER the box installs agents-cli
|
|
40
40
|
* (this host-side push happens before the box boots agents-cli, so a host-side
|
|
@@ -47,7 +47,7 @@ export interface CopySetupResult {
|
|
|
47
47
|
files: string[];
|
|
48
48
|
/** rsync exit code, or null when the process failed to spawn. */
|
|
49
49
|
pushExitCode: number | null;
|
|
50
|
-
/** `agents
|
|
50
|
+
/** `agents sync --local` exit code, or null when it was skipped/failed to spawn. */
|
|
51
51
|
refreshExitCode: number | null;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -80,7 +80,7 @@ export declare function buildSetupRsyncArgs(opts: {
|
|
|
80
80
|
/**
|
|
81
81
|
* Replicate the git-tracked subset of the local `~/.agents` onto the crabbox box
|
|
82
82
|
* and refresh it. Enumerates tracked files, rsyncs them over ssh, then runs
|
|
83
|
-
* `agents
|
|
83
|
+
* `agents sync --local` on the box. Refresh is skipped when the push fails or the
|
|
84
84
|
* file set is empty (nothing to refresh). Never throws — surfaces failure through
|
|
85
85
|
* the returned exit codes.
|
|
86
86
|
*/
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 2. `rsync` that exact file set to `~/.agents` on the box over crabbox's OWN
|
|
13
13
|
* ssh invocation (`crabboxSshArgv`) — crabbox provisions a per-lease identity
|
|
14
14
|
* key, so a raw `ssh crabbox@ip` fails publickey; only crabbox's key works.
|
|
15
|
-
* 3. `agents
|
|
15
|
+
* 3. `agents sync --local` on the box so the copied config takes effect.
|
|
16
16
|
*
|
|
17
17
|
* NEVER copies `~/.claude` / `~/.claude.json` — they live in `$HOME`, not
|
|
18
18
|
* `~/.agents`, and are rebuilt on the box by `agents add` + refresh; an explicit
|
|
@@ -88,7 +88,7 @@ function runStreaming(cmd, args, env, onData) {
|
|
|
88
88
|
/**
|
|
89
89
|
* Replicate the git-tracked subset of the local `~/.agents` onto the crabbox box
|
|
90
90
|
* and refresh it. Enumerates tracked files, rsyncs them over ssh, then runs
|
|
91
|
-
* `agents
|
|
91
|
+
* `agents sync --local` on the box. Refresh is skipped when the push fails or the
|
|
92
92
|
* file set is empty (nothing to refresh). Never throws — surfaces failure through
|
|
93
93
|
* the returned exit codes.
|
|
94
94
|
*/
|
|
@@ -115,8 +115,8 @@ export async function copySetupToBox(opts) {
|
|
|
115
115
|
const pushExitCode = await runStreaming('rsync', rsyncArgs, env, opts.onData);
|
|
116
116
|
let refreshExitCode = null;
|
|
117
117
|
if (pushExitCode === 0 && opts.refresh !== false) {
|
|
118
|
-
// ssh <opts> crabbox@host bash -lc 'agents
|
|
119
|
-
const refreshArgs = [...sshArgv.slice(1), 'bash', '-lc', 'agents
|
|
118
|
+
// ssh <opts> crabbox@host bash -lc 'agents sync --local -y'
|
|
119
|
+
const refreshArgs = [...sshArgv.slice(1), 'bash', '-lc', 'agents sync --local -y'];
|
|
120
120
|
refreshExitCode = await runStreaming('ssh', refreshArgs, env, opts.onData);
|
|
121
121
|
}
|
|
122
122
|
return { files, pushExitCode, refreshExitCode };
|