rterm-backend 2.9.1 → 2.9.2

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/bin/gybackend.cjs CHANGED
@@ -9040,7 +9040,7 @@ var require_eventemitter3 = __commonJS({
9040
9040
  if (listeners.fn) return 1;
9041
9041
  return listeners.length;
9042
9042
  };
9043
- EventEmitter4.prototype.emit = function emit9(event, a1, a2, a3, a4, a5) {
9043
+ EventEmitter4.prototype.emit = function emit10(event, a1, a2, a3, a4, a5) {
9044
9044
  var evt = prefix ? prefix + event : event;
9045
9045
  if (!this._events[evt]) return false;
9046
9046
  var listeners = this._events[evt], len = arguments.length, args, i;
@@ -51648,7 +51648,7 @@ var require_pdf_worker = __commonJS({
51648
51648
  });
51649
51649
  exports3.getMetrics = void 0;
51650
51650
  var _util = __w_pdfjs_require__(0);
51651
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
51651
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
51652
51652
  t["Courier"] = 600;
51653
51653
  t["Courier-Bold"] = 600;
51654
51654
  t["Courier-BoldOblique"] = 600;
@@ -54586,7 +54586,7 @@ var require_pdf_worker = __commonJS({
54586
54586
  t2["a191"] = 918;
54587
54587
  });
54588
54588
  });
54589
- exports3.getMetrics = getMetrics;
54589
+ exports3.getMetrics = getMetrics2;
54590
54590
  }),
54591
54591
  /* 142 */
54592
54592
  /***/
@@ -113850,7 +113850,7 @@ var require_pdf_worker2 = __commonJS({
113850
113850
  });
113851
113851
  exports3.getMetrics = void 0;
113852
113852
  var _util = __w_pdfjs_require__(0);
113853
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
113853
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
113854
113854
  t["Courier"] = 600;
113855
113855
  t["Courier-Bold"] = 600;
113856
113856
  t["Courier-BoldOblique"] = 600;
@@ -116788,7 +116788,7 @@ var require_pdf_worker2 = __commonJS({
116788
116788
  t2["a191"] = 918;
116789
116789
  });
116790
116790
  });
116791
- exports3.getMetrics = getMetrics;
116791
+ exports3.getMetrics = getMetrics2;
116792
116792
  }),
116793
116793
  /* 141 */
116794
116794
  /***/
@@ -170585,7 +170585,7 @@ var require_pdf_worker3 = __commonJS({
170585
170585
  });
170586
170586
  exports3.getMetrics = void 0;
170587
170587
  var _util = __w_pdfjs_require__(0);
170588
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
170588
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
170589
170589
  t["Courier"] = 600;
170590
170590
  t["Courier-Bold"] = 600;
170591
170591
  t["Courier-BoldOblique"] = 600;
@@ -173523,7 +173523,7 @@ var require_pdf_worker3 = __commonJS({
173523
173523
  t2["a191"] = 918;
173524
173524
  });
173525
173525
  });
173526
- exports3.getMetrics = getMetrics;
173526
+ exports3.getMetrics = getMetrics2;
173527
173527
  }),
173528
173528
  /* 30 */
173529
173529
  /***/
@@ -229083,7 +229083,7 @@ var require_pdf_worker4 = __commonJS({
229083
229083
  });
229084
229084
  exports3.getMetrics = void 0;
229085
229085
  var _util = __w_pdfjs_require__(2);
229086
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
229086
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
229087
229087
  t["Courier"] = 600;
229088
229088
  t["Courier-Bold"] = 600;
229089
229089
  t["Courier-BoldOblique"] = 600;
@@ -232021,7 +232021,7 @@ var require_pdf_worker4 = __commonJS({
232021
232021
  t2["a191"] = 918;
232022
232022
  });
232023
232023
  });
232024
- exports3.getMetrics = getMetrics;
232024
+ exports3.getMetrics = getMetrics2;
232025
232025
  }),
232026
232026
  /* 149 */
232027
232027
  /***/
@@ -281574,18 +281574,18 @@ var SSHBackend = class _SSHBackend {
281574
281574
  });
281575
281575
  return info.socket;
281576
281576
  }
