rterm-backend 2.7.4 → 2.7.6

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 (2) hide show
  1. package/bin/gybackend.js +95 -0
  2. package/package.json +1 -1
package/bin/gybackend.js CHANGED
@@ -382209,6 +382209,87 @@ var EvidenceSealer = class {
382209
382209
  }
382210
382210
  };
382211
382211
 
382212
+ // ../../packages/backend/src/services/sre/monitorStatusService.ts
382213
+ var MonitorStatusService = class {
382214
+ constructor(monitor, terminalService, now = () => Date.now()) {
382215
+ this.monitor = monitor;
382216
+ this.terminalService = terminalService;
382217
+ this.now = now;
382218
+ }
382219
+ /** Build the full monitor status report. */
382220
+ report() {
382221
+ const publisherWired = this.monitor.publisher !== null;
382222
+ const entries = [];
382223
+ const issues = [];
382224
+ const terminals = this.terminalService.getDisplayTerminals();
382225
+ const now = this.now();
382226
+ for (const terminal of terminals) {
382227
+ const terminalId = terminal.id;
382228
+ const connected = terminal.runtimeState === "ready";
382229
+ const platform2 = terminal.remoteOs ?? terminal.type ?? "unknown";
382230
+ const sessions = this.monitor.sessions;
382231
+ const session = sessions?.get(terminalId);
382232
+ const hasSession = session !== void 0;
382233
+ const inFlight = session?.inFlight === true;
382234
+ const lastCollectAt = session?.lastCollectAt ?? 0;
382235
+ const lastCollectAgoMs = lastCollectAt > 0 ? now - lastCollectAt : -1;
382236
+ let diagnosis = "ok";
382237
+ if (!connected) {
382238
+ diagnosis = "terminal_not_connected";
382239
+ } else if (!hasSession) {
382240
+ diagnosis = "no_monitor_session";
382241
+ } else if (inFlight) {
382242
+ diagnosis = "collection_stuck_in_flight";
382243
+ } else if (lastCollectAt === 0) {
382244
+ diagnosis = "never_collected";
382245
+ } else if (lastCollectAgoMs > 3e4) {
382246
+ diagnosis = `stale_collection (${Math.round(lastCollectAgoMs / 1e3)}s ago)`;
382247
+ }
382248
+ entries.push({
382249
+ terminalId,
382250
+ connected,
382251
+ platform: platform2,
382252
+ hasSession,
382253
+ inFlight,
382254
+ lastCollectAt,
382255
+ lastCollectAgoMs,
382256
+ diagnosis
382257
+ });
382258
+ if (diagnosis !== "ok") {
382259
+ issues.push(`${terminalId}: ${diagnosis}`);
382260
+ }
382261
+ }
382262
+ if (!publisherWired) {
382263
+ issues.unshift("publisher_not_wired \u2014 createObservability may not have been called");
382264
+ }
382265
+ if (entries.length === 0) {
382266
+ issues.push("no_terminals \u2014 no terminals connected");
382267
+ }
382268
+ return {
382269
+ publisherWired,
382270
+ terminalCount: entries.length,
382271
+ entries,
382272
+ issues
382273
+ };
382274
+ }
382275
+ /** Build a compact summary string for the agent. */
382276
+ summary() {
382277
+ const r = this.report();
382278
+ const parts = [];
382279
+ parts.push(`publisher=${r.publisherWired ? "wired" : "NOT WIRED"}`);
382280
+ parts.push(`terminals=${r.terminalCount}`);
382281
+ if (r.issues.length > 0) {
382282
+ parts.push(`issues=${r.issues.length}:`);
382283
+ for (const issue2 of r.issues) {
382284
+ parts.push(` - ${issue2}`);
382285
+ }
382286
+ } else {
382287
+ parts.push("all terminals collecting normally");
382288
+ }
382289
+ return parts.join("\n");
382290
+ }
382291
+ };
382292
+
382212
382293
  // ../../packages/backend/src/services/observability.ts
382213
382294
  function createObservability(deps) {
382214
382295
  const log = deps.onLog ?? (() => {
@@ -382287,6 +382368,7 @@ function createObservability(deps) {
382287
382368
  });
382288
382369
  const auditLedger = new AuditLedger({});
382289
382370
  const evidenceSealer = new EvidenceSealer({});
382371
+ const monitorStatus = new MonitorStatusService(deps.resourceMonitorService, deps.terminalService);
382290
382372
  const pluginScanRoot = (process.env.GYBACKEND_DATA_DIR ?? "./.gybackend-data") + "/plugins";
382291
382373
  const bundlePluginRoot = new URL("../../plugins/", import.meta.url).pathname;
382292
382374
  const scanRoots = [pluginScanRoot, "./plugins"];
@@ -382296,6 +382378,17 @@ function createObservability(deps) {
382296
382378
  if (fs22.existsSync(bundlePluginRoot)) scanRoots.push(bundlePluginRoot);
382297
382379
  } catch {
382298
382380
  }
382381
+ try {
382382
+ const req = createRequire2(import.meta.url);
382383
+ const fs22 = req("node:fs");
382384
+ const path31 = req("node:path");
382385
+ const resourcesPath = process.resourcesPath;
382386
+ if (resourcesPath) {
382387
+ const resourcesPlugins = path31.join(resourcesPath, "plugins");
382388
+ if (fs22.existsSync(resourcesPlugins)) scanRoots.push(resourcesPlugins);
382389
+ }
382390
+ } catch {
382391
+ }
382299
382392
  const pluginRegistry = new PluginRegistry({
382300
382393
  scanRoots,
382301
382394
  createContext: (record2) => PluginRegistry.defaultContext(
@@ -382348,6 +382441,7 @@ function createObservability(deps) {
382348
382441
  notify: { slackChannel, teamsChannel, smtpChannel, telegramChannel },
382349
382442
  aperf: { service: aperfService, toMetricPoint: aperfSummaryToMetricPoint },
382350
382443
  audit: { ledger: auditLedger, sealer: evidenceSealer },
382444
+ monitorStatus,
382351
382445
  pluginRegistry
382352
382446
  };
382353
382447
  }
@@ -384353,6 +384447,7 @@ async function startGyBackend() {
384353
384447
  automationManager,
384354
384448
  agentRunLedger,
384355
384449
  gatewayService,
384450
+ resourceMonitorService,
384356
384451
  setMonitorPublisher: (pub) => resourceMonitorService.setPublisher((channel, data) => {
384357
384452
  pub(channel, data);
384358
384453
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rterm-backend",
3
- "version": "2.7.4",
3
+ "version": "2.7.6",
4
4
  "description": "RTerm headless backend — run RTerm-as-a-service (AI agent, SSH/WinRM/Serial/local terminals, fleet orchestration, advanced automation with event-driven triggers + NATS event mesh, scheduled automation, SRE observability, Netdata integration, AWS APerf performance deep-dive, plugin system) and drive it over a WebSocket JSON-RPC gateway. No desktop UI required.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",