@camstack/agent 1.1.17 → 1.1.19

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/dist/cli.js CHANGED
@@ -37,15 +37,45 @@ var path6 = __toESM(require("path"));
37
37
  var fs = __toESM(require("fs"));
38
38
  var path = __toESM(require("path"));
39
39
  var import_fastify = __toESM(require("fastify"));
40
- function resolveUiDistDir(dataDir) {
41
- const candidates = [
42
- path.resolve(__dirname, "../../addon-agent-ui/dist"),
43
- path.join(dataDir, "addons", "@camstack", "addon-agent-ui", "dist"),
44
- path.join(dataDir, "agent-ui")
45
- ];
46
- for (const dir of candidates) {
47
- if (fs.existsSync(path.join(dir, "index.html"))) return dir;
40
+ function compareVersions(a, b) {
41
+ if (a === null && b === null) return 0;
42
+ if (a === null) return -1;
43
+ if (b === null) return 1;
44
+ const pa = a.split(".").map((s) => Number.parseInt(s, 10) || 0);
45
+ const pb = b.split(".").map((s) => Number.parseInt(s, 10) || 0);
46
+ const len = Math.max(pa.length, pb.length);
47
+ for (let i = 0; i < len; i++) {
48
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
49
+ if (diff !== 0) return diff;
50
+ }
51
+ return 0;
52
+ }
53
+ function readUiDistCandidate(baseDir) {
54
+ const dir = path.join(baseDir, "dist");
55
+ if (!fs.existsSync(path.join(dir, "index.html"))) return null;
56
+ let version = null;
57
+ try {
58
+ const parsed = JSON.parse(fs.readFileSync(path.join(baseDir, "package.json"), "utf-8"));
59
+ version = typeof parsed.version === "string" ? parsed.version : null;
60
+ } catch {
61
+ version = null;
48
62
  }
63
+ return { dir, version };
64
+ }
65
+ function pickUiDist(installed, bundled) {
66
+ if (installed && bundled) {
67
+ return compareVersions(bundled.version, installed.version) > 0 ? bundled.dir : installed.dir;
68
+ }
69
+ return installed?.dir ?? bundled?.dir ?? null;
70
+ }
71
+ function resolveUiDistDir(dataDir, bundledAddonsDir, siblingDistDir = path.resolve(__dirname, "../../addon-agent-ui/dist")) {
72
+ if (fs.existsSync(path.join(siblingDistDir, "index.html"))) return siblingDistDir;
73
+ const installed = readUiDistCandidate(path.join(dataDir, "addons", "@camstack", "addon-agent-ui"));
74
+ const bundled = bundledAddonsDir ? readUiDistCandidate(path.join(bundledAddonsDir, "addon-agent-ui")) : null;
75
+ const picked = pickUiDist(installed, bundled);
76
+ if (picked) return picked;
77
+ const legacy = path.join(dataDir, "agent-ui");
78
+ if (fs.existsSync(path.join(legacy, "index.html"))) return legacy;
49
79
  return null;
50
80
  }
51
81
  function readConfigFile(configPath) {
@@ -224,19 +254,26 @@ async function createAgentHttpServer(getBroker, config) {
224
254
  const nodes = getRegistryNodes(b);
225
255
  return mapDiscoveredNodes(nodes, b.nodeID);
226
256
  });
227
- const uiDir = resolveUiDistDir(config.dataDir);
257
+ const uiDir = resolveUiDistDir(config.dataDir, process.env["CAMSTACK_BUNDLED_ADDONS_DIR"]);
228
258
  if (uiDir) {
229
259
  const fastifyStatic = await import("@fastify/static");
230
260
  await app.register(fastifyStatic.default, {
231
261
  root: uiDir,
232
262
  prefix: "/",
233
263
  wildcard: false,
234
- decorateReply: false
264
+ // MUST stay true: the SPA-fallback below uses `reply.sendFile`, which
265
+ // only exists when the plugin decorates Reply. With `false` every
266
+ // fallback request 500'd with "reply.sendFile is not a function".
267
+ decorateReply: true
235
268
  });
236
269
  app.setNotFoundHandler(async (req, reply) => {
237
270
  if (req.url.startsWith("/api/") || req.url.startsWith("/health")) {
238
271
  return reply.status(404).send({ error: "Not found" });
239
272
  }
273
+ if (req.url.startsWith("/assets/")) {
274
+ console.warn(`[Agent] UI asset not found (stale index.html?): ${req.url}`);
275
+ return reply.status(404).send({ error: "Asset not found" });
276
+ }
240
277
  return reply.type("text/html").sendFile("index.html");
241
278
  });
242
279
  console.log(`[Agent] UI served from: ${uiDir}`);
@@ -1321,8 +1358,17 @@ async function startAgent(configPath) {
1321
1358
  udsEventBridgeDispose = (0, import_system3.createUdsEventBridge)({
1322
1359
  registry: agentUdsRegistry,
1323
1360
  parentBus: agentBrokerEventBus,
1324
- parentNodeId: broker.nodeID
1361
+ parentNodeId: broker.nodeID,
1362
+ // D2: relay to children via the pass-through subscription so the bridge's
1363
+ // wildcard does NOT count toward this node's local interest (otherwise the
1364
+ // gate could never filter anything).
1365
+ subscribePassthrough: (handler) => (0, import_system3.subscribePassthrough)(broker, handler)
1325
1366
  });
1367
+ const interestRegistry = agentUdsRegistry;
1368
+ (0, import_system3.setNodeEventInterest)(
1369
+ broker,
1370
+ () => interestRegistry.aggregateEventInterest()
1371
+ );
1326
1372
  const agentReadinessRegistry = (0, import_system3.getOrInitReadinessRegistry)(
1327
1373
  broker,
1328
1374
  agentBrokerEventBus,