@dotobokuri/fleet-console 1.13.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/AGENTS.md +1 -1
  2. package/dist/cli-bin.mjs +137 -39
  3. package/dist/cli.d.ts +4 -0
  4. package/dist/cli.mjs +137 -39
  5. package/dist/client/assets/{_baseUniq-ChU2hrfs.js → _baseUniq-cnqj2OOU.js} +1 -1
  6. package/dist/client/assets/{arc-EiqS42us.js → arc-DKvQCH7P.js} +1 -1
  7. package/dist/client/assets/{architectureDiagram-Q4EWVU46-qmztEGo1.js → architectureDiagram-Q4EWVU46-iJqnsZ6O.js} +1 -1
  8. package/dist/client/assets/{blockDiagram-DXYQGD6D-BAAvrsl8.js → blockDiagram-DXYQGD6D-CkJhTJZi.js} +1 -1
  9. package/dist/client/assets/{c4Diagram-AHTNJAMY-BLx5I4Kb.js → c4Diagram-AHTNJAMY-DHkUfhoy.js} +1 -1
  10. package/dist/client/assets/channel-C3r_coHh.js +1 -0
  11. package/dist/client/assets/{chunk-4BX2VUAB-r5DIUY_B.js → chunk-4BX2VUAB-CJmFkUz-.js} +1 -1
  12. package/dist/client/assets/{chunk-4TB4RGXK-Ddf67h97.js → chunk-4TB4RGXK-Dp00Zwg3.js} +1 -1
  13. package/dist/client/assets/{chunk-55IACEB6-RcUEP-ZS.js → chunk-55IACEB6-DFBvwrH_.js} +1 -1
  14. package/dist/client/assets/{chunk-EDXVE4YY-DsvOtQoH.js → chunk-EDXVE4YY-Dik0hYho.js} +1 -1
  15. package/dist/client/assets/{chunk-FMBD7UC4-BB_S2idL.js → chunk-FMBD7UC4-DYcmg67a.js} +1 -1
  16. package/dist/client/assets/{chunk-OYMX7WX6-DHEgUzUK.js → chunk-OYMX7WX6-B9bhXkOc.js} +1 -1
  17. package/dist/client/assets/{chunk-QZHKN3VN-DtrROVh7.js → chunk-QZHKN3VN-CW_BXRdy.js} +1 -1
  18. package/dist/client/assets/{chunk-YZCP3GAM-esfAqfqa.js → chunk-YZCP3GAM-uJM9wQJs.js} +1 -1
  19. package/dist/client/assets/classDiagram-6PBFFD2Q-DmoF5itQ.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DmoF5itQ.js +1 -0
  21. package/dist/client/assets/clone-CJPQGOBM.js +1 -0
  22. package/dist/client/assets/{cose-bilkent-S5V4N54A-Dzm0WtWj.js → cose-bilkent-S5V4N54A-BpsaUYJS.js} +1 -1
  23. package/dist/client/assets/{dagre-KV5264BT-BuizUtNo.js → dagre-KV5264BT-CLaMczco.js} +1 -1
  24. package/dist/client/assets/{diagram-5BDNPKRD-CwzQTgo4.js → diagram-5BDNPKRD-CFOnN2pM.js} +1 -1
  25. package/dist/client/assets/{diagram-G4DWMVQ6-CSaUKQrB.js → diagram-G4DWMVQ6-CkLTTvmR.js} +1 -1
  26. package/dist/client/assets/{diagram-MMDJMWI5-ClU81X-4.js → diagram-MMDJMWI5-c8R_KOlQ.js} +1 -1
  27. package/dist/client/assets/{diagram-TYMM5635-De0hefNw.js → diagram-TYMM5635-Cfz4vDC5.js} +1 -1
  28. package/dist/client/assets/{erDiagram-SMLLAGMA-DquAk5AT.js → erDiagram-SMLLAGMA-BZFJRBcT.js} +1 -1
  29. package/dist/client/assets/fira-code-cyrillic-ext-wght-normal-DhYMMuQd.woff2 +0 -0
  30. package/dist/client/assets/fira-code-cyrillic-wght-normal-Y3u8pIsh.woff2 +0 -0
  31. package/dist/client/assets/fira-code-greek-ext-wght-normal-wWus70Ix.woff2 +0 -0
  32. package/dist/client/assets/fira-code-greek-wght-normal-B2SviObF.woff2 +0 -0
  33. package/dist/client/assets/fira-code-latin-ext-wght-normal-Dvfvaomy.woff2 +0 -0
  34. package/dist/client/assets/fira-code-latin-wght-normal-CHoedHDv.woff2 +0 -0
  35. package/dist/client/assets/fira-code-symbols2-wght-normal-CE6EOz_n.woff2 +0 -0
  36. package/dist/client/assets/{flowDiagram-DWJPFMVM-B2UECwg2.js → flowDiagram-DWJPFMVM-CSbwVNst.js} +1 -1
  37. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-BKGKAKUk.js → ganttDiagram-T4ZO3ILL-Z3BPe1vZ.js} +1 -1
  38. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-fBBbSMvv.js → gitGraphDiagram-UUTBAWPF-7Ka8NeSE.js} +1 -1
  39. package/dist/client/assets/{graph-DXYFz3qN.js → graph-DG6E-jsV.js} +1 -1
  40. package/dist/client/assets/index-B-bmeDQZ.js +777 -0
  41. package/dist/client/assets/index-BfTQyXzZ.css +1 -0
  42. package/dist/client/assets/{infoDiagram-42DDH7IO-C6ij_zTC.js → infoDiagram-42DDH7IO-CN7rF9WG.js} +1 -1
  43. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-CfRd8PLR.js → ishikawaDiagram-UXIWVN3A-jus38Ki6.js} +1 -1
  44. package/dist/client/assets/{journeyDiagram-VCZTEJTY-C8Pi51PP.js → journeyDiagram-VCZTEJTY-CCn-AdDe.js} +1 -1
  45. package/dist/client/assets/{kanban-definition-6JOO6SKY-DJ0RiIlP.js → kanban-definition-6JOO6SKY-BOfals_F.js} +1 -1
  46. package/dist/client/assets/{layout-CxPTfkhA.js → layout-B2qTAIS5.js} +1 -1
  47. package/dist/client/assets/{linear-DXo_1O-i.js → linear-BmsYolMA.js} +1 -1
  48. package/dist/client/assets/{mermaid.core-CfU0SF8u.js → mermaid.core-D0OYO4L1.js} +4 -4
  49. package/dist/client/assets/{min-DNKQJJON.js → min-jZihhkYo.js} +1 -1
  50. package/dist/client/assets/{mindmap-definition-QFDTVHPH-CnoQOTpu.js → mindmap-definition-QFDTVHPH-35wK1xy9.js} +1 -1
  51. package/dist/client/assets/{pieDiagram-DEJITSTG-pkn-HZnT.js → pieDiagram-DEJITSTG-BynWLFT0.js} +1 -1
  52. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-BGzlb80c.js → quadrantDiagram-34T5L4WZ-w5UoFlnr.js} +1 -1
  53. package/dist/client/assets/{requirementDiagram-MS252O5E-CojepMS0.js → requirementDiagram-MS252O5E-BQ9zR_XY.js} +1 -1
  54. package/dist/client/assets/{sankeyDiagram-XADWPNL6-DBK_MdUK.js → sankeyDiagram-XADWPNL6-BL1Lj8dz.js} +1 -1
  55. package/dist/client/assets/{sequenceDiagram-FGHM5R23-yuQ86htX.js → sequenceDiagram-FGHM5R23-jC78BST4.js} +1 -1
  56. package/dist/client/assets/source-code-pro-cyrillic-ext-wght-normal-BODHZjil.woff2 +0 -0
  57. package/dist/client/assets/source-code-pro-cyrillic-wght-normal-aqTvhEeI.woff2 +0 -0
  58. package/dist/client/assets/source-code-pro-greek-wght-normal-BvT6WsG1.woff2 +0 -0
  59. package/dist/client/assets/source-code-pro-latin-ext-wght-normal-0UZNSh4u.woff2 +0 -0
  60. package/dist/client/assets/source-code-pro-latin-wght-normal-BP8Zz55n.woff2 +0 -0
  61. package/dist/client/assets/source-code-pro-vietnamese-wght-normal-B6x53GZG.woff2 +0 -0
  62. package/dist/client/assets/{stateDiagram-FHFEXIEX-B8Ze2bIg.js → stateDiagram-FHFEXIEX-iVYQ2VCC.js} +1 -1
  63. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BEYzM5Cb.js +1 -0
  64. package/dist/client/assets/{timeline-definition-GMOUNBTQ-C3iREGsD.js → timeline-definition-GMOUNBTQ-CYAlka_x.js} +1 -1
  65. package/dist/client/assets/{vennDiagram-DHZGUBPP-D37DpOPl.js → vennDiagram-DHZGUBPP-BFcj10GU.js} +1 -1
  66. package/dist/client/assets/{wardley-RL74JXVD-AQGWPT1m.js → wardley-RL74JXVD-CIUgshxb.js} +1 -1
  67. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-C1CVXpp0.js → wardleyDiagram-NUSXRM2D-BEV516Os.js} +1 -1
  68. package/dist/client/assets/{xychartDiagram-5P7HB3ND-BHnFjh9Q.js → xychartDiagram-5P7HB3ND-D1DFk2ax.js} +1 -1
  69. package/dist/client/index.html +2 -2
  70. package/package.json +3 -1
  71. package/dist/client/assets/channel-D_ykRZSv.js +0 -1
  72. package/dist/client/assets/classDiagram-6PBFFD2Q-DGWtQVRo.js +0 -1
  73. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DGWtQVRo.js +0 -1
  74. package/dist/client/assets/clone-BLbl3yHE.js +0 -1
  75. package/dist/client/assets/index-C6rRtW0v.js +0 -777
  76. package/dist/client/assets/index-CFIhCFSM.css +0 -1
  77. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DO0adfjo.js +0 -1
