@nekzus/liop 2.4.6 → 2.5.0-beta.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.
Files changed (95) hide show
  1. package/NOTICE +19 -0
  2. package/README.md +66 -34
  3. package/dist/bin/agent.js +673 -82
  4. package/dist/bin/agent.js.map +1 -1
  5. package/dist/bridge.d.ts +3 -3
  6. package/dist/bridge.js +3 -3
  7. package/dist/{chunk-PYKRQAER.js → chunk-2KSO3W4A.js} +2 -2
  8. package/dist/chunk-2KSO3W4A.js.map +1 -0
  9. package/dist/{chunk-32ADSAJS.js → chunk-2STZHJ24.js} +14 -4
  10. package/dist/chunk-2STZHJ24.js.map +1 -0
  11. package/dist/chunk-3QH44NKZ.js +115 -0
  12. package/dist/chunk-3QH44NKZ.js.map +1 -0
  13. package/dist/{chunk-WCCGE4QR.js → chunk-5SWHE62F.js} +196 -33
  14. package/dist/chunk-5SWHE62F.js.map +1 -0
  15. package/dist/{chunk-SONUORBT.js → chunk-7BSCUYUE.js} +2 -2
  16. package/dist/chunk-7BSCUYUE.js.map +1 -0
  17. package/dist/{chunk-QLCOEP5J.js → chunk-7PITYWOV.js} +2 -2
  18. package/dist/chunk-7PITYWOV.js.map +1 -0
  19. package/dist/{chunk-T5IUZF47.js → chunk-EJ426URA.js} +109 -7
  20. package/dist/chunk-EJ426URA.js.map +1 -0
  21. package/dist/{chunk-CRZBVFDV.js → chunk-FCFTYOAS.js} +243 -66
  22. package/dist/chunk-FCFTYOAS.js.map +1 -0
  23. package/dist/chunk-FTF6AMF6.js +3 -0
  24. package/dist/{chunk-RWRRBYG4.js.map → chunk-FTF6AMF6.js.map} +1 -1
  25. package/dist/{chunk-OUUTDSOW.js → chunk-IK7CGWAZ.js} +3 -3
  26. package/dist/chunk-IK7CGWAZ.js.map +1 -0
  27. package/dist/chunk-K3DGJLUY.js +106 -0
  28. package/dist/chunk-K3DGJLUY.js.map +1 -0
  29. package/dist/{chunk-U5BZ66VX.js → chunk-PAICJCKJ.js} +60 -175
  30. package/dist/chunk-PAICJCKJ.js.map +1 -0
  31. package/dist/chunk-PUDETPL4.js +279 -0
  32. package/dist/chunk-PUDETPL4.js.map +1 -0
  33. package/dist/{chunk-547TYL27.js → chunk-UJFWPRDM.js} +164 -1389
  34. package/dist/chunk-UJFWPRDM.js.map +1 -0
  35. package/dist/chunk-VRB5HUYU.js +1492 -0
  36. package/dist/chunk-VRB5HUYU.js.map +1 -0
  37. package/dist/{chunk-GA3Q2S7O.js → chunk-VRDZ5IKE.js} +5 -5
  38. package/dist/chunk-VRDZ5IKE.js.map +1 -0
  39. package/dist/chunk-WPTOJYN5.js +181 -0
  40. package/dist/chunk-WPTOJYN5.js.map +1 -0
  41. package/dist/{chunk-74CISO2I.js → chunk-XRDN232O.js} +28 -4
  42. package/dist/chunk-XRDN232O.js.map +1 -0
  43. package/dist/{chunk-JIJPZFR2.js → chunk-Y62GORQF.js} +2 -2
  44. package/dist/chunk-Y62GORQF.js.map +1 -0
  45. package/dist/chunk-ZP3VVXOI.js +66 -0
  46. package/dist/chunk-ZP3VVXOI.js.map +1 -0
  47. package/dist/client.d.ts +4 -3
  48. package/dist/client.js +10 -8
  49. package/dist/gateway.d.ts +4 -4
  50. package/dist/gateway.js +10 -9
  51. package/dist/{hybrid-CF__0YnC.d.ts → hybrid-DWe1bMoV.d.ts} +5 -4
  52. package/dist/{index-cMV0_yD9.d.ts → index-BuEQtBHD.d.ts} +39 -34
  53. package/dist/{index-BW95kAL4.d.ts → index-CdW8j8Bn.d.ts} +9 -72
  54. package/dist/index.d.ts +172 -48
  55. package/dist/index.js +20 -15
  56. package/dist/index.js.map +1 -1
  57. package/dist/kyber-CGOA7Q6A.js +3 -0
  58. package/dist/{kyber-3ULIJSE3.js.map → kyber-CGOA7Q6A.js.map} +1 -1
  59. package/dist/mesh.d.ts +27 -143
  60. package/dist/mesh.js +4 -3
  61. package/dist/node-B0b2vUFS.d.ts +164 -0
  62. package/dist/protocol/liop_core.proto +3 -0
  63. package/dist/server.d.ts +3 -3
  64. package/dist/server.js +7 -6
  65. package/dist/types-CzRSOlOo.d.ts +452 -0
  66. package/dist/types.d.ts +1 -1
  67. package/dist/types.js +1 -1
  68. package/dist/verifier-XFU7ZB2W.js +6 -0
  69. package/dist/{verifier-3FAKCFNN.js.map → verifier-XFU7ZB2W.js.map} +1 -1
  70. package/dist/workers/logic-execution.js +3 -3
  71. package/dist/workers/logic-execution.js.map +1 -1
  72. package/dist/workers/zk-verifier.js +1 -1
  73. package/dist/workers/zk-verifier.js.map +1 -1
  74. package/package.json +50 -38
  75. package/dist/chunk-32ADSAJS.js.map +0 -1
  76. package/dist/chunk-547TYL27.js.map +0 -1
  77. package/dist/chunk-72MNYFR6.js +0 -64
  78. package/dist/chunk-72MNYFR6.js.map +0 -1
  79. package/dist/chunk-74CISO2I.js.map +0 -1
  80. package/dist/chunk-CRZBVFDV.js.map +0 -1
  81. package/dist/chunk-GA3Q2S7O.js.map +0 -1
  82. package/dist/chunk-JIJPZFR2.js.map +0 -1
  83. package/dist/chunk-OUUTDSOW.js.map +0 -1
  84. package/dist/chunk-PYKRQAER.js.map +0 -1
  85. package/dist/chunk-QLCOEP5J.js.map +0 -1
  86. package/dist/chunk-RWRRBYG4.js +0 -3
  87. package/dist/chunk-SONUORBT.js.map +0 -1
  88. package/dist/chunk-T5IUZF47.js.map +0 -1
  89. package/dist/chunk-U5BZ66VX.js.map +0 -1
  90. package/dist/chunk-WCCGE4QR.js.map +0 -1
  91. package/dist/chunk-WSW6YJNY.js +0 -168
  92. package/dist/chunk-WSW6YJNY.js.map +0 -1
  93. package/dist/kyber-3ULIJSE3.js +0 -3
  94. package/dist/types-lJIxBlWF.d.ts +0 -256
  95. package/dist/verifier-3FAKCFNN.js +0 -5
