@phnx-labs/agents-cli 1.22.46 → 1.22.49
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 +663 -0
- package/LICENSE +102 -182
- package/README.md +96 -49
- package/dist/bootstrap.js +4 -2
- package/dist/cli/command-registry.d.ts +2 -1
- package/dist/cli/command-registry.js +6 -2
- package/dist/commands/accounts.d.ts +58 -0
- package/dist/commands/accounts.js +243 -25
- package/dist/commands/artifacts.js +7 -6
- package/dist/commands/attach.js +1 -1
- package/dist/commands/auth.js +7 -5
- package/dist/commands/browser-sessions-picker.js +9 -7
- package/dist/commands/browser.js +711 -62
- package/dist/commands/config.d.ts +0 -1
- package/dist/commands/config.js +26 -24
- package/dist/commands/cost.d.ts +1 -1
- package/dist/commands/daemon.d.ts +21 -0
- package/dist/commands/daemon.js +147 -12
- package/dist/commands/detach.d.ts +13 -0
- package/dist/commands/detach.js +11 -8
- package/dist/commands/exec.js +107 -53
- package/dist/commands/feed-watch.d.ts +2 -0
- package/dist/commands/feed-watch.js +28 -0
- package/dist/commands/feed.js +27 -0
- package/dist/commands/feedback.js +3 -19
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +48 -5
- package/dist/commands/go.d.ts +3 -0
- package/dist/commands/go.js +16 -3
- package/dist/commands/insights.d.ts +1 -1
- package/dist/commands/insights.js +2 -2
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/lease.d.ts +1 -1
- package/dist/commands/lease.js +7 -6
- package/dist/commands/mailboxes.js +4 -3
- package/dist/commands/menubar.js +11 -4
- package/dist/commands/projects.d.ts +16 -1
- package/dist/commands/projects.js +58 -64
- package/dist/commands/resume.js +1 -1
- package/dist/commands/route.js +4 -4
- package/dist/commands/routines.js +4 -3
- package/dist/commands/run-broadcast.d.ts +1 -1
- package/dist/commands/run-broadcast.js +1 -1
- package/dist/commands/sessions-picker-factory.d.ts +2 -1
- package/dist/commands/sessions-picker-factory.js +1 -1
- package/dist/commands/sessions-picker.d.ts +22 -0
- package/dist/commands/sessions-picker.js +48 -9
- package/dist/commands/sessions-stop.d.ts +24 -0
- package/dist/commands/sessions-stop.js +66 -0
- package/dist/commands/sessions-trace.d.ts +82 -0
- package/dist/commands/sessions-trace.js +387 -0
- package/dist/commands/sessions.js +5 -0
- package/dist/commands/setup-secrets.js +23 -0
- package/dist/commands/share.d.ts +20 -5
- package/dist/commands/share.js +152 -52
- package/dist/commands/ssh.d.ts +15 -0
- package/dist/commands/ssh.js +243 -18
- package/dist/commands/teams.js +34 -2
- package/dist/commands/traces.d.ts +2 -0
- package/dist/commands/traces.js +184 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +32 -62
- package/dist/commands/watchdog.js +9 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/lib/account-capabilities.d.ts +4 -0
- package/dist/lib/account-capabilities.js +13 -9
- package/dist/lib/account-registry.d.ts +2 -0
- package/dist/lib/account-registry.js +30 -2
- package/dist/lib/accounting/rotate.d.ts +9 -0
- package/dist/lib/accounting/rotate.js +12 -2
- package/dist/lib/accounting/usage.d.ts +84 -6
- package/dist/lib/accounting/usage.js +293 -75
- package/dist/lib/agent-modes.js +29 -1
- package/dist/lib/agent-spec/agents.d.ts +4 -3
- package/dist/lib/agent-spec/agents.js +25 -15
- package/dist/lib/analytics/mix-commands.d.ts +1 -1
- package/dist/lib/analytics/mix-commands.js +2 -2
- package/dist/lib/auth-health.d.ts +13 -3
- package/dist/lib/auth-health.js +50 -8
- package/dist/lib/browser/devices.d.ts +19 -0
- package/dist/lib/browser/devices.js +23 -0
- package/dist/lib/browser/drivers/ssh.d.ts +16 -2
- package/dist/lib/browser/drivers/ssh.js +36 -9
- package/dist/lib/browser/ipc.d.ts +1 -1
- package/dist/lib/browser/ipc.js +40 -9
- package/dist/lib/browser/profiles.d.ts +104 -65
- package/dist/lib/browser/profiles.js +277 -165
- package/dist/lib/browser/registry.d.ts +39 -0
- package/dist/lib/browser/registry.js +149 -0
- package/dist/lib/browser/remote-control.d.ts +28 -2
- package/dist/lib/browser/remote-control.js +35 -3
- package/dist/lib/browser/resolve-target.d.ts +68 -0
- package/dist/lib/browser/resolve-target.js +250 -0
- package/dist/lib/browser/runtime-state.d.ts +44 -11
- package/dist/lib/browser/runtime-state.js +98 -15
- package/dist/lib/browser/service.d.ts +65 -9
- package/dist/lib/browser/service.js +196 -61
- package/dist/lib/browser/sessions-list.d.ts +1 -3
- package/dist/lib/browser/sessions-list.js +3 -16
- package/dist/lib/browser/task-index.d.ts +70 -0
- package/dist/lib/browser/task-index.js +180 -0
- package/dist/lib/browser/types.d.ts +12 -1
- package/dist/lib/byok-usage.js +2 -2
- package/dist/lib/claude-statusline.d.ts +29 -0
- package/dist/lib/claude-statusline.js +139 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +1 -1
- package/dist/lib/cloud/rush.js +1 -1
- package/dist/lib/codex-policy.d.ts +11 -1
- package/dist/lib/codex-policy.js +20 -5
- package/dist/lib/computer/computer-rpc.js +2 -2
- package/dist/lib/computer/download.d.ts +15 -15
- package/dist/lib/computer/download.js +35 -98
- package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
- package/dist/lib/computer/ssh-tunnel.js +12 -22
- package/dist/lib/config-keys.d.ts +6 -11
- package/dist/lib/config-keys.js +18 -19
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +2 -2
- package/dist/lib/crabbox/lease.d.ts +9 -0
- package/dist/lib/crabbox/lease.js +70 -15
- package/dist/lib/crabbox/runtimes.js +1 -1
- package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
- package/dist/lib/daemon/account-state-daemon-service.js +26 -0
- package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
- package/dist/lib/daemon/browser-ipc-service.js +46 -0
- package/dist/lib/daemon/daemon.d.ts +3 -0
- package/dist/lib/daemon/daemon.js +212 -444
- package/dist/lib/daemon/device-probe-service.d.ts +26 -0
- package/dist/lib/daemon/device-probe-service.js +47 -0
- package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
- package/dist/lib/daemon/keychain-reap-service.js +32 -0
- package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
- package/dist/lib/daemon/monitor-engine-service.js +29 -0
- package/dist/lib/daemon/runner.js +15 -2
- package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
- package/dist/lib/daemon/secrets-broker-service.js +66 -0
- package/dist/lib/daemon/self-heal-service.d.ts +27 -0
- package/dist/lib/daemon/self-heal-service.js +48 -0
- package/dist/lib/daemon/service.d.ts +102 -0
- package/dist/lib/daemon/service.js +98 -0
- package/dist/lib/daemon/session-index-service.d.ts +22 -0
- package/dist/lib/daemon/session-index-service.js +40 -0
- package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
- package/dist/lib/daemon/state-dir-check-service.js +63 -0
- package/dist/lib/daemon/supervisor.d.ts +87 -0
- package/dist/lib/daemon/supervisor.js +298 -0
- package/dist/lib/daemon/watchdog-service.d.ts +19 -0
- package/dist/lib/daemon/watchdog-service.js +40 -0
- package/dist/lib/daemon-health.d.ts +15 -0
- package/dist/lib/daemon-health.js +29 -5
- package/dist/lib/daemon-services.d.ts +8 -1
- package/dist/lib/daemon-services.js +55 -0
- package/dist/lib/daemon-ticks.d.ts +13 -2
- package/dist/lib/daemon-ticks.js +22 -20
- package/dist/lib/device-config.d.ts +25 -10
- package/dist/lib/device-config.js +90 -39
- package/dist/lib/devices/config-migration.d.ts +7 -0
- package/dist/lib/devices/config-migration.js +67 -3
- package/dist/lib/devices/health.d.ts +27 -2
- package/dist/lib/devices/health.js +39 -9
- package/dist/lib/devices/interactive-host.d.ts +15 -0
- package/dist/lib/devices/interactive-host.js +53 -0
- package/dist/lib/devices/registry.d.ts +61 -4
- package/dist/lib/devices/registry.js +94 -38
- package/dist/lib/devices/stats-cache.d.ts +26 -0
- package/dist/lib/devices/stats-cache.js +59 -7
- package/dist/lib/devices/worker-pick.d.ts +48 -0
- package/dist/lib/devices/worker-pick.js +113 -0
- package/dist/lib/exec.d.ts +70 -14
- package/dist/lib/exec.js +110 -38
- package/dist/lib/feed/answer.d.ts +29 -0
- package/dist/lib/feed/answer.js +145 -0
- package/dist/lib/feed/attention.d.ts +83 -0
- package/dist/lib/feed/attention.js +0 -0
- package/dist/lib/feed/feed.d.ts +109 -0
- package/dist/lib/feed/feed.js +154 -3
- package/dist/lib/feed/pr-status.d.ts +14 -0
- package/dist/lib/feed/pr-status.js +47 -0
- package/dist/lib/feed/watch.d.ts +59 -0
- package/dist/lib/feed/watch.js +180 -0
- package/dist/lib/fleet/capture.js +6 -0
- package/dist/lib/fleet/remote-login.js +8 -3
- package/dist/lib/fleet/types.d.ts +17 -0
- package/dist/lib/harness/adapter.d.ts +11 -0
- package/dist/lib/harness/adapters/claude.js +38 -24
- package/dist/lib/harness/adapters/codex.js +2 -4
- package/dist/lib/harness/adapters/cursor.js +8 -11
- package/dist/lib/helper-download.d.ts +108 -0
- package/dist/lib/helper-download.js +194 -0
- package/dist/lib/helper-versions.d.ts +52 -0
- package/dist/lib/helper-versions.js +58 -0
- package/dist/lib/hooks/cache.js +19 -0
- package/dist/lib/hooks/install.js +2 -2
- package/dist/lib/hooks/match.d.ts +3 -0
- package/dist/lib/hooks/match.js +25 -0
- package/dist/lib/hosts/credentials.d.ts +1 -1
- package/dist/lib/hosts/credentials.js +1 -1
- package/dist/lib/hosts/dispatch.d.ts +7 -1
- package/dist/lib/hosts/dispatch.js +24 -5
- package/dist/lib/hosts/passthrough.d.ts +8 -15
- package/dist/lib/hosts/passthrough.js +35 -16
- package/dist/lib/hosts/providers/devices.d.ts +1 -1
- package/dist/lib/hosts/providers/devices.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +179 -21
- package/dist/lib/hosts/reconnect.js +266 -45
- package/dist/lib/hosts/registry.js +7 -0
- package/dist/lib/installations/migrate.d.ts +4 -5
- package/dist/lib/installations/migrate.js +6 -7
- package/dist/lib/installations/shims.d.ts +1 -1
- package/dist/lib/installations/shims.js +23 -13
- package/dist/lib/installations/versions.js +25 -2
- package/dist/lib/linear-autoclose.d.ts +1 -1
- package/dist/lib/linear-autoclose.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/menubar/download-menubar.d.ts +47 -0
- package/dist/lib/menubar/download-menubar.js +60 -0
- package/dist/lib/menubar/install-menubar.d.ts +44 -7
- package/dist/lib/menubar/install-menubar.js +105 -23
- package/dist/lib/menubar/notify-desktop.d.ts +3 -3
- package/dist/lib/menubar/notify-desktop.js +6 -6
- package/dist/lib/model-tiers.d.ts +1 -1
- package/dist/lib/open-url.d.ts +60 -2
- package/dist/lib/open-url.js +167 -12
- package/dist/lib/project-probe.d.ts +1 -1
- package/dist/lib/project-probe.js +1 -1
- package/dist/lib/project-pull.d.ts +1 -1
- package/dist/lib/project-pull.js +2 -2
- package/dist/lib/projects.d.ts +1 -1
- package/dist/lib/projects.js +1 -1
- package/dist/lib/refresh-coordinator.d.ts +1 -1
- package/dist/lib/refresh-coordinator.js +1 -1
- package/dist/lib/sandbox.js +6 -7
- package/dist/lib/secrets/download-keychain.d.ts +47 -0
- package/dist/lib/secrets/download-keychain.js +70 -0
- package/dist/lib/secrets/install-helper.d.ts +20 -1
- package/dist/lib/secrets/install-helper.js +44 -3
- package/dist/lib/session/active.d.ts +67 -0
- package/dist/lib/session/active.js +86 -2
- package/dist/lib/session/db.d.ts +11 -1
- package/dist/lib/session/db.js +142 -8
- package/dist/lib/session/discover.d.ts +23 -1
- package/dist/lib/session/discover.js +44 -10
- package/dist/lib/session/highlights.d.ts +49 -1
- package/dist/lib/session/highlights.js +95 -0
- package/dist/lib/session/host-link.d.ts +16 -2
- package/dist/lib/session/host-link.js +7 -1
- package/dist/lib/session/parse.js +33 -1
- package/dist/lib/session/prompt.d.ts +35 -0
- package/dist/lib/session/prompt.js +56 -0
- package/dist/lib/session/remote/remote-list.d.ts +9 -0
- package/dist/lib/session/remote/remote-list.js +19 -2
- package/dist/lib/session/remote/watch.d.ts +1 -1
- package/dist/lib/session/remote/watch.js +17 -3
- package/dist/lib/session/render.js +7 -3
- package/dist/lib/session/session-cache.d.ts +53 -0
- package/dist/lib/session/session-cache.js +93 -1
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/tool-calls.d.ts +2 -0
- package/dist/lib/session/tool-calls.js +1 -1
- package/dist/lib/session/trajectory-compare.d.ts +47 -0
- package/dist/lib/session/trajectory-compare.js +116 -0
- package/dist/lib/session/trajectory-html.d.ts +19 -0
- package/dist/lib/session/trajectory-html.js +770 -0
- package/dist/lib/session/trajectory-lineage.d.ts +92 -0
- package/dist/lib/session/trajectory-lineage.js +195 -0
- package/dist/lib/session/trajectory-text.d.ts +37 -0
- package/dist/lib/session/trajectory-text.js +284 -0
- package/dist/lib/session/trajectory.d.ts +102 -0
- package/dist/lib/session/trajectory.js +384 -0
- package/dist/lib/session/types.d.ts +15 -0
- package/dist/lib/sha256-asset.d.ts +26 -0
- package/dist/lib/sha256-asset.js +41 -0
- package/dist/lib/share/backend.d.ts +95 -0
- package/dist/lib/share/backend.js +139 -0
- package/dist/lib/share/delete.d.ts +6 -2
- package/dist/lib/share/delete.js +8 -9
- package/dist/lib/share/html.d.ts +22 -0
- package/dist/lib/share/html.js +88 -0
- package/dist/lib/share/provision.d.ts +18 -4
- package/dist/lib/share/provision.js +38 -4
- package/dist/lib/share/publish.d.ts +39 -15
- package/dist/lib/share/publish.js +55 -26
- package/dist/lib/share/worker-template.js +171 -11
- package/dist/lib/sqlite.js +16 -3
- package/dist/lib/ssh-exec.d.ts +65 -0
- package/dist/lib/ssh-exec.js +120 -4
- package/dist/lib/startup/command-registry.d.ts +3 -1
- package/dist/lib/startup/command-registry.js +6 -3
- package/dist/lib/startup/dev-build.js +3 -3
- package/dist/lib/state.d.ts +2 -2
- package/dist/lib/state.js +11 -5
- package/dist/lib/subagents-registry.js +1 -1
- package/dist/lib/teams/agents.js +9 -0
- package/dist/lib/terminal/index.d.ts +1 -1
- package/dist/lib/terminal/inject.d.ts +19 -0
- package/dist/lib/terminal/inject.js +19 -9
- package/dist/lib/terminal/types.d.ts +1 -1
- package/dist/lib/terminal/types.js +1 -1
- package/dist/lib/tmux/orphan-reap.js +1 -1
- package/dist/lib/tmux/session.d.ts +46 -13
- package/dist/lib/tmux/session.js +204 -27
- package/dist/lib/traces/backend.d.ts +29 -0
- package/dist/lib/traces/backend.js +46 -0
- package/dist/lib/traces/classify.d.ts +52 -0
- package/dist/lib/traces/classify.js +72 -0
- package/dist/lib/traces/config.d.ts +10 -0
- package/dist/lib/traces/config.js +2 -0
- package/dist/lib/traces/provision.d.ts +19 -0
- package/dist/lib/traces/provision.js +30 -0
- package/dist/lib/traces/sync.d.ts +150 -0
- package/dist/lib/traces/sync.js +447 -0
- package/dist/lib/traces/worker-template.d.ts +4 -0
- package/dist/lib/traces/worker-template.js +159 -0
- package/dist/lib/types.d.ts +34 -19
- package/dist/lib/types.js +14 -0
- package/dist/lib/usage-backoff.d.ts +2 -1
- package/dist/lib/usage-backoff.js +60 -19
- package/dist/lib/usage-refresh.d.ts +18 -4
- package/dist/lib/usage-refresh.js +68 -19
- package/dist/lib/watchdog/log.d.ts +1 -1
- package/dist/lib/watchdog/log.js +1 -1
- package/dist/lib/watchdog/runner.d.ts +36 -45
- package/dist/lib/watchdog/runner.js +150 -119
- package/dist/lib/watchdog/service.d.ts +0 -1
- package/dist/lib/watchdog/service.js +0 -1
- package/dist/lib/watchdog/watchdog-agent.d.ts +38 -0
- package/dist/lib/watchdog/watchdog-agent.js +59 -0
- package/dist/lib/watchdog/watchdog.d.ts +11 -2
- package/dist/lib/watchdog/watchdog.js +37 -104
- package/dist/lib/workflows.d.ts +1 -1
- package/package.json +5 -7
- package/dist/commands/usage.d.ts +0 -27
- package/dist/commands/usage.js +0 -96
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
- 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 +0 -128
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -24
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -123
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/usage-fleet.d.ts +0 -32
- package/dist/lib/usage-fleet.js +0 -125
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
1
3
|
import chalk from 'chalk';
|
|
2
|
-
import { password } from '@inquirer/prompts';
|
|
4
|
+
import { password, select } from '@inquirer/prompts';
|
|
5
|
+
import { resolveClaudeSetupToken } from '../lib/claude-account-token.js';
|
|
3
6
|
import { setHelpSections } from '../lib/help.js';
|
|
4
7
|
import { readMeta, updateMeta } from '../lib/state.js';
|
|
5
8
|
import { ALL_AGENT_IDS, getAccountInfo, resolveAgentName } from '../lib/agents.js';
|
|
6
|
-
import { getVersionHomePath, listInstalledVersions } from '../lib/installations/versions.js';
|
|
9
|
+
import { getGlobalDefault, getVersionHomePath, listInstalledVersions } from '../lib/installations/versions.js';
|
|
7
10
|
import { assertNativeAccountNameable, nativeAccountCapability, nativeIdentityKey } from '../lib/account-capabilities.js';
|
|
8
11
|
import { collectRunCandidates } from '../lib/accounting/rotate.js';
|
|
9
|
-
import { isInteractiveTerminal } from './utils.js';
|
|
12
|
+
import { isInteractiveTerminal, isPromptCancelled, requireInteractiveSelection } from './utils.js';
|
|
10
13
|
import { buildSwitchAccountChoices, formatAccountLimits, pickSwitchAccount } from './run-account-picker.js';
|
|
11
14
|
import { profileExists, readProfile } from '../lib/profiles.js';
|
|
12
15
|
import { pushBundleToHost } from '../lib/secrets/push.js';
|
|
@@ -16,7 +19,10 @@ import { runDevicesAccounts } from './ssh.js';
|
|
|
16
19
|
import { discoverNativeAccounts } from '../lib/account-catalog.js';
|
|
17
20
|
import { readAndResolveBundleEnv } from '../lib/secrets/bundles.js';
|
|
18
21
|
import { getAccountProvider, listAccountProviders } from '../lib/account-provider-registry.js';
|
|
19
|
-
import { accountBindings, addAccount, addNativeAccount, bindAccount, findAccount, findUnifiedAccount, inspectAccount, listNativeAccounts, readAccountRegistry, removeAccount, renameAccount, setAccountSecret, unbindAccount } from '../lib/account-registry.js';
|
|
22
|
+
import { accountBindings, addAccount, addNativeAccount, bindAccount, findAccount, findUnifiedAccount, inspectAccount, labelNativeAccount, listNativeAccounts, readAccountRegistry, removeAccount, renameAccount, setAccountSecret, unbindAccount } from '../lib/account-registry.js';
|
|
23
|
+
function cleanCommandError(command, err) {
|
|
24
|
+
command.error(err instanceof Error ? err.message : String(err), { exitCode: 1, code: 'accounts.error' });
|
|
25
|
+
}
|
|
20
26
|
function parseInstallation(raw) {
|
|
21
27
|
const at = raw.lastIndexOf('@');
|
|
22
28
|
if (at < 1 || at === raw.length - 1)
|
|
@@ -63,6 +69,33 @@ export function classifyAttachTarget(target) {
|
|
|
63
69
|
return { kind: 'device-agent', agent };
|
|
64
70
|
throw new Error(`Unknown attach target '${target}'. Expected an installed <agent>@<version>, a harness id, or an existing custom harness profile.`);
|
|
65
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Persist the attached setup-token to a per-version `.oauth_token` file so an
|
|
74
|
+
* INTERACTIVE Claude launch on a keychain-less Linux worker can authenticate from it.
|
|
75
|
+
* Headless runs inject the token via `buildExecEnv`, but an interactive launch defers to
|
|
76
|
+
* the per-version login (`claudeAdapter.applyExecConfigEnv`), and the shim's Linux fallback
|
|
77
|
+
* (`claudeAdapter.shimConfigEnvBash`) reads exactly this file. Without writing it, a
|
|
78
|
+
* freshly-attached setup-token was invisible to interactive runs on a worker. macOS keeps
|
|
79
|
+
* the credential in the keychain, so `resolveClaudeSetupToken` returns null there and this
|
|
80
|
+
* is a no-op off Linux.
|
|
81
|
+
*/
|
|
82
|
+
export function writeClaudeInteractiveOauthToken(target, targetAgent) {
|
|
83
|
+
if (process.platform !== 'linux' || targetAgent !== 'claude' || target.kind !== 'installation')
|
|
84
|
+
return;
|
|
85
|
+
const versionHome = getVersionHomePath('claude', target.version);
|
|
86
|
+
const tokenPath = path.join(versionHome, '.claude', '.oauth_token');
|
|
87
|
+
const token = resolveClaudeSetupToken(versionHome);
|
|
88
|
+
// A re-point (attach B over A, or a detach) can leave no setup-token resolving for
|
|
89
|
+
// this version — B's may not be minted yet. A leftover file from the previous binding
|
|
90
|
+
// would silently authenticate interactive runs as the OLD account (the shim's Linux
|
|
91
|
+
// fallback reads it), so clear it rather than leave it stale.
|
|
92
|
+
if (!token) {
|
|
93
|
+
fs.rmSync(tokenPath, { force: true });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
fs.mkdirSync(path.dirname(tokenPath), { recursive: true });
|
|
97
|
+
fs.writeFileSync(tokenPath, token, { mode: 0o600 });
|
|
98
|
+
}
|
|
66
99
|
export function parseBundleKey(raw) {
|
|
67
100
|
const colon = raw.indexOf(':');
|
|
68
101
|
if (colon < 1 || colon === raw.length - 1)
|
|
@@ -90,18 +123,59 @@ async function printAccounts(json, fleet = false) {
|
|
|
90
123
|
console.log(JSON.stringify([...records.map(account => publicAccount(inspectAccount(account.name))), ...native], null, 2));
|
|
91
124
|
return;
|
|
92
125
|
}
|
|
93
|
-
console.log(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
126
|
+
console.log(renderAccountList(records, native));
|
|
127
|
+
}
|
|
128
|
+
/** Pure text renderer for `agents accounts list` — grouped, column-aligned, labels first-class. */
|
|
129
|
+
export function renderAccountList(records, native) {
|
|
130
|
+
const out = [];
|
|
131
|
+
// Native logins, grouped by harness — the selection surface for `<harness>#<label>`.
|
|
132
|
+
out.push(chalk.bold('Native logins') + chalk.gray(' ') + chalk.gray('run <harness>#<label>'));
|
|
133
|
+
if (!native.length) {
|
|
134
|
+
out.push(chalk.gray(' No signed-in native accounts found.'));
|
|
99
135
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
else {
|
|
137
|
+
const byHarness = new Map();
|
|
138
|
+
for (const acct of native) {
|
|
139
|
+
const list = byHarness.get(acct.agent) ?? [];
|
|
140
|
+
list.push(acct);
|
|
141
|
+
byHarness.set(acct.agent, list);
|
|
142
|
+
}
|
|
143
|
+
const harnessW = Math.max(6, ...[...byHarness.keys()].map(h => h.length));
|
|
144
|
+
const labelW = Math.max(6, ...native.map(a => (a.name ?? '—').length));
|
|
145
|
+
const idW = Math.max(8, ...native.map(a => a.display.length));
|
|
146
|
+
let sawDefault = false;
|
|
147
|
+
for (const [harness, list] of [...byHarness.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
148
|
+
const defaultVersion = getGlobalDefault(harness);
|
|
149
|
+
list.forEach((acct, i) => {
|
|
150
|
+
const harnessCell = chalk.gray((i === 0 ? harness : '').padEnd(harnessW));
|
|
151
|
+
const rawLabel = acct.name ?? '—';
|
|
152
|
+
const labelCell = acct.name ? chalk.cyan(rawLabel.padEnd(labelW)) : chalk.gray(rawLabel.padEnd(labelW));
|
|
153
|
+
const isDefault = defaultVersion ? acct.versions.includes(defaultVersion) : false;
|
|
154
|
+
if (isDefault)
|
|
155
|
+
sawDefault = true;
|
|
156
|
+
const marker = isDefault ? chalk.green('*') : ' ';
|
|
157
|
+
out.push(` ${harnessCell} ${labelCell}${marker} ${acct.display.padEnd(idW)} ${chalk.gray(acct.versions.join(', '))}`);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (sawDefault)
|
|
161
|
+
out.push(chalk.gray('\n * default account for that harness (used when you pass neither @version nor #label)'));
|
|
162
|
+
}
|
|
163
|
+
// Provider bundles — the durable API-key/setup-token accounts, selected with `--account <name>`.
|
|
164
|
+
out.push('');
|
|
165
|
+
out.push(chalk.bold('Provider bundles') + chalk.gray(' run <harness> --account <name>'));
|
|
166
|
+
if (!records.length) {
|
|
167
|
+
out.push(chalk.gray(" None. Add one with 'agents accounts add <name> --provider <provider> --auth <type>'."));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const nameW = Math.max(4, ...records.map(a => a.name.length));
|
|
171
|
+
const provW = Math.max(8, ...records.map(a => a.provider.length));
|
|
172
|
+
const authW = Math.max(10, ...records.map(a => a.auth.length));
|
|
173
|
+
for (const account of records) {
|
|
174
|
+
const present = inspectAccount(account.name).secretPresent ? chalk.green('ready') : chalk.red('missing on this device');
|
|
175
|
+
out.push(` ${chalk.cyan(account.name.padEnd(nameW))} ${account.provider.padEnd(provW)} ${account.auth.padEnd(authW)} ${present}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out.join('\n');
|
|
105
179
|
}
|
|
106
180
|
function parseAuth(raw) {
|
|
107
181
|
if (raw === 'api-key' || raw === 'setup-token' || raw === 'bearer-token')
|
|
@@ -113,6 +187,107 @@ function parseHarness(agentRaw) {
|
|
|
113
187
|
throw new Error(`Unknown agent '${agentRaw}'.`);
|
|
114
188
|
return agentRaw;
|
|
115
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Fold signed-in run candidates into distinct identities — the unit a label
|
|
192
|
+
* binds to. The same account signed into several versions is ONE row, so a
|
|
193
|
+
* multi-version single-account harness never demands a selector. Candidates
|
|
194
|
+
* with no stable identity (no accountKey, no email) are dropped: there is
|
|
195
|
+
* nothing durable for a label to bind to. Default-version identity first.
|
|
196
|
+
*/
|
|
197
|
+
export function groupLabelIdentities(candidates, defaultVersion) {
|
|
198
|
+
const byKey = new Map();
|
|
199
|
+
for (const candidate of candidates) {
|
|
200
|
+
const key = candidate.accountKey ?? candidate.email?.toLowerCase();
|
|
201
|
+
if (!key)
|
|
202
|
+
continue;
|
|
203
|
+
const row = byKey.get(key) ?? { identityKey: key, email: null, versions: [], isDefault: false };
|
|
204
|
+
row.email ??= candidate.email;
|
|
205
|
+
row.versions.push(candidate.version);
|
|
206
|
+
if (candidate.version === defaultVersion)
|
|
207
|
+
row.isDefault = true;
|
|
208
|
+
byKey.set(key, row);
|
|
209
|
+
}
|
|
210
|
+
return [...byKey.values()].sort((a, b) => a.isDefault !== b.isDefault ? (a.isDefault ? -1 : 1) : (a.email ?? a.identityKey).localeCompare(b.email ?? b.identityKey));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolve which signed-in login a bare-harness `accounts label` call means.
|
|
214
|
+
* `collect` is injectable (the `resolveRunVersion` pattern) so tests drive the
|
|
215
|
+
* real selection path against fixture candidates.
|
|
216
|
+
*/
|
|
217
|
+
export async function resolveLabelIdentity(agent, accountSelector, collect = collectRunCandidates) {
|
|
218
|
+
const candidates = (await collect(agent)).filter(candidate => candidate.signedIn);
|
|
219
|
+
const identities = groupLabelIdentities(candidates, getGlobalDefault(agent));
|
|
220
|
+
if (identities.length === 0)
|
|
221
|
+
throw new Error(`No signed-in ${agent} account with a stable identity. Run the harness and complete its login first.`);
|
|
222
|
+
const needle = accountSelector?.toLowerCase();
|
|
223
|
+
if (needle) {
|
|
224
|
+
const match = identities.find(identity => identity.email?.toLowerCase() === needle || identity.identityKey.toLowerCase() === needle);
|
|
225
|
+
if (!match)
|
|
226
|
+
throw new Error(`Unknown ${agent} account '${accountSelector}'.`);
|
|
227
|
+
return { kind: 'selected', identity: match };
|
|
228
|
+
}
|
|
229
|
+
if (identities.length === 1)
|
|
230
|
+
return { kind: 'selected', identity: identities[0] };
|
|
231
|
+
return { kind: 'ambiguous', identities };
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Body of `accounts label`, exported with the injectable candidate collector
|
|
235
|
+
* so tests exercise everything but the TTY prompt itself.
|
|
236
|
+
*/
|
|
237
|
+
export async function runAccountsLabel(source, label, opts, collect = collectRunCandidates) {
|
|
238
|
+
if (source.includes('@')) {
|
|
239
|
+
// <harness>@<version> pins the login by where it is signed in, so a
|
|
240
|
+
// second selector can only contradict it.
|
|
241
|
+
if (opts.account)
|
|
242
|
+
throw new Error(`'${source}' already selects one login; drop --account.`);
|
|
243
|
+
const identity = await nativeIdentityFromSource(source);
|
|
244
|
+
const account = labelNativeAccount(identity.agent, identity.identityKey, identity.identityLabel, label, identity.scope);
|
|
245
|
+
console.log(chalk.green(`Labeled ${identity.agent} account ${identity.identityLabel ?? identity.identityKey} as '${account.name}'.`));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const agent = parseHarness(source);
|
|
249
|
+
assertNativeAccountNameable(agent);
|
|
250
|
+
const selection = await resolveLabelIdentity(agent, opts.account, collect);
|
|
251
|
+
let selected;
|
|
252
|
+
if (selection.kind === 'selected') {
|
|
253
|
+
selected = selection.identity;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
if (!isInteractiveTerminal()) {
|
|
257
|
+
requireInteractiveSelection(`Selecting the ${agent} login to label`, [
|
|
258
|
+
`agents accounts label ${agent} ${label ?? '<label>'} --account <email|id>`,
|
|
259
|
+
`agents accounts label ${agent}@<version> ${label ?? '<label>'}`,
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
const picked = await pickLabelIdentity(agent, selection.identities);
|
|
263
|
+
if (!picked)
|
|
264
|
+
return;
|
|
265
|
+
selected = picked;
|
|
266
|
+
}
|
|
267
|
+
const account = labelNativeAccount(agent, selected.identityKey, selected.email ?? undefined, label, nativeAccountCapability(agent).scope);
|
|
268
|
+
console.log(chalk.green(`Labeled ${agent} account ${selected.email ?? selected.identityKey} as '${account.name}'.`));
|
|
269
|
+
}
|
|
270
|
+
/** Prompt for the login a label should bind to. A cancelled picker writes nothing. */
|
|
271
|
+
async function pickLabelIdentity(agent, identities) {
|
|
272
|
+
const idW = Math.max(0, ...identities.map(identity => (identity.email ?? identity.identityKey).length));
|
|
273
|
+
const choices = identities.map(identity => ({
|
|
274
|
+
name: [
|
|
275
|
+
(identity.email ?? identity.identityKey).padEnd(idW),
|
|
276
|
+
identity.isDefault ? chalk.green('default') : ' ',
|
|
277
|
+
chalk.gray(identity.versions.join(', ')),
|
|
278
|
+
].join(' '),
|
|
279
|
+
value: identity.identityKey,
|
|
280
|
+
}));
|
|
281
|
+
try {
|
|
282
|
+
const key = await select({ message: `Select the ${agent} login to label:`, choices, loop: false });
|
|
283
|
+
return identities.find(identity => identity.identityKey === key) ?? null;
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (isPromptCancelled(err))
|
|
287
|
+
return null;
|
|
288
|
+
throw err;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
116
291
|
function providerAuthenticatesHarness(provider, auth, agent) {
|
|
117
292
|
try {
|
|
118
293
|
getAccountProvider(provider).envFor(agent, auth);
|
|
@@ -273,12 +448,35 @@ export function registerAccountsCommand(program) {
|
|
|
273
448
|
});
|
|
274
449
|
accounts.command('name <source> <name>')
|
|
275
450
|
.description('Name a signed-in native installation without copying its OAuth credentials')
|
|
276
|
-
.action(async (source, name) => {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
451
|
+
.action(async (source, name, _o, command) => {
|
|
452
|
+
try {
|
|
453
|
+
const identity = await nativeIdentityFromSource(source);
|
|
454
|
+
const account = addNativeAccount(name, identity.agent, identity.identityKey, identity.identityLabel, identity.scope);
|
|
455
|
+
console.log(chalk.green(`Named ${source} as ${account.name}.`));
|
|
456
|
+
if (account.scope === 'device')
|
|
457
|
+
console.log(chalk.gray(`${identity.agent} authentication is device-scoped; attach '${account.name}' to '${identity.agent}', not an individual version.`));
|
|
458
|
+
}
|
|
459
|
+
catch (err) {
|
|
460
|
+
cleanCommandError(command, err);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
const labelCmd = accounts.command('label <source> [label]')
|
|
464
|
+
.description('Label a native login by harness or <harness>@<version>; the label binds to the account identity, not the version')
|
|
465
|
+
.option('--account <email-or-id>', 'Native identity to label when the harness has multiple logins')
|
|
466
|
+
.action(async (source, label, o, command) => {
|
|
467
|
+
try {
|
|
468
|
+
await runAccountsLabel(source, label, o);
|
|
469
|
+
}
|
|
470
|
+
catch (err) {
|
|
471
|
+
cleanCommandError(command, err);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
setHelpSections(labelCmd, {
|
|
475
|
+
examples: `agents accounts label codex work
|
|
476
|
+
agents accounts label codex@0.146.0 personal
|
|
477
|
+
agents accounts label codex work --account you@example.com
|
|
478
|
+
agents run codex#work`,
|
|
479
|
+
notes: 'The label binds to the signed-in account identity, not the version — codex#work keeps selecting that account after it moves to a newer install. One signed-in login needs no selector; with several, an interactive terminal opens a picker, while scripts pass --account or <harness>@<version>.',
|
|
282
480
|
});
|
|
283
481
|
accounts.command('attach <account> <target>')
|
|
284
482
|
.description('Attach a named account to a native installation or custom harness')
|
|
@@ -317,27 +515,46 @@ export function registerAccountsCommand(program) {
|
|
|
317
515
|
getAccountProvider(account.provider).envFor(targetAgent, account.auth);
|
|
318
516
|
}
|
|
319
517
|
bindAccount(name, target);
|
|
518
|
+
writeClaudeInteractiveOauthToken(t, targetAgent);
|
|
320
519
|
console.log(chalk.green(`Attached ${account.name} to ${target}.`));
|
|
321
520
|
});
|
|
322
521
|
accounts.command('detach <account> <target>')
|
|
323
522
|
.description('Remove one account attachment')
|
|
324
523
|
.action((name, target) => {
|
|
325
524
|
unbindAccount(name, target);
|
|
525
|
+
// With the binding gone, no setup-token resolves for this version home, so this
|
|
526
|
+
// clears any .oauth_token the attach left behind (else interactive runs would keep
|
|
527
|
+
// authenticating as the just-detached account).
|
|
528
|
+
try {
|
|
529
|
+
const t = classifyAttachTarget(target);
|
|
530
|
+
writeClaudeInteractiveOauthToken(t, t.kind === 'profile' ? t.profile.host.agent : t.agent);
|
|
531
|
+
}
|
|
532
|
+
catch { /* an unresolvable target has no version home to clean */ }
|
|
326
533
|
console.log(chalk.green(`Detached ${name} from ${target}.`));
|
|
327
534
|
});
|
|
328
535
|
accounts.command('rename <old> <new>').description('Rename an account without changing its stable id').action((oldName, newName) => renameAccount(oldName, newName));
|
|
329
536
|
accounts.command('remove <name>').description('Remove an account and its device-local credential').action((name) => removeAccount(name));
|
|
330
537
|
accounts.command('set-default <agent> <name>')
|
|
331
538
|
.description('Use this account for a harness when --account is omitted')
|
|
332
|
-
.action((agentRaw, name) => {
|
|
333
|
-
|
|
334
|
-
|
|
539
|
+
.action((agentRaw, name, _o, command) => {
|
|
540
|
+
try {
|
|
541
|
+
const { agent, account } = setDefaultAccount(agentRaw, name);
|
|
542
|
+
console.log(chalk.green(`${agent} now uses account '${account.name}' unless --account overrides it.`));
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
cleanCommandError(command, err);
|
|
546
|
+
}
|
|
335
547
|
});
|
|
336
548
|
const switchCmd = accounts.command('switch <harness> [account]')
|
|
337
549
|
.description('Pick the default account for a harness')
|
|
338
550
|
.option('--json', 'Machine-readable account list or the resulting default')
|
|
339
551
|
.action(async (harness, account, o, command) => {
|
|
340
|
-
|
|
552
|
+
try {
|
|
553
|
+
await runAccountsSwitch(harness, account, { json: !!(o.json || command.optsWithGlobals().json) });
|
|
554
|
+
}
|
|
555
|
+
catch (err) {
|
|
556
|
+
cleanCommandError(command, err);
|
|
557
|
+
}
|
|
341
558
|
});
|
|
342
559
|
accounts.command('clear-default <agent>')
|
|
343
560
|
.description('Return a harness to native login or balanced account selection')
|
|
@@ -425,6 +642,7 @@ agents run claude`,
|
|
|
425
642
|
agents accounts add openrouter-work --provider openrouter --auth api-key --from-secrets openrouter.ai:OPENROUTER_API_KEY
|
|
426
643
|
agents accounts set-key work
|
|
427
644
|
agents accounts name claude@2.1.220 work
|
|
645
|
+
agents accounts label codex@0.146.0 personal
|
|
428
646
|
agents accounts attach work claude@2.1.225
|
|
429
647
|
agents accounts view work --json
|
|
430
648
|
agents accounts switch claude
|
|
@@ -20,18 +20,19 @@ import { registerArtifactsSetupCommand } from './artifacts-setup.js';
|
|
|
20
20
|
export function registerArtifactsCommands(program) {
|
|
21
21
|
const artifactsCmd = program
|
|
22
22
|
.command('artifacts')
|
|
23
|
-
.description('Publish agent-made artifacts (plans, reports, visuals) to
|
|
23
|
+
.description('Publish agent-made artifacts (plans, reports, visuals) to a shareable link — managed if signed in, otherwise your Cloudflare R2.');
|
|
24
24
|
registerArtifactsSetupCommand(artifactsCmd);
|
|
25
25
|
registerShareCommands(artifactsCmd);
|
|
26
26
|
setHelpSections(artifactsCmd, {
|
|
27
27
|
examples: `
|
|
28
|
-
#
|
|
28
|
+
# Signed in? Just publish — no Cloudflare setup
|
|
29
|
+
agents auth login
|
|
30
|
+
agents artifacts share ./out/plan.html
|
|
31
|
+
|
|
32
|
+
# Or provision your own Cloudflare endpoint (or join a teammate's)
|
|
29
33
|
agents artifacts setup
|
|
30
34
|
agents artifacts share join https://share.agents-cli.sh
|
|
31
35
|
|
|
32
|
-
# Publish — auto OG cover, default 30d expiry, shareable link
|
|
33
|
-
agents artifacts share ./out/plan.html
|
|
34
|
-
|
|
35
36
|
# What's live in your namespace, and taking one down
|
|
36
37
|
agents artifacts share list
|
|
37
38
|
agents artifacts unshare my-plan-a1b2
|
|
@@ -50,7 +51,7 @@ export function registerArtifactsCommands(program) {
|
|
|
50
51
|
agents artifacts unshare <targets...> is the nested alias of
|
|
51
52
|
agents artifacts share delete. Top-level \`agents unshare\` is gone.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
Architecture: cli/docs/observability.md.
|
|
54
55
|
`,
|
|
55
56
|
});
|
|
56
57
|
registerUnshareCommand(artifactsCmd);
|
package/dist/commands/attach.js
CHANGED
|
@@ -50,7 +50,7 @@ export async function attachAction(id) {
|
|
|
50
50
|
// process on the owning machine.
|
|
51
51
|
const peer = sessionRecoveryPeer(meta);
|
|
52
52
|
if (peer) {
|
|
53
|
-
const routed = await runOnPeer(attachRecoveryArgs(meta), peer, { tty: true });
|
|
53
|
+
const routed = await runOnPeer(attachRecoveryArgs(meta), peer, { tty: true, sessionId: meta.id });
|
|
54
54
|
if (routed === 'no-target') {
|
|
55
55
|
console.error(chalk.red(`Cannot attach ${meta.shortId}: origin device ${peer} is not a registered reachable peer.`));
|
|
56
56
|
process.exitCode = 1;
|
package/dist/commands/auth.js
CHANGED
|
@@ -3,9 +3,10 @@ import { PhoenixApiError, clearSession, createSpace, createSpaceInvite, fetchWho
|
|
|
3
3
|
import { setHelpSections } from '../lib/help.js';
|
|
4
4
|
import { runOrDie } from '../lib/format.js';
|
|
5
5
|
/**
|
|
6
|
-
* `agents auth` — sign in to Phoenix ID, the account layer behind
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* `agents auth` — sign in to Phoenix ID, the account layer behind team spaces.
|
|
7
|
+
* Signing in is optional: every local feature works with no account. Everything
|
|
8
|
+
* here goes through `lib/identity`; this file builds no URLs and reads no
|
|
9
|
+
* credential files of its own.
|
|
9
10
|
*/
|
|
10
11
|
function sleep(ms) {
|
|
11
12
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -90,14 +91,15 @@ async function requireSpace(ref) {
|
|
|
90
91
|
export function registerAuthCommand(program) {
|
|
91
92
|
const auth = program
|
|
92
93
|
.command('auth')
|
|
93
|
-
.description('Sign in to Phoenix ID — the account layer behind spaces
|
|
94
|
+
.description('Sign in to Phoenix ID — the account layer behind team spaces');
|
|
94
95
|
setHelpSections(auth, {
|
|
95
96
|
examples: `agents auth login # device-code sign-in via your browser
|
|
96
97
|
agents auth whoami # who this machine is signed in as
|
|
97
98
|
agents auth space create "Design Team" # start a space
|
|
98
99
|
agents auth space invite ada@example.com # add a teammate
|
|
99
100
|
agents auth logout # clear this machine only`,
|
|
100
|
-
notes: `
|
|
101
|
+
notes: `Signing in is optional — every local feature works with no account; team spaces are what it unlocks.
|
|
102
|
+
Sign-in is Google-only and opens a Phoenix-branded page; the CLI never sees a password.
|
|
101
103
|
The session lives in this machine's agents state dir, so logging out here signs out nothing else.
|
|
102
104
|
Point at a different backend with PHOENIX_ID_BASE (defaults to the production service).`,
|
|
103
105
|
});
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
* second renderer. Interactive routing and the browse loop live in
|
|
11
11
|
* `sessions-picker-factory.ts` (shared with the computer twin).
|
|
12
12
|
*/
|
|
13
|
+
import { showFile } from '../lib/open-url.js';
|
|
13
14
|
import chalk from 'chalk';
|
|
14
15
|
import { itemPicker } from '../lib/picker.js';
|
|
15
16
|
import { isPromptCancelled } from './utils.js';
|
|
16
17
|
import { buildPreview } from './sessions-picker.js';
|
|
17
18
|
import { createSessionsPickerCommand } from './sessions-picker-factory.js';
|
|
18
|
-
import { runBrowserSessions, buildBrowserSessionRows, matchesBrowserSessionRow,
|
|
19
|
+
import { runBrowserSessions, buildBrowserSessionRows, matchesBrowserSessionRow, formatBytes, } from '../lib/browser/sessions-list.js';
|
|
19
20
|
import { formatRelativeTime } from '../lib/session/relative-time.js';
|
|
20
21
|
const KIND_LABEL = {
|
|
21
22
|
screenshot: 'shots',
|
|
@@ -89,11 +90,12 @@ function formatArtifactLabel(a) {
|
|
|
89
90
|
const age = formatRelativeTime(new Date(a.mtimeMs).toISOString());
|
|
90
91
|
return `${age.padEnd(11)} ${a.name.padEnd(34)} ${formatBytes(a.bytes).padStart(8)}`;
|
|
91
92
|
}
|
|
92
|
-
/** Open one artifact
|
|
93
|
-
*
|
|
94
|
-
|
|
93
|
+
/** Open one artifact, printing its path (matches the non-interactive `--open`
|
|
94
|
+
* behavior) and any open failure. Routes through the same viewer seam as
|
|
95
|
+
* `--open`, so the interactive and non-interactive halves cannot diverge. */
|
|
96
|
+
async function openAndReport(a) {
|
|
95
97
|
console.log(a.path);
|
|
96
|
-
if (
|
|
98
|
+
if ((await showFile(a.path)).via === 'none')
|
|
97
99
|
console.error(`Could not open ${a.path}`);
|
|
98
100
|
}
|
|
99
101
|
/** Second-level picker over one row's captures, newest first. Enter opens the
|
|
@@ -136,12 +138,12 @@ const browserSessionsPicker = createSessionsPickerCommand({
|
|
|
136
138
|
return;
|
|
137
139
|
}
|
|
138
140
|
if (row.artifacts.length === 1) {
|
|
139
|
-
openAndReport(row.artifacts[0]);
|
|
141
|
+
await openAndReport(row.artifacts[0]);
|
|
140
142
|
return;
|
|
141
143
|
}
|
|
142
144
|
const artifact = await pickArtifact(row);
|
|
143
145
|
if (artifact)
|
|
144
|
-
openAndReport(artifact);
|
|
146
|
+
await openAndReport(artifact);
|
|
145
147
|
},
|
|
146
148
|
});
|
|
147
149
|
/** True when the interactive picker should open instead of the printed table:
|