@phnx-labs/agents-cli 1.22.84 → 1.22.85
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 +57 -0
- package/README.md +80 -53
- package/dist/bootstrap.d.ts +7 -6
- package/dist/bootstrap.js +20 -27
- package/dist/cli/command-registry.js +5 -1
- package/dist/commands/accounts.d.ts +6 -13
- package/dist/commands/accounts.js +330 -143
- package/dist/commands/apply.js +1 -1
- package/dist/commands/auth-mint.d.ts +7 -3
- package/dist/commands/auth-mint.js +21 -9
- package/dist/commands/auth.js +2 -3
- package/dist/commands/browser.js +10 -10
- package/dist/commands/daemon.d.ts +7 -3
- package/dist/commands/daemon.js +40 -25
- package/dist/commands/doctor.js +28 -2
- package/dist/commands/exec.js +87 -39
- package/dist/commands/fleet-capture.js +21 -2
- package/dist/commands/harness-wizard.js +2 -2
- package/dist/commands/lease.js +7 -12
- package/dist/commands/profiles.d.ts +2 -2
- package/dist/commands/profiles.js +20 -13
- package/dist/commands/repo.js +3 -3
- package/dist/commands/run-account-picker.d.ts +3 -3
- package/dist/commands/run-account-picker.js +29 -30
- package/dist/commands/secrets-passthrough.d.ts +20 -0
- package/dist/commands/secrets-passthrough.js +43 -0
- package/dist/commands/setup-accounts.d.ts +3 -2
- package/dist/commands/setup-accounts.js +4 -4
- package/dist/commands/setup-secrets.d.ts +16 -21
- package/dist/commands/setup-secrets.js +43 -224
- package/dist/commands/ssh.js +2 -2
- package/dist/commands/sync.js +1 -1
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.js +43 -40
- package/dist/commands/versions.d.ts +11 -11
- package/dist/commands/versions.js +131 -83
- package/dist/commands/view.d.ts +1 -9
- package/dist/commands/view.js +41 -55
- package/dist/commands/webhook.js +5 -5
- package/dist/commands/workflows.js +2 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +13 -42
- package/dist/lib/account-capabilities.d.ts +1 -1
- package/dist/lib/account-capabilities.js +1 -1
- package/dist/lib/account-catalog.d.ts +121 -6
- package/dist/lib/account-catalog.js +421 -7
- package/dist/lib/account-registry.d.ts +8 -30
- package/dist/lib/account-registry.js +36 -79
- package/dist/lib/account-schema.d.ts +1 -1
- package/dist/lib/account-schema.js +1 -1
- package/dist/lib/accounting/account-pool-collect.js +16 -4
- package/dist/lib/accounting/rotate.d.ts +20 -7
- package/dist/lib/accounting/rotate.js +89 -13
- package/dist/lib/accounting/usage.js +11 -16
- package/dist/lib/accounts/add.d.ts +138 -0
- package/dist/lib/accounts/add.js +651 -0
- package/dist/lib/accounts/migrate.d.ts +117 -0
- package/dist/lib/accounts/migrate.js +536 -0
- package/dist/lib/accounts/slots.d.ts +13 -0
- package/dist/lib/accounts/slots.js +100 -0
- package/dist/lib/agent-spec/agents.d.ts +16 -0
- package/dist/lib/agent-spec/agents.js +32 -4
- package/dist/lib/app-bundle-install.js +5 -4
- package/dist/lib/auth-health.d.ts +3 -0
- package/dist/lib/auth-health.js +11 -0
- package/dist/lib/auth-mint.d.ts +52 -16
- package/dist/lib/auth-mint.js +117 -39
- package/dist/lib/browser/chrome.d.ts +1 -1
- package/dist/lib/browser/chrome.js +5 -5
- package/dist/lib/byok-usage.js +3 -3
- package/dist/lib/claude-account-token.d.ts +47 -3
- package/dist/lib/claude-account-token.js +172 -50
- package/dist/lib/cloud/antigravity.js +4 -4
- package/dist/lib/cloud/cursor.js +4 -4
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +6 -6
- package/dist/lib/crabbox/runtimes.d.ts +3 -3
- package/dist/lib/crabbox/runtimes.js +5 -5
- package/dist/lib/daemon/account-state-daemon-service.d.ts +37 -1
- package/dist/lib/daemon/account-state-daemon-service.js +199 -3
- package/dist/lib/daemon/auth-sync-service.js +28 -1
- package/dist/lib/daemon/daemon.d.ts +6 -16
- package/dist/lib/daemon/daemon.js +52 -97
- package/dist/lib/daemon/daemon.test-fixture.d.ts +7 -9
- package/dist/lib/daemon/daemon.test-fixture.js +22 -40
- package/dist/lib/daemon/harness-update-service.d.ts +1 -1
- package/dist/lib/daemon/harness-update-service.js +1 -1
- package/dist/lib/daemon/runner.d.ts +15 -3
- package/dist/lib/daemon/runner.js +49 -24
- package/dist/lib/daemon-health.d.ts +1 -2
- package/dist/lib/daemon-health.js +7 -6
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +1 -11
- package/dist/lib/daemon-webhooks.d.ts +8 -7
- package/dist/lib/daemon-webhooks.js +10 -9
- package/dist/lib/device-config.js +1 -1
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/harness-inventory.d.ts +39 -0
- package/dist/lib/devices/harness-inventory.js +126 -4
- package/dist/lib/doctor-diff.js +2 -1
- package/dist/lib/exec-account-home.d.ts +38 -0
- package/dist/lib/exec-account-home.js +164 -0
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +101 -31
- package/dist/lib/fleet/apply.d.ts +2 -2
- package/dist/lib/fleet/apply.js +4 -4
- package/dist/lib/fleet/auth-sync.js +4 -3
- package/dist/lib/fleet-shared-repo-sync.js +6 -9
- package/dist/lib/harness/adapter.d.ts +7 -7
- package/dist/lib/harness/adapter.js +10 -6
- package/dist/lib/harness/adapters/grok.js +8 -3
- package/dist/lib/harness/adapters/muse.js +1 -1
- package/dist/lib/harness/adapters/opencode.js +12 -3
- package/dist/lib/harness-auth-capabilities.d.ts +61 -0
- package/dist/lib/harness-auth-capabilities.js +52 -0
- package/dist/lib/helper-versions.d.ts +6 -4
- package/dist/lib/helper-versions.js +5 -4
- package/dist/lib/hosts/credential-transport.d.ts +10 -0
- package/dist/lib/hosts/credential-transport.js +37 -0
- package/dist/lib/hosts/dispatch.d.ts +7 -0
- package/dist/lib/hosts/dispatch.js +13 -6
- package/dist/lib/identity/client.d.ts +3 -3
- package/dist/lib/identity/client.js +3 -3
- package/dist/lib/installations/index.d.ts +1 -1
- package/dist/lib/installations/index.js +1 -1
- package/dist/lib/installations/migrate.js +9 -0
- package/dist/lib/installations/resolve.js +1 -1
- package/dist/lib/installations/shims.d.ts +15 -0
- package/dist/lib/installations/shims.js +69 -0
- package/dist/lib/installations/store.d.ts +43 -0
- package/dist/lib/installations/store.js +75 -7
- package/dist/lib/installations/versions.js +1 -1
- package/dist/lib/menubar/install-menubar.d.ts +3 -3
- package/dist/lib/menubar/install-menubar.js +3 -3
- package/dist/lib/native-accounts.d.ts +35 -0
- package/dist/lib/native-accounts.js +41 -0
- package/dist/lib/net-close.d.ts +11 -0
- package/dist/lib/net-close.js +25 -0
- package/dist/lib/openclaw-keychain.js +27 -1
- package/dist/lib/profiles.js +22 -9
- package/dist/lib/project-resources.js +1 -1
- package/dist/lib/reserved-stores.d.ts +53 -0
- package/dist/lib/reserved-stores.js +120 -0
- package/dist/lib/secrets-client.d.ts +191 -0
- package/dist/lib/secrets-client.js +710 -0
- package/dist/lib/secrets-policy.d.ts +222 -0
- package/dist/lib/secrets-policy.js +483 -0
- package/dist/lib/secrets-types.d.ts +188 -0
- package/dist/lib/secrets-types.js +24 -0
- package/dist/lib/service-manifest.js +3 -4
- package/dist/lib/session/db.d.ts +18 -0
- package/dist/lib/session/db.js +47 -14
- package/dist/lib/session/sync/config.js +2 -2
- package/dist/lib/sha256-asset.d.ts +11 -16
- package/dist/lib/sha256-asset.js +11 -16
- package/dist/lib/share/config.js +14 -5
- package/dist/lib/signin-badge.d.ts +26 -0
- package/dist/lib/signin-badge.js +42 -0
- package/dist/lib/staleness/detectors/workflows.js +3 -105
- package/dist/lib/staleness/writers/workflows.js +2 -1
- package/dist/lib/state.d.ts +7 -4
- package/dist/lib/state.js +18 -7
- package/dist/lib/sync-umbrella.js +2 -2
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/types.d.ts +74 -33
- package/dist/lib/view-types.d.ts +6 -3
- package/dist/lib/workflows-registry.d.ts +71 -0
- package/dist/lib/workflows-registry.js +280 -0
- package/dist/lib/workflows.d.ts +21 -21
- package/dist/lib/workflows.js +12 -327
- package/package.json +2 -3
- package/scripts/postinstall.js +4 -29
- package/dist/commands/secrets-import.d.ts +0 -18
- package/dist/commands/secrets-import.js +0 -74
- package/dist/commands/secrets-migrate.d.ts +0 -25
- package/dist/commands/secrets-migrate.js +0 -334
- package/dist/commands/secrets-rotate-passphrase.d.ts +0 -17
- package/dist/commands/secrets-rotate-passphrase.js +0 -96
- package/dist/commands/secrets-sync.d.ts +0 -11
- package/dist/commands/secrets-sync.js +0 -153
- package/dist/commands/secrets-vault.d.ts +0 -10
- package/dist/commands/secrets-vault.js +0 -130
- package/dist/commands/secrets.d.ts +0 -212
- package/dist/commands/secrets.js +0 -3030
- package/dist/lib/accounts/connect.d.ts +0 -176
- package/dist/lib/accounts/connect.js +0 -453
- package/dist/lib/daemon/keychain-reap-service.d.ts +0 -17
- package/dist/lib/daemon/keychain-reap-service.js +0 -32
- package/dist/lib/daemon/secrets-broker-service.d.ts +0 -21
- package/dist/lib/daemon/secrets-broker-service.js +0 -51
- package/dist/lib/secrets/agent.d.ts +0 -358
- package/dist/lib/secrets/agent.js +0 -1291
- package/dist/lib/secrets/audit.d.ts +0 -46
- package/dist/lib/secrets/audit.js +0 -101
- package/dist/lib/secrets/bundles.d.ts +0 -290
- package/dist/lib/secrets/bundles.js +0 -1547
- package/dist/lib/secrets/download-keychain.d.ts +0 -47
- package/dist/lib/secrets/download-keychain.js +0 -70
- package/dist/lib/secrets/drivers/rush.d.ts +0 -14
- package/dist/lib/secrets/drivers/rush.js +0 -90
- package/dist/lib/secrets/fallback.d.ts +0 -48
- package/dist/lib/secrets/fallback.js +0 -48
- package/dist/lib/secrets/filestore.d.ts +0 -222
- package/dist/lib/secrets/filestore.js +0 -1099
- package/dist/lib/secrets/headless.d.ts +0 -43
- package/dist/lib/secrets/headless.js +0 -56
- package/dist/lib/secrets/icloud-import.d.ts +0 -79
- package/dist/lib/secrets/icloud-import.js +0 -206
- package/dist/lib/secrets/index.d.ts +0 -451
- package/dist/lib/secrets/index.js +0 -1568
- package/dist/lib/secrets/install-helper.d.ts +0 -72
- package/dist/lib/secrets/install-helper.js +0 -245
- package/dist/lib/secrets/lease.d.ts +0 -25
- package/dist/lib/secrets/lease.js +0 -44
- package/dist/lib/secrets/linux.d.ts +0 -77
- package/dist/lib/secrets/linux.js +0 -393
- package/dist/lib/secrets/list-filter.d.ts +0 -109
- package/dist/lib/secrets/list-filter.js +0 -261
- package/dist/lib/secrets/mcp.d.ts +0 -93
- package/dist/lib/secrets/mcp.js +0 -211
- package/dist/lib/secrets/profiles.d.ts +0 -10
- package/dist/lib/secrets/profiles.js +0 -13
- package/dist/lib/secrets/push.d.ts +0 -133
- package/dist/lib/secrets/push.js +0 -273
- package/dist/lib/secrets/rc-hygiene.d.ts +0 -63
- package/dist/lib/secrets/rc-hygiene.js +0 -143
- package/dist/lib/secrets/read-backoff.d.ts +0 -27
- package/dist/lib/secrets/read-backoff.js +0 -64
- package/dist/lib/secrets/reaper.d.ts +0 -90
- package/dist/lib/secrets/reaper.js +0 -243
- package/dist/lib/secrets/remote.d.ts +0 -152
- package/dist/lib/secrets/remote.js +0 -344
- package/dist/lib/secrets/reserved-sync.d.ts +0 -66
- package/dist/lib/secrets/reserved-sync.js +0 -147
- package/dist/lib/secrets/scope.d.ts +0 -26
- package/dist/lib/secrets/scope.js +0 -29
- package/dist/lib/secrets/session-store.d.ts +0 -107
- package/dist/lib/secrets/session-store.js +0 -342
- package/dist/lib/secrets/sync-backend.d.ts +0 -48
- package/dist/lib/secrets/sync-backend.js +0 -13
- package/dist/lib/secrets/sync-commands.d.ts +0 -21
- package/dist/lib/secrets/sync-commands.js +0 -21
- package/dist/lib/secrets/sync.d.ts +0 -48
- package/dist/lib/secrets/sync.js +0 -237
- package/dist/lib/secrets/unlock-hints.d.ts +0 -27
- package/dist/lib/secrets/unlock-hints.js +0 -36
- package/dist/lib/secrets/usage-db.d.ts +0 -46
- package/dist/lib/secrets/usage-db.js +0 -96
- package/dist/lib/secrets/vault-age-helper.d.ts +0 -1
- package/dist/lib/secrets/vault-age-helper.js +0 -34
- package/dist/lib/secrets/vault.d.ts +0 -49
- package/dist/lib/secrets/vault.js +0 -399
- package/dist/lib/secrets/windows.d.ts +0 -81
- package/dist/lib/secrets/windows.js +0 -556
- package/scripts/install-helper.js +0 -97
- /package/dist/lib/{secrets/sync-passphrase.d.ts → sync-passphrase.d.ts} +0 -0
- /package/dist/lib/{secrets/sync-passphrase.js → sync-passphrase.js} +0 -0
package/dist/commands/apply.js
CHANGED
|
@@ -18,7 +18,7 @@ import { isHostPinned, isDevicePinned, managedKnownHostsPath } from '../lib/devi
|
|
|
18
18
|
import { ensureDevicesRegistered } from '../lib/devices/sync.js';
|
|
19
19
|
import { readFleetFile, resolveDesired, emptyTargetsMessage } from '../lib/fleet/manifest.js';
|
|
20
20
|
import { snapshotAuth } from '../lib/fleet/auth-sync.js';
|
|
21
|
-
import { AUTH_BUNDLE_NAME } from '../lib/secrets
|
|
21
|
+
import { AUTH_BUNDLE_NAME } from '../lib/secrets-policy.js';
|
|
22
22
|
import { agentIdOf, diffFleet, probeDevice, runFleetApply, pool, sourceHome, expandAllSpecs, rosterNeedsVersions, fleetSecretsBundles, } from '../lib/fleet/apply.js';
|
|
23
23
|
import { listInstalledVersions } from '../lib/installations/versions.js';
|
|
24
24
|
/** Version of the running agents-cli — the fleet target version. */
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared `mint` subcommand registered on both `agents auth` (the ticket
|
|
3
|
-
* surface) and `agents accounts` (the credential noun).
|
|
4
|
-
*
|
|
3
|
+
* surface) and `agents accounts` (the credential noun). Hidden on both:
|
|
4
|
+
* `agents accounts add <harness> [name]` / `agents accounts login <harness>#<name>`
|
|
5
|
+
* is the taught path. Implementation lives in lib/auth-mint.ts so neither
|
|
6
|
+
* command file owns the seed path.
|
|
5
7
|
*/
|
|
6
8
|
import type { Command } from 'commander';
|
|
7
9
|
import { type MintDriveHooks } from '../lib/auth-mint.js';
|
|
8
|
-
export declare function registerMintCommand(parent: Command, testHooks?: MintDriveHooks
|
|
10
|
+
export declare function registerMintCommand(parent: Command, testHooks?: MintDriveHooks, opts?: {
|
|
11
|
+
hidden?: boolean;
|
|
12
|
+
}): Command;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `mint` subcommand registered on both `agents auth` (the ticket
|
|
3
|
+
* surface) and `agents accounts` (the credential noun). Hidden on both:
|
|
4
|
+
* `agents accounts add <harness> [name]` / `agents accounts login <harness>#<name>`
|
|
5
|
+
* is the taught path. Implementation lives in lib/auth-mint.ts so neither
|
|
6
|
+
* command file owns the seed path.
|
|
7
|
+
*/
|
|
1
8
|
import chalk from 'chalk';
|
|
2
9
|
import { setHelpSections } from '../lib/help.js';
|
|
3
10
|
import { readStdinSync, runOrDie } from '../lib/format.js';
|
|
4
11
|
import { isInteractiveTerminal } from './utils.js';
|
|
5
12
|
import { getMintFlow, listMintableHarnesses, mintAndSeed, } from '../lib/auth-mint.js';
|
|
13
|
+
const MINT_POINTER = 'agents accounts add <harness> [name] / agents accounts login <harness>#<name>';
|
|
6
14
|
function collect(value, previous) {
|
|
7
15
|
return [...previous, value];
|
|
8
16
|
}
|
|
@@ -28,9 +36,10 @@ function printResult(result, json) {
|
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
|
-
export function registerMintCommand(parent, testHooks) {
|
|
39
|
+
export function registerMintCommand(parent, testHooks, opts) {
|
|
40
|
+
const hidden = opts?.hidden ?? true;
|
|
32
41
|
const mint = parent
|
|
33
|
-
.command('mint <harness>')
|
|
42
|
+
.command('mint <harness>', { hidden })
|
|
34
43
|
.description('Mint a long-lived setup-token and seed it as a named account')
|
|
35
44
|
.option('--account <name-or-email>', 'Named account to create/rotate, or the account email')
|
|
36
45
|
.option('--email <email>', 'Email that keys the reserved auth bundle when --account is a name')
|
|
@@ -78,19 +87,22 @@ export function registerMintCommand(parent, testHooks) {
|
|
|
78
87
|
printResult(result, json);
|
|
79
88
|
}, { json });
|
|
80
89
|
});
|
|
90
|
+
if (hidden) {
|
|
91
|
+
mint.hook('preAction', () => {
|
|
92
|
+
console.error(chalk.gray(`'agents ${parent.name()} mint' is a hidden alias; use \`${MINT_POINTER}\` — still works this release.`));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
81
95
|
setHelpSections(mint, {
|
|
82
|
-
examples: `agents accounts
|
|
83
|
-
agents accounts
|
|
84
|
-
agents accounts mint claude --account work --email ada@example.com
|
|
96
|
+
examples: `agents accounts add claude work
|
|
97
|
+
agents accounts login claude#work
|
|
85
98
|
agents accounts mint claude --token-stdin < token.txt
|
|
86
99
|
agents accounts mint claude --code AUTHCODE --json
|
|
87
|
-
agents accounts mint claude --fleet
|
|
88
|
-
agents
|
|
89
|
-
notes: `Claude is the only harness with an interactive long-lived setup-token (\`claude setup-token\`, ~1 year, shareable across machines). The command drives that flow in a PTY, opens the authorize URL, captures a well-formed sk-ant-oat01- token (refusing the #1767 TTY-banner capture), and seeds:
|
|
100
|
+
agents accounts mint claude --fleet`,
|
|
101
|
+
notes: `Hidden alias of the worker-credential step that \`agents accounts add <harness> [name]\` (mint during add) and \`agents accounts login <harness>#<name>\` (re-mint) now own. Claude is the only harness with an interactive long-lived setup-token (\`claude setup-token\`, ~1 year, shareable across machines). The command drives that flow in a PTY, opens the authorize URL, captures a well-formed sk-ant-oat01- token (refusing the #1767 TTY-banner capture), and seeds:
|
|
90
102
|
1. a named provider account (policy never) for \`agents run --account\` / \`agents accounts sync\`
|
|
91
103
|
2. the reserved FILE-BASED auth bundle keyed per email, which usage/probe reads
|
|
92
104
|
Native rotating OAuth is never copied. Other harnesses fail loud: device-code login is \`agents fleet login\`; API keys are \`agents accounts add\`.
|
|
93
|
-
Already have a token? \`--token-stdin\` skips the browser dance. \`agents auth mint\`
|
|
105
|
+
Already have a token? \`--token-stdin\` skips the browser dance. \`agents auth mint\` and \`agents accounts mint\` are the same hidden command.`,
|
|
94
106
|
});
|
|
95
107
|
return mint;
|
|
96
108
|
}
|
package/dist/commands/auth.js
CHANGED
|
@@ -105,7 +105,6 @@ export function registerAuthCommand(program) {
|
|
|
105
105
|
setHelpSections(auth, {
|
|
106
106
|
examples: `agents auth login # device-code sign-in via your browser
|
|
107
107
|
agents auth whoami # who this machine is signed in as
|
|
108
|
-
agents auth mint claude # mint a Claude setup-token into a named account
|
|
109
108
|
agents auth space create "Design Team" # start a space
|
|
110
109
|
agents auth space invite ada@example.com # add a teammate
|
|
111
110
|
agents auth logout # clear this machine only`,
|
|
@@ -113,7 +112,7 @@ agents auth logout # clear this machine only`,
|
|
|
113
112
|
Sign-in is Google-only and opens a Phoenix-branded page; the CLI never sees a password.
|
|
114
113
|
The session lives in this machine's agents state dir, so logging out here signs out nothing else.
|
|
115
114
|
Point at a different backend with PHOENIX_ID_BASE (defaults to the production service).
|
|
116
|
-
|
|
115
|
+
Harness worker credentials are minted by \`agents accounts add <harness> [name]\` / \`agents accounts login <harness>#<name>\`, not by this command.`,
|
|
117
116
|
});
|
|
118
117
|
auth
|
|
119
118
|
.command('login')
|
|
@@ -127,7 +126,7 @@ Point at a different backend with PHOENIX_ID_BASE (defaults to the production se
|
|
|
127
126
|
const json = !!o.json || !!command.optsWithGlobals().json;
|
|
128
127
|
return runOrDie(() => whoami(json), { json });
|
|
129
128
|
});
|
|
130
|
-
registerMintCommand(auth);
|
|
129
|
+
registerMintCommand(auth, undefined, { hidden: true });
|
|
131
130
|
auth
|
|
132
131
|
.command('logout')
|
|
133
132
|
.description("Clear this machine's session (no other device is affected)")
|
package/dist/commands/browser.js
CHANGED
|
@@ -8,7 +8,7 @@ import { declaringDevices, migrateCentralBrowserProfiles, profileKind } from '..
|
|
|
8
8
|
import { resolveActor } from '../lib/actor.js';
|
|
9
9
|
import { loginsForProfile, profilesLoggedInto, serviceForUrl, loginsWithAccountsForProfile, accountsForProfile, credKeysForService, AUTH_SIGNATURES, } from '../lib/browser/login-detection.js';
|
|
10
10
|
import { parseSecretRef } from '../lib/browser/secret-ref.js';
|
|
11
|
-
import { readAndResolveBundleEnv, bundleExists, readBundle
|
|
11
|
+
import { readAndResolveBundleEnv, bundleExists, readBundle } from '../lib/secrets-client.js';
|
|
12
12
|
import { findBrowserPath, getPortOccupant, getProcessUserDataDir, isLauncherScript, listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
13
13
|
import { listProfileCacheDirs, removeProfileCache, listAllProfileSnapshots, buildProfilePrunePlan, pruneProfiles, PRUNE_REASON_TEXT, identityLoopbackMismatch, } from '../lib/browser/runtime-state.js';
|
|
14
14
|
import { DEFAULT_VIEWPORT, parseWindowSize, parseWindowPosition } from '../lib/browser/devices.js';
|
|
@@ -452,16 +452,16 @@ function registerBrowserUseCommand(browser) {
|
|
|
452
452
|
* keys exist, '-' when not, or '(unknown)' if the metadata read would prompt or
|
|
453
453
|
* fails — the view must never block on Touch ID.
|
|
454
454
|
*/
|
|
455
|
-
function credAvailability(bundleName, service) {
|
|
455
|
+
async function credAvailability(bundleName, service) {
|
|
456
456
|
if (!bundleName)
|
|
457
457
|
return '-';
|
|
458
458
|
const keys = credKeysForService(service);
|
|
459
459
|
if (!keys)
|
|
460
460
|
return '-';
|
|
461
461
|
try {
|
|
462
|
-
if (!bundleExists(bundleName))
|
|
462
|
+
if (!(await bundleExists(bundleName)))
|
|
463
463
|
return '-';
|
|
464
|
-
const present = new Set(
|
|
464
|
+
const present = new Set(Object.keys((await readBundle(bundleName)).vars));
|
|
465
465
|
return present.has(keys.user) && present.has(keys.pass) ? bundleName : '-';
|
|
466
466
|
}
|
|
467
467
|
catch {
|
|
@@ -590,7 +590,7 @@ function registerProfilesCommands(browser) {
|
|
|
590
590
|
console.log(name.padEnd(20) +
|
|
591
591
|
r.service.padEnd(12) +
|
|
592
592
|
(r.username ?? '(unknown)').padEnd(32) +
|
|
593
|
-
credAvailability(p.secrets, r.service));
|
|
593
|
+
(await credAvailability(p.secrets, r.service)));
|
|
594
594
|
first = false;
|
|
595
595
|
}
|
|
596
596
|
}
|
|
@@ -712,7 +712,7 @@ function registerProfilesCommands(browser) {
|
|
|
712
712
|
}
|
|
713
713
|
// Warn (don't fail) if the declared secrets bundle doesn't exist yet — it
|
|
714
714
|
// may be created later, but a typo should surface now.
|
|
715
|
-
if (opts.secrets && !bundleExists(opts.secrets)) {
|
|
715
|
+
if (opts.secrets && !(await bundleExists(opts.secrets))) {
|
|
716
716
|
console.error(`warning: secrets bundle "${opts.secrets}" does not exist yet. Create it with: agents secrets create ${opts.secrets}`);
|
|
717
717
|
}
|
|
718
718
|
});
|
|
@@ -847,7 +847,7 @@ function registerProfilesCommands(browser) {
|
|
|
847
847
|
else {
|
|
848
848
|
console.log(`Updated ${name} on ${machineId()}: ${result.changed.join(', ')}`);
|
|
849
849
|
}
|
|
850
|
-
if (patch.secrets && !bundleExists(patch.secrets)) {
|
|
850
|
+
if (patch.secrets && !(await bundleExists(patch.secrets))) {
|
|
851
851
|
console.error(`warning: secrets bundle "${patch.secrets}" does not exist yet. Create it with: agents secrets create ${patch.secrets}`);
|
|
852
852
|
}
|
|
853
853
|
});
|
|
@@ -957,7 +957,7 @@ function registerProfilesCommands(browser) {
|
|
|
957
957
|
const lines = [];
|
|
958
958
|
for (const service of Object.keys(AUTH_SIGNATURES)) {
|
|
959
959
|
const isActive = active.includes(service);
|
|
960
|
-
const creds = credAvailability(profile.secrets, service);
|
|
960
|
+
const creds = await credAvailability(profile.secrets, service);
|
|
961
961
|
if (!isActive && creds === '-')
|
|
962
962
|
continue; // nothing interesting to show
|
|
963
963
|
const status = isActive
|
|
@@ -2661,12 +2661,12 @@ function registerTaskCommands(browser) {
|
|
|
2661
2661
|
console.error(`--secret must be <bundle>/<KEY>, got: ${opts.secret}`);
|
|
2662
2662
|
process.exit(1);
|
|
2663
2663
|
}
|
|
2664
|
-
if (!bundleExists(parsed.bundle)) {
|
|
2664
|
+
if (!(await bundleExists(parsed.bundle))) {
|
|
2665
2665
|
console.error(`Secrets bundle "${parsed.bundle}" not found.`);
|
|
2666
2666
|
process.exit(1);
|
|
2667
2667
|
}
|
|
2668
2668
|
try {
|
|
2669
|
-
const { env } = readAndResolveBundleEnv(parsed.bundle, { caller: 'browser type', keys: [parsed.key], keyMode: 'storage', agentOnly: true });
|
|
2669
|
+
const { env } = await readAndResolveBundleEnv(parsed.bundle, { caller: 'browser type', keys: [parsed.key], keyMode: 'storage', agentOnly: true });
|
|
2670
2670
|
if (!(parsed.key in env)) {
|
|
2671
2671
|
console.error(`Key "${parsed.key}" not in bundle "${parsed.bundle}".`);
|
|
2672
2672
|
process.exit(1);
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* `agents daemon` — runtime, hosted services, and failure visibility for the
|
|
3
3
|
* always-on daemon (RUSH-2354).
|
|
4
4
|
*
|
|
5
|
-
* The daemon holds the routines scheduler, the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The daemon holds the routines scheduler, the browser IPC server, and the
|
|
6
|
+
* watchdog pass — but until this command group existed it had no user-facing
|
|
7
|
+
* surface: no way to see it, restart it, or turn it off. The secrets broker
|
|
8
|
+
* moved out of this daemon entirely with the standalone `secrets` engine
|
|
9
|
+
* (PHNX-3989 OWN-1); `agents daemon status` only probes its reachability.
|
|
8
10
|
* `daemon.ts` (the runtime) has always implemented every mechanism this file
|
|
9
11
|
* wires up; nothing here is new machinery, only the missing CLI surface.
|
|
10
12
|
*
|
|
@@ -16,6 +18,8 @@
|
|
|
16
18
|
*/
|
|
17
19
|
import type { Command } from 'commander';
|
|
18
20
|
import { type DaemonServiceId } from '../lib/daemon-services.js';
|
|
21
|
+
/** Parse a `ps -o etime=` value (`[[dd-]hh:]mm:ss`) into elapsed seconds. */
|
|
22
|
+
export declare function parseEtimeToSeconds(raw: string): number | null;
|
|
19
23
|
/** Elapsed wall-clock seconds since `pid` started, or null if unavailable (best-effort, POSIX only). */
|
|
20
24
|
export declare function uptimeSeconds(pid: number): number | null;
|
|
21
25
|
/** One row of the roster every registered daemon service — supervisor-managed or legacy — renders in `agents daemon services`. */
|
package/dist/commands/daemon.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* `agents daemon` — runtime, hosted services, and failure visibility for the
|
|
3
3
|
* always-on daemon (RUSH-2354).
|
|
4
4
|
*
|
|
5
|
-
* The daemon holds the routines scheduler, the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The daemon holds the routines scheduler, the browser IPC server, and the
|
|
6
|
+
* watchdog pass — but until this command group existed it had no user-facing
|
|
7
|
+
* surface: no way to see it, restart it, or turn it off. The secrets broker
|
|
8
|
+
* moved out of this daemon entirely with the standalone `secrets` engine
|
|
9
|
+
* (PHNX-3989 OWN-1); `agents daemon status` only probes its reachability.
|
|
8
10
|
* `daemon.ts` (the runtime) has always implemented every mechanism this file
|
|
9
11
|
* wires up; nothing here is new machinery, only the missing CLI surface.
|
|
10
12
|
*
|
|
@@ -21,7 +23,7 @@ import * as path from 'path';
|
|
|
21
23
|
import { setHelpSections } from '../lib/help.js';
|
|
22
24
|
import { getDaemonStatus, isDaemonRunning, isDaemonWedged, readDaemonLog, startDaemon, stopDaemon, signalDaemonReload, findSurvivingStateDirDaemons, getDaemonLogPath, isDaemonAutostartCircuitOpen, } from '../lib/daemon/daemon.js';
|
|
23
25
|
import { getConfigValue, setConfigValue, isDaemonEnabled } from '../lib/device-config.js';
|
|
24
|
-
import { readSubsystemHealth, readAllSubsystemHealth,
|
|
26
|
+
import { readSubsystemHealth, readAllSubsystemHealth, SUBSYSTEM_BROWSER_IPC, SUBSYSTEM_DAEMON_START, } from '../lib/daemon-health.js';
|
|
25
27
|
import { DAEMON_SERVICE_IDS, listDaemonServiceStates, setDaemonServiceEnabled, getDaemonServicesConfigPath, queueDaemonServiceRestart, } from '../lib/daemon-services.js';
|
|
26
28
|
import { listJobs, getLatestRun } from '../lib/scheduling/routines.js';
|
|
27
29
|
import { JobScheduler } from '../lib/scheduler.js';
|
|
@@ -30,7 +32,6 @@ import { parseDuration } from '../lib/hooks/cache.js';
|
|
|
30
32
|
import { registerFunnelCommand } from './funnel.js';
|
|
31
33
|
import { DEFAULT_WEBHOOK_PORT, DEFAULT_WEBHOOK_RATE_LIMIT, addHostedReceiver, getDaemonWebhooksConfigPath, hostedReceiverPort, readDaemonWebhooksConfig, removeHostedReceiver, } from '../lib/daemon-webhooks.js';
|
|
32
34
|
import { parseFunnelPort } from '../lib/funnel.js';
|
|
33
|
-
import { parseEtimeToSeconds } from '../lib/secrets/reaper.js';
|
|
34
35
|
/**
|
|
35
36
|
* Provably absent, or null when unknowable.
|
|
36
37
|
*
|
|
@@ -256,6 +257,19 @@ function registryScopedDuplicates(processes, ownerPid) {
|
|
|
256
257
|
const registered = new Set(findSurvivingStateDirDaemons(exclude));
|
|
257
258
|
return processes.filter((p) => registered.has(p.pid));
|
|
258
259
|
}
|
|
260
|
+
/** Parse a `ps -o etime=` value (`[[dd-]hh:]mm:ss`) into elapsed seconds. */
|
|
261
|
+
export function parseEtimeToSeconds(raw) {
|
|
262
|
+
const m = raw.match(/^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/);
|
|
263
|
+
if (!m)
|
|
264
|
+
return null;
|
|
265
|
+
const days = m[1] ? parseInt(m[1], 10) : 0;
|
|
266
|
+
const hours = m[2] ? parseInt(m[2], 10) : 0;
|
|
267
|
+
const mins = parseInt(m[3], 10);
|
|
268
|
+
const secs = parseInt(m[4], 10);
|
|
269
|
+
if ([days, hours, mins, secs].some(isNaN))
|
|
270
|
+
return null;
|
|
271
|
+
return ((days * 24 + hours) * 60 + mins) * 60 + secs;
|
|
272
|
+
}
|
|
259
273
|
/** Elapsed wall-clock seconds since `pid` started, or null if unavailable (best-effort, POSIX only). */
|
|
260
274
|
export function uptimeSeconds(pid) {
|
|
261
275
|
if (process.platform === 'win32')
|
|
@@ -264,7 +278,7 @@ export function uptimeSeconds(pid) {
|
|
|
264
278
|
// `-o etimes=` is a GNU/procps keyword macOS/BSD `ps` rejects with a
|
|
265
279
|
// non-zero exit (`ps: etimes: keyword not found`), so `agents daemon status`
|
|
266
280
|
// errored out entirely on macOS. `etime` (`[[dd-]hh:]mm:ss`) is the portable
|
|
267
|
-
// POSIX field; `parseEtimeToSeconds`
|
|
281
|
+
// POSIX field; `parseEtimeToSeconds` above parses it.
|
|
268
282
|
const out = execFileSync('ps', ['-o', 'etime=', '-p', String(pid)], { encoding: 'utf-8' }).trim();
|
|
269
283
|
return parseEtimeToSeconds(out);
|
|
270
284
|
}
|
|
@@ -281,18 +295,18 @@ function humanDuration(seconds) {
|
|
|
281
295
|
return `${Math.round(seconds / 3600)}h`;
|
|
282
296
|
return `${Math.round(seconds / 86400)}d`;
|
|
283
297
|
}
|
|
298
|
+
/** Reachability probe only — the daemon does not host, supervise, or take over the broker (OWN-1). */
|
|
284
299
|
async function probeSecretsBroker() {
|
|
285
|
-
const record = readSubsystemHealth(SUBSYSTEM_SECRETS_BROKER);
|
|
286
300
|
try {
|
|
287
|
-
const { agentPing, agentStatus
|
|
301
|
+
const { agentPing, agentStatus } = await import('../lib/secrets-client.js');
|
|
288
302
|
const ping = await agentPing();
|
|
289
303
|
if (!ping.reachable)
|
|
290
|
-
return { reachable: false, socketPath:
|
|
304
|
+
return { reachable: false, socketPath: null, heldBundles: null, record: null };
|
|
291
305
|
const entries = await agentStatus();
|
|
292
|
-
return { reachable: true, socketPath:
|
|
306
|
+
return { reachable: true, socketPath: null, heldBundles: entries.length, record: null };
|
|
293
307
|
}
|
|
294
308
|
catch {
|
|
295
|
-
return { reachable: false, socketPath: null, heldBundles: null, record };
|
|
309
|
+
return { reachable: false, socketPath: null, heldBundles: null, record: null };
|
|
296
310
|
}
|
|
297
311
|
}
|
|
298
312
|
async function probeBrowserIPC() {
|
|
@@ -732,8 +746,8 @@ function registerWebhooksSubcommand(parent) {
|
|
|
732
746
|
notes: `
|
|
733
747
|
The bundle must hold GITHUB_WEBHOOK_SECRET and/or LINEAR_WEBHOOK_SECRET
|
|
734
748
|
('agents secrets add <bundle> LINEAR_WEBHOOK_SECRET'). The daemon reads it
|
|
735
|
-
through the secrets
|
|
736
|
-
AGENTS_SECRETS_PASSPHRASE and no nohup. A LOCKED bundle fails that receiver
|
|
749
|
+
headlessly through the standalone 'secrets' CLI, so a hosted receiver needs
|
|
750
|
+
no AGENTS_SECRETS_PASSPHRASE and no nohup. A LOCKED bundle fails that receiver
|
|
737
751
|
loud in 'agents daemon logs' rather than binding unverified ingress.
|
|
738
752
|
|
|
739
753
|
Port is the identity: a second 'add' on the same port edits that receiver.
|
|
@@ -831,7 +845,7 @@ function runWebhooksList(json) {
|
|
|
831
845
|
export function registerDaemonCommand(program) {
|
|
832
846
|
const cmd = program
|
|
833
847
|
.command('daemon')
|
|
834
|
-
.description('The always-on daemon:
|
|
848
|
+
.description('The always-on daemon: browser IPC, watchdog, and the routines scheduler. Bare `agents daemon` shows status.')
|
|
835
849
|
.option('--json', 'Emit as JSON')
|
|
836
850
|
.action(async (opts, command) => {
|
|
837
851
|
await runStatus({ json: command.optsWithGlobals().json === true });
|
|
@@ -860,12 +874,12 @@ export function registerDaemonCommand(program) {
|
|
|
860
874
|
agents daemon services
|
|
861
875
|
|
|
862
876
|
# Toggle or restart a service live — applies without a daemon restart
|
|
863
|
-
# for supervisor-managed services (
|
|
864
|
-
#
|
|
865
|
-
#
|
|
866
|
-
agents daemon services disable
|
|
867
|
-
agents daemon services enable
|
|
868
|
-
agents daemon services restart
|
|
877
|
+
# for supervisor-managed services (browser-ipc, account-state,
|
|
878
|
+
# session-index, monitors' off-transition, watchdog, device-probe,
|
|
879
|
+
# self-heal, state-dir-check)
|
|
880
|
+
agents daemon services disable browser-ipc
|
|
881
|
+
agents daemon services enable browser-ipc
|
|
882
|
+
agents daemon services restart browser-ipc
|
|
869
883
|
|
|
870
884
|
# Host a signed webhook receiver here, supervised and restarted on crash
|
|
871
885
|
agents daemon webhooks add --secrets-bundle linear-webhook
|
|
@@ -1006,17 +1020,18 @@ export function registerDaemonCommand(program) {
|
|
|
1006
1020
|
agents daemon services
|
|
1007
1021
|
|
|
1008
1022
|
# Machine-readable — additive: also carries the pre-existing
|
|
1009
|
-
# secretsBroker
|
|
1023
|
+
# secretsBroker (reachability-only probe, PHNX-3989)/browserIpc
|
|
1024
|
+
# hosted-socket fields
|
|
1010
1025
|
agents daemon services --json
|
|
1011
1026
|
|
|
1012
1027
|
# Just the enable/disable metadata, no health probe
|
|
1013
1028
|
agents daemon services list
|
|
1014
1029
|
|
|
1015
1030
|
# Toggle or restart live — no daemon restart for a supervisor-managed
|
|
1016
|
-
# service (
|
|
1017
|
-
agents daemon services disable
|
|
1018
|
-
agents daemon services enable
|
|
1019
|
-
agents daemon services restart
|
|
1031
|
+
# service (browser-ipc, account-state, session-index)
|
|
1032
|
+
agents daemon services disable browser-ipc
|
|
1033
|
+
agents daemon services enable browser-ipc
|
|
1034
|
+
agents daemon services restart browser-ipc
|
|
1020
1035
|
`,
|
|
1021
1036
|
notes: `
|
|
1022
1037
|
A service disabled at daemon boot is normally not registered on the
|
package/dist/commands/doctor.js
CHANGED
|
@@ -24,7 +24,7 @@ import { resolveAgentTargets, AgentSpecError } from '../lib/agent-spec/index.js'
|
|
|
24
24
|
import { loadManifest, isStale } from '../lib/staleness/index.js';
|
|
25
25
|
import { diffVersionResources, DOCTOR_ALL_KINDS, } from '../lib/doctor-diff.js';
|
|
26
26
|
import { inspectDuplicateVersionHooks } from '../lib/hooks/install.js';
|
|
27
|
-
import { inspectReservedAuthBundle } from '../lib/secrets
|
|
27
|
+
import { inspectReservedAuthBundle } from '../lib/secrets-policy.js';
|
|
28
28
|
import { isVersionIsolated } from '../lib/installations/versions.js';
|
|
29
29
|
import { computeDrift, checkSyncStatus, countOrphans, computeSourceBehind } from '../lib/drift.js';
|
|
30
30
|
import { readAuthHealthCache, summarizeHostAuth } from '../lib/auth-health.js';
|
|
@@ -35,13 +35,39 @@ import { listCliStatus, listCliStatusAsync } from '../lib/cli-resources.js';
|
|
|
35
35
|
import { setHelpSections } from '../lib/help.js';
|
|
36
36
|
import { getEffectiveExecutionPolicy } from '../lib/platform/winpath.js';
|
|
37
37
|
import { auditWindowsSshEnrollment, diagnoseWindowsSshFailure } from '../lib/devices/windows-ssh-enrollment.js';
|
|
38
|
-
import {
|
|
38
|
+
import { scanUserRcFilesSync, masterPassphraseInEnvSync, isSecretsTransportError, } from '../lib/secrets-client.js';
|
|
39
39
|
import { terminalWidth, truncateToWidth, stringWidth, padToWidth } from '../lib/session/width.js';
|
|
40
40
|
import { readRepoBehindMarkers } from '../lib/auto-pull.js';
|
|
41
41
|
import { detectAgentsBinaryShadows } from '../lib/binary-shadow.js';
|
|
42
42
|
import * as fs from 'fs';
|
|
43
43
|
const AGENT_NAMES = Object.fromEntries(ALL_AGENT_IDS.map((id) => [id, AGENTS[id].name]));
|
|
44
44
|
// ─── overview mode (no target) ────────────────────────────────────────────────
|
|
45
|
+
// doctor is the umbrella diagnostic and must never crash on one subsystem
|
|
46
|
+
// (§Diagnostic command taxonomy). The standalone secrets CLI being absent from
|
|
47
|
+
// PATH is a routine, expected state on a box that hasn't installed it — not a
|
|
48
|
+
// reason to abort the whole report — so these two checks degrade to "nothing to
|
|
49
|
+
// report" on a transport error and let every other finding still print. A data
|
|
50
|
+
// error the standalone actually answered with must still surface.
|
|
51
|
+
function scanUserRcFiles() {
|
|
52
|
+
try {
|
|
53
|
+
return scanUserRcFilesSync();
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (isSecretsTransportError(error))
|
|
57
|
+
return [];
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function masterPassphraseInEnv() {
|
|
62
|
+
try {
|
|
63
|
+
return masterPassphraseInEnvSync();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (isSecretsTransportError(error))
|
|
67
|
+
return false;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
45
71
|
function collapseWhitespace(s) {
|
|
46
72
|
return s.replace(/\s+/g, ' ').trim();
|
|
47
73
|
}
|
package/dist/commands/exec.js
CHANGED
|
@@ -843,6 +843,23 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
843
843
|
console.error(chalk.red(`Invalid account picker target: ${agentSpec}. Use agents run <agent>@.`));
|
|
844
844
|
process.exit(1);
|
|
845
845
|
}
|
|
846
|
+
// Peel `#name` off before --device dispatch so the selector rides the hop
|
|
847
|
+
// unchanged and the peer resolves ITS slot (PHNX-3940 T5). The later local
|
|
848
|
+
// parse is idempotent when the values match.
|
|
849
|
+
{
|
|
850
|
+
const labelParts = normalizedAgentSpec.split('#');
|
|
851
|
+
if (labelParts.length > 2 || labelParts[1] === '') {
|
|
852
|
+
console.error(chalk.red(`Invalid account label in '${normalizedAgentSpec}'.`));
|
|
853
|
+
process.exit(1);
|
|
854
|
+
}
|
|
855
|
+
const specAccountLabel = labelParts[1];
|
|
856
|
+
if (specAccountLabel && options.account && specAccountLabel !== options.account) {
|
|
857
|
+
console.error(chalk.red(`Account '${specAccountLabel}' from the agent spec conflicts with --account '${options.account}'.`));
|
|
858
|
+
process.exit(1);
|
|
859
|
+
}
|
|
860
|
+
if (specAccountLabel)
|
|
861
|
+
options.account = specAccountLabel;
|
|
862
|
+
}
|
|
846
863
|
// Hard-deprecated harnesses cannot be run — point the user at the successor.
|
|
847
864
|
const runBaseAgentName = normalizedAgentSpec.split('#')[0].split('@')[0];
|
|
848
865
|
const runBaseAgentId = resolveAgentName(runBaseAgentName);
|
|
@@ -1130,11 +1147,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1130
1147
|
// with an actionable hint instead of hard-failing the run (F5).
|
|
1131
1148
|
if (netMode === 'tailscale') {
|
|
1132
1149
|
const { pickTailscaleBundleFromList } = await import('../lib/crabbox/cli.js');
|
|
1133
|
-
const { listBundles } = await import('../lib/secrets
|
|
1150
|
+
const { listBundles } = await import('../lib/secrets-client.js');
|
|
1134
1151
|
let hasKey = !!process.env.CRABBOX_TAILSCALE_AUTH_KEY;
|
|
1135
1152
|
if (!hasKey) {
|
|
1136
1153
|
try {
|
|
1137
|
-
hasKey = !!pickTailscaleBundleFromList(listBundles());
|
|
1154
|
+
hasKey = !!pickTailscaleBundleFromList(await listBundles());
|
|
1138
1155
|
}
|
|
1139
1156
|
catch {
|
|
1140
1157
|
hasKey = false;
|
|
@@ -1800,12 +1817,16 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1800
1817
|
}
|
|
1801
1818
|
process.exit(resumeExit);
|
|
1802
1819
|
}
|
|
1803
|
-
const [{ buildExecCommand, parseExecEnv, execAgent, runWithFallback, normalizeMode, resolveMode, implicitModeFor, headlessPlanStallCommand, nativeResume, resolveInteractive, inferredInteractiveWithoutTty }, { ALL_AGENT_IDS, ACCOUNT_INSPECTION_AGENT_IDS, agentLabel, supportsAccountInspection }, { profileExists, readProfile, resolveProfileForRun },
|
|
1820
|
+
const [{ buildExecCommand, parseExecEnv, execAgent, runWithFallback, normalizeMode, resolveMode, implicitModeFor, headlessPlanStallCommand, nativeResume, resolveInteractive, inferredInteractiveWithoutTty }, { ALL_AGENT_IDS, ACCOUNT_INSPECTION_AGENT_IDS, agentLabel, supportsAccountInspection }, { profileExists, readProfile, resolveProfileForRun },
|
|
1821
|
+
// Engine DATA ops resolve through the standalone `secrets` process client
|
|
1822
|
+
// (PHNX-3989); the agents-owned `bundle@host` policy helpers stay in agents-cli.
|
|
1823
|
+
{ readAndResolveBundleEnv, describeBundle, remoteResolveEnv }, { assertRemoteBundleFlagsUnsupported, splitBundleRef, resolveSecretsContextForRun }, { resolveHostSshTarget }, { getConfiguredRunStrategy, normalizeRunStrategy, resolveRunVersion, rotationFailoverChain, shouldArmRotationFailover, RUN_STRATEGIES, collectHarnessCandidates, pickHarnessWeighted, classifyHarnessCandidates, formatHarnessPickBanner, formatNoHealthyHarnessError, formatNoHealthyAccountError, formatNoVerifiedUsageError, signInRecoverableCandidates }, { getGlobalDefault, getVersionHomePath, resolveVersion, resolveVersionAlias, ensureAgentRunnable }, { buildDiscoveredPlugin, loadPluginManifest, syncPluginToVersion }, { parseWorkflowFrontmatter, resolveWorkflowRef, resolveAllowedSubagents, pruneStaleWorkflowSubagents, ensureSubagentDispatchTool }, { resolveRunDefaults }, { getMcpServersByName, buildWorkflowMcpConfig }, { supports, capableAgents }, { shareRuntimeEnv },] = await Promise.all([
|
|
1804
1824
|
import('../lib/exec.js'),
|
|
1805
1825
|
import('../lib/agents.js'),
|
|
1806
1826
|
import('../lib/profiles.js'),
|
|
1807
|
-
import('../lib/secrets
|
|
1808
|
-
import('../lib/secrets
|
|
1827
|
+
import('../lib/secrets-client.js'),
|
|
1828
|
+
import('../lib/secrets-policy.js'),
|
|
1829
|
+
import('../lib/hosts/credential-transport.js'),
|
|
1809
1830
|
import('../lib/accounting/rotate.js'),
|
|
1810
1831
|
import('../lib/installations/versions.js'),
|
|
1811
1832
|
import('../lib/plugins/plugins.js'),
|
|
@@ -1844,6 +1865,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1844
1865
|
let profileEnv;
|
|
1845
1866
|
let accountEnv;
|
|
1846
1867
|
let accountConfigVersion;
|
|
1868
|
+
let execHome;
|
|
1847
1869
|
let profileProvider;
|
|
1848
1870
|
let fromProfile = false;
|
|
1849
1871
|
let profileName;
|
|
@@ -2169,6 +2191,10 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2169
2191
|
if (!selected)
|
|
2170
2192
|
return;
|
|
2171
2193
|
version = selected.version;
|
|
2194
|
+
if (selected.nativeAccount)
|
|
2195
|
+
options.account = selected.nativeAccount;
|
|
2196
|
+
if (selected.slotDir)
|
|
2197
|
+
execHome = selected.slotDir;
|
|
2172
2198
|
if (!options.quiet) {
|
|
2173
2199
|
const identity = selected.accountLabel || 'signed-in account';
|
|
2174
2200
|
process.stderr.write(chalk.gray(`[agents] selected ${identity} · ${agent}@${selected.version} for this run\n`));
|
|
@@ -2204,35 +2230,49 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2204
2230
|
process.exit(1);
|
|
2205
2231
|
}
|
|
2206
2232
|
if (spawnAccount.kind === 'native') {
|
|
2207
|
-
//
|
|
2208
|
-
//
|
|
2209
|
-
// injected. Fail closed for a remote target.
|
|
2233
|
+
// `#name` / `--account` on a --device run is forwarded unchanged at
|
|
2234
|
+
// dispatch time; the peer resolves ITS slot. This block is local-only.
|
|
2210
2235
|
const remoteTarget = options.host || options.device;
|
|
2211
|
-
if (remoteTarget) {
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2236
|
+
if (!remoteTarget) {
|
|
2237
|
+
const { adoptedConfigPointsAtHome, adoptedSymlinkMismatchError, isSymlinkAdoptedHarness, resolveNativeSpawnHome, symlinkAdoptedAccountError, } = await import('../lib/exec-account-home.js');
|
|
2238
|
+
const { readMeta } = await import('../lib/state.js');
|
|
2239
|
+
const meta = readMeta();
|
|
2240
|
+
if (isSymlinkAdoptedHarness(agent)) {
|
|
2241
|
+
const defaultName = meta.accounts?.defaults?.[agent];
|
|
2242
|
+
if (spawnAccount.name !== defaultName) {
|
|
2243
|
+
console.error(chalk.red(symlinkAdoptedAccountError(agent, spawnAccount.name, defaultName)));
|
|
2244
|
+
process.exit(1);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
try {
|
|
2248
|
+
const resolved = await resolveNativeSpawnHome(agent, spawnAccount, meta);
|
|
2249
|
+
if (isSymlinkAdoptedHarness(agent) && !adoptedConfigPointsAtHome(agent, resolved.execHome)) {
|
|
2250
|
+
console.error(chalk.red(adoptedSymlinkMismatchError(agent, spawnAccount.name, resolved.execHome)));
|
|
2251
|
+
process.exit(1);
|
|
2252
|
+
}
|
|
2253
|
+
execHome = resolved.execHome;
|
|
2254
|
+
if (resolved.source === 'legacy-home') {
|
|
2255
|
+
accountConfigVersion = resolved.label;
|
|
2256
|
+
// A leftover version-labeled home is both the spawn HOME and
|
|
2257
|
+
// the account's installation — the pre-T5 `resolveAccountVersion`
|
|
2258
|
+
// behavior. An explicit `@<label>` still controls the binary.
|
|
2259
|
+
if (!version && !fromProfile && resolved.label)
|
|
2260
|
+
version = resolved.label;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
catch (err) {
|
|
2264
|
+
console.error(chalk.red(err.message));
|
|
2265
|
+
process.exit(1);
|
|
2266
|
+
}
|
|
2267
|
+
// Slot / provisioned: binary comes from the one managed install unless `@<label>` pins it.
|
|
2268
|
+
if (!version && !fromProfile) {
|
|
2269
|
+
const { ensureHarnessInstallation } = await import('../lib/installations/store.js');
|
|
2270
|
+
const { installation } = await ensureHarnessInstallation(agent);
|
|
2271
|
+
version = installation.label;
|
|
2272
|
+
}
|
|
2273
|
+
if (!options.quiet)
|
|
2274
|
+
process.stderr.write(chalk.gray(`[agents] account '${spawnAccount.name}' · ${agent}\n`));
|
|
2227
2275
|
}
|
|
2228
|
-
// An account-only run executes the account's own stable installation.
|
|
2229
|
-
// This keeps its model/mode configuration and binary update policy
|
|
2230
|
-
// together. An explicit installation or profile still controls the
|
|
2231
|
-
// executable independently; configVersion continues to select auth.
|
|
2232
|
-
if (!version && !fromProfile)
|
|
2233
|
-
version = accountConfigVersion;
|
|
2234
|
-
if (!options.quiet)
|
|
2235
|
-
process.stderr.write(chalk.gray(`[agents] account '${spawnAccount.name}' · ${agent}\n`));
|
|
2236
2276
|
}
|
|
2237
2277
|
else {
|
|
2238
2278
|
accountEnv = spawnAccount.env;
|
|
@@ -2713,10 +2753,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2713
2753
|
authedViaSetupToken = resolveClaudeSetupToken(getVersionHomePath('claude', version)) !== null;
|
|
2714
2754
|
}
|
|
2715
2755
|
if (!info.signedIn && !authedViaSetupToken) {
|
|
2716
|
-
const {
|
|
2717
|
-
const hint =
|
|
2718
|
-
? `agents accounts
|
|
2719
|
-
:
|
|
2756
|
+
const { addSupported } = await import('../lib/accounts/add.js');
|
|
2757
|
+
const hint = spawnAccount?.kind === 'native'
|
|
2758
|
+
? `agents accounts login ${agent}#${spawnAccount.name}`
|
|
2759
|
+
: addSupported(agent)
|
|
2760
|
+
? `agents accounts add ${agent} <name>`
|
|
2761
|
+
: loginHint(agent);
|
|
2720
2762
|
process.stderr.write(chalk.yellow(`${agent} looks logged out — sign in with: ${hint}. Launching anyway...\n`));
|
|
2721
2763
|
}
|
|
2722
2764
|
}
|
|
@@ -2805,6 +2847,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2805
2847
|
? options.secretsKeys.split(',').map((k) => k.trim()).filter(Boolean)
|
|
2806
2848
|
: undefined;
|
|
2807
2849
|
let secretsEnv = {};
|
|
2850
|
+
// Resource-profile scoping (CTX-1): agents-cli computes which bundle
|
|
2851
|
+
// names the active profile allows and forwards it as the client's
|
|
2852
|
+
// `allowedBundles` on every local resolution — the standalone has no
|
|
2853
|
+
// concept of a profile. undefined (no active profile) is full trust.
|
|
2854
|
+
const secretsContext = await resolveSecretsContextForRun(agent);
|
|
2808
2855
|
for (const bundleRef of options.secrets) {
|
|
2809
2856
|
try {
|
|
2810
2857
|
const { bundle: bundleName, host } = splitBundleRef(bundleRef);
|
|
@@ -2822,7 +2869,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2822
2869
|
secretsEnv = { ...secretsEnv, ...bundleEnv };
|
|
2823
2870
|
}
|
|
2824
2871
|
else {
|
|
2825
|
-
const { bundle, env: bundleEnv } = readAndResolveBundleEnv(bundleName, {
|
|
2872
|
+
const { bundle, env: bundleEnv } = await readAndResolveBundleEnv(bundleName, {
|
|
2826
2873
|
caller: `agent ${agent}`,
|
|
2827
2874
|
agent,
|
|
2828
2875
|
keys: secretsKeysSubset,
|
|
@@ -2834,8 +2881,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2834
2881
|
// isHeadlessSecretsContext() left `--interactive` launches (the watchdog's
|
|
2835
2882
|
// `agents run auto --interactive`) able to prompt, piling up helper sheets.
|
|
2836
2883
|
agentOnly: true,
|
|
2837
|
-
});
|
|
2838
|
-
const entries = describeBundle(bundle);
|
|
2884
|
+
}, secretsContext);
|
|
2885
|
+
const entries = await describeBundle(bundle, secretsContext);
|
|
2839
2886
|
const counts = {};
|
|
2840
2887
|
for (const e of entries) {
|
|
2841
2888
|
counts[e.kind] = (counts[e.kind] || 0) + 1;
|
|
@@ -2881,6 +2928,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2881
2928
|
harnessName: profileName,
|
|
2882
2929
|
version,
|
|
2883
2930
|
configVersion: accountConfigVersion,
|
|
2931
|
+
execHome,
|
|
2884
2932
|
prompt,
|
|
2885
2933
|
interactive: options.interactive || forceInteractive,
|
|
2886
2934
|
mode: requestedMode,
|