package/AGENTS.md CHANGED
@@ -84,7 +84,7 @@ The console is the operations variant of Fleet Wiki's **Maritime Codex** languag
84
84
  - `brass` means "지금 보고 있는 곳" — selected job brass dot indicator, active navigation, structural decoration, and non-live active/focus-adjacent emphasis.
85
85
  - `aurora` means "지금 살아있는 것" — streaming status, live dots, tenant beacons, stream caret, follow button, and `connection-chip--live`. Unlike Fleet Wiki, console does not reserve aurora only for document linkage because there is no document-link concept here.
86
86
  - `coral` means error/bad; `--warn` (amber, near `oklch(80% 0.13 85)`) means warning/connecting; neutral ink means idle.
87
- - User accents recolor the Dock chip `::before` perimeter ring (the same edge band the underway/in-progress orbit rides) to a user-chosen hue, which may be any hue across the wheel (red/amber/green included). The accent is the static full-perimeter fill of that ring; the underway state overrides the same `::before` with the animated aurora/warn conic and wins while work is in progress (functional status outranks an identity tag). Accents never tint the chip fill, name, border, box-shadow ring, beacon, count, or close, and never animate on their own (an infinitely orbiting ring is reserved for the functional in-progress signal). Active brass lives on the border/fill/name, so an accented chip can be active and accented at once without collision.
87
+ - User accents recolor the Dock chip `::before` perimeter ring (the same edge band the underway/in-progress orbit rides) to a user-chosen hue, which may be any hue across the wheel (red/amber/green included). The accent is the static full-perimeter fill of that ring; the underway state overrides the same `::before` and wins while work is in progress (functional status outranks an identity tag), so an accented chip never exposes its accent while underway. The rotating aurora/warn conic rides only one surface at a time to avoid duplicated GPU cost: a minimized operation's dock chip `::before` carries the conic, while a visible operation's rotation is owned by its canvas panel and the dock chip `::before` stays transparent (accent suppressed, no ring). Accents never tint the chip fill, name, border, box-shadow ring, beacon, count, or close, and never animate on their own (an infinitely orbiting ring is reserved for the functional in-progress signal). Active brass lives on the border/fill/name, so an accented chip can be active and accented at once without collision.
88
88
  - **Typography**: `Fraunces Variable` is display type for the topbar brand, job titles, idle marks, and large headings. `Manrope Variable` is the default UI family. `JetBrains Mono Variable` is for stream output, job ids, timelines, and eyebrow labels with uppercase tracked styling. **Exception**: the Operations terminal (xterm) uses `Cascadia Code` — a terminal-tuned face for box-drawing/Powerline glyph alignment — rendered via the xterm WebGL addon with DOM fallback. This is the sole surface where the console mono identity deliberately diverges from JetBrains Mono; the terminal font lives in the `terminal.tsx` xterm options (xterm takes a JS font string, not a CSS token), so it is not a `theme.css` variable.
