@neuralnomads/codenomad-dev 0.20.0-dev-20260909-855d2ee7 → 0.20.0-dev-20260910-abaf6eba

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.
Files changed (113) hide show
  1. package/dist/index.js +29 -31
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.test.js +9 -1
  4. package/dist/index.test.js.map +1 -1
  5. package/dist/server/__tests__/listener-base-url.test.js +26 -1
  6. package/dist/server/__tests__/listener-base-url.test.js.map +1 -1
  7. package/dist/server/__tests__/network-addresses.test.js +40 -0
  8. package/dist/server/__tests__/network-addresses.test.js.map +1 -1
  9. package/dist/server/__tests__/network-host.test.js +34 -0
  10. package/dist/server/__tests__/network-host.test.js.map +1 -0
  11. package/dist/server/__tests__/tls-ipv6.test.js +54 -0
  12. package/dist/server/__tests__/tls-ipv6.test.js.map +1 -0
  13. package/dist/server/http-server.js +6 -5
  14. package/dist/server/http-server.js.map +1 -1
  15. package/dist/server/listener-base-url.js +12 -3
  16. package/dist/server/listener-base-url.js.map +1 -1
  17. package/dist/server/network-addresses.js +20 -42
  18. package/dist/server/network-addresses.js.map +1 -1
  19. package/dist/server/network-host.js +62 -0
  20. package/dist/server/network-host.js.map +1 -0
  21. package/dist/server/routes/meta.js +2 -4
  22. package/dist/server/routes/meta.js.map +1 -1
  23. package/dist/server/tls.js +52 -32
  24. package/dist/server/tls.js.map +1 -1
  25. package/package.json +1 -1
  26. package/public/assets/{App-Nlt9zV-v.js → App-0ECD8eRb.js} +25 -25
  27. package/public/assets/App-0ECD8eRb.js.map +1 -0
  28. package/public/assets/FilesTab-BVJawmU7.js +3 -0
  29. package/public/assets/{FilesTab-z7UrjcAQ.js.map → FilesTab-BVJawmU7.js.map} +1 -1
  30. package/public/assets/{GitChangesTab-C04bYKhs.js → GitChangesTab-BVdfbJ_l.js} +2 -2
  31. package/public/assets/{GitChangesTab-C04bYKhs.js.map → GitChangesTab-BVdfbJ_l.js.map} +1 -1
  32. package/public/assets/{SplitFilePanel-B29MqCuU.js → SplitFilePanel-CSR5-RHY.js} +2 -2
  33. package/public/assets/{SplitFilePanel-B29MqCuU.js.map → SplitFilePanel-CSR5-RHY.js.map} +1 -1
  34. package/public/assets/{StatusTab-wUKfwnFf.js → StatusTab-DIodfPQd.js} +2 -2
  35. package/public/assets/{StatusTab-wUKfwnFf.js.map → StatusTab-DIodfPQd.js.map} +1 -1
  36. package/public/assets/{align-justify-glU678D9.js → align-justify-kDFhSvpm.js} +2 -2
  37. package/public/assets/{align-justify-glU678D9.js.map → align-justify-kDFhSvpm.js.map} +1 -1
  38. package/public/assets/{bundle-full-BrsCElYv.js → bundle-full-B4eYITdG.js} +2 -2
  39. package/public/assets/{bundle-full-BrsCElYv.js.map → bundle-full-B4eYITdG.js.map} +1 -1
  40. package/public/assets/{client-state-j9Iu7F-E.js → client-state-D3g-WH8W.js} +2 -2
  41. package/public/assets/{client-state-j9Iu7F-E.js.map → client-state-D3g-WH8W.js.map} +1 -1
  42. package/public/assets/{diff-viewer-B0VS1voD.js → diff-viewer-BLL0OcUK.js} +2 -2
  43. package/public/assets/{diff-viewer-B0VS1voD.js.map → diff-viewer-BLL0OcUK.js.map} +1 -1
  44. package/public/assets/{index-ClaHfu-1.js → index-BIqxsbaj.js} +2 -2
  45. package/public/assets/{index-ClaHfu-1.js.map → index-BIqxsbaj.js.map} +1 -1
  46. package/public/assets/index-BtuH3zKP.js +2 -0
  47. package/public/assets/index-BtuH3zKP.js.map +1 -0
  48. package/public/assets/index-Bz_OQJYA.css +1 -0
  49. package/public/assets/{index-B6bX3AMT.js → index-CeF-jpOV.js} +2 -2
  50. package/public/assets/{index-B6bX3AMT.js.map → index-CeF-jpOV.js.map} +1 -1
  51. package/public/assets/index-CrOPzgHN.js +2 -0
  52. package/public/assets/index-CrOPzgHN.js.map +1 -0
  53. package/public/assets/index-D21P0GMO.js +2 -0
  54. package/public/assets/index-D21P0GMO.js.map +1 -0
  55. package/public/assets/index-DLRrUgI7.js +2 -0
  56. package/public/assets/index-DLRrUgI7.js.map +1 -0
  57. package/public/assets/index-DLtH2OSD.js +2 -0
  58. package/public/assets/index-DLtH2OSD.js.map +1 -0
  59. package/public/assets/index-DWnsOFes.js +2 -0
  60. package/public/assets/index-DWnsOFes.js.map +1 -0
  61. package/public/assets/index-DbfYo3i-.js +2 -0
  62. package/public/assets/index-DbfYo3i-.js.map +1 -0
  63. package/public/assets/index-DnqYBc2b.js +2 -0
  64. package/public/assets/index-DnqYBc2b.js.map +1 -0
  65. package/public/assets/index-ZnQhzm1X.js +2 -0
  66. package/public/assets/index-ZnQhzm1X.js.map +1 -0
  67. package/public/assets/index-e5yyN2yK.js +3 -0
  68. package/public/assets/index-e5yyN2yK.js.map +1 -0
  69. package/public/assets/{loading-CYiiwb08.js → loading-CaoeVfIV.js} +2 -2
  70. package/public/assets/{loading-CYiiwb08.js.map → loading-CaoeVfIV.js.map} +1 -1
  71. package/public/assets/main-CeMcnDRn.js +48 -0
  72. package/public/assets/main-CeMcnDRn.js.map +1 -0
  73. package/public/assets/{markdown-DWvSdCZz.js → markdown-BeJ9YIFU.js} +4 -4
  74. package/public/assets/{markdown-DWvSdCZz.js.map → markdown-BeJ9YIFU.js.map} +1 -1
  75. package/public/assets/{startup-state-settings-card-2KHpBL8U.js → startup-state-settings-card-BvpJJ6ei.js} +2 -2
  76. package/public/assets/{startup-state-settings-card-2KHpBL8U.js.map → startup-state-settings-card-BvpJJ6ei.js.map} +1 -1
  77. package/public/assets/{terminal-square-lzHuj_of.js → terminal-square-DBCSEAmh.js} +2 -2
  78. package/public/assets/{terminal-square-lzHuj_of.js.map → terminal-square-DBCSEAmh.js.map} +1 -1
  79. package/public/assets/{tool-call-DjkszeT4.js → tool-call-BJiSHSx7.js} +10 -10
  80. package/public/assets/{tool-call-DjkszeT4.js.map → tool-call-BJiSHSx7.js.map} +1 -1
  81. package/public/assets/{unified-picker-5JmIM6a0.js → unified-picker-CAEyj3a0.js} +2 -2
  82. package/public/assets/{unified-picker-5JmIM6a0.js.map → unified-picker-CAEyj3a0.js.map} +1 -1
  83. package/public/assets/{wrap-text-N0Cav2Vp.js → wrap-text-DJNV0ypl.js} +2 -2
  84. package/public/assets/{wrap-text-N0Cav2Vp.js.map → wrap-text-DJNV0ypl.js.map} +1 -1
  85. package/public/index.html +3 -3
  86. package/public/loading.html +3 -3
  87. package/public/sw.js +1 -1
  88. package/public/sw.js.map +1 -1
  89. package/public/assets/App-Nlt9zV-v.js.map +0 -1
  90. package/public/assets/FilesTab-z7UrjcAQ.js +0 -3
  91. package/public/assets/index-BIRLnDWY.js +0 -2
  92. package/public/assets/index-BIRLnDWY.js.map +0 -1
  93. package/public/assets/index-BuScpzpP.js +0 -2
  94. package/public/assets/index-BuScpzpP.js.map +0 -1
  95. package/public/assets/index-BzAEHHap.js +0 -3
  96. package/public/assets/index-BzAEHHap.js.map +0 -1
  97. package/public/assets/index-C-DZt-oz.css +0 -1
  98. package/public/assets/index-C9RXVQl9.js +0 -2
  99. package/public/assets/index-C9RXVQl9.js.map +0 -1
  100. package/public/assets/index-DBx5htn3.js +0 -2
  101. package/public/assets/index-DBx5htn3.js.map +0 -1
  102. package/public/assets/index-DHHMf3u1.js +0 -2
  103. package/public/assets/index-DHHMf3u1.js.map +0 -1
  104. package/public/assets/index-DN4Kstsd.js +0 -2
  105. package/public/assets/index-DN4Kstsd.js.map +0 -1
  106. package/public/assets/index-DbMyNDyo.js +0 -2
  107. package/public/assets/index-DbMyNDyo.js.map +0 -1
  108. package/public/assets/index-rcsmuqww.js +0 -2
  109. package/public/assets/index-rcsmuqww.js.map +0 -1
  110. package/public/assets/index-uz2QFRlk.js +0 -2
  111. package/public/assets/index-uz2QFRlk.js.map +0 -1
  112. package/public/assets/main-OmXs7qtG.js +0 -48
  113. package/public/assets/main-OmXs7qtG.js.map +0 -1
package/dist/index.js CHANGED
@@ -22,7 +22,8 @@ import { AuthManager, BOOTSTRAP_TOKEN_STDOUT_PREFIX, DEFAULT_AUTH_COOKIE_NAME, D
22
22
  import { resolveHttpsOptions } from "./server/tls";
23
23
  import { RemoteProxySessionManager } from "./server/remote-proxy";
24
24
  import { resolveNetworkAddresses, resolveRemoteAddresses } from "./server/network-addresses";
25
- import { resolveAutomationBridgeUrl, resolvePluginBaseUrl } from "./server/listener-base-url";
25
+ import { resolveAutomationBridgeUrl, resolvePluginBaseUrl, resolvePreferredRemoteListener } from "./server/listener-base-url";
26
+ import { formatHostForUrl, hasIPv6Zone, isLoopbackHost, isWildcardHost, normalizeNetworkHost } from "./server/network-host";
26
27
  import { startDevReleaseMonitor } from "./releases/dev-release-monitor";
27
28
  import { SpeechService } from "./speech/service";
28
29
  import { SideCarManager } from "./sidecars/manager";
@@ -166,17 +167,18 @@ function parsePort(input) {
166
167
  }
167
168
  return value;
168
169
  }
