@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
|
@@ -1,249 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents setup secrets` —
|
|
2
|
+
* `agents setup secrets` — install guidance for the standalone `secrets` CLI,
|
|
3
|
+
* then a pass-through to its own `secrets migrate` onboarding (PHNX-3989).
|
|
3
4
|
*
|
|
4
|
-
* The wizard
|
|
5
|
-
*
|
|
5
|
+
* The wizard that used to pick a default backend/policy and delegate imports
|
|
6
|
+
* lived entirely against the in-repo secrets engine. That engine is extracted
|
|
7
|
+
* to `@phnx-labs/secrets-cli`, which owns its own interactive onboarding
|
|
8
|
+
* (`secrets migrate`) — agents-cli never rebundles it (DIST-1), so there is no
|
|
9
|
+
* in-process fallback when it isn't installed: this command names the install
|
|
10
|
+
* command and stops.
|
|
6
11
|
*/
|
|
7
12
|
import chalk from 'chalk';
|
|
8
13
|
import * as fs from 'fs';
|
|
9
14
|
import * as path from 'path';
|
|
10
15
|
import { spawnSync } from 'node:child_process';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
import { parsePolicyOpt } from './secrets.js';
|
|
15
|
-
function defaultBackendForPlatform(platform = process.platform) {
|
|
16
|
-
return platform === 'darwin' ? 'keychain' : 'file';
|
|
17
|
-
}
|
|
16
|
+
import { getHistoryDir } from '../lib/state.js';
|
|
17
|
+
import { resolveSecretsBin, invocation, SecretsClientError } from '../lib/secrets-client.js';
|
|
18
|
+
const INSTALL_HINT = 'npm i -g @phnx-labs/secrets-cli';
|
|
18
19
|
export function setupSecretsPrefsPath() {
|
|
19
20
|
return path.join(getHistoryDir(), 'setup', 'secrets.json');
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (value === 'keychain' || value === 'file' || value === 'vault')
|
|
24
|
-
return value;
|
|
25
|
-
throw new Error(`Invalid --backend '${raw}'. Use keychain, file, or vault.`);
|
|
26
|
-
}
|
|
27
|
-
/** The wizard's `--policy` shares the canonical parser with `agents secrets
|
|
28
|
-
* policy`, so it accepts `hold` (and the `daily`/`session` aliases) rather than
|
|
29
|
-
* carrying its own copy that knows only the retired vocabulary. `parsePolicyOpt`
|
|
30
|
-
* defaults an absent value to `always`; the wizard's own default is `hold`, so
|
|
31
|
-
* it is supplied here rather than inherited. */
|
|
32
|
-
export function parsePolicy(raw) {
|
|
33
|
-
return parsePolicyOpt(raw ?? 'hold');
|
|
34
|
-
}
|
|
35
|
-
function parseImportSource(raw) {
|
|
36
|
-
const value = (raw ?? 'none').toLowerCase();
|
|
37
|
-
if (value === 'none' || value === 'env' || value === '1password' || value === 'icloud')
|
|
38
|
-
return value;
|
|
39
|
-
throw new Error(`Invalid --import-from '${raw}'. Use none, env, 1password, or icloud.`);
|
|
40
|
-
}
|
|
41
|
-
function hasCommand(command) {
|
|
42
|
-
const res = spawnSync(command, ['--version'], { stdio: 'ignore', windowsHide: true });
|
|
43
|
-
return !res.error;
|
|
44
|
-
}
|
|
45
|
-
function saveSetupSecretsPrefs(prefs) {
|
|
46
|
-
const file = setupSecretsPrefsPath();
|
|
47
|
-
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
48
|
-
fs.writeFileSync(file, JSON.stringify(prefs, null, 2) + '\n', { mode: 0o600 });
|
|
49
|
-
return file;
|
|
50
|
-
}
|
|
51
|
-
function applySecretsDefaults(backend, policy) {
|
|
52
|
-
updateMeta((meta) => ({
|
|
53
|
-
...meta,
|
|
54
|
-
secrets: {
|
|
55
|
-
...meta.secrets,
|
|
56
|
-
backend,
|
|
57
|
-
...(policy === 'never' ? {} : { policy }),
|
|
58
|
-
},
|
|
59
|
-
}));
|
|
60
|
-
}
|
|
61
|
-
function backendArgs(backend) {
|
|
62
|
-
return backend === 'vault' ? ['--synced'] : ['--backend', backend];
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Provision the signed macOS keychain broker on the explicit onboarding path.
|
|
66
|
-
* This is the async, download-capable trigger the hot sync `getKeychainHelperPath()`
|
|
67
|
-
* fails loud toward: with a bundled `.app` it is a local copy (no network); on a
|
|
68
|
-
* tarball that lacks the bundle it fetches the verified release asset. Best-effort
|
|
69
|
-
* — the wizard's saved prefs must survive an offline provision failure; the next
|
|
70
|
-
* secret op re-points here.
|
|
71
|
-
*/
|
|
72
|
-
async function maybeProvisionKeychainHelper(backend) {
|
|
73
|
-
if (backend !== 'keychain' || process.platform !== 'darwin')
|
|
74
|
-
return;
|
|
75
|
-
const { ensureKeychainHelperInstalledAsync } = await import('../lib/secrets/install-helper.js');
|
|
22
|
+
/** True when the standalone `secrets` executable resolves ($SECRETS_BIN or PATH). */
|
|
23
|
+
export function isSecretsCliInstalled() {
|
|
76
24
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
25
|
+
resolveSecretsBin();
|
|
26
|
+
return true;
|
|
79
27
|
}
|
|
80
28
|
catch (err) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
function printBackendNotes(backend) {
|
|
86
|
-
if (backend === 'keychain') {
|
|
87
|
-
console.log(chalk.gray('backend: keychain — macOS reads may ask for Touch ID or the device password.'));
|
|
88
|
-
}
|
|
89
|
-
else if (backend === 'file') {
|
|
90
|
-
console.log(chalk.gray('backend: file — encrypted at rest; headless reads need no passphrase by default, via a machine-local key at ~/.agents/.secrets-key/passphrase.'));
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
console.log(chalk.gray('backend: vault — synced ~/.agents/vault.age storage; unlock it with `agents secrets vault unlock`.'));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function runAgentsSubcommand(args) {
|
|
97
|
-
const launch = getCliLaunch(args);
|
|
98
|
-
const res = spawnSync(launch.command, launch.args, { stdio: 'inherit', env: process.env });
|
|
99
|
-
if ((res.status ?? 1) !== 0) {
|
|
100
|
-
throw new Error(`agents ${args.join(' ')} failed with exit ${res.status ?? 1}.`);
|
|
29
|
+
if (err instanceof SecretsClientError && err.code === 'SECRETS_BIN_MISSING')
|
|
30
|
+
return false;
|
|
31
|
+
throw err;
|
|
101
32
|
}
|
|
102
33
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (!bundle) {
|
|
108
|
-
if (!isInteractiveTerminal()) {
|
|
109
|
-
throw new Error(`--bundle is required with --import-from ${source} in a non-interactive shell.`);
|
|
110
|
-
}
|
|
111
|
-
const { input } = await import('@inquirer/prompts');
|
|
112
|
-
bundle = await input({
|
|
113
|
-
message: 'Import into which bundle?',
|
|
114
|
-
default: 'default',
|
|
115
|
-
validate: (v) => (v.trim().length > 0 ? true : 'Enter a bundle name.'),
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
const args = ['secrets', 'import', bundle, ...backendArgs(opts.backend)];
|
|
119
|
-
if (opts.force)
|
|
120
|
-
args.push('--force');
|
|
121
|
-
if (source === 'env') {
|
|
122
|
-
let envPath = opts.vault;
|
|
123
|
-
if (!envPath) {
|
|
124
|
-
if (!isInteractiveTerminal()) {
|
|
125
|
-
throw new Error('--vault must name the .env path when --import-from env is used non-interactively.');
|
|
126
|
-
}
|
|
127
|
-
const { input } = await import('@inquirer/prompts');
|
|
128
|
-
envPath = await input({
|
|
129
|
-
message: '.env file path',
|
|
130
|
-
default: '.env',
|
|
131
|
-
validate: (v) => (v.trim().length > 0 ? true : 'Enter a .env path.'),
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
args.push('--from', envPath);
|
|
135
|
-
}
|
|
136
|
-
else if (source === '1password') {
|
|
137
|
-
const vault = opts.vault;
|
|
138
|
-
if (!vault)
|
|
139
|
-
throw new Error('--vault <name> is required with --import-from 1password.');
|
|
140
|
-
args.push('--from', `1password:${vault}`);
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
args.push('--from', 'icloud');
|
|
144
|
-
}
|
|
145
|
-
runAgentsSubcommand(args);
|
|
146
|
-
}
|
|
147
|
-
async function resolveInteractiveChoices(opts) {
|
|
148
|
-
if (!isInteractiveTerminal()) {
|
|
149
|
-
return {
|
|
150
|
-
backend: parseBackend(opts.backend),
|
|
151
|
-
policy: parsePolicy(opts.policy),
|
|
152
|
-
importSource: parseImportSource(opts.importFrom),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
const { select } = await import('@inquirer/prompts');
|
|
156
|
-
const backend = opts.backend ? parseBackend(opts.backend) : await select({
|
|
157
|
-
message: 'Default secrets backend',
|
|
158
|
-
default: defaultBackendForPlatform(),
|
|
159
|
-
choices: [
|
|
160
|
-
{ name: 'keychain — local OS keychain; reads may ask for Touch ID/device password', value: 'keychain' },
|
|
161
|
-
{ name: 'file — passphrase-encrypted file store for headless machines', value: 'file' },
|
|
162
|
-
{ name: 'vault — synced ~/.agents/vault.age file; requires `agents secrets vault unlock`', value: 'vault' },
|
|
163
|
-
],
|
|
164
|
-
});
|
|
165
|
-
const policy = opts.policy ? parsePolicy(opts.policy) : await select({
|
|
166
|
-
message: 'Default prompt policy',
|
|
167
|
-
default: 'hold',
|
|
168
|
-
choices: [
|
|
169
|
-
{ name: 'hold — ask once, then hold for the configured window (7 days by default)', value: 'hold' },
|
|
170
|
-
{ name: 'always — ask on every read', value: 'always' },
|
|
171
|
-
{ name: 'never — no biometry ACL; use only for automation-only bundles', value: 'never' },
|
|
172
|
-
],
|
|
173
|
-
});
|
|
174
|
-
const importChoices = [
|
|
175
|
-
{ name: 'skip import', value: 'none' },
|
|
176
|
-
{ name: 'import from .env file', value: 'env' },
|
|
177
|
-
...(hasCommand('op') ? [{ name: 'import from 1Password vault', value: '1password' }] : []),
|
|
178
|
-
{ name: 'import legacy iCloud Keychain bundles', value: 'icloud' },
|
|
179
|
-
];
|
|
180
|
-
const importSource = opts.importFrom ? parseImportSource(opts.importFrom) : await select({
|
|
181
|
-
message: 'Import existing secrets now?',
|
|
182
|
-
default: 'none',
|
|
183
|
-
choices: importChoices,
|
|
184
|
-
});
|
|
185
|
-
return { backend, policy, importSource };
|
|
186
|
-
}
|
|
187
|
-
function printOnboardingSummary(backend, policy, prefsFile) {
|
|
188
|
-
console.log(chalk.bold('\nSecrets setup saved.'));
|
|
189
|
-
console.log(chalk.gray(`preferences: ${prefsFile}`));
|
|
190
|
-
printBackendNotes(backend);
|
|
191
|
-
if (policy === 'never') {
|
|
192
|
-
console.log(chalk.yellow('policy: never is saved as a setup preference; create automation-only bundles with --policy never --i-understand.'));
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
console.log(chalk.gray(`policy: ${policy} — used by bundles that do not set their own policy.`));
|
|
196
|
-
}
|
|
197
|
-
console.log(chalk.bold('\nTry:'));
|
|
198
|
-
console.log(chalk.cyan(` agents secrets create prod ${backendArgs(backend).join(' ')} --policy ${policy === 'never' ? 'hold' : policy}`));
|
|
199
|
-
console.log(chalk.cyan(' agents secrets add prod API_KEY'));
|
|
200
|
-
console.log(chalk.cyan(' agents run claude "deploy" --secrets prod'));
|
|
34
|
+
function recordSetupComplete() {
|
|
35
|
+
const file = setupSecretsPrefsPath();
|
|
36
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
37
|
+
fs.writeFileSync(file, JSON.stringify({ updatedAt: new Date().toISOString() }, null, 2) + '\n', { mode: 0o600 });
|
|
201
38
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Print install guidance when the standalone is missing, else hand off to its
|
|
41
|
+
* own interactive `secrets migrate`. Returns whether setup is now complete
|
|
42
|
+
* (installed, and — when it ran — `migrate` exited 0).
|
|
43
|
+
*/
|
|
44
|
+
export async function runSecretsSetupWizard() {
|
|
45
|
+
if (!isSecretsCliInstalled()) {
|
|
46
|
+
console.log(chalk.yellow('The standalone `secrets` CLI is not installed.'));
|
|
47
|
+
console.log(chalk.gray('Install it, then re-run `agents setup secrets`:'));
|
|
48
|
+
console.log(chalk.cyan(` ${INSTALL_HINT}`));
|
|
49
|
+
return false;
|
|
206
50
|
}
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
await maybeProvisionKeychainHelper(backend);
|
|
215
|
-
await maybeImportSecrets(importSource, {
|
|
216
|
-
bundle: opts.bundle,
|
|
217
|
-
vault: opts.vault,
|
|
218
|
-
backend,
|
|
219
|
-
force: opts.force,
|
|
220
|
-
});
|
|
221
|
-
printOnboardingSummary(backend, policy, prefsFile);
|
|
222
|
-
return true;
|
|
51
|
+
const bin = resolveSecretsBin();
|
|
52
|
+
const { command, prefix } = invocation(bin);
|
|
53
|
+
const res = spawnSync(command, [...prefix, 'migrate'], { stdio: 'inherit' });
|
|
54
|
+
const ok = (res.status ?? 1) === 0;
|
|
55
|
+
if (ok)
|
|
56
|
+
recordSetupComplete();
|
|
57
|
+
return ok;
|
|
223
58
|
}
|
|
224
59
|
/** Register `agents setup secrets` under the parent `setup` command. */
|
|
225
60
|
export function registerSetupSecretsCommand(setupCmd) {
|
|
226
61
|
setupCmd
|
|
227
62
|
.command('secrets')
|
|
228
|
-
.description('
|
|
229
|
-
.
|
|
230
|
-
|
|
231
|
-
.option('--import-from <source>', 'optional import source: none, env, 1password, or icloud')
|
|
232
|
-
.option('--bundle <name>', 'bundle name for optional imports')
|
|
233
|
-
.option('--vault <name-or-path>', '1Password vault name, or .env path with --import-from env')
|
|
234
|
-
.option('--i-understand', 'allow saving the "never" policy preference without an interactive prompt')
|
|
235
|
-
.option('--force', 'pass --force through to optional imports')
|
|
236
|
-
.action(async (options) => {
|
|
237
|
-
try {
|
|
238
|
-
await runSecretsSetupWizard(options);
|
|
239
|
-
}
|
|
240
|
-
catch (err) {
|
|
241
|
-
if (isPromptCancelled(err)) {
|
|
242
|
-
console.log(chalk.yellow('\nCancelled'));
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
console.error(chalk.red(err.message));
|
|
63
|
+
.description('Install guidance for the standalone `secrets` CLI, then run its own `secrets migrate` onboarding.')
|
|
64
|
+
.action(async () => {
|
|
65
|
+
if (!(await runSecretsSetupWizard()))
|
|
246
66
|
process.exitCode = 1;
|
|
247
|
-
}
|
|
248
67
|
});
|
|
249
68
|
}
|
package/dist/commands/ssh.js
CHANGED
|
@@ -16,7 +16,7 @@ import * as path from 'path';
|
|
|
16
16
|
import chalk from 'chalk';
|
|
17
17
|
import ora from 'ora';
|
|
18
18
|
import { getCliVersion } from '../lib/version.js';
|
|
19
|
-
import { readAndResolveBundleEnv } from '../lib/secrets
|
|
19
|
+
import { readAndResolveBundleEnv } from '../lib/secrets-client.js';
|
|
20
20
|
import { machineId } from '../lib/session/sync/config.js';
|
|
21
21
|
import { assertRegistrableDeviceName } from '../lib/devices/registry.js';
|
|
22
22
|
import { isDeviceAuto, resolveDeviceAffinity } from '../lib/smart-launch.js';
|
|
@@ -2766,7 +2766,7 @@ async function runAskpass() {
|
|
|
2766
2766
|
// render load/mem for an uncached password-auth device (RUSH-1970).
|
|
2767
2767
|
const agentOnly = true;
|
|
2768
2768
|
try {
|
|
2769
|
-
const { env } = readAndResolveBundleEnv(bundle, { caller: 'agents ssh', keys: [key], keyMode: 'storage', agentOnly });
|
|
2769
|
+
const { env } = await readAndResolveBundleEnv(bundle, { caller: 'agents ssh', keys: [key], keyMode: 'storage', agentOnly });
|
|
2770
2770
|
const value = env[key];
|
|
2771
2771
|
if (value === undefined) {
|
|
2772
2772
|
console.error(`askpass: key '${key}' not found in bundle '${bundle}'`);
|
package/dist/commands/sync.js
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
import * as path from 'path';
|
|
34
34
|
import { Option } from 'commander';
|
|
35
35
|
import chalk from 'chalk';
|
|
36
|
-
import { resolveSyncPassphraseFromEnv } from '../lib/
|
|
36
|
+
import { resolveSyncPassphraseFromEnv } from '../lib/sync-passphrase.js';
|
|
37
37
|
import { agentLabel, resolveAgentName, MANAGED_AGENT_IDS, isAgentHardDeprecated, hardDeprecationError } from '../lib/agents.js';
|
|
38
38
|
import { autoEvictCentralBrowserProfiles } from '../lib/browser/registry.js';
|
|
39
39
|
import { shouldAutoClaimCentralProfile } from '../lib/browser/profiles.js';
|
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import type { AgentId } from '../lib/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* One line naming the installations a bare `agents update <agent>` did NOT
|
|
5
|
+
* touch — isolated (`--isolated`) copies and legacy pre-v2 per-version homes —
|
|
6
|
+
* or `null` when the managed install is the only one. Bare `<agent>` moves only
|
|
7
|
+
* the single managed install, so leaving these silent would let a user believe
|
|
8
|
+
* every copy is current (PHNX-3940). Pure over the installation store so the
|
|
9
|
+
* naming logic is unit-testable without running a real update.
|
|
10
|
+
*/
|
|
11
|
+
export declare function describeSkippedInstallations(agent: AgentId, managedId: string): string | null;
|
|
2
12
|
export declare function registerUpdateCommand(program: Command): void;
|
package/dist/commands/update.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { AGENTS, formatAgentError, resolveAgentName } from '../lib/agents.js';
|
|
3
3
|
import { setHelpSections } from '../lib/help.js';
|
|
4
|
-
import { describeInstallation,
|
|
4
|
+
import { describeInstallation, listInstallations, planAutoUpdates, resolveInstallation, runAutoUpdatePass, selectUpdateStrategy, supportsPinnedUpdate, updateInstallation, } from '../lib/installations/index.js';
|
|
5
|
+
import { resolveManagedInstallation } from '../lib/installations/index.js';
|
|
5
6
|
/**
|
|
6
7
|
* Split `<agent>[@<selector>]`. The selector names an INSTALLATION — its frozen
|
|
7
8
|
* label, or the release it currently carries — never a release to install; that
|
|
@@ -20,6 +21,22 @@ function parseTarget(raw) {
|
|
|
20
21
|
throw new Error(formatAgentError(name));
|
|
21
22
|
return { agent, selector };
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* One line naming the installations a bare `agents update <agent>` did NOT
|
|
26
|
+
* touch — isolated (`--isolated`) copies and legacy pre-v2 per-version homes —
|
|
27
|
+
* or `null` when the managed install is the only one. Bare `<agent>` moves only
|
|
28
|
+
* the single managed install, so leaving these silent would let a user believe
|
|
29
|
+
* every copy is current (PHNX-3940). Pure over the installation store so the
|
|
30
|
+
* naming logic is unit-testable without running a real update.
|
|
31
|
+
*/
|
|
32
|
+
export function describeSkippedInstallations(agent, managedId) {
|
|
33
|
+
const skipped = listInstallations(agent).filter((i) => i.id !== managedId);
|
|
34
|
+
if (skipped.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
const names = skipped.map((i) => `${agent}@${describeInstallation(i)}`).join(', ');
|
|
37
|
+
return `Left ${skipped.length} other ${AGENTS[agent].name} installation${skipped.length === 1 ? '' : 's'} unchanged `
|
|
38
|
+
+ `(${names}). Update one with: agents update ${agent}@<label>.`;
|
|
39
|
+
}
|
|
23
40
|
function serialize(installation) {
|
|
24
41
|
return {
|
|
25
42
|
id: installation.id,
|
|
@@ -65,7 +82,7 @@ function printInstallations(agent, json) {
|
|
|
65
82
|
return;
|
|
66
83
|
}
|
|
67
84
|
if (!installations.length) {
|
|
68
|
-
console.log(chalk.gray(`No managed ${agent} installations. Install one with: agents add ${agent}
|
|
85
|
+
console.log(chalk.gray(`No managed ${agent} installations. Install one with: agents add ${agent}`));
|
|
69
86
|
return;
|
|
70
87
|
}
|
|
71
88
|
console.log(chalk.bold(`${agent} installations\n`));
|
|
@@ -222,35 +239,21 @@ export function registerUpdateCommand(program) {
|
|
|
222
239
|
printOutcome(outcome, !!options.json);
|
|
223
240
|
return;
|
|
224
241
|
}
|
|
225
|
-
// Bare `<agent>`, no `@label`:
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
throw new Error(`No ${AGENTS[agent].name} installations are managed by agents-cli. Install one with: agents add ${agent}@latest`);
|
|
242
|
+
// Bare `<agent>`, no `@label`: update the harness's ONE managed
|
|
243
|
+
// installation (PHNX-3940). The `@<label>` selector above remains for
|
|
244
|
+
// legacy multi-install layouts and isolated copies; the automatic pass
|
|
245
|
+
// (`--auto`, the daemon) still sweeps every installation by policy.
|
|
246
|
+
const managed = resolveManagedInstallation(agent);
|
|
247
|
+
if (!managed) {
|
|
248
|
+
throw new Error(`No managed ${AGENTS[agent].name} installation. Install one with: agents add ${agent}`);
|
|
233
249
|
}
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
let anyError = false;
|
|
242
|
-
for (const installation of targets) {
|
|
243
|
-
try {
|
|
244
|
-
const outcome = await updateOne(agent, installation, options);
|
|
245
|
-
printOutcome(outcome, !!options.json);
|
|
246
|
-
}
|
|
247
|
-
catch (err) {
|
|
248
|
-
anyError = true;
|
|
249
|
-
fail(err);
|
|
250
|
-
}
|
|
250
|
+
const outcome = await updateOne(agent, managed, options);
|
|
251
|
+
printOutcome(outcome, !!options.json);
|
|
252
|
+
if (!options.json) {
|
|
253
|
+
const skippedLine = describeSkippedInstallations(agent, managed.id);
|
|
254
|
+
if (skippedLine)
|
|
255
|
+
console.log(chalk.gray(skippedLine));
|
|
251
256
|
}
|
|
252
|
-
if (anyError)
|
|
253
|
-
process.exitCode = 1;
|
|
254
257
|
}
|
|
255
258
|
catch (err) {
|
|
256
259
|
fail(err);
|
|
@@ -275,21 +278,21 @@ export function registerUpdateCommand(program) {
|
|
|
275
278
|
}
|
|
276
279
|
});
|
|
277
280
|
setHelpSections(update, {
|
|
278
|
-
examples: `agents update
|
|
279
|
-
agents update claude
|
|
280
|
-
agents update claude
|
|
281
|
-
agents update claude
|
|
282
|
-
agents update claude
|
|
281
|
+
examples: `agents update claude
|
|
282
|
+
agents update claude --to 2.1.220
|
|
283
|
+
agents update claude --to latest
|
|
284
|
+
agents update list claude
|
|
283
285
|
agents update --check
|
|
284
286
|
agents update claude --check --json
|
|
285
287
|
agents update --auto`,
|
|
286
|
-
notes: '
|
|
287
|
-
+ 'a routine version, or a profile that names claude@
|
|
288
|
-
+ '
|
|
289
|
-
+ '
|
|
288
|
+
notes: 'One managed installation per harness: a bare `<agent>` updates that installation, keeping its name and every '
|
|
289
|
+
+ 'reference to it. That is why a default, a project pin, a routine version, or a profile that names claude@main '
|
|
290
|
+
+ 'keeps working after you update it. '
|
|
291
|
+
+ '`--to <release>` pins the installation to a concrete release (excluded from the automatic pass), `--to latest` '
|
|
292
|
+
+ 'unpins it. The legacy `agents update <agent>@<label>` selector still addresses a specific installation by its '
|
|
293
|
+
+ 'name or the release it currently carries, for pre-v2 layouts with several installations. '
|
|
290
294
|
+ 'The new release is fetched and launched before it replaces the working one, so a bad release leaves your agent running. '
|
|
291
|
-
+ '
|
|
292
|
-
+ 'installations it touches, `--to latest` unpins them. Pinned and manual/vendor-managed installations are also skipped '
|
|
295
|
+
+ 'Pinned and manual/vendor-managed installations are also skipped '
|
|
293
296
|
+ 'by the automatic background pass (agents config set updates.auto / updates.<agent>.auto). `--check` reports what '
|
|
294
297
|
+ '`--auto` would do without changing anything; `--auto` (no target) runs the exact pass the daemon runs, across every '
|
|
295
298
|
+ 'harness.',
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
* switching, resource sync prompts, and project-level version pinning.
|
|
8
8
|
*/
|
|
9
9
|
import type { Command } from 'commander';
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
10
|
+
/**
|
|
11
|
+
* What `agents add <spec>` does with the harness's ONE managed installation
|
|
12
|
+
* (PHNX-3940): with no managed install it installs one (label `main`); with
|
|
13
|
+
* one, a bare spec reuses it and an explicit `@<release>` pins that same
|
|
14
|
+
* install — exactly `agents update <agent> --to <release>`. A second home is
|
|
15
|
+
* only ever an `--isolated` copy, which bypasses this plan entirely.
|
|
16
|
+
*/
|
|
17
|
+
export declare function planManagedAdd(input: {
|
|
18
|
+
explicitPin: boolean;
|
|
19
|
+
managedInstalled: boolean;
|
|
20
|
+
}): 'reuse' | 'pin' | 'install';
|
|
21
21
|
/** Register `agents add`, `agents prune`, `agents remove`, and `agents use`. */
|
|
22
22
|
export declare function registerVersionsCommands(program: Command): void;
|