89
89
  - **Surface and atmosphere**: `body::before` owns the multi-radial cold teal + brass afterglow field, and `body::after` owns the `feTurbulence` grain overlay. Sidebar, selected-job stage, timeline dock, and job summary are glass cards using `backdrop-filter: blur(18px) saturate(140%)`, `--surface-glass`, `--surface-rim`, `--shadow-soft`, and `--radius-xl`/large-radius surfaces.
90
90
  - **Motion**: panes use one first-paint `codex-rise` reveal (720ms, `--ease-spring`, topbar/sidebar/stage staggered 40/120/200ms). Live dots use aurora pulse, the stream caret keeps its blink, and ambient infinite motion is forbidden. `prefers-reduced-motion` must continue to short-circuit animation. Exception: the Operations canvas background may render a user-toggleable ambient radar sweep that defaults on and persists per browser; it remains short-circuited by `prefers-reduced-motion`. Second exception: a running Operation panel renders a continuous perimeter "wake" ripple as a functional status signal (not ambient decoration) — it appears only while work is in progress (an active carrier job, or an in-progress Agent CLI turn), its color **follows the panel beacon** (aurora for an active job, amber `--warn` for a turn in progress), and it stays short-circuited by `prefers-reduced-motion`, degrading to a static tinted rim and glow. Like the live-dot pulse, this is allowed functional status motion, not forbidden ambient motion.
package/dist/cli-bin.mjs CHANGED
@@ -21650,6 +21650,8 @@ var GLOBAL_OPTIONS_FILE_NAME = "settings.json";
21650
21650
  var LOCK_DIR_NAME = "settings.json.lock";
21651
21651
  var LOCK_OWNER_FILE_NAME = "owner";
21652
21652
  var TEMP_FILE_PREFIX = `.tmp-${GLOBAL_OPTIONS_FILE_NAME}-`;
