@arenahito/droid-webscr 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # droid-webscr
2
2
 
3
- droid-webscr is a local Android screen streaming and control tool. It runs a small
4
- Node.js agent on your machine, pushes a temporary Android-side server through ADB,
5
- and opens a browser UI for viewing and controlling an authorized Android device.
3
+ droid-webscr is a local Android screen streaming and control tool. It runs a local
4
+ Node.js server on your machine, pushes a temporary Android-side server through ADB,
5
+ and serves a browser UI for viewing and controlling an authorized Android device.
6
6
 
7
7
  The project is under active development. Expect CLI and protocol details to keep
8
8
  moving until the first stable release.
@@ -44,21 +44,21 @@ droid-webscr
44
44
 
45
45
  ## Usage
46
46
 
47
- Start the local agent:
47
+ Start the local server and web UI:
48
48
 
49
49
  ```sh
50
50
  droid-webscr
51
51
  ```
52
52
 
53
- By default the agent listens on:
53
+ By default the integrated server listens on:
54
54
 
55
55
  ```text
56
56
  http://127.0.0.1:7391
57
57
  ```
58
58
 
59
- Open the web UI, select an authorized device, and start a session. The session
59
+ Open the printed URL, select an authorized device, and start a session. The session
60
60
  streams the Android display into the browser and sends control frames back to the
61
- device through the local agent.
61
+ device through the local server.
62
62
 
63
63
  The UI supports:
64
64
 
package/dist/bin.d.ts CHANGED
@@ -1,19 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { AgentRuntime } from './main.js';
3
- import '@droid-webscr/adb';
4
- import '@droid-webscr/config';
2
+ declare function startPackagedRuntime(): Promise<{
3
+ close: () => Promise<void>;
4
+ readonly url: string;
5
+ }>;
5
6
 
