@maintainer-pro/ai-bridge 0.1.22 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maintainer-pro/ai-bridge",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Local bridge daemon that pairs a machine to Maintainer Pro and configures multiple client sandboxes.",
5
5
  "keywords": [
6
6
  "maintainer-pro",
@@ -28,7 +28,7 @@
28
28
  "node": ">=22"
29
29
  },
30
30
  "dependencies": {
31
- "@maintainer-pro/ai-cli": "^0.1.12",
31
+ "@maintainer-pro/ai-cli": "^0.1.13",
32
32
  "@maintainer-pro/ai-server": "^0.1.7"
33
33
  }
34
34
  }
package/src/daemon.mjs CHANGED
@@ -16,6 +16,7 @@ import os from "node:os";
16
16
  import path from "node:path";
17
17
  import readline from "node:readline";
18
18
  import { fileURLToPath, pathToFileURL } from "node:url";
19
+ import { createRequire } from "node:module";
19
20
  import { createLogger, ensureProjectDataDir } from "@maintainer-pro/ai-cli";
20
21
  import { findIife, startAiServer } from "@maintainer-pro/ai-server";
21
22
  import {
@@ -39,7 +40,9 @@ import {
39
40
  } from "./discarded-tunnels.mjs";
40
41
 
41
42
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
43
+ const requireFromHere = createRequire(import.meta.url);
42
44
  const PACKAGE_VERSION = readPackageVersion();
45
+ const PACKAGE_VERSIONS = readPackageVersions();
43
46
  const HEARTBEAT_MS = 15_000;
44
47
  const WS_PING_MS = 10_000;
45
48
  const WS_RECONNECT_MIN_MS = 1_000;
@@ -157,6 +160,53 @@ function readPackageVersion() {
157
160
  }
158
161
  }
159
162
 
163
+ function readDepPackageVersion(name) {
164
+ const files = [];
165
+ try {
166
+ files.push(requireFromHere.resolve(`${name}/package.json`));
167
+ } catch {
168
+ /* try nested next */
169
+ }
170
+ try {
171
+ const serverDir = path.dirname(
172
+ requireFromHere.resolve("@maintainer-pro/ai-server/package.json")
173
+ );
174
+ files.push(path.join(serverDir, "node_modules", name, "package.json"));
175
+ files.push(path.join(serverDir, "..", name.replace("@maintainer-pro/", ""), "package.json"));
176
+ } catch {
177
+ /* ignore */
178
+ }
179
+ for (const file of files) {
180
+ try {
181
+ const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
182
+ if (typeof pkg.version === "string" && pkg.version) return pkg.version;
183
+ } catch {
184
+ /* try next */
185
+ }
186
+ }
187
+ return null;
188
+ }
189
+
190
+ function readPackageVersions() {
191
+ return {
192
+ bridge: PACKAGE_VERSION,
193
+ cli: readDepPackageVersion("@maintainer-pro/ai-cli"),
194
+ server: readDepPackageVersion("@maintainer-pro/ai-server"),
195
+ ui: readDepPackageVersion("@maintainer-pro/ai-ui"),
196
+ };
197
+ }
198
+
199
+ function formatPackageVersions(versions = PACKAGE_VERSIONS) {
200
+ return [
201
+ versions.bridge && `bridge ${versions.bridge}`,
202
+ versions.cli && `cli ${versions.cli}`,
203
+ versions.server && `server ${versions.server}`,
204
+ versions.ui && `ui ${versions.ui}`,
205
+ ]
206
+ .filter(Boolean)
207
+ .join(" · ");
208
+ }
209
+
160
210
  async function warnIfBridgeOutdated() {
161
211
  const fromWorkspace = path
162
212
  .normalize(__dirname)
@@ -2325,6 +2375,7 @@ function bridgeEmbedConfigJs(ws) {
2325
2375
  logLevel: "debug",
2326
2376
  maintainerProUrl: bridgeCfg?.adminUrl || "",
2327
2377
  maintainerProApiKey: String(store.clientKey || "").trim(),
2378
+ versions: PACKAGE_VERSIONS,
2328
2379
  };
2329
2380
  return `window.__MAINTAINER_PRO__=${JSON.stringify(payload)};`;
2330
2381
  }
