@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
|
@@ -4,11 +4,13 @@ import * as path from 'path';
|
|
|
4
4
|
import { BrowserCdpConnectionError, CDPClient, discoverBrowserWsUrl, verifyBrowserIdentity, } from './cdp.js';
|
|
5
5
|
import { getProfile, getProfileRuntimeDir, getProfileDownloadsDir, getProfileSessionsDir, getBrowserRuntimeDir, listProfiles, extractConfiguredPort, resolveEndpoint, parseEndpointUrl, } from './profiles.js';
|
|
6
6
|
import { killChrome, getRunningChromeInfo, launchBrowser, allocatePort } from './chrome.js';
|
|
7
|
+
import { assertRemoteControlAllowedForRequest } from './remote-control.js';
|
|
7
8
|
import { connectLocal } from './drivers/local.js';
|
|
8
9
|
import { connectSSH, shellQuote } from './drivers/ssh.js';
|
|
10
|
+
import { adoptLegacyRuntimeIfLocal, isLegacyEndpointKey, resolveBrowserTarget, shouldForkProfile, } from './resolve-target.js';
|
|
9
11
|
import { clearProfileRuntime, listProfileCacheDirs, readProfileRuntimeMeta, isProcessAlive } from './runtime-state.js';
|
|
10
12
|
import { resolveDomainSkill } from './domain-skills.js';
|
|
11
|
-
import { generateTaskId, generateShortId,
|
|
13
|
+
import { generateTaskId, generateShortId, asConnectionKey, parseConnectionKey, keyBelongsToProfile, } from './types.js';
|
|
12
14
|
import { reapAbandonedTasks, resolveLiveIdentities, taskOwnerIsGone, } from './hygiene.js';
|
|
13
15
|
import { taskMatchesCaller } from './caller-identity.js';
|
|
14
16
|
import { getRefs, resolveRefToCoords, describeRefs, healRef } from './refs.js';
|
|
@@ -297,7 +299,8 @@ export class BrowserService {
|
|
|
297
299
|
* Live browsers, keyed by {@link ConnectionKey} — NOT by profile name. The
|
|
298
300
|
* branded key type is what makes `connections.get(someProfileName)` (the
|
|
299
301
|
* RUSH-2709 miss that made `status --profile <name>` return empty for a
|
|
300
|
-
* running `<name
|
|
302
|
+
* running `<name>@<device>`) fail to compile. Keys are `<profile>@<device>`
|
|
303
|
+
* (legacy leftover `<profile>@endpoint-N` dirs are still recognized).
|
|
301
304
|
*/
|
|
302
305
|
connections = new Map();
|
|
303
306
|
forkingProfiles = new Set();
|
|
@@ -312,26 +315,21 @@ export class BrowserService {
|
|
|
312
315
|
/** Coalescing window for the `touchTask` write. See {@link touchTask}. */
|
|
313
316
|
static TOUCH_PERSIST_INTERVAL_MS = 60_000;
|
|
314
317
|
async start(profileName, opts = {}) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
const effectiveProfile = {
|
|
331
|
-
...profile,
|
|
332
|
-
binary: resolved.binary,
|
|
333
|
-
targetFilter: resolved.targetFilter,
|
|
334
|
-
};
|
|
318
|
+
// Consent gate, before anything is resolved or launched. This is the
|
|
319
|
+
// authoritative one: gating only the `browser start` COMMAND left the ~18
|
|
320
|
+
// page verbs that create a browser implicitly (navigate, click, screenshot,
|
|
321
|
+
// …) able to open a browser on a machine whose owner never opted in.
|
|
322
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
323
|
+
// Registry decides WHERE. Three outcomes, no fourth: local if this
|
|
324
|
+
// device declares the name; tunnel to a declaring device otherwise;
|
|
325
|
+
// fail loud if nobody does. Never auto-create a local browser under a
|
|
326
|
+
// name that means a logged-in browser somewhere else.
|
|
327
|
+
const routed = resolveBrowserTarget(profileName, {
|
|
328
|
+
endpointName: opts.endpointName,
|
|
329
|
+
probe: opts.probe,
|
|
330
|
+
});
|
|
331
|
+
const composite = routed.key;
|
|
332
|
+
const effectiveProfile = routed.profile;
|
|
335
333
|
const taskId = generateTaskId();
|
|
336
334
|
let taskName;
|
|
337
335
|
if (opts.taskName) {
|
|
@@ -345,23 +343,12 @@ export class BrowserService {
|
|
|
345
343
|
taskName = taskId;
|
|
346
344
|
}
|
|
347
345
|
const taskLabel = deriveTaskLabel({ title: opts.title, url: opts.url });
|
|
348
|
-
|
|
349
|
-
let
|
|
350
|
-
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
// open" and the user has no way to recover short of killing the daemon.
|
|
355
|
-
if (conn && !(await isConnHealthy(conn))) {
|
|
356
|
-
try {
|
|
357
|
-
conn.cdp.close();
|
|
358
|
-
}
|
|
359
|
-
catch { /* already closed */ }
|
|
360
|
-
conn.cleanup?.();
|
|
361
|
-
this.connections.delete(composite);
|
|
362
|
-
conn = undefined;
|
|
363
|
-
}
|
|
364
|
-
if (conn && conn.electron && conn.tasks.size > 0) {
|
|
346
|
+
const reused = await this.reuseProfileConnection(profileName, composite, routed.local);
|
|
347
|
+
let conn = reused?.conn;
|
|
348
|
+
let effectiveKey = reused?.key ?? composite;
|
|
349
|
+
// Fork is a local Electron chrome-data mint. Never fork a tunnelled
|
|
350
|
+
// connection — that would launch a logged-out browser on THIS box.
|
|
351
|
+
if (conn && routed.local && shouldForkProfile(routed.kind, conn)) {
|
|
365
352
|
if (this.forkingProfiles.has(composite)) {
|
|
366
353
|
while (this.forkingProfiles.has(composite)) {
|
|
367
354
|
await new Promise((r) => setTimeout(r, 50));
|
|
@@ -388,13 +375,14 @@ export class BrowserService {
|
|
|
388
375
|
}
|
|
389
376
|
}
|
|
390
377
|
else if (!conn) {
|
|
391
|
-
|
|
392
|
-
conn
|
|
393
|
-
|
|
394
|
-
this.connections.set(composite, conn);
|
|
395
|
-
await this.applyDefaultDownloadBehavior(conn, composite);
|
|
378
|
+
adoptLegacyRuntimeIfLocal(routed.local, profileName, composite, getBrowserRuntimeDir());
|
|
379
|
+
conn = await this.openConnection(effectiveProfile, routed.target, composite, profileName, { persistRemote: !routed.local });
|
|
380
|
+
effectiveKey = composite;
|
|
396
381
|
}
|
|
397
|
-
if (
|
|
382
|
+
if (!conn) {
|
|
383
|
+
throw new Error(`Could not connect to profile "${profileName}"`);
|
|
384
|
+
}
|
|
385
|
+
if (!conn.profile)
|
|
398
386
|
conn.profile = profileName;
|
|
399
387
|
// Browsers launch with --no-startup-window (session-cookie persistence,
|
|
400
388
|
// see launchBrowser), so a bare `start` with no --url would otherwise
|
|
@@ -515,7 +503,16 @@ export class BrowserService {
|
|
|
515
503
|
if (resolved)
|
|
516
504
|
skill = resolved;
|
|
517
505
|
}
|
|
518
|
-
return {
|
|
506
|
+
return {
|
|
507
|
+
task: taskId,
|
|
508
|
+
name: taskName,
|
|
509
|
+
tabId,
|
|
510
|
+
profile: profileName,
|
|
511
|
+
key: effectiveKey,
|
|
512
|
+
device: routed.device,
|
|
513
|
+
picked: routed.picked,
|
|
514
|
+
skill,
|
|
515
|
+
};
|
|
519
516
|
}
|
|
520
517
|
/**
|
|
521
518
|
* Reclaim a live page already showing `url` from an ABANDONED task, instead
|
|
@@ -668,7 +665,7 @@ export class BrowserService {
|
|
|
668
665
|
/**
|
|
669
666
|
* Close tasks whose owning agent session is gone, or that have sat untouched
|
|
670
667
|
* past the idle window. The entry point the daemon's periodic tick and
|
|
671
|
-
* `agents browser
|
|
668
|
+
* `agents browser prune` both call; the policy lives in `hygiene.ts`.
|
|
672
669
|
*/
|
|
673
670
|
async reapAbandoned(opts = {}) {
|
|
674
671
|
return reapAbandonedTasks(this, opts);
|
|
@@ -748,7 +745,7 @@ export class BrowserService {
|
|
|
748
745
|
return this.stop(taskName);
|
|
749
746
|
}
|
|
750
747
|
async stopProfile(profileRef) {
|
|
751
|
-
// Connections are keyed by the runtime key `<profile>@<
|
|
748
|
+
// Connections are keyed by the runtime key `<profile>@<device>` (see
|
|
752
749
|
// start()) while callers pass the bare profile name (or, occasionally, an
|
|
753
750
|
// exact key). A plain `connections.get(profileRef)` therefore missed every
|
|
754
751
|
// real remote connection, so `cleanup()` never ran — leaving the SSH tunnel
|
|
@@ -1529,8 +1526,9 @@ export class BrowserService {
|
|
|
1529
1526
|
* `profileName` is a {@link ProfileName} — a BARE name, never a runtime key.
|
|
1530
1527
|
* Every candidate is selected by the one rule ({@link keyBelongsToProfile}),
|
|
1531
1528
|
* and a scoped query that finds no live connection falls through to disk, so
|
|
1532
|
-
* `status --profile comet-local` reports the LIVE `comet-local
|
|
1533
|
-
* instead of the empty list
|
|
1529
|
+
* `status --profile comet-local` reports the LIVE `comet-local@<device>`
|
|
1530
|
+
* (and leftover `comet-local@endpoint-0` dirs) instead of the empty list
|
|
1531
|
+
* it used to return (RUSH-2709).
|
|
1534
1532
|
*/
|
|
1535
1533
|
async status(profileRef) {
|
|
1536
1534
|
// Reconnect live browsers after a daemon restart so status is not empty
|
|
@@ -2064,14 +2062,24 @@ export class BrowserService {
|
|
|
2064
2062
|
* already resolved the endpoint and built the `effectiveProfile` with
|
|
2065
2063
|
* the per-endpoint binary/targetFilter overrides applied; we just use it.
|
|
2066
2064
|
*
|
|
2067
|
-
* `key` is the runtime key (`<profile>@<
|
|
2068
|
-
* lookup uses
|
|
2069
|
-
*
|
|
2070
|
-
* because `effectiveProfile.name` stays the bare, user-facing name (RUSH-2709).
|
|
2065
|
+
* `key` is the runtime key (`<profile>@<device>`) and is what every on-disk
|
|
2066
|
+
* lookup uses. It is a SEPARATE argument because `effectiveProfile.name`
|
|
2067
|
+
* stays the bare, user-facing name (RUSH-2709).
|
|
2071
2068
|
*/
|
|
2072
|
-
async connectProfile(effectiveProfile, target, key) {
|
|
2069
|
+
async connectProfile(effectiveProfile, target, key, opts = {}) {
|
|
2073
2070
|
const existingInfo = getRunningChromeInfo(key);
|
|
2074
|
-
|
|
2071
|
+
const tunnelled = opts.persistRemote || target.startsWith('ssh:');
|
|
2072
|
+
if (tunnelled) {
|
|
2073
|
+
// A leftover local chrome-data / pid file under this key is the
|
|
2074
|
+
// pre-T2 logged-out browser on THIS box. Attaching localhost CDP
|
|
2075
|
+
// here is the original bug. Only a recorded SSH tunnel is ours to
|
|
2076
|
+
// reuse, and connectSSH already does that via isOwnTunnel.
|
|
2077
|
+
const meta = readProfileRuntimeMeta(key);
|
|
2078
|
+
if (meta && meta.kind !== 'tunnel') {
|
|
2079
|
+
clearProfileRuntime(key);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
else if (existingInfo) {
|
|
2075
2083
|
try {
|
|
2076
2084
|
const { wsUrl, browser } = await discoverBrowserWsUrl(existingInfo.port, 'localhost', effectiveProfile.name);
|
|
2077
2085
|
verifyBrowserIdentity(browser, effectiveProfile.browser, existingInfo.port);
|
|
@@ -2100,13 +2108,13 @@ export class BrowserService {
|
|
|
2100
2108
|
clearProfileRuntime(key);
|
|
2101
2109
|
}
|
|
2102
2110
|
}
|
|
2103
|
-
const conn = await this.connectEndpoint(effectiveProfile, target, key);
|
|
2111
|
+
const conn = await this.connectEndpoint(effectiveProfile, target, key, opts);
|
|
2104
2112
|
if (!conn) {
|
|
2105
2113
|
throw new Error(`Could not connect to endpoint ${target} for profile "${effectiveProfile.name}"`);
|
|
2106
2114
|
}
|
|
2107
2115
|
return conn;
|
|
2108
2116
|
}
|
|
2109
|
-
async connectEndpoint(profile, endpoint, key) {
|
|
2117
|
+
async connectEndpoint(profile, endpoint, key, opts = {}) {
|
|
2110
2118
|
const url = new URL(endpoint);
|
|
2111
2119
|
if (url.protocol === 'cdp:') {
|
|
2112
2120
|
const conn = await connectLocal(endpoint, profile, key);
|
|
@@ -2123,7 +2131,9 @@ export class BrowserService {
|
|
|
2123
2131
|
};
|
|
2124
2132
|
}
|
|
2125
2133
|
if (url.protocol === 'ssh:') {
|
|
2126
|
-
const conn = await connectSSH(endpoint, profile, key
|
|
2134
|
+
const conn = await connectSSH(endpoint, profile, key, {
|
|
2135
|
+
persistRemote: opts.persistRemote,
|
|
2136
|
+
});
|
|
2127
2137
|
await this.enableDomains(conn.cdp);
|
|
2128
2138
|
return {
|
|
2129
2139
|
cdp: conn.cdp,
|
|
@@ -2277,6 +2287,15 @@ export class BrowserService {
|
|
|
2277
2287
|
* - no handle, zero, !createIfMissing → return null (caller reports "nothing to close")
|
|
2278
2288
|
*/
|
|
2279
2289
|
async resolveOrCreateTask(opts) {
|
|
2290
|
+
// Consent gate — the one chokepoint every drive/mutate verb passes through.
|
|
2291
|
+
// ipc.ts routes each PAGE_RESOLVE_VERB and CLOSE_VERB here via bindTask, so
|
|
2292
|
+
// gating at the top refuses a fleet-remote ATTACH (an explicit --task, or a
|
|
2293
|
+
// lone identity match) exactly as it already refused an implicit CREATE.
|
|
2294
|
+
// Gating only the create branch below left tab-add/navigate/done on an
|
|
2295
|
+
// already-running browser ungated, so a remote caller could drive the
|
|
2296
|
+
// owner's authenticated profile with consent off (RUSH-3064). Read the
|
|
2297
|
+
// per-request marker, never the daemon's env — see remote-control.ts.
|
|
2298
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
2280
2299
|
if (opts.task) {
|
|
2281
2300
|
const found = await this.findTask(opts.task, opts.profile);
|
|
2282
2301
|
return { ...found, created: false };
|
|
@@ -2310,6 +2329,10 @@ export class BrowserService {
|
|
|
2310
2329
|
// Zero matches for this caller.
|
|
2311
2330
|
if (!opts.createIfMissing)
|
|
2312
2331
|
return null;
|
|
2332
|
+
// The top-of-function consent gate already refused a fleet-remote create
|
|
2333
|
+
// here — before ensureDefaultBrowserProfile() below can probe local browser
|
|
2334
|
+
// installs and persist an `auto-chrome` profile — so a refused request never
|
|
2335
|
+
// leaves state behind on the target machine.
|
|
2313
2336
|
// Implicit start on the default / named profile.
|
|
2314
2337
|
let profileName = opts.profile;
|
|
2315
2338
|
if (!profileName) {
|
|
@@ -2318,13 +2341,19 @@ export class BrowserService {
|
|
|
2318
2341
|
profileName = detected.name;
|
|
2319
2342
|
}
|
|
2320
2343
|
const started = await this.start(profileName, {
|
|
2344
|
+
fleetRemote: opts.fleetRemote,
|
|
2321
2345
|
url: opts.url,
|
|
2322
2346
|
actor: opts.actor,
|
|
2323
2347
|
launchId: opts.launchId,
|
|
2324
2348
|
sessionId: opts.sessionId,
|
|
2325
2349
|
title: opts.title,
|
|
2326
2350
|
});
|
|
2327
|
-
return {
|
|
2351
|
+
return {
|
|
2352
|
+
...(await this.findTask(started.name, started.profile)),
|
|
2353
|
+
created: true,
|
|
2354
|
+
picked: started.picked,
|
|
2355
|
+
device: started.device,
|
|
2356
|
+
};
|
|
2328
2357
|
}
|
|
2329
2358
|
listTasksForCaller(caller) {
|
|
2330
2359
|
const out = [];
|
|
@@ -2465,7 +2494,15 @@ export class BrowserService {
|
|
|
2465
2494
|
return null;
|
|
2466
2495
|
let resolved;
|
|
2467
2496
|
try {
|
|
2468
|
-
|
|
2497
|
+
// Legacy keys encode the preset (`endpoint-0`). New keys encode the
|
|
2498
|
+
// declaring device, which is not a preset name — resolve via registry.
|
|
2499
|
+
if (endpointFromKey && /^endpoint-\d+$/.test(endpointFromKey)) {
|
|
2500
|
+
resolved = resolveEndpoint(profile, endpointFromKey);
|
|
2501
|
+
}
|
|
2502
|
+
else {
|
|
2503
|
+
const routed = resolveBrowserTarget(bare);
|
|
2504
|
+
resolved = { name: routed.device, target: routed.target };
|
|
2505
|
+
}
|
|
2469
2506
|
}
|
|
2470
2507
|
catch {
|
|
2471
2508
|
return null;
|
|
@@ -2835,6 +2872,104 @@ export class BrowserService {
|
|
|
2835
2872
|
history = history.slice(0, 50);
|
|
2836
2873
|
await fs.promises.writeFile(historyFile, JSON.stringify(history, null, 2));
|
|
2837
2874
|
}
|
|
2875
|
+
/**
|
|
2876
|
+
* The cached connection for `key`, or undefined — evicting it first if the
|
|
2877
|
+
* browser died underneath us.
|
|
2878
|
+
*
|
|
2879
|
+
* A browser killed externally (Cmd-Q, crash, a user clearing the profile by
|
|
2880
|
+
* hand) leaves a closed WebSocket in the map. Without this the next
|
|
2881
|
+
* `cdp.send` throws "CDP connection not open" and there is no recovery short
|
|
2882
|
+
* of killing the daemon.
|
|
2883
|
+
*/
|
|
2884
|
+
async reuseHealthyConnection(key) {
|
|
2885
|
+
const conn = this.connections.get(key);
|
|
2886
|
+
if (!conn)
|
|
2887
|
+
return undefined;
|
|
2888
|
+
if (await isConnHealthy(conn))
|
|
2889
|
+
return conn;
|
|
2890
|
+
try {
|
|
2891
|
+
conn.cdp.close();
|
|
2892
|
+
}
|
|
2893
|
+
catch { /* already closed */ }
|
|
2894
|
+
conn.cleanup?.();
|
|
2895
|
+
this.connections.delete(key);
|
|
2896
|
+
return undefined;
|
|
2897
|
+
}
|
|
2898
|
+
/**
|
|
2899
|
+
* Reuse a live connection for this profile: the new `<name>@<device>` key
|
|
2900
|
+
* first, then any leftover `<name>@endpoint-N` key still in the map so a
|
|
2901
|
+
* browser started before the key collapse is not abandoned.
|
|
2902
|
+
*/
|
|
2903
|
+
async reuseProfileConnection(profileName, preferred, local) {
|
|
2904
|
+
const preferredConn = await this.reuseHealthyConnection(preferred);
|
|
2905
|
+
if (preferredConn)
|
|
2906
|
+
return { conn: preferredConn, key: preferred };
|
|
2907
|
+
// Leftover `@endpoint-N` connections are THIS machine's pre-T2 local
|
|
2908
|
+
// browser. Reusing them on a tunnelled resolve is the original bug.
|
|
2909
|
+
if (!local)
|
|
2910
|
+
return undefined;
|
|
2911
|
+
for (const key of [...this.connections.keys()]) {
|
|
2912
|
+
if (key === preferred)
|
|
2913
|
+
continue;
|
|
2914
|
+
if (!isLegacyEndpointKey(key, profileName))
|
|
2915
|
+
continue;
|
|
2916
|
+
if (parseConnectionKey(key).fork !== undefined)
|
|
2917
|
+
continue;
|
|
2918
|
+
const conn = await this.reuseHealthyConnection(key);
|
|
2919
|
+
if (conn)
|
|
2920
|
+
return { conn, key };
|
|
2921
|
+
}
|
|
2922
|
+
return undefined;
|
|
2923
|
+
}
|
|
2924
|
+
/** Connect a profile at `target`, register it under `key`, and arm downloads. */
|
|
2925
|
+
async openConnection(profile, target, key, profileName, opts = {}) {
|
|
2926
|
+
const conn = await this.connectProfile(profile, target, key, opts);
|
|
2927
|
+
conn.key = key;
|
|
2928
|
+
conn.profile = profileName;
|
|
2929
|
+
this.connections.set(key, conn);
|
|
2930
|
+
await this.applyDefaultDownloadBehavior(conn, key);
|
|
2931
|
+
return conn;
|
|
2932
|
+
}
|
|
2933
|
+
/**
|
|
2934
|
+
* Open a tab for a HUMAN to read, bound to no task.
|
|
2935
|
+
*
|
|
2936
|
+
* That is the entire difference from {@link start}, and it is the point. The
|
|
2937
|
+
* abandoned-task reaper closes a task's tabs when the calling session dies or
|
|
2938
|
+
* after the idle window, but it "deliberately never touches a tab that is not
|
|
2939
|
+
* in `task.tabs`" (hygiene.ts) — so a viewer tab must not be in one, or the
|
|
2940
|
+
* artifact the user is reading vanishes when the agent that rendered it exits.
|
|
2941
|
+
*
|
|
2942
|
+
* Consequently `stop`/`done` do not close it either, which is correct: it is
|
|
2943
|
+
* the user's tab now.
|
|
2944
|
+
*/
|
|
2945
|
+
async showUrl(profileName, url, opts = {}) {
|
|
2946
|
+
// Same consent gate as start(): this opens a browser, so a fleet-remote
|
|
2947
|
+
// caller needs the target machine's opt-in.
|
|
2948
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
2949
|
+
const routed = resolveBrowserTarget(profileName, {
|
|
2950
|
+
endpointName: opts.endpointName,
|
|
2951
|
+
probe: opts.probe,
|
|
2952
|
+
});
|
|
2953
|
+
const key = routed.key;
|
|
2954
|
+
const effectiveProfile = routed.profile;
|
|
2955
|
+
const reused = await this.reuseProfileConnection(profileName, key, routed.local);
|
|
2956
|
+
let conn = reused?.conn;
|
|
2957
|
+
const effectiveKey = reused?.key ?? key;
|
|
2958
|
+
if (!conn) {
|
|
2959
|
+
adoptLegacyRuntimeIfLocal(routed.local, profileName, key, getBrowserRuntimeDir());
|
|
2960
|
+
conn = await this.openConnection(effectiveProfile, routed.target, key, profileName, { persistRemote: !routed.local });
|
|
2961
|
+
}
|
|
2962
|
+
// createPageTarget refuses Arc with an actionable error rather than crashing it.
|
|
2963
|
+
const created = await this.createPageTarget(conn, { url });
|
|
2964
|
+
this.invalidateTargetCache(conn);
|
|
2965
|
+
return {
|
|
2966
|
+
profile: profileName,
|
|
2967
|
+
key: effectiveKey,
|
|
2968
|
+
tabId: created.targetId,
|
|
2969
|
+
device: routed.device,
|
|
2970
|
+
picked: routed.picked,
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2838
2973
|
async getHistory(limit = 10) {
|
|
2839
2974
|
const historyFile = path.join(getBrowserRuntimeDir(), 'history.json');
|
|
2840
2975
|
if (!fs.existsSync(historyFile))
|
|
@@ -32,8 +32,6 @@ export declare function renderBrowserSessions(groups: ProfileArtifacts[]): strin
|
|
|
32
32
|
* substring match. Returns the absolute path, or null if nothing matched.
|
|
33
33
|
*/
|
|
34
34
|
export declare function resolveArtifact(groups: ProfileArtifacts[], selector: string): string | null;
|
|
35
|
-
/** Open a file in the OS default app. Returns true on success. */
|
|
36
|
-
export declare function openArtifact(filePath: string): boolean;
|
|
37
35
|
/** The identity fields this module cares about for one task. */
|
|
38
36
|
export interface TaskIdentity {
|
|
39
37
|
owner?: string;
|
|
@@ -139,4 +137,4 @@ export declare function runBrowserSessions(opts: {
|
|
|
139
137
|
profile?: string;
|
|
140
138
|
open?: string | boolean;
|
|
141
139
|
json?: boolean;
|
|
142
|
-
}): void
|
|
140
|
+
}): Promise<void>;
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* problem (pid registry, the SessionStart hook index, the activity log; see
|
|
15
15
|
* `feed-post.ts` `resolvePostIdentity`), never a second parser.
|
|
16
16
|
*/
|
|
17
|
+
import { showFile } from '../open-url.js';
|
|
17
18
|
import * as fs from 'fs';
|
|
18
19
|
import { formatBytes } from '../format.js';
|
|
19
20
|
// Re-exported for the picker, which lists artifacts from this module's rows.
|
|
20
21
|
export { formatBytes };
|
|
21
22
|
import * as path from 'path';
|
|
22
|
-
import { spawnSync } from 'child_process';
|
|
23
23
|
import { getBrowserRuntimeDir, getProfileRuntimeDir } from './profiles.js';
|
|
24
24
|
import { formatRelativeTime } from '../session/relative-time.js';
|
|
25
25
|
import { getSessionById, listBrowserSessionRecords, pruneToolSessions } from '../session/db.js';
|
|
@@ -158,19 +158,6 @@ export function resolveArtifact(groups, selector) {
|
|
|
158
158
|
const hit = all.find((a) => a.name === selector) ?? all.find((a) => a.name.includes(selector));
|
|
159
159
|
return hit ? hit.path : null;
|
|
160
160
|
}
|
|
161
|
-
/** Open a file in the OS default app. Returns true on success. */
|
|
162
|
-
export function openArtifact(filePath) {
|
|
163
|
-
const openers = process.platform === 'darwin'
|
|
164
|
-
? [['open', [filePath]]]
|
|
165
|
-
: process.platform === 'win32'
|
|
166
|
-
? [['cmd', ['/c', 'start', '""', filePath]]]
|
|
167
|
-
: [['xdg-open', [filePath]], ['gnome-open', [filePath]]];
|
|
168
|
-
for (const [cmd, args] of openers) {
|
|
169
|
-
if (spawnSync(cmd, args, { stdio: 'ignore' }).status === 0)
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
161
|
/**
|
|
175
162
|
* Read a profile's `tasks.json` for the identity of its CURRENTLY LIVE tasks,
|
|
176
163
|
* keyed by task name. A task's entry is deleted on `agents browser stop` (see
|
|
@@ -380,7 +367,7 @@ export function matchesBrowserSessionRow(row, query) {
|
|
|
380
367
|
* `open` is the Commander value for `--open [selector]`: undefined when the flag
|
|
381
368
|
* is absent, `true` when passed bare (defaults to 'latest'), or the selector string.
|
|
382
369
|
*/
|
|
383
|
-
export function runBrowserSessions(opts) {
|
|
370
|
+
export async function runBrowserSessions(opts) {
|
|
384
371
|
const groups = listBrowserSessions(opts.profile);
|
|
385
372
|
if (opts.open !== undefined && opts.open !== false) {
|
|
386
373
|
const selector = opts.open === true ? 'latest' : opts.open;
|
|
@@ -390,7 +377,7 @@ export function runBrowserSessions(opts) {
|
|
|
390
377
|
process.exit(1);
|
|
391
378
|
}
|
|
392
379
|
console.log(target);
|
|
393
|
-
if (
|
|
380
|
+
if ((await showFile(target)).via === 'none') {
|
|
394
381
|
console.error(`Could not open ${target}`);
|
|
395
382
|
process.exit(1);
|
|
396
383
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface TaskBinding {
|
|
2
|
+
device: string;
|
|
3
|
+
profile?: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
launchId?: string;
|
|
7
|
+
createdAt: number;
|
|
8
|
+
}
|
|
9
|
+
export type TaskIndex = Record<string, TaskBinding>;
|
|
10
|
+
export declare const REJECT_DEVICE_MESSAGE: string;
|
|
11
|
+
export type TaskRoute = {
|
|
12
|
+
kind: 'proceed';
|
|
13
|
+
task?: string;
|
|
14
|
+
device: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'unknown';
|
|
17
|
+
task: string;
|
|
18
|
+
message: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'ambiguous';
|
|
21
|
+
message: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'reject-device';
|
|
24
|
+
message: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function taskIndexPath(): string;
|
|
27
|
+
export declare function readTaskIndex(): TaskIndex;
|
|
28
|
+
export declare function getTaskBinding(name: string): TaskBinding | undefined;
|
|
29
|
+
export declare function listTaskBindings(): Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
} & TaskBinding>;
|
|
32
|
+
export declare function bindTask(name: string, binding: TaskBinding): void;
|
|
33
|
+
export declare function updateTaskBinding(name: string, patch: Partial<TaskBinding>): void;
|
|
34
|
+
export declare function unbindTask(name: string): void;
|
|
35
|
+
/** Drop every binding recorded under this profile (after `stop --profile` / gc). */
|
|
36
|
+
export declare function unbindTasksForProfile(profile: string): void;
|
|
37
|
+
export declare function tasksForCaller(sessionId?: string, launchId?: string): Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
} & TaskBinding>;
|
|
40
|
+
export declare function formatOpenTaskList(entries: Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
} & TaskBinding>, now?: number): string;
|
|
43
|
+
export declare function unknownTaskMessage(name: string, entries?: ({
|
|
44
|
+
name: string;
|
|
45
|
+
} & TaskBinding)[]): string;
|
|
46
|
+
export declare function ambiguousTasksMessage(entries: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
} & TaskBinding>): string;
|
|
49
|
+
/**
|
|
50
|
+
* Decide where a page verb should run.
|
|
51
|
+
*
|
|
52
|
+
* `--device` on a later verb is always rejected (bind it at start).
|
|
53
|
+
* A named task that is not in the local index fails loud with the open-task
|
|
54
|
+
* list. Two or more tasks for this caller, with no `--task`, fail the same way.
|
|
55
|
+
* Zero matches with no `--task` proceeds locally — the daemon still resolves
|
|
56
|
+
* from caller identity for the first implicit create.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveTaskRoute(opts: {
|
|
59
|
+
task?: string;
|
|
60
|
+
device?: string;
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
launchId?: string;
|
|
63
|
+
self?: string;
|
|
64
|
+
}): TaskRoute;
|
|
65
|
+
/**
|
|
66
|
+
* The daemon sandboxes screenshot writes to the browser runtime dir, so `-o`
|
|
67
|
+
* outside that dir is ignored there. The CLI process honors `-o` by copying
|
|
68
|
+
* the captured file to the requested path. Same path → no copy.
|
|
69
|
+
*/
|
|
70
|
+
export declare function honorScreenshotOutput(requested: string | undefined, daemonPath: string): string;
|