@openscout/scout 0.2.69 → 0.2.72

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.
@@ -15,6 +15,7 @@ import { fileURLToPath } from "url";
15
15
 
16
16
  // packages/runtime/src/broker-api.ts
17
17
  import { request as httpRequest } from "http";
18
+ var DEFAULT_BROKER_JSON_REQUEST_TIMEOUT_MS = 30000;
18
19
  function normalizeBaseUrl(baseUrl) {
19
20
  const trimmed = baseUrl.trim();
20
21
  if (!trimmed) {
@@ -115,12 +116,19 @@ function requestBrokerOverUnixSocket(socketPath, baseUrl, path, options) {
115
116
  request.end();
116
117
  });
117
118
  }
119
+ function defaultBrokerRequestSignal(options) {
120
+ return options.signal ?? AbortSignal.timeout(DEFAULT_BROKER_JSON_REQUEST_TIMEOUT_MS);
121
+ }
118
122
  async function requestBrokerWire(baseUrl, path, options) {
123
+ const requestOptions = {
124
+ ...options,
125
+ signal: defaultBrokerRequestSignal(options)
126
+ };
119
127
  const socketPath = options.socketPath?.trim();
120
128
  if (socketPath) {
121
129
  try {
122
130
  return {
123
- response: await requestBrokerOverUnixSocket(socketPath, baseUrl, path, options),
131
+ response: await requestBrokerOverUnixSocket(socketPath, baseUrl, path, requestOptions),
124
132
  trace: {
125
133
  transport: "unix_socket",
126
134
  socketPath
@@ -131,7 +139,7 @@ async function requestBrokerWire(baseUrl, path, options) {
131
139
  throw error;
132
140
  }
133
141
  return {
134
- response: await requestBrokerOverHttp(baseUrl, path, options),
142
+ response: await requestBrokerOverHttp(baseUrl, path, requestOptions),
135
143
  trace: {
136
144
  transport: "http",
137
145
  socketPath,
@@ -141,7 +149,7 @@ async function requestBrokerWire(baseUrl, path, options) {
141
149
  }
142
150
  }
143
151
  return {
144
- response: await requestBrokerOverHttp(baseUrl, path, options),
152
+ response: await requestBrokerOverHttp(baseUrl, path, requestOptions),
145
153
  trace: {
146
154
  transport: "http"
147
155
  }
@@ -182,6 +190,8 @@ function resolveOpenScoutSupportPaths() {
182
190
  const logsDirectory = join(supportDirectory, "logs");
183
191
  const runtimeDirectory = join(supportDirectory, "runtime");
184
192
  const catalogDirectory = join(supportDirectory, "catalog");
193
+ const controlHome = process.env.OPENSCOUT_CONTROL_HOME ?? join(home, ".openscout", "control-plane");
194
+ const knowledgeDirectory = join(controlHome, "knowledge");
185
195
  return {
186
196
  supportDirectory,
187
197
  logsDirectory,
@@ -193,8 +203,12 @@ function resolveOpenScoutSupportPaths() {
193
203
  settingsPath: join(supportDirectory, "settings.json"),
194
204
  harnessCatalogPath: join(catalogDirectory, "harness-catalog.json"),
195
205
  relayAgentsRegistryPath: join(supportDirectory, "relay-agents.json"),
206
+ managedInstallsPath: join(supportDirectory, "managed-installs.json"),
196
207
  relayHubDirectory: process.env.OPENSCOUT_RELAY_HUB ?? join(home, ".openscout", "relay"),
197
- controlHome: process.env.OPENSCOUT_CONTROL_HOME ?? join(home, ".openscout", "control-plane"),
208
+ controlHome,
209
+ knowledgeDirectory,
210
+ knowledgeQmdDirectory: join(knowledgeDirectory, "qmd"),
211
+ knowledgeSqlitePath: join(knowledgeDirectory, "knowledge.sqlite"),
198
212
  desktopStatusPath: join(supportDirectory, "agent-status.json"),
199
213
  workspaceStatePath: join(supportDirectory, "workspace-state.json"),
200
214
  cutoverMarkerPath: join(supportDirectory, OPENSCOUT_RPC_CUTOVER_MARKER)
@@ -342,6 +356,7 @@ function resolveBrokerHost(scope = resolveAdvertiseScope()) {
342
356
  }
343
357
  var BROKER_SERVICE_POLL_INTERVAL_MS = 100;
344
358
  var DEFAULT_BROKER_START_TIMEOUT_MS = 15000;
359
+ var DEFAULT_BROKER_STOP_TIMEOUT_MS = 20000;
345
360
  function buildDefaultBrokerUrl(host = DEFAULT_BROKER_HOST, port = DEFAULT_BROKER_PORT) {
346
361
  return `http://${host}:${port}`;
347
362
  }
@@ -437,6 +452,13 @@ function resolveBrokerStartTimeoutMs() {
437
452
  }
438
453
  return DEFAULT_BROKER_START_TIMEOUT_MS;
439
454
  }
455
+ function resolveBrokerStopTimeoutMs() {
456
+ const explicit = Number.parseInt(process.env.OPENSCOUT_BROKER_STOP_TIMEOUT_MS ?? "", 10);
457
+ if (Number.isFinite(explicit) && explicit > 0) {
458
+ return Math.max(explicit, BROKER_SERVICE_POLL_INTERVAL_MS);
459
+ }
460
+ return DEFAULT_BROKER_STOP_TIMEOUT_MS;
461
+ }
440
462
  function resolveBrokerServiceLabel(mode) {
441
463
  const explicit = process.env.OPENSCOUT_SERVICE_LABEL?.trim() || process.env.OPENSCOUT_BROKER_SERVICE_LABEL?.trim();
442
464
  if (explicit) {
@@ -526,7 +548,18 @@ function renderLaunchAgentPlist(config) {
526
548
  "OPENSCOUT_NODE_QUALIFIER",
527
549
  "OPENSCOUT_TAILSCALE_BIN",
528
550
  "OPENSCOUT_TAILSCALE_STATUS_JSON",
529
- "OPENSCOUT_SSE_KEEPALIVE_MS"
551
+ "OPENSCOUT_SSE_KEEPALIVE_MS",
552
+ "OPENSCOUT_WEB_EDGE_SCHEME",
553
+ "OPENSCOUT_WEB_PUBLIC_ORIGIN",
554
+ "OPENSCOUT_WEB_PORTAL_HOST",
555
+ "OPENSCOUT_WEB_LOCAL_NAME",
556
+ "OPENSCOUT_WEB_ADVERTISED_HOST",
557
+ "OPENSCOUT_WEB_TRUSTED_HOSTS",
558
+ "OPENSCOUT_WEB_TRUSTED_ORIGINS",
559
+ "OPENSCOUT_WEB_PORT",
560
+ "OPENSCOUT_WEB_FLAG_BUNDLE",
561
+ "OPENSCOUT_WEB_EXPERIENCE",
562
+ "OPENSCOUT_WEB_AB_VARIANT"
530
563
  ])
531
564
  };
532
565
  if (coreAgentsValue) {
@@ -809,6 +842,7 @@ async function startBrokerService(config = resolveBrokerServiceConfig()) {
809
842
  bootoutLegacyBrokerService(config);
810
843
  writeLaunchAgentPlist(config);
811
844
  runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
845
+ await waitForBrokerServiceStopped(config);
812
846
  runCommand(launchctlPath(), ["bootstrap", config.domainTarget, config.launchAgentPath], { allowFailure: true });
813
847
  runCommand(launchctlPath(), ["kickstart", "-k", config.serviceTarget], { allowFailure: true });
814
848
  const attempts = Math.ceil(resolveBrokerStartTimeoutMs() / BROKER_SERVICE_POLL_INTERVAL_MS);
@@ -825,16 +859,21 @@ async function startBrokerService(config = resolveBrokerServiceConfig()) {
825
859
  function sleep(ms) {
826
860
  return new Promise((resolve3) => setTimeout(resolve3, ms));
827
861
  }
828
- async function stopBrokerService(config = resolveBrokerServiceConfig()) {
829
- runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
830
- for (let attempt = 0;attempt < 30; attempt += 1) {
831
- const status = await brokerServiceStatus(config);
832
- if (!status.health.reachable) {
862
+ async function waitForBrokerServiceStopped(config) {
863
+ let status = await brokerServiceStatus(config);
864
+ const attempts = Math.ceil(resolveBrokerStopTimeoutMs() / BROKER_SERVICE_POLL_INTERVAL_MS);
865
+ for (let attempt = 0;attempt < attempts; attempt += 1) {
866
+ status = await brokerServiceStatus(config);
867
+ if (!status.loaded && !status.health.reachable) {
833
868
  return status;
834
869
  }
835
870
  await sleep(BROKER_SERVICE_POLL_INTERVAL_MS);
836
871
  }
837
- return brokerServiceStatus(config);
872
+ return status;
873
+ }
874
+ async function stopBrokerService(config = resolveBrokerServiceConfig()) {
875
+ runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
876
+ return waitForBrokerServiceStopped(config);
838
877
  }
839
878
  async function restartBrokerService(config = resolveBrokerServiceConfig()) {
840
879
  await stopBrokerService(config);
@@ -1282,6 +1321,7 @@ var RESTART_MIN_DELAY_MS = 1000;
1282
1321
  var RESTART_MAX_DELAY_MS = 30000;
1283
1322
  var BROKER_HEALTH_TIMEOUT_MS = 30000;
1284
1323
  var BROKER_HEALTH_POLL_MS = 250;
1324
+ var CHILD_SHUTDOWN_TIMEOUT_MS = 12000;
1285
1325
  var MENU_BUNDLE_ID = "com.openscout.menu";
1286
1326
  var MENU_PROCESS_NAME = "OpenScoutMenu";
1287
1327
  var PROCESS_NAME = "scout-base";
@@ -1395,6 +1435,9 @@ function resolveEdgeScheme() {
1395
1435
  }
1396
1436
  return "http";
1397
1437
  }
1438
+ function forwardedProtoForEdgeScheme(scheme) {
1439
+ return scheme === "http" ? "http" : "https";
1440
+ }
1398
1441
  function resolveEdgeConfig() {
1399
1442
  const portalHost = process.env.OPENSCOUT_WEB_PORTAL_HOST?.trim() || DEFAULT_SCOUT_WEB_PORTAL_HOST;
1400
1443
  const nodeHost = process.env.OPENSCOUT_WEB_ADVERTISED_HOST?.trim() || (process.env.OPENSCOUT_WEB_LOCAL_NAME?.trim() ? resolveScoutWebNamedHostname(process.env.OPENSCOUT_WEB_LOCAL_NAME) : resolveConfiguredScoutWebHostname());
@@ -1519,7 +1562,7 @@ async function startWebWhenBrokerIsReady() {
1519
1562
  }
1520
1563
  try {
1521
1564
  const edgeConfig = resolveEdgeConfig();
1522
- const scheme = edgeConfig.scheme === "https" ? "https" : "http";
1565
+ const scheme = forwardedProtoForEdgeScheme(edgeConfig.scheme);
1523
1566
  const response = await fetch(new URL("/v1/web/start", config.brokerUrl), {
1524
1567
  method: "POST",
1525
1568
  headers: {
@@ -1588,6 +1631,44 @@ function stopMenuBarApp() {
1588
1631
  }
1589
1632
  spawn("pkill", ["-x", MENU_PROCESS_NAME], { stdio: "ignore" }).unref();
1590
1633
  }
1634
+ function isChildExited(child) {
1635
+ return child.exitCode !== null || child.signalCode !== null;
1636
+ }
1637
+ function waitForChildExit(child, timeoutMs) {
1638
+ if (isChildExited(child)) {
1639
+ return Promise.resolve(true);
1640
+ }
1641
+ return new Promise((resolve4) => {
1642
+ const timeout = setTimeout(() => {
1643
+ child.off("exit", onExit);
1644
+ resolve4(false);
1645
+ }, timeoutMs);
1646
+ timeout.unref();
1647
+ const onExit = () => {
1648
+ clearTimeout(timeout);
1649
+ resolve4(true);
1650
+ };
1651
+ child.once("exit", onExit);
1652
+ });
1653
+ }
1654
+ async function terminateChildProcess(child, label, timeoutMs = CHILD_SHUTDOWN_TIMEOUT_MS) {
1655
+ if (!child || isChildExited(child)) {
1656
+ return;
1657
+ }
1658
+ if (!child.killed) {
1659
+ child.kill("SIGTERM");
1660
+ }
1661
+ if (await waitForChildExit(child, timeoutMs)) {
1662
+ return;
1663
+ }
1664
+ warn(`${label} did not exit after SIGTERM; forcing shutdown`, { pid: child.pid });
1665
+ try {
1666
+ child.kill("SIGKILL");
1667
+ } catch {
1668
+ return;
1669
+ }
1670
+ await waitForChildExit(child, 2000);
1671
+ }
1591
1672
  function stopSupervisedWeb() {
1592
1673
  if (supervisedWebPid && supervisedWebPid > 0) {
1593
1674
  try {
@@ -1607,11 +1688,10 @@ async function shutdown(exitCode = 0) {
1607
1688
  }
1608
1689
  stopSupervisedWeb();
1609
1690
  stopMenuBarApp();
1691
+ const activeCaddyProcess = caddyProcess;
1610
1692
  stopEdgeProcesses();
1611
- if (brokerProcess && !brokerProcess.killed) {
1612
- brokerProcess.kill("SIGTERM");
1613
- }
1614
- await sleep2(500);
1693
+ await terminateChildProcess(brokerProcess, "broker");
1694
+ await terminateChildProcess(activeCaddyProcess, "local edge", 2000);
1615
1695
  process.exit(exitCode);
1616
1696
  }
1617
1697
  function sleep2(ms) {