169
- function resolveHost(input) {
170
+ export function resolveHost(input) {
170
171
  const trimmed = input?.trim();
171
172
  if (!trimmed)
172
173
  return DEFAULT_HOST;
173
- if (trimmed === "0.0.0.0") {
174
- return "0.0.0.0";
174
+ if (hasIPv6Zone(trimmed)) {
175
+ throw new InvalidArgumentError("IPv6 zone identifiers are not supported in --host");
175
176
  }
176
- if (trimmed === "localhost") {
177
+ const normalized = normalizeNetworkHost(trimmed);
178
+ if (normalized === "localhost") {
177
179
  return DEFAULT_HOST;
178
180
  }
179
- return trimmed;
181
+ return normalized;
180
182
  }
181
183
  export function programHasArg(argv, flag) {
182
184
  return argv.some((argument) => argument === flag || argument.startsWith(`${flag}=`));
@@ -201,7 +203,6 @@ async function main() {
201
203
  logger.warn("DANGEROUS: internal authentication is disabled (--dangerously-skip-auth / CODENOMAD_SKIP_AUTH).");
202
204
  }
203
205
  const eventBus = new EventBus(eventLogger);
204
- const isLoopbackHost = (host) => host === "127.0.0.1" || host === "::1" || host.startsWith("127.");
205
206
  const configLocation = resolveConfigLocation(options.configPath);
206
207
  const configDir = configLocation.baseDir;
207
208
  if ((options.tlsKeyPath && !options.tlsCertPath) || (!options.tlsKeyPath && options.tlsCertPath)) {
@@ -328,7 +329,6 @@ async function main() {
328
329
  },
329
330
  })
330
331
  : null;
331
- const remoteAccessEnabled = options.host === "0.0.0.0" || !isLoopbackHost(options.host);
332
332
  const clientConnectionManager = new ClientConnectionManager(logger.child({ component: "client-connections" }));
333
333
  const remoteProxySessionManager = new RemoteProxySessionManager({
334
334
  authManager,
@@ -340,10 +340,9 @@ async function main() {
340
340
  const httpsBindPort = httpsPortExplicit ? options.httpsPort : 0;
341
341
  const httpBindPort = httpPortExplicit ? options.httpPort : 0;
342
342
  // Listener binding rules:
343
- // - Remote access enabled: HTTP listens on loopback, HTTPS on all IPs (host=0.0.0.0 / LAN IP).
344
- // - Remote access disabled: both listen on loopback.
345
- // - HTTP-only mode: respect --host (used for dev/testing).
346
- const httpsBindHost = remoteAccessEnabled ? options.host : "127.0.0.1";
343
+ // - Native desktop HTTP and dual-listener HTTP stay on loopback.
344
+ // - HTTPS and non-native HTTP-only modes respect --host.
345
+ const httpsBindHost = options.host;
347
346
  const httpBindHost = nativeParent.available ? "127.0.0.1" : options.http ? (options.https ? "127.0.0.1" : options.host) : "127.0.0.1";
348
347
  const servers = [];
349
348
  const httpServer = options.http || nativeParent.available
@@ -412,41 +411,40 @@ async function main() {
412
411
  if (!localStart) {
413
412
  throw new Error("No listeners started");
414
413
  }
415
- const remoteStart = httpsStart ?? httpStart;
416
- const remoteProtocol = httpsStart ? "https" : "http";
414
+ const httpListener = httpStart ? { protocol: "http", bindHost: httpBindHost, port: httpStart.port } : null;
415
+ const httpsListener = httpsStart ? { protocol: "https", bindHost: httpsBindHost, port: httpsStart.port } : null;
416
+ const remoteListener = resolvePreferredRemoteListener({ httpStart: httpListener, httpsStart: httpsListener });
417
417
  let remoteUrl;
418
418
  let remoteAddresses = [];
419
- if (remoteStart) {
420
- const wantsAll = options.host === "0.0.0.0" || !isLoopbackHost(options.host);
421
- let remoteHost = options.host;
422
- if (wantsAll) {
423
- if (options.host === "0.0.0.0") {
424
- const resolved = resolveRemoteAddresses({ host: options.host, protocol: remoteProtocol, port: remoteStart.port });
425
- remoteAddresses = resolved.userVisible;
426
- remoteUrl = resolved.primaryRemoteUrl ?? `${remoteProtocol}://localhost:${remoteStart.port}`;
427
- }
419
+ if (remoteListener) {
420
+ let remoteHost = remoteListener.bindHost;
421
+ if (isWildcardHost(remoteListener.bindHost)) {
422
+ const resolved = resolveRemoteAddresses({ host: remoteListener.bindHost, protocol: remoteListener.protocol, port: remoteListener.port });
423
+ remoteAddresses = resolved.userVisible;
424
+ const loopbackHost = remoteListener.bindHost === "0.0.0.0" ? "127.0.0.1" : "::1";
425
+ remoteUrl = resolved.primaryRemoteUrl ?? `${remoteListener.protocol}://${formatHostForUrl(loopbackHost)}:${remoteListener.port}`;
428
426
  }
429
- else {
427
+ else if (remoteListener.bindHost === "127.0.0.1") {
430
428
  remoteHost = "localhost";
431
429
  }
432
430
  if (!remoteUrl) {
433
- remoteUrl = `${remoteProtocol}://${remoteHost}:${remoteStart.port}`;
431
+ remoteUrl = `${remoteListener.protocol}://${formatHostForUrl(remoteHost)}:${remoteListener.port}`;
434
432
  }
435
433
  }
436
434
  // Prefer an explicit IPv4 loopback address only when one of the bound listeners
437
435
  // accepts loopback. Concrete LAN bindings do not, so plugins need the reachable
438
436
  // bound/listener URL instead of an unreachable 127.0.0.1 URL.
439
437
  const localUrl = resolvePluginBaseUrl({
440
- httpStart: visibleHttpStart ? { protocol: "http", bindHost: httpBindHost, port: visibleHttpStart.port } : null,
441
- httpsStart: httpsStart ? { protocol: "https", bindHost: httpsBindHost, port: httpsStart.port } : null,
438
+ httpStart: options.http ? httpListener : null,
439
+ httpsStart: httpsListener,
442
440
  remoteUrl,
443
441
  });
444
442
  serverMeta.localUrl = localUrl;
445
443
  serverMeta.localPort = localStart.port;
446
444
  serverMeta.remoteUrl = remoteUrl;
447
- serverMeta.remotePort = remoteStart?.port;
448
- serverMeta.host = options.host;
449
- serverMeta.listeningMode = options.host === "0.0.0.0" || !isLoopbackHost(options.host) ? "all" : "local";
445
+ serverMeta.remotePort = remoteListener?.port;
446
+ serverMeta.host = remoteListener?.bindHost ?? options.host;
447
+ serverMeta.listeningMode = isWildcardHost(serverMeta.host) || !isLoopbackHost(serverMeta.host) ? "all" : "local";
450
448
  let removeAutomationBridge;
451
449
  if (nativeParent.available && process.env.CODENOMAD_DEVELOPER_MODE === "1") {
452
450
  try {
@@ -465,7 +463,7 @@ async function main() {
465
463
  if (serverMeta.remotePort && remoteUrl) {
466
464
  serverMeta.addresses = remoteAddresses.length
467
465
  ? remoteAddresses
468
- : resolveNetworkAddresses({ host: options.host, protocol: remoteProtocol, port: serverMeta.remotePort });
466
+ : resolveNetworkAddresses({ host: serverMeta.host, protocol: remoteListener?.protocol ?? "http", port: serverMeta.remotePort });
469
467
  }
470
468
  else {
471
469
  serverMeta.addresses = [];
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI entry point.\n * For now this only wires the typed modules together; actual command handling comes later.\n */\nimport { Command, InvalidArgumentError, Option } from \"commander\"\nimport path from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { createRequire } from \"module\"\nimport { createHttpServer } from \"./server/http-server\"\nimport { WorkspaceManager } from \"./workspaces/manager\"\nimport { resolveConfigLocation } from \"./config/location\"\nimport { SettingsService } from \"./settings/service\"\nimport { BinaryResolver } from \"./settings/binaries\"\nimport { FileSystemBrowser } from \"./filesystem/browser\"\nimport { EventBus } from \"./events/bus\"\nimport { ServerMeta } from \"./api-types\"\nimport { InstanceStore } from \"./storage/instance-store\"\nimport { InstanceEventBridge } from \"./workspaces/instance-events\"\nimport { createLogger } from \"./logger\"\nimport { launchInBrowser } from \"./launcher\"\nimport { resolveUi } from \"./ui/remote-ui\"\nimport { AuthManager, BOOTSTRAP_TOKEN_STDOUT_PREFIX, DEFAULT_AUTH_COOKIE_NAME, DEFAULT_AUTH_USERNAME } from \"./auth/manager\"\nimport { resolveHttpsOptions } from \"./server/tls\"\nimport { RemoteProxySessionManager } from \"./server/remote-proxy\"\nimport { resolveNetworkAddresses, resolveRemoteAddresses } from \"./server/network-addresses\"\nimport { resolveAutomationBridgeUrl, resolvePluginBaseUrl } from \"./server/listener-base-url\"\nimport { startDevReleaseMonitor } from \"./releases/dev-release-monitor\"\nimport { SpeechService } from \"./speech/service\"\nimport { SideCarManager } from \"./sidecars/manager\"\nimport { PreviewManager } from \"./previews/manager\"\nimport { ClientConnectionManager } from \"./clients/connection-manager\"\nimport { runCliUpgrade } from \"./cli-upgrade\"\nimport { createServerShutdownHandler, orchestrateServerShutdown, type ServerShutdownTrigger } from \"./shutdown\"\nimport { AutoAcceptManager } from \"./permissions/auto-accept-manager\"\nimport { createOpencodePermissionReplier } from \"./permissions/opencode-replier\"\nimport { createOpencodeYoloPersistence } from \"./permissions/opencode-yolo-metadata\"\nimport { NativeParent } from \"./native-parent\"\nimport { AUTOMATION_BRIDGE_PATH, createAutomationBridgeRegistration, publishAutomationBridge, removeLegacyAutomationPlugin } from \"./opencode/automation-plugin\"\n\nconst require = createRequire(import.meta.url)\n\nconst packageJson = require(\"../package.json\") as { version: string }\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\nconst DEFAULT_UI_STATIC_DIR = path.resolve(__dirname, \"../public\")\n\ninterface CliOptions {\n host: string\n https: boolean\n http: boolean\n httpsPort: number\n httpPort: number\n tlsKeyPath?: string\n tlsCertPath?: string\n tlsCaPath?: string\n tlsSANs?: string\n rootDir: string\n configPath: string\n unrestrictedRoot: boolean\n logLevel?: string\n logDestination?: string\n uiStaticDir: string\n uiDevServer?: string\n uiAutoUpdate: boolean\n uiNoUpdate: boolean\n uiManifestUrl?: string\n launch: boolean\n authUsername: string\n authPassword?: string\n authCookieName: string\n generateToken: boolean\n dangerouslySkipAuth: boolean\n upgrade?: string | boolean\n}\n\nconst DEFAULT_HOST = \"127.0.0.1\"\nconst DEFAULT_CONFIG_PATH = \"~/.config/codenomad/config.json\"\nconst DEFAULT_HTTPS_PORT = 9898\nconst DEFAULT_HTTP_PORT = 9899\nexport const STDIN_SHUTDOWN_COMMAND = \"codenomad:shutdown\"\n\ninterface ShutdownSignalSource {\n on: (signal: \"SIGINT\" | \"SIGTERM\", listener: () => void) => unknown\n}\n\nexport function installShutdownSignalHandlers(\n source: ShutdownSignalSource,\n shutdown: (signal: ServerShutdownTrigger) => Promise<void>,\n): void {\n source.on(\"SIGINT\", () => void shutdown(\"SIGINT\"))\n source.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"))\n}\n\ninterface ShutdownStdinSource {\n on(event: \"data\", listener: (chunk: Buffer | string) => void): unknown\n off?(event: \"data\", listener: (chunk: Buffer | string) => void): unknown\n destroy?(): unknown\n}\n\nexport function installShutdownStdinHandler(\n source: ShutdownStdinSource,\n shutdown: (signal: ServerShutdownTrigger) => Promise<void>,\n handleLine?: (line: string) => boolean,\n): void {\n let buffer = \"\"\n let requested = false\n const onData = (chunk: Buffer | string) => {\n if (requested) return\n buffer += chunk.toString()\n const lines = buffer.split(/\\r?\\n/)\n buffer = lines.pop() ?? \"\"\n let shutdownRequested = false\n for (const line of lines) {\n if (line.trim() === STDIN_SHUTDOWN_COMMAND) shutdownRequested = true\n else handleLine?.(line)\n }\n if (!shutdownRequested) return\n\n requested = true\n source.off?.(\"data\", onData)\n source.destroy?.()\n void shutdown(\"stdin\")\n }\n source.on(\"data\", onData)\n}\n\nfunction parseCliOptions(argv: string[]): CliOptions {\n const program = new Command()\n .name(\"codenomad\")\n .description(\"CodeNomad CLI server\")\n .version(packageJson.version, \"-v, --version\", \"Show the CLI version\")\n .addOption(new Option(\"--host <host>\", \"Host interface to bind\").env(\"CLI_HOST\").default(DEFAULT_HOST))\n .addOption(new Option(\"--https <enabled>\", \"Enable HTTPS listener (true|false)\").env(\"CLI_HTTPS\").default(\"true\"))\n .addOption(new Option(\"--http <enabled>\", \"Enable HTTP listener (true|false)\").env(\"CLI_HTTP\").default(\"false\"))\n .addOption(new Option(\"--https-port <number>\", \"HTTPS port (0 for auto)\").env(\"CLI_HTTPS_PORT\").default(DEFAULT_HTTPS_PORT).argParser(parsePort))\n .addOption(new Option(\"--http-port <number>\", \"HTTP port (0 for auto)\").env(\"CLI_HTTP_PORT\").default(DEFAULT_HTTP_PORT).argParser(parsePort))\n .addOption(new Option(\"--tls-key <path>\", \"TLS private key (PEM)\").env(\"CLI_TLS_KEY\"))\n .addOption(new Option(\"--tls-cert <path>\", \"TLS certificate (PEM)\").env(\"CLI_TLS_CERT\"))\n .addOption(new Option(\"--tls-ca <path>\", \"TLS CA chain (PEM)\").env(\"CLI_TLS_CA\"))\n .addOption(new Option(\"--tlsSANs <list>\", \"Additional TLS SANs (comma-separated)\").env(\"CLI_TLS_SANS\"))\n .addOption(\n new Option(\"--workspace-root <path>\", \"Restricts root path where workspaces can be opened\").env(\"CLI_WORKSPACE_ROOT\").default(process.cwd()),\n )\n .addOption(new Option(\"--root <path>\").env(\"CLI_ROOT\").hideHelp(true))\n .addOption(new Option(\"--unrestricted-root\", \"Allow browsing the full filesystem\").env(\"CLI_UNRESTRICTED_ROOT\").default(false))\n .addOption(new Option(\"--config <path>\", \"Path to the config file\").env(\"CLI_CONFIG\").default(DEFAULT_CONFIG_PATH))\n .addOption(new Option(\"--log-level <level>\", \"Log level (trace|debug|info|warn|error)\").env(\"CLI_LOG_LEVEL\"))\n .addOption(new Option(\"--log-destination <path>\", \"Log destination file (defaults to stdout)\").env(\"CLI_LOG_DESTINATION\"))\n .addOption(\n new Option(\"--ui-dir <path>\", \"Directory containing the built UI bundle\").env(\"CLI_UI_DIR\").default(DEFAULT_UI_STATIC_DIR),\n )\n .addOption(new Option(\"--ui-dev-server <url>\", \"Proxy UI requests to a running dev server\").env(\"CLI_UI_DEV_SERVER\"))\n .addOption(new Option(\"--ui-no-update\", \"Disable remote UI updates\").env(\"CLI_UI_NO_UPDATE\").default(false))\n .addOption(new Option(\"--ui-auto-update <enabled>\", \"Enable remote UI updates (true|false)\").env(\"CLI_UI_AUTO_UPDATE\").default(\"true\"))\n .addOption(new Option(\"--ui-manifest-url <url>\", \"Remote UI manifest URL\").env(\"CLI_UI_MANIFEST_URL\"))\n .addOption(new Option(\"--launch\", \"Launch the UI in a browser after start\").env(\"CLI_LAUNCH\").default(false))\n .addOption(\n new Option(\"--username <username>\", \"Username for server authentication\")\n .env(\"CODENOMAD_SERVER_USERNAME\")\n .default(DEFAULT_AUTH_USERNAME),\n )\n .addOption(new Option(\"--password <password>\", \"Password for server authentication\").env(\"CODENOMAD_SERVER_PASSWORD\"))\n .addOption(\n new Option(\"--auth-cookie-name <name>\", \"Cookie name for server authentication\")\n .env(\"CODENOMAD_AUTH_COOKIE_NAME\")\n .default(DEFAULT_AUTH_COOKIE_NAME),\n )\n .addOption(\n new Option(\"--generate-token\", \"Emit a one-time bootstrap token for desktop\")\n .env(\"CODENOMAD_GENERATE_TOKEN\")\n .default(false),\n )\n .addOption(\n new Option(\n \"--dangerously-skip-auth\",\n \"Disable CodeNomad's internal auth. Use only behind a trusted perimeter (SSO/VPN/etc).\",\n )\n .env(\"CODENOMAD_SKIP_AUTH\")\n .default(false),\n )\n .addOption(new Option(\"--upgrade [version]\", \"Upgrade the global CodeNomad CLI server package and exit\"))\n\n program.parse(argv, { from: \"user\" })\n const parsed = program.opts<{\n host: string\n https?: string\n http?: string\n httpsPort: number\n httpPort: number\n tlsKey?: string\n tlsCert?: string\n tlsCa?: string\n tlsSANs?: string\n workspaceRoot?: string\n root?: string\n unrestrictedRoot?: boolean\n config: string\n logLevel?: string\n logDestination?: string\n uiDir: string\n uiDevServer?: string\n uiNoUpdate?: boolean\n uiAutoUpdate?: string\n uiManifestUrl?: string\n launch?: boolean\n username: string\n password?: string\n authCookieName: string\n generateToken?: boolean\n dangerouslySkipAuth?: boolean\n upgrade?: string | boolean\n }>()\n\n const upgrade = parsed.upgrade\n const parseBooleanEnv = (value: string | undefined): boolean => {\n const normalized = (value ?? \"\").trim().toLowerCase()\n return normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"y\" || normalized === \"on\"\n }\n\n const resolvedRoot = parsed.workspaceRoot ?? parsed.root ?? process.cwd()\n\n const normalizedHost = resolveHost(parsed.host)\n\n const autoUpdateString = (parsed.uiAutoUpdate ?? \"true\").trim().toLowerCase()\n const uiAutoUpdate = autoUpdateString === \"1\" || autoUpdateString === \"true\" || autoUpdateString === \"yes\"\n\n const httpsEnabled = parseBooleanEnv(parsed.https)\n const httpEnabled = parseBooleanEnv(parsed.http)\n\n if (upgrade === undefined && !httpsEnabled && !httpEnabled) {\n throw new InvalidArgumentError(\"At least one listener must be enabled (--https or --http)\")\n }\n\n return {\n host: normalizedHost,\n https: httpsEnabled,\n http: httpEnabled,\n httpsPort: parsed.httpsPort,\n httpPort: parsed.httpPort,\n tlsKeyPath: parsed.tlsKey,\n tlsCertPath: parsed.tlsCert,\n tlsCaPath: parsed.tlsCa,\n tlsSANs: parsed.tlsSANs,\n rootDir: resolvedRoot,\n configPath: parsed.config,\n unrestrictedRoot: Boolean(parsed.unrestrictedRoot),\n logLevel: parsed.logLevel,\n logDestination: parsed.logDestination,\n uiStaticDir: parsed.uiDir,\n uiDevServer: parsed.uiDevServer,\n uiAutoUpdate,\n uiNoUpdate: Boolean(parsed.uiNoUpdate),\n uiManifestUrl: parsed.uiManifestUrl,\n launch: Boolean(parsed.launch),\n authUsername: parsed.username,\n authPassword: parsed.password,\n authCookieName: parsed.authCookieName,\n generateToken: Boolean(parsed.generateToken),\n dangerouslySkipAuth: Boolean(parsed.dangerouslySkipAuth),\n upgrade,\n }\n}\n\nfunction parsePort(input: string): number {\n const value = Number(input)\n if (!Number.isInteger(value) || value < 0 || value > 65535) {\n throw new InvalidArgumentError(\"Port must be an integer between 0 and 65535\")\n }\n return value\n}\n\nfunction resolveHost(input: string | undefined): string {\n const trimmed = input?.trim()\n if (!trimmed) return DEFAULT_HOST\n\n if (trimmed === \"0.0.0.0\") {\n return \"0.0.0.0\"\n }\n\n if (trimmed === \"localhost\") {\n return DEFAULT_HOST\n }\n\n return trimmed\n}\n\nexport function programHasArg(argv: string[], flag: string): boolean {\n return argv.some((argument) => argument === flag || argument.startsWith(`${flag}=`))\n}\n\nasync function main() {\n const options = parseCliOptions(process.argv.slice(2))\n if (options.upgrade !== undefined) {\n const version = typeof options.upgrade === \"string\" ? options.upgrade : undefined\n process.exitCode = await runCliUpgrade(version)\n return\n }\n\n const logger = createLogger({ level: options.logLevel, destination: options.logDestination, component: \"app\" })\n const workspaceLogger = logger.child({ component: \"workspace\" })\n const configLogger = logger.child({ component: \"config\" })\n const eventLogger = logger.child({ component: \"events\" })\n\n const logOptions = {\n ...options,\n authPassword: options.authPassword ? \"[REDACTED]\" : undefined,\n }\n\n logger.info({ options: logOptions }, \"Starting CodeNomad CLI server\")\n\n if (options.dangerouslySkipAuth) {\n logger.warn(\n \"DANGEROUS: internal authentication is disabled (--dangerously-skip-auth / CODENOMAD_SKIP_AUTH).\",\n )\n }\n\n const eventBus = new EventBus(eventLogger)\n\n const isLoopbackHost = (host: string) => host === \"127.0.0.1\" || host === \"::1\" || host.startsWith(\"127.\")\n\n const configLocation = resolveConfigLocation(options.configPath)\n const configDir = configLocation.baseDir\n\n if ((options.tlsKeyPath && !options.tlsCertPath) || (!options.tlsKeyPath && options.tlsCertPath)) {\n throw new InvalidArgumentError(\"--tls-key and --tls-cert must be provided together\")\n }\n\n const serverMeta: ServerMeta = {\n localUrl: \"http://localhost:0\",\n remoteUrl: undefined,\n eventsUrl: `/api/events`,\n host: options.host,\n listeningMode: isLoopbackHost(options.host) ? \"local\" : \"all\",\n localPort: 0,\n remotePort: undefined,\n hostLabel: options.host,\n workspaceRoot: options.rootDir,\n addresses: [],\n }\n\n const authManager = new AuthManager(\n {\n configPath: configLocation.configYamlPath,\n username: options.authUsername,\n password: options.authPassword,\n cookieName: options.authCookieName,\n generateToken: options.generateToken,\n dangerouslySkipAuth: options.dangerouslySkipAuth,\n },\n logger.child({ component: \"auth\" }),\n )\n\n if (options.generateToken && !options.dangerouslySkipAuth) {\n const token = authManager.issueBootstrapToken()\n if (token) {\n console.log(`${BOOTSTRAP_TOKEN_STDOUT_PREFIX}${token}`)\n }\n }\n\n const tlsResolution = resolveHttpsOptions({\n enabled: options.https,\n configDir,\n host: options.host,\n tlsKeyPath: options.tlsKeyPath,\n tlsCertPath: options.tlsCertPath,\n tlsCaPath: options.tlsCaPath,\n tlsSANs: options.tlsSANs,\n logger: logger.child({ component: \"tls\" }),\n })\n\n const settings = new SettingsService(configLocation, eventBus, configLogger)\n const binaryResolver = new BinaryResolver(settings)\n const workspaceManager = new WorkspaceManager({\n rootDir: options.rootDir,\n settings,\n binaryResolver,\n eventBus,\n logger: workspaceLogger,\n })\n const nativeParent = new NativeParent()\n if (nativeParent.available) {\n try {\n await removeLegacyAutomationPlugin()\n } catch (error) {\n logger.warn({ err: error }, \"Failed to remove the legacy global Developer Mode plugin\")\n }\n }\n const automationBridge = createAutomationBridgeRegistration(\"http://127.0.0.1\")\n const fileSystemBrowser = new FileSystemBrowser({\n rootDir: options.rootDir,\n unrestricted: options.unrestrictedRoot,\n })\n const instanceStore = new InstanceStore(configLocation.instancesDir)\n const speechService = new SpeechService(settings, logger.child({ component: \"speech\" }))\n const sidecarManager = new SideCarManager({\n settings,\n eventBus,\n logger: logger.child({ component: \"sidecars\" }),\n })\n const previewManager = new PreviewManager()\n const yoloLogger = logger.child({ component: \"yolo\" })\n const sessionMetadataPersistence = createOpencodeYoloPersistence(workspaceManager, settings)\n const yoloManager = new AutoAcceptManager({\n eventBus,\n logger: yoloLogger,\n replier: createOpencodePermissionReplier({ workspaceManager }),\n persistence: sessionMetadataPersistence,\n })\n yoloManager.start()\n const instanceEventBridge = new InstanceEventBridge({\n workspaceManager,\n eventBus,\n logger: logger.child({ component: \"instance-events\" }),\n })\n\n const uiDirEnvOverride = Boolean(process.env.CLI_UI_DIR)\n const uiDirCliOverride = programHasArg(process.argv.slice(2), \"--ui-dir\")\n const uiOverrideIsExplicit = uiDirEnvOverride || uiDirCliOverride\n const uiDirOverride = uiOverrideIsExplicit ? options.uiStaticDir : undefined\n\n const autoUpdateEnabled = options.uiAutoUpdate && !options.uiNoUpdate\n\n const uiResolution = await resolveUi({\n serverVersion: packageJson.version,\n bundledUiDir: DEFAULT_UI_STATIC_DIR,\n autoUpdate: autoUpdateEnabled,\n overrideUiDir: uiDirOverride,\n uiDevServerUrl: options.uiDevServer,\n manifestUrl: options.uiManifestUrl,\n logger: logger.child({ component: \"ui\" }),\n })\n\n serverMeta.serverVersion = packageJson.version\n serverMeta.ui = {\n version: uiResolution.uiVersion,\n source: uiResolution.source,\n }\n serverMeta.support = {\n supported: uiResolution.supported,\n message: uiResolution.message,\n latestServerVersion: uiResolution.latestServerVersion,\n latestServerUrl: uiResolution.latestServerUrl,\n minServerVersion: uiResolution.minServerVersion,\n }\n\n const updateChannel = (process.env.CODENOMAD_UPDATE_CHANNEL ?? \"\").trim().toLowerCase()\n const githubRepo = (process.env.CODENOMAD_GITHUB_REPO ?? \"NeuralNomadsAI/CodeNomad\").trim()\n const isDevVersion = packageJson.version.includes(\"-dev.\") || packageJson.version.includes(\"-dev-\")\n const enableDevUpdateChecks = updateChannel === \"dev\" || (updateChannel === \"\" && isDevVersion)\n const devReleaseMonitor = enableDevUpdateChecks\n ? startDevReleaseMonitor({\n currentVersion: packageJson.version,\n repo: githubRepo,\n logger: logger.child({ component: \"updates\" }),\n onUpdate: (release) => {\n serverMeta.update = release\n },\n })\n : null\n\n const remoteAccessEnabled = options.host === \"0.0.0.0\" || !isLoopbackHost(options.host)\n\n const clientConnectionManager = new ClientConnectionManager(logger.child({ component: \"client-connections\" }))\n const remoteProxySessionManager = new RemoteProxySessionManager({\n authManager,\n logger: logger.child({ component: \"remote-proxy\" }),\n httpsOptions: tlsResolution?.httpsOptions,\n })\n const httpsPortExplicit = programHasArg(process.argv.slice(2), \"--https-port\") || Boolean(process.env.CLI_HTTPS_PORT)\n const httpPortExplicit = programHasArg(process.argv.slice(2), \"--http-port\") || Boolean(process.env.CLI_HTTP_PORT)\n\n const httpsBindPort = httpsPortExplicit ? options.httpsPort : 0\n const httpBindPort = httpPortExplicit ? options.httpPort : 0\n\n // Listener binding rules:\n // - Remote access enabled: HTTP listens on loopback, HTTPS on all IPs (host=0.0.0.0 / LAN IP).\n // - Remote access disabled: both listen on loopback.\n // - HTTP-only mode: respect --host (used for dev/testing).\n const httpsBindHost = remoteAccessEnabled ? options.host : \"127.0.0.1\"\n const httpBindHost = nativeParent.available ? \"127.0.0.1\" : options.http ? (options.https ? \"127.0.0.1\" : options.host) : \"127.0.0.1\"\n\n const servers: Array<ReturnType<typeof createHttpServer>> = []\n\n const httpServer = options.http || nativeParent.available\n ? createHttpServer({\n bindHost: httpBindHost,\n bindPort: httpBindPort,\n defaultPort: options.httpPort,\n protocol: \"http\",\n workspaceManager,\n settings,\n fileSystemBrowser,\n eventBus,\n serverMeta,\n instanceStore,\n speechService,\n sidecarManager,\n previewManager,\n authManager,\n clientConnectionManager,\n remoteProxySessionManager,\n yoloManager,\n uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,\n uiDevServerUrl: uiResolution.uiDevServerUrl,\n logger,\n nativeParent,\n automationBridgeToken: automationBridge.token,\n })\n : null\n\n const httpsServer = options.https\n ? createHttpServer({\n bindHost: httpsBindHost,\n bindPort: httpsBindPort,\n defaultPort: options.httpsPort,\n protocol: \"https\",\n httpsOptions: tlsResolution?.httpsOptions,\n workspaceManager,\n settings,\n fileSystemBrowser,\n eventBus,\n serverMeta,\n instanceStore,\n speechService,\n sidecarManager,\n previewManager,\n authManager,\n clientConnectionManager,\n remoteProxySessionManager,\n yoloManager,\n uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,\n uiDevServerUrl: undefined,\n logger,\n nativeParent,\n automationBridgeToken: automationBridge.token,\n })\n : null\n\n if (httpServer) servers.push(httpServer)\n if (httpsServer) servers.push(httpsServer)\n\n const [httpStart, httpsStart] = await Promise.all([\n httpServer ? httpServer.start() : Promise.resolve(null),\n httpsServer ? httpsServer.start() : Promise.resolve(null),\n ])\n\n const visibleHttpStart = options.http ? httpStart : null\n const localStart = visibleHttpStart ?? httpsStart\n if (!localStart) {\n throw new Error(\"No listeners started\")\n }\n\n const remoteStart = httpsStart ?? httpStart\n const remoteProtocol: \"http\" | \"https\" = httpsStart ? \"https\" : \"http\"\n\n let remoteUrl: string | undefined\n let remoteAddresses = [] as ReturnType<typeof resolveNetworkAddresses>\n if (remoteStart) {\n const wantsAll = options.host === \"0.0.0.0\" || !isLoopbackHost(options.host)\n let remoteHost = options.host\n if (wantsAll) {\n if (options.host === \"0.0.0.0\") {\n const resolved = resolveRemoteAddresses({ host: options.host, protocol: remoteProtocol, port: remoteStart.port })\n remoteAddresses = resolved.userVisible\n remoteUrl = resolved.primaryRemoteUrl ?? `${remoteProtocol}://localhost:${remoteStart.port}`\n }\n } else {\n remoteHost = \"localhost\"\n }\n if (!remoteUrl) {\n remoteUrl = `${remoteProtocol}://${remoteHost}:${remoteStart.port}`\n }\n }\n\n // Prefer an explicit IPv4 loopback address only when one of the bound listeners\n // accepts loopback. Concrete LAN bindings do not, so plugins need the reachable\n // bound/listener URL instead of an unreachable 127.0.0.1 URL.\n const localUrl = resolvePluginBaseUrl({\n httpStart: visibleHttpStart ? { protocol: \"http\", bindHost: httpBindHost, port: visibleHttpStart.port } : null,\n httpsStart: httpsStart ? { protocol: \"https\", bindHost: httpsBindHost, port: httpsStart.port } : null,\n remoteUrl,\n })\n\n serverMeta.localUrl = localUrl\n serverMeta.localPort = localStart.port\n serverMeta.remoteUrl = remoteUrl\n serverMeta.remotePort = remoteStart?.port\n serverMeta.host = options.host\n serverMeta.listeningMode = options.host === \"0.0.0.0\" || !isLoopbackHost(options.host) ? \"all\" : \"local\"\n\n let removeAutomationBridge: (() => Promise<void>) | undefined\n if (nativeParent.available && process.env.CODENOMAD_DEVELOPER_MODE === \"1\") {\n try {\n if (!httpStart) throw new Error(\"Developer Mode HTTP listener did not start\")\n const automationUrl = resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: httpBindHost, port: httpStart.port })\n removeAutomationBridge = await publishAutomationBridge({\n ...automationBridge,\n url: new URL(AUTOMATION_BRIDGE_PATH, automationUrl).href,\n })\n } catch (error) {\n logger.warn({ err: error }, \"Failed to publish the Developer Mode bridge\")\n }\n }\n\n if (serverMeta.remotePort && remoteUrl) {\n serverMeta.addresses = remoteAddresses.length\n ? remoteAddresses\n : resolveNetworkAddresses({ host: options.host, protocol: remoteProtocol, port: serverMeta.remotePort })\n } else {\n serverMeta.addresses = []\n }\n\n console.log(`Local Connection URL : ${serverMeta.localUrl}`)\n if (serverMeta.remoteUrl) {\n console.log(`Remote Connection URL : ${serverMeta.remoteUrl}`)\n const additionalRemoteUrls = serverMeta.addresses\n .map((addr) => addr.remoteUrl)\n .filter((url) => url !== serverMeta.remoteUrl)\n\n if (additionalRemoteUrls.length > 0) {\n console.log(\"Other Accessible URLs:\")\n for (const url of additionalRemoteUrls) {\n console.log(` - ${url}`)\n }\n }\n }\n\n if (options.launch) {\n await launchInBrowser(serverMeta.localUrl, logger.child({ component: \"launcher\" }))\n }\n\n const shutdown = createServerShutdownHandler({\n logger,\n holdAfterFailure: () => new Promise<void>(() => { setInterval(() => undefined, 60_000) }),\n setExitCode: (code) => {\n process.stdin.destroy()\n process.exitCode = code\n },\n shutdown: () =>\n orchestrateServerShutdown(\n {\n stopInstanceEventBridge: () => instanceEventBridge.shutdown(),\n stopSidecars: () => sidecarManager.shutdown(),\n stopClientConnections: () => clientConnectionManager.shutdown(),\n stopRemoteProxySessions: () => remoteProxySessionManager.shutdown(),\n stopWorkspaces: () => workspaceManager.shutdown(),\n stopHttpServers: async () => {\n nativeParent.close()\n await removeAutomationBridge?.()\n yoloManager.stop()\n const results = await Promise.allSettled(servers.map((srv) => srv.stop()))\n const failures = results.flatMap((result) => (result.status === \"rejected\" ? [result.reason] : []))\n if (failures.length > 0) {\n const error = new Error(\"One or more HTTP servers failed to stop\") as Error & { failures: unknown[] }\n error.failures = failures\n throw error\n }\n logger.info(\"HTTP server(s) stopped\")\n },\n stopReleaseMonitor: () => devReleaseMonitor?.stop(),\n },\n logger,\n ),\n })\n\n installShutdownSignalHandlers(process, shutdown)\n installShutdownStdinHandler(process.stdin, shutdown, (line) => nativeParent.handleLine(line))\n}\n\nif (path.resolve(process.argv[1] ?? \"\") === __filename) {\n main().catch((error) => {\n const logger = createLogger({ component: \"app\" })\n logger.error({ err: error }, \"CLI server crashed\")\n process.exit(1)\n })\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI entry point.\n * For now this only wires the typed modules together; actual command handling comes later.\n */\nimport { Command, InvalidArgumentError, Option } from \"commander\"\nimport path from \"path\"\nimport { fileURLToPath } from \"url\"\nimport { createRequire } from \"module\"\nimport { createHttpServer } from \"./server/http-server\"\nimport { WorkspaceManager } from \"./workspaces/manager\"\nimport { resolveConfigLocation } from \"./config/location\"\nimport { SettingsService } from \"./settings/service\"\nimport { BinaryResolver } from \"./settings/binaries\"\nimport { FileSystemBrowser } from \"./filesystem/browser\"\nimport { EventBus } from \"./events/bus\"\nimport { ServerMeta } from \"./api-types\"\nimport { InstanceStore } from \"./storage/instance-store\"\nimport { InstanceEventBridge } from \"./workspaces/instance-events\"\nimport { createLogger } from \"./logger\"\nimport { launchInBrowser } from \"./launcher\"\nimport { resolveUi } from \"./ui/remote-ui\"\nimport { AuthManager, BOOTSTRAP_TOKEN_STDOUT_PREFIX, DEFAULT_AUTH_COOKIE_NAME, DEFAULT_AUTH_USERNAME } from \"./auth/manager\"\nimport { resolveHttpsOptions } from \"./server/tls\"\nimport { RemoteProxySessionManager } from \"./server/remote-proxy\"\nimport { resolveNetworkAddresses, resolveRemoteAddresses } from \"./server/network-addresses\"\nimport { resolveAutomationBridgeUrl, resolvePluginBaseUrl, resolvePreferredRemoteListener } from \"./server/listener-base-url\"\nimport { formatHostForUrl, hasIPv6Zone, isLoopbackHost, isWildcardHost, normalizeNetworkHost } from \"./server/network-host\"\nimport { startDevReleaseMonitor } from \"./releases/dev-release-monitor\"\nimport { SpeechService } from \"./speech/service\"\nimport { SideCarManager } from \"./sidecars/manager\"\nimport { PreviewManager } from \"./previews/manager\"\nimport { ClientConnectionManager } from \"./clients/connection-manager\"\nimport { runCliUpgrade } from \"./cli-upgrade\"\nimport { createServerShutdownHandler, orchestrateServerShutdown, type ServerShutdownTrigger } from \"./shutdown\"\nimport { AutoAcceptManager } from \"./permissions/auto-accept-manager\"\nimport { createOpencodePermissionReplier } from \"./permissions/opencode-replier\"\nimport { createOpencodeYoloPersistence } from \"./permissions/opencode-yolo-metadata\"\nimport { NativeParent } from \"./native-parent\"\nimport { AUTOMATION_BRIDGE_PATH, createAutomationBridgeRegistration, publishAutomationBridge, removeLegacyAutomationPlugin } from \"./opencode/automation-plugin\"\n\nconst require = createRequire(import.meta.url)\n\nconst packageJson = require(\"../package.json\") as { version: string }\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\nconst DEFAULT_UI_STATIC_DIR = path.resolve(__dirname, \"../public\")\n\ninterface CliOptions {\n host: string\n https: boolean\n http: boolean\n httpsPort: number\n httpPort: number\n tlsKeyPath?: string\n tlsCertPath?: string\n tlsCaPath?: string\n tlsSANs?: string\n rootDir: string\n configPath: string\n unrestrictedRoot: boolean\n logLevel?: string\n logDestination?: string\n uiStaticDir: string\n uiDevServer?: string\n uiAutoUpdate: boolean\n uiNoUpdate: boolean\n uiManifestUrl?: string\n launch: boolean\n authUsername: string\n authPassword?: string\n authCookieName: string\n generateToken: boolean\n dangerouslySkipAuth: boolean\n upgrade?: string | boolean\n}\n\nconst DEFAULT_HOST = \"127.0.0.1\"\nconst DEFAULT_CONFIG_PATH = \"~/.config/codenomad/config.json\"\nconst DEFAULT_HTTPS_PORT = 9898\nconst DEFAULT_HTTP_PORT = 9899\nexport const STDIN_SHUTDOWN_COMMAND = \"codenomad:shutdown\"\n\ninterface ShutdownSignalSource {\n on: (signal: \"SIGINT\" | \"SIGTERM\", listener: () => void) => unknown\n}\n\nexport function installShutdownSignalHandlers(\n source: ShutdownSignalSource,\n shutdown: (signal: ServerShutdownTrigger) => Promise<void>,\n): void {\n source.on(\"SIGINT\", () => void shutdown(\"SIGINT\"))\n source.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"))\n}\n\ninterface ShutdownStdinSource {\n on(event: \"data\", listener: (chunk: Buffer | string) => void): unknown\n off?(event: \"data\", listener: (chunk: Buffer | string) => void): unknown\n destroy?(): unknown\n}\n\nexport function installShutdownStdinHandler(\n source: ShutdownStdinSource,\n shutdown: (signal: ServerShutdownTrigger) => Promise<void>,\n handleLine?: (line: string) => boolean,\n): void {\n let buffer = \"\"\n let requested = false\n const onData = (chunk: Buffer | string) => {\n if (requested) return\n buffer += chunk.toString()\n const lines = buffer.split(/\\r?\\n/)\n buffer = lines.pop() ?? \"\"\n let shutdownRequested = false\n for (const line of lines) {\n if (line.trim() === STDIN_SHUTDOWN_COMMAND) shutdownRequested = true\n else handleLine?.(line)\n }\n if (!shutdownRequested) return\n\n requested = true\n source.off?.(\"data\", onData)\n source.destroy?.()\n void shutdown(\"stdin\")\n }\n source.on(\"data\", onData)\n}\n\nfunction parseCliOptions(argv: string[]): CliOptions {\n const program = new Command()\n .name(\"codenomad\")\n .description(\"CodeNomad CLI server\")\n .version(packageJson.version, \"-v, --version\", \"Show the CLI version\")\n .addOption(new Option(\"--host <host>\", \"Host interface to bind\").env(\"CLI_HOST\").default(DEFAULT_HOST))\n .addOption(new Option(\"--https <enabled>\", \"Enable HTTPS listener (true|false)\").env(\"CLI_HTTPS\").default(\"true\"))\n .addOption(new Option(\"--http <enabled>\", \"Enable HTTP listener (true|false)\").env(\"CLI_HTTP\").default(\"false\"))\n .addOption(new Option(\"--https-port <number>\", \"HTTPS port (0 for auto)\").env(\"CLI_HTTPS_PORT\").default(DEFAULT_HTTPS_PORT).argParser(parsePort))\n .addOption(new Option(\"--http-port <number>\", \"HTTP port (0 for auto)\").env(\"CLI_HTTP_PORT\").default(DEFAULT_HTTP_PORT).argParser(parsePort))\n .addOption(new Option(\"--tls-key <path>\", \"TLS private key (PEM)\").env(\"CLI_TLS_KEY\"))\n .addOption(new Option(\"--tls-cert <path>\", \"TLS certificate (PEM)\").env(\"CLI_TLS_CERT\"))\n .addOption(new Option(\"--tls-ca <path>\", \"TLS CA chain (PEM)\").env(\"CLI_TLS_CA\"))\n .addOption(new Option(\"--tlsSANs <list>\", \"Additional TLS SANs (comma-separated)\").env(\"CLI_TLS_SANS\"))\n .addOption(\n new Option(\"--workspace-root <path>\", \"Restricts root path where workspaces can be opened\").env(\"CLI_WORKSPACE_ROOT\").default(process.cwd()),\n )\n .addOption(new Option(\"--root <path>\").env(\"CLI_ROOT\").hideHelp(true))\n .addOption(new Option(\"--unrestricted-root\", \"Allow browsing the full filesystem\").env(\"CLI_UNRESTRICTED_ROOT\").default(false))\n .addOption(new Option(\"--config <path>\", \"Path to the config file\").env(\"CLI_CONFIG\").default(DEFAULT_CONFIG_PATH))\n .addOption(new Option(\"--log-level <level>\", \"Log level (trace|debug|info|warn|error)\").env(\"CLI_LOG_LEVEL\"))\n .addOption(new Option(\"--log-destination <path>\", \"Log destination file (defaults to stdout)\").env(\"CLI_LOG_DESTINATION\"))\n .addOption(\n new Option(\"--ui-dir <path>\", \"Directory containing the built UI bundle\").env(\"CLI_UI_DIR\").default(DEFAULT_UI_STATIC_DIR),\n )\n .addOption(new Option(\"--ui-dev-server <url>\", \"Proxy UI requests to a running dev server\").env(\"CLI_UI_DEV_SERVER\"))\n .addOption(new Option(\"--ui-no-update\", \"Disable remote UI updates\").env(\"CLI_UI_NO_UPDATE\").default(false))\n .addOption(new Option(\"--ui-auto-update <enabled>\", \"Enable remote UI updates (true|false)\").env(\"CLI_UI_AUTO_UPDATE\").default(\"true\"))\n .addOption(new Option(\"--ui-manifest-url <url>\", \"Remote UI manifest URL\").env(\"CLI_UI_MANIFEST_URL\"))\n .addOption(new Option(\"--launch\", \"Launch the UI in a browser after start\").env(\"CLI_LAUNCH\").default(false))\n .addOption(\n new Option(\"--username <username>\", \"Username for server authentication\")\n .env(\"CODENOMAD_SERVER_USERNAME\")\n .default(DEFAULT_AUTH_USERNAME),\n )\n .addOption(new Option(\"--password <password>\", \"Password for server authentication\").env(\"CODENOMAD_SERVER_PASSWORD\"))\n .addOption(\n new Option(\"--auth-cookie-name <name>\", \"Cookie name for server authentication\")\n .env(\"CODENOMAD_AUTH_COOKIE_NAME\")\n .default(DEFAULT_AUTH_COOKIE_NAME),\n )\n .addOption(\n new Option(\"--generate-token\", \"Emit a one-time bootstrap token for desktop\")\n .env(\"CODENOMAD_GENERATE_TOKEN\")\n .default(false),\n )\n .addOption(\n new Option(\n \"--dangerously-skip-auth\",\n \"Disable CodeNomad's internal auth. Use only behind a trusted perimeter (SSO/VPN/etc).\",\n )\n .env(\"CODENOMAD_SKIP_AUTH\")\n .default(false),\n )\n .addOption(new Option(\"--upgrade [version]\", \"Upgrade the global CodeNomad CLI server package and exit\"))\n\n program.parse(argv, { from: \"user\" })\n const parsed = program.opts<{\n host: string\n https?: string\n http?: string\n httpsPort: number\n httpPort: number\n tlsKey?: string\n tlsCert?: string\n tlsCa?: string\n tlsSANs?: string\n workspaceRoot?: string\n root?: string\n unrestrictedRoot?: boolean\n config: string\n logLevel?: string\n logDestination?: string\n uiDir: string\n uiDevServer?: string\n uiNoUpdate?: boolean\n uiAutoUpdate?: string\n uiManifestUrl?: string\n launch?: boolean\n username: string\n password?: string\n authCookieName: string\n generateToken?: boolean\n dangerouslySkipAuth?: boolean\n upgrade?: string | boolean\n }>()\n\n const upgrade = parsed.upgrade\n const parseBooleanEnv = (value: string | undefined): boolean => {\n const normalized = (value ?? \"\").trim().toLowerCase()\n return normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"y\" || normalized === \"on\"\n }\n\n const resolvedRoot = parsed.workspaceRoot ?? parsed.root ?? process.cwd()\n\n const normalizedHost = resolveHost(parsed.host)\n\n const autoUpdateString = (parsed.uiAutoUpdate ?? \"true\").trim().toLowerCase()\n const uiAutoUpdate = autoUpdateString === \"1\" || autoUpdateString === \"true\" || autoUpdateString === \"yes\"\n\n const httpsEnabled = parseBooleanEnv(parsed.https)\n const httpEnabled = parseBooleanEnv(parsed.http)\n\n if (upgrade === undefined && !httpsEnabled && !httpEnabled) {\n throw new InvalidArgumentError(\"At least one listener must be enabled (--https or --http)\")\n }\n\n return {\n host: normalizedHost,\n https: httpsEnabled,\n http: httpEnabled,\n httpsPort: parsed.httpsPort,\n httpPort: parsed.httpPort,\n tlsKeyPath: parsed.tlsKey,\n tlsCertPath: parsed.tlsCert,\n tlsCaPath: parsed.tlsCa,\n tlsSANs: parsed.tlsSANs,\n rootDir: resolvedRoot,\n configPath: parsed.config,\n unrestrictedRoot: Boolean(parsed.unrestrictedRoot),\n logLevel: parsed.logLevel,\n logDestination: parsed.logDestination,\n uiStaticDir: parsed.uiDir,\n uiDevServer: parsed.uiDevServer,\n uiAutoUpdate,\n uiNoUpdate: Boolean(parsed.uiNoUpdate),\n uiManifestUrl: parsed.uiManifestUrl,\n launch: Boolean(parsed.launch),\n authUsername: parsed.username,\n authPassword: parsed.password,\n authCookieName: parsed.authCookieName,\n generateToken: Boolean(parsed.generateToken),\n dangerouslySkipAuth: Boolean(parsed.dangerouslySkipAuth),\n upgrade,\n }\n}\n\nfunction parsePort(input: string): number {\n const value = Number(input)\n if (!Number.isInteger(value) || value < 0 || value > 65535) {\n throw new InvalidArgumentError(\"Port must be an integer between 0 and 65535\")\n }\n return value\n}\n\nexport function resolveHost(input: string | undefined): string {\n const trimmed = input?.trim()\n if (!trimmed) return DEFAULT_HOST\n\n if (hasIPv6Zone(trimmed)) {\n throw new InvalidArgumentError(\"IPv6 zone identifiers are not supported in --host\")\n }\n\n const normalized = normalizeNetworkHost(trimmed)\n if (normalized === \"localhost\") {\n return DEFAULT_HOST\n }\n\n return normalized\n}\n\nexport function programHasArg(argv: string[], flag: string): boolean {\n return argv.some((argument) => argument === flag || argument.startsWith(`${flag}=`))\n}\n\nasync function main() {\n const options = parseCliOptions(process.argv.slice(2))\n if (options.upgrade !== undefined) {\n const version = typeof options.upgrade === \"string\" ? options.upgrade : undefined\n process.exitCode = await runCliUpgrade(version)\n return\n }\n\n const logger = createLogger({ level: options.logLevel, destination: options.logDestination, component: \"app\" })\n const workspaceLogger = logger.child({ component: \"workspace\" })\n const configLogger = logger.child({ component: \"config\" })\n const eventLogger = logger.child({ component: \"events\" })\n\n const logOptions = {\n ...options,\n authPassword: options.authPassword ? \"[REDACTED]\" : undefined,\n }\n\n logger.info({ options: logOptions }, \"Starting CodeNomad CLI server\")\n\n if (options.dangerouslySkipAuth) {\n logger.warn(\n \"DANGEROUS: internal authentication is disabled (--dangerously-skip-auth / CODENOMAD_SKIP_AUTH).\",\n )\n }\n\n const eventBus = new EventBus(eventLogger)\n\n const configLocation = resolveConfigLocation(options.configPath)\n const configDir = configLocation.baseDir\n\n if ((options.tlsKeyPath && !options.tlsCertPath) || (!options.tlsKeyPath && options.tlsCertPath)) {\n throw new InvalidArgumentError(\"--tls-key and --tls-cert must be provided together\")\n }\n\n const serverMeta: ServerMeta = {\n localUrl: \"http://localhost:0\",\n remoteUrl: undefined,\n eventsUrl: `/api/events`,\n host: options.host,\n listeningMode: isLoopbackHost(options.host) ? \"local\" : \"all\",\n localPort: 0,\n remotePort: undefined,\n hostLabel: options.host,\n workspaceRoot: options.rootDir,\n addresses: [],\n }\n\n const authManager = new AuthManager(\n {\n configPath: configLocation.configYamlPath,\n username: options.authUsername,\n password: options.authPassword,\n cookieName: options.authCookieName,\n generateToken: options.generateToken,\n dangerouslySkipAuth: options.dangerouslySkipAuth,\n },\n logger.child({ component: \"auth\" }),\n )\n\n if (options.generateToken && !options.dangerouslySkipAuth) {\n const token = authManager.issueBootstrapToken()\n if (token) {\n console.log(`${BOOTSTRAP_TOKEN_STDOUT_PREFIX}${token}`)\n }\n }\n\n const tlsResolution = resolveHttpsOptions({\n enabled: options.https,\n configDir,\n host: options.host,\n tlsKeyPath: options.tlsKeyPath,\n tlsCertPath: options.tlsCertPath,\n tlsCaPath: options.tlsCaPath,\n tlsSANs: options.tlsSANs,\n logger: logger.child({ component: \"tls\" }),\n })\n\n const settings = new SettingsService(configLocation, eventBus, configLogger)\n const binaryResolver = new BinaryResolver(settings)\n const workspaceManager = new WorkspaceManager({\n rootDir: options.rootDir,\n settings,\n binaryResolver,\n eventBus,\n logger: workspaceLogger,\n })\n const nativeParent = new NativeParent()\n if (nativeParent.available) {\n try {\n await removeLegacyAutomationPlugin()\n } catch (error) {\n logger.warn({ err: error }, \"Failed to remove the legacy global Developer Mode plugin\")\n }\n }\n const automationBridge = createAutomationBridgeRegistration(\"http://127.0.0.1\")\n const fileSystemBrowser = new FileSystemBrowser({\n rootDir: options.rootDir,\n unrestricted: options.unrestrictedRoot,\n })\n const instanceStore = new InstanceStore(configLocation.instancesDir)\n const speechService = new SpeechService(settings, logger.child({ component: \"speech\" }))\n const sidecarManager = new SideCarManager({\n settings,\n eventBus,\n logger: logger.child({ component: \"sidecars\" }),\n })\n const previewManager = new PreviewManager()\n const yoloLogger = logger.child({ component: \"yolo\" })\n const sessionMetadataPersistence = createOpencodeYoloPersistence(workspaceManager, settings)\n const yoloManager = new AutoAcceptManager({\n eventBus,\n logger: yoloLogger,\n replier: createOpencodePermissionReplier({ workspaceManager }),\n persistence: sessionMetadataPersistence,\n })\n yoloManager.start()\n const instanceEventBridge = new InstanceEventBridge({\n workspaceManager,\n eventBus,\n logger: logger.child({ component: \"instance-events\" }),\n })\n\n const uiDirEnvOverride = Boolean(process.env.CLI_UI_DIR)\n const uiDirCliOverride = programHasArg(process.argv.slice(2), \"--ui-dir\")\n const uiOverrideIsExplicit = uiDirEnvOverride || uiDirCliOverride\n const uiDirOverride = uiOverrideIsExplicit ? options.uiStaticDir : undefined\n\n const autoUpdateEnabled = options.uiAutoUpdate && !options.uiNoUpdate\n\n const uiResolution = await resolveUi({\n serverVersion: packageJson.version,\n bundledUiDir: DEFAULT_UI_STATIC_DIR,\n autoUpdate: autoUpdateEnabled,\n overrideUiDir: uiDirOverride,\n uiDevServerUrl: options.uiDevServer,\n manifestUrl: options.uiManifestUrl,\n logger: logger.child({ component: \"ui\" }),\n })\n\n serverMeta.serverVersion = packageJson.version\n serverMeta.ui = {\n version: uiResolution.uiVersion,\n source: uiResolution.source,\n }\n serverMeta.support = {\n supported: uiResolution.supported,\n message: uiResolution.message,\n latestServerVersion: uiResolution.latestServerVersion,\n latestServerUrl: uiResolution.latestServerUrl,\n minServerVersion: uiResolution.minServerVersion,\n }\n\n const updateChannel = (process.env.CODENOMAD_UPDATE_CHANNEL ?? \"\").trim().toLowerCase()\n const githubRepo = (process.env.CODENOMAD_GITHUB_REPO ?? \"NeuralNomadsAI/CodeNomad\").trim()\n const isDevVersion = packageJson.version.includes(\"-dev.\") || packageJson.version.includes(\"-dev-\")\n const enableDevUpdateChecks = updateChannel === \"dev\" || (updateChannel === \"\" && isDevVersion)\n const devReleaseMonitor = enableDevUpdateChecks\n ? startDevReleaseMonitor({\n currentVersion: packageJson.version,\n repo: githubRepo,\n logger: logger.child({ component: \"updates\" }),\n onUpdate: (release) => {\n serverMeta.update = release\n },\n })\n : null\n\n const clientConnectionManager = new ClientConnectionManager(logger.child({ component: \"client-connections\" }))\n const remoteProxySessionManager = new RemoteProxySessionManager({\n authManager,\n logger: logger.child({ component: \"remote-proxy\" }),\n httpsOptions: tlsResolution?.httpsOptions,\n })\n const httpsPortExplicit = programHasArg(process.argv.slice(2), \"--https-port\") || Boolean(process.env.CLI_HTTPS_PORT)\n const httpPortExplicit = programHasArg(process.argv.slice(2), \"--http-port\") || Boolean(process.env.CLI_HTTP_PORT)\n\n const httpsBindPort = httpsPortExplicit ? options.httpsPort : 0\n const httpBindPort = httpPortExplicit ? options.httpPort : 0\n\n // Listener binding rules:\n // - Native desktop HTTP and dual-listener HTTP stay on loopback.\n // - HTTPS and non-native HTTP-only modes respect --host.\n const httpsBindHost = options.host\n const httpBindHost = nativeParent.available ? \"127.0.0.1\" : options.http ? (options.https ? \"127.0.0.1\" : options.host) : \"127.0.0.1\"\n\n const servers: Array<ReturnType<typeof createHttpServer>> = []\n\n const httpServer = options.http || nativeParent.available\n ? createHttpServer({\n bindHost: httpBindHost,\n bindPort: httpBindPort,\n defaultPort: options.httpPort,\n protocol: \"http\",\n workspaceManager,\n settings,\n fileSystemBrowser,\n eventBus,\n serverMeta,\n instanceStore,\n speechService,\n sidecarManager,\n previewManager,\n authManager,\n clientConnectionManager,\n remoteProxySessionManager,\n yoloManager,\n uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,\n uiDevServerUrl: uiResolution.uiDevServerUrl,\n logger,\n nativeParent,\n automationBridgeToken: automationBridge.token,\n })\n : null\n\n const httpsServer = options.https\n ? createHttpServer({\n bindHost: httpsBindHost,\n bindPort: httpsBindPort,\n defaultPort: options.httpsPort,\n protocol: \"https\",\n httpsOptions: tlsResolution?.httpsOptions,\n workspaceManager,\n settings,\n fileSystemBrowser,\n eventBus,\n serverMeta,\n instanceStore,\n speechService,\n sidecarManager,\n previewManager,\n authManager,\n clientConnectionManager,\n remoteProxySessionManager,\n yoloManager,\n uiStaticDir: uiResolution.uiStaticDir ?? DEFAULT_UI_STATIC_DIR,\n uiDevServerUrl: undefined,\n logger,\n nativeParent,\n automationBridgeToken: automationBridge.token,\n })\n : null\n\n if (httpServer) servers.push(httpServer)\n if (httpsServer) servers.push(httpsServer)\n\n const [httpStart, httpsStart] = await Promise.all([\n httpServer ? httpServer.start() : Promise.resolve(null),\n httpsServer ? httpsServer.start() : Promise.resolve(null),\n ])\n\n const visibleHttpStart = options.http ? httpStart : null\n const localStart = visibleHttpStart ?? httpsStart\n if (!localStart) {\n throw new Error(\"No listeners started\")\n }\n\n const httpListener = httpStart ? { protocol: \"http\" as const, bindHost: httpBindHost, port: httpStart.port } : null\n const httpsListener = httpsStart ? { protocol: \"https\" as const, bindHost: httpsBindHost, port: httpsStart.port } : null\n const remoteListener = resolvePreferredRemoteListener({ httpStart: httpListener, httpsStart: httpsListener })\n\n let remoteUrl: string | undefined\n let remoteAddresses = [] as ReturnType<typeof resolveNetworkAddresses>\n if (remoteListener) {\n let remoteHost = remoteListener.bindHost\n if (isWildcardHost(remoteListener.bindHost)) {\n const resolved = resolveRemoteAddresses({ host: remoteListener.bindHost, protocol: remoteListener.protocol, port: remoteListener.port })\n remoteAddresses = resolved.userVisible\n const loopbackHost = remoteListener.bindHost === \"0.0.0.0\" ? \"127.0.0.1\" : \"::1\"\n remoteUrl = resolved.primaryRemoteUrl ?? `${remoteListener.protocol}://${formatHostForUrl(loopbackHost)}:${remoteListener.port}`\n } else if (remoteListener.bindHost === \"127.0.0.1\") {\n remoteHost = \"localhost\"\n }\n if (!remoteUrl) {\n remoteUrl = `${remoteListener.protocol}://${formatHostForUrl(remoteHost)}:${remoteListener.port}`\n }\n }\n\n // Prefer an explicit IPv4 loopback address only when one of the bound listeners\n // accepts loopback. Concrete LAN bindings do not, so plugins need the reachable\n // bound/listener URL instead of an unreachable 127.0.0.1 URL.\n const localUrl = resolvePluginBaseUrl({\n httpStart: options.http ? httpListener : null,\n httpsStart: httpsListener,\n remoteUrl,\n })\n\n serverMeta.localUrl = localUrl\n serverMeta.localPort = localStart.port\n serverMeta.remoteUrl = remoteUrl\n serverMeta.remotePort = remoteListener?.port\n serverMeta.host = remoteListener?.bindHost ?? options.host\n serverMeta.listeningMode = isWildcardHost(serverMeta.host) || !isLoopbackHost(serverMeta.host) ? \"all\" : \"local\"\n\n let removeAutomationBridge: (() => Promise<void>) | undefined\n if (nativeParent.available && process.env.CODENOMAD_DEVELOPER_MODE === \"1\") {\n try {\n if (!httpStart) throw new Error(\"Developer Mode HTTP listener did not start\")\n const automationUrl = resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: httpBindHost, port: httpStart.port })\n removeAutomationBridge = await publishAutomationBridge({\n ...automationBridge,\n url: new URL(AUTOMATION_BRIDGE_PATH, automationUrl).href,\n })\n } catch (error) {\n logger.warn({ err: error }, \"Failed to publish the Developer Mode bridge\")\n }\n }\n\n if (serverMeta.remotePort && remoteUrl) {\n serverMeta.addresses = remoteAddresses.length\n ? remoteAddresses\n : resolveNetworkAddresses({ host: serverMeta.host, protocol: remoteListener?.protocol ?? \"http\", port: serverMeta.remotePort })\n } else {\n serverMeta.addresses = []\n }\n\n console.log(`Local Connection URL : ${serverMeta.localUrl}`)\n if (serverMeta.remoteUrl) {\n console.log(`Remote Connection URL : ${serverMeta.remoteUrl}`)\n const additionalRemoteUrls = serverMeta.addresses\n .map((addr) => addr.remoteUrl)\n .filter((url) => url !== serverMeta.remoteUrl)\n\n if (additionalRemoteUrls.length > 0) {\n console.log(\"Other Accessible URLs:\")\n for (const url of additionalRemoteUrls) {\n console.log(` - ${url}`)\n }\n }\n }\n\n if (options.launch) {\n await launchInBrowser(serverMeta.localUrl, logger.child({ component: \"launcher\" }))\n }\n\n const shutdown = createServerShutdownHandler({\n logger,\n holdAfterFailure: () => new Promise<void>(() => { setInterval(() => undefined, 60_000) }),\n setExitCode: (code) => {\n process.stdin.destroy()\n process.exitCode = code\n },\n shutdown: () =>\n orchestrateServerShutdown(\n {\n stopInstanceEventBridge: () => instanceEventBridge.shutdown(),\n stopSidecars: () => sidecarManager.shutdown(),\n stopClientConnections: () => clientConnectionManager.shutdown(),\n stopRemoteProxySessions: () => remoteProxySessionManager.shutdown(),\n stopWorkspaces: () => workspaceManager.shutdown(),\n stopHttpServers: async () => {\n nativeParent.close()\n await removeAutomationBridge?.()\n yoloManager.stop()\n const results = await Promise.allSettled(servers.map((srv) => srv.stop()))\n const failures = results.flatMap((result) => (result.status === \"rejected\" ? [result.reason] : []))\n if (failures.length > 0) {\n const error = new Error(\"One or more HTTP servers failed to stop\") as Error & { failures: unknown[] }\n error.failures = failures\n throw error\n }\n logger.info(\"HTTP server(s) stopped\")\n },\n stopReleaseMonitor: () => devReleaseMonitor?.stop(),\n },\n logger,\n ),\n })\n\n installShutdownSignalHandlers(process, shutdown)\n installShutdownStdinHandler(process.stdin, shutdown, (line) => nativeParent.handleLine(line))\n}\n\nif (path.resolve(process.argv[1] ?? \"\") === __filename) {\n main().catch((error) => {\n const logger = createLogger({ component: \"app\" })\n logger.error({ err: error }, \"CLI server crashed\")\n process.exit(1)\n })\n}\n"]}
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
2
2
  import { spawn } from "node:child_process";
3
3
  import { once } from "node:events";
4
4
  import { describe, it } from "node:test";
5
- import { installShutdownSignalHandlers, installShutdownStdinHandler, STDIN_SHUTDOWN_COMMAND } from "./index";
5
+ import { installShutdownSignalHandlers, installShutdownStdinHandler, resolveHost, STDIN_SHUTDOWN_COMMAND } from "./index";
6
6
  import { createServerShutdownHandler } from "./shutdown";
7
7
  describe("CLI shutdown signal registration", () => {
8
8
  it("routes a second process signal to forced nonzero escalation", async () => {
@@ -60,4 +60,12 @@ describe("CLI shutdown signal registration", () => {
60
60
  assert.equal(code, 0);
61
61
  });
62
62
  });
63
+ describe("CLI host normalization", () => {
64
+ it("normalizes mapped and internationalized hosts and rejects IPv6 zones", () => {
65
+ assert.equal(resolveHost("::ffff:0:0"), "0.0.0.0");
66
+ assert.equal(resolveHost("::ffff:7f00:1"), "127.0.0.1");
67
+ assert.equal(resolveHost("münchen.local"), "xn--mnchen-3ya.local");
68
+ assert.throws(() => resolveHost("fe80::1%12"), /IPv6 zone identifiers/);
69
+ });
70
+ });
63
71
  //# sourceMappingURL=index.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { spawn } from \"node:child_process\"\nimport { once } from \"node:events\"\nimport { describe, it } from \"node:test\"\n\nimport { installShutdownSignalHandlers, installShutdownStdinHandler, STDIN_SHUTDOWN_COMMAND } from \"./index\"\nimport { createServerShutdownHandler } from \"./shutdown\"\n\ndescribe(\"CLI shutdown signal registration\", () => {\n it(\"routes a second process signal to forced nonzero escalation\", async () => {\n const listeners = new Map<string, () => void>()\n let finishCleanup!: () => void\n const cleanup = new Promise<void>((resolve) => {\n finishCleanup = resolve\n })\n const exits: number[] = []\n let handled: Promise<void> | undefined\n const shutdown = createServerShutdownHandler({\n shutdown: () => cleanup,\n logger: { info() {}, warn() {}, error() {} },\n forceExit: (code) => exits.push(code),\n setExitCode: () => undefined,\n reportStatus: () => undefined,\n })\n installShutdownSignalHandlers(\n { on: (signal, listener) => listeners.set(signal, listener) },\n (signal) => (handled = shutdown(signal)),\n )\n\n listeners.get(\"SIGINT\")?.()\n listeners.get(\"SIGTERM\")?.()\n assert.deepEqual(exits, [1])\n\n finishCleanup()\n await handled\n })\n\n it(\"coalesces chunked and repeated stdin shutdown commands through the same handler\", async () => {\n const listeners = new Map<string, (chunk: Buffer | string) => void>()\n const triggers: string[] = []\n let destroys = 0\n const source = {\n on: (event: \"data\", listener: (chunk: Buffer | string) => void) => listeners.set(event, listener),\n off: (event: \"data\", listener: (chunk: Buffer | string) => void) => {\n if (listeners.get(event) === listener) listeners.delete(event)\n },\n destroy: () => { destroys++ },\n }\n installShutdownStdinHandler(source, async (trigger) => { triggers.push(trigger) })\n\n const listener = listeners.get(\"data\")!\n listener(STDIN_SHUTDOWN_COMMAND.slice(0, 8))\n listener(`${STDIN_SHUTDOWN_COMMAND.slice(8)}\\n${STDIN_SHUTDOWN_COMMAND}\\n`)\n listener(`${STDIN_SHUTDOWN_COMMAND}\\n`)\n await Promise.resolve()\n\n assert.deepEqual(triggers, [\"stdin\"])\n assert.equal(destroys, 1)\n assert.equal(listeners.has(\"data\"), false)\n })\n\n it(\"allows a real piped process to exit naturally after the shutdown command\", { timeout: 5_000 }, async () => {\n const moduleUrl = new URL(\"./index.ts\", import.meta.url).href\n const child = spawn(process.execPath, [\"--import\", \"tsx\", \"--input-type=module\", \"-e\", `\n import { installShutdownStdinHandler } from ${JSON.stringify(moduleUrl)}\n installShutdownStdinHandler(process.stdin, async () => { process.exitCode = 0 })\n `], { stdio: [\"pipe\", \"ignore\", \"inherit\"] })\n\n child.stdin.end(`${STDIN_SHUTDOWN_COMMAND}\\n`)\n const [code] = await once(child, \"exit\")\n assert.equal(code, 0)\n })\n})\n"]}
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAExC,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AACzH,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAExD,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAA;QAC/C,IAAI,aAA0B,CAAA;QAC9B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC5C,aAAa,GAAG,OAAO,CAAA;QACzB,CAAC,CAAC,CAAA;QACF,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,IAAI,OAAkC,CAAA;QACtC,MAAM,QAAQ,GAAG,2BAA2B,CAAC;YAC3C,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO;YACvB,MAAM,EAAE,EAAE,IAAI,KAAI,CAAC,EAAE,IAAI,KAAI,CAAC,EAAE,KAAK,KAAI,CAAC,EAAE;YAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YACrC,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;YAC5B,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;SAC9B,CAAC,CAAA;QACF,6BAA6B,CAC3B,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAC7D,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CACzC,CAAA;QAED,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAA;QAC3B,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,CAAA;QAC5B,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAE5B,aAAa,EAAE,CAAA;QACf,MAAM,OAAO,CAAA;IACf,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;QAC/F,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4C,CAAA;QACrE,MAAM,QAAQ,GAAa,EAAE,CAAA;QAC7B,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,MAAM,MAAM,GAAG;YACb,EAAE,EAAE,CAAC,KAAa,EAAE,QAA0C,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC;YACjG,GAAG,EAAE,CAAC,KAAa,EAAE,QAA0C,EAAE,EAAE;gBACjE,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ;oBAAE,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAChE,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAA,CAAC,CAAC;SAC9B,CAAA;QACD,2BAA2B,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;QAElF,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QACvC,QAAQ,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5C,QAAQ,CAAC,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,sBAAsB,IAAI,CAAC,CAAA;QAC3E,QAAQ,CAAC,GAAG,sBAAsB,IAAI,CAAC,CAAA;QACvC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;QAEvB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;QACrC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACzB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,EAAE;QAC5G,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE;oDACvC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;KAExE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,CAAA;QAE7C,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,sBAAsB,IAAI,CAAC,CAAA;QAC9C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC,CAAA;QAClD,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,CAAA;QACvD,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC,CAAA;QAClE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,uBAAuB,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import assert from \"node:assert/strict\"\nimport { spawn } from \"node:child_process\"\nimport { once } from \"node:events\"\nimport { describe, it } from \"node:test\"\n\nimport { installShutdownSignalHandlers, installShutdownStdinHandler, resolveHost, STDIN_SHUTDOWN_COMMAND } from \"./index\"\nimport { createServerShutdownHandler } from \"./shutdown\"\n\ndescribe(\"CLI shutdown signal registration\", () => {\n it(\"routes a second process signal to forced nonzero escalation\", async () => {\n const listeners = new Map<string, () => void>()\n let finishCleanup!: () => void\n const cleanup = new Promise<void>((resolve) => {\n finishCleanup = resolve\n })\n const exits: number[] = []\n let handled: Promise<void> | undefined\n const shutdown = createServerShutdownHandler({\n shutdown: () => cleanup,\n logger: { info() {}, warn() {}, error() {} },\n forceExit: (code) => exits.push(code),\n setExitCode: () => undefined,\n reportStatus: () => undefined,\n })\n installShutdownSignalHandlers(\n { on: (signal, listener) => listeners.set(signal, listener) },\n (signal) => (handled = shutdown(signal)),\n )\n\n listeners.get(\"SIGINT\")?.()\n listeners.get(\"SIGTERM\")?.()\n assert.deepEqual(exits, [1])\n\n finishCleanup()\n await handled\n })\n\n it(\"coalesces chunked and repeated stdin shutdown commands through the same handler\", async () => {\n const listeners = new Map<string, (chunk: Buffer | string) => void>()\n const triggers: string[] = []\n let destroys = 0\n const source = {\n on: (event: \"data\", listener: (chunk: Buffer | string) => void) => listeners.set(event, listener),\n off: (event: \"data\", listener: (chunk: Buffer | string) => void) => {\n if (listeners.get(event) === listener) listeners.delete(event)\n },\n destroy: () => { destroys++ },\n }\n installShutdownStdinHandler(source, async (trigger) => { triggers.push(trigger) })\n\n const listener = listeners.get(\"data\")!\n listener(STDIN_SHUTDOWN_COMMAND.slice(0, 8))\n listener(`${STDIN_SHUTDOWN_COMMAND.slice(8)}\\n${STDIN_SHUTDOWN_COMMAND}\\n`)\n listener(`${STDIN_SHUTDOWN_COMMAND}\\n`)\n await Promise.resolve()\n\n assert.deepEqual(triggers, [\"stdin\"])\n assert.equal(destroys, 1)\n assert.equal(listeners.has(\"data\"), false)\n })\n\n it(\"allows a real piped process to exit naturally after the shutdown command\", { timeout: 5_000 }, async () => {\n const moduleUrl = new URL(\"./index.ts\", import.meta.url).href\n const child = spawn(process.execPath, [\"--import\", \"tsx\", \"--input-type=module\", \"-e\", `\n import { installShutdownStdinHandler } from ${JSON.stringify(moduleUrl)}\n installShutdownStdinHandler(process.stdin, async () => { process.exitCode = 0 })\n `], { stdio: [\"pipe\", \"ignore\", \"inherit\"] })\n\n child.stdin.end(`${STDIN_SHUTDOWN_COMMAND}\\n`)\n const [code] = await once(child, \"exit\")\n assert.equal(code, 0)\n })\n})\n\ndescribe(\"CLI host normalization\", () => {\n it(\"normalizes mapped and internationalized hosts and rejects IPv6 zones\", () => {\n assert.equal(resolveHost(\"::ffff:0:0\"), \"0.0.0.0\")\n assert.equal(resolveHost(\"::ffff:7f00:1\"), \"127.0.0.1\")\n assert.equal(resolveHost(\"münchen.local\"), \"xn--mnchen-3ya.local\")\n assert.throws(() => resolveHost(\"fe80::1%12\"), /IPv6 zone identifiers/)\n })\n})\n"]}
@@ -1,6 +1,14 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
- import { resolveAutomationBridgeUrl, resolvePluginBaseUrl } from "../listener-base-url";
3
+ import { resolveAutomationBridgeUrl, resolvePluginBaseUrl, resolvePreferredRemoteListener } from "../listener-base-url";
4
+ describe("resolvePreferredRemoteListener", () => {
5
+ it("keeps the effective bind host paired with the preferred listener", () => {
6
+ const httpStart = { protocol: "http", bindHost: "127.0.0.1", port: 9899 };
7
+ const httpsStart = { protocol: "https", bindHost: "0.0.0.0", port: 9898 };
8
+ assert.deepEqual(resolvePreferredRemoteListener({ httpStart, httpsStart }), httpsStart);
9
+ assert.deepEqual(resolvePreferredRemoteListener({ httpStart, httpsStart: null }), httpStart);
10
+ });
11
+ });
4
12
  describe("resolvePluginBaseUrl", () => {
5
13
  it("keeps loopback URLs for default local listeners", () => {
6
14
  assert.equal(resolvePluginBaseUrl({
@@ -27,6 +35,23 @@ describe("resolvePluginBaseUrl", () => {
27
35
  remoteUrl: "https://192.168.1.25:9898",
28
36
  }), "http://127.0.0.1:9899");
29
37
  });
38
+ it("uses the exact concrete loopback bind host", () => {
39
+ assert.equal(resolvePluginBaseUrl({
40
+ httpsStart: { protocol: "https", bindHost: "127.0.0.2", port: 9898 },
41
+ remoteUrl: "https://127.0.0.2:9898",
42
+ }), "https://127.0.0.2:9898");
43
+ });
44
+ it("uses bracketed IPv6 loopback for IPv6 wildcard listeners", () => {
45
+ assert.equal(resolvePluginBaseUrl({
46
+ httpsStart: { protocol: "https", bindHost: "0:0:0:0:0:0:0:0", port: 9898 },
47
+ remoteUrl: "https://[2001:db8::20]:9898",
48
+ }), "https://[::1]:9898");
49
+ });
50
+ it("formats concrete IPv6 fallback listeners", () => {
51
+ assert.equal(resolvePluginBaseUrl({
52
+ httpsStart: { protocol: "https", bindHost: "2001:db8::20", port: 9898 },
53
+ }), "https://[2001:db8::20]:9898");
54
+ });
30
55
  });
31
56
  describe("resolveAutomationBridgeUrl", () => {
32
57
  it("uses IPv4 loopback for an internal HTTP listener", () => {
@@ -1 +1 @@
1
- {"version":3,"file":"listener-base-url.test.js","sourceRoot":"","sources":["../../../src/server/__tests__/listener-base-url.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAExC,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEvF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,KAAK,CACV,oBAAoB,CAAC;YACnB,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;YACpE,SAAS,EAAE,wBAAwB;SACpC,CAAC,EACF,wBAAwB,CACzB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,KAAK,CACV,oBAAoB,CAAC;YACnB,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE;YACvE,SAAS,EAAE,2BAA2B;SACvC,CAAC,EACF,2BAA2B,CAC5B,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,CAAC,KAAK,CACV,oBAAoB,CAAC;YACnB,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE;YAClE,SAAS,EAAE,2BAA2B;SACvC,CAAC,EACF,wBAAwB,CACzB,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,KAAK,CACV,oBAAoB,CAAC;YACnB,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;YAClE,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE;YACvE,SAAS,EAAE,2BAA2B;SACvC,CAAC,EACF,uBAAuB,CACxB,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAA;IAC1H,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,eAAe,CAAC,CAAA;QAC1H,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,eAAe,CAAC,CAAA;IAC7H,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import assert from \"node:assert/strict\"\nimport { describe, it } from \"node:test\"\n\nimport { resolveAutomationBridgeUrl, resolvePluginBaseUrl } from \"../listener-base-url\"\n\ndescribe(\"resolvePluginBaseUrl\", () => {\n it(\"keeps loopback URLs for default local listeners\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"127.0.0.1\", port: 9898 },\n remoteUrl: \"https://localhost:9898\",\n }),\n \"https://127.0.0.1:9898\",\n )\n })\n\n it(\"uses the concrete LAN listener when no loopback listener exists\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"192.168.1.25\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"https://192.168.1.25:9898\",\n )\n })\n\n it(\"prefers loopback for wildcard listeners because 0.0.0.0 accepts loopback\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"0.0.0.0\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"https://127.0.0.1:9898\",\n )\n })\n\n it(\"keeps loopback HTTP when remote HTTPS also exists\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpStart: { protocol: \"http\", bindHost: \"127.0.0.1\", port: 9899 },\n httpsStart: { protocol: \"https\", bindHost: \"192.168.1.25\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"http://127.0.0.1:9899\",\n )\n })\n})\n\ndescribe(\"resolveAutomationBridgeUrl\", () => {\n it(\"uses IPv4 loopback for an internal HTTP listener\", () => {\n assert.equal(resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: \"0.0.0.0\", port: 3210 }), \"http://127.0.0.1:3210\")\n })\n\n it(\"rejects HTTPS and non-loopback listeners\", () => {\n assert.throws(() => resolveAutomationBridgeUrl({ protocol: \"https\", bindHost: \"127.0.0.1\", port: 3210 }), /loopback HTTP/)\n assert.throws(() => resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: \"192.168.1.2\", port: 3210 }), /loopback HTTP/)\n })\n})\n"]}
1
+ {"version":3,"file":"listener-base-url.test.js","sourceRoot":"","sources":["../../../src/server/__tests__/listener-base-url.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { describe, it } from \"node:test\"\n\nimport { resolveAutomationBridgeUrl, resolvePluginBaseUrl, resolvePreferredRemoteListener } from \"../listener-base-url\"\n\ndescribe(\"resolvePreferredRemoteListener\", () => {\n it(\"keeps the effective bind host paired with the preferred listener\", () => {\n const httpStart = { protocol: \"http\" as const, bindHost: \"127.0.0.1\", port: 9899 }\n const httpsStart = { protocol: \"https\" as const, bindHost: \"0.0.0.0\", port: 9898 }\n\n assert.deepEqual(resolvePreferredRemoteListener({ httpStart, httpsStart }), httpsStart)\n assert.deepEqual(resolvePreferredRemoteListener({ httpStart, httpsStart: null }), httpStart)\n })\n})\n\ndescribe(\"resolvePluginBaseUrl\", () => {\n it(\"keeps loopback URLs for default local listeners\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"127.0.0.1\", port: 9898 },\n remoteUrl: \"https://localhost:9898\",\n }),\n \"https://127.0.0.1:9898\",\n )\n })\n\n it(\"uses the concrete LAN listener when no loopback listener exists\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"192.168.1.25\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"https://192.168.1.25:9898\",\n )\n })\n\n it(\"prefers loopback for wildcard listeners because 0.0.0.0 accepts loopback\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"0.0.0.0\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"https://127.0.0.1:9898\",\n )\n })\n\n it(\"keeps loopback HTTP when remote HTTPS also exists\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpStart: { protocol: \"http\", bindHost: \"127.0.0.1\", port: 9899 },\n httpsStart: { protocol: \"https\", bindHost: \"192.168.1.25\", port: 9898 },\n remoteUrl: \"https://192.168.1.25:9898\",\n }),\n \"http://127.0.0.1:9899\",\n )\n })\n\n it(\"uses the exact concrete loopback bind host\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"127.0.0.2\", port: 9898 },\n remoteUrl: \"https://127.0.0.2:9898\",\n }),\n \"https://127.0.0.2:9898\",\n )\n })\n\n it(\"uses bracketed IPv6 loopback for IPv6 wildcard listeners\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"0:0:0:0:0:0:0:0\", port: 9898 },\n remoteUrl: \"https://[2001:db8::20]:9898\",\n }),\n \"https://[::1]:9898\",\n )\n })\n\n it(\"formats concrete IPv6 fallback listeners\", () => {\n assert.equal(\n resolvePluginBaseUrl({\n httpsStart: { protocol: \"https\", bindHost: \"2001:db8::20\", port: 9898 },\n }),\n \"https://[2001:db8::20]:9898\",\n )\n })\n})\n\ndescribe(\"resolveAutomationBridgeUrl\", () => {\n it(\"uses IPv4 loopback for an internal HTTP listener\", () => {\n assert.equal(resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: \"0.0.0.0\", port: 3210 }), \"http://127.0.0.1:3210\")\n })\n\n it(\"rejects HTTPS and non-loopback listeners\", () => {\n assert.throws(() => resolveAutomationBridgeUrl({ protocol: \"https\", bindHost: \"127.0.0.1\", port: 3210 }), /loopback HTTP/)\n assert.throws(() => resolveAutomationBridgeUrl({ protocol: \"http\", bindHost: \"192.168.1.2\", port: 3210 }), /loopback HTTP/)\n })\n})\n"]}
@@ -16,6 +16,46 @@ describe("resolveNetworkAddresses", () => {
16
16
  assert.deepEqual(result.map((entry) => entry.ip), ["172.24.0.1", "192.168.1.128", "10.0.0.8", "169.254.10.20", "127.0.0.1"]);
17
17
  });
18
18
  });
19
+ it("advertises only a concrete IPv4 bind host", () => {
20
+ const result = resolveNetworkAddresses({ host: "127.0.0.2", protocol: "https", port: 9898 });
21
+ assert.deepEqual(result, [
22
+ { ip: "127.0.0.2", family: "ipv4", scope: "loopback", remoteUrl: "https://127.0.0.2:9898" },
23
+ ]);
24
+ });
25
+ it("formats concrete IPv6 bind hosts as valid URLs", () => {
26
+ const result = resolveNetworkAddresses({ host: "::1", protocol: "https", port: 9898 });
27
+ assert.deepEqual(result, [
28
+ { ip: "::1", family: "ipv6", scope: "loopback", remoteUrl: "https://[::1]:9898" },
29
+ ]);
30
+ });
31
+ it("reports IPv4-mapped wildcard and loopback hosts as IPv4", () => {
32
+ usingMockedNetworkInterfaces([{ address: "192.168.1.20", family: "IPv4", internal: false }], () => {
33
+ assert.deepEqual(resolveNetworkAddresses({ host: "::ffff:0:0", protocol: "https", port: 9898 }), [
34
+ { ip: "192.168.1.20", family: "ipv4", scope: "external", remoteUrl: "https://192.168.1.20:9898" },
35
+ ]);
36
+ assert.deepEqual(resolveNetworkAddresses({ host: "::ffff:7f00:1", protocol: "https", port: 9898 }), [
37
+ { ip: "127.0.0.1", family: "ipv4", scope: "loopback", remoteUrl: "https://127.0.0.1:9898" },
38
+ ]);
39
+ });
40
+ });
41
+ it("enumerates dual-stack interfaces and excludes unusable IPv6 link-local addresses", () => {
42
+ const addresses = [
43
+ { address: "2001:db8::20", family: "IPv6", internal: false },
44
+ { address: "fe80::20", family: "IPv6", internal: false },
45
+ { address: "::1", family: 6, internal: true },
46
+ { address: "192.168.1.20", family: "IPv4", internal: false },
47
+ ];
48
+ usingMockedNetworkInterfaces(addresses, () => {
49
+ for (const host of ["::", "0:0:0:0:0:0:0:0"]) {
50
+ const result = resolveNetworkAddresses({ host, protocol: "https", port: 9898 });
51
+ assert.deepEqual(result, [
52
+ { ip: "2001:db8::20", family: "ipv6", scope: "external", remoteUrl: "https://[2001:db8::20]:9898" },
53
+ { ip: "192.168.1.20", family: "ipv4", scope: "external", remoteUrl: "https://192.168.1.20:9898" },
54
+ { ip: "::1", family: "ipv6", scope: "loopback", remoteUrl: "https://[::1]:9898" },
55
+ ]);
56
+ }
57
+ });
58
+ });
19
59
  });
20
60
  describe("resolveRemoteAddresses", () => {
21
61
  it("keeps all external addresses user-visible while preferring non-link-local addresses for the primary URL", () => {
@@ -1 +1 @@
1
- {"version":3,"file":"network-addresses.test.js","sourceRoot":"","sources":["../../../src/server/__tests__/network-addresses.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport os from \"node:os\"\nimport { describe, it } from \"node:test\"\n\nimport { resolveNetworkAddresses, resolveRemoteAddresses } from \"../network-addresses\"\n\ndescribe(\"resolveNetworkAddresses\", () => {\n it(\"preserves interface order among external addresses\", () => {\n const addresses = [\n { address: \"172.24.0.1\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"10.0.0.8\", family: 4, internal: false },\n { address: \"127.0.0.1\", family: \"IPv4\", internal: true },\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveNetworkAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.map((entry) => entry.ip),\n [\"172.24.0.1\", \"192.168.1.128\", \"10.0.0.8\", \"169.254.10.20\", \"127.0.0.1\"],\n )\n })\n })\n})\n\ndescribe(\"resolveRemoteAddresses\", () => {\n it(\"keeps all external addresses user-visible while preferring non-link-local addresses for the primary URL\", () => {\n const addresses = [\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"172.24.0.1\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.userVisible.map((entry) => entry.ip),\n [\"192.168.1.128\", \"172.24.0.1\", \"169.254.10.20\"],\n )\n assert.equal(result.primaryRemoteUrl, \"https://192.168.1.128:9898\")\n })\n })\n\n it(\"prefers private LAN addresses over public addresses\", () => {\n const addresses = [\n { address: \"203.0.113.40\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"8.8.8.8\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.userVisible.map((entry) => entry.ip),\n [\"192.168.1.128\", \"203.0.113.40\", \"8.8.8.8\"],\n )\n assert.equal(result.primaryRemoteUrl, \"https://192.168.1.128:9898\")\n })\n })\n\n it(\"uses a public address when no private LAN address is available\", () => {\n const addresses = [\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n { address: \"203.0.113.40\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(result.userVisible.map((entry) => entry.ip), [\"203.0.113.40\", \"169.254.10.20\"])\n assert.equal(result.primaryRemoteUrl, \"https://203.0.113.40:9898\")\n })\n })\n})\n\nfunction usingMockedNetworkInterfaces(\n addresses: Array<{ address: string; family: string | number; internal: boolean }>,\n callback: () => void,\n) {\n const original = os.networkInterfaces\n os.networkInterfaces = (() => ({\n ethernet0: addresses as unknown as ReturnType<typeof os.networkInterfaces>[string],\n })) as typeof os.networkInterfaces\n\n try {\n callback()\n } finally {\n os.networkInterfaces = original\n }\n}\n"]}
1
+ {"version":3,"file":"network-addresses.test.js","sourceRoot":"","sources":["../../../src/server/__tests__/network-addresses.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport os from \"node:os\"\nimport { describe, it } from \"node:test\"\n\nimport { resolveNetworkAddresses, resolveRemoteAddresses } from \"../network-addresses\"\n\ndescribe(\"resolveNetworkAddresses\", () => {\n it(\"preserves interface order among external addresses\", () => {\n const addresses = [\n { address: \"172.24.0.1\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"10.0.0.8\", family: 4, internal: false },\n { address: \"127.0.0.1\", family: \"IPv4\", internal: true },\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveNetworkAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.map((entry) => entry.ip),\n [\"172.24.0.1\", \"192.168.1.128\", \"10.0.0.8\", \"169.254.10.20\", \"127.0.0.1\"],\n )\n })\n })\n\n it(\"advertises only a concrete IPv4 bind host\", () => {\n const result = resolveNetworkAddresses({ host: \"127.0.0.2\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(result, [\n { ip: \"127.0.0.2\", family: \"ipv4\", scope: \"loopback\", remoteUrl: \"https://127.0.0.2:9898\" },\n ])\n })\n\n it(\"formats concrete IPv6 bind hosts as valid URLs\", () => {\n const result = resolveNetworkAddresses({ host: \"::1\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(result, [\n { ip: \"::1\", family: \"ipv6\", scope: \"loopback\", remoteUrl: \"https://[::1]:9898\" },\n ])\n })\n\n it(\"reports IPv4-mapped wildcard and loopback hosts as IPv4\", () => {\n usingMockedNetworkInterfaces([{ address: \"192.168.1.20\", family: \"IPv4\", internal: false }], () => {\n assert.deepEqual(resolveNetworkAddresses({ host: \"::ffff:0:0\", protocol: \"https\", port: 9898 }), [\n { ip: \"192.168.1.20\", family: \"ipv4\", scope: \"external\", remoteUrl: \"https://192.168.1.20:9898\" },\n ])\n assert.deepEqual(resolveNetworkAddresses({ host: \"::ffff:7f00:1\", protocol: \"https\", port: 9898 }), [\n { ip: \"127.0.0.1\", family: \"ipv4\", scope: \"loopback\", remoteUrl: \"https://127.0.0.1:9898\" },\n ])\n })\n })\n\n it(\"enumerates dual-stack interfaces and excludes unusable IPv6 link-local addresses\", () => {\n const addresses = [\n { address: \"2001:db8::20\", family: \"IPv6\", internal: false },\n { address: \"fe80::20\", family: \"IPv6\", internal: false },\n { address: \"::1\", family: 6, internal: true },\n { address: \"192.168.1.20\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n for (const host of [\"::\", \"0:0:0:0:0:0:0:0\"]) {\n const result = resolveNetworkAddresses({ host, protocol: \"https\", port: 9898 })\n assert.deepEqual(result, [\n { ip: \"2001:db8::20\", family: \"ipv6\", scope: \"external\", remoteUrl: \"https://[2001:db8::20]:9898\" },\n { ip: \"192.168.1.20\", family: \"ipv4\", scope: \"external\", remoteUrl: \"https://192.168.1.20:9898\" },\n { ip: \"::1\", family: \"ipv6\", scope: \"loopback\", remoteUrl: \"https://[::1]:9898\" },\n ])\n }\n })\n })\n})\n\ndescribe(\"resolveRemoteAddresses\", () => {\n it(\"keeps all external addresses user-visible while preferring non-link-local addresses for the primary URL\", () => {\n const addresses = [\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"172.24.0.1\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.userVisible.map((entry) => entry.ip),\n [\"192.168.1.128\", \"172.24.0.1\", \"169.254.10.20\"],\n )\n assert.equal(result.primaryRemoteUrl, \"https://192.168.1.128:9898\")\n })\n })\n\n it(\"prefers private LAN addresses over public addresses\", () => {\n const addresses = [\n { address: \"203.0.113.40\", family: \"IPv4\", internal: false },\n { address: \"192.168.1.128\", family: \"IPv4\", internal: false },\n { address: \"8.8.8.8\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(\n result.userVisible.map((entry) => entry.ip),\n [\"192.168.1.128\", \"203.0.113.40\", \"8.8.8.8\"],\n )\n assert.equal(result.primaryRemoteUrl, \"https://192.168.1.128:9898\")\n })\n })\n\n it(\"uses a public address when no private LAN address is available\", () => {\n const addresses = [\n { address: \"169.254.10.20\", family: \"IPv4\", internal: false },\n { address: \"203.0.113.40\", family: \"IPv4\", internal: false },\n ]\n\n usingMockedNetworkInterfaces(addresses, () => {\n const result = resolveRemoteAddresses({ host: \"0.0.0.0\", protocol: \"https\", port: 9898 })\n\n assert.deepEqual(result.userVisible.map((entry) => entry.ip), [\"203.0.113.40\", \"169.254.10.20\"])\n assert.equal(result.primaryRemoteUrl, \"https://203.0.113.40:9898\")\n })\n })\n})\n\nfunction usingMockedNetworkInterfaces(\n addresses: Array<{ address: string; family: string | number; internal: boolean }>,\n callback: () => void,\n) {\n const original = os.networkInterfaces\n os.networkInterfaces = (() => ({\n ethernet0: addresses as unknown as ReturnType<typeof os.networkInterfaces>[string],\n })) as typeof os.networkInterfaces\n\n try {\n callback()\n } finally {\n os.networkInterfaces = original\n }\n}\n"]}