package/dist/bin/agent.js CHANGED
@@ -1,28 +1,41 @@
1
1
  #!/usr/bin/env node
2
- import { LiopServer } from '../chunk-WCCGE4QR.js';
3
- import '../chunk-JIJPZFR2.js';
4
- import { LiopMcpRouter } from '../chunk-547TYL27.js';
5
- import '../chunk-32ADSAJS.js';
6
- import '../chunk-OUUTDSOW.js';
7
- import '../chunk-QLCOEP5J.js';
8
- import '../chunk-U5BZ66VX.js';
9
- import '../chunk-WSW6YJNY.js';
10
- import '../chunk-PYKRQAER.js';
11
- import '../chunk-RWRRBYG4.js';
12
- import { MeshNode } from '../chunk-74CISO2I.js';
13
- import { log } from '../chunk-72MNYFR6.js';
2
+ import { probeTopology, RoutingTable } from '../chunk-PUDETPL4.js';
3
+ import { TokenManager } from '../chunk-3QH44NKZ.js';
4
+ import { LiopServer } from '../chunk-5SWHE62F.js';
5
+ import '../chunk-Y62GORQF.js';
6
+ import { LiopMcpRouter } from '../chunk-VRB5HUYU.js';
7
+ import '../chunk-2STZHJ24.js';
8
+ import '../chunk-IK7CGWAZ.js';
9
+ import '../chunk-7PITYWOV.js';
10
+ import '../chunk-WPTOJYN5.js';
11
+ import '../chunk-UJFWPRDM.js';
12
+ import '../chunk-PAICJCKJ.js';
13
+ import { isLegacyRequest } from '../chunk-2KSO3W4A.js';
14
+ import '../chunk-FTF6AMF6.js';
15
+ import '../chunk-ZP3VVXOI.js';
16
+ import { MeshNode } from '../chunk-XRDN232O.js';
17
+ import { log } from '../chunk-K3DGJLUY.js';
14
18
  import * as fs from 'fs';
15
19
  import * as os from 'os';
16
20
  import * as path from 'path';
21
+ import * as readline from 'readline';
17
22
  import { multiaddr } from '@multiformats/multiaddr';
18
23
 
