@phnx-labs/agents-cli 1.22.117 → 1.22.119
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 +301 -0
- package/dist/bootstrap.js +4 -11
- package/dist/commands/accounts.js +7 -4
- package/dist/commands/browser.d.ts +52 -70
- package/dist/commands/browser.js +192 -3562
- package/dist/commands/daemon.d.ts +39 -2
- package/dist/commands/daemon.js +72 -73
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +53 -1
- package/dist/commands/projects.js +92 -7
- package/dist/commands/repo.js +13 -49
- package/dist/commands/route.js +5 -5
- package/dist/commands/routines.js +39 -12
- package/dist/commands/sessions-render.d.ts +1 -1
- package/dist/commands/sessions-render.js +0 -1
- package/dist/commands/sessions.test-fixture.d.ts +0 -1
- package/dist/commands/sessions.test-fixture.js +0 -37
- package/dist/commands/setup-browser.d.ts +17 -12
- package/dist/commands/setup-browser.js +52 -87
- package/dist/commands/setup-preferences.d.ts +0 -17
- package/dist/commands/setup-preferences.js +18 -49
- package/dist/commands/setup.js +9 -9
- package/dist/commands/ssh.js +10 -1
- package/dist/commands/sync.js +6 -44
- package/dist/commands/teams.js +0 -1
- package/dist/commands/update.d.ts +19 -0
- package/dist/commands/update.js +34 -6
- package/dist/commands/view.d.ts +12 -1
- package/dist/commands/view.js +47 -2
- package/dist/index.js +107 -26
- package/dist/lib/account-capabilities.js +0 -2
- package/dist/lib/account-catalog.d.ts +38 -0
- package/dist/lib/account-catalog.js +110 -26
- package/dist/lib/account-provider-registry.js +1 -1
- package/dist/lib/account-registry.d.ts +1 -1
- package/dist/lib/account-registry.js +36 -2
- package/dist/lib/accounting/rotate.js +22 -8
- package/dist/lib/accounting/usage-ingest.d.ts +6 -1
- package/dist/lib/accounting/usage-ingest.js +115 -45
- package/dist/lib/accounting/usage-sync.d.ts +134 -31
- package/dist/lib/accounting/usage-sync.js +227 -66
- package/dist/lib/accounting/usage.d.ts +16 -3
- package/dist/lib/accounting/usage.js +26 -8
- package/dist/lib/accounts/add.d.ts +3 -1
- package/dist/lib/accounts/add.js +24 -13
- package/dist/lib/accounts/slots.d.ts +8 -0
- package/dist/lib/accounts/slots.js +17 -0
- package/dist/lib/add-dir.js +0 -1
- package/dist/lib/agent-cli-commands.js +0 -1
- package/dist/lib/agent-spec/agents.d.ts +6 -7
- package/dist/lib/agent-spec/agents.js +7 -60
- package/dist/lib/auth-health.d.ts +69 -1
- package/dist/lib/auth-health.js +133 -4
- package/dist/lib/browser/context.d.ts +82 -0
- package/dist/lib/browser/context.js +88 -0
- package/dist/lib/browser/paths.d.ts +25 -0
- package/dist/lib/browser/paths.js +51 -0
- package/dist/lib/browser/record.d.ts +38 -0
- package/dist/lib/browser/record.js +57 -0
- package/dist/lib/browser/sessions-list.js +1 -2
- package/dist/lib/browser-client.d.ts +158 -0
- package/dist/lib/browser-client.js +234 -0
- package/dist/lib/channels/owner-sink.d.ts +1 -18
- package/dist/lib/channels/owner-sink.js +29 -82
- package/dist/lib/channels/providers/rush.d.ts +7 -7
- package/dist/lib/channels/providers/rush.js +127 -57
- package/dist/lib/claude-account-token.d.ts +7 -1
- package/dist/lib/claude-account-token.js +26 -4
- package/dist/lib/claude-statusline.d.ts +1 -1
- package/dist/lib/claude-statusline.js +15 -3
- package/dist/lib/commands.js +1 -1
- package/dist/lib/crabbox/lease.js +1 -1
- package/dist/lib/crabbox/runtimes.js +1 -3
- package/dist/lib/daemon/account-state-daemon-service.js +1 -0
- package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
- package/dist/lib/daemon/auth-sync-service.js +37 -43
- package/dist/lib/daemon/daemon.d.ts +25 -14
- package/dist/lib/daemon/daemon.js +92 -154
- package/dist/lib/daemon/runner.d.ts +2 -2
- package/dist/lib/daemon/runner.js +32 -9
- package/dist/lib/daemon/self-update-service.d.ts +35 -34
- package/dist/lib/daemon/self-update-service.js +40 -36
- package/dist/lib/daemon/service.d.ts +12 -8
- package/dist/lib/daemon/supervisor.d.ts +65 -54
- package/dist/lib/daemon/supervisor.js +136 -171
- package/dist/lib/daemon/testdata/process-view-start.js +5 -2
- package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
- package/dist/lib/daemon/usage-sync-service.js +46 -78
- package/dist/lib/daemon-health.d.ts +22 -5
- package/dist/lib/daemon-health.js +47 -3
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +0 -10
- package/dist/lib/daemon-ticks.js +4 -2
- package/dist/lib/devices/doctor-findings.js +8 -11
- package/dist/lib/devices/harness-inventory.js +14 -5
- package/dist/lib/exec-account-home.js +5 -0
- package/dist/lib/exec.js +10 -13
- package/dist/lib/feed/events.js +0 -1
- package/dist/lib/feed/tool-activity.js +5 -2
- package/dist/lib/fleet-shared-state.d.ts +45 -0
- package/dist/lib/fleet-shared-state.js +78 -9
- package/dist/lib/fs-atomic.js +25 -0
- package/dist/lib/github/pr-mergeable.d.ts +4 -2
- package/dist/lib/github/pr-mergeable.js +5 -3
- package/dist/lib/github/project-prs.d.ts +58 -3
- package/dist/lib/github/project-prs.js +205 -7
- package/dist/lib/harness/adapters/cursor.js +14 -4
- package/dist/lib/harness-auth-capabilities.d.ts +4 -3
- package/dist/lib/harness-auth-capabilities.js +1 -2
- package/dist/lib/helper-versions.js +1 -1
- package/dist/lib/hooks/cache.d.ts +7 -0
- package/dist/lib/hooks/cache.js +27 -2
- package/dist/lib/hooks/install.js +7 -1
- package/dist/lib/hosts/ready.d.ts +38 -8
- package/dist/lib/hosts/ready.js +62 -14
- package/dist/lib/installations/active-check.d.ts +27 -0
- package/dist/lib/installations/active-check.js +61 -0
- package/dist/lib/installations/migrate.js +6 -3
- package/dist/lib/installations/shims.d.ts +1 -1
- package/dist/lib/installations/shims.js +32 -12
- package/dist/lib/installations/store.d.ts +9 -0
- package/dist/lib/installations/store.js +24 -0
- package/dist/lib/installations/update.js +21 -15
- package/dist/lib/installations/versions.js +15 -3
- package/dist/lib/manifest.js +1 -1
- package/dist/lib/models.js +0 -2
- package/dist/lib/open-url.js +28 -54
- package/dist/lib/profiles.js +0 -2
- package/dist/lib/projects.d.ts +16 -0
- package/dist/lib/projects.js +31 -0
- package/dist/lib/refresh.js +1 -1
- package/dist/lib/routine-readiness.d.ts +35 -0
- package/dist/lib/routine-readiness.js +74 -16
- package/dist/lib/rules/compile.js +6 -0
- package/dist/lib/sandbox.js +0 -2
- package/dist/lib/secrets-policy.d.ts +89 -11
- package/dist/lib/secrets-policy.js +175 -28
- package/dist/lib/session/active.d.ts +17 -6
- package/dist/lib/session/active.js +105 -49
- package/dist/lib/session/db.d.ts +1 -1
- package/dist/lib/session/db.js +65 -18
- package/dist/lib/session/discover.js +1 -283
- package/dist/lib/session/mirror.d.ts +4 -3
- package/dist/lib/session/mirror.js +4 -3
- package/dist/lib/session/parse.d.ts +0 -2
- package/dist/lib/session/parse.js +1 -138
- package/dist/lib/session/pid-registry.d.ts +6 -3
- package/dist/lib/session/pid-registry.js +18 -8
- package/dist/lib/session/remote/watch.d.ts +1 -1
- package/dist/lib/session/remote/watch.js +7 -3
- package/dist/lib/session/throughput.d.ts +1 -3
- package/dist/lib/session/throughput.js +0 -20
- package/dist/lib/session/types.d.ts +2 -2
- package/dist/lib/session/types.js +2 -2
- package/dist/lib/sessions-client.d.ts +60 -1
- package/dist/lib/sessions-client.js +227 -4
- package/dist/lib/setup-tool-status.js +5 -10
- package/dist/lib/signin-badge.d.ts +3 -2
- package/dist/lib/signin-badge.js +6 -3
- package/dist/lib/smart-launch.js +4 -1
- package/dist/lib/staleness/detectors/commands.d.ts +1 -1
- package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
- package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
- package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
- package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
- package/dist/lib/staleness/detectors/rules.d.ts +1 -1
- package/dist/lib/staleness/detectors/skills.d.ts +1 -1
- package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
- package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.d.ts +1 -1
- package/dist/lib/staleness/writers/hooks.d.ts +1 -1
- package/dist/lib/staleness/writers/mcp.d.ts +1 -1
- package/dist/lib/staleness/writers/permissions.d.ts +1 -1
- package/dist/lib/staleness/writers/plugins.d.ts +1 -1
- package/dist/lib/staleness/writers/rules.d.ts +1 -1
- package/dist/lib/staleness/writers/skills.d.ts +1 -1
- package/dist/lib/staleness/writers/sources.js +5 -0
- package/dist/lib/staleness/writers/subagents.d.ts +1 -1
- package/dist/lib/staleness/writers/workflows.d.ts +1 -1
- package/dist/lib/state.d.ts +6 -4
- package/dist/lib/state.js +7 -17
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/teams/parsers.js +1 -136
- package/dist/lib/teams/placement-probe.js +50 -15
- package/dist/lib/teams/scheduler.d.ts +7 -0
- package/dist/lib/types.d.ts +16 -1
- package/dist/lib/types.js +1 -1
- package/dist/lib/view-types.d.ts +32 -0
- package/dist/lib/watchdog/read.js +0 -1
- package/dist/lib/watchdog/rotate.js +1 -2
- package/dist/lib/watchdog/runner.js +2 -2
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdogTail.js +0 -31
- package/package.json +1 -1
- package/scripts/postinstall.js +8 -8
- package/dist/browser.d.ts +0 -2
- package/dist/browser.js +0 -17
- package/dist/commands/browser-picker.d.ts +0 -18
- package/dist/commands/browser-picker.js +0 -97
- package/dist/lib/browser/arc-discovery.d.ts +0 -52
- package/dist/lib/browser/arc-discovery.js +0 -197
- package/dist/lib/browser/arc-dom.d.ts +0 -14
- package/dist/lib/browser/arc-dom.js +0 -121
- package/dist/lib/browser/caller-identity.d.ts +0 -40
- package/dist/lib/browser/caller-identity.js +0 -175
- package/dist/lib/browser/cdp.d.ts +0 -51
- package/dist/lib/browser/cdp.js +0 -254
- package/dist/lib/browser/chrome.d.ts +0 -141
- package/dist/lib/browser/chrome.js +0 -704
- package/dist/lib/browser/chromium-discovery.d.ts +0 -28
- package/dist/lib/browser/chromium-discovery.js +0 -96
- package/dist/lib/browser/devices.d.ts +0 -34
- package/dist/lib/browser/devices.js +0 -61
- package/dist/lib/browser/domain-skills.d.ts +0 -71
- package/dist/lib/browser/domain-skills.js +0 -195
- package/dist/lib/browser/drivers/arc.d.ts +0 -40
- package/dist/lib/browser/drivers/arc.js +0 -276
- package/dist/lib/browser/drivers/firefox.d.ts +0 -99
- package/dist/lib/browser/drivers/firefox.js +0 -377
- package/dist/lib/browser/drivers/local.d.ts +0 -55
- package/dist/lib/browser/drivers/local.js +0 -266
- package/dist/lib/browser/drivers/ssh.d.ts +0 -120
- package/dist/lib/browser/drivers/ssh.js +0 -467
- package/dist/lib/browser/editor.d.ts +0 -3
- package/dist/lib/browser/editor.js +0 -50
- package/dist/lib/browser/ffmpeg.d.ts +0 -12
- package/dist/lib/browser/ffmpeg.js +0 -184
- package/dist/lib/browser/firefox-discovery.d.ts +0 -69
- package/dist/lib/browser/firefox-discovery.js +0 -162
- package/dist/lib/browser/har.d.ts +0 -85
- package/dist/lib/browser/har.js +0 -77
- package/dist/lib/browser/hygiene.d.ts +0 -97
- package/dist/lib/browser/hygiene.js +0 -153
- package/dist/lib/browser/index.d.ts +0 -5
- package/dist/lib/browser/index.js +0 -5
- package/dist/lib/browser/input.d.ts +0 -7
- package/dist/lib/browser/input.js +0 -92
- package/dist/lib/browser/ipc.d.ts +0 -204
- package/dist/lib/browser/ipc.js +0 -1453
- package/dist/lib/browser/login-detection.d.ts +0 -87
- package/dist/lib/browser/login-detection.js +0 -274
- package/dist/lib/browser/profiles.d.ts +0 -422
- package/dist/lib/browser/profiles.js +0 -1157
- package/dist/lib/browser/refs.d.ts +0 -89
- package/dist/lib/browser/refs.js +0 -191
- package/dist/lib/browser/registry.d.ts +0 -70
- package/dist/lib/browser/registry.js +0 -252
- package/dist/lib/browser/remote-control.d.ts +0 -59
- package/dist/lib/browser/remote-control.js +0 -85
- package/dist/lib/browser/resolve-target.d.ts +0 -66
- package/dist/lib/browser/resolve-target.js +0 -264
- package/dist/lib/browser/runtime-state.d.ts +0 -291
- package/dist/lib/browser/runtime-state.js +0 -584
- package/dist/lib/browser/secret-ref.d.ts +0 -10
- package/dist/lib/browser/secret-ref.js +0 -14
- package/dist/lib/browser/service.d.ts +0 -812
- package/dist/lib/browser/service.js +0 -4693
- package/dist/lib/browser/stream.d.ts +0 -17
- package/dist/lib/browser/stream.js +0 -72
- package/dist/lib/browser/task-index.d.ts +0 -78
- package/dist/lib/browser/task-index.js +0 -199
- package/dist/lib/browser/types.d.ts +0 -647
- package/dist/lib/browser/types.js +0 -61
- package/dist/lib/browser/upload.d.ts +0 -29
- package/dist/lib/browser/upload.js +0 -298
- package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
- package/dist/lib/daemon/browser-ipc-service.js +0 -46
- package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
- package/dist/lib/daemon/browser-task-reap-service.js +0 -26
- package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
- package/dist/lib/fleet-shared-repo-sync.js +0 -490
package/dist/commands/repo.js
CHANGED
|
@@ -55,34 +55,13 @@ function syncMarketplacesForDefaults() {
|
|
|
55
55
|
catch { /* best-effort */ }
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const { syncReservedAuthBundle } = await import('../lib/secrets-policy.js');
|
|
66
|
-
const auth = await syncReservedAuthBundle();
|
|
67
|
-
if (auth.pushed.length > 0)
|
|
68
|
-
console.log(chalk.gray(`Auth bundle: pushed to ${auth.pushed.join(', ')}`));
|
|
69
|
-
for (const err of auth.errors)
|
|
70
|
-
console.error(chalk.yellow(`Auth bundle: ${err.device}: ${err.message}`));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const { publishReservedAuthVerdict } = await import('../lib/secrets-policy.js');
|
|
74
|
-
const auth = await publishReservedAuthVerdict();
|
|
75
|
-
if (auth.error)
|
|
76
|
-
console.error(chalk.yellow(`Auth verdict: ${auth.device}: ${auth.error}`));
|
|
77
|
-
}
|
|
78
|
-
/** Consume freshly pulled usage/auth metadata from the local user-repo checkout. */
|
|
79
|
-
async function consumeUserRepoAccountState() {
|
|
80
|
-
const { consumeUsageSnapshotsFromSharedStore } = await import('../lib/accounting/usage-sync.js');
|
|
81
|
-
const usage = consumeUsageSnapshotsFromSharedStore();
|
|
82
|
-
if (usage.merged > 0)
|
|
83
|
-
console.log(chalk.gray(`Usage snapshot: merged ${usage.merged} row(s) from ${usage.sources.join(', ')}`));
|
|
84
|
-
for (const err of usage.errors)
|
|
85
|
-
console.error(chalk.yellow(`Usage snapshot: ${err.device}: ${err.message}`));
|
|
58
|
+
/**
|
|
59
|
+
* Push the reserved auth bundle to peers whose last-received verdict says
|
|
60
|
+
* `missing`. Daemon state (usage, verdicts, session digests) no longer rides the
|
|
61
|
+
* user repo — it moves over SSH on the usage-sync tick (PHNX-4116) — so a repo
|
|
62
|
+
* push/sync of human-authored resources only runs this credential half.
|
|
63
|
+
*/
|
|
64
|
+
async function syncUserRepoAuthBundle() {
|
|
86
65
|
const { syncReservedAuthBundle } = await import('../lib/secrets-policy.js');
|
|
87
66
|
const auth = await syncReservedAuthBundle();
|
|
88
67
|
if (auth.pushed.length > 0)
|
|
@@ -1085,7 +1064,7 @@ export function registerRepoCommands(program) {
|
|
|
1085
1064
|
].filter(Boolean);
|
|
1086
1065
|
if (parts.length > 0)
|
|
1087
1066
|
console.log(chalk.gray(`Device policy: ${parts.join(' · ')}`));
|
|
1088
|
-
await
|
|
1067
|
+
await syncUserRepoAuthBundle();
|
|
1089
1068
|
}
|
|
1090
1069
|
});
|
|
1091
1070
|
repoCmd
|
|
@@ -1121,10 +1100,8 @@ export function registerRepoCommands(program) {
|
|
|
1121
1100
|
return;
|
|
1122
1101
|
}
|
|
1123
1102
|
for (const t of pushable) {
|
|
1124
|
-
// Account snapshots must exist BEFORE commitAndPush or this push ships
|
|
1125
|
-
// the previous tick's state and delays propagation by one repo cycle.
|
|
1126
1103
|
if (t.alias === 'user')
|
|
1127
|
-
await
|
|
1104
|
+
await syncUserRepoAuthBundle();
|
|
1128
1105
|
const spinner = interruptibleSpinner(`Pushing ${formatRepoTarget(t.alias, t.dir)}...`).start();
|
|
1129
1106
|
const result = await commitAndPush(t.dir, options.message);
|
|
1130
1107
|
if (result.success) {
|
|
@@ -1193,23 +1170,10 @@ Examples:
|
|
|
1193
1170
|
}
|
|
1194
1171
|
}
|
|
1195
1172
|
const push = t.alias !== 'system';
|
|
1196
|
-
//
|
|
1197
|
-
//
|
|
1198
|
-
if (t.alias === 'user')
|
|
1199
|
-
await publishUserRepoAccountState(false);
|
|
1173
|
+
// A plain pull/rebase (+ push) of human-authored resources for every
|
|
1174
|
+
// alias, the user repo included: daemon state left git (PHNX-4116).
|
|
1200
1175
|
const spinner = interruptibleSpinner(`Syncing ${formatRepoTarget(t.alias, t.dir)}...`).start();
|
|
1201
|
-
const result = t.
|
|
1202
|
-
? await (async () => {
|
|
1203
|
-
const { syncFleetSharedStateRepo } = await import('../lib/fleet-shared-repo-sync.js');
|
|
1204
|
-
const synced = await syncFleetSharedStateRepo({ userAgentsDir: t.dir });
|
|
1205
|
-
return {
|
|
1206
|
-
success: synced.success,
|
|
1207
|
-
commit: synced.commit ?? '',
|
|
1208
|
-
pushed: synced.pushed,
|
|
1209
|
-
error: synced.error ?? synced.skipped ?? undefined,
|
|
1210
|
-
};
|
|
1211
|
-
})()
|
|
1212
|
-
: await syncRepoGit(t.dir, { push });
|
|
1176
|
+
const result = await syncRepoGit(t.dir, { push });
|
|
1213
1177
|
if (result.success) {
|
|
1214
1178
|
const pushed = result.pushed ? ' (pushed)' : '';
|
|
1215
1179
|
spinner.succeed(`${formatRepoTarget(t.alias, t.dir)}: ${result.commit}${pushed}`);
|
|
@@ -1219,7 +1183,7 @@ Examples:
|
|
|
1219
1183
|
recordUserRepoRemote(t.dir, u);
|
|
1220
1184
|
const { reconcileDeviceDiscoveryPolicies } = await import('../lib/devices/discovery-policy.js');
|
|
1221
1185
|
await reconcileDeviceDiscoveryPolicies();
|
|
1222
|
-
await
|
|
1186
|
+
await syncUserRepoAuthBundle();
|
|
1223
1187
|
}
|
|
1224
1188
|
}
|
|
1225
1189
|
else {
|
package/dist/commands/route.js
CHANGED
|
@@ -95,13 +95,13 @@ export function registerRouteCommands(program) {
|
|
|
95
95
|
setHelpSections(routeCmd, {
|
|
96
96
|
examples: `
|
|
97
97
|
# Create a router scoped to two harnesses, capped at a tier
|
|
98
|
-
agents route add research --harness
|
|
98
|
+
agents route add research --harness grok,kimi --tier cheap,default
|
|
99
99
|
|
|
100
100
|
# Narrow one harness's model set
|
|
101
101
|
agents route allow research kimi kimi-k2
|
|
102
102
|
|
|
103
103
|
# Link accounts so routing under this router only ever picks them
|
|
104
|
-
agents route link-account research
|
|
104
|
+
agents route link-account research grok personal
|
|
105
105
|
agents route link-account research kimi work
|
|
106
106
|
|
|
107
107
|
# Inspect, rename, remove it
|
|
@@ -126,7 +126,7 @@ export function registerRouteCommands(program) {
|
|
|
126
126
|
.command('add <name>')
|
|
127
127
|
.alias('create')
|
|
128
128
|
.description('Create a named router with an initial harness + tier allowlist.')
|
|
129
|
-
.option('--harness <list>', 'Comma-separated harness ids to allow, e.g.
|
|
129
|
+
.option('--harness <list>', 'Comma-separated harness ids to allow, e.g. grok,kimi')
|
|
130
130
|
.option('--tier <list>', 'Comma-separated tier tokens applied to every listed harness, e.g. cheap,default')
|
|
131
131
|
.option('--task <type>', 'Free-text task type this router serves, e.g. research')
|
|
132
132
|
.action((name, opts) => {
|
|
@@ -134,7 +134,7 @@ export function registerRouteCommands(program) {
|
|
|
134
134
|
die(`Router '${name}' already exists. Use 'agents route allow ${name} <harness> <model|tier>...' to edit it.`);
|
|
135
135
|
}
|
|
136
136
|
if (!opts.harness) {
|
|
137
|
-
die("Missing --harness. Example: agents route add research --harness
|
|
137
|
+
die("Missing --harness. Example: agents route add research --harness grok,kimi --tier cheap,default");
|
|
138
138
|
}
|
|
139
139
|
const harnesses = opts.harness.split(',').map((h) => h.trim()).filter(Boolean);
|
|
140
140
|
const tiers = (opts.tier ?? '').split(',').map((t) => t.trim()).filter(Boolean);
|
|
@@ -170,7 +170,7 @@ export function registerRouteCommands(program) {
|
|
|
170
170
|
}
|
|
171
171
|
if (routers.length === 0) {
|
|
172
172
|
console.log(chalk.gray('No routers configured.'));
|
|
173
|
-
console.log(chalk.gray('Try: agents route add research --harness
|
|
173
|
+
console.log(chalk.gray('Try: agents route add research --harness grok,kimi --tier cheap,default'));
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
176
176
|
for (const router of routers)
|
|
@@ -246,7 +246,7 @@ function renderRoutineRows({ jobs, scheduler, overdueSet, link, now, local = tru
|
|
|
246
246
|
: lastStatus === 'missed' ? chalk.magenta
|
|
247
247
|
: chalk.gray;
|
|
248
248
|
const overdueTag = overdueSet.has(job.name) ? chalk.yellow(' (overdue)') : '';
|
|
249
|
-
// Append the concrete reason a routine did not complete (auth_failed,
|
|
249
|
+
// Append the concrete reason a routine did not complete (auth_failed,
|
|
250
250
|
// blocked, missed) right in the Last Status cell, so the list answers "why"
|
|
251
251
|
// without a drill-in. Only for non-completed local runs; peer rows stay blank.
|
|
252
252
|
const reason = latestRun ? runFailureReason(latestRun) : null;
|
|
@@ -650,12 +650,29 @@ function routineMatchesQuery(job, q) {
|
|
|
650
650
|
.toLowerCase()
|
|
651
651
|
.includes(q);
|
|
652
652
|
}
|
|
653
|
-
/**
|
|
653
|
+
/**
|
|
654
|
+
* Friendly one-liners for the claim a `skipped` run lost — the reasons whose
|
|
655
|
+
* message is static. `active_run` is dynamic (it names the live run that owns
|
|
656
|
+
* the slot and when it started), built in {@link runFailureReason}: since
|
|
657
|
+
* PHNX-4116 there is no "wedged" daemon state, so an overlapping routine reads
|
|
658
|
+
* as `blocked` on the live run, not "wedged".
|
|
659
|
+
*/
|
|
654
660
|
const SKIP_REASON_LABEL = {
|
|
655
|
-
active_run: 'wedged: a prior run is still active',
|
|
656
661
|
duplicate_slot: 'duplicate slot (already fired)',
|
|
657
662
|
wrong_owner: 'pinned to another device',
|
|
658
663
|
};
|
|
664
|
+
/**
|
|
665
|
+
* A run id is an ISO timestamp with `:`/`.` replaced by `-` (`slotRunId` /
|
|
666
|
+
* `generateRunId`), so it reverses losslessly to the run's start time. Returns
|
|
667
|
+
* the ISO string, or null when the id is not that shape (a hand-set id).
|
|
668
|
+
*/
|
|
669
|
+
function runIdToStartIso(runId) {
|
|
670
|
+
const m = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/.exec(runId);
|
|
671
|
+
if (!m)
|
|
672
|
+
return null;
|
|
673
|
+
const iso = `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z`;
|
|
674
|
+
return Number.isFinite(Date.parse(iso)) ? iso : null;
|
|
675
|
+
}
|
|
659
676
|
/**
|
|
660
677
|
* The short, human reason a run did not simply complete — for inline display in
|
|
661
678
|
* the list/detail so "why did it fail" needs no dig into the run dir. Prefers the
|
|
@@ -670,6 +687,21 @@ export function runFailureReason(run) {
|
|
|
670
687
|
const one = s.replace(/\s+/g, ' ').trim();
|
|
671
688
|
return one.length > 80 ? one.slice(0, 79) + '…' : one;
|
|
672
689
|
};
|
|
690
|
+
// An overlap skip names the live run it lost to (PHNX-4116): `blocked: run
|
|
691
|
+
// <id> active since <t>`, not the removed "wedged" wording. The structured
|
|
692
|
+
// `activeRunId` is preferred; a legacy record without it falls back to the
|
|
693
|
+
// errorMessage (which embeds the same id) so nothing regresses to vaguer text.
|
|
694
|
+
if (run.skipReason === 'active_run') {
|
|
695
|
+
if (run.activeRunId) {
|
|
696
|
+
const since = runIdToStartIso(run.activeRunId);
|
|
697
|
+
return since
|
|
698
|
+
? `blocked: run ${run.activeRunId} active since ${since}`
|
|
699
|
+
: `blocked: run ${run.activeRunId} still active`;
|
|
700
|
+
}
|
|
701
|
+
if (run.errorMessage)
|
|
702
|
+
return compact(run.errorMessage);
|
|
703
|
+
return 'blocked: a prior run is still active';
|
|
704
|
+
}
|
|
673
705
|
if (run.errorMessage)
|
|
674
706
|
return compact(run.errorMessage);
|
|
675
707
|
if (run.status === 'blocked' && run.readiness) {
|
|
@@ -751,8 +783,8 @@ function buildRoutineDetail(job, scheduler, now) {
|
|
|
751
783
|
: chalk.yellow(run.status);
|
|
752
784
|
const dur = run.completedAt ? ` ${formatRunDuration(run.startedAt, run.completedAt)}` : '';
|
|
753
785
|
// Surface WHY a run did not complete, inline, so "looking at status" does not
|
|
754
|
-
// require digging into the run dir. auth_failed / OAuth-revoked,
|
|
755
|
-
// active-run skip, or a readiness block all live on the RunMeta already.
|
|
786
|
+
// require digging into the run dir. auth_failed / OAuth-revoked, an
|
|
787
|
+
// active-run overlap skip, or a readiness block all live on the RunMeta already.
|
|
756
788
|
const reason = runFailureReason(run);
|
|
757
789
|
const why = reason ? chalk.gray(` — ${reason}`) : '';
|
|
758
790
|
lines.push(` ${run.startedAt} ${status}${dur}${why}`);
|
|
@@ -1941,7 +1973,7 @@ export function registerRoutinesCommands(program) {
|
|
|
1941
1973
|
chalk.gray(` ${run.startedAt}`) +
|
|
1942
1974
|
chalk.gray(formatRunDuration(run.startedAt, run.completedAt)) +
|
|
1943
1975
|
(run.exitCode !== null && run.exitCode !== undefined ? chalk.gray(` exit ${run.exitCode}`) : ''));
|
|
1944
|
-
// The structured reason (auth_failed, blocked readiness,
|
|
1976
|
+
// The structured reason (auth_failed, blocked readiness, overlap skip) — the
|
|
1945
1977
|
// report/stdout tail below often buries or omits it, so name it up front.
|
|
1946
1978
|
const logsReason = runFailureReason(run);
|
|
1947
1979
|
if (logsReason)
|
|
@@ -2300,9 +2332,7 @@ export function registerRoutinesCommands(program) {
|
|
|
2300
2332
|
console.log(chalk.bold('Scheduler\n'));
|
|
2301
2333
|
const stateLabel = schedulerState === 'running'
|
|
2302
2334
|
? chalk.green('running')
|
|
2303
|
-
:
|
|
2304
|
-
? chalk.red('wedged')
|
|
2305
|
-
: chalk.gray('stopped');
|
|
2335
|
+
: chalk.gray('stopped');
|
|
2306
2336
|
console.log(` Status: ${stateLabel}`);
|
|
2307
2337
|
console.log(` Daemon: ${status.running ? chalk.green('running') : chalk.gray('stopped')}`);
|
|
2308
2338
|
if (status.pid)
|
|
@@ -2316,9 +2346,6 @@ export function registerRoutinesCommands(program) {
|
|
|
2316
2346
|
const jobs = listAllJobs();
|
|
2317
2347
|
const enabled = jobs.filter((j) => j.enabled);
|
|
2318
2348
|
console.log(` Routines: ${enabled.length} enabled / ${jobs.length} total`);
|
|
2319
|
-
if (status.state === 'wedged') {
|
|
2320
|
-
console.log(chalk.red('\n The shared daemon is wedged (heartbeat stale). Restart deliberately with: agents daemon restart'));
|
|
2321
|
-
}
|
|
2322
2349
|
if (schedulerState === 'running' && enabled.length > 0) {
|
|
2323
2350
|
const scheduler = new JobScheduler(async () => { });
|
|
2324
2351
|
scheduler.loadAll();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import type { SessionMeta } from '../lib/session/types.js';
|
|
3
|
-
export declare const MARKDOWN_RENDER_AGENTS: readonly ["claude", "codex", "
|
|
3
|
+
export declare const MARKDOWN_RENDER_AGENTS: readonly ["claude", "codex", "antigravity", "opencode", "grok", "rush", "hermes", "kimi", "droid", "cursor"];
|
|
4
4
|
export type ReasoningMode = 'omit' | 'fold' | 'include';
|
|
5
5
|
/** Build one shareable Markdown document from the canonical preview and event model. */
|
|
6
6
|
export declare function renderSessionMarkdownDocument(session: SessionMeta, options?: {
|
|
@@ -15,7 +15,6 @@ export declare const tsxLoaderUrl: string;
|
|
|
15
15
|
export declare function writeUpdateCache(tempHome: string): void;
|
|
16
16
|
export declare function writeClaudeSession(tempHome: string, projectKey: string, sessionId: string, cwd: string, content: string, timestamp: string): void;
|
|
17
17
|
export declare function writeCodexSession(tempHome: string, sessionId: string, cwd: string, prompt: string, timestamp: string): void;
|
|
18
|
-
export declare function writeGeminiSession(tempHome: string, sessionId: string, cwd: string, prompt: string, timestamp: string, version?: string): void;
|
|
19
18
|
export declare function writeOpenClawSetup(tempHome: string, version?: string): string;
|
|
20
19
|
export declare function runAgents(args: string[], cwd: string, home: string, envOverrides?: Record<string, string>): import("node:child_process").SpawnSyncReturns<string>;
|
|
21
20
|
export declare function outputOf(result: {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { describe } from 'vitest';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
import * as crypto from 'crypto';
|
|
5
4
|
import { spawnSync } from 'child_process';
|
|
6
5
|
import { createRequire } from 'node:module';
|
|
7
6
|
import { pathToFileURL } from 'node:url';
|
|
@@ -121,42 +120,6 @@ export function writeCodexSession(tempHome, sessionId, cwd, prompt, timestamp) {
|
|
|
121
120
|
];
|
|
122
121
|
fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
|
|
123
122
|
}
|
|
124
|
-
export function writeGeminiSession(tempHome, sessionId, cwd, prompt, timestamp, version = '0.29.5') {
|
|
125
|
-
const versionHome = path.join(tempHome, '.agents', '.history', 'versions', 'gemini', version, 'home');
|
|
126
|
-
const geminiHome = path.join(versionHome, '.gemini');
|
|
127
|
-
const projectHash = crypto.createHash('sha256').update(cwd).digest('hex');
|
|
128
|
-
const chatsDir = path.join(geminiHome, 'tmp', projectHash, 'chats');
|
|
129
|
-
fs.mkdirSync(cwd, { recursive: true });
|
|
130
|
-
fs.mkdirSync(chatsDir, { recursive: true });
|
|
131
|
-
fs.mkdirSync(path.dirname(path.join(tempHome, '.gemini')), { recursive: true });
|
|
132
|
-
const activeGeminiHome = path.join(tempHome, '.gemini');
|
|
133
|
-
if (!fs.existsSync(activeGeminiHome)) {
|
|
134
|
-
fs.symlinkSync(geminiHome, activeGeminiHome);
|
|
135
|
-
}
|
|
136
|
-
fs.writeFileSync(path.join(geminiHome, 'projects.json'), JSON.stringify({ projects: [cwd] }), 'utf-8');
|
|
137
|
-
fs.writeFileSync(path.join(chatsDir, `session-${timestamp.replace(/[:.]/g, '-')}-${sessionId.slice(0, 8)}.json`), JSON.stringify({
|
|
138
|
-
sessionId,
|
|
139
|
-
projectHash,
|
|
140
|
-
startTime: timestamp,
|
|
141
|
-
lastUpdated: timestamp,
|
|
142
|
-
messages: [
|
|
143
|
-
{
|
|
144
|
-
id: `${sessionId}-user`,
|
|
145
|
-
timestamp,
|
|
146
|
-
type: 'user',
|
|
147
|
-
content: [{ text: prompt }],
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: `${sessionId}-assistant`,
|
|
151
|
-
timestamp,
|
|
152
|
-
type: 'gemini',
|
|
153
|
-
content: 'Investigating now.',
|
|
154
|
-
model: 'gemini-3-flash-preview',
|
|
155
|
-
tokens: { total: 1234 },
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
}, null, 2), 'utf-8');
|
|
159
|
-
}
|
|
160
123
|
export function writeOpenClawSetup(tempHome, version = '2026.3.8') {
|
|
161
124
|
const managedHome = path.join(tempHome, '.agents', '.history', 'versions', 'openclaw', version, 'home', '.openclaw');
|
|
162
125
|
fs.mkdirSync(managedHome, { recursive: true });
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents setup browser` —
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* `agents setup browser` — get `agents browser` working on a fresh machine:
|
|
3
|
+
* install the standalone `browser` CLI (@phnx-labs/browser-cli), let it detect
|
|
4
|
+
* installed browsers and create machine-local profiles (`browser profiles seed`),
|
|
5
|
+
* then pick this machine's default (`browser use`).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* The engine owns profile declarations and browser detection now (PHNX-4101), so
|
|
8
|
+
* this wizard DELEGATES to it rather than crafting profiles itself. What stays
|
|
9
|
+
* agents-cli's is the onboarding flow and the readiness check over the shared
|
|
10
|
+
* `browser.profile` config key both CLIs read/write.
|
|
11
|
+
*
|
|
12
|
+
* Idempotent: `profiles seed` leaves existing profiles untouched, and `use`
|
|
13
|
+
* re-points the device default.
|
|
9
14
|
*/
|
|
10
15
|
import type { Command } from 'commander';
|
|
11
16
|
/**
|
|
12
|
-
* Interactive browser setup. Returns true if a
|
|
13
|
-
* afterwards, false if none
|
|
14
|
-
*
|
|
15
|
-
* silently minting a logged-out
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* Interactive browser setup. Returns true if a default profile is configured
|
|
18
|
+
* afterwards, false if none is / the user backed out. Non-interactively it only
|
|
19
|
+
* RECOGNIZES an existing default — it never creates one (PHNX-3296), since
|
|
20
|
+
* silently minting a logged-out profile on a headless box is the exact bug that
|
|
21
|
+
* removed; a headless box gets its browser from the fleet hub. Never throws on
|
|
22
|
+
* cancel — the `agents setup` hub relies on that.
|
|
18
23
|
*/
|
|
19
24
|
export declare function runBrowserWizard(): Promise<boolean>;
|
|
20
25
|
/** Register `agents setup browser` under the parent `setup` command. */
|
|
@@ -1,124 +1,89 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents setup browser` —
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* `agents setup browser` — get `agents browser` working on a fresh machine:
|
|
3
|
+
* install the standalone `browser` CLI (@phnx-labs/browser-cli), let it detect
|
|
4
|
+
* installed browsers and create machine-local profiles (`browser profiles seed`),
|
|
5
|
+
* then pick this machine's default (`browser use`).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* The engine owns profile declarations and browser detection now (PHNX-4101), so
|
|
8
|
+
* this wizard DELEGATES to it rather than crafting profiles itself. What stays
|
|
9
|
+
* agents-cli's is the onboarding flow and the readiness check over the shared
|
|
10
|
+
* `browser.profile` config key both CLIs read/write.
|
|
11
|
+
*
|
|
12
|
+
* Idempotent: `profiles seed` leaves existing profiles untouched, and `use`
|
|
13
|
+
* re-points the device default.
|
|
9
14
|
*/
|
|
10
15
|
import { openSetupTerminal } from './setup-terminal.js';
|
|
11
16
|
import chalk from 'chalk';
|
|
12
|
-
import {
|
|
13
|
-
import { listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
14
|
-
import { DEFAULT_BROWSER_PROFILE_NAME, getAutoDetectedProfile, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, } from '../lib/browser/profiles.js';
|
|
15
|
-
import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
|
|
17
|
+
import { getConfigValue } from '../lib/device-config.js';
|
|
16
18
|
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
17
|
-
import { defaultBrowserChoice } from './setup-preferences.js';
|
|
18
19
|
import { installSetupTool } from '../lib/setup-tool-install.js';
|
|
19
20
|
import { refreshToolSetup } from '../lib/setup-tool-status.js';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { browserInstalled, runBrowser } from '../lib/browser-client.js';
|
|
22
|
+
import { buildBrowserContext } from '../lib/browser/context.js';
|
|
23
|
+
/** The device-local default profile, as both agents-cli and browser-cli see it. */
|
|
24
|
+
function configuredDefaultProfile() {
|
|
25
|
+
return getConfigValue('browser.profile').value || undefined;
|
|
26
|
+
}
|
|
27
|
+
/** Run one standalone `browser` verb, inheriting the terminal, and return its exit code. */
|
|
28
|
+
async function runBrowserVerb(argv) {
|
|
29
|
+
const { exitCode } = await runBrowser({ argv, context: await buildBrowserContext() });
|
|
30
|
+
return exitCode;
|
|
31
|
+
}
|
|
23
32
|
/**
|
|
24
|
-
* Interactive browser setup. Returns true if a
|
|
25
|
-
* afterwards, false if none
|
|
26
|
-
*
|
|
27
|
-
* silently minting a logged-out
|
|
28
|
-
*
|
|
29
|
-
*
|
|
33
|
+
* Interactive browser setup. Returns true if a default profile is configured
|
|
34
|
+
* afterwards, false if none is / the user backed out. Non-interactively it only
|
|
35
|
+
* RECOGNIZES an existing default — it never creates one (PHNX-3296), since
|
|
36
|
+
* silently minting a logged-out profile on a headless box is the exact bug that
|
|
37
|
+
* removed; a headless box gets its browser from the fleet hub. Never throws on
|
|
38
|
+
* cancel — the `agents setup` hub relies on that.
|
|
30
39
|
*/
|
|
31
40
|
export async function runBrowserWizard() {
|
|
32
41
|
if (!isInteractiveTerminal()) {
|
|
33
|
-
|
|
34
|
-
// one. Silently auto-detecting an installed browser and creating an
|
|
35
|
-
// `auto-chrome` here is exactly the bug PHNX-3296 removed — a headless box
|
|
36
|
-
// gets its browser from the fleet hub (`browser.device`), or from an
|
|
37
|
-
// interactive pick later.
|
|
38
|
-
const existing = await getAutoDetectedProfile();
|
|
42
|
+
const existing = configuredDefaultProfile();
|
|
39
43
|
if (existing) {
|
|
40
|
-
console.log(chalk.dim(`
|
|
44
|
+
console.log(chalk.dim(`Default browser profile "${existing}" already configured on this machine.`));
|
|
41
45
|
return true;
|
|
42
46
|
}
|
|
43
47
|
console.log(chalk.dim('No default browser profile on this machine. Re-run `agents setup browser` in an ' +
|
|
44
48
|
'interactive terminal to pick one, or use the fleet hub: agents config set browser.device <host>.'));
|
|
45
49
|
return false;
|
|
46
50
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
const { confirm, select } = await import('@inquirer/prompts');
|
|
54
|
-
// If a default profile already exists, this is a reconfigure.
|
|
55
|
-
const existing = await getAutoDetectedProfile();
|
|
56
|
-
if (existing) {
|
|
57
|
-
console.log(chalk.dim(`Browser profile "${existing.name}" already exists (${existing.browser}${existing.binary ? ` · ${existing.binary}` : ''}).`));
|
|
58
|
-
const change = await confirm({ message: 'Re-create it (e.g. to pin a different browser)?', default: false });
|
|
59
|
-
if (!change) {
|
|
60
|
-
await maybeSetDeviceDefault(existing.name, confirm);
|
|
61
|
-
printOnboardingNextStep(existing.name);
|
|
62
|
-
return true;
|
|
51
|
+
if (!browserInstalled()) {
|
|
52
|
+
console.log(chalk.dim('Installing the standalone Browser CLI (@phnx-labs/browser-cli)…'));
|
|
53
|
+
if (!(await installSetupTool('browser'))) {
|
|
54
|
+
console.error(chalk.red('Could not install @phnx-labs/browser-cli. Install it manually with `npm i -g @phnx-labs/browser-cli`, then re-run.'));
|
|
55
|
+
return false;
|
|
63
56
|
}
|
|
64
|
-
// Re-create: drop the old one so createProfile doesn't collide.
|
|
65
|
-
const { deleteProfile } = await import('../lib/browser/profiles.js');
|
|
66
|
-
await deleteProfile(existing.name);
|
|
67
57
|
}
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
message: 'Which browser should the default profile use?',
|
|
75
|
-
default: defaultBrowserChoice(installed) ?? undefined,
|
|
76
|
-
choices: installed.map((b) => ({ name: `${b.browserType} ${chalk.dim(b.binary)}`, value: b.browserType })),
|
|
77
|
-
});
|
|
78
|
-
chosen = installed.find((b) => b.browserType === value) ?? installed[0];
|
|
58
|
+
// Let the engine detect installed browsers and create a machine-local profile
|
|
59
|
+
// for each (idempotent), then open its own picker to set this machine's default.
|
|
60
|
+
const seedCode = await runBrowserVerb(['profiles', 'seed']);
|
|
61
|
+
if (seedCode !== 0) {
|
|
62
|
+
console.error(chalk.red('`browser profiles seed` failed — see the output above.'));
|
|
63
|
+
return false;
|
|
79
64
|
}
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
binary: chosen.binary,
|
|
86
|
-
endpoints: [`cdp://127.0.0.1:${freePort}`],
|
|
87
|
-
viewport: { width: DEFAULT_VIEWPORT.width, height: DEFAULT_VIEWPORT.height },
|
|
88
|
-
};
|
|
89
|
-
await createProfile(profile);
|
|
90
|
-
console.log(chalk.green(`\nCreated browser profile "${profile.name}" → ${chosen.browserType} (CDP 127.0.0.1:${freePort}).`));
|
|
91
|
-
await maybeSetDeviceDefault(profile.name, confirm);
|
|
92
|
-
printOnboardingNextStep(profile.name);
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
/** Offer to make `name` this machine's default browser profile (device-local). */
|
|
96
|
-
async function maybeSetDeviceDefault(name, confirm) {
|
|
97
|
-
const current = getConfiguredDefaultProfileName();
|
|
98
|
-
if (current === name)
|
|
99
|
-
return; // already the device default
|
|
100
|
-
const set = await confirm({
|
|
101
|
-
message: `Make "${name}" this machine's default browser profile?`,
|
|
102
|
-
default: true,
|
|
103
|
-
});
|
|
104
|
-
if (set) {
|
|
105
|
-
setConfigValue('browser.profile', name);
|
|
106
|
-
console.log(chalk.dim(`Bare \`agents browser start\` will now use "${name}" on this machine.`));
|
|
65
|
+
await runBrowserVerb(['use']);
|
|
66
|
+
const chosen = configuredDefaultProfile();
|
|
67
|
+
if (!chosen) {
|
|
68
|
+
console.log(chalk.dim('No default profile chosen. Run `agents browser use <name>` later to set one.'));
|
|
69
|
+
return false;
|
|
107
70
|
}
|
|
71
|
+
printOnboardingNextStep(chosen);
|
|
72
|
+
return true;
|
|
108
73
|
}
|
|
109
|
-
/** The one step we can't automate:
|
|
74
|
+
/** The one step we can't automate: the browser's first-run + your own sign-in. */
|
|
110
75
|
function printOnboardingNextStep(name) {
|
|
111
76
|
console.log(chalk.bold('\nOne manual step left:'));
|
|
112
77
|
console.log(' ' +
|
|
113
78
|
chalk.cyan(`agents browser start --profile ${name}`) +
|
|
114
|
-
chalk.dim(' # finish
|
|
79
|
+
chalk.dim(' # finish the browser first-run + sign in to any sites you want automated'));
|
|
115
80
|
console.log(chalk.dim(` Then check it's ready: agents browser profiles doctor ${name}`));
|
|
116
81
|
}
|
|
117
82
|
/** Register `agents setup browser` under the parent `setup` command. */
|
|
118
83
|
export function registerSetupBrowserCommand(setupCmd) {
|
|
119
84
|
setupCmd
|
|
120
85
|
.command('browser')
|
|
121
|
-
.description('Set up `agents browser` —
|
|
86
|
+
.description('Set up `agents browser` — install the Browser CLI, seed profiles, and pick this machine\'s default.')
|
|
122
87
|
.option('--install-only', 'Install the standalone Browser CLI without changing profiles or starting a browser')
|
|
123
88
|
.option('--terminal [backend]', 'Open interactive setup in a detected or selected terminal')
|
|
124
89
|
.action(async (options) => {
|
|
@@ -21,14 +21,6 @@ export declare function macDeviceNames(reg: DeviceRegistry): string[];
|
|
|
21
21
|
* first candidate. null when there are no candidates.
|
|
22
22
|
*/
|
|
23
23
|
export declare function defaultInteractiveHostChoice(candidates: string[], self?: string): string | null;
|
|
24
|
-
/**
|
|
25
|
-
* The browser picker's highlighted default — the same browser auto-detect
|
|
26
|
-
* would win, since `listInstalledBrowsers` returns platform priority order
|
|
27
|
-
* (macOS: chrome first). null when nothing is installed.
|
|
28
|
-
*/
|
|
29
|
-
export declare function defaultBrowserChoice<T extends {
|
|
30
|
-
browserType: string;
|
|
31
|
-
}>(installed: T[]): T['browserType'] | null;
|
|
32
24
|
/**
|
|
33
25
|
* Offer to set the interactive host when none is configured and the registry
|
|
34
26
|
* has more than one macOS device. Returns true when a host was set. Silent
|
|
@@ -53,15 +45,6 @@ export declare function maybePickInteractiveHost(): Promise<boolean>;
|
|
|
53
45
|
export declare function maybePickBrowserProfile(deps?: {
|
|
54
46
|
/** Force interactivity in a test; defaults to a real TTY probe. */
|
|
55
47
|
interactive?: boolean;
|
|
56
|
-
/** Inject the prompt so the pick is testable without a TTY. */
|
|
57
|
-
select?: (config: {
|
|
58
|
-
message: string;
|
|
59
|
-
default?: string;
|
|
60
|
-
choices: Array<{
|
|
61
|
-
name: string;
|
|
62
|
-
value: string;
|
|
63
|
-
}>;
|
|
64
|
-
}) => Promise<string>;
|
|
65
48
|
}): Promise<boolean>;
|
|
66
49
|
/**
|
|
67
50
|
* The bare-`agents setup` preferences step: interactive host, then browser.
|