@phnx-labs/agents-cli 1.22.40 → 1.22.42
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 +36 -0
- package/README.md +14 -3
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.js +0 -1
- package/dist/cli/command-registry.d.ts +2 -0
- package/dist/cli/command-registry.js +5 -2
- package/dist/commands/accounts.d.ts +29 -0
- package/dist/commands/accounts.js +220 -29
- package/dist/commands/alias.js +1 -1
- package/dist/commands/auth.d.ts +9 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/browser-sessions-picker.js +42 -62
- package/dist/commands/browser.d.ts +15 -0
- package/dist/commands/browser.js +145 -78
- package/dist/commands/computer-actions.d.ts +1 -1
- package/dist/commands/computer-actions.js +1 -1
- package/dist/commands/computer-sessions-picker.js +32 -55
- package/dist/commands/computer.d.ts +1 -1
- package/dist/commands/computer.js +2 -2
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/feed.js +4 -12
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +1 -1
- package/dist/commands/insights.js +163 -85
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/mine.js +1 -1
- package/dist/commands/org.d.ts +6 -0
- package/dist/commands/org.js +174 -0
- package/dist/commands/packages.js +1 -1
- package/dist/commands/prune.js +1 -1
- package/dist/commands/routines.js +1 -1
- package/dist/commands/run-account-picker.d.ts +19 -0
- package/dist/commands/run-account-picker.js +81 -0
- package/dist/commands/secrets.js +87 -97
- package/dist/commands/sessions-picker-factory.d.ts +40 -0
- package/dist/commands/sessions-picker-factory.js +67 -0
- package/dist/commands/sessions-picker.d.ts +1 -0
- package/dist/commands/sessions-picker.js +27 -5
- package/dist/commands/sessions-share.d.ts +25 -0
- package/dist/commands/sessions-share.js +166 -0
- package/dist/commands/sessions.js +2 -0
- package/dist/commands/setup-browser.js +5 -5
- package/dist/commands/setup-mine.js +1 -1
- package/dist/commands/setup-preferences.js +4 -4
- package/dist/commands/setup.js +5 -3
- package/dist/commands/sync.js +1 -1
- package/dist/commands/versions.js +1 -1
- package/dist/commands/view.js +1 -1
- package/dist/commands/webhook.js +14 -9
- package/dist/lib/account-capabilities.d.ts +10 -0
- package/dist/lib/account-capabilities.js +34 -0
- package/dist/lib/agent-spec/agents.d.ts +584 -0
- package/dist/lib/agent-spec/agents.js +3127 -0
- package/dist/lib/agent-spec/provider.js +1 -1
- package/dist/lib/agents.d.ts +2 -584
- package/dist/lib/agents.js +2 -3127
- package/dist/lib/browser/cdp.js +4 -0
- package/dist/lib/browser/chrome.js +12 -1
- package/dist/lib/browser/drivers/local.d.ts +8 -2
- package/dist/lib/browser/drivers/local.js +8 -2
- package/dist/lib/browser/drivers/ssh.d.ts +8 -2
- package/dist/lib/browser/drivers/ssh.js +11 -4
- package/dist/lib/browser/hygiene.d.ts +1 -1
- package/dist/lib/browser/hygiene.js +5 -1
- package/dist/lib/browser/profiles.d.ts +77 -4
- package/dist/lib/browser/profiles.js +121 -12
- package/dist/lib/browser/runtime-state.d.ts +11 -5
- package/dist/lib/browser/runtime-state.js +13 -9
- package/dist/lib/browser/service.d.ts +91 -30
- package/dist/lib/browser/service.js +342 -207
- package/dist/lib/browser/types.d.ts +96 -4
- package/dist/lib/browser/types.js +51 -0
- package/dist/lib/catchup.js +1 -1
- package/dist/lib/computer/actions.d.ts +1 -1
- package/dist/lib/computer/actions.js +1 -1
- package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
- package/dist/lib/computer/dispatch.d.ts +1 -1
- package/dist/lib/computer/download.d.ts +1 -1
- package/dist/lib/computer/download.js +3 -3
- package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
- package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
- package/dist/lib/daemon/daemon.js +1 -1
- package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +10 -10
- package/dist/lib/{runner.js → daemon/runner.js} +59 -118
- package/dist/lib/daemon-webhooks.d.ts +3 -1
- package/dist/lib/daemon-webhooks.js +12 -7
- package/dist/lib/device-config.js +1 -1
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/doctor-findings.js +3 -3
- package/dist/lib/devices/fleet-inventory.js +1 -1
- package/dist/lib/devices/harness-inventory.js +1 -1
- package/dist/lib/devices/registry.js +4 -22
- package/dist/lib/doctor-diff.d.ts +1 -1
- package/dist/lib/doctor-diff.js +1 -1
- package/dist/lib/drift.js +1 -1
- package/dist/lib/entitlement.d.ts +31 -0
- package/dist/lib/entitlement.js +137 -0
- package/dist/lib/exec.js +39 -202
- package/dist/lib/feed/feed.js +2 -8
- package/dist/lib/fs-atomic.d.ts +7 -0
- package/dist/lib/fs-atomic.js +9 -0
- package/dist/lib/harness/adapter.d.ts +160 -0
- package/dist/lib/harness/adapter.js +47 -0
- package/dist/lib/harness/adapters/claude.d.ts +2 -0
- package/dist/lib/harness/adapters/claude.js +110 -0
- package/dist/lib/harness/adapters/codex.d.ts +2 -0
- package/dist/lib/harness/adapters/codex.js +83 -0
- package/dist/lib/harness/adapters/copilot.d.ts +2 -0
- package/dist/lib/harness/adapters/copilot.js +23 -0
- package/dist/lib/harness/adapters/cursor.d.ts +2 -0
- package/dist/lib/harness/adapters/cursor.js +38 -0
- package/dist/lib/harness/adapters/droid.d.ts +2 -0
- package/dist/lib/harness/adapters/droid.js +17 -0
- package/dist/lib/harness/adapters/grok.d.ts +2 -0
- package/dist/lib/harness/adapters/grok.js +14 -0
- package/dist/lib/harness/adapters/kimi.d.ts +2 -0
- package/dist/lib/harness/adapters/kimi.js +49 -0
- package/dist/lib/harness/adapters/muse.d.ts +2 -0
- package/dist/lib/harness/adapters/muse.js +44 -0
- package/dist/lib/harness/adapters/opencode.d.ts +2 -0
- package/dist/lib/harness/adapters/opencode.js +14 -0
- package/dist/lib/harness/exec-config-version.d.ts +8 -0
- package/dist/lib/harness/exec-config-version.js +22 -0
- package/dist/lib/harness/index.d.ts +1 -0
- package/dist/lib/harness/index.js +34 -0
- package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
- package/dist/lib/{hooks.js → hooks/install.js} +11 -11
- package/dist/lib/import.js +1 -1
- package/dist/lib/installations/index.d.ts +4 -4
- package/dist/lib/installations/index.js +3 -4
- package/dist/lib/installations/migrate.js +6 -6
- package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
- package/dist/lib/{shims.js → installations/shims.js} +12 -114
- package/dist/lib/installations/store.d.ts +141 -3
- package/dist/lib/installations/store.js +475 -5
- package/dist/lib/installations/versions.d.ts +1 -126
- package/dist/lib/installations/versions.js +5 -465
- package/dist/lib/isolation-boundary-report.d.ts +1 -1
- package/dist/lib/isolation-boundary-report.js +1 -1
- package/dist/lib/mailbox-gc.js +2 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/monitors/dispatch.d.ts +1 -1
- package/dist/lib/monitors/dispatch.js +2 -2
- package/dist/lib/monitors/state.d.ts +1 -1
- package/dist/lib/observe-aliases.d.ts +2 -2
- package/dist/lib/observe-aliases.js +2 -11
- package/dist/lib/plugins/plugins.js +1 -1
- package/dist/lib/plugins/skills.js +1 -1
- package/dist/lib/prix-account.d.ts +158 -0
- package/dist/lib/prix-account.js +214 -0
- package/dist/lib/project-key.js +7 -0
- package/dist/lib/project-launch.js +1 -1
- package/dist/lib/refresh.js +2 -2
- package/dist/lib/resource-inventory.d.ts +1 -1
- package/dist/lib/resource-inventory.js +1 -1
- package/dist/lib/rules/rules.js +1 -1
- package/dist/lib/scheduling/routines.js +1 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/bundles.d.ts +1 -1
- package/dist/lib/secrets/bundles.js +1 -1
- package/dist/lib/secrets/headless.d.ts +16 -0
- package/dist/lib/secrets/headless.js +21 -0
- package/dist/lib/secrets/remote.d.ts +9 -7
- package/dist/lib/secrets/remote.js +18 -9
- package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
- package/dist/lib/self-heal/checks/path.js +1 -1
- package/dist/lib/self-heal/checks/shadowing.js +1 -1
- package/dist/lib/self-heal/checks/shims.js +1 -1
- package/dist/lib/session/discover.d.ts +39 -0
- package/dist/lib/session/discover.js +3 -3
- package/dist/lib/session/parse.js +24 -42
- package/dist/lib/session/recovery.js +1 -1
- package/dist/lib/session/share-html.d.ts +55 -0
- package/dist/lib/session/share-html.js +319 -0
- package/dist/lib/settings-manifest.d.ts +2 -0
- package/dist/lib/settings-manifest.js +81 -3
- package/dist/lib/share/publish.d.ts +38 -0
- package/dist/lib/share/publish.js +81 -8
- package/dist/lib/staleness/prune.d.ts +1 -1
- package/dist/lib/staleness/prune.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +2 -1
- package/dist/lib/startup/command-registry.js +5 -3
- package/dist/lib/teams/agents.js +2 -19
- package/dist/lib/teams/parsers.js +20 -26
- package/dist/lib/teams/registry.js +2 -21
- package/dist/lib/triggers/handlers.d.ts +37 -2
- package/dist/lib/triggers/handlers.js +57 -6
- package/dist/lib/triggers/webhook.d.ts +80 -6
- package/dist/lib/triggers/webhook.js +128 -4
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/uninstall.js +1 -1
- package/dist/lib/version.d.ts +9 -2
- package/dist/lib/version.js +11 -9
- package/dist/lib/wrap.d.ts +33 -0
- package/dist/lib/wrap.js +70 -0
- package/package.json +1 -1
- /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { setHelpSections } from '../lib/help.js';
|
|
3
|
+
import { clearPrixSession, fetchWhoAmI, pollDeviceToken, PrixApiError, readPrixSession, resolvePrixToken, startDeviceAuthorization, writePrixSession, } from '../lib/prix-account.js';
|
|
4
|
+
function sleep(ms) {
|
|
5
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* `agents auth login` — RFC 8628 device-code flow against the already-shipped
|
|
9
|
+
* `/api/v1/auth/device/*` routes. If the live API rejects the request shape
|
|
10
|
+
* (a route this spec missed, or the endpoint moved), this fails loud with the
|
|
11
|
+
* `rush login` fallback rather than silently stubbing a fake session.
|
|
12
|
+
*/
|
|
13
|
+
export async function runAuthLogin() {
|
|
14
|
+
let authorization;
|
|
15
|
+
try {
|
|
16
|
+
authorization = await startDeviceAuthorization();
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
20
|
+
const existing = resolvePrixToken();
|
|
21
|
+
if (existing?.source === 'rush') {
|
|
22
|
+
console.log(chalk.yellow(`Device login is unavailable right now (${message}), but you're already signed in via 'rush login'.`));
|
|
23
|
+
console.log("Run 'agents auth whoami' to confirm.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`Device login is unavailable right now (${message}). Run 'rush login' instead, then 'agents auth whoami' to confirm.`);
|
|
27
|
+
}
|
|
28
|
+
console.log(`To sign in, open:\n\n ${chalk.cyan(authorization.verification_uri_complete)}\n`);
|
|
29
|
+
console.log(chalk.gray(`(code: ${authorization.user_code})`));
|
|
30
|
+
const deadline = Date.now() + authorization.expires_in * 1000;
|
|
31
|
+
let interval = Math.max(authorization.interval, 1) * 1000;
|
|
32
|
+
while (Date.now() < deadline) {
|
|
33
|
+
await sleep(interval);
|
|
34
|
+
const poll = await pollDeviceToken(authorization.device_code);
|
|
35
|
+
if (poll.status === 'pending')
|
|
36
|
+
continue;
|
|
37
|
+
if (poll.status === 'slow_down') {
|
|
38
|
+
interval += 1000;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (poll.status === 'expired')
|
|
42
|
+
throw new Error('Login code expired. Run `agents auth login` again.');
|
|
43
|
+
if (poll.status === 'denied')
|
|
44
|
+
throw new Error('Login was denied.');
|
|
45
|
+
writePrixSession({
|
|
46
|
+
access_token: poll.access_token,
|
|
47
|
+
refresh_token: poll.refresh_token,
|
|
48
|
+
expires_at: poll.expires_in ? Date.now() + poll.expires_in * 1000 : undefined,
|
|
49
|
+
email: poll.user.email,
|
|
50
|
+
userId: poll.user.id,
|
|
51
|
+
});
|
|
52
|
+
console.log(chalk.green(`Signed in as ${poll.user.email}.`));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
throw new Error('Login code expired. Run `agents auth login` again.');
|
|
56
|
+
}
|
|
57
|
+
async function runAuthWhoami(json) {
|
|
58
|
+
const resolved = resolvePrixToken();
|
|
59
|
+
if (!resolved)
|
|
60
|
+
throw new Error("Not signed in. Run 'agents auth login' first.");
|
|
61
|
+
let who;
|
|
62
|
+
try {
|
|
63
|
+
who = await fetchWhoAmI(resolved.token);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (err instanceof PrixApiError && err.status === 401) {
|
|
67
|
+
throw new Error(`Signed-in token is no longer valid (${resolved.source === 'agents' ? "run 'agents auth login'" : "run 'rush login'"} again).`);
|
|
68
|
+
}
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
if (json) {
|
|
72
|
+
console.log(JSON.stringify({ ...who, source: resolved.source }, null, 2));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log(`${chalk.bold(who.email)} ${chalk.gray(who.userId)}`);
|
|
76
|
+
console.log(chalk.gray(`signed in via ${resolved.source === 'agents' ? "'agents auth login'" : "'rush login' (shared session)"}`));
|
|
77
|
+
}
|
|
78
|
+
function runAuthLogout() {
|
|
79
|
+
const cleared = clearPrixSession();
|
|
80
|
+
const rushRemains = resolvePrixToken()?.source === 'rush';
|
|
81
|
+
if (!cleared && !readPrixSession()) {
|
|
82
|
+
console.log(chalk.gray('Not signed in via `agents auth login` — nothing to clear.'));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(chalk.green('Signed out.'));
|
|
86
|
+
}
|
|
87
|
+
if (rushRemains) {
|
|
88
|
+
console.log(chalk.gray("You're still signed in via `rush login` — `agents auth whoami` will use that session. Run `rush logout` to clear it too."));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function registerAuthCommand(program) {
|
|
92
|
+
const auth = program.command('auth').description('Sign in to your Rush account (shared by `agents org` and paid tiers)');
|
|
93
|
+
auth.command('login').description('Sign in via the device-code flow').action(async () => runAuthLogin());
|
|
94
|
+
auth.command('whoami').description('Show the signed-in account').option('--json', 'Machine-readable output')
|
|
95
|
+
.action((o, command) => runAuthWhoami(!!(o.json || command.optsWithGlobals().json)));
|
|
96
|
+
auth.command('logout').description('Clear the local `agents auth login` session').action(() => runAuthLogout());
|
|
97
|
+
setHelpSections(auth, {
|
|
98
|
+
examples: `agents auth login
|
|
99
|
+
agents auth whoami
|
|
100
|
+
agents auth whoami --json
|
|
101
|
+
agents auth logout`,
|
|
102
|
+
notes: "`agents auth login` writes its own session, separate from \`rush login\`'s \`~/.rush/user.yaml\` — \`agents auth logout\` never signs you out of \`rush\`. If you're already signed in via \`rush login\`, \`agents auth whoami\`/\`agents org\` use that session automatically; no separate login is required.",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -7,36 +7,16 @@
|
|
|
7
7
|
* Reuses the same `itemPicker` + `buildPreview` primitives as the ordinary
|
|
8
8
|
* session picker (`sessions-picker.ts`) — same search/filter/quit help, and the
|
|
9
9
|
* preview pane for a linked task IS the canonical session digest, not a
|
|
10
|
-
* second renderer.
|
|
10
|
+
* second renderer. Interactive routing and the browse loop live in
|
|
11
|
+
* `sessions-picker-factory.ts` (shared with the computer twin).
|
|
11
12
|
*/
|
|
12
13
|
import chalk from 'chalk';
|
|
13
14
|
import { itemPicker } from '../lib/picker.js';
|
|
14
|
-
import {
|
|
15
|
+
import { isPromptCancelled } from './utils.js';
|
|
15
16
|
import { buildPreview } from './sessions-picker.js';
|
|
17
|
+
import { createSessionsPickerCommand } from './sessions-picker-factory.js';
|
|
16
18
|
import { runBrowserSessions, buildBrowserSessionRows, matchesBrowserSessionRow, openArtifact, formatBytes, } from '../lib/browser/sessions-list.js';
|
|
17
19
|
import { formatRelativeTime } from '../lib/session/relative-time.js';
|
|
18
|
-
/** True when the interactive picker should open instead of the printed table:
|
|
19
|
-
* a real TTY, no `--json`/`--open`, and `--no-interactive` not set. */
|
|
20
|
-
export function shouldOpenInteractiveBrowserSessions(opts, isTTY) {
|
|
21
|
-
return opts.interactive !== false && !opts.json && opts.open === undefined && isTTY;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Shared entry point for `agents browser sessions` and `agents sessions
|
|
25
|
-
* --browser`. Replaces direct calls to `runBrowserSessions` at both call
|
|
26
|
-
* sites so the interactive routing decision lives in one place.
|
|
27
|
-
*/
|
|
28
|
-
export async function runBrowserSessionsCommand(opts) {
|
|
29
|
-
if (!shouldOpenInteractiveBrowserSessions(opts, isInteractiveTerminal())) {
|
|
30
|
-
runBrowserSessions({ profile: opts.profile, open: opts.open, json: opts.json });
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const rows = buildBrowserSessionRows(opts.profile);
|
|
34
|
-
if (rows.length === 0) {
|
|
35
|
-
console.log(`No browser captures found${opts.profile ? ` for profile "${opts.profile}"` : ''}.`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
await browseAndOpen(rows);
|
|
39
|
-
}
|
|
40
20
|
const KIND_LABEL = {
|
|
41
21
|
screenshot: 'shots',
|
|
42
22
|
pdf: 'pdf',
|
|
@@ -116,44 +96,6 @@ function openAndReport(a) {
|
|
|
116
96
|
if (!openArtifact(a.path))
|
|
117
97
|
console.error(`Could not open ${a.path}`);
|
|
118
98
|
}
|
|
119
|
-
/** Task-level picker with a captures preview, then an artifact drill-down when
|
|
120
|
-
* a task holds more than one capture. Loops until the user quits (esc) so a
|
|
121
|
-
* capture-heavy task can be browsed and opened repeatedly in one session. */
|
|
122
|
-
async function browseAndOpen(rows) {
|
|
123
|
-
for (;;) {
|
|
124
|
-
let picked;
|
|
125
|
-
try {
|
|
126
|
-
picked = await itemPicker({
|
|
127
|
-
message: 'Browser sessions:',
|
|
128
|
-
items: rows,
|
|
129
|
-
filter: (query) => (query.trim() ? rows.filter((r) => matchesBrowserSessionRow(r, query)) : rows),
|
|
130
|
-
labelFor: (row) => formatRowLabel(row),
|
|
131
|
-
buildPreview: (row) => buildRowPreview(row),
|
|
132
|
-
emptyMessage: 'No browser sessions match.',
|
|
133
|
-
enterHint: 'open capture',
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
catch (err) {
|
|
137
|
-
if (isPromptCancelled(err))
|
|
138
|
-
return;
|
|
139
|
-
throw err;
|
|
140
|
-
}
|
|
141
|
-
if (!picked)
|
|
142
|
-
return;
|
|
143
|
-
const row = picked.item;
|
|
144
|
-
if (row.artifacts.length === 0) {
|
|
145
|
-
console.log('No captures in this task yet.');
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (row.artifacts.length === 1) {
|
|
149
|
-
openAndReport(row.artifacts[0]);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const artifact = await pickArtifact(row);
|
|
153
|
-
if (artifact)
|
|
154
|
-
openAndReport(artifact);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
99
|
/** Second-level picker over one row's captures, newest first. Enter opens the
|
|
158
100
|
* highlighted capture; esc returns to the task list. */
|
|
159
101
|
async function pickArtifact(row) {
|
|
@@ -177,3 +119,41 @@ async function pickArtifact(row) {
|
|
|
177
119
|
throw err;
|
|
178
120
|
}
|
|
179
121
|
}
|
|
122
|
+
const browserSessionsPicker = createSessionsPickerCommand({
|
|
123
|
+
requireOpenUndefined: true,
|
|
124
|
+
runFlat: (opts) => runBrowserSessions({ profile: opts.profile, open: opts.open, json: opts.json }),
|
|
125
|
+
buildRows: (opts) => buildBrowserSessionRows(opts.profile),
|
|
126
|
+
emptyMessage: (opts) => `No browser captures found${opts.profile ? ` for profile "${opts.profile}"` : ''}.`,
|
|
127
|
+
message: 'Browser sessions:',
|
|
128
|
+
matches: matchesBrowserSessionRow,
|
|
129
|
+
labelFor: formatRowLabel,
|
|
130
|
+
buildPreview: buildRowPreview,
|
|
131
|
+
emptyFilterMessage: 'No browser sessions match.',
|
|
132
|
+
enterHint: 'open capture',
|
|
133
|
+
onOpen: async (row) => {
|
|
134
|
+
if (row.artifacts.length === 0) {
|
|
135
|
+
console.log('No captures in this task yet.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (row.artifacts.length === 1) {
|
|
139
|
+
openAndReport(row.artifacts[0]);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const artifact = await pickArtifact(row);
|
|
143
|
+
if (artifact)
|
|
144
|
+
openAndReport(artifact);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
/** True when the interactive picker should open instead of the printed table:
|
|
148
|
+
* a real TTY, no `--json`/`--open`, and `--no-interactive` not set. */
|
|
149
|
+
export function shouldOpenInteractiveBrowserSessions(opts, isTTY) {
|
|
150
|
+
return browserSessionsPicker.shouldOpen(opts, isTTY);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Shared entry point for `agents browser sessions` and `agents sessions
|
|
154
|
+
* --browser`. Replaces direct calls to `runBrowserSessions` at both call
|
|
155
|
+
* sites so the interactive routing decision lives in one place.
|
|
156
|
+
*/
|
|
157
|
+
export async function runBrowserSessionsCommand(opts) {
|
|
158
|
+
await browserSessionsPicker.run(opts);
|
|
159
|
+
}
|
|
@@ -1,3 +1,18 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { type BrowserProfile } from '../lib/browser/profiles.js';
|
|
3
|
+
import { listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
2
4
|
export declare function registerBrowserCommand(program: Command): void;
|
|
3
5
|
export declare function registerBrowserSubcommands(program: Command): void;
|
|
6
|
+
interface BrowserUseOptions {
|
|
7
|
+
unset?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface BrowserUseChoice {
|
|
10
|
+
name: string;
|
|
11
|
+
value: {
|
|
12
|
+
name: string;
|
|
13
|
+
installed?: ReturnType<typeof listInstalledBrowsers>[number];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare function buildBrowserUseChoices(profiles: BrowserProfile[], installed: ReturnType<typeof listInstalledBrowsers>, current?: string): BrowserUseChoice[];
|
|
17
|
+
export declare function runBrowserUse(name: string | undefined, opts: BrowserUseOptions, interactive?: boolean): Promise<boolean>;
|
|
18
|
+
export {};
|
package/dist/commands/browser.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
import { listProfiles, getProfile, createProfile, deleteProfile,
|
|
4
|
+
import { listProfiles, getProfile, createProfile, deleteProfile, getConfiguredDefaultProfileName, resolveProfileRef, resolveProfileRefForStart, getProfileRuntimeDir, extractConfiguredPort, findFreeProfilePort, getEndpointPresets, listProfilesWithScope, formatProfilesTable, } from '../lib/browser/profiles.js';
|
|
5
5
|
import { resolveActor } from '../lib/actor.js';
|
|
6
6
|
import { loginsForProfile, profilesLoggedInto, serviceForUrl, loginsWithAccountsForProfile, accountsForProfile, credKeysForService, AUTH_SIGNATURES, } from '../lib/browser/login-detection.js';
|
|
7
7
|
import { parseSecretRef } from '../lib/browser/secret-ref.js';
|
|
8
8
|
import { readAndResolveBundleEnv, bundleExists, readBundle, describeBundle } from '../lib/secrets/bundles.js';
|
|
9
|
-
import { findBrowserPath, getPortOccupant, isLauncherScript } from '../lib/browser/chrome.js';
|
|
9
|
+
import { findBrowserPath, getPortOccupant, isLauncherScript, listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
10
10
|
import { listProfileCacheDirs, removeProfileCache, listAllProfileSnapshots, buildProfilePrunePlan, pruneProfiles, PRUNE_REASON_TEXT, } from '../lib/browser/runtime-state.js';
|
|
11
11
|
import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
|
|
12
12
|
import { runBrowserSessionsCommand } from './browser-sessions-picker.js';
|
|
@@ -49,7 +49,7 @@ const TASK_OPTION_DESC = 'Task name (defaults to $AGENTS_BROWSER_TASK, else the
|
|
|
49
49
|
// instead of an alphabetical dump. Everything not listed falls into a
|
|
50
50
|
// trailing "Other commands" section automatically.
|
|
51
51
|
const BROWSER_HELP_GROUPS = [
|
|
52
|
-
{ title: 'Session lifecycle', names: ['start', 'done', 'status', 'gc'] },
|
|
52
|
+
{ title: 'Session lifecycle', names: ['use', 'start', 'done', 'status', 'gc'] },
|
|
53
53
|
{ title: 'Fast action loop', names: ['stream'] },
|
|
54
54
|
{
|
|
55
55
|
title: 'Drive the page',
|
|
@@ -105,22 +105,104 @@ export function registerBrowserCommand(program) {
|
|
|
105
105
|
Most agent workflows should use the 'browser' skill instead of raw subcommands.
|
|
106
106
|
The skill wraps profile selection, snapshotting, and tunneling.
|
|
107
107
|
|
|
108
|
-
Browser support: Chromium-family only (Chrome, Comet, Chromium, Brave, Edge).
|
|
108
|
+
Browser support: Chromium-family only (Chrome, Comet, Chromium, Brave, Edge, Arc).
|
|
109
109
|
Safari and Firefox are not supported — they don't speak the Chrome DevTools
|
|
110
110
|
Protocol the way agents browser expects. On Windows, Edge is the default
|
|
111
111
|
because it's preinstalled. On macOS and Linux, Chrome is preferred when
|
|
112
112
|
installed; otherwise the first Chromium-family binary on disk wins.
|
|
113
113
|
`,
|
|
114
114
|
});
|
|
115
|
+
registerBrowserUseCommand(browser);
|
|
115
116
|
registerProfilesCommands(browser);
|
|
116
117
|
registerTaskCommands(browser);
|
|
117
118
|
registerCommandGroups(browser, BROWSER_HELP_GROUPS);
|
|
118
119
|
}
|
|
119
120
|
export function registerBrowserSubcommands(program) {
|
|
121
|
+
registerBrowserUseCommand(program);
|
|
120
122
|
registerProfilesCommands(program);
|
|
121
123
|
registerTaskCommands(program);
|
|
122
124
|
registerCommandGroups(program, BROWSER_HELP_GROUPS);
|
|
123
125
|
}
|
|
126
|
+
export function buildBrowserUseChoices(profiles, installed, current) {
|
|
127
|
+
const choices = profiles.map((profile) => ({
|
|
128
|
+
name: `${profile.name}${profile.name === current ? ' (current)' : ''}`,
|
|
129
|
+
value: { name: profile.name },
|
|
130
|
+
}));
|
|
131
|
+
const known = new Set(profiles.map((profile) => profile.name));
|
|
132
|
+
for (const browser of installed) {
|
|
133
|
+
const name = `${browser.browserType}-local`;
|
|
134
|
+
if (!known.has(name)) {
|
|
135
|
+
choices.push({ name: `${name} (installed ${browser.browserType})`, value: { name, installed: browser } });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return choices;
|
|
139
|
+
}
|
|
140
|
+
export async function runBrowserUse(name, opts, interactive = isInteractiveTerminal()) {
|
|
141
|
+
if (opts.unset || name === 'auto') {
|
|
142
|
+
unsetConfigValue('browser.profile');
|
|
143
|
+
console.log('Default browser profile cleared. `agents browser start` will auto-detect an installed Chromium-family browser.');
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
let selectedName = name;
|
|
147
|
+
if (!selectedName) {
|
|
148
|
+
const current = getConfiguredDefaultProfileName();
|
|
149
|
+
if (!interactive) {
|
|
150
|
+
console.log(current
|
|
151
|
+
? `Default browser profile (this machine): ${current}`
|
|
152
|
+
: 'Default browser profile (this machine): auto-detect');
|
|
153
|
+
console.log('Usage: agents browser use <name> (or --unset)');
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
const choices = buildBrowserUseChoices(await listProfiles(), listInstalledBrowsers(), current);
|
|
157
|
+
if (choices.length === 0) {
|
|
158
|
+
console.error('No configured profiles or supported installed browsers found.');
|
|
159
|
+
console.error('Create one with: agents browser profiles create <name> --browser chrome');
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const { select } = await import('@inquirer/prompts');
|
|
163
|
+
const selected = await select({ message: 'Select default browser profile:', choices });
|
|
164
|
+
selectedName = selected.name;
|
|
165
|
+
if (selected.installed) {
|
|
166
|
+
const freePort = await findFreeProfilePort();
|
|
167
|
+
await createProfile({
|
|
168
|
+
name: selected.name,
|
|
169
|
+
description: `Seeded ${selected.installed.browserType} profile`,
|
|
170
|
+
browser: selected.installed.browserType,
|
|
171
|
+
binary: selected.installed.binary,
|
|
172
|
+
endpoints: [`cdp://127.0.0.1:${freePort}`],
|
|
173
|
+
viewport: { width: DEFAULT_VIEWPORT.width, height: DEFAULT_VIEWPORT.height },
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const target = await getProfile(selectedName);
|
|
178
|
+
if (!target) {
|
|
179
|
+
console.error(`Profile "${selectedName}" not found.`);
|
|
180
|
+
const all = await listProfiles();
|
|
181
|
+
if (all.length > 0)
|
|
182
|
+
console.error(`Available profiles: ${all.map((profile) => profile.name).join(', ')}`);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
setConfigValue('browser.profile', selectedName);
|
|
186
|
+
const endpoint = Object.values(getEndpointPresets(target))[0]?.target ?? '';
|
|
187
|
+
console.log(`Default browser profile (this machine) is now "${selectedName}" (${target.browser}${endpoint ? `, ${endpoint}` : ''}).`);
|
|
188
|
+
console.log('Bare `agents browser start` and `--profile default` will use it.');
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
function configureBrowserUseCommand(command, deprecated = false) {
|
|
192
|
+
command
|
|
193
|
+
.description('Pick the profile `agents browser start` uses when no --profile is passed. No name opens a picker on a TTY or prints the current default headlessly.')
|
|
194
|
+
.option('--unset', 'Clear the configured default (revert to auto-detecting an installed browser)')
|
|
195
|
+
.action(async (name, opts) => {
|
|
196
|
+
if (deprecated) {
|
|
197
|
+
console.warn(chalk.yellow('Deprecation: `agents browser profiles set-default` is replaced by `agents browser use`.'));
|
|
198
|
+
}
|
|
199
|
+
if (!await runBrowserUse(name, opts))
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function registerBrowserUseCommand(browser) {
|
|
204
|
+
configureBrowserUseCommand(browser.command('use [name]'));
|
|
205
|
+
}
|
|
124
206
|
/**
|
|
125
207
|
* Whether a profile's secrets bundle holds login creds for `service`
|
|
126
208
|
* (`<PREFIX>_USERNAME` + `<PREFIX>_PASSWORD`). Reads bundle METADATA only (key
|
|
@@ -174,43 +256,36 @@ function registerProfilesCommands(browser) {
|
|
|
174
256
|
for (const line of formatProfilesTable(scoped, configuredDefault))
|
|
175
257
|
console.log(line);
|
|
176
258
|
});
|
|
177
|
-
const browserProfileDeprecation = chalk.yellow('Deprecation: `agents browser profiles set-default` is replaced by `agents config set browser.profile <name>`.');
|
|
178
259
|
profiles
|
|
179
|
-
.command('
|
|
180
|
-
.description('
|
|
181
|
-
.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
console.log('Default browser profile cleared. `agents browser start` will auto-detect an installed Chromium-family browser.');
|
|
187
|
-
return;
|
|
260
|
+
.command('seed')
|
|
261
|
+
.description('Create a machine-local profile for each installed browser (named <browser>-local), so you can pick or use one instead of hand-crafting each. Idempotent — existing profiles are left untouched.')
|
|
262
|
+
.action(async () => {
|
|
263
|
+
const installed = listInstalledBrowsers();
|
|
264
|
+
if (installed.length === 0) {
|
|
265
|
+
console.error('No supported browser found to seed a profile for.');
|
|
266
|
+
process.exit(1);
|
|
188
267
|
}
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
if (
|
|
192
|
-
console.log(
|
|
193
|
-
|
|
194
|
-
else {
|
|
195
|
-
console.log('No default browser profile set. `agents browser start` auto-detects an installed Chromium-family browser.');
|
|
196
|
-
console.log('Set one with: agents config set browser.profile <name>');
|
|
268
|
+
for (const { browserType, binary } of installed) {
|
|
269
|
+
const name = `${browserType}-local`;
|
|
270
|
+
if (await getProfile(name)) {
|
|
271
|
+
console.log(`= ${name} (already exists)`);
|
|
272
|
+
continue;
|
|
197
273
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
274
|
+
const freePort = await findFreeProfilePort();
|
|
275
|
+
await createProfile({
|
|
276
|
+
name,
|
|
277
|
+
description: `Seeded ${browserType} profile`,
|
|
278
|
+
browser: browserType,
|
|
279
|
+
binary,
|
|
280
|
+
endpoints: [`cdp://127.0.0.1:${freePort}`],
|
|
281
|
+
viewport: { width: DEFAULT_VIEWPORT.width, height: DEFAULT_VIEWPORT.height },
|
|
282
|
+
});
|
|
283
|
+
console.log(`+ ${name} (${browserType})`);
|
|
207
284
|
}
|
|
208
|
-
|
|
209
|
-
const eps = getEndpointPresets(target);
|
|
210
|
-
const epStr = Object.values(eps)[0]?.target ?? '';
|
|
211
|
-
console.log(`Default browser profile (this machine) is now "${name}" (${target.browser}${epStr ? `, ${epStr}` : ''}).`);
|
|
212
|
-
console.log('Bare `agents browser start` and `--profile default` will use it.');
|
|
285
|
+
console.log('Pick your default with: agents browser use <name>');
|
|
213
286
|
});
|
|
287
|
+
configureBrowserUseCommand(profiles.command('use [name]'));
|
|
288
|
+
configureBrowserUseCommand(profiles.command('set-default [name]', { hidden: true }), true);
|
|
214
289
|
profiles
|
|
215
290
|
.command('logins')
|
|
216
291
|
.description('Show which login-gated services each profile has a live session for, the account signed in, and whether login creds are available in the profile\'s secrets bundle (reads cookie/username presence only, never decrypts).')
|
|
@@ -239,7 +314,7 @@ function registerProfilesCommands(browser) {
|
|
|
239
314
|
}
|
|
240
315
|
}
|
|
241
316
|
});
|
|
242
|
-
const VALID_BROWSERS = ['chrome', 'comet', 'chromium', 'brave', 'edge', 'custom'];
|
|
317
|
+
const VALID_BROWSERS = ['chrome', 'comet', 'chromium', 'brave', 'edge', 'arc', 'custom'];
|
|
243
318
|
profiles
|
|
244
319
|
.command('create <name>')
|
|
245
320
|
.description('Create a new browser profile (machine-local unless --fleet)')
|
|
@@ -439,7 +514,7 @@ function registerProfilesCommands(browser) {
|
|
|
439
514
|
(removed > 0 ? ` (and ${removed} cache dir${removed === 1 ? '' : 's'})` : ''));
|
|
440
515
|
if (getConfiguredDefaultProfileName() === name) {
|
|
441
516
|
console.error(`warning: "${name}" was this machine's default browser profile; ` +
|
|
442
|
-
`\`agents browser start\` will auto-detect until you run: agents
|
|
517
|
+
`\`agents browser start\` will auto-detect until you run: agents browser use <name>`);
|
|
443
518
|
}
|
|
444
519
|
});
|
|
445
520
|
profiles
|
|
@@ -493,7 +568,7 @@ function registerProfilesCommands(browser) {
|
|
|
493
568
|
agents browser profiles prune
|
|
494
569
|
|
|
495
570
|
# Make one the machine's default for a bare \`agents browser start\`
|
|
496
|
-
agents
|
|
571
|
+
agents browser use work
|
|
497
572
|
`,
|
|
498
573
|
notes: `
|
|
499
574
|
Profiles are machine-local by default. A profile pins an OS-specific binary
|
|
@@ -501,12 +576,12 @@ function registerProfilesCommands(browser) {
|
|
|
501
576
|
other machine — pass --fleet only when the profile really is fleet config.
|
|
502
577
|
|
|
503
578
|
In \`list\`, the \`*\` marker means "this machine's configured default"
|
|
504
|
-
(\`agents browser start\` with no --profile).
|
|
505
|
-
|
|
506
|
-
|
|
579
|
+
(\`agents browser start\` with no --profile). The auto-detected profile is
|
|
580
|
+
named \`auto-chrome\`; \`default\` is only an ALIAS for whichever profile
|
|
581
|
+
this machine is configured to use, resolved the same way by every command.
|
|
507
582
|
|
|
508
583
|
\`prune\` never removes a profile that is in use, the configured default, the
|
|
509
|
-
auto \`
|
|
584
|
+
auto-detected \`auto-chrome\`, or (without --fleet) a fleet-synced one.
|
|
510
585
|
`,
|
|
511
586
|
});
|
|
512
587
|
profiles
|
|
@@ -748,7 +823,7 @@ function registerTaskCommands(browser) {
|
|
|
748
823
|
});
|
|
749
824
|
browser
|
|
750
825
|
.command('start')
|
|
751
|
-
.description('Start a browser task. Pass --profile <name>; omit to use your configured default (`agents
|
|
826
|
+
.description('Start a browser task. Pass --profile <name>; omit to use your configured default (`agents browser use <name>`), else auto-pick an installed Chromium-family browser. Page verbs (navigate/screenshot/…) create a task implicitly when none exists — start is for --profile/--url/--record/--title.')
|
|
752
827
|
.option('-p, --profile <name>', 'Browser profile to use (omit to use the configured default, else auto-pick an installed Chromium-family browser)')
|
|
753
828
|
.option(TASK_OPTION_FLAG, 'Task name (auto-generated short id if omitted)')
|
|
754
829
|
.option('--title <label>', 'Human label shown in `browser status` (defaults to first navigated host)')
|
|
@@ -771,33 +846,20 @@ function registerTaskCommands(browser) {
|
|
|
771
846
|
console.error(err instanceof Error ? err.message : String(err));
|
|
772
847
|
process.exit(1);
|
|
773
848
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
849
|
+
// One resolution order for every command (RUSH-2709): `--profile default`
|
|
850
|
+
// means the same profile here as it does in stop / status / navigate.
|
|
851
|
+
// `start` is the one command that LAUNCHES, so its implicit path goes
|
|
852
|
+
// through ensureDefaultBrowserProfile, which additionally verifies the
|
|
853
|
+
// resolved default can launch on THIS machine and regenerates it when it
|
|
854
|
+
// can't (the "Custom binary not found" repair) — a filter-only command
|
|
855
|
+
// must not warn or rewrite a profile, so that check lives only here.
|
|
856
|
+
let profileName;
|
|
857
|
+
try {
|
|
858
|
+
profileName = await resolveProfileRefForStart(opts.profile);
|
|
784
859
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
// user's chosen profile (e.g. their logged-in Comet) rather than a
|
|
789
|
-
// literal `default` (which auto-detects Chrome). Narrowly scoped: only
|
|
790
|
-
// the reserved name, only here in `start`.
|
|
791
|
-
const configured = getConfiguredDefaultProfileName();
|
|
792
|
-
if (configured && configured !== DEFAULT_BROWSER_PROFILE_NAME) {
|
|
793
|
-
const target = await getProfile(configured);
|
|
794
|
-
if (target) {
|
|
795
|
-
profileName = target.name;
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
console.error(`warning: configured default profile "${configured}" not found; using "${DEFAULT_BROWSER_PROFILE_NAME}".`);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
860
|
+
catch (err) {
|
|
861
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
862
|
+
process.exit(1);
|
|
801
863
|
}
|
|
802
864
|
// Pre-check the profile locally so we fail fast with a helpful error
|
|
803
865
|
// instead of round-tripping a generic "Profile not found" through the daemon.
|
|
@@ -808,7 +870,7 @@ function registerTaskCommands(browser) {
|
|
|
808
870
|
if (all.length > 0) {
|
|
809
871
|
console.error(`Available profiles: ${all.map((p) => p.name).join(', ')}`);
|
|
810
872
|
}
|
|
811
|
-
console.error(`Create one with: agents browser profiles create ${profileName} --browser <chrome|comet|chromium|brave|edge|custom>`);
|
|
873
|
+
console.error(`Create one with: agents browser profiles create ${profileName} --browser <chrome|comet|chromium|brave|edge|arc|custom>`);
|
|
812
874
|
process.exit(1);
|
|
813
875
|
}
|
|
814
876
|
// Pre-check the endpoint name too — same fail-fast rationale.
|
|
@@ -926,15 +988,16 @@ function registerTaskCommands(browser) {
|
|
|
926
988
|
.option('-p, --profile <name>', 'Detach the whole profile (incl. composite "name@endpoint") instead of stopping a single task')
|
|
927
989
|
.action(async (opts) => {
|
|
928
990
|
if (opts.profile) {
|
|
991
|
+
const profile = (await resolveProfileRef(opts.profile)) ?? opts.profile;
|
|
929
992
|
const response = await sendIPCRequest({
|
|
930
993
|
action: 'stop',
|
|
931
|
-
profile
|
|
994
|
+
profile,
|
|
932
995
|
});
|
|
933
996
|
if (!response.ok) {
|
|
934
997
|
console.error(response.error);
|
|
935
998
|
process.exit(1);
|
|
936
999
|
}
|
|
937
|
-
console.log(`Stopped profile: ${
|
|
1000
|
+
console.log(`Stopped profile: ${profile}`);
|
|
938
1001
|
return;
|
|
939
1002
|
}
|
|
940
1003
|
const task = resolveTaskName(opts);
|
|
@@ -1008,7 +1071,7 @@ function registerTaskCommands(browser) {
|
|
|
1008
1071
|
action: 'navigate',
|
|
1009
1072
|
task,
|
|
1010
1073
|
url,
|
|
1011
|
-
profile: opts.profile,
|
|
1074
|
+
profile: opts.profile ? await resolveProfileRef(opts.profile) : undefined,
|
|
1012
1075
|
});
|
|
1013
1076
|
if (!response.ok) {
|
|
1014
1077
|
console.error(response.error);
|
|
@@ -1033,7 +1096,7 @@ function registerTaskCommands(browser) {
|
|
|
1033
1096
|
action: 'tab-add',
|
|
1034
1097
|
task,
|
|
1035
1098
|
url: opts.url,
|
|
1036
|
-
profile: opts.profile,
|
|
1099
|
+
profile: opts.profile ? await resolveProfileRef(opts.profile) : undefined,
|
|
1037
1100
|
});
|
|
1038
1101
|
if (!response.ok) {
|
|
1039
1102
|
console.error(response.error);
|
|
@@ -1294,7 +1357,7 @@ function registerTaskCommands(browser) {
|
|
|
1294
1357
|
try {
|
|
1295
1358
|
response = await sendIPCRequest({
|
|
1296
1359
|
action: 'status',
|
|
1297
|
-
profile: opts.profile,
|
|
1360
|
+
profile: opts.profile ? await resolveProfileRef(opts.profile) : undefined,
|
|
1298
1361
|
}, { autoStartDaemon: false });
|
|
1299
1362
|
}
|
|
1300
1363
|
catch (err) {
|
|
@@ -1383,7 +1446,11 @@ function registerTaskCommands(browser) {
|
|
|
1383
1446
|
// pid 0 means the daemon attached to a browser we didn't launch — no
|
|
1384
1447
|
// tracked pid. Render it as "attached" rather than the literal 0.
|
|
1385
1448
|
const pidLabel = profile.pid ? `pid ${profile.pid}` : 'attached';
|
|
1386
|
-
|
|
1449
|
+
// `profile.name` is the BARE profile; the endpoint is its own field,
|
|
1450
|
+
// so the row reads `comet-local (endpoint: endpoint-0, port …)`
|
|
1451
|
+
// instead of the raw `comet-local@endpoint-0` key (RUSH-2709).
|
|
1452
|
+
const endpointLabel = profile.endpoint ? `endpoint: ${profile.endpoint}, ` : '';
|
|
1453
|
+
console.log(`\n${profile.name} (${endpointLabel}${portLabel}, ${pidLabel})`);
|
|
1387
1454
|
if (profile.tasks.length === 0) {
|
|
1388
1455
|
console.log(' No active tasks');
|
|
1389
1456
|
}
|
|
@@ -1418,7 +1485,7 @@ function registerTaskCommands(browser) {
|
|
|
1418
1485
|
.action(async (opts) => {
|
|
1419
1486
|
const response = await sendIPCRequest({
|
|
1420
1487
|
action: 'status',
|
|
1421
|
-
profile: opts.profile,
|
|
1488
|
+
profile: opts.profile ? await resolveProfileRef(opts.profile) : undefined,
|
|
1422
1489
|
});
|
|
1423
1490
|
if (!response.ok) {
|
|
1424
1491
|
if (opts.json) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { type ComputerClient, type RPCResponse } from '../lib/computer-rpc.js';
|
|
2
|
+
import { type ComputerClient, type RPCResponse } from '../lib/computer/computer-rpc.js';
|
|
3
3
|
export { emitComputerAction, pickTarget, resolveTargetPidDecision, type AppInfo } from '../lib/computer/actions.js';
|
|
4
4
|
export declare function parseXY(s: string, flag: string): {
|
|
5
5
|
x: number;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { execFileSync } from 'child_process';
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
|
-
import { openComputerClient, describeTransport, } from '../lib/computer-rpc.js';
|
|
12
|
+
import { openComputerClient, describeTransport, } from '../lib/computer/computer-rpc.js';
|
|
13
13
|
import { emitComputerAction, resolveTargetPidDecision } from '../lib/computer/actions.js';
|
|
14
14
|
export { emitComputerAction, pickTarget, resolveTargetPidDecision } from '../lib/computer/actions.js';
|
|
15
15
|
// Pure target picker — exercised by unit tests. Precedence: explicit --pid,
|