diff --git a/CHANGELOG.md b/CHANGELOG.md index c99ca7fd94..a532cf25b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Behavior change: `resolveHubAppReference`, shipped through `agent-device/plugins/webdriver`, now needs `cwd` to resolve a relative app path. Without it the call fails with `INVALID_ARGS` and `details.reason: provider_app_cwd_missing`; it used to resolve against the process's working directory. Absolute paths, URLs and provider references are unaffected. The daemon fills it from the client's working directory (or its host's) for every provider lease request, so `connect` and `lease_allocate` are unchanged. - The `daemon-not-running` hint now always names `--state-dir
( + command: (params: P) => R, +): (params: Omit
) => R {
+ return (params) => command({ host: createTestHostEnvironment(), ...params } as P);
+}
diff --git a/src/agent-device-client.ts b/src/agent-device-client.ts
index 4bc838f0a0..07f0635f74 100644
--- a/src/agent-device-client.ts
+++ b/src/agent-device-client.ts
@@ -59,7 +59,7 @@ import {
type DaemonCommandName,
} from './commands/command-projection.ts';
import type { CommandResult } from '@agent-device/command-registry/command-result';
-import { sendToDaemon } from './daemon-client/daemon-client.ts';
+import { createDaemonTransport } from './daemon-client/daemon-client.ts';
import { resolveDaemonPaths } from '@agent-device/daemon-contracts/daemon-resolution';
import {
prepareMetroRuntime,
@@ -76,15 +76,18 @@ import {
} from '@agent-device/kernel/record';
import { readSnapshotViewportSize } from '@agent-device/kernel/rect';
import { readResponseWarnings } from '@agent-device/kernel/success-text';
+import { captureHostEnvironment } from '@agent-device/host-kit/process';
+import type { HostEnvironment } from '@agent-device/kernel/source-value';
import { createLeaseClient } from './client/lease-client.ts';
import { normalizeScreenshotCaptureResult } from './client/screenshot-result.ts';
import { createRequestGuard } from './daemon-client/daemon-client-transport.ts';
export function createAgentDeviceClient(
config: AgentDeviceClientConfig = {},
- deps: { transport?: AgentDeviceDaemonTransport } = {},
+ deps: { transport?: AgentDeviceDaemonTransport; host?: HostEnvironment } = {},
): AgentDeviceClient {
- const transport = deps.transport ?? sendToDaemon;
+ const host = deps.host ?? captureHostEnvironment(process);
+ const transport = deps.transport ?? createDaemonTransport(host);
// A typo in a JSON or JS config must not fall through to the default and manage a daemon.
readDaemonLifecycle(config.daemonLifecycle);
@@ -216,7 +219,10 @@ export function createAgentDeviceClient(
// Pure local resolution; mirrors how the daemon client picks its state dir.
stateDir: async (options = {}) => {
const merged = mergeClientOptions(config, options);
- return resolveDaemonPaths(merged.stateDir ?? process.env.AGENT_DEVICE_STATE_DIR).baseDir;
+ return resolveDaemonPaths(merged.stateDir ?? host.env.AGENT_DEVICE_STATE_DIR, {
+ env: host.env,
+ cwd: host.cwd,
+ }).baseDir;
},
close: async (options = {}) => {
const session = resolveRequestSession(options);
diff --git a/src/bin.ts b/src/bin.ts
index 1763cfff55..c42815e437 100644
--- a/src/bin.ts
+++ b/src/bin.ts
@@ -1,13 +1,29 @@
+import { withCommandHost } from '@agent-device/host-kit/command';
+import { captureHostEnvironment } from '@agent-device/host-kit/process';
import { runEntry } from './cli/entry.ts';
declare const __AGENT_DEVICE_VERSION__: string;
+const host = captureHostEnvironment(process);
+
runEntry(
process.argv.slice(2),
{
help: () => import('./commands/schema/cli-help.ts'),
- cli: () => import('./cli/process-entry.ts'),
- mcp: () => import('./mcp/server.ts'),
+ cli: async () => {
+ const { runCliProcess } = await import('./cli/process-entry.ts');
+ return { runCliProcess: (argv) => runCliProcess(argv, host) };
+ },
+ mcp: async () => {
+ const { runAgentDeviceMcpServer } = await import('./mcp/server.ts');
+ return {
+ runAgentDeviceMcpServer: async () =>
+ await withCommandHost(
+ { host, requestEnv: undefined },
+ async () => await runAgentDeviceMcpServer(),
+ ),
+ };
+ },
version: () => import('@agent-device/host-kit/version'),
processExit: () => import('./cli/process-exit.ts'),
},
diff --git a/src/cli.ts b/src/cli.ts
index 9a50fbf6fe..aaecb8c0b5 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -8,10 +8,17 @@ import {
type NormalizedError,
} from '@agent-device/kernel/errors';
import { resolveDaemonPaths } from '@agent-device/daemon-contracts/daemon-resolution';
+import { withCommandHost } from '@agent-device/host-kit/command';
+import { captureHostEnvironment } from '@agent-device/host-kit/process';
+import type { HostEnvironment } from '@agent-device/kernel/source-value';
import { exitAfterFlush } from './cli/process-exit.ts';
import { readVersion } from '@agent-device/host-kit/version';
import { pathToFileURL } from 'node:url';
-import { createEnsuredDaemonTransport, sendToDaemon } from './daemon-client/daemon-client.ts';
+import {
+ createEnsuredDaemonTransport,
+ resolveRunTransport,
+ sendToDaemon,
+} from './daemon-client/daemon-client.ts';
import fs from 'node:fs';
import type { BatchStep } from '@agent-device/contracts/client';
import type { ReplayTestReporterRuntime } from './cli/replay-test/reporting.ts';
@@ -51,6 +58,8 @@ import { isKnownCliCommandName } from '@agent-device/command-registry/catalog';
type CliDeps = {
sendToDaemon: typeof sendToDaemon;
+ /** Builds the transport that talks as a given host; injected deps leave it out. */
+ transportForHost?: (host: HostEnvironment) => typeof sendToDaemon;
};
type CliDaemonTransport = typeof sendToDaemon;
@@ -71,6 +80,8 @@ const printJson = (
const DEFAULT_CLI_DEPS: CliDeps = {
sendToDaemon: createEnsuredDaemonTransport({ onReplaced: writeDaemonReplacedNotice }),
+ transportForHost: (host) =>
+ createEnsuredDaemonTransport({ host, onReplaced: writeDaemonReplacedNotice }),
};
function writeDaemonReplacedNotice(replaced: {
@@ -121,14 +132,28 @@ const REMOTE_MATERIALIZATION_DEFERRED_COMMANDS = new Set([
'takeover',
]);
-export async function runCli(argv: string[], deps: CliDeps = DEFAULT_CLI_DEPS): Promise