@phnx-labs/agents-cli 1.22.116 → 1.22.118
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 +247 -0
- package/dist/bootstrap.js +4 -11
- 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.d.ts +18 -0
- package/dist/commands/exec.js +104 -12
- 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-term.d.ts +4 -3
- package/dist/commands/setup-term.js +5 -4
- package/dist/commands/setup.js +11 -11
- 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/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 +6 -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-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 +0 -11
- 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/harness-auth-capabilities.js +0 -1
- 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/hosts/remote-cmd.js +1 -0
- 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.js +9 -7
- package/dist/lib/installations/update.js +21 -15
- package/dist/lib/installations/versions.js +12 -1
- 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/placement.d.ts +2 -0
- package/dist/lib/placement.js +5 -0
- package/dist/lib/profiles.js +0 -2
- 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/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/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 +8 -12
- 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 +10 -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
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/** The single site that derives a {@link ConnectionKey} from its two parts. */
|
|
2
|
-
export function connectionKey(profile, endpoint) {
|
|
3
|
-
return `${profile}@${endpoint}`;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Adopt a string that IS already a runtime key — a runtime directory name, a
|
|
7
|
-
* `tasks.json` `profile` field, a fork key. Never use it to launder a bare
|
|
8
|
-
* profile name into a key; use {@link connectionKey} for that.
|
|
9
|
-
*/
|
|
10
|
-
export function asConnectionKey(raw) {
|
|
11
|
-
return raw;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Split a {@link ConnectionKey} back into its parts. The inverse of
|
|
15
|
-
* {@link connectionKey}, and the ONE rule every consumer uses to decide whether
|
|
16
|
-
* a runtime key belongs to a profile.
|
|
17
|
-
*
|
|
18
|
-
* Tolerates the legacy shape still on disk: a pre-composite key that is just
|
|
19
|
-
* the bare profile name (`comet-local`).
|
|
20
|
-
*
|
|
21
|
-
* A key with no `@` is read as a WHOLE profile name, never as `<name>.<fork>`,
|
|
22
|
-
* because nothing constrains a profile's name (`createProfile` checks only for
|
|
23
|
-
* a duplicate name and a port collision). Reading the trailing digits as a fork
|
|
24
|
-
* would let `stop --profile chrome` claim the runtime dirs of a separate
|
|
25
|
-
* profile named `chrome.2` and kill its browser. A fork is only ever created
|
|
26
|
-
* from a composite base (`forkElectronProfile` appends to a `<p>@<e>` key), so
|
|
27
|
-
* the `@`-bearing branch below is the one that must understand forks.
|
|
28
|
-
*/
|
|
29
|
-
export function parseConnectionKey(key) {
|
|
30
|
-
// LAST `@`, not the first: a profile name may itself contain one (`me@work`),
|
|
31
|
-
// and splitting on the first would report its profile as `me` — so
|
|
32
|
-
// `status --profile me@work` would find nothing for a running browser.
|
|
33
|
-
const at = key.lastIndexOf('@');
|
|
34
|
-
if (at === -1)
|
|
35
|
-
return { profile: key };
|
|
36
|
-
const profile = key.slice(0, at);
|
|
37
|
-
const rest = key.slice(at + 1);
|
|
38
|
-
const dot = rest.indexOf('.');
|
|
39
|
-
if (dot === -1)
|
|
40
|
-
return { profile, endpoint: rest };
|
|
41
|
-
const fork = Number(rest.slice(dot + 1));
|
|
42
|
-
return {
|
|
43
|
-
profile,
|
|
44
|
-
endpoint: rest.slice(0, dot),
|
|
45
|
-
fork: Number.isFinite(fork) ? fork : undefined,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
/** True when `key` is a runtime key of `profile`. The only reconciliation rule. */
|
|
49
|
-
export function keyBelongsToProfile(key, profile) {
|
|
50
|
-
return parseConnectionKey(key).profile === profile;
|
|
51
|
-
}
|
|
52
|
-
const TASK_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
|
|
53
|
-
export function isValidTaskId(id) {
|
|
54
|
-
return TASK_ID_REGEX.test(id) && id.length <= 64;
|
|
55
|
-
}
|
|
56
|
-
export function generateTaskId() {
|
|
57
|
-
return crypto.randomUUID().slice(0, 8);
|
|
58
|
-
}
|
|
59
|
-
export function generateShortId() {
|
|
60
|
-
return crypto.randomUUID().split('-')[0]; // 8 chars
|
|
61
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { CDPClient } from './cdp.js';
|
|
2
|
-
import { type RefNode } from './refs.js';
|
|
3
|
-
export declare function getUploadStagingDir(): string;
|
|
4
|
-
export declare function stageUploadFile(source: string): string;
|
|
5
|
-
/** Pattern A — direct file input via `DOM.setFileInputFiles`. */
|
|
6
|
-
export declare function uploadToFileInput(cdp: CDPClient, sessionId: string, backendNodeId: number, files: string[]): Promise<void>;
|
|
7
|
-
/** Pattern B — synthetic drag-drop onto a target node. */
|
|
8
|
-
export declare function uploadToDropTarget(cdp: CDPClient, sessionId: string, backendNodeId: number, files: string[]): Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* Pattern C — click a trigger, intercept the OS file chooser, feed files.
|
|
11
|
-
*
|
|
12
|
-
* `Page.setInterceptFileChooserDialog` must be enabled before the click; the
|
|
13
|
-
* chooser only fires once, so we register a single-shot handler ahead of time.
|
|
14
|
-
* Auto-attached child sessions matter here: the chooser event arrives on the
|
|
15
|
-
* session whose page hosts the input, which is the same session we used for
|
|
16
|
-
* the click — so we filter event params by sessionId.
|
|
17
|
-
*/
|
|
18
|
-
export declare function uploadViaFileChooser(cdp: CDPClient, sessionId: string, triggerRef: {
|
|
19
|
-
node: RefNode;
|
|
20
|
-
nodeMap: Map<number, RefNode>;
|
|
21
|
-
}, files: string[], timeoutMs?: number): Promise<void>;
|
|
22
|
-
export declare function mimeFromExt(filePath: string): string;
|
|
23
|
-
/**
|
|
24
|
-
* Inspect a ref's DOM node to decide which pattern fits when the caller
|
|
25
|
-
* didn't specify. Returns 'input' if the node is `<input type=file>`,
|
|
26
|
-
* otherwise 'drop'. Chooser interception (Pattern C) is never auto-selected
|
|
27
|
-
* because it requires clicking the ref, which mutates page state — opt-in only.
|
|
28
|
-
*/
|
|
29
|
-
export declare function detectUploadPattern(cdp: CDPClient, sessionId: string, backendNodeId: number): Promise<'input' | 'drop'>;
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { randomBytes } from 'crypto';
|
|
4
|
-
import { clickAtCoords } from './input.js';
|
|
5
|
-
import { getBrowserRuntimeDir } from './profiles.js';
|
|
6
|
-
import { resolveRefToCoords } from './refs.js';
|
|
7
|
-
export function getUploadStagingDir() {
|
|
8
|
-
return path.join(getBrowserRuntimeDir(), 'uploads');
|
|
9
|
-
}
|
|
10
|
-
export function stageUploadFile(source) {
|
|
11
|
-
if (!path.isAbsolute(source)) {
|
|
12
|
-
throw new Error(`upload-stage: source path must be absolute: ${source}`);
|
|
13
|
-
}
|
|
14
|
-
const resolvedSource = fs.realpathSync(source);
|
|
15
|
-
const stat = fs.statSync(resolvedSource);
|
|
16
|
-
if (!stat.isFile()) {
|
|
17
|
-
throw new Error(`upload-stage: source path is not a file: ${source}`);
|
|
18
|
-
}
|
|
19
|
-
const stagingDir = getUploadStagingDir();
|
|
20
|
-
fs.mkdirSync(stagingDir, { recursive: true, mode: 0o700 });
|
|
21
|
-
fs.chmodSync(stagingDir, 0o700);
|
|
22
|
-
const stagedPath = path.join(stagingDir, `${randomBytes(8).toString('hex')}${path.extname(source)}`);
|
|
23
|
-
fs.copyFileSync(resolvedSource, stagedPath);
|
|
24
|
-
return stagedPath;
|
|
25
|
-
}
|
|
26
|
-
const RESOLVE_FILE_INPUT_FN = `(function() {
|
|
27
|
-
const start = this;
|
|
28
|
-
// Walk multiple paths to find an <input type=file>:
|
|
29
|
-
// 1. The node itself (when the AX backend node IS the input).
|
|
30
|
-
// 2. Its ancestors via parentElement (custom button wrappers).
|
|
31
|
-
// 3. closest('input[type=file]') (handles label/span/button inside or
|
|
32
|
-
// near a file input).
|
|
33
|
-
// 4. Across user-agent shadow boundaries via getRootNode().host
|
|
34
|
-
// (Chromium's internal shadow-button pseudo-element for file inputs).
|
|
35
|
-
// 5. If the AX backend node is associated with a <label for=...>, follow
|
|
36
|
-
// the htmlFor relationship.
|
|
37
|
-
// 6. Last resort: if the start node was a click target that fires
|
|
38
|
-
// input.click() inside a click handler, fall back to the unique
|
|
39
|
-
// <input type=file> on the page (when there is exactly one).
|
|
40
|
-
let el = start;
|
|
41
|
-
for (let i = 0; i < 8 && el; i++) {
|
|
42
|
-
if (el.tagName === 'INPUT' && el.type === 'file') return el;
|
|
43
|
-
if (el.closest) {
|
|
44
|
-
const found = el.closest('input[type=file]');
|
|
45
|
-
if (found) return found;
|
|
46
|
-
}
|
|
47
|
-
if (el.tagName === 'LABEL' && el.htmlFor) {
|
|
48
|
-
const t = document.getElementById(el.htmlFor);
|
|
49
|
-
if (t && t.tagName === 'INPUT' && t.type === 'file') return t;
|
|
50
|
-
}
|
|
51
|
-
const root = el.getRootNode && el.getRootNode();
|
|
52
|
-
if (root && root.host && root !== document) {
|
|
53
|
-
el = root.host;
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
el = el.parentElement;
|
|
57
|
-
}
|
|
58
|
-
// Final fallback: if exactly one file input exists on the page, use it.
|
|
59
|
-
// This handles cases where the AX tree exposes the input as an internal
|
|
60
|
-
// pseudo-button whose parentElement is null. A page with a single uploader
|
|
61
|
-
// (Slack composer, Notion image block, Canva ingredient) hits this branch.
|
|
62
|
-
const all = document.querySelectorAll('input[type=file]');
|
|
63
|
-
if (all.length === 1) return all[0];
|
|
64
|
-
return null;
|
|
65
|
-
})`;
|
|
66
|
-
/** Pattern A — direct file input via `DOM.setFileInputFiles`. */
|
|
67
|
-
export async function uploadToFileInput(cdp, sessionId, backendNodeId, files) {
|
|
68
|
-
validateFiles(files);
|
|
69
|
-
const resolvedId = await resolveActualFileInput(cdp, sessionId, backendNodeId);
|
|
70
|
-
await cdp.send('DOM.setFileInputFiles', { files, backendNodeId: resolvedId }, sessionId);
|
|
71
|
-
}
|
|
72
|
-
async function resolveActualFileInput(cdp, sessionId, backendNodeId) {
|
|
73
|
-
const { object } = await cdp.send('DOM.resolveNode', { backendNodeId }, sessionId);
|
|
74
|
-
if (!object.objectId)
|
|
75
|
-
return backendNodeId;
|
|
76
|
-
const objectId = object.objectId;
|
|
77
|
-
try {
|
|
78
|
-
const { result } = await cdp.send('Runtime.callFunctionOn', { objectId, functionDeclaration: RESOLVE_FILE_INPUT_FN, returnByValue: false }, sessionId);
|
|
79
|
-
if (!result.objectId) {
|
|
80
|
-
throw new Error('Ref is not (and is not contained in) an <input type=file>');
|
|
81
|
-
}
|
|
82
|
-
const inputObjectId = result.objectId;
|
|
83
|
-
try {
|
|
84
|
-
const { node } = await cdp.send('DOM.describeNode', { objectId: inputObjectId }, sessionId);
|
|
85
|
-
return node.backendNodeId;
|
|
86
|
-
}
|
|
87
|
-
finally {
|
|
88
|
-
await cdp.send('Runtime.releaseObject', { objectId: inputObjectId }, sessionId);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
92
|
-
await cdp.send('Runtime.releaseObject', { objectId }, sessionId);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const DRAG_DROP_FN = `(function(files) {
|
|
96
|
-
const el = this;
|
|
97
|
-
const rect = el.getBoundingClientRect();
|
|
98
|
-
const x = rect.left + rect.width / 2;
|
|
99
|
-
const y = rect.top + rect.height / 2;
|
|
100
|
-
const dt = new DataTransfer();
|
|
101
|
-
for (const f of files) {
|
|
102
|
-
const u8 = Uint8Array.from(atob(f.bytes), c => c.charCodeAt(0));
|
|
103
|
-
const blob = new Blob([u8], { type: f.type || 'application/octet-stream' });
|
|
104
|
-
const file = new File([blob], f.name, { type: f.type || 'application/octet-stream' });
|
|
105
|
-
dt.items.add(file);
|
|
106
|
-
}
|
|
107
|
-
function dispatch(type) {
|
|
108
|
-
// Chromium does not honor the dataTransfer field in DragEventInit for
|
|
109
|
-
// synthetic events. Build the DragEvent with no dataTransfer in the init,
|
|
110
|
-
// then override the event dataTransfer getter via defineProperty so
|
|
111
|
-
// page-level listeners see the File list we constructed.
|
|
112
|
-
const ev = new DragEvent(type, {
|
|
113
|
-
bubbles: true,
|
|
114
|
-
cancelable: true,
|
|
115
|
-
composed: true,
|
|
116
|
-
clientX: x,
|
|
117
|
-
clientY: y,
|
|
118
|
-
});
|
|
119
|
-
Object.defineProperty(ev, 'dataTransfer', { value: dt });
|
|
120
|
-
el.dispatchEvent(ev);
|
|
121
|
-
}
|
|
122
|
-
dispatch('dragenter');
|
|
123
|
-
dispatch('dragover');
|
|
124
|
-
dispatch('drop');
|
|
125
|
-
return { dispatched: 3, files: files.length };
|
|
126
|
-
})`;
|
|
127
|
-
/** Pattern B — synthetic drag-drop onto a target node. */
|
|
128
|
-
export async function uploadToDropTarget(cdp, sessionId, backendNodeId, files) {
|
|
129
|
-
validateFiles(files);
|
|
130
|
-
const payload = files.map((p) => ({
|
|
131
|
-
name: path.basename(p),
|
|
132
|
-
type: mimeFromExt(p),
|
|
133
|
-
bytes: fs.readFileSync(p).toString('base64'),
|
|
134
|
-
}));
|
|
135
|
-
const { object } = await cdp.send('DOM.resolveNode', { backendNodeId }, sessionId);
|
|
136
|
-
if (!object.objectId) {
|
|
137
|
-
throw new Error('Drop target node could not be resolved');
|
|
138
|
-
}
|
|
139
|
-
const objectId = object.objectId;
|
|
140
|
-
try {
|
|
141
|
-
const r = await cdp.send('Runtime.callFunctionOn', {
|
|
142
|
-
objectId,
|
|
143
|
-
functionDeclaration: DRAG_DROP_FN,
|
|
144
|
-
arguments: [{ value: payload }],
|
|
145
|
-
returnByValue: true,
|
|
146
|
-
awaitPromise: true,
|
|
147
|
-
}, sessionId);
|
|
148
|
-
if (r.exceptionDetails) {
|
|
149
|
-
throw new Error('Drop dispatch threw: ' + JSON.stringify(r.exceptionDetails));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
finally {
|
|
153
|
-
await cdp.send('Runtime.releaseObject', { objectId }, sessionId);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Pattern C — click a trigger, intercept the OS file chooser, feed files.
|
|
158
|
-
*
|
|
159
|
-
* `Page.setInterceptFileChooserDialog` must be enabled before the click; the
|
|
160
|
-
* chooser only fires once, so we register a single-shot handler ahead of time.
|
|
161
|
-
* Auto-attached child sessions matter here: the chooser event arrives on the
|
|
162
|
-
* session whose page hosts the input, which is the same session we used for
|
|
163
|
-
* the click — so we filter event params by sessionId.
|
|
164
|
-
*/
|
|
165
|
-
export async function uploadViaFileChooser(cdp, sessionId, triggerRef, files, timeoutMs = 5000) {
|
|
166
|
-
validateFiles(files);
|
|
167
|
-
await cdp.send('Page.enable', {}, sessionId);
|
|
168
|
-
await cdp.send('Page.setInterceptFileChooserDialog', { enabled: true }, sessionId);
|
|
169
|
-
let opened = null;
|
|
170
|
-
let resolve;
|
|
171
|
-
let reject;
|
|
172
|
-
const wait = new Promise((res, rej) => {
|
|
173
|
-
resolve = res;
|
|
174
|
-
reject = rej;
|
|
175
|
-
});
|
|
176
|
-
const handler = (params) => {
|
|
177
|
-
const ev = params;
|
|
178
|
-
if (typeof ev.backendNodeId === 'number') {
|
|
179
|
-
opened = { backendNodeId: ev.backendNodeId };
|
|
180
|
-
resolve();
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
cdp.on('Page.fileChooserOpened', handler);
|
|
184
|
-
const timer = setTimeout(() => {
|
|
185
|
-
reject(new Error(`File chooser did not open within ${timeoutMs}ms — is the trigger ref correct?`));
|
|
186
|
-
}, timeoutMs);
|
|
187
|
-
try {
|
|
188
|
-
const { x, y } = await resolveRefToCoords(cdp, sessionId, triggerRef.nodeMap, triggerRef.node.ref);
|
|
189
|
-
await clickAtCoords(cdp, sessionId, x, y);
|
|
190
|
-
await wait;
|
|
191
|
-
await cdp.send('Page.handleFileChooser', { action: 'accept', files }, sessionId);
|
|
192
|
-
// Some Chromium builds expect setFileInputFiles instead of handleFileChooser.
|
|
193
|
-
// We try handleFileChooser first because it's the documented path for
|
|
194
|
-
// intercepted dialogs; if Chromium rejects it (older protocol), fall back
|
|
195
|
-
// to setFileInputFiles using the backendNodeId from the event.
|
|
196
|
-
}
|
|
197
|
-
catch (err) {
|
|
198
|
-
if (opened && err instanceof Error && /not supported|not found|Method/i.test(err.message)) {
|
|
199
|
-
await cdp.send('DOM.setFileInputFiles', { files, backendNodeId: opened.backendNodeId }, sessionId);
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
throw err;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
finally {
|
|
206
|
-
clearTimeout(timer);
|
|
207
|
-
cdp.off('Page.fileChooserOpened', handler);
|
|
208
|
-
await cdp.send('Page.setInterceptFileChooserDialog', { enabled: false }, sessionId).catch(() => { });
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
function validateFiles(files) {
|
|
212
|
-
if (!files || files.length === 0) {
|
|
213
|
-
throw new Error('At least one file path is required');
|
|
214
|
-
}
|
|
215
|
-
const stagingDir = getUploadStagingDir();
|
|
216
|
-
fs.mkdirSync(stagingDir, { recursive: true, mode: 0o700 });
|
|
217
|
-
fs.chmodSync(stagingDir, 0o700);
|
|
218
|
-
const resolvedStagingDir = fs.realpathSync(stagingDir);
|
|
219
|
-
for (const f of files) {
|
|
220
|
-
if (!path.isAbsolute(f)) {
|
|
221
|
-
throw new Error(`Upload path must be absolute: ${f}`);
|
|
222
|
-
}
|
|
223
|
-
if (!fs.existsSync(f)) {
|
|
224
|
-
throw new Error(`File not found: ${f}`);
|
|
225
|
-
}
|
|
226
|
-
const resolvedFile = fs.realpathSync(f);
|
|
227
|
-
if (!isPathInside(resolvedFile, resolvedStagingDir)) {
|
|
228
|
-
throw new Error(`upload: path ${f} is outside the upload staging directory ${stagingDir}. ` +
|
|
229
|
-
`Stage files via 'agents browser upload-stage <path>' first.`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
function isPathInside(candidate, dir) {
|
|
234
|
-
const rel = path.relative(dir, candidate);
|
|
235
|
-
return rel === '' || (!!rel && !rel.startsWith('..') && !path.isAbsolute(rel));
|
|
236
|
-
}
|
|
237
|
-
const MIME_BY_EXT = {
|
|
238
|
-
'.png': 'image/png',
|
|
239
|
-
'.jpg': 'image/jpeg',
|
|
240
|
-
'.jpeg': 'image/jpeg',
|
|
241
|
-
'.gif': 'image/gif',
|
|
242
|
-
'.webp': 'image/webp',
|
|
243
|
-
'.svg': 'image/svg+xml',
|
|
244
|
-
'.pdf': 'application/pdf',
|
|
245
|
-
'.txt': 'text/plain',
|
|
246
|
-
'.csv': 'text/csv',
|
|
247
|
-
'.json': 'application/json',
|
|
248
|
-
'.zip': 'application/zip',
|
|
249
|
-
'.mp4': 'video/mp4',
|
|
250
|
-
'.mov': 'video/quicktime',
|
|
251
|
-
'.mp3': 'audio/mpeg',
|
|
252
|
-
'.wav': 'audio/wav',
|
|
253
|
-
};
|
|
254
|
-
export function mimeFromExt(filePath) {
|
|
255
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
256
|
-
return MIME_BY_EXT[ext] ?? 'application/octet-stream';
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Inspect a ref's DOM node to decide which pattern fits when the caller
|
|
260
|
-
* didn't specify. Returns 'input' if the node is `<input type=file>`,
|
|
261
|
-
* otherwise 'drop'. Chooser interception (Pattern C) is never auto-selected
|
|
262
|
-
* because it requires clicking the ref, which mutates page state — opt-in only.
|
|
263
|
-
*/
|
|
264
|
-
export async function detectUploadPattern(cdp, sessionId, backendNodeId) {
|
|
265
|
-
const { node } = await cdp.send('DOM.describeNode', { backendNodeId, depth: 0 }, sessionId);
|
|
266
|
-
if (isFileInputNode(node))
|
|
267
|
-
return 'input';
|
|
268
|
-
// The node itself isn't <input type=file>, but it might be a button or
|
|
269
|
-
// shadow-DOM descendant *inside* one — that's what the accessibility tree
|
|
270
|
-
// surfaces for file inputs. Walk up to confirm before falling back to drop.
|
|
271
|
-
const { object } = await cdp.send('DOM.resolveNode', { backendNodeId }, sessionId);
|
|
272
|
-
if (!object.objectId)
|
|
273
|
-
return 'drop';
|
|
274
|
-
const objectId = object.objectId;
|
|
275
|
-
try {
|
|
276
|
-
const { result } = await cdp.send('Runtime.callFunctionOn', { objectId, functionDeclaration: RESOLVE_FILE_INPUT_FN, returnByValue: false }, sessionId);
|
|
277
|
-
if (result.objectId) {
|
|
278
|
-
await cdp.send('Runtime.releaseObject', { objectId: result.objectId }, sessionId);
|
|
279
|
-
return 'input';
|
|
280
|
-
}
|
|
281
|
-
return 'drop';
|
|
282
|
-
}
|
|
283
|
-
finally {
|
|
284
|
-
await cdp.send('Runtime.releaseObject', { objectId }, sessionId);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function isFileInputNode(node) {
|
|
288
|
-
const tag = (node.nodeName ?? '').toLowerCase();
|
|
289
|
-
if (tag !== 'input')
|
|
290
|
-
return false;
|
|
291
|
-
const attrs = node.attributes ?? [];
|
|
292
|
-
for (let i = 0; i < attrs.length; i += 2) {
|
|
293
|
-
if (attrs[i] === 'type' && attrs[i + 1]?.toLowerCase() === 'file') {
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser IPC server lifecycle as a `DaemonService` (RUSH-3193 P2).
|
|
3
|
-
*
|
|
4
|
-
* Wraps `BrowserIPCServer` (backed by a `BrowserService`) under the
|
|
5
|
-
* `ServiceSupervisor` contract. `onStart()` runs the orphan-process reap
|
|
6
|
-
* that must happen before the BrowserService comes up (same as the comment
|
|
7
|
-
* at daemon.ts:1303 — reaps browser/tunnel processes from prior daemons so
|
|
8
|
-
* the new session doesn't hijack stale tunnels or fail to bind claimed ports).
|
|
9
|
-
*/
|
|
10
|
-
import { BaseDaemonService, type DaemonContext } from './service.js';
|
|
11
|
-
import type { DaemonServiceId } from '../daemon-services.js';
|
|
12
|
-
import { BrowserService } from '../browser/service.js';
|
|
13
|
-
export declare class BrowserIPCService extends BaseDaemonService {
|
|
14
|
-
readonly id: DaemonServiceId;
|
|
15
|
-
private readonly browserSvc;
|
|
16
|
-
private ipc;
|
|
17
|
-
constructor(browserService: BrowserService);
|
|
18
|
-
protected onStart(ctx: DaemonContext): Promise<void>;
|
|
19
|
-
protected onStop(): Promise<void>;
|
|
20
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser IPC server lifecycle as a `DaemonService` (RUSH-3193 P2).
|
|
3
|
-
*
|
|
4
|
-
* Wraps `BrowserIPCServer` (backed by a `BrowserService`) under the
|
|
5
|
-
* `ServiceSupervisor` contract. `onStart()` runs the orphan-process reap
|
|
6
|
-
* that must happen before the BrowserService comes up (same as the comment
|
|
7
|
-
* at daemon.ts:1303 — reaps browser/tunnel processes from prior daemons so
|
|
8
|
-
* the new session doesn't hijack stale tunnels or fail to bind claimed ports).
|
|
9
|
-
*/
|
|
10
|
-
import { BaseDaemonService } from './service.js';
|
|
11
|
-
import { BrowserIPCServer } from '../browser/ipc.js';
|
|
12
|
-
export class BrowserIPCService extends BaseDaemonService {
|
|
13
|
-
id = 'browser-ipc';
|
|
14
|
-
browserSvc;
|
|
15
|
-
ipc = null;
|
|
16
|
-
constructor(browserService) {
|
|
17
|
-
super();
|
|
18
|
-
this.browserSvc = browserService;
|
|
19
|
-
}
|
|
20
|
-
async onStart(ctx) {
|
|
21
|
-
// Reap browser/tunnel orphans from prior daemons before the IPC server
|
|
22
|
-
// binds. A hard-crashed daemon may leave processes that either hijack a
|
|
23
|
-
// stale CDP profile or hold ports the new socket would need.
|
|
24
|
-
try {
|
|
25
|
-
const { reapOrphanedProcesses } = await import('../browser/runtime-state.js');
|
|
26
|
-
const result = reapOrphanedProcesses();
|
|
27
|
-
if (result.reaped > 0) {
|
|
28
|
-
ctx.log('INFO', `Reaped ${result.reaped} orphan process(es) from prior daemon(s)`);
|
|
29
|
-
for (const d of result.details)
|
|
30
|
-
ctx.log('INFO', ` ${d}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
ctx.log('ERROR', `Orphan reaper failed: ${err.message}`);
|
|
35
|
-
}
|
|
36
|
-
this.ipc = new BrowserIPCServer(this.browserSvc);
|
|
37
|
-
await this.ipc.start();
|
|
38
|
-
ctx.log('INFO', 'Browser IPC server started');
|
|
39
|
-
}
|
|
40
|
-
async onStop() {
|
|
41
|
-
if (this.ipc) {
|
|
42
|
-
await this.ipc.stop();
|
|
43
|
-
this.ipc = null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/** Abandoned browser-task cleanup under supervision. */
|
|
2
|
-
import { BrowserService } from '../browser/service.js';
|
|
3
|
-
import type { DaemonServiceId } from '../daemon-services.js';
|
|
4
|
-
import { BasePeriodicService, type DaemonContext } from './service.js';
|
|
5
|
-
export declare class BrowserTaskReapService extends BasePeriodicService {
|
|
6
|
-
private readonly browserService;
|
|
7
|
-
readonly id: DaemonServiceId;
|
|
8
|
-
readonly intervalMs: number;
|
|
9
|
-
readonly deadlineMs: number;
|
|
10
|
-
constructor(browserService: BrowserService);
|
|
11
|
-
protected onStart(_ctx: DaemonContext): Promise<void>;
|
|
12
|
-
protected onStop(): Promise<void>;
|
|
13
|
-
protected onTick(ctx: DaemonContext): Promise<void>;
|
|
14
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** Abandoned browser-task cleanup under supervision. */
|
|
2
|
-
import { resolveBrowserTaskIdleMs } from '../device-config.js';
|
|
3
|
-
import { BasePeriodicService } from './service.js';
|
|
4
|
-
const BROWSER_TASK_REAP_TICK_MS = 5 * 60_000;
|
|
5
|
-
const BROWSER_TASK_REAP_DEADLINE_MS = 2 * 60_000;
|
|
6
|
-
export class BrowserTaskReapService extends BasePeriodicService {
|
|
7
|
-
browserService;
|
|
8
|
-
id = 'browser-task-reap';
|
|
9
|
-
intervalMs = BROWSER_TASK_REAP_TICK_MS;
|
|
10
|
-
deadlineMs = BROWSER_TASK_REAP_DEADLINE_MS;
|
|
11
|
-
constructor(browserService) {
|
|
12
|
-
super();
|
|
13
|
-
this.browserService = browserService;
|
|
14
|
-
}
|
|
15
|
-
async onStart(_ctx) { }
|
|
16
|
-
async onStop() { }
|
|
17
|
-
async onTick(ctx) {
|
|
18
|
-
const result = await this.browserService.reapAbandoned({ idleMs: await resolveBrowserTaskIdleMs() });
|
|
19
|
-
if (result.closed.length > 0) {
|
|
20
|
-
ctx.log('INFO', `Browser-task reaper: closed ${result.closed.length} task(s)`);
|
|
21
|
-
for (const closed of result.closed) {
|
|
22
|
-
ctx.log('INFO', ` ${closed.task} (${closed.reason}, profile ${closed.profile})`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export declare const FLEET_SHARED_REPO_SYNC_DEADLINE_MS = 45000;
|
|
2
|
-
export declare const FLEET_SHARED_REPO_OUTPUT_MAX_BYTES: number;
|
|
3
|
-
/**
|
|
4
|
-
* When the shared-state exchange last completed successfully, in epoch ms, or
|
|
5
|
-
* `null` if it never has on this box (no marker yet) or the marker is unreadable.
|
|
6
|
-
* Reads the default daemon-dir marker the periodic exchange writes.
|
|
7
|
-
*/
|
|
8
|
-
export declare function readLastSuccessfulExchangeMs(): number | null;
|
|
9
|
-
interface BoundedProcessResult {
|
|
10
|
-
code: number | null;
|
|
11
|
-
stdout: string;
|
|
12
|
-
stderr: string;
|
|
13
|
-
timedOut: boolean;
|
|
14
|
-
}
|
|
15
|
-
interface FleetSharedRepoSyncOptions {
|
|
16
|
-
userAgentsDir?: string;
|
|
17
|
-
device?: string;
|
|
18
|
-
timeoutMs?: number;
|
|
19
|
-
/** Test-only redirection for the untracked cross-process lock target. */
|
|
20
|
-
lockPath?: string;
|
|
21
|
-
}
|
|
22
|
-
export interface FleetSharedRepoSyncResult {
|
|
23
|
-
success: boolean;
|
|
24
|
-
committed: boolean;
|
|
25
|
-
pushed: boolean;
|
|
26
|
-
commit: string | null;
|
|
27
|
-
timedOut: boolean;
|
|
28
|
-
skipped: string | null;
|
|
29
|
-
error: string | null;
|
|
30
|
-
/**
|
|
31
|
-
* Untracked working-tree files that collided with origin and were dropped
|
|
32
|
-
* (byte-identical to origin) before rebasing. See clearCollidingUntracked.
|
|
33
|
-
*/
|
|
34
|
-
untrackedCleared?: number;
|
|
35
|
-
/**
|
|
36
|
-
* Untracked working-tree files that collided with origin, differed from it,
|
|
37
|
-
* and were moved to untrackedBackupDir before rebasing.
|
|
38
|
-
*/
|
|
39
|
-
untrackedBackedUp?: string[];
|
|
40
|
-
/** Directory the differing untracked collisions were moved to, if any. */
|
|
41
|
-
untrackedBackupDir?: string;
|
|
42
|
-
}
|
|
43
|
-
/** Run one real process asynchronously with a hard wall-clock/process-tree bound. */
|
|
44
|
-
export declare function runBoundedProcess(command: string, args: string[], options: {
|
|
45
|
-
cwd: string;
|
|
46
|
-
timeoutMs: number;
|
|
47
|
-
env?: NodeJS.ProcessEnv;
|
|
48
|
-
}): Promise<BoundedProcessResult>;
|
|
49
|
-
/**
|
|
50
|
-
* Commit/pull/push this device's shared state under one cross-process lock.
|
|
51
|
-
* Callers publish their local fields first and consume peer fields only after
|
|
52
|
-
* this resolves successfully.
|
|
53
|
-
*/
|
|
54
|
-
export declare function syncFleetSharedStateRepo(options?: FleetSharedRepoSyncOptions): Promise<FleetSharedRepoSyncResult>;
|
|
55
|
-
export {};
|