21653
+ var MIN_CONSOLE_STATIC_PORT = 1024;
21654
+ var MAX_CONSOLE_STATIC_PORT = 65535;
21653
21655
  function createGlobalOptionsStore(deps = {}) {
21654
21656
  const dataDir = deps.dataDir ?? getFleetDataDir();
21655
21657
  const optionsPath = path92.join(dataDir, GLOBAL_OPTIONS_FILE_NAME);
@@ -21687,15 +21689,20 @@ function sanitizeGlobalOptionsData(value) {
21687
21689
  const data = {
21688
21690
  version: GLOBAL_OPTIONS_VERSION,
21689
21691
  ...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
21690
- ...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
21692
+ ...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {},
21693
+ ...value.consolePortMode === "dynamic" || value.consolePortMode === "static" ? { consolePortMode: value.consolePortMode } : {},
21694
+ ...isValidConsoleStaticPort(value.consoleStaticPort) ? { consoleStaticPort: value.consoleStaticPort } : {}
21691
21695
  };
21692
- const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
21693
- const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
21696
+ const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor", "consolePortMode", "consoleStaticPort"]);
21697
+ const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean" || "consolePortMode" in value && value.consolePortMode !== "dynamic" && value.consolePortMode !== "static" || "consoleStaticPort" in value && !isValidConsoleStaticPort(value.consoleStaticPort);
21694
21698
  return { data, changed };
21695
21699
  }
21696
21700
  function isRecord(value) {
21697
21701
  return typeof value === "object" && value !== null && !Array.isArray(value);
21698
21702
  }
21703
+ function isValidConsoleStaticPort(value) {
21704
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT && value <= MAX_CONSOLE_STATIC_PORT;
21705
+ }
21699
21706
  function createGlobalOptionsService(deps = {}) {
21700
21707
  const store2 = deps.store ?? createGlobalOptionsStore({ dataDir: deps.dataDir });
21701
21708
  return {
@@ -40736,6 +40743,8 @@ function requireCarrierConfig(registry3, carrierId) {
40736
40743
  }
40737
40744
 
40738
40745
  // src/global-settings-routes.ts
40746
+ var MIN_CONSOLE_STATIC_PORT2 = 1024;
40747
+ var MAX_CONSOLE_STATIC_PORT2 = 65535;
40739
40748
  var GLOBAL_SETTINGS_API_CATALOG = [
40740
40749
  {
40741
40750
  method: "GET",
@@ -40799,10 +40808,20 @@ async function mutateGlobalSettings(req, res, deps) {
40799
40808
  deps.writeJson(res, 400, { error: "invalid_enable_metaphor" });
40800
40809
  return;
40801
40810
  }
40811
+ if (body.consolePortMode !== void 0 && body.consolePortMode !== "dynamic" && body.consolePortMode !== "static") {
40812
+ deps.writeJson(res, 400, { error: "invalid_console_port_mode" });
40813
+ return;
40814
+ }
40815
+ if (body.consoleStaticPort !== void 0 && body.consoleStaticPort !== null && !isValidConsoleStaticPort2(body.consoleStaticPort)) {
40816
+ deps.writeJson(res, 400, { error: "invalid_console_static_port" });
40817
+ return;
40818
+ }
40802
40819
  const updated = deps.globalOptionsService.update((current) => ({
40803
40820
  ...current,
40804
40821
  ...typeof body.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: body.replaceSystemPrompt } : {},
40805
- ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {}
40822
+ ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {},
40823
+ ...body.consolePortMode === "dynamic" || body.consolePortMode === "static" ? { consolePortMode: body.consolePortMode } : {},
40824
+ ...isValidConsoleStaticPort2(body.consoleStaticPort) ? { consoleStaticPort: body.consoleStaticPort } : {}
40806
40825
  }));
40807
40826
  const response = { state: toGlobalSettingsState(updated) };
40808
40827
  deps.writeJson(res, 200, response);
@@ -40810,13 +40829,18 @@ async function mutateGlobalSettings(req, res, deps) {
40810
40829
  function toGlobalSettingsState(data) {
40811
40830
  return {
40812
40831
  replaceSystemPrompt: data.replaceSystemPrompt ?? false,
40813
- enableMetaphor: data.enableMetaphor ?? false
40832
+ enableMetaphor: data.enableMetaphor ?? false,
40833
+ consolePortMode: data.consolePortMode ?? "dynamic",
40834
+ consoleStaticPort: data.consoleStaticPort ?? null
40814
40835
  };
40815
40836
  }
40816
40837
  function isJsonRequest2(req) {
40817
40838
  const contentType = req.headers["content-type"];
40818
40839
  return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
40819
40840
  }
40841
+ function isValidConsoleStaticPort2(value) {
40842
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT2 && value <= MAX_CONSOLE_STATIC_PORT2;
40843
+ }
40820
40844
 
40821
40845
  // src/model-auth-routes.ts
40822
40846
  var MODEL_AUTH_PROVIDERS = [
@@ -44608,6 +44632,8 @@ function createConsoleUpdateCheckService(deps = {}) {
44608
44632
  // src/server.ts
44609
44633
  var DEFAULT_HOST2 = "127.0.0.1";
44610
44634
  var DEFAULT_PORT2 = 0;
44635
+ var MIN_CONSOLE_STATIC_PORT3 = 1024;
44636
+ var MAX_CONSOLE_STATIC_PORT3 = 65535;
44611
44637
  var SHELL_TERMINAL_SESSION_ID = "shell";
44612
44638
  var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
44613
44639
  var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -44778,7 +44804,7 @@ var SERVER_API_CATALOG = [
44778
44804
  ];
44779
44805
  function createConsoleServer(deps = {}) {
44780
44806
  const host = deps.host ?? DEFAULT_HOST2;
44781
- const port = deps.port ?? DEFAULT_PORT2;
44807
+ const injectedPort = deps.port ?? DEFAULT_PORT2;
44782
44808
  const release = deps.release ?? readFleetConsoleRelease();
44783
44809
  const version2 = deps.version ?? release.version;
44784
44810
  const channel = release.channel;
@@ -44818,7 +44844,7 @@ function createConsoleServer(deps = {}) {
44818
44844
  cwd: deps.codexCwd ?? process.cwd(),
44819
44845
  host,
44820
44846
  version: version2,
44821
- getPort: () => lockHandle?.payload.port ?? port,
44847
+ getPort: () => lockHandle?.payload.port ?? portState.effectivePort,
44822
44848
  getAdminToken: () => lockHandle?.payload.token ?? null
44823
44849
  });
44824
44850
  const pendingRuntimeSessions = /* @__PURE__ */ new Map();
@@ -44866,7 +44892,7 @@ function createConsoleServer(deps = {}) {
44866
44892
  });
44867
44893
  const terminalUpgrade = createTerminalUpgradeHandler({
44868
44894
  expectedHost: host,
44869
- getExpectedPort: () => lockHandle?.payload.port ?? port,
44895
+ getExpectedPort: () => lockHandle?.payload.port ?? portState.effectivePort,
44870
44896
  tickets: terminalTickets,
44871
44897
  sessions: terminalSessions,
44872
44898
  validateHost
@@ -44876,6 +44902,12 @@ function createConsoleServer(deps = {}) {
44876
44902
  let lockHandle = null;
44877
44903
  let activeLockFile = null;
44878
44904
  let activeEndpoint = null;
44905
+ let portState = {
44906
+ requestedPort: null,
44907
+ effectivePort: injectedPort,
44908
+ portMode: "dynamic",
44909
+ portHonored: true
44910
+ };
44879
44911
  let agentRuntimeStopped = false;
44880
44912
  let consoleResourcesDisposed = false;
44881
44913
  let updateApplyInFlight = false;
@@ -44909,7 +44941,7 @@ function createConsoleServer(deps = {}) {
44909
44941
  runAsyncBooleanHandler(codex.handle(req, res), res, () => tryServeStaticConsole(req, res, pathname));
44910
44942
  return;
44911
44943
  }
44912
- if (!validateHost(req, lockHandle?.payload.port ?? port)) {
44944
+ if (!validateHost(req, lockHandle?.payload.port ?? portState.effectivePort)) {
44913
44945
  writeJson(res, 403, { error: "host_mismatch" });
44914
44946
  return;
44915
44947
  }
@@ -45036,7 +45068,11 @@ function createConsoleServer(deps = {}) {
45036
45068
  endpoint: payload.endpoint,
45037
45069
  startedAt: payload.startedAt,
45038
45070
  version: payload.version,
45039
- workspaceCount: observability.workspaceCount()
45071
+ workspaceCount: observability.workspaceCount(),
45072
+ portMode: portState.portMode,
45073
+ requestedPort: portState.requestedPort,
45074
+ effectivePort: portState.effectivePort,
45075
+ portHonored: portState.portHonored
45040
45076
  };
45041
45077
  writeJson(res, 200, body);
45042
45078
  }
@@ -45439,7 +45475,11 @@ function createConsoleServer(deps = {}) {
45439
45475
  version: version2,
45440
45476
  channel,
45441
45477
  ...updateCheck.getStatus(),
45442
- port: lockHandle?.payload.port ?? port,
45478
+ port: lockHandle?.payload.port ?? portState.effectivePort,
45479
+ portMode: portState.portMode,
45480
+ requestedPort: portState.requestedPort,
45481
+ effectivePort: portState.effectivePort,
45482
+ portHonored: portState.portHonored,
45443
45483
  wikiServerStatus: resolveWikiServerStatus(theaterId)
45444
45484
  };
45445
45485
  writeJson(res, 200, payload);
@@ -45562,11 +45602,11 @@ function createConsoleServer(deps = {}) {
45562
45602
  }
45563
45603
  function isTerminalAuthorized(req) {
45564
45604
  if (!lockHandle) return false;
45565
- return isAllowedTerminalOrigin(req, lockHandle.payload.port ?? port);
45605
+ return isAllowedTerminalOrigin(req, lockHandle.payload.port ?? portState.effectivePort);
45566
45606
  }
45567
45607
  function isExactConsoleOrigin(req) {
45568
45608
  if (!lockHandle) return false;
45569
- return req.headers.origin === `http://127.0.0.1:${lockHandle.payload.port ?? port}`;
45609
+ return req.headers.origin === `http://127.0.0.1:${lockHandle.payload.port ?? portState.effectivePort}`;
45570
45610
  }
45571
45611
  function listVisibleWorkspaces(requestedTenantId) {
45572
45612
  if (requestedTenantId) {
@@ -45740,36 +45780,19 @@ function createConsoleServer(deps = {}) {
45740
45780
  }
45741
45781
  const returnedServer = {
45742
45782
  host,
45743
- port,
45783
+ port: injectedPort,
45744
45784
  async start(lockPaths) {
45745
45785
  if (server && lockHandle) return lockHandle.payload.endpoint;
45746
45786
  try {
45747
45787
  await rehydrateDurableState();
45748
- await new Promise((resolve, reject) => {
45749
- const srv = createHttpServer(handleRequest, terminalUpgrade);
45750
- srv.once("error", reject);
45751
- srv.listen(port, host, async () => {
45752
- srv.off("error", reject);
45753
- const address = srv.address();
45754
- const actualPort = typeof address === "object" && address ? address.port : port;
45755
- const endpoint = `http://${host}:${actualPort}/`;
45756
- try {
45757
- const localLoopbackServer = await maybeStartLoopbackServer(host, actualPort, handleRequest, terminalUpgrade);
45758
- server = srv;
45759
- loopbackServer = localLoopbackServer;
45760
- lockHandle = lock.writeLock({ dir: lockPaths.dir, lockFile: lockPaths.lockFile, pid: process.pid, port: actualPort, endpoint, version: version2 });
45761
- activeLockFile = lockPaths.lockFile;
45762
- activeEndpoint = endpoint;
45763
- resolve();
45764
- } catch (err) {
45765
- await closeHttpServer(srv);
45766
- await closeHttpServer(loopbackServer);
45767
- server = null;
45768
- loopbackServer = null;
45769
- reject(err);
45770
- }
45771
- });
45772
- });
45788
+ const listenPlan = resolveConsolePortListenPlan();
45789
+ const result = await listenConsolePort(listenPlan);
45790
+ server = result.srv;
45791
+ loopbackServer = result.localLoopbackServer;
45792
+ portState = result.portState;
45793
+ lockHandle = lock.writeLock({ dir: lockPaths.dir, lockFile: lockPaths.lockFile, pid: process.pid, port: result.actualPort, endpoint: result.endpoint, version: version2 });
45794
+ activeLockFile = lockPaths.lockFile;
45795
+ activeEndpoint = result.endpoint;
45773
45796
  } catch (error51) {
45774
45797
  await cleanupAfterFailedStart();
45775
45798
  throw error51;
@@ -45782,6 +45805,78 @@ function createConsoleServer(deps = {}) {
45782
45805
  await stopServer();
45783
45806
  }
45784
45807
  };
45808
+ function resolveConsolePortListenPlan() {
45809
+ if (deps.port !== void 0) {
45810
+ return {
45811
+ port: injectedPort,
45812
+ requestedPort: null,
45813
+ portMode: "dynamic",
45814
+ allowFallback: false
45815
+ };
45816
+ }
45817
+ const options = infraServices.globalOptionsService.load();
45818
+ if (options.consolePortMode === "static" && isValidConsoleStaticPort3(options.consoleStaticPort)) {
45819
+ return {
45820
+ port: options.consoleStaticPort,
45821
+ requestedPort: options.consoleStaticPort,
45822
+ portMode: "static",
45823
+ allowFallback: true
45824
+ };
45825
+ }
45826
+ return {
45827
+ port: DEFAULT_PORT2,
45828
+ requestedPort: null,
45829
+ portMode: "dynamic",
45830
+ allowFallback: false
45831
+ };
45832
+ }
45833
+ async function listenConsolePort(plan) {
45834
+ try {
45835
+ return await listenOnce(plan.port, {
45836
+ requestedPort: plan.requestedPort,
45837
+ portMode: plan.portMode,
45838
+ portHonored: true
45839
+ });
45840
+ } catch (error51) {
45841
+ if (!plan.allowFallback || plan.requestedPort === null) throw error51;
45842
+ return listenOnce(DEFAULT_PORT2, {
45843
+ requestedPort: plan.requestedPort,
45844
+ portMode: "static",
45845
+ portHonored: false
45846
+ });
45847
+ }
45848
+ }
45849
+ function listenOnce(portToBind, statePatch) {
45850
+ return new Promise((resolve, reject) => {
45851
+ const srv = createHttpServer(handleRequest, terminalUpgrade);
45852
+ const onError = (error51) => {
45853
+ reject(error51);
45854
+ };
45855
+ srv.once("error", onError);
45856
+ srv.listen(portToBind, host, async () => {
45857
+ srv.off("error", onError);
45858
+ const address = srv.address();
45859
+ const actualPort = typeof address === "object" && address ? address.port : portToBind;
45860
+ const endpoint = `http://${host}:${actualPort}/`;
45861
+ try {
45862
+ const localLoopbackServer = await maybeStartLoopbackServer(host, actualPort, handleRequest, terminalUpgrade);
45863
+ resolve({
45864
+ srv,
45865
+ localLoopbackServer,
45866
+ actualPort,
45867
+ endpoint,
45868
+ portState: {
45869
+ ...statePatch,
45870
+ effectivePort: actualPort
45871
+ }
45872
+ });
45873
+ } catch (err) {
45874
+ await closeHttpServer(srv);
45875
+ reject(err);
45876
+ }
45877
+ });
45878
+ });
45879
+ }
45785
45880
  return returnedServer;
45786
45881
  }
45787
45882
  function resolveCarrierEventOrigin(event, jobOriginById) {
@@ -45934,6 +46029,9 @@ function validateHost(req, expectedPort) {
45934
46029
  if (!hostHeader) return false;
45935
46030
  return hostHeader === `127.0.0.1:${expectedPort}`;
45936
46031
  }
46032
+ function isValidConsoleStaticPort3(value) {
46033
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT3 && value <= MAX_CONSOLE_STATIC_PORT3;
46034
+ }
45937
46035
  function isAllowedTerminalOrigin(req, expectedPort) {
45938
46036
  const origin = req.headers.origin;
45939
46037
  if (origin === void 0) return true;
package/dist/cli.d.ts CHANGED
@@ -12,6 +12,10 @@ interface ConsoleHealth {
12
12
  readonly pid: number;
13
13
  readonly host: string;
14
14
  readonly port: number;
15
+ readonly portMode: "dynamic" | "static";
16
+ readonly requestedPort: number | null;
17
+ readonly effectivePort: number;
18
+ readonly portHonored: boolean;
15
19
  readonly endpoint: string;
16
20
  readonly startedAt: number;
17
21
  readonly version: string;
package/dist/cli.mjs CHANGED
@@ -21650,6 +21650,8 @@ var GLOBAL_OPTIONS_FILE_NAME = "settings.json";
21650
21650
  var LOCK_DIR_NAME = "settings.json.lock";
21651
21651
  var LOCK_OWNER_FILE_NAME = "owner";
21652
21652
  var TEMP_FILE_PREFIX = `.tmp-${GLOBAL_OPTIONS_FILE_NAME}-`;
21653
+ var MIN_CONSOLE_STATIC_PORT = 1024;
21654
+ var MAX_CONSOLE_STATIC_PORT = 65535;
21653
21655
  function createGlobalOptionsStore(deps = {}) {
21654
21656
  const dataDir = deps.dataDir ?? getFleetDataDir();
21655
21657
  const optionsPath = path92.join(dataDir, GLOBAL_OPTIONS_FILE_NAME);
@@ -21687,15 +21689,20 @@ function sanitizeGlobalOptionsData(value) {
21687
21689
  const data = {
21688
21690
  version: GLOBAL_OPTIONS_VERSION,
21689
21691
  ...typeof value.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: value.replaceSystemPrompt } : {},
21690
- ...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {}
21692
+ ...typeof value.enableMetaphor === "boolean" ? { enableMetaphor: value.enableMetaphor } : {},
21693
+ ...value.consolePortMode === "dynamic" || value.consolePortMode === "static" ? { consolePortMode: value.consolePortMode } : {},
21694
+ ...isValidConsoleStaticPort(value.consoleStaticPort) ? { consoleStaticPort: value.consoleStaticPort } : {}
21691
21695
  };
21692
- const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor"]);
21693
- const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean";
21696
+ const allowedKeys = /* @__PURE__ */ new Set(["version", "replaceSystemPrompt", "enableMetaphor", "consolePortMode", "consoleStaticPort"]);
21697
+ const changed = Object.keys(value).some((key) => !allowedKeys.has(key)) || "replaceSystemPrompt" in value && typeof value.replaceSystemPrompt !== "boolean" || "enableMetaphor" in value && typeof value.enableMetaphor !== "boolean" || "consolePortMode" in value && value.consolePortMode !== "dynamic" && value.consolePortMode !== "static" || "consoleStaticPort" in value && !isValidConsoleStaticPort(value.consoleStaticPort);
21694
21698
  return { data, changed };
21695
21699
  }
21696
21700
  function isRecord(value) {
21697
21701
  return typeof value === "object" && value !== null && !Array.isArray(value);
21698
21702
  }
21703
+ function isValidConsoleStaticPort(value) {
21704
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT && value <= MAX_CONSOLE_STATIC_PORT;
21705
+ }
21699
21706
  function createGlobalOptionsService(deps = {}) {
21700
21707
  const store2 = deps.store ?? createGlobalOptionsStore({ dataDir: deps.dataDir });
21701
21708
  return {
@@ -40736,6 +40743,8 @@ function requireCarrierConfig(registry3, carrierId) {
40736
40743
  }
40737
40744
 
40738
40745
  // src/global-settings-routes.ts
40746
+ var MIN_CONSOLE_STATIC_PORT2 = 1024;
40747
+ var MAX_CONSOLE_STATIC_PORT2 = 65535;
40739
40748
  var GLOBAL_SETTINGS_API_CATALOG = [
40740
40749
  {
40741
40750
  method: "GET",
@@ -40799,10 +40808,20 @@ async function mutateGlobalSettings(req, res, deps) {
40799
40808
  deps.writeJson(res, 400, { error: "invalid_enable_metaphor" });
40800
40809
  return;
40801
40810
  }
40811
+ if (body.consolePortMode !== void 0 && body.consolePortMode !== "dynamic" && body.consolePortMode !== "static") {
40812
+ deps.writeJson(res, 400, { error: "invalid_console_port_mode" });
40813
+ return;
40814
+ }
40815
+ if (body.consoleStaticPort !== void 0 && body.consoleStaticPort !== null && !isValidConsoleStaticPort2(body.consoleStaticPort)) {
40816
+ deps.writeJson(res, 400, { error: "invalid_console_static_port" });
40817
+ return;
40818
+ }
40802
40819
  const updated = deps.globalOptionsService.update((current) => ({
40803
40820
  ...current,
40804
40821
  ...typeof body.replaceSystemPrompt === "boolean" ? { replaceSystemPrompt: body.replaceSystemPrompt } : {},
40805
- ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {}
40822
+ ...typeof body.enableMetaphor === "boolean" ? { enableMetaphor: body.enableMetaphor } : {},
40823
+ ...body.consolePortMode === "dynamic" || body.consolePortMode === "static" ? { consolePortMode: body.consolePortMode } : {},
40824
+ ...isValidConsoleStaticPort2(body.consoleStaticPort) ? { consoleStaticPort: body.consoleStaticPort } : {}
40806
40825
  }));
40807
40826
  const response = { state: toGlobalSettingsState(updated) };
40808
40827
  deps.writeJson(res, 200, response);
@@ -40810,13 +40829,18 @@ async function mutateGlobalSettings(req, res, deps) {
40810
40829
  function toGlobalSettingsState(data) {
40811
40830
  return {
40812
40831
  replaceSystemPrompt: data.replaceSystemPrompt ?? false,
40813
- enableMetaphor: data.enableMetaphor ?? false
40832
+ enableMetaphor: data.enableMetaphor ?? false,
40833
+ consolePortMode: data.consolePortMode ?? "dynamic",
40834
+ consoleStaticPort: data.consoleStaticPort ?? null
40814
40835
  };
40815
40836
  }
40816
40837
  function isJsonRequest2(req) {
40817
40838
  const contentType = req.headers["content-type"];
40818
40839
  return typeof contentType === "string" && contentType.toLowerCase().split(";")[0]?.trim() === "application/json";
40819
40840
  }
40841
+ function isValidConsoleStaticPort2(value) {
40842
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT2 && value <= MAX_CONSOLE_STATIC_PORT2;
40843
+ }
40820
40844
 
40821
40845
  // src/model-auth-routes.ts
40822
40846
  var MODEL_AUTH_PROVIDERS = [
@@ -44608,6 +44632,8 @@ function createConsoleUpdateCheckService(deps = {}) {
44608
44632
  // src/server.ts
44609
44633
  var DEFAULT_HOST2 = "127.0.0.1";
44610
44634
  var DEFAULT_PORT2 = 0;
44635
+ var MIN_CONSOLE_STATIC_PORT3 = 1024;
44636
+ var MAX_CONSOLE_STATIC_PORT3 = 65535;
44611
44637
  var SHELL_TERMINAL_SESSION_ID = "shell";
44612
44638
  var THEATER_SHELL_SESSION_PREFIX2 = "shell:";
44613
44639
  var SERVER_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -44778,7 +44804,7 @@ var SERVER_API_CATALOG = [
44778
44804
  ];
44779
44805
  function createConsoleServer(deps = {}) {
44780
44806
  const host = deps.host ?? DEFAULT_HOST2;
44781
- const port = deps.port ?? DEFAULT_PORT2;
44807
+ const injectedPort = deps.port ?? DEFAULT_PORT2;
44782
44808
  const release = deps.release ?? readFleetConsoleRelease();
44783
44809
  const version2 = deps.version ?? release.version;
44784
44810
  const channel = release.channel;
@@ -44818,7 +44844,7 @@ function createConsoleServer(deps = {}) {
44818
44844
  cwd: deps.codexCwd ?? process.cwd(),
44819
44845
  host,
44820
44846
  version: version2,
44821
- getPort: () => lockHandle?.payload.port ?? port,
44847
+ getPort: () => lockHandle?.payload.port ?? portState.effectivePort,
44822
44848
  getAdminToken: () => lockHandle?.payload.token ?? null
44823
44849
  });
44824
44850
  const pendingRuntimeSessions = /* @__PURE__ */ new Map();
@@ -44866,7 +44892,7 @@ function createConsoleServer(deps = {}) {
44866
44892
  });
44867
44893
  const terminalUpgrade = createTerminalUpgradeHandler({
44868
44894
  expectedHost: host,
44869
- getExpectedPort: () => lockHandle?.payload.port ?? port,
44895
+ getExpectedPort: () => lockHandle?.payload.port ?? portState.effectivePort,
44870
44896
  tickets: terminalTickets,
44871
44897
  sessions: terminalSessions,
44872
44898
  validateHost
@@ -44876,6 +44902,12 @@ function createConsoleServer(deps = {}) {
44876
44902
  let lockHandle = null;
44877
44903
  let activeLockFile = null;
44878
44904
  let activeEndpoint = null;
44905
+ let portState = {
44906
+ requestedPort: null,
44907
+ effectivePort: injectedPort,
44908
+ portMode: "dynamic",
44909
+ portHonored: true
44910
+ };
44879
44911
  let agentRuntimeStopped = false;
44880
44912
  let consoleResourcesDisposed = false;
44881
44913
  let updateApplyInFlight = false;
@@ -44909,7 +44941,7 @@ function createConsoleServer(deps = {}) {
44909
44941
  runAsyncBooleanHandler(codex.handle(req, res), res, () => tryServeStaticConsole(req, res, pathname));
44910
44942
  return;
44911
44943
  }
44912
- if (!validateHost(req, lockHandle?.payload.port ?? port)) {
44944
+ if (!validateHost(req, lockHandle?.payload.port ?? portState.effectivePort)) {
44913
44945
  writeJson(res, 403, { error: "host_mismatch" });
44914
44946
  return;
44915
44947
  }
@@ -45036,7 +45068,11 @@ function createConsoleServer(deps = {}) {
45036
45068
  endpoint: payload.endpoint,
45037
45069
  startedAt: payload.startedAt,
45038
45070
  version: payload.version,
45039
- workspaceCount: observability.workspaceCount()
45071
+ workspaceCount: observability.workspaceCount(),
45072
+ portMode: portState.portMode,
45073
+ requestedPort: portState.requestedPort,
45074
+ effectivePort: portState.effectivePort,
45075
+ portHonored: portState.portHonored
45040
45076
  };
45041
45077
  writeJson(res, 200, body);
45042
45078
  }
@@ -45439,7 +45475,11 @@ function createConsoleServer(deps = {}) {
45439
45475
  version: version2,
45440
45476
  channel,
45441
45477
  ...updateCheck.getStatus(),
45442
- port: lockHandle?.payload.port ?? port,
45478
+ port: lockHandle?.payload.port ?? portState.effectivePort,
45479
+ portMode: portState.portMode,
45480
+ requestedPort: portState.requestedPort,
45481
+ effectivePort: portState.effectivePort,
45482
+ portHonored: portState.portHonored,
45443
45483
  wikiServerStatus: resolveWikiServerStatus(theaterId)
45444
45484
  };
45445
45485
  writeJson(res, 200, payload);
@@ -45562,11 +45602,11 @@ function createConsoleServer(deps = {}) {
45562
45602
  }
45563
45603
  function isTerminalAuthorized(req) {
45564
45604
  if (!lockHandle) return false;
45565
- return isAllowedTerminalOrigin(req, lockHandle.payload.port ?? port);
45605
+ return isAllowedTerminalOrigin(req, lockHandle.payload.port ?? portState.effectivePort);
45566
45606
  }
45567
45607
  function isExactConsoleOrigin(req) {
45568
45608
  if (!lockHandle) return false;
45569
- return req.headers.origin === `http://127.0.0.1:${lockHandle.payload.port ?? port}`;
45609
+ return req.headers.origin === `http://127.0.0.1:${lockHandle.payload.port ?? portState.effectivePort}`;
45570
45610
  }
45571
45611
  function listVisibleWorkspaces(requestedTenantId) {
45572
45612
  if (requestedTenantId) {
@@ -45740,36 +45780,19 @@ function createConsoleServer(deps = {}) {
45740
45780
  }
45741
45781
  const returnedServer = {
45742
45782
  host,
45743
- port,
45783
+ port: injectedPort,
45744
45784
  async start(lockPaths) {
45745
45785
  if (server && lockHandle) return lockHandle.payload.endpoint;
45746
45786
  try {
45747
45787
  await rehydrateDurableState();
45748
- await new Promise((resolve, reject) => {
45749
- const srv = createHttpServer(handleRequest, terminalUpgrade);
45750
- srv.once("error", reject);
45751
- srv.listen(port, host, async () => {
45752
- srv.off("error", reject);
45753
- const address = srv.address();
45754
- const actualPort = typeof address === "object" && address ? address.port : port;
45755
- const endpoint = `http://${host}:${actualPort}/`;
45756
- try {
45757
- const localLoopbackServer = await maybeStartLoopbackServer(host, actualPort, handleRequest, terminalUpgrade);
45758
- server = srv;
45759
- loopbackServer = localLoopbackServer;
45760
- lockHandle = lock.writeLock({ dir: lockPaths.dir, lockFile: lockPaths.lockFile, pid: process.pid, port: actualPort, endpoint, version: version2 });
45761
- activeLockFile = lockPaths.lockFile;
45762
- activeEndpoint = endpoint;
45763
- resolve();
45764
- } catch (err) {
45765
- await closeHttpServer(srv);
45766
- await closeHttpServer(loopbackServer);
45767
- server = null;
45768
- loopbackServer = null;
45769
- reject(err);
45770
- }
45771
- });
45772
- });
45788
+ const listenPlan = resolveConsolePortListenPlan();
45789
+ const result = await listenConsolePort(listenPlan);
45790
+ server = result.srv;
45791
+ loopbackServer = result.localLoopbackServer;
45792
+ portState = result.portState;
45793
+ lockHandle = lock.writeLock({ dir: lockPaths.dir, lockFile: lockPaths.lockFile, pid: process.pid, port: result.actualPort, endpoint: result.endpoint, version: version2 });
45794
+ activeLockFile = lockPaths.lockFile;
45795
+ activeEndpoint = result.endpoint;
45773
45796
  } catch (error51) {
45774
45797
  await cleanupAfterFailedStart();
45775
45798
  throw error51;
@@ -45782,6 +45805,78 @@ function createConsoleServer(deps = {}) {
45782
45805
  await stopServer();
45783
45806
  }
45784
45807
  };
45808
+ function resolveConsolePortListenPlan() {
45809
+ if (deps.port !== void 0) {
45810
+ return {
45811
+ port: injectedPort,
45812
+ requestedPort: null,
45813
+ portMode: "dynamic",
45814
+ allowFallback: false
45815
+ };
45816
+ }
45817
+ const options = infraServices.globalOptionsService.load();
45818
+ if (options.consolePortMode === "static" && isValidConsoleStaticPort3(options.consoleStaticPort)) {
45819
+ return {
45820
+ port: options.consoleStaticPort,
45821
+ requestedPort: options.consoleStaticPort,
45822
+ portMode: "static",
45823
+ allowFallback: true
45824
+ };
45825
+ }
45826
+ return {
45827
+ port: DEFAULT_PORT2,
45828
+ requestedPort: null,
45829
+ portMode: "dynamic",
45830
+ allowFallback: false
45831
+ };
45832
+ }
45833
+ async function listenConsolePort(plan) {
45834
+ try {
45835
+ return await listenOnce(plan.port, {
45836
+ requestedPort: plan.requestedPort,
45837
+ portMode: plan.portMode,
45838
+ portHonored: true
45839
+ });
45840
+ } catch (error51) {
45841
+ if (!plan.allowFallback || plan.requestedPort === null) throw error51;
45842
+ return listenOnce(DEFAULT_PORT2, {
45843
+ requestedPort: plan.requestedPort,
45844
+ portMode: "static",
45845
+ portHonored: false
45846
+ });
45847
+ }
45848
+ }
45849
+ function listenOnce(portToBind, statePatch) {
45850
+ return new Promise((resolve, reject) => {
45851
+ const srv = createHttpServer(handleRequest, terminalUpgrade);
45852
+ const onError = (error51) => {
45853
+ reject(error51);
45854
+ };
45855
+ srv.once("error", onError);
45856
+ srv.listen(portToBind, host, async () => {
45857
+ srv.off("error", onError);
45858
+ const address = srv.address();
45859
+ const actualPort = typeof address === "object" && address ? address.port : portToBind;
45860
+ const endpoint = `http://${host}:${actualPort}/`;
45861
+ try {
45862
+ const localLoopbackServer = await maybeStartLoopbackServer(host, actualPort, handleRequest, terminalUpgrade);
45863
+ resolve({
45864
+ srv,
45865
+ localLoopbackServer,
45866
+ actualPort,
45867
+ endpoint,
45868
+ portState: {
45869
+ ...statePatch,
45870
+ effectivePort: actualPort
45871
+ }
45872
+ });
45873
+ } catch (err) {
45874
+ await closeHttpServer(srv);
45875
+ reject(err);
45876
+ }
45877
+ });
45878
+ });
45879
+ }
45785
45880
  return returnedServer;
45786
45881
  }
45787
45882
  function resolveCarrierEventOrigin(event, jobOriginById) {
@@ -45934,6 +46029,9 @@ function validateHost(req, expectedPort) {
45934
46029
  if (!hostHeader) return false;
45935
46030
  return hostHeader === `127.0.0.1:${expectedPort}`;
45936
46031
  }
46032
+ function isValidConsoleStaticPort3(value) {
46033
+ return typeof value === "number" && Number.isInteger(value) && value >= MIN_CONSOLE_STATIC_PORT3 && value <= MAX_CONSOLE_STATIC_PORT3;
46034
+ }
45937
46035
  function isAllowedTerminalOrigin(req, expectedPort) {
45938
46036
  const origin = req.headers.origin;
45939
46037
  if (origin === void 0) return true;