24
+ var LIOP_MESH_STATUS_TOOL = {
25
+ name: "LiopMeshStatus",
26
+ description: "LiopMeshStatus: Returns the current dynamic diagnostic status of the Zero-Trust Neural Mesh.",
27
+ inputSchema: {
28
+ type: "object",
29
+ properties: {},
30
+ additionalProperties: false
31
+ }
32
+ };
19
33
  async function resolveBootstrapFromUrl(url) {
20
34
  try {
21
35
  const healthUrl = url.endsWith("/health") ? url : `${url}/health`;
22
36
  const response = await fetch(healthUrl, {
23
37
  headers: { Accept: "application/json" },
24
38
  signal: AbortSignal.timeout(1e4)
25
- // Increased to 10s
26
39
  });
27
40
  if (!response.ok) return null;
28
41
  const data = await response.json();
@@ -61,6 +74,26 @@ function normalizeBootstrap(addr) {
61
74
  return trimmed;
62
75
  }
63
76
  function industrialAddressMapper(addr) {
77
+ if (addr.includes("/ip4/172.23.0.10"))
78
+ return addr.replace(
79
+ /\/ip4\/172\.23\.0\.10\/tcp\/[0-9]+/,
80
+ "/ip4/127.0.0.1/tcp/15001"
81
+ );
82
+ if (addr.includes("/ip4/172.23.0.20"))
83
+ return addr.replace(
84
+ /\/ip4\/172\.23\.0\.20\/tcp\/[0-9]+/,
85
+ "/ip4/127.0.0.1/tcp/15011"
86
+ );
87
+ if (addr.includes("/ip4/172.21.0.13"))
88
+ return addr.replace(
89
+ /\/ip4\/172\.21\.0\.13\/tcp\/[0-9]+/,
90
+ "/ip4/127.0.0.1/tcp/15031"
91
+ );
92
+ if (addr.includes("/ip4/172.21.0.14"))
93
+ return addr.replace(
94
+ /\/ip4\/172\.21\.0\.14\/tcp\/[0-9]+/,
95
+ "/ip4/127.0.0.1/tcp/15041"
96
+ );
64
97
  if (addr.includes("/ip4/172.20.0.10"))
65
98
  return addr.replace(
66
99
  /\/ip4\/172\.20\.0\.10\/tcp\/[0-9]+/,
@@ -89,7 +122,7 @@ function industrialAddressMapper(addr) {
89
122
  function isDockerDemoHost(urlStr) {
90
123
  try {
91
124
  const u = new URL(urlStr);
92
- return (u.hostname === "127.0.0.1" || u.hostname === "localhost") && (u.port === "13000" || u.port === "13001");
125
+ return (u.hostname === "127.0.0.1" || u.hostname === "localhost") && (u.port === "13000" || u.port === "13001" || u.port === "15000" || u.port === "15018");
93
126
  } catch {
94
127
  return false;
95
128
  }
@@ -97,45 +130,14 @@ function isDockerDemoHost(urlStr) {
97
130
  function shouldEnableDockerMap() {
98
131
  return process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test" || process.env.LIOP_DOCKER_MAP === "true" || process.env.LIOP_DEV_MODE === "true" || !!process.env.LIOP_NEXUS_URL && isDockerDemoHost(process.env.LIOP_NEXUS_URL);
99
132
  }
100
- async function main() {
101
- if ((process.platform === "win32" || process.platform === "darwin") && !process.execArgv.includes("--use-system-ca") && !(process.env.NODE_OPTIONS ?? "").includes("--use-system-ca")) {
102
- const { spawn } = await import('child_process');
103
- const child = spawn(
104
- process.execPath,
105
- ["--use-system-ca", ...process.argv.slice(1)],
106
- { stdio: "inherit", env: process.env }
107
- );
108
- child.on("exit", (code) => process.exit(code ?? 1));
109
- child.on("error", () => process.exit(1));
110
- await new Promise(() => {
111
- });
112
- return;
113
- }
114
- const buildTime = (/* @__PURE__ */ new Date()).toISOString();
115
- log.info(`[LIOP-Agent] \u{1F680} Version 1.2.0-alpha.9 | Build: ${buildTime}`);
116
- const liopDir = path.join(os.homedir(), ".liop");
117
- const identityPath = path.join(liopDir, "identity.json");
118
- if (!fs.existsSync(liopDir)) {
119
- fs.mkdirSync(liopDir, { recursive: true });
120
- }
133
+ async function resolveBootstrapNodes(liopDir) {
121
134
  let bootstrapNodes = [];
122
135
  const args = process.argv.slice(2);
123
136
  if (args.length > 0) {
124
137
  bootstrapNodes = args.filter((a) => a.startsWith("/"));
125
138
  }
126
139
  if (bootstrapNodes.length === 0) {
127
- const searchDirs = [];
128
- if (process.env.LIOP_BOOTSTRAP_FILE) {
129
- log.warn(
130
- "LIOP_BOOTSTRAP_FILE is deprecated and will be removed in the next major version. Use LIOP_NEXUS_URL for Auto-Discovery instead."
131
- );
132
- const filePath = path.resolve(process.env.LIOP_BOOTSTRAP_FILE);
133
- if (fs.existsSync(filePath)) {
134
- const addr = fs.readFileSync(filePath, "utf8").trim();
135
- if (addr) bootstrapNodes.push(normalizeBootstrap(addr));
136
- }
137
- }
138
- searchDirs.push(
140
+ const searchDirs = [
139
141
  process.cwd(),
140
142
  path.join(process.cwd(), "tests/infra/nexus-data"),
141
143
  liopDir,
@@ -143,7 +145,7 @@ async function main() {
143
145
  path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, "$1"),
144
146
  "../../tests/infra/nexus-data"
145
147
  )
146
- );
148
+ ];
147
149
  for (const dir of searchDirs) {
148
150
  try {
149
151
  if (fs.existsSync(dir)) {
@@ -162,15 +164,12 @@ async function main() {
162
164
  }
163
165
  if (bootstrapNodes.length > 0) break;
164
166
  }
165
- } catch (_e) {
167
+ } catch {
166
168
  }
167
169
  }
168
170
  }
169
171
  if (process.env.LIOP_NEXUS_URL) {
170
172
  const nexusUrl = process.env.LIOP_NEXUS_URL;
171
- log.info(
172
- `[LIOP-Agent] \u{1F310} Running parallel discovery from: ${nexusUrl} (Sources Found: ${bootstrapNodes.length})`
173
- );
174
173
  const resolved = await resolveBootstrapFromUrl(nexusUrl);
175
174
  if (resolved) {
176
175
  const normalized = normalizeBootstrap(resolved);
@@ -185,36 +184,322 @@ async function main() {
185
184
  if (bootstrapNodes.length === 0 && process.env.LIOP_BOOTSTRAP) {
186
185
  bootstrapNodes.push(process.env.LIOP_BOOTSTRAP.trim());
187
186
  }
188
- if (bootstrapNodes.length === 0) {
189
- bootstrapNodes.push(
190
- "/ip4/127.0.0.1/tcp/13001/p2p/12D3KooWD8FUFdnLQzzLFNdicsaTknM5cpD7os9sK9NWVSVABJMD"
191
- );
192
- }
193
- bootstrapNodes = bootstrapNodes.filter((addr) => {
187
+ return bootstrapNodes.filter((addr) => {
194
188
  try {
195
189
  multiaddr(addr);
196
190
  return true;
197
191
  } catch {
198
- log.warn(`[LIOP-Agent] Ignoring invalid bootstrap multiaddr: ${addr}`);
199
192
  return false;
200
193
  }
201
194
  });
202
- if (bootstrapNodes.length === 0) {
203
- log.info(
204
- "[LIOP-Agent] No bootstrap nodes configured. Operating in standalone mode."
195
+ }
196
+ async function forwardToGateway(mcpEndpoint, request, tokenManager) {
197
+ const send = async (token2) => {
198
+ const headers = {
199
+ "Content-Type": "application/json"
200
+ };
201
+ if (token2) {
202
+ headers.Authorization = `Bearer ${token2}`;
203
+ }
204
+ if (request.method) {
205
+ headers["Mcp-Method"] = request.method;
206
+ }
207
+ const params = request.params;
208
+ if (params?.name) {
209
+ headers["Mcp-Name"] = params.name;
210
+ }
211
+ return await fetch(mcpEndpoint, {
212
+ method: "POST",
213
+ headers,
214
+ body: JSON.stringify(request),
215
+ signal: AbortSignal.timeout(3e4)
216
+ });
217
+ };
218
+ let token;
219
+ try {
220
+ token = await tokenManager.getToken();
221
+ } catch (err) {
222
+ log.warn(
223
+ `[LIOP-Agent] Token acquisition warning: ${err instanceof Error ? err.message : String(err)}`
205
224
  );
225
+ }
226
+ let response = await send(token);
227
+ if (response.status === 401 && token) {
206
228
  log.info(
207
- "[LIOP-Agent] Pass a multiaddr as argument or create 'nexus.multiaddr' file."
229
+ "[LIOP-Agent] \u{1F504} 401 received from Gateway. Refreshing token and retrying..."
208
230
  );
231
+ tokenManager.invalidate();
232
+ try {
233
+ token = await tokenManager.getToken();
234
+ response = await send(token);
235
+ } catch {
236
+ }
209
237
  }
238
+ if (!response.ok) {
239
+ const errorBody = await response.text();
240
+ let parsedError = null;
241
+ try {
242
+ parsedError = JSON.parse(errorBody);
243
+ } catch {
244
+ }
245
+ const errorObj = parsedError?.error;
246
+ return {
247
+ jsonrpc: "2.0",
248
+ id: request.id,
249
+ error: {
250
+ code: errorObj?.code ?? -32603,
251
+ message: errorObj?.message ?? `Gateway returned HTTP ${response.status}: ${errorBody}`
252
+ }
253
+ };
254
+ }
255
+ return await response.json();
256
+ }
257
+ async function runGatewayMode(gateway, tokenManager, routingTable) {
258
+ log.info(
259
+ `[LIOP-Agent] \u{1F6E1}\uFE0F Running in ADAPTIVE GATEWAY MODE -> ${gateway.mcpEndpoint}`
260
+ );
261
+ routingTable.registerLocalTool(LIOP_MESH_STATUS_TOOL);
262
+ routingTable.registerGatewayTools(
263
+ gateway.tools.map((t) => ({ name: t })),
264
+ gateway.mcpEndpoint
265
+ );
266
+ let lastToolCount = gateway.tools.length;
267
+ const pollInterval = setInterval(async () => {
268
+ try {
269
+ const res = await fetch(gateway.healthEndpoint, {
270
+ headers: { Accept: "application/json" },
271
+ signal: AbortSignal.timeout(4e3)
272
+ });
273
+ if (res.ok) {
274
+ const data = await res.json();
275
+ if (data.tools && data.tools.length !== lastToolCount) {
276
+ log.info(
277
+ `[LIOP-Agent] Gateway tools topology updated (${lastToolCount} -> ${data.tools.length})`
278
+ );
279
+ lastToolCount = data.tools.length;
280
+ routingTable.registerGatewayTools(
281
+ data.tools.map((t) => ({ name: t })),
282
+ gateway.mcpEndpoint
283
+ );
284
+ process.stdout.write(
285
+ `{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}
286
+ `
287
+ );
288
+ process.stdout.write(
289
+ `{"jsonrpc":"2.0","method":"notifications/resources/list_changed"}
290
+ `
291
+ );
292
+ }
293
+ }
294
+ } catch {
295
+ }
296
+ }, 15e3);
297
+ const rl = readline.createInterface({
298
+ input: process.stdin,
299
+ terminal: false
300
+ });
301
+ process.stdout.on("error", (err) => {
302
+ if (err.code === "EPIPE") {
303
+ clearInterval(pollInterval);
304
+ process.exit(0);
305
+ }
306
+ });
307
+ rl.on("line", async (line) => {
308
+ const trimmed = line.trim();
309
+ if (!trimmed) return;
310
+ let request;
311
+ try {
312
+ request = JSON.parse(trimmed);
313
+ } catch {
314
+ return;
315
+ }
316
+ const { id, method } = request;
317
+ if (method === "server/discover") {
318
+ const discoverResponse = {
319
+ jsonrpc: "2.0",
320
+ id,
321
+ result: {
322
+ resultType: "complete",
323
+ supportedVersions: ["2026-07-28", "2025-11-25"],
324
+ capabilities: {
325
+ tools: { listChanged: true },
326
+ resources: { listChanged: true, subscribe: true },
327
+ prompts: { listChanged: true }
328
+ },
329
+ serverInfo: {
330
+ name: "liop-adaptive-agent",
331
+ version: "2.5.0"
332
+ }
333
+ }
334
+ };
335
+ process.stdout.write(`${JSON.stringify(discoverResponse)}
336
+ `);
337
+ return;
338
+ }
339
+ if (method === "initialize") {
340
+ const clientVersion = request.params?.protocolVersion ?? request.params?._meta?.["io.modelcontextprotocol/protocolVersion"];
341
+ const protocolVersion = clientVersion === "2026-07-28" ? "2026-07-28" : "2025-11-25";
342
+ const initResponse = {
343
+ jsonrpc: "2.0",
344
+ id,
345
+ result: {
346
+ protocolVersion,
347
+ capabilities: {
348
+ tools: { listChanged: true },
349
+ resources: { listChanged: true, subscribe: true },
350
+ prompts: { listChanged: true }
351
+ },
352
+ serverInfo: {
353
+ name: "liop-adaptive-agent",
354
+ version: "2.5.0"
355
+ }
356
+ }
357
+ };
358
+ process.stdout.write(`${JSON.stringify(initResponse)}
359
+ `);
360
+ return;
361
+ }
362
+ if (method === "notifications/initialized" || method === "notifications/cancelled") {
363
+ return;
364
+ }
365
+ if (method === "ping") {
366
+ process.stdout.write(
367
+ `${JSON.stringify({ jsonrpc: "2.0", id, result: {} })}
368
+ `
369
+ );
370
+ return;
371
+ }
372
+ if (method === "resources/templates/list") {
373
+ const templatesResponse = {
374
+ jsonrpc: "2.0",
375
+ id,
376
+ result: {
377
+ resultType: "complete",
378
+ ttlMs: 3e5,
379
+ cacheScope: "public",
380
+ resourceTemplates: []
381
+ }
382
+ };
383
+ process.stdout.write(`${JSON.stringify(templatesResponse)}
384
+ `);
385
+ return;
386
+ }
387
+ if (method === "subscriptions/listen") {
388
+ const listenResponse = {
389
+ jsonrpc: "2.0",
390
+ id,
391
+ result: {
392
+ resultType: "complete"
393
+ }
394
+ };
395
+ process.stdout.write(`${JSON.stringify(listenResponse)}
396
+ `);
397
+ return;
398
+ }
399
+ if (method === "tools/call") {
400
+ const params = request.params;
401
+ if (params?.name === "LiopMeshStatus") {
402
+ const statusResponse = {
403
+ jsonrpc: "2.0",
404
+ id,
405
+ result: {
406
+ content: [
407
+ {
408
+ type: "text",
409
+ text: JSON.stringify({
410
+ mode: "adaptive-gateway",
411
+ gatewayUrl: gateway.baseUrl,
412
+ tier: gateway.tier,
413
+ toolsAvailable: routingTable.getAllToolDefinitions().length,
414
+ authenticated: true,
415
+ status: "ONLINE"
416
+ })
417
+ }
418
+ ]
419
+ }
420
+ };
421
+ process.stdout.write(`${JSON.stringify(statusResponse)}
422
+ `);
423
+ return;
424
+ }
425
+ }
426
+ try {
427
+ const response = await forwardToGateway(
428
+ gateway.mcpEndpoint,
429
+ request,
430
+ tokenManager
431
+ );
432
+ if (method === "tools/list" && response.result && typeof response.result === "object") {
433
+ const resObj = response.result;
434
+ const toolsList = resObj.tools;
435
+ if (Array.isArray(toolsList)) {
436
+ const hasStatus = toolsList.some((t) => t.name === "LiopMeshStatus");
437
+ if (!hasStatus) {
438
+ toolsList.unshift(LIOP_MESH_STATUS_TOOL);
439
+ }
440
+ routingTable.registerGatewayTools(toolsList, gateway.mcpEndpoint);
441
+ }
442
+ if (!isLegacyRequest(request)) {
443
+ if (!resObj.resultType) {
444
+ resObj.resultType = "complete";
445
+ }
446
+ if (!resObj.ttlMs) {
447
+ resObj.ttlMs = 3e5;
448
+ }
449
+ if (!resObj.cacheScope) {
450
+ resObj.cacheScope = "public";
451
+ }
452
+ }
453
+ }
454
+ process.stdout.write(`${JSON.stringify(response)}
455
+ `);
456
+ } catch (err) {
457
+ if (method === "tools/list") {
458
+ const isLegacy = isLegacyRequest(request);
459
+ const fallbackResult = isLegacy ? { tools: routingTable.getAllToolDefinitions() } : {
460
+ resultType: "complete",
461
+ ttlMs: 3e5,
462
+ cacheScope: "public",
463
+ tools: routingTable.getAllToolDefinitions()
464
+ };
465
+ const fallbackResponse = {
466
+ jsonrpc: "2.0",
467
+ id,
468
+ result: fallbackResult
469
+ };
470
+ process.stdout.write(`${JSON.stringify(fallbackResponse)}
471
+ `);
472
+ } else {
473
+ const errResponse = {
474
+ jsonrpc: "2.0",
475
+ id,
476
+ error: {
477
+ code: -32603,
478
+ message: `Forwarding failed: ${err instanceof Error ? err.message : String(err)}`
479
+ }
480
+ };
481
+ process.stdout.write(`${JSON.stringify(errResponse)}
482
+ `);
483
+ }
484
+ }
485
+ });
486
+ rl.on("close", () => {
487
+ clearInterval(pollInterval);
488
+ process.exit(0);
489
+ });
490
+ }
491
+ async function runMeshMode(mesh) {
492
+ log.info(
493
+ `[LIOP-Agent] \u{1F310} Running in P2P MESH MODE (${mesh.bootstrapNodes.length} bootstraps)`
494
+ );
210
495
  const liopServer = new LiopServer({
211
496
  name: "@nekzus/liop",
212
- version: "1.0.0"
497
+ version: "2.5.0"
213
498
  });
214
499
  liopServer.enableZeroShotAutonomy();
215
500
  const meshNode = new MeshNode({
216
- identityPath,
217
- bootstrapNodes,
501
+ identityPath: mesh.identityPath,
502
+ bootstrapNodes: mesh.bootstrapNodes,
218
503
  addressMapper: shouldEnableDockerMap() ? industrialAddressMapper : void 0
219
504
  });
220
505
  await meshNode.start();
@@ -230,8 +515,6 @@ async function main() {
230
515
  );
231
516
  };
232
517
  setTimeout(() => {
233
- const rtSize = meshNode.getRoutingTableSize?.() || 0;
234
- log.info(`[LIOP-Agent] Warm-up complete. Routing Table size: ${rtSize}`);
235
518
  router.refreshManifestCache(true).catch(() => {
236
519
  });
237
520
  }, 2e3);
@@ -246,9 +529,6 @@ async function main() {
246
529
  const newSize = router.getCacheSize();
247
530
  if (newSize !== prevSize) {
248
531
  pollIntervalMs = POLL_BASE_MS;
249
- log.info(
250
- `[LIOP-Agent] Topology change detected (${prevSize} \u2192 ${newSize}). Resetting poll to ${POLL_BASE_MS / 1e3}s.`
251
- );
252
532
  } else {
253
533
  pollIntervalMs = Math.min(
254
534
  Math.round(pollIntervalMs * 1.5),
@@ -259,15 +539,12 @@ async function main() {
259
539
  }, pollIntervalMs);
260
540
  };
261
541
  scheduleAdaptivePoll();
262
- const readline = await import('readline');
263
542
  const rl = readline.createInterface({
264
543
  input: process.stdin,
265
544
  terminal: false
266
545
  });
267
546
  process.stdout.on("error", (err) => {
268
- if (err.code === "EPIPE") {
269
- process.exit(0);
270
- }
547
+ if (err.code === "EPIPE") process.exit(0);
271
548
  });
272
549
  rl.on("line", async (line) => {
273
550
  const trimmed = line.trim();
@@ -281,22 +558,336 @@ async function main() {
281
558
  `);
282
559
  }
283
560
  }
284
- } catch (_err) {
561
+ } catch {
285
562
  }
286
563
  });
287
- rl.on("close", () => {
564
+ rl.on("close", () => process.exit(0));
565
+ process.on("SIGINT", async () => {
566
+ await meshNode.stop();
288
567
  process.exit(0);
289
568
  });
290
- log.info(`[LIOP-Agent] Guarding Claude Desktop via STDIO.`);
569
+ }
570
+ async function runHybridMode(topology, tokenManager, routingTable) {
571
+ const gateway = topology.gateway;
572
+ const mesh = topology.mesh;
573
+ if (!gateway || !mesh) {
574
+ if (gateway) return runGatewayMode(gateway, tokenManager, routingTable);
575
+ if (mesh) return runMeshMode(mesh);
576
+ return;
577
+ }
291
578
  log.info(
292
- `[LIOP-Agent] P2P Mesh: Joined (${bootstrapNodes.length} bootstraps)`
579
+ `[LIOP-Agent] \u26A1 Running in HYBRID MODE (Gateway: ${gateway.baseUrl} + Mesh P2P)`
293
580
  );
294
- log.info("[LIOP-Agent] Tool discovery: Dynamic via /liop/manifest/1.0.0");
295
- process.on("SIGINT", async () => {
296
- await meshNode.stop();
581
+ routingTable.registerLocalTool(LIOP_MESH_STATUS_TOOL);
582
+ routingTable.registerGatewayTools(
583
+ gateway.tools.map((t) => ({ name: t })),
584
+ gateway.mcpEndpoint
585
+ );
586
+ let meshNode = null;
587
+ let router = null;
588
+ const initMeshPromise = (async () => {
589
+ try {
590
+ const liopServer = new LiopServer({
591
+ name: "@nekzus/liop-hybrid",
592
+ version: "2.5.0"
593
+ });
594
+ liopServer.enableZeroShotAutonomy();
595
+ meshNode = new MeshNode({
596
+ identityPath: mesh.identityPath,
597
+ bootstrapNodes: mesh.bootstrapNodes,
598
+ addressMapper: shouldEnableDockerMap() ? industrialAddressMapper : void 0
599
+ });
600
+ await meshNode.start();
601
+ router = new LiopMcpRouter(liopServer, meshNode);
602
+ router.onToolsChanged = () => {
603
+ process.stdout.write(
604
+ `{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}
605
+ `
606
+ );
607
+ process.stdout.write(
608
+ `{"jsonrpc":"2.0","method":"notifications/resources/list_changed"}
609
+ `
610
+ );
611
+ };
612
+ await router.refreshManifestCache(true).catch(() => {
613
+ });
614
+ log.info("[LIOP-Agent] \u2705 Background P2P Mesh initialization completed.");
615
+ } catch (err) {
616
+ log.warn(
617
+ `[LIOP-Agent] Background Mesh init warning: ${err instanceof Error ? err.message : String(err)}`
618
+ );
619
+ }
620
+ })();
621
+ const rl = readline.createInterface({
622
+ input: process.stdin,
623
+ terminal: false
624
+ });
625
+ process.stdout.on("error", (err) => {
626
+ if (err.code === "EPIPE") process.exit(0);
627
+ });
628
+ rl.on("line", async (line) => {
629
+ const trimmed = line.trim();
630
+ if (!trimmed) return;
631
+ let request;
632
+ try {
633
+ request = JSON.parse(trimmed);
634
+ } catch {
635
+ return;
636
+ }
637
+ const { id, method } = request;
638
+ if (method === "server/discover") {
639
+ const discoverResponse = {
640
+ jsonrpc: "2.0",
641
+ id,
642
+ result: {
643
+ resultType: "complete",
644
+ supportedVersions: ["2026-07-28", "2025-11-25"],
645
+ capabilities: {
646
+ tools: { listChanged: true },
647
+ resources: { listChanged: true, subscribe: true },
648
+ prompts: { listChanged: true }
649
+ },
650
+ serverInfo: {
651
+ name: "liop-hybrid-agent",
652
+ version: "2.5.0"
653
+ }
654
+ }
655
+ };
656
+ process.stdout.write(`${JSON.stringify(discoverResponse)}
657
+ `);
658
+ return;
659
+ }
660
+ if (method === "initialize") {
661
+ const clientVersion = request.params?.protocolVersion ?? request.params?._meta?.["io.modelcontextprotocol/protocolVersion"];
662
+ const protocolVersion = clientVersion === "2026-07-28" ? "2026-07-28" : "2025-11-25";
663
+ const initResponse = {
664
+ jsonrpc: "2.0",
665
+ id,
666
+ result: {
667
+ protocolVersion,
668
+ capabilities: {
669
+ tools: { listChanged: true },
670
+ resources: { listChanged: true, subscribe: true },
671
+ prompts: { listChanged: true }
672
+ },
673
+ serverInfo: {
674
+ name: "liop-hybrid-agent",
675
+ version: "2.5.0"
676
+ }
677
+ }
678
+ };
679
+ process.stdout.write(`${JSON.stringify(initResponse)}
680
+ `);
681
+ return;
682
+ }
683
+ if (method === "notifications/initialized" || method === "notifications/cancelled") {
684
+ return;
685
+ }
686
+ if (method === "ping") {
687
+ process.stdout.write(
688
+ `${JSON.stringify({ jsonrpc: "2.0", id, result: {} })}
689
+ `
690
+ );
691
+ return;
692
+ }
693
+ if (method === "resources/templates/list") {
694
+ const templatesResponse = {
695
+ jsonrpc: "2.0",
696
+ id,
697
+ result: {
698
+ resultType: "complete",
699
+ ttlMs: 3e5,
700
+ cacheScope: "public",
701
+ resourceTemplates: []
702
+ }
703
+ };
704
+ process.stdout.write(`${JSON.stringify(templatesResponse)}
705
+ `);
706
+ return;
707
+ }
708
+ if (method === "subscriptions/listen") {
709
+ const listenResponse = {
710
+ jsonrpc: "2.0",
711
+ id,
712
+ result: {
713
+ resultType: "complete"
714
+ }
715
+ };
716
+ process.stdout.write(`${JSON.stringify(listenResponse)}
717
+ `);
718
+ return;
719
+ }
720
+ if (method === "tools/call") {
721
+ const params = request.params;
722
+ const toolName = params?.name || "";
723
+ const route = routingTable.resolve(toolName);
724
+ if (route?.provider === "http-gateway") {
725
+ const start = Date.now();
726
+ try {
727
+ const res = await forwardToGateway(
728
+ gateway.mcpEndpoint,
729
+ request,
730
+ tokenManager
731
+ );
732
+ routingTable.recordSuccess(toolName, Date.now() - start);
733
+ process.stdout.write(`${JSON.stringify(res)}
734
+ `);
735
+ return;
736
+ } catch (_err) {
737
+ routingTable.recordFailure(toolName);
738
+ log.warn(
739
+ `[LIOP-Agent] Gateway call failed for '${toolName}'. Checking P2P fallback...`
740
+ );
741
+ }
742
+ }
743
+ await initMeshPromise;
744
+ if (router) {
745
+ const res = await router.dispatch(request);
746
+ if (res) process.stdout.write(`${JSON.stringify(res)}
747
+ `);
748
+ return;
749
+ }
750
+ }
751
+ if (method === "tools/list") {
752
+ let gatewayTools = [];
753
+ try {
754
+ const gwRes = await forwardToGateway(
755
+ gateway.mcpEndpoint,
756
+ request,
757
+ tokenManager
758
+ );
759
+ const resObj = gwRes.result;
760
+ if (Array.isArray(resObj?.tools)) {
761
+ gatewayTools = resObj.tools;
762
+ routingTable.registerGatewayTools(gatewayTools, gateway.mcpEndpoint);
763
+ }
764
+ } catch {
765
+ gatewayTools = routingTable.getAllToolDefinitions();
766
+ }
767
+ let meshTools = [];
768
+ if (router) {
769
+ const meshRes = await router.dispatch(request);
770
+ const meshObj = meshRes?.result;
771
+ if (Array.isArray(meshObj?.tools)) {
772
+ meshTools = meshObj.tools;
773
+ }
774
+ }
775
+ const toolMap = /* @__PURE__ */ new Map();
776
+ toolMap.set("LiopMeshStatus", LIOP_MESH_STATUS_TOOL);
777
+ for (const t of gatewayTools) toolMap.set(t.name, t);
778
+ for (const t of meshTools)
779
+ if (!toolMap.has(t.name)) toolMap.set(t.name, t);
780
+ const merged = Array.from(toolMap.values()).sort(
781
+ (a, b) => a.name.localeCompare(b.name)
782
+ );
783
+ const isLegacy = isLegacyRequest(request);
784
+ const toolsResult = isLegacy ? { tools: merged } : {
785
+ resultType: "complete",
786
+ ttlMs: 3e5,
787
+ cacheScope: "public",
788
+ tools: merged
789
+ };
790
+ process.stdout.write(
791
+ `${JSON.stringify({ jsonrpc: "2.0", id, result: toolsResult })}
792
+ `
793
+ );
794
+ return;
795
+ }
796
+ try {
797
+ const res = await forwardToGateway(
798
+ gateway.mcpEndpoint,
799
+ request,
800
+ tokenManager
801
+ );
802
+ if (!isLegacyRequest(request) && res.result && typeof res.result === "object") {
803
+ const resObj = res.result;
804
+ if (!resObj.resultType) {
805
+ resObj.resultType = "complete";
806
+ }
807
+ }
808
+ process.stdout.write(`${JSON.stringify(res)}
809
+ `);
810
+ } catch {
811
+ await initMeshPromise;
812
+ if (router) {
813
+ const res = await router.dispatch(request);
814
+ if (res) process.stdout.write(`${JSON.stringify(res)}
815
+ `);
816
+ }
817
+ }
818
+ });
819
+ rl.on("close", async () => {
820
+ if (meshNode) await meshNode.stop();
297
821
  process.exit(0);
298
822
  });
299
823
  }
824
+ async function main() {
825
+ if ((process.platform === "win32" || process.platform === "darwin") && !process.execArgv.includes("--use-system-ca") && !(process.env.NODE_OPTIONS ?? "").includes("--use-system-ca")) {
826
+ const { spawn } = await import('child_process');
827
+ const child = spawn(
828
+ process.execPath,
829
+ ["--use-system-ca", ...process.argv.slice(1)],
830
+ { stdio: "inherit", env: process.env }
831
+ );
832
+ child.on("exit", (code) => process.exit(code ?? 1));
833
+ child.on("error", () => process.exit(1));
834
+ await new Promise(() => {
835
+ });
836
+ return;
837
+ }
838
+ const buildTime = (/* @__PURE__ */ new Date()).toISOString();
839
+ log.info(
840
+ `[LIOP-Agent] \u{1F680} Version 2.5.0 (Adaptive Zero-Config) | Build: ${buildTime}`
841
+ );
842
+ const liopDir = path.join(os.homedir(), ".liop");
843
+ const identityPath = path.join(liopDir, "identity.json");
844
+ if (!fs.existsSync(liopDir)) {
845
+ fs.mkdirSync(liopDir, { recursive: true });
846
+ }
847
+ const bootstrapNodes = await resolveBootstrapNodes(liopDir);
848
+ const blgUrl = process.env.LIOP_BLG_URL;
849
+ const nexusUrl = process.env.LIOP_NEXUS_URL;
850
+ const clientId = process.env.LIOP_CLIENT_ID || process.env.LIOP_OAUTH_CLIENT_ID || "liop-agent";
851
+ const clientSecret = process.env.LIOP_CLIENT_SECRET || process.env.LIOP_OAUTH_CLIENT_SECRET || "dev-secret-change-me";
852
+ const staticToken = process.env.LIOP_TOKEN || process.env.LIOP_OAUTH_TOKEN;
853
+ const topology = await probeTopology({
854
+ blgUrl,
855
+ nexusUrl,
856
+ clientId,
857
+ clientSecret,
858
+ staticToken,
859
+ bootstrapNodes,
860
+ identityPath
861
+ });
862
+ const routingTable = new RoutingTable();
863
+ const tokenManager = new TokenManager({
864
+ tokenEndpoint: topology.gateway?.tokenEndpoint || `${nexusUrl || "http://127.0.0.1:15000"}/oidc/token`,
865
+ clientId,
866
+ clientSecret,
867
+ audience: topology.gateway?.audience,
868
+ scopes: topology.gateway?.scopes,
869
+ staticToken
870
+ });
871
+ switch (topology.mode) {
872
+ case "gateway":
873
+ if (!topology.gateway)
874
+ throw new Error(
875
+ "Topology probe indicated gateway mode without gateway info."
876
+ );
877
+ await runGatewayMode(topology.gateway, tokenManager, routingTable);
878
+ break;
879
+ case "mesh":
880
+ if (!topology.mesh)
881
+ throw new Error(
882
+ "Topology probe indicated mesh mode without mesh info."
883
+ );
884
+ await runMeshMode(topology.mesh);
885
+ break;
886
+ case "hybrid":
887
+ await runHybridMode(topology, tokenManager, routingTable);
888
+ break;
889
+ }
890
+ }
300
891
  main().catch((err) => {
301
892
  log.error(`[LIOP-Agent] Fatal Error: ${err.message}`);
302
893
  process.exit(1);