rterm-backend 3.7.6 → 3.7.7
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 +167 -88
- package/package.json +1 -1
package/bin/gybackend.cjs
CHANGED
|
@@ -276397,9 +276397,12 @@ var init_compoundingStore = __esm({
|
|
|
276397
276397
|
init_betterSqlite3Runtime();
|
|
276398
276398
|
init_historyStoragePaths();
|
|
276399
276399
|
COMPOUNDING_DB_FILE = "gyshell-compounding.sqlite";
|
|
276400
|
-
CompoundingStore = class {
|
|
276400
|
+
CompoundingStore = class _CompoundingStore {
|
|
276401
276401
|
filePath;
|
|
276402
276402
|
db;
|
|
276403
|
+
/** Avoid sync SQLite on every agent turn (desktop freeze). Invalidated on writes. */
|
|
276404
|
+
promptCache = null;
|
|
276405
|
+
static PROMPT_CACHE_MS = 2e3;
|
|
276403
276406
|
constructor(options) {
|
|
276404
276407
|
this.filePath = options?.filePath || import_node_path28.default.join(resolveHistoryStorageDir(), COMPOUNDING_DB_FILE);
|
|
276405
276408
|
import_node_fs12.default.mkdirSync(import_node_path28.default.dirname(this.filePath), { recursive: true });
|
|
@@ -276453,6 +276456,7 @@ var init_compoundingStore = __esm({
|
|
|
276453
276456
|
recordLessons(lessons, runId) {
|
|
276454
276457
|
const now = Date.now();
|
|
276455
276458
|
const out = [];
|
|
276459
|
+
this.promptCache = null;
|
|
276456
276460
|
try {
|
|
276457
276461
|
const sel = this.db.prepare("SELECT * FROM lessons WHERE fingerprint = ?");
|
|
276458
276462
|
const ins = this.db.prepare(
|
|
@@ -276506,6 +276510,7 @@ var init_compoundingStore = __esm({
|
|
|
276506
276510
|
}
|
|
276507
276511
|
}
|
|
276508
276512
|
upsertEstateFact(input) {
|
|
276513
|
+
this.promptCache = null;
|
|
276509
276514
|
try {
|
|
276510
276515
|
const now = Date.now();
|
|
276511
276516
|
this.db.prepare(
|
|
@@ -276552,6 +276557,7 @@ var init_compoundingStore = __esm({
|
|
|
276552
276557
|
}
|
|
276553
276558
|
}
|
|
276554
276559
|
upsertGoal(input) {
|
|
276560
|
+
this.promptCache = null;
|
|
276555
276561
|
try {
|
|
276556
276562
|
this.db.prepare(
|
|
276557
276563
|
`INSERT INTO goals (id, session_id, text, status, blocked_by, next_probe, updated_at)
|
|
@@ -276589,6 +276595,7 @@ var init_compoundingStore = __esm({
|
|
|
276589
276595
|
}
|
|
276590
276596
|
}
|
|
276591
276597
|
recordProbe(sessionId, tag, hypothesis, command, ok) {
|
|
276598
|
+
this.promptCache = null;
|
|
276592
276599
|
try {
|
|
276593
276600
|
this.db.prepare(
|
|
276594
276601
|
`INSERT INTO probes (session_id, tag, hypothesis, command, ok, at)
|
|
@@ -276620,6 +276627,11 @@ var init_compoundingStore = __esm({
|
|
|
276620
276627
|
*/
|
|
276621
276628
|
promptBlock(maxChars = 4e3) {
|
|
276622
276629
|
try {
|
|
276630
|
+
const now = Date.now();
|
|
276631
|
+
if (this.promptCache && now - this.promptCache.at < _CompoundingStore.PROMPT_CACHE_MS) {
|
|
276632
|
+
const cached2 = this.promptCache.text;
|
|
276633
|
+
return cached2.length > maxChars ? cached2.slice(0, maxChars) + "\n\u2026" : cached2;
|
|
276634
|
+
}
|
|
276623
276635
|
const lessons = this.listLessons(20);
|
|
276624
276636
|
const facts = this.listEstateFacts();
|
|
276625
276637
|
const lines = ["# Compounding knowledge (auto)"];
|
|
@@ -276641,6 +276653,7 @@ var init_compoundingStore = __esm({
|
|
|
276641
276653
|
}
|
|
276642
276654
|
}
|
|
276643
276655
|
const text = lines.join("\n");
|
|
276656
|
+
this.promptCache = { at: now, text };
|
|
276644
276657
|
return text.length > maxChars ? text.slice(0, maxChars) + "\n\u2026" : text;
|
|
276645
276658
|
} catch {
|
|
276646
276659
|
return "";
|
|
@@ -366951,6 +366964,11 @@ function reconcileToolCalls(toolCalls) {
|
|
|
366951
366964
|
}
|
|
366952
366965
|
return result;
|
|
366953
366966
|
}
|
|
366967
|
+
var TOOL_RESULT_MAX_CHARS = 32768;
|
|
366968
|
+
function stringifyToolResult(result) {
|
|
366969
|
+
const raw = typeof result === "string" ? result : JSON.stringify(result);
|
|
366970
|
+
return clipTextMiddle(raw, TOOL_RESULT_MAX_CHARS);
|
|
366971
|
+
}
|
|
366954
366972
|
function clipTextMiddle(input, maxChars) {
|
|
366955
366973
|
if (maxChars <= 0) return "";
|
|
366956
366974
|
if (input.length <= maxChars) return input;
|
|
@@ -368873,7 +368891,7 @@ Actually, your intention might be different. Please re-read the description of t
|
|
|
368873
368891
|
try {
|
|
368874
368892
|
const pluginArgs = typeof toolCall.args === "string" ? JSON.parse(toolCall.args) : toolCall.args || {};
|
|
368875
368893
|
const pluginResult = await pluginHandler(pluginArgs);
|
|
368876
|
-
result =
|
|
368894
|
+
result = stringifyToolResult(pluginResult);
|
|
368877
368895
|
} catch (err) {
|
|
368878
368896
|
result = `Plugin tool "${toolCall.name}" error: ${err.message}`;
|
|
368879
368897
|
}
|
|
@@ -369161,7 +369179,7 @@ Actually, your intention might be different. Please re-read the description of t
|
|
|
369161
369179
|
const pluginHandler = this.pluginTools.get(name);
|
|
369162
369180
|
if (pluginHandler) {
|
|
369163
369181
|
const result = await pluginHandler(args);
|
|
369164
|
-
return
|
|
369182
|
+
return stringifyToolResult(result);
|
|
369165
369183
|
}
|
|
369166
369184
|
return `Tool "${name}" is not supported in parallel execution mode.`;
|
|
369167
369185
|
}
|
|
@@ -369242,7 +369260,7 @@ Actually, your intention might be different. Please re-read the description of t
|
|
|
369242
369260
|
args,
|
|
369243
369261
|
signal
|
|
369244
369262
|
);
|
|
369245
|
-
resultText =
|
|
369263
|
+
resultText = stringifyToolResult(result);
|
|
369246
369264
|
} catch (err) {
|
|
369247
369265
|
if (this.helpers.isAbortError(err)) throw err;
|
|
369248
369266
|
resultText = err instanceof Error ? err.message : String(err);
|
|
@@ -373021,6 +373039,22 @@ var WebSocketRpcError = class extends Error {
|
|
|
373021
373039
|
this.code = code;
|
|
373022
373040
|
}
|
|
373023
373041
|
};
|
|
373042
|
+
function httpRouteMatches(pattern, pathname) {
|
|
373043
|
+
if (pattern === pathname) return true;
|
|
373044
|
+
if (pattern.endsWith("/*")) {
|
|
373045
|
+
const prefix = pattern.slice(0, -1);
|
|
373046
|
+
const base = pattern.slice(0, -2);
|
|
373047
|
+
return pathname === base || pathname.startsWith(prefix) || pathname.startsWith(base + "/");
|
|
373048
|
+
}
|
|
373049
|
+
const a = pattern.split("/").filter(Boolean);
|
|
373050
|
+
const b = pathname.split("/").filter(Boolean);
|
|
373051
|
+
if (a.length !== b.length) return false;
|
|
373052
|
+
for (let i = 0; i < a.length; i++) {
|
|
373053
|
+
if (a[i].startsWith(":")) continue;
|
|
373054
|
+
if (a[i] !== b[i]) return false;
|
|
373055
|
+
}
|
|
373056
|
+
return true;
|
|
373057
|
+
}
|
|
373024
373058
|
function createDefaultWebSocketServerFactory(httpRoutes) {
|
|
373025
373059
|
return ({ host, port }) => {
|
|
373026
373060
|
if (!httpRoutes || httpRoutes.length === 0) {
|
|
@@ -373043,7 +373077,7 @@ function createDefaultWebSocketServerFactory(httpRoutes) {
|
|
|
373043
373077
|
).pathname;
|
|
373044
373078
|
} catch {
|
|
373045
373079
|
}
|
|
373046
|
-
const route = routes.find((r) => r.path
|
|
373080
|
+
const route = routes.find((r) => httpRouteMatches(r.path, pathname));
|
|
373047
373081
|
if (!route) {
|
|
373048
373082
|
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
373049
373083
|
res.end("not found");
|
|
@@ -384954,8 +384988,9 @@ var IdleTimeoutService = class {
|
|
|
384954
384988
|
// ../../packages/backend/src/services/Gateway/restApi.ts
|
|
384955
384989
|
function matchRestRoute(routes, method, path33) {
|
|
384956
384990
|
const normalized = path33.replace(/\/+$/, "") || "/";
|
|
384991
|
+
const verb = method.toUpperCase();
|
|
384957
384992
|
for (const route of routes) {
|
|
384958
|
-
if (route.method !==
|
|
384993
|
+
if (route.method !== verb) continue;
|
|
384959
384994
|
const patternParts = route.path.split("/").filter(Boolean);
|
|
384960
384995
|
const pathParts = normalized.split("/").filter(Boolean);
|
|
384961
384996
|
if (patternParts.length !== pathParts.length) continue;
|
|
@@ -384976,36 +385011,18 @@ function matchRestRoute(routes, method, path33) {
|
|
|
384976
385011
|
}
|
|
384977
385012
|
function defaultRestRoutes() {
|
|
384978
385013
|
return [
|
|
385014
|
+
{ method: "GET", path: "/api/v1/health", gatewayMethod: "gateway:ping", description: "Liveness check" },
|
|
385015
|
+
{ method: "GET", path: "/api/v1/methods", gatewayMethod: "gateway:describe", description: "List all gateway RPC methods" },
|
|
385016
|
+
{ method: "GET", path: "/api/v1/openapi.json", gatewayMethod: "__openapi", description: "OpenAPI 3 document for this REST overlay + RPC escape hatch" },
|
|
385017
|
+
{ method: "GET", path: "/api/v1/terminals", gatewayMethod: "terminal:list", description: "List terminal tabs" },
|
|
385018
|
+
{ method: "GET", path: "/api/v1/sessions", gatewayMethod: "session:list", description: "List chat sessions" },
|
|
384979
385019
|
{
|
|
384980
|
-
method: "
|
|
384981
|
-
path: "/api/v1/health",
|
|
384982
|
-
gatewayMethod: "gateway:ping",
|
|
384983
|
-
description: "Liveness check"
|
|
384984
|
-
},
|
|
384985
|
-
{
|
|
384986
|
-
method: "GET",
|
|
384987
|
-
path: "/api/v1/methods",
|
|
384988
|
-
gatewayMethod: "gateway:describe",
|
|
384989
|
-
description: "List all gateway methods (self-describing)"
|
|
384990
|
-
},
|
|
384991
|
-
{
|
|
384992
|
-
method: "GET",
|
|
384993
|
-
path: "/api/v1/terminals",
|
|
384994
|
-
gatewayMethod: "terminal:list",
|
|
384995
|
-
description: "List terminal tabs"
|
|
384996
|
-
},
|
|
384997
|
-
{
|
|
384998
|
-
method: "GET",
|
|
385020
|
+
method: "POST",
|
|
384999
385021
|
path: "/api/v1/sessions",
|
|
385000
|
-
gatewayMethod: "
|
|
385001
|
-
description: "
|
|
385002
|
-
},
|
|
385003
|
-
{
|
|
385004
|
-
method: "GET",
|
|
385005
|
-
path: "/api/v1/skills",
|
|
385006
|
-
gatewayMethod: "skills:getAll",
|
|
385007
|
-
description: "List loaded skills"
|
|
385022
|
+
gatewayMethod: "gateway:createSession",
|
|
385023
|
+
description: "Create a chat/agent session"
|
|
385008
385024
|
},
|
|
385025
|
+
{ method: "GET", path: "/api/v1/skills", gatewayMethod: "skills:getAll", description: "List loaded skills" },
|
|
385009
385026
|
{
|
|
385010
385027
|
method: "GET",
|
|
385011
385028
|
path: "/api/v1/observability/metrics",
|
|
@@ -385022,13 +385039,13 @@ function defaultRestRoutes() {
|
|
|
385022
385039
|
method: "GET",
|
|
385023
385040
|
path: "/api/v1/observability/apm",
|
|
385024
385041
|
gatewayMethod: "observability:apmSummary",
|
|
385025
|
-
description: "APM summary
|
|
385042
|
+
description: "APM summary"
|
|
385026
385043
|
},
|
|
385027
385044
|
{
|
|
385028
385045
|
method: "GET",
|
|
385029
385046
|
path: "/api/v1/history/search",
|
|
385030
385047
|
gatewayMethod: "history:search",
|
|
385031
|
-
description: "Cross-session history search (?q
|
|
385048
|
+
description: "Cross-session history search (?q=)",
|
|
385032
385049
|
buildParams: (_p, body) => {
|
|
385033
385050
|
const b = body ?? {};
|
|
385034
385051
|
return { query: b.q ?? b.query ?? "" };
|
|
@@ -385048,17 +385065,18 @@ function defaultRestRoutes() {
|
|
|
385048
385065
|
method: "GET",
|
|
385049
385066
|
path: "/api/v1/terminals/:id/buffer",
|
|
385050
385067
|
gatewayMethod: "terminal:getBufferDelta",
|
|
385051
|
-
description: "Read
|
|
385068
|
+
description: "Read terminal output delta (?fromOffset=)",
|
|
385052
385069
|
buildParams: (p, body) => {
|
|
385053
385070
|
const b = body ?? {};
|
|
385054
|
-
|
|
385071
|
+
const n2 = Number(b.fromOffset ?? 0);
|
|
385072
|
+
return { terminalId: p.id, fromOffset: Number.isFinite(n2) ? n2 : 0 };
|
|
385055
385073
|
}
|
|
385056
385074
|
},
|
|
385057
385075
|
{
|
|
385058
385076
|
method: "POST",
|
|
385059
385077
|
path: "/api/v1/sessions/:id/chat",
|
|
385060
385078
|
gatewayMethod: "agent:startTask",
|
|
385061
|
-
description: "Send a message
|
|
385079
|
+
description: "Send a message (blocking until the run finishes \u2014 prefer chat-async)",
|
|
385062
385080
|
buildParams: (p, body) => {
|
|
385063
385081
|
const b = body ?? {};
|
|
385064
385082
|
return { sessionId: p.id, userInput: b.message ?? b.userInput ?? "" };
|
|
@@ -385066,17 +385084,66 @@ function defaultRestRoutes() {
|
|
|
385066
385084
|
},
|
|
385067
385085
|
{
|
|
385068
385086
|
method: "POST",
|
|
385069
|
-
path: "/api/v1/
|
|
385070
|
-
gatewayMethod: "",
|
|
385071
|
-
description: "
|
|
385072
|
-
buildParams: (
|
|
385087
|
+
path: "/api/v1/sessions/:id/chat-async",
|
|
385088
|
+
gatewayMethod: "agent:startTaskAsync",
|
|
385089
|
+
description: "Start an agent turn without waiting; subscribe to WS gateway:event for tokens",
|
|
385090
|
+
buildParams: (p, body) => {
|
|
385073
385091
|
const b = body ?? {};
|
|
385074
|
-
return {
|
|
385092
|
+
return { sessionId: p.id, userInput: b.message ?? b.userInput ?? "" };
|
|
385075
385093
|
}
|
|
385094
|
+
},
|
|
385095
|
+
{
|
|
385096
|
+
method: "POST",
|
|
385097
|
+
path: "/api/v1/rpc",
|
|
385098
|
+
gatewayMethod: "",
|
|
385099
|
+
description: "Escape hatch: any gateway method {method, params}"
|
|
385076
385100
|
}
|
|
385077
385101
|
];
|
|
385078
385102
|
}
|
|
385103
|
+
function buildOpenApiDocument() {
|
|
385104
|
+
const routes = defaultRestRoutes();
|
|
385105
|
+
const paths = {};
|
|
385106
|
+
for (const r of routes) {
|
|
385107
|
+
if (r.gatewayMethod === "__openapi") continue;
|
|
385108
|
+
const item = paths[r.path] || {};
|
|
385109
|
+
item[r.method.toLowerCase()] = {
|
|
385110
|
+
summary: r.description,
|
|
385111
|
+
operationId: `${r.method}_${r.path.replace(/[^a-zA-Z0-9]+/g, "_")}`,
|
|
385112
|
+
tags: ["rest"],
|
|
385113
|
+
...r.method === "POST" ? {
|
|
385114
|
+
requestBody: {
|
|
385115
|
+
content: { "application/json": { schema: { type: "object" } } }
|
|
385116
|
+
}
|
|
385117
|
+
} : {},
|
|
385118
|
+
responses: { "200": { description: "OK" }, "401": { description: "Unauthorized" } }
|
|
385119
|
+
};
|
|
385120
|
+
paths[r.path] = item;
|
|
385121
|
+
}
|
|
385122
|
+
const rpcMethods = [...CORE_METHODS, DESCRIBE_METHOD].map((m2) => m2.name);
|
|
385123
|
+
return {
|
|
385124
|
+
openapi: "3.0.3",
|
|
385125
|
+
info: {
|
|
385126
|
+
title: "RTerm HTTP overlay",
|
|
385127
|
+
version: "1.0.0",
|
|
385128
|
+
description: `Thin REST on the same port as the WebSocket JSON-RPC gateway. Streaming agent/PTY traffic stays on ws://. POST /api/v1/rpc reaches every RPC method. Core RPC methods: ${rpcMethods.length}. Categories: ${METHOD_CATEGORIES.join(", ")}.`
|
|
385129
|
+
},
|
|
385130
|
+
paths,
|
|
385131
|
+
"x-gateway-rpc-methods": rpcMethods
|
|
385132
|
+
};
|
|
385133
|
+
}
|
|
385079
385134
|
async function handleRestRequest(routes, dispatch, req) {
|
|
385135
|
+
const verb = req.method.toUpperCase();
|
|
385136
|
+
if (verb === "OPTIONS") {
|
|
385137
|
+
return {
|
|
385138
|
+
status: 204,
|
|
385139
|
+
body: "",
|
|
385140
|
+
headers: {
|
|
385141
|
+
"access-control-allow-origin": "*",
|
|
385142
|
+
"access-control-allow-methods": "GET, POST, OPTIONS",
|
|
385143
|
+
"access-control-allow-headers": "Authorization, Content-Type"
|
|
385144
|
+
}
|
|
385145
|
+
};
|
|
385146
|
+
}
|
|
385080
385147
|
const match = matchRestRoute(routes, req.method, req.path);
|
|
385081
385148
|
if (!match) {
|
|
385082
385149
|
return {
|
|
@@ -385084,12 +385151,18 @@ async function handleRestRequest(routes, dispatch, req) {
|
|
|
385084
385151
|
body: { error: "not_found", message: `No REST route for ${req.method} ${req.path}` }
|
|
385085
385152
|
};
|
|
385086
385153
|
}
|
|
385154
|
+
if (match.route.gatewayMethod === "__openapi") {
|
|
385155
|
+
return { status: 200, body: buildOpenApiDocument() };
|
|
385156
|
+
}
|
|
385087
385157
|
let gatewayMethod = match.route.gatewayMethod;
|
|
385088
385158
|
let params;
|
|
385089
385159
|
if (gatewayMethod === "") {
|
|
385090
385160
|
const raw = req.body ?? {};
|
|
385091
385161
|
if (!raw.method) {
|
|
385092
|
-
return {
|
|
385162
|
+
return {
|
|
385163
|
+
status: 400,
|
|
385164
|
+
body: { error: "bad_request", message: 'POST /api/v1/rpc needs {"method": "...", "params": {...}}' }
|
|
385165
|
+
};
|
|
385093
385166
|
}
|
|
385094
385167
|
gatewayMethod = raw.method;
|
|
385095
385168
|
params = raw.params ?? {};
|
|
@@ -385105,6 +385178,52 @@ async function handleRestRequest(routes, dispatch, req) {
|
|
|
385105
385178
|
return { status, body: { error: "gateway_error", message } };
|
|
385106
385179
|
}
|
|
385107
385180
|
}
|
|
385181
|
+
var JSON_HEADERS = { "content-type": "application/json; charset=utf-8" };
|
|
385182
|
+
function readJsonBody(req) {
|
|
385183
|
+
return new Promise((resolve2) => {
|
|
385184
|
+
let data = "";
|
|
385185
|
+
req.on?.("data", (d) => {
|
|
385186
|
+
data += String(d ?? "");
|
|
385187
|
+
if (data.length > 2e6) {
|
|
385188
|
+
resolve2({});
|
|
385189
|
+
}
|
|
385190
|
+
});
|
|
385191
|
+
req.on?.("end", () => {
|
|
385192
|
+
try {
|
|
385193
|
+
resolve2(data ? JSON.parse(data) : {});
|
|
385194
|
+
} catch {
|
|
385195
|
+
resolve2({});
|
|
385196
|
+
}
|
|
385197
|
+
});
|
|
385198
|
+
});
|
|
385199
|
+
}
|
|
385200
|
+
function makeRestCatchAllHandler(opts) {
|
|
385201
|
+
const routes = defaultRestRoutes();
|
|
385202
|
+
return async (req, res) => {
|
|
385203
|
+
const r = req;
|
|
385204
|
+
const s = res;
|
|
385205
|
+
try {
|
|
385206
|
+
if (!await opts.isAuthorized(r)) {
|
|
385207
|
+
s.writeHead?.(401, JSON_HEADERS);
|
|
385208
|
+
s.end?.(JSON.stringify({ error: "unauthorized" }));
|
|
385209
|
+
return;
|
|
385210
|
+
}
|
|
385211
|
+
const url2 = new URL(r.url ?? "/", "http://localhost");
|
|
385212
|
+
const body = r.method === "POST" || r.method === "PUT" ? await readJsonBody(r) : Object.fromEntries(url2.searchParams.entries());
|
|
385213
|
+
const result = await handleRestRequest(routes, opts.dispatch, {
|
|
385214
|
+
method: r.method ?? "GET",
|
|
385215
|
+
path: url2.pathname,
|
|
385216
|
+
body
|
|
385217
|
+
});
|
|
385218
|
+
s.writeHead?.(result.status, { ...JSON_HEADERS, ...result.headers ?? {} });
|
|
385219
|
+
if (result.body === "" || result.body === void 0) s.end?.();
|
|
385220
|
+
else s.end?.(typeof result.body === "string" ? result.body : JSON.stringify(result.body));
|
|
385221
|
+
} catch (e) {
|
|
385222
|
+
s.writeHead?.(500, JSON_HEADERS);
|
|
385223
|
+
s.end?.(JSON.stringify({ error: "internal", message: e instanceof Error ? e.message : String(e) }));
|
|
385224
|
+
}
|
|
385225
|
+
};
|
|
385226
|
+
}
|
|
385108
385227
|
|
|
385109
385228
|
// ../../packages/backend/src/services/Gateway/gatewayRateLimit.ts
|
|
385110
385229
|
var GatewayRateLimiter = class {
|
|
@@ -396172,51 +396291,8 @@ async function startGyBackend() {
|
|
|
396172
396291
|
return await target.handleRequest(method, params);
|
|
396173
396292
|
};
|
|
396174
396293
|
const buildRestHttpRoutesSync = (opts) => {
|
|
396175
|
-
|
|
396176
|
-
const staticRoutes = routes.filter((r) => !r.path.includes(":")).map((route) => ({
|
|
396177
|
-
path: route.path,
|
|
396178
|
-
handler: makeRestHandler(routes, opts)
|
|
396179
|
-
}));
|
|
396180
|
-
return staticRoutes;
|
|
396294
|
+
return [{ path: "/api/v1/*", handler: makeRestCatchAllHandler(opts) }];
|
|
396181
396295
|
};
|
|
396182
|
-
const makeRestHandler = (routes, opts) => {
|
|
396183
|
-
return async (req, res) => {
|
|
396184
|
-
const r = req;
|
|
396185
|
-
const s = res;
|
|
396186
|
-
try {
|
|
396187
|
-
if (!await opts.isAuthorized(r)) {
|
|
396188
|
-
s.writeHead?.(401, { "content-type": "application/json" });
|
|
396189
|
-
s.end?.(JSON.stringify({ error: "unauthorized" }));
|
|
396190
|
-
return;
|
|
396191
|
-
}
|
|
396192
|
-
const url2 = new URL(r.url ?? "/", "http://localhost");
|
|
396193
|
-
const body = r.method === "POST" ? await readJsonBody(r) : Object.fromEntries(url2.searchParams.entries());
|
|
396194
|
-
const result = await handleRestRequest(routes, opts.dispatch, {
|
|
396195
|
-
method: r.method ?? "GET",
|
|
396196
|
-
path: url2.pathname,
|
|
396197
|
-
body
|
|
396198
|
-
});
|
|
396199
|
-
s.writeHead?.(result.status, { "content-type": "application/json" });
|
|
396200
|
-
s.end?.(JSON.stringify(result.body));
|
|
396201
|
-
} catch (e) {
|
|
396202
|
-
s.writeHead?.(500, { "content-type": "application/json" });
|
|
396203
|
-
s.end?.(JSON.stringify({ error: "internal", message: e instanceof Error ? e.message : String(e) }));
|
|
396204
|
-
}
|
|
396205
|
-
};
|
|
396206
|
-
};
|
|
396207
|
-
const readJsonBody = (req) => new Promise((resolve2) => {
|
|
396208
|
-
let data = "";
|
|
396209
|
-
req.on?.("data", (d) => {
|
|
396210
|
-
data += String(d ?? "");
|
|
396211
|
-
});
|
|
396212
|
-
req.on?.("end", () => {
|
|
396213
|
-
try {
|
|
396214
|
-
resolve2(data ? JSON.parse(data) : {});
|
|
396215
|
-
} catch {
|
|
396216
|
-
resolve2({});
|
|
396217
|
-
}
|
|
396218
|
-
});
|
|
396219
|
-
});
|
|
396220
396296
|
const wsGatewayControlService = new WebSocketGatewayControlService({
|
|
396221
396297
|
createAdapter: (host, port, ipFilter) => {
|
|
396222
396298
|
const adapter = new WebSocketGatewayAdapter(gatewayService, {
|
|
@@ -396712,6 +396788,9 @@ async function startGyBackend() {
|
|
|
396712
396788
|
console.log(
|
|
396713
396789
|
`[gybackend] Live dashboard: http://${wsState.host}:${wsState.port}/dashboard`
|
|
396714
396790
|
);
|
|
396791
|
+
console.log(
|
|
396792
|
+
`[gybackend] REST API: http://${wsState.host}:${wsState.port}/api/v1/health (OpenAPI /api/v1/openapi.json)`
|
|
396793
|
+
);
|
|
396715
396794
|
} else {
|
|
396716
396795
|
console.log("[gybackend] WebSocket RPC endpoint: disabled");
|
|
396717
396796
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rterm-backend",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.7",
|
|
4
4
|
"description": "AI-native terminal & agentic-AI operations platform for Forward Deployed Engineers & SREs: AIOps closed-loop remediation, AI SRE, self-healing infrastructure, runbook automation, ChatOps; executes over SSH/WinRM/serial under policy with tamper-evident audit.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"forward-deployed-engineer",
|