@@ -4834,6 +4885,7 @@ async function sendHeartbeat(cfg, folders, localStates) {
4834
4885
  hostname: os.hostname(),
4835
4886
  platform: `${os.platform()}-${os.arch()}`,
4836
4887
  bridgeVersion: PACKAGE_VERSION,
4888
+ packageVersions: PACKAGE_VERSIONS,
4837
4889
  folders,
4838
4890
  issues: await buildIssues(cfg, localStates),
4839
4891
  workspaces: localStates.map((st) => ({
@@ -4866,6 +4918,7 @@ function buildLightHeartbeatPayload(cfg, folders) {
4866
4918
  hostname: os.hostname(),
4867
4919
  platform: `${os.platform()}-${os.arch()}`,
4868
4920
  bridgeVersion: PACKAGE_VERSION,
4921
+ packageVersions: PACKAGE_VERSIONS,
4869
4922
  folders,
4870
4923
  };
4871
4924
  }
@@ -4887,6 +4940,7 @@ async function buildHeartbeatPayload(cfg, folders, localStates) {
4887
4940
  hostname: os.hostname(),
4888
4941
  platform: `${os.platform()}-${os.arch()}`,
4889
4942
  bridgeVersion: PACKAGE_VERSION,
4943
+ packageVersions: PACKAGE_VERSIONS,
4890
4944
  folders,
4891
4945
  issues: await buildIssues(cfg, localStates),
4892
4946
  workspaces: localStates.map((st) => ({
@@ -5021,6 +5075,7 @@ async function pairFlow(args) {
5021
5075
  hostname: os.hostname(),
5022
5076
  platform: `${os.platform()}-${os.arch()}`,
5023
5077
  bridgeVersion: PACKAGE_VERSION,
5078
+ packageVersions: PACKAGE_VERSIONS,
5024
5079
  name: os.hostname(),
5025
5080
  });
5026
5081
 
@@ -5048,9 +5103,9 @@ async function main() {
5048
5103
  process.exit(0);
5049
5104
  }
5050
5105
 
5051
- logger.debug(
5052
- { logLevel: logger.level, nodeEnv: process.env.NODE_ENV },
5053
- "bridge starting"
5106
+ logger.info(
5107
+ { versions: PACKAGE_VERSIONS },
5108
+ `bridge v${PACKAGE_VERSION} starting (${formatPackageVersions()})`
5054
5109
  );
5055
5110
  void warnIfBridgeOutdated();
5056
5111
 
@@ -698,6 +698,19 @@ function isShareAssetPath(path) {
698
698
  );
699
699
  }
700
700
 
701
+ function rewriteShareAsLocalEnv(body) {
702
+ let out = String(body);
703
+ out = out.replace(
704
+ /(\/\.\*localhost\.\*\/\.test\()([^)]+)(\))/g,
705
+ "($1$2$3||location.pathname.indexOf(\"/p/\")===0)"
706
+ );
707
+ out = out.replace(
708
+ /((?:window\.)?location\.hostname)\s*===\s*(['"])localhost\2/g,
709
+ "($1===$2localhost$2||location.pathname.indexOf(\"/p/\")===0)"
710
+ );
711
+ return out;
712
+ }
713
+
701
714
  function prefixQuotedAssetPaths(body, pathPrefix) {
702
715
  if (!pathPrefix) return body;
703
716
  return String(body).replace(/(["'`])(\/(?!\/)[^"'`]*)/g, (full, q, path) => {
@@ -844,6 +857,7 @@ function prefixRootPaths(body, publicBase, contentType = "") {
844
857
  const css = mime === "text/css" || (!isCode && !html && /css/.test(mime));
845
858
  if (!html && !css) {
846
859
  let code = rewriteViteBaseLiterals(body, pathPrefix);
860
+ code = rewriteShareAsLocalEnv(code);
847
861
  code = prefixQuotedAssetPaths(code, pathPrefix);
848
862
  code = code.replace(
849
863
  /(?<![A-Za-z0-9])\/__nextjs_/g,
@@ -913,7 +927,7 @@ function isHtmlDocument(headers, body) {
913
927
 
914
928
  function isScriptRequestPath(path) {
915
929
  const p = String(path || "").split("?")[0]?.toLowerCase() || "";
916
- return /\.(?:m?js|cjs)$/.test(p);
930
+ return /\.(?:m?[jt]sx?|cjs)$/.test(p);
917
931
  }
918
932
 
919
933
  function isScriptOrJsonBody(headers, path) {
@@ -1098,42 +1112,28 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
1098
1112
  if (typeof v !== "string" || !v) return v;
1099
1113
  var mapped = mapLocal(v);
1100
1114
  if (mapped !== v) return mapped;
1101
- var backend = backendBase();
1102
- var path = "";
1103
- var search = "";
1104
- var hash = "";
1105
- var abs = null;
1106
- try {
1107
- if (/^(https?:|wss?:)\/\//i.test(v)) {
1108
- abs = new URL(v);
1109
- var host = String(abs.hostname || "")
1110
- .replace(/^\[|\]$/g, "")
1111
- .toLowerCase();
1112
- if (!loopback(host) && host !== String(location.hostname || "").toLowerCase()) {
1113
- return v;
1114
- }
1115
- path = abs.pathname || "/";
1116
- search = abs.search || "";
1117
- hash = abs.hash || "";
1118
- } else if (v.charAt(0) === "/" && v.charAt(1) !== "/") {
1119
- var rel = new URL(v, location.href);
1120
- path = rel.pathname || "/";
1121
- search = rel.search || "";
1122
- hash = rel.hash || "";
1123
- } else {
1124
- return addNav(v);
1125
- }
1126
- } catch (e) {
1127
- return addNav(v);
1115
+ if (/^(https?:|wss?:)\/\//i.test(v)) {
1116
+ try {
1117
+ var abs = new URL(v);
1118
+ if (!loopback(abs.hostname)) return v;
1119
+ } catch (e) {}
1128
1120
  }
1129
- if (path === "/api/v1" || path.indexOf("/api/v1/") === 0) return v;
1130
- if (path.indexOf("/p/") === 0) return v;
1131
- if (path === "/" || path === "") return addNav(v);
1132
- if (isAsset(path)) return addNav(v);
1133
- if (backend) {
1134
- var dest = backend + path + search + hash;
1135
- if (abs && /^ws/i.test(abs.protocol)) dest = dest.replace(/^http/i, "ws");
1136
- return dest;
1121
+ if (v.charAt(0) === "/" && v.charAt(1) !== "/") {
1122
+ var backend = backendBase();
1123
+ var path = v.split("?")[0];
1124
+ if (path === "/api/v1" || path.indexOf("/api/v1/") === 0 || path.indexOf("/p/") === 0) {
1125
+ return v;
1126
+ }
1127
+ if (
1128
+ backend &&
1129
+ !isAsset(path) &&
1130
+ (/^\/sreo(?:\/|$)/i.test(path) || /^\/api(?:\/|$)/i.test(path))
1131
+ ) {
1132
+ try {
1133
+ var rel = new URL(v, location.href);
1134
+ return backend + rel.pathname + rel.search + rel.hash;
1135
+ } catch (e) {}
1136
+ }
1137
1137
  }
1138
1138
  return addNav(v);
1139
1139
  }
@@ -1355,34 +1355,22 @@ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
1355
1355
  function prefixWith(url, prefix) {
1356
1356
  if (!prefix) return url;
1357
1357
  try {
1358
- var backend = backendBase();
1359
- var parsed = new URL(url, self.location.href);
1360
- var host = String(parsed.hostname || "")
1361
- .replace(/^\[|\]$/g, "")
1362
- .toLowerCase();
1363
- var pageHost = String(self.location.hostname || "")
1364
- .replace(/^\[|\]$/g, "")
1365
- .toLowerCase();
1366
- if (/^(https?:|wss?:)\/\//i.test(url) && !loopback(host) && host !== pageHost) {
1367
- return url;
1358
+ if (/^(https?:|wss?:)\/\//i.test(url)) {
1359
+ var abs = new URL(url);
1360
+ if (!loopback(abs.hostname)) return url;
1368
1361
  }
1369
- var path = parsed.pathname || "/";
1362
+ var u = new URL(url, self.location.href);
1363
+ var path = u.pathname || "/";
1364
+ var backend = backendBase();
1370
1365
  if (path === "/api/v1" || path.indexOf("/api/v1/") === 0) return url;
1371
1366
  if (path.indexOf("/p/") === 0) return url;
1372
1367
  if (
1373
1368
  backend &&
1374
- path !== "/" &&
1375
- path !== "" &&
1376
- !/\/(?:_next\/|__nextjs_|@vite(?:\/|$)|@react-refresh(?:\/|$)|@fs\/|@id\/|node_modules\/)/.test(
1377
- path
1378
- ) &&
1379
- !/\.(?:m?[jt]sx?|cjs|mjs|css|scss|sass|less|map|wasm|vue|svelte)$/i.test(path)
1369
+ !/^(https?:|wss?:)\/\//i.test(url) &&
1370
+ (/^\/sreo(?:\/|$)/i.test(path) || /^\/api(?:\/|$)/i.test(path))
1380
1371
  ) {
1381
- var dest = backend + path + (parsed.search || "") + (parsed.hash || "");
1382
- if (/^ws/i.test(parsed.protocol)) dest = dest.replace(/^http/i, "ws");
1383
- return dest;
1372
+ return backend + path + (u.search || "") + (u.hash || "");
1384
1373
  }
1385
- var u = parsed;
1386
1374
  if (u.origin !== self.location.origin) return url;
1387
1375
  if (u.pathname === "/" || u.pathname === "") return url;
1388
1376
  if (u.pathname === prefix || u.pathname.indexOf(prefix + "/") === 0) return url;
@@ -1550,14 +1538,14 @@ export function processShareHttpResponse(opts) {
1550
1538
  text = prefixRootPaths(text, publicBase, headers["content-type"] || "");
1551
1539
  mutated = true;
1552
1540
  }
1553
- if (Object.keys(portUrls).length && rewriteTextBody) {
1541
+ if (Object.keys(portUrls).length && rewriteTextBody && !isScriptOrJsonBody(headers, path)) {
1554
1542
  const mapped = rewriteMappedLocalUrls(text, portUrls);
1555
1543
  if (mapped !== text) {
1556
1544
  text = mapped;
1557
1545
  mutated = true;
1558
1546
  }
1559
1547
  }
1560
- if (publicBase && rewriteTextBody) {
1548
+ if (publicBase && rewriteTextBody && !isScriptOrJsonBody(headers, path)) {
1561
1549
  const prefixed = rewriteShareOriginPaths(text, publicBase, portUrls);
1562
1550
  if (prefixed !== text) {
1563
1551
  text = prefixed;