@phnx-labs/agents-cli 1.22.45 → 1.22.47
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 +303 -0
- package/LICENSE +102 -182
- package/README.md +54 -17
- package/dist/cli/command-registry.d.ts +2 -1
- package/dist/cli/command-registry.js +6 -2
- package/dist/commands/accounts.js +56 -12
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +229 -0
- package/dist/commands/browser-sessions-picker.js +9 -7
- package/dist/commands/browser.js +266 -15
- package/dist/commands/config.js +26 -4
- package/dist/commands/cost.d.ts +1 -1
- package/dist/commands/detach.d.ts +13 -0
- package/dist/commands/detach.js +11 -8
- package/dist/commands/exec.js +55 -38
- 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/insights.d.ts +1 -1
- package/dist/commands/insights.js +2 -2
- package/dist/commands/lease.js +3 -3
- package/dist/commands/routines.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-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 +4 -0
- package/dist/commands/ssh.d.ts +15 -0
- package/dist/commands/ssh.js +194 -16
- package/dist/commands/teams.js +34 -2
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +19 -32
- package/dist/commands/watchdog.js +9 -14
- 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 +92 -6
- package/dist/lib/accounting/usage.js +329 -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 +20 -7
- 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/ipc.d.ts +1 -1
- package/dist/lib/browser/ipc.js +33 -7
- package/dist/lib/browser/profiles.d.ts +106 -1
- package/dist/lib/browser/profiles.js +300 -17
- package/dist/lib/browser/remote-control.d.ts +26 -2
- package/dist/lib/browser/remote-control.js +33 -3
- package/dist/lib/browser/runtime-state.d.ts +9 -0
- package/dist/lib/browser/runtime-state.js +24 -8
- package/dist/lib/browser/service.d.ts +37 -0
- package/dist/lib/browser/service.js +78 -20
- package/dist/lib/browser/sessions-list.d.ts +1 -3
- package/dist/lib/browser/sessions-list.js +3 -16
- package/dist/lib/browser/types.d.ts +12 -1
- package/dist/lib/cli-resources.js +17 -15
- package/dist/lib/codex-policy.d.ts +11 -1
- package/dist/lib/codex-policy.js +20 -5
- package/dist/lib/config-keys.d.ts +4 -3
- package/dist/lib/config-keys.js +17 -7
- package/dist/lib/daemon/runner.js +15 -2
- package/dist/lib/daemon-ticks.js +2 -2
- package/dist/lib/device-config.d.ts +25 -8
- package/dist/lib/device-config.js +90 -17
- package/dist/lib/devices/config-migration.d.ts +7 -0
- package/dist/lib/devices/config-migration.js +67 -3
- package/dist/lib/devices/harness-inventory.js +20 -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 +6 -0
- package/dist/lib/devices/stats-cache.js +10 -2
- package/dist/lib/exec.d.ts +25 -3
- package/dist/lib/exec.js +75 -22
- 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/hooks/cache.js +8 -0
- package/dist/lib/hooks/match.d.ts +3 -0
- package/dist/lib/hooks/match.js +25 -0
- package/dist/lib/hosts/passthrough.js +16 -0
- package/dist/lib/hosts/registry.js +7 -0
- package/dist/lib/identity/client.d.ts +53 -0
- package/dist/lib/identity/client.js +106 -0
- package/dist/lib/identity/index.d.ts +115 -0
- package/dist/lib/identity/index.js +82 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +13 -0
- package/dist/lib/menubar/install-menubar.js +26 -2
- package/dist/lib/open-url.d.ts +60 -2
- package/dist/lib/open-url.js +167 -12
- package/dist/lib/probe.d.ts +8 -0
- package/dist/lib/probe.js +105 -0
- package/dist/lib/refresh-coordinator.d.ts +1 -1
- package/dist/lib/refresh-coordinator.js +1 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +2 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +13 -1
- package/dist/lib/session/active.d.ts +67 -0
- package/dist/lib/session/active.js +69 -1
- package/dist/lib/session/db.js +4 -2
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +12 -6
- package/dist/lib/session/prompt.d.ts +35 -0
- package/dist/lib/session/prompt.js +56 -0
- package/dist/lib/session/remote/watch.d.ts +1 -1
- package/dist/lib/session/remote/watch.js +6 -1
- package/dist/lib/session/render.js +7 -3
- package/dist/lib/session/session-cache.js +5 -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 +15 -0
- package/dist/lib/session/trajectory-html.js +750 -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 +277 -0
- package/dist/lib/session/trajectory.d.ts +102 -0
- package/dist/lib/session/trajectory.js +335 -0
- package/dist/lib/startup/command-registry.d.ts +5 -2
- package/dist/lib/startup/command-registry.js +8 -5
- package/dist/lib/state.d.ts +1 -1
- package/dist/lib/state.js +4 -2
- package/dist/lib/teams/agents.js +9 -0
- package/dist/lib/terminal/inject.d.ts +19 -0
- package/dist/lib/terminal/inject.js +19 -9
- package/dist/lib/tmux/session.d.ts +46 -13
- package/dist/lib/tmux/session.js +173 -27
- package/dist/lib/types.d.ts +16 -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 +17 -3
- package/dist/lib/usage-refresh.js +57 -11
- package/dist/lib/view-types.d.ts +2 -2
- 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/package.json +2 -2
- package/dist/commands/usage.d.ts +0 -27
- package/dist/commands/usage.js +0 -96
|
@@ -4,6 +4,7 @@ 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';
|
|
9
10
|
import { clearProfileRuntime, listProfileCacheDirs, readProfileRuntimeMeta, isProcessAlive } from './runtime-state.js';
|
|
@@ -312,6 +313,11 @@ export class BrowserService {
|
|
|
312
313
|
/** Coalescing window for the `touchTask` write. See {@link touchTask}. */
|
|
313
314
|
static TOUCH_PERSIST_INTERVAL_MS = 60_000;
|
|
314
315
|
async start(profileName, opts = {}) {
|
|
316
|
+
// Consent gate, before anything is resolved or launched. This is the
|
|
317
|
+
// authoritative one: gating only the `browser start` COMMAND left the ~18
|
|
318
|
+
// page verbs that create a browser implicitly (navigate, click, screenshot,
|
|
319
|
+
// …) able to open a browser on a machine whose owner never opted in.
|
|
320
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
315
321
|
const profile = await getProfile(profileName);
|
|
316
322
|
if (!profile) {
|
|
317
323
|
throw new Error(`Profile "${profileName}" not found`);
|
|
@@ -345,22 +351,8 @@ export class BrowserService {
|
|
|
345
351
|
taskName = taskId;
|
|
346
352
|
}
|
|
347
353
|
const taskLabel = deriveTaskLabel({ title: opts.title, url: opts.url });
|
|
348
|
-
let conn = this.
|
|
354
|
+
let conn = await this.reuseHealthyConnection(composite);
|
|
349
355
|
let effectiveKey = composite;
|
|
350
|
-
// If we have a cached connection, confirm it's still usable before any
|
|
351
|
-
// caller relies on it. A browser killed externally (Cmd-Q, crash, or a
|
|
352
|
-
// user clearing the profile by hand) leaves a closed WebSocket here.
|
|
353
|
-
// Without this check the next `cdp.send` throws "CDP connection not
|
|
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
356
|
if (conn && conn.electron && conn.tasks.size > 0) {
|
|
365
357
|
if (this.forkingProfiles.has(composite)) {
|
|
366
358
|
while (this.forkingProfiles.has(composite)) {
|
|
@@ -388,11 +380,7 @@ export class BrowserService {
|
|
|
388
380
|
}
|
|
389
381
|
}
|
|
390
382
|
else if (!conn) {
|
|
391
|
-
conn = await this.
|
|
392
|
-
conn.key = composite;
|
|
393
|
-
conn.profile = profileName;
|
|
394
|
-
this.connections.set(composite, conn);
|
|
395
|
-
await this.applyDefaultDownloadBehavior(conn, composite);
|
|
383
|
+
conn = await this.openConnection(effectiveProfile, resolved.target, composite, profileName);
|
|
396
384
|
}
|
|
397
385
|
if (conn && !conn.profile)
|
|
398
386
|
conn.profile = profileName;
|
|
@@ -2310,6 +2298,10 @@ export class BrowserService {
|
|
|
2310
2298
|
// Zero matches for this caller.
|
|
2311
2299
|
if (!opts.createIfMissing)
|
|
2312
2300
|
return null;
|
|
2301
|
+
// Refuse BEFORE ensureDefaultBrowserProfile() below, which probes local
|
|
2302
|
+
// browser installs and may CREATE and persist an `auto-chrome` profile — a
|
|
2303
|
+
// refused request must not leave state behind on the target machine.
|
|
2304
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
2313
2305
|
// Implicit start on the default / named profile.
|
|
2314
2306
|
let profileName = opts.profile;
|
|
2315
2307
|
if (!profileName) {
|
|
@@ -2318,6 +2310,7 @@ export class BrowserService {
|
|
|
2318
2310
|
profileName = detected.name;
|
|
2319
2311
|
}
|
|
2320
2312
|
const started = await this.start(profileName, {
|
|
2313
|
+
fleetRemote: opts.fleetRemote,
|
|
2321
2314
|
url: opts.url,
|
|
2322
2315
|
actor: opts.actor,
|
|
2323
2316
|
launchId: opts.launchId,
|
|
@@ -2835,6 +2828,71 @@ export class BrowserService {
|
|
|
2835
2828
|
history = history.slice(0, 50);
|
|
2836
2829
|
await fs.promises.writeFile(historyFile, JSON.stringify(history, null, 2));
|
|
2837
2830
|
}
|
|
2831
|
+
/**
|
|
2832
|
+
* The cached connection for `key`, or undefined — evicting it first if the
|
|
2833
|
+
* browser died underneath us.
|
|
2834
|
+
*
|
|
2835
|
+
* A browser killed externally (Cmd-Q, crash, a user clearing the profile by
|
|
2836
|
+
* hand) leaves a closed WebSocket in the map. Without this the next
|
|
2837
|
+
* `cdp.send` throws "CDP connection not open" and there is no recovery short
|
|
2838
|
+
* of killing the daemon.
|
|
2839
|
+
*/
|
|
2840
|
+
async reuseHealthyConnection(key) {
|
|
2841
|
+
const conn = this.connections.get(key);
|
|
2842
|
+
if (!conn)
|
|
2843
|
+
return undefined;
|
|
2844
|
+
if (await isConnHealthy(conn))
|
|
2845
|
+
return conn;
|
|
2846
|
+
try {
|
|
2847
|
+
conn.cdp.close();
|
|
2848
|
+
}
|
|
2849
|
+
catch { /* already closed */ }
|
|
2850
|
+
conn.cleanup?.();
|
|
2851
|
+
this.connections.delete(key);
|
|
2852
|
+
return undefined;
|
|
2853
|
+
}
|
|
2854
|
+
/** Connect a profile at `target`, register it under `key`, and arm downloads. */
|
|
2855
|
+
async openConnection(profile, target, key, profileName) {
|
|
2856
|
+
const conn = await this.connectProfile(profile, target, key);
|
|
2857
|
+
conn.key = key;
|
|
2858
|
+
conn.profile = profileName;
|
|
2859
|
+
this.connections.set(key, conn);
|
|
2860
|
+
await this.applyDefaultDownloadBehavior(conn, key);
|
|
2861
|
+
return conn;
|
|
2862
|
+
}
|
|
2863
|
+
/**
|
|
2864
|
+
* Open a tab for a HUMAN to read, bound to no task.
|
|
2865
|
+
*
|
|
2866
|
+
* That is the entire difference from {@link start}, and it is the point. The
|
|
2867
|
+
* abandoned-task reaper closes a task's tabs when the calling session dies or
|
|
2868
|
+
* after the idle window, but it "deliberately never touches a tab that is not
|
|
2869
|
+
* in `task.tabs`" (hygiene.ts) — so a viewer tab must not be in one, or the
|
|
2870
|
+
* artifact the user is reading vanishes when the agent that rendered it exits.
|
|
2871
|
+
*
|
|
2872
|
+
* Consequently `stop`/`done` do not close it either, which is correct: it is
|
|
2873
|
+
* the user's tab now.
|
|
2874
|
+
*/
|
|
2875
|
+
async showUrl(profileName, url, opts = {}) {
|
|
2876
|
+
// Same consent gate as start(): this opens a browser, so a fleet-remote
|
|
2877
|
+
// caller needs the target machine's opt-in.
|
|
2878
|
+
assertRemoteControlAllowedForRequest(opts.fleetRemote, { actor: opts.actor });
|
|
2879
|
+
const profile = await getProfile(profileName);
|
|
2880
|
+
if (!profile)
|
|
2881
|
+
throw new Error(`Profile "${profileName}" not found`);
|
|
2882
|
+
const resolved = resolveEndpoint(profile, opts.endpointName);
|
|
2883
|
+
const key = connectionKey(profileName, resolved.name);
|
|
2884
|
+
const effectiveProfile = {
|
|
2885
|
+
...profile,
|
|
2886
|
+
binary: resolved.binary,
|
|
2887
|
+
targetFilter: resolved.targetFilter,
|
|
2888
|
+
};
|
|
2889
|
+
const conn = (await this.reuseHealthyConnection(key)) ??
|
|
2890
|
+
(await this.openConnection(effectiveProfile, resolved.target, key, profileName));
|
|
2891
|
+
// createPageTarget refuses Arc with an actionable error rather than crashing it.
|
|
2892
|
+
const created = await this.createPageTarget(conn, { url });
|
|
2893
|
+
this.invalidateTargetCache(conn);
|
|
2894
|
+
return { profile: profileName, key, tabId: created.targetId };
|
|
2895
|
+
}
|
|
2838
2896
|
async getHistory(limit = 10) {
|
|
2839
2897
|
const historyFile = path.join(getBrowserRuntimeDir(), 'history.json');
|
|
2840
2898
|
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
|
}
|
|
@@ -287,7 +287,7 @@ export interface ReapResult {
|
|
|
287
287
|
/** Tasks left alone this pass: still live, still inside the idle window, or recording. */
|
|
288
288
|
skipped: number;
|
|
289
289
|
}
|
|
290
|
-
export type IPCAction = 'start' | 'gc' | 'record-start' | 'record-stop' | 'done' | 'stop' | 'status' | 'history' | 'navigate' | 'tab-add' | 'tab-focus' | 'tab-close' | 'tab-list' | 'evaluate' | 'screenshot' | 'pdf' | 'refs' | 'click' | 'type' | 'press' | 'hover' | 'scroll' | 'set-viewport' | 'set-device' | 'console' | 'errors' | 'requests' | 'response-body' | 'wait' | 'set-download-path' | 'wait-download' | 'upload' | 'getAppLogs' | 'version';
|
|
290
|
+
export type IPCAction = 'start' | 'show' | 'gc' | 'record-start' | 'record-stop' | 'done' | 'stop' | 'status' | 'history' | 'navigate' | 'tab-add' | 'tab-focus' | 'tab-close' | 'tab-list' | 'evaluate' | 'screenshot' | 'pdf' | 'refs' | 'click' | 'type' | 'press' | 'hover' | 'scroll' | 'set-viewport' | 'set-device' | 'console' | 'errors' | 'requests' | 'response-body' | 'wait' | 'set-download-path' | 'wait-download' | 'upload' | 'getAppLogs' | 'version';
|
|
291
291
|
export interface IPCRequest {
|
|
292
292
|
action: IPCAction;
|
|
293
293
|
task?: string;
|
|
@@ -366,6 +366,17 @@ export interface IPCRequest {
|
|
|
366
366
|
* for `computer.action` events, so both tool surfaces key on one signal.
|
|
367
367
|
*/
|
|
368
368
|
sessionId?: string;
|
|
369
|
+
/**
|
|
370
|
+
* True when the CLI process that issued this request was itself dispatched to
|
|
371
|
+
* this machine by a fleet `--device` hop.
|
|
372
|
+
*
|
|
373
|
+
* Stamped client-side for the same reason actor/launchId are — and
|
|
374
|
+
* additionally because the daemon may have been auto-started BY a fleet-remote
|
|
375
|
+
* CLI and inherited AGENTS_FLEET_REMOTE for its whole life (startDetached
|
|
376
|
+
* passes `env: opts.env ?? process.env`). The daemon's own env is therefore
|
|
377
|
+
* not a truthful signal about the CURRENT caller; only the request is.
|
|
378
|
+
*/
|
|
379
|
+
fleetRemote?: boolean;
|
|
369
380
|
}
|
|
370
381
|
/** Subset of IPCResponse describing a recording start result. */
|
|
371
382
|
export interface RecordStartFields {
|
|
@@ -21,6 +21,7 @@ import * as path from 'path';
|
|
|
21
21
|
import { spawnSync, execFile } from 'child_process';
|
|
22
22
|
import * as yaml from 'yaml';
|
|
23
23
|
import { listResources, resolveResource } from './resources.js';
|
|
24
|
+
import { probeCapture } from './probe.js';
|
|
24
25
|
import { composeWin32CommandLine } from './platform/index.js';
|
|
25
26
|
import { localBinDir } from './platform/posixpath.js';
|
|
26
27
|
// ─── Validation primitives ───────────────────────────────────────────────────
|
|
@@ -318,22 +319,23 @@ export function isCliInstalledAsync(manifest) {
|
|
|
318
319
|
cmdExistsCache.delete(c.cmd);
|
|
319
320
|
return Promise.resolve(hasCommand(c.cmd));
|
|
320
321
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
322
|
+
// probeCapture, not bare execFile: a checked CLI can fork children of its
|
|
323
|
+
// own (copilot's platform-binary downloader), and settling without reaping
|
|
324
|
+
// the probe's process group would orphan them mid-write (RUSH-3028).
|
|
325
|
+
return probeCapture(c.cmd, c.args, 10_000).then(() => true, (err) => {
|
|
326
|
+
// A spawn failure (as opposed to a non-zero exit) surfaces as a string
|
|
327
|
+
// errno code (ENOENT/EINVAL) on the rejection; a non-zero exit or
|
|
328
|
+
// timeout carries no errno. On Windows a `.cmd`/`.bat` shim spawn-fails
|
|
329
|
+
// without a shell — retry once through the shell, exactly as the sync
|
|
330
|
+
// path does.
|
|
331
|
+
const spawnFailed = typeof err.code === 'string';
|
|
332
|
+
if (process.platform === 'win32' && spawnFailed) {
|
|
333
|
+
const line = composeWin32CommandLine(c.cmd, c.args);
|
|
334
|
+
return new Promise((resolve) => {
|
|
332
335
|
execFile(line, { timeout: 10_000, shell: true }, (retryErr) => resolve(!retryErr));
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
});
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
337
339
|
});
|
|
338
340
|
}
|
|
339
341
|
// ─── Method selection ────────────────────────────────────────────────────────
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export type CodexPolicyMode = 'plan' | 'edit' | 'skip';
|
|
1
|
+
export type CodexPolicyMode = 'plan' | 'edit' | 'auto' | 'skip';
|
|
2
2
|
export declare const CODEX_PLAN_PROFILE = "agents-plan";
|
|
3
3
|
export declare const CODEX_EDIT_PROFILE = "agents-edit";
|
|
4
|
+
export declare const CODEX_AUTO_PROFILE = "agents-auto";
|
|
4
5
|
/**
|
|
5
6
|
* Writable roots for Codex's `edit` profile: the managed user `.agents` dir, the
|
|
6
7
|
* baseline toolchain caches, and — when `cwd` is inside a repo — that repo's
|
|
@@ -17,6 +18,15 @@ export declare function codexPermissionProfileConfig(mode: Exclude<CodexPolicyMo
|
|
|
17
18
|
* Config overrides are deliberately used instead of the legacy `--sandbox`
|
|
18
19
|
* flags: named permission profiles are the only Codex surface that can keep a
|
|
19
20
|
* plan run filesystem-read-only while independently enabling network access.
|
|
21
|
+
*
|
|
22
|
+
* `auto` and `edit` share one sandbox (`:workspace` plus the writable roots) and
|
|
23
|
+
* differ only in `approval_policy`. `edit` is `on-request`: a command the sandbox
|
|
24
|
+
* denies comes back as an approval prompt, which is right when someone is sitting
|
|
25
|
+
* at the terminal. `auto` is `never`: nothing prompts, and a denied command
|
|
26
|
+
* surfaces to the model as a plain command failure — the only behavior that works
|
|
27
|
+
* for an unattended run, where a prompt nobody answers is an agent that has
|
|
28
|
+
* stopped. Autonomy is the approval axis only; neither widens the sandbox, and
|
|
29
|
+
* `skip` remains the sole mode that removes it.
|
|
20
30
|
*/
|
|
21
31
|
export declare function codexPolicyArgs(mode: CodexPolicyMode, writableRoots?: string[]): string[];
|
|
22
32
|
/** Preserve whether --mode was omitted when a run is re-dispatched remotely. */
|
package/dist/lib/codex-policy.js
CHANGED
|
@@ -4,6 +4,7 @@ import { codexDefaultWritableRoots } from './permissions.js';
|
|
|
4
4
|
import { repoAgentsDirForCwd } from './project-key.js';
|
|
5
5
|
export const CODEX_PLAN_PROFILE = 'agents-plan';
|
|
6
6
|
export const CODEX_EDIT_PROFILE = 'agents-edit';
|
|
7
|
+
export const CODEX_AUTO_PROFILE = 'agents-auto';
|
|
7
8
|
function unique(values) {
|
|
8
9
|
return [...new Set(values)];
|
|
9
10
|
}
|
|
@@ -28,25 +29,39 @@ function inlineWorkspaceRoots(roots) {
|
|
|
28
29
|
}
|
|
29
30
|
export function codexPermissionProfileConfig(mode, writableRoots = codexEditWritableRoots()) {
|
|
30
31
|
const parent = mode === 'plan' ? ':read-only' : ':workspace';
|
|
31
|
-
const roots = mode === '
|
|
32
|
-
?
|
|
33
|
-
:
|
|
32
|
+
const roots = mode === 'plan'
|
|
33
|
+
? ''
|
|
34
|
+
: `, workspace_roots = { ${inlineWorkspaceRoots(unique(writableRoots))} }`;
|
|
34
35
|
return `{ extends = ${JSON.stringify(parent)}${roots}, network = { enabled = true, allow_local_binding = true } }`;
|
|
35
36
|
}
|
|
37
|
+
const CODEX_PROFILES = {
|
|
38
|
+
plan: CODEX_PLAN_PROFILE,
|
|
39
|
+
edit: CODEX_EDIT_PROFILE,
|
|
40
|
+
auto: CODEX_AUTO_PROFILE,
|
|
41
|
+
};
|
|
36
42
|
/**
|
|
37
43
|
* Canonical Codex safety policy used by every native launch path.
|
|
38
44
|
*
|
|
39
45
|
* Config overrides are deliberately used instead of the legacy `--sandbox`
|
|
40
46
|
* flags: named permission profiles are the only Codex surface that can keep a
|
|
41
47
|
* plan run filesystem-read-only while independently enabling network access.
|
|
48
|
+
*
|
|
49
|
+
* `auto` and `edit` share one sandbox (`:workspace` plus the writable roots) and
|
|
50
|
+
* differ only in `approval_policy`. `edit` is `on-request`: a command the sandbox
|
|
51
|
+
* denies comes back as an approval prompt, which is right when someone is sitting
|
|
52
|
+
* at the terminal. `auto` is `never`: nothing prompts, and a denied command
|
|
53
|
+
* surfaces to the model as a plain command failure — the only behavior that works
|
|
54
|
+
* for an unattended run, where a prompt nobody answers is an agent that has
|
|
55
|
+
* stopped. Autonomy is the approval axis only; neither widens the sandbox, and
|
|
56
|
+
* `skip` remains the sole mode that removes it.
|
|
42
57
|
*/
|
|
43
58
|
export function codexPolicyArgs(mode, writableRoots = codexEditWritableRoots()) {
|
|
44
59
|
if (mode === 'skip')
|
|
45
60
|
return ['--dangerously-bypass-approvals-and-sandbox'];
|
|
46
|
-
const profile = mode
|
|
61
|
+
const profile = CODEX_PROFILES[mode];
|
|
47
62
|
return [
|
|
48
63
|
'-c',
|
|
49
|
-
'
|
|
64
|
+
`approval_policy=${mode === 'auto' ? '"never"' : '"on-request"'}`,
|
|
50
65
|
'-c',
|
|
51
66
|
`default_permissions=${JSON.stringify(profile)}`,
|
|
52
67
|
'-c',
|
|
@@ -33,10 +33,11 @@ export interface ParsedAutoConfigKey {
|
|
|
33
33
|
scope: 'auto';
|
|
34
34
|
property: 'pool';
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/** A device-scope browser key (self or peer): the profile agents drive, or the
|
|
37
|
+
* browser that shows the user a page. */
|
|
37
38
|
export interface ParsedBrowserConfigKey {
|
|
38
39
|
scope: 'browser';
|
|
39
|
-
property: 'profile';
|
|
40
|
+
property: 'profile' | 'viewer';
|
|
40
41
|
device?: string;
|
|
41
42
|
}
|
|
42
43
|
export interface ParsedProjectConfigKey {
|
|
@@ -50,7 +51,7 @@ export interface ParsedDeviceConfigKey {
|
|
|
50
51
|
property: DeviceConfigProperty;
|
|
51
52
|
}
|
|
52
53
|
export type ParsedConfigKey = ParsedRunConfigKey | ParsedInteractiveConfigKey | ParsedUsageConfigKey | ParsedAutoConfigKey | ParsedBrowserConfigKey | ParsedProjectConfigKey | ParsedDeviceConfigKey;
|
|
53
|
-
export type DeviceConfigProperty = 'role' | 'max-agents' | 'scheduler' | 'daemon' | 'watchdog' | 'tmux' | 'browser.remote-control' | 'browser.task-idle-minutes' | 'notes' | 'browser.profile';
|
|
54
|
+
export type DeviceConfigProperty = 'role' | 'max-agents' | 'scheduler' | 'daemon' | 'watchdog' | 'tmux' | 'browser.remote-control' | 'browser.task-idle-minutes' | 'notes' | 'browser.profile' | 'browser.viewer';
|
|
54
55
|
/** Normalize agent@version to use `@` consistently. */
|
|
55
56
|
export declare function formatAgentVersion(agent: AgentId, version: string): string;
|
|
56
57
|
/**
|
package/dist/lib/config-keys.js
CHANGED
|
@@ -10,6 +10,7 @@ import { AGENTS } from './agents.js';
|
|
|
10
10
|
import { MODEL_TIERS } from './model-tiers.js';
|
|
11
11
|
import { VERSION_RE } from './run-defaults.js';
|
|
12
12
|
const DEVICE_CONFIG_PROPERTIES = [
|
|
13
|
+
'browser.viewer',
|
|
13
14
|
'role',
|
|
14
15
|
'max-agents',
|
|
15
16
|
'scheduler',
|
|
@@ -88,10 +89,13 @@ export function parseConfigKey(key) {
|
|
|
88
89
|
if (raw === 'browser.profile') {
|
|
89
90
|
return { scope: 'browser', property: 'profile' };
|
|
90
91
|
}
|
|
92
|
+
if (raw === 'browser.viewer') {
|
|
93
|
+
return { scope: 'browser', property: 'viewer' };
|
|
94
|
+
}
|
|
91
95
|
if (raw === 'project.root') {
|
|
92
96
|
return { scope: 'project', property: 'root' };
|
|
93
97
|
}
|
|
94
|
-
const deviceMatch = raw.match(/^devices\.(.+)\.(role|max-agents|scheduler|daemon|watchdog|tmux|notes|browser\.remote-control|browser\.task-idle-minutes|browser\.profile)$/);
|
|
98
|
+
const deviceMatch = raw.match(/^devices\.(.+)\.(role|max-agents|scheduler|daemon|watchdog|tmux|notes|browser\.remote-control|browser\.task-idle-minutes|browser\.profile|browser\.viewer)$/);
|
|
95
99
|
if (deviceMatch) {
|
|
96
100
|
return {
|
|
97
101
|
scope: 'device',
|
|
@@ -113,7 +117,7 @@ export function parseConfigKey(key) {
|
|
|
113
117
|
throw new Error(`Invalid auto config key '${key}'. Use auto.pool.`);
|
|
114
118
|
}
|
|
115
119
|
if (raw.startsWith('browser.')) {
|
|
116
|
-
throw new Error(`Invalid browser config key '${key}'. Use browser.profile.`);
|
|
120
|
+
throw new Error(`Invalid browser config key '${key}'. Use browser.profile or browser.viewer.`);
|
|
117
121
|
}
|
|
118
122
|
if (raw.startsWith('project.')) {
|
|
119
123
|
throw new Error(`Invalid project config key '${key}'. Use project.root.`);
|
|
@@ -138,7 +142,9 @@ export function formatConfigKey(parsed) {
|
|
|
138
142
|
case 'auto':
|
|
139
143
|
return 'auto.pool';
|
|
140
144
|
case 'browser':
|
|
141
|
-
return parsed.device
|
|
145
|
+
return parsed.device
|
|
146
|
+
? `devices.${parsed.device}.browser.${parsed.property}`
|
|
147
|
+
: `browser.${parsed.property}`;
|
|
142
148
|
case 'project':
|
|
143
149
|
return 'project.root';
|
|
144
150
|
case 'device':
|
|
@@ -152,7 +158,7 @@ export function listKnownConfigKeys() {
|
|
|
152
158
|
for (const tier of MODEL_TIERS) {
|
|
153
159
|
keys.push(`run.<agent@version>.tier.${tier}`);
|
|
154
160
|
}
|
|
155
|
-
keys.push('interactive.host', 'usage.primary-host', 'auto.pool', 'browser.profile', 'project.root');
|
|
161
|
+
keys.push('interactive.host', 'usage.primary-host', 'auto.pool', 'browser.profile', 'browser.viewer', 'project.root');
|
|
156
162
|
for (const prop of DEVICE_CONFIG_PROPERTIES) {
|
|
157
163
|
keys.push(`devices.<name>.${prop}`);
|
|
158
164
|
}
|
|
@@ -185,6 +191,8 @@ export function devicePropertyToConfigName(property) {
|
|
|
185
191
|
return 'notes';
|
|
186
192
|
case 'browser.profile':
|
|
187
193
|
return 'browser.profile';
|
|
194
|
+
case 'browser.viewer':
|
|
195
|
+
return 'browser.viewer';
|
|
188
196
|
}
|
|
189
197
|
}
|
|
190
198
|
/**
|
|
@@ -204,10 +212,12 @@ export function configKeyStorageHint(parsed) {
|
|
|
204
212
|
return 'config.usagePrimaryHost';
|
|
205
213
|
case 'auto':
|
|
206
214
|
return 'config.autoPool';
|
|
207
|
-
case 'browser':
|
|
215
|
+
case 'browser': {
|
|
216
|
+
const yamlKey = parsed.property === 'viewer' ? 'browserViewer' : 'defaultBrowserProfile';
|
|
208
217
|
return parsed.device
|
|
209
|
-
? `devices/${parsed.device}/agents.yaml config
|
|
210
|
-
:
|
|
218
|
+
? `devices/${parsed.device}/agents.yaml config.${yamlKey}`
|
|
219
|
+
: `devices/<self>/agents.yaml config.${yamlKey}`;
|
|
220
|
+
}
|
|
211
221
|
case 'project':
|
|
212
222
|
return 'devices.<self>.projectRoot';
|
|
213
223
|
case 'device':
|
|
@@ -39,6 +39,7 @@ import { resolveClaudeSetupToken } from '../claude-account-token.js';
|
|
|
39
39
|
import { getConfiguredRunStrategy, resolveRunVersion, resolveAccountVersion, rotationFailoverChain, readinessFromCandidate, formatNoHealthyAccountError, } from '../accounting/rotate.js';
|
|
40
40
|
import { readAuthHealth, isDeadVerdict } from '../auth-health.js';
|
|
41
41
|
import { machineId } from '../machine-id.js';
|
|
42
|
+
import { selfConfiguredDeviceRole } from '../device-config.js';
|
|
42
43
|
import { isSelfUpdatingAgent, ROUTINE_AGENT_IDS, isAgentHardDeprecated, hardDeprecationError } from '../agents.js';
|
|
43
44
|
import { isCustomHarnessName, readProfile } from '../profiles.js';
|
|
44
45
|
export class RoutineAlreadyRunningError extends Error {
|
|
@@ -1120,10 +1121,22 @@ export function buildRoutineSpawnEnv(baseEnv, agent, version, timezone, overlayH
|
|
|
1120
1121
|
const setupToken = agent === 'claude' && version
|
|
1121
1122
|
? resolveClaudeSetupToken(getVersionHomePath('claude', version))
|
|
1122
1123
|
: null;
|
|
1123
|
-
|
|
1124
|
+
// A `personal` device (the user's own interactive box) uses the per-version
|
|
1125
|
+
// login for EVERY run, routines included — the setup-token is a worker-only
|
|
1126
|
+
// credential (RUSH-2395, mirrors the claude adapter's personal-device branch).
|
|
1127
|
+
// On a personal box, only strip an inherited copy of the account's OWN
|
|
1128
|
+
// setup-token by value so a leaked ambient value can't override the login; a
|
|
1129
|
+
// token the user set deliberately is a different string and survives.
|
|
1130
|
+
if (selfConfiguredDeviceRole() === 'personal') {
|
|
1131
|
+
if (setupToken && out.CLAUDE_CODE_OAUTH_TOKEN === setupToken)
|
|
1132
|
+
delete out.CLAUDE_CODE_OAUTH_TOKEN;
|
|
1133
|
+
}
|
|
1134
|
+
else if (setupToken) {
|
|
1124
1135
|
out.CLAUDE_CODE_OAUTH_TOKEN = setupToken;
|
|
1125
|
-
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1126
1138
|
delete out.CLAUDE_CODE_OAUTH_TOKEN;
|
|
1139
|
+
}
|
|
1127
1140
|
if (agent === 'cursor' && overlayHome) {
|
|
1128
1141
|
// prepareJobHome links this host's Cursor auth file here. Pin XDG_CONFIG_HOME
|
|
1129
1142
|
// to the overlay so an ambient value cannot bypass the routine sandbox.
|
package/dist/lib/daemon-ticks.js
CHANGED
|
@@ -89,7 +89,7 @@ export async function refreshLocalFleetAuthState(opts) {
|
|
|
89
89
|
// Fleet status publishes every tick regardless — it does not ride that endpoint.
|
|
90
90
|
const cached = readFleetAuthRows(self);
|
|
91
91
|
const reuse = shouldReuseCachedAuthProbe(force, cached, requestedAt);
|
|
92
|
-
const authRows = reuse ? cached : await probeLocalFleetAuth({ cliVersion: getCliVersion() });
|
|
92
|
+
const authRows = reuse ? cached : await probeLocalFleetAuth({ cliVersion: getCliVersion(), forceLive: force });
|
|
93
93
|
if (!reuse)
|
|
94
94
|
writeFleetAuthRows(self, authRows);
|
|
95
95
|
const row = await publishLocalFleetStatus(self);
|
|
@@ -129,7 +129,7 @@ export async function runUsageRefreshTick() {
|
|
|
129
129
|
const r = await runUsageRefresh({
|
|
130
130
|
listAccounts: buildLocalUsageAccounts,
|
|
131
131
|
writeUsageCache: writeClaudeUsageCache,
|
|
132
|
-
backoffUntil: usageRateLimitedUntil,
|
|
132
|
+
backoffUntil: (agentId, usageKey) => usageRateLimitedUntil(agentId, Date.now(), usageKey),
|
|
133
133
|
});
|
|
134
134
|
const { listProfiles } = await import('./profiles.js');
|
|
135
135
|
const { refreshDueByokUsage } = await import('./byok-usage.js');
|
|
@@ -147,8 +147,32 @@ export type AutoPoolMode = (typeof AUTO_POOL_MODES)[number];
|
|
|
147
147
|
* explicit `worker` mark (see {@link listConfiguredDeviceRoles}).
|
|
148
148
|
*/
|
|
149
149
|
export declare function configuredDeviceRole(name: string): ConfiguredDeviceRole | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* The role marked on THIS machine — the one running the CLI — or undefined when
|
|
152
|
+
* it was never marked. Keyed off {@link machineId} (overridable via
|
|
153
|
+
* AGENTS_SYNC_MACHINE_ID), so it matches the device's own config-folder key.
|
|
154
|
+
*
|
|
155
|
+
* The auth strategy reads this: a `personal` device (the user's own interactive
|
|
156
|
+
* box) holds a real per-version login and MUST authenticate from it for EVERY
|
|
157
|
+
* run, interactive or headless; only a `worker` uses the file-based setup-token
|
|
158
|
+
* (RUSH-2395). `undefined` is treated as non-personal (worker-equivalent) by
|
|
159
|
+
* that gate — an unmarked box has no login to defer to.
|
|
160
|
+
*/
|
|
161
|
+
export declare function selfConfiguredDeviceRole(): ConfiguredDeviceRole | undefined;
|
|
150
162
|
/** Mark a device's role fleet-wide; `undefined` clears the mark. */
|
|
151
163
|
export declare function setConfiguredDeviceRole(name: string, role: ConfiguredDeviceRole | undefined): void;
|
|
164
|
+
/**
|
|
165
|
+
* Devices whose OWN config pins one of the browser profile keys to `profile`.
|
|
166
|
+
*
|
|
167
|
+
* Used by `profiles rename` to warn rather than silently leave a peer pointing at
|
|
168
|
+
* a name that no longer exists. Deliberately read-only: rewriting another
|
|
169
|
+
* machine's device doc from here would be a cross-machine mutation nobody asked
|
|
170
|
+
* for, and the pin may well be correct there (a local profile of the same name).
|
|
171
|
+
*/
|
|
172
|
+
export declare function devicesPinningBrowserProfile(profile: string): Array<{
|
|
173
|
+
device: string;
|
|
174
|
+
key: 'browser.profile' | 'browser.viewer';
|
|
175
|
+
}>;
|
|
152
176
|
/**
|
|
153
177
|
* Every device with an effective role, keyed by device name. Layers like every
|
|
154
178
|
* other device-scope key: the fleet default (central fleet.defaults.config)
|
|
@@ -194,14 +218,7 @@ export declare function isSchedulerEnabled(): boolean;
|
|
|
194
218
|
* scheduler init) refuses with.
|
|
195
219
|
*/
|
|
196
220
|
export declare function assertSchedulerEnabled(): void;
|
|
197
|
-
/**
|
|
198
|
-
* True unless this machine's config turns off the managed tmux wrap for
|
|
199
|
-
* interactive `agents run` launches (`tmux.enabled=false`).
|
|
200
|
-
*
|
|
201
|
-
* Read as one of the guards in `shouldWrapInTmux` (lib/exec.ts) — the durable,
|
|
202
|
-
* per-machine form of `--no-tmux` / `AGENTS_NO_TMUX=1`, for a box whose tmux is
|
|
203
|
-
* broken or unwanted. Unset means today's behavior: wrap.
|
|
204
|
-
*/
|
|
221
|
+
/** True only when this machine explicitly enables the managed tmux wrap. */
|
|
205
222
|
export declare function isTmuxEnabled(): boolean;
|
|
206
223
|
/** True unless this machine's config disables the daemon outright (top-level kill switch). */
|
|
207
224
|
export declare function isDaemonEnabled(): boolean;
|