281577
- async buildConnectSocketIfNeeded(sshConfig, emit9) {
281577
+ async buildConnectSocketIfNeeded(sshConfig, emit10) {
281578
281578
  if (sshConfig.jumpHost) {
281579
281579
  const jumpId = `[Jump:${sshConfig.jumpHost.host}]`;
281580
281580
  console.log(`${jumpId} Starting jump host connection flow...`);
281581
- emit9(
281581
+ emit10(
281582
281582
  `\x1B[36m\u25B9 ${jumpId} Establishing tunnel via jump host ${sshConfig.jumpHost.host}...\x1B[0m\r
281583
281583
  `
281584
281584
  );
281585
281585
  const jumpClient = new (loadSsh2()).Client();
281586
281586
  const jumpSock = await this.buildConnectSocketIfNeeded(
281587
281587
  sshConfig.jumpHost,
281588
- emit9
281588
+ emit10
281589
281589
  );
281590
281590
  if (jumpSock) {
281591
281591
  console.log(
@@ -281629,7 +281629,7 @@ var SSHBackend = class _SSHBackend {
281629
281629
  });
281630
281630
  jumpClient.connect(jumpConnectConfig);
281631
281631
  });
281632
- emit9(
281632
+ emit10(
281633
281633
  `\x1B[32m\u2714 ${jumpId} Jump host ready. Requesting forward to target ${sshConfig.host}:${sshConfig.port}...\x1B[0m\r
281634
281634
  `
281635
281635
  );
@@ -281945,25 +281945,25 @@ var SSHBackend = class _SSHBackend {
281945
281945
  };
281946
281946
  this.sessions.set(config2.id, instance);
281947
281947
  (async () => {
281948
- const emit9 = (data) => {
281948
+ const emit10 = (data) => {
281949
281949
  instance.dataCallbacks.forEach((cb) => cb(data));
281950
281950
  };
281951
281951
  const emitExit = (code) => {
281952
281952
  this.emitExitOnce(config2.id, instance, code);
281953
281953
  };
281954
281954
  client2.on("ready", async () => {
281955
- emit9("\x1B[2J\x1B[H\x1B[32m\u2714 Connection established.\x1B[0m\r\n");
281955
+ emit10("\x1B[2J\x1B[H\x1B[32m\u2714 Connection established.\x1B[0m\r\n");
281956
281956
  console.log(
281957
281957
  `[SSH] Connection ready for ${sshConfig.host}:${sshConfig.port}`
281958
281958
  );
281959
281959
  const rawShell = isRawShellPreset(sshConfig.algorithmsPreset);
281960
281960
  try {
281961
- emit9("\x1B[36m\u25B9 Setting up port forwards...\x1B[0m\r\n");
281961
+ emit10("\x1B[36m\u25B9 Setting up port forwards...\x1B[0m\r\n");
281962
281962
  console.log(`[SSH] Setting up port forwards...`);
281963
281963
  await this.setupPortForwards(instance, sshConfig);
281964
281964
  } catch (e) {
281965
281965
  console.error(`[SSH] Port forward setup failed:`, e);
281966
- emit9(`\x1B[31m\u2718 Port forward failed: ${e.message}\x1B[0m\r
281966
+ emit10(`\x1B[31m\u2718 Port forward failed: ${e.message}\x1B[0m\r
281967
281967
  `);
281968
281968
  }
281969
281969
  if (rawShell) {
@@ -281973,7 +281973,7 @@ var SSHBackend = class _SSHBackend {
281973
281973
  );
281974
281974
  } else {
281975
281975
  try {
281976
- emit9("\x1B[36m\u25B9 Detecting remote OS...\x1B[0m\r\n");
281976
+ emit10("\x1B[36m\u25B9 Detecting remote OS...\x1B[0m\r\n");
281977
281977
  console.log(`[SSH] Detecting remote OS...`);
281978
281978
  const uname = await this.execCollect(client2, "uname -s");
281979
281979
  const u = (uname.stdout || uname.stderr || "").toLowerCase();
@@ -281993,13 +281993,13 @@ var SSHBackend = class _SSHBackend {
281993
281993
  if (!instance.remoteOs) instance.remoteOs = "unix";
281994
281994
  console.log(`[SSH] Remote OS detected: ${instance.remoteOs}`);
281995
281995
  try {
281996
- emit9("\x1B[36m\u25B9 Initializing SFTP channel...\x1B[0m\r\n");
281996
+ emit10("\x1B[36m\u25B9 Initializing SFTP channel...\x1B[0m\r\n");
281997
281997
  await this.initializeSftp(instance);
281998
- emit9("\x1B[32m\u2714 SFTP channel ready.\x1B[0m\r\n");
281998
+ emit10("\x1B[32m\u2714 SFTP channel ready.\x1B[0m\r\n");
281999
281999
  } catch (error40) {
282000
282000
  const message = error40 instanceof Error ? error40.message : String(error40);
282001
282001
  instance.sftpInitError = message;
282002
- emit9(
282002
+ emit10(
282003
282003
  `\x1B[33m\u26A0 SFTP unavailable: ${message}. File panel features may be limited.\x1B[0m\r
282004
282004
  `
282005
282005
  );
@@ -282012,7 +282012,7 @@ var SSHBackend = class _SSHBackend {
282012
282012
  }
282013
282013
  }
282014
282014
  }
282015
- emit9("\x1B[36m\u25B9 Opening interactive shell...\x1B[0m\r\n");
282015
+ emit10("\x1B[36m\u25B9 Opening interactive shell...\x1B[0m\r\n");
282016
282016
  console.log(`[SSH] Opening interactive shell...`);
282017
282017
  const initialWindowSize = this.resolveRequestedWindowSize(instance, {
282018
282018
  cols: config2.cols,
@@ -282042,7 +282042,7 @@ var SSHBackend = class _SSHBackend {
282042
282042
  console.error(`[SSH] Failed to open shell:`, err);
282043
282043
  instance.initializationState = "failed";
282044
282044
  instance.isInitializing = false;
282045
- emit9(`\x1B[31m\u2718 Failed to open shell: ${err.message}\x1B[0m\r
282045
+ emit10(`\x1B[31m\u2718 Failed to open shell: ${err.message}\x1B[0m\r
282046
282046
  `);
282047
282047
  emitExit(-1);
282048
282048
  return;
@@ -282052,7 +282052,7 @@ var SSHBackend = class _SSHBackend {
282052
282052
  if (rawShell) {
282053
282053
  instance.initializationState = "ready";
282054
282054
  instance.isInitializing = false;
282055
- emit9("\x1B[32m\u2714 Shell ready.\x1B[0m\r\n");
282055
+ emit10("\x1B[32m\u2714 Shell ready.\x1B[0m\r\n");
282056
282056
  console.log(
282057
282057
  `[SSH] Raw-shell mode: shell ready immediately (preset=${sshConfig.algorithmsPreset}).`
282058
282058
  );
@@ -282060,14 +282060,14 @@ var SSHBackend = class _SSHBackend {
282060
282060
  const chunk2 = data.toString();
282061
282061
  const sanitizedChunk = this.stripReadyMarker(chunk2);
282062
282062
  this.consumeOscMarkers(instance, sanitizedChunk);
282063
- if (sanitizedChunk) emit9(sanitizedChunk);
282063
+ if (sanitizedChunk) emit10(sanitizedChunk);
282064
282064
  });
282065
282065
  stream.on("close", async (code) => {
282066
282066
  emitExit(typeof code === "number" ? code : 0);
282067
282067
  });
282068
282068
  return;
282069
282069
  }
282070
- emit9("\x1B[36m\u25B9 Initializing shell integration...\x1B[0m\r\n");
282070
+ emit10("\x1B[36m\u25B9 Initializing shell integration...\x1B[0m\r\n");
282071
282071
  console.log(
282072
282072
  `[SSH] Shell stream opened. Starting robust initialization...`
282073
282073
  );
@@ -282113,7 +282113,7 @@ var SSHBackend = class _SSHBackend {
282113
282113
  if (retryCount >= maxRetries) {
282114
282114
  instance.initializationState = "failed";
282115
282115
  instance.isInitializing = false;
282116
- emit9(
282116
+ emit10(
282117
282117
  "\x1B[31m\u2718 Initialization failed. Entering fallback mode.\x1B[0m\r\n"
282118
282118
  );
282119
282119
  console.error(
@@ -282122,7 +282122,7 @@ var SSHBackend = class _SSHBackend {
282122
282122
  clearInterval(watchdogInterval);
282123
282123
  return;
282124
282124
  }
282125
- emit9(
282125
+ emit10(
282126
282126
  `\x1B[33m\u26A0 Initialization timeout, retrying (${retryCount}/${maxRetries})...\x1B[0m\r
282127
282127
  `
282128
282128
  );
@@ -282136,7 +282136,7 @@ var SSHBackend = class _SSHBackend {
282136
282136
  if (instance.isInitializing) {
282137
282137
  instance.buffer += chunk2;
282138
282138
  if (instance.buffer.includes(GYSHELL_READY_MARKER2)) {
282139
- emit9("\x1B[2J\x1B[H");
282139
+ emit10("\x1B[2J\x1B[H");
282140
282140
  isReadySent = true;
282141
282141
  clearInterval(watchdogInterval);
282142
282142
  const sawContinuation = /(?:\r?\n)>>\s*\r?\n/.test(instance.buffer) || instance.buffer.trimEnd().endsWith("\n>>") || instance.buffer.trimEnd().endsWith("\r\n>>");
@@ -282147,7 +282147,7 @@ var SSHBackend = class _SSHBackend {
282147
282147
  const realContent = this.stripReadyMarker(
282148
282148
  parts.slice(1).join(GYSHELL_READY_MARKER2)
282149
282149
  ).trimStart();
282150
- if (realContent) emit9(realContent);
282150
+ if (realContent) emit10(realContent);
282151
282151
  }
282152
282152
  instance.buffer = "";
282153
282153
  if (sawContinuation && instance.remoteOs === "windows" && instance.stream) {
@@ -282163,7 +282163,7 @@ var SSHBackend = class _SSHBackend {
282163
282163
  const sanitizedChunk = this.stripReadyMarker(chunk2);
282164
282164
  this.consumeOscMarkers(instance, sanitizedChunk);
282165
282165
  if (sanitizedChunk) {
282166
- emit9(sanitizedChunk);
282166
+ emit10(sanitizedChunk);
282167
282167
  }
282168
282168
  }
282169
282169
  });
@@ -282177,7 +282177,7 @@ var SSHBackend = class _SSHBackend {
282177
282177
  console.error(`[SSH] Client error:`, err);
282178
282178
  instance.initializationState = "failed";
282179
282179
  instance.isInitializing = false;
282180
- emit9(`\x1B[31m\u2718 SSH Error: ${err.message}\x1B[0m\r
282180
+ emit10(`\x1B[31m\u2718 SSH Error: ${err.message}\x1B[0m\r
282181
282181
  `);
282182
282182
  emitExit(-1);
282183
282183
  });
@@ -282200,7 +282200,7 @@ var SSHBackend = class _SSHBackend {
282200
282200
  sshConfig.privateKeyPath
282201
282201
  );
282202
282202
  } catch (e) {
282203
- emit9(
282203
+ emit10(
282204
282204
  `\x1B[31m\u2718 Failed to read private key: ${e.message}\x1B[0m\r
282205
282205
  `
282206
282206
  );
@@ -282212,19 +282212,19 @@ var SSHBackend = class _SSHBackend {
282212
282212
  }
282213
282213
  try {
282214
282214
  await new Promise((r) => setTimeout(r, 50));
282215
- emit9(
282215
+ emit10(
282216
282216
  `\x1B[36m\u25B9 Connecting to ${sshConfig.host}:${sshConfig.port}...\x1B[0m\r
282217
282217
  `
282218
282218
  );
282219
282219
  console.log(
282220
282220
  `[SSH] Attempting to connect to ${sshConfig.host}:${sshConfig.port}...`
282221
282221
  );
282222
- const sock = await this.buildConnectSocketIfNeeded(sshConfig, emit9);
282222
+ const sock = await this.buildConnectSocketIfNeeded(sshConfig, emit10);
282223
282223
  if (sock) {
282224
282224
  console.log(
282225
282225
  `[SSH] SUCCESS: Connection to ${sshConfig.host} will be tunneled through sock (Jump Host/Proxy).`
282226
282226
  );
282227
- emit9(
282227
+ emit10(
282228
282228
  "\x1B[36m\u25B9 [Final] Using tunnel socket for target connection...\x1B[0m\r\n"
282229
282229
  );
282230
282230
  connectConfig.sock = sock;
@@ -282238,7 +282238,7 @@ var SSHBackend = class _SSHBackend {
282238
282238
  const errMsg = e instanceof Error ? e.message : String(e);
282239
282239
  instance.initializationState = "failed";
282240
282240
  instance.isInitializing = false;
282241
- emit9(`\x1B[31m\u2718 Connection failed: ${errMsg}\x1B[0m\r
282241
+ emit10(`\x1B[31m\u2718 Connection failed: ${errMsg}\x1B[0m\r
282242
282242
  `);
282243
282243
  emitExit(-1);
282244
282244
  }
@@ -327549,7 +327549,7 @@ var initializeSax = function() {
327549
327549
  if (parser.opt.xmlns) parser.ns = Object.create(rootNS);
327550
327550
  parser.trackPosition = parser.opt.position !== false;
327551
327551
  if (parser.trackPosition) parser.position = parser.line = parser.column = 0;
327552
- emit9(parser, "onready");
327552
+ emit10(parser, "onready");
327553
327553
  }
327554
327554
  if (!Object.create) Object.create = function(o) {
327555
327555
  function F() {
@@ -328015,16 +328015,16 @@ var initializeSax = function() {
328015
328015
  });
328016
328016
  for (var s in sax$1.STATE) sax$1.STATE[sax$1.STATE[s]] = s;
328017
328017
  S = sax$1.STATE;
328018
- function emit9(parser, event, data) {
328018
+ function emit10(parser, event, data) {
328019
328019
  parser[event] && parser[event](data);
328020
328020
  }
328021
328021
  function emitNode(parser, nodeType, data) {
328022
328022
  if (parser.textNode) closeText(parser);
328023
- emit9(parser, nodeType, data);
328023
+ emit10(parser, nodeType, data);
328024
328024
  }
328025
328025
  function closeText(parser) {
328026
328026
  parser.textNode = textopts(parser.opt, parser.textNode);
328027
- if (parser.textNode) emit9(parser, "ontext", parser.textNode);
328027
+ if (parser.textNode) emit10(parser, "ontext", parser.textNode);
328028
328028
  parser.textNode = "";
328029
328029
  }
328030
328030
  function textopts(opt, text) {
@@ -328037,7 +328037,7 @@ var initializeSax = function() {
328037
328037
  if (parser.trackPosition) er += "\nLine: " + parser.line + "\nColumn: " + parser.column + "\nChar: " + parser.c;
328038
328038
  er = new Error(er);
328039
328039
  parser.error = er;
328040
- emit9(parser, "onerror", er);
328040
+ emit10(parser, "onerror", er);
328041
328041
  return parser;
328042
328042
  }
328043
328043
  function end(parser) {
@@ -328046,7 +328046,7 @@ var initializeSax = function() {
328046
328046
  closeText(parser);
328047
328047
  parser.c = "";
328048
328048
  parser.closed = true;
328049
- emit9(parser, "onend");
328049
+ emit10(parser, "onend");
328050
328050
  SAXParser.call(parser, parser.strict, parser.opt);
328051
328051
  return parser;
328052
328052
  }
@@ -346381,6 +346381,332 @@ ${body}`;
346381
346381
  return msg;
346382
346382
  }
346383
346383
 
346384
+ // packages/backend/src/services/AgentHelper/tools/observability_tools.ts
346385
+ function emit9(context2, toolName, input, output) {
346386
+ context2.sendEvent(context2.sessionId, {
346387
+ messageId: context2.messageId,
346388
+ type: "tool_call",
346389
+ toolName,
346390
+ input: typeof input === "string" ? input : JSON.stringify(input),
346391
+ output
346392
+ });
346393
+ }
346394
+ function obs(context2, toolName, args) {
346395
+ const o = context2.observability;
346396
+ if (!o) {
346397
+ const msg = `${toolName} is not available in this runtime (observability not wired).`;
346398
+ emit9(context2, toolName, args, msg);
346399
+ return { o: null, msg };
346400
+ }
346401
+ return { o, msg: null };
346402
+ }
346403
+ var getMetricsSchema = external_exports.object({
346404
+ format: external_exports.enum(["prometheus", "summary"]).optional().describe("'prometheus' = exposition text for a scraper; 'summary' = dashboard summary line (default).")
346405
+ });
346406
+ async function getMetrics(args, context2) {
346407
+ const { o, msg } = obs(context2, "get_metrics", args);
346408
+ if (!o) return msg;
346409
+ const out = args.format === "prometheus" ? o.metricsExport.renderPrometheus() || "# no host metrics recorded yet" : await o.dashboard.summary();
346410
+ emit9(context2, "get_metrics", args, out);
346411
+ return out;
346412
+ }
346413
+ var manageSecretSchema = external_exports.object({
346414
+ action: external_exports.enum(["list", "set", "delete", "has"]).describe("list metadata (never values), set a secret, delete one, or check existence."),
346415
+ key: external_exports.string().optional().describe("Secret key (required for set/delete/has)."),
346416
+ value: external_exports.string().optional().describe("Secret value (required for set). Never echoed back."),
346417
+ labels: external_exports.record(external_exports.string()).optional().describe("Optional labels (service, scope, connection id).")
346418
+ });
346419
+ async function manageSecret(args, context2) {
346420
+ const { o, msg } = obs(context2, "manage_secret", args);
346421
+ if (!o) return msg;
346422
+ const v = o.secrets;
346423
+ if (!v.unlocked()) {
346424
+ const m = "Secrets vault is locked \u2014 start RTerm with RTERM_SECRETS_MASTER_KEY set.";
346425
+ emit9(context2, "manage_secret", args, m);
346426
+ return m;
346427
+ }
346428
+ let out;
346429
+ if (args.action === "list") {
346430
+ const items = v.list();
346431
+ out = items.length ? items.map((m) => `- ${m.key}${m.labels ? ` ${JSON.stringify(m.labels)}` : ""} (updated ${new Date(m.updatedAt).toISOString()})`).join("\n") : "No secrets stored.";
346432
+ } else if (args.action === "set") {
346433
+ if (!args.key || args.value === void 0) {
346434
+ out = "set requires key + value.";
346435
+ } else {
346436
+ v.set(args.key, args.value, args.labels);
346437
+ out = `Stored secret '${args.key}'.`;
346438
+ }
346439
+ } else if (args.action === "delete") {
346440
+ if (!args.key) {
346441
+ out = "delete requires key.";
346442
+ } else {
346443
+ out = v.delete(args.key) ? `Deleted secret '${args.key}'.` : `No secret '${args.key}'.`;
346444
+ }
346445
+ } else {
346446
+ if (!args.key) {
346447
+ out = "has requires key.";
346448
+ } else {
346449
+ out = v.has(args.key) ? `'${args.key}' exists.` : `'${args.key}' does not exist.`;
346450
+ }
346451
+ }
346452
+ emit9(context2, "manage_secret", args, out);
346453
+ return out;
346454
+ }
346455
+ var manageOncallSchema = external_exports.object({
346456
+ action: external_exports.enum(["open_pages", "page", "ack", "resolve", "list_policies", "tick"]).describe("List open pages, raise a page, ack/resolve a page, list policies, or advance the escalation clock."),
346457
+ pageId: external_exports.string().optional().describe("Page id (ack/resolve)."),
346458
+ by: external_exports.string().optional().describe("Who is acknowledging (ack)."),
346459
+ incidentId: external_exports.string().optional().describe("Incident id (page)."),
346460
+ policyId: external_exports.string().optional().describe("Escalation policy id (page)."),
346461
+ title: external_exports.string().optional().describe("Page title (page)."),
346462
+ severity: external_exports.string().optional().describe("Severity e.g. sev1/sev2/sev3 (page).")
346463
+ });
346464
+ async function manageOncall(args, context2) {
346465
+ const { o, msg } = obs(context2, "manage_oncall", args);
346466
+ if (!o) return msg;
346467
+ const s = o.oncall;
346468
+ let out;
346469
+ try {
346470
+ if (args.action === "open_pages") {
346471
+ const pages = s.openPages();
346472
+ out = pages.length ? pages.map((p) => `- [${p.severity}] ${p.title} (level ${p.levelIndex}, page ${p.id})`).join("\n") : "No open pages.";
346473
+ } else if (args.action === "list_policies") {
346474
+ const pols = s.listPolicies();
346475
+ out = pols.length ? pols.map((p) => `- ${p.name} (${p.id}): ${p.levels.length} level(s)`).join("\n") : "No escalation policies registered.";
346476
+ } else if (args.action === "page") {
346477
+ if (!args.incidentId || !args.policyId || !args.title || !args.severity) {
346478
+ out = "page requires incidentId, policyId, title, severity.";
346479
+ } else {
346480
+ const p = await s.page({ incidentId: args.incidentId, policyId: args.policyId, title: args.title, severity: args.severity });
346481
+ out = `Paged (page ${p.id}) at level 0.`;
346482
+ }
346483
+ } else if (args.action === "ack") {
346484
+ if (!args.pageId || !args.by) {
346485
+ out = "ack requires pageId + by.";
346486
+ } else {
346487
+ s.acknowledge(args.pageId, args.by);
346488
+ out = `Page ${args.pageId} acknowledged by ${args.by}.`;
346489
+ }
346490
+ } else if (args.action === "resolve") {
346491
+ if (!args.pageId) {
346492
+ out = "resolve requires pageId.";
346493
+ } else {
346494
+ s.resolve(args.pageId);
346495
+ out = `Page ${args.pageId} resolved.`;
346496
+ }
346497
+ } else {
346498
+ const esc2 = await s.tick();
346499
+ out = esc2.length ? `Escalated ${esc2.length} page(s).` : "No pages needed escalation.";
346500
+ }
346501
+ } catch (e) {
346502
+ out = `on-call error: ${e instanceof Error ? e.message : String(e)}`;
346503
+ }
346504
+ emit9(context2, "manage_oncall", args, out);
346505
+ return out;
346506
+ }
346507
+ var getCostSchema = external_exports.object({
346508
+ action: external_exports.enum(["summary", "check", "list_budgets"]).describe("summary of spend, check a run against budgets, or list budgets."),
346509
+ period: external_exports.enum(["daily", "monthly"]).optional().describe("Window for summary (default daily)."),
346510
+ model: external_exports.string().optional().describe("Filter by model / the model to check."),
346511
+ profileId: external_exports.string().optional().describe("Filter by profile / the profile to check.")
346512
+ });
346513
+ async function getCost(args, context2) {
346514
+ const { o, msg } = obs(context2, "get_cost", args);
346515
+ if (!o) return msg;
346516
+ let out;
346517
+ if (args.action === "summary") {
346518
+ const s = o.cost.summarize({ period: args.period ?? "daily", model: args.model, profileId: args.profileId });
346519
+ const lines = s.byModel.map((m) => ` ${m.model}: $${m.usd.toFixed(4)} (${m.promptTokens}in/${m.completionTokens}out)`).join("\n");
346520
+ out = `Spend (${args.period ?? "daily"}): $${s.totalUsd.toFixed(4)} total.${lines ? "\n" + lines : ""}`;
346521
+ } else if (args.action === "check") {
346522
+ const r = o.cost.check({ model: args.model, profileId: args.profileId });
346523
+ out = `Budget check \u2192 ${r.action.toUpperCase()}${r.statuses.length ? ` (${r.statuses.map((s) => `${s.budget.id}=${(s.ratio * 100).toFixed(0)}%`).join(", ")})` : " (no matching budgets)"}.`;
346524
+ } else {
346525
+ const b = o.cost.listBudgets();
346526
+ out = b.length ? b.map((x) => `- ${x.id}: ${x.model ?? "*"}/${x.profileId ?? "*"} ${x.period} cap $${x.capUsd}`).join("\n") : "No budgets configured.";
346527
+ }
346528
+ emit9(context2, "get_cost", args, out);
346529
+ return out;
346530
+ }
346531
+ var manageRecordingSchema = external_exports.object({
346532
+ action: external_exports.enum(["list", "start", "stop", "replay", "export_cast", "delete"]).describe("List, start, stop, replay, export (.cast), or delete a recording."),
346533
+ recordingId: external_exports.string().optional().describe("Recording id (stop/replay/export_cast/delete)."),
346534
+ terminalId: external_exports.string().optional().describe("Terminal to record (start)."),
346535
+ title: external_exports.string().optional().describe("Title (start)."),
346536
+ fromSec: external_exports.number().optional().describe("Replay start offset seconds."),
346537
+ durationSec: external_exports.number().optional().describe("Replay duration seconds.")
346538
+ });
346539
+ async function manageRecording(args, context2) {
346540
+ const { o, msg } = obs(context2, "manage_recording", args);
346541
+ if (!o) return msg;
346542
+ const r = o.recording;
346543
+ let out;
346544
+ try {
346545
+ if (args.action === "list") {
346546
+ const list = r.list();
346547
+ out = list.length ? list.map((x) => `- ${x.id} (${x.terminalId}) ${x.events} events${x.endedAt ? " [stopped]" : " [recording]"}`).join("\n") : "No recordings.";
346548
+ } else if (args.action === "start") {
346549
+ if (!args.terminalId) {
346550
+ out = "start requires terminalId.";
346551
+ } else {
346552
+ out = `Recording started: ${r.start(args.terminalId, { title: args.title })}`;
346553
+ }
346554
+ } else if (args.action === "stop") {
346555
+ if (!args.recordingId) {
346556
+ out = "stop requires recordingId.";
346557
+ } else {
346558
+ const rec = r.stop(args.recordingId);
346559
+ out = `Recording ${args.recordingId} stopped (${rec.events.length} events).`;
346560
+ }
346561
+ } else if (args.action === "replay") {
346562
+ if (!args.recordingId) {
346563
+ out = "replay requires recordingId.";
346564
+ } else {
346565
+ const ev = r.replay(args.recordingId, { fromSec: args.fromSec, durationSec: args.durationSec });
346566
+ out = ev.length ? ev.map((e) => `[+${e.t.toFixed(1)}s] ${e.data}`).join("") : "(no events in window)";
346567
+ }
346568
+ } else if (args.action === "export_cast") {
346569
+ if (!args.recordingId) {
346570
+ out = "export_cast requires recordingId.";
346571
+ } else {
346572
+ out = r.exportCast(args.recordingId);
346573
+ }
346574
+ } else {
346575
+ if (!args.recordingId) {
346576
+ out = "delete requires recordingId.";
346577
+ } else {
346578
+ out = r.delete(args.recordingId) ? `Deleted ${args.recordingId}.` : `No recording ${args.recordingId}.`;
346579
+ }
346580
+ }
346581
+ } catch (e) {
346582
+ out = `recording error: ${e instanceof Error ? e.message : String(e)}`;
346583
+ }
346584
+ emit9(context2, "manage_recording", args, out);
346585
+ return out;
346586
+ }
346587
+ var manageGitopsSchema = external_exports.object({
346588
+ action: external_exports.enum(["export", "drift", "in_sync"]).describe("export the live desired-state manifest, or diff/verify a manifest against live."),
346589
+ manifest: external_exports.any().optional().describe("A StateManifest (for drift/in_sync).")
346590
+ });
346591
+ async function manageGitops(args, context2) {
346592
+ const { o, msg } = obs(context2, "manage_gitops", args);
346593
+ if (!o) return msg;
346594
+ let out;
346595
+ try {
346596
+ if (args.action === "export") {
346597
+ const m = await o.gitops.exportLive();
346598
+ out = `Exported manifest: ${m.entities.length} entities, stateHash ${m.stateHash.slice(0, 12)}\u2026`;
346599
+ } else if (args.action === "drift") {
346600
+ if (!args.manifest) {
346601
+ out = "drift requires a manifest.";
346602
+ } else {
346603
+ const d = await o.gitops.drift(args.manifest);
346604
+ out = d.length ? d.map((x) => `- ${x.id} (${x.kind}): ${x.drift}`).join("\n") : "No drift \u2014 live matches the manifest.";
346605
+ }
346606
+ } else {
346607
+ if (!args.manifest) {
346608
+ out = "in_sync requires a manifest.";
346609
+ } else {
346610
+ out = await o.gitops.inSync(args.manifest) ? "In sync." : "Out of sync (drift present).";
346611
+ }
346612
+ }
346613
+ } catch (e) {
346614
+ out = `gitops error: ${e instanceof Error ? e.message : String(e)}`;
346615
+ }
346616
+ emit9(context2, "manage_gitops", args, out);
346617
+ return out;
346618
+ }
346619
+ var managePlaybookVersionSchema = external_exports.object({
346620
+ action: external_exports.enum(["lint", "history", "rollback", "diff"]).describe("lint a playbook def, list version history, roll back, or diff two versions."),
346621
+ playbookId: external_exports.string().optional().describe("Playbook id (history/rollback/diff)."),
346622
+ def: external_exports.any().optional().describe("Playbook definition (lint)."),
346623
+ version: external_exports.number().int().optional().describe("Version to roll back to (rollback)."),
346624
+ a: external_exports.number().int().optional().describe("First version (diff)."),
346625
+ b: external_exports.number().int().optional().describe("Second version (diff).")
346626
+ });
346627
+ async function managePlaybookVersion(args, context2) {
346628
+ const { o, msg } = obs(context2, "manage_playbook_version", args);
346629
+ if (!o) return msg;
346630
+ let out;
346631
+ try {
346632
+ if (args.action === "lint") {
346633
+ if (!args.def) {
346634
+ out = "lint requires a playbook def.";
346635
+ } else {
346636
+ const issues = o.playbooks.lint(args.def);
346637
+ out = issues.length ? issues.map((i) => `- [${i.severity}] ${i.rule}: ${i.message}`).join("\n") : "Playbook lints clean.";
346638
+ }
346639
+ } else if (args.action === "history") {
346640
+ if (!args.playbookId) {
346641
+ out = "history requires playbookId.";
346642
+ } else {
346643
+ const h = o.playbooks.versioning.history(args.playbookId);
346644
+ out = h.length ? h.map((v) => `- v${v.version} (${v.hash})${v.comment ? ` ${v.comment}` : ""}`).join("\n") : `No versions for '${args.playbookId}'.`;
346645
+ }
346646
+ } else if (args.action === "rollback") {
346647
+ if (!args.playbookId || args.version === void 0) {
346648
+ out = "rollback requires playbookId + version.";
346649
+ } else {
346650
+ const v = o.playbooks.versioning.rollback(args.playbookId, args.version);
346651
+ out = `Rolled back to v${args.version} \u2192 new v${v.version}.`;
346652
+ }
346653
+ } else {
346654
+ if (!args.playbookId || args.a === void 0 || args.b === void 0) {
346655
+ out = "diff requires playbookId + a + b.";
346656
+ } else {
346657
+ out = o.playbooks.versioning.diff(args.playbookId, args.a, args.b);
346658
+ }
346659
+ }
346660
+ } catch (e) {
346661
+ out = `playbook error: ${e instanceof Error ? e.message : String(e)}`;
346662
+ }
346663
+ emit9(context2, "manage_playbook_version", args, out);
346664
+ return out;
346665
+ }
346666
+ var getCloudInventorySchema = external_exports.object({
346667
+ action: external_exports.enum(["summary", "query", "sync"]).describe("summary counts, query resources, or pull fresh inventory."),
346668
+ provider: external_exports.enum(["aws", "gcp", "azure"]).optional().describe("Filter by provider."),
346669
+ state: external_exports.string().optional().describe("Filter by state (running/stopped/\u2026)."),
346670
+ region: external_exports.string().optional().describe("Filter by region.")
346671
+ });
346672
+ async function getCloudInventory(args, context2) {
346673
+ const { o, msg } = obs(context2, "get_cloud_inventory", args);
346674
+ if (!o) return msg;
346675
+ let out;
346676
+ try {
346677
+ if (args.action === "summary") {
346678
+ const s = o.cloud.summary();
346679
+ out = `Cloud inventory: ${s.total} resources. By provider: ${JSON.stringify(s.byProvider)}. By state: ${JSON.stringify(s.byState)}.`;
346680
+ } else if (args.action === "query") {
346681
+ const r = o.cloud.query({ provider: args.provider, state: args.state, region: args.region });
346682
+ out = r.length ? r.map((x) => `- [${x.provider}] ${x.name} (${x.machineType ?? x.kind}) ${x.state ?? ""} ${x.region ?? ""}`).join("\n") : "No matching cloud resources.";
346683
+ } else {
346684
+ const r = await o.cloud.sync();
346685
+ out = `Synced ${r.added} resources${r.errors.length ? `, ${r.errors.length} account error(s)` : ""}.`;
346686
+ }
346687
+ } catch (e) {
346688
+ out = `cloud error: ${e instanceof Error ? e.message : String(e)}`;
346689
+ }
346690
+ emit9(context2, "get_cloud_inventory", args, out);
346691
+ return out;
346692
+ }
346693
+ var getLiveDashboardSchema = external_exports.object({
346694
+ action: external_exports.enum(["state", "subscribers"]).describe("'state' = current dashboard state; 'subscribers' = connected client count.")
346695
+ });
346696
+ async function getLiveDashboard(args, context2) {
346697
+ const { o, msg } = obs(context2, "get_live_dashboard", args);
346698
+ if (!o) return msg;
346699
+ let out;
346700
+ if (args.action === "subscribers") {
346701
+ out = `${o.liveDashboard.subscriberCount()} dashboard subscriber(s) connected.`;
346702
+ } else {
346703
+ const s = await o.dashboard.summary();
346704
+ out = s;
346705
+ }
346706
+ emit9(context2, "get_live_dashboard", args, out);
346707
+ return out;
346708
+ }
346709
+
346384
346710
  // packages/backend/src/services/AgentHelper/tools/skill_tools.ts
346385
346711
  var skillToolSchema = external_exports.object({
346386
346712
  name: external_exports.string().describe("The skill identifier from available_skills")
@@ -346648,6 +346974,51 @@ function buildToolsForModel(readFileSupport) {
346648
346974
  name: "import_putty",
346649
346975
  description: BUILTIN_TOOL_INFO.find((t) => t.name === "import_putty")?.description ?? "",
346650
346976
  schema: importPuttySchema
346977
+ },
346978
+ {
346979
+ name: "get_metrics",
346980
+ description: 'Read host metrics as Prometheus exposition text (for a scraper) or a one-line dashboard summary. Use to answer "how are my hosts doing" or to feed an external Prometheus/OTel collector.',
346981
+ schema: getMetricsSchema
346982
+ },
346983
+ {
346984
+ name: "manage_secret",
346985
+ description: "Manage the encrypted secrets vault \u2014 list metadata (never values), set, delete, or check a secret. Secrets are materialized only at exec time and never enter the conversation. Vault must be unlocked (RTERM_SECRETS_MASTER_KEY).",
346986
+ schema: manageSecretSchema
346987
+ },
346988
+ {
346989
+ name: "manage_oncall",
346990
+ description: "Incident on-call paging \u2014 list open pages, raise a page for an incident under an escalation policy, acknowledge or resolve a page, list policies, or advance the escalation clock.",
346991
+ schema: manageOncallSchema
346992
+ },
346993
+ {
346994
+ name: "get_cost",
346995
+ description: "AI cost & budgets \u2014 summarize token spend in dollars (per model/profile, daily/monthly), check an intended run against budgets (ok/warn/throttle/deny), or list budgets.",
346996
+ schema: getCostSchema
346997
+ },
346998
+ {
346999
+ name: "manage_recording",
347000
+ description: "asciinema-style session recording \u2014 list, start, stop, replay (scrub), export (.cast), or delete a terminal session recording.",
347001
+ schema: manageRecordingSchema
347002
+ },
347003
+ {
347004
+ name: "manage_gitops",
347005
+ description: "GitOps for desired state \u2014 export the live estate (connections/playbooks/triggers/etc.) as a content-hashed manifest, or detect drift / verify a manifest against live.",
347006
+ schema: manageGitopsSchema
347007
+ },
347008
+ {
347009
+ name: "manage_playbook_version",
347010
+ description: "Playbook/runbook versioning + lint \u2014 statically lint a playbook definition (undefined params, dependsOn cycles, empty steps, missing rollback), list version history, roll back, or diff two versions.",
347011
+ schema: managePlaybookVersionSchema
347012
+ },
347013
+ {
347014
+ name: "get_cloud_inventory",
347015
+ description: "Cloud resource inventory (AWS/GCP/Azure) \u2014 summary counts by provider/state, query instances (filter by provider/state/region), or pull fresh inventory.",
347016
+ schema: getCloudInventorySchema
347017
+ },
347018
+ {
347019
+ name: "get_live_dashboard",
347020
+ description: "Live multi-client dashboard \u2014 read the current unified dashboard state/summary, or the number of connected dashboard subscribers.",
347021
+ schema: getLiveDashboardSchema
346651
347022
  }
346652
347023
  ].map((tool2) => convertToOpenAITool(tool2));
346653
347024
  }
@@ -346684,6 +347055,15 @@ var toolImplementations = {
346684
347055
  manageChange,
346685
347056
  manageTrigger,
346686
347057
  importPutty,
347058
+ getMetrics,
347059
+ manageSecret,
347060
+ manageOncall,
347061
+ getCost,
347062
+ manageRecording,
347063
+ manageGitops,
347064
+ managePlaybookVersion,
347065
+ getCloudInventory,
347066
+ getLiveDashboard,
346687
347067
  writeFile,
346688
347068
  editFile,
346689
347069
  writeAndEdit,
@@ -348813,11 +349193,11 @@ var AbstractChatCompletionRunner = class extends EventStream {
348813
349193
  this._addMessage(message);
348814
349194
  return chatCompletion;
348815
349195
  }
348816
- _addMessage(message, emit9 = true) {
349196
+ _addMessage(message, emit10 = true) {
348817
349197
  if (!("content" in message))
348818
349198
  message.content = null;
348819
349199
  this.messages.push(message);
348820
- if (emit9) {
349200
+ if (emit10) {
348821
349201
  this._emit("message", message);
348822
349202
  if (isToolMessage2(message) && message.content) {
348823
349203
  this._emit("functionToolCallResult", message.content);
@@ -349069,8 +349449,8 @@ var ChatCompletionRunner = class _ChatCompletionRunner extends AbstractChatCompl
349069
349449
  runner._run(() => runner._runTools(client2, params, opts));
349070
349450
  return runner;
349071
349451
  }
349072
- _addMessage(message, emit9 = true) {
349073
- super._addMessage(message, emit9);
349452
+ _addMessage(message, emit10 = true) {
349453
+ super._addMessage(message, emit10);
349074
349454
  if (isAssistantMessage(message) && message.content) {
349075
349455
  this._emit("content", message.content);
349076
349456
  }
@@ -359896,6 +360276,7 @@ var AgentService_v2 = class {
359896
360276
  /** Optional automation store backing the automation agent tools. */
359897
360277
  automationManager;
359898
360278
  triggerEngine;
360279
+ observability;
359899
360280
  /** Optional session-log handle for list_session_logs / read_session_log. */
359900
360281
  sessionLogger;
359901
360282
  /** Optional run ledger — persisted audit + token-cost record of every
@@ -359969,6 +360350,10 @@ var AgentService_v2 = class {
359969
360350
  setTriggerEngine(engine) {
359970
360351
  this.triggerEngine = engine ?? void 0;
359971
360352
  }
360353
+ /** Wire the observability handle (v2.9.x) so the observability_* agent tools work. */
360354
+ setObservability(obs2) {
360355
+ this.observability = obs2 ?? void 0;
360356
+ }
359972
360357
  /** Wire a session-log handle so list_session_logs / read_session_log work. */
359973
360358
  setSessionLogger(logger) {
359974
360359
  this.sessionLogger = logger ?? void 0;
@@ -361145,6 +361530,87 @@ Actually, your intention might be different. Please re-read the description of t
361145
361530
  }
361146
361531
  break;
361147
361532
  }
361533
+ case "get_metrics": {
361534
+ try {
361535
+ const validatedArgs = getMetricsSchema.parse(toolCall.args || {});
361536
+ result = await toolImplementations.getMetrics(validatedArgs, executionContext);
361537
+ } catch (err) {
361538
+ result = `Parameter validation error for get_metrics: ${err.message}`;
361539
+ }
361540
+ break;
361541
+ }
361542
+ case "manage_secret": {
361543
+ try {
361544
+ const validatedArgs = manageSecretSchema.parse(toolCall.args || {});
361545
+ result = await toolImplementations.manageSecret(validatedArgs, executionContext);
361546
+ } catch (err) {
361547
+ result = `Parameter validation error for manage_secret: ${err.message}`;
361548
+ }
361549
+ break;
361550
+ }
361551
+ case "manage_oncall": {
361552
+ try {
361553
+ const validatedArgs = manageOncallSchema.parse(toolCall.args || {});
361554
+ result = await toolImplementations.manageOncall(validatedArgs, executionContext);
361555
+ } catch (err) {
361556
+ result = `Parameter validation error for manage_oncall: ${err.message}`;
361557
+ }
361558
+ break;
361559
+ }
361560
+ case "get_cost": {
361561
+ try {
361562
+ const validatedArgs = getCostSchema.parse(toolCall.args || {});
361563
+ result = await toolImplementations.getCost(validatedArgs, executionContext);
361564
+ } catch (err) {
361565
+ result = `Parameter validation error for get_cost: ${err.message}`;
361566
+ }
361567
+ break;
361568
+ }
361569
+ case "manage_recording": {
361570
+ try {
361571
+ const validatedArgs = manageRecordingSchema.parse(toolCall.args || {});
361572
+ result = await toolImplementations.manageRecording(validatedArgs, executionContext);
361573
+ } catch (err) {
361574
+ result = `Parameter validation error for manage_recording: ${err.message}`;
361575
+ }
361576
+ break;
361577
+ }
361578
+ case "manage_gitops": {
361579
+ try {
361580
+ const validatedArgs = manageGitopsSchema.parse(toolCall.args || {});
361581
+ result = await toolImplementations.manageGitops(validatedArgs, executionContext);
361582
+ } catch (err) {
361583
+ result = `Parameter validation error for manage_gitops: ${err.message}`;
361584
+ }
361585
+ break;
361586
+ }
361587
+ case "manage_playbook_version": {
361588
+ try {
361589
+ const validatedArgs = managePlaybookVersionSchema.parse(toolCall.args || {});
361590
+ result = await toolImplementations.managePlaybookVersion(validatedArgs, executionContext);
361591
+ } catch (err) {
361592
+ result = `Parameter validation error for manage_playbook_version: ${err.message}`;
361593
+ }
361594
+ break;
361595
+ }
361596
+ case "get_cloud_inventory": {
361597
+ try {
361598
+ const validatedArgs = getCloudInventorySchema.parse(toolCall.args || {});
361599
+ result = await toolImplementations.getCloudInventory(validatedArgs, executionContext);
361600
+ } catch (err) {
361601
+ result = `Parameter validation error for get_cloud_inventory: ${err.message}`;
361602
+ }
361603
+ break;
361604
+ }
361605
+ case "get_live_dashboard": {
361606
+ try {
361607
+ const validatedArgs = getLiveDashboardSchema.parse(toolCall.args || {});
361608
+ result = await toolImplementations.getLiveDashboard(validatedArgs, executionContext);
361609
+ } catch (err) {
361610
+ result = `Parameter validation error for get_live_dashboard: ${err.message}`;
361611
+ }
361612
+ break;
361613
+ }
361148
361614
  case "manage_device_memory": {
361149
361615
  try {
361150
361616
  const validatedArgs = manageDeviceMemorySchema.parse(toolCall.args || {});
@@ -361946,6 +362412,7 @@ ${reminder}`;
361946
362412
  agentRunLedger: this.agentRunLedger,
361947
362413
  changeLedger: this.changeLedger,
361948
362414
  triggerEngine: this.triggerEngine,
362415
+ observability: this.observability,
361949
362416
  agentRunId,
361950
362417
  savedSshConnections: this.settings?.connections?.ssh ?? [],
361951
362418
  savedWinrmConnections: this.settings?.connections?.winrm ?? [],
@@ -365469,6 +365936,24 @@ var WebSocketGatewayAdapter = class {
365469
365936
  }
365470
365937
  async executeRequest(request, socket) {
365471
365938
  const params = request.params ?? {};
365939
+ if (request.method.startsWith("observability:")) {
365940
+ const bridge = this.options.observabilityBridge;
365941
+ if (!bridge) {
365942
+ throw new WebSocketRpcError(
365943
+ "METHOD_NOT_FOUND",
365944
+ `${request.method} is not available on this websocket gateway.`
365945
+ );
365946
+ }
365947
+ const fnName = request.method.slice("observability:".length);
365948
+ const fn = bridge[fnName];
365949
+ if (typeof fn !== "function") {
365950
+ throw new WebSocketRpcError(
365951
+ "METHOD_NOT_FOUND",
365952
+ `Unknown observability method: ${request.method}`
365953
+ );
365954
+ }
365955
+ return await fn(params);
365956
+ }
365472
365957
  switch (request.method) {
365473
365958
  case "gateway:ping":
365474
365959
  return { pong: true, ts: Date.now() };
@@ -383986,6 +384471,89 @@ function createObservability(deps) {
383986
384471
  };
383987
384472
  }
383988
384473
 
384474
+ // packages/backend/src/services/Gateway/observabilityBridge.ts
384475
+ function requireObs(deps) {
384476
+ const o = deps.observability();
384477
+ if (!o) throw new Error("observability is not available on this runtime");
384478
+ return o;
384479
+ }
384480
+ function createObservabilityBridge(deps) {
384481
+ return {
384482
+ // ── metrics / prometheus / otel ─────────────────────────────────────────
384483
+ /** Prometheus exposition text for all host metrics. */
384484
+ metricsPrometheus: async () => requireObs(deps).metricsExport.renderPrometheus(),
384485
+ /** dashboard state (unified). */
384486
+ dashboardState: async () => requireObs(deps).dashboard.state(),
384487
+ /** dashboard summary line. */
384488
+ dashboardSummary: async () => requireObs(deps).dashboard.summary(),
384489
+ // ── secrets vault (metadata only — never values) ────────────────────────
384490
+ secretsList: async (params) => requireObs(deps).secrets.list(params),
384491
+ secretsSet: async (params) => {
384492
+ const v = requireObs(deps).secrets;
384493
+ v.set(params.key, params.value, params.labels);
384494
+ return { ok: true, key: params.key };
384495
+ },
384496
+ secretsDelete: async (params) => ({ deleted: requireObs(deps).secrets.delete(params.key) }),
384497
+ secretsHas: async (params) => ({ exists: requireObs(deps).secrets.has(params.key) }),
384498
+ // ── on-call / escalation ────────────────────────────────────────────────
384499
+ oncallListPolicies: async () => requireObs(deps).oncall.listPolicies(),
384500
+ oncallRegisterPolicy: async (params) => {
384501
+ requireObs(deps).oncall.registerPolicy(params);
384502
+ return { ok: true, id: params.id };
384503
+ },
384504
+ oncallOpenPages: async () => requireObs(deps).oncall.openPages(),
384505
+ oncallPage: async (params) => requireObs(deps).oncall.page(params),
384506
+ oncallAck: async (params) => requireObs(deps).oncall.acknowledge(params.pageId, params.by),
384507
+ oncallResolve: async (params) => requireObs(deps).oncall.resolve(params.pageId),
384508
+ oncallTick: async () => requireObs(deps).oncall.tick(),
384509
+ // ── AI cost & budgets ───────────────────────────────────────────────────
384510
+ costSummary: async (params) => requireObs(deps).cost.summarize(params),
384511
+ costRecord: async (params) => ({
384512
+ usd: requireObs(deps).cost.record(params)
384513
+ }),
384514
+ costCheck: async (params) => requireObs(deps).cost.check(params),
384515
+ costListBudgets: async () => requireObs(deps).cost.listBudgets(),
384516
+ costSetBudget: async (params) => {
384517
+ requireObs(deps).cost.setBudget(params);
384518
+ return { ok: true, id: params.id };
384519
+ },
384520
+ costRemoveBudget: async (params) => ({ removed: requireObs(deps).cost.removeBudget(params.id) }),
384521
+ // ── session recording ───────────────────────────────────────────────────
384522
+ recordingList: async () => requireObs(deps).recording.list(),
384523
+ recordingStart: async (params) => ({
384524
+ recordingId: requireObs(deps).recording.start(params.terminalId, params)
384525
+ }),
384526
+ recordingStop: async (params) => requireObs(deps).recording.stop(params.recordingId),
384527
+ recordingReplay: async (params) => requireObs(deps).recording.replay(params.recordingId, params),
384528
+ recordingExportCast: async (params) => requireObs(deps).recording.exportCast(params.recordingId),
384529
+ recordingDelete: async (params) => ({ deleted: requireObs(deps).recording.delete(params.recordingId) }),
384530
+ // ── gitops ──────────────────────────────────────────────────────────────
384531
+ gitopsExport: async () => requireObs(deps).gitops.exportLive(),
384532
+ gitopsDrift: async (params) => requireObs(deps).gitops.drift(params.manifest),
384533
+ gitopsInSync: async (params) => ({
384534
+ inSync: await requireObs(deps).gitops.inSync(params.manifest)
384535
+ }),
384536
+ gitopsReconcile: async (params) => requireObs(deps).gitops.reconcile(params.manifest, { deleteRemoved: params.deleteRemoved }),
384537
+ // ── playbook versioning + lint ──────────────────────────────────────────
384538
+ playbookLint: async (params) => requireObs(deps).playbooks.lint(params.def),
384539
+ playbookHistory: async (params) => requireObs(deps).playbooks.versioning.history(params.playbookId),
384540
+ playbookSave: async (params) => requireObs(deps).playbooks.versioning.save(params.playbookId, params.def, params.comment),
384541
+ playbookRollback: async (params) => requireObs(deps).playbooks.versioning.rollback(params.playbookId, params.version, params.comment),
384542
+ playbookDiff: async (params) => requireObs(deps).playbooks.versioning.diff(params.playbookId, params.a, params.b),
384543
+ // ── cloud inventory ─────────────────────────────────────────────────────
384544
+ cloudSummary: async () => requireObs(deps).cloud.summary(),
384545
+ cloudQuery: async (params) => requireObs(deps).cloud.query(params),
384546
+ cloudSync: async () => requireObs(deps).cloud.sync(),
384547
+ cloudAddAccount: async (params) => {
384548
+ requireObs(deps).cloud.addAccount(params);
384549
+ return { ok: true };
384550
+ },
384551
+ // ── live dashboard hub ──────────────────────────────────────────────────
384552
+ liveDashboardState: async () => requireObs(deps).liveDashboard.lastState() ?? await requireObs(deps).dashboard.state(),
384553
+ liveDashboardSubscriberCount: async () => ({ count: requireObs(deps).liveDashboard.subscriberCount() })
384554
+ };
384555
+ }
384556
+
383989
384557
  // packages/backend/src/services/ResourceMonitorService.ts
383990
384558
  var import_os2 = __toESM(require("os"), 1);
383991
384559
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
@@ -385995,6 +386563,7 @@ async function startGyBackend() {
385995
386563
  }
385996
386564
  });
385997
386565
  console.log(`[gybackend] Observability wired: dashboard state available (hosts=${observability.metricsLedger.hosts().length})`);
386566
+ agentService.setObservability(observability);
385998
386567
  if (settingsService.getSettings().sessionLogging?.enabled) {
385999
386568
  const logDir = import_node_path28.default.join(
386000
386569
  import_node_process2.default.env.GYSHELL_STORE_DIR || "",
@@ -386434,7 +387003,13 @@ async function startGyBackend() {
386434
387003
  gatewayService.broadcastRaw("tools:builtInUpdated", summary);
386435
387004
  return summary;
386436
387005
  }
386437
- }
387006
+ },
387007
+ // Observability bridge (v2.9.x): exposes the 9 platform capabilities
387008
+ // (metrics export, secrets, on-call, cost, recording, gitops, playbooks,
387009
+ // cloud, live dashboard) as observability:* RPC methods.
387010
+ observabilityBridge: createObservabilityBridge({
387011
+ observability: () => observability
387012
+ })
386438
387013
  })
386439
387014
  });
386440
387015
  await wsGatewayControlService.applyPolicy(startupPolicy);