6
- interface CliIo {
7
- stderr(value: string): void;
8
- stdout(value: string): void;
9
- }
10
- interface CliRuntime {
11
- readonly packageVersion?: string | undefined;
12
- readonly startAgent?: (() => Promise<AgentRuntime>) | undefined;
13
- readonly stderr?: ((value: string) => void) | undefined;
14
- readonly stdout?: ((value: string) => void) | undefined;
15
- }
16
- declare function runCli(argv: readonly string[], runtime?: CliRuntime): Promise<number>;
17
- declare function createCliHelp(): string;
18
-
19
- export { type CliIo, type CliRuntime, createCliHelp, runCli };
7
+ export { startPackagedRuntime };
package/dist/bin.js CHANGED
@@ -5,56 +5,64 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
8
- // package.json
9
- var package_default = {
10
- name: "@arenahito/droid-webscr",
11
- version: "0.1.0",
12
- private: false,
13
- license: "MIT",
14
- repository: {
15
- type: "git",
16
- url: "git+https://github.com/arenahito/droid-webscr.git",
17
- directory: "apps/agent"
18
- },
19
- bin: {
20
- "droid-webscr": "dist/bin.js"
21
- },
22
- files: [
23
- "dist",
24
- "android",
25
- "README.md",
26
- "LICENSE"
27
- ],
28
- type: "module",
29
- exports: {
30
- ".": {
31
- types: "./dist/index.d.ts",
32
- default: "./dist/index.js"
8
+ // src/bin.ts
9
+ import { dirname as dirname2 } from "path";
10
+ import { fileURLToPath as fileURLToPath2 } from "url";
11
+
12
+ // ../agent/src/device-server/artifact.ts
13
+ import { access } from "fs/promises";
14
+ import { constants } from "fs";
15
+ import { dirname, join } from "path";
16
+ import { fileURLToPath } from "url";
17
+ var deviceServerArtifactFileName = "droid-webscr-server-android.jar";
18
+ var deviceServerArtifactRemotePath = "/data/local/tmp/droid-webscr-server.jar";
19
+ var defaultDeviceServerArtifact = {
20
+ localPath: `android/server/build/${deviceServerArtifactFileName}`,
21
+ remotePath: deviceServerArtifactRemotePath
22
+ };
23
+ async function resolveDeviceServerArtifact(moduleUrl = import.meta.url, startDirectory = dirname(fileURLToPath(moduleUrl))) {
24
+ const candidates = ancestorDirectories(startDirectory).flatMap((directory) => [
25
+ join(directory, "android", deviceServerArtifactFileName),
26
+ join(directory, "android", "server", "build", deviceServerArtifactFileName)
27
+ ]);
28
+ const checks = await Promise.all(
29
+ candidates.map(async (candidate) => ({
30
+ candidate,
31
+ exists: await isReadableFile(candidate)
32
+ }))
33
+ );
34
+ for (const check2 of checks) {
35
+ if (check2.exists) {
36
+ return {
37
+ localPath: check2.candidate,
38
+ remotePath: deviceServerArtifactRemotePath
39
+ };
33
40
  }
34
- },
35
- publishConfig: {
36
- access: "public"
37
- },
38
- scripts: {
39
- build: "tsup && node ../../tools/package-agent.mjs",
40
- dev: "tsc -p tsconfig.build.json --watch",
41
- lint: "oxlint --config ../../oxlint.json src",
42
- test: "vitest run",
43
- "type-check": "tsc -p tsconfig.json --noEmit"
44
- },
45
- dependencies: {
46
- "@fastify/websocket": "11.2.0",
47
- fastify: "5.8.5",
48
- pino: "10.3.1"
49
- },
50
- devDependencies: {
51
- "@droid-webscr/adb": "workspace:*",
52
- "@droid-webscr/config": "workspace:*",
53
- "@droid-webscr/protocol": "workspace:*",
54
- "@droid-webscr/transport": "workspace:*",
55
- "@types/ws": "8.18.1"
56
41
  }
57
- };
42
+ throw new Error(
43
+ `Android server artifact was not found. Run pnpm android:build before starting droid-webscr.`
44
+ );
45
+ }
46
+ function ancestorDirectories(startDirectory) {
47
+ const directories = [];
48
+ let current = startDirectory;
49
+ while (true) {
50
+ directories.push(current);
51
+ const parent = dirname(current);
52
+ if (parent === current) {
53
+ return directories;
54
+ }
55
+ current = parent;
56
+ }
57
+ }
58
+ async function isReadableFile(path) {
59
+ try {
60
+ await access(path, constants.R_OK);
61
+ return true;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
58
66
 
59
67
  // ../../packages/adb/src/provider.ts
60
68
  import { Readable } from "stream";
@@ -14976,70 +14984,15 @@ function isLocalBind(host) {
14976
14984
  return host === "127.0.0.1" || host === "localhost" || host === "::1";
14977
14985
  }
14978
14986
 
14979
- // src/runtime.ts
14987
+ // ../agent/src/runtime.ts
14980
14988
  import { pathToFileURL } from "url";
14981
14989
 
14982
- // src/device-server/artifact.ts
14983
- import { access } from "fs/promises";
14984
- import { constants } from "fs";
14985
- import { dirname, join } from "path";
14986
- import { fileURLToPath } from "url";
14987
- var deviceServerArtifactFileName = "droid-webscr-server-android.jar";
14988
- var deviceServerArtifactRemotePath = "/data/local/tmp/droid-webscr-server.jar";
14989
- var defaultDeviceServerArtifact = {
14990
- localPath: `android/server/build/${deviceServerArtifactFileName}`,
14991
- remotePath: deviceServerArtifactRemotePath
14992
- };
14993
- async function resolveDeviceServerArtifact(moduleUrl = import.meta.url, startDirectory = dirname(fileURLToPath(moduleUrl))) {
14994
- const candidates = ancestorDirectories(startDirectory).flatMap((directory) => [
14995
- join(directory, "android", deviceServerArtifactFileName),
14996
- join(directory, "android", "server", "build", deviceServerArtifactFileName)
14997
- ]);
14998
- const checks = await Promise.all(
14999
- candidates.map(async (candidate) => ({
15000
- candidate,
15001
- exists: await isReadableFile(candidate)
15002
- }))
15003
- );
15004
- for (const check2 of checks) {
15005
- if (check2.exists) {
15006
- return {
15007
- localPath: check2.candidate,
15008
- remotePath: deviceServerArtifactRemotePath
15009
- };
15010
- }
15011
- }
15012
- throw new Error(
15013
- `Android server artifact was not found. Run pnpm android:build before starting droid-webscr.`
15014
- );
15015
- }
15016
- function ancestorDirectories(startDirectory) {
15017
- const directories = [];
15018
- let current = startDirectory;
15019
- while (true) {
15020
- directories.push(current);
15021
- const parent = dirname(current);
15022
- if (parent === current) {
15023
- return directories;
15024
- }
15025
- current = parent;
15026
- }
15027
- }
15028
- async function isReadableFile(path) {
15029
- try {
15030
- await access(path, constants.R_OK);
15031
- return true;
15032
- } catch {
15033
- return false;
15034
- }
15035
- }
15036
-
15037
- // src/device-server/deploy.ts
14990
+ // ../agent/src/device-server/deploy.ts
15038
14991
  async function deployDeviceServer(session, artifact) {
15039
14992
  await session.push(artifact.localPath, artifact.remotePath);
15040
14993
  }
15041
14994
 
15042
- // src/device-server/start.ts
14995
+ // ../agent/src/device-server/start.ts
15043
14996
  var AdbDeviceServer = class {
15044
14997
  constructor(adbProvider, artifact = defaultDeviceServerArtifact) {
15045
14998
  this.adbProvider = adbProvider;
@@ -15197,8 +15150,9 @@ async function collectTextUntil(chunks, expected) {
15197
15150
  return output + decoder.decode();
15198
15151
  }
15199
15152
 
15200
- // src/server/create-fastify-app.ts
15153
+ // ../agent/src/server/create-fastify-app.ts
15201
15154
  import websocket from "@fastify/websocket";
15155
+ import middie from "@fastify/middie";
15202
15156
 
15203
15157
  // ../../packages/protocol/src/streams.ts
15204
15158
  var StreamId = /* @__PURE__ */ ((StreamId2) => {
@@ -15404,10 +15358,13 @@ function readPayloadLength(bytes) {
15404
15358
  // ../../packages/transport/src/backpressure.ts
15405
15359
  var VIDEO_KEYFRAME_FLAG = 1 << 0;
15406
15360
 
15407
- // src/server/create-fastify-app.ts
15361
+ // ../agent/src/server/create-fastify-app.ts
15408
15362
  import Fastify from "fastify";
15363
+ import { constants as constants2 } from "fs";
15364
+ import { access as access2, readFile } from "fs/promises";
15365
+ import { extname, join as join2, normalize, relative, sep } from "path";
15409
15366
 
15410
- // src/security/origin.ts
15367
+ // ../agent/src/security/origin.ts
15411
15368
  function isAllowedOrigin(origin, config2, requestHost) {
15412
15369
  if (!origin) {
15413
15370
  return true;
@@ -15417,9 +15374,6 @@ function isAllowedOrigin(origin, config2, requestHost) {
15417
15374
  if (url2.protocol !== "http:") {
15418
15375
  return false;
15419
15376
  }
15420
- if (requestHost !== void 0 && isLocalDevUiOrigin(url2) && isAllowedHost(requestHost, config2)) {
15421
- return true;
15422
- }
15423
15377
  if (!isAllowedHost(url2.host, config2)) {
15424
15378
  return false;
15425
15379
  }
@@ -15462,9 +15416,6 @@ function isLocalHost(host) {
15462
15416
  const normalized = normalizeHost(host);
15463
15417
  return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
15464
15418
  }
15465
- function isLocalDevUiOrigin(url2) {
15466
- return url2.port === "5173" && isLocalHost(url2.host);
15467
- }
15468
15419
  function samePort(url2, host) {
15469
15420
  return (url2.port || defaultPort(url2.protocol)) === (extractPort(host) || defaultPort(url2.protocol));
15470
15421
  }
@@ -15483,7 +15434,7 @@ function extractPort(host) {
15483
15434
  return parts.length === 2 ? parts[1] ?? "" : "";
15484
15435
  }
15485
15436
 
15486
- // src/security/session-token.ts
15437
+ // ../agent/src/security/session-token.ts
15487
15438
  import { randomBytes } from "crypto";
15488
15439
  function createSessionToken(sessionId, deviceSerial, nowMs, ttlMs, video) {
15489
15440
  return {
@@ -15495,7 +15446,7 @@ function createSessionToken(sessionId, deviceSerial, nowMs, ttlMs, video) {
15495
15446
  };
15496
15447
  }
15497
15448
 
15498
- // src/session/session-manager.ts
15449
+ // ../agent/src/session/session-manager.ts
15499
15450
  var SessionManager = class {
15500
15451
  constructor(adbProvider, now = () => Date.now(), ttlMs = 6e4) {
15501
15452
  this.adbProvider = adbProvider;
@@ -15581,7 +15532,7 @@ var SessionManager = class {
15581
15532
  }
15582
15533
  };
15583
15534
 
15584
- // src/security/auth.ts
15535
+ // ../agent/src/security/auth.ts
15585
15536
  function validateAgentAuthHeader(authorization, config2) {
15586
15537
  if (!config2.authToken) {
15587
15538
  return true;
@@ -15590,7 +15541,7 @@ function validateAgentAuthHeader(authorization, config2) {
15590
15541
  return values.some((value) => value === `Bearer ${config2.authToken}`);
15591
15542
  }
15592
15543
 
15593
- // src/server/routes.ts
15544
+ // ../agent/src/server/routes.ts
15594
15545
  var noopUpdateRuntimeConfig = () => {
15595
15546
  return;
15596
15547
  };
@@ -15918,10 +15869,10 @@ function createShareUrl(bindHost, port) {
15918
15869
  return `http://${host}:${port}`;
15919
15870
  }
15920
15871
 
15921
- // src/server/websocket.ts
15872
+ // ../agent/src/server/websocket.ts
15922
15873
  var binaryWebSocketProtocol = "droid-webscr.v1";
15923
15874
 
15924
- // src/server/create-fastify-app.ts
15875
+ // ../agent/src/server/create-fastify-app.ts
15925
15876
  function createLoggerOptions(enabled) {
15926
15877
  return enabled === false ? false : {
15927
15878
  level: "info",
@@ -15936,6 +15887,12 @@ async function createFastifyApp(context) {
15936
15887
  const app = Fastify({
15937
15888
  logger: createLoggerOptions(context.logger)
15938
15889
  });
15890
+ if (context.webUi?.devMiddleware) {
15891
+ await app.register(middie);
15892
+ app.use(
15893
+ context.webUi.devMiddleware
15894
+ );
15895
+ }
15939
15896
  await app.register(websocket, {
15940
15897
  options: {
15941
15898
  handleProtocols: selectBinaryWebSocketProtocol
@@ -15978,6 +15935,7 @@ async function createFastifyApp(context) {
15978
15935
  app.closeActiveDeviceSessions = closeActiveSessions;
15979
15936
  app.addHook("preClose", async () => {
15980
15937
  await closeActiveSessions({ waitForStartup: true });
15938
+ await context.webUi?.close?.();
15981
15939
  });
15982
15940
  app.addHook("onRequest", async (request, reply) => {
15983
15941
  const origin = request.headers.origin;
@@ -16125,6 +16083,7 @@ async function createFastifyApp(context) {
16125
16083
  });
16126
16084
  }
16127
16085
  );
16086
+ registerWebUiRoutes(app, context.webUi);
16128
16087
  return app;
16129
16088
  }
16130
16089
  function selectBinaryWebSocketProtocol(protocols) {
@@ -16140,8 +16099,85 @@ function ignoreAsyncError2() {
16140
16099
  function closeBrowserSocket(socket, code, reason) {
16141
16100
  socket.close?.(code, reason);
16142
16101
  }
16102
+ function registerWebUiRoutes(app, webUi) {
16103
+ if (!webUi) {
16104
+ return;
16105
+ }
16106
+ app.get("/*", async (request, reply) => {
16107
+ const path = request.url.split("?")[0] ?? "/";
16108
+ if (path.startsWith("/api/") || path === "/api" || path.startsWith("/ws/") || path === "/ws") {
16109
+ return reply.code(404).send({ error: "Not found" });
16110
+ }
16111
+ const file2 = await readWebUiFile(webUi, path);
16112
+ if (file2) {
16113
+ return reply.type(file2.contentType).send(file2.content);
16114
+ }
16115
+ if (webUi.renderIndex) {
16116
+ return reply.type("text/html; charset=utf-8").send(await webUi.renderIndex(request.url));
16117
+ }
16118
+ const index = await readWebUiFile(webUi, "/");
16119
+ if (index) {
16120
+ return reply.type(index.contentType).send(index.content);
16121
+ }
16122
+ return reply.code(404).send({ error: "Not found" });
16123
+ });
16124
+ }
16125
+ async function readWebUiFile(webUi, path) {
16126
+ const staticFile = webUi.staticFiles?.[path] ?? (path === "/" ? webUi.staticFiles?.["/"] : void 0);
16127
+ if (staticFile) {
16128
+ return staticFile;
16129
+ }
16130
+ if (!webUi.staticRoot) {
16131
+ return void 0;
16132
+ }
16133
+ const filePath = resolveStaticFilePath(webUi.staticRoot, path);
16134
+ if (!filePath || !await isReadableFile2(filePath)) {
16135
+ return void 0;
16136
+ }
16137
+ return {
16138
+ content: await readFile(filePath),
16139
+ contentType: contentTypeForPath(filePath)
16140
+ };
16141
+ }
16142
+ function resolveStaticFilePath(root, path) {
16143
+ const normalizedPath = path === "/" ? "/index.html" : path;
16144
+ const decodedPath = decodeURIComponent(normalizedPath);
16145
+ const relativePath = decodedPath.replace(/^\/+/, "");
16146
+ const resolvedPath = normalize(join2(root, relativePath));
16147
+ const relativeToRoot = relative(root, resolvedPath);
16148
+ if (relativeToRoot.startsWith("..") || relativeToRoot.includes(`..${sep}`)) {
16149
+ return void 0;
16150
+ }
16151
+ return resolvedPath;
16152
+ }
16153
+ async function isReadableFile2(path) {
16154
+ try {
16155
+ await access2(path, constants2.R_OK);
16156
+ return true;
16157
+ } catch {
16158
+ return false;
16159
+ }
16160
+ }
16161
+ function contentTypeForPath(path) {
16162
+ switch (extname(path)) {
16163
+ case ".css":
16164
+ return "text/css; charset=utf-8";
16165
+ case ".html":
16166
+ return "text/html; charset=utf-8";
16167
+ case ".js":
16168
+ return "text/javascript; charset=utf-8";
16169
+ case ".json":
16170
+ return "application/json; charset=utf-8";
16171
+ case ".svg":
16172
+ return "image/svg+xml";
16173
+ case ".wasm":
16174
+ return "application/wasm";
16175
+ default:
16176
+ return "application/octet-stream";
16177
+ }
16178
+ }
16143
16179
 
16144
- // src/runtime.ts
16180
+ // ../agent/src/runtime.ts
16145
16181
  async function startAgent(options = {}) {
16146
16182
  const adbProvider = options.adbProvider ?? new SystemAdbProvider();
16147
16183
  let runtimeConfig = options.config ?? defaultAgentConfig;
@@ -16157,7 +16193,8 @@ async function startAgent(options = {}) {
16157
16193
  rebindRuntime,
16158
16194
  updateRuntimeConfig: (nextConfig) => {
16159
16195
  runtimeConfig = nextConfig;
16160
- }
16196
+ },
16197
+ webUi: options.webUi
16161
16198
  });
16162
16199
  const applyRuntimeRebind = async (bindHost, port) => {
16163
16200
  const previousApp = currentApp;
@@ -16202,9 +16239,17 @@ async function startAgent(options = {}) {
16202
16239
  await currentApp?.close();
16203
16240
  await Promise.all(closingPorts.values());
16204
16241
  currentApp = void 0;
16242
+ },
16243
+ get url() {
16244
+ return createRuntimeUrl(runtimeConfig.bindHost, runtimeConfig.port);
16205
16245
  }
16206
16246
  };
16207
16247
  }
16248
+ function createRuntimeUrl(bindHost, port) {
16249
+ const host = bindHost === "0.0.0.0" || bindHost === "::" ? "127.0.0.1" : bindHost;
16250
+ const formattedHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
16251
+ return `http://${formattedHost}:${port}`;
16252
+ }
16208
16253
  function isDirectRun(moduleUrl, argv) {
16209
16254
  const entrypoint = argv[1];
16210
16255
  return entrypoint !== void 0 && pathToFileURL(entrypoint).href === moduleUrl;
@@ -16246,41 +16291,89 @@ function ignoreAsyncError3() {
16246
16291
  return void 0;
16247
16292
  }
16248
16293
 
16249
- // src/bin.ts
16294
+ // package.json
16295
+ var package_default = {
16296
+ name: "@arenahito/droid-webscr",
16297
+ version: "0.2.0",
16298
+ private: false,
16299
+ license: "MIT",
16300
+ repository: {
16301
+ type: "git",
16302
+ url: "git+https://github.com/arenahito/droid-webscr.git",
16303
+ directory: "apps/cli"
16304
+ },
16305
+ bin: {
16306
+ "droid-webscr": "dist/bin.js"
16307
+ },
16308
+ files: [
16309
+ "dist",
16310
+ "web",
16311
+ "android",
16312
+ "README.md",
16313
+ "LICENSE"
16314
+ ],
16315
+ type: "module",
16316
+ publishConfig: {
16317
+ access: "public"
16318
+ },
16319
+ scripts: {
16320
+ build: "tsup && node ../../tools/package-cli.mjs",
16321
+ "build:dev": "tsup --config tsup.dev.config.ts",
16322
+ lint: "oxlint --config ../../oxlint.json src",
16323
+ test: "vitest run",
16324
+ "type-check": "tsc -p tsconfig.json --noEmit"
16325
+ },
16326
+ dependencies: {
16327
+ "@droid-webscr/agent": "workspace:*",
16328
+ "@fastify/middie": "9.3.2",
16329
+ "@fastify/websocket": "11.2.0",
16330
+ fastify: "5.8.5",
16331
+ pino: "10.3.1"
16332
+ },
16333
+ devDependencies: {
16334
+ vite: "^8.0.16"
16335
+ }
16336
+ };
16337
+
16338
+ // src/cli.ts
16250
16339
  async function runCli(argv, runtime = {}) {
16251
16340
  const args = argv.slice(2);
16252
16341
  const io = createCliIo(runtime);
16253
- const packageVersion = runtime.packageVersion ?? package_default.version;
16254
- const start = runtime.startAgent ?? startAgent;
16255
- if (args.length === 0) {
16256
- await start();
16257
- return 0;
16258
- }
16259
16342
  if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
16260
16343
  io.stdout(createCliHelp());
16261
16344
  return 0;
16262
16345
  }
16263
16346
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v")) {
16264
- io.stdout(`${packageVersion}
16347
+ io.stdout(`${runtime.packageVersion ?? "0.0.0"}
16265
16348
  `);
16266
16349
  return 0;
16267
16350
  }
16268
- io.stderr(`Unknown option: ${args.join(" ")}
16351
+ if (args.length > 0) {
16352
+ io.stderr(`Unknown option: ${args.join(" ")}
16269
16353
 
16270
16354
  `);
16271
- io.stderr(createCliHelp());
16272
- return 1;
16355
+ io.stderr(createCliHelp());
16356
+ return 1;
16357
+ }
16358
+ const startRuntime = runtime.startRuntime;
16359
+ if (!startRuntime) {
16360
+ throw new Error("No droid-webscr runtime was configured.");
16361
+ }
16362
+ const started = await startRuntime();
16363
+ io.stdout(`droid-webscr is running at ${started.url}
16364
+ `);
16365
+ return 0;
16273
16366
  }
16274
16367
  function createCliHelp() {
16275
16368
  return `Usage: droid-webscr [options]
16276
16369
 
16277
- Starts the local droid-webscr agent.
16370
+ Starts the integrated droid-webscr local server and web UI.
16278
16371
 
16279
16372
  Options:
16280
16373
  -h, --help Show this help text
16281
16374
  -v, --version Show the package version
16282
16375
 
16283
- The agent listens on http://127.0.0.1:7391 by default.
16376
+ The web UI and agent API share http://127.0.0.1:7391 by default.
16284
16377
  `;
16285
16378
  }
16286
16379
  function createCliIo(runtime) {
@@ -16289,8 +16382,35 @@ function createCliIo(runtime) {
16289
16382
  stdout: runtime.stdout ?? ((value) => process.stdout.write(value))
16290
16383
  };
16291
16384
  }
16385
+
16386
+ // src/package-paths.ts
16387
+ import { join as join3 } from "path";
16388
+ var packagedAndroidArtifactFileName = "droid-webscr-server-android.jar";
16389
+ function resolvePackagedWebRoot(packageRoot2) {
16390
+ return join3(packageRoot2, "web");
16391
+ }
16392
+ function resolvePackagedAndroidArtifact(packageRoot2) {
16393
+ return {
16394
+ localPath: join3(packageRoot2, "android", packagedAndroidArtifactFileName),
16395
+ remotePath: deviceServerArtifactRemotePath
16396
+ };
16397
+ }
16398
+
16399
+ // src/bin.ts
16400
+ var packageRoot = dirname2(dirname2(fileURLToPath2(import.meta.url)));
16401
+ async function startPackagedRuntime() {
16402
+ return startAgent({
16403
+ deviceServerArtifact: resolvePackagedAndroidArtifact(packageRoot),
16404
+ webUi: {
16405
+ staticRoot: resolvePackagedWebRoot(packageRoot)
16406
+ }
16407
+ });
16408
+ }
16292
16409
  if (isDirectRun(import.meta.url, process.argv)) {
16293
- runCli(process.argv).then(
16410
+ runCli(process.argv, {
16411
+ packageVersion: package_default.version,
16412
+ startRuntime: startPackagedRuntime
16413
+ }).then(
16294
16414
  (exitCode) => {
16295
16415
  process.exitCode = exitCode;
16296
16416
  },
@@ -16301,7 +16421,6 @@ if (isDirectRun(import.meta.url, process.argv)) {
16301
16421
  );
16302
16422
  }
16303
16423
  export {
16304
- createCliHelp,
16305
- runCli
16424
+ startPackagedRuntime
16306
16425
  };
16307
16426
  //# sourceMappingURL=bin.js.map