From 0f7ef0b927a0b5de98510a86ff1537ff67ec644a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 16 Oct 2026 14:25:10 +0200 Subject: [PATCH 1/2] refactor(plugins): extract the provider plugins into a private package Move manifest, store, host, load and connection into @agent-device/plugins. ProviderPluginHost is owned by the package and re-exported by agent-device/plugins. RemoteConfigProfile is declared once in contracts and re-exported by the remote schema; the webdriver plugin options come from provider-webdriver. --- package.json | 1 + packages/contracts/src/facades/remote.ts | 1 + .../contracts/src/remote-config-fields.ts | 15 ++++++ .../host-kit/src/internal/path-resolution.ts | 2 +- packages/plugins/package.json | 16 +++++++ .../plugins/src}/connection.ts | 2 +- {src/plugins => packages/plugins/src}/host.ts | 10 +++- .../plugins/src}/load.test.ts | 2 +- {src/plugins => packages/plugins/src}/load.ts | 11 ++--- .../plugins/src}/manifest.test.ts | 8 +--- .../plugins/src}/manifest.ts | 0 .../plugins/src}/store.test.ts | 0 .../plugins => packages/plugins/src}/store.ts | 0 packages/plugins/tsconfig.json | 20 ++++++++ pnpm-lock.yaml | 46 +++++++++++++++++++ src/__tests__/cloud-connect-testmu.test.ts | 8 ++-- .../provider-device-runtimes.test.ts | 7 +++ src/cli/commands/plugins.ts | 2 +- .../connection/connect-provider-adapters.ts | 4 +- src/cli/connection/provider-policy.test.ts | 2 +- src/cli/connection/provider-policy.ts | 7 ++- src/provider-credential-fingerprint.ts | 4 +- src/provider-device-runtimes.ts | 4 +- src/remote/remote-config-schema.ts | 27 ++--------- src/sdk/plugins.ts | 9 +--- .../cloud-webdriver-provider-adapters.test.ts | 2 +- 26 files changed, 146 insertions(+), 64 deletions(-) create mode 100644 packages/plugins/package.json rename {src/plugins => packages/plugins/src}/connection.ts (94%) rename {src/plugins => packages/plugins/src}/host.ts (55%) rename {src/plugins => packages/plugins/src}/load.test.ts (99%) rename {src/plugins => packages/plugins/src}/load.ts (92%) rename {src/plugins => packages/plugins/src}/manifest.test.ts (89%) rename {src/plugins => packages/plugins/src}/manifest.ts (100%) rename {src/plugins => packages/plugins/src}/store.test.ts (100%) rename {src/plugins => packages/plugins/src}/store.ts (100%) create mode 100644 packages/plugins/tsconfig.json diff --git a/package.json b/package.json index 6c8fafdf4e..09831d5894 100644 --- a/package.json +++ b/package.json @@ -305,6 +305,7 @@ "@agent-device/platform-linux": "workspace:*", "@agent-device/platform-vega": "workspace:*", "@agent-device/platform-web": "workspace:*", + "@agent-device/plugins": "workspace:*", "@agent-device/provider-limrun": "workspace:*", "@agent-device/provider-webdriver": "workspace:*", "@agent-device/provision-kit": "workspace:*", diff --git a/packages/contracts/src/facades/remote.ts b/packages/contracts/src/facades/remote.ts index 41314baee8..a90c19472d 100644 --- a/packages/contracts/src/facades/remote.ts +++ b/packages/contracts/src/facades/remote.ts @@ -26,5 +26,6 @@ export type { ProviderDeviceOrientation, ProviderDeviceType, RemoteConfigMetroOptions, + RemoteConfigProfile, RemoteConnectionProfileFields, } from '../remote-config-fields.ts'; diff --git a/packages/contracts/src/remote-config-fields.ts b/packages/contracts/src/remote-config-fields.ts index 06ea1ad1f7..f5516f5ac2 100644 --- a/packages/contracts/src/remote-config-fields.ts +++ b/packages/contracts/src/remote-config-fields.ts @@ -1,3 +1,4 @@ +import type { DeviceTarget, PlatformSelector } from '@agent-device/kernel/device'; import type { DaemonServerMode, DaemonTransportPreference, @@ -129,3 +130,17 @@ export type RemoteConnectionProfileFields = { deviceKey?: string; clientId?: string; }; + +/** A resolved remote-config profile: the field groups above plus the device-selection fields. */ +export type RemoteConfigProfile = RemoteConfigMetroOptions & + CloudProviderProfileFields & + RemoteConnectionProfileFields & { + platform?: PlatformSelector; + target?: DeviceTarget; + device?: string; + udid?: string; + serial?: string; + iosSimulatorDeviceSet?: string; + androidDeviceAllowlist?: string; + session?: string; + }; diff --git a/packages/host-kit/src/internal/path-resolution.ts b/packages/host-kit/src/internal/path-resolution.ts index fc350084f2..e702589c53 100644 --- a/packages/host-kit/src/internal/path-resolution.ts +++ b/packages/host-kit/src/internal/path-resolution.ts @@ -33,7 +33,7 @@ export function resolveUserPath(inputPath: string, options: PathResolutionOption * same question those two answer — a location named by the environment becomes an absolute path — * and it answers it with nothing but `env`: no option schema, no flag grammar, no command facet. * Plugin discovery needs the answer at daemon start and must not acquire the CLI's schema layer to - * get it (`src/plugins/store.ts`), which is a 153-file zone rather than a path helper. + * get it (`packages/plugins/src/store.ts`), which is a 153-file zone rather than a path helper. */ export function resolveUserConfigPath(env: EnvMap): string { const home = env.AGENT_DEVICE_HOME diff --git a/packages/plugins/package.json b/packages/plugins/package.json new file mode 100644 index 0000000000..3de2e9a868 --- /dev/null +++ b/packages/plugins/package.json @@ -0,0 +1,16 @@ +{ + "name": "@agent-device/plugins", + "version": "0.0.0", + "private": true, + "type": "module", + "description": "Provider plugin manifest, installation store, host and loader for agent-device. Internal workspace package bundled into the published artifact.", + "dependencies": { + "@agent-device/contracts": "workspace:*", + "@agent-device/host-kit": "workspace:*", + "@agent-device/kernel": "workspace:*", + "@agent-device/provider-webdriver": "workspace:*" + }, + "devDependencies": { + "@agent-device/test-kit": "workspace:*" + } +} diff --git a/src/plugins/connection.ts b/packages/plugins/src/connection.ts similarity index 94% rename from src/plugins/connection.ts rename to packages/plugins/src/connection.ts index 295f8f8cbe..3f581f8607 100644 --- a/src/plugins/connection.ts +++ b/packages/plugins/src/connection.ts @@ -2,9 +2,9 @@ import type { CliFlags } from '@agent-device/contracts/command'; import type { ConnectionProviderCapabilities, ProviderConnectionVerification, + RemoteConfigProfile, } from '@agent-device/contracts/remote'; import type { EnvMap } from '@agent-device/kernel/source-value'; -import type { RemoteConfigProfile } from '../remote/remote-config-schema.ts'; import { installedPlugins } from './store.ts'; export type PluginConnection = Readonly<{ diff --git a/src/plugins/host.ts b/packages/plugins/src/host.ts similarity index 55% rename from src/plugins/host.ts rename to packages/plugins/src/host.ts index 3021c710ae..19ac09c688 100644 --- a/src/plugins/host.ts +++ b/packages/plugins/src/host.ts @@ -1,6 +1,12 @@ -import { AppError } from '@agent-device/kernel/errors'; +import { AppError, type AppErrorCode, type AppErrorDetails } from '@agent-device/kernel/errors'; import { readVersion } from '@agent-device/host-kit/version'; -import type { ProviderPluginHost } from '../sdk/plugins.ts'; + +export type ProviderPluginHost = Readonly<{ + env: Readonly>; + options: Readonly>; + clientVersion: string; + createError(code: AppErrorCode, message: string, details?: AppErrorDetails): AppError; +}>; export function createPluginHost( env: NodeJS.ProcessEnv, diff --git a/src/plugins/load.test.ts b/packages/plugins/src/load.test.ts similarity index 99% rename from src/plugins/load.test.ts rename to packages/plugins/src/load.test.ts index 113a1d9e3e..5d7720e318 100644 --- a/src/plugins/load.test.ts +++ b/packages/plugins/src/load.test.ts @@ -10,7 +10,7 @@ import { webDriverPluginSource, } from '@agent-device/test-kit'; import { AppError } from '@agent-device/kernel/errors'; -import type { ProviderPluginHost } from '../sdk/plugins.ts'; +import type { ProviderPluginHost } from './host.ts'; import type { DeviceLease, ProviderDeviceRuntime } from '@agent-device/contracts/device'; const realFetch = globalThis.fetch; diff --git a/src/plugins/load.ts b/packages/plugins/src/load.ts similarity index 92% rename from src/plugins/load.ts rename to packages/plugins/src/load.ts index f9b2d6472b..c590506430 100644 --- a/src/plugins/load.ts +++ b/packages/plugins/src/load.ts @@ -2,16 +2,15 @@ import { pathToFileURL } from 'node:url'; import { AppError } from '@agent-device/kernel/errors'; import type { ProviderDeviceRuntime } from '@agent-device/contracts/device'; import type { PlatformRuntimeProviderModule } from '@agent-device/contracts/platform-runtime-operations'; -import type { ProviderPluginHost } from '../sdk/plugins.ts'; import { installedPlugins } from './store.ts'; import { resolvePluginEntry, assertUniquePluginProviders, RESERVED_PLUGIN_PROVIDERS, } from './manifest.ts'; -import { createPluginHost } from './host.ts'; +import { createPluginHost, type ProviderPluginHost } from './host.ts'; import type { PluginConnection } from './connection.ts'; -import type { WebDriverPluginOptions } from '../sdk/plugin-webdriver.ts'; +import type { CloudWebDriverProviderOptions } from '@agent-device/provider-webdriver/plugin'; type ProviderPluginRegistration = Readonly<{ runtime: ProviderDeviceRuntime; @@ -75,10 +74,10 @@ async function instantiateProviderPlugin( host: ProviderPluginHost, ) => | ProviderPluginRegistration - | { webDriver: WebDriverPluginOptions; connection?: PluginConnection } + | { webDriver: CloudWebDriverProviderOptions; connection?: PluginConnection } | Promise< | ProviderPluginRegistration - | { webDriver: WebDriverPluginOptions; connection?: PluginConnection } + | { webDriver: CloudWebDriverProviderOptions; connection?: PluginConnection } > )(host); let registration: ProviderPluginRegistration; @@ -108,7 +107,7 @@ async function instantiateProviderPlugin( function isWebDriverPluginResult( result: unknown, -): result is { webDriver: WebDriverPluginOptions; connection?: PluginConnection } { +): result is { webDriver: CloudWebDriverProviderOptions; connection?: PluginConnection } { return typeof result === 'object' && result !== null && 'webDriver' in result; } diff --git a/src/plugins/manifest.test.ts b/packages/plugins/src/manifest.test.ts similarity index 89% rename from src/plugins/manifest.test.ts rename to packages/plugins/src/manifest.test.ts index 458dbc6a55..78c38d1faf 100644 --- a/src/plugins/manifest.test.ts +++ b/packages/plugins/src/manifest.test.ts @@ -2,8 +2,7 @@ import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { test } from 'vitest'; -import { readPluginManifest, RESERVED_PLUGIN_PROVIDERS } from './manifest.ts'; -import { DEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS } from '../provider-device-runtimes.ts'; +import { readPluginManifest } from './manifest.ts'; import { pluginHome, writePlugin } from '@agent-device/test-kit'; test('manifest compatibility is checked without evaluating plugin code', () => { @@ -85,8 +84,3 @@ test('credential variables are optional environment variable names', () => { for (const invalid of [null, 'EXAMPLE_USER', {}, [''], ['example_user'], ['2KEY'], ['A-B'], [1]]) assert.throws(() => read(invalid), { code: 'INVALID_ARGS' }, JSON.stringify(invalid)); }); - -test('every bundled provider runtime is reserved from plugins', () => { - for (const provider of DEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS) - assert.ok((RESERVED_PLUGIN_PROVIDERS as readonly string[]).includes(provider), provider); -}); diff --git a/src/plugins/manifest.ts b/packages/plugins/src/manifest.ts similarity index 100% rename from src/plugins/manifest.ts rename to packages/plugins/src/manifest.ts diff --git a/src/plugins/store.test.ts b/packages/plugins/src/store.test.ts similarity index 100% rename from src/plugins/store.test.ts rename to packages/plugins/src/store.test.ts diff --git a/src/plugins/store.ts b/packages/plugins/src/store.ts similarity index 100% rename from src/plugins/store.ts rename to packages/plugins/src/store.ts diff --git a/packages/plugins/tsconfig.json b/packages/plugins/tsconfig.json new file mode 100644 index 0000000000..4f983abbbc --- /dev/null +++ b/packages/plugins/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "declarationDir": "./dist-types", + "rootDir": "./src", + "tsBuildInfoFile": "./dist-types/index.tsbuildinfo" + }, + "include": ["src"], + "references": [ + { "path": "../contracts" }, + { "path": "../host-kit" }, + { "path": "../kernel" }, + { "path": "../provider-webdriver" }, + { "path": "../test-kit" } + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f77596f558..4f4f40ede8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,9 @@ importers: '@agent-device/platform-web': specifier: workspace:* version: link:packages/platform-web + '@agent-device/plugins': + specifier: workspace:* + version: link:packages/plugins '@agent-device/provider-limrun': specifier: workspace:* version: link:packages/provider-limrun @@ -578,6 +581,25 @@ importers: specifier: workspace:* version: link:../test-kit + packages/plugins: + dependencies: + '@agent-device/contracts': + specifier: workspace:* + version: link:../contracts + '@agent-device/host-kit': + specifier: workspace:* + version: link:../host-kit + '@agent-device/kernel': + specifier: workspace:* + version: link:../kernel + '@agent-device/provider-webdriver': + specifier: workspace:* + version: link:../provider-webdriver + devDependencies: + '@agent-device/test-kit': + specifier: workspace:* + version: link:../test-kit + packages/provider-limrun: dependencies: '@agent-device/capture-kit': @@ -2354,133 +2376,157 @@ packages: resolution: {integrity: sha512-C/0zV5IhgVdYhGJTwrY0v8dknxlhiKwtVJkMUaexu9/QvRmzlV4vfU3hZlUSgqc2BxQHntL1mCVbDq8j0FRFDw==} cpu: [arm64] os: [android] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-darwin-arm64@0.8.7': resolution: {integrity: sha512-/u+REDMI4a0/lsJXTM4c53/w31OGZLOReZIyg62uhgLs0kc8NHsj/nOcxTdlQjq5gi0zhdkccD9LaLTXcdzPvw==} cpu: [arm64] os: [darwin] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-darwin-x64@0.8.7': resolution: {integrity: sha512-sMMzFOwCo4WXR+/6zIBThOocSC50iIIZZdfiIDbaLvj0Ax/rWt/iavyfEAqajyvzydLyCqR/ZItdLWSRlu1umw==} cpu: [x64] os: [darwin] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-freebsd-x64@0.8.7': resolution: {integrity: sha512-MpdpKXix9P+Y1rKgjvcNeNtGjXeL1CmttNhYINrWls8kRpm4xM/oBGTmn6w7to8lAlwj5jm8q03dQPl5mRv4Qw==} cpu: [x64] os: [freebsd] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm-gnu@0.8.7': resolution: {integrity: sha512-rr1srFLlPAmC1vtxfc9C1YLDe3iH09YjfSeeIidBqKhzx1MATjOAq4mjlRUOnhr/L27MotWIYOFKwVsd5JZFOg==} cpu: [arm] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm-musl@0.8.7': resolution: {integrity: sha512-eAufXh8qBRpiSO6ueaMDL+yyoXIGLhpUce72YbcACtZU2qhExwBIJyEtQf5kH2Ki0X2aqkSjSfog4OPtKXan3Q==} cpu: [arm] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm64-gnu@0.8.7': resolution: {integrity: sha512-gw4w6wPoHObBrdIC4duVWLmJOvpdE25j5D7yrM5mACNlK4klRz/lv8hK+ssQk9EJHBgZjSaqZIJVFgqNYbfv7A==} cpu: [arm64] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-arm64-musl@0.8.7': resolution: {integrity: sha512-L68N6Y4XkqcIaKo3Ra88JEvBEH4AHff44A4INcrxeVWZ8CZtu2tCpfVxe3hR8qQQMcvBSQlDn24KpkCKEhVvfA==} cpu: [arm64] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-x64-gnu@0.8.7': resolution: {integrity: sha512-dzyAbltJmf3Cqlb8HcFuYIf5Yn0fl1vTr3XJ9HiVNNvOlhqPSArOqtw9vI1p6/VTXTjrMLXlU+s+/kNHiIy/Cw==} cpu: [x64] os: [linux] libc: [glibc] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-linux-x64-musl@0.8.7': resolution: {integrity: sha512-Otw4MH3404q0Bbvl+YTdW9aoUV5vXmUw8260bWvt1XlaoIX/ceSgI4ygheRDMfBPoHt6FDayQaO9OLVUZAgkFA==} cpu: [x64] os: [linux] libc: [musl] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-win32-arm64@0.8.7': resolution: {integrity: sha512-qo/jyrzryiBuKEsFiuWaBCBe3tRMynQ0qFWFgOEjcCMQeZfBm+wKiVEUEFXXLc7bh8YezguAWp0Mtnhq4ARNyA==} cpu: [arm64] os: [win32] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-codegen/binding-win32-x64@0.8.7': resolution: {integrity: sha512-D5lDsVDx6m00E6bWySlWdH72Ca4TPSaphDqB6QjU6MpuNLIJqoGoatYyq2rOmBE8Zv/kunot/o58KGL03P3eiA==} cpu: [x64] os: [win32] + deprecated: yuku-codegen is pure JavaScript since 0.14 '@yuku-parser/binding-android-arm64@0.8.7': resolution: {integrity: sha512-eGKYiUDX7Y0V7tDTmg+JTVnXnjMqfXXsorZ+EDf5kxwchQ3Or1HS14MzI2fw+jFhHR85fCWt+mtX33Yao73hIQ==} cpu: [arm64] os: [android] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-darwin-arm64@0.8.7': resolution: {integrity: sha512-Re0RHelKLnjEURulY2/KxW+Ngb8zuNA4BRZuMwgGQNzVumT6u4U2N2hc01oeYVNVof0i7GrXE4UCNBgbpRRnjQ==} cpu: [arm64] os: [darwin] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-darwin-x64@0.8.7': resolution: {integrity: sha512-Hn8DROtQkjlA1ACbPgj4a7eP9IuVOI504oiTwpkWPbpaDWD9KdmnVYCqW+1LfenNK/g7O9NhWGpXEdaCNX7lIA==} cpu: [x64] os: [darwin] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-freebsd-x64@0.8.7': resolution: {integrity: sha512-bAP2OV8wRuzplX/jYxv9+vvqQT8JxyNphI8fLfXGL054Xs+4/J5u33cIm3y4rxY8rdoLmmdiJs2Tq7r7lrDRfA==} cpu: [x64] os: [freebsd] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm-gnu@0.8.7': resolution: {integrity: sha512-kTYwJQQgmZeAWdDIWabiReIZMpmfLueIj1tCmjStUtFGhR1Z0qwxonKVfUC4N7h/VhGGzLZ//7O1kgt1QKqgCg==} cpu: [arm] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm-musl@0.8.7': resolution: {integrity: sha512-uL4jE8HPT2BLlxAXyD10LqgPuXa9eDa0BKpCdSANmzIJghq/2eZo3/gQNtaxPZMupWoxjYzSad9IXrwu7aYPXQ==} cpu: [arm] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm64-gnu@0.8.7': resolution: {integrity: sha512-3gVN4pWSKZmXiNX7cU164dR9MPvesCHnlH6nPfpK+yQsCuYphjKKplcb4SnZBrhiqmXbgb2HR0c2TS0IZUPhgA==} cpu: [arm64] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-arm64-musl@0.8.7': resolution: {integrity: sha512-S0mwfEjoLpxzXeZw802Wa4RaELsQiPtWqG6INcy8j4GtvNFtl4LCX3eGO1XLn9pyLAISLzTRyU3zUCBUPin8lg==} cpu: [arm64] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-x64-gnu@0.8.7': resolution: {integrity: sha512-lnbWdPmerE5D1uH1G4IEZKnPzCrWCStRGrtgpSIe1RibAo5bZIjDbbbPYXmMHCEh4F+x/JaJpElh26a3r+BPbg==} cpu: [x64] os: [linux] libc: [glibc] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-linux-x64-musl@0.8.7': resolution: {integrity: sha512-769uwndMvMzUvATWbAcEvyLHKA+DzhHSCl/obBUrRdYfRo26yxui6S8y3z7uJ+Naup7UKrDxrpK7OnQkxkl9KQ==} cpu: [x64] os: [linux] libc: [musl] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-win32-arm64@0.8.7': resolution: {integrity: sha512-mEB/9PlaAkisJ6KWGz0zvywXoU6+80dTlR2LwS7s/jcXXoU6fm2+sitBZXtqu3+Q4DcDgPxM45uWMCzPs0TSRw==} cpu: [arm64] os: [win32] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-parser/binding-win32-x64@0.8.7': resolution: {integrity: sha512-8vNB2DP0ou61nGb8tc/qfi41gfyDXz1MHr2zqL3nR+cJ6CEbiuWV/l/a/vv151gCgiZLLAyGkQGENpozdg716w==} cpu: [x64] os: [win32] + deprecated: yuku-parser runs on yuku-core since 0.14 '@yuku-toolchain/types@0.8.7': resolution: {integrity: sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA==} diff --git a/src/__tests__/cloud-connect-testmu.test.ts b/src/__tests__/cloud-connect-testmu.test.ts index e6d3a0ac5c..c94a3755de 100644 --- a/src/__tests__/cloud-connect-testmu.test.ts +++ b/src/__tests__/cloud-connect-testmu.test.ts @@ -10,18 +10,18 @@ import { import { AppError } from '@agent-device/kernel/errors'; import { verifyTestMuConnection } from '@agent-device/testmu/connection-verification'; import testMuPlugin from '@agent-device/testmu'; -import { createPluginHost } from '../plugins/host.ts'; +import { createPluginHost } from '@agent-device/plugins/host'; import { resolveConnectProviderProfile } from '../cli/connection/connect-provider-adapters.ts'; import { mkdtempForTestSync, pluginHome, selectPlugin } from '@agent-device/test-kit'; -import { installedPlugins } from '../plugins/store.ts'; +import { installedPlugins } from '@agent-device/plugins/store'; import manifest from '@agent-device/testmu/package.json' with { type: 'json' }; -import type { PluginConnection } from '../plugins/connection.ts'; +import type { PluginConnection } from '@agent-device/plugins/connection'; import { connectWithGeneratedProviderProfile } from './test-utils/connect-command.ts'; vi.mock('@agent-device/testmu/connection-verification', () => ({ verifyTestMuConnection: vi.fn(), })); -vi.mock('../plugins/load.ts', () => ({ +vi.mock('@agent-device/plugins/load', () => ({ withPluginConnection: async ( _provider: string, env: NodeJS.ProcessEnv, diff --git a/src/__tests__/provider-device-runtimes.test.ts b/src/__tests__/provider-device-runtimes.test.ts index 2d9f0b0b10..c0a5f76bba 100644 --- a/src/__tests__/provider-device-runtimes.test.ts +++ b/src/__tests__/provider-device-runtimes.test.ts @@ -1,6 +1,8 @@ import assert from 'node:assert/strict'; import { test } from 'vitest'; +import { RESERVED_PLUGIN_PROVIDERS } from '@agent-device/plugins/manifest'; import { + DEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS, createDefaultProviderRuntimeComposition, createDaemonProviderRuntimeComposition, } from '../provider-device-runtimes.ts'; @@ -115,3 +117,8 @@ function assertPlatformModuleCoverage( assert.equal('provider' in runtime ? runtime.provider : undefined, module.owner.provider); } } + +test('every bundled provider runtime is reserved from plugins', () => { + for (const provider of DEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS) + assert.ok((RESERVED_PLUGIN_PROVIDERS as readonly string[]).includes(provider), provider); +}); diff --git a/src/cli/commands/plugins.ts b/src/cli/commands/plugins.ts index 8fbf202bb9..97a8d89529 100644 --- a/src/cli/commands/plugins.ts +++ b/src/cli/commands/plugins.ts @@ -1,5 +1,5 @@ import { AppError } from '@agent-device/kernel/errors'; -import { changePlugin, listPlugins } from '../../plugins/store.ts'; +import { changePlugin, listPlugins } from '@agent-device/plugins/store'; import { writeCommandOutput } from './shared.ts'; import type { ClientCommandHandler } from './router-types.ts'; diff --git a/src/cli/connection/connect-provider-adapters.ts b/src/cli/connection/connect-provider-adapters.ts index 084c465665..0f7fadc22c 100644 --- a/src/cli/connection/connect-provider-adapters.ts +++ b/src/cli/connection/connect-provider-adapters.ts @@ -15,8 +15,8 @@ import { resolveProxyConnectProfile } from './proxy-profile.ts'; import { profileToCliFlags } from '../remote-config-flags.ts'; import { isConnectProviderName, type ConnectProvider } from './provider-policy.ts'; import { bundledCloudWebDriverConnection } from '../../provider-webdriver.ts'; -import { withPluginConnection } from '../../plugins/load.ts'; -import type { PluginConnection } from '../../plugins/connection.ts'; +import { withPluginConnection } from '@agent-device/plugins/load'; +import type { PluginConnection } from '@agent-device/plugins/connection'; import { readMetroProfileFields } from './profile-fields.ts'; import { buildConnectClientId } from './client-id.ts'; import { persistAndResolveGeneratedProfile } from './generated-config.ts'; diff --git a/src/cli/connection/provider-policy.test.ts b/src/cli/connection/provider-policy.test.ts index 1a4805aa43..64e09ea96b 100644 --- a/src/cli/connection/provider-policy.test.ts +++ b/src/cli/connection/provider-policy.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { test } from 'vitest'; import { connectionProviderCapabilities, isConnectProviderName } from './provider-policy.ts'; import { pluginHome, selectPlugin } from '@agent-device/test-kit'; -import { installedPlugins } from '../../plugins/store.ts'; +import { installedPlugins } from '@agent-device/plugins/store'; test('provider policy projects provider identity into semantic capabilities', () => { assert.deepEqual(connectionProviderCapabilities('limrun'), { diff --git a/src/cli/connection/provider-policy.ts b/src/cli/connection/provider-policy.ts index a33e894296..3cd0871e7a 100644 --- a/src/cli/connection/provider-policy.ts +++ b/src/cli/connection/provider-policy.ts @@ -1,7 +1,10 @@ import type { ConnectionProviderCapabilities } from '@agent-device/contracts/remote'; import { cloudWebDriverProviderDeclaration } from '@agent-device/provider-webdriver/providers'; -import { pluginConnectionCapabilities, pluginConnectionNames } from '../../plugins/connection.ts'; -import { RESERVED_PLUGIN_PROVIDERS as BUILTIN_CONNECT_PROVIDERS } from '../../plugins/manifest.ts'; +import { + pluginConnectionCapabilities, + pluginConnectionNames, +} from '@agent-device/plugins/connection'; +import { RESERVED_PLUGIN_PROVIDERS as BUILTIN_CONNECT_PROVIDERS } from '@agent-device/plugins/manifest'; export type BuiltinConnectProvider = (typeof BUILTIN_CONNECT_PROVIDERS)[number]; export type ConnectProvider = BuiltinConnectProvider | (string & {}); diff --git a/src/provider-credential-fingerprint.ts b/src/provider-credential-fingerprint.ts index 4559c52b36..125b330258 100644 --- a/src/provider-credential-fingerprint.ts +++ b/src/provider-credential-fingerprint.ts @@ -4,8 +4,8 @@ import { cloudWebDriverProviderDeclaration } from '@agent-device/provider-webdri import type { LIMRUN_PROVIDER } from '@agent-device/provider-limrun'; import type { EnvMap } from '@agent-device/kernel/source-value'; import { readLimrunCredentialValues } from './provider-limrun-credentials.ts'; -import { RESERVED_PLUGIN_PROVIDERS } from './plugins/manifest.ts'; -import { installedPlugins } from './plugins/store.ts'; +import { RESERVED_PLUGIN_PROVIDERS } from '@agent-device/plugins/manifest'; +import { installedPlugins } from '@agent-device/plugins/store'; type CredentialValues = Readonly>; diff --git a/src/provider-device-runtimes.ts b/src/provider-device-runtimes.ts index 031087c789..4dff7d4352 100644 --- a/src/provider-device-runtimes.ts +++ b/src/provider-device-runtimes.ts @@ -51,8 +51,8 @@ export async function createDaemonProviderRuntimeComposition( const bundled = await createDefaultProviderRuntimeComposition(env); try { const [{ loadProviderPlugins }, { RESERVED_PLUGIN_PROVIDERS }] = await Promise.all([ - import('./plugins/load.ts'), - import('./plugins/manifest.ts'), + import('@agent-device/plugins/load'), + import('@agent-device/plugins/manifest'), ]); const plugins = await loadProviderPlugins(env, RESERVED_PLUGIN_PROVIDERS); return Object.freeze({ diff --git a/src/remote/remote-config-schema.ts b/src/remote/remote-config-schema.ts index 49f06dcfbc..90e7653b6b 100644 --- a/src/remote/remote-config-schema.ts +++ b/src/remote/remote-config-schema.ts @@ -1,33 +1,14 @@ import { PROVIDER_DEVICE_ORIENTATIONS, PROVIDER_DEVICE_TYPES, - type CloudProviderProfileFields, - type RemoteConfigMetroOptions, - type RemoteConnectionProfileFields, + type RemoteConfigProfile, } from '@agent-device/contracts/remote'; -// Declared in contracts/ so zones below remote/ can be stated in terms of the field vocabulary; +// Declared in contracts/ so zones below remote/ can be stated in terms of the profile vocabulary; // re-exported here because this module is where consumers already import it from. -export type { RemoteConnectionProfileFields } from '@agent-device/contracts/remote'; +export type { RemoteConfigProfile } from '@agent-device/contracts/remote'; import { LEASE_BACKENDS } from '@agent-device/kernel/contracts'; import { buildPrimaryEnvVarName } from '@agent-device/kernel/source-value'; -import { - PLATFORM_SELECTORS, - type DeviceTarget, - type PlatformSelector, -} from '@agent-device/kernel/device'; - -export type RemoteConfigProfile = RemoteConfigMetroOptions & - CloudProviderProfileFields & - RemoteConnectionProfileFields & { - platform?: PlatformSelector; - target?: DeviceTarget; - device?: string; - udid?: string; - serial?: string; - iosSimulatorDeviceSet?: string; - androidDeviceAllowlist?: string; - session?: string; - }; +import { PLATFORM_SELECTORS } from '@agent-device/kernel/device'; export type RemoteConfigProfileOptions = { configPath: string; diff --git a/src/sdk/plugins.ts b/src/sdk/plugins.ts index 8cbc13d56c..e1a376ac0e 100644 --- a/src/sdk/plugins.ts +++ b/src/sdk/plugins.ts @@ -1,8 +1 @@ -import type { AppError, AppErrorCode, AppErrorDetails } from '@agent-device/kernel/errors'; - -export type ProviderPluginHost = Readonly<{ - env: Readonly>; - options: Readonly>; - clientVersion: string; - createError(code: AppErrorCode, message: string, details?: AppErrorDetails): AppError; -}>; +export type { ProviderPluginHost } from '@agent-device/plugins/host'; diff --git a/test/integration/provider-scenarios/cloud-webdriver-provider-adapters.test.ts b/test/integration/provider-scenarios/cloud-webdriver-provider-adapters.test.ts index dc63fd4165..42b6d0b786 100644 --- a/test/integration/provider-scenarios/cloud-webdriver-provider-adapters.test.ts +++ b/test/integration/provider-scenarios/cloud-webdriver-provider-adapters.test.ts @@ -26,7 +26,7 @@ import { } from './cloud-webdriver-test-server.ts'; import testMuPlugin from '@agent-device/testmu'; -import { createPluginHost } from '../../../src/plugins/host.ts'; +import { createPluginHost } from '@agent-device/plugins/host'; import { createCloudWebDriverRuntime } from '@agent-device/provider-webdriver/plugin'; import { CLOUD_WEBDRIVER_PROVIDERS } from '@agent-device/provider-webdriver/providers'; From 03f44c4f11aaee2a44a0e94ead0255ccf7b23b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 16 Oct 2026 14:25:10 +0200 Subject: [PATCH 2/2] chore(gates): register the plugins package exports and references Expose the five production subpaths, reference the package from the typecheck and SDK example projects, update the fallow loader-path comment, and accept the type re-export form in the installed-package host declaration assertion. --- .fallowrc.json | 2 +- examples/sdk/tsconfig.json | 1 + packages/plugins/package.json | 22 +++++++++++++++++++ .../installed-package-metro.test.ts | 2 +- tsconfig.typecheck.json | 1 + 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.fallowrc.json b/.fallowrc.json index 573f19888c..1eb6d254be 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -94,7 +94,7 @@ "exports": ["*"] }, { - // A published provider package's default export is its plugin contract; src/plugins/load.ts imports the package by name at runtime and reads `default`. + // A published provider package's default export is its plugin contract; packages/plugins/src/load.ts imports the package by name at runtime and reads `default`. "file": "packages/provider-*/src/index.ts", "exports": ["default"] }, diff --git a/examples/sdk/tsconfig.json b/examples/sdk/tsconfig.json index 683f8cd4c8..57d927c4e3 100644 --- a/examples/sdk/tsconfig.json +++ b/examples/sdk/tsconfig.json @@ -51,6 +51,7 @@ { "path": "../../packages/platform-linux" }, { "path": "../../packages/platform-vega" }, { "path": "../../packages/platform-web" }, + { "path": "../../packages/plugins" }, { "path": "../../packages/provider-limrun" }, { "path": "../../packages/provider-testmu" }, { "path": "../../packages/provider-webdriver" }, diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 3de2e9a868..941f5faeff 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -10,6 +10,28 @@ "@agent-device/kernel": "workspace:*", "@agent-device/provider-webdriver": "workspace:*" }, + "exports": { + "./connection": { + "types": "./src/connection.ts", + "default": "./src/connection.ts" + }, + "./host": { + "types": "./src/host.ts", + "default": "./src/host.ts" + }, + "./load": { + "types": "./src/load.ts", + "default": "./src/load.ts" + }, + "./manifest": { + "types": "./src/manifest.ts", + "default": "./src/manifest.ts" + }, + "./store": { + "types": "./src/store.ts", + "default": "./src/store.ts" + } + }, "devDependencies": { "@agent-device/test-kit": "workspace:*" } diff --git a/test/integration/installed-package-metro.test.ts b/test/integration/installed-package-metro.test.ts index 2157a09273..57e330d08f 100644 --- a/test/integration/installed-package-metro.test.ts +++ b/test/integration/installed-package-metro.test.ts @@ -232,7 +232,7 @@ test('installed package exposes Node APIs and packaged companion tunnel entrypoi path.join(installedPackageRoot, 'dist/src/plugins/webdriver.d.ts'), ); assert.ok(webDriverPluginTypes.length < 5120); - assert.match(pluginTypes.toString(), /export \{ ProviderPluginHost \}/); + assert.match(pluginTypes.toString(), /export (?:type )?\{ ProviderPluginHost \}/); metroPort = await listenOnLoopback(metroServer); t.after(async () => { await closeLoopbackServer(metroServer); diff --git a/tsconfig.typecheck.json b/tsconfig.typecheck.json index d6be52177b..f61d57960b 100644 --- a/tsconfig.typecheck.json +++ b/tsconfig.typecheck.json @@ -22,6 +22,7 @@ { "path": "packages/platform-linux" }, { "path": "packages/platform-vega" }, { "path": "packages/platform-web" }, + { "path": "packages/plugins" }, { "path": "packages/provider-limrun" }, { "path": "packages/provider-testmu" }, { "path": "packages/provider-webdriver" },