@nekzus/liop-studio 1.0.0-alpha.5 → 1.0.0-alpha.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/dist/cli/index.js CHANGED
@@ -5,9 +5,9 @@ import { Command } from "commander";
5
5
  import pc2 from "picocolors";
6
6
 
7
7
  // src/server/index.ts
8
- import path from "path";
8
+ import path2 from "path";
9
9
  import process3 from "process";
10
- import { fileURLToPath } from "url";
10
+ import { fileURLToPath as fileURLToPath2 } from "url";
11
11
  import { serve } from "@hono/node-server";
12
12
  import { serveStatic } from "@hono/node-server/serve-static";
13
13
  import { TokenTelemetryEngine as TokenTelemetryEngine5 } from "@nekzus/liop";
@@ -63,10 +63,29 @@ function validateHttpTarget(targetUrl) {
63
63
  }
64
64
  return parsed;
65
65
  }
66
- function validateHostHeader(host, allowedHosts = ["localhost", "127.0.0.1", "0.0.0.0"]) {
66
+ function validateHostHeader(host, allowedHosts = [
67
+ "localhost",
68
+ "127.0.0.1",
69
+ "0.0.0.0",
70
+ "::1",
71
+ "[::1]"
72
+ ]) {
67
73
  if (!host) return false;
68
- const hostname = host.split(":")[0].toLowerCase();
69
- return allowedHosts.includes(hostname);
74
+ const trimmed = host.trim();
75
+ let hostname;
76
+ if (trimmed.startsWith("[")) {
77
+ const closingIndex = trimmed.indexOf("]");
78
+ hostname = closingIndex !== -1 ? trimmed.slice(0, closingIndex + 1) : trimmed;
79
+ } else if (trimmed.includes(":") && trimmed.indexOf(":") !== trimmed.lastIndexOf(":")) {
80
+ hostname = trimmed;
81
+ } else {
82
+ hostname = trimmed.split(":")[0];
83
+ }
84
+ hostname = hostname.toLowerCase();
85
+ return allowedHosts.some((allowed) => {
86
+ const normAllowed = allowed.toLowerCase();
87
+ return normAllowed === hostname || hostname === "[::1]" && normAllowed === "::1" || hostname === "::1" && normAllowed === "[::1]";
88
+ });
70
89
  }
71
90
 
72
91
  // src/transports/grpc.transport.ts
@@ -467,16 +486,22 @@ var GrpcTransport = class {
467
486
  connected = false;
468
487
  target;
469
488
  token;
489
+ tlsConfig;
470
490
  constructor(options) {
471
491
  this.target = options.target.replace(/^grpc:\/\//, "");
472
492
  this.token = options.token;
493
+ this.tlsConfig = options.tls;
473
494
  }
474
495
  isConnected() {
475
496
  return this.connected && this.client !== null;
476
497
  }
477
498
  async connect() {
478
499
  const tokenProvider = this.token || createStudioTokenProvider();
479
- this.client = new LiopRpcClient(this.target, void 0, tokenProvider);
500
+ const tls = this.tlsConfig || {
501
+ insecure: true,
502
+ suppressWarning: true
503
+ };
504
+ this.client = new LiopRpcClient(this.target, tls, tokenProvider);
480
505
  this.connected = true;
481
506
  }
482
507
  async disconnect() {
@@ -1191,9 +1216,7 @@ var MeshTransport = class {
1191
1216
  if (!this.isConnected()) {
1192
1217
  await this.connect();
1193
1218
  }
1194
- const clientAny = this.client;
1195
- const peerId = clientAny.meshNode?.getPeerId?.()?.toString() || "UnknownPeer";
1196
- const _connections = clientAny.meshNode?.node?.getConnections?.() || [];
1219
+ const peerId = this.client.peerId ?? "UnknownPeer";
1197
1220
  const latencyMs = Math.max(1, Math.round(performance.now() - tStart));
1198
1221
  const discovery = NetworkDiscoveryEngine.getInstance();
1199
1222
  const meshDiscovered = await discovery.scanNetwork("127.0.0.1").catch(() => []);
@@ -1878,12 +1901,40 @@ function createTransport(config) {
1878
1901
  }
1879
1902
  }
1880
1903
 
1881
- // src/server/index.ts
1904
+ // src/version.ts
1905
+ import fs from "fs";
1906
+ import path from "path";
1907
+ import { fileURLToPath } from "url";
1882
1908
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
1909
+ function getPackageVersion() {
1910
+ try {
1911
+ let currentDir = __dirname;
1912
+ for (let i = 0; i < 4; i++) {
1913
+ const candidate = path.join(currentDir, "package.json");
1914
+ if (fs.existsSync(candidate)) {
1915
+ const raw = fs.readFileSync(candidate, "utf-8");
1916
+ const parsed = JSON.parse(raw);
1917
+ if (parsed.name === "@nekzus/liop-studio" && typeof parsed.version === "string") {
1918
+ return parsed.version;
1919
+ }
1920
+ }
1921
+ currentDir = path.dirname(currentDir);
1922
+ }
1923
+ } catch {
1924
+ }
1925
+ return "1.0.0-alpha.5";
1926
+ }
1927
+ var STUDIO_VERSION = getPackageVersion();
1928
+
1929
+ // src/server/index.ts
1930
+ var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
1883
1931
  function createStudioServer(options = {}) {
1932
+ if (!process3.env.LIOP_SUPPRESS_TLS_WARNING) {
1933
+ process3.env.LIOP_SUPPRESS_TLS_WARNING = "true";
1934
+ }
1884
1935
  const app = new Hono();
1885
1936
  const port = options.port || 16e3;
1886
- const distPath = options.distPath || path.resolve(__dirname, "../../ui/dist");
1937
+ const distPath = options.distPath || path2.resolve(__dirname2, "../../ui/dist");
1887
1938
  let activeConfig = options.initialTarget || {
1888
1939
  type: "http",
1889
1940
  http: { url: process3.env.LIOP_MCP_URL || "http://127.0.0.1:15000/mcp" }
@@ -1916,7 +1967,7 @@ function createStudioServer(options = {}) {
1916
1967
  const isConnected = activeTransport.isConnected() && lastReport?.status === "online";
1917
1968
  return c.json({
1918
1969
  status: isConnected ? "healthy" : "offline",
1919
- version: "1.0.0",
1970
+ version: STUDIO_VERSION,
1920
1971
  targetType: activeConfig.type,
1921
1972
  connected: isConnected
1922
1973
  });
@@ -1932,7 +1983,7 @@ function createStudioServer(options = {}) {
1932
1983
  connected: isConnected,
1933
1984
  toolsCount: isConnected ? lastReport?.totalTools || 0 : 0,
1934
1985
  latencyMs: isConnected ? lastReport?.latencyMs || 0 : 0,
1935
- version: "1.0.0",
1986
+ version: STUDIO_VERSION,
1936
1987
  serverInfo: lastReport?.serverInfo
1937
1988
  });
1938
1989
  });
@@ -2197,7 +2248,11 @@ function resolveTargetConfig(target, options = {}) {
2197
2248
  if (isGrpcExplicit || /^([a-zA-Z0-9.-]+):(\d+)$/.test(trimmed) || trimmed.startsWith("grpc://")) {
2198
2249
  return {
2199
2250
  type: "grpc",
2200
- grpc: { target: trimmed, token }
2251
+ grpc: {
2252
+ target: trimmed,
2253
+ token,
2254
+ tls: { insecure: true, suppressWarning: true }
2255
+ }
2201
2256
  };
2202
2257
  }
2203
2258
  const parts = trimmed.split(/\s+/);
@@ -2210,6 +2265,9 @@ function resolveTargetConfig(target, options = {}) {
2210
2265
  };
2211
2266
  }
2212
2267
  async function runScan(targetStr, options) {
2268
+ if (!process4.env.LIOP_SUPPRESS_TLS_WARNING) {
2269
+ process4.env.LIOP_SUPPRESS_TLS_WARNING = "true";
2270
+ }
2213
2271
  const config = resolveTargetConfig(targetStr, options.token);
2214
2272
  const transport = createTransport(config);
2215
2273
  try {
@@ -2237,14 +2295,24 @@ async function main() {
2237
2295
  const program = new Command();
2238
2296
  program.name("liop-studio").description(
2239
2297
  "LIOP Sovereign Studio & Mesh Scanner (Universal MCP / LIOP Inspector)"
2240
- ).version("1.0.0-alpha.0").option("-p, --port <port>", "Port to bind local Studio server", "16000").option("--no-open", "Do not automatically open browser on launch").option(
2298
+ ).version(STUDIO_VERSION).option("-p, --port <port>", "Port to bind local Studio server", "16000").option("--no-open", "Do not automatically open browser on launch").option(
2241
2299
  "--stdio <command>",
2242
2300
  "Initial target: Stdio command (e.g. 'node server.js')"
2243
2301
  ).option("--http <url>", "Initial target: HTTP / SSE MCP URL").option("--grpc <target>", "Initial target: Native LIOP gRPC endpoint").option("--mesh <multiaddr>", "Initial target: Libp2p P2P bootstrap node").option(
2244
2302
  "--token <token>",
2245
2303
  "Bearer or access token for target authentication"
2304
+ ).option("--tls-ca <path>", "Path to root CA certificate for gRPC target").option(
2305
+ "--tls-cert <path>",
2306
+ "Path to client certificate chain for gRPC target"
2307
+ ).option("--tls-key <path>", "Path to client private key for gRPC target").option(
2308
+ "--insecure",
2309
+ "Explicitly permit unencrypted gRPC credentials",
2310
+ true
2246
2311
  ).action(async (options) => {
2247
2312
  const port = Number.parseInt(options.port, 10) || 16e3;
2313
+ if (!options.tlsCa && !options.tlsCert && !options.tlsKey) {
2314
+ process5.env.LIOP_SUPPRESS_TLS_WARNING = "true";
2315
+ }
2248
2316
  let initialTarget;
2249
2317
  if (options.stdio) {
2250
2318
  const parts = options.stdio.trim().split(/\s+/);
@@ -2260,7 +2328,18 @@ async function main() {
2260
2328
  } else if (options.grpc) {
2261
2329
  initialTarget = {
2262
2330
  type: "grpc",
2263
- grpc: { target: options.grpc, token: options.token }
2331
+ grpc: {
2332
+ target: options.grpc,
2333
+ token: options.token,
2334
+ tls: options.tlsCa ? {
2335
+ rootCert: options.tlsCa,
2336
+ certChain: options.tlsCert,
2337
+ privateKey: options.tlsKey
2338
+ } : {
2339
+ insecure: true,
2340
+ suppressWarning: true
2341
+ }
2342
+ }
2264
2343
  };
2265
2344
  } else if (options.mesh) {
2266
2345